diff --git a/CHANGELOG.md b/CHANGELOG.md index fd269e106..ecd462ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,1425 @@ +# 1.47.0-beta3 (Oct 26, 2022) +BUG FIXES +* Fix attach script loop for satellite host attach ([4117](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4117)) +* fix(bm-nic): added check for 0.0.0.0 reserved ip on nic availability ([4122](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4122)) +# 1.47.0-beta2 (Oct 18, 2022) +Features +* Support for DirectLink + - **DataSources** + - ibm_dl_route_reports + - ibm_dl_route_report + - **Resource** + - ibm_dl_route_report + +Enhancements +* supported CoreOS-enabled clusters (default worker pool) and workerPools in satellite clusters ([3985](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3985)) +* support cos one rate plan ([4092](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4092)) +* Fix GRE tunnel in cloud connection ([4093](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4093)) +* support floating_bare_metal_server attribute for resource ibm_is_bare_metal_server_network_interface_allow_float ([4115](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4115)) +* added support for catalog images for enterprises ([3994](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3994)) + +BUG FIXES +* data source: ibm_is_backup_policies, expected 'the empty list', but returned 'no BackupPolicies found' ([4079](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4079)) +* Add fix for storage capacity & system pool output ([4074](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4074)) +* fixes the endpoint; updates go sdk for Atracker ([4073](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4073)) +* fix(vpn_gateway_connection): adding support to null patch ike_policy and ipsec_policy on vpn_gateway_connection ([4058](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4058)) +* fix(bare_metal_server_network_interface_allow_float) : reordered the wait logic in bare metal nics ([4101](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4101)) +* Update VNF Scalability NIC in docs ([4047](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4047)) +* fix(iam-access-groups): added retry logic for access groups read ([4098](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4098)) +* ibm_satellite_attach_host_script shows incorrect syntax for labels ([4099](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4099)) + +# 1.47.0-beta0 (Oct 10, 2022) +Features +* Support for Kubernetes Service + - **Resource** + - ibm_container_vpc_worker +* Support for APP Configuration + - **DataSources** + - ibm_app_config_snapshot + - ibm_app_config_snapshots + - **Resources** + - ibm_app_config_snapshot +Enhancements +* Update schema validation to latest schema methods ([4068](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4068)) +* Support Private end-point for APP Configuration ([4048](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4048)) + +# 1.46.0 (Oct 03, 2022) +Features +* Support for Power Instance + - **DataSources** + - ibm_pi_instance_action + - ibm_pi_shared_processor_pool + - ibm_pi_shared_processor_pools + - ibm_pi_spp_placement_group + - ibm_pi_spp_placement_groups + - **Resources** + - ibm_pi_shared_processor_pool + - ibm_pi_spp_placement_group +* Support Security and Compilance + - **DataSources** + - ibm_scc_posture_profile_import + - ibm_scc_posture_scan_initiate_validation + - **Resources** + - ibm_scc_posture_scan_initiate_validation +* Support App Configuration + - **DataSources** + - ibm_app_config_collection + - ibm_app_config_collections + - ibm_app_config_property + - ibm_app_config_properties + - **Resources** + - ibm_app_config_collection + - ibm_app_config_collection +* Support Virtual Private Cloud + - **DataSources** + - ibm_is_instance_groups + - ibm_is_bare_metal_server_network_interface_reserved_ip + - ibm_is_bare_metal_server_network_interface_reserved_ips + +Enhancements +* Update CD Toolchain resources and datasources with latest SDK ([3933](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3933)) +* Support uset tags in volumes of instance, instance template and volume attachement ([3993](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3993)) +* Add replication enabled attribute in pi volume resource ([4007](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4007)) +* Update Subnets on LoadBalancer ([4026](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4026)) +* Support for lifecycle status and reasons in VPC instance ([4017](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4017)) +* Support VPC reference in VPN gateway ([4039](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4039)) +* Examples and docs updated for HPCS COS support ([4034](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4034)) +* Deprecate connection strings for IBM-cloud-databases ([4050](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4050)) +* Revert volume replication attribute in pi volume resource ([4059](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4059)) +* added support for new ciphers ([4018](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4018)) + +BUG FIXES +* terraform ibm_is_instance_template volume_attachments removal from configuration not changing resource ([3972](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3972)) +* docs in is_instance_template do not cover volume_attachments completely ([3967](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3967)) +* Note section is not in proper format ([3970](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3970)) +* Wrong tagging for TOC ([4019](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4019)) +* ibm_kms_key unhelpful deprecation box ([3923](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3923)) +* "data iam_authorization_policy" is "data iam_authorization_policies" ([4015](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4015)) +* ibm_scc_rule vs ibm_scc_configuration_rule ([3908](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3908)) +* ibm_cos_bucket.abort_incomplete_multipart_upload_days is undocumented ([3799](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3799)) +* Updated Description for Deployment type EPIC ([4037](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4037)) +* Doc corrections for resource group to intimate id and subnet floating ip changes ([4025](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4025)) +* fix(ibm_is_vpn_gateway): reordered the setting of id in ibm_is_vpn_gateway resource to taint the resource properly ([4055](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4055)) +* fix(docs): added details about user data and update link for ibmcloud docs ([4066](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4066)) +# 1.46.0-beta0 (Sep 19, 2022) +Features +* Support for Power Instance + - **DataSources** + - ibm_pi_instance_action + - ibm_pi_shared_processor_pool + - ibm_pi_shared_processor_pools + - ibm_pi_spp_placement_group + - ibm_pi_spp_placement_groups + - **Resources** + - ibm_pi_shared_processor_pool + - ibm_pi_shared_processor_pool +* Support Security and Compilance + - **DataSources** + - ibm_scc_posture_profile_import + - ibm_scc_posture_scan_initiate_validation + - **Resources** + - ibm_scc_posture_scan_initiate_validation +* Support App Configuration + - **DataSources** + - ibm_app_config_collection + - ibm_app_config_collections + - ibm_app_config_property + - ibm_app_config_properties + - **Resources** + - ibm_app_config_collection + - ibm_app_config_collection +* Support Virtual Private Cloud + - **DataSources** + - ibm_is_instance_groups + - ibm_is_bare_metal_server_network_interface_reserved_ip + - ibm_is_bare_metal_server_network_interface_reserved_ips + +Enhancements +* Update CD Toolchain resources and datasources with latest SDK ([3933](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3933)) +* Support uset tags in volumes of instance, instance template and volume attachement ([3993](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3993)) +* Add replication enabled attribute in pi volume resource ([4007](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4007)) +* Update Subnets on LoadBalancer ([4026](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4026)) +* Support for lifecycle status and reasons in VPC instance ([4017](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4017)) +* Support VPC reference in VPN gateway ([4039](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4039)) +* Examples and docs updated for HPCS COS support ([4034](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4034)) + +BUG FIXES +* terraform ibm_is_instance_template volume_attachments removal from configuration not changing resource ([3972](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3972)) +* docs in is_instance_template do not cover volume_attachments completely ([3967](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3967)) +* Note section is not in proper format ([3970](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3970)) +* Wrong tagging for TOC ([4019](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4019)) +* ibm_kms_key unhelpful deprecation box ([3923](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3923)) +* "data iam_authorization_policy" is "data iam_authorization_policies" ([4015](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4015)) +* ibm_scc_rule vs ibm_scc_configuration_rule ([3908](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3908)) +* ibm_cos_bucket.abort_incomplete_multipart_upload_days is undocumented ([3799](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3799)) +* Updated Description for Deployment type EPIC ([4037](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4037)) +* Doc corrections for resource group to intimate id and subnet floating ip changes ([4025](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4025)) + +# 1.45.1 (Sep 14, 2022) +Enhancements +* Support location argument to target the respective Schematics region service ([4030](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4030)) + +# 1.45.0 (Sep 05, 2022) +Features +* Support App Configuration + - **DataSources** + - ibm_app_config_segment + - ibm_app_config_segment + - **Resources** + - ibm_app_config_segment +* Support IAM Access Group + - **Resources** + - ibm_iam_access_group_account_settings + +Enhancements +* CIS CNAME Setup : Create Partial Zone ([3937](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3937)) +* deprecating Security Insights ([3755](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3755)) +* Add SNAP enabled bool for DHCP create function ([3932](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3932)) +* Support for EPIC offering Create flow ([3949](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3949)) +* Add minimum role notes ([3962](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3962)) +* enhancement(is_vpc): added support for identifier in vpc data source ([3959](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3959)) +* Atracker v2 metadata backup ([3887](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3887)) +* coreos host attach support ([3968](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3968)) +* add CBR rule API type support ([3971](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3971)) +* Mark key_protect_key_id as deprecate in database datasource ([3939](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3939)) +* doc changes for VPC Load Balancer ([3872](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3872)) +* Add source units required parameter ([3991](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3991)) +* Add default_network_acl computed attribute for VPC ([3997](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3997)) + + +BUG FIXES +* added log entry for redacted credentials ([3942](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3942)) +* stack trace with ibm_pi_dhcps data resource ([3951](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3951)) +* Fix crash on schematics_action resource ([3969](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3969)) +* Fix duplicate VPC entries in cloud connection create +operation ([3958](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3958)) +* fix: account_id issue when service id apikey is used ([3950](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3950)) +* Delete Over Count Bug Fix ([3946](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3946)) +* Fix the setting of monitoring if it fails with error during update ([3974](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3974)) +* CIS - Delete filter on deletion of Firewall Rules ([3963](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3963)) +* Fix VPN Server clientAuthentication ([3947](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3947)) +* fix(security_group): added wait logic to wait for target removal to avoid 409 ([3957](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3957)) +* The IBM database fails with Error: Unprocessable Entity ([3964](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3964)) +* Prevent runtime error on 0 member allocations ([3992](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3992)) +* key_protect_key_id doc typo fix for database ([3980](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3980)) +* Fix links in database docs ([3977](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3977)) +* fix(ibm_is_security_group_target): missing set statements in sg target resource ([4002](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4002)) +* target_http_status_code correction for VPC LoadBalancer listener ([4005](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4005)) +* fix the diff on cis tags if provisioned from Schematics ([4008](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4008)) +* CIS Firewall Rules : added priority key ([3998](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3998)) +# 1.44.3 (Aug 29, 2022) +BUG FIXES +* The IBM database fails with Error: Unprocessable Entity ([3964](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3964)) +* Prevent runtime error on 0 member allocations ([3992](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3992)) + +# 1.45.0-beta0 (Aug 18, 2022) +Features +* Support App Configuration + - **DataSources** + - ibm_app_config_segment + - ibm_app_config_segment + - **Resources** + - ibm_app_config_segment +* Support IAM Access Group + - **Resources** + - ibm_iam_access_group_account_settings + +Enhancements +* CIS CNAME Setup : Create Partial Zone ([3937](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3937)) +* deprecating Security Insights ([3755](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3755)) +* Add SNAP enabled bool for DHCP create function ([3932](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3932)) +* Support for EPIC offering Create flow ([3949](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3949)) +* Add minimum role notes ([3962](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3962)) +* enhancement(is_vpc): added support for identifier in vpc data source ([3959](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3959)) +* Atracker v2 metadata backup ([3887](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3887)) +* coreos host attach support ([3968](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3968)) +* add CBR rule API type support ([3971](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3971)) +* Mark key_protect_key_id as deprecate in database datasource ([3939](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3939)) +* doc changes for VPC Load Balancer ([3872](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3872)) + +BUG FIXES +* added log entry for redacted credentials ([3942](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3942)) +* stack trace with ibm_pi_dhcps data resource ([3951](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3951)) +* Fix crash on schematics_action resource ([3969](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3969)) +* Fix duplicate VPC entries in cloud connection create +operation ([3958](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3958)) +* fix: account_id issue when service id apikey is used ([3950](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3950)) +* Delete Over Count Bug Fix ([3946](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3946)) +* Fix the setting of monitoring if it fails with error during update ([3974](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3974)) +* CIS - Delete filter on deletion of Firewall Rules ([3963](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3963)) +* Fix VPN Server clientAuthentication ([3947](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3947)) +* fix(security_group): added wait logic to wait for target removal to avoid 409 ([3957](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3957)) + +# 1.44.2 (Aug 8, 2022) +BUG FIXES +* fix: schematics template metadata issue ([3953](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3953)) + +# 1.44.1 (Aug 3, 2022) +BUG FIXES +* Fix the breaking change of cos bucket with replication configuration ([3945](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3945)) +* fix the firewall allowed_ip issue ([3894](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3894)) +* Fix the nil pointer for coreos enabled ([3948](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3948)) + +# 1.44.0 (Aug 2, 2022) +Features +* Support Internt Services + - **DataSources** + - ibm_cis_mtlss + - ibm_cis_mtls_apps + - ibm_cis_origin_auths + - **Resources** + - ibm_cis_mtls + - ibm_cis_mtls_app + - ibm_cis_origin_auth +* Support Internt Services + - **DataSources** + - ibm_database_task + - ibm_database_tasks +* Support Security and Compilance + - **DataSources** + - ibm_scc_posture_credential + - ibm_scc_posture_collector + - ibm_scc_posture_scope + - ibm_scc_posture_credentials + - ibm_scc_posture_collectors +* Support Virtual Private Cloud + - **DataSources** + - ibm_is_backup_policy + - ibm_is_backup_policies + - ibm_is_backup_policy_plan + - ibm_is_backup_policy_plans + - ibm_is_vpn_server + - ibm_is_vpn_servers + - ibm_is_vpn_server_client + - ibm_is_vpn_server_client_configuration + - ibm_is_vpn_server_clients + - ibm_is_vpn_server_route + - ibm_is_vpn_server_routes + - **Resources** + - ibm_is_backup_policy + - ibm_is_backup_policy_plan + - ibm_is_vpn_server + - ibm_is_vpn_server_route +* Support IBM Cloud Storage + - **DataSources** + - ibm_cos_bucket_replication_rule +* Support Private DNS + - **DataSources** + - ibm_dns_custom_resolver_secondary_zones + - **Resources** + - ibm_dns_custom_resolver_secondary_zones + +Enhancements +* Routing Table in Subnet Datasource ([3909](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3909)) +* Added cidr param to dhcp ([3916](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3916)) +* Add CoreOS-enabled option for Satellite location create ([3914](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3914)) + +BUG FIXES +* fix(documentation): error statement fix on security group and is_volumes ([3993](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3893)) +* CIS WAF Group Documentation Fix ([3997](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3897)) +* CD doc fix from generator utility ([3905](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3905)) +* added note for default cipher values ([3915](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3915)) +* Deprecation of vpc_route resource & correction in vpc_routing_table_route ([3919](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3919)) +* Roll back the strogae types for existing buckets ([3928](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3928)) +* Fix the subcategory for cbr docs ([3928](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3928)) +* terraform versions 1.1 added to validator check ([3930](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3920)) +* fix(is_bare_metal_server): removed nics with allow float from server nics ([3938](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3928)) +# 1.44.0-beta0 (Jul 20, 2022) +Features +* Support Internt Services + - **DataSources** + - ibm_cis_mtlss + - ibm_cis_mtls_apps + - ibm_cis_origin_auths + - **Resources** + - ibm_cis_mtls + - ibm_cis_mtls_app + - ibm_cis_origin_auth +* Support Internt Services + - **DataSources** + - ibm_database_task + - ibm_database_tasks +* Support Security and Compilance + - **DataSources** + - ibm_scc_posture_credential + - ibm_scc_posture_collector + - ibm_scc_posture_scope + - ibm_scc_posture_credentials + - ibm_scc_posture_collectors +* Support Virtual Private Cloud + - **DataSources** + - ibm_is_backup_policy + - ibm_is_backup_policies + - ibm_is_backup_policy_plan + - ibm_is_backup_policy_plans + - ibm_is_vpn_server + - ibm_is_vpn_servers + - ibm_is_vpn_server_client + - ibm_is_vpn_server_client_configuration + - ibm_is_vpn_server_clients + - ibm_is_vpn_server_route + - ibm_is_vpn_server_routes + - **Resources** + - ibm_is_backup_policy + - ibm_is_backup_policy_plan + - ibm_is_vpn_server + - ibm_is_vpn_server_route +* Support IBM Cloud Storage + - **DataSources** + - ibm_cos_bucket_replication_rule +* Support Private DNS + - **DataSources** + - ibm_dns_custom_resolver_secondary_zones + - **Resources** + - ibm_dns_custom_resolver_secondary_zones + +Enhancements +* Routing Table in Subnet Datasource ([3909](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3909)) +* Added cidr param to dhcp ([3916](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3916)) +* Add CoreOS-enabled option for Satellite location create ([3914](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3914)) + +BUG FIXES +* fix(documentation): error statement fix on security group and is_volumes ([3993](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3893)) +* CIS WAF Group Documentation Fix ([3997](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3897)) +* CD doc fix from generator utility ([3905](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3905)) +* added note for default cipher values ([3915](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3915)) +* Deprecation of vpc_route resource & correction in vpc_routing_table_route ([3919](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3919)) +* Roll back the strogae types for existing buckets ([3928](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3928)) +* Fix the subcategory for cbr docs ([3928](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3928)) + +# 1.43.0 (Jul 01, 2022) +Features +* Support Kubernetes + - **DataSources** + - ibm_container_dedicated_host_pool + - ibm_container_dedicated_host_flavor + - ibm_container_dedicated_host_flavors + - ibm_container_dedicated_host + - **Resources** + - ibm_container_dedicated_host_pool + - ibm_container_dedicated_host + +* Support EventNotification + - **DataSources** + - ibm_en_source + - ibm_en_destination_slack + - ibm_en_subscription_slack + - ibm_en_subscription_safari + - ibm_en_destination_safari + - **Resources** + - ibm_en_source + - ibm_en_destination_slack + - ibm_en_subscription_slack + - ibm_en_subscription_safari + - ibm_en_destination_safari + +* Support HPCS + - **DataSources** + - ibm_hpcs_managed_key + - ibm_hpcs_key_template + - ibm_hpcs_keystore + - ibm_hpcs_vault + - **Resources** + - ibm_hpcs_managed_key + - ibm_hpcs_key_template + - ibm_hpcs_keystore + - ibm_hpcs_vault + +* Support CD Toolchain + - **DataSources** + - ibm_cd_toolchain + - ibm_cd_toolchain_tool_keyprotect + - ibm_cd_toolchain_tool_secretsmanager + - ibm_cd_toolchain_tool_bitbucketgit + - ibm_cd_toolchain_tool_githubintegrated + - ibm_cd_toolchain_tool_githubconsolidated + - ibm_cd_toolchain_tool_gitlab + - ibm_cd_toolchain_tool_hostedgit + - ibm_cd_toolchain_tool_artifactory + - ibm_cd_toolchain_tool_custom + - ibm_cd_toolchain_tool_pipeline + - ibm_cd_toolchain_tool_devopsinsights + - ibm_cd_toolchain_tool_slack + - ibm_cd_toolchain_tool_sonarqube + - ibm_cd_toolchain_tool_hashicorpvault + - ibm_cd_toolchain_tool_securitycompliance + - ibm_cd_toolchain_tool_privateworker + - ibm_cd_toolchain_tool_appconfig + - ibm_cd_toolchain_tool_jenkins + - ibm_cd_toolchain_tool_nexus + - ibm_cd_toolchain_tool_pagerduty + - ibm_cd_toolchain_tool_saucelabs + - **Resources** + - ibm_cd_toolchain + - ibm_cd_toolchain_tool_keyprotect + - ibm_cd_toolchain_tool_secretsmanager + - ibm_cd_toolchain_tool_bitbucketgit + - ibm_cd_toolchain_tool_githubintegrated + - ibm_cd_toolchain_tool_githubconsolidated + - ibm_cd_toolchain_tool_gitlab + - ibm_cd_toolchain_tool_hostedgit + - ibm_cd_toolchain_tool_artifactory + - ibm_cd_toolchain_tool_custom + - ibm_cd_toolchain_tool_pipeline + - ibm_cd_toolchain_tool_devopsinsights + - ibm_cd_toolchain_tool_slack + - ibm_cd_toolchain_tool_sonarqube + - ibm_cd_toolchain_tool_hashicorpvault + - ibm_cd_toolchain_tool_securitycompliance + - ibm_cd_toolchain_tool_privateworker + - ibm_cd_toolchain_tool_appconfig + - ibm_cd_toolchain_tool_jenkins + - ibm_cd_toolchain_tool_nexus + - ibm_cd_toolchain_tool_pagerduty + - ibm_cd_toolchain_tool_saucelabs + +* Support CD Tekton Pipeline + - **Datasources** + - ibm_cd_tekton_pipeline_definition + - ibm_cd_tekton_pipeline_trigger_property + - ibm_cd_tekton_pipeline_property + - ibm_cd_tekton_pipeline_trigger + - ibm_cd_tekton_pipeline + - **Resources** + - ibm_cd_tekton_pipeline_definition + - ibm_cd_tekton_pipeline_trigger_property + - ibm_cd_tekton_pipeline_property + - ibm_cd_tekton_pipeline_trigger + - ibm_cd_tekton_pipeline + +Enhancements +* support for creation of bucket on Satellite location ([3727](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3727)) +* Allow status filtering in ibm_is_images ([3841](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3841)) +* IBM Cloud CD terraform resources examples - empty toolchain template ([3858](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3858)) +* updated platform-services-go-sdk version to 0.26.1 ([3881](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3881)) +* placement target patch support ([3809](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3809)) +* Added multithreading for 49 requests for Private DNS Resource Record ([3886](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3886)) +* add vpc cluster and workerpool to the dhost example ([3878](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3878)) +* CBR: context-based-restriction update for Enforcement mode support ([3853](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3853)) +* profile patch enhancement for VPC instance ([3860](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3860)) + +BUG Fixes +* ibm_dns_glb docs to not specify the enabled argument ([3818](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3818)) +* floating ip data source nil fix ([3843](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3843)) +* support TLS 1.3 supported ciphers for ibm_cis_domain_settings ([3736](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3736)) +* Update provider version in docs ([3750](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3750)) +* Update cloud_shell_account_settings.html.markdown ([3812](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3812)) +* fix: placement targets empty list ([3787](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3787)) +* fix: instance network interface mutex sync ([3791](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3791)) +* ibm_scc_posture_scope does not allow for blank-space in description ([3733](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3733)) +* SCC provider should output User friendly error messages clearly indicating the problem ([3844](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3844)) +* ibm_is_instance should not not suppress change and force new on boot_volume.0.snapshot change ([3819](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3819)) +* fix(bare_metal_server) : vlan id in multi nic fix ([3767](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3767)) +* fix ibm_container_storage_attachment import ([3862](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3862)) +* Remove rogue CD website document ([3865](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3865)) +* IAM User inivte always shows a diff on "invited_users" ([3863](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3863)) +* name corrections for VPC instance group manager docs ([3884](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3884)) +* UKO Terraform Doc and Bugfixes ([3889](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3889)) +* Make CD Pagerduty prop computed and general tidy up ([3891](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3891)) +* cis waf group settings fix ([3882](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3882)) +* Fix: validator identifier names ([3870](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3870)) +* Fix validateSchema from one element to zero ([3870](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3870)) +# 1.43.0-beta0 (Jun 22, 2022) +Features +* Support Kubernetes + - **DataSources** + - ibm_container_dedicated_host_pool + - ibm_container_dedicated_host_flavor + - ibm_container_dedicated_host_flavors + - ibm_container_dedicated_host + - **Resources** + - ibm_container_dedicated_host_pool + - ibm_container_dedicated_host + +* Support EventNotification + - **DataSources** + - ibm_en_source + - ibm_en_destination_slack + - ibm_en_subscription_slack + - ibm_en_subscription_safari + - ibm_en_destination_safari + - **Resources** + - ibm_en_source + - ibm_en_destination_slack + - ibm_en_subscription_slack + - ibm_en_subscription_safari + - ibm_en_destination_safari + +* Support HPCS + - **DataSources** + - ibm_hpcs_managed_key + - ibm_hpcs_key_template + - ibm_hpcs_keystore + - ibm_hpcs_vault + - **Resources** + - ibm_hpcs_managed_key + - ibm_hpcs_key_template + - ibm_hpcs_keystore + - ibm_hpcs_vault + +* Support CD Toolchain + - **DataSources** + - ibm_cd_toolchain + - ibm_cd_toolchain_tool_keyprotect + - ibm_cd_toolchain_tool_secretsmanager + - ibm_cd_toolchain_tool_bitbucketgit + - ibm_cd_toolchain_tool_githubintegrated + - ibm_cd_toolchain_tool_githubconsolidated + - ibm_cd_toolchain_tool_gitlab + - ibm_cd_toolchain_tool_hostedgit + - ibm_cd_toolchain_tool_artifactory + - ibm_cd_toolchain_tool_custom + - ibm_cd_toolchain_tool_pipeline + - ibm_cd_toolchain_tool_devopsinsights + - ibm_cd_toolchain_tool_slack + - ibm_cd_toolchain_tool_sonarqube + - ibm_cd_toolchain_tool_hashicorpvault + - ibm_cd_toolchain_tool_securitycompliance + - ibm_cd_toolchain_tool_privateworker + - ibm_cd_toolchain_tool_appconfig + - ibm_cd_toolchain_tool_jenkins + - ibm_cd_toolchain_tool_nexus + - ibm_cd_toolchain_tool_pagerduty + - ibm_cd_toolchain_tool_saucelabs + - **Resources** + - ibm_cd_toolchain + - ibm_cd_toolchain_tool_keyprotect + - ibm_cd_toolchain_tool_secretsmanager + - ibm_cd_toolchain_tool_bitbucketgit + - ibm_cd_toolchain_tool_githubintegrated + - ibm_cd_toolchain_tool_githubconsolidated + - ibm_cd_toolchain_tool_gitlab + - ibm_cd_toolchain_tool_hostedgit + - ibm_cd_toolchain_tool_artifactory + - ibm_cd_toolchain_tool_custom + - ibm_cd_toolchain_tool_pipeline + - ibm_cd_toolchain_tool_devopsinsights + - ibm_cd_toolchain_tool_slack + - ibm_cd_toolchain_tool_sonarqube + - ibm_cd_toolchain_tool_hashicorpvault + - ibm_cd_toolchain_tool_securitycompliance + - ibm_cd_toolchain_tool_privateworker + - ibm_cd_toolchain_tool_appconfig + - ibm_cd_toolchain_tool_jenkins + - ibm_cd_toolchain_tool_nexus + - ibm_cd_toolchain_tool_pagerduty + - ibm_cd_toolchain_tool_saucelabs + +* Support CD Tekton Pipeline + - **Datasources** + - ibm_cd_tekton_pipeline_definition + - ibm_cd_tekton_pipeline_trigger_property + - ibm_cd_tekton_pipeline_property + - ibm_cd_tekton_pipeline_trigger + - ibm_cd_tekton_pipeline + - **Resources** + - ibm_cd_tekton_pipeline_definition + - ibm_cd_tekton_pipeline_trigger_property + - ibm_cd_tekton_pipeline_property + - ibm_cd_tekton_pipeline_trigger + - ibm_cd_tekton_pipeline + +Enhancements +* support for creation of bucket on Satellite location ([3727](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3727)) + +BUG Fixes +* ibm_dns_glb docs to not specify the enabled argument ([3818](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3818)) +* floating ip data source nil fix ([3843](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3843)) +* support TLS 1.3 supported ciphers for ibm_cis_domain_settings ([3736](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3736)) +* Update provider version in docs ([3750](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3750)) +* Update cloud_shell_account_settings.html.markdown ([3812](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3812)) +* fix: placement targets empty list ([3787](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3787)) +* fix: instance network interface mutex sync ([3791](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3791)) +* ibm_scc_posture_scope does not allow for blank-space in description ([3733](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3733)) +* SCC provider should output User friendly error messages clearly indicating the problem ([3844](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3844)) +* ibm_is_instance should not not suppress change and force new on boot_volume.0.snapshot change ([3819](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3819)) +* fix(bare_metal_server) : vlan id in multi nic fix ([3767](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3767)) +* fix ibm_container_storage_attachment import ([3862](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3862)) + +# 1.42.0 (Jun 07, 2022) +Breaking Changes +* Redesign Dns Custom resolver resource and deprecate Custom resolver location ([3820](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3820)) + +Features +* Support Databases + - **DataSources** + - ibm_database_remotes + - ibm_database_point_in_time_recovery + - ibm_database_backup + - ibm_database_backups +* Support PowerSystem + - **DataSources** + - ibm_pi_system_pools +* Support EventNotification + - **DataSources** + - ibm_en_destination_chrome + - ibm_en_destination_firefox + - **Resources** + - ibm_en_destination_chrome + - ibm_en_destination_firefox +* Support VPC + - **DataSources** + - ibm_is_ssh_keys + - ibm_is_volumes +* Support Atracker + - **DataSources** + - ibm_atracker_settings + - **Resources** + - ibm_atracker_settings +* Support Cloudant + - **Datasources** + - ibm_cloudant_database + - **Resources** + - ibm_cloudant_database +Enhancements +* enhancement(Cloud Databases): add support for User types, roles ([3475](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3475)) +* added in preliminary changes for v2 atracker ([3724](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3724)) +* add support to retrieve all secret types ([3793](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3793)) +* Support of Transaction-Id for IAM Policy Management ([3518](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3518)) +* Deprecate flat list of scaling attributes ([3782](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3782)) +* added docs & enhanced network-port-attach resource ([3756](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3756)) +* Add support for transit enabled cloud connections ([3758](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3758)) +* Support boot volume encryption in cluster and workerpool ([3776](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3776)) +* Alias support for key policies ([3768](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3768)) +* Enable VPC cluster and worker pool to accept a dedicated host pool ID ([3781](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3781)) +* Support SAP deployment type ([3822](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3822)) +* + +BUGFIXES +* Name Validation Error Fix for VPC ([3675](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3675)) +* fix for route by name VPC Routing Table ([3754](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3754)) +* Documentation Update VPC Lb Listener and SG Rule ([3673](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3673)) +* Added fix for optional weight attribute's value ([3684](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3684)) +* Error on failed bucket parsing ([3757](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3757)) +* Fix to list the policies even policy contains service specific attributes ([3811](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3811)) +* Resource: ibm_resource_key is always recreated even when no changes are available for service Role ([3803](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3803)) +* browser cachec issue fixed for zero valid input ([3823](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3823)) +* Add new Healthcheck regions ([3827](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3827)) + + +# 1.42.0-beta0 (May 23, 2022) +Features +* Support Databases + - **DataSources** + - ibm_database_remotes + - ibm_database_point_in_time_recovery + - ibm_database_backup + - ibm_database_backups +* Support PowerSystem + - **DataSources** + - ibm_pi_system_pools +* Support EventNotification + - **DataSources** + - ibm_en_destination_chrome + - ibm_en_destination_firefox + - **Resources** + - ibm_en_destination_chrome + - ibm_en_destination_firefox +* Support VPC + - **DataSources** + - ibm_is_ssh_keys + - ibm_is_volumes +* Support Atracker + - **DataSources** + - ibm_atracker_settings + - **Resources** + - ibm_atracker_settings +* Support Cloudant + - **Datasources** + - ibm_cloudant_database + - **Resources** + - ibm_cloudant_database +Enhancements +* enhancement(Cloud Databases): add support for User types, roles ([3475](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3475)) +* added in preliminary changes for v2 atracker ([3724](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3724)) +* add support to retrieve all secret types ([3793](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3793)) +* Support of Transaction-Id for IAM Policy Management ([3518](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3518)) +* Deprecate flat list of scaling attributes ([3782](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3782)) + +BUGFIXES +* Name Validation Error Fix for VPC ([3675](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3675)) +* fix for route by name VPC Routing Table ([3754](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3754)) +* Documentation Update VPC Lb Listener and SG Rule ([3673](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3673)) +* Added fix for optional weight attribute's value ([3684](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3684)) +* Error on failed bucket parsing ([3757](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3757)) + +# 1.41.1 (May 17, 2022) +BUGFIXES +* fix(floating_ip): fixed nil check on floating ip target ([3783](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3783)) + +# 1.41.0 (May 04, 2022) +Features +* Support Databases + - **DataSources** + - ibm_database_connection +* Support Power Instances + - **Resources** + - ibm_pi_cloud_connection_network_attach + +* Support Event Notifications + - **Resources** + - ibm_en_destination_webhook + - ibm_en_destination_android + - ibm_en_destination_ios + - ibm_en_subscription_sms + - ibm_en_subscription_email + - ibm_en_subscription_webhook + - ibm_en_subscription_android + - ibm_en_subscription_ios + - **DataSources** + - ibm_en_destination_webhook + - ibm_en_destination_android + - ibm_en_destination_ios + - ibm_en_subscription_sms + - ibm_en_subscription_email + - ibm_en_subscription_webhook + - ibm_en_subscription_android + - ibm_en_subscription_ios +* Support SCC + - **Resources** + - ibm_scc_rule + - ibm_scc_rule_attachment + - ibm_scc_template + - ibm_scc_template_attachment +* Support Transist Gateway + - **Resources** + - ibm_tg_connection_prefix_filter + - **DataSources** + - ibm_tg_connection_prefix_filter + - ibm_tg_connection_prefix_filters + + +Enhancements +* Key Policies Deprecate ([3670](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3670)) +* Support dynamic network type address ([3659](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3659)) +* Update connections schema with mongodbee analytics and bi_connector ([3705](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3705)) +* Support port speed attribute in primary nic of instance ([3367](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3367)) +* Support for reserved ip changes for VPC ([3712](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3712)) +* Support for udp protocol in load balancers ([3711](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3711)) +* Fix(status_reasons): fixed status reasons in volume, instance and baremetalserver service ([3725](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3725)) +* Support group scaling for IBM Cloud Databases ([3699](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3699)) +* Support for port range for public network load balancers ([3660](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3660)) +* Add gateway & ip_address_range attribute for network resource ([3585](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3585)) + +BUGFIXES +* read cloud connection for details ([3650](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3650)) +* Fix for optional weight attribute's value ([3685](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3685)) +* add DiffSuppressFunc for public key for ibm_is_ssh_key ([3701](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3701)) +* Changed list logic in datasource by name ([3415](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3415)) +* SCC-PostureManagement Create scope issue ([3708](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3708)) +* Limitation on the number of characters in the resource ibm_resource_tag ([3703](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3703)) +* Correct a minor typo in docs ([3735](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3735)) +* fix(Cloud Databases): fix group scaling crash during provisioning ([3737](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3737)) +* fix(Cloud Databases): remove nodeCount update during group resource validation ([3739](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3739)) +* show pi instance provisioning time error ([3738](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3738)) +* fix(reserved ip) : bare metal server reserved ip multi nic changes ([3747](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3747)) +* Fix: authorisation policy docs ([3753](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3753)) +* Broken link for Host Auto Assigment in Cluster ([3752](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3752)) +* iam_access_group data source can't see more than 50 access groups ([3728](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3728)) + +# 1.41.0-beta0 (Apr18, 2022) +Features +* Support Databases + - **DataSources** + - ibm_database_connection +* Support Power Instances + - **Resources** + - ibm_pi_cloud_connection_network_attach + +* Support Event Notifications + - **Resources** + - ibm_en_destination_webhook + - ibm_en_destination_android + - ibm_en_destination_ios + - ibm_en_subscription_sms + - ibm_en_subscription_email + - ibm_en_subscription_webhook + - ibm_en_subscription_android + - ibm_en_subscription_ios + - **DataSources** + - ibm_en_destination_webhook + - ibm_en_destination_android + - ibm_en_destination_ios + - ibm_en_subscription_sms + - ibm_en_subscription_email + - ibm_en_subscription_webhook + - ibm_en_subscription_android + - ibm_en_subscription_ios +* Support SCC + - **Resources** + - ibm_scc_rule + - ibm_scc_rule_attachment + - ibm_scc_template + - ibm_scc_template_attachment +* Support Transist Gateway + - **Resources** + - ibm_tg_connection_prefix_filter + - **DataSources** + - ibm_tg_connection_prefix_filter + - ibm_tg_connection_prefix_filters + + +Enhancements +* Key Policies Deprecate ([3670](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3670)) +* Support dynamic network type address ([3659](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3659)) +* Update connections schema with mongodbee analytics and bi_connector ([3705](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3705)) +* Support port speed attribute in primary nic of instance ([3367](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3367)) +* Support for reserved ip changes for VPC ([3712](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3712)) +* Support for udp protocol in load balancers ([3711](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3711)) +* Fix(status_reasons): fixed status reasons in volume, instance and baremetalserver service ([3725](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3725)) +* Support group scaling for IBM Cloud Databases ([3699](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3699)) +* Support for port range for public network load balancers ([3660](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3660)) + +BUGFIXES +* read cloud connection for details ([3650](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3650)) +* Fix for optional weight attribute's value ([3685](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3685)) +* add DiffSuppressFunc for public key for ibm_is_ssh_key ([3701](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3701)) +* Changed list logic in datasource by name ([3415](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3415)) +* SCC-PostureManagement Create scope issue ([3708](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3708)) + +# 1.40.1 (Apr08, 2022) +BUGFIXES: + Allow 0 allocation for optional scaling group types ([3714](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3714)) + + +# 1.40.0 (Mar31, 2022) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_lb_listener + - ibm_is_lb_listeners + - ibm_is_lb_listener_policies + - ibm_is_lb_listener_policy + - ibm_is_lb_listener_policy_rule + - ibm_is_lb_listener_policy_rules + - ibm_is_security_groups + - ibm_is_security_group_rule + - ibm_is_security_group_rules + - ibm_is_ipsec_policy + - ibm_is_ipsec_policies + - ibm_is_ike_policies + - ibm_is_ike_policy + - **Resources** + - ibm_is_subnet_public_gateway_attachment + - ibm_is_subnet_routing_table_attachment +* Support Transist Gateway + - **DataSources** + - ibm_tg_route_report + - ibm_tg_route_reports + - **Resources** + - ibm_tg_route_report +* Support CIS + - **DataSources** + - ibm_cis_alerts + - **Resources** + - ibm_cis_alerts + +* Support Power Instance + - **Datasources** + - ibm_pi_storage_pool_capacity + - ibm_pi_storage_pools_capacity + - ibm_pi_storage_type_capacity + - ibm_pi_storage_types_capacity + +ENHANCEMENTS: +* Support resize boot volume for VPC instance ([2205](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2205)) +* Support to allow SAP create with a placement group ([3633](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3633)) +* Support VM Host Failure - Available Policy Development ([3604](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3604)) +* Support default forwarding rule in custom resolver ([3588](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3588)) +* Support trusted-profiles for access group members ([3651](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3651)) +* Authorization policy to support any service specific attributes ([3482](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3482)) +* Move `name` as optional argument in ibm_is_region datasource ([3431](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3431)) +* Add note for disabled VTL creation ([3693](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3693)) + +BUGFIXES: +* resource_ibm_is_virtual_endpoint_gateway does not allow for full name character limit ([3606](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3606)) +* Added the doc support for endpoint gateway identifier ([3649](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3649)) +* Fixing resource_attributes to support the service specific roles ([3648](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3648)) +* endpoint gateways target datasource fix, interchanging the order and including other targets ([3492](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3492)) + +# 1.40.0-beta0 (Mar17, 2022) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_lb_listener + - ibm_is_lb_listeners + - ibm_is_lb_listener_policies + - ibm_is_lb_listener_policy + - ibm_is_lb_listener_policy_rule + - ibm_is_lb_listener_policy_rules + - ibm_is_security_groups + - ibm_is_security_group_rule + - ibm_is_security_group_rules + - ibm_is_ipsec_policy + - ibm_is_ipsec_policies + - ibm_is_ike_policies + - ibm_is_ike_policy + - **Resources** + - ibm_is_subnet_public_gateway_attachment + - ibm_is_subnet_routing_table_attachment +* Support Transist Gateway + - **DataSources** + - ibm_tg_route_report + - ibm_tg_route_reports + - **Resources** + - ibm_tg_route_report +* Support CIS + - **DataSources** + - ibm_cis_alerts + - **Resources** + - ibm_cis_alerts + +* Support Power Instance + - **Datasources** + - ibm_pi_storage_pool_capacity + - ibm_pi_storage_pools_capacity + - ibm_pi_storage_type_capacity + - ibm_pi_storage_types_capacity + +ENHANCEMENTS: +* Support resize boot volume for VPC instance ([2205](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2205)) +* Support to allow SAP create with a placement group ([3633](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3633)) +* Support VM Host Failure - Available Policy Development ([3604](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3604)) +* Support default forwarding rule in custom resolver ([3588](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3588)) +* Support trusted-profiles for access group members ([3651](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3651)) +* Authorization policy to support any service specific attributes ([3482](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3482)) +* Move `name` as optional argument in ibm_is_region datasource ([3431](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3431)) + +BUGFIXES: +* resource_ibm_is_virtual_endpoint_gateway does not allow for full name character limit ([3606](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3606)) +* Added the doc support for endpoint gateway identifier ([3649](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3649)) +* Fixing resource_attributes to support the service specific roles ([3648](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3648)) +* endpoint gateways target datasource fix, interchanging the order and including other targets ([3492](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3492)) + +# 1.39.2 (Mar11, 2022) +BUGFIXES: +* fix proxy on kms client ([3634](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3634)) +* Fix crash on resource_instance ([3643](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3643)) +* SCC data.ibm_scc_posture_latest_scans failing ([3594](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3594)) +* Error: Collector Creation in Security Posture Management API service: us region not supported ([3630](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3630)) +* Fix ibm_cloud_shell_account_settings IAM issue ([3654](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3654)) + +# 1.39.1 (Mar02, 2022) +BUGFIXES: +* Fix the breaking change of 1.39.0 release for ibm_is_instance resource for force_new on VSI([3619](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3619)) + +# 1.39.0 (Feb28, 2022) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_lb_pool + - ibm_is_lb_pools + - ibm_is_lb_pool_member + - ibm_is_lb_pool_members + - ibm_is_vpc_address_prefix + - ibm_is_vpc_routing_table + - ibm_is_vpc_routing_table_route + - ibm_is_vpn_gateway + - ibm_is_vpn_gateway_connection + - ibm_is_bare_metal_server_disk + - ibm_is_bare_metal_server_disks + - ibm_is_bare_metal_server_initialization + - ibm_is_bare_metal_server_network_interface_floating_ip + - ibm_is_bare_metal_server_network_interface_floating_ips + - ibm_is_bare_metal_server_network_interface + - ibm_is_bare_metal_server_network_interfaces + - ibm_is_bare_metal_server_profile + - ibm_is_bare_metal_server_profiles + - ibm_is_bare_metal_server + - ibm_is_bare_metal_servers + - **Resources** + - ibm_is_bare_metal_server_action + - ibm_is_bare_metal_server_disk + - ibm_is_bare_metal_server_network_interface_allow_float + - ibm_is_bare_metal_server_network_interface_floating_ip + - ibm_is_bare_metal_server_network_interface + - ibm_is_bare_metal_server +* Support for CIS + - **Datasources** + - ibm_cis_webhooks + - **Resources** + - ibm_cis_webhook + + +ENHANCEMENTS: +* Remove hmac-md5-96 authentication from IPSec VPN policy ([3515](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3515)) +* added status reason in case of failure in is_instance ([3505](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3505)) +* Updated PI IKEPolicy and IPSecPolicy ([3530](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3530)) +* IBM Cloud VPC Documentation Update ([3479](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3479)) +* IKS image security enforcement ([3344](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3344)) +* add check for empty slice ([3528](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3528)) +* push notifications deprecation label ([3550](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3550)) +* Allow passing cloud connection while creating DHCP server ([3559](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3559)) +* Add dns attribute to power network data source ([3551](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3551)) +* Support arm , arm64 for terraform provider ([2626](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2626)) +* Add support to use the new IAMAuthenticatior for token ([3542](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3542)) +* add network update support ([3565](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3565)) +* P10 enablement for SAP ([3534](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3534)) +* implement provider gateway vlan assignment ([3558](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3558)) +* Support storage pool and affinity while importing image ([3543](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3543)) +* Add custom_script argument to satellite_host_script datasource to avoid provider dependancy ([3579](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3579)) +* Add wait_till to satellite_host resource to wait until location normal ([3579](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3579)) +* Snapshot captured at deletable ([3555](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3555)) +* Support access tags in ibm_iam_access_group_policy ([3290](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3290)) +* Bumpup: terraform-plugin-sdk to 2.10.1 ([3613](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3613)) +* support instance metadata and trusted profile ([3616](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3616)) + +BUGFIXES: +* Not able to list all the subnets for a given VPC ([3506](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3506)) +* panic while creating cloud connections ([3498](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3498)) +* schema and test fix for instance group manager action ([3495](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3495)) +* API endpoints for SCC are wrong and cannot be changed ([3524](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3524)) +* log improvement: subnet delete retry logs ([3485](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3485)) +* added a check to check if remote sg id exists in is_security_group_rule ([3493](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3493)) +* document fix for routing table ([3489](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3489)) +* Fix the sub category ([3560](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3560)) +* Added more info for href ([3486](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3486)) +* Subnet pagination fix in is_vpcs datasource ([3537](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3537)) +* Destroy resource group failed with 204 ([3529](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3529)) +* ibm_is_lb resource is silently updating subnet details in state with no actual affect on lb ([3538](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3538)) +* Fixed satellite location immutable error ([3537](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3537)) +* ibm_cloud_shell_account_settings issue ([3289](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3289)) +* typo in "network_interaces" ([3548](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3548)) +* Add additional example to ibm_iam_trusted_profile_policy ([3532](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3532)) +* remove default from resource_group doc as datasource doesnot support ([3564](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3564)) +* Fix: visibility private for vpc ([3578](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3578)) +* Satellite Host Attach Configuration Adds Incorrect Repos ([3576](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3576)) +* Missing Resource Group Id argument in Data block docs ([3586](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3586)) +* container_addons doesnt update version as expected ([3584](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3584)) +* added description for managed_from parameter in satellite location ([3591](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3591)) +* Fix for ibm_pi_volume response ([3598](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3598)) +* Added a check for "Deleted" status of the VPC worker pool ([3595](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3595)) +* Fix: Ignore 500 on getclusterkey in container cluster datasource ([3613](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3613)) +* Power client update to refresh token for every API call ([3614](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3614)) + + +# 1.39.0-beta0 (Feb16, 2022) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_lb_pool + - ibm_is_lb_pools + - ibm_is_lb_pool_member + - ibm_is_lb_pool_members + - ibm_is_vpc_address_prefix + - ibm_is_vpc_routing_table + - ibm_is_vpc_routing_table_route + - ibm_is_vpn_gateway + - ibm_is_vpn_gateway_connection + - ibm_is_bare_metal_server_disk + - ibm_is_bare_metal_server_disks + - ibm_is_bare_metal_server_initialization + - ibm_is_bare_metal_server_network_interface_floating_ip + - ibm_is_bare_metal_server_network_interface_floating_ips + - ibm_is_bare_metal_server_network_interface + - ibm_is_bare_metal_server_network_interfaces + - ibm_is_bare_metal_server_profile + - ibm_is_bare_metal_server_profiles + - ibm_is_bare_metal_server + - ibm_is_bare_metal_servers + - **Resources** + - ibm_is_bare_metal_server_action + - ibm_is_bare_metal_server_disk + - ibm_is_bare_metal_server_network_interface_allow_float + - ibm_is_bare_metal_server_network_interface_floating_ip + - ibm_is_bare_metal_server_network_interface + - ibm_is_bare_metal_server +* Support for CIS + - **Datasources** + - ibm_cis_webhooks + - **Resources** + - ibm_cis_webhook + + +ENHANCEMENTS: +* Remove hmac-md5-96 authentication from IPSec VPN policy ([3515](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3515)) +* added status reason in case of failure in is_instance ([3505](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3505)) +* Updated PI IKEPolicy and IPSecPolicy ([3530](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3530)) +* IBM Cloud VPC Documentation Update ([3479](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3479)) +* IKS image security enforcement ([3344](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3344)) +* add check for empty slice ([3528](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3528)) +* push notifications deprecation label ([3550](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3550)) +* Allow passing cloud connection while creating DHCP server ([3559](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3559)) +* Add dns attribute to power network data source ([3551](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3551)) +* Support arm , arm64 for terraform provider ([2626](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2626)) +* Add support to use the new IAMAuthenticatior for token ([3542](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3542)) +* add network update support ([3565](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3565)) +* P10 enablement for SAP ([3534](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3534)) +* implement provider gateway vlan assignment ([3558](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3558)) +* Support storage pool and affinity while importing image ([3543](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3543)) +* Add custom_script argument to satellite_host_script datasource to avoid provider dependancy ([3579](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3579)) +* Add wait_till to satellite_host resource to wait until location normal ([3579](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3579)) +* Snapshot captured at deletable ([3555](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3555)) +* Support access tags in ibm_iam_access_group_policy ([3290](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3290)) + +BUGFIXES: +* Not able to list all the subnets for a given VPC ([3506](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3506)) +* panic while creating cloud connections ([3498](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3498)) +* schema and test fix for instance group manager action ([3495](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3495)) +* API endpoints for SCC are wrong and cannot be changed ([3524](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3524)) +* log improvement: subnet delete retry logs ([3485](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3485)) +* added a check to check if remote sg id exists in is_security_group_rule ([3493](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3493)) +* document fix for routing table ([3489](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3489)) +* Fix the sub category ([3560](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3560)) +* Added more info for href ([3486](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3486)) +* Subnet pagination fix in is_vpcs datasource ([3537](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3537)) +* Destroy resource group failed with 204 ([3529](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3529)) +* ibm_is_lb resource is silently updating subnet details in state with no actual affect on lb ([3538](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3538)) +* Fixed satellite location immutable error ([3537](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3537)) +* ibm_cloud_shell_account_settings issue ([3289](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3289)) +* typo in "network_interaces" ([3548](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3548)) +* Add additional example to ibm_iam_trusted_profile_policy ([3532](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3532)) +* remove default from resource_group doc as datasource doesnot support ([3564](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3564)) +* Fix: visibility private for vpc ([3578](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3578)) +* Satellite Host Attach Configuration Adds Incorrect Repos ([3576](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3576)) +* Missing Resource Group Id argument in Data block docs ([3586](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3586)) +* container_addons doesnt update version as expected ([3584](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3584)) +* added description for managed_from parameter in satellite location ([3591](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3591)) + +# 1.38.2 (Feb09, 2022) +BugFIXES: +* Updating members_cpu_allocation_count to 0 fails with ibm_database ([3567](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3567)) + + +# 1.38.1 (Jan27, 2022) +ENHANCEMENTS: +* Support intergation of security groups with virtual private endpoint gateway ([3488](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3488)) +* Update the deprecation notice of policy management from KMS resource ([3520](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3520) + +# 1.38.0 (Jan12, 2022) +Features +* Support Power Instance + - **DataSources** + - ibm_pi_cloud_connections + - ibm_pi_keys + - ibm_pi_console_languages + - ibm_pi_placement_group + - ibm_pi_placement_groups + - **Resources** + - ibm_pi_console_language + - ibm_pi_volume_attach + - ibm_pi_image_export + - ibm_pi_placement_group + - ibm_pi_capture +* Support Security and Compliance Center + - **DataSources** + - ibm_scc_posture_profile + - ibm_scc_posture_group_profile + - ibm_scc_posture_scope_correlation + - **Resources** + - ibm_scc_posture_collector + - ibm_scc_posture_scope + - ibm_scc_posture_credential +* Support IAM Authorization Policies + - **Datasources** + - ibm_iam_authorization_policies +* Support Satellite Cluster + - **Datasources** + - ibm_satellite_cluster_worker_pool_zone_attachment + - **Resources** + - ibm_satellite_cluster_worker_pool_zone_attachment + +ENHANCEMENTS: +* Add issue labeler workflow and update issue template ([3430](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3430)) +* Enhance log statements ([3442](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3442)) +* Allow retrieval of IAM access tag (data source) ([3287](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3287)) +* Refactor multiple pi resources with context awareness ([3429](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3429)) +* Support: mysql in ibm_database ([3454](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3454)) +* ibm_resource_instance cannot except json in "parameters" ([3458](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3458)) +* Add release process and maintainers ([3472](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3472)) +* Allow mixed storage for pi_instance ([3484](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3484)) + +BUGFIXES: +* Invite Users module it's not working as expected ([3226](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3226)) +* Docs: data iam_trusted_profile_claim_rules actually is documented as iam_trusted_profiles_claim_rules ([3421](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3421)) +* ibm_iam_custom_role does not honor description changes ([3353](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3353)) +* ibm_cos_bucket documented storge_class flex does not work ([3349](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3349)) +* DocFix: satellite_host resource ([3437](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3437)) +* ibm_cos_bucket missing docs and missing s3_endpoint_direct ([3436](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3436)) +* Docs for data ibm_iam_trusted_profile_policy: Wrong title for examples ([3425](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3425)) +* Not documented: how to access ibm_resource_key.objectstorage.credentials.cos_hmac_keys.access_key_id ([2180](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2180)) +* Cloud Object Storage access key and secret ([1860](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/1860)) +* ibm_resource_key for COS does not nest HMAC object ([1741](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/1741)) +* IBM Cloud Databases CLI Behavior Update ([1387](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/1387)) +* Feature Request: Make ibm_resource_key resources linked to ibm_database resources more importable ([1232](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/1232)) +* Bug Fix Policy ([3413](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3413)) +* Fix: iam url issue in kms client ([3417](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3417)) +* Update doc of container service bind ([3450](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3450)) +* removed required tag from name in instance template ([3432](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3432)) +* DocFix: dns services ([3462](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3462)) +* Fix the entitlement for VPC worker pool ([3464](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3464)) +* Add Watson query example ([3451](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3451)) +* Issue with Access group creation ([3476](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3476)) + +# 1.37.1 (Dec09, 2021) +BUGFIXES: +* Regression: Breaking change on policy resources ([3410](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3410)) +* ibm_pi_instance is not able to complete with pi_health_status "WARNING" ([3401](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3401)) +* trusted profiles- doc fixes ([3407](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3407)) +* DocFix: cis_page_rule resource and flowlog and cbr_rule datasource ([3402](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3402)) + +# 1.37.0 (Dec07, 2021) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_instance_network_interface + - ibm_is_instance_network_interfaces + - **Resources** + - ibm_is_instance_network_interface +* Support Power Instance + - **Resources** + - ibm_pi_ike_policy + - ibm_pi_ipsec_policy + - ibm_pi_vpn_connection + - **DataSources** + - ibm_pi_sap_profiles + - ibm_pi_sap_profile +* Support Security and Compliance Center + - **DataSources** + - ibm_scc_account_location + - ibm_scc_account_locations + - ibm_scc_account_settings + - **Resources** + - ibm_scc_account_settings +* Support Container, Satellite nlb and ALB + - **Resources** + - ibm_container_nlb_dns + - ibm_satellite_location_nlb_dns + - ibm_container_alb_create + - ibm_container_vpc_alb_create +* Support IAM Trusted Profiles + - **DataSources** + - ibm_iam_trusted_profile_claim_rules + - ibm_iam_trusted_profile_links + - ibm_iam_trusted_profiles +* Support Context Based Restriction + - **Resources** + - ibm_cbr_zone + - ibm_cbr_rule + - **DataSources** + - ibm_cbr_zone + - ibm_cbr_rule +* Support IAM Access Group + - **DataSources** + - ibm_iam_access_group_policy + + + +ENHANCEMENTS: +* Support abort_incomplete_multipart_upload_days, expired object delete markers and noncurrent_version_expiration feature for Cloud Object Storage ([3359](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3359)) +* Added new resource attribute service_type for access policies ([3347](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3347)) +* vpc-go-sdk migration to 0.14.0 ([3376](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3376)) +* Add support for VTL in Power Instance ([3328](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3328)) +* Added filters to VPC Volume Snapshot collection datasource ([3238](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3238)) + + +BUGFIXES: +* Documentation fixes for Security and Compilance ([3342](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3342)) +* Update container-registry SDK and fix default region ([3356](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3356)) +* Fix: private endpoint for secrets manager ([3378](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3378)) +* Fix ibm_appid_token_config has source "roles", but missing in docs ([3370](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3370)) +* Bug in documentation for ibm_access_group_policy ([3365](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3365)) +* Bug in documentation for ibm_iam_api_key datasource ([3363](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3363)) +* Rename App ID provider ([3355](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3355)) +* DocFix: remove API from Activity Tracker subcategory ([3379](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3379)) +* doc fix for instance and subnet ([3372](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3372)) +* Inconsistent examples ibm_kms_key_rings example ([3279](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3279)) +* added wait logic for security group target ([3373](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3373)) +* do not return error when topic exists in creation ([3223](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3223)) +* private endpoints doesn't work for iam_access_group resources ([3340](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3340)) +* ibm_kms_key and ibm_kp_key produce inconsistent plan/apply ([3314](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3314)) +* Actions fail to import for ibm_cis_page_rule resources ([2765](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2765)) +* Upgrade of MongoDB from standard to enterprise should not work ([3327](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3327)) + +# 1.36.0 (Nov16, 2021) +Features +* Support VPC Infrastructure + - **DataSources** + - ibm_is_network_acls + - ibm_is_network_acl + - ibm_is_flow_log + - ibm_is_floating_ips + - **Resources** + - ibm_is_instance_action +* Support Power Instance + - **DataSources** + - ibm_pi_dhcp + - ibm_pi_dhcps + - ibm_pi_cloud_connection + - **Resources** + - ibm_pi_dhcp + - ibm_pi_cloud_connection +* Support SCC Security Insights + - **DataSources** + - ibm_scc_si_occurrence + - ibm_scc_si_occurrences + - **Resources** + - ibm_scc_si_occurrence +* Support Schematics + - **DataSources** + - ibm_schematics_inventory + - ibm_schematics_resource_query + - **Resources** + - ibm_schematics_inventory + - ibm_schematics_resource_query + + +ENHANCEMENTS: +* Support storage pool and affinity for instance and volume ([3270](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3270)) + +* Import image from public and private COS bucket ([3265](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3265)) + +* Support br-sao region for Container Registry ([3258](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3258)) + +* Support gpu for instance profile datasource ([3158](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3158)) + +* add resource group to cm_catalog resource and datasource ([3291](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3291)) + +* Support: default headers for service client ([3257](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3257)) + +* Support VPC instance bandwidth ([3156](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3156)) + +* Postgres configuration through terraform ([3278](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3278)) + +* Configure Redis database ([1428](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/1428)) + +* Add force_create to create classic infrastructure reserved capacity with exisitng name ([3306](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3306)) + +* vtl and sap options for Power Instance stock images ([3310](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3310)) + +* Allow Power Instance volume update when in-use ([3323](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3323)) + +* added support for enabling sdk debug logging ([3268](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3268)) + + +BUGFIXES: +* updated docs and examples for vpn gateway and gateway connections ([3283](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3283)) + +* Load Balancer cannot be updated because its status is 'UPDATE_PENDING' ([3006](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3006)) + +* VPC Address Prefix can't delete even though Subnet Deletion process complete. ([2759](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2759)) + +* RC api returning incorrect response when instance already exists ([3187](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3187)) + +* Failures when creating ibm_database because of bad values for allocations should be more clear ([3294](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3294)) + +* Fix: nil pointer on pi_key ([3133](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3133)) + +* Regression: "AuthorizationDelegator" no longer works in 1.30.0 ([3013](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3013)) + +* adding custom retry to fix the enabling of logging and moniotirg ([3319](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3319)) + +* Update ibm-hpcs-tke-sdk ([3313](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/3313)) + +* Update schematics terraform resources and datasources based on latest API's ([2901](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/2901)) + +* ibm_schematics_workspace adding template_inputs causes panic ([3295](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3295)) + +* ibm_schematics_workspace add template_git_url fails ([3296](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3296)) + +* Cannot provision Schematics workspaces with recent versions of Terraform ([3048](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/3048)) + + # 1.35.0 (Oct28, 2021) Features @@ -1833,5 +3255,3 @@ BUG FIXES: * example/ibm-key-protect : Updated example to create an authorisation policy between COS and Key Protect instance([#1133](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/1133)) * resource/ibm_resource_group: Removed suppression of error during deletion ([#1108](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/1108)) * resource/ibm_iam_user_invite : Fix for inviting user from IBM Cloud lite account. ([#1114](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/1114)) - - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..9abedf01d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,360 @@ +# Contributing to IBM Cloud Terraform Provider + +**Table of contents** +- [Contributing to IBM Cloud Terraform Provider](#contributing-to-ibm-cloud-terraform-provider) + - [Issues](#issues) + - [Issue reporting checklists](#issue-reporting-checklists) + - [Bug Reports](#bug-reports) + - [Feature requests](#feature-requests) + - [Questions](#questions) + - [Pull requests](#pull-requests) + - [Checklists for contribution](#checklists-for-contribution) + - [Enhancement or Bugfix to a resource](#enhancement-or-bugfix-to-a-resource) + - [New resource](#new-resource) + - [Writing acceptance tests](#writing-acceptance-tests) + - [Acceptance tests often cost money to run](#acceptance-tests-often-cost-money-to-run) + - [Running an acceptance test](#running-an-acceptance-test) + - [Writing an acceptance test](#writing-an-acceptance-test) + - [Release management](#release-management) + - [Production release](#production-release) + - [Pre-production release](#pre-production-release) + - [Dev release](#dev-release) + +--- +**Change history** +| Change date | Change description | +|-------------|--------------------| +| 03-Jan-2022 | Updated the release management process to include pre-production & production releases of the IBM Cloud Provider | + +--- +**First:** if you are unsure _anything_, just ask or submit the issue or create pull request anyways. We appreciate any sort of contributions. + +However, for those individuals who want a bit more guidance on the best way to contribute to the project. This document will cover what we are looking for. By addressing all the points we are looking for, it raises the chances to quickly merge or address your contributions. + +Specifically, we have provided checklists below for each type of an issue and pull request that can happen on the project. These checklists represent everything we need to review and respond quickly. + +## Issues + +### Issue reporting checklists + +We welcome issues of all kinds including feature requests, bug reports, and general questions. Following checklists provides the guidelines for the well-formed issue of specific type. + +#### Bug Reports + + - [ ] __Test against latest release__: Make sure you test against the latest released version. It is possible we already fixed the bug that you are experiencing. + + - [ ] __Search for possible duplicate reports__: It is helpful to keep bug reports consolidated to one thread, so do a quick search on existing bug reports to check if anybody else has reported the same thing. You can scope searches by the label `bug` to quickly narrow down the search. + + - [ ] __Include steps to reproduce__: Provide steps to reproduce the issue, along with your `.tf` files, with secrets removed, so we can try to reproduce it. Without this, it makes much harder to fix an issue. + + - [ ] __For panics, include `crash.log`__: If you experience a panic, please create a [gist](https://gist.github.com) of the **entire** generated crash log to us to look at. Double check no sensitive items are present in the log. + +#### Feature requests + + - [ ] __Search for possible duplicate requests__: It is helpful to keep requests consolidated to one thread, so do a quick search on an existing requests to check if anybody else has reported the same requests. You can scope searches by the label `enhancement` to quickly narrow down the search. + + - [ ] __Include a use case description__: In addition to describing the behavior of the feature you would like to see added, it is helpful you to lay out the reason why the feature would be important and how it would benefit Terraform users? + +#### Questions + + - [ ] __Search for answers in Terraform documentation__: We are happy to answer questions in GitHub issues, but it helps reduce issue churn and maintainer workload if you work to find answers to common questions in the documentation. Usually question issues results in documentation updates to help future users, so if you do not find an answer, you can give us pointers for where you would expect to see it in the documentation. + +## Pull requests + +Thank you for contributing! Here you will find the information on what to include in your pull request (PRs) to ensure it is accepted quickly. + + * For PRs that follow the guidelines, we expect to review and merge very quickly. + * PRs that do not follow the guidelines is annotated with what they are missing. A community or core team member may be able to swing around and help finish up the work, but these PRs generally hang out much longer until completed and merged. + +### Checklists for contribution + +There are different kinds of contribution, each of which has its own standards for a speedy review. The following sections describe the guidelines for each type of the contribution. + +#### Enhancement or Bugfix to a resource + +Working on an existing resources is a great way to start as a Terraform contributor because you can work within an existing code and tests to get a feel for what to do. + + - [ ] __Acceptance test coverage of new behavior__: Existing resources each have a set of [acceptance tests][acctests] covering their functionality. These tests exercises all the behavior of the resource. Whether you are adding something or fixing a bug, the idea is to have an acceptance test that fails if your code are removed. Sometimes it is sufficient to **enhance** an existing test by adding an assertion or tweaking the configuration that are used, but often a new test is better to add. You can copy or paste an existing test and follow the conventions you see there, modifying the test to exercise the behavior of your code. + + - [ ] __Documentation updates__: If your code makes any changes that need to be documented, you should include those documentation updates in the same PR. + + - [ ] __Well-formed Code__: Do your best to follow an existing conventions you see in the codebase, and ensure your code is formatted with **go fmt**. (The Travis CI build fails if **go fmt** has not been run on incoming code.) The PR reviewers can help out on this front, and may provide comments with suggestions on how to improve the code. + +#### New resource + +Implementing a new resource is a good way to learn more about how Terraform interacts with upstream APIs. There are plenty of examples to draw from in the existing resources, but you still get to implement something completely new. + + - [ ] __Minimal LOC__: It can be inefficient for both the reviewer and author to go through long feedback cycles on a big PR with many resources. We therefore encourage you to only submit **one resource at a time**. + - [ ] __Acceptance tests__: New resources should include acceptance tests covering their behavior. See [Writing Acceptance Tests](#writing-acceptance-tests) below for a detailed guide on how to approach these. + - [ ] __Documentation__: Each resource gets a page in the Terraform documentation. The [Terraform website](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) source is in this repository and includes instructions for getting a local copy of the site up and running if you would like to preview your changes. For a resource, you will want to add a new file in the appropriate place and add a link to the sidebar for that page. + - [ ] __Well-formed Code__: Do your best to follow an existing conventions you see in the codebase, and ensure your code is formatted with **go fmt**. (The Travis CI build fail if **go fmt** has not been run on incoming code.) The PR reviewers help out on this front, and may provide comments with suggestions on how to improve the code. + +### Writing acceptance tests + +Terraform includes an acceptance test harness that does most of the repetitive work involved in testing a resource. + +#### Acceptance tests often cost money to run + +Acceptance tests create real resources, they often cost money to run. Because the resources only exist for a short period of time, the total amount of money required is usually a relatively small. Nevertheless, we do not want financial limitations to be a barrier for contribution, so if you are unable to pay to run acceptance tests for your contribution, simply mention this in your PR. We happily accept **best effort** implementations of acceptance tests and run them for you on our side. This might mean that your PR takes a bit longer to merge, but it definitely is not a blocker for contributions. + +#### Running an acceptance test + +Acceptance tests can be run by using the **testacc** target in the **Makefile**. The individual tests to run is controlled by using a regular expression. Prior to running the tests provider configuration details such as access keys must be made available as an environment variables. + +For example, to run an acceptance test, the following environment variables must be set: + +```sh +export IC_API_KEY=... +export IAAS_CLASSIC_API_KEY=... +export IAAS_CLASSIC_USERNAME=... +``` + +For certain tests, the following values may also needs to be set: + +```sh +export IBM_ORG=... +export IBM_SPACE=... +export IBM_ID1=... +export IBM_ID2=... +export IBM_IAMUSER=... +``` + +You can enable the Terraform logs by setting the following environment variable: + +```sh +export TF_LOG=DEBUG +``` + +Tests can then be run by specifying the target provider and a regular expression defining the tests to run: + +```sh +$ make testacc TEST=./ibm TESTARGS='-run=TestAccIBMComputeVmInstance_basic' +==> Checking that code complies with gofmt requirements... +go generate ./... +TF_ACC=1 go test ./ibm -v -run=TestAccIBMComputeVmInstance_basic -timeout 700m +=== RUN TestAccIBMComputeVmInstance_basic +--- PASS: TestAccIBMComputeVmInstance_basic (177.48s) +PASS +ok github.com/terraform-providers/terraform-provider-ibm/ibm 177.504s +``` + +Entire resource test suites can be targeted by using the naming convention to write the regular expression. For example, to run all tests of the `ibm_compute_vm_instance` resource rather than just the update test, you can start testing like this: + +```sh +$ make testacc TEST=./ibm TESTARGS='-run=TestAccIBMComputeVmInstance' +==> Checking that code complies with gofmt requirements... +go generate ./... +TF_ACC=1 go test ./builtin/providers/azurerm -v -run=TestAccIBMComputeVmInstance -timeout 700m +=== RUN TestAccIBMComputeVmInstance_basic +--- PASS: TestAccIBMComputeVmInstance_basic (137.74s) +=== RUN TestAccIBMComputeVmInstance_basic_import +--- PASS: TestAccIBMComputeVmInstance_basic_import (180.63s) +PASS +ok github.com/terraform-providers/terraform-provider-ibm/ibm 318.392s +``` + +#### Writing an acceptance test + +Terraform has a framework for writing acceptance tests which minimises the amount of boilerplate code necessary to use common testing patterns. The entry point to the framework is the `resource.Test()` function. + +Tests are divided into `TestSteps`. Each `TestStep` proceeds by applying some +Terraform configuration by using the provider under test, and then verifying that results are as expected by making assertions by using the provider API. It is common for a single test function to exercise both the creation of and updates to a single resource. Most tests follow a similar structure. + +1. Pre-flight checks are made to ensure that sufficient provider configuration is available to proceed. For example, in an acceptance test `IAAS_CLASSIC_API_KEY` , `IAAS_CLASSIC_USERNAME` and `IC_API_KEY` must be set prior to running acceptance tests. This is common to all tests exercising a single provider. + +Each `TestStep` is defined in the call to `resource.Test()`. Most assertion functions are defined out of band with the tests. This keeps the tests readable, and allows reuse of assertion functions across different tests of the same type of resource. The definition of a complete test looks as follows: + +```go +func TestAccIBMComputeVmInstance_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccIBMComputeVmInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccIBMComputeVmInstanceConfigBasic, + Check: resource.ComposeTestCheckFunc( + testAccIBMComputeVmInstanceExists("ibm_compute_vm_instance.terraform-acceptance-test-1"), + ), + }, + }, + }) +} +``` + +When executing the test, the following steps are taken for each `TestStep`: + +1. The Terraform configuration required for the test is applied. This is responsible for configuring the resource under test, and any dependencies it may have. For example, to test the `ibm_compute_vm_instance` resource. This results in configuration which looks like this: + +```terraform +resource "ibm_compute_vm_instance" "terraform-acceptance-test-1" { + hostname = "terraform-sample-blockDeviceTemplateGroup" + domain = "bar.example.com" + datacenter = "ams01" + public_network_speed = 10 + hourly_billing = false + cores = 1 + memory = 1024 + local_disk = false + image_id = 12345 + tags = [ + "collectd", + "mesos-master" + ] + public_subnet = "50.97.46.160/28" + private_subnet = "10.56.109.128/26" +} +``` + +2. Assertions are run by using the provider API. These use the provider API directly rather than asserting against the resource state. For example, to verify that the `ibm_compute_vm_instance` described above was created successfully, a test function like this is used: + +```go + func resourceIBMComputeVmInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) + guestID, err := strconv.Atoi(d.Id()) + if err != nil { + return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + } + + result, err := service.Id(guestID).GetObject() + if err != nil { + if apiErr, ok := err.(sl.Error); ok { + if apiErr.StatusCode == 404 { + return false, nil + } + } + return false, fmt.Errorf("Error communicating with the API: %s", err) + } + + return result.Id != nil && *result.Id == guestID, nil + } +``` + +Notice that the only information used from the Terraform state is the ID of the resource - though in this case it is necessary to split the ID into constituent parts in order to use the provider API. For computed properties, we instead assert that the value saved in the Terraform state was the expected value if possible. The testing framework provides helper functions for several common types of check. For example: + +```go + resource.TestCheckResourceAttr("ibm_compute_vm_instance.terraform-test-1", "hourly_billing", "true"), +``` + +1. The resources created by the test are destroyed. This step happens automatically, and is the equivalent of calling `terraform destroy`. + +2. Assertions are made against the provider API to verify that the resources have indeed been removed. If these checks fail, the test fails and reports **dangling resources**. The code to ensure that the `ibm_compute_vm_instance` shown above looks as follow: + +```go + go func testAccIBMComputeVmInstanceDestroy(s *terraform.State) error { + service := services.GetVirtualGuestService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_compute_vm_instance" { + continue + } + + guestID, _ := strconv.Atoi(rs.Primary.ID) + + // Try to find the guest + _, err := service.Id(guestID).GetObject() + + // Wait + + if err == nil { + return fmt.Errorf("Virtual guest still exists: %s", rs.Primary.ID) + else if !strings.Contains(err.Error(), "404") { + return fmt.Errorf( + "Error waiting for virtual guest (%s) to be destroyed: %s", + rs.Primary.ID, err) + } + } + return nil + } +``` + +These functions usually test only for the resource directly under test. + +## Release management + +The `IBM Cloud Provider for Terraform` release can be mainly classified in to three types: +- Production release +- Pre-production release +- Dev release + +### Production release +Typically, the production release of the `IBM Cloud Provider for Terraform` will be made, once in a month. The release can be major or minor based on the PR's commited. The production release is targetted from branch **release**. Once the release is published, users can download the binary from [Terraform registry](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest). + +#### How to use this provider + +To install Terraform 0.13 or higher version provider, copy and paste this code into your Terraform configuration. Then, run `terraform init`. + +```terraform + terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "release version number" + } + } +} + +provider "ibm" { + # Configuration options +} +``` + +### Pre-production release + +Typically, the pre-production releases of the `IBM Cloud Provider for Terraform` will be made every two weeks or on-demand. This release will be tagged with **pre** tag. For example, **1.38.0-pre0**. The pre-production release is targeted from branch **master** and marked as pre-release (release is identified as non-production ready). + +~> **Note** A pre-release version is a version number that contains a suffix introduced by a dash, such as **1.38.0-pre**. A pre-release version can be selected only by an exact version constraint (the = operator or no operator). Pre-release versions do not match inexact operators such as `>=`, `~>`, etc. + +#### How to use this provider +To install Terraform 0.13 or higher version provider, copy and paste this code into your Terraform configuration. Then, run `terraform init`. + +```terraform + terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.38.0-pre0" + } + } +} + +provider "ibm" { + # Configuration options +} +``` + +### Dev release + +The individual developers or the IBM Cloud Service team can make their own `dev` releases, from their respective Git repository (forked from https://github.com/IBM-Cloud/terraform-provider-ibm). + +Note: You can use the existing GitHub actions to run the release workflows, in your forked repository. You can prepare a `dev` release by adding a new version tag in your repository. + +#### How to use this provider (dev release) + +- Download the respective binary from `dev` release repository +- Unzip the folder +- Depending on particular target platform create a directory structure as stated + ``` + mkdir -p $TERRAFORMHOME/registry.terraform.io/ibm-cloud/ibm/#version#/#target# + ``` + where, TERRAFORMHOME + - Windows: %APPDATA%/terraform.d/plugins + - Mac OS X: $HOME/.terraform.d/plugins + - Linux: $HOME/.terraform.d/plugins + - #version# : The release version of the binary + - #target# : specifies a particular target platform using a format like darwin_amd64, linux_amd64, windows_amd64. +- Create a CLI configuration file + - On Windows, the file must be named **terraform.rc** and placed in the relevant user's %APPDATA% directory. + - On all other systems, the file must be named **.terraformrc** (note the leading period) and placed directly in the home directory of the relevant user. +- Add below content to CLI configuration file + ```terraform + provider_installation { + filesystem_mirror { + path = "" + include = ["ibm-cloud/ibm"] + } + direct { + include = ["*/*"] + } + } + ``` diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 000000000..d6eb74b8e --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,37 @@ +Maintainers +=========== + +**Active Maintainers** + +| Name | GitHub | email +|------|--------|------| +| Ashish Thakur | [ashishth09][ashishth09] | +| Harini | [hkantare][hkantare] | +| Kavya Handadi | [kavya498][kavya498] | +| Vijay R Kalangumvathakkal | [vkalangu][vkalangu] | + + +**Documentation Maintainers** + +| Name | GitHub | email +|------|--------|---------------------- +| Geetha Sathyamurthy | [geethasathyamurthy][geethasathyamurthy] | + + +**Retired Maintainers** + +| Name | GitHub | email +|------|--------|---------------------- +| Anilkumar Mallakkanavar | [Anil-CM][Anil-CM] | +| Praveen Gostu | [Praveengostu][Praveengostu] | +| Sakshi Agarwal | [sakshiag][sakshiag] | + + +[ashishth09]: https://github.com/ashishth09 +[kavya498]: https://github.com/kavya498 +[hkantare]: https://github.com/hkantare +[vkalangu]: https://github.com/vkalangu/ +[geethasathyamurthy]: https://github.com/geethasathyamurthy +[Anil-CM]: https://github.com/Anil-CM +[Praveengostu]: https://github.com/Praveengostu +[sakshiag]: https://github.com/sakshiag diff --git a/README.md b/README.md index 82f9c0986..f02c0b800 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/IBM-Cloud/terraform-provider-ibm) +![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/IBM-Cloud/terraform-provider-ibm?include_prereleases) +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/IBM-Cloud/terraform-provider-ibm/release) +![GitHub](https://img.shields.io/github/license/IBM-Cloud/terraform-provider-ibm)
+![GitHub contributors](https://img.shields.io/github/contributors/IBM-Cloud/terraform-provider-ibm?color=blueviolet) +![GitHub commit activity](https://img.shields.io/github/commit-activity/m/IBM-Cloud/terraform-provider-ibm?color=blueviolet) +![GitHub all releases](https://img.shields.io/github/downloads/IBM-Cloud/terraform-provider-ibm/total) +[![GitHub stars](https://img.shields.io/github/stars/IBM-Cloud/terraform-provider-ibm?color=yellow)](https://github.com/IBM-Cloud/terraform-provider-ibm/stargazers) + # Terraform Provider - Website: https://www.terraform.io @@ -7,7 +16,7 @@ ## Requirements - [Terraform](https://www.terraform.io/downloads.html) 0.10.1+ -- [Go](https://golang.org/doc/install) 1.16 (to build the provider plugin) +- [Go](https://golang.org/doc/install) 1.18 (to build the provider plugin) ## Building The Provider diff --git a/examples/ibm-api-gateway/README.md b/examples/ibm-api-gateway/README.md index a011a1a85..1433ece61 100644 --- a/examples/ibm-api-gateway/README.md +++ b/examples/ibm-api-gateway/README.md @@ -4,14 +4,15 @@ This example illustrates how to use the API Gateway Endpoint and Subscription re These types of resources are supported: -* [API Gateway Endpoint](https://cloud.ibm.com/docs/terraform?topic=terraform-api-gateway-resources#api-gw-endpoint) -* [API Gateway Endpoint Subscription](https://cloud.ibm.com/docs/terraform?topic=terraform-api-gateway-resources#api-gw-endpoint-subscript) +* [API Gateway Endpoint](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/api_gateway_endpoint) +* [API Gateway Endpoint Subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/api_gateway_endpoint_subscription) ## Terraform versions -Terraform 0.12. Pin module version to `~> v1.4.0`. Branch - `master`. +| Name | Version | +|------|---------| +| terraform | >=1.0.0, <2.0 | -Terraform 0.11. Pin module version to `~> v0.25.0`. Branch - `terraform_v0.11.x`. ## Usage @@ -30,7 +31,7 @@ Run `terraform destroy` when you don't need these resources. API Gateway Endpoint resource with single OpenAPI document: -```hcl +```terraform resource "ibm_api_gateway_endpoint" "endpoint" { service_instance_crn = ibm_resource_instance.apigateway.id name = "test-endpoint" @@ -40,7 +41,7 @@ resource "ibm_api_gateway_endpoint" "endpoint" { } ``` API Gateway Endpoint resource with directory of OpenAPI documents: -```hcl +```terraform resource "ibm_api_gateway_endpoint" "endpoint" { for_each = fileset(var.dir_path, "*.json") service_instance_crn = ibm_resource_instance.apigateway.id @@ -51,7 +52,7 @@ resource "ibm_api_gateway_endpoint" "endpoint" { } ``` API Gateway Endpoint Subscription Resource: -```hcl +```terraform resource "ibm_api_gateway_endpoint_subscription" "subs" { artifact_id = data.ibm_api_gateway.endpoint.endpoints[0].endpoint_id client_id = "testapikey" @@ -64,7 +65,7 @@ resource "ibm_api_gateway_endpoint_subscription" "subs" { ## API Gateway Data Source Lists all endpoints and its subscriptions of an API Gateway Instance. -```hcl +```terraform data "ibm_api_gateway" "endpoint"{ service_instance_crn =ibm_resource_instance.apigateway.id } @@ -72,13 +73,13 @@ data "ibm_api_gateway" "endpoint"{ ## Assumptions -1. It's recommended to use subscription resource by making the endpoint online. i.e manged attribute of endpoint resource should be true. +1. It's recommended to use subscription resource by making the endpoint online. i.e managed attribute of endpoint resource should be `true`. 2. To view the subscriptions it is required to enable any of the two options of `Application authentication via API key` under `Define and Secure` page and save the endpoint in API Gateway service page. 3. The `client ID` of a particular subscription is available as an `API key` in the `Manage and Sharing` page of an endpoint of the API Gateway service. ## Notes -1. Terraform IBM provider v1.4.0 (via Terraform 0.12) supports "Autogeneration of Client ID i.e API key and Client Secret for the endpoint subscription". +1. Terraform IBM provider supports "Autogeneration of Client ID i.e API key and Client Secret for the endpoint subscription". ## Examples @@ -89,7 +90,7 @@ data "ibm_api_gateway" "endpoint"{ | Name | Version | |------|---------| -| terraform | ~> 0.12 | +| terraform | >=1.0.0, <2.0 | Single OpenAPI document or directory of documents. @@ -97,23 +98,23 @@ Single OpenAPI document or directory of documents. | Name | Version | |------|---------| -| ibm | n/a | +| ibm | Latest | ## Inputs | Name | Description | Type | Required | |------|-------------|------|---------| | region | THe region where the resource has to be provisioned. Default: `us-south`| `string` | yes | -| service\_name | The name of the API Gateway Service Instance. | `string` | yes | +| service_name | The name of the API Gateway Service Instance. | `string` | yes | | endpoint_name | The name of the API Gateway Endpoint resource. | `string` | yes | | managed | Indicates whether endpoint is online or not. Default: false | `bool` | yes | | routes | Invokable routes for an endpoint | `list` | no | -| file\_path | The API document name that represents the endpoint. It is required when a single endpoint is created| `string` | yes | +| file_path | The API document name that represents the endpoint. It is required when a single endpoint is created| `string` | yes | | dir_path | The directory name of API documents that represents multiple endpoint. It is required when a multipple endpoints are created| `string` | no | -| action\_type | The type of action that is performed on the API endpoint. Supported values are [`share`], [`unshare`], [`manage`], and [`unmanage`].To manage API to offline and online action\_type has to be set. The default value is [`unshare`]. Note that endpoint actions are performed by using the type parameter after the endpoint is created. As a consequence, endpoint actions are invoked during an endpoint update only. | `string` | required while managing actions. | -| subscription\_name | The name of the subscription resource indicates the name for an API key. | `string` | yes | -| client\_id | The API key to generate an API key for the subscription. The generated API key represents the ID of a subscription. If not provided it is auto generated. | `string` | yes | -| subscription\_type | The type of the subscription resource indicates the type of API key sharing. Supported values are [`external`], and [`internal`]. | `string` | yes | +| action_type | The type of action that is performed on the API endpoint. Supported values are [`share`], [`unshare`], [`manage`], and [`unmanage`].To manage API to offline and online action_type has to be set. The default value is [`unshare`]. Note that endpoint actions are performed by using the type parameter after the endpoint is created. As a consequence, endpoint actions are invoked during an endpoint update only. | `string` | required while managing actions. | +| subscription_name | The name of the subscription resource indicates the name for an API key. | `string` | yes | +| client_id | The API key to generate an API key for the subscription. The generated API key represents the ID of a subscription. If not provided it is auto generated. | `string` | yes | +| subscription_type | The type of the subscription resource indicates the type of API key sharing. Supported values are [`external`], and [`internal`]. | `string` | yes | | secret | The secret of the API key. | `string` | yes | | generate_secret | It conflicts with secret. If `generate_secret`- `true`, secret is auto generated. | `bool` | no | diff --git a/examples/ibm-api-gateway/versions.tf b/examples/ibm-api-gateway/versions.tf index d9b6f790b..0961e033d 100644 --- a/examples/ibm-api-gateway/versions.tf +++ b/examples/ibm-api-gateway/versions.tf @@ -1,3 +1,8 @@ terraform { - required_version = ">= 0.12" -} +required_version = ">=1.0.0, <2.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-atracker/README.md b/examples/ibm-atracker/README.md index 6afa2c87d..910c4058e 100644 --- a/examples/ibm-atracker/README.md +++ b/examples/ibm-atracker/README.md @@ -6,6 +6,7 @@ These types of resources are supported: * Activity Tracker Target * Activity Tracker Route +* Activity Tracker Settings ## Usage @@ -41,6 +42,17 @@ resource "atracker_route" "atracker_route_instance" { } ``` +atracker_settings resource: + +```hcl +resource "atracker_settings" "atracker_settings_instance" { + metadata_region_primary = var.atracker_settings_metadata_region_primary + private_api_endpoint_only = var.atracker_settings_private_api_endpoint_only + default_targets = var.atracker_settings_default_targets + permitted_target_regions = var.atracker_settings_permitted_target_regions +} +``` + ## AtrackerV1 Data sources atracker_targets data source: @@ -107,3 +119,4 @@ data "atracker_endpoints" "atracker_endpoints_instance" { | atracker_targets | atracker_targets object | | atracker_routes | atracker_routes object | | atracker_endpoints | atracker_endpoints object | +| atracker_settings | atracker_settings object | diff --git a/examples/ibm-atracker/main.tf b/examples/ibm-atracker/main.tf index 3a825e048..02501106b 100644 --- a/examples/ibm-atracker/main.tf +++ b/examples/ibm-atracker/main.tf @@ -12,6 +12,18 @@ resource "ibm_atracker_target" "atracker_target_instance" { bucket = "my-atracker-bucket" api_key = "xxxxxxxxxxxxxx" } + region = var.atracker_target_region +} + +// Provision atracker_target resource instance for logdna +resource "ibm_atracker_target" "atracker_target_logdna_instance" { + name = var.atracker_target_name + target_type = "logdna" + logdna_endpoint { + target_crn = "crn:v1:bluemix:public:logdna:us-south:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + ingestion_key = "xxxxxxxxxxxxxx" + } + region = var.atracker_target_region } // Provision atracker_route resource instance @@ -21,6 +33,14 @@ resource "ibm_atracker_route" "atracker_route_instance" { rules = var.atracker_route_rules } +// Provision atracker_settings resource instance +resource "ibm_atracker_settings" "atracker_settings_instance" { + metadata_region_primary = var.atracker_settings_metadata_region_primary + private_api_endpoint_only = var.atracker_settings_private_api_endpoint_only + default_targets = var.atracker_settings_default_targets + permitted_target_regions = var.atracker_settings_permitted_target_regions +} + // Create atracker_targets data source data "ibm_atracker_targets" "atracker_targets_instance" { name = var.atracker_targets_name @@ -31,6 +51,6 @@ data "ibm_atracker_routes" "atracker_routes_instance" { name = var.atracker_routes_name } -// Create atracker_endpoints data source +// Create atracker_endpoints data source (DEPRECATED) data "ibm_atracker_endpoints" "atracker_endpoints_instance" { } diff --git a/examples/ibm-atracker/outputs.tf b/examples/ibm-atracker/outputs.tf index 9664da1f4..86b7f6265 100644 --- a/examples/ibm-atracker/outputs.tf +++ b/examples/ibm-atracker/outputs.tf @@ -10,3 +10,10 @@ output "ibm_atracker_route" { value = ibm_atracker_route.atracker_route_instance description = "atracker_route resource instance" } + +// This allows atracker_settings data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_atracker_settings" { + value = ibm_atracker_settings.atracker_settings_instance + description = "atracker_settings resource instance" +} diff --git a/examples/ibm-atracker/variables.tf b/examples/ibm-atracker/variables.tf index 2fd96e107..09adc4bc0 100644 --- a/examples/ibm-atracker/variables.tf +++ b/examples/ibm-atracker/variables.tf @@ -45,5 +45,26 @@ variable "atracker_routes_name" { type = string default = "my-route" } +// Resource arguments for atracker_settings +variable "atracker_settings_metadata_region_primary" { + description = "To store all your meta data in a single region." + type = string + default = "us-south" +} +variable "atracker_settings_private_api_endpoint_only" { + description = "If you set this true then you cannot access api through public network." + type = bool + default = false +} +variable "atracker_settings_default_targets" { + description = "The target ID List. In the event that no routing rule causes the event to be sent to a target, these targets will receive the event." + type = list(string) + default = [ "c3af557f-fb0e-4476-85c3-0889e7fe7bc4" ] +} +variable "atracker_settings_permitted_target_regions" { + description = "If present then only these regions may be used to define a target." + type = list(string) + default = [ "us-south" ] +} // Data source arguments for atracker_endpoints diff --git a/examples/ibm-catalog-management/README.md b/examples/ibm-catalog-management/README.md new file mode 100644 index 000000000..0f651ce32 --- /dev/null +++ b/examples/ibm-catalog-management/README.md @@ -0,0 +1,342 @@ +# Example for CatalogManagementV1 + +This example illustrates how to use the CatalogManagementV1 + +These types of resources are supported: + +* cm_catalog +* cm_offering +* cm_version +* cm_offering_instance + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## CatalogManagementV1 resources + +cm_catalog resource: + +```hcl +resource "cm_catalog" "cm_catalog_instance" { + label = var.cm_catalog_label + label_i18n = var.cm_catalog_label_i18n + short_description = var.cm_catalog_short_description + short_description_i18n = var.cm_catalog_short_description_i18n + catalog_icon_url = var.cm_catalog_catalog_icon_url + tags = var.cm_catalog_tags + features = var.cm_catalog_features + disabled = var.cm_catalog_disabled + resource_group_id = var.cm_catalog_resource_group_id + owning_account = var.cm_catalog_owning_account + catalog_filters = var.cm_catalog_catalog_filters + syndication_settings = var.cm_catalog_syndication_settings + kind = var.cm_catalog_kind + metadata = var.cm_catalog_metadata +} +``` +cm_offering resource: + +```hcl +resource "cm_offering" "cm_offering_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + url = var.cm_offering_url + crn = var.cm_offering_crn + label = var.cm_offering_label + label_i18n = var.cm_offering_label_i18n + name = var.cm_offering_name + offering_icon_url = var.cm_offering_offering_icon_url + offering_docs_url = var.cm_offering_offering_docs_url + offering_support_url = var.cm_offering_offering_support_url + tags = var.cm_offering_tags + keywords = var.cm_offering_keywords + rating = var.cm_offering_rating + created = var.cm_offering_created + updated = var.cm_offering_updated + short_description = var.cm_offering_short_description + short_description_i18n = var.cm_offering_short_description_i18n + long_description = var.cm_offering_long_description + long_description_i18n = var.cm_offering_long_description_i18n + features = var.cm_offering_features + kinds = var.cm_offering_kinds + pc_managed = var.cm_offering_pc_managed + publish_approved = var.cm_offering_publish_approved + share_with_all = var.cm_offering_share_with_all + share_with_ibm = var.cm_offering_share_with_ibm + share_enabled = var.cm_offering_share_enabled + permit_request_ibm_public_publish = var.cm_offering_permit_request_ibm_public_publish + ibm_publish_approved = var.cm_offering_ibm_publish_approved + public_publish_approved = var.cm_offering_public_publish_approved + public_original_crn = var.cm_offering_public_original_crn + publish_public_crn = var.cm_offering_publish_public_crn + portal_approval_record = var.cm_offering_portal_approval_record + portal_ui_url = var.cm_offering_portal_ui_url + catalog_id = ibm_cm_catalog.cm_catalog_instance.id + catalog_name = var.cm_offering_catalog_name + metadata = var.cm_offering_metadata + disclaimer = var.cm_offering_disclaimer + hidden = var.cm_offering_hidden + provider = var.cm_offering_provider + provider_info = var.cm_offering_provider_info + repo_info = var.cm_offering_repo_info + image_pull_keys = var.cm_offering_image_pull_keys + support = var.cm_offering_support + media = var.cm_offering_media + deprecate_pending = var.cm_offering_deprecate_pending + product_kind = var.cm_offering_product_kind + badges = var.cm_offering_badges +} +``` +cm_version resource: + +```hcl +resource "cm_version" "cm_version_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + offering_id = ibm_cm_offering.cm_offering_instance.offering_id + tags = var.cm_version_tags + content = var.cm_version_content + name = var.cm_version_name + label = var.cm_version_label + install_kind = var.cm_version_install_kind + target_kinds = var.cm_version_target_kinds + format_kind = var.cm_version_format_kind + product_kind = var.cm_version_product_kind + import_sha = var.cm_version_sha + version = var.cm_version_version + flavor = var.cm_version_flavor + import_metadata = var.cm_version_metadata + working_directory = var.cm_version_working_directory + zipurl = var.cm_version_zipurl + target_version = var.cm_version_target_version + include_config = var.cm_version_include_config + is_vsi = var.cm_version_is_vsi + repotype = var.cm_version_repotype + x_auth_token = var.cm_version_x_auth_token +} +``` +cm_offering_instance resource: + +```hcl +resource "cm_offering_instance" "cm_offering_instance_instance" { + x_auth_refresh_token = var.cm_offering_instance_x_auth_refresh_token + rev = var.cm_offering_instance_rev + url = var.cm_offering_instance_url + crn = var.cm_offering_instance_crn + label = var.cm_offering_instance_label + catalog_id = var.cm_offering_instance_catalog_id + offering_id = var.cm_offering_instance_offering_id + kind_format = var.cm_offering_instance_kind_format + version = var.cm_offering_instance_version + version_id = var.cm_offering_instance_version_id + cluster_id = var.cm_offering_instance_cluster_id + cluster_region = var.cm_offering_instance_cluster_region + cluster_namespaces = var.cm_offering_instance_cluster_namespaces + cluster_all_namespaces = var.cm_offering_instance_cluster_all_namespaces + schematics_workspace_id = var.cm_offering_instance_schematics_workspace_id + install_plan = var.cm_offering_instance_install_plan + channel = var.cm_offering_instance_channel + created = var.cm_offering_instance_created + updated = var.cm_offering_instance_updated + metadata = var.cm_offering_instance_metadata + resource_group_id = var.cm_offering_instance_resource_group_id + location = var.cm_offering_instance_location + disabled = var.cm_offering_instance_disabled + account = var.cm_offering_instance_account + last_operation = var.cm_offering_instance_last_operation + kind_target = var.cm_offering_instance_kind_target + sha = var.cm_offering_instance_sha +} +``` + +## CatalogManagementV1 Data sources + +cm_catalog data source: + +```hcl +data "cm_catalog" "cm_catalog_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id +} +``` +cm_offering data source: + +```hcl +data "cm_offering" "cm_offering_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + offering_id = ibm_cm_offering.cm_offering_instance.offering_id +} +``` +cm_version data source: + +```hcl +data "cm_version" "cm_version_instance" { + version_loc_id = var.cm_version_version_loc_id +} +``` +cm_offering_instance data source: + +```hcl +data "cm_offering_instance" "cm_offering_instance_instance" { + instance_identifier = var.cm_offering_instance_instance_identifier +} +``` + +## Assumptions + +1. TODO + +## Notes + +1. TODO + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| label | Display Name in the requested language. | `string` | false | +| label_i18n | A map of translated strings, by language code. | `map(string)` | false | +| short_description | Description in the requested language. | `string` | false | +| short_description_i18n | A map of translated strings, by language code. | `map(string)` | false | +| catalog_icon_url | URL for an icon associated with this catalog. | `string` | false | +| tags | List of tags associated with this catalog. | `list(string)` | false | +| features | List of features associated with this catalog. | `list()` | false | +| disabled | Denotes whether a catalog is disabled. | `bool` | false | +| resource_group_id | Resource group id the catalog is owned by. | `string` | false | +| owning_account | Account that owns catalog. | `string` | false | +| catalog_filters | Filters for account and catalog filters. | `` | false | +| syndication_settings | Feature information. | `` | false | +| kind | Kind of catalog. Supported kinds are offering and vpe. | `string` | false | +| metadata | Catalog specific metadata. | `map()` | false | +| catalog_identifier | Catalog identifier. | `string` | true | +| url | The url for this specific offering. | `string` | false | +| crn | The crn for this specific offering. | `string` | false | +| label | Display Name in the requested language. | `string` | false | +| label_i18n | A map of translated strings, by language code. | `map(string)` | false | +| name | The programmatic name of this offering. | `string` | false | +| offering_icon_url | URL for an icon associated with this offering. | `string` | false | +| offering_docs_url | URL for an additional docs with this offering. | `string` | false | +| offering_support_url | [deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering. | `string` | false | +| tags | List of tags associated with this catalog. | `list(string)` | false | +| keywords | List of keywords associated with offering, typically used to search for it. | `list(string)` | false | +| rating | Repository info for offerings. | `` | false | +| created | The date and time this catalog was created. | `` | false | +| updated | The date and time this catalog was last updated. | `` | false | +| short_description | Short description in the requested language. | `string` | false | +| short_description_i18n | A map of translated strings, by language code. | `map(string)` | false | +| long_description | Long description in the requested language. | `string` | false | +| long_description_i18n | A map of translated strings, by language code. | `map(string)` | false | +| features | list of features associated with this offering. | `list()` | false | +| kinds | Array of kind. | `list()` | false | +| pc_managed | Offering is managed by Partner Center. | `bool` | false | +| publish_approved | Offering has been approved to publish to permitted to IBM or Public Catalog. | `bool` | false | +| share_with_all | Denotes public availability of an Offering - if share_enabled is true. | `bool` | false | +| share_with_ibm | Denotes IBM employee availability of an Offering - if share_enabled is true. | `bool` | false | +| share_enabled | Denotes sharing including access list availability of an Offering is enabled. | `bool` | false | +| permit_request_ibm_public_publish | Is it permitted to request publishing to IBM or Public. | `bool` | false | +| ibm_publish_approved | Indicates if this offering has been approved for use by all IBMers. | `bool` | false | +| public_publish_approved | Indicates if this offering has been approved for use by all IBM Cloud users. | `bool` | false | +| public_original_crn | The original offering CRN that this publish entry came from. | `string` | false | +| publish_public_crn | The crn of the public catalog entry of this offering. | `string` | false | +| portal_approval_record | The portal's approval record ID. | `string` | false | +| portal_ui_url | The portal UI URL. | `string` | false | +| catalog_id | The id of the catalog containing this offering. | `string` | false | +| catalog_name | The name of the catalog. | `string` | false | +| metadata | Map of metadata values for this offering. | `map()` | false | +| disclaimer | A disclaimer for this offering. | `string` | false | +| hidden | Determine if this offering should be displayed in the Consumption UI. | `bool` | false | +| provider | Deprecated - Provider of this offering. | `string` | false | +| provider_info | Information on the provider for this offering, or omitted if no provider information is given. | `` | false | +| repo_info | Repository info for offerings. | `` | false | +| image_pull_keys | Image pull keys for this offering. | `list()` | false | +| support | Offering Support information. | `` | false | +| media | A list of media items related to this offering. | `list()` | false | +| deprecate_pending | Deprecation information for an Offering. | `` | false | +| product_kind | The product kind. Valid values are module, solution, or empty string. | `string` | false | +| badges | A list of badges for this offering. | `list()` | false | +| catalog_identifier | Catalog identifier. | `string` | true | +| offering_id | Offering identification. | `string` | true | +| tags | Tags array. | `list(string)` | false | +| content | Byte array representing the content to be imported. Only supported for OVA images at this time. | `` | false | +| name | Name of version. Required for virtual server image for VPC. | `string` | false | +| label | Display name of version. Required for virtual server image for VPC. | `string` | false | +| install_kind | Install type. Example: instance. Required for virtual server image for VPC. | `string` | false | +| target_kinds | Deployment target of the content being onboarded. Current valid values are iks, roks, vcenter, power-iaas, terraform, and vpc-x86. Required for virtual server image for VPC. | `list(string)` | false | +| format_kind | Format of content being onboarded. Example: vsi-image. Required for virtual server image for VPC. | `string` | false | +| product_kind | Optional product kind for the software being onboarded. Valid values are software, module, or solution. Default value is software. | `string` | false | +| sha | SHA256 fingerprint of the image file. Required for virtual server image for VPC. | `string` | false | +| version | Semantic version of the software being onboarded. Required for virtual server image for VPC. | `string` | false | +| flavor | Version Flavor Information. Only supported for Product kind Solution. | `` | false | +| metadata | Generic data to be included with content being onboarded. Required for virtual server image for VPC. | `` | false | +| working_directory | Optional - The sub-folder within the specified tgz file that contains the software being onboarded. | `string` | false | +| zipurl | URL path to zip location. If not specified, must provide content in the body of this call. | `string` | false | +| target_version | The semver value for this new version, if not found in the zip url package content. | `string` | false | +| include_config | Add all possible configuration values to this version when importing. | `bool` | false | +| is_vsi | Indicates that the current terraform template is used to install a virtual server image. | `bool` | false | +| repotype | The type of repository containing this version. Valid values are 'public_git' or 'enterprise_git'. | `string` | false | +| x_auth_token | Authentication token used to access the specified zip file. | `string` | false | +| x_auth_refresh_token | IAM Refresh token. | `string` | true | +| rev | Cloudant revision. | `string` | false | +| url | url reference to this object. | `string` | false | +| crn | platform CRN for this instance. | `string` | false | +| label | the label for this instance. | `string` | false | +| catalog_id | Catalog ID this instance was created from. | `string` | false | +| offering_id | Offering ID this instance was created from. | `string` | false | +| kind_format | the format this instance has (helm, operator, ova...). | `string` | false | +| version | The version this instance was installed from (semver - not version id). | `string` | false | +| version_id | The version id this instance was installed from (version id - not semver). | `string` | false | +| cluster_id | Cluster ID. | `string` | false | +| cluster_region | Cluster region (e.g., us-south). | `string` | false | +| cluster_namespaces | List of target namespaces to install into. | `list(string)` | false | +| cluster_all_namespaces | designate to install into all namespaces. | `bool` | false | +| schematics_workspace_id | Id of the schematics workspace, for offering instances provisioned through schematics. | `string` | false | +| install_plan | Type of install plan (also known as approval strategy) for operator subscriptions. Can be either automatic, which automatically upgrades operators to the latest in a channel, or manual, which requires approval on the cluster. | `string` | false | +| channel | Channel to pin the operator subscription to. | `string` | false | +| created | date and time create. | `` | false | +| updated | date and time updated. | `` | false | +| metadata | Map of metadata values for this offering instance. | `map()` | false | +| resource_group_id | Id of the resource group to provision the offering instance into. | `string` | false | +| location | String location of OfferingInstance deployment. | `string` | false | +| disabled | Indicates if Resource Controller has disabled this instance. | `bool` | false | +| account | The account this instance is owned by. | `string` | false | +| last_operation | the last operation performed and status. | `` | false | +| kind_target | The target kind for the installed software version. | `string` | false | +| sha | The digest value of the installed software version. | `string` | false | +| catalog_identifier | Catalog identifier. | `string` | true | +| catalog_identifier | Catalog identifier. | `string` | true | +| offering_id | Offering identification. | `string` | true | +| version_loc_id | A dotted value of `catalogID`.`versionID`. | `string` | true | +| instance_identifier | Version Instance identifier. | `string` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| cm_catalog | cm_catalog object | +| cm_offering | cm_offering object | +| cm_version | cm_version object | +| cm_offering_instance | cm_offering_instance object | +| cm_catalog | cm_catalog object | +| cm_offering | cm_offering object | +| cm_version | cm_version object | +| cm_offering_instance | cm_offering_instance object | diff --git a/examples/ibm-catalog-management/main.tf b/examples/ibm-catalog-management/main.tf new file mode 100644 index 000000000..5c9abf2c6 --- /dev/null +++ b/examples/ibm-catalog-management/main.tf @@ -0,0 +1,136 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Provision cm_catalog resource instance +resource "ibm_cm_catalog" "cm_catalog_instance" { + label = var.cm_catalog_label + short_description = var.cm_catalog_short_description + catalog_icon_url = var.cm_catalog_catalog_icon_url + tags = var.cm_catalog_tags + disabled = var.cm_catalog_disabled + resource_group_id = var.cm_catalog_resource_group_id + kind = var.cm_catalog_kind +} + +// Provision cm_offering resource instance +resource "ibm_cm_offering" "cm_offering_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + label = var.cm_offering_label + name = var.cm_offering_name + offering_icon_url = var.cm_offering_offering_icon_url + tags = var.cm_offering_tags +} + +// Provision cm_version resource instance +resource "ibm_cm_version" "cm_version_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + offering_identifier = ibm_cm_offering.cm_offering_instance.offering_id + tags = var.cm_version_tags + name = var.cm_version_name + label = var.cm_version_label + install_kind = var.cm_version_install_kind + target_kinds = var.cm_version_target_kinds + format_kind = var.cm_version_format_kind + product_kind = var.cm_version_product_kind + import_sha = var.cm_version_sha + flavor { + name = "name" + label = "label" + label_i18n = { "key": "inner" } + index = 1 + } + import_metadata { + operating_system { + dedicated_host_only = true + vendor = "vendor" + name = "name" + href = "href" + display_name = "display_name" + family = "family" + version = "version" + architecture = "architecture" + } + file { + size = 1 + } + minimum_provisioned_size = 1 + images { + id = "id" + name = "name" + region = "region" + } + } + working_directory = var.cm_version_working_directory + zipurl = var.cm_version_zipurl + target_version = var.cm_version_target_version + include_config = var.cm_version_include_config + is_vsi = var.cm_version_is_vsi +} + +// Provision cm_offering_instance resource instance +resource "ibm_cm_offering_instance" "cm_offering_instance_instance" { + x_auth_refresh_token = var.cm_offering_instance_x_auth_refresh_token + rev = var.cm_offering_instance_rev + url = var.cm_offering_instance_url + crn = var.cm_offering_instance_crn + label = var.cm_offering_instance_label + catalog_id = var.cm_offering_instance_catalog_id + offering_id = var.cm_offering_instance_offering_id + kind_format = var.cm_offering_instance_kind_format + version = var.cm_offering_instance_version + version_id = var.cm_offering_instance_version_id + cluster_id = var.cm_offering_instance_cluster_id + cluster_region = var.cm_offering_instance_cluster_region + cluster_namespaces = var.cm_offering_instance_cluster_namespaces + cluster_all_namespaces = var.cm_offering_instance_cluster_all_namespaces + schematics_workspace_id = var.cm_offering_instance_schematics_workspace_id + install_plan = var.cm_offering_instance_install_plan + channel = var.cm_offering_instance_channel + created = var.cm_offering_instance_created + updated = var.cm_offering_instance_updated + metadata = var.cm_offering_instance_metadata + resource_group_id = var.cm_offering_instance_resource_group_id + location = var.cm_offering_instance_location + disabled = var.cm_offering_instance_disabled + account = var.cm_offering_instance_account + last_operation { + operation = "operation" + state = "state" + message = "message" + transaction_id = "transaction_id" + updated = "2021-01-31T09:44:12Z" + code = "code" + } + kind_target = var.cm_offering_instance_kind_target + sha = var.cm_offering_instance_sha +} + +// Create cm_catalog data source +data "ibm_cm_catalog" "cm_catalog_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id +} + +// Create cm_offering data source +data "ibm_cm_offering" "cm_offering_instance" { + catalog_identifier = ibm_cm_catalog.cm_catalog_instance.id + offering_identifier = ibm_cm_offering.cm_offering_instance.offering_id +} + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create cm_version data source +data "ibm_cm_version" "cm_version_instance" { + version_loc_id = var.cm_version_version_loc_id +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create cm_offering_instance data source +data "ibm_cm_offering_instance" "cm_offering_instance_instance" { + instance_identifier = var.cm_offering_instance_instance_identifier +} +*/ diff --git a/examples/ibm-catalog-management/outputs.tf b/examples/ibm-catalog-management/outputs.tf new file mode 100644 index 000000000..1de24d39c --- /dev/null +++ b/examples/ibm-catalog-management/outputs.tf @@ -0,0 +1,24 @@ +// This allows cm_catalog data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cm_catalog" { + value = ibm_cm_catalog.cm_catalog_instance + description = "cm_catalog resource instance" +} +// This allows cm_offering data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cm_offering" { + value = ibm_cm_offering.cm_offering_instance + description = "cm_offering resource instance" +} +// This allows cm_version data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cm_version" { + value = ibm_cm_version.cm_version_instance + description = "cm_version resource instance" +} +// This allows cm_offering_instance data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cm_offering_instance" { + value = ibm_cm_offering_instance.cm_offering_instance_instance + description = "cm_offering_instance resource instance" +} diff --git a/examples/ibm-catalog-management/variables.tf b/examples/ibm-catalog-management/variables.tf new file mode 100644 index 000000000..8c3500939 --- /dev/null +++ b/examples/ibm-catalog-management/variables.tf @@ -0,0 +1,500 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Resource arguments for cm_catalog +variable "cm_catalog_label" { + description = "Display Name in the requested language." + type = string + default = "label" +} +variable "cm_catalog_label_i18n" { + description = "A map of translated strings, by language code." + type = map(string) + default = { "key": "inner" } +} +variable "cm_catalog_short_description" { + description = "Description in the requested language." + type = string + default = "short_description" +} +variable "cm_catalog_short_description_i18n" { + description = "A map of translated strings, by language code." + type = map(string) + default = { "key": "inner" } +} +variable "cm_catalog_catalog_icon_url" { + description = "URL for an icon associated with this catalog." + type = string + default = "catalog_icon_url" +} +variable "cm_catalog_tags" { + description = "List of tags associated with this catalog." + type = list(string) + default = [ "tags" ] +} +variable "cm_catalog_disabled" { + description = "Denotes whether a catalog is disabled." + type = bool + default = true +} +variable "cm_catalog_resource_group_id" { + description = "Resource group id the catalog is owned by." + type = string + default = "resource_group_id" +} +variable "cm_catalog_owning_account" { + description = "Account that owns catalog." + type = string + default = "owning_account" +} +variable "cm_catalog_kind" { + description = "Kind of catalog. Supported kinds are offering and vpe." + type = string + default = "kind" +} +variable "cm_catalog_metadata" { + description = "Catalog specific metadata." + type = map() + default = { "key": null } +} + +// Resource arguments for cm_offering +variable "cm_offering_catalog_identifier" { + description = "Catalog identifier." + type = string + default = "catalog_identifier" +} +variable "cm_offering_url" { + description = "The url for this specific offering." + type = string + default = "url" +} +variable "cm_offering_crn" { + description = "The crn for this specific offering." + type = string + default = "crn" +} +variable "cm_offering_label" { + description = "Display Name in the requested language." + type = string + default = "label" +} +variable "cm_offering_label_i18n" { + description = "A map of translated strings, by language code." + type = map(string) + default = { "key": "inner" } +} +variable "cm_offering_name" { + description = "The programmatic name of this offering." + type = string + default = "name" +} +variable "cm_offering_offering_icon_url" { + description = "URL for an icon associated with this offering." + type = string + default = "offering_icon_url" +} +variable "cm_offering_offering_docs_url" { + description = "URL for an additional docs with this offering." + type = string + default = "offering_docs_url" +} +variable "cm_offering_offering_support_url" { + description = "[deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering." + type = string + default = "offering_support_url" +} +variable "cm_offering_tags" { + description = "List of tags associated with this catalog." + type = list(string) + default = [ "tags" ] +} +variable "cm_offering_keywords" { + description = "List of keywords associated with offering, typically used to search for it." + type = list(string) + default = [ "keywords" ] +} +variable "cm_offering_created" { + description = "The date and time this catalog was created." + type = string + default = "2021-01-31T09:44:12Z" +} +variable "cm_offering_updated" { + description = "The date and time this catalog was last updated." + type = string + default = "2021-01-31T09:44:12Z" +} +variable "cm_offering_short_description" { + description = "Short description in the requested language." + type = string + default = "short_description" +} +variable "cm_offering_short_description_i18n" { + description = "A map of translated strings, by language code." + type = map(string) + default = { "key": "inner" } +} +variable "cm_offering_long_description" { + description = "Long description in the requested language." + type = string + default = "long_description" +} +variable "cm_offering_long_description_i18n" { + description = "A map of translated strings, by language code." + type = map(string) + default = { "key": "inner" } +} +variable "cm_offering_pc_managed" { + description = "Offering is managed by Partner Center." + type = bool + default = true +} +variable "cm_offering_publish_approved" { + description = "Offering has been approved to publish to permitted to IBM or Public Catalog." + type = bool + default = true +} +variable "cm_offering_share_with_all" { + description = "Denotes public availability of an Offering - if share_enabled is true." + type = bool + default = true +} +variable "cm_offering_share_with_ibm" { + description = "Denotes IBM employee availability of an Offering - if share_enabled is true." + type = bool + default = true +} +variable "cm_offering_share_enabled" { + description = "Denotes sharing including access list availability of an Offering is enabled." + type = bool + default = true +} +variable "cm_offering_permit_request_ibm_public_publish" { + description = "Is it permitted to request publishing to IBM or Public." + type = bool + default = true +} +variable "cm_offering_ibm_publish_approved" { + description = "Indicates if this offering has been approved for use by all IBMers." + type = bool + default = true +} +variable "cm_offering_public_publish_approved" { + description = "Indicates if this offering has been approved for use by all IBM Cloud users." + type = bool + default = true +} +variable "cm_offering_public_original_crn" { + description = "The original offering CRN that this publish entry came from." + type = string + default = "public_original_crn" +} +variable "cm_offering_publish_public_crn" { + description = "The crn of the public catalog entry of this offering." + type = string + default = "publish_public_crn" +} +variable "cm_offering_portal_approval_record" { + description = "The portal's approval record ID." + type = string + default = "portal_approval_record" +} +variable "cm_offering_portal_ui_url" { + description = "The portal UI URL." + type = string + default = "portal_ui_url" +} +variable "cm_offering_catalog_id" { + description = "The id of the catalog containing this offering." + type = string + default = "catalog_id" +} +variable "cm_offering_catalog_name" { + description = "The name of the catalog." + type = string + default = "catalog_name" +} +variable "cm_offering_metadata" { + description = "Map of metadata values for this offering." + type = map() + default = { "key": null } +} +variable "cm_offering_disclaimer" { + description = "A disclaimer for this offering." + type = string + default = "disclaimer" +} +variable "cm_offering_hidden" { + description = "Determine if this offering should be displayed in the Consumption UI." + type = bool + default = true +} +variable "cm_offering_provider" { + description = "Deprecated - Provider of this offering." + type = string + default = "provider" +} +variable "cm_offering_product_kind" { + description = "The product kind. Valid values are module, solution, or empty string." + type = string + default = "product_kind" +} + +// Resource arguments for cm_version +variable "cm_version_catalog_identifier" { + description = "Catalog identifier." + type = string + default = "catalog_identifier" +} +variable "cm_version_offering_id" { + description = "Offering identification." + type = string + default = "offering_id" +} +variable "cm_version_tags" { + description = "Tags array." + type = list(string) + default = [ "tags" ] +} +variable "cm_version_name" { + description = "Name of version. Required for virtual server image for VPC." + type = string + default = "name" +} +variable "cm_version_label" { + description = "Display name of version. Required for virtual server image for VPC." + type = string + default = "label" +} +variable "cm_version_install_kind" { + description = "Install type. Example: instance. Required for virtual server image for VPC." + type = string + default = "install_kind" +} +variable "cm_version_target_kinds" { + description = "Deployment target of the content being onboarded. Current valid values are iks, roks, vcenter, power-iaas, terraform, and vpc-x86. Required for virtual server image for VPC." + type = list(string) + default = [ "target_kinds" ] +} +variable "cm_version_format_kind" { + description = "Format of content being onboarded. Example: vsi-image. Required for virtual server image for VPC." + type = string + default = "format_kind" +} +variable "cm_version_product_kind" { + description = "Optional product kind for the software being onboarded. Valid values are software, module, or solution. Default value is software." + type = string + default = "product_kind" +} +variable "cm_version_sha" { + description = "SHA256 fingerprint of the image file. Required for virtual server image for VPC." + type = string + default = "sha" +} +variable "cm_version_version" { + description = "Semantic version of the software being onboarded. Required for virtual server image for VPC." + type = string + default = "version" +} +variable "cm_version_working_directory" { + description = "Optional - The sub-folder within the specified tgz file that contains the software being onboarded." + type = string + default = "working_directory" +} +variable "cm_version_zipurl" { + description = "URL path to zip location. If not specified, must provide content in the body of this call." + type = string + default = "zipurl" +} +variable "cm_version_target_version" { + description = "The semver value for this new version, if not found in the zip url package content." + type = string + default = "target_version" +} +variable "cm_version_include_config" { + description = "Add all possible configuration values to this version when importing." + type = bool + default = true +} +variable "cm_version_is_vsi" { + description = "Indicates that the current terraform template is used to install a virtual server image." + type = bool + default = true +} +variable "cm_version_repotype" { + description = "The type of repository containing this version. Valid values are 'public_git' or 'enterprise_git'." + type = string + default = "repotype" +} +variable "cm_version_x_auth_token" { + description = "Authentication token used to access the specified zip file." + type = string + default = "x_auth_token" +} + +// Resource arguments for cm_offering_instance +variable "cm_offering_instance_x_auth_refresh_token" { + description = "IAM Refresh token." + type = string + default = "x_auth_refresh_token" +} +variable "cm_offering_instance_rev" { + description = "Cloudant revision." + type = string + default = "rev" +} +variable "cm_offering_instance_url" { + description = "url reference to this object." + type = string + default = "url" +} +variable "cm_offering_instance_crn" { + description = "platform CRN for this instance." + type = string + default = "crn" +} +variable "cm_offering_instance_label" { + description = "the label for this instance." + type = string + default = "label" +} +variable "cm_offering_instance_catalog_id" { + description = "Catalog ID this instance was created from." + type = string + default = "catalog_id" +} +variable "cm_offering_instance_offering_id" { + description = "Offering ID this instance was created from." + type = string + default = "offering_id" +} +variable "cm_offering_instance_kind_format" { + description = "the format this instance has (helm, operator, ova...)." + type = string + default = "kind_format" +} +variable "cm_offering_instance_version" { + description = "The version this instance was installed from (semver - not version id)." + type = string + default = "version" +} +variable "cm_offering_instance_version_id" { + description = "The version id this instance was installed from (version id - not semver)." + type = string + default = "version_id" +} +variable "cm_offering_instance_cluster_id" { + description = "Cluster ID." + type = string + default = "cluster_id" +} +variable "cm_offering_instance_cluster_region" { + description = "Cluster region (e.g., us-south)." + type = string + default = "cluster_region" +} +variable "cm_offering_instance_cluster_namespaces" { + description = "List of target namespaces to install into." + type = list(string) + default = [ "cluster_namespaces" ] +} +variable "cm_offering_instance_cluster_all_namespaces" { + description = "designate to install into all namespaces." + type = bool + default = true +} +variable "cm_offering_instance_schematics_workspace_id" { + description = "Id of the schematics workspace, for offering instances provisioned through schematics." + type = string + default = "schematics_workspace_id" +} +variable "cm_offering_instance_install_plan" { + description = "Type of install plan (also known as approval strategy) for operator subscriptions. Can be either automatic, which automatically upgrades operators to the latest in a channel, or manual, which requires approval on the cluster." + type = string + default = "install_plan" +} +variable "cm_offering_instance_channel" { + description = "Channel to pin the operator subscription to." + type = string + default = "channel" +} +variable "cm_offering_instance_created" { + description = "date and time create." + type = string + default = "2021-01-31T09:44:12Z" +} +variable "cm_offering_instance_updated" { + description = "date and time updated." + type = string + default = "2021-01-31T09:44:12Z" +} +variable "cm_offering_instance_metadata" { + description = "Map of metadata values for this offering instance." + type = map() + default = { "key": null } +} +variable "cm_offering_instance_resource_group_id" { + description = "Id of the resource group to provision the offering instance into." + type = string + default = "resource_group_id" +} +variable "cm_offering_instance_location" { + description = "String location of OfferingInstance deployment." + type = string + default = "location" +} +variable "cm_offering_instance_disabled" { + description = "Indicates if Resource Controller has disabled this instance." + type = bool + default = true +} +variable "cm_offering_instance_account" { + description = "The account this instance is owned by." + type = string + default = "account" +} +variable "cm_offering_instance_kind_target" { + description = "The target kind for the installed software version." + type = string + default = "kind_target" +} +variable "cm_offering_instance_sha" { + description = "The digest value of the installed software version." + type = string + default = "sha" +} + +// Data source arguments for cm_catalog +variable "cm_catalog_catalog_identifier" { + description = "Catalog identifier." + type = string + default = "catalog_identifier" +} + +// Data source arguments for cm_offering +variable "cm_offering_catalog_identifier" { + description = "Catalog identifier." + type = string + default = "catalog_identifier" +} +variable "cm_offering_offering_id" { + description = "Offering identification." + type = string + default = "offering_id" +} + +// Data source arguments for cm_version +variable "cm_version_version_loc_id" { + description = "A dotted value of `catalogID`.`versionID`." + type = string + default = "version_loc_id" +} + +// Data source arguments for cm_offering_instance +variable "cm_offering_instance_instance_identifier" { + description = "Version Instance identifier." + type = string + default = "instance_identifier" +} diff --git a/examples/ibm-catalog-management/versions.tf b/examples/ibm-catalog-management/versions.tf new file mode 100644 index 000000000..ee0f9705a --- /dev/null +++ b/examples/ibm-catalog-management/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.12" +} \ No newline at end of file diff --git a/examples/ibm-cd-tekton-pipeline/README.md b/examples/ibm-cd-tekton-pipeline/README.md new file mode 100644 index 000000000..ebda36afd --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/README.md @@ -0,0 +1,181 @@ +# Example for CdTektonPipelineV2 + +This example illustrates how to use the CdTektonPipelineV2 + +These types of resources are supported: + +* cd_tekton_pipeline +* cd_tekton_pipeline_definition +* cd_tekton_pipeline_trigger_property +* cd_tekton_pipeline_property +* cd_tekton_pipeline_trigger + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + +## CdTektonPipelineV2 resources + +cd_tekton_pipeline resource: + +```terraform +resource "cd_tekton_pipeline" "cd_tekton_pipeline_instance" { + enable_slack_notifications = false + enable_partial_cloning = false + worker = var.cd_tekton_pipeline_worker +} +``` + +cd_tekton_pipeline_definition resource: + +```terraform +resource "cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + scm_source { + url = ibm_cd_toolchain_tool_hostedgit.tekton_repo.repo_url + branch = "master" + path = ".tekton" + } +} +``` + +cd_tekton_pipeline_property resource: + +```terraform +resource "cd_tekton_pipeline_property" "cd_tekton_pipeline_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "env-prop-1" + value = "Environment text property 1" + type = "text" +} +``` + +cd_tekton_pipeline_trigger resource: + +```terraform +resource "cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + type = "manual" + name = "trigger1" + event_listener = "listener" + tags = [ "tag1", "tag2" ] + worker { + id = "public" + } + max_concurrent_runs = 1 +} +``` + +cd_tekton_pipeline_trigger_property resource: + +```terraform +resource "cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + trigger_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger_instance.trigger_id + name = "trig-prop-1" + value = "trigger 1 text property" + type = "text" +} +``` + +## CdTektonPipelineV2 Data sources + +cd_tekton_pipeline data source: + +```terraform +data "cd_tekton_pipeline" "cd_tekton_pipeline_instance" { + id = var.cd_tekton_pipeline_id +} +``` + +cd_tekton_pipeline_definition data source: + +```terraform +data "cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition_instance" { + pipeline_id = var.cd_tekton_pipeline_definition_pipeline_id + definition_id = var.cd_tekton_pipeline_definition_definition_id +} +``` + +cd_tekton_pipeline_property data source: + +```terraform +data "cd_tekton_pipeline_property" "cd_tekton_pipeline_property_instance" { + pipeline_id = var.cd_tekton_pipeline_property_pipeline_id + property_name = var.cd_tekton_pipeline_property_property_name +} +``` + +cd_tekton_pipeline_trigger data source: + +```terraform +data "cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger_instance" { + pipeline_id = var.cd_tekton_pipeline_trigger_pipeline_id + trigger_id = var.cd_tekton_pipeline_trigger_trigger_id +} +``` + +cd_tekton_pipeline_trigger_property data source: + +```terraform +data "cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property_instance" { + pipeline_id = var.cd_tekton_pipeline_trigger_property_pipeline_id + trigger_id = var.cd_tekton_pipeline_trigger_property_trigger_id + property_name = var.cd_tekton_pipeline_trigger_property_property_name +} +``` + +## Assumptions + +1. Creating a Tekton Pipeline requires creating an IBM CD Toolchain (ibm_cd_toolchain) resource and a Tekton Pipeline tool resource instance (ibm_cd_toolchain_tool_pipeline) in that toolchain. These are included in the example in `main.tf`. +2. The Tekton Pipeline resource also requires a repository to be included in the toolchain, which contains the Tekton Pipeline declaration. An example is included in the `main.tf`. + +## Notes + +1. Copy the `variables.tfvars.example` file to your own `terraform.tfvars` file and add values for the variables within. +2. Use `terraform apply -var-file="terraform.tfvars"` to generate the toolchain and pipeline using your provided variables. + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >=1.0.0, <2.0 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | >=1.45.0 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| resource\_group | Resource group within which toolchain will be created | `string` | true | +| region | IBM Cloud region where your toolchain will be created | `string` | true | +| toolchain\_name | Name of the Toolchain | `string` | true | +| toolchain\_description | Description for the Toolchain | `string` | true | +| clone\_repo | URL of the tekton repo to clone, e.g. `https://github.com/open-toolchain/hello-tekton` | `string` | true | +| repo\_name | Name of the new repo that will be created in the toolchain | `string` | true | +| cluster | Name of the cluster where the app will be deployed | `string` | true | +| cluster_namespace | Namespace in the cluster where the app will be deployed. Default = `prod` | `string` | false | +| registry_namespace | IBM Cloud Container Registry namespace where the app image will be built and stored | `string` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| cd_tekton_pipeline | cd_tekton_pipeline object | +| cd_tekton_pipeline_definition | cd_tekton_pipeline_definition object | +| cd_tekton_pipeline_property | cd_tekton_pipeline_property object | +| cd_tekton_pipeline_trigger | cd_tekton_pipeline_trigger object | +| cd_tekton_pipeline_trigger_property | cd_tekton_pipeline_trigger_property object | diff --git a/examples/ibm-cd-tekton-pipeline/main.tf b/examples/ibm-cd-tekton-pipeline/main.tf new file mode 100644 index 000000000..29b0bcca3 --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/main.tf @@ -0,0 +1,158 @@ +// Base resources +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} +data "ibm_resource_group" "resource_group" { + name = var.resource_group +} + +// Create toolchain instance +resource "ibm_cd_toolchain" "toolchain_instance" { + name = var.toolchain_name + description = var.toolchain_description + resource_group_id = data.ibm_resource_group.resource_group.id +} + +// Create git repo tool instance +resource "ibm_cd_toolchain_tool_hostedgit" "tekton_repo" { + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + name = "tekton-repo" + initialization { + type = "clone" + source_repo_url = var.clone_repo + private_repo = false + repo_name = var.repo_name + } + parameters { + has_issues = false + enable_traceability = false + } +} + +// Create tekton pipeline instance +resource "ibm_cd_toolchain_tool_pipeline" "cd_pipeline" { + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + parameters { + name = "tf-pipeline" + type = "tekton" + } +} +resource "ibm_cd_tekton_pipeline" "cd_pipeline_instance" { + pipeline_id = ibm_cd_toolchain_tool_pipeline.cd_pipeline.tool_id + enable_slack_notifications = false + enable_partial_cloning = false + worker { + id = "public" + } +} + +// Provision cd_tekton_pipeline_definition resource instance +resource "ibm_cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + scm_source { + url = ibm_cd_toolchain_tool_hostedgit.tekton_repo.parameters[0].repo_url + branch = "master" + path = ".tekton" + } +} + +// Provision cd_tekton_pipeline_property resource instance +resource "ibm_cd_tekton_pipeline_property" "cd_tekton_pipeline_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "env-prop-1" + value = "Environment text property 1" + type = "text" +} + +// Provision pipeline properties +resource "ibm_cd_tekton_pipeline_property" "apikey" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "apikey" + value = var.ibmcloud_api_key + type = "secure" +} +resource "ibm_cd_tekton_pipeline_property" "cluster_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "cluster" + value = var.cluster + type = "text" +} +resource "ibm_cd_tekton_pipeline_property" "cluster_namespace_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "clusterNamespace" + value = var.cluster_namespace + type = "text" +} +resource "ibm_cd_tekton_pipeline_property" "cluster_region_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "clusterRegion" + value = var.region + type = "text" +} +resource "ibm_cd_tekton_pipeline_property" "registry_region_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "registryRegion" + value = var.region + type = "text" +} +resource "ibm_cd_tekton_pipeline_property" "registry_namespace_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "registryNamespace" + value = var.registry_namespace + type = "text" +} +resource "ibm_cd_tekton_pipeline_property" "repository_property" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + name = "repository" + value = ibm_cd_toolchain_tool_hostedgit.tekton_repo.parameters[0].repo_url + type = "text" +} + +// Provision cd_tekton_pipeline_trigger resource instance +resource "ibm_cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + type = "manual" + name = "trigger1" + event_listener = "listener" + tags = [ "tag1", "tag2" ] + worker { + id = "public" + } + max_concurrent_runs = 1 +} + +// Provision cd_tekton_pipeline_trigger_property resource instance +resource "ibm_cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + trigger_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger_instance.trigger_id + name = "trig-prop-1" + value = "trigger 1 text property" + type = "text" +} + +// Data sources +// Create cd_tekton_pipeline_definition data source +data "ibm_cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + definition_id = ibm_cd_tekton_pipeline_definition.cd_tekton_pipeline_definition_instance.definition_id +} +// Create cd_tekton_pipeline_trigger data source +data "ibm_cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + trigger_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger_instance.trigger_id +} +// Create cd_tekton_pipeline_trigger_property data source +data "ibm_cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + trigger_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger_instance.trigger_id + property_name = ibm_cd_tekton_pipeline_trigger_property.cd_tekton_pipeline_trigger_property_instance.name +} +// Create cd_tekton_pipeline_property data source +data "ibm_cd_tekton_pipeline_property" "cd_tekton_pipeline_property_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id + property_name = ibm_cd_tekton_pipeline_property.cd_tekton_pipeline_property_instance.name +} +// Create cd_tekton_pipeline data source +data "ibm_cd_tekton_pipeline" "cd_tekton_pipeline_instance" { + pipeline_id = ibm_cd_tekton_pipeline.cd_pipeline_instance.pipeline_id +} diff --git a/examples/ibm-cd-tekton-pipeline/outputs.tf b/examples/ibm-cd-tekton-pipeline/outputs.tf new file mode 100644 index 000000000..08c7c1618 --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/outputs.tf @@ -0,0 +1,30 @@ +// This allows cd_tekton_pipeline data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed" +output "ibm_cd_tekton_pipeline" { + value = ibm_cd_tekton_pipeline.cd_pipeline_instance + description = "cd_pipeline_instance resource instance" +} +// This allows cd_tekton_pipeline_definition data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cd_tekton_pipeline_definition" { + value = ibm_cd_tekton_pipeline_definition.cd_tekton_pipeline_definition_instance + description = "cd_tekton_pipeline_definition resource instance" +} +// This allows cd_tekton_pipeline_trigger_property data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cd_tekton_pipeline_trigger_property" { + value = ibm_cd_tekton_pipeline_trigger_property.cd_tekton_pipeline_trigger_property_instance + description = "cd_tekton_pipeline_trigger_property resource instance" +} +// This allows cd_tekton_pipeline_property data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cd_tekton_pipeline_property" { + value = ibm_cd_tekton_pipeline_property.cd_tekton_pipeline_property_instance + description = "cd_tekton_pipeline_property resource instance" +} +// This allows cd_tekton_pipeline_trigger data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cd_tekton_pipeline_trigger" { + value = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger_instance + description = "cd_tekton_pipeline_trigger resource instance" +} \ No newline at end of file diff --git a/examples/ibm-cd-tekton-pipeline/variables.tf b/examples/ibm-cd-tekton-pipeline/variables.tf new file mode 100644 index 000000000..402f0468b --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/variables.tf @@ -0,0 +1,56 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +variable "resource_group" { + type = string + description = "Resource group within which toolchain will be created" + default = "Default" +} + +variable "clone_repo" { + type = string + description = "URL of the tekton repo to clone" + default = "https://github.com/open-toolchain/hello-tekton" +} + +variable "repo_name" { + type = string + description = "Name of the new repo that will be created in the toolchain" + default = "simple-tekton" +} + +variable "region" { + type = string + description = "IBM Cloud region where your toolchain will be created" + default = "us-south" +} + +variable "toolchain_name" { + type = string + description = "Name of the Toolchain" + default = "Simple Helm Toolchain" +} + +variable "toolchain_description" { + type = string + description = "Description for the Toolchain" + default = "Toolchain created using IBM Cloud Continuous Delivery Service" +} + +variable "cluster" { + type = string + description = "The name of your IKS cluster where you will be deploying the sample app" +} + +variable "cluster_namespace" { + type = string + description = "The namespace in your cluster where the app will be deployed" + default = "prod" +} + +variable "registry_namespace" { + type = string + description = "The IBM Cloud Container Registry namespace where the app image will be built and stored." +} diff --git a/examples/ibm-cd-tekton-pipeline/variables.tfvars.example b/examples/ibm-cd-tekton-pipeline/variables.tfvars.example new file mode 100644 index 000000000..b24cb3334 --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/variables.tfvars.example @@ -0,0 +1,13 @@ +/*****************************************************/ +/* Variables for Module "Main" */ +/*****************************************************/ +resource_group = "" +ibmcloud_api_key = "" +region = "" +toolchain_name = "some name for toolchain" +toolchain_description = "some description for toolchain" +clone_repo = "URL for the Tekton repo to clone, e.g. 'https://github.com/open-toolchain/hello-tekton'" +repo_name = "some name for the repository that will be created in the toolchain" +cluster = " where the app will be deployed" +cluster_namespace = " in the cluster where the app will be deployed" +registry_namespace = " where the app image will be built and stored" diff --git a/examples/ibm-cd-tekton-pipeline/versions.tf b/examples/ibm-cd-tekton-pipeline/versions.tf new file mode 100644 index 000000000..8eedc1f1a --- /dev/null +++ b/examples/ibm-cd-tekton-pipeline/versions.tf @@ -0,0 +1,12 @@ +############################### +# IBM Cloud Copyright 2022 IBM +############################### + +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-empty/README.md b/examples/ibm-cd-toolchain-empty/README.md new file mode 100644 index 000000000..b2db00d08 --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/README.md @@ -0,0 +1,59 @@ +# Terraform Toolchain Template for Build your own toolchain + +This toolchain templates creates an empty toolchain in IBM Cloud region and resource group of your selection. This toolchain has no preconfigured tools. Use this toolchain template as a starting toolchain and keep adding toolchain integrations as per your requirement. + +## Usage + +The terraform template requires you to provide values for the terraform variables. +Copy the file `variables.tfvars.example` as `variables.tfvars`. Provide appropriate values to the variables within the file. + + +1. Initialize the terraform project to download the terraform providers and modules +```bash +$ terraform init +``` +2. Perform terraform plan with the variables. Run `terraform plan` to see the changes that will be applied to your account after you make any change to the terraform code. +```bash +$ terraform plan -var-file=./variables.tfvars +``` + +3. Perform terraform apply with the variables. Run `terraform apply` to apply the changes to the IBM Cloud after that will be applied to your account after you make any change to the terraform code. + +```bash +$ terraform apply -var-file=./variables.tfvars +``` + +Run `terraform destroy` to clean up and destroy all the resources created for the toolchain. + +## Assumptions + + + +## Notes + + + +## Requirements + + + +## Providers + + + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| resource_group | Name of the resource group that the toolchain will belong to. | `string` | true | +| region | IBM Cloud Region in which toolchain will be created. Defaults to `us-south` | `string` | false | +| name | Name of tool. | `string` | false | +| toolchain_name | Name of the toolchain | `string` | false | +| toolchain_description | Description of the toolchain | `string` | false | + +## Outputs + +| Name | Description | +|------|-------------| +| toolchain_id | Toolchain ID of the newly created toolchain resource | \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-empty/main.tf b/examples/ibm-cd-toolchain-empty/main.tf new file mode 100644 index 000000000..a3a664bc9 --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/main.tf @@ -0,0 +1,13 @@ +data "ibm_resource_group" "resource_group" { + name = var.resource_group +} + +resource "ibm_cd_toolchain" "toolchain_instance" { + name = var.toolchain_name + description = var.toolchain_description + resource_group_id = data.ibm_resource_group.resource_group.id +} + +output "toolchain_id" { + value = ibm_cd_toolchain.toolchain_instance.id +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-empty/provider.tf b/examples/ibm-cd-toolchain-empty/provider.tf new file mode 100644 index 000000000..88d3d9882 --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-empty/variables.tf b/examples/ibm-cd-toolchain-empty/variables.tf new file mode 100644 index 000000000..1b55a2d0e --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/variables.tf @@ -0,0 +1,29 @@ +variable "resource_group" { + type = string + description = "Resource group within which toolchain will be created" + default = "Default" +} + +variable "region" { + type = string + description = "IBM Cloud region where your toolchain will be created" + default = "us-south" +} + +variable "ibmcloud_api_key" { + type = string + description = "IBM Cloud API KEY to interact with IBM Cloud" +} + +variable "toolchain_name" { + type = string + description = "Name of the Toolchain." + default = "Sample Empty Toolchain" +} + +variable "toolchain_description" { + type = string + description = "Description for the Toolchain." + default = "This toolchain has no preconfigured tools. If you are already familiar with toolchains, you can set up your own toolchain." +} + diff --git a/examples/ibm-cd-toolchain-empty/variables.tfvars.example b/examples/ibm-cd-toolchain-empty/variables.tfvars.example new file mode 100644 index 000000000..253a1b4fa --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/variables.tfvars.example @@ -0,0 +1,2 @@ +resource_group = "" +ibmcloud_api_key = "" \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-empty/versions.tf b/examples/ibm-cd-toolchain-empty/versions.tf new file mode 100644 index 000000000..8eedc1f1a --- /dev/null +++ b/examples/ibm-cd-toolchain-empty/versions.tf @@ -0,0 +1,12 @@ +############################### +# IBM Cloud Copyright 2022 IBM +############################### + +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/README.md b/examples/ibm-cd-toolchain-simple-helm/README.md new file mode 100644 index 000000000..10dcb52ea --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/README.md @@ -0,0 +1,79 @@ +# Terraform Toolchain Template for Develop a Kubernetes app with Helm Toolchain Template + +This toolchain templates creates a toolchain with which you can develop a Docker application and its Helm chart together in source control and have it built and deployed automatically to a Kubernetes cluster. The toolchain performs sanity checks prior to building or deploying and ensures privacy by using a private container registry and namespaces for the container registry and the Kubernetes cluster. This toolchain is also leveraging Code Risk Analyzer and Vulnerability Advisor, to ensure only secure images get deployed. + +By default, the toolchain uses a sample Node.js "Hello World" app, but you can link to your own Git repository instead as long as it has a Dockerfile and a Helm chart. + +You can manage your IBM Cloud Container clusters in the console. + +This toolchain uses tools that are part of the Continuous Delivery service. For more information and terms, see [here](https://www.ibm.com/cloud/architecture/tutorials/use-develop-kubernetes-app-helm-toolchain-with-tekton-pipelines) + +## Usage + +The terraform template requires you to provide values for the terraform variables. +Copy the file `variables.tfvars.example` as `variables.tfvars`. Provide appropriate values to the variables within the file. + + +1. Initialize the terraform project to download the terraform providers and modules +```bash +$ terraform init +``` +2. Perform terraform plan with the variables. Run `terraform plan` to see the changes that will be applied to your account after you make any change to the terraform code. +```bash +$ terraform plan -var-file=./variables.tfvars +``` + +3. Perform terraform apply with the variables. Run `terraform apply` to apply the changes to the IBM Cloud after that will be applied to your account after you make any change to the terraform code. + +```bash +$ terraform apply -var-file=./variables.tfvars +``` + +Run `terraform destroy` to clean up and destroy all the resources created for the toolchain. + +## Assumptions + +1. You have an existing Key Protect Instance created in your account. If not follow the process [here](https://cloud.ibm.com/catalog/services/key-protect) to create one. +2. You have your IBM Cloud API Key stored in the Key Protect Instance as `Import your own key` option with the Key Name as `ibmcloud-api-key`. This is the same key name which the terraform template requires to pass to the CI and PR Pipelines as environment properties. +3. You have an existing Kubernetes Cluster created using IBM Cloud Kubernetes Service. If not follow the process [here](https://cloud.ibm.com/kubernetes/catalog/create). Once created you will need the name of the Kubernetes Cluster to be passed on to the terraform template. +4. You have an existing namespace within the IBM Cloud Container Registry. If not follow the process [here](https://cloud.ibm.com/registry/namespaces). Once created you will need the name of the Container Registry namespace to be passed on to the terraform template. + +## Notes + + + +## Requirements + + + +## Providers + + + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key required by the terraform provider to interact with IBM Cloud | `string` | true | +| resource_group | Name of the resource group that the toolchain will belong to. | `string` | true | +| region | IBM Cloud Region in which toolchain will be created. Defaults to `us-south` | `string` | true | +| toolchain_name | Name of the toolchain | `string` | false | +| toolchain_description | Description of the toolchain | `string` | false | +| ibmcloud\_api | IBM Cloud API Endpoint that will be used by the CI/PR Pipelies to interact with IBM Cloud Services | `string` | false | +| app_name | Name of the application that will be deployed by the CI Pipeline | `string` | false | +| app_image_name | Name of the application container image that will be create by the CI Pipeline | `string` | false | +| cluster_name | Name of the IKS Cluster where the application container image will be deployed | `string` | true | +| cluster_namespace | Name of the IKS Cluster Namespace where the application container image will be deployed | `string` | true | +| cluster_region | Region of the IKS Cluster | `string` | true | +| registry_namespace | Name of the Container Registry Namespace where the application container image will be stored | `string` | true | +| registry_region | Region of the Container Registry where the application container image will be stored | `string` | true | +| kp_name | Name of the Key Protect Instance where the IBM Cloud API Key to be used within the CI/PR Pipeline is stored | `string` | true | +| app_repo | IBM Cloud Hosted GIT Repository where the application source code resides. Default behavior of the template is to clone this repository from this [source application repository](https://us-south.git.cloud.ibm.com/open-toolchain/hello-helm.git) | `string` | false | +| pipeline_repo | IBM Cloud Hosted GIT Repository where the tekton pipeline code resides. Default behavior of the template is to clone this repository from this [source pipeline repository](https://us-south.git.cloud.ibm.com/open-toolchain/simple-helm-toolchain.git) | `string` | false | +| tekton_tasks_catalog_repo | IBM Cloud Hosted GIT Repository where the common tekton tasks resides. Default behavior of the template is to clone this repository from this [common tekton tasks repository](https://us-south.git.cloud.ibm.com/open-toolchain/tekton-catalog.git) | `string` | false | + +## Outputs + +| Name | Description | +|------|-------------| +| toolchain_id | Toolchain ID of the newly created toolchain resource | \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/integrations/integrations.tf b/examples/ibm-cd-toolchain-simple-helm/integrations/integrations.tf new file mode 100644 index 000000000..9f59d7503 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/integrations/integrations.tf @@ -0,0 +1,21 @@ +resource "ibm_iam_authorization_policy" "s2sAuth1" { + source_service_name = "toolchain" + source_resource_instance_id = var.toolchain_id + target_service_name = "kms" + target_resource_instance_id = var.key_protect_instance_guid + roles = ["Viewer", "ReaderPlus"] +} + +resource "ibm_cd_toolchain_tool_keyprotect" "keyprotect" { + toolchain_id = var.toolchain_id + parameters { + name = var.key_protect_integration_name + region = var.key_protect_instance_region + resource_group = var.resource_group + instance_name = var.key_protect_instance_name + } +} + +output "keyprotect_integration_name" { + value = var.key_protect_integration_name +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/integrations/variables.tf b/examples/ibm-cd-toolchain-simple-helm/integrations/variables.tf new file mode 100644 index 000000000..f0d5a326e --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/integrations/variables.tf @@ -0,0 +1,35 @@ +variable "toolchain_id" { +} + +variable "resource_group" { +} + +variable "region" { +} + +variable "key_protect_integration_name" { + type = string + description = "Name of the Key Protect Toolchain Integration" + default = "Key Protect Integration Instance" +} + +variable "key_protect_instance_name" { + type = string + description = "Name of the Key Protect Toolchain Service Instance in IBM Cloud" +} + +variable "key_protect_instance_region" { + type = string + description = "Region of the Key Protect Toolchain Service Instance in IBM Cloud" +} + +variable "key_protect_instance_guid" { + type = string + description = "GUID of the Key Protect Toolchain Service Instance in IBM Cloud" +} + +variable "key_protect_service_auth" { + type = string + description = "Authorization Permission for the Key Protect Toolchain Service Instance in IBM Cloud" + default = "[\"Viewer\", \"ReaderPlus\"]" +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/integrations/versions.tf b/examples/ibm-cd-toolchain-simple-helm/integrations/versions.tf new file mode 100644 index 000000000..88d6f0aa3 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/integrations/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/main.tf b/examples/ibm-cd-toolchain-simple-helm/main.tf new file mode 100644 index 000000000..392cbc3ea --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/main.tf @@ -0,0 +1,99 @@ +data "ibm_resource_group" "resource_group" { + name = var.resource_group +} + +resource "ibm_cd_toolchain" "toolchain_instance" { + name = var.toolchain_name + description = var.toolchain_description + resource_group_id = data.ibm_resource_group.resource_group.id +} + +module "repositories" { + source = "./repositories" + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + resource_group = data.ibm_resource_group.resource_group.id + ibm_cloud_api_key = var.ibm_cloud_api_key + region = var.region + app_repo = var.app_repo + pipeline_repo = var.pipeline_repo + tekton_tasks_catalog_repo = var.tekton_tasks_catalog_repo + repositories_prefix = var.app_name +} + +resource "ibm_cd_toolchain_tool_pipeline" "ci_pipeline" { + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + parameters { + name = "ci-pipeline" + type = "tekton" + } +} + +module "pipeline-ci" { + source = "./pipeline-ci" + depends_on = [ module.repositories ] + ibm_cloud_api_key = var.ibm_cloud_api_key + region = var.region + pipeline_id = split("/", ibm_cd_toolchain_tool_pipeline.ci_pipeline.id)[1] + resource_group = var.resource_group + app_name = var.app_name + app_image_name = var.app_image_name + cluster_name = var.cluster_name + cluster_namespace = var.cluster_namespace + cluster_region = var.cluster_region + registry_namespace = var.registry_namespace + registry_region = var.registry_region + app_repo = module.repositories.app_repo_url + pipeline_repo = module.repositories.pipeline_repo_url + tekton_tasks_catalog_repo = module.repositories.tekton_tasks_catalog_repo_url + kp_integration_name = module.integrations.keyprotect_integration_name +} + +resource "ibm_cd_toolchain_tool_pipeline" "pr_pipeline" { + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + parameters { + name = "pr-pipeline" + type = "tekton" + } +} + +module "pipeline-pr" { + source = "./pipeline-pr" + depends_on = [ module.repositories ] + ibm_cloud_api_key = var.ibm_cloud_api_key + region = var.region + pipeline_id = split("/", ibm_cd_toolchain_tool_pipeline.pr_pipeline.id)[1] + resource_group = var.resource_group + app_name = var.app_name + app_repo = module.repositories.app_repo_url + pipeline_repo = module.repositories.pipeline_repo_url + tekton_tasks_catalog_repo = module.repositories.tekton_tasks_catalog_repo_url + kp_integration_name = module.integrations.keyprotect_integration_name +} + +module "services" { + source = "./services" + kp_name = var.kp_name + kp_region = var.kp_region + region = var.region + ibm_cloud_api = var.ibm_cloud_api + cluster_name = var.cluster_name + cluster_namespace = var.cluster_namespace + cluster_region = var.cluster_region + registry_namespace = var.registry_namespace + registry_region = var.registry_region +} + +module "integrations" { + source = "./integrations" + depends_on = [ module.repositories, module.services ] + toolchain_id = ibm_cd_toolchain.toolchain_instance.id + region = var.region + resource_group = var.resource_group + key_protect_instance_region = var.kp_region + key_protect_instance_name = module.services.key_protect_instance_name + key_protect_instance_guid = module.services.key_protect_instance_guid +} + +output "toolchain_id" { + value = ibm_cd_toolchain.toolchain_instance.id +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/environments.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/environments.tf new file mode 100644 index 000000000..9ef57229b --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/environments.tf @@ -0,0 +1,97 @@ +resource "ibm_cd_tekton_pipeline_property" "ci_env_apikey" { + name = "apikey" + type = "secure" + value = format("{vault::%s.ibmcloud-api-key}", var.kp_integration_name) + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_app_name" { + name = "app-name" + type = "text" + value = var.app_name + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_branch" { + name = "branch" + type = "text" + value = "main" + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_cluster_name" { + name = "cluster-name" + type = "text" + value = var.cluster_name + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_commons_hosted_region" { + name = "commons-hosted-region" + type = "text" + value = "https://raw.githubusercontent.com/open-toolchain/commons/master" + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_dev_cluster_namespace" { + name = "dev-cluster-namespace" + type = "text" + value = var.cluster_namespace + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_dev_region" { + name = "dev-region" + type = "text" + value = var.cluster_region + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_dev_resource_group" { + name = "dev-resource-group" + type = "text" + value = var.resource_group + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_image_name" { + name = "image-name" + type = "text" + value = var.app_image_name + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_registry_namespace" { + name = "registry-namespace" + type = "text" + value = var.registry_namespace + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_registry_region" { + name = "registry-region" + type = "text" + value = var.registry_region + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_toolchain_apikey" { + name = "toolchain-apikey" + type = "secure" + value = format("{vault::%s.ibmcloud-api-key}", var.kp_integration_name) + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_repository" { + name = "repository" + type = "text" + value = var.app_repo + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "ci_env_ibmcloud-api" { + name = "ibmcloud-api" + type = "text" + value = "https://cloud.ibm.com" + pipeline_id = var.pipeline_id +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/pipeline-ci.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/pipeline-ci.tf new file mode 100644 index 000000000..507475834 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/pipeline-ci.tf @@ -0,0 +1,112 @@ +resource "ibm_cd_tekton_pipeline" "ci_pipeline_instance" { + pipeline_id = var.pipeline_id + worker { + id = "public" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_pipeline_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.pipeline_repo + branch = "master" + path = ".pipeline" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_git_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "git" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_cr_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "container-registry" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_kube_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "kubernetes-service" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_toolchain_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "toolchain" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_insights_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "devops-insights" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_linter_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "linter" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_tester_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "tester" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "ci_utils_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "utils" + } +} + +resource "ibm_cd_tekton_pipeline_trigger" "ci_pipeline_scm_trigger" { + pipeline_id = ibm_cd_tekton_pipeline.ci_pipeline_instance.pipeline_id + type = var.ci_pipeline_scm_trigger_type + name = var.ci_pipeline_scm_trigger_name + event_listener = var.ci_pipeline_scm_trigger_listener_name + scm_source { + url = var.app_repo + branch = "master" + } + events { + push = false + pull_request_closed = true + pull_request = false + } + disabled = var.ci_pipeline_scm_trigger_disabled + max_concurrent_runs = var.ci_pipeline_max_concurrent_runs +} + +resource "ibm_cd_tekton_pipeline_trigger" "ci_pipeline_manual_trigger" { + pipeline_id = var.pipeline_id + type = "manual" + name = "manual-run" + event_listener = "manual-run" +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/variables.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/variables.tf new file mode 100644 index 000000000..842b53226 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/variables.tf @@ -0,0 +1,99 @@ +variable "pipeline_id" { +} + +variable "resource_group" { +} + +variable "app_name" { +} + +variable "app_image_name" { +} + +variable "cluster_name" { +} + +variable "cluster_namespace" { +} + +variable "cluster_region" { +} + +variable "registry_namespace" { +} + +variable "registry_region" { +} + +variable "region" { +} + +variable "ibm_cloud_api_key" { +} + +variable "kp_integration_name" { +} + +variable "app_repo" { +} + +variable "pipeline_repo" { +} + +variable "tekton_tasks_catalog_repo" { +} + +variable "ci_pipeline_manual_trigger_name" { + type = string + description = "The name of Manual Trigger for CI Pipeline as defined in tekton definition." + default = "Manual Trigger" +} + +variable "ci_pipeline_manual_trigger_type" { + type = string + description = "The type of Manual Trigger for CI Pipeline as defined in tekton definition." + default = "manual" +} + +variable "ci_pipeline_manual_trigger_disabled" { + type = bool + description = "Flag to disable manual CI Trigger" + default = false +} + +variable "ci_pipeline_manual_trigger_listener_name" { + type = string + description = "The name of EventListener for the CI Pipeline SCM Trigger as defined in tekton definition." + default = "manual-run" +} + +variable "ci_pipeline_scm_trigger_name" { + type = string + description = "The name of SCM Trigger for CI Pipeline as defined in tekton definition." + default = "SCM Trigger" +} + +variable "ci_pipeline_scm_trigger_type" { + type = string + description = "The type of SCM Trigger for CI Pipeline as defined in tekton definition." + default = "scm" +} + +variable "ci_pipeline_scm_trigger_disabled" { + type = bool + description = "Flag to disable SCM CI Trigger" + default = false +} + +variable "ci_pipeline_scm_trigger_listener_name" { + type = string + description = "The name of EventListener for the CI Pipeline SCM Trigger as defined in tekton definition." + default = "grit-or-gitlab-commit" +} + +variable "ci_pipeline_max_concurrent_runs" { + type = number + description = "The number of maximum concurrent runs to be supported by CI Pipeline" + default = 1 +} + diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/versions.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/versions.tf new file mode 100644 index 000000000..88d6f0aa3 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-ci/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/environments.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/environments.tf new file mode 100644 index 000000000..c94bccaf4 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/environments.tf @@ -0,0 +1,20 @@ +resource "ibm_cd_tekton_pipeline_property" "pr_env_apikey" { + name = "apikey" + type = "secure" + value = format("{vault::%s.ibmcloud-api-key}", var.kp_integration_name) + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "pr_env_ibmcloud-api" { + name = "ibmcloud-api" + type = "text" + value = "https://cloud.ibm.com" + pipeline_id = var.pipeline_id +} + +resource "ibm_cd_tekton_pipeline_property" "pr_env_pipeline-debug" { + name = "pipeline-debug" + type = "text" + value = "0" + pipeline_id = var.pipeline_id +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/pipeline-pr.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/pipeline-pr.tf new file mode 100644 index 000000000..fd91fd602 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/pipeline-pr.tf @@ -0,0 +1,77 @@ +resource "ibm_cd_tekton_pipeline" "pr_pipeline_instance" { + pipeline_id = var.pipeline_id + worker { + id = "public" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_pipeline_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.pipeline_repo + branch = var.pipeline_branch + path = var.pipeline_path + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_git_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "git" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_toolchain_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "toolchain" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_linter_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "linter" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_tester_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "tester" + } +} + +resource "ibm_cd_tekton_pipeline_definition" "pr_utils_task_def" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + scm_source { + url = var.tekton_tasks_catalog_repo + branch = "master" + path = "utils" + } +} + +resource "ibm_cd_tekton_pipeline_trigger" "pr_pipeline_scm_trigger" { + pipeline_id = ibm_cd_tekton_pipeline.pr_pipeline_instance.pipeline_id + type = var.pr_pipeline_scm_trigger_type + name = var.pr_pipeline_scm_trigger_name + event_listener = var.pr_pipeline_scm_trigger_listener_name + scm_source { + url = var.app_repo + branch = "master" + } + events { + push = true + pull_request_closed = true + pull_request = true + } + max_concurrent_runs = var.pr_pipeline_max_concurrent_runs +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/variables.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/variables.tf new file mode 100644 index 000000000..48ae50f39 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/variables.tf @@ -0,0 +1,70 @@ +variable "pipeline_id" { +} + +variable "resource_group" { +} + +variable "app_name" { +} + +variable "region" { +} + +variable "ibm_cloud_api_key" { +} + +variable "kp_integration_name" { +} + +variable "app_repo" { +} + +variable "pipeline_repo" { + type = string + description = "The repository url containing pipeline definitions for Simple Helm Toolchain." +} + +variable "pipeline_branch" { + type = string + description = "The branch within pipeline definitions repository for Simple Helm Toolchain." + default = "main" +} + +variable "pipeline_path" { + type = string + description = "The relative folder path within pipeline definitions repository containing tekton definitions for pipelines." + default = ".pr-pipeline" +} + +variable "tekton_tasks_catalog_repo" { +} + +variable "pr_pipeline_scm_trigger_type" { + type = string + description = "The type of SCM Trigger for PR Pipeline as defined in tekton definition." + default = "scm" +} + +variable "pr_pipeline_scm_trigger_name" { + type = string + description = "The name of SCM Trigger for PR Pipeline as defined in tekton definition." + default = "SCM Trigger" +} + +variable "pr_pipeline_scm_trigger_listener_name" { + type = string + description = "The name of EventListener for the PR Pipeline SCM Trigger as defined in tekton definition." + default = "gitlab-pr-listener" +} + +variable "pr_pipeline_scm_trigger_disabled" { + type = bool + description = "Flag to disable SCM CI Trigger" + default = false +} + +variable "pr_pipeline_max_concurrent_runs" { + type = number + description = "The number of maximum concurrent runs to be supported by PR Pipeline" + default = 1 +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/versions.tf b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/versions.tf new file mode 100644 index 000000000..57fda86c7 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/pipeline-pr/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} diff --git a/examples/ibm-cd-toolchain-simple-helm/provider.tf b/examples/ibm-cd-toolchain-simple-helm/provider.tf new file mode 100644 index 000000000..d25d10ca7 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/provider.tf @@ -0,0 +1,7 @@ +provider "ibm" { + ibmcloud_api_key = var.ibm_cloud_api_key + region = var.region +} + + + diff --git a/examples/ibm-cd-toolchain-simple-helm/repositories/repositories.tf b/examples/ibm-cd-toolchain-simple-helm/repositories/repositories.tf new file mode 100644 index 000000000..37195e373 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/repositories/repositories.tf @@ -0,0 +1,56 @@ +resource "ibm_cd_toolchain_tool_hostedgit" "app_repo" { + toolchain_id = var.toolchain_id + name = "app-repo" + initialization { + type = "clone" + source_repo_url = var.app_repo + private_repo = true + repo_name = join("-", [ var.repositories_prefix, "app-repo" ]) + } + parameters { + has_issues = true + enable_traceability = true + } +} + +resource "ibm_cd_toolchain_tool_hostedgit" "pipeline_repo" { + toolchain_id = var.toolchain_id + name = "pipeline-repo" + initialization { + type = "clone" + repo_url = var.pipeline_repo + private_repo = true + repo_name = join("-", [ var.repositories_prefix, "pipeline-repo" ]) + } + parameters { + has_issues = false + enable_traceability = false + } +} + +resource "ibm_cd_toolchain_tool_hostedgit" "tekton_tasks_catalog_repo" { + toolchain_id = var.toolchain_id + name = "tasks-repo" + initialization { + type = "clone" + repo_url = var.tekton_tasks_catalog_repo + private_repo = true + repo_name = join("-", [ var.repositories_prefix, "tasks-repo" ]) + } + parameters { + has_issues = false + enable_traceability = false + } +} + +output "app_repo_url" { + value = ibm_cd_toolchain_tool_hostedgit.app_repo.parameters[0].repo_url +} + +output "pipeline_repo_url" { + value = ibm_cd_toolchain_tool_hostedgit.pipeline_repo.parameters[0].repo_url +} + +output "tekton_tasks_catalog_repo_url" { + value = ibm_cd_toolchain_tool_hostedgit.tekton_tasks_catalog_repo.parameters[0].repo_url +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/repositories/variables.tf b/examples/ibm-cd-toolchain-simple-helm/repositories/variables.tf new file mode 100644 index 000000000..76c0227d7 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/repositories/variables.tf @@ -0,0 +1,23 @@ +variable "app_repo" { +} + +variable "pipeline_repo" { +} + +variable "tekton_tasks_catalog_repo" { +} + +variable "toolchain_id" { +} + +variable "resource_group" { +} + +variable "region" { +} + +variable "ibm_cloud_api_key" { +} + +variable "repositories_prefix" { +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/repositories/versions.tf b/examples/ibm-cd-toolchain-simple-helm/repositories/versions.tf new file mode 100644 index 000000000..57fda86c7 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/repositories/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} diff --git a/examples/ibm-cd-toolchain-simple-helm/services/services.tf b/examples/ibm-cd-toolchain-simple-helm/services/services.tf new file mode 100644 index 000000000..95377983d --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/services/services.tf @@ -0,0 +1,44 @@ +#################################################################################### +# +# IBM Kubernetes Services Details +# +#################################################################################### + +// Limitation with datasource: Cannot fetch clusters for a specific region. Only query with cluster name. +// Can only fetch clusters in the region targeted for the provider. +# data "ibm_container_cluster" "kubernetes_cluster" { +# name = var.cluster_name +# } + +# output "ibm_container_cluster_name" { +# value = data.ibm_container_cluster.kubernetes_cluster.name +# } + +#################################################################################### +# +# IBM Container Registry Services Details +# +#################################################################################### + +// Limitation with datasource: Cannot fetch registry namespaces for a specific region. +// Can only fetch registries in the region targeted for the provider. +# data "ibm_cr_namespaces" "registry_namespace" {} + + +#################################################################################### +# +# IBM Key Protect Services Details +# +#################################################################################### + +data ibm_resource_instance "key_protect_instance" { + name = var.kp_name +} + +output "key_protect_instance_guid" { + value = data.ibm_resource_instance.key_protect_instance.guid +} + +output "key_protect_instance_name" { + value = data.ibm_resource_instance.key_protect_instance.name +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/services/variables.tf b/examples/ibm-cd-toolchain-simple-helm/services/variables.tf new file mode 100644 index 000000000..6c5edc2d5 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/services/variables.tf @@ -0,0 +1,29 @@ +variable "kp_name" { + type = string + description = "Name of the Key Protect Toolchain Service Instance in IBM Cloud" +} +variable "kp_region" { + type = string + description = "Resion of the Key Protect Toolchain Service Instance in IBM Cloud" +} + +variable "cluster_name" { +} + +variable "cluster_namespace" { +} + +variable "cluster_region" { +} + +variable "registry_namespace" { +} + +variable "registry_region" { +} + +variable "region" { +} + +variable "ibm_cloud_api" { +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/services/versions.tf b/examples/ibm-cd-toolchain-simple-helm/services/versions.tf new file mode 100644 index 000000000..88d6f0aa3 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/services/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/variables.tf b/examples/ibm-cd-toolchain-simple-helm/variables.tf new file mode 100644 index 000000000..f8fbcc895 --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/variables.tf @@ -0,0 +1,106 @@ +variable "resource_group" { + type = string + description = "Resource group within which toolchain will be created" + default = "Default" +} + +variable "ibm_cloud_api_key" { + type = string + description = "IBM Cloud API KEY to fetch cloud resources" +} + +variable "ibm_cloud_api" { + type = string + description = "IBM Cloud API Endpoint" + default = "https://cloud.ibm.com" +} + +variable "region" { + type = string + description = "IBM Cloud region where your toolchain will be created" + default = "us-south" +} + +variable "toolchain_name" { + type = string + description = "Name of the Toolchain." + default = "Simple Helm Toolchain" +} + +variable "toolchain_description" { + type = string + description = "Description for the Toolchain." + default = "Toolchain created using IBM Cloud Continuous Delivery Service" +} + +variable "app_name" { + type = string + description = "Name of the application." + default = "simple-helm-app" +} + +variable "app_image_name" { + type = string + description = "Name of the application image." + default = "simple-helm-app" +} + +variable "cluster_name" { + type = string + description = "Name of the kubernetes cluster where the application will be deployed." + default = "mycluster-free" +} + +variable "cluster_namespace" { + type = string + description = "Name of the kubernetes cluster where the application will be deployed." + default = "prod" +} + +variable "cluster_region" { + type = string + description = "Region of the kubernetes cluster where the application will be deployed." + default = "ibm:yp:us-south" +} + +variable "registry_namespace" { + type = string + description = "Namespace within the IBM Cloud Container Registry where application image need to be stored." + default = "myregistry-free" +} + +variable "registry_region" { + type = string + description = "IBM Cloud Region where the IBM Cloud Container Registry where registry is to be created." + default = "ibm:yp:us-south" +} + +variable "kp_name" { + type = string + description = "Name of the Key Protect Instance to store the secrets." + default = "Key Protect Service" +} + +variable "kp_region" { + type = string + description = "IBM Cloud Region where the Key Protect Instance is created." + default = "ibm:yp:us-south" +} + +variable "app_repo" { + type = string + description = "Repository url for the repository containing application source code." + default = "https://us-south.git.cloud.ibm.com/open-toolchain/hello-helm.git" +} + +variable "pipeline_repo" { + type = string + description = "Repository url for the repository containing pipeline source code." + default = "https://us-south.git.cloud.ibm.com/open-toolchain/simple-helm-toolchain.git" +} + +variable "tekton_tasks_catalog_repo" { + type = string + description = "Repository url for the repository containing commonly used tekton tasks." + default = "https://us-south.git.cloud.ibm.com/open-toolchain/tekton-catalog.git" +} \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/variables.tfvars.example b/examples/ibm-cd-toolchain-simple-helm/variables.tfvars.example new file mode 100644 index 000000000..9e3972cbe --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/variables.tfvars.example @@ -0,0 +1,32 @@ +/*****************************************************/ +/* Variables for Module "Main" */ +/*****************************************************/ +resource_group = "" +ibm_cloud_api_key = "" +region = "" +ibm_cloud_api = "" +toolchain_name = "some name for toolchain" +toolchain_description = "some description for toolchain" +app_name = "some name for the application that will be deployed by the toolchain" +app_image_name = "some name for the application docker image that will be created by the toolchain" + +/*****************************************************/ +/* Variables for Module "Repositories" */ +/*****************************************************/ +app_repo = "repository url for application repository" +pipeline_repo = "repository url for the pipeline repository" +tekton_tasks_catalog_repo = "repository url for the tekton tasks catalog repository" + +/*****************************************************/ +/* Variables for Module "Services" */ +/*****************************************************/ +cluster_name = "" +cluster_namespace = "some name for the namespace to be created in the cluster" +cluster_region = "" +registry_namespace = "some name for the namespace to be created in the registry" +registry_region = "" +kp_name = "" + +/*****************************************************/ +/* Variables for Module "Integrations" */ +/*****************************************************/ \ No newline at end of file diff --git a/examples/ibm-cd-toolchain-simple-helm/versions.tf b/examples/ibm-cd-toolchain-simple-helm/versions.tf new file mode 100644 index 000000000..8eedc1f1a --- /dev/null +++ b/examples/ibm-cd-toolchain-simple-helm/versions.tf @@ -0,0 +1,12 @@ +############################### +# IBM Cloud Copyright 2022 IBM +############################### + +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.45.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cis/main.tf b/examples/ibm-cis/main.tf index 57d343187..aa4b0ac9d 100644 --- a/examples/ibm-cis/main.tf +++ b/examples/ibm-cis/main.tf @@ -32,12 +32,30 @@ resource "ibm_cis_domain_settings" "web_domain" { brotli = "on" } +#Domain settings for IBM CIS instance for TLS v1.3 +resource "ibm_cis_domain_settings" "web_domain_tls_v1.3" { + cis_id = ibm_cis.web_domain.id + domain_id = ibm_cis_domain.web_domain.id + waf = "on" + ssl = "full" + min_tls_version = "1.3" + brotli = "on" + cipher = [] +} + #Adding valid Domain for IBM CIS instance resource "ibm_cis_domain" "web_domain" { cis_id = ibm_cis.web_domain.id domain = var.domain } +#Adding valid partial Domain for IBM CIS instance +resource "ibm_cis_domain" "web_domain" { + cis_id = ibm_cis.web_domain.id + domain = var.domain + type = "partial" +} + # CIS GLB Monitor|HealthCheck resource "ibm_cis_healthcheck" "root" { cis_id = ibm_cis.web_domain.id @@ -401,3 +419,199 @@ resource "ibm_cis_dns_records_import" "test" { domain_id = data.ibm_cis_domain.cis_domain.domain_id file = "dns_records.txt" } + +# CIS Webhooks +resource "ibm_cis_webhook" "test" { + cis_id = data.ibm_cis.cis.id + name = "test-Webhooks" + url = "https://hooks.slack.com/services/Ds3fdBFbV/1234568" + secret = "ZaHkAf0iNXNWn8ySUJjTJHkzlanchfnR4TISjOPC_I1U" +} + +# CIS Webhooks data source +data "ibm_cis_webhooks" "test1" { + cis_id = data.ibm_cis.cis.id +} + +# CIS Alert Policy +resource "ibm_cis_alert" "test" { + depends_on = [ibm_cis_webhook.test] + cis_id = data.ibm_cis.cis.id + name = "test-alert-police" + description = "alert policy description" + enabled = true + alert_type = "clickhouse_alert_fw_anomaly" + mechanisms { + email = ["mynotifications@email.com"] + webhooks = [ibm_cis_webhook.test.webhook_id] + } + filters =< 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.38+ | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| provision | Enable this to bind key to cloudant instance (true/false) | `bool` | true | +| rg_name | Enter resource group name for the instance | `string` | true | +| region | Provisioning Region for the instance | `string` | true | +| instance_name | Name of the cloudant instance | `string` | true | +| resource_key | Name of the resource key of the instance | `string` | true | +| legacy_credentials | Legacy authentication method for cloudant | `bool` | false | +| plan | plan type (standard and lite) | `string` | false | +| service_endpoints | Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private' | `string` | false | +| tags | Tags that should be applied to the service | `list` | false | +| service_policy_provision | Enable this to provision the service policy (true/false) | `bool` | true | +| service_name | Name of the service ID | `string` | true | +| description | Description to service ID | `string` | false | +| roles | service policy roles | `list` | false | +| db_name | Database name | `string` | true | +| is_partitioned | To set whether the database is partitioned | `bool` | false | +| cloudant_database_shards | The number of shards in the database. Each shard is a partition of the hash value range. Default set by server. | `number` | false | diff --git a/examples/ibm-cloudant-database/main.tf b/examples/ibm-cloudant-database/main.tf new file mode 100644 index 000000000..a8cf6c4b2 --- /dev/null +++ b/examples/ibm-cloudant-database/main.tf @@ -0,0 +1,44 @@ +data "ibm_resource_group" "res_group" { + name = var.rg_name +} + +module "cloudant-instance" { + //Uncomment the following line to point the source to registry level + //source = "terraform-ibm-modules/cloudant/ibm//modules/instance" + + source = "./modules/instance" + provision = var.provision + provision_resource_key = var.provision_resource_key + + instance_name = var.instance_name + resource_group_id = data.ibm_resource_group.res_group.id + plan = var.plan + region = var.region + service_endpoints = var.service_endpoints + legacy_credentials = var.legacy_credentials + tags = var.tags + resource_key_name = var.resource_key + role = var.role + resource_key_tags = var.resource_key_tags + + ################### + # Service Policy + ################### + service_policy_provision = var.service_policy_provision + service_name = var.service_name + description = var.description + roles = var.roles +} + +module "cloudant-database" { + //Uncomment the following line to point the source to registry level + //source = "terraform-ibm-modules/cloudant/ibm//modules/config-database" + + source = "./modules/config-database" + cloudant_instance_crn = module.cloudant-instance.cloudant_instance_crn + cloudant_database_partitioned = var.is_partitioned + db_name = var.db_name + cloudant_database_shards = var.cloudant_database_shards + + depends_on = [module.cloudant-instance] +} diff --git a/examples/ibm-cloudant-database/modules/config-database/README.md b/examples/ibm-cloudant-database/modules/config-database/README.md new file mode 100644 index 000000000..bf986b6e4 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/config-database/README.md @@ -0,0 +1,30 @@ +# Module Cloudant Database + +This module is used to create cloudant database. + +## Example Usage +``` +module "cloudant-database" { + //Uncomment the following line to point the source to registry level + //source = "terraform-ibm-modules/cloudant/ibm//modules/database" + + source = "../../modules/database" + db_name = var.db_name + cloudant_instance_crn = var.instance_crn + cloudant_database_partitioned = var.is_partitioned +} + +``` + + +## Inputs + + +| Name | Description | Type | Default | Required | +|-------------------------------|---------------------------------------------------------------------------------|:-------------|:------- |:---------| +| db_name | Database name | string | n/a | yes | +| cloudant_instance_crn | CRN of the cloudant instance. | string | n/a | yes | +| cloudant_database_partitioned | Enable partition database | bool | false | no | +| cloudant_database_shards | The number of shards in the database. Default set by server. | number | null | no | + + \ No newline at end of file diff --git a/examples/ibm-cloudant-database/modules/config-database/main.tf b/examples/ibm-cloudant-database/modules/config-database/main.tf new file mode 100644 index 000000000..d53c75673 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/config-database/main.tf @@ -0,0 +1,13 @@ + +// Provision cloudant_database resource instance +resource "ibm_cloudant_database" "cloudant_database_instance" { + instance_crn = var.cloudant_instance_crn + db = var.db_name + partitioned = var.cloudant_database_partitioned + shards = (var.cloudant_database_shards != null ? var.cloudant_database_shards : null) +} + +data "ibm_cloudant_database" "read_database" { + instance_crn = ibm_cloudant_database.cloudant_database_instance.instance_crn + db = var.db_name +} diff --git a/examples/ibm-cloudant-database/modules/config-database/variables.tf b/examples/ibm-cloudant-database/modules/config-database/variables.tf new file mode 100644 index 000000000..0522325c0 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/config-database/variables.tf @@ -0,0 +1,23 @@ + + +variable "cloudant_instance_crn" { + description = "The cloudant instance CRN" + type = string +} + +variable "db_name" { + type = string + description = "Database name" +} + +variable "cloudant_database_partitioned" { + description = "Query parameter to specify whether to enable database partitions when creating a database." + type = bool + default = false +} + +variable "cloudant_database_shards" { + description = "The number of shards in the database. Each shard is a partition of the hash value range. When omitted the default is set by the server." + type = number + default = null +} \ No newline at end of file diff --git a/examples/ibm-cloudant-database/modules/config-database/versions.tf b/examples/ibm-cloudant-database/modules/config-database/versions.tf new file mode 100644 index 000000000..90554b393 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/config-database/versions.tf @@ -0,0 +1,27 @@ +##################################################### +# Cloudant +# Copyright 2021 IBM +##################################################### + +/*************************************************** +NOTE: To source a particular version of IBM terraform provider, configure the parameter `version` as follows +terraform { + required_version = ">=0.13" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.21.0" + } + } +} +If we dont configure the version parameter, it fetches the latest provider version. +****************************************************/ + +terraform { + required_version = ">=0.13" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} diff --git a/examples/ibm-cloudant-database/modules/instance/README.md b/examples/ibm-cloudant-database/modules/instance/README.md new file mode 100644 index 000000000..e86bc95d3 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/instance/README.md @@ -0,0 +1,111 @@ +# IBM Cloud Cloudant - Terraform Module + +This is a collection of modules that make it easier to provision cloudant instance and assign service prolicy, create a database: +* [instance](modules/instance) +* [service-policy](modules/service-policy) +* [database](modules/database) + +## Compatibility + +This module is meant for use with Terraform 0.13 (and higher). + +## Usage + +Full examples are in the [examples](./examples/) folder, but basic usage is as follows for creation of a Cloudant instance & key: + +```hcl +provider "ibm" { +} + +data "ibm_resource_group" "cloudant" { + name = var.resource_group +} + +module "cloudant-instance" { + //Uncomment the following line to point the source to registry level + //source = "terraform-ibm-modules/cloudant/ibm//modules/instance" + + source = "../../modules/instance" + provision = var.provision + provision_resource_key = var.provision_resource_key + + instance_name = var.instance_name + resource_group_id = data.ibm_resource_group.cloudant.id + plan = var.plan + region = var.region + service_endpoints = var.service_endpoints + legacy_credentials = var.legacy_credentials + tags = var.tags + create_timeout = var.create_timeout + update_timeout = var.update_timeout + delete_timeout = var.delete_timeout + resource_key_name = var.resource_key_name + role = var.role + resource_key_tags = var.resource_key_tags + + ################### + # Service Policy + ################### + service_policy_provision = var.service_policy_provision + service_name = var.service_name + description = var.description + roles = var.roles +} + +``` + +## Requirements + +### Terraform plugins + +- [Terraform](https://www.terraform.io/downloads.html) 0.13 (or later) +- [terraform-provider-ibm](https://github.com/IBM-Cloud/terraform-provider-ibm) + +## Install + +### Terraform + +Be sure you have the correct Terraform version (0.13), you can choose the binary here: +- https://releases.hashicorp.com/terraform/ + +### Terraform plugins + +Be sure you have the compiled plugins on $HOME/.terraform.d/plugins/ + +- [terraform-provider-ibm](https://github.com/IBM-Cloud/terraform-provider-ibm) + +### Pre-commit hooks + +Run the following command to execute the pre-commit hooks defined in .pre-commit-config.yaml file +``` +pre-commit run -a +``` +You can install pre-coomit tool using + +``` +pip install pre-commit +``` +or +``` +pip3 install pre-commit +``` +## How to input varaible values through a file + +To review the plan for the configuration defined (no resources actually provisioned) +``` +terraform plan -var-file=./input.tfvars +``` +To execute and start building the configuration defined in the plan (provisions resources) +``` +terraform apply -var-file=./input.tfvars +``` + +To destroy the VPC and all related resources +``` +terraform destroy -var-file=./input.tfvars +``` + +## Note + +All optional parameters, by default, will be set to `null` in respective example's varaible.tf file. You can also override these optional parameters. + diff --git a/examples/ibm-cloudant-database/modules/instance/main.tf b/examples/ibm-cloudant-database/modules/instance/main.tf new file mode 100644 index 000000000..2118258ad --- /dev/null +++ b/examples/ibm-cloudant-database/modules/instance/main.tf @@ -0,0 +1,77 @@ +##################################################### +# Cloudant Instance +# Copyright 2021 IBM +##################################################### +resource "ibm_cloudant" "cloudant_instance" { + count = var.provision ? 1 : 0 + + name = var.instance_name + plan = var.plan + location = var.region + resource_group_id = var.resource_group_id + legacy_credentials = var.legacy_credentials + tags = (var.tags != null ? var.tags : []) + service_endpoints = (var.service_endpoints != "" ? var.service_endpoints : null) + + + //User can increase timeouts + timeouts { + create = (var.create_timeout != null ? var.create_timeout : null) + update = (var.update_timeout != null ? var.update_timeout : null) + delete = (var.delete_timeout != null ? var.delete_timeout : null) + } +} + +data "ibm_cloudant" "cloudant" { + count = var.provision ? 0 : 1 + + name = var.instance_name + location = var.region + resource_group_id = var.resource_group_id +} + + +//Create new service credentials with auto-generated service id +resource "ibm_resource_key" "resource_key" { + count = var.provision_resource_key ? 1 : 0 + + name = var.resource_key_name + role = var.role + resource_instance_id = var.provision == true ? ibm_cloudant.cloudant_instance.0.id : data.ibm_cloudant.cloudant.0.id + tags = (var.resource_key_tags != null ? var.resource_key_tags : []) +} + +data "ibm_resource_key" "cloudant_resource_key" { + count = var.provision_resource_key ? 0 : 1 + + name = var.resource_key_name + resource_instance_id = var.provision == true ? ibm_cloudant.cloudant_instance.0.id : data.ibm_cloudant.cloudant.0.id +} + + + +##################################################### +# Service Policy Configuration +##################################################### + +resource "ibm_iam_service_id" "serviceID" { + count = var.service_policy_provision ? 1 : 0 + + name = var.service_name + description = (var.description != null ? var.description : null) +} + +data "ibm_iam_service_id" "data_serviceID" { + count = var.service_policy_provision ? 0 : 1 + name = var.service_name +} + +resource "ibm_iam_service_policy" "policy" { + iam_service_id = var.service_policy_provision ? ibm_iam_service_id.serviceID.0.id : data.ibm_iam_service_id.ds_serviceID.0.id + roles = var.roles + + resources { + service = "cloudantnosqldb" + resource_instance_id = var.provision == true ? ibm_cloudant.cloudant_instance.0.id : data.ibm_cloudant.cloudant.0.id + } +} diff --git a/examples/ibm-cloudant-database/modules/instance/output.tf b/examples/ibm-cloudant-database/modules/instance/output.tf new file mode 100644 index 000000000..39393146f --- /dev/null +++ b/examples/ibm-cloudant-database/modules/instance/output.tf @@ -0,0 +1,64 @@ +##################################################### +# Cloudant +# Copyright 2021 IBM +##################################################### + +output "cloudant_id" { + description = "The ID of the cloudant instance" + value = var.provision ? concat(ibm_cloudant.cloudant_instance.*.id, [""])[0] : concat(data.ibm_cloudant.cloudant.*.id, [""])[0] +} + +output "cloudant_instance_name" { + description = "The name of the cloudant instance" + value = var.provision ? concat(ibm_cloudant.cloudant_instance.*.name, [""])[0] : concat(data.ibm_cloudant.cloudant.*.name, [""])[0] +} + +output "cloudant_instance_crn" { + description = "The CRN of the cloudant instance" + value = var.provision ? concat(ibm_cloudant.cloudant_instance.*.crn, [""])[0] : concat(data.ibm_cloudant.cloudant.*.crn, [""])[0] +} + +output "cloudant_key_id" { + description = "The ID of the cloudant key" + value = var.provision_resource_key ? concat(ibm_resource_key.resource_key.*.id, [""])[0] : concat(data.ibm_resource_key.cloudant_resource_key.*.id, [""])[0] +} + +output "cloudant_key_host" { + description = "API key" + value = var.provision_resource_key ? concat(ibm_resource_key.resource_key.*.credentials.host, [""])[0] : concat(data.ibm_resource_key.cloudant_resource_key.*.credentials.host, [""])[0] +} + +output "cloudant_key_username" { + description = "username" + value = var.provision_resource_key ? concat(ibm_resource_key.resource_key.*.credentials.username, [""])[0] : concat(data.ibm_resource_key.cloudant_resource_key.*.credentials.username, [""])[0] +} + +output "cloudant_key_password" { + description = "password" + value = var.provision_resource_key ? concat(ibm_resource_key.resource_key.*.credentials.password, [""])[0] : concat(data.ibm_resource_key.cloudant_resource_key.*.credentials.password, [""])[0] +} + +output "cloudant_key_apikey" { + description = "password" + value = var.provision_resource_key ? concat(ibm_resource_key.resource_key.*.credentials.apikey, [""])[0] : concat(data.ibm_resource_key.cloudant_resource_key.*.credentials.apikey, [""])[0] +} + + +##################################################### +# Service Policy +##################################################### + +output "cloudant_service_uuid" { + description = "The UUID of the service ID" + value = ibm_iam_service_policy.policy.iam_service_id +} + +output "cloudant_service_iam_id" { + description = "IAM ID of the service ID" + value = ibm_iam_service_policy.policy.iam_id +} + +output "cloudant_service_policy_id" { + description = "The ID of the service policy" + value = ibm_iam_service_policy.policy.id +} \ No newline at end of file diff --git a/examples/ibm-cloudant-database/modules/instance/variables.tf b/examples/ibm-cloudant-database/modules/instance/variables.tf new file mode 100644 index 000000000..4ea6ca722 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/instance/variables.tf @@ -0,0 +1,113 @@ +##################################################### +# Cloudant Instance +# Copyright 2021 IBM +##################################################### + +variable "provision" { + description = "Enable this to provision the cloudant instance (true/false)" + type = bool + default = true +} + +variable "provision_resource_key" { + description = "Enable this to bind key to cloudant instance (true/false)" + type = bool + default = true +} + +variable "instance_name" { + description = "Name of the cloudant instance" + type = string +} + +variable "plan" { + description = "plan type (standard and lite)" + type = string + default = "standard" +} + +variable "create_timeout" { + type = string + description = "Timeout duration for create." + default = null +} + +variable "update_timeout" { + type = string + description = "Timeout duration for update." + default = null +} + +variable "delete_timeout" { + type = string + description = "Timeout duration for delete." + default = null +} + +variable "resource_group_id" { + description = "Enter resource group name" + type = string +} + +variable "region" { + description = "Provisioning Region" + type = string +} + +variable "service_endpoints" { + description = "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'." + type = string + default = null +} + +variable "resource_key_name" { + description = "Name of the resource key" + type = string +} + +variable "tags" { + type = list(string) + description = "Tags that should be applied to the service" + default = null +} + +variable "legacy_credentials" { + description = "Legacy authentication method for cloudant" + type = bool + default = false +} + +variable "role" { + description = "Resource key role" + type = string +} + +variable "resource_key_tags" { + type = list(string) + description = "Tags that should be applied to the service" + default = null +} + +##################################################### +# Service Policy Configuration +##################################################### +variable "service_policy_provision" { + description = "Enable this to provision the service policy (true/false)" + type = bool +} + +variable "service_name" { + description = "Name of the service ID" + type = string +} + +variable "description" { + description = "Description to service ID" + type = string + default = null +} + +variable "roles" { + description = "service policy roles" + type = list(string) +} diff --git a/examples/ibm-cloudant-database/modules/instance/versions.tf b/examples/ibm-cloudant-database/modules/instance/versions.tf new file mode 100644 index 000000000..90554b393 --- /dev/null +++ b/examples/ibm-cloudant-database/modules/instance/versions.tf @@ -0,0 +1,27 @@ +##################################################### +# Cloudant +# Copyright 2021 IBM +##################################################### + +/*************************************************** +NOTE: To source a particular version of IBM terraform provider, configure the parameter `version` as follows +terraform { + required_version = ">=0.13" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.21.0" + } + } +} +If we dont configure the version parameter, it fetches the latest provider version. +****************************************************/ + +terraform { + required_version = ">=0.13" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} diff --git a/examples/ibm-cloudant-database/variables.tf b/examples/ibm-cloudant-database/variables.tf new file mode 100644 index 000000000..9620a0b27 --- /dev/null +++ b/examples/ibm-cloudant-database/variables.tf @@ -0,0 +1,125 @@ + +##################################################### +# Cloudant - database +# Copyright 2021 IBM +##################################################### + +##################################################### +# IBMCLOUD Cloudant Instance Variables +##################################################### + +variable "provision" { + description = "Enable this to provision the cloudant instance (true/false)" + type = bool + default = true +} + +variable "provision_resource_key" { + description = "Enable this to bind key to cloudant instance (true/false)" + type = bool + default = true +} + +variable "region" { + description = "Provisioning Region for the instance" + type = string + default = "us-south" +} + +variable "instance_name" { + description = "Name of the cloudant instance" + type = string +} + +variable "resource_key" { + description = "Name of the resource key of the instance" + type = string +} + +variable "rg_name" { + type = string + description = "Enter resource group name for the cloudant instance" +} + +variable "legacy_credentials" { + description = "Legacy authentication method for cloudant" + type = bool + default = false +} + +variable "plan" { + description = "plan type (standard and lite)" + type = string + default = "standard" +} + +variable "service_endpoints" { + description = "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'." + type = string + default = null +} + +variable "tags" { + type = list(string) + description = "Tags that should be applied to the service" + default = null +} + +variable "role" { + type = string + description = "Resource key role" + default = "Writer" +} + +variable "resource_key_tags" { + type = list(string) + description = "Tags that should be applied to the service" + default = null +} + +##################################################### +# Service Policy Configuration +##################################################### +variable "service_policy_provision" { + description = "Enable this to provision the service policy (true/false)" + type = bool + default = true +} + +variable "service_name" { + description = "Name of the service ID" + type = string +} + +variable "description" { + description = "Description to service ID" + type = string + default = null +} + +variable "roles" { + description = "service policy roles" + type = list(string) + default = ["Writer"] +} + + +##################################################### +# IBMCLOUD Cloudant Database Variables +##################################################### + +variable "db_name" { + type = string + description = "Database name" +} + +variable "is_partitioned" { + description = "To set whether the database is partitioned" + default = false +} + +variable "cloudant_database_shards" { + description = "The number of shards in the database. Each shard is a partition of the hash value range. When omitted the default is set by the server." + type = number + default = null +} diff --git a/examples/ibm-cloudant-database/versions.tf b/examples/ibm-cloudant-database/versions.tf new file mode 100644 index 000000000..8faec8521 --- /dev/null +++ b/examples/ibm-cloudant-database/versions.tf @@ -0,0 +1,11 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} + +provider "ibm" { + # Configuration options +} \ No newline at end of file diff --git a/examples/ibm-cloudant/README.md b/examples/ibm-cloudant/README.md index adcd9ffc2..921b53526 100644 --- a/examples/ibm-cloudant/README.md +++ b/examples/ibm-cloudant/README.md @@ -16,6 +16,7 @@ Examples can be found in the subfolders along with the instructions how to run t - [Lite plan with legacy credentials](lite-plan-legacy) - [Lite plan with IAM credentials](lite-plan-iam) - [Standard plan with custom capacity](standard-plan) +- [Standard plan with a new database](standard-plan-with-database) - [Standard plan with data event tracking](standard-plan-with-data-events) - [Standard plan on dedicated hardware](standard-plan-on-dedicated-hw) @@ -23,6 +24,9 @@ Examples can be found in the subfolders along with the instructions how to run t ## Notes +1. The credentials used by the Terraform provider must at a minimum have these roles or equivalent actions: + - `Administrator` role for Cloudant Platform + - `Viewer` role for the resource group that the resources will be in 1. With `Lite` plan `capacity` can be set no more than 1 throughput blocks. 1. `parameters` can overwrite the previously set arguments named the same way. 1. With [`Standard` plan on dedicated hardware](standard-plan-on-dedicated-hw) the hardware must be ordered separately and provisioning should be completed before using Terraform on it @@ -60,6 +64,7 @@ Examples can be found in the subfolders along with the instructions how to run t | resource_group_id | The resource group id. (Forces new resource.) | `string` | false | - | service_endpoints | Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'. | `string` | false | - | tags | Tags associated with the instance. | `set(string)` | false | - +| db_name | A name of database to create. | `string` | true | - | timeouts.create
timeouts.update
timeouts.delete | The operation of the IBM Cloudant instance is considered failed if no response received for the given timeout. | `string` | false | - ## Outputs diff --git a/examples/ibm-cloudant/standard-plan-with-database/README.md b/examples/ibm-cloudant/standard-plan-with-database/README.md new file mode 100644 index 000000000..ca1c504bd --- /dev/null +++ b/examples/ibm-cloudant/standard-plan-with-database/README.md @@ -0,0 +1,25 @@ +# IBM Cloudant example for Standard plan with a new database + +This example shows how to create a Standard plan Cloudant instance with a new database. + +To run, configure your IBM Cloudant provider + +Running the example + +For planning phase + +```sh +terraform plan +``` + +For apply phase + +```sh +terraform apply +``` + +For destroy + +```sh +terraform destroy +``` diff --git a/examples/ibm-cloudant/standard-plan-with-database/main.tf b/examples/ibm-cloudant/standard-plan-with-database/main.tf new file mode 100644 index 000000000..ac037d587 --- /dev/null +++ b/examples/ibm-cloudant/standard-plan-with-database/main.tf @@ -0,0 +1,30 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.service_region +} + +// Provision cloudant resource instance with Standard plan and 2 capacity throughput blocks +resource "ibm_cloudant" "cloudant" { + // Required arguments: + name = "test_standard_plan_cloudant" + location = var.service_region + plan = "standard" + // Optional arguments: + capacity = 2 +} + +// Create cloudant data source +data "ibm_cloudant" "cloudant" { + name = ibm_cloudant.cloudant.name +} + +// Create database with +resource "ibm_cloudant_database" "database" { + db = var.db_name + instance_crn = ibm_cloudant.cloudant.crn +} + +data "ibm_cloudant_database" "database" { + db = ibm_cloudant_database.database.db + instance_crn = ibm_cloudant_database.database.instance_crn +} \ No newline at end of file diff --git a/examples/ibm-cloudant/standard-plan-with-database/outputs.tf b/examples/ibm-cloudant/standard-plan-with-database/outputs.tf new file mode 100644 index 000000000..27fdbbd69 --- /dev/null +++ b/examples/ibm-cloudant/standard-plan-with-database/outputs.tf @@ -0,0 +1,6 @@ +// This allows cloudant data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cloudant" { + value = ibm_cloudant.cloudant + description = "cloudant resource instance" +} diff --git a/examples/ibm-cloudant/standard-plan-with-database/variables.tf b/examples/ibm-cloudant/standard-plan-with-database/variables.tf new file mode 100644 index 000000000..447cb74f3 --- /dev/null +++ b/examples/ibm-cloudant/standard-plan-with-database/variables.tf @@ -0,0 +1,18 @@ +// Resource arguments for ibmcloud_api_key +variable "ibmcloud_api_key" { + description = "IBM Cloud API key." + type = string +} + +// Resource arguments for service_region +variable "service_region" { + description = "Region in which service has to be provisioned." + type = string + default = "us-south" +} + +// Resource arguments for db +variable "db_name" { + description = "A name of database to create." + type = string +} diff --git a/examples/ibm-cloudant/standard-plan-with-database/versions.tf b/examples/ibm-cloudant/standard-plan-with-database/versions.tf new file mode 100644 index 000000000..d9b6f790b --- /dev/null +++ b/examples/ibm-cloudant/standard-plan-with-database/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.12" +} diff --git a/examples/ibm-cluster/vpc-gen2-cluster/README.md b/examples/ibm-cluster/vpc-gen2-cluster/README.md index 412b0c21d..35cb7a7d7 100644 --- a/examples/ibm-cluster/vpc-gen2-cluster/README.md +++ b/examples/ibm-cluster/vpc-gen2-cluster/README.md @@ -1,23 +1,16 @@ -# IBM VPC Gen2 Cluster example +# IBM Cloud VPC Gen 2 cluster example -This example shows how to create a Kubernetes VPC Gen-2 Cluster under a specified resource group id, with default worker node with given zone and subnets. To have a multizone cluster, update the zones with new zone-name and subnet-id. +This example shows how to create a Kubernetes VPC Gen-2 Cluster under a specified resource group ID, in a default worker node with given zone and subnets. To have a multizone cluster, update the zones with new zone-name and subnet-id. Following types of resources are supported: -* [ VPC Gen-2 Cluster Resource ](https://cloud.ibm.com/docs/terraform?topic=terraform-container-resources#vpc-gen2) - - -## Terraform versions - -Terraform 0.12. Pin module version to `~> v1.7.1`. Branch - `master`. - -Terraform 0.11. Pin module version to `~> v0.29.1`. Branch - `terraform_v0.11.x`. +* [VPC Gen 2 cluster resource](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-index-of-terraform-on-ibm-cloud-resources-and-data-sources#vpc-infrastructure_rd) ## Usage To run this example you need to execute: -```bash +```sh $ terraform init $ terraform plan $ terraform apply @@ -25,11 +18,11 @@ $ terraform apply Run `terraform destroy` when you don't need these resources. -## Example Usage +## Example usage Create a container cluster: -```hcl +```terraform resource "ibm_is_vpc" "vpc1" { name = "vpc" } @@ -78,7 +71,7 @@ resource "ibm_container_vpc_cluster" "cluster" { } ``` -```hcl +```terraform data "ibm_container_vpc_cluster" "cluster" { cluster_name_id = "vpccluster" resource_group_id = data.ibm_resource_group.group.id @@ -87,20 +80,20 @@ data "ibm_container_vpc_cluster" "cluster" { ## Examples -* [ VPC Gen-2 Cluster ](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-cluster/vpc-gen2-cluster) +* [VPC Gen 2 cluster](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-cluster/vpc-gen2-cluster) ## Requirements | Name | Version | |------|---------| -| terraform | ~> 0.12 | +| terraform | >=1.0.0, <2.0 | ## Providers | Name | Version | |------|---------| -| ibm | n/a | +| ibm | latest | ## Inputs @@ -108,12 +101,14 @@ data "ibm_container_vpc_cluster" "cluster" { |------|-------------|------|---------| | name | Name of the cluster. | `string` | yes | | flavor | The flavor of the VPC worker node that you want to use. | `string` | yes | -| worker\_count | The number of worker nodes per zone in the default worker pool. Default value `1`.| `integer` | no | +| worker_count | The number of worker nodes per zone in the default worker pool. Default value `1`.| `integer` | no | | zone | Name of the zone.| `string` | yes | -| resource\_group | Name of the resource group.| `string` | yes | +| resource_group | Name of the resource group.| `string` | yes | +{: caption="inputs"} ## Outputs | Name | Description | |------|-------------| -| cluster_config_file_path | Path where cluster config file is written to. | \ No newline at end of file +| cluster_config_file_path | Path where cluster config file is written to. | +{: caption="outputs"} diff --git a/examples/ibm-cluster/vpc-gen2-cluster/versions.tf b/examples/ibm-cluster/vpc-gen2-cluster/versions.tf index ac97c6ac8..80fb63aec 100644 --- a/examples/ibm-cluster/vpc-gen2-cluster/versions.tf +++ b/examples/ibm-cluster/vpc-gen2-cluster/versions.tf @@ -1,4 +1,12 @@ +############################### +# IBM Cloud Copyright 2020 IBM +############################### terraform { - required_version = ">= 0.12" -} +required_version = ">=1.0.0, <2.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-context-based-restrictions/README.md b/examples/ibm-context-based-restrictions/README.md new file mode 100644 index 000000000..405a09f17 --- /dev/null +++ b/examples/ibm-context-based-restrictions/README.md @@ -0,0 +1,100 @@ +# Example for ContextBasedRestrictionsV1 + +This example illustrates how to use the ContextBasedRestrictionsV1 + +These types of resources are supported: + +* cbr_zone +* cbr_rule + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## ContextBasedRestrictionsV1 resources + +cbr_zone resource: + +```hcl +resource "cbr_zone" "cbr_zone_instance" { + name = var.cbr_zone_name + account_id = var.cbr_zone_account_id + description = var.cbr_zone_description + addresses = var.cbr_zone_addresses + excluded = var.cbr_zone_excluded +} +``` +cbr_rule resource: + +```hcl +resource "cbr_rule" "cbr_rule_instance" { + description = var.cbr_rule_description + contexts = var.cbr_rule_contexts + resources = var.cbr_rule_resources +} +``` + +## ContextBasedRestrictionsV1 Data sources + +cbr_zone data source: + +```hcl +data "cbr_zone" "cbr_zone_instance" { + zone_id = var.cbr_zone_zone_id +} +``` +cbr_rule data source: + +```hcl +data "cbr_rule" "cbr_rule_instance" { + rule_id = var.cbr_rule_rule_id +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| name | The name of the zone. | `string` | false | +| account_id | The id of the account owning this zone. | `string` | false | +| description | The description of the zone. | `string` | false | +| addresses | The list of addresses in the zone. | `list()` | false | +| excluded | The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded. | `list()` | false | +| description | The description of the rule. | `string` | false | +| contexts | The contexts this rule applies to. | `list()` | false | +| resources | The resources this rule apply to. | `list()` | false | +| operations | The operations this rule applies to. | `` | false | +| enforcement_mode | The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced. | `string` | false | +| zone_id | The ID of a zone. | `string` | true | +| rule_id | The ID of a rule. | `string` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| cbr_zone | cbr_zone object | +| cbr_rule | cbr_rule object | +| cbr_zone | cbr_zone object | +| cbr_rule | cbr_rule object | diff --git a/examples/ibm-context-based-restrictions/main.tf b/examples/ibm-context-based-restrictions/main.tf new file mode 100644 index 000000000..cdbde0e64 --- /dev/null +++ b/examples/ibm-context-based-restrictions/main.tf @@ -0,0 +1,64 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Provision cbr_zone resource instance +resource "ibm_cbr_zone" "cbr_zone_instance" { + name = "A terraform example of network zone" + account_id = var.ibmcloud_account_id + description = "A terraform example of network zone" + addresses { + type = "ipAddress" + value = "169.23.56.234" + } + addresses { + type = "ipRange" + value = "169.23.22.0-169.23.22.255" + } + excluded { + type = "ipAddress" + value = "169.23.22.10" + } +} + +// Provision cbr_rule resource instance +resource "ibm_cbr_rule" "cbr_rule_instance" { + description = var.cbr_rule_description + contexts { + attributes { + name = "networkZoneId" + value = ibm_cbr_zone.cbr_zone_instance.id + } + } + resources { + attributes { + name = "accountId" + value = var.ibmcloud_account_id + } + attributes { + name = "serviceName" + value = "containers-kubernetes" + } + tags { + name = "tag_name" + value = "tag_value" + } + } + operations { + api_types { + api_type_id = "crn:v1:bluemix:public:containers-kubernetes::::api-type:management" + } + } + enforcement_mode = "disabled" +} + +// Create cbr_zone data source +data "ibm_cbr_zone" "cbr_zone_instance" { + zone_id = ibm_cbr_zone.cbr_zone_instance.id +} + + +// Create cbr_rule data source +data "ibm_cbr_rule" "cbr_rule_instance" { + rule_id = ibm_cbr_rule.cbr_rule_instance.id +} diff --git a/examples/ibm-context-based-restrictions/outputs.tf b/examples/ibm-context-based-restrictions/outputs.tf new file mode 100644 index 000000000..df4753e9f --- /dev/null +++ b/examples/ibm-context-based-restrictions/outputs.tf @@ -0,0 +1,12 @@ +// This allows cbr_zone data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cbr_zone" { + value = ibm_cbr_zone.cbr_zone_instance + description = "cbr_zone resource instance" +} +// This allows cbr_rule data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_cbr_rule" { + value = ibm_cbr_rule.cbr_rule_instance + description = "cbr_rule resource instance" +} diff --git a/examples/ibm-context-based-restrictions/variables.tf b/examples/ibm-context-based-restrictions/variables.tf new file mode 100644 index 000000000..3ce2c1dbc --- /dev/null +++ b/examples/ibm-context-based-restrictions/variables.tf @@ -0,0 +1,46 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Resource arguments for cbr_zone +variable "cbr_zone_name" { + description = "The name of the zone." + type = string + default = "an example of zone" +} +variable "cbr_zone_description" { + description = "The description of the zone." + type = string + default = "this is an example of zone" +} + + +// Resource arguments for cbr_rule +variable "cbr_rule_description" { + description = "The description of rule." + type = string + default = "A terraform example of rule" +} + +// Data source arguments for cbr_zone +variable "cbr_zone_zone_id" { + description = "The ID of a zone." + type = string + default = "559052eb8f43302824e7ae490c0281eb" +} + +// Data source arguments for cbr_rule +variable "cbr_rule_rule_id" { + description = "The ID of a rule." + type = string + default = "07bca38c06db1a6e125d9738c701f2c1" +} + + +// IBM cloud account ID +variable "ibmcloud_account_id" { + description = "Account ID for rule / zone" + type = string + default = "12ab34cd56ef78ab90cd12ef34ab56cd" +} \ No newline at end of file diff --git a/examples/ibm-context-based-restrictions/versions.tf b/examples/ibm-context-based-restrictions/versions.tf new file mode 100644 index 000000000..69693066d --- /dev/null +++ b/examples/ibm-context-based-restrictions/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.31.0" + } + } +} \ No newline at end of file diff --git a/examples/ibm-cos-bucket/README.md b/examples/ibm-cos-bucket/README.md index d6b828091..15b49148d 100644 --- a/examples/ibm-cos-bucket/README.md +++ b/examples/ibm-cos-bucket/README.md @@ -4,20 +4,13 @@ The following example creates an instance of IBM Cloud Object Storage, IBM Cloud Following types of resources are supported: -* [ Cloud Object Storage Resource](https://cloud.ibm.com/docs/terraform?topic=terraform-object-storage-resources#cos-bucket) - - -## Terraform versions - -Terraform 0.12. Pin module version to `~> v1.7.1`. Branch - `master`. - -Terraform 0.11. Pin module version to `~> v0.29.1`. Branch - `terraform_v0.11.x`. +* [Cloud Object Storage resource](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-index-of-terraform-on-ibm-cloud-resources-and-data-sources#ibm-object-storage_rd) ## Usage To run this example you need to execute: -```bash +```sh $ terraform init $ terraform plan $ terraform apply @@ -29,7 +22,7 @@ Run `terraform destroy` when you don't need these resources. Create an IBM Cloud Object Storage bucket. The bucket is used to store your data: -```hcl +```terraform data "ibm_resource_group" "cos_group" { name = var.resource_group_name @@ -96,6 +89,62 @@ resource "ibm_cos_bucket" "archive_expire_rule_cos" { prefix = "logs/" } } +resource "ibm_cos_bucket" "expirebucket" { + bucket_name = "a-bucket-expiredat" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + force_delete = true + object_versioning { + enable = true + } + expire_rule { + rule_id = "a-bucket-expire-rule" + enable = true + date = "2021-11-18" + prefix = "logs/" + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-expireddelemarkertest" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } + expire_rule { + rule_id = "my-rule-id-bucket-expired" + enable = true + expired_object_delete_marker = true + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-multipartupload" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = "" + days_after_initiation = 1 + } +} resource "ibm_cos_bucket" "retention_cos" { bucket_name = "a-bucket-retention" @@ -125,7 +174,7 @@ resource "ibm_cos_bucket" "objectversioning" { ``` -```hcl +```terraform data "ibm_resource_instance" "cos_instance" { name = "cos-instance" resource_group_id = data.ibm_resource_group.cos_group.id @@ -142,45 +191,219 @@ data "ibm_cos_bucket" "standard-ams03" { ## Examples -* [ Cloud Objcet Storage ](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-cos-bucket) +* [Cloud Object Storage](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-cos-bucket) + + + +## COS SATELLITE + +The following example creates a bucket and add object versioning and expiration features on COS satellite location. As of now we are using existing cos instance to create bucket , so no need to create any cos instance via a terraform. We don't have any resource group in satellite.We can not use storage_class with Satellite location id. + +* [IBM Satellite](https://cloud.ibm.com/docs/satellite?topic=satellite-getting-started) +* [IBM COS Satellite](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-about-cos-satellite) + +## Example Usage + +```terraform +data "ibm_resource_group" "group" { + name = "Default" +} + +resource "ibm_satellite_location" "create_location" { + location = var.location + zones = var.location_zones + managed_from = var.managed_from + resource_group_id = data.ibm_resource_group.group.id +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "cos-sat-terraform" + resource_instance_id = data.ibm_resource_instance.cos_instance.id + satellite_location_id = data.ibm_satellite_location.create_location.id + object_versioning { + enable = true + } + expire_rule { + rule_id = "bucket-tf-rule1" + enable = false + days = 20 + prefix = "logs/" + } +} +``` + +## COS REPLICATION + +Replication allows users to define rules for automatic, asynchronous copying of objects from a source bucket to a destination bucket in the same or different location. + +**Note:** + + you must have `writer` or `manager` platform roles on source bucket and sufficient platform roles to create new [IAM policies](https://cloud.ibm.com/docs/account?topic=account-iamoverview#iamoverview) that allow the source bucket to write to the destination bucket. + Add depends_on on ibm_iam_authorization_policy.policy in template to make sure replication only enabled once iam authorization policy set. + +## Example usage +The following example creates an instance of IBM Cloud Object Storage. Then, multiple buckets are created and configured replication policy. + +```terraform +data "ibm_resource_group" "cos_group" { + name = "cos-resource-group" +} + +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "a-bucket-source" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "a-bucket-destination" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + + +### Configure IAM authorization policy + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "an-account-id" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + value = "an-account-id" + } + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + value = "bucket" + } +} + +### Configure replication policy + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "a-rule-id" + enable = "true" + prefix = "a-prefix" + priority = "a-priority-associated-with-the-rule" + deletemarker_replication_status = "Enabled/Suspened" + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } +} + +``` + ## Requirements | Name | Version | |------|---------| -| terraform | ~> 0.12 | +| terraform | >=1.0.0, <2.0 | ## Providers | Name | Version | |------|---------| -| ibm | n/a | +| ibm | Latest | ## Inputs | Name | Description | Type | Required | |------|-------------|------|---------| -| bucket\_name | Name of the bucket. | `string` | yes | -| resource\_group\_name | Name of the resource group. | `string` | yes | -| storage | The storage class that you want to use for the bucket. Supported values are standard, vault, cold, flex, and smart.| `string` | no | -| region | The location for a cross-regional bucket. Supported values are us, eu, and ap. | `string` | no | -| read_data_events | Enables sending log data to Activity Tracker and LogDNA to provide visibility into object read and write events.. | `array` | no -| write_data_events | all object write events (i.e. uploads) will be sent to Activity Tracker. | `bool` | no +| bucket_name | Name of the bucket. | `string` | yes | +| resource_group_name | Name of the resource group. | `string` | yes | +| satellite_location_id | satellite location. | `string` | no | +| storage | The storage class that you want to use for the bucket. Supported values are **standard, vault, cold, flex, and smart**.| `string` | no | +| region | The location for a cross-regional bucket. Supported values are **us, eu, and ap**. | `string` | no | +| read_data_events | Enables sending log data to Activity Tracker and LogDNA to provide visibility into object read and write events. | `array` | no +| write_data_events | All object write events (i.e. uploads) will be sent to Activity Tracker. | `bool` | no | activity_tracker_crn | Required the first time activity_tracking is configured. | `string` | yes -| usage_metrics_enabled | Specify true or false to set usage metrics (i.e. bytes_used). | `bool` | no -| request_metrics_enabled | Specify true or false to set cos request metrics (i.e. get,put,post request). | `bool` | no +| usage_metrics_enabled | Specify **true or false** to set usage metrics (i.e. bytes_used). | `bool` | no +| request_metrics_enabled | Specify true or false to set cos request metrics (i.e. get, put, or post request). | `bool` | no | metrics_monitoring_crn | Required the first time metrics_monitoring is configured. The instance of IBM Cloud Monitoring that will receive the bucket metrics. | `string` | yes -| archive_ruleid | Unique identifier for the rule. | `string` | no -| regional_loc | The location for a regional bucket. Supported values are au-syd, eu-de, eu-gb, jp-tok,,us-east,us-south. | `string` | no -| archive_days | Specifies the number of days when the specific archive rule action takes effect. | `int` | yes -| archive_types | Specifies the archive type to which you want the object to transition. Supported values are Glacier or Accelerated. | `string` | yes -| expire_ruleid | Unique identifier for the rule. | `string` | no -| expire_days | Specifies the number of days when the specific expire rule action takes effect. | `int` | yes -| expire_prefix | Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. | `string` | no +| regional_loc | The location for a regional bucket. Supported values are **au-syd, eu-de, eu-gb, jp-tok, us-east, or us-south**. | `string` | no +| type | Specifies the archive type to which you want the object to transition. Supported values are **Glacier or Accelerated**. | `string` |yes +| rule_id | Unique identifier for the rule. | `string` | no +| days | Specifies the number of days when the specific expire rule action takes effect. | `int` | no +| date | After the specifies date , the current version of objects in your bucket expires. | `string` | no +| expired_object_delete_marker | Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration. | `bool` | no +| prefix | Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. | `string` | no +| noncurrent_days | Configuration parameter in your policy that says how long to retain a non-current version before deleting it. | `int` | no +| days_after_initiation | Specifies the number of days that govern the automatic cancellation of part upload. Clean up incomplete multi-part uploads after a period of time. | `int` | no | default | Specifies a default retention period to apply in all objects in the bucket. | `int` | yes | maximum | Specifies maximum duration of time an object can be kept unmodified in the bucket. | `int` | yes | minimum | Specifies minimum duration of time an object must be kept unmodified in the bucket. | `int` | yes | permanent | Specifies a permanent retention status either enable or disable for a bucket. | `bool` | no -| enable | Specifies Versioning status either enable or Suspended for the objects in the bucket. | `bool` | no -| hard_quota | sets a maximum amount of storage (in bytes) available for a bucket. | `int` | no \ No newline at end of file +| enable | Specifies Versioning status either **enable or suspended** for an objects in the bucket. | `bool` | no +| hard_quota | sets a maximum amount of storage (in bytes) available for a bucket. | `int` | no +| bucket\_crn | The CRN of the source COS bucket. | `string` | yes | +| bucket\_location | The location of the source COS bucket. | `string` | yes | +| destination_bucket_crn | The CRN of your destination bucket that you want to replicate to. | `String` | yes +| deletemarker_replication_status | Specifies whether Object storage replicates delete markers. Specify true for Enabling it or false for Disabling it. | `String` | no +| status | Specifies whether the rule is enabled. Specify true for Enabling it or false for Disabling it. | `String` | yes +| rule_id | The rule id. | `String` | no +| priority | A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority | `String` | no +| prefix | An object key name prefix that identifies the subset of objects to which the rule applies. | `String` | no +{: caption="inputs"} diff --git a/examples/ibm-cos-bucket/main.tf b/examples/ibm-cos-bucket/main.tf index c884c870a..92b1f3fcf 100644 --- a/examples/ibm-cos-bucket/main.tf +++ b/examples/ibm-cos-bucket/main.tf @@ -13,14 +13,14 @@ resource "ibm_resource_instance" "activity_tracker" { resource_group_id = data.ibm_resource_group.cos_group.id service = "logdnaat" plan = "lite" - location = "us-south" + location = var.regional_loc } resource "ibm_resource_instance" "metrics_monitor" { name = "metrics_monitor" resource_group_id = data.ibm_resource_group.cos_group.id service = "sysdig-monitor" plan = "graduated-tier" - location = "us-south" + location = var.regional_loc parameters = { default_receiver = true } @@ -29,7 +29,7 @@ resource "ibm_cos_bucket" "standard-ams03" { bucket_name = var.bucket_name resource_instance_id = ibm_resource_instance.cos_instance.id single_site_location = var.single_site_loc - storage_class = var.storage + storage_class = var.standard_storage_class hard_quota = var.quota activity_tracking { read_data_events = true @@ -48,7 +48,7 @@ resource "ibm_cos_bucket" "lifecycle_rule_cos" { bucket_name = var.bucket_name resource_instance_id = ibm_resource_instance.cos_instance.id region_location = var.regional_loc - storage_class = var.storage + storage_class = var.standard_storage_class hard_quota = var.quota archive_rule { rule_id = var.archive_ruleid @@ -74,13 +74,248 @@ resource "ibm_cos_bucket" "cos_bucket" { bucket_name = var.bucket_name resource_instance_id = ibm_resource_instance.cos_instance.id region_location = var.regional_loc - storage_class = var.storage + storage_class = var.standard_storage_class hard_quota = var.quota object_versioning { enable = true } + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = var.abort_mpu_prefix + days_after_initiation = var.abort_mpu_days_init + } + expire_rule { + rule_id = var.expire_ruleid + enable = true + date = var.expire_date + prefix = var.expire_prefix + } + noncurrent_version_expiration { + rule_id = var.nc_exp_ruleid + enable = true + prefix = var.nc_exp_prefix + noncurrent_days = var.nc_exp_days + } +} +//Replication +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "sourcetest" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = var.regional_loc + storage_class = var.standard_storage_class + object_versioning { + enable = true + } +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "desttest" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = var.regional_loc + storage_class = var.standard_storage_class + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination_1" { + bucket_name = "desttest01" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = var.regional_loc + storage_class = var.standard_storage_class + object_versioning { + enable = true + } +} + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } +} + +resource "ibm_iam_authorization_policy" "policy1" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination_1.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } } + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy, ibm_iam_authorization_policy.policy1 + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + enable = true + prefix = var.replicate_prefix + priority = var.replicate_priority + deletemarker_replication_status = var.delmarkerrep_status + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } + replication_rule { + enable = true + priority = "2" + deletemarker_replication_status = var.delmarkerrep_status + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination_1.crn + } +} + +//HPCS - standard plan +resource ibm_hpcs hpcs { + location = var.location + name = "hpcs-instance" + plan = var.hpcs_plan + units = var.units + signature_threshold = var.signature_threshold + revocation_threshold = var.revocation_threshold + dynamic admins { + for_each = var.admins + content { + name = admins.value.name + key = admins.value.key + token = admins.value.token + } + } +} +resource "ibm_iam_authorization_policy" "policy2" { + source_service_name = "cloud-object-storage" + target_service_name = "hs-crypto" + roles = ["Reader"] +} +resource "ibm_kms_key" "key" { + instance_id = ibm_hpcs.hpcs.guid + key_name = var.hpcs_key_name + standard_key = false + force_delete = true +} + +resource "ibm_cos_bucket" "hpcs-enabled" { + depends_on = [ibm_iam_authorization_policy.policy2] + bucket_name = var.bucket_name + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = var.regional_loc + storage_class = var.standard_storage_class + key_protect = ibm_kms_key.key.id +} + +//HPCS - UKO plan +resource "ibm_cos_bucket" "hpcs-uko-enabled" { + depends_on = [ibm_iam_authorization_policy.policy2] + bucket_name = var.bucket_name + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = var.regional_loc + storage_class = var.standard_storage_class + key_protect = var.hpcs_uko_rootkeycrn +} resource "ibm_cos_bucket_object" "plaintext" { bucket_crn = ibm_cos_bucket.cos_bucket.crn bucket_location = ibm_cos_bucket.cos_bucket.region_location @@ -94,3 +329,36 @@ resource "ibm_cos_bucket_object" "base64" { content_base64 = "RW5jb2RlZCBpbiBiYXNlNjQ=" key = "base64.txt" } + +//Satellite Location +resource "ibm_cos_bucket" "cos_bucket_sat" { + bucket_name = var.bucket_name + resource_instance_id = "crn:v1:bluemix:public:cloud-object-storage:satloc_wdc_c8jh7hfw0ppoapdqrmpg:a/d0c259a490e4488c83b62707ad3f5182:756ad6b6-72a6-4e55-8c94-b02e51e708b3::" + satellite_location_id = var.satellite_location_id + object_versioning { + enable = true + } + expire_rule { + rule_id = "bucket-tf-rule1" + enable = false + days = 20 + prefix = "logs/" + } +} + +//One Rate COS plan + +resource "ibm_resource_instance" "cos_instance_onerate" { + name = "cos-instance-onerate" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" +} +resource "ibm_cos_bucket" "cos_bucket_onerate" { + bucket_name = var.bucket_name + resource_instance_id = ibm_resource_instance.cos_instance_onerate.id + region_location = var.regional_loc + storage_class = var.onerate_storage_class + } + \ No newline at end of file diff --git a/examples/ibm-cos-bucket/provider.tf b/examples/ibm-cos-bucket/provider.tf index 3e54a3bf6..8a9ca7d17 100644 --- a/examples/ibm-cos-bucket/provider.tf +++ b/examples/ibm-cos-bucket/provider.tf @@ -14,4 +14,4 @@ provider "ibm" { iaas_classic_username = var.iaas_classic_username iaas_classic_api_key = var.iaas_classic_api_key ibmcloud_api_key = var.ibmcloud_api_key -} \ No newline at end of file +} diff --git a/examples/ibm-cos-bucket/variables.tf b/examples/ibm-cos-bucket/variables.tf index 8ae98e179..fd595742f 100644 --- a/examples/ibm-cos-bucket/variables.tf +++ b/examples/ibm-cos-bucket/variables.tf @@ -6,10 +6,15 @@ variable "resource_group_name" { default = "Default" } -variable "storage" { +variable "standard_storage_class" { default = "standard" } +variable "onerate_storage_class" { + default = "onerate_active" +} + + variable "region" { default = "us" } @@ -42,10 +47,38 @@ variable "expire_days" { default = 1 } +variable "expire_date" { + default = "2022-06-09" +} + variable "expire_prefix" { default = "" } +variable "nc_exp_ruleid" { + default = "test-obj-ver-exp-3" +} + +variable "nc_exp_days" { + default = 1 +} + +variable "nc_exp_prefix" { + default = "" +} + +variable "abort_mpu_ruleid" { + default = "test-abort_mpu-5" +} + +variable "abort_mpu_days_init" { + default = 1 +} + +variable "abort_mpu_prefix" { + default = "" +} + variable "default_retention" { default = "0" } @@ -60,4 +93,63 @@ variable "maximum_retention" { variable "quota" { default = "1" -} \ No newline at end of file +} + +variable "satellite_location_id" { + default = "" +} + +variable "replicate_ruleid" { + default = "" +} + +variable "replicate_prefix" { + default = "" +} + +variable "replicate_priority" { + default = "1" +} + +variable "delmarkerrep_status" { + default = true +} + +variable "dest_rep_bkt_crn" { + default = "" +} + +variable "hpcs_location" { + default = "us-south" + type = string +} +variable "hpcs_plan" { + default = "standard" + type = string +} +variable "hpcs_crypto_units" { + type = number + default = 2 +} +variable "hpcs_signature_threshold" { + type = number + default = 1 +} +variable "hpcs_revocation_threshold" { + type = number + default = 1 +} +variable "hpcs_crypto_unit_admins" { + type = list(object({ + name = string + key = string + token = string + })) +} +# Key name that has to be created on the HPCS Instance +variable "hpcs_key_name" { + type = string +} +variable "hpcs_uko_rootkeycrn" { + default = "" +} diff --git a/examples/ibm-cos-bucket/versions.tf b/examples/ibm-cos-bucket/versions.tf index ac97c6ac8..80fb63aec 100644 --- a/examples/ibm-cos-bucket/versions.tf +++ b/examples/ibm-cos-bucket/versions.tf @@ -1,4 +1,12 @@ +############################### +# IBM Cloud Copyright 2020 IBM +############################### terraform { - required_version = ">= 0.12" -} +required_version = ">=1.0.0, <2.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-dedicated-host/main.tf b/examples/ibm-dedicated-host/main.tf new file mode 100644 index 000000000..b86e9ef7e --- /dev/null +++ b/examples/ibm-dedicated-host/main.tf @@ -0,0 +1,60 @@ +data "ibm_container_dedicated_host_flavor" "dhostflavor" { + host_flavor_id = var.dhostflavorid + zone = var.zone +} + +resource "ibm_container_dedicated_host_pool" "dhostpool" { + name = var.dhostpoolname + flavor_class = data.ibm_container_dedicated_host_flavor.dhostflavor.flavor_class + metro = var.metro + resource_group_id = var.resource_group_id +} + +resource "ibm_container_dedicated_host" "dhost" { + flavor = data.ibm_container_dedicated_host_flavor.dhostflavor.host_flavor_id + host_pool_id = ibm_container_dedicated_host_pool.dhostpool.id + zone = var.zone +} + +data "ibm_is_vpc" "vpc" { + name = var.vpc_name +} + +data "ibm_is_subnet" "subnet" { + name = var.subnet_name +} + +resource "ibm_container_vpc_cluster" "dhost_vpc_cluster" { + name = var.cluster_name + vpc_id = data.ibm_is_vpc.vpc.id + flavor = var.flavor + zones { + name = var.zone + subnet_id = data.ibm_is_subnet.subnet.id + } + worker_count = var.worker_count + resource_group_id = var.resource_group_id + wait_till = "OneWorkerNodeReady" + host_pool_id = ibm_container_dedicated_host_pool.dhostpool.id + + depends_on = [ + ibm_container_dedicated_host.dhost + ] +} + +resource "ibm_container_vpc_worker_pool" "dhost_vpc_worker_pool" { + cluster = ibm_container_vpc_cluster.dhost_vpc_cluster.name + worker_pool_name = var.worker_pool_name + flavor = ibm_container_vpc_cluster.dhost_vpc_cluster.flavor + vpc_id = ibm_container_vpc_cluster.dhost_vpc_cluster.vpc_id + host_pool_id = ibm_container_vpc_cluster.dhost_vpc_cluster.host_pool_id + worker_count = var.worker_count + zones { + name = var.zone + subnet_id = data.ibm_is_subnet.subnet.id + } + depends_on = [ + ibm_container_dedicated_host.dhost + ] +} + diff --git a/examples/ibm-dedicated-host/variables.tf b/examples/ibm-dedicated-host/variables.tf new file mode 100644 index 000000000..6c19f49a9 --- /dev/null +++ b/examples/ibm-dedicated-host/variables.tf @@ -0,0 +1,47 @@ +variable "ibmcloud_api_key" { + default = "" +} + +variable "resource_group_id" { + default = "" +} + +variable "metro" { + default = "dal" +} + +variable "zone" { + default = "us-south-2" +} + +variable "dhostflavorid" { + default = "bx2d.host.152x608" +} + +variable "dhostpoolname" { + default = "tf-dhostpool-1" +} + +variable "cluster_name" { + default = "tf-dhost-vpc-cluster" +} + +variable "worker_pool_name" { + default = "tf-dhost-vpc-worker-pool" +} + +variable "vpc_name" { + default = "tf-vpc" +} + +variable "subnet_name" { + default = "tf-subnet" +} + +variable "flavor" { + default = "bx2d.4x16" +} + +variable "worker_count" { + default = "1" +} diff --git a/examples/ibm-dedicated-host/versions.tf b/examples/ibm-dedicated-host/versions.tf new file mode 100644 index 000000000..38fd583be --- /dev/null +++ b/examples/ibm-dedicated-host/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} diff --git a/examples/ibm-hpcs-uko/README.md b/examples/ibm-hpcs-uko/README.md new file mode 100644 index 000000000..84b85090e --- /dev/null +++ b/examples/ibm-hpcs-uko/README.md @@ -0,0 +1,218 @@ +# Example for Unified Key Orchestrator (UKO) feature of Hyper Protect Crypto Services + +This example illustrates how to use the UkoV4 terraform plugin + +These types of resources are supported: + +* ibm_hpcs_managed_key +* ibm_hpcs_key_template +* ibm_hpcs_keystore +* ibm_hpcs_vault + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## UkoV4 resources + +ibm_hpcs_managed_key resource: + +```hcl +resource "ibm_hpcs_managed_key" "managed_key_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + label = "terraformKey" + description = "example key" + template_name = ibm_hpcs_key_template.key_template_instance.name +} +``` +ibm_hpcs_key_template resource: + +```hcl +resource "ibm_hpcs_key_template" "key_template_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeyTemplate" + description = "example key template" + key { + size = "256" + algorithm = "aes" + activation_date = "P5Y1M1W2D" + expiration_date = "P1Y2M1W4D" + state = "active" + } + keystores { + group = "Production" + type = "aws_kms" + } +} +``` +ibm_hpcs_keystore resource: + +```hcl +resource "ibm_hpcs_keystore" "keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "aws_kms" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeystore" + description = "example keystore" + groups = ["Production"] + aws_region = "eu_central_1" + aws_access_key_id = "HSNGYJMKHGFFF" + aws_secret_access_key = "JHGSY766YUG67GFV" +} +``` +vault resource: + +```hcl +resource "ibm_hpcs_vault" "vault_instance" { + instance_id = "" + region = "us-east" + name = "terraformVault" + description = "example vault" +} +``` + +## UkoV4 Data sources + +ibm_hpcs_managed_key data source: + +```hcl +data "ibm_hpcs_managed_key" "managed_key_data" { + instance_id = ibm_hpcs_vault.vault_data.instance_id + region = ibm_hpcs_vault.vault_data.region + id = var.managed_key_id + uko_vault = var.managed_key_uko_vault +} +``` +ibm_hpcs_key_template data source: + +```hcl +data "ibm_hpcs_key_template" "key_template_data" { + instance_id = ibm_hpcs_vault.vault_data.instance_id + region = ibm_hpcs_vault.vault_data.region + id = var.key_template_id + uko_vault = var.key_template_uko_vault +} +``` +ibm_hpcs_keystore data source: + +```hcl +data "ibm_hpcs_keystore" "keystore_data" { + instance_id = ibm_hpcs_vault.vault_data.instance_id + region = ibm_hpcs_vault.vault_data.region + id = var.keystore_id + uko_vault = var.keystore_uko_vault +} +``` +ibm_hpcs_vault data source: + +```hcl +data "ibm_hpcs_vault" "vault_data" { + instance_id = ibm_hpcs_vault.vault_data.instance_id + region = ibm_hpcs_vault.vault_data.region + id = var.vault_id +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +### Resources +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| instance_id | ID of the UKO Instance. | `string` | true | +| region | Region of the UKO Instance. | `string` | true | +| uko_vault | The UUID of the Vault in which the update is to take place. | `string` | true (except in vaults) | +| vault | Object with ID of the Vault where the entity is to be created in. | `` | true (except in vaults) | +| description | Description of the resource. | `string` | false | + +### Managed Key +| Name | Description | Type | Required | +|------|-------------|------|---------| +| template_name | Name of the key template to use when creating a key. | `string` | true | +| label | The label of the key. | `string` | true | +| tags | Key-value pairs associated with the key. | `list()` | false | + +### Key Template +| Name | Description | Type | Required | +|------|-------------|------|---------| +| name | Name of the template, it will be referenced when creating managed keys. | `string` | true | +| key | Properties describing the properties of the managed key. | `` | true | +| keystores | An array describing the type and group of target keystores the managed key is to be installed in. | `list()` | true | + +### Keystore +| Name | Description | Type | Required | +|------|-------------|------|---------| +| type | The type of Keystore: "aws_kms", "azure_key_vault", or "ibm_cloud_kms" | string | true | + | aws_region | AWS Region | string | true when type = "aws_kms" | + | aws_access_key_id | AWS Access Key ID | string | true when type = "aws_kms" | + | aws_secret_access_key| AWS Secret Access Key | string | true when type = "aws_kms" | + | ibm_api_endpoint | IBM API Endpoint | string | true when type = "ibm_cloud_kms" | + | ibm_iam_endpoint | IBM IAM Endpoint | string | true when type = "ibm_cloud_kms" | + | ibm_api_key | IBM API Key | string | true when type = "ibm_cloud_kms" | + | ibm_instance_id | IBM HPCS Instance ID | string | true when type = "ibm_cloud_kms" | +| azure_resource_group | Azure Resource Group | string | true when type = "azure_key_vault" | +| azure_location | Azure Location | string | true when type = "azure_key_vault" | + | azure_service_principal_client_id| Azure Service Principle Client ID | string | true when type = "azure_key_vault" | + | azure_service_principal_password| Azure Service Principle Password | string | true when type = "azure_key_vault" | + | azure_tenant | Azure Tenant | string | true when type = "azure_key_vault" | + | azure_subscription_id| Azure Subscription ID | string | true when type = "azure_key_vault" | + | azure_environment| Azure Environment | string | true when type = "azure_key_vault" | + | azure_service_name| Azure Service Name | string | true when type = "azure_key_vault" | + +### Vault +| Name | Description | Type | Required | +|------|-------------|------|---------| +| name | A human-readable name to assign to your vault. To protect your privacy, do not use personal data, such as your name or location. | `string` | true | +| description | Description of the vault. | `string` | false | + +### Data Source +| Name | Description | Type | Required | +|------|-------------|------|---------| +| instance_id | ID of the UKO Instance. | `string` | true | +| region | Region of the UKO Instance. | `string` | true | +| id | UUID of the key. | `string` | true | +| uko_vault | The UUID of the Vault in which the update is to take place. | `string` | true (except in vaults) | + +## Outputs + +| Name | Description | +|------|-------------| +| ibm_hpcs_managed_key | managed_key object | +| ibm_hpcs_key_template | key_template object | +| ibm_hpcs_keystore | keystore object | +| ibm_hpcs_vault | vault object | diff --git a/examples/ibm-hpcs-uko/main.tf b/examples/ibm-hpcs-uko/main.tf new file mode 100644 index 000000000..00e33f77f --- /dev/null +++ b/examples/ibm-hpcs-uko/main.tf @@ -0,0 +1,60 @@ +// Provision managed_key resource instance +resource "ibm_hpcs_managed_key" "managed_key_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + label = "terraformKey" + description = "example key" + template_name = ibm_hpcs_key_template.key_template_instance.name +} + +// Provision key_template resource instance +resource "ibm_hpcs_key_template" "key_template_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeyTemplate" + description = "example key template" + key { + size = "256" + algorithm = "aes" + activation_date = "P5Y1M1W2D" + expiration_date = "P1Y2M1W4D" + state = "active" + } + keystores { + group = "Production" + type = "aws_kms" + } +} + +// Provision keystore resource instance +resource "ibm_hpcs_keystore" "keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "aws_kms" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeystore" + description = "example keystore" + groups = ["Production"] + aws_region = "eu_central_1" + aws_access_key_id = "XXXXXXX" + aws_secret_access_key = "XXXXXXX" // pragma: allowlist secret +} + +// Provision vault resource instance +resource "ibm_hpcs_vault" "vault_instance" { + instance_id = "" + region = "us-east" + name = "terraformVault" + description = "example vault" +} \ No newline at end of file diff --git a/examples/ibm-hpcs-uko/outputs.tf b/examples/ibm-hpcs-uko/outputs.tf new file mode 100644 index 000000000..d17305f47 --- /dev/null +++ b/examples/ibm-hpcs-uko/outputs.tf @@ -0,0 +1,25 @@ +// This allows managed_key data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_hpcs_managed_key" { + value = ibm_managed_key.managed_key_instance + description = "managed_key resource instance" +} +// This allows key_template data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_hpcs_key_template" { + value = ibm_key_template.key_template_instance + description = "key_template resource instance" +} +// This allows keystore data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_hpcs_keystore" { + value = ibm_keystore.keystore_instance + description = "keystore resource instance" + sensitive = true +} +// This allows vault data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_hpcs_vault" { + value = ibm_vault.vault_instance + description = "vault resource instance" +} diff --git a/examples/ibm-hpcs-uko/provider.tf b/examples/ibm-hpcs-uko/provider.tf new file mode 100644 index 000000000..b3549365a --- /dev/null +++ b/examples/ibm-hpcs-uko/provider.tf @@ -0,0 +1,13 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = "us-south" +} + +terraform { + required_providers { + ibm = { + source = "zaas/uko" + version = "0.0.1" + } + } +} \ No newline at end of file diff --git a/examples/ibm-hpcs-uko/variables.tf b/examples/ibm-hpcs-uko/variables.tf new file mode 100644 index 000000000..988251e4b --- /dev/null +++ b/examples/ibm-hpcs-uko/variables.tf @@ -0,0 +1,90 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Resource arguments for managed_key +variable "managed_key_uko_vault" { + description = "The UUID of the Vault in which the update is to take place." + type = string + default = "uko_vault" +} +variable "managed_key_template_name" { + description = "Name of the key template to use when creating a key." + type = string + default = "template_name" +} +variable "managed_key_label" { + description = "The label of the key." + type = string + default = "IBM CLOUD KEY" +} +variable "managed_key_description" { + description = "Description of the managed key." + type = string + default = "description" +} + +// Resource arguments for key_template +variable "key_template_uko_vault" { + description = "The UUID of the Vault in which the update is to take place." + type = string + default = "uko_vault" +} +variable "key_template_name" { + description = "Name of the template, it will be referenced when creating managed keys." + type = string + default = "EXAMPLE-TEMPLATE" +} +variable "key_template_description" { + description = "Description of the key template." + type = string + default = "description" +} + +// Resource arguments for keystore +variable "keystore_uko_vault" { + description = "The UUID of the Vault in which the update is to take place." + type = string + default = "uko_vault" +} + +// Resource arguments for vault +variable "vault_name" { + description = "A human-readable name to assign to your vault. To protect your privacy, do not use personal data, such as your name or location." + type = string + default = "Example Vault" +} +variable "vault_description" { + description = "Description of the vault." + type = string + default = "The description of the creating vault" +} + +// Data source arguments for managed_key +variable "managed_key_id" { + description = "UUID of the key." + type = string + default = "id" +} + +// Data source arguments for key_template +variable "key_template_id" { + description = "UUID of the template." + type = string + default = "id" +} + +// Data source arguments for keystore +variable "keystore_id" { + description = "UUID of the keystore." + type = string + default = "id" +} + +// Data source arguments for vault +variable "vault_id" { + description = "UUID of the vault." + type = string + default = "id" +} diff --git a/examples/ibm-hpcs-uko/versions.tf b/examples/ibm-hpcs-uko/versions.tf new file mode 100644 index 000000000..ee0f9705a --- /dev/null +++ b/examples/ibm-hpcs-uko/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.12" +} \ No newline at end of file diff --git a/examples/ibm-iam-accessgroups/README.md b/examples/ibm-iam-accessgroups/README.md new file mode 100644 index 000000000..805776ea3 --- /dev/null +++ b/examples/ibm-iam-accessgroups/README.md @@ -0,0 +1,54 @@ +# Example for IBM IAM Access Group Account Settings + +This example illustrates how to use the IAM Access Group Account Settings to configure public access on groups. + +These types of resources are supported: + +* ibm_iam_access_group_account_settings + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## IAM Access Group Account Setting Resource + +Access Group Account Setting Resource: + +```hcl +resource "ibm_iam_access_group_account_settings" "iam_access_groups_account_settings_instance" { + public_access_enabled = true +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | n/a | + +## Inputs + +| Name | Description | Type | Required | +|-----------------------|---------------------------------------------|-----------|----------| +| public_access_enabled | Defines if public access groups are enabled | `boolean` | true | | `string` | false | + +## Outputs + +| Name | Description | +|------|---------------| +| public_access_enabled | boolean | diff --git a/examples/ibm-iam-accessgroups/main.tf b/examples/ibm-iam-accessgroups/main.tf new file mode 100644 index 000000000..84a43e2ea --- /dev/null +++ b/examples/ibm-iam-accessgroups/main.tf @@ -0,0 +1,10 @@ +provider "ibm" { +} + +resource "ibm_iam_access_group" "accgroup" { + name = var.ag_name +} + +resource "ibm_iam_access_group_account_settings" "ag_account_setting"{ + public_access_enabled = true +} \ No newline at end of file diff --git a/examples/ibm-iam-accessgroups/variables.tf b/examples/ibm-iam-accessgroups/variables.tf new file mode 100644 index 000000000..0d73b38f4 --- /dev/null +++ b/examples/ibm-iam-accessgroups/variables.tf @@ -0,0 +1,7 @@ +variable "ag_name" { + description = "Enter the name of the access group" +} + +variable "resource_group" { + description = "Enter the resource group name" +} \ No newline at end of file diff --git a/examples/ibm-iam-accessgroups/versions.tf b/examples/ibm-iam-accessgroups/versions.tf new file mode 100644 index 000000000..ac97c6ac8 --- /dev/null +++ b/examples/ibm-iam-accessgroups/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/ibm-iam-identity-claim-rules/main.tf b/examples/ibm-iam-identity-claim-rules/main.tf index 22ace3ffe..a79462620 100644 --- a/examples/ibm-iam-identity-claim-rules/main.tf +++ b/examples/ibm-iam-identity-claim-rules/main.tf @@ -21,3 +21,8 @@ data "ibm_iam_trusted_profile_claim_rule" "iam_trusted_profile_claim_rule_instan profile_id = var.iam_trusted_profile_claim_rule_profile_id rule_id = var.iam_trusted_profile_claim_rule_rule_id } + +// Create iam_trusted_profile_claim_rules data source +data "ibm_iam_trusted_profile_claim_rules" "iam_trusted_profile_claim_rules_instance" { + profile_id = "profile_id" +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-claim-rules/outputs.tf b/examples/ibm-iam-identity-claim-rules/outputs.tf index ddfebdd58..4f1e13d1c 100644 --- a/examples/ibm-iam-identity-claim-rules/outputs.tf +++ b/examples/ibm-iam-identity-claim-rules/outputs.tf @@ -1,6 +1,14 @@ // This allows iam_trusted_profile_claim_rule data to be referenced by other resources and the terraform CLI // Modify this if only certain data should be exposed + +// for claim rule CRUD operations output "ibm_iam_trusted_profile_claim_rule" { value = ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule_instance description = "iam_trusted_profile_claim_rule resource instance" } + +// for claim rule list operation +output "ibm_iam_trusted_profile_claim_rules" { + value = data.ibm_iam_trusted_profile_claim_rules.iam_trusted_profile_claim_rules_instance + description = "iam_trusted_profile_claim_rules resource instance" +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-claim-rules/variables.tf b/examples/ibm-iam-identity-claim-rules/variables.tf index 488ef0e83..11a0f1240 100644 --- a/examples/ibm-iam-identity-claim-rules/variables.tf +++ b/examples/ibm-iam-identity-claim-rules/variables.tf @@ -4,50 +4,57 @@ variable "ibmcloud_api_key" { } // Resource arguments for iam_trusted_profiles_claim_rule -variable "iam_trusted_profiles_claim_rule_profile_id" { +variable "iam_trusted_profile_claim_rule_profile_id" { description = "ID of the trusted profile to create a claim rule." type = string default = "profile_id" } -variable "iam_trusted_profiles_claim_rule_type" { +variable "iam_trusted_profile_claim_rule_type" { description = "Type of the calim rule, either 'Profile-SAML' or 'Profile-CR'." type = string default = "type" } -variable "iam_trusted_profiles_claim_rule_conditions" { +variable "iam_trusted_profile_claim_rule_conditions" { description = "Conditions of this claim rule." type = list(object({ claim=string })) default = [ { "claim" : "claim", "operator" : "operator", "value" : "value" } ] } -variable "iam_trusted_profiles_claim_rule_name" { +variable "iam_trusted_profile_claim_rule_name" { description = "Name of the claim rule to be created or updated." type = string default = "placeholder" } -variable "iam_trusted_profiles_claim_rule_realm_name" { +variable "iam_trusted_profile_claim_rule_realm_name" { description = "The realm name of the Idp this claim rule applies to. This field is required only if the type is specified as 'Profile-SAML'." type = string default = "placeholder" } -variable "iam_trusted_profiles_claim_rule_cr_type" { +variable "iam_trusted_profile_claim_rule_cr_type" { description = "The compute resource type the rule applies to, required only if type is specified as 'Profile-CR'. Valid values are VSI, IKS_SA, ROKS_SA." type = string default = "placeholder" } -variable "iam_trusted_profiles_claim_rule_expiration" { +variable "iam_trusted_profile_claim_rule_expiration" { description = "Session expiration in seconds, only required if type is 'Profile-SAML'." type = number default = 0 } // Data source arguments for iam_trusted_profiles_claim_rule -variable "data_source_iam_trusted_profiles_claim_rule_profile_id" { +variable "data_source_iam_trusted_profile_claim_rule_profile_id" { description = "ID of the trusted profile." type = string default = "profile_id" } -variable "iam_trusted_profiles_claim_rule_rule_id" { +variable "iam_trusted_profile_claim_rule_rule_id" { description = "ID of the claim rule to get." type = string default = "rule_id" } + +// Data source arguments for iam_trusted_profile_claim_rules +variable "iam_trusted_profile_claim_rule_profile_id" { + description = "ID of the trusted profile." + type = string + default = "profile_id" +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-claim-rules/versions.tf b/examples/ibm-iam-identity-claim-rules/versions.tf index c9129e65f..f29abee0a 100644 --- a/examples/ibm-iam-identity-claim-rules/versions.tf +++ b/examples/ibm-iam-identity-claim-rules/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.31.0" + version = "1.33.0" } } } \ No newline at end of file diff --git a/examples/ibm-iam-identity-link/main.tf b/examples/ibm-iam-identity-link/main.tf index 99bb024bd..259b181a0 100644 --- a/examples/ibm-iam-identity-link/main.tf +++ b/examples/ibm-iam-identity-link/main.tf @@ -19,3 +19,8 @@ data "ibm_iam_trusted_profile_link" "iam_trusted_profile_link_instance" { profile_id = var.iam_trusted_profile_link_profile_id link_id = var.iam_trusted_profile_link_link_id } + +// Create iam_trusted_profile_links data source +data "ibm_iam_trusted_profile_links" "iam_trusted_profile_links_instance" { + profile_id = var.iam_trusted_profile_link_profile_id +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-link/outputs.tf b/examples/ibm-iam-identity-link/outputs.tf index 2275c49bf..3d59fb254 100644 --- a/examples/ibm-iam-identity-link/outputs.tf +++ b/examples/ibm-iam-identity-link/outputs.tf @@ -1,6 +1,14 @@ // This allows iam_trusted_profile_link data to be referenced by other resources and the terraform CLI // Modify this if only certain data should be exposed + +// for link CRUD operations output "ibm_iam_trusted_profile_link" { value = ibm_iam_trusted_profile_link.iam_trusted_profile_link_instance description = "iam_trusted_profile_link resource instance" } + +// for link list operation +output "ibm_iam_trusted_profile_links" { + value = data.ibm_iam_trusted_profile_links.iam_trusted_profile_links_instance + description = "iam_trusted_profile_links resource instance" +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-link/variables.tf b/examples/ibm-iam-identity-link/variables.tf index 496ea80b9..4b1c0ad4c 100644 --- a/examples/ibm-iam-identity-link/variables.tf +++ b/examples/ibm-iam-identity-link/variables.tf @@ -3,31 +3,38 @@ variable "ibmcloud_api_key" { type = string } -// Resource arguments for iam_trusted_profiles_link -variable "iam_trusted_profiles_link_profile_id" { +// Resource arguments for iam_trusted_profile_link +variable "iam_trusted_profile_link_profile_id" { description = "ID of the trusted profile." type = string default = "profile_id" } -variable "iam_trusted_profiles_link_cr_type" { +variable "iam_trusted_profile_link_cr_type" { description = "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA." type = string default = "cr_type" } -variable "iam_trusted_profiles_link_name" { +variable "iam_trusted_profile_link_name" { description = "Optional name of the Link." type = string default = "placeholder" } -// Data source arguments for iam_trusted_profiles_link -variable "data_source_iam_trusted_profiles_link_profile_id" { +// Data source arguments for iam_trusted_profile_link +variable "data_source_iam_trusted_profile_link_profile_id" { description = "ID of the trusted profile." type = string default = "profile_id" } -variable "iam_trusted_profiles_link_link_id" { +variable "iam_trusted_profile_link_link_id" { description = "ID of the link." type = string default = "link_id" } + +// Data source arguments for iam_trusted_profile_links +variable "iam_trusted_profile_links_profile_id" { + description = "ID of the trusted profile." + type = string + default = "profile_id" +} diff --git a/examples/ibm-iam-identity-link/versions.tf b/examples/ibm-iam-identity-link/versions.tf index c9129e65f..f29abee0a 100644 --- a/examples/ibm-iam-identity-link/versions.tf +++ b/examples/ibm-iam-identity-link/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.31.0" + version = "1.33.0" } } } \ No newline at end of file diff --git a/examples/ibm-iam-identity-trusted-profiles/main.tf b/examples/ibm-iam-identity-trusted-profiles/main.tf index 08bba5f06..0acfe0edd 100644 --- a/examples/ibm-iam-identity-trusted-profiles/main.tf +++ b/examples/ibm-iam-identity-trusted-profiles/main.tf @@ -11,4 +11,10 @@ resource "ibm_iam_trusted_profile" "iam_trusted_profile_instance" { // Create iam_trusted_profile data source data "ibm_iam_trusted_profile" "iam_trusted_profile_instance" { profile_id = var.iam_trusted_profile_profile_id +} + +// Create iam_trusted_profiles data source +data "ibm_iam_trusted_profiles" "iam_trusted_profiles_instance" { + account_id = var.iam_trusted_profiles_account_id + name = "name" } \ No newline at end of file diff --git a/examples/ibm-iam-identity-trusted-profiles/outputs.tf b/examples/ibm-iam-identity-trusted-profiles/outputs.tf index 7d6c78cf8..f8cf692be 100644 --- a/examples/ibm-iam-identity-trusted-profiles/outputs.tf +++ b/examples/ibm-iam-identity-trusted-profiles/outputs.tf @@ -1,6 +1,10 @@ // This allows iam_trusted_profile data to be referenced by other resources and the terraform CLI // Modify this if only certain data should be exposed -output "ibm_iam_trusted_profile" { - value = ibm_iam_trusted_profile.iam_trusted_profile_instance - description = "iam_trusted_profile resource instance" + + + +// for trusted profile list operation +output "ibm_iam_trusted_profiles" { + value = data.ibm_iam_trusted_profiles.iam_trusted_profiles_instance + description = "iam_trusted_profiles resource instance" } diff --git a/examples/ibm-iam-identity-trusted-profiles/variables.tf b/examples/ibm-iam-identity-trusted-profiles/variables.tf index 4aaa63d8f..6c3ab254b 100644 --- a/examples/ibm-iam-identity-trusted-profiles/variables.tf +++ b/examples/ibm-iam-identity-trusted-profiles/variables.tf @@ -3,26 +3,33 @@ variable "ibmcloud_api_key" { type = string } -// Resource arguments for iam_trusted_profiles -variable "iam_trusted_profiles_name" { +// Resource arguments for iam_trusted_profile +variable "iam_trusted_profile_name" { description = "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account." type = string default = "name" } -variable "iam_trusted_profiles_account_id" { +variable "iam_trusted_profile_account_id" { description = "The account ID of the trusted profile." type = string default = "account_id" } -variable "iam_trusted_profiles_description" { +variable "iam_trusted_profile_description" { description = "The optional description of the trusted profile. The 'description' property is only available if a description was provided during creation of trusted profile." type = string default = "placeholder" } -// Data source arguments for iam_trusted_profiles -variable "iam_trusted_profiles_profile_id" { +// Data source arguments for iam_trusted_profile +variable "iam_trusted_profile_profile_id" { description = "ID of the trusted profile to get." type = string default = "profile_id" } + +// Data source arguments for iam_trusted_profiles +variable "iam_trusted_profiles_account_id" { + description = "Account ID to query for trusted profiles." + type = string + default = "account_id" +} \ No newline at end of file diff --git a/examples/ibm-iam-identity-trusted-profiles/versions.tf b/examples/ibm-iam-identity-trusted-profiles/versions.tf index c9129e65f..f29abee0a 100644 --- a/examples/ibm-iam-identity-trusted-profiles/versions.tf +++ b/examples/ibm-iam-identity-trusted-profiles/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.31.0" + version = "1.33.0" } } } \ No newline at end of file diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 6d0f96e13..189b82883 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -161,6 +161,37 @@ resource "ibm_is_lb_pool" "testacc_pool" { session_persistence_type = "source_ip" } +data "ibm_is_lb_listener" "is_lb_listener" { + lb = "${ibm_is_lb.lb2.id}" + listener_id = ibm_is_lb_listener.lb_listener2.listener_id +} +data "ibm_is_lb_listeners" "is_lb_listeners" { + lb = "${ibm_is_lb.lb2.id}" +} + +data "ibm_is_lb_listener_policy" "is_lb_listener_policy" { + lb = "${ibm_is_lb.lb2.id}" + listener = ibm_is_lb_listener.lb_listener2.listener_id + policy_id = ibm_is_lb_listener_policy.lb_listener_policy.policy_id +} +data "ibm_is_lb_listener_policies" "is_lb_listener_policies" { + lb = "${ibm_is_lb.lb2.id}" + listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" +} + +data "ibm_is_lb_listener_policy_rule" "is_lb_listener_policy_rule" { + lb = "${ibm_is_lb.lb2.id}" + listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" + policy = "${ibm_is_lb_listener_policy.lb_listener_policy.policy_id}" + rule = "${ibm_is_lb_listener_policy_rule.lb_listener_policy_rule.rule}" +} + +data "ibm_is_lb_listener_policy_rules" "is_lb_listener_policy_rules" { + lb = "${ibm_is_lb.lb2.id}" + listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" + policy = "${ibm_is_lb_listener_policy.lb_listener_policy.policy_id}" +} + resource "ibm_is_vpn_gateway" "VPNGateway1" { name = "vpn1" subnet = ibm_is_subnet.subnet1.id @@ -201,6 +232,24 @@ data "ibm_is_instance" "ds_instance" { passphrase = "" } + +resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.instance1.id + subnet = ibm_is_subnet.subnet1.id + allow_ip_spoofing = true + name = "my-network-interface" + primary_ipv4_address = "10.0.0.5" +} + +data "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance_name = ibm_is_instance.instance1.name + network_interface_name = ibm_is_instance_network_interface.is_instance_network_interface.name +} + +data "ibm_is_instance_network_interfaces" "is_instance_network_interfaces" { + instance_name = ibm_is_instance.instance1.name +} + resource "ibm_is_floating_ip" "floatingip1" { name = "fip1" target = ibm_is_instance.instance1.primary_network_interface[0].id @@ -370,6 +419,7 @@ resource "ibm_is_volume" "vol2" { resource "ibm_is_network_acl" "isExampleACL" { name = "is-example-acl" + vpc = ibm_is_vpc.vpc1.id rules { name = "outbound" action = "allow" @@ -420,12 +470,30 @@ data "ibm_is_network_acl_rules" "testacc_dsnaclrules" { network_acl = ibm_is_network_acl.isExampleACL.id } +data "ibm_is_network_acl" "is_network_acl" { + network_acl = ibm_is_network_acl.isExampleACL.id +} + +data "ibm_is_network_acl" "is_network_acl1" { + name = ibm_is_network_acl.isExampleACL.name + vpc_name = ibm_is_vpc.vpc1.name +} + +data "ibm_is_network_acls" "is_network_acls" { +} + resource "ibm_is_public_gateway" "publicgateway1" { name = "gateway1" vpc = ibm_is_vpc.vpc1.id zone = var.zone1 } +// subnet public gateway attachment +resource "ibm_is_subnet_public_gateway_attachment" "example" { + subnet = ibm_is_subnet.subnet1.id + public_gateway = ibm_is_public_gateway.publicgateway1.id +} + data "ibm_is_public_gateway" "testacc_dspgw"{ name = ibm_is_public_gateway.publicgateway1.name } @@ -516,12 +584,14 @@ resource "ibm_is_instance" "instance4" { resource "ibm_is_snapshot" "b_snapshot" { name = "my-snapshot-boot" source_volume = ibm_is_instance.instance4.volume_attachments[0].volume_id + tags = ["tags1"] } // creating a snapshot from data volume resource "ibm_is_snapshot" "d_snapshot" { name = "my-snapshot-data" source_volume = ibm_is_instance.instance4.volume_attachments[1].volume_id + tags = ["tags1"] } // data source for snapshot by name @@ -555,6 +625,7 @@ resource "ibm_is_volume" "vol5" { name = "vol5" profile = "10iops-tier" zone = "us-south-2" + tags = ["tag1"] } // creating a volume attachment on an existing instance using an existing volume @@ -624,6 +695,66 @@ data "ibm_is_instance_disks" "disk1" { instance = ibm_is_instance.instance1.id } +// reserved ips + +resource "ibm_is_instance" "instance7" { + name = "instance5" + profile = var.profile + boot_volume { + name = "boot-restore" + snapshot = ibm_is_snapshot.b_snapshot.id + } + auto_delete_volume = true + primary_network_interface { + primary_ip { + address = "10.0.0.5" + auto_delete = true + } + name = "test-reserved-ip" + subnet = ibm_is_subnet.subnet2.id + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] +} + +// catalog images + +data "ibm_is_images" "imageslist" { + catalog_managed = true +} +resource "ibm_is_instance" "instance8" { + name = "instance8" + profile = var.profile + auto_delete_volume = true + primary_network_interface { + primary_ip { + name = "example-reserved-ip" + auto_delete = true + } + name = "test-reserved-ip" + subnet = ibm_is_subnet.subnet2.id + } + catalog_offering { + version_crn = data.ibm_is_images.imageslist.images.0.catalog_offering.0.version.0.crn + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] +} + + +data "ibm_is_instance_network_interface_reserved_ip" "data_reserved_ip" { + instance = ibm_is_instance.test_instance.id + network_interface = ibm_is_instance.test_instance.network_interfaces.0.id + reserved_ip = ibm_is_instance.test_instance.network_interfaces.0.ips.0.id +} + +data "ibm_is_instance_network_interface_reserved_ips" "data_reserved_ips" { + instance = ibm_is_instance.test_instance.id + network_interface = ibm_is_instance.test_instance.network_interfaces.0.id +} + data "ibm_is_instance_disk" "disk1" { instance = ibm_is_instance.instance1.id disk = data.ibm_is_instance_disks.disk1.disks.0.id @@ -659,6 +790,122 @@ data "ibm_is_operating_system" "os"{ data "ibm_is_operating_systems" "oslist"{ } +#### BARE METAL SERVER + + +resource "ibm_is_bare_metal_server" "bms" { + profile = "bx2-metal-192x768" + name = "my-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.subnet1.id + } + vpc = ibm_is_vpc.vpc1.id +} + +resource ibm_is_bare_metal_server_disk this { + bare_metal_server = ibm_is_bare_metal_server.bms.id + disk = ibm_is_bare_metal_server.bms.disks.0.id + name = "bms-disk-update" +} + +resource ibm_is_bare_metal_server_action this { + bare_metal_server = ibm_is_bare_metal_server.bms.id + action = "stop" + stop_type = "hard" +} + +data ibm_is_bare_metal_server_profiles this { +} + +data ibm_is_bare_metal_server_profile this { + name = data.ibm_is_bare_metal_server_profiles.this.profiles.0.name +} + +data ibm_is_bare_metal_server_disk this { + bare_metal_server = ibm_is_bare_metal_server.this.id + disk = ibm_is_bare_metal_server.this.disks.0.id +} + +data ibm_is_bare_metal_server_disks this { + bare_metal_server = ibm_is_bare_metal_server.this.id +} + +resource ibm_is_bare_metal_server_network_interface bms_nic { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet1.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] +} + +resource ibm_is_bare_metal_server_network_interface_allow_float bms_vlan_nic { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet1.id + name = "eth2" + vlan = 102 +} + +resource ibm_is_bare_metal_server_network_interface bms_nic2 { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet1.id + name = "eth2" + allow_ip_spoofing = true + vlan = 101 +} + +resource ibm_is_floating_ip testacc_fip { + name = "testaccfip" + zone = ibm_is_subnet.subnet1.zone +} + +resource ibm_is_bare_metal_server_network_interface_floating_ip bms_nic_fip { + bare_metal_server = ibm_is_bare_metal_server.bms.id + network_interface = ibm_is_bare_metal_server_network_interface.bms_nic2.id + floating_ip = ibm_is_floating_ip.testacc_fip.id +} + +data ibm_is_bare_metal_server_network_interface this { + bare_metal_server = ibm_is_bare_metal_server.this.id + network_interface = ibm_is_bare_metal_server.this.primary_network_interface.id +} + +data ibm_is_bare_metal_server_network_interfaces this { + bare_metal_server = ibm_is_bare_metal_server.this.id +} + +data ibm_is_bare_metal_server this { + identifier = ibm_is_bare_metal_server.this.id +} + +data ibm_is_bare_metal_servers this { +} + +data ibm_is_bare_metal_server_initialization this { + bare_metal_server = ibm_is_bare_metal_server.this.id +} + +resource "ibm_is_floating_ip" "floatingipbms" { + name = "fip1" + zone = ibm_is_subnet.subnet1.zone +} + +data "ibm_is_bare_metal_server_network_interface_floating_ip" "this" { + bare_metal_server = ibm_is_bare_metal_server.this.id + network_interface = ibm_is_bare_metal_server.this.primary_network_interface[0].id + floating_ip = ibm_is_floating_ip.floatingipbms.id +} + +data "ibm_is_bare_metal_server_network_interface_floating_ips" "this" { + bare_metal_server = ibm_is_bare_metal_server.this.id + network_interface = ibm_is_bare_metal_server.this.primary_network_interface[0].id +} + resource "ibm_is_placement_group" "is_placement_group" { strategy = "%s" name = "%s" @@ -675,3 +922,223 @@ data "ibm_is_placement_groups" "is_placement_groups" { ## List regions data "ibm_is_regions" "regions" { } + +data "ibm_is_vpc_address_prefix" "example" { + vpc = ibm_is_vpc.vpc1.id + address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix +} + +data "ibm_is_vpc_address_prefix" "example-1" { + vpc_name = ibm_is_vpc.vpc1.name + address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix +} + +data "ibm_is_vpc_address_prefix" "example-2" { + vpc = ibm_is_vpc.vpc1.id + address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name +} + +data "ibm_is_vpc_address_prefix" "example-3" { + vpc_name = ibm_is_vpc.vpc1.name + address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name +} + +## Security Groups/Rules/Rule +// Create is_security_groups data source +data "ibm_is_security_groups" "example" { +} + +// Create is_security_group data source +resource "ibm_is_security_group" "example" { + name = "example-security-group" + vpc = ibm_is_vpc.vpc1.id +} + +resource "ibm_is_security_group_rule" "exampleudp" { + depends_on = [ + ibm_is_security_group.example, + ] + group = ibm_is_security_group.example.id + direction = "inbound" + remote = "127.0.0.1" + udp { + port_min = 805 + port_max = 807 + } +} + +data "ibm_is_security_group_rule" "example" { + depends_on = [ + ibm_is_security_group_rule.exampleudp, + ] + security_group_rule = ibm_is_security_group_rule.exampleudp.rule_id + security_group = ibm_is_security_group.example.id +} + +// Create is_security_group_rules data source +resource "ibm_is_security_group_rule" "exampletcp" { + group = ibm_is_security_group.example.id + direction = "outbound" + remote = "127.0.0.1" + tcp { + port_min = 8080 + port_max = 8080 + } + depends_on = [ + ibm_is_security_group.example, + ] +} + +data "ibm_is_security_group_rules" "example" { + depends_on = [ + ibm_is_security_group_rule.exampletcp, + ] +} + +data "ibm_is_vpn_gateway" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id +} +data "ibm_is_vpn_gateway" "example-1" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name +} +data "ibm_is_vpn_gateway_connection" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection +} +data "ibm_is_vpn_gateway_connection" "example-1" { + vpn_gateway = ibm_is_vpn_gateway.example-1.id + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name +} +data "ibm_is_vpn_gateway_connection" "example-2" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection +} +data "ibm_is_vpn_gateway_connection" "example-3" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name +} +data "ibm_is_ike_policies" "example" { +} + +data "ibm_is_ipsec_policies" "example" { +} + +data "ibm_is_ike_policy" "example" { + ike_policy = ibm_is_ike_policy.example.id +} + +data "ibm_is_ipsec_policy" "example1" { + ipsec_policy = ibm_is_ipsec_policy.example.id +} + +data "ibm_is_ike_policy" "example2" { + name = "my-ike-policy" +} + +data "ibm_is_ipsec_policy" "example3" { + name = "my-ipsec-policy" +} + +# List ssh keys +data "ibm_is_ssh_keys" "example" { +} + +# List ssh keys by Resource group id +data "ibm_is_ssh_keys" "example" { + resource_group = data.ibm_resource_group.default.id +} + +# List volumes +data "ibm_is_volumes" "example-volumes" { +} + +# List Volumes by Name +data "ibm_is_volumes" "example" { + volume_name = "worrier-mailable-timpani-scowling" +} + +# List Volumes by Zone name +data "ibm_is_volumes" "example" { + zone_name = "us-south-1" +} + +## Backup Policy +resource "ibm_is_backup_policy" "is_backup_policy" { + match_user_tags = ["tag1"] + name = "my-backup-policy" +} + +resource "ibm_is_backup_policy_plan" "is_backup_policy_plan" { + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + cron_spec = "30 09 * * *" + active = false + attach_user_tags = ["tag2"] + copy_user_tags = true + deletion_trigger { + delete_after = 20 + delete_over_count = "20" + } + name = "my-backup-policy-plan-1" +} + +data "ibm_is_backup_policies" "is_backup_policies" { +} + +data "ibm_is_backup_policy" "is_backup_policy" { + name = "my-backup-policy" +} + +data "ibm_is_backup_policy_plans" "is_backup_policy_plans" { + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id +} + +data "ibm_is_backup_policy_plan" "is_backup_policy_plan" { + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + name = "my-backup-policy-plan" +} + +// Vpn Server +resource "ibm_is_vpn_server" "is_vpn_server" { + certificate_crn = var.is_certificate_crn + client_authentication { + method = "certificate" + client_ca = var.is_client_ca + } + client_ip_pool = "10.5.0.0/21" + subnets = [ibm_is_subnet.subnet1.id] + client_dns_server_ips = ["192.168.3.4"] + client_idle_timeout = 2800 + enable_split_tunneling = false + name = "example-vpn-server" + port = 443 + protocol = "udp" +} + +resource "ibm_is_vpn_server_route" "is_vpn_server_route" { + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + destination = "172.16.0.0/16" + action = "translate" + name = "example-vpn-server-route" +} + +data "ibm_is_vpn_server" "is_vpn_server" { + identifier = ibm_is_vpn_server.is_vpn_server.vpn_server +} +data "ibm_is_vpn_servers" "is_vpn_servers" { +} + +data "ibm_is_vpn_server_routes" "is_vpn_server_routes" { + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server +} + +data "ibm_is_vpn_server_route" "is_vpn_server_route" { + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + identifier = ibm_is_vpn_server_route.is_vpn_server_route.vpn_route +} +data "ibm_is_vpn_server_clients" "is_vpn_server_clients" { + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server +} +data "ibm_is_vpn_server_client" "is_vpn_server_client" { + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + identifier = "0726-61b2f53f-1e95-42a7-94ab-55de8f8cbdd5" +} \ No newline at end of file diff --git a/examples/ibm-is-ng/variables.tf b/examples/ibm-is-ng/variables.tf index 1a244d909..e9ac053de 100644 --- a/examples/ibm-is-ng/variables.tf +++ b/examples/ibm-is-ng/variables.tf @@ -29,3 +29,36 @@ variable "image_operating_system" { variable "cidr1" { default = "10.120.0.0/24" } + + +// Data source arguments for is_security_groups + +// Data source arguments for is_security_group_rule +variable "is_security_group_rule_security_group_id" { + description = "The security group identifier." + type = string + default = "r134-4d5db1a7-ca45-4c29-80d1-2a90cf94d11a" +} +variable "is_security_group_rule_id" { + description = "The rule identifier." + type = string + default = "r134-5b206956-0990-4337-bab4-02005315db0a" +} + +// Data source arguments for is_security_group_rules +variable "is_security_group_rules_security_group_id" { + description = "The security group identifier." + type = string + default = "r134-4d5db1a7-ca45-4c29-80d1-2a90cf94d11a" +} + + +variable "is_certificate_crn" { + description = "The Certificate Crn for VPN Server." + type = string +} + +variable "is_client_ca" { + description = "The Client Ca for VPN Server." + type = string +} \ No newline at end of file diff --git a/examples/ibm-power/README.md b/examples/ibm-power/README.md new file mode 100644 index 000000000..c1f69d2f4 --- /dev/null +++ b/examples/ibm-power/README.md @@ -0,0 +1,66 @@ +# IBM Power Examples +This directory contains sample Terraform code to create a Power Systems Virtual Server. +​ +## Prerequisites +- An [IBM Cloud Account](https://cloud.ibm.com/registration) +- An IBM Cloud [IAM API key](https://cloud.ibm.com/docs/account?topic=account-userapikey) +- [Terraform](https://www.terraform.io/downloads) +​ +## Setup +The following steps are for setting up the example terraform configuration locally: + - Make a local copy of the files in this directory. + - Modify the variables in `variables.tf`. + - To use using a stock image, specified by `image_name` in `variables.tf`, you must first copy the stock image to Cloud Instance. You can copy an image using the [IBM Cloud CLI](https://cloud.ibm.com/docs/cli): `ibmcloud pi image-create `. + - If using a custom or imported image remove `pi_storage_type` from the `ibm_pi_instance` resource since the storage type will default to the custom image's storage type. + - For developers using a staging environment, export the following environment variables. +```bash +export IBMCLOUD_IAM_API_ENDPOINT="https://iam.test.cloud.ibm.com" +export IBMCLOUD_PI_API_ENDPOINT=".power-iaas.test.cloud.ibm.com" +``` +​ +## Export vs Define +You can define variables for the provider in `provider.tf` or you can export env variables. More information can be found about exporting env vairables [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#argument-reference). + +## Running the Configuration +```bash +# Initalize terraform directory and validate the configuration +terraform init +terraform fmt +terraform validate +​ +# Show changes required by the current configuration +terraform plan +​ +# Create or update infrastructure +terraform apply +​ +# Destroy previously-created infrastructure +terraform destroy +``` + +## Documentation + - [IBM Power Systems Virtual Server Docs](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started) + - [Intro to Terraform](https://www.terraform.io/intro) | [Terraform Overview](https://www.terraform.io/language) + - [Terraform SDK Docs](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk) (For devs contributing to repo) +​ +## IBM Power Systems Terraform Docs +> [Link](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_capture) to IBM Terrafom Docs + + +| Resource Type | Resource Docs | Data Source Docs | +| :------------ |:------------- | :--------------- | +| Capture | [ibm_pi_capture](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_capture) | | +| Cloud Connection | [ibm_pi_cloud_connection](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_cloud_connection)
[ibm_pi_cloud_connection_network_attach](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_cloud_connection_network_attach) | [ibm_pi_cloud_connection](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_cloud_connection)
[ibm_pi_cloud_connections](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_cloud_connections) | +| Cloud Instance | | [ibm_pi_cloud_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_cloud_instance) | +| DHCP | [ibm_pi_dhcp](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_dhcp) | [ibm_pi_dhcp](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_dhcp)
[ibm_pi_dhcps](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_dhcps) | +| Image | [ibm_pi_image](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_image)
[image_export](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_image_export) | [ibm_pi_catalog_images](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_catalog_images)
[ibm_pi_image](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_image)
[ibm_pi_images](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_images) | +| Instance | [ibm_pi_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_instance)
[ibm_pi_instance_console_language](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_console_language)
[ibm_pi_snapshot](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_snapshot) | [ibm_pi_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_instance)
[ibm_pi_instances](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_instances)
[ibm_pi_instance_console_languages](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_console_languages)
[ibm_pi_instance_ip](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_instance_i)
[ibm_pi_snapshot](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_pvm_snapshots)
[ibm_pi_snapshots](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_pvm_snapshots) | +| Key | [ibm_pi_key](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_key) | [ibm_pi_key](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_key)
[ibm_pi_keys](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_keys) | +| Network | [ibm_pi_network](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_network)
[ibm_pi_network_port](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_network_port)
[ibm_pi_network_port_attach](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_network) | [ibm_pi_network](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_network)
[ibm_pi_network_port](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_network)
[ibm_pi_public_network](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_public_network) | +| Placement Group | [ibm_pi_placement_group](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_placement_group) | [ibm_pi_placement group](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_placement_group)
[ibm_pi_placement_groups](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_placement_groups) | +| SAP | | [ibm_pi_sap_profile](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_sap_profile)
[ibm_pi_sap_profiles](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_sap_profiles) | +| Storage Capacity | | [ibm_pi_storage_pool_capacity](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_storage_pool_capacity)
[ibm_pi_storage_pools_capacity](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_storage_pools_capacity)
[ibm_pi_system_pools]() | +| Storage Type | | [ibm_pi_storage_type_capacity](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_storage_type_capacity)
[ibm_pi_storage_types_capacity](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_storage_types_capacity) | +| Tenant | | [ibm_pi_tenant](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_tenant) | +| Volume | [ibm_pi_volume](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_volume)
[ibm_pi_volume_attach](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_volume_attach) | [ibm_pi_instance_volumes](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_instance_volumes)
[ibm_pi_volume](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_volume) | +| VPN | [ibm_pi_ike_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_vpn_ike_policy)
[ibm_pi_ipsec_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_vpn_ipsec_policy)
[ibm_pi_vpn_connection](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_vpn_connection) | | diff --git a/examples/ibm-power/main.tf b/examples/ibm-power/main.tf index d5490ccff..bf6c35f70 100644 --- a/examples/ibm-power/main.tf +++ b/examples/ibm-power/main.tf @@ -1,54 +1,64 @@ +data "ibm_pi_image" "data_source_image" { + pi_cloud_instance_id = var.cloud_instance_id + pi_image_name = var.image_name +} resource "ibm_pi_key" "key" { - pi_cloud_instance_id = var.powerinstanceid - pi_key_name = var.sshkeyname - pi_ssh_key = var.sshkey + pi_cloud_instance_id = var.cloud_instance_id + pi_key_name = var.ssh_key_name + pi_ssh_key = var.ssh_key_rsa } +data "ibm_pi_key" "data_source_key" { + depends_on = [ibm_pi_key.key] -data "ibm_pi_key" "dskey" { - depends_on = ["ibm_pi_key.key"] - pi_cloud_instance_id = var.powerinstanceid - pi_key_name = var.sshkeyname + pi_cloud_instance_id = var.cloud_instance_id + pi_key_name = var.ssh_key_name } - -resource "ibm_pi_network" "power_networks" { - count = 1 - pi_network_name = var.networkname - pi_cloud_instance_id = var.powerinstanceid - pi_network_type = "pub-vlan" +resource "ibm_pi_network" "network" { + pi_cloud_instance_id = var.cloud_instance_id + pi_network_name = var.network_name + pi_network_type = var.network_type + count = var.network_count } +data "ibm_pi_public_network" "data_source_network" { + depends_on = [ibm_pi_network.network] -data "ibm_pi_public_network" "dsnetwork" { - depends_on = ["ibm_pi_network.power_networks"] - pi_cloud_instance_id = var.powerinstanceid + pi_cloud_instance_id = var.cloud_instance_id } +resource "ibm_pi_volume" "volume" { + pi_cloud_instance_id = var.cloud_instance_id + pi_volume_name = var.volume_name + pi_volume_type = var.volume_type + pi_volume_size = var.volume_size + pi_volume_shareable = var.volume_shareable +} +data "ibm_pi_volume" "data_source_volume" { + depends_on = [ibm_pi_volume.volume] -resource "ibm_pi_volume" "volume"{ - pi_volume_size = 20 - pi_volume_name = var.volname - pi_volume_type = "ssd" - pi_volume_shareable = true - pi_cloud_instance_id = var.powerinstanceid // Get ot by running cmd "ic resource service-instances --long" -} -data "ibm_pi_volume" "dsvolume" { - depends_on = ["ibm_pi_volume.volume"] - pi_cloud_instance_id = var.powerinstanceid - pi_volume_name = var.volname + pi_cloud_instance_id = var.cloud_instance_id + pi_volume_name = var.volume_name } +resource "ibm_pi_instance" "instance" { + depends_on = [data.ibm_pi_image.data_source_image, + data.ibm_pi_key.data_source_key, + data.ibm_pi_volume.data_source_volume, + data.ibm_pi_public_network.data_source_network] -data "ibm_pi_image" "powerimages" { - pi_image_name = var.imagename - pi_cloud_instance_id = var.powerinstanceid + pi_cloud_instance_id = var.cloud_instance_id + pi_instance_name = var.instance_name + pi_memory = var.memory + pi_processors = var.processors + pi_proc_type = var.proc_type + pi_storage_type = var.storage_type + pi_sys_type = var.sys_type + pi_image_id = data.ibm_pi_image.data_source_image.id + pi_key_pair_name = data.ibm_pi_key.data_source_key.id + pi_network { network_id = data.ibm_pi_public_network.data_source_network.id } + pi_volume_ids = [data.ibm_pi_volume.data_source_volume.id] } -resource "ibm_pi_instance" "test-instance" { - pi_memory = "4" - pi_processors = "2" - pi_instance_name = var.instancename - pi_proc_type = "shared" - pi_image_id = "${data.ibm_pi_image.powerimages.id}" - pi_network_ids = [data.ibm_pi_public_network.dsnetwork.id] - pi_key_pair_name = ibm_pi_key.key.key_id - pi_sys_type = "s922" - pi_cloud_instance_id = var.powerinstanceid - pi_volume_ids = ["${ibm_pi_volume.volume.volume_id}"] +data "ibm_pi_instance" "data_source_instance" { + depends_on = [ibm_pi_instance.instance] + + pi_cloud_instance_id = var.cloud_instance_id + pi_instance_name = var.instance_name } \ No newline at end of file diff --git a/examples/ibm-power/provider.tf b/examples/ibm-power/provider.tf new file mode 100644 index 000000000..476fdab08 --- /dev/null +++ b/examples/ibm-power/provider.tf @@ -0,0 +1,5 @@ +provider "ibm" { + ibmcloud_api_key = var.ibm_cloud_api_key // export IC_API_KEY = "" + region = var.region // export IBMCLOUD_REGION = "" + zone = var.zone // export IBMCLOUD_ZONE = "" +} \ No newline at end of file diff --git a/examples/ibm-power/var.tf b/examples/ibm-power/var.tf deleted file mode 100644 index 911bf6a7b..000000000 --- a/examples/ibm-power/var.tf +++ /dev/null @@ -1,32 +0,0 @@ -variable "imagename" { - description = "Name of the image key to be used" - default = "7200-04-01" -} - -variable "powerinstanceid" { - description = "Power Instance associated with the account" -} - -variable "instancename" { - default = "myinstance" - description = "Name of the instance" -} - -variable "sshkeyname" { - default = "mykey" - description = "Name of the ssh key to be used" -} - -variable "volname" { - default = "myvol" - description = "Name of the volume" -} -variable "networkname" { - default = "mypublicnw" - description = "Name of the network" -} - -variable "sshkey" { - description = "Public ssh key" -} - diff --git a/examples/ibm-power/variables.tf b/examples/ibm-power/variables.tf new file mode 100644 index 000000000..b3d9adc29 --- /dev/null +++ b/examples/ibm-power/variables.tf @@ -0,0 +1,111 @@ +// Service / Account +variable "ibm_cloud_api_key" { + description = "API Key" + type = string + default = "" +} +variable "region" { + description = "Reigon of Service" + type = string + default = "" +} +variable "zone" { + description = "Zone of Service" + type = string + default = "" +} +variable "cloud_instance_id" { + description = "Cloud Instance ID of Service" + type = string + default = "" +} + +// Image +variable "image_name" { + description = "Name of the image to be used" + type = string + default = "" +} + +// Instance +variable "instance_name" { + description = "Name of the instance" + type = string + default = "" +} +variable "memory" { + description = "Instance memory" + type = number + default = 1 +} +variable "processors" { + description = "Instance processors" + type = number + default = 1 +} +variable "proc_type" { + description = "Instance ProcType" + type = string + default = "" +} +variable "storage_type" { + description = "The storage type to be used" + type = string + default = "" +} +variable "sys_type" { + description = "Instance System Type" + type = string + default = "" +} + +// SSH Key +variable "ssh_key_name" { + description = "Name of the ssh key to be used" + type = string + default = "" +} +variable "ssh_key_rsa" { + description = "Public ssh key" + type = string + default = "" +} + +// Network +variable "network_name" { + description = "Name of the network" + type = string + default = "" +} +variable "network_type" { + description = "Type of a network" + type = string + default = "" +} +variable "network_count" { + description = "Number of networks to provision" + type = number + default = 1 +} + +// Volume +variable "volume_name" { + description = "Name of the volume" + type = string + default = "" +} +variable "volume_size" { + description = "Size of a volume" + type = number + default = 0.25 +} +variable "volume_shareable" { + description = "Is a volume shareable" + type = bool + default = true +} +variable "volume_type" { + description = "Type of a volume" + type = string + default = "" +} \ No newline at end of file diff --git a/examples/ibm-power/versions.tf b/examples/ibm-power/versions.tf index ac97c6ac8..0b29488aa 100644 --- a/examples/ibm-power/versions.tf +++ b/examples/ibm-power/versions.tf @@ -1,4 +1,7 @@ - terraform { - required_version = ">= 0.12" -} + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-private-dns/main.tf b/examples/ibm-private-dns/main.tf index 23dbef141..297fe51dc 100644 --- a/examples/ibm-private-dns/main.tf +++ b/examples/ibm-private-dns/main.tf @@ -174,6 +174,7 @@ resource "ibm_dns_glb" "test_pdns_glb" { zone_id = ibm_dns_zone.test-pdns-zone.zone_id description = "new glb" ttl = 120 + enabled = true fallback_pool = ibm_dns_glb_pool.test-pdns-pool-nw.pool_id default_pools = [ibm_dns_glb_pool.test-pdns-pool-nw.pool_id] az_pools { @@ -240,4 +241,23 @@ resource "ibm_dns_custom_resolver_forwarding_rule" "test" { data "ibm_dns_custom_resolver_forwarding_rules" "test-fr" { instance_id = ibm_dns_custom_resolver.test.instance_id resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id -} \ No newline at end of file +} + +resource "ibm_dns_custom_resolver_secondary_zone" "test" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + description = "seczone terraform plugin test" + zone = "seczone-terraform-plugin-test.com" + enabled = false + transfer_from = ["10.0.0.8"] +} + +data "ibm_dns_custom_resolver_secondary_zones" "test-sz" { + depends_on = [ibm_dns_custom_resolver_secondary_zone.test] + instance_id = ibm_dns_custom_resolver.test.instance_id + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id +} + +output "ibm_dns_custom_resolver_secondary_zones_output" { + value = data.ibm_dns_custom_resolver_secondary_zones.test-sz +} diff --git a/examples/ibm-resource-instance/README.md b/examples/ibm-resource-instance/README.md index e97f8b745..a74c90475 100644 --- a/examples/ibm-resource-instance/README.md +++ b/examples/ibm-resource-instance/README.md @@ -1,19 +1,13 @@ # IBM Cloud resource instance example -The following example creates an instance of IBM Cloud resource. Instance could be of any resource, for example cloud object staorage, activity tracker, metrics monitor etc. By specifying the right value to argument `service`, we can provision respective resource instance. +The following example creates an instance of IBM Cloud resource. Instance could be of any resource, for example Cloud Object Storage, Activity Tracker, metrics monitor etc. By specifying the right value to argument `service`, we can provision respective resource instance. Document reference http://servicedata.mybluemix.net/ Following types of resources are supported: -* [ Resource Instance](https://cloud.ibm.com/docs/terraform?topic=terraform-resource-mgmt-resources#resource-instance) +* [Resource Instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) -## Terraform versions - -Terraform 0.12. Pin module version to `~> v1.7.1`. Branch - `master`. - -Terraform 0.11. Pin module version to `~> v0.29.1`. Branch - `terraform_v0.11.x`. - ## Usage To run this example you need to execute: @@ -30,7 +24,7 @@ Run `terraform destroy` when you don't need these resources. Create an IBM Cloud Object Storage bucket resource instance. -```hcl +```terraform data "ibm_resource_group" "cos_group" { name = var.resource_group_name @@ -53,29 +47,31 @@ data "ibm_resource_instance" "test" { ## Examples -* [ Resource Istance ](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-resource-instance) +* [Resource Instance](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-resource-instance) + ## Requirements +You need Terraform v1.0.0 installer to execute this example in your account. For more information, about Terraform installation, see [Installing the Terraform CLI](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-getting-started) + | Name | Version | |------|---------| -| terraform | ~> 0.12 | +| terraform | >=1.0.0, <2.0 | ## Providers | Name | Version | |------|---------| -| ibm | n/a | +| ibm | latest | ## Inputs | Name | Description | Type | Required | |------|-------------|------|---------| -| name | Name of the resource group. | `string` | yes | | service_name | The name of the service offering. | `string` | yes | | service_type | The type of the service offering. | `string` | yes | | plan| The name of the plan type supported by service.| `string` | yes | | location | Target location or environment to create the resource instance. | `string` | yes | - +| resource_group | Name of your resource group. | `string` | yes | diff --git a/examples/ibm-resource-instance/main.tf b/examples/ibm-resource-instance/main.tf index 1f97d221e..315e77248 100644 --- a/examples/ibm-resource-instance/main.tf +++ b/examples/ibm-resource-instance/main.tf @@ -1,5 +1,5 @@ data "ibm_resource_group" "group" { - name = var.name + name = var.resource_group } resource "ibm_resource_instance" "resource_instance" { diff --git a/examples/ibm-resource-instance/variables.tf b/examples/ibm-resource-instance/variables.tf index 3682fb56f..08776547c 100644 --- a/examples/ibm-resource-instance/variables.tf +++ b/examples/ibm-resource-instance/variables.tf @@ -14,7 +14,7 @@ variable "location" { default = "global" } -variable "name" { +variable "resource_group" { default = "default" } diff --git a/examples/ibm-resource-instance/versions.tf b/examples/ibm-resource-instance/versions.tf index ac97c6ac8..35ea306e2 100644 --- a/examples/ibm-resource-instance/versions.tf +++ b/examples/ibm-resource-instance/versions.tf @@ -1,4 +1,12 @@ +############################### +# IBM Cloud Copyright 2020 IBM +############################### terraform { - required_version = ">= 0.12" + required_version = ">= 1.0.0, < 2.0.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } } diff --git a/examples/ibm-satellite/README.md b/examples/ibm-satellite/README.md index cb488c275..5ce3ca6a3 100644 --- a/examples/ibm-satellite/README.md +++ b/examples/ibm-satellite/README.md @@ -6,19 +6,13 @@ This example uses below modules to set up the satellite location with IBM enviro 1. [satellite-location](modules/location) This module `creates satellite location` for the specified zone|location|region and `generates script` named addhost.sh in the working directory by performing attach host.The generated script is used by `ibm_is_instance` as `user_data` and runs the script. At this stage all the VMs that has run addhost.sh will be attached to the satellite location and will be in unassigned state. 2. [satellite-host](modules/host) This module assigns 3 host to setup the location control plane. -3. [satellite-cluster](modules/cluster) This module will create ROKS satellite cluster and worker pool. +3. [satellite-cluster](modules/cluster) This module will create ROKS satellite cluster and worker pool, attach zone to worker pool. 4. [satellite-link](modules/link) This module will create satellite link. 5. [satellite-route](modules/route) This module will create openshift route. 6. [satellite-endpoint](modules/endpoint) This module will create satellite endpoint. +7. [satellite-dns](modules/dns) This module will register public IPs to control plane & open-shit cluster subdomain DNS records. + -## Prerequisite - -* Set up the IBM Cloud command line interface (CLI), the Satellite plug-in, and other related CLIs. -* Install cli and plugin package -```console - ibmcloud plugin install container-service -``` -* Follow the Host [requirements](https://cloud.ibm.com/docs/satellite?topic=satellite-host-reqs) ## Usage ``` @@ -75,6 +69,16 @@ module "satellite-cluster" { workerpool_labels = var.workerpool_labels cluster_tags = var.cluster_tags host_labels = var.host_labels + zone_name = var.zone_name +} + +module "satellite-dns" { + source = "./modules/dns" + + location = var.location + cluster = var.cluster_server_url + control_plane_ips = var.control_plane_ips + cluster_ips = var.cluster_ips } module "satellite-link" { @@ -128,9 +132,9 @@ module "satellite-endpoint" { | Name | Description | Type | Default | Required | |--------------------------------|-------------------------------------------------------------------|----------|---------|----------| | ibmcloud_api_key | IBM Cloud API Key. | string | n/a | yes | -| resource_group | Resource Group Name that has to be targeted. | string | n/a | no | -| ibm_region | The location or the region in which VM instance exists. | string | us-east | yes | -| location | Name of the Location that has to be created | string | satellite-ibm | yes | +| resource_group | Resource Group Name that has to be targeted. | string | n/a | yes | +| ibm_region | The location or the region in which VM instance exists. | string | us-east | no | +| location | Name of the Location that has to be created | string | satellite-ibm | no | | managed_from | The IBM Cloud region to manage your Satellite location from. | string | n/a | yes | | location_zones | Allocate your hosts across these three zones | list | ["us-east-1", "us-east-2", "us-east-3"] | no | | location_bucket | COS bucket name | string | n/a | no | @@ -143,6 +147,7 @@ module "satellite-endpoint" { | default_wp_labels | Labels on the default worker pool | map | n/a | no | | worker_pool_name | Public SSH key used to provision Host/VSI | string | satellite-ibm-cluster-wp | no | | workerpool_labels | Labels on the worker pool | map | n/a | no | +| zone_name | creates new zone on workerpool | string | n/a | no | | cluster_tags | List of tags for the cluster resource | list | [ "env:cluster" ] | no | | connection_type | The type of the endpoint. | string | n/a | no | | is_endpoint_provision | Determines if the route and endpoint has to be created or not. | bool | false | no | @@ -155,8 +160,8 @@ module "satellite-endpoint" { | server_protocol | The protocol in the server application side. This parameter will change to default value if it is omitted even when using PATCH API. If client_protocol is 'udp', server_protocol must be 'udp'. If client_protocol is 'tcp'/'http', server_protocol could be 'tcp'/'tls' and default to 'tcp'. If client_protocol is 'tls'/'https', server_protocol could be 'tcp'/'tls' and default to 'tls'. If client_protocol is 'http-tunnel', server_protocol must be 'tcp'. | string | n/a | no | | server_mutual_auth | Whether enable mutual auth in the server application side, when client_protocol is 'tls', this field is required. | bool | n/a | no | | reject_unauth | Whether reject any connection to the server application which is not authorized with the list of supplied CAs in the fields certs.server_cert. | bool | n/a | no | -| timeout | The inactivity timeout in the Endpoint side. | number | n/a | no | +| timeout | The inactivity timeout in the Endpoint side. | number | n/a | no | | created_by | The service or person who created the endpoint. Must be 1000 characters or fewer. | string | n/a | no | -| client_certificate | The certs.| string | n/a | no | +| client_certificate | The certs. | string | n/a | no | \ No newline at end of file diff --git a/examples/ibm-satellite/cluster.tf b/examples/ibm-satellite/cluster.tf index 2697c7269..e301c8600 100644 --- a/examples/ibm-satellite/cluster.tf +++ b/examples/ibm-satellite/cluster.tf @@ -2,7 +2,7 @@ module "satellite-cluster" { source = "./modules/cluster" cluster = var.cluster - location = module.satellite-host.location + location = module.satellite-location.location_id kube_version = var.kube_version default_wp_labels = var.default_wp_labels zones = var.cluster_zones @@ -12,4 +12,7 @@ module "satellite-cluster" { workerpool_labels = var.workerpool_labels cluster_tags = var.cluster_tags host_labels = var.host_labels + zone_name = var.zone_name + + depends_on = [module.satellite-host] } \ No newline at end of file diff --git a/examples/ibm-satellite/dns.tf b/examples/ibm-satellite/dns.tf new file mode 100644 index 000000000..cb70369a4 --- /dev/null +++ b/examples/ibm-satellite/dns.tf @@ -0,0 +1,10 @@ +module "satellite-dns" { + source = "./modules/dns" + + location = module.satellite-location.location_id + cluster = module.satellite-cluster.cluster_id + control_plane_ips = slice(ibm_is_floating_ip.satellite_ip[*].address, 0, var.host_count) + cluster_ips = slice(ibm_is_floating_ip.satellite_ip[*].address, var.host_count, (var.host_count + var.addl_host_count)) + resource_group = var.resource_group + depends_on = [module.satellite-cluster] +} \ No newline at end of file diff --git a/examples/ibm-satellite/instance.tf b/examples/ibm-satellite/instance.tf index a9fcb068b..64a02b3b3 100644 --- a/examples/ibm-satellite/instance.tf +++ b/examples/ibm-satellite/instance.tf @@ -3,21 +3,114 @@ data "ibm_resource_group" "resource_group" { } data "ibm_is_image" "rhel7" { - name = "ibm-redhat-7-9-minimal-amd64-3" + name = "ibm-redhat-7-9-minimal-amd64-4" } -resource "ibm_is_vpc" "satellite_vpc" { +resource "ibm_is_vpc" "vpc" { name = "${var.is_prefix}-vpc" } resource "ibm_is_subnet" "satellite_subnet" { count = 3 name = "${var.is_prefix}-subnet-${count.index}" - vpc = ibm_is_vpc.satellite_vpc.id + vpc = ibm_is_vpc.vpc.id total_ipv4_address_count = 256 zone = "${var.ibm_region}-${count.index + 1}" } +resource "ibm_is_security_group_rule" "sg-rule-inbound-ssh" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 22 + port_max = 22 + } +} + +# Port 80 is needed for default routes into OpenShift. A TODO is to figure out +# how to do this securely using HTTPS instead. +resource "ibm_is_security_group_rule" "sg-rule-inbound-http" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 80 + port_max = 80 + } +} + +resource "ibm_is_security_group_rule" "sg-rule-inbound-https" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 443 + port_max = 443 + } +} + +resource "ibm_is_security_group_rule" "sg-rule-inbound-api" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 30000 + port_max = 32767 + } +} + +resource "ibm_is_security_group_rule" "sg-rule-inbound-api2" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + udp { + port_min = 30000 + port_max = 32767 + } +} + +resource "ibm_is_security_group_rule" "sg-rule-inbound-icmp" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = "0.0.0.0/0" + + icmp { + type = 8 + } +} + +resource "ibm_is_security_group_rule" "sg-rule-outbound" { + group = ibm_is_vpc.vpc.default_security_group + direction = "outbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 1 + port_max = 65535 + } +} + +# Hosts must have TCP/UDP/ICMP Layer 3 connectivity for all ports across hosts. +# You cannot block access to certain ports that might block communication across hosts. +resource "ibm_is_security_group_rule" "sg-rule-inbound-from-the-group" { + group = ibm_is_vpc.vpc.default_security_group + direction = "inbound" + remote = ibm_is_vpc.vpc.default_security_group +} + +resource "ibm_is_security_group_rule" "sg-rule-outbound-to-the-group" { + group = ibm_is_vpc.vpc.default_security_group + direction = "outbound" + remote = ibm_is_vpc.vpc.default_security_group +} + + resource "tls_private_key" "example" { algorithm = "RSA" rsa_bits = 4096 @@ -39,7 +132,7 @@ resource "ibm_is_instance" "satellite_instance" { count = var.host_count + var.addl_host_count name = "${var.is_prefix}-instance-${count.index}" - vpc = ibm_is_vpc.satellite_vpc.id + vpc = ibm_is_vpc.vpc.id zone = element(local.zones, count.index) image = data.ibm_is_image.rhel7.id profile = "mx2-8x64" diff --git a/examples/ibm-satellite/link.tf b/examples/ibm-satellite/link.tf index 225352d35..42ce83a02 100644 --- a/examples/ibm-satellite/link.tf +++ b/examples/ibm-satellite/link.tf @@ -1,7 +1,13 @@ +data "ibm_satellite_location" "ds_location" { + location = var.location + + depends_on = [module.satellite-dns] +} + module "satellite-link" { source = "./modules/link" location = module.satellite-location.location_id - crn = module.satellite-location.location_crn + crn = data.ibm_satellite_location.ds_location.crn depends_on = [module.satellite-cluster] -} \ No newline at end of file +} diff --git a/examples/ibm-satellite/main.tf b/examples/ibm-satellite/main.tf index 027586859..7190350bb 100644 --- a/examples/ibm-satellite/main.tf +++ b/examples/ibm-satellite/main.tf @@ -10,5 +10,4 @@ module "satellite-location" { ibm_region = var.ibm_region resource_group = var.resource_group host_labels = var.host_labels - tags = var.tags } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/cluster/README.md b/examples/ibm-satellite/modules/cluster/README.md index a984c08c6..0c3f45e99 100644 --- a/examples/ibm-satellite/modules/cluster/README.md +++ b/examples/ibm-satellite/modules/cluster/README.md @@ -40,6 +40,7 @@ module "satellite-cluster" { workerpool_labels = var.workerpool_labels cluster_tags = var.cluster_tags host_labels = var.host_labels + zone_name = var.zone_name } ``` @@ -61,6 +62,7 @@ module "satellite-cluster" { | host_labels | List of host labels to assign host to cluter | list | n/a | no | | workerpool_labels | Labels on the worker pool | map | n/a | no | | cluster_tags | List of tags for the cluster resource | list | n/a | no | +| zone_name | creates new zone on workerpool | string | n/a | no | \ No newline at end of file diff --git a/examples/ibm-satellite/modules/cluster/main.tf b/examples/ibm-satellite/modules/cluster/main.tf index 271f1ab39..93d15ab1e 100644 --- a/examples/ibm-satellite/modules/cluster/main.tf +++ b/examples/ibm-satellite/modules/cluster/main.tf @@ -1,64 +1,64 @@ data "ibm_resource_group" "rg" { - name = var.resource_group + name = var.resource_group } resource "ibm_satellite_cluster" "create_cluster" { - name = var.cluster - location = var.location - resource_group_id = data.ibm_resource_group.rg.id - enable_config_admin = true - kube_version = var.kube_version - wait_for_worker_update = true - worker_count = var.worker_count - host_labels = var.host_labels - - dynamic "zones" { - for_each = var.zones - content { - id = zones.value - } - } + name = var.cluster + location = var.location + resource_group_id = data.ibm_resource_group.rg.id + enable_config_admin = true + kube_version = var.kube_version + wait_for_worker_update = true + worker_count = var.worker_count + host_labels = var.host_labels - default_worker_pool_labels = var.default_wp_labels - tags = var.cluster_tags + dynamic "zones" { + for_each = var.zones + content { + id = zones.value + } + } + + default_worker_pool_labels = var.default_wp_labels + tags = var.cluster_tags } data "ibm_satellite_cluster" "read_cluster" { - name = ibm_satellite_cluster.create_cluster.id + name = ibm_satellite_cluster.create_cluster.id } resource "ibm_satellite_cluster_worker_pool" "create_cluster_wp" { - name = var.worker_pool_name - cluster = data.ibm_satellite_cluster.read_cluster.id - resource_group_id = data.ibm_resource_group.rg.id - worker_count = var.worker_count - host_labels = var.host_labels + name = var.worker_pool_name + cluster = data.ibm_satellite_cluster.read_cluster.id + resource_group_id = data.ibm_resource_group.rg.id + worker_count = var.worker_count + host_labels = var.host_labels - dynamic "zones" { - for_each = var.zones - content { - id = zones.value - } - } + dynamic "zones" { + for_each = var.zones + content { + id = zones.value + } + } - worker_pool_labels = var.workerpool_labels -} + worker_pool_labels = var.workerpool_labels +} data "ibm_satellite_cluster_worker_pool" "read_cluster_wp" { - name = ibm_satellite_cluster_worker_pool.create_cluster_wp.name - cluster = data.ibm_satellite_cluster.read_cluster.id - - depends_on = [ibm_satellite_cluster_worker_pool.create_cluster_wp] -} + name = ibm_satellite_cluster_worker_pool.create_cluster_wp.name + cluster = data.ibm_satellite_cluster.read_cluster.id -output "cluster_id" { - value = data.ibm_satellite_cluster.read_cluster.id + depends_on = [ibm_satellite_cluster_worker_pool.create_cluster_wp] } -output "master_url" { - value = data.ibm_satellite_cluster.read_cluster.server_url +resource "ibm_satellite_cluster_worker_pool_zone_attachment" "create_worker_pool_zone" { + cluster = data.ibm_satellite_cluster_worker_pool.read_cluster_wp.cluster + worker_pool = var.worker_pool_name + zone = var.zone_name } -output "worker_pool_id" { - value = data.ibm_satellite_cluster_worker_pool.read_cluster_wp.id +data "ibm_satellite_cluster_worker_pool_zone_attachment" "read_worker_pool_zone_attachment" { + cluster = ibm_satellite_cluster_worker_pool_zone_attachment.create_worker_pool_zone.cluster + worker_pool = var.worker_pool_name + zone = var.zone_name } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/cluster/outputs.tf b/examples/ibm-satellite/modules/cluster/outputs.tf new file mode 100644 index 000000000..4d9303f03 --- /dev/null +++ b/examples/ibm-satellite/modules/cluster/outputs.tf @@ -0,0 +1,11 @@ +output "cluster_id" { + value = data.ibm_satellite_cluster.read_cluster.id +} + +output "master_url" { + value = data.ibm_satellite_cluster.read_cluster.server_url +} + +output "worker_pool_id" { + value = data.ibm_satellite_cluster_worker_pool.read_cluster_wp.id +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/cluster/variables.tf b/examples/ibm-satellite/modules/cluster/variables.tf index 7b415c5c6..b8c25ace5 100644 --- a/examples/ibm-satellite/modules/cluster/variables.tf +++ b/examples/ibm-satellite/modules/cluster/variables.tf @@ -1,11 +1,11 @@ variable "cluster" { description = "Satellite Location Name" - type = string + type = string } variable "location" { description = "Satellite Location Name" - type = string + type = string } variable "kube_version" { @@ -14,40 +14,40 @@ variable "kube_version" { variable "resource_group" { description = "Resource Group Name that has to be targeted" - type = string + type = string } variable "zones" { - type = list(string) - default = ["us-east-1", "us-east-2", "us-east-3"] + type = list(string) + default = ["us-east-1", "us-east-2", "us-east-3"] } variable "worker_pool_name" { description = "Worker Pool Name" - type = string + type = string } variable "worker_count" { description = "Worker Count for default pool" - type = number - default = 1 + type = number + default = 1 } variable "default_wp_labels" { description = "Label to add default worker pool" - type = map + type = map(any) default = { - "poolname" = "default-worker-pool" + "poolname" = "default-worker-pool" } } variable "workerpool_labels" { description = "Label to add to workerpool" - type = map + type = map(any) default = { - "poolname" = "worker-pool" + "poolname" = "worker-pool" } } @@ -59,5 +59,10 @@ variable "host_labels" { variable "cluster_tags" { description = "List of tags associated with this resource." type = list(string) - default = [ "env:cluster" ] + default = ["env:cluster"] +} + +variable "zone_name" { + description = "zone name" + type = string } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/dns/README.md b/examples/ibm-satellite/modules/dns/README.md new file mode 100644 index 000000000..52bd96676 --- /dev/null +++ b/examples/ibm-satellite/modules/dns/README.md @@ -0,0 +1,46 @@ +# This Module is used to register public IP address to satellite location & cluster dns records. + +This module register public IP address to control plane & openshift cluster subdomain DNS records. + +## Usage + +``` +terraform init +``` +``` +terraform plan +``` +``` +terraform apply +``` +``` +terraform destroy +``` +## Example Usage + +``` hcl +module "satellite-dns" { + source = "./modules/dns" + + location = var.location + cluster = var.cluster + control_plane_ips = var.control_plane_ips + cluster_ips = var.cluster_ips +} +``` + + +## Inputs + +| Name | Description | Type | Default | Required | +|-------------------|-------------------------------------------------------------------|----------|---------|----------| +| location | Name of the Location | string | n/a | yes | +| cluster | Name of the cluster | string | n/a | yes | +| control_plane_ips | Public IP addresses | list | n/a | yes | +| cluster_ips | Public IP addresses | list | n/a | yes | + + +## Note + +All optional fields are given value `null` in varaible.tf file. User can configure the same by overwriting with appropriate values. + diff --git a/examples/ibm-satellite/modules/dns/main.tf b/examples/ibm-satellite/modules/dns/main.tf new file mode 100644 index 000000000..f558f83a8 --- /dev/null +++ b/examples/ibm-satellite/modules/dns/main.tf @@ -0,0 +1,23 @@ +data "ibm_resource_group" "resource_group" { + name = var.resource_group +} + +resource "ibm_satellite_location_nlb_dns" "location_dns_instance" { + location = var.location + ips = var.control_plane_ips +} + +data "ibm_satellite_location_nlb_dns" "location_dns_instance" { + location = ibm_satellite_location_nlb_dns.location_dns_instance.location +} + +data "ibm_container_nlb_dns" "dns" { + cluster = var.cluster +} + +resource "ibm_container_nlb_dns" "container_nlb_dns" { + cluster = var.cluster + nlb_host = data.ibm_container_nlb_dns.dns.nlb_config.0.nlb_sub_domain + nlb_ips = var.cluster_ips + resource_group_id = data.ibm_resource_group.resource_group.id +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/dns/variables.tf b/examples/ibm-satellite/modules/dns/variables.tf new file mode 100644 index 000000000..63795528c --- /dev/null +++ b/examples/ibm-satellite/modules/dns/variables.tf @@ -0,0 +1,23 @@ +variable "resource_group" { + description = "resource group" + type = string +} + +variable "location" { + description = "Satellite Location Name" + type = string +} + +variable "cluster" { + description = "Cluster name" +} + +variable "control_plane_ips" { + description = "public ips to register for control plane" + type = list(string) +} + +variable "cluster_ips" { + description = "public ips to register for ROKS cluster" + type = list(string) +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/dns/versions.tf b/examples/ibm-satellite/modules/dns/versions.tf new file mode 100644 index 000000000..01feea38b --- /dev/null +++ b/examples/ibm-satellite/modules/dns/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + ibm = { + source = "ibm-cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/endpoint/main.tf b/examples/ibm-satellite/modules/endpoint/main.tf index 070f67190..9c6d2fb9d 100644 --- a/examples/ibm-satellite/modules/endpoint/main.tf +++ b/examples/ibm-satellite/modules/endpoint/main.tf @@ -1,7 +1,7 @@ // Provision satellite_endpoint resource instance resource "ibm_satellite_endpoint" "instance" { count = var.is_endpoint_provision ? 1 : 0 - + location = var.location connection_type = var.connection_type display_name = var.display_name @@ -16,12 +16,5 @@ resource "ibm_satellite_endpoint" "instance" { timeout = var.timeout created_by = var.created_by - certs { - client { - cert { - filename = "client.pem" - file_contents = var.client_certificate - } - } - } + } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/location/main.tf b/examples/ibm-satellite/modules/location/main.tf index f56e637b8..55e954aec 100644 --- a/examples/ibm-satellite/modules/location/main.tf +++ b/examples/ibm-satellite/modules/location/main.tf @@ -1,10 +1,10 @@ data "ibm_resource_group" "resource_group" { - name = var.resource_group + name = var.resource_group } resource "ibm_satellite_location" "create_location" { - count = var.is_location_exist == false ? 1 : 0 + count = var.is_location_exist == false ? 1 : 0 location = var.location managed_from = var.managed_from @@ -12,31 +12,31 @@ resource "ibm_satellite_location" "create_location" { resource_group_id = data.ibm_resource_group.resource_group.id cos_config { - bucket = var.location_bucket != null ? var.location_bucket : null + bucket = var.location_bucket != null ? var.location_bucket : null } tags = var.tags } data "ibm_satellite_location" "location" { - location = var.is_location_exist == false ? ibm_satellite_location.create_location.0.id : var.location - depends_on = [ ibm_satellite_location.create_location ] + location = var.is_location_exist == false ? ibm_satellite_location.create_location.0.id : var.location + depends_on = [ibm_satellite_location.create_location] } data "ibm_satellite_attach_host_script" "script" { - location = data.ibm_satellite_location.location.id - labels = var.host_labels - host_provider = var.host_provider + location = data.ibm_satellite_location.location.id + labels = var.host_labels + host_provider = var.host_provider } output "location_id" { - value = data.ibm_satellite_location.location.id + value = data.ibm_satellite_location.location.id } output "location_crn" { - value = data.ibm_satellite_location.location.crn + value = data.ibm_satellite_location.location.crn } output "host_script" { - value = data.ibm_satellite_attach_host_script.script.host_script + value = data.ibm_satellite_attach_host_script.script.host_script } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/location/variables.tf b/examples/ibm-satellite/modules/location/variables.tf index 5e2962a86..b3aaf21e4 100644 --- a/examples/ibm-satellite/modules/location/variables.tf +++ b/examples/ibm-satellite/modules/location/variables.tf @@ -5,14 +5,13 @@ variable "location" { description = "Location Name" - type = string - default = "sat-loc-1031" + type = string } variable "managed_from" { description = "The IBM Cloud region to manage your Satellite location from. Choose a region close to your on-prem data center for better performance." - type = string - default = "wdc" + type = string + default = "wdc" } variable "location_zones" { @@ -23,8 +22,8 @@ variable "location_zones" { variable "is_location_exist" { description = "Location Name" - type = bool - default = false + type = bool + default = false } variable "location_bucket" { @@ -51,19 +50,19 @@ variable "host_labels" { default = ["env:prod"] validation { - condition = can([for s in var.host_labels : regex("^[a-zA-Z0-9:]+$", s)]) - error_message = "A `host_labels` can include only alphanumeric characters and with one colon." + condition = can([for s in var.host_labels : regex("^[a-zA-Z0-9:]+$", s)]) + error_message = "A `host_labels` can include only alphanumeric characters and with one colon." } } variable "host_provider" { - description = "The cloud provider of host|vms" - type = string - default = "ibm" + description = "The cloud provider of host|vms" + type = string + default = "ibm" } variable "tags" { description = "List of tags associated with this satellite." type = list(string) - default = [ "env:dev" ] + default = ["env:dev"] } \ No newline at end of file diff --git a/examples/ibm-satellite/modules/route/main.tf b/examples/ibm-satellite/modules/route/main.tf index 8eceb8587..eb5e92183 100644 --- a/examples/ibm-satellite/modules/route/main.tf +++ b/examples/ibm-satellite/modules/route/main.tf @@ -1,18 +1,26 @@ resource "null_resource" "get_oc_token" { count = var.is_endpoint_provision ? 1 : 0 + provisioner "local-exec" { + when = create interpreter = ["/bin/bash", "-c"] command = <<-EOT + sleep 200 curl -u "apikey:${var.ibmcloud_api_key}" -H "X-CSRF-Token: a" "$(curl ${var.cluster_master_url}/.well-known/oauth-authorization-server | jq -r .issuer)/oauth/authorize?client_id=openshift-challenging-client&response_type=token" -vvv &> /dev/stdout | tee -a resp.log token=$(awk -v FS="(#access_token=|&expires_in)" '{print $2}' resp.log) echo $token > token.log rm -f resp.log EOT } + + provisioner "local-exec" { + when = destroy + command = "rm -f token.log" + } } data "local_file" "token_file" { - count = var.is_endpoint_provision ? 1 : 0 + count = var.is_endpoint_provision ? 1 : 0 filename = "token.log" depends_on = [null_resource.get_oc_token] @@ -26,7 +34,7 @@ resource "restapi_object" "create_route" { path = "/apis/route.openshift.io/v1/namespaces/default/routes" data = "{ \"kind\":\"Route\",\"apiVersion\": \"route.openshift.io/v1\", \"metadata\": { \"name\": \"${var.route_name}\", \"creationTimestamp\":null }, \"spec\": { \"to\": { \"kind\": \"\", \"name\": \"nginx-service\", \"weight\": null}, \"port\": { \"targetPort\": \"https\"}, \"tls\": { \"termination\": \"passthrough\"}}, \"status\":{} }" - depends_on = [ null_resource.get_oc_token ] + depends_on = [null_resource.get_oc_token] } output "token_data" { diff --git a/examples/ibm-satellite/modules/route/variables.tf b/examples/ibm-satellite/modules/route/variables.tf index c78302950..d502aad19 100644 --- a/examples/ibm-satellite/modules/route/variables.tf +++ b/examples/ibm-satellite/modules/route/variables.tf @@ -1,6 +1,6 @@ variable "ibmcloud_api_key" { description = "IBM Cloud api key" - type = string + type = string } variable "is_endpoint_provision" { @@ -10,8 +10,8 @@ variable "is_endpoint_provision" { variable "cluster_master_url" { description = "Satellite Cluster URL" - type = string - default = "test.com" + type = string + default = "test.com" } variable "route_name" { diff --git a/examples/ibm-satellite/modules/route/versions.tf b/examples/ibm-satellite/modules/route/versions.tf index 1ab0a1cf2..96cb8731a 100644 --- a/examples/ibm-satellite/modules/route/versions.tf +++ b/examples/ibm-satellite/modules/route/versions.tf @@ -14,9 +14,6 @@ provider "restapi" { uri = fileexists("token.log") ? var.cluster_master_url : "test.com" debug = true headers = { - Authorization = var.is_endpoint_provision ? format("Bearer %v",chomp(element(tolist(data.local_file.token_file.*.content), 0))) : "" + Authorization = var.is_endpoint_provision ? format("Bearer %v", chomp(element(tolist(data.local_file.token_file.*.content), 0))) : "" } -} - -provider "ibm" { } \ No newline at end of file diff --git a/examples/ibm-satellite/route.tf b/examples/ibm-satellite/route.tf index aee9ac6e3..84a8e965c 100644 --- a/examples/ibm-satellite/route.tf +++ b/examples/ibm-satellite/route.tf @@ -1,8 +1,13 @@ +data "ibm_satellite_cluster" "ds_cluster" { + name = var.cluster + depends_on = [module.satellite-dns] +} + module "satellite-route" { - source = "./modules/route" - + source = "./modules/route" + is_endpoint_provision = var.is_endpoint_provision ibmcloud_api_key = var.ibmcloud_api_key - cluster_master_url = module.satellite-cluster.master_url + cluster_master_url = data.ibm_satellite_cluster.ds_cluster.server_url route_name = var.route_name } \ No newline at end of file diff --git a/examples/ibm-satellite/variables.tf b/examples/ibm-satellite/variables.tf index 124a3e032..252327e02 100644 --- a/examples/ibm-satellite/variables.tf +++ b/examples/ibm-satellite/variables.tf @@ -9,6 +9,7 @@ variable "ibmcloud_api_key" { variable "ibm_region" { description = "Region of the IBM Cloud account. Currently supported regions for satellite are us-east and eu-gb region." + default = "us-east" } variable "resource_group" { @@ -20,6 +21,7 @@ variable "resource_group" { ################################################## variable "location" { description = "Location Name" + default = "satelllite-ibm" } variable "managed_from" { @@ -74,7 +76,7 @@ variable "host_count" { variable "addl_host_count" { description = "The total number of additional host for cluster assignment" type = number - default = 6 + default = 3 } variable "is_prefix" { @@ -106,7 +108,7 @@ variable "cluster_zones" { variable "default_wp_labels" { description = "Label to add default worker pool" - type = map + type = map(any) default = { "pool_name" = "default-worker-pool" @@ -116,7 +118,7 @@ variable "default_wp_labels" { variable "kube_version" { description = "Satellite Kube Version" type = string - default = "4.6_openshift" + default = "4.7_openshift" } variable "worker_pool_name" { @@ -127,7 +129,7 @@ variable "worker_pool_name" { variable "workerpool_labels" { description = "Label to add to workerpool" - type = map + type = map(any) default = { "pool_name" = "worker-pool" @@ -146,6 +148,12 @@ variable "cluster_tags" { default = ["env:cluster"] } +variable "zone_name" { + description = "zone name" + type = string + default = "test_zone" +} + ################################################## # Satellite - Link, Route, Endpoint variables ################################################## @@ -162,9 +170,16 @@ variable "is_provision_link" { description = "Determines if the link has to be created or not" } +variable "namespace" { + type = string + description = "Namespace name" + default = "default" +} + variable "route_name" { type = string description = "Cluster route name." + default = "sat-route-01" } // Resource arguments for satellite_link @@ -183,12 +198,13 @@ variable "connection_type" { variable "display_name" { description = "The display name of the endpoint. Endpoint names must start with a letter and end with an alphanumeric character, can contain letters, numbers, and hyphen (-), and must be 63 characters or fewer." type = string + default = "ds-01" } variable "server_host" { description = "The host name or IP address of the server endpoint. For 'http-tunnel' protocol, server_host can start with '*.' , which means a wildcard to it's sub domains. Such as '*.example.com' can accept request to 'api.example.com' and 'www.example.com'." type = string - default = "cloud.ibm.com" + default = "cloud.ibm.com" } variable "server_port" { @@ -248,5 +264,5 @@ variable "created_by" { variable "client_certificate" { description = "The certs." type = string - default = "-----BEGIN CERTIFICATE-----\nMIIDmzCCAoOgAwIBAgIUMVdDe4IYAIMKRixT4v+bbvkXhxMwDQYJKoZIhvcNAQEL\nBQAwHTEbMBkGA1UEAxMScm9vdC1jYS0xNjI2OTYyMzg0MB4XDTIxMDcyMjEzNTYw\nMFoXDTIzMTAyNTEzNTYwMFowYjELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBG\ncmFuY2lzY28xCzAJBgNVBAcTAkNBMRcwFQYDVQQKEw5zeXN0ZW06bWFzdGVyczEV\nMBMGA1UEAxMMc3lzdGVtOmFkbWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAuJ5VeZGEA10qgnqhSSeBtEFxrxCDRvXyY7NFw9NYvwy6ihTPpWAISSs6\nHsH1jlXuXgXtizru8QQ4HSGXyYNvFqVreZgrseUE08B3sL9FTzAehO3Q/azm5jTX\nFLTseUE2mSfSeWPMIYTWgvwMBl1DGRO3GATsp7Ep4uRN4zWIOC94JD76rk8HZSn6\nBVcvOyQT4XcyD9xYRcmztUoQjd92OAbI362OdjrJd/GaOFXSMYsK5MqhT/R/5p/I\nkDP+tHcp4m8ECI55//ztZvmxWAZsVymsvtU0HombLGSGO6WHcdqwenDyqX1toq+t\nVmgmkdzglV34dZkz7jxtS3j3GdzpDQIDAQABo4GNMIGKMA4GA1UdDwEB/wQEAwIF\noDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd\nBgNVHQ4EFgQU4V3A7K5Fe2cO2XesFhvtiwe2QTowHwYDVR0jBBgwFoAUHpq8RvCW\n/vJ31q3868e5CyhhLiAwCwYDVR0RBAQwAoIAMA0GCSqGSIb3DQEBCwUAA4IBAQB0\n0H+QlV6QlALq3tKwPkYaBkYW2m403T/pBtziaxKI5d1GOx4AR4per3IASVWOQYJE\nmA6Iur5dmfKasUJXFZada7KseGFSdrEqG8bhghwn3O0TvCeINgwaiOSS2PRLsIg3\nGo9ErbdhiJgvZ7fSy9B3Gd9SlJpKMNiWrPwyhyv5yGdgxwnKO0hn994eMziag1AH\nfvuIBU0MRYCF3+lq6Nn+ZyUE4H3zv2bvMc9SzRlhDOg6cQUjGWYVTBszR9UmPnC9\nIAzW51A7d2MIEI5Nt7dsuCnnT/TLMOZG4mDnLXrCulvCnaRfk64jq9oUs+K9cYAM\ns3v73KPkn8OrZRh2CKbF\n-----END CERTIFICATE-----" + default = null } \ No newline at end of file diff --git a/examples/ibm-satellite/versions.tf b/examples/ibm-satellite/versions.tf index bf5ff7162..08bf9d768 100644 --- a/examples/ibm-satellite/versions.tf +++ b/examples/ibm-satellite/versions.tf @@ -3,6 +3,10 @@ terraform { ibm = { source = "IBM-Cloud/ibm" } + restapi = { + source = "fmontezuma/restapi" + version = "1.14.1" + } } } diff --git a/examples/ibm-scc/admin/README.md b/examples/ibm-scc/admin/README.md new file mode 100644 index 000000000..f2110f4c6 --- /dev/null +++ b/examples/ibm-scc/admin/README.md @@ -0,0 +1,83 @@ +# Example for AdminServiceApiV1 + +This example illustrates how to use the AdminServiceApiV1 + +These types of resources are supported: + + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## AdminServiceApiV1 resources +```hcl +resource "ibm_scc_account_settings" "ibm_scc_account_settings_instance" { + location_id = var.ibm_scc_account_settings_location_id +} +``` + +## AdminServiceApiV1 Data sources + +scc_account_location_settings data source: + +```hcl +data "scc_account_location_settings" "scc_account_location_settings_instance" { +} +``` +scc_account_location data source: + +```hcl +data "scc_account_location" "scc_account_location_instance" { + location_id = var.scc_account_location_location_id +} +``` +scc_account_locations data source: + +```hcl +data "scc_account_locations" "scc_account_locations_instance" { +} +``` + +## Assumptions + +- The default location has already been set for you + +## Notes + +- Running `terraform apply` will output the location your account is operating in as well as the available locations for your Security and Compliance center + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| location_id | The programatic ID of the location that you want to work in. | `string` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| available_locations | The available Security and Compliance Center locations | +| location_details | The details of a given location | +| current_location_settings_details | The details of the current account settings | diff --git a/examples/ibm-scc/admin/main.tf b/examples/ibm-scc/admin/main.tf new file mode 100644 index 000000000..060649b0d --- /dev/null +++ b/examples/ibm-scc/admin/main.tf @@ -0,0 +1,26 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Update the current account settings +resource "ibm_scc_account_settings" "ibm_scc_account_settings_instance" { + // Optional input of location + location { + location_id = "us" + } + // Optional input of event_notifications + event_notifications { + // instance_crn = "instance_crn" + } +} + +// Read the current account location settings +data "ibm_scc_account_settings" "scc_account_location_settings_instance" {} + +// Read the details of a given location +data "ibm_scc_account_location" "scc_account_location_instance" { + location_id = var.scc_account_location_location_id +} + +// Read all the available locations +data "ibm_scc_account_locations" "scc_account_locations_instance" {} diff --git a/examples/ibm-scc/admin/outputs.tf b/examples/ibm-scc/admin/outputs.tf new file mode 100644 index 000000000..b6f652b0f --- /dev/null +++ b/examples/ibm-scc/admin/outputs.tf @@ -0,0 +1,11 @@ +output "available_locations" { + value = data.ibm_scc_account_locations.scc_account_locations_instance.locations +} + +output "location_details" { + value = data.ibm_scc_account_location.scc_account_location_instance +} + +output "current_location_settings_details" { + value = data.ibm_scc_account_settings.scc_account_location_settings_instance +} diff --git a/examples/ibm-scc/admin/variables.tf b/examples/ibm-scc/admin/variables.tf new file mode 100644 index 000000000..7442d2e2d --- /dev/null +++ b/examples/ibm-scc/admin/variables.tf @@ -0,0 +1,17 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Data source arguments for scc_account_location +variable "scc_account_location_location_id" { + description = "The programatic ID of the location that you want to work in." + type = string + default = "us" +} + +// Resource arguments for ibm_scc_account_settings +variable "ibm_scc_account_settings_location_id" { + description = "The programatic ID of the location that you want to work in." + type = string +} diff --git a/examples/ibm-scc/admin/versions.tf b/examples/ibm-scc/admin/versions.tf new file mode 100644 index 000000000..d9b6f790b --- /dev/null +++ b/examples/ibm-scc/admin/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.12" +} diff --git a/examples/ibm-scc/configuration/README.md b/examples/ibm-scc/configuration/README.md new file mode 100644 index 000000000..3218c5d6d --- /dev/null +++ b/examples/ibm-scc/configuration/README.md @@ -0,0 +1,100 @@ +# Example for ConfigurationGovernanceV1 + +This example illustrates how to use the ConfigurationGovernanceV1 + +These types of resources are supported: + +* scc_template +* scc_template_attachment +* scc_rule +* scc_rule_attachment + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## ConfigurationGovernanceV1 resources + +scc_template resource: + +```hcl +resource "scc_template" "scc_template_instance" { + template = var.scc_template_template +} +``` +scc_template_attachment resource: + +```hcl +resource "scc_template_attachment" "scc_template_attachment_instance" { + template_id = var.scc_template_attachment_template_id + attachment = var.scc_template_attachment_attachment +} +``` +scc_rule resource: + +```hcl +resource "scc_rule" "scc_rule_instance" { + rule = var.scc_rule_rule +} +``` +scc_rule_attachment resource: + +```hcl +resource "scc_rule_attachment" "scc_rule_attachment_instance" { + rule_id = var.scc_rule_attachment_rule_id + attachment = var.scc_rule_attachment_attachment +} +``` + +## ConfigurationGovernanceV1 Data sources + + +## Assumptions + +1. TODO + +## Notes + +1. TODO + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| template | A list of templates to be created. | `list()` | true | +| template_id | The UUID that uniquely identifies the template. | `string` | true | +| attachment | | `list()` | true | +| rule | A list of rules to be created. | `list()` | true | +| rule_id | The UUID that uniquely identifies the rule. | `string` | true | +| attachment | | `list()` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| scc_template | scc_template object | +| scc_template_attachment | scc_template_attachment object | +| scc_rule | scc_rule object | +| scc_rule_attachment | scc_rule_attachment object | diff --git a/examples/ibm-scc/configuration/main.tf b/examples/ibm-scc/configuration/main.tf new file mode 100644 index 000000000..2c191020e --- /dev/null +++ b/examples/ibm-scc/configuration/main.tf @@ -0,0 +1,91 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Provision scc_template resource instance +resource "ibm_scc_template" "scc_template_instance" { + account_id = var.account_id + name = "Terraform template" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + } + } + customized_defaults { + property = "activity_tracking.write_data_events" + value = "true" + } + customized_defaults { + property = "activity_tracking.read_data_events" + value = "true" + } +} + +// Provision scc_template_attachment resource instance +resource "ibm_scc_template_attachment" "scc_template_attachment_instance" { + template_id = ibm_scc_template.scc_template_instance.id + account_id = var.account_id + included_scope { + note = "account id" + scope_id = var.account_id + scope_type = "account" + } + excluded_scopes { + note = "Automated Testing resource group" + scope_id = var.resource_group_id + scope_type = "account.resource_group" + } + depends_on = [ + ibm_scc_template.scc_template_instance // ensures that the template is created first + ] +} +// Provision scc_rule resource instance +resource "ibm_scc_rule" "scc_rule_instance" { + account_id = var.account_id + name = "Terraform rule" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + operator = "string_equals" + value = "us-south" + } + } + labels = ["example"] + required_config { + description = "test config" + and { + property = "storage_class" + operator = "string_equals" + value = "smart" + } + } + enforcement_actions { + action = "disallow" + } +} + +// Provision scc_rule_attachment resource instance +resource "ibm_scc_rule_attachment" "scc_rule_attachment_instance" { + rule_id = ibm_scc_rule.scc_rule_instance.id + account_id = var.account_id + included_scope { + note = "account id" + scope_id = var.account_id + scope_type = "account" + } + excluded_scopes { + note = "Automated Testing resource group" + scope_id = var.resource_group_id + scope_type = "account.resource_group" + } + depends_on = [ + ibm_scc_rule.scc_rule_instance // ensures that the rule is created first + ] +} \ No newline at end of file diff --git a/examples/ibm-scc/configuration/outputs.tf b/examples/ibm-scc/configuration/outputs.tf new file mode 100644 index 000000000..571ddaa6f --- /dev/null +++ b/examples/ibm-scc/configuration/outputs.tf @@ -0,0 +1,24 @@ +// This allows scc_template data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_scc_template" { + value = ibm_scc_template.scc_template_instance + description = "scc_template resource instance" +} +// This allows scc_template_attachment data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_scc_template_attachment" { + value = ibm_scc_template_attachment.scc_template_attachment_instance + description = "scc_template_attachment resource instance" +} +// This allows scc_rule data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_scc_rule" { + value = ibm_scc_rule.scc_rule_instance + description = "scc_rule resource instance" +} +// This allows scc_rule_attachment data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_scc_rule_attachment" { + value = ibm_scc_rule_attachment.scc_rule_attachment_instance + description = "scc_rule_attachment resource instance" +} diff --git a/examples/ibm-scc/configuration/provider.tf b/examples/ibm-scc/configuration/provider.tf new file mode 100644 index 000000000..41fe3e374 --- /dev/null +++ b/examples/ibm-scc/configuration/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + ibm = { + source = "github.ibm.com/cloudengineering/ibm" + version = "0.0.1" + } + } +} \ No newline at end of file diff --git a/examples/ibm-scc/configuration/variables.tf b/examples/ibm-scc/configuration/variables.tf new file mode 100644 index 000000000..6440a3aea --- /dev/null +++ b/examples/ibm-scc/configuration/variables.tf @@ -0,0 +1,16 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Resource arguments + +variable "account_id" { + description = "The ID of the account to target found in: https://cloud.ibm.com/account/settings" + type = string +} + +variable "resource_group_id" { + description = "The ID of the account's resource group to target found in: https://cloud.ibm.com/account/resource-groups" + type = string +} diff --git a/examples/ibm-scc/configuration/versions.tf b/examples/ibm-scc/configuration/versions.tf new file mode 100644 index 000000000..ee0f9705a --- /dev/null +++ b/examples/ibm-scc/configuration/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.12" +} \ No newline at end of file diff --git a/examples/ibm-scc/findings/main.tf b/examples/ibm-scc/findings/main.tf index f985d7ce7..7519ffbf2 100644 --- a/examples/ibm-scc/findings/main.tf +++ b/examples/ibm-scc/findings/main.tf @@ -2,17 +2,37 @@ provider "ibm" { ibmcloud_api_key = var.ibmcloud_api_key } +# Provision scc_si_providers data source instance + +data "ibm_scc_si_providers" "providers" { + limit = 4 +} + # Provision scc_si_notes data source instance data "ibm_scc_si_notes" "notes" { + provider_id = var.provider_id page_size = 3 +} + +# Provision scc_si_note data source instance + +data "ibm_scc_si_note" "note" { provider_id = var.provider_id + note_id = var.note_id } -# Provision scc_si_providers data source instance +# Provision scc_si_occurrences data source instance +data "ibm_scc_si_occurrences" "occurrences" { + provider_id = var.provider_id + page_size = 4 +} -data "ibm_scc_si_providers" "providers" { - limit = 4 +# Provision scc_si_occurrence data source instance + +data "ibm_scc_si_occurrence" "occurrence" { + provider_id = var.provider_id + occurrence_id = var.occurrence_id } # Provision scc_si_note resource instance - Kind FINDING @@ -68,13 +88,13 @@ resource "ibm_scc_si_note" "num-card-finding" { card { section = "Terraform Insights" title = "NUMERIC Finding Card" - subtitle = "Summary of Finding Threats" - finding_note_names = ["providers/scc/notes/finding"] + subtitle = "Summary of Findings" + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] elements { kind = "NUMERIC" text = "Issue Count" value_type { - finding_note_names = ["providers/scc/notes/finding"] + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] kind = "FINDING_COUNT" } } @@ -96,13 +116,13 @@ resource "ibm_scc_si_note" "num-card-kpi" { card { section = "Terraform Insights" title = "NUMERIC KPI Card" - subtitle = "Summary of KPI Threats" - finding_note_names = ["providers/scc/notes/finding"] + subtitle = "Summary of KPIs" + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] elements { kind = "NUMERIC" text = "Issue Count" value_type { - kpi_note_name = "providers/scc/notes/kpi" + kpi_note_name = "${var.account_id}/providers/scc/notes/kpi" kind = "KPI" } } @@ -124,14 +144,14 @@ resource "ibm_scc_si_note" "bkd-card-finding" { card { section = "Terraform Insights" title = "BREAKDOWN Finding Card" - subtitle = "Summary of Finding Threats" - finding_note_names = ["providers/scc/notes/finding"] + subtitle = "Summary of Findings" + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] elements { kind = "BREAKDOWN" text = "Issue Count" value_types { text = "Issue Count" - finding_note_names = ["providers/scc/notes/finding"] + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] kind = "FINDING_COUNT" } } @@ -153,14 +173,14 @@ resource "ibm_scc_si_note" "bkd-card-kpi" { card { section = "Terraform Insights" title = "BREAKDOWN KPI Card" - subtitle = "Summary of KPI Threats" - finding_note_names = ["providers/scc/notes/finding"] + subtitle = "Summary of KPIs" + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] elements { kind = "BREAKDOWN" text = "Issue Count" value_types { text = "Issue Count" - kpi_note_name = "providers/scc/notes/kpi" + kpi_note_name = "${var.account_id}/providers/scc/notes/kpi" kind = "KPI" } } @@ -182,17 +202,52 @@ resource "ibm_scc_si_note" "ts-card-finding" { card { section = "Terraform Insights" title = "TIME_SERIES Finding Card" - subtitle = "Summary of Finding Threats" - finding_note_names = ["providers/scc/notes/finding"] + subtitle = "Summary of Findings" + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] elements { kind = "TIME_SERIES" text = "Issue Count" default_time_range = "3d" value_types { text = "Issue Count" - finding_note_names = ["providers/scc/notes/finding"] + finding_note_names = ["${var.account_id}/providers/scc/notes/finding"] kind = "FINDING_COUNT" } } } } + + +// Provision scc_si_occurrence resource instance - Kind FINDING + +resource "ibm_scc_si_occurrence" "finding-occurrence" { + provider_id = var.provider_id + note_name = "${var.account_id}/providers/${var.provider_id}/notes/${var.note_id}" + kind = "FINDING" + occurrence_id = "finding-occ" + resource_url = "https://cloud.ibm.com" + remediation = "Limit the cluster access" + finding { + severity = "HIGH" + certainty = "LOW" + next_steps { + title = "Security Threat" + url = "https://cloud.ibm.com/security-compliance/findings" + } + } +} + +// Provision scc_si_occurrence resource instance - Kind KPI + +resource "ibm_scc_si_occurrence" "kpi-occurrence" { + provider_id = var.provider_id + note_name = "${var.account_id}/providers/${var.provider_id}/notes/${var.note_id}" + kind = "KPI" + occurrence_id = "kpi-occ" + resource_url = "https://cloud.ibm.com" + remediation = "Limit the cluster access" + kpi { + value = 40 + total = 100 + } +} \ No newline at end of file diff --git a/examples/ibm-scc/findings/outputs.tf b/examples/ibm-scc/findings/outputs.tf index aecc2a2e5..d42bfd6b5 100644 --- a/examples/ibm-scc/findings/outputs.tf +++ b/examples/ibm-scc/findings/outputs.tf @@ -1,4 +1,9 @@ output "ibm_scc_si_note" { value = ibm_scc_si_note.bkd-card-kpi description = "scc_si_note resource instance" +} + +output "ibm_scc_si_occurrence" { + value = ibm_scc_si_occurrence.kpi-occurrence + description = "scc_si_occurrence resource instance" } \ No newline at end of file diff --git a/examples/ibm-scc/findings/variables.tf b/examples/ibm-scc/findings/variables.tf index 688bde40e..ec4cce449 100644 --- a/examples/ibm-scc/findings/variables.tf +++ b/examples/ibm-scc/findings/variables.tf @@ -3,8 +3,23 @@ variable "ibmcloud_api_key" { type = string } +variable "account_id" { + description = "IBM Cloud Account ID" + type = string +} + variable "provider_id" { - default = "scc" description = "Part of parent. This field contains the provider_id for example: providers/{provider_id}" + type = string +} + +variable "note_id" { + description = "Second part of note name: providers/{provider_id}/notes/{note_id}" + type = string +} + +variable "occurrence_id" { + description = "Second part of occurrence name: providers/{provider_id}/occurrences/{occurrence_id}" + type = string } diff --git a/examples/ibm-scc/posture-management/README.md b/examples/ibm-scc/posture-management/README.md index b09158cab..f2450ce15 100644 --- a/examples/ibm-scc/posture-management/README.md +++ b/examples/ibm-scc/posture-management/README.md @@ -1,9 +1,12 @@ -# Example for PostureManagementV1 +# Example for PostureManagementV2 -This example illustrates how to use the PostureManagementV1 +This example illustrates how to use the PostureManagementV2 These types of resources are supported: +* collectors +* scopes +* credentials ## Usage @@ -18,23 +21,67 @@ $ terraform apply Run `terraform destroy` when you don't need these resources. -## PostureManagementV1 resources +## PostureManagementV2 resources +scc_posture_collector resource: -## PostureManagementV1 Data sources +```hcl +resource "ibm_scc_posture_collector" "collectors_instance" { + name = var.collectors_name + is_public = var.collectors_is_public + managed_by = var.collectors_managed_by + description = var.collectors_description + passphrase = var.collectors_passphrase + is_ubi_image = var.collectors_is_ubi_image +} +``` +scc_posture_scope resource: + +```hcl +resource "ibm_scc_posture_scope" "scopes_instance" { + name = var.scopes_name + description = var.scopes_description + collector_ids = var.scopes_collector_ids + credential_id = var.scopes_credential_id + credential_type = var.scopes_credential_type + interval = var.scopes_interval + is_discovery_scheduled = var.scopes_is_discovery_scheduled +} +``` +scc_posture_credential resource: + +```hcl +resource "ibm_scc_posture_credential" "credentials_instance" { + enabled = var.credentials_enabled + type = var.credentials_type + name = var.credentials_name + description = var.credentials_description + display_fields = var.credentials_display_fields + group = var.credentials_group + purpose = var.credentials_purpose +} +``` + +## PostureManagementV2 Data sources scc_posture_scopes data source: ```hcl data "ibm_scc_posture_scopes" "list_scopes_instance" { - scope_id = var.list_scopes_scope_id +} +``` +scc_posture_profile data source: + +```hcl +data "ibm_scc_posture_profile" "profileDetails_instance" { + id = var.profileDetails_id + profile_type = var.profileDetails_profile_type } ``` scc_posture_profiles data source: ```hcl data "ibm_scc_posture_profiles" "list_profiles_instance" { - profile_id = var.list_profiles_profile_id } ``` scc_posture_latest_scans data source: @@ -56,12 +103,32 @@ scc_posture_scan_summaries data source: ```hcl data "ibm_scc_posture_scan_summaries" "scan_summaries_instance" { - profile_id = var.scan_summaries_profile_id - scope_id = var.scan_summaries_scope_id - scan_id = var.scan_summaries_scan_id + report_setting_id = var.scan_summaries_report_setting_id +} +``` +scc_posture_group_profile data source: + +```hcl +data "ibm_scc_posture_group_profile" "group_profile_details_instance" { + profile_id = var.group_profile_details_profile_id +} +``` +scc_posture_scope_correlation data source: + +```hcl +data "ibm_scc_posture_scope_correlation" "scope_correlation_instance" { + correlation_id = var.scope_correlation_correlation_id } ``` +## Assumptions + +1. TODO + +## Notes + +1. TODO + ## Requirements | Name | Version | @@ -79,21 +146,47 @@ data "ibm_scc_posture_scan_summaries" "scan_summaries_instance" { | Name | Description | Type | Required | |------|-------------|------|---------| | ibmcloud\_api\_key | IBM Cloud API key | `string` | true | -| scope_id | An auto-generated unique identifier for the scope. | `string` | false | -| profile_id | An auto-generated unique identifying number of the profile. | `string` | false | +| name | A unique name for your collector. | `string` | true | +| is_public | Determines whether the collector endpoint is accessible on a public network. If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. | `bool` | true | +| managed_by | Determines whether the collector is an IBM or customer-managed virtual machine. Use `ibm` to allow Security and Compliance Center to create, install, and manage the collector on your behalf. The collector is installed in an OpenShift cluster and approved automatically for use. Use `customer` if you would like to install the collector by using your own virtual machine. For more information, check out the [docs](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-collector). | `string` | true | +| description | A detailed description of the collector. | `string` | false | +| passphrase | To protect the credentials that you add to the service, a passphrase is used to generate a data encryption key. The key is used to securely store your credentials and prevent anyone from accessing them. | `string` | false | +| is_ubi_image | Determines whether the collector has a Ubi image. | `bool` | false | +| name | A unique name for your scope. | `string` | true | +| description | A detailed description of the scope. | `string` | true | +| collector_ids | The unique IDs of the collectors that are attached to the scope. | `list(string)` | true | +| credential_id | The unique identifier of the credential. | `string` | true | +| credential_type | The environment that the scope is targeted to. | `string` | true | +| interval | Stores the value of Frequency. This is used in case of on-prem Scope if the user wants to schedule a discovery task.The unit is seconds. Example if a user wants to trigger discovery every hour, this value will be set to 3600. | `number` | false | +| is_discovery_scheduled | Stores the value of Discovery Scheduled.This is used in case of on-prem Scope if the user wants to schedule a discovery task. | `bool` | false | +| enabled | Credentials status enabled/disbaled. | `bool` | true | +| type | Credentials type. | `string` | true | +| name | Credentials name. | `string` | true | +| description | Credentials description. | `string` | true | +| display_fields | Details the fields on the credential. This will change as per credential type selected. | `` | true | +| group | Credential group details. | `` | true | +| purpose | Purpose for which the credential is created. | `string` | true | +| id | The id for the given API. | `string` | true | +| profile_type | The profile type ID. This will be 4 for profiles and 6 for group profiles. | `string` | true | | scan_id | The ID of the scan. | `string` | false | | scan_id | Your Scan ID. | `string` | true | | profile_id | The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID. | `string` | true | +| report_setting_id | The report setting ID. This can be obtained from the /validations/latest_scans API call. | `string` | true | | profile_id | The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID. | `string` | true | -| scope_id | The scope ID. This can be obtained from the Security and Compliance Center UI by clicking on the scope name. The URL contains the ID. | `string` | true | -| scan_id | The ID of the scan. | `string` | false | +| correlation_id | A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation). | `string` | true | ## Outputs | Name | Description | |------|-------------| -| scc_posture_scopes | list_scopes object | +| collectors | collectors object | +| scopes | scopes object | +| credentials | credentials object | +| list_scopes | list_scopes object | +| profileDetails | profileDetails object | | list_profiles | list_profiles object | | list_latest_scans | list_latest_scans object | | scans_summary | scans_summary object | | scan_summaries | scan_summaries object | +| group_profile_details | group_profile_details object | +| scope_correlation | scope_correlation object | diff --git a/examples/ibm-scc/posture-management/main.tf b/examples/ibm-scc/posture-management/main.tf index 572f92486..208ac4a72 100644 --- a/examples/ibm-scc/posture-management/main.tf +++ b/examples/ibm-scc/posture-management/main.tf @@ -12,6 +12,14 @@ data "ibm_scc_posture_profiles" "list_profiles_instance" { profile_id = var.list_profiles_profile_id } +// Create list_credentials data source +data "ibm_scc_posture_credentials" "list_credentials_instance" { +} + +// Create list_collectors data source +data "ibm_scc_posture_collectors" "list_collectors_instance" { +} + // Create list_latest_scans data source data "ibm_scc_posture_latest_scans" "list_latest_scans_instance" { scan_id = var.list_latest_scans_scan_id @@ -29,3 +37,18 @@ data "ibm_scc_posture_scan_summaries" "scan_summaries_instance" { scope_id = var.scan_summaries_scope_id scan_id = var.scan_summaries_scan_id } + +// Create scope data source +data "ibm_scc_posture_scope" "scope_instance" { + scope_id = var.scope_id +} + +// Create collector data source +data "ibm_scc_posture_collector" "collector_instance" { + collector_id = var.collector_id +} + +// Create credential data source +data "ibm_scc_posture_credential" "credential_instance" { + credential_id = var.credential_id +} \ No newline at end of file diff --git a/examples/ibm-scc/posture-management/variables.tf b/examples/ibm-scc/posture-management/variables.tf index ca61b65b1..fc4de589b 100644 --- a/examples/ibm-scc/posture-management/variables.tf +++ b/examples/ibm-scc/posture-management/variables.tf @@ -3,22 +3,109 @@ variable "ibmcloud_api_key" { type = string } -// Data source arguments for list_scopes -variable "list_scopes_scope_id" { - description = "An auto-generated unique identifier for the scope." +// Resource arguments for collectors +variable "collectors_name" { + description = "A unique name for your collector." + type = string + default = "IBM-collector-sample" +} +variable "collectors_is_public" { + description = "Determines whether the collector endpoint is accessible on a public network. If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network." + type = bool + default = true +} +variable "collectors_managed_by" { + description = "Determines whether the collector is an IBM or customer-managed virtual machine. Use `ibm` to allow Security and Compliance Center to create, install, and manage the collector on your behalf. The collector is installed in an OpenShift cluster and approved automatically for use. Use `customer` if you would like to install the collector by using your own virtual machine. For more information, check out the [docs](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-collector)." + type = string + default = "customer" +} +variable "collectors_description" { + description = "A detailed description of the collector." type = string + default = "sample collector" +} +variable "collectors_passphrase" { + description = "To protect the credentials that you add to the service, a passphrase is used to generate a data encryption key. The key is used to securely store your credentials and prevent anyone from accessing them." + type = string + default = "secret" +} +variable "collectors_is_ubi_image" { + description = "Determines whether the collector has a Ubi image." + type = bool + default = true } -// Data source arguments for list_profiles -variable "list_profiles_profile_id" { - description = "An auto-generated unique identifying number of the profile." +// Resource arguments for scopes +variable "scopes_name" { + description = "A unique name for your scope." + type = string + default = "IBMSchema-new-048-test1" +} +variable "scopes_description" { + description = "A detailed description of the scope." + type = string + default = "IBMSchema1" +} +variable "scopes_collector_ids" { + description = "The unique IDs of the collectors that are attached to the scope." + type = list(string) + default = ["3"] +} +variable "scopes_credential_id" { + description = "The unique identifier of the credential." + type = string + default = "4" +} +variable "scopes_credential_type" { + description = "The environment that the scope is targeted to." + type = string + default = "ibm" +} + +// Resource arguments for credentials +variable "credentials_enabled" { + description = "Credentials status enabled/disbaled." + type = bool + default = true +} +variable "credentials_type" { + description = "Credentials type." + type = string + default = "ibm_cloud" +} +variable "credentials_name" { + description = "Credentials name." type = string + default = "test_create1" } +variable "credentials_description" { + description = "Credentials description." + type = string + default = "This credential is used for testing" +} +variable "credentials_purpose" { + description = "Purpose for which the credential is created." + type = string + default = "discovery_fact_collection_remediation" +} + +// Data source arguments for list_scopes + +// Data source arguments for profileDetails +variable "profileDetails_id" { + description = "The id for the given API." + type = string +} +variable "profileDetails_profile_type" { + description = "The profile type ID. This will be 4 for profiles and 6 for group profiles." + type = string + default = "4" +} + +// Data source arguments for list_profiles // Data source arguments for list_latest_scans variable "list_latest_scans_scan_id" { - description = "The ID of the scan." - type = string } // Data source arguments for scans_summary @@ -32,15 +119,37 @@ variable "scans_summary_profile_id" { } // Data source arguments for scan_summaries -variable "scan_summaries_profile_id" { - description = "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID." +variable "scan_summaries_report_setting_id" { + description = "The report setting ID. This can be obtained from the /validations/latest_scans API call." type = string } -variable "scan_summaries_scope_id" { - description = "The scope ID. This can be obtained from the Security and Compliance Center UI by clicking on the scope name. The URL contains the ID." + +// Data source arguments for group_profile_details +variable "group_profile_details_profile_id" { + description = "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID." type = string } -variable "scan_summaries_scan_id" { - description = "The ID of the scan." + +// Data source arguments for scope_correlation +variable "scope_correlation_correlation_id" { + description = "A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation)." type = string } + +// Data source arguments for scope +variable "scope_id" { + description = "The scope ID. This can be obtained from the Security and Compliance Center UI by clicking on the scope name. The URL contains the ID." + type = string +} + +// Data source arguments for credential +variable "credential_id" { + description = "The collector ID. This can be obtained from the Security and Compliance Center UI by clicking on the credential name. The network tab contains the ID." + type = string +} + +// Data source arguments for collector +variable "collector_id" { + description = "The collector ID. This can be obtained from the Security and Compliance Center UI by clicking on the collector name. The network tab contains the ID." + type = string +} \ No newline at end of file diff --git a/examples/ibm-transit-gateway/README.md b/examples/ibm-transit-gateway/README.md index 78fa612bc..68a51990a 100644 --- a/examples/ibm-transit-gateway/README.md +++ b/examples/ibm-transit-gateway/README.md @@ -47,12 +47,32 @@ resource "ibm_is_vpc" "test_tg_vpc" { } resource "ibm_tg_connection" "test_ibm_tg_connection"{ - gateway = "${ibm_tg_gateway.new_tg_gw.id}" - network_type = var.network_type - name= vc_name - network_id = ibm_is_vpc.test_tg_vpc.resource_crn + gateway = "${ibm_tg_gateway.new_tg_gw.id}" + network_type = var.network_type + name= vc_name + network_id = ibm_is_vpc.test_tg_vpc.resource_crn } ``` + +Create a transit gateway connection prefix filter: +```hcl +resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + action = "permit" + prefix = "192.168.100.0/24" + le = 0 + ge = 32 +} +``` + +Create a transit gateway route report: + +```hcl +resource ibm_tg_route_report" "test_tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw.id +} +``` ## Transit Gateway Data Sources Retrieves specified Transit Gateway: @@ -80,7 +100,34 @@ Get the details of a Transit Gateway Location. data "ibm_tg_location" "tg_location" { name = var.location } - +``` +List all prefix filters for a Transit Gateway Connection +```` +data "ibm_tg_connection_prefix_filters" "tg_prefix_filters" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id +} +``` +Retrieve specified Transit Gateway Connection Prefix Filter +``` +data "ibm_tg_connection_prefix_filter" "tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + filter_id = ibm_tg_connection_prefix_filter.test_tg_prefix_filter.filter_id +} +``` +List all route reports for a Transit Gateway +``` +data "ibm_tg_route_reports" "tg_route_reports" { + gateway = ibm_tg_gateway.new_tg_gw.id +} +``` +Retrieve specified Transit Gateway Route Report +``` +data "ibm_tg_route_report" "tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw. + route_report = ibm_tg_route_report_test_tg_route_report.route_report_id +} ``` ## Examples diff --git a/examples/ibm-transit-gateway/main.tf b/examples/ibm-transit-gateway/main.tf index f8041ca72..09409f8b3 100644 --- a/examples/ibm-transit-gateway/main.tf +++ b/examples/ibm-transit-gateway/main.tf @@ -15,6 +15,15 @@ resource "ibm_tg_connection" "test_ibm_tg_connection"{ name = var.vc_name network_id = ibm_is_vpc.test_tg_vpc.resource_crn } +# Add a prefix filter to a Transit Gateway connection +resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + action = "permit" + prefix = "192.168.100.0/24" + le = "0" + ge = "32" +} /* # Create a transit gateway cross account connection resource "ibm_tg_connection" "test_tg_cross_connection"{ @@ -50,6 +59,11 @@ resource "ibm_tg_connection" "test_tg_dl_connection"{ network_id = var.network_id } +# Create a transit gateway route report +resource ibm_tg_route_report" "test_tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw.id +} + # Retrieves specified Transit Gateway data "ibm_tg_gateway" "tg_gateway" { name= ibm_tg_gateway.new_tg_gw.name @@ -65,4 +79,28 @@ data "ibm_tg_location" "tg_location" { name = "us-south" } +# List all prefix filters for a Transit Gateway Connection +data "ibm_tg_connection_prefix_filters" "tg_prefix_filters" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id +} + +# Retrieve specified Transit Gateway Connection Prefix Filter +data "ibm_tg_connection_prefix_filter" "tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + filter_id = ibm_tg_connection_prefix_filter.test_tg_prefix_filter.filter_id +} + +# List all route reports for a Transit Gateway +data "ibm_tg_route_reports" "tg_route_reports" { + gateway = ibm_tg_gateway.new_tg_gw.id +} + +# Retrieve specified Transit Gateway Route report +data "ibm_tg_route_report" "tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw. + route_report = ibm_tg_route_report_test_tg_route_report.route_report_id +} + */ \ No newline at end of file diff --git a/examples/ibm-watson-query/README.md b/examples/ibm-watson-query/README.md new file mode 100644 index 000000000..6814f169b --- /dev/null +++ b/examples/ibm-watson-query/README.md @@ -0,0 +1,51 @@ +# IBM Watson Query examples + +This example shows 1 usage scenario. + +#### Scenario 1: Create a Watson Query service instance. + +```terraform +resource "ibm_resource_instance" "wq_instance_1" { + name = "terraform-integration-1" + service = "data-virtualization" + plan = "data-virtualization-enterprise" # "data-virtualization-enterprise-dev","data-virtualization-enterprise-preprod","data-virtualization-enterprise-dev-stable" + location = "us-south" # "eu-gb", "eu-de", "jp-tok" + resource_group_id = data.ibm_resource_group.group.id + + # timeouts { + # create = "15m" # use 3h when creating enterprise instance, add additional 1h for each level of non-default throughput, add additional 30m for each level of non-default storage_size + # update = "15m" # use 1h when updating enterprise instance, add additional 1h for each level of non-default throughput, add additional 30m for each level of non-default storage_size + # delete = "15m" + # } +} + +``` + +## Dependencies + +- The owner of the `ibmcloud_api_key` has permission to create Watson Query instance under specified resource group. + +## Configuration + +- `ibmcloud_api_key` - An API key for IBM Cloud services. If you don't have one already, go to https://cloud.ibm.com/iam/#/apikeys and create a new key. + +## Running the configuration + +For planning phase + +```bash +terraform init +terraform plan +``` + +For apply phase + +```bash +terraform apply +``` + +For destroy + +```bash +terraform destroy +``` diff --git a/examples/ibm-watson-query/main.tf b/examples/ibm-watson-query/main.tf new file mode 100644 index 000000000..c418f20bd --- /dev/null +++ b/examples/ibm-watson-query/main.tf @@ -0,0 +1,20 @@ + +data "ibm_resource_group" "group" { + name = "Default" +} + +#### Scenario 1: Create Watson Query service instance +resource "ibm_resource_instance" "wq_instance_1" { + name = "terraform-integration-1" + service = "data-virtualization" + plan = "data-virtualization-enterprise" # "data-virtualization-enterprise-dev","data-virtualization-enterprise-preprod","data-virtualization-enterprise-dev-stable" + location = "us-south" # "eu-gb", "eu-de", "jp-tok" + resource_group_id = data.ibm_resource_group.group.id + + # timeouts { + # create = "15m" # use 3h when creating enterprise instance, add additional 1h for each level of non-default throughput, add additional 30m for each level of non-default storage_size + # update = "15m" # use 1h when updating enterprise instance, add additional 1h for each level of non-default throughput, add additional 30m for each level of non-default storage_size + # delete = "15m" + # } +} + diff --git a/examples/ibm-watson-query/provider.tf b/examples/ibm-watson-query/provider.tf new file mode 100644 index 000000000..5742ff889 --- /dev/null +++ b/examples/ibm-watson-query/provider.tf @@ -0,0 +1,7 @@ +variable "ibmcloud_api_key" { + description = "Enter your IBM Cloud API Key, you can get your IBM Cloud API key using: https://cloud.ibm.com/iam#/apikeys" +} + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} \ No newline at end of file diff --git a/examples/ibm-watson-query/terraform.tfvars b/examples/ibm-watson-query/terraform.tfvars new file mode 100644 index 000000000..99c60a070 --- /dev/null +++ b/examples/ibm-watson-query/terraform.tfvars @@ -0,0 +1,2 @@ +# Enter your IBM Cloud API Key, you can get your IBM Cloud API key using: https://cloud.ibm.com/iam#/apikeys +ibmcloud_api_key = "" diff --git a/examples/ibm-watson-query/versions.tf b/examples/ibm-watson-query/versions.tf new file mode 100644 index 000000000..ed2a70ecd --- /dev/null +++ b/examples/ibm-watson-query/versions.tf @@ -0,0 +1,9 @@ + +terraform { + required_version = ">= 0.12" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} diff --git a/examples/portworx/README.md b/examples/portworx/installation/README.md similarity index 100% rename from examples/portworx/README.md rename to examples/portworx/installation/README.md diff --git a/examples/portworx/main.tf b/examples/portworx/installation/main.tf similarity index 100% rename from examples/portworx/main.tf rename to examples/portworx/installation/main.tf diff --git a/examples/portworx/outputs.tf b/examples/portworx/installation/outputs.tf similarity index 100% rename from examples/portworx/outputs.tf rename to examples/portworx/installation/outputs.tf diff --git a/examples/portworx/variables.tf b/examples/portworx/installation/variables.tf similarity index 100% rename from examples/portworx/variables.tf rename to examples/portworx/installation/variables.tf diff --git a/examples/portworx/vpc-worker-replace/README.md b/examples/portworx/vpc-worker-replace/README.md new file mode 100644 index 000000000..aa0506d74 --- /dev/null +++ b/examples/portworx/vpc-worker-replace/README.md @@ -0,0 +1,84 @@ +# IBM Cloud VPC Gen 2 Worker Replace + +This example shows how to replace & update the Kubernetes VPC Gen-2 worker to the latest patch in the specified cluster. For more information, about VPC worker updates, see [Updating VPC worker nodes](https://cloud.ibm.com/docs/containers?topic=containers-update&interface=ui#vpc_worker_node) + +## Usage + +To run this example you need to execute: + +```sh +$ terraform init +$ terraform plan -var-file input.tfvars +$ terraform apply -var-file input.tfvars +``` + +* Run `terraform untaint ibm_container_vpc_worker.[index]` to untaint the failed worker after fixing it manually to proceed with next set of workers +* Run `terraform destroy` when you need to provide new set of worker list + +## Example usage + +Perform worker replace: + +```terraform +resource "ibm_container_vpc_worker" "worker" { + count = length(var.worker_list) + cluster_name = var.cluster_name + replace_worker = element(var.worker_list, count.index) + resource_group_id = data.ibm_resource_group.group.id + kube_config_path = data.ibm_container_cluster_config.cluster_config.config_file_path + check_ptx_status = var.check_ptx_status + ptx_timeout = (var.ptx_timeout != null ? var.ptx_timeout : null) + + timeouts { + create = (var.create_timeout != null ? var.create_timeout : null) + delete = (var.delete_timeout != null ? var.delete_timeout : null) + } +} +``` + +```terraform +data ibm_resource_group group { + name = var.resource_group +} + +data ibm_container_cluster_config cluster_config { + cluster_name_id = var.cluster_name + resource_group_id = data.ibm_resource_group.group.id +} +``` + +## Examples + +* [Portworx VPC Gen 2 worker replace](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/portworx/vpc-worker-replace) + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >=1.0.0, <2.0 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | latest | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| cluster_name | Name of the cluster. | `string` | yes | +| replace_worker | ID of the worker to be replaced. | `string` | yes | +| resource_group_id | ID of the resousrce group | `string` | no | +| check_ptx_status | Whether to check ptx status on replaced workers | `bool` | no | +| kube_config_path | The Cluster config with absolute path | `string` | no | +| ptx_timeout | Timeout used while checking the portworx status | `string` | no + +## Note + +* This resource is different from all other resource of IBM Cloud. Worker replace has 2 operations, i.e. Delete old worker & Create a new worker. On `terraform apply`, Replace operation is being handled where both the deletion & creation happens whereas on the `terraform destroy`, only the state is cleared but not the actual resource. +* When the worker list is being provided as inputs, the list must be user generated and should not be passed from the `ibm_container_cluster` data source. +* If `terraform apply` fails during worker replace or while checking the portworx status, perform any one of the following actions before retrying. + * Resolve the issue manually and perform `terraform untaint` to proceed with the subsequent workers in the list. + * If worker replace is still needed, update the input list by replacing the existing worker id with the new worker id. diff --git a/examples/portworx/vpc-worker-replace/main.tf b/examples/portworx/vpc-worker-replace/main.tf new file mode 100644 index 000000000..c49d9ab76 --- /dev/null +++ b/examples/portworx/vpc-worker-replace/main.tf @@ -0,0 +1,31 @@ +##################################################### +# vpc worker replace/update +# Copyright 2022 IBM +##################################################### + +##################################################### +# Read each worker information attached to cluster +##################################################### +data ibm_resource_group group { + name = var.resource_group +} + +data ibm_container_cluster_config cluster_config { + cluster_name_id = var.cluster_name + resource_group_id = data.ibm_resource_group.group.id +} + +resource "ibm_container_vpc_worker" "worker" { + count = length(var.worker_list) + cluster_name = var.cluster_name + replace_worker = element(var.worker_list, count.index) + resource_group_id = data.ibm_resource_group.group.id + kube_config_path = data.ibm_container_cluster_config.cluster_config.config_file_path + check_ptx_status = var.check_ptx_status + ptx_timeout = (var.ptx_timeout != null ? var.ptx_timeout : null) + + timeouts { + create = (var.create_timeout != null ? var.create_timeout : null) + delete = (var.delete_timeout != null ? var.delete_timeout : null) + } +} diff --git a/examples/portworx/vpc-worker-replace/provider.tf b/examples/portworx/vpc-worker-replace/provider.tf new file mode 100644 index 000000000..4a12678dd --- /dev/null +++ b/examples/portworx/vpc-worker-replace/provider.tf @@ -0,0 +1,3 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} diff --git a/examples/portworx/vpc-worker-replace/variables.tf b/examples/portworx/vpc-worker-replace/variables.tf new file mode 100644 index 000000000..a887951eb --- /dev/null +++ b/examples/portworx/vpc-worker-replace/variables.tf @@ -0,0 +1,69 @@ +###################################################### +#IBM-Cloud Authentication Credentials +###################################################### + +variable "ibmcloud_api_key" { + type = string + description = "IBM-Cloud API Key" +} + +##################################################### +# Vpc Kubernetes cluster +# Copyright 2020 IBM +##################################################### +variable "cluster_name" { + description = "Name of the VPC cluster" + type = string +} + + +##################################################### +# If the worker list is being provided as inputs, +# the list should be user generated and +# should not be passed from the `ibm_container_cluster` data source. +# +# The order of the list should not be changed until +# all the workers in the list are replaced. +# +# This is required to avoid diffs of order changes. +##################################################### +variable "worker_list" { + description = "List of workers to process" + type = list(string) +} + +variable "resource_group" { + description = "Name of resource group." + type = string + default = null +} + +variable "create_timeout" { + type = string + description = "Timeout duration for create." + default = null +} + +variable "delete_timeout" { + type = string + description = "Timeout duration for delete." + default = null +} + +variable "ptx_timeout" { + type = string + description = "Timeout duration for checking ptx pods/status." + default = null +} + +variable "kube_config_path" { + description = "Path of downloaded cluster config" + type = string + default = "" +} + +variable "check_ptx_status" { + description = "Check status of portworx on replaced workers" + type = bool + default = true +} diff --git a/examples/portworx/vpc-worker-replace/versions.tf b/examples/portworx/vpc-worker-replace/versions.tf new file mode 100644 index 000000000..80fb63aec --- /dev/null +++ b/examples/portworx/vpc-worker-replace/versions.tf @@ -0,0 +1,12 @@ +############################### +# IBM Cloud Copyright 2020 IBM +############################### + +terraform { +required_version = ">=1.0.0, <2.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + } + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index d396260af..3f7a38d50 100644 --- a/go.mod +++ b/go.mod @@ -1,60 +1,171 @@ module github.com/IBM-Cloud/terraform-provider-ibm -go 1.16 +go 1.18 require ( - github.com/IBM-Cloud/bluemix-go v0.0.0-20211005115032-00ba77f0db57 - github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62 - github.com/IBM-Cloud/power-go-client v1.0.74 + github.com/IBM-Cloud/bluemix-go v0.0.0-20220523145737-34645883de47 + github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20220922071204-21813161c36f + github.com/IBM-Cloud/power-go-client v1.2.1 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca - github.com/IBM/appconfiguration-go-admin-sdk v0.1.0 + github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f - github.com/IBM/cloudant-go-sdk v0.0.36 - github.com/IBM/container-registry-go-sdk v0.0.13 - github.com/IBM/event-notifications-go-admin-sdk v0.0.2 + github.com/IBM/cloud-databases-go-sdk v0.2.0 + github.com/IBM/cloudant-go-sdk v0.0.43 + github.com/IBM/container-registry-go-sdk v0.0.15 + github.com/IBM/continuous-delivery-go-sdk v0.1.2 + github.com/IBM/event-notifications-go-admin-sdk v0.1.2 github.com/IBM/eventstreams-go-sdk v1.2.0 - github.com/IBM/go-sdk-core/v4 v4.10.0 - github.com/IBM/go-sdk-core/v5 v5.6.5 - github.com/IBM/ibm-cos-sdk-go v1.7.0 + github.com/IBM/go-sdk-core/v5 v5.10.2 + github.com/IBM/ibm-cos-sdk-go v1.9.0 github.com/IBM/ibm-cos-sdk-go-config v1.2.0 - github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20210723145459-a232c3f3ac91 + github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 + github.com/IBM/ibm-hpcs-uko-sdk v0.0.4 github.com/IBM/keyprotect-go-client v0.7.0 - github.com/IBM/networking-go-sdk v0.23.0 - github.com/IBM/platform-services-go-sdk v0.20.1 + github.com/IBM/networking-go-sdk v0.34.0 + github.com/IBM/platform-services-go-sdk v0.28.5 github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 - github.com/IBM/scc-go-sdk v1.2.0 - github.com/IBM/schematics-go-sdk v0.0.2 + github.com/IBM/scc-go-sdk/v3 v3.1.6 + github.com/IBM/scc-go-sdk/v4 v4.0.0 + github.com/IBM/schematics-go-sdk v0.2.1 github.com/IBM/secrets-manager-go-sdk v0.1.19 - github.com/IBM/vpc-go-sdk v0.12.0 - github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect + github.com/IBM/vpc-go-sdk v0.27.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/Shopify/sarama v1.29.1 github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105 github.com/apparentlymart/go-cidr v1.1.0 - github.com/aws/aws-sdk-go v1.37.0 // indirect - github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect github.com/ghodss/yaml v1.0.0 - github.com/go-openapi/strfmt v0.20.2 - github.com/go-openapi/validate v0.20.1 // indirect - github.com/go-test/deep v1.0.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/strfmt v0.21.3 github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.5.6 - github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.2.0 - github.com/hashicorp/go-uuid v1.0.2 - github.com/hashicorp/go-version v1.3.0 - github.com/hashicorp/hcl/v2 v2.8.2 // indirect - github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 - github.com/hokaccha/go-prettyjson v0.0.0-20170213120834-e6b9231a2b1c // indirect + github.com/google/go-cmp v0.5.8 + github.com/google/uuid v1.3.0 + github.com/hashicorp/go-uuid v1.0.3 + github.com/hashicorp/go-version v1.6.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.16.0 github.com/jinzhu/copier v0.3.2 github.com/minsikl/netscaler-nitro-go v0.0.0-20170827154432-5b14ce3643e3 github.com/mitchellh/go-homedir v1.1.0 github.com/softlayer/softlayer-go v1.0.3 - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 - golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect - golang.org/x/tools v0.1.7 // indirect - google.golang.org/api v0.34.0 // indirect + go.mongodb.org/mongo-driver v1.10.2 // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d gotest.tools v2.2.0+incompatible + k8s.io/api v0.25.0 + k8s.io/apimachinery v0.25.0 + k8s.io/client-go v0.25.0 +) + +require ( + github.com/IBM/go-sdk-core/v3 v3.2.4 // indirect + github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect + github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/agext/levenshtein v1.2.2 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/eapache/go-resiliency v1.2.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/analysis v0.21.2 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/loads v0.21.1 // indirect + github.com/go-openapi/runtime v0.23.0 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/go-openapi/validate v0.20.3 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-test/deep v1.0.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-checkpoint v0.5.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect + github.com/hashicorp/go-hclog v1.2.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.3 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect + github.com/hashicorp/hc-install v0.3.2 // indirect + github.com/hashicorp/hcl/v2 v2.12.0 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect + github.com/hashicorp/terraform-exec v0.16.1 // indirect + github.com/hashicorp/terraform-json v0.13.0 // indirect + github.com/hashicorp/terraform-plugin-go v0.9.0 // indirect + github.com/hashicorp/terraform-plugin-log v0.4.0 // indirect + github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect + github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect + github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/hokaccha/go-prettyjson v0.0.0-20170213120834-e6b9231a2b1c // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.4 // indirect + github.com/mattn/go-isatty v0.0.11 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nicksnyder/go-i18n v1.10.0 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pelletier/go-toml v1.7.0 // indirect + github.com/pierrec/lz4 v2.6.0+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect + github.com/vmihailenco/tagparser v0.1.1 // indirect + github.com/zclconf/go-cty v1.10.0 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 // indirect + google.golang.org/grpc v1.45.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/go-playground/validator.v9 v9.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog/v2 v2.70.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) replace github.com/softlayer/softlayer-go v1.0.3 => github.com/IBM-Cloud/softlayer-go v1.0.5-tf diff --git a/go.sum b/go.sum index 62d2acf37..2cdd8163a 100644 --- a/go.sum +++ b/go.sum @@ -11,9 +11,7 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.61.0/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -31,80 +29,82 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/IBM-Cloud/bluemix-go v0.0.0-20211005115032-00ba77f0db57 h1:TTNIFMCfTO30MLvEpkhcDM9MTLHuBNz0//DnVTVX3JY= -github.com/IBM-Cloud/bluemix-go v0.0.0-20211005115032-00ba77f0db57/go.mod h1:q0fXFSbum/16D8Mgn1ROSfSyX4BmvBCm/hHdcXz0wCU= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62 h1:MOkcr6qQGk4tY542ZJ1DggVh2WUP72EEyLB79llFVH8= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= +github.com/IBM-Cloud/bluemix-go v0.0.0-20220523145737-34645883de47 h1:lpClRYyGuSXX4m3PRO2fruDQiesshUrObgbnPi+Xbxk= +github.com/IBM-Cloud/bluemix-go v0.0.0-20220523145737-34645883de47/go.mod h1:tfNN3lCKuA2+SQvndt0+5CjPr2qn/wdNLjrue1GrOhY= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20220922071204-21813161c36f h1:VMMqaAUXrNQH84ba/EDbfe8lvQJF9FBUnaQbIa1iKZ0= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20220922071204-21813161c36f/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= -github.com/IBM-Cloud/power-go-client v1.0.74 h1:11FvAa/tcdJnatj7eLb5kjUSvd5u5vVj2jg7vtkjgH4= -github.com/IBM-Cloud/power-go-client v1.0.74/go.mod h1:I4r5tCrA8mV5GFqGAJG4/Tn+/JpR+XLnDCLLNVKJxuI= +github.com/IBM-Cloud/power-go-client v1.2.1 h1:21z0hxZLgM9npv6u2IvKCHxhfbwxQM/q8ULV+pua5Sk= +github.com/IBM-Cloud/power-go-client v1.2.1/go.mod h1:Qfx0fNi+9hms+xu9Z6Euhu9088ByW6C/TCMLECTRWNE= github.com/IBM-Cloud/softlayer-go v1.0.5-tf h1:koUAyF9b6X78lLLruGYPSOmrfY2YcGYKOj/Ug9nbKNw= github.com/IBM-Cloud/softlayer-go v1.0.5-tf/go.mod h1:6HepcfAXROz0Rf63krk5hPZyHT6qyx2MNvYyHof7ik4= github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca h1:crniVcf+YcmgF03NmmfonXwSQ73oJF+IohFYBwknMxs= github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca/go.mod h1:IjXrnOcTe92Q4pEBHmui3H/GM1hw5Pd0zXA5cw5/iZU= -github.com/IBM/appconfiguration-go-admin-sdk v0.1.0 h1:9rdOk32VQFnMqsBB7cTpkZbD7/b0EnwrU3VNN8vuUYc= -github.com/IBM/appconfiguration-go-admin-sdk v0.1.0/go.mod h1:6x6KbqIwrEi07OvEM1+EnU4Lyk+JFm2O0vrSPPGTleU= +github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 h1:OqFxnDxro0JiRwHBKytCcseY2YKD4n87JN1UcaOD4Ss= +github.com/IBM/appconfiguration-go-admin-sdk v0.3.0/go.mod h1:xPxAYhr/uywUIDEo/JqWbkUdTryPdzRdYBfUpA5IjoE= github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f h1:4c1kqY4GqmkQ+tO03rneDb74Tv7BhTj8jDiDB1p8mdM= github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f/go.mod h1:d22kTYY7RYBWcQlZpqrSdshpB/lJ16viWS5Sbjtlc8s= -github.com/IBM/cloudant-go-sdk v0.0.36 h1:h14ORyRs2pi2RtuqOGB+y9gWytRfQKnne2lMhl2MCws= -github.com/IBM/cloudant-go-sdk v0.0.36/go.mod h1:04hA+Ok9aLYvnMEG4dMHTzU1W5b5tnl+Ddkdz4Z+xGs= -github.com/IBM/container-registry-go-sdk v0.0.13 h1:nifb9L0dpMaECkZy7MsNvXaH8vxRW2ARBRbF8cV7S5g= -github.com/IBM/container-registry-go-sdk v0.0.13/go.mod h1:GYi1VN59VaJWWq2xP06o9Vpi6+K8V5vtmji6WjMJf0w= -github.com/IBM/event-notifications-go-admin-sdk v0.0.2 h1:53guiGbjLcrO26NhPv+Xf0Sbgn/DPlfPwek9s6YlIg8= -github.com/IBM/event-notifications-go-admin-sdk v0.0.2/go.mod h1:VCtV/cAN8qSPeWEjIWeXOQGTq6LCWP9yZEk7wt3g0HM= +github.com/IBM/cloud-databases-go-sdk v0.2.0 h1:OkyYpj1LjUnBEgAkp5LMYyla40keEg4ZzWdEXAig4nk= +github.com/IBM/cloud-databases-go-sdk v0.2.0/go.mod h1:ZOujnMABgw39Mr/5sFd16eniw9mSS4/if1Vht3m+F4M= +github.com/IBM/cloudant-go-sdk v0.0.43 h1:YxTy4RpAEezX32YIWnds76hrBREmO4u6IkBz1WylNuQ= +github.com/IBM/cloudant-go-sdk v0.0.43/go.mod h1:WeYrJPaHTw19943ndWnVfwMIlZ5z0XUM2uEXNBrwZ1M= +github.com/IBM/container-registry-go-sdk v0.0.15 h1:sfEXm4qNj9ZCwTlFOsdjF5P/lvajU/Sc22yNlzg0F9I= +github.com/IBM/container-registry-go-sdk v0.0.15/go.mod h1:KqSZFO4VIK9QAyF8O1JW6jkyzkfE/BNKUIo+OdzIDk4= +github.com/IBM/continuous-delivery-go-sdk v0.1.2 h1:2GKFSXzlUUrLvJ6xgUDkm7kE4jWOu/fDwKfZl3Hvat4= +github.com/IBM/continuous-delivery-go-sdk v0.1.2/go.mod h1:u63XH83hLREOAeGs+/nbe3BEn21udFP9dddryP24OGM= +github.com/IBM/event-notifications-go-admin-sdk v0.1.2 h1:LLA12WFqSD0+Uf16SNdErcu2MVK4EnyXHJmDIkKkudE= +github.com/IBM/event-notifications-go-admin-sdk v0.1.2/go.mod h1:VCtV/cAN8qSPeWEjIWeXOQGTq6LCWP9yZEk7wt3g0HM= github.com/IBM/eventstreams-go-sdk v1.2.0 h1:eP0afHArMGjwhGqvZAhhu/3EDKRch2JehpveqF1TUjs= github.com/IBM/eventstreams-go-sdk v1.2.0/go.mod h1:2tuAxaYLctfqfr5jvyqSrxxEQGMwYPm3yJGWSj85YVQ= -github.com/IBM/go-sdk-core v1.1.0 h1:pV73lZqr9r1xKb3h08c1uNG3AphwoV5KzUzhS+pfEqY= -github.com/IBM/go-sdk-core v1.1.0/go.mod h1:2pcx9YWsIsZ3I7kH+1amiAkXvLTZtAq9kbxsfXilSoY= github.com/IBM/go-sdk-core/v3 v3.0.0/go.mod h1:JI5NS2+iCoY/D8Oq3JNEZNA7qO42agu6fnaUmDsRcJA= github.com/IBM/go-sdk-core/v3 v3.2.4 h1:WKYJYYKlZnw1y/gM+Qbf5EQVAL9xaoD54+ooJZz/iBQ= github.com/IBM/go-sdk-core/v3 v3.2.4/go.mod h1:lk9eOzNbNltPf3CBpcg1Ewkhw4qC3u2QCCKDRsUA2M0= -github.com/IBM/go-sdk-core/v4 v4.8.1/go.mod h1:GECJ/p0r9Hs0XcOnCiGjZrt6M/rQc+gW8YkCsGJ+j5U= -github.com/IBM/go-sdk-core/v4 v4.9.0/go.mod h1:DbQ+3pFoIjxGGTEiA9zQ2V0cemMNmFMkLBBnR729HKg= -github.com/IBM/go-sdk-core/v4 v4.10.0 h1:aLoKusSFVsxMJeKHf8csj9tBWt4Y50kVvfxoKh6scN0= -github.com/IBM/go-sdk-core/v4 v4.10.0/go.mod h1:0uz2ca0MZ2DwsBRGl9Jp3EaCTqxmKZTdvV/CkCB7JnI= github.com/IBM/go-sdk-core/v5 v5.0.0/go.mod h1:vyNdbFujJtdTj9HbihtvKwwS3k/GKSKpOx9ZIQ6MWDY= -github.com/IBM/go-sdk-core/v5 v5.0.3/go.mod h1:vyNdbFujJtdTj9HbihtvKwwS3k/GKSKpOx9ZIQ6MWDY= github.com/IBM/go-sdk-core/v5 v5.1.0/go.mod h1:vyNdbFujJtdTj9HbihtvKwwS3k/GKSKpOx9ZIQ6MWDY= -github.com/IBM/go-sdk-core/v5 v5.4.5/go.mod h1:Sn+z+qTDREQvCr+UFa22TqqfXNxx3o723y8GsfLV8e0= github.com/IBM/go-sdk-core/v5 v5.5.1/go.mod h1:Sn+z+qTDREQvCr+UFa22TqqfXNxx3o723y8GsfLV8e0= github.com/IBM/go-sdk-core/v5 v5.6.3/go.mod h1:tt/B9rxLkRtglE7pvqLuYikgCXaZFL3btdruJaoUeek= -github.com/IBM/go-sdk-core/v5 v5.6.5 h1:zXlt5x/udqZTD617SKUQzPDON4x5y0+22vNxsdCGYpg= github.com/IBM/go-sdk-core/v5 v5.6.5/go.mod h1:tt/B9rxLkRtglE7pvqLuYikgCXaZFL3btdruJaoUeek= +github.com/IBM/go-sdk-core/v5 v5.7.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc= +github.com/IBM/go-sdk-core/v5 v5.8.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc= +github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= +github.com/IBM/go-sdk-core/v5 v5.9.5/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= +github.com/IBM/go-sdk-core/v5 v5.10.1/go.mod h1:u/33BzPy8sthgEhSeBnf6/kPCqwvC9VKw5byfqQfbe0= +github.com/IBM/go-sdk-core/v5 v5.10.2 h1:bfqhYNwwpJ3zJQSYpF3umhmRIKaa762itvJkTAWCCLU= +github.com/IBM/go-sdk-core/v5 v5.10.2/go.mod h1:WZPFasUzsKab/2mzt29xPcfruSk5js2ywAPwW4VJjdI= github.com/IBM/ibm-cos-sdk-go v1.3.1/go.mod h1:YLBAYobEA8bD27P7xpMwSQeNQu6W3DNBtBComXrRzRY= -github.com/IBM/ibm-cos-sdk-go v1.7.0 h1:3DZULY/D5WzjlIm+Iaj6h0surEjQs65EZk1YAe8+rj0= -github.com/IBM/ibm-cos-sdk-go v1.7.0/go.mod h1:Oi8AC5WNDhmUJgbo1GL2FtBdo0nRgbzE/1HmCL1SERU= +github.com/IBM/ibm-cos-sdk-go v1.9.0 h1:kXTLB9GBwks3+YZopYz/eRbdyeVl2BXFALeqtQ8Duoc= +github.com/IBM/ibm-cos-sdk-go v1.9.0/go.mod h1:Oi8AC5WNDhmUJgbo1GL2FtBdo0nRgbzE/1HmCL1SERU= github.com/IBM/ibm-cos-sdk-go-config v1.2.0 h1:1E93234yZgVS0ntm7eUwVb3h0AAayPGcxEhhizEN1LE= github.com/IBM/ibm-cos-sdk-go-config v1.2.0/go.mod h1:Wetfgv6m1xyuzpZLQTTLIBsWstxjYa15h+Utj7x53Dk= -github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20210723145459-a232c3f3ac91 h1:8ICDvg7YM+PmfF+LQ42D4w/p4QEpiknbycAgGdbk0dw= -github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20210723145459-a232c3f3ac91/go.mod h1:M2JyuyeWHPtgGNeezr6YqVRuaav2MpY8Ha4QrEYvMoI= +github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 h1:T5UwRKKd+BoaPZ7UIlpJrzXzVTUEs8HcxwQ3pCIbORs= +github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1/go.mod h1:M2JyuyeWHPtgGNeezr6YqVRuaav2MpY8Ha4QrEYvMoI= +github.com/IBM/ibm-hpcs-uko-sdk v0.0.4 h1:B3FEq830k/B7HjQqvQubxmz8PxOUvKYD2ZypDq3FD7k= +github.com/IBM/ibm-hpcs-uko-sdk v0.0.4/go.mod h1:MLVNHMYoKsvovJZ4v1gQCpIYtRDHTtoIHK6XztDZGsU= github.com/IBM/keyprotect-go-client v0.7.0 h1:JstSHD14Lp6ihwQseyPuGcs1AjOBjAmcisP0dTBA6A0= github.com/IBM/keyprotect-go-client v0.7.0/go.mod h1:SVr2ylV/fhSQPDiUjWirN9fsyWFCNNbt8GIT8hPJVjE= -github.com/IBM/networking-go-sdk v0.23.0 h1:11ud+f0P6SMRuZ/JprGl1H+TqCwDvjpciQVS6xNU77o= -github.com/IBM/networking-go-sdk v0.23.0/go.mod h1:nViqUm1Bv+ke8dyOhjQ6e+2U1XeqZX2y4bQbR8Od3Hc= -github.com/IBM/platform-services-go-sdk v0.20.1 h1:s708Cqd4FiIbJOLXkcdhdVbvpYebvUlv+xZJH94jDaU= -github.com/IBM/platform-services-go-sdk v0.20.1/go.mod h1:mKtwiSvf5s2nyaSvcG+GNphun5pmiABcnsPjXzkC0OE= +github.com/IBM/networking-go-sdk v0.34.0 h1:E8H+v8ipie3vk9w+jvNm8TBeVNrUhqUAKWQOYw9POEc= +github.com/IBM/networking-go-sdk v0.34.0/go.mod h1:tDJtlySQC/txyejU9KeQ27Amc6xKH0MwHFE/B2+Sn5w= +github.com/IBM/platform-services-go-sdk v0.28.5 h1:wVwapdVU3+J/JtS0P6WYi21gqsm1pX/MH4UX69c3+5E= +github.com/IBM/platform-services-go-sdk v0.28.5/go.mod h1:jy0Ahvj5Gkkua3Gd7t22bo0GfmHRQaPZcaqwfVgEY7k= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 h1:NPUhkoOCRuv3OFWt19PmwjXGGTKlvmbuPg9fUrBUNe4= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5/go.mod h1:b07XHUVh0XYnQE9s2mqgjYST1h9buaQNqN4EcKhOsX0= -github.com/IBM/scc-go-sdk v1.2.0 h1:fYh9Mviiul/96/fFSsLnsXD87smHrkmoOUq8FwYNsr8= -github.com/IBM/scc-go-sdk v1.2.0/go.mod h1:xMmAdp8B4Gh/jyJZG2qnIE8jE0KJi/QufOX1lWHcCeE= -github.com/IBM/schematics-go-sdk v0.0.2 h1:IFdM73VL3xwf/KaTh1IY99hkiTfFRYg5F1JNj69FOEg= -github.com/IBM/schematics-go-sdk v0.0.2/go.mod h1:ymN1+3uEaWNT0RthwHzExxMiN0AnTh6W3piSY8canjs= +github.com/IBM/scc-go-sdk/v3 v3.1.6 h1:wg7yujuJJ1O1pcGrIn8ITq6i6GeXb7GRBPNq6kLrkMU= +github.com/IBM/scc-go-sdk/v3 v3.1.6/go.mod h1:cBxkth9AIOcKQx4Gy9bWgyGYa7vYwHAalUBvY+O8xAE= +github.com/IBM/scc-go-sdk/v4 v4.0.0 h1:Fes2/SVzhrNkD8U12W75MQeOzAZmhSPJHmq6+Txsn4A= +github.com/IBM/scc-go-sdk/v4 v4.0.0/go.mod h1:ufqf/kBtRn3Pq/pFXF6zQGHXV2P2EzPsntw1Sw19clE= +github.com/IBM/schematics-go-sdk v0.2.1 h1:byATysGD+Z1k/wdtNqQmKALcAPjgSLuSyzcabh1jRAw= +github.com/IBM/schematics-go-sdk v0.2.1/go.mod h1:Tw2OSAPdpC69AxcwoyqcYYaGTTW6YpERF9uNEU+BFRQ= github.com/IBM/secrets-manager-go-sdk v0.1.19 h1:0GPs5EoTaWNsjo4QPj64GNxlWfN8VHJy4RDFLqddSe8= github.com/IBM/secrets-manager-go-sdk v0.1.19/go.mod h1:eO3dBhzPrHkkt+yPex/jB2xD6qHZxBko+Aw+0tfqHeA= -github.com/IBM/vpc-go-sdk v0.12.0 h1:tOuEveEJOEjNhLcRxTOG/w5mf0e59fqJVwSysq2oSx8= -github.com/IBM/vpc-go-sdk v0.12.0/go.mod h1:B3Pgkwb0tQqTeIojR1MFLp96qW7cKnWyJ74jbAJgdbk= +github.com/IBM/vpc-go-sdk v0.27.0 h1:PBpgjh5bjxrMT5BlaHfyaiJ/71pvycbmVQMuPOQ33ZY= +github.com/IBM/vpc-go-sdk v0.27.0/go.mod h1:jYjS3EySPkC7DuOg33gMHtm8DcIf75Tc+Gxo3zmMBTQ= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:vuquMR410psHNax14XKNWa0Ae/kYgWJcXi0IFuX60N0= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56/go.mod h1:Zb3OT4l0mf7P/GOs2w2Ilj5sdm5Whoq3pa24dAEBHFc= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= @@ -129,24 +129,21 @@ github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105 h1:k1wP1gZMrNJeXTz6a+3010NKC/ZvSffk07BzrLmYrmc= github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105/go.mod h1:jLLKYP7+1+LFlIJW1n9U1gqeveLM1HIwa4ZHNOFxjPw= -github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= -github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -155,16 +152,9 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:o github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk= -github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -172,6 +162,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -181,24 +176,29 @@ github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFn github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/form3tech-oss/jwt-go v3.2.1+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -215,15 +215,22 @@ github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -231,8 +238,11 @@ github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9sn github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= -github.com/go-openapi/analysis v0.19.16 h1:Ub9e++M8sDwtHD+S587TYi+6ANBG1NRYGZDihqk0SaY= github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= +github.com/go-openapi/analysis v0.20.0/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= +github.com/go-openapi/analysis v0.20.1/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= +github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= @@ -241,8 +251,11 @@ github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.0 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM= github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -253,27 +266,30 @@ github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= -github.com/go-openapi/loads v0.20.0 h1:Pymw1O8zDmWeNv4kVsHd0W3cvgdp8juRa4U/U/8D/Pk= github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= +github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vYP2bQYKA/o= +github.com/go-openapi/loads v0.21.0/go.mod h1:rHYve9nZrQ4CJhyeIIFJINGCg1tQpx2yJrrNo8sf1ws= +github.com/go-openapi/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/runtime v0.19.11/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= -github.com/go-openapi/runtime v0.19.24 h1:TqagMVlRAOTwllE/7hNKx6rQ10O6T8ZzeJdMjSTKaD4= github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= +github.com/go-openapi/runtime v0.23.0 h1:HX6ET2sHCIvaKeDDQoU01CtO1ekg5EkekHSkLTtWXH0= +github.com/go-openapi/runtime v0.23.0/go.mod h1:aQg+kaIQEn+A2CRSY1TxbM8+sT9g2V3aLc1FbIAnbbs= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= @@ -281,8 +297,11 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= -github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I= github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ= +github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= @@ -290,38 +309,46 @@ github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6 github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/strfmt v0.19.8/go.mod h1:qBBipho+3EoIqn6YDI+4RnQEtj6jT/IdKm+PAlXxSUc= github.com/go-openapi/strfmt v0.19.10/go.mod h1:qBBipho+3EoIqn6YDI+4RnQEtj6jT/IdKm+PAlXxSUc= github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= github.com/go-openapi/strfmt v0.20.1/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk= -github.com/go-openapi/strfmt v0.20.2 h1:6XZL+fF4VZYFxKQGLAUB358hOrRh/wS51uWEtlONADE= github.com/go-openapi/strfmt v0.20.2/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI= github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= +github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= -github.com/go-openapi/validate v0.19.6/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= -github.com/go-openapi/validate v0.20.1 h1:QGQ5CvK74E28t3DkegGweKR+auemUi5IdpMc4x3UW6s= github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= +github.com/go-openapi/validate v0.20.3 h1:GZPPhhKSZrE8HjB4eEkoYAZmoWA4+tCemSgINH1/vKw= +github.com/go-openapi/validate v0.20.3/go.mod h1:goDdqVGiigM3jChcrYJxD2joalke3ZXeftD16byIjA4= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -351,6 +378,8 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -358,7 +387,6 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -381,6 +409,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -389,6 +418,8 @@ github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -399,13 +430,15 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -414,17 +447,20 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -437,55 +473,58 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-getter v1.5.3 h1:NF5+zOlQegim+w/EUhSLh6QhXHmZMEeHLQzllkQ3ROU= -github.com/hashicorp/go-getter v1.5.3/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.15.0 h1:qMuK0wxsoW4D0ddCCYwPSTm4KQv1X1ke3WmPWZ0Mvsk= -github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= -github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= -github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= +github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= -github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= -github.com/hashicorp/hcl/v2 v2.8.2 h1:wmFle3D1vu0okesm8BTLVDyJ6/OL9DCLUwn0b2OptiY= -github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= +github.com/hashicorp/hc-install v0.3.2 h1:oiQdJZvXmkNcRcEOOfM5n+VTsvNjWQeOjfAoO6dKSH8= +github.com/hashicorp/hc-install v0.3.2/go.mod h1:xMG6Tr8Fw1WFjlxH0A9v61cW15pFwgEGqEz0V4jisHs= +github.com/hashicorp/hcl/v2 v2.12.0 h1:PsYxySWpMD4KPaoJLnsHwtK5Qptvj/4Q6s0t4sUxZf4= +github.com/hashicorp/hcl/v2 v2.12.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.14.0 h1:UQoUcxKTZZXhyyK68Cwn4mApT4mnFPmEXPiqaHL9r+w= -github.com/hashicorp/terraform-exec v0.14.0/go.mod h1:qrAASDq28KZiMPDnQ02sFS9udcqEkRly002EA2izXTA= -github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQAwYYLETaTvw= -github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= -github.com/hashicorp/terraform-plugin-go v0.3.0 h1:AJqYzP52JFYl9NABRI7smXI1pNjgR5Q/y2WyVJ/BOZA= -github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 h1:SuI59MqNjYDrL7EfqHX9V6P/24isgqYx/FdglwVs9bg= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= +github.com/hashicorp/terraform-exec v0.16.1 h1:NAwZFJW2L2SaCBVZoVaH8LPImLOGbPLkSHy0IYbs2uE= +github.com/hashicorp/terraform-exec v0.16.1/go.mod h1:aj0lVshy8l+MHhFNoijNHtqTJQI3Xlowv5EOsEaGO7M= +github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY= +github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= +github.com/hashicorp/terraform-plugin-go v0.9.0 h1:FvLY/3z4SNVatPZdoFcyrlNbCar+WyyOTv5X4Tp+WZc= +github.com/hashicorp/terraform-plugin-go v0.9.0/go.mod h1:EawBkgjBWNf7jiKnVoyDyF39OSV+u6KUX+Y73EPj3oM= +github.com/hashicorp/terraform-plugin-log v0.4.0 h1:F3eVnm8r2EfQCe2k9blPIiF/r2TT01SHijXnS7bujvc= +github.com/hashicorp/terraform-plugin-log v0.4.0/go.mod h1:9KclxdunFownr4pIm1jdmwKRmE4d6HVG2c9XDq47rpg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.16.0 h1:9fjPgCenJqnbjo95SDcbJ+YdLyEC1N35cwKWcRWhJTQ= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.16.0/go.mod h1:hLa0sTiySU/AWEgV2GxJh0/pQIqcCmm30IPja9N9lTg= +github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 h1:1FGtlkJw87UsTMg5s8jrekrHmUPUJaMcu6ELiVhQrNw= +github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896/go.mod h1:bzBPnUIkI0RxauU8Dqo+2KrZZ28Cf48s8V6IHt3p4co= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hokaccha/go-prettyjson v0.0.0-20170213120834-e6b9231a2b1c h1:vlXZsaTgJ55QZrAkOrpq0tsJmuuM4ky5OMZOvXnhvqE= github.com/hokaccha/go-prettyjson v0.0.0-20170213120834-e6b9231a2b1c/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -505,37 +544,43 @@ github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJz github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/johnstarich/go/gopages v0.1.8/go.mod h1:OaSRjfHdFfN+LS7u6xqgNO7C2Uxjlvpm17DcKcvLBhY= +github.com/johnstarich/go/pipe v0.2.0/go.mod h1:3X9IdVJJnI7pkpzEH6np98wqHl55zFmbilKG+9+koMo= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -545,7 +590,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -553,37 +597,29 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/minsikl/netscaler-nitro-go v0.0.0-20170827154432-5b14ce3643e3 h1:PHPBYVeLuR7/2XSOfVwDpW+70KNuxMWygsyOZSKK15Y= github.com/minsikl/netscaler-nitro-go v0.0.0-20170827154432-5b14ce3643e3/go.mod h1:jh28TRFZwBumf7OjMQbRb8TNtDuuX7QNAGRjFEt+h6I= -github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= -github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= @@ -591,18 +627,26 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo96+Q= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= -github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -616,23 +660,34 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.0/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -641,10 +696,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -653,42 +708,51 @@ github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdk github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= @@ -698,29 +762,35 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.8.4 h1:pwhhz5P+Fjxse7S7UriBrMu6AUJSZM5pKqGem1PjGAs= -github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.9.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= -go.mongodb.org/mongo-driver v1.7.0 h1:hHrvOBWlWB2c7+8Gh/Xi5jj82AgidK/t7KVXBZ+IyUA= go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.10.2 h1:4Wk3cnqOrQCn0P92L3/mmurMxzdvWWs5J9jinAVKD+k= +go.mongodb.org/mongo-driver v1.10.2/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -737,13 +807,14 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -765,7 +836,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -775,8 +845,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -796,6 +865,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -816,19 +886,27 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -844,6 +922,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -883,20 +962,27 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs= -golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -904,11 +990,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -955,18 +1044,17 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201021000207-d49c4edd7d96/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -984,15 +1072,14 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.34.0 h1:k40adF3uR+6x/+hO5Dh4ZFUqFp67vxvbpafFiJxl10A= -google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1017,15 +1104,15 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d h1:92D1fum1bJLKSdr11OJ+54YeCMCGYIygTA7R/YZxH5M= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1039,9 +1126,10 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1053,15 +1141,15 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= @@ -1071,12 +1159,15 @@ gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+a gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1085,8 +1176,9 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1096,6 +1188,25 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0= +k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk= +k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= +k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go new file mode 100644 index 000000000..3c16d71a0 --- /dev/null +++ b/ibm/acctest/acctest.go @@ -0,0 +1,1142 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package acctest + +import ( + "fmt" + "os" + "strconv" + "testing" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/provider" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var AppIDTenantID string +var AppIDTestUserEmail string +var CfOrganization string +var CfSpace string +var CisDomainStatic string +var CisDomainTest string +var CisInstance string +var CisResourceGroup string +var CloudShellAccountID string +var CosCRN string +var Ibmid1 string +var Ibmid2 string +var IAMUser string +var Datacenter string +var MachineType string +var trustedMachineType string +var PublicVlanID string +var PrivateVlanID string +var PrivateSubnetID string +var PublicSubnetID string +var SubnetID string +var LbaasDatacenter string +var LbaasSubnetId string +var LbListerenerCertificateInstance string +var IpsecDatacenter string +var Customersubnetid string +var Customerpeerip string +var DedicatedHostName string +var DedicatedHostID string +var KubeVersion string +var KubeUpdateVersion string +var Zone string +var ZonePrivateVlan string +var ZonePublicVlan string +var ZoneUpdatePrivateVlan string +var ZoneUpdatePublicVlan string +var CsRegion string +var ExtendedHardwareTesting bool +var err error +var placementGroupName string +var CertCRN string +var UpdatedCertCRN string +var RegionName string +var ISZoneName string +var ISZoneName2 string +var ISCIDR string +var ISCIDR2 string +var ISAddressPrefixCIDR string +var InstanceName string +var InstanceProfileName string +var InstanceProfileNameUpdate string +var IsBareMetalServerProfileName string +var IsBareMetalServerImage string +var DedicatedHostProfileName string +var DedicatedHostGroupID string +var InstanceDiskProfileName string +var DedicatedHostGroupFamily string +var DedicatedHostGroupClass string +var VolumeProfileName string +var ISRouteDestination string +var ISRouteNextHop string +var WorkspaceID string +var TemplateID string +var ActionID string +var JobID string +var RepoURL string +var RepoBranch string +var imageName string +var functionNamespace string +var HpcsInstanceID string +var SecretsManagerInstanceID string +var SecretsManagerSecretType string +var SecretsManagerSecretID string +var HpcsAdmin1 string +var HpcsToken1 string +var HpcsAdmin2 string +var HpcsToken2 string +var HpcsRootKeyCrn string +var RealmName string +var IksSa string +var IksClusterID string +var IksClusterVpcID string +var IksClusterSubnetID string +var IksClusterResourceGroupID string +var IcdDbRegion string +var IcdDbDeploymentId string +var IcdDbBackupId string +var IcdDbTaskId string +var KmsInstanceID string +var CrkID string + +// For Power Colo + +var Pi_image string +var Pi_sap_image string +var Pi_image_bucket_name string +var Pi_image_bucket_file_name string +var Pi_image_bucket_access_key string +var Pi_image_bucket_secret_key string +var Pi_image_bucket_region string +var Pi_key_name string +var Pi_volume_name string +var Pi_network_name string +var Pi_cloud_instance_id string +var Pi_instance_name string +var Pi_dhcp_id string +var PiCloudConnectionName string +var PiSAPProfileID string +var Pi_placement_group_name string +var Pi_spp_placement_group_id string +var PiStoragePool string +var PiStorageType string +var Pi_shared_processor_pool_id string + +var Pi_capture_storage_image_path string +var Pi_capture_cloud_storage_access_key string +var Pi_capture_cloud_storage_secret_key string + +// For Image + +var IsImageName string +var IsImage string +var IsImageEncryptedDataKey string +var IsImageEncryptionKey string +var IsWinImage string +var Image_cos_url string +var Image_cos_url_encrypted string +var Image_operating_system string + +// Transit Gateway cross account +var Tg_cross_network_account_id string +var Tg_cross_network_id string + +// Enterprise Management +var Account_to_be_imported string + +// Secuity and Complinace Center, Governance +var Scc_gov_account_id string +var Scc_resource_group_id string + +// Security and Compliance Center, SI +var Scc_si_account string + +// Security and Compliance Center, Posture Management +var Scc_posture_scope_id string +var Scc_posture_scan_id string +var Scc_posture_profile_id string +var Scc_posture_group_profile_id string +var Scc_posture_correlation_id string +var Scc_posture_report_setting_id string +var Scc_posture_profile_id_scansummary string +var Scc_posture_scan_id_scansummary string +var Scc_posture_credential_id_scope string +var Scc_posture_credential_id_scope_update string +var Scc_posture_collector_id_scope []string +var Scc_posture_collector_id_scope_update []string +var Scc_posture_collector_id string +var Scc_posture_credential_id string + +// ROKS Cluster +var ClusterName string + +// Satellite instance +var Satellite_location_id string +var Satellite_Resource_instance_id string + +// Dedicated host +var HostPoolID string + +// Continuous Delivery +var CdResourceGroupID string + +// VPN Server +var ISCertificateCrn string +var ISClientCaCrn string + +// COS Replication Bucket +var IBM_AccountID_REPL string + +func init() { + testlogger := os.Getenv("TF_LOG") + if testlogger != "" { + os.Setenv("IBMCLOUD_BLUEMIX_GO_TRACE", "true") + } + + AppIDTenantID = os.Getenv("IBM_APPID_TENANT_ID") + if AppIDTenantID == "" { + fmt.Println("[WARN] Set the environment variable IBM_APPID_TENANT_ID for testing AppID resources, AppID tests will fail if this is not set") + } + + AppIDTestUserEmail = os.Getenv("IBM_APPID_TEST_USER_EMAIL") + if AppIDTestUserEmail == "" { + fmt.Println("[WARN] Set the environment variable IBM_APPID_TEST_USER_EMAIL for testing AppID user resources, the tests will fail if this is not set") + } + + CfOrganization = os.Getenv("IBM_ORG") + if CfOrganization == "" { + fmt.Println("[WARN] Set the environment variable IBM_ORG for testing ibm_org resource Some tests for that resource will fail if this is not set correctly") + } + CfSpace = os.Getenv("IBM_SPACE") + if CfSpace == "" { + fmt.Println("[WARN] Set the environment variable IBM_SPACE for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") + } + Ibmid1 = os.Getenv("IBM_ID1") + if Ibmid1 == "" { + fmt.Println("[WARN] Set the environment variable IBM_ID1 for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") + } + + Ibmid2 = os.Getenv("IBM_ID2") + if Ibmid2 == "" { + fmt.Println("[WARN] Set the environment variable IBM_ID2 for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") + } + + IAMUser = os.Getenv("IBM_IAMUSER") + if IAMUser == "" { + fmt.Println("[WARN] Set the environment variable IBM_IAMUSER for testing ibm_iam_user_policy resource Some tests for that resource will fail if this is not set correctly") + } + + Datacenter = os.Getenv("IBM_DATACENTER") + if Datacenter == "" { + Datacenter = "par01" + fmt.Println("[WARN] Set the environment variable IBM_DATACENTER for testing ibm_container_cluster resource else it is set to default value 'par01'") + } + MachineType = os.Getenv("IBM_MACHINE_TYPE") + if MachineType == "" { + MachineType = "b3c.4x16" + fmt.Println("[WARN] Set the environment variable IBM_MACHINE_TYPE for testing ibm_container_cluster resource else it is set to default value 'b3c.4x16'") + } + + CertCRN = os.Getenv("IBM_CERT_CRN") + if CertCRN == "" { + CertCRN = "crn:v1:bluemix:public:cloudcerts:us-south:a/52b2e14f385aca5da781baa1b9c28e53:6efac0c2-b955-49ca-939d-d7bc0cb8132f:certificate:e786b0ea2af8b5435603803ec2ff8118" + fmt.Println("[WARN] Set the environment variable IBM_CERT_CRN for testing ibm_container_alb_cert resource else it is set to default value") + } + + UpdatedCertCRN = os.Getenv("IBM_UPDATE_CERT_CRN") + if UpdatedCertCRN == "" { + UpdatedCertCRN = "crn:v1:bluemix:public:cloudcerts:eu-de:a/e9021a4d06e9b108b4a221a3cec47e3d:77e527aa-65b2-4cb3-969b-7e8714174346:certificate:1bf3d0c2b7764402dde25744218e6cba" + fmt.Println("[WARN] Set the environment variable IBM_UPDATE_CERT_CRN for testing ibm_container_alb_cert resource else it is set to default value") + } + + CsRegion = os.Getenv("IBM_CONTAINER_REGION") + if CsRegion == "" { + CsRegion = "eu-de" + fmt.Println("[WARN] Set the environment variable IBM_CONTAINER_REGION for testing ibm_container resources else it is set to default value 'eu-de'") + } + + CisInstance = os.Getenv("IBM_CIS_INSTANCE") + if CisInstance == "" { + CisInstance = "" + fmt.Println("[WARN] Set the environment variable IBM_CIS_INSTANCE with a VALID CIS Instance NAME for testing ibm_cis resources on staging/test") + } + CisDomainStatic = os.Getenv("IBM_CIS_DOMAIN_STATIC") + if CisDomainStatic == "" { + CisDomainStatic = "" + fmt.Println("[WARN] Set the environment variable IBM_CIS_DOMAIN_STATIC with the Domain name registered with the CIS instance on test/staging. Domain must be predefined in CIS to avoid CIS billing costs due to domain delete/create") + } + + CisDomainTest = os.Getenv("IBM_CIS_DOMAIN_TEST") + if CisDomainTest == "" { + CisDomainTest = "" + fmt.Println("[WARN] Set the environment variable IBM_CIS_DOMAIN_TEST with a VALID Domain name for testing the one time create and delete of a domain in CIS. Note each create/delete will trigger a monthly billing instance. Only to be run in staging/test") + } + + CisResourceGroup = os.Getenv("IBM_CIS_RESOURCE_GROUP") + if CisResourceGroup == "" { + CisResourceGroup = "" + fmt.Println("[WARN] Set the environment variable IBM_CIS_RESOURCE_GROUP with the resource group for the CIS Instance ") + } + + CosCRN = os.Getenv("IBM_COS_CRN") + if CosCRN == "" { + CosCRN = "" + fmt.Println("[WARN] Set the environment variable IBM_COS_CRN with a VALID COS instance CRN for testing ibm_cos_* resources") + } + + trustedMachineType = os.Getenv("IBM_TRUSTED_MACHINE_TYPE") + if trustedMachineType == "" { + trustedMachineType = "mb1c.16x64" + fmt.Println("[WARN] Set the environment variable IBM_TRUSTED_MACHINE_TYPE for testing ibm_container_cluster resource else it is set to default value 'mb1c.16x64'") + } + + ExtendedHardwareTesting, err = strconv.ParseBool(os.Getenv("IBM_BM_EXTENDED_HW_TESTING")) + if err != nil { + ExtendedHardwareTesting = false + fmt.Println("[WARN] Set the environment variable IBM_BM_EXTENDED_HW_TESTING to true/false for testing ibm_compute_bare_metal resource else it is set to default value 'false'") + } + + PublicVlanID = os.Getenv("IBM_PUBLIC_VLAN_ID") + if PublicVlanID == "" { + PublicVlanID = "2393319" + fmt.Println("[WARN] Set the environment variable IBM_PUBLIC_VLAN_ID for testing ibm_container_cluster resource else it is set to default value '2393319'") + } + + PrivateVlanID = os.Getenv("IBM_PRIVATE_VLAN_ID") + if PrivateVlanID == "" { + PrivateVlanID = "2393321" + fmt.Println("[WARN] Set the environment variable IBM_PRIVATE_VLAN_ID for testing ibm_container_cluster resource else it is set to default value '2393321'") + } + + KubeVersion = os.Getenv("IBM_KUBE_VERSION") + if KubeVersion == "" { + KubeVersion = "1.18" + fmt.Println("[WARN] Set the environment variable IBM_KUBE_VERSION for testing ibm_container_cluster resource else it is set to default value '1.18.14'") + } + + KubeUpdateVersion = os.Getenv("IBM_KUBE_UPDATE_VERSION") + if KubeUpdateVersion == "" { + KubeUpdateVersion = "1.19" + fmt.Println("[WARN] Set the environment variable IBM_KUBE_UPDATE_VERSION for testing ibm_container_cluster resource else it is set to default value '1.19.6'") + } + + PrivateSubnetID = os.Getenv("IBM_PRIVATE_SUBNET_ID") + if PrivateSubnetID == "" { + PrivateSubnetID = "1636107" + fmt.Println("[WARN] Set the environment variable IBM_PRIVATE_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1636107'") + } + + PublicSubnetID = os.Getenv("IBM_PUBLIC_SUBNET_ID") + if PublicSubnetID == "" { + PublicSubnetID = "1165645" + fmt.Println("[WARN] Set the environment variable IBM_PUBLIC_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1165645'") + } + + SubnetID = os.Getenv("IBM_SUBNET_ID") + if SubnetID == "" { + SubnetID = "1165645" + fmt.Println("[WARN] Set the environment variable IBM_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1165645'") + } + + IpsecDatacenter = os.Getenv("IBM_IPSEC_DATACENTER") + if IpsecDatacenter == "" { + IpsecDatacenter = "tok02" + fmt.Println("[INFO] Set the environment variable IBM_IPSEC_DATACENTER for testing ibm_ipsec_vpn resource else it is set to default value 'tok02'") + } + + Customersubnetid = os.Getenv("IBM_IPSEC_CUSTOMER_SUBNET_ID") + if Customersubnetid == "" { + Customersubnetid = "123456" + fmt.Println("[INFO] Set the environment variable IBM_IPSEC_CUSTOMER_SUBNET_ID for testing ibm_ipsec_vpn resource else it is set to default value '123456'") + } + + Customerpeerip = os.Getenv("IBM_IPSEC_CUSTOMER_PEER_IP") + if Customerpeerip == "" { + Customerpeerip = "192.168.0.1" + fmt.Println("[INFO] Set the environment variable IBM_IPSEC_CUSTOMER_PEER_IP for testing ibm_ipsec_vpn resource else it is set to default value '192.168.0.1'") + } + + LbaasDatacenter = os.Getenv("IBM_LBAAS_DATACENTER") + if LbaasDatacenter == "" { + LbaasDatacenter = "dal13" + fmt.Println("[WARN] Set the environment variable IBM_LBAAS_DATACENTER for testing ibm_lbaas resource else it is set to default value 'dal13'") + } + + LbaasSubnetId = os.Getenv("IBM_LBAAS_SUBNETID") + if LbaasSubnetId == "" { + LbaasSubnetId = "2144241" + fmt.Println("[WARN] Set the environment variable IBM_LBAAS_SUBNETID for testing ibm_lbaas resource else it is set to default value '2144241'") + } + LbListerenerCertificateInstance = os.Getenv("IBM_LB_LISTENER_CERTIFICATE_INSTANCE") + if LbListerenerCertificateInstance == "" { + LbListerenerCertificateInstance = "crn:v1:staging:public:cloudcerts:us-south:a/2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" + fmt.Println("[WARN] Set the environment variable IBM_LB_LISTENER_CERTIFICATE_INSTANCE for testing ibm_is_lb_listener resource for https redirect else it is set to default value 'crn:v1:staging:public:cloudcerts:us-south:a/2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed'") + } + + DedicatedHostName = os.Getenv("IBM_DEDICATED_HOSTNAME") + if DedicatedHostName == "" { + DedicatedHostName = "terraform-dedicatedhost" + fmt.Println("[WARN] Set the environment variable IBM_DEDICATED_HOSTNAME for testing ibm_compute_vm_instance resource else it is set to default value 'terraform-dedicatedhost'") + } + + DedicatedHostID = os.Getenv("IBM_DEDICATED_HOST_ID") + if DedicatedHostID == "" { + DedicatedHostID = "30301" + fmt.Println("[WARN] Set the environment variable IBM_DEDICATED_HOST_ID for testing ibm_compute_vm_instance resource else it is set to default value '30301'") + } + + Zone = os.Getenv("IBM_WORKER_POOL_ZONE") + if Zone == "" { + Zone = "ams03" + fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value 'ams03'") + } + + ZonePrivateVlan = os.Getenv("IBM_WORKER_POOL_ZONE_PRIVATE_VLAN") + if ZonePrivateVlan == "" { + ZonePrivateVlan = "2538975" + fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_PRIVATE_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2538975'") + } + + ZonePublicVlan = os.Getenv("IBM_WORKER_POOL_ZONE_PUBLIC_VLAN") + if ZonePublicVlan == "" { + ZonePublicVlan = "2538967" + fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_PUBLIC_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2538967'") + } + + ZoneUpdatePrivateVlan = os.Getenv("IBM_WORKER_POOL_ZONE_UPDATE_PRIVATE_VLAN") + if ZoneUpdatePrivateVlan == "" { + ZoneUpdatePrivateVlan = "2388377" + fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_UPDATE_PRIVATE_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2388377'") + } + + ZoneUpdatePublicVlan = os.Getenv("IBM_WORKER_POOL_ZONE_UPDATE_PUBLIC_VLAN") + if ZoneUpdatePublicVlan == "" { + ZoneUpdatePublicVlan = "2388375" + fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_UPDATE_PUBLIC_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2388375'") + } + + placementGroupName = os.Getenv("IBM_PLACEMENT_GROUP_NAME") + if placementGroupName == "" { + placementGroupName = "terraform_group" + fmt.Println("[WARN] Set the environment variable IBM_PLACEMENT_GROUP_NAME for testing ibm_compute_vm_instance resource else it is set to default value 'terraform-group'") + } + + RegionName = os.Getenv("SL_REGION") + if RegionName == "" { + RegionName = "us-south" + fmt.Println("[INFO] Set the environment variable SL_REGION for testing ibm_is_region datasource else it is set to default value 'us-south'") + } + + ISZoneName = os.Getenv("SL_ZONE") + if ISZoneName == "" { + ISZoneName = "us-south-1" + fmt.Println("[INFO] Set the environment variable SL_ZONE for testing ibm_is_zone datasource else it is set to default value 'us-south-1'") + } + + ISZoneName2 = os.Getenv("SL_ZONE_2") + if ISZoneName2 == "" { + ISZoneName2 = "us-south-2" + fmt.Println("[INFO] Set the environment variable SL_ZONE_2 for testing ibm_is_zone datasource else it is set to default value 'us-south-2'") + } + + ISCIDR = os.Getenv("SL_CIDR") + if ISCIDR == "" { + ISCIDR = "10.240.0.0/24" + fmt.Println("[INFO] Set the environment variable SL_CIDR for testing ibm_is_subnet else it is set to default value '10.240.0.0/24'") + } + + ISCIDR2 = os.Getenv("SL_CIDR_2") + if ISCIDR2 == "" { + ISCIDR2 = "10.240.64.0/24" + fmt.Println("[INFO] Set the environment variable SL_CIDR_2 for testing ibm_is_subnet else it is set to default value '10.240.64.0/24'") + } + + ISAddressPrefixCIDR = os.Getenv("SL_ADDRESS_PREFIX_CIDR") + if ISAddressPrefixCIDR == "" { + ISAddressPrefixCIDR = "10.120.0.0/24" + fmt.Println("[INFO] Set the environment variable SL_ADDRESS_PREFIX_CIDR for testing ibm_is_vpc_address_prefix else it is set to default value '10.120.0.0/24'") + } + + IsImage = os.Getenv("IS_IMAGE") + if IsImage == "" { + //IsImage = "fc538f61-7dd6-4408-978c-c6b85b69fe76" // for classic infrastructure + IsImage = "r006-13938c0a-89e4-4370-b59b-55cd1402562d" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_IMAGE for testing ibm_is_instance, ibm_is_floating_ip else it is set to default value 'r006-ed3f775f-ad7e-4e37-ae62-7199b4988b00'") + } + + IsWinImage = os.Getenv("IS_WIN_IMAGE") + if IsWinImage == "" { + //IsWinImage = "a7a0626c-f97e-4180-afbe-0331ec62f32a" // classic windows machine: ibm-windows-server-2012-full-standard-amd64-1 + IsWinImage = "r006-5f9568ae-792e-47e1-a710-5538b2bdfca7" // next gen windows machine: ibm-windows-server-2012-full-standard-amd64-3 + fmt.Println("[INFO] Set the environment variable IS_WIN_IMAGE for testing ibm_is_instance data source else it is set to default value 'r006-5f9568ae-792e-47e1-a710-5538b2bdfca7'") + } + + InstanceName = os.Getenv("IS_INSTANCE_NAME") + if InstanceName == "" { + InstanceName = "placement-check-ins" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_INSTANCE_NAME for testing ibm_is_instance resource else it is set to default value 'instance-01'") + } + + InstanceProfileName = os.Getenv("SL_INSTANCE_PROFILE") + if InstanceProfileName == "" { + //InstanceProfileName = "bc1-2x8" // for classic infrastructure + InstanceProfileName = "cx2-2x4" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE for testing ibm_is_instance resource else it is set to default value 'cx2-2x4'") + } + + InstanceProfileNameUpdate = os.Getenv("SL_INSTANCE_PROFILE_UPDATE") + if InstanceProfileNameUpdate == "" { + InstanceProfileNameUpdate = "cx2-4x8" + fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE_UPDATE for testing ibm_is_instance resource else it is set to default value 'cx2-4x8'") + } + + IsBareMetalServerProfileName = os.Getenv("IS_BARE_METAL_SERVER_PROFILE") + if IsBareMetalServerProfileName == "" { + IsBareMetalServerProfileName = "bx2-metal-192x768" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_BARE_METAL_SERVER_PROFILE for testing ibm_is_bare_metal_server resource else it is set to default value 'bx2-metal-192x768'") + } + + IsBareMetalServerImage = os.Getenv("IS_BARE_METAL_SERVER_IMAGE") + if IsBareMetalServerImage == "" { + IsBareMetalServerImage = "r006-2d1f36b0-df65-4570-82eb-df7ae5f778b1" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IsBareMetalServerImage for testing ibm_is_bare_metal_server resource else it is set to default value 'r006-2d1f36b0-df65-4570-82eb-df7ae5f778b1'") + } + + DedicatedHostName = os.Getenv("IS_DEDICATED_HOST_NAME") + if DedicatedHostName == "" { + DedicatedHostName = "tf-dhost-01" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_NAME for testing ibm_is_instance resource else it is set to default value 'tf-dhost-01'") + } + + DedicatedHostGroupID = os.Getenv("IS_DEDICATED_HOST_GROUP_ID") + if DedicatedHostGroupID == "" { + DedicatedHostGroupID = "0717-9104e7b5-77ad-44ad-9eaa-091e6b6efce1" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_ID for testing ibm_is_instance resource else it is set to default value '0717-9104e7b5-77ad-44ad-9eaa-091e6b6efce1'") + } + + DedicatedHostProfileName = os.Getenv("IS_DEDICATED_HOST_PROFILE") + if DedicatedHostProfileName == "" { + DedicatedHostProfileName = "bx2d-host-152x608" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_PROFILE for testing ibm_is_instance resource else it is set to default value 'bx2d-host-152x608'") + } + + DedicatedHostGroupClass = os.Getenv("IS_DEDICATED_HOST_GROUP_CLASS") + if DedicatedHostGroupClass == "" { + DedicatedHostGroupClass = "bx2d" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_CLASS for testing ibm_is_instance resource else it is set to default value 'bx2d'") + } + + DedicatedHostGroupFamily = os.Getenv("IS_DEDICATED_HOST_GROUP_FAMILY") + if DedicatedHostGroupFamily == "" { + DedicatedHostGroupFamily = "balanced" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_FAMILY for testing ibm_is_instance resource else it is set to default value 'balanced'") + } + + InstanceDiskProfileName = os.Getenv("IS_INSTANCE_DISK_PROFILE") + if InstanceDiskProfileName == "" { + //InstanceProfileName = "bc1-2x8" // for classic infrastructure + InstanceDiskProfileName = "bx2d-16x64" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE for testing ibm_is_instance resource else it is set to default value 'bx2d-16x64'") + } + + VolumeProfileName = os.Getenv("IS_VOLUME_PROFILE") + if VolumeProfileName == "" { + VolumeProfileName = "general-purpose" + fmt.Println("[INFO] Set the environment variable IS_VOLUME_PROFILE for testing ibm_is_volume_profile else it is set to default value 'general-purpose'") + } + + ISRouteDestination = os.Getenv("SL_ROUTE_DESTINATION") + if ISRouteDestination == "" { + ISRouteDestination = "192.168.4.0/24" + fmt.Println("[INFO] Set the environment variable SL_ROUTE_DESTINATION for testing ibm_is_vpc_route else it is set to default value '192.168.4.0/24'") + } + + ISRouteNextHop = os.Getenv("SL_ROUTE_NEXTHOP") + if ISRouteNextHop == "" { + ISRouteNextHop = "10.240.0.0" + fmt.Println("[INFO] Set the environment variable SL_ROUTE_NEXTHOP for testing ibm_is_vpc_route else it is set to default value '10.0.0.4'") + } + + IcdDbRegion = os.Getenv("ICD_DB_REGION") + if IcdDbRegion == "" { + IcdDbRegion = "eu-gb" + fmt.Println("[INFO] Set the environment variable ICD_DB_REGION for testing ibm_cloud_databases else it is set to default value 'eu-gb'") + } + + IcdDbDeploymentId = os.Getenv("ICD_DB_DEPLOYMENT_ID") + if IcdDbDeploymentId == "" { + IcdDbDeploymentId = "crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:5042afe1-72c2-4231-89cc-c949e5d56251::" + fmt.Println("[INFO] Set the environment variable ICD_DB_DEPLOYMENT_ID for testing ibm_cloud_databases else it is set to default value 'crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:5042afe1-72c2-4231-89cc-c949e5d56251::'") + } + + IcdDbBackupId = os.Getenv("ICD_DB_BACKUP_ID") + if IcdDbBackupId == "" { + IcdDbBackupId = "crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:5042afe1-72c2-4231-89cc-c949e5d56251:backup:0d862fdb-4faa-42e5-aecb-5057f4d399c3" + fmt.Println("[INFO] Set the environment variable ICD_DB_BACKUP_ID for testing ibm_cloud_databases else it is set to default value 'crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:5042afe1-72c2-4231-89cc-c949e5d56251:backup:0d862fdb-4faa-42e5-aecb-5057f4d399c3'") + } + + IcdDbTaskId = os.Getenv("ICD_DB_TASK_ID") + if IcdDbTaskId == "" { + IcdDbTaskId = "crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:367b0a22-05bb-41e3-a1ed-ded1ff0889e5:task:882013a6-2751-4df7-a77a-98d258638704" + fmt.Println("[INFO] Set the environment variable ICD_DB_TASK_ID for testing ibm_cloud_databases else it is set to default value 'crn:v1:bluemix:public:databases-for-redis:au-syd:a/40ddc34a953a8c02f10987b59085b60e:367b0a22-05bb-41e3-a1ed-ded1ff0889e5:task:882013a6-2751-4df7-a77a-98d258638704'") + } + // Added for Power Colo Testing + Pi_image = os.Getenv("PI_IMAGE") + if Pi_image == "" { + Pi_image = "c93dc4c6-e85a-4da2-9ea6-f24576256122" + fmt.Println("[INFO] Set the environment variable PI_IMAGE for testing ibm_pi_image resource else it is set to default value '7200-03-03'") + } + Pi_sap_image = os.Getenv("PI_SAP_IMAGE") + if Pi_sap_image == "" { + Pi_sap_image = "2e29d6d2-e5ed-4ff8-8fad-64e4be90e023" + fmt.Println("[INFO] Set the environment variable PI_SAP_IMAGE for testing ibm_pi_image resource else it is set to default value 'Linux-RHEL-SAP-8-2'") + } + Pi_image_bucket_name = os.Getenv("PI_IMAGE_BUCKET_NAME") + if Pi_image_bucket_name == "" { + Pi_image_bucket_name = "images-public-bucket" + fmt.Println("[INFO] Set the environment variable PI_IMAGE_BUCKET_NAME for testing ibm_pi_image resource else it is set to default value 'images-public-bucket'") + } + Pi_image_bucket_file_name = os.Getenv("PI_IMAGE_BUCKET_FILE_NAME") + if Pi_image_bucket_file_name == "" { + Pi_image_bucket_file_name = "rhel.ova.gz" + fmt.Println("[INFO] Set the environment variable PI_IMAGE_BUCKET_FILE_NAME for testing ibm_pi_image resource else it is set to default value 'rhel.ova.gz'") + } + Pi_image_bucket_access_key = os.Getenv("PI_IMAGE_BUCKET_ACCESS_KEY") + if Pi_image_bucket_access_key == "" { + Pi_image_bucket_access_key = "images-bucket-access-key" + fmt.Println("[INFO] Set the environment variable PI_IMAGE_BUCKET_ACCESS_KEY for testing ibm_pi_image_export resource else it is set to default value 'images-bucket-access-key'") + } + + Pi_image_bucket_secret_key = os.Getenv("PI_IMAGE_BUCKET_SECRET_KEY") + if Pi_image_bucket_secret_key == "" { + Pi_image_bucket_secret_key = "images-bucket-secret-key" + fmt.Println("[INFO] Set the environment variable PI_IMAGE_BUCKET_SECRET_KEY for testing ibm_pi_image_export resource else it is set to default value 'PI_IMAGE_BUCKET_SECRET_KEY'") + } + + Pi_image_bucket_region = os.Getenv("PI_IMAGE_BUCKET_REGION") + if Pi_image_bucket_region == "" { + Pi_image_bucket_region = "us-east" + fmt.Println("[INFO] Set the environment variable PI_IMAGE_BUCKET_REGION for testing ibm_pi_image_export resource else it is set to default value 'us-east'") + } + + Pi_key_name = os.Getenv("PI_KEY_NAME") + if Pi_key_name == "" { + Pi_key_name = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_KEY_NAME for testing ibm_pi_key_name resource else it is set to default value 'terraform-test-power'") + } + + Pi_network_name = os.Getenv("PI_NETWORK_NAME") + if Pi_network_name == "" { + Pi_network_name = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_NETWORK_NAME for testing ibm_pi_network_name resource else it is set to default value 'terraform-test-power'") + } + + Pi_volume_name = os.Getenv("PI_VOLUME_NAME") + if Pi_volume_name == "" { + Pi_volume_name = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_VOLUME_NAME for testing ibm_pi_network_name resource else it is set to default value 'terraform-test-power'") + } + + Pi_cloud_instance_id = os.Getenv("PI_CLOUDINSTANCE_ID") + if Pi_cloud_instance_id == "" { + Pi_cloud_instance_id = "fd3454a3-14d8-4eb0-b075-acf3da5cd324" + fmt.Println("[INFO] Set the environment variable PI_CLOUDINSTANCE_ID for testing ibm_pi_image resource else it is set to default value 'd16705bd-7f1a-48c9-9e0e-1c17b71e7331'") + } + + Pi_instance_name = os.Getenv("PI_PVM_INSTANCE_NAME") + if Pi_instance_name == "" { + Pi_instance_name = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_PVM_INSTANCE_ID for testing Pi_instance_name resource else it is set to default value 'terraform-test-power'") + } + + Pi_dhcp_id = os.Getenv("PI_DHCP_ID") + if Pi_dhcp_id == "" { + Pi_dhcp_id = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_DHCP_ID for testing ibm_pi_dhcp resource else it is set to default value 'terraform-test-power'") + } + + PiCloudConnectionName = os.Getenv("PI_CLOUD_CONNECTION_NAME") + if PiCloudConnectionName == "" { + PiCloudConnectionName = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_CLOUD_CONNECTION_NAME for testing ibm_pi_cloud_connection resource else it is set to default value 'terraform-test-power'") + } + + PiSAPProfileID = os.Getenv("PI_SAP_PROFILE_ID") + if PiSAPProfileID == "" { + PiSAPProfileID = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_SAP_PROFILE_ID for testing ibm_pi_sap_profile resource else it is set to default value 'terraform-test-power'") + } + + Pi_placement_group_name = os.Getenv("PI_PLACEMENT_GROUP_NAME") + if Pi_placement_group_name == "" { + Pi_placement_group_name = "tf-pi-placement-group" + fmt.Println("[WARN] Set the environment variable PI_PLACEMENT_GROUP_NAME for testing ibm_pi_placement_group resource else it is set to default value 'tf-pi-placement-group'") + } + Pi_spp_placement_group_id = os.Getenv("PI_SPP_PLACEMENT_GROUP_ID") + if Pi_spp_placement_group_id == "" { + Pi_spp_placement_group_id = "tf-pi-spp-placement-group" + fmt.Println("[WARN] Set the environment variable PI_SPP_PLACEMENT_GROUP_ID for testing ibm_pi_spp_placement_group resource else it is set to default value 'tf-pi-spp-placement-group'") + } + PiStoragePool = os.Getenv("PI_STORAGE_POOL") + if PiStoragePool == "" { + PiStoragePool = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_STORAGE_POOL for testing ibm_pi_storage_pool_capacity else it is set to default value 'terraform-test-power'") + } + PiStorageType = os.Getenv("PI_STORAGE_TYPE") + if PiStorageType == "" { + PiStorageType = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_STORAGE_TYPE for testing ibm_pi_storage_type_capacity else it is set to default value 'terraform-test-power'") + } + // Added for resource capture instance testing + Pi_capture_storage_image_path = os.Getenv("PI_CAPTURE_STORAGE_IMAGE_PATH") + if Pi_capture_storage_image_path == "" { + Pi_capture_storage_image_path = "bucket-test" + fmt.Println("[INFO] Set the environment variable PI_CAPTURE_STORAGE_IMAGE_PATH for testing Pi_capture_storage_image_path resource else it is set to default value 'terraform-test-power'") + } + + Pi_capture_cloud_storage_access_key = os.Getenv("PI_CAPTURE_CLOUD_STORAGE_ACCESS_KEY") + if Pi_capture_cloud_storage_access_key == "" { + Pi_capture_cloud_storage_access_key = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_CAPTURE_CLOUD_STORAGE_ACCESS_KEY for testing Pi_capture_cloud_storage_access_key resource else it is set to default value 'terraform-test-power'") + } + + Pi_capture_cloud_storage_secret_key = os.Getenv("PI_CAPTURE_CLOUD_STORAGE_SECRET_KEY") + if Pi_capture_cloud_storage_secret_key == "" { + Pi_capture_cloud_storage_secret_key = "terraform-test-power" + fmt.Println("[INFO] Set the environment variable PI_CAPTURE_CLOUD_STORAGE_SECRET_KEY for testing Pi_capture_cloud_storage_secret_key resource else it is set to default value 'terraform-test-power'") + } + + Pi_shared_processor_pool_id = os.Getenv("PI_SHARED_PROCESSOR_POOL_ID") + if Pi_shared_processor_pool_id == "" { + Pi_shared_processor_pool_id = "tf-pi-shared-processor-pool" + fmt.Println("[WARN] Set the environment variable PI_SHARED_PROCESSOR_POOL_ID for testing ibm_pi_shared_processor_pool resource else it is set to default value 'tf-pi-shared-processor-pool'") + } + + WorkspaceID = os.Getenv("SCHEMATICS_WORKSPACE_ID") + if WorkspaceID == "" { + WorkspaceID = "us-south.workspace.tf-acc-test-schematics-state-test.392cd99f" + fmt.Println("[INFO] Set the environment variable SCHEMATICS_WORKSPACE_ID for testing schematics resources else it is set to default value") + } + TemplateID = os.Getenv("SCHEMATICS_TEMPLATE_ID") + if TemplateID == "" { + TemplateID = "c8d52331-056f-40" + fmt.Println("[INFO] Set the environment variable SCHEMATICS_TEMPLATE_ID for testing schematics resources else it is set to default value") + } + ActionID = os.Getenv("SCHEMATICS_ACTION_ID") + if ActionID == "" { + ActionID = "us-east.ACTION.action_pm.a4ffeec3" + fmt.Println("[INFO] Set the environment variable SCHEMATICS_ACTION_ID for testing schematics resources else it is set to default value") + } + JobID = os.Getenv("SCHEMATICS_JOB_ID") + if JobID == "" { + JobID = "us-east.ACTION.action_pm.a4ffeec3" + fmt.Println("[INFO] Set the environment variable SCHEMATICS_JOB_ID for testing schematics resources else it is set to default value") + } + RepoURL = os.Getenv("SCHEMATICS_REPO_URL") + if RepoURL == "" { + fmt.Println("[INFO] Set the environment variable SCHEMATICS_REPO_URL for testing schematics resources else tests will fail if this is not set correctly") + } + RepoBranch = os.Getenv("SCHEMATICS_REPO_BRANCH") + if RepoBranch == "" { + fmt.Println("[INFO] Set the environment variable SCHEMATICS_REPO_BRANCH for testing schematics resources else tests will fail if this is not set correctly") + } + // Added for resource image testing + Image_cos_url = os.Getenv("IMAGE_COS_URL") + if Image_cos_url == "" { + Image_cos_url = "cos://us-south/cosbucket-vpc-image-gen2/rhel-guest-image-7.0-20140930.0.x86_64.qcow2" + fmt.Println("[WARN] Set the environment variable IMAGE_COS_URL with a VALID COS Image SQL URL for testing ibm_is_image resources on staging/test") + } + + // Added for resource image testing + Image_cos_url_encrypted = os.Getenv("IMAGE_COS_URL_ENCRYPTED") + if Image_cos_url_encrypted == "" { + Image_cos_url_encrypted = "cos://us-south/cosbucket-vpc-image-gen2/rhel-guest-image-7.0-encrypted.qcow2" + fmt.Println("[WARN] Set the environment variable IMAGE_COS_URL_ENCRYPTED with a VALID COS Image SQL URL for testing ibm_is_image resources on staging/test") + } + Image_operating_system = os.Getenv("IMAGE_OPERATING_SYSTEM") + if Image_operating_system == "" { + Image_operating_system = "red-7-amd64" + fmt.Println("[WARN] Set the environment variable IMAGE_OPERATING_SYSTEM with a VALID Operating system for testing ibm_is_image resources on staging/test") + } + + IsImageName = os.Getenv("IS_IMAGE_NAME") + if IsImageName == "" { + //IsImageName = "ibm-ubuntu-18-04-2-minimal-amd64-1" // for classic infrastructure + IsImageName = "ibm-ubuntu-18-04-1-minimal-amd64-2" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_IMAGE_NAME for testing data source ibm_is_image else it is set to default value `ibm-ubuntu-18-04-1-minimal-amd64-2`") + } + IsImageEncryptedDataKey = os.Getenv("IS_IMAGE_ENCRYPTED_DATA_KEY") + if IsImageEncryptedDataKey == "" { + IsImageEncryptedDataKey = "eyJjaXBoZXJ0ZXh0IjoidElsZnRjUXB5L0krSGJsMlVIK2ZxZ1FGK1diR3loV1dPRFk9IiwiaXYiOiJ3SlhSVklsSHUzMzFqUEY0IiwidmVyc2lvbiI6IjQuMC4wIiwiaGFuZGxlIjoiZjM2YTA2NGUtY2E2My00NmU0LThlNjAtYmJiMzEyNTY5YzM1In0=" + fmt.Println("[INFO] Set the environment variable IS_IMAGE_ENCRYPTED_DATA_KEY for testing resource ibm_is_image else it is set to default value") + } + IsImageEncryptionKey = os.Getenv("IS_IMAGE_ENCRYPTION_KEY") + if IsImageEncryptionKey == "" { + IsImageEncryptionKey = "crn:v1:bluemix:public:kms:us-south:a/52b2e14f385aca5da781baa1b9c28e53:21d9f13d-5895-49a1-9e80-b4aff69dfc1f:key:f36a064e-ca63-46e4-8e60-bbb312569c35" + fmt.Println("[INFO] Set the environment variable IS_IMAGE_ENCRYPTION_KEY for testing resource ibm_is_image else it is set to default value") + } + + functionNamespace = os.Getenv("IBM_FUNCTION_NAMESPACE") + if functionNamespace == "" { + fmt.Println("[INFO] Set the environment variable IBM_FUNCTION_NAMESPACE for testing ibm_function_package, ibm_function_action, ibm_function_rule, ibm_function_trigger resource else tests will fail if this is not set correctly") + } + + HpcsInstanceID = os.Getenv("HPCS_INSTANCE_ID") + if HpcsInstanceID == "" { + HpcsInstanceID = "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8" + fmt.Println("[INFO] Set the environment variable HPCS_INSTANCE_ID for testing data_source_ibm_kms_key_test else it is set to default value") + } + + SecretsManagerInstanceID = os.Getenv("SECRETS_MANAGER_INSTANCE_ID") + if SecretsManagerInstanceID == "" { + // SecretsManagerInstanceID = "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8" + fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_INSTANCE_ID for testing data_source_ibm_secrets_manager_secrets_test else tests will fail if this is not set correctly") + } + + SecretsManagerSecretType = os.Getenv("SECRETS_MANAGER_SECRET_TYPE") + if SecretsManagerSecretType == "" { + SecretsManagerSecretType = "username_password" + fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_SECRET_TYPE for testing data_source_ibm_secrets_manager_secrets_test, else it is set to default value. For data_source_ibm_secrets_manager_secret_test, tests will fail if this is not set correctly") + } + + SecretsManagerSecretID = os.Getenv("SECRETS_MANAGER_SECRET_ID") + if SecretsManagerSecretID == "" { + // SecretsManagerSecretID = "644f4a69-0d17-198f-3b58-23f2746c706d" + fmt.Println("[WARN] Set the environment variable SECRETS_MANAGER_SECRET_ID for testing data_source_ibm_secrets_manager_secret_test else tests will fail if this is not set correctly") + } + + Tg_cross_network_account_id = os.Getenv("IBM_TG_CROSS_ACCOUNT_ID") + if Tg_cross_network_account_id == "" { + fmt.Println("[INFO] Set the environment variable IBM_TG_CROSS_ACCOUNT_ID for testing ibm_tg_connection resource else tests will fail if this is not set correctly") + } + Tg_cross_network_id = os.Getenv("IBM_TG_CROSS_NETWORK_ID") + if Tg_cross_network_id == "" { + fmt.Println("[INFO] Set the environment variable IBM_TG_CROSS_NETWORK_ID for testing ibm_tg_connection resource else tests will fail if this is not set correctly") + } + Account_to_be_imported = os.Getenv("ACCOUNT_TO_BE_IMPORTED") + if Account_to_be_imported == "" { + fmt.Println("[INFO] Set the environment variable ACCOUNT_TO_BE_IMPORTED for testing import enterprise account resource else tests will fail if this is not set correctly") + } + HpcsAdmin1 = os.Getenv("IBM_HPCS_ADMIN1") + if HpcsAdmin1 == "" { + fmt.Println("[WARN] Set the environment variable IBM_HPCS_ADMIN1 with a VALID HPCS Admin Key1 Path") + } + HpcsToken1 = os.Getenv("IBM_HPCS_TOKEN1") + if HpcsToken1 == "" { + fmt.Println("[WARN] Set the environment variable IBM_HPCS_TOKEN1 with a VALID token for HPCS Admin Key1") + } + HpcsAdmin2 = os.Getenv("IBM_HPCS_ADMIN2") + if HpcsAdmin2 == "" { + fmt.Println("[WARN] Set the environment variable IBM_HPCS_ADMIN2 with a VALID HPCS Admin Key2 Path") + } + RealmName = os.Getenv("IBM_IAM_REALM_NAME") + if RealmName == "" { + fmt.Println("[WARN] Set the environment variable IBM_IAM_REALM_NAME with a VALID realm name for iam trusted profile claim rule") + } + + IksSa = os.Getenv("IBM_IAM_IKS_SA") + if IksSa == "" { + fmt.Println("[WARN] Set the environment variable IBM_IAM_IKS_SA with a VALID realm name for iam trusted profile link") + } + + HpcsToken2 = os.Getenv("IBM_HPCS_TOKEN2") + if HpcsToken2 == "" { + fmt.Println("[WARN] Set the environment variable IBM_HPCS_TOKEN2 with a VALID token for HPCS Admin Key2") + } + HpcsRootKeyCrn = os.Getenv("IBM_HPCS_ROOTKEY_CRN") + if HpcsRootKeyCrn == "" { + fmt.Println("[WARN] Set the environment variable IBM_HPCS_ROOTKEY_CRN with a VALID CRN for a root key created in the HPCS instance") + } + + Scc_gov_account_id = os.Getenv("SCC_GOVERNANCE_ACCOUNT_ID") + if Scc_gov_account_id == "" { + fmt.Println("[WARN] Set the environment variable SCC_GOVERNANCE_ACCOUNT_ID with a VALID account name") + } + + Scc_resource_group_id = os.Getenv("IBM_SCC_RESOURCE_GROUP") + if Scc_resource_group_id == "" { + fmt.Println("[WARN] Set the environment variable IBM_SCC_RESOURCE_GROUP with a VALID resource group id") + } + + Scc_si_account = os.Getenv("SCC_SI_ACCOUNT") + if Scc_si_account == "" { + fmt.Println("[INFO] Set the environment variable SCC_SI_ACCOUNT for testing SCC SI resources resource else tests will fail if this is not set correctly") + } + + Scc_posture_scope_id = os.Getenv("SCC_POSTURE_SCOPE_ID") + if Scc_posture_scope_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_SCOPE_ID for testing SCC Posture resources or datasource resource else tests will fail if this is not set correctly") + } + + Scc_posture_scan_id = os.Getenv("SCC_POSTURE_SCAN_ID") + if Scc_posture_scan_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_SCAN_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_profile_id = os.Getenv("SCC_POSTURE_PROFILE_ID") + if Scc_posture_profile_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_PROFILE_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + Scc_posture_group_profile_id = os.Getenv("SCC_POSTURE_GROUP_PROFILE_ID") + if Scc_posture_group_profile_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_GROUP_PROFILE_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_correlation_id = os.Getenv("SCC_POSTURE_CORRELATION_ID") + if Scc_posture_correlation_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_CORRELATION_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_report_setting_id = os.Getenv("SCC_POSTURE_REPORT_SETTING_ID") + if Scc_posture_report_setting_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_REPORT_SETTING_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_profile_id_scansummary = os.Getenv("SCC_POSTURE_PROFILE_ID_SCANSUMMARY") + if Scc_posture_profile_id_scansummary == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_PROFILE_ID_SCANSUMMARY for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_scan_id_scansummary = os.Getenv("SCC_POSTURE_SCAN_ID_SCANSUMMARY") + if Scc_posture_scan_id_scansummary == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_SCAN_ID_SCANSUMMARY for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_credential_id_scope = os.Getenv("SCC_POSTURE_CREDENTIAL_ID_SCOPE") + if Scc_posture_credential_id_scope == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_CREDENTIAL_ID_SCOPE for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_credential_id_scope_update = os.Getenv("SCC_POSTURE_CREDENTIAL_ID_SCOPE_UPDATE") + if Scc_posture_credential_id_scope_update == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_CREDENTIAL_ID_SCOPE_UPDATE for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_collector_id_scope = []string{os.Getenv("SCC_POSTURE_COLLECTOR_ID_SCOPE")} + if os.Getenv("SCC_POSTURE_COLLECTOR_ID_SCOPE") == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_COLLECTOR_ID_SCOPE for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_collector_id_scope_update = []string{os.Getenv("SCC_POSTURE_COLLECTOR_ID_SCOPE_UPDATE")} + if os.Getenv("SCC_POSTURE_COLLECTOR_ID_SCOPE_UPDATE") == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_COLLECTOR_ID_SCOPE_UPDATE for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") + } + + Scc_posture_collector_id = os.Getenv("SCC_POSTURE_COLLECTOR_ID") + if Scc_posture_collector_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_COLLECTOR_ID for testing SCC Posture resources or datasource resource else tests will fail if this is not set correctly") + } + + Scc_posture_credential_id = os.Getenv("SCC_POSTURE_CREDENTIAL_ID") + if Scc_posture_credential_id == "" { + fmt.Println("[INFO] Set the environment variable SCC_POSTURE_CREDENTIAL_ID for testing SCC Posture resources or datasource resource else tests will fail if this is not set correctly") + } + + CloudShellAccountID = os.Getenv("IBM_CLOUD_SHELL_ACCOUNT_ID") + if CloudShellAccountID == "" { + fmt.Println("[INFO] Set the environment variable IBM_CLOUD_SHELL_ACCOUNT_ID for ibm-cloud-shell resource or datasource else tests will fail if this is not set correctly") + } + + IksClusterVpcID = os.Getenv("IBM_CLUSTER_VPC_ID") + if IksClusterVpcID == "" { + fmt.Println("[WARN] Set the environment variable IBM_CLUSTER_VPC_ID for testing ibm_container_vpc_alb_create resources, ibm_container_vpc_alb_create tests will fail if this is not set") + } + + IksClusterSubnetID = os.Getenv("IBM_CLUSTER_VPC_SUBNET_ID") + if IksClusterSubnetID == "" { + fmt.Println("[WARN] Set the environment variable IBM_CLUSTER_VPC_SUBNET_ID for testing ibm_container_vpc_alb_create resources, ibm_container_vpc_alb_creates tests will fail if this is not set") + } + + IksClusterResourceGroupID = os.Getenv("IBM_CLUSTER_VPC_RESOURCE_GROUP_ID") + if IksClusterResourceGroupID == "" { + fmt.Println("[WARN] Set the environment variable IBM_CLUSTER_VPC_RESOURCE_GROUP_ID for testing ibm_container_vpc_alb_create resources, ibm_container_vpc_alb_creates tests will fail if this is not set") + } + + ClusterName = os.Getenv("IBM_CONTAINER_CLUSTER_NAME") + if ClusterName == "" { + fmt.Println("[INFO] Set the environment variable IBM_CONTAINER_CLUSTER_NAME for ibm_container_nlb_dns resource or datasource else tests will fail if this is not set correctly") + } + + Satellite_location_id = os.Getenv("SATELLITE_LOCATION_ID") + if Satellite_location_id == "" { + fmt.Println("[INFO] Set the environment variable SATELLITE_LOCATION_ID for ibm_cos_bucket satellite location resource or datasource else tests will fail if this is not set correctly") + } + + Satellite_Resource_instance_id = os.Getenv("SATELLITE_RESOURCE_INSTANCE_ID") + if Satellite_Resource_instance_id == "" { + fmt.Println("[INFO] Set the environment variable SATELLITE_RESOURCE_INSTANCE_ID for ibm_cos_bucket satellite location resource or datasource else tests will fail if this is not set correctly") + } + + HostPoolID = os.Getenv("IBM_CONTAINER_DEDICATEDHOST_POOL_ID") + if HostPoolID == "" { + fmt.Println("[INFO] Set the environment variable IBM_CONTAINER_DEDICATEDHOST_POOL_ID for ibm_container_vpc_cluster resource to test dedicated host functionality") + } + + KmsInstanceID = os.Getenv("IBM_KMS_INSTANCE_ID") + if KmsInstanceID == "" { + fmt.Println("[INFO] Set the environment variable IBM_KMS_INSTANCE_ID for ibm_container_vpc_cluster resource or datasource else tests will fail if this is not set correctly") + } + + CrkID = os.Getenv("IBM_CRK_ID") + if CrkID == "" { + fmt.Println("[INFO] Set the environment variable IBM_CRK_ID for ibm_container_vpc_cluster resource or datasource else tests will fail if this is not set correctly") + } + + IksClusterID = os.Getenv("IBM_CLUSTER_ID") + if IksClusterID == "" { + fmt.Println("[INFO] Set the environment variable IBM_CLUSTER_ID for ibm_container_vpc_worker_pool resource or datasource else tests will fail if this is not set correctly") + } + + CdResourceGroupID = os.Getenv("IBM_CD_RESOURCE_GROUP_ID") + if CdResourceGroupID == "" { + fmt.Println("[WARN] Set the environment variable IBM_CD_RESOURCE_GROUP_ID for testing CD resources, CD tests will fail if this is not set") + } + + ISCertificateCrn = os.Getenv("IS_CERTIFICATE_CRN") + if ISCertificateCrn == "" { + fmt.Println("[INFO] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + ISClientCaCrn = os.Getenv("IS_CLIENT_CA_CRN") + if ISClientCaCrn == "" { + fmt.Println("[INFO] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + + IBM_AccountID_REPL = os.Getenv("IBM_AccountID_REPL") + if IBM_AccountID_REPL == "" { + fmt.Println("[INFO] Set the environment variable IBM_AccountID_REPL for setting up authorization policy to enable replication feature resource or datasource else tests will fail if this is not set correctly") + } +} + +var TestAccProviders map[string]*schema.Provider +var TestAccProvider *schema.Provider + +func init() { + TestAccProvider = provider.Provider() + TestAccProviders = map[string]*schema.Provider{ + "ibm": TestAccProvider, + } +} + +func TestProvider(t *testing.T) { + if err := provider.Provider().InternalValidate(); err != nil { + t.Fatalf("err: %s", err) + } +} + +func TestProvider_impl(t *testing.T) { + var _ *schema.Provider = provider.Provider() +} + +func TestAccPreCheck(t *testing.T) { + if v := os.Getenv("IC_API_KEY"); v == "" { + t.Fatal("IC_API_KEY must be set for acceptance tests") + } + if v := os.Getenv("IAAS_CLASSIC_API_KEY"); v == "" { + t.Fatal("IAAS_CLASSIC_API_KEY must be set for acceptance tests") + } + if v := os.Getenv("IAAS_CLASSIC_USERNAME"); v == "" { + t.Fatal("IAAS_CLASSIC_USERNAME must be set for acceptance tests") + } +} + +func TestAccPreCheckEnterprise(t *testing.T) { + if v := os.Getenv("IC_API_KEY"); v == "" { + t.Fatal("IC_API_KEY must be set for acceptance tests") + } + +} + +func TestAccPreCheckEnterpriseAccountImport(t *testing.T) { + if v := os.Getenv("IC_API_KEY"); v == "" { + t.Fatal("IC_API_KEY must be set for acceptance tests") + } + if Account_to_be_imported == "" { + t.Fatal("ACCOUNT_TO_BE_IMPORTED must be set for acceptance tests") + } + +} +func TestAccPreCheckCis(t *testing.T) { + TestAccPreCheck(t) + if CisInstance == "" { + t.Fatal("IBM_CIS_INSTANCE must be set for acceptance tests") + } + if CisResourceGroup == "" { + t.Fatal("IBM_CIS_RESOURCE_GROUP must be set for acceptance tests") + } + if CisDomainStatic == "" { + t.Fatal("IBM_CIS_DOMAIN_STATIC must be set for acceptance tests") + } + if CisDomainTest == "" { + t.Fatal("IBM_CIS_DOMAIN_TEST must be set for acceptance tests") + } +} + +func TestAccPreCheckCloudShell(t *testing.T) { + TestAccPreCheck(t) + if CloudShellAccountID == "" { + t.Fatal("IBM_CLOUD_SHELL_ACCOUNT_ID must be set for acceptance tests") + } +} + +func TestAccPreCheckHPCS(t *testing.T) { + TestAccPreCheck(t) + if HpcsAdmin1 == "" { + t.Fatal("IBM_HPCS_ADMIN1 must be set for acceptance tests") + } + if HpcsToken1 == "" { + t.Fatal("IBM_HPCS_TOKEN1 must be set for acceptance tests") + } + if HpcsAdmin2 == "" { + t.Fatal("IBM_HPCS_ADMIN2 must be set for acceptance tests") + } + if HpcsToken2 == "" { + t.Fatal("IBM_HPCS_TOKEN2 must be set for acceptance tests") + } +} +func TestAccPreCheckIAMTrustedProfile(t *testing.T) { + TestAccPreCheck(t) + if RealmName == "" { + t.Fatal("IBM_IAM_REALM_NAME must be set for acceptance tests") + } + if IksSa == "" { + t.Fatal("IBM_IAM_IKS_SA must be set for acceptance tests") + } +} + +func TestAccPreCheckCOS(t *testing.T) { + TestAccPreCheck(t) + if CosCRN == "" { + t.Fatal("IBM_COS_CRN must be set for acceptance tests") + } +} + +func TestAccPreCheckImage(t *testing.T) { + TestAccPreCheck(t) + if Image_cos_url == "" { + t.Fatal("IMAGE_COS_URL must be set for acceptance tests") + } + if Image_operating_system == "" { + t.Fatal("IMAGE_OPERATING_SYSTEM must be set for acceptance tests") + } +} +func TestAccPreCheckEncryptedImage(t *testing.T) { + TestAccPreCheck(t) + if Image_cos_url_encrypted == "" { + t.Fatal("IMAGE_COS_URL_ENCRYPTED must be set for acceptance tests") + } + if Image_operating_system == "" { + t.Fatal("IMAGE_OPERATING_SYSTEM must be set for acceptance tests") + } + if IsImageEncryptedDataKey == "" { + t.Fatal("IS_IMAGE_ENCRYPTED_DATA_KEY must be set for acceptance tests") + } + if IsImageEncryptionKey == "" { + t.Fatal("IS_IMAGE_ENCRYPTION_KEY must be set for acceptance tests") + } +} diff --git a/ibm/config.go b/ibm/config.go deleted file mode 100644 index 7ef4c8576..000000000 --- a/ibm/config.go +++ /dev/null @@ -1,2745 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "log" - "net" - gohttp "net/http" - "os" - "strings" - "time" - - // Added code for the Power Colo Offering - - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" - apigateway "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" - "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/IBM/container-registry-go-sdk/containerregistryv1" - "github.com/IBM/go-sdk-core/v5/core" - cosconfig "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" - kp "github.com/IBM/keyprotect-go-client" - ciscachev1 "github.com/IBM/networking-go-sdk/cachingapiv1" - cisipv1 "github.com/IBM/networking-go-sdk/cisipapiv1" - ciscustompagev1 "github.com/IBM/networking-go-sdk/custompagesv1" - dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" - dl "github.com/IBM/networking-go-sdk/directlinkv1" - cisdnsbulkv1 "github.com/IBM/networking-go-sdk/dnsrecordbulkv1" - cisdnsrecordsv1 "github.com/IBM/networking-go-sdk/dnsrecordsv1" - dns "github.com/IBM/networking-go-sdk/dnssvcsv1" - cisedgefunctionv1 "github.com/IBM/networking-go-sdk/edgefunctionsapiv1" - cisfiltersv1 "github.com/IBM/networking-go-sdk/filtersv1" - cisfirewallrulesv1 "github.com/IBM/networking-go-sdk/firewallrulesv1" - cisglbhealthcheckv1 "github.com/IBM/networking-go-sdk/globalloadbalancermonitorv1" - cisglbpoolv0 "github.com/IBM/networking-go-sdk/globalloadbalancerpoolsv0" - cisglbv1 "github.com/IBM/networking-go-sdk/globalloadbalancerv1" - cispagerulev1 "github.com/IBM/networking-go-sdk/pageruleapiv1" - cisrangeappv1 "github.com/IBM/networking-go-sdk/rangeapplicationsv1" - cisroutingv1 "github.com/IBM/networking-go-sdk/routingv1" - cissslv1 "github.com/IBM/networking-go-sdk/sslcertificateapiv1" - tg "github.com/IBM/networking-go-sdk/transitgatewayapisv1" - cisuarulev1 "github.com/IBM/networking-go-sdk/useragentblockingrulesv1" - ciswafgroupv1 "github.com/IBM/networking-go-sdk/wafrulegroupsapiv1" - ciswafpackagev1 "github.com/IBM/networking-go-sdk/wafrulepackagesapiv1" - ciswafrulev1 "github.com/IBM/networking-go-sdk/wafrulesapiv1" - cisaccessrulev1 "github.com/IBM/networking-go-sdk/zonefirewallaccessrulesv1" - cislockdownv1 "github.com/IBM/networking-go-sdk/zonelockdownv1" - cisratelimitv1 "github.com/IBM/networking-go-sdk/zoneratelimitsv1" - cisdomainsettingsv1 "github.com/IBM/networking-go-sdk/zonessettingsv1" - ciszonesv1 "github.com/IBM/networking-go-sdk/zonesv1" - "github.com/IBM/platform-services-go-sdk/atrackerv1" - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" - "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" - "github.com/IBM/platform-services-go-sdk/globaltaggingv1" - iamaccessgroups "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - iamidentity "github.com/IBM/platform-services-go-sdk/iamidentityv1" - iampolicymanagement "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - ibmcloudshellv1 "github.com/IBM/platform-services-go-sdk/ibmcloudshellv1" - resourcecontroller "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - resourcemanager "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" - "github.com/IBM/push-notifications-go-sdk/pushservicev1" - "github.com/IBM/scc-go-sdk/findingsv1" - schematicsv1 "github.com/IBM/schematics-go-sdk/schematicsv1" - "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1" - vpc "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/apache/openwhisk-client-go/whisk" - jwt "github.com/golang-jwt/jwt" - slsession "github.com/softlayer/softlayer-go/session" - - bluemix "github.com/IBM-Cloud/bluemix-go" - "github.com/IBM-Cloud/bluemix-go/api/account/accountv1" - "github.com/IBM-Cloud/bluemix-go/api/account/accountv2" - "github.com/IBM-Cloud/bluemix-go/api/certificatemanager" - "github.com/IBM-Cloud/bluemix-go/api/cis/cisv1" - "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" - "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" - "github.com/IBM-Cloud/bluemix-go/api/functions" - "github.com/IBM-Cloud/bluemix-go/api/globalsearch/globalsearchv2" - "github.com/IBM-Cloud/bluemix-go/api/globaltagging/globaltaggingv3" - "github.com/IBM-Cloud/bluemix-go/api/hpcs" - "github.com/IBM-Cloud/bluemix-go/api/iam/iamv1" - "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" - "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/controller" - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/managementv2" - "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" - "github.com/IBM-Cloud/bluemix-go/authentication" - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/http" - "github.com/IBM-Cloud/bluemix-go/rest" - bxsession "github.com/IBM-Cloud/bluemix-go/session" - ibmpisession "github.com/IBM-Cloud/power-go-client/ibmpisession" - "github.com/IBM-Cloud/terraform-provider-ibm/version" - "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" - "github.com/IBM/eventstreams-go-sdk/pkg/schemaregistryv1" - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -// RetryAPIDelay - retry api delay -const RetryAPIDelay = 5 * time.Second - -//BluemixRegion ... -var BluemixRegion string - -var ( - errEmptyBluemixCredentials = errors.New("ibmcloud_api_key or bluemix_api_key or iam_token and iam_refresh_token must be provided. Please see the documentation on how to configure it") -) - -//UserConfig ... -type UserConfig struct { - userID string - userEmail string - userAccount string - cloudName string `default:"bluemix"` - cloudType string `default:"public"` - generation int `default:"2"` -} - -//Config stores user provider input -type Config struct { - //BluemixAPIKey is the Bluemix api key - BluemixAPIKey string - //Bluemix region - Region string - //Resource group id - ResourceGroup string - //Bluemix API timeout - BluemixTimeout time.Duration - - //Softlayer end point url - SoftLayerEndpointURL string - - //Softlayer API timeout - SoftLayerTimeout time.Duration - - // Softlayer User Name - SoftLayerUserName string - - // Softlayer API Key - SoftLayerAPIKey string - - //Retry Count for API calls - //Unexposed in the schema at this point as they are used only during session creation for a few calls - //When sdk implements it we an expose them for expected behaviour - //https://github.com/softlayer/softlayer-go/issues/41 - RetryCount int - //Constant Retry Delay for API calls - RetryDelay time.Duration - - // FunctionNameSpace ... - FunctionNameSpace string - - //Riaas End point - RiaasEndPoint string - - //Generation - Generation int - - //IAM Token - IAMToken string - - //IAM Refresh Token - IAMRefreshToken string - - // PowerService Instance - PowerServiceInstance string - - // Zone - Zone string - Visibility string - EndpointsFile string -} - -//Session stores the information required for communication with the SoftLayer and Bluemix API -type Session struct { - // SoftLayerSesssion is the the SoftLayer session used to connect to the SoftLayer API - SoftLayerSession *slsession.Session - - // BluemixSession is the the Bluemix session used to connect to the Bluemix API - BluemixSession *bxsession.Session -} - -// ClientSession ... -type ClientSession interface { - AppIDAPI() (*appid.AppIDManagementV4, error) - BluemixSession() (*bxsession.Session, error) - BluemixAcccountAPI() (accountv2.AccountServiceAPI, error) - BluemixAcccountv1API() (accountv1.AccountServiceAPI, error) - BluemixUserDetails() (*UserConfig, error) - ContainerAPI() (containerv1.ContainerServiceAPI, error) - VpcContainerAPI() (containerv2.ContainerServiceAPI, error) - ContainerRegistryV1() (*containerregistryv1.ContainerRegistryV1, error) - FunctionClient() (*whisk.Client, error) - GlobalSearchAPI() (globalsearchv2.GlobalSearchServiceAPI, error) - GlobalTaggingAPI() (globaltaggingv3.GlobalTaggingServiceAPI, error) - GlobalTaggingAPIv1() (globaltaggingv1.GlobalTaggingV1, error) - ICDAPI() (icdv4.ICDServiceAPI, error) - IAMAPI() (iamv1.IAMServiceAPI, error) - IAMPolicyManagementV1API() (*iampolicymanagement.IamPolicyManagementV1, error) - IAMAccessGroupsV2() (*iamaccessgroups.IamAccessGroupsV2, error) - MccpAPI() (mccpv2.MccpServiceAPI, error) - ResourceCatalogAPI() (catalog.ResourceCatalogAPI, error) - ResourceManagementAPIv2() (managementv2.ResourceManagementAPIv2, error) - ResourceControllerAPI() (controller.ResourceControllerAPI, error) - ResourceControllerAPIV2() (controllerv2.ResourceControllerAPIV2, error) - SoftLayerSession() *slsession.Session - IBMPISession() (*ibmpisession.IBMPISession, error) - UserManagementAPI() (usermanagementv2.UserManagementAPI, error) - PushServiceV1() (*pushservicev1.PushServiceV1, error) - EventNotificationsApiV1() (*eventnotificationsv1.EventNotificationsV1, error) - AppConfigurationV1() (*appconfigurationv1.AppConfigurationV1, error) - CertificateManagerAPI() (certificatemanager.CertificateManagerServiceAPI, error) - keyProtectAPI() (*kp.Client, error) - keyManagementAPI() (*kp.Client, error) - VpcV1API() (*vpc.VpcV1, error) - APIGateway() (*apigateway.ApiGatewayControllerApiV1, error) - PrivateDNSClientSession() (*dns.DnsSvcsV1, error) - CosConfigV1API() (*cosconfig.ResourceConfigurationV1, error) - DirectlinkV1API() (*dl.DirectLinkV1, error) - DirectlinkProviderV2API() (*dlProviderV2.DirectLinkProviderV2, error) - TransitGatewayV1API() (*tg.TransitGatewayApisV1, error) - HpcsEndpointAPI() (hpcs.HPCSV2, error) - FunctionIAMNamespaceAPI() (functions.FunctionServiceAPI, error) - CisZonesV1ClientSession() (*ciszonesv1.ZonesV1, error) - CisDNSRecordClientSession() (*cisdnsrecordsv1.DnsRecordsV1, error) - CisDNSRecordBulkClientSession() (*cisdnsbulkv1.DnsRecordBulkV1, error) - CisGLBClientSession() (*cisglbv1.GlobalLoadBalancerV1, error) - CisGLBPoolClientSession() (*cisglbpoolv0.GlobalLoadBalancerPoolsV0, error) - CisGLBHealthCheckClientSession() (*cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1, error) - CisIPClientSession() (*cisipv1.CisIpApiV1, error) - CisPageRuleClientSession() (*cispagerulev1.PageRuleApiV1, error) - CisRLClientSession() (*cisratelimitv1.ZoneRateLimitsV1, error) - CisEdgeFunctionClientSession() (*cisedgefunctionv1.EdgeFunctionsApiV1, error) - CisSSLClientSession() (*cissslv1.SslCertificateApiV1, error) - CisWAFPackageClientSession() (*ciswafpackagev1.WafRulePackagesApiV1, error) - CisDomainSettingsClientSession() (*cisdomainsettingsv1.ZonesSettingsV1, error) - CisRoutingClientSession() (*cisroutingv1.RoutingV1, error) - CisWAFGroupClientSession() (*ciswafgroupv1.WafRuleGroupsApiV1, error) - CisCacheClientSession() (*ciscachev1.CachingApiV1, error) - CisCustomPageClientSession() (*ciscustompagev1.CustomPagesV1, error) - CisAccessRuleClientSession() (*cisaccessrulev1.ZoneFirewallAccessRulesV1, error) - CisUARuleClientSession() (*cisuarulev1.UserAgentBlockingRulesV1, error) - CisLockdownClientSession() (*cislockdownv1.ZoneLockdownV1, error) - CisRangeAppClientSession() (*cisrangeappv1.RangeApplicationsV1, error) - CisWAFRuleClientSession() (*ciswafrulev1.WafRulesApiV1, error) - IAMIdentityV1API() (*iamidentity.IamIdentityV1, error) - IBMCloudShellV1() (*ibmcloudshellv1.IBMCloudShellV1, error) - ResourceManagerV2API() (*resourcemanager.ResourceManagerV2, error) - CatalogManagementV1() (*catalogmanagementv1.CatalogManagementV1, error) - EnterpriseManagementV1() (*enterprisemanagementv1.EnterpriseManagementV1, error) - ResourceControllerV2API() (*resourcecontroller.ResourceControllerV2, error) - SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) - SchematicsV1() (*schematicsv1.SchematicsV1, error) - SatelliteClientSession() (*kubernetesserviceapiv1.KubernetesServiceApiV1, error) - SatellitLinkClientSession() (*satellitelinkv1.SatelliteLinkV1, error) - CisFiltersSession() (*cisfiltersv1.FiltersV1, error) - CisFirewallRulesSession() (*cisfirewallrulesv1.FirewallRulesV1, error) - AtrackerV1() (*atrackerv1.AtrackerV1, error) - ESschemaRegistrySession() (*schemaregistryv1.SchemaregistryV1, error) - FindingsV1() (*findingsv1.FindingsV1, error) - PostureManagementV1() (*posturemanagementv1.PostureManagementV1, error) -} - -type clientSession struct { - session *Session - - appidErr error - appidAPI *appid.AppIDManagementV4 - - apigatewayErr error - apigatewayAPI *apigateway.ApiGatewayControllerApiV1 - - accountConfigErr error - bmxAccountServiceAPI accountv2.AccountServiceAPI - - accountV1ConfigErr error - bmxAccountv1ServiceAPI accountv1.AccountServiceAPI - - bmxUserDetails *UserConfig - bmxUserFetchErr error - - csConfigErr error - csServiceAPI containerv1.ContainerServiceAPI - - csv2ConfigErr error - csv2ServiceAPI containerv2.ContainerServiceAPI - - containerRegistryClientErr error - containerRegistryClient *containerregistryv1.ContainerRegistryV1 - - certManagementErr error - certManagementAPI certificatemanager.CertificateManagerServiceAPI - - cfConfigErr error - cfServiceAPI mccpv2.MccpServiceAPI - - cisConfigErr error - cisServiceAPI cisv1.CisServiceAPI - - functionConfigErr error - functionClient *whisk.Client - - globalSearchConfigErr error - globalSearchServiceAPI globalsearchv2.GlobalSearchServiceAPI - - globalTaggingConfigErr error - globalTaggingServiceAPI globaltaggingv3.GlobalTaggingServiceAPI - - globalTaggingConfigErrV1 error - globalTaggingServiceAPIV1 globaltaggingv1.GlobalTaggingV1 - - ibmCloudShellClient *ibmcloudshellv1.IBMCloudShellV1 - ibmCloudShellClientErr error - - userManagementErr error - userManagementAPI usermanagementv2.UserManagementAPI - - iamConfigErr error - iamServiceAPI iamv1.IAMServiceAPI - - icdConfigErr error - icdServiceAPI icdv4.ICDServiceAPI - - resourceControllerConfigErr error - resourceControllerServiceAPI controller.ResourceControllerAPI - - resourceControllerConfigErrv2 error - resourceControllerServiceAPIv2 controllerv2.ResourceControllerAPIV2 - - resourceManagementConfigErrv2 error - resourceManagementServiceAPIv2 managementv2.ResourceManagementAPIv2 - - resourceCatalogConfigErr error - resourceCatalogServiceAPI catalog.ResourceCatalogAPI - - powerConfigErr error - ibmpiConfigErr error - ibmpiSession *ibmpisession.IBMPISession - - kpErr error - kpAPI *kp.API - - kmsErr error - kmsAPI *kp.API - - hpcsEndpointErr error - hpcsEndpointAPI hpcs.HPCSV2 - - pDNSClient *dns.DnsSvcsV1 - pDNSErr error - - bluemixSessionErr error - - pushServiceClient *pushservicev1.PushServiceV1 - pushServiceClientErr error - - eventNotificationsApiClient *eventnotificationsv1.EventNotificationsV1 - eventNotificationsApiClientErr error - - appConfigurationClient *appconfigurationv1.AppConfigurationV1 - appConfigurationClientErr error - - vpcErr error - vpcAPI *vpc.VpcV1 - - directlinkAPI *dl.DirectLinkV1 - directlinkErr error - dlProviderAPI *dlProviderV2.DirectLinkProviderV2 - dlProviderErr error - - cosConfigErr error - cosConfigAPI *cosconfig.ResourceConfigurationV1 - - transitgatewayAPI *tg.TransitGatewayApisV1 - transitgatewayErr error - - functionIAMNamespaceAPI functions.FunctionServiceAPI - functionIAMNamespaceErr error - - // CIS Zones - cisZonesErr error - cisZonesV1Client *ciszonesv1.ZonesV1 - - // CIS dns service options - cisDNSErr error - cisDNSRecordsClient *cisdnsrecordsv1.DnsRecordsV1 - - // CIS dns bulk service options - cisDNSBulkErr error - cisDNSRecordBulkClient *cisdnsbulkv1.DnsRecordBulkV1 - - // CIS Global Load Balancer Pool service options - cisGLBPoolErr error - cisGLBPoolClient *cisglbpoolv0.GlobalLoadBalancerPoolsV0 - - // CIS GLB service options - cisGLBErr error - cisGLBClient *cisglbv1.GlobalLoadBalancerV1 - - // CIS GLB health check service options - cisGLBHealthCheckErr error - cisGLBHealthCheckClient *cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1 - - // CIS IP service options - cisIPErr error - cisIPClient *cisipv1.CisIpApiV1 - - // CIS Zone Rate Limits service options - cisRLErr error - cisRLClient *cisratelimitv1.ZoneRateLimitsV1 - - // CIS Page Rules service options - cisPageRuleErr error - cisPageRuleClient *cispagerulev1.PageRuleApiV1 - - // CIS Edge Functions service options - cisEdgeFunctionErr error - cisEdgeFunctionClient *cisedgefunctionv1.EdgeFunctionsApiV1 - - // CIS SSL certificate service options - cisSSLErr error - cisSSLClient *cissslv1.SslCertificateApiV1 - - // CIS WAF Package service options - cisWAFPackageErr error - cisWAFPackageClient *ciswafpackagev1.WafRulePackagesApiV1 - - // CIS Zone Setting service options - cisDomainSettingsErr error - cisDomainSettingsClient *cisdomainsettingsv1.ZonesSettingsV1 - - // CIS Routing service options - cisRoutingErr error - cisRoutingClient *cisroutingv1.RoutingV1 - - // CIS WAF Group service options - cisWAFGroupErr error - cisWAFGroupClient *ciswafgroupv1.WafRuleGroupsApiV1 - - // CIS Caching service options - cisCacheErr error - cisCacheClient *ciscachev1.CachingApiV1 - - // CIS Custom Pages service options - cisCustomPageErr error - cisCustomPageClient *ciscustompagev1.CustomPagesV1 - - // CIS Firewall Access rule service option - cisAccessRuleErr error - cisAccessRuleClient *cisaccessrulev1.ZoneFirewallAccessRulesV1 - - // CIS User Agent Blocking Rule service option - cisUARuleErr error - cisUARuleClient *cisuarulev1.UserAgentBlockingRulesV1 - - // CIS Firewall Lockdwon Rule service option - cisLockdownErr error - cisLockdownClient *cislockdownv1.ZoneLockdownV1 - - // CIS Range app service option - cisRangeAppErr error - cisRangeAppClient *cisrangeappv1.RangeApplicationsV1 - - // CIS WAF rule service options - cisWAFRuleErr error - cisWAFRuleClient *ciswafrulev1.WafRulesApiV1 - //IAM Identity Option - iamIdentityErr error - iamIdentityAPI *iamidentity.IamIdentityV1 - - //Resource Manager Option - resourceManagerErr error - resourceManagerAPI *resourcemanager.ResourceManagerV2 - - //Catalog Management Option - catalogManagementClient *catalogmanagementv1.CatalogManagementV1 - catalogManagementClientErr error - - enterpriseManagementClient *enterprisemanagementv1.EnterpriseManagementV1 - enterpriseManagementClientErr error - - //Resource Controller Option - resourceControllerErr error - resourceControllerAPI *resourcecontroller.ResourceControllerV2 - secretsManagerClient *secretsmanagerv1.SecretsManagerV1 - secretsManagerClientErr error - - // Schematics service options - schematicsClient *schematicsv1.SchematicsV1 - schematicsClientErr error - - //Satellite service - satelliteClient *kubernetesserviceapiv1.KubernetesServiceApiV1 - satelliteClientErr error - - //IAM Policy Management - iamPolicyManagementErr error - iamPolicyManagementAPI *iampolicymanagement.IamPolicyManagementV1 - - //IAM Access Groups - iamAccessGroupsErr error - iamAccessGroupsAPI *iamaccessgroups.IamAccessGroupsV2 - - // CIS Filters options - cisFiltersClient *cisfiltersv1.FiltersV1 - cisFiltersErr error - - // CIS FirewallRules options - cisFirewallRulesClient *cisfirewallrulesv1.FirewallRulesV1 - cisFirewallRulesErr error - - //Atracker - atrackerClient *atrackerv1.AtrackerV1 - atrackerClientErr error - - //Satellite link service - satelliteLinkClient *satellitelinkv1.SatelliteLinkV1 - satelliteLinkClientErr error - - esSchemaRegistryClient *schemaregistryv1.SchemaregistryV1 - esSchemaRegistryErr error - - // Security and Compliance Center (SCC) - findingsClient *findingsv1.FindingsV1 - findingsClientErr error - - //Security and Compliance Center (SCC) Compliance posture - postureManagementClientErr error - postureManagementClient *posturemanagementv1.PostureManagementV1 -} - -// AppIDAPI provides AppID Service APIs ... -func (session clientSession) AppIDAPI() (*appid.AppIDManagementV4, error) { - return session.appidAPI, session.appidErr -} - -func (session clientSession) CatalogManagementV1() (*catalogmanagementv1.CatalogManagementV1, error) { - return session.catalogManagementClient, session.catalogManagementClientErr -} - -// BluemixAcccountAPI ... -func (sess clientSession) BluemixAcccountAPI() (accountv2.AccountServiceAPI, error) { - return sess.bmxAccountServiceAPI, sess.accountConfigErr -} - -// BluemixAcccountAPI ... -func (sess clientSession) BluemixAcccountv1API() (accountv1.AccountServiceAPI, error) { - return sess.bmxAccountv1ServiceAPI, sess.accountV1ConfigErr -} - -// BluemixSession to provide the Bluemix Session -func (sess clientSession) BluemixSession() (*bxsession.Session, error) { - return sess.session.BluemixSession, sess.bluemixSessionErr -} - -// BluemixUserDetails ... -func (sess clientSession) BluemixUserDetails() (*UserConfig, error) { - return sess.bmxUserDetails, sess.bmxUserFetchErr -} - -// ContainerAPI provides Container Service APIs ... -func (sess clientSession) ContainerAPI() (containerv1.ContainerServiceAPI, error) { - return sess.csServiceAPI, sess.csConfigErr -} - -// VpcContainerAPI provides v2Container Service APIs ... -func (sess clientSession) VpcContainerAPI() (containerv2.ContainerServiceAPI, error) { - return sess.csv2ServiceAPI, sess.csv2ConfigErr -} - -// ContainerRegistryV1 provides Container Registry Service APIs ... -func (session clientSession) ContainerRegistryV1() (*containerregistryv1.ContainerRegistryV1, error) { - return session.containerRegistryClient, session.containerRegistryClientErr -} - -// SchematicsAPI provides schematics Service APIs ... -func (sess clientSession) SchematicsV1() (*schematicsv1.SchematicsV1, error) { - return sess.schematicsClient, sess.schematicsClientErr -} - -// FunctionClient ... -func (sess clientSession) FunctionClient() (*whisk.Client, error) { - return sess.functionClient, sess.functionConfigErr -} - -// GlobalSearchAPI provides Global Search APIs ... -func (sess clientSession) GlobalSearchAPI() (globalsearchv2.GlobalSearchServiceAPI, error) { - return sess.globalSearchServiceAPI, sess.globalSearchConfigErr -} - -// GlobalTaggingAPI provides Global Search APIs ... -func (sess clientSession) GlobalTaggingAPI() (globaltaggingv3.GlobalTaggingServiceAPI, error) { - return sess.globalTaggingServiceAPI, sess.globalTaggingConfigErr -} - -// GlobalTaggingAPIV1 provides Platform-go Global Tagging APIs ... -func (sess clientSession) GlobalTaggingAPIv1() (globaltaggingv1.GlobalTaggingV1, error) { - return sess.globalTaggingServiceAPIV1, sess.globalTaggingConfigErrV1 -} - -// HpcsEndpointAPI provides Hpcs Endpoint generator APIs ... -func (sess clientSession) HpcsEndpointAPI() (hpcs.HPCSV2, error) { - return sess.hpcsEndpointAPI, sess.hpcsEndpointErr -} - -// UserManagementAPI provides User management APIs ... -func (sess clientSession) UserManagementAPI() (usermanagementv2.UserManagementAPI, error) { - return sess.userManagementAPI, sess.userManagementErr -} - -// IAMAPI provides IAM PAP APIs ... -func (sess clientSession) IAMAPI() (iamv1.IAMServiceAPI, error) { - return sess.iamServiceAPI, sess.iamConfigErr -} - -// IAM Policy Management -func (sess clientSession) IAMPolicyManagementV1API() (*iampolicymanagement.IamPolicyManagementV1, error) { - return sess.iamPolicyManagementAPI, sess.iamPolicyManagementErr -} - -// IAMAccessGroupsV2 provides IAM AG APIs ... -func (sess clientSession) IAMAccessGroupsV2() (*iamaccessgroups.IamAccessGroupsV2, error) { - return sess.iamAccessGroupsAPI, sess.iamAccessGroupsErr -} - -// IBM Cloud Shell -func (session clientSession) IBMCloudShellV1() (*ibmcloudshellv1.IBMCloudShellV1, error) { - return session.ibmCloudShellClient, session.ibmCloudShellClientErr -} - -// IcdAPI provides IBM Cloud Databases APIs ... -func (sess clientSession) ICDAPI() (icdv4.ICDServiceAPI, error) { - return sess.icdServiceAPI, sess.icdConfigErr -} - -// MccpAPI provides Multi Cloud Controller Proxy APIs ... -func (sess clientSession) MccpAPI() (mccpv2.MccpServiceAPI, error) { - return sess.cfServiceAPI, sess.cfConfigErr -} - -// ResourceCatalogAPI ... -func (sess clientSession) ResourceCatalogAPI() (catalog.ResourceCatalogAPI, error) { - return sess.resourceCatalogServiceAPI, sess.resourceCatalogConfigErr -} - -// ResourceManagementAPIv2 ... -func (sess clientSession) ResourceManagementAPIv2() (managementv2.ResourceManagementAPIv2, error) { - return sess.resourceManagementServiceAPIv2, sess.resourceManagementConfigErrv2 -} - -// ResourceControllerAPI ... -func (sess clientSession) ResourceControllerAPI() (controller.ResourceControllerAPI, error) { - return sess.resourceControllerServiceAPI, sess.resourceControllerConfigErr -} - -// ResourceControllerAPIv2 ... -func (sess clientSession) ResourceControllerAPIV2() (controllerv2.ResourceControllerAPIV2, error) { - return sess.resourceControllerServiceAPIv2, sess.resourceControllerConfigErrv2 -} - -// SoftLayerSession providers SoftLayer Session -func (sess clientSession) SoftLayerSession() *slsession.Session { - return sess.session.SoftLayerSession -} - -// CertManagementAPI provides Certificate management APIs ... -func (sess clientSession) CertificateManagerAPI() (certificatemanager.CertificateManagerServiceAPI, error) { - return sess.certManagementAPI, sess.certManagementErr -} - -//apigatewayAPI provides API Gateway APIs -func (sess clientSession) APIGateway() (*apigateway.ApiGatewayControllerApiV1, error) { - return sess.apigatewayAPI, sess.apigatewayErr -} - -func (session clientSession) PushServiceV1() (*pushservicev1.PushServiceV1, error) { - return session.pushServiceClient, session.pushServiceClientErr -} - -func (session clientSession) EventNotificationsApiV1() (*eventnotificationsv1.EventNotificationsV1, error) { - return session.eventNotificationsApiClient, session.eventNotificationsApiClientErr -} - -func (session clientSession) AppConfigurationV1() (*appconfigurationv1.AppConfigurationV1, error) { - return session.appConfigurationClient, session.appConfigurationClientErr -} - -func (sess clientSession) keyProtectAPI() (*kp.Client, error) { - return sess.kpAPI, sess.kpErr -} - -func (sess clientSession) keyManagementAPI() (*kp.Client, error) { - return sess.kmsAPI, sess.kmsErr -} - -func (sess clientSession) VpcV1API() (*vpc.VpcV1, error) { - return sess.vpcAPI, sess.vpcErr -} - -func (sess clientSession) DirectlinkV1API() (*dl.DirectLinkV1, error) { - return sess.directlinkAPI, sess.directlinkErr -} -func (sess clientSession) DirectlinkProviderV2API() (*dlProviderV2.DirectLinkProviderV2, error) { - return sess.dlProviderAPI, sess.dlProviderErr -} -func (sess clientSession) CosConfigV1API() (*cosconfig.ResourceConfigurationV1, error) { - return sess.cosConfigAPI, sess.cosConfigErr -} - -func (sess clientSession) TransitGatewayV1API() (*tg.TransitGatewayApisV1, error) { - return sess.transitgatewayAPI, sess.transitgatewayErr -} - -// Session to the Power Colo Service - -func (sess clientSession) IBMPISession() (*ibmpisession.IBMPISession, error) { - return sess.ibmpiSession, sess.powerConfigErr -} - -// Private DNS Service - -func (sess clientSession) PrivateDNSClientSession() (*dns.DnsSvcsV1, error) { - return sess.pDNSClient, sess.pDNSErr -} - -// Session to the Namespace cloud function - -func (sess clientSession) FunctionIAMNamespaceAPI() (functions.FunctionServiceAPI, error) { - return sess.functionIAMNamespaceAPI, sess.functionIAMNamespaceErr -} - -// CIS Zones Service -func (sess clientSession) CisZonesV1ClientSession() (*ciszonesv1.ZonesV1, error) { - if sess.cisZonesErr != nil { - return sess.cisZonesV1Client, sess.cisZonesErr - } - return sess.cisZonesV1Client.Clone(), nil -} - -// CIS DNS Service -func (sess clientSession) CisDNSRecordClientSession() (*cisdnsrecordsv1.DnsRecordsV1, error) { - if sess.cisDNSErr != nil { - return sess.cisDNSRecordsClient, sess.cisDNSErr - } - return sess.cisDNSRecordsClient.Clone(), nil -} - -// CIS DNS Bulk Service -func (sess clientSession) CisDNSRecordBulkClientSession() (*cisdnsbulkv1.DnsRecordBulkV1, error) { - if sess.cisDNSBulkErr != nil { - return sess.cisDNSRecordBulkClient, sess.cisDNSBulkErr - } - return sess.cisDNSRecordBulkClient.Clone(), nil -} - -// CIS GLB Pool -func (sess clientSession) CisGLBPoolClientSession() (*cisglbpoolv0.GlobalLoadBalancerPoolsV0, error) { - if sess.cisGLBPoolErr != nil { - return sess.cisGLBPoolClient, sess.cisGLBPoolErr - } - return sess.cisGLBPoolClient.Clone(), nil -} - -// CIS GLB -func (sess clientSession) CisGLBClientSession() (*cisglbv1.GlobalLoadBalancerV1, error) { - if sess.cisGLBErr != nil { - return sess.cisGLBClient, sess.cisGLBErr - } - return sess.cisGLBClient.Clone(), nil -} - -// CIS GLB Health Check/Monitor -func (sess clientSession) CisGLBHealthCheckClientSession() (*cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1, error) { - if sess.cisGLBHealthCheckErr != nil { - return sess.cisGLBHealthCheckClient, sess.cisGLBHealthCheckErr - } - return sess.cisGLBHealthCheckClient.Clone(), nil -} - -// CIS Zone Rate Limits -func (sess clientSession) CisRLClientSession() (*cisratelimitv1.ZoneRateLimitsV1, error) { - if sess.cisRLErr != nil { - return sess.cisRLClient, sess.cisRLErr - } - return sess.cisRLClient.Clone(), nil -} - -// CIS IP -func (sess clientSession) CisIPClientSession() (*cisipv1.CisIpApiV1, error) { - if sess.cisIPErr != nil { - return sess.cisIPClient, sess.cisIPErr - } - return sess.cisIPClient.Clone(), nil -} - -// CIS Page Rules -func (sess clientSession) CisPageRuleClientSession() (*cispagerulev1.PageRuleApiV1, error) { - if sess.cisPageRuleErr != nil { - return sess.cisPageRuleClient, sess.cisPageRuleErr - } - return sess.cisPageRuleClient.Clone(), nil -} - -// CIS Edge Function -func (sess clientSession) CisEdgeFunctionClientSession() (*cisedgefunctionv1.EdgeFunctionsApiV1, error) { - if sess.cisEdgeFunctionErr != nil { - return sess.cisEdgeFunctionClient, sess.cisEdgeFunctionErr - } - return sess.cisEdgeFunctionClient.Clone(), nil -} - -// CIS SSL certificate -func (sess clientSession) CisSSLClientSession() (*cissslv1.SslCertificateApiV1, error) { - if sess.cisSSLErr != nil { - return sess.cisSSLClient, sess.cisSSLErr - } - return sess.cisSSLClient.Clone(), nil -} - -// CIS WAF Packages -func (sess clientSession) CisWAFPackageClientSession() (*ciswafpackagev1.WafRulePackagesApiV1, error) { - if sess.cisWAFPackageErr != nil { - return sess.cisWAFPackageClient, sess.cisWAFPackageErr - } - return sess.cisWAFPackageClient.Clone(), nil -} - -// CIS Zone Settings -func (sess clientSession) CisDomainSettingsClientSession() (*cisdomainsettingsv1.ZonesSettingsV1, error) { - if sess.cisDomainSettingsErr != nil { - return sess.cisDomainSettingsClient, sess.cisDomainSettingsErr - } - return sess.cisDomainSettingsClient.Clone(), nil -} - -// CIS Routing -func (sess clientSession) CisRoutingClientSession() (*cisroutingv1.RoutingV1, error) { - if sess.cisRoutingErr != nil { - return sess.cisRoutingClient, sess.cisRoutingErr - } - return sess.cisRoutingClient.Clone(), nil -} - -// CIS WAF Group -func (sess clientSession) CisWAFGroupClientSession() (*ciswafgroupv1.WafRuleGroupsApiV1, error) { - if sess.cisWAFGroupErr != nil { - return sess.cisWAFGroupClient, sess.cisWAFGroupErr - } - return sess.cisWAFGroupClient.Clone(), nil -} - -// CIS Cache service -func (sess clientSession) CisCacheClientSession() (*ciscachev1.CachingApiV1, error) { - if sess.cisCacheErr != nil { - return sess.cisCacheClient, sess.cisCacheErr - } - return sess.cisCacheClient.Clone(), nil -} - -// CIS Zone Settings -func (sess clientSession) CisCustomPageClientSession() (*ciscustompagev1.CustomPagesV1, error) { - if sess.cisCustomPageErr != nil { - return sess.cisCustomPageClient, sess.cisCustomPageErr - } - return sess.cisCustomPageClient.Clone(), nil -} - -// CIS Firewall access rule -func (sess clientSession) CisAccessRuleClientSession() (*cisaccessrulev1.ZoneFirewallAccessRulesV1, error) { - if sess.cisAccessRuleErr != nil { - return sess.cisAccessRuleClient, sess.cisAccessRuleErr - } - return sess.cisAccessRuleClient.Clone(), nil -} - -// CIS User Agent Blocking rule -func (sess clientSession) CisUARuleClientSession() (*cisuarulev1.UserAgentBlockingRulesV1, error) { - if sess.cisUARuleErr != nil { - return sess.cisUARuleClient, sess.cisUARuleErr - } - return sess.cisUARuleClient.Clone(), nil -} - -// CIS Firewall Lockdown rule -func (sess clientSession) CisLockdownClientSession() (*cislockdownv1.ZoneLockdownV1, error) { - if sess.cisLockdownErr != nil { - return sess.cisLockdownClient, sess.cisLockdownErr - } - return sess.cisLockdownClient.Clone(), nil -} - -// CIS Range app rule -func (sess clientSession) CisRangeAppClientSession() (*cisrangeappv1.RangeApplicationsV1, error) { - if sess.cisRangeAppErr != nil { - return sess.cisRangeAppClient, sess.cisRangeAppErr - } - return sess.cisRangeAppClient.Clone(), nil -} - -// CIS WAF Rule -func (sess clientSession) CisWAFRuleClientSession() (*ciswafrulev1.WafRulesApiV1, error) { - if sess.cisWAFRuleErr != nil { - return sess.cisWAFRuleClient, sess.cisWAFRuleErr - } - return sess.cisWAFRuleClient.Clone(), nil -} - -// IAM Identity Session -func (sess clientSession) IAMIdentityV1API() (*iamidentity.IamIdentityV1, error) { - return sess.iamIdentityAPI, sess.iamIdentityErr -} - -// ResourceMAanger Session -func (sess clientSession) ResourceManagerV2API() (*resourcemanager.ResourceManagerV2, error) { - return sess.resourceManagerAPI, sess.resourceManagerErr -} - -func (session clientSession) EnterpriseManagementV1() (*enterprisemanagementv1.EnterpriseManagementV1, error) { - return session.enterpriseManagementClient, session.enterpriseManagementClientErr -} - -// ResourceController Session -func (sess clientSession) ResourceControllerV2API() (*resourcecontroller.ResourceControllerV2, error) { - return sess.resourceControllerAPI, sess.resourceControllerErr -} - -// SecretsManager Session -func (session clientSession) SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) { - return session.secretsManagerClient, session.secretsManagerClientErr -} - -// Satellite Link -func (session clientSession) SatellitLinkClientSession() (*satellitelinkv1.SatelliteLinkV1, error) { - return session.satelliteLinkClient, session.satelliteLinkClientErr -} - -var cloudEndpoint = "cloud.ibm.com" - -// Session to the Satellite client -func (sess clientSession) SatelliteClientSession() (*kubernetesserviceapiv1.KubernetesServiceApiV1, error) { - return sess.satelliteClient, sess.satelliteClientErr -} - -// CIS Filters -func (sess clientSession) CisFiltersSession() (*cisfiltersv1.FiltersV1, error) { - if sess.cisFiltersErr != nil { - return sess.cisFiltersClient, sess.cisFiltersErr - } - return sess.cisFiltersClient.Clone(), nil -} - -// CIS FirewallRules -func (sess clientSession) CisFirewallRulesSession() (*cisfirewallrulesv1.FirewallRulesV1, error) { - if sess.cisFirewallRulesErr != nil { - return sess.cisFirewallRulesClient, sess.cisFirewallRulesErr - } - return sess.cisFirewallRulesClient.Clone(), nil -} - -// Activity Tracker API -func (session clientSession) AtrackerV1() (*atrackerv1.AtrackerV1, error) { - return session.atrackerClient, session.atrackerClientErr -} - -func (session clientSession) ESschemaRegistrySession() (*schemaregistryv1.SchemaregistryV1, error) { - return session.esSchemaRegistryClient, session.esSchemaRegistryErr -} - -// Security and Compliance center Findings API -func (session clientSession) FindingsV1() (*findingsv1.FindingsV1, error) { - if session.findingsClientErr != nil { - return session.findingsClient, session.findingsClientErr - } - return session.findingsClient.Clone(), nil -} - -// Security and Compliance center Posture Management -func (session clientSession) PostureManagementV1() (*posturemanagementv1.PostureManagementV1, error) { - if session.postureManagementClientErr != nil { - return session.postureManagementClient, session.postureManagementClientErr - } - return session.postureManagementClient.Clone(), nil -} - -// ClientSession configures and returns a fully initialized ClientSession -func (c *Config) ClientSession() (interface{}, error) { - sess, err := newSession(c) - if err != nil { - return nil, err - } - log.Printf("[INFO] Configured Region: %s\n", c.Region) - session := clientSession{ - session: sess, - } - - if sess.BluemixSession == nil { - //Can be nil only if bluemix_api_key is not provided - log.Println("Skipping Bluemix Clients configuration") - session.bluemixSessionErr = errEmptyBluemixCredentials - session.accountConfigErr = errEmptyBluemixCredentials - session.accountV1ConfigErr = errEmptyBluemixCredentials - session.csConfigErr = errEmptyBluemixCredentials - session.csv2ConfigErr = errEmptyBluemixCredentials - session.containerRegistryClientErr = errEmptyBluemixCredentials - session.kpErr = errEmptyBluemixCredentials - session.pushServiceClientErr = errEmptyBluemixCredentials - session.appConfigurationClientErr = errEmptyBluemixCredentials - session.kmsErr = errEmptyBluemixCredentials - session.cfConfigErr = errEmptyBluemixCredentials - session.cisConfigErr = errEmptyBluemixCredentials - session.functionConfigErr = errEmptyBluemixCredentials - session.globalSearchConfigErr = errEmptyBluemixCredentials - session.globalTaggingConfigErr = errEmptyBluemixCredentials - session.globalTaggingConfigErrV1 = errEmptyBluemixCredentials - session.hpcsEndpointErr = errEmptyBluemixCredentials - session.iamAccessGroupsErr = errEmptyBluemixCredentials - session.icdConfigErr = errEmptyBluemixCredentials - session.resourceCatalogConfigErr = errEmptyBluemixCredentials - session.resourceManagerErr = errEmptyBluemixCredentials - session.resourceManagementConfigErrv2 = errEmptyBluemixCredentials - session.resourceControllerConfigErr = errEmptyBluemixCredentials - session.resourceControllerConfigErrv2 = errEmptyBluemixCredentials - session.enterpriseManagementClientErr = errEmptyBluemixCredentials - session.resourceControllerErr = errEmptyBluemixCredentials - session.catalogManagementClientErr = errEmptyBluemixCredentials - session.powerConfigErr = errEmptyBluemixCredentials - session.ibmpiConfigErr = errEmptyBluemixCredentials - session.iamConfigErr = errEmptyBluemixCredentials - session.userManagementErr = errEmptyBluemixCredentials - session.certManagementErr = errEmptyBluemixCredentials - session.vpcErr = errEmptyBluemixCredentials - session.apigatewayErr = errEmptyBluemixCredentials - session.pDNSErr = errEmptyBluemixCredentials - session.bmxUserFetchErr = errEmptyBluemixCredentials - session.directlinkErr = errEmptyBluemixCredentials - session.dlProviderErr = errEmptyBluemixCredentials - session.cosConfigErr = errEmptyBluemixCredentials - session.transitgatewayErr = errEmptyBluemixCredentials - session.functionIAMNamespaceErr = errEmptyBluemixCredentials - session.cisDNSErr = errEmptyBluemixCredentials - session.cisDNSBulkErr = errEmptyBluemixCredentials - session.cisGLBPoolErr = errEmptyBluemixCredentials - session.cisGLBErr = errEmptyBluemixCredentials - session.cisGLBHealthCheckErr = errEmptyBluemixCredentials - session.cisIPErr = errEmptyBluemixCredentials - session.cisZonesErr = errEmptyBluemixCredentials - session.cisRLErr = errEmptyBluemixCredentials - session.cisPageRuleErr = errEmptyBluemixCredentials - session.cisEdgeFunctionErr = errEmptyBluemixCredentials - session.cisSSLErr = errEmptyBluemixCredentials - session.cisWAFPackageErr = errEmptyBluemixCredentials - session.cisDomainSettingsErr = errEmptyBluemixCredentials - session.cisRoutingErr = errEmptyBluemixCredentials - session.cisWAFGroupErr = errEmptyBluemixCredentials - session.cisCacheErr = errEmptyBluemixCredentials - session.cisCustomPageErr = errEmptyBluemixCredentials - session.cisAccessRuleErr = errEmptyBluemixCredentials - session.cisUARuleErr = errEmptyBluemixCredentials - session.cisLockdownErr = errEmptyBluemixCredentials - session.cisRangeAppErr = errEmptyBluemixCredentials - session.cisWAFRuleErr = errEmptyBluemixCredentials - session.iamIdentityErr = errEmptyBluemixCredentials - session.secretsManagerClientErr = errEmptyBluemixCredentials - session.cisFiltersErr = errEmptyBluemixCredentials - session.schematicsClientErr = errEmptyBluemixCredentials - session.satelliteClientErr = errEmptyBluemixCredentials - session.iamPolicyManagementErr = errEmptyBluemixCredentials - session.satelliteLinkClientErr = errEmptyBluemixCredentials - session.esSchemaRegistryErr = errEmptyBluemixCredentials - - return session, nil - } - - if sess.BluemixSession.Config.BluemixAPIKey != "" { - err = authenticateAPIKey(sess.BluemixSession) - if err != nil { - for count := c.RetryCount; count >= 0; count-- { - if err == nil || !isRetryable(err) { - break - } - time.Sleep(c.RetryDelay) - log.Printf("Retrying IAM Authentication %d", count) - err = authenticateAPIKey(sess.BluemixSession) - } - if err != nil { - session.bmxUserFetchErr = fmt.Errorf("Error occured while fetching auth key for account user details: %q", err) - session.functionConfigErr = fmt.Errorf("Error occured while fetching auth key for function: %q", err) - session.powerConfigErr = fmt.Errorf("Error occured while fetching the auth key for power iaas: %q", err) - session.ibmpiConfigErr = fmt.Errorf("Error occured while fetching the auth key for power iaas: %q", err) - } - } - err = authenticateCF(sess.BluemixSession) - if err != nil { - for count := c.RetryCount; count >= 0; count-- { - if err == nil || !isRetryable(err) { - break - } - time.Sleep(c.RetryDelay) - log.Printf("Retrying CF Authentication %d", count) - err = authenticateCF(sess.BluemixSession) - } - if err != nil { - session.functionConfigErr = fmt.Errorf("Error occured while fetching auth key for function: %q", err) - } - } - } - - if sess.BluemixSession.Config.IAMAccessToken != "" && sess.BluemixSession.Config.BluemixAPIKey == "" { - err := refreshToken(sess.BluemixSession) - if err != nil { - for count := c.RetryCount; count >= 0; count-- { - if err == nil || !isRetryable(err) { - break - } - time.Sleep(c.RetryDelay) - log.Printf("Retrying refresh token %d", count) - err = refreshToken(sess.BluemixSession) - } - if err != nil { - return nil, fmt.Errorf("Error occured while refreshing the token: %q", err) - } - } - - } - userConfig, err := fetchUserDetails(sess.BluemixSession, c.RetryCount, c.RetryDelay) - if err != nil { - session.bmxUserFetchErr = fmt.Errorf("Error occured while fetching account user details: %q", err) - } - session.bmxUserDetails = userConfig - - if sess.SoftLayerSession != nil && sess.SoftLayerSession.IAMToken != "" { - sess.SoftLayerSession.IAMToken = sess.BluemixSession.Config.IAMAccessToken - sess.SoftLayerSession.IAMRefreshToken = sess.BluemixSession.Config.IAMRefreshToken - } - - session.functionClient, session.functionConfigErr = FunctionClient(sess.BluemixSession.Config) - - BluemixRegion = sess.BluemixSession.Config.Region - var fileMap map[string]interface{} - if f := envFallBack([]string{"IBMCLOUD_ENDPOINTS_FILE_PATH", "IC_ENDPOINTS_FILE_PATH"}, c.EndpointsFile); f != "" { - jsonFile, err := os.Open(f) - if err != nil { - log.Fatalf("Unable to open Endpoints File %s", err) - } - defer jsonFile.Close() - bytes, err := ioutil.ReadAll(jsonFile) - if err != nil { - log.Fatalf("Unable to read Endpoints File %s", err) - } - err = json.Unmarshal([]byte(bytes), &fileMap) - if err != nil { - log.Fatalf("Unable to unmarshal Endpoints File %s", err) - } - } - accv1API, err := accountv1.New(sess.BluemixSession) - if err != nil { - session.accountV1ConfigErr = fmt.Errorf("Error occured while configuring Bluemix Accountv1 Service: %q", err) - } - session.bmxAccountv1ServiceAPI = accv1API - - accAPI, err := accountv2.New(sess.BluemixSession) - if err != nil { - session.accountConfigErr = fmt.Errorf("Error occured while configuring Account Service: %q", err) - } - session.bmxAccountServiceAPI = accAPI - - cfAPI, err := mccpv2.New(sess.BluemixSession) - if err != nil { - session.cfConfigErr = fmt.Errorf("Error occured while configuring MCCP service: %q", err) - } - session.cfServiceAPI = cfAPI - - clusterAPI, err := containerv1.New(sess.BluemixSession) - if err != nil { - session.csConfigErr = fmt.Errorf("Error occured while configuring Container Service for K8s cluster: %q", err) - } - session.csServiceAPI = clusterAPI - - v2clusterAPI, err := containerv2.New(sess.BluemixSession) - if err != nil { - session.csv2ConfigErr = fmt.Errorf("Error occured while configuring vpc Container Service for K8s cluster: %q", err) - } - session.csv2ServiceAPI = v2clusterAPI - - hpcsAPI, err := hpcs.New(sess.BluemixSession) - if err != nil { - session.hpcsEndpointErr = fmt.Errorf("Error occured while configuring hpcs Endpoint: %q", err) - } - session.hpcsEndpointAPI = hpcsAPI - - kpurl := contructEndpoint(fmt.Sprintf("%s.kms", c.Region), cloudEndpoint) - if c.Visibility == "private" || c.Visibility == "public-and-private" { - kpurl = contructEndpoint(fmt.Sprintf("private.%s.kms", c.Region), cloudEndpoint) - } - if fileMap != nil && c.Visibility != "public-and-private" { - kpurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_KP_API_ENDPOINT", c.Region, kpurl) - } - var options kp.ClientConfig - if c.BluemixAPIKey != "" { - options = kp.ClientConfig{ - BaseURL: envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kpurl), - APIKey: sess.BluemixSession.Config.BluemixAPIKey, //pragma: allowlist secret - // InstanceID: "42fET57nnadurKXzXAedFLOhGqETfIGYxOmQXkFgkJV9", - Verbose: kp.VerboseFailOnly, - } - - } else { - options = kp.ClientConfig{ - BaseURL: envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kpurl), - Authorization: sess.BluemixSession.Config.IAMAccessToken, - // InstanceID: "42fET57nnadurKXzXAedFLOhGqETfIGYxOmQXkFgkJV9", - Verbose: kp.VerboseFailOnly, - } - } - kpAPIclient, err := kp.New(options, kp.DefaultTransport()) - if err != nil { - session.kpErr = fmt.Errorf("Error occured while configuring Key Protect Service: %q", err) - } - session.kpAPI = kpAPIclient - - // KEY MANAGEMENT Service - kmsurl := contructEndpoint(fmt.Sprintf("%s.kms", c.Region), cloudEndpoint) - if c.Visibility == "private" || c.Visibility == "public-and-private" { - kmsurl = contructEndpoint(fmt.Sprintf("private.%s.kms", c.Region), cloudEndpoint) - } - if fileMap != nil && c.Visibility != "public-and-private" { - kmsurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_KP_API_ENDPOINT", c.Region, kmsurl) - } - var kmsOptions kp.ClientConfig - if c.BluemixAPIKey != "" { - kmsOptions = kp.ClientConfig{ - BaseURL: envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kmsurl), - APIKey: sess.BluemixSession.Config.BluemixAPIKey, //pragma: allowlist secret - // InstanceID: "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8", - Verbose: kp.VerboseFailOnly, - } - - } else { - kmsOptions = kp.ClientConfig{ - BaseURL: envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kmsurl), - Authorization: sess.BluemixSession.Config.IAMAccessToken, - // InstanceID: "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8", - Verbose: kp.VerboseFailOnly, - } - } - kmsAPIclient, err := kp.New(kmsOptions, DefaultTransport()) - if err != nil { - session.kmsErr = fmt.Errorf("Error occured while configuring key Service: %q", err) - } - session.kmsAPI = kmsAPIclient - - var authenticator core.Authenticator - - if c.BluemixAPIKey != "" { - iamURL := iamidentity.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - iamURL = contructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) - } else { - iamURL = contructEndpoint("private.iam", cloudEndpoint) - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - iamURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamURL) - } - authenticator = &core.IamAuthenticator{ - ApiKey: c.BluemixAPIKey, - URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL) + "/identity/token", - } - } else if strings.HasPrefix(sess.BluemixSession.Config.IAMAccessToken, "Bearer") { - authenticator = &core.BearerTokenAuthenticator{ - BearerToken: sess.BluemixSession.Config.IAMAccessToken[7:], - } - } else { - authenticator = &core.BearerTokenAuthenticator{ - BearerToken: sess.BluemixSession.Config.IAMAccessToken, - } - } - - // APPID Service - appIDEndpoint := fmt.Sprintf("https://%s.appid.cloud.ibm.com", c.Region) - if c.Visibility == "private" { - session.appidErr = fmt.Errorf("App Id resources doesnot support private endpoints") - } - if fileMap != nil && c.Visibility != "public-and-private" { - appIDEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_APPID_MANAGEMENT_API_ENDPOINT", c.Region, appIDEndpoint) - } - appIDClientOptions := &appid.AppIDManagementV4Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_APPID_MANAGEMENT_API_ENDPOINT"}, appIDEndpoint), - } - appIDClient, err := appid.NewAppIDManagementV4(appIDClientOptions) - if err != nil { - session.appidErr = fmt.Errorf("error occured while configuring AppID service: #{err}") - } - if appIDClient != nil { - appIDClient.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.appidAPI = appIDClient - - // CATALOG MANAGEMENT Service - catalogManagementURL := "https://cm.globalcatalog.cloud.ibm.com/api/v1-beta" - if c.Visibility == "private" { - session.catalogManagementClientErr = fmt.Errorf("Catalog Management resource doesnot support private endpoints") - } - if fileMap != nil && c.Visibility != "public-and-private" { - catalogManagementURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CATALOG_MANAGEMENT_API_ENDPOINT", c.Region, catalogManagementURL) - } - catalogManagementClientOptions := &catalogmanagementv1.CatalogManagementV1Options{ - URL: envFallBack([]string{"IBMCLOUD_CATALOG_MANAGEMENT_API_ENDPOINT"}, catalogManagementURL), - Authenticator: authenticator, - } - // Construct the service client. - session.catalogManagementClient, err = catalogmanagementv1.NewCatalogManagementV1(catalogManagementClientOptions) - if err == nil { - // Enable retries for API calls - session.catalogManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.catalogManagementClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.catalogManagementClientErr = fmt.Errorf("Error occurred while configuring Catalog Management API service: %q", err) - } - - // ATRACKER Service - var atrackerClientURL string - atrackerClientURL, err = atrackerv1.GetServiceURLForRegion(c.Region) - if err != nil { - session.atrackerClientErr = err - } - if c.Visibility == "private" || c.Visibility == "public-and-private" { - atrackerClientURL, err = atrackerv1.GetServiceURLForRegion("private." + c.Region) - if err != nil && c.Visibility == "public-and-private" { - atrackerClientURL, err = atrackerv1.GetServiceURLForRegion(c.Region) - if err != nil { - session.atrackerClientErr = err - } - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - atrackerClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_ATRACKER_API_ENDPOINT", c.Region, atrackerClientURL) - } - atrackerClientOptions := &atrackerv1.AtrackerV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_ATRACKER_API_ENDPOINT"}, atrackerClientURL), - } - // Construct the service client. - session.atrackerClient, err = atrackerv1.NewAtrackerV1(atrackerClientOptions) - if err == nil { - // Enable retries for API calls - session.atrackerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.atrackerClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.atrackerClientErr = fmt.Errorf("Error occurred while configuring Activity Tracker API service: %q", err) - } - - // SCC FINDINGS Service - var findingsClientURL string - if c.Visibility == "public" || c.Visibility == "public-and-private" { - findingsClientURL, err = findingsv1.GetServiceURLForRegion(c.Region) - if err != nil { - session.findingsClientErr = fmt.Errorf("Error occurred while configuring Security Insights Findings API service: `%s` region not supported", c.Region) - } - } else { - session.findingsClientErr = fmt.Errorf("Error occurred while configuring Security Insights Findings API service: `%v` visibility not supported", c.Visibility) - } - if fileMap != nil && c.Visibility != "public-and-private" { - findingsClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SCC_FINDINGS_API_ENDPOINT", c.Region, findingsClientURL) - } - findingsClientOptions := &findingsv1.FindingsV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_SCC_FINDINGS_API_ENDPOINT"}, findingsClientURL), - AccountID: core.StringPtr(userConfig.userAccount), - } - // Construct the service client. - session.findingsClient, err = findingsv1.NewFindingsV1(findingsClientOptions) - if err == nil { - // Enable retries for API calls - session.findingsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.findingsClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.findingsClientErr = fmt.Errorf("Error occurred while configuring Security Insights Findings API service: %q", err) - } - - // SCHEMATICS Service - schematicsEndpoint := "https://schematics.cloud.ibm.com" - if c.Visibility == "private" || c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - schematicsEndpoint = contructEndpoint("private-us.schematics", cloudEndpoint) - } else if c.Region == "eu-gb" || c.Region == "eu-de" { - schematicsEndpoint = contructEndpoint("private-eu.schematics", cloudEndpoint) - } else { - schematicsEndpoint = "https://schematics.cloud.ibm.com" - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - schematicsEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SCHEMATICS_API_ENDPOINT", c.Region, schematicsEndpoint) - } - schematicsClientOptions := &schematicsv1.SchematicsV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_SCHEMATICS_API_ENDPOINT"}, schematicsEndpoint), - } - // Construct the service client. - schematicsClient, err := schematicsv1.NewSchematicsV1(schematicsClientOptions) - // Enable retries for API calls - if schematicsClient != nil && schematicsClient.Service != nil { - schematicsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - if err != nil { - session.schematicsClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Schematics Service API service: %q", err) - } - } - session.schematicsClient = schematicsClient - - // VPC Service - vpcurl := contructEndpoint(fmt.Sprintf("%s.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) - if c.Visibility == "private" { - if c.Region == "us-south" || c.Region == "us-east" { - vpcurl = contructEndpoint(fmt.Sprintf("%s.private.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) - } else { - session.vpcErr = fmt.Errorf("[ERROR] VPC supports private endpoints only in us-south and us-east") - } - } - if c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - vpcurl = contructEndpoint(fmt.Sprintf("%s.private.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) - } - vpcurl = contructEndpoint(fmt.Sprintf("%s.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - vpcurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IS_NG_API_ENDPOINT", c.Region, vpcurl) - } - vpcoptions := &vpc.VpcV1Options{ - URL: envFallBack([]string{"IBMCLOUD_IS_NG_API_ENDPOINT"}, vpcurl), - Authenticator: authenticator, - } - vpcclient, err := vpc.NewVpcV1(vpcoptions) - if err != nil { - session.vpcErr = fmt.Errorf("[ERROR] Error occured while configuring vpc service: %q", err) - } - if vpcclient != nil && vpcclient.Service != nil { - vpcclient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.vpcAPI = vpcclient - - // PUSH NOTIFICATIONS Service - pnurl := fmt.Sprintf("https://%s.imfpush.cloud.ibm.com/imfpush/v1", c.Region) - if c.Visibility == "private" { - session.pushServiceClientErr = fmt.Errorf("Push Notifications Service API doesnot support private endpoints") - } - if fileMap != nil && c.Visibility != "public-and-private" { - pnurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_PUSH_API_ENDPOINT", c.Region, pnurl) - } - pushNotificationOptions := &pushservicev1.PushServiceV1Options{ - URL: envFallBack([]string{"IBMCLOUD_PUSH_API_ENDPOINT"}, pnurl), - Authenticator: authenticator, - } - pnclient, err := pushservicev1.NewPushServiceV1(pushNotificationOptions) - if pnclient != nil { - // Enable retries for API calls - pnclient.EnableRetries(c.RetryCount, c.RetryDelay) - session.pushServiceClient = pnclient - } else { - session.pushServiceClientErr = fmt.Errorf("[ERROR] Error occured while configuring Push Notifications service: %q", err) - } - - // event notifications - enurl := fmt.Sprintf("https://%s.event-notifications.cloud.ibm.com/event-notifications", c.Region) - if c.Visibility == "private" { - session.eventNotificationsApiClientErr = fmt.Errorf("Event Notifications Service does not support private endpoints") - } - if fileMap != nil && c.Visibility != "public-and-private" { - enurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_EVENT_NOTIFICATIONS_API_ENDPOINT", c.Region, enurl) - } - enClientOptions := &eventnotificationsv1.EventNotificationsV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_EVENT_NOTIFICATIONS_API_ENDPOINT"}, enurl), - } - // Construct the service client. - session.eventNotificationsApiClient, err = eventnotificationsv1.NewEventNotificationsV1(enClientOptions) - if err == nil { - // Enable retries for API calls - session.eventNotificationsApiClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } else { - session.eventNotificationsApiClientErr = fmt.Errorf("Error occurred while configuring Event Notifications service: %q", err) - } - - // APP CONFIGURATION Service - if c.Visibility == "private" { - session.appConfigurationClientErr = fmt.Errorf("[ERROR] App Configuration Service API doesnot support private endpoints") - } - appConfigurationClientOptions := &appconfigurationv1.AppConfigurationV1Options{ - Authenticator: authenticator, - } - appConfigClient, err := appconfigurationv1.NewAppConfigurationV1(appConfigurationClientOptions) - if appConfigClient != nil { - // Enable retries for API calls - appConfigClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - session.appConfigurationClient = appConfigClient - } else { - session.appConfigurationClientErr = fmt.Errorf("[ERROR] Error occurred while configuring App Configuration service: %q", err) - } - - // CONTAINER REGISTRY Service - // Construct an "options" struct for creating the service client. - containerRegistryClientURL, err := containerregistryv1.GetServiceURLForRegion(c.Region) - if err != nil { - containerRegistryClientURL = containerregistryv1.DefaultServiceURL - } - if c.Visibility == "private" || c.Visibility == "public-and-private" { - containerRegistryClientURL, err = GetPrivateServiceURLForRegion(c.Region) - if err != nil { - containerRegistryClientURL, _ = GetPrivateServiceURLForRegion("us-south") - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - containerRegistryClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CR_API_ENDPOINT", c.Region, containerRegistryClientURL) - } - containerRegistryClientOptions := &containerregistryv1.ContainerRegistryV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_CR_API_ENDPOINT"}, containerRegistryClientURL), - Account: core.StringPtr(userConfig.userAccount), - } - // Construct the service client. - session.containerRegistryClient, err = containerregistryv1.NewContainerRegistryV1(containerRegistryClientOptions) - if err == nil { - // Enable retries for API calls - session.containerRegistryClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.containerRegistryClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.containerRegistryClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Container Registry API service: %q", err) - } - - // OBJECT STORAGE Service - cosconfigurl := "https://config.cloud-object-storage.cloud.ibm.com/v1" - if fileMap != nil && c.Visibility != "public-and-private" { - cosconfigurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_COS_CONFIG_ENDPOINT", c.Region, cosconfigurl) - } - cosconfigoptions := &cosconfig.ResourceConfigurationV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_COS_CONFIG_ENDPOINT"}, cosconfigurl), - } - cosconfigclient, err := cosconfig.NewResourceConfigurationV1(cosconfigoptions) - if err != nil { - session.cosConfigErr = fmt.Errorf("[ERROR] Error occured while configuring COS config service: %q", err) - } - session.cosConfigAPI = cosconfigclient - - globalSearchAPI, err := globalsearchv2.New(sess.BluemixSession) - if err != nil { - session.globalSearchConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Global Search: %q", err) - } - session.globalSearchServiceAPI = globalSearchAPI - // Global Tagging Bluemix-go - globalTaggingAPI, err := globaltaggingv3.New(sess.BluemixSession) - if err != nil { - session.globalTaggingConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Global Tagging: %q", err) - } - session.globalTaggingServiceAPI = globalTaggingAPI - - // GLOBAL TAGGING Service - globalTaggingEndpoint := "https://tags.global-search-tagging.cloud.ibm.com" - if c.Visibility == "private" || c.Visibility == "public-and-private" { - var globalTaggingRegion string - if c.Region != "us-south" && c.Region != "us-east" { - globalTaggingRegion = "us-south" - } else { - globalTaggingRegion = c.Region - } - globalTaggingEndpoint = contructEndpoint(fmt.Sprintf("tags.private.%s", globalTaggingRegion), fmt.Sprintf("global-search-tagging.%s", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - globalTaggingEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_GT_API_ENDPOINT", c.Region, globalTaggingEndpoint) - } - globalTaggingV1Options := &globaltaggingv1.GlobalTaggingV1Options{ - URL: envFallBack([]string{"IBMCLOUD_GT_API_ENDPOINT"}, globalTaggingEndpoint), - Authenticator: authenticator, - } - globalTaggingAPIV1, err := globaltaggingv1.NewGlobalTaggingV1(globalTaggingV1Options) - if err != nil { - session.globalTaggingConfigErrV1 = fmt.Errorf("Error occured while configuring Global Tagging: %q", err) - } - if globalTaggingAPIV1 != nil { - session.globalTaggingServiceAPIV1 = *globalTaggingAPIV1 - session.globalTaggingServiceAPIV1.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - icdAPI, err := icdv4.New(sess.BluemixSession) - if err != nil { - session.icdConfigErr = fmt.Errorf("Error occured while configuring IBM Cloud Database Services: %q", err) - } - session.icdServiceAPI = icdAPI - - resourceCatalogAPI, err := catalog.New(sess.BluemixSession) - if err != nil { - session.resourceCatalogConfigErr = fmt.Errorf("Error occured while configuring Resource Catalog service: %q", err) - } - session.resourceCatalogServiceAPI = resourceCatalogAPI - - resourceManagementAPIv2, err := managementv2.New(sess.BluemixSession) - if err != nil { - session.resourceManagementConfigErrv2 = fmt.Errorf("Error occured while configuring Resource Management service: %q", err) - } - session.resourceManagementServiceAPIv2 = resourceManagementAPIv2 - - resourceControllerAPI, err := controller.New(sess.BluemixSession) - if err != nil { - session.resourceControllerConfigErr = fmt.Errorf("Error occured while configuring Resource Controller service: %q", err) - } - session.resourceControllerServiceAPI = resourceControllerAPI - - ResourceControllerAPIv2, err := controllerv2.New(sess.BluemixSession) - if err != nil { - session.resourceControllerConfigErrv2 = fmt.Errorf("Error occured while configuring Resource Controller v2 service: %q", err) - } - session.resourceControllerServiceAPIv2 = ResourceControllerAPIv2 - - iam, err := iamv1.New(sess.BluemixSession) - if err != nil { - session.iamConfigErr = fmt.Errorf("Error occured while configuring Bluemix IAM Service: %q", err) - } - session.iamServiceAPI = iam - - userManagementAPI, err := usermanagementv2.New(sess.BluemixSession) - if err != nil { - session.userManagementErr = fmt.Errorf("Error occured while configuring user management service: %q", err) - } - session.userManagementAPI = userManagementAPI - - certManagementAPI, err := certificatemanager.New(sess.BluemixSession) - if err != nil { - session.certManagementErr = fmt.Errorf("Error occured while configuring Certificate manager service: %q", err) - } - session.certManagementAPI = certManagementAPI - - namespaceFunction, err := functions.New(sess.BluemixSession) - if err != nil { - session.functionIAMNamespaceErr = fmt.Errorf("Error occured while configuring Cloud Funciton Service : %q", err) - } - session.functionIAMNamespaceAPI = namespaceFunction - - // API GATEWAY service - apicurl := contructEndpoint(fmt.Sprintf("api.%s.apigw", c.Region), fmt.Sprintf("%s/controller", cloudEndpoint)) - if c.Visibility == "private" || c.Visibility == "public-and-private" { - apicurl = contructEndpoint(fmt.Sprintf("api.private.%s.apigw", c.Region), fmt.Sprintf("%s/controller", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - apicurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_API_GATEWAY_ENDPOINT", c.Region, apicurl) - } - APIGatewayControllerAPIV1Options := &apigateway.ApiGatewayControllerApiV1Options{ - URL: envFallBack([]string{"IBMCLOUD_API_GATEWAY_ENDPOINT"}, apicurl), - Authenticator: &core.NoAuthAuthenticator{}, - } - apigatewayAPI, err := apigateway.NewApiGatewayControllerApiV1(APIGatewayControllerAPIV1Options) - if err != nil { - session.apigatewayErr = fmt.Errorf("Error occured while configuring APIGateway service: %q", err) - } - session.apigatewayAPI = apigatewayAPI - - // POWER SYSTEMS Service - ibmpisession, err := ibmpisession.New(sess.BluemixSession.Config.IAMAccessToken, c.Region, false, 90000000000, session.bmxUserDetails.userAccount, c.Zone) - if err != nil { - session.ibmpiConfigErr = err - return nil, err - } - session.ibmpiSession = ibmpisession - - // PRIVATE DNS Service - pdnsURL := dns.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - pdnsURL = contructEndpoint("api.private.dns-svcs", fmt.Sprintf("%s/v1", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - pdnsURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_PRIVATE_DNS_API_ENDPOINT", c.Region, pdnsURL) - } - dnsOptions := &dns.DnsSvcsV1Options{ - URL: envFallBack([]string{"IBMCLOUD_PRIVATE_DNS_API_ENDPOINT"}, pdnsURL), - Authenticator: authenticator, - } - session.pDNSClient, session.pDNSErr = dns.NewDnsSvcsV1(dnsOptions) - if session.pDNSErr != nil { - session.pDNSErr = fmt.Errorf("Error occured while configuring PrivateDNS Service: %s", session.pDNSErr) - } - if session.pDNSClient != nil && session.pDNSClient.Service != nil { - session.pDNSClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // DIRECT LINK Service - ver := time.Now().Format("2006-01-02") - dlURL := dl.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - dlURL = contructEndpoint("private.directlink", fmt.Sprintf("%s/v1", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - dlURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_DL_API_ENDPOINT", c.Region, dlURL) - } - directlinkOptions := &dl.DirectLinkV1Options{ - URL: envFallBack([]string{"IBMCLOUD_DL_API_ENDPOINT"}, dlURL), - Authenticator: authenticator, - Version: &ver, - } - session.directlinkAPI, session.directlinkErr = dl.NewDirectLinkV1(directlinkOptions) - if session.directlinkErr != nil { - session.directlinkErr = fmt.Errorf("Error occured while configuring Direct Link Service: %s", session.directlinkErr) - } - if session.directlinkAPI != nil && session.directlinkAPI.Service != nil { - session.directlinkAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // DIRECT LINK PROVIDER Service - dlproviderURL := dlProviderV2.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - dlproviderURL = contructEndpoint("private.directlink", fmt.Sprintf("%s/provider/v2", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - dlproviderURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_DL_PROVIDER_API_ENDPOINT", c.Region, dlproviderURL) - } - directLinkProviderV2Options := &dlProviderV2.DirectLinkProviderV2Options{ - URL: envFallBack([]string{"IBMCLOUD_DL_PROVIDER_API_ENDPOINT"}, dlproviderURL), - Authenticator: authenticator, - Version: &ver, - } - session.dlProviderAPI, session.dlProviderErr = dlProviderV2.NewDirectLinkProviderV2(directLinkProviderV2Options) - if session.dlProviderErr != nil { - session.dlProviderErr = fmt.Errorf("Error occured while configuring Direct Link Provider Service: %s", session.dlProviderErr) - } - if session.dlProviderAPI != nil && session.dlProviderAPI.Service != nil { - session.dlProviderAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // TRANSIT GATEWAY Service - tgURL := tg.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - tgURL = contructEndpoint("private.transit", fmt.Sprintf("%s/v1", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - tgURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_TG_API_ENDPOINT", c.Region, tgURL) - } - transitgatewayOptions := &tg.TransitGatewayApisV1Options{ - URL: envFallBack([]string{"IBMCLOUD_TG_API_ENDPOINT"}, tgURL), - Authenticator: authenticator, - Version: CreateVersionDate(), - } - session.transitgatewayAPI, session.transitgatewayErr = tg.NewTransitGatewayApisV1(transitgatewayOptions) - if session.transitgatewayErr != nil { - session.transitgatewayErr = fmt.Errorf("Error occured while configuring Transit Gateway Service: %s", session.transitgatewayErr) - } - if session.transitgatewayAPI != nil && session.transitgatewayAPI.Service != nil { - session.transitgatewayAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // CIS Service instances starts here. - cisURL := contructEndpoint("api.cis", cloudEndpoint) - if c.Visibility == "private" { - // cisURL = contructEndpoint("api.private.cis", cloudEndpoint) - session.cisZonesErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisDNSBulkErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisGLBPoolErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisGLBErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisGLBHealthCheckErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisIPErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisRLErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisPageRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisEdgeFunctionErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisSSLErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisWAFPackageErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisDomainSettingsErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisRoutingErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisWAFGroupErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisCacheErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisCustomPageErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisAccessRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisUARuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisLockdownErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisRangeAppErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisWAFRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - session.cisFiltersErr = fmt.Errorf("CIS Service doesnt support private endpoints.") - } - if fileMap != nil && c.Visibility != "public-and-private" { - cisURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CIS_API_ENDPOINT", c.Region, cisURL) - } - cisEndPoint := envFallBack([]string{"IBMCLOUD_CIS_API_ENDPOINT"}, cisURL) - - // IBM Network CIS Zones service - cisZonesV1Opt := &ciszonesv1.ZonesV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisZonesV1Client, session.cisZonesErr = ciszonesv1.NewZonesV1(cisZonesV1Opt) - if session.cisZonesErr != nil { - session.cisZonesErr = fmt.Errorf( - "Error occured while configuring CIS Zones service: %s", - session.cisZonesErr) - } - if session.cisZonesV1Client != nil && session.cisZonesV1Client.Service != nil { - session.cisZonesV1Client.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS DNS Record service - cisDNSRecordsOpt := &cisdnsrecordsv1.DnsRecordsV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisDNSRecordsClient, session.cisDNSErr = cisdnsrecordsv1.NewDnsRecordsV1(cisDNSRecordsOpt) - if session.cisDNSErr != nil { - session.cisDNSErr = fmt.Errorf("Error occured while configuring CIS DNS Service: %s", session.cisDNSErr) - } - if session.cisDNSRecordsClient != nil && session.cisDNSRecordsClient.Service != nil { - session.cisDNSRecordsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS DNS Record bulk service - cisDNSRecordBulkOpt := &cisdnsbulkv1.DnsRecordBulkV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisDNSRecordBulkClient, session.cisDNSBulkErr = cisdnsbulkv1.NewDnsRecordBulkV1(cisDNSRecordBulkOpt) - if session.cisDNSBulkErr != nil { - session.cisDNSBulkErr = fmt.Errorf( - "Error occured while configuration CIS DNS bulk service : %s", - session.cisDNSBulkErr) - } - if session.cisDNSRecordBulkClient != nil && session.cisDNSRecordBulkClient.Service != nil { - session.cisDNSRecordBulkClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Global load balancer pool - cisGLBPoolOpt := &cisglbpoolv0.GlobalLoadBalancerPoolsV0Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisGLBPoolClient, session.cisGLBPoolErr = - cisglbpoolv0.NewGlobalLoadBalancerPoolsV0(cisGLBPoolOpt) - if session.cisGLBPoolErr != nil { - session.cisGLBPoolErr = - fmt.Errorf("Error occured while configuring CIS GLB Pool service: %s", - session.cisGLBPoolErr) - } - if session.cisGLBPoolClient != nil && session.cisGLBPoolClient.Service != nil { - session.cisGLBPoolClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Global load balancer - cisGLBOpt := &cisglbv1.GlobalLoadBalancerV1Options{ - URL: cisEndPoint, - Authenticator: authenticator, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - } - session.cisGLBClient, session.cisGLBErr = cisglbv1.NewGlobalLoadBalancerV1(cisGLBOpt) - if session.cisGLBErr != nil { - session.cisGLBErr = - fmt.Errorf("Error occured while configuring CIS GLB service: %s", - session.cisGLBErr) - } - if session.cisGLBClient != nil && session.cisGLBClient.Service != nil { - session.cisGLBClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Global load balancer health check/monitor - cisGLBHealthCheckOpt := &cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisGLBHealthCheckClient, session.cisGLBHealthCheckErr = - cisglbhealthcheckv1.NewGlobalLoadBalancerMonitorV1(cisGLBHealthCheckOpt) - if session.cisGLBHealthCheckErr != nil { - session.cisGLBHealthCheckErr = - fmt.Errorf("Error occured while configuring CIS GLB Health Check service: %s", - session.cisGLBHealthCheckErr) - } - if session.cisGLBHealthCheckClient != nil && session.cisGLBHealthCheckClient.Service != nil { - session.cisGLBHealthCheckClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS IP - cisIPOpt := &cisipv1.CisIpApiV1Options{ - URL: cisEndPoint, - Authenticator: authenticator, - } - session.cisIPClient, session.cisIPErr = cisipv1.NewCisIpApiV1(cisIPOpt) - if session.cisIPErr != nil { - session.cisIPErr = fmt.Errorf("Error occured while configuring CIS IP service: %s", - session.cisIPErr) - } - if session.cisIPClient != nil && session.cisIPClient.Service != nil { - session.cisIPClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Zone Rate Limit - cisRLOpt := &cisratelimitv1.ZoneRateLimitsV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisRLClient, session.cisRLErr = cisratelimitv1.NewZoneRateLimitsV1(cisRLOpt) - if session.cisRLErr != nil { - session.cisRLErr = fmt.Errorf( - "Error occured while cofiguring CIS Zone Rate Limit service: %s", - session.cisRLErr) - } - if session.cisRLClient != nil && session.cisRLClient.Service != nil { - session.cisRLClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Page Rules - cisPageRuleOpt := &cispagerulev1.PageRuleApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneID: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisPageRuleClient, session.cisPageRuleErr = cispagerulev1.NewPageRuleApiV1(cisPageRuleOpt) - if session.cisPageRuleErr != nil { - session.cisPageRuleErr = fmt.Errorf( - "Error occured while cofiguring CIS Page Rule service: %s", - session.cisPageRuleErr) - } - if session.cisPageRuleClient != nil && session.cisPageRuleClient.Service != nil { - session.cisPageRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Edge Function - cisEdgeFunctionOpt := &cisedgefunctionv1.EdgeFunctionsApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisEdgeFunctionClient, session.cisEdgeFunctionErr = - cisedgefunctionv1.NewEdgeFunctionsApiV1(cisEdgeFunctionOpt) - if session.cisEdgeFunctionErr != nil { - session.cisEdgeFunctionErr = - fmt.Errorf("Error occured while configuring CIS Edge Function service: %s", - session.cisEdgeFunctionErr) - } - if session.cisEdgeFunctionClient != nil && session.cisEdgeFunctionClient.Service != nil { - session.cisEdgeFunctionClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS SSL certificate - cisSSLOpt := &cissslv1.SslCertificateApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - - session.cisSSLClient, session.cisSSLErr = cissslv1.NewSslCertificateApiV1(cisSSLOpt) - if session.cisSSLErr != nil { - session.cisSSLErr = - fmt.Errorf("Error occured while configuring CIS SSL certificate service: %s", - session.cisSSLErr) - } - if session.cisSSLClient != nil && session.cisSSLClient.Service != nil { - session.cisSSLClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS WAF Package - cisWAFPackageOpt := &ciswafpackagev1.WafRulePackagesApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneID: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisWAFPackageClient, session.cisWAFPackageErr = - ciswafpackagev1.NewWafRulePackagesApiV1(cisWAFPackageOpt) - if session.cisWAFPackageErr != nil { - session.cisWAFPackageErr = - fmt.Errorf("Error occured while configuration CIS WAF Package service: %s", - session.cisWAFPackageErr) - } - if session.cisWAFPackageClient != nil && session.cisWAFPackageClient.Service != nil { - session.cisWAFPackageClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Domain settings - cisDomainSettingsOpt := &cisdomainsettingsv1.ZonesSettingsV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisDomainSettingsClient, session.cisDomainSettingsErr = - cisdomainsettingsv1.NewZonesSettingsV1(cisDomainSettingsOpt) - if session.cisDomainSettingsErr != nil { - session.cisDomainSettingsErr = - fmt.Errorf("[ERROR] Error occured while configuring CIS Domain Settings service: %s", - session.cisDomainSettingsErr) - } - if session.cisDomainSettingsClient != nil && session.cisDomainSettingsClient.Service != nil { - session.cisDomainSettingsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Routing - cisRoutingOpt := &cisroutingv1.RoutingV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisRoutingClient, session.cisRoutingErr = - cisroutingv1.NewRoutingV1(cisRoutingOpt) - if session.cisRoutingErr != nil { - session.cisRoutingErr = - fmt.Errorf("[ERROR] Error occured while configuring CIS Routing service: %s", - session.cisRoutingErr) - } - if session.cisRoutingClient != nil && session.cisRoutingClient.Service != nil { - session.cisRoutingClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS WAF Group - cisWAFGroupOpt := &ciswafgroupv1.WafRuleGroupsApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneID: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisWAFGroupClient, session.cisWAFGroupErr = - ciswafgroupv1.NewWafRuleGroupsApiV1(cisWAFGroupOpt) - if session.cisWAFGroupErr != nil { - session.cisWAFGroupErr = - fmt.Errorf("Error occured while configuring CIS WAF Group service: %s", - session.cisWAFGroupErr) - } - if session.cisWAFGroupClient != nil && session.cisWAFGroupClient.Service != nil { - session.cisWAFGroupClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Cache service - cisCacheOpt := &ciscachev1.CachingApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneID: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisCacheClient, session.cisCacheErr = - ciscachev1.NewCachingApiV1(cisCacheOpt) - if session.cisCacheErr != nil { - session.cisCacheErr = - fmt.Errorf("Error occured while configuring CIS Caching service: %s", - session.cisCacheErr) - } - if session.cisCacheClient != nil && session.cisCacheClient.Service != nil { - session.cisCacheClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Custom pages service - cisCustomPageOpt := &ciscustompagev1.CustomPagesV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - - session.cisCustomPageClient, session.cisCustomPageErr = - ciscustompagev1.NewCustomPagesV1(cisCustomPageOpt) - if session.cisCustomPageErr != nil { - session.cisCustomPageErr = - fmt.Errorf("Error occured while configuring CIS Custom Pages service: %s", - session.cisCustomPageErr) - } - if session.cisCustomPageClient != nil && session.cisCustomPageClient.Service != nil { - session.cisCustomPageClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Firewall Access rule - cisAccessRuleOpt := &cisaccessrulev1.ZoneFirewallAccessRulesV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisAccessRuleClient, session.cisAccessRuleErr = - cisaccessrulev1.NewZoneFirewallAccessRulesV1(cisAccessRuleOpt) - if session.cisAccessRuleErr != nil { - session.cisAccessRuleErr = - fmt.Errorf("Error occured while configuring CIS Firewall Access Rule service: %s", - session.cisAccessRuleErr) - } - if session.cisAccessRuleClient != nil && session.cisAccessRuleClient.Service != nil { - session.cisAccessRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Firewall User Agent Blocking rule - cisUARuleOpt := &cisuarulev1.UserAgentBlockingRulesV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisUARuleClient, session.cisUARuleErr = - cisuarulev1.NewUserAgentBlockingRulesV1(cisUARuleOpt) - if session.cisUARuleErr != nil { - session.cisUARuleErr = - fmt.Errorf("Error occured while configuring CIS Firewall User Agent Blocking Rule service: %s", - session.cisUARuleErr) - } - if session.cisUARuleClient != nil && session.cisUARuleClient.Service != nil { - session.cisUARuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Firewall Lockdown rule - cisLockdownOpt := &cislockdownv1.ZoneLockdownV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisLockdownClient, session.cisLockdownErr = - cislockdownv1.NewZoneLockdownV1(cisLockdownOpt) - if session.cisLockdownErr != nil { - session.cisLockdownErr = - fmt.Errorf("Error occured while configuring CIS Firewall Lockdown Rule service: %s", - session.cisLockdownErr) - } - if session.cisLockdownClient != nil && session.cisLockdownClient.Service != nil { - session.cisLockdownClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Range Application rule - cisRangeAppOpt := &cisrangeappv1.RangeApplicationsV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneIdentifier: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisRangeAppClient, session.cisRangeAppErr = - cisrangeappv1.NewRangeApplicationsV1(cisRangeAppOpt) - if session.cisRangeAppErr != nil { - session.cisRangeAppErr = - fmt.Errorf("Error occured while configuring CIS Range Application rule service: %s", - session.cisRangeAppErr) - } - if session.cisRangeAppClient != nil && session.cisRangeAppClient.Service != nil { - session.cisRangeAppClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS WAF Rule Service - cisWAFRuleOpt := &ciswafrulev1.WafRulesApiV1Options{ - URL: cisEndPoint, - Crn: core.StringPtr(""), - ZoneID: core.StringPtr(""), - Authenticator: authenticator, - } - session.cisWAFRuleClient, session.cisWAFRuleErr = - ciswafrulev1.NewWafRulesApiV1(cisWAFRuleOpt) - if session.cisWAFRuleErr != nil { - session.cisWAFRuleErr = fmt.Errorf( - "Error occured while configuring CIS WAF Rules service: %s", - session.cisWAFRuleErr) - } - if session.cisWAFRuleClient != nil && session.cisWAFRuleClient.Service != nil { - session.cisWAFRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Filters - cisFiltersOpt := &cisfiltersv1.FiltersV1Options{ - URL: cisEndPoint, - Authenticator: authenticator, - } - session.cisFiltersClient, session.cisFiltersErr = cisfiltersv1.NewFiltersV1(cisFiltersOpt) - if session.cisFiltersErr != nil { - session.cisFiltersErr = - fmt.Errorf("Error occured while configuring CIS Filters : %s", - session.cisFiltersErr) - } - if session.cisFiltersClient != nil && session.cisFiltersClient.Service != nil { - session.cisFiltersClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IBM Network CIS Firewall rules - cisFirewallrulesOpt := &cisfirewallrulesv1.FirewallRulesV1Options{ - URL: cisEndPoint, - Authenticator: authenticator, - } - session.cisFirewallRulesClient, session.cisFirewallRulesErr = cisfirewallrulesv1.NewFirewallRulesV1(cisFirewallrulesOpt) - if session.cisFirewallRulesErr != nil { - session.cisFirewallRulesErr = - fmt.Errorf("Error occured while configuring CIS Firewall rules : %s", - session.cisFirewallRulesErr) - } - if session.cisFirewallRulesClient != nil && session.cisFirewallRulesClient.Service != nil { - session.cisFirewallRulesClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - - // IAM IDENTITY Service - // iamIdenityURL := fmt.Sprintf("https://%s.iam.cloud.ibm.com/v1", c.Region) - iamURL := iamidentity.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - iamURL = contructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) - } else { - iamURL = contructEndpoint("private.iam", cloudEndpoint) - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - iamURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamURL) - } - iamIdentityOptions := &iamidentity.IamIdentityV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL), - } - iamIdentityClient, err := iamidentity.NewIamIdentityV1(iamIdentityOptions) - if err != nil { - session.iamIdentityErr = fmt.Errorf("Error occured while configuring IAM Identity service: %q", err) - } - if iamIdentityClient != nil && iamIdentityClient.Service != nil { - iamIdentityClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.iamIdentityAPI = iamIdentityClient - - // IAM POLICY MANAGEMENT Service - iamPolicyManagementURL := iampolicymanagement.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - iamPolicyManagementURL = contructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) - } else { - iamPolicyManagementURL = contructEndpoint("private.iam", cloudEndpoint) - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - iamPolicyManagementURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamPolicyManagementURL) - } - iamPolicyManagementOptions := &iampolicymanagement.IamPolicyManagementV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamPolicyManagementURL), - } - iamPolicyManagementClient, err := iampolicymanagement.NewIamPolicyManagementV1(iamPolicyManagementOptions) - if err != nil { - session.iamPolicyManagementErr = fmt.Errorf("Error occured while configuring IAM Policy Management service: %q", err) - } - if iamPolicyManagementClient != nil && iamPolicyManagementClient.Service != nil { - iamPolicyManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.iamPolicyManagementAPI = iamPolicyManagementClient - - // IAM ACCESS GROUP - iamAccessGroupsURL := iamaccessgroups.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - iamAccessGroupsURL = contructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) - } else { - iamAccessGroupsURL = contructEndpoint("private.iam", cloudEndpoint) - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - iamAccessGroupsURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamAccessGroupsURL) - } - iamAccessGroupsOptions := &iamaccessgroups.IamAccessGroupsV2Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamAccessGroupsURL), - } - iamAccessGroupsClient, err := iamaccessgroups.NewIamAccessGroupsV2(iamAccessGroupsOptions) - if err != nil { - session.iamAccessGroupsErr = fmt.Errorf("Error occured while configuring IAM Access Group service: %q", err) - } - if iamAccessGroupsClient != nil && iamAccessGroupsClient.Service != nil { - iamAccessGroupsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.iamAccessGroupsAPI = iamAccessGroupsClient - - // RESOURCE MANAGEMENT Service - rmURL := resourcemanager.DefaultServiceURL - if c.Visibility == "private" { - if c.Region == "us-south" || c.Region == "us-east" { - rmURL = contructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), fmt.Sprintf("%s/v2", cloudEndpoint)) - } else { - fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") - rmURL = contructEndpoint("private.us-south.resource-controller", fmt.Sprintf("%s/v2", cloudEndpoint)) - } - } - if c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - rmURL = contructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), fmt.Sprintf("%s/v2", cloudEndpoint)) - } else { - rmURL = resourcemanager.DefaultServiceURL - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - rmURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_RESOURCE_MANAGEMENT_API_ENDPOINT", c.Region, rmURL) - } - resourceManagerOptions := &resourcemanager.ResourceManagerV2Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_RESOURCE_MANAGEMENT_API_ENDPOINT"}, rmURL), - } - resourceManagerClient, err := resourcemanager.NewResourceManagerV2(resourceManagerOptions) - if err != nil { - session.resourceManagerErr = fmt.Errorf("Error occured while configuring Resource Manager service: %q", err) - } - if resourceManagerClient != nil { - resourceManagerClient.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.resourceManagerAPI = resourceManagerClient - - //CLOUD SHELL Service - cloudShellUrl := ibmcloudshellv1.DefaultServiceURL - if fileMap != nil && c.Visibility != "public-and-private" { - cloudShellUrl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CLOUD_SHELL_API_ENDPOINT", c.Region, cloudShellUrl) - } - ibmCloudShellClientOptions := &ibmcloudshellv1.IBMCloudShellV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_CLOUD_SHELL_API_ENDPOINT"}, cloudShellUrl), - } - session.ibmCloudShellClient, err = ibmcloudshellv1.NewIBMCloudShellV1(ibmCloudShellClientOptions) - if err == nil { - session.ibmCloudShellClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - session.ibmCloudShellClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.ibmCloudShellClientErr = fmt.Errorf("Error occurred while configuring IBM Cloud Shell service: %q", err) - } - - // ENTERPRISE Service - enterpriseURL := enterprisemanagementv1.DefaultServiceURL - if c.Visibility == "private" { - if c.Region == "us-south" || c.Region == "us-east" || c.Region == "eu-fr" { - enterpriseURL = contructEndpoint(fmt.Sprintf("private.%s.enterprise", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) - } else { - fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") - enterpriseURL = contructEndpoint("private.us-south.enterprise", fmt.Sprintf("%s/v1", cloudEndpoint)) - } - } - if c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" || c.Region == "eu-fr" { - enterpriseURL = contructEndpoint(fmt.Sprintf("private.%s.enterprise", c.Region), - fmt.Sprintf("%s/v1", cloudEndpoint)) - } else { - enterpriseURL = enterprisemanagementv1.DefaultServiceURL - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - enterpriseURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_ENTERPRISE_API_ENDPOINT", c.Region, enterpriseURL) - } - enterpriseManagementClientOptions := &enterprisemanagementv1.EnterpriseManagementV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_ENTERPRISE_API_ENDPOINT"}, enterpriseURL), - } - enterpriseManagementClient, err := enterprisemanagementv1.NewEnterpriseManagementV1(enterpriseManagementClientOptions) - if err == nil { - enterpriseManagementClient.EnableRetries(c.RetryCount, c.RetryDelay) - } else { - session.enterpriseManagementClientErr = fmt.Errorf("Error occurred while configuring IBM Cloud Enterprise Management API service: %q", err) - } - session.enterpriseManagementClient = enterpriseManagementClient - - // RESOURCE CONTROLLER Service - rcURL := resourcecontroller.DefaultServiceURL - if c.Visibility == "private" { - if c.Region == "us-south" || c.Region == "us-east" { - rcURL = contructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), cloudEndpoint) - } else { - fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") - rcURL = contructEndpoint("private.us-south.resource-controller", cloudEndpoint) - } - } - if c.Visibility == "public-and-private" { - if c.Region == "us-south" || c.Region == "us-east" { - rcURL = contructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), cloudEndpoint) - } else { - rcURL = resourcecontroller.DefaultServiceURL - } - } - if fileMap != nil && c.Visibility != "public-and-private" { - rcURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_RESOURCE_CONTROLLER_API_ENDPOINT", c.Region, rcURL) - } - resourceControllerOptions := &resourcecontroller.ResourceControllerV2Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_RESOURCE_CONTROLLER_API_ENDPOINT"}, rcURL), - } - resourceControllerClient, err := resourcecontroller.NewResourceControllerV2(resourceControllerOptions) - if err != nil { - session.resourceControllerErr = fmt.Errorf("Error occured while configuring Resource Controller service: %q", err) - } - if resourceControllerClient != nil { - resourceControllerClient.EnableRetries(c.RetryCount, c.RetryDelay) - } - session.resourceControllerAPI = resourceControllerClient - - // SECRETS MANAGER Service - secretsManagerClientOptions := &secretsmanagerv1.SecretsManagerV1Options{ - Authenticator: authenticator, - } - /// Construct the service client. - session.secretsManagerClient, err = secretsmanagerv1.NewSecretsManagerV1(secretsManagerClientOptions) - if err == nil { - // Enable retries for API calls - session.secretsManagerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.secretsManagerClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.secretsManagerClientErr = fmt.Errorf("Error occurred while configuring IBM Cloud Secrets Manager API service: %q", err) - } - - // SATELLITE Service - containerEndpoint := kubernetesserviceapiv1.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - containerEndpoint = contructEndpoint(fmt.Sprintf("private.%s.containers", c.Region), fmt.Sprintf("%s/global", cloudEndpoint)) - } - if fileMap != nil && c.Visibility != "public-and-private" { - containerEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SATELLITE_API_ENDPOINT", c.Region, containerEndpoint) - } - kubernetesServiceV1Options := &kubernetesserviceapiv1.KubernetesServiceApiV1Options{ - URL: envFallBack([]string{"IBMCLOUD_SATELLITE_API_ENDPOINT"}, containerEndpoint), - Authenticator: authenticator, - } - session.satelliteClient, err = kubernetesserviceapiv1.NewKubernetesServiceApiV1(kubernetesServiceV1Options) - if err != nil { - session.satelliteClientErr = fmt.Errorf("Error occured while configuring satellite client: %q", err) - } - // Enable retries for API calls - session.satelliteClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - - // SATELLITE LINK Service - // Construct an "options" struct for creating the service client. - satelliteLinkEndpoint := satellitelinkv1.DefaultServiceURL - if c.Visibility == "private" || c.Visibility == "public-and-private" { - satelliteLinkEndpoint = contructEndpoint("private.api.link.satellite", cloudEndpoint) - } - if fileMap != nil && c.Visibility != "public-and-private" { - satelliteLinkEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SATELLITE_LINK_API_ENDPOINT", c.Region, satelliteLinkEndpoint) - } - satelliteLinkClientOptions := &satellitelinkv1.SatelliteLinkV1Options{ - URL: envFallBack([]string{"IBMCLOUD_SATELLITE_LINK_API_ENDPOINT"}, satelliteLinkEndpoint), - Authenticator: authenticator, - } - session.satelliteLinkClient, err = satellitelinkv1.NewSatelliteLinkV1(satelliteLinkClientOptions) - if err == nil { - // Enable retries for API calls - session.satelliteLinkClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.satelliteLinkClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.satelliteLinkClientErr = fmt.Errorf("Error occurred while configuring Satellite Link service: %q", err) - } - - esSchemaRegistryV1Options := &schemaregistryv1.SchemaregistryV1Options{ - Authenticator: authenticator, - } - session.esSchemaRegistryClient, err = schemaregistryv1.NewSchemaregistryV1(esSchemaRegistryV1Options) - if err == nil { - session.esSchemaRegistryClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - session.esSchemaRegistryClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.esSchemaRegistryErr = fmt.Errorf("Error occured while configuring Event Streams schema registry: %q", err) - } - - //COMPLIANCE Service - // Construct an "options" struct for creating the service client. - var postureManagementClientURL string - if c.Visibility == "public" || c.Visibility == "public-and-private" { - postureManagementClientURL, err = posturemanagementv1.GetServiceURLForRegion(c.Region) - } else { - session.findingsClientErr = fmt.Errorf("Error occurred while configuring Security Insights Findings API service: `%v` visibility not supported", c.Visibility) - } - if err != nil { - postureManagementClientURL = posturemanagementv1.DefaultServiceURL - } - if fileMap != nil && c.Visibility != "public-and-private" { - postureManagementClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_COMPLIANCE_API_ENDPOINT", c.Region, postureManagementClientURL) - } - postureManagementClientOptions := &posturemanagementv1.PostureManagementV1Options{ - Authenticator: authenticator, - URL: envFallBack([]string{"IBMCLOUD_COMPLIANCE_API_ENDPOINT"}, postureManagementClientURL), - AccountID: core.StringPtr(userConfig.userAccount), - } - - // Construct the service client. - session.postureManagementClient, err = posturemanagementv1.NewPostureManagementV1(postureManagementClientOptions) - if err == nil { - // Enable retries for API calls - session.postureManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.postureManagementClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.postureManagementClientErr = fmt.Errorf("Error occurred while configuring Posture Management service: %q", err) - } - return session, nil -} - -// CreateVersionDate requires mandatory version attribute. Any date from 2019-12-13 up to the currentdate may be provided. Specify the current date to request the latest version. -func CreateVersionDate() *string { - version := time.Now().Format("2006-01-02") - return &version -} - -func newSession(c *Config) (*Session, error) { - ibmSession := &Session{} - - softlayerSession := &slsession.Session{ - Endpoint: c.SoftLayerEndpointURL, - Timeout: c.SoftLayerTimeout, - UserName: c.SoftLayerUserName, - APIKey: c.SoftLayerAPIKey, - Debug: os.Getenv("TF_LOG") != "", - Retries: c.RetryCount, - RetryWait: c.RetryDelay, - } - - if c.IAMToken != "" { - log.Println("Configuring SoftLayer Session with token") - softlayerSession.IAMToken = c.IAMToken - softlayerSession.IAMRefreshToken = c.IAMRefreshToken - } - if c.SoftLayerAPIKey != "" && c.SoftLayerUserName != "" { - log.Println("Configuring SoftLayer Session with API key") - softlayerSession.APIKey = c.SoftLayerAPIKey - softlayerSession.UserName = c.SoftLayerUserName - } - softlayerSession.AppendUserAgent(fmt.Sprintf("terraform-provider-ibm/%s", version.Version)) - ibmSession.SoftLayerSession = softlayerSession - - if (c.IAMToken != "" && c.IAMRefreshToken == "") || (c.IAMToken == "" && c.IAMRefreshToken != "") { - return nil, fmt.Errorf("iam_token and iam_refresh_token must be provided") - } - - if c.IAMToken != "" && c.IAMRefreshToken != "" { - log.Println("Configuring IBM Cloud Session with token") - var sess *bxsession.Session - bmxConfig := &bluemix.Config{ - IAMAccessToken: c.IAMToken, - IAMRefreshToken: c.IAMRefreshToken, - //Comment out debug mode for v0.12 - //Debug: os.Getenv("TF_LOG") != "", - HTTPTimeout: c.BluemixTimeout, - Region: c.Region, - ResourceGroup: c.ResourceGroup, - RetryDelay: &c.RetryDelay, - MaxRetries: &c.RetryCount, - Visibility: c.Visibility, - EndpointsFile: c.EndpointsFile, - } - sess, err := bxsession.New(bmxConfig) - if err != nil { - return nil, err - } - ibmSession.BluemixSession = sess - } - - if c.BluemixAPIKey != "" { - log.Println("Configuring IBM Cloud Session with API key") - var sess *bxsession.Session - bmxConfig := &bluemix.Config{ - BluemixAPIKey: c.BluemixAPIKey, - //Comment out debug mode for v0.12 - //Debug: os.Getenv("TF_LOG") != "", - HTTPTimeout: c.BluemixTimeout, - Region: c.Region, - ResourceGroup: c.ResourceGroup, - RetryDelay: &c.RetryDelay, - MaxRetries: &c.RetryCount, - Visibility: c.Visibility, - EndpointsFile: c.EndpointsFile, - - //PowerServiceInstance: c.PowerServiceInstance, - } - sess, err := bxsession.New(bmxConfig) - if err != nil { - return nil, err - } - ibmSession.BluemixSession = sess - } - - return ibmSession, nil -} - -func authenticateAPIKey(sess *bxsession.Session) error { - config := sess.Config - tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ - DefaultHeader: gohttp.Header{ - "User-Agent": []string{http.UserAgent()}, - }, - }) - if err != nil { - return err - } - return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) -} - -func authenticateCF(sess *bxsession.Session) error { - config := sess.Config - tokenRefresher, err := authentication.NewUAARepository(config, &rest.Client{ - DefaultHeader: gohttp.Header{ - "User-Agent": []string{http.UserAgent()}, - }, - }) - if err != nil { - return err - } - return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) -} - -func fetchUserDetails(sess *bxsession.Session, retries int, retryDelay time.Duration) (*UserConfig, error) { - config := sess.Config - user := UserConfig{} - var bluemixToken string - - if strings.HasPrefix(config.IAMAccessToken, "Bearer") { - bluemixToken = config.IAMAccessToken[7:len(config.IAMAccessToken)] - } else { - bluemixToken = config.IAMAccessToken - } - - token, err := jwt.Parse(bluemixToken, func(token *jwt.Token) (interface{}, error) { - return "", nil - }) - //TODO validate with key - if err != nil && !strings.Contains(err.Error(), "key is of invalid type") { - if retries > 0 { - if config.BluemixAPIKey != "" { - time.Sleep(retryDelay) - log.Printf("Retrying authentication for user details %d", retries) - _ = authenticateAPIKey(sess) - return fetchUserDetails(sess, retries-1, retryDelay) - } - } - return &user, err - } - claims := token.Claims.(jwt.MapClaims) - if email, ok := claims["email"]; ok { - user.userEmail = email.(string) - } - user.userID = claims["id"].(string) - user.userAccount = claims["account"].(map[string]interface{})["bss"].(string) - iss := claims["iss"].(string) - if strings.Contains(iss, "https://iam.cloud.ibm.com") { - user.cloudName = "bluemix" - } else { - user.cloudName = "staging" - } - user.cloudType = "public" - - user.generation = 2 - return &user, nil -} - -func refreshToken(sess *bxsession.Session) error { - config := sess.Config - tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ - DefaultHeader: gohttp.Header{ - "User-Agent": []string{http.UserAgent()}, - }, - }) - if err != nil { - return err - } - _, err = tokenRefresher.RefreshToken() - return err -} - -func envFallBack(envs []string, defaultValue string) string { - for _, k := range envs { - if v := os.Getenv(k); v != "" { - return v - } - } - return defaultValue -} -func fileFallBack(fileMap map[string]interface{}, visibility, key, region, defaultValue string) string { - if val, ok := fileMap[key]; ok { - if v, ok := val.(map[string]interface{})[visibility]; ok { - if r, ok := v.(map[string]interface{})[region]; ok && r.(string) != "" { - return r.(string) - } - } - } - return defaultValue -} - -// DefaultTransport ... -func DefaultTransport() gohttp.RoundTripper { - transport := &gohttp.Transport{ - Proxy: gohttp.ProxyFromEnvironment, - DisableKeepAlives: true, - MaxIdleConnsPerHost: -1, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: false, - }, - } - return transport -} - -func isRetryable(err error) bool { - if bmErr, ok := err.(bmxerror.RequestFailure); ok { - switch bmErr.StatusCode() { - case 408, 504, 599, 429, 500, 502, 520, 503: - return true - } - } - - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - return true - } - - if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() { - return true - } - - if netErr, ok := err.(net.UnknownNetworkError); ok && netErr.Timeout() { - return true - } - - return false -} - -func contructEndpoint(subdomain, domain string) string { - endpoint := fmt.Sprintf("https://%s.%s", subdomain, domain) - return endpoint -} diff --git a/ibm/conns/config.go b/ibm/conns/config.go new file mode 100644 index 000000000..fd7520596 --- /dev/null +++ b/ibm/conns/config.go @@ -0,0 +1,3420 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package conns + +import ( + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "net" + gohttp "net/http" + "os" + "strings" + "time" + + // Added code for the Power Colo Offering + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" + apigateway "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" + "github.com/IBM/container-registry-go-sdk/containerregistryv1" + "github.com/IBM/go-sdk-core/v5/core" + cosconfig "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" + kp "github.com/IBM/keyprotect-go-client" + cisalertsv1 "github.com/IBM/networking-go-sdk/alertsv1" + cisoriginpull "github.com/IBM/networking-go-sdk/authenticatedoriginpullapiv1" + ciscachev1 "github.com/IBM/networking-go-sdk/cachingapiv1" + cisipv1 "github.com/IBM/networking-go-sdk/cisipapiv1" + ciscustompagev1 "github.com/IBM/networking-go-sdk/custompagesv1" + dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" + dl "github.com/IBM/networking-go-sdk/directlinkv1" + cisdnsbulkv1 "github.com/IBM/networking-go-sdk/dnsrecordbulkv1" + cisdnsrecordsv1 "github.com/IBM/networking-go-sdk/dnsrecordsv1" + dns "github.com/IBM/networking-go-sdk/dnssvcsv1" + cisedgefunctionv1 "github.com/IBM/networking-go-sdk/edgefunctionsapiv1" + cisfiltersv1 "github.com/IBM/networking-go-sdk/filtersv1" + cisfirewallrulesv1 "github.com/IBM/networking-go-sdk/firewallrulesv1" + cisglbhealthcheckv1 "github.com/IBM/networking-go-sdk/globalloadbalancermonitorv1" + cisglbpoolv0 "github.com/IBM/networking-go-sdk/globalloadbalancerpoolsv0" + cisglbv1 "github.com/IBM/networking-go-sdk/globalloadbalancerv1" + cislogpushjobsapiv1 "github.com/IBM/networking-go-sdk/logpushjobsapiv1" + cismtlsv1 "github.com/IBM/networking-go-sdk/mtlsv1" + cispagerulev1 "github.com/IBM/networking-go-sdk/pageruleapiv1" + cisrangeappv1 "github.com/IBM/networking-go-sdk/rangeapplicationsv1" + cisroutingv1 "github.com/IBM/networking-go-sdk/routingv1" + cissslv1 "github.com/IBM/networking-go-sdk/sslcertificateapiv1" + tg "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + cisuarulev1 "github.com/IBM/networking-go-sdk/useragentblockingrulesv1" + ciswafgroupv1 "github.com/IBM/networking-go-sdk/wafrulegroupsapiv1" + ciswafpackagev1 "github.com/IBM/networking-go-sdk/wafrulepackagesapiv1" + ciswafrulev1 "github.com/IBM/networking-go-sdk/wafrulesapiv1" + ciswebhooksv1 "github.com/IBM/networking-go-sdk/webhooksv1" + cisaccessrulev1 "github.com/IBM/networking-go-sdk/zonefirewallaccessrulesv1" + cislockdownv1 "github.com/IBM/networking-go-sdk/zonelockdownv1" + cisratelimitv1 "github.com/IBM/networking-go-sdk/zoneratelimitsv1" + cisdomainsettingsv1 "github.com/IBM/networking-go-sdk/zonessettingsv1" + ciszonesv1 "github.com/IBM/networking-go-sdk/zonesv1" + "github.com/IBM/platform-services-go-sdk/atrackerv1" + "github.com/IBM/platform-services-go-sdk/atrackerv2" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" + "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + iamaccessgroups "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + iamidentity "github.com/IBM/platform-services-go-sdk/iamidentityv1" + iampolicymanagement "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + ibmcloudshellv1 "github.com/IBM/platform-services-go-sdk/ibmcloudshellv1" + resourcecontroller "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + resourcemanager "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" + "github.com/IBM/push-notifications-go-sdk/pushservicev1" + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" + schematicsv1 "github.com/IBM/schematics-go-sdk/schematicsv1" + "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1" + "github.com/IBM/vpc-go-sdk/common" + vpc "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/apache/openwhisk-client-go/whisk" + jwt "github.com/golang-jwt/jwt" + slsession "github.com/softlayer/softlayer-go/session" + + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/account/accountv1" + "github.com/IBM-Cloud/bluemix-go/api/account/accountv2" + "github.com/IBM-Cloud/bluemix-go/api/certificatemanager" + "github.com/IBM-Cloud/bluemix-go/api/cis/cisv1" + "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/api/functions" + "github.com/IBM-Cloud/bluemix-go/api/globalsearch/globalsearchv2" + "github.com/IBM-Cloud/bluemix-go/api/globaltagging/globaltaggingv3" + "github.com/IBM-Cloud/bluemix-go/api/hpcs" + "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/controller" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/managementv2" + "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" + "github.com/IBM-Cloud/bluemix-go/authentication" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/http" + "github.com/IBM-Cloud/bluemix-go/rest" + bxsession "github.com/IBM-Cloud/bluemix-go/session" + ibmpisession "github.com/IBM-Cloud/power-go-client/ibmpisession" + "github.com/IBM-Cloud/terraform-provider-ibm/version" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" + "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/eventstreams-go-sdk/pkg/schemaregistryv1" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv1" +) + +// RetryAPIDelay - retry api delay +const RetryAPIDelay = 5 * time.Second + +// BluemixRegion ... +var BluemixRegion string + +var ( + errEmptyBluemixCredentials = errors.New("ibmcloud_api_key or bluemix_api_key or iam_token and iam_refresh_token must be provided. Please see the documentation on how to configure it") +) + +// UserConfig ... +type UserConfig struct { + UserID string + UserEmail string + UserAccount string + CloudName string `default:"bluemix"` + cloudType string `default:"public"` + generation int `default:"2"` +} + +// Config stores user provider input +type Config struct { + //BluemixAPIKey is the Bluemix api key + BluemixAPIKey string + //Bluemix region + Region string + //Resource group id + ResourceGroup string + //Bluemix API timeout + BluemixTimeout time.Duration + + //Softlayer end point url + SoftLayerEndpointURL string + + //Softlayer API timeout + SoftLayerTimeout time.Duration + + // Softlayer User Name + SoftLayerUserName string + + // Softlayer API Key + SoftLayerAPIKey string + + //Retry Count for API calls + //Unexposed in the schema at this point as they are used only during session creation for a few calls + //When sdk implements it we an expose them for expected behaviour + //https://github.com/softlayer/softlayer-go/issues/41 + RetryCount int + //Constant Retry Delay for API calls + RetryDelay time.Duration + + // FunctionNameSpace ... + FunctionNameSpace string + + //Riaas End point + RiaasEndPoint string + + //Generation + Generation int + + //IAM Token + IAMToken string + + //TrustedProfileToken Token + IAMTrustedProfileID string + + //IAM Refresh Token + IAMRefreshToken string + + // Zone + Zone string + Visibility string + EndpointsFile string +} + +// Session stores the information required for communication with the SoftLayer and Bluemix API +type Session struct { + // SoftLayerSesssion is the the SoftLayer session used to connect to the SoftLayer API + SoftLayerSession *slsession.Session + + // BluemixSession is the the Bluemix session used to connect to the Bluemix API + BluemixSession *bxsession.Session +} + +// ClientSession ... +type ClientSession interface { + AppIDAPI() (*appid.AppIDManagementV4, error) + BluemixSession() (*bxsession.Session, error) + BluemixAcccountAPI() (accountv2.AccountServiceAPI, error) + BluemixAcccountv1API() (accountv1.AccountServiceAPI, error) + BluemixUserDetails() (*UserConfig, error) + ContainerAPI() (containerv1.ContainerServiceAPI, error) + VpcContainerAPI() (containerv2.ContainerServiceAPI, error) + ContainerRegistryV1() (*containerregistryv1.ContainerRegistryV1, error) + FunctionClient() (*whisk.Client, error) + GlobalSearchAPI() (globalsearchv2.GlobalSearchServiceAPI, error) + GlobalTaggingAPI() (globaltaggingv3.GlobalTaggingServiceAPI, error) + GlobalTaggingAPIv1() (globaltaggingv1.GlobalTaggingV1, error) + ICDAPI() (icdv4.ICDServiceAPI, error) + CloudDatabasesV5() (*clouddatabasesv5.CloudDatabasesV5, error) + IAMPolicyManagementV1API() (*iampolicymanagement.IamPolicyManagementV1, error) + IAMAccessGroupsV2() (*iamaccessgroups.IamAccessGroupsV2, error) + MccpAPI() (mccpv2.MccpServiceAPI, error) + ResourceCatalogAPI() (catalog.ResourceCatalogAPI, error) + ResourceManagementAPIv2() (managementv2.ResourceManagementAPIv2, error) + ResourceControllerAPI() (controller.ResourceControllerAPI, error) + ResourceControllerAPIV2() (controllerv2.ResourceControllerAPIV2, error) + SoftLayerSession() *slsession.Session + IBMPISession() (*ibmpisession.IBMPISession, error) + UserManagementAPI() (usermanagementv2.UserManagementAPI, error) + PushServiceV1() (*pushservicev1.PushServiceV1, error) + EventNotificationsApiV1() (*eventnotificationsv1.EventNotificationsV1, error) + AppConfigurationV1() (*appconfigurationv1.AppConfigurationV1, error) + CertificateManagerAPI() (certificatemanager.CertificateManagerServiceAPI, error) + KeyProtectAPI() (*kp.Client, error) + KeyManagementAPI() (*kp.Client, error) + VpcV1API() (*vpc.VpcV1, error) + APIGateway() (*apigateway.ApiGatewayControllerApiV1, error) + PrivateDNSClientSession() (*dns.DnsSvcsV1, error) + CosConfigV1API() (*cosconfig.ResourceConfigurationV1, error) + DirectlinkV1API() (*dl.DirectLinkV1, error) + DirectlinkProviderV2API() (*dlProviderV2.DirectLinkProviderV2, error) + TransitGatewayV1API() (*tg.TransitGatewayApisV1, error) + HpcsEndpointAPI() (hpcs.HPCSV2, error) + UkoV4() (*ukov4.UkoV4, error) + FunctionIAMNamespaceAPI() (functions.FunctionServiceAPI, error) + CisZonesV1ClientSession() (*ciszonesv1.ZonesV1, error) + CisAlertsSession() (*cisalertsv1.AlertsV1, error) + CisOrigAuthSession() (*cisoriginpull.AuthenticatedOriginPullApiV1, error) + CisDNSRecordClientSession() (*cisdnsrecordsv1.DnsRecordsV1, error) + CisDNSRecordBulkClientSession() (*cisdnsbulkv1.DnsRecordBulkV1, error) + CisGLBClientSession() (*cisglbv1.GlobalLoadBalancerV1, error) + CisGLBPoolClientSession() (*cisglbpoolv0.GlobalLoadBalancerPoolsV0, error) + CisGLBHealthCheckClientSession() (*cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1, error) + CisIPClientSession() (*cisipv1.CisIpApiV1, error) + CisPageRuleClientSession() (*cispagerulev1.PageRuleApiV1, error) + CisLogpushJobsSession() (*cislogpushjobsapiv1.LogpushJobsApiV1, error) + CisRLClientSession() (*cisratelimitv1.ZoneRateLimitsV1, error) + CisEdgeFunctionClientSession() (*cisedgefunctionv1.EdgeFunctionsApiV1, error) + CisSSLClientSession() (*cissslv1.SslCertificateApiV1, error) + CisWAFPackageClientSession() (*ciswafpackagev1.WafRulePackagesApiV1, error) + CisDomainSettingsClientSession() (*cisdomainsettingsv1.ZonesSettingsV1, error) + CisRoutingClientSession() (*cisroutingv1.RoutingV1, error) + CisWAFGroupClientSession() (*ciswafgroupv1.WafRuleGroupsApiV1, error) + CisCacheClientSession() (*ciscachev1.CachingApiV1, error) + CisMtlsSession() (*cismtlsv1.MtlsV1, error) + CisWebhookSession() (*ciswebhooksv1.WebhooksV1, error) + CisCustomPageClientSession() (*ciscustompagev1.CustomPagesV1, error) + CisAccessRuleClientSession() (*cisaccessrulev1.ZoneFirewallAccessRulesV1, error) + CisUARuleClientSession() (*cisuarulev1.UserAgentBlockingRulesV1, error) + CisLockdownClientSession() (*cislockdownv1.ZoneLockdownV1, error) + CisRangeAppClientSession() (*cisrangeappv1.RangeApplicationsV1, error) + CisWAFRuleClientSession() (*ciswafrulev1.WafRulesApiV1, error) + IAMIdentityV1API() (*iamidentity.IamIdentityV1, error) + IBMCloudShellV1() (*ibmcloudshellv1.IBMCloudShellV1, error) + ResourceManagerV2API() (*resourcemanager.ResourceManagerV2, error) + CatalogManagementV1() (*catalogmanagementv1.CatalogManagementV1, error) + EnterpriseManagementV1() (*enterprisemanagementv1.EnterpriseManagementV1, error) + ResourceControllerV2API() (*resourcecontroller.ResourceControllerV2, error) + SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) + SchematicsV1() (*schematicsv1.SchematicsV1, error) + SatelliteClientSession() (*kubernetesserviceapiv1.KubernetesServiceApiV1, error) + SatellitLinkClientSession() (*satellitelinkv1.SatelliteLinkV1, error) + CisFiltersSession() (*cisfiltersv1.FiltersV1, error) + CisFirewallRulesSession() (*cisfirewallrulesv1.FirewallRulesV1, error) + AtrackerV1() (*atrackerv1.AtrackerV1, error) + AtrackerV2() (*atrackerv2.AtrackerV2, error) + ESschemaRegistrySession() (*schemaregistryv1.SchemaregistryV1, error) + AdminServiceApiV1() (*adminserviceapiv1.AdminServiceApiV1, error) + ConfigurationGovernanceV1() (*configurationgovernancev1.ConfigurationGovernanceV1, error) + PostureManagementV1() (*posturemanagementv1.PostureManagementV1, error) + ContextBasedRestrictionsV1() (*contextbasedrestrictionsv1.ContextBasedRestrictionsV1, error) + PostureManagementV2() (*posturemanagementv2.PostureManagementV2, error) + CdToolchainV2() (*cdtoolchainv2.CdToolchainV2, error) + CdTektonPipelineV2() (*cdtektonpipelinev2.CdTektonPipelineV2, error) +} + +type clientSession struct { + session *Session + + appidErr error + appidAPI *appid.AppIDManagementV4 + + apigatewayErr error + apigatewayAPI *apigateway.ApiGatewayControllerApiV1 + + accountConfigErr error + bmxAccountServiceAPI accountv2.AccountServiceAPI + + accountV1ConfigErr error + bmxAccountv1ServiceAPI accountv1.AccountServiceAPI + + bmxUserDetails *UserConfig + bmxUserFetchErr error + + csConfigErr error + csServiceAPI containerv1.ContainerServiceAPI + + csv2ConfigErr error + csv2ServiceAPI containerv2.ContainerServiceAPI + + containerRegistryClientErr error + containerRegistryClient *containerregistryv1.ContainerRegistryV1 + + certManagementErr error + certManagementAPI certificatemanager.CertificateManagerServiceAPI + + cfConfigErr error + cfServiceAPI mccpv2.MccpServiceAPI + + cisConfigErr error + cisServiceAPI cisv1.CisServiceAPI + + functionConfigErr error + functionClient *whisk.Client + + globalSearchConfigErr error + globalSearchServiceAPI globalsearchv2.GlobalSearchServiceAPI + + globalTaggingConfigErr error + globalTaggingServiceAPI globaltaggingv3.GlobalTaggingServiceAPI + + globalTaggingConfigErrV1 error + globalTaggingServiceAPIV1 globaltaggingv1.GlobalTaggingV1 + + ibmCloudShellClient *ibmcloudshellv1.IBMCloudShellV1 + ibmCloudShellClientErr error + + userManagementErr error + userManagementAPI usermanagementv2.UserManagementAPI + + icdConfigErr error + icdServiceAPI icdv4.ICDServiceAPI + + cloudDatabasesClientErr error + cloudDatabasesClient *clouddatabasesv5.CloudDatabasesV5 + + resourceControllerConfigErr error + resourceControllerServiceAPI controller.ResourceControllerAPI + + resourceControllerConfigErrv2 error + resourceControllerServiceAPIv2 controllerv2.ResourceControllerAPIV2 + + resourceManagementConfigErrv2 error + resourceManagementServiceAPIv2 managementv2.ResourceManagementAPIv2 + + resourceCatalogConfigErr error + resourceCatalogServiceAPI catalog.ResourceCatalogAPI + + ibmpiConfigErr error + ibmpiSession *ibmpisession.IBMPISession + + kpErr error + kpAPI *kp.API + + kmsErr error + kmsAPI *kp.API + + hpcsEndpointErr error + hpcsEndpointAPI hpcs.HPCSV2 + + ukoClient *ukov4.UkoV4 + ukoClientErr error + + pDNSClient *dns.DnsSvcsV1 + pDNSErr error + + bluemixSessionErr error + + pushServiceClient *pushservicev1.PushServiceV1 + pushServiceClientErr error + + eventNotificationsApiClient *eventnotificationsv1.EventNotificationsV1 + eventNotificationsApiClientErr error + + appConfigurationClient *appconfigurationv1.AppConfigurationV1 + appConfigurationClientErr error + + vpcErr error + vpcAPI *vpc.VpcV1 + + directlinkAPI *dl.DirectLinkV1 + directlinkErr error + dlProviderAPI *dlProviderV2.DirectLinkProviderV2 + dlProviderErr error + + cosConfigErr error + cosConfigAPI *cosconfig.ResourceConfigurationV1 + + transitgatewayAPI *tg.TransitGatewayApisV1 + transitgatewayErr error + + functionIAMNamespaceAPI functions.FunctionServiceAPI + functionIAMNamespaceErr error + + // CIS Zones + cisZonesErr error + cisZonesV1Client *ciszonesv1.ZonesV1 + + // CIS Alerts + cisAlertsClient *cisalertsv1.AlertsV1 + cisAlertsErr error + + // CIS Authenticated Origin Pull + cisOriginAuthClient *cisoriginpull.AuthenticatedOriginPullApiV1 + cisOriginAuthPullErr error + + // CIS dns service options + cisDNSErr error + cisDNSRecordsClient *cisdnsrecordsv1.DnsRecordsV1 + + // CIS dns bulk service options + cisDNSBulkErr error + cisDNSRecordBulkClient *cisdnsbulkv1.DnsRecordBulkV1 + + // CIS Global Load Balancer Pool service options + cisGLBPoolErr error + cisGLBPoolClient *cisglbpoolv0.GlobalLoadBalancerPoolsV0 + + // CIS GLB service options + cisGLBErr error + cisGLBClient *cisglbv1.GlobalLoadBalancerV1 + + // CIS GLB health check service options + cisGLBHealthCheckErr error + cisGLBHealthCheckClient *cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1 + + // CIS IP service options + cisIPErr error + cisIPClient *cisipv1.CisIpApiV1 + + // CIS Zone Rate Limits service options + cisRLErr error + cisRLClient *cisratelimitv1.ZoneRateLimitsV1 + + // CIS Page Rules service options + cisPageRuleErr error + cisPageRuleClient *cispagerulev1.PageRuleApiV1 + + // CIS Edge Functions service options + cisEdgeFunctionErr error + cisEdgeFunctionClient *cisedgefunctionv1.EdgeFunctionsApiV1 + + // CIS SSL certificate service options + cisSSLErr error + cisSSLClient *cissslv1.SslCertificateApiV1 + + // CIS WAF Package service options + cisWAFPackageErr error + cisWAFPackageClient *ciswafpackagev1.WafRulePackagesApiV1 + + // CIS Zone Setting service options + cisDomainSettingsErr error + cisDomainSettingsClient *cisdomainsettingsv1.ZonesSettingsV1 + + // CIS Routing service options + cisRoutingErr error + cisRoutingClient *cisroutingv1.RoutingV1 + + // CIS WAF Group service options + cisWAFGroupErr error + cisWAFGroupClient *ciswafgroupv1.WafRuleGroupsApiV1 + + // CIS Caching service options + cisCacheErr error + cisCacheClient *ciscachev1.CachingApiV1 + + // CIS Custom Pages service options + cisCustomPageErr error + cisCustomPageClient *ciscustompagev1.CustomPagesV1 + + // CIS Firewall Access rule service option + cisAccessRuleErr error + cisAccessRuleClient *cisaccessrulev1.ZoneFirewallAccessRulesV1 + + // CIS User Agent Blocking Rule service option + cisUARuleErr error + cisUARuleClient *cisuarulev1.UserAgentBlockingRulesV1 + + // CIS Firewall Lockdwon Rule service option + cisLockdownErr error + cisLockdownClient *cislockdownv1.ZoneLockdownV1 + + // CIS LogpushJobs service option + cisLogpushJobsClient *cislogpushjobsapiv1.LogpushJobsApiV1 + cisLogpushJobsErr error + + // CIS Range app service option + cisRangeAppErr error + cisRangeAppClient *cisrangeappv1.RangeApplicationsV1 + + // CIS WAF rule service options + cisWAFRuleErr error + cisWAFRuleClient *ciswafrulev1.WafRulesApiV1 + //IAM Identity Option + iamIdentityErr error + iamIdentityAPI *iamidentity.IamIdentityV1 + + //Resource Manager Option + resourceManagerErr error + resourceManagerAPI *resourcemanager.ResourceManagerV2 + + //Catalog Management Option + catalogManagementClient *catalogmanagementv1.CatalogManagementV1 + catalogManagementClientErr error + + enterpriseManagementClient *enterprisemanagementv1.EnterpriseManagementV1 + enterpriseManagementClientErr error + + //Resource Controller Option + resourceControllerErr error + resourceControllerAPI *resourcecontroller.ResourceControllerV2 + secretsManagerClient *secretsmanagerv1.SecretsManagerV1 + secretsManagerClientErr error + + // Schematics service options + schematicsClient *schematicsv1.SchematicsV1 + schematicsClientErr error + + //Satellite service + satelliteClient *kubernetesserviceapiv1.KubernetesServiceApiV1 + satelliteClientErr error + + //IAM Policy Management + iamPolicyManagementErr error + iamPolicyManagementAPI *iampolicymanagement.IamPolicyManagementV1 + + //IAM Access Groups + iamAccessGroupsErr error + iamAccessGroupsAPI *iamaccessgroups.IamAccessGroupsV2 + + // MTLS Session options + cisMtlsClient *cismtlsv1.MtlsV1 + cisMtlsErr error + + // CIS Webhooks options + cisWebhooksClient *ciswebhooksv1.WebhooksV1 + cisWebhooksErr error + + // CIS Filters options + cisFiltersClient *cisfiltersv1.FiltersV1 + cisFiltersErr error + + // CIS FirewallRules options + cisFirewallRulesClient *cisfirewallrulesv1.FirewallRulesV1 + cisFirewallRulesErr error + + //Atracker + atrackerClient *atrackerv1.AtrackerV1 + atrackerClientErr error + + atrackerClientV2 *atrackerv2.AtrackerV2 + atrackerClientV2Err error + + //Satellite link service + satelliteLinkClient *satellitelinkv1.SatelliteLinkV1 + satelliteLinkClientErr error + + esSchemaRegistryClient *schemaregistryv1.SchemaregistryV1 + esSchemaRegistryErr error + + // Security and Compliance Center (SCC) Admin + adminServiceApiClient *adminserviceapiv1.AdminServiceApiV1 + adminServiceApiClientErr error + + // Security and Compliance Center (SCC) Governance + configServiceApiClient *configurationgovernancev1.ConfigurationGovernanceV1 + configServiceApiClientErr error + + //Security and Compliance Center (SCC) Compliance posture + postureManagementClientErr error + postureManagementClient *posturemanagementv1.PostureManagementV1 + + //Security and Compliance Center (SCC) Compliance posture v2 + postureManagementClientv2 *posturemanagementv2.PostureManagementV2 + postureManagementClientErrv2 error + + // context Based Restrictions (CBR) + contextBasedRestrictionsClient *contextbasedrestrictionsv1.ContextBasedRestrictionsV1 + contextBasedRestrictionsClientErr error + + // CD Toolchain + cdToolchainClient *cdtoolchainv2.CdToolchainV2 + cdToolchainClientErr error + + // CD Tekton Pipeline + cdTektonPipelineClient *cdtektonpipelinev2.CdTektonPipelineV2 + cdTektonPipelineClientErr error +} + +// AppIDAPI provides AppID Service APIs ... +func (session clientSession) AppIDAPI() (*appid.AppIDManagementV4, error) { + return session.appidAPI, session.appidErr +} + +func (session clientSession) CatalogManagementV1() (*catalogmanagementv1.CatalogManagementV1, error) { + return session.catalogManagementClient, session.catalogManagementClientErr +} + +// BluemixAcccountAPI ... +func (sess clientSession) BluemixAcccountAPI() (accountv2.AccountServiceAPI, error) { + return sess.bmxAccountServiceAPI, sess.accountConfigErr +} + +// BluemixAcccountAPI ... +func (sess clientSession) BluemixAcccountv1API() (accountv1.AccountServiceAPI, error) { + return sess.bmxAccountv1ServiceAPI, sess.accountV1ConfigErr +} + +// BluemixSession to provide the Bluemix Session +func (sess clientSession) BluemixSession() (*bxsession.Session, error) { + return sess.session.BluemixSession, sess.bluemixSessionErr +} + +// BluemixUserDetails ... +func (sess clientSession) BluemixUserDetails() (*UserConfig, error) { + return sess.bmxUserDetails, sess.bmxUserFetchErr +} + +// ContainerAPI provides Container Service APIs ... +func (sess clientSession) ContainerAPI() (containerv1.ContainerServiceAPI, error) { + return sess.csServiceAPI, sess.csConfigErr +} + +// VpcContainerAPI provides v2Container Service APIs ... +func (sess clientSession) VpcContainerAPI() (containerv2.ContainerServiceAPI, error) { + return sess.csv2ServiceAPI, sess.csv2ConfigErr +} + +// ContainerRegistryV1 provides Container Registry Service APIs ... +func (session clientSession) ContainerRegistryV1() (*containerregistryv1.ContainerRegistryV1, error) { + return session.containerRegistryClient, session.containerRegistryClientErr +} + +// SchematicsAPI provides schematics Service APIs ... +func (sess clientSession) SchematicsV1() (*schematicsv1.SchematicsV1, error) { + if sess.schematicsClientErr != nil { + return sess.schematicsClient, sess.schematicsClientErr + } + return sess.schematicsClient.Clone(), nil + // return sess.schematicsClient, sess.schematicsClientErr +} + +// FunctionClient ... +func (sess clientSession) FunctionClient() (*whisk.Client, error) { + return sess.functionClient, sess.functionConfigErr +} + +// GlobalSearchAPI provides Global Search APIs ... +func (sess clientSession) GlobalSearchAPI() (globalsearchv2.GlobalSearchServiceAPI, error) { + return sess.globalSearchServiceAPI, sess.globalSearchConfigErr +} + +// GlobalTaggingAPI provides Global Search APIs ... +func (sess clientSession) GlobalTaggingAPI() (globaltaggingv3.GlobalTaggingServiceAPI, error) { + return sess.globalTaggingServiceAPI, sess.globalTaggingConfigErr +} + +// GlobalTaggingAPIV1 provides Platform-go Global Tagging APIs ... +func (sess clientSession) GlobalTaggingAPIv1() (globaltaggingv1.GlobalTaggingV1, error) { + return sess.globalTaggingServiceAPIV1, sess.globalTaggingConfigErrV1 +} + +// HpcsEndpointAPI provides Hpcs Endpoint generator APIs ... +func (sess clientSession) HpcsEndpointAPI() (hpcs.HPCSV2, error) { + return sess.hpcsEndpointAPI, sess.hpcsEndpointErr +} + +// UKO +func (session clientSession) UkoV4() (*ukov4.UkoV4, error) { + return session.ukoClient, session.ukoClientErr +} + +// UserManagementAPI provides User management APIs ... +func (sess clientSession) UserManagementAPI() (usermanagementv2.UserManagementAPI, error) { + return sess.userManagementAPI, sess.userManagementErr +} + +// IAM Policy Management +func (sess clientSession) IAMPolicyManagementV1API() (*iampolicymanagement.IamPolicyManagementV1, error) { + return sess.iamPolicyManagementAPI, sess.iamPolicyManagementErr +} + +// IAMAccessGroupsV2 provides IAM AG APIs ... +func (sess clientSession) IAMAccessGroupsV2() (*iamaccessgroups.IamAccessGroupsV2, error) { + return sess.iamAccessGroupsAPI, sess.iamAccessGroupsErr +} + +// IBM Cloud Shell +func (session clientSession) IBMCloudShellV1() (*ibmcloudshellv1.IBMCloudShellV1, error) { + return session.ibmCloudShellClient, session.ibmCloudShellClientErr +} + +// IcdAPI provides IBM Cloud Databases APIs ... +func (sess clientSession) ICDAPI() (icdv4.ICDServiceAPI, error) { + return sess.icdServiceAPI, sess.icdConfigErr +} + +// The IBM Cloud Databases API +func (session clientSession) CloudDatabasesV5() (*clouddatabasesv5.CloudDatabasesV5, error) { + return session.cloudDatabasesClient, session.cloudDatabasesClientErr +} + +// MccpAPI provides Multi Cloud Controller Proxy APIs ... +func (sess clientSession) MccpAPI() (mccpv2.MccpServiceAPI, error) { + return sess.cfServiceAPI, sess.cfConfigErr +} + +// ResourceCatalogAPI ... +func (sess clientSession) ResourceCatalogAPI() (catalog.ResourceCatalogAPI, error) { + return sess.resourceCatalogServiceAPI, sess.resourceCatalogConfigErr +} + +// ResourceManagementAPIv2 ... +func (sess clientSession) ResourceManagementAPIv2() (managementv2.ResourceManagementAPIv2, error) { + return sess.resourceManagementServiceAPIv2, sess.resourceManagementConfigErrv2 +} + +// ResourceControllerAPI ... +func (sess clientSession) ResourceControllerAPI() (controller.ResourceControllerAPI, error) { + return sess.resourceControllerServiceAPI, sess.resourceControllerConfigErr +} + +// ResourceControllerAPIv2 ... +func (sess clientSession) ResourceControllerAPIV2() (controllerv2.ResourceControllerAPIV2, error) { + return sess.resourceControllerServiceAPIv2, sess.resourceControllerConfigErrv2 +} + +// SoftLayerSession providers SoftLayer Session +func (sess clientSession) SoftLayerSession() *slsession.Session { + return sess.session.SoftLayerSession +} + +// CertManagementAPI provides Certificate management APIs ... +func (sess clientSession) CertificateManagerAPI() (certificatemanager.CertificateManagerServiceAPI, error) { + return sess.certManagementAPI, sess.certManagementErr +} + +// apigatewayAPI provides API Gateway APIs +func (sess clientSession) APIGateway() (*apigateway.ApiGatewayControllerApiV1, error) { + return sess.apigatewayAPI, sess.apigatewayErr +} + +func (session clientSession) PushServiceV1() (*pushservicev1.PushServiceV1, error) { + return session.pushServiceClient, session.pushServiceClientErr +} + +func (session clientSession) EventNotificationsApiV1() (*eventnotificationsv1.EventNotificationsV1, error) { + return session.eventNotificationsApiClient, session.eventNotificationsApiClientErr +} + +func (session clientSession) AppConfigurationV1() (*appconfigurationv1.AppConfigurationV1, error) { + return session.appConfigurationClient, session.appConfigurationClientErr +} + +func (sess clientSession) KeyProtectAPI() (*kp.Client, error) { + return sess.kpAPI, sess.kpErr +} + +func (sess clientSession) KeyManagementAPI() (*kp.Client, error) { + if sess.kmsErr == nil { + var clientConfig *kp.ClientConfig + if sess.kmsAPI.Config.APIKey != "" { + clientConfig = &kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, sess.kmsAPI.Config.BaseURL), + APIKey: sess.kmsAPI.Config.APIKey, //pragma: allowlist secret + Verbose: kp.VerboseFailOnly, + TokenURL: sess.kmsAPI.Config.TokenURL, + } + } else { + clientConfig = &kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, sess.kmsAPI.Config.BaseURL), + Authorization: sess.session.BluemixSession.Config.IAMAccessToken, //pragma: allowlist secret + Verbose: kp.VerboseFailOnly, + TokenURL: sess.kmsAPI.Config.TokenURL, + } + } + + kpClient, err := kp.New(*clientConfig, DefaultTransport()) + if err != nil { + sess.kpErr = fmt.Errorf("[ERROR] Error occured while configuring Key Protect Service: %q", err) + } + return kpClient, nil + } + return sess.kmsAPI, sess.kmsErr +} + +func (sess clientSession) VpcV1API() (*vpc.VpcV1, error) { + return sess.vpcAPI, sess.vpcErr +} + +func (sess clientSession) DirectlinkV1API() (*dl.DirectLinkV1, error) { + return sess.directlinkAPI, sess.directlinkErr +} +func (sess clientSession) DirectlinkProviderV2API() (*dlProviderV2.DirectLinkProviderV2, error) { + return sess.dlProviderAPI, sess.dlProviderErr +} +func (sess clientSession) CosConfigV1API() (*cosconfig.ResourceConfigurationV1, error) { + return sess.cosConfigAPI, sess.cosConfigErr +} + +func (sess clientSession) TransitGatewayV1API() (*tg.TransitGatewayApisV1, error) { + return sess.transitgatewayAPI, sess.transitgatewayErr +} + +// Session to the Power Colo Service + +func (sess clientSession) IBMPISession() (*ibmpisession.IBMPISession, error) { + return sess.ibmpiSession, sess.ibmpiConfigErr +} + +// Private DNS Service + +func (sess clientSession) PrivateDNSClientSession() (*dns.DnsSvcsV1, error) { + return sess.pDNSClient, sess.pDNSErr +} + +// Session to the Namespace cloud function + +func (sess clientSession) FunctionIAMNamespaceAPI() (functions.FunctionServiceAPI, error) { + return sess.functionIAMNamespaceAPI, sess.functionIAMNamespaceErr +} + +// CIS Zones Service +func (sess clientSession) CisZonesV1ClientSession() (*ciszonesv1.ZonesV1, error) { + if sess.cisZonesErr != nil { + return sess.cisZonesV1Client, sess.cisZonesErr + } + return sess.cisZonesV1Client.Clone(), nil +} + +// CIS DNS Service +func (sess clientSession) CisDNSRecordClientSession() (*cisdnsrecordsv1.DnsRecordsV1, error) { + if sess.cisDNSErr != nil { + return sess.cisDNSRecordsClient, sess.cisDNSErr + } + return sess.cisDNSRecordsClient.Clone(), nil +} + +// CIS DNS Bulk Service +func (sess clientSession) CisDNSRecordBulkClientSession() (*cisdnsbulkv1.DnsRecordBulkV1, error) { + if sess.cisDNSBulkErr != nil { + return sess.cisDNSRecordBulkClient, sess.cisDNSBulkErr + } + return sess.cisDNSRecordBulkClient.Clone(), nil +} + +// CIS GLB Pool +func (sess clientSession) CisGLBPoolClientSession() (*cisglbpoolv0.GlobalLoadBalancerPoolsV0, error) { + if sess.cisGLBPoolErr != nil { + return sess.cisGLBPoolClient, sess.cisGLBPoolErr + } + return sess.cisGLBPoolClient.Clone(), nil +} + +// CIS GLB +func (sess clientSession) CisGLBClientSession() (*cisglbv1.GlobalLoadBalancerV1, error) { + if sess.cisGLBErr != nil { + return sess.cisGLBClient, sess.cisGLBErr + } + return sess.cisGLBClient.Clone(), nil +} + +// CIS GLB Health Check/Monitor +func (sess clientSession) CisGLBHealthCheckClientSession() (*cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1, error) { + if sess.cisGLBHealthCheckErr != nil { + return sess.cisGLBHealthCheckClient, sess.cisGLBHealthCheckErr + } + return sess.cisGLBHealthCheckClient.Clone(), nil +} + +// CIS Zone Rate Limits +func (sess clientSession) CisRLClientSession() (*cisratelimitv1.ZoneRateLimitsV1, error) { + if sess.cisRLErr != nil { + return sess.cisRLClient, sess.cisRLErr + } + return sess.cisRLClient.Clone(), nil +} + +// CIS IP +func (sess clientSession) CisIPClientSession() (*cisipv1.CisIpApiV1, error) { + if sess.cisIPErr != nil { + return sess.cisIPClient, sess.cisIPErr + } + return sess.cisIPClient.Clone(), nil +} + +// CIS Page Rules +func (sess clientSession) CisPageRuleClientSession() (*cispagerulev1.PageRuleApiV1, error) { + if sess.cisPageRuleErr != nil { + return sess.cisPageRuleClient, sess.cisPageRuleErr + } + return sess.cisPageRuleClient.Clone(), nil +} + +// CIS Edge Function +func (sess clientSession) CisEdgeFunctionClientSession() (*cisedgefunctionv1.EdgeFunctionsApiV1, error) { + if sess.cisEdgeFunctionErr != nil { + return sess.cisEdgeFunctionClient, sess.cisEdgeFunctionErr + } + return sess.cisEdgeFunctionClient.Clone(), nil +} + +// CIS SSL certificate +func (sess clientSession) CisSSLClientSession() (*cissslv1.SslCertificateApiV1, error) { + if sess.cisSSLErr != nil { + return sess.cisSSLClient, sess.cisSSLErr + } + return sess.cisSSLClient.Clone(), nil +} + +// CIS WAF Packages +func (sess clientSession) CisWAFPackageClientSession() (*ciswafpackagev1.WafRulePackagesApiV1, error) { + if sess.cisWAFPackageErr != nil { + return sess.cisWAFPackageClient, sess.cisWAFPackageErr + } + return sess.cisWAFPackageClient.Clone(), nil +} + +// CIS Zone Settings +func (sess clientSession) CisDomainSettingsClientSession() (*cisdomainsettingsv1.ZonesSettingsV1, error) { + if sess.cisDomainSettingsErr != nil { + return sess.cisDomainSettingsClient, sess.cisDomainSettingsErr + } + return sess.cisDomainSettingsClient.Clone(), nil +} + +// CIS Alerts +func (sess clientSession) CisAlertsSession() (*cisalertsv1.AlertsV1, error) { + if sess.cisAlertsErr != nil { + return sess.cisAlertsClient, sess.cisAlertsErr + } + return sess.cisAlertsClient.Clone(), nil +} + +// CIS Routing +func (sess clientSession) CisRoutingClientSession() (*cisroutingv1.RoutingV1, error) { + if sess.cisRoutingErr != nil { + return sess.cisRoutingClient, sess.cisRoutingErr + } + return sess.cisRoutingClient.Clone(), nil +} + +// CIS WAF Group +func (sess clientSession) CisWAFGroupClientSession() (*ciswafgroupv1.WafRuleGroupsApiV1, error) { + if sess.cisWAFGroupErr != nil { + return sess.cisWAFGroupClient, sess.cisWAFGroupErr + } + return sess.cisWAFGroupClient.Clone(), nil +} + +// CIS Cache service +func (sess clientSession) CisCacheClientSession() (*ciscachev1.CachingApiV1, error) { + if sess.cisCacheErr != nil { + return sess.cisCacheClient, sess.cisCacheErr + } + return sess.cisCacheClient.Clone(), nil +} + +// CIS Zone Settings +func (sess clientSession) CisCustomPageClientSession() (*ciscustompagev1.CustomPagesV1, error) { + if sess.cisCustomPageErr != nil { + return sess.cisCustomPageClient, sess.cisCustomPageErr + } + return sess.cisCustomPageClient.Clone(), nil +} + +// CIS Firewall access rule +func (sess clientSession) CisAccessRuleClientSession() (*cisaccessrulev1.ZoneFirewallAccessRulesV1, error) { + if sess.cisAccessRuleErr != nil { + return sess.cisAccessRuleClient, sess.cisAccessRuleErr + } + return sess.cisAccessRuleClient.Clone(), nil +} + +// CIS User Agent Blocking rule +func (sess clientSession) CisUARuleClientSession() (*cisuarulev1.UserAgentBlockingRulesV1, error) { + if sess.cisUARuleErr != nil { + return sess.cisUARuleClient, sess.cisUARuleErr + } + return sess.cisUARuleClient.Clone(), nil +} + +// CIS Firewall Lockdown rule +func (sess clientSession) CisLockdownClientSession() (*cislockdownv1.ZoneLockdownV1, error) { + if sess.cisLockdownErr != nil { + return sess.cisLockdownClient, sess.cisLockdownErr + } + return sess.cisLockdownClient.Clone(), nil +} + +// CIS Range app rule +func (sess clientSession) CisRangeAppClientSession() (*cisrangeappv1.RangeApplicationsV1, error) { + if sess.cisRangeAppErr != nil { + return sess.cisRangeAppClient, sess.cisRangeAppErr + } + return sess.cisRangeAppClient.Clone(), nil +} + +// CIS WAF Rule +func (sess clientSession) CisWAFRuleClientSession() (*ciswafrulev1.WafRulesApiV1, error) { + if sess.cisWAFRuleErr != nil { + return sess.cisWAFRuleClient, sess.cisWAFRuleErr + } + return sess.cisWAFRuleClient.Clone(), nil +} + +// CIS Authenticated Origin Pull +func (sess clientSession) CisOrigAuthSession() (*cisoriginpull.AuthenticatedOriginPullApiV1, error) { + if sess.cisOriginAuthPullErr != nil { + return sess.cisOriginAuthClient, sess.cisOriginAuthPullErr + } + return sess.cisOriginAuthClient.Clone(), nil +} + +// IAM Identity Session +func (sess clientSession) IAMIdentityV1API() (*iamidentity.IamIdentityV1, error) { + return sess.iamIdentityAPI, sess.iamIdentityErr +} + +// ResourceMAanger Session +func (sess clientSession) ResourceManagerV2API() (*resourcemanager.ResourceManagerV2, error) { + return sess.resourceManagerAPI, sess.resourceManagerErr +} + +func (session clientSession) EnterpriseManagementV1() (*enterprisemanagementv1.EnterpriseManagementV1, error) { + return session.enterpriseManagementClient, session.enterpriseManagementClientErr +} + +// ResourceController Session +func (sess clientSession) ResourceControllerV2API() (*resourcecontroller.ResourceControllerV2, error) { + return sess.resourceControllerAPI, sess.resourceControllerErr +} + +// SecretsManager Session +func (session clientSession) SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) { + return session.secretsManagerClient, session.secretsManagerClientErr +} + +// Satellite Link +func (session clientSession) SatellitLinkClientSession() (*satellitelinkv1.SatelliteLinkV1, error) { + return session.satelliteLinkClient, session.satelliteLinkClientErr +} + +var cloudEndpoint = "cloud.ibm.com" + +// Session to the Satellite client +func (sess clientSession) SatelliteClientSession() (*kubernetesserviceapiv1.KubernetesServiceApiV1, error) { + return sess.satelliteClient, sess.satelliteClientErr +} + +// CIS LogPushJob +func (sess clientSession) CisLogpushJobsSession() (*cislogpushjobsapiv1.LogpushJobsApiV1, error) { + if sess.cisLogpushJobsErr != nil { + return sess.cisLogpushJobsClient, sess.cisLogpushJobsErr + } + return sess.cisLogpushJobsClient.Clone(), nil +} + +// CIS MTLS session +func (sess clientSession) CisMtlsSession() (*cismtlsv1.MtlsV1, error) { + if sess.cisMtlsErr != nil { + return sess.cisMtlsClient, sess.cisMtlsErr + } + return sess.cisMtlsClient.Clone(), nil +} + +// CIS Webhooks +func (sess clientSession) CisWebhookSession() (*ciswebhooksv1.WebhooksV1, error) { + if sess.cisWebhooksErr != nil { + return sess.cisWebhooksClient, sess.cisWebhooksErr + } + return sess.cisWebhooksClient.Clone(), nil +} + +// CIS Filters +func (sess clientSession) CisFiltersSession() (*cisfiltersv1.FiltersV1, error) { + if sess.cisFiltersErr != nil { + return sess.cisFiltersClient, sess.cisFiltersErr + } + return sess.cisFiltersClient.Clone(), nil +} + +// CIS FirewallRules +func (sess clientSession) CisFirewallRulesSession() (*cisfirewallrulesv1.FirewallRulesV1, error) { + if sess.cisFirewallRulesErr != nil { + return sess.cisFirewallRulesClient, sess.cisFirewallRulesErr + } + return sess.cisFirewallRulesClient.Clone(), nil +} + +// Activity Tracker API +func (session clientSession) AtrackerV1() (*atrackerv1.AtrackerV1, error) { + return session.atrackerClient, session.atrackerClientErr +} + +func (session clientSession) AtrackerV2() (*atrackerv2.AtrackerV2, error) { + return session.atrackerClientV2, session.atrackerClientV2Err +} + +func (session clientSession) ESschemaRegistrySession() (*schemaregistryv1.SchemaregistryV1, error) { + return session.esSchemaRegistryClient, session.esSchemaRegistryErr +} + +// Security and Compliance center Admin API +func (session clientSession) AdminServiceApiV1() (*adminserviceapiv1.AdminServiceApiV1, error) { + return session.adminServiceApiClient, session.adminServiceApiClientErr +} + +func (session clientSession) ConfigurationGovernanceV1() (*configurationgovernancev1.ConfigurationGovernanceV1, error) { + return session.configServiceApiClient, session.configServiceApiClientErr +} + +// Security and Compliance center Posture Management +func (session clientSession) PostureManagementV1() (*posturemanagementv1.PostureManagementV1, error) { + if session.postureManagementClientErr != nil { + return session.postureManagementClient, session.postureManagementClientErr + } + return session.postureManagementClient.Clone(), nil +} + +// Security and Compliance center Posture Management v2 +func (session clientSession) PostureManagementV2() (*posturemanagementv2.PostureManagementV2, error) { + if session.postureManagementClientErrv2 != nil { + return session.postureManagementClientv2, session.postureManagementClientErrv2 + } + return session.postureManagementClientv2.Clone(), nil +} + +// Context Based Restrictions +func (session clientSession) ContextBasedRestrictionsV1() (*contextbasedrestrictionsv1.ContextBasedRestrictionsV1, error) { + return session.contextBasedRestrictionsClient, session.contextBasedRestrictionsClientErr +} + +// CD Toolchain +func (session clientSession) CdToolchainV2() (*cdtoolchainv2.CdToolchainV2, error) { + return session.cdToolchainClient, session.cdToolchainClientErr +} + +// CD Tekton Pipeline +func (session clientSession) CdTektonPipelineV2() (*cdtektonpipelinev2.CdTektonPipelineV2, error) { + return session.cdTektonPipelineClient, session.cdTektonPipelineClientErr +} + +// ClientSession configures and returns a fully initialized ClientSession +func (c *Config) ClientSession() (interface{}, error) { + sess, err := newSession(c) + if err != nil { + return nil, err + } + log.Printf("[INFO] Configured Region: %s\n", c.Region) + session := clientSession{ + session: sess, + } + + if sess.BluemixSession == nil { + //Can be nil only if bluemix_api_key is not provided + log.Println("Skipping Bluemix Clients configuration") + session.bluemixSessionErr = errEmptyBluemixCredentials + session.accountConfigErr = errEmptyBluemixCredentials + session.accountV1ConfigErr = errEmptyBluemixCredentials + session.csConfigErr = errEmptyBluemixCredentials + session.csv2ConfigErr = errEmptyBluemixCredentials + session.containerRegistryClientErr = errEmptyBluemixCredentials + session.kpErr = errEmptyBluemixCredentials + session.pushServiceClientErr = errEmptyBluemixCredentials + session.appConfigurationClientErr = errEmptyBluemixCredentials + session.kmsErr = errEmptyBluemixCredentials + session.cfConfigErr = errEmptyBluemixCredentials + session.cisConfigErr = errEmptyBluemixCredentials + session.functionConfigErr = errEmptyBluemixCredentials + session.globalSearchConfigErr = errEmptyBluemixCredentials + session.globalTaggingConfigErr = errEmptyBluemixCredentials + session.globalTaggingConfigErrV1 = errEmptyBluemixCredentials + session.hpcsEndpointErr = errEmptyBluemixCredentials + session.iamAccessGroupsErr = errEmptyBluemixCredentials + session.icdConfigErr = errEmptyBluemixCredentials + session.resourceCatalogConfigErr = errEmptyBluemixCredentials + session.resourceManagerErr = errEmptyBluemixCredentials + session.resourceManagementConfigErrv2 = errEmptyBluemixCredentials + session.resourceControllerConfigErr = errEmptyBluemixCredentials + session.resourceControllerConfigErrv2 = errEmptyBluemixCredentials + session.enterpriseManagementClientErr = errEmptyBluemixCredentials + session.resourceControllerErr = errEmptyBluemixCredentials + session.catalogManagementClientErr = errEmptyBluemixCredentials + session.ibmpiConfigErr = errEmptyBluemixCredentials + session.userManagementErr = errEmptyBluemixCredentials + session.certManagementErr = errEmptyBluemixCredentials + session.vpcErr = errEmptyBluemixCredentials + session.apigatewayErr = errEmptyBluemixCredentials + session.pDNSErr = errEmptyBluemixCredentials + session.bmxUserFetchErr = errEmptyBluemixCredentials + session.directlinkErr = errEmptyBluemixCredentials + session.dlProviderErr = errEmptyBluemixCredentials + session.cosConfigErr = errEmptyBluemixCredentials + session.transitgatewayErr = errEmptyBluemixCredentials + session.functionIAMNamespaceErr = errEmptyBluemixCredentials + session.cisDNSErr = errEmptyBluemixCredentials + session.cisAlertsErr = errEmptyBluemixCredentials + session.cisDNSBulkErr = errEmptyBluemixCredentials + session.cisGLBPoolErr = errEmptyBluemixCredentials + session.cisGLBErr = errEmptyBluemixCredentials + session.cisGLBHealthCheckErr = errEmptyBluemixCredentials + session.cisIPErr = errEmptyBluemixCredentials + session.cisZonesErr = errEmptyBluemixCredentials + session.cisRLErr = errEmptyBluemixCredentials + session.cisPageRuleErr = errEmptyBluemixCredentials + session.cisEdgeFunctionErr = errEmptyBluemixCredentials + session.cisSSLErr = errEmptyBluemixCredentials + session.cisWAFPackageErr = errEmptyBluemixCredentials + session.cisDomainSettingsErr = errEmptyBluemixCredentials + session.cisRoutingErr = errEmptyBluemixCredentials + session.cisWAFGroupErr = errEmptyBluemixCredentials + session.cisCacheErr = errEmptyBluemixCredentials + session.cisCustomPageErr = errEmptyBluemixCredentials + session.cisMtlsErr = errEmptyBluemixCredentials + session.cisAccessRuleErr = errEmptyBluemixCredentials + session.cisUARuleErr = errEmptyBluemixCredentials + session.cisLockdownErr = errEmptyBluemixCredentials + session.cisRangeAppErr = errEmptyBluemixCredentials + session.cisWAFRuleErr = errEmptyBluemixCredentials + session.iamIdentityErr = errEmptyBluemixCredentials + session.secretsManagerClientErr = errEmptyBluemixCredentials + session.cisFiltersErr = errEmptyBluemixCredentials + session.cisWebhooksErr = errEmptyBluemixCredentials + session.cisLogpushJobsErr = errEmptyBluemixCredentials + session.schematicsClientErr = errEmptyBluemixCredentials + session.satelliteClientErr = errEmptyBluemixCredentials + session.iamPolicyManagementErr = errEmptyBluemixCredentials + session.satelliteLinkClientErr = errEmptyBluemixCredentials + session.esSchemaRegistryErr = errEmptyBluemixCredentials + session.contextBasedRestrictionsClientErr = errEmptyBluemixCredentials + session.postureManagementClientErr = errEmptyBluemixCredentials + session.postureManagementClientErrv2 = errEmptyBluemixCredentials + session.configServiceApiClientErr = errEmptyBluemixCredentials + session.cdTektonPipelineClientErr = errEmptyBluemixCredentials + session.cdToolchainClientErr = errEmptyBluemixCredentials + + return session, nil + } + + if sess.BluemixSession.Config.BluemixAPIKey != "" { + err = authenticateAPIKey(sess.BluemixSession) + if err != nil { + for count := c.RetryCount; count >= 0; count-- { + if err == nil || !isRetryable(err) { + break + } + time.Sleep(c.RetryDelay) + log.Printf("Retrying IAM Authentication %d", count) + err = authenticateAPIKey(sess.BluemixSession) + } + if err != nil { + session.bmxUserFetchErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for account user details: %q", err) + session.functionConfigErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for function: %q", err) + } + } + err = authenticateCF(sess.BluemixSession) + if err != nil { + for count := c.RetryCount; count >= 0; count-- { + if err == nil || !isRetryable(err) { + break + } + time.Sleep(c.RetryDelay) + log.Printf("Retrying CF Authentication %d", count) + err = authenticateCF(sess.BluemixSession) + } + if err != nil { + session.functionConfigErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for function: %q", err) + } + } + } + + if c.IAMTrustedProfileID == "" && sess.BluemixSession.Config.IAMAccessToken != "" && sess.BluemixSession.Config.BluemixAPIKey == "" { + err := RefreshToken(sess.BluemixSession) + if err != nil { + for count := c.RetryCount; count >= 0; count-- { + if err == nil || !isRetryable(err) { + break + } + time.Sleep(c.RetryDelay) + log.Printf("Retrying refresh token %d", count) + err = RefreshToken(sess.BluemixSession) + } + if err != nil { + return nil, fmt.Errorf("[ERROR] Error occured while refreshing the token: %q", err) + } + } + + } + userConfig, err := fetchUserDetails(sess.BluemixSession, c.RetryCount, c.RetryDelay) + if err != nil { + session.bmxUserFetchErr = fmt.Errorf("[ERROR] Error occured while fetching account user details: %q", err) + } + session.bmxUserDetails = userConfig + + if sess.SoftLayerSession != nil && sess.SoftLayerSession.IAMToken != "" { + sess.SoftLayerSession.IAMToken = sess.BluemixSession.Config.IAMAccessToken + sess.SoftLayerSession.IAMRefreshToken = sess.BluemixSession.Config.IAMRefreshToken + } + + session.functionClient, session.functionConfigErr = FunctionClient(sess.BluemixSession.Config) + + BluemixRegion = sess.BluemixSession.Config.Region + var fileMap map[string]interface{} + if f := EnvFallBack([]string{"IBMCLOUD_ENDPOINTS_FILE_PATH", "IC_ENDPOINTS_FILE_PATH"}, c.EndpointsFile); f != "" { + jsonFile, err := os.Open(f) + if err != nil { + log.Fatalf("Unable to open Endpoints File %s", err) + } + defer jsonFile.Close() + bytes, err := ioutil.ReadAll(jsonFile) + if err != nil { + log.Fatalf("Unable to read Endpoints File %s", err) + } + err = json.Unmarshal([]byte(bytes), &fileMap) + if err != nil { + log.Fatalf("Unable to unmarshal Endpoints File %s", err) + } + } + accv1API, err := accountv1.New(sess.BluemixSession) + if err != nil { + session.accountV1ConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Bluemix Accountv1 Service: %q", err) + } + session.bmxAccountv1ServiceAPI = accv1API + + accAPI, err := accountv2.New(sess.BluemixSession) + if err != nil { + session.accountConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Account Service: %q", err) + } + session.bmxAccountServiceAPI = accAPI + + cfAPI, err := mccpv2.New(sess.BluemixSession) + if err != nil { + session.cfConfigErr = fmt.Errorf("[ERROR] Error occured while configuring MCCP service: %q", err) + } + session.cfServiceAPI = cfAPI + + clusterAPI, err := containerv1.New(sess.BluemixSession) + if err != nil { + session.csConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Container Service for K8s cluster: %q", err) + } + session.csServiceAPI = clusterAPI + + v2clusterAPI, err := containerv2.New(sess.BluemixSession) + if err != nil { + session.csv2ConfigErr = fmt.Errorf("[ERROR] Error occured while configuring vpc Container Service for K8s cluster: %q", err) + } + session.csv2ServiceAPI = v2clusterAPI + + hpcsAPI, err := hpcs.New(sess.BluemixSession) + if err != nil { + session.hpcsEndpointErr = fmt.Errorf("[ERROR] Error occured while configuring hpcs Endpoint: %q", err) + } + session.hpcsEndpointAPI = hpcsAPI + + kpurl := ContructEndpoint(fmt.Sprintf("%s.kms", c.Region), cloudEndpoint) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + kpurl = ContructEndpoint(fmt.Sprintf("private.%s.kms", c.Region), cloudEndpoint) + } + if fileMap != nil && c.Visibility != "public-and-private" { + kpurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_KP_API_ENDPOINT", c.Region, kpurl) + } + var options kp.ClientConfig + if c.BluemixAPIKey != "" { + options = kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kpurl), + APIKey: sess.BluemixSession.Config.BluemixAPIKey, //pragma: allowlist secret + // InstanceID: "42fET57nnadurKXzXAedFLOhGqETfIGYxOmQXkFgkJV9", + Verbose: kp.VerboseFailOnly, + } + + } else { + options = kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kpurl), + Authorization: sess.BluemixSession.Config.IAMAccessToken, + // InstanceID: "42fET57nnadurKXzXAedFLOhGqETfIGYxOmQXkFgkJV9", + Verbose: kp.VerboseFailOnly, + } + } + kpAPIclient, err := kp.New(options, DefaultTransport()) + if err != nil { + session.kpErr = fmt.Errorf("[ERROR] Error occured while configuring Key Protect Service: %q", err) + } + session.kpAPI = kpAPIclient + + iamURL := iamidentity.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + iamURL = ContructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) + } else { + iamURL = ContructEndpoint("private.iam", cloudEndpoint) + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + iamURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamURL) + } + + // KEY MANAGEMENT Service + kmsurl := ContructEndpoint(fmt.Sprintf("%s.kms", c.Region), cloudEndpoint) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + kmsurl = ContructEndpoint(fmt.Sprintf("private.%s.kms", c.Region), cloudEndpoint) + } + if fileMap != nil && c.Visibility != "public-and-private" { + kmsurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_KP_API_ENDPOINT", c.Region, kmsurl) + } + var kmsOptions kp.ClientConfig + if c.BluemixAPIKey != "" { + kmsOptions = kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kmsurl), + APIKey: sess.BluemixSession.Config.BluemixAPIKey, //pragma: allowlist secret + // InstanceID: "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8", + Verbose: kp.VerboseFailOnly, + TokenURL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL) + "/identity/token", + } + + } else { + kmsOptions = kp.ClientConfig{ + BaseURL: EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kmsurl), + Authorization: sess.BluemixSession.Config.IAMAccessToken, + // InstanceID: "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8", + Verbose: kp.VerboseFailOnly, + TokenURL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL) + "/identity/token", + } + } + kmsAPIclient, err := kp.New(kmsOptions, DefaultTransport()) + if err != nil { + session.kmsErr = fmt.Errorf("[ERROR] Error occured while configuring key Service: %q", err) + } + session.kmsAPI = kmsAPIclient + + var authenticator core.Authenticator + + if c.BluemixAPIKey != "" || sess.BluemixSession.Config.IAMRefreshToken != "" { + if c.BluemixAPIKey != "" { + authenticator = &core.IamAuthenticator{ + ApiKey: c.BluemixAPIKey, + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL), + } + } else { + // Construct the IamAuthenticator with the IAM refresh token. + authenticator = &core.IamAuthenticator{ + RefreshToken: sess.BluemixSession.Config.IAMRefreshToken, + ClientId: "bx", + ClientSecret: "bx", + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL), + } + } + } else if strings.HasPrefix(sess.BluemixSession.Config.IAMAccessToken, "Bearer") { + authenticator = &core.BearerTokenAuthenticator{ + BearerToken: sess.BluemixSession.Config.IAMAccessToken[7:], + } + } else { + authenticator = &core.BearerTokenAuthenticator{ + BearerToken: sess.BluemixSession.Config.IAMAccessToken, + } + } + + // Construct an "options" struct for creating the service client. + ukoClientOptions := &ukov4.UkoV4Options{ + Authenticator: authenticator, + } + + // Construct the service client. + session.ukoClient, err = ukov4.NewUkoV4(ukoClientOptions) + if err == nil { + // Enable retries for API calls + session.ukoClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.ukoClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.ukoClientErr = fmt.Errorf("Error occurred while configuring HPCS UKO service: %q", err) + } + + // APPID Service + appIDEndpoint := fmt.Sprintf("https://%s.appid.cloud.ibm.com", c.Region) + if c.Visibility == "private" { + session.appidErr = fmt.Errorf("App Id resources doesnot support private endpoints") + } + if fileMap != nil && c.Visibility != "public-and-private" { + appIDEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_APPID_MANAGEMENT_API_ENDPOINT", c.Region, appIDEndpoint) + } + appIDClientOptions := &appid.AppIDManagementV4Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_APPID_MANAGEMENT_API_ENDPOINT"}, appIDEndpoint), + } + appIDClient, err := appid.NewAppIDManagementV4(appIDClientOptions) + if err != nil { + session.appidErr = fmt.Errorf("error occured while configuring AppID service: #{err}") + } + if appIDClient != nil && appIDClient.Service != nil { + appIDClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + appIDClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.appidAPI = appIDClient + + // Construct an "options" struct for creating Context Based Restrictions service client. + cbrURL := contextbasedrestrictionsv1.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + session.contextBasedRestrictionsClientErr = fmt.Errorf("Context Based Restrictions Service API does not support private endpoints") //return this error if private endpoints are not supported + } + if fileMap != nil && c.Visibility != "public-and-private" { + cbrURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CONTEXT_BASED_RESTRICTIONS_ENDPOINT", c.Region, cbrURL) + } + contextBasedRestrictionsClientOptions := &contextbasedrestrictionsv1.ContextBasedRestrictionsV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_CONTEXT_BASED_RESTRICTIONS_ENDPOINT"}, cbrURL), + } + + // Construct the service client. + session.contextBasedRestrictionsClient, err = contextbasedrestrictionsv1.NewContextBasedRestrictionsV1(contextBasedRestrictionsClientOptions) + if err == nil && session.contextBasedRestrictionsClient != nil { + // Enable retries for API calls + session.contextBasedRestrictionsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.contextBasedRestrictionsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.contextBasedRestrictionsClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Context Based Restrictions service: %q", err) + } + + // CATALOG MANAGEMENT Service + catalogManagementURL := "https://cm.globalcatalog.cloud.ibm.com/api/v1-beta" + if c.Visibility == "private" { + session.catalogManagementClientErr = fmt.Errorf("Catalog Management resource doesnot support private endpoints") + } + if fileMap != nil && c.Visibility != "public-and-private" { + catalogManagementURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CATALOG_MANAGEMENT_API_ENDPOINT", c.Region, catalogManagementURL) + } + catalogManagementClientOptions := &catalogmanagementv1.CatalogManagementV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_CATALOG_MANAGEMENT_API_ENDPOINT"}, catalogManagementURL), + Authenticator: authenticator, + } + // Construct the service client. + session.catalogManagementClient, err = catalogmanagementv1.NewCatalogManagementV1(catalogManagementClientOptions) + if err != nil { + session.catalogManagementClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Catalog Management API service: %q", err) + } + if session.catalogManagementClient != nil && session.catalogManagementClient.Service != nil { + // Enable retries for API calls + session.catalogManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.catalogManagementClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // ATRACKER Service + var atrackerClientURL string + var atrackerURLErr error + + atrackerClientURL, atrackerURLErr = atrackerv1.GetServiceURLForRegion(c.Region) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + atrackerClientURL, atrackerURLErr = atrackerv1.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + atrackerClientURL, atrackerURLErr = atrackerv1.GetServiceURLForRegion(c.Region) + } + } + + if fileMap != nil && c.Visibility != "public-and-private" { + atrackerClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_ATRACKER_API_ENDPOINT", c.Region, atrackerClientURL) + } + atrackerClientOptions := &atrackerv1.AtrackerV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_ATRACKER_API_ENDPOINT"}, atrackerClientURL), + } + // If we provide IBMCLOUD_ATRACKER_API_ENDPOINT, then ignore any missing region url + if atrackerURLErr != nil && len(atrackerClientOptions.URL) == 0 { + session.atrackerClientErr = atrackerURLErr + } + // Construct the service client. + session.atrackerClient, err = atrackerv1.NewAtrackerV1(atrackerClientOptions) + if err != nil { + session.atrackerClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Activity Tracker API service: %q", err) + } + if session.atrackerClient != nil && session.atrackerClient.Service != nil { + // Enable retries for API calls + session.atrackerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.atrackerClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + // Version 2 Atracker + var atrackerClientV2URL string + var atrackerURLV2Err error + + if c.Visibility == "private" || c.Visibility == "public-and-private" { + atrackerClientV2URL, atrackerURLV2Err = atrackerv2.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + atrackerClientV2URL, atrackerURLV2Err = atrackerv2.GetServiceURLForRegion(c.Region) + } + } else { + atrackerClientV2URL, atrackerURLV2Err = atrackerv2.GetServiceURLForRegion(c.Region) + } + if atrackerURLV2Err != nil { + atrackerClientV2URL = atrackerv2.DefaultServiceURL + } + if fileMap != nil && c.Visibility != "public-and-private" { + atrackerClientV2URL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_ATRACKER_API_ENDPOINT", c.Region, atrackerClientV2URL) + } + atrackerClientV2Options := &atrackerv2.AtrackerV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_ATRACKER_API_ENDPOINT"}, atrackerClientV2URL), + } + // If we provide IBMCLOUD_ATRACKER_API_ENDPOINT, then ignore any missing region url, or should use the default. + // This should technically never happen as we default this for v2 + if atrackerURLV2Err != nil && len(atrackerClientOptions.URL) == 0 { + session.atrackerClientErr = atrackerURLErr + } + session.atrackerClientV2, err = atrackerv2.NewAtrackerV2(atrackerClientV2Options) + if err == nil { + // Enable retries for API calls + session.atrackerClientV2.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.atrackerClientV2.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.atrackerClientV2Err = fmt.Errorf("Error occurred while configuring Activity Tracker API Version 2 service: %q", err) + } + + // SCC ADMIN Service + var adminServiceApiClientURL string + if c.Visibility == "private" || c.Visibility == "public-and-private" { + adminServiceApiClientURL, err = adminserviceapiv1.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + adminServiceApiClientURL, err = adminserviceapiv1.GetServiceURLForRegion(c.Region) + } + } else { + adminServiceApiClientURL, err = adminserviceapiv1.GetServiceURLForRegion(c.Region) + } + if err != nil { + adminServiceApiClientURL = adminserviceapiv1.DefaultServiceURL + } + adminServiceApiClientOptions := &adminserviceapiv1.AdminServiceApiV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_SCC_ADMIN_API_ENDPOINT"}, adminServiceApiClientURL), + } + + // Construct the service client. + session.adminServiceApiClient, err = adminserviceapiv1.NewAdminServiceApiV1(adminServiceApiClientOptions) + if err == nil { + // Enable retries for API calls + session.adminServiceApiClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.adminServiceApiClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.adminServiceApiClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Admin Service API service: %q", err) + } + + // SCHEMATICS Service + // schematicsEndpoint := "https://schematics.cloud.ibm.com" + schematicsEndpoint := ContructEndpoint(fmt.Sprintf("%s.schematics", c.Region), cloudEndpoint) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + schematicsEndpoint = ContructEndpoint(fmt.Sprintf("private-%s.schematics", c.Region), cloudEndpoint) + } + if fileMap != nil && c.Visibility != "public-and-private" { + schematicsEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SCHEMATICS_API_ENDPOINT", c.Region, schematicsEndpoint) + } + schematicsClientOptions := &schematicsv1.SchematicsV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_SCHEMATICS_API_ENDPOINT"}, schematicsEndpoint), + } + // Construct the service client. + schematicsClient, err := schematicsv1.NewSchematicsV1(schematicsClientOptions) + if err != nil { + session.schematicsClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Schematics Service API service: %q", err) + } + // Enable retries for API calls + if schematicsClient != nil && schematicsClient.Service != nil { + schematicsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + schematicsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.schematicsClient = schematicsClient + + // VPC Service + vpcurl := ContructEndpoint(fmt.Sprintf("%s.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + vpcurl = ContructEndpoint(fmt.Sprintf("%s.private.iaas", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + vpcurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IS_NG_API_ENDPOINT", c.Region, vpcurl) + } + vpcoptions := &vpc.VpcV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_IS_NG_API_ENDPOINT"}, vpcurl), + Authenticator: authenticator, + } + vpcclient, err := vpc.NewVpcV1(vpcoptions) + if err != nil { + session.vpcErr = fmt.Errorf("[ERROR] Error occured while configuring vpc service: %q", err) + } + if vpcclient != nil && vpcclient.Service != nil { + vpcclient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + vpcclient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.vpcAPI = vpcclient + + // PUSH NOTIFICATIONS Service + pnurl := fmt.Sprintf("https://%s.imfpush.cloud.ibm.com/imfpush/v1", c.Region) + if c.Visibility == "private" { + session.pushServiceClientErr = fmt.Errorf("Push Notifications Service API doesnot support private endpoints") + } + if fileMap != nil && c.Visibility != "public-and-private" { + pnurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_PUSH_API_ENDPOINT", c.Region, pnurl) + } + pushNotificationOptions := &pushservicev1.PushServiceV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_PUSH_API_ENDPOINT"}, pnurl), + Authenticator: authenticator, + } + pnclient, err := pushservicev1.NewPushServiceV1(pushNotificationOptions) + if err != nil { + session.pushServiceClientErr = fmt.Errorf("[ERROR] Error occured while configuring Push Notifications service: %q", err) + } + if pnclient != nil && pnclient.Service != nil { + // Enable retries for API calls + pnclient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + pnclient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.pushServiceClient = pnclient + // event notifications + enurl := fmt.Sprintf("https://%s.event-notifications.cloud.ibm.com/event-notifications", c.Region) + if c.Visibility == "private" { + session.eventNotificationsApiClientErr = fmt.Errorf("Event Notifications Service does not support private endpoints") + } + if fileMap != nil && c.Visibility != "public-and-private" { + enurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_EVENT_NOTIFICATIONS_API_ENDPOINT", c.Region, enurl) + } + enClientOptions := &eventnotificationsv1.EventNotificationsV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_EVENT_NOTIFICATIONS_API_ENDPOINT"}, enurl), + } + // Construct the service client. + session.eventNotificationsApiClient, err = eventnotificationsv1.NewEventNotificationsV1(enClientOptions) + if err != nil { + // Enable { + session.eventNotificationsApiClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Event Notifications service: %q", err) + } + if session.eventNotificationsApiClient != nil && session.eventNotificationsApiClient.Service != nil { + // Enable retries for API calls + session.eventNotificationsApiClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.eventNotificationsApiClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // APP CONFIGURATION Service + appconfigurl := ContructEndpoint(fmt.Sprintf("%s", c.Region), fmt.Sprintf("%s.apprapp.", cloudEndpoint)) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + appconfigurl = ContructEndpoint(fmt.Sprintf("%s.private", c.Region), fmt.Sprintf("%s.apprapp", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + appconfigurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_APP_CONFIG_ENDPOINT", c.Region, appconfigurl) + } + appConfigurationClientOptions := &appconfigurationv1.AppConfigurationV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_APP_CONFIG_ENDPOINT"}, appconfigurl), + Authenticator: authenticator, + } + + appConfigClient, err := appconfigurationv1.NewAppConfigurationV1(appConfigurationClientOptions) + if appConfigClient != nil { + // Enable retries for API calls + appConfigClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.appConfigurationClient = appConfigClient + } else { + session.appConfigurationClientErr = fmt.Errorf("[ERROR] Error occurred while configuring App Configuration service: %q", err) + } + + // CONTAINER REGISTRY Service + // Construct an "options" struct for creating the service client. + containerRegistryClientURL, err := containerregistryv1.GetServiceURLForRegion(c.Region) + if err != nil { + containerRegistryClientURL = containerregistryv1.DefaultServiceURL + } + if c.Visibility == "private" || c.Visibility == "public-and-private" { + containerRegistryClientURL, err = GetPrivateServiceURLForRegion(c.Region) + if err != nil { + containerRegistryClientURL, _ = GetPrivateServiceURLForRegion("global") + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + containerRegistryClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CR_API_ENDPOINT", c.Region, containerRegistryClientURL) + } + containerRegistryClientOptions := &containerregistryv1.ContainerRegistryV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_CR_API_ENDPOINT"}, containerRegistryClientURL), + Account: core.StringPtr(userConfig.UserAccount), + } + // Construct the service client. + session.containerRegistryClient, err = containerregistryv1.NewContainerRegistryV1(containerRegistryClientOptions) + if err != nil { + session.containerRegistryClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Container Registry API service: %q", err) + } + if session.containerRegistryClient != nil && session.containerRegistryClient.Service != nil { + // Enable retries for API calls + session.containerRegistryClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.containerRegistryClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // OBJECT STORAGE Service + cosconfigurl := "https://config.cloud-object-storage.cloud.ibm.com/v1" + if fileMap != nil && c.Visibility != "public-and-private" { + cosconfigurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_COS_CONFIG_ENDPOINT", c.Region, cosconfigurl) + } + cosconfigoptions := &cosconfig.ResourceConfigurationV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_COS_CONFIG_ENDPOINT"}, cosconfigurl), + } + cosconfigclient, err := cosconfig.NewResourceConfigurationV1(cosconfigoptions) + if err != nil { + session.cosConfigErr = fmt.Errorf("[ERROR] Error occured while configuring COS config service: %q", err) + } + session.cosConfigAPI = cosconfigclient + + globalSearchAPI, err := globalsearchv2.New(sess.BluemixSession) + if err != nil { + session.globalSearchConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Global Search: %q", err) + } + session.globalSearchServiceAPI = globalSearchAPI + // Global Tagging Bluemix-go + globalTaggingAPI, err := globaltaggingv3.New(sess.BluemixSession) + if err != nil { + session.globalTaggingConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Global Tagging: %q", err) + } + session.globalTaggingServiceAPI = globalTaggingAPI + + // GLOBAL TAGGING Service + globalTaggingEndpoint := "https://tags.global-search-tagging.cloud.ibm.com" + if c.Visibility == "private" || c.Visibility == "public-and-private" { + var globalTaggingRegion string + if c.Region != "us-south" && c.Region != "us-east" { + globalTaggingRegion = "us-south" + } else { + globalTaggingRegion = c.Region + } + globalTaggingEndpoint = ContructEndpoint(fmt.Sprintf("tags.private.%s", globalTaggingRegion), fmt.Sprintf("global-search-tagging.%s", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + globalTaggingEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_GT_API_ENDPOINT", c.Region, globalTaggingEndpoint) + } + globalTaggingV1Options := &globaltaggingv1.GlobalTaggingV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_GT_API_ENDPOINT"}, globalTaggingEndpoint), + Authenticator: authenticator, + } + globalTaggingAPIV1, err := globaltaggingv1.NewGlobalTaggingV1(globalTaggingV1Options) + if err != nil { + session.globalTaggingConfigErrV1 = fmt.Errorf("[ERROR] Error occured while configuring Global Tagging: %q", err) + } + if globalTaggingAPIV1 != nil && globalTaggingAPIV1.Service != nil { + session.globalTaggingServiceAPIV1 = *globalTaggingAPIV1 + session.globalTaggingServiceAPIV1.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.globalTaggingServiceAPIV1.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + icdAPI, err := icdv4.New(sess.BluemixSession) + if err != nil { + session.icdConfigErr = fmt.Errorf("[ERROR] Error occured while configuring IBM Cloud Database Services: %q", err) + } + session.icdServiceAPI = icdAPI + + var cloudDatabasesEndpoint string + + if c.Visibility == "private" || c.Visibility == "public-and-private" { + cloudDatabasesEndpoint = fmt.Sprintf("https://api.%s.private.databases.cloud.ibm.com/v5/ibm", c.Region) + } else { + cloudDatabasesEndpoint = fmt.Sprintf("https://api.%s.databases.cloud.ibm.com/v5/ibm", c.Region) + } + + // Construct an "options" struct for creating the service client. + cloudDatabasesClientOptions := &clouddatabasesv5.CloudDatabasesV5Options{ + URL: EnvFallBack([]string{"IBMCLOUD_DATABASES_API_ENDPOINT"}, cloudDatabasesEndpoint), + Authenticator: authenticator, + } + + // Construct the service client. + session.cloudDatabasesClient, err = clouddatabasesv5.NewCloudDatabasesV5(cloudDatabasesClientOptions) + if err == nil { + // Enable retries for API calls + session.cloudDatabasesClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.cloudDatabasesClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.cloudDatabasesClientErr = fmt.Errorf("Error occurred while configuring The IBM Cloud Databases API service: %q", err) + } + + resourceCatalogAPI, err := catalog.New(sess.BluemixSession) + if err != nil { + session.resourceCatalogConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Resource Catalog service: %q", err) + } + session.resourceCatalogServiceAPI = resourceCatalogAPI + + resourceManagementAPIv2, err := managementv2.New(sess.BluemixSession) + if err != nil { + session.resourceManagementConfigErrv2 = fmt.Errorf("[ERROR] Error occured while configuring Resource Management service: %q", err) + } + session.resourceManagementServiceAPIv2 = resourceManagementAPIv2 + + resourceControllerAPI, err := controller.New(sess.BluemixSession) + if err != nil { + session.resourceControllerConfigErr = fmt.Errorf("[ERROR] Error occured while configuring Resource Controller service: %q", err) + } + session.resourceControllerServiceAPI = resourceControllerAPI + + ResourceControllerAPIv2, err := controllerv2.New(sess.BluemixSession) + if err != nil { + session.resourceControllerConfigErrv2 = fmt.Errorf("[ERROR] Error occured while configuring Resource Controller v2 service: %q", err) + } + session.resourceControllerServiceAPIv2 = ResourceControllerAPIv2 + + userManagementAPI, err := usermanagementv2.New(sess.BluemixSession) + if err != nil { + session.userManagementErr = fmt.Errorf("[ERROR] Error occured while configuring user management service: %q", err) + } + session.userManagementAPI = userManagementAPI + + certManagementAPI, err := certificatemanager.New(sess.BluemixSession) + if err != nil { + session.certManagementErr = fmt.Errorf("[ERROR] Error occured while configuring Certificate manager service: %q", err) + } + session.certManagementAPI = certManagementAPI + + namespaceFunction, err := functions.New(sess.BluemixSession) + if err != nil { + session.functionIAMNamespaceErr = fmt.Errorf("[ERROR] Error occured while configuring Cloud Funciton Service : %q", err) + } + session.functionIAMNamespaceAPI = namespaceFunction + + // API GATEWAY service + apicurl := ContructEndpoint(fmt.Sprintf("api.%s.apigw", c.Region), fmt.Sprintf("%s/controller", cloudEndpoint)) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + apicurl = ContructEndpoint(fmt.Sprintf("api.private.%s.apigw", c.Region), fmt.Sprintf("%s/controller", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + apicurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_API_GATEWAY_ENDPOINT", c.Region, apicurl) + } + APIGatewayControllerAPIV1Options := &apigateway.ApiGatewayControllerApiV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_API_GATEWAY_ENDPOINT"}, apicurl), + Authenticator: &core.NoAuthAuthenticator{}, + } + apigatewayAPI, err := apigateway.NewApiGatewayControllerApiV1(APIGatewayControllerAPIV1Options) + if err != nil { + session.apigatewayErr = fmt.Errorf("[ERROR] Error occured while configuring APIGateway service: %q", err) + } + session.apigatewayAPI = apigatewayAPI + + // POWER SYSTEMS Service + piURL := ContructEndpoint(c.Region, "power-iaas.cloud.ibm.com") + ibmPIOptions := &ibmpisession.IBMPIOptions{ + Authenticator: authenticator, + Debug: os.Getenv("TF_LOG") != "", + Region: c.Region, + URL: EnvFallBack([]string{"IBMCLOUD_PI_API_ENDPOINT"}, piURL), + UserAccount: userConfig.UserAccount, + Zone: c.Zone, + } + ibmpisession, err := ibmpisession.NewIBMPISession(ibmPIOptions) + if err != nil { + session.ibmpiConfigErr = fmt.Errorf("Error occured while configuring ibmpisession: %q", err) + } + session.ibmpiSession = ibmpisession + + // PRIVATE DNS Service + pdnsURL := dns.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + pdnsURL = ContructEndpoint("api.private.dns-svcs", fmt.Sprintf("%s/v1", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + pdnsURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_PRIVATE_DNS_API_ENDPOINT", c.Region, pdnsURL) + } + dnsOptions := &dns.DnsSvcsV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_PRIVATE_DNS_API_ENDPOINT"}, pdnsURL), + Authenticator: authenticator, + } + session.pDNSClient, session.pDNSErr = dns.NewDnsSvcsV1(dnsOptions) + if session.pDNSErr != nil { + session.pDNSErr = fmt.Errorf("[ERROR] Error occured while configuring PrivateDNS Service: %s", session.pDNSErr) + } + if session.pDNSClient != nil && session.pDNSClient.Service != nil { + session.pDNSClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.pDNSClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // DIRECT LINK Service + ver := time.Now().Format("2006-01-02") + dlURL := dl.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + dlURL = ContructEndpoint("private.directlink", fmt.Sprintf("%s/v1", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + dlURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_DL_API_ENDPOINT", c.Region, dlURL) + } + directlinkOptions := &dl.DirectLinkV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_DL_API_ENDPOINT"}, dlURL), + Authenticator: authenticator, + Version: &ver, + } + session.directlinkAPI, session.directlinkErr = dl.NewDirectLinkV1(directlinkOptions) + if session.directlinkErr != nil { + session.directlinkErr = fmt.Errorf("[ERROR] Error occured while configuring Direct Link Service: %s", session.directlinkErr) + } + if session.directlinkAPI != nil && session.directlinkAPI.Service != nil { + session.directlinkAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.directlinkAPI.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // DIRECT LINK PROVIDER Service + dlproviderURL := dlProviderV2.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + dlproviderURL = ContructEndpoint("private.directlink", fmt.Sprintf("%s/provider/v2", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + dlproviderURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_DL_PROVIDER_API_ENDPOINT", c.Region, dlproviderURL) + } + directLinkProviderV2Options := &dlProviderV2.DirectLinkProviderV2Options{ + URL: EnvFallBack([]string{"IBMCLOUD_DL_PROVIDER_API_ENDPOINT"}, dlproviderURL), + Authenticator: authenticator, + Version: &ver, + } + session.dlProviderAPI, session.dlProviderErr = dlProviderV2.NewDirectLinkProviderV2(directLinkProviderV2Options) + if session.dlProviderErr != nil { + session.dlProviderErr = fmt.Errorf("[ERROR] Error occured while configuring Direct Link Provider Service: %s", session.dlProviderErr) + } + if session.dlProviderAPI != nil && session.dlProviderAPI.Service != nil { + session.dlProviderAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.dlProviderAPI.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // TRANSIT GATEWAY Service + tgURL := tg.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + tgURL = ContructEndpoint("private.transit", fmt.Sprintf("%s/v1", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + tgURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_TG_API_ENDPOINT", c.Region, tgURL) + } + transitgatewayOptions := &tg.TransitGatewayApisV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_TG_API_ENDPOINT"}, tgURL), + Authenticator: authenticator, + Version: CreateVersionDate(), + } + session.transitgatewayAPI, session.transitgatewayErr = tg.NewTransitGatewayApisV1(transitgatewayOptions) + if session.transitgatewayErr != nil { + session.transitgatewayErr = fmt.Errorf("[ERROR] Error occured while configuring Transit Gateway Service: %s", session.transitgatewayErr) + } + if session.transitgatewayAPI != nil && session.transitgatewayAPI.Service != nil { + session.transitgatewayAPI.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // session.transitgatewayAPI.SetDefaultHeaders(gohttp.Header{ + // "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + // }) + } + + // CIS Service instances starts here. + cisURL := ContructEndpoint("api.cis", cloudEndpoint) + if c.Visibility == "private" { + // cisURL = ContructEndpoint("api.private.cis", cloudEndpoint) + session.cisZonesErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisDNSBulkErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisGLBPoolErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisGLBErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisGLBHealthCheckErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisIPErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisRLErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisPageRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisEdgeFunctionErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisSSLErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisWAFPackageErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisDomainSettingsErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisRoutingErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisWAFGroupErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisCacheErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisCustomPageErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisAccessRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisUARuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisLockdownErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisRangeAppErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisWAFRuleErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisFiltersErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisWebhooksErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + session.cisMtlsErr = fmt.Errorf("CIS Service doesnt support private endpoints.") + + } + if fileMap != nil && c.Visibility != "public-and-private" { + cisURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CIS_API_ENDPOINT", c.Region, cisURL) + } + cisEndPoint := EnvFallBack([]string{"IBMCLOUD_CIS_API_ENDPOINT"}, cisURL) + + // IBM Network CIS Zones service + cisZonesV1Opt := &ciszonesv1.ZonesV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisZonesV1Client, session.cisZonesErr = ciszonesv1.NewZonesV1(cisZonesV1Opt) + if session.cisZonesErr != nil { + session.cisZonesErr = fmt.Errorf( + "Error occured while configuring CIS Zones service: %s", + session.cisZonesErr) + } + if session.cisZonesV1Client != nil && session.cisZonesV1Client.Service != nil { + session.cisZonesV1Client.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisZonesV1Client.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS DNS Record service + cisDNSRecordsOpt := &cisdnsrecordsv1.DnsRecordsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisDNSRecordsClient, session.cisDNSErr = cisdnsrecordsv1.NewDnsRecordsV1(cisDNSRecordsOpt) + if session.cisDNSErr != nil { + session.cisDNSErr = fmt.Errorf("[ERROR] Error occured while configuring CIS DNS Service: %s", session.cisDNSErr) + } + if session.cisDNSRecordsClient != nil && session.cisDNSRecordsClient.Service != nil { + session.cisDNSRecordsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisDNSRecordsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS DNS Record bulk service + cisDNSRecordBulkOpt := &cisdnsbulkv1.DnsRecordBulkV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisDNSRecordBulkClient, session.cisDNSBulkErr = cisdnsbulkv1.NewDnsRecordBulkV1(cisDNSRecordBulkOpt) + if session.cisDNSBulkErr != nil { + session.cisDNSBulkErr = fmt.Errorf( + "Error occured while configuration CIS DNS bulk service : %s", + session.cisDNSBulkErr) + } + if session.cisDNSRecordBulkClient != nil && session.cisDNSRecordBulkClient.Service != nil { + session.cisDNSRecordBulkClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisDNSRecordBulkClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Global load balancer pool + cisGLBPoolOpt := &cisglbpoolv0.GlobalLoadBalancerPoolsV0Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisGLBPoolClient, session.cisGLBPoolErr = + cisglbpoolv0.NewGlobalLoadBalancerPoolsV0(cisGLBPoolOpt) + if session.cisGLBPoolErr != nil { + session.cisGLBPoolErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS GLB Pool service: %s", + session.cisGLBPoolErr) + } + if session.cisGLBPoolClient != nil && session.cisGLBPoolClient.Service != nil { + session.cisGLBPoolClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisGLBPoolClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Global load balancer + cisGLBOpt := &cisglbv1.GlobalLoadBalancerV1Options{ + URL: cisEndPoint, + Authenticator: authenticator, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + } + session.cisGLBClient, session.cisGLBErr = cisglbv1.NewGlobalLoadBalancerV1(cisGLBOpt) + if session.cisGLBErr != nil { + session.cisGLBErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS GLB service: %s", + session.cisGLBErr) + } + if session.cisGLBClient != nil && session.cisGLBClient.Service != nil { + session.cisGLBClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisGLBClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Global load balancer health check/monitor + cisGLBHealthCheckOpt := &cisglbhealthcheckv1.GlobalLoadBalancerMonitorV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisGLBHealthCheckClient, session.cisGLBHealthCheckErr = + cisglbhealthcheckv1.NewGlobalLoadBalancerMonitorV1(cisGLBHealthCheckOpt) + if session.cisGLBHealthCheckErr != nil { + session.cisGLBHealthCheckErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS GLB Health Check service: %s", + session.cisGLBHealthCheckErr) + } + if session.cisGLBHealthCheckClient != nil && session.cisGLBHealthCheckClient.Service != nil { + session.cisGLBHealthCheckClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisGLBHealthCheckClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS IP + cisIPOpt := &cisipv1.CisIpApiV1Options{ + URL: cisEndPoint, + Authenticator: authenticator, + } + session.cisIPClient, session.cisIPErr = cisipv1.NewCisIpApiV1(cisIPOpt) + if session.cisIPErr != nil { + session.cisIPErr = fmt.Errorf("[ERROR] Error occured while configuring CIS IP service: %s", + session.cisIPErr) + } + if session.cisIPClient != nil && session.cisIPClient.Service != nil { + session.cisIPClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisIPClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Zone Rate Limit + cisRLOpt := &cisratelimitv1.ZoneRateLimitsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisRLClient, session.cisRLErr = cisratelimitv1.NewZoneRateLimitsV1(cisRLOpt) + if session.cisRLErr != nil { + session.cisRLErr = fmt.Errorf( + "Error occured while cofiguring CIS Zone Rate Limit service: %s", + session.cisRLErr) + } + if session.cisRLClient != nil && session.cisRLClient.Service != nil { + session.cisRLClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisRLClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + // IBM Network CIS Alerts + cisAlertsOpt := &cisalertsv1.AlertsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisAlertsClient, session.cisAlertsErr = cisalertsv1.NewAlertsV1(cisAlertsOpt) + if session.cisAlertsErr != nil { + session.cisAlertsErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Alerts : %s", + session.cisAlertsErr) + } + if session.cisAlertsClient != nil && session.cisAlertsClient.Service != nil { + session.cisAlertsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisAlertsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Page Rules + cisPageRuleOpt := &cispagerulev1.PageRuleApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisPageRuleClient, session.cisPageRuleErr = cispagerulev1.NewPageRuleApiV1(cisPageRuleOpt) + if session.cisPageRuleErr != nil { + session.cisPageRuleErr = fmt.Errorf( + "Error occured while cofiguring CIS Page Rule service: %s", + session.cisPageRuleErr) + } + if session.cisPageRuleClient != nil && session.cisPageRuleClient.Service != nil { + session.cisPageRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisPageRuleClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Edge Function + cisEdgeFunctionOpt := &cisedgefunctionv1.EdgeFunctionsApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisEdgeFunctionClient, session.cisEdgeFunctionErr = + cisedgefunctionv1.NewEdgeFunctionsApiV1(cisEdgeFunctionOpt) + if session.cisEdgeFunctionErr != nil { + session.cisEdgeFunctionErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Edge Function service: %s", + session.cisEdgeFunctionErr) + } + if session.cisEdgeFunctionClient != nil && session.cisEdgeFunctionClient.Service != nil { + session.cisEdgeFunctionClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisEdgeFunctionClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS SSL certificate + cisSSLOpt := &cissslv1.SslCertificateApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + + session.cisSSLClient, session.cisSSLErr = cissslv1.NewSslCertificateApiV1(cisSSLOpt) + if session.cisSSLErr != nil { + session.cisSSLErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS SSL certificate service: %s", + session.cisSSLErr) + } + if session.cisSSLClient != nil && session.cisSSLClient.Service != nil { + session.cisSSLClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisSSLClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS WAF Package + cisWAFPackageOpt := &ciswafpackagev1.WafRulePackagesApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisWAFPackageClient, session.cisWAFPackageErr = + ciswafpackagev1.NewWafRulePackagesApiV1(cisWAFPackageOpt) + if session.cisWAFPackageErr != nil { + session.cisWAFPackageErr = + fmt.Errorf("[ERROR] Error occured while configuration CIS WAF Package service: %s", + session.cisWAFPackageErr) + } + if session.cisWAFPackageClient != nil && session.cisWAFPackageClient.Service != nil { + session.cisWAFPackageClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisWAFPackageClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Domain settings + cisDomainSettingsOpt := &cisdomainsettingsv1.ZonesSettingsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisDomainSettingsClient, session.cisDomainSettingsErr = + cisdomainsettingsv1.NewZonesSettingsV1(cisDomainSettingsOpt) + if session.cisDomainSettingsErr != nil { + session.cisDomainSettingsErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Domain Settings service: %s", + session.cisDomainSettingsErr) + } + if session.cisDomainSettingsClient != nil && session.cisDomainSettingsClient.Service != nil { + session.cisDomainSettingsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisDomainSettingsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Routing + cisRoutingOpt := &cisroutingv1.RoutingV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisRoutingClient, session.cisRoutingErr = + cisroutingv1.NewRoutingV1(cisRoutingOpt) + if session.cisRoutingErr != nil { + session.cisRoutingErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Routing service: %s", + session.cisRoutingErr) + } + if session.cisRoutingClient != nil && session.cisRoutingClient.Service != nil { + session.cisRoutingClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisRoutingClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS WAF Group + cisWAFGroupOpt := &ciswafgroupv1.WafRuleGroupsApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisWAFGroupClient, session.cisWAFGroupErr = + ciswafgroupv1.NewWafRuleGroupsApiV1(cisWAFGroupOpt) + if session.cisWAFGroupErr != nil { + session.cisWAFGroupErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS WAF Group service: %s", + session.cisWAFGroupErr) + } + if session.cisWAFGroupClient != nil && session.cisWAFGroupClient.Service != nil { + session.cisWAFGroupClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisWAFGroupClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Cache service + cisCacheOpt := &ciscachev1.CachingApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisCacheClient, session.cisCacheErr = + ciscachev1.NewCachingApiV1(cisCacheOpt) + if session.cisCacheErr != nil { + session.cisCacheErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Caching service: %s", + session.cisCacheErr) + } + if session.cisCacheClient != nil && session.cisCacheClient.Service != nil { + session.cisCacheClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisCacheClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Custom pages service + cisCustomPageOpt := &ciscustompagev1.CustomPagesV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + + session.cisCustomPageClient, session.cisCustomPageErr = + ciscustompagev1.NewCustomPagesV1(cisCustomPageOpt) + if session.cisCustomPageErr != nil { + session.cisCustomPageErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Custom Pages service: %s", + session.cisCustomPageErr) + } + if session.cisCustomPageClient != nil && session.cisCustomPageClient.Service != nil { + session.cisCustomPageClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisCustomPageClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Firewall Access rule + cisAccessRuleOpt := &cisaccessrulev1.ZoneFirewallAccessRulesV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisAccessRuleClient, session.cisAccessRuleErr = + cisaccessrulev1.NewZoneFirewallAccessRulesV1(cisAccessRuleOpt) + if session.cisAccessRuleErr != nil { + session.cisAccessRuleErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Firewall Access Rule service: %s", + session.cisAccessRuleErr) + } + if session.cisAccessRuleClient != nil && session.cisAccessRuleClient.Service != nil { + session.cisAccessRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisAccessRuleClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Firewall User Agent Blocking rule + cisUARuleOpt := &cisuarulev1.UserAgentBlockingRulesV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisUARuleClient, session.cisUARuleErr = + cisuarulev1.NewUserAgentBlockingRulesV1(cisUARuleOpt) + if session.cisUARuleErr != nil { + session.cisUARuleErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Firewall User Agent Blocking Rule service: %s", + session.cisUARuleErr) + } + if session.cisUARuleClient != nil && session.cisUARuleClient.Service != nil { + session.cisUARuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisUARuleClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Firewall Lockdown rule + cisLockdownOpt := &cislockdownv1.ZoneLockdownV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisLockdownClient, session.cisLockdownErr = + cislockdownv1.NewZoneLockdownV1(cisLockdownOpt) + if session.cisLockdownErr != nil { + session.cisLockdownErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Firewall Lockdown Rule service: %s", + session.cisLockdownErr) + } + if session.cisLockdownClient != nil && session.cisLockdownClient.Service != nil { + session.cisLockdownClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisLockdownClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Range Application rule + cisRangeAppOpt := &cisrangeappv1.RangeApplicationsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisRangeAppClient, session.cisRangeAppErr = + cisrangeappv1.NewRangeApplicationsV1(cisRangeAppOpt) + if session.cisRangeAppErr != nil { + session.cisRangeAppErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Range Application rule service: %s", + session.cisRangeAppErr) + } + if session.cisRangeAppClient != nil && session.cisRangeAppClient.Service != nil { + session.cisRangeAppClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisRangeAppClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS WAF Rule Service + cisWAFRuleOpt := &ciswafrulev1.WafRulesApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisWAFRuleClient, session.cisWAFRuleErr = + ciswafrulev1.NewWafRulesApiV1(cisWAFRuleOpt) + if session.cisWAFRuleErr != nil { + session.cisWAFRuleErr = fmt.Errorf( + "Error occured while configuring CIS WAF Rules service: %s", + session.cisWAFRuleErr) + } + if session.cisWAFRuleClient != nil && session.cisWAFRuleClient.Service != nil { + session.cisWAFRuleClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisWAFRuleClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS LogpushJobs + cisLogpushJobOpt := &cislogpushjobsapiv1.LogpushJobsApiV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + ZoneID: core.StringPtr(""), + Dataset: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisLogpushJobsClient, session.cisLogpushJobsErr = cislogpushjobsapiv1.NewLogpushJobsApiV1(cisLogpushJobOpt) + if session.cisLogpushJobsErr != nil { + session.cisLogpushJobsErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS LogpushJobs : %s", + session.cisLogpushJobsErr) + } + if session.cisLogpushJobsClient != nil && session.cisLogpushJobsClient.Service != nil { + session.cisLogpushJobsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisLogpushJobsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM MTLS Session + cisMtlsOpt := &cismtlsv1.MtlsV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisMtlsClient, session.cisMtlsErr = cismtlsv1.NewMtlsV1(cisMtlsOpt) + if session.cisMtlsErr != nil { + session.cisMtlsErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS MTLS : %s", + session.cisMtlsErr) + } + if session.cisMtlsClient != nil && session.cisMtlsClient.Service != nil { + session.cisMtlsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisMtlsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Webhooks + cisWebhooksOpt := &ciswebhooksv1.WebhooksV1Options{ + URL: cisEndPoint, + Crn: core.StringPtr(""), + Authenticator: authenticator, + } + session.cisWebhooksClient, session.cisWebhooksErr = ciswebhooksv1.NewWebhooksV1(cisWebhooksOpt) + if session.cisWebhooksErr != nil { + session.cisWebhooksErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Webhooks : %s", + session.cisWebhooksErr) + } + if session.cisWebhooksClient != nil && session.cisWebhooksClient.Service != nil { + session.cisWebhooksClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisWebhooksClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + // IBM Network CIS Filters + cisFiltersOpt := &cisfiltersv1.FiltersV1Options{ + URL: cisEndPoint, + Authenticator: authenticator, + } + session.cisFiltersClient, session.cisFiltersErr = cisfiltersv1.NewFiltersV1(cisFiltersOpt) + if session.cisFiltersErr != nil { + session.cisFiltersErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Filters : %s", + session.cisFiltersErr) + } + if session.cisFiltersClient != nil && session.cisFiltersClient.Service != nil { + session.cisFiltersClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisFiltersClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Firewall rules + cisFirewallrulesOpt := &cisfirewallrulesv1.FirewallRulesV1Options{ + URL: cisEndPoint, + Authenticator: authenticator, + } + session.cisFirewallRulesClient, session.cisFirewallRulesErr = cisfirewallrulesv1.NewFirewallRulesV1(cisFirewallrulesOpt) + if session.cisFirewallRulesErr != nil { + session.cisFirewallRulesErr = + fmt.Errorf("[ERROR] Error occured while configuring CIS Firewall rules : %s", + session.cisFirewallRulesErr) + } + if session.cisFirewallRulesClient != nil && session.cisFirewallRulesClient.Service != nil { + session.cisFirewallRulesClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisFirewallRulesClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IBM Network CIS Authenticated Origin Pull + cisOriginAuthOptions := &cisoriginpull.AuthenticatedOriginPullApiV1Options{ + URL: cisEndPoint, + Authenticator: authenticator, + Crn: core.StringPtr(""), + ZoneIdentifier: core.StringPtr(""), + } + + session.cisOriginAuthClient, session.cisOriginAuthPullErr = + cisoriginpull.NewAuthenticatedOriginPullApiV1(cisOriginAuthOptions) + if session.cisOriginAuthPullErr != nil { + session.cisOriginAuthPullErr = fmt.Errorf( + "Error occured while configuring CIS Authenticated Origin Pullservice: %s", + session.cisOriginAuthPullErr) + } + if session.cisOriginAuthClient != nil && session.cisOriginAuthClient.Service != nil { + session.cisOriginAuthClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.cisOriginAuthClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // IAM IDENTITY Service + // iamIdenityURL := fmt.Sprintf("https://%s.iam.cloud.ibm.com/v1", c.Region) + iamIdenityURL := iamidentity.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + iamIdenityURL = ContructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) + } else { + iamIdenityURL = ContructEndpoint("private.iam", cloudEndpoint) + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + iamIdenityURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamIdenityURL) + } + iamIdentityOptions := &iamidentity.IamIdentityV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamIdenityURL), + } + iamIdentityClient, err := iamidentity.NewIamIdentityV1(iamIdentityOptions) + if err != nil { + session.iamIdentityErr = fmt.Errorf("[ERROR] Error occured while configuring IAM Identity service: %q", err) + } + if iamIdentityClient != nil && iamIdentityClient.Service != nil { + iamIdentityClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + iamIdentityClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.iamIdentityAPI = iamIdentityClient + + // IAM POLICY MANAGEMENT Service + iamPolicyManagementURL := iampolicymanagement.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + iamPolicyManagementURL = ContructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) + } else { + iamPolicyManagementURL = ContructEndpoint("private.iam", cloudEndpoint) + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + iamPolicyManagementURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamPolicyManagementURL) + } + iamPolicyManagementOptions := &iampolicymanagement.IamPolicyManagementV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamPolicyManagementURL), + } + iamPolicyManagementClient, err := iampolicymanagement.NewIamPolicyManagementV1(iamPolicyManagementOptions) + if err != nil { + session.iamPolicyManagementErr = fmt.Errorf("[ERROR] Error occured while configuring IAM Policy Management service: %q", err) + } + if iamPolicyManagementClient != nil && iamPolicyManagementClient.Service != nil { + iamPolicyManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + iamPolicyManagementClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.iamPolicyManagementAPI = iamPolicyManagementClient + + // IAM ACCESS GROUP + iamAccessGroupsURL := iamaccessgroups.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + iamAccessGroupsURL = ContructEndpoint(fmt.Sprintf("private.%s.iam", c.Region), cloudEndpoint) + } else { + iamAccessGroupsURL = ContructEndpoint("private.iam", cloudEndpoint) + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + iamAccessGroupsURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_IAM_API_ENDPOINT", c.Region, iamAccessGroupsURL) + } + iamAccessGroupsOptions := &iamaccessgroups.IamAccessGroupsV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamAccessGroupsURL), + } + iamAccessGroupsClient, err := iamaccessgroups.NewIamAccessGroupsV2(iamAccessGroupsOptions) + if err != nil { + session.iamAccessGroupsErr = fmt.Errorf("[ERROR] Error occured while configuring IAM Access Group service: %q", err) + } + if iamAccessGroupsClient != nil && iamAccessGroupsClient.Service != nil { + iamAccessGroupsClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + iamAccessGroupsClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.iamAccessGroupsAPI = iamAccessGroupsClient + + // RESOURCE MANAGEMENT Service + rmURL := resourcemanager.DefaultServiceURL + if c.Visibility == "private" { + if c.Region == "us-south" || c.Region == "us-east" { + rmURL = ContructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), fmt.Sprintf("%s", cloudEndpoint)) + } else { + fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") + rmURL = ContructEndpoint("private.us-south.resource-controller", fmt.Sprintf("%s", cloudEndpoint)) + } + } + if c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + rmURL = ContructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), fmt.Sprintf("%s", cloudEndpoint)) + } else { + rmURL = resourcemanager.DefaultServiceURL + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + rmURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_RESOURCE_MANAGEMENT_API_ENDPOINT", c.Region, rmURL) + } + resourceManagerOptions := &resourcemanager.ResourceManagerV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_RESOURCE_MANAGEMENT_API_ENDPOINT"}, rmURL), + } + resourceManagerClient, err := resourcemanager.NewResourceManagerV2(resourceManagerOptions) + if err != nil { + session.resourceManagerErr = fmt.Errorf("[ERROR] Error occured while configuring Resource Manager service: %q", err) + } + if resourceManagerClient != nil && resourceManagerClient.Service != nil { + resourceManagerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + resourceManagerClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.resourceManagerAPI = resourceManagerClient + + //CLOUD SHELL Service + cloudShellUrl := ibmcloudshellv1.DefaultServiceURL + if fileMap != nil && c.Visibility != "public-and-private" { + cloudShellUrl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_CLOUD_SHELL_API_ENDPOINT", c.Region, cloudShellUrl) + } + ibmCloudShellClientOptions := &ibmcloudshellv1.IBMCloudShellV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_CLOUD_SHELL_API_ENDPOINT"}, cloudShellUrl), + } + session.ibmCloudShellClient, err = ibmcloudshellv1.NewIBMCloudShellV1(ibmCloudShellClientOptions) + if err != nil { + session.ibmCloudShellClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Shell service: %q", err) + } + if session.ibmCloudShellClient != nil && session.ibmCloudShellClient.Service != nil { + session.ibmCloudShellClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.ibmCloudShellClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // ENTERPRISE Service + enterpriseURL := enterprisemanagementv1.DefaultServiceURL + if c.Visibility == "private" { + if c.Region == "us-south" || c.Region == "us-east" || c.Region == "eu-fr" { + enterpriseURL = ContructEndpoint(fmt.Sprintf("private.%s.enterprise", c.Region), fmt.Sprintf("%s/v1", cloudEndpoint)) + } else { + fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") + enterpriseURL = ContructEndpoint("private.us-south.enterprise", fmt.Sprintf("%s/v1", cloudEndpoint)) + } + } + if c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" || c.Region == "eu-fr" { + enterpriseURL = ContructEndpoint(fmt.Sprintf("private.%s.enterprise", c.Region), + fmt.Sprintf("%s/v1", cloudEndpoint)) + } else { + enterpriseURL = enterprisemanagementv1.DefaultServiceURL + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + enterpriseURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_ENTERPRISE_API_ENDPOINT", c.Region, enterpriseURL) + } + enterpriseManagementClientOptions := &enterprisemanagementv1.EnterpriseManagementV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_ENTERPRISE_API_ENDPOINT"}, enterpriseURL), + } + enterpriseManagementClient, err := enterprisemanagementv1.NewEnterpriseManagementV1(enterpriseManagementClientOptions) + if err != nil { + session.enterpriseManagementClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Enterprise Management API service: %q", err) + } + if enterpriseManagementClient != nil && enterpriseManagementClient.Service != nil { + enterpriseManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + enterpriseManagementClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.enterpriseManagementClient = enterpriseManagementClient + + // RESOURCE CONTROLLER Service + rcURL := resourcecontroller.DefaultServiceURL + if c.Visibility == "private" { + if c.Region == "us-south" || c.Region == "us-east" { + rcURL = ContructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), cloudEndpoint) + } else { + fmt.Println("Private Endpint supports only us-south and us-east region specific endpoint") + rcURL = ContructEndpoint("private.us-south.resource-controller", cloudEndpoint) + } + } + if c.Visibility == "public-and-private" { + if c.Region == "us-south" || c.Region == "us-east" { + rcURL = ContructEndpoint(fmt.Sprintf("private.%s.resource-controller", c.Region), cloudEndpoint) + } else { + rcURL = resourcecontroller.DefaultServiceURL + } + } + if fileMap != nil && c.Visibility != "public-and-private" { + rcURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_RESOURCE_CONTROLLER_API_ENDPOINT", c.Region, rcURL) + } + resourceControllerOptions := &resourcecontroller.ResourceControllerV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_RESOURCE_CONTROLLER_API_ENDPOINT"}, rcURL), + } + resourceControllerClient, err := resourcecontroller.NewResourceControllerV2(resourceControllerOptions) + if err != nil { + session.resourceControllerErr = fmt.Errorf("[ERROR] Error occured while configuring Resource Controller service: %q", err) + } + if resourceControllerClient != nil && resourceControllerClient.Service != nil { + resourceControllerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + resourceControllerClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + session.resourceControllerAPI = resourceControllerClient + + // SECRETS MANAGER Service + secretsManagerClientOptions := &secretsmanagerv1.SecretsManagerV1Options{ + Authenticator: authenticator, + } + /// Construct the service client. + session.secretsManagerClient, err = secretsmanagerv1.NewSecretsManagerV1(secretsManagerClientOptions) + if err != nil { + session.secretsManagerClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Secrets Manager API service: %q", err) + } + if session.secretsManagerClient != nil && session.secretsManagerClient.Service != nil { + // Enable retries for API calls + session.secretsManagerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.secretsManagerClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // SATELLITE Service + containerEndpoint := kubernetesserviceapiv1.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + containerEndpoint = ContructEndpoint(fmt.Sprintf("private.%s.containers", c.Region), fmt.Sprintf("%s/global", cloudEndpoint)) + } + if fileMap != nil && c.Visibility != "public-and-private" { + containerEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SATELLITE_API_ENDPOINT", c.Region, containerEndpoint) + } + kubernetesServiceV1Options := &kubernetesserviceapiv1.KubernetesServiceApiV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_SATELLITE_API_ENDPOINT"}, containerEndpoint), + Authenticator: authenticator, + } + session.satelliteClient, err = kubernetesserviceapiv1.NewKubernetesServiceApiV1(kubernetesServiceV1Options) + if err != nil { + session.satelliteClientErr = fmt.Errorf("[ERROR] Error occured while configuring satellite client: %q", err) + } + + // Enable retries for API calls + if session.satelliteClient != nil && session.satelliteClient.Service != nil { + session.satelliteClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.satelliteClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // SATELLITE LINK Service + // Construct an "options" struct for creating the service client. + satelliteLinkEndpoint := satellitelinkv1.DefaultServiceURL + if c.Visibility == "private" || c.Visibility == "public-and-private" { + satelliteLinkEndpoint = ContructEndpoint("private.api.link.satellite", cloudEndpoint) + } + if fileMap != nil && c.Visibility != "public-and-private" { + satelliteLinkEndpoint = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_SATELLITE_LINK_API_ENDPOINT", c.Region, satelliteLinkEndpoint) + } + satelliteLinkClientOptions := &satellitelinkv1.SatelliteLinkV1Options{ + URL: EnvFallBack([]string{"IBMCLOUD_SATELLITE_LINK_API_ENDPOINT"}, satelliteLinkEndpoint), + Authenticator: authenticator, + } + session.satelliteLinkClient, err = satellitelinkv1.NewSatelliteLinkV1(satelliteLinkClientOptions) + if err != nil { + session.satelliteLinkClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Satellite Link service: %q", err) + } + if session.satelliteLinkClient != nil && session.satelliteLinkClient.Service != nil { + // Enable retries for API calls + session.satelliteLinkClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.satelliteLinkClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + esSchemaRegistryV1Options := &schemaregistryv1.SchemaregistryV1Options{ + Authenticator: authenticator, + } + session.esSchemaRegistryClient, err = schemaregistryv1.NewSchemaregistryV1(esSchemaRegistryV1Options) + if err != nil { + session.esSchemaRegistryErr = fmt.Errorf("[ERROR] Error occured while configuring Event Streams schema registry: %q", err) + } + if session.esSchemaRegistryClient != nil && session.esSchemaRegistryClient.Service != nil { + session.esSchemaRegistryClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + session.esSchemaRegistryClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // Governance Service + var configServiceApiClientURL string + if c.Visibility == "private" || c.Visibility == "public-and-private" { + configServiceApiClientURL, err = configurationgovernancev1.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + configServiceApiClientURL, err = configurationgovernancev1.GetServiceURLForRegion(c.Region) + } + } else { + configServiceApiClientURL, err = configurationgovernancev1.GetServiceURLForRegion(c.Region) + } + if err != nil { + configServiceApiClientURL = configurationgovernancev1.DefaultServiceURL + } + configServiceApiClientOptions := &configurationgovernancev1.ConfigurationGovernanceV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_CONFIGURATION_GOVERNANCE_API_ENDPOINT"}, configServiceApiClientURL), + } + session.configServiceApiClient, err = configurationgovernancev1.NewConfigurationGovernanceV1(configServiceApiClientOptions) + if err == nil { + // Enable retries for API calls + session.configServiceApiClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.configServiceApiClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.configServiceApiClientErr = fmt.Errorf("Error occurred while configuring Config Service API service: %q", err) + } + + //COMPLIANCE Service + // Construct an "options" struct for creating the service client. + var postureManagementClientURL string + if c.Visibility == "public" || c.Visibility == "public-and-private" { + postureManagementClientURL, err = posturemanagementv1.GetServiceURLForRegion(c.Region) + } else { + session.postureManagementClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Security Insights Findings API service: `%v` visibility not supported", c.Visibility) + } + if err != nil { + postureManagementClientURL = posturemanagementv1.DefaultServiceURL + } + if fileMap != nil && c.Visibility != "public-and-private" { + postureManagementClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_COMPLIANCE_API_ENDPOINT", c.Region, postureManagementClientURL) + } + postureManagementClientOptions := &posturemanagementv1.PostureManagementV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_COMPLIANCE_API_ENDPOINT"}, postureManagementClientURL), + AccountID: core.StringPtr(userConfig.UserAccount), + } + + // Construct the service client. + session.postureManagementClient, err = posturemanagementv1.NewPostureManagementV1(postureManagementClientOptions) + if err != nil { + session.postureManagementClientErr = fmt.Errorf("[ERROR] Error occurred while configuring Posture Management service: %q", err) + } + if session.postureManagementClient != nil && session.postureManagementClient.Service != nil { + // Enable retries for API calls + session.postureManagementClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.postureManagementClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + //COMPLIANCE Service v2 version + // Construct an "options" struct for creating the service client. + var postureManagementClientURLv2 string + if c.Visibility == "public" || c.Visibility == "public-and-private" { + postureManagementClientURLv2, err = posturemanagementv2.GetServiceURLForRegion(c.Region) + } else { + session.postureManagementClientErrv2 = fmt.Errorf("[ERROR] Error occurred while configuring Security Compliance Centre API service: `%v` visibility not supported", c.Visibility) + } + if err != nil { + session.postureManagementClientErrv2 = fmt.Errorf("[ERROR] Error occurred while configuring Security Posture Management API service: `%s` region not supported", c.Region) + } + if fileMap != nil && c.Visibility != "public-and-private" { + postureManagementClientURLv2 = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_COMPLIANCE_API_ENDPOINT", c.Region, postureManagementClientURLv2) + } + postureManagementClientOptionsv2 := &posturemanagementv2.PostureManagementV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_COMPLIANCE_API_ENDPOINT"}, postureManagementClientURLv2), + } + + // Construct the service client. + session.postureManagementClientv2, err = posturemanagementv2.NewPostureManagementV2(postureManagementClientOptionsv2) + if err != nil { + session.postureManagementClientErrv2 = fmt.Errorf("[ERROR] Error occurred while configuring Posture Management v2 service: %q", err) + } + if session.postureManagementClientv2 != nil && session.postureManagementClientv2.Service != nil { + // Enable retries for API calls + session.postureManagementClientv2.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.postureManagementClientv2.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + + // Construct an "options" struct for creating the service client. + var cdToolchainClientURL string + if c.Visibility == "private" || c.Visibility == "public-and-private" { + cdToolchainClientURL, err = cdtoolchainv2.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + cdToolchainClientURL, err = cdtoolchainv2.GetServiceURLForRegion(c.Region) + } + } else { + cdToolchainClientURL, err = cdtoolchainv2.GetServiceURLForRegion(c.Region) + } + if err != nil { + cdToolchainClientURL = cdtoolchainv2.DefaultServiceURL + } + if fileMap != nil && c.Visibility != "public-and-private" { + cdToolchainClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_TOOLCHAIN_ENDPOINT", c.Region, cdToolchainClientURL) + } + cdToolchainClientOptions := &cdtoolchainv2.CdToolchainV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_TOOLCHAIN_ENDPOINT"}, cdToolchainClientURL), + } + + // Construct the service client. + session.cdToolchainClient, err = cdtoolchainv2.NewCdToolchainV2(cdToolchainClientOptions) + if err == nil { + // Enable retries for API calls + session.cdToolchainClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.cdToolchainClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.cdToolchainClientErr = fmt.Errorf("Error occurred while configuring Toolchain service: %q", err) + } + + // Construct an "options" struct for creating the tekton pipeline service client. + var cdTektonPipelineClientURL string + if c.Visibility == "private" || c.Visibility == "public-and-private" { + cdTektonPipelineClientURL, err = cdtektonpipelinev2.GetServiceURLForRegion("private." + c.Region) + if err != nil && c.Visibility == "public-and-private" { + cdTektonPipelineClientURL, err = cdtektonpipelinev2.GetServiceURLForRegion(c.Region) + } + } else { + cdTektonPipelineClientURL, err = cdtektonpipelinev2.GetServiceURLForRegion(c.Region) + } + if err != nil { + cdTektonPipelineClientURL = cdtektonpipelinev2.DefaultServiceURL + } + if fileMap != nil && c.Visibility != "public-and-private" { + cdTektonPipelineClientURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_TEKTON_PIPELINE_ENDPOINT", c.Region, cdTektonPipelineClientURL) + } + cdTektonPipelineClientOptions := &cdtektonpipelinev2.CdTektonPipelineV2Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_TEKTON_PIPELINE_ENDPOINT"}, cdTektonPipelineClientURL), + } + // Construct the service client. + session.cdTektonPipelineClient, err = cdtektonpipelinev2.NewCdTektonPipelineV2(cdTektonPipelineClientOptions) + if err == nil { + // Enable retries for API calls + session.cdTektonPipelineClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.cdTektonPipelineClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } else { + session.cdTektonPipelineClientErr = fmt.Errorf("Error occurred while configuring CD Tekton Pipeline service: %q", err) + } + + if os.Getenv("TF_LOG") != "" { + logDestination := log.Writer() + goLogger := log.New(logDestination, "", log.LstdFlags) + core.SetLogger(core.NewLogger(core.LevelDebug, goLogger, goLogger)) + } + + // setting UserAgent for vpc-go-sdk common + common.UserAgent = fmt.Sprintf("terraform-provider-ibm/%s", version.Version) + return session, nil +} + +// CreateVersionDate requires mandatory version attribute. Any date from 2019-12-13 up to the currentdate may be provided. Specify the current date to request the latest version. +func CreateVersionDate() *string { + version := time.Now().Format("2006-01-02") + return &version +} + +func newSession(c *Config) (*Session, error) { + ibmSession := &Session{} + + softlayerSession := &slsession.Session{ + Endpoint: c.SoftLayerEndpointURL, + Timeout: c.SoftLayerTimeout, + UserName: c.SoftLayerUserName, + APIKey: c.SoftLayerAPIKey, + Debug: os.Getenv("TF_LOG") != "", + Retries: c.RetryCount, + RetryWait: c.RetryDelay, + } + + if c.IAMToken != "" { + log.Println("Configuring SoftLayer Session with token") + softlayerSession.IAMToken = c.IAMToken + softlayerSession.IAMRefreshToken = c.IAMRefreshToken + } + if c.SoftLayerAPIKey != "" && c.SoftLayerUserName != "" { + log.Println("Configuring SoftLayer Session with API key") + softlayerSession.APIKey = c.SoftLayerAPIKey + softlayerSession.UserName = c.SoftLayerUserName + } + softlayerSession.AppendUserAgent(fmt.Sprintf("terraform-provider-ibm/%s", version.Version)) + ibmSession.SoftLayerSession = softlayerSession + + if c.IAMTrustedProfileID == "" && (c.IAMToken != "" && c.IAMRefreshToken == "") || (c.IAMToken == "" && c.IAMRefreshToken != "") { + return nil, fmt.Errorf("iam_token and iam_refresh_token must be provided") + } + if c.IAMTrustedProfileID != "" && c.IAMToken == "" { + return nil, fmt.Errorf("iam_token and iam_profile_id must be provided") + } + + if c.IAMToken != "" { + log.Println("Configuring IBM Cloud Session with token") + var sess *bxsession.Session + bmxConfig := &bluemix.Config{ + IAMAccessToken: c.IAMToken, + IAMRefreshToken: c.IAMRefreshToken, + //Comment out debug mode for v0.12 + Debug: os.Getenv("TF_LOG") != "", + HTTPTimeout: c.BluemixTimeout, + Region: c.Region, + ResourceGroup: c.ResourceGroup, + RetryDelay: &c.RetryDelay, + MaxRetries: &c.RetryCount, + Visibility: c.Visibility, + EndpointsFile: c.EndpointsFile, + UserAgent: fmt.Sprintf("terraform-provider-ibm/%s", version.Version), + } + sess, err := bxsession.New(bmxConfig) + if err != nil { + return nil, err + } + ibmSession.BluemixSession = sess + } + + if c.BluemixAPIKey != "" { + log.Println("Configuring IBM Cloud Session with API key") + var sess *bxsession.Session + bmxConfig := &bluemix.Config{ + BluemixAPIKey: c.BluemixAPIKey, + //Comment out debug mode for v0.12 + Debug: os.Getenv("TF_LOG") != "", + HTTPTimeout: c.BluemixTimeout, + Region: c.Region, + ResourceGroup: c.ResourceGroup, + RetryDelay: &c.RetryDelay, + MaxRetries: &c.RetryCount, + Visibility: c.Visibility, + EndpointsFile: c.EndpointsFile, + UserAgent: fmt.Sprintf("terraform-provider-ibm/%s", version.Version), + } + sess, err := bxsession.New(bmxConfig) + if err != nil { + return nil, err + } + ibmSession.BluemixSession = sess + } + + return ibmSession, nil +} + +func authenticateAPIKey(sess *bxsession.Session) error { + config := sess.Config + tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ + DefaultHeader: gohttp.Header{ + "User-Agent": []string{http.UserAgent()}, + "X-Original-User-Agent": []string{config.UserAgent}, + }, + }) + if err != nil { + return err + } + return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) +} + +func authenticateCF(sess *bxsession.Session) error { + config := sess.Config + tokenRefresher, err := authentication.NewUAARepository(config, &rest.Client{ + DefaultHeader: gohttp.Header{ + "User-Agent": []string{http.UserAgent()}, + "X-Original-User-Agent": []string{http.UserAgent()}, + }, + }) + if err != nil { + return err + } + return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) +} + +func fetchUserDetails(sess *bxsession.Session, retries int, retryDelay time.Duration) (*UserConfig, error) { + config := sess.Config + user := UserConfig{} + var bluemixToken string + + if strings.HasPrefix(config.IAMAccessToken, "Bearer") { + bluemixToken = config.IAMAccessToken[7:len(config.IAMAccessToken)] + } else { + bluemixToken = config.IAMAccessToken + } + + token, err := jwt.Parse(bluemixToken, func(token *jwt.Token) (interface{}, error) { + return "", nil + }) + //TODO validate with key + if err != nil && !strings.Contains(err.Error(), "key is of invalid type") { + if retries > 0 { + if config.BluemixAPIKey != "" { + time.Sleep(retryDelay) + log.Printf("Retrying authentication for user details %d", retries) + _ = authenticateAPIKey(sess) + return fetchUserDetails(sess, retries-1, retryDelay) + } + } + return &user, err + } + claims := token.Claims.(jwt.MapClaims) + if email, ok := claims["email"]; ok { + user.UserEmail = email.(string) + } + user.UserID = claims["id"].(string) + user.UserAccount = claims["account"].(map[string]interface{})["bss"].(string) + iss := claims["iss"].(string) + if strings.Contains(iss, "https://iam.cloud.ibm.com") { + user.CloudName = "bluemix" + } else { + user.CloudName = "staging" + } + user.cloudType = "public" + + user.generation = 2 + return &user, nil +} + +func RefreshToken(sess *bxsession.Session) error { + config := sess.Config + tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ + DefaultHeader: gohttp.Header{ + "User-Agent": []string{http.UserAgent()}, + "X-Original-User-Agent": []string{config.UserAgent}, + }, + }) + if err != nil { + return err + } + _, err = tokenRefresher.RefreshToken() + return err +} + +func EnvFallBack(envs []string, defaultValue string) string { + for _, k := range envs { + if v := os.Getenv(k); v != "" { + return v + } + } + return defaultValue +} +func fileFallBack(fileMap map[string]interface{}, visibility, key, region, defaultValue string) string { + if val, ok := fileMap[key]; ok { + if v, ok := val.(map[string]interface{})[visibility]; ok { + if r, ok := v.(map[string]interface{})[region]; ok && r.(string) != "" { + return r.(string) + } + } + } + return defaultValue +} + +// DefaultTransport ... +func DefaultTransport() gohttp.RoundTripper { + transport := &gohttp.Transport{ + Proxy: gohttp.ProxyFromEnvironment, + DisableKeepAlives: true, + MaxIdleConnsPerHost: -1, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + }, + } + return transport +} + +func isRetryable(err error) bool { + if bmErr, ok := err.(bmxerror.RequestFailure); ok { + switch bmErr.StatusCode() { + case 408, 504, 599, 429, 500, 502, 520, 503: + return true + } + } + + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + return true + } + + if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() { + return true + } + + if netErr, ok := err.(net.UnknownNetworkError); ok && netErr.Timeout() { + return true + } + + return false +} + +func ContructEndpoint(subdomain, domain string) string { + endpoint := fmt.Sprintf("https://%s.%s", subdomain, domain) + return endpoint +} diff --git a/ibm/config_functions.go b/ibm/conns/config_functions.go similarity index 87% rename from ibm/config_functions.go rename to ibm/conns/config_functions.go index f7988da19..5e185bee5 100644 --- a/ibm/config_functions.go +++ b/ibm/conns/config_functions.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package conns import ( "fmt" "net/http" "net/url" "os" + "strings" bluemix "github.com/IBM-Cloud/bluemix-go" "github.com/IBM-Cloud/bluemix-go/api/functions" @@ -18,7 +19,7 @@ import ( // DefaultServiceURL is the default URL to make service requests to. const DefaultServiceURL = "https://us-south.functions.cloud.ibm.com" -//FunctionClient ... +// FunctionClient ... func FunctionClient(c *bluemix.Config) (*whisk.Client, error) { baseEndpoint := getBaseURL(c.Region) u, err := url.Parse(fmt.Sprintf("%s/api", baseEndpoint)) @@ -34,7 +35,7 @@ func FunctionClient(c *bluemix.Config) (*whisk.Client, error) { return functionsClient, err } -//getBaseURL .. +// getBaseURL .. func getBaseURL(region string) string { baseEndpoint := fmt.Sprintf(DefaultServiceURL) if region != "us-south" { @@ -51,7 +52,7 @@ func getBaseURL(region string) string { * iam-based namespace don't have an auth key and needs only iam token for authorization. * */ -func setupOpenWhiskClientConfig(namespace string, sess *bxsession.Session, functionNamespace functions.FunctionServiceAPI) (*whisk.Client, error) { +func SetupOpenWhiskClientConfig(namespace string, sess *bxsession.Session, functionNamespace functions.FunctionServiceAPI) (*whisk.Client, error) { u, _ := url.Parse(fmt.Sprintf("https://%s.functions.cloud.ibm.com/api", sess.Config.Region)) wskClient, _ := whisk.NewClient(http.DefaultClient, &whisk.Config{ Host: u.Host, @@ -81,13 +82,13 @@ func setupOpenWhiskClientConfig(namespace string, sess *bxsession.Session, funct if n.IsIamEnabled() { additionalHeaders := make(http.Header) - err := refreshToken(sess) + err := RefreshToken(sess) if err != nil { for count := sess.Config.MaxRetries; *count >= 0; *count-- { if err == nil || !isRetryable(err) { break } - err = refreshToken(sess) + err = RefreshToken(sess) } if err != nil { return nil, err @@ -134,3 +135,11 @@ func setupOpenWhiskClientConfig(namespace string, sess *bxsession.Session, funct return nil, fmt.Errorf("Failed to create whisk config object for namespace '%s'", namespace) } +func validateNamespace(ns string) error { + os := strings.Split(ns, "_") + if len(os) < 2 || (len(os) == 2 && (len(os[0]) == 0 || len(os[1]) == 0)) { + return fmt.Errorf( + "Namespace is (%s), it must be of the form _, provider can't find the auth key if you use _ as well", ns) + } + return nil +} diff --git a/ibm/internal/hashcode/hashcode.go b/ibm/conns/hashcode.go similarity index 97% rename from ibm/internal/hashcode/hashcode.go rename to ibm/conns/hashcode.go index 94c0ff508..fb903d4d1 100644 --- a/ibm/internal/hashcode/hashcode.go +++ b/ibm/conns/hashcode.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package hashcode +package conns import ( "bytes" diff --git a/ibm/internal/hashcode/hashcode_test.go b/ibm/conns/hashcode_test.go similarity index 97% rename from ibm/internal/hashcode/hashcode_test.go rename to ibm/conns/hashcode_test.go index e691cfc61..2178e155e 100644 --- a/ibm/internal/hashcode/hashcode_test.go +++ b/ibm/conns/hashcode_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package hashcode +package conns import ( "testing" diff --git a/ibm/internal/mutexkv/mutexkv.go b/ibm/conns/mutexkv.go similarity index 95% rename from ibm/internal/mutexkv/mutexkv.go rename to ibm/conns/mutexkv.go index 77c001342..0615bddfd 100644 --- a/ibm/internal/mutexkv/mutexkv.go +++ b/ibm/conns/mutexkv.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package mutexkv +package conns import ( "log" @@ -17,6 +17,10 @@ import ( // // The initial use case is to let aws_security_group_rule resources serialize // their access to individual security groups based on SG ID. + +// This is a global MutexKV for use within this plugin. +var IbmMutexKV = NewMutexKV() + type MutexKV struct { lock sync.Mutex store map[string]*sync.Mutex diff --git a/ibm/internal/mutexkv/mutexkv_test.go b/ibm/conns/mutexkv_test.go similarity index 98% rename from ibm/internal/mutexkv/mutexkv_test.go rename to ibm/conns/mutexkv_test.go index ce472296e..5cd55d771 100644 --- a/ibm/internal/mutexkv/mutexkv_test.go +++ b/ibm/conns/mutexkv_test.go @@ -1,6 +1,6 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package mutexkv +package conns import ( "testing" diff --git a/ibm/conns/utils.go b/ibm/conns/utils.go new file mode 100644 index 000000000..7fefb6d9c --- /dev/null +++ b/ibm/conns/utils.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package conns + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Used for retry logic on resource timeout. +func IsResourceTimeoutError(err error) bool { + timeoutErr, ok := err.(*resource.TimeoutError) + return ok && timeoutErr.LastError == nil +} +func GetPrivateServiceURLForRegion(region string) (string, error) { + var endpoints = map[string]string{ + "us-south": "https://private.us.icr.io", // us-south + "uk-south": "https://private.uk.icr.io", // uk-south + "eu-gb": "https://private.uk.icr.io", // eu-gb + "eu-central": "https://private.de.icr.io", // eu-central + "eu-de": "https://private.de.icr.io", // eu-de + "ap-north": "https://private.jp.icr.io", // ap-north + "jp-tok": "https://private.jp.icr.io", // jp-tok + "ap-south": "https://private.au.icr.io", // ap-south + "au-syd": "https://private.au.icr.io", // au-syd + "global": "https://private.icr.io", // global + "jp-osa": "https://private.jp2.icr.io", // jp-osa + "ca-tor": "https://private.ca.icr.io", // ca-tor + "br-sao": "https://private.br.icr.io", // br-sao + } + + if url, ok := endpoints[region]; ok { + return url, nil + } + return "", fmt.Errorf("service URL for region '%s' not found", region) +} diff --git a/ibm/data_source_ibm_app_domain_private.go b/ibm/data_source_ibm_app_domain_private.go deleted file mode 100644 index dc8bdeb71..000000000 --- a/ibm/data_source_ibm_app_domain_private.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMAppDomainPrivate() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMAppDomainPrivateRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "The name of the private domain", - Type: schema.TypeString, - Required: true, - }, - }, - } -} - -func dataSourceIBMAppDomainPrivateRead(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - domainName := d.Get("name").(string) - prdomain, err := cfAPI.PrivateDomains().FindByName(domainName) - if err != nil { - return fmt.Errorf("Error retrieving domain: %s", err) - } - d.SetId(prdomain.GUID) - return nil - -} diff --git a/ibm/data_source_ibm_app_domain_shared.go b/ibm/data_source_ibm_app_domain_shared.go deleted file mode 100644 index 4e9ddc0c8..000000000 --- a/ibm/data_source_ibm_app_domain_shared.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMAppDomainShared() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMAppDomainSharedRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "The name of the shared domain", - Type: schema.TypeString, - Required: true, - ValidateFunc: validateDomainName, - }, - }, - } -} - -func dataSourceIBMAppDomainSharedRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - domainName := d.Get("name").(string) - shdomain, err := cfClient.SharedDomains().FindByName(domainName) - if err != nil { - return fmt.Errorf("Error retrieving shared domain: %s", err) - } - d.SetId(shdomain.GUID) - return nil - -} diff --git a/ibm/data_source_ibm_appid_audit_status_test.go b/ibm/data_source_ibm_appid_audit_status_test.go deleted file mode 100644 index 740e6a5ad..000000000 --- a/ibm/data_source_ibm_appid_audit_status_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package ibm - -import ( - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" -) - -func TestAccIBMAppIDAuditStatusDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: setupAppIDAuditStatusDataSourceConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_audit_status.status", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("data.ibm_appid_audit_status.status", "is_active", "true"), - ), - }, - }, - }) -} - -func setupAppIDAuditStatusDataSourceConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_audit_status" "status" { - tenant_id = "%s" - is_active = true - } - - data "ibm_appid_audit_status" "status" { - tenant_id = ibm_appid_audit_status.status.tenant_id - - depends_on = [ - ibm_appid_audit_status.status - ] - } - `, tenantID) -} diff --git a/ibm/data_source_ibm_appid_idp_saml_metadata_test.go b/ibm/data_source_ibm_appid_idp_saml_metadata_test.go deleted file mode 100644 index 7d3f7ef09..000000000 --- a/ibm/data_source_ibm_appid_idp_saml_metadata_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMAppIDIDPSAMLMetadataDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: setupAppIDIDPSAMLMetadataDataSourceConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_saml_metadata.meta", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttrSet("data.ibm_appid_idp_saml_metadata.meta", "metadata"), - ), - }, - }, - }) -} - -func setupAppIDIDPSAMLMetadataDataSourceConfig(tenantID string) string { - return fmt.Sprintf(` - data "ibm_appid_idp_saml_metadata" "meta" { - tenant_id = "%s" - } - `, tenantID) -} diff --git a/ibm/data_source_ibm_appid_mfa_test.go b/ibm/data_source_ibm_appid_mfa_test.go deleted file mode 100644 index 1aa4ef766..000000000 --- a/ibm/data_source_ibm_appid_mfa_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package ibm - -import ( - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" -) - -func TestAccAppIDMFADataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: setupIBMMFADataSourceConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_mfa.mf", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("data.ibm_appid_mfa.mf", "is_active", "true"), - ), - }, - }, - }) -} - -func setupIBMMFADataSourceConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_mfa" "mf" { - tenant_id = "%s" - is_active = true - } - data "ibm_appid_mfa" "mf" { - tenant_id = ibm_appid_mfa.mf.tenant_id - depends_on = [ - ibm_appid_mfa.mf - ] - } - `, tenantID) -} diff --git a/ibm/data_source_ibm_appid_theme_color_test.go b/ibm/data_source_ibm_appid_theme_color_test.go deleted file mode 100644 index 594980b20..000000000 --- a/ibm/data_source_ibm_appid_theme_color_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package ibm - -import ( - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" -) - -func TestAccThemeColorDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: setupAppIDThemeColorDataSourceConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_theme_color.color", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("data.ibm_appid_theme_color.color", "header_color", "#000000"), - ), - }, - }, - }) -} - -func setupAppIDThemeColorDataSourceConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_theme_color" "color" { - tenant_id = "%s" - header_color = "#000000" - } - - data "ibm_appid_theme_color" "color" { - tenant_id = ibm_appid_theme_color.color.tenant_id - - depends_on = [ - ibm_appid_theme_color.color - ] - } - `, tenantID) -} diff --git a/ibm/data_source_ibm_atracker_routes.go b/ibm/data_source_ibm_atracker_routes.go deleted file mode 100644 index 20d22b36c..000000000 --- a/ibm/data_source_ibm_atracker_routes.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/atrackerv1" -) - -func dataSourceIBMAtrackerRoutes() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMAtrackerRoutesRead, - - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the route.", - }, - "routes": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of route resources.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The uuid of the route resource.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the route.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the route resource.", - }, - "version": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The version of the route.", - }, - "receive_global_events": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether or not all global events should be forwarded to this region.", - }, - "rules": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The routing rules that will be evaluated in their order of the array.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target_ids": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The target ID List. Only 1 target id is supported.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "created": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the route creation time.", - }, - "updated": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the route last updated time.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMAtrackerRoutesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - listRoutesOptions := &atrackerv1.ListRoutesOptions{} - - routeList, response, err := atrackerClient.ListRoutesWithContext(context, listRoutesOptions) - if err != nil { - log.Printf("[DEBUG] ListRoutesWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListRoutesWithContext failed %s\n%s", err, response)) - } - - // Use the provided filter argument and construct a new list with only the requested resource(s) - var matchRoutes []atrackerv1.Route - var name string - var suppliedFilter bool - - if v, ok := d.GetOk("name"); ok { - name = v.(string) - suppliedFilter = true - for _, data := range routeList.Routes { - if *data.Name == name { - matchRoutes = append(matchRoutes, data) - } - } - } else { - matchRoutes = routeList.Routes - } - routeList.Routes = matchRoutes - - if suppliedFilter { - if len(routeList.Routes) == 0 { - return diag.FromErr(fmt.Errorf("no Routes found with name %s", name)) - } - d.SetId(name) - } else { - d.SetId(dataSourceIBMAtrackerRoutesID(d)) - } - - if routeList.Routes != nil { - err = d.Set("routes", dataSourceRouteListFlattenRoutes(routeList.Routes)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting routes %s", err)) - } - } - - return nil -} - -// dataSourceIBMAtrackerRoutesID returns a reasonable ID for the list. -func dataSourceIBMAtrackerRoutesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceRouteListFlattenRoutes(result []atrackerv1.Route) (routes []map[string]interface{}) { - for _, routesItem := range result { - routes = append(routes, dataSourceRouteListRoutesToMap(routesItem)) - } - - return routes -} - -func dataSourceRouteListRoutesToMap(routesItem atrackerv1.Route) (routesMap map[string]interface{}) { - routesMap = map[string]interface{}{} - - if routesItem.ID != nil { - routesMap["id"] = routesItem.ID - } - if routesItem.Name != nil { - routesMap["name"] = routesItem.Name - } - if routesItem.CRN != nil { - routesMap["crn"] = routesItem.CRN - } - if routesItem.Version != nil { - routesMap["version"] = routesItem.Version - } - if routesItem.ReceiveGlobalEvents != nil { - routesMap["receive_global_events"] = routesItem.ReceiveGlobalEvents - } - if routesItem.Rules != nil { - rulesList := []map[string]interface{}{} - for _, rulesItem := range routesItem.Rules { - rulesList = append(rulesList, dataSourceRouteListRoutesRulesToMap(rulesItem)) - } - routesMap["rules"] = rulesList - } - if routesItem.Created != nil { - routesMap["created"] = routesItem.Created.String() - } - if routesItem.Updated != nil { - routesMap["updated"] = routesItem.Updated.String() - } - - return routesMap -} - -func dataSourceRouteListRoutesRulesToMap(rulesItem atrackerv1.Rule) (rulesMap map[string]interface{}) { - rulesMap = map[string]interface{}{} - - if rulesItem.TargetIds != nil { - rulesMap["target_ids"] = rulesItem.TargetIds - } - - return rulesMap -} diff --git a/ibm/data_source_ibm_atracker_targets.go b/ibm/data_source_ibm_atracker_targets.go deleted file mode 100644 index 1663304c0..000000000 --- a/ibm/data_source_ibm_atracker_targets.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/atrackerv1" -) - -func dataSourceIBMAtrackerTargets() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMAtrackerTargetsRead, - - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the target resource.", - }, - "targets": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of target resources.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The uuid of the target resource.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the target resource.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the target resource.", - }, - "target_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of the target.", - }, - "encrypt_key": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", - }, - "cos_endpoint": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Property values for a Cloud Object Storage Endpoint.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "endpoint": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The host name of the Cloud Object Storage endpoint.", - }, - "target_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the Cloud Object Storage instance.", - }, - "bucket": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The bucket name under the Cloud Object Storage instance.", - }, - "api_key": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response.", - }, - }, - }, - }, - "cos_write_status": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The status of the write attempt with the provided cos_endpoint parameters.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The status such as failed or success.", - }, - "last_failure": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the failure.", - }, - "reason_for_last_failure": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Detailed description of the cause of the failure.", - }, - }, - }, - }, - "created": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the target creation time.", - }, - "updated": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the target last updated time.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMAtrackerTargetsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - listTargetsOptions := &atrackerv1.ListTargetsOptions{} - - targetList, response, err := atrackerClient.ListTargetsWithContext(context, listTargetsOptions) - if err != nil { - log.Printf("[DEBUG] ListTargetsWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListTargetsWithContext failed %s\n%s", err, response)) - } - - // Use the provided filter argument and construct a new list with only the requested resource(s) - var matchTargets []atrackerv1.Target - var name string - var suppliedFilter bool - - if v, ok := d.GetOk("name"); ok { - name = v.(string) - suppliedFilter = true - for _, data := range targetList.Targets { - if *data.Name == name { - matchTargets = append(matchTargets, data) - } - } - } else { - matchTargets = targetList.Targets - } - targetList.Targets = matchTargets - - if suppliedFilter { - if len(targetList.Targets) == 0 { - return diag.FromErr(fmt.Errorf("no Targets found with name %s", name)) - } - d.SetId(name) - } else { - d.SetId(dataSourceIBMAtrackerTargetsID(d)) - } - - if targetList.Targets != nil { - err = d.Set("targets", dataSourceTargetListFlattenTargets(targetList.Targets)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting targets %s", err)) - } - } - - return nil -} - -// dataSourceIBMAtrackerTargetsID returns a reasonable ID for the list. -func dataSourceIBMAtrackerTargetsID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceTargetListFlattenTargets(result []atrackerv1.Target) (targets []map[string]interface{}) { - for _, targetsItem := range result { - targets = append(targets, dataSourceTargetListTargetsToMap(targetsItem)) - } - - return targets -} - -func dataSourceTargetListTargetsToMap(targetsItem atrackerv1.Target) (targetsMap map[string]interface{}) { - targetsMap = map[string]interface{}{} - - if targetsItem.ID != nil { - targetsMap["id"] = targetsItem.ID - } - if targetsItem.Name != nil { - targetsMap["name"] = targetsItem.Name - } - if targetsItem.CRN != nil { - targetsMap["crn"] = targetsItem.CRN - } - if targetsItem.TargetType != nil { - targetsMap["target_type"] = targetsItem.TargetType - } - if targetsItem.EncryptKey != nil { - targetsMap["encrypt_key"] = targetsItem.EncryptKey - } - if targetsItem.CosEndpoint != nil { - cosEndpointList := []map[string]interface{}{} - cosEndpointMap := dataSourceTargetListTargetsCosEndpointToMap(*targetsItem.CosEndpoint) - cosEndpointList = append(cosEndpointList, cosEndpointMap) - targetsMap["cos_endpoint"] = cosEndpointList - } - if targetsItem.CosWriteStatus != nil { - cosWriteStatusList := []map[string]interface{}{} - cosWriteStatusMap := dataSourceTargetListTargetsCosWriteStatusToMap(*targetsItem.CosWriteStatus) - cosWriteStatusList = append(cosWriteStatusList, cosWriteStatusMap) - targetsMap["cos_write_status"] = cosWriteStatusList - } - if targetsItem.Created != nil { - targetsMap["created"] = targetsItem.Created.String() - } - if targetsItem.Updated != nil { - targetsMap["updated"] = targetsItem.Updated.String() - } - - return targetsMap -} - -func dataSourceTargetListTargetsCosEndpointToMap(cosEndpointItem atrackerv1.CosEndpoint) (cosEndpointMap map[string]interface{}) { - cosEndpointMap = map[string]interface{}{} - - if cosEndpointItem.Endpoint != nil { - cosEndpointMap["endpoint"] = cosEndpointItem.Endpoint - } - if cosEndpointItem.TargetCRN != nil { - cosEndpointMap["target_crn"] = cosEndpointItem.TargetCRN - } - if cosEndpointItem.Bucket != nil { - cosEndpointMap["bucket"] = cosEndpointItem.Bucket - } - if cosEndpointItem.APIKey != nil { - cosEndpointMap["api_key"] = cosEndpointItem.APIKey - } - - return cosEndpointMap -} - -func dataSourceTargetListTargetsCosWriteStatusToMap(cosWriteStatusItem atrackerv1.CosWriteStatus) (cosWriteStatusMap map[string]interface{}) { - cosWriteStatusMap = map[string]interface{}{} - - if cosWriteStatusItem.Status != nil { - cosWriteStatusMap["status"] = cosWriteStatusItem.Status - } - if cosWriteStatusItem.LastFailure != nil { - cosWriteStatusMap["last_failure"] = cosWriteStatusItem.LastFailure.String() - } - if cosWriteStatusItem.ReasonForLastFailure != nil { - cosWriteStatusMap["reason_for_last_failure"] = cosWriteStatusItem.ReasonForLastFailure - } - - return cosWriteStatusMap -} diff --git a/ibm/data_source_ibm_atracker_targets_test.go b/ibm/data_source_ibm_atracker_targets_test.go deleted file mode 100644 index 8b96ed870..000000000 --- a/ibm/data_source_ibm_atracker_targets_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMAtrackerTargetsDataSourceBasic(t *testing.T) { - targetName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - targetTargetType := "cloud_object_storage" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMAtrackerTargetsDataSourceConfigBasic(targetName, targetTargetType), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "id"), - resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.#"), - resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.name", targetName), - resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.target_type", targetTargetType), - ), - }, - }, - }) -} - -func testAccCheckIBMAtrackerTargetsDataSourceConfigBasic(targetName string, targetTargetType string) string { - return fmt.Sprintf(` - resource "ibm_atracker_target" "atracker_target" { - name = "%s" - target_type = "%s" - cos_endpoint { - endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" - target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" - bucket = "my-atracker-bucket" - api_key = "xxxxxxxxxxxxxx" - } - } - - data "ibm_atracker_targets" "atracker_targets" { - name = ibm_atracker_target.atracker_target.name - } - `, targetName, targetTargetType) -} diff --git a/ibm/data_source_ibm_cis.go b/ibm/data_source_ibm_cis.go deleted file mode 100644 index 14448fc3d..000000000 --- a/ibm/data_source_ibm_cis.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "net/url" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" - "github.com/IBM-Cloud/bluemix-go/models" -) - -func dataSourceIBMCISInstance() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISInstanceRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Resource instance name for example, my cis instance", - Type: schema.TypeString, - Required: true, - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "The id of the resource group in which the cis instance is present", - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Unique identifier of resource instance", - }, - - "location": { - Description: "The location or the environment in which cis instance exists", - Type: schema.TypeString, - Computed: true, - }, - - "service": { - Description: "The name of the Cloud Internet Services offering, 'internet-svcs'", - Type: schema.TypeString, - Computed: true, - }, - - "plan": { - Description: "The plan type of the cis instance", - Type: schema.TypeString, - Computed: true, - }, - - "status": { - Description: "The resource instance status", - Type: schema.TypeString, - Computed: true, - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} - -func dataSourceIBMCISInstanceRead(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerAPIV2() - if err != nil { - return err - } - rsAPI := rsConClient.ResourceServiceInstanceV2() - name := d.Get("name").(string) - - rsInstQuery := controllerv2.ServiceInstanceQuery{ - Name: name, - } - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rsInstQuery.ResourceGroupID = rsGrpID.(string) - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInstQuery.ResourceGroupID = defaultRg - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - if service, ok := d.GetOk("service"); ok { - - serviceOff, err := rsCatRepo.FindByName(service.(string), true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - rsInstQuery.ServiceID = serviceOff[0].ID - } - - var instances []models.ServiceInstanceV2 - - instances, err = rsAPI.ListInstances(rsInstQuery) - if err != nil { - return err - } - var filteredInstances []models.ServiceInstanceV2 - var location string - - if loc, ok := d.GetOk("location"); ok { - location = loc.(string) - for _, instance := range instances { - if getLocation(instance) == location { - filteredInstances = append(filteredInstances, instance) - } - } - } else { - filteredInstances = instances - } - - if len(filteredInstances) == 0 { - return fmt.Errorf("No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) - } - - var instance models.ServiceInstanceV2 - - if len(filteredInstances) > 1 { - return fmt.Errorf( - "More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) - } - instance = filteredInstances[0] - - d.SetId(instance.ID) - d.Set("status", instance.State) - d.Set("resource_group_id", instance.ResourceGroupID) - d.Set("location", instance.RegionID) - d.Set("guid", instance.Guid) - serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - d.Set("service", serviceOff) - - servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - - d.Set(ResourceName, instance.Name) - d.Set(ResourceCRN, instance.Crn.String()) - d.Set(ResourceStatus, instance.State) - d.Set(ResourceGroupName, instance.ResourceGroupName) - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/internet-svcs/"+url.QueryEscape(instance.Crn.String())) - - return nil -} diff --git a/ibm/data_source_ibm_cis_custom_certificates.go b/ibm/data_source_ibm_cis_custom_certificates.go deleted file mode 100644 index 93e15fe13..000000000 --- a/ibm/data_source_ibm_cis_custom_certificates.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisCustomCertificates = "custom_certificates" -) - -func dataSourceIBMCISCustomCertificates() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISCustomCertificatesRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisCustomCertificates: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - cisCertificateUploadCustomCertID: { - Type: schema.TypeString, - Computed: true, - }, - cisCertificateUploadBundleMethod: { - Type: schema.TypeString, - Description: "Certificate bundle method", - Computed: true, - }, - cisCertificateUploadHosts: { - Type: schema.TypeList, - Computed: true, - Description: "hosts which the certificate uploaded to", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - cisPageRulePriority: { - Type: schema.TypeInt, - Description: "Certificate priority", - Computed: true, - }, - cisCertificateUploadStatus: { - Type: schema.TypeString, - Description: "certificate status", - Computed: true, - }, - cisCertificateUploadIssuer: { - Type: schema.TypeString, - Description: "certificate issuer", - Computed: true, - }, - cisCertificateUploadSignature: { - Type: schema.TypeString, - Description: "certificate signature", - Computed: true, - }, - cisCertificateUploadUploadedOn: { - Type: schema.TypeString, - Description: "certificate uploaded date", - Computed: true, - }, - cisCertificateUploadModifiedOn: { - Type: schema.TypeString, - Description: "certificate modified date", - Computed: true, - }, - cisCertificateUploadExpiresOn: { - Type: schema.TypeString, - Description: "certificate expires date", - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISCustomCertificatesRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewListCustomCertificatesOptions() - result, resp, err := cisClient.ListCustomCertificates(opt) - if err != nil { - return fmt.Errorf("Failed to list custom certificates: %v", resp) - } - certsList := make([]map[string]interface{}, 0) - for _, r := range result.Result { - cert := map[string]interface{}{} - cert["id"] = convertCisToTfThreeVar(*r.ID, zoneID, crn) - cert[cisCertificateUploadCustomCertID] = *r.ID - cert[cisCertificateUploadBundleMethod] = *r.BundleMethod - cert[cisCertificateUploadHosts] = flattenStringList(r.Hosts) - cert[cisCertificateUploadIssuer] = *r.Issuer - cert[cisCertificateUploadSignature] = *r.Signature - cert[cisCertificateUploadStatus] = *r.Status - cert[cisCertificateUploadPriority] = *r.Priority - cert[cisCertificateUploadUploadedOn] = *r.UploadedOn - cert[cisCertificateUploadModifiedOn] = *r.ModifiedOn - cert[cisCertificateUploadExpiresOn] = *r.ExpiresOn - certsList = append(certsList, cert) - } - d.SetId(dataSourceIBMCISCustomCertificatesID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisCustomCertificates, certsList) - return nil -} - -func dataSourceIBMCISCustomCertificatesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_custom_pages.go b/ibm/data_source_ibm_cis_custom_pages.go deleted file mode 100644 index 6e9cd1891..000000000 --- a/ibm/data_source_ibm_cis_custom_pages.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisCustomPages = "cis_custom_pages" -) - -func dataSourceIBMCISCustomPages() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISCustomPagesRead, - Importer: &schema.ResourceImporter{}, - Timeouts: &schema.ResourceTimeout{ - Read: schema.DefaultTimeout(10 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisCustomPages: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisCustomPageIdentifier: { - Type: schema.TypeString, - Description: "Custom page identifier", - Computed: true, - }, - cisCustomPageURL: { - Type: schema.TypeString, - Description: "Custom page url", - Computed: true, - }, - cisCustomPageState: { - Type: schema.TypeString, - Description: "Custom page state", - Computed: true, - }, - cisCustomPageDesc: { - Type: schema.TypeString, - Description: "Free text", - Computed: true, - }, - cisCustomPageRequiredTokens: { - Type: schema.TypeList, - Description: "Custom page state", - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - cisCustomPagePreviewTarget: { - Type: schema.TypeString, - Description: "Custom page preview target", - Computed: true, - }, - cisCustomPageCreatedOn: { - Type: schema.TypeString, - Description: "Custom page created date", - Computed: true, - }, - cisCustomPageModifiedOn: { - Type: schema.TypeString, - Description: "Custom page modified date", - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISCustomPagesRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisCustomPageClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID := d.Get(cisDomainID).(string) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewListZoneCustomPagesOptions() - - result, response, err := cisClient.ListZoneCustomPages(opt) - if err != nil { - log.Printf("List custom pages failed: %v", response) - return err - } - customPagesOutput := make([]map[string]interface{}, 0) - for _, instance := range result.Result { - customPage := make(map[string]interface{}, 0) - customPage[cisCustomPageIdentifier] = *instance.ID - customPage[cisCustomPageState] = *instance.State - customPage[cisCustomPageDesc] = *instance.Description - customPage[cisCustomPagePreviewTarget] = *instance.PreviewTarget - customPage[cisCustomPageRequiredTokens] = flattenStringList(instance.RequiredTokens) - if instance.CreatedOn != nil { - customPage[cisCustomPageCreatedOn] = (*instance.CreatedOn).String() - } - if instance.ModifiedOn != nil { - customPage[cisCustomPageModifiedOn] = (*instance.ModifiedOn).String() - } - if instance.URL != nil { - customPage[cisCustomPageURL] = *instance.URL - } - - customPagesOutput = append(customPagesOutput, customPage) - } - d.SetId(dataSourceIBMCISCustomPageID(d)) - d.Set(cisCustomPages, customPagesOutput) - return nil -} - -func dataSourceIBMCISCustomPageID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_domain.go b/ibm/data_source_ibm_cis_domain.go deleted file mode 100644 index 8dd536e66..000000000 --- a/ibm/data_source_ibm_cis_domain.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMCISDomain() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISDomainRead, - - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS object id", - Required: true, - }, - cisDomain: { - Type: schema.TypeString, - Description: "CISzone - Domain", - Required: true, - }, - cisDomainPaused: { - Type: schema.TypeBool, - Computed: true, - }, - cisDomainStatus: { - Type: schema.TypeString, - Computed: true, - }, - cisDomainNameServers: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisDomainOriginalNameServers: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisDomainID: { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func dataSourceIBMCISDomainRead(d *schema.ResourceData, meta interface{}) error { - var zoneFound bool - cisClient, err := meta.(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - cisClient.Crn = core.StringPtr(crn) - zoneName := d.Get(cisDomain).(string) - - opt := cisClient.NewListZonesOptions() - opt.SetPage(1) // list all zones in one page - opt.SetPerPage(1000) // maximum allowed limit is 1000 per page - zones, resp, err := cisClient.ListZones(opt) - if err != nil { - log.Printf("dataSourcCISdomainRead - ListZones Failed %s\n", resp) - return err - } - - for _, zone := range zones.Result { - if *zone.Name == zoneName { - d.SetId(convertCisToTfTwoVar(*zone.ID, crn)) - d.Set(cisID, crn) - d.Set(cisDomain, *zone.Name) - d.Set(cisDomainStatus, *zone.Status) - d.Set(cisDomainPaused, *zone.Paused) - d.Set(cisDomainNameServers, zone.NameServers) - d.Set(cisDomainOriginalNameServers, zone.OriginalNameServers) - d.Set(cisDomainID, *zone.ID) - zoneFound = true - } - } - - if zoneFound == false { - return fmt.Errorf("Given zone does not exist. Please specify correct domain") - } - - return nil -} diff --git a/ibm/data_source_ibm_cis_edge_functions_triggers.go b/ibm/data_source_ibm_cis_edge_functions_triggers.go deleted file mode 100644 index 41745b381..000000000 --- a/ibm/data_source_ibm_cis_edge_functions_triggers.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const cisEdgeFunctionsTriggers = "cis_edge_functions_triggers" - -func dataSourceIBMCISEdgeFunctionsTriggers() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISEdgeFunctionsTriggerRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDataDiff, - }, - cisEdgeFunctionsTriggers: { - Type: schema.TypeList, - Description: "List of edge functions triggers", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Edge function trigger id", - }, - cisEdgeFunctionsTriggerID: { - Type: schema.TypeString, - Computed: true, - Description: "Edge function trigger route id", - }, - cisEdgeFunctionsTriggerPattern: { - Type: schema.TypeString, - Computed: true, - Description: "Edge function trigger pattern", - }, - cisEdgeFunctionsTriggerActionName: { - Type: schema.TypeString, - Computed: true, - Description: "Edge function trigger script name", - }, - cisEdgeFunctionsTriggerRequestLimitFailOpen: { - Type: schema.TypeBool, - Computed: true, - Description: "Edge function trigger request limit fail open", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISEdgeFunctionsTriggerRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewListEdgeFunctionsTriggersOptions() - result, _, err := cisClient.ListEdgeFunctionsTriggers(opt) - if err != nil { - return fmt.Errorf("Error listing edge functions triggers: %v", err) - } - triggerInfo := make([]map[string]interface{}, 0) - for _, trigger := range result.Result { - l := map[string]interface{}{} - l["id"] = convertCisToTfThreeVar(*trigger.ID, zoneID, crn) - l[cisEdgeFunctionsTriggerID] = *trigger.ID - l[cisEdgeFunctionsTriggerPattern] = *trigger.Pattern - l[cisEdgeFunctionsTriggerRequestLimitFailOpen] = *trigger.RequestLimitFailOpen - if trigger.Script != nil { - l[cisEdgeFunctionsTriggerActionName] = *trigger.Script - } - triggerInfo = append(triggerInfo, l) - } - d.SetId(dataSourceIBMCISEdgeFunctionsTriggersID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisEdgeFunctionsTriggers, triggerInfo) - return nil -} - -func dataSourceIBMCISEdgeFunctionsTriggersID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_filters.go b/ibm/data_source_ibm_cis_filters.go deleted file mode 100644 index b88aa1878..000000000 --- a/ibm/data_source_ibm_cis_filters.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const cisFiltersList = "cis_filters_list" - -func dataSourceIBMCISFilters() *schema.Resource { - return &schema.Resource{ - Read: dataIBMCISFiltersRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisFiltersList: { - Type: schema.TypeList, - Description: "Collection of Filter detail", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisFilterPaused: { - Type: schema.TypeBool, - Computed: true, - Description: "Filter Paused", - }, - cisFilterID: { - Type: schema.TypeString, - Computed: true, - Description: "Filter ID", - }, - cisFilterExpression: { - Type: schema.TypeString, - Computed: true, - Description: "Filter Expression", - }, - cisFilterDescription: { - Type: schema.TypeString, - Computed: true, - Description: "Filter Description", - }, - }, - }, - }, - }, - } -} -func dataIBMCISFiltersRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return fmt.Errorf("Error while Getting IAM Access Token using BluemixSession %s", err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFiltersSession() - if err != nil { - return fmt.Errorf("Error while getting the CisFiltersSession %s", err) - } - crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - - result, resp, err := cisClient.ListAllFilters(cisClient.NewListAllFiltersOptions(xAuthtoken, crn, zoneID)) - if err != nil || result == nil { - return fmt.Errorf("Error Listing all filters %q: %s %s", d.Id(), err, resp) - } - - filtersList := make([]map[string]interface{}, 0) - - for _, filtersObj := range result.Result { - filtersOutput := map[string]interface{}{} - filtersOutput[cisFilterID] = *filtersObj.ID - filtersOutput[cisFilterDescription] = filtersObj.Description - filtersOutput[cisFilterExpression] = *filtersObj.Expression - filtersOutput[cisFilterPaused] = *filtersObj.Paused - filtersList = append(filtersList, filtersOutput) - } - d.SetId(dataSourceCISFiltersCheckID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisFiltersList, filtersList) - return nil -} - -func dataSourceCISFiltersCheckID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_filters_test.go b/ibm/data_source_ibm_cis_filters_test.go deleted file mode 100644 index 9c4884c75..000000000 --- a/ibm/data_source_ibm_cis_filters_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisFilterDataSource_Basic(t *testing.T) { - name := "data.ibm_cis_filter.test" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisFilterDataSource_basic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(name, "id"), - ), - }, - }, - }) -} -func testAccCheckCisFilterDataSource_basic(id, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - data "ibm_cis_filter" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - } -`, id, cisDomainStatic) -} diff --git a/ibm/data_source_ibm_cis_firewall_rule.go b/ibm/data_source_ibm_cis_firewall_rule.go deleted file mode 100644 index 648c63151..000000000 --- a/ibm/data_source_ibm_cis_firewall_rule.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMCISFirewallRules() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMCISFirewallRulesRead, - - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "Full url-encoded cloud resource name (CRN) of resource instance.", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "Zone identifier of the zone for which firewall rules are listed.", - }, - cisFirewallrulesList: { - Type: schema.TypeList, - Computed: true, - Description: "Container for response information.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisFirewallrulesID: { - Type: schema.TypeString, - Computed: true, - Description: "Identifier of the firewall rule.", - }, - cisFirewallrulesPaused: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if the firewall rule is active.", - }, - cisFirewallrulesDescription: { - Type: schema.TypeString, - Computed: true, - Description: "To briefly describe the firewall rule, omitted from object if empty.", - }, - cisFirewallrulesAction: { - Type: schema.TypeString, - Computed: true, - Description: "The firewall action to perform, \"log\" action is only available for enterprise plan instances.", - }, - cisFilter: { - Type: schema.TypeMap, - Computed: true, - Description: "An existing filter.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISFirewallRulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFirewallRulesSession() - if err != nil { - return diag.FromErr(err) - } - crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - - result, resp, err := cisClient.ListAllFirewallRules(cisClient.NewListAllFirewallRulesOptions(xAuthtoken, crn, zoneID)) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error listing the firewall rules %s:%s", err, resp)) - } - - fwrList := make([]map[string]interface{}, 0) - - for _, instance := range result.Result { - firewallrules := map[string]interface{}{} - fr_filters := map[string]interface{}{} - firewallrules[cisFirewallrulesID] = *instance.ID - firewallrules[cisFirewallrulesPaused] = *instance.Paused - firewallrules[cisFirewallrulesDescription] = instance.Description - firewallrules[cisFirewallrulesAction] = *instance.Action - fr_filters[cisFilterID] = *instance.Filter.ID - if *instance.Filter.Paused { - fr_filters[cisFilterPaused] = "true" - } else { - fr_filters[cisFilterPaused] = "false" - } - fr_filters[cisFilterExpression] = *instance.Filter.Expression - fr_filters[cisFilterDescription] = instance.Filter.Description - firewallrules[cisFilter] = fr_filters - fwrList = append(fwrList, firewallrules) - } - d.SetId(dataSourceCISFirewallrulesCheckID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisFirewallrulesList, fwrList) - return nil -} -func dataSourceCISFirewallrulesCheckID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_firewall_rule_test.go b/ibm/data_source_ibm_cis_firewall_rule_test.go deleted file mode 100644 index 054f297fb..000000000 --- a/ibm/data_source_ibm_cis_firewall_rule_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisFirewallRulesDataSource_Basic(t *testing.T) { - name := "data.ibm_cis_firewall_rules.test" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIbmFirewallRulesDataSourceConfigBasic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(name, "id"), - ), - }, - }, - }) -} - -func testAccCheckIbmFirewallRulesDataSourceConfigBasic(id, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - data "ibm_cis_firewall_rules" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - } -`, id, cisDomainStatic) -} diff --git a/ibm/data_source_ibm_cis_ip_addresses.go b/ibm/data_source_ibm_cis_ip_addresses.go deleted file mode 100644 index 10f55ea06..000000000 --- a/ibm/data_source_ibm_cis_ip_addresses.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisIPv4CIDRs = "ipv4_cidrs" - cisIPv6CIDRs = "ipv6_cidrs" -) - -func dataSourceIBMCISIP() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISIPRead, - - Schema: map[string]*schema.Schema{ - cisIPv4CIDRs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisIPv6CIDRs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - } -} - -func dataSourceIBMCISIPRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisIPClientSession() - if err != nil { - return err - } - opt := cisClient.NewListIpsOptions() - result, response, err := cisClient.ListIps(opt) - if err != nil { - log.Printf("Failed to list IP addresses: %v", response) - return err - } - - d.Set(cisIPv4CIDRs, flattenStringList(result.Result.Ipv4Cidrs)) - d.Set(cisIPv6CIDRs, flattenStringList(result.Result.Ipv4Cidrs)) - d.SetId(dataSourceIBMCISIPID(d)) - return nil -} - -func dataSourceIBMCISIPID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_ip_addresses_test.go b/ibm/data_source_ibm_cis_ip_addresses_test.go deleted file mode 100644 index b97d261e8..000000000 --- a/ibm/data_source_ibm_cis_ip_addresses_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strconv" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMCisIPDataSource_Basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: fmt.Sprintf(testAccCheckIBMCisIPDataSourceConfigBasic), - Check: resource.ComposeTestCheckFunc( - testAccIBMCisIPAddrs("data.ibm_cis_ip_addresses.test_acc"), - ), - }, - }, - }) -} - -func testAccIBMCisIPAddrs(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - r := s.RootModule().Resources[n] - a := r.Primary.Attributes - - cidrs, _ := strconv.Atoi(a["ipv4_cidrs.#"]) - if cidrs == 0 { - return fmt.Errorf("No ipv4 cidrs returned") - } - cidrs, _ = strconv.Atoi(a["ipv6_cidrs.#"]) - if cidrs == 0 { - return fmt.Errorf("No ipv6 cidrs returned") - } - return nil - } -} - -const testAccCheckIBMCisIPDataSourceConfigBasic = ` -data "ibm_cis_ip_addresses" "test_acc" {} -` diff --git a/ibm/data_source_ibm_cis_origin_pools_test.go b/ibm/data_source_ibm_cis_origin_pools_test.go deleted file mode 100644 index a9cefc79e..000000000 --- a/ibm/data_source_ibm_cis_origin_pools_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisPoolsDataSource_Basic(t *testing.T) { - node := "data.ibm_cis_origin_pools.test" - rnd := acctest.RandString(10) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMCisPoolsDataSourceConfig(rnd, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.id"), - resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.pool_id"), - resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.description"), - ), - }, - }, - }) -} - -func testAccCheckIBMCisPoolsDataSourceConfig(resourceID, cisDomainStatic string) string { - return testAccCheckCisPoolConfigCisDSBasic(resourceID, cisDomainStatic) + fmt.Sprintf(` - data "ibm_cis_origin_pools" "test" { - cis_id = ibm_cis_origin_pool.origin_pool.cis_id - } - `) -} diff --git a/ibm/data_source_ibm_cis_page_rules.go b/ibm/data_source_ibm_cis_page_rules.go deleted file mode 100644 index 482127137..000000000 --- a/ibm/data_source_ibm_cis_page_rules.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisPageRules = "cis_page_rules" -) - -func dataSourceIBMCISPageRules() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISPageRulesRead, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Read: schema.DefaultTimeout(10 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "DNS Zone CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "DNS Zone ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisPageRules: { - Type: schema.TypeList, - Description: "Collection of page rules detail", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Page rule identifier", - }, - cisPageRuleID: { - Type: schema.TypeString, - Computed: true, - }, - cisPageRulePriority: { - Type: schema.TypeInt, - Description: "Page rule priority", - Computed: true, - }, - cisPageRuleStatus: { - Type: schema.TypeString, - Description: "Page Rule status", - Computed: true, - }, - cisPageRuleTargets: { - Type: schema.TypeList, - Description: "Page rule targets", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisPageRuleTargetsTarget: { - Type: schema.TypeString, - Computed: true, - Description: "Page rule target url", - }, - cisPageRuleTargetsConstraint: { - Type: schema.TypeList, - Computed: true, - Description: "Page rule constraint", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisPageRuleTargetsConstraintOperator: { - Type: schema.TypeString, - Computed: true, - Description: "Constraint operator", - }, - cisPageRuleTargetsConstraintValue: { - Type: schema.TypeString, - Computed: true, - Description: "Constraint value", - }, - }, - }, - }, - }, - }, - }, - cisPageRuleActions: { - Type: schema.TypeList, - Description: "Page rule actions", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisPageRuleActionsID: { - Type: schema.TypeString, - Computed: true, - Description: "Page rule target url", - }, - cisPageRuleActionsValue: { - Type: schema.TypeString, - Computed: true, - Description: "Page rule target url", - }, - cisPageRuleActionsValueURL: { - Type: schema.TypeString, - Computed: true, - Description: "Page rule actions value url", - }, - cisPageRuleActionsValueStatusCode: { - Type: schema.TypeInt, - Computed: true, - Description: "Page rule actions status code", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISPageRulesRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisPageRuleClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - sess.Crn = core.StringPtr(crn) - sess.ZoneID = core.StringPtr(zoneID) - - opt := sess.NewListPageRulesOptions() - - result, resp, err := sess.ListPageRules(opt) - if err != nil { - log.Printf("Error listing page rules detail: %s", resp) - return err - } - - pageRules := make([]map[string]interface{}, 0) - for _, instance := range result.Result { - pageRule := map[string]interface{}{} - pageRule["id"] = convertCisToTfThreeVar(*instance.ID, zoneID, crn) - pageRule[cisPageRuleID] = *instance.ID - pageRule[cisPageRulePriority] = *instance.Priority - pageRule[cisPageRuleStatus] = *instance.Status - pageRule[cisPageRuleTargets] = flattenCISPageRuleTargets(instance.Targets) - pageRule[cisPageRuleActions] = flattenCISPageRuleActions(instance.Actions) - pageRules = append(pageRules, pageRule) - } - d.SetId(dataSourceIBMCISPageRulesID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisPageRules, pageRules) - return nil -} - -func dataSourceIBMCISPageRulesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_waf_groups.go b/ibm/data_source_ibm_cis_waf_groups.go deleted file mode 100644 index 4aec958b0..000000000 --- a/ibm/data_source_ibm_cis_waf_groups.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const cisWAFGroups = "waf_groups" - -func dataSourceIBMCISWAFGroups() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISWAFGroupsRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFGroupPackageID: { - Type: schema.TypeString, - Required: true, - Description: "WAF Rule package id", - }, - cisWAFGroups: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group id", - }, - cisWAFGroupID: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group id", - }, - cisWAFGroupMode: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group mode on/off", - }, - cisWAFGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group name", - }, - cisWAFGroupDesc: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group description", - }, - cisWAFGroupRulesCount: { - Type: schema.TypeInt, - Computed: true, - Description: "WAF Rule group rules count", - }, - cisWAFGroupModifiedRulesCount: { - Type: schema.TypeInt, - Computed: true, - Description: "WAF Rule group modified rules count", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISWAFGroupsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFGroupClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - packageID, _, _, _ := convertTfToCisThreeVar(d.Get(cisWAFGroupPackageID).(string)) - - opt := cisClient.NewListWafRuleGroupsOptions(packageID) - opt.SetPage(1) - opt.SetPerPage(100) - result, resp, err := cisClient.ListWafRuleGroups(opt) - if err != nil { - log.Printf("List waf rule groups failed: %s\n", resp) - return err - } - wafGroups := []interface{}{} - for _, i := range result.Result { - waf := map[string]interface{}{} - waf["id"] = convertCisToTfFourVar(*i.ID, packageID, zoneID, crn) - waf[cisWAFGroupID] = *i.ID - waf[cisWAFGroupName] = *i.Name - waf[cisWAFGroupDesc] = *i.Description - waf[cisWAFGroupMode] = *i.Mode - waf[cisWAFGroupModifiedRulesCount] = *i.ModifiedRulesCount - waf[cisWAFGroupRulesCount] = *i.RulesCount - wafGroups = append(wafGroups, waf) - } - d.SetId(dataSourceIBMCISWAFGroupID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFGroupPackageID, packageID) - d.Set(cisWAFGroups, wafGroups) - return nil -} - -func dataSourceIBMCISWAFGroupID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_waf_packages.go b/ibm/data_source_ibm_cis_waf_packages.go deleted file mode 100644 index 943e18da9..000000000 --- a/ibm/data_source_ibm_cis_waf_packages.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisWAFPackages = "waf_packages" -) - -func dataSourceIBMCISWAFPackages() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISWAFPackagesRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "DNS Zone CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS domain id", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFPackages: { - Type: schema.TypeList, - Description: "Collection of GLB Health check/monitor detail", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF package id", - }, - cisWAFPackageID: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage ID", - }, - cisWAFPackageName: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage name", - }, - cisWAFPackageDetectionMode: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage detection mode", - }, - cisWAFPackageDescription: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage description", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISWAFPackagesRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFPackageClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - - opt := cisClient.NewListWafPackagesOptions() - result, resp, err := cisClient.ListWafPackages(opt) - if err != nil { - log.Printf("Error listing waf packages detail: %s", resp) - return err - } - - packages := make([]interface{}, 0) - for _, instance := range result.Result { - packageDetail := make(map[string]interface{}, 0) - packageDetail["id"] = convertCisToTfThreeVar(*instance.ID, zoneID, crn) - packageDetail[cisWAFPackageID] = *instance.ID - packageDetail[cisWAFPackageName] = *instance.Name - packageDetail[cisWAFPackageDetectionMode] = *instance.DetectionMode - - if instance.Description != nil { - packageDetail[cisWAFPackageDescription] = *instance.Description - } - packages = append(packages, packageDetail) - } - d.SetId(dataSourceIBMCISWAFPackagesCheckID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFPackages, packages) - return nil -} - -func dataSourceIBMCISWAFPackagesCheckID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cis_waf_rules.go b/ibm/data_source_ibm_cis_waf_rules.go deleted file mode 100644 index 7ff3f1d22..000000000 --- a/ibm/data_source_ibm_cis_waf_rules.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const cisWAFRules = "waf_rules" - -func dataSourceIBMCISWAFRules() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCISWAFRuleRead, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS object id", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "CISzone - Domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFRulePackageID: { - Type: schema.TypeString, - Description: "WAF rule package id", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFRules: { - Type: schema.TypeList, - Description: "Collection of WAF Rules", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule id", - }, - cisWAFRuleID: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule id", - }, - cisWAFRulePackageID: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Package id", - }, - cisWAFRuleMode: { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF Rule mode", - }, - cisWAFRuleDesc: { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF Rule descriptions", - }, - cisWAFRulePriority: { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF Rule Priority", - }, - cisWAFRuleGroup: { - Type: schema.TypeList, - Computed: true, - Description: "CIS WAF Rule group", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisWAFRuleGroupID: { - Type: schema.TypeString, - Computed: true, - Description: "waf rule group id", - }, - cisWAFRuleGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "waf rule group name", - }, - }, - }, - }, - cisWAFRuleAllowedModes: { - Type: schema.TypeList, - Computed: true, - Description: "CIS WAF Rule allowed modes", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCISWAFRuleRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFRuleClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - packageID, _, _, _ := convertTfToCisThreeVar(d.Get(cisWAFRulePackageID).(string)) - - opt := cisClient.NewListWafRulesOptions(packageID) - opt.SetPage(1) - opt.SetPerPage(1000) - result, response, err := cisClient.ListWafRules(opt) - if err != nil { - log.Printf("List waf rules failed %s\n", response) - return err - } - rules := []interface{}{} - for _, i := range result.Result { - - groups := []interface{}{} - group := map[string]interface{}{} - group[cisWAFRuleGroupID] = *i.Group.ID - group[cisWAFRuleGroupName] = *i.Group.Name - groups = append(groups, group) - - rule := map[string]interface{}{} - rule["id"] = convertCisToTfFourVar(*i.ID, *i.PackageID, zoneID, crn) - rule[cisWAFRuleID] = *i.ID - rule[cisWAFRulePackageID] = *i.PackageID - rule[cisWAFRuleMode] = *i.Mode - rule[cisWAFRuleDesc] = *i.Description - rule[cisWAFRulePriority] = *i.Priority - rule[cisWAFRuleGroup] = groups - rule[cisWAFRuleAllowedModes] = flattenStringList(i.AllowedModes) - - rules = append(rules, rule) - } - d.SetId(dataSourceIBMCISWAFRulesID(d)) - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFRulePackageID, packageID) - d.Set(cisWAFRules, rules) - return nil -} - -func dataSourceIBMCISWAFRulesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_cm_catalog.go b/ibm/data_source_ibm_cm_catalog.go deleted file mode 100644 index 1e724833d..000000000 --- a/ibm/data_source_ibm_cm_catalog.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func dataSourceIBMCmCatalog() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMCmCatalogRead, - - Schema: map[string]*schema.Schema{ - "catalog_identifier": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "ID for catalog", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of catalog, offering or vpe.", - }, - "label": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display Name in the requested language.", - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description in the requested language.", - }, - "catalog_icon_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL for an icon associated with this catalog.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of tags associated with this catalog.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url for this specific catalog.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "CRN associated with the catalog.", - }, - "offerings_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL path to offerings.", - }, - "resource_group_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource Group ID", - }, - }, - } -} - -func dataSourceIBMCmCatalogRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return diag.FromErr(err) - } - - getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} - - getCatalogOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) - - catalog, response, err := catalogManagementClient.GetCatalogWithContext(context, getCatalogOptions) - if err != nil { - log.Printf("[DEBUG] GetCatalogWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*catalog.ID) - if err = d.Set("label", catalog.Label); err != nil { - return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) - } - if err = d.Set("short_description", catalog.ShortDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) - } - if err = d.Set("catalog_icon_url", catalog.CatalogIconURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_icon_url: %s", err)) - } - if err = d.Set("tags", catalog.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - if err = d.Set("url", catalog.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) - } - if err = d.Set("crn", catalog.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("offerings_url", catalog.OfferingsURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting offerings_url: %s", err)) - } - if err = d.Set("kind", catalog.Kind); err != nil { - return diag.FromErr(fmt.Errorf("Error setting kind: %s", err)) - } - if err = d.Set("resource_group_id", catalog.ResourceGroupID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) - } - - return nil -} diff --git a/ibm/data_source_ibm_cm_catalog_test.go b/ibm/data_source_ibm_cm_catalog_test.go deleted file mode 100644 index bea991e05..000000000 --- a/ibm/data_source_ibm_cm_catalog_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "os" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCmCatalogDataSource(t *testing.T) { - ResourceGroupID := os.Getenv("CATMGMT_RESOURCE_GROUP_ID") - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmCatalogDataSourceConfig(ResourceGroupID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "label"), - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "crn"), - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "kind"), - resource.TestCheckResourceAttrSet("ibm_cm_catalog.cm_catalog", "resource_group_id"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCmCatalogDataSourceConfigDefault(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "label"), - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "crn"), - resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog_data", "kind"), - resource.TestCheckResourceAttrSet("ibm_cm_catalog.cm_catalog", "resource_group_id"), - ), - }, - }, - }) -} - -func testAccCheckIBMCmCatalogDataSourceConfig(resourceGroupID string) string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_datasource_catalog" - short_description = "testing terraform provider with catalog" - resource_group_id = "%s" - } - - data "ibm_cm_catalog" "cm_catalog_data" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - } - `, resourceGroupID) -} - -func testAccCheckIBMCmCatalogDataSourceConfigDefault() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_datasource_catalog" - short_description = "testing terraform provider with catalog" - } - - data "ibm_cm_catalog" "cm_catalog_data" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - } - `) -} diff --git a/ibm/data_source_ibm_cm_offering.go b/ibm/data_source_ibm_cm_offering.go deleted file mode 100644 index 6557d2b59..000000000 --- a/ibm/data_source_ibm_cm_offering.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func dataSourceIBMCmOffering() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMCmOfferingRead, - - Schema: map[string]*schema.Schema{ - "catalog_identifier": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Catalog identifier.", - ForceNew: true, - }, - "offering_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The id of the catalog containing this offering.", - ForceNew: true, - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url for this specific offering.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn for this specific offering.", - }, - "label": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display Name in the requested language.", - ForceNew: true, - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The programmatic name of this offering.", - }, - "offering_icon_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL for an icon associated with this offering.", - }, - "offering_docs_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL for an additional docs with this offering.", - }, - "offering_support_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL to be displayed in the Consumption UI for getting support on this offering.", - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Short description in the requested language.", - }, - "long_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Long description in the requested language.", - }, - "permit_request_ibm_public_publish": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is it permitted to request publishing to IBM or Public.", - }, - "ibm_publish_approved": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if this offering has been approved for use by all IBMers.", - }, - "public_publish_approved": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if this offering has been approved for use by all IBM Cloud users.", - }, - "public_original_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The original offering CRN that this publish entry came from.", - }, - "publish_public_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the public catalog entry of this offering.", - }, - "portal_approval_record": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The portal's approval record ID.", - }, - "portal_ui_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The portal UI URL.", - }, - "catalog_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The id of the catalog containing this offering.", - }, - "catalog_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the catalog.", - }, - "disclaimer": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A disclaimer for this offering.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Determine if this offering should be displayed in the Consumption UI.", - }, - "repo_info": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Repository info for offerings.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "token": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Token for private repos.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Public or enterprise GitHub.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMCmOfferingRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return diag.FromErr(err) - } - - getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} - - getOfferingOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) - getOfferingOptions.SetOfferingID(d.Get("offering_id").(string)) - - offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) - if err != nil { - log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*offering.ID) - if err = d.Set("url", offering.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) - } - if err = d.Set("crn", offering.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("label", offering.Label); err != nil { - return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) - } - if err = d.Set("name", offering.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("offering_icon_url", offering.OfferingIconURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting offering_icon_url: %s", err)) - } - if err = d.Set("offering_docs_url", offering.OfferingDocsURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting offering_docs_url: %s", err)) - } - if err = d.Set("offering_support_url", offering.OfferingSupportURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting offering_support_url: %s", err)) - } - if err = d.Set("short_description", offering.ShortDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) - } - if err = d.Set("long_description", offering.LongDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) - } - if err = d.Set("permit_request_ibm_public_publish", offering.PermitRequestIBMPublicPublish); err != nil { - return diag.FromErr(fmt.Errorf("Error setting permit_request_ibm_public_publish: %s", err)) - } - if err = d.Set("ibm_publish_approved", offering.IBMPublishApproved); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ibm_publish_approved: %s", err)) - } - if err = d.Set("public_publish_approved", offering.PublicPublishApproved); err != nil { - return diag.FromErr(fmt.Errorf("Error setting public_publish_approved: %s", err)) - } - if err = d.Set("public_original_crn", offering.PublicOriginalCRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting public_original_crn: %s", err)) - } - if err = d.Set("publish_public_crn", offering.PublishPublicCRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting publish_public_crn: %s", err)) - } - if err = d.Set("portal_approval_record", offering.PortalApprovalRecord); err != nil { - return diag.FromErr(fmt.Errorf("Error setting portal_approval_record: %s", err)) - } - if err = d.Set("portal_ui_url", offering.PortalUIURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting portal_ui_url: %s", err)) - } - if err = d.Set("catalog_id", offering.CatalogID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) - } - if err = d.Set("catalog_name", offering.CatalogName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_name: %s", err)) - } - if err = d.Set("disclaimer", offering.Disclaimer); err != nil { - return diag.FromErr(fmt.Errorf("Error setting disclaimer: %s", err)) - } - if err = d.Set("hidden", offering.Hidden); err != nil { - return diag.FromErr(fmt.Errorf("Error setting hidden: %s", err)) - } - - if offering.RepoInfo != nil { - repoInfoMap := dataSourceOfferingRepoInfoToMap(*offering.RepoInfo) - if err = d.Set("repo_info", []map[string]interface{}{repoInfoMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting repo_info %s", err)) - } - } - - return nil -} - -func dataSourceOfferingRepoInfoToMap(repoInfoItem catalogmanagementv1.RepoInfo) (repoInfoMap map[string]interface{}) { - repoInfoMap = map[string]interface{}{} - - if repoInfoItem.Token != nil { - repoInfoMap["token"] = repoInfoItem.Token - } - if repoInfoItem.Type != nil { - repoInfoMap["type"] = repoInfoItem.Type - } - - return repoInfoMap -} diff --git a/ibm/data_source_ibm_cm_offering_instance.go b/ibm/data_source_ibm_cm_offering_instance.go deleted file mode 100644 index 3f74b9202..000000000 --- a/ibm/data_source_ibm_cm_offering_instance.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func dataSourceIBMCmOfferingInstance() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMCmOfferingInstanceRead, - - Schema: map[string]*schema.Schema{ - "instance_identifier": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID for this instance", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "url reference to this object.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "platform CRN for this instance.", - }, - "_rev": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cloudant Revision for this instance", - }, - "label": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "the label for this instance.", - }, - "catalog_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Catalog ID this instance was created from.", - }, - "offering_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Offering ID this instance was created from.", - }, - "kind_format": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "the format this instance has (helm, operator, ova...).", - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The version this instance was installed from (not version id).", - }, - "cluster_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cluster ID.", - }, - "cluster_region": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cluster region (e.g., us-south).", - }, - "cluster_namespaces": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of target namespaces to install into.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "cluster_all_namespaces": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "designate to install into all namespaces.", - }, - "schematics_workspace_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "id of the schematics workspace, for offerings installed through schematics", - }, - "resource_group_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "id of the resource group", - }, - "install_plan": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "install plan for the subscription of the operator- can be either Automatic or Manual. Required for operator bundles", - }, - "channel": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "channel to target for the operator subscription. Required for operator bundles", - }, - }, - } -} - -func dataSourceIBMCmOfferingInstanceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return diag.FromErr(err) - } - - getOfferingInstanceOptions := &catalogmanagementv1.GetOfferingInstanceOptions{} - - getOfferingInstanceOptions.SetInstanceIdentifier(d.Get("instance_identifier").(string)) - - offeringInstance, response, err := catalogManagementClient.GetOfferingInstanceWithContext(context, getOfferingInstanceOptions) - if err != nil { - log.Printf("[DEBUG] GetOfferingInstanceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*offeringInstance.ID) - - if err = d.Set("url", offeringInstance.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) - } - if err = d.Set("crn", offeringInstance.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("_rev", offeringInstance.Rev); err != nil { - return diag.FromErr(fmt.Errorf("Error setting _rev: %s", err)) - } - if err = d.Set("label", offeringInstance.Label); err != nil { - return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) - } - if err = d.Set("catalog_id", offeringInstance.CatalogID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) - } - if err = d.Set("offering_id", offeringInstance.OfferingID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting offering_id: %s", err)) - } - if err = d.Set("kind_format", offeringInstance.KindFormat); err != nil { - return diag.FromErr(fmt.Errorf("Error setting kind_format: %s", err)) - } - if err = d.Set("version", offeringInstance.Version); err != nil { - return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) - } - if err = d.Set("cluster_id", offeringInstance.ClusterID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cluster_id: %s", err)) - } - if err = d.Set("cluster_region", offeringInstance.ClusterRegion); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cluster_region: %s", err)) - } - if err = d.Set("cluster_namespaces", offeringInstance.ClusterNamespaces); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cluster_namespaces: %s", err)) - } - if err = d.Set("cluster_all_namespaces", offeringInstance.ClusterAllNamespaces); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cluster_all_namespaces: %s", err)) - } - if err = d.Set("schematics_workspace_id", offeringInstance.SchematicsWorkspaceID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting schematics_workspace_id: %s", err)) - } - if err = d.Set("resource_group_id", offeringInstance.ResourceGroupID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) - } - if err = d.Set("install_plan", offeringInstance.InstallPlan); err != nil { - return diag.FromErr(fmt.Errorf("Error setting install_plan: %s", err)) - } - if err = d.Set("channel", offeringInstance.Channel); err != nil { - return diag.FromErr(fmt.Errorf("Error setting channel: %s", err)) - } - - return nil -} diff --git a/ibm/data_source_ibm_cm_offering_test.go b/ibm/data_source_ibm_cm_offering_test.go deleted file mode 100644 index 1eac914ac..000000000 --- a/ibm/data_source_ibm_cm_offering_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCmOfferingDataSource(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmOfferingDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering_data", "crn"), - resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering_data", "label"), - ), - }, - }, - }) -} - -func testAccCheckIBMCmOfferingDataSourceConfig() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_data_offering_catalog" - short_description = "testing terraform provider with catalog" - } - - resource "ibm_cm_offering" "cm_offering" { - catalog_id = ibm_cm_catalog.cm_catalog.id - label = "tf_test_offering" - tags = ["dev_ops", "target_roks", "operator"] - } - - data "ibm_cm_offering" "cm_offering_data" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - offering_id = ibm_cm_offering.cm_offering.id - } - `) -} diff --git a/ibm/data_source_ibm_cm_version.go b/ibm/data_source_ibm_cm_version.go deleted file mode 100644 index 4069b9a88..000000000 --- a/ibm/data_source_ibm_cm_version.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func dataSourceIBMCmVersion() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMCmVersionRead, - - Schema: map[string]*schema.Schema{ - "version_loc_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Catalog identifier.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version's CRN.", - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version of content type.", - }, - "sha": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "hash of the content.", - }, - "catalog_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Catalog ID.", - }, - "repo_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Content's repo URL.", - }, - "source_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Content's source URL (e.g git repo).", - }, - "tgz_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "File used to on-board this version.", - }, - }, - } -} - -func dataSourceIBMCmVersionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return diag.FromErr(err) - } - - getVersionOptions := &catalogmanagementv1.GetVersionOptions{} - - getVersionOptions.SetVersionLocID(d.Get("version_loc_id").(string)) - - offering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) - version := offering.Kinds[0].Versions[0] - - if err != nil { - log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*version.VersionLocator) - if err = d.Set("crn", version.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("version", version.Version); err != nil { - return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) - } - if err = d.Set("sha", version.Sha); err != nil { - return diag.FromErr(fmt.Errorf("Error setting sha: %s", err)) - } - if err = d.Set("catalog_id", version.CatalogID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) - } - if err = d.Set("repo_url", version.RepoURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting repo_url: %s", err)) - } - if err = d.Set("source_url", version.SourceURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_url: %s", err)) - } - if err = d.Set("tgz_url", version.TgzURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tgz_url: %s", err)) - } - - return nil -} diff --git a/ibm/data_source_ibm_cm_version_test.go b/ibm/data_source_ibm_cm_version_test.go deleted file mode 100644 index d5b502d75..000000000 --- a/ibm/data_source_ibm_cm_version_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCmVersionDataSource(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmVersionDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version_data", "crn"), - resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version_data", "repo_url"), - ), - }, - }, - }) -} - -func testAccCheckIBMCmVersionDataSourceConfig() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_data_version_catalog" - short_description = "testing terraform provider with catalog" - } - - resource "ibm_cm_offering" "cm_offering" { - catalog_id = ibm_cm_catalog.cm_catalog.id - label = "tf_test_offering" - tags = ["dev_ops", "target_roks", "operator"] - } - - resource "ibm_cm_version" "cm_version" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - offering_id = ibm_cm_offering.cm_offering.id - zipurl = "https://raw.githubusercontent.com/operator-framework/community-operators/master/community-operators/cockroachdb/5.0.3/manifests/cockroachdb.clusterserviceversion.yaml" - } - - data "ibm_cm_version" "cm_version_data" { - version_loc_id = ibm_cm_version.cm_version.id - } - `) -} diff --git a/ibm/data_source_ibm_container_bind_service.go b/ibm/data_source_ibm_container_bind_service.go deleted file mode 100644 index 232480ef2..000000000 --- a/ibm/data_source_ibm_container_bind_service.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMContainerBindService() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMContainerBindServiceRead, - - Schema: map[string]*schema.Schema{ - "cluster_name_id": { - Type: schema.TypeString, - Required: true, - Description: "Cluster name or ID", - }, - "service_instance_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ConflictsWith: []string{"service_instance_name"}, - Description: "Service instance ID", - }, - "service_instance_name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ConflictsWith: []string{"service_instance_id"}, - Description: "serivice instance name", - }, - "namespace_id": { - Type: schema.TypeString, - Required: true, - Description: "namespace ID", - }, - "service_key_name": { - Type: schema.TypeString, - Computed: true, - Description: "Key info", - }, - }, - } -} - -func dataSourceIBMContainerBindServiceRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() - if err != nil { - return err - } - - clusterNameID := d.Get("cluster_name_id").(string) - namespaceID := d.Get("namespace_id").(string) - var serviceInstanceNameID string - if serviceInstanceName, ok := d.GetOk("service_instance_name"); ok { - serviceInstanceNameID = serviceInstanceName.(string) - } else if serviceInstanceID, ok := d.GetOk("service_instance_id"); ok { - serviceInstanceNameID = serviceInstanceID.(string) - } else { - return fmt.Errorf("Please set either service_instance_name or service_instance_id") - } - - targetEnv, err := getClusterTargetHeader(d, meta) - if err != nil { - return err - } - - boundService, err := csClient.Clusters().FindServiceBoundToCluster(clusterNameID, serviceInstanceNameID, namespaceID, targetEnv) - if err != nil { - return err - } - d.Set("namespace_id", boundService.Namespace) - d.Set("service_instance_name", boundService.ServiceName) - d.Set("service_instance_id", boundService.ServiceID) - d.Set("service_key_name", boundService.ServiceKeyName) - d.SetId(fmt.Sprintf("%s/%s/%s", clusterNameID, serviceInstanceNameID, namespaceID)) - return nil -} diff --git a/ibm/data_source_ibm_container_cluster_config.go b/ibm/data_source_ibm_container_cluster_config.go deleted file mode 100644 index 75e27e37d..000000000 --- a/ibm/data_source_ibm_container_cluster_config.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "path/filepath" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - homedir "github.com/mitchellh/go-homedir" - - v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" - "github.com/IBM-Cloud/bluemix-go/helpers" -) - -func dataSourceIBMContainerClusterConfig() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMContainerClusterConfigRead, - - Schema: map[string]*schema.Schema{ - - "org_guid": { - Description: "The bluemix organization guid this cluster belongs to", - Type: schema.TypeString, - Optional: true, - Deprecated: "This field is deprecated", - }, - "space_guid": { - Description: "The bluemix space guid this cluster belongs to", - Type: schema.TypeString, - Optional: true, - Deprecated: "This field is deprecated", - }, - "account_guid": { - Description: "The bluemix account guid this cluster belongs to", - Type: schema.TypeString, - Optional: true, - Deprecated: "This field is deprecated", - }, - "region": { - Type: schema.TypeString, - Optional: true, - Description: "The cluster region", - Deprecated: "This field is deprecated", - }, - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - "cluster_name_id": { - Description: "The name/id of the cluster", - Type: schema.TypeString, - Required: true, - }, - "config_dir": { - Description: "The directory where the cluster config to be downloaded. Default is home directory ", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "download": { - Description: "If set to false will not download the config, otherwise they are downloaded each time but onto the same path for a given cluster name/id", - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - "admin": { - Description: "If set to true will download the config for admin", - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "network": { - Description: "If set to true will download the Calico network config with the Admin config", - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "config_file_path": { - Description: "The absolute path to the kubernetes config yml file ", - Type: schema.TypeString, - Computed: true, - }, - "calico_config_file_path": { - Description: "The absolute path to the calico network config file ", - Type: schema.TypeString, - Computed: true, - }, - "admin_key": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - "admin_certificate": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - "ca_certificate": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - "host": { - Type: schema.TypeString, - Computed: true, - }, - "token": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - }, - } -} - -func dataSourceIBMContainerClusterConfigRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - csAPI := csClient.Clusters() - name := d.Get("cluster_name_id").(string) - download := d.Get("download").(bool) - admin := d.Get("admin").(bool) - configDir := d.Get("config_dir").(string) - network := d.Get("network").(bool) - - clusterId := "Cluster_Config_" + name - ibmMutexKV.Lock(clusterId) - defer ibmMutexKV.Unlock(clusterId) - - if len(configDir) == 0 { - configDir, err = homedir.Dir() - if err != nil { - return fmt.Errorf("Error fetching homedir: %s", err) - } - } - configDir, _ = filepath.Abs(configDir) - - var configPath string - if !download { - log.Println("Skipping download of the cluster config", "Going to check if it already exists") - expectedDir := v1.ComputeClusterConfigDir(configDir, name, admin) - configPath = filepath.Join(expectedDir, "config.yml") - if !helpers.FileExists(configPath) { - return fmt.Errorf(`Couldn't find the cluster config at expected path %s. Please set "download" to true to download the new config`, configPath) - } - d.Set("config_file_path", configPath) - - } else { - targetEnv, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return err - } - if network { - // For the Network config we need to gather the certs so we must override the admin value - var calicoConfigFilePath string - var clusterKeyDetails v1.ClusterKeyInfo - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - calicoConfigFilePath, clusterKeyDetails, err = csAPI.StoreConfigDetail(name, configDir, admin || true, network, targetEnv) - if err != nil { - log.Printf("[DEBUG] Failed to fetch cluster config err %s", err) - if strings.Contains(err.Error(), "Could not login to openshift account runtime error:") { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - calicoConfigFilePath, clusterKeyDetails, err = csAPI.StoreConfigDetail(name, configDir, admin || true, network, targetEnv) - } - if err != nil { - return fmt.Errorf("Error downloading the cluster config [%s]: %s", name, err) - } - d.Set("calico_config_file_path", calicoConfigFilePath) - d.Set("admin_key", clusterKeyDetails.AdminKey) - d.Set("admin_certificate", clusterKeyDetails.Admin) - d.Set("ca_certificate", clusterKeyDetails.ClusterCACertificate) - d.Set("host", clusterKeyDetails.Host) - d.Set("token", clusterKeyDetails.Token) - d.Set("config_file_path", clusterKeyDetails.FilePath) - - } else { - var clusterKeyDetails v1.ClusterKeyInfo - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - clusterKeyDetails, err = csAPI.GetClusterConfigDetail(name, configDir, admin, targetEnv) - if err != nil { - log.Printf("[DEBUG] Failed to fetch cluster config err %s", err) - if strings.Contains(err.Error(), "Could not login to openshift account runtime error:") { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - clusterKeyDetails, err = csAPI.GetClusterConfigDetail(name, configDir, admin, targetEnv) - } - if err != nil { - return fmt.Errorf("Error downloading the cluster config [%s]: %s", name, err) - } - d.Set("admin_key", clusterKeyDetails.AdminKey) - d.Set("admin_certificate", clusterKeyDetails.Admin) - d.Set("ca_certificate", clusterKeyDetails.ClusterCACertificate) - d.Set("host", clusterKeyDetails.Host) - d.Set("token", clusterKeyDetails.Token) - d.Set("config_file_path", clusterKeyDetails.FilePath) - } - } - - d.SetId(name) - d.Set("config_dir", configDir) - return nil -} diff --git a/ibm/data_source_ibm_container_nlb_dns.go b/ibm/data_source_ibm_container_nlb_dns.go deleted file mode 100644 index 38a2945e0..000000000 --- a/ibm/data_source_ibm_container_nlb_dns.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMContainerNLBDNS() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMContainerNLBDNSRead, - - Schema: map[string]*schema.Schema{ - "cluster": { - Type: schema.TypeString, - Required: true, - Description: "A unique name of the cluster", - }, - "nlb_config": { - Type: schema.TypeList, - Computed: true, - Description: "List of nlb config of cluster", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "secret_name": { - Type: schema.TypeString, - Computed: true, - Description: "Name of the secret.", - }, - "secret_status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of Secret.", - }, - "cluster": { - Type: schema.TypeString, - Computed: true, - Description: "Cluster Id.", - }, - "dns_type": { - Type: schema.TypeString, - Computed: true, - Description: "Type of DNS.", - }, - "lb_hostname": { - Type: schema.TypeString, - Computed: true, - Description: "Host Name of load Balancer.", - }, - "nlb_ips": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: " NLB IPs.", - }, - "nlb_sub_domain": { - Type: schema.TypeString, - Computed: true, - Description: "NLB Sub-Domain.", - }, - "type": { - Type: schema.TypeString, - Computed: true, - Description: " Nlb Type.", - }, - "secret_namespace": { - Type: schema.TypeString, - Computed: true, - Description: "Namespace of Secret.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMContainerNLBDNSRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - name := d.Get("cluster").(string) - - kubeClient, err := meta.(ClientSession).VpcContainerAPI() - if err != nil { - return diag.FromErr(err) - } - - nlbData, err := kubeClient.NlbDns().GetNLBDNSList(name) - if err != nil || nlbData == nil || len(nlbData) < 1 { - return diag.FromErr(fmt.Errorf("[ERROR] Error Listing NLB DNS (%s): %s", name, err)) - } - d.SetId(name) - d.Set("cluster", name) - d.Set("nlb_config", flattenNlbConfigs(nlbData)) - return nil -} -func flattenNlbConfigs(nlbData []containerv2.NlbVPCListConfig) []map[string]interface{} { - nlbConfigList := make([]map[string]interface{}, 0) - for _, n := range nlbData { - nlbConfig := make(map[string]interface{}) - nlbConfig["secret_name"] = n.SecretName - nlbConfig["secret_status"] = n.SecretStatus - c := n.Nlb - nlbConfig["cluster"] = c.Cluster - nlbConfig["dns_type"] = c.DnsType - nlbConfig["lb_hostname"] = c.LbHostname - nlbConfig["nlb_ips"] = c.NlbIPArray - nlbConfig["nlb_sub_domain"] = c.NlbSubdomain - nlbConfig["secret_namespace"] = c.SecretNamespace - nlbConfig["type"] = c.Type - nlbConfigList = append(nlbConfigList, nlbConfig) - } - - return nlbConfigList -} diff --git a/ibm/data_source_ibm_container_storage_attachment.go b/ibm/data_source_ibm_container_storage_attachment.go deleted file mode 100644 index 002b3fc43..000000000 --- a/ibm/data_source_ibm_container_storage_attachment.go +++ /dev/null @@ -1,92 +0,0 @@ -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMContainerVpcWorkerVolumeAttachmentRead, - - Schema: map[string]*schema.Schema{ - "volume_attachment_id": { - Type: schema.TypeString, - Required: true, - Description: "The volume attachment ID", - }, - - "cluster": { - Type: schema.TypeString, - Required: true, - Description: "Cluster name or ID", - }, - - "worker": { - Type: schema.TypeString, - Required: true, - Description: "Worker node ID", - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "ID of the resource group.", - }, - - "volume": { - Type: schema.TypeString, - Computed: true, - Description: "Volume ID", - }, - - "volume_attachment_name": { - Type: schema.TypeString, - Computed: true, - Description: "Volume attachment name", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Volume attachment status", - }, - "volume_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of volume", - }, - }, - } -} - -func dataSourceIBMContainerVpcWorkerVolumeAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - wpClient, err := meta.(ClientSession).VpcContainerAPI() - if err != nil { - return diag.FromErr(err) - } - - workersAPI := wpClient.Workers() - target, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return diag.FromErr(err) - } - - clusterNameorID := d.Get("cluster").(string) - volumeAttachmentID := d.Get("volume_attachment_id").(string) - workerID := d.Get("worker").(string) - - volume, err := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, target) - if err != nil { - return diag.FromErr(err) - } - d.Set("volume_attachment_name", volume.Name) - d.Set("status", volume.Status) - d.Set("volume_type", volume.Type) - d.SetId(fmt.Sprintf("%s/%s/%s", clusterNameorID, workerID, volumeAttachmentID)) - return nil -} diff --git a/ibm/data_source_ibm_container_vpc_cluster_test.go b/ibm/data_source_ibm_container_vpc_cluster_test.go deleted file mode 100644 index ae14758a2..000000000 --- a/ibm/data_source_ibm_container_vpc_cluster_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMContainerVPCClusterDataSource_basic(t *testing.T) { - name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerVPCClusterDataSource(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster.testacc_ds_cluster", "id"), - resource.TestCheckResourceAttrSet("data.ibm_container_cluster_config.testacc_ds_cluster", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMContainerVPCClusterDataSource(name string) string { - return testAccCheckIBMContainerVpcClusterBasic(name) + fmt.Sprintf(` -data "ibm_container_vpc_cluster" "testacc_ds_cluster" { - cluster_name_id = ibm_container_vpc_cluster.cluster.id -} -data "ibm_container_cluster_config" "testacc_ds_cluster" { - cluster_name_id = ibm_container_vpc_cluster.cluster.id - } -`) -} diff --git a/ibm/data_source_ibm_container_vpc_cluster_worker.go b/ibm/data_source_ibm_container_vpc_cluster_worker.go deleted file mode 100644 index ea9055b4a..000000000 --- a/ibm/data_source_ibm_container_vpc_cluster_worker.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMContainerVPCClusterWorker() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMContainerVPCClusterWorkerRead, - - Schema: map[string]*schema.Schema{ - "worker_id": { - Description: "ID of the worker", - Type: schema.TypeString, - Required: true, - }, - "cluster_name_id": { - Description: "Name or ID of the cluster", - Type: schema.TypeString, - Required: true, - }, - "flavor": { - Description: "flavor of the worker", - Type: schema.TypeString, - Computed: true, - }, - "kube_version": { - Description: "kube version of the worker", - Type: schema.TypeString, - Computed: true, - }, - "state": { - Description: "State of the worker", - Type: schema.TypeString, - Computed: true, - }, - "pool_id": { - Description: "worker pool id", - Type: schema.TypeString, - Computed: true, - }, - "pool_name": { - Description: "worker pool name", - Type: schema.TypeString, - Computed: true, - }, - "network_interfaces": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cidr": { - Type: schema.TypeString, - Computed: true, - }, - "ip_address": { - Type: schema.TypeString, - Computed: true, - }, - "subnet_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", - }, - }, - } -} - -func dataSourceIBMContainerVPCClusterWorkerRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - - targetEnv, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return err - } - - wrkAPI := csClient.Workers() - workerID := d.Get("worker_id").(string) - clusterID := d.Get("cluster_name_id").(string) - - workerFields, err := wrkAPI.Get(clusterID, workerID, targetEnv) - if err != nil { - return fmt.Errorf("Error retrieving worker: %s", err) - } - - d.SetId(workerFields.ID) - d.Set("flavor", workerFields.Flavor) - d.Set("kube_version", workerFields.KubeVersion.Actual) - d.Set("state", workerFields.Health.State) - d.Set("pool_id", workerFields.PoolID) - d.Set("pool_name", workerFields.PoolName) - d.Set("network_interfaces", flattenNetworkInterfaces(workerFields.NetworkInterfaces)) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") - - return nil -} diff --git a/ibm/data_source_ibm_container_vpc_cluster_worker_test.go b/ibm/data_source_ibm_container_vpc_cluster_worker_test.go deleted file mode 100644 index 2af60e7a6..000000000 --- a/ibm/data_source_ibm_container_vpc_cluster_worker_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMContainerVPCClusterWorkerDataSource_basic(t *testing.T) { - name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerVPCClusterWorkerDataSourceConfig(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster_worker.testacc_ds_worker", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMContainerVPCClusterWorkerDataSourceConfig(name string) string { - return testAccCheckIBMVpcContainerWorkerPoolBasic(name) + fmt.Sprintf(` - data "ibm_container_vpc_cluster" "testacc_ds_cluster" { - cluster_name_id = ibm_container_vpc_cluster.cluster.id - } - data "ibm_container_vpc_cluster_worker" "testacc_ds_worker" { - cluster_name_id = ibm_container_vpc_cluster.cluster.id - worker_id = data.ibm_container_vpc_cluster.testacc_ds_cluster.workers[0] - } -`) -} diff --git a/ibm/data_source_ibm_container_vpc_worker_pool.go b/ibm/data_source_ibm_container_vpc_worker_pool.go deleted file mode 100644 index 61d9243d3..000000000 --- a/ibm/data_source_ibm_container_vpc_worker_pool.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMContainerVpcClusterWorkerPool() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMContainerVpcClusterWorkerPoolRead, - Schema: map[string]*schema.Schema{ - "cluster": { - Type: schema.TypeString, - Required: true, - Description: "Cluster name", - }, - "worker_pool_name": { - Type: schema.TypeString, - Required: true, - Description: "worker pool name", - }, - "flavor": { - Type: schema.TypeString, - Computed: true, - }, - "zones": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - - "subnet_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "labels": { - Type: schema.TypeMap, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - }, - "vpc_id": { - Type: schema.TypeString, - Computed: true, - }, - "worker_count": { - Type: schema.TypeInt, - Computed: true, - }, - "isolation": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} -func dataSourceIBMContainerVpcClusterWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { - wpClient, err := meta.(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - clusterName := d.Get("cluster").(string) - workerPoolName := d.Get("worker_pool_name").(string) - workerPoolsAPI := wpClient.WorkerPools() - targetEnv, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return err - } - - workerPool, err := workerPoolsAPI.GetWorkerPool(clusterName, workerPoolName, targetEnv) - if err != nil { - return err - } - - var zones = make([]map[string]interface{}, 0) - for _, zone := range workerPool.Zones { - for _, subnet := range zone.Subnets { - zoneInfo := map[string]interface{}{ - "name": zone.ID, - "subnet_id": subnet.ID, - } - zones = append(zones, zoneInfo) - } - } - d.Set("worker_pool_name", workerPool.PoolName) - d.Set("flavor", workerPool.Flavor) - d.Set("worker_count", workerPool.WorkerCount) - d.Set("provider", workerPool.Provider) - d.Set("labels", workerPool.Labels) - d.Set("zones", zones) - d.Set("cluster", clusterName) - d.Set("vpc_id", workerPool.VpcID) - d.Set("isolation", workerPool.Isolation) - d.Set("resource_group_id", targetEnv.ResourceGroup) - d.SetId(workerPool.ID) - return nil -} diff --git a/ibm/data_source_ibm_container_vpc_worker_pool_test.go b/ibm/data_source_ibm_container_vpc_worker_pool_test.go deleted file mode 100644 index 3554765c0..000000000 --- a/ibm/data_source_ibm_container_vpc_worker_pool_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMContainerVPCClusterWorkerPoolDataSource_basic(t *testing.T) { - name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfig(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster_worker_pool.testacc_ds_worker_pool", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfig(name string) string { - return testAccCheckIBMVpcContainerWorkerPoolBasic(name) + fmt.Sprintf(` - data "ibm_container_vpc_cluster_worker_pool" "testacc_ds_worker_pool" { - cluster = "${ibm_container_vpc_cluster.cluster.id}" - worker_pool_name = "${ibm_container_vpc_worker_pool.test_pool.worker_pool_name}" - } -`) -} diff --git a/ibm/data_source_ibm_cos_bucket.go b/ibm/data_source_ibm_cos_bucket.go deleted file mode 100644 index fcc45f66f..000000000 --- a/ibm/data_source_ibm_cos_bucket.go +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "regexp" - "strings" - "time" - - "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" - "github.com/IBM/ibm-cos-sdk-go/aws" - "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" - token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" - "github.com/IBM/ibm-cos-sdk-go/aws/session" - "github.com/IBM/ibm-cos-sdk-go/service/s3" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var bucketTypes = []string{"single_site_location", "region_location", "cross_region_location"} - -func dataSourceIBMCosBucket() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMCosBucketRead, - - Schema: map[string]*schema.Schema{ - "bucket_name": { - Type: schema.TypeString, - Required: true, - }, - "bucket_type": { - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue(bucketTypes), - Required: true, - }, - "bucket_region": { - Type: schema.TypeString, - Required: true, - }, - "resource_instance_id": { - Type: schema.TypeString, - Required: true, - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "direct"}), - Description: "public or private", - Default: "public", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "CRN of resource instance", - }, - "key_protect": { - Type: schema.TypeString, - Computed: true, - Description: "CRN of the key you want to use data at rest encryption", - }, - "single_site_location": { - Type: schema.TypeString, - Computed: true, - }, - "region_location": { - Type: schema.TypeString, - Computed: true, - }, - "cross_region_location": { - Type: schema.TypeString, - Computed: true, - }, - "storage_class": { - Type: schema.TypeString, - Computed: true, - }, - "s3_endpoint_public": { - Type: schema.TypeString, - Computed: true, - Description: "Public endpoint for the COS bucket", - }, - "s3_endpoint_private": { - Type: schema.TypeString, - Computed: true, - Description: "Private endpoint for the COS bucket", - }, - "allowed_ip": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of IPv4 or IPv6 addresses ", - }, - "activity_tracking": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_data_events": { - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, all object read events will be sent to Activity Tracker.", - }, - "write_data_events": { - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, all object write events will be sent to Activity Tracker.", - }, - "activity_tracker_crn": { - Type: schema.TypeString, - Computed: true, - Description: "The instance of Activity Tracker that will receive object event data", - }, - }, - }, - }, - "metrics_monitoring": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "usage_metrics_enabled": { - Type: schema.TypeBool, - Computed: true, - Description: "Usage metrics will be sent to the monitoring service.", - }, - "request_metrics_enabled": { - Type: schema.TypeBool, - Computed: true, - Description: "Request metrics will be sent to the monitoring service.", - }, - "metrics_monitoring_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", - }, - }, - }, - }, - "archive_rule": { - Type: schema.TypeList, - Computed: true, - Description: "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rule_id": { - Type: schema.TypeString, - Computed: true, - }, - "enable": { - Type: schema.TypeBool, - Computed: true, - Description: "Enable or disable an archive rule for a bucket", - }, - "days": { - Type: schema.TypeInt, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "expire_rule": { - Type: schema.TypeList, - Computed: true, - Description: "Enable configuration expire_rule to COS Bucket", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rule_id": { - Type: schema.TypeString, - Computed: true, - }, - "enable": { - Type: schema.TypeBool, - Computed: true, - Description: "Enable or disable an archive rule for a bucket", - }, - "days": { - Type: schema.TypeInt, - Computed: true, - Description: "Specifies the number of days when the specific rule action takes effect.", - }, - "prefix": { - Type: schema.TypeString, - Computed: true, - Description: "The rule applies to any objects with keys that match this prefix", - }, - }, - }, - }, - "retention_rule": { - Type: schema.TypeList, - Computed: true, - Description: "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": { - Type: schema.TypeInt, - Computed: true, - Description: "If an object is stored in the bucket without specifying a custom retention period.", - }, - "maximum": { - Type: schema.TypeInt, - Computed: true, - Description: "Maximum duration of time an object can be kept unmodified in the bucket.", - }, - "minimum": { - Type: schema.TypeInt, - Computed: true, - Description: "Minimum duration of time an object must be kept unmodified in the bucket", - }, - "permanent": { - Type: schema.TypeBool, - Computed: true, - Description: "Enable or disable the permanent retention policy on the bucket", - }, - }, - }, - }, - "object_versioning": { - Type: schema.TypeList, - Computed: true, - Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enable": { - Type: schema.TypeBool, - Computed: true, - Description: "Enable or suspend the versioning for objects in the bucket", - }, - }, - }, - }, - "hard_quota": { - Type: schema.TypeInt, - Computed: true, - Description: "sets a maximum amount of storage (in bytes) available for a bucket", - }, - }, - } -} - -func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error { - var s3Conf *aws.Config - rsConClient, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - bucketName := d.Get("bucket_name").(string) - serviceID := d.Get("resource_instance_id").(string) - bucketType := d.Get("bucket_type").(string) - bucketRegion := d.Get("bucket_region").(string) - var endpointType = d.Get("endpoint_type").(string) - apiEndpoint, apiEndpointPrivate, directApiEndpoint := selectCosApi(bucketLocationConvert(bucketType), bucketRegion) - if endpointType == "private" { - apiEndpoint = apiEndpointPrivate - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) - if apiEndpoint == "" { - return fmt.Errorf("The endpoint doesn't exists for given location %s and endpoint type %s", bucketRegion, endpointType) - } - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - headInput := &s3.HeadBucketInput{ - Bucket: aws.String(bucketName), - } - err = s3Client.WaitUntilBucketExists(headInput) - if err != nil { - return fmt.Errorf("failed waiting for bucket %s to be created, %v", - bucketName, err) - } - bucketLocationInput := &s3.GetBucketLocationInput{ - Bucket: aws.String(bucketName), - } - bucketLocationConstraint, err := s3Client.GetBucketLocation(bucketLocationInput) - if err != nil { - return err - } - bLocationConstraint := *bucketLocationConstraint.LocationConstraint - - singleSiteLocationRegex, err := regexp.Compile("^[a-z]{3}[0-9][0-9]-[a-z]{4,8}$") - if err != nil { - return err - } - regionLocationRegex, err := regexp.Compile("^[a-z]{2}-[a-z]{2,5}-[a-z]{4,8}$") - if err != nil { - return err - } - crossRegionLocationRegex, err := regexp.Compile("^[a-z]{2}-[a-z]{4,8}$") - if err != nil { - return err - } - - if singleSiteLocationRegex.MatchString(bLocationConstraint) { - d.Set("single_site_location", strings.Split(bLocationConstraint, "-")[0]) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) - } - if regionLocationRegex.MatchString(bLocationConstraint) { - d.Set("region_location", fmt.Sprintf("%s-%s", strings.Split(bLocationConstraint, "-")[0], strings.Split(bLocationConstraint, "-")[1])) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[2]) - } - if crossRegionLocationRegex.MatchString(bLocationConstraint) { - d.Set("cross_region_location", strings.Split(bLocationConstraint, "-")[0]) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) - } - - head, err := s3Client.HeadBucket(headInput) - if err != nil { - return err - } - bucketID := fmt.Sprintf("%s:%s:%s:meta:%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName, bucketLocationConvert(bucketType), bucketRegion, endpointType) - d.SetId(bucketID) - d.Set("key_protect", head.IBMSSEKPCrkId) - bucketCRN := fmt.Sprintf("%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName) - d.Set("crn", bucketCRN) - d.Set("resource_instance_id", serviceID) - d.Set("s3_endpoint_public", apiEndpoint) - d.Set("s3_endpoint_private", apiEndpointPrivate) - - getBucketConfigOptions := &resourceconfigurationv1.GetBucketConfigOptions{ - Bucket: &bucketName, - } - - sess, err := meta.(ClientSession).CosConfigV1API() - if err != nil { - return err - } - - if endpointType == "private" { - sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") - } - bucketPtr, response, err := sess.GetBucketConfig(getBucketConfigOptions) - - if err != nil { - return fmt.Errorf("Error in getting bucket info rule: %s\n%s", err, response) - } - - if bucketPtr != nil { - - if bucketPtr.Firewall != nil { - d.Set("allowed_ip", flattenStringList(bucketPtr.Firewall.AllowedIp)) - } - if bucketPtr.ActivityTracking != nil { - d.Set("activity_tracking", flattenActivityTrack(bucketPtr.ActivityTracking)) - } - if bucketPtr.MetricsMonitoring != nil { - d.Set("metrics_monitoring", flattenMetricsMonitor(bucketPtr.MetricsMonitoring)) - } - if bucketPtr.HardQuota != nil { - d.Set("hard_quota", bucketPtr.HardQuota) - } - - } - - // Read the lifecycle configuration (archive) - - gInput := &s3.GetBucketLifecycleConfigurationInput{ - Bucket: aws.String(bucketName), - } - - lifecycleptr, err := s3Client.GetBucketLifecycleConfiguration(gInput) - - if (err != nil && !strings.Contains(err.Error(), "NoSuchLifecycleConfiguration: The lifecycle configuration does not exist")) && (err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied")) { - return err - } - - if lifecycleptr != nil { - if len(lifecycleptr.Rules) > 0 { - archiveRules := archiveRuleGet(lifecycleptr.Rules) - expireRules := expireRuleGet(lifecycleptr.Rules) - if len(archiveRules) > 0 { - d.Set("archive_rule", archiveRules) - } - if len(expireRules) > 0 { - d.Set("expire_rule", expireRules) - } - } - } - - // Read the retention policy - retentionInput := &s3.GetBucketProtectionConfigurationInput{ - Bucket: aws.String(bucketName), - } - retentionptr, err := s3Client.GetBucketProtectionConfiguration(retentionInput) - - if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { - return err - } - - if retentionptr != nil { - retentionRules := retentionRuleGet(retentionptr.ProtectionConfiguration) - if len(retentionRules) > 0 { - d.Set("retention_rule", retentionRules) - } - } - - // Get the object Versioning - versionInput := &s3.GetBucketVersioningInput{ - Bucket: aws.String(bucketName), - } - versionPtr, err := s3Client.GetBucketVersioning(versionInput) - - if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { - return err - } - if versionPtr != nil { - versioningData := flattenCosObejctVersioning(versionPtr) - if len(versioningData) > 0 { - d.Set("object_versioning", versioningData) - } - } - - return nil -} - -func bucketLocationConvert(locationtype string) string { - if locationtype == "cross_region_location" { - return "crl" - } - if locationtype == "region_location" { - return "rl" - } - if locationtype == "single_site_location" { - return "crl" - } - return "" -} diff --git a/ibm/data_source_ibm_database.go b/ibm/data_source_ibm_database.go deleted file mode 100644 index d7308ed4e..000000000 --- a/ibm/data_source_ibm_database.go +++ /dev/null @@ -1,743 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "encoding/base64" - "fmt" - "io/ioutil" - "net/url" - "path/filepath" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/models" -) - -func dataSourceIBMDatabaseInstance() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMDatabaseInstanceRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Resource instance name for example, my Database instance", - Type: schema.TypeString, - Required: true, - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "The id of the resource group in which the Database instance is present", - }, - - "location": { - Description: "The location or the region in which the Database instance exists", - Type: schema.TypeString, - Optional: true, - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Unique identifier of resource instance", - }, - - "service": { - Description: "The name of the Cloud Database service", - Type: schema.TypeString, - Optional: true, - }, - "plan": { - Description: "The plan type of the Database instance", - Type: schema.TypeString, - Computed: true, - }, - - "status": { - Description: "The resource instance status", - Type: schema.TypeString, - Computed: true, - }, - "adminuser": { - Description: "The admin user id for the instance", - Type: schema.TypeString, - Computed: true, - }, - "adminpassword": { - Description: "The admin user id for the instance", - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - "version": { - Description: "The database version to provision if specified", - Type: schema.TypeString, - Computed: true, - }, - "members_memory_allocation_mb": { - Description: "Memory allocation required for cluster", - Type: schema.TypeInt, - Computed: true, - }, - "members_disk_allocation_mb": { - Description: "Disk allocation required for cluster", - Type: schema.TypeInt, - Computed: true, - }, - "platform_options": { - Description: "Platform-specific options for this deployment.r", - Type: schema.TypeMap, - Computed: true, - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - "users": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Description: "User name", - Type: schema.TypeString, - Computed: true, - }, - "password": { - Description: "User password", - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - }, - }, - }, - "cert_file_path": { - Description: "The absolute path to certificate PEM file", - Type: schema.TypeString, - Computed: true, - }, - "connectionstrings": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Description: "User name", - Type: schema.TypeString, - Computed: true, - }, - "composed": { - Description: "Connection string", - Type: schema.TypeString, - Computed: true, - }, - "scheme": { - Description: "DB scheme", - Type: schema.TypeString, - Computed: true, - }, - "certname": { - Description: "Certificate Name", - Type: schema.TypeString, - Computed: true, - }, - "certbase64": { - Description: "Certificate in base64 encoding", - Type: schema.TypeString, - Computed: true, - }, - "bundlename": { - Description: "Cassandra Bundle Name", - Type: schema.TypeString, - Computed: true, - }, - "bundlebase64": { - Description: "Cassandra base64 encoding", - Type: schema.TypeString, - Computed: true, - }, - "password": { - Description: "Password", - Type: schema.TypeString, - Computed: true, - }, - "queryoptions": { - Description: "DB query options", - Type: schema.TypeString, - Computed: true, - }, - "database": { - Description: "DB name", - Type: schema.TypeString, - Computed: true, - }, - "path": { - Description: "DB path", - Type: schema.TypeString, - Computed: true, - }, - "hosts": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "hostname": { - Description: "DB host name", - Type: schema.TypeString, - Computed: true, - }, - "port": { - Description: "DB port", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - "whitelist": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "address": { - Description: "Whitelist IP address in CIDR notation", - Type: schema.TypeString, - Computed: true, - }, - "description": { - Description: "Unique white list description", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "groups": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "group_id": { - Description: "Scaling group name", - Type: schema.TypeString, - Computed: true, - }, - "count": { - Description: "Count of scaling groups for the instance", - Type: schema.TypeInt, - Computed: true, - }, - "memory": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The units memory is allocated in.", - }, - "allocation_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The current memory allocation for a group instance", - }, - "minimum_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum memory size for a group instance", - }, - "step_size_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The step size memory increases or decreases in.", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Is the memory size adjustable.", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can memory scale down as well as up.", - }, - }, - }, - }, - "cpu": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The .", - }, - "allocation_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The current cpu allocation count", - }, - "minimum_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum number of cpus allowed", - }, - "step_size_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The number of CPUs allowed to step up or down by", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Are the number of CPUs adjustable", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can the number of CPUs be scaled down as well as up", - }, - }, - }, - }, - "disk": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The units disk is allocated in", - }, - "allocation_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The current disk allocation", - }, - "minimum_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum disk size allowed", - }, - "step_size_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The step size disk increases or decreases in", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Is the disk size adjustable", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can the disk size be scaled down as well as up", - }, - }, - }, - }, - }, - }, - }, - "auto_scaling": { - Type: schema.TypeList, - Description: "ICD Auto Scaling", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "disk": { - Type: schema.TypeList, - Description: "Disk Auto Scaling", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "capacity_enabled": { - Description: "Auto Scaling Scalar: Capacity Enabled", - Type: schema.TypeBool, - Computed: true, - }, - "free_space_remaining_percent": { - Description: "Auto Scaling Scalar: Capacity Free Space Remaining Percent", - Type: schema.TypeInt, - Computed: true, - }, - "free_space_less_than_percent": { - Description: "Auto Scaling Scalar: Capacity Free Space Less Than Percent", - Type: schema.TypeInt, - Computed: true, - }, - "io_enabled": { - Description: "Auto Scaling Scalar: IO Utilization Enabled", - Type: schema.TypeBool, - Computed: true, - }, - - "io_over_period": { - Description: "Auto Scaling Scalar: IO Utilization Over Period", - Type: schema.TypeString, - Computed: true, - }, - "io_above_percent": { - Description: "Auto Scaling Scalar: IO Utilization Above Percent", - Type: schema.TypeInt, - Computed: true, - }, - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_mb_per_member": { - Description: "Auto Scaling Rate: Limit mb per member", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_count_per_member": { - Description: "Auto Scaling Rate: Limit count per number", - Type: schema.TypeInt, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "memory": { - Type: schema.TypeList, - Description: "Memory Auto Scaling", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "io_enabled": { - Description: "Auto Scaling Scalar: IO Utilization Enabled", - Type: schema.TypeBool, - Computed: true, - }, - - "io_over_period": { - Description: "Auto Scaling Scalar: IO Utilization Over Period", - Type: schema.TypeString, - Computed: true, - }, - "io_above_percent": { - Description: "Auto Scaling Scalar: IO Utilization Above Percent", - Type: schema.TypeInt, - Computed: true, - }, - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_mb_per_member": { - Description: "Auto Scaling Rate: Limit mb per member", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_count_per_member": { - Description: "Auto Scaling Rate: Limit count per number", - Type: schema.TypeInt, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "cpu": { - Type: schema.TypeList, - Description: "CPU Auto Scaling", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_mb_per_member": { - Description: "Auto Scaling Rate: Limit mb per member", - Type: schema.TypeInt, - Computed: true, - }, - "rate_limit_count_per_member": { - Description: "Auto Scaling Rate: Limit count per number", - Type: schema.TypeInt, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} - -func dataSourceIBMDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerAPIV2() - if err != nil { - return err - } - rsAPI := rsConClient.ResourceServiceInstanceV2() - name := d.Get("name").(string) - - rsInstQuery := controllerv2.ServiceInstanceQuery{ - Name: name, - } - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rsInstQuery.ResourceGroupID = rsGrpID.(string) - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInstQuery.ResourceGroupID = defaultRg - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - if service, ok := d.GetOk("service"); ok { - - serviceOff, err := rsCatRepo.FindByName(service.(string), true) - if err != nil { - return fmt.Errorf("Error retrieving database offering: %s", err) - } - - rsInstQuery.ServiceID = serviceOff[0].ID - } - - var instances []models.ServiceInstanceV2 - - instances, err = rsAPI.ListInstances(rsInstQuery) - if err != nil { - return err - } - var filteredInstances []models.ServiceInstanceV2 - var location string - - if loc, ok := d.GetOk("location"); ok { - location = loc.(string) - for _, instance := range instances { - if getLocation(instance) == location { - filteredInstances = append(filteredInstances, instance) - } - } - } else { - filteredInstances = instances - } - - if len(filteredInstances) == 0 { - return fmt.Errorf("No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or database", name) - } - - var instance models.ServiceInstanceV2 - - if len(filteredInstances) > 1 { - return fmt.Errorf( - "More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or database", name) - } - instance = filteredInstances[0] - - d.SetId(instance.ID) - - err = GetTags(d, meta) - if err != nil { - return fmt.Errorf( - "Error on get of resource instance (%s) tags: %s", d.Id(), err) - } - - d.Set("name", instance.Name) - d.Set("status", instance.State) - d.Set("resource_group_id", instance.ResourceGroupID) - d.Set("location", instance.RegionID) - d.Set("guid", instance.Guid) - - serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - d.Set("service", serviceOff) - - servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - - d.Set(ResourceName, instance.Name) - d.Set(ResourceCRN, instance.Crn.String()) - d.Set(ResourceStatus, instance.State) - d.Set(ResourceGroupName, instance.ResourceGroupName) - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/services/"+url.QueryEscape(instance.Crn.String())) - - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return fmt.Errorf("Error getting database client settings: %s", err) - } - - icdId := EscapeUrlParm(instance.ID) - cdb, err := icdClient.Cdbs().GetCdb(icdId) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return fmt.Errorf("The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err) - } - return fmt.Errorf("Error getting database config for: %s with error %s\n", icdId, err) - } - d.Set("adminuser", cdb.AdminUser) - d.Set("version", cdb.Version) - if &cdb.PlatformOptions != nil { - platformOptions := map[string]interface{}{ - "key_protect_key_id": cdb.PlatformOptions.KeyProtectKey, - "disk_encryption_key_crn": cdb.PlatformOptions.DiskENcryptionKeyCrn, - "backup_encryption_key_crn": cdb.PlatformOptions.BackUpEncryptionKeyCrn, - } - d.Set("platform_options", platformOptions) - } - - groupList, err := icdClient.Groups().GetGroups(icdId) - if err != nil { - return fmt.Errorf("Error getting database groups: %s", err) - } - d.Set("groups", flattenIcdGroups(groupList)) - d.Set("members_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb) - d.Set("members_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb) - - autoSclaingGroup, err := icdClient.AutoScaling().GetAutoScaling(icdId, "member") - if err != nil { - return fmt.Errorf("Error getting database groups: %s", err) - } - d.Set("auto_scaling", flattenICDAutoScalingGroup(autoSclaingGroup)) - - whitelist, err := icdClient.Whitelists().GetWhitelist(icdId) - if err != nil { - return fmt.Errorf("Error getting database whitelist: %s", err) - } - d.Set("whitelist", flattenWhitelist(whitelist)) - - connectionEndpoint := "public" - if instance.Parameters != nil { - if endpoint, ok := instance.Parameters["service-endpoints"]; ok { - if endpoint == "private" { - connectionEndpoint = "private" - } - } - - } - - var connectionStrings []CsEntry - //ICD does not implement a GetUsers API. Users populated from tf configuration. - tfusers := d.Get("users").(*schema.Set) - users := expandUsers(tfusers) - user := icdv4.User{ - UserName: cdb.AdminUser, - } - users = append(users, user) - for _, user := range users { - userName := user.UserName - csEntry, err := getConnectionString(d, userName, connectionEndpoint, meta) - if err != nil { - return fmt.Errorf("Error getting user connection string for user (%s): %s", userName, err) - } - connectionStrings = append(connectionStrings, csEntry) - } - d.Set("connectionstrings", flattenConnectionStrings(connectionStrings)) - - connStr := connectionStrings[0] - certFile, err := filepath.Abs(connStr.CertName + ".pem") - if err != nil { - return fmt.Errorf("Error generating certificate file path: %s", err) - } - content, err := base64.StdEncoding.DecodeString(connStr.CertBase64) - if err != nil { - return fmt.Errorf("Error decoding certificate content: %s", err) - } - if err := ioutil.WriteFile(certFile, content, 0644); err != nil { - return fmt.Errorf("Error writing certificate to file: %s", err) - } - d.Set("cert_file_path", certFile) - - return nil -} diff --git a/ibm/data_source_ibm_dns_domain.go b/ibm/data_source_ibm_dns_domain.go deleted file mode 100644 index c2738ed3a..000000000 --- a/ibm/data_source_ibm_dns_domain.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/softlayer/softlayer-go/filter" - "github.com/softlayer/softlayer-go/services" -) - -func dataSourceIBMDNSDomain() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMDNSDomainRead, - - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Description: "A domain record's internal identifier", - Type: schema.TypeInt, - Computed: true, - }, - - "name": &schema.Schema{ - Description: "The name of the domain", - Type: schema.TypeString, - Required: true, - }, - }, - } -} - -func dataSourceIBMDNSDomainRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetAccountService(sess) - - name := d.Get("name").(string) - - names, err := service. - Filter(filter.Build(filter.Path("domains.name").Eq(name))). - Mask("id,name"). - GetDomains() - - if err != nil { - return fmt.Errorf("Error retrieving domain: %s", err) - } - - if len(names) == 0 { - return fmt.Errorf("No domain found with name [%s]", name) - } - - d.SetId(fmt.Sprintf("%d", *names[0].Id)) - return nil -} diff --git a/ibm/data_source_ibm_en_subscription.go b/ibm/data_source_ibm_en_subscription.go deleted file mode 100644 index b7fee3636..000000000 --- a/ibm/data_source_ibm_en_subscription.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" -) - -func dataSourceIBMEnSubscription() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMEnSubscriptionRead, - - Schema: map[string]*schema.Schema{ - "instance_guid": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier for IBM Cloud Event Notifications instance.", - }, - "subscription_id": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier for result.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription name.", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription description.", - }, - "destination_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of destination.", - }, - "destination_id": { - Type: schema.TypeString, - Computed: true, - Description: "The destination ID.", - }, - "destination_name": { - Type: schema.TypeString, - Computed: true, - Description: "The destination name.", - }, - "topic_id": { - Type: schema.TypeString, - Computed: true, - Description: "Topic ID.", - }, - "topic_name": { - Type: schema.TypeString, - Computed: true, - Description: "Topic name.", - }, - "from": { - Type: schema.TypeString, - Computed: true, - Description: "From Email ID (it will be displayed only in case of smtp_ibm destination type).", - }, - "attributes": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "to": { - Type: schema.TypeList, - Computed: true, - Description: "The phone number to send the SMS to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "recipient_selection": { - Type: schema.TypeString, - Computed: true, - Description: "The recipient selection method.", - }, - "add_notification_payload": { - Type: schema.TypeBool, - Computed: true, - Description: "Whether to add the notification payload to the email.", - }, - "reply_to": { - Type: schema.TypeString, - Computed: true, - Description: "The email address to reply to.", - }, - "signing_enabled": { - Type: schema.TypeBool, - Computed: true, - Description: "Signing webhook attributes.", - }, - }, - }, - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "Last updated time.", - }, - }, - } -} - -func dataSourceIBMEnSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - getSubscriptionOptions := &en.GetSubscriptionOptions{} - - getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) - getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) - - result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) - - if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) - } - - if result.Description != nil { - if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) - } - } - if err = d.Set("updated_at", result.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) - } - - if result.DestinationType != nil { - if err = d.Set("destination_type", result.DestinationType); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_type: %s", err)) - } - } - - if err = d.Set("destination_id", result.DestinationID); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_id: %s", err)) - } - - if err = d.Set("destination_name", result.DestinationName); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_name: %s", err)) - } - - if err = d.Set("topic_id", result.TopicID); err != nil { - return diag.FromErr(fmt.Errorf("error setting topic_id: %s", err)) - } - - if err = d.Set("topic_name", result.TopicName); err != nil { - return diag.FromErr(fmt.Errorf("error setting topic_name: %s", err)) - } - - if result.Attributes != nil { - if err = d.Set("attributes", enSubscriptionFlattenAttributes(result.Attributes)); err != nil { - return diag.FromErr(fmt.Errorf("error setting attributes %s", err)) - } - } - - if result.From != nil { - if err = d.Set("from", result.From); err != nil { - return diag.FromErr(fmt.Errorf("error setting from %s", err)) - } - } - - return nil -} - -func enSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - - attributes := result.(*en.SubscriptionAttributes) - - finalMap := enSubscriptionToMap(attributes) - finalList = append(finalList, finalMap) - - return finalList -} - -func enSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { - attributeMap = map[string]interface{}{} - - if attributeItem.AddNotificationPayload != nil { - attributeMap["add_notification_payload"] = attributeItem.AddNotificationPayload - } - - if attributeItem.RecipientSelection != nil { - attributeMap["recipient_selection"] = attributeItem.RecipientSelection - } - - if attributeItem.ReplyTo != nil { - attributeMap["reply_to"] = attributeItem.ReplyTo - } - - if attributeItem.To != nil { - attributeMap["to"] = attributeItem.To - } - - if attributeItem.SigningEnabled != nil { - attributeMap["signing_enabled"] = attributeItem.SigningEnabled - } - - return attributeMap -} diff --git a/ibm/data_source_ibm_en_topic.go b/ibm/data_source_ibm_en_topic.go deleted file mode 100644 index eecff6dd9..000000000 --- a/ibm/data_source_ibm_en_topic.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" -) - -func dataSourceIBMEnTopic() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMEnTopicRead, - - Schema: map[string]*schema.Schema{ - "instance_guid": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier for IBM Cloud Event Notifications instance.", - }, - "topic_id": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier for Topic.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Name of the topic.", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Description of the topic.", - }, - "source_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Number of sources.", - }, - "sources": { - Type: schema.TypeList, - Computed: true, - Description: "List of sources.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of the source.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Name of the source.", - }, - "rules": { - Type: schema.TypeList, - Computed: true, - Description: "List of rules.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Computed: true, - Description: "Whether the rule is enabled or not.", - }, - "event_type_filter": { - Type: schema.TypeString, - Computed: true, - Description: "Event type filter.", - }, - "notification_filter": { - Type: schema.TypeString, - Computed: true, - Description: "Notification filter.", - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "Last time the topic was updated.", - }, - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Autogenerated rule ID.", - }, - }, - }, - }, - }, - }, - }, - "subscription_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Number of subscriptions.", - }, - "subscriptions": { - Type: schema.TypeList, - Computed: true, - Description: "List of subscriptions.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription ID.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription name.", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription description.", - }, - "destination_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of destination.", - }, - "destination_id": { - Type: schema.TypeString, - Computed: true, - Description: "The destination ID.", - }, - "topic_id": { - Type: schema.TypeString, - Computed: true, - Description: "Topic ID.", - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "Last updated time.", - }, - }, - }, - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "Last time the topic was updated.", - }, - }, - } -} - -func dataSourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - options := &en.GetTopicOptions{} - - options.SetInstanceID(d.Get("instance_guid").(string)) - options.SetID(d.Get("topic_id").(string)) - - result, response, err := enClient.GetTopicWithContext(context, options) - - if err != nil { - return diag.FromErr(fmt.Errorf("GetTopicWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) - - d.Set("topic_id", options.ID) - - if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) - } - - if result.Description != nil { - if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) - } - } - - if err = d.Set("updated_at", result.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) - } - - if err = d.Set("source_count", intValue(result.SourceCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting source_count: %s", err)) - } - - if err = d.Set("subscription_count", intValue(result.SubscriptionCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_count: %s", err)) - } - - if result.Sources != nil { - err = d.Set("sources", dataSourceTopicFlattenSources(result.Sources)) - if err != nil { - return diag.FromErr(fmt.Errorf("error setting sources %s", err)) - } - } - - if result.Subscriptions != nil { - err = d.Set("subscriptions", enFlattenSubscriptions(result.Subscriptions)) - if err != nil { - return diag.FromErr(fmt.Errorf("error setting subscriptions %s", err)) - } - } - - return nil -} - -func dataSourceTopicFlattenSources(result []en.TopicSourcesItem) (sources []map[string]interface{}) { - sources = []map[string]interface{}{} - - for _, sourcesItem := range result { - sources = append(sources, dataSourceTopicSourcesToMap(sourcesItem)) - } - - return sources -} - -func dataSourceTopicSourcesToMap(sourcesItem en.TopicSourcesItem) (sourcesMap map[string]interface{}) { - sourcesMap = map[string]interface{}{} - - if sourcesItem.ID != nil { - sourcesMap["id"] = sourcesItem.ID - } - if sourcesItem.Name != nil { - sourcesMap["name"] = sourcesItem.Name - } - - if sourcesItem.Rules != nil { - rulesList := []map[string]interface{}{} - for _, rulesItem := range sourcesItem.Rules { - rulesList = append(rulesList, enRulesToMap(rulesItem)) - } - sourcesMap["rules"] = rulesList - } - - return sourcesMap -} - -func enRulesToMap(rulesItem en.RulesGet) (rulesMap map[string]interface{}) { - rulesMap = map[string]interface{}{} - - if rulesItem.ID != nil { - rulesMap["id"] = rulesItem.ID - } - - if rulesItem.Enabled != nil { - rulesMap["enabled"] = rulesItem.Enabled - } - - if rulesItem.EventTypeFilter != nil { - rulesMap["event_type_filter"] = rulesItem.EventTypeFilter - } - - if rulesItem.NotificationFilter != nil { - rulesMap["notification_filter"] = rulesItem.NotificationFilter - } - - if rulesItem.UpdatedAt != nil { - rulesMap["updated_at"] = rulesItem.UpdatedAt - } - - return rulesMap -} - -func enFlattenSubscriptions(subscriptionList []en.SubscriptionListItem) (subscriptions []map[string]interface{}) { - subscriptions = []map[string]interface{}{} - - for _, subscription := range subscriptionList { - subscriptions = append(subscriptions, enSubscriptionsToMap(subscription)) - } - - return subscriptions -} - -func enSubscriptionsToMap(subscription en.SubscriptionListItem) (subscriptionsMap map[string]interface{}) { - subscriptionsMap = map[string]interface{}{} - - if subscription.ID != nil { - subscriptionsMap["id"] = subscription.ID - } - - if subscription.Name != nil { - subscriptionsMap["name"] = subscription.Name - } - - if subscription.Description != nil { - subscriptionsMap["description"] = subscription.Description - } - - if subscription.UpdatedAt != nil { - subscriptionsMap["updated_at"] = subscription.UpdatedAt - } - - if subscription.DestinationType != nil { - subscriptionsMap["destination_type"] = subscription.DestinationType - } - - if subscription.DestinationID != nil { - subscriptionsMap["destination_id"] = subscription.DestinationID - } - - if subscription.TopicID != nil { - subscriptionsMap["topic_id"] = subscription.TopicID - } - - return subscriptionsMap -} diff --git a/ibm/data_source_ibm_iam_access_group.go b/ibm/data_source_ibm_iam_access_group.go deleted file mode 100644 index 30d738186..000000000 --- a/ibm/data_source_ibm_iam_access_group.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "log" - - "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMIAMAccessGroup() *schema.Resource { - return &schema.Resource{ - Read: dataIBMIAMAccessGroupRead, - Schema: map[string]*schema.Schema{ - "access_group_name": { - Type: schema.TypeString, - Optional: true, - Description: "Name of the access group", - }, - "groups": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "id": { - Type: schema.TypeString, - Computed: true, - }, - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the access group", - }, - "ibm_ids": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "iam_service_ids": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "rules": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - Description: "The name of the Rule", - }, - "expiration": { - Type: schema.TypeInt, - Computed: true, - Description: "The expiration in hours", - }, - "identity_provider": { - Type: schema.TypeString, - Computed: true, - Description: "The realm name or identity proivider url", - }, - "conditions": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "claim": { - Type: schema.TypeString, - Computed: true, - }, - "operator": { - Type: schema.TypeString, - Computed: true, - }, - "value": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "rule_id": { - Type: schema.TypeString, - Computed: true, - Description: "id of the rule", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataIBMIAMAccessGroupRead(d *schema.ResourceData, meta interface{}) error { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - userManagement, err := meta.(ClientSession).UserManagementAPI() - if err != nil { - return err - } - client := userManagement.UserInvite() - res, err := client.ListUsers(accountID) - if err != nil { - return err - } - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - - start := "" - allrecs := []iamidentityv1.ServiceID{} - var pg int64 = 100 - for { - listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ - AccountID: &userDetails.userAccount, - Pagesize: &pg, - } - if start != "" { - listServiceIDOptions.Pagetoken = &start - } - - serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) - } - start = GetNextIAM(serviceIDs.Next) - allrecs = append(allrecs, serviceIDs.Serviceids...) - if start == "" { - break - } - } - - listAccessGroupOption := iamAccessGroupsClient.NewListAccessGroupsOptions(accountID) - retreivedGroups, detailedResponse, err := iamAccessGroupsClient.ListAccessGroups(listAccessGroupOption) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving access groups: %s. API Response is: %s", err, detailedResponse) - } - - if len(retreivedGroups.Groups) == 0 { - return fmt.Errorf("[ERROR] No access group in account") - } - var agName string - var matchGroups []iamaccessgroupsv2.Group - if v, ok := d.GetOk("access_group_name"); ok { - agName = v.(string) - for _, grpData := range retreivedGroups.Groups { - if *grpData.Name == agName { - matchGroups = append(matchGroups, grpData) - } - } - } else { - matchGroups = retreivedGroups.Groups - } - if len(matchGroups) == 0 { - return fmt.Errorf("[ERROR] No Access Groups with name %s in Account", agName) - } - - grpMap := make([]map[string]interface{}, 0, len(matchGroups)) - - for _, grp := range matchGroups { - accessGroupMembersListOptions := iamAccessGroupsClient.NewListAccessGroupMembersOptions(*grp.ID) - members, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupMembers(accessGroupMembersListOptions) - if err != nil { - log.Printf("Error retrieving access group members: %s.API Response: %s", err, detailedResponse) - } - - accessGroupRulesListOptions := iamAccessGroupsClient.NewListAccessGroupRulesOptions(*grp.ID) - rules, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupRules(accessGroupRulesListOptions) - if err != nil { - log.Printf("Error retrieving access group rules: %s. API Response: %s", err, detailedResponse) - } - ibmID, serviceID := flattenMembersData(members.Members, res, allrecs) - - grpInstance := map[string]interface{}{ - "id": grp.ID, - "name": grp.Name, - "description": grp.Description, - "ibm_ids": ibmID, - "iam_service_ids": serviceID, - "rules": flattenAccessGroupRules(rules), - } - - grpMap = append(grpMap, grpInstance) - - } - - d.SetId(accountID) - d.Set("groups", grpMap) - d.Set("access_group_name", agName) - - return nil -} diff --git a/ibm/data_source_ibm_iam_api_key.go b/ibm/data_source_ibm_iam_api_key.go deleted file mode 100644 index 1ab7b158e..000000000 --- a/ibm/data_source_ibm_iam_api_key.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -func dataSourceIbmIamApiKey() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIbmIamApiKeyRead, - - Schema: map[string]*schema.Schema{ - "apikey_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Unique ID of the API key.", - }, - "entity_tag": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678'.", - }, - "locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "The API key cannot be changed if set to true.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the creation date in ISO format.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "IAM ID of the user or service which created the API key.", - }, - "modified_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the last modification date in ISO format.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the API key. The name is not checked for uniqueness. Therefore multiple names with the same value can exist. Access is done via the UUID of the API key.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The optional description of the API key. The 'description' property is only available if a description was provided during a create of an API key.", - }, - "iam_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The iam_id that this API key authenticates.", - }, - "account_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "ID of the account that this API key authenticates for.", - }, - }, - } -} - -func dataSourceIbmIamApiKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - getApiKeyOptions := &iamidentityv1.GetAPIKeyOptions{} - - getApiKeyOptions.SetID(d.Get("apikey_id").(string)) - - apiKey, response, err := iamIdentityClient.GetAPIKey(getApiKeyOptions) - if err != nil { - log.Printf("[DEBUG] GetApiKey failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*apiKey.ID) - - if err = d.Set("entity_tag", apiKey.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) - } - if err = d.Set("crn", apiKey.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("locked", apiKey.Locked); err != nil { - return diag.FromErr(fmt.Errorf("Error setting locked: %s", err)) - } - if err = d.Set("created_at", apiKey.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("created_by", apiKey.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) - } - if err = d.Set("modified_at", apiKey.ModifiedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) - } - if err = d.Set("name", apiKey.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", apiKey.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("iam_id", apiKey.IamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting iam_id: %s", err)) - } - if err = d.Set("account_id", apiKey.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) - } - - return nil -} diff --git a/ibm/data_source_ibm_iam_roles.go b/ibm/data_source_ibm_iam_roles.go deleted file mode 100644 index 5c8e64dcd..000000000 --- a/ibm/data_source_ibm_iam_roles.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func datasourceIBMIAMRole() *schema.Resource { - return &schema.Resource{ - Read: datasourceIBMIAMRoleRead, - - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Optional: true, - Description: "The Service Name", - ForceNew: true, - }, - "roles": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "description": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } - -} - -func datasourceIBMIAMRoleRead(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - var serviceName string - var customRoles []iampolicymanagementv1.CustomRole - var serviceRoles, systemRoles []iampolicymanagementv1.Role - - listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ - AccountID: &userDetails.userAccount, - } - - if service, ok := d.GetOk("service"); ok { - serviceName = service.(string) - listRoleOptions.ServiceName = &serviceName - } - roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) - if err != nil { - return err - } - customRoles = roleList.CustomRoles - serviceRoles = roleList.ServiceRoles - systemRoles = roleList.SystemRoles - - d.SetId(userDetails.userAccount) - - var roles []map[string]string - - roles = append(flattenRoleData(systemRoles, "platform"), append(flattenRoleData(serviceRoles, "service"), flattenCustomRoleData(customRoles, "custom")...)...) - - d.Set("roles", roles) - - return nil -} diff --git a/ibm/data_source_ibm_iam_service_id.go b/ibm/data_source_ibm_iam_service_id.go deleted file mode 100644 index f8f937352..000000000 --- a/ibm/data_source_ibm_iam_service_id.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMIAMServiceID() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMIAMServiceIDRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Name of the serviceID", - Type: schema.TypeString, - Required: true, - }, - - "service_ids": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - - "bound_to": { - Description: "bound to of the serviceID", - Type: schema.TypeString, - Computed: true, - Deprecated: "bound_to attribute in service_ids list has been deprecated", - }, - - "crn": { - Description: "CRN of the serviceID", - Type: schema.TypeString, - Computed: true, - }, - - "description": { - Description: "description of the serviceID", - Type: schema.TypeString, - Computed: true, - }, - - "version": { - Description: "Version of the serviceID", - Type: schema.TypeString, - Computed: true, - }, - - "locked": { - Description: "lock state of the serviceID", - Type: schema.TypeBool, - Computed: true, - }, - - "iam_id": { - Description: "The IAM ID of the serviceID", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIAMServiceIDRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get("name").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - - start := "" - allrecs := []iamidentityv1.ServiceID{} - var pg int64 = 100 - for { - listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ - AccountID: &userDetails.userAccount, - Pagesize: &pg, - Name: &name, - } - if start != "" { - listServiceIDOptions.Pagetoken = &start - } - - serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) - } - start = GetNextIAM(serviceIDs.Next) - allrecs = append(allrecs, serviceIDs.Serviceids...) - if start == "" { - break - } - } - if len(allrecs) == 0 { - return fmt.Errorf("[ERROR] No serviceID found with name [%s]", name) - - } - - serviceIDListMap := make([]map[string]interface{}, 0, len(allrecs)) - for _, serviceID := range allrecs { - l := map[string]interface{}{ - "id": serviceID.ID, - // "bound_to": serviceID.BoundTo, - "version": serviceID.EntityTag, - "description": serviceID.Description, - "crn": serviceID.CRN, - "locked": serviceID.Locked, - "iam_id": serviceID.IamID, - } - serviceIDListMap = append(serviceIDListMap, l) - } - d.SetId(name) - d.Set("service_ids", serviceIDListMap) - return nil -} diff --git a/ibm/data_source_ibm_iam_service_policy.go b/ibm/data_source_ibm_iam_service_policy.go deleted file mode 100644 index efa0bc821..000000000 --- a/ibm/data_source_ibm_iam_service_policy.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" -) - -// Data source to find all the policies for a serviceID -func dataSourceIBMIAMServicePolicy() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMIAMServicePolicyRead, - - Schema: map[string]*schema.Schema{ - "iam_service_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"iam_service_id", "iam_id"}, - Description: "UUID of ServiceID", - }, - "iam_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"iam_service_id", "iam_id"}, - Description: "IAM ID of ServiceID", - }, - "sort": { - Description: "Sort query for policies", - Type: schema.TypeString, - Optional: true, - }, - "policies": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "roles": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - "resources": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Computed: true, - Description: "Service name of the policy definition", - }, - "resource_instance_id": { - Type: schema.TypeString, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "ID of resource instance of the policy definition", - }, - "region": { - Type: schema.TypeString, - Computed: true, - Description: "Region of the policy definition", - }, - "resource_type": { - Type: schema.TypeString, - Computed: true, - Description: "Resource type of the policy definition", - }, - "resource": { - Type: schema.TypeString, - Computed: true, - Description: "Resource of the policy definition", - }, - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of the resource group.", - }, - }, - }, - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Description of the Policy", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) error { - - var iamID string - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - - serviceIDUUID := v.(string) - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ - ID: &serviceIDUUID, - } - serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) - } - iamID = *serviceID.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ - AccountID: core.StringPtr(userDetails.userAccount), - IamID: core.StringPtr(iamID), - Type: core.StringPtr("access"), - } - - if v, ok := d.GetOk("sort"); ok { - listPoliciesOptions.Sort = core.StringPtr(v.(string)) - } - - policyList, _, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) - policies := policyList.Policies - if err != nil { - return err - } - - servicePolicies := make([]map[string]interface{}, 0, len(policies)) - for _, policy := range policies { - roles := make([]string, len(policy.Roles)) - for i, role := range policy.Roles { - roles[i] = *role.DisplayName - } - resources := flattenPolicyResource(policy.Resources) - p := map[string]interface{}{ - "roles": roles, - "resources": resources, - } - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - p["id"] = fmt.Sprintf("%s/%s", serviceIDUUID, *policy.ID) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - p["id"] = fmt.Sprintf("%s/%s", iamID, *policy.ID) - } - if policy.Description != nil { - p["description"] = policy.Description - } - servicePolicies = append(servicePolicies, p) - } - - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - d.SetId(serviceIDUUID) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(iamID) - } - d.Set("policies", servicePolicies) - return nil -} diff --git a/ibm/data_source_ibm_iam_service_policy_test.go b/ibm/data_source_ibm_iam_service_policy_test.go deleted file mode 100644 index bbc26ebab..000000000 --- a/ibm/data_source_ibm_iam_service_policy_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMIAMServicePolicyDataSource_Basic(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyDataSourceConfig(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_iam_service_policy.testacc_ds_service_policy", "policies.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicyDataSource_Multiple_Policies(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyDataSourceMultiplePolicies(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_iam_service_policy.testacc_ds_service_policy", "policies.#", "2"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMServicePolicyDataSourceConfig(name string) string { - return fmt.Sprintf(` - -resource "ibm_iam_service_id" "serviceID" { - name = "%s" - description = "Service ID for test" -} - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_iam_service_policy" "testacc_ds_service_policy" { - iam_service_id = ibm_iam_service_policy.policy.iam_service_id -}`, name, name) - -} - -func testAccCheckIBMIAMServicePolicyDataSourceMultiplePolicies(name string) string { - return fmt.Sprintf(` - -resource "ibm_iam_service_id" "serviceID" { - name = "%s" - description = "Service ID for test" -} - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_resource_group" "group" { - is_default=true -} - -resource "ibm_iam_service_policy" "policy1" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } -} - - -data "ibm_iam_service_policy" "testacc_ds_service_policy" { - iam_service_id = ibm_iam_service_policy.policy.iam_service_id - sort = "id" -}`, name, name) - -} diff --git a/ibm/data_source_ibm_iam_trusted_profile.go b/ibm/data_source_ibm_iam_trusted_profile.go deleted file mode 100644 index 7c73e75dd..000000000 --- a/ibm/data_source_ibm_iam_trusted_profile.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -func dataSourceIBMIamTrustedProfile() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMIamTrustedProfileRead, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID of the trusted profile to get.", - }, - "entity_tag": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The optional description of the trusted profile. The 'description' property is only available if a description was provided during a create of a trusted profile.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the creation date in ISO format.", - }, - "modified_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the last modification date in ISO format.", - }, - "iam_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The iam_id of this trusted profile.", - }, - "account_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "ID of the account that this trusted profile belong to.", - }, - "ims_account_id": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "IMS acount ID of the trusted profile.", - }, - "ims_user_id": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "IMS user ID of the trusted profile.", - }, - "history": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "History of the trusted profile.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "timestamp": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Timestamp when the action was triggered.", - }, - "iam_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "IAM ID of the identity which triggered the action.", - }, - "iam_id_account": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Account of the identity which triggered the action.", - }, - "action": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action of the history entry.", - }, - "params": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Params of the history entry.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Message which summarizes the executed action.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIamTrustedProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - getProfileOptions := &iamidentityv1.GetProfileOptions{} - - getProfileOptions.SetProfileID(d.Get("profile_id").(string)) - - trustedProfile, response, err := iamIdentityClient.GetProfile(getProfileOptions) - if err != nil { - log.Printf("[DEBUG] GetProfile failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetProfile failed %s\n%s", err, response)) - } - - d.SetId(*trustedProfile.ID) - - if err = d.Set("entity_tag", trustedProfile.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) - } - if err = d.Set("crn", trustedProfile.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("name", trustedProfile.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", trustedProfile.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("created_at", dateTimeToString(trustedProfile.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("modified_at", dateTimeToString(trustedProfile.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) - } - if err = d.Set("iam_id", trustedProfile.IamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting iam_id: %s", err)) - } - if err = d.Set("account_id", trustedProfile.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) - } - if err = d.Set("ims_account_id", intValue(trustedProfile.ImsAccountID)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ims_account_id: %s", err)) - } - if err = d.Set("ims_user_id", intValue(trustedProfile.ImsUserID)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ims_user_id: %s", err)) - } - - err = d.Set("history", dataSourceTrustedProfileFlattenHistory(trustedProfile.History)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting history %s", err)) - } - - return nil -} - -func dataSourceTrustedProfileFlattenHistory(result []iamidentityv1.EnityHistoryRecord) (history []map[string]interface{}) { - for _, historyItem := range result { - history = append(history, dataSourceTrustedProfileHistoryToMap(historyItem)) - } - - return history -} - -func dataSourceTrustedProfileHistoryToMap(historyItem iamidentityv1.EnityHistoryRecord) (historyMap map[string]interface{}) { - historyMap = map[string]interface{}{} - - if historyItem.Timestamp != nil { - historyMap["timestamp"] = historyItem.Timestamp - } - if historyItem.IamID != nil { - historyMap["iam_id"] = historyItem.IamID - } - if historyItem.IamIDAccount != nil { - historyMap["iam_id_account"] = historyItem.IamIDAccount - } - if historyItem.Action != nil { - historyMap["action"] = historyItem.Action - } - if historyItem.Params != nil { - historyMap["params"] = historyItem.Params - } - if historyItem.Message != nil { - historyMap["message"] = historyItem.Message - } - - return historyMap -} diff --git a/ibm/data_source_ibm_iam_trusted_profile_claim_rule.go b/ibm/data_source_ibm_iam_trusted_profile_claim_rule.go deleted file mode 100644 index 73312205d..000000000 --- a/ibm/data_source_ibm_iam_trusted_profile_claim_rule.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -func dataSourceIBMIamTrustedProfileClaimRule() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMIamTrustedProfileClaimRuleRead, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID of the trusted profile.", - }, - "rule_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID of the claim rule to get.", - }, - "entity_tag": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "version of the claim rule.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the creation date in ISO format.", - }, - "modified_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the last modification date in ISO format.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The optional claim rule name.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the Calim rule, either 'Profile-SAML' or 'Profile-CR'.", - }, - "realm_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The realm name of the Idp this claim rule applies to.", - }, - "expiration": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Session expiration in seconds.", - }, - "cr_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA.", - }, - "conditions": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Conditions of this claim rule.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "claim": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The claim to evaluate against.", - }, - "operator": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The stringified JSON value that the claim is compared to using the operator.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIamTrustedProfileClaimRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - getClaimRuleOptions := &iamidentityv1.GetClaimRuleOptions{} - - getClaimRuleOptions.SetProfileID(d.Get("profile_id").(string)) - getClaimRuleOptions.SetRuleID(d.Get("rule_id").(string)) - - profileClaimRule, response, err := iamIdentityClient.GetClaimRule(getClaimRuleOptions) - if err != nil { - log.Printf("[DEBUG] GetClaimRule failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetClaimRule failed %s\n%s", err, response)) - } - d.SetId(fmt.Sprintf("%s/%s", *getClaimRuleOptions.ProfileID, *profileClaimRule.ID)) - if err = d.Set("entity_tag", profileClaimRule.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) - } - if err = d.Set("created_at", dateTimeToString(profileClaimRule.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("modified_at", dateTimeToString(profileClaimRule.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) - } - if err = d.Set("name", profileClaimRule.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("type", profileClaimRule.Type); err != nil { - return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) - } - if err = d.Set("realm_name", profileClaimRule.RealmName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting realm_name: %s", err)) - } - if err = d.Set("expiration", intValue(profileClaimRule.Expiration)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting expiration: %s", err)) - } - if err = d.Set("cr_type", profileClaimRule.CrType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cr_type: %s", err)) - } - - if profileClaimRule.Conditions != nil { - err = d.Set("conditions", dataSourceProfileClaimRuleFlattenConditions(profileClaimRule.Conditions)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting conditions %s", err)) - } - } - - return nil -} - -func dataSourceProfileClaimRuleFlattenConditions(result []iamidentityv1.ProfileClaimRuleConditions) (conditions []map[string]interface{}) { - for _, conditionsItem := range result { - conditions = append(conditions, dataSourceProfileClaimRuleConditionsToMap(conditionsItem)) - } - - return conditions -} - -func dataSourceProfileClaimRuleConditionsToMap(conditionsItem iamidentityv1.ProfileClaimRuleConditions) (conditionsMap map[string]interface{}) { - conditionsMap = map[string]interface{}{} - - if conditionsItem.Claim != nil { - conditionsMap["claim"] = conditionsItem.Claim - } - if conditionsItem.Operator != nil { - conditionsMap["operator"] = conditionsItem.Operator - } - if conditionsItem.Value != nil { - conditionsMap["value"] = conditionsItem.Value - } - - return conditionsMap -} diff --git a/ibm/data_source_ibm_iam_trusted_profile_link.go b/ibm/data_source_ibm_iam_trusted_profile_link.go deleted file mode 100644 index 1e6cfa754..000000000 --- a/ibm/data_source_ibm_iam_trusted_profile_link.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -func dataSourceIBMIamTrustedProfileLink() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMIamTrustedProfileLinkRead, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID of the trusted profile.", - }, - "link_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "ID of the link.", - }, - "entity_tag": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "version of the claim rule.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the creation date in ISO format.", - }, - "modified_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the last modification date in ISO format.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Optional name of the Link.", - }, - "cr_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", - }, - "link": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the compute resource.", - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIamTrustedProfileLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - getLinkOptions := &iamidentityv1.GetLinkOptions{} - - getLinkOptions.SetProfileID(d.Get("profile_id").(string)) - getLinkOptions.SetLinkID(d.Get("link_id").(string)) - - profileLink, response, err := iamIdentityClient.GetLink(getLinkOptions) - if err != nil { - log.Printf("[DEBUG] GetLink failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetLink failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", *getLinkOptions.ProfileID, *getLinkOptions.LinkID)) - if err = d.Set("entity_tag", profileLink.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) - } - if err = d.Set("created_at", dateTimeToString(profileLink.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("modified_at", dateTimeToString(profileLink.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) - } - if err = d.Set("name", profileLink.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("cr_type", profileLink.CrType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cr_type: %s", err)) - } - - if profileLink.Link != nil { - err = d.Set("link", dataSourceProfileLinkFlattenLink(*profileLink.Link)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting link %s", err)) - } - } - - return nil -} - -func dataSourceProfileLinkFlattenLink(result iamidentityv1.ProfileLinkLink) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceProfileLinkLinkToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceProfileLinkLinkToMap(linkItem iamidentityv1.ProfileLinkLink) (linkMap map[string]interface{}) { - linkMap = map[string]interface{}{} - - if linkItem.CRN != nil { - linkMap["crn"] = linkItem.CRN - } - if linkItem.Namespace != nil { - linkMap["namespace"] = linkItem.Namespace - } - if linkItem.Name != nil { - linkMap["name"] = linkItem.Name - } - - return linkMap -} diff --git a/ibm/data_source_ibm_iam_trusted_profile_policy.go b/ibm/data_source_ibm_iam_trusted_profile_policy.go deleted file mode 100644 index 4cbbac407..000000000 --- a/ibm/data_source_ibm_iam_trusted_profile_policy.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" -) - -// Data source to find all the policies for a trusted profile -func dataSourceIBMIAMTrustedProfilePolicy() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMIAMTrustedProfilePolicyRead, - - Schema: map[string]*schema.Schema{ - "profile_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"profile_id", "iam_id"}, - Description: "UUID of trusted profile", - }, - "iam_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"profile_id", "iam_id"}, - Description: "IAM ID of trusted profile", - }, - "sort": { - Description: "Sort query for policies", - Type: schema.TypeString, - Optional: true, - }, - "policies": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "roles": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - "resources": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Computed: true, - Description: "Service name of the policy definition", - }, - "resource_instance_id": { - Type: schema.TypeString, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "ID of resource instance of the policy definition", - }, - "region": { - Type: schema.TypeString, - Computed: true, - Description: "Region of the policy definition", - }, - "resource_type": { - Type: schema.TypeString, - Computed: true, - Description: "Resource type of the policy definition", - }, - "resource": { - Type: schema.TypeString, - Computed: true, - Description: "Resource of the policy definition", - }, - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of the resource group.", - }, - }, - }, - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Description of the Policy", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIAMTrustedProfilePolicyRead(d *schema.ResourceData, meta interface{}) error { - - var iamID string - if v, ok := d.GetOk("profile_id"); ok && v != nil { - - profileUUID := v.(string) - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getprofileOptions := iamidentityv1.GetProfileOptions{ - ProfileID: &profileUUID, - } - profile, resp, err := iamClient.GetProfile(&getprofileOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error getting profile ID %s %s", err, resp) - } - iamID = *profile.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ - AccountID: core.StringPtr(userDetails.userAccount), - IamID: core.StringPtr(iamID), - Type: core.StringPtr("access"), - } - - if v, ok := d.GetOk("sort"); ok { - listPoliciesOptions.Sort = core.StringPtr(v.(string)) - } - - policyList, _, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) - policies := policyList.Policies - if err != nil { - return err - } - - profilePolicies := make([]map[string]interface{}, 0, len(policies)) - for _, policy := range policies { - roles := make([]string, len(policy.Roles)) - for i, role := range policy.Roles { - roles[i] = *role.DisplayName - } - resources := flattenPolicyResource(policy.Resources) - p := map[string]interface{}{ - "roles": roles, - "resources": resources, - } - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileUUID := v.(string) - p["id"] = fmt.Sprintf("%s/%s", profileUUID, *policy.ID) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - p["id"] = fmt.Sprintf("%s/%s", iamID, *policy.ID) - } - if policy.Description != nil { - p["description"] = policy.Description - } - profilePolicies = append(profilePolicies, p) - } - - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileUUID := v.(string) - d.SetId(profileUUID) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(iamID) - } - d.Set("policies", profilePolicies) - return nil -} diff --git a/ibm/data_source_ibm_iam_trusted_profile_policy_test.go b/ibm/data_source_ibm_iam_trusted_profile_policy_test.go deleted file mode 100644 index dd6af7a20..000000000 --- a/ibm/data_source_ibm_iam_trusted_profile_policy_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMIAMTrustedProfilePolicyDataSource_Basic(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyDataSourceConfig(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_iam_trusted_profile_policy.policy", "policies.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicyDataSource_Multiple_Policies(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyDataSourceMultiplePolicies(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_iam_trusted_profile_policy.policy", "policies.#", "2"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMTrustedProfilePolicyDataSourceConfig(name string) string { - return fmt.Sprintf(` - -resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - description = "Profile ID for test" -} - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile_policy.policy.profile_id -}`, name, name) - -} - -func testAccCheckIBMIAMTrustedProfilePolicyDataSourceMultiplePolicies(name string) string { - return fmt.Sprintf(` - -resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - description = "Profile ID for test" -} - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_resource_group" "group" { - is_default=true -} - -resource "ibm_iam_trusted_profile_policy" "policy1" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } -} - -data "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile_policy.policy.profile_id - sort = "id" -}`, name, name) - -} diff --git a/ibm/data_source_ibm_iam_user_policy.go b/ibm/data_source_ibm_iam_user_policy.go deleted file mode 100644 index f87ed82aa..000000000 --- a/ibm/data_source_ibm_iam_user_policy.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// Data source to find all the policies for a user in a particular account -func dataSourceIBMIAMUserPolicy() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMIAMUserPolicyRead, - - Schema: map[string]*schema.Schema{ - "ibm_id": { - Description: "The ibm id or email of user", - Type: schema.TypeString, - Required: true, - }, - "sort": { - Description: "Sort query for policies", - Type: schema.TypeString, - Optional: true, - }, - "policies": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "roles": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - "resources": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Computed: true, - Description: "Service name of the policy definition", - }, - "resource_instance_id": { - Type: schema.TypeString, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "ID of resource instance of the policy definition", - }, - "region": { - Type: schema.TypeString, - Computed: true, - Description: "Region of the policy definition", - }, - "resource_type": { - Type: schema.TypeString, - Computed: true, - Description: "Resource type of the policy definition", - }, - "resource": { - Type: schema.TypeString, - Computed: true, - Description: "Resource of the policy definition", - }, - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of the resource group.", - }, - }, - }, - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Description of the Policy", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMIAMUserPolicyRead(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - userEmail := d.Get("ibm_id").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - - ibmUniqueID, err := getIBMUniqueId(accountID, userEmail, meta) - if err != nil { - return err - } - - listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ - AccountID: core.StringPtr(accountID), - IamID: core.StringPtr(ibmUniqueID), - Type: core.StringPtr("access"), - } - - if v, ok := d.GetOk("sort"); ok { - listPoliciesOptions.Sort = core.StringPtr(v.(string)) - } - - policyList, _, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) - policies := policyList.Policies - if err != nil { - return err - } - - if err != nil { - return err - } - - userPolicies := make([]map[string]interface{}, 0, len(policies)) - for _, policy := range policies { - roles := make([]string, len(policy.Roles)) - for i, role := range policy.Roles { - roles[i] = *role.DisplayName - } - resources := flattenPolicyResource(policy.Resources) - p := map[string]interface{}{ - "id": fmt.Sprintf("%s/%s", userEmail, *policy.ID), - "roles": roles, - "resources": resources, - } - if policy.Description != nil { - p["description"] = policy.Description - } - userPolicies = append(userPolicies, p) - } - d.SetId(userEmail) - d.Set("policies", userPolicies) - - return nil -} diff --git a/ibm/data_source_ibm_iam_user_policy_test.go b/ibm/data_source_ibm_iam_user_policy_test.go deleted file mode 100644 index ce5da42ee..000000000 --- a/ibm/data_source_ibm_iam_user_policy_test.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -// TODO: test fails locally using test env because it returns 3 policies (even existing test) -func TestAccIBMIAMUserPolicyDataSource_Basic(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyDataSourceConfig(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_iam_user_policy.testacc_ds_user_policy", "policies.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicyDataSource_Multiple_Policies(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyDataSourceMultiplePolicies(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_iam_user_policy.testacc_ds_user_policy", "policies.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMUserPolicyDataSourceConfig(name string) string { - return fmt.Sprintf(` - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_iam_user_policy" "testacc_ds_user_policy" { - ibm_id = ibm_iam_user_policy.policy.ibm_id -} -`, name, IAMUser) - -} - -func testAccCheckIBMIAMUserPolicyDataSourceMultiplePolicies(name string) string { - return fmt.Sprintf(` - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } -} - -data "ibm_resource_group" "group" { - is_default=true -} - -resource "ibm_iam_user_policy" "policy1" { - ibm_id = "%s" - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } -} - - -data "ibm_iam_user_policy" "testacc_ds_user_policy" { - ibm_id = ibm_iam_user_policy.policy.ibm_id - sort = "-id" -}`, name, IAMUser, IAMUser) - -} diff --git a/ibm/data_source_ibm_is_dedicated_host_disk_test.go b/ibm/data_source_ibm_is_dedicated_host_disk_test.go deleted file mode 100644 index 31daf5e8b..000000000 --- a/ibm/data_source_ibm_is_dedicated_host_disk_test.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISDedicatedHostDiskDataSource_basic(t *testing.T) { - resName := "data.ibm_is_dedicated_host_disk.test1" - var conf vpcv1.DedicatedHost - groupname := fmt.Sprintf("tf-dhostgroup%d", acctest.RandIntRange(10, 100)) - dhname := fmt.Sprintf("tf-dhost%d", acctest.RandIntRange(10, 100)) - dhresname := "ibm_is_dedicated_host.dhost" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIbmIsDedicatedHostConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIbmIsDedicatedHostExists(dhresname, conf), - resource.TestCheckResourceAttr(dhresname, "name", dhname), - resource.TestCheckResourceAttr(dhresname, "disks.#", "2"), - resource.TestCheckResourceAttrSet(dhresname, "disks.0.name"), - resource.TestCheckResourceAttrSet(dhresname, "disks.0.size"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMISDedicatedHostDiskDataSourceConfig(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "name"), - resource.TestCheckResourceAttrSet(resName, "size"), - ), - }, - }, - }) -} - -func testAccCheckIBMISDedicatedHostDiskDataSourceConfig(class, family, groupname, dedicatedHostProfileName, dhname string) string { - return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, dedicatedHostProfileName, dhname) + fmt.Sprintf(` - data "ibm_is_dedicated_host" "dhost" { - name = "%s" - host_group = ibm_is_dedicated_host.dhost.host_group - } - data "ibm_is_dedicated_host_disks" "test1" { - dedicated_host = data.ibm_is_dedicated_host.dhost.id - - } - data "ibm_is_dedicated_host_disk" "test1" { - dedicated_host = data.ibm_is_dedicated_host.dhost.id - disk = data.ibm_is_dedicated_host_disks.test1.disks.0.id - }`, dhname) -} diff --git a/ibm/data_source_ibm_is_dedicated_host_profile_test.go b/ibm/data_source_ibm_is_dedicated_host_profile_test.go deleted file mode 100644 index 6ee0d4987..000000000 --- a/ibm/data_source_ibm_is_dedicated_host_profile_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIbmIsDedicatedHostProfileDataSourceBasic(t *testing.T) { - - resName := "data.ibm_is_dedicated_host_profile.dhprofile" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostProfileDataSourceConfigBasic(dedicatedHostProfileName), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", dedicatedHostProfileName), - resource.TestCheckResourceAttrSet(resName, "class"), - resource.TestCheckResourceAttrSet(resName, "family"), - ), - }, - }, - }) -} - -func testAccCheckIbmIsDedicatedHostProfileDataSourceConfigBasic(profile string) string { - return fmt.Sprintf(` - - data "ibm_is_dedicated_host_profile" "dhprofile" { - name = "%s" - } - `, profile) -} diff --git a/ibm/data_source_ibm_is_endpoint_gateway_targets.go b/ibm/data_source_ibm_is_endpoint_gateway_targets.go deleted file mode 100644 index 398de8ad4..000000000 --- a/ibm/data_source_ibm_is_endpoint_gateway_targets.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "strconv" - "strings" - "time" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isVPEResources = "resources" - isVPEResourceCRN = "crn" - isVPEResourceParent = "parent" - isVPEResourceName = "name" - isVPEResourceEndpointType = "endpoint_type" - isVPEResourceType = "resource_type" - isVPEResourceFullQualifiedDomainNames = "full_qualified_domain_names" - isVPEResourceServiceLocation = "location" -) - -func dataSourceIBMISEndpointGatewayTargets() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMISEndpointGatewayTargetsRead, - - Schema: map[string]*schema.Schema{ - isVPEResources: { - Type: schema.TypeList, - Computed: true, - Description: "List of resources", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVPEResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "CRN for this specific object", - }, - isVPEResourceParent: { - Type: schema.TypeString, - Computed: true, - Description: "Parent for this specific object", - }, - isVPEResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "Display name in the requested language", - }, - isVPEResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Resource type of this offering.", - }, - isVPEResourceEndpointType: { - Type: schema.TypeString, - Computed: true, - Description: "Data endpoint type of this offering", - }, - isVPEResourceFullQualifiedDomainNames: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Fully qualified domain names", - }, - isVPEResourceServiceLocation: { - Type: schema.TypeString, - Computed: true, - Description: "Service location of this offering", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISEndpointGatewayTargetsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - bmxSess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - region := bmxSess.Config.Region - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return diag.FromErr(err) - } - - getCatalogOptions := &catalogmanagementv1.SearchObjectsOptions{} - // query := "kind%3Avpe+AND+svc+AND+parent_id%3Aus-south" - query := fmt.Sprintf("kind:vpe AND svc AND parent_id:%s", region) - getCatalogOptions.Query = &query - digest := false - getCatalogOptions.Digest = &digest - - start := int64(0) - catalog := []catalogmanagementv1.CatalogObject{} - for { - if start != int64(0) { - getCatalogOptions.Offset = &start - } - search, response, err := catalogManagementClient.SearchObjectsWithContext(context, getCatalogOptions) - if err != nil { - log.Printf("[DEBUG] GetCatalogWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - next := search.Next - if next == nil { - start = int64(0) - } else { - u, _ := url.Parse(fmt.Sprintf("%s", *next)) - q := u.Query() - start, _ = strconv.ParseInt(q.Get("offset"), 10, 64) - } - catalog = append(catalog, search.Resources...) - if start == int64(0) { - break - } - } - if catalog != nil { - resourceInfo := make([]map[string]interface{}, 0) - for _, res := range catalog { - l := map[string]interface{}{} - if res.ParentID != nil { - l[isVPEResourceParent] = *res.ParentID - } - l[isVPEResourceName] = "provider_cloud_service" - if res.Label != nil { - l[isVPEResourceType] = *res.Label - } - sl := "" - data := res.Data - if data != nil { - if serviceCrn, ok := data["service_crn"].(string); ok { - if serviceCrn != "" { - l[isVPEResourceCRN] = serviceCrn - crnFs := strings.Split(serviceCrn, ":") - if len(crnFs) > 5 { - sl = crnFs[5] - } - l[isVPEResourceServiceLocation] = sl - } - } - if data["endpoint_type"] != nil { - l[isVPEResourceEndpointType] = data["endpoint_type"] - } - if data["fully_qualified_domain_names"] != nil { - l[isVPEResourceFullQualifiedDomainNames] = data["fully_qualified_domain_names"] - } - } - resourceInfo = append(resourceInfo, l) - } - d.Set(isVPEResources, resourceInfo) - d.SetId(dataSourceIBMISEndpointGatewayTargetsId(d)) - } - return nil -} -func dataSourceIBMISEndpointGatewayTargetsId(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_floating_ip.go b/ibm/data_source_ibm_is_floating_ip.go deleted file mode 100644 index 3caf53294..000000000 --- a/ibm/data_source_ibm_is_floating_ip.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - floatingIPName = "name" - floatingIPAddress = "address" - floatingIPStatus = "status" - floatingIPZone = "zone" - floatingIPTarget = "target" - floatingIPTags = "tags" - floatingIPCRN = "crn" -) - -func dataSourceIBMISFloatingIP() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISFloatingIPRead, - - Schema: map[string]*schema.Schema{ - - floatingIPName: { - Type: schema.TypeString, - Required: true, - Description: "Name of the floating IP", - }, - - floatingIPAddress: { - Type: schema.TypeString, - Computed: true, - Description: "Floating IP address", - }, - - floatingIPStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Floating IP status", - }, - - floatingIPZone: { - Type: schema.TypeString, - Computed: true, - Description: "Zone name", - }, - - floatingIPTarget: { - Type: schema.TypeString, - Computed: true, - Description: "Target info", - }, - - floatingIPCRN: { - Type: schema.TypeString, - Computed: true, - Description: "Floating IP crn", - }, - - floatingIPTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "Floating IP tags", - }, - }, - } -} - -func dataSourceIBMISFloatingIPRead(d *schema.ResourceData, meta interface{}) error { - floatingIPName := d.Get(isFloatingIPName).(string) - err := floatingIPGet(d, meta, floatingIPName) - if err != nil { - return err - } - return nil -} - -func floatingIPGet(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - start := "" - allFloatingIPs := []vpcv1.FloatingIP{} - for { - floatingIPOptions := &vpcv1.ListFloatingIpsOptions{} - if start != "" { - floatingIPOptions.Start = &start - } - floatingIPs, response, err := sess.ListFloatingIps(floatingIPOptions) - if err != nil { - return fmt.Errorf("Error Fetching floating IPs %s\n%s", err, response) - } - start = GetNext(floatingIPs.Next) - allFloatingIPs = append(allFloatingIPs, floatingIPs.FloatingIps...) - if start == "" { - break - } - } - - for _, ip := range allFloatingIPs { - if *ip.Name == name { - - d.Set(floatingIPName, *ip.Name) - d.Set(floatingIPAddress, *ip.Address) - d.Set(floatingIPStatus, *ip.Status) - d.Set(floatingIPZone, *ip.Zone.Name) - - d.Set(floatingIPCRN, *ip.CRN) - - target, ok := ip.Target.(*vpcv1.FloatingIPTarget) - if ok { - d.Set(floatingIPTarget, target.ID) - } - - tags, err := GetTagsUsingCRN(meta, *ip.CRN) - if err != nil { - fmt.Printf("Error on get of vpc Floating IP (%s) tags: %s", *ip.Address, err) - } - - d.Set(floatingIPTags, tags) - d.SetId(*ip.ID) - - return nil - } - } - - return fmt.Errorf("No floatingIP found with name %s", name) - -} diff --git a/ibm/data_source_ibm_is_image.go b/ibm/data_source_ibm_is_image.go deleted file mode 100644 index 0607db00c..000000000 --- a/ibm/data_source_ibm_is_image.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMISImage() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISImageRead, - - Schema: map[string]*schema.Schema{ - - "name": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"identifier", "name"}, - Description: "Image name", - }, - - "identifier": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"identifier", "name"}, - Description: "Image id", - }, - - "visibility": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "Whether the image is publicly visible or private to the account", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "The status of this image", - }, - - "os": { - Type: schema.TypeString, - Computed: true, - Description: "Image Operating system", - }, - "architecture": { - Type: schema.TypeString, - Computed: true, - Description: "The operating system architecture", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this image", - }, - isImageCheckSum: { - Type: schema.TypeString, - Computed: true, - Description: "The SHA256 Checksum for this image", - }, - isImageEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", - }, - isImageEncryption: { - Type: schema.TypeString, - Computed: true, - Description: "The type of encryption used on the image", - }, - "source_volume": { - Type: schema.TypeString, - Computed: true, - Description: "Source volume id of the image", - }, - }, - } -} - -func dataSourceIBMISImageRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get("name").(string) - identifier := d.Get("identifier").(string) - var visibility string - if v, ok := d.GetOk("visibility"); ok { - visibility = v.(string) - } - if name != "" { - err := imageGetByName(d, meta, name, visibility) - if err != nil { - return err - } - } else if identifier != "" { - err := imageGetById(d, meta, identifier) - if err != nil { - return err - } - } - - return nil -} - -func imageGetByName(d *schema.ResourceData, meta interface{}, name, visibility string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.Image{} - for { - listImagesOptions := &vpcv1.ListImagesOptions{} - if start != "" { - listImagesOptions.Start = &start - } - if visibility != "" { - listImagesOptions.Visibility = &visibility - } - availableImages, response, err := sess.ListImages(listImagesOptions) - if err != nil { - return fmt.Errorf("Error Fetching Images %s\n%s", err, response) - } - start = GetNext(availableImages.Next) - allrecs = append(allrecs, availableImages.Images...) - if start == "" { - break - } - } - - for _, image := range allrecs { - if *image.Name == name { - d.SetId(*image.ID) - d.Set("status", *image.Status) - if *image.Status == "deprecated" { - fmt.Printf("[WARN] Given image %s is deprecated and soon will be obsolete.", name) - } - d.Set("name", *image.Name) - d.Set("visibility", *image.Visibility) - d.Set("os", *image.OperatingSystem.Name) - d.Set("architecture", *image.OperatingSystem.Architecture) - d.Set("crn", *image.CRN) - if image.Encryption != nil { - d.Set("encryption", *image.Encryption) - } - if image.EncryptionKey != nil { - d.Set("encryption_key", *image.EncryptionKey.CRN) - } - if image.File != nil && image.File.Checksums != nil { - d.Set(isImageCheckSum, *image.File.Checksums.Sha256) - } - if image.SourceVolume != nil { - d.Set("source_volume", *image.SourceVolume.ID) - } - return nil - } - } - - return fmt.Errorf("No image found with name %s", name) -} -func imageGetById(d *schema.ResourceData, meta interface{}, identifier string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getImageOptions := &vpcv1.GetImageOptions{ - ID: &identifier, - } - - image, response, err := sess.GetImage(getImageOptions) - if err != nil { - if response.StatusCode == 404 { - return fmt.Errorf("No image found with id %s", identifier) - } - return fmt.Errorf("Error Fetching Images %s\n%s", err, response) - } - - d.SetId(*image.ID) - d.Set("status", *image.Status) - if *image.Status == "deprecated" { - fmt.Printf("[WARN] Given image %s is deprecated and soon will be obsolete.", name) - } - d.Set("name", *image.Name) - d.Set("visibility", *image.Visibility) - d.Set("os", *image.OperatingSystem.Name) - d.Set("architecture", *image.OperatingSystem.Architecture) - d.Set("crn", *image.CRN) - if image.Encryption != nil { - d.Set("encryption", *image.Encryption) - } - if image.EncryptionKey != nil { - d.Set("encryption_key", *image.EncryptionKey.CRN) - } - if image.File != nil && image.File.Checksums != nil { - d.Set(isImageCheckSum, *image.File.Checksums.Sha256) - } - if image.SourceVolume != nil { - d.Set("source_volume", *image.SourceVolume.ID) - } - return nil -} diff --git a/ibm/data_source_ibm_is_image_test.go b/ibm/data_source_ibm_is_image_test.go deleted file mode 100644 index 5456da71c..000000000 --- a/ibm/data_source_ibm_is_image_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISImageDataSource_basic(t *testing.T) { - resName := "data.ibm_is_image.test1" - imageName := fmt.Sprintf("tfimage-name-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISImageDataSourceConfig(imageName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", imageName), - resource.TestCheckResourceAttrSet(resName, "os"), - resource.TestCheckResourceAttrSet(resName, "architecture"), - resource.TestCheckResourceAttrSet(resName, "visibility"), - resource.TestCheckResourceAttrSet(resName, "status"), - ), - }, - }, - }) -} - -func TestAccIBMISImageDataSource_With_VisibiltyPublic(t *testing.T) { - resName := "data.ibm_is_image.test1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISImageDataSourceWithVisibilityPublic("public"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", IsImageName), - resource.TestCheckResourceAttrSet(resName, "os"), - resource.TestCheckResourceAttrSet(resName, "architecture"), - resource.TestCheckResourceAttrSet(resName, "visibility"), - resource.TestCheckResourceAttrSet(resName, "status"), - ), - }, - }, - }) -} - -func TestAccIBMISImageDataSource_With_VisibiltyPrivate(t *testing.T) { - resName := "data.ibm_is_image.test1" - imageName := fmt.Sprintf("tfimage-name-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISImageDataSourceWithVisibilityPrivate(imageName, "private"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", imageName), - resource.TestCheckResourceAttrSet(resName, "os"), - resource.TestCheckResourceAttrSet(resName, "architecture"), - resource.TestCheckResourceAttrSet(resName, "visibility"), - resource.TestCheckResourceAttrSet(resName, "status"), - ), - }, - }, - }) -} - -func testAccCheckIBMISImageDataSourceConfig(imageName string) string { - return fmt.Sprintf(` - resource "ibm_is_image" "isExampleImage" { - href = "%s" - name = "%s" - operating_system = "%s" - } - data "ibm_is_image" "test1" { - name = ibm_is_image.isExampleImage.name - }`, image_cos_url, imageName, image_operating_system) -} - -func testAccCheckIBMISImageDataSourceWithVisibilityPublic(visibility string) string { - return fmt.Sprintf(` - data "ibm_is_image" "test1" { - name = "%s" - visibility = "%s" - }`, IsImageName, visibility) -} - -func testAccCheckIBMISImageDataSourceWithVisibilityPrivate(imageName, visibility string) string { - return fmt.Sprintf(` - resource "ibm_is_image" "isExampleImage" { - href = "%s" - name = "%s" - operating_system = "%s" - } - data "ibm_is_image" "test1" { - name = ibm_is_image.isExampleImage.name - visibility = "%s" - }`, image_cos_url, imageName, image_operating_system, visibility) -} diff --git a/ibm/data_source_ibm_is_images.go b/ibm/data_source_ibm_is_images.go deleted file mode 100644 index f5536b264..000000000 --- a/ibm/data_source_ibm_is_images.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isImages = "images" - isImagesResourceGroupID = "resource_group" -) - -func dataSourceIBMISImages() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISImagesRead, - - Schema: map[string]*schema.Schema{ - isImagesResourceGroupID: { - Type: schema.TypeString, - Description: "The id of the resource group", - Optional: true, - }, - isImageName: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator("ibm_is_image", isImageName), - Description: "The name of the image", - }, - isImageVisibility: { - Type: schema.TypeString, - Optional: true, - Description: "Whether the image is publicly visible or private to the account", - }, - - isImages: { - Type: schema.TypeList, - Description: "List of images", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Image name", - }, - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this image", - }, - "status": { - Type: schema.TypeString, - Computed: true, - Description: "The status of this image", - }, - "visibility": { - Type: schema.TypeString, - Computed: true, - Description: "Whether the image is publicly visible or private to the account", - }, - "os": { - Type: schema.TypeString, - Computed: true, - Description: "Image Operating system", - }, - "architecture": { - Type: schema.TypeString, - Computed: true, - Description: "The operating system architecture", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this image", - }, - isImageCheckSum: { - Type: schema.TypeString, - Computed: true, - Description: "The SHA256 Checksum for this image", - }, - isImageEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", - }, - isImageEncryption: { - Type: schema.TypeString, - Computed: true, - Description: "The type of encryption used on the image", - }, - "source_volume": { - Type: schema.TypeString, - Computed: true, - Description: "Source volume id of the image", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISImagesRead(d *schema.ResourceData, meta interface{}) error { - - err := imageList(d, meta) - if err != nil { - return err - } - return nil -} - -func imageList(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.Image{} - - var resourceGroupID string - if v, ok := d.GetOk(isImagesResourceGroupID); ok { - resourceGroupID = v.(string) - } - - var imageName string - if v, ok := d.GetOk(isImageName); ok { - imageName = v.(string) - } - - var visibility string - if v, ok := d.GetOk(isImageVisibility); ok { - visibility = v.(string) - } - - listImagesOptions := &vpcv1.ListImagesOptions{} - if resourceGroupID != "" { - listImagesOptions.SetResourceGroupID(resourceGroupID) - } - if imageName != "" { - listImagesOptions.SetName(imageName) - } - if visibility != "" { - listImagesOptions.SetVisibility(visibility) - } - - for { - if start != "" { - listImagesOptions.Start = &start - } - availableImages, response, err := sess.ListImages(listImagesOptions) - if err != nil { - return fmt.Errorf("Error Fetching Images %s\n%s", err, response) - } - start = GetNext(availableImages.Next) - allrecs = append(allrecs, availableImages.Images...) - if start == "" { - break - } - } - imagesInfo := make([]map[string]interface{}, 0) - for _, image := range allrecs { - - l := map[string]interface{}{ - "name": *image.Name, - "id": *image.ID, - "status": *image.Status, - "crn": *image.CRN, - "visibility": *image.Visibility, - "os": *image.OperatingSystem.Name, - "architecture": *image.OperatingSystem.Architecture, - } - if image.File != nil && image.File.Checksums != nil { - l[isImageCheckSum] = *image.File.Checksums.Sha256 - } - if image.Encryption != nil { - l["encryption"] = *image.Encryption - } - if image.EncryptionKey != nil { - l["encryption_key"] = *image.EncryptionKey.CRN - } - if image.SourceVolume != nil { - l["source_volume"] = *image.SourceVolume.ID - } - imagesInfo = append(imagesInfo, l) - } - d.SetId(dataSourceIBMISSubnetsID(d)) - d.Set(isImages, imagesInfo) - return nil -} - -// dataSourceIBMISImagesId returns a reasonable ID for a image list. -func dataSourceIBMISImagesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_images_test.go b/ibm/data_source_ibm_is_images_test.go deleted file mode 100644 index d1ca64f79..000000000 --- a/ibm/data_source_ibm_is_images_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISImagesDataSource_basic(t *testing.T) { - resName := "data.ibm_is_images.test1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISImagesDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "images.0.name"), - resource.TestCheckResourceAttrSet(resName, "images.0.status"), - resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), - ), - }, - }, - }) -} - -func TestAccIBMISImageDataSource_With_FilterVisibilty(t *testing.T) { - resName := "data.ibm_is_images.test1" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISImagesDataSourceWithVisibilityPublic("public"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "images.0.name"), - resource.TestCheckResourceAttrSet(resName, "images.0.status"), - resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), - ), - }, - }, - }) -} - -func testAccCheckIBMISImagesDataSourceConfig() string { - // status filter defaults to empty - return fmt.Sprintf(` - data "ibm_is_images" "test1" { - }`) -} - -func testAccCheckIBMISImagesDataSourceWithVisibilityPublic(visibility string) string { - return fmt.Sprintf(` - data "ibm_is_images" "test1" { - visibility = "%s" - } - `, visibility) -} diff --git a/ibm/data_source_ibm_is_instance.go b/ibm/data_source_ibm_is_instance.go deleted file mode 100644 index 1c9ce6166..000000000 --- a/ibm/data_source_ibm_is_instance.go +++ /dev/null @@ -1,874 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "errors" - "fmt" - "log" - "strings" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/ScaleFT/sshkeys" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "golang.org/x/crypto/ssh" -) - -const ( - isInstancePEM = "private_key" - isInstancePassphrase = "passphrase" - isInstanceInitPassword = "password" - isInstanceInitKeys = "keys" -) - -func dataSourceIBMISInstance() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISInstanceRead, - - Schema: map[string]*schema.Schema{ - - isInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Instance name", - }, - - isInstancePEM: { - Type: schema.TypeString, - Optional: true, - Description: "Instance Private Key file", - }, - - isInstancePassphrase: { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - Description: "Passphrase for Instance Private Key file", - }, - - isInstanceInitPassword: { - Type: schema.TypeString, - Sensitive: true, - Computed: true, - Description: "password for Windows Instance", - }, - - isInstanceInitKeys: { - Type: schema.TypeList, - Computed: true, - Description: "Instance keys", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance key id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance key name", - }, - }, - }, - }, - - isInstanceVPC: { - Type: schema.TypeString, - Computed: true, - Description: "VPC id", - }, - - isInstanceZone: { - Type: schema.TypeString, - Computed: true, - Description: "Zone name", - }, - - isInstanceProfile: { - Type: schema.TypeString, - Computed: true, - Description: "Profile info", - }, - - isInstanceTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "list of tags for the instance", - }, - isInstanceBootVolume: { - Type: schema.TypeList, - Computed: true, - Description: "Instance Boot Volume", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume name", - }, - "device": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume device", - }, - "volume_id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume id", - }, - "volume_name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume name", - }, - "volume_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume CRN", - }, - }, - }, - }, - - isInstanceVolumeAttachments: { - Type: schema.TypeList, - Computed: true, - Description: "Instance Volume Attachments", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Volume Attachment id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Volume Attachment name", - }, - "volume_id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume id", - }, - "volume_name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume name", - }, - "volume_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot Volume's volume CRN", - }, - }, - }, - }, - - isInstancePrimaryNetworkInterface: { - Type: schema.TypeList, - Computed: true, - Description: "Primary Network interface info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network Interface id", - }, - isInstanceNicName: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network Interface name", - }, - isInstanceNicPortSpeed: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance Primary Network Interface port speed", - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network Interface IPV4 Address", - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Instance Primary Network Interface Security groups", - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network Interface subnet", - }, - }, - }, - }, - - isInstanceNetworkInterfaces: { - Type: schema.TypeList, - Computed: true, - Description: "Instance Network interface info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network Interface id", - }, - isInstanceNicName: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network Interface name", - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network Interface IPV4 Address", - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Instance Network Interface Security Groups", - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network Interface subnet", - }, - }, - }, - }, - - isInstanceImage: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Image", - }, - - isInstanceVolumes: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "List of volumes", - }, - - isInstanceResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Instance resource group", - }, - - isInstanceCPU: { - Type: schema.TypeList, - Computed: true, - Description: "Instance vCPU", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceCPUArch: { - Type: schema.TypeString, - Computed: true, - Description: "Instance vCPU Architecture", - }, - isInstanceCPUCount: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance vCPU count", - }, - }, - }, - }, - - isInstanceGpu: { - Type: schema.TypeList, - Computed: true, - Description: "Instance GPU", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceGpuCount: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance GPU Count", - }, - isInstanceGpuMemory: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance GPU Memory", - }, - isInstanceGpuManufacturer: { - Type: schema.TypeString, - Computed: true, - Description: "Instance GPU Manufacturer", - }, - isInstanceGpuModel: { - Type: schema.TypeString, - Computed: true, - Description: "Instance GPU Model", - }, - }, - }, - }, - - isInstanceMemory: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance memory", - }, - - isInstanceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "instance status", - }, - - isInstanceStatusReasons: { - Type: schema.TypeList, - Computed: true, - Description: "The reasons for the current status (if any).", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceStatusReasonsCode: { - Type: schema.TypeString, - Computed: true, - Description: "A snake case string succinctly identifying the status reason", - }, - - isInstanceStatusReasonsMessage: { - Type: schema.TypeString, - Computed: true, - Description: "An explanation of the status reason", - }, - }, - }, - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - IsInstanceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - isInstanceDisks: &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Collection of the instance's disks.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the disk was created.", - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this instance disk.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this instance disk.", - }, - "interface_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user-defined name for this disk.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - "size": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The size of the disk in GB (gigabytes).", - }, - }, - }, - }, - "placement_target": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions for the virtual server instance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this dedicated host group.", - }, - "deleted": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Link to documentation about deleted resources.", - }, - }, - }, - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this dedicated host group.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this dedicated host group.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of resource referenced.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstanceRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isInstanceName).(string) - - err := instanceGetByName(d, meta, name) - if err != nil { - return err - } - return nil -} - -func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.Instance{} - for { - listInstancesOptions := &vpcv1.ListInstancesOptions{} - if start != "" { - listInstancesOptions.Start = &start - } - instances, response, err := sess.ListInstances(listInstancesOptions) - if err != nil { - return fmt.Errorf("Error Fetching Instances %s\n%s", err, response) - } - start = GetNext(instances.Next) - allrecs = append(allrecs, instances.Instances...) - if start == "" { - break - } - } - for _, instance := range allrecs { - if *instance.Name == name { - d.SetId(*instance.ID) - id := *instance.ID - d.Set(isInstanceName, *instance.Name) - if instance.Profile != nil { - d.Set(isInstanceProfile, *instance.Profile.Name) - } - cpuList := make([]map[string]interface{}, 0) - if instance.Vcpu != nil { - currentCPU := map[string]interface{}{} - currentCPU[isInstanceCPUArch] = *instance.Vcpu.Architecture - currentCPU[isInstanceCPUCount] = *instance.Vcpu.Count - cpuList = append(cpuList, currentCPU) - } - d.Set(isInstanceCPU, cpuList) - - if instance.PlacementTarget != nil { - placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) - d.Set("placement_target", []map[string]interface{}{placementTargetMap}) - } - - d.Set(isInstanceMemory, *instance.Memory) - - gpuList := make([]map[string]interface{}, 0) - if instance.Gpu != nil { - currentGpu := map[string]interface{}{} - currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer - currentGpu[isInstanceGpuModel] = instance.Gpu.Model - currentGpu[isInstanceGpuCount] = instance.Gpu.Count - currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory - gpuList = append(gpuList, currentGpu) - d.Set(isInstanceGpu, gpuList) - } - - if instance.Disks != nil { - d.Set(isInstanceDisks, dataSourceInstanceFlattenDisks(instance.Disks)) - } - - if instance.PrimaryNetworkInterface != nil { - primaryNicList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID - currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: instance.PrimaryNetworkInterface.ID, - } - insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentPrimNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - primaryNicList = append(primaryNicList, currentPrimNic) - d.Set(isInstancePrimaryNetworkInterface, primaryNicList) - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - if *intfc.ID != *instance.PrimaryNetworkInterface.ID { - currentNic := map[string]interface{}{} - currentNic["id"] = *intfc.ID - currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: intfc.ID, - } - insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfacesList = append(interfacesList, currentNic) - - } - } - - d.Set(isInstanceNetworkInterfaces, interfacesList) - } - - var rsaKey *rsa.PrivateKey - if instance.Image != nil { - d.Set(isInstanceImage, *instance.Image.ID) - image := *instance.Image.Name - res := strings.Contains(image, "windows") - if res { - if privatekey, ok := d.GetOk(isInstancePEM); ok { - keyFlag := privatekey.(string) - keybytes := []byte(keyFlag) - - if keyFlag != "" { - block, err := pem.Decode(keybytes) - if block == nil { - return fmt.Errorf("Failed to load the private key from the given key contents. Instead of the key file path, please make sure the private key is pem format") - } - isEncrypted := false - switch block.Type { - case "RSA PRIVATE KEY": - isEncrypted = x509.IsEncryptedPEMBlock(block) - case "OPENSSH PRIVATE KEY": - var err error - isEncrypted, err = isOpenSSHPrivKeyEncrypted(block.Bytes) - if err != nil { - return fmt.Errorf("Failed to check if the provided open ssh key is encrypted or not %s", err) - } - default: - return fmt.Errorf("PEM and OpenSSH private key formats with RSA key type are supported, can not support this key file type: %s", err) - } - passphrase := "" - var privateKey interface{} - if isEncrypted { - if pass, ok := d.GetOk(isInstancePassphrase); ok { - passphrase = pass.(string) - } else { - return fmt.Errorf("Mandatory field 'passphrase' not provided") - } - var err error - privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, []byte(passphrase)) - if err != nil { - return fmt.Errorf("Fail to decrypting the private key: %s", err) - } - } else { - var err error - privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, nil) - if err != nil { - return fmt.Errorf("Fail to decrypting the private key: %s", err) - } - } - var ok bool - rsaKey, ok = privateKey.(*rsa.PrivateKey) - if !ok { - return fmt.Errorf("Failed to convert to RSA private key") - } - } - } - } - } - - getInstanceInitializationOptions := &vpcv1.GetInstanceInitializationOptions{ - ID: &id, - } - initParms, response, err := sess.GetInstanceInitialization(getInstanceInitializationOptions) - if err != nil { - return fmt.Errorf("Error Getting instance Initialization: %s\n%s", err, response) - } - if initParms.Keys != nil { - initKeyList := make([]map[string]interface{}, 0) - for _, key := range initParms.Keys { - initKey := map[string]interface{}{} - id := "" - if key.ID != nil { - id = *key.ID - } - initKey["id"] = id - name := "" - if key.Name != nil { - name = *key.Name - } - initKey["name"] = name - initKeyList = append(initKeyList, initKey) - break - - } - d.Set(isInstanceInitKeys, initKeyList) - } - if initParms.Password != nil && initParms.Password.EncryptedPassword != nil { - ciphertext := *initParms.Password.EncryptedPassword - password := base64.StdEncoding.EncodeToString(ciphertext) - if rsaKey != nil { - rng := rand.Reader - clearPassword, err := rsa.DecryptPKCS1v15(rng, rsaKey, ciphertext) - if err != nil { - return fmt.Errorf("Can not decrypt the password with the given key, %s", err) - } - password = string(clearPassword) - } - d.Set(isInstanceInitPassword, password) - } - - d.Set(isInstanceStatus, *instance.Status) - //set the status reasons - if instance.StatusReasons != nil { - statusReasonsList := make([]map[string]interface{}, 0) - for _, sr := range instance.StatusReasons { - currentSR := map[string]interface{}{} - if sr.Code != nil && sr.Message != nil { - currentSR[isInstanceStatusReasonsCode] = *sr.Code - currentSR[isInstanceStatusReasonsMessage] = *sr.Message - statusReasonsList = append(statusReasonsList, currentSR) - } - } - d.Set(isInstanceStatusReasons, statusReasonsList) - } - d.Set(isInstanceVPC, *instance.VPC.ID) - d.Set(isInstanceZone, *instance.Zone.Name) - - var volumes []string - volumes = make([]string, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - if volume.Volume != nil && *volume.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { - volumes = append(volumes, *volume.Volume.ID) - } - } - } - d.Set(isInstanceVolumes, newStringSet(schema.HashString, volumes)) - if instance.VolumeAttachments != nil { - volList := make([]map[string]interface{}, 0) - for _, volume := range instance.VolumeAttachments { - vol := map[string]interface{}{} - if volume.Volume != nil { - vol["id"] = *volume.ID - vol["volume_id"] = *volume.Volume.ID - vol["name"] = *volume.Name - vol["volume_name"] = *volume.Volume.Name - vol["volume_crn"] = *volume.Volume.CRN - volList = append(volList, vol) - } - } - d.Set(isInstanceVolumeAttachments, volList) - } - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - bootVol["id"] = *instance.BootVolumeAttachment.ID - bootVol["name"] = *instance.BootVolumeAttachment.Name - if instance.BootVolumeAttachment.Device != nil { - bootVol["device"] = *instance.BootVolumeAttachment.Device.ID - } - if instance.BootVolumeAttachment.Volume != nil { - bootVol["volume_name"] = *instance.BootVolumeAttachment.Volume.Name - bootVol["volume_id"] = *instance.BootVolumeAttachment.Volume.ID - bootVol["volume_crn"] = *instance.BootVolumeAttachment.Volume.CRN - } - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceBootVolume, bootVolList) - } - tags, err := GetTagsUsingCRN(meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on get of resource vpc Instance (%s) tags: %s", d.Id(), err) - } - d.Set(isInstanceTags, tags) - - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/compute/vs") - d.Set(ResourceName, instance.Name) - d.Set(ResourceCRN, instance.CRN) - d.Set(IsInstanceCRN, instance.CRN) - d.Set(ResourceStatus, instance.Status) - if instance.ResourceGroup != nil { - d.Set(isInstanceResourceGroup, instance.ResourceGroup.ID) - d.Set(ResourceGroupName, instance.ResourceGroup.Name) - } - return nil - } - } - return fmt.Errorf("No Instance found with name %s", name) -} - -const opensshv1Magic = "openssh-key-v1" - -type opensshPrivateKey struct { - CipherName string - KdfName string - KdfOpts string - NumKeys uint32 - PubKey string - PrivKeyBlock string -} - -func isOpenSSHPrivKeyEncrypted(data []byte) (bool, error) { - magic := append([]byte(opensshv1Magic), 0) - if !bytes.Equal(magic, data[0:len(magic)]) { - return false, errors.New("Invalid openssh private key format") - } - content := data[len(magic):] - - privKey := opensshPrivateKey{} - - if err := ssh.Unmarshal(content, &privKey); err != nil { - return false, err - } - - if privKey.KdfName == "none" && privKey.CipherName == "none" { - return false, nil - } - return true, nil -} - -func dataSourceInstanceFlattenDisks(result []vpcv1.InstanceDisk) (disks []map[string]interface{}) { - for _, disksItem := range result { - disks = append(disks, dataSourceInstanceDisksToMap(disksItem)) - } - - return disks -} - -func dataSourceInstanceDisksToMap(disksItem vpcv1.InstanceDisk) (disksMap map[string]interface{}) { - disksMap = map[string]interface{}{} - - if disksItem.CreatedAt != nil { - disksMap["created_at"] = disksItem.CreatedAt.String() - } - if disksItem.Href != nil { - disksMap["href"] = disksItem.Href - } - if disksItem.ID != nil { - disksMap["id"] = disksItem.ID - } - if disksItem.InterfaceType != nil { - disksMap["interface_type"] = disksItem.InterfaceType - } - if disksItem.Name != nil { - disksMap["name"] = disksItem.Name - } - if disksItem.ResourceType != nil { - disksMap["resource_type"] = disksItem.ResourceType - } - if disksItem.Size != nil { - disksMap["size"] = disksItem.Size - } - - return disksMap -} diff --git a/ibm/data_source_ibm_is_instance_profile.go b/ibm/data_source_ibm_is_instance_profile.go deleted file mode 100644 index 59e0fc30b..000000000 --- a/ibm/data_source_ibm_is_instance_profile.go +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceProfileName = "name" - isInstanceProfileFamily = "family" - isInstanceProfileArchitecture = "architecture" -) - -func dataSourceIBMISInstanceProfile() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISInstanceProfileRead, - - Schema: map[string]*schema.Schema{ - - isInstanceProfileName: { - Type: schema.TypeString, - Required: true, - }, - - isInstanceProfileFamily: { - Type: schema.TypeString, - Computed: true, - Description: "The product family this virtual server instance profile belongs to.", - }, - - isInstanceProfileArchitecture: { - Type: schema.TypeString, - Computed: true, - Description: "The default OS architecture for an instance with this profile.", - }, - - "architecture_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for the OS architecture.", - }, - - "architecture_values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The supported OS architecture(s) for an instance with this profile.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - - "bandwidth": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "disks": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Collection of the instance profile's disks.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "quantity": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "size": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "supported_interface_types": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The supported disk interfaces used for attaching the disk.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - }, - }, - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this virtual server instance profile.", - }, - "memory": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "port_speed": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - }, - }, - }, - "vcpu_architecture": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default VCPU architecture for an instance with this profile.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The VCPU architecture for an instance with this profile.", - }, - }, - }, - }, - "vcpu_count": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstanceProfileRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isInstanceProfileName).(string) - err := instanceProfileGet(d, meta, name) - if err != nil { - return err - } - return nil -} - -func instanceProfileGet(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - getInstanceProfileOptions := &vpcv1.GetInstanceProfileOptions{ - Name: &name, - } - profile, _, err := sess.GetInstanceProfile(getInstanceProfileOptions) - if err != nil { - return err - } - // For lack of anything better, compose our id from profile name. - d.SetId(*profile.Name) - d.Set(isInstanceProfileName, *profile.Name) - d.Set(isInstanceProfileFamily, *profile.Family) - if profile.OsArchitecture != nil { - if profile.OsArchitecture.Default != nil { - d.Set(isInstanceProfileArchitecture, *profile.OsArchitecture.Default) - } - if profile.OsArchitecture.Type != nil { - d.Set("architecture_type", *profile.OsArchitecture.Type) - } - if profile.OsArchitecture.Values != nil { - d.Set("architecture_values", *&profile.OsArchitecture.Values) - } - - } - if profile.Bandwidth != nil { - err = d.Set("bandwidth", dataSourceInstanceProfileFlattenBandwidth(*profile.Bandwidth.(*vpcv1.InstanceProfileBandwidth))) - if err != nil { - return err - } - } - if profile.Disks != nil { - err = d.Set("disks", dataSourceInstanceProfileFlattenDisks(profile.Disks)) - if err != nil { - return err - } - } - if err = d.Set("href", profile.Href); err != nil { - return err - } - - if profile.Memory != nil { - err = d.Set("memory", dataSourceInstanceProfileFlattenMemory(*profile.Memory.(*vpcv1.InstanceProfileMemory))) - if err != nil { - return err - } - } - if profile.PortSpeed != nil { - err = d.Set("port_speed", dataSourceInstanceProfileFlattenPortSpeed(*profile.PortSpeed.(*vpcv1.InstanceProfilePortSpeed))) - if err != nil { - return err - } - } - - if profile.VcpuArchitecture != nil { - err = d.Set("vcpu_architecture", dataSourceInstanceProfileFlattenVcpuArchitecture(*profile.VcpuArchitecture)) - if err != nil { - return err - } - } - - if profile.VcpuCount != nil { - err = d.Set("vcpu_count", dataSourceInstanceProfileFlattenVcpuCount(*profile.VcpuCount.(*vpcv1.InstanceProfileVcpu))) - if err != nil { - return err - } - } - return nil -} - -func dataSourceInstanceProfileFlattenBandwidth(result vpcv1.InstanceProfileBandwidth) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceInstanceProfileBandwidthToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceInstanceProfileBandwidthToMap(bandwidthItem vpcv1.InstanceProfileBandwidth) (bandwidthMap map[string]interface{}) { - bandwidthMap = map[string]interface{}{} - - if bandwidthItem.Type != nil { - bandwidthMap["type"] = bandwidthItem.Type - } - if bandwidthItem.Value != nil { - bandwidthMap["value"] = bandwidthItem.Value - } - if bandwidthItem.Default != nil { - bandwidthMap["default"] = bandwidthItem.Default - } - if bandwidthItem.Max != nil { - bandwidthMap["max"] = bandwidthItem.Max - } - if bandwidthItem.Min != nil { - bandwidthMap["min"] = bandwidthItem.Min - } - if bandwidthItem.Step != nil { - bandwidthMap["step"] = bandwidthItem.Step - } - if bandwidthItem.Values != nil { - bandwidthMap["values"] = bandwidthItem.Values - } - - return bandwidthMap -} - -func dataSourceInstanceProfileFlattenMemory(result vpcv1.InstanceProfileMemory) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceInstanceProfileMemoryToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceInstanceProfileMemoryToMap(memoryItem vpcv1.InstanceProfileMemory) (memoryMap map[string]interface{}) { - memoryMap = map[string]interface{}{} - - if memoryItem.Type != nil { - memoryMap["type"] = memoryItem.Type - } - if memoryItem.Value != nil { - memoryMap["value"] = memoryItem.Value - } - if memoryItem.Default != nil { - memoryMap["default"] = memoryItem.Default - } - if memoryItem.Max != nil { - memoryMap["max"] = memoryItem.Max - } - if memoryItem.Min != nil { - memoryMap["min"] = memoryItem.Min - } - if memoryItem.Step != nil { - memoryMap["step"] = memoryItem.Step - } - if memoryItem.Values != nil { - memoryMap["values"] = memoryItem.Values - } - - return memoryMap -} - -func dataSourceInstanceProfileFlattenPortSpeed(result vpcv1.InstanceProfilePortSpeed) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceInstanceProfilePortSpeedToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceInstanceProfilePortSpeedToMap(portSpeedItem vpcv1.InstanceProfilePortSpeed) (portSpeedMap map[string]interface{}) { - portSpeedMap = map[string]interface{}{} - - if portSpeedItem.Type != nil { - portSpeedMap["type"] = portSpeedItem.Type - } - if portSpeedItem.Value != nil { - portSpeedMap["value"] = portSpeedItem.Value - } - - return portSpeedMap -} - -func dataSourceInstanceProfileFlattenVcpuArchitecture(result vpcv1.InstanceProfileVcpuArchitecture) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceInstanceProfileVcpuArchitectureToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceInstanceProfileVcpuArchitectureToMap(vcpuArchitectureItem vpcv1.InstanceProfileVcpuArchitecture) (vcpuArchitectureMap map[string]interface{}) { - vcpuArchitectureMap = map[string]interface{}{} - - if vcpuArchitectureItem.Default != nil { - vcpuArchitectureMap["default"] = vcpuArchitectureItem.Default - } - if vcpuArchitectureItem.Type != nil { - vcpuArchitectureMap["type"] = vcpuArchitectureItem.Type - } - if vcpuArchitectureItem.Value != nil { - vcpuArchitectureMap["value"] = vcpuArchitectureItem.Value - } - - return vcpuArchitectureMap -} - -func dataSourceInstanceProfileFlattenVcpuCount(result vpcv1.InstanceProfileVcpu) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceInstanceProfileVcpuCountToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceInstanceProfileVcpuCountToMap(vcpuCountItem vpcv1.InstanceProfileVcpu) (vcpuCountMap map[string]interface{}) { - vcpuCountMap = map[string]interface{}{} - - if vcpuCountItem.Type != nil { - vcpuCountMap["type"] = vcpuCountItem.Type - } - if vcpuCountItem.Value != nil { - vcpuCountMap["value"] = vcpuCountItem.Value - } - if vcpuCountItem.Default != nil { - vcpuCountMap["default"] = vcpuCountItem.Default - } - if vcpuCountItem.Max != nil { - vcpuCountMap["max"] = vcpuCountItem.Max - } - if vcpuCountItem.Min != nil { - vcpuCountMap["min"] = vcpuCountItem.Min - } - if vcpuCountItem.Step != nil { - vcpuCountMap["step"] = vcpuCountItem.Step - } - if vcpuCountItem.Values != nil { - vcpuCountMap["values"] = vcpuCountItem.Values - } - - return vcpuCountMap -} - -func dataSourceInstanceProfileFlattenDisks(result []vpcv1.InstanceProfileDisk) (disks []map[string]interface{}) { - for _, disksItem := range result { - disks = append(disks, dataSourceInstanceProfileDisksToMap(disksItem)) - } - - return disks -} - -func dataSourceInstanceProfileDisksToMap(disksItem vpcv1.InstanceProfileDisk) (disksMap map[string]interface{}) { - disksMap = map[string]interface{}{} - - if disksItem.Quantity != nil { - quantityList := []map[string]interface{}{} - quantityMap := dataSourceInstanceProfileDisksQuantityToMap(*disksItem.Quantity.(*vpcv1.InstanceProfileDiskQuantity)) - quantityList = append(quantityList, quantityMap) - disksMap["quantity"] = quantityList - } - if disksItem.Size != nil { - sizeList := []map[string]interface{}{} - sizeMap := dataSourceInstanceProfileDisksSizeToMap(*disksItem.Size.(*vpcv1.InstanceProfileDiskSize)) - sizeList = append(sizeList, sizeMap) - disksMap["size"] = sizeList - } - if disksItem.SupportedInterfaceTypes != nil { - supportedInterfaceTypesList := []map[string]interface{}{} - supportedInterfaceTypesMap := dataSourceInstanceProfileDisksSupportedInterfaceTypesToMap(*disksItem.SupportedInterfaceTypes) - supportedInterfaceTypesList = append(supportedInterfaceTypesList, supportedInterfaceTypesMap) - disksMap["supported_interface_types"] = supportedInterfaceTypesList - } - - return disksMap -} - -func dataSourceInstanceProfileDisksQuantityToMap(quantityItem vpcv1.InstanceProfileDiskQuantity) (quantityMap map[string]interface{}) { - quantityMap = map[string]interface{}{} - - if quantityItem.Type != nil { - quantityMap["type"] = quantityItem.Type - } - if quantityItem.Value != nil { - quantityMap["value"] = quantityItem.Value - } - if quantityItem.Default != nil { - quantityMap["default"] = quantityItem.Default - } - if quantityItem.Max != nil { - quantityMap["max"] = quantityItem.Max - } - if quantityItem.Min != nil { - quantityMap["min"] = quantityItem.Min - } - if quantityItem.Step != nil { - quantityMap["step"] = quantityItem.Step - } - if quantityItem.Values != nil { - quantityMap["values"] = quantityItem.Values - } - - return quantityMap -} - -func dataSourceInstanceProfileDisksSizeToMap(sizeItem vpcv1.InstanceProfileDiskSize) (sizeMap map[string]interface{}) { - sizeMap = map[string]interface{}{} - - if sizeItem.Type != nil { - sizeMap["type"] = sizeItem.Type - } - if sizeItem.Value != nil { - sizeMap["value"] = sizeItem.Value - } - if sizeItem.Default != nil { - sizeMap["default"] = sizeItem.Default - } - if sizeItem.Max != nil { - sizeMap["max"] = sizeItem.Max - } - if sizeItem.Min != nil { - sizeMap["min"] = sizeItem.Min - } - if sizeItem.Step != nil { - sizeMap["step"] = sizeItem.Step - } - if sizeItem.Values != nil { - sizeMap["values"] = sizeItem.Values - } - - return sizeMap -} - -func dataSourceInstanceProfileDisksSupportedInterfaceTypesToMap(supportedInterfaceTypesItem vpcv1.InstanceProfileDiskSupportedInterfaces) (supportedInterfaceTypesMap map[string]interface{}) { - supportedInterfaceTypesMap = map[string]interface{}{} - - if supportedInterfaceTypesItem.Default != nil { - supportedInterfaceTypesMap["default"] = supportedInterfaceTypesItem.Default - } - if supportedInterfaceTypesItem.Type != nil { - supportedInterfaceTypesMap["type"] = supportedInterfaceTypesItem.Type - } - if supportedInterfaceTypesItem.Values != nil { - supportedInterfaceTypesMap["values"] = supportedInterfaceTypesItem.Values - } - - return supportedInterfaceTypesMap -} diff --git a/ibm/data_source_ibm_is_instance_profiles.go b/ibm/data_source_ibm_is_instance_profiles.go deleted file mode 100644 index 444606078..000000000 --- a/ibm/data_source_ibm_is_instance_profiles.go +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceProfiles = "profiles" -) - -func dataSourceIBMISInstanceProfiles() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISInstanceProfilesRead, - - Schema: map[string]*schema.Schema{ - - isInstanceProfiles: { - Type: schema.TypeList, - Description: "List of instance profile maps", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "family": { - Type: schema.TypeString, - Computed: true, - Description: "The product family this virtual server instance profile belongs to.", - }, - "architecture": { - Type: schema.TypeString, - Computed: true, - Description: "The default OS architecture for an instance with this profile.", - }, - "architecture_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for the OS architecture.", - }, - - "architecture_values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The supported OS architecture(s) for an instance with this profile.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "bandwidth": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "disks": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Collection of the instance profile's disks.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "quantity": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "size": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "supported_interface_types": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The supported disk interfaces used for attaching the disk.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - }, - }, - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this virtual server instance profile.", - }, - "memory": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - "port_speed": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - }, - }, - }, - "vcpu_architecture": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default VCPU architecture for an instance with this profile.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The VCPU architecture for an instance with this profile.", - }, - }, - }, - }, - "vcpu_count": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type for this profile field.", - }, - "value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The value for this profile field.", - }, - "default": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The default value for this profile field.", - }, - "max": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The maximum value for this profile field.", - }, - "min": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The minimum value for this profile field.", - }, - "step": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The increment step value for this profile field.", - }, - "values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The permitted values for this profile field.", - Elem: &schema.Schema{ - Type: schema.TypeInt, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstanceProfilesRead(d *schema.ResourceData, meta interface{}) error { - err := instanceProfilesList(d, meta) - if err != nil { - return err - } - return nil -} - -func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - listInstanceProfilesOptions := &vpcv1.ListInstanceProfilesOptions{} - availableProfiles, response, err := sess.ListInstanceProfiles(listInstanceProfilesOptions) - if err != nil { - return fmt.Errorf("Error Fetching Instance Profiles %s\n%s", err, response) - } - profilesInfo := make([]map[string]interface{}, 0) - for _, profile := range availableProfiles.Profiles { - - l := map[string]interface{}{ - "name": *profile.Name, - "family": *profile.Family, - } - if profile.OsArchitecture != nil { - if profile.OsArchitecture.Default != nil { - l["architecture"] = *profile.OsArchitecture.Default - } - if profile.OsArchitecture.Type != nil { - l["architecture_type"] = profile.OsArchitecture.Type - } - if profile.OsArchitecture.Values != nil { - l["architecture_values"] = profile.OsArchitecture.Values - } - } - if profile.Bandwidth != nil { - bandwidthList := []map[string]interface{}{} - bandwidthMap := dataSourceInstanceProfileBandwidthToMap(*profile.Bandwidth.(*vpcv1.InstanceProfileBandwidth)) - bandwidthList = append(bandwidthList, bandwidthMap) - l["bandwidth"] = bandwidthList - } - if profile.Disks != nil { - disksList := []map[string]interface{}{} - for _, disksItem := range profile.Disks { - disksList = append(disksList, dataSourceInstanceProfileDisksToMap(disksItem)) - } - l["disks"] = disksList - } - if profile.Href != nil { - l["href"] = profile.Href - } - if profile.Memory != nil { - memoryList := []map[string]interface{}{} - memoryMap := dataSourceInstanceProfileMemoryToMap(*profile.Memory.(*vpcv1.InstanceProfileMemory)) - memoryList = append(memoryList, memoryMap) - l["memory"] = memoryList - } - if profile.PortSpeed != nil { - portSpeedList := []map[string]interface{}{} - portSpeedMap := dataSourceInstanceProfilePortSpeedToMap(*profile.PortSpeed.(*vpcv1.InstanceProfilePortSpeed)) - portSpeedList = append(portSpeedList, portSpeedMap) - l["port_speed"] = portSpeedList - } - if profile.VcpuArchitecture != nil { - vcpuArchitectureList := []map[string]interface{}{} - vcpuArchitectureMap := dataSourceInstanceProfileVcpuArchitectureToMap(*profile.VcpuArchitecture) - vcpuArchitectureList = append(vcpuArchitectureList, vcpuArchitectureMap) - l["vcpu_architecture"] = vcpuArchitectureList - } - if profile.VcpuCount != nil { - vcpuCountList := []map[string]interface{}{} - vcpuCountMap := dataSourceInstanceProfileVcpuCountToMap(*profile.VcpuCount.(*vpcv1.InstanceProfileVcpu)) - vcpuCountList = append(vcpuCountList, vcpuCountMap) - l["vcpu_count"] = vcpuCountList - } - if profile.Disks != nil { - l[isInstanceDisks] = dataSourceInstanceProfileFlattenDisks(profile.Disks) - if err != nil { - return fmt.Errorf("Error setting disks %s", err) - } - } - profilesInfo = append(profilesInfo, l) - } - d.SetId(dataSourceIBMISInstanceProfilesID(d)) - d.Set(isInstanceProfiles, profilesInfo) - return nil -} - -// dataSourceIBMISInstanceProfilesID returns a reasonable ID for a Instance Profile list. -func dataSourceIBMISInstanceProfilesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_instance_template.go b/ibm/data_source_ibm_is_instance_template.go deleted file mode 100644 index b15d3f9e7..000000000 --- a/ibm/data_source_ibm_is_instance_template.go +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceTemplateHref = "href" - isInstanceTemplateCrn = "crn" - isInstanceTemplateLimit = "limit" - isInstanceTemplateNext = "next" - isInstanceTemplateTotalCount = "total_count" - isInstanceTemplatePortSpeed = "port_speed" - isInstanceTemplatePortType = "type" - isInstanceTemplatePortValue = "value" - isInstanceTemplateDeleteVol = "delete_volume_on_instance_delete" - isInstanceTemplateVol = "volume" - isInstanceTemplateMemory = "memory" - isInstanceTemplateMemoryValue = "value" - isInstanceTemplateMemoryType = "type" - isInstanceTemplateMemoryValues = "values" - isInstanceTemplateMemoryDefault = "default" - isInstanceTemplateMemoryMin = "min" - isInstanceTemplateMemoryMax = "max" - isInstanceTemplateMemoryStep = "step" - isInstanceTemplateSocketCount = "socket_count" - isInstanceTemplateSocketValue = "value" - isInstanceTemplateSocketType = "type" - isInstanceTemplateSocketValues = "values" - isInstanceTemplateSocketDefault = "default" - isInstanceTemplateSocketMin = "min" - isInstanceTemplateSocketMax = "max" - isInstanceTemplateSocketStep = "step" - isInstanceTemplateVcpuArch = "vcpu_architecture" - isInstanceTemplateVcpuArchType = "type" - isInstanceTemplateVcpuArchValue = "value" - isInstanceTemplateVcpuCount = "vcpu_count" - isInstanceTemplateVcpuCountValue = "value" - isInstanceTemplateVcpuCountType = "type" - isInstanceTemplateVcpuCountValues = "values" - isInstanceTemplateVcpuCountDefault = "default" - isInstanceTemplateVcpuCountMin = "min" - isInstanceTemplateVcpuCountMax = "max" - isInstanceTemplateVcpuCountStep = "step" - isInstanceTemplateStart = "start" - isInstanceTemplateVersion = "version" - isInstanceTemplateBootVolumeAttachment = "boot_volume_attachment" -) - -func dataSourceIBMISInstanceTemplate() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMISInstanceTemplateRead, - Schema: map[string]*schema.Schema{ - "identifier": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ExactlyOneOf: []string{"identifier", isInstanceTemplateName}, - }, - isInstanceTemplateName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ExactlyOneOf: []string{"identifier", isInstanceTemplateName}, - }, - isInstanceTemplateHref: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateCrn: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVPC: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateZone: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateProfile: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateKeys: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - isInstanceTemplateVolumeAttachments: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateDeleteVol: { - Type: schema.TypeBool, - Computed: true, - }, - isInstanceTemplateName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVol: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVolAttVolPrototype: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateVolAttVolIops: { - Type: schema.TypeInt, - Computed: true, - Description: "The maximum I/O operations per second (IOPS) for the volume.", - }, - isInstanceTemplateVolAttVolProfile: { - Type: schema.TypeString, - Computed: true, - Description: "The globally unique name for the volume profile to use for this volume.", - }, - isInstanceTemplateVolAttVolCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", - }, - isInstanceTemplateVolAttVolEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", - }, - }, - }, - }, - }, - }, - }, - isInstanceTemplatePrimaryNetworkInterface: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - isInstanceTemplateNetworkInterfaces: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - isInstanceTemplateUserData: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateImage: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateBootVolumeAttachment: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateDeleteVol: { - Type: schema.TypeBool, - Computed: true, - }, - isInstanceTemplateName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVol: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateBootSize: { - Type: schema.TypeInt, - Computed: true, - }, - isInstanceTemplateBootProfile: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - isInstanceTemplateResourceGroup: { - Type: schema.TypeString, - Computed: true, - }, - "placement_target": { - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions to use for the virtual server instance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this dedicated host.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this dedicated host.", - }, - "href": { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this dedicated host.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - instanceC, err := meta.(ClientSession).VpcV1API() - if err != nil { - return diag.FromErr(err) - } - if idOk, ok := d.GetOk("identifier"); ok { - id := idOk.(string) - getInstanceTemplatesOptions := &vpcv1.GetInstanceTemplateOptions{ - ID: &id, - } - instTempl, _, err := instanceC.GetInstanceTemplate(getInstanceTemplatesOptions) - if err != nil { - return diag.FromErr(err) - } - instance := instTempl.(*vpcv1.InstanceTemplate) - d.SetId(*instance.ID) - d.Set(isInstanceTemplateHref, instance.Href) - d.Set(isInstanceTemplateCrn, instance.CRN) - d.Set(isInstanceTemplateName, instance.Name) - d.Set(isInstanceTemplateUserData, instance.UserData) - - if instance.Keys != nil { - keys := []string{} - for _, intfc := range instance.Keys { - instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) - keys = append(keys, *instanceKeyIntf.ID) - } - d.Set(isInstanceTemplateKeys, keys) - } - if instance.Profile != nil { - instanceProfileIntf := instance.Profile - identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) - d.Set(isInstanceTemplateProfile, *identity.Name) - } - - if instance.PlacementTarget != nil { - placementTargetList := []map[string]interface{}{} - placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - placementTargetList = append(placementTargetList, placementTargetMap) - d.Set("placement_target", placementTargetList) - } - - if instance.PrimaryNetworkInterface != nil { - interfaceList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name - if instance.PrimaryNetworkInterface.PrimaryIpv4Address != nil { - currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - } - subInf := instance.PrimaryNetworkInterface.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - - if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { - secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentPrimNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfaceList = append(interfaceList, currentPrimNic) - d.Set(isInstanceTemplatePrimaryNetworkInterface, interfaceList) - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - currentNic := map[string]interface{}{} - currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - } - //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing - subInf := intfc.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if len(intfc.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(intfc.SecurityGroups); i++ { - secGrpInf := intfc.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - interfacesList = append(interfacesList, currentNic) - } - d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) - } - - if instance.Image != nil { - imageInf := instance.Image - imageIdentity := imageInf.(*vpcv1.ImageIdentity) - d.Set(isInstanceTemplateImage, imageIdentity.ID) - } - - if instance.VPC != nil { - vpcInf := instance.VPC - vpcRef := vpcInf.(*vpcv1.VPCIdentity) - d.Set(isInstanceTemplateVPC, vpcRef.ID) - } - - if instance.Zone != nil { - zoneInf := instance.Zone - zone := zoneInf.(*vpcv1.ZoneIdentity) - d.Set(isInstanceTemplateZone, zone.Name) - } - - interfacesList := make([]map[string]interface{}, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - volumeAttach := map[string]interface{}{} - volumeAttach[isInstanceTemplateVolAttName] = *volume.Name - volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - newVolumeArr := []map[string]interface{}{} - newVolume := map[string]interface{}{} - - if volumeInst.ID != nil { - volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID - } - - if volumeInst.Capacity != nil { - newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity - } - if volumeInst.Profile != nil { - profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) - newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name - } - - if volumeInst.Iops != nil { - newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops - } - if volumeInst.EncryptionKey != nil { - encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) - newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN - } - newVolumeArr = append(newVolumeArr, newVolume) - volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr - - interfacesList = append(interfacesList, volumeAttach) - } - d.Set(isInstanceTemplateVolumeAttachments, interfacesList) - } - - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - - bootVol[isInstanceTemplateDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete - if instance.BootVolumeAttachment.Volume != nil { - volumeIntf := instance.BootVolumeAttachment.Volume - bootVol[isInstanceTemplateName] = volumeIntf.Name - bootVol[isInstanceTemplateVol] = volumeIntf.Name - bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity - if instance.BootVolumeAttachment.Volume.Profile != nil { - volProfIntf := instance.BootVolumeAttachment.Volume.Profile - volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) - bootVol[isInstanceTemplateBootProfile] = volProfInst.Name - } - } - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceTemplateBootVolumeAttachment, bootVolList) - } - - if instance.ResourceGroup != nil { - rg := instance.ResourceGroup - d.Set(isInstanceTemplateResourceGroup, rg.ID) - } - } else if nameOk, ok := d.GetOk(isInstanceTemplateName); ok { - name := nameOk.(string) - listInstanceTemplatesOptions := &vpcv1.ListInstanceTemplatesOptions{} - availableTemplates, _, err := instanceC.ListInstanceTemplates(listInstanceTemplatesOptions) - if err != nil { - return diag.FromErr(err) - } - flag := false - for _, instTempl := range availableTemplates.Templates { - instance := instTempl.(*vpcv1.InstanceTemplate) - if name == *instance.Name { - flag = true - d.SetId(*instance.ID) - d.Set(isInstanceTemplateHref, instance.Href) - d.Set(isInstanceTemplateCrn, instance.CRN) - d.Set(isInstanceTemplateName, instance.Name) - d.Set(isInstanceTemplateUserData, instance.UserData) - - if instance.Keys != nil { - keys := []string{} - for _, intfc := range instance.Keys { - instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) - keys = append(keys, *instanceKeyIntf.ID) - } - d.Set(isInstanceTemplateKeys, keys) - } - if instance.Profile != nil { - instanceProfileIntf := instance.Profile - identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) - d.Set(isInstanceTemplateProfile, identity.Name) - } - - if instance.PlacementTarget != nil { - placementTargetList := []map[string]interface{}{} - placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - placementTargetList = append(placementTargetList, placementTargetMap) - d.Set("placement_target", placementTargetList) - } - - if instance.PrimaryNetworkInterface != nil { - interfaceList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name - if instance.PrimaryNetworkInterface.PrimaryIpv4Address != nil { - currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - } - subInf := instance.PrimaryNetworkInterface.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - - if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { - secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentPrimNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfaceList = append(interfaceList, currentPrimNic) - d.Set(isInstanceTemplatePrimaryNetworkInterface, interfaceList) - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - currentNic := map[string]interface{}{} - currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - } - //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing - subInf := intfc.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if len(intfc.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(intfc.SecurityGroups); i++ { - secGrpInf := intfc.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - interfacesList = append(interfacesList, currentNic) - } - d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) - } - - if instance.Image != nil { - imageInf := instance.Image - imageIdentity := imageInf.(*vpcv1.ImageIdentity) - d.Set(isInstanceTemplateImage, imageIdentity.ID) - } - - if instance.VPC != nil { - vpcInf := instance.VPC - vpcRef := vpcInf.(*vpcv1.VPCIdentity) - d.Set(isInstanceTemplateVPC, vpcRef.ID) - } - - if instance.Zone != nil { - zoneInf := instance.Zone - zone := zoneInf.(*vpcv1.ZoneIdentity) - d.Set(isInstanceTemplateZone, zone.Name) - } - - interfacesList := make([]map[string]interface{}, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - volumeAttach := map[string]interface{}{} - volumeAttach[isInstanceTemplateVolAttName] = *volume.Name - volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - newVolumeArr := []map[string]interface{}{} - newVolume := map[string]interface{}{} - - if volumeInst.ID != nil { - volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID - } - - if volumeInst.Capacity != nil { - newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity - } - if volumeInst.Profile != nil { - profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) - newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name - } - - if volumeInst.Iops != nil { - newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops - } - if volumeInst.EncryptionKey != nil { - encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) - newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN - } - newVolumeArr = append(newVolumeArr, newVolume) - volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr - - interfacesList = append(interfacesList, volumeAttach) - } - d.Set(isInstanceTemplateVolumeAttachments, interfacesList) - } - - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - - bootVol[isInstanceTemplateDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete - if instance.BootVolumeAttachment.Volume != nil { - volumeIntf := instance.BootVolumeAttachment.Volume - bootVol[isInstanceTemplateName] = volumeIntf.Name - bootVol[isInstanceTemplateVol] = volumeIntf.Name - bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity - if instance.BootVolumeAttachment.Volume.Profile != nil { - volProfIntf := instance.BootVolumeAttachment.Volume.Profile - volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) - bootVol[isInstanceTemplateBootProfile] = volProfInst.Name - } - } - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceTemplateBootVolumeAttachment, bootVolList) - } - - if instance.ResourceGroup != nil { - rg := instance.ResourceGroup - d.Set(isInstanceTemplateResourceGroup, rg.ID) - } - } - } - if !flag { - return diag.FromErr(fmt.Errorf("No Instance Template found with name %s", name)) - } - } - return nil -} - -func dataSourceInstanceTemplateCollectionTemplatePlacementTargetToMap(placementTargetItem vpcv1.InstancePlacementTargetPrototype) (placementTargetMap map[string]interface{}) { - placementTargetMap = map[string]interface{}{} - - if placementTargetItem.ID != nil { - placementTargetMap["id"] = placementTargetItem.ID - } - if placementTargetItem.CRN != nil { - placementTargetMap["crn"] = placementTargetItem.CRN - } - if placementTargetItem.Href != nil { - placementTargetMap["href"] = placementTargetItem.Href - } - - return placementTargetMap -} diff --git a/ibm/data_source_ibm_is_instance_template_test.go b/ibm/data_source_ibm_is_instance_template_test.go deleted file mode 100644 index ed1ac6eaa..000000000 --- a/ibm/data_source_ibm_is_instance_template_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISInstanceTemplate_dataBasic(t *testing.T) { - randInt := acctest.RandIntRange(600, 700) - publicKey := strings.TrimSpace(` - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 - `) - vpcName := fmt.Sprintf("testvpc%d", randInt) - subnetName := fmt.Sprintf("testsubnet%d", randInt) - templateName := fmt.Sprintf("testtemplate%d", randInt) - sshKeyName := fmt.Sprintf("testsshkey%d", randInt) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.ibm_is_instance_template.instance_template_data", "name", templateName), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { - return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` - data "ibm_is_instance_template" "instance_template_data" { - name = ibm_is_instance_template.instancetemplate1.name - } - `) -} diff --git a/ibm/data_source_ibm_is_instance_templates.go b/ibm/data_source_ibm_is_instance_templates.go deleted file mode 100644 index 43845fbe5..000000000 --- a/ibm/data_source_ibm_is_instance_templates.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceTemplates = "templates" - isInstanceTemplatesFirst = "first" - isInstanceTemplatesHref = "href" - isInstanceTemplatesCrn = "crn" - isInstanceTemplatesLimit = "limit" - isInstanceTemplatesNext = "next" - isInstanceTemplatesTotalCount = "total_count" - isInstanceTemplatesName = "name" - isInstanceTemplatesPortSpeed = "port_speed" - isInstanceTemplatesPortType = "type" - isInstanceTemplatesPortValue = "value" - isInstanceTemplatesDeleteVol = "delete_volume_on_instance_delete" - isInstanceTemplatesVol = "volume" - isInstanceTemplatesMemory = "memory" - isInstanceTemplatesMemoryValue = "value" - isInstanceTemplatesMemoryType = "type" - isInstanceTemplatesMemoryValues = "values" - isInstanceTemplatesMemoryDefault = "default" - isInstanceTemplatesMemoryMin = "min" - isInstanceTemplatesMemoryMax = "max" - isInstanceTemplatesMemoryStep = "step" - isInstanceTemplatesSocketCount = "socket_count" - isInstanceTemplatesSocketValue = "value" - isInstanceTemplatesSocketType = "type" - isInstanceTemplatesSocketValues = "values" - isInstanceTemplatesSocketDefault = "default" - isInstanceTemplatesSocketMin = "min" - isInstanceTemplatesSocketMax = "max" - isInstanceTemplatesSocketStep = "step" - isInstanceTemplatesVcpuArch = "vcpu_architecture" - isInstanceTemplatesVcpuArchType = "type" - isInstanceTemplatesVcpuArchValue = "value" - isInstanceTemplatesVcpuCount = "vcpu_count" - isInstanceTemplatesVcpuCountValue = "value" - isInstanceTemplatesVcpuCountType = "type" - isInstanceTemplatesVcpuCountValues = "values" - isInstanceTemplatesVcpuCountDefault = "default" - isInstanceTemplatesVcpuCountMin = "min" - isInstanceTemplatesVcpuCountMax = "max" - isInstanceTemplatesVcpuCountStep = "step" - isInstanceTemplatesStart = "start" - isInstanceTemplatesVersion = "version" - isInstanceTemplatesGeneration = "generation" - isInstanceTemplatesBootVolumeAttachment = "boot_volume_attachment" - - isInstanceTemplateVPC = "vpc" - isInstanceTemplateZone = "zone" - isInstanceTemplateProfile = "profile" - isInstanceTemplateKeys = "keys" - isInstanceTemplateVolumeAttachments = "volume_attachments" - isInstanceTemplateNetworkInterfaces = "network_interfaces" - isInstanceTemplatePrimaryNetworkInterface = "primary_network_interface" - isInstanceTemplateNicName = "name" - isInstanceTemplateNicPortSpeed = "port_speed" - isInstanceTemplateNicAllowIPSpoofing = "allow_ip_spoofing" - isInstanceTemplateNicPrimaryIpv4Address = "primary_ipv4_address" - isInstanceTemplateNicSecondaryAddress = "secondary_addresses" - isInstanceTemplateNicSecurityGroups = "security_groups" - isInstanceTemplateNicSubnet = "subnet" - isInstanceTemplateNicFloatingIPs = "floating_ips" - isInstanceTemplateUserData = "user_data" - isInstanceTemplateGeneration = "generation" - isInstanceTemplateImage = "image" - isInstanceTemplateResourceGroup = "resource_group" - isInstanceTemplateName = "name" - isInstanceTemplateDeleteVolume = "delete_volume_on_instance_delete" - isInstanceTemplateVolAttName = "name" - isInstanceTemplateVolAttVolume = "volume" -) - -func dataSourceIBMISInstanceTemplates() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISInstanceTemplatesRead, - Schema: map[string]*schema.Schema{ - isInstanceTemplates: { - Type: schema.TypeList, - Description: "Collection of instance templates", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesHref: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesCrn: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVPC: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateZone: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateProfile: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateKeys: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - isInstanceTemplateVolumeAttachments: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplatesDeleteVol: { - Type: schema.TypeBool, - Computed: true, - }, - isInstanceTemplatesName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesVol: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVolAttVolPrototype: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateVolAttVolIops: { - Type: schema.TypeInt, - Computed: true, - Description: "The maximum I/O operations per second (IOPS) for the volume.", - }, - isInstanceTemplateVolAttVolProfile: { - Type: schema.TypeString, - Computed: true, - Description: "The globally unique name for the volume profile to use for this volume.", - }, - isInstanceTemplateVolAttVolCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", - }, - isInstanceTemplateVolAttVolEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", - }, - }, - }, - }, - }, - }, - }, - - "placement_target": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions for the virtual server instance. For the target tobe changed, the instance `status` must be `stopping` or `stopped`.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this dedicated host.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this dedicated host.", - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this dedicated host.", - }, - }, - }, - }, - - isInstanceTemplatePrimaryNetworkInterface: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - isInstanceTemplateNetworkInterfaces: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - isInstanceTemplateUserData: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateImage: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesBootVolumeAttachment: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplatesDeleteVol: { - Type: schema.TypeBool, - Computed: true, - }, - isInstanceTemplatesName: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplatesVol: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateBootSize: { - Type: schema.TypeInt, - Computed: true, - }, - isInstanceTemplateBootProfile: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - isInstanceTemplateResourceGroup: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface{}) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - listInstanceTemplatesOptions := &vpcv1.ListInstanceTemplatesOptions{} - availableTemplates, _, err := instanceC.ListInstanceTemplates(listInstanceTemplatesOptions) - if err != nil { - return err - } - templates := make([]map[string]interface{}, 0) - for _, instTempl := range availableTemplates.Templates { - template := map[string]interface{}{} - instance := instTempl.(*vpcv1.InstanceTemplate) - template["id"] = instance.ID - template[isInstanceTemplatesHref] = instance.Href - template[isInstanceTemplatesCrn] = instance.CRN - template[isInstanceTemplateName] = instance.Name - template[isInstanceTemplateUserData] = instance.UserData - - if instance.PlacementTarget != nil { - placementTargetMap := resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - template["placement_target"] = []map[string]interface{}{placementTargetMap} - } - - if instance.Keys != nil { - keys := []string{} - for _, intfc := range instance.Keys { - instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) - keys = append(keys, *instanceKeyIntf.ID) - } - template[isInstanceTemplateKeys] = keys - } - if instance.Profile != nil { - instanceProfileIntf := instance.Profile - identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) - template[isInstanceTemplateProfile] = identity.Name - } - - if instance.PlacementTarget != nil { - placementTargetList := []map[string]interface{}{} - placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - placementTargetList = append(placementTargetList, placementTargetMap) - template["placement_target"] = placementTargetList - } - - if instance.PrimaryNetworkInterface != nil { - interfaceList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name - if instance.PrimaryNetworkInterface.PrimaryIpv4Address != nil { - currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - } - subInf := instance.PrimaryNetworkInterface.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - - if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { - secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentPrimNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfaceList = append(interfaceList, currentPrimNic) - template[isInstanceTemplatePrimaryNetworkInterface] = interfaceList - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - currentNic := map[string]interface{}{} - currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - } - //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing - subInf := intfc.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if len(intfc.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(intfc.SecurityGroups); i++ { - secGrpInf := intfc.SecurityGroups[i] - secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) - } - currentNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - interfacesList = append(interfacesList, currentNic) - } - template[isInstanceTemplateNetworkInterfaces] = interfacesList - } - - if instance.Image != nil { - imageInf := instance.Image - imageIdentity := imageInf.(*vpcv1.ImageIdentity) - template[isInstanceTemplateImage] = imageIdentity.ID - } - - if instance.VPC != nil { - vpcInf := instance.VPC - vpcRef := vpcInf.(*vpcv1.VPCIdentity) - template[isInstanceTemplateVPC] = vpcRef.ID - } - - if instance.Zone != nil { - zoneInf := instance.Zone - zone := zoneInf.(*vpcv1.ZoneIdentity) - template[isInstanceTemplateZone] = zone.Name - } - - interfacesList := make([]map[string]interface{}, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - volumeAttach := map[string]interface{}{} - volumeAttach[isInstanceTemplateVolAttName] = *volume.Name - volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - newVolumeArr := []map[string]interface{}{} - newVolume := map[string]interface{}{} - - if volumeInst.ID != nil { - volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID - } - - if volumeInst.Capacity != nil { - newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity - } - if volumeInst.Profile != nil { - profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) - newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name - } - - if volumeInst.Iops != nil { - newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops - } - if volumeInst.EncryptionKey != nil { - encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) - newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN - } - newVolumeArr = append(newVolumeArr, newVolume) - volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr - - interfacesList = append(interfacesList, volumeAttach) - } - template[isInstanceTemplateVolumeAttachments] = interfacesList - } - - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - - bootVol[isInstanceTemplatesDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete - if instance.BootVolumeAttachment.Volume != nil { - volumeIntf := instance.BootVolumeAttachment.Volume - bootVol[isInstanceTemplatesName] = volumeIntf.Name - bootVol[isInstanceTemplatesVol] = volumeIntf.Name - bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity - if instance.BootVolumeAttachment.Volume.Profile != nil { - volProfIntf := instance.BootVolumeAttachment.Volume.Profile - volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) - bootVol[isInstanceTemplateBootProfile] = volProfInst.Name - } - } - bootVolList = append(bootVolList, bootVol) - template[isInstanceTemplatesBootVolumeAttachment] = bootVolList - } - - if instance.ResourceGroup != nil { - rg := instance.ResourceGroup - template[isInstanceTemplateResourceGroup] = rg.ID - } - - templates = append(templates, template) - } - d.SetId(dataSourceIBMISInstanceTemplatesID(d)) - d.Set(isInstanceTemplates, templates) - return nil -} - -// dataSourceIBMISInstanceTemplatesID returns a reasonable ID for a instance templates list. -func dataSourceIBMISInstanceTemplatesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(placementTargetItem vpcv1.InstancePlacementTargetPrototype) (placementTargetMap map[string]interface{}) { - placementTargetMap = map[string]interface{}{} - - if placementTargetItem.ID != nil { - placementTargetMap["id"] = placementTargetItem.ID - } - if placementTargetItem.CRN != nil { - placementTargetMap["crn"] = placementTargetItem.CRN - } - if placementTargetItem.Href != nil { - placementTargetMap["href"] = placementTargetItem.Href - } - - return placementTargetMap -} diff --git a/ibm/data_source_ibm_is_instance_templates_test.go b/ibm/data_source_ibm_is_instance_templates_test.go deleted file mode 100644 index 1651a0491..000000000 --- a/ibm/data_source_ibm_is_instance_templates_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISInstanceTemplates_dataBasic(t *testing.T) { - randInt := acctest.RandIntRange(600, 700) - publicKey := strings.TrimSpace(` - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 - `) - vpcName := fmt.Sprintf("testvpc%d", randInt) - subnetName := fmt.Sprintf("testsubnet%d", randInt) - templateName := fmt.Sprintf("testtemplate%d", randInt) - sshKeyName := fmt.Sprintf("testsshkey%d", randInt) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet( - "data.ibm_is_instance_templates.instance_templates_data", "templates.0.id"), - resource.TestCheckResourceAttrSet( - "data.ibm_is_instance_templates.instance_templates_data", "templates.0.name"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { - return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` - - data "ibm_is_instance_templates" "instance_templates_data" { - } - `) -} diff --git a/ibm/data_source_ibm_is_instance_test.go b/ibm/data_source_ibm_is_instance_test.go deleted file mode 100644 index abcbf19fa..000000000 --- a/ibm/data_source_ibm_is_instance_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISInstanceDataSource_basic(t *testing.T) { - - vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) - sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) - instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) - resName := "data.ibm_is_instance.ds_instance" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISInstanceDataSourceConfig(vpcname, subnetname, sshname, instanceName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - resName, "name", instanceName), - resource.TestCheckResourceAttr( - resName, "tags.#", "1"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceDataSourceConfig(vpcname, subnetname, sshname, instanceName string) string { - return fmt.Sprintf(` -resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" -} - -resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" -} - -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = file("test-fixtures/.ssh/id_rsa.pub") -} - -resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - port_speed = "100" - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - tags = ["tag1"] -} -data "ibm_is_instance" "ds_instance" { - name = ibm_is_instance.testacc_instance.name - private_key = file("test-fixtures/.ssh/id_rsa") - passphrase = "" -}`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, instanceName, isWinImage, instanceProfileName, ISZoneName) -} diff --git a/ibm/data_source_ibm_is_instances.go b/ibm/data_source_ibm_is_instances.go deleted file mode 100644 index 72cd886da..000000000 --- a/ibm/data_source_ibm_is_instances.go +++ /dev/null @@ -1,789 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstances = "instances" - isInstanceGroupName = "instance_group_name" -) - -func dataSourceIBMISInstances() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISInstancesRead, - - Schema: map[string]*schema.Schema{ - isInstanceGroup: { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"vpc", "vpc_crn", "vpc_name", isInstanceGroupName}, - Description: "Instance group ID to filter the instances attached to it", - }, - isInstanceGroupName: { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"vpc", "vpc_crn", "vpc_name", isInstanceGroup}, - Description: "Instance group name to filter the instances attached to it", - }, - "vpc_name": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"vpc", "vpc_crn", "instance_group"}, - Description: "Name of the vpc to filter the instances attached to it", - }, - - "vpc": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"vpc_name", "vpc_crn", "instance_group"}, - Description: "VPC ID to filter the instances attached to it", - }, - - "vpc_crn": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"vpc_name", "vpc", "instance_group"}, - Description: "VPC CRN to filter the instances attached to it", - }, - - "resource_group": { - Type: schema.TypeString, - Optional: true, - Description: "Instance resource group", - }, - - "dedicated_host_name": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"dedicated_host"}, - Description: "Name of the dedicated host to filter the instances attached to it", - }, - - "dedicated_host": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"dedicated_host_name"}, - Description: "ID of the dedicated host to filter the instances attached to it", - }, - - "placement_group_name": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"placement_group"}, - Description: "Name of the placement group to filter the instances attached to it", - }, - - "placement_group": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"placement_group_name"}, - Description: "ID of the placement group to filter the instances attached to it", - }, - - isInstances: { - Type: schema.TypeList, - Description: "List of instances", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance name", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The crn for this Instance", - }, - "memory": { - Type: schema.TypeInt, - Computed: true, - Description: "Instance memory", - }, - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Instance status", - }, - - isInstanceStatusReasons: { - Type: schema.TypeList, - Computed: true, - Description: "The reasons for the current status (if any).", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceStatusReasonsCode: { - Type: schema.TypeString, - Computed: true, - Description: "A snake case string succinctly identifying the status reason", - }, - - isInstanceStatusReasonsMessage: { - Type: schema.TypeString, - Computed: true, - Description: "An explanation of the status reason", - }, - }, - }, - }, - - "resource_group": { - Type: schema.TypeString, - Computed: true, - Description: "Instance resource group", - }, - "vpc": { - Type: schema.TypeString, - Computed: true, - Description: "vpc attached to the instance", - }, - "boot_volume": { - Type: schema.TypeList, - Computed: true, - Description: "Instance Boot Volume", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot volume id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot volume name", - }, - "device": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot volume device", - }, - "volume_id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot volume's volume id", - }, - "volume_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Boot volume's volume CRN", - }, - }, - }, - }, - - "volume_attachments": { - Type: schema.TypeList, - Computed: true, - Description: "Instance Volume Attachments", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance volume Attachment id", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance volume Attachment name", - }, - "volume_id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance volume Attachment's volume id", - }, - "volume_name": { - Type: schema.TypeString, - Computed: true, - Description: "Instance volume Attachment's volume name", - }, - "volume_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Instance volume Attachment's volume CRN", - }, - }, - }, - }, - - "primary_network_interface": { - Type: schema.TypeList, - Computed: true, - Description: "Instance Primary Network Interface", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network interface id", - }, - isInstanceNicName: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network interface name", - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network interface IPV4 Address", - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Instance Primary Network interface security groups", - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Primary Network interface subnet", - }, - }, - }, - }, - "placement_target": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions for the virtual server instance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this placement target resource.", - }, - "deleted": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Link to documentation about deleted resources.", - }, - }, - }, - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this placement target resource.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this placement target resource.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique user-defined name for this placement target resource. If unspecified, the name will be a hyphenated list of randomly-selected words.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of resource referenced.", - }, - }, - }, - }, - "network_interfaces": { - Type: schema.TypeList, - Computed: true, - Description: "Instance Network Interfaces", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network interface id", - }, - isInstanceNicName: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network interface name", - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network interface IPV4 Address", - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Instance Network interface security groups", - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Computed: true, - Description: "Instance Network interface subnet", - }, - }, - }, - }, - "profile": { - Type: schema.TypeString, - Computed: true, - Description: "Instance Profile", - }, - "vcpu": { - Type: schema.TypeList, - Computed: true, - Description: "Instance vcpu", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "architecture": { - Type: schema.TypeString, - Computed: true, - Description: "Instance vcpu architecture", - }, - "count": { - Type: schema.TypeInt, - Computed: true, - Description: "Instance vcpu count", - }, - }, - }, - }, - "zone": { - Type: schema.TypeString, - Computed: true, - Description: "Instance zone", - }, - "image": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Instance Image", - }, - - isInstanceGpu: { - Type: schema.TypeList, - Computed: true, - Description: "Instance GPU", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceGpuCount: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance GPU Count", - }, - isInstanceGpuMemory: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance GPU Memory", - }, - isInstanceGpuManufacturer: { - Type: schema.TypeString, - Computed: true, - Description: "Instance GPU Manufacturer", - }, - isInstanceGpuModel: { - Type: schema.TypeString, - Computed: true, - Description: "Instance GPU Model", - }, - }, - }, - }, - - isInstanceDisks: &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Collection of the instance's disks.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the disk was created.", - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this instance disk.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this instance disk.", - }, - "interface_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user-defined name for this disk.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - "size": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The size of the disk in GB (gigabytes).", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISInstancesRead(d *schema.ResourceData, meta interface{}) error { - - err := instancesList(d, meta) - if err != nil { - return err - } - return nil -} - -func instancesList(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - var vpcName, vpcID, vpcCrn, resourceGroup, insGrp, dHostNameStr, dHostIdStr, placementGrpNameStr, placementGrpIdStr string - - if vpc, ok := d.GetOk("vpc_name"); ok { - vpcName = vpc.(string) - } - - if vpc, ok := d.GetOk("vpc"); ok { - vpcID = vpc.(string) - } - - if vpccrn, ok := d.GetOk("vpc_crn"); ok { - vpcCrn = vpccrn.(string) - } - - if rg, ok := d.GetOk("resource_group"); ok { - resourceGroup = rg.(string) - } - - if dHostNameIntf, ok := d.GetOk("dedicated_host_name"); ok { - dHostNameStr = dHostNameIntf.(string) - } - - if dHostIdIntf, ok := d.GetOk("dedicated_host"); ok { - dHostIdStr = dHostIdIntf.(string) - } - - if placementGrpNameIntf, ok := d.GetOk("placement_group_name"); ok { - placementGrpNameStr = placementGrpNameIntf.(string) - } - - if placementGrpIdIntf, ok := d.GetOk("placement_group"); ok { - placementGrpIdStr = placementGrpIdIntf.(string) - } - - if insGrpInf, ok := d.GetOk(isInstanceGroup); ok { - insGrp = insGrpInf.(string) - } else if insGrpNameInf, ok := d.GetOk(isInstanceGroupName); ok { - insGrpName := insGrpNameInf.(string) - start := "" - allrecs := []vpcv1.InstanceGroup{} - for { - listInstanceGroupOptions := vpcv1.ListInstanceGroupsOptions{} - if start != "" { - listInstanceGroupOptions.Start = &start - } - instanceGroupsCollection, response, err := sess.ListInstanceGroups(&listInstanceGroupOptions) - if err != nil { - return fmt.Errorf("Error Fetching InstanceGroups %s\n%s", err, response) - } - start = GetNext(instanceGroupsCollection.Next) - allrecs = append(allrecs, instanceGroupsCollection.InstanceGroups...) - - if start == "" { - break - } - - } - - for _, instanceGroup := range allrecs { - if *instanceGroup.Name == insGrpName { - insGrp = *instanceGroup.ID - break - } - } - } - - listInstancesOptions := &vpcv1.ListInstancesOptions{} - - if vpcName != "" { - listInstancesOptions.VPCName = &vpcName - } - if vpcID != "" { - listInstancesOptions.VPCID = &vpcID - } - if resourceGroup != "" { - listInstancesOptions.ResourceGroupID = &resourceGroup - } - if vpcCrn != "" { - listInstancesOptions.VPCCRN = &vpcCrn - } - - if dHostNameStr != "" { - listInstancesOptions.DedicatedHostName = &dHostNameStr - } - - if dHostIdStr != "" { - listInstancesOptions.DedicatedHostID = &dHostIdStr - } - - if placementGrpNameStr != "" { - listInstancesOptions.PlacementGroupName = &placementGrpNameStr - } - - if placementGrpIdStr != "" { - listInstancesOptions.PlacementGroupID = &placementGrpIdStr - } - - start := "" - allrecs := []vpcv1.Instance{} - for { - - if start != "" { - listInstancesOptions.Start = &start - } - - instances, response, err := sess.ListInstances(listInstancesOptions) - if err != nil { - return fmt.Errorf("Error Fetching Instances %s\n%s", err, response) - } - start = GetNext(instances.Next) - allrecs = append(allrecs, instances.Instances...) - if start == "" { - break - } - } - - if insGrp != "" { - membershipMap := map[string]bool{} - start := "" - for { - listInstanceGroupMembershipsOptions := vpcv1.ListInstanceGroupMembershipsOptions{ - InstanceGroupID: &insGrp, - } - if start != "" { - listInstanceGroupMembershipsOptions.Start = &start - } - instanceGroupMembershipCollection, response, err := sess.ListInstanceGroupMemberships(&listInstanceGroupMembershipsOptions) - if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Membership Collection %s\n%s", err, response) - } - - start = GetNext(instanceGroupMembershipCollection.Next) - for _, membershipItem := range instanceGroupMembershipCollection.Memberships { - membershipMap[*membershipItem.Instance.ID] = true - } - - if start == "" { - break - } - - } - - //Filtering instance allrecs to contain instance group members only - i := 0 - for _, ins := range allrecs { - if membershipMap[*ins.ID] { - allrecs[i] = ins - i++ - } - } - allrecs = allrecs[:i] - } - - instancesInfo := make([]map[string]interface{}, 0) - for _, instance := range allrecs { - id := *instance.ID - l := map[string]interface{}{} - l["id"] = id - l["crn"] = *instance.CRN - l["name"] = *instance.Name - l["memory"] = *instance.Memory - l["status"] = *instance.Status - l["resource_group"] = *instance.ResourceGroup.ID - l["vpc"] = *instance.VPC.ID - - if instance.PlacementTarget != nil { - placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) - l["placement_target"] = []map[string]interface{}{placementTargetMap} - } - - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - bootVol["id"] = *instance.BootVolumeAttachment.ID - bootVol["name"] = *instance.BootVolumeAttachment.Name - if instance.BootVolumeAttachment.Device != nil { - bootVol["device"] = *instance.BootVolumeAttachment.Device.ID - } - if instance.BootVolumeAttachment.Volume != nil { - bootVol["volume_id"] = *instance.BootVolumeAttachment.Volume.ID - bootVol["volume_crn"] = *instance.BootVolumeAttachment.Volume.CRN - } - bootVolList = append(bootVolList, bootVol) - l["boot_volume"] = bootVolList - } - //set the status reasons - statusReasonsList := make([]map[string]interface{}, 0) - if instance.StatusReasons != nil { - for _, sr := range instance.StatusReasons { - currentSR := map[string]interface{}{} - if sr.Code != nil && sr.Message != nil { - currentSR[isInstanceStatusReasonsCode] = *sr.Code - currentSR[isInstanceStatusReasonsMessage] = *sr.Message - statusReasonsList = append(statusReasonsList, currentSR) - } - } - } - l[isInstanceStatusReasons] = statusReasonsList - - if instance.VolumeAttachments != nil { - volList := make([]map[string]interface{}, 0) - for _, volume := range instance.VolumeAttachments { - vol := map[string]interface{}{} - if volume.Volume != nil { - vol["id"] = *volume.ID - vol["volume_id"] = *volume.Volume.ID - vol["name"] = *volume.Name - vol["volume_name"] = *volume.Volume.Name - vol["volume_crn"] = *volume.Volume.CRN - volList = append(volList, vol) - } - } - l["volume_attachments"] = volList - } - - if instance.PrimaryNetworkInterface != nil { - primaryNicList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID - currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: instance.PrimaryNetworkInterface.ID, - } - insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentPrimNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - primaryNicList = append(primaryNicList, currentPrimNic) - l["primary_network_interface"] = primaryNicList - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - if *intfc.ID != *instance.PrimaryNetworkInterface.ID { - currentNic := map[string]interface{}{} - currentNic["id"] = *intfc.ID - currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: intfc.ID, - } - insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfacesList = append(interfacesList, currentNic) - } - } - l["network_interfaces"] = interfacesList - } - - l["profile"] = *instance.Profile.Name - - cpuList := make([]map[string]interface{}, 0) - if instance.Vcpu != nil { - currentCPU := map[string]interface{}{} - currentCPU["architecture"] = *instance.Vcpu.Architecture - currentCPU["count"] = *instance.Vcpu.Count - cpuList = append(cpuList, currentCPU) - } - l["vcpu"] = cpuList - - gpuList := make([]map[string]interface{}, 0) - if instance.Gpu != nil { - currentGpu := map[string]interface{}{} - currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer - currentGpu[isInstanceGpuModel] = instance.Gpu.Model - currentGpu[isInstanceGpuCount] = instance.Gpu.Count - currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory - gpuList = append(gpuList, currentGpu) - l[isInstanceGpu] = gpuList - } - - l["zone"] = *instance.Zone.Name - if instance.Image != nil { - l["image"] = *instance.Image.ID - } - - if instance.Disks != nil { - l[isInstanceDisks] = dataSourceInstanceFlattenDisks(instance.Disks) - } - - instancesInfo = append(instancesInfo, l) - } - d.SetId(dataSourceIBMISInstancesID(d)) - d.Set(isInstances, instancesInfo) - return nil -} - -// dataSourceIBMISInstancesID returns a reasonable ID for a Instance list. -func dataSourceIBMISInstancesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_instances_test.go b/ibm/data_source_ibm_is_instances_test.go deleted file mode 100644 index a52ab3980..000000000 --- a/ibm/data_source_ibm_is_instances_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISInstancesDataSource_basic(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) - instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) - resName := "data.ibm_is_instances.ds_instances" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", instanceName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - ), - }, - { - Config: testAccCheckIBMISInstancesDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "instances.0.name"), - resource.TestCheckResourceAttrSet(resName, "instances.0.memory"), - resource.TestCheckResourceAttrSet(resName, "instances.0.status"), - resource.TestCheckResourceAttrSet(resName, "instances.0.resource_group"), - resource.TestCheckResourceAttrSet(resName, "instances.0.vpc"), - resource.TestCheckResourceAttrSet(resName, "instances.0.boot_volume.#"), - resource.TestCheckResourceAttrSet(resName, "instances.0.volume_attachments.#"), - resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.#"), - resource.TestCheckResourceAttrSet(resName, "instances.0.network_interfaces.#"), - resource.TestCheckResourceAttrSet(resName, "instances.0.profile"), - resource.TestCheckResourceAttrSet(resName, "instances.0.vcpu.#"), - resource.TestCheckResourceAttrSet(resName, "instances.0.zone"), - ), - }, - }, - }) -} - -func TestAccIBMISInstancesDataSource_vpcfilter(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) - instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) - resName := "data.ibm_is_instances.ds_instances1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", instanceName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - ), - }, - { - Config: testAccCheckIBMISInstancesDataSourceConfig1(vpcname), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "instances.0.name"), - ), - }, - }, - }) -} - -func TestAccIBMISInstancesDataSource_InsGroupfilter(t *testing.T) { - - randInt := acctest.RandIntRange(10, 100) - instanceGroupName := fmt.Sprintf("testinstancegroup%d", randInt) - publicKey := strings.TrimSpace(` - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 - `) - vpcName := fmt.Sprintf("testvpc%d", randInt) - subnetName := fmt.Sprintf("testsubnet%d", randInt) - templateName := fmt.Sprintf("testtemplate%d", randInt) - sshKeyName := fmt.Sprintf("testsshkey%d", randInt) - resName := "data.ibm_is_instances.ds_instances1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceGroupConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_is_instance_group.instance_group", "name", instanceGroupName), - ), - }, - { - Config: testAccCheckIBMISInstancesDataSourceConfigInstanceGroup(instanceGroupName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(resName, "instances.0.name"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstancesDataSourceConfig() string { - return fmt.Sprintf(` - data "ibm_is_instances" "ds_instances" { - }`) -} - -func testAccCheckIBMISInstancesDataSourceConfig1(vpcname string) string { - return fmt.Sprintf(` - data "ibm_is_instances" "ds_instances1" { - vpc_name = "%s" - }`, vpcname) -} -func testAccCheckIBMISInstancesDataSourceConfigInstanceGroup(insGrpName string) string { - return fmt.Sprintf(` - data "ibm_is_instances" "ds_instances1" { - instance_group_name = "%s" - }`, insGrpName) -} diff --git a/ibm/data_source_ibm_is_lb.go b/ibm/data_source_ibm_is_lb.go deleted file mode 100644 index a945c115a..000000000 --- a/ibm/data_source_ibm_is_lb.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strconv" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - name = "name" - poolAlgorithm = "algorithm" - href = "href" - poolProtocol = "protocol" - poolCreatedAt = "created_at" - poolProvisioningStatus = "provisioning_status" - healthMonitor = "health_monitor" - instanceGroup = "instance_group" - members = "members" - sessionPersistence = "session_persistence" - crnInstance = "crn" - sessionType = "type" - healthMonitorType = "type" - healthMonitorDelay = "delay" - healthMonitorMaxRetries = "max_retries" - healthMonitorPort = "port" - healthMonitorTimeout = "timeout" - healthMonitorURLPath = "url_path" -) - -func dataSourceIBMISLB() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISLBRead, - - Schema: map[string]*schema.Schema{ - isLBName: { - Type: schema.TypeString, - Required: true, - Description: "Load Balancer name", - }, - - isLBType: { - Type: schema.TypeString, - Computed: true, - Description: "Load Balancer type", - }, - - isLBStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Load Balancer status", - }, - - isLBRouteMode: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether route mode is enabled for this load balancer", - }, - - isLBCrn: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this Load Balancer", - }, - - isLBOperatingStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Load Balancer operating status", - }, - - isLBPublicIPs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Load Balancer Public IPs", - }, - - isLBPrivateIPs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Load Balancer private IPs", - }, - - isLBSubnets: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Load Balancer subnets list", - }, - - isLBSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Load Balancer securitygroups list", - }, - - isLBSecurityGroupsSupported: { - Type: schema.TypeBool, - Computed: true, - Description: "Security Group Supported for this Load Balancer", - }, - - isLBTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "Tags associated to Load Balancer", - }, - - isLBResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Load Balancer Resource group", - }, - - isLBHostName: { - Type: schema.TypeString, - Computed: true, - Description: "Load Balancer Host Name", - }, - - isLBLogging: { - Type: schema.TypeBool, - Computed: true, - Description: "Logging of Load Balancer", - }, - - isLBListeners: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Load Balancer Listeners list", - }, - isLBPools: { - Type: schema.TypeList, - Computed: true, - Description: "Load Balancer Pools list", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - poolAlgorithm: { - Type: schema.TypeString, - Computed: true, - Description: "The load balancing algorithm.", - }, - healthMonitor: { - Description: "The health monitor of this pool.", - Computed: true, - Type: schema.TypeMap, - }, - - instanceGroup: { - Description: "The instance group that is managing this pool.", - Computed: true, - Type: schema.TypeMap, - }, - - members: { - Description: "The backend server members of the pool.", - Computed: true, - Type: schema.TypeList, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - href: { - Type: schema.TypeString, - Computed: true, - Description: "The member's canonical URL.", - }, - ID: { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this load balancer pool member.", - }, - }, - }, - }, - sessionPersistence: { - Description: "The session persistence of this pool.", - Computed: true, - Type: schema.TypeMap, - }, - poolCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "The date and time that this pool was created.", - }, - href: { - Type: schema.TypeString, - Computed: true, - Description: "The pool's canonical URL.", - }, - ID: { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this load balancer pool", - }, - name: { - Type: schema.TypeString, - Computed: true, - Description: "The user-defined name for this load balancer pool", - }, - poolProtocol: { - Type: schema.TypeString, - Computed: true, - Description: "The protocol used for this load balancer pool.", - }, - poolProvisioningStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The provisioning status of this pool.", - }, - }, - }, - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func dataSourceIBMISLBRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isLBName).(string) - err := lbGetByName(d, meta, name) - if err != nil { - return err - } - return nil -} - -func lbGetByName(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - start := "" - allrecs := []vpcv1.LoadBalancer{} - for { - listLoadBalancersOptions := &vpcv1.ListLoadBalancersOptions{} - if start != "" { - listLoadBalancersOptions.Start = &start - } - lbs, response, err := sess.ListLoadBalancers(listLoadBalancersOptions) - if err != nil { - return fmt.Errorf("Error Fetching Load Balancers %s\n%s", err, response) - } - start = GetNext(lbs.Next) - allrecs = append(allrecs, lbs.LoadBalancers...) - if start == "" { - break - } - } - - for _, lb := range allrecs { - if *lb.Name == name { - d.SetId(*lb.ID) - d.Set(isLBName, *lb.Name) - if lb.Logging != nil && lb.Logging.Datapath != nil { - d.Set(isLBLogging, *lb.Logging.Datapath.Active) - } - if *lb.IsPublic { - d.Set(isLBType, "public") - } else { - d.Set(isLBType, "private") - } - d.Set(isLBStatus, *lb.ProvisioningStatus) - if lb.RouteMode != nil { - d.Set(isLBRouteMode, *lb.RouteMode) - } - d.Set(isLBCrn, *lb.CRN) - d.Set(isLBOperatingStatus, *lb.OperatingStatus) - publicIpList := make([]string, 0) - if lb.PublicIps != nil { - for _, ip := range lb.PublicIps { - if ip.Address != nil { - pubip := *ip.Address - publicIpList = append(publicIpList, pubip) - } - } - } - d.Set(isLBPublicIPs, publicIpList) - privateIpList := make([]string, 0) - if lb.PrivateIps != nil { - for _, ip := range lb.PrivateIps { - if ip.Address != nil { - prip := *ip.Address - privateIpList = append(privateIpList, prip) - } - } - } - d.Set(isLBPrivateIPs, privateIpList) - if lb.Subnets != nil { - subnetList := make([]string, 0) - for _, subnet := range lb.Subnets { - if subnet.ID != nil { - sub := *subnet.ID - subnetList = append(subnetList, sub) - } - } - d.Set(isLBSubnets, subnetList) - } - - d.Set(isLBSecurityGroupsSupported, false) - if lb.SecurityGroups != nil { - securitygroupList := make([]string, 0) - for _, securityGroup := range lb.SecurityGroups { - if securityGroup.ID != nil { - securityGroupID := *securityGroup.ID - securitygroupList = append(securitygroupList, securityGroupID) - } - } - d.Set(isLBSecurityGroups, securitygroupList) - d.Set(isLBSecurityGroupsSupported, true) - } - - if lb.Listeners != nil { - listenerList := make([]string, 0) - for _, listener := range lb.Listeners { - if listener.ID != nil { - lis := *listener.ID - listenerList = append(listenerList, lis) - } - } - d.Set(isLBListeners, listenerList) - } - listLoadBalancerPoolsOptions := &vpcv1.ListLoadBalancerPoolsOptions{} - listLoadBalancerPoolsOptions.SetLoadBalancerID(*lb.ID) - poolsResult, _, _ := sess.ListLoadBalancerPools(listLoadBalancerPoolsOptions) - if poolsResult != nil { - poolsInfo := make([]map[string]interface{}, 0) - - for _, p := range poolsResult.Pools { - // log.Printf("******* p ******** : (%+v)", p) - pool := make(map[string]interface{}) - pool[poolAlgorithm] = *p.Algorithm - pool[ID] = *p.ID - pool[href] = *p.Href - pool[poolProtocol] = *p.Protocol - pool[poolCreatedAt] = p.CreatedAt.String() - pool[poolProvisioningStatus] = *p.ProvisioningStatus - pool["name"] = *p.Name - if p.HealthMonitor != nil { - healthMonitorInfo := make(map[string]interface{}) - delayfinal := strconv.FormatInt(*(p.HealthMonitor.Delay), 10) - healthMonitorInfo[healthMonitorDelay] = delayfinal - maxRetriesfinal := strconv.FormatInt(*(p.HealthMonitor.MaxRetries), 10) - timeoutfinal := strconv.FormatInt(*(p.HealthMonitor.Timeout), 10) - healthMonitorInfo[healthMonitorMaxRetries] = maxRetriesfinal - healthMonitorInfo[healthMonitorTimeout] = timeoutfinal - if p.HealthMonitor.URLPath != nil { - healthMonitorInfo[healthMonitorURLPath] = *(p.HealthMonitor.URLPath) - } - healthMonitorInfo[healthMonitorType] = *(p.HealthMonitor.Type) - pool[healthMonitor] = healthMonitorInfo - } - - if p.SessionPersistence != nil { - sessionPersistenceInfo := make(map[string]interface{}) - sessionPersistenceInfo[sessionType] = *p.SessionPersistence.Type - pool[sessionPersistence] = sessionPersistenceInfo - } - if p.Members != nil { - memberList := make([]map[string]interface{}, len(p.Members)) - for j, m := range p.Members { - member := make(map[string]interface{}) - member[ID] = *m.ID - member[href] = *m.Href - memberList[j] = member - } - pool[members] = memberList - } - - if p.InstanceGroup != nil { - instanceGroupInfo := make(map[string]interface{}) - instanceGroupInfo[ID] = *(p.InstanceGroup.ID) - instanceGroupInfo[crnInstance] = *(p.InstanceGroup.CRN) - instanceGroupInfo[href] = *(p.InstanceGroup.Href) - instanceGroupInfo[name] = *(p.InstanceGroup.Name) - pool[instanceGroup] = instanceGroupInfo - } - poolsInfo = append(poolsInfo, pool) - } //for - d.Set(isLBPools, poolsInfo) - } - - d.Set(isLBResourceGroup, *lb.ResourceGroup.ID) - d.Set(isLBHostName, *lb.Hostname) - tags, err := GetTagsUsingCRN(meta, *lb.CRN) - if err != nil { - log.Printf( - "Error on get of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) - } - d.Set(isLBTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/loadBalancers") - d.Set(ResourceName, *lb.Name) - if lb.ResourceGroup != nil { - d.Set(ResourceGroupName, *lb.ResourceGroup.ID) - } - return nil - } - } - return fmt.Errorf("No Load balancer found with name %s", name) -} diff --git a/ibm/data_source_ibm_is_lb_profiles.go b/ibm/data_source_ibm_is_lb_profiles.go deleted file mode 100644 index 44c6f1b25..000000000 --- a/ibm/data_source_ibm_is_lb_profiles.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "reflect" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isLbsProfiles = "lb_profiles" -) - -func dataSourceIBMISLbProfiles() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISLbProfilesRead, - - Schema: map[string]*schema.Schema{ - - isLbsProfiles: { - Type: schema.TypeList, - Description: "Collection of load balancer profile collectors", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - Description: "The name for this load balancer profile", - }, - "href": { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this load balancer profile", - }, - "family": { - Type: schema.TypeString, - Computed: true, - Description: "The product family this load balancer profile belongs to", - }, - "route_mode_supported": { - Type: schema.TypeBool, - Computed: true, - Description: "The route mode support for a load balancer with this profile depends on its configuration", - }, - "route_mode_type": { - Type: schema.TypeString, - Computed: true, - Description: "The route mode type for this load balancer profile, one of [fixed, dependent]", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISLbProfilesRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - start := "" - allrecs := []vpcv1.LoadBalancerProfile{} - for { - listOptions := &vpcv1.ListLoadBalancerProfilesOptions{} - if start != "" { - listOptions.Start = &start - } - profileCollectors, response, err := sess.ListLoadBalancerProfiles(listOptions) - if err != nil { - return fmt.Errorf("Error Fetching Load Balancer Profiles for VPC %s\n%s", err, response) - } - start = GetNext(profileCollectors.Next) - allrecs = append(allrecs, profileCollectors.Profiles...) - if start == "" { - break - } - } - lbprofilesInfo := make([]map[string]interface{}, 0) - for _, profileCollector := range allrecs { - - l := map[string]interface{}{ - "name": *profileCollector.Name, - "href": *profileCollector.Href, - "family": *profileCollector.Family, - } - if profileCollector.RouteModeSupported != nil { - routeMode := profileCollector.RouteModeSupported - switch reflect.TypeOf(routeMode).String() { - case "*vpcv1.LoadBalancerProfileRouteModeSupportedFixed": - { - rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupportedFixed) - l["route_mode_supported"] = rms.Value - l["route_mode_type"] = rms.Type - } - case "*vpcv1.LoadBalancerProfileRouteModeSupportedDependent": - { - rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupportedDependent) - if rms.Type != nil { - l["route_mode_type"] = *rms.Type - } - } - case "*vpcv1.LoadBalancerProfileRouteModeSupported": - { - rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupported) - if rms.Type != nil { - l["route_mode_type"] = *rms.Type - } - if rms.Value != nil { - l["route_mode_supported"] = *rms.Value - } - } - } - } - lbprofilesInfo = append(lbprofilesInfo, l) - } - d.SetId(dataSourceIBMISLbProfilesID(d)) - d.Set(isLbsProfiles, lbprofilesInfo) - return nil -} - -// dataSourceIBMISLbProfilesID returns a reasonable ID for a profileCollector list. -func dataSourceIBMISLbProfilesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_lb_test.go b/ibm/data_source_ibm_is_lb_test.go deleted file mode 100644 index 294ebf33c..000000000 --- a/ibm/data_source_ibm_is_lb_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISLBDatasource_basic(t *testing.T) { - name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - routeMode := "false" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testDSCheckIBMISLBConfig(vpcname, subnetname, ISZoneName, ISCIDR, name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.ibm_is_lb.ds_lb", "name", name), - resource.TestCheckResourceAttr( - "data.ibm_is_lb.ds_lb", "route_mode", routeMode), - ), - }, - }, - }) -} - -func testDSCheckIBMISLBConfig(vpcname, subnetname, zone, cidr, name string) string { - return fmt.Sprintf(` -resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" -} - -resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" -} -resource "ibm_is_lb" "testacc_lb" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] -} -data "ibm_is_lb" "ds_lb" { - name = ibm_is_lb.testacc_lb.name -}`, vpcname, subnetname, zone, cidr, name) -} diff --git a/ibm/data_source_ibm_is_lbs_test.go b/ibm/data_source_ibm_is_lbs_test.go deleted file mode 100644 index 7fe2df052..000000000 --- a/ibm/data_source_ibm_is_lbs_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISLBSDatasource_basic(t *testing.T) { - name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - var lb string - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - - { - Config: testDSCheckIBMISLBSConfig(vpcname, subnetname, ISZoneName, ISCIDR, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_lb", lb), - resource.TestCheckResourceAttr( - "data.ibm_is_lb.ds_lb", "name", name), - ), - }, - { - Config: testDSCheckIBMISLBSDatasourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.name"), - resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.route_mode"), - ), - }, - }, - }) - -} - -func testDSCheckIBMISLBSConfig(vpcname, subnetname, zone, cidr, name string) string { - // status filter defaults to empty - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_lb" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - } - data "ibm_is_lb" "ds_lb" { - name = ibm_is_lb.testacc_lb.name - }`, vpcname, subnetname, zone, cidr, name) -} -func testDSCheckIBMISLBSDatasourceConfig() string { - // status filter defaults to empty - return fmt.Sprintf(` - data "ibm_is_lbs" "test_lbs" { - }`) -} diff --git a/ibm/data_source_ibm_is_region_test.go b/ibm/data_source_ibm_is_region_test.go deleted file mode 100644 index 70a5aa4b9..000000000 --- a/ibm/data_source_ibm_is_region_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISRegionDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISRegionDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_is_region.testacc_ds_region", "name", regionName), - ), - }, - }, - }) -} - -func testAccCheckIBMISRegionDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_is_region" "testacc_ds_region" { - name = "%s" -}`, regionName) - -} diff --git a/ibm/data_source_ibm_is_snapshot.go b/ibm/data_source_ibm_is_snapshot.go deleted file mode 100644 index f8820179e..000000000 --- a/ibm/data_source_ibm_is_snapshot.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceSnapshot() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISSnapshotRead, - - Schema: map[string]*schema.Schema{ - "identifier": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{isSnapshotName, "identifier"}, - Description: "Snapshot identifier", - ValidateFunc: InvokeDataSourceValidator("ibm_is_snapshot", "identifier"), - }, - - isSnapshotName: { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{isSnapshotName, "identifier"}, - ValidateFunc: InvokeDataSourceValidator("ibm_is_snapshot", isSnapshotName), - Description: "Snapshot name", - }, - - isSnapshotResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Resource group info", - }, - - isSnapshotSourceVolume: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot source volume id", - }, - isSnapshotSourceImage: { - Type: schema.TypeString, - Computed: true, - Description: "If present, the image id from which the data on this volume was most directly provisioned.", - }, - - isSnapshotOperatingSystem: { - Type: schema.TypeString, - Computed: true, - Description: "The globally unique name for the operating system included in this image", - }, - - isSnapshotBootable: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", - }, - - isSnapshotLCState: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot lifecycle state", - }, - isSnapshotCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - isSnapshotEncryption: { - Type: schema.TypeString, - Computed: true, - Description: "Encryption type of the snapshot", - }, - isSnapshotHref: { - Type: schema.TypeString, - Computed: true, - Description: "URL for the snapshot", - }, - - isSnapshotMinCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "Minimum capacity of the snapshot", - }, - isSnapshotResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type of the snapshot", - }, - - isSnapshotSize: { - Type: schema.TypeInt, - Computed: true, - Description: "The size of the snapshot", - }, - }, - } -} - -func dataSourceIBMISSnapshotValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "identifier", - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isSnapshotName, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - - ibmISSnapshotDataSourceValidator := ResourceValidator{ResourceName: "ibm_is_snapshot", Schema: validateSchema} - return &ibmISSnapshotDataSourceValidator -} - -func dataSourceIBMISSnapshotRead(d *schema.ResourceData, meta interface{}) error { - name := d.Get(isSnapshotName).(string) - id := d.Get("identifier").(string) - err := snapshotGetByNameOrID(d, meta, name, id) - if err != nil { - return err - } - return nil -} - -func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - if name != "" { - start := "" - allrecs := []vpcv1.Snapshot{} - for { - listSnapshotOptions := &vpcv1.ListSnapshotsOptions{} - if start != "" { - listSnapshotOptions.Start = &start - } - snapshots, response, err := sess.ListSnapshots(listSnapshotOptions) - if err != nil { - return fmt.Errorf("Error Fetching snapshots %s\n%s", err, response) - } - start = GetNext(snapshots.Next) - allrecs = append(allrecs, snapshots.Snapshots...) - if start == "" { - break - } - } - for _, snapshot := range allrecs { - if *snapshot.Name == name || *snapshot.ID == id { - d.SetId(*snapshot.ID) - d.Set(isSnapshotName, *snapshot.Name) - d.Set(isSnapshotHref, *snapshot.Href) - d.Set(isSnapshotCRN, *snapshot.CRN) - d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) - d.Set(isSnapshotSize, *snapshot.Size) - d.Set(isSnapshotEncryption, *snapshot.Encryption) - d.Set(isSnapshotLCState, *snapshot.LifecycleState) - d.Set(isSnapshotResourceType, *snapshot.ResourceType) - d.Set(isSnapshotBootable, *snapshot.Bootable) - if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { - d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) - } - if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { - d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) - } - if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { - d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) - } - if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { - d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) - } - return nil - } - } - return fmt.Errorf("No snapshot found with name %s", name) - } else { - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - return fmt.Errorf("Error fetching snapshot %s\n%s", err, response) - } - if (response != nil && response.StatusCode == 404) || snapshot == nil { - return fmt.Errorf("No snapshot found with id %s", id) - } - d.SetId(*snapshot.ID) - d.Set(isSnapshotName, *snapshot.Name) - d.Set(isSnapshotHref, *snapshot.Href) - d.Set(isSnapshotCRN, *snapshot.CRN) - d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) - d.Set(isSnapshotSize, *snapshot.Size) - d.Set(isSnapshotEncryption, *snapshot.Encryption) - d.Set(isSnapshotLCState, *snapshot.LifecycleState) - d.Set(isSnapshotResourceType, *snapshot.ResourceType) - d.Set(isSnapshotBootable, *snapshot.Bootable) - if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { - d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) - } - if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { - d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) - } - if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { - d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) - } - if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { - d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) - } - return nil - } -} diff --git a/ibm/data_source_ibm_is_snapshots.go b/ibm/data_source_ibm_is_snapshots.go deleted file mode 100644 index ca8683917..000000000 --- a/ibm/data_source_ibm_is_snapshots.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isSnapshots = "snapshots" - isSnapshotId = "id" -) - -func dataSourceSnapshots() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISSnapshotsRead, - - Schema: map[string]*schema.Schema{ - - isSnapshots: { - Type: schema.TypeList, - Description: "List of snapshots", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isSnapshotId: { - Type: schema.TypeString, - Computed: true, - }, - - isSnapshotName: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot name", - }, - - isSnapshotResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Resource group info", - }, - - isSnapshotSourceVolume: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot source volume", - }, - isSnapshotSourceImage: { - Type: schema.TypeString, - Computed: true, - Description: "If present, the image id from which the data on this volume was most directly provisioned.", - }, - - isSnapshotOperatingSystem: { - Type: schema.TypeString, - Computed: true, - Description: "The globally unique name for the operating system included in this image", - }, - - isSnapshotLCState: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot lifecycle state", - }, - isSnapshotCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - isSnapshotEncryption: { - Type: schema.TypeString, - Computed: true, - Description: "Encryption type of the snapshot", - }, - isSnapshotHref: { - Type: schema.TypeString, - Computed: true, - Description: "URL for the snapshot", - }, - - isSnapshotBootable: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", - }, - - isSnapshotMinCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "Minimum capacity of the snapshot", - }, - isSnapshotResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type of the snapshot", - }, - - isSnapshotSize: { - Type: schema.TypeInt, - Computed: true, - Description: "The size of the snapshot", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISSnapshotsRead(d *schema.ResourceData, meta interface{}) error { - err := getSnapshots(d, meta) - if err != nil { - return err - } - return nil -} - -func getSnapshots(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.Snapshot{} - for { - listSnapshotOptions := &vpcv1.ListSnapshotsOptions{} - if start != "" { - listSnapshotOptions.Start = &start - } - snapshots, response, err := sess.ListSnapshots(listSnapshotOptions) - if err != nil { - return fmt.Errorf("Error fetching snapshots %s\n%s", err, response) - } - start = GetNext(snapshots.Next) - allrecs = append(allrecs, snapshots.Snapshots...) - if start == "" { - break - } - } - - snapshotsInfo := make([]map[string]interface{}, 0) - for _, snapshot := range allrecs { - l := map[string]interface{}{ - isSnapshotId: *snapshot.ID, - isSnapshotName: *snapshot.Name, - isSnapshotHref: *snapshot.Href, - isSnapshotCRN: *snapshot.CRN, - isSnapshotMinCapacity: *snapshot.MinimumCapacity, - isSnapshotSize: *snapshot.Size, - isSnapshotEncryption: *snapshot.Encryption, - isSnapshotLCState: *snapshot.LifecycleState, - isSnapshotResourceType: *snapshot.ResourceType, - isSnapshotBootable: *snapshot.Bootable, - } - if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { - l[isSnapshotResourceGroup] = *snapshot.ResourceGroup.ID - } - if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { - l[isSnapshotSourceVolume] = *snapshot.SourceVolume.ID - } - if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { - l[isSnapshotSourceImage] = *snapshot.SourceImage.ID - } - if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { - l[isSnapshotOperatingSystem] = *snapshot.OperatingSystem.Name - } - snapshotsInfo = append(snapshotsInfo, l) - } - d.SetId(dataSourceIBMISSnapshotsID(d)) - d.Set(isSnapshots, snapshotsInfo) - return nil -} - -// dataSourceIBMISSnapshotsID returns a reasonable ID for the snapshot list. -func dataSourceIBMISSnapshotsID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_subnet.go b/ibm/data_source_ibm_is_subnet.go deleted file mode 100644 index 370e3f390..000000000 --- a/ibm/data_source_ibm_is_subnet.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMISSubnet() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISSubnetRead, - - Schema: map[string]*schema.Schema{ - - "identifier": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{isSubnetName, "identifier"}, - ValidateFunc: InvokeDataSourceValidator("ibm_is_subnet", "identifier"), - }, - - isSubnetIpv4CidrBlock: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetAvailableIpv4AddressCount: { - Type: schema.TypeInt, - Computed: true, - }, - - isSubnetTotalIpv4AddressCount: { - Type: schema.TypeInt, - Computed: true, - }, - - isSubnetName: { - Type: schema.TypeString, - Computed: true, - Optional: true, - ExactlyOneOf: []string{isSubnetName, "identifier"}, - ValidateFunc: InvokeDataSourceValidator("ibm_is_subnet", isSubnetName), - }, - - isSubnetTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "List of tags", - }, - - isSubnetAccessTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "List of access tags", - }, - - isSubnetCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - isSubnetNetworkACL: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetPublicGateway: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetStatus: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetVPC: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetVPCName: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetZone: { - Type: schema.TypeString, - Computed: true, - }, - - isSubnetResourceGroup: { - Type: schema.TypeString, - Computed: true, - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func dataSourceIBMISSubnetValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "identifier", - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isSubnetName, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - - ibmISSubnetDataSourceValidator := ResourceValidator{ResourceName: "ibm_is_subnet", Schema: validateSchema} - return &ibmISSubnetDataSourceValidator -} - -func dataSourceIBMISSubnetRead(d *schema.ResourceData, meta interface{}) error { - err := subnetGetByNameOrID(d, meta) - if err != nil { - return err - } - return nil -} - -func subnetGetByNameOrID(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - var subnet *vpcv1.Subnet - if v, ok := d.GetOk("identifier"); ok { - id := v.(string) - getSubnetOptions := &vpcv1.GetSubnetOptions{ - ID: &id, - } - subnetinfo, response, err := sess.GetSubnet(getSubnetOptions) - if err != nil { - return fmt.Errorf("Error Getting Subnet (%s): %s\n%s", id, err, response) - } - subnet = subnetinfo - } else if v, ok := d.GetOk(isSubnetName); ok { - name := v.(string) - start := "" - allrecs := []vpcv1.Subnet{} - getSubnetsListOptions := &vpcv1.ListSubnetsOptions{} - - for { - if start != "" { - getSubnetsListOptions.Start = &start - } - subnetsCollection, response, err := sess.ListSubnets(getSubnetsListOptions) - if err != nil { - return fmt.Errorf("Error Fetching subnets List %s\n%s", err, response) - } - start = GetNext(subnetsCollection.Next) - allrecs = append(allrecs, subnetsCollection.Subnets...) - if start == "" { - break - } - } - - for _, subnetInfo := range allrecs { - if *subnetInfo.Name == name { - subnet = &subnetInfo - break - } - } - if subnet == nil { - return fmt.Errorf("No subnet found with name (%s)", name) - } - } - - d.SetId(*subnet.ID) - d.Set(isSubnetName, *subnet.Name) - d.Set(isSubnetIpv4CidrBlock, *subnet.Ipv4CIDRBlock) - d.Set(isSubnetAvailableIpv4AddressCount, *subnet.AvailableIpv4AddressCount) - d.Set(isSubnetTotalIpv4AddressCount, *subnet.TotalIpv4AddressCount) - if subnet.NetworkACL != nil { - d.Set(isSubnetNetworkACL, *subnet.NetworkACL.ID) - } - if subnet.PublicGateway != nil { - d.Set(isSubnetPublicGateway, *subnet.PublicGateway.ID) - } else { - d.Set(isSubnetPublicGateway, nil) - } - d.Set(isSubnetStatus, *subnet.Status) - d.Set(isSubnetZone, *subnet.Zone.Name) - d.Set(isSubnetVPC, *subnet.VPC.ID) - d.Set(isSubnetVPCName, *subnet.VPC.Name) - - controller, err := getBaseController(meta) - if err != nil { - return err - } - - tags, err := GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isUserTagType) - if err != nil { - log.Printf( - "An error occured during reading of subnet (%s) tags : %s", d.Id(), err) - } - - accesstags, err := GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isAccessTagType) - if err != nil { - log.Printf( - "Error on get of resource subnet (%s) access tags: %s", d.Id(), err) - } - - d.Set(isSubnetTags, tags) - d.Set(isSubnetAccessTags, accesstags) - d.Set(isSubnetCRN, *subnet.CRN) - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/subnets") - d.Set(ResourceName, *subnet.Name) - d.Set(ResourceCRN, *subnet.CRN) - d.Set(ResourceStatus, *subnet.Status) - if subnet.ResourceGroup != nil { - d.Set(isSubnetResourceGroup, *subnet.ResourceGroup.ID) - d.Set(ResourceGroupName, *subnet.ResourceGroup.Name) - } - return nil -} diff --git a/ibm/data_source_ibm_is_subnet_reserved_ip.go b/ibm/data_source_ibm_is_subnet_reserved_ip.go deleted file mode 100644 index d5c827f1c..000000000 --- a/ibm/data_source_ibm_is_subnet_reserved_ip.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// Define all the constants that matches with the given terrafrom attribute -const ( - // Request Param Constants - isSubNetID = "subnet" - isReservedIPID = "reserved_ip" - - // Response Param Constants - isReservedIPAddress = "address" - isReservedIPAutoDelete = "auto_delete" - isReservedIPCreatedAt = "created_at" - isReservedIPhref = "href" - isReservedIPName = "name" - isReservedIPOwner = "owner" - isReservedIPType = "resource_type" -) - -func dataSourceIBMISReservedIP() *schema.Resource { - return &schema.Resource{ - Read: dataSdataSourceIBMISReservedIPRead, - Schema: map[string]*schema.Schema{ - /* - Request Parameters - ================== - These are mandatory req parameters - */ - isSubNetID: { - Type: schema.TypeString, - Required: true, - Description: "The subnet identifier.", - }, - isReservedIPID: { - Type: schema.TypeString, - Required: true, - Description: "The reserved IP identifier.", - }, - - /* - Response Parameters - =================== - All of these are computed and an user doesn't need to provide - these from outside. - */ - - isReservedIPAddress: { - Type: schema.TypeString, - Computed: true, - Description: "The IP address", - }, - isReservedIPAutoDelete: { - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, this reserved IP will be automatically deleted", - }, - isReservedIPCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the reserved IP was created.", - }, - isReservedIPhref: { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this reserved IP.", - }, - isReservedIPName: { - Type: schema.TypeString, - Computed: true, - Description: "The user-defined or system-provided name for this reserved IP.", - }, - isReservedIPOwner: { - Type: schema.TypeString, - Computed: true, - Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", - }, - isReservedIPType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - isReservedIPTarget: { - Type: schema.TypeString, - Computed: true, - Description: "Reserved IP target id.", - }, - }, - } -} - -// dataSdataSourceIBMISReservedIPRead is used when the reserved IPs are read from the vpc -func dataSdataSourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := vpcClient(meta) - if err != nil { - return err - } - - subnetID := d.Get(isSubNetID).(string) - reservedIPID := d.Get(isReservedIPID).(string) - - options := sess.NewGetSubnetReservedIPOptions(subnetID, reservedIPID) - reserveIP, response, err := sess.GetSubnetReservedIP(options) - - if err != nil || response == nil || reserveIP == nil { - return fmt.Errorf("Error fetching the reserved IP %s\n%s", err, response) - } - - d.SetId(*reserveIP.ID) - d.Set(isReservedIPAutoDelete, *reserveIP.AutoDelete) - d.Set(isReservedIPCreatedAt, (*reserveIP.CreatedAt).String()) - d.Set(isReservedIPhref, *reserveIP.Href) - d.Set(isReservedIPName, *reserveIP.Name) - d.Set(isReservedIPOwner, *reserveIP.Owner) - d.Set(isReservedIPType, *reserveIP.ResourceType) - if reserveIP.Target != nil { - target, ok := reserveIP.Target.(*vpcv1.ReservedIPTarget) - if ok { - d.Set(isReservedIPTarget, target.ID) - } - } - return nil // By default there should be no error -} diff --git a/ibm/data_source_ibm_is_subnet_reserved_ips.go b/ibm/data_source_ibm_is_subnet_reserved_ips.go deleted file mode 100644 index 06eac954e..000000000 --- a/ibm/data_source_ibm_is_subnet_reserved_ips.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// Define all the constants that matches with the given terrafrom attribute -const ( - // Request Param Constants - isReservedIPLimit = "limit" - isReservedIPSort = "sort" - isReservedIPs = "reserved_ips" - isReservedIPsCount = "total_count" -) - -func dataSourceIBMISReservedIPs() *schema.Resource { - return &schema.Resource{ - Read: dataSdataSourceIBMISReservedIPsRead, - Schema: map[string]*schema.Schema{ - /* - Request Parameters - ================== - These are mandatory req parameters - */ - isSubNetID: { - Type: schema.TypeString, - Required: true, - Description: "The subnet identifier.", - }, - /* - Response Parameters - =================== - All of these are computed and an user doesn't need to provide - these from outside. - */ - - isReservedIPs: { - Type: schema.TypeList, - Description: "Collection of reserved IPs in this subnet.", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isReservedIPAddress: { - Type: schema.TypeString, - Computed: true, - Description: "The IP address", - }, - isReservedIPAutoDelete: { - Type: schema.TypeBool, - Computed: true, - Description: "If reserved ip shall be deleted automatically", - }, - isReservedIPCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the reserved IP was created.", - }, - isReservedIPhref: { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this reserved IP.", - }, - isReservedIPID: { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this reserved IP", - }, - isReservedIPName: { - Type: schema.TypeString, - Computed: true, - Description: "The user-defined or system-provided name for this reserved IP.", - }, - isReservedIPOwner: { - Type: schema.TypeString, - Computed: true, - Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", - }, - isReservedIPType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - isReservedIPTarget: { - Type: schema.TypeString, - Computed: true, - Description: "Reserved IP target id", - }, - }, - }, - }, - isReservedIPsCount: { - Type: schema.TypeInt, - Computed: true, - Description: "The total number of resources across all pages", - }, - }, - } -} - -func dataSdataSourceIBMISReservedIPsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - subnetID := d.Get(isSubNetID).(string) - - // Flatten all the reserved IPs - start := "" - allrecs := []vpcv1.ReservedIP{} - for { - options := &vpcv1.ListSubnetReservedIpsOptions{SubnetID: &subnetID} - - if start != "" { - options.Start = &start - } - - result, response, err := sess.ListSubnetReservedIps(options) - if err != nil || response == nil || result == nil { - return fmt.Errorf("Error fetching reserved ips %s\n%s", err, response) - } - start = GetNext(result.Next) - allrecs = append(allrecs, result.ReservedIps...) - if start == "" { - break - } - } - - // Now store all the reserved IP info with their response tags - reservedIPs := []map[string]interface{}{} - for _, data := range allrecs { - ipsOutput := map[string]interface{}{} - ipsOutput[isReservedIPAddress] = *data.Address - ipsOutput[isReservedIPAutoDelete] = *data.AutoDelete - ipsOutput[isReservedIPCreatedAt] = (*data.CreatedAt).String() - ipsOutput[isReservedIPhref] = *data.Href - ipsOutput[isReservedIPID] = *data.ID - ipsOutput[isReservedIPName] = *data.Name - ipsOutput[isReservedIPOwner] = *data.Owner - ipsOutput[isReservedIPType] = *data.ResourceType - target, ok := data.Target.(*vpcv1.ReservedIPTarget) - if ok { - ipsOutput[isReservedIPTarget] = target.ID - } - reservedIPs = append(reservedIPs, ipsOutput) - } - - d.SetId(time.Now().UTC().String()) // This is not any reserved ip or subnet id but state id - d.Set(isReservedIPs, reservedIPs) - d.Set(isReservedIPsCount, len(reservedIPs)) - d.Set(isSubNetID, subnetID) - return nil -} diff --git a/ibm/data_source_ibm_is_subnets.go b/ibm/data_source_ibm_is_subnets.go deleted file mode 100644 index 3fa4264da..000000000 --- a/ibm/data_source_ibm_is_subnets.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strconv" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isSubnets = "subnets" - isSubnetResourceGroupID = "resource_group" - isSubnetRoutingTableName = "routing_table_name" -) - -func dataSourceIBMISSubnets() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISSubnetsRead, - - Schema: map[string]*schema.Schema{ - isSubnetResourceGroupID: { - Type: schema.TypeString, - Description: "Resource Group ID", - Optional: true, - }, - - isSubnetRoutingTableName: { - Type: schema.TypeString, - Description: "Name of the routing table", - Optional: true, - }, - - isSubnetRoutingTableID: { - Type: schema.TypeString, - Description: "ID of the routing table", - Optional: true, - }, - - isSubnets: { - Type: schema.TypeList, - Description: "List of subnets", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "id": { - Type: schema.TypeString, - Computed: true, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "crn": { - Type: schema.TypeString, - Computed: true, - }, - "ipv4_cidr_block": { - Type: schema.TypeString, - Computed: true, - }, - "available_ipv4_address_count": { - Type: schema.TypeString, - Computed: true, - }, - "network_acl": { - Type: schema.TypeString, - Computed: true, - }, - "public_gateway": { - Type: schema.TypeString, - Computed: true, - }, - isSubnetResourceGroupID: { - Type: schema.TypeString, - Computed: true, - }, - "total_ipv4_address_count": { - Type: schema.TypeString, - Computed: true, - }, - "vpc": { - Type: schema.TypeString, - Computed: true, - }, - "zone": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISSubnetsRead(d *schema.ResourceData, meta interface{}) error { - err := subnetList(d, meta) - if err != nil { - return err - } - return nil -} - -func subnetList(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.Subnet{} - - var resourceGroup string - if v, ok := d.GetOk(isSubnetResourceGroupID); ok { - resourceGroup = v.(string) - } - - var routingTable string - if v, ok := d.GetOk(isSubnetRoutingTableID); ok { - routingTable = v.(string) - } - - var resourceTableName string - if v, ok := d.GetOk(isSubnetRoutingTableName); ok { - resourceTableName = v.(string) - } - - options := &vpcv1.ListSubnetsOptions{} - if resourceGroup != "" { - options.SetResourceGroupID(resourceGroup) - } - if routingTable != "" { - options.SetRoutingTableID(routingTable) - } - if resourceTableName != "" { - options.SetRoutingTableName(resourceTableName) - } - - for { - if start != "" { - options.Start = &start - } - subnets, response, err := sess.ListSubnets(options) - if err != nil { - return fmt.Errorf("Error Fetching subnets %s\n%s", err, response) - } - start = GetNext(subnets.Next) - allrecs = append(allrecs, subnets.Subnets...) - if start == "" { - break - } - } - subnetsInfo := make([]map[string]interface{}, 0) - for _, subnet := range allrecs { - - var aac string = strconv.FormatInt(*subnet.AvailableIpv4AddressCount, 10) - var tac string = strconv.FormatInt(*subnet.TotalIpv4AddressCount, 10) - l := map[string]interface{}{ - "name": *subnet.Name, - "id": *subnet.ID, - "status": *subnet.Status, - "crn": *subnet.CRN, - "ipv4_cidr_block": *subnet.Ipv4CIDRBlock, - "available_ipv4_address_count": aac, - "network_acl": *subnet.NetworkACL.Name, - "total_ipv4_address_count": tac, - "vpc": *subnet.VPC.ID, - "zone": *subnet.Zone.Name, - } - if subnet.PublicGateway != nil { - l["public_gateway"] = *subnet.PublicGateway.ID - } - if subnet.ResourceGroup != nil { - l["resource_group"] = *subnet.ResourceGroup.ID - } - subnetsInfo = append(subnetsInfo, l) - } - d.SetId(dataSourceIBMISSubnetsID(d)) - d.Set(isSubnets, subnetsInfo) - return nil -} - -// dataSourceIBMISSubnetsId returns a reasonable ID for a subnet list. -func dataSourceIBMISSubnetsID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_virtual_endpoint_gateway.go b/ibm/data_source_ibm_is_virtual_endpoint_gateway.go deleted file mode 100644 index 82bfd2f88..000000000 --- a/ibm/data_source_ibm_is_virtual_endpoint_gateway.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMISEndpointGateway() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISEndpointGatewayRead, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayName: { - Type: schema.TypeString, - Required: true, - Description: "Endpoint gateway name", - }, - isVirtualEndpointGatewayResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway resource type", - }, - isVirtualEndpointGatewayCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this Endpoint gateway", - }, - isVirtualEndpointGatewayResourceGroupID: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group id", - }, - isVirtualEndpointGatewayCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway created date and time", - }, - isVirtualEndpointGatewayHealthState: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway health state", - }, - isVirtualEndpointGatewayLifecycleState: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway lifecycle state", - }, - isVirtualEndpointGatewayIPs: { - Type: schema.TypeList, - Computed: true, - Description: "Endpoint gateway IPs", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayIPsID: { - Type: schema.TypeString, - Computed: true, - Description: "The IPs id", - }, - isVirtualEndpointGatewayIPsName: { - Type: schema.TypeString, - Computed: true, - Description: "The IPs name", - }, - isVirtualEndpointGatewayIPsResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway IP resource type", - }, - isVirtualEndpointGatewayIPsAddress: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway IP Address", - }, - }, - }, - }, - isVirtualEndpointGatewayTarget: { - Type: schema.TypeList, - Computed: true, - Description: "Endpoint gateway target", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayTargetName: { - Type: schema.TypeString, - Computed: true, - Description: "The target name", - }, - isVirtualEndpointGatewayTargetResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The target resource type", - }, - }, - }, - }, - isVirtualEndpointGatewayVpcID: { - Type: schema.TypeString, - Computed: true, - Description: "The VPC id", - }, - }, - } -} - -func dataSourceIBMISEndpointGatewayRead( - d *schema.ResourceData, meta interface{}) error { - var found bool - sess, err := vpcClient(meta) - if err != nil { - return err - } - - name := d.Get(isVirtualEndpointGatewayName).(string) - - start := "" - allrecs := []vpcv1.EndpointGateway{} - for { - options := sess.NewListEndpointGatewaysOptions() - if start != "" { - options.Start = &start - } - result, response, err := sess.ListEndpointGateways(options) - if err != nil { - return fmt.Errorf("Error fetching endpoint gateways %s\n%s", err, response) - } - start = GetNext(result.Next) - allrecs = append(allrecs, result.EndpointGateways...) - if start == "" { - break - } - } - for _, result := range allrecs { - if *result.Name == name { - d.SetId(*result.ID) - d.Set(isVirtualEndpointGatewayName, result.Name) - d.Set(isVirtualEndpointGatewayCRN, result.CRN) - d.Set(isVirtualEndpointGatewayHealthState, result.HealthState) - d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String()) - d.Set(isVirtualEndpointGatewayLifecycleState, result.LifecycleState) - d.Set(isVirtualEndpointGatewayResourceType, result.ResourceType) - d.Set(isVirtualEndpointGatewayIPs, flattenIPs(result.Ips)) - d.Set(isVirtualEndpointGatewayResourceGroupID, result.ResourceGroup.ID) - d.Set(isVirtualEndpointGatewayTarget, flattenEndpointGatewayTarget( - result.Target.(*vpcv1.EndpointGatewayTarget))) - d.Set(isVirtualEndpointGatewayVpcID, result.VPC.ID) - found = true - break - } - } - if !found { - return fmt.Errorf("No Virtual Endpoints Gateway found with given name %s", name) - } - return nil -} diff --git a/ibm/data_source_ibm_is_volume.go b/ibm/data_source_ibm_is_volume.go deleted file mode 100644 index ef6e71048..000000000 --- a/ibm/data_source_ibm_is_volume.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMISVolume() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISVolumeRead, - - Schema: map[string]*schema.Schema{ - - isVolumeName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeDataSourceValidator("ibm_is_subnet", isVolumeName), - Description: "Volume name", - }, - - isVolumeZone: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Zone name", - }, - - isVolumeResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Resource group name", - }, - - isVolumeProfileName: { - Type: schema.TypeString, - Computed: true, - Description: "Volume profile name", - }, - - isVolumeEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "Volume encryption key info", - }, - - isVolumeEncryptionType: { - Type: schema.TypeString, - Computed: true, - Description: "Volume encryption type info", - }, - - isVolumeCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "Vloume capacity value", - }, - - isVolumeIops: { - Type: schema.TypeInt, - Computed: true, - Description: "IOPS value for the Volume", - }, - - isVolumeCrn: { - Type: schema.TypeString, - Computed: true, - Description: "CRN value for the volume instance", - }, - - isVolumeStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Volume status", - }, - - isVolumeStatusReasons: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVolumeStatusReasonsCode: { - Type: schema.TypeString, - Computed: true, - Description: "A snake case string succinctly identifying the status reason", - }, - - isVolumeStatusReasonsMessage: { - Type: schema.TypeString, - Computed: true, - Description: "An explanation of the status reason", - }, - }, - }, - }, - - isVolumeTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "Tags for the volume instance", - }, - - isVolumeSourceSnapshot: { - Type: schema.TypeString, - Computed: true, - Description: "Identifier of the snapshot from which this volume was cloned", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func dataSourceIBMISVolumeValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVolumeName, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - - ibmISVoulmeDataSourceValidator := ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} - return &ibmISVoulmeDataSourceValidator -} - -func dataSourceIBMISVolumeRead(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isVolumeName).(string) - - err := volumeGet(d, meta, name) - if err != nil { - return err - } - return nil -} - -func volumeGet(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - zone := "" - if zname, ok := d.GetOk(isVolumeZone); ok { - zone = zname.(string) - } - start := "" - allrecs := []vpcv1.Volume{} - for { - listVolumesOptions := &vpcv1.ListVolumesOptions{} - if start != "" { - listVolumesOptions.Start = &start - } - if zone != "" { - listVolumesOptions.ZoneName = &zone - } - listVolumesOptions.Name = &name - vols, response, err := sess.ListVolumes(listVolumesOptions) - if err != nil { - return fmt.Errorf("Error Fetching volumes %s\n%s", err, response) - } - start = GetNext(vols.Next) - allrecs = append(allrecs, vols.Volumes...) - if start == "" { - break - } - } - for _, vol := range allrecs { - d.SetId(*vol.ID) - d.Set(isVolumeName, *vol.Name) - d.Set(isVolumeProfileName, *vol.Profile.Name) - d.Set(isVolumeZone, *vol.Zone.Name) - if vol.EncryptionKey != nil { - d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) - } - if vol.Encryption != nil { - d.Set(isVolumeEncryptionType, vol.Encryption) - } - if vol.SourceSnapshot != nil { - d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) - } - d.Set(isVolumeIops, *vol.Iops) - d.Set(isVolumeCapacity, *vol.Capacity) - d.Set(isVolumeCrn, *vol.CRN) - d.Set(isVolumeStatus, *vol.Status) - if vol.StatusReasons != nil { - statusReasonsList := make([]map[string]interface{}, 0) - for _, sr := range vol.StatusReasons { - currentSR := map[string]interface{}{} - if sr.Code != nil && sr.Message != nil { - currentSR[isVolumeStatusReasonsCode] = *sr.Code - currentSR[isVolumeStatusReasonsMessage] = *sr.Message - statusReasonsList = append(statusReasonsList, currentSR) - } - } - d.Set(isVolumeStatusReasons, statusReasonsList) - } - tags, err := GetTagsUsingCRN(meta, *vol.CRN) - if err != nil { - log.Printf( - "Error on get of resource vpc volume (%s) tags: %s", d.Id(), err) - } - d.Set(isVolumeTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") - d.Set(ResourceName, *vol.Name) - d.Set(ResourceCRN, *vol.CRN) - d.Set(ResourceStatus, *vol.Status) - if vol.ResourceGroup != nil { - d.Set(ResourceGroupName, vol.ResourceGroup.Name) - d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) - } - return nil - } - return fmt.Errorf("No Volume found with name %s", name) -} diff --git a/ibm/data_source_ibm_is_volume_profile_test.go b/ibm/data_source_ibm_is_volume_profile_test.go deleted file mode 100644 index c5e79db2e..000000000 --- a/ibm/data_source_ibm_is_volume_profile_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISVolumeProfileDataSource_basic(t *testing.T) { - resName := "data.ibm_is_volume_profile.test1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISVolumeProfileDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", volumeProfileName), - resource.TestCheckResourceAttrSet(resName, "family"), - ), - }, - }, - }) -} - -func testAccCheckIBMISVolumeProfileDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_is_volume_profile" "test1" { - name = "%s" -}`, volumeProfileName) -} diff --git a/ibm/data_source_ibm_is_vpc.go b/ibm/data_source_ibm_is_vpc.go deleted file mode 100644 index 3a6d21675..000000000 --- a/ibm/data_source_ibm_is_vpc.go +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "reflect" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMISVPC() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISVPCRead, - - Schema: map[string]*schema.Schema{ - isVPCDefaultNetworkACL: { - Type: schema.TypeString, - Computed: true, - }, - - isVPCClassicAccess: { - Type: schema.TypeBool, - Computed: true, - }, - - isVPCDefaultRoutingTable: { - Type: schema.TypeString, - Computed: true, - Description: "Default routing table associated with VPC", - }, - - isVPCName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeDataSourceValidator("ibm_is_subnet", isVPCName), - }, - - isVPCDefaultNetworkACLName: { - Type: schema.TypeString, - Computed: true, - Description: "Default Network ACL name", - }, - - isVPCDefaultSecurityGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "Default security group name", - }, - - isVPCDefaultSecurityGroupCRN: { - Type: schema.TypeString, - Computed: true, - Description: "Default security group CRN", - }, - - isVPCDefaultNetworkACLCRN: { - Type: schema.TypeString, - Computed: true, - Description: "Default Network ACL CRN", - }, - - isVPCDefaultRoutingTableName: { - Type: schema.TypeString, - Computed: true, - Description: "Default routing table name", - }, - - isVPCResourceGroup: { - Type: schema.TypeString, - Computed: true, - }, - - isVPCStatus: { - Type: schema.TypeString, - Computed: true, - }, - - isVPCDefaultSecurityGroup: { - Type: schema.TypeString, - Computed: true, - Description: "Security group associated with VPC", - }, - - isVPCTags: { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - }, - - isVPCCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - - cseSourceAddresses: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "address": { - Type: schema.TypeString, - Computed: true, - Description: "Cloud service endpoint IP Address", - }, - - "zone_name": { - Type: schema.TypeString, - Computed: true, - Description: "Location info of CSE Address", - }, - }, - }, - }, - - isVPCSecurityGroupList: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVPCSecurityGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "Security group name", - }, - - isVPCSecurityGroupID: { - Type: schema.TypeString, - Computed: true, - Description: "Security group id", - }, - - isSecurityGroupRules: { - Type: schema.TypeList, - Computed: true, - Description: "Security Rules", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - - isVPCSecurityGroupRuleID: { - Type: schema.TypeString, - Computed: true, - Description: "Rule ID", - }, - - isVPCSecurityGroupRuleDirection: { - Type: schema.TypeString, - Computed: true, - Description: "Direction of traffic to enforce, either inbound or outbound", - }, - - isVPCSecurityGroupRuleIPVersion: { - Type: schema.TypeString, - Computed: true, - Description: "IP version: ipv4", - }, - - isVPCSecurityGroupRuleRemote: { - Type: schema.TypeString, - Computed: true, - Description: "Security group id: an IP address, a CIDR block, or a single security group identifier", - }, - - isVPCSecurityGroupRuleType: { - Type: schema.TypeInt, - Computed: true, - }, - - isVPCSecurityGroupRuleCode: { - Type: schema.TypeInt, - Computed: true, - }, - - isVPCSecurityGroupRulePortMin: { - Type: schema.TypeInt, - Computed: true, - }, - - isVPCSecurityGroupRulePortMax: { - Type: schema.TypeInt, - Computed: true, - }, - - isVPCSecurityGroupRuleProtocol: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - - subnetsList: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - Description: "subent name", - }, - - "id": { - Type: schema.TypeString, - Computed: true, - Description: "subnet ID", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "subnet status", - }, - - "zone": { - Type: schema.TypeString, - Computed: true, - Description: "subnet location", - }, - - totalIPV4AddressCount: { - Type: schema.TypeInt, - Computed: true, - Description: "Total IPv4 address count in the subnet", - }, - - availableIPV4AddressCount: { - Type: schema.TypeInt, - Computed: true, - Description: "Available IPv4 address count in the subnet", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISVpcValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVPCName, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - - ibmISVpcDataSourceValidator := ResourceValidator{ResourceName: "ibm_is_vpc", Schema: validateSchema} - return &ibmISVpcDataSourceValidator -} - -func dataSourceIBMISVPCRead(d *schema.ResourceData, meta interface{}) error { - name := d.Get(isVPCName).(string) - err := vpcGetByName(d, meta, name) - if err != nil { - return err - } - return nil -} - -func vpcGetByName(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - start := "" - allrecs := []vpcv1.VPC{} - for { - listVpcsOptions := &vpcv1.ListVpcsOptions{} - if start != "" { - listVpcsOptions.Start = &start - } - vpcs, response, err := sess.ListVpcs(listVpcsOptions) - if err != nil { - return fmt.Errorf("Error Fetching vpcs %s\n%s", err, response) - } - start = GetNext(vpcs.Next) - allrecs = append(allrecs, vpcs.Vpcs...) - if start == "" { - break - } - } - for _, vpc := range allrecs { - if *vpc.Name == name { - d.SetId(*vpc.ID) - d.Set(isVPCName, *vpc.Name) - d.Set(isVPCClassicAccess, *vpc.ClassicAccess) - d.Set(isVPCStatus, *vpc.Status) - if vpc.ResourceGroup != nil { - d.Set(isVPCResourceGroup, *vpc.ResourceGroup.ID) - } - if vpc.DefaultNetworkACL != nil { - d.Set(isVPCDefaultNetworkACLName, *vpc.DefaultNetworkACL.Name) - d.Set(isVPCDefaultNetworkACL, *vpc.DefaultNetworkACL.ID) - d.Set(isVPCDefaultNetworkACLCRN, vpc.DefaultNetworkACL.CRN) - } else { - d.Set(isVPCDefaultNetworkACL, nil) - } - if vpc.DefaultRoutingTable != nil { - d.Set(isVPCDefaultRoutingTableName, *vpc.DefaultRoutingTable.Name) - d.Set(isVPCDefaultRoutingTable, *vpc.DefaultRoutingTable.ID) - } - if vpc.DefaultSecurityGroup != nil { - d.Set(isVPCDefaultSecurityGroupName, *vpc.DefaultSecurityGroup.Name) - d.Set(isVPCDefaultSecurityGroup, *vpc.DefaultSecurityGroup.ID) - d.Set(isVPCDefaultSecurityGroupCRN, vpc.DefaultSecurityGroup.CRN) - } else { - d.Set(isVPCDefaultSecurityGroup, nil) - } - tags, err := GetTagsUsingCRN(meta, *vpc.CRN) - if err != nil { - log.Printf( - "An error occured during reading of vpc (%s) tags : %s", d.Id(), err) - } - d.Set(isVPCTags, tags) - d.Set(isVPCCRN, *vpc.CRN) - - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/vpcs") - d.Set(ResourceName, *vpc.Name) - d.Set(ResourceCRN, *vpc.CRN) - d.Set(ResourceStatus, *vpc.Status) - if vpc.ResourceGroup != nil { - d.Set(ResourceGroupName, *vpc.ResourceGroup.Name) - } - //set the cse ip addresses info - if vpc.CseSourceIps != nil { - cseSourceIpsList := make([]map[string]interface{}, 0) - for _, sourceIP := range vpc.CseSourceIps { - currentCseSourceIp := map[string]interface{}{} - if sourceIP.IP != nil { - currentCseSourceIp["address"] = *sourceIP.IP.Address - currentCseSourceIp["zone_name"] = *sourceIP.Zone.Name - cseSourceIpsList = append(cseSourceIpsList, currentCseSourceIp) - } - } - d.Set(cseSourceAddresses, cseSourceIpsList) - } - - // adding pagination support for subnets inside vpc - - startSub := "" - allrecsSub := []vpcv1.Subnet{} - options := &vpcv1.ListSubnetsOptions{} - - for { - if startSub != "" { - options.Start = &start - } - s, response, err := sess.ListSubnets(options) - if err != nil { - return fmt.Errorf("Error fetching subnets %s\n%s", err, response) - } - start = GetNext(s.Next) - allrecsSub = append(allrecsSub, s.Subnets...) - if startSub == "" { - break - } - } - if err == nil { - subnetsInfo := make([]map[string]interface{}, 0) - for _, subnet := range allrecsSub { - if *subnet.VPC.ID == d.Id() { - l := map[string]interface{}{ - "name": *subnet.Name, - "id": *subnet.ID, - "status": *subnet.Status, - "zone": *subnet.Zone.Name, - totalIPV4AddressCount: *subnet.TotalIpv4AddressCount, - availableIPV4AddressCount: *subnet.AvailableIpv4AddressCount, - } - subnetsInfo = append(subnetsInfo, l) - } - } - d.Set(subnetsList, subnetsInfo) - } - - // adding pagination support for subnets inside vpc - - startSg := "" - allrecsSg := []vpcv1.SecurityGroup{} - - for { - vpcId := d.Id() - listSgOptions := &vpcv1.ListSecurityGroupsOptions{ - VPCID: &vpcId, - } - if startSg != "" { - listSgOptions.Start = &start - } - sgs, response, err := sess.ListSecurityGroups(listSgOptions) - if err != nil || sgs == nil { - return fmt.Errorf("Error fetching Security Groups %s\n%s", err, response) - } - if *sgs.TotalCount == int64(0) { - break - } - start = GetNext(sgs.Next) - allrecsSg = append(allrecsSg, sgs.SecurityGroups...) - - if startSg == "" { - break - } - - } - - securityGroupList := make([]map[string]interface{}, 0) - - for _, group := range allrecsSg { - g := make(map[string]interface{}) - - g[isVPCSecurityGroupName] = *group.Name - g[isVPCSecurityGroupID] = *group.ID - - rules := make([]map[string]interface{}, 0) - for _, sgrule := range group.Rules { - switch reflect.TypeOf(sgrule).String() { - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": - { - rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) - r := make(map[string]interface{}) - if rule.Code != nil { - r[isVPCSecurityGroupRuleCode] = int(*rule.Code) - } - if rule.Type != nil { - r[isVPCSecurityGroupRuleType] = int(*rule.Type) - } - r[isVPCSecurityGroupRuleDirection] = *rule.Direction - r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.Protocol != nil { - r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol - } - r[isVPCSecurityGroupRuleID] = *rule.ID - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isVPCSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isVPCSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": - { - rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) - r := make(map[string]interface{}) - r[isVPCSecurityGroupRuleDirection] = *rule.Direction - r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.Protocol != nil { - r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol - } - r[isVPCSecurityGroupRuleID] = *rule.ID - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isVPCSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isVPCSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": - { - rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) - r := make(map[string]interface{}) - r[isVPCSecurityGroupRuleDirection] = *rule.Direction - r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.PortMin != nil { - r[isVPCSecurityGroupRulePortMin] = int(*rule.PortMin) - } - if rule.PortMax != nil { - r[isVPCSecurityGroupRulePortMax] = int(*rule.PortMax) - } - r[isVPCSecurityGroupRuleID] = *rule.ID - if rule.Protocol != nil { - r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol - } - - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isVPCSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isVPCSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - } - } - g[isVPCSgRules] = rules - securityGroupList = append(securityGroupList, g) - } - - d.Set(isVPCSecurityGroupList, securityGroupList) - - return nil - } - } - return fmt.Errorf("No VPC found with name %s", name) -} diff --git a/ibm/data_source_ibm_is_vpc_routing_table_routes.go b/ibm/data_source_ibm_is_vpc_routing_table_routes.go deleted file mode 100644 index c11c9535f..000000000 --- a/ibm/data_source_ibm_is_vpc_routing_table_routes.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isRoutingTableRouteID = "route_id" - isRoutingTableRouteHref = "href" - isRoutingTableRouteName = "name" - isRoutingTableRouteCreatedAt = "created_at" - isRoutingTableRouteLifecycleState = "lifecycle_state" - isRoutingTableRouteAction = "action" - isRoutingTableRouteDestination = "destination" - isRoutingTableRouteNexthop = "nexthop" - isRoutingTableRouteZoneName = "zone" - isRoutingTableRouteVpcID = "vpc" - isRouteTableID = "routing_table" - isRoutingTableRoutes = "routes" -) - -func dataSourceIBMISVPCRoutingTableRoutes() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMISVPCRoutingTableRoutesList, - Schema: map[string]*schema.Schema{ - isRoutingTableRouteVpcID: { - Type: schema.TypeString, - Required: true, - Description: "VPC identifier", - }, - isRouteTableID: { - Type: schema.TypeString, - Required: true, - Description: "Routing table identifier", - }, - isRoutingTableRoutes: { - Type: schema.TypeList, - Description: "Collection of Routing Table Routes", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isRoutingTableRouteID: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route ID", - }, - isRoutingTableRouteHref: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Href", - }, - isRoutingTableRouteName: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Name", - }, - isRoutingTableRouteCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Created At", - }, - isRoutingTableRouteLifecycleState: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Lifecycle State", - }, - isRoutingTableRouteAction: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Action", - }, - isRoutingTableRouteDestination: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Destination", - }, - isRoutingTableRouteNexthop: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Nexthop Address or VPN Gateway Connection ID", - }, - isRoutingTableRouteZoneName: { - Type: schema.TypeString, - Computed: true, - Description: "Routing Table Route Zone Name", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMISVPCRoutingTableRoutesList(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - vpcID := d.Get(isRoutingTableRouteVpcID).(string) - routingTableID := d.Get(isRouteTableID).(string) - start := "" - allrecs := []vpcv1.Route{} - for { - listVpcRoutingTablesRoutesOptions := sess.NewListVPCRoutingTableRoutesOptions(vpcID, routingTableID) - if start != "" { - listVpcRoutingTablesRoutesOptions.Start = &start - } - result, detail, err := sess.ListVPCRoutingTableRoutes(listVpcRoutingTablesRoutesOptions) - if err != nil { - log.Printf("Error reading list of VPC Routing Table Routes:%s\n%s", err, detail) - return err - } - start = GetNext(result.Next) - allrecs = append(allrecs, result.Routes...) - if start == "" { - break - } - } - - vpcRoutingTableRoutes := make([]map[string]interface{}, 0) - - for _, instance := range allrecs { - route := map[string]interface{}{} - if instance.ID != nil { - route[isRoutingTableRouteID] = *instance.ID - } - if instance.Href != nil { - route[isRoutingTableRouteHref] = *instance.Href - } - if instance.Name != nil { - route[isRoutingTableRouteName] = *instance.Name - } - if instance.CreatedAt != nil { - route[isRoutingTableRouteCreatedAt] = (*instance.CreatedAt).String() - } - if instance.LifecycleState != nil { - route[isRoutingTableRouteLifecycleState] = *instance.LifecycleState - } - if instance.Destination != nil { - route[isRoutingTableRouteDestination] = *instance.Destination - } - if instance.Zone != nil && instance.Zone.Name != nil { - route[isRoutingTableRouteZoneName] = *instance.Zone.Name - } - if instance.NextHop != nil { - nexthop := *instance.NextHop.(*vpcv1.RouteNextHop) - if nexthop.Address != nil { - route[isRoutingTableRouteNexthop] = *nexthop.Address - } else { - route[isRoutingTableRouteNexthop] = *nexthop.ID - } - } - - vpcRoutingTableRoutes = append(vpcRoutingTableRoutes, route) - } - d.SetId(dataSourceIBMISVPCRoutingTableRoutesID(d)) - d.Set(isRoutingTableRouteVpcID, vpcID) - d.Set(isRouteTableID, routingTableID) - d.Set(isRoutingTableRoutes, vpcRoutingTableRoutes) - return nil -} - -// dataSourceIBMISVPCRoutingTablesID returns a reasonable ID for dns zones list. -func dataSourceIBMISVPCRoutingTableRoutesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_vpn_gateways.go b/ibm/data_source_ibm_is_vpn_gateways.go deleted file mode 100644 index cdd5f70d1..000000000 --- a/ibm/data_source_ibm_is_vpn_gateways.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isvpnGateways = "vpn_gateways" - isVPNGatewayResourceType = "resource_type" - isVPNGatewayCrn = "crn" -) - -func dataSourceIBMISVPNGateways() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMVPNGatewaysRead, - - Schema: map[string]*schema.Schema{ - - isvpnGateways: { - Type: schema.TypeList, - Description: "Collection of VPN Gateways", - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVPNGatewayName: { - Type: schema.TypeString, - Computed: true, - Description: "VPN Gateway instance name", - }, - isVPNGatewayCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "The date and time that this VPN gateway was created", - }, - isVPNGatewayCrn: { - Type: schema.TypeString, - Computed: true, - Description: "The VPN gateway's CRN", - }, - isVPNGatewayMembers: { - Type: schema.TypeList, - Computed: true, - Description: "Collection of VPN gateway members", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "address": { - Type: schema.TypeString, - Computed: true, - Description: "The public IP address assigned to the VPN gateway member", - }, - - "private_address": { - Type: schema.TypeString, - Computed: true, - Description: "The private IP address assigned to the VPN gateway member", - }, - - "role": { - Type: schema.TypeString, - Computed: true, - Description: "The high availability role assigned to the VPN gateway member", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "The status of the VPN gateway member", - }, - }, - }, - }, - - isVPNGatewayResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - - isVPNGatewayStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the VPN gateway", - }, - - isVPNGatewaySubnet: { - Type: schema.TypeString, - Computed: true, - Description: "VPNGateway subnet info", - }, - isVPNGatewayResourceGroup: { - Type: schema.TypeString, - Computed: true, - Description: "resource group identifiers ", - }, - isVPNGatewayMode: { - Type: schema.TypeString, - Computed: true, - Description: " VPN gateway mode(policy/route) ", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMVPNGatewaysRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := vpcClient(meta) - if err != nil { - return err - } - - listvpnGWOptions := sess.NewListVPNGatewaysOptions() - - start := "" - allrecs := []vpcv1.VPNGatewayIntf{} - for { - if start != "" { - listvpnGWOptions.Start = &start - } - availableVPNGateways, detail, err := sess.ListVPNGateways(listvpnGWOptions) - if err != nil { - return fmt.Errorf("Error reading list of VPN Gateways:%s\n%s", err, detail) - } - start = GetNext(availableVPNGateways.Next) - allrecs = append(allrecs, availableVPNGateways.VPNGateways...) - if start == "" { - break - } - } - - vpngateways := make([]map[string]interface{}, 0) - for _, instance := range allrecs { - gateway := map[string]interface{}{} - data := instance.(*vpcv1.VPNGateway) - gateway[isVPNGatewayName] = *data.Name - gateway[isVPNGatewayCreatedAt] = data.CreatedAt.String() - gateway[isVPNGatewayResourceType] = *data.ResourceType - gateway[isVPNGatewayStatus] = *data.Status - gateway[isVPNGatewayMode] = *data.Mode - gateway[isVPNGatewayResourceGroup] = *data.ResourceGroup.ID - gateway[isVPNGatewaySubnet] = *data.Subnet.ID - gateway[isVPNGatewayCrn] = *data.CRN - - if data.Members != nil { - vpcMembersIpsList := make([]map[string]interface{}, 0) - for _, memberIP := range data.Members { - currentMemberIP := map[string]interface{}{} - if memberIP.PublicIP != nil { - currentMemberIP["address"] = *memberIP.PublicIP.Address - currentMemberIP["role"] = *memberIP.Role - currentMemberIP["status"] = *memberIP.Status - vpcMembersIpsList = append(vpcMembersIpsList, currentMemberIP) - } - if memberIP.PrivateIP != nil { - currentMemberIP["private_address"] = *memberIP.PrivateIP.Address - } - } - gateway[isVPNGatewayMembers] = vpcMembersIpsList - } - - vpngateways = append(vpngateways, gateway) - } - - d.SetId(dataSourceIBMVPNGatewaysID(d)) - d.Set(isvpnGateways, vpngateways) - return nil -} - -// dataSourceIBMVPNGatewaysID returns a reasonable ID list. -func dataSourceIBMVPNGatewaysID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_is_vpn_gateways_test.go b/ibm/data_source_ibm_is_vpn_gateways_test.go deleted file mode 100644 index a172aa94f..000000000 --- a/ibm/data_source_ibm_is_vpn_gateways_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISVpnGatewaysDataSource_basic(t *testing.T) { - var vpnGateway string - node := "data.ibm_is_vpn_gateways.test1" - vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVpnGatewaysDataSourceConfig(vpcname, subnetname, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), - resource.TestCheckResourceAttrSet(node, "vpn_gateways.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMISVpnGatewaysDataSourceConfig(vpc, subnet, name string) string { - // status filter defaults to empty - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - - } - resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet.id}" - } - data "ibm_is_vpn_gateways" "test1" { - - }`, vpc, subnet, ISZoneName, ISCIDR, name) - -} diff --git a/ibm/data_source_ibm_is_zone_test.go b/ibm/data_source_ibm_is_zone_test.go deleted file mode 100644 index 1a144c181..000000000 --- a/ibm/data_source_ibm_is_zone_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMISZoneDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISZoneDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_is_zone.testacc_ds_zone", "name", ISZoneName), - resource.TestCheckResourceAttr("data.ibm_is_zone.testacc_ds_zone", "region", regionName), - ), - }, - }, - }) -} - -func testAccCheckIBMISZoneDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_is_zone" "testacc_ds_zone" { - name = "%s" - region = "%s" -}`, ISZoneName, regionName) -} diff --git a/ibm/data_source_ibm_kms_key_rings.go b/ibm/data_source_ibm_kms_key_rings.go deleted file mode 100644 index a1c50212f..000000000 --- a/ibm/data_source_ibm_kms_key_rings.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "strings" - - //kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMKMSkeyRings() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMKMSKeyRingsRead, - - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - Description: "Key protect or hpcs instance GUID", - DiffSuppressFunc: suppressKMSInstanceIDDiff, - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "public or private", - Default: "public", - }, - "key_rings": { - Type: schema.TypeList, - Computed: true, - Description: "Key Rings for a particualer instance", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMKMSKeyRingsRead(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(api, endpointType, extensions) - if err != nil { - return err - } - api.URL = URL - - api.Config.InstanceID = instanceID - keys, err := api.GetKeyRings(context.Background()) - if err != nil { - return fmt.Errorf( - "Get Key Rings failed with error: %s", err) - } - retreivedKeyRings := keys.KeyRings - if keys == nil || len(retreivedKeyRings) == 0 { - return fmt.Errorf("No key Rings in instance %s", instanceID) - } - var keyRingName string - - if len(retreivedKeyRings) == 0 { - return fmt.Errorf("No key Ring with name %s in instance %s", keyRingName, instanceID) - } - - keyRingMap := make([]map[string]interface{}, 0, len(retreivedKeyRings)) - - for _, keyRing := range retreivedKeyRings { - keyInstance := make(map[string]interface{}) - - keyInstance["id"] = keyRing.ID - keyInstance["created_by"] = keyRing.CreatedBy - if keyRing.CreationDate != nil { - keyInstance["creation_date"] = keyRing.CreationDate.String() - } - keyRingMap = append(keyRingMap, keyInstance) - - } - - d.SetId(instanceID) - d.Set("key_rings", keyRingMap) - d.Set("instance_id", instanceID) - d.Set("endpoint_type", endpointType) - - return nil - -} diff --git a/ibm/data_source_ibm_org_test.go b/ibm/data_source_ibm_org_test.go deleted file mode 100644 index 1553e669c..000000000 --- a/ibm/data_source_ibm_org_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMOrgDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMOrgDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_org.testacc_ds_org", "org", cfOrganization), - ), - }, - }, - }) -} - -func testAccCheckIBMOrgDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_org" "testacc_ds_org" { - org = "%s" -}`, cfOrganization) - -} diff --git a/ibm/data_source_ibm_pi_catalog_images_test.go b/ibm/data_source_ibm_pi_catalog_images_test.go deleted file mode 100644 index c80a436cc..000000000 --- a/ibm/data_source_ibm_pi_catalog_images_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPICatalogImagesDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPICatalogImagesDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_pi_catalog_images.power_catalog_images", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMPICatalogImagesDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_pi_catalog_images" "power_catalog_images" { - pi_cloud_instance_id = "%s" -}`, pi_cloud_instance_id) - -} diff --git a/ibm/data_source_ibm_pi_image.go b/ibm/data_source_ibm_pi_image.go deleted file mode 100644 index 3edd9f583..000000000 --- a/ibm/data_source_ibm_pi_image.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -func dataSourceIBMPIImage() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIImagesRead, - Schema: map[string]*schema.Schema{ - - helpers.PIImageName: { - Type: schema.TypeString, - Required: true, - Description: "Imagename Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - "state": { - Type: schema.TypeString, - Computed: true, - }, - "size": { - Type: schema.TypeInt, - Computed: true, - }, - "architecture": { - Type: schema.TypeString, - Computed: true, - }, - "operatingsystem": { - Type: schema.TypeString, - Computed: true, - }, - "hypervisor": { - Type: schema.TypeString, - Computed: true, - }, - "storage_type": { - Type: schema.TypeString, - Computed: true, - }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIImagesRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - - imageC := instance.NewIBMPIImageClient(sess, powerinstanceid) - imagedata, err := imageC.Get(d.Get(helpers.PIImageName).(string), powerinstanceid) - - if err != nil { - return err - } - - d.SetId(*imagedata.ImageID) - d.Set("state", imagedata.State) - d.Set("size", imagedata.Size) - d.Set("architecture", imagedata.Specifications.Architecture) - d.Set("hypervisor", imagedata.Specifications.HypervisorType) - d.Set("operatingsystem", imagedata.Specifications.OperatingSystem) - d.Set("storage_type", imagedata.StorageType) - d.Set("storage_pool", imagedata.StoragePool) - - return nil - -} diff --git a/ibm/data_source_ibm_pi_images.go b/ibm/data_source_ibm_pi_images.go deleted file mode 100644 index d0b57a31b..000000000 --- a/ibm/data_source_ibm_pi_images.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -/* -Datasource to get the list of images that are available when a power instance is created - -*/ -func dataSourceIBMPIImages() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIImagesAllRead, - Schema: map[string]*schema.Schema{ - - helpers.PIImageName: { - Type: schema.TypeString, - Optional: true, - Description: "Imagename Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - Deprecated: "This field is deprectaed.", - }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - - "image_info": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "href": { - Type: schema.TypeString, - Computed: true, - }, - "state": { - Type: schema.TypeString, - Computed: true, - }, - "storage_type": { - Type: schema.TypeString, - Computed: true, - }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMPIImagesAllRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - - imageC := instance.NewIBMPIImageClient(sess, powerinstanceid) - - imagedata, err := imageC.GetAll(powerinstanceid) - - if err != nil { - return err - } - - var clientgenU, _ = uuid.GenerateUUID() - d.SetId(clientgenU) - _ = d.Set("image_info", flattenStockImages(imagedata.Images)) - - return nil - -} - -func flattenStockImages(list []*models.ImageReference) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - - l := map[string]interface{}{ - "id": *i.ImageID, - "state": *i.State, - "href": *i.Href, - "name": *i.Name, - "storage_type": *i.StorageType, - "storage_pool": *i.StoragePool, - } - - result = append(result, l) - - } - return result -} diff --git a/ibm/data_source_ibm_pi_instance.go b/ibm/data_source_ibm_pi_instance.go deleted file mode 100644 index 17069286d..000000000 --- a/ibm/data_source_ibm_pi_instance.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func dataSourceIBMPIInstance() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIInstancesRead, - Schema: map[string]*schema.Schema{ - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Server Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - "volumes": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "memory": { - Type: schema.TypeFloat, - Computed: true, - }, - "processors": { - Type: schema.TypeFloat, - Computed: true, - }, - "health_status": { - Type: schema.TypeString, - Computed: true, - }, - "addresses": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "ip": { - Type: schema.TypeString, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "network_id": { - Type: schema.TypeString, - Computed: true, - }, - "network_name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "external_ip": { - Type: schema.TypeString, - Computed: true, - }, - /*"version": { - Type: schema.TypeFloat, - Computed: true, - },*/ - }, - }, - }, - "proctype": { - Type: schema.TypeString, - Computed: true, - }, - - "status": { - Type: schema.TypeString, - Computed: true, - }, - - "minproc": { - Type: schema.TypeFloat, - Computed: true, - }, - "minmem": { - Type: schema.TypeFloat, - Computed: true, - }, - "maxproc": { - Type: schema.TypeFloat, - Computed: true, - }, - "maxmem": { - Type: schema.TypeFloat, - Computed: true, - }, - "pin_policy": { - Type: schema.TypeString, - Computed: true, - }, - "virtual_cores_assigned": { - Type: schema.TypeInt, - Computed: true, - }, - "max_virtual_cores": { - Type: schema.TypeInt, - Computed: true, - }, - "min_virtual_cores": { - Type: schema.TypeInt, - Computed: true, - }, - "storage_type": { - Type: schema.TypeString, - Computed: true, - }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIInstancesRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - - powerC := instance.NewIBMPIInstanceClient(sess, powerinstanceid) - powervmdata, err := powerC.Get(d.Get(helpers.PIInstanceName).(string), powerinstanceid, getTimeOut) - - if err != nil { - return err - } - - pvminstanceid := *powervmdata.PvmInstanceID - d.SetId(pvminstanceid) - d.Set("memory", powervmdata.Memory) - d.Set("processors", powervmdata.Processors) - d.Set("status", powervmdata.Status) - d.Set("proctype", powervmdata.ProcType) - d.Set("volumes", powervmdata.VolumeIds) - d.Set("minproc", powervmdata.Minproc) - d.Set("minmem", powervmdata.Minmem) - d.Set("maxproc", powervmdata.Maxproc) - d.Set("maxmem", powervmdata.Maxmem) - d.Set("pin_policy", powervmdata.PinPolicy) - d.Set("virtual_cores_assigned", powervmdata.VirtualCores.Assigned) - d.Set("max_virtual_cores", powervmdata.VirtualCores.Max) - d.Set("min_virtual_cores", powervmdata.VirtualCores.Min) - d.Set("storage_type", powervmdata.StorageType) - d.Set("storage_pool", powervmdata.StoragePool) - - if powervmdata.Addresses != nil { - pvmaddress := make([]map[string]interface{}, len(powervmdata.Addresses)) - for i, pvmip := range powervmdata.Addresses { - - p := make(map[string]interface{}) - p["ip"] = pvmip.IP - p["network_name"] = pvmip.NetworkName - p["network_id"] = pvmip.NetworkID - p["macaddress"] = pvmip.MacAddress - p["type"] = pvmip.Type - p["external_ip"] = pvmip.ExternalIP - pvmaddress[i] = p - } - d.Set("addresses", pvmaddress) - - } - - if powervmdata.Health != nil { - - d.Set("health_status", powervmdata.Health.Status) - - } - - return nil - -} diff --git a/ibm/data_source_ibm_pi_instance_ip.go b/ibm/data_source_ibm_pi_instance_ip.go deleted file mode 100644 index 28b1b02d3..000000000 --- a/ibm/data_source_ibm_pi_instance_ip.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "net" - "strconv" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -func dataSourceIBMPIInstanceIP() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIInstancesIPRead, - Schema: map[string]*schema.Schema{ - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Server Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - "ip": { - Type: schema.TypeString, - Computed: true, - }, - - "ipoctet": { - Type: schema.TypeString, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - - "network_id": { - Type: schema.TypeString, - Computed: true, - }, - - "type": { - Type: schema.TypeString, - Computed: true, - }, - "external_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIInstancesIPRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - checkValidSubnet(d, meta) - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - powerinstancesubnet := d.Get(helpers.PINetworkName).(string) - powerC := instance.NewIBMPIInstanceClient(sess, powerinstanceid) - powervmdata, err := powerC.Get(d.Get(helpers.PIInstanceName).(string), powerinstanceid, getTimeOut) - - if err != nil { - return err - } - - for i, _ := range powervmdata.Addresses { - if powervmdata.Addresses[i].NetworkName == powerinstancesubnet { - log.Printf("Printing the ip %s", powervmdata.Addresses[i].IP) - d.Set("ip", powervmdata.Addresses[i].IP) - d.Set("network_id", powervmdata.Addresses[i].NetworkID) - d.Set("macaddress", powervmdata.Addresses[i].MacAddress) - d.Set("external_ip", powervmdata.Addresses[i].ExternalIP) - d.Set("type", powervmdata.Addresses[i].Type) - - IPObject := net.ParseIP(powervmdata.Addresses[i].IP).To4() - - d.Set("ipoctet", strconv.Itoa(int(IPObject[3]))) - - } - - } - - return nil - -} - -func checkValidSubnet(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - powerinstancesubnet := d.Get(helpers.PINetworkName).(string) - - networkC := instance.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.Get(powerinstancesubnet, powerinstanceid, getTimeOut) - - if err != nil { - return err - } - - d.SetId(*networkdata.NetworkID) - - return nil -} diff --git a/ibm/data_source_ibm_pi_instance_ip_test.go b/ibm/data_source_ibm_pi_instance_ip_test.go deleted file mode 100644 index 12f319589..000000000 --- a/ibm/data_source_ibm_pi_instance_ip_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPIInstanceIPDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIInstanceIPDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_pi_instance_ip.testacc_ds_instance_ip", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMPIInstanceIPDataSourceConfig() string { - return fmt.Sprintf(` -data "ibm_pi_instance_ip" "testacc_ds_instance_ip" { - pi_network_name = "%[1]s" - pi_instance_name = "%[2]s" - pi_cloud_instance_id = "%[3]s" -}`, pi_network_name, pi_instance_name, pi_cloud_instance_id) - -} diff --git a/ibm/data_source_ibm_pi_key.go b/ibm/data_source_ibm_pi_key.go deleted file mode 100644 index 16ce4ea55..000000000 --- a/ibm/data_source_ibm_pi_key.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func dataSourceIBMPIKey() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIKeysRead, - Schema: map[string]*schema.Schema{ - - helpers.PIKeyName: { - Type: schema.TypeString, - Required: true, - Description: "SSHKey Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - //Computed Attributes - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "sshkey": { - Type: schema.TypeString, - Sensitive: true, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIKeysRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - sshkeyC := instance.NewIBMPIKeyClient(sess, powerinstanceid) - sshkeydata, err := sshkeyC.Get(d.Get(helpers.PIKeyName).(string), powerinstanceid) - - if err != nil { - return err - } - - d.SetId(*sshkeydata.Name) - d.Set("creation_date", sshkeydata.CreationDate.String()) - d.Set("sshkey", sshkeydata.SSHKey) - d.Set(helpers.PIKeyName, sshkeydata.Name) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil - -} diff --git a/ibm/data_source_ibm_pi_network.go b/ibm/data_source_ibm_pi_network.go deleted file mode 100644 index 952750070..000000000 --- a/ibm/data_source_ibm_pi_network.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - //"fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func dataSourceIBMPINetwork() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPINetworksRead, - Schema: map[string]*schema.Schema{ - - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - Description: "Network Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - - "cidr": { - Type: schema.TypeString, - Computed: true, - }, - - "type": { - Type: schema.TypeString, - Computed: true, - }, - - "vlan_id": { - Type: schema.TypeInt, - Computed: true, - }, - "gateway": { - Type: schema.TypeString, - Computed: true, - }, - "available_ip_count": { - Type: schema.TypeFloat, - Computed: true, - }, - "used_ip_count": { - Type: schema.TypeFloat, - Computed: true, - }, - "used_ip_percent": { - Type: schema.TypeFloat, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "jumbo": { - Type: schema.TypeBool, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPINetworksRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkC := instance.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.Get(d.Get(helpers.PINetworkName).(string), powerinstanceid, getTimeOut) - - if err != nil || networkdata == nil { - return err - } - - d.SetId(*networkdata.NetworkID) - if networkdata.Cidr != nil { - d.Set("cidr", networkdata.Cidr) - } - if networkdata.Type != nil { - d.Set("type", networkdata.Type) - } - if &networkdata.Gateway != nil { - d.Set("gateway", networkdata.Gateway) - } - if networkdata.VlanID != nil { - d.Set("vlan_id", networkdata.VlanID) - } - if networkdata.IPAddressMetrics.Available != nil { - d.Set("available_ip_count", networkdata.IPAddressMetrics.Available) - } - if networkdata.IPAddressMetrics.Used != nil { - d.Set("used_ip_count", networkdata.IPAddressMetrics.Used) - } - if networkdata.IPAddressMetrics.Utilization != nil { - d.Set("used_ip_percent", networkdata.IPAddressMetrics.Utilization) - } - if networkdata.Name != nil { - d.Set("name", networkdata.Name) - } - d.Set("jumbo", networkdata.Jumbo) - - return nil - -} diff --git a/ibm/data_source_ibm_pi_public_network.go b/ibm/data_source_ibm_pi_public_network.go deleted file mode 100644 index 280fbf59c..000000000 --- a/ibm/data_source_ibm_pi_public_network.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - //"fmt" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func dataSourceIBMPIPublicNetwork() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIPublicNetworksRead, - Schema: map[string]*schema.Schema{ - - helpers.PINetworkName: { - Type: schema.TypeString, - Optional: true, - Description: "Network Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - Deprecated: "This field is deprectaed.", - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - - "network_id": { - Type: schema.TypeString, - Computed: true, - }, - - "name": { - Type: schema.TypeString, - Computed: true, - }, - - "type": { - Type: schema.TypeString, - Computed: true, - }, - - "vlan_id": { - Type: schema.TypeInt, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIPublicNetworksRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkC := instance.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.GetPublic(powerinstanceid, getTimeOut) - - if err != nil || networkdata == nil || len(networkdata.Networks) < 1 { - return fmt.Errorf("Error getting public network or no public network found in %s", powerinstanceid) - } - d.SetId(*networkdata.Networks[0].NetworkID) - if networkdata.Networks[0].Type != nil { - d.Set("type", networkdata.Networks[0].Type) - } - if networkdata.Networks[0].Name != nil { - d.Set("name", networkdata.Networks[0].Name) - } - if networkdata.Networks[0].VlanID != nil { - d.Set("vlan_id", networkdata.Networks[0].VlanID) - } - if networkdata.Networks[0].NetworkID != nil { - d.Set("network_id", networkdata.Networks[0].NetworkID) - } - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil - -} diff --git a/ibm/data_source_ibm_pi_snapshot_test.go b/ibm/data_source_ibm_pi_snapshot_test.go deleted file mode 100644 index cbdee8f7a..000000000 --- a/ibm/data_source_ibm_pi_snapshot_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPISnapshotDataSource_basic(t *testing.T) { - t.Skip() - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMPISnapshotDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_pi_pvm_snapshots.testacc_pi_snapshots", "pi_instance_name", pi_instance_name), - ), - }, - }, - }) -} - -func testAccCheckIBMPISnapshotDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_pi_pvm_snapshots" "testacc_pi_pvm_snapshot" { - pi_instance_name = "%s" - pi_cloud_instance_id = "%s" -}`, pi_volume_name, pi_cloud_instance_id) - -} diff --git a/ibm/data_source_ibm_pi_snapshots_test.go b/ibm/data_source_ibm_pi_snapshots_test.go deleted file mode 100644 index a3b38f5b2..000000000 --- a/ibm/data_source_ibm_pi_snapshots_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPISnapshotsDataSource_basic(t *testing.T) { - t.Skip() - //name := "Trial " - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMPISnapshotsDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_pi_pvminstance_snapshots.testacc_ds_snapshots", "pi_cloud_instance_id", pi_cloud_instance_id), - ), - }, - }, - }) -} - -func testAccCheckIBMPISnapshotsDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_pi_instance_snapshots" "testacc_ds_snapshots" { - pi_cloud_instance_id = "%s" -}`, pi_cloud_instance_id) - -} diff --git a/ibm/data_source_ibm_pi_tenant.go b/ibm/data_source_ibm_pi_tenant.go deleted file mode 100644 index f87904b40..000000000 --- a/ibm/data_source_ibm_pi_tenant.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -func dataSourceIBMPITenant() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPITenantRead, - Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - - "enabled": { - Type: schema.TypeBool, - Computed: true, - }, - - "tenant_name": { - Type: schema.TypeString, - Computed: true, - }, - "cloud_instances": { - - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cloud_instance_id": { - Type: schema.TypeString, - Computed: true, - }, - "region": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMPITenantRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - //tenantid := d.Get("tenantid").(string) - - tenantC := instance.NewIBMPITenantClient(sess, powerinstanceid) - tenantData, err := tenantC.Get(powerinstanceid) - - if err != nil { - return err - } - - d.SetId(*tenantData.TenantID) - d.Set("creation_date", tenantData.CreationDate) - d.Set("enabled", tenantData.Enabled) - - if tenantData.CloudInstances != nil { - - d.Set("tenant_name", tenantData.CloudInstances[0].Name) - } - - if tenantData.CloudInstances != nil { - tenants := make([]map[string]interface{}, len(tenantData.CloudInstances)) - for i, cloudinstance := range tenantData.CloudInstances { - j := make(map[string]interface{}) - j["region"] = cloudinstance.Region - j["cloud_instance_id"] = cloudinstance.CloudInstanceID - tenants[i] = j - } - - d.Set("cloud_instances", tenants) - } - - return nil - -} diff --git a/ibm/data_source_ibm_pi_volume.go b/ibm/data_source_ibm_pi_volume.go deleted file mode 100644 index e9064afc6..000000000 --- a/ibm/data_source_ibm_pi_volume.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - //"fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func dataSourceIBMPIVolume() *schema.Resource { - - return &schema.Resource{ - Read: dataSourceIBMPIVolumeRead, - Schema: map[string]*schema.Schema{ - - helpers.PIVolumeName: { - Type: schema.TypeString, - Required: true, - Description: "Volume Name to be used for pvminstances", - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - // Computed Attributes - "state": { - Type: schema.TypeString, - Computed: true, - }, - "size": { - Type: schema.TypeInt, - Computed: true, - }, - "shareable": { - Type: schema.TypeBool, - Computed: true, - }, - "bootable": { - Type: schema.TypeBool, - Computed: true, - }, - "disk_type": { - Type: schema.TypeString, - Computed: true, - }, - "volume_pool": { - Type: schema.TypeString, - Computed: true, - }, - "wwn": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func dataSourceIBMPIVolumeRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - volumeC := instance.NewIBMPIVolumeClient(sess, powerinstanceid) - volumedata, err := volumeC.Get(d.Get(helpers.PIVolumeName).(string), powerinstanceid, getTimeOut) - if err != nil { - return err - } - - d.SetId(*volumedata.VolumeID) - d.Set("size", volumedata.Size) - d.Set("state", volumedata.State) - d.Set("shareable", volumedata.Shareable) - d.Set("bootable", volumedata.Bootable) - d.Set("disk_type", volumedata.DiskType) - d.Set("volume_pool", volumedata.VolumePool) - d.Set("wwn", volumedata.Wwn) - return nil - -} diff --git a/ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go b/ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go deleted file mode 100644 index b960fb1f9..000000000 --- a/ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPrivateDNSCustomResolverForwardingRulesDataSource_basic(t *testing.T) { - forwardingRuleDescription := "test-forward-rule" - forwardingRuleType := "zone" - forwardingRuleMatch := "test.example.com" - node := "data.ibm_dns_custom_resolver_forwarding_rules.test-fr" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIbmDnsCrForwardingRulesDataSourceConfig(forwardingRuleDescription, forwardingRuleType, forwardingRuleMatch), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(node, "rules.0.description"), - resource.TestCheckResourceAttrSet(node, "rules.0.type"), - resource.TestCheckResourceAttrSet(node, "rules.0.match"), - ), - }, - }, - }) -} - -func testAccCheckIbmDnsCrForwardingRulesDataSourceConfig(forwardingRuleDescription string, forwardingRuleType string, forwardingRuleMatch string) string { - return fmt.Sprintf(` - resource "ibm_dns_custom_resolver" "test" { - name = "CustomResolverFW" - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - description = "FW rules" - high_availability = false - enabled = true - locations { - subnet_crn = "crn:v1:bluemix:public:is:us-south-1:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0717-4f53a236-cd7a-4688-9347-066bb5058a5c" - enabled = true - } - } - resource "ibm_dns_custom_resolver_forwarding_rule" "dns_custom_resolver_forwarding_rule" { - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id - description = "%s" - type = "%s" - match = "%s" - forward_to = ["168.20.22.122"] - } - - data "ibm_dns_custom_resolver_forwarding_rules" "test-fr" { - depends_on = [ibm_dns_custom_resolver.test] - instance_id = ibm_dns_custom_resolver.test.instance_id - resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id - } - `, forwardingRuleDescription, forwardingRuleType, forwardingRuleMatch) -} diff --git a/ibm/data_source_ibm_private_dns_custom_resolver_test.go b/ibm/data_source_ibm_private_dns_custom_resolver_test.go deleted file mode 100644 index 12b353c3c..000000000 --- a/ibm/data_source_ibm_private_dns_custom_resolver_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPrivateDNSCustomResolverDataSource_basic(t *testing.T) { - node := "data.ibm_dns_custom_resolvers.test-cr" - crname := fmt.Sprintf("tf-pdns-custom-resolver-%d", acctest.RandIntRange(100, 200)) - crdescription := fmt.Sprintf("tf-pdns-custom-resolver-tf-test%d", acctest.RandIntRange(100, 200)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPrivateDNSCustomResolverDataSourceConfig(crname, crdescription), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.name"), - resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.description"), - resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.enabled"), - resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.locations.0.subnet_crn"), - resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.locations.0.enabled"), - ), - }, - }, - }) -} - -func testAccCheckIBMPrivateDNSCustomResolverDataSourceConfig(crname, crdescription string) string { - return fmt.Sprintf(` - resource "ibm_dns_custom_resolver" "test" { - name = "%s" - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - description = "%s" - high_availability = false - locations{ - subnet_crn = "crn:v1:bluemix:public:is:us-south-1:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0717-4f53a236-cd7a-4688-9347-066bb5058a5c" - enabled = true - } - } - data "ibm_dns_custom_resolvers" "test-cr" { - depends_on = [ibm_dns_custom_resolver.test] - instance_id = ibm_dns_custom_resolver.test.instance_id - }`, crname, crdescription) -} diff --git a/ibm/data_source_ibm_push_notification_chrome.go b/ibm/data_source_ibm_push_notification_chrome.go deleted file mode 100644 index 7e838b268..000000000 --- a/ibm/data_source_ibm_push_notification_chrome.go +++ /dev/null @@ -1,63 +0,0 @@ -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/IBM/push-notifications-go-sdk/pushservicev1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMPNApplicationChrome() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceApplicationChromeRead, - - Schema: map[string]*schema.Schema{ - "guid": { - Type: schema.TypeString, - Required: true, - Description: "Unique guid of the application using the push service.", - }, - "server_key": { - Type: schema.TypeString, - Computed: true, - Description: "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", - }, - "web_site_url": { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", - }, - }, - } -} - -func dataSourceApplicationChromeRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - pushServiceClient, err := meta.(ClientSession).PushServiceV1() - if err != nil { - return diag.FromErr(err) - } - - getChromeWebConfOptions := &pushservicev1.GetChromeWebConfOptions{} - - guid := d.Get("guid").(string) - getChromeWebConfOptions.SetApplicationID(guid) - - chromeWebConf, response, err := pushServiceClient.GetChromeWebConfWithContext(context, getChromeWebConfOptions) - if err != nil { - log.Printf("[DEBUG] GetChromeWebConfWithContext failed %s\n%d", err, response.StatusCode) - return diag.FromErr(err) - } - - d.SetId(guid) - if err = d.Set("server_key", chromeWebConf.ApiKey); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_key: %s", err)) - } - if err = d.Set("web_site_url", chromeWebConf.WebSiteURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting web_site_url: %s", err)) - } - - return nil -} diff --git a/ibm/data_source_ibm_resource_instance.go b/ibm/data_source_ibm_resource_instance.go deleted file mode 100644 index af871394d..000000000 --- a/ibm/data_source_ibm_resource_instance.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" - "github.com/IBM-Cloud/bluemix-go/models" -) - -func dataSourceIBMResourceInstance() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMResourceInstanceRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Resource instance name for example, myobjectstorage", - Type: schema.TypeString, - Required: true, - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The id of the resource group in which the instance is present", - }, - - "location": { - Description: "The location or the environment in which instance exists", - Optional: true, - Type: schema.TypeString, - Computed: true, - }, - - "service": { - Description: "The service type of the instance", - Optional: true, - Type: schema.TypeString, - Computed: true, - }, - - "plan": { - Description: "The plan type of the instance", - Type: schema.TypeString, - Computed: true, - }, - - "status": { - Description: "The resource instance status", - Type: schema.TypeString, - Computed: true, - }, - - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "CRN of resource instance", - }, - "tags": { - Type: schema.TypeSet, - Computed: true, - Description: "Tags of Resource Instance", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Guid of resource instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - - "extensions": { - Type: schema.TypeMap, - Computed: true, - Description: "The extended metadata as a map associated with the resource instance.", - }, - }, - } -} - -func dataSourceIBMResourceInstanceRead(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerAPIV2() - if err != nil { - return err - } - rsAPI := rsConClient.ResourceServiceInstanceV2() - name := d.Get("name").(string) - - rsInstQuery := controllerv2.ServiceInstanceQuery{ - Name: name, - } - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rsInstQuery.ResourceGroupID = rsGrpID.(string) - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInstQuery.ResourceGroupID = defaultRg - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - if service, ok := d.GetOk("service"); ok { - - serviceOff, err := rsCatRepo.FindByName(service.(string), true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - rsInstQuery.ServiceID = serviceOff[0].ID - } - - var instances []models.ServiceInstanceV2 - - instances, err = rsAPI.ListInstances(rsInstQuery) - if err != nil { - return err - } - var filteredInstances []models.ServiceInstanceV2 - var location string - - if loc, ok := d.GetOk("location"); ok { - location = loc.(string) - for _, instance := range instances { - if getLocation(instance) == location { - filteredInstances = append(filteredInstances, instance) - } - } - } else { - filteredInstances = instances - } - - if len(filteredInstances) == 0 { - return fmt.Errorf("No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) - } - - var instance models.ServiceInstanceV2 - - if len(filteredInstances) > 1 { - return fmt.Errorf( - "More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) - } - instance = filteredInstances[0] - - d.SetId(instance.ID) - d.Set("status", instance.State) - d.Set("resource_group_id", instance.ResourceGroupID) - d.Set("location", instance.RegionID) - serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - d.Set("service", serviceOff) - - d.Set(ResourceName, instance.Name) - d.Set(ResourceCRN, instance.Crn.String()) - d.Set(ResourceStatus, instance.State) - d.Set(ResourceGroupName, instance.ResourceGroupName) - d.Set("guid", instance.Guid) - if len(instance.Extensions) == 0 { - d.Set("extensions", instance.Extensions) - } else { - d.Set("extensions", Flatten(instance.Extensions)) - } - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/services/") - - servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - d.Set("crn", instance.Crn.String()) - tags, err := GetTagsUsingCRN(meta, instance.Crn.String()) - if err != nil { - log.Printf( - "Error on get of resource instance tags (%s) tags: %s", d.Id(), err) - } - d.Set("tags", tags) - - return nil -} - -func getLocation(instance models.ServiceInstanceV2) string { - region := instance.Crn.Region - cName := instance.Crn.CName - if cName == "bluemix" || cName == "staging" { - return region - } else { - return cName + "-" + region - } -} diff --git a/ibm/data_source_ibm_resource_instance_test.go b/ibm/data_source_ibm_resource_instance_test.go deleted file mode 100644 index 5aa11f3e2..000000000 --- a/ibm/data_source_ibm_resource_instance_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMResourceInstanceDataSource_basic(t *testing.T) { - instanceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: setupResourceInstanceConfig(instanceName), - Destroy: false, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance2", "service", "kms"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMResourceInstanceDataSourceConfig(instanceName), - Destroy: false, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "name", instanceName), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "service", "cloud-object-storage"), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "plan", "standard"), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "location", "global"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMResourceInstanceDataSourceConfigWithService(instanceName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "name", instanceName), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "service", "kms"), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "plan", "tiered-pricing"), - resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "location", "us-south"), - ), - }, - }, - }) -} - -func setupResourceInstanceConfig(instanceName string) string { - return fmt.Sprintf(` - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" -} - -resource "ibm_resource_instance" "instance2" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -`, instanceName, instanceName) - -} - -func testAccCheckIBMResourceInstanceDataSourceConfig(instanceName string) string { - return fmt.Sprintf(` -data "ibm_resource_group" "group" { - is_default=true -} - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" -} - -resource "ibm_resource_instance" "instance2" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -data "ibm_resource_instance" "testacc_ds_resource_instance" { - name = ibm_resource_instance.instance.name - location = "global" - resource_group_id = data.ibm_resource_group.group.id -} -`, instanceName, instanceName) - -} - -func testAccCheckIBMResourceInstanceDataSourceConfigWithService(instanceName string) string { - return fmt.Sprintf(` - -resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" -} - -resource "ibm_resource_instance" "instance2" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} - -data "ibm_resource_instance" "testacc_ds_resource_instance2" { - name = ibm_resource_instance.instance2.name - service = "kms" -} -`, instanceName, instanceName) - -} diff --git a/ibm/data_source_ibm_resource_key.go b/ibm/data_source_ibm_resource_key.go deleted file mode 100644 index c47864e52..000000000 --- a/ibm/data_source_ibm_resource_key.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "sort" - "strings" - - "github.com/IBM-Cloud/bluemix-go/crn" - "github.com/IBM-Cloud/bluemix-go/models" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMResourceKey() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMResourceKeyRead, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "The name of the resource key", - Type: schema.TypeString, - Required: true, - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - Description: "The id of the resource instance", - ConflictsWith: []string{"resource_alias_id"}, - }, - - "resource_alias_id": { - Type: schema.TypeString, - Optional: true, - Description: "The id of the resource alias", - ConflictsWith: []string{"resource_instance_id"}, - }, - - "role": { - Type: schema.TypeString, - Computed: true, - Description: "User role", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of resource key", - }, - - "credentials": { - Description: "Credentials asociated with the key", - Sensitive: true, - Type: schema.TypeMap, - Computed: true, - }, - - "most_recent": &schema.Schema{ - Description: "If true and multiple entries are found, the most recently created resource key is used. " + - "If false, an error is returned", - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "crn of resource key", - }, - }, - } -} - -func dataSourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error { - rsContClient, err := meta.(ClientSession).ResourceControllerAPI() - if err != nil { - return err - } - rkAPI := rsContClient.ResourceServiceKey() - name := d.Get("name").(string) - mostRecent := d.Get("most_recent").(bool) - - keys, err := rkAPI.GetKeys(name) - if err != nil { - return err - } - var filteredKeys []models.ServiceKey - - if d.Get("resource_instance_id") == "" && d.Get("resource_instance_id") == "" { - filteredKeys = keys - } else { - crn, err := getCRN(d, meta) - if err != nil { - return err - } - for _, key := range keys { - if key.SourceCrn == *crn { - filteredKeys = append(filteredKeys, key) - } - } - - } - - if len(filteredKeys) == 0 { - return fmt.Errorf("No resource keys found with name [%s]", name) - } - - var key models.ServiceKey - - if len(filteredKeys) > 1 { - if mostRecent { - key = mostRecentResourceKey(filteredKeys) - } else { - return fmt.Errorf( - "More than one resource key found with name matching [%s]. "+ - "Set 'most_recent' to true in your configuration to force the most recent resource key "+ - "to be used", name) - } - } else { - key = filteredKeys[0] - } - - d.SetId(key.ID) - - if roleCrn, ok := key.Parameters["role_crn"].(string); ok { - d.Set("role", roleCrn[strings.LastIndex(roleCrn, ":")+1:]) - } else if roleCrn, ok := key.Credentials["iam_role_crn"].(string); ok { - d.Set("role", roleCrn[strings.LastIndex(roleCrn, ":")+1:]) - } - - d.Set("credentials", Flatten(key.Credentials)) - d.Set("status", key.State) - d.Set("crn", key.Crn.String()) - return nil -} - -func getCRN(d *schema.ResourceData, meta interface{}) (*crn.CRN, error) { - - rsContClient, err := meta.(ClientSession).ResourceControllerAPI() - if err != nil { - return nil, err - } - - if insID, ok := d.GetOk("resource_instance_id"); ok { - instance, err := rsContClient.ResourceServiceInstance().GetInstance(insID.(string)) - if err != nil { - return nil, err - } - return &(instance.Crn), nil - - } - - alias, err := rsContClient.ResourceServiceAlias().Alias(d.Get("resource_alias_id").(string)) - if err != nil { - return nil, err - } - return &(alias.CRN), nil - -} - -type resourceKeys []models.ServiceKey - -func (k resourceKeys) Len() int { return len(k) } - -func (k resourceKeys) Swap(i, j int) { k[i], k[j] = k[j], k[i] } - -func (k resourceKeys) Less(i, j int) bool { - return (*k[i].CreatedAt).Before(*k[j].CreatedAt) -} - -func mostRecentResourceKey(keys resourceKeys) models.ServiceKey { - sortedKeys := keys - sort.Sort(sortedKeys) - return sortedKeys[len(sortedKeys)-1] -} diff --git a/ibm/data_source_ibm_resource_tag.go b/ibm/data_source_ibm_resource_tag.go deleted file mode 100644 index 8ebc35baf..000000000 --- a/ibm/data_source_ibm_resource_tag.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMResourceTag() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMResourceTagRead, - - Schema: map[string]*schema.Schema{ - "resource_id": { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_resource_tag", resourceID), - Description: "CRN of the resource on which the tags should be attached", - }, - "tags": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_resource_tag", tags)}, - Set: resourceIBMVPCHash, - Description: "List of tags associated with resource instance", - }, - "resource_type": { - Type: schema.TypeString, - Optional: true, - Description: "Resource type on which the tags should be fetched", - }, - }, - } -} - -func dataSourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error { - var rID, rType string - rID = d.Get("resource_id").(string) - if v, ok := d.GetOk(resourceType); ok && v != nil { - rType = v.(string) - } - - tags, err := GetGlobalTagsUsingCRN(meta, rID, rType, "") - if err != nil { - return fmt.Errorf( - "Error on get of resource tags (%s) tags: %s", d.Id(), err) - } - - d.SetId(rID) - d.Set("resource_id", rID) - d.Set("resource_type", rType) - d.Set("tags", tags) - - return nil -} diff --git a/ibm/data_source_ibm_resource_tag_test.go b/ibm/data_source_ibm_resource_tag_test.go deleted file mode 100644 index 7e5b4b896..000000000 --- a/ibm/data_source_ibm_resource_tag_test.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccResourceTagDataSource_basic(t *testing.T) { - name := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) - managed_from := "wdc04" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - - resource.TestStep{ - Config: testAccCheckResourceTagReadDataSource(name, managed_from), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_resource_tag.read_tag", "tags.#", "2"), - ), - }, - }, - }) -} - -func testAccCheckResourceTagReadDataSource(name, managed_from string) string { - return fmt.Sprintf(` - - resource "ibm_satellite_location" "location" { - location = "%s" - managed_from = "%s" - description = "satellite service" - zones = ["us-east-1", "us-east-2", "us-east-3"] - } - - data "ibm_satellite_location" "get_location" { - location = ibm_satellite_location.location.id - } - - resource "ibm_resource_tag" "tag" { - resource_id = data.ibm_satellite_location.get_location.crn - tags = ["env:dev", "cpu:4"] - } - - data "ibm_resource_tag" "read_tag" { - resource_id = ibm_resource_tag.tag.resource_id - } -`, name, managed_from) -} diff --git a/ibm/data_source_ibm_satellite_host_script.go b/ibm/data_source_ibm_satellite_host_script.go deleted file mode 100644 index e3be012c8..000000000 --- a/ibm/data_source_ibm_satellite_host_script.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "io/ioutil" - "log" - "path/filepath" - "strings" - "time" - - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - homedir "github.com/mitchellh/go-homedir" -) - -func dataSourceIBMSatelliteAttachHostScript() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMSatelliteAttachHostScriptRead, - - Schema: map[string]*schema.Schema{ - "location": { - Type: schema.TypeString, - Required: true, - Description: "A unique name for the new Satellite location", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "A unique name for the new Satellite location", - }, - "labels": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "List of labels for the attach host", - }, - "host_provider": { - Type: schema.TypeString, - Required: true, - }, - "script_dir": { - Description: "The directory where the satellite attach host script to be downloaded. Default is home directory", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "script_path": { - Description: "The absolute path to the generated host script file", - Type: schema.TypeString, - Computed: true, - }, - "host_script": { - Type: schema.TypeString, - Computed: true, - Description: "Attach host script content", - }, - }, - } -} - -func dataSourceIBMSatelliteAttachHostScriptRead(d *schema.ResourceData, meta interface{}) error { - var scriptDir string - location := d.Get("location").(string) - hostProvider := d.Get("host_provider").(string) - - if _, ok := d.GetOk("script_dir"); ok { - scriptDir = d.Get("script_dir").(string) - } - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - var locData *kubernetesserviceapiv1.MultishiftGetController - var response *core.DetailedResponse - getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ - Controller: &location, - } - - err = resource.Retry(1*time.Minute, func() *resource.RetryError { - locData, response, err = satClient.GetSatelliteLocation(getSatLocOptions) - if err != nil || locData == nil { - if response != nil && response.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - locData, response, err = satClient.GetSatelliteLocation(getSatLocOptions) - } - if err != nil || locData == nil { - return fmt.Errorf("Error getting Satellite location (%s): %s\n%s", location, err, response) - } - - // script labels - labels := make(map[string]string) - if v, ok := d.GetOk("labels"); ok { - l := v.(*schema.Set) - labels = flattenHostLabels(l.List()) - d.Set("labels", l) - } - - if len(scriptDir) == 0 { - scriptDir, err = homedir.Dir() - if err != nil { - return fmt.Errorf("Error fetching homedir: %s", err) - } - } - scriptDir, _ = filepath.Abs(scriptDir) - scriptPath := filepath.Join(scriptDir, "addHost.sh") - - //Generate script - createRegOptions := &kubernetesserviceapiv1.AttachSatelliteHostOptions{} - createRegOptions.Controller = locData.ID - createRegOptions.Labels = labels - - resp, err := satClient.AttachSatelliteHost(createRegOptions) - if err != nil { - return fmt.Errorf("Error Generating Satellite Registration Script: %s\n%s", err, resp) - } - - lines := strings.Split(string(resp), "\n") - for i, line := range lines { - if strings.Contains(line, "API_URL=") { - i = i + 1 - if strings.ToLower(hostProvider) == "aws" { - lines[i] = "yum update -y\nyum-config-manager --enable '*'\nyum repolist all\nyum install container-selinux -y" - } else if strings.ToLower(hostProvider) == "ibm" { - lines[i] = "subscription-manager refresh\nsubscription-manager repos --enable=*\n" - } else if strings.ToLower(hostProvider) == "azure" { - lines[i] = fmt.Sprintf(`yum update --disablerepo=* --enablerepo="*microsoft*" -y -yum-config-manager --enable '*' -yum repolist all -yum install container-selinux -y - `) - } else if strings.ToLower(hostProvider) == "google" { - lines[i] = fmt.Sprintf(`yum update --disablerepo=* --enablerepo="*" -y -yum repolist all -yum install container-selinux -y -yum install subscription-manager -y -`) - } else { - lines[i] = "subscription-manager refresh\nyum update -y\n" - } - } - } - - scriptContent := strings.Join(lines, "\n") - err = ioutil.WriteFile(scriptPath, []byte(scriptContent), 0644) - if err != nil { - return fmt.Errorf("Error Creating Satellite Attach Host Script: %s", err) - } - - d.Set("location", location) - d.Set("host_script", scriptContent) - d.Set("host_provider", hostProvider) - d.Set("script_dir", scriptDir) - d.Set("script_path", scriptPath) - d.SetId(*locData.ID) - - log.Printf("[INFO] Generated satellite location script : %s", *locData.Name) - - return nil -} diff --git a/ibm/data_source_ibm_satellite_host_script_test.go b/ibm/data_source_ibm_satellite_host_script_test.go deleted file mode 100644 index 7050170f7..000000000 --- a/ibm/data_source_ibm_satellite_host_script_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSatelliteAttachHostScriptDataSourceBasic(t *testing.T) { - locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMSatelliteAttachHostScriptDataSourceConfig(locationName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_satellite_attach_host_script.script", "host_provider", "ibm"), - ), - }, - }, - }) -} - -func testAccCheckIBMSatelliteAttachHostScriptDataSourceConfig(locationName string) string { - return fmt.Sprintf(` -resource "ibm_satellite_location" "testacc_satellite" { - location = "%s" - managed_from = "wdc04" - zones = ["us-east-1", "us-east-2", "us-east-3"] -} - -data "ibm_satellite_attach_host_script" "script" { - location = ibm_satellite_location.testacc_satellite.id - labels = ["env:prod"] - host_provider = "ibm" -}`, locationName) -} diff --git a/ibm/data_source_ibm_scc_posture_latest_scans.go b/ibm/data_source_ibm_scc_posture_latest_scans.go deleted file mode 100644 index 0991f7937..000000000 --- a/ibm/data_source_ibm_scc_posture_latest_scans.go +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "reflect" - "strconv" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -func dataSourceIBMSccPostureLatestScans() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccPostureLatestScansRead, - - Schema: map[string]*schema.Schema{ - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the scan.", - }, - "first": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the first page of scans.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the first page of scans.", - }, - }, - }, - }, - "last": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the last page of scans.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the last page of scans.", - }, - }, - }, - }, - "previous": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the previous page of scans.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the previous page of scans.", - }, - }, - }, - }, - "latest_scans": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The details of a scan.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the scan.", - }, - "scan_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", - }, - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the scan.", - }, - "scope_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the scope.", - }, - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the profile.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the profile.", - }, - "profile_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", - }, - "group_profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The group ID of profile.", - }, - "group_profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The group name of the profile.", - }, - "report_run_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The entity that ran the report.", - }, - "start_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time the scan was run.", - }, - "end_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time the scan completed.", - }, - "result": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a scan.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "goals_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that passed the scan.", - }, - "goals_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "goals_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "goals_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that failed the scan.", - }, - "goals_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of goals that were included in the scan.", - }, - "controls_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that passed the scan.", - }, - "controls_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that failed the scan.", - }, - "controls_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "controls_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "controls_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of controls that were included in the scan.", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccPostureLatestScansRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - postureManagementClient, err := meta.(ClientSession).PostureManagementV1() - if err != nil { - return diag.FromErr(err) - } - - listLatestScansOptions := &posturemanagementv1.ListLatestScansOptions{} - - var scansList *posturemanagementv1.ScansList - var offset int64 - finalList := []posturemanagementv1.ScanItem{} - var scanID string - var suppliedFilter bool - - if v, ok := d.GetOk("scan_id"); ok { - scanID = v.(string) - suppliedFilter = true - } - - for { - listLatestScansOptions.Offset = &offset - - listLatestScansOptions.Limit = core.Int64Ptr(int64(100)) - result, response, err := postureManagementClient.ListLatestScansWithContext(context, listLatestScansOptions) - scansList = result - if err != nil { - log.Printf("[DEBUG] ListLatestScansWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListLatestScansWithContext failed %s\n%s", err, response)) - } - offset = dataSourceScansListGetNext(result.Next) - if suppliedFilter { - for _, data := range result.LatestScans { - if *data.ScanID == scanID { - finalList = append(finalList, data) - } - } - } else { - finalList = append(finalList, result.LatestScans...) - } - if offset == 0 { - break - } - } - - scansList.LatestScans = finalList - - if suppliedFilter { - if len(scansList.LatestScans) == 0 { - return diag.FromErr(fmt.Errorf("no LatestScans found with scanID %s", scanID)) - } - d.SetId(scanID) - } else { - d.SetId(dataSourceIBMSccPostureLatestScansID(d)) - } - - if scansList.First != nil { - err = d.Set("first", dataSourceScansListFlattenFirst(*scansList.First)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting first %s", err)) - } - } - - if scansList.Last != nil { - err = d.Set("last", dataSourceScansListFlattenLast(*scansList.Last)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting last %s", err)) - } - } - - if scansList.Previous != nil { - err = d.Set("previous", dataSourceScansListFlattenPrevious(*scansList.Previous)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting previous %s", err)) - } - } - - if scansList.LatestScans != nil { - err = d.Set("latest_scans", dataSourceScansListFlattenLatestScans(scansList.LatestScans)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting latest_scans %s", err)) - } - } - - return nil -} - -// dataSourceIBMSccPostureLatestScansID returns a reasonable ID for the list. -func dataSourceIBMSccPostureLatestScansID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceScansListFlattenFirst(result posturemanagementv1.ScansListFirst) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceScansListFirstToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceScansListFirstToMap(firstItem posturemanagementv1.ScansListFirst) (firstMap map[string]interface{}) { - firstMap = map[string]interface{}{} - - if firstItem.Href != nil { - firstMap["href"] = firstItem.Href - } - - return firstMap -} - -func dataSourceScansListFlattenLast(result posturemanagementv1.ScansListLast) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceScansListLastToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceScansListLastToMap(lastItem posturemanagementv1.ScansListLast) (lastMap map[string]interface{}) { - lastMap = map[string]interface{}{} - - if lastItem.Href != nil { - lastMap["href"] = lastItem.Href - } - - return lastMap -} - -func dataSourceScansListFlattenPrevious(result posturemanagementv1.ScansListPrevious) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceScansListPreviousToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceScansListPreviousToMap(previousItem posturemanagementv1.ScansListPrevious) (previousMap map[string]interface{}) { - previousMap = map[string]interface{}{} - - if previousItem.Href != nil { - previousMap["href"] = previousItem.Href - } - - return previousMap -} - -func dataSourceScansListFlattenLatestScans(result []posturemanagementv1.ScanItem) (latestScans []map[string]interface{}) { - for _, latestScansItem := range result { - latestScans = append(latestScans, dataSourceScansListLatestScansToMap(latestScansItem)) - } - - return latestScans -} - -func dataSourceScansListLatestScansToMap(latestScansItem posturemanagementv1.ScanItem) (latestScansMap map[string]interface{}) { - latestScansMap = map[string]interface{}{} - - if latestScansItem.ScanID != nil { - latestScansMap["scan_id"] = latestScansItem.ScanID - } - if latestScansItem.ScanName != nil { - latestScansMap["scan_name"] = latestScansItem.ScanName - } - if latestScansItem.ScopeID != nil { - latestScansMap["scope_id"] = latestScansItem.ScopeID - } - if latestScansItem.ScopeName != nil { - latestScansMap["scope_name"] = latestScansItem.ScopeName - } - if latestScansItem.ProfileID != nil { - latestScansMap["profile_id"] = latestScansItem.ProfileID - } - if latestScansItem.ProfileName != nil { - latestScansMap["profile_name"] = latestScansItem.ProfileName - } - if latestScansItem.ProfileType != nil { - latestScansMap["profile_type"] = latestScansItem.ProfileType - } - if latestScansItem.GroupProfileID != nil { - latestScansMap["group_profile_id"] = latestScansItem.GroupProfileID - } - if latestScansItem.GroupProfileName != nil { - latestScansMap["group_profile_name"] = latestScansItem.GroupProfileName - } - if latestScansItem.ReportRunBy != nil { - latestScansMap["report_run_by"] = latestScansItem.ReportRunBy - } - if latestScansItem.StartTime != nil { - latestScansMap["start_time"] = latestScansItem.StartTime.String() - } - if latestScansItem.EndTime != nil { - latestScansMap["end_time"] = latestScansItem.EndTime.String() - } - if latestScansItem.Result != nil { - resultList := []map[string]interface{}{} - resultMap := dataSourceScansListLatestScansResultToMap(*latestScansItem.Result) - resultList = append(resultList, resultMap) - latestScansMap["result"] = resultList - } - - return latestScansMap -} - -func dataSourceScansListLatestScansResultToMap(resultItem posturemanagementv1.ScanResult) (resultMap map[string]interface{}) { - resultMap = map[string]interface{}{} - - if resultItem.GoalsPassCount != nil { - resultMap["goals_pass_count"] = resultItem.GoalsPassCount - } - if resultItem.GoalsUnableToPerformCount != nil { - resultMap["goals_unable_to_perform_count"] = resultItem.GoalsUnableToPerformCount - } - if resultItem.GoalsNotApplicableCount != nil { - resultMap["goals_not_applicable_count"] = resultItem.GoalsNotApplicableCount - } - if resultItem.GoalsFailCount != nil { - resultMap["goals_fail_count"] = resultItem.GoalsFailCount - } - if resultItem.GoalsTotalCount != nil { - resultMap["goals_total_count"] = resultItem.GoalsTotalCount - } - if resultItem.ControlsPassCount != nil { - resultMap["controls_pass_count"] = resultItem.ControlsPassCount - } - if resultItem.ControlsFailCount != nil { - resultMap["controls_fail_count"] = resultItem.ControlsFailCount - } - if resultItem.ControlsNotApplicableCount != nil { - resultMap["controls_not_applicable_count"] = resultItem.ControlsNotApplicableCount - } - if resultItem.ControlsUnableToPerformCount != nil { - resultMap["controls_unable_to_perform_count"] = resultItem.ControlsUnableToPerformCount - } - if resultItem.ControlsTotalCount != nil { - resultMap["controls_total_count"] = resultItem.ControlsTotalCount - } - - return resultMap -} - -func dataSourceScansListGetNext(next interface{}) int64 { - if reflect.ValueOf(next).IsNil() { - return 0 - } - - u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) - if err != nil { - return 0 - } - - q := u.Query() - var page string - - if q.Get("start") != "" { - page = q.Get("start") - } else if q.Get("offset") != "" { - page = q.Get("offset") - } - - convertedVal, err := strconv.ParseInt(page, 10, 64) - if err != nil { - return 0 - } - return convertedVal -} diff --git a/ibm/data_source_ibm_scc_posture_latest_scans_test.go b/ibm/data_source_ibm_scc_posture_latest_scans_test.go deleted file mode 100644 index 0522f2719..000000000 --- a/ibm/data_source_ibm_scc_posture_latest_scans_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccPostureLatestScansDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccPostureLatestScansDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_latest_scans.list_latest_scans", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccPostureLatestScansDataSourceConfigBasic() string { - return fmt.Sprintf(` - data "ibm_scc_posture_latest_scans" "list_latest_scans" { - } - `) -} diff --git a/ibm/data_source_ibm_scc_posture_profiles.go b/ibm/data_source_ibm_scc_posture_profiles.go deleted file mode 100644 index d858f5586..000000000 --- a/ibm/data_source_ibm_scc_posture_profiles.go +++ /dev/null @@ -1,550 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "reflect" - "strconv" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -func dataSourceIBMSccPostureProfiles() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccPostureProfilesRead, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "An auto-generated unique identifying number of the profile.", - }, - "first": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the first page of profiles.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the first page of profiles.", - }, - }, - }, - }, - "last": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the last page of profiles.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the last page of profiles.", - }, - }, - }, - }, - "previous": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the previous page of profiles.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the previous page of profiles.", - }, - }, - }, - }, - "profiles": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Profiles.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the profile.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A description of the profile.", - }, - "version": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The version of the profile.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user who created the profile.", - }, - "modified_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user who last modified the profile.", - }, - "reason_for_delete": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A reason that you want to delete a profile.", - }, - "applicability_criteria": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The criteria that defines how a profile applies.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "environment": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of environments that a profile can be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of resources that a profile can be used with.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_category": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The type of environment that a profile is able to be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_category": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The type of resource that a profile is able to be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_type": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The resource type that the profile applies to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "software_details": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The software that the profile applies to.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "os_details": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The operatoring system that the profile applies to.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "additional_details": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "Any additional details about the profile.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_category_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The type of environment that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The environment that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_category_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The type of resource that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_type_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "A further classification of the type of resource that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The resource that is scanned as part of your scope.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "An auto-generated unique identifying number of the profile.", - }, - "base_profile": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The base profile that the controls are pulled from.", - }, - "profile_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of profile.", - }, - "created_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The time that the profile was created in UTC.", - }, - "modified_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The time that the profile was most recently modified in UTC.", - }, - "enabled": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccPostureProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - postureManagementClient, err := meta.(ClientSession).PostureManagementV1() - if err != nil { - return diag.FromErr(err) - } - - listProfilesOptions := &posturemanagementv1.ListProfilesOptions{} - - var profilesList *posturemanagementv1.ProfilesList - var offset int64 - finalList := []posturemanagementv1.ProfileItem{} - var profileID string - var suppliedFilter bool - - if v, ok := d.GetOk("profile_id"); ok { - profileID = v.(string) - suppliedFilter = true - } - - for { - listProfilesOptions.Offset = &offset - - listProfilesOptions.Limit = core.Int64Ptr(int64(100)) - result, response, err := postureManagementClient.ListProfilesWithContext(context, listProfilesOptions) - profilesList = result - if err != nil { - log.Printf("[DEBUG] ListProfilesWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListProfilesWithContext failed %s\n%s", err, response)) - } - offset = dataSourceProfilesListGetNext(result.Next) - if suppliedFilter { - for _, data := range result.Profiles { - if *data.ProfileID == profileID { - finalList = append(finalList, data) - } - } - } else { - finalList = append(finalList, result.Profiles...) - } - if offset == 0 { - break - } - } - - profilesList.Profiles = finalList - - if suppliedFilter { - if len(profilesList.Profiles) == 0 { - return diag.FromErr(fmt.Errorf("no Profiles found with profileID %s", profileID)) - } - d.SetId(profileID) - } else { - d.SetId(dataSourceIBMSccPostureProfilesID(d)) - } - - if profilesList.First != nil { - err = d.Set("first", dataSourceProfilesListFlattenFirst(*profilesList.First)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting first %s", err)) - } - } - - if profilesList.Last != nil { - err = d.Set("last", dataSourceProfilesListFlattenLast(*profilesList.Last)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting last %s", err)) - } - } - - if profilesList.Previous != nil { - err = d.Set("previous", dataSourceProfilesListFlattenPrevious(*profilesList.Previous)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting previous %s", err)) - } - } - - if profilesList.Profiles != nil { - err = d.Set("profiles", dataSourceProfilesListFlattenProfiles(profilesList.Profiles)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting profiles %s", err)) - } - } - - return nil -} - -// dataSourceIBMSccPostureProfilesID returns a reasonable ID for the list. -func dataSourceIBMSccPostureProfilesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceProfilesListFlattenFirst(result posturemanagementv1.ProfilesListFirst) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceProfilesListFirstToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceProfilesListFirstToMap(firstItem posturemanagementv1.ProfilesListFirst) (firstMap map[string]interface{}) { - firstMap = map[string]interface{}{} - - if firstItem.Href != nil { - firstMap["href"] = firstItem.Href - } - - return firstMap -} - -func dataSourceProfilesListFlattenLast(result posturemanagementv1.ProfilesListLast) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceProfilesListLastToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceProfilesListLastToMap(lastItem posturemanagementv1.ProfilesListLast) (lastMap map[string]interface{}) { - lastMap = map[string]interface{}{} - - if lastItem.Href != nil { - lastMap["href"] = lastItem.Href - } - - return lastMap -} - -func dataSourceProfilesListFlattenPrevious(result posturemanagementv1.ProfilesListPrevious) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceProfilesListPreviousToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceProfilesListPreviousToMap(previousItem posturemanagementv1.ProfilesListPrevious) (previousMap map[string]interface{}) { - previousMap = map[string]interface{}{} - - if previousItem.Href != nil { - previousMap["href"] = previousItem.Href - } - - return previousMap -} - -func dataSourceProfilesListFlattenProfiles(result []posturemanagementv1.ProfileItem) (profiles []map[string]interface{}) { - for _, profilesItem := range result { - profiles = append(profiles, dataSourceProfilesListProfilesToMap(profilesItem)) - } - - return profiles -} - -func dataSourceProfilesListProfilesToMap(profilesItem posturemanagementv1.ProfileItem) (profilesMap map[string]interface{}) { - profilesMap = map[string]interface{}{} - - if profilesItem.Name != nil { - profilesMap["name"] = profilesItem.Name - } - if profilesItem.Description != nil { - profilesMap["description"] = profilesItem.Description - } - if profilesItem.Version != nil { - profilesMap["version"] = profilesItem.Version - } - if profilesItem.CreatedBy != nil { - profilesMap["created_by"] = profilesItem.CreatedBy - } - if profilesItem.ModifiedBy != nil { - profilesMap["modified_by"] = profilesItem.ModifiedBy - } - if profilesItem.ReasonForDelete != nil { - profilesMap["reason_for_delete"] = profilesItem.ReasonForDelete - } - if profilesItem.ApplicabilityCriteria != nil { - applicabilityCriteriaList := []map[string]interface{}{} - applicabilityCriteriaMap := dataSourceProfilesListProfilesApplicabilityCriteriaToMap(*profilesItem.ApplicabilityCriteria) - applicabilityCriteriaList = append(applicabilityCriteriaList, applicabilityCriteriaMap) - profilesMap["applicability_criteria"] = applicabilityCriteriaList - } - if profilesItem.ProfileID != nil { - profilesMap["profile_id"] = profilesItem.ProfileID - } - if profilesItem.BaseProfile != nil { - profilesMap["base_profile"] = profilesItem.BaseProfile - } - if profilesItem.ProfileType != nil { - profilesMap["profile_type"] = profilesItem.ProfileType - } - if profilesItem.CreatedTime != nil { - profilesMap["created_time"] = profilesItem.CreatedTime.String() - } - if profilesItem.ModifiedTime != nil { - profilesMap["modified_time"] = profilesItem.ModifiedTime.String() - } - if profilesItem.Enabled != nil { - profilesMap["enabled"] = profilesItem.Enabled - } - - return profilesMap -} - -func dataSourceProfilesListProfilesApplicabilityCriteriaToMap(applicabilityCriteriaItem posturemanagementv1.ApplicabilityCriteria) (applicabilityCriteriaMap map[string]interface{}) { - applicabilityCriteriaMap = map[string]interface{}{} - - if applicabilityCriteriaItem.Environment != nil { - applicabilityCriteriaMap["environment"] = applicabilityCriteriaItem.Environment - } - if applicabilityCriteriaItem.Resource != nil { - applicabilityCriteriaMap["resource"] = applicabilityCriteriaItem.Resource - } - if applicabilityCriteriaItem.EnvironmentCategory != nil { - applicabilityCriteriaMap["environment_category"] = applicabilityCriteriaItem.EnvironmentCategory - } - if applicabilityCriteriaItem.ResourceCategory != nil { - applicabilityCriteriaMap["resource_category"] = applicabilityCriteriaItem.ResourceCategory - } - if applicabilityCriteriaItem.ResourceType != nil { - applicabilityCriteriaMap["resource_type"] = applicabilityCriteriaItem.ResourceType - } - if applicabilityCriteriaItem.SoftwareDetails != nil { - applicabilityCriteriaMap["software_details"] = applicabilityCriteriaItem.SoftwareDetails - } - if applicabilityCriteriaItem.OsDetails != nil { - applicabilityCriteriaMap["os_details"] = applicabilityCriteriaItem.OsDetails - } - if applicabilityCriteriaItem.AdditionalDetails != nil { - applicabilityCriteriaMap["additional_details"] = applicabilityCriteriaItem.AdditionalDetails - } - if applicabilityCriteriaItem.EnvironmentCategoryDescription != nil { - applicabilityCriteriaMap["environment_category_description"] = applicabilityCriteriaItem.EnvironmentCategoryDescription - } - if applicabilityCriteriaItem.EnvironmentDescription != nil { - applicabilityCriteriaMap["environment_description"] = applicabilityCriteriaItem.EnvironmentDescription - } - if applicabilityCriteriaItem.ResourceCategoryDescription != nil { - applicabilityCriteriaMap["resource_category_description"] = applicabilityCriteriaItem.ResourceCategoryDescription - } - if applicabilityCriteriaItem.ResourceTypeDescription != nil { - applicabilityCriteriaMap["resource_type_description"] = applicabilityCriteriaItem.ResourceTypeDescription - } - if applicabilityCriteriaItem.ResourceDescription != nil { - applicabilityCriteriaMap["resource_description"] = applicabilityCriteriaItem.ResourceDescription - } - - return applicabilityCriteriaMap -} - -func dataSourceProfilesListGetNext(next interface{}) int64 { - if reflect.ValueOf(next).IsNil() { - return 0 - } - - u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) - if err != nil { - return 0 - } - - q := u.Query() - var page string - - if q.Get("start") != "" { - page = q.Get("start") - } else if q.Get("offset") != "" { - page = q.Get("offset") - } - - convertedVal, err := strconv.ParseInt(page, 10, 64) - if err != nil { - return 0 - } - return convertedVal -} diff --git a/ibm/data_source_ibm_scc_posture_profiles_test.go b/ibm/data_source_ibm_scc_posture_profiles_test.go deleted file mode 100644 index a0c270d9b..000000000 --- a/ibm/data_source_ibm_scc_posture_profiles_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccPostureProfilesDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccPostureProfilesDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profiles.list_profiles", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccPostureProfilesDataSourceConfigBasic() string { - return fmt.Sprintf(` - data "ibm_scc_posture_profiles" "list_profiles" { - } - `) -} diff --git a/ibm/data_source_ibm_scc_posture_scan_summaries.go b/ibm/data_source_ibm_scc_posture_scan_summaries.go deleted file mode 100644 index d94422da2..000000000 --- a/ibm/data_source_ibm_scc_posture_scan_summaries.go +++ /dev/null @@ -1,753 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "reflect" - "strconv" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -func dataSourceIBMSccPostureScanSummaries() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccPostureScanSummariesRead, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", - }, - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The scope ID. This can be obtained from the Security and Compliance Center UI by clicking on the scope name. The URL contains the ID.", - }, - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the scan.", - }, - "first": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "he URL of the first scan summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the first scan summary.", - }, - }, - }, - }, - "last": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the last scan summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the last scan summary.", - }, - }, - }, - }, - "previous": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The URL of the previous scan summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL of the previous scan summary.", - }, - }, - }, - }, - "summaries": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Summaries.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the scan.", - }, - "scan_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", - }, - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the scan.", - }, - "scope_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the scope.", - }, - "report_run_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The entity that ran the report.", - }, - "start_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time the scan was run.", - }, - "end_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time the scan completed.", - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The status of the collector as it completes a scan.", - }, - "profile": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a profile.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the profile.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the profile.", - }, - "profile_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", - }, - "validation_result": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a scan.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "goals_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that passed the scan.", - }, - "goals_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "goals_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "goals_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that failed the scan.", - }, - "goals_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of goals that were included in the scan.", - }, - "controls_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that passed the scan.", - }, - "controls_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that failed the scan.", - }, - "controls_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "controls_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "controls_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of controls that were included in the scan.", - }, - }, - }, - }, - }, - }, - }, - "group_profiles": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a group profile.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "group_profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The group ID of profile.", - }, - "group_profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The group name of the profile.", - }, - "profile_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", - }, - "validation_result": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a scan.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "goals_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that passed the scan.", - }, - "goals_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "goals_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "goals_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of goals that failed the scan.", - }, - "goals_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of goals that were included in the scan.", - }, - "controls_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that passed the scan.", - }, - "controls_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that failed the scan.", - }, - "controls_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "controls_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "controls_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of controls that were included in the scan.", - }, - }, - }, - }, - "profiles": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a each profile in group profile.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the profile.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the profile.", - }, - "profile_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", - }, - "validation_result": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The result of a scan.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "controls_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that passed the scan.", - }, - "controls_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that failed the scan.", - }, - "controls_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", - }, - "controls_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", - }, - "controls_total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of controls that were included in the scan.", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccPostureScanSummariesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - postureManagementClient, err := meta.(ClientSession).PostureManagementV1() - if err != nil { - return diag.FromErr(err) - } - - scanSummariesOptions := &posturemanagementv1.ScanSummariesOptions{} - - scanSummariesOptions.SetProfileID(d.Get("profile_id").(string)) - scanSummariesOptions.SetScopeID(d.Get("scope_id").(string)) - - var summariesList *posturemanagementv1.SummariesList - var offset int64 - finalList := []posturemanagementv1.SummaryItem{} - var scanID string - var suppliedFilter bool - - if v, ok := d.GetOk("scan_id"); ok { - scanID = v.(string) - suppliedFilter = true - } - - for { - scanSummariesOptions.Offset = &offset - - scanSummariesOptions.Limit = core.Int64Ptr(int64(100)) - result, response, err := postureManagementClient.ScanSummariesWithContext(context, scanSummariesOptions) - summariesList = result - if err != nil { - log.Printf("[DEBUG] ScanSummariesWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ScanSummariesWithContext failed %s\n%s", err, response)) - } - offset = dataSourceSummariesListGetNext(result.Next) - if suppliedFilter { - for _, data := range result.Summaries { - if *data.ScanID == scanID { - finalList = append(finalList, data) - } - } - } else { - finalList = append(finalList, result.Summaries...) - } - if offset == 0 { - break - } - } - - summariesList.Summaries = finalList - - if suppliedFilter { - if len(summariesList.Summaries) == 0 { - return diag.FromErr(fmt.Errorf("no Summaries found with scanID %s", scanID)) - } - d.SetId(scanID) - } else { - d.SetId(dataSourceIBMSccPostureScanSummariesID(d)) - } - - if summariesList.First != nil { - err = d.Set("first", dataSourceSummariesListFlattenFirst(*summariesList.First)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting first %s", err)) - } - } - - if summariesList.Last != nil { - err = d.Set("last", dataSourceSummariesListFlattenLast(*summariesList.Last)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting last %s", err)) - } - } - - if summariesList.Previous != nil { - err = d.Set("previous", dataSourceSummariesListFlattenPrevious(*summariesList.Previous)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting previous %s", err)) - } - } - - if summariesList.Summaries != nil { - err = d.Set("summaries", dataSourceSummariesListFlattenSummaries(summariesList.Summaries)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting summaries %s", err)) - } - } - - return nil -} - -// dataSourceIBMSccPostureScanSummariesID returns a reasonable ID for the list. -func dataSourceIBMSccPostureScanSummariesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceSummariesListFlattenFirst(result posturemanagementv1.SummariesListFirst) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceSummariesListFirstToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceSummariesListFirstToMap(firstItem posturemanagementv1.SummariesListFirst) (firstMap map[string]interface{}) { - firstMap = map[string]interface{}{} - - if firstItem.Href != nil { - firstMap["href"] = firstItem.Href - } - - return firstMap -} - -func dataSourceSummariesListFlattenLast(result posturemanagementv1.SummariesListLast) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceSummariesListLastToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceSummariesListLastToMap(lastItem posturemanagementv1.SummariesListLast) (lastMap map[string]interface{}) { - lastMap = map[string]interface{}{} - - if lastItem.Href != nil { - lastMap["href"] = lastItem.Href - } - - return lastMap -} - -func dataSourceSummariesListFlattenPrevious(result posturemanagementv1.SummariesListPrevious) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceSummariesListPreviousToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceSummariesListPreviousToMap(previousItem posturemanagementv1.SummariesListPrevious) (previousMap map[string]interface{}) { - previousMap = map[string]interface{}{} - - if previousItem.Href != nil { - previousMap["href"] = previousItem.Href - } - - return previousMap -} - -func dataSourceSummariesListFlattenSummaries(result []posturemanagementv1.SummaryItem) (summaries []map[string]interface{}) { - for _, summariesItem := range result { - summaries = append(summaries, dataSourceSummariesListSummariesToMap(summariesItem)) - } - - return summaries -} - -func dataSourceSummariesListSummariesToMap(summariesItem posturemanagementv1.SummaryItem) (summariesMap map[string]interface{}) { - summariesMap = map[string]interface{}{} - - if summariesItem.ScanID != nil { - summariesMap["scan_id"] = summariesItem.ScanID - } - if summariesItem.ScanName != nil { - summariesMap["scan_name"] = summariesItem.ScanName - } - if summariesItem.ScopeID != nil { - summariesMap["scope_id"] = summariesItem.ScopeID - } - if summariesItem.ScopeName != nil { - summariesMap["scope_name"] = summariesItem.ScopeName - } - if summariesItem.ReportRunBy != nil { - summariesMap["report_run_by"] = summariesItem.ReportRunBy - } - if summariesItem.StartTime != nil { - summariesMap["start_time"] = summariesItem.StartTime.String() - } - if summariesItem.EndTime != nil { - summariesMap["end_time"] = summariesItem.EndTime.String() - } - if summariesItem.Status != nil { - summariesMap["status"] = summariesItem.Status - } - if summariesItem.Profile != nil { - profileList := []map[string]interface{}{} - profileMap := dataSourceSummariesListSummariesProfileToMap(*summariesItem.Profile) - profileList = append(profileList, profileMap) - summariesMap["profile"] = profileList - } - if summariesItem.GroupProfiles != nil { - groupProfilesList := []map[string]interface{}{} - groupProfilesMap := dataSourceSummariesListSummariesGroupProfilesToMap(*summariesItem.GroupProfiles) - groupProfilesList = append(groupProfilesList, groupProfilesMap) - summariesMap["group_profiles"] = groupProfilesList - } - - return summariesMap -} - -func dataSourceSummariesListSummariesProfileToMap(profileItem posturemanagementv1.ProfileResult) (profileMap map[string]interface{}) { - profileMap = map[string]interface{}{} - - if profileItem.ProfileID != nil { - profileMap["profile_id"] = profileItem.ProfileID - } - if profileItem.ProfileName != nil { - profileMap["profile_name"] = profileItem.ProfileName - } - if profileItem.ProfileType != nil { - profileMap["profile_type"] = profileItem.ProfileType - } - if profileItem.ValidationResult != nil { - validationResultList := []map[string]interface{}{} - validationResultMap := dataSourceSummariesListProfileValidationResultToMap(*profileItem.ValidationResult) - validationResultList = append(validationResultList, validationResultMap) - profileMap["validation_result"] = validationResultList - } - - return profileMap -} - -func dataSourceSummariesListProfileValidationResultToMap(validationResultItem posturemanagementv1.ScanResult) (validationResultMap map[string]interface{}) { - validationResultMap = map[string]interface{}{} - - if validationResultItem.GoalsPassCount != nil { - validationResultMap["goals_pass_count"] = validationResultItem.GoalsPassCount - } - if validationResultItem.GoalsUnableToPerformCount != nil { - validationResultMap["goals_unable_to_perform_count"] = validationResultItem.GoalsUnableToPerformCount - } - if validationResultItem.GoalsNotApplicableCount != nil { - validationResultMap["goals_not_applicable_count"] = validationResultItem.GoalsNotApplicableCount - } - if validationResultItem.GoalsFailCount != nil { - validationResultMap["goals_fail_count"] = validationResultItem.GoalsFailCount - } - if validationResultItem.GoalsTotalCount != nil { - validationResultMap["goals_total_count"] = validationResultItem.GoalsTotalCount - } - if validationResultItem.ControlsPassCount != nil { - validationResultMap["controls_pass_count"] = validationResultItem.ControlsPassCount - } - if validationResultItem.ControlsFailCount != nil { - validationResultMap["controls_fail_count"] = validationResultItem.ControlsFailCount - } - if validationResultItem.ControlsNotApplicableCount != nil { - validationResultMap["controls_not_applicable_count"] = validationResultItem.ControlsNotApplicableCount - } - if validationResultItem.ControlsUnableToPerformCount != nil { - validationResultMap["controls_unable_to_perform_count"] = validationResultItem.ControlsUnableToPerformCount - } - if validationResultItem.ControlsTotalCount != nil { - validationResultMap["controls_total_count"] = validationResultItem.ControlsTotalCount - } - - return validationResultMap -} - -func dataSourceSummariesListSummariesGroupProfilesToMap(groupProfilesItem posturemanagementv1.GroupProfileResult) (groupProfilesMap map[string]interface{}) { - groupProfilesMap = map[string]interface{}{} - - if groupProfilesItem.GroupProfileID != nil { - groupProfilesMap["group_profile_id"] = groupProfilesItem.GroupProfileID - } - if groupProfilesItem.GroupProfileName != nil { - groupProfilesMap["group_profile_name"] = groupProfilesItem.GroupProfileName - } - if groupProfilesItem.ProfileType != nil { - groupProfilesMap["profile_type"] = groupProfilesItem.ProfileType - } - if groupProfilesItem.ValidationResult != nil { - validationResultList := []map[string]interface{}{} - validationResultMap := dataSourceSummariesListGroupProfilesValidationResultToMap(*groupProfilesItem.ValidationResult) - validationResultList = append(validationResultList, validationResultMap) - groupProfilesMap["validation_result"] = validationResultList - } - if groupProfilesItem.Profiles != nil { - profilesList := []map[string]interface{}{} - for _, profilesItem := range groupProfilesItem.Profiles { - profilesList = append(profilesList, dataSourceSummariesListGroupProfilesProfilesToMap(profilesItem)) - } - groupProfilesMap["profiles"] = profilesList - } - - return groupProfilesMap -} - -func dataSourceSummariesListGroupProfilesValidationResultToMap(validationResultItem posturemanagementv1.ScanResult) (validationResultMap map[string]interface{}) { - validationResultMap = map[string]interface{}{} - - if validationResultItem.GoalsPassCount != nil { - validationResultMap["goals_pass_count"] = validationResultItem.GoalsPassCount - } - if validationResultItem.GoalsUnableToPerformCount != nil { - validationResultMap["goals_unable_to_perform_count"] = validationResultItem.GoalsUnableToPerformCount - } - if validationResultItem.GoalsNotApplicableCount != nil { - validationResultMap["goals_not_applicable_count"] = validationResultItem.GoalsNotApplicableCount - } - if validationResultItem.GoalsFailCount != nil { - validationResultMap["goals_fail_count"] = validationResultItem.GoalsFailCount - } - if validationResultItem.GoalsTotalCount != nil { - validationResultMap["goals_total_count"] = validationResultItem.GoalsTotalCount - } - if validationResultItem.ControlsPassCount != nil { - validationResultMap["controls_pass_count"] = validationResultItem.ControlsPassCount - } - if validationResultItem.ControlsFailCount != nil { - validationResultMap["controls_fail_count"] = validationResultItem.ControlsFailCount - } - if validationResultItem.ControlsNotApplicableCount != nil { - validationResultMap["controls_not_applicable_count"] = validationResultItem.ControlsNotApplicableCount - } - if validationResultItem.ControlsUnableToPerformCount != nil { - validationResultMap["controls_unable_to_perform_count"] = validationResultItem.ControlsUnableToPerformCount - } - if validationResultItem.ControlsTotalCount != nil { - validationResultMap["controls_total_count"] = validationResultItem.ControlsTotalCount - } - - return validationResultMap -} - -func dataSourceSummariesListGroupProfilesProfilesToMap(profilesItem posturemanagementv1.ProfilesResult) (profilesMap map[string]interface{}) { - profilesMap = map[string]interface{}{} - - if profilesItem.ProfileID != nil { - profilesMap["profile_id"] = profilesItem.ProfileID - } - if profilesItem.ProfileName != nil { - profilesMap["profile_name"] = profilesItem.ProfileName - } - if profilesItem.ProfileType != nil { - profilesMap["profile_type"] = profilesItem.ProfileType - } - if profilesItem.ValidationResult != nil { - validationResultList := []map[string]interface{}{} - validationResultMap := dataSourceSummariesListProfilesValidationResultToMap(*profilesItem.ValidationResult) - validationResultList = append(validationResultList, validationResultMap) - profilesMap["validation_result"] = validationResultList - } - - return profilesMap -} - -func dataSourceSummariesListProfilesValidationResultToMap(validationResultItem posturemanagementv1.Results) (validationResultMap map[string]interface{}) { - validationResultMap = map[string]interface{}{} - - if validationResultItem.ControlsPassCount != nil { - validationResultMap["controls_pass_count"] = validationResultItem.ControlsPassCount - } - if validationResultItem.ControlsFailCount != nil { - validationResultMap["controls_fail_count"] = validationResultItem.ControlsFailCount - } - if validationResultItem.ControlsNotApplicableCount != nil { - validationResultMap["controls_not_applicable_count"] = validationResultItem.ControlsNotApplicableCount - } - if validationResultItem.ControlsUnableToPerformCount != nil { - validationResultMap["controls_unable_to_perform_count"] = validationResultItem.ControlsUnableToPerformCount - } - if validationResultItem.ControlsTotalCount != nil { - validationResultMap["controls_total_count"] = validationResultItem.ControlsTotalCount - } - - return validationResultMap -} - -func dataSourceSummariesListGetNext(next interface{}) int64 { - if reflect.ValueOf(next).IsNil() { - return 0 - } - - u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) - if err != nil { - return 0 - } - - q := u.Query() - var page string - - if q.Get("start") != "" { - page = q.Get("start") - } else if q.Get("offset") != "" { - page = q.Get("offset") - } - - convertedVal, err := strconv.ParseInt(page, 10, 64) - if err != nil { - return 0 - } - return convertedVal -} diff --git a/ibm/data_source_ibm_scc_posture_scan_summaries_test.go b/ibm/data_source_ibm_scc_posture_scan_summaries_test.go deleted file mode 100644 index 0c3b7d0fc..000000000 --- a/ibm/data_source_ibm_scc_posture_scan_summaries_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccPostureScanSummariesDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccPostureScanSummariesDataSourceConfigBasic(scc_posture_profile_id, scc_posture_scope_id), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "profile_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "scope_id"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccPostureScanSummariesDataSourceConfigBasic(profileId string, scopeId string) string { - return fmt.Sprintf(` - data "ibm_scc_posture_scan_summaries" "scan_summaries" { - profile_id = "%s" - scope_id = "%s" - } - `, profileId, scopeId) -} diff --git a/ibm/data_source_ibm_scc_posture_scan_summary.go b/ibm/data_source_ibm_scc_posture_scan_summary.go deleted file mode 100644 index a89601b86..000000000 --- a/ibm/data_source_ibm_scc_posture_scan_summary.go +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -func dataSourceIBMSccPostureScansSummary() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccPostureScansSummaryRead, - - Schema: map[string]*schema.Schema{ - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Your Scan ID.", - }, - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", - }, - "discover_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The scan discovery ID.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The scan profile name.", - }, - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The scan summary scope ID.", - }, - "controls": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The list of controls on the scan summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "control_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The scan summary control ID.", - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The control status.", - }, - "external_control_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The external control ID.", - }, - "control_desciption": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The scan profile name.", - }, - "goals": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The list of goals on the control.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "goal_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The description of the goal.", - }, - "goal_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The goal ID.", - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The goal status.", - }, - "severity": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The severity of the goal.", - }, - "completed_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The report completed time.", - }, - "error": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The error on goal validation.", - }, - "resource_result": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The list of resource results.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "resource_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource name.", - }, - "resource_types": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - "resource_status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource control result status.", - }, - "display_expected_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The expected results of a resource.", - }, - "actual_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The actual results of a resource.", - }, - "results_info": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The results information.", - }, - "not_applicable_reason": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The reason for goal not applicable for a resource.", - }, - }, - }, - }, - "goal_applicability_criteria": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The criteria that defines how a profile applies.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "environment": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of environments that a profile can be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of resources that a profile can be used with.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_category": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The type of environment that a profile is able to be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_category": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The type of resource that a profile is able to be applied to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_type": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The resource type that the profile applies to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "software_details": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The software that the profile applies to.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "os_details": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The operating system that the profile applies to.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "additional_details": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "Any additional details about the profile.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_category_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The type of environment that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "environment_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The environment that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_category_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The type of resource that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_type_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "A further classification of the type of resource that your scope is targeted to.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "resource_description": &schema.Schema{ - Type: schema.TypeMap, - Computed: true, - Description: "The resource that is scanned as part of your scope.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - }, - }, - }, - "resource_statistics": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A scans summary controls.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "resource_pass_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The resource count of pass controls.", - }, - "resource_fail_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The resource count of fail controls.", - }, - "resource_unable_to_perform_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The number of resources that were unable to be scanned against a control.", - }, - "resource_not_applicable_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The resource count of not applicable(na) controls.", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccPostureScansSummaryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - postureManagementClient, err := meta.(ClientSession).PostureManagementV1() - if err != nil { - return diag.FromErr(err) - } - - scansSummaryOptions := &posturemanagementv1.ScansSummaryOptions{} - - scansSummaryOptions.SetScanID(d.Get("scan_id").(string)) - scansSummaryOptions.SetProfileID(d.Get("profile_id").(string)) - - summary, response, err := postureManagementClient.ScansSummaryWithContext(context, scansSummaryOptions) - if err != nil { - log.Printf("[DEBUG] ScansSummaryWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ScansSummaryWithContext failed %s\n%s", err, response)) - } - - d.SetId(dataSourceIBMSccPostureScansSummaryID(d)) - if err = d.Set("discover_id", summary.DiscoverID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting discover_id: %s", err)) - } - if err = d.Set("profile_name", summary.ProfileName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting profile_name: %s", err)) - } - if err = d.Set("scope_id", summary.ScopeID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting scope_id: %s", err)) - } - - if summary.Controls != nil { - err = d.Set("controls", dataSourceSummaryFlattenControls(summary.Controls)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting controls %s", err)) - } - } - - return nil -} - -// dataSourceIBMSccPostureScansSummaryID returns a reasonable ID for the list. -func dataSourceIBMSccPostureScansSummaryID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceSummaryFlattenControls(result []posturemanagementv1.Control) (controls []map[string]interface{}) { - for _, controlsItem := range result { - controls = append(controls, dataSourceSummaryControlsToMap(controlsItem)) - } - - return controls -} - -func dataSourceSummaryControlsToMap(controlsItem posturemanagementv1.Control) (controlsMap map[string]interface{}) { - controlsMap = map[string]interface{}{} - - if controlsItem.ControlID != nil { - controlsMap["control_id"] = controlsItem.ControlID - } - if controlsItem.Status != nil { - controlsMap["status"] = controlsItem.Status - } - if controlsItem.ExternalControlID != nil { - controlsMap["external_control_id"] = controlsItem.ExternalControlID - } - if controlsItem.ControlDesciption != nil { - controlsMap["control_desciption"] = controlsItem.ControlDesciption - } - if controlsItem.Goals != nil { - goalsList := []map[string]interface{}{} - for _, goalsItem := range controlsItem.Goals { - goalsList = append(goalsList, dataSourceSummaryControlsGoalsToMap(goalsItem)) - } - controlsMap["goals"] = goalsList - } - if controlsItem.ResourceStatistics != nil { - resourceStatisticsList := []map[string]interface{}{} - resourceStatisticsMap := dataSourceSummaryControlsResourceStatisticsToMap(*controlsItem.ResourceStatistics) - resourceStatisticsList = append(resourceStatisticsList, resourceStatisticsMap) - controlsMap["resource_statistics"] = resourceStatisticsList - } - - return controlsMap -} - -func dataSourceSummaryControlsGoalsToMap(goalsItem posturemanagementv1.Goal) (goalsMap map[string]interface{}) { - goalsMap = map[string]interface{}{} - - if goalsItem.GoalDescription != nil { - goalsMap["goal_description"] = goalsItem.GoalDescription - } - if goalsItem.GoalID != nil { - goalsMap["goal_id"] = goalsItem.GoalID - } - if goalsItem.Status != nil { - goalsMap["status"] = goalsItem.Status - } - if goalsItem.Severity != nil { - goalsMap["severity"] = goalsItem.Severity - } - if goalsItem.CompletedTime != nil { - goalsMap["completed_time"] = goalsItem.CompletedTime.String() - } - if goalsItem.Error != nil { - goalsMap["error"] = goalsItem.Error - } - if goalsItem.ResourceResult != nil { - resourceResultList := []map[string]interface{}{} - for _, resourceResultItem := range goalsItem.ResourceResult { - resourceResultList = append(resourceResultList, dataSourceSummaryGoalsResourceResultToMap(resourceResultItem)) - } - goalsMap["resource_result"] = resourceResultList - } - if goalsItem.GoalApplicabilityCriteria != nil { - goalApplicabilityCriteriaList := []map[string]interface{}{} - goalApplicabilityCriteriaMap := dataSourceSummaryGoalsGoalApplicabilityCriteriaToMap(*goalsItem.GoalApplicabilityCriteria) - goalApplicabilityCriteriaList = append(goalApplicabilityCriteriaList, goalApplicabilityCriteriaMap) - goalsMap["goal_applicability_criteria"] = goalApplicabilityCriteriaList - } - - return goalsMap -} - -func dataSourceSummaryGoalsResourceResultToMap(resourceResultItem posturemanagementv1.ResourceResult) (resourceResultMap map[string]interface{}) { - resourceResultMap = map[string]interface{}{} - - if resourceResultItem.ResourceName != nil { - resourceResultMap["resource_name"] = resourceResultItem.ResourceName - } - if resourceResultItem.ResourceTypes != nil { - resourceResultMap["resource_types"] = resourceResultItem.ResourceTypes - } - if resourceResultItem.ResourceStatus != nil { - resourceResultMap["resource_status"] = resourceResultItem.ResourceStatus - } - if resourceResultItem.DisplayExpectedValue != nil { - resourceResultMap["display_expected_value"] = resourceResultItem.DisplayExpectedValue - } - if resourceResultItem.ActualValue != nil { - resourceResultMap["actual_value"] = resourceResultItem.ActualValue - } - if resourceResultItem.ResultsInfo != nil { - resourceResultMap["results_info"] = resourceResultItem.ResultsInfo - } - if resourceResultItem.NotApplicableReason != nil { - resourceResultMap["not_applicable_reason"] = resourceResultItem.NotApplicableReason - } - - return resourceResultMap -} - -func dataSourceSummaryGoalsGoalApplicabilityCriteriaToMap(goalApplicabilityCriteriaItem posturemanagementv1.GoalApplicabilityCriteria) (goalApplicabilityCriteriaMap map[string]interface{}) { - goalApplicabilityCriteriaMap = map[string]interface{}{} - - if goalApplicabilityCriteriaItem.Environment != nil { - goalApplicabilityCriteriaMap["environment"] = goalApplicabilityCriteriaItem.Environment - } - if goalApplicabilityCriteriaItem.Resource != nil { - goalApplicabilityCriteriaMap["resource"] = goalApplicabilityCriteriaItem.Resource - } - if goalApplicabilityCriteriaItem.EnvironmentCategory != nil { - goalApplicabilityCriteriaMap["environment_category"] = goalApplicabilityCriteriaItem.EnvironmentCategory - } - if goalApplicabilityCriteriaItem.ResourceCategory != nil { - goalApplicabilityCriteriaMap["resource_category"] = goalApplicabilityCriteriaItem.ResourceCategory - } - if goalApplicabilityCriteriaItem.ResourceType != nil { - goalApplicabilityCriteriaMap["resource_type"] = goalApplicabilityCriteriaItem.ResourceType - } - if goalApplicabilityCriteriaItem.SoftwareDetails != nil { - goalApplicabilityCriteriaMap["software_details"] = goalApplicabilityCriteriaItem.SoftwareDetails - } - if goalApplicabilityCriteriaItem.OsDetails != nil { - goalApplicabilityCriteriaMap["os_details"] = goalApplicabilityCriteriaItem.OsDetails - } - if goalApplicabilityCriteriaItem.AdditionalDetails != nil { - goalApplicabilityCriteriaMap["additional_details"] = goalApplicabilityCriteriaItem.AdditionalDetails - } - if goalApplicabilityCriteriaItem.EnvironmentCategoryDescription != nil { - goalApplicabilityCriteriaMap["environment_category_description"] = goalApplicabilityCriteriaItem.EnvironmentCategoryDescription - } - if goalApplicabilityCriteriaItem.EnvironmentDescription != nil { - goalApplicabilityCriteriaMap["environment_description"] = goalApplicabilityCriteriaItem.EnvironmentDescription - } - if goalApplicabilityCriteriaItem.ResourceCategoryDescription != nil { - goalApplicabilityCriteriaMap["resource_category_description"] = goalApplicabilityCriteriaItem.ResourceCategoryDescription - } - if goalApplicabilityCriteriaItem.ResourceTypeDescription != nil { - goalApplicabilityCriteriaMap["resource_type_description"] = goalApplicabilityCriteriaItem.ResourceTypeDescription - } - if goalApplicabilityCriteriaItem.ResourceDescription != nil { - goalApplicabilityCriteriaMap["resource_description"] = goalApplicabilityCriteriaItem.ResourceDescription - } - - return goalApplicabilityCriteriaMap -} - -func dataSourceSummaryControlsResourceStatisticsToMap(resourceStatisticsItem posturemanagementv1.ResourceStatistics) (resourceStatisticsMap map[string]interface{}) { - resourceStatisticsMap = map[string]interface{}{} - - if resourceStatisticsItem.ResourcePassCount != nil { - resourceStatisticsMap["resource_pass_count"] = resourceStatisticsItem.ResourcePassCount - } - if resourceStatisticsItem.ResourceFailCount != nil { - resourceStatisticsMap["resource_fail_count"] = resourceStatisticsItem.ResourceFailCount - } - if resourceStatisticsItem.ResourceUnableToPerformCount != nil { - resourceStatisticsMap["resource_unable_to_perform_count"] = resourceStatisticsItem.ResourceUnableToPerformCount - } - if resourceStatisticsItem.ResourceNotApplicableCount != nil { - resourceStatisticsMap["resource_not_applicable_count"] = resourceStatisticsItem.ResourceNotApplicableCount - } - - return resourceStatisticsMap -} diff --git a/ibm/data_source_ibm_scc_posture_scopes.go b/ibm/data_source_ibm_scc_posture_scopes.go deleted file mode 100644 index de53e26cd..000000000 --- a/ibm/data_source_ibm_scc_posture_scopes.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/scc-go-sdk/posturemanagementv1" -) - -func dataSourceIBMSccPostureScopes() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccPostureScopesRead, - - Schema: map[string]*schema.Schema{ - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "An auto-generated unique identifier for the scope.", - }, - "scopes": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Scopes.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A detailed description of the scope.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user who created the scope.", - }, - "modified_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user who most recently modified the scope.", - }, - "scope_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "An auto-generated unique identifier for the scope.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A unique name for your scope.", - }, - "enabled": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether scope is enabled/disabled.", - }, - "environment_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The environment that the scope is targeted to.", - }, - "created_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The time that the scope was created in UTC.", - }, - "modified_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The time that the scope was last modified in UTC.", - }, - "last_scan_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The last type of scan that was run on the scope.", - }, - "last_scan_type_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A description of the last scan type.", - }, - "last_scan_status_updated_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The last time that a scan status for a scope was updated in UTC.", - }, - "collectors_id": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The unique IDs of the collectors that are attached to the scope.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "scans": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of the scans that have been run on the scope.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "scan_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "An auto-generated unique identifier for the scan.", - }, - "discover_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "An auto-generated unique identifier for discovery.", - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The status of the collector as it completes a scan.", - }, - "status_message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The current status of the collector.", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccPostureScopesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - postureManagementClient, err := meta.(ClientSession).PostureManagementV1() - if err != nil { - return diag.FromErr(err) - } - - listScopesOptions := &posturemanagementv1.ListScopesOptions{} - - scopesList, response, err := postureManagementClient.ListScopesWithContext(context, listScopesOptions) - if err != nil { - log.Printf("[DEBUG] ListScopesWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListScopesWithContext failed %s\n%s", err, response)) - } - - // Use the provided filter argument and construct a new list with only the requested resource(s) - var matchScopes []posturemanagementv1.ScopeItem - var scopeID string - var suppliedFilter bool - - if v, ok := d.GetOk("scope_id"); ok { - scopeID = v.(string) - suppliedFilter = true - for _, data := range scopesList.Scopes { - if *data.ScopeID == scopeID { - matchScopes = append(matchScopes, data) - } - } - } else { - matchScopes = scopesList.Scopes - } - scopesList.Scopes = matchScopes - - if suppliedFilter { - if len(scopesList.Scopes) == 0 { - return diag.FromErr(fmt.Errorf("no Scopes found with scopeID %s", scopeID)) - } - d.SetId(scopeID) - } else { - d.SetId(dataSourceIBMSccPostureScopesID(d)) - } - - if scopesList.Scopes != nil { - err = d.Set("scopes", dataSourceScopesListFlattenScopes(scopesList.Scopes)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting scopes %s", err)) - } - } - - return nil -} - -// dataSourceIBMSccPostureScopesID returns a reasonable ID for the list. -func dataSourceIBMSccPostureScopesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceScopesListFlattenScopes(result []posturemanagementv1.ScopeItem) (scopes []map[string]interface{}) { - for _, scopesItem := range result { - scopes = append(scopes, dataSourceScopesListScopesToMap(scopesItem)) - } - - return scopes -} - -func dataSourceScopesListScopesToMap(scopesItem posturemanagementv1.ScopeItem) (scopesMap map[string]interface{}) { - scopesMap = map[string]interface{}{} - - if scopesItem.Description != nil { - scopesMap["description"] = scopesItem.Description - } - if scopesItem.CreatedBy != nil { - scopesMap["created_by"] = scopesItem.CreatedBy - } - if scopesItem.ModifiedBy != nil { - scopesMap["modified_by"] = scopesItem.ModifiedBy - } - if scopesItem.ScopeID != nil { - scopesMap["scope_id"] = scopesItem.ScopeID - } - if scopesItem.Name != nil { - scopesMap["name"] = scopesItem.Name - } - if scopesItem.Enabled != nil { - scopesMap["enabled"] = scopesItem.Enabled - } - if scopesItem.EnvironmentType != nil { - scopesMap["environment_type"] = scopesItem.EnvironmentType - } - if scopesItem.CreatedTime != nil { - scopesMap["created_time"] = scopesItem.CreatedTime.String() - } - if scopesItem.ModifiedTime != nil { - scopesMap["modified_time"] = scopesItem.ModifiedTime.String() - } - if scopesItem.LastScanType != nil { - scopesMap["last_scan_type"] = scopesItem.LastScanType - } - if scopesItem.LastScanTypeDescription != nil { - scopesMap["last_scan_type_description"] = scopesItem.LastScanTypeDescription - } - if scopesItem.LastScanStatusUpdatedTime != nil { - scopesMap["last_scan_status_updated_time"] = scopesItem.LastScanStatusUpdatedTime.String() - } - if scopesItem.CollectorsID != nil { - scopesMap["collectors_id"] = scopesItem.CollectorsID - } - if scopesItem.Scans != nil { - scansList := []map[string]interface{}{} - for _, scansItem := range scopesItem.Scans { - scansList = append(scansList, dataSourceScopesListScopesScansToMap(scansItem)) - } - scopesMap["scans"] = scansList - } - - return scopesMap -} - -func dataSourceScopesListScopesScansToMap(scansItem posturemanagementv1.Scan) (scansMap map[string]interface{}) { - scansMap = map[string]interface{}{} - - if scansItem.ScanID != nil { - scansMap["scan_id"] = scansItem.ScanID - } - if scansItem.DiscoverID != nil { - scansMap["discover_id"] = scansItem.DiscoverID - } - if scansItem.Status != nil { - scansMap["status"] = scansItem.Status - } - if scansItem.StatusMessage != nil { - scansMap["status_message"] = scansItem.StatusMessage - } - - return scansMap -} diff --git a/ibm/data_source_ibm_scc_posture_scopes_test.go b/ibm/data_source_ibm_scc_posture_scopes_test.go deleted file mode 100644 index 5d4e97912..000000000 --- a/ibm/data_source_ibm_scc_posture_scopes_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccPostureScopesDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccPostureScopesDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "id"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccPostureScopesDataSourceConfigBasic() string { - return fmt.Sprintf(` - data "ibm_scc_posture_scopes" "list_scopes" { - } - `) -} diff --git a/ibm/data_source_ibm_scc_si_note.go b/ibm/data_source_ibm_scc_si_note.go deleted file mode 100644 index 002bc1dce..000000000 --- a/ibm/data_source_ibm_scc_si_note.go +++ /dev/null @@ -1,626 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "encoding/json" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/scc-go-sdk/findingsv1" -) - -func dataSourceIBMSccSiNote() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccSiNoteRead, - - Schema: map[string]*schema.Schema{ - "account_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - "provider_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Part of the parent. This field contains the provider ID. For example: providers/{provider_id}.", - }, - "note_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Second part of note `name`: providers/{provider_id}/notes/{note_id}.", - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A one sentence description of your note.", - }, - "long_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A more detailed description of your note.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of note. Use this field to filter notes and occurences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard.", - }, - "related_url": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "label": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Label to describe usage of the URL.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL that you want to associate with the note.", - }, - }, - }, - }, - "create_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was created. This field can be used as a filter in list requests.", - }, - "update_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was last updated. This field can be used as a filter in list requests.", - }, - "shared": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "True if this note can be shared by multiple accounts.", - }, - "reported_by": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The entity reporting a note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The id of this reporter.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this reporter.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url of this reporter.", - }, - }, - }, - }, - "finding": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "FindingType provides details about a finding note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "severity": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact.", - }, - "next_steps": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Common remediation steps for the finding of this type.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Title of this next step.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL associated to this next steps.", - }, - }, - }, - }, - }, - }, - }, - "kpi": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "KpiType provides details about a KPI note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "aggregation_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The aggregation type of the KPI values. - SUM: A single-value metrics aggregation type that sums up numeric values that are extracted from KPI occurrences.", - }, - }, - }, - }, - "card": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "section": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The section this card belongs to.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this card.", - }, - "subtitle": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The subtitle of this card.", - }, - "order": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The order of the card in which it will appear on SA dashboard in the mentioned section.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The finding note names associated to this card.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "requires_configuration": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - }, - "badge_text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text associated to the card's badge.", - }, - "badge_image": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The base64 content of the image associated to the card's badge.", - }, - "elements": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The elements of this card.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this card element.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- NUMERIC: Single numeric value- BREAKDOWN: Breakdown of numeric values- TIME_SERIES: Time-series of numeric values.", - }, - "default_time_range": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default time range of this card element.", - }, - "value_type": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "value_types": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the value types associated to this card element.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "default_interval": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default interval of the time series.", - }, - }, - }, - }, - }, - }, - }, - "section": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this section.", - }, - "image": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The image of this section.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccSiNoteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := d.Get("account_id").(string) - log.Println(fmt.Sprintf("[DEBUG] using specified AccountID %s", accountID)) - if accountID == "" { - accountID = userDetails.userAccount - log.Println(fmt.Sprintf("[DEBUG] AccountID not spedified, using %s", accountID)) - } - findingsClient.AccountID = &accountID - - getNoteOptions := &findingsv1.GetNoteOptions{} - - getNoteOptions.SetProviderID(d.Get("provider_id").(string)) - getNoteOptions.SetNoteID(d.Get("note_id").(string)) - - apiNote, response, err := findingsClient.GetNoteWithContext(context, getNoteOptions) - if err != nil { - log.Printf("[DEBUG] GetNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetNoteWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", *getNoteOptions.ProviderID, *getNoteOptions.NoteID)) - if err = d.Set("short_description", apiNote.ShortDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) - } - if err = d.Set("long_description", apiNote.LongDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) - } - if err = d.Set("kind", apiNote.Kind); err != nil { - return diag.FromErr(fmt.Errorf("Error setting kind: %s", err)) - } - - if apiNote.RelatedURL != nil { - err = d.Set("related_url", dataSourceAPINoteFlattenRelatedURL(apiNote.RelatedURL)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting related_url %s", err)) - } - } - if err = d.Set("create_time", dateTimeToString(apiNote.CreateTime)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting create_time: %s", err)) - } - if err = d.Set("update_time", dateTimeToString(apiNote.UpdateTime)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting update_time: %s", err)) - } - if err = d.Set("shared", apiNote.Shared); err != nil { - return diag.FromErr(fmt.Errorf("Error setting shared: %s", err)) - } - - if apiNote.ReportedBy != nil { - err = d.Set("reported_by", dataSourceAPINoteFlattenReportedBy(*apiNote.ReportedBy)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting reported_by %s", err)) - } - } - - if apiNote.Finding != nil { - err = d.Set("finding", dataSourceAPINoteFlattenFinding(*apiNote.Finding)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting finding %s", err)) - } - } - - if apiNote.Kpi != nil { - err = d.Set("kpi", dataSourceAPINoteFlattenKpi(*apiNote.Kpi)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting kpi %s", err)) - } - } - - if apiNote.Card != nil { - err = d.Set("card", dataSourceAPINoteFlattenCard(*apiNote.Card)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting card %s", err)) - } - } - - if apiNote.Section != nil { - err = d.Set("section", dataSourceAPINoteFlattenSection(*apiNote.Section)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting section %s", err)) - } - } - - return nil -} - -func dataSourceAPINoteFlattenRelatedURL(result []findingsv1.APINoteRelatedURL) (relatedURL []map[string]interface{}) { - for _, relatedURLItem := range result { - relatedURL = append(relatedURL, dataSourceAPINoteRelatedURLToMap(relatedURLItem)) - } - - return relatedURL -} - -func dataSourceAPINoteRelatedURLToMap(relatedURLItem findingsv1.APINoteRelatedURL) (relatedURLMap map[string]interface{}) { - relatedURLMap = map[string]interface{}{} - - if relatedURLItem.Label != nil { - relatedURLMap["label"] = relatedURLItem.Label - } - if relatedURLItem.URL != nil { - relatedURLMap["url"] = relatedURLItem.URL - } - - return relatedURLMap -} - -func dataSourceAPINoteFlattenReportedBy(result findingsv1.Reporter) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteReportedByToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINoteReportedByToMap(reportedByItem findingsv1.Reporter) (reportedByMap map[string]interface{}) { - reportedByMap = map[string]interface{}{} - - if reportedByItem.ID != nil { - reportedByMap["id"] = reportedByItem.ID - } - if reportedByItem.Title != nil { - reportedByMap["title"] = reportedByItem.Title - } - if reportedByItem.URL != nil { - reportedByMap["url"] = reportedByItem.URL - } - - return reportedByMap -} - -func dataSourceAPINoteFlattenFinding(result findingsv1.FindingType) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteFindingToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINoteFindingToMap(findingItem findingsv1.FindingType) (findingMap map[string]interface{}) { - findingMap = map[string]interface{}{} - - if findingItem.Severity != nil { - findingMap["severity"] = findingItem.Severity - } - if findingItem.NextSteps != nil { - nextStepsList := []map[string]interface{}{} - for _, nextStepsItem := range findingItem.NextSteps { - nextStepsList = append(nextStepsList, dataSourceAPINoteFindingNextStepsToMap(nextStepsItem)) - } - findingMap["next_steps"] = nextStepsList - } - - return findingMap -} - -func dataSourceAPINoteFindingNextStepsToMap(nextStepsItem findingsv1.RemediationStep) (nextStepsMap map[string]interface{}) { - nextStepsMap = map[string]interface{}{} - - if nextStepsItem.Title != nil { - nextStepsMap["title"] = nextStepsItem.Title - } - if nextStepsItem.URL != nil { - nextStepsMap["url"] = nextStepsItem.URL - } - - return nextStepsMap -} - -func dataSourceAPINoteFlattenKpi(result findingsv1.KpiType) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteKpiToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINoteKpiToMap(kpiItem findingsv1.KpiType) (kpiMap map[string]interface{}) { - kpiMap = map[string]interface{}{} - - if kpiItem.AggregationType != nil { - kpiMap["aggregation_type"] = kpiItem.AggregationType - } - - return kpiMap -} - -func dataSourceAPINoteFlattenCard(result findingsv1.Card) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteCardToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINoteCardToMap(cardItem findingsv1.Card) (cardMap map[string]interface{}) { - cardMap = map[string]interface{}{} - - if cardItem.Section != nil { - cardMap["section"] = cardItem.Section - } - if cardItem.Title != nil { - cardMap["title"] = cardItem.Title - } - if cardItem.Subtitle != nil { - cardMap["subtitle"] = cardItem.Subtitle - } - if cardItem.Order != nil { - cardMap["order"] = cardItem.Order - } - if cardItem.FindingNoteNames != nil { - cardMap["finding_note_names"] = cardItem.FindingNoteNames - } - if cardItem.RequiresConfiguration != nil { - cardMap["requires_configuration"] = cardItem.RequiresConfiguration - } - if cardItem.BadgeText != nil { - cardMap["badge_text"] = cardItem.BadgeText - } - if cardItem.BadgeImage != nil { - cardMap["badge_image"] = cardItem.BadgeImage - } - if cardItem.Elements != nil { - elementsList := []map[string]interface{}{} - for _, elementsItem := range cardItem.Elements { - elementsList = append(elementsList, dataSourceAPINoteCardElementsToMap(elementsItem)) - } - cardMap["elements"] = elementsList - } - - return cardMap -} - -func dataSourceAPINoteCardElementsToMap(elementsItem findingsv1.CardElementIntf) (elementsMap map[string]interface{}) { - cardElementMap := map[string]interface{}{} - - cardElementByte, _ := json.Marshal(elementsItem) - _ = json.Unmarshal(cardElementByte, &cardElementMap) - - if cardElementMap["value_type"] != nil && cardElementMap["value_type"].(map[string]interface{}) != nil { - cardElementValueTypeMapSlice := make([]map[string]interface{}, 1) - cardElementValueTypeMapSlice[0] = cardElementMap["value_type"].(map[string]interface{}) - - cardElementMap["value_type"] = cardElementValueTypeMapSlice - - } - - return cardElementMap -} - -func dataSourceAPINoteElementsValueTypeToMap(valueTypeItem findingsv1.NumericCardElementValueType) (valueTypeMap map[string]interface{}) { - valueTypeMap = map[string]interface{}{} - - if valueTypeItem.Kind != nil { - valueTypeMap["kind"] = valueTypeItem.Kind - } - if valueTypeItem.KpiNoteName != nil { - valueTypeMap["kpi_note_name"] = valueTypeItem.KpiNoteName - } - if valueTypeItem.Text != nil { - valueTypeMap["text"] = valueTypeItem.Text - } - if valueTypeItem.FindingNoteNames != nil { - valueTypeMap["finding_note_names"] = valueTypeItem.FindingNoteNames - } - - return valueTypeMap -} - -func dataSourceAPINoteElementsValueTypesToMap(valueTypesItem findingsv1.ValueTypeIntf) (valueTypesMap map[string]interface{}) { - valueTypesMap = map[string]interface{}{} - - // TODO: Add code here to convert a findingsv1.ValueTypeIntf to map[string]interface{} - - return valueTypesMap -} - -func dataSourceAPINoteFlattenSection(result findingsv1.Section) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteSectionToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINoteSectionToMap(sectionItem findingsv1.Section) (sectionMap map[string]interface{}) { - sectionMap = map[string]interface{}{} - - if sectionItem.Title != nil { - sectionMap["title"] = sectionItem.Title - } - if sectionItem.Image != nil { - sectionMap["image"] = sectionItem.Image - } - - return sectionMap -} diff --git a/ibm/data_source_ibm_scc_si_note_test.go b/ibm/data_source_ibm_scc_si_note_test.go deleted file mode 100644 index 65c45fb7f..000000000 --- a/ibm/data_source_ibm_scc_si_note_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccSiNoteDataSourceBasic(t *testing.T) { - apiNoteProviderID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - apiNoteLongDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - apiNoteKind := "FINDING" - apiNoteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteDataSourceConfigBasic(scc_si_account, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "provider_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "note_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "short_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "long_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "kind"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "reported_by.#"), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNoteDataSourceAllArgs(t *testing.T) { - apiNoteProviderID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - apiNoteLongDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - apiNoteKind := "FINDING" - apiNoteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShared := "true" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteDataSourceConfig(scc_si_account, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID, apiNoteShared), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "provider_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "note_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "short_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "long_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "kind"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "related_url.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "related_url.0.label"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "related_url.0.url"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "create_time"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "update_time"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "shared"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "reported_by.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_note.scc_si_note", "finding.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccSiNoteDataSourceConfigBasic(accountID string, apiNoteProviderID string, apiNoteShortDescription string, apiNoteLongDescription string, apiNoteKind string, apiNoteID string) string { - return fmt.Sprintf(` - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - - data "ibm_scc_si_note" "scc_si_note" { - account_id = ibm_scc_si_note.scc_si_note.account_id - provider_id = ibm_scc_si_note.scc_si_note.provider_id - note_id = ibm_scc_si_note.scc_si_note.note_id - } - `, accountID, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID) -} - -func testAccCheckIBMSccSiNoteDataSourceConfig(accountID string, apiNoteProviderID string, apiNoteShortDescription string, apiNoteLongDescription string, apiNoteKind string, apiNoteID string, apiNoteShared string) string { - return fmt.Sprintf(` - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - related_url { - label = "label" - url = "url" - } - shared = %s - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - - data "ibm_scc_si_note" "scc_si_note" { - account_id = ibm_scc_si_note.scc_si_note.account_id - provider_id = ibm_scc_si_note.scc_si_note.provider_id - note_id = ibm_scc_si_note.scc_si_note.note_id - } - `, accountID, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID, apiNoteShared) -} diff --git a/ibm/data_source_ibm_scc_si_notes.go b/ibm/data_source_ibm_scc_si_notes.go deleted file mode 100644 index b1915434d..000000000 --- a/ibm/data_source_ibm_scc_si_notes.go +++ /dev/null @@ -1,668 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/scc-go-sdk/findingsv1" -) - -func ValidatePageSize(val interface{}, key string) (warns []string, errs []error) { - v := int64(val.(int)) - if v < 2 { - errs = append(errs, fmt.Errorf("%q must be atleast 2, got: %d", key, v)) - } - return -} - -func dataSourceIBMSccSiNotes() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccSiNotesRead, - - Schema: map[string]*schema.Schema{ - "account_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - "provider_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Part of the parent. This field contains the provider ID. For example: providers/{provider_id}.", - }, - "page_size": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ValidateFunc: ValidatePageSize, - Description: "Number of notes to return in the list.", - }, - "page_token": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Token to provide to skip to a particular spot in the list.", - }, - "notes": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The notes requested.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "short_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A one sentence description of your note.", - }, - "long_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A more detailed description of your note.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of note. Use this field to filter notes and occurences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard.", - }, - "related_url": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "label": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Label to describe usage of the URL.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL that you want to associate with the note.", - }, - }, - }, - }, - "create_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was created. This field can be used as a filter in list requests.", - }, - "update_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was last updated. This field can be used as a filter in list requests.", - }, - "shared": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "True if this note can be shared by multiple accounts.", - }, - "reported_by": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The entity reporting a note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The id of this reporter.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this reporter.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url of this reporter.", - }, - }, - }, - }, - "finding": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "FindingType provides details about a finding note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "severity": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact.", - }, - "next_steps": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Common remediation steps for the finding of this type.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Title of this next step.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL associated to this next steps.", - }, - }, - }, - }, - }, - }, - }, - "kpi": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "KpiType provides details about a KPI note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "aggregation_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The aggregation type of the KPI values. - SUM: A single-value metrics aggregation type that sums up numeric values that are extracted from KPI occurrences.", - }, - }, - }, - }, - "card": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "section": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The section this card belongs to.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this card.", - }, - "subtitle": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The subtitle of this card.", - }, - "order": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The order of the card in which it will appear on SA dashboard in the mentioned section.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The finding note names associated to this card.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "requires_configuration": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - }, - "badge_text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text associated to the card's badge.", - }, - "badge_image": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The base64 content of the image associated to the card's badge.", - }, - "elements": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The elements of this card.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this card element.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- NUMERIC: Single numeric value- BREAKDOWN: Breakdown of numeric values- TIME_SERIES: Time-series of numeric values.", - }, - "default_time_range": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default time range of this card element.", - }, - "value_type": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "value_types": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the value types associated to this card element.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "default_interval": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The default interval of the time series.", - }, - }, - }, - }, - }, - }, - }, - "section": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The title of this section.", - }, - "image": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The image of this section.", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSccSiNotesValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "page_size", - ValidateFunctionIdentifier: IntBetween, - Required: false, - MinValue: "2"}) - - ibmSccSiNotesDataSourceValidator := ResourceValidator{ResourceName: "ibm_scc_si_notes", Schema: validateSchema} - return &ibmSccSiNotesDataSourceValidator -} - -func dataSourceIBMSccSiNotesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := d.Get("account_id").(string) - log.Println(fmt.Sprintf("[DEBUG] using specified AccountID %s", accountID)) - if accountID == "" { - accountID = userDetails.userAccount - log.Println(fmt.Sprintf("[DEBUG] AccountID not spedified, using %s", accountID)) - } - findingsClient.AccountID = &accountID - - listNoteOptions := &findingsv1.ListNotesOptions{} - - if pageSize, ok := d.GetOk("page_size"); ok { - listNoteOptions.SetPageSize(int64(pageSize.(int))) - } - if pageToken, ok := d.GetOk("page_token"); ok { - listNoteOptions.SetPageToken(pageToken.(string)) - } - listNoteOptions.SetProviderID(d.Get("provider_id").(string)) - - apiListNotesResponse, response, err := findingsClient.ListNotesWithContext(context, listNoteOptions) - if err != nil { - log.Printf("[DEBUG] GetNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetNoteWithContext failed %s\n%s", err, response)) - } - - d.SetId(dataSourceIBMSccSiNotesID(d)) - - if apiListNotesResponse.Notes != nil { - err = d.Set("notes", dataSourceAPIListNotesResponseFlattenProviders(apiListNotesResponse.Notes)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting notes %s", err)) - } - } - - return nil -} - -func dataSourceAPIListNotesResponseFlattenProviders(result []findingsv1.APINote) (notes []map[string]interface{}) { - for _, notesItem := range result { - notes = append(notes, dataSourceAPIListNotesResponseProvidersToMap(notesItem)) - } - - return notes -} - -func dataSourceAPIListNotesResponseProvidersToMap(notesItem findingsv1.APINote) (notesMap map[string]interface{}) { - notesMap = map[string]interface{}{} - - if notesItem.ShortDescription != nil { - notesMap["short_description"] = notesItem.ShortDescription - } - if notesItem.LongDescription != nil { - notesMap["long_description"] = notesItem.LongDescription - } - if notesItem.Kind != nil { - notesMap["kind"] = notesItem.Kind - } - - if notesItem.RelatedURL != nil { - notesMap["related_url"] = dataSourceAPINoteFlattenRelatedURL(notesItem.RelatedURL) - } - - if notesItem.CreateTime != nil { - notesMap["create_time"] = dateTimeToString(notesItem.CreateTime) - } - if notesItem.UpdateTime != nil { - notesMap["update_time"] = dateTimeToString(notesItem.UpdateTime) - } - if notesItem.Shared != nil { - notesMap["shared"] = notesItem.Shared - } - - if notesItem.ReportedBy != nil { - notesMap["reported_by"] = dataSourceAPINoteFlattenReportedBy(*notesItem.ReportedBy) - } - - if notesItem.Finding != nil { - notesMap["finding"] = dataSourceAPINoteFlattenFinding(*notesItem.Finding) - } - - if notesItem.Kpi != nil { - notesMap["kpi"] = dataSourceAPINoteFlattenKpi(*notesItem.Kpi) - } - - if notesItem.Card != nil { - notesMap["card"] = dataSourceAPINoteFlattenCard(*notesItem.Card) - } - - if notesItem.Section != nil { - notesMap["section"] = dataSourceAPINoteFlattenSection(*notesItem.Section) - } - - return notesMap -} - -// dataSourceIBMSccSiNotesID returns a reasonable ID for the list. -func dataSourceIBMSccSiNotesID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceAPINotesFlattenRelatedURL(result []findingsv1.APINoteRelatedURL) (relatedURL []map[string]interface{}) { - for _, relatedURLItem := range result { - relatedURL = append(relatedURL, dataSourceAPINoteRelatedURLToMap(relatedURLItem)) - } - - return relatedURL -} - -func dataSourceAPINotesRelatedURLToMap(relatedURLItem findingsv1.APINoteRelatedURL) (relatedURLMap map[string]interface{}) { - relatedURLMap = map[string]interface{}{} - - if relatedURLItem.Label != nil { - relatedURLMap["label"] = relatedURLItem.Label - } - if relatedURLItem.URL != nil { - relatedURLMap["url"] = relatedURLItem.URL - } - - return relatedURLMap -} - -func dataSourceAPINotesFlattenReportedBy(result findingsv1.Reporter) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteReportedByToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINotesReportedByToMap(reportedByItem findingsv1.Reporter) (reportedByMap map[string]interface{}) { - reportedByMap = map[string]interface{}{} - - if reportedByItem.ID != nil { - reportedByMap["id"] = reportedByItem.ID - } - if reportedByItem.Title != nil { - reportedByMap["title"] = reportedByItem.Title - } - if reportedByItem.URL != nil { - reportedByMap["url"] = reportedByItem.URL - } - - return reportedByMap -} - -func dataSourceAPINotesFlattenFinding(result findingsv1.FindingType) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteFindingToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINotesFindingToMap(findingItem findingsv1.FindingType) (findingMap map[string]interface{}) { - findingMap = map[string]interface{}{} - - if findingItem.Severity != nil { - findingMap["severity"] = findingItem.Severity - } - if findingItem.NextSteps != nil { - nextStepsList := []map[string]interface{}{} - for _, nextStepsItem := range findingItem.NextSteps { - nextStepsList = append(nextStepsList, dataSourceAPINoteFindingNextStepsToMap(nextStepsItem)) - } - findingMap["next_steps"] = nextStepsList - } - - return findingMap -} - -func dataSourceAPINotesFindingNextStepsToMap(nextStepsItem findingsv1.RemediationStep) (nextStepsMap map[string]interface{}) { - nextStepsMap = map[string]interface{}{} - - if nextStepsItem.Title != nil { - nextStepsMap["title"] = nextStepsItem.Title - } - if nextStepsItem.URL != nil { - nextStepsMap["url"] = nextStepsItem.URL - } - - return nextStepsMap -} - -func dataSourceAPINotesFlattenKpi(result findingsv1.KpiType) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteKpiToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINotesKpiToMap(kpiItem findingsv1.KpiType) (kpiMap map[string]interface{}) { - kpiMap = map[string]interface{}{} - - if kpiItem.AggregationType != nil { - kpiMap["aggregation_type"] = kpiItem.AggregationType - } - - return kpiMap -} - -func dataSourceAPINotesFlattenCard(result findingsv1.Card) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteCardToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINotesCardToMap(cardItem findingsv1.Card) (cardMap map[string]interface{}) { - cardMap = map[string]interface{}{} - - if cardItem.Section != nil { - cardMap["section"] = cardItem.Section - } - if cardItem.Title != nil { - cardMap["title"] = cardItem.Title - } - if cardItem.Subtitle != nil { - cardMap["subtitle"] = cardItem.Subtitle - } - if cardItem.Order != nil { - cardMap["order"] = cardItem.Order - } - if cardItem.FindingNoteNames != nil { - cardMap["finding_note_names"] = cardItem.FindingNoteNames - } - if cardItem.RequiresConfiguration != nil { - cardMap["requires_configuration"] = cardItem.RequiresConfiguration - } - if cardItem.BadgeText != nil { - cardMap["badge_text"] = cardItem.BadgeText - } - if cardItem.BadgeImage != nil { - cardMap["badge_image"] = cardItem.BadgeImage - } - if cardItem.Elements != nil { - elementsList := []map[string]interface{}{} - for _, elementsItem := range cardItem.Elements { - elementsList = append(elementsList, dataSourceAPINoteCardElementsToMap(elementsItem)) - } - cardMap["elements"] = elementsList - } - - return cardMap -} - -func dataSourceAPINotesCardElementsToMap(elementsItem findingsv1.CardElementIntf) (elementsMap map[string]interface{}) { - elementsMap = map[string]interface{}{} - - // TODO: Add code here to convert a findingsv1.CardElementIntf to map[string]interface{} - - return elementsMap -} - -func dataSourceAPINotesElementsValueTypeToMap(valueTypeItem findingsv1.NumericCardElementValueType) (valueTypeMap map[string]interface{}) { - valueTypeMap = map[string]interface{}{} - - if valueTypeItem.Kind != nil { - valueTypeMap["kind"] = valueTypeItem.Kind - } - if valueTypeItem.KpiNoteName != nil { - valueTypeMap["kpi_note_name"] = valueTypeItem.KpiNoteName - } - if valueTypeItem.Text != nil { - valueTypeMap["text"] = valueTypeItem.Text - } - if valueTypeItem.FindingNoteNames != nil { - valueTypeMap["finding_note_names"] = valueTypeItem.FindingNoteNames - } - - return valueTypeMap -} - -func dataSourceAPINotesElementsValueTypesToMap(valueTypesItem findingsv1.ValueTypeIntf) (valueTypesMap map[string]interface{}) { - valueTypesMap = map[string]interface{}{} - - // TODO: Add code here to convert a findingsv1.ValueTypeIntf to map[string]interface{} - - return valueTypesMap -} - -func dataSourceAPINotesFlattenSection(result findingsv1.Section) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceAPINoteSectionToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceAPINotesSectionToMap(sectionItem findingsv1.Section) (sectionMap map[string]interface{}) { - sectionMap = map[string]interface{}{} - - if sectionItem.Title != nil { - sectionMap["title"] = sectionItem.Title - } - if sectionItem.Image != nil { - sectionMap["image"] = sectionItem.Image - } - - return sectionMap -} diff --git a/ibm/data_source_ibm_scc_si_notes_test.go b/ibm/data_source_ibm_scc_si_notes_test.go deleted file mode 100644 index 6c0601cce..000000000 --- a/ibm/data_source_ibm_scc_si_notes_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccSiNotesDataSourceBasic(t *testing.T) { - apiNoteProviderID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - apiNoteLongDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - apiNoteKind := "FINDING" - apiNoteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNotesDataSourceConfigBasic(scc_si_account, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "provider_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.short_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.long_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.kind"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.related_url.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.create_time"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.update_time"), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNotesDataSourceAllArgs(t *testing.T) { - apiNoteProviderID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - apiNoteLongDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - apiNoteKind := "FINDING" - apiNoteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - apiNoteShared := "true" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNotesDataSourceConfig(scc_si_account, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID, apiNoteShared), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "provider_id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.short_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.long_description"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.kind"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.related_url.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.related_url.0.label"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.related_url.0.url"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.create_time"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.update_time"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.shared"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.reported_by.#"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_notes.scc_si_notes", "notes.0.finding.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccSiNotesDataSourceConfigBasic(accountID string, apiNoteProviderID string, apiNoteShortDescription string, apiNoteLongDescription string, apiNoteKind string, apiNoteID string) string { - return fmt.Sprintf(` - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - - data "ibm_scc_si_notes" "scc_si_notes" { - account_id = ibm_scc_si_note.scc_si_note.account_id - provider_id = ibm_scc_si_note.scc_si_note.provider_id - } - `, accountID, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID) -} - -func testAccCheckIBMSccSiNotesDataSourceConfig(accountID string, apiNoteProviderID string, apiNoteShortDescription string, apiNoteLongDescription string, apiNoteKind string, apiNoteID string, apiNoteShared string) string { - return fmt.Sprintf(` - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - related_url { - label = "label" - url = "url" - } - shared = %s - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - - data "ibm_scc_si_notes" "scc_si_notes" { - account_id = ibm_scc_si_note.scc_si_note.account_id - provider_id = ibm_scc_si_note.scc_si_note.provider_id - } - `, accountID, apiNoteProviderID, apiNoteShortDescription, apiNoteLongDescription, apiNoteKind, apiNoteID, apiNoteShared) -} diff --git a/ibm/data_source_ibm_scc_si_providers.go b/ibm/data_source_ibm_scc_si_providers.go deleted file mode 100644 index 04d9dc77a..000000000 --- a/ibm/data_source_ibm_scc_si_providers.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/scc-go-sdk/findingsv1" -) - -func dataSourceIBMSccSiProviders() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSccSiProvidersRead, - - Schema: map[string]*schema.Schema{ - "account_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - "providers": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The providers requested.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the provider in the form '{account_id}/providers/{provider_id}'.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the provider.", - }, - }, - }, - }, - "limit": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "The number of elements returned in the current instance. The default is 200.", - }, - "skip": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "The offset is the index of the item from which you want to start returning data from. The default is 0.", - }, - "total_count": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The total number of providers available.", - }, - }, - } -} - -func dataSourceIBMSccSiProvidersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := d.Get("account_id").(string) - log.Println(fmt.Sprintf("[DEBUG] using specified AccountID %s", accountID)) - if accountID == "" { - accountID = userDetails.userAccount - log.Println(fmt.Sprintf("[DEBUG] AccountID not spedified, using %s", accountID)) - } - findingsClient.AccountID = &accountID - - listProvidersOptions := &findingsv1.ListProvidersOptions{} - - if skip, ok := d.GetOk("skip"); ok { - listProvidersOptions.SetSkip(int64(skip.(int))) - } - if limit, ok := d.GetOk("limit"); ok { - listProvidersOptions.SetLimit(int64(limit.(int))) - } - - apiListProvidersResponse, response, err := findingsClient.ListProvidersWithContext(context, listProvidersOptions) - if err != nil { - log.Printf("[DEBUG] ListProvidersWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ListProvidersWithContext failed %s\n%s", err, response)) - } - - d.SetId(dataSourceIBMSccSiProvidersID(d)) - - if apiListProvidersResponse.Providers != nil { - err = d.Set("providers", dataSourceAPIListProvidersResponseFlattenProviders(apiListProvidersResponse.Providers)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting providers %s", err)) - } - } - if err = d.Set("total_count", intValue(apiListProvidersResponse.TotalCount)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) - } - - return nil -} - -// dataSourceIBMSccSiProviderID returns a reasonable ID for the list. -func dataSourceIBMSccSiProvidersID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceAPIListProvidersResponseFlattenProviders(result []findingsv1.APIProvider) (providers []map[string]interface{}) { - for _, providersItem := range result { - providers = append(providers, dataSourceAPIListProvidersResponseProvidersToMap(providersItem)) - } - - return providers -} - -func dataSourceAPIListProvidersResponseProvidersToMap(providersItem findingsv1.APIProvider) (providersMap map[string]interface{}) { - providersMap = map[string]interface{}{} - - if providersItem.Name != nil { - providersMap["name"] = providersItem.Name - } - if providersItem.ID != nil { - providersMap["id"] = providersItem.ID - } - - return providersMap -} diff --git a/ibm/data_source_ibm_scc_si_providers_test.go b/ibm/data_source_ibm_scc_si_providers_test.go deleted file mode 100644 index 0374f17fa..000000000 --- a/ibm/data_source_ibm_scc_si_providers_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSccSiProvidersDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiProvidersDataSourceConfigBasic(scc_si_account), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_scc_si_providers.scc_si_providers", "id"), - resource.TestCheckResourceAttrSet("data.ibm_scc_si_providers.scc_si_providers", "providers.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMSccSiProvidersDataSourceConfigBasic(accountID string) string { - return fmt.Sprintf(` - data "ibm_scc_si_providers" "scc_si_providers" { - account_id = "%s" - } - `, accountID) -} diff --git a/ibm/data_source_ibm_schematics_action.go b/ibm/data_source_ibm_schematics_action.go deleted file mode 100644 index df92a39ec..000000000 --- a/ibm/data_source_ibm_schematics_action.go +++ /dev/null @@ -1,1531 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func dataSourceIBMSchematicsAction() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSchematicsActionRead, - - Schema: map[string]*schema.Schema{ - "action_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Use GET or actions API to look up the action IDs in your IBM Cloud account.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action name (unique for an account).", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action description.", - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "List of action locations supported by IBM Cloud Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics.", - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource-group name for an action. By default, action is created in default resource group.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Action tags.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "user_state": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User defined status of the Schematics object.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "state": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "User defined states * `draft` Object can be modified, and can be used by jobs run by an author, during execution * `live` Object can be modified, and can be used by jobs during execution * `locked` Object cannot be modified, and can be used by jobs during execution * `disable` Object can be modified, and cannot be used by Jobs during execution.", - }, - "set_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the user who set the state of an Object.", - }, - "set_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "When the user who set the state of an Object.", - }, - }, - }, - }, - "source_readme_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL of the `README` file, for the source.", - }, - "source": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Source of templates, playbooks, or controls.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "source_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of source for the Template.", - }, - "git": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Connection details to Git source.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "git_repo_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL to the GIT Repo that can be used to clone the template.", - }, - "git_token": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Personal Access Token to connect to Git URLs.", - }, - "git_repo_folder": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the folder in the Git Repo, that contains the template.", - }, - "git_release": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the release tag, used to fetch the Git Repo.", - }, - "git_branch": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the branch, used to fetch the Git Repo.", - }, - }, - }, - }, - }, - }, - }, - "source_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of source for the Template.", - }, - "command_parameter": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Schematics job command parameter (playbook-name, capsule-name or flow-name).", - }, - "bastion": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Complete target details with the user inputs and the system generated data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target name.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target type (`cluster`, `vsi`, `icd`, `vpc`).", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target description.", - }, - "resource_query": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource selection query string.", - }, - "credential_ref": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Override credential for each resource. Reference to credentials values, used by all the resources.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target ID.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Targets creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who created the targets.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Targets updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who updated the targets.", - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - "resource_ids": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Array of the resource IDs.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "targets_ini": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", - }, - "credentials": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "credentials of the Action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "action_inputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Input variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "action_outputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Output variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "settings": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Environment variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "trigger_record_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "ID to the trigger.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action Id.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action Cloud Resource Name.", - }, - "account": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action account ID.", - }, - "source_created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action Playbook Source creation time.", - }, - "source_created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who created the Action Playbook Source.", - }, - "source_updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The action playbook updation time.", - }, - "source_updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who updated the action playbook source.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who created an action.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who updated an action.", - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the namespace.", - }, - "state": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Computed state of an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "status_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Status of automation (workspace or action).", - }, - "status_job_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job id reference for this status.", - }, - "status_message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Automation status message - to be displayed along with the status_code.", - }, - }, - }, - }, - "playbook_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Playbook names retrieved from the respository.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMSchematicsActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getActionOptions := &schematicsv1.GetActionOptions{} - - getActionOptions.SetActionID(d.Get("action_id").(string)) - - action, response, err := schematicsClient.GetActionWithContext(context, getActionOptions) - if err != nil { - log.Printf("[DEBUG] GetActionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*action.ID) - if err = d.Set("name", action.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", action.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("location", action.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if err = d.Set("resource_group", action.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - if err = d.Set("tags", action.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - - if action.UserState != nil { - err = d.Set("user_state", dataSourceActionFlattenUserState(*action.UserState)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting user_state %s", err)) - } - } - if err = d.Set("source_readme_url", action.SourceReadmeURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_readme_url: %s", err)) - } - - if action.Source != nil { - err = d.Set("source", dataSourceActionFlattenSource(*action.Source)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting source %s", err)) - } - } - if err = d.Set("source_type", action.SourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_type: %s", err)) - } - if err = d.Set("command_parameter", action.CommandParameter); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_parameter: %s", err)) - } - - if action.Bastion != nil { - err = d.Set("bastion", dataSourceActionFlattenBastion(*action.Bastion)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting bastion %s", err)) - } - } - if err = d.Set("targets_ini", action.TargetsIni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting targets_ini: %s", err)) - } - - if action.Credentials != nil { - err = d.Set("credentials", dataSourceActionFlattenCredentials(action.Credentials)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting credentials %s", err)) - } - } - - if action.Inputs != nil { - err = d.Set("action_inputs", dataSourceActionFlattenInputs(action.Inputs)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting action_inputs %s", err)) - } - } - - if action.Outputs != nil { - err = d.Set("action_outputs", dataSourceActionFlattenOutputs(action.Outputs)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting action_outputs %s", err)) - } - } - - if action.Settings != nil { - err = d.Set("settings", dataSourceActionFlattenSettings(action.Settings)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting settings %s", err)) - } - } - if err = d.Set("trigger_record_id", action.TriggerRecordID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting trigger_record_id: %s", err)) - } - if err = d.Set("id", action.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) - } - if err = d.Set("crn", action.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("account", action.Account); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account: %s", err)) - } - if action.SourceCreatedAt != nil { - if err = d.Set("source_created_at", action.SourceCreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_created_at: %s", err)) - } - } - if err = d.Set("source_created_by", action.SourceCreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_created_by: %s", err)) - } - if action.SourceUpdatedAt != nil { - if err = d.Set("source_updated_at", action.SourceUpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_updated_at: %s", err)) - } - } - if err = d.Set("source_updated_by", action.SourceUpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_updated_by: %s", err)) - } - if action.CreatedAt != nil { - if err = d.Set("created_at", action.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - } - if err = d.Set("created_by", action.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) - } - if action.UpdatedAt != nil { - if err = d.Set("updated_at", action.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - } - if err = d.Set("updated_by", action.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) - } - if err = d.Set("namespace", action.Namespace); err != nil { - return diag.FromErr(fmt.Errorf("Error setting namespace: %s", err)) - } - - if action.State != nil { - err = d.Set("state", dataSourceActionFlattenState(*action.State)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting state %s", err)) - } - } - - if action.PlaybookNames != nil { - if err = d.Set("playbook_names", action.PlaybookNames); err != nil { - return diag.FromErr(fmt.Errorf("Error setting playbook_names: %s", err)) - } - } else { - d.Set("playbook_names", []string{}) - } - - if action.SysLock != nil { - err = d.Set("sys_lock", dataSourceActionFlattenSysLock(*action.SysLock)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting sys_lock %s", err)) - } - } - - return nil -} - -func dataSourceActionFlattenUserState(result schematicsv1.UserState) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceActionUserStateToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceActionUserStateToMap(userStateItem schematicsv1.UserState) (userStateMap map[string]interface{}) { - userStateMap = map[string]interface{}{} - - if userStateItem.State != nil { - userStateMap["state"] = userStateItem.State - } - if userStateItem.SetBy != nil { - userStateMap["set_by"] = userStateItem.SetBy - } - if userStateItem.SetAt != nil { - userStateMap["set_at"] = userStateItem.SetAt.String() - } - - return userStateMap -} - -func dataSourceActionFlattenSource(result schematicsv1.ExternalSource) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceActionSourceToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceActionSourceToMap(sourceItem schematicsv1.ExternalSource) (sourceMap map[string]interface{}) { - sourceMap = map[string]interface{}{} - - if sourceItem.SourceType != nil { - sourceMap["source_type"] = sourceItem.SourceType - } - if sourceItem.Git != nil { - gitList := []map[string]interface{}{} - gitMap := dataSourceActionSourceGitToMap(*sourceItem.Git) - gitList = append(gitList, gitMap) - sourceMap["git"] = gitList - } - - return sourceMap -} - -func dataSourceActionSourceGitToMap(gitItem schematicsv1.ExternalSourceGit) (gitMap map[string]interface{}) { - gitMap = map[string]interface{}{} - - if gitItem.GitRepoURL != nil { - gitMap["git_repo_url"] = gitItem.GitRepoURL - } - if gitItem.GitToken != nil { - gitMap["git_token"] = gitItem.GitToken - } - if gitItem.GitRepoFolder != nil { - gitMap["git_repo_folder"] = gitItem.GitRepoFolder - } - if gitItem.GitRelease != nil { - gitMap["git_release"] = gitItem.GitRelease - } - if gitItem.GitBranch != nil { - gitMap["git_branch"] = gitItem.GitBranch - } - - return gitMap -} - -func dataSourceActionFlattenBastion(result schematicsv1.TargetResourceset) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceActionBastionToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceActionBastionToMap(bastionItem schematicsv1.TargetResourceset) (bastionMap map[string]interface{}) { - bastionMap = map[string]interface{}{} - - if bastionItem.Name != nil { - bastionMap["name"] = bastionItem.Name - } - if bastionItem.Type != nil { - bastionMap["type"] = bastionItem.Type - } - if bastionItem.Description != nil { - bastionMap["description"] = bastionItem.Description - } - if bastionItem.ResourceQuery != nil { - bastionMap["resource_query"] = bastionItem.ResourceQuery - } - if bastionItem.CredentialRef != nil { - bastionMap["credential_ref"] = bastionItem.CredentialRef - } - if bastionItem.ID != nil { - bastionMap["id"] = bastionItem.ID - } - if bastionItem.CreatedAt != nil { - bastionMap["created_at"] = bastionItem.CreatedAt.String() - } - if bastionItem.CreatedBy != nil { - bastionMap["created_by"] = bastionItem.CreatedBy - } - if bastionItem.UpdatedAt != nil { - bastionMap["updated_at"] = bastionItem.UpdatedAt.String() - } - if bastionItem.UpdatedBy != nil { - bastionMap["updated_by"] = bastionItem.UpdatedBy - } - if bastionItem.SysLock != nil { - sysLockList := []map[string]interface{}{} - sysLockMap := dataSourceActionBastionSysLockToMap(*bastionItem.SysLock) - sysLockList = append(sysLockList, sysLockMap) - bastionMap["sys_lock"] = sysLockList - } - if bastionItem.ResourceIds != nil { - bastionMap["resource_ids"] = bastionItem.ResourceIds - } - - return bastionMap -} - -func dataSourceActionBastionSysLockToMap(sysLockItem schematicsv1.SystemLock) (sysLockMap map[string]interface{}) { - sysLockMap = map[string]interface{}{} - - if sysLockItem.SysLocked != nil { - sysLockMap["sys_locked"] = sysLockItem.SysLocked - } - if sysLockItem.SysLockedBy != nil { - sysLockMap["sys_locked_by"] = sysLockItem.SysLockedBy - } - if sysLockItem.SysLockedAt != nil { - sysLockMap["sys_locked_at"] = sysLockItem.SysLockedAt.String() - } - - return sysLockMap -} - -func dataSourceActionFlattenCredentials(result []schematicsv1.VariableData) (credentials []map[string]interface{}) { - for _, credentialsItem := range result { - credentials = append(credentials, dataSourceActionCredentialsToMap(credentialsItem)) - } - - return credentials -} - -func dataSourceActionCredentialsToMap(credentialsItem schematicsv1.VariableData) (credentialsMap map[string]interface{}) { - credentialsMap = map[string]interface{}{} - - if credentialsItem.Name != nil { - credentialsMap["name"] = credentialsItem.Name - } - if credentialsItem.Value != nil { - credentialsMap["value"] = credentialsItem.Value - } - if credentialsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceActionCredentialsMetadataToMap(*credentialsItem.Metadata) - metadataList = append(metadataList, metadataMap) - credentialsMap["metadata"] = metadataList - } - if credentialsItem.Link != nil { - credentialsMap["link"] = credentialsItem.Link - } - - return credentialsMap -} - -func dataSourceActionCredentialsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceActionFlattenInputs(result []schematicsv1.VariableData) (inputs []map[string]interface{}) { - for _, inputsItem := range result { - inputs = append(inputs, dataSourceActionInputsToMap(inputsItem)) - } - - return inputs -} - -func dataSourceActionInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { - inputsMap = map[string]interface{}{} - - if inputsItem.Name != nil { - inputsMap["name"] = inputsItem.Name - } - if inputsItem.Value != nil { - inputsMap["value"] = inputsItem.Value - } - if inputsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceActionInputsMetadataToMap(*inputsItem.Metadata) - metadataList = append(metadataList, metadataMap) - inputsMap["metadata"] = metadataList - } - if inputsItem.Link != nil { - inputsMap["link"] = inputsItem.Link - } - - return inputsMap -} - -func dataSourceActionInputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceActionFlattenOutputs(result []schematicsv1.VariableData) (outputs []map[string]interface{}) { - for _, outputsItem := range result { - outputs = append(outputs, dataSourceActionOutputsToMap(outputsItem)) - } - - return outputs -} - -func dataSourceActionOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { - outputsMap = map[string]interface{}{} - - if outputsItem.Name != nil { - outputsMap["name"] = outputsItem.Name - } - if outputsItem.Value != nil { - outputsMap["value"] = outputsItem.Value - } - if outputsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceActionOutputsMetadataToMap(*outputsItem.Metadata) - metadataList = append(metadataList, metadataMap) - outputsMap["metadata"] = metadataList - } - if outputsItem.Link != nil { - outputsMap["link"] = outputsItem.Link - } - - return outputsMap -} - -func dataSourceActionOutputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceActionFlattenSettings(result []schematicsv1.VariableData) (settings []map[string]interface{}) { - for _, settingsItem := range result { - settings = append(settings, dataSourceActionSettingsToMap(settingsItem)) - } - - return settings -} - -func dataSourceActionSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { - settingsMap = map[string]interface{}{} - - if settingsItem.Name != nil { - settingsMap["name"] = settingsItem.Name - } - if settingsItem.Value != nil { - settingsMap["value"] = settingsItem.Value - } - if settingsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceActionSettingsMetadataToMap(*settingsItem.Metadata) - metadataList = append(metadataList, metadataMap) - settingsMap["metadata"] = metadataList - } - if settingsItem.Link != nil { - settingsMap["link"] = settingsItem.Link - } - - return settingsMap -} - -func dataSourceActionSettingsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceActionFlattenState(result schematicsv1.ActionState) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceActionStateToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceActionStateToMap(stateItem schematicsv1.ActionState) (stateMap map[string]interface{}) { - stateMap = map[string]interface{}{} - - if stateItem.StatusCode != nil { - stateMap["status_code"] = stateItem.StatusCode - } - if stateItem.StatusJobID != nil { - stateMap["status_job_id"] = stateItem.StatusJobID - } - if stateItem.StatusMessage != nil { - stateMap["status_message"] = stateItem.StatusMessage - } - - return stateMap -} - -func dataSourceActionFlattenSysLock(result schematicsv1.SystemLock) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceActionSysLockToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceActionSysLockToMap(sysLockItem schematicsv1.SystemLock) (sysLockMap map[string]interface{}) { - sysLockMap = map[string]interface{}{} - - if sysLockItem.SysLocked != nil { - sysLockMap["sys_locked"] = sysLockItem.SysLocked - } - if sysLockItem.SysLockedBy != nil { - sysLockMap["sys_locked_by"] = sysLockItem.SysLockedBy - } - if sysLockItem.SysLockedAt != nil { - sysLockMap["sys_locked_at"] = sysLockItem.SysLockedAt.String() - } - - return sysLockMap -} diff --git a/ibm/data_source_ibm_schematics_job.go b/ibm/data_source_ibm_schematics_job.go deleted file mode 100644 index 3c15f36b6..000000000 --- a/ibm/data_source_ibm_schematics_job.go +++ /dev/null @@ -1,1806 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func dataSourceIBMSchematicsJob() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSchematicsJobRead, - - Schema: map[string]*schema.Schema{ - "job_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Use GET jobs API to look up the Job IDs in your IBM Cloud account.", - }, - "command_object": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the Schematics automation resource.", - }, - "command_object_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job command object ID (`workspace-id, action-id or control-id`).", - }, - "command_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Schematics job command name.", - }, - "command_options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Command line options for the command.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "job_inputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job inputs used by an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "job_env_settings": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Environment variables used by the job while performing an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User defined tags, while running the job.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job ID.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job name, uniquely derived from the related action.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job description derived from the related action.", - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "List of action locations supported by IBM Cloud Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics.", - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource group name derived from the related action.", - }, - "submitted_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job submission time.", - }, - "submitted_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who submitted the job.", - }, - "start_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job start time.", - }, - "end_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job end time.", - }, - "duration": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Duration of job execution, for example, `40 sec`.", - }, - "status": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job Status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_job_status": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Action Job Status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action name.", - }, - "status_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Status of the jobs.", - }, - "status_message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action job status message to be displayed along with the `action_status_code`.", - }, - "bastion_status_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Status of the resources.", - }, - "bastion_status_message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Bastion status message to be displayed along with the `bastion_status_code`.", - }, - "targets_status_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Status of the resources.", - }, - "targets_status_message": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Aggregated status message for all target resources, to be displayed along with the `targets_status_code`.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job status updation timestamp.", - }, - }, - }, - }, - }, - }, - }, - "data": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "job_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the job.", - }, - "action_job_data": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Action Job data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Flow name.", - }, - "inputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Input variables data used by an action job.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "outputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Output variables data from an action job.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "settings": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Environment variables used by all the templates in an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job status updation timestamp.", - }, - }, - }, - }, - }, - }, - }, - "targets_ini": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", - }, - "bastion": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Complete target details with the user inputs and the system generated data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target name.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target type (`cluster`, `vsi`, `icd`, `vpc`).", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target description.", - }, - "resource_query": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource selection query string.", - }, - "credential_ref": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Override credential for each resource. Reference to credentials values, used by all the resources.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target ID.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Targets creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who created the targets.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Targets updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who updated the targets.", - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - "resource_ids": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Array of the resource IDs.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "job_log_summary": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job log summary record.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "job_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Workspace ID.", - }, - "job_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of Job.", - }, - "log_start_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job log start timestamp.", - }, - "log_analyzed_till": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job log update timestamp.", - }, - "elapsed_time": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Job log elapsed time (`log_analyzed_till - log_start_at`).", - }, - "log_errors": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job log errors.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "error_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Error code in the Log.", - }, - "error_msg": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Summary error message in the log.", - }, - "error_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of occurrence.", - }, - }, - }, - }, - "repo_download_job": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Repo download Job log summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "scanned_file_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of files scanned.", - }, - "quarantined_file_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of files quarantined.", - }, - "detected_filetype": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Detected template or data file type.", - }, - "inputs_count": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Number of inputs detected.", - }, - "outputs_count": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Number of outputs detected.", - }, - }, - }, - }, - "action_job": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Flow Job log summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "number of targets or hosts.", - }, - "task_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "number of tasks in playbook.", - }, - "play_count": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "number of plays in playbook.", - }, - "recap": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Recap records.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of target or host name.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "ok": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of OK.", - }, - "changed": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of changed.", - }, - "failed": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of failed.", - }, - "skipped": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of skipped.", - }, - "unreachable": &schema.Schema{ - Type: schema.TypeFloat, - Computed: true, - Description: "Number of unreachable.", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - "log_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job log store URL.", - }, - "state_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job state store URL.", - }, - "results_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job results store URL.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job status updation timestamp.", - }, - }, - } -} - -func dataSourceIBMSchematicsJobRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getJobOptions := &schematicsv1.GetJobOptions{} - - getJobOptions.SetJobID(d.Get("job_id").(string)) - - job, response, err := schematicsClient.GetJobWithContext(context, getJobOptions) - if err != nil { - log.Printf("[DEBUG] GetJobWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*job.ID) - if err = d.Set("command_object", job.CommandObject); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_object: %s", err)) - } - if err = d.Set("command_object_id", job.CommandObjectID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_object_id: %s", err)) - } - if err = d.Set("command_name", job.CommandName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_name: %s", err)) - } - if err = d.Set("command_options", job.CommandOptions); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_options: %s", err)) - } - - if job.Inputs != nil { - err = d.Set("job_inputs", dataSourceJobFlattenInputs(job.Inputs)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_inputs %s", err)) - } - } - - if job.Settings != nil { - err = d.Set("job_env_settings", dataSourceJobFlattenSettings(job.Settings)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_env_settings %s", err)) - } - } - if err = d.Set("tags", job.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - if err = d.Set("id", job.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) - } - if err = d.Set("name", job.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", job.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("location", job.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if err = d.Set("resource_group", job.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - if job.SubmittedAt != nil { - if err = d.Set("submitted_at", job.SubmittedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting submitted_at: %s", err)) - } - } - if err = d.Set("submitted_by", job.SubmittedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting submitted_by: %s", err)) - } - if job.StartAt != nil { - if err = d.Set("start_at", job.StartAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting start_at: %s", err)) - } - } - if job.EndAt != nil { - if err = d.Set("end_at", job.EndAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting end_at: %s", err)) - } - } - if err = d.Set("duration", job.Duration); err != nil { - return diag.FromErr(fmt.Errorf("Error setting duration: %s", err)) - } - - if job.Status != nil { - err = d.Set("status", dataSourceJobFlattenStatus(*job.Status)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting status %s", err)) - } - } - - if job.Data != nil { - err = d.Set("data", dataSourceJobFlattenData(*job.Data)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting data %s", err)) - } - } - if err = d.Set("targets_ini", job.TargetsIni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting targets_ini: %s", err)) - } - - if job.Bastion != nil { - err = d.Set("bastion", dataSourceJobFlattenBastion(*job.Bastion)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting bastion %s", err)) - } - } - - if job.LogSummary != nil { - err = d.Set("job_log_summary", dataSourceJobFlattenLogSummary(*job.LogSummary)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_log_summary %s", err)) - } - } - if err = d.Set("log_store_url", job.LogStoreURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting log_store_url: %s", err)) - } - if err = d.Set("state_store_url", job.StateStoreURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state_store_url: %s", err)) - } - if err = d.Set("results_url", job.ResultsURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting results_url: %s", err)) - } - if job.UpdatedAt != nil { - if err = d.Set("updated_at", job.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - } - - return nil -} - -func dataSourceJobFlattenInputs(result []schematicsv1.VariableData) (inputs []map[string]interface{}) { - for _, inputsItem := range result { - inputs = append(inputs, dataSourceJobInputsToMap(inputsItem)) - } - - return inputs -} - -func dataSourceJobInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { - inputsMap = map[string]interface{}{} - - if inputsItem.Name != nil { - inputsMap["name"] = inputsItem.Name - } - if inputsItem.Value != nil { - inputsMap["value"] = inputsItem.Value - } - if inputsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) - metadataList = append(metadataList, metadataMap) - inputsMap["metadata"] = metadataList - } - if inputsItem.Link != nil { - inputsMap["link"] = inputsItem.Link - } - - return inputsMap -} - -func dataSourceJobInputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceJobOutputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceJobFlattenSettings(result []schematicsv1.VariableData) (settings []map[string]interface{}) { - for _, settingsItem := range result { - settings = append(settings, dataSourceJobSettingsToMap(settingsItem)) - } - - return settings -} - -func dataSourceJobSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { - settingsMap = map[string]interface{}{} - - if settingsItem.Name != nil { - settingsMap["name"] = settingsItem.Name - } - if settingsItem.Value != nil { - settingsMap["value"] = settingsItem.Value - } - if settingsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) - metadataList = append(metadataList, metadataMap) - settingsMap["metadata"] = metadataList - } - if settingsItem.Link != nil { - settingsMap["link"] = settingsItem.Link - } - - return settingsMap -} - -func dataSourceJobSettingsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.Type != nil { - metadataMap["type"] = metadataItem.Type - } - if metadataItem.Aliases != nil { - metadataMap["aliases"] = metadataItem.Aliases - } - if metadataItem.Description != nil { - metadataMap["description"] = metadataItem.Description - } - if metadataItem.DefaultValue != nil { - metadataMap["default_value"] = metadataItem.DefaultValue - } - if metadataItem.Secure != nil { - metadataMap["secure"] = metadataItem.Secure - } - if metadataItem.Immutable != nil { - metadataMap["immutable"] = metadataItem.Immutable - } - if metadataItem.Hidden != nil { - metadataMap["hidden"] = metadataItem.Hidden - } - if metadataItem.Options != nil { - metadataMap["options"] = metadataItem.Options - } - if metadataItem.MinValue != nil { - metadataMap["min_value"] = metadataItem.MinValue - } - if metadataItem.MaxValue != nil { - metadataMap["max_value"] = metadataItem.MaxValue - } - if metadataItem.MinLength != nil { - metadataMap["min_length"] = metadataItem.MinLength - } - if metadataItem.MaxLength != nil { - metadataMap["max_length"] = metadataItem.MaxLength - } - if metadataItem.Matches != nil { - metadataMap["matches"] = metadataItem.Matches - } - if metadataItem.Position != nil { - metadataMap["position"] = metadataItem.Position - } - if metadataItem.GroupBy != nil { - metadataMap["group_by"] = metadataItem.GroupBy - } - if metadataItem.Source != nil { - metadataMap["source"] = metadataItem.Source - } - - return metadataMap -} - -func dataSourceJobFlattenStatus(result schematicsv1.JobStatus) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceJobStatusToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceJobStatusToMap(statusItem schematicsv1.JobStatus) (statusMap map[string]interface{}) { - statusMap = map[string]interface{}{} - - if statusItem.ActionJobStatus != nil { - actionJobStatusList := []map[string]interface{}{} - actionJobStatusMap := dataSourceJobStatusActionJobStatusToMap(*statusItem.ActionJobStatus) - actionJobStatusList = append(actionJobStatusList, actionJobStatusMap) - statusMap["action_job_status"] = actionJobStatusList - } - - return statusMap -} - -func dataSourceJobStatusActionJobStatusToMap(actionJobStatusItem schematicsv1.JobStatusAction) (actionJobStatusMap map[string]interface{}) { - actionJobStatusMap = map[string]interface{}{} - - if actionJobStatusItem.ActionName != nil { - actionJobStatusMap["action_name"] = actionJobStatusItem.ActionName - } - if actionJobStatusItem.StatusCode != nil { - actionJobStatusMap["status_code"] = actionJobStatusItem.StatusCode - } - if actionJobStatusItem.StatusMessage != nil { - actionJobStatusMap["status_message"] = actionJobStatusItem.StatusMessage - } - if actionJobStatusItem.BastionStatusCode != nil { - actionJobStatusMap["bastion_status_code"] = actionJobStatusItem.BastionStatusCode - } - if actionJobStatusItem.BastionStatusMessage != nil { - actionJobStatusMap["bastion_status_message"] = actionJobStatusItem.BastionStatusMessage - } - if actionJobStatusItem.TargetsStatusCode != nil { - actionJobStatusMap["targets_status_code"] = actionJobStatusItem.TargetsStatusCode - } - if actionJobStatusItem.TargetsStatusMessage != nil { - actionJobStatusMap["targets_status_message"] = actionJobStatusItem.TargetsStatusMessage - } - if actionJobStatusItem.UpdatedAt != nil { - actionJobStatusMap["updated_at"] = actionJobStatusItem.UpdatedAt.String() - } - - return actionJobStatusMap -} - -func dataSourceJobFlattenData(result schematicsv1.JobData) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceJobDataToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceJobDataToMap(dataItem schematicsv1.JobData) (dataMap map[string]interface{}) { - dataMap = map[string]interface{}{} - - if dataItem.JobType != nil { - dataMap["job_type"] = dataItem.JobType - } - if dataItem.ActionJobData != nil { - actionJobDataList := []map[string]interface{}{} - actionJobDataMap := dataSourceJobDataActionJobDataToMap(*dataItem.ActionJobData) - actionJobDataList = append(actionJobDataList, actionJobDataMap) - dataMap["action_job_data"] = actionJobDataList - } - - return dataMap -} - -func dataSourceJobDataActionJobDataToMap(actionJobDataItem schematicsv1.JobDataAction) (actionJobDataMap map[string]interface{}) { - actionJobDataMap = map[string]interface{}{} - - if actionJobDataItem.ActionName != nil { - actionJobDataMap["action_name"] = actionJobDataItem.ActionName - } - if actionJobDataItem.Inputs != nil { - inputsList := []map[string]interface{}{} - for _, inputsItem := range actionJobDataItem.Inputs { - inputsList = append(inputsList, dataSourceJobActionJobDataInputsToMap(inputsItem)) - } - actionJobDataMap["inputs"] = inputsList - } - if actionJobDataItem.Outputs != nil { - outputsList := []map[string]interface{}{} - for _, outputsItem := range actionJobDataItem.Outputs { - outputsList = append(outputsList, dataSourceJobActionJobDataOutputsToMap(outputsItem)) - } - actionJobDataMap["outputs"] = outputsList - } - if actionJobDataItem.Settings != nil { - settingsList := []map[string]interface{}{} - for _, settingsItem := range actionJobDataItem.Settings { - settingsList = append(settingsList, dataSourceJobActionJobDataSettingsToMap(settingsItem)) - } - actionJobDataMap["settings"] = settingsList - } - if actionJobDataItem.UpdatedAt != nil { - actionJobDataMap["updated_at"] = actionJobDataItem.UpdatedAt.String() - } - - return actionJobDataMap -} - -func dataSourceJobActionJobDataInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { - inputsMap = map[string]interface{}{} - - if inputsItem.Name != nil { - inputsMap["name"] = inputsItem.Name - } - if inputsItem.Value != nil { - inputsMap["value"] = inputsItem.Value - } - if inputsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) - metadataList = append(metadataList, metadataMap) - inputsMap["metadata"] = metadataList - } - if inputsItem.Link != nil { - inputsMap["link"] = inputsItem.Link - } - - return inputsMap -} - -func dataSourceJobActionJobDataOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { - outputsMap = map[string]interface{}{} - - if outputsItem.Name != nil { - outputsMap["name"] = outputsItem.Name - } - if outputsItem.Value != nil { - outputsMap["value"] = outputsItem.Value - } - if outputsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceJobOutputsMetadataToMap(*outputsItem.Metadata) - metadataList = append(metadataList, metadataMap) - outputsMap["metadata"] = metadataList - } - if outputsItem.Link != nil { - outputsMap["link"] = outputsItem.Link - } - - return outputsMap -} - -func dataSourceJobActionJobDataSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { - settingsMap = map[string]interface{}{} - - if settingsItem.Name != nil { - settingsMap["name"] = settingsItem.Name - } - if settingsItem.Value != nil { - settingsMap["value"] = settingsItem.Value - } - if settingsItem.Metadata != nil { - metadataList := []map[string]interface{}{} - metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) - metadataList = append(metadataList, metadataMap) - settingsMap["metadata"] = metadataList - } - if settingsItem.Link != nil { - settingsMap["link"] = settingsItem.Link - } - - return settingsMap -} - -func dataSourceJobFlattenBastion(result schematicsv1.TargetResourceset) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceJobBastionToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceJobBastionToMap(bastionItem schematicsv1.TargetResourceset) (bastionMap map[string]interface{}) { - bastionMap = map[string]interface{}{} - - if bastionItem.Name != nil { - bastionMap["name"] = bastionItem.Name - } - if bastionItem.Type != nil { - bastionMap["type"] = bastionItem.Type - } - if bastionItem.Description != nil { - bastionMap["description"] = bastionItem.Description - } - if bastionItem.ResourceQuery != nil { - bastionMap["resource_query"] = bastionItem.ResourceQuery - } - if bastionItem.CredentialRef != nil { - bastionMap["credential_ref"] = bastionItem.CredentialRef - } - if bastionItem.ID != nil { - bastionMap["id"] = bastionItem.ID - } - if bastionItem.CreatedAt != nil { - bastionMap["created_at"] = bastionItem.CreatedAt.String() - } - if bastionItem.CreatedBy != nil { - bastionMap["created_by"] = bastionItem.CreatedBy - } - if bastionItem.UpdatedAt != nil { - bastionMap["updated_at"] = bastionItem.UpdatedAt.String() - } - if bastionItem.UpdatedBy != nil { - bastionMap["updated_by"] = bastionItem.UpdatedBy - } - if bastionItem.SysLock != nil { - sysLockList := []map[string]interface{}{} - sysLockMap := dataSourceJobBastionSysLockToMap(*bastionItem.SysLock) - sysLockList = append(sysLockList, sysLockMap) - bastionMap["sys_lock"] = sysLockList - } - if bastionItem.ResourceIds != nil { - bastionMap["resource_ids"] = bastionItem.ResourceIds - } - - return bastionMap -} - -func dataSourceJobBastionSysLockToMap(sysLockItem schematicsv1.SystemLock) (sysLockMap map[string]interface{}) { - sysLockMap = map[string]interface{}{} - - if sysLockItem.SysLocked != nil { - sysLockMap["sys_locked"] = sysLockItem.SysLocked - } - if sysLockItem.SysLockedBy != nil { - sysLockMap["sys_locked_by"] = sysLockItem.SysLockedBy - } - if sysLockItem.SysLockedAt != nil { - sysLockMap["sys_locked_at"] = sysLockItem.SysLockedAt.String() - } - - return sysLockMap -} - -func dataSourceJobFlattenLogSummary(result schematicsv1.JobLogSummary) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceJobLogSummaryToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceJobLogSummaryToMap(logSummaryItem schematicsv1.JobLogSummary) (logSummaryMap map[string]interface{}) { - logSummaryMap = map[string]interface{}{} - - if logSummaryItem.JobID != nil { - logSummaryMap["job_id"] = logSummaryItem.JobID - } - if logSummaryItem.JobType != nil { - logSummaryMap["job_type"] = logSummaryItem.JobType - } - if logSummaryItem.LogStartAt != nil { - logSummaryMap["log_start_at"] = logSummaryItem.LogStartAt.String() - } - if logSummaryItem.LogAnalyzedTill != nil { - logSummaryMap["log_analyzed_till"] = logSummaryItem.LogAnalyzedTill.String() - } - if logSummaryItem.ElapsedTime != nil { - logSummaryMap["elapsed_time"] = logSummaryItem.ElapsedTime - } - if logSummaryItem.LogErrors != nil { - logErrorsList := []map[string]interface{}{} - for _, logErrorsItem := range logSummaryItem.LogErrors { - logErrorsList = append(logErrorsList, dataSourceJobLogSummaryLogErrorsToMap(logErrorsItem)) - } - logSummaryMap["log_errors"] = logErrorsList - } - if logSummaryItem.RepoDownloadJob != nil { - repoDownloadJobList := []map[string]interface{}{} - repoDownloadJobMap := dataSourceJobLogSummaryRepoDownloadJobToMap(*logSummaryItem.RepoDownloadJob) - repoDownloadJobList = append(repoDownloadJobList, repoDownloadJobMap) - logSummaryMap["repo_download_job"] = repoDownloadJobList - } - if logSummaryItem.ActionJob != nil { - actionJobList := []map[string]interface{}{} - actionJobMap := dataSourceJobLogSummaryActionJobToMap(*logSummaryItem.ActionJob) - actionJobList = append(actionJobList, actionJobMap) - logSummaryMap["action_job"] = actionJobList - } - - return logSummaryMap -} - -func dataSourceJobLogSummaryLogErrorsToMap(logErrorsItem schematicsv1.JobLogSummaryLogErrorsItem) (logErrorsMap map[string]interface{}) { - logErrorsMap = map[string]interface{}{} - - if logErrorsItem.ErrorCode != nil { - logErrorsMap["error_code"] = logErrorsItem.ErrorCode - } - if logErrorsItem.ErrorMsg != nil { - logErrorsMap["error_msg"] = logErrorsItem.ErrorMsg - } - if logErrorsItem.ErrorCount != nil { - logErrorsMap["error_count"] = logErrorsItem.ErrorCount - } - - return logErrorsMap -} - -func dataSourceJobLogSummaryRepoDownloadJobToMap(repoDownloadJobItem schematicsv1.JobLogSummaryRepoDownloadJob) (repoDownloadJobMap map[string]interface{}) { - repoDownloadJobMap = map[string]interface{}{} - - if repoDownloadJobItem.ScannedFileCount != nil { - repoDownloadJobMap["scanned_file_count"] = repoDownloadJobItem.ScannedFileCount - } - if repoDownloadJobItem.QuarantinedFileCount != nil { - repoDownloadJobMap["quarantined_file_count"] = repoDownloadJobItem.QuarantinedFileCount - } - if repoDownloadJobItem.DetectedFiletype != nil { - repoDownloadJobMap["detected_filetype"] = repoDownloadJobItem.DetectedFiletype - } - if repoDownloadJobItem.InputsCount != nil { - repoDownloadJobMap["inputs_count"] = repoDownloadJobItem.InputsCount - } - if repoDownloadJobItem.OutputsCount != nil { - repoDownloadJobMap["outputs_count"] = repoDownloadJobItem.OutputsCount - } - - return repoDownloadJobMap -} - -func dataSourceJobLogSummaryActionJobToMap(actionJobItem schematicsv1.JobLogSummaryActionJob) (actionJobMap map[string]interface{}) { - actionJobMap = map[string]interface{}{} - - if actionJobItem.TargetCount != nil { - actionJobMap["target_count"] = actionJobItem.TargetCount - } - if actionJobItem.TaskCount != nil { - actionJobMap["task_count"] = actionJobItem.TaskCount - } - if actionJobItem.PlayCount != nil { - actionJobMap["play_count"] = actionJobItem.PlayCount - } - if actionJobItem.Recap != nil { - recapList := []map[string]interface{}{} - recapMap := dataSourceJobActionJobRecapToMap(*actionJobItem.Recap) - recapList = append(recapList, recapMap) - actionJobMap["recap"] = recapList - } - - return actionJobMap -} - -func dataSourceJobActionJobRecapToMap(recapItem schematicsv1.JobLogSummaryActionJobRecap) (recapMap map[string]interface{}) { - recapMap = map[string]interface{}{} - - if recapItem.Target != nil { - recapMap["target"] = recapItem.Target - } - if recapItem.Ok != nil { - recapMap["ok"] = recapItem.Ok - } - if recapItem.Changed != nil { - recapMap["changed"] = recapItem.Changed - } - if recapItem.Failed != nil { - recapMap["failed"] = recapItem.Failed - } - if recapItem.Skipped != nil { - recapMap["skipped"] = recapItem.Skipped - } - if recapItem.Unreachable != nil { - recapMap["unreachable"] = recapItem.Unreachable - } - - return recapMap -} diff --git a/ibm/data_source_ibm_schematics_output_test.go b/ibm/data_source_ibm_schematics_output_test.go deleted file mode 100644 index 87943f4d6..000000000 --- a/ibm/data_source_ibm_schematics_output_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSchematicsOutputDataSourceBasic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSchematicsOutputDataSourceConfigBasic(workspaceID, templateID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_schematics_output.schematics_output", "workspace_id", workspaceID), - ), - }, - }, - }) -} - -func testAccCheckIBMSchematicsOutputDataSourceConfigBasic(wID string, templateID string) string { - return fmt.Sprintf(` - data "ibm_schematics_output" "schematics_output" { - workspace_id = "%s" - template_id = "%s" - } - `, workspaceID, templateID) -} diff --git a/ibm/data_source_ibm_schematics_state.go b/ibm/data_source_ibm_schematics_state.go deleted file mode 100644 index 46f6bc1c9..000000000 --- a/ibm/data_source_ibm_schematics_state.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func dataSourceIBMSchematicsState() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSchematicsStateRead, - - Schema: map[string]*schema.Schema{ - "workspace_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The ID of the workspace for which you want to retrieve the Terraform statefile. To find the workspace ID, use the `GET /v1/workspaces` API.", - }, - "template_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The ID of the Terraform template for which you want to retrieve the Terraform statefile. When you create a workspace, the Terraform template that your workspace points to is assigned a unique ID. To find this ID, use the `GET /v1/workspaces` API and review the `template_data.id` value.", - }, - "state_store": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "state_store_json": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", - }, - }, - } -} - -func dataSourceIBMSchematicsStateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getWorkspaceTemplateStateOptions := &schematicsv1.GetWorkspaceTemplateStateOptions{} - - getWorkspaceTemplateStateOptions.SetWID(d.Get("workspace_id").(string)) - getWorkspaceTemplateStateOptions.SetTID(d.Get("template_id").(string)) - - _, response, err := schematicsClient.GetWorkspaceTemplateStateWithContext(context, getWorkspaceTemplateStateOptions) - if err != nil { - log.Printf("[DEBUG] GetWorkspaceTemplateStateWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(dataSourceIBMSchematicsStateID(d)) - - var stateStore map[string]interface{} - json.Unmarshal(response.Result.(json.RawMessage), &stateStore) - - b := bytes.NewReader(response.Result.(json.RawMessage)) - - decoder := json.NewDecoder(b) - decoder.UseNumber() - decoder.Decode(&stateStore) - - statestr := fmt.Sprintf("%v", stateStore) - d.Set("state_store", statestr) - - stateByte, err := json.MarshalIndent(stateStore, "", "") - if err != nil { - return diag.FromErr(err) - } - - stateStoreJSON := string(stateByte[:]) - d.Set("state_store_json", stateStoreJSON) - - controller, err := getBaseController(meta) - if err != nil { - return diag.FromErr(err) - } - d.Set(ResourceControllerURL, controller+"/schematics") - - return nil -} - -// dataSourceIBMSchematicsStateID returns a reasonable ID for the list. -func dataSourceIBMSchematicsStateID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} diff --git a/ibm/data_source_ibm_schematics_workspace.go b/ibm/data_source_ibm_schematics_workspace.go deleted file mode 100644 index dae8cb65f..000000000 --- a/ibm/data_source_ibm_schematics_workspace.go +++ /dev/null @@ -1,929 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func dataSourceIBMSchematicsWorkspace() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIBMSchematicsWorkspaceRead, - - Schema: map[string]*schema.Schema{ - "workspace_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The ID of the workspace for which you want to retrieve detailed information. To find the workspace ID, use the `GET /v1/workspaces` API.", - }, - "applied_shareddata_ids": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of applied shared dataset id.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "catalog_ref": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "dry_run": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Dry run.", - }, - "item_icon_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the icon of the software template in the IBM Cloud catalog.", - }, - "item_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", - }, - "item_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the software that you chose to install from the IBM Cloud catalog.", - }, - "item_readme_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the readme file of the software template in the IBM Cloud catalog.", - }, - "item_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the software template in the IBM Cloud catalog.", - }, - "launch_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the dashboard to access your software.", - }, - "offering_version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The version of the software template that you chose to install from the IBM Cloud catalog.", - }, - }, - }, - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was created.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that created the workspace.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Workspace CRN.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The description of the workspace.", - }, - "last_health_check_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the last health check was performed by Schematics.", - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The IBM Cloud location where your workspace was provisioned.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the workspace.", - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource group the workspace was provisioned in.", - }, - "runtime_data": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Information about the provisioning engine, state file, and runtime logs.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "engine_cmd": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", - }, - "engine_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", - }, - "engine_version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The version of the provisioning engine that was used.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", - }, - "log_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", - }, - "output_values": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of Output values.", - Elem: &schema.Schema{ - Type: schema.TypeMap, - }, - }, - "resources": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of resources.", - Elem: &schema.Schema{ - Type: schema.TypeMap, - }, - }, - "state_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion actions.", - }, - }, - }, - }, - "shared_data": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Information that is shared across templates in IBM Cloud catalog offerings. This information is not provided when you create a workspace from your own Terraform template.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cluster_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - "cluster_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Target cluster name.", - }, - "entitlement_keys": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The entitlement key that you want to use to install IBM Cloud entitled software.", - Elem: &schema.Schema{ - Type: schema.TypeMap, - }, - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", - }, - "region": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - "resource_group_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - }, - }, - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply actions to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy action was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "A list of tags that are associated with the workspace.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "template_env_settings": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "List of environment values.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", - }, - }, - }, - }, - "template_git_folder": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The subfolder in your GitHub or GitLab repository where your Terraform template is stored. If your template is stored in the root directory, `.` is returned.", - }, - "template_init_state_file": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Init state file.", - }, - "template_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The Terraform version that was used to run your Terraform code.", - }, - "template_uninstall_script_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Uninstall script name.", - }, - "template_values": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", - }, - "template_values_metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "A list of input variables that are associated with the workspace.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "template_inputs": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Information about the input variables that your template uses.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The description of your input variable.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the variable.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`, `object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", - }, - "use_default": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Variable uses default value; and is not over-ridden.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", - }, - }, - }, - }, - "template_ref": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Workspace template ref.", - }, - "template_git_branch": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The branch in GitHub where your Terraform template is stored.", - }, - "template_git_full_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Full repo URL.", - }, - "template_git_has_uploadedgitrepotar": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "Has uploaded git repo tar.", - }, - "template_git_release": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The release tag in GitHub of your Terraform template.", - }, - "template_git_repo_sha_value": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Repo SHA value.", - }, - "template_git_repo_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the repository where the IBM Cloud catalog software template is stored.", - }, - "template_git_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL to the GitHub or GitLab repository where your Terraform template is stored.", - }, - - /*"template_type": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of Workspace type.", - Elem: &schema.Schema{Type: schema.TypeString}, - },*/ - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was last updated.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that updated the workspace.", - }, - "is_frozen": { - Type: schema.TypeBool, - Computed: true, - Deprecated: "use frozen instead", - }, - "frozen": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, the workspace is frozen and changes to the workspace are disabled.", - }, - "frozen_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was frozen.", - }, - "frozen_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that froze the workspace.", - }, - "is_locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, the workspace is locked and disabled for changes.", - Deprecated: "Use locked instead", - }, - "locked": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "If set to true, the workspace is locked and disabled for changes.", - }, - "locked_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that initiated a resource-related action, such as applying or destroying resources, that locked the workspace.", - }, - "locked_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was locked.", - }, - "status_code": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The success or error code that was returned for the last plan, apply, or destroy action that ran against your workspace.", - }, - "status_msg": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The success or error message that was returned for the last plan, apply, or destroy action that ran against your workspace.", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", - }, - }, - } -} - -func dataSourceIBMSchematicsWorkspaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} - - getWorkspaceOptions.SetWID(d.Get("workspace_id").(string)) - - workspaceResponse, response, err := schematicsClient.GetWorkspaceWithContext(context, getWorkspaceOptions) - if err != nil { - log.Printf("[DEBUG] GetWorkspaceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*workspaceResponse.ID) - if err = d.Set("applied_shareddata_ids", workspaceResponse.AppliedShareddataIds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting applied_shareddata_ids: %s", err)) - } - - if workspaceResponse.CatalogRef != nil { - err = d.Set("catalog_ref", dataSourceWorkspaceResponseFlattenCatalogRef(*workspaceResponse.CatalogRef)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_ref %s", err)) - } - } - if err = d.Set("created_at", workspaceResponse.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("created_by", workspaceResponse.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) - } - if err = d.Set("crn", workspaceResponse.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("description", workspaceResponse.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("last_health_check_at", workspaceResponse.LastHealthCheckAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting last_health_check_at: %s", err)) - } - if err = d.Set("location", workspaceResponse.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if err = d.Set("name", workspaceResponse.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("resource_group", workspaceResponse.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - - if workspaceResponse.RuntimeData != nil { - err = d.Set("runtime_data", dataSourceWorkspaceResponseFlattenRuntimeData(workspaceResponse.RuntimeData)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting runtime_data %s", err)) - } - } - - if workspaceResponse.SharedData != nil { - err = d.Set("shared_data", dataSourceWorkspaceResponseFlattenSharedData(*workspaceResponse.SharedData)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting shared_data %s", err)) - } - } - if err = d.Set("status", workspaceResponse.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) - } - if err = d.Set("tags", workspaceResponse.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - - if workspaceResponse.TemplateData != nil { - templateData := dataSourceWorkspaceResponseFlattenTemplateData(workspaceResponse.TemplateData) - - if err = d.Set("template_env_settings", templateData[0]["env_values"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading env_values: %s", err)) - } - if err = d.Set("template_git_folder", templateData[0]["folder"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading folder: %s", err)) - } - if err = d.Set("template_init_state_file", templateData[0]["init_state_file"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading init_state_file: %s", err)) - } - if err = d.Set("template_type", templateData[0]["type"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading type: %s", err)) - } - if err = d.Set("template_uninstall_script_name", templateData[0]["uninstall_script_name"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading uninstall_script_name: %s", err)) - } - if err = d.Set("template_values", templateData[0]["values"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading values: %s", err)) - } - if err = d.Set("template_values_metadata", templateData[0]["values_metadata"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading values_metadata: %s", err)) - } - if err = d.Set("template_inputs", templateData[0]["variablestore"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading variablestore: %s", err)) - } - } - if err = d.Set("template_ref", workspaceResponse.TemplateRef); err != nil { - return diag.FromErr(fmt.Errorf("Error setting template_ref: %s", err)) - } - - if workspaceResponse.TemplateRepo != nil { - templateRepoMap := dataSourceWorkspaceResponseFlattenTemplateRepo(*workspaceResponse.TemplateRepo) - if err = d.Set("template_git_branch", templateRepoMap[0]["branch"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading branch: %s", err)) - } - if err = d.Set("template_git_release", templateRepoMap[0]["release"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading release: %s", err)) - } - if err = d.Set("template_git_repo_sha_value", templateRepoMap[0]["repo_sha_value"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading repo_sha_value: %s", err)) - } - if err = d.Set("template_git_repo_url", templateRepoMap[0]["repo_url"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading repo_url: %s", err)) - } - if err = d.Set("template_git_url", templateRepoMap[0]["url"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading url: %s", err)) - } - if err = d.Set("template_git_has_uploadedgitrepotar", templateRepoMap[0]["has_uploadedgitrepotar"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading has_uploadedgitrepotar: %s", err)) - } - } - /*if err = d.Set("type", workspaceResponse.Type); err != nil { - return fmt.Errorf("Error setting type: %s", err) - }*/ - if workspaceResponse.UpdatedAt != nil { - if err = d.Set("updated_at", workspaceResponse.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - } - if err = d.Set("updated_by", workspaceResponse.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) - } - - if workspaceResponse.WorkspaceStatus != nil { - workspaceStatusMap := dataSourceWorkspaceResponseFlattenWorkspaceStatus(*workspaceResponse.WorkspaceStatus) - if err = d.Set("is_frozen", workspaceStatusMap[0]["frozen"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen: %s", err)) - } - if err = d.Set("frozen", workspaceStatusMap[0]["frozen"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen: %s", err)) - } - if err = d.Set("frozen_at", workspaceStatusMap[0]["frozen_at"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen_at: %s", err)) - } - if err = d.Set("frozen_by", workspaceStatusMap[0]["frozen_by"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen_by: %s", err)) - } - if err = d.Set("is_locked", workspaceStatusMap[0]["locked"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked: %s", err)) - } - if err = d.Set("locked", workspaceStatusMap[0]["locked"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked: %s", err)) - } - if err = d.Set("locked_by", workspaceStatusMap[0]["locked_by"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked_by: %s", err)) - } - if err = d.Set("locked_time", workspaceStatusMap[0]["locked_time"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked_time: %s", err)) - } - } - - if workspaceResponse.WorkspaceStatusMsg != nil { - workspaceStatusMsgMap := dataSourceWorkspaceResponseFlattenWorkspaceStatusMsg(*workspaceResponse.WorkspaceStatusMsg) - if err = d.Set("status_code", workspaceStatusMsgMap[0]["status_code"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading status_code: %s", err)) - } - if err = d.Set("status_msg", workspaceStatusMsgMap[0]["status_msg"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading status_msg: %s", err)) - } - } - - controller, err := getBaseController(meta) - if err != nil { - return diag.FromErr(err) - } - d.Set(ResourceControllerURL, controller+"/schematics") - - return nil -} - -func dataSourceWorkspaceResponseFlattenCatalogRef(result schematicsv1.CatalogRef) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceWorkspaceResponseCatalogRefToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceWorkspaceResponseCatalogRefToMap(catalogRefItem schematicsv1.CatalogRef) (catalogRefMap map[string]interface{}) { - catalogRefMap = map[string]interface{}{} - - if catalogRefItem.DryRun != nil { - catalogRefMap["dry_run"] = catalogRefItem.DryRun - } - if catalogRefItem.ItemIconURL != nil { - catalogRefMap["item_icon_url"] = catalogRefItem.ItemIconURL - } - if catalogRefItem.ItemID != nil { - catalogRefMap["item_id"] = catalogRefItem.ItemID - } - if catalogRefItem.ItemName != nil { - catalogRefMap["item_name"] = catalogRefItem.ItemName - } - if catalogRefItem.ItemReadmeURL != nil { - catalogRefMap["item_readme_url"] = catalogRefItem.ItemReadmeURL - } - if catalogRefItem.ItemURL != nil { - catalogRefMap["item_url"] = catalogRefItem.ItemURL - } - if catalogRefItem.LaunchURL != nil { - catalogRefMap["launch_url"] = catalogRefItem.LaunchURL - } - if catalogRefItem.OfferingVersion != nil { - catalogRefMap["offering_version"] = catalogRefItem.OfferingVersion - } - - return catalogRefMap -} - -func dataSourceWorkspaceResponseFlattenRuntimeData(result []schematicsv1.TemplateRunTimeDataResponse) (runtimeData []map[string]interface{}) { - for _, runtimeDataItem := range result { - runtimeData = append(runtimeData, dataSourceWorkspaceResponseRuntimeDataToMap(runtimeDataItem)) - } - - return runtimeData -} - -func dataSourceWorkspaceResponseRuntimeDataToMap(runtimeDataItem schematicsv1.TemplateRunTimeDataResponse) (runtimeDataMap map[string]interface{}) { - runtimeDataMap = map[string]interface{}{} - - if runtimeDataItem.EngineCmd != nil { - runtimeDataMap["engine_cmd"] = runtimeDataItem.EngineCmd - } - if runtimeDataItem.EngineName != nil { - runtimeDataMap["engine_name"] = runtimeDataItem.EngineName - } - if runtimeDataItem.EngineVersion != nil { - runtimeDataMap["engine_version"] = runtimeDataItem.EngineVersion - } - if runtimeDataItem.ID != nil { - runtimeDataMap["id"] = runtimeDataItem.ID - } - if runtimeDataItem.LogStoreURL != nil { - runtimeDataMap["log_store_url"] = runtimeDataItem.LogStoreURL - } - if runtimeDataItem.OutputValues != nil { - runtimeDataMap["output_values"] = runtimeDataItem.OutputValues - } - if runtimeDataItem.Resources != nil { - runtimeDataMap["resources"] = runtimeDataItem.Resources - } - if runtimeDataItem.StateStoreURL != nil { - runtimeDataMap["state_store_url"] = runtimeDataItem.StateStoreURL - } - - return runtimeDataMap -} - -func dataSourceWorkspaceResponseFlattenSharedData(result schematicsv1.SharedTargetDataResponse) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceWorkspaceResponseSharedDataToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceWorkspaceResponseSharedDataToMap(sharedDataItem schematicsv1.SharedTargetDataResponse) (sharedDataMap map[string]interface{}) { - sharedDataMap = map[string]interface{}{} - - if sharedDataItem.ClusterID != nil { - sharedDataMap["cluster_id"] = sharedDataItem.ClusterID - } - if sharedDataItem.ClusterName != nil { - sharedDataMap["cluster_name"] = sharedDataItem.ClusterName - } - if sharedDataItem.EntitlementKeys != nil { - sharedDataMap["entitlement_keys"] = sharedDataItem.EntitlementKeys - } - if sharedDataItem.Namespace != nil { - sharedDataMap["namespace"] = sharedDataItem.Namespace - } - if sharedDataItem.Region != nil { - sharedDataMap["region"] = sharedDataItem.Region - } - if sharedDataItem.ResourceGroupID != nil { - sharedDataMap["resource_group_id"] = sharedDataItem.ResourceGroupID - } - - return sharedDataMap -} - -func dataSourceWorkspaceResponseFlattenTemplateData(result []schematicsv1.TemplateSourceDataResponse) (templateData []map[string]interface{}) { - for _, templateDataItem := range result { - templateData = append(templateData, dataSourceWorkspaceResponseTemplateDataToMap(templateDataItem)) - } - - return templateData -} - -func dataSourceWorkspaceResponseTemplateDataToMap(templateDataItem schematicsv1.TemplateSourceDataResponse) (templateDataMap map[string]interface{}) { - templateDataMap = map[string]interface{}{} - - if templateDataItem.EnvValues != nil { - envValuesList := []map[string]interface{}{} - for _, envValuesItem := range templateDataItem.EnvValues { - envValuesList = append(envValuesList, dataSourceWorkspaceResponseTemplateDataEnvValuesToMap(envValuesItem)) - } - templateDataMap["env_values"] = envValuesList - } - if templateDataItem.Folder != nil { - templateDataMap["folder"] = templateDataItem.Folder - } - if templateDataItem.HasGithubtoken != nil { - templateDataMap["has_githubtoken"] = templateDataItem.HasGithubtoken - } - if templateDataItem.ID != nil { - templateDataMap["id"] = templateDataItem.ID - } - if templateDataItem.Type != nil { - templateDataMap["type"] = templateDataItem.Type - } - if templateDataItem.UninstallScriptName != nil { - templateDataMap["uninstall_script_name"] = templateDataItem.UninstallScriptName - } - if templateDataItem.Values != nil { - templateDataMap["values"] = templateDataItem.Values - } - if templateDataItem.ValuesMetadata != nil { - templateDataMap["values_metadata"] = templateDataItem.ValuesMetadata - } - if templateDataItem.ValuesURL != nil { - templateDataMap["values_url"] = templateDataItem.ValuesURL - } - if templateDataItem.Variablestore != nil { - variablestoreList := []map[string]interface{}{} - for _, variablestoreItem := range templateDataItem.Variablestore { - variablestoreList = append(variablestoreList, dataSourceWorkspaceResponseTemplateDataVariablestoreToMap(variablestoreItem)) - } - templateDataMap["variablestore"] = variablestoreList - } - - return templateDataMap -} - -func dataSourceWorkspaceResponseTemplateDataEnvValuesToMap(envValuesItem schematicsv1.EnvVariableResponse) (envValuesMap map[string]interface{}) { - envValuesMap = map[string]interface{}{} - - if envValuesItem.Hidden != nil { - envValuesMap["hidden"] = *envValuesItem.Hidden - } - if envValuesItem.Name != nil { - envValuesMap["name"] = envValuesItem.Name - } - if envValuesItem.Secure != nil { - envValuesMap["secure"] = *envValuesItem.Secure - } - if envValuesItem.Value != nil { - envValuesMap["value"] = envValuesItem.Value - } - - return envValuesMap -} - -func dataSourceWorkspaceResponseTemplateDataVariablestoreToMap(variablestoreItem schematicsv1.WorkspaceVariableResponse) (variablestoreMap map[string]interface{}) { - variablestoreMap = map[string]interface{}{} - - if variablestoreItem.Description != nil { - variablestoreMap["description"] = variablestoreItem.Description - } - if variablestoreItem.Name != nil { - variablestoreMap["name"] = variablestoreItem.Name - } - if variablestoreItem.Secure != nil { - variablestoreMap["secure"] = variablestoreItem.Secure - } - if variablestoreItem.Type != nil { - variablestoreMap["type"] = variablestoreItem.Type - } - if variablestoreItem.Value != nil { - variablestoreMap["value"] = variablestoreItem.Value - } - - return variablestoreMap -} - -func dataSourceWorkspaceResponseFlattenTemplateRepo(result schematicsv1.TemplateRepoResponse) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceWorkspaceResponseTemplateRepoToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceWorkspaceResponseTemplateRepoToMap(templateRepoItem schematicsv1.TemplateRepoResponse) (templateRepoMap map[string]interface{}) { - templateRepoMap = map[string]interface{}{} - - if templateRepoItem.Branch != nil { - templateRepoMap["branch"] = templateRepoItem.Branch - } - if templateRepoItem.FullURL != nil { - templateRepoMap["full_url"] = templateRepoItem.FullURL - } - if templateRepoItem.HasUploadedgitrepotar != nil { - templateRepoMap["has_uploadedgitrepotar"] = templateRepoItem.HasUploadedgitrepotar - } - if templateRepoItem.Release != nil { - templateRepoMap["release"] = templateRepoItem.Release - } - if templateRepoItem.RepoShaValue != nil { - templateRepoMap["repo_sha_value"] = templateRepoItem.RepoShaValue - } - if templateRepoItem.RepoURL != nil { - templateRepoMap["repo_url"] = templateRepoItem.RepoURL - } - if templateRepoItem.URL != nil { - templateRepoMap["url"] = templateRepoItem.URL - } - - return templateRepoMap -} - -func dataSourceWorkspaceResponseFlattenWorkspaceStatus(result schematicsv1.WorkspaceStatusResponse) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceWorkspaceResponseWorkspaceStatusToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceWorkspaceResponseWorkspaceStatusToMap(workspaceStatusItem schematicsv1.WorkspaceStatusResponse) (workspaceStatusMap map[string]interface{}) { - workspaceStatusMap = map[string]interface{}{} - - if workspaceStatusItem.Frozen != nil { - workspaceStatusMap["frozen"] = workspaceStatusItem.Frozen - } - if workspaceStatusItem.FrozenAt != nil { - workspaceStatusMap["frozen_at"] = workspaceStatusItem.FrozenAt.String() - } - if workspaceStatusItem.FrozenBy != nil { - workspaceStatusMap["frozen_by"] = workspaceStatusItem.FrozenBy - } - if workspaceStatusItem.Locked != nil { - workspaceStatusMap["locked"] = workspaceStatusItem.Locked - } - if workspaceStatusItem.LockedBy != nil { - workspaceStatusMap["locked_by"] = workspaceStatusItem.LockedBy - } - if workspaceStatusItem.LockedTime != nil { - workspaceStatusMap["locked_time"] = workspaceStatusItem.LockedTime.String() - } - - return workspaceStatusMap -} - -func dataSourceWorkspaceResponseFlattenWorkspaceStatusMsg(result schematicsv1.WorkspaceStatusMessage) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceWorkspaceResponseWorkspaceStatusMsgToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceWorkspaceResponseWorkspaceStatusMsgToMap(workspaceStatusMsgItem schematicsv1.WorkspaceStatusMessage) (workspaceStatusMsgMap map[string]interface{}) { - workspaceStatusMsgMap = map[string]interface{}{} - - if workspaceStatusMsgItem.StatusCode != nil { - workspaceStatusMsgMap["status_code"] = workspaceStatusMsgItem.StatusCode - } - if workspaceStatusMsgItem.StatusMsg != nil { - workspaceStatusMsgMap["status_msg"] = workspaceStatusMsgItem.StatusMsg - } - - return workspaceStatusMsgMap -} diff --git a/ibm/data_source_ibm_space.go b/ibm/data_source_ibm_space.go deleted file mode 100644 index 338e76aa6..000000000 --- a/ibm/data_source_ibm_space.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceIBMSpace() *schema.Resource { - return &schema.Resource{ - Read: dataSourceIBMSpaceRead, - - Schema: map[string]*schema.Schema{ - "space": { - Description: "Space name, for example dev", - Type: schema.TypeString, - Optional: true, - Deprecated: "use name instead", - ExactlyOneOf: []string{"space", "name"}, - }, - "name": { - Description: "Space name, for example dev", - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"space", "name"}, - }, - "org": { - Description: "The org this space belongs to", - Type: schema.TypeString, - Required: true, - }, - "auditors": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who have auditor role in this space, ex - user@example.com", - }, - "managers": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who have manager role in this space, ex - user@example.com", - }, - "developers": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who have developer role in this space, ex - user@example.com", - }, - }, - } -} - -func dataSourceIBMSpaceRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - orgAPI := cfClient.Organizations() - spaceAPI := cfClient.Spaces() - var space string - if v, ok := d.GetOk("name"); ok { - space = v.(string) - } - if v, ok := d.GetOk("space"); ok { - space = v.(string) - } - - org := d.Get("org").(string) - - orgFields, err := orgAPI.FindByName(org, BluemixRegion) - if err != nil { - return fmt.Errorf("Error retrieving org: %s", err) - } - spaceFields, err := spaceAPI.FindByNameInOrg(orgFields.GUID, space, BluemixRegion) - if err != nil { - return fmt.Errorf("Error retrieving space: %s", err) - } - - spaceGUID := spaceFields.GUID - d.SetId(spaceGUID) - - auditors, err := spaceAPI.ListAuditors(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving auditors in the space: %s", err) - } - - managers, err := spaceAPI.ListManagers(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving managers in the space: %s", err) - } - - developers, err := spaceAPI.ListDevelopers(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving developers in space: %s", err) - } - - d.Set("auditors", flattenSpaceRoleUsers(auditors)) - d.Set("managers", flattenSpaceRoleUsers(managers)) - d.Set("developers", flattenSpaceRoleUsers(developers)) - - return nil -} diff --git a/ibm/data_source_ibm_space_test.go b/ibm/data_source_ibm_space_test.go deleted file mode 100644 index 5fecf6e73..000000000 --- a/ibm/data_source_ibm_space_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSpaceDataSource_basic(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSpaceDataSourceConfig(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_space.testacc_ds_space", "org", cfOrganization), - resource.TestCheckResourceAttr("data.ibm_space.testacc_ds_space", "space", cfSpace), - ), - }, - }, - }) -} - -func testAccCheckIBMSpaceDataSourceConfig() string { - return fmt.Sprintf(` -data "ibm_space" "testacc_ds_space" { - org = "%s" - space = "%s" -}`, cfOrganization, cfSpace) - -} diff --git a/ibm/diff_supress_funcs.go b/ibm/diff_supress_funcs.go deleted file mode 100644 index 968f7ee30..000000000 --- a/ibm/diff_supress_funcs.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "encoding/json" - "log" - "reflect" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func suppressEquivalentJSON(k, old, new string, d *schema.ResourceData) bool { - - if old == "" { - return false - } - var oldObj, newObj []map[string]interface{} - err := json.Unmarshal([]byte(old), &oldObj) - if err != nil { - log.Printf("Error unmarshalling old json :: %s", err.Error()) - return false - } - err = json.Unmarshal([]byte(new), &newObj) - if err != nil { - log.Printf("Error unmarshalling new json :: %s", err.Error()) - return false - } - - oldm := make(map[interface{}]interface{}) - newm := make(map[interface{}]interface{}) - - for _, m := range oldObj { - oldm[m["key"]] = m["value"] - } - for _, m := range newObj { - newm[m["key"]] = m["value"] - } - return reflect.DeepEqual(oldm, newm) -} diff --git a/ibm/flex/diff_supress_funcs.go b/ibm/flex/diff_supress_funcs.go new file mode 100644 index 000000000..adcdf47e0 --- /dev/null +++ b/ibm/flex/diff_supress_funcs.go @@ -0,0 +1,102 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package flex + +import ( + "crypto/hmac" + "encoding/hex" + "encoding/json" + "log" + "reflect" + "regexp" + "strings" + + "golang.org/x/crypto/sha3" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func SuppressEquivalentJSON(k, old, new string, d *schema.ResourceData) bool { + + if old == "" { + return false + } + var oldObj, newObj []map[string]interface{} + err := json.Unmarshal([]byte(old), &oldObj) + if err != nil { + log.Printf("Error unmarshalling old json :: %s", err.Error()) + return false + } + err = json.Unmarshal([]byte(new), &newObj) + if err != nil { + log.Printf("Error unmarshalling new json :: %s", err.Error()) + return false + } + + oldm := make(map[interface{}]interface{}) + newm := make(map[interface{}]interface{}) + + for _, m := range oldObj { + oldm[m["key"]] = m["value"] + } + for _, m := range newObj { + newm[m["key"]] = m["value"] + } + return reflect.DeepEqual(oldm, newm) +} + +func SuppressHashedRawSecret(k, old, new string, d *schema.ResourceData) bool { + if len(d.Id()) == 0 { + return false + } + isSecretRef, _ := regexp.MatchString("[{]{1}(\\b(vault)\\b[:]{2}([ a-zA-Z0-9_-]*)[.]{0,1}(.*))[}]{1}", new) + if isSecretRef { + return false + } + parts, _ := SepIdParts(d.Id(), "/") + secret := parts[1] + mac := hmac.New(sha3.New512, []byte(secret)) + mac.Write([]byte(new)) + secureHmac := hex.EncodeToString(mac.Sum(nil)) + return cmp.Equal(strings.Join([]string{"hash", "SHA3-512", secureHmac}, ":"), old) +} + +func SuppressPipelinePropertyRawSecret(k, old, new string, d *schema.ResourceData) bool { + // ResourceIBMCdTektonPipelineProperty + if d.Get("type").(string) == "secure" { + segs := []string{d.Get("pipeline_id").(string), d.Get("name").(string)} + secret := strings.Join(segs, ".") + mac := hmac.New(sha3.New512, []byte(secret)) + mac.Write([]byte(new)) + secureHmac := hex.EncodeToString(mac.Sum(nil)) + return cmp.Equal(strings.Join([]string{"hash", "SHA3-512", secureHmac}, ":"), old) + } else { + return old == new + } +} + +func SuppressTriggerPropertyRawSecret(k, old, new string, d *schema.ResourceData) bool { + // ResourceIBMCdTektonPipelineTriggerProperty + if d.Get("type").(string) == "secure" { + segs := []string{d.Get("pipeline_id").(string), d.Get("trigger_id").(string), d.Get("name").(string)} + secret := strings.Join(segs, ".") + mac := hmac.New(sha3.New512, []byte(secret)) + mac.Write([]byte(new)) + secureHmac := hex.EncodeToString(mac.Sum(nil)) + return cmp.Equal(strings.Join([]string{"hash", "SHA3-512", secureHmac}, ":"), old) + } else { + return old == new + } +} + +func SuppressGenericWebhookRawSecret(k, old, new string, d *schema.ResourceData) bool { + // ResourceIBMCdTektonPipelineTrigger + segs := []string{d.Get("pipeline_id").(string), d.Get("trigger_id").(string)} + secret := strings.Join(segs, ".") + mac := hmac.New(sha3.New512, []byte(secret)) + mac.Write([]byte(new)) + secureHmac := hex.EncodeToString(mac.Sum(nil)) + return cmp.Equal(strings.Join([]string{"hash", "SHA3-512", secureHmac}, ":"), old) +} diff --git a/ibm/flatten.go b/ibm/flex/flatten.go similarity index 98% rename from ibm/flatten.go rename to ibm/flex/flatten.go index 21f0bd1e4..161a9691d 100644 --- a/ibm/flatten.go +++ b/ibm/flex/flatten.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package flex import ( "fmt" @@ -41,6 +41,7 @@ func flatten(result map[string]string, prefix string, v reflect.Value) { result[prefix] = "false" } case reflect.Int: + case reflect.Int64: result[prefix] = fmt.Sprintf("%d", v.Int()) case reflect.Map: flattenMap(result, prefix, v) diff --git a/ibm/map.go b/ibm/flex/map.go similarity index 99% rename from ibm/map.go rename to ibm/flex/map.go index 153ae70d6..12c91340b 100644 --- a/ibm/map.go +++ b/ibm/flex/map.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package flex import ( "strings" diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go new file mode 100644 index 000000000..a251d530a --- /dev/null +++ b/ibm/flex/structures.go @@ -0,0 +1,3226 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package flex + +import ( + "bytes" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "net/url" + "os" + "path" + "reflect" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + kp "github.com/IBM/keyprotect-go-client" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" + "github.com/apache/openwhisk-client-go/whisk" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/softlayer/softlayer-go/datatypes" + "github.com/softlayer/softlayer-go/sl" + + "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/bluemix-go/api/schematics" + "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +const ( + prodBaseController = "https://cloud.ibm.com" + stageBaseController = "https://test.cloud.ibm.com" + //ResourceControllerURL ... + ResourceControllerURL = "resource_controller_url" + //ResourceName ... + ResourceName = "resource_name" + //ResourceCRN ... + ResourceCRN = "resource_crn" + //ResourceStatus ... + ResourceStatus = "resource_status" + //ResourceGroupName ... + ResourceGroupName = "resource_group_name" + //RelatedCRN ... + RelatedCRN = "related_crn" + SystemIBMLabelPrefix = "ibm-cloud.kubernetes.io/" + KubernetesLabelPrefix = "kubernetes.io/" + K8sLabelPrefix = "k8s.io/" + isLBListenerPolicyAction = "action" + isLBListenerPolicyTargetID = "target_id" + isLBListenerPolicyTargetURL = "target_url" + isLBListenerPolicyTargetHTTPStatusCode = "target_http_status_code" + isLBListenerPolicyHTTPSRedirectStatusCode = "target_https_redirect_status_code" + isLBListenerPolicyHTTPSRedirectURI = "target_https_redirect_uri" + isLBListenerPolicyHTTPSRedirectListener = "target_https_redirect_listener" + isLBPoolSessPersistenceType = "session_persistence_type" + isLBPoolSessPersistenceAppCookieName = "session_persistence_app_cookie_name" + isLBProfile = "profile" + isLBRouteMode = "route_mode" + isLBType = "type" +) + +// HashInt ... +func HashInt(v interface{}) int { return v.(int) } + +func ExpandStringList(input []interface{}) []string { + vs := make([]string, len(input)) + for i, v := range input { + vs[i] = v.(string) + } + return vs +} + +func FlattenStringList(list []string) []interface{} { + vs := make([]interface{}, len(list)) + for i, v := range list { + vs[i] = v + } + return vs +} + +func ExpandIntList(input []interface{}) []int { + vs := make([]int, len(input)) + for i, v := range input { + vs[i] = v.(int) + } + return vs +} + +func FlattenIntList(list []int) []interface{} { + vs := make([]interface{}, len(list)) + for i, v := range list { + vs[i] = v + } + return vs +} + +func NewStringSet(f schema.SchemaSetFunc, in []string) *schema.Set { + var out = make([]interface{}, len(in), len(in)) + for i, v := range in { + out[i] = v + } + return schema.NewSet(f, out) +} + +func FlattenRoute(in []mccpv2.Route) *schema.Set { + vs := make([]string, len(in)) + for i, v := range in { + vs[i] = v.GUID + } + return NewStringSet(schema.HashString, vs) +} + +func stringSliceToSet(in []string) *schema.Set { + vs := make([]string, len(in)) + for i, v := range in { + vs[i] = v + } + return NewStringSet(schema.HashString, vs) +} + +func FlattenServiceBindings(in []mccpv2.ServiceBinding) *schema.Set { + vs := make([]string, len(in)) + for i, v := range in { + vs[i] = v.ServiceInstanceGUID + } + return NewStringSet(schema.HashString, vs) +} + +func flattenPort(in []int) *schema.Set { + var out = make([]interface{}, len(in)) + for i, v := range in { + out[i] = v + } + return schema.NewSet(HashInt, out) +} + +func FlattenFileStorageID(in []datatypes.Network_Storage) *schema.Set { + var out = []interface{}{} + for _, v := range in { + if *v.NasType == "NAS" { + out = append(out, *v.Id) + } + } + return schema.NewSet(HashInt, out) +} + +func FlattenBlockStorageID(in []datatypes.Network_Storage) *schema.Set { + var out = []interface{}{} + for _, v := range in { + if *v.NasType == "ISCSI" { + out = append(out, *v.Id) + } + } + return schema.NewSet(HashInt, out) +} + +func FlattenSSHKeyIDs(in []datatypes.Security_Ssh_Key) *schema.Set { + var out = []interface{}{} + for _, v := range in { + out = append(out, *v.Id) + } + return schema.NewSet(HashInt, out) +} + +func FlattenSpaceRoleUsers(in []mccpv2.SpaceRole) *schema.Set { + var out = []interface{}{} + for _, v := range in { + out = append(out, v.UserName) + } + return schema.NewSet(schema.HashString, out) +} + +func FlattenOrgRole(in []mccpv2.OrgRole, excludeUsername string) *schema.Set { + var out = []interface{}{} + for _, v := range in { + if excludeUsername == "" { + out = append(out, v.UserName) + } else { + if v.UserName != excludeUsername { + out = append(out, v.UserName) + } + } + } + return schema.NewSet(schema.HashString, out) +} + +func flattenMapInterfaceVal(m map[string]interface{}) map[string]string { + out := make(map[string]string) + for k, v := range m { + out[k] = fmt.Sprintf("%v", v) + } + return out +} + +func flattenCredentials(creds map[string]interface{}) map[string]string { + return flattenMapInterfaceVal(creds) +} + +func flattenServiceKeyCredentials(creds map[string]interface{}) map[string]string { + return flattenCredentials(creds) +} + +func FlattenServiceInstanceCredentials(keys []mccpv2.ServiceKeyFields) []interface{} { + var out = make([]interface{}, len(keys), len(keys)) + for i, k := range keys { + m := make(map[string]interface{}) + m["name"] = k.Entity.Name + m["credentials"] = Flatten(k.Entity.Credentials) + out[i] = m + } + return out +} + +func FlattenUsersSet(userList *schema.Set) []string { + users := make([]string, 0) + for _, user := range userList.List() { + users = append(users, user.(string)) + } + return users +} + +func ExpandProtocols(configured []interface{}) ([]datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration, error) { + protocols := make([]datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration, 0, len(configured)) + var lbMethodToId = make(map[string]string) + for _, lRaw := range configured { + data := lRaw.(map[string]interface{}) + p := &datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration{ + FrontendProtocol: sl.String(data["frontend_protocol"].(string)), + BackendProtocol: sl.String(data["backend_protocol"].(string)), + FrontendPort: sl.Int(data["frontend_port"].(int)), + BackendPort: sl.Int(data["backend_port"].(int)), + } + if v, ok := data["session_stickiness"]; ok && v.(string) != "" { + p.SessionType = sl.String(v.(string)) + } + if v, ok := data["max_conn"]; ok && v.(int) != 0 { + p.MaxConn = sl.Int(v.(int)) + } + if v, ok := data["tls_certificate_id"]; ok && v.(int) != 0 { + p.TlsCertificateId = sl.Int(v.(int)) + } + if v, ok := data["load_balancing_method"]; ok { + p.LoadBalancingMethod = sl.String(lbMethodToId[v.(string)]) + } + if v, ok := data["protocol_id"]; ok && v.(string) != "" { + p.ListenerUuid = sl.String(v.(string)) + } + + var isValid bool + if p.TlsCertificateId != nil && *p.TlsCertificateId != 0 { + // validate the protocol is correct + if *p.FrontendProtocol == "HTTPS" { + isValid = true + } + } else { + isValid = true + } + + if isValid { + protocols = append(protocols, *p) + } else { + return protocols, fmt.Errorf("tls_certificate_id may be set only when frontend protocol is 'HTTPS'") + } + + } + return protocols, nil +} + +func ExpandMembers(configured []interface{}) []datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo { + members := make([]datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo, 0, len(configured)) + for _, lRaw := range configured { + data := lRaw.(map[string]interface{}) + p := &datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo{} + if v, ok := data["private_ip_address"]; ok && v.(string) != "" { + p.PrivateIpAddress = sl.String(v.(string)) + } + if v, ok := data["weight"]; ok && v.(int) != 0 { + p.Weight = sl.Int(v.(int)) + } + + members = append(members, *p) + } + return members +} + +func FlattenServerInstances(list []datatypes.Network_LBaaS_Member) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + "private_ip_address": *i.Address, + "member_id": *i.Uuid, + } + if i.Weight != nil { + l["weight"] = *i.Weight + } + result = append(result, l) + } + return result +} + +func FlattenProtocols(list []datatypes.Network_LBaaS_Listener) []map[string]interface{} { + var lbIdToMethod = make(map[string]string) + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + "frontend_protocol": *i.Protocol, + "frontend_port": *i.ProtocolPort, + "backend_protocol": *i.DefaultPool.Protocol, + "backend_port": *i.DefaultPool.ProtocolPort, + "load_balancing_method": lbIdToMethod[*i.DefaultPool.LoadBalancingAlgorithm], + "protocol_id": *i.Uuid, + } + if i.DefaultPool.SessionAffinity != nil && i.DefaultPool.SessionAffinity.Type != nil && *i.DefaultPool.SessionAffinity.Type != "" { + l["session_stickiness"] = *i.DefaultPool.SessionAffinity.Type + } + if i.ConnectionLimit != nil && *i.ConnectionLimit != 0 { + l["max_conn"] = *i.ConnectionLimit + } + if i.TlsCertificateId != nil && *i.TlsCertificateId != 0 { + l["tls_certificate_id"] = *i.TlsCertificateId + } + result = append(result, l) + } + return result +} + +func FlattenVpcWorkerPools(list []containerv2.GetWorkerPoolResponse) []map[string]interface{} { + workerPools := make([]map[string]interface{}, len(list)) + for i, workerPool := range list { + l := map[string]interface{}{ + "id": workerPool.ID, + "name": workerPool.PoolName, + "flavor": workerPool.Flavor, + "worker_count": workerPool.WorkerCount, + "isolation": workerPool.Isolation, + "labels": workerPool.Labels, + "state": workerPool.Lifecycle.ActualState, + "host_pool_id": workerPool.HostPoolID, + } + zones := workerPool.Zones + zonesConfig := make([]map[string]interface{}, len(zones)) + for j, zone := range zones { + z := map[string]interface{}{ + "zone": zone.ID, + "worker_count": zone.WorkerCount, + } + subnets := zone.Subnets + subnetConfig := make([]map[string]interface{}, len(subnets)) + for k, subnet := range subnets { + s := map[string]interface{}{ + "id": subnet.ID, + "primary": subnet.Primary, + } + subnetConfig[k] = s + } + z["subnets"] = subnetConfig + zonesConfig[j] = z + } + l["zones"] = zonesConfig + workerPools[i] = l + } + + return workerPools +} + +func flattenVpcZones(list []containerv2.ZoneResp) []map[string]interface{} { + zones := make([]map[string]interface{}, len(list)) + for i, zone := range list { + l := map[string]interface{}{ + "id": zone.ID, + "subnet_id": FlattenSubnets(zone.Subnets), + "worker_count": zone.WorkerCount, + } + zones[i] = l + } + return zones +} +func FlattenConditions(list []iamaccessgroupsv2.RuleConditions) []map[string]interface{} { + conditions := make([]map[string]interface{}, len(list)) + for i, cond := range list { + l := map[string]interface{}{ + "claim": cond.Claim, + "operator": cond.Operator, + "value": strings.ReplaceAll(*cond.Value, "\"", ""), + } + conditions[i] = l + } + return conditions +} +func FlattenAccessGroupRules(list *iamaccessgroupsv2.RulesList) []map[string]interface{} { + rules := make([]map[string]interface{}, len(list.Rules)) + for i, item := range list.Rules { + l := map[string]interface{}{ + "name": item.Name, + "expiration": item.Expiration, + "identity_provider": item.RealmName, + "conditions": FlattenConditions(item.Conditions), + } + rules[i] = l + } + return rules +} + +func FlattenSubnets(list []containerv2.Subnet) []map[string]interface{} { + subs := make([]map[string]interface{}, len(list)) + for i, sub := range list { + l := map[string]interface{}{ + "id": sub.ID, + "worker_count": sub.Primary, + } + subs[i] = l + } + return subs +} + +func FlattenZones(list []containerv1.WorkerPoolZoneResponse) []map[string]interface{} { + zones := make([]map[string]interface{}, len(list)) + for i, zone := range list { + l := map[string]interface{}{ + "zone": zone.WorkerPoolZone.ID, + "private_vlan": zone.WorkerPoolZone.WorkerPoolZoneNetwork.PrivateVLAN, + "public_vlan": zone.WorkerPoolZone.WorkerPoolZoneNetwork.PublicVLAN, + "worker_count": zone.WorkerCount, + } + zones[i] = l + } + return zones +} + +func FlattenWorkerPools(list []containerv1.WorkerPoolResponse) []map[string]interface{} { + workerPools := make([]map[string]interface{}, len(list)) + for i, workerPool := range list { + l := map[string]interface{}{ + "id": workerPool.ID, + "hardware": workerPool.Isolation, + "name": workerPool.Name, + "machine_type": workerPool.MachineType, + "size_per_zone": workerPool.Size, + "state": workerPool.State, + "labels": workerPool.Labels, + } + zones := workerPool.Zones + zonesConfig := make([]map[string]interface{}, len(zones)) + for j, zone := range zones { + z := map[string]interface{}{ + "zone": zone.ID, + "private_vlan": zone.PrivateVLAN, + "public_vlan": zone.PublicVLAN, + "worker_count": zone.WorkerCount, + } + zonesConfig[j] = z + } + l["zones"] = zonesConfig + workerPools[i] = l + } + + return workerPools +} + +func FlattenAlbs(list []containerv1.ALBConfig, filterType string) []map[string]interface{} { + albs := make([]map[string]interface{}, 0) + for _, alb := range list { + if alb.ALBType == filterType || filterType == "all" { + l := map[string]interface{}{ + "id": alb.ALBID, + "name": alb.Name, + "alb_type": alb.ALBType, + "enable": alb.Enable, + "state": alb.State, + "num_of_instances": alb.NumOfInstances, + "alb_ip": alb.ALBIP, + "resize": alb.Resize, + "disable_deployment": alb.DisableDeployment, + } + albs = append(albs, l) + } + } + return albs +} + +func FlattenVpcAlbs(list []containerv2.AlbConfig, filterType string) []map[string]interface{} { + albs := make([]map[string]interface{}, 0) + for _, alb := range list { + if alb.AlbType == filterType || filterType == "all" { + l := map[string]interface{}{ + "id": alb.AlbID, + "name": alb.Name, + "alb_type": alb.AlbType, + "enable": alb.Enable, + "state": alb.State, + "resize": alb.Resize, + "disable_deployment": alb.DisableDeployment, + "load_balancer_hostname": alb.LoadBalancerHostname, + } + albs = append(albs, l) + } + } + return albs +} + +func FlattenNetworkInterfaces(list []containerv2.Network) []map[string]interface{} { + nwInterfaces := make([]map[string]interface{}, len(list)) + for i, nw := range list { + l := map[string]interface{}{ + "cidr": nw.Cidr, + "ip_address": nw.IpAddress, + "subnet_id": nw.SubnetID, + } + nwInterfaces[i] = l + } + return nwInterfaces +} + +func FlattenVlans(list []containerv1.Vlan) []map[string]interface{} { + vlans := make([]map[string]interface{}, len(list)) + for i, vlanR := range list { + subnets := make([]map[string]interface{}, len(vlanR.Subnets)) + for j, subnetR := range vlanR.Subnets { + subnet := make(map[string]interface{}) + subnet["id"] = subnetR.ID + subnet["cidr"] = subnetR.Cidr + subnet["is_byoip"] = subnetR.IsByOIP + subnet["is_public"] = subnetR.IsPublic + ips := make([]string, len(subnetR.Ips)) + for k, ip := range subnetR.Ips { + ips[k] = ip + } + subnet["ips"] = ips + subnets[j] = subnet + } + l := map[string]interface{}{ + "id": vlanR.ID, + "subnets": subnets, + } + vlans[i] = l + } + return vlans +} + +func FlattenIcdGroups(grouplist icdv4.GroupList) []map[string]interface{} { + groups := make([]map[string]interface{}, len(grouplist.Groups)) + for i, group := range grouplist.Groups { + memorys := make([]map[string]interface{}, 1) + memory := make(map[string]interface{}) + memory["units"] = group.Memory.Units + memory["allocation_mb"] = group.Memory.AllocationMb + memory["minimum_mb"] = group.Memory.MinimumMb + memory["step_size_mb"] = group.Memory.StepSizeMb + memory["is_adjustable"] = group.Memory.IsAdjustable + memory["can_scale_down"] = group.Memory.CanScaleDown + memorys[0] = memory + + cpus := make([]map[string]interface{}, 1) + cpu := make(map[string]interface{}) + cpu["units"] = group.Cpu.Units + cpu["allocation_count"] = group.Cpu.AllocationCount + cpu["minimum_count"] = group.Cpu.MinimumCount + cpu["step_size_count"] = group.Cpu.StepSizeCount + cpu["is_adjustable"] = group.Cpu.IsAdjustable + cpu["can_scale_down"] = group.Cpu.CanScaleDown + cpus[0] = cpu + + disks := make([]map[string]interface{}, 1) + disk := make(map[string]interface{}) + disk["units"] = group.Disk.Units + disk["allocation_mb"] = group.Disk.AllocationMb + disk["minimum_mb"] = group.Disk.MinimumMb + disk["step_size_mb"] = group.Disk.StepSizeMb + disk["is_adjustable"] = group.Disk.IsAdjustable + disk["can_scale_down"] = group.Disk.CanScaleDown + disks[0] = disk + + l := map[string]interface{}{ + "group_id": group.Id, + "count": group.Count, + "memory": memorys, + "cpu": cpus, + "disk": disks, + } + groups[i] = l + } + return groups +} + +func NormalizeJSONString(jsonString interface{}) (string, error) { + var j interface{} + if jsonString == nil || jsonString.(string) == "" { + return "", nil + } + s := jsonString.(string) + err := json.Unmarshal([]byte(s), &j) + if err != nil { + return s, err + } + bytes, err := json.Marshal(j) + if err != nil { + return "", err + } + return string(bytes[:]), nil +} + +func ExpandAnnotations(annotations string) (whisk.KeyValueArr, error) { + var result whisk.KeyValueArr + dc := json.NewDecoder(strings.NewReader(annotations)) + dc.UseNumber() + err := dc.Decode(&result) + return result, err +} + +func FlattenAnnotations(in whisk.KeyValueArr) (string, error) { + b, err := json.Marshal(in) + if err != nil { + return "", err + } + return string(b[:]), nil +} + +func ExpandParameters(annotations string) (whisk.KeyValueArr, error) { + var result whisk.KeyValueArr + dc := json.NewDecoder(strings.NewReader(annotations)) + dc.UseNumber() + err := dc.Decode(&result) + return result, err +} + +func FlattenParameters(in whisk.KeyValueArr) (string, error) { + b, err := json.Marshal(in) + if err != nil { + return "", err + } + return string(b[:]), nil +} + +func ExpandLimits(l []interface{}) *whisk.Limits { + if len(l) == 0 || l[0] == nil { + return &whisk.Limits{} + } + in := l[0].(map[string]interface{}) + obj := &whisk.Limits{ + Timeout: ptrToInt(in["timeout"].(int)), + Memory: ptrToInt(in["memory"].(int)), + Logsize: ptrToInt(in["log_size"].(int)), + } + return obj +} + +func FlattenActivityTrack(in *resourceconfigurationv1.ActivityTracking) []interface{} { + + att := make(map[string]interface{}) + if in != nil { + if in.ReadDataEvents != nil { + att["read_data_events"] = *in.ReadDataEvents + } + if in.WriteDataEvents != nil { + att["write_data_events"] = *in.WriteDataEvents + } + if in.ActivityTrackerCrn != nil { + att["activity_tracker_crn"] = *in.ActivityTrackerCrn + } + } + return []interface{}{att} +} + +func FlattenMetricsMonitor(in *resourceconfigurationv1.MetricsMonitoring) []interface{} { + att := make(map[string]interface{}) + if in != nil { + if in.UsageMetricsEnabled != nil { + att["usage_metrics_enabled"] = *in.UsageMetricsEnabled + } + if in.MetricsMonitoringCrn != nil { + att["metrics_monitoring_crn"] = *in.MetricsMonitoringCrn + } + if in.RequestMetricsEnabled != nil { + att["request_metrics_enabled"] = *in.RequestMetricsEnabled + } + } + return []interface{}{att} +} + +func ArchiveRuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + // Checking this is not an expire_rule. LifeCycle rules are either archive or expire or non current version or abort incomplete multipart upload + if r.Expiration == nil && r.NoncurrentVersionExpiration == nil && r.AbortIncompleteMultipartUpload == nil { + rule := make(map[string]interface{}) + + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + + for _, transition := range r.Transitions { + if transition.Days != nil { + rule["days"] = int(*transition.Days) + } + if transition.StorageClass != nil { + rule["type"] = *transition.StorageClass + } + } + + rules = append(rules, rule) + } + } + return rules +} + +func ExpireRuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + if r.Expiration != nil && r.Transitions == nil { + rule := make(map[string]interface{}) + + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + + if r.Expiration != nil { + if r.Expiration.Days != nil { + days := int(*(r.Expiration).Days) + if days > 0 { + rule["days"] = days + } + } + if r.Expiration.Date != nil { + expirationTime := *(r.Expiration).Date + d := strings.Split(expirationTime.Format(time.RFC3339), "T") + rule["date"] = d[0] + } + + if r.Expiration.ExpiredObjectDeleteMarker != nil { + rule["expired_object_delete_marker"] = *(r.Expiration).ExpiredObjectDeleteMarker + } + } + if r.Filter != nil && r.Filter.Prefix != nil { + rule["prefix"] = *(r.Filter).Prefix + } + + rules = append(rules, rule) + } + } + + return rules + +} + +func Nc_exp_RuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + if r.Expiration == nil && r.AbortIncompleteMultipartUpload == nil && r.Transitions == nil { + rule := make(map[string]interface{}) + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + if r.NoncurrentVersionExpiration != nil { + rule["noncurrent_days"] = int(*(r.NoncurrentVersionExpiration).NoncurrentDays) + } + if r.Filter != nil && r.Filter.Prefix != nil { + rule["prefix"] = *(r.Filter).Prefix + } + rules = append(rules, rule) + } + } + return rules +} + +func Abort_mpu_RuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + if r.Expiration == nil && r.NoncurrentVersionExpiration == nil && r.Transitions == nil { + rule := make(map[string]interface{}) + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + if r.AbortIncompleteMultipartUpload != nil { + rule["days_after_initiation"] = int(*(r.AbortIncompleteMultipartUpload).DaysAfterInitiation) + } + if r.Filter != nil && r.Filter.Prefix != nil { + rule["prefix"] = *(r.Filter).Prefix + } + rules = append(rules, rule) + } + } + return rules +} + +func RetentionRuleGet(in *s3.ProtectionConfiguration) []interface{} { + rules := make([]interface{}, 0, 1) + if in != nil && in.Status != nil && *in.Status == "COMPLIANCE" { + protectConfig := make(map[string]interface{}) + if in.DefaultRetention != nil { + protectConfig["default"] = int(*(in.DefaultRetention).Days) + } + if in.MaximumRetention != nil { + protectConfig["maximum"] = int(*(in.MaximumRetention).Days) + } + if in.MinimumRetention != nil { + protectConfig["minimum"] = int(*(in.MinimumRetention).Days) + } + if in.EnablePermanentRetention != nil { + protectConfig["permanent"] = *in.EnablePermanentRetention + } + rules = append(rules, protectConfig) + } + return rules +} + +func FlattenCosObejctVersioning(in *s3.GetBucketVersioningOutput) []interface{} { + versioning := make([]interface{}, 0, 1) + if in != nil { + if in.Status != nil { + att := make(map[string]interface{}) + if *in.Status == "Enabled" { + att["enable"] = true + } else { + att["enable"] = false + } + versioning = append(versioning, att) + } + } + return versioning +} + +func ReplicationRuleGet(in *s3.ReplicationConfiguration) []map[string]interface{} { + rules := make([]map[string]interface{}, 0, 1) + if in != nil { + for _, replicaterule := range in.Rules { + replicationConfig := make(map[string]interface{}) + if replicaterule.DeleteMarkerReplication != nil { + if *(replicaterule.DeleteMarkerReplication).Status == "Enabled" { + replicationConfig["deletemarker_replication_status"] = true + } else { + replicationConfig["deletemarker_replication_status"] = false + } + } + if replicaterule.Destination != nil { + replicationConfig["destination_bucket_crn"] = *(replicaterule.Destination).Bucket + } + if replicaterule.ID != nil { + replicationConfig["rule_id"] = *replicaterule.ID + } + if replicaterule.Priority != nil { + replicationConfig["priority"] = int(*replicaterule.Priority) + } + if replicaterule.Status != nil { + if *replicaterule.Status == "Enabled" { + replicationConfig["enable"] = true + } else { + replicationConfig["enable"] = false + } + } + if replicaterule.Filter != nil && replicaterule.Filter.Prefix != nil { + replicationConfig["prefix"] = *(replicaterule.Filter).Prefix + } + rules = append(rules, replicationConfig) + } + } + return rules +} + +func FlattenLimits(in *whisk.Limits) []interface{} { + att := make(map[string]interface{}) + if in.Timeout != nil { + att["timeout"] = *in.Timeout + } + if in.Memory != nil { + att["memory"] = *in.Memory + } + if in.Memory != nil { + att["log_size"] = *in.Logsize + } + return []interface{}{att} +} + +func ExpandExec(execs []interface{}) *whisk.Exec { + var code string + var document []byte + for _, exec := range execs { + e, _ := exec.(map[string]interface{}) + code_path := e["code_path"].(string) + if code_path != "" { + ext := path.Ext(code_path) + if strings.ToLower(ext) == ".zip" { + data, err := ioutil.ReadFile(code_path) + if err != nil { + log.Println("Error reading file", err) + return &whisk.Exec{} + } + sEnc := b64.StdEncoding.EncodeToString([]byte(data)) + code = sEnc + } else { + data, err := ioutil.ReadFile(code_path) + if err != nil { + log.Println("Error reading file", err) + return &whisk.Exec{} + } + document = data + code = string(document) + } + } else { + code = e["code"].(string) + } + obj := &whisk.Exec{ + Image: e["image"].(string), + Init: e["init"].(string), + Code: PtrToString(code), + Kind: e["kind"].(string), + Main: e["main"].(string), + Components: ExpandStringList(e["components"].([]interface{})), + } + return obj + } + + return &whisk.Exec{} +} + +func FlattenExec(in *whisk.Exec, d *schema.ResourceData) []interface{} { + code_data := 4194304 // length of 'code' parameter should be always <= 4MB data + att := make(map[string]interface{}) + // open-whisk SDK will not return the value for code_path + // Hence using d.GetOk method to setback the code_path value. + if cPath, ok := d.GetOk("exec.0.code_path"); ok { + att["code_path"] = cPath.(string) + } + if in.Image != "" { + att["image"] = in.Image + } + if in.Init != "" { + att["init"] = in.Init + } + if in != nil && in.Code != nil && len(*in.Code) <= code_data { + att["code"] = *in.Code + } + if in.Kind != "" { + att["kind"] = in.Kind + } + if in.Main != "" { + att["main"] = in.Main + } + + if len(in.Components) > 0 { + att["components"] = FlattenStringList(in.Components) + } + + return []interface{}{att} +} + +func ptrToInt(i int) *int { + return &i +} + +func PtrToString(s string) *string { + return &s +} + +func IntValue(i64 *int64) (i int) { + if i64 != nil { + i = int(*i64) + } + return +} + +func float64Value(f32 *float32) (f float64) { + if f32 != nil { + f = float64(*f32) + } + return +} + +func DateToString(d *strfmt.Date) (s string) { + if d != nil { + s = d.String() + } + return +} + +func DateTimeToString(dt *strfmt.DateTime) (s string) { + if dt != nil { + s = dt.String() + } + return +} + +func FilterActionAnnotations(in whisk.KeyValueArr) (string, error) { + noExec := make(whisk.KeyValueArr, 0, len(in)) + for _, v := range in { + if v.Key == "exec" { + continue + } + noExec = append(noExec, v) + } + + return FlattenAnnotations(noExec) +} + +func FilterActionParameters(in whisk.KeyValueArr) (string, error) { + noAction := make(whisk.KeyValueArr, 0, len(in)) + for _, v := range in { + if v.Key == "_actions" { + continue + } + noAction = append(noAction, v) + } + return FlattenParameters(noAction) +} + +func FilterInheritedAnnotations(inheritedAnnotations, annotations whisk.KeyValueArr) whisk.KeyValueArr { + userDefinedAnnotations := make(whisk.KeyValueArr, 0) + for _, a := range annotations { + insert := false + if a.Key == "binding" || a.Key == "exec" { + insert = false + break + } + for _, b := range inheritedAnnotations { + if a.Key == b.Key && reflect.DeepEqual(a.Value, b.Value) { + insert = false + break + } + insert = true + } + if insert { + userDefinedAnnotations = append(userDefinedAnnotations, a) + } + } + return userDefinedAnnotations +} + +func FilterInheritedParameters(inheritedParameters, parameters whisk.KeyValueArr) whisk.KeyValueArr { + userDefinedParameters := make(whisk.KeyValueArr, 0) + for _, p := range parameters { + insert := false + if p.Key == "_actions" { + insert = false + break + } + for _, b := range inheritedParameters { + if p.Key == b.Key && reflect.DeepEqual(p.Value, b.Value) { + insert = false + break + } + insert = true + } + if insert { + userDefinedParameters = append(userDefinedParameters, p) + } + + } + return userDefinedParameters +} + +func IsEmpty(object interface{}) bool { + //First check normal definitions of empty + if object == nil { + return true + } else if object == "" { + return true + } else if object == false { + return true + } + + //Then see if it's a struct + if reflect.ValueOf(object).Kind() == reflect.Struct { + // and create an empty copy of the struct object to compare against + empty := reflect.New(reflect.TypeOf(object)).Elem().Interface() + if reflect.DeepEqual(object, empty) { + return true + } + } + return false +} + +func FilterTriggerAnnotations(in whisk.KeyValueArr) (string, error) { + noFeed := make(whisk.KeyValueArr, 0, len(in)) + for _, v := range in { + if v.Key == "feed" { + continue + } + noFeed = append(noFeed, v) + } + return FlattenParameters(noFeed) +} + +func FlattenFeed(feedName string) []interface{} { + att := make(map[string]interface{}) + att["name"] = feedName + att["parameters"] = "[]" + return []interface{}{att} +} + +func FlattenGatewayVlans(list []datatypes.Network_Gateway_Vlan) []map[string]interface{} { + vlans := make([]map[string]interface{}, len(list)) + for i, ele := range list { + vlan := make(map[string]interface{}) + vlan["bypass"] = *ele.BypassFlag + vlan["network_vlan_id"] = *ele.NetworkVlanId + vlan["vlan_id"] = *ele.Id + vlans[i] = vlan + } + return vlans +} + +func FlattenGatewayMembers(d *schema.ResourceData, list []datatypes.Network_Gateway_Member) []map[string]interface{} { + members := make([]map[string]interface{}, len(list)) + for i, ele := range list { + hardware := *ele.Hardware + member := make(map[string]interface{}) + member["member_id"] = *ele.HardwareId + member["hostname"] = *hardware.Hostname + member["domain"] = *hardware.Domain + if hardware.Notes != nil { + member["notes"] = *hardware.Notes + } + if hardware.Datacenter != nil { + member["datacenter"] = *hardware.Datacenter.Name + } + if hardware.PrimaryNetworkComponent.MaxSpeed != nil { + member["network_speed"] = *hardware.PrimaryNetworkComponent.MaxSpeed + } + member["redundant_network"] = false + member["unbonded_network"] = false + backendNetworkComponent := ele.Hardware.BackendNetworkComponents + + if len(backendNetworkComponent) > 2 && ele.Hardware.PrimaryBackendNetworkComponent != nil { + if *hardware.PrimaryBackendNetworkComponent.RedundancyEnabledFlag { + member["redundant_network"] = true + } else { + member["unbonded_network"] = true + } + } + tagReferences := ele.Hardware.TagReferences + tagReferencesLen := len(tagReferences) + if tagReferencesLen > 0 { + tags := make([]interface{}, 0, tagReferencesLen) + for _, tagRef := range tagReferences { + tags = append(tags, *tagRef.Tag.Name) + } + member["tags"] = schema.NewSet(schema.HashString, tags) + } + + member["redundant_power_supply"] = false + + if *hardware.PowerSupplyCount == 2 { + member["redundant_power_supply"] = true + } + member["memory"] = *hardware.MemoryCapacity + if !(*hardware.PrivateNetworkOnlyFlag) { + member["public_vlan_id"] = *hardware.NetworkVlans[1].Id + } + member["private_vlan_id"] = *hardware.NetworkVlans[0].Id + + if hardware.PrimaryIpAddress != nil { + member["public_ipv4_address"] = *hardware.PrimaryIpAddress + } + if hardware.PrimaryBackendIpAddress != nil { + member["private_ipv4_address"] = *hardware.PrimaryBackendIpAddress + } + member["ipv6_enabled"] = false + if ele.Hardware.PrimaryNetworkComponent.PrimaryVersion6IpAddressRecord != nil { + member["ipv6_enabled"] = true + member["ipv6_address"] = *hardware.PrimaryNetworkComponent.PrimaryVersion6IpAddressRecord.IpAddress + } + + member["private_network_only"] = *hardware.PrivateNetworkOnlyFlag + userData := hardware.UserData + if len(userData) > 0 && userData[0].Value != nil { + member["user_metadata"] = *userData[0].Value + } + members[i] = member + } + return members +} + +func FlattenDisks(result datatypes.Virtual_Guest) []int { + var out = make([]int, 0) + + for _, v := range result.BlockDevices { + // skip 1,7 which is reserved for the swap disk and metadata + _, ok := sl.GrabOk(result, "BillingItem.OrderItem.Preset") + if ok { + if *v.Device != "1" && *v.Device != "7" && *v.Device != "0" { + capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") + + if ok { + out = append(out, capacity.(int)) + } + + } + } else { + if *v.Device != "1" && *v.Device != "7" { + capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") + + if ok { + out = append(out, capacity.(int)) + } + } + } + } + + return out +} + +func FlattenDisksForWindows(result datatypes.Virtual_Guest) []int { + var out = make([]int, 0) + + for _, v := range result.BlockDevices { + // skip 1,7 which is reserved for the swap disk and metadata + _, ok := sl.GrabOk(result, "BillingItem.OrderItem.Preset") + if ok { + if *v.Device != "1" && *v.Device != "7" && *v.Device != "0" && *v.Device != "3" { + capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") + + if ok { + out = append(out, capacity.(int)) + } + } + } else { + if *v.Device != "1" && *v.Device != "7" && *v.Device != "3" { + capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") + + if ok { + out = append(out, capacity.(int)) + } + } + } + } + + return out +} + +func filterResourceKeyParameters(params map[string]interface{}) map[string]interface{} { + delete(params, "role_crn") + return params +} + +func IdParts(id string) ([]string, error) { + if strings.Contains(id, "/") { + parts := strings.Split(id, "/") + return parts, nil + } + return []string{}, fmt.Errorf("The given id %s does not contain / please check documentation on how to provider id during import command", id) +} + +func SepIdParts(id string, separator string) ([]string, error) { + if strings.Contains(id, separator) { + parts := strings.Split(id, separator) + return parts, nil + } + return []string{}, fmt.Errorf("The given id %s does not contain %s please check documentation on how to provider id during import command", id, separator) +} + +func VmIdParts(id string) ([]string, error) { + parts := strings.Split(id, "/") + return parts, nil +} + +func CfIdParts(id string) ([]string, error) { + parts := strings.Split(id, ":") + return parts, nil +} + +// getCustomAttributes will return all attributes which are not system defined +func getCustomAttributes(r iampolicymanagementv1.PolicyResource) []iampolicymanagementv1.ResourceAttribute { + attributes := []iampolicymanagementv1.ResourceAttribute{} + for _, a := range r.Attributes { + switch *a.Name { + case "accesGroupId": + case "accountId": + case "organizationId": + case "spaceId": + case "region": + case "resource": + case "resourceType": + case "resourceGroupId": + case "serviceType": + case "serviceName": + case "serviceInstance": + default: + attributes = append(attributes, a) + } + } + return attributes +} + +func FlattenPolicyResource(list []iampolicymanagementv1.PolicyResource) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + "service": GetResourceAttribute("serviceName", i), + "resource_instance_id": GetResourceAttribute("serviceInstance", i), + "region": GetResourceAttribute("region", i), + "resource_type": GetResourceAttribute("resourceType", i), + "resource": GetResourceAttribute("resource", i), + "resource_group_id": GetResourceAttribute("resourceGroupId", i), + "service_type": GetResourceAttribute("serviceType", i), + } + customAttributes := getCustomAttributes(i) + if len(customAttributes) > 0 { + out := make(map[string]string) + for _, a := range customAttributes { + out[*a.Name] = *a.Value + } + l["attributes"] = out + } + + result = append(result, l) + } + return result +} +func FlattenPolicyResourceAttributes(list []iampolicymanagementv1.PolicyResource) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + for _, i := range list { + for _, a := range i.Attributes { + if *a.Name != "accountId" { + l := map[string]interface{}{ + "name": a.Name, + "value": a.Value, + "operator": a.Operator, + } + result = append(result, l) + } + } + } + return result +} + +func FlattenPolicyResourceTags(resources []iampolicymanagementv1.PolicyResource) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + + for _, resource := range resources { + if resource.Tags != nil { + for _, tags := range resource.Tags { + tag := map[string]interface{}{ + "name": tags.Name, + "value": tags.Value, + "operator": tags.Operator, + } + result = append(result, tag) + } + } + } + return result +} + +// Cloud Internet Services +func FlattenHealthMonitors(list []datatypes.Network_LBaaS_Listener) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + ports := make([]int, 0, 0) + for _, i := range list { + l := map[string]interface{}{ + "protocol": *i.DefaultPool.Protocol, + "port": *i.DefaultPool.ProtocolPort, + "interval": *i.DefaultPool.HealthMonitor.Interval, + "max_retries": *i.DefaultPool.HealthMonitor.MaxRetries, + "timeout": *i.DefaultPool.HealthMonitor.Timeout, + "monitor_id": *i.DefaultPool.HealthMonitor.Uuid, + } + + if i.DefaultPool.HealthMonitor.UrlPath != nil { + l["url_path"] = *i.DefaultPool.HealthMonitor.UrlPath + } + + if !contains(ports, *i.DefaultPool.ProtocolPort) { + result = append(result, l) + } + + ports = append(ports, *i.DefaultPool.ProtocolPort) + } + return result +} + +func contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} +func StringContains(s []string, str string) bool { + for _, a := range s { + if a == str { + return true + } + } + return false +} + +func FlattenMembersData(list []iamaccessgroupsv2.ListGroupMembersResponseMember, users []usermanagementv2.UserInfo, serviceids []iamidentityv1.ServiceID, profileids []iamidentityv1.TrustedProfile) ([]string, []string, []string) { + var ibmid []string + var serviceid []string + var profileid []string + for _, m := range list { + if *m.Type == "user" { + for _, user := range users { + if user.IamID == *m.IamID { + ibmid = append(ibmid, user.Email) + break + } + } + } else if *m.Type == "profile" { + for _, prid := range profileids { + if *prid.IamID == *m.IamID { + profileid = append(profileid, *prid.ID) + break + } + } + } else { + for _, srid := range serviceids { + if *srid.IamID == *m.IamID { + serviceid = append(serviceid, *srid.ID) + break + } + } + } + + } + return ibmid, serviceid, profileid +} + +func FlattenAccessGroupMembers(list []iamaccessgroupsv2.ListGroupMembersResponseMember, users []usermanagementv2.UserInfo, serviceids []iamidentityv1.ServiceID) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, m := range list { + var value, vtype string + vtype = *m.Type + if *m.Type == "user" { + for _, user := range users { + if user.IamID == *m.IamID { + value = user.Email + break + } + } + } else { + for _, srid := range serviceids { + if *srid.IamID == *m.IamID { + value = *srid.ID + break + } + } + + } + l := map[string]interface{}{ + "iam_id": value, + "type": vtype, + } + result = append(result, l) + } + return result +} + +func FlattenUserIds(accountID string, users []string, meta interface{}) ([]string, error) { + userids := make([]string, len(users)) + for i, name := range users { + iamID, err := GetIBMUniqueId(accountID, name, meta) + if err != nil { + return nil, err + } + userids[i] = iamID + } + return userids, nil +} + +func ExpandUsers(userList *schema.Set) (users []icdv4.User) { + for _, iface := range userList.List() { + userEl := iface.(map[string]interface{}) + user := icdv4.User{ + UserName: userEl["name"].(string), + Password: userEl["password"].(string), + } + users = append(users, user) + } + return +} + +type CsEntry struct { + Name string + Password string + String string + Composed string + CertName string + CertBase64 string + Hosts []struct { + HostName string `json:"hostname"` + Port int `json:"port"` + } + Scheme string + QueryOptions map[string]interface{} + Path string + Database string + BundleName string + BundleBase64 string +} + +// IBM Cloud Databases +func FlattenConnectionStrings(cs []CsEntry) []map[string]interface{} { + entries := make([]map[string]interface{}, len(cs), len(cs)) + for i, csEntry := range cs { + l := map[string]interface{}{ + "name": csEntry.Name, + "password": csEntry.Password, + "composed": csEntry.Composed, + "certname": csEntry.CertName, + "certbase64": csEntry.CertBase64, + "queryoptions": csEntry.QueryOptions, + "scheme": csEntry.Scheme, + "path": csEntry.Path, + "database": csEntry.Database, + "bundlename": csEntry.BundleName, + "bundlebase64": csEntry.BundleBase64, + } + hosts := csEntry.Hosts + hostsList := make([]map[string]interface{}, len(hosts), len(hosts)) + for j, host := range hosts { + z := map[string]interface{}{ + "hostname": host.HostName, + "port": strconv.Itoa(host.Port), + } + hostsList[j] = z + } + l["hosts"] = hostsList + var queryOpts string + if len(csEntry.QueryOptions) != 0 { + queryOpts = "?" + count := 0 + for k, v := range csEntry.QueryOptions { + if count >= 1 { + queryOpts = queryOpts + "&" + } + queryOpts = queryOpts + fmt.Sprintf("%v", k) + "=" + fmt.Sprintf("%v", v) + count++ + } + } else { + queryOpts = "" + } + l["queryoptions"] = queryOpts + entries[i] = l + } + + return entries +} + +func FlattenPhaseOneAttributes(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { + phaseoneAttributesMap := make([]map[string]interface{}, 0, 1) + phaseoneAttributes := make(map[string]interface{}) + phaseoneAttributes["authentication"] = *vpn.PhaseOneAuthentication + phaseoneAttributes["encryption"] = *vpn.PhaseOneEncryption + phaseoneAttributes["diffie_hellman_group"] = *vpn.PhaseOneDiffieHellmanGroup + phaseoneAttributes["keylife"] = *vpn.PhaseOneKeylife + phaseoneAttributesMap = append(phaseoneAttributesMap, phaseoneAttributes) + return phaseoneAttributesMap +} + +func FlattenPhaseTwoAttributes(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { + phasetwoAttributesMap := make([]map[string]interface{}, 0, 1) + phasetwoAttributes := make(map[string]interface{}) + phasetwoAttributes["authentication"] = *vpn.PhaseTwoAuthentication + phasetwoAttributes["encryption"] = *vpn.PhaseTwoEncryption + phasetwoAttributes["diffie_hellman_group"] = *vpn.PhaseTwoDiffieHellmanGroup + phasetwoAttributes["keylife"] = *vpn.PhaseTwoKeylife + phasetwoAttributesMap = append(phasetwoAttributesMap, phasetwoAttributes) + return phasetwoAttributesMap +} + +func FlattenaddressTranslation(vpn *datatypes.Network_Tunnel_Module_Context, fwID int) []map[string]interface{} { + addressTranslationMap := make([]map[string]interface{}, 0, 1) + addressTranslationAttributes := make(map[string]interface{}) + for _, networkAddressTranslation := range vpn.AddressTranslations { + if *networkAddressTranslation.NetworkTunnelContext.Id == fwID { + addressTranslationAttributes["remote_ip_adress"] = *networkAddressTranslation.CustomerIpAddress + addressTranslationAttributes["internal_ip_adress"] = *networkAddressTranslation.InternalIpAddress + addressTranslationAttributes["notes"] = *networkAddressTranslation.Notes + } + } + addressTranslationMap = append(addressTranslationMap, addressTranslationAttributes) + return addressTranslationMap +} + +func FlattenremoteSubnet(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { + remoteSubnetMap := make([]map[string]interface{}, 0, 1) + remoteSubnetAttributes := make(map[string]interface{}) + for _, customerSubnet := range vpn.CustomerSubnets { + remoteSubnetAttributes["remote_ip_adress"] = customerSubnet.NetworkIdentifier + remoteSubnetAttributes["remote_ip_cidr"] = customerSubnet.Cidr + remoteSubnetAttributes["account_id"] = customerSubnet.AccountId + } + remoteSubnetMap = append(remoteSubnetMap, remoteSubnetAttributes) + return remoteSubnetMap +} + +// IBM Cloud Databases +func ExpandWhitelist(whiteList *schema.Set) (whitelist []icdv4.WhitelistEntry) { + for _, iface := range whiteList.List() { + wlItem := iface.(map[string]interface{}) + wlEntry := icdv4.WhitelistEntry{ + Address: wlItem["address"].(string), + Description: wlItem["description"].(string), + } + whitelist = append(whitelist, wlEntry) + } + return +} + +// Cloud Internet Services +func FlattenWhitelist(whitelist icdv4.Whitelist) []map[string]interface{} { + entries := make([]map[string]interface{}, len(whitelist.WhitelistEntrys), len(whitelist.WhitelistEntrys)) + for i, whitelistEntry := range whitelist.WhitelistEntrys { + l := map[string]interface{}{ + "address": whitelistEntry.Address, + "description": whitelistEntry.Description, + } + entries[i] = l + } + return entries +} + +func ExpandPlatformOptions(platformOptions icdv4.PlatformOptions) []map[string]interface{} { + pltOptions := make([]map[string]interface{}, 0, 1) + pltOption := make(map[string]interface{}) + pltOption["key_protect_key_id"] = platformOptions.KeyProtectKey + pltOption["disk_encryption_key_crn"] = platformOptions.DiskENcryptionKeyCrn + pltOption["backup_encryption_key_crn"] = platformOptions.BackUpEncryptionKeyCrn + pltOptions = append(pltOptions, pltOption) + return pltOptions +} + +func expandStringMap(inVal interface{}) map[string]string { + outVal := make(map[string]string) + if inVal == nil { + return outVal + } + for k, v := range inVal.(map[string]interface{}) { + strValue := fmt.Sprintf("%v", v) + outVal[k] = strValue + } + return outVal +} + +// Cloud Internet Services +func ConvertTfToCisThreeVar(glbTfId string) (glbId string, zoneId string, cisId string, err error) { + g := strings.SplitN(glbTfId, ":", 3) + glbId = g[0] + if len(g) > 2 { + zoneId = g[1] + cisId = g[2] + } else { + err = errors.New("cis_id or zone_id not passed") + return + } + return +} +func ConvertCisToTfFourVar(firewallType string, ID string, ID2 string, cisID string) (buildID string) { + if ID != "" { + buildID = firewallType + ":" + ID + ":" + ID2 + ":" + cisID + } else { + buildID = "" + } + return +} +func ConvertTfToCisFourVar(TfID string) (firewallType string, ID string, zoneID string, cisID string, err error) { + g := strings.SplitN(TfID, ":", 4) + firewallType = g[0] + if len(g) > 3 { + ID = g[1] + zoneID = g[2] + cisID = g[3] + } else { + err = errors.New("Id or cis_id or zone_id not passed") + return + } + return +} + +// Cloud Internet Services +func ConvertCisToTfThreeVar(Id string, Id2 string, cisId string) (buildId string) { + if Id != "" { + buildId = Id + ":" + Id2 + ":" + cisId + } else { + buildId = "" + } + return +} + +// Cloud Internet Services +func ConvertTfToCisTwoVarSlice(tfIds []string) (Ids []string, cisId string, err error) { + for _, item := range tfIds { + Id := strings.SplitN(item, ":", 2) + if len(Id) < 2 { + err = errors.New("cis_id not passed") + return + } + Ids = append(Ids, Id[0]) + cisId = Id[1] + } + return +} + +// Cloud Internet Services +func ConvertCisToTfTwoVarSlice(Ids []string, cisId string) (buildIds []string) { + for _, Id := range Ids { + buildIds = append(buildIds, Id+":"+cisId) + } + return +} + +// Cloud Internet Services +func ConvertCisToTfTwoVar(Id string, cisId string) (buildId string) { + if Id != "" { + buildId = Id + ":" + cisId + } else { + buildId = "" + } + return +} + +// Cloud Internet Services +func ConvertTftoCisTwoVar(tfId string) (Id string, cisId string, err error) { + g := strings.SplitN(tfId, ":", 2) + Id = g[0] + if len(g) > 1 { + cisId = g[1] + } else { + err = errors.New(" cis_id or zone_id not passed") + return + } + return +} +func stringInSlice(str string, list []string) bool { + for _, v := range list { + if v == str { + return true + } + } + return false +} + +var dnsTypeIntFields = []string{ + "algorithm", + "key_tag", + "type", + "usage", + "selector", + "matching_type", + "weight", + "priority", + "port", + "long_degrees", + "lat_degrees", + "long_minutes", + "lat_minutes", + "protocol", + "digest_type", + "order", + "preference", +} + +var dnsTypeFloatFields = []string{ + "size", + "altitude", + "precision_horz", + "precision_vert", + "long_seconds", + "lat_seconds", +} + +// Cloud Internet Services +func TransformToIBMCISDnsData(recordType string, id string, value interface{}) (newValue interface{}, err error) { + switch { + case id == "flags": + switch { + case strings.ToUpper(recordType) == "SRV", + strings.ToUpper(recordType) == "CAA", + strings.ToUpper(recordType) == "DNSKEY": + newValue, err = strconv.Atoi(value.(string)) + case strings.ToUpper(recordType) == "NAPTR": + newValue, err = value.(string), nil + } + case stringInSlice(id, dnsTypeIntFields): + newValue, err = strconv.Atoi(value.(string)) + case stringInSlice(id, dnsTypeFloatFields): + newValue, err = strconv.ParseFloat(value.(string), 32) + default: + newValue, err = value.(string), nil + } + + return +} + +func IndexOf(element string, data []string) int { + for k, v := range data { + if element == v { + return k + } + } + return -1 //not found. +} + +func rcInstanceExists(resourceId string, resourceType string, meta interface{}) (bool, error) { + // Check to see if Resource Manager instance exists + rsConClient, err := meta.(conns.ClientSession).ResourceControllerAPI() + if err != nil { + return true, nil + } + exists := true + instance, err := rsConClient.ResourceServiceInstance().GetInstance(resourceId) + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + exists = false + } else { + return true, fmt.Errorf("[ERROR] Error checking resource instance exists: %s", err) + } + } else { + if strings.Contains(instance.State, "removed") { + exists = false + } + } + if exists { + return true, nil + } + // Implement when pointer to terraform.State available + // If rcInstance is now in removed state, set TF state to removed + // s := *terraform.State + // for _, r := range s.RootModule().Resources { + // if r.Type != resourceType { + // continue + // } + // if r.Primary.ID == resourceId { + // r.Primary.Set("status", "removed") + // } + // } + return false, nil +} + +// Implement when pointer to terraform.State available +// func resourceInstanceExistsTf(resourceId string, resourceType string) bool { +// // Check TF state to see if Cloud resource instance has already been removed +// s := *terraform.State +// for _, r := range s.RootModule().Resources { +// if r.Type != resourceType { +// continue +// } +// if r.Primary.ID == resourceId { +// if strings.Contains(r.Primary.Attributes["status"], "removed") { +// return false +// } +// } +// } +// return true +// } + +// convert CRN to be url safe +func EscapeUrlParm(urlParm string) string { + if strings.Contains(urlParm, "/") { + newUrlParm := url.PathEscape(urlParm) + return newUrlParm + } + return urlParm +} +func GetLocation(instance models.ServiceInstanceV2) string { + region := instance.Crn.Region + cName := instance.Crn.CName + if cName == "bluemix" || cName == "staging" { + return region + } else { + return cName + "-" + region + } +} + +func GetTags(d *schema.ResourceData, meta interface{}) error { + resourceID := d.Id() + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPI() + if err != nil { + return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + taggingResult, err := gtClient.Tags().GetTags(resourceID) + if err != nil { + return err + } + var taglist []string + for _, item := range taggingResult.Items { + taglist = append(taglist, item.Name) + } + d.Set("tags", FlattenStringList(taglist)) + return nil +} + +// func UpdateTags(d *schema.ResourceData, meta interface{}) error { +// resourceID := d.Id() +// gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPI() +// if err != nil { +// return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) +// } +// oldList, newList := d.GetChange("tags") +// if oldList == nil { +// oldList = new(schema.Set) +// } +// if newList == nil { +// newList = new(schema.Set) +// } +// olds := oldList.(*schema.Set) +// news := newList.(*schema.Set) +// removeInt := olds.Difference(news).List() +// addInt := news.Difference(olds).List() +// add := make([]string, len(addInt)) +// for i, v := range addInt { +// add[i] = fmt.Sprint(v) +// } +// remove := make([]string, len(removeInt)) +// for i, v := range removeInt { +// remove[i] = fmt.Sprint(v) +// } + +// if len(add) > 0 { +// _, err := gtClient.Tags().AttachTags(resourceID, add) +// if err != nil { +// return fmt.Errorf("[ERROR] Error updating database tags %v : %s", add, err) +// } +// } +// if len(remove) > 0 { +// _, err := gtClient.Tags().DetachTags(resourceID, remove) +// if err != nil { +// return fmt.Errorf("[ERROR] Error detaching database tags %v: %s", remove, err) +// } +// for _, v := range remove { +// _, err := gtClient.Tags().DeleteTag(v) +// if err != nil { +// return fmt.Errorf("[ERROR] Error deleting database tag %v: %s", v, err) +// } +// } +// } +// return nil +// } + +func GetGlobalTagsUsingCRN(meta interface{}, resourceID, resourceType, tagType string) (*schema.Set, error) { + + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() + if err != nil { + return nil, fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return nil, err + } + accountID := userDetails.UserAccount + + var providers []string + if strings.Contains(resourceType, "SoftLayer_") { + providers = []string{"ims"} + } + + ListTagsOptions := &globaltaggingv1.ListTagsOptions{} + if resourceID != "" { + ListTagsOptions.AttachedTo = &resourceID + } + ListTagsOptions.Providers = providers + if len(tagType) > 0 { + ListTagsOptions.TagType = PtrToString(tagType) + + if tagType == "service" { + ListTagsOptions.AccountID = PtrToString(accountID) + } + } + taggingResult, _, err := gtClient.ListTags(ListTagsOptions) + if err != nil { + return nil, err + } + var taglist []string + for _, item := range taggingResult.Items { + taglist = append(taglist, *item.Name) + } + log.Println("tagList: ", taglist) + return NewStringSet(ResourceIBMVPCHash, taglist), nil +} + +func UpdateGlobalTagsUsingCRN(oldList, newList interface{}, meta interface{}, resourceID, resourceType, tagType string) error { + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() + if err != nil { + return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + acctID := userDetails.UserAccount + + resources := []globaltaggingv1.Resource{} + r := globaltaggingv1.Resource{ResourceID: PtrToString(resourceID), ResourceType: PtrToString(resourceType)} + resources = append(resources, r) + + if oldList == nil { + oldList = new(schema.Set) + } + if newList == nil { + newList = new(schema.Set) + } + olds := oldList.(*schema.Set) + news := newList.(*schema.Set) + removeInt := olds.Difference(news).List() + addInt := news.Difference(olds).List() + add := make([]string, len(addInt)) + for i, v := range addInt { + add[i] = fmt.Sprint(v) + } + remove := make([]string, len(removeInt)) + for i, v := range removeInt { + remove[i] = fmt.Sprint(v) + } + + if strings.TrimSpace(tagType) == "" || tagType == "user" { + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + add = append(add, envTags...) + } + } + + if len(remove) > 0 { + detachTagOptions := &globaltaggingv1.DetachTagOptions{} + detachTagOptions.Resources = resources + detachTagOptions.TagNames = remove + if len(tagType) > 0 { + detachTagOptions.TagType = PtrToString(tagType) + if tagType == "service" { + detachTagOptions.AccountID = PtrToString(acctID) + } + } + + _, resp, err := gtClient.DetachTag(detachTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error detaching database tags %v: %s\n%s", remove, err, resp) + } + for _, v := range remove { + delTagOptions := &globaltaggingv1.DeleteTagOptions{ + TagName: PtrToString(v), + } + _, resp, err := gtClient.DeleteTag(delTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting database tag %v: %s\n%s", v, err, resp) + } + } + } + + if len(add) > 0 { + AttachTagOptions := &globaltaggingv1.AttachTagOptions{} + AttachTagOptions.Resources = resources + AttachTagOptions.TagNames = add + if len(tagType) > 0 { + AttachTagOptions.TagType = PtrToString(tagType) + if tagType == "service" { + AttachTagOptions.AccountID = PtrToString(acctID) + } + } + + _, resp, err := gtClient.AttachTag(AttachTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating database tags %v : %s\n%s", add, err, resp) + } + } + + return nil +} + +func ResourceIBMVPCHash(v interface{}) int { + var buf bytes.Buffer + buf.WriteString(fmt.Sprintf("%s", + strings.ToLower(v.(string)))) + return conns.String(buf.String()) +} + +// Use this function for attributes which only should be applied in resource creation time. +func ApplyOnce(k, o, n string, d *schema.ResourceData) bool { + if len(d.Id()) == 0 { + return false + } + return true +} +func GetTagsUsingCRN(meta interface{}, resourceCRN string) (*schema.Set, error) { + + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPI() + if err != nil { + return nil, fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + taggingResult, err := gtClient.Tags().GetTags(resourceCRN) + if err != nil { + return nil, err + } + var taglist []string + for _, item := range taggingResult.Items { + taglist = append(taglist, item.Name) + } + log.Println("tagList: ", taglist) + return NewStringSet(ResourceIBMVPCHash, taglist), nil +} + +func UpdateTagsUsingCRN(oldList, newList interface{}, meta interface{}, resourceCRN string) error { + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPI() + if err != nil { + return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + if oldList == nil { + oldList = new(schema.Set) + } + if newList == nil { + newList = new(schema.Set) + } + olds := oldList.(*schema.Set) + news := newList.(*schema.Set) + removeInt := olds.Difference(news).List() + addInt := news.Difference(olds).List() + add := make([]string, len(addInt)) + for i, v := range addInt { + add[i] = fmt.Sprint(v) + } + remove := make([]string, len(removeInt)) + for i, v := range removeInt { + remove[i] = fmt.Sprint(v) + } + + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + add = append(add, envTags...) + } + + if len(remove) > 0 { + _, err := gtClient.Tags().DetachTags(resourceCRN, remove) + if err != nil { + return fmt.Errorf("[ERROR] Error detaching database tags %v: %s", remove, err) + } + for _, v := range remove { + _, err := gtClient.Tags().DeleteTag(v) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting database tag %v: %s", v, err) + } + } + } + + if len(add) > 0 { + _, err := gtClient.Tags().AttachTags(resourceCRN, add) + if err != nil { + return fmt.Errorf("[ERROR] Error updating database tags %v : %s", add, err) + } + } + + return nil +} + +func GetBaseController(meta interface{}) (string, error) { + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return "", err + } + if userDetails != nil && userDetails.CloudName == "staging" { + return stageBaseController, nil + } + return prodBaseController, nil +} + +func FlattenSSLCiphers(ciphers []datatypes.Network_LBaaS_SSLCipher) *schema.Set { + c := make([]string, len(ciphers)) + for i, v := range ciphers { + c[i] = *v.Name + } + return NewStringSet(schema.HashString, c) +} + +func ResourceTagsCustomizeDiff(diff *schema.ResourceDiff) error { + + if diff.Id() != "" && diff.HasChange("tags") { + o, n := diff.GetChange("tags") + oldSet := o.(*schema.Set) + newSet := n.(*schema.Set) + removeInt := oldSet.Difference(newSet).List() + addInt := newSet.Difference(oldSet).List() + if v := os.Getenv("IC_ENV_TAGS"); v != "" { + s := strings.Split(v, ",") + if len(removeInt) == len(s) && len(addInt) == 0 { + fmt.Println("Suppresing the TAG diff ") + return diff.Clear("tags") + } + } + } + return nil +} + +func ResourceLBListenerPolicyCustomizeDiff(diff *schema.ResourceDiff) error { + policyActionIntf, _ := diff.GetOk(isLBListenerPolicyAction) + policyAction := policyActionIntf.(string) + + if policyAction == "forward" { + _, policyTargetIDSet := diff.GetOk(isLBListenerPolicyTargetID) + + if !policyTargetIDSet && diff.NewValueKnown(isLBListenerPolicyTargetID) { + return fmt.Errorf("Load balancer listener policy: When action is forward please specify target_id") + } + } else if policyAction == "redirect" { + _, httpsStatusCodeSet := diff.GetOk(isLBListenerPolicyTargetHTTPStatusCode) + _, targetURLSet := diff.GetOk(isLBListenerPolicyTargetURL) + + if !httpsStatusCodeSet && diff.NewValueKnown(isLBListenerPolicyTargetHTTPStatusCode) { + return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_http_status_code") + } + + if !targetURLSet && diff.NewValueKnown(isLBListenerPolicyTargetURL) { + return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_url") + } + } else if policyAction == "https_redirect" { + _, listenerSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectListener) + _, httpsStatusSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectStatusCode) + + if !listenerSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectListener) { + return fmt.Errorf("Load balancer listener policy: When action is https_redirect please specify target_https_redirect_listener") + } + + if !httpsStatusSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectStatusCode) { + return fmt.Errorf("When action is https_redirect please specify target_https_redirect_status_code") + } + } + + return nil +} + +func ResourceIBMISLBPoolCookieValidate(diff *schema.ResourceDiff) error { + _, sessionPersistenceTypeIntf := diff.GetChange(isLBPoolSessPersistenceType) + _, sessionPersistenceCookieNameIntf := diff.GetChange(isLBPoolSessPersistenceAppCookieName) + sessionPersistenceType := sessionPersistenceTypeIntf.(string) + sessionPersistenceCookieName := sessionPersistenceCookieNameIntf.(string) + + if sessionPersistenceType == "app_cookie" { + if sessionPersistenceCookieName == "" { + return fmt.Errorf("Load Balancer Pool: %s is required for %s 'app_cookie'", isLBPoolSessPersistenceAppCookieName, isLBPoolSessPersistenceType) + } + if strings.HasPrefix(sessionPersistenceCookieName, "IBM") { + return fmt.Errorf("Load Balancer Pool: %s starting with IBM are not allowed", isLBPoolSessPersistenceAppCookieName) + } + } + + if sessionPersistenceCookieName != "" && sessionPersistenceType != "app_cookie" { + return fmt.Errorf("Load Balancer Pool: %s is only applicable for %s 'app_cookie'.", isLBPoolSessPersistenceAppCookieName, isLBPoolSessPersistenceType) + } + return nil +} + +func ResourceVolumeAttachmentValidate(diff *schema.ResourceDiff) error { + + if volsintf, ok := diff.GetOk("volume_attachments"); ok { + vols := volsintf.([]interface{}) + for volAttIdx := range vols { + volumeid := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + "volume" + volumePrototype := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + "volume_prototype" + var volIdnterpolated = false + var volumeIdFound = false + if _, volumeIdFound = diff.GetOk(volumeid); !volumeIdFound { + if !diff.NewValueKnown(volumeid) { + volIdnterpolated = true + } + } + _, volPrototypeFound := diff.GetOk(volumePrototype) + + if volPrototypeFound && (volumeIdFound || volIdnterpolated) { + return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Cannot provide both 'volume' and 'volume_prototype' together.", volAttIdx) + } + if !volPrototypeFound && !volumeIdFound && !volIdnterpolated { + return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Volume details missing. Provide either 'volume' or 'volume_prototype'.", volAttIdx) + } + } + } + + return nil +} + +func InstanceProfileValidate(diff *schema.ResourceDiff) error { + if diff.Id() != "" && diff.HasChange("profile") { + o, n := diff.GetChange("profile") + old := o.(string) + new := n.(string) + log.Println("old profile : ", old) + log.Println("new profile : ", new) + if !strings.Contains(old, "d") && strings.Contains(new, "d") { + diff.ForceNew("profile") + } else if strings.Contains(old, "d") && !strings.Contains(new, "d") { + diff.ForceNew("profile") + } + } + return nil +} + +func ResourceIPSecPolicyValidate(diff *schema.ResourceDiff) error { + + newEncAlgo := diff.Get("encryption_algorithm").(string) + newAuthAlgo := diff.Get("authentication_algorithm").(string) + if (newEncAlgo == "aes128gcm16" || newEncAlgo == "aes192gcm16" || newEncAlgo == "aes256gcm16") && newAuthAlgo != "disabled" { + return fmt.Errorf("authentication_algorithm must be set to 'disabled' when the encryption_algorithm is either one of 'aes128gcm16', 'aes192gcm16', 'aes256gcm16'") + } + + return nil +} + +func ResourceVolumeValidate(diff *schema.ResourceDiff) error { + + if diff.Id() != "" && diff.HasChange("capacity") { + o, n := diff.GetChange("capacity") + old := int64(o.(int)) + new := int64(n.(int)) + if new < old { + return fmt.Errorf("'%s' attribute has a constraint, it supports only expansion and can't be changed from %d to %d.", "capacity", old, new) + } + } + + profile := "" + var capacity, iops int64 + if profileOk, ok := diff.GetOk("profile"); ok { + profile = profileOk.(string) + } + if capacityOk, ok := diff.GetOk("capacity"); ok { + capacity = int64(capacityOk.(int)) + } + + if capacity == int64(0) { + capacity = int64(100) + } + if profile == "5iops-tier" && capacity > 9600 { + return fmt.Errorf("'%s' storage block supports capacity up to %d.", profile, 9600) + } else if profile == "10iops-tier" && capacity > 4800 { + return fmt.Errorf("'%s' storage block supports capacity up to %d.", profile, 4800) + } + + if iopsOk, ok := diff.GetOk("iops"); ok { + iops = int64(iopsOk.(int)) + } + + if diff.HasChange("profile") { + oldProfile, newProfile := diff.GetChange("profile") + if oldProfile.(string) == "custom" || newProfile.(string) == "custom" { + diff.ForceNew("profile") + } + } + + if profile != "custom" { + if iops != 0 && diff.NewValueKnown("iops") && diff.HasChange("iops") { + return fmt.Errorf("VolumeError : iops is applicable for only custom volume profiles") + } + } else { + if capacity == 0 { + capacity = int64(100) + } + if capacity >= 10 && capacity <= 39 { + min := int64(100) + max := int64(1000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 40 && capacity <= 79 { + min := int64(100) + max := int64(2000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 80 && capacity <= 99 { + min := int64(100) + max := int64(4000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 100 && capacity <= 499 { + min := int64(100) + max := int64(6000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 500 && capacity <= 999 { + min := int64(100) + max := int64(10000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 1000 && capacity <= 1999 { + min := int64(100) + max := int64(20000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 2000 && capacity <= 3999 { + min := int64(200) + max := int64(40000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 4000 && capacity <= 7999 { + min := int64(300) + max := int64(40000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 8000 && capacity <= 9999 { + min := int64(500) + max := int64(48000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + if capacity >= 10000 && capacity <= 16000 { + min := int64(1000) + max := int64(48000) + if !(iops >= min && iops <= max) { + return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) + } + } + } + return nil +} + +func ResourceRouteModeValidate(diff *schema.ResourceDiff) error { + + var lbtype, lbprofile string + if typeOk, ok := diff.GetOk(isLBType); ok { + lbtype = typeOk.(string) + } + if profileOk, ok := diff.GetOk(isLBProfile); ok { + lbprofile = profileOk.(string) + } + if rmOk, ok := diff.GetOk(isLBRouteMode); ok { + routeMode := rmOk.(bool) + + if routeMode && lbtype != "private" { + return fmt.Errorf("'type' must be 'private', at present public load balancers are not supported with route mode enabled.") + } + if routeMode && lbprofile != "network-fixed" { + return fmt.Errorf("'profile' must be 'network-fixed', route mode is supported by private network load balancer.") + } + } + + return nil +} + +func FlattenRoleData(object []iampolicymanagementv1.Role, roleType string) []map[string]string { + var roles []map[string]string + + for _, item := range object { + role := make(map[string]string) + role["name"] = *item.DisplayName + role["type"] = roleType + role["description"] = *item.Description + roles = append(roles, role) + } + return roles +} + +func FlattenCustomRoleData(object []iampolicymanagementv1.CustomRole, roleType string) []map[string]string { + var roles []map[string]string + + for _, item := range object { + role := make(map[string]string) + role["name"] = *item.DisplayName + role["type"] = roleType + role["description"] = *item.Description + roles = append(roles, role) + } + return roles +} + +func flattenActions(object []iampolicymanagementv1.Role) map[string]interface{} { + actions := map[string]interface{}{ + "reader": FlattenActionbyDisplayName("Reader", object), + "manager": FlattenActionbyDisplayName("Manager", object), + "reader_plus": FlattenActionbyDisplayName("ReaderPlus", object), + "writer": FlattenActionbyDisplayName("Writer", object), + } + return actions +} + +func FlattenActionbyDisplayName(displayName string, object []iampolicymanagementv1.Role) []string { + var actionIDs []string + for _, role := range object { + if *role.DisplayName == displayName { + actionIDs = role.Actions + } + } + return actionIDs +} + +func flattenCatalogRef(object schematics.CatalogInfo) map[string]interface{} { + catalogRef := map[string]interface{}{ + "item_id": object.ItemID, + "item_name": object.ItemName, + "item_url": object.ItemURL, + "offering_version": object.OfferingVersion, + } + return catalogRef +} + +// GetNext ... +func GetNext(next interface{}) string { + if reflect.ValueOf(next).IsNil() { + return "" + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return "" + } + + q := u.Query() + return q.Get("start") +} + +// GetNextIAM ... +func GetNextIAM(next interface{}) string { + if reflect.ValueOf(next).IsNil() { + return "" + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().String()) + if err != nil { + return "" + } + q := u.Query() + return q.Get("pagetoken") +} + +/* Return the default resource group */ +func DefaultResourceGroup(meta interface{}) (string, error) { + + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() + if err != nil { + return "", err + } + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return "", err + } + accountID := userDetails.UserAccount + defaultGrp := true + resourceGroupList := rg.ListResourceGroupsOptions{ + Default: &defaultGrp, + } + if accountID != "" { + resourceGroupList.AccountID = &accountID + } + grpList, resp, err := rMgtClient.ListResourceGroups(&resourceGroupList) + if err != nil || grpList == nil || grpList.Resources == nil { + return "", fmt.Errorf("[ERROR] Error retrieving resource group: %s %s", err, resp) + } + if len(grpList.Resources) <= 0 { + return "", fmt.Errorf("[ERROR] The default resource group could not be found. Make sure you have required permissions to access the resource group") + } + return *grpList.Resources[0].ID, nil +} + +func FlattenKeyPolicies(policies []kp.Policy) []map[string]interface{} { + policyMap := make([]map[string]interface{}, 0, 1) + rotationMap := make([]map[string]interface{}, 0, 1) + dualAuthMap := make([]map[string]interface{}, 0, 1) + for _, policy := range policies { + log.Println("Policy CRN Data =============>", policy.CRN) + policyCRNData := strings.Split(policy.CRN, ":") + policyInstance := map[string]interface{}{ + "id": policyCRNData[9], + "crn": policy.CRN, + "created_by": policy.CreatedBy, + "creation_date": (*(policy.CreatedAt)).String(), + "updated_by": policy.UpdatedBy, + "last_update_date": (*(policy.UpdatedAt)).String(), + } + if policy.Rotation != nil { + policyInstance["interval_month"] = policy.Rotation.Interval + rotationMap = append(rotationMap, policyInstance) + } else if policy.DualAuth != nil { + policyInstance["enabled"] = *(policy.DualAuth.Enabled) + dualAuthMap = append(dualAuthMap, policyInstance) + } + } + tempMap := map[string]interface{}{ + "rotation": rotationMap, + "dual_auth_delete": dualAuthMap, + } + policyMap = append(policyMap, tempMap) + return policyMap +} + +func FlattenKeyIndividualPolicy(policy string, policies []kp.Policy) []map[string]interface{} { + rotationMap := make([]map[string]interface{}, 0, 1) + dualAuthMap := make([]map[string]interface{}, 0, 1) + for _, policy := range policies { + log.Println("Policy CRN Data =============>", policy.CRN) + policyCRNData := strings.Split(policy.CRN, ":") + policyInstance := map[string]interface{}{ + "id": policyCRNData[9], + "crn": policy.CRN, + "created_by": policy.CreatedBy, + "creation_date": (*(policy.CreatedAt)).String(), + "updated_by": policy.UpdatedBy, + "last_update_date": (*(policy.UpdatedAt)).String(), + } + if policy.Rotation != nil { + policyInstance["interval_month"] = policy.Rotation.Interval + rotationMap = append(rotationMap, policyInstance) + } else if policy.DualAuth != nil { + policyInstance["enabled"] = *(policy.DualAuth.Enabled) + dualAuthMap = append(dualAuthMap, policyInstance) + } + } + if policy == "rotation" { + return rotationMap + } else if policy == "dual_auth_delete" { + return dualAuthMap + } + return nil +} + +// IgnoreSystemLabels returns non-IBM tag keys. +func IgnoreSystemLabels(labels map[string]string) map[string]string { + result := make(map[string]string) + + for k, v := range labels { + if (strings.HasPrefix(k, SystemIBMLabelPrefix) || + strings.HasPrefix(k, KubernetesLabelPrefix) || + strings.HasPrefix(k, K8sLabelPrefix)) && + !strings.Contains(k, "node-local-dns-enabled") { + continue + } + + result[k] = v + } + + return result +} + +// ExpandCosConfig .. +func ExpandCosConfig(cos []interface{}) *kubernetesserviceapiv1.COSBucket { + if len(cos) == 0 || cos[0] == nil { + return &kubernetesserviceapiv1.COSBucket{} + } + in := cos[0].(map[string]interface{}) + obj := &kubernetesserviceapiv1.COSBucket{ + Bucket: PtrToString(in["bucket"].(string)), + Endpoint: PtrToString(in["endpoint"].(string)), + Region: PtrToString(in["region"].(string)), + } + return obj +} + +// expandCosCredentials .. +func ExpandCosCredentials(cos []interface{}) *kubernetesserviceapiv1.COSAuthorization { + if len(cos) == 0 || cos[0] == nil { + return &kubernetesserviceapiv1.COSAuthorization{} + } + in := cos[0].(map[string]interface{}) + obj := &kubernetesserviceapiv1.COSAuthorization{ + AccessKeyID: PtrToString(in["access_key-id"].(string)), + SecretAccessKey: PtrToString(in["secret_access_key"].(string)), + } + return obj +} +func FlattenNlbConfigs(nlbData []containerv2.NlbVPCListConfig) []map[string]interface{} { + nlbConfigList := make([]map[string]interface{}, 0) + for _, n := range nlbData { + nlbConfig := make(map[string]interface{}) + nlbConfig["secret_name"] = n.SecretName + nlbConfig["secret_status"] = n.SecretStatus + c := n.Nlb + nlbConfig["cluster"] = c.Cluster + nlbConfig["dns_type"] = c.DnsType + nlbConfig["lb_hostname"] = c.LbHostname + nlbConfig["nlb_ips"] = c.NlbIPArray + nlbConfig["nlb_sub_domain"] = c.NlbSubdomain + nlbConfig["secret_namespace"] = c.SecretNamespace + nlbConfig["type"] = c.Type + nlbConfigList = append(nlbConfigList, nlbConfig) + } + + return nlbConfigList +} + +// flattenHostLabels .. +func FlattenHostLabels(hostLabels []interface{}) map[string]string { + labels := make(map[string]string) + for _, v := range hostLabels { + parts := strings.Split(v.(string), ":") + if len(parts) != 2 { + log.Fatal("Entered label " + v.(string) + "is in incorrect format.") + } + labels[parts[0]] = parts[1] + } + + return labels +} + +func FlattenSatelliteZones(zones *schema.Set) []string { + zoneList := make([]string, zones.Len()) + for i, v := range zones.List() { + zoneList[i] = fmt.Sprint(v) + } + + return zoneList +} + +// error object +type ServiceErrorResponse struct { + Message string + StatusCode int + Result interface{} +} + +func BeautifyError(err error, response *core.DetailedResponse) *ServiceErrorResponse { + var ( + statusCode int + result interface{} + ) + if response != nil { + statusCode = response.StatusCode + result = response.Result + } + return &ServiceErrorResponse{ + Message: err.Error(), + StatusCode: statusCode, + Result: result, + } +} + +func (response *ServiceErrorResponse) String() string { + output, err := json.MarshalIndent(response, "", " ") + if err == nil { + return fmt.Sprintf("%+v\n", string(output)) + } + return fmt.Sprintf("Error : %#v", response) +} + +// IAM Policy Management +func GetResourceAttribute(name string, r iampolicymanagementv1.PolicyResource) *string { + for _, a := range r.Attributes { + if *a.Name == name { + return a.Value + } + } + return core.StringPtr("") +} + +func GetSubjectAttribute(name string, s iampolicymanagementv1.PolicySubject) *string { + for _, a := range s.Attributes { + if *a.Name == name { + return a.Value + } + } + return core.StringPtr("") +} + +func SetResourceAttribute(name *string, value *string, r []iampolicymanagementv1.ResourceAttribute) []iampolicymanagementv1.ResourceAttribute { + for _, a := range r { + if *a.Name == *name { + a.Value = value + return r + } + } + r = append(r, iampolicymanagementv1.ResourceAttribute{ + Name: name, + Value: value, + Operator: core.StringPtr("stringEquals"), + }) + return r +} +func FindRoleByName(supported []iampolicymanagementv1.PolicyRole, name string) (iampolicymanagementv1.PolicyRole, error) { + for _, role := range supported { + if role.DisplayName != nil { + if *role.DisplayName == name { + role.DisplayName = nil + return role, nil + } + } + } + supportedRoles := getSupportedRolesStr(supported) + return iampolicymanagementv1.PolicyRole{}, bmxerror.New("RoleDoesnotExist", + fmt.Sprintf("%s was not found. Valid roles are %s", name, supportedRoles)) + +} + +func getSupportedRolesStr(supported []iampolicymanagementv1.PolicyRole) string { + rolesStr := "" + for index, role := range supported { + if index != 0 { + rolesStr += ", " + } + if role.DisplayName != nil { + rolesStr += *role.DisplayName + } + } + return rolesStr +} + +func GetRolesFromRoleNames(roleNames []string, roles []iampolicymanagementv1.PolicyRole) ([]iampolicymanagementv1.PolicyRole, error) { + + filteredRoles := []iampolicymanagementv1.PolicyRole{} + for _, roleName := range roleNames { + role, err := FindRoleByName(roles, roleName) + if err != nil { + return []iampolicymanagementv1.PolicyRole{}, err + } + role.DisplayName = nil + filteredRoles = append(filteredRoles, role) + } + return filteredRoles, nil +} + +func MapRoleListToPolicyRoles(roleList iampolicymanagementv1.RoleList) []iampolicymanagementv1.PolicyRole { + var policyRoles []iampolicymanagementv1.PolicyRole + for _, customRole := range roleList.CustomRoles { + newPolicyRole := iampolicymanagementv1.PolicyRole{ + DisplayName: customRole.DisplayName, + RoleID: customRole.CRN, + } + policyRoles = append(policyRoles, newPolicyRole) + } + for _, serviceRole := range roleList.ServiceRoles { + newPolicyRole := iampolicymanagementv1.PolicyRole{ + DisplayName: serviceRole.DisplayName, + RoleID: serviceRole.CRN, + } + policyRoles = append(policyRoles, newPolicyRole) + } + for _, systemRole := range roleList.SystemRoles { + newPolicyRole := iampolicymanagementv1.PolicyRole{ + DisplayName: systemRole.DisplayName, + RoleID: systemRole.CRN, + } + policyRoles = append(policyRoles, newPolicyRole) + } + return policyRoles +} + +func GeneratePolicyOptions(d *schema.ResourceData, meta interface{}) (iampolicymanagementv1.CreatePolicyOptions, error) { + + var serviceName string + var resourceType string + resourceAttributes := []iampolicymanagementv1.ResourceAttribute{} + + if res, ok := d.GetOk("resources"); ok { + resources := res.([]interface{}) + for _, resource := range resources { + r, _ := resource.(map[string]interface{}) + + if r, ok := r["service"]; ok && r != nil { + serviceName = r.(string) + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceName"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["resource_instance_id"]; ok { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceInstance"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["region"]; ok { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("region"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["resource_type"]; ok { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("resourceType"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["resource"]; ok { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("resource"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["resource_group_id"]; ok { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("resourceGroupId"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["service_type"]; ok && r != nil { + if r.(string) != "" { + resourceAttr := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceType"), + Value: core.StringPtr(r.(string)), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, resourceAttr) + } + } + + if r, ok := r["attributes"]; ok { + for k, v := range r.(map[string]interface{}) { + resourceAttributes = SetResourceAttribute(core.StringPtr(k), core.StringPtr(v.(string)), resourceAttributes) + } + } + } + } + if r, ok := d.GetOk("resource_attributes"); ok { + for _, attribute := range r.(*schema.Set).List() { + a := attribute.(map[string]interface{}) + name := a["name"].(string) + value := a["value"].(string) + operator := a["operator"].(string) + if name == "serviceName" { + serviceName = value + } + at := iampolicymanagementv1.ResourceAttribute{ + Name: &name, + Value: &value, + Operator: &operator, + } + resourceAttributes = append(resourceAttributes, at) + } + } + + var serviceTypeResourceAttribute iampolicymanagementv1.ResourceAttribute + + if d.Get("account_management").(bool) { + serviceTypeResourceAttribute = iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceType"), + Value: core.StringPtr("platform_service"), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, serviceTypeResourceAttribute) + } + + if len(resourceAttributes) == 0 { + serviceTypeResourceAttribute = iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceType"), + Value: core.StringPtr("service"), + Operator: core.StringPtr("stringEquals"), + } + resourceAttributes = append(resourceAttributes, serviceTypeResourceAttribute) + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: resourceAttributes, + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return iampolicymanagementv1.CreatePolicyOptions{}, err + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + + if err != nil { + return iampolicymanagementv1.CreatePolicyOptions{}, err + } + + serviceToQuery := serviceName + + if serviceName == "" && // no specific service specified + !d.Get("account_management").(bool) && // not all account management services + resourceType != "resource-group" { // not to a resource group + serviceToQuery = "alliamserviceroles" + } + + listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ + AccountID: &userDetails.UserAccount, + ServiceName: &serviceToQuery, + } + + roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) + if err != nil { + return iampolicymanagementv1.CreatePolicyOptions{}, err + } + + roles := MapRoleListToPolicyRoles(*roleList) + policyRoles, err := GetRolesFromRoleNames(ExpandStringList(d.Get("roles").([]interface{})), roles) + if err != nil { + return iampolicymanagementv1.CreatePolicyOptions{}, err + } + + return iampolicymanagementv1.CreatePolicyOptions{Roles: policyRoles, Resources: []iampolicymanagementv1.PolicyResource{policyResources}}, nil +} + +func SetTags(d *schema.ResourceData) []iampolicymanagementv1.ResourceTag { + resourceAttributes := []iampolicymanagementv1.ResourceTag{} + if r, ok := d.GetOk("resource_tags"); ok { + for _, attribute := range r.(*schema.Set).List() { + a := attribute.(map[string]interface{}) + name := a["name"].(string) + value := a["value"].(string) + operator := a["operator"].(string) + tag := iampolicymanagementv1.ResourceTag{ + Name: &name, + Value: &value, + Operator: &operator, + } + resourceAttributes = append(resourceAttributes, tag) + } + return resourceAttributes + } + return []iampolicymanagementv1.ResourceTag{} +} + +func GetIBMUniqueId(accountID, userEmail string, meta interface{}) (string, error) { + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() + if err != nil { + return "", err + } + client := userManagement.UserInvite() + res, err := client.ListUsers(accountID) + if err != nil { + return "", err + } + for _, userInfo := range res { + //handling case-sensitivity in userEmail + if strings.ToLower(userInfo.Email) == strings.ToLower(userEmail) { + return userInfo.IamID, nil + } + } + return "", fmt.Errorf("User %s is not found under account %s", userEmail, accountID) +} + +func ImmutableResourceCustomizeDiff(resourceList []string, diff *schema.ResourceDiff) error { + + sateLocZone := "managed_from" + for _, rName := range resourceList { + if diff.Id() != "" && diff.HasChange(rName) && rName != sateLocZone { + return fmt.Errorf("'%s' attribute is immutable and can't be changed", rName) + } else if diff.Id() != "" && diff.HasChange(rName) && rName == sateLocZone { + o, n := diff.GetChange(rName) + old := o.(string) + new := n.(string) + if len(old) >= 3 && len(new) >= 3 { + if old[0:3] != new[0:3] { + return fmt.Errorf("'%s' attribute is immutable and can't be changed from %s to %s", rName, old, new) + } + } + } + } + return nil +} + +func FlattenSatelliteWorkerPoolZones(zones *schema.Set) []kubernetesserviceapiv1.SatelliteCreateWorkerPoolZone { + zoneList := make([]kubernetesserviceapiv1.SatelliteCreateWorkerPoolZone, zones.Len()) + for i, v := range zones.List() { + data := v.(map[string]interface{}) + if v, ok := data["id"]; ok && v.(string) != "" { + zoneList[i].ID = sl.String(v.(string)) + } + } + + return zoneList +} + +func FlattenSatelliteWorkerPools(list []kubernetesserviceapiv1.GetWorkerPoolResponse) []map[string]interface{} { + workerPools := make([]map[string]interface{}, len(list)) + for i, workerPool := range list { + l := map[string]interface{}{ + "id": *workerPool.ID, + "name": *workerPool.PoolName, + "isolation": *workerPool.Isolation, + "flavour": *workerPool.Flavor, + "size_per_zone": *workerPool.WorkerCount, + "state": *workerPool.Lifecycle.ActualState, + "default_worker_pool_labels": workerPool.Labels, + "host_labels": workerPool.HostLabels, + } + zones := workerPool.Zones + zonesConfig := make([]map[string]interface{}, len(zones)) + for j, zone := range zones { + z := map[string]interface{}{ + "zone": *zone.ID, + "worker_count": int(*zone.WorkerCount), + } + zonesConfig[j] = z + } + l["zones"] = zonesConfig + workerPools[i] = l + } + + return workerPools +} + +func FlattenSatelliteHosts(hostList []kubernetesserviceapiv1.MultishiftQueueNode) []map[string]interface{} { + hosts := make([]map[string]interface{}, len(hostList)) + for i, host := range hostList { + l := map[string]interface{}{ + "host_id": *host.ID, + "host_name": *host.Name, + "status": *host.Health.Status, + "ip_address": *host.Assignment.IpAddress, + "cluster_name": *host.Assignment.ClusterName, + "zone": *host.Assignment.Zone, + "host_labels": *&host.Labels, + } + hosts[i] = l + } + + return hosts +} + +func FlattenWorkerPoolHostLabels(hostLabels map[string]string) *schema.Set { + mapped := make([]string, len(hostLabels)-1) + idx := 0 + for k, v := range hostLabels { + if strings.HasPrefix(k, "os") { + continue + } + mapped[idx] = fmt.Sprintf("%s:%v", k, v) + idx++ + } + + return NewStringSet(schema.HashString, mapped) +} + +// KMS Private Endpoint +func updatePrivateURL(kpURL string) (string, error) { + var kmsEndpointURL string + if !strings.Contains(kpURL, "private") { + kmsEndpURL := strings.SplitAfter(kpURL, "https://") + if len(kmsEndpURL) == 2 { + kmsEndpointURL = kmsEndpURL[0] + "private." + kmsEndpURL[1] + "/api/v2/" + + } else { + return "", fmt.Errorf("[ERROR] Error in Kms EndPoint URL ") + } + } + return kmsEndpointURL, nil +} + +func FlattenSatelliteClusterZones(list []string) []map[string]interface{} { + zones := make([]map[string]interface{}, len(list)) + for i, zone := range list { + l := map[string]interface{}{ + "id": zone, + } + zones[i] = l + } + return zones +} diff --git a/ibm/provider.go b/ibm/provider.go deleted file mode 100644 index fa4f959a6..000000000 --- a/ibm/provider.go +++ /dev/null @@ -1,1008 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "os" - "sync" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/mutexkv" -) - -// This is a global MutexKV for use within this plugin. -var ibmMutexKV = mutexkv.NewMutexKV() - -// Provider returns a *schema.Provider. -func Provider() *schema.Provider { - return &schema.Provider{ - Schema: map[string]*schema.Schema{ - "bluemix_api_key": { - Type: schema.TypeString, - Optional: true, - Description: "The Bluemix API Key", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"BM_API_KEY", "BLUEMIX_API_KEY"}, nil), - Deprecated: "This field is deprecated please use ibmcloud_api_key", - }, - "bluemix_timeout": { - Type: schema.TypeInt, - Optional: true, - Description: "The timeout (in seconds) to set for any Bluemix API calls made.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"BM_TIMEOUT", "BLUEMIX_TIMEOUT"}, nil), - Deprecated: "This field is deprecated please use ibmcloud_timeout", - }, - "ibmcloud_api_key": { - Type: schema.TypeString, - Optional: true, - Description: "The IBM Cloud API Key", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_API_KEY", "IBMCLOUD_API_KEY"}, nil), - }, - "ibmcloud_timeout": { - Type: schema.TypeInt, - Optional: true, - Description: "The timeout (in seconds) to set for any IBM Cloud API calls made.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_TIMEOUT", "IBMCLOUD_TIMEOUT"}, 60), - }, - "region": { - Type: schema.TypeString, - Optional: true, - Description: "The IBM cloud Region (for example 'us-south').", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_REGION", "IBMCLOUD_REGION", "BM_REGION", "BLUEMIX_REGION"}, "us-south"), - }, - "zone": { - Type: schema.TypeString, - Optional: true, - Description: "The IBM cloud Region zone (for example 'us-south-1') for power resources.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_ZONE", "IBMCLOUD_ZONE"}, ""), - }, - "resource_group": { - Type: schema.TypeString, - Optional: true, - Description: "The Resource group id.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_RESOURCE_GROUP", "IBMCLOUD_RESOURCE_GROUP", "BM_RESOURCE_GROUP", "BLUEMIX_RESOURCE_GROUP"}, ""), - }, - "softlayer_api_key": { - Type: schema.TypeString, - Optional: true, - Description: "The SoftLayer API Key", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_API_KEY", "SOFTLAYER_API_KEY"}, nil), - Deprecated: "This field is deprecated please use iaas_classic_api_key", - }, - "softlayer_username": { - Type: schema.TypeString, - Optional: true, - Description: "The SoftLayer user name", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_USERNAME", "SOFTLAYER_USERNAME"}, nil), - Deprecated: "This field is deprecated please use iaas_classic_username", - }, - "softlayer_endpoint_url": { - Type: schema.TypeString, - Optional: true, - Description: "The Softlayer Endpoint", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_ENDPOINT_URL", "SOFTLAYER_ENDPOINT_URL"}, nil), - Deprecated: "This field is deprecated please use iaas_classic_endpoint_url", - }, - "softlayer_timeout": { - Type: schema.TypeInt, - Optional: true, - Description: "The timeout (in seconds) to set for any SoftLayer API calls made.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_TIMEOUT", "SOFTLAYER_TIMEOUT"}, nil), - Deprecated: "This field is deprecated please use iaas_classic_timeout", - }, - "iaas_classic_api_key": { - Type: schema.TypeString, - Optional: true, - Description: "The Classic Infrastructure API Key", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_API_KEY"}, nil), - }, - "iaas_classic_username": { - Type: schema.TypeString, - Optional: true, - Description: "The Classic Infrastructure API user name", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_USERNAME"}, nil), - }, - "iaas_classic_endpoint_url": { - Type: schema.TypeString, - Optional: true, - Description: "The Classic Infrastructure Endpoint", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_ENDPOINT_URL"}, "https://api.softlayer.com/rest/v3"), - }, - "iaas_classic_timeout": { - Type: schema.TypeInt, - Optional: true, - Description: "The timeout (in seconds) to set for any Classic Infrastructure API calls made.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_TIMEOUT"}, 60), - }, - "max_retries": { - Type: schema.TypeInt, - Optional: true, - Description: "The retry count to set for API calls.", - DefaultFunc: schema.EnvDefaultFunc("MAX_RETRIES", 10), - }, - "function_namespace": { - Type: schema.TypeString, - Optional: true, - Description: "The IBM Cloud Function namespace", - DefaultFunc: schema.EnvDefaultFunc("FUNCTION_NAMESPACE", nil), - Deprecated: "This field will be deprecated soon", - }, - "riaas_endpoint": { - Type: schema.TypeString, - Optional: true, - Description: "The next generation infrastructure service endpoint url.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"RIAAS_ENDPOINT"}, nil), - Deprecated: "This field is deprecated use generation", - }, - "generation": { - Type: schema.TypeInt, - Optional: true, - Description: "Generation of Virtual Private Cloud. Default is 2", - //DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_GENERATION", "IBMCLOUD_GENERATION"}, nil), - Deprecated: "The generation field is deprecated and will be removed after couple of releases", - }, - "iam_token": { - Type: schema.TypeString, - Optional: true, - Description: "IAM Authentication token", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_IAM_TOKEN", "IBMCLOUD_IAM_TOKEN"}, nil), - }, - "iam_refresh_token": { - Type: schema.TypeString, - Optional: true, - Description: "IAM Authentication refresh token", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_IAM_REFRESH_TOKEN", "IBMCLOUD_IAM_REFRESH_TOKEN"}, nil), - }, - "visibility": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "public-and-private"}), - Description: "Visibility of the provider if it is private or public.", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_VISIBILITY", "IBMCLOUD_VISIBILITY"}, "public"), - }, - "endpoints_file_path": { - Type: schema.TypeString, - Optional: true, - Description: "Path of the file that contains private and public regional endpoints mapping", - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_ENDPOINTS_FILE_PATH", "IBMCLOUD_ENDPOINTS_FILE_PATH"}, nil), - }, - }, - - DataSourcesMap: map[string]*schema.Resource{ - "ibm_api_gateway": dataSourceIBMApiGateway(), - "ibm_account": dataSourceIBMAccount(), - "ibm_app": dataSourceIBMApp(), - "ibm_app_domain_private": dataSourceIBMAppDomainPrivate(), - "ibm_app_domain_shared": dataSourceIBMAppDomainShared(), - "ibm_app_route": dataSourceIBMAppRoute(), - - // AppID - "ibm_appid_action_url": dataSourceIBMAppIDActionURL(), - "ibm_appid_apm": dataSourceIBMAppIDAPM(), - "ibm_appid_application": dataSourceIBMAppIDApplication(), - "ibm_appid_application_scopes": dataSourceIBMAppIDApplicationScopes(), - "ibm_appid_application_roles": dataSourceIBMAppIDApplicationRoles(), - "ibm_appid_applications": dataSourceIBMAppIDApplications(), - "ibm_appid_audit_status": dataSourceIBMAppIDAuditStatus(), - "ibm_appid_cloud_directory_template": dataSourceIBMAppIDCloudDirectoryTemplate(), - "ibm_appid_cloud_directory_user": dataSourceIBMAppIDCloudDirectoryUser(), - "ibm_appid_idp_cloud_directory": dataSourceIBMAppIDIDPCloudDirectory(), - "ibm_appid_idp_custom": dataSourceIBMAppIDIDPCustom(), - "ibm_appid_idp_facebook": dataSourceIBMAppIDIDPFacebook(), - "ibm_appid_idp_google": dataSourceIBMAppIDIDPGoogle(), - "ibm_appid_idp_saml": dataSourceIBMAppIDIDPSAML(), - "ibm_appid_idp_saml_metadata": dataSourceIBMAppIDIDPSAMLMetadata(), - "ibm_appid_languages": dataSourceIBMAppIDLanguages(), - "ibm_appid_mfa": dataSourceIBMAppIDMFA(), - "ibm_appid_mfa_channel": dataSourceIBMAppIDMFAChannel(), - "ibm_appid_password_regex": dataSourceIBMAppIDPasswordRegex(), - "ibm_appid_token_config": dataSourceIBMAppIDTokenConfig(), - "ibm_appid_redirect_urls": dataSourceIBMAppIDRedirectURLs(), - "ibm_appid_role": dataSourceIBMAppIDRole(), - "ibm_appid_roles": dataSourceIBMAppIDRoles(), - "ibm_appid_theme_color": dataSourceIBMAppIDThemeColor(), - "ibm_appid_theme_text": dataSourceIBMAppIDThemeText(), - "ibm_appid_user_roles": dataSourceIBMAppIDUserRoles(), - - "ibm_function_action": dataSourceIBMFunctionAction(), - "ibm_function_package": dataSourceIBMFunctionPackage(), - "ibm_function_rule": dataSourceIBMFunctionRule(), - "ibm_function_trigger": dataSourceIBMFunctionTrigger(), - "ibm_function_namespace": dataSourceIBMFunctionNamespace(), - "ibm_certificate_manager_certificates": dataIBMCertificateManagerCertificates(), - "ibm_certificate_manager_certificate": dataIBMCertificateManagerCertificate(), - "ibm_cis": dataSourceIBMCISInstance(), - "ibm_cis_dns_records": dataSourceIBMCISDNSRecords(), - "ibm_cis_certificates": dataIBMCISCertificates(), - "ibm_cis_global_load_balancers": dataSourceIBMCISGlbs(), - "ibm_cis_origin_pools": dataSourceIBMCISOriginPools(), - "ibm_cis_healthchecks": dataSourceIBMCISHealthChecks(), - "ibm_cis_domain": dataSourceIBMCISDomain(), - "ibm_cis_firewall": dataIBMCISFirewallsRecord(), - "ibm_cis_cache_settings": dataSourceIBMCISCacheSetting(), - "ibm_cis_waf_packages": dataSourceIBMCISWAFPackages(), - "ibm_cis_range_apps": dataSourceIBMCISRangeApps(), - "ibm_cis_custom_certificates": dataSourceIBMCISCustomCertificates(), - "ibm_cis_rate_limit": dataSourceIBMCISRateLimit(), - "ibm_cis_ip_addresses": dataSourceIBMCISIP(), - "ibm_cis_waf_groups": dataSourceIBMCISWAFGroups(), - "ibm_cis_edge_functions_actions": dataSourceIBMCISEdgeFunctionsActions(), - "ibm_cis_edge_functions_triggers": dataSourceIBMCISEdgeFunctionsTriggers(), - "ibm_cis_custom_pages": dataSourceIBMCISCustomPages(), - "ibm_cis_page_rules": dataSourceIBMCISPageRules(), - "ibm_cis_waf_rules": dataSourceIBMCISWAFRules(), - "ibm_cis_filters": dataSourceIBMCISFilters(), - "ibm_cis_firewall_rules": dataSourceIBMCISFirewallRules(), - "ibm_cloudant": dataSourceIBMCloudant(), - "ibm_database": dataSourceIBMDatabaseInstance(), - "ibm_compute_bare_metal": dataSourceIBMComputeBareMetal(), - "ibm_compute_image_template": dataSourceIBMComputeImageTemplate(), - "ibm_compute_placement_group": dataSourceIBMComputePlacementGroup(), - "ibm_compute_reserved_capacity": dataSourceIBMComputeReservedCapacity(), - "ibm_compute_ssh_key": dataSourceIBMComputeSSHKey(), - "ibm_compute_vm_instance": dataSourceIBMComputeVmInstance(), - "ibm_container_addons": datasourceIBMContainerAddOns(), - "ibm_container_alb": dataSourceIBMContainerALB(), - "ibm_container_alb_cert": dataSourceIBMContainerALBCert(), - "ibm_container_bind_service": dataSourceIBMContainerBindService(), - "ibm_container_cluster": dataSourceIBMContainerCluster(), - "ibm_container_cluster_config": dataSourceIBMContainerClusterConfig(), - "ibm_container_cluster_versions": dataSourceIBMContainerClusterVersions(), - "ibm_container_cluster_worker": dataSourceIBMContainerClusterWorker(), - "ibm_container_nlb_dns": dataSourceIBMContainerNLBDNS(), - "ibm_container_vpc_cluster_alb": dataSourceIBMContainerVPCClusterALB(), - "ibm_container_vpc_alb": dataSourceIBMContainerVPCClusterALB(), - "ibm_container_vpc_cluster": dataSourceIBMContainerVPCCluster(), - "ibm_container_vpc_cluster_worker": dataSourceIBMContainerVPCClusterWorker(), - "ibm_container_vpc_cluster_worker_pool": dataSourceIBMContainerVpcClusterWorkerPool(), - "ibm_container_vpc_worker_pool": dataSourceIBMContainerVpcClusterWorkerPool(), - "ibm_container_worker_pool": dataSourceIBMContainerWorkerPool(), - "ibm_container_storage_attachment": dataSourceIBMContainerVpcWorkerVolumeAttachment(), - "ibm_cr_namespaces": dataIBMContainerRegistryNamespaces(), - "ibm_cloud_shell_account_settings": dataSourceIBMCloudShellAccountSettings(), - "ibm_cos_bucket": dataSourceIBMCosBucket(), - "ibm_cos_bucket_object": dataSourceIBMCosBucketObject(), - "ibm_dns_domain_registration": dataSourceIBMDNSDomainRegistration(), - "ibm_dns_domain": dataSourceIBMDNSDomain(), - "ibm_dns_secondary": dataSourceIBMDNSSecondary(), - "ibm_event_streams_topic": dataSourceIBMEventStreamsTopic(), - "ibm_event_streams_schema": dataSourceIBMEventStreamsSchema(), - "ibm_hpcs": dataSourceIBMHPCS(), - "ibm_iam_access_group": dataSourceIBMIAMAccessGroup(), - "ibm_iam_account_settings": dataSourceIBMIAMAccountSettings(), - "ibm_iam_auth_token": dataSourceIBMIAMAuthToken(), - "ibm_iam_role_actions": datasourceIBMIAMRoleAction(), - "ibm_iam_users": dataSourceIBMIAMUsers(), - "ibm_iam_roles": datasourceIBMIAMRole(), - "ibm_iam_user_policy": dataSourceIBMIAMUserPolicy(), - "ibm_iam_user_profile": dataSourceIBMIAMUserProfile(), - "ibm_iam_service_id": dataSourceIBMIAMServiceID(), - "ibm_iam_service_policy": dataSourceIBMIAMServicePolicy(), - "ibm_iam_api_key": dataSourceIbmIamApiKey(), - "ibm_iam_trusted_profile": dataSourceIBMIamTrustedProfile(), - "ibm_iam_trusted_profile_claim_rule": dataSourceIBMIamTrustedProfileClaimRule(), - "ibm_iam_trusted_profile_link": dataSourceIBMIamTrustedProfileLink(), - "ibm_iam_trusted_profile_policy": dataSourceIBMIAMTrustedProfilePolicy(), - "ibm_is_dedicated_host": dataSourceIbmIsDedicatedHost(), - "ibm_is_dedicated_hosts": dataSourceIbmIsDedicatedHosts(), - "ibm_is_dedicated_host_profile": dataSourceIbmIsDedicatedHostProfile(), - "ibm_is_dedicated_host_profiles": dataSourceIbmIsDedicatedHostProfiles(), - "ibm_is_dedicated_host_group": dataSourceIbmIsDedicatedHostGroup(), - "ibm_is_dedicated_host_groups": dataSourceIbmIsDedicatedHostGroups(), - "ibm_is_dedicated_host_disk": dataSourceIbmIsDedicatedHostDisk(), - "ibm_is_dedicated_host_disks": dataSourceIbmIsDedicatedHostDisks(), - "ibm_is_placement_group": dataSourceIbmIsPlacementGroup(), - "ibm_is_placement_groups": dataSourceIbmIsPlacementGroups(), - "ibm_is_floating_ip": dataSourceIBMISFloatingIP(), - "ibm_is_flow_logs": dataSourceIBMISFlowLogs(), - "ibm_is_image": dataSourceIBMISImage(), - "ibm_is_images": dataSourceIBMISImages(), - "ibm_is_endpoint_gateway_targets": dataSourceIBMISEndpointGatewayTargets(), - "ibm_is_instance_group": dataSourceIBMISInstanceGroup(), - "ibm_is_instance_group_memberships": dataSourceIBMISInstanceGroupMemberships(), - "ibm_is_instance_group_membership": dataSourceIBMISInstanceGroupMembership(), - "ibm_is_instance_group_manager": dataSourceIBMISInstanceGroupManager(), - "ibm_is_instance_group_managers": dataSourceIBMISInstanceGroupManagers(), - "ibm_is_instance_group_manager_policies": dataSourceIBMISInstanceGroupManagerPolicies(), - "ibm_is_instance_group_manager_policy": dataSourceIBMISInstanceGroupManagerPolicy(), - "ibm_is_instance_group_manager_action": dataSourceIBMISInstanceGroupManagerAction(), - "ibm_is_instance_group_manager_actions": dataSourceIBMISInstanceGroupManagerActions(), - "ibm_is_virtual_endpoint_gateways": dataSourceIBMISEndpointGateways(), - "ibm_is_virtual_endpoint_gateway_ips": dataSourceIBMISEndpointGatewayIPs(), - "ibm_is_virtual_endpoint_gateway": dataSourceIBMISEndpointGateway(), - "ibm_is_instance_template": dataSourceIBMISInstanceTemplate(), - "ibm_is_instance_templates": dataSourceIBMISInstanceTemplates(), - "ibm_is_instance_profile": dataSourceIBMISInstanceProfile(), - "ibm_is_instance_profiles": dataSourceIBMISInstanceProfiles(), - "ibm_is_instance": dataSourceIBMISInstance(), - "ibm_is_instances": dataSourceIBMISInstances(), - "ibm_is_instance_disk": dataSourceIbmIsInstanceDisk(), - "ibm_is_instance_disks": dataSourceIbmIsInstanceDisks(), - "ibm_is_instance_volume_attachment": dataSourceIBMISInstanceVolumeAttachment(), - "ibm_is_instance_volume_attachments": dataSourceIBMISInstanceVolumeAttachments(), - "ibm_is_lb": dataSourceIBMISLB(), - "ibm_is_lb_profiles": dataSourceIBMISLbProfiles(), - "ibm_is_lbs": dataSourceIBMISLBS(), - "ibm_is_public_gateway": dataSourceIBMISPublicGateway(), - "ibm_is_public_gateways": dataSourceIBMISPublicGateways(), - "ibm_is_region": dataSourceIBMISRegion(), - "ibm_is_regions": dataSourceIBMISRegions(), - "ibm_is_ssh_key": dataSourceIBMISSSHKey(), - "ibm_is_subnet": dataSourceIBMISSubnet(), - "ibm_is_subnets": dataSourceIBMISSubnets(), - "ibm_is_subnet_reserved_ip": dataSourceIBMISReservedIP(), - "ibm_is_subnet_reserved_ips": dataSourceIBMISReservedIPs(), - "ibm_is_security_group": dataSourceIBMISSecurityGroup(), - "ibm_is_security_group_target": dataSourceIBMISSecurityGroupTarget(), - "ibm_is_security_group_targets": dataSourceIBMISSecurityGroupTargets(), - "ibm_is_snapshot": dataSourceSnapshot(), - "ibm_is_snapshots": dataSourceSnapshots(), - "ibm_is_volume": dataSourceIBMISVolume(), - "ibm_is_volume_profile": dataSourceIBMISVolumeProfile(), - "ibm_is_volume_profiles": dataSourceIBMISVolumeProfiles(), - "ibm_is_vpc": dataSourceIBMISVPC(), - "ibm_is_vpcs": dataSourceIBMISVPCs(), - "ibm_is_vpn_gateways": dataSourceIBMISVPNGateways(), - "ibm_is_vpc_address_prefixes": dataSourceIbmIsVpcAddressPrefixes(), - "ibm_is_vpn_gateway_connections": dataSourceIBMISVPNGatewayConnections(), - "ibm_is_vpc_default_routing_table": dataSourceIBMISVPCDefaultRoutingTable(), - "ibm_is_vpc_routing_tables": dataSourceIBMISVPCRoutingTables(), - "ibm_is_vpc_routing_table_routes": dataSourceIBMISVPCRoutingTableRoutes(), - "ibm_is_zone": dataSourceIBMISZone(), - "ibm_is_zones": dataSourceIBMISZones(), - "ibm_is_operating_system": dataSourceIBMISOperatingSystem(), - "ibm_is_operating_systems": dataSourceIBMISOperatingSystems(), - "ibm_is_network_acl_rule": dataSourceIBMISNetworkACLRule(), - "ibm_is_network_acl_rules": dataSourceIBMISNetworkACLRules(), - "ibm_lbaas": dataSourceIBMLbaas(), - "ibm_network_vlan": dataSourceIBMNetworkVlan(), - "ibm_org": dataSourceIBMOrg(), - "ibm_org_quota": dataSourceIBMOrgQuota(), - "ibm_kp_key": dataSourceIBMkey(), - "ibm_kms_key_rings": dataSourceIBMKMSkeyRings(), - "ibm_kms_key_policies": dataSourceIBMKMSkeyPolicies(), - "ibm_kms_keys": dataSourceIBMKMSkeys(), - "ibm_pn_application_chrome": dataSourceIBMPNApplicationChrome(), - "ibm_app_config_environment": dataSourceIbmAppConfigEnvironment(), - "ibm_app_config_environments": dataSourceIbmAppConfigEnvironments(), - "ibm_app_config_feature": dataSourceIbmAppConfigFeature(), - "ibm_app_config_features": dataSourceIbmAppConfigFeatures(), - "ibm_kms_key": dataSourceIBMKMSkey(), - "ibm_resource_quota": dataSourceIBMResourceQuota(), - "ibm_resource_group": dataSourceIBMResourceGroup(), - "ibm_resource_instance": dataSourceIBMResourceInstance(), - "ibm_resource_key": dataSourceIBMResourceKey(), - "ibm_security_group": dataSourceIBMSecurityGroup(), - "ibm_service_instance": dataSourceIBMServiceInstance(), - "ibm_service_key": dataSourceIBMServiceKey(), - "ibm_service_plan": dataSourceIBMServicePlan(), - "ibm_space": dataSourceIBMSpace(), - - // Added for Schematics - "ibm_schematics_workspace": dataSourceIBMSchematicsWorkspace(), - "ibm_schematics_output": dataSourceIBMSchematicsOutput(), - "ibm_schematics_state": dataSourceIBMSchematicsState(), - "ibm_schematics_action": dataSourceIBMSchematicsAction(), - "ibm_schematics_job": dataSourceIBMSchematicsJob(), - - // Added for Power Resources - - "ibm_pi_key": dataSourceIBMPIKey(), - "ibm_pi_image": dataSourceIBMPIImage(), - "ibm_pi_instance": dataSourceIBMPIInstance(), - "ibm_pi_tenant": dataSourceIBMPITenant(), - "ibm_pi_network": dataSourceIBMPINetwork(), - "ibm_pi_volume": dataSourceIBMPIVolume(), - "ibm_pi_instance_volumes": dataSourceIBMPIInstanceVolumes(), - "ibm_pi_public_network": dataSourceIBMPIPublicNetwork(), - "ibm_pi_images": dataSourceIBMPIImages(), - "ibm_pi_instance_ip": dataSourceIBMPIInstanceIP(), - "ibm_pi_instance_snapshots": dataSourceIBMPISnapshots(), - "ibm_pi_pvm_snapshots": dataSourceIBMPISnapshot(), - "ibm_pi_network_port": dataSourceIBMPINetworkPort(), - "ibm_pi_cloud_instance": dataSourceIBMPICloudInstance(), - "ibm_pi_catalog_images": dataSourceIBMPICatalogImages(), - - // Added for private dns zones - - "ibm_dns_zones": dataSourceIBMPrivateDNSZones(), - "ibm_dns_permitted_networks": dataSourceIBMPrivateDNSPermittedNetworks(), - "ibm_dns_resource_records": dataSourceIBMPrivateDNSResourceRecords(), - "ibm_dns_glb_monitors": dataSourceIBMPrivateDNSGLBMonitors(), - "ibm_dns_glb_pools": dataSourceIBMPrivateDNSGLBPools(), - "ibm_dns_glbs": dataSourceIBMPrivateDNSGLBs(), - "ibm_dns_custom_resolvers": dataSourceIBMDNSCustomResolver(), - "ibm_dns_custom_resolver_forwarding_rules": dataSourceIBMPrivateDNSForwardingRules(), - - // Added for Direct Link - - "ibm_dl_gateways": dataSourceIBMDLGateways(), - "ibm_dl_offering_speeds": dataSourceIBMDLOfferingSpeeds(), - "ibm_dl_port": dataSourceIBMDirectLinkPort(), - "ibm_dl_ports": dataSourceIBMDirectLinkPorts(), - "ibm_dl_gateway": dataSourceIBMDLGateway(), - "ibm_dl_locations": dataSourceIBMDLLocations(), - "ibm_dl_routers": dataSourceIBMDLRouters(), - "ibm_dl_provider_ports": dataSourceIBMDirectLinkProviderPorts(), - "ibm_dl_provider_gateways": dataSourceIBMDirectLinkProviderGateways(), - - //Added for Transit Gateway - "ibm_tg_gateway": dataSourceIBMTransitGateway(), - "ibm_tg_gateways": dataSourceIBMTransitGateways(), - "ibm_tg_locations": dataSourceIBMTransitGatewaysLocations(), - "ibm_tg_location": dataSourceIBMTransitGatewaysLocation(), - - //Added for BSS Enterprise - "ibm_enterprises": dataSourceIbmEnterprises(), - "ibm_enterprise_account_groups": dataSourceIbmEnterpriseAccountGroups(), - "ibm_enterprise_accounts": dataSourceIbmEnterpriseAccounts(), - - //Added for Secrets Manager - "ibm_secrets_manager_secrets": dataSourceIBMSecretsManagerSecrets(), - "ibm_secrets_manager_secret": dataSourceIBMSecretsManagerSecret(), - - //Added for Satellite - "ibm_satellite_location": dataSourceIBMSatelliteLocation(), - "ibm_satellite_location_nlb_dns": dataSourceIBMSatelliteLocationNLBDNS(), - "ibm_satellite_attach_host_script": dataSourceIBMSatelliteAttachHostScript(), - "ibm_satellite_cluster": dataSourceIBMSatelliteCluster(), - "ibm_satellite_cluster_worker_pool": dataSourceIBMSatelliteClusterWorkerPool(), - "ibm_satellite_link": dataSourceIbmSatelliteLink(), - "ibm_satellite_endpoint": dataSourceIbmSatelliteEndpoint(), - - // Catalog related resources - "ibm_cm_catalog": dataSourceIBMCmCatalog(), - "ibm_cm_offering": dataSourceIBMCmOffering(), - "ibm_cm_version": dataSourceIBMCmVersion(), - "ibm_cm_offering_instance": dataSourceIBMCmOfferingInstance(), - - //Added for Resource Tag - "ibm_resource_tag": dataSourceIBMResourceTag(), - - // Atracker - "ibm_atracker_targets": dataSourceIBMAtrackerTargets(), - "ibm_atracker_routes": dataSourceIBMAtrackerRoutes(), - "ibm_atracker_endpoints": dataSourceIBMAtrackerEndpoints(), - - //Security and Compliance Center - "ibm_scc_si_providers": dataSourceIBMSccSiProviders(), - "ibm_scc_si_note": dataSourceIBMSccSiNote(), - "ibm_scc_si_notes": dataSourceIBMSccSiNotes(), - - // Compliance Posture Management - "ibm_scc_posture_scopes": dataSourceIBMSccPostureScopes(), - "ibm_scc_posture_latest_scans": dataSourceIBMSccPostureLatestScans(), - "ibm_scc_posture_profiles": dataSourceIBMSccPostureProfiles(), - "ibm_scc_posture_scan_summary": dataSourceIBMSccPostureScansSummary(), - "ibm_scc_posture_scan_summaries": dataSourceIBMSccPostureScanSummaries(), - - // Added for Event Notifications - "ibm_en_destination": dataSourceIBMEnDestination(), - "ibm_en_destinations": dataSourceIBMEnDestinations(), - "ibm_en_topic": dataSourceIBMEnTopic(), - "ibm_en_topics": dataSourceIBMEnTopics(), - "ibm_en_subscription": dataSourceIBMEnSubscription(), - "ibm_en_subscriptions": dataSourceIBMEnSubscriptions(), - }, - - ResourcesMap: map[string]*schema.Resource{ - "ibm_api_gateway_endpoint": resourceIBMApiGatewayEndPoint(), - "ibm_api_gateway_endpoint_subscription": resourceIBMApiGatewayEndpointSubscription(), - "ibm_app": resourceIBMApp(), - "ibm_app_domain_private": resourceIBMAppDomainPrivate(), - "ibm_app_domain_shared": resourceIBMAppDomainShared(), - "ibm_app_route": resourceIBMAppRoute(), - - // AppID - "ibm_appid_action_url": resourceIBMAppIDActionURL(), - "ibm_appid_apm": resourceIBMAppIDAPM(), - "ibm_appid_application": resourceIBMAppIDApplication(), - "ibm_appid_application_scopes": resourceIBMAppIDApplicationScopes(), - "ibm_appid_application_roles": resourceIBMAppIDApplicationRoles(), - "ibm_appid_audit_status": resourceIBMAppIDAuditStatus(), - "ibm_appid_cloud_directory_template": resourceIBMAppIDCloudDirectoryTemplate(), - "ibm_appid_cloud_directory_user": resourceIBMAppIDCloudDirectoryUser(), - "ibm_appid_idp_cloud_directory": resourceIBMAppIDIDPCloudDirectory(), - "ibm_appid_idp_custom": resourceIBMAppIDIDPCustom(), - "ibm_appid_idp_facebook": resourceIBMAppIDIDPFacebook(), - "ibm_appid_idp_google": resourceIBMAppIDIDPGoogle(), - "ibm_appid_idp_saml": resourceIBMAppIDIDPSAML(), - "ibm_appid_languages": resourceIBMAppIDLanguages(), - "ibm_appid_mfa": resourceIBMAppIDMFA(), - "ibm_appid_mfa_channel": resourceIBMAppIDMFAChannel(), - "ibm_appid_password_regex": resourceIBMAppIDPasswordRegex(), - "ibm_appid_token_config": resourceIBMAppIDTokenConfig(), - "ibm_appid_redirect_urls": resourceIBMAppIDRedirectURLs(), - "ibm_appid_role": resourceIBMAppIDRole(), - "ibm_appid_theme_color": resourceIBMAppIDThemeColor(), - "ibm_appid_theme_text": resourceIBMAppIDThemeText(), - "ibm_appid_user_roles": resourceIBMAppIDUserRoles(), - - "ibm_function_action": resourceIBMFunctionAction(), - "ibm_function_package": resourceIBMFunctionPackage(), - "ibm_function_rule": resourceIBMFunctionRule(), - "ibm_function_trigger": resourceIBMFunctionTrigger(), - "ibm_function_namespace": resourceIBMFunctionNamespace(), - "ibm_cis": resourceIBMCISInstance(), - "ibm_database": resourceIBMDatabaseInstance(), - "ibm_certificate_manager_import": resourceIBMCertificateManagerImport(), - "ibm_certificate_manager_order": resourceIBMCertificateManagerOrder(), - "ibm_cis_domain": resourceIBMCISDomain(), - "ibm_cis_domain_settings": resourceIBMCISSettings(), - "ibm_cis_firewall": resourceIBMCISFirewallRecord(), - "ibm_cis_range_app": resourceIBMCISRangeApp(), - "ibm_cis_healthcheck": resourceIBMCISHealthCheck(), - "ibm_cis_origin_pool": resourceIBMCISPool(), - "ibm_cis_global_load_balancer": resourceIBMCISGlb(), - "ibm_cis_certificate_upload": resourceIBMCISCertificateUpload(), - "ibm_cis_dns_record": resourceIBMCISDnsRecord(), - "ibm_cis_dns_records_import": resourceIBMCISDNSRecordsImport(), - "ibm_cis_rate_limit": resourceIBMCISRateLimit(), - "ibm_cis_page_rule": resourceIBMCISPageRule(), - "ibm_cis_edge_functions_action": resourceIBMCISEdgeFunctionsAction(), - "ibm_cis_edge_functions_trigger": resourceIBMCISEdgeFunctionsTrigger(), - "ibm_cis_tls_settings": resourceIBMCISTLSSettings(), - "ibm_cis_waf_package": resourceIBMCISWAFPackage(), - "ibm_cis_routing": resourceIBMCISRouting(), - "ibm_cis_waf_group": resourceIBMCISWAFGroup(), - "ibm_cis_cache_settings": resourceIBMCISCacheSettings(), - "ibm_cis_custom_page": resourceIBMCISCustomPage(), - "ibm_cis_waf_rule": resourceIBMCISWAFRule(), - "ibm_cis_certificate_order": resourceIBMCISCertificateOrder(), - "ibm_cis_filter": resourceIBMCISFilter(), - "ibm_cis_firewall_rule": resourceIBMCISFirewallrules(), - "ibm_cloudant": resourceIBMCloudant(), - "ibm_cloud_shell_account_settings": resourceIBMCloudShellAccountSettings(), - "ibm_compute_autoscale_group": resourceIBMComputeAutoScaleGroup(), - "ibm_compute_autoscale_policy": resourceIBMComputeAutoScalePolicy(), - "ibm_compute_bare_metal": resourceIBMComputeBareMetal(), - "ibm_compute_dedicated_host": resourceIBMComputeDedicatedHost(), - "ibm_compute_monitor": resourceIBMComputeMonitor(), - "ibm_compute_placement_group": resourceIBMComputePlacementGroup(), - "ibm_compute_reserved_capacity": resourceIBMComputeReservedCapacity(), - "ibm_compute_provisioning_hook": resourceIBMComputeProvisioningHook(), - "ibm_compute_ssh_key": resourceIBMComputeSSHKey(), - "ibm_compute_ssl_certificate": resourceIBMComputeSSLCertificate(), - "ibm_compute_user": resourceIBMComputeUser(), - "ibm_compute_vm_instance": resourceIBMComputeVmInstance(), - "ibm_container_addons": resourceIBMContainerAddOns(), - "ibm_container_alb": resourceIBMContainerALB(), - "ibm_container_api_key_reset": resourceIBMContainerAPIKeyReset(), - "ibm_container_vpc_alb": resourceIBMContainerVpcALB(), - "ibm_container_vpc_worker_pool": resourceIBMContainerVpcWorkerPool(), - "ibm_container_vpc_cluster": resourceIBMContainerVpcCluster(), - "ibm_container_alb_cert": resourceIBMContainerALBCert(), - "ibm_container_cluster": resourceIBMContainerCluster(), - "ibm_container_cluster_feature": resourceIBMContainerClusterFeature(), - "ibm_container_bind_service": resourceIBMContainerBindService(), - "ibm_container_worker_pool": resourceIBMContainerWorkerPool(), - "ibm_container_worker_pool_zone_attachment": resourceIBMContainerWorkerPoolZoneAttachment(), - "ibm_container_storage_attachment": resourceIBMContainerVpcWorkerVolumeAttachment(), - "ibm_cr_namespace": resourceIBMCrNamespace(), - "ibm_cr_retention_policy": resourceIBMCrRetentionPolicy(), - "ibm_ob_logging": resourceIBMObLogging(), - "ibm_ob_monitoring": resourceIBMObMonitoring(), - "ibm_cos_bucket": resourceIBMCOSBucket(), - "ibm_cos_bucket_object": resourceIBMCOSBucketObject(), - "ibm_dns_domain": resourceIBMDNSDomain(), - "ibm_dns_domain_registration_nameservers": resourceIBMDNSDomainRegistrationNameservers(), - "ibm_dns_secondary": resourceIBMDNSSecondary(), - "ibm_dns_record": resourceIBMDNSRecord(), - "ibm_event_streams_topic": resourceIBMEventStreamsTopic(), - "ibm_event_streams_schema": resourceIBMEventStreamsSchema(), - "ibm_firewall": resourceIBMFirewall(), - "ibm_firewall_policy": resourceIBMFirewallPolicy(), - "ibm_hpcs": resourceIBMHPCS(), - "ibm_iam_access_group": resourceIBMIAMAccessGroup(), - "ibm_iam_account_settings": resourceIbmIamAccountSettings(), - "ibm_iam_custom_role": resourceIBMIAMCustomRole(), - "ibm_iam_access_group_dynamic_rule": resourceIBMIAMDynamicRule(), - "ibm_iam_access_group_members": resourceIBMIAMAccessGroupMembers(), - "ibm_iam_access_group_policy": resourceIBMIAMAccessGroupPolicy(), - "ibm_iam_authorization_policy": resourceIBMIAMAuthorizationPolicy(), - "ibm_iam_authorization_policy_detach": resourceIBMIAMAuthorizationPolicyDetach(), - "ibm_iam_user_policy": resourceIBMIAMUserPolicy(), - "ibm_iam_user_settings": resourceIBMUserSettings(), - "ibm_iam_service_id": resourceIBMIAMServiceID(), - "ibm_iam_service_api_key": resourceIBMIAMServiceAPIKey(), - "ibm_iam_service_policy": resourceIBMIAMServicePolicy(), - "ibm_iam_user_invite": resourceIBMUserInvite(), - "ibm_iam_api_key": resourceIbmIamApiKey(), - "ibm_iam_trusted_profile": resourceIBMIamTrustedProfile(), - "ibm_iam_trusted_profile_claim_rule": resourceIBMIamTrustedProfileClaimRule(), - "ibm_iam_trusted_profile_link": resourceIBMIamTrustedProfileLink(), - "ibm_iam_trusted_profile_policy": resourceIBMIAMTrustedProfilePolicy(), - "ibm_ipsec_vpn": resourceIBMIPSecVPN(), - "ibm_is_dedicated_host": resourceIbmIsDedicatedHost(), - "ibm_is_dedicated_host_group": resourceIbmIsDedicatedHostGroup(), - "ibm_is_dedicated_host_disk_management": resourceIBMISDedicatedHostDiskManagement(), - "ibm_is_placement_group": resourceIbmIsPlacementGroup(), - "ibm_is_floating_ip": resourceIBMISFloatingIP(), - "ibm_is_flow_log": resourceIBMISFlowLog(), - "ibm_is_instance": resourceIBMISInstance(), - "ibm_is_instance_disk_management": resourceIBMISInstanceDiskManagement(), - "ibm_is_instance_group": resourceIBMISInstanceGroup(), - "ibm_is_instance_group_membership": resourceIBMISInstanceGroupMembership(), - "ibm_is_instance_group_manager": resourceIBMISInstanceGroupManager(), - "ibm_is_instance_group_manager_policy": resourceIBMISInstanceGroupManagerPolicy(), - "ibm_is_instance_group_manager_action": resourceIBMISInstanceGroupManagerAction(), - "ibm_is_instance_volume_attachment": resourceIBMISInstanceVolumeAttachment(), - "ibm_is_virtual_endpoint_gateway": resourceIBMISEndpointGateway(), - "ibm_is_virtual_endpoint_gateway_ip": resourceIBMISEndpointGatewayIP(), - "ibm_is_instance_template": resourceIBMISInstanceTemplate(), - "ibm_is_ike_policy": resourceIBMISIKEPolicy(), - "ibm_is_ipsec_policy": resourceIBMISIPSecPolicy(), - "ibm_is_lb": resourceIBMISLB(), - "ibm_is_lb_listener": resourceIBMISLBListener(), - "ibm_is_lb_listener_policy": resourceIBMISLBListenerPolicy(), - "ibm_is_lb_listener_policy_rule": resourceIBMISLBListenerPolicyRule(), - "ibm_is_lb_pool": resourceIBMISLBPool(), - "ibm_is_lb_pool_member": resourceIBMISLBPoolMember(), - "ibm_is_network_acl": resourceIBMISNetworkACL(), - "ibm_is_network_acl_rule": resourceIBMISNetworkACLRule(), - "ibm_is_public_gateway": resourceIBMISPublicGateway(), - "ibm_is_security_group": resourceIBMISSecurityGroup(), - "ibm_is_security_group_rule": resourceIBMISSecurityGroupRule(), - "ibm_is_security_group_target": resourceIBMISSecurityGroupTarget(), - "ibm_is_security_group_network_interface_attachment": resourceIBMISSecurityGroupNetworkInterfaceAttachment(), - "ibm_is_subnet": resourceIBMISSubnet(), - "ibm_is_subnet_reserved_ip": resourceIBMISReservedIP(), - "ibm_is_subnet_network_acl_attachment": resourceIBMISSubnetNetworkACLAttachment(), - "ibm_is_ssh_key": resourceIBMISSSHKey(), - "ibm_is_snapshot": resourceIBMSnapshot(), - "ibm_is_volume": resourceIBMISVolume(), - "ibm_is_vpn_gateway": resourceIBMISVPNGateway(), - "ibm_is_vpn_gateway_connection": resourceIBMISVPNGatewayConnection(), - "ibm_is_vpc": resourceIBMISVPC(), - "ibm_is_vpc_address_prefix": resourceIBMISVpcAddressPrefix(), - "ibm_is_vpc_route": resourceIBMISVpcRoute(), - "ibm_is_vpc_routing_table": resourceIBMISVPCRoutingTable(), - "ibm_is_vpc_routing_table_route": resourceIBMISVPCRoutingTableRoute(), - "ibm_is_image": resourceIBMISImage(), - "ibm_lb": resourceIBMLb(), - "ibm_lbaas": resourceIBMLbaas(), - "ibm_lbaas_health_monitor": resourceIBMLbaasHealthMonitor(), - "ibm_lbaas_server_instance_attachment": resourceIBMLbaasServerInstanceAttachment(), - "ibm_lb_service": resourceIBMLbService(), - "ibm_lb_service_group": resourceIBMLbServiceGroup(), - "ibm_lb_vpx": resourceIBMLbVpx(), - "ibm_lb_vpx_ha": resourceIBMLbVpxHa(), - "ibm_lb_vpx_service": resourceIBMLbVpxService(), - "ibm_lb_vpx_vip": resourceIBMLbVpxVip(), - "ibm_multi_vlan_firewall": resourceIBMMultiVlanFirewall(), - "ibm_network_gateway": resourceIBMNetworkGateway(), - "ibm_network_gateway_vlan_association": resourceIBMNetworkGatewayVlanAttachment(), - "ibm_network_interface_sg_attachment": resourceIBMNetworkInterfaceSGAttachment(), - "ibm_network_public_ip": resourceIBMNetworkPublicIp(), - "ibm_network_vlan": resourceIBMNetworkVlan(), - "ibm_network_vlan_spanning": resourceIBMNetworkVlanSpan(), - "ibm_object_storage_account": resourceIBMObjectStorageAccount(), - "ibm_org": resourceIBMOrg(), - "ibm_pn_application_chrome": resourceIBMPNApplicationChrome(), - "ibm_app_config_environment": resourceIbmAppConfigEnvironment(), - "ibm_app_config_feature": resourceIbmIbmAppConfigFeature(), - "ibm_kms_key": resourceIBMKmskey(), - "ibm_kms_key_alias": resourceIBMKmskeyAlias(), - "ibm_kms_key_rings": resourceIBMKmskeyRings(), - "ibm_kms_key_policies": resourceIBMKmskeyPolicies(), - "ibm_kp_key": resourceIBMkey(), - "ibm_resource_group": resourceIBMResourceGroup(), - "ibm_resource_instance": resourceIBMResourceInstance(), - "ibm_resource_key": resourceIBMResourceKey(), - "ibm_security_group": resourceIBMSecurityGroup(), - "ibm_security_group_rule": resourceIBMSecurityGroupRule(), - "ibm_service_instance": resourceIBMServiceInstance(), - "ibm_service_key": resourceIBMServiceKey(), - "ibm_space": resourceIBMSpace(), - "ibm_storage_evault": resourceIBMStorageEvault(), - "ibm_storage_block": resourceIBMStorageBlock(), - "ibm_storage_file": resourceIBMStorageFile(), - "ibm_subnet": resourceIBMSubnet(), - "ibm_dns_reverse_record": resourceIBMDNSReverseRecord(), - "ibm_ssl_certificate": resourceIBMSSLCertificate(), - "ibm_cdn": resourceIBMCDN(), - "ibm_hardware_firewall_shared": resourceIBMFirewallShared(), - - //Added for Power Colo - - "ibm_pi_key": resourceIBMPIKey(), - "ibm_pi_volume": resourceIBMPIVolume(), - "ibm_pi_network": resourceIBMPINetwork(), - "ibm_pi_instance": resourceIBMPIInstance(), - "ibm_pi_operations": resourceIBMPIIOperations(), - "ibm_pi_volume_attach": resourceIBMPIVolumeAttach(), - "ibm_pi_capture": resourceIBMPICapture(), - "ibm_pi_image": resourceIBMPIImage(), - "ibm_pi_network_port": resourceIBMPINetworkPort(), - "ibm_pi_snapshot": resourceIBMPISnapshot(), - "ibm_pi_network_port_attach": resourceIBMPINetworkPortAttach(), - - //Private DNS related resources - "ibm_dns_zone": resourceIBMPrivateDNSZone(), - "ibm_dns_permitted_network": resourceIBMPrivateDNSPermittedNetwork(), - "ibm_dns_resource_record": resourceIBMPrivateDNSResourceRecord(), - "ibm_dns_glb_monitor": resourceIBMPrivateDNSGLBMonitor(), - "ibm_dns_glb_pool": resourceIBMPrivateDNSGLBPool(), - "ibm_dns_glb": resourceIBMPrivateDNSGLB(), - - //Added for Custom Resolver - "ibm_dns_custom_resolver": resouceIBMPrivateDNSCustomResolver(), - "ibm_dns_custom_resolver_location": resourceIBMPrivateDNSCRLocation(), - "ibm_dns_custom_resolver_forwarding_rule": resourceIBMPrivateDNSForwardingRule(), - - //Direct Link related resources - "ibm_dl_gateway": resourceIBMDLGateway(), - "ibm_dl_virtual_connection": resourceIBMDLGatewayVC(), - "ibm_dl_provider_gateway": resourceIBMDLProviderGateway(), - //Added for Transit Gateway - "ibm_tg_gateway": resourceIBMTransitGateway(), - "ibm_tg_connection": resourceIBMTransitGatewayConnection(), - - //Catalog related resources - "ibm_cm_offering_instance": resourceIBMCmOfferingInstance(), - "ibm_cm_catalog": resourceIBMCmCatalog(), - "ibm_cm_offering": resourceIBMCmOffering(), - "ibm_cm_version": resourceIBMCmVersion(), - - //Added for enterprise - "ibm_enterprise": resourceIbmEnterprise(), - "ibm_enterprise_account_group": resourceIbmEnterpriseAccountGroup(), - "ibm_enterprise_account": resourceIbmEnterpriseAccount(), - - //Added for Schematics - "ibm_schematics_workspace": resourceIBMSchematicsWorkspace(), - "ibm_schematics_action": resourceIBMSchematicsAction(), - "ibm_schematics_job": resourceIBMSchematicsJob(), - - //satellite resources - "ibm_satellite_location": resourceIBMSatelliteLocation(), - "ibm_satellite_host": resourceIBMSatelliteHost(), - "ibm_satellite_cluster": resourceIBMSatelliteCluster(), - "ibm_satellite_cluster_worker_pool": resourceIBMSatelliteClusterWorkerPool(), - "ibm_satellite_link": resourceIbmSatelliteLink(), - "ibm_satellite_endpoint": resourceIbmSatelliteEndpoint(), - - //Added for Resource Tag - "ibm_resource_tag": resourceIBMResourceTag(), - - // Atracker - "ibm_atracker_target": resourceIBMAtrackerTarget(), - "ibm_atracker_route": resourceIBMAtrackerRoute(), - - //Security and Compliance Center - "ibm_scc_si_note": resourceIBMSccSiNote(), - - // Added for Event Notifications - "ibm_en_destination": resourceIBMEnDestination(), - "ibm_en_topic": resourceIBMEnTopic(), - "ibm_en_subscription": resourceIBMEnSubscription(), - }, - - ConfigureFunc: providerConfigure, - } -} - -var globalValidatorDict ValidatorDict -var initOnce sync.Once - -// Validator return validator -func Validator() ValidatorDict { - initOnce.Do(func() { - globalValidatorDict = ValidatorDict{ - ResourceValidatorDictionary: map[string]*ResourceValidator{ - "ibm_iam_account_settings": resourceIBMIAMAccountSettingsValidator(), - "ibm_iam_custom_role": resourceIBMIAMCustomRoleValidator(), - "ibm_cis_healthcheck": resourceIBMCISHealthCheckValidator(), - "ibm_cis_rate_limit": resourceIBMCISRateLimitValidator(), - "ibm_cis": resourceIBMCISValidator(), - "ibm_cis_domain_settings": resourceIBMCISDomainSettingValidator(), - "ibm_cis_tls_settings": resourceIBMCISTLSSettingsValidator(), - "ibm_cis_routing": resourceIBMCISRoutingValidator(), - "ibm_cis_page_rule": resourceCISPageRuleValidator(), - "ibm_cis_waf_package": resourceIBMCISWAFPackageValidator(), - "ibm_cis_waf_group": resourceIBMCISWAFGroupValidator(), - "ibm_cis_certificate_upload": resourceCISCertificateUploadValidator(), - "ibm_cis_cache_settings": resourceIBMCISCacheSettingsValidator(), - "ibm_cis_custom_page": resourceIBMCISCustomPageValidator(), - "ibm_cis_firewall": resourceIBMCISFirewallValidator(), - "ibm_cis_range_app": resourceIBMCISRangeAppValidator(), - "ibm_cis_waf_rule": resourceIBMCISWAFRuleValidator(), - "ibm_cis_certificate_order": resourceIBMCISCertificateOrderValidator(), - "ibm_cis_filter": resourceIBMCISFilterValidator(), - "ibm_cis_firewall_rules": resourceIBMCISFirewallrulesValidator(), - "ibm_container_cluster": resourceIBMContainerClusterValidator(), - "ibm_container_worker_pool": resourceContainerWorkerPoolValidator(), - "ibm_container_vpc_worker_pool": resourceContainerVPCWorkerPoolValidator(), - "ibm_container_vpc_cluster": resourceIBMContainerVpcClusterValidator(), - "ibm_cr_namespace": resourceIBMCrNamespaceValidator(), - "ibm_tg_gateway": resourceIBMTGValidator(), - "ibm_app_config_feature": resourceIbmAppConfigFeatureValidator(), - "ibm_tg_connection": resourceIBMTransitGatewayConnectionValidator(), - "ibm_dl_virtual_connection": resourceIBMdlGatewayVCValidator(), - "ibm_dl_gateway": resourceIBMDLGatewayValidator(), - "ibm_dl_provider_gateway": resourceIBMDLProviderGatewayValidator(), - "ibm_database": resourceIBMICDValidator(), - "ibm_function_package": resourceIBMFuncPackageValidator(), - "ibm_function_action": resourceIBMFuncActionValidator(), - "ibm_function_rule": resourceIBMFuncRuleValidator(), - "ibm_function_trigger": resourceIBMFuncTriggerValidator(), - "ibm_function_namespace": resourceIBMFuncNamespaceValidator(), - "ibm_hpcs": resourceIBMHPCSValidator(), - "ibm_is_dedicated_host_group": resourceIbmIsDedicatedHostGroupValidator(), - "ibm_is_dedicated_host": resourceIbmIsDedicatedHostValidator(), - "ibm_is_dedicated_host_disk_management": resourceIBMISDedicatedHostDiskManagementValidator(), - "ibm_is_flow_log": resourceIBMISFlowLogValidator(), - "ibm_is_instance_group": resourceIBMISInstanceGroupValidator(), - "ibm_is_instance_group_membership": resourceIBMISInstanceGroupMembershipValidator(), - "ibm_is_instance_group_manager": resourceIBMISInstanceGroupManagerValidator(), - "ibm_is_instance_group_manager_policy": resourceIBMISInstanceGroupManagerPolicyValidator(), - "ibm_is_instance_group_manager_action": resourceIBMISInstanceGroupManagerActionValidator(), - "ibm_is_floating_ip": resourceIBMISFloatingIPValidator(), - "ibm_is_ike_policy": resourceIBMISIKEValidator(), - "ibm_is_image": resourceIBMISImageValidator(), - "ibm_is_instance_template": resourceIBMISInstanceTemplateValidator(), - "ibm_is_instance": resourceIBMISInstanceValidator(), - "ibm_is_instance_disk_management": resourceIBMISInstanceDiskManagementValidator(), - "ibm_is_instance_volume_attachment": resourceIBMISInstanceVolumeAttachmentValidator(), - "ibm_is_ipsec_policy": resourceIBMISIPSECValidator(), - "ibm_is_lb_listener_policy_rule": resourceIBMISLBListenerPolicyRuleValidator(), - "ibm_is_lb_listener_policy": resourceIBMISLBListenerPolicyValidator(), - "ibm_is_lb_listener": resourceIBMISLBListenerValidator(), - "ibm_is_lb_pool_member": resourceIBMISLBPoolMemberValidator(), - "ibm_is_lb_pool": resourceIBMISLBPoolValidator(), - "ibm_is_lb": resourceIBMISLBValidator(), - "ibm_is_network_acl": resourceIBMISNetworkACLValidator(), - "ibm_is_network_acl_rule": resourceIBMISNetworkACLRuleValidator(), - "ibm_is_public_gateway": resourceIBMISPublicGatewayValidator(), - "ibm_is_placement_group": resourceIbmIsPlacementGroupValidator(), - "ibm_is_security_group_target": resourceIBMISSecurityGroupTargetValidator(), - "ibm_is_security_group_rule": resourceIBMISSecurityGroupRuleValidator(), - "ibm_is_security_group": resourceIBMISSecurityGroupValidator(), - "ibm_is_snapshot": resourceIBMISSnapshotValidator(), - "ibm_is_ssh_key": resourceIBMISSHKeyValidator(), - "ibm_is_subnet": resourceIBMISSubnetValidator(), - "ibm_is_subnet_reserved_ip": resourceIBMISSubnetReservedIPValidator(), - "ibm_is_volume": resourceIBMISVolumeValidator(), - "ibm_is_address_prefix": resourceIBMISAddressPrefixValidator(), - "ibm_is_route": resourceIBMISRouteValidator(), - "ibm_is_vpc": resourceIBMISVPCValidator(), - "ibm_is_vpc_routing_table": resourceIBMISVPCRoutingTableValidator(), - "ibm_is_vpc_routing_table_route": resourceIBMISVPCRoutingTableRouteValidator(), - "ibm_is_vpn_gateway_connection": resourceIBMISVPNGatewayConnectionValidator(), - "ibm_is_vpn_gateway": resourceIBMISVPNGatewayValidator(), - "ibm_kms_key_rings": resourceIBMKeyRingValidator(), - "ibm_dns_glb_monitor": resourceIBMPrivateDNSGLBMonitorValidator(), - "ibm_dns_glb_pool": resourceIBMPrivateDNSGLBPoolValidator(), - "ibm_dns_custom_resolver_forwarding_rule": resourceIBMPrivateDNSForwardingRuleValidator(), - "ibm_schematics_action": resourceIBMSchematicsActionValidator(), - "ibm_schematics_job": resourceIBMSchematicsJobValidator(), - "ibm_schematics_workspace": resourceIBMSchematicsWorkspaceValidator(), - "ibm_resource_instance": resourceIBMResourceInstanceValidator(), - "ibm_is_virtual_endpoint_gateway": resourceIBMISEndpointGatewayValidator(), - "ibm_resource_tag": resourceIBMResourceTagValidator(), - "ibm_satellite_location": resourceIBMSatelliteLocationValidator(), - "ibm_satellite_cluster": resourceIBMSatelliteClusterValidator(), - "ibm_pi_volume": resourceIBMPIVolumeValidator(), - "ibm_atracker_target": resourceIBMAtrackerTargetValidator(), - "ibm_atracker_route": resourceIBMAtrackerRouteValidator(), - "ibm_satellite_endpoint": resourceIbmSatelliteEndpointValidator(), - "ibm_scc_si_note": resourceIBMSccSiNoteValidator(), - - // Added for Event Notifications - "ibm_en_destination": resourceIBMEnDestinationValidator(), - }, - DataSourceValidatorDictionary: map[string]*ResourceValidator{ - "ibm_is_subnet": dataSourceIBMISSubnetValidator(), - "ibm_is_snapshot": dataSourceIBMISSnapshotValidator(), - "ibm_dl_offering_speeds": datasourceIBMDLOfferingSpeedsValidator(), - "ibm_dl_routers": datasourceIBMDLRoutersValidator(), - "ibm_is_vpc": dataSourceIBMISVpcValidator(), - "ibm_is_volume": dataSourceIBMISVolumeValidator(), - "ibm_scc_si_notes": dataSourceIBMSccSiNotesValidator(), - "ibm_secrets_manager_secret": datasourceIBMSecretsManagerSecretValidator(), - "ibm_secrets_manager_secrets": datasourceIBMSecretsManagerSecretsValidator(), - }, - } - }) - return globalValidatorDict -} - -func providerConfigure(d *schema.ResourceData) (interface{}, error) { - var bluemixAPIKey string - var bluemixTimeout int - var iamToken, iamRefreshToken string - if key, ok := d.GetOk("bluemix_api_key"); ok { - bluemixAPIKey = key.(string) - } - if key, ok := d.GetOk("ibmcloud_api_key"); ok { - bluemixAPIKey = key.(string) - } - if itoken, ok := d.GetOk("iam_token"); ok { - iamToken = itoken.(string) - } - if rtoken, ok := d.GetOk("iam_refresh_token"); ok { - iamRefreshToken = rtoken.(string) - } - var softlayerUsername, softlayerAPIKey, softlayerEndpointUrl string - var softlayerTimeout int - if username, ok := d.GetOk("softlayer_username"); ok { - softlayerUsername = username.(string) - } - if username, ok := d.GetOk("iaas_classic_username"); ok { - softlayerUsername = username.(string) - } - if apikey, ok := d.GetOk("softlayer_api_key"); ok { - softlayerAPIKey = apikey.(string) - } - if apikey, ok := d.GetOk("iaas_classic_api_key"); ok { - softlayerAPIKey = apikey.(string) - } - if endpoint, ok := d.GetOk("softlayer_endpoint_url"); ok { - softlayerEndpointUrl = endpoint.(string) - } - if endpoint, ok := d.GetOk("iaas_classic_endpoint_url"); ok { - softlayerEndpointUrl = endpoint.(string) - } - if tm, ok := d.GetOk("softlayer_timeout"); ok { - softlayerTimeout = tm.(int) - } - if tm, ok := d.GetOk("iaas_classic_timeout"); ok { - softlayerTimeout = tm.(int) - } - - if tm, ok := d.GetOk("bluemix_timeout"); ok { - bluemixTimeout = tm.(int) - } - if tm, ok := d.GetOk("ibmcloud_timeout"); ok { - bluemixTimeout = tm.(int) - } - var visibility string - if v, ok := d.GetOk("visibility"); ok { - visibility = v.(string) - } - var file string - if f, ok := d.GetOk("endpoints_file_path"); ok { - file = f.(string) - } - - resourceGrp := d.Get("resource_group").(string) - region := d.Get("region").(string) - zone := d.Get("zone").(string) - retryCount := d.Get("max_retries").(int) - wskNameSpace := d.Get("function_namespace").(string) - riaasEndPoint := d.Get("riaas_endpoint").(string) - - wskEnvVal, err := schema.EnvDefaultFunc("FUNCTION_NAMESPACE", "")() - if err != nil { - return nil, err - } - //Set environment variable to be used in DiffSupressFunction - if wskEnvVal.(string) == "" { - os.Setenv("FUNCTION_NAMESPACE", wskNameSpace) - } - - config := Config{ - BluemixAPIKey: bluemixAPIKey, - Region: region, - ResourceGroup: resourceGrp, - BluemixTimeout: time.Duration(bluemixTimeout) * time.Second, - SoftLayerTimeout: time.Duration(softlayerTimeout) * time.Second, - SoftLayerUserName: softlayerUsername, - SoftLayerAPIKey: softlayerAPIKey, - RetryCount: retryCount, - SoftLayerEndpointURL: softlayerEndpointUrl, - RetryDelay: RetryAPIDelay, - FunctionNameSpace: wskNameSpace, - RiaasEndPoint: riaasEndPoint, - IAMToken: iamToken, - IAMRefreshToken: iamRefreshToken, - Zone: zone, - Visibility: visibility, - EndpointsFile: file, - //PowerServiceInstance: powerServiceInstance, - } - - return config.ClientSession() -} diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go new file mode 100644 index 000000000..3f97a8355 --- /dev/null +++ b/ibm/provider/provider.go @@ -0,0 +1,1543 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package provider + +import ( + "os" + "sync" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/apigateway" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/appconfiguration" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/appid" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/atracker" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/catalogmanagement" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cdtektonpipeline" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cdtoolchain" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/certificatemanager" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cis" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/classicinfrastructure" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cloudant" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cloudfoundry" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cloudshell" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/contextbasedrestrictions" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cos" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/database" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/directlink" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/dnsservices" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/enterprise" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/eventnotification" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/eventstreams" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/functions" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/globaltagging" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/hpcs" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/iamaccessgroup" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/iamidentity" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/iampolicy" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kms" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kubernetes" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/pushnotification" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/registry" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcecontroller" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcemanager" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/satellite" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/scc" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/schematics" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/secretsmanager" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/transitgateway" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +// Provider returns a *schema.Provider. +func Provider() *schema.Provider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "bluemix_api_key": { + Type: schema.TypeString, + Optional: true, + Description: "The Bluemix API Key", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"BM_API_KEY", "BLUEMIX_API_KEY"}, nil), + Deprecated: "This field is deprecated please use ibmcloud_api_key", + }, + "bluemix_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "The timeout (in seconds) to set for any Bluemix API calls made.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"BM_TIMEOUT", "BLUEMIX_TIMEOUT"}, nil), + Deprecated: "This field is deprecated please use ibmcloud_timeout", + }, + "ibmcloud_api_key": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM Cloud API Key", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_API_KEY", "IBMCLOUD_API_KEY"}, nil), + }, + "ibmcloud_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "The timeout (in seconds) to set for any IBM Cloud API calls made.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_TIMEOUT", "IBMCLOUD_TIMEOUT"}, 60), + }, + "region": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM cloud Region (for example 'us-south').", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_REGION", "IBMCLOUD_REGION", "BM_REGION", "BLUEMIX_REGION"}, "us-south"), + }, + "zone": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM cloud Region zone (for example 'us-south-1') for power resources.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_ZONE", "IBMCLOUD_ZONE"}, ""), + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "The Resource group id.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_RESOURCE_GROUP", "IBMCLOUD_RESOURCE_GROUP", "BM_RESOURCE_GROUP", "BLUEMIX_RESOURCE_GROUP"}, ""), + }, + "softlayer_api_key": { + Type: schema.TypeString, + Optional: true, + Description: "The SoftLayer API Key", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_API_KEY", "SOFTLAYER_API_KEY"}, nil), + Deprecated: "This field is deprecated please use iaas_classic_api_key", + }, + "softlayer_username": { + Type: schema.TypeString, + Optional: true, + Description: "The SoftLayer user name", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_USERNAME", "SOFTLAYER_USERNAME"}, nil), + Deprecated: "This field is deprecated please use iaas_classic_username", + }, + "softlayer_endpoint_url": { + Type: schema.TypeString, + Optional: true, + Description: "The Softlayer Endpoint", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_ENDPOINT_URL", "SOFTLAYER_ENDPOINT_URL"}, nil), + Deprecated: "This field is deprecated please use iaas_classic_endpoint_url", + }, + "softlayer_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "The timeout (in seconds) to set for any SoftLayer API calls made.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"SL_TIMEOUT", "SOFTLAYER_TIMEOUT"}, nil), + Deprecated: "This field is deprecated please use iaas_classic_timeout", + }, + "iaas_classic_api_key": { + Type: schema.TypeString, + Optional: true, + Description: "The Classic Infrastructure API Key", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_API_KEY"}, nil), + }, + "iaas_classic_username": { + Type: schema.TypeString, + Optional: true, + Description: "The Classic Infrastructure API user name", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_USERNAME"}, nil), + }, + "iaas_classic_endpoint_url": { + Type: schema.TypeString, + Optional: true, + Description: "The Classic Infrastructure Endpoint", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_ENDPOINT_URL"}, "https://api.softlayer.com/rest/v3"), + }, + "iaas_classic_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "The timeout (in seconds) to set for any Classic Infrastructure API calls made.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IAAS_CLASSIC_TIMEOUT"}, 60), + }, + "max_retries": { + Type: schema.TypeInt, + Optional: true, + Description: "The retry count to set for API calls.", + DefaultFunc: schema.EnvDefaultFunc("MAX_RETRIES", 10), + }, + "function_namespace": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM Cloud Function namespace", + DefaultFunc: schema.EnvDefaultFunc("FUNCTION_NAMESPACE", nil), + Deprecated: "This field will be deprecated soon", + }, + "riaas_endpoint": { + Type: schema.TypeString, + Optional: true, + Description: "The next generation infrastructure service endpoint url.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"RIAAS_ENDPOINT"}, nil), + Deprecated: "This field is deprecated use generation", + }, + "generation": { + Type: schema.TypeInt, + Optional: true, + Description: "Generation of Virtual Private Cloud. Default is 2", + //DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_GENERATION", "IBMCLOUD_GENERATION"}, nil), + Deprecated: "The generation field is deprecated and will be removed after couple of releases", + }, + "iam_profile_id": { + Type: schema.TypeString, + Optional: true, + Description: "IAM Trusted Profile Authentication token", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_IAM_PROFILE_ID", "IBMCLOUD_IAM_PROFILE_ID"}, nil), + }, + "iam_token": { + Type: schema.TypeString, + Optional: true, + Description: "IAM Authentication token", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_IAM_TOKEN", "IBMCLOUD_IAM_TOKEN"}, nil), + }, + "iam_refresh_token": { + Type: schema.TypeString, + Optional: true, + Description: "IAM Authentication refresh token", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_IAM_REFRESH_TOKEN", "IBMCLOUD_IAM_REFRESH_TOKEN"}, nil), + }, + "visibility": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "public-and-private"}), + Description: "Visibility of the provider if it is private or public.", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_VISIBILITY", "IBMCLOUD_VISIBILITY"}, "public"), + }, + "endpoints_file_path": { + Type: schema.TypeString, + Optional: true, + Description: "Path of the file that contains private and public regional endpoints mapping", + DefaultFunc: schema.MultiEnvDefaultFunc([]string{"IC_ENDPOINTS_FILE_PATH", "IBMCLOUD_ENDPOINTS_FILE_PATH"}, nil), + }, + }, + + DataSourcesMap: map[string]*schema.Resource{ + "ibm_api_gateway": apigateway.DataSourceIBMApiGateway(), + "ibm_account": cloudfoundry.DataSourceIBMAccount(), + "ibm_app": cloudfoundry.DataSourceIBMApp(), + "ibm_app_domain_private": cloudfoundry.DataSourceIBMAppDomainPrivate(), + "ibm_app_domain_shared": cloudfoundry.DataSourceIBMAppDomainShared(), + "ibm_app_route": cloudfoundry.DataSourceIBMAppRoute(), + + // // AppID + "ibm_appid_action_url": appid.DataSourceIBMAppIDActionURL(), + "ibm_appid_apm": appid.DataSourceIBMAppIDAPM(), + "ibm_appid_application": appid.DataSourceIBMAppIDApplication(), + "ibm_appid_application_scopes": appid.DataSourceIBMAppIDApplicationScopes(), + "ibm_appid_application_roles": appid.DataSourceIBMAppIDApplicationRoles(), + "ibm_appid_applications": appid.DataSourceIBMAppIDApplications(), + "ibm_appid_audit_status": appid.DataSourceIBMAppIDAuditStatus(), + "ibm_appid_cloud_directory_template": appid.DataSourceIBMAppIDCloudDirectoryTemplate(), + "ibm_appid_cloud_directory_user": appid.DataSourceIBMAppIDCloudDirectoryUser(), + "ibm_appid_idp_cloud_directory": appid.DataSourceIBMAppIDIDPCloudDirectory(), + "ibm_appid_idp_custom": appid.DataSourceIBMAppIDIDPCustom(), + "ibm_appid_idp_facebook": appid.DataSourceIBMAppIDIDPFacebook(), + "ibm_appid_idp_google": appid.DataSourceIBMAppIDIDPGoogle(), + "ibm_appid_idp_saml": appid.DataSourceIBMAppIDIDPSAML(), + "ibm_appid_idp_saml_metadata": appid.DataSourceIBMAppIDIDPSAMLMetadata(), + "ibm_appid_languages": appid.DataSourceIBMAppIDLanguages(), + "ibm_appid_mfa": appid.DataSourceIBMAppIDMFA(), + "ibm_appid_mfa_channel": appid.DataSourceIBMAppIDMFAChannel(), + "ibm_appid_password_regex": appid.DataSourceIBMAppIDPasswordRegex(), + "ibm_appid_token_config": appid.DataSourceIBMAppIDTokenConfig(), + "ibm_appid_redirect_urls": appid.DataSourceIBMAppIDRedirectURLs(), + "ibm_appid_role": appid.DataSourceIBMAppIDRole(), + "ibm_appid_roles": appid.DataSourceIBMAppIDRoles(), + "ibm_appid_theme_color": appid.DataSourceIBMAppIDThemeColor(), + "ibm_appid_theme_text": appid.DataSourceIBMAppIDThemeText(), + "ibm_appid_user_roles": appid.DataSourceIBMAppIDUserRoles(), + + "ibm_function_action": functions.DataSourceIBMFunctionAction(), + "ibm_function_package": functions.DataSourceIBMFunctionPackage(), + "ibm_function_rule": functions.DataSourceIBMFunctionRule(), + "ibm_function_trigger": functions.DataSourceIBMFunctionTrigger(), + "ibm_function_namespace": functions.DataSourceIBMFunctionNamespace(), + "ibm_certificate_manager_certificates": certificatemanager.DataIBMCertificateManagerCertificates(), + "ibm_certificate_manager_certificate": certificatemanager.DataIBMCertificateManagerCertificate(), + "ibm_cis": cis.DataSourceIBMCISInstance(), + "ibm_cis_dns_records": cis.DataSourceIBMCISDNSRecords(), + "ibm_cis_certificates": cis.DataSourceIBMCISCertificates(), + "ibm_cis_global_load_balancers": cis.DataSourceIBMCISGlbs(), + "ibm_cis_origin_pools": cis.DataSourceIBMCISOriginPools(), + "ibm_cis_healthchecks": cis.DataSourceIBMCISHealthChecks(), + "ibm_cis_domain": cis.DataSourceIBMCISDomain(), + "ibm_cis_firewall": cis.DataSourceIBMCISFirewallsRecord(), + "ibm_cis_cache_settings": cis.DataSourceIBMCISCacheSetting(), + "ibm_cis_waf_packages": cis.DataSourceIBMCISWAFPackages(), + "ibm_cis_range_apps": cis.DataSourceIBMCISRangeApps(), + "ibm_cis_custom_certificates": cis.DataSourceIBMCISCustomCertificates(), + "ibm_cis_rate_limit": cis.DataSourceIBMCISRateLimit(), + "ibm_cis_ip_addresses": cis.DataSourceIBMCISIP(), + "ibm_cis_waf_groups": cis.DataSourceIBMCISWAFGroups(), + "ibm_cis_alerts": cis.DataSourceIBMCISAlert(), + "ibm_cis_origin_auths": cis.DataSourceIBMCISOriginAuthPull(), + "ibm_cis_mtlss": cis.DataSourceIBMCISMtls(), + "ibm_cis_mtls_apps": cis.DataSourceIBMCISMtlsApp(), + "ibm_cis_webhooks": cis.DataSourceIBMCISWebhooks(), + "ibm_cis_logpush_jobs": cis.DataSourceIBMCISLogPushJobs(), + "ibm_cis_edge_functions_actions": cis.DataSourceIBMCISEdgeFunctionsActions(), + "ibm_cis_edge_functions_triggers": cis.DataSourceIBMCISEdgeFunctionsTriggers(), + "ibm_cis_custom_pages": cis.DataSourceIBMCISCustomPages(), + "ibm_cis_page_rules": cis.DataSourceIBMCISPageRules(), + "ibm_cis_waf_rules": cis.DataSourceIBMCISWAFRules(), + "ibm_cis_filters": cis.DataSourceIBMCISFilters(), + "ibm_cis_firewall_rules": cis.DataSourceIBMCISFirewallRules(), + "ibm_cloudant": cloudant.DataSourceIBMCloudant(), + "ibm_cloudant_database": cloudant.DataSourceIBMCloudantDatabase(), + "ibm_database": database.DataSourceIBMDatabaseInstance(), + "ibm_database_connection": database.DataSourceIBMDatabaseConnection(), + "ibm_database_point_in_time_recovery": database.DataSourceIBMDatabasePointInTimeRecovery(), + "ibm_database_remotes": database.DataSourceIBMDatabaseRemotes(), + "ibm_database_task": database.DataSourceIBMDatabaseTask(), + "ibm_database_tasks": database.DataSourceIBMDatabaseTasks(), + "ibm_database_backup": database.DataSourceIBMDatabaseBackup(), + "ibm_database_backups": database.DataSourceIBMDatabaseBackups(), + "ibm_compute_bare_metal": classicinfrastructure.DataSourceIBMComputeBareMetal(), + "ibm_compute_image_template": classicinfrastructure.DataSourceIBMComputeImageTemplate(), + "ibm_compute_placement_group": classicinfrastructure.DataSourceIBMComputePlacementGroup(), + "ibm_compute_reserved_capacity": classicinfrastructure.DataSourceIBMComputeReservedCapacity(), + "ibm_compute_ssh_key": classicinfrastructure.DataSourceIBMComputeSSHKey(), + "ibm_compute_vm_instance": classicinfrastructure.DataSourceIBMComputeVmInstance(), + "ibm_container_addons": kubernetes.DataSourceIBMContainerAddOns(), + "ibm_container_alb": kubernetes.DataSourceIBMContainerALB(), + "ibm_container_alb_cert": kubernetes.DataSourceIBMContainerALBCert(), + "ibm_container_bind_service": kubernetes.DataSourceIBMContainerBindService(), + "ibm_container_cluster": kubernetes.DataSourceIBMContainerCluster(), + "ibm_container_cluster_config": kubernetes.DataSourceIBMContainerClusterConfig(), + "ibm_container_cluster_versions": kubernetes.DataSourceIBMContainerClusterVersions(), + "ibm_container_cluster_worker": kubernetes.DataSourceIBMContainerClusterWorker(), + "ibm_container_nlb_dns": kubernetes.DataSourceIBMContainerNLBDNS(), + "ibm_container_vpc_cluster_alb": kubernetes.DataSourceIBMContainerVPCClusterALB(), + "ibm_container_vpc_alb": kubernetes.DataSourceIBMContainerVPCClusterALB(), + "ibm_container_vpc_cluster": kubernetes.DataSourceIBMContainerVPCCluster(), + "ibm_container_vpc_cluster_worker": kubernetes.DataSourceIBMContainerVPCClusterWorker(), + "ibm_container_vpc_cluster_worker_pool": kubernetes.DataSourceIBMContainerVpcClusterWorkerPool(), + "ibm_container_vpc_worker_pool": kubernetes.DataSourceIBMContainerVpcClusterWorkerPool(), + "ibm_container_worker_pool": kubernetes.DataSourceIBMContainerWorkerPool(), + "ibm_container_storage_attachment": kubernetes.DataSourceIBMContainerVpcWorkerVolumeAttachment(), + "ibm_container_dedicated_host_pool": kubernetes.DataSourceIBMContainerDedicatedHostPool(), + "ibm_container_dedicated_host_flavor": kubernetes.DataSourceIBMContainerDedicatedHostFlavor(), + "ibm_container_dedicated_host_flavors": kubernetes.DataSourceIBMContainerDedicatedHostFlavors(), + "ibm_container_dedicated_host": kubernetes.DataSourceIBMContainerDedicatedHost(), + "ibm_cr_namespaces": registry.DataIBMContainerRegistryNamespaces(), + "ibm_cloud_shell_account_settings": cloudshell.DataSourceIBMCloudShellAccountSettings(), + "ibm_cos_bucket": cos.DataSourceIBMCosBucket(), + "ibm_cos_bucket_object": cos.DataSourceIBMCosBucketObject(), + "ibm_dns_domain_registration": classicinfrastructure.DataSourceIBMDNSDomainRegistration(), + "ibm_dns_domain": classicinfrastructure.DataSourceIBMDNSDomain(), + "ibm_dns_secondary": classicinfrastructure.DataSourceIBMDNSSecondary(), + "ibm_event_streams_topic": eventstreams.DataSourceIBMEventStreamsTopic(), + "ibm_event_streams_schema": eventstreams.DataSourceIBMEventStreamsSchema(), + "ibm_hpcs": hpcs.DataSourceIBMHPCS(), + "ibm_hpcs_managed_key": hpcs.DataSourceIbmManagedKey(), + "ibm_hpcs_key_template": hpcs.DataSourceIbmKeyTemplate(), + "ibm_hpcs_keystore": hpcs.DataSourceIbmKeystore(), + "ibm_hpcs_vault": hpcs.DataSourceIbmVault(), + "ibm_iam_access_group": iamaccessgroup.DataSourceIBMIAMAccessGroup(), + "ibm_iam_access_group_policy": iampolicy.DataSourceIBMIAMAccessGroupPolicy(), + "ibm_iam_account_settings": iamidentity.DataSourceIBMIAMAccountSettings(), + "ibm_iam_auth_token": iamidentity.DataSourceIBMIAMAuthToken(), + "ibm_iam_role_actions": iampolicy.DataSourceIBMIAMRoleAction(), + "ibm_iam_users": iamidentity.DataSourceIBMIAMUsers(), + "ibm_iam_roles": iampolicy.DataSourceIBMIAMRole(), + "ibm_iam_user_policy": iampolicy.DataSourceIBMIAMUserPolicy(), + "ibm_iam_authorization_policies": iampolicy.DataSourceIBMIAMAuthorizationPolicies(), + "ibm_iam_user_profile": iamidentity.DataSourceIBMIAMUserProfile(), + "ibm_iam_service_id": iamidentity.DataSourceIBMIAMServiceID(), + "ibm_iam_service_policy": iampolicy.DataSourceIBMIAMServicePolicy(), + "ibm_iam_api_key": iamidentity.DataSourceIBMIamApiKey(), + "ibm_iam_trusted_profile": iamidentity.DataSourceIBMIamTrustedProfile(), + "ibm_iam_trusted_profile_claim_rule": iamidentity.DataSourceIBMIamTrustedProfileClaimRule(), + "ibm_iam_trusted_profile_link": iamidentity.DataSourceIBMIamTrustedProfileLink(), + "ibm_iam_trusted_profile_claim_rules": iamidentity.DataSourceIBMIamTrustedProfileClaimRules(), + "ibm_iam_trusted_profile_links": iamidentity.DataSourceIBMIamTrustedProfileLinks(), + "ibm_iam_trusted_profiles": iamidentity.DataSourceIBMIamTrustedProfiles(), + "ibm_iam_trusted_profile_policy": iampolicy.DataSourceIBMIAMTrustedProfilePolicy(), + + //backup as Service + "ibm_is_backup_policy": vpc.DataSourceIBMIsBackupPolicy(), + "ibm_is_backup_policies": vpc.DataSourceIBMIsBackupPolicies(), + "ibm_is_backup_policy_plan": vpc.DataSourceIBMIsBackupPolicyPlan(), + "ibm_is_backup_policy_plans": vpc.DataSourceIBMIsBackupPolicyPlans(), + + // bare_metal_server + "ibm_is_bare_metal_server_disk": vpc.DataSourceIBMIsBareMetalServerDisk(), + "ibm_is_bare_metal_server_disks": vpc.DataSourceIBMIsBareMetalServerDisks(), + "ibm_is_bare_metal_server_initialization": vpc.DataSourceIBMIsBareMetalServerInitialization(), + "ibm_is_bare_metal_server_network_interface_floating_ip": vpc.DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIP(), + "ibm_is_bare_metal_server_network_interface_floating_ips": vpc.DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIPs(), + "ibm_is_bare_metal_server_network_interface_reserved_ip": vpc.DataSourceIBMISBareMetalServerNICReservedIP(), + "ibm_is_bare_metal_server_network_interface_reserved_ips": vpc.DataSourceIBMISBareMetalServerNICReservedIPs(), + "ibm_is_bare_metal_server_network_interface": vpc.DataSourceIBMIsBareMetalServerNetworkInterface(), + "ibm_is_bare_metal_server_network_interfaces": vpc.DataSourceIBMIsBareMetalServerNetworkInterfaces(), + "ibm_is_bare_metal_server_profile": vpc.DataSourceIBMIsBareMetalServerProfile(), + "ibm_is_bare_metal_server_profiles": vpc.DataSourceIBMIsBareMetalServerProfiles(), + "ibm_is_bare_metal_server": vpc.DataSourceIBMIsBareMetalServer(), + "ibm_is_bare_metal_servers": vpc.DataSourceIBMIsBareMetalServers(), + + "ibm_is_dedicated_host": vpc.DataSourceIbmIsDedicatedHost(), + "ibm_is_dedicated_hosts": vpc.DataSourceIbmIsDedicatedHosts(), + "ibm_is_dedicated_host_profile": vpc.DataSourceIbmIsDedicatedHostProfile(), + "ibm_is_dedicated_host_profiles": vpc.DataSourceIbmIsDedicatedHostProfiles(), + "ibm_is_dedicated_host_group": vpc.DataSourceIbmIsDedicatedHostGroup(), + "ibm_is_dedicated_host_groups": vpc.DataSourceIbmIsDedicatedHostGroups(), + "ibm_is_dedicated_host_disk": vpc.DataSourceIbmIsDedicatedHostDisk(), + "ibm_is_dedicated_host_disks": vpc.DataSourceIbmIsDedicatedHostDisks(), + "ibm_is_placement_group": vpc.DataSourceIbmIsPlacementGroup(), + "ibm_is_placement_groups": vpc.DataSourceIbmIsPlacementGroups(), + "ibm_is_floating_ip": vpc.DataSourceIBMISFloatingIP(), + "ibm_is_floating_ips": vpc.DataSourceIBMIsFloatingIps(), + "ibm_is_flow_log": vpc.DataSourceIBMIsFlowLog(), + "ibm_is_flow_logs": vpc.DataSourceIBMISFlowLogs(), + "ibm_is_image": vpc.DataSourceIBMISImage(), + "ibm_is_images": vpc.DataSourceIBMISImages(), + "ibm_is_endpoint_gateway_targets": vpc.DataSourceIBMISEndpointGatewayTargets(), + "ibm_is_instance_group": vpc.DataSourceIBMISInstanceGroup(), + "ibm_is_instance_groups": vpc.DataSourceIBMISInstanceGroups(), + "ibm_is_instance_group_memberships": vpc.DataSourceIBMISInstanceGroupMemberships(), + "ibm_is_instance_group_membership": vpc.DataSourceIBMISInstanceGroupMembership(), + "ibm_is_instance_group_manager": vpc.DataSourceIBMISInstanceGroupManager(), + "ibm_is_instance_group_managers": vpc.DataSourceIBMISInstanceGroupManagers(), + "ibm_is_instance_group_manager_policies": vpc.DataSourceIBMISInstanceGroupManagerPolicies(), + "ibm_is_instance_group_manager_policy": vpc.DataSourceIBMISInstanceGroupManagerPolicy(), + "ibm_is_instance_group_manager_action": vpc.DataSourceIBMISInstanceGroupManagerAction(), + "ibm_is_instance_group_manager_actions": vpc.DataSourceIBMISInstanceGroupManagerActions(), + "ibm_is_virtual_endpoint_gateways": vpc.DataSourceIBMISEndpointGateways(), + "ibm_is_virtual_endpoint_gateway_ips": vpc.DataSourceIBMISEndpointGatewayIPs(), + "ibm_is_virtual_endpoint_gateway": vpc.DataSourceIBMISEndpointGateway(), + "ibm_is_instance_template": vpc.DataSourceIBMISInstanceTemplate(), + "ibm_is_instance_templates": vpc.DataSourceIBMISInstanceTemplates(), + "ibm_is_instance_profile": vpc.DataSourceIBMISInstanceProfile(), + "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), + "ibm_is_instance": vpc.DataSourceIBMISInstance(), + "ibm_is_instances": vpc.DataSourceIBMISInstances(), + "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), + "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), + "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), + "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), + + // reserved ips + "ibm_is_instance_network_interface_reserved_ip": vpc.DataSourceIBMISInstanceNICReservedIP(), + "ibm_is_instance_network_interface_reserved_ips": vpc.DataSourceIBMISInstanceNICReservedIPs(), + + "ibm_is_instance_volume_attachment": vpc.DataSourceIBMISInstanceVolumeAttachment(), + "ibm_is_instance_volume_attachments": vpc.DataSourceIBMISInstanceVolumeAttachments(), + "ibm_is_ipsec_policy": vpc.DataSourceIBMIsIpsecPolicy(), + "ibm_is_ipsec_policies": vpc.DataSourceIBMIsIpsecPolicies(), + "ibm_is_ike_policies": vpc.DataSourceIBMIsIkePolicies(), + "ibm_is_ike_policy": vpc.DataSourceIBMIsIkePolicy(), + "ibm_is_lb": vpc.DataSourceIBMISLB(), + "ibm_is_lb_listener": vpc.DataSourceIBMISLBListener(), + "ibm_is_lb_listeners": vpc.DataSourceIBMISLBListeners(), + "ibm_is_lb_listener_policies": vpc.DataSourceIBMISLBListenerPolicies(), + "ibm_is_lb_listener_policy": vpc.DataSourceIBMISLBListenerPolicy(), + "ibm_is_lb_listener_policy_rule": vpc.DataSourceIBMISLBListenerPolicyRule(), + "ibm_is_lb_listener_policy_rules": vpc.DataSourceIBMISLBListenerPolicyRules(), + "ibm_is_lb_pool": vpc.DataSourceIBMISLBPool(), + "ibm_is_lb_pools": vpc.DataSourceIBMISLBPools(), + "ibm_is_lb_pool_member": vpc.DataSourceIBMIBLBPoolMember(), + "ibm_is_lb_pool_members": vpc.DataSourceIBMISLBPoolMembers(), + "ibm_is_lb_profiles": vpc.DataSourceIBMISLbProfiles(), + "ibm_is_lbs": vpc.DataSourceIBMISLBS(), + "ibm_is_public_gateway": vpc.DataSourceIBMISPublicGateway(), + "ibm_is_public_gateways": vpc.DataSourceIBMISPublicGateways(), + "ibm_is_region": vpc.DataSourceIBMISRegion(), + "ibm_is_regions": vpc.DataSourceIBMISRegions(), + "ibm_is_ssh_key": vpc.DataSourceIBMISSSHKey(), + "ibm_is_ssh_keys": vpc.DataSourceIBMIsSshKeys(), + "ibm_is_subnet": vpc.DataSourceIBMISSubnet(), + "ibm_is_subnets": vpc.DataSourceIBMISSubnets(), + "ibm_is_subnet_reserved_ip": vpc.DataSourceIBMISReservedIP(), + "ibm_is_subnet_reserved_ips": vpc.DataSourceIBMISReservedIPs(), + "ibm_is_security_group": vpc.DataSourceIBMISSecurityGroup(), + "ibm_is_security_groups": vpc.DataSourceIBMIsSecurityGroups(), + "ibm_is_security_group_rule": vpc.DataSourceIBMIsSecurityGroupRule(), + "ibm_is_security_group_rules": vpc.DataSourceIBMIsSecurityGroupRules(), + "ibm_is_security_group_target": vpc.DataSourceIBMISSecurityGroupTarget(), + "ibm_is_security_group_targets": vpc.DataSourceIBMISSecurityGroupTargets(), + "ibm_is_snapshot": vpc.DataSourceSnapshot(), + "ibm_is_snapshots": vpc.DataSourceSnapshots(), + "ibm_is_volume": vpc.DataSourceIBMISVolume(), + "ibm_is_volumes": vpc.DataSourceIBMIsVolumes(), + "ibm_is_volume_profile": vpc.DataSourceIBMISVolumeProfile(), + "ibm_is_volume_profiles": vpc.DataSourceIBMISVolumeProfiles(), + "ibm_is_vpc": vpc.DataSourceIBMISVPC(), + "ibm_is_vpcs": vpc.DataSourceIBMISVPCs(), + "ibm_is_vpn_gateway": vpc.DataSourceIBMISVPNGateway(), + "ibm_is_vpn_gateways": vpc.DataSourceIBMISVPNGateways(), + "ibm_is_vpc_address_prefixes": vpc.DataSourceIbmIsVpcAddressPrefixes(), + "ibm_is_vpc_address_prefix": vpc.DataSourceIBMIsVPCAddressPrefix(), + "ibm_is_vpn_gateway_connection": vpc.DataSourceIBMISVPNGatewayConnection(), + "ibm_is_vpn_gateway_connections": vpc.DataSourceIBMISVPNGatewayConnections(), + "ibm_is_vpc_default_routing_table": vpc.DataSourceIBMISVPCDefaultRoutingTable(), + "ibm_is_vpc_routing_table": vpc.DataSourceIBMIBMIsVPCRoutingTable(), + "ibm_is_vpc_routing_tables": vpc.DataSourceIBMISVPCRoutingTables(), + "ibm_is_vpc_routing_table_route": vpc.DataSourceIBMIBMIsVPCRoutingTableRoute(), + "ibm_is_vpc_routing_table_routes": vpc.DataSourceIBMISVPCRoutingTableRoutes(), + "ibm_is_vpn_server": vpc.DataSourceIBMIsVPNServer(), + "ibm_is_vpn_servers": vpc.DataSourceIBMIsVPNServers(), + "ibm_is_vpn_server_client": vpc.DataSourceIBMIsVPNServerClient(), + "ibm_is_vpn_server_client_configuration": vpc.DataSourceIBMIsVPNServerClientConfiguration(), + "ibm_is_vpn_server_clients": vpc.DataSourceIBMIsVPNServerClients(), + "ibm_is_vpn_server_route": vpc.DataSourceIBMIsVPNServerRoute(), + "ibm_is_vpn_server_routes": vpc.DataSourceIBMIsVPNServerRoutes(), + "ibm_is_zone": vpc.DataSourceIBMISZone(), + "ibm_is_zones": vpc.DataSourceIBMISZones(), + "ibm_is_operating_system": vpc.DataSourceIBMISOperatingSystem(), + "ibm_is_operating_systems": vpc.DataSourceIBMISOperatingSystems(), + "ibm_is_network_acls": vpc.DataSourceIBMIsNetworkAcls(), + "ibm_is_network_acl": vpc.DataSourceIBMIsNetworkACL(), + "ibm_is_network_acl_rule": vpc.DataSourceIBMISNetworkACLRule(), + "ibm_is_network_acl_rules": vpc.DataSourceIBMISNetworkACLRules(), + "ibm_lbaas": classicinfrastructure.DataSourceIBMLbaas(), + "ibm_network_vlan": classicinfrastructure.DataSourceIBMNetworkVlan(), + "ibm_org": cloudfoundry.DataSourceIBMOrg(), + "ibm_org_quota": cloudfoundry.DataSourceIBMOrgQuota(), + "ibm_kp_key": kms.DataSourceIBMkey(), + "ibm_kms_key_rings": kms.DataSourceIBMKMSkeyRings(), + "ibm_kms_key_policies": kms.DataSourceIBMKMSkeyPolicies(), + "ibm_kms_keys": kms.DataSourceIBMKMSkeys(), + "ibm_kms_key": kms.DataSourceIBMKMSkey(), + "ibm_pn_application_chrome": pushnotification.DataSourceIBMPNApplicationChrome(), + "ibm_app_config_environment": appconfiguration.DataSourceIBMAppConfigEnvironment(), + "ibm_app_config_environments": appconfiguration.DataSourceIBMAppConfigEnvironments(), + "ibm_app_config_collection": appconfiguration.DataSourceIBMAppConfigCollection(), + "ibm_app_config_collections": appconfiguration.DataSourceIBMAppConfigCollections(), + "ibm_app_config_feature": appconfiguration.DataSourceIBMAppConfigFeature(), + "ibm_app_config_features": appconfiguration.DataSourceIBMAppConfigFeatures(), + "ibm_app_config_property": appconfiguration.DataSourceIBMAppConfigProperty(), + "ibm_app_config_properties": appconfiguration.DataSourceIBMAppConfigProperties(), + "ibm_app_config_segment": appconfiguration.DataSourceIBMAppConfigSegment(), + "ibm_app_config_segments": appconfiguration.DataSourceIBMAppConfigSegments(), + "ibm_app_config_snapshot": appconfiguration.DataSourceIBMAppConfigSnapshot(), + "ibm_app_config_snapshots": appconfiguration.DataSourceIBMAppConfigSnapshots(), + + "ibm_resource_quota": resourcecontroller.DataSourceIBMResourceQuota(), + "ibm_resource_group": resourcemanager.DataSourceIBMResourceGroup(), + "ibm_resource_instance": resourcecontroller.DataSourceIBMResourceInstance(), + "ibm_resource_key": resourcecontroller.DataSourceIBMResourceKey(), + "ibm_security_group": classicinfrastructure.DataSourceIBMSecurityGroup(), + "ibm_service_instance": cloudfoundry.DataSourceIBMServiceInstance(), + "ibm_service_key": cloudfoundry.DataSourceIBMServiceKey(), + "ibm_service_plan": cloudfoundry.DataSourceIBMServicePlan(), + "ibm_space": cloudfoundry.DataSourceIBMSpace(), + + // Added for Schematics + "ibm_schematics_workspace": schematics.DataSourceIBMSchematicsWorkspace(), + "ibm_schematics_output": schematics.DataSourceIBMSchematicsOutput(), + "ibm_schematics_state": schematics.DataSourceIBMSchematicsState(), + "ibm_schematics_action": schematics.DataSourceIBMSchematicsAction(), + "ibm_schematics_job": schematics.DataSourceIBMSchematicsJob(), + "ibm_schematics_inventory": schematics.DataSourceIBMSchematicsInventory(), + "ibm_schematics_resource_query": schematics.DataSourceIBMSchematicsResourceQuery(), + + // // Added for Power Resources + + "ibm_pi_catalog_images": power.DataSourceIBMPICatalogImages(), + "ibm_pi_cloud_connection": power.DataSourceIBMPICloudConnection(), + "ibm_pi_cloud_connections": power.DataSourceIBMPICloudConnections(), + "ibm_pi_cloud_instance": power.DataSourceIBMPICloudInstance(), + "ibm_pi_console_languages": power.DataSourceIBMPIInstanceConsoleLanguages(), + "ibm_pi_dhcp": power.DataSourceIBMPIDhcp(), + "ibm_pi_dhcps": power.DataSourceIBMPIDhcps(), + "ibm_pi_image": power.DataSourceIBMPIImage(), + "ibm_pi_images": power.DataSourceIBMPIImages(), + "ibm_pi_instance": power.DataSourceIBMPIInstance(), + "ibm_pi_instances": power.DataSourceIBMPIInstances(), + "ibm_pi_instance_ip": power.DataSourceIBMPIInstanceIP(), + "ibm_pi_instance_snapshots": power.DataSourceIBMPISnapshots(), + "ibm_pi_instance_volumes": power.DataSourceIBMPIInstanceVolumes(), + "ibm_pi_key": power.DataSourceIBMPIKey(), + "ibm_pi_keys": power.DataSourceIBMPIKeys(), + "ibm_pi_network": power.DataSourceIBMPINetwork(), + "ibm_pi_network_port": power.DataSourceIBMPINetworkPort(), + "ibm_pi_placement_group": power.DataSourceIBMPIPlacementGroup(), + "ibm_pi_placement_groups": power.DataSourceIBMPIPlacementGroups(), + "ibm_pi_public_network": power.DataSourceIBMPIPublicNetwork(), + "ibm_pi_pvm_snapshots": power.DataSourceIBMPISnapshot(), + "ibm_pi_sap_profile": power.DataSourceIBMPISAPProfile(), + "ibm_pi_sap_profiles": power.DataSourceIBMPISAPProfiles(), + "ibm_pi_shared_processor_pool": power.DataSourceIBMPISharedProcessorPool(), + "ibm_pi_shared_processor_pools": power.DataSourceIBMPISharedProcessorPools(), + "ibm_pi_spp_placement_group": power.DataSourceIBMPISPPPlacementGroup(), + "ibm_pi_spp_placement_groups": power.DataSourceIBMPISPPPlacementGroups(), + "ibm_pi_storage_pool_capacity": power.DataSourceIBMPIStoragePoolCapacity(), + "ibm_pi_storage_pools_capacity": power.DataSourceIBMPIStoragePoolsCapacity(), + "ibm_pi_storage_type_capacity": power.DataSourceIBMPIStorageTypeCapacity(), + "ibm_pi_storage_types_capacity": power.DataSourceIBMPIStorageTypesCapacity(), + "ibm_pi_system_pools": power.DataSourceIBMPISystemPools(), + "ibm_pi_tenant": power.DataSourceIBMPITenant(), + "ibm_pi_volume": power.DataSourceIBMPIVolume(), + + // // Added for private dns zones + + "ibm_dns_zones": dnsservices.DataSourceIBMPrivateDNSZones(), + "ibm_dns_permitted_networks": dnsservices.DataSourceIBMPrivateDNSPermittedNetworks(), + "ibm_dns_resource_records": dnsservices.DataSourceIBMPrivateDNSResourceRecords(), + "ibm_dns_glb_monitors": dnsservices.DataSourceIBMPrivateDNSGLBMonitors(), + "ibm_dns_glb_pools": dnsservices.DataSourceIBMPrivateDNSGLBPools(), + "ibm_dns_glbs": dnsservices.DataSourceIBMPrivateDNSGLBs(), + "ibm_dns_custom_resolvers": dnsservices.DataSourceIBMPrivateDNSCustomResolver(), + "ibm_dns_custom_resolver_forwarding_rules": dnsservices.DataSourceIBMPrivateDNSForwardingRules(), + "ibm_dns_custom_resolver_secondary_zones": dnsservices.DataSourceIBMPrivateDNSSecondaryZones(), + + // // Added for Direct Link + + "ibm_dl_gateways": directlink.DataSourceIBMDLGateways(), + "ibm_dl_offering_speeds": directlink.DataSourceIBMDLOfferingSpeeds(), + "ibm_dl_port": directlink.DataSourceIBMDirectLinkPort(), + "ibm_dl_ports": directlink.DataSourceIBMDirectLinkPorts(), + "ibm_dl_gateway": directlink.DataSourceIBMDLGateway(), + "ibm_dl_locations": directlink.DataSourceIBMDLLocations(), + "ibm_dl_routers": directlink.DataSourceIBMDLRouters(), + "ibm_dl_provider_ports": directlink.DataSourceIBMDirectLinkProviderPorts(), + "ibm_dl_provider_gateways": directlink.DataSourceIBMDirectLinkProviderGateways(), + "ibm_dl_route_reports": directlink.DataSourceIBMDLRouteReports(), + "ibm_dl_route_report": directlink.DataSourceIBMDLRouteReport(), + + // //Added for Transit Gateway + "ibm_tg_gateway": transitgateway.DataSourceIBMTransitGateway(), + "ibm_tg_gateways": transitgateway.DataSourceIBMTransitGateways(), + "ibm_tg_connection_prefix_filter": transitgateway.DataSourceIBMTransitGatewayConnectionPrefixFilter(), + "ibm_tg_connection_prefix_filters": transitgateway.DataSourceIBMTransitGatewayConnectionPrefixFilters(), + "ibm_tg_locations": transitgateway.DataSourceIBMTransitGatewaysLocations(), + "ibm_tg_location": transitgateway.DataSourceIBMTransitGatewaysLocation(), + "ibm_tg_route_report": transitgateway.DataSourceIBMTransitGatewayRouteReport(), + "ibm_tg_route_reports": transitgateway.DataSourceIBMTransitGatewayRouteReports(), + + // //Added for BSS Enterprise + "ibm_enterprises": enterprise.DataSourceIBMEnterprises(), + "ibm_enterprise_account_groups": enterprise.DataSourceIBMEnterpriseAccountGroups(), + "ibm_enterprise_accounts": enterprise.DataSourceIBMEnterpriseAccounts(), + + // //Added for Secrets Manager + "ibm_secrets_manager_secrets": secretsmanager.DataSourceIBMSecretsManagerSecrets(), + "ibm_secrets_manager_secret": secretsmanager.DataSourceIBMSecretsManagerSecret(), + + // //Added for Satellite + "ibm_satellite_location": satellite.DataSourceIBMSatelliteLocation(), + "ibm_satellite_location_nlb_dns": satellite.DataSourceIBMSatelliteLocationNLBDNS(), + "ibm_satellite_attach_host_script": satellite.DataSourceIBMSatelliteAttachHostScript(), + "ibm_satellite_cluster": satellite.DataSourceIBMSatelliteCluster(), + "ibm_satellite_cluster_worker_pool": satellite.DataSourceIBMSatelliteClusterWorkerPool(), + "ibm_satellite_link": satellite.DataSourceIBMSatelliteLink(), + "ibm_satellite_endpoint": satellite.DataSourceIBMSatelliteEndpoint(), + "ibm_satellite_cluster_worker_pool_zone_attachment": satellite.DataSourceIBMSatelliteClusterWorkerPoolAttachment(), + + // // Catalog related resources + "ibm_cm_catalog": catalogmanagement.DataSourceIBMCmCatalog(), + "ibm_cm_offering": catalogmanagement.DataSourceIBMCmOffering(), + "ibm_cm_version": catalogmanagement.DataSourceIBMCmVersion(), + "ibm_cm_offering_instance": catalogmanagement.DataSourceIBMCmOfferingInstance(), + "ibm_cm_preset": catalogmanagement.DataSourceIBMCmPreset(), + + // //Added for Resource Tag + "ibm_resource_tag": globaltagging.DataSourceIBMResourceTag(), + + // // Atracker + "ibm_atracker_targets": atracker.DataSourceIBMAtrackerTargets(), + "ibm_atracker_routes": atracker.DataSourceIBMAtrackerRoutes(), + "ibm_atracker_endpoints": atracker.DataSourceIBMAtrackerEndpoints(), + + //Security and Compliance Center + "ibm_scc_account_location": scc.DataSourceIBMSccAccountLocation(), + "ibm_scc_account_locations": scc.DataSourceIBMSccAccountLocations(), + "ibm_scc_account_location_settings": scc.DataSourceIBMSccAccountLocationSettings(), + "ibm_scc_account_notification_settings": scc.DataSourceIBMSccNotificationSettings(), + + // Compliance Posture Management + "ibm_scc_posture_scopes": scc.DataSourceIBMSccPostureScopes(), + "ibm_scc_posture_latest_scans": scc.DataSourceIBMSccPostureLatestScans(), + "ibm_scc_posture_profiles": scc.DataSourceIBMSccPostureProfiles(), + "ibm_scc_posture_scan_summary": scc.DataSourceIBMSccPostureScansSummary(), + "ibm_scc_posture_scan_summaries": scc.DataSourceIBMSccPostureScanSummaries(), + "ibm_scc_posture_profile": scc.DataSourceIBMSccPostureProfileDetails(), + "ibm_scc_posture_group_profile": scc.DataSourceIBMSccPostureGroupProfileDetails(), + "ibm_scc_posture_scope_correlation": scc.DataSourceIBMSccPostureScopeCorrelation(), + "ibm_scc_posture_credential": scc.DataSourceIBMSccPostureCredential(), + "ibm_scc_posture_collector": scc.DataSourceIBMSccPostureCollector(), + "ibm_scc_posture_scope": scc.DataSourceIBMSccPostureScope(), + "ibm_scc_posture_credentials": scc.DataSourceIBMSccPostureCredentials(), + "ibm_scc_posture_collectors": scc.DataSourceIBMSccPostureCollectors(), + // // Added for Context Based Restrictions + "ibm_cbr_zone": contextbasedrestrictions.DataSourceIBMCbrZone(), + "ibm_cbr_rule": contextbasedrestrictions.DataSourceIBMCbrRule(), + + // // Added for Event Notifications + "ibm_en_source": eventnotification.DataSourceIBMEnSource(), + "ibm_en_destination": eventnotification.DataSourceIBMEnDestination(), + "ibm_en_destinations": eventnotification.DataSourceIBMEnDestinations(), + "ibm_en_topic": eventnotification.DataSourceIBMEnTopic(), + "ibm_en_topics": eventnotification.DataSourceIBMEnTopics(), + "ibm_en_subscription": eventnotification.DataSourceIBMEnSubscription(), + "ibm_en_subscriptions": eventnotification.DataSourceIBMEnSubscriptions(), + "ibm_en_destination_webhook": eventnotification.DataSourceIBMEnWebhookDestination(), + "ibm_en_destination_android": eventnotification.DataSourceIBMEnFCMDestination(), + "ibm_en_destination_ios": eventnotification.DataSourceIBMEnAPNSDestination(), + "ibm_en_destination_chrome": eventnotification.DataSourceIBMEnChromeDestination(), + "ibm_en_destination_firefox": eventnotification.DataSourceIBMEnFirefoxDestination(), + "ibm_en_destination_slack": eventnotification.DataSourceIBMEnSlackDestination(), + "ibm_en_subscription_sms": eventnotification.DataSourceIBMEnSMSSubscription(), + "ibm_en_subscription_email": eventnotification.DataSourceIBMEnEmailSubscription(), + "ibm_en_subscription_webhook": eventnotification.DataSourceIBMEnWebhookSubscription(), + "ibm_en_subscription_android": eventnotification.DataSourceIBMEnFCMSubscription(), + "ibm_en_subscription_ios": eventnotification.DataSourceIBMEnFCMSubscription(), + "ibm_en_subscription_chrome": eventnotification.DataSourceIBMEnFCMSubscription(), + "ibm_en_subscription_firefox": eventnotification.DataSourceIBMEnFCMSubscription(), + "ibm_en_subscription_slack": eventnotification.DataSourceIBMEnSlackSubscription(), + "ibm_en_subscription_safari": eventnotification.DataSourceIBMEnFCMSubscription(), + "ibm_en_destination_safari": eventnotification.DataSourceIBMEnSafariDestination(), + + // // Added for Toolchain + "ibm_cd_toolchain": cdtoolchain.DataSourceIBMCdToolchain(), + "ibm_cd_toolchain_tool_keyprotect": cdtoolchain.DataSourceIBMCdToolchainToolKeyprotect(), + "ibm_cd_toolchain_tool_secretsmanager": cdtoolchain.DataSourceIBMCdToolchainToolSecretsmanager(), + "ibm_cd_toolchain_tool_bitbucketgit": cdtoolchain.DataSourceIBMCdToolchainToolBitbucketgit(), + "ibm_cd_toolchain_tool_githubintegrated": cdtoolchain.DataSourceIBMCdToolchainToolGithubintegrated(), + "ibm_cd_toolchain_tool_githubconsolidated": cdtoolchain.DataSourceIBMCdToolchainToolGithubconsolidated(), + "ibm_cd_toolchain_tool_gitlab": cdtoolchain.DataSourceIBMCdToolchainToolGitlab(), + "ibm_cd_toolchain_tool_hostedgit": cdtoolchain.DataSourceIBMCdToolchainToolHostedgit(), + "ibm_cd_toolchain_tool_artifactory": cdtoolchain.DataSourceIBMCdToolchainToolArtifactory(), + "ibm_cd_toolchain_tool_custom": cdtoolchain.DataSourceIBMCdToolchainToolCustom(), + "ibm_cd_toolchain_tool_pipeline": cdtoolchain.DataSourceIBMCdToolchainToolPipeline(), + "ibm_cd_toolchain_tool_devopsinsights": cdtoolchain.DataSourceIBMCdToolchainToolDevopsinsights(), + "ibm_cd_toolchain_tool_slack": cdtoolchain.DataSourceIBMCdToolchainToolSlack(), + "ibm_cd_toolchain_tool_sonarqube": cdtoolchain.DataSourceIBMCdToolchainToolSonarqube(), + "ibm_cd_toolchain_tool_hashicorpvault": cdtoolchain.DataSourceIBMCdToolchainToolHashicorpvault(), + "ibm_cd_toolchain_tool_securitycompliance": cdtoolchain.DataSourceIBMCdToolchainToolSecuritycompliance(), + "ibm_cd_toolchain_tool_privateworker": cdtoolchain.DataSourceIBMCdToolchainToolPrivateworker(), + "ibm_cd_toolchain_tool_appconfig": cdtoolchain.DataSourceIBMCdToolchainToolAppconfig(), + "ibm_cd_toolchain_tool_jenkins": cdtoolchain.DataSourceIBMCdToolchainToolJenkins(), + "ibm_cd_toolchain_tool_nexus": cdtoolchain.DataSourceIBMCdToolchainToolNexus(), + "ibm_cd_toolchain_tool_pagerduty": cdtoolchain.DataSourceIBMCdToolchainToolPagerduty(), + "ibm_cd_toolchain_tool_saucelabs": cdtoolchain.DataSourceIBMCdToolchainToolSaucelabs(), + + // Added for Tekton Pipeline + "ibm_cd_tekton_pipeline_definition": cdtektonpipeline.DataSourceIBMCdTektonPipelineDefinition(), + "ibm_cd_tekton_pipeline_trigger_property": cdtektonpipeline.DataSourceIBMCdTektonPipelineTriggerProperty(), + "ibm_cd_tekton_pipeline_property": cdtektonpipeline.DataSourceIBMCdTektonPipelineProperty(), + "ibm_cd_tekton_pipeline_trigger": cdtektonpipeline.DataSourceIBMCdTektonPipelineTrigger(), + "ibm_cd_tekton_pipeline": cdtektonpipeline.DataSourceIBMCdTektonPipeline(), + }, + + ResourcesMap: map[string]*schema.Resource{ + "ibm_api_gateway_endpoint": apigateway.ResourceIBMApiGatewayEndPoint(), + "ibm_api_gateway_endpoint_subscription": apigateway.ResourceIBMApiGatewayEndpointSubscription(), + "ibm_app": cloudfoundry.ResourceIBMApp(), + "ibm_app_domain_private": cloudfoundry.ResourceIBMAppDomainPrivate(), + "ibm_app_domain_shared": cloudfoundry.ResourceIBMAppDomainShared(), + "ibm_app_route": cloudfoundry.ResourceIBMAppRoute(), + + // // AppID + "ibm_appid_action_url": appid.ResourceIBMAppIDActionURL(), + "ibm_appid_apm": appid.ResourceIBMAppIDAPM(), + "ibm_appid_application": appid.ResourceIBMAppIDApplication(), + "ibm_appid_application_scopes": appid.ResourceIBMAppIDApplicationScopes(), + "ibm_appid_application_roles": appid.ResourceIBMAppIDApplicationRoles(), + "ibm_appid_audit_status": appid.ResourceIBMAppIDAuditStatus(), + "ibm_appid_cloud_directory_template": appid.ResourceIBMAppIDCloudDirectoryTemplate(), + "ibm_appid_cloud_directory_user": appid.ResourceIBMAppIDCloudDirectoryUser(), + "ibm_appid_idp_cloud_directory": appid.ResourceIBMAppIDIDPCloudDirectory(), + "ibm_appid_idp_custom": appid.ResourceIBMAppIDIDPCustom(), + "ibm_appid_idp_facebook": appid.ResourceIBMAppIDIDPFacebook(), + "ibm_appid_idp_google": appid.ResourceIBMAppIDIDPGoogle(), + "ibm_appid_idp_saml": appid.ResourceIBMAppIDIDPSAML(), + "ibm_appid_languages": appid.ResourceIBMAppIDLanguages(), + "ibm_appid_mfa": appid.ResourceIBMAppIDMFA(), + "ibm_appid_mfa_channel": appid.ResourceIBMAppIDMFAChannel(), + "ibm_appid_password_regex": appid.ResourceIBMAppIDPasswordRegex(), + "ibm_appid_token_config": appid.ResourceIBMAppIDTokenConfig(), + "ibm_appid_redirect_urls": appid.ResourceIBMAppIDRedirectURLs(), + "ibm_appid_role": appid.ResourceIBMAppIDRole(), + "ibm_appid_theme_color": appid.ResourceIBMAppIDThemeColor(), + "ibm_appid_theme_text": appid.ResourceIBMAppIDThemeText(), + "ibm_appid_user_roles": appid.ResourceIBMAppIDUserRoles(), + + "ibm_function_action": functions.ResourceIBMFunctionAction(), + "ibm_function_package": functions.ResourceIBMFunctionPackage(), + "ibm_function_rule": functions.ResourceIBMFunctionRule(), + "ibm_function_trigger": functions.ResourceIBMFunctionTrigger(), + "ibm_function_namespace": functions.ResourceIBMFunctionNamespace(), + "ibm_cis": cis.ResourceIBMCISInstance(), + "ibm_database": database.ResourceIBMDatabaseInstance(), + "ibm_certificate_manager_import": certificatemanager.ResourceIBMCertificateManagerImport(), + "ibm_certificate_manager_order": certificatemanager.ResourceIBMCertificateManagerOrder(), + "ibm_cis_domain": cis.ResourceIBMCISDomain(), + "ibm_cis_domain_settings": cis.ResourceIBMCISSettings(), + "ibm_cis_firewall": cis.ResourceIBMCISFirewallRecord(), + "ibm_cis_range_app": cis.ResourceIBMCISRangeApp(), + "ibm_cis_healthcheck": cis.ResourceIBMCISHealthCheck(), + "ibm_cis_origin_pool": cis.ResourceIBMCISPool(), + "ibm_cis_global_load_balancer": cis.ResourceIBMCISGlb(), + "ibm_cis_certificate_upload": cis.ResourceIBMCISCertificateUpload(), + "ibm_cis_dns_record": cis.ResourceIBMCISDnsRecord(), + "ibm_cis_dns_records_import": cis.ResourceIBMCISDNSRecordsImport(), + "ibm_cis_rate_limit": cis.ResourceIBMCISRateLimit(), + "ibm_cis_page_rule": cis.ResourceIBMCISPageRule(), + "ibm_cis_edge_functions_action": cis.ResourceIBMCISEdgeFunctionsAction(), + "ibm_cis_edge_functions_trigger": cis.ResourceIBMCISEdgeFunctionsTrigger(), + "ibm_cis_tls_settings": cis.ResourceIBMCISTLSSettings(), + "ibm_cis_waf_package": cis.ResourceIBMCISWAFPackage(), + "ibm_cis_webhook": cis.ResourceIBMCISWebhooks(), + "ibm_cis_origin_auth": cis.ResourceIBMCISOriginAuthPull(), + "ibm_cis_mtls": cis.ResourceIBMCISMtls(), + "ibm_cis_mtls_app": cis.ResourceIBMCISMtlsApp(), + "ibm_cis_logpush_job": cis.ResourceIBMCISLogPushJob(), + "ibm_cis_alert": cis.ResourceIBMCISAlert(), + "ibm_cis_routing": cis.ResourceIBMCISRouting(), + "ibm_cis_waf_group": cis.ResourceIBMCISWAFGroup(), + "ibm_cis_cache_settings": cis.ResourceIBMCISCacheSettings(), + "ibm_cis_custom_page": cis.ResourceIBMCISCustomPage(), + "ibm_cis_waf_rule": cis.ResourceIBMCISWAFRule(), + "ibm_cis_certificate_order": cis.ResourceIBMCISCertificateOrder(), + "ibm_cis_filter": cis.ResourceIBMCISFilter(), + "ibm_cis_firewall_rule": cis.ResourceIBMCISFirewallrules(), + "ibm_cloudant": cloudant.ResourceIBMCloudant(), + "ibm_cloudant_database": cloudant.ResourceIBMCloudantDatabase(), + "ibm_cloud_shell_account_settings": cloudshell.ResourceIBMCloudShellAccountSettings(), + "ibm_compute_autoscale_group": classicinfrastructure.ResourceIBMComputeAutoScaleGroup(), + "ibm_compute_autoscale_policy": classicinfrastructure.ResourceIBMComputeAutoScalePolicy(), + "ibm_compute_bare_metal": classicinfrastructure.ResourceIBMComputeBareMetal(), + "ibm_compute_dedicated_host": classicinfrastructure.ResourceIBMComputeDedicatedHost(), + "ibm_compute_monitor": classicinfrastructure.ResourceIBMComputeMonitor(), + "ibm_compute_placement_group": classicinfrastructure.ResourceIBMComputePlacementGroup(), + "ibm_compute_reserved_capacity": classicinfrastructure.ResourceIBMComputeReservedCapacity(), + "ibm_compute_provisioning_hook": classicinfrastructure.ResourceIBMComputeProvisioningHook(), + "ibm_compute_ssh_key": classicinfrastructure.ResourceIBMComputeSSHKey(), + "ibm_compute_ssl_certificate": classicinfrastructure.ResourceIBMComputeSSLCertificate(), + "ibm_compute_user": classicinfrastructure.ResourceIBMComputeUser(), + "ibm_compute_vm_instance": classicinfrastructure.ResourceIBMComputeVmInstance(), + "ibm_container_addons": kubernetes.ResourceIBMContainerAddOns(), + "ibm_container_alb": kubernetes.ResourceIBMContainerALB(), + "ibm_container_alb_create": kubernetes.ResourceIBMContainerAlbCreate(), + "ibm_container_api_key_reset": kubernetes.ResourceIBMContainerAPIKeyReset(), + "ibm_container_vpc_alb": kubernetes.ResourceIBMContainerVpcALB(), + "ibm_container_vpc_alb_create": kubernetes.ResourceIBMContainerVpcAlbCreateNew(), + "ibm_container_vpc_worker_pool": kubernetes.ResourceIBMContainerVpcWorkerPool(), + "ibm_container_vpc_worker": kubernetes.ResourceIBMContainerVpcWorker(), + "ibm_container_vpc_cluster": kubernetes.ResourceIBMContainerVpcCluster(), + "ibm_container_alb_cert": kubernetes.ResourceIBMContainerALBCert(), + "ibm_container_cluster": kubernetes.ResourceIBMContainerCluster(), + "ibm_container_cluster_feature": kubernetes.ResourceIBMContainerClusterFeature(), + "ibm_container_bind_service": kubernetes.ResourceIBMContainerBindService(), + "ibm_container_worker_pool": kubernetes.ResourceIBMContainerWorkerPool(), + "ibm_container_worker_pool_zone_attachment": kubernetes.ResourceIBMContainerWorkerPoolZoneAttachment(), + "ibm_container_storage_attachment": kubernetes.ResourceIBMContainerVpcWorkerVolumeAttachment(), + "ibm_container_nlb_dns": kubernetes.ResourceIBMContainerNlbDns(), + "ibm_container_dedicated_host_pool": kubernetes.ResourceIBMContainerDedicatedHostPool(), + "ibm_container_dedicated_host": kubernetes.ResourceIBMContainerDedicatedHost(), + "ibm_cr_namespace": registry.ResourceIBMCrNamespace(), + "ibm_cr_retention_policy": registry.ResourceIBMCrRetentionPolicy(), + "ibm_ob_logging": kubernetes.ResourceIBMObLogging(), + "ibm_ob_monitoring": kubernetes.ResourceIBMObMonitoring(), + "ibm_cos_bucket": cos.ResourceIBMCOSBucket(), + "ibm_cos_bucket_replication_rule": cos.ResourceIBMCOSBucketReplicationConfiguration(), + "ibm_cos_bucket_object": cos.ResourceIBMCOSBucketObject(), + "ibm_dns_domain": classicinfrastructure.ResourceIBMDNSDomain(), + "ibm_dns_domain_registration_nameservers": classicinfrastructure.ResourceIBMDNSDomainRegistrationNameservers(), + "ibm_dns_secondary": classicinfrastructure.ResourceIBMDNSSecondary(), + "ibm_dns_record": classicinfrastructure.ResourceIBMDNSRecord(), + "ibm_event_streams_topic": eventstreams.ResourceIBMEventStreamsTopic(), + "ibm_event_streams_schema": eventstreams.ResourceIBMEventStreamsSchema(), + "ibm_firewall": classicinfrastructure.ResourceIBMFirewall(), + "ibm_firewall_policy": classicinfrastructure.ResourceIBMFirewallPolicy(), + "ibm_hpcs": hpcs.ResourceIBMHPCS(), + "ibm_hpcs_managed_key": hpcs.ResourceIbmManagedKey(), + "ibm_hpcs_key_template": hpcs.ResourceIbmKeyTemplate(), + "ibm_hpcs_keystore": hpcs.ResourceIbmKeystore(), + "ibm_hpcs_vault": hpcs.ResourceIbmVault(), + "ibm_iam_access_group": iamaccessgroup.ResourceIBMIAMAccessGroup(), + "ibm_iam_access_group_account_settings": iamaccessgroup.ResourceIBMIAMAccessGroupAccountSettings(), + "ibm_iam_account_settings": iamidentity.ResourceIBMIAMAccountSettings(), + "ibm_iam_custom_role": iampolicy.ResourceIBMIAMCustomRole(), + "ibm_iam_access_group_dynamic_rule": iamaccessgroup.ResourceIBMIAMDynamicRule(), + "ibm_iam_access_group_members": iamaccessgroup.ResourceIBMIAMAccessGroupMembers(), + "ibm_iam_access_group_policy": iampolicy.ResourceIBMIAMAccessGroupPolicy(), + "ibm_iam_authorization_policy": iampolicy.ResourceIBMIAMAuthorizationPolicy(), + "ibm_iam_authorization_policy_detach": iampolicy.ResourceIBMIAMAuthorizationPolicyDetach(), + "ibm_iam_user_policy": iampolicy.ResourceIBMIAMUserPolicy(), + "ibm_iam_user_settings": iamidentity.ResourceIBMIAMUserSettings(), + "ibm_iam_service_id": iamidentity.ResourceIBMIAMServiceID(), + "ibm_iam_service_api_key": iamidentity.ResourceIBMIAMServiceAPIKey(), + "ibm_iam_service_policy": iampolicy.ResourceIBMIAMServicePolicy(), + "ibm_iam_user_invite": iampolicy.ResourceIBMIAMUserInvite(), + "ibm_iam_api_key": iamidentity.ResourceIBMIAMApiKey(), + "ibm_iam_trusted_profile": iamidentity.ResourceIBMIAMTrustedProfile(), + "ibm_iam_trusted_profile_claim_rule": iamidentity.ResourceIBMIAMTrustedProfileClaimRule(), + "ibm_iam_trusted_profile_link": iamidentity.ResourceIBMIAMTrustedProfileLink(), + "ibm_iam_trusted_profile_policy": iampolicy.ResourceIBMIAMTrustedProfilePolicy(), + "ibm_ipsec_vpn": classicinfrastructure.ResourceIBMIPSecVPN(), + + "ibm_is_backup_policy": vpc.ResourceIBMIsBackupPolicy(), + "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlan(), + + // bare_metal_server + "ibm_is_bare_metal_server_action": vpc.ResourceIBMIsBareMetalServerAction(), + "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDisk(), + "ibm_is_bare_metal_server_network_interface_allow_float": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceAllowFloat(), + "ibm_is_bare_metal_server_network_interface_floating_ip": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceFloatingIp(), + "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterface(), + "ibm_is_bare_metal_server": vpc.ResourceIBMIsBareMetalServer(), + + "ibm_is_dedicated_host": vpc.ResourceIbmIsDedicatedHost(), + "ibm_is_dedicated_host_group": vpc.ResourceIbmIsDedicatedHostGroup(), + "ibm_is_dedicated_host_disk_management": vpc.ResourceIBMISDedicatedHostDiskManagement(), + "ibm_is_placement_group": vpc.ResourceIbmIsPlacementGroup(), + "ibm_is_floating_ip": vpc.ResourceIBMISFloatingIP(), + "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), + "ibm_is_instance": vpc.ResourceIBMISInstance(), + "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), + "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), + "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagement(), + "ibm_is_instance_group": vpc.ResourceIBMISInstanceGroup(), + "ibm_is_instance_group_membership": vpc.ResourceIBMISInstanceGroupMembership(), + "ibm_is_instance_group_manager": vpc.ResourceIBMISInstanceGroupManager(), + "ibm_is_instance_group_manager_policy": vpc.ResourceIBMISInstanceGroupManagerPolicy(), + "ibm_is_instance_group_manager_action": vpc.ResourceIBMISInstanceGroupManagerAction(), + "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachment(), + "ibm_is_virtual_endpoint_gateway": vpc.ResourceIBMISEndpointGateway(), + "ibm_is_virtual_endpoint_gateway_ip": vpc.ResourceIBMISEndpointGatewayIP(), + "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplate(), + "ibm_is_ike_policy": vpc.ResourceIBMISIKEPolicy(), + "ibm_is_ipsec_policy": vpc.ResourceIBMISIPSecPolicy(), + "ibm_is_lb": vpc.ResourceIBMISLB(), + "ibm_is_lb_listener": vpc.ResourceIBMISLBListener(), + "ibm_is_lb_listener_policy": vpc.ResourceIBMISLBListenerPolicy(), + "ibm_is_lb_listener_policy_rule": vpc.ResourceIBMISLBListenerPolicyRule(), + "ibm_is_lb_pool": vpc.ResourceIBMISLBPool(), + "ibm_is_lb_pool_member": vpc.ResourceIBMISLBPoolMember(), + "ibm_is_network_acl": vpc.ResourceIBMISNetworkACL(), + "ibm_is_network_acl_rule": vpc.ResourceIBMISNetworkACLRule(), + "ibm_is_public_gateway": vpc.ResourceIBMISPublicGateway(), + "ibm_is_security_group": vpc.ResourceIBMISSecurityGroup(), + "ibm_is_security_group_rule": vpc.ResourceIBMISSecurityGroupRule(), + "ibm_is_security_group_target": vpc.ResourceIBMISSecurityGroupTarget(), + "ibm_is_security_group_network_interface_attachment": vpc.ResourceIBMISSecurityGroupNetworkInterfaceAttachment(), + "ibm_is_subnet": vpc.ResourceIBMISSubnet(), + "ibm_is_subnet_reserved_ip": vpc.ResourceIBMISReservedIP(), + "ibm_is_subnet_network_acl_attachment": vpc.ResourceIBMISSubnetNetworkACLAttachment(), + "ibm_is_subnet_public_gateway_attachment": vpc.ResourceIBMISSubnetPublicGatewayAttachment(), + "ibm_is_subnet_routing_table_attachment": vpc.ResourceIBMISSubnetRoutingTableAttachment(), + "ibm_is_ssh_key": vpc.ResourceIBMISSSHKey(), + "ibm_is_snapshot": vpc.ResourceIBMSnapshot(), + "ibm_is_volume": vpc.ResourceIBMISVolume(), + "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGateway(), + "ibm_is_vpn_gateway_connection": vpc.ResourceIBMISVPNGatewayConnection(), + "ibm_is_vpc": vpc.ResourceIBMISVPC(), + "ibm_is_vpc_address_prefix": vpc.ResourceIBMISVpcAddressPrefix(), + "ibm_is_vpc_route": vpc.ResourceIBMISVpcRoute(), + "ibm_is_vpc_routing_table": vpc.ResourceIBMISVPCRoutingTable(), + "ibm_is_vpc_routing_table_route": vpc.ResourceIBMISVPCRoutingTableRoute(), + "ibm_is_vpn_server": vpc.ResourceIBMIsVPNServer(), + "ibm_is_vpn_server_client": vpc.ResourceIBMIsVPNServerClient(), + "ibm_is_vpn_server_route": vpc.ResourceIBMIsVPNServerRoute(), + "ibm_is_image": vpc.ResourceIBMISImage(), + "ibm_lb": classicinfrastructure.ResourceIBMLb(), + "ibm_lbaas": classicinfrastructure.ResourceIBMLbaas(), + "ibm_lbaas_health_monitor": classicinfrastructure.ResourceIBMLbaasHealthMonitor(), + "ibm_lbaas_server_instance_attachment": classicinfrastructure.ResourceIBMLbaasServerInstanceAttachment(), + "ibm_lb_service": classicinfrastructure.ResourceIBMLbService(), + "ibm_lb_service_group": classicinfrastructure.ResourceIBMLbServiceGroup(), + "ibm_lb_vpx": classicinfrastructure.ResourceIBMLbVpx(), + "ibm_lb_vpx_ha": classicinfrastructure.ResourceIBMLbVpxHa(), + "ibm_lb_vpx_service": classicinfrastructure.ResourceIBMLbVpxService(), + "ibm_lb_vpx_vip": classicinfrastructure.ResourceIBMLbVpxVip(), + "ibm_multi_vlan_firewall": classicinfrastructure.ResourceIBMMultiVlanFirewall(), + "ibm_network_gateway": classicinfrastructure.ResourceIBMNetworkGateway(), + "ibm_network_gateway_vlan_association": classicinfrastructure.ResourceIBMNetworkGatewayVlanAttachment(), + "ibm_network_interface_sg_attachment": classicinfrastructure.ResourceIBMNetworkInterfaceSGAttachment(), + "ibm_network_public_ip": classicinfrastructure.ResourceIBMNetworkPublicIp(), + "ibm_network_vlan": classicinfrastructure.ResourceIBMNetworkVlan(), + "ibm_network_vlan_spanning": classicinfrastructure.ResourceIBMNetworkVlanSpan(), + "ibm_object_storage_account": classicinfrastructure.ResourceIBMObjectStorageAccount(), + "ibm_org": cloudfoundry.ResourceIBMOrg(), + "ibm_pn_application_chrome": pushnotification.ResourceIBMPNApplicationChrome(), + "ibm_app_config_environment": appconfiguration.ResourceIBMAppConfigEnvironment(), + "ibm_app_config_collection": appconfiguration.ResourceIBMAppConfigCollection(), + "ibm_app_config_feature": appconfiguration.ResourceIBMIbmAppConfigFeature(), + "ibm_app_config_property": appconfiguration.ResourceIBMIbmAppConfigProperty(), + "ibm_app_config_segment": appconfiguration.ResourceIBMIbmAppConfigSegment(), + "ibm_app_config_snapshot": appconfiguration.ResourceIBMIbmAppConfigSnapshot(), + "ibm_kms_key": kms.ResourceIBMKmskey(), + "ibm_kms_key_alias": kms.ResourceIBMKmskeyAlias(), + "ibm_kms_key_rings": kms.ResourceIBMKmskeyRings(), + "ibm_kms_key_policies": kms.ResourceIBMKmskeyPolicies(), + "ibm_kp_key": kms.ResourceIBMkey(), + "ibm_resource_group": resourcemanager.ResourceIBMResourceGroup(), + "ibm_resource_instance": resourcecontroller.ResourceIBMResourceInstance(), + "ibm_resource_key": resourcecontroller.ResourceIBMResourceKey(), + "ibm_security_group": classicinfrastructure.ResourceIBMSecurityGroup(), + "ibm_security_group_rule": classicinfrastructure.ResourceIBMSecurityGroupRule(), + "ibm_service_instance": cloudfoundry.ResourceIBMServiceInstance(), + "ibm_service_key": cloudfoundry.ResourceIBMServiceKey(), + "ibm_space": cloudfoundry.ResourceIBMSpace(), + "ibm_storage_evault": classicinfrastructure.ResourceIBMStorageEvault(), + "ibm_storage_block": classicinfrastructure.ResourceIBMStorageBlock(), + "ibm_storage_file": classicinfrastructure.ResourceIBMStorageFile(), + "ibm_subnet": classicinfrastructure.ResourceIBMSubnet(), + "ibm_dns_reverse_record": classicinfrastructure.ResourceIBMDNSReverseRecord(), + "ibm_ssl_certificate": classicinfrastructure.ResourceIBMSSLCertificate(), + "ibm_cdn": classicinfrastructure.ResourceIBMCDN(), + "ibm_hardware_firewall_shared": classicinfrastructure.ResourceIBMFirewallShared(), + + // //Added for Power Colo + + "ibm_pi_key": power.ResourceIBMPIKey(), + "ibm_pi_volume": power.ResourceIBMPIVolume(), + "ibm_pi_network": power.ResourceIBMPINetwork(), + "ibm_pi_instance": power.ResourceIBMPIInstance(), + "ibm_pi_instance_action": power.ResourceIBMPIInstanceAction(), + "ibm_pi_volume_attach": power.ResourceIBMPIVolumeAttach(), + "ibm_pi_capture": power.ResourceIBMPICapture(), + "ibm_pi_image": power.ResourceIBMPIImage(), + "ibm_pi_image_export": power.ResourceIBMPIImageExport(), + "ibm_pi_network_port": power.ResourceIBMPINetworkPort(), + "ibm_pi_snapshot": power.ResourceIBMPISnapshot(), + "ibm_pi_network_port_attach": power.ResourceIBMPINetworkPortAttach(), + "ibm_pi_dhcp": power.ResourceIBMPIDhcp(), + "ibm_pi_cloud_connection": power.ResourceIBMPICloudConnection(), + "ibm_pi_cloud_connection_network_attach": power.ResourceIBMPICloudConnectionNetworkAttach(), + "ibm_pi_ike_policy": power.ResourceIBMPIIKEPolicy(), + "ibm_pi_ipsec_policy": power.ResourceIBMPIIPSecPolicy(), + "ibm_pi_vpn_connection": power.ResourceIBMPIVPNConnection(), + "ibm_pi_console_language": power.ResourceIBMPIInstanceConsoleLanguage(), + "ibm_pi_placement_group": power.ResourceIBMPIPlacementGroup(), + "ibm_pi_spp_placement_group": power.ResourceIBMPISPPPlacementGroup(), + "ibm_pi_shared_processor_pool": power.ResourceIBMPISharedProcessorPool(), + + // //Private DNS related resources + "ibm_dns_zone": dnsservices.ResourceIBMPrivateDNSZone(), + "ibm_dns_permitted_network": dnsservices.ResourceIBMPrivateDNSPermittedNetwork(), + "ibm_dns_resource_record": dnsservices.ResourceIBMPrivateDNSResourceRecord(), + "ibm_dns_glb_monitor": dnsservices.ResourceIBMPrivateDNSGLBMonitor(), + "ibm_dns_glb_pool": dnsservices.ResourceIBMPrivateDNSGLBPool(), + "ibm_dns_glb": dnsservices.ResourceIBMPrivateDNSGLB(), + + // //Added for Custom Resolver + "ibm_dns_custom_resolver": dnsservices.ResourceIBMPrivateDNSCustomResolver(), + "ibm_dns_custom_resolver_location": dnsservices.ResourceIBMPrivateDNSCRLocation(), + "ibm_dns_custom_resolver_forwarding_rule": dnsservices.ResourceIBMPrivateDNSForwardingRule(), + "ibm_dns_custom_resolver_secondary_zone": dnsservices.ResourceIBMPrivateDNSSecondaryZone(), + + // //Direct Link related resources + "ibm_dl_gateway": directlink.ResourceIBMDLGateway(), + "ibm_dl_virtual_connection": directlink.ResourceIBMDLGatewayVC(), + "ibm_dl_provider_gateway": directlink.ResourceIBMDLProviderGateway(), + "ibm_dl_route_report": directlink.ResourceIBMDLGatewayRouteReport(), + // //Added for Transit Gateway + "ibm_tg_gateway": transitgateway.ResourceIBMTransitGateway(), + "ibm_tg_connection": transitgateway.ResourceIBMTransitGatewayConnection(), + "ibm_tg_connection_prefix_filter": transitgateway.ResourceIBMTransitGatewayConnectionPrefixFilter(), + "ibm_tg_route_report": transitgateway.ResourceIBMTransitGatewayRouteReport(), + + // //Catalog related resources + "ibm_cm_offering_instance": catalogmanagement.ResourceIBMCmOfferingInstance(), + "ibm_cm_catalog": catalogmanagement.ResourceIBMCmCatalog(), + "ibm_cm_offering": catalogmanagement.ResourceIBMCmOffering(), + "ibm_cm_version": catalogmanagement.ResourceIBMCmVersion(), + "ibm_cm_validation": catalogmanagement.ResourceIBMCmValidation(), + + // //Added for enterprise + "ibm_enterprise": enterprise.ResourceIBMEnterprise(), + "ibm_enterprise_account_group": enterprise.ResourceIBMEnterpriseAccountGroup(), + "ibm_enterprise_account": enterprise.ResourceIBMEnterpriseAccount(), + + //Added for Schematics + "ibm_schematics_workspace": schematics.ResourceIBMSchematicsWorkspace(), + "ibm_schematics_action": schematics.ResourceIBMSchematicsAction(), + "ibm_schematics_job": schematics.ResourceIBMSchematicsJob(), + "ibm_schematics_inventory": schematics.ResourceIBMSchematicsInventory(), + "ibm_schematics_resource_query": schematics.ResourceIBMSchematicsResourceQuery(), + + // //satellite resources + "ibm_satellite_location": satellite.ResourceIBMSatelliteLocation(), + "ibm_satellite_host": satellite.ResourceIBMSatelliteHost(), + "ibm_satellite_cluster": satellite.ResourceIBMSatelliteCluster(), + "ibm_satellite_cluster_worker_pool": satellite.ResourceIBMSatelliteClusterWorkerPool(), + "ibm_satellite_link": satellite.ResourceIBMSatelliteLink(), + "ibm_satellite_endpoint": satellite.ResourceIBMSatelliteEndpoint(), + "ibm_satellite_location_nlb_dns": satellite.ResourceIBMSatelliteLocationNlbDns(), + "ibm_satellite_cluster_worker_pool_zone_attachment": satellite.ResourceIbmSatelliteClusterWorkerPoolZoneAttachment(), + + //Added for Resource Tag + "ibm_resource_tag": globaltagging.ResourceIBMResourceTag(), + + // // Atracker + "ibm_atracker_target": atracker.ResourceIBMAtrackerTarget(), + "ibm_atracker_route": atracker.ResourceIBMAtrackerRoute(), + "ibm_atracker_settings": atracker.ResourceIBMAtrackerSettings(), + + // //Security and Compliance Center + "ibm_scc_account_settings": scc.ResourceIBMSccAccountSettings(), + "ibm_scc_rule": scc.ResourceIBMSccRule(), + "ibm_scc_rule_attachment": scc.ResourceIBMSccRuleAttachment(), + "ibm_scc_template": scc.ResourceIBMSccTemplate(), + "ibm_scc_template_attachment": scc.ResourceIBMSccTemplateAttachment(), + + //Security and Compliance Center - PostureManagement + "ibm_scc_posture_collector": scc.ResourceIBMSccPostureCollectors(), + "ibm_scc_posture_scope": scc.ResourceIBMSccPostureScopes(), + "ibm_scc_posture_credential": scc.ResourceIBMSccPostureCredentials(), + "ibm_scc_posture_profile_import": scc.ResourceIBMSccPostureProfileImport(), + "ibm_scc_posture_scan_initiate_validation": scc.ResourceIBMSccPostureScanInitiateValidation(), + + // // Added for Context Based Restrictions + "ibm_cbr_zone": contextbasedrestrictions.ResourceIBMCbrZone(), + "ibm_cbr_rule": contextbasedrestrictions.ResourceIBMCbrRule(), + + // // Added for Event Notifications + "ibm_en_source": eventnotification.ResourceIBMEnSource(), + "ibm_en_destination": eventnotification.ResourceIBMEnDestination(), + "ibm_en_topic": eventnotification.ResourceIBMEnTopic(), + "ibm_en_subscription": eventnotification.ResourceIBMEnSubscription(), + "ibm_en_destination_webhook": eventnotification.ResourceIBMEnWebhookDestination(), + "ibm_en_destination_android": eventnotification.ResourceIBMEnFCMDestination(), + "ibm_en_destination_chrome": eventnotification.ResourceIBMEnChromeDestination(), + "ibm_en_destination_firefox": eventnotification.ResourceIBMEnFirefoxDestination(), + "ibm_en_destination_ios": eventnotification.ResourceIBMEnAPNSDestination(), + "ibm_en_destination_slack": eventnotification.ResourceIBMEnSlackDestination(), + "ibm_en_subscription_sms": eventnotification.ResourceIBMEnSMSSubscription(), + "ibm_en_subscription_email": eventnotification.ResourceIBMEnEmailSubscription(), + "ibm_en_subscription_webhook": eventnotification.ResourceIBMEnWebhookSubscription(), + "ibm_en_subscription_android": eventnotification.ResourceIBMEnFCMSubscription(), + "ibm_en_subscription_ios": eventnotification.ResourceIBMEnFCMSubscription(), + "ibm_en_subscription_chrome": eventnotification.ResourceIBMEnFCMSubscription(), + "ibm_en_subscription_firefox": eventnotification.ResourceIBMEnFCMSubscription(), + "ibm_en_subscription_slack": eventnotification.ResourceIBMEnSlackSubscription(), + "ibm_en_subscription_safari": eventnotification.ResourceIBMEnFCMSubscription(), + "ibm_en_destination_safari": eventnotification.ResourceIBMEnSafariDestination(), + + // // Added for Toolchain + "ibm_cd_toolchain": cdtoolchain.ResourceIBMCdToolchain(), + "ibm_cd_toolchain_tool_keyprotect": cdtoolchain.ResourceIBMCdToolchainToolKeyprotect(), + "ibm_cd_toolchain_tool_secretsmanager": cdtoolchain.ResourceIBMCdToolchainToolSecretsmanager(), + "ibm_cd_toolchain_tool_bitbucketgit": cdtoolchain.ResourceIBMCdToolchainToolBitbucketgit(), + "ibm_cd_toolchain_tool_githubintegrated": cdtoolchain.ResourceIBMCdToolchainToolGithubintegrated(), + "ibm_cd_toolchain_tool_githubconsolidated": cdtoolchain.ResourceIBMCdToolchainToolGithubconsolidated(), + "ibm_cd_toolchain_tool_gitlab": cdtoolchain.ResourceIBMCdToolchainToolGitlab(), + "ibm_cd_toolchain_tool_hostedgit": cdtoolchain.ResourceIBMCdToolchainToolHostedgit(), + "ibm_cd_toolchain_tool_artifactory": cdtoolchain.ResourceIBMCdToolchainToolArtifactory(), + "ibm_cd_toolchain_tool_custom": cdtoolchain.ResourceIBMCdToolchainToolCustom(), + "ibm_cd_toolchain_tool_pipeline": cdtoolchain.ResourceIBMCdToolchainToolPipeline(), + "ibm_cd_toolchain_tool_devopsinsights": cdtoolchain.ResourceIBMCdToolchainToolDevopsinsights(), + "ibm_cd_toolchain_tool_slack": cdtoolchain.ResourceIBMCdToolchainToolSlack(), + "ibm_cd_toolchain_tool_sonarqube": cdtoolchain.ResourceIBMCdToolchainToolSonarqube(), + "ibm_cd_toolchain_tool_hashicorpvault": cdtoolchain.ResourceIBMCdToolchainToolHashicorpvault(), + "ibm_cd_toolchain_tool_securitycompliance": cdtoolchain.ResourceIBMCdToolchainToolSecuritycompliance(), + "ibm_cd_toolchain_tool_privateworker": cdtoolchain.ResourceIBMCdToolchainToolPrivateworker(), + "ibm_cd_toolchain_tool_appconfig": cdtoolchain.ResourceIBMCdToolchainToolAppconfig(), + "ibm_cd_toolchain_tool_jenkins": cdtoolchain.ResourceIBMCdToolchainToolJenkins(), + "ibm_cd_toolchain_tool_nexus": cdtoolchain.ResourceIBMCdToolchainToolNexus(), + "ibm_cd_toolchain_tool_pagerduty": cdtoolchain.ResourceIBMCdToolchainToolPagerduty(), + "ibm_cd_toolchain_tool_saucelabs": cdtoolchain.ResourceIBMCdToolchainToolSaucelabs(), + + // // Added for Tekton Pipeline + "ibm_cd_tekton_pipeline_definition": cdtektonpipeline.ResourceIBMCdTektonPipelineDefinition(), + "ibm_cd_tekton_pipeline_trigger_property": cdtektonpipeline.ResourceIBMCdTektonPipelineTriggerProperty(), + "ibm_cd_tekton_pipeline_property": cdtektonpipeline.ResourceIBMCdTektonPipelineProperty(), + "ibm_cd_tekton_pipeline_trigger": cdtektonpipeline.ResourceIBMCdTektonPipelineTrigger(), + "ibm_cd_tekton_pipeline": cdtektonpipeline.ResourceIBMCdTektonPipeline(), + }, + + ConfigureFunc: providerConfigure, + } +} + +var globalValidatorDict validate.ValidatorDict +var initOnce sync.Once + +func init() { + validate.SetValidatorDict(Validator()) +} + +// Validator return validator +func Validator() validate.ValidatorDict { + initOnce.Do(func() { + globalValidatorDict = validate.ValidatorDict{ + ResourceValidatorDictionary: map[string]*validate.ResourceValidator{ + "ibm_iam_account_settings": iamidentity.ResourceIBMIAMAccountSettingsValidator(), + "ibm_iam_custom_role": iampolicy.ResourceIBMIAMCustomRoleValidator(), + "ibm_cis_healthcheck": cis.ResourceIBMCISHealthCheckValidator(), + "ibm_cis_rate_limit": cis.ResourceIBMCISRateLimitValidator(), + "ibm_cis": cis.ResourceIBMCISValidator(), + "ibm_cis_domain_settings": cis.ResourceIBMCISDomainSettingValidator(), + "ibm_cis_domain": cis.ResourceIBMCISDomainValidator(), + "ibm_cis_tls_settings": cis.ResourceIBMCISTLSSettingsValidator(), + "ibm_cis_routing": cis.ResourceIBMCISRoutingValidator(), + "ibm_cis_page_rule": cis.ResourceIBMCISPageRuleValidator(), + "ibm_cis_waf_package": cis.ResourceIBMCISWAFPackageValidator(), + "ibm_cis_waf_group": cis.ResourceIBMCISWAFGroupValidator(), + "ibm_cis_certificate_upload": cis.ResourceIBMCISCertificateUploadValidator(), + "ibm_cis_cache_settings": cis.ResourceIBMCISCacheSettingsValidator(), + "ibm_cis_custom_page": cis.ResourceIBMCISCustomPageValidator(), + "ibm_cis_firewall": cis.ResourceIBMCISFirewallValidator(), + "ibm_cis_range_app": cis.ResourceIBMCISRangeAppValidator(), + "ibm_cis_waf_rule": cis.ResourceIBMCISWAFRuleValidator(), + "ibm_cis_certificate_order": cis.ResourceIBMCISCertificateOrderValidator(), + "ibm_cis_filter": cis.ResourceIBMCISFilterValidator(), + "ibm_cis_firewall_rules": cis.ResourceIBMCISFirewallrulesValidator(), + "ibm_cis_webhook": cis.ResourceIBMCISWebhooksValidator(), + "ibm_cis_alert": cis.ResourceIBMCISAlertValidator(), + "ibm_cis_dns_record": cis.ResourceIBMCISDnsRecordValidator(), + "ibm_cis_dns_records_import": cis.ResourceIBMCISDnsRecordsImportValidator(), + "ibm_cis_edge_functions_action": cis.ResourceIBMCISEdgeFunctionsActionValidator(), + "ibm_cis_edge_functions_trigger": cis.ResourceIBMCISEdgeFunctionsTriggerValidator(), + "ibm_cis_global_load_balancer": cis.ResourceIBMCISGlbValidator(), + "ibm_cis_logpush_job": cis.ResourceIBMCISLogPushJobValidator(), + "ibm_cis_mtls_app": cis.ResourceIBMCISMtlsAppValidator(), + "ibm_cis_mtls": cis.ResourceIBMCISMtlsValidator(), + "ibm_cis_origin_auth": cis.ResourceIBMCISOriginAuthPullValidator(), + "ibm_cis_origin_pool": cis.ResourceIBMCISPoolValidator(), + "ibm_container_cluster": kubernetes.ResourceIBMContainerClusterValidator(), + "ibm_container_worker_pool": kubernetes.ResourceIBMContainerWorkerPoolValidator(), + "ibm_container_vpc_worker_pool": kubernetes.ResourceIBMContainerVPCWorkerPoolValidator(), + "ibm_container_vpc_worker": kubernetes.ResourceIBMContainerVPCWorkerValidator(), + "ibm_container_vpc_cluster": kubernetes.ResourceIBMContainerVpcClusterValidator(), + "ibm_cos_bucket": cos.ResourceIBMCOSBucketValidator(), + "ibm_cr_namespace": registry.ResourceIBMCrNamespaceValidator(), + "ibm_tg_gateway": transitgateway.ResourceIBMTGValidator(), + "ibm_app_config_feature": appconfiguration.ResourceIBMAppConfigFeatureValidator(), + "ibm_tg_connection": transitgateway.ResourceIBMTransitGatewayConnectionValidator(), + "ibm_tg_connection_prefix_filter": transitgateway.ResourceIBMTransitGatewayConnectionPrefixFilterValidator(), + "ibm_dl_virtual_connection": directlink.ResourceIBMDLGatewayVCValidator(), + "ibm_dl_gateway": directlink.ResourceIBMDLGatewayValidator(), + "ibm_dl_provider_gateway": directlink.ResourceIBMDLProviderGatewayValidator(), + "ibm_database": database.ResourceIBMICDValidator(), + "ibm_function_package": functions.ResourceIBMFuncPackageValidator(), + "ibm_function_action": functions.ResourceIBMFuncActionValidator(), + "ibm_function_rule": functions.ResourceIBMFuncRuleValidator(), + "ibm_function_trigger": functions.ResourceIBMFuncTriggerValidator(), + "ibm_function_namespace": functions.ResourceIBMFuncNamespaceValidator(), + "ibm_hpcs": hpcs.ResourceIBMHPCSValidator(), + "ibm_hpcs_managed_key": hpcs.ResourceIbmManagedKeyValidator(), + "ibm_hpcs_keystore": hpcs.ResourceIbmKeystoreValidator(), + "ibm_hpcs_key_template": hpcs.ResourceIbmKeyTemplateValidator(), + "ibm_hpcs_vault": hpcs.ResourceIbmVaultValidator(), + + "ibm_is_backup_policy": vpc.ResourceIBMIsBackupPolicyValidator(), + "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlanValidator(), + + // bare_metal_server + "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDiskValidator(), + "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceValidator(), + "ibm_is_bare_metal_server": vpc.ResourceIBMIsBareMetalServerValidator(), + + "ibm_is_dedicated_host_group": vpc.ResourceIbmIsDedicatedHostGroupValidator(), + "ibm_is_dedicated_host": vpc.ResourceIbmIsDedicatedHostValidator(), + "ibm_is_dedicated_host_disk_management": vpc.ResourceIBMISDedicatedHostDiskManagementValidator(), + "ibm_is_flow_log": vpc.ResourceIBMISFlowLogValidator(), + "ibm_is_instance_group": vpc.ResourceIBMISInstanceGroupValidator(), + "ibm_is_instance_group_membership": vpc.ResourceIBMISInstanceGroupMembershipValidator(), + "ibm_is_instance_group_manager": vpc.ResourceIBMISInstanceGroupManagerValidator(), + "ibm_is_instance_group_manager_policy": vpc.ResourceIBMISInstanceGroupManagerPolicyValidator(), + "ibm_is_instance_group_manager_action": vpc.ResourceIBMISInstanceGroupManagerActionValidator(), + "ibm_is_floating_ip": vpc.ResourceIBMISFloatingIPValidator(), + "ibm_is_ike_policy": vpc.ResourceIBMISIKEValidator(), + "ibm_is_image": vpc.ResourceIBMISImageValidator(), + "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), + "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), + "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), + "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), + "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagementValidator(), + "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachmentValidator(), + "ibm_is_ipsec_policy": vpc.ResourceIBMISIPSECValidator(), + "ibm_is_lb_listener_policy_rule": vpc.ResourceIBMISLBListenerPolicyRuleValidator(), + "ibm_is_lb_listener_policy": vpc.ResourceIBMISLBListenerPolicyValidator(), + "ibm_is_lb_listener": vpc.ResourceIBMISLBListenerValidator(), + "ibm_is_lb_pool_member": vpc.ResourceIBMISLBPoolMemberValidator(), + "ibm_is_lb_pool": vpc.ResourceIBMISLBPoolValidator(), + "ibm_is_lb": vpc.ResourceIBMISLBValidator(), + "ibm_is_network_acl": vpc.ResourceIBMISNetworkACLValidator(), + "ibm_is_network_acl_rule": vpc.ResourceIBMISNetworkACLRuleValidator(), + "ibm_is_public_gateway": vpc.ResourceIBMISPublicGatewayValidator(), + "ibm_is_placement_group": vpc.ResourceIbmIsPlacementGroupValidator(), + "ibm_is_security_group_target": vpc.ResourceIBMISSecurityGroupTargetValidator(), + "ibm_is_security_group_rule": vpc.ResourceIBMISSecurityGroupRuleValidator(), + "ibm_is_security_group": vpc.ResourceIBMISSecurityGroupValidator(), + "ibm_is_snapshot": vpc.ResourceIBMISSnapshotValidator(), + "ibm_is_ssh_key": vpc.ResourceIBMISSHKeyValidator(), + "ibm_is_subnet": vpc.ResourceIBMISSubnetValidator(), + "ibm_is_subnet_reserved_ip": vpc.ResourceIBMISSubnetReservedIPValidator(), + "ibm_is_volume": vpc.ResourceIBMISVolumeValidator(), + "ibm_is_address_prefix": vpc.ResourceIBMISAddressPrefixValidator(), + "ibm_is_route": vpc.ResourceIBMISRouteValidator(), + "ibm_is_vpc": vpc.ResourceIBMISVPCValidator(), + "ibm_is_vpc_routing_table": vpc.ResourceIBMISVPCRoutingTableValidator(), + "ibm_is_vpc_routing_table_route": vpc.ResourceIBMISVPCRoutingTableRouteValidator(), + "ibm_is_vpn_gateway_connection": vpc.ResourceIBMISVPNGatewayConnectionValidator(), + "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGatewayValidator(), + "ibm_is_vpn_server": vpc.ResourceIBMIsVPNServerValidator(), + "ibm_is_vpn_server_route": vpc.ResourceIBMIsVPNServerRouteValidator(), + "ibm_kms_key_rings": kms.ResourceIBMKeyRingValidator(), + "ibm_dns_glb_monitor": dnsservices.ResourceIBMPrivateDNSGLBMonitorValidator(), + "ibm_dns_custom_resolver_forwarding_rule": dnsservices.ResourceIBMPrivateDNSForwardingRuleValidator(), + "ibm_schematics_action": schematics.ResourceIBMSchematicsActionValidator(), + "ibm_schematics_job": schematics.ResourceIBMSchematicsJobValidator(), + "ibm_schematics_workspace": schematics.ResourceIBMSchematicsWorkspaceValidator(), + "ibm_schematics_inventory": schematics.ResourceIBMSchematicsInventoryValidator(), + "ibm_schematics_resource_query": schematics.ResourceIBMSchematicsResourceQueryValidator(), + "ibm_resource_instance": resourcecontroller.ResourceIBMResourceInstanceValidator(), + "ibm_resource_key": resourcecontroller.ResourceIBMResourceKeyValidator(), + "ibm_is_virtual_endpoint_gateway": vpc.ResourceIBMISEndpointGatewayValidator(), + "ibm_resource_tag": globaltagging.ResourceIBMResourceTagValidator(), + "ibm_satellite_location": satellite.ResourceIBMSatelliteLocationValidator(), + "ibm_satellite_cluster": satellite.ResourceIBMSatelliteClusterValidator(), + "ibm_pi_volume": power.ResourceIBMPIVolumeValidator(), + "ibm_atracker_target": atracker.ResourceIBMAtrackerTargetValidator(), + "ibm_atracker_route": atracker.ResourceIBMAtrackerRouteValidator(), + "ibm_atracker_settings": atracker.ResourceIBMAtrackerSettingsValidator(), + "ibm_satellite_endpoint": satellite.ResourceIBMSatelliteEndpointValidator(), + "ibm_scc_account_settings": scc.ResourceIBMSccAccountSettingsValidator(), + "ibm_scc_posture_collector": scc.ResourceIBMSccPostureCollectorsValidator(), + "ibm_scc_posture_scope": scc.ResourceIBMSccPostureScopesValidator(), + "ibm_scc_posture_credential": scc.ResourceIBMSccPostureCredentialsValidator(), + "ibm_scc_posture_scan_initiate_validation": scc.ResourceIBMSccPostureScanInitiateValidationValidator(), + "ibm_scc_rule": scc.ResourceIBMSccRuleValidator(), + "ibm_scc_rule_attachment": scc.ResourceIBMSccRuleAttachmentValidator(), + "ibm_scc_template": scc.ResourceIBMSccTemplateValidator(), + "ibm_scc_template_attachment": scc.ResourceIBMSccTemplateAttachmentValidator(), + "ibm_cbr_zone": contextbasedrestrictions.ResourceIBMCbrZoneValidator(), + "ibm_cbr_rule": contextbasedrestrictions.ResourceIBMCbrRuleValidator(), + "ibm_satellite_host": satellite.ResourceIBMSatelliteHostValidator(), + + // // Added for Event Notifications + "ibm_en_destination": eventnotification.ResourceIBMEnDestinationValidator(), + + // // Added for Toolchains + "ibm_cd_toolchain": cdtoolchain.ResourceIBMCdToolchainValidator(), + "ibm_cd_toolchain_tool_keyprotect": cdtoolchain.ResourceIBMCdToolchainToolKeyprotectValidator(), + "ibm_cd_toolchain_tool_secretsmanager": cdtoolchain.ResourceIBMCdToolchainToolSecretsmanagerValidator(), + "ibm_cd_toolchain_tool_bitbucketgit": cdtoolchain.ResourceIBMCdToolchainToolBitbucketgitValidator(), + "ibm_cd_toolchain_tool_githubintegrated": cdtoolchain.ResourceIBMCdToolchainToolGithubintegratedValidator(), + "ibm_cd_toolchain_tool_githubconsolidated": cdtoolchain.ResourceIBMCdToolchainToolGithubconsolidatedValidator(), + "ibm_cd_toolchain_tool_gitlab": cdtoolchain.ResourceIBMCdToolchainToolGitlabValidator(), + "ibm_cd_toolchain_tool_hostedgit": cdtoolchain.ResourceIBMCdToolchainToolHostedgitValidator(), + "ibm_cd_toolchain_tool_artifactory": cdtoolchain.ResourceIBMCdToolchainToolArtifactoryValidator(), + "ibm_cd_toolchain_tool_custom": cdtoolchain.ResourceIBMCdToolchainToolCustomValidator(), + "ibm_cd_toolchain_tool_pipeline": cdtoolchain.ResourceIBMCdToolchainToolPipelineValidator(), + "ibm_cd_toolchain_tool_slack": cdtoolchain.ResourceIBMCdToolchainToolSlackValidator(), + "ibm_cd_toolchain_tool_devopsinsights": cdtoolchain.ResourceIBMCdToolchainToolDevopsinsightsValidator(), + "ibm_cd_toolchain_tool_sonarqube": cdtoolchain.ResourceIBMCdToolchainToolSonarqubeValidator(), + "ibm_cd_toolchain_tool_hashicorpvault": cdtoolchain.ResourceIBMCdToolchainToolHashicorpvaultValidator(), + "ibm_cd_toolchain_tool_securitycompliance": cdtoolchain.ResourceIBMCdToolchainToolSecuritycomplianceValidator(), + "ibm_cd_toolchain_tool_privateworker": cdtoolchain.ResourceIBMCdToolchainToolPrivateworkerValidator(), + "ibm_cd_toolchain_tool_appconfig": cdtoolchain.ResourceIBMCdToolchainToolAppconfigValidator(), + "ibm_cd_toolchain_tool_jenkins": cdtoolchain.ResourceIBMCdToolchainToolJenkinsValidator(), + "ibm_cd_toolchain_tool_nexus": cdtoolchain.ResourceIBMCdToolchainToolNexusValidator(), + "ibm_cd_toolchain_tool_pagerduty": cdtoolchain.ResourceIBMCdToolchainToolPagerdutyValidator(), + "ibm_cd_toolchain_tool_saucelabs": cdtoolchain.ResourceIBMCdToolchainToolSaucelabsValidator(), + + // // Added for Tekton Pipeline + "ibm_cd_tekton_pipeline_definition": cdtektonpipeline.ResourceIBMCdTektonPipelineDefinitionValidator(), + "ibm_cd_tekton_pipeline_trigger_property": cdtektonpipeline.ResourceIBMCdTektonPipelineTriggerPropertyValidator(), + "ibm_cd_tekton_pipeline_property": cdtektonpipeline.ResourceIBMCdTektonPipelinePropertyValidator(), + "ibm_cd_tekton_pipeline_trigger": cdtektonpipeline.ResourceIBMCdTektonPipelineTriggerValidator(), + + "ibm_container_addons": kubernetes.ResourceIBMContainerAddOnsValidator(), + "ibm_container_alb_create": kubernetes.ResourceIBMContainerAlbCreateValidator(), + "ibm_container_nlb_dns": kubernetes.ResourceIBMContainerNlbDnsValidator(), + "ibm_container_vpc_alb_create": kubernetes.ResourceIBMContainerVpcAlbCreateNewValidator(), + "ibm_container_storage_attachment": kubernetes.ResourceIBMContainerVpcWorkerVolumeAttachmentValidator(), + "ibm_container_worker_pool_zone_attachment": kubernetes.ResourceIBMContainerWorkerPoolZoneAttachmentValidator(), + "ibm_container_bind_service": kubernetes.ResourceIBMContainerBindServiceValidator(), + "ibm_container_alb_cert": kubernetes.ResourceIBMContainerALBCertValidator(), + "ibm_container_cluster_feature": kubernetes.ResourceIBMContainerClusterFeatureValidator(), + + "ibm_iam_access_group_dynamic_rule": iamaccessgroup.ResourceIBMIAMDynamicRuleValidator(), + "ibm_iam_access_group_members": iamaccessgroup.ResourceIBMIAMAccessGroupMembersValidator(), + + "ibm_iam_trusted_profile_claim_rule": iamidentity.ResourceIBMIAMTrustedProfileClaimRuleValidator(), + "ibm_iam_trusted_profile_link": iamidentity.ResourceIBMIAMTrustedProfileLinkValidator(), + "ibm_iam_service_api_key": iamidentity.ResourceIBMIAMServiceAPIKeyValidator(), + + "ibm_iam_trusted_profile_policy": iampolicy.ResourceIBMIAMTrustedProfilePolicyValidator(), + "ibm_iam_access_group_policy": iampolicy.ResourceIBMIAMAccessGroupPolicyValidator(), + "ibm_iam_service_policy": iampolicy.ResourceIBMIAMServicePolicyValidator(), + "ibm_iam_authorization_policy": iampolicy.ResourceIBMIAMAuthorizationPolicyValidator(), + }, + DataSourceValidatorDictionary: map[string]*validate.ResourceValidator{ + "ibm_is_subnet": vpc.DataSourceIBMISSubnetValidator(), + "ibm_is_snapshot": vpc.DataSourceIBMISSnapshotValidator(), + "ibm_is_images": vpc.DataSourceIBMISImagesValidator(), + "ibm_dl_offering_speeds": directlink.DataSourceIBMDLOfferingSpeedsValidator(), + "ibm_dl_routers": directlink.DataSourceIBMDLRoutersValidator(), + "ibm_resource_instance": resourcecontroller.DataSourceIBMResourceInstanceValidator(), + "ibm_resource_key": resourcecontroller.DataSourceIBMResourceKeyValidator(), + "ibm_resource_group": resourcemanager.DataSourceIBMResourceGroupValidator(), + + // bare_metal_server + "ibm_is_bare_metal_server": vpc.DataSourceIBMIsBareMetalServerValidator(), + + "ibm_is_vpc": vpc.DataSourceIBMISVpcValidator(), + "ibm_is_volume": vpc.DataSourceIBMISVolumeValidator(), + "ibm_secrets_manager_secret": secretsmanager.DataSourceIBMSecretsManagerSecretValidator(), + "ibm_secrets_manager_secrets": secretsmanager.DataSourceIBMSecretsManagerSecretsValidator(), + "ibm_cis_webhooks": cis.DataSourceIBMCISAlertWebhooksValidator(), + "ibm_cis_alerts": cis.DataSourceIBMCISAlertsValidator(), + "ibm_cis_cache_settings": cis.DataSourceIBMCISCacheSettingsValidator(), + "ibm_cis_custom_certificates": cis.DataSourceIBMCISCustomCertificatesValidator(), + "ibm_cis_custom_pages": cis.DataSourceIBMCISCustomPagesValidator(), + "ibm_cis_dns_records": cis.DataSourceIBMCISDNSRecordsValidator(), + "ibm_cis_domain": cis.DataSourceIBMCISDomainValidator(), + "ibm_cis_certificates": cis.DataSourceIBMCISCertificatesValidator(), + "ibm_cis_edge_functions_actions": cis.DataSourceIBMCISEdgeFunctionsActionsValidator(), + "ibm_cis_edge_functions_triggers": cis.DataSourceIBMCISEdgeFunctionsTriggersValidator(), + "ibm_cis_filters": cis.DataSourceIBMCISFiltersValidator(), + "ibm_cis_firewall_rules": cis.DataSourceIBMCISFirewallRulesValidator(), + "ibm_cis_firewall": cis.DataSourceIBMCISFirewallsRecordValidator(), + "ibm_cis_global_load_balancers": cis.DataSourceIBMCISGlbsValidator(), + "ibm_cis_healthchecks": cis.DataSourceIBMCISHealthChecksValidator(), + "ibm_cis_mtls_apps": cis.DataSourceIBMCISMtlsAppValidator(), + "ibm_cis_mtlss": cis.DataSourceIBMCISMtlsValidator(), + "ibm_cis_origin_auths": cis.DataSourceIBMCISOriginAuthPullValidator(), + "ibm_cis_origin_pools": cis.DataSourceIBMCISOriginPoolsValidator(), + "ibm_cis_page_rules": cis.DataSourceIBMCISPageRulesValidator(), + "ibm_cis_range_apps": cis.DataSourceIBMCISRangeAppsValidator(), + "ibm_cis_rate_limit": cis.DataSourceIBMCISRateLimitValidator(), + "ibm_cis_waf_groups": cis.DataSourceIBMCISWAFGroupsValidator(), + "ibm_cis_waf_packages": cis.DataSourceIBMCISWAFPackagesValidator(), + "ibm_cis_waf_rules": cis.DataSourceIBMCISWAFRulesValidator(), + "ibm_cis_logpush_jobs": cis.DataSourceIBMCISLogPushJobsValidator(), + + "ibm_cos_bucket": cos.DataSourceIBMCosBucketValidator(), + + "ibm_database_backups": database.DataSourceIBMDatabaseBackupsValidator(), + "ibm_database_connection": database.DataSourceIBMDatabaseConnectionValidator(), + "ibm_database_point_in_time_recovery": database.DataSourceIBMDatabasePointInTimeRecoveryValidator(), + "ibm_database_remotes": database.DataSourceIBMDatabaseRemotesValidator(), + "ibm_database_tasks": database.DataSourceIBMDatabaseTasksValidator(), + "ibm_database": database.DataSourceIBMDatabaseInstanceValidator(), + + "ibm_container_addons": kubernetes.DataSourceIBMContainerAddOnsValidator(), + "ibm_container_nlb_dns": kubernetes.DataSourceIBMContainerNLBDNSValidator(), + "ibm_container_storage_attachment": kubernetes.DataSourceIBMContainerVpcWorkerVolumeAttachmentValidator(), + "ibm_container_vpc_cluster_worker_pool": kubernetes.DataSourceIBMContainerVpcClusterWorkerPoolValidator(), + "ibm_container_worker_pool": kubernetes.DataSourceIBMContainerWorkerPoolValidator(), + "ibm_container_bind_service": kubernetes.DataSourceIBMContainerBindServiceValidator(), + "ibm_container_cluster_config": kubernetes.DataSourceIBMContainerClusterConfigValidator(), + "ibm_container_cluster": kubernetes.DataSourceIBMContainerClusterValidator(), + "ibm_container_vpc_cluster_worker": kubernetes.DataSourceIBMContainerVPCClusterWorkerValidator(), + "ibm_container_vpc_cluster": kubernetes.DataSourceIBMContainerVPCClusterValidator(), + "ibm_container_alb_cert": kubernetes.DataSourceIBMContainerALBCertValidator(), + "ibm_iam_access_group": iamaccessgroup.DataSourceIBMIAMAccessGroupValidator(), + + "ibm_iam_service_id": iamidentity.DataSourceIBMIAMServiceIDValidator(), + "ibm_iam_trusted_profile_claim_rule": iamidentity.DataSourceIBMIamTrustedProfileClaimRuleValidator(), + "ibm_iam_trusted_profile_link": iamidentity.DataSourceIBMIamTrustedProfileLinkValidator(), + "ibm_iam_trusted_profile_links": iamidentity.DataSourceIBMIamTrustedProfileLinksValidator(), + "ibm_iam_trusted_profile": iamidentity.DataSourceIBMIamTrustedProfileValidator(), + "ibm_iam_trusted_profile_claim_rules": iamidentity.DataSourceIBMIamTrustedProfileClaimRulesValidator(), + "ibm_iam_trusted_profiles": iamidentity.DataSourceIBMIamTrustedProfilesValidator(), + + "ibm_iam_access_group_policy": iampolicy.DataSourceIBMIAMAccessGroupPolicyValidator(), + "ibm_iam_service_policy": iampolicy.DataSourceIBMIAMServicePolicyValidator(), + "ibm_iam_trusted_profile_policy": iampolicy.DataSourceIBMIAMTrustedProfilePolicyValidator(), + }, + } + }) + return globalValidatorDict +} + +func providerConfigure(d *schema.ResourceData) (interface{}, error) { + var bluemixAPIKey string + var bluemixTimeout int + var iamToken, iamRefreshToken, iamTrustedProfileId string + if key, ok := d.GetOk("bluemix_api_key"); ok { + bluemixAPIKey = key.(string) + } + if key, ok := d.GetOk("ibmcloud_api_key"); ok { + bluemixAPIKey = key.(string) + } + if itoken, ok := d.GetOk("iam_token"); ok { + iamToken = itoken.(string) + } + if rtoken, ok := d.GetOk("iam_refresh_token"); ok { + iamRefreshToken = rtoken.(string) + } + if ttoken, ok := d.GetOk("iam_profile_id"); ok { + iamTrustedProfileId = ttoken.(string) + } + var softlayerUsername, softlayerAPIKey, softlayerEndpointUrl string + var softlayerTimeout int + if username, ok := d.GetOk("softlayer_username"); ok { + softlayerUsername = username.(string) + } + if username, ok := d.GetOk("iaas_classic_username"); ok { + softlayerUsername = username.(string) + } + if apikey, ok := d.GetOk("softlayer_api_key"); ok { + softlayerAPIKey = apikey.(string) + } + if apikey, ok := d.GetOk("iaas_classic_api_key"); ok { + softlayerAPIKey = apikey.(string) + } + if endpoint, ok := d.GetOk("softlayer_endpoint_url"); ok { + softlayerEndpointUrl = endpoint.(string) + } + if endpoint, ok := d.GetOk("iaas_classic_endpoint_url"); ok { + softlayerEndpointUrl = endpoint.(string) + } + if tm, ok := d.GetOk("softlayer_timeout"); ok { + softlayerTimeout = tm.(int) + } + if tm, ok := d.GetOk("iaas_classic_timeout"); ok { + softlayerTimeout = tm.(int) + } + + if tm, ok := d.GetOk("bluemix_timeout"); ok { + bluemixTimeout = tm.(int) + } + if tm, ok := d.GetOk("ibmcloud_timeout"); ok { + bluemixTimeout = tm.(int) + } + var visibility string + if v, ok := d.GetOk("visibility"); ok { + visibility = v.(string) + } + var file string + if f, ok := d.GetOk("endpoints_file_path"); ok { + file = f.(string) + } + + resourceGrp := d.Get("resource_group").(string) + region := d.Get("region").(string) + zone := d.Get("zone").(string) + retryCount := d.Get("max_retries").(int) + wskNameSpace := d.Get("function_namespace").(string) + riaasEndPoint := d.Get("riaas_endpoint").(string) + + wskEnvVal, err := schema.EnvDefaultFunc("FUNCTION_NAMESPACE", "")() + if err != nil { + return nil, err + } + //Set environment variable to be used in DiffSupressFunction + if wskEnvVal.(string) == "" { + os.Setenv("FUNCTION_NAMESPACE", wskNameSpace) + } + + config := conns.Config{ + BluemixAPIKey: bluemixAPIKey, + Region: region, + ResourceGroup: resourceGrp, + BluemixTimeout: time.Duration(bluemixTimeout) * time.Second, + SoftLayerTimeout: time.Duration(softlayerTimeout) * time.Second, + SoftLayerUserName: softlayerUsername, + SoftLayerAPIKey: softlayerAPIKey, + RetryCount: retryCount, + SoftLayerEndpointURL: softlayerEndpointUrl, + RetryDelay: conns.RetryAPIDelay, + FunctionNameSpace: wskNameSpace, + RiaasEndPoint: riaasEndPoint, + IAMToken: iamToken, + IAMRefreshToken: iamRefreshToken, + Zone: zone, + Visibility: visibility, + EndpointsFile: file, + IAMTrustedProfileID: iamTrustedProfileId, + } + + return config.ClientSession() +} diff --git a/ibm/provider_test.go b/ibm/provider_test.go deleted file mode 100644 index 870a7cb60..000000000 --- a/ibm/provider_test.go +++ /dev/null @@ -1,771 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "os" - "strconv" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var appIDTenantID string -var appIDTestUserEmail string -var cfOrganization string -var cfSpace string -var cisDomainStatic string -var cisDomainTest string -var cisInstance string -var cisResourceGroup string -var cloudShellAccountID string -var cosCRN string -var ibmid1 string -var ibmid2 string -var IAMUser string -var datacenter string -var machineType string -var trustedMachineType string -var publicVlanID string -var privateVlanID string -var privateSubnetID string -var publicSubnetID string -var subnetID string -var lbaasDatacenter string -var lbaasSubnetId string -var lbListerenerCertificateInstance string -var ipsecDatacenter string -var customersubnetid string -var customerpeerip string -var dedicatedHostName string -var dedicatedHostID string -var kubeVersion string -var kubeUpdateVersion string -var zone string -var zonePrivateVlan string -var zonePublicVlan string -var zoneUpdatePrivateVlan string -var zoneUpdatePublicVlan string -var csRegion string -var extendedHardwareTesting bool -var err error -var placementGroupName string -var certCRN string -var updatedCertCRN string -var regionName string -var ISZoneName string -var ISCIDR string -var ISAddressPrefixCIDR string -var instanceProfileName string -var instanceProfileNameUpdate string -var dedicatedHostProfileName string -var dedicatedHostGroupID string -var instanceDiskProfileName string -var dedicatedHostGroupFamily string -var dedicatedHostGroupClass string -var volumeProfileName string -var ISRouteDestination string -var ISRouteNextHop string -var workspaceID string -var templateID string -var actionID string -var jobID string -var imageName string -var functionNamespace string -var hpcsInstanceID string -var secretsManagerInstanceID string -var secretsManagerSecretType string -var secretsManagerSecretID string -var hpcsAdmin1 string -var hpcsToken1 string -var hpcsAdmin2 string -var hpcsToken2 string -var realmName string -var iksSa string - -// For Power Colo - -var pi_image string -var pi_key_name string -var pi_volume_name string -var pi_network_name string -var pi_cloud_instance_id string -var pi_instance_name string - -// For Image - -var IsImageName string -var isImage string -var IsImageEncryptedDataKey string -var IsImageEncryptionKey string -var isWinImage string -var image_cos_url string -var image_cos_url_encrypted string -var image_operating_system string - -// Transit Gateway cross account -var tg_cross_network_account_id string -var tg_cross_network_id string - -//Enterprise Management -var account_to_be_imported string - -//Security and Compliance Center, SI -var scc_si_account string - -//Security and Compliance Center, Posture Management -var scc_posture_scope_id string -var scc_posture_scan_id string -var scc_posture_profile_id string - -func init() { - appIDTenantID = os.Getenv("IBM_APPID_TENANT_ID") - if appIDTenantID == "" { - fmt.Println("[WARN] Set the environment variable IBM_APPID_TENANT_ID for testing AppID resources, AppID tests will fail if this is not set") - } - - appIDTestUserEmail = os.Getenv("IBM_APPID_TEST_USER_EMAIL") - if appIDTestUserEmail == "" { - fmt.Println("[WARN] Set the environment variable IBM_APPID_TEST_USER_EMAIL for testing AppID user resources, the tests will fail if this is not set") - } - - cfOrganization = os.Getenv("IBM_ORG") - if cfOrganization == "" { - fmt.Println("[WARN] Set the environment variable IBM_ORG for testing ibm_org resource Some tests for that resource will fail if this is not set correctly") - } - cfSpace = os.Getenv("IBM_SPACE") - if cfSpace == "" { - fmt.Println("[WARN] Set the environment variable IBM_SPACE for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") - } - ibmid1 = os.Getenv("IBM_ID1") - if ibmid1 == "" { - fmt.Println("[WARN] Set the environment variable IBM_ID1 for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") - } - - ibmid2 = os.Getenv("IBM_ID2") - if ibmid2 == "" { - fmt.Println("[WARN] Set the environment variable IBM_ID2 for testing ibm_space resource Some tests for that resource will fail if this is not set correctly") - } - - IAMUser = os.Getenv("IBM_IAMUSER") - if IAMUser == "" { - fmt.Println("[WARN] Set the environment variable IBM_IAMUSER for testing ibm_iam_user_policy resource Some tests for that resource will fail if this is not set correctly") - } - - datacenter = os.Getenv("IBM_DATACENTER") - if datacenter == "" { - datacenter = "par01" - fmt.Println("[WARN] Set the environment variable IBM_DATACENTER for testing ibm_container_cluster resource else it is set to default value 'par01'") - } - - machineType = os.Getenv("IBM_MACHINE_TYPE") - if machineType == "" { - machineType = "b3c.4x16" - fmt.Println("[WARN] Set the environment variable IBM_MACHINE_TYPE for testing ibm_container_cluster resource else it is set to default value 'u2c.2x4'") - } - - certCRN = os.Getenv("IBM_CERT_CRN") - if certCRN == "" { - certCRN = "crn:v1:bluemix:public:cloudcerts:us-south:a/52b2e14f385aca5da781baa1b9c28e53:6efac0c2-b955-49ca-939d-d7bc0cb8132f:certificate:e786b0ea2af8b5435603803ec2ff8118" - fmt.Println("[WARN] Set the environment variable IBM_CERT_CRN for testing ibm_container_alb_cert resource else it is set to default value") - } - - updatedCertCRN = os.Getenv("IBM_UPDATE_CERT_CRN") - if updatedCertCRN == "" { - updatedCertCRN = "crn:v1:bluemix:public:cloudcerts:eu-de:a/e9021a4d06e9b108b4a221a3cec47e3d:77e527aa-65b2-4cb3-969b-7e8714174346:certificate:1bf3d0c2b7764402dde25744218e6cba" - fmt.Println("[WARN] Set the environment variable IBM_UPDATE_CERT_CRN for testing ibm_container_alb_cert resource else it is set to default value") - } - - csRegion = os.Getenv("IBM_CONTAINER_REGION") - if csRegion == "" { - csRegion = "eu-de" - fmt.Println("[WARN] Set the environment variable IBM_CONTAINER_REGION for testing ibm_container resources else it is set to default value 'eu-de'") - } - - cisInstance = os.Getenv("IBM_CIS_INSTANCE") - if cisInstance == "" { - cisInstance = "" - fmt.Println("[WARN] Set the environment variable IBM_CIS_INSTANCE with a VALID CIS Instance NAME for testing ibm_cis resources on staging/test") - } - cisDomainStatic = os.Getenv("IBM_CIS_DOMAIN_STATIC") - if cisDomainStatic == "" { - cisDomainStatic = "" - fmt.Println("[WARN] Set the environment variable IBM_CIS_DOMAIN_STATIC with the Domain name registered with the CIS instance on test/staging. Domain must be predefined in CIS to avoid CIS billing costs due to domain delete/create") - } - - cisDomainTest = os.Getenv("IBM_CIS_DOMAIN_TEST") - if cisDomainTest == "" { - cisDomainTest = "" - fmt.Println("[WARN] Set the environment variable IBM_CIS_DOMAIN_TEST with a VALID Domain name for testing the one time create and delete of a domain in CIS. Note each create/delete will trigger a monthly billing instance. Only to be run in staging/test") - } - - cisResourceGroup = os.Getenv("IBM_CIS_RESOURCE_GROUP") - if cisResourceGroup == "" { - cisResourceGroup = "" - fmt.Println("[WARN] Set the environment variable IBM_CIS_RESOURCE_GROUP with the resource group for the CIS Instance ") - } - - cosCRN = os.Getenv("IBM_COS_CRN") - if cosCRN == "" { - cosCRN = "" - fmt.Println("[WARN] Set the environment variable IBM_COS_CRN with a VALID COS instance CRN for testing ibm_cos_* resources") - } - - trustedMachineType = os.Getenv("IBM_TRUSTED_MACHINE_TYPE") - if trustedMachineType == "" { - trustedMachineType = "mb1c.16x64" - fmt.Println("[WARN] Set the environment variable IBM_TRUSTED_MACHINE_TYPE for testing ibm_container_cluster resource else it is set to default value 'mb1c.16x64'") - } - - extendedHardwareTesting, err = strconv.ParseBool(os.Getenv("IBM_BM_EXTENDED_HW_TESTING")) - if err != nil { - extendedHardwareTesting = false - fmt.Println("[WARN] Set the environment variable IBM_BM_EXTENDED_HW_TESTING to true/false for testing ibm_compute_bare_metal resource else it is set to default value 'false'") - } - - publicVlanID = os.Getenv("IBM_PUBLIC_VLAN_ID") - if publicVlanID == "" { - publicVlanID = "2393319" - fmt.Println("[WARN] Set the environment variable IBM_PUBLIC_VLAN_ID for testing ibm_container_cluster resource else it is set to default value '2393319'") - } - - privateVlanID = os.Getenv("IBM_PRIVATE_VLAN_ID") - if privateVlanID == "" { - privateVlanID = "2393321" - fmt.Println("[WARN] Set the environment variable IBM_PRIVATE_VLAN_ID for testing ibm_container_cluster resource else it is set to default value '2393321'") - } - - kubeVersion = os.Getenv("IBM_KUBE_VERSION") - if kubeVersion == "" { - kubeVersion = "1.18" - fmt.Println("[WARN] Set the environment variable IBM_KUBE_VERSION for testing ibm_container_cluster resource else it is set to default value '1.18.14'") - } - - kubeUpdateVersion = os.Getenv("IBM_KUBE_UPDATE_VERSION") - if kubeUpdateVersion == "" { - kubeUpdateVersion = "1.19" - fmt.Println("[WARN] Set the environment variable IBM_KUBE_UPDATE_VERSION for testing ibm_container_cluster resource else it is set to default value '1.19.6'") - } - - privateSubnetID = os.Getenv("IBM_PRIVATE_SUBNET_ID") - if privateSubnetID == "" { - privateSubnetID = "1636107" - fmt.Println("[WARN] Set the environment variable IBM_PRIVATE_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1636107'") - } - - publicSubnetID = os.Getenv("IBM_PUBLIC_SUBNET_ID") - if publicSubnetID == "" { - publicSubnetID = "1165645" - fmt.Println("[WARN] Set the environment variable IBM_PUBLIC_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1165645'") - } - - subnetID = os.Getenv("IBM_SUBNET_ID") - if subnetID == "" { - subnetID = "1165645" - fmt.Println("[WARN] Set the environment variable IBM_SUBNET_ID for testing ibm_container_cluster resource else it is set to default value '1165645'") - } - - ipsecDatacenter = os.Getenv("IBM_IPSEC_DATACENTER") - if ipsecDatacenter == "" { - ipsecDatacenter = "tok02" - fmt.Println("[INFO] Set the environment variable IBM_IPSEC_DATACENTER for testing ibm_ipsec_vpn resource else it is set to default value 'tok02'") - } - - customersubnetid = os.Getenv("IBM_IPSEC_CUSTOMER_SUBNET_ID") - if customersubnetid == "" { - customersubnetid = "123456" - fmt.Println("[INFO] Set the environment variable IBM_IPSEC_CUSTOMER_SUBNET_ID for testing ibm_ipsec_vpn resource else it is set to default value '123456'") - } - - customerpeerip = os.Getenv("IBM_IPSEC_CUSTOMER_PEER_IP") - if customerpeerip == "" { - customerpeerip = "192.168.0.1" - fmt.Println("[INFO] Set the environment variable IBM_IPSEC_CUSTOMER_PEER_IP for testing ibm_ipsec_vpn resource else it is set to default value '192.168.0.1'") - } - - lbaasDatacenter = os.Getenv("IBM_LBAAS_DATACENTER") - if lbaasDatacenter == "" { - lbaasDatacenter = "dal13" - fmt.Println("[WARN] Set the environment variable IBM_LBAAS_DATACENTER for testing ibm_lbaas resource else it is set to default value 'dal13'") - } - - lbaasSubnetId = os.Getenv("IBM_LBAAS_SUBNETID") - if lbaasSubnetId == "" { - lbaasSubnetId = "2144241" - fmt.Println("[WARN] Set the environment variable IBM_LBAAS_SUBNETID for testing ibm_lbaas resource else it is set to default value '2144241'") - } - lbListerenerCertificateInstance = os.Getenv("IBM_LB_LISTENER_CERTIFICATE_INSTANCE") - if lbListerenerCertificateInstance == "" { - lbListerenerCertificateInstance = "crn:v1:staging:public:cloudcerts:us-south:a/2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" - fmt.Println("[WARN] Set the environment variable IBM_LB_LISTENER_CERTIFICATE_INSTANCE for testing ibm_is_lb_listener resource for https redirect else it is set to default value 'crn:v1:staging:public:cloudcerts:us-south:a/2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed'") - } - - dedicatedHostName = os.Getenv("IBM_DEDICATED_HOSTNAME") - if dedicatedHostName == "" { - dedicatedHostName = "terraform-dedicatedhost" - fmt.Println("[WARN] Set the environment variable IBM_DEDICATED_HOSTNAME for testing ibm_compute_vm_instance resource else it is set to default value 'terraform-dedicatedhost'") - } - - dedicatedHostID = os.Getenv("IBM_DEDICATED_HOST_ID") - if dedicatedHostID == "" { - dedicatedHostID = "30301" - fmt.Println("[WARN] Set the environment variable IBM_DEDICATED_HOST_ID for testing ibm_compute_vm_instance resource else it is set to default value '30301'") - } - - zone = os.Getenv("IBM_WORKER_POOL_ZONE") - if zone == "" { - zone = "ams03" - fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value 'ams03'") - } - - zonePrivateVlan = os.Getenv("IBM_WORKER_POOL_ZONE_PRIVATE_VLAN") - if zonePrivateVlan == "" { - zonePrivateVlan = "2538975" - fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_PRIVATE_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2538975'") - } - - zonePublicVlan = os.Getenv("IBM_WORKER_POOL_ZONE_PUBLIC_VLAN") - if zonePublicVlan == "" { - zonePublicVlan = "2538967" - fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_PUBLIC_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2538967'") - } - - zoneUpdatePrivateVlan = os.Getenv("IBM_WORKER_POOL_ZONE_UPDATE_PRIVATE_VLAN") - if zoneUpdatePrivateVlan == "" { - zoneUpdatePrivateVlan = "2388377" - fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_UPDATE_PRIVATE_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2388377'") - } - - zoneUpdatePublicVlan = os.Getenv("IBM_WORKER_POOL_ZONE_UPDATE_PUBLIC_VLAN") - if zoneUpdatePublicVlan == "" { - zoneUpdatePublicVlan = "2388375" - fmt.Println("[WARN] Set the environment variable IBM_WORKER_POOL_ZONE_UPDATE_PUBLIC_VLAN for testing ibm_container_worker_pool_zone_attachment resource else it is set to default value '2388375'") - } - - placementGroupName = os.Getenv("IBM_PLACEMENT_GROUP_NAME") - if placementGroupName == "" { - placementGroupName = "terraform_group" - fmt.Println("[WARN] Set the environment variable IBM_PLACEMENT_GROUP_NAME for testing ibm_compute_vm_instance resource else it is set to default value 'terraform-group'") - } - - regionName = os.Getenv("SL_REGION") - if regionName == "" { - regionName = "us-south" - fmt.Println("[INFO] Set the environment variable SL_REGION for testing ibm_is_region datasource else it is set to default value 'us-south'") - } - - ISZoneName = os.Getenv("SL_ZONE") - if ISZoneName == "" { - ISZoneName = "us-south-1" - fmt.Println("[INFO] Set the environment variable SL_ZONE for testing ibm_is_zone datasource else it is set to default value 'us-south-1'") - } - - ISCIDR = os.Getenv("SL_CIDR") - if ISCIDR == "" { - ISCIDR = "10.240.0.0/24" - fmt.Println("[INFO] Set the environment variable SL_CIDR for testing ibm_is_subnet else it is set to default value '10.240.0.0/24'") - } - - ISAddressPrefixCIDR = os.Getenv("SL_ADDRESS_PREFIX_CIDR") - if ISAddressPrefixCIDR == "" { - ISAddressPrefixCIDR = "10.120.0.0/24" - fmt.Println("[INFO] Set the environment variable SL_ADDRESS_PREFIX_CIDR for testing ibm_is_vpc_address_prefix else it is set to default value '10.120.0.0/24'") - } - - isImage = os.Getenv("IS_IMAGE") - if isImage == "" { - //isImage = "fc538f61-7dd6-4408-978c-c6b85b69fe76" // for classic infrastructure - isImage = "r006-13938c0a-89e4-4370-b59b-55cd1402562d" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_IMAGE for testing ibm_is_instance, ibm_is_floating_ip else it is set to default value 'r006-ed3f775f-ad7e-4e37-ae62-7199b4988b00'") - } - - isWinImage = os.Getenv("IS_WIN_IMAGE") - if isWinImage == "" { - //isWinImage = "a7a0626c-f97e-4180-afbe-0331ec62f32a" // classic windows machine: ibm-windows-server-2012-full-standard-amd64-1 - isWinImage = "r006-5f9568ae-792e-47e1-a710-5538b2bdfca7" // next gen windows machine: ibm-windows-server-2012-full-standard-amd64-3 - fmt.Println("[INFO] Set the environment variable IS_WIN_IMAGE for testing ibm_is_instance data source else it is set to default value 'r006-5f9568ae-792e-47e1-a710-5538b2bdfca7'") - } - - instanceProfileName = os.Getenv("SL_INSTANCE_PROFILE") - if instanceProfileName == "" { - //instanceProfileName = "bc1-2x8" // for classic infrastructure - instanceProfileName = "cx2-2x4" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE for testing ibm_is_instance resource else it is set to default value 'cx2-2x4'") - } - - instanceProfileNameUpdate = os.Getenv("SL_INSTANCE_PROFILE_UPDATE") - if instanceProfileNameUpdate == "" { - instanceProfileNameUpdate = "cx2-4x8" - fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE_UPDATE for testing ibm_is_instance resource else it is set to default value 'cx2-4x8'") - } - - dedicatedHostName = os.Getenv("IS_DEDICATED_HOST_NAME") - if dedicatedHostName == "" { - dedicatedHostName = "tf-dhost-01" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_NAME for testing ibm_is_instance resource else it is set to default value 'tf-dhost-01'") - } - - dedicatedHostGroupID = os.Getenv("IS_DEDICATED_HOST_GROUP_ID") - if dedicatedHostGroupID == "" { - dedicatedHostGroupID = "0717-9104e7b5-77ad-44ad-9eaa-091e6b6efce1" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_ID for testing ibm_is_instance resource else it is set to default value '0717-9104e7b5-77ad-44ad-9eaa-091e6b6efce1'") - } - - dedicatedHostProfileName = os.Getenv("IS_DEDICATED_HOST_PROFILE") - if dedicatedHostProfileName == "" { - dedicatedHostProfileName = "bx2d-host-152x608" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_PROFILE for testing ibm_is_instance resource else it is set to default value 'bx2d-host-152x608'") - } - - dedicatedHostGroupClass = os.Getenv("IS_DEDICATED_HOST_GROUP_CLASS") - if dedicatedHostGroupClass == "" { - dedicatedHostGroupClass = "bx2d" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_CLASS for testing ibm_is_instance resource else it is set to default value 'bx2d'") - } - - dedicatedHostGroupFamily = os.Getenv("IS_DEDICATED_HOST_GROUP_FAMILY") - if dedicatedHostGroupFamily == "" { - dedicatedHostGroupFamily = "balanced" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_DEDICATED_HOST_GROUP_FAMILY for testing ibm_is_instance resource else it is set to default value 'balanced'") - } - - instanceDiskProfileName = os.Getenv("IS_INSTANCE_DISK_PROFILE") - if instanceDiskProfileName == "" { - //instanceProfileName = "bc1-2x8" // for classic infrastructure - instanceDiskProfileName = "bx2d-16x64" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE for testing ibm_is_instance resource else it is set to default value 'bx2d-16x64'") - } - - volumeProfileName = os.Getenv("IS_VOLUME_PROFILE") - if volumeProfileName == "" { - volumeProfileName = "general-purpose" - fmt.Println("[INFO] Set the environment variable IS_VOLUME_PROFILE for testing ibm_is_volume_profile else it is set to default value 'general-purpose'") - } - - ISRouteDestination = os.Getenv("SL_ROUTE_DESTINATION") - if ISRouteDestination == "" { - ISRouteDestination = "192.168.4.0/24" - fmt.Println("[INFO] Set the environment variable SL_ROUTE_DESTINATION for testing ibm_is_vpc_route else it is set to default value '192.168.4.0/24'") - } - - ISRouteNextHop = os.Getenv("SL_ROUTE_NEXTHOP") - if ISRouteNextHop == "" { - ISRouteNextHop = "10.240.0.0" - fmt.Println("[INFO] Set the environment variable SL_ROUTE_NEXTHOP for testing ibm_is_vpc_route else it is set to default value '10.0.0.4'") - } - - // Added for Power Colo Testing - pi_image = os.Getenv("PI_IMAGE") - if pi_image == "" { - pi_image = "c93dc4c6-e85a-4da2-9ea6-f24576256122" - fmt.Println("[INFO] Set the environment variable PI_IMAGE for testing ibm_pi_image resource else it is set to default value '7200-03-03'") - } - - pi_key_name = os.Getenv("PI_KEY_NAME") - if pi_key_name == "" { - pi_key_name = "terraform-test-power" - fmt.Println("[INFO] Set the environment variable PI_KEY_NAME for testing ibm_pi_key_name resource else it is set to default value 'terraform-test-power'") - } - - pi_network_name = os.Getenv("PI_NETWORK_NAME") - if pi_network_name == "" { - pi_network_name = "terraform-test-power" - fmt.Println("[INFO] Set the environment variable PI_NETWORK_NAME for testing ibm_pi_network_name resource else it is set to default value 'terraform-test-power'") - } - - pi_volume_name = os.Getenv("PI_VOLUME_NAME") - if pi_volume_name == "" { - pi_volume_name = "terraform-test-power" - fmt.Println("[INFO] Set the environment variable PI_VOLUME_NAME for testing ibm_pi_network_name resource else it is set to default value 'terraform-test-power'") - } - - pi_cloud_instance_id = os.Getenv("PI_CLOUDINSTANCE_ID") - if pi_cloud_instance_id == "" { - pi_cloud_instance_id = "fd3454a3-14d8-4eb0-b075-acf3da5cd324" - fmt.Println("[INFO] Set the environment variable PI_CLOUDINSTANCE_ID for testing ibm_pi_image resource else it is set to default value 'd16705bd-7f1a-48c9-9e0e-1c17b71e7331'") - } - - pi_instance_name = os.Getenv("PI_PVM_INSTANCE_NAME") - if pi_instance_name == "" { - pi_instance_name = "terraform-test-power" - fmt.Println("[INFO] Set the environment variable PI_PVM_INSTANCE_ID for testing pi_instance_name resource else it is set to default value 'terraform-test-power'") - } - workspaceID = os.Getenv("SCHEMATICS_WORKSPACE_ID") - if workspaceID == "" { - workspaceID = "us-south.workspace.tf-acc-test-schematics-state-test.392cd99f" - fmt.Println("[INFO] Set the environment variable SCHEMATICS_WORKSPACE_ID for testing schematics resources else it is set to default value") - } - templateID = os.Getenv("SCHEMATICS_TEMPLATE_ID") - if templateID == "" { - templateID = "c8d52331-056f-40" - fmt.Println("[INFO] Set the environment variable SCHEMATICS_TEMPLATE_ID for testing schematics resources else it is set to default value") - } - actionID = os.Getenv("SCHEMATICS_ACTION_ID") - if actionID == "" { - actionID = "us-east.ACTION.action_pm.a4ffeec3" - fmt.Println("[INFO] Set the environment variable SCHEMATICS_ACTION_ID for testing schematics resources else it is set to default value") - } - jobID = os.Getenv("SCHEMATICS_JOB_ID") - if actionID == "" { - actionID = "us-east.ACTION.action_pm.a4ffeec3" - fmt.Println("[INFO] Set the environment variable SCHEMATICS_JOB_ID for testing schematics resources else it is set to default value") - } - // Added for resource image testing - image_cos_url = os.Getenv("IMAGE_COS_URL") - if image_cos_url == "" { - image_cos_url = "cos://us-south/cosbucket-vpc-image-gen2/rhel-guest-image-7.0-20140930.0.x86_64.qcow2" - fmt.Println("[WARN] Set the environment variable IMAGE_COS_URL with a VALID COS Image SQL URL for testing ibm_is_image resources on staging/test") - } - - // Added for resource image testing - image_cos_url_encrypted = os.Getenv("IMAGE_COS_URL_ENCRYPTED") - if image_cos_url_encrypted == "" { - image_cos_url_encrypted = "cos://us-south/cosbucket-vpc-image-gen2/rhel-guest-image-7.0-encrypted.qcow2" - fmt.Println("[WARN] Set the environment variable IMAGE_COS_URL_ENCRYPTED with a VALID COS Image SQL URL for testing ibm_is_image resources on staging/test") - } - image_operating_system = os.Getenv("IMAGE_OPERATING_SYSTEM") - if image_operating_system == "" { - image_operating_system = "red-7-amd64" - fmt.Println("[WARN] Set the environment variable IMAGE_OPERATING_SYSTEM with a VALID Operating system for testing ibm_is_image resources on staging/test") - } - - IsImageName = os.Getenv("IS_IMAGE_NAME") - if IsImageName == "" { - //IsImageName = "ibm-ubuntu-18-04-2-minimal-amd64-1" // for classic infrastructure - IsImageName = "ibm-ubuntu-18-04-1-minimal-amd64-2" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_IMAGE_NAME for testing data source ibm_is_image else it is set to default value `ibm-ubuntu-18-04-1-minimal-amd64-2`") - } - IsImageEncryptedDataKey = os.Getenv("IS_IMAGE_ENCRYPTED_DATA_KEY") - if IsImageEncryptedDataKey == "" { - IsImageEncryptedDataKey = "eyJjaXBoZXJ0ZXh0IjoidElsZnRjUXB5L0krSGJsMlVIK2ZxZ1FGK1diR3loV1dPRFk9IiwiaXYiOiJ3SlhSVklsSHUzMzFqUEY0IiwidmVyc2lvbiI6IjQuMC4wIiwiaGFuZGxlIjoiZjM2YTA2NGUtY2E2My00NmU0LThlNjAtYmJiMzEyNTY5YzM1In0=" - fmt.Println("[INFO] Set the environment variable IS_IMAGE_ENCRYPTED_DATA_KEY for testing resource ibm_is_image else it is set to default value") - } - IsImageEncryptionKey = os.Getenv("IS_IMAGE_ENCRYPTION_KEY") - if IsImageEncryptionKey == "" { - IsImageEncryptionKey = "crn:v1:bluemix:public:kms:us-south:a/52b2e14f385aca5da781baa1b9c28e53:21d9f13d-5895-49a1-9e80-b4aff69dfc1f:key:f36a064e-ca63-46e4-8e60-bbb312569c35" - fmt.Println("[INFO] Set the environment variable IS_IMAGE_ENCRYPTION_KEY for testing resource ibm_is_image else it is set to default value") - } - - functionNamespace = os.Getenv("IBM_FUNCTION_NAMESPACE") - if functionNamespace == "" { - fmt.Println("[INFO] Set the environment variable IBM_FUNCTION_NAMESPACE for testing ibm_function_package, ibm_function_action, ibm_function_rule, ibm_function_trigger resource else tests will fail if this is not set correctly") - } - - hpcsInstanceID = os.Getenv("HPCS_INSTANCE_ID") - if hpcsInstanceID == "" { - hpcsInstanceID = "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8" - fmt.Println("[INFO] Set the environment variable HPCS_INSTANCE_ID for testing data_source_ibm_kms_key_test else it is set to default value") - } - - secretsManagerInstanceID = os.Getenv("SECRETS_MANAGER_INSTANCE_ID") - if secretsManagerInstanceID == "" { - // secretsManagerInstanceID = "5af62d5d-5d90-4b84-bbcd-90d2123ae6c8" - fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_INSTANCE_ID for testing data_source_ibm_secrets_manager_secrets_test else tests will fail if this is not set correctly") - } - - secretsManagerSecretType = os.Getenv("SECRETS_MANAGER_SECRET_TYPE") - if secretsManagerSecretType == "" { - secretsManagerSecretType = "username_password" - fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_SECRET_TYPE for testing data_source_ibm_secrets_manager_secrets_test, else it is set to default value. For data_source_ibm_secrets_manager_secret_test, tests will fail if this is not set correctly") - } - - secretsManagerSecretID = os.Getenv("SECRETS_MANAGER_SECRET_ID") - if secretsManagerSecretID == "" { - // secretsManagerSecretID = "644f4a69-0d17-198f-3b58-23f2746c706d" - fmt.Println("[WARN] Set the environment variable SECRETS_MANAGER_SECRET_ID for testing data_source_ibm_secrets_manager_secret_test else tests will fail if this is not set correctly") - } - - tg_cross_network_account_id = os.Getenv("IBM_TG_CROSS_ACCOUNT_ID") - if tg_cross_network_account_id == "" { - fmt.Println("[INFO] Set the environment variable IBM_TG_CROSS_ACCOUNT_ID for testing ibm_tg_connection resource else tests will fail if this is not set correctly") - } - tg_cross_network_id = os.Getenv("IBM_TG_CROSS_NETWORK_ID") - if tg_cross_network_id == "" { - fmt.Println("[INFO] Set the environment variable IBM_TG_CROSS_NETWORK_ID for testing ibm_tg_connection resource else tests will fail if this is not set correctly") - } - account_to_be_imported = os.Getenv("ACCOUNT_TO_BE_IMPORTED") - if account_to_be_imported == "" { - fmt.Println("[INFO] Set the environment variable ACCOUNT_TO_BE_IMPORTED for testing import enterprise account resource else tests will fail if this is not set correctly") - } - hpcsAdmin1 = os.Getenv("IBM_HPCS_ADMIN1") - if hpcsAdmin1 == "" { - fmt.Println("[WARN] Set the environment variable IBM_HPCS_ADMIN1 with a VALID HPCS Admin Key1 Path") - } - hpcsToken1 = os.Getenv("IBM_HPCS_TOKEN1") - if hpcsToken1 == "" { - fmt.Println("[WARN] Set the environment variable IBM_HPCS_TOKEN1 with a VALID token for HPCS Admin Key1") - } - hpcsAdmin2 = os.Getenv("IBM_HPCS_ADMIN2") - if hpcsAdmin2 == "" { - fmt.Println("[WARN] Set the environment variable IBM_HPCS_ADMIN2 with a VALID HPCS Admin Key2 Path") - } - realmName = os.Getenv("IBM_IAM_REALM_NAME") - if realmName == "" { - fmt.Println("[WARN] Set the environment variable IBM_IAM_REALM_NAME with a VALID realm name for iam trusted profile claim rule") - } - - iksSa = os.Getenv("IBM_IAM_IKS_SA") - if iksSa == "" { - fmt.Println("[WARN] Set the environment variable IBM_IAM_IKS_SA with a VALID realm name for iam trusted profile link") - } - - hpcsToken2 = os.Getenv("IBM_HPCS_TOKEN2") - if hpcsToken2 == "" { - fmt.Println("[WARN] Set the environment variable IBM_HPCS_TOKEN2 with a VALID token for HPCS Admin Key2") - } - scc_si_account = os.Getenv("SCC_SI_ACCOUNT") - if scc_si_account == "" { - fmt.Println("[INFO] Set the environment variable SCC_SI_ACCOUNT for testing SCC SI resources resource else tests will fail if this is not set correctly") - } - - scc_posture_scope_id = os.Getenv("SCC_POSTURE_SCOPE_ID") - if scc_posture_scope_id == "" { - fmt.Println("[INFO] Set the environment variable SCC_POSTURE_SCOPE_ID for testing SCC Posture resources or datasource resource else tests will fail if this is not set correctly") - } - - scc_posture_scan_id = os.Getenv("SCC_POSTURE_SCAN_ID") - if scc_posture_scan_id == "" { - fmt.Println("[INFO] Set the environment variable SCC_POSTURE_SCAN_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") - } - - scc_posture_profile_id = os.Getenv("SCC_POSTURE_PROFILE_ID") - if scc_posture_profile_id == "" { - fmt.Println("[INFO] Set the environment variable SCC_POSTURE_PROFILE_ID for testing SCC Posture resource or datasource else tests will fail if this is not set correctly") - } - - cloudShellAccountID = os.Getenv("IBM_CLOUD_SHELL_ACCOUNT_ID") - if cloudShellAccountID == "" { - fmt.Println("[INFO] Set the environment variable IBM_CLOUD_SHELL_ACCOUNT_ID for ibm-cloud-shell resource or datasource else tests will fail if this is not set correctly") - } - -} - -var testAccProviders map[string]*schema.Provider -var testAccProvider *schema.Provider - -func init() { - testAccProvider = Provider() - testAccProviders = map[string]*schema.Provider{ - "ibm": testAccProvider, - } -} - -func TestProvider(t *testing.T) { - if err := Provider().InternalValidate(); err != nil { - t.Fatalf("err: %s", err) - } -} - -func TestProvider_impl(t *testing.T) { - var _ *schema.Provider = Provider() -} - -func testAccPreCheck(t *testing.T) { - if v := os.Getenv("IC_API_KEY"); v == "" { - t.Fatal("IC_API_KEY must be set for acceptance tests") - } - if v := os.Getenv("IAAS_CLASSIC_API_KEY"); v == "" { - t.Fatal("IAAS_CLASSIC_API_KEY must be set for acceptance tests") - } - if v := os.Getenv("IAAS_CLASSIC_USERNAME"); v == "" { - t.Fatal("IAAS_CLASSIC_USERNAME must be set for acceptance tests") - } -} - -func testAccPreCheckEnterprise(t *testing.T) { - if v := os.Getenv("IC_API_KEY"); v == "" { - t.Fatal("IC_API_KEY must be set for acceptance tests") - } - -} - -func testAccPreCheckEnterpriseAccountImport(t *testing.T) { - if v := os.Getenv("IC_API_KEY"); v == "" { - t.Fatal("IC_API_KEY must be set for acceptance tests") - } - if account_to_be_imported == "" { - t.Fatal("ACCOUNT_TO_BE_IMPORTED must be set for acceptance tests") - } - -} -func testAccPreCheckCis(t *testing.T) { - testAccPreCheck(t) - if cisInstance == "" { - t.Fatal("IBM_CIS_INSTANCE must be set for acceptance tests") - } - if cisResourceGroup == "" { - t.Fatal("IBM_CIS_RESOURCE_GROUP must be set for acceptance tests") - } - if cisDomainStatic == "" { - t.Fatal("IBM_CIS_DOMAIN_STATIC must be set for acceptance tests") - } - if cisDomainTest == "" { - t.Fatal("IBM_CIS_DOMAIN_TEST must be set for acceptance tests") - } -} - -func testAccPreCheckCloudShell(t *testing.T) { - testAccPreCheck(t) - if cloudShellAccountID == "" { - t.Fatal("IBM_CLOUD_SHELL_ACCOUNT_ID must be set for acceptance tests") - } -} - -func testAccPreCheckHPCS(t *testing.T) { - testAccPreCheck(t) - if hpcsAdmin1 == "" { - t.Fatal("IBM_HPCS_ADMIN1 must be set for acceptance tests") - } - if hpcsToken1 == "" { - t.Fatal("IBM_HPCS_TOKEN1 must be set for acceptance tests") - } - if hpcsAdmin2 == "" { - t.Fatal("IBM_HPCS_ADMIN2 must be set for acceptance tests") - } - if hpcsToken2 == "" { - t.Fatal("IBM_HPCS_TOKEN2 must be set for acceptance tests") - } -} -func testAccPreCheckIAMTrustedProfile(t *testing.T) { - testAccPreCheck(t) - if realmName == "" { - t.Fatal("IBM_IAM_REALM_NAME must be set for acceptance tests") - } - if iksSa == "" { - t.Fatal("IBM_IAM_IKS_SA must be set for acceptance tests") - } -} - -func testAccPreCheckCOS(t *testing.T) { - testAccPreCheck(t) - if cosCRN == "" { - t.Fatal("IBM_COS_CRN must be set for acceptance tests") - } -} - -func testAccPreCheckImage(t *testing.T) { - testAccPreCheck(t) - if image_cos_url == "" { - t.Fatal("IMAGE_COS_URL must be set for acceptance tests") - } - if image_operating_system == "" { - t.Fatal("IMAGE_OPERATING_SYSTEM must be set for acceptance tests") - } -} -func testAccPreCheckEncryptedImage(t *testing.T) { - testAccPreCheck(t) - if image_cos_url_encrypted == "" { - t.Fatal("IMAGE_COS_URL_ENCRYPTED must be set for acceptance tests") - } - if image_operating_system == "" { - t.Fatal("IMAGE_OPERATING_SYSTEM must be set for acceptance tests") - } - if IsImageEncryptedDataKey == "" { - t.Fatal("IS_IMAGE_ENCRYPTED_DATA_KEY must be set for acceptance tests") - } - if IsImageEncryptionKey == "" { - t.Fatal("IS_IMAGE_ENCRYPTION_KEY must be set for acceptance tests") - } -} diff --git a/ibm/qualified_name.go b/ibm/qualified_name.go deleted file mode 100644 index 95a67fce5..000000000 --- a/ibm/qualified_name.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "os" - "strings" -) - -type QualifiedName struct { - namespace string // namespace. does not include leading '/'. may be "" (i.e. default namespace) - packageName string // package. may be "". does not include leading/trailing '/' - entity string // entity. should not be "" - EntityName string // pkg+entity -} - -// Imported code from openwhisk cli https://github.com/apache/incubator-openwhisk/tree/26146368f1dd07f817062e662db64c73a8d486d6/tools/cli/go-whisk-cli/commands -/////////////////////////// -// QualifiedName Methods // -/////////////////////////// - -// GetFullQualifiedName() returns a full qualified name in proper string format -// from qualifiedName with proper syntax. -// Example: /namespace/[package/]entity -func (qualifiedName *QualifiedName) GetFullQualifiedName() string { - output := []string{} - - if len(qualifiedName.GetNamespace()) > 0 { - output = append(output, "/", qualifiedName.GetNamespace(), "/") - } - if len(qualifiedName.GetPackageName()) > 0 { - output = append(output, qualifiedName.GetPackageName(), "/") - } - output = append(output, qualifiedName.GetEntity()) - - return strings.Join(output, "") -} - -// GetPackageName() returns the package name from qualifiedName without a -// leading '/' -func (qualifiedName *QualifiedName) GetPackageName() string { - return qualifiedName.packageName -} - -// GetEntityName() returns the entity name ([package/]entity) of qualifiedName -// without a leading '/' -func (qualifiedName *QualifiedName) GetEntityName() string { - return qualifiedName.EntityName -} - -// GetEntity() returns the name of entity in qualifiedName without a leading '/' -func (qualifiedName *QualifiedName) GetEntity() string { - return qualifiedName.entity -} - -// GetNamespace() returns the name of the namespace in qualifiedName without -// a leading '/' -func (qualifiedName *QualifiedName) GetNamespace() string { - return qualifiedName.namespace -} - -// NewQualifiedName(name) initializes and constructs a (possibly fully qualified) -// QualifiedName struct. -// -// NOTE: If the given qualified name is None, then this is a default qualified -// name and it is resolved from properties. -// NOTE: If the namespace is missing from the qualified name, the namespace -// is also resolved from the property file. -// -// Examples: -// foo => qualifiedName {namespace: "_", entityName: foo} -// pkg/foo => qualifiedName {namespace: "_", entityName: pkg/foo} -// /ns/foo => qualifiedName {namespace: ns, entityName: foo} -// /ns/pkg/foo => qualifiedName {namespace: ns, entityName: pkg/foo} -func NewQualifiedName(name string) (*QualifiedName, error) { - qualifiedName := new(QualifiedName) - - // If name has a preceding delimiter (/), or if it has two delimiters with a - // leading non-empty string, then it contains a namespace. Otherwise the name - // does not specify a namespace, so default the namespace to the namespace - // value set in the properties file; if that is not set, use "_" - name = addLeadSlash(name) - parts := strings.Split(name, "/") - if strings.HasPrefix(name, "/") { - qualifiedName.namespace = parts[1] - - if len(parts) < 2 || len(parts) > 4 { - return qualifiedName, qualifiedNameNotSpecifiedErr() - } - - for i := 1; i < len(parts); i++ { - if len(parts[i]) == 0 || parts[i] == "." { - return qualifiedName, qualifiedNameNotSpecifiedErr() - } - } - - qualifiedName.EntityName = strings.Join(parts[2:], "/") - if len(parts) == 4 { - qualifiedName.packageName = parts[2] - } - qualifiedName.entity = parts[len(parts)-1] - } else { - if len(name) == 0 || name == "." { - return qualifiedName, qualifiedNameNotSpecifiedErr() - } - - qualifiedName.entity = parts[len(parts)-1] - if len(parts) == 2 { - qualifiedName.packageName = parts[0] - } - qualifiedName.EntityName = name - qualifiedName.namespace = getNamespaceFromProp() - } - - return qualifiedName, nil -} - -///////////////////// -// Error Functions // -///////////////////// - -// qualifiedNameNotSpecifiedErr() returns generic whisk error for -// invalid qualified names detected while building a new -// QualifiedName struct. -func qualifiedNameNotSpecifiedErr() error { - return errors.New("A valid qualified name must be specified.") -} - -// NewQualifiedNameError(entityName, err) returns specific whisk error -// for invalid qualified names. -func NewQualifiedNameError(entityName string, err error) error { - errorMsg := fmt.Sprintf("%s is not a alid qualified name %s", entityName, err) - return errors.New(errorMsg) -} - -/////////////////////////// -// Helper/Misc Functions // -/////////////////////////// - -// addLeadSlash(name) returns a (possibly fully qualified) resource name, -// inserting a leading '/' if it is of 3 parts (namespace/package/action) -// and lacking the leading '/'. -func addLeadSlash(name string) string { - parts := strings.Split(name, "/") - if len(parts) == 3 && parts[0] != "" { - name = "/" + name - } - return name -} - -// getNamespaceFromProp() returns a namespace from Properties if one exists, -// else defaults to returning "_" -func getNamespaceFromProp() string { - namespace := os.Getenv("FUNCTION_NAMESPACE") - return namespace -} - -// getQualifiedName(name, namespace) returns a fully qualified name given a -// (possibly fully qualified) resource name and optional namespace. -// -// Examples: -// (foo, None) => /_/foo -// (pkg/foo, None) => /_/pkg/foo -// (foo, ns) => /ns/foo -// (/ns/pkg/foo, None) => /ns/pkg/foo -// (/ns/pkg/foo, otherns) => /ns/pkg/foo -func getQualifiedName(name string, namespace string) string { - name = addLeadSlash(name) - if strings.HasPrefix(name, "/") { - return name - } else if strings.HasPrefix(namespace, "/") { - return fmt.Sprintf("%s/%s", namespace, name) - } else { - if len(namespace) == 0 { - namespace = getNamespaceFromProp() - } - return fmt.Sprintf("/%s/%s", namespace, name) - } -} diff --git a/ibm/resource_ibm_appid_audit_status_test.go b/ibm/resource_ibm_appid_audit_status_test.go deleted file mode 100644 index 2ff8f946d..000000000 --- a/ibm/resource_ibm_appid_audit_status_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccIBMAppIDAuditStatus_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDAuditStatusDestroy, - Steps: []resource.TestStep{ - { - Config: setupAppIDAuditStatusConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_audit_status.status", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_audit_status.status", "is_active", "true"), - ), - }, - }, - }) -} - -func testAccCheckIBMAppIDAuditStatusDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_audit_status" { - continue - } - - tenantID := rs.Primary.ID - - cfg, _, err := appIDClient.GetAuditStatus(&appid.GetAuditStatusOptions{ - TenantID: &tenantID, - }) - - // default for audit status is `false` - if err != nil || (cfg.IsActive != nil && *cfg.IsActive != false) { - return fmt.Errorf("error checking if AppID audit status (%s) has been destroyed", rs.Primary.ID) - } - } - - return nil -} - -func setupAppIDAuditStatusConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_audit_status" "status" { - tenant_id = "%s" - is_active = true - } - `, tenantID) -} diff --git a/ibm/resource_ibm_appid_idp_facebook_test.go b/ibm/resource_ibm_appid_idp_facebook_test.go deleted file mode 100644 index fba28aa30..000000000 --- a/ibm/resource_ibm_appid_idp_facebook_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccAppIDIDPFacebook_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDIDPFacebookDestroy, - Steps: []resource.TestStep{ - { - Config: setupIBMAppIDFacebookIDPConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "config.0.application_id", "test_id"), - resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "config.0.application_secret", "test_secret"), - resource.TestCheckResourceAttrSet("ibm_appid_idp_facebook.fb", "redirect_url"), - ), - }, - }, - }) -} - -func setupIBMAppIDFacebookIDPConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_idp_facebook" "fb" { - tenant_id = "%s" - is_active = true - - config { - application_id = "test_id" - application_secret = "test_secret" - } - } - `, tenantID) -} - -func testAccCheckIBMAppIDIDPFacebookDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_idp_facebook" { - continue - } - - tenantID := rs.Primary.ID - - config, _, err := appIDClient.GetFacebookIDP(&appid.GetFacebookIDPOptions{ - TenantID: &tenantID, - }) - - if err != nil { - return fmt.Errorf("Error checking if AppID Facebook IDP configuration was reset: %s", err) - } - - if config == nil || (config.IsActive != nil && *config.IsActive != false) { - return fmt.Errorf("Error checking if AppID Facebook IDP configuration was reset") - } - } - - return nil -} diff --git a/ibm/resource_ibm_appid_idp_google_test.go b/ibm/resource_ibm_appid_idp_google_test.go deleted file mode 100644 index 475645d44..000000000 --- a/ibm/resource_ibm_appid_idp_google_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccAppIDIDPGoogle_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDIDPGoogleDestroy, - Steps: []resource.TestStep{ - { - Config: setupIBMAppIDGoogleIDPConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "config.0.application_id", "test_id"), - resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "config.0.application_secret", "test_secret"), - resource.TestCheckResourceAttrSet("ibm_appid_idp_google.gg", "redirect_url"), - ), - }, - }, - }) -} - -func setupIBMAppIDGoogleIDPConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_idp_google" "gg" { - tenant_id = "%s" - is_active = true - - config { - application_id = "test_id" - application_secret = "test_secret" - } - } - `, tenantID) -} - -func testAccCheckIBMAppIDIDPGoogleDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_idp_google" { - continue - } - - tenantID := rs.Primary.ID - - config, _, err := appIDClient.GetGoogleIDP(&appid.GetGoogleIDPOptions{ - TenantID: &tenantID, - }) - - if err != nil { - return fmt.Errorf("Error checking if AppID Google IDP configuration was reset: %s", err) - } - - if config == nil || (config.IsActive != nil && *config.IsActive != false) { - return fmt.Errorf("Error checking if AppID Google IDP configuration was reset") - } - } - - return nil -} diff --git a/ibm/resource_ibm_appid_mfa_channel_test.go b/ibm/resource_ibm_appid_mfa_channel_test.go deleted file mode 100644 index 82f7d585b..000000000 --- a/ibm/resource_ibm_appid_mfa_channel_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccAppIDMFAChannel_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDMFAChannelDestroy, - Steps: []resource.TestStep{ - { - Config: setupIBMMFAChannelConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "active", "sms"), - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.#", "1"), - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.key", "api_key"), - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.secret", "api_secret"), - resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.from", "+12223334444"), - ), - }, - }, - }) -} - -func setupIBMMFAChannelConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_mfa_channel" "mf" { - tenant_id = "%s" - active = "sms" - - sms_config { - key = "api_key" - secret = "api_secret" - from = "+12223334444" - } - } - `, tenantID) -} - -func testAccCheckIBMAppIDMFAChannelDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_mfa_channel" { - continue - } - - tenantID := rs.Primary.ID - - ch, _, err := appIDClient.ListChannels(&appid.ListChannelsOptions{ - TenantID: &tenantID, - }) - - if err != nil { - return fmt.Errorf("Error checking if AppID MFA channel configuration was reset: %s", err) - } - - for _, channel := range ch.Channels { - if *channel.IsActive && *channel.Type != "email" { - return fmt.Errorf("Error checking if AppID MFA channel configuration was reset") - } - } - } - - return nil -} diff --git a/ibm/resource_ibm_appid_mfa_test.go b/ibm/resource_ibm_appid_mfa_test.go deleted file mode 100644 index 9bd78197e..000000000 --- a/ibm/resource_ibm_appid_mfa_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package ibm - -import ( - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" -) - -func TestAccAppIDMFA_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: setupIBMMFAConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_mfa.mf", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_mfa.mf", "is_active", "true"), - ), - }, - }, - }) -} - -func setupIBMMFAConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_mfa" "mf" { - tenant_id = "%s" - is_active = true - } - `, tenantID) -} diff --git a/ibm/resource_ibm_appid_password_regex_test.go b/ibm/resource_ibm_appid_password_regex_test.go deleted file mode 100644 index e01dc811d..000000000 --- a/ibm/resource_ibm_appid_password_regex_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccIBMAppIDPasswordRegex_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDPasswordRegexDestroy, - Steps: []resource.TestStep{ - { - Config: setupIBMAppIDPasswordRegexConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "regex", "^(?:(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*)$"), - resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "error_message", "test error"), - ), - }, - }, - }) -} - -func setupIBMAppIDPasswordRegexConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_password_regex" "rgx" { - tenant_id = "%s" - regex = "^(?:(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*)$" - error_message = "test error" - } - `, tenantID) -} - -func testAccCheckIBMAppIDPasswordRegexDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_password_regex" { - continue - } - - tenantID := rs.Primary.ID - - config, _, err := appIDClient.GetCloudDirectoryPasswordRegex(&appid.GetCloudDirectoryPasswordRegexOptions{ - TenantID: &tenantID, - }) - - if err != nil { - return fmt.Errorf("Error checking if AppID Password Regex was reset: %s", err) - } - - // verify that configuration is reset to defaults - if config == nil || (config.Base64EncodedRegex != nil && *config.Base64EncodedRegex != "") { - return fmt.Errorf("Error checking if AppID Password Regex was reset") - } - } - - return nil -} diff --git a/ibm/resource_ibm_appid_theme_color_test.go b/ibm/resource_ibm_appid_theme_color_test.go deleted file mode 100644 index 9b8ab00c6..000000000 --- a/ibm/resource_ibm_appid_theme_color_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccThemeColor_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDThemeColorDestroy, - Steps: []resource.TestStep{ - { - Config: setupAppIDThemeColorConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_theme_color.color", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_theme_color.color", "header_color", "#000000"), - ), - }, - }, - }) -} - -func setupAppIDThemeColorConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_theme_color" "color" { - tenant_id = "%s" - header_color = "#000000" - } - `, tenantID) -} - -func testAccCheckIBMAppIDThemeColorDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_theme_color" { - continue - } - - tenantID := rs.Primary.ID - - cfg, _, err := appIDClient.GetThemeColor(&appid.GetThemeColorOptions{ - TenantID: &tenantID, - }) - - // AppID default default #EEF2F5 - if err != nil || (cfg.HeaderColor != nil && *cfg.HeaderColor != "#EEF2F5") { - return fmt.Errorf("error checking if AppID theme color configuration (%s) has been reset", rs.Primary.ID) - } - } - - return nil -} diff --git a/ibm/resource_ibm_appid_theme_text_test.go b/ibm/resource_ibm_appid_theme_text_test.go deleted file mode 100644 index 736ccd42c..000000000 --- a/ibm/resource_ibm_appid_theme_text_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package ibm - -import ( - "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" -) - -func TestAccThemeText_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAppIDThemeTextDestroy, - Steps: []resource.TestStep{ - { - Config: setupAppIDThemeTextConfig(appIDTenantID), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "tenant_id", appIDTenantID), - resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "tab_title", "resource test title"), - resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "footnote", "resource test footnote"), - ), - }, - }, - }) -} - -func setupAppIDThemeTextConfig(tenantID string) string { - return fmt.Sprintf(` - resource "ibm_appid_theme_text" "text" { - tenant_id = "%s" - tab_title = "resource test title" - footnote = "resource test footnote" - } - `, tenantID) -} - -func testAccCheckIBMAppIDThemeTextDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() - - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_appid_theme_text" { - continue - } - - tenantID := rs.Primary.ID - - cfg, _, err := appIDClient.GetThemeText(&appid.GetThemeTextOptions{ - TenantID: &tenantID, - }) - - if err != nil || (cfg.TabTitle != nil && *cfg.TabTitle != "Login") || (cfg.Footnote != nil && *cfg.Footnote != "Powered by App ID") { - return fmt.Errorf("error checking if AppID theme text configuration (%s) has been reset", rs.Primary.ID) - } - } - - return nil -} diff --git a/ibm/resource_ibm_atracker_route.go b/ibm/resource_ibm_atracker_route.go deleted file mode 100644 index 9e09a99e2..000000000 --- a/ibm/resource_ibm_atracker_route.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/atrackerv1" -) - -func resourceIBMAtrackerRoute() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMAtrackerRouteCreate, - ReadContext: resourceIBMAtrackerRouteRead, - UpdateContext: resourceIBMAtrackerRouteUpdate, - DeleteContext: resourceIBMAtrackerRouteDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_atracker_route", "name"), - Description: "The name of the route. The name must be 1000 characters or less and cannot include any special characters other than `(space) - . _ :`.", - }, - "receive_global_events": &schema.Schema{ - Type: schema.TypeBool, - Required: true, - Description: "Indicates whether or not all global events should be forwarded to this region.", - }, - "rules": &schema.Schema{ - Type: schema.TypeList, - Required: true, - Description: "Routing rules that will be evaluated in their order of the array.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target_ids": &schema.Schema{ - Type: schema.TypeList, - Required: true, - Description: "The target ID List. Only 1 target id is supported.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the route resource.", - }, - "version": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The version of the route.", - }, - "created": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the route creation time.", - }, - "updated": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the route last updated time.", - }, - }, - } -} - -func resourceIBMAtrackerRouteValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^[a-zA-Z0-9 -._:]+$`, - MinValueLength: 1, - MaxValueLength: 1000, - }, - ) - - resourceValidator := ResourceValidator{ResourceName: "ibm_atracker_route", Schema: validateSchema} - return &resourceValidator -} - -func resourceIBMAtrackerRouteCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - createRouteOptions := &atrackerv1.CreateRouteOptions{} - - createRouteOptions.SetName(d.Get("name").(string)) - createRouteOptions.SetReceiveGlobalEvents(d.Get("receive_global_events").(bool)) - var rules []atrackerv1.Rule - for _, e := range d.Get("rules").([]interface{}) { - value := e.(map[string]interface{}) - rulesItem := resourceIBMAtrackerRouteMapToRule(value) - rules = append(rules, rulesItem) - } - createRouteOptions.SetRules(rules) - - route, response, err := atrackerClient.CreateRouteWithContext(context, createRouteOptions) - if err != nil { - log.Printf("[DEBUG] CreateRouteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("CreateRouteWithContext failed %s\n%s", err, response)) - } - - d.SetId(*route.ID) - - return resourceIBMAtrackerRouteRead(context, d, meta) -} - -func resourceIBMAtrackerRouteMapToRule(ruleMap map[string]interface{}) atrackerv1.Rule { - rule := atrackerv1.Rule{} - - targetIds := []string{} - for _, targetIdsItem := range ruleMap["target_ids"].([]interface{}) { - targetIds = append(targetIds, targetIdsItem.(string)) - } - rule.TargetIds = targetIds - - return rule -} - -func resourceIBMAtrackerRouteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - getRouteOptions := &atrackerv1.GetRouteOptions{} - - getRouteOptions.SetID(d.Id()) - - route, response, err := atrackerClient.GetRouteWithContext(context, getRouteOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetRouteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetRouteWithContext failed %s\n%s", err, response)) - } - - if err = d.Set("name", route.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("receive_global_events", route.ReceiveGlobalEvents); err != nil { - return diag.FromErr(fmt.Errorf("Error setting receive_global_events: %s", err)) - } - rules := []map[string]interface{}{} - for _, rulesItem := range route.Rules { - rulesItemMap := resourceIBMAtrackerRouteRuleToMap(rulesItem) - rules = append(rules, rulesItemMap) - } - if err = d.Set("rules", rules); err != nil { - return diag.FromErr(fmt.Errorf("Error setting rules: %s", err)) - } - if err = d.Set("crn", route.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("version", intValue(route.Version)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) - } - if err = d.Set("created", dateTimeToString(route.Created)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) - } - if err = d.Set("updated", dateTimeToString(route.Updated)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) - } - - return nil -} - -func resourceIBMAtrackerRouteRuleToMap(rule atrackerv1.Rule) map[string]interface{} { - ruleMap := map[string]interface{}{} - - ruleMap["target_ids"] = rule.TargetIds - - return ruleMap -} - -func resourceIBMAtrackerRouteUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - replaceRouteOptions := &atrackerv1.ReplaceRouteOptions{} - - replaceRouteOptions.SetID(d.Id()) - replaceRouteOptions.SetName(d.Get("name").(string)) - replaceRouteOptions.SetReceiveGlobalEvents(d.Get("receive_global_events").(bool)) - var rules []atrackerv1.Rule - for _, e := range d.Get("rules").([]interface{}) { - value := e.(map[string]interface{}) - rulesItem := resourceIBMAtrackerRouteMapToRule(value) - rules = append(rules, rulesItem) - } - replaceRouteOptions.SetRules(rules) - - _, response, err := atrackerClient.ReplaceRouteWithContext(context, replaceRouteOptions) - if err != nil { - log.Printf("[DEBUG] ReplaceRouteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ReplaceRouteWithContext failed %s\n%s", err, response)) - } - - return resourceIBMAtrackerRouteRead(context, d, meta) -} - -func resourceIBMAtrackerRouteDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - deleteRouteOptions := &atrackerv1.DeleteRouteOptions{} - - deleteRouteOptions.SetID(d.Id()) - - response, err := atrackerClient.DeleteRouteWithContext(context, deleteRouteOptions) - if err != nil { - log.Printf("[DEBUG] DeleteRouteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("DeleteRouteWithContext failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_atracker_route_test.go b/ibm/resource_ibm_atracker_route_test.go deleted file mode 100644 index b614d3c6b..000000000 --- a/ibm/resource_ibm_atracker_route_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/platform-services-go-sdk/atrackerv1" -) - -func TestAccIBMAtrackerRouteBasic(t *testing.T) { - var conf atrackerv1.Route - name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - receiveGlobalEvents := "false" - nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - receiveGlobalEventsUpdate := "true" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMAtrackerRouteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMAtrackerRouteConfigBasic(name, receiveGlobalEvents), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMAtrackerRouteExists("ibm_atracker_route.atracker_route", conf), - resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "name", name), - resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "receive_global_events", receiveGlobalEvents), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMAtrackerRouteConfigBasic(nameUpdate, receiveGlobalEventsUpdate), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "name", nameUpdate), - resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "receive_global_events", receiveGlobalEventsUpdate), - ), - }, - resource.TestStep{ - ResourceName: "ibm_atracker_route.atracker_route", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckIBMAtrackerRouteConfigBasic(name string, receiveGlobalEvents string) string { - return fmt.Sprintf(` - - - resource "ibm_atracker_target" "atracker_target" { - name = "my-cos-target" - target_type = "cloud_object_storage" - cos_endpoint { - endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" - target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" - bucket = "my-atracker-bucket" - api_key = "xxxxxxxxxxxxxx" - } - } - - resource "ibm_atracker_route" "atracker_route" { - name = "%s" - receive_global_events = %s - rules { - target_ids = [ ibm_atracker_target.atracker_target.id ] - } - } - - `, name, receiveGlobalEvents) -} - -func testAccCheckIBMAtrackerRouteExists(n string, obj atrackerv1.Route) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - atrackerClient, err := testAccProvider.Meta().(ClientSession).AtrackerV1() - if err != nil { - return err - } - - getRouteOptions := &atrackerv1.GetRouteOptions{} - - getRouteOptions.SetID(rs.Primary.ID) - - route, _, err := atrackerClient.GetRoute(getRouteOptions) - if err != nil { - return err - } - - obj = *route - return nil - } -} - -func testAccCheckIBMAtrackerRouteDestroy(s *terraform.State) error { - atrackerClient, err := testAccProvider.Meta().(ClientSession).AtrackerV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_atracker_route" { - continue - } - - getRouteOptions := &atrackerv1.GetRouteOptions{} - - getRouteOptions.SetID(rs.Primary.ID) - - // Try to find the key - _, response, err := atrackerClient.GetRoute(getRouteOptions) - - if err == nil { - return fmt.Errorf("Activity Tracker Route still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for Activity Tracker Route (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_atracker_target.go b/ibm/resource_ibm_atracker_target.go deleted file mode 100644 index 43f4e9e80..000000000 --- a/ibm/resource_ibm_atracker_target.go +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/atrackerv1" -) - -func resourceIBMAtrackerTarget() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMAtrackerTargetCreate, - ReadContext: resourceIBMAtrackerTargetRead, - UpdateContext: resourceIBMAtrackerTargetUpdate, - DeleteContext: resourceIBMAtrackerTargetDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_atracker_target", "name"), - Description: "The name of the target. The name must be 1000 characters or less, and cannot include any special characters other than `(space) - . _ :`.", - }, - "target_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: InvokeValidator("ibm_atracker_target", "target_type"), - Description: "The type of the target.", - }, - "cos_endpoint": &schema.Schema{ - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - Description: "Property values for a Cloud Object Storage Endpoint.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "endpoint": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The host name of the Cloud Object Storage endpoint.", - }, - "target_crn": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The CRN of the Cloud Object Storage instance.", - }, - "bucket": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The bucket name under the Cloud Object Storage instance.", - }, - "api_key": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Sensitive: true, - Description: "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response.", - DiffSuppressFunc: applyOnce, - }, - }, - }, - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the target resource.", - }, - "encrypt_key": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", - }, - "cos_write_status": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The status of the write attempt with the provided cos_endpoint parameters.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "status": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The status such as failed or success.", - }, - "last_failure": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The timestamp of the failure.", - }, - "reason_for_last_failure": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Detailed description of the cause of the failure.", - }, - }, - }, - }, - "created": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the target creation time.", - }, - "updated": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp of the target last updated time.", - }, - }, - } -} - -func resourceIBMAtrackerTargetValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^[a-zA-Z0-9 -._:]+$`, - MinValueLength: 1, - MaxValueLength: 1000, - }, - ValidateSchema{ - Identifier: "target_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "cloud_object_storage", - }, - ) - - resourceValidator := ResourceValidator{ResourceName: "ibm_atracker_target", Schema: validateSchema} - return &resourceValidator -} - -func resourceIBMAtrackerTargetCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - createTargetOptions := &atrackerv1.CreateTargetOptions{} - - createTargetOptions.SetName(d.Get("name").(string)) - createTargetOptions.SetTargetType(d.Get("target_type").(string)) - cosEndpoint := resourceIBMAtrackerTargetMapToCosEndpoint(d.Get("cos_endpoint.0").(map[string]interface{})) - createTargetOptions.SetCosEndpoint(&cosEndpoint) - - target, response, err := atrackerClient.CreateTargetWithContext(context, createTargetOptions) - if err != nil { - log.Printf("[DEBUG] CreateTargetWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("CreateTargetWithContext failed %s\n%s", err, response)) - } - - d.SetId(*target.ID) - - return resourceIBMAtrackerTargetRead(context, d, meta) -} - -func resourceIBMAtrackerTargetMapToCosEndpoint(cosEndpointMap map[string]interface{}) atrackerv1.CosEndpoint { - cosEndpoint := atrackerv1.CosEndpoint{} - - cosEndpoint.Endpoint = core.StringPtr(cosEndpointMap["endpoint"].(string)) - cosEndpoint.TargetCRN = core.StringPtr(cosEndpointMap["target_crn"].(string)) - cosEndpoint.Bucket = core.StringPtr(cosEndpointMap["bucket"].(string)) - cosEndpoint.APIKey = core.StringPtr(cosEndpointMap["api_key"].(string)) - - return cosEndpoint -} - -func resourceIBMAtrackerTargetRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - getTargetOptions := &atrackerv1.GetTargetOptions{} - - getTargetOptions.SetID(d.Id()) - - target, response, err := atrackerClient.GetTargetWithContext(context, getTargetOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetTargetWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetTargetWithContext failed %s\n%s", err, response)) - } - - if err = d.Set("name", target.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("target_type", target.TargetType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_type: %s", err)) - } - cosEndpointMap := resourceIBMAtrackerTargetCosEndpointToMap(*target.CosEndpoint) - if err = d.Set("cos_endpoint", []map[string]interface{}{cosEndpointMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cos_endpoint: %s", err)) - } - if err = d.Set("crn", target.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("encrypt_key", target.EncryptKey); err != nil { - return diag.FromErr(fmt.Errorf("Error setting encrypt_key: %s", err)) - } - if target.CosWriteStatus != nil { - cosWriteStatusMap := resourceIBMAtrackerTargetCosWriteStatusToMap(*target.CosWriteStatus) - if err = d.Set("cos_write_status", []map[string]interface{}{cosWriteStatusMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cos_write_status: %s", err)) - } - } - if err = d.Set("created", dateTimeToString(target.Created)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) - } - if err = d.Set("updated", dateTimeToString(target.Updated)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) - } - - return nil -} - -func resourceIBMAtrackerTargetCosEndpointToMap(cosEndpoint atrackerv1.CosEndpoint) map[string]interface{} { - cosEndpointMap := map[string]interface{}{} - - cosEndpointMap["endpoint"] = cosEndpoint.Endpoint - cosEndpointMap["target_crn"] = cosEndpoint.TargetCRN - cosEndpointMap["bucket"] = cosEndpoint.Bucket - cosEndpointMap["api_key"] = cosEndpoint.APIKey - - return cosEndpointMap -} - -func resourceIBMAtrackerTargetCosWriteStatusToMap(cosWriteStatus atrackerv1.CosWriteStatus) map[string]interface{} { - cosWriteStatusMap := map[string]interface{}{} - - if cosWriteStatus.Status != nil { - cosWriteStatusMap["status"] = cosWriteStatus.Status - } - if cosWriteStatus.LastFailure != nil { - cosWriteStatusMap["last_failure"] = cosWriteStatus.LastFailure.String() - } - if cosWriteStatus.ReasonForLastFailure != nil { - cosWriteStatusMap["reason_for_last_failure"] = cosWriteStatus.ReasonForLastFailure - } - - return cosWriteStatusMap -} - -func resourceIBMAtrackerTargetUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - replaceTargetOptions := &atrackerv1.ReplaceTargetOptions{} - - replaceTargetOptions.SetID(d.Id()) - - hasChange := false - - if d.HasChange("name") || d.HasChange("cos_endpoint") || d.HasChange("target_type") { - replaceTargetOptions.SetTargetType(d.Get("target_type").(string)) - replaceTargetOptions.SetName(d.Get("name").(string)) - cosEndpoint := resourceIBMAtrackerTargetMapToCosEndpoint(d.Get("cos_endpoint.0").(map[string]interface{})) - replaceTargetOptions.SetCosEndpoint(&cosEndpoint) - hasChange = true - } - - if hasChange { - _, response, err := atrackerClient.ReplaceTargetWithContext(context, replaceTargetOptions) - if err != nil { - log.Printf("[DEBUG] ReplaceTargetWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("ReplaceTargetWithContext failed %s\n%s", err, response)) - } - } - - return resourceIBMAtrackerTargetRead(context, d, meta) -} - -func resourceIBMAtrackerTargetDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() - if err != nil { - return diag.FromErr(err) - } - - deleteTargetOptions := &atrackerv1.DeleteTargetOptions{} - - deleteTargetOptions.SetID(d.Id()) - - _, response, err := atrackerClient.DeleteTargetWithContext(context, deleteTargetOptions) - if err != nil { - log.Printf("[DEBUG] DeleteTargetWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("DeleteTargetWithContext failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_cis.go b/ibm/resource_ibm_cis.go deleted file mode 100644 index be7884ba0..000000000 --- a/ibm/resource_ibm_cis.go +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net/url" - "os" - "strings" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/models" -) - -const ( - cisInstanceSuccessStatus = "active" - cisInstanceProgressStatus = "in progress" - cisInstanceProvisioningStatus = "provisioning" - cisInstanceInactiveStatus = "inactive" - cisInstanceFailStatus = "failed" - cisInstanceRemovedStatus = "removed" - cisInstanceReclamation = "pending_reclamation" -) - -func resourceIBMCISInstance() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISInstanceCreate, - Read: resourceIBMCISInstanceRead, - Update: resourceIBMCISInstanceUpdate, - Delete: resourceIBMCISInstanceDelete, - Exists: resourceIBMCISInstanceExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "A name for the resource instance", - }, - - "service": { - Type: schema.TypeString, - Computed: true, - Description: "The name of the Cloud Internet Services offering", - }, - - "plan": { - Type: schema.TypeString, - Required: true, - Description: "The plan type of the service", - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Unique identifier of resource instance", - }, - - "location": { - Description: "The location where the instance available", - Required: true, - ForceNew: true, - Type: schema.TypeString, - }, - - "resource_group_id": { - Description: "The resource group id", - Optional: true, - ForceNew: true, - Type: schema.TypeString, - Computed: true, - }, - - "parameters": { - Type: schema.TypeMap, - Optional: true, - ForceNew: true, - Description: "Arbitrary parameters to pass. Must be a JSON object", - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_cis", "tag")}, - Set: schema.HashString, - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of resource instance", - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} - -func resourceIBMCISValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmCISResourceValidator := ResourceValidator{ResourceName: "ibm_cis", Schema: validateSchema} - return &ibmCISResourceValidator -} - -// Replace with func wrapper for resourceIBMResourceInstanceCreate specifying serviceName := "internet-svcs" -func resourceIBMCISInstanceCreate(d *schema.ResourceData, meta interface{}) error { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - serviceName := "internet-svcs" - plan := d.Get("plan").(string) - name := d.Get("name").(string) - location := d.Get("location").(string) - - rsInst := rc.CreateResourceInstanceOptions{ - Name: &name, - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.FindByName(serviceName, true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - rsInst.ResourcePlanID = &servicePlan - - deployments, err := rsCatRepo.ListDeployments(servicePlan) - if err != nil { - return fmt.Errorf("Error retrieving deployment for plan %s : %s", plan, err) - } - if len(deployments) == 0 { - return fmt.Errorf("No deployment found for service plan : %s", plan) - } - deployments, supportedLocations := filterCISDeployments(deployments, location) - - if len(deployments) == 0 { - locationList := make([]string, 0, len(supportedLocations)) - for l := range supportedLocations { - locationList = append(locationList, l) - } - return fmt.Errorf("No deployment found for service plan %s at location %s.\nValid location(s) are: %q.", plan, location, locationList) - } - - rsInst.Target = &deployments[0].CatalogCRN - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rg := rsGrpID.(string) - rsInst.ResourceGroup = &rg - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInst.ResourceGroup = &defaultRg - } - - if parameters, ok := d.GetOk("parameters"); ok { - rsInst.Parameters = parameters.(map[string]interface{}) - } - - instance, response, err := rsConClient.CreateResourceInstance(&rsInst) - if err != nil { - return fmt.Errorf("Error creating resource instance: %s %s", err, response) - } - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk("tags"); ok || v != "" { - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of ibm cis (%s) tags: %s", d.Id(), err) - } - } - - // Moved d.SetId(instance.ID) to after waiting for resource to finish creation. Otherwise Terraform initates depedent tasks too early. - // Original flow had SetId here as its required as input to waitForCISInstanceCreate - - _, err = waitForCISInstanceCreate(d, meta, *instance.ID) - if err != nil { - return fmt.Errorf( - "Error waiting for create resource instance (%s) to be succeeded: %s", d.Id(), err) - } - - d.SetId(*instance.ID) - - return resourceIBMCISInstanceRead(d, meta) -} - -func resourceIBMCISInstanceRead(d *schema.ResourceData, meta interface{}) error { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - log.Printf("[WARN] Removing record from state because it's not found via the API") - d.SetId("") - return nil - } - return fmt.Errorf("Error retrieving resource instance: %s %s", err, response) - } - if strings.Contains(*instance.State, "removed") { - log.Printf("[WARN] Removing instance from TF state because it's now in removed state") - d.SetId("") - return nil - } - tags, err := GetTagsUsingCRN(meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on get of ibm cis tags (%s) tags: %s", d.Id(), err) - } - d.Set("tags", tags) - d.Set("name", *instance.Name) - d.Set("status", *instance.State) - d.Set("resource_group_id", *instance.ResourceGroupID) - d.Set("parameters", Flatten(instance.Parameters)) - if instance.CRN != nil { - location := strings.Split(*instance.CRN, ":") - if len(location) > 5 { - d.Set("location", location[5]) - } - } - d.Set("guid", *instance.GUID) - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - d.Set("service", "internet-svcs") - - servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - - d.Set(ResourceName, *instance.Name) - d.Set(ResourceCRN, *instance.CRN) - d.Set(ResourceStatus, *instance.State) - d.Set(ResourceGroupName, *instance.ResourceGroupCRN) - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/internet-svcs/"+url.QueryEscape(*instance.CRN)) - - return nil -} - -func resourceIBMCISInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - - updateReq := rc.UpdateResourceInstanceOptions{ - ID: &instanceID, - } - if d.HasChange("name") { - name := d.Get("name").(string) - updateReq.Name = &name - } - - if d.HasChange("plan") { - plan := d.Get("plan").(string) - service := d.Get("service").(string) - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.FindByName(service, true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - - updateReq.ResourcePlanID = &servicePlan - - } - - if d.HasChange("tags") { - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, instanceID) - if err != nil { - log.Printf( - "Error on update of CIS (%s) tags: %s", d.Id(), err) - } - } - - _, response, err := rsConClient.UpdateResourceInstance(&updateReq) - if err != nil { - return fmt.Errorf("Error updating resource instance: %s %s", err, response) - } - - _, err = waitForCISInstanceUpdate(d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for update resource instance (%s) to be succeeded: %s", d.Id(), err) - } - - return resourceIBMCISInstanceRead(d, meta) -} - -func resourceIBMCISInstanceDelete(d *schema.ResourceData, meta interface{}) error { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - id := d.Id() - recursive := true - deleteReq := rc.DeleteResourceInstanceOptions{ - ID: &id, - Recursive: &recursive, - } - response, err := rsConClient.DeleteResourceInstance(&deleteReq) - if err != nil { - // If prior delete occurs, instance is not immediately deleted, but remains in "removed" state" - // RC 410 with "Gone" returned as error - if strings.Contains(err.Error(), "Gone") || - strings.Contains(err.Error(), "status code: 410") { - log.Printf("[WARN] Resource instance already deleted %s\n %s", err, response) - err = nil - } else { - return fmt.Errorf("Error deleting resource instance: %s %s", err, response) - } - } - - _, err = waitForCISInstanceDelete(d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err) - } - - d.SetId("") - - return nil -} -func resourceIBMCISInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s %s", err, response) - } - if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, cisInstanceReclamation)) { - log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") - d.SetId("") - return false, nil - } - - return *instance.ID == instanceID, nil -} - -func waitForCISInstanceCreate(d *schema.ResourceData, meta interface{}, instanceID string) (interface{}, error) { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - //instanceID := d.Id() - - stateConf := &resource.StateChangeConf{ - Pending: []string{cisInstanceProgressStatus, cisInstanceInactiveStatus, cisInstanceProvisioningStatus}, - Target: []string{cisInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The resource instance %s does not exist anymore: %v %s", d.Id(), err, response) - } - return nil, "", err - } - if *instance.State == cisInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed: %v %s", d.Id(), err, response) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func waitForCISInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - - stateConf := &resource.StateChangeConf{ - Pending: []string{cisInstanceProgressStatus, cisInstanceInactiveStatus}, - Target: []string{cisInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The resource instance %s does not exist anymore: %v %s", d.Id(), err, response) - } - return nil, "", err - } - if *instance.State == cisInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed: %v %s", d.Id(), err, response) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func waitForCISInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - stateConf := &resource.StateChangeConf{ - Pending: []string{cisInstanceProgressStatus, cisInstanceInactiveStatus, cisInstanceSuccessStatus}, - Target: []string{cisInstanceRemovedStatus, cisInstanceReclamation}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return instance, cisInstanceSuccessStatus, nil - } - return nil, "", err - } - if *instance.State == cisInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed to delete: %v %s", d.Id(), err, response) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func filterCISDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { - supportedDeployments := []models.ServiceDeployment{} - supportedLocations := make(map[string]bool) - for _, d := range deployments { - if d.Metadata.RCCompatible { - deploymentLocation := d.Metadata.Deployment.Location - supportedLocations[deploymentLocation] = true - if deploymentLocation == location { - supportedDeployments = append(supportedDeployments, d) - } - } - } - return supportedDeployments, supportedLocations -} diff --git a/ibm/resource_ibm_cis_cache_settings.go b/ibm/resource_ibm_cis_cache_settings.go deleted file mode 100644 index 37f995d39..000000000 --- a/ibm/resource_ibm_cis_cache_settings.go +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISCacheSettings = "ibm_cis_cache_settings" - cisCacheSettingsCachingLevel = "caching_level" - cisCacheSettingsBrowserExpiration = "browser_expiration" - cisCacheSettingsDevelopmentMode = "development_mode" - cisCacheSettingsQueryStringSort = "query_string_sort" - cisCachePurgeAll = "purge_all" - cisCachePurgeByURLs = "purge_by_urls" - cisCachePurgeByCacheTags = "purge_by_tags" - cisCachePurgeByHosts = "purge_by_hosts" - cisCacheSettingsOnOffValidatorID = "on_off_validator_id" - cisCacheServeStaleContent = "serve_stale_content" -) - -func resourceIBMCISCacheSettings() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisCacheSettingsCachingLevel: { - Type: schema.TypeString, - Description: "Cache level setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISCacheSettings, - cisCacheSettingsCachingLevel), - }, - cisCacheServeStaleContent: { - Type: schema.TypeString, - Description: "Serve Stale Content ", - Default: "on", - Optional: true, - ValidateFunc: InvokeValidator(ibmCISCacheSettings, - cisCacheServeStaleContent), - }, - cisCacheSettingsBrowserExpiration: { - Type: schema.TypeInt, - Description: "Browser Expiration setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISCacheSettings, - cisCacheSettingsBrowserExpiration), - }, - cisCacheSettingsDevelopmentMode: { - Type: schema.TypeString, - Description: "Development mode setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISCacheSettings, - cisCacheSettingsOnOffValidatorID), - }, - cisCacheSettingsQueryStringSort: { - Type: schema.TypeString, - Description: "Query String sort setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISCacheSettings, - cisCacheSettingsOnOffValidatorID), - }, - cisCachePurgeAll: { - Type: schema.TypeBool, - Description: "Purge all setting", - Optional: true, - ConflictsWith: []string{ - cisCachePurgeByURLs, - cisCachePurgeByCacheTags, - cisCachePurgeByHosts}, - }, - cisCachePurgeByURLs: { - Type: schema.TypeList, - Description: "Purge by URLs", - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ConflictsWith: []string{ - cisCachePurgeAll, - cisCachePurgeByCacheTags, - cisCachePurgeByHosts}, - }, - cisCachePurgeByCacheTags: { - Type: schema.TypeList, - Description: "Purge by tags", - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ConflictsWith: []string{ - cisCachePurgeAll, - cisCachePurgeByURLs, - cisCachePurgeByHosts}, - }, - cisCachePurgeByHosts: { - Type: schema.TypeList, - Description: "Purge by hosts", - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ConflictsWith: []string{ - cisCachePurgeAll, - cisCachePurgeByURLs, - cisCachePurgeByCacheTags, - }, - }, - }, - Create: resourceCISCacheSettingsUpdate, - Read: resourceCISCacheSettingsRead, - Update: resourceCISCacheSettingsUpdate, - Delete: resourceCISCacheSettingsDelete, - Importer: &schema.ResourceImporter{}, - } -} - -func resourceIBMCISCacheSettingsValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - browserCacheTTL := "0, 30, 60, 300, 1200, 1800, 3600, 7200, 10800, 14400," + - "18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000," + - "691200, 1382400, 2073600, 2678400, 5356800, 16070400, 31536000" - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisCacheSettingsOnOffValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "on, off"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisCacheSettingsBrowserExpiration, - ValidateFunctionIdentifier: ValidateAllowedIntValue, - Type: TypeInt, - Optional: true, - AllowedValues: browserCacheTTL}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisCacheServeStaleContent, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "on, off"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisCacheSettingsCachingLevel, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "basic, simplified, aggressive"}) - ibmCISCacheSettingsResourceValidator := ResourceValidator{ - ResourceName: ibmCISCacheSettings, - Schema: validateSchema} - return &ibmCISCacheSettingsResourceValidator -} - -func resourceCISCacheSettingsUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisCacheClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - - if d.HasChange(cisCacheSettingsCachingLevel) || - d.HasChange(cisCacheSettingsBrowserExpiration) || - d.HasChange(cisCacheSettingsDevelopmentMode) || - d.HasChange(cisCacheSettingsQueryStringSort) || - d.HasChange(cisCachePurgeAll) || - d.HasChange(cisCachePurgeByURLs) || - d.HasChange(cisCachePurgeByCacheTags) || - d.HasChange(cisCachePurgeByHosts) || - d.HasChange(cisCacheServeStaleContent) { - - // Caching Level Setting - if value, ok := d.GetOk(cisCacheSettingsCachingLevel); ok { - opt := cisClient.NewUpdateCacheLevelOptions() - opt.SetValue(value.(string)) - _, resp, err := cisClient.UpdateCacheLevel(opt) - if err != nil { - log.Printf("Update caching level failed : %v\n", resp) - return err - } - } - // Serve Stale Content Setting - if value, ok := d.GetOk(cisCacheServeStaleContent); ok { - opt := cisClient.NewUpdateServeStaleContentOptions() - opt.SetValue(value.(string)) - _, resp, err := cisClient.UpdateServeStaleContent(opt) - if err != nil { - log.Printf("Update Serve Stale Content Setting failed : %v\n", resp) - return err - } - } - - // Browser Expiration setting - if value, ok := d.GetOk(cisCacheSettingsBrowserExpiration); ok { - opt := cisClient.NewUpdateBrowserCacheTtlOptions() - opt.SetValue(int64(value.(int))) - _, resp, err := cisClient.UpdateBrowserCacheTTL(opt) - if err != nil { - log.Printf("Update browser expiration setting failed : %v\n", resp) - return err - } - } - - // development mode setting - if value, ok := d.GetOk(cisCacheSettingsDevelopmentMode); ok { - opt := cisClient.NewUpdateDevelopmentModeOptions() - opt.SetValue(value.(string)) - _, resp, err := cisClient.UpdateDevelopmentMode(opt) - if err != nil { - log.Printf("Update development mode setting failed : %v\n", resp) - return err - } - } - // Query string sort setting - if value, ok := d.GetOk(cisCacheSettingsQueryStringSort); ok { - opt := cisClient.NewUpdateQueryStringSortOptions() - opt.SetValue(value.(string)) - _, resp, err := cisClient.UpdateQueryStringSort(opt) - if err != nil { - log.Printf("Update query string sort setting failed : %v\n", resp) - return err - } - } - - if value, ok := d.GetOkExists(cisCachePurgeAll); ok { - if value.(bool) == true { - opt := cisClient.NewPurgeAllOptions() - result, response, err := cisClient.PurgeAll(opt) - if err != nil { - log.Printf("Purge all failed : %v", response) - return err - } - log.Printf("Purge all successful : %s", *result.Result.ID) - } - } - if value, ok := d.GetOk(cisCachePurgeByURLs); ok { - urls := expandStringList(value.([]interface{})) - opt := cisClient.NewPurgeByUrlsOptions() - opt.SetFiles(urls) - _, response, err := cisClient.PurgeByUrls(opt) - if err != nil { - log.Printf("Purge by urls failed : %v", response) - return err - } - } - if value, ok := d.GetOk(cisCachePurgeByCacheTags); ok { - cacheTags := expandStringList(value.([]interface{})) - opt := cisClient.NewPurgeByCacheTagsOptions() - opt.SetTags(cacheTags) - result, response, err := cisClient.PurgeByCacheTags(opt) - if err != nil { - log.Printf("Purge by cache tags failed : %v", response) - return err - } - log.Printf("Purge by tags successful : %s", *result.Result.ID) - - } - if value, ok := d.GetOk(cisCachePurgeByHosts); ok { - hosts := expandStringList(value.([]interface{})) - opt := cisClient.NewPurgeByHostsOptions() - opt.SetHosts(hosts) - result, response, err := cisClient.PurgeByHosts(opt) - if err != nil { - log.Printf("Purge by hosts failed : %v", response) - return err - } - log.Printf("Purge by hosts successful : %s", *result.Result.ID) - } - } - d.SetId(convertCisToTfTwoVar(zoneID, crn)) - return resourceCISCacheSettingsRead(d, meta) -} - -func resourceCISCacheSettingsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisCacheClientSession() - if err != nil { - return err - } - zoneID, crn, _ := convertTftoCisTwoVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - - // Caching Level Setting - cacheLevel, resp, err := cisClient.GetCacheLevel(cisClient.NewGetCacheLevelOptions()) - if err != nil { - log.Printf("Get caching leve setting failed : %v\n", resp) - return err - } - - // Serve Stale Content setting - servestaleContent, resp, err := cisClient.GetServeStaleContent(cisClient.NewGetServeStaleContentOptions()) - if err != nil { - log.Printf("Get Serve Stale Content setting failed : %v\n", resp) - return err - } - - // Browser Expiration setting - browserCacheTTL, resp, err := cisClient.GetBrowserCacheTTL( - cisClient.NewGetBrowserCacheTtlOptions()) - if err != nil { - log.Printf("Get browser expiration setting failed : %v\n", resp) - return err - } - - // development mode setting - devMode, resp, err := cisClient.GetDevelopmentMode( - cisClient.NewGetDevelopmentModeOptions()) - if err != nil { - log.Printf("Get development mode setting failed : %v", resp) - return err - } - - // Query string sort setting - queryStringSort, resp, err := cisClient.GetQueryStringSort( - cisClient.NewGetQueryStringSortOptions()) - if err != nil { - log.Printf("Get query string sort setting failed : %v", resp) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisCacheSettingsBrowserExpiration, *browserCacheTTL.Result.Value) - d.Set(cisCacheSettingsCachingLevel, *cacheLevel.Result.Value) - d.Set(cisCacheSettingsDevelopmentMode, *devMode.Result.Value) - d.Set(cisCacheSettingsQueryStringSort, *queryStringSort.Result.Value) - d.Set(cisCacheServeStaleContent, *servestaleContent.Result.Value) - return nil -} - -func resourceCISCacheSettingsDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_certificate_order.go b/ibm/resource_ibm_cis_certificate_order.go deleted file mode 100644 index 860934285..000000000 --- a/ibm/resource_ibm_cis_certificate_order.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISCertificateOrder = "ibm_cis_certificate_order" - cisCertificateOrderID = "certificate_id" - cisCertificateOrderHosts = "hosts" - cisCertificateOrderType = "type" - cisCertificateOrderTypeDedicated = "dedicated" - cisCertificateOrderStatus = "status" - cisCertificateOrderDeleted = "deleted" - cisCertificateOrderDeletePending = "deleting" -) - -func resourceIBMCISCertificateOrder() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISCertificateOrderCreate, - Update: resourceIBMCISCertificateOrderRead, - Read: resourceIBMCISCertificateOrderRead, - Delete: resourceIBMCISCertificateOrderDelete, - Exists: resourceIBMCISCertificateOrderExist, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS object id or CRN", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisCertificateOrderID: { - Type: schema.TypeString, - Description: "certificate id", - Computed: true, - }, - cisCertificateOrderType: { - Type: schema.TypeString, - Description: "certificate type", - Optional: true, - Default: cisCertificateOrderTypeDedicated, - }, - cisCertificateOrderHosts: { - Type: schema.TypeList, - Description: "Hosts which certificate need to be ordered", - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisCertificateOrderStatus: { - Type: schema.TypeString, - Description: "certificate status", - Computed: true, - }, - }, - } -} - -func resourceIBMCISCertificateOrderValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisCertificateOrderType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: cisCertificateOrderTypeDedicated}) - - cisCertificateOrderValidator := ResourceValidator{ - ResourceName: ibmCISCertificateOrder, - Schema: validateSchema} - return &cisCertificateOrderValidator -} - -func resourceIBMCISCertificateOrderCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - certType := d.Get(cisCertificateOrderType).(string) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - hosts := d.Get(cisCertificateOrderHosts) - hostsList := expandStringList(hosts.([]interface{})) - opt := cisClient.NewOrderCertificateOptions() - opt.SetType(certType) - opt.SetHosts(hostsList) - - result, resp, err := cisClient.OrderCertificate(opt) - if err != nil { - log.Printf("Certificate order failed: %v", resp) - return err - } - - d.SetId(convertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) - return resourceIBMCISCertificateOrderRead(d, meta) -} - -func resourceIBMCISCertificateOrderRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - certificateID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - log.Println("Error in reading certificate id") - return err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetCustomCertificateOptions(certificateID) - result, resp, err := cisClient.GetCustomCertificate(opt) - if err != nil { - log.Printf("Certificate read failed: %v", resp) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisCertificateOrderID, result.Result.ID) - d.Set(cisCertificateOrderType, cisCertificateOrderTypeDedicated) - d.Set(cisCertificateOrderHosts, flattenStringList(result.Result.Hosts)) - d.Set(cisCertificateOrderStatus, result.Result.Status) - return nil -} - -func resourceIBMCISCertificateOrderDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - certificateID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - log.Println("Error in reading certificate id") - return err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewDeleteCertificateOptions(certificateID) - resp, err := cisClient.DeleteCertificate(opt) - if err != nil { - log.Printf("Certificate delete failed: %v", resp) - return err - } - - _, err = waitForCISCertificateOrderDelete(d, meta) - if err != nil { - return err - } - - return nil -} - -func resourceIBMCISCertificateOrderExist(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return false, err - } - certificateID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - log.Println("Error in reading certificate id") - return false, err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetCustomCertificateOptions(certificateID) - _, response, err := cisClient.GetCustomCertificate(opt) - if err != nil { - if response != nil && response.StatusCode == 400 { - log.Printf("Certificate is not found") - return false, nil - } - log.Printf("Get Certificate failed: %v", response) - return false, err - } - return true, nil -} - -func waitForCISCertificateOrderDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return nil, err - } - certificateID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - log.Println("Error in reading certificate id") - return nil, err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetCustomCertificateOptions(certificateID) - stateConf := &resource.StateChangeConf{ - Pending: []string{cisCertificateOrderDeletePending}, - Target: []string{cisCertificateOrderDeleted}, - Refresh: func() (interface{}, string, error) { - _, detail, err := cisClient.GetCustomCertificate(opt) - if err != nil { - if detail != nil && detail.StatusCode == 400 { - return detail, cisCertificateOrderDeleted, nil - } - return nil, "", err - } - return detail, cisCertificateOrderDeletePending, nil - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - PollInterval: 10 * time.Second, - } - - return stateConf.WaitForState() -} diff --git a/ibm/resource_ibm_cis_dns_records_import.go b/ibm/resource_ibm_cis_dns_records_import.go deleted file mode 100644 index c2fa378d9..000000000 --- a/ibm/resource_ibm_cis_dns_records_import.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "os" - "strconv" - "strings" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisDNSRecordsImportFile = "file" - cisDNSRecordsImportTotalRecordsParsed = "total_records_parsed" - cisDNSRecordsImportRecordsAdded = "records_added" -) - -func resourceIBMCISDNSRecordsImport() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisDNSRecordsImportFile: { - Type: schema.TypeString, - Description: "File to import", - Required: true, - ForceNew: true, - }, - cisDNSRecordsImportTotalRecordsParsed: { - Type: schema.TypeInt, - Description: "total records parsed", - Computed: true, - }, - cisDNSRecordsImportRecordsAdded: { - Type: schema.TypeInt, - Description: "added records count", - Computed: true, - }, - }, - - Create: resourceCISDNSRecordsImportUpdate, - Read: resourceCISDNSRecordsImportRead, - Update: resourceCISDNSRecordsImportRead, - Delete: resourceCISDNSRecordsImportDelete, - Importer: &schema.ResourceImporter{}, - } -} -func resourceCISDNSRecordsImportUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisDNSRecordBulkClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - file := d.Get(cisDNSRecordsImportFile).(string) - - f, err := os.Open(file) - if err != nil { - return err - } - opt := cisClient.NewPostDnsRecordsBulkOptions() - opt.SetFile(f) - result, response, err := cisClient.PostDnsRecordsBulk(opt) - if err != nil { - log.Printf("Error importing dns records: %v", response) - return err - } - id := fmt.Sprintf("%v:%v:%s:%s:%s", *result.Result.TotalRecordsParsed, - *result.Result.RecsAdded, file, zoneID, crn) - d.SetId(id) - - return nil - -} - -func resourceCISDNSRecordsImportRead(d *schema.ResourceData, meta interface{}) error { - idSplitStr := strings.SplitN(d.Id(), ":", 5) - parsed, _ := strconv.Atoi(idSplitStr[0]) - added, _ := strconv.Atoi(idSplitStr[1]) - file := idSplitStr[2] - zoneID := idSplitStr[3] - crn := idSplitStr[4] - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisDNSRecordsImportFile, file) - d.Set(cisDNSRecordsImportTotalRecordsParsed, parsed) - d.Set(cisDNSRecordsImportRecordsAdded, added) - return nil -} - -func resourceCISDNSRecordsImportDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS DNS Record import resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_domain.go b/ibm/resource_ibm_cis_domain.go deleted file mode 100644 index aa918e0a9..000000000 --- a/ibm/resource_ibm_cis_domain.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisDomain = "domain" - cisDomainPaused = "paused" - cisDomainStatus = "status" - cisDomainNameServers = "name_servers" - cisDomainOriginalNameServers = "original_name_servers" -) - -func resourceIBMCISDomain() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS object id", - Required: true, - }, - cisDomain: { - Type: schema.TypeString, - Description: "CISzone - Domain", - Required: true, - }, - cisDomainPaused: { - Type: schema.TypeBool, - Computed: true, - }, - cisDomainStatus: { - Type: schema.TypeString, - Computed: true, - }, - cisDomainNameServers: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisDomainOriginalNameServers: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - cisDomainID: { - Type: schema.TypeString, - Computed: true, - }, - }, - Create: resourceCISdomainCreate, - Read: resourceCISdomainRead, - Exists: resourceCISdomainExists, - Update: resourceCISdomainUpdate, - Delete: resourceCISdomainDelete, - Importer: &schema.ResourceImporter{}, - } -} - -func resourceCISdomainCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - cisClient.Crn = core.StringPtr(crn) - zoneName := d.Get(cisDomain).(string) - - opt := cisClient.NewCreateZoneOptions() - opt.SetName(zoneName) - result, resp, err := cisClient.CreateZone(opt) - if err != nil { - log.Printf("CreateZones Failed %s", resp) - return err - } - d.SetId(convertCisToTfTwoVar(*result.Result.ID, crn)) - return resourceCISdomainRead(d, meta) -} - -func resourceCISdomainRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - - zoneID, crn, err := convertTftoCisTwoVar(d.Id()) - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - opt := cisClient.NewGetZoneOptions(zoneID) - result, resp, err := cisClient.GetZone(opt) - if err != nil { - log.Printf("[WARN] Error getting zone %v\n", resp) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, result.Result.ID) - d.Set(cisDomain, result.Result.Name) - d.Set(cisDomainStatus, result.Result.Status) - d.Set(cisDomainPaused, result.Result.Paused) - d.Set(cisDomainNameServers, result.Result.NameServers) - d.Set(cisDomainOriginalNameServers, result.Result.OriginalNameServers) - - return nil -} -func resourceCISdomainExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisZonesV1ClientSession() - if err != nil { - return false, err - } - - zoneID, crn, err := convertTftoCisTwoVar(d.Id()) - log.Println("resource exist :", d.Id()) - if err != nil { - return false, err - } - log.Println("resource exist :", d.Id()) - cisClient.Crn = core.StringPtr(crn) - opt := cisClient.NewGetZoneOptions(zoneID) - _, resp, err := cisClient.GetZone(opt) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - log.Printf("[WARN] zone is not found") - return false, nil - } - log.Printf("[WARN] Error getting zone %v\n", resp) - return false, err - } - return true, nil -} - -func resourceCISdomainUpdate(d *schema.ResourceData, meta interface{}) error { - return resourceCISdomainRead(d, meta) -} - -func resourceCISdomainDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - - zoneID, crn, err := convertTftoCisTwoVar(d.Id()) - log.Println("resource delete :", d.Id()) - - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - opt := cisClient.NewGetZoneOptions(zoneID) - _, resp, err := cisClient.GetZone(opt) - if err != nil { - log.Printf("[WARN] Error getting zone %v\n", resp) - return err - } - delOpt := cisClient.NewDeleteZoneOptions(zoneID) - _, resp, err = cisClient.DeleteZone(delOpt) - if err != nil { - log.Printf("[ERR] Error deleting zone %v\n", resp) - return err - } - return nil -} diff --git a/ibm/resource_ibm_cis_domain_settings.go b/ibm/resource_ibm_cis_domain_settings.go deleted file mode 100644 index 7e4a6a394..000000000 --- a/ibm/resource_ibm_cis_domain_settings.go +++ /dev/null @@ -1,1261 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v4/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISDomainSettings = "ibm_cis_domain_settings" - cisDomainSettingsDNSSEC = "dnssec" - cisDomainSettingsWAF = "waf" - cisDomainSettingsSSL = "ssl" - cisDomainSettingsCertificateStatus = "certificate_status" - cisDomainSettingsMinTLSVersion = "min_tls_version" - cisDomainSettingsCNAMEFlattening = "cname_flattening" - cisDomainSettingsOpportunisticEncryption = "opportunistic_encryption" - cisDomainSettingsAutomaticHTPSRewrites = "automatic_https_rewrites" - cisDomainSettingsAlwaysUseHTTPS = "always_use_https" - cisDomainSettingsIPv6 = "ipv6" - cisDomainSettingsBrowserCheck = "browser_check" - cisDomainSettingsHotlinkProtection = "hotlink_protection" - cisDomainSettingsHTTP2 = "http2" - cisDomainSettingsImageLoadOptimization = "image_load_optimization" - cisDomainSettingsImageSizeOptimization = "image_size_optimization" - cisDomainSettingsIPGeoLocation = "ip_geolocation" - cisDomainSettingsOriginErrorPagePassThru = "origin_error_page_pass_thru" - cisDomainSettingsBrotli = "brotli" - cisDomainSettingsPseudoIPv4 = "pseudo_ipv4" - cisDomainSettingsPrefetchPreload = "prefetch_preload" - cisDomainSettingsResponseBuffering = "response_buffering" - cisDomainSettingsScriptLoadOptimisation = "script_load_optimization" - cisDomainSettingsServerSideExclude = "server_side_exclude" - cisDomainSettingsTLSClientAuth = "tls_client_auth" - cisDomainSettingsTrueClientIPHeader = "true_client_ip_header" - cisDomainSettingsWebSockets = "websockets" - cisDomainSettingsChallengeTTL = "challenge_ttl" - cisDomainSettingsMinify = "minify" - cisDomainSettingsMinifyCSS = "css" - cisDomainSettingsMinifyHTML = "html" - cisDomainSettingsMinifyJS = "js" - cisDomainSettingsSecurityHeader = "security_header" - cisDomainSettingsSecurityHeaderEnabled = "enabled" - cisDomainSettingsSecurityHeaderMaxAge = "max_age" - cisDomainSettingsSecurityHeaderIncludeSubdomains = "include_subdomains" - cisDomainSettingsSecurityHeaderNoSniff = "nosniff" - cisDomainSettingsMobileRedirect = "mobile_redirect" - cisDomainSettingsMobileRedirectStatus = "status" - cisDomainSettingsMobileRedirectMobileSubdomain = "mobile_subdomain" - cisDomainSettingsMobileRedirectStripURI = "strip_uri" - cisDomainSettingsMaxUpload = "max_upload" - cisDomainSettingsCipher = "cipher" - cisDomainSettingsONOFFValidatorID = "on_off" - cisDomainSettingsActiveDisableValidatorID = "active_disable" - cisDomainSettingsSSLSettingValidatorID = "ssl_setting" - cisDomainSettingsTLSVersionValidatorID = "tls_version" - cisDomainSettingsCNAMEFlattenValidatorID = "cname_flatten" - cisDomainSettingsImgSizeOptimizeValidatorID = "img_size_optimize" - cisDomainSettingsPseudoIPv4ValidatorID = "psuedo_ipv4" - cisDomainSettingsChallengeTTLValidatorID = "challenge_ttl" - cisDomainSettingsMaxUploadValidatorID = "max_upload" - cisDomainSettingsCipherValidatorID = "cipher" -) - -func resourceIBMCISSettings() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisDomainSettingsDNSSEC: { - Type: schema.TypeString, - Description: "DNS Sec setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsActiveDisableValidatorID), - }, - cisDomainSettingsWAF: { - Type: schema.TypeString, - Description: "WAF setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsSSL: { - Type: schema.TypeString, - Description: "SSL/TLS setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsSSLSettingValidatorID), - }, - cisDomainSettingsCertificateStatus: { - Type: schema.TypeString, - Description: "Certificate status", - Computed: true, - Deprecated: "This field is deprecated", - }, - cisDomainSettingsMinTLSVersion: { - Type: schema.TypeString, - Description: "Minimum version of TLS required", - Optional: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsTLSVersionValidatorID), - Default: "1.1", - }, - cisDomainSettingsCNAMEFlattening: { - Type: schema.TypeString, - Description: "cname_flattening setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsCNAMEFlattenValidatorID), - }, - cisDomainSettingsOpportunisticEncryption: { - Type: schema.TypeString, - Description: "opportunistic_encryption setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsAutomaticHTPSRewrites: { - Type: schema.TypeString, - Description: "automatic_https_rewrites setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsAlwaysUseHTTPS: { - Type: schema.TypeString, - Description: "always_use_https setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsIPv6: { - Type: schema.TypeString, - Description: "ipv6 setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsBrowserCheck: { - Type: schema.TypeString, - Description: "browser_check setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsHotlinkProtection: { - Type: schema.TypeString, - Description: "hotlink_protection setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsHTTP2: { - Type: schema.TypeString, - Description: "http2 setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsImageLoadOptimization: { - Type: schema.TypeString, - Description: "image_load_optimization setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsImageSizeOptimization: { - Type: schema.TypeString, - Description: "image_size_optimization setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsImgSizeOptimizeValidatorID), - }, - cisDomainSettingsIPGeoLocation: { - Type: schema.TypeString, - Description: "ip_geolocation setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsOriginErrorPagePassThru: { - Type: schema.TypeString, - Description: "origin_error_page_pass_thru setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsBrotli: { - Type: schema.TypeString, - Description: "brotli setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsPseudoIPv4: { - Type: schema.TypeString, - Description: "pseudo_ipv4 setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsPseudoIPv4ValidatorID), - }, - cisDomainSettingsPrefetchPreload: { - Type: schema.TypeString, - Description: "prefetch_preload setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsResponseBuffering: { - Type: schema.TypeString, - Description: "response_buffering setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsScriptLoadOptimisation: { - Type: schema.TypeString, - Description: "script_load_optimization setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsServerSideExclude: { - Type: schema.TypeString, - Description: "server_side_exclude setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsTLSClientAuth: { - Type: schema.TypeString, - Description: "tls_client_auth setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsTrueClientIPHeader: { - Type: schema.TypeString, - Description: "true_client_ip_header setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsWebSockets: { - Type: schema.TypeString, - Description: "websockets setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsChallengeTTL: { - Type: schema.TypeInt, - Description: "Challenge TTL setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsChallengeTTLValidatorID), - }, - cisDomainSettingsMaxUpload: { - Type: schema.TypeInt, - Description: "Maximum upload", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsMaxUploadValidatorID), - }, - cisDomainSettingsCipher: { - Type: schema.TypeSet, - Description: "Cipher settings", - Optional: true, - Computed: true, - Set: schema.HashString, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsCipherValidatorID), - }, - }, - cisDomainSettingsMinify: { - Type: schema.TypeList, - Description: "Minify setting", - Optional: true, - Computed: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisDomainSettingsMinifyCSS: { - Type: schema.TypeString, - Description: "Minify CSS setting", - Required: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsMinifyHTML: { - Type: schema.TypeString, - Description: "Minify HTML setting", - Required: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsMinifyJS: { - Type: schema.TypeString, - Description: "Minify JS setting", - Required: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - }, - }, - }, - cisDomainSettingsSecurityHeader: { - Type: schema.TypeList, - Description: "Security Header Setting", - Optional: true, - Computed: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisDomainSettingsSecurityHeaderEnabled: { - Type: schema.TypeBool, - Description: "security header enabled/disabled", - Required: true, - }, - cisDomainSettingsSecurityHeaderIncludeSubdomains: { - Type: schema.TypeBool, - Description: "security header subdomain included or not", - Required: true, - }, - cisDomainSettingsSecurityHeaderMaxAge: { - Type: schema.TypeInt, - Description: "security header max age", - Required: true, - }, - cisDomainSettingsSecurityHeaderNoSniff: { - Type: schema.TypeBool, - Description: "security header no sniff", - Required: true, - }, - }, - }, - }, - cisDomainSettingsMobileRedirect: { - Type: schema.TypeList, - Optional: true, - Computed: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisDomainSettingsMobileRedirectStatus: { - Type: schema.TypeString, - Description: "mobile redirect status", - Required: true, - ValidateFunc: InvokeValidator( - ibmCISDomainSettings, - cisDomainSettingsONOFFValidatorID), - }, - cisDomainSettingsMobileRedirectMobileSubdomain: { - Type: schema.TypeString, - Description: "Mobile redirect subdomain", - Optional: true, - Computed: true, - }, - cisDomainSettingsMobileRedirectStripURI: { - Type: schema.TypeBool, - Description: "mobile redirect strip URI", - Optional: true, - Computed: true, - }, - }, - }, - }, - }, - - Create: resourceCISSettingsUpdate, - Read: resourceCISSettingsRead, - Update: resourceCISSettingsUpdate, - Delete: resourceCISSettingsDelete, - Importer: &schema.ResourceImporter{}, - } -} - -func resourceIBMCISDomainSettingValidator() *ResourceValidator { - - sslSetting := "off, flexible, full, strict, origin_pull" - tlsVersion := "1.1, 1.2, 1.3, 1.4" - cnameFlatten := "flatten_at_root, flatten_all, flatten_none" - imgSizeOptimize := "lossless, off, lossy" - pseudoIPv4 := "overwrite_header, off, add_header" - challengeTTL := "300, 900, 1800, 2700, 3600, 7200, 10800, 14400, 28800, 57600, 86400, 604800, 2592000, 31536000" - maxUpload := "100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500" - cipher := "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305, ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-CHACHA20-POLY1305, ECDHE-ECDSA-AES128-SHA256, ECDHE-ECDSA-AES128-SHA, ECDHE-RSA-AES128-SHA256, ECDHE-RSA-AES128-SHA, AES128-GCM-SHA256, AES128-SHA256, AES128-SHA, ECDHE-ECDSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-SHA384, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA, AES256-GCM-SHA384, AES256-SHA256, AES256-SHA, DES-CBC3-SHA" - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsONOFFValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "on, off"}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsActiveDisableValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "active, disabled"}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsSSLSettingValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: sslSetting}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsTLSVersionValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: tlsVersion}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsCNAMEFlattenValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: cnameFlatten}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsImgSizeOptimizeValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: imgSizeOptimize}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsPseudoIPv4ValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: pseudoIPv4}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsChallengeTTLValidatorID, - ValidateFunctionIdentifier: ValidateAllowedIntValue, - Type: TypeInt, - Optional: true, - AllowedValues: challengeTTL}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsMaxUploadValidatorID, - ValidateFunctionIdentifier: ValidateAllowedIntValue, - Type: TypeInt, - Optional: true, - AllowedValues: maxUpload}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisDomainSettingsCipherValidatorID, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: cipher}) - ibmCISDomainSettingResourceValidator := ResourceValidator{ - ResourceName: ibmCISDomainSettings, - Schema: validateSchema} - return &ibmCISDomainSettingResourceValidator -} - -var settingsList = []string{ - cisDomainSettingsDNSSEC, - cisDomainSettingsWAF, - cisDomainSettingsSSL, - cisDomainSettingsMinTLSVersion, - cisDomainSettingsCNAMEFlattening, - cisDomainSettingsOpportunisticEncryption, - cisDomainSettingsAutomaticHTPSRewrites, - cisDomainSettingsAlwaysUseHTTPS, - cisDomainSettingsIPv6, - cisDomainSettingsBrowserCheck, - cisDomainSettingsHotlinkProtection, - cisDomainSettingsHTTP2, - cisDomainSettingsImageLoadOptimization, - cisDomainSettingsImageSizeOptimization, - cisDomainSettingsIPGeoLocation, - cisDomainSettingsOriginErrorPagePassThru, - cisDomainSettingsBrotli, - cisDomainSettingsPseudoIPv4, - cisDomainSettingsPrefetchPreload, - cisDomainSettingsResponseBuffering, - cisDomainSettingsScriptLoadOptimisation, - cisDomainSettingsServerSideExclude, - cisDomainSettingsTLSClientAuth, - cisDomainSettingsTrueClientIPHeader, - cisDomainSettingsWebSockets, - cisDomainSettingsChallengeTTL, - cisDomainSettingsMinify, - cisDomainSettingsSecurityHeader, - cisDomainSettingsMobileRedirect, - cisDomainSettingsMaxUpload, - cisDomainSettingsCipher, -} - -func resourceCISSettingsUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisDomainSettingsClientSession() - if err != nil { - return err - } - - cisID := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(cisID) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - for _, item := range settingsList { - var err error - var resp *core.DetailedResponse - - switch item { - case cisDomainSettingsDNSSEC: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateZoneDnssecOptions() - opt.SetStatus(v.(string)) - _, resp, err = cisClient.UpdateZoneDnssec(opt) - } - } - case cisDomainSettingsWAF: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateWebApplicationFirewallOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateWebApplicationFirewall(opt) - } - } - case cisDomainSettingsSSL: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(cisID) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewChangeSslSettingOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.ChangeSslSetting(opt) - } - } - - case cisDomainSettingsMinTLSVersion: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateMinTlsVersionOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateMinTlsVersion(opt) - } - } - case cisDomainSettingsBrotli: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateBrotliOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateBrotli(opt) - } - } - case cisDomainSettingsCNAMEFlattening: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateZoneCnameFlatteningOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateZoneCnameFlattening(opt) - } - } - case cisDomainSettingsOpportunisticEncryption: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateOpportunisticEncryptionOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateOpportunisticEncryption(opt) - } - } - case cisDomainSettingsAutomaticHTPSRewrites: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateAutomaticHttpsRewritesOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateAutomaticHttpsRewrites(opt) - } - } - case cisDomainSettingsAlwaysUseHTTPS: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateAlwaysUseHttpsOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateAlwaysUseHttps(opt) - } - } - case cisDomainSettingsIPv6: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateIpv6Options() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateIpv6(opt) - } - } - case cisDomainSettingsBrowserCheck: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateBrowserCheckOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateBrowserCheck(opt) - } - } - case cisDomainSettingsHotlinkProtection: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateHotlinkProtectionOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateHotlinkProtection(opt) - } - } - case cisDomainSettingsHTTP2: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateHttp2Options() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateHttp2(opt) - } - } - case cisDomainSettingsImageLoadOptimization: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateImageLoadOptimizationOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateImageLoadOptimization(opt) - } - } - case cisDomainSettingsImageSizeOptimization: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateImageSizeOptimizationOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateImageSizeOptimization(opt) - } - } - case cisDomainSettingsIPGeoLocation: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateIpGeolocationOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateIpGeolocation(opt) - } - } - case cisDomainSettingsOriginErrorPagePassThru: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateEnableErrorPagesOnOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateEnableErrorPagesOn(opt) - } - } - case cisDomainSettingsPseudoIPv4: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdatePseudoIpv4Options() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdatePseudoIpv4(opt) - } - } - case cisDomainSettingsPrefetchPreload: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdatePrefetchPreloadOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdatePrefetchPreload(opt) - } - } - case cisDomainSettingsResponseBuffering: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateResponseBufferingOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateResponseBuffering(opt) - } - } - case cisDomainSettingsScriptLoadOptimisation: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateScriptLoadOptimizationOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateScriptLoadOptimization(opt) - } - } - case cisDomainSettingsServerSideExclude: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateServerSideExcludeOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateServerSideExclude(opt) - } - } - case cisDomainSettingsTLSClientAuth: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateTlsClientAuthOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateTlsClientAuth(opt) - } - } - case cisDomainSettingsTrueClientIPHeader: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateTrueClientIpOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateTrueClientIp(opt) - } - } - case cisDomainSettingsWebSockets: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateWebSocketsOptions() - opt.SetValue(v.(string)) - _, resp, err = cisClient.UpdateWebSockets(opt) - } - } - case cisDomainSettingsChallengeTTL: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateChallengeTtlOptions() - opt.SetValue(int64(v.(int))) - _, resp, err = cisClient.UpdateChallengeTTL(opt) - } - } - case cisDomainSettingsMaxUpload: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - opt := cisClient.NewUpdateMaxUploadOptions() - opt.SetValue(int64(v.(int))) - _, resp, err = cisClient.UpdateMaxUpload(opt) - } - } - case cisDomainSettingsCipher: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - cipherValue := expandStringList(v.(*schema.Set).List()) - opt := cisClient.NewUpdateCiphersOptions() - opt.SetValue(cipherValue) - _, resp, err = cisClient.UpdateCiphers(opt) - } - } - case cisDomainSettingsMinify: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - dataMap := v.([]interface{})[0].(map[string]interface{}) - css := dataMap[cisDomainSettingsMinifyCSS].(string) - html := dataMap[cisDomainSettingsMinifyHTML].(string) - js := dataMap[cisDomainSettingsMinifyJS].(string) - minifyVal, err := cisClient.NewMinifySettingValue(css, html, js) - if err != nil { - log.Println("Invalid minfiy setting values") - return err - } - opt := cisClient.NewUpdateMinifyOptions() - opt.SetValue(minifyVal) - _, resp, err = cisClient.UpdateMinify(opt) - } - } - case cisDomainSettingsSecurityHeader: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - dataMap := v.([]interface{})[0].(map[string]interface{}) - enabled := dataMap[cisDomainSettingsSecurityHeaderEnabled].(bool) - nosniff := dataMap[cisDomainSettingsSecurityHeaderNoSniff].(bool) - includeSubdomain := dataMap[cisDomainSettingsSecurityHeaderIncludeSubdomains].(bool) - maxAge := int64(dataMap[cisDomainSettingsSecurityHeaderMaxAge].(int)) - securityVal, err := cisClient.NewSecurityHeaderSettingValueStrictTransportSecurity( - enabled, maxAge, includeSubdomain, nosniff) - if err != nil { - log.Println("Invalid security header setting values") - return err - } - securityOpt, err := cisClient.NewSecurityHeaderSettingValue(securityVal) - if err != nil { - log.Println("Invalid security header setting options") - return err - } - opt := cisClient.NewUpdateSecurityHeaderOptions() - opt.SetValue(securityOpt) - _, resp, err = cisClient.UpdateSecurityHeader(opt) - } - } - case cisDomainSettingsMobileRedirect: - if d.HasChange(item) { - if v, ok := d.GetOk(item); ok { - dataMap := v.([]interface{})[0].(map[string]interface{}) - status := dataMap[cisDomainSettingsMobileRedirectStatus].(string) - mobileSubdomain := dataMap[cisDomainSettingsMobileRedirectMobileSubdomain].(string) - stripURI := dataMap[cisDomainSettingsMobileRedirectStripURI].(bool) - mobileOpt, err := cisClient.NewMobileRedirecSettingValue(status, mobileSubdomain, stripURI) - if err != nil { - log.Println("Invalid mobile redirect options") - return err - } - opt := cisClient.NewUpdateMobileRedirectOptions() - opt.SetValue(mobileOpt) - _, resp, err = cisClient.UpdateMobileRedirect(opt) - } - } - } - if err != nil { - if resp != nil && resp.StatusCode == 405 { - log.Printf("[WARN] Update %s : %s", item, err) - continue - } - log.Printf("Update settings Failed on %s, %v\n", item, resp) - return err - } - } - d.SetId(convertCisToTfTwoVar(zoneID, cisID)) - return resourceCISSettingsRead(d, meta) -} - -func resourceCISSettingsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisDomainSettingsClientSession() - if err != nil { - return err - } - - zoneID, crn, _ := convertTftoCisTwoVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - for _, item := range settingsList { - var settingErr error - var settingResponse *core.DetailedResponse - switch item { - case cisDomainSettingsDNSSEC: - opt := cisClient.NewGetZoneDnssecOptions() - result, resp, err := cisClient.GetZoneDnssec(opt) - if err == nil { - d.Set(cisDomainSettingsDNSSEC, result.Result.Status) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsWAF: - opt := cisClient.NewGetWebApplicationFirewallOptions() - result, resp, err := cisClient.GetWebApplicationFirewall(opt) - if err == nil { - d.Set(cisDomainSettingsWAF, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsSSL: - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetSslSettingOptions() - result, resp, err := cisClient.GetSslSetting(opt) - if err == nil { - d.Set(cisDomainSettingsSSL, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsBrotli: - opt := cisClient.NewGetBrotliOptions() - result, resp, err := cisClient.GetBrotli(opt) - if err == nil { - d.Set(cisDomainSettingsBrotli, result.Result.Value) - } - settingResponse = resp - - case cisDomainSettingsMinTLSVersion: - opt := cisClient.NewGetMinTlsVersionOptions() - result, resp, err := cisClient.GetMinTlsVersion(opt) - if err == nil { - d.Set(cisDomainSettingsMinTLSVersion, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsCNAMEFlattening: - opt := cisClient.NewGetZoneCnameFlatteningOptions() - result, resp, err := cisClient.GetZoneCnameFlattening(opt) - if err == nil { - d.Set(cisDomainSettingsCNAMEFlattening, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsOpportunisticEncryption: - opt := cisClient.NewGetOpportunisticEncryptionOptions() - result, resp, err := cisClient.GetOpportunisticEncryption(opt) - if err == nil { - d.Set(cisDomainSettingsOpportunisticEncryption, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsAutomaticHTPSRewrites: - opt := cisClient.NewGetAutomaticHttpsRewritesOptions() - result, resp, err := cisClient.GetAutomaticHttpsRewrites(opt) - if err == nil { - d.Set(cisDomainSettingsAutomaticHTPSRewrites, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsAlwaysUseHTTPS: - opt := cisClient.NewGetAlwaysUseHttpsOptions() - result, resp, err := cisClient.GetAlwaysUseHttps(opt) - if err == nil { - d.Set(cisDomainSettingsAlwaysUseHTTPS, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsIPv6: - opt := cisClient.NewGetIpv6Options() - result, resp, err := cisClient.GetIpv6(opt) - if err == nil { - d.Set(cisDomainSettingsIPv6, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsBrowserCheck: - opt := cisClient.NewGetBrowserCheckOptions() - result, resp, err := cisClient.GetBrowserCheck(opt) - if err == nil { - d.Set(cisDomainSettingsBrowserCheck, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsHotlinkProtection: - opt := cisClient.NewGetHotlinkProtectionOptions() - result, resp, err := cisClient.GetHotlinkProtection(opt) - if err == nil { - d.Set(cisDomainSettingsHotlinkProtection, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsHTTP2: - opt := cisClient.NewGetHttp2Options() - result, resp, err := cisClient.GetHttp2(opt) - if err == nil { - d.Set(cisDomainSettingsHTTP2, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsImageLoadOptimization: - opt := cisClient.NewGetImageLoadOptimizationOptions() - result, resp, err := cisClient.GetImageLoadOptimization(opt) - if err == nil { - d.Set(cisDomainSettingsImageLoadOptimization, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsImageSizeOptimization: - opt := cisClient.NewGetImageSizeOptimizationOptions() - result, resp, err := cisClient.GetImageSizeOptimization(opt) - if err == nil { - d.Set(cisDomainSettingsImageSizeOptimization, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsIPGeoLocation: - opt := cisClient.NewGetIpGeolocationOptions() - result, resp, err := cisClient.GetIpGeolocation(opt) - if err == nil { - d.Set(cisDomainSettingsIPGeoLocation, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsOriginErrorPagePassThru: - opt := cisClient.NewGetEnableErrorPagesOnOptions() - result, resp, err := cisClient.GetEnableErrorPagesOn(opt) - if err == nil { - d.Set(cisDomainSettingsOriginErrorPagePassThru, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsPseudoIPv4: - opt := cisClient.NewGetPseudoIpv4Options() - result, resp, err := cisClient.GetPseudoIpv4(opt) - if err == nil { - d.Set(cisDomainSettingsPseudoIPv4, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsPrefetchPreload: - opt := cisClient.NewGetPrefetchPreloadOptions() - result, resp, err := cisClient.GetPrefetchPreload(opt) - if err == nil { - d.Set(cisDomainSettingsPrefetchPreload, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsResponseBuffering: - opt := cisClient.NewGetResponseBufferingOptions() - result, resp, err := cisClient.GetResponseBuffering(opt) - if err == nil { - d.Set(cisDomainSettingsResponseBuffering, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsScriptLoadOptimisation: - opt := cisClient.NewGetScriptLoadOptimizationOptions() - result, resp, err := cisClient.GetScriptLoadOptimization(opt) - if err == nil { - d.Set(cisDomainSettingsScriptLoadOptimisation, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsServerSideExclude: - opt := cisClient.NewGetServerSideExcludeOptions() - result, resp, err := cisClient.GetServerSideExclude(opt) - if err == nil { - d.Set(cisDomainSettingsServerSideExclude, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsTLSClientAuth: - opt := cisClient.NewGetTlsClientAuthOptions() - result, resp, err := cisClient.GetTlsClientAuth(opt) - if err == nil { - d.Set(cisDomainSettingsTLSClientAuth, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsTrueClientIPHeader: - opt := cisClient.NewGetTrueClientIpOptions() - result, resp, err := cisClient.GetTrueClientIp(opt) - if err == nil { - d.Set(cisDomainSettingsTrueClientIPHeader, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsWebSockets: - opt := cisClient.NewGetWebSocketsOptions() - result, resp, err := cisClient.GetWebSockets(opt) - if err == nil { - d.Set(cisDomainSettingsWebSockets, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsChallengeTTL: - opt := cisClient.NewGetChallengeTtlOptions() - result, resp, err := cisClient.GetChallengeTTL(opt) - if err == nil { - d.Set(cisDomainSettingsChallengeTTL, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsMaxUpload: - opt := cisClient.NewGetMaxUploadOptions() - result, resp, err := cisClient.GetMaxUpload(opt) - if err == nil { - d.Set(cisDomainSettingsMaxUpload, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsCipher: - opt := cisClient.NewGetCiphersOptions() - result, resp, err := cisClient.GetCiphers(opt) - if err == nil { - d.Set(cisDomainSettingsCipher, result.Result.Value) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsMinify: - opt := cisClient.NewGetMinifyOptions() - result, resp, err := cisClient.GetMinify(opt) - if err == nil { - minify := result.Result.Value - value := map[string]string{ - cisDomainSettingsMinifyCSS: *minify.Css, - cisDomainSettingsMinifyHTML: *minify.HTML, - cisDomainSettingsMinifyJS: *minify.Js, - } - d.Set(cisDomainSettingsMinify, []interface{}{value}) - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsSecurityHeader: - opt := cisClient.NewGetSecurityHeaderOptions() - result, resp, err := cisClient.GetSecurityHeader(opt) - if err == nil { - - if result.Result.Value != nil && result.Result.Value.StrictTransportSecurity != nil { - - securityHeader := result.Result.Value.StrictTransportSecurity - value := map[string]interface{}{} - if securityHeader.Enabled != nil { - value[cisDomainSettingsSecurityHeaderEnabled] = *securityHeader.Enabled - } - if securityHeader.Nosniff != nil { - value[cisDomainSettingsSecurityHeaderNoSniff] = *securityHeader.Nosniff - } - if securityHeader.IncludeSubdomains != nil { - value[cisDomainSettingsSecurityHeaderIncludeSubdomains] = *securityHeader.IncludeSubdomains - } - if securityHeader.MaxAge != nil { - value[cisDomainSettingsSecurityHeaderMaxAge] = *securityHeader.MaxAge - } - d.Set(cisDomainSettingsSecurityHeader, []interface{}{value}) - } - } - settingResponse = resp - settingErr = err - - case cisDomainSettingsMobileRedirect: - opt := cisClient.NewGetMobileRedirectOptions() - result, resp, err := cisClient.GetMobileRedirect(opt) - if err == nil { - if result.Result.Value != nil { - - value := result.Result.Value - - uri := map[string]interface{}{} - if value.MobileSubdomain != nil { - uri[cisDomainSettingsMobileRedirectMobileSubdomain] = *value.MobileSubdomain - } - if value.Status != nil { - uri[cisDomainSettingsMobileRedirectStatus] = *value.Status - } - if value.StripURI != nil { - uri[cisDomainSettingsMobileRedirectStripURI] = *value.StripURI - } - d.Set(cisDomainSettingsMobileRedirect, []interface{}{uri}) - } - } - settingResponse = resp - settingErr = err - } - - if settingErr != nil { - if settingResponse != nil && settingResponse.StatusCode == 405 { - log.Printf("[WARN] Get %s. : %s", item, settingErr) - continue - } - log.Printf("Get settings failed on %s, %v\n", item, settingErr) - return settingErr - } - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - return nil -} - -func resourceCISSettingsDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_domain_test.go b/ibm/resource_ibm_cis_domain_test.go deleted file mode 100644 index f4868c299..000000000 --- a/ibm/resource_ibm_cis_domain_test.go +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "testing" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/google/uuid" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMCisDomain_basic(t *testing.T) { - name := "ibm_cis_domain." + "cis_domain" - testDomain := uuid.New().String() + cisDomainTest - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - // No requirement for CheckDestory of this resource as by reaching this test it must have already been deleted - // correctly during the resource destroy phase of test. The destroy of resource_ibm_cis used in testAccCheckCisPoolConfigBasic - // will fail if this resource is not correctly deleted. - Steps: []resource.TestStep{ - { - Config: testAccCheckCisDomainConfigCisRIbasic("test_acc", testDomain), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "domain", testDomain), - resource.TestCheckResourceAttr(name, "name_servers.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMCisDomain_CreateAfterManualDestroy(t *testing.T) { - // Manual destroy of Domain resource - //t.Parallel() - t.Skip() - var zoneOne, zoneTwo string - name := "ibm_cis_domain." + "cis_domain" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisDomainDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisDomainConfigCisRIbasic("test", cisDomainTest), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisDomainExists(name, &zoneOne), - testAccCisDomainManuallyDelete(&zoneOne), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: testAccCheckCisDomainConfigCisRIbasic("test", cisDomainTest), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisDomainExists(name, &zoneTwo), - // No check for change in ID as CIS retains the same domainid across create/delete for a domain - ), - }, - }, - }) -} - -func TestAccIBMCisDomain_CreateAfterManualCisRIDestroy(t *testing.T) { - // Manual destroy of Domain resource & CIS Resource Instance - //t.Parallel() - t.Skip() - var zoneOne, zoneTwo string - name := "ibm_cis_domain." + "cis_domain" - testDomain := uuid.New().String() + cisDomainTest - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisDomainDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisDomainConfigCisRIbasic("test", testDomain), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisDomainExists(name, &zoneOne), - testAccCisDomainManuallyDelete(&zoneOne), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: testAccCheckCisDomainConfigCisRIbasic("test", testDomain), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisDomainExists(name, &zoneTwo), - // No check for change in ID as CIS retains the same domainid across create/delete for a domain - ), - }, - }, - }) -} - -func TestAccIBMCisDomain_import(t *testing.T) { - name := "ibm_cis_domain.cis_domain" - testDomain := uuid.New().String() + cisDomainTest - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisDomainConfigCisRIbasic("test_acc", testDomain), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "status", "pending"), - resource.TestCheckResourceAttr(name, "domain", testDomain), - resource.TestCheckResourceAttr(name, "name_servers.#", "2"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes"}, - }, - }, - }) -} - -func testAccCisDomainManuallyDelete(tfZoneID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - tfZone := *tfZoneID - - cisClient, err := testAccProvider.Meta().(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - - zoneID, crn, err := convertTftoCisTwoVar(tfZone) - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - delOpt := cisClient.NewDeleteZoneOptions(zoneID) - _, resp, err := cisClient.DeleteZone(delOpt) - if err != nil { - return fmt.Errorf("[ERR] Error deleting zone %v", resp) - } - return nil - } -} - -func testAccCheckCisDomainDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cis_domain" { - continue - } - log.Println("check domain destroy : ", rs.Primary.ID) - zoneID, crn, err := convertTftoCisTwoVar(rs.Primary.ID) - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - opt := cisClient.NewGetZoneOptions(zoneID) - _, _, err = cisClient.GetZone(opt) - if err == nil { - return fmt.Errorf("Domain still exists when destroying") - } - } - - return nil -} - -func testAccCheckCisDomainExists(n string, tfZoneID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No Domain ID is set") - } - - cisClient, err := testAccProvider.Meta().(ClientSession).CisZonesV1ClientSession() - if err != nil { - return err - } - zoneID, crn, err := convertTftoCisTwoVar(rs.Primary.ID) - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - opt := cisClient.NewGetZoneOptions(zoneID) - foundZone, resp, err := cisClient.GetZone(opt) - if err != nil { - return fmt.Errorf("Domain does not exists: %v", resp) - } - *tfZoneID = convertCisToTfTwoVar(*foundZone.Result.ID, crn) - return nil - } -} - -// func testAccCheckCisDomainConfigCisDS_basic(resourceName string, domain string) string { -// // Cis instance data source -// return testAccCheckCisInstanceDataSourceConfig_basic(cisResourceGroup, cisInstance) + fmt.Sprintf(` -// resource "ibm_cis_domain" "%[1]s" { -// cis_id = data.ibm_cis.testacc_ds_cis.id -// domain = "%[2]s" -// } -// `, resourceName, domain) -// } - -func testAccCheckCisDomainConfigCisRIbasic(resourceName string, domain string) string { - // Cis dynamically created resource instance - return testAccCheckIBMCisDataSourceConfig(cisInstance) + fmt.Sprintf(` - resource "ibm_cis_domain" "cis_domain" { - cis_id = data.ibm_cis.cis.id - domain = "%[1]s" - } - `, domain) -} - -// func testAccCheckCisDomainDataSourceConfig_basic(resourceName string, domain string) string { -// return testAccCheckCisInstanceDataSourceConfig_basic(cisResourceGroup, cisInstance) + fmt.Sprintf(` -// data "ibm_cis_domain" "%[1]s" { -// cis_id = data.ibm_cis.testacc_ds_cis.id -// domain = "%[2]s" -// } -// `, resourceName, domain) -// } - -// func testAccCheckCisInstanceDataSourceConfig_basic(cisResourceGroup string, cisInstance string) string { -// // defaultResourceGroup from env vars -// //cisInstance from env vars -// return fmt.Sprintf(` -// data "ibm_resource_group" "test_acc" { -// name = "%[1]s" -// } - -// data "ibm_cis" "testacc_ds_cis" { -// resource_group_id = data.ibm_resource_group.test_acc.id -// name = "%[2]s" -// } -// `, cisResourceGroup, cisInstance) - -// } diff --git a/ibm/resource_ibm_cis_edge_functions_action.go b/ibm/resource_ibm_cis_edge_functions_action.go deleted file mode 100644 index d5f4ef3da..000000000 --- a/ibm/resource_ibm_cis_edge_functions_action.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "strings" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisEdgeFunctionsActionActionName = "action_name" - cisEdgeFunctionsActionScript = "script" -) - -func resourceIBMCISEdgeFunctionsAction() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISEdgeFunctionsActionCreate, - Read: resourceIBMCISEdgeFunctionsActionRead, - Update: resourceIBMCISEdgeFunctionsActionUpdate, - Delete: resourceIBMCISEdgeFunctionsActionDelete, - Exists: resourceIBMCISEdgeFunctionsActionExists, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisEdgeFunctionsActionActionName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Edge function action script name", - }, - cisEdgeFunctionsActionScript: { - Type: schema.TypeString, - Required: true, - Description: "Edge function action script", - }, - }, - } -} - -func resourceIBMCISEdgeFunctionsActionCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - scriptName := d.Get(cisEdgeFunctionsActionActionName).(string) - script := d.Get(cisEdgeFunctionsActionScript).(string) - r := ioutil.NopCloser(strings.NewReader(script)) - opt := cisClient.NewUpdateEdgeFunctionsActionOptions(scriptName) - opt.SetEdgeFunctionsAction(r) - - _, _, err = cisClient.UpdateEdgeFunctionsAction(opt) - if err != nil { - return fmt.Errorf("Error: %v", err) - } - d.SetId(convertCisToTfThreeVar(scriptName, zoneID, crn)) - return resourceIBMCISEdgeFunctionsActionRead(d, meta) -} - -func resourceIBMCISEdgeFunctionsActionUpdate(d *schema.ResourceData, meta interface{}) error { - if d.HasChange(cisEdgeFunctionsActionScript) { - return resourceIBMCISEdgeFunctionsActionCreate(d, meta) - } - - return resourceIBMCISEdgeFunctionsActionRead(d, meta) -} - -func resourceIBMCISEdgeFunctionsActionRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - - scriptName, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewGetEdgeFunctionsActionOptions(scriptName) - result, resp, err := cisClient.GetEdgeFunctionsAction(opt) - if err != nil { - return fmt.Errorf("Error: %v", resp) - } - - // read script content - content := []byte{} - p := make([]byte, 8) - for { - n, err := result.Read(p) - content = append(content, p[:n]...) - if err == io.EOF || n < 1 { - break - } - } - err = result.Close() - if err != nil { - return fmt.Errorf("Error in closing reader") - } - - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisEdgeFunctionsActionActionName, scriptName) - d.Set(cisEdgeFunctionsActionScript, string(content)) - return nil -} - -func resourceIBMCISEdgeFunctionsActionExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return false, fmt.Errorf("Error in creating CIS object") - } - - scriptName, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewGetEdgeFunctionsActionOptions(scriptName) - _, response, err := cisClient.GetEdgeFunctionsAction(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("Edge functions action script is not found") - return false, nil - } - return false, fmt.Errorf("Error: %v", response) - } - return true, nil -} - -func resourceIBMCISEdgeFunctionsActionDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return fmt.Errorf("Error in creating CIS object") - } - - scriptName, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewDeleteEdgeFunctionsActionOptions(scriptName) - _, response, err := cisClient.DeleteEdgeFunctionsAction(opt) - if err != nil { - return fmt.Errorf("Error in edge function action script deletion: %v", response) - } - return nil -} diff --git a/ibm/resource_ibm_cis_edge_functions_trigger.go b/ibm/resource_ibm_cis_edge_functions_trigger.go deleted file mode 100644 index a552b2782..000000000 --- a/ibm/resource_ibm_cis_edge_functions_trigger.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - cisEdgeFunctionsTriggerID = "trigger_id" - cisEdgeFunctionsTriggerPattern = "pattern_url" - cisEdgeFunctionsTriggerActionName = "action_name" - cisEdgeFunctionsTriggerRequestLimitFailOpen = "request_limit_fail_open" -) - -func resourceIBMCISEdgeFunctionsTrigger() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISEdgeFunctionsTriggerCreate, - Read: resourceIBMCISEdgeFunctionsTriggerRead, - Update: resourceIBMCISEdgeFunctionsTriggerUpdate, - Delete: resourceIBMCISEdgeFunctionsTriggerDelete, - Exists: resourceIBMCISEdgeFunctionsTriggerExists, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDataDiff, - }, - cisEdgeFunctionsTriggerID: { - Type: schema.TypeString, - Computed: true, - Description: "CIS Edge Functions trigger route ID", - }, - cisEdgeFunctionsTriggerPattern: { - Type: schema.TypeString, - Required: true, - Description: "Edge function trigger pattern", - }, - cisEdgeFunctionsTriggerActionName: { - Type: schema.TypeString, - Optional: true, - Description: "Edge function trigger action name", - }, - cisEdgeFunctionsTriggerRequestLimitFailOpen: { - Type: schema.TypeBool, - Computed: true, - Description: "Edge function trigger request limit fail open", - }, - }, - } -} - -func resourceIBMCISEdgeFunctionsTriggerCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewCreateEdgeFunctionsTriggerOptions() - if action, ok := d.GetOk(cisEdgeFunctionsTriggerActionName); ok { - opt.SetScript(action.(string)) - } - pattern := d.Get(cisEdgeFunctionsTriggerPattern).(string) - opt.SetPattern(pattern) - - result, _, err := cisClient.CreateEdgeFunctionsTrigger(opt) - if err != nil { - return fmt.Errorf("Error creating edge function trigger route : %v", err) - } - d.SetId(convertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) - return resourceIBMCISEdgeFunctionsTriggerRead(d, meta) -} - -func resourceIBMCISEdgeFunctionsTriggerUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - - routeID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - if d.HasChange(cisEdgeFunctionsTriggerActionName) || - d.HasChange(cisEdgeFunctionsTriggerPattern) { - opt := cisClient.NewUpdateEdgeFunctionsTriggerOptions(routeID) - - if action, ok := d.GetOk(cisEdgeFunctionsTriggerActionName); ok { - opt.SetScript(action.(string)) - } - pattern := d.Get(cisEdgeFunctionsTriggerPattern).(string) - opt.SetPattern(pattern) - - _, _, err := cisClient.UpdateEdgeFunctionsTrigger(opt) - if err != nil { - return fmt.Errorf("Error updating edge function trigger route : %v", err) - } - } - return resourceIBMCISEdgeFunctionsTriggerRead(d, meta) -} - -func resourceIBMCISEdgeFunctionsTriggerRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return err - } - - routeID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewGetEdgeFunctionsTriggerOptions(routeID) - result, resp, err := cisClient.GetEdgeFunctionsTrigger(opt) - if err != nil { - return fmt.Errorf("Error: %v", resp) - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisEdgeFunctionsTriggerID, routeID) - d.Set(cisEdgeFunctionsTriggerActionName, result.Result.Script) - d.Set(cisEdgeFunctionsTriggerPattern, result.Result.Pattern) - d.Set(cisEdgeFunctionsTriggerRequestLimitFailOpen, result.Result.RequestLimitFailOpen) - return nil -} - -func resourceIBMCISEdgeFunctionsTriggerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return false, err - } - - routeID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewGetEdgeFunctionsTriggerOptions(routeID) - _, response, err := cisClient.GetEdgeFunctionsTrigger(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("Edge functions trigger route is not found") - return false, nil - } - return false, fmt.Errorf("Error: %v", response) - } - return true, nil -} - -func resourceIBMCISEdgeFunctionsTriggerDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() - if err != nil { - return fmt.Errorf("Error in creating CIS object") - } - - routeID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewDeleteEdgeFunctionsTriggerOptions(routeID) - _, response, err := cisClient.DeleteEdgeFunctionsTrigger(opt) - if err != nil { - return fmt.Errorf("Error in edge function trigger route deletion: %v", response) - } - return nil -} diff --git a/ibm/resource_ibm_cis_filter.go b/ibm/resource_ibm_cis_filter.go deleted file mode 100644 index d40154ef0..000000000 --- a/ibm/resource_ibm_cis_filter.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/networking-go-sdk/filtersv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISFilters = "ibm_cis_filter" - cisFilterExpression = "expression" - cisFilterPaused = "paused" - cisFilterDescription = "description" - cisFilterID = "filter_id" -) - -func resourceIBMCISFilter() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISFilterCreate, - Read: resourceIBMCISFilterRead, - Update: resourceIBMCISFilterUpdate, - Delete: resourceIBMCISFilterDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisFilterPaused: { - Type: schema.TypeBool, - Optional: true, - Description: "Filter Paused", - }, - cisFilterID: { - Type: schema.TypeString, - Computed: true, - Description: "Filter ID", - }, - cisFilterExpression: { - Type: schema.TypeString, - Required: true, - Description: "Filter Expression", - }, - cisFilterDescription: { - Type: schema.TypeString, - Optional: true, - Description: "Filter Description", - ValidateFunc: InvokeValidator(ibmCISFilters, cisFilterDescription), - }, - }, - } -} -func resourceIBMCISFilterCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return fmt.Errorf("Error while Getting IAM Access Token using BluemixSession %s", err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFiltersSession() - if err != nil { - return fmt.Errorf("Error while getting the CisFiltersSession %s", err) - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - - var newfilter filtersv1.FilterInput - - if p, ok := d.GetOkExists(cisFilterPaused); ok { - paused := p.(bool) - newfilter.Paused = &paused - } - if des, ok := d.GetOk(cisFilterDescription); ok { - description := des.(string) - newfilter.Description = &description - } - if e, ok := d.GetOk(cisFilterExpression); ok { - expression := e.(string) - newfilter.Expression = &expression - } - - opt := cisClient.NewCreateFilterOptions(xAuthtoken, crn, zoneID) - - opt.SetFilterInput([]filtersv1.FilterInput{newfilter}) - - result, resp, err := cisClient.CreateFilter(opt) - if err != nil || result == nil { - return fmt.Errorf("Error creating Filter for zone %q: %s %s", zoneID, err, resp) - } - d.SetId(convertCisToTfThreeVar(*result.Result[0].ID, zoneID, crn)) - return resourceIBMCISFilterRead(d, meta) - -} -func resourceIBMCISFilterRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return fmt.Errorf("Error while Getting IAM Access Token using BluemixSession %s", err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFiltersSession() - if err != nil { - return fmt.Errorf("Error while getting the CisFiltersSession %s", err) - } - filterid, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return err - } - opt := cisClient.NewGetFilterOptions(xAuthtoken, crn, zoneID, filterid) - - result, response, err := cisClient.GetFilter(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("Error GetFilter not found ") - d.SetId("") - return nil - } - return fmt.Errorf("Error finding GetFilter %q: %s %s", d.Id(), err, response) - } - if result.Result != nil { - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisFilterID, result.Result.ID) - d.Set(cisFilterPaused, result.Result.Paused) - d.Set(cisFilterDescription, result.Result.Description) - d.Set(cisFilterExpression, result.Result.Expression) - } - return nil -} -func resourceIBMCISFilterUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return fmt.Errorf("Error while Getting IAM Access Token using BluemixSession %s", err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFiltersSession() - if err != nil { - return fmt.Errorf("Error while getting the CisFiltersSession %s", err) - } - - filterid, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return err - } - - if d.HasChange(cisFilterExpression) || - d.HasChange(cisFilterPaused) || - d.HasChange(cisFilterDescription) { - - var updatefilter filtersv1.FilterUpdateInput - updatefilter.ID = &filterid - - if p, ok := d.GetOkExists(cisFilterPaused); ok { - paused := p.(bool) - updatefilter.Paused = &paused - } - if des, ok := d.GetOk(cisFilterDescription); ok { - description := des.(string) - updatefilter.Description = &description - } - if e, ok := d.GetOk(cisFilterExpression); ok { - expression := e.(string) - updatefilter.Expression = &expression - } - - opt := cisClient.NewUpdateFiltersOptions(xAuthtoken, crn, zoneID) - - opt.SetFilterUpdateInput([]filtersv1.FilterUpdateInput{updatefilter}) - - result, resp, err := cisClient.UpdateFilters(opt) - if err != nil { - return fmt.Errorf("Error updating Filter for zone %q: %s %s", zoneID, err, resp) - } - - if *result.Result[0].ID == "" { - return fmt.Errorf("Error failed to find id in Update response; resource was empty") - } - } - return resourceIBMCISFilterRead(d, meta) -} -func resourceIBMCISFilterDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - xAuthtoken := sess.Config.IAMAccessToken - cisClient, err := meta.(ClientSession).CisFiltersSession() - if err != nil { - return err - } - filterid, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return err - } - opt := cisClient.NewDeleteFiltersOptions(xAuthtoken, crn, zoneID, filterid) - _, _, err = cisClient.DeleteFilters(opt) - if err != nil { - return fmt.Errorf("Error deleting Filter: %s", err) - } - - return nil -} -func resourceIBMCISFilterValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisFilterDescription, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "Filter-creation"}) - - ibmCISFiltersResourceValidator := ResourceValidator{ResourceName: ibmCISFilters, Schema: validateSchema} - return &ibmCISFiltersResourceValidator -} diff --git a/ibm/resource_ibm_cis_filter_test.go b/ibm/resource_ibm_cis_filter_test.go deleted file mode 100644 index 8b14b09ac..000000000 --- a/ibm/resource_ibm_cis_filter_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisFilter_Basic(t *testing.T) { - name := "ibm_cis_filter." + "test" - filterexp := "(http.request.uri eq \"/test-update?number=5\")" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisFilter_basic("test", cisDomainStatic, "true", "Filter-creation", filterexp), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "description", "Filter-creation"), - resource.TestCheckResourceAttr(name, "expression", filterexp), - resource.TestCheckResourceAttr(name, "paused", "true"), - ), - }, - }, - }) -} - -func TestAccIBMCisFilter_Import(t *testing.T) { - name := "ibm_cis_filter." + "test" - filterexp := "(http.request.uri eq \"/test-update?number=5\")" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisFilter_basic("test", cisDomainStatic, "true", "Filter-creation", filterexp), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "expression", filterexp), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} -func testAccCheckCisFilter_basic(id, cisDomainStatic, paused, description, expression string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_filter" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - paused = "true" - description = "Filter-creation" - expression = "(http.request.uri eq \"/test-update?number=5\")" - } -`, id, cisDomainStatic, paused, description, expression) -} diff --git a/ibm/resource_ibm_cis_firewall_rules.go b/ibm/resource_ibm_cis_firewall_rules.go deleted file mode 100644 index d10b48fce..000000000 --- a/ibm/resource_ibm_cis_firewall_rules.go +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/IBM/networking-go-sdk/firewallrulesv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISFirewallrules = "ibm_cis_firewall_rules" - cisFirewallrulesID = "firewall_rule_id" - cisFilter = "filter" - cisFirewallrulesAction = "action" - cisFirewallrulesPaused = "paused" - cisFirewallrulesPriority = "priority" - cisFirewallrulesDescription = "description" - cisFirewallrulesList = "firewall_rules" -) - -func resourceIBMCISFirewallrules() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMCISFirewallrulesCreate, - ReadContext: resourceIBMCISFirewallrulesRead, - UpdateContext: resourceIBMCISFirewallrulesUpdate, - DeleteContext: resourceIBMCISFirewallrulesDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisFilterID: { - Type: schema.TypeString, - Required: true, - Description: "Firewallrules Existing FilterID", - }, - cisFirewallrulesAction: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator(ibmCISFirewallrules, cisFirewallrulesAction), - Description: "Firewallrules Action", - }, - cisFirewallrulesPriority: { - Type: schema.TypeInt, - Description: "Firewallrules Action", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISFirewallrules, cisFirewallrulesPriority), - }, - cisFirewallrulesDescription: { - Type: schema.TypeString, - Optional: true, - Description: "Firewallrules Description", - ValidateFunc: InvokeValidator(ibmCISFirewallrules, cisFirewallrulesDescription), - }, - cisFirewallrulesPaused: { - Type: schema.TypeBool, - Optional: true, - Description: "Firewallrules Paused", - }, - }, - } -} - -func resourceIBMCISFirewallrulesCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFirewallRulesSession() - if err != nil { - return diag.FromErr(err) - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - - var newFirewallRules firewallrulesv1.FirewallRuleInputWithFilterID - - if a, ok := d.GetOk(cisFirewallrulesAction); ok { - action := a.(string) - newFirewallRules.Action = &action - } - if des, ok := d.GetOk(cisFilterDescription); ok { - description := des.(string) - newFirewallRules.Description = &description - } - if id, ok := d.GetOk(cisFilterID); ok { - filterid := id.(string) - filterModel, _ := cisClient.NewFirewallRuleInputWithFilterIdFilter(filterid) - newFirewallRules.Filter = filterModel - } - - opt := cisClient.NewCreateFirewallRulesOptions(xAuthtoken, crn, zoneID) - - opt.SetFirewallRuleInputWithFilterID([]firewallrulesv1.FirewallRuleInputWithFilterID{newFirewallRules}) - - result, _, err := cisClient.CreateFirewallRulesWithContext(context, opt) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error reading the %s", err)) - } - d.SetId(convertCisToTfThreeVar(*result.Result[0].ID, zoneID, crn)) - - return resourceIBMCISFirewallrulesRead(context, d, meta) - -} -func resourceIBMCISFirewallrulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFirewallRulesSession() - if err != nil { - return diag.FromErr(err) - } - firwallruleID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - opt := cisClient.NewGetFirewallRuleOptions(xAuthtoken, crn, zoneID, firwallruleID) - - result, response, err := cisClient.GetFirewallRuleWithContext(context, opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("Error reading the firewall rules %s:%s", err, response)) - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisFilterID, result.Result.Filter.ID) - d.Set(cisFirewallrulesAction, result.Result.Action) - d.Set(cisFirewallrulesPaused, result.Result.Paused) - d.Set(cisFilterDescription, result.Result.Description) - - return nil -} -func resourceIBMCISFirewallrulesUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFirewallRulesSession() - if err != nil { - return diag.FromErr(err) - } - - firewallruleID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - if d.HasChange(cisFilterID) || - d.HasChange(cisFirewallrulesAction) || - d.HasChange(cisFirewallrulesPaused) || - d.HasChange(cisFilterDescription) { - - var updatefirewallrules firewallrulesv1.FirewallRulesUpdateInputItem - updatefirewallrules.ID = &firewallruleID - - if a, ok := d.GetOk(cisFirewallrulesAction); ok { - action := a.(string) - updatefirewallrules.Action = &action - } - if p, ok := d.GetOk(cisFirewallrulesPaused); ok { - paused := p.(bool) - updatefirewallrules.Paused = &paused - } - if des, ok := d.GetOk(cisFilterDescription); ok { - description := des.(string) - updatefirewallrules.Description = &description - } - - if id, ok := d.GetOk(cisFilterID); ok { - filterid := id.(string) - filterUpdate, _ := cisClient.NewFirewallRulesUpdateInputItemFilter(filterid) - updatefirewallrules.Filter = filterUpdate - } - opt := cisClient.NewUpdateFirewllRulesOptions(xAuthtoken, crn, zoneID) - - opt.SetFirewallRulesUpdateInputItem([]firewallrulesv1.FirewallRulesUpdateInputItem{updatefirewallrules}) - - result, _, err := cisClient.UpdateFirewllRulesWithContext(context, opt) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error updating the firewall rules %s", err)) - } - } - return resourceIBMCISFirewallrulesRead(context, d, meta) -} -func resourceIBMCISFirewallrulesDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - xAuthtoken := sess.Config.IAMAccessToken - - cisClient, err := meta.(ClientSession).CisFirewallRulesSession() - if err != nil { - return diag.FromErr(err) - } - - firewallruleid, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - opt := cisClient.NewDeleteFirewallRulesOptions(xAuthtoken, crn, zoneID, firewallruleid) - _, response, err := cisClient.DeleteFirewallRulesWithContext(context, opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return diag.FromErr(fmt.Errorf("Error deleting the custom resolver %s:%s", err, response)) - } - - d.SetId("") - return nil -} -func resourceIBMCISFirewallrulesValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 1) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisFirewallrulesAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "log, allow, challenge, js_challenge, block"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisFirewallrulesDescription, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "Firewallrules-creation"}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisFirewallrulesPriority, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, - Optional: true, - MinValue: "1", - MaxValue: "2147483647"}) - ibmCISFirewallrulesResourceValidator := ResourceValidator{ResourceName: ibmCISFirewallrules, Schema: validateSchema} - return &ibmCISFirewallrulesResourceValidator -} diff --git a/ibm/resource_ibm_cis_healthcheck_test.go b/ibm/resource_ibm_cis_healthcheck_test.go deleted file mode 100644 index fd0b2106f..000000000 --- a/ibm/resource_ibm_cis_healthcheck_test.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMCisHealthcheck_Basic(t *testing.T) { - var monitor string - name := "ibm_cis_healthcheck.health_check" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - // No requirement for CheckDestory of this resource as by reaching this point it must have already been deleted from CIS. - Steps: []resource.TestStep{ - { - Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisHealthcheckExists(name, &monitor), - resource.TestCheckResourceAttr(name, "expected_body", "alive"), - ), - }, - }, - }) -} - -func TestAccIBMCisHealthcheck_import(t *testing.T) { - name := "ibm_cis_healthcheck.health_check" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisMonitorDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "expected_body", "alive"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes"}, - }, - }, - }) -} - -func TestAccIBMCisHealthcheck_FullySpecified(t *testing.T) { - var monitor string - name := "ibm_cis_healthcheck.health_check" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisMonitorDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisHealthcheckConfigFullySpecified("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisHealthcheckExists(name, &monitor), - resource.TestCheckResourceAttr(name, "path", "/custom"), - resource.TestCheckResourceAttr(name, "retries", "3"), - resource.TestCheckResourceAttr(name, "expected_codes", "5xx"), - ), - }, - }, - }) -} - -func TestAccIBMCisHealthcheck_CreateAfterManualDestroy(t *testing.T) { - var monitorOne, monitorTwo string - name := "ibm_cis_healthcheck.health_check" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisMonitorDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisHealthcheckExists(name, &monitorOne), - testAccCisMonitorManuallyDelete(&monitorOne), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisHealthcheckExists(name, &monitorTwo), - func(state *terraform.State) error { - if monitorOne == monitorTwo { - return fmt.Errorf("load balancer monitor id is unchanged even after we thought we deleted it ( %s )", - monitorTwo) - } - return nil - }, - ), - }, - }, - }) -} - -func testAccCisMonitorManuallyDelete(tfMonitorID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBHealthCheckClientSession() - if err != nil { - return err - } - tfMonitor := *tfMonitorID - healthcheckID, cisID, _ := convertTftoCisTwoVar(tfMonitor) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewDeleteLoadBalancerMonitorOptions(healthcheckID) - _, _, err = cisClient.DeleteLoadBalancerMonitor(opt) - if err != nil { - return fmt.Errorf("Error deleting IBMCISMonitor Record: %s", err) - } - return nil - } -} - -func testAccCheckCisMonitorDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBHealthCheckClientSession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cis_healthcheck" { - continue - } - healthcheckID, cisID, _ := convertTftoCisTwoVar(rs.Primary.ID) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewGetLoadBalancerMonitorOptions(healthcheckID) - _, _, err = cisClient.GetLoadBalancerMonitor(opt) - if err == nil { - return fmt.Errorf("Load balancer Monitor still exists") - } - } - - return nil -} - -func testAccCheckCisHealthcheckExists(n string, tfMonitorID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - if rs.Primary.ID == "" { - return fmt.Errorf("No Load Balancer Monitor ID is set") - } - - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBHealthCheckClientSession() - if err != nil { - return err - } - healthcheckID, cisID, _ := convertTftoCisTwoVar(rs.Primary.ID) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewGetLoadBalancerMonitorOptions(healthcheckID) - foundHealthcheck, _, err := cisClient.GetLoadBalancerMonitor(opt) - if err != nil { - return fmt.Errorf("Load balancer Monitor still exists") - } - *tfMonitorID = convertCisToTfTwoVar(*foundHealthcheck.Result.ID, cisID) - return nil - } -} - -func testAccCheckCisHealthcheckConfigCisDSBasic(resourceID string, cisDomain string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_healthcheck" "health_check" { - cis_id = data.ibm_cis.cis.id - expected_body = "alive" - expected_codes = "2xx" - } - `) -} - -func testAccCheckCisHealthcheckConfigFullySpecified(resourceID string, cisDomain string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_healthcheck" "health_check" { - cis_id = data.ibm_cis.cis.id - expected_body = "dead" - expected_codes = "5xx" - method = "HEAD" - timeout = 9 - path = "/custom" - interval = 60 - retries = 3 - description = "this is a very weird load balancer" - headers { - header = "Host" - values = ["example.com", "example1.com"] - } - headers { - header = "Host1" - values = ["example3.com", "example11.com"] - } - } - `) -} diff --git a/ibm/resource_ibm_cis_origin_pool_test.go b/ibm/resource_ibm_cis_origin_pool_test.go deleted file mode 100644 index 015efcead..000000000 --- a/ibm/resource_ibm_cis_origin_pool_test.go +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "testing" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMCisPool_Basic(t *testing.T) { - var pool string - rnd := acctest.RandString(10) - name := "ibm_cis_origin_pool.origin_pool" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - // No requirement for CheckDestory of this resource as by reaching this test it must have already been deleted - // correctly during the resource destroy phase of test. The destroy of resource_ibm_cis used in testAccCheckCisPoolConfigCisDSBasic - // will fail if this resource is not correctly deleted. - Steps: []resource.TestStep{ - { - Config: testAccCheckCisPoolConfigCisDSBasic(rnd, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisPoolExists(name, &pool), - resource.TestCheckResourceAttr(name, "check_regions.#", "1"), - ), - }, - { - Config: testAccCheckCisPoolConfigCisDSUpdate(rnd, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisPoolExists(name, &pool), - resource.TestCheckResourceAttr(name, "check_regions.#", "1"), - resource.TestCheckResourceAttr(name, "description", "tfacc-update-specified"), - ), - }, - }, - }) -} - -func TestAccIBMCisPool_import(t *testing.T) { - name := "ibm_cis_origin_pool.origin_pool" - rnd := acctest.RandString(10) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisPoolConfigCisDSBasic(rnd, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "check_regions.#", "1"), - resource.TestCheckResourceAttr(name, "origins.#", "1"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIBMCisPool_FullySpecified(t *testing.T) { - var pool string - rnd := acctest.RandString(10) - name := "ibm_cis_origin_pool.origin_pool" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisPoolConfigFullySpecified(rnd, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisPoolExists(name, &pool), - resource.TestCheckResourceAttr(name, "enabled", "false"), - resource.TestCheckResourceAttr(name, "description", "tfacc-fully-specified"), - resource.TestCheckResourceAttr(name, "check_regions.#", "2"), - resource.TestCheckResourceAttr(name, "minimum_origins", "2"), - resource.TestCheckResourceAttr(name, "notification_email", "admin@outlook.com"), - resource.TestCheckResourceAttr(name, "origins.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMCisPool_CreateAfterManualDestroy(t *testing.T) { - //t.Parallel() - t.Skip() - var poolOne, poolTwo string - testName := "test_acc" - name := "ibm_cis_origin_pool.origin_pool" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCisPoolDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisPoolConfigCisDSBasic(testName, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisPoolExists(name, &poolOne), - testAccCisPoolManuallyDelete(&poolOne), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: testAccCheckCisPoolConfigCisDSBasic(testName, cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - testAccCheckCisPoolExists(name, &poolTwo), - func(state *terraform.State) error { - if poolOne == poolTwo { - return fmt.Errorf("id is unchanged even after we thought we deleted it ( %s )", - poolTwo) - } - return nil - }, - ), - }, - }, - }) -} - -func testAccCheckCisPoolDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBPoolClientSession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cis_origin_pool" { - continue - } - poolID, cisID, _ := convertTftoCisTwoVar(rs.Primary.ID) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewGetLoadBalancerPoolOptions(poolID) - _, _, err := cisClient.GetLoadBalancerPool(opt) - if err == nil { - return fmt.Errorf("Load balancer pool still exists") - } - } - - return nil -} - -func testAccCheckCisPoolExists(n string, tfPoolID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No Load Balancer ID is set") - } - - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBPoolClientSession() - if err != nil { - return err - } - - poolID, cisID, _ := convertTftoCisTwoVar(rs.Primary.ID) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewGetLoadBalancerPoolOptions(poolID) - result, resp, err := cisClient.GetLoadBalancerPool(opt) - if err != nil { - return fmt.Errorf("Error getting glb pool: %v", resp) - } - - foundPool := result.Result - if *foundPool.ID != poolID { - return fmt.Errorf("Record not found") - } - - tfPool := convertCisToTfTwoVar(*foundPool.ID, cisID) - *tfPoolID = tfPool - return nil - } -} - -func testAccCisPoolManuallyDelete(tfPoolID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - log.Printf("[WARN] Manually removing pool") - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBPoolClientSession() - if err != nil { - return err - } - tfPool := *tfPoolID - poolID, cisID, _ := convertTftoCisTwoVar(tfPool) - cisClient.Crn = core.StringPtr(cisID) - opt := cisClient.NewDeleteLoadBalancerPoolOptions(poolID) - _, resp, err := cisClient.DeleteLoadBalancerPool(opt) - if err != nil { - return fmt.Errorf("[WARN] Delete GLB Pools failed : %v", resp) - } - return nil - } -} - -func testAccCheckCisPoolConfigCisDSBasic(resourceID string, cisDomainStatic string) string { - return testAccCheckCisHealthcheckConfigCisDSBasic(resourceID, cisDomainStatic) + fmt.Sprintf(` - resource "ibm_cis_origin_pool" "origin_pool" { - cis_id = data.ibm_cis.cis.id - name = "my-tf-pool-basic-%[1]s" - check_regions = ["WEU"] - description = "tfacc-fully-specified" - origins { - name = "example-1" - address = "www.google.com" - enabled = true - weight = 1 - } - enabled = false - monitor = ibm_cis_healthcheck.health_check.id - } - `, resourceID) -} - -func testAccCheckCisPoolConfigCisDSUpdate(resourceID string, cisDomainStatic string) string { - return testAccCheckCisHealthcheckConfigCisDSBasic(resourceID, cisDomainStatic) + fmt.Sprintf(` - resource "ibm_cis_origin_pool" "origin_pool" { - cis_id = data.ibm_cis.cis.id - name = "my-tf-pool-update-%[1]s" - check_regions = ["ENAM"] - description = "tfacc-update-specified" - origins { - name = "example-2" - address = "www.google2.com" - enabled = false - weight = 0.5 - } - enabled = true - monitor = ibm_cis_healthcheck.health_check.monitor_id - } - `, resourceID) -} - -func testAccCheckCisPoolConfigFullySpecified(resourceID string, cisDomainStatic string) string { - return testAccCheckCisHealthcheckConfigCisDSBasic(resourceID, cisDomainStatic) + fmt.Sprintf(` - resource "ibm_cis_origin_pool" "origin_pool" { - cis_id = data.ibm_cis.cis.id - name = "my-tf-pool-basic-%[1]s" - notification_email = "admin@outlook.com" - origins { - name = "example-1" - address = "150.0.0.1" - enabled = true - } - origins { - name = "example-2" - address = "150.0.0.2" - enabled = true - } - check_regions = ["WEU", "ENAM"] - description = "tfacc-fully-specified" - enabled = false - minimum_origins = 2 - monitor = ibm_cis_healthcheck.health_check.monitor_id - } - `, resourceID) -} diff --git a/ibm/resource_ibm_cis_range_app.go b/ibm/resource_ibm_cis_range_app.go deleted file mode 100644 index f0ce3c280..000000000 --- a/ibm/resource_ibm_cis_range_app.go +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/go-sdk-core/v5/core" - cisrangeappv1 "github.com/IBM/networking-go-sdk/rangeapplicationsv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISRangeApp = "ibm_cis_range_app" - cisRangeAppID = "app_id" - cisRangeAppProtocol = "protocol" - cisRangeAppDNS = "dns" - cisRangeAppDNSType = "dns_type" - cisRangeAppOriginDirect = "origin_direct" - cisRangeAppOriginDNS = "origin_dns" - cisRangeAppOriginPort = "origin_port" - cisRangeAppIPFirewall = "ip_firewall" - cisRangeAppProxyProtocol = "proxy_protocol" - cisRangeAppProxyProtocolOff = "off" - cisRangeAppProxyProtocolV1 = "v1" - cisRangeAppProxyProtocolV2 = "v2" - cisRangeAppProxyProtocolSimple = "simple" - cisRangeAppEdgeIPsType = "edge_ips_type" - cisRangeAppEdgeIPsTypeDynamic = "dynamic" - cisRangeAppEdgeIPsConnectivity = "edge_ips_connectivity" - cisRangeAppEdgeIPsConnectivityIPv4 = "ipv4" - cisRangeAppEdgeIPsConnectivityIPv6 = "ipv6" - cisRangeAppEdgeIPsConnectivityAll = "all" - cisRangeAppTrafficType = "traffic_type" - cisRangeAppTrafficTypeDirect = "direct" - cisRangeAppTrafficTypeHTTP = "http" - cisRangeAppTrafficTypeHTTPS = "https" - cisRangeAppTLS = "tls" - cisRangeAppTLSOff = "off" - cisRangeAppTLSFlexible = "flexible" - cisRangeAppTLSFull = "full" - cisRangeAppTLSStrict = "strict" - cisRangeAppCreatedOn = "created_on" - cisRangeAppModifiedOn = "modified_on" -) - -func resourceIBMCISRangeApp() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISRangeAppCreate, - Read: resourceIBMCISRangeAppRead, - Update: resourceIBMCISRangeAppUpdate, - Delete: resourceIBMCISRangeAppDelete, - Exists: resourceIBMCISRangeAppExists, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisRangeAppID: { - Type: schema.TypeString, - Computed: true, - Description: "Application identifier", - }, - cisRangeAppProtocol: { - Type: schema.TypeString, - Required: true, - Description: "Defines the protocol and port for this application", - }, - cisRangeAppDNS: { - Type: schema.TypeString, - Required: true, - Description: "Name of the DNS record for this application", - }, - cisRangeAppDNSType: { - Type: schema.TypeString, - Required: true, - Description: "Type of the DNS record for this application", - }, - cisRangeAppOriginDirect: { - Type: schema.TypeList, - Optional: true, - AtLeastOneOf: []string{cisRangeAppOriginDirect, cisRangeAppOriginDNS}, - Description: "IP address and port of the origin for this Range application.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - cisRangeAppOriginDNS: { - Type: schema.TypeString, - Optional: true, - AtLeastOneOf: []string{cisRangeAppOriginDirect, cisRangeAppOriginDNS}, - Description: "DNS record pointing to the origin for this Range application.", - }, - cisRangeAppOriginPort: { - Type: schema.TypeInt, - Optional: true, - ConflictsWith: []string{cisRangeAppOriginDirect}, - Description: "Port at the origin that listens to traffic", - }, - cisRangeAppIPFirewall: { - Type: schema.TypeBool, - Optional: true, - Description: "Enables the IP Firewall for this application. Only available for TCP applications.", - }, - cisRangeAppProxyProtocol: { - Type: schema.TypeString, - Optional: true, - Description: "Allows for the true client IP to be passed to the service.", - ValidateFunc: InvokeValidator(ibmCISRangeApp, cisRangeAppProtocol), - }, - cisRangeAppEdgeIPsType: { - Type: schema.TypeString, - Optional: true, - Default: cisRangeAppEdgeIPsTypeDynamic, - Description: "The type of edge IP configuration.", - ValidateFunc: InvokeValidator(ibmCISRangeApp, cisRangeAppEdgeIPsType), - }, - cisRangeAppEdgeIPsConnectivity: { - Type: schema.TypeString, - Optional: true, - Default: cisRangeAppEdgeIPsConnectivityAll, - Description: "Specifies the IP version.", - ValidateFunc: InvokeValidator(ibmCISRangeApp, cisRangeAppEdgeIPsConnectivity), - }, - cisRangeAppTrafficType: { - Type: schema.TypeString, - Optional: true, - Default: cisRangeAppTrafficTypeDirect, - Description: "Configure how traffic is handled at the edge.", - ValidateFunc: InvokeValidator(ibmCISRangeApp, cisRangeAppTrafficType), - }, - cisRangeAppTLS: { - Type: schema.TypeString, - Optional: true, - Default: cisRangeAppTLSOff, - Description: "Configure if and how TLS connections are terminated at the edge.", - ValidateFunc: InvokeValidator(ibmCISRangeApp, cisRangeAppTLS), - }, - cisRangeAppCreatedOn: { - Type: schema.TypeString, - Computed: true, - Description: "created on date", - }, - cisRangeAppModifiedOn: { - Type: schema.TypeString, - Computed: true, - Description: "modified on date", - }, - }, - } -} -func resourceIBMCISRangeAppValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - proxyProtocol := "off, v1, v2, simple" - connectivity := "ipv4, ipv6, all" - trafficType := "direct, http, https" - tls := "off, flexible, full, strict" - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRangeAppProxyProtocol, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: proxyProtocol}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRangeAppEdgeIPsConnectivity, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: connectivity}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRangeAppEdgeIPsType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "dynamic"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRangeAppTrafficType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: trafficType}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRangeAppTLS, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: tls}) - - ibmCISRangeAppResourceValidator := ResourceValidator{ResourceName: ibmCISRangeApp, Schema: validateSchema} - return &ibmCISRangeAppResourceValidator -} -func resourceIBMCISRangeAppCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - protocol := d.Get(cisRangeAppProtocol).(string) - dns := d.Get(cisRangeAppDNS).(string) - dnsType := d.Get(cisRangeAppDNSType).(string) - - dnsOpt := &cisrangeappv1.RangeAppReqDns{ - Type: &dnsType, - Name: &dns, - } - - opt := cisClient.NewCreateRangeAppOptions(protocol, dnsOpt) - - if v, ok := d.GetOk(cisRangeAppOriginDirect); ok { - opt.SetOriginDirect(expandStringList(v.([]interface{}))) - } - if v, ok := d.GetOk(cisRangeAppOriginDNS); ok { - originDNSOpt := &cisrangeappv1.RangeAppReqOriginDns{ - Name: core.StringPtr(v.(string)), - } - opt.SetOriginDns(originDNSOpt) - } - if v, ok := d.GetOk(cisRangeAppOriginPort); ok { - opt.SetOriginPort(int64(v.(int))) - } - if v, ok := d.GetOkExists(cisRangeAppIPFirewall); ok { - opt.SetIpFirewall(v.(bool)) - } - if v, ok := d.GetOk(cisRangeAppProxyProtocol); ok { - opt.SetProxyProtocol(v.(string)) - } - edgeIPsOpt := &cisrangeappv1.RangeAppReqEdgeIps{ - Type: core.StringPtr(cisRangeAppEdgeIPsTypeDynamic), - Connectivity: core.StringPtr(cisRangeAppEdgeIPsConnectivityAll), - } - if v, ok := d.GetOk(cisRangeAppEdgeIPsType); ok { - edgeIPsOpt.Type = core.StringPtr(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppEdgeIPsType); ok { - edgeIPsOpt.Connectivity = core.StringPtr(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppTrafficType); ok { - opt.SetTrafficType(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppTLS); ok { - opt.SetTls(v.(string)) - } - - result, resp, err := cisClient.CreateRangeApp(opt) - if err != nil { - return fmt.Errorf("Failed to create range application: %v", resp) - } - d.SetId(convertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) - return resourceIBMCISRangeAppRead(d, meta) -} - -func resourceIBMCISRangeAppRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() - if err != nil { - return err - } - - rangeAppID, zoneID, crn, _ := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - opt := cisClient.NewGetRangeAppOptions(rangeAppID) - result, resp, err := cisClient.GetRangeApp(opt) - if err != nil { - return fmt.Errorf("Failed to read range application: %v", resp) - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisRangeAppID, result.Result.ID) - d.Set(cisRangeAppProtocol, result.Result.Protocol) - d.Set(cisRangeAppDNSType, result.Result.Dns.Type) - d.Set(cisRangeAppDNS, result.Result.Dns.Name) - d.Set(cisRangeAppOriginDirect, flattenStringList(result.Result.OriginDirect)) - d.Set(cisRangeAppProxyProtocol, result.Result.ProxyProtocol) - d.Set(cisRangeAppIPFirewall, result.Result.IpFirewall) - d.Set(cisRangeAppTrafficType, result.Result.TrafficType) - d.Set(cisRangeAppEdgeIPsType, result.Result.EdgeIps.Type) - d.Set(cisRangeAppEdgeIPsConnectivity, result.Result.EdgeIps.Connectivity) - d.Set(cisRangeAppTLS, result.Result.Tls) - d.Set(cisRangeAppCreatedOn, result.Result.CreatedOn.String()) - d.Set(cisRangeAppModifiedOn, result.Result.ModifiedOn.String()) - return nil -} - -func resourceIBMCISRangeAppUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() - if err != nil { - return err - } - - if d.HasChange(cisRangeAppOriginDirect) || - d.HasChange(cisRangeAppOriginDNS) || - d.HasChange(cisRangeAppOriginPort) || - d.HasChange(cisRangeAppIPFirewall) || - d.HasChange(cisRangeAppProxyProtocol) || - d.HasChange(cisRangeAppEdgeIPsType) || - d.HasChange(cisRangeAppEdgeIPsConnectivity) || - d.HasChange(cisRangeAppTLS) || - d.HasChange(cisRangeAppTrafficType) { - - rangeAppID, zoneID, crn, _ := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - protocol := d.Get(cisRangeAppProtocol).(string) - dns := d.Get(cisRangeAppDNS).(string) - dnsType := d.Get(cisRangeAppDNSType).(string) - - dnsOpt := &cisrangeappv1.RangeAppReqDns{ - Type: &dnsType, - Name: &dns, - } - - opt := cisClient.NewUpdateRangeAppOptions(rangeAppID, protocol, dnsOpt) - - if v, ok := d.GetOk(cisRangeAppOriginDirect); ok { - opt.SetOriginDirect(expandStringList(v.([]interface{}))) - } - if v, ok := d.GetOk(cisRangeAppOriginDNS); ok { - originDNSOpt := &cisrangeappv1.RangeAppReqOriginDns{ - Name: core.StringPtr(v.(string)), - } - opt.SetOriginDns(originDNSOpt) - } - if v, ok := d.GetOk(cisRangeAppOriginPort); ok { - opt.SetOriginPort(int64(v.(int))) - } - if v, ok := d.GetOkExists(cisRangeAppIPFirewall); ok { - opt.SetIpFirewall(v.(bool)) - } - if v, ok := d.GetOk(cisRangeAppProxyProtocol); ok { - opt.SetProxyProtocol(v.(string)) - } - edgeIPsOpt := &cisrangeappv1.RangeAppReqEdgeIps{ - Type: core.StringPtr(cisRangeAppEdgeIPsTypeDynamic), - Connectivity: core.StringPtr(cisRangeAppEdgeIPsConnectivityAll), - } - if v, ok := d.GetOk(cisRangeAppEdgeIPsType); ok { - edgeIPsOpt.Type = core.StringPtr(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppEdgeIPsType); ok { - edgeIPsOpt.Connectivity = core.StringPtr(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppTrafficType); ok { - opt.SetTrafficType(v.(string)) - } - if v, ok := d.GetOk(cisRangeAppTLS); ok { - opt.SetTls(v.(string)) - } - _, resp, err := cisClient.UpdateRangeApp(opt) - if err != nil { - return fmt.Errorf("Failed to update range application: %v", resp) - } - } - return resourceIBMCISRangeAppRead(d, meta) -} - -func resourceIBMCISRangeAppDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() - if err != nil { - return err - } - - rangeAppID, zoneID, cisID, _ := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(cisID) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewDeleteRangeAppOptions(rangeAppID) - _, resp, err := cisClient.DeleteRangeApp(opt) - if err != nil { - return fmt.Errorf("Failed to delete range application: %v", resp) - } - return nil -} - -func resourceIBMCISRangeAppExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() - if err != nil { - return false, err - } - rangeAppID, zoneID, cisID, _ := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(cisID) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetRangeAppOptions(rangeAppID) - _, resp, err := cisClient.GetRangeApp(opt) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - log.Println("range application is not found") - return false, nil - } - return false, fmt.Errorf("Failed to getting existing range application: %v", err) - } - return true, nil -} diff --git a/ibm/resource_ibm_cis_routing.go b/ibm/resource_ibm_cis_routing.go deleted file mode 100644 index 3f739f455..000000000 --- a/ibm/resource_ibm_cis_routing.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISRouting = "ibm_cis_routing" - cisRoutingSmartRouting = "smart_routing" -) - -func resourceIBMCISRouting() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISRoutingUpdate, - Read: resourceIBMCISRoutingRead, - Update: resourceIBMCISRoutingUpdate, - Delete: resourceIBMCISRoutingDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisRoutingSmartRouting: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Smart Routing value", - ValidateFunc: InvokeValidator(ibmCISRouting, cisRoutingSmartRouting), - }, - }, - } -} - -func resourceIBMCISRoutingValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - smartRoutingValues := "on, off" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisRoutingSmartRouting, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: smartRoutingValues}) - ibmCISRoutingValidator := ResourceValidator{ResourceName: ibmCISRouting, Schema: validateSchema} - return &ibmCISRoutingValidator -} - -func resourceIBMCISRoutingUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRoutingClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - if d.HasChange(cisRoutingSmartRouting) { - smartRoutingValue := d.Get(cisRoutingSmartRouting).(string) - opt := cisClient.NewUpdateSmartRoutingOptions() - opt.SetValue(smartRoutingValue) - _, response, err := cisClient.UpdateSmartRouting(opt) - if err != nil { - log.Printf("Update smart route setting failed: %v", response) - return err - } - } - - d.SetId(convertCisToTfTwoVar(zoneID, crn)) - return resourceIBMCISRoutingRead(d, meta) -} - -func resourceIBMCISRoutingRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRoutingClientSession() - if err != nil { - return err - } - zoneID, crn, err := convertTftoCisTwoVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewGetSmartRoutingOptions() - result, response, err := cisClient.GetSmartRouting(opt) - if err != nil { - log.Printf("Get smart route setting failed: %v", response) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisRoutingSmartRouting, *result.Result.Value) - return nil -} - -func resourceIBMCISRoutingDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_routing_test.go b/ibm/resource_ibm_cis_routing_test.go deleted file mode 100644 index 33386aa5d..000000000 --- a/ibm/resource_ibm_cis_routing_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisRouting_Basic(t *testing.T) { - name := "ibm_cis_routing." + "test" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisRoutingConfigBasic1("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "smart_routing", "on"), - ), - }, - { - Config: testAccCheckCisRoutingConfigBasic2("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "smart_routing", "off"), - ), - }, - }, - }) -} - -func TestAccIBMCisRouting_Import(t *testing.T) { - name := "ibm_cis_routing." + "test" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisRoutingConfigBasic2("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "smart_routing", "off"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckCisRoutingConfigBasic1(id string, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_routing" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - smart_routing = "on" - } -`, id) -} -func testAccCheckCisRoutingConfigBasic2(id string, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_routing" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - smart_routing = "off" - } -`, id) -} diff --git a/ibm/resource_ibm_cis_test.go b/ibm/resource_ibm_cis_test.go deleted file mode 100644 index 072585dc0..000000000 --- a/ibm/resource_ibm_cis_test.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" -) - -func TestAccIBMCisInstance_Basic(t *testing.T) { - t.Skip() - var cisInstanceOne string - testName := "test_acc" - name := "ibm_cis.cis" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCisInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCisInstance_basic(cisResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCisInstanceExists(name, &cisInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "internet-svcs"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "global"), - ), - }, - }, - }) -} - -func TestAccIBMCisInstance_CreateAfterManualDestroy(t *testing.T) { - //t.Parallel() - t.Skip() - var cisInstanceOne, cisInstanceTwo string - testName := "test_acc" - name := "ibm_cis.cis" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCisInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMCisInstance_basic(cisResourceGroup, testName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMCisInstanceExists(name, &cisInstanceOne), - testAccCisInstanceManuallyDelete(&cisInstanceOne), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: testAccCheckIBMCisInstance_basic(cisResourceGroup, testName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMCisInstanceExists(name, &cisInstanceTwo), - func(state *terraform.State) error { - if cisInstanceOne == cisInstanceTwo { - return fmt.Errorf("Cis instance id is unchanged even after we thought we deleted it ( %s )", cisInstanceTwo) - } - return nil - }, - ), - }, - }, - }) -} - -func TestAccIBMCisInstance_import(t *testing.T) { - t.Skip() - var cisInstanceOne string - serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_cis.cis" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCisInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCisInstance_basic(cisResourceGroup, serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCisInstanceExists(resourceName, &cisInstanceOne), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "internet-svcs"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "global"), - ), - }, - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes"}, - }, - }, - }) -} - -func testAccCheckIBMCisInstanceDestroy(s *terraform.State) error { - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cis" { - continue - } - - instanceID := rs.Primary.ID - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - _, response, err := rsConClient.GetResourceInstance(&rsInst) - - if err == nil { - return fmt.Errorf("Instance still exists: %s", rs.Primary.ID) - } else if strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) - } - } - return nil -} - -func testAccCisInstanceManuallyDelete(tfCisId *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _ = testAccCisInstanceManuallyDeleteUnwrapped(s, tfCisId) - return nil - } -} - -func testAccCisInstanceManuallyDeleteUnwrapped(s *terraform.State, tfCisId *string) error { - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instance := *tfCisId - var instanceId string - // if Id does not start with CRN, then zoneId/Pool/HealthCheckId passed. Extract InstanceId - if strings.HasPrefix(instance, "crn") { - instanceId = instance - } else { - _, instanceId, _ = convertTftoCisTwoVar(instance) - } - recursive := true - deleteReq := rc.DeleteResourceInstanceOptions{ - ID: &instanceId, - Recursive: &recursive, - } - response, err := rsConClient.DeleteResourceInstance(&deleteReq) - if err != nil { - return fmt.Errorf("Error deleting resource instance: %s %s", err, response) - } - - _ = &resource.StateChangeConf{ - Pending: []string{cisInstanceProgressStatus, cisInstanceInactiveStatus, cisInstanceSuccessStatus}, - Target: []string{cisInstanceRemovedStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceId, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return instance, cisInstanceSuccessStatus, nil - } - return nil, "", err - } - if *instance.State == cisInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed to delete: %v %s", instanceId, err, response) - } - return instance, *instance.State, nil - }, - Timeout: 90 * time.Second, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - if err != nil { - return fmt.Errorf( - "Error waiting for resource instance (%s) to be deleted: %s", instanceId, err) - } - return nil -} - -func testAccCheckIBMCisInstanceExists(n string, tfCisId *string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instanceID := rs.Primary.ID - - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - *tfCisId = "" - return nil - } - return fmt.Errorf("Error retrieving resource instance: %s %s", err, response) - } - if strings.Contains(*instance.State, "removed") { - *tfCisId = "" - return nil - } - - *tfCisId = instanceID - return nil - } -} - -func testAccCheckIBMCisInstance_basic(cisResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_cis" "cis" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - plan = "standard" - location = "global" - } - `, cisResourceGroup, name) -} diff --git a/ibm/resource_ibm_cis_tls_settings.go b/ibm/resource_ibm_cis_tls_settings.go deleted file mode 100644 index 124dc4373..000000000 --- a/ibm/resource_ibm_cis_tls_settings.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISTLSSettings = "ibm_cis_tls_settings" - cisTLSSettingsUniversalSSL = "universal_ssl" - cisTLSSettingsTLS12Only = "tls_1_2_only" - cisTLSSettingsTLS13 = "tls_1_3" - cisTLSSettingsMinTLSVersion = "min_tls_version" -) - -func resourceIBMCISTLSSettings() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Description: "CIS instance crn", - Required: true, - }, - cisDomainID: { - Type: schema.TypeString, - Description: "Associated CIS domain", - Required: true, - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisTLSSettingsUniversalSSL: { - Type: schema.TypeBool, - Description: "Universal SSL setting", - Optional: true, - Computed: true, - }, - cisTLSSettingsTLS13: { - Type: schema.TypeString, - Description: "TLS 1.3 setting", - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator(ibmCISTLSSettings, cisTLSSettingsTLS13), - DiffSuppressFunc: suppressTLS13Diff, - }, - cisTLSSettingsMinTLSVersion: { - Type: schema.TypeString, - Description: "Minimum version of TLS required", - Optional: true, - ValidateFunc: InvokeValidator(ibmCISTLSSettings, cisTLSSettingsMinTLSVersion), - Default: "1.1", - }, - }, - Create: resourceCISTLSSettingsUpdate, - Read: resourceCISTLSSettingsRead, - Update: resourceCISTLSSettingsUpdate, - Delete: resourceCISTLSSettingsDelete, - Importer: &schema.ResourceImporter{}, - } -} - -func resourceIBMCISTLSSettingsValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisTLSSettingsTLS13, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "on, off, zrt"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisTLSSettingsMinTLSVersion, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "1.1, 1.2, 1.3, 1.4"}) - ibmCISTLSSettingsResourceValidator := ResourceValidator{ - ResourceName: ibmCISTLSSettings, - Schema: validateSchema} - return &ibmCISTLSSettingsResourceValidator -} - -func resourceCISTLSSettingsUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - if d.HasChange(cisTLSSettingsTLS12Only) || - d.HasChange(cisTLSSettingsTLS13) || - d.HasChange(cisTLSSettingsUniversalSSL) || - d.HasChange(cisTLSSettingsMinTLSVersion) { - - // TLS 1.3 setting - if tls13, ok := d.GetOk(cisTLSSettingsTLS13); ok { - opt := cisClient.NewChangeTls13SettingOptions() - opt.SetValue(tls13.(string)) - _, resp, err := cisClient.ChangeTls13Setting(opt) - if err != nil { - log.Printf("Update TLS 1.3 setting Failed : %v\n", resp) - return err - } - } - - // Universal SSL setting - if universalSSL, ok := d.GetOkExists(cisTLSSettingsUniversalSSL); ok { - opt := cisClient.NewChangeUniversalCertificateSettingOptions() - opt.SetEnabled(universalSSL.(bool)) - resp, err := cisClient.ChangeUniversalCertificateSetting(opt) - if err != nil { - log.Printf("Update universal ssl setting Failed : %v\n", resp) - return err - } - } - - // Minimum TLS version - if minTLSVer, ok := d.GetOk(cisTLSSettingsMinTLSVersion); ok { - cisClient, err := meta.(ClientSession).CisDomainSettingsClientSession() - if err != nil { - return err - } - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - opt := cisClient.NewUpdateMinTlsVersionOptions() - opt.SetValue(minTLSVer.(string)) - _, resp, err := cisClient.UpdateMinTlsVersion(opt) - if err != nil { - log.Printf("Update minimum TLS version setting Failed : %v\n", resp) - return err - } - } - } - d.SetId(convertCisToTfTwoVar(zoneID, crn)) - return resourceCISTLSSettingsRead(d, meta) -} - -func resourceCISTLSSettingsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() - if err != nil { - return err - } - zoneID, crn, _ := convertTftoCisTwoVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneIdentifier = core.StringPtr(zoneID) - - // TLS 1.3 setting - tls13Result, resp, err := cisClient.GetTls13Setting(cisClient.NewGetTls13SettingOptions()) - if err != nil { - log.Printf("Get TLS 1.3 setting failed : %v\n", resp) - return err - } - - // Universal SSL setting - universalSSLResult, resp, err := cisClient.GetUniversalCertificateSetting( - cisClient.NewGetUniversalCertificateSettingOptions()) - if err != nil { - log.Printf("Update TLS 1.3 setting failed : %v\n", resp) - return err - } - - // Minumum TLS version setting - minTLSClient, err := meta.(ClientSession).CisDomainSettingsClientSession() - if err != nil { - return err - } - minTLSClient.Crn = core.StringPtr(crn) - minTLSClient.ZoneIdentifier = core.StringPtr(zoneID) - minTLSVerResult, resp, err := minTLSClient.GetMinTlsVersion( - minTLSClient.NewGetMinTlsVersionOptions()) - if err != nil { - log.Printf("Min TLS Version setting get request failed : %v", resp) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisTLSSettingsTLS13, tls13Result.Result.Value) - d.Set(cisTLSSettingsUniversalSSL, universalSSLResult.Result.Enabled) - d.Set(cisTLSSettingsMinTLSVersion, minTLSVerResult.Result.Value) - return nil -} - -func resourceCISTLSSettingsDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS resource - d.SetId("") - return nil -} - -func suppressTLS13Diff(k, old, new string, d *schema.ResourceData) bool { - // if we enable TLS 1.3, it gives zrt in output. - if "zrt" == old && new == "on" { - return true - } - return false -} diff --git a/ibm/resource_ibm_cis_waf_group.go b/ibm/resource_ibm_cis_waf_group.go deleted file mode 100644 index 78e1510ea..000000000 --- a/ibm/resource_ibm_cis_waf_group.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISWAFGroup = "ibm_cis_waf_group" - cisWAFGroupID = "group_id" - cisWAFGroupPackageID = "package_id" - cisWAFGroupMode = "mode" - cisWAFGroupName = "name" - cisWAFGroupRulesCount = "rules_count" - cisWAFGroupModifiedRulesCount = "modified_rules_count" - cisWAFGroupDesc = "description" -) - -func resourceIBMCISWAFGroup() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISWAFGroupUpdate, - Read: resourceIBMCISWAFGroupRead, - Update: resourceIBMCISWAFGroupUpdate, - Delete: resourceIBMCISWAFGroupDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFGroupPackageID: { - Type: schema.TypeString, - Required: true, - Description: "WAF Rule package id", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFGroupID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "WAF Rule group id", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFGroupMode: { - Type: schema.TypeString, - Required: true, - Description: "WAF Rule group mode on/off", - ValidateFunc: InvokeValidator(ibmCISWAFGroup, cisWAFGroupMode), - }, - cisWAFGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group name", - }, - cisWAFGroupDesc: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group description", - }, - cisWAFGroupRulesCount: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group rules count", - }, - cisWAFGroupModifiedRulesCount: { - Type: schema.TypeString, - Computed: true, - Description: "WAF Rule group modified rules count", - }, - }, - } -} - -func resourceIBMCISWAFGroupValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - mode := "on, off" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisWAFGroupMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: mode}) - ibmCISWAFGroupValidator := ResourceValidator{ResourceName: ibmCISWAFGroup, Schema: validateSchema} - return &ibmCISWAFGroupValidator -} - -func resourceIBMCISWAFGroupUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFGroupClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - packageID, _, _, _ := convertTfToCisThreeVar(d.Get(cisWAFGroupPackageID).(string)) - groupID := d.Get(cisWAFGroupID).(string) - - if d.HasChange(cisWAFGroupMode) { - mode := d.Get(cisWAFGroupMode).(string) - opt := cisClient.NewUpdateWafRuleGroupOptions(packageID, groupID) - opt.SetMode(mode) - _, response, err := cisClient.UpdateWafRuleGroup(opt) - if err != nil { - log.Printf("Update waf rule group mode failed: %v", response) - return err - } - } - d.SetId(convertCisToTfFourVar(groupID, packageID, zoneID, crn)) - return resourceIBMCISWAFGroupRead(d, meta) -} - -func resourceIBMCISWAFGroupRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFGroupClientSession() - if err != nil { - return err - } - groupID, packageID, zoneID, crn, err := convertTfToCisFourVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - opt := cisClient.NewGetWafRuleGroupOptions(packageID, groupID) - result, response, err := cisClient.GetWafRuleGroup(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("WAF group is not found!") - d.SetId("") - return nil - } - log.Printf("Get waf rule group setting failed: %v", response) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFGroupID, groupID) - d.Set(cisWAFGroupPackageID, result.Result.PackageID) - d.Set(cisWAFGroupMode, result.Result.Mode) - d.Set(cisWAFGroupName, result.Result.Name) - d.Set(cisWAFGroupDesc, result.Result.Description) - d.Set(cisWAFGroupModifiedRulesCount, result.Result.ModifiedRulesCount) - d.Set(cisWAFGroupRulesCount, result.Result.RulesCount) - return nil -} - -func resourceIBMCISWAFGroupDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS WAF Group resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_waf_group_test.go b/ibm/resource_ibm_cis_waf_group_test.go deleted file mode 100644 index ee03de864..000000000 --- a/ibm/resource_ibm_cis_waf_group_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCisWAFGroup_Basic(t *testing.T) { - name := "ibm_cis_waf_group." + "test" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisWAFGroupConfigBasic1("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "mode", "on"), - ), - }, - { - Config: testAccCheckCisWAFGroupConfigBasic2("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "mode", "off"), - ), - }, - { - Config: testAccCheckCisWAFGroupConfigBasic1("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "mode", "on"), - ), - }, - }, - }) -} - -func TestAccIBMCisWAFGroup_Import(t *testing.T) { - name := "ibm_cis_waf_group." + "test" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckCisWAFGroupConfigBasic2("test", cisDomainStatic), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "mode", "off"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckCisWAFGroupConfigBasic1(id string, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_waf_group" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - package_id = "c504870194831cd12c3fc0284f294abb" - group_id = "3d8fb0c18b5a6ba7682c80e94c7937b2" - mode = "on" - } -`, id) -} -func testAccCheckCisWAFGroupConfigBasic2(id string, cisDomainStatic string) string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` - resource "ibm_cis_waf_group" "%[1]s" { - cis_id = data.ibm_cis.cis.id - domain_id = data.ibm_cis_domain.cis_domain.domain_id - package_id = "c504870194831cd12c3fc0284f294abb" - group_id = "3d8fb0c18b5a6ba7682c80e94c7937b2" - mode = "off" - } -`, id) -} diff --git a/ibm/resource_ibm_cis_waf_package.go b/ibm/resource_ibm_cis_waf_package.go deleted file mode 100644 index 262f393a7..000000000 --- a/ibm/resource_ibm_cis_waf_package.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISWAFPackage = "ibm_cis_waf_package" - cisWAFPackageID = "package_id" - cisWAFPackageName = "name" - cisWAFPackageDescription = "description" - cisWAFPackageDetectionMode = "detection_mode" - cisWAFPackageSensitivity = "sensitivity" - cisWAFPackageActionMode = "action_mode" -) - -func resourceIBMCISWAFPackage() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISWAFPackageUpdate, - Read: resourceIBMCISWAFPackageRead, - Update: resourceIBMCISWAFPackageUpdate, - Delete: resourceIBMCISWAFPackageDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFPackageID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "WAF pakcage ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFPackageName: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage name", - }, - cisWAFPackageDetectionMode: { - Type: schema.TypeString, - Computed: true, - Description: "WAF pakcage detection mode", - }, - cisWAFPackageSensitivity: { - Type: schema.TypeString, - Required: true, - Description: "WAF pakcage sensitivity", - ValidateFunc: InvokeValidator( - ibmCISWAFPackage, cisWAFPackageSensitivity), - }, - cisWAFPackageActionMode: { - Type: schema.TypeString, - Required: true, - Description: "WAF pakcage action mode", - ValidateFunc: InvokeValidator( - ibmCISWAFPackage, cisWAFPackageActionMode), - }, - cisWAFPackageDescription: { - Type: schema.TypeString, - Computed: true, - Description: "WAF package description", - }, - }, - } -} - -func resourceIBMCISWAFPackageValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - sesitivity := "high, medium, low, off" - actionMode := "simulate, block, challenge" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisWAFPackageSensitivity, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: sesitivity}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisWAFPackageActionMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: actionMode}) - ibmCISWAFPackageValidator := ResourceValidator{ResourceName: ibmCISWAFPackage, Schema: validateSchema} - return &ibmCISWAFPackageValidator -} - -func resourceIBMCISWAFPackageUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFPackageClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - packageID, _, _, err := convertTfToCisThreeVar(d.Get(cisWAFPackageID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - - if d.HasChange(cisWAFPackageSensitivity) || - d.HasChange(cisWAFPackageActionMode) { - opt := cisClient.NewUpdateWafPackageOptions(packageID) - if v, ok := d.GetOk(cisWAFPackageSensitivity); ok { - opt.SetSensitivity(v.(string)) - } - if v, ok := d.GetOk(cisWAFPackageActionMode); ok { - opt.SetActionMode(v.(string)) - } - result, response, err := cisClient.UpdateWafPackage(opt) - if err != nil { - log.Printf("Update waf package setting failed: %v", response) - return err - } - d.SetId(convertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) - } - - return resourceIBMCISWAFPackageRead(d, meta) -} - -func resourceIBMCISWAFPackageRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFPackageClientSession() - if err != nil { - return err - } - packageID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - opt := cisClient.NewGetWafPackageOptions(packageID) - result, response, err := cisClient.GetWafPackage(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("WAF package is not found!") - d.SetId("") - return nil - } - log.Printf("Get waf package setting failed: %v", response) - return err - } - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFPackageID, result.Result.ID) - d.Set(cisWAFPackageName, result.Result.Name) - d.Set(cisWAFPackageDetectionMode, result.Result.DetectionMode) - d.Set(cisWAFPackageActionMode, result.Result.ActionMode) - d.Set(cisWAFPackageSensitivity, result.Result.Sensitivity) - d.Set(cisWAFPackageDescription, result.Result.Description) - return nil -} - -func resourceIBMCISWAFPackageDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS WAF Package resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cis_waf_rule.go b/ibm/resource_ibm_cis_waf_rule.go deleted file mode 100644 index 73ce49ae4..000000000 --- a/ibm/resource_ibm_cis_waf_rule.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCISWAFRule = "ibm_cis_waf_rule" - cisWAFRuleID = "rule_id" - cisWAFRuleDesc = "description" - cisWAFRulePriority = "priority" - cisWAFRulePackageID = "package_id" - cisWAFRuleGroup = "group" - cisWAFRuleGroupID = "id" - cisWAFRuleGroupName = "name" - cisWAFRuleMode = "mode" - cisWAFRuleModeOn = "on" - cisWAFRuleModeOff = "off" - cisWAFRuleAllowedModes = "allowed_modes" -) - -func resourceIBMCISWAFRule() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCISWAFRuleUpdate, - Read: resourceIBMCISWAFRuleRead, - Update: resourceIBMCISWAFRuleUpdate, - Delete: resourceIBMCISWAFRuleDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - cisID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Intance CRN", - }, - cisDomainID: { - Type: schema.TypeString, - Required: true, - Description: "CIS Domain ID", - DiffSuppressFunc: suppressDomainIDDiff, - }, - cisWAFRuleID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "CIS WAF Rule id", - }, - cisWAFRulePackageID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "CIS WAF Rule package id", - }, - cisWAFRuleMode: { - Type: schema.TypeString, - Required: true, - Description: "CIS WAF Rule mode", - ValidateFunc: InvokeValidator(ibmCISWAFRule, cisWAFRuleMode), - }, - cisWAFRuleDesc: { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF Rule descriptions", - }, - cisWAFRulePriority: { - Type: schema.TypeInt, - Computed: true, - Description: "CIS WAF Rule Priority", - }, - cisWAFRuleGroup: { - Type: schema.TypeList, - Computed: true, - Description: "CIS WAF Rule group", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - cisWAFRuleGroupID: { - Type: schema.TypeString, - Computed: true, - Description: "waf rule group id", - }, - cisWAFRuleGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "waf rule group name", - }, - }, - }, - }, - cisWAFRuleAllowedModes: { - Type: schema.TypeString, - Computed: true, - Description: "CIS WAF Rule allowed modes", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - } -} - -func resourceIBMCISWAFRuleValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - modes := "on, off, default, disable, simulate, block, challenge" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: cisWAFRuleMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: modes}) - ibmCISWAFRuleValidator := ResourceValidator{ResourceName: ibmCISWAFRule, Schema: validateSchema} - return &ibmCISWAFRuleValidator -} - -func resourceIBMCISWAFRuleUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFRuleClientSession() - if err != nil { - return err - } - - crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - ruleID := d.Get(cisWAFRuleID).(string) - packageID, _, _, _ := convertTfToCisThreeVar(d.Get(cisWAFRulePackageID).(string)) - - if d.HasChange(cisWAFRuleMode) { - mode := d.Get(cisWAFRuleMode).(string) - - getOpt := cisClient.NewGetWafRuleOptions(packageID, ruleID) - getResult, getResponse, err := cisClient.GetWafRule(getOpt) - if err != nil { - log.Printf("Get WAF rule setting failed: %v", getResponse) - return err - } - getMode := *getResult.Result.Mode - updateOpt := cisClient.NewUpdateWafRuleOptions(packageID, ruleID) - - // Mode differs based on OWASP and CIS - if getMode == cisWAFRuleModeOn || getMode == cisWAFRuleModeOff { - - owaspOpt, _ := cisClient.NewWafRuleBodyOwasp(mode) - updateOpt.SetOwasp(owaspOpt) - - } else { - - cisOpt, _ := cisClient.NewWafRuleBodyCis(mode) - updateOpt.SetCis(cisOpt) - - } - _, response, err := cisClient.UpdateWafRule(updateOpt) - if err != nil { - log.Printf("Update WAF rule setting failed: %v", response) - return err - } - } - - d.SetId(convertCisToTfFourVar(ruleID, packageID, zoneID, crn)) - return resourceIBMCISWAFRuleRead(d, meta) -} - -func resourceIBMCISWAFRuleRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisWAFRuleClientSession() - if err != nil { - return err - } - ruleID, packageID, zoneID, crn, err := convertTfToCisFourVar(d.Id()) - cisClient.Crn = core.StringPtr(crn) - cisClient.ZoneID = core.StringPtr(zoneID) - opt := cisClient.NewGetWafRuleOptions(packageID, ruleID) - result, response, err := cisClient.GetWafRule(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("WAF Rule is not found!") - d.SetId("") - return nil - } - log.Printf("Get waf rule setting failed: %v", response) - return err - } - groups := []interface{}{} - group := map[string]interface{}{} - group[cisWAFRuleGroupID] = *result.Result.Group.ID - group[cisWAFRuleGroupName] = *result.Result.Group.Name - groups = append(groups, group) - - d.Set(cisID, crn) - d.Set(cisDomainID, zoneID) - d.Set(cisWAFRuleID, ruleID) - d.Set(cisWAFRulePackageID, packageID) - d.Set(cisWAFRuleDesc, *result.Result.Description) - d.Set(cisWAFRulePriority, *result.Result.Priority) - d.Set(cisWAFRuleGroup, groups) - d.Set(cisWAFRuleMode, *result.Result.Mode) - d.Set(cisWAFRuleAllowedModes, flattenStringList(result.Result.AllowedModes)) - return nil -} - -func resourceIBMCISWAFRuleDelete(d *schema.ResourceData, meta interface{}) error { - // Nothing to delete on CIS WAF rule resource - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_cm_catalog.go b/ibm/resource_ibm_cm_catalog.go deleted file mode 100644 index a7c65920d..000000000 --- a/ibm/resource_ibm_cm_catalog.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func resourceIBMCmCatalog() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCmCatalogCreate, - Read: resourceIBMCmCatalogRead, - Delete: resourceIBMCmCatalogDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: "offering", - Description: "Kind of catalog, offering or vpe.", - }, - "label": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Display Name in the requested language.", - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Description in the requested language.", - }, - "catalog_icon_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "URL for an icon associated with this catalog.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Description: "List of tags associated with this catalog.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url for this specific catalog.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "CRN associated with the catalog.", - }, - "offerings_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL path to offerings.", - }, - "resource_group_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - ForceNew: true, - Optional: true, - Description: "Resource Group ID", - }, - }, - } -} - -func resourceIBMCmCatalogCreate(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - createCatalogOptions := &catalogmanagementv1.CreateCatalogOptions{} - - if _, ok := d.GetOk("label"); ok { - createCatalogOptions.SetLabel(d.Get("label").(string)) - } - if _, ok := d.GetOk("short_description"); ok { - createCatalogOptions.SetShortDescription(d.Get("short_description").(string)) - } - if _, ok := d.GetOk("catalog_icon_url"); ok { - createCatalogOptions.SetCatalogIconURL(d.Get("catalog_icon_url").(string)) - } - if _, ok := d.GetOk("tags"); ok { - createCatalogOptions.SetTags(d.Get("tags").([]string)) - } - if _, ok := d.GetOk("kind"); ok { - createCatalogOptions.SetKind(d.Get("kind").(string)) - } - if _, ok := d.GetOk("resource_group_id"); ok { - createCatalogOptions.SetResourceGroupID(d.Get("resource_group_id").(string)) - } - - catalog, response, err := catalogManagementClient.CreateCatalog(createCatalogOptions) - if err != nil { - log.Printf("[DEBUG] CreateCatalog failed %s\n%s", err, response) - return err - } - - d.SetId(*catalog.ID) - - return resourceIBMCmCatalogRead(d, meta) -} - -func resourceIBMCmCatalogRead(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - log.Printf("[DEBUG] client is a nil pointer: %v\n", catalogManagementClient == nil) - - getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} - - getCatalogOptions.SetCatalogIdentifier(d.Id()) - - catalog, response, err := catalogManagementClient.GetCatalog(getCatalogOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetCatalog failed %s\n%s", err, response) - return err - } - if err = d.Set("label", catalog.Label); err != nil { - return fmt.Errorf("Error setting label: %s", err) - } - if err = d.Set("short_description", catalog.ShortDescription); err != nil { - return fmt.Errorf("Error setting short_description: %s", err) - } - if err = d.Set("catalog_icon_url", catalog.CatalogIconURL); err != nil { - return fmt.Errorf("Error setting catalog_icon_url: %s", err) - } - if catalog.Tags != nil { - if err = d.Set("tags", catalog.Tags); err != nil { - return fmt.Errorf("Error setting tags: %s", err) - } - } - if err = d.Set("url", catalog.URL); err != nil { - return fmt.Errorf("Error setting url: %s", err) - } - if err = d.Set("crn", catalog.CRN); err != nil { - return fmt.Errorf("Error setting crn: %s", err) - } - if err = d.Set("offerings_url", catalog.OfferingsURL); err != nil { - return fmt.Errorf("Error setting offerings_url: %s", err) - } - if err = d.Set("kind", catalog.Kind); err != nil { - return fmt.Errorf("Error setting kind: %s", err) - } - if err = d.Set("resource_group_id", catalog.ResourceGroupID); err != nil { - return fmt.Errorf("Error setting resource_group_id: %s", err) - } - - return nil -} - -func resourceIBMCmCatalogDelete(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - deleteCatalogOptions := &catalogmanagementv1.DeleteCatalogOptions{} - - deleteCatalogOptions.SetCatalogIdentifier(d.Id()) - - response, err := catalogManagementClient.DeleteCatalog(deleteCatalogOptions) - if err != nil { - log.Printf("[DEBUG] DeleteCatalog failed %s\n%s", err, response) - return err - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_cm_catalog_test.go b/ibm/resource_ibm_cm_catalog_test.go deleted file mode 100644 index 7dfd77e87..000000000 --- a/ibm/resource_ibm_cm_catalog_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func TestAccIBMCmCatalog(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCmCatalogDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmCatalogConfig(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCmCatalogExists("ibm_cm_catalog.cm_catalog"), - resource.TestCheckResourceAttrSet("ibm_cm_catalog.cm_catalog", "label"), - resource.TestCheckResourceAttrSet("ibm_cm_catalog.cm_catalog", "resource_group_id"), - ), - }, - resource.TestStep{ - ResourceName: "ibm_cm_catalog.cm_catalog", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckIBMCmCatalogConfig() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_catalog" - short_description = "testing terraform provider with catalog" - } - `) -} - -func testAccCheckIBMCmCatalogExists(n string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} - - getCatalogOptions.SetCatalogIdentifier(rs.Primary.ID) - - _, response, err := catalogManagementClient.GetCatalog(getCatalogOptions) - if err != nil { - if response.StatusCode == 404 { - return nil - } - return err - } - - return nil - } -} - -func testAccCheckIBMCmCatalogDestroy(s *terraform.State) error { - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cm_catalog" { - continue - } - - getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} - - getCatalogOptions.SetCatalogIdentifier(rs.Primary.ID) - - // Try to find the key - _, response, err := catalogManagementClient.GetCatalog(getCatalogOptions) - - if err == nil { - return fmt.Errorf("cm_catalog still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 403 { - return fmt.Errorf("Error checking for cm_catalog (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_cm_offering.go b/ibm/resource_ibm_cm_offering.go deleted file mode 100644 index 11dc914e6..000000000 --- a/ibm/resource_ibm_cm_offering.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func resourceIBMCmOffering() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCmOfferingCreate, - Read: resourceIBMCmOfferingRead, - Delete: resourceIBMCmOfferingDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "offering_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The id of the catalog containing this offering.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The url for this specific offering.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn for this specific offering.", - }, - "label": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Display Name in the requested language.", - ForceNew: true, - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The programmatic name of this offering.", - }, - "offering_icon_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL for an icon associated with this offering.", - }, - "offering_docs_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL for an additional docs with this offering.", - }, - "offering_support_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "URL to be displayed in the Consumption UI for getting support on this offering.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Description: "List of tags associated with this catalog.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Short description in the requested language.", - }, - "long_description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Long description in the requested language.", - }, - "permit_request_ibm_public_publish": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Is it permitted to request publishing to IBM or Public.", - }, - "ibm_publish_approved": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if this offering has been approved for use by all IBMers.", - }, - "public_publish_approved": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if this offering has been approved for use by all IBM Cloud users.", - }, - "public_original_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The original offering CRN that this publish entry came from.", - }, - "publish_public_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The crn of the public catalog entry of this offering.", - }, - "portal_approval_record": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The portal's approval record ID.", - }, - "portal_ui_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The portal UI URL.", - }, - "catalog_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The id of the catalog containing this offering.", - }, - "catalog_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the catalog.", - }, - "disclaimer": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A disclaimer for this offering.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Computed: true, - Description: "Determine if this offering should be displayed in the Consumption UI.", - }, - "repo_info": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Repository info for offerings.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "token": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Token for private repos.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Public or enterprise GitHub.", - }, - }, - }, - }, - }, - } -} - -func resourceIBMCmOfferingCreate(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - createOfferingOptions := catalogManagementClient.NewCreateOfferingOptions(d.Get("catalog_id").(string)) - - if _, ok := d.GetOk("label"); ok { - createOfferingOptions.SetLabel(d.Get("label").(string)) - } - if _, ok := d.GetOk("offering_icon_url"); ok { - createOfferingOptions.SetOfferingIconURL(d.Get("offering_icon_url").(string)) - } - if _, ok := d.GetOk("offering_docs_url"); ok { - createOfferingOptions.SetOfferingDocsURL(d.Get("offering_docs_url").(string)) - } - if _, ok := d.GetOk("offering_support_url"); ok { - createOfferingOptions.SetOfferingSupportURL(d.Get("offering_support_url").(string)) - } - if tags, ok := d.GetOk("tags"); ok { - list := expandStringList(tags.([]interface{})) - createOfferingOptions.SetTags(list) - - } - - offering, response, err := catalogManagementClient.CreateOffering(createOfferingOptions) - if err != nil { - log.Printf("[DEBUG] CreateOffering failed %s\n%s", err, response) - return err - } - - d.SetId(*offering.ID) - - return resourceIBMCmOfferingRead(d, meta) -} - -func resourceIBMCmOfferingRead(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} - - getOfferingOptions.SetCatalogIdentifier(d.Get("catalog_id").(string)) - getOfferingOptions.SetOfferingID(d.Id()) - - offering, response, err := catalogManagementClient.GetOffering(getOfferingOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetOffering failed %s\n%s", err, response) - return err - } - if err = d.Set("url", offering.URL); err != nil { - return fmt.Errorf("Error setting url: %s", err) - } - if err = d.Set("crn", offering.CRN); err != nil { - return fmt.Errorf("Error setting crn: %s", err) - } - if err = d.Set("label", offering.Label); err != nil { - return fmt.Errorf("Error setting label: %s", err) - } - if err = d.Set("name", offering.Name); err != nil { - return fmt.Errorf("Error setting name: %s", err) - } - if err = d.Set("offering_icon_url", offering.OfferingIconURL); err != nil { - return fmt.Errorf("Error setting offering_icon_url: %s", err) - } - if err = d.Set("offering_docs_url", offering.OfferingDocsURL); err != nil { - return fmt.Errorf("Error setting offering_docs_url: %s", err) - } - if err = d.Set("offering_support_url", offering.OfferingSupportURL); err != nil { - return fmt.Errorf("Error setting offering_support_url: %s", err) - } - if err = d.Set("short_description", offering.ShortDescription); err != nil { - return fmt.Errorf("Error setting short_description: %s", err) - } - if err = d.Set("long_description", offering.LongDescription); err != nil { - return fmt.Errorf("Error setting long_description: %s", err) - } - if err = d.Set("permit_request_ibm_public_publish", offering.PermitRequestIBMPublicPublish); err != nil { - return fmt.Errorf("Error setting permit_request_ibm_public_publish: %s", err) - } - if err = d.Set("ibm_publish_approved", offering.IBMPublishApproved); err != nil { - return fmt.Errorf("Error setting ibm_publish_approved: %s", err) - } - if err = d.Set("public_publish_approved", offering.PublicPublishApproved); err != nil { - return fmt.Errorf("Error setting public_publish_approved: %s", err) - } - if err = d.Set("public_original_crn", offering.PublicOriginalCRN); err != nil { - return fmt.Errorf("Error setting public_original_crn: %s", err) - } - if err = d.Set("publish_public_crn", offering.PublishPublicCRN); err != nil { - return fmt.Errorf("Error setting publish_public_crn: %s", err) - } - if err = d.Set("portal_approval_record", offering.PortalApprovalRecord); err != nil { - return fmt.Errorf("Error setting portal_approval_record: %s", err) - } - if err = d.Set("portal_ui_url", offering.PortalUIURL); err != nil { - return fmt.Errorf("Error setting portal_ui_url: %s", err) - } - if err = d.Set("catalog_id", offering.CatalogID); err != nil { - return fmt.Errorf("Error setting catalog_id: %s", err) - } - if err = d.Set("catalog_name", offering.CatalogName); err != nil { - return fmt.Errorf("Error setting catalog_name: %s", err) - } - if err = d.Set("disclaimer", offering.Disclaimer); err != nil { - return fmt.Errorf("Error setting disclaimer: %s", err) - } - if err = d.Set("hidden", offering.Hidden); err != nil { - return fmt.Errorf("Error setting hidden: %s", err) - } - if offering.RepoInfo != nil { - repoInfoMap := resourceIBMCmOfferingRepoInfoToMap(*offering.RepoInfo) - if err = d.Set("repo_info", []map[string]interface{}{repoInfoMap}); err != nil { - return fmt.Errorf("Error setting repo_info: %s", err) - } - } - - return nil -} - -func resourceIBMCmOfferingRepoInfoToMap(repoInfo catalogmanagementv1.RepoInfo) map[string]interface{} { - repoInfoMap := map[string]interface{}{} - - repoInfoMap["token"] = repoInfo.Token - repoInfoMap["type"] = repoInfo.Type - - return repoInfoMap -} - -func resourceIBMCmOfferingDelete(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - deleteOfferingOptions := &catalogmanagementv1.DeleteOfferingOptions{} - - deleteOfferingOptions.SetCatalogIdentifier(d.Get("catalog_id").(string)) - deleteOfferingOptions.SetOfferingID(d.Id()) - - response, err := catalogManagementClient.DeleteOffering(deleteOfferingOptions) - if err != nil { - log.Printf("[DEBUG] DeleteOfferingWithContext failed %s\n%s", err, response) - return err - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_cm_offering_test.go b/ibm/resource_ibm_cm_offering_test.go deleted file mode 100644 index f7583bf98..000000000 --- a/ibm/resource_ibm_cm_offering_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func TestAccIBMCmOffering(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCmOfferingDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmOfferingConfig(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCmOfferingExists("ibm_cm_offering.cm_offering"), - resource.TestCheckResourceAttrSet("ibm_cm_offering.cm_offering", "label"), - ), - }, - }, - }) -} - -func testAccCheckIBMCmOfferingConfig() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_offering_catalog" - short_description = "testing terraform provider with catalog" - } - - resource "ibm_cm_offering" "cm_offering" { - catalog_id = ibm_cm_catalog.cm_catalog.id - label = "tf_test_offering" - tags = ["dev_ops", "target_roks", "operator"] - } - - data "ibm_cm_offering" "cm_offering_data" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - offering_id = ibm_cm_offering.cm_offering.id - } - `) -} - -func testAccCheckIBMCmOfferingExists(n string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} - - getOfferingOptions.SetCatalogIdentifier(rs.Primary.Attributes["catalog_id"]) - getOfferingOptions.SetOfferingID(rs.Primary.ID) - - _, _, err = catalogManagementClient.GetOffering(getOfferingOptions) - if err != nil { - return err - } - - return nil - } -} - -func testAccCheckIBMCmOfferingDestroy(s *terraform.State) error { - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cm_offering" { - continue - } - - getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} - - getOfferingOptions.SetCatalogIdentifier(rs.Primary.Attributes["catalog_id"]) - getOfferingOptions.SetOfferingID(rs.Primary.ID) - - // Try to find the key - _, response, err := catalogManagementClient.GetOffering(getOfferingOptions) - - if err == nil { - return fmt.Errorf("cm_offering still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 403 { - return fmt.Errorf("Error checking for cm_offering (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_cm_version.go b/ibm/resource_ibm_cm_version.go deleted file mode 100644 index 2a879e704..000000000 --- a/ibm/resource_ibm_cm_version.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func resourceIBMCmVersion() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMCmVersionCreate, - Read: resourceIBMCmVersionRead, - Delete: resourceIBMCmVersionDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "catalog_identifier": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Catalog identifier.", - }, - "offering_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Offering identification.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Description: "Tags array.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "target_kinds": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Description: "Target kinds. Current valid values are 'iks', 'roks', 'vcenter', and 'terraform'.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "content": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "byte array representing the content to be imported. Only supported for OVA images at this time.", - }, - "zipurl": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "URL path to zip location. If not specified, must provide content in the body of this call.", - }, - "target_version": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The semver value for this new version, if not found in the zip url package content.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version's CRN.", - }, - "version": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Version of content type.", - }, - "sha": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "hash of the content.", - }, - "created": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time this version was created.", - }, - "updated": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time this version was last updated.", - }, - "catalog_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Catalog ID.", - }, - "kind_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Kind ID.", - }, - "repo_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Content's repo URL.", - }, - "source_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Content's source URL (e.g git repo).", - }, - "tgz_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "File used to on-board this version.", - }, - }, - } -} - -func resourceIBMCmVersionCreate(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - importOfferingVersionOptions := catalogManagementClient.NewImportOfferingVersionOptions(d.Get("catalog_identifier").(string), d.Get("offering_id").(string)) - - if _, ok := d.GetOk("tags"); ok { - importOfferingVersionOptions.SetTags(d.Get("tags").([]string)) - } - if _, ok := d.GetOk("target_kinds"); ok { - list := expandStringList(d.Get("target_kinds").([]interface{})) - importOfferingVersionOptions.SetTargetKinds(list) - - } - if _, ok := d.GetOk("content"); ok { - importOfferingVersionOptions.SetContent([]byte(d.Get("content").(string))) - } - if _, ok := d.GetOk("zipurl"); ok { - importOfferingVersionOptions.SetZipurl(d.Get("zipurl").(string)) - } - if _, ok := d.GetOk("target_version"); ok { - importOfferingVersionOptions.SetTargetVersion(d.Get("target_version").(string)) - } - - offering, response, err := catalogManagementClient.ImportOfferingVersion(importOfferingVersionOptions) - - if err != nil { - log.Printf("[DEBUG] ImportOfferingVersion failed %s\n%s", err, response) - return err - } - - versionLocator := *offering.Kinds[0].Versions[0].VersionLocator - - d.SetId(versionLocator) - - return resourceIBMCmVersionRead(d, meta) -} - -func resourceIBMCmVersionRead(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - getVersionOptions := &catalogmanagementv1.GetVersionOptions{} - - getVersionOptions.SetVersionLocID(d.Id()) - - offering, response, err := catalogManagementClient.GetVersion(getVersionOptions) - version := offering.Kinds[0].Versions[0] - - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetVersion failed %s\n%s", err, response) - return err - } - - if err = d.Set("crn", version.CRN); err != nil { - return fmt.Errorf("Error setting crn: %s", err) - } - if err = d.Set("version", version.Version); err != nil { - return fmt.Errorf("Error setting version: %s", err) - } - if err = d.Set("sha", version.Sha); err != nil { - return fmt.Errorf("Error setting sha: %s", err) - } - if err = d.Set("created", version.Created.String()); err != nil { - return fmt.Errorf("Error setting created: %s", err) - } - if err = d.Set("updated", version.Updated.String()); err != nil { - return fmt.Errorf("Error setting updated: %s", err) - } - if err = d.Set("catalog_id", version.CatalogID); err != nil { - return fmt.Errorf("Error setting catalog_id: %s", err) - } - if err = d.Set("kind_id", version.KindID); err != nil { - return fmt.Errorf("Error setting kind_id: %s", err) - } - if err = d.Set("repo_url", version.RepoURL); err != nil { - return fmt.Errorf("Error setting repo_url: %s", err) - } - if err = d.Set("source_url", version.SourceURL); err != nil { - return fmt.Errorf("Error setting source_url: %s", err) - } - if err = d.Set("tgz_url", version.TgzURL); err != nil { - return fmt.Errorf("Error setting tgz_url: %s", err) - } - - return nil -} - -func resourceIBMCmVersionDelete(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - deleteVersionOptions := &catalogmanagementv1.DeleteVersionOptions{} - deleteVersionOptions.SetVersionLocID(d.Id()) - - response, err := catalogManagementClient.DeleteVersion(deleteVersionOptions) - if err != nil { - log.Printf("[DEBUG] DeleteVersion failed %s\n%s", err, response) - return err - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_cm_version_test.go b/ibm/resource_ibm_cm_version_test.go deleted file mode 100644 index c9b820d4a..000000000 --- a/ibm/resource_ibm_cm_version_test.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" -) - -func TestAccIBMCmVersion(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCmVersionDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCmVersionConfig(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCmVersionExists("ibm_cm_version.cm_version"), - resource.TestCheckResourceAttrSet("ibm_cm_version.cm_version", "repo_url"), - ), - }, - }, - }) -} - -func testAccCheckIBMCmVersionConfig() string { - return fmt.Sprintf(` - - resource "ibm_cm_catalog" "cm_catalog" { - label = "tf_test_version_catalog" - short_description = "testing terraform provider with catalog" - } - - resource "ibm_cm_offering" "cm_offering" { - catalog_id = ibm_cm_catalog.cm_catalog.id - label = "tf_test_offering" - tags = ["dev_ops", "target_roks", "operator"] - } - - resource "ibm_cm_version" "cm_version" { - catalog_identifier = ibm_cm_catalog.cm_catalog.id - offering_id = ibm_cm_offering.cm_offering.id - zipurl = "https://raw.githubusercontent.com/operator-framework/community-operators/master/community-operators/cockroachdb/5.0.3/manifests/cockroachdb.clusterserviceversion.yaml" - } - `) -} - -func testAccCheckIBMCmVersionExists(n string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - - getVersionOptions := &catalogmanagementv1.GetVersionOptions{} - - getVersionOptions.SetVersionLocID(rs.Primary.ID) - - _, _, err = catalogManagementClient.GetVersion(getVersionOptions) - if err != nil { - return err - } - return nil - } -} - -func testAccCheckIBMCmVersionDestroy(s *terraform.State) error { - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_cm_version" { - continue - } - - getVersionOptions := &catalogmanagementv1.GetVersionOptions{} - - getVersionOptions.SetVersionLocID(rs.Primary.ID) - - // Try to find the key - _, response, err := catalogManagementClient.GetVersion(getVersionOptions) - - if err == nil { - return fmt.Errorf("cm_version still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 403 { - return fmt.Errorf("Error checking for cm_version (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_container_storage_attachment_test.go b/ibm/resource_ibm_container_storage_attachment_test.go deleted file mode 100644 index 9a27e1c9f..000000000 --- a/ibm/resource_ibm_container_storage_attachment_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMContainerVpcClusterWorkerVolumeAttachment_Basic(t *testing.T) { - clusterName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - randint := acctest.RandIntRange(10, 100) - vpc := fmt.Sprintf("terraformvpc-%d", randint) - subnet := fmt.Sprintf("terraformsubnet-%d", randint) - flavor := "bx2.16x64" - zone := "us-south" - workerCount := "1" - volumeName := fmt.Sprintf("terraformvpcvol-%d", randint) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMContainerVpcWorkerStorageDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerVpcClusterWorkerVolumeAttach_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_storage_attachment.volume_attach", "status", "attached"), - ), - }, - }, - }) -} - -func testAccCheckIBMContainerVpcClusterWorkerVolumeAttach_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName string) string { - return fmt.Sprintf(` - provider "ibm" { - region ="us-south" - } - data "ibm_resource_group" "resource_group" { - is_default = "true" - } - resource "ibm_is_vpc" "vpc" { - name = "%s" - } - resource "ibm_is_subnet" "subnet" { - name = "%s" - vpc = ibm_is_vpc.vpc.id - zone = "us-south-1" - total_ipv4_address_count = 256 - } - - resource "ibm_container_vpc_cluster" "cluster" { - name = "%s" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - wait_till = "OneWorkerNodeReady" - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - subnet_id = ibm_is_subnet.subnet.id - name = "us-south-1" - } - worker_labels = { - "test" = "test-default-pool" - "test1" = "test-default-pool1" - "test2" = "test-default-pool2" - } - - } - - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "10iops-tier" - zone = "us-south-1" - # capacity= 200 - } - - data "ibm_container_vpc_cluster" "cluster" { - name = ibm_container_vpc_cluster.cluster.id - } - - resource "ibm_container_storage_attachment" "volume_attach"{ - volume = ibm_is_volume.storage.id - cluster = ibm_container_vpc_cluster.cluster.id - worker = data.ibm_container_vpc_cluster.cluster.workers[0] - }`, vpc, subnet, clusterName, volumeName) -} - -func testAccCheckIBMContainerVpcWorkerStorageDestroy(s *terraform.State) error { - - wpClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - workersAPI := wpClient.Workers() - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_container_vpc_worker_storgae" { - continue - } - - targetEnv := getVpcClusterTargetHeaderTestACC() - // Try to find the key - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - clusterNameorID := parts[0] - workerID := parts[1] - volumeAttachmentID := parts[2] - - _, attchmentErr := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, targetEnv) - - if attchmentErr == nil { - return fmt.Errorf("Volume attachment still exists: %s", rs.Primary.ID) - } else if !strings.Contains(attchmentErr.Error(), "404") { - return fmt.Errorf("Error waiting for volume attachment (%s) to be destroyed: %s", rs.Primary.ID, attchmentErr) - } - } - - return nil -} diff --git a/ibm/resource_ibm_container_vpc_cluster_test.go b/ibm/resource_ibm_container_vpc_cluster_test.go deleted file mode 100644 index a7d0feb9b..000000000 --- a/ibm/resource_ibm_container_vpc_cluster_test.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - bluemix "github.com/IBM-Cloud/bluemix-go" - v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" - "github.com/IBM-Cloud/bluemix-go/session" -) - -func TestAccIBMContainerVpcClusterBasic(t *testing.T) { - name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) - var conf *v2.ClusterInfo - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerVpcClusterBasic(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "name", name), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "worker_count", "1"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "flavor", "cx2.2x4"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "zones.#", "1"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "worker_labels.%", "3"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "kms_config.#", "1"), - ), - }, - { - Config: testAccCheckIBMContainerVpcClusterUpdate(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "name", name), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "worker_count", "1"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "flavor", "cx2.2x4"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "zones.#", "2"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "worker_labels.%", "2"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "kms_config.#", "1"), - ), - }, - { - ResourceName: "ibm_container_vpc_cluster.cluster", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_till", "update_all_workers", "kms_config", "force_delete_storage", "wait_for_worker_update"}, - }, - }, - }) -} -func TestAccIBMContainerOpenshiftClusterBasic(t *testing.T) { - name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) - openshiftFlavour := "bx2.16x64" - openShiftworkerCount := "2" - var conf *v2.ClusterInfo - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerOcpClusterBasic(name, openshiftFlavour, openShiftworkerCount), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "name", name), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "worker_count", openShiftworkerCount), - resource.TestCheckResourceAttr( - "ibm_container_vpc_cluster.cluster", "flavor", openshiftFlavour), - ), - }, - }, - }) -} -func testAccCheckIBMContainerVpcClusterDestroy(s *terraform.State) error { - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_container_vpc_cluster" { - continue - } - - targetEnv := getVpcClusterTargetHeaderTestACC() - // Try to find the key - _, err := csClient.Clusters().GetCluster(rs.Primary.ID, targetEnv) - - if err == nil { - return fmt.Errorf("Cluster still exists: %s", rs.Primary.ID) - } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} -func testAccCheckIBMContainerVpcExists(n string, conf *v2.ClusterInfo) resource.TestCheckFunc { - - return func(s *terraform.State) error { - - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_container_vpc_cluster" { - continue - } - - targetEnv := getVpcClusterTargetHeaderTestACC() - - cls, err := csClient.Clusters().GetCluster(rs.Primary.ID, targetEnv) - - if err != nil && !strings.Contains(err.Error(), "404") { - return err - } - - conf = cls - - } - return nil - } -} -func getVpcClusterTargetHeaderTestACC() v2.ClusterTargetHeader { - c := new(bluemix.Config) - sess, err := session.New(c) - if err != nil { - log.Fatal(err) - } - resourceGroup := sess.Config.ResourceGroup - targetEnv := v2.ClusterTargetHeader{ - ResourceGroup: resourceGroup, - } - return targetEnv -} -func testAccCheckIBMContainerVpcClusterBasic(name string) string { - return fmt.Sprintf(` -provider "ibm" { - region ="eu-de" -} -data "ibm_resource_group" "resource_group" { - is_default = "true" - //name = "Default" -} -resource "ibm_is_vpc" "vpc" { - name = "%[1]s" -} -resource "ibm_is_subnet" "subnet" { - name = "%[1]s" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-1" - total_ipv4_address_count = 256 -} -resource "ibm_resource_instance" "kms_instance" { - name = "%[1]s" - service = "kms" - plan = "tiered-pricing" - location = "eu-de" -} - -resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kms_instance.guid - key_name = "%[1]s" - standard_key = false - force_delete = true -} -resource "ibm_container_vpc_cluster" "cluster" { - name = "%[1]s" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - wait_till = "OneWorkerNodeReady" - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - subnet_id = ibm_is_subnet.subnet.id - name = "eu-de-1" - } - kms_config { - instance_id = ibm_resource_instance.kms_instance.guid - crk_id = ibm_kms_key.test.key_id - private_endpoint = false - } - worker_labels = { - "test" = "test-default-pool" - "test1" = "test-default-pool1" - "test2" = "test-default-pool2" - } - - }`, name) -} -func testAccCheckIBMContainerVpcClusterUpdate(name string) string { - return fmt.Sprintf(` -provider "ibm" { - region ="eu-de" -} -data "ibm_resource_group" "resource_group" { - is_default = "true" -} -resource "ibm_is_vpc" "vpc" { - name = "%[1]s" -} -resource "ibm_is_subnet" "subnet" { - name = "%[1]s" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-1" - total_ipv4_address_count = 256 -} -resource "ibm_is_subnet" "subnet2" { - name = "%[1]s-2" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-2" - total_ipv4_address_count = 256 -} -resource "ibm_resource_instance" "kms_instance" { - name = "%[1]s" - service = "kms" - plan = "tiered-pricing" - location = "eu-de" -} - -resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kms_instance.guid - key_name = "%[1]s" - standard_key = false - force_delete = true -} -resource "ibm_container_vpc_cluster" "cluster" { - name = "%[1]s" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - wait_till = "OneWorkerNodeReady" - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - subnet_id = ibm_is_subnet.subnet.id - name = "eu-de-1" - } - zones { - subnet_id = ibm_is_subnet.subnet2.id - name = "eu-de-2" - } - kms_config { - instance_id = ibm_resource_instance.kms_instance.guid - crk_id = ibm_kms_key.test.key_id - private_endpoint = false - } - worker_labels = { - "test" = "test-default-pool" - "test1" = "test-default-pool1" - } - - }`, name) -} -func testAccCheckIBMContainerOcpClusterBasic(name, openshiftFlavour, openShiftworkerCount string) string { - return fmt.Sprintf(` -provider "ibm" { - region="eu-de" -} -data "ibm_resource_group" "resource_group" { - is_default = "true" -} -resource "ibm_is_vpc" "vpc1" { - name = "%[1]s" -} -resource "ibm_is_subnet" "subnet" { - name = "%[1]s" - vpc = "${ibm_is_vpc.vpc1.id}" - zone = "eu-de-1" - total_ipv4_address_count = 256 -} -resource "ibm_resource_instance" "cos_instance" { - name = "testcos_instance" - service = "cloud-object-storage" - plan = "standard" - location = "global" -} -resource "ibm_container_vpc_cluster" "cluster" { - name = "%[1]s" - vpc_id = "${ibm_is_vpc.vpc1.id}" - flavor = "%s" - worker_count = "%s" - kube_version = "4.3.23_openshift" - wait_till = "IngressReady" - entitlement = "cloud_pak" - cos_instance_crn = ibm_resource_instance.cos_instance.id - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - subnet_id = ibm_is_subnet.subnet.id - name = "eu-de-1" - } - } - data "ibm_container_cluster_config" "testacc_ds_cluster" { - cluster_name_id = ibm_container_vpc_cluster.cluster.id - } - `, name, openshiftFlavour, openShiftworkerCount) - -} diff --git a/ibm/resource_ibm_container_vpc_worker_pool_test.go b/ibm/resource_ibm_container_vpc_worker_pool_test.go deleted file mode 100644 index 6e5d52223..000000000 --- a/ibm/resource_ibm_container_vpc_worker_pool_test.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" -) - -func TestAccIBMContainerVpcClusterWorkerPoolBasic(t *testing.T) { - - name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMVpcContainerWorkerPoolDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMVpcContainerWorkerPoolBasic(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "flavor", "cx2.2x4"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "zones.#", "1"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "labels.%", "2"), - ), - }, - { - Config: testAccCheckIBMVpcContainerWorkerPoolUpdate(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "flavor", "cx2.2x4"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "zones.#", "2"), - resource.TestCheckResourceAttr( - "ibm_container_vpc_worker_pool.test_pool", "labels.%", "3"), - ), - }, - { - ResourceName: "ibm_container_vpc_worker_pool.test_pool", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckIBMVpcContainerWorkerPoolDestroy(s *terraform.State) error { - - wpClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_container_vpc_worker_pool" { - continue - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - cluster := parts[0] - workerPoolID := parts[1] - - target := v2.ClusterTargetHeader{} - - // Try to find the key - _, err = wpClient.WorkerPools().GetWorkerPool(cluster, workerPoolID, target) - - if err == nil { - return fmt.Errorf("Worker pool still exists: %s", rs.Primary.ID) - } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for worker pool (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMVpcContainerWorkerPoolBasic(name string) string { - return fmt.Sprintf(` - provider "ibm" { - region="eu-de" - } - data "ibm_resource_group" "resource_group" { - is_default=true - } - resource "ibm_is_vpc" "vpc" { - name = "%[1]s" - } - - resource "ibm_is_subnet" "subnet1" { - name = "%[1]s-1" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-1" - total_ipv4_address_count = 256 - } - - resource "ibm_is_subnet" "subnet2" { - name = "%[1]s-2" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-2" - total_ipv4_address_count = 256 - } - - resource "ibm_container_vpc_cluster" "cluster" { - name = "%[1]s" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - resource_group_id = data.ibm_resource_group.resource_group.id - wait_till = "MasterNodeReady" - zones { - subnet_id = ibm_is_subnet.subnet1.id - name = "eu-de-1" - } - } - resource "ibm_container_vpc_worker_pool" "test_pool" { - cluster = ibm_container_vpc_cluster.cluster.id - worker_pool_name = "%[1]s" - flavor = "cx2.2x4" - vpc_id = ibm_is_vpc.vpc.id - worker_count = 1 - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - name = "eu-de-2" - subnet_id = ibm_is_subnet.subnet2.id - } - labels = { - "test" = "test-pool" - "test1" = "test-pool1" - } - } - `, name) -} - -func testAccCheckIBMVpcContainerWorkerPoolUpdate(name string) string { - return fmt.Sprintf(` - provider "ibm" { - region="eu-de" - } - data "ibm_resource_group" "resource_group" { - is_default=true - } - resource "ibm_is_vpc" "vpc" { - name = "%[1]s" - } - resource "ibm_is_subnet" "subnet1" { - name = "%[1]s-1" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-1" - total_ipv4_address_count = 256 - } - resource "ibm_is_subnet" "subnet2" { - name = "%[1]s-2" - vpc = ibm_is_vpc.vpc.id - zone = "eu-de-2" - total_ipv4_address_count = 256 - } - resource "ibm_container_vpc_cluster" "cluster" { - name = "%[1]s" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - resource_group_id = data.ibm_resource_group.resource_group.id - wait_till = "MasterNodeReady" - zones { - subnet_id = ibm_is_subnet.subnet1.id - name = "eu-de-1" - } - } - resource "ibm_container_vpc_worker_pool" "test_pool" { - cluster = ibm_container_vpc_cluster.cluster.id - worker_pool_name = "%[1]s" - flavor = "cx2.2x4" - vpc_id = ibm_is_vpc.vpc.id - worker_count = 1 - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - name = "eu-de-2" - subnet_id = ibm_is_subnet.subnet2.id - } - zones { - subnet_id = ibm_is_subnet.subnet1.id - name = "eu-de-1" - } - labels = { - "test" = "test-pool" - "test1" = "test-pool1" - "test2" = "test-pool2" - } - } - `, name) -} diff --git a/ibm/resource_ibm_container_worker_pool_zone_attachment_test.go b/ibm/resource_ibm_container_worker_pool_zone_attachment_test.go deleted file mode 100644 index 85e71fbad..000000000 --- a/ibm/resource_ibm_container_worker_pool_zone_attachment_test.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMContainerWorkerPoolZoneAttachment_basic(t *testing.T) { - - workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) - clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentBasic(clusterName, workerPoolName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", zoneUpdatePrivateVlan), - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "public_vlan_id", zonePublicVlan), - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "2"), - ), - }, - { - Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentUpdatePublicVlan(clusterName, workerPoolName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", zoneUpdatePrivateVlan), - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "public_vlan_id", zoneUpdatePublicVlan), - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "1"), - ), - }, - { - ResourceName: "ibm_container_worker_pool_zone_attachment.test_zone", - ImportState: true, - ImportStateVerify: false, - }, - }, - }) -} - -func TestAccIBMContainerWorkerPoolZoneAttachment_privateVlanOnly(t *testing.T) { - workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) - clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentPrivateVlanOnly(clusterName, workerPoolName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", zoneUpdatePrivateVlan), - resource.TestCheckResourceAttr( - "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "1"), - ), - }, - }, - }) -} - -func TestAccIBMContainerWorkerPoolZoneAttachment_publicVlanOnly(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMLbaasDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentPublicVlanOnly(), - ExpectError: regexp.MustCompile("must be specified if a public_vlan_id"), - }, - }, - }) -} - -func testAccCheckIBMContainerWorkerPoolZoneAttachmentBasic(clusterName, workerPoolName string) string { - return fmt.Sprintf(` - -resource "ibm_container_cluster" "testacc_cluster" { - name = "%s" - datacenter = "%s" - machine_type = "%s" - hardware = "shared" - public_vlan_id = "%s" - private_vlan_id = "%s" - kube_version = "%s" - wait_till = "OneWorkerNodeReady" -} - -resource "ibm_container_worker_pool" "test_pool" { - worker_pool_name = "%s" - machine_type = "%s" - cluster = ibm_container_cluster.testacc_cluster.id - size_per_zone = 2 - hardware = "shared" - disk_encryption = "true" - labels = { - "test" = "test-pool" - "test1" = "test-pool1" - } -} - -resource "ibm_container_worker_pool_zone_attachment" "test_zone" { - cluster = ibm_container_cluster.testacc_cluster.id - zone = "%s" - worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) - private_vlan_id = "%s" - public_vlan_id = "%s" - wait_till_albs = false -} - - `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeUpdateVersion, workerPoolName, machineType, zone, zoneUpdatePrivateVlan, zonePublicVlan) -} - -func testAccCheckIBMContainerWorkerPoolZoneAttachmentPrivateVlanOnly(clusterName, workerPoolName string) string { - return fmt.Sprintf(` - -resource "ibm_container_cluster" "testacc_cluster" { - name = "%s" - datacenter = "%s" - machine_type = "%s" - hardware = "shared" - public_vlan_id = "%s" - private_vlan_id = "%s" - kube_version = "%s" - wait_time_minutes = 180 - wait_till = "MasterNodeReady" -} - -resource "ibm_container_worker_pool" "test_pool" { - worker_pool_name = "%s" - machine_type = "%s" - cluster = ibm_container_cluster.testacc_cluster.id - size_per_zone = 1 - hardware = "shared" - disk_encryption = "true" - labels = { - "test" = "test-pool" - "test1" = "test-pool1" - } -} - -resource "ibm_container_worker_pool_zone_attachment" "test_zone" { - cluster = ibm_container_cluster.testacc_cluster.id - zone = "%s" - worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) - private_vlan_id = "%s" -} - - `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeUpdateVersion, workerPoolName, machineType, zone, zoneUpdatePrivateVlan) -} - -func testAccCheckIBMContainerWorkerPoolZoneAttachmentPublicVlanOnly() string { - return fmt.Sprintf(` - resource "ibm_container_worker_pool_zone_attachment" "test_zone" { - cluster = "test" - zone = "ams03" - worker_pool = "testpool" - public_vlan_id = "%s" - } - - `, publicVlanID) -} - -func testAccCheckIBMContainerWorkerPoolZoneAttachmentUpdatePublicVlan(clusterName, workerPoolName string) string { - return fmt.Sprintf(` - -resource "ibm_container_cluster" "testacc_cluster" { - name = "%s" - datacenter = "%s" - machine_type = "%s" - hardware = "shared" - public_vlan_id = "%s" - private_vlan_id = "%s" - kube_version = "%s" - wait_till = "OneWorkerNodeReady" -} - -resource "ibm_container_worker_pool" "test_pool" { - worker_pool_name = "%s" - machine_type = "%s" - cluster = ibm_container_cluster.testacc_cluster.id - size_per_zone = 1 - hardware = "shared" - disk_encryption = "true" - labels = { - "test" = "test-pool" - "test1" = "test-pool1" - } -} - -resource "ibm_container_worker_pool_zone_attachment" "test_zone" { - cluster = ibm_container_cluster.testacc_cluster.id - zone = "%s" - worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) - private_vlan_id = "%s" - public_vlan_id = "%s" -} - - `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeUpdateVersion, workerPoolName, machineType, zone, zoneUpdatePrivateVlan, zoneUpdatePublicVlan) -} diff --git a/ibm/resource_ibm_cos_bucket.go b/ibm/resource_ibm_cos_bucket.go deleted file mode 100644 index a01912125..000000000 --- a/ibm/resource_ibm_cos_bucket.go +++ /dev/null @@ -1,1163 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "regexp" - "strings" - "time" - - "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" - "github.com/IBM/ibm-cos-sdk-go/aws" - "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" - token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" - "github.com/IBM/ibm-cos-sdk-go/aws/session" - "github.com/IBM/ibm-cos-sdk-go/service/s3" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var singleSiteLocation = []string{ - "ams03", "che01", "hkg02", "mel01", "mex01", - "mil01", "mon01", "osl01", "par01", "sjc04", "sao01", - "seo01", "sng01", "tor01", -} - -var regionLocation = []string{ - "au-syd", "ca-tor", "eu-de", "eu-gb", "jp-tok", "jp-osa", "us-east", "us-south", "br-sao", -} - -var crossRegionLocation = []string{ - "us", "eu", "ap", -} - -var storageClass = []string{ - "standard", "vault", "cold", "flex", "smart", -} - -const ( - keyAlgorithm = "AES256" -) - -func resourceIBMCOSBucket() *schema.Resource { - return &schema.Resource{ - Read: resourceIBMCOSBucketRead, - Create: resourceIBMCOSBucketCreate, - Update: resourceIBMCOSBucketUpdate, - Delete: resourceIBMCOSBucketDelete, - Exists: resourceIBMCOSBucketExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(20 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - "bucket_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "COS Bucket name", - }, - "resource_instance_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "resource instance ID", - ValidateFunc: validateRegexp(`^crn:.+:.+:.+:.+:.+:a\/[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\:\:$`), - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "CRN of resource instance", - }, - "key_protect": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Description: "CRN of the key you want to use data at rest encryption", - }, - "single_site_location": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue(singleSiteLocation), - ForceNew: true, - ConflictsWith: []string{"region_location", "cross_region_location"}, - Description: "single site location info", - }, - "region_location": { - Type: schema.TypeString, - Optional: true, - //ValidateFunc: validateAllowedStringValue(regionLocation), - ForceNew: true, - ConflictsWith: []string{"cross_region_location", "single_site_location"}, - Description: "Region Location info.", - }, - "cross_region_location": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue(crossRegionLocation), - ForceNew: true, - ConflictsWith: []string{"region_location", "single_site_location"}, - Description: "Cros region location info", - }, - "storage_class": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue(storageClass), - ForceNew: true, - Description: "Storage class info", - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "direct"}), - Description: "public or private", - DiffSuppressFunc: applyOnce, - Default: "public", - }, - "s3_endpoint_public": { - Type: schema.TypeString, - Computed: true, - Description: "Public endpoint for the COS bucket", - }, - "s3_endpoint_private": { - Type: schema.TypeString, - Computed: true, - Description: "Private endpoint for the COS bucket", - }, - "allowed_ip": { - Type: schema.TypeList, - Optional: true, - ForceNew: false, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of IPv4 or IPv6 addresses ", - }, - "activity_tracking": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "Enables sending log data to Activity Tracker and LogDNA to provide visibility into object read and write events", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "read_data_events": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "If set to true, all object read events will be sent to Activity Tracker.", - }, - "write_data_events": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "If set to true, all object write events will be sent to Activity Tracker.", - }, - "activity_tracker_crn": { - Type: schema.TypeString, - Required: true, - Description: "The instance of Activity Tracker that will receive object event data", - }, - }, - }, - }, - "metrics_monitoring": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "Enables sending metrics to IBM Cloud Monitoring.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "usage_metrics_enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Usage metrics will be sent to the monitoring service.", - }, - "request_metrics_enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Request metrics will be sent to the monitoring service.", - }, - "metrics_monitoring_crn": { - Type: schema.TypeString, - Required: true, - Description: "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", - }, - }, - }, - }, - "archive_rule": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rule_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Unique identifier for the rule.Archive rules allow you to set a specific time frame after which objects transition to the archive. Set Rule ID for cos bucket", - }, - "enable": { - Type: schema.TypeBool, - Required: true, - Description: "Enable or disable an archive rule for a bucket", - }, - "days": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 3650), - Description: "Specifies the number of days when the specific rule action takes effect.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"GLACIER", "ACCELERATED", "Glacier", "Accelerated", "glacier", "accelerated"}), - DiffSuppressFunc: caseDiffSuppress, - Description: "Specifies the storage class/archive type to which you want the object to transition. It can be Glacier or Accelerated", - }, - }, - }, - }, - "expire_rule": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1000, - Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rule_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", - }, - "enable": { - Type: schema.TypeBool, - Required: true, - Description: "Enable or disable an expire rule for a bucket", - }, - "prefix": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The rule applies to any objects with keys that match this prefix", - }, - "days": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 3650), - Description: "Specifies the number of days when the specific rule action takes effect.", - }, - }, - }, - }, - "retention_rule": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "default": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 365243), - Description: "If an object is stored in the bucket without specifying a custom retention period.", - ForceNew: false, - }, - "maximum": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 365243), - Description: "Maximum duration of time an object can be kept unmodified in the bucket.", - ForceNew: false, - }, - "minimum": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 365243), - Description: "Minimum duration of time an object must be kept unmodified in the bucket", - ForceNew: false, - }, - "permanent": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Enable or disable the permanent retention policy on the bucket", - }, - }, - }, - }, - "object_versioning": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"retention_rule", "expire_rule"}, - Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enable": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Enable or suspend the versioning for objects in the bucket", - }, - }, - }, - }, - "hard_quota": { - Type: schema.TypeInt, - Optional: true, - Description: "sets a maximum amount of storage (in bytes) available for a bucket", - }, - "force_delete": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "COS buckets need to be empty before they can be deleted. force_delete option empty the bucket and delete it.", - }, - }, - } -} - -func archiveRuleList(archiveList []interface{}) []*s3.LifecycleRule { - var archive_status, archiveStorageClass, rule_id string - var days int64 - var rules []*s3.LifecycleRule - - for _, l := range archiveList { - archiveMap, _ := l.(map[string]interface{}) - //Rule ID - if rule_idSet, exist := archiveMap["rule_id"]; exist { - id := rule_idSet.(string) - rule_id = id - } - - //Status Enable/Disable - if archive_statusSet, exist := archiveMap["enable"]; exist { - archiveStatusEnabled := archive_statusSet.(bool) - if archiveStatusEnabled == true { - archive_status = "Enabled" - } else { - archive_status = "Disabled" - } - } - //Days - if daysarchiveSet, exist := archiveMap["days"]; exist { - daysarchive := int64(daysarchiveSet.(int)) - days = daysarchive - } - //Archive Type - if archiveStorgaeClassSet, exist := archiveMap["type"]; exist { - archiveType := archiveStorgaeClassSet.(string) - archiveStorageClass = archiveType - } - - archive_rule := s3.LifecycleRule{ - ID: aws.String(rule_id), - Status: aws.String(archive_status), - Filter: &s3.LifecycleRuleFilter{}, - Transitions: []*s3.Transition{ - { - Days: aws.Int64(days), - StorageClass: aws.String(archiveStorageClass), - }, - }, - } - - rules = append(rules, &archive_rule) - } - return rules -} - -func expireRuleList(expireList []interface{}) []*s3.LifecycleRule { - var expire_prefix, expire_status, rule_id string - var days int64 - var rules []*s3.LifecycleRule - - for _, l := range expireList { - expireMap, _ := l.(map[string]interface{}) - //Rule ID - if rule_idSet, exist := expireMap["rule_id"]; exist { - id := rule_idSet.(string) - rule_id = id - } - - //Status Enable/Disable - if expire_statusSet, exist := expireMap["enable"]; exist { - archiveStatusEnabled := expire_statusSet.(bool) - if archiveStatusEnabled == true { - expire_status = "Enabled" - } else { - expire_status = "Disabled" - } - } - //Days - if daysexpireSet, exist := expireMap["days"]; exist { - daysexpire := int64(daysexpireSet.(int)) - days = daysexpire - } - //Expire Prefix - if expirePrefixClassSet, exist := expireMap["prefix"]; exist { - expire_prefix = expirePrefixClassSet.(string) - } - - expire_rule := s3.LifecycleRule{ - ID: aws.String(rule_id), - Status: aws.String(expire_status), - Filter: &s3.LifecycleRuleFilter{ - Prefix: aws.String(expire_prefix), - }, - Expiration: &s3.LifecycleExpiration{ - Days: aws.Int64(days), - }, - } - - rules = append(rules, &expire_rule) - } - return rules -} - -func resourceIBMCOSBucketUpdate(d *schema.ResourceData, meta interface{}) error { - var s3Conf *aws.Config - rsConClient, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - bucketName := parseBucketId(d.Id(), "bucketName") - serviceID := parseBucketId(d.Id(), "serviceID") - endpointType := parseBucketId(d.Id(), "endpointType") - apiEndpoint, apiEndpointPrivate, directApiEndpoint := selectCosApi(parseBucketId(d.Id(), "apiType"), parseBucketId(d.Id(), "bLocation")) - if endpointType == "private" { - apiEndpoint = apiEndpointPrivate - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint)).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint)).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - //// Update the lifecycle (Archive or Expire) - if d.HasChange("archive_rule") || d.HasChange("expire_rule") { - var archive, archive_ok = d.GetOk("archive_rule") - var expire, expire_ok = d.GetOk("expire_rule") - var rules []*s3.LifecycleRule - if archive_ok || expire_ok { - if expire_ok { - rules = append(rules, expireRuleList(expire.([]interface{}))...) - } - if archive_ok { - rules = append(rules, archiveRuleList(archive.([]interface{}))...) - } - - lInput := &s3.PutBucketLifecycleConfigurationInput{ - Bucket: aws.String(bucketName), - LifecycleConfiguration: &s3.LifecycleConfiguration{ - Rules: rules, - }, - } - _, err := s3Client.PutBucketLifecycleConfiguration(lInput) - if err != nil { - return fmt.Errorf("failed to update the archive rule on COS bucket %s, %v", bucketName, err) - } - - } else { - DelInput := &s3.DeleteBucketLifecycleInput{ - Bucket: aws.String(bucketName), - } - - delarchive, _ := s3Client.DeleteBucketLifecycleRequest(DelInput) - err := delarchive.Send() - if err != nil { - return err - } - } - } - - //// Update the Retention policy - if d.HasChange("retention_rule") { - var defaultretention, minretention, maxretention int64 - var permanentretention bool - if retention, ok := d.GetOk("retention_rule"); ok { - retentionList := retention.([]interface{}) - if len(retentionList) > 1 { - return fmt.Errorf("Can not more than 1 retention policy") - } - for _, l := range retentionList { - retentionMap, _ := l.(map[string]interface{}) - //Default Days - if defaultretentionSet, exist := retentionMap["default"]; exist { - defaultdays := int64(defaultretentionSet.(int)) - defaultretention = defaultdays - } - //Maximum Days - if maxretentionSet, exist := retentionMap["maximum"]; exist { - maxdays := int64(maxretentionSet.(int)) - maxretention = maxdays - } - //Minimum Days - if minretentionSet, exist := retentionMap["minimum"]; exist { - mindays := int64(minretentionSet.(int)) - minretention = mindays - } - //Permanent Retention Enable/Disable - if permanentretentionSet, exist := retentionMap["permanent"]; exist { - permanentretention = permanentretentionSet.(bool) - } - } - // PUT BUCKET PROTECTION CONFIGURATION - pInput := &s3.PutBucketProtectionConfigurationInput{ - Bucket: aws.String(bucketName), - ProtectionConfiguration: &s3.ProtectionConfiguration{ - DefaultRetention: &s3.BucketProtectionDefaultRetention{ - Days: aws.Int64(defaultretention), - }, - MaximumRetention: &s3.BucketProtectionMaximumRetention{ - Days: aws.Int64(maxretention), - }, - MinimumRetention: &s3.BucketProtectionMinimumRetention{ - Days: aws.Int64(minretention), - }, - Status: aws.String("Retention"), - EnablePermanentRetention: aws.Bool(permanentretention), - }, - } - _, err := s3Client.PutBucketProtectionConfiguration(pInput) - if err != nil { - return fmt.Errorf("failed to update the retention rule on COS bucket %s, %v", bucketName, err) - } - } - } - - //update the object versioning (object versioning) - if d.HasChange("object_versioning") { - versioningConf := &s3.VersioningConfiguration{} - if versioning, ok := d.GetOk("object_versioning"); ok { - versioningList := versioning.([]interface{}) - for _, l := range versioningList { - versioningMap, _ := l.(map[string]interface{}) - //Status Enable/Disable - if object_versioning_statusSet, exist1 := versioningMap["enable"]; exist1 { - versioningStatusEnabled := object_versioning_statusSet.(bool) - if versioningStatusEnabled == true { - versioningConf.Status = aws.String("Enabled") - } else { - versioningConf.Status = aws.String("Suspended") - } - } - } - } else { - versioningConf.Status = aws.String("Suspended") - } - // PUT BUCKET Object Versioning - input := &s3.PutBucketVersioningInput{ - Bucket: aws.String(bucketName), - VersioningConfiguration: versioningConf, - } - _, err := s3Client.PutBucketVersioning(input) - if err != nil { - return fmt.Errorf("failed to update the object versioning on COS bucket %s, %v", bucketName, err) - } - } - - sess, err := meta.(ClientSession).CosConfigV1API() - if err != nil { - return err - } - if endpointType == "private" { - sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") - } - - hasChanged := false - updateBucketConfigOptions := &resourceconfigurationv1.UpdateBucketConfigOptions{} - - //BucketName - bucketName = d.Get("bucket_name").(string) - updateBucketConfigOptions.Bucket = &bucketName - - if d.HasChange("hard_quota") { - hasChanged = true - updateBucketConfigOptions.HardQuota = aws.Int64(int64(d.Get("hard_quota").(int))) - } - - if d.HasChange("allowed_ip") { - firewall := &resourceconfigurationv1.Firewall{} - var ips = make([]string, 0) - if ip, ok := d.GetOk("allowed_ip"); ok && ip != nil { - for _, i := range ip.([]interface{}) { - ips = append(ips, i.(string)) - } - firewall.AllowedIp = ips - } else { - firewall.AllowedIp = []string{} - } - hasChanged = true - updateBucketConfigOptions.Firewall = firewall - } - - if d.HasChange("activity_tracking") { - activityTracker := &resourceconfigurationv1.ActivityTracking{} - if activity, ok := d.GetOk("activity_tracking"); ok { - activitylist := activity.([]interface{}) - for _, l := range activitylist { - activityMap, _ := l.(map[string]interface{}) - - //Read event - as its optional check for existence - if readEvent := activityMap["read_data_events"]; readEvent != nil { - readSet := readEvent.(bool) - activityTracker.ReadDataEvents = &readSet - } - - //Write Event - as its optional check for existence - if writeEvent := activityMap["write_data_events"]; writeEvent != nil { - writeSet := writeEvent.(bool) - activityTracker.WriteDataEvents = &writeSet - } - - //crn - Required field - crn := activityMap["activity_tracker_crn"].(string) - activityTracker.ActivityTrackerCrn = &crn - } - } - hasChanged = true - updateBucketConfigOptions.ActivityTracking = activityTracker - } - - if d.HasChange("metrics_monitoring") { - metricsMonitor := &resourceconfigurationv1.MetricsMonitoring{} - if metrics, ok := d.GetOk("metrics_monitoring"); ok { - metricslist := metrics.([]interface{}) - for _, l := range metricslist { - metricsMap, _ := l.(map[string]interface{}) - - //metrics enabled - as its optional check for existence - if metricsSet := metricsMap["usage_metrics_enabled"]; metricsSet != nil { - metrics := metricsSet.(bool) - metricsMonitor.UsageMetricsEnabled = &metrics - } - // request metrics enabled - as its optional check for existence - if metricsSet := metricsMap["request_metrics_enabled"]; metricsSet != nil { - metrics := metricsSet.(bool) - metricsMonitor.RequestMetricsEnabled = &metrics - } - //crn - Required field - crn := metricsMap["metrics_monitoring_crn"].(string) - metricsMonitor.MetricsMonitoringCrn = &crn - } - } - hasChanged = true - updateBucketConfigOptions.MetricsMonitoring = metricsMonitor - } - - if hasChanged { - response, err := sess.UpdateBucketConfig(updateBucketConfigOptions) - if err != nil { - return fmt.Errorf("Error Update COS Bucket: %s\n%s", err, response) - } - } - - return resourceIBMCOSBucketRead(d, meta) -} - -func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { - var s3Conf *aws.Config - rsConClient, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - bucketName := parseBucketId(d.Id(), "bucketName") - serviceID := parseBucketId(d.Id(), "serviceID") - endpointType := parseBucketId(d.Id(), "endpointType") - apiEndpoint, apiEndpointPrivate, directApiEndpoint := selectCosApi(parseBucketId(d.Id(), "apiType"), parseBucketId(d.Id(), "bLocation")) - if endpointType == "private" { - apiEndpoint = apiEndpointPrivate - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" && apiKey == "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - headInput := &s3.HeadBucketInput{ - Bucket: aws.String(bucketName), - } - err = s3Client.WaitUntilBucketExists(headInput) - if err != nil { - return fmt.Errorf("failed waiting for bucket %s to be created, %v", - bucketName, err) - } - - bucketOutput, err := s3Client.ListBucketsExtended(&s3.ListBucketsExtendedInput{}) - - if err != nil { - return err - } - var bLocationConstraint string - for _, b := range bucketOutput.Buckets { - if *b.Name == bucketName { - bLocationConstraint = *b.LocationConstraint - } - } - - singleSiteLocationRegex, err := regexp.Compile("^[a-z]{3}[0-9][0-9]-[a-z]{4,8}$") - if err != nil { - return err - } - regionLocationRegex, err := regexp.Compile("^[a-z]{2}-[a-z]{2,5}-[a-z]{4,8}$") - if err != nil { - return err - } - crossRegionLocationRegex, err := regexp.Compile("^[a-z]{2}-[a-z]{4,8}$") - if err != nil { - return err - } - - if singleSiteLocationRegex.MatchString(bLocationConstraint) { - d.Set("single_site_location", strings.Split(bLocationConstraint, "-")[0]) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) - } - if regionLocationRegex.MatchString(bLocationConstraint) { - d.Set("region_location", fmt.Sprintf("%s-%s", strings.Split(bLocationConstraint, "-")[0], strings.Split(bLocationConstraint, "-")[1])) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[2]) - } - if crossRegionLocationRegex.MatchString(bLocationConstraint) { - d.Set("cross_region_location", strings.Split(bLocationConstraint, "-")[0]) - d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) - } - - bucketCRN := fmt.Sprintf("%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName) - d.Set("crn", bucketCRN) - d.Set("resource_instance_id", serviceID) - d.Set("bucket_name", bucketName) - d.Set("s3_endpoint_public", apiEndpoint) - d.Set("s3_endpoint_private", apiEndpointPrivate) - if endpointType != "" { - d.Set("endpoint_type", endpointType) - } - - getBucketConfigOptions := &resourceconfigurationv1.GetBucketConfigOptions{ - Bucket: &bucketName, - } - - sess, err := meta.(ClientSession).CosConfigV1API() - if err != nil { - return err - } - if endpointType == "private" { - sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") - } - - bucketPtr, response, err := sess.GetBucketConfig(getBucketConfigOptions) - if err != nil { - return fmt.Errorf("Error in getting bucket info rule: %s\n%s", err, response) - } - - if bucketPtr != nil { - - if bucketPtr.Firewall != nil { - d.Set("allowed_ip", flattenStringList(bucketPtr.Firewall.AllowedIp)) - } - if bucketPtr.ActivityTracking != nil { - d.Set("activity_tracking", flattenActivityTrack(bucketPtr.ActivityTracking)) - } - if bucketPtr.MetricsMonitoring != nil { - d.Set("metrics_monitoring", flattenMetricsMonitor(bucketPtr.MetricsMonitoring)) - } - if bucketPtr.HardQuota != nil { - d.Set("hard_quota", bucketPtr.HardQuota) - } - } - // Read the lifecycle configuration (archive & expiration) - - gInput := &s3.GetBucketLifecycleConfigurationInput{ - Bucket: aws.String(bucketName), - } - - lifecycleptr, err := s3Client.GetBucketLifecycleConfiguration(gInput) - - if (err != nil && !strings.Contains(err.Error(), "NoSuchLifecycleConfiguration: The lifecycle configuration does not exist")) && (err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied")) { - return err - } - - if lifecycleptr != nil { - archiveRules := archiveRuleGet(lifecycleptr.Rules) - expireRules := expireRuleGet(lifecycleptr.Rules) - if len(archiveRules) > 0 { - d.Set("archive_rule", archiveRules) - } - if len(expireRules) > 0 { - d.Set("expire_rule", expireRules) - } - } - - // Read retention rule - retentionInput := &s3.GetBucketProtectionConfigurationInput{ - Bucket: aws.String(bucketName), - } - retentionptr, err := s3Client.GetBucketProtectionConfiguration(retentionInput) - - if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { - return err - } - - if retentionptr != nil { - retentionRules := retentionRuleGet(retentionptr.ProtectionConfiguration) - if len(retentionRules) > 0 { - d.Set("retention_rule", retentionRules) - } - } - - // Read Object versioning - versionInput := &s3.GetBucketVersioningInput{ - Bucket: aws.String(bucketName), - } - versionPtr, err := s3Client.GetBucketVersioning(versionInput) - - if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { - return err - } - if versionPtr != nil { - versioningData := flattenCosObejctVersioning(versionPtr) - if len(versioningData) > 0 { - d.Set("object_versioning", versioningData) - } else { - d.Set("object_versioning", nil) - } - } - return nil -} - -func resourceIBMCOSBucketCreate(d *schema.ResourceData, meta interface{}) error { - var s3Conf *aws.Config - rsConClient, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - bucketName := d.Get("bucket_name").(string) - storageClass := d.Get("storage_class").(string) - var bLocation string - var apiType string - serviceID := d.Get("resource_instance_id").(string) - - if bucketLocation, ok := d.GetOk("cross_region_location"); ok { - bLocation = bucketLocation.(string) - apiType = "crl" - } - if bucketLocation, ok := d.GetOk("region_location"); ok { - bLocation = bucketLocation.(string) - apiType = "rl" - } - if bucketLocation, ok := d.GetOk("single_site_location"); ok { - bLocation = bucketLocation.(string) - apiType = "ssl" - } - if bLocation == "" { - return fmt.Errorf("Provide either `cross_region_location` or `region_location` or `single_site_location`") - } - lConstraint := fmt.Sprintf("%s-%s", bLocation, storageClass) - var endpointType = d.Get("endpoint_type").(string) - apiEndpoint, privateApiEndpoint, directApiEndpoint := selectCosApi(apiType, bLocation) - if endpointType == "private" { - apiEndpoint = privateApiEndpoint - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) - if apiEndpoint == "" { - return fmt.Errorf("The endpoint doesn't exists for given location %s and endpoint type %s", bLocation, endpointType) - } - create := &s3.CreateBucketInput{ - Bucket: aws.String(bucketName), - CreateBucketConfiguration: &s3.CreateBucketConfiguration{ - LocationConstraint: aws.String(lConstraint), - }, - } - - if keyprotect, ok := d.GetOk("key_protect"); ok { - create.IBMSSEKPCustomerRootKeyCrn = aws.String(keyprotect.(string)) - create.IBMSSEKPEncryptionAlgorithm = aws.String(keyAlgorithm) - } - - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" && apiKey == "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - _, err = s3Client.CreateBucket(create) - if err != nil { - return err - } - // Generating a fake id which contains every information about to get the bucket via s3 api - bucketID := fmt.Sprintf("%s:%s:%s:meta:%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName, apiType, bLocation, endpointType) - d.SetId(bucketID) - - return resourceIBMCOSBucketUpdate(d, meta) - -} - -func resourceIBMCOSBucketDelete(d *schema.ResourceData, meta interface{}) error { - var s3Conf *aws.Config - rsConClient, _ := meta.(ClientSession).BluemixSession() - bucketName := parseBucketId(d.Id(), "bucketName") - serviceID := d.Get("resource_instance_id").(string) - var bLocation string - var apiType string - if bucketLocation, ok := d.GetOk("cross_region_location"); ok { - bLocation = bucketLocation.(string) - apiType = "crl" - } - if bucketLocation, ok := d.GetOk("region_location"); ok { - bLocation = bucketLocation.(string) - apiType = "rl" - } - if bucketLocation, ok := d.GetOk("single_site_location"); ok { - bLocation = bucketLocation.(string) - apiType = "ssl" - } - endpointType := parseBucketId(d.Id(), "endpointType") - apiEndpoint, apiEndpointPrivate, directApiEndpoint := selectCosApi(apiType, bLocation) - if endpointType == "private" { - apiEndpoint = apiEndpointPrivate - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) - if apiEndpoint == "" { - return fmt.Errorf("The endpoint doesn't exists for given location %s and endpoint type %s", bLocation, endpointType) - } - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" && apiKey == "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - delete := &s3.DeleteBucketInput{ - Bucket: aws.String(bucketName), - } - _, err = s3Client.DeleteBucket(delete) - - if err != nil && strings.Contains(err.Error(), "BucketNotEmpty") { - if delbucket, ok := d.GetOk("force_delete"); ok { - if delbucket.(bool) { - // Use a S3 service client that can handle multiple slashes in URIs. - // While ibm_cos_bucket_object resources cannot create these object - // keys, other AWS services and applications using the COS Bucket can. - - // bucket may have things delete them - log.Printf("[DEBUG] COS Bucket attempting to forceDelete %+v", err) - - // Delete everything including locked objects. - // Don't ignore any object errors or we could recurse infinitely. - err = deleteAllCOSObjectVersions(s3Client, bucketName, "", false, false) - - if err != nil { - return fmt.Errorf("error COS Bucket force_delete: %s", err) - } - - // this line recurses until all objects are deleted or an error is returned - return resourceIBMCOSBucketDelete(d, meta) - } - } - } - if err != nil { - return fmt.Errorf("error deleting COS Bucket (%s): %s", d.Id(), err) - } - - return nil -} - -func resourceIBMCOSBucketExists(d *schema.ResourceData, meta interface{}) (bool, error) { - var s3Conf *aws.Config - rsConClient, err := meta.(ClientSession).BluemixSession() - if err != nil { - return false, err - } - - bucketName := parseBucketId(d.Id(), "bucketName") - serviceID := parseBucketId(d.Id(), "serviceID") - endpointType := parseBucketId(d.Id(), "endpointType") - apiEndpoint, apiEndpointPrivate, directApiEndpoint := selectCosApi(parseBucketId(d.Id(), "apiType"), parseBucketId(d.Id(), "bLocation")) - if endpointType == "private" { - apiEndpoint = apiEndpointPrivate - } - if endpointType == "direct" { - apiEndpoint = directApiEndpoint - } - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) - if apiEndpoint == "" { - return false, fmt.Errorf("The endpoint doesn't exists for given endpoint type %s", endpointType) - } - authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return false, err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - - apiKey := rsConClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsConClient.Config.IAMAccessToken - if iamAccessToken != "" && apiKey == "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsConClient.Config.IAMAccessToken, - RefreshToken: rsConClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) - } - - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - bucketList, err := s3Client.ListBuckets(&s3.ListBucketsInput{}) - if err != nil { - return false, err - } - for _, bucket := range bucketList.Buckets { - if *bucket.Name == bucketName { - return true, nil - } - } - return false, nil -} - -func selectCosApi(apiType string, bLocation string) (string, string, string) { - if apiType == "crl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) - } - if apiType == "rl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) - } - if apiType == "ssl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) - } - return "", "", "" -} - -func parseBucketId(id string, info string) string { - crn := strings.Split(id, ":meta:")[0] - meta := strings.Split(id, ":meta:")[1] - - if info == "bucketName" { - return strings.Split(crn, ":bucket:")[1] - } - if info == "serviceID" { - return fmt.Sprintf("%s::", strings.Split(crn, ":bucket:")[0]) - } - if info == "apiType" { - return strings.Split(meta, ":")[0] - } - if info == "bLocation" { - return strings.Split(meta, ":")[1] - } - if info == "endpointType" { - s := strings.Split(meta, ":") - if len(s) > 2 { - return strings.Split(meta, ":")[2] - } - return "" - - } - return "" -} diff --git a/ibm/resource_ibm_cos_bucket_test.go b/ibm/resource_ibm_cos_bucket_test.go deleted file mode 100644 index f63f3017d..000000000 --- a/ibm/resource_ibm_cos_bucket_test.go +++ /dev/null @@ -1,1065 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - "time" - - "github.com/IBM/ibm-cos-sdk-go/aws" - "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" - token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" - "github.com/IBM/ibm-cos-sdk-go/aws/session" - "github.com/IBM/ibm-cos-sdk-go/service/s3" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMCosBucket_Basic(t *testing.T) { - - serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "eu" - bucketClass := "standard" - bucketRegionType := "cross_region_location" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_updateWithSameName(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Direct(t *testing.T) { - - serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "eu" - bucketClass := "standard" - bucketRegionType := "cross_region_location" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_direct(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - }, - }) -} -func TestAccIBMCosBucket_ActivityTracker_Monitor(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - activityServiceName := fmt.Sprintf("activity_tracker_%d", acctest.RandIntRange(10, 100)) - monitorServiceName := fmt.Sprintf("metrics_monitor_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("tf-bucket%d", acctest.RandIntRange(10, 100)) - bucketRegion := "sjc04" - bucketClass := "standard" - bucketRegionType := "single_site_location" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance2", "ibm_cos_bucket.bucket2", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "single_site_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "activity_tracking.#", "1"), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "metrics_monitoring.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_update_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance2", "ibm_cos_bucket.bucket2", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "single_site_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "activity_tracking.#", "0"), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "metrics_monitoring.#", "0"), - ), - }, - }, - }) -} -func TestAccIBMCosBucket_Archive_Expiration(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("tf-bucket%d", acctest.RandIntRange(10, 100)) - bucketRegion := "us-south" - bucketClass := "standard" - bucketRegionType := "region_location" - arch_ruleId := "my-rule-id-bucket-arch" - arch_enable := true - archiveDays := 1 - ruleType := "GLACIER" - exp_ruleId := "my-rule-id-bucket-expire" - exp_enable := true - expireDays := 1 - prefix := "prefix/" - archDaysUpdate := 3 - expDaysUpdate := 2 - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_archive_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archiveDays, ruleType, exp_ruleId, exp_enable, expireDays, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "1"), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_archive_expire_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archDaysUpdate, ruleType, exp_ruleId, exp_enable, expDaysUpdate, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.0.days", fmt.Sprintf("%d", archDaysUpdate)), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.days", fmt.Sprintf("%d", expDaysUpdate)), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_update_archive_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archiveDays, ruleType, exp_ruleId, exp_enable, expireDays, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "0"), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Archive(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "us-south" - bucketClass := "standard" - bucketRegionType := "region_location" - ruleId := "my-rule-id-bucket-arch" - enable := true - archiveDays := 1 - ruleType := "GLACIER" - archiveDaysUpdate := 3 - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_archive(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDays, ruleType), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_archive_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDaysUpdate, ruleType), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.0.days", fmt.Sprintf("%d", archiveDaysUpdate)), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_update_archive(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDays, ruleType), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "0"), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Expire(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "us-south" - bucketClass := "standard" - bucketRegionType := "region_location" - ruleId := "my-rule-id-bucket-expire" - enable := true - expireDays := 2 - prefix := "prefix/" - expireDaysUpdate := 3 - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_expire_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDaysUpdate, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.days", fmt.Sprintf("%d", expireDaysUpdate)), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_update_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Retention(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "jp-tok" - bucketClass := "standard" - bucketRegionType := "region_location" - default_retention := 0 - maximum_retention := 1 - minimum_retention := 0 - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_retention(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, default_retention, maximum_retention, minimum_retention), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "retention_rule.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Object_Versioning(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "us-east" - bucketClass := "standard" - bucketRegionType := "region_location" - enable := true - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_object_versioning(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, enable), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "object_versioning.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Hard_Quota(t *testing.T) { - - cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "us-south" - bucketClass := "standard" - bucketRegionType := "region_location" - hardQuota := 1024 - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_hard_quota(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, hardQuota), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "hard_quota", fmt.Sprintf("%d", hardQuota)), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_Smart_Type(t *testing.T) { - serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "eu" - bucketClass := "smart" - bucketRegionType := "cross_region_location" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMCosBucket_updateWithSameName(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - }, - }) -} - -func TestAccIBMCosBucket_import(t *testing.T) { - serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) - bucketRegion := "eu" - bucketClass := "standard" - bucketRegionType := "cross_region_location" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMCosBucketDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), - resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), - ), - }, - resource.TestStep{ - ResourceName: "ibm_cos_bucket.bucket", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "parameters", "force_delete"}, - }, - }, - }) -} - -func testAccCheckIBMCosBucketDestroy(s *terraform.State) error { - - var s3Conf *aws.Config - var apiEndpoint string - var resourceInstance string - for _, rs := range s.RootModule().Resources { - if rs.Type == "ibm_cos_bucket" { - apiEndpoint = rs.Primary.Attributes["s3_endpoint_public"] - } - if rs.Type == "ibm_resource_instance" && rs.Primary.Attributes["service"] == "cloud-object-storage" { - resourceInstance = rs.Primary.Attributes["crn"] - - } - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).BluemixSession() - if err != nil { - return err - } - - authEndpoint, err := rsContClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsContClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, resourceInstance)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsContClient.Config.IAMAccessToken - if iamAccessToken != "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsContClient.Config.IAMAccessToken, - RefreshToken: rsContClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, resourceInstance)).WithS3ForcePathStyle(true) - } - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - bucketList, _ := s3Client.ListBuckets(&s3.ListBucketsInput{}) - if len(bucketList.Buckets) > 0 { - return errors.New("Bucket still exists") - - } - return nil -} - -func testAccCheckIBMCosBucketExists(resource string, bucket string, regiontype string, region string, bucketname string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - var s3Conf *aws.Config - resourceInstance, ok := s.RootModule().Resources[resource] - if !ok { - return fmt.Errorf("Not found: %s", resource) - } - - bucket, ok := s.RootModule().Resources[bucket] - if !ok { - return fmt.Errorf("Not found: %s", bucket) - } - - var rt string - if regiontype == "single_site_location" { - rt = "ssl" - } - if regiontype == "region_location" { - rt = "rl" - } - if regiontype == "cross_region_location" { - rt = "crl" - } - - apiEndpoint, _, _ := selectCosApi(rt, region) - - rsContClient, err := testAccProvider.Meta().(ClientSession).BluemixSession() - if err != nil { - return err - } - - authEndpoint, err := rsContClient.Config.EndpointLocator.IAMEndpoint() - if err != nil { - return err - } - authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") - apiKey := rsContClient.Config.BluemixAPIKey - if apiKey != "" { - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, resourceInstance.Primary.ID)).WithS3ForcePathStyle(true) - } - iamAccessToken := rsContClient.Config.IAMAccessToken - if iamAccessToken != "" { - initFunc := func() (*token.Token, error) { - return &token.Token{ - AccessToken: rsContClient.Config.IAMAccessToken, - RefreshToken: rsContClient.Config.IAMRefreshToken, - TokenType: "Bearer", - ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, - Expiration: time.Now().Add(-1 * time.Hour).Unix(), - }, nil - } - s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, resourceInstance.Primary.ID)).WithS3ForcePathStyle(true) - } - s3Sess := session.Must(session.NewSession()) - s3Client := s3.New(s3Sess, s3Conf) - - bucketList, _ := s3Client.ListBuckets(&s3.ListBucketsInput{}) - for _, bucket := range bucketList.Buckets { - bn := *bucket.Name - if bn == bucketname { - return nil - } - } - return errors.New("bucket does not exist") - } -} - -func testAccCheckIBMCosBucket_basic(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - storage_class = "%s" - cross_region_location = "%s" - } - - - `, serviceName, bucketName, storageClass, region) -} -func testAccCheckIBMCosBucket_direct(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - storage_class = "%s" - cross_region_location = "%s" - endpoint_type= "direct" - } - - - `, serviceName, bucketName, storageClass, region) -} -func testAccCheckIBMCosBucket_updateWithSameName(serviceName string, bucketName string, regiontype string, region, storageClass string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - storage_class = "%s" - cross_region_location = "%s" - } - `, serviceName, bucketName, storageClass, region) -} - -func testAccCheckIBMCosBucket_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, regiontype, region, storageClass string) string { - - return fmt.Sprintf(` - - data "ibm_resource_group" "cos_group" { - is_default=true - } - resource "ibm_resource_instance" "instance2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "cloud-object-storage" - plan = "standard" - location = "global" - } - resource "ibm_resource_instance" "activity_tracker2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "logdnaat" - plan = "7-day" - location = "us-south" - } - resource "ibm_resource_instance" "metrics_monitor2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "sysdig-monitor" - plan = "graduated-tier" - location = "us-south" - parameters = { - default_receiver = true - } - } - resource "ibm_cos_bucket" "bucket2" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance2.id - single_site_location = "%s" - storage_class = "%s" - activity_tracking { - read_data_events = true - write_data_events = true - activity_tracker_crn = ibm_resource_instance.activity_tracker2.id - } - metrics_monitoring { - usage_metrics_enabled = true - request_metrics_enabled = true - metrics_monitoring_crn = ibm_resource_instance.metrics_monitor2.id - } - } - `, cosServiceName, activityServiceName, monitorServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_update_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, regiontype, region, storageClass string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "cloud-object-storage" - plan = "standard" - location = "global" - } - - resource "ibm_resource_instance" "activity_tracker2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "logdnaat" - plan = "7-day" - location = "us-south" - } - - resource "ibm_resource_instance" "metrics_monitor2" { - name = "%s" - resource_group_id = data.ibm_resource_group.cos_group.id - service = "sysdig-monitor" - plan = "graduated-tier" - location = "us-south" - parameters = { - default_receiver = true - } - } - resource "ibm_cos_bucket" "bucket2" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance2.id - single_site_location = "%s" - storage_class = "%s" - } - `, cosServiceName, activityServiceName, monitorServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_archive(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDays int, ruleType string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - archive_rule { - rule_id = "%s" - enable = true - days = %d - type = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, ruleId, archiveDays, ruleType) -} - -func testAccCheckIBMCosBucket_archive_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDaysUpdate int, ruleType string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - archive_rule { - rule_id = "%s" - enable = true - days = %d - type = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, ruleId, archiveDaysUpdate, ruleType) -} - -func testAccCheckIBMCosBucket_update_archive(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDays int, ruleType string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - } - `, cosServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - expire_rule { - rule_id = "%s" - enable = true - days = %d - prefix = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, ruleId, expireDays, prefix) -} - -func testAccCheckIBMCosBucket_expire_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDaysUpdate int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - expire_rule { - rule_id = "%s" - enable = true - days = %d - prefix = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, ruleId, expireDaysUpdate, prefix) - -} - -func testAccCheckIBMCosBucket_update_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - } - `, cosServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_archive_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archiveDays int, ruleType string, exp_ruleId string, exp_enable bool, expireDays int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - archive_rule { - rule_id = "%s" - enable = true - days = %d - type = "%s" - } - expire_rule { - rule_id = "%s" - enable = true - days = %d - prefix = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, arch_ruleId, archiveDays, ruleType, exp_ruleId, expireDays, prefix) - -} -func testAccCheckIBMCosBucket_archive_expire_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archDaysUpdate int, ruleType string, exp_ruleId string, exp_enable bool, expDaysUpdate int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - archive_rule { - rule_id = "%s" - enable = true - days = %d - type = "%s" - } - expire_rule { - rule_id = "%s" - enable = true - days = %d - prefix = "%s" - } - } - `, cosServiceName, bucketName, region, storageClass, arch_ruleId, archDaysUpdate, ruleType, exp_ruleId, expDaysUpdate, prefix) - -} - -func testAccCheckIBMCosBucket_update_archive_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archiveDays int, ruleType string, exp_ruleId string, exp_enable bool, expireDays int, prefix string) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - } - `, cosServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_retention(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, default_retention int, maximum_retention int, minimum_retention int) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - name = "Default" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - retention_rule { - default = %d - maximum = %d - minimum = %d - permanent = false - } - } - `, cosServiceName, bucketName, region, storageClass, default_retention, maximum_retention, minimum_retention) -} - -func testAccCheckIBMCosBucket_object_versioning(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, enable bool) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - name = "Default" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - object_versioning { - enable = true - } - } - `, cosServiceName, bucketName, region, storageClass) -} - -func testAccCheckIBMCosBucket_hard_quota(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, hardQuota int) string { - - return fmt.Sprintf(` - data "ibm_resource_group" "cos_group" { - name = "Default" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.cos_group.id - } - resource "ibm_cos_bucket" "bucket" { - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.instance.id - region_location = "%s" - storage_class = "%s" - hard_quota = %d - } - `, cosServiceName, bucketName, region, storageClass, hardQuota) -} diff --git a/ibm/resource_ibm_database.go b/ibm/resource_ibm_database.go deleted file mode 100644 index 3686bf40d..000000000 --- a/ibm/resource_ibm_database.go +++ /dev/null @@ -1,2200 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "encoding/json" - "fmt" - "log" - "net/url" - "os" - "reflect" - "strings" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - validation "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - // "github.com/IBM-Cloud/bluemix-go/api/globaltagging/globaltaggingv3" - "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/models" -) - -const ( - databaseInstanceSuccessStatus = "active" - databaseInstanceProvisioningStatus = "provisioning" - databaseInstanceProgressStatus = "in progress" - databaseInstanceInactiveStatus = "inactive" - databaseInstanceFailStatus = "failed" - databaseInstanceRemovedStatus = "removed" - databaseInstanceReclamation = "pending_reclamation" -) - -const ( - databaseTaskSuccessStatus = "completed" - databaseTaskProgressStatus = "running" - databaseTaskFailStatus = "failed" -) - -type CsEntry struct { - Name string - Password string - String string - Composed string - CertName string - CertBase64 string - Hosts []struct { - HostName string `json:"hostname"` - Port int `json:"port"` - } - Scheme string - QueryOptions map[string]interface{} - Path string - Database string - BundleName string - BundleBase64 string -} - -func retry(f func() error) (err error) { - attempts := 3 - - for i := 0; ; i++ { - sleep := time.Duration(10*i*i) * time.Second - time.Sleep(sleep) - - err = f() - if err == nil { - return nil - } - - if i == attempts { - return err - } - - log.Println("retrying after error:", err) - } -} -func retryTask(f func() (icdv4.Task, error)) (task icdv4.Task, err error) { - attempts := 3 - - for i := 0; ; i++ { - sleep := time.Duration(5*i) * time.Second - time.Sleep(sleep) - - task, err = f() - if err == nil { - return task, nil - } - - if i == attempts { - return task, nil - } - - log.Println("retrying after error:", err) - } -} - -func resourceIBMDatabaseInstance() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMDatabaseInstanceCreate, - Read: resourceIBMDatabaseInstanceRead, - Update: resourceIBMDatabaseInstanceUpdate, - Delete: resourceIBMDatabaseInstanceDelete, - Exists: resourceIBMDatabaseInstanceExists, - CustomizeDiff: resourceIBMDatabaseInstanceDiff, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Resource instance name for example, my Database instance", - Type: schema.TypeString, - Required: true, - }, - - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - Optional: true, - ForceNew: true, - Description: "The id of the resource group in which the Database instance is present", - }, - - "location": { - Description: "The location or the region in which Database instance exists", - Type: schema.TypeString, - Required: true, - }, - - "service": { - Description: "The name of the Cloud Internet database service", - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"databases-for-etcd", "databases-for-postgresql", "databases-for-redis", "databases-for-elasticsearch", "databases-for-mongodb", "messages-for-rabbitmq", "databases-for-mysql", "databases-for-cassandra", "databases-for-enterprisedb"}), - }, - "plan": { - Description: "The plan type of the Database instance", - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"standard", "enterprise"}), - }, - - "status": { - Description: "The resource instance status", - Type: schema.TypeString, - Computed: true, - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Unique identifier of resource instance", - }, - - "adminuser": { - Description: "The admin user id for the instance", - Type: schema.TypeString, - Computed: true, - }, - "adminpassword": { - Description: "The admin user password for the instance", - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(10, 32), - Sensitive: true, - // DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - // return true - // }, - }, - "version": { - Description: "The database version to provision if specified", - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - "members_memory_allocation_mb": { - Description: "Memory allocation required for cluster", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count"}, - }, - "members_disk_allocation_mb": { - Description: "Disk allocation required for cluster", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count"}, - }, - "members_cpu_allocation_count": { - Description: "CPU allocation required for cluster", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count"}, - }, - "node_count": { - Description: "Total number of nodes in the cluster", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count"}, - }, - "node_memory_allocation_mb": { - Description: "Memory allocation per node", - Type: schema.TypeInt, - Optional: true, - Computed: true, - - ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count"}, - }, - "node_disk_allocation_mb": { - Description: "Disk allocation per node", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count"}, - }, - "node_cpu_allocation_count": { - Description: "CPU allocation per node", - Type: schema.TypeInt, - Optional: true, - Computed: true, - ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count"}, - }, - "plan_validation": { - Description: "For elasticsearch and postgres perform database parameter validation during the plan phase. Otherwise, database parameter validation happens in apply phase.", - Type: schema.TypeBool, - Optional: true, - Default: true, - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - if o == "" { - return true - } - return false - }, - }, - "service_endpoints": { - Description: "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", - Type: schema.TypeString, - Optional: true, - Default: "public", - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "public-and-private"}), - }, - "backup_id": { - Description: "The CRN of backup source database", - Type: schema.TypeString, - Optional: true, - }, - "remote_leader_id": { - Description: "The CRN of leader database", - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: applyOnce, - }, - "key_protect_instance": { - Description: "The CRN of Key protect instance", - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "key_protect_key": { - Description: "The CRN of Key protect key", - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "backup_encryption_key_crn": { - Description: "The Backup Encryption Key CRN", - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_database", "tag")}, - Set: resourceIBMVPCHash, - }, - "point_in_time_recovery_deployment_id": { - Description: "The CRN of source instance", - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: applyOnce, - }, - "point_in_time_recovery_time": { - Description: "The point in time recovery time stamp of the deployed instance", - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: applyOnce, - }, - "users": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Description: "User name", - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(5, 32), - }, - "password": { - Description: "User password", - Type: schema.TypeString, - Optional: true, - Sensitive: true, - ValidateFunc: validation.StringLenBetween(10, 32), - }, - }, - }, - }, - "connectionstrings": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Description: "User name", - Type: schema.TypeString, - Computed: true, - }, - "composed": { - Description: "Connection string", - Type: schema.TypeString, - Computed: true, - }, - "scheme": { - Description: "DB scheme", - Type: schema.TypeString, - Computed: true, - }, - "certname": { - Description: "Certificate Name", - Type: schema.TypeString, - Computed: true, - }, - "certbase64": { - Description: "Certificate in base64 encoding", - Type: schema.TypeString, - Computed: true, - }, - "bundlename": { - Description: "Cassandra Bundle Name", - Type: schema.TypeString, - Computed: true, - }, - "bundlebase64": { - Description: "Cassandra base64 encoding", - Type: schema.TypeString, - Computed: true, - }, - "password": { - Description: "Password", - Type: schema.TypeString, - Computed: true, - }, - "queryoptions": { - Description: "DB query options", - Type: schema.TypeString, - Computed: true, - }, - "database": { - Description: "DB name", - Type: schema.TypeString, - Computed: true, - }, - "path": { - Description: "DB path", - Type: schema.TypeString, - Computed: true, - }, - "hosts": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "hostname": { - Description: "DB host name", - Type: schema.TypeString, - Computed: true, - }, - "port": { - Description: "DB port", - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - "whitelist": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "address": { - Description: "Whitelist IP address in CIDR notation", - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateCIDR, - }, - "description": { - Description: "Unique white list description", - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 32), - }, - }, - }, - }, - "groups": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "group_id": { - Description: "Scaling group name", - Type: schema.TypeString, - Computed: true, - }, - "count": { - Description: "Count of scaling groups for the instance", - Type: schema.TypeInt, - Computed: true, - }, - "memory": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The units memory is allocated in.", - }, - "allocation_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The current memory allocation for a group instance", - }, - "minimum_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum memory size for a group instance", - }, - "step_size_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The step size memory increases or decreases in.", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Is the memory size adjustable.", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can memory scale down as well as up.", - }, - }, - }, - }, - "cpu": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The .", - }, - "allocation_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The current cpu allocation count", - }, - "minimum_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum number of cpus allowed", - }, - "step_size_count": { - Type: schema.TypeInt, - Computed: true, - Description: "The number of CPUs allowed to step up or down by", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Are the number of CPUs adjustable", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can the number of CPUs be scaled down as well as up", - }, - }, - }, - }, - "disk": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "units": { - Type: schema.TypeString, - Computed: true, - Description: "The units disk is allocated in", - }, - "allocation_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The current disk allocation", - }, - "minimum_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The minimum disk size allowed", - }, - "step_size_mb": { - Type: schema.TypeInt, - Computed: true, - Description: "The step size disk increases or decreases in", - }, - "is_adjustable": { - Type: schema.TypeBool, - Computed: true, - Description: "Is the disk size adjustable", - }, - "can_scale_down": { - Type: schema.TypeBool, - Computed: true, - Description: "Can the disk size be scaled down as well as up", - }, - }, - }, - }, - }, - }, - }, - "auto_scaling": { - Type: schema.TypeList, - Description: "ICD Auto Scaling", - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "disk": { - Type: schema.TypeList, - Description: "Disk Auto Scaling", - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "capacity_enabled": { - Description: "Auto Scaling Scalar: Capacity Enabled", - Type: schema.TypeBool, - Optional: true, - Computed: true, - }, - "free_space_less_than_percent": { - Description: "Auto Scaling Scalar: Capacity Free Space Less Than Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "io_enabled": { - Description: "Auto Scaling Scalar: IO Utilization Enabled", - Type: schema.TypeBool, - Optional: true, - Computed: true, - }, - - "io_over_period": { - Description: "Auto Scaling Scalar: IO Utilization Over Period", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "io_above_percent": { - Description: "Auto Scaling Scalar: IO Utilization Above Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_limit_mb_per_member": { - Description: "Auto Scaling Rate: Limit mb per member", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - }, - }, - }, - "memory": { - Type: schema.TypeList, - Description: "Memory Auto Scaling", - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "io_enabled": { - Description: "Auto Scaling Scalar: IO Utilization Enabled", - Type: schema.TypeBool, - Optional: true, - Computed: true, - }, - - "io_over_period": { - Description: "Auto Scaling Scalar: IO Utilization Over Period", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "io_above_percent": { - Description: "Auto Scaling Scalar: IO Utilization Above Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_limit_mb_per_member": { - Description: "Auto Scaling Rate: Limit mb per member", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - }, - }, - }, - "cpu": { - Type: schema.TypeList, - Description: "CPU Auto Scaling", - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rate_increase_percent": { - Description: "Auto Scaling Rate: Increase Percent", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_period_seconds": { - Description: "Auto Scaling Rate: Period Seconds", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_limit_count_per_member": { - Description: "Auto Scaling Rate: Limit count per number", - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "rate_units": { - Description: "Auto Scaling Rate: Units ", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} -func resourceIBMICDValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmICDResourceValidator := ResourceValidator{ResourceName: "ibm_database", Schema: validateSchema} - return &ibmICDResourceValidator -} - -type Params struct { - Version string `json:"version,omitempty"` - KeyProtectKey string `json:"disk_encryption_key_crn,omitempty"` - BackUpEncryptionCRN string `json:"backup_encryption_key_crn,omitempty"` - Memory int `json:"members_memory_allocation_mb,omitempty"` - Disk int `json:"members_disk_allocation_mb,omitempty"` - CPU int `json:"members_cpu_allocation_count,omitempty"` - KeyProtectInstance string `json:"disk_encryption_instance_crn,omitempty"` - ServiceEndpoints string `json:"service-endpoints,omitempty"` - BackupID string `json:"backup-id,omitempty"` - RemoteLeaderID string `json:"remote_leader_id,omitempty"` - PITRDeploymentID string `json:"point_in_time_recovery_deployment_id,omitempty"` - PITRTimeStamp string `json:"point_in_time_recovery_time,omitempty"` -} - -func getDatabaseServiceDefaults(service string, meta interface{}) (*icdv4.Group, error) { - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return nil, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - - var dbType string - if service == "databases-for-cassandra" { - dbType = "datastax_enterprise_full" - } else if strings.HasPrefix(service, "messages-for-") { - dbType = service[len("messages-for-"):] - } else { - dbType = service[len("databases-for-"):] - } - - groupDefaults, err := icdClient.Groups().GetDefaultGroups(dbType) - if err != nil { - return nil, fmt.Errorf("ICD API is down for plan validation, set plan_validation=false %s", err) - } - return &groupDefaults.Groups[0], nil -} - -func getInitialNodeCount(d *schema.ResourceData, meta interface{}) (int, error) { - service := d.Get("service").(string) - planPhase := d.Get("plan_validation").(bool) - if planPhase { - groupDefaults, err := getDatabaseServiceDefaults(service, meta) - if err != nil { - return 0, err - } - return groupDefaults.Members.MinimumCount, nil - } else { - if service == "databases-for-elasticsearch" { - return 3, nil - } else if service == "databases-for-cassandra" { - return 3, nil - } - return 2, nil - } -} - -type GroupLimit struct { - Units string - Allocation int - Minimum int - Maximum int - StepSize int - IsAdjustable bool - CanScaleDown bool -} - -func checkGroupValue(name string, limits GroupLimit, divider int, diff *schema.ResourceDiff) error { - if diff.HasChange(name) { - oldSetting, newSetting := diff.GetChange(name) - old := oldSetting.(int) - new := newSetting.(int) - - if new < limits.Minimum/divider || new > limits.Maximum/divider || new%(limits.StepSize/divider) != 0 { - return fmt.Errorf("%s must be >= %d and <= %d in increments of %d", name, limits.Minimum/divider, limits.Maximum/divider/divider, limits.StepSize/divider) - } - if old != new && !limits.IsAdjustable { - return fmt.Errorf("%s can not change value after create", name) - } - if new < old && !limits.CanScaleDown { - return fmt.Errorf("%s can not scale down from %d to %d", name, old, new) - } - return nil - } - return nil -} - -type CountLimit struct { - Units string - AllocationCount int - MinimumCount int - MaximumCount int - StepSizeCount int - IsAdjustable bool - CanScaleDown bool -} - -func checkCountValue(name string, limits CountLimit, divider int, diff *schema.ResourceDiff) error { - groupLimit := GroupLimit{ - Units: limits.Units, - Allocation: limits.AllocationCount, - Minimum: limits.MinimumCount, - Maximum: limits.MaximumCount, - StepSize: limits.StepSizeCount, - IsAdjustable: limits.IsAdjustable, - CanScaleDown: limits.CanScaleDown, - } - return checkGroupValue(name, groupLimit, divider, diff) -} - -type MbLimit struct { - Units string - AllocationMb int - MinimumMb int - MaximumMb int - StepSizeMb int - IsAdjustable bool - CanScaleDown bool -} - -func checkMbValue(name string, limits MbLimit, divider int, diff *schema.ResourceDiff) error { - groupLimit := GroupLimit{ - Units: limits.Units, - Allocation: limits.AllocationMb, - Minimum: limits.MinimumMb, - Maximum: limits.MaximumMb, - StepSize: limits.StepSizeMb, - IsAdjustable: limits.IsAdjustable, - CanScaleDown: limits.CanScaleDown, - } - return checkGroupValue(name, groupLimit, divider, diff) -} - -func resourceIBMDatabaseInstanceDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { - - err := resourceTagsCustomizeDiff(diff) - if err != nil { - return err - } - - service := diff.Get("service").(string) - if service == "databases-for-postgresql" || service == "databases-for-elasticsearch" || service == "databases-for-cassandra" || service == "databases-for-enterprisedb" { - planPhase := diff.Get("plan_validation").(bool) - - if planPhase { - - groupDefaults, err := getDatabaseServiceDefaults(service, meta) - if err != nil { - return err - } - - err = checkMbValue("members_memory_allocation_mb", MbLimit(groupDefaults.Memory), 1, diff) - if err != nil { - return err - } - - err = checkMbValue("members_disk_allocation_mb", MbLimit(groupDefaults.Disk), 1, diff) - if err != nil { - return err - } - - err = checkCountValue("members_cpu_allocation_count", CountLimit(groupDefaults.Cpu), 1, diff) - if err != nil { - return err - } - - err = checkCountValue("node_count", CountLimit(groupDefaults.Members), 1, diff) - if err != nil { - return err - } - - var divider = groupDefaults.Members.MinimumCount - err = checkMbValue("node_memory_allocation_mb", MbLimit(groupDefaults.Memory), divider, diff) - if err != nil { - return err - } - - err = checkMbValue("node_disk_allocation_mb", MbLimit(groupDefaults.Disk), divider, diff) - if err != nil { - return err - } - - if diff.HasChange("node_cpu_allocation_count") { - err = checkCountValue("node_cpu_allocation_count", CountLimit(groupDefaults.Cpu), divider, diff) - if err != nil { - return err - } - } else if diff.HasChange("node_count") { - if _, ok := diff.GetOk("node_cpu_allocation_count"); !ok { - _, newSetting := diff.GetChange("node_count") - min := groupDefaults.Cpu.MinimumCount / divider - if newSetting != min { - return fmt.Errorf("node_cpu_allocation_count must be set when node_count is greater then the minimum %d", min) - } - } - } - } - } else if diff.HasChange("node_count") || diff.HasChange("node_memory_allocation_mb") || diff.HasChange("node_disk_allocation_mb") || diff.HasChange("node_cpu_allocation_count") { - return fmt.Errorf("[ERROR] node_count, node_memory_allocation_mb, node_disk_allocation_mb, node_cpu_allocation_count only supported for postgresql, elasticsearch and cassandra") - } - - return nil -} - -// Replace with func wrapper for resourceIBMResourceInstanceCreate specifying serviceName := "database......." -func resourceIBMDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - serviceName := d.Get("service").(string) - plan := d.Get("plan").(string) - name := d.Get("name").(string) - location := d.Get("location").(string) - - rsInst := rc.CreateResourceInstanceOptions{ - Name: &name, - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.FindByName(serviceName, true) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving database service offering: %s", err) - } - - servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) - } - rsInst.ResourcePlanID = &servicePlan - - deployments, err := rsCatRepo.ListDeployments(servicePlan) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving deployment for plan %s : %s", plan, err) - } - if len(deployments) == 0 { - return fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan) - } - deployments, supportedLocations := filterDatabaseDeployments(deployments, location) - - if len(deployments) == 0 { - locationList := make([]string, 0, len(supportedLocations)) - for l := range supportedLocations { - locationList = append(locationList, l) - } - return fmt.Errorf("[ERROR] No deployment found for service plan %s at location %s.\nValid location(s) are: %q", plan, location, locationList) - } - catalogCRN := deployments[0].CatalogCRN - rsInst.Target = &catalogCRN - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rgID := rsGrpID.(string) - rsInst.ResourceGroup = &rgID - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInst.ResourceGroup = &defaultRg - } - - initialNodeCount, err := getInitialNodeCount(d, meta) - if err != nil { - return err - } - - params := Params{} - if memory, ok := d.GetOk("members_memory_allocation_mb"); ok { - params.Memory = memory.(int) - } - if memory, ok := d.GetOk("node_memory_allocation_mb"); ok { - params.Memory = memory.(int) * initialNodeCount - } - if disk, ok := d.GetOk("members_disk_allocation_mb"); ok { - params.Disk = disk.(int) - } - if disk, ok := d.GetOk("node_disk_allocation_mb"); ok { - params.Disk = disk.(int) * initialNodeCount - } - if cpu, ok := d.GetOk("members_cpu_allocation_count"); ok { - params.CPU = cpu.(int) - } - if cpu, ok := d.GetOk("node_cpu_allocation_count"); ok { - params.CPU = cpu.(int) * initialNodeCount - } - if version, ok := d.GetOk("version"); ok { - params.Version = version.(string) - } - if keyProtect, ok := d.GetOk("key_protect_key"); ok { - params.KeyProtectKey = keyProtect.(string) - } - if keyProtectInstance, ok := d.GetOk("key_protect_instance"); ok { - params.KeyProtectInstance = keyProtectInstance.(string) - } - if backupID, ok := d.GetOk("backup_id"); ok { - params.BackupID = backupID.(string) - } - if backUpEncryptionKey, ok := d.GetOk("backup_encryption_key_crn"); ok { - params.BackUpEncryptionCRN = backUpEncryptionKey.(string) - } - if remoteLeader, ok := d.GetOk("remote_leader_id"); ok { - params.RemoteLeaderID = remoteLeader.(string) - } - if pitrID, ok := d.GetOk("point_in_time_recovery_deployment_id"); ok { - params.PITRDeploymentID = pitrID.(string) - } - if pitrTime, ok := d.GetOk("point_in_time_recovery_time"); ok { - params.PITRTimeStamp = pitrTime.(string) - } - serviceEndpoint := d.Get("service_endpoints").(string) - params.ServiceEndpoints = serviceEndpoint - parameters, _ := json.Marshal(params) - var raw map[string]interface{} - json.Unmarshal(parameters, &raw) - //paramString := string(parameters[:]) - rsInst.Parameters = raw - - instance, response, err := rsConClient.CreateResourceInstance(&rsInst) - if err != nil { - return fmt.Errorf("[ERROR] Error creating database instance: %s %s", err, response) - } - d.SetId(*instance.ID) - - _, err = waitForDatabaseInstanceCreate(d, meta, *instance.ID) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for create database instance (%s) to complete: %s", *instance.ID, err) - } - - if node_count, ok := d.GetOk("node_count"); ok { - if initialNodeCount != node_count { - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - - err = horizontalScale(d, meta, icdClient) - if err != nil { - return err - } - } - } - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk("tags"); ok || v != "" { - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of ibm database (%s) tags: %s", d.Id(), err) - } - } - - icdId := EscapeUrlParm(*instance.ID) - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - - if pw, ok := d.GetOk("adminpassword"); ok { - adminPassword := pw.(string) - cdb, err := icdClient.Cdbs().GetCdb(icdId) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err) - } - return fmt.Errorf("[ERROR] Error getting database config while updating adminpassword for: %s with error %s", icdId, err) - } - - userParams := icdv4.UserReq{ - User: icdv4.User{ - Password: adminPassword, - }, - } - task, err := icdClient.Users().UpdateUser(icdId, cdb.AdminUser, userParams) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database admin password: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for update of database (%s) admin password task to complete: %s", icdId, err) - } - } - - if wl, ok := d.GetOk("whitelist"); ok { - whitelist := expandWhitelist(wl.(*schema.Set)) - for _, wlEntry := range whitelist { - whitelistReq := icdv4.WhitelistReq{ - WhitelistEntry: icdv4.WhitelistEntry{ - Address: wlEntry.Address, - Description: wlEntry.Description, - }, - } - task, err := icdClient.Whitelists().CreateWhitelist(icdId, whitelistReq) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database whitelist entry: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for update of database (%s) whitelist task to complete: %s", icdId, err) - } - } - } - if cpuRecord, ok := d.GetOk("auto_scaling.0.cpu"); ok { - params := icdv4.AutoscalingSetGroup{} - cpuBody, err := expandICDAutoScalingGroup(d, cpuRecord, "cpu") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting cpuBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.CPU = &cpuBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database cpu auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) cpu auto_scaling group update task to complete: %s", icdId, err) - } - - } - if diskRecord, ok := d.GetOk("auto_scaling.0.disk"); ok { - params := icdv4.AutoscalingSetGroup{} - diskBody, err := expandICDAutoScalingGroup(d, diskRecord, "disk") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting diskBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.Disk = &diskBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database disk auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) disk auto_scaling group update task to complete: %s", icdId, err) - } - - } - if memoryRecord, ok := d.GetOk("auto_scaling.0.memory"); ok { - params := icdv4.AutoscalingSetGroup{} - memoryBody, err := expandICDAutoScalingGroup(d, memoryRecord, "memory") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting memoryBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.Memory = &memoryBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database memory auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) memory auto_scaling group update task to complete: %s", icdId, err) - } - - } - - if userlist, ok := d.GetOk("users"); ok { - users := expandUsers(userlist.(*schema.Set)) - for _, user := range users { - userReq := icdv4.UserReq{ - User: icdv4.User{ - UserName: user.UserName, - Password: user.Password, - }, - } - task, err := icdClient.Users().CreateUser(icdId, userReq) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database user (%s) entry: %s", user.UserName, err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for update of database (%s) user (%s) create task to complete: %s", icdId, user.UserName, err) - } - } - } - - return resourceIBMDatabaseInstanceRead(d, meta) -} - -func resourceIBMDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - connectionEndpoint := "public" - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - log.Printf("[WARN] Removing record from state because it's not found via the API") - d.SetId("") - return nil - } - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) - } - if strings.Contains(*instance.State, "removed") { - log.Printf("[WARN] Removing instance from TF state because it's now in removed state") - d.SetId("") - return nil - } - - tags, err := GetTagsUsingCRN(meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on get of ibm Database tags (%s) tags: %s", d.Id(), err) - } - d.Set("tags", tags) - d.Set("name", *instance.Name) - d.Set("status", *instance.State) - d.Set("resource_group_id", *instance.ResourceGroupID) - if instance.CRN != nil { - location := strings.Split(*instance.CRN, ":") - if len(location) > 5 { - d.Set("location", location[5]) - } - } - d.Set("guid", *instance.GUID) - - if instance.Parameters != nil { - if endpoint, ok := instance.Parameters["service-endpoints"]; ok { - if endpoint == "private" { - connectionEndpoint = "private" - } - d.Set("service_endpoints", endpoint) - } - - } - - d.Set(ResourceName, *instance.Name) - d.Set(ResourceCRN, *instance.CRN) - d.Set(ResourceStatus, *instance.State) - d.Set(ResourceGroupName, *instance.ResourceGroupCRN) - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/services/"+url.QueryEscape(*instance.CRN)) - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.GetServiceName(*instance.ResourceID) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) - } - - d.Set("service", serviceOff) - - servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - - icdId := EscapeUrlParm(instanceID) - cdb, err := icdClient.Cdbs().GetCdb(icdId) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider. Specify the correct region in the provider definition. %v", err) - } - return fmt.Errorf("[ERROR] Error getting database config for: %s with error %s", icdId, err) - } - d.Set("adminuser", cdb.AdminUser) - d.Set("version", cdb.Version) - - groupList, err := icdClient.Groups().GetGroups(icdId) - if err != nil { - return fmt.Errorf("[ERROR] Error getting database groups: %s", err) - } - d.Set("groups", flattenIcdGroups(groupList)) - d.Set("node_count", groupList.Groups[0].Members.AllocationCount) - - d.Set("members_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb) - d.Set("node_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb/groupList.Groups[0].Members.AllocationCount) - - d.Set("members_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb) - d.Set("node_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb/groupList.Groups[0].Members.AllocationCount) - - d.Set("members_cpu_allocation_count", groupList.Groups[0].Cpu.AllocationCount) - d.Set("node_cpu_allocation_count", groupList.Groups[0].Cpu.AllocationCount/groupList.Groups[0].Members.AllocationCount) - - autoSclaingGroup, err := icdClient.AutoScaling().GetAutoScaling(icdId, "member") - if err != nil { - return fmt.Errorf("[ERROR] Error getting database autoscaling groups: %s", err) - } - d.Set("auto_scaling", flattenICDAutoScalingGroup(autoSclaingGroup)) - - whitelist, err := icdClient.Whitelists().GetWhitelist(icdId) - if err != nil { - return fmt.Errorf("[ERROR] Error getting database whitelist: %s", err) - } - d.Set("whitelist", flattenWhitelist(whitelist)) - - var connectionStrings []CsEntry - //ICD does not implement a GetUsers API. Users populated from tf configuration. - tfusers := d.Get("users").(*schema.Set) - users := expandUsers(tfusers) - user := icdv4.User{ - UserName: cdb.AdminUser, - } - users = append(users, user) - for _, user := range users { - userName := user.UserName - csEntry, err := getConnectionString(d, userName, connectionEndpoint, meta) - if err != nil { - return fmt.Errorf("[ERROR] Error getting user connection string for user (%s): %s", userName, err) - } - connectionStrings = append(connectionStrings, csEntry) - } - d.Set("connectionstrings", flattenConnectionStrings(connectionStrings)) - - return nil -} - -func resourceIBMDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - updateReq := rc.UpdateResourceInstanceOptions{ - ID: &instanceID, - } - update := false - if d.HasChange("name") { - name := d.Get("name").(string) - updateReq.Name = &name - update = true - } - if d.HasChange("service_endpoints") { - params := Params{} - params.ServiceEndpoints = d.Get("service_endpoints").(string) - parameters, _ := json.Marshal(params) - var raw map[string]interface{} - json.Unmarshal(parameters, &raw) - updateReq.Parameters = raw - update = true - } - - if update { - _, response, err := rsConClient.UpdateResourceInstance(&updateReq) - if err != nil { - return fmt.Errorf("[ERROR] Error updating resource instance: %s %s", err, response) - } - - _, err = waitForDatabaseInstanceUpdate(d, meta) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for update of resource instance (%s) to complete: %s", d.Id(), err) - } - - } - - if d.HasChange("tags") { - - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, instanceID) - if err != nil { - log.Printf( - "[ERROR] Error on update of Database (%s) tags: %s", d.Id(), err) - } - } - - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - icdId := EscapeUrlParm(instanceID) - - if d.HasChange("node_count") { - err = horizontalScale(d, meta, icdClient) - if err != nil { - return err - } - } - - if d.HasChange("members_memory_allocation_mb") || d.HasChange("members_disk_allocation_mb") || d.HasChange("members_cpu_allocation_count") || d.HasChange("node_memory_allocation_mb") || d.HasChange("node_disk_allocation_mb") || d.HasChange("node_cpu_allocation_count") { - params := icdv4.GroupReq{} - if d.HasChange("members_memory_allocation_mb") { - memory := d.Get("members_memory_allocation_mb").(int) - memoryReq := icdv4.MemoryReq{AllocationMb: memory} - params.GroupBdy.Memory = &memoryReq - } - if d.HasChange("node_memory_allocation_mb") || d.HasChange("node_count") { - memory := d.Get("node_memory_allocation_mb").(int) - count := d.Get("node_count").(int) - memoryReq := icdv4.MemoryReq{AllocationMb: memory * count} - params.GroupBdy.Memory = &memoryReq - } - if d.HasChange("members_disk_allocation_mb") { - disk := d.Get("members_disk_allocation_mb").(int) - diskReq := icdv4.DiskReq{AllocationMb: disk} - params.GroupBdy.Disk = &diskReq - } - if d.HasChange("node_disk_allocation_mb") || d.HasChange("node_count") { - disk := d.Get("node_disk_allocation_mb").(int) - count := d.Get("node_count").(int) - diskReq := icdv4.DiskReq{AllocationMb: disk * count} - params.GroupBdy.Disk = &diskReq - } - if d.HasChange("members_cpu_allocation_count") { - cpu := d.Get("members_cpu_allocation_count").(int) - cpuReq := icdv4.CpuReq{AllocationCount: cpu} - params.GroupBdy.Cpu = &cpuReq - } - if d.HasChange("node_cpu_allocation_mb") || d.HasChange("node_count") { - cpu := d.Get("node_cpu_allocation_count").(int) - count := d.Get("node_count").(int) - CpuReq := icdv4.CpuReq{AllocationCount: cpu * count} - params.GroupBdy.Cpu = &CpuReq - } - - task, err := icdClient.Groups().UpdateGroup(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database scaling group: %s", err) - } - - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) scaling group update task to complete: %s", icdId, err) - } - } - - if d.HasChange("auto_scaling.0.cpu") { - cpuRecord := d.Get("auto_scaling.0.cpu") - params := icdv4.AutoscalingSetGroup{} - cpuBody, err := expandICDAutoScalingGroup(d, cpuRecord, "cpu") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting cpuBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.CPU = &cpuBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database cpu auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) cpu auto_scaling group update task to complete: %s", icdId, err) - } - - } - if d.HasChange("auto_scaling.0.disk") { - diskRecord := d.Get("auto_scaling.0.disk") - params := icdv4.AutoscalingSetGroup{} - diskBody, err := expandICDAutoScalingGroup(d, diskRecord, "disk") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting diskBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.Disk = &diskBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database disk auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) disk auto_scaling group update task to complete: %s", icdId, err) - } - - } - if d.HasChange("auto_scaling.0.memory") { - memoryRecord := d.Get("auto_scaling.0.memory") - params := icdv4.AutoscalingSetGroup{} - memoryBody, err := expandICDAutoScalingGroup(d, memoryRecord, "memory") - if err != nil { - return fmt.Errorf("[ERROR] Error in getting memoryBody from expandICDAutoScalingGroup %s", err) - } - params.Autoscaling.Memory = &memoryBody - task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database memory auto_scaling group: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) memory auto_scaling group update task to complete: %s", icdId, err) - } - - } - - if d.HasChange("adminpassword") { - adminUser := d.Get("adminuser").(string) - password := d.Get("adminpassword").(string) - userParams := icdv4.UserReq{ - User: icdv4.User{ - Password: password, - }, - } - task, err := icdClient.Users().UpdateUser(icdId, adminUser, userParams) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database admin password: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) admin password update task to complete: %s", icdId, err) - } - } - - if d.HasChange("whitelist") { - oldList, newList := d.GetChange("whitelist") - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - os := oldList.(*schema.Set) - ns := newList.(*schema.Set) - remove := os.Difference(ns).List() - add := ns.Difference(os).List() - - if len(add) > 0 { - for _, entry := range add { - newEntry := entry.(map[string]interface{}) - wlEntry := icdv4.WhitelistEntry{ - Address: newEntry["address"].(string), - Description: newEntry["description"].(string), - } - whitelistReq := icdv4.WhitelistReq{ - WhitelistEntry: wlEntry, - } - task, err := icdClient.Whitelists().CreateWhitelist(icdId, whitelistReq) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database whitelist entry %v : %s", wlEntry.Address, err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) whitelist create task to complete for entry %s : %s", icdId, wlEntry.Address, err) - } - - } - - } - - if len(remove) > 0 { - for _, entry := range remove { - newEntry := entry.(map[string]interface{}) - wlEntry := icdv4.WhitelistEntry{ - Address: newEntry["address"].(string), - Description: newEntry["description"].(string), - } - ipAddress := wlEntry.Address - task, err := icdClient.Whitelists().DeleteWhitelist(icdId, ipAddress) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting database whitelist entry: %s", err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) whitelist delete task to complete for ipAddress %s : %s", icdId, ipAddress, err) - } - - } - } - } - - if d.HasChange("users") { - oldList, newList := d.GetChange("users") - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - os := oldList.(*schema.Set) - ns := newList.(*schema.Set) - remove := os.Difference(ns).List() - add := ns.Difference(os).List() - - if len(add) > 0 { - for _, entry := range add { - newEntry := entry.(map[string]interface{}) - userEntry := icdv4.User{ - UserName: newEntry["name"].(string), - Password: newEntry["password"].(string), - } - userReq := icdv4.UserReq{ - User: userEntry, - } - task, err := icdClient.Users().CreateUser(icdId, userReq) - if err != nil { - // ICD does not report if error was due to user already being defined. Check if can - // successfully update password by itself. - userParams := icdv4.UserReq{ - User: icdv4.User{ - Password: newEntry["password"].(string), - }, - } - task, err := icdClient.Users().UpdateUser(icdId, newEntry["name"].(string), userParams) - if err != nil { - return fmt.Errorf("[ERROR] Error updating database user (%s) password: %s", newEntry["name"].(string), err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) user (%s) password update task to complete: %s", icdId, newEntry["name"].(string), err) - } - } else { - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) user (%s) create task to complete: %s", icdId, newEntry["name"].(string), err) - } - } - } - - } - - if len(remove) > 0 { - for _, entry := range remove { - newEntry := entry.(map[string]interface{}) - userEntry := icdv4.User{ - UserName: newEntry["name"].(string), - Password: newEntry["password"].(string), - } - user := userEntry.UserName - task, err := icdClient.Users().DeleteUser(icdId, user) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting database user (%s) entry: %s", user, err) - } - _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) user (%s) delete task to complete: %s", icdId, user, err) - } - } - } - } - - return resourceIBMDatabaseInstanceRead(d, meta) -} - -func horizontalScale(d *schema.ResourceData, meta interface{}, icdClient icdv4.ICDServiceAPI) error { - params := icdv4.GroupReq{} - - icdId := EscapeUrlParm(d.Id()) - - members := d.Get("node_count").(int) - membersReq := icdv4.MembersReq{AllocationCount: members} - params.GroupBdy.Members = &membersReq - - _, err := icdClient.Groups().UpdateGroup(icdId, "member", params) - - if err != nil { - return fmt.Errorf("[ERROR] Error updating database scaling group: %s", err) - } - - // ScaleOut is handled with an ICD API call, however, the check is is on the instance status - _, err = waitForDatabaseInstanceUpdate(d, meta) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for database (%s) horizontal scale to complete: %s", d.Id(), err) - } - - return nil -} - -func getConnectionString(d *schema.ResourceData, userName, connectionEndpoint string, meta interface{}) (CsEntry, error) { - csEntry := CsEntry{} - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return csEntry, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - - icdId := d.Id() - connection, err := icdClient.Connections().GetConnection(icdId, userName, connectionEndpoint) - if err != nil { - return csEntry, fmt.Errorf("[ERROR] Error getting database user connection string via ICD API: %s", err) - } - - service := d.Get("service") - dbConnection := icdv4.Uri{} - var cassandraConnection icdv4.CassandraUri - - switch service { - case "databases-for-postgresql": - dbConnection = connection.Postgres - case "databases-for-redis": - dbConnection = connection.Rediss - case "databases-for-mongodb": - dbConnection = connection.Mongo - // case "databases-for-mysql": - // dbConnection = connection.Mysql - case "databases-for-elasticsearch": - dbConnection = connection.Https - case "databases-for-cassandra": - cassandraConnection = connection.Secure - case "databases-for-etcd": - dbConnection = connection.Grpc - case "messages-for-rabbitmq": - dbConnection = connection.Amqps - case "databases-for-enterprisedb": - dbConnection = connection.Postgres - default: - return csEntry, fmt.Errorf("[ERROR] Unrecognised database type during connection string lookup: %s", service) - } - - if !reflect.DeepEqual(cassandraConnection, icdv4.CassandraUri{}) { - csEntry = CsEntry{ - Name: userName, - Hosts: cassandraConnection.Hosts, - BundleName: cassandraConnection.Bundle.Name, - BundleBase64: cassandraConnection.Bundle.BundleBase64, - } - } else { - csEntry = CsEntry{ - Name: userName, - Password: "", - // Populate only first 'composed' connection string as an example - Composed: dbConnection.Composed[0], - CertName: dbConnection.Certificate.Name, - CertBase64: dbConnection.Certificate.CertificateBase64, - Hosts: dbConnection.Hosts, - Scheme: dbConnection.Scheme, - Path: dbConnection.Path, - QueryOptions: dbConnection.QueryOptions.(map[string]interface{}), - } - - // Postgres DB name is of type string, Redis is json.Number, others are nil - if dbConnection.Database != nil { - switch v := dbConnection.Database.(type) { - default: - return csEntry, fmt.Errorf("Unexpected data type: %T", v) - case json.Number: - csEntry.Database = dbConnection.Database.(json.Number).String() - case string: - csEntry.Database = dbConnection.Database.(string) - } - } else { - csEntry.Database = "" - } - } - - return csEntry, nil -} - -func resourceIBMDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - id := d.Id() - recursive := true - deleteReq := rc.DeleteResourceInstanceOptions{ - Recursive: &recursive, - ID: &id, - } - response, err := rsConClient.DeleteResourceInstance(&deleteReq) - if err != nil { - // If prior delete occurs, instance is not immediately deleted, but remains in "removed" state" - // RC 410 with "Gone" returned as error - if strings.Contains(err.Error(), "Gone") || - strings.Contains(err.Error(), "status code: 410") { - log.Printf("[WARN] Resource instance already deleted %s\n ", err) - err = nil - } else { - return fmt.Errorf("[ERROR] Error deleting resource instance: %s %s ", err, response) - } - } - - _, err = waitForDatabaseInstanceDelete(d, meta) - if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err) - } - - d.SetId("") - - return nil -} -func resourceIBMDatabaseInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("[ERROR] Error communicating with the API: %s %s", err, response) - } - if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, databaseInstanceReclamation)) { - log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") - d.SetId("") - return false, nil - } - - return *instance.ID == instanceID, nil -} - -func waitForICDReady(meta interface{}, instanceID string) error { - icdId := EscapeUrlParm(instanceID) - icdClient, clientErr := meta.(ClientSession).ICDAPI() - if clientErr != nil { - return fmt.Errorf("Error getting database client settings: %s", clientErr) - } - - // Wait for ICD Interface - err := retry(func() (err error) { - _, cdbErr := icdClient.Cdbs().GetCdb(icdId) - if cdbErr != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return fmt.Errorf("The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err) - } - return fmt.Errorf("Error getting database config for: %s with error %s\n", icdId, err) - } - return nil - }) - if err != nil { - return err - } - return nil -} - -func waitForDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}, instanceID string) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceProvisioningStatus}, - Target: []string{databaseInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil || instance == nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %s %s", d.Id(), err, response) - } - return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) - } - if *instance.State == databaseInstanceFailStatus { - return *instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %s %s", d.Id(), err, response) - } - return *instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - waitErr := waitForICDReady(meta, instanceID) - if waitErr != nil { - return false, fmt.Errorf("Error ICD interface not ready after create: %s with error %s\n", instanceID, waitErr) - - } - - return stateConf.WaitForState() -} - -func waitForDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - - stateConf := &resource.StateChangeConf{ - Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus}, - Target: []string{databaseInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %s %s", d.Id(), err, response) - } - return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) - } - if *instance.State == databaseInstanceFailStatus { - return *instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %s %s", d.Id(), err, response) - } - return *instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - waitErr := waitForICDReady(meta, instanceID) - if waitErr != nil { - return false, fmt.Errorf("Error ICD interface not ready after update: %s with error %s\n", instanceID, waitErr) - - } - - return stateConf.WaitForState() -} - -func waitForDatabaseTaskComplete(taskId string, d *schema.ResourceData, meta interface{}, t time.Duration) (bool, error) { - icdClient, err := meta.(ClientSession).ICDAPI() - if err != nil { - return false, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) - } - delayDuration := 5 * time.Second - - timeout := time.After(t) - delay := time.Tick(delayDuration) - innerTask := icdv4.Task{} - - for { - select { - case <-timeout: - return false, fmt.Errorf("[Error] Time out waiting for database task to complete") - case <-delay: - innerTask, err = icdClient.Tasks().GetTask(EscapeUrlParm(taskId)) - if err != nil { - return false, fmt.Errorf("[ERROR] The ICD Get task on database update errored: %v", err) - } - if innerTask.Status == "failed" { - return false, fmt.Errorf("[Error] Database task failed") - } - // Completed status could be returned as "" due to interaction between bluemix-go and icd task response - // Otherwise Running an queued - if innerTask.Status == "completed" || innerTask.Status == "" { - return true, nil - } - } - } -} - -func waitForDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - stateConf := &resource.StateChangeConf{ - Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, - Target: []string{databaseInstanceRemovedStatus, databaseInstanceReclamation}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return instance, databaseInstanceSuccessStatus, nil - } - return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) - } - if *instance.State == databaseInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %s %s", d.Id(), err, response) - } - return *instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func filterDatabaseDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { - supportedDeployments := []models.ServiceDeployment{} - supportedLocations := make(map[string]bool) - for _, d := range deployments { - if d.Metadata.RCCompatible { - deploymentLocation := d.Metadata.Deployment.Location - supportedLocations[deploymentLocation] = true - if deploymentLocation == location { - supportedDeployments = append(supportedDeployments, d) - } - } - } - return supportedDeployments, supportedLocations -} - -func expandICDAutoScalingGroup(d *schema.ResourceData, asRecord interface{}, asType string) (asgBody icdv4.ASGBody, err error) { - - asgRecord := asRecord.([]interface{})[0].(map[string]interface{}) - asgCapacity := icdv4.CapacityBody{} - if _, ok := asgRecord["capacity_enabled"]; ok { - asgCapacity.Enabled = asgRecord["capacity_enabled"].(bool) - asgBody.Scalers.Capacity = &asgCapacity - } - if _, ok := asgRecord["free_space_less_than_percent"]; ok { - asgCapacity.FreeSpaceLessThanPercent = asgRecord["free_space_less_than_percent"].(int) - asgBody.Scalers.Capacity = &asgCapacity - } - - // IO Payload - asgIO := icdv4.IOBody{} - if _, ok := asgRecord["io_enabled"]; ok { - asgIO.Enabled = asgRecord["io_enabled"].(bool) - asgBody.Scalers.IO = &asgIO - } - if _, ok := asgRecord["io_over_period"]; ok { - asgIO.OverPeriod = asgRecord["io_over_period"].(string) - asgBody.Scalers.IO = &asgIO - } - if _, ok := asgRecord["io_above_percent"]; ok { - asgIO.AbovePercent = asgRecord["io_above_percent"].(int) - asgBody.Scalers.IO = &asgIO - } - - // Rate Payload - asgRate := icdv4.RateBody{} - if _, ok := asgRecord["rate_increase_percent"]; ok { - asgRate.IncreasePercent = asgRecord["rate_increase_percent"].(int) - asgBody.Rate = asgRate - } - if _, ok := asgRecord["rate_period_seconds"]; ok { - asgRate.PeriodSeconds = asgRecord["rate_period_seconds"].(int) - asgBody.Rate = asgRate - } - if _, ok := asgRecord["rate_limit_mb_per_member"]; ok { - asgRate.LimitMBPerMember = asgRecord["rate_limit_mb_per_member"].(int) - asgBody.Rate = asgRate - } - if _, ok := asgRecord["rate_limit_count_per_member"]; ok { - asgRate.LimitCountPerMember = asgRecord["rate_limit_count_per_member"].(int) - asgBody.Rate = asgRate - } - if _, ok := asgRecord["rate_units"]; ok { - asgRate.Units = asgRecord["rate_units"].(string) - asgBody.Rate = asgRate - } - - return asgBody, nil -} - -func flattenICDAutoScalingGroup(autoScalingGroup icdv4.AutoscalingGetGroup) []map[string]interface{} { - result := make([]map[string]interface{}, 0) - - memorys := make([]map[string]interface{}, 0) - memory := make(map[string]interface{}) - - if autoScalingGroup.Autoscaling.Memory.Scalers.IO != nil { - memoryIO := *autoScalingGroup.Autoscaling.Memory.Scalers.IO - memory["io_enabled"] = memoryIO.Enabled - memory["io_over_period"] = memoryIO.OverPeriod - memory["io_above_percent"] = memoryIO.AbovePercent - } - if &autoScalingGroup.Autoscaling.Memory.Rate != nil { - ip, _ := autoScalingGroup.Autoscaling.Memory.Rate.IncreasePercent.Float64() - memory["rate_increase_percent"] = int(ip) - memory["rate_period_seconds"] = autoScalingGroup.Autoscaling.Memory.Rate.PeriodSeconds - lmp, _ := autoScalingGroup.Autoscaling.Memory.Rate.LimitMBPerMember.Float64() - memory["rate_limit_mb_per_member"] = int(lmp) - memory["rate_units"] = autoScalingGroup.Autoscaling.Memory.Rate.Units - } - memorys = append(memorys, memory) - - cpus := make([]map[string]interface{}, 0) - cpu := make(map[string]interface{}) - - if &autoScalingGroup.Autoscaling.CPU.Rate != nil { - - ip, _ := autoScalingGroup.Autoscaling.CPU.Rate.IncreasePercent.Float64() - cpu["rate_increase_percent"] = int(ip) - cpu["rate_period_seconds"] = autoScalingGroup.Autoscaling.CPU.Rate.PeriodSeconds - cpu["rate_limit_count_per_member"] = autoScalingGroup.Autoscaling.CPU.Rate.LimitCountPerMember - cpu["rate_units"] = autoScalingGroup.Autoscaling.CPU.Rate.Units - } - cpus = append(cpus, cpu) - - disks := make([]map[string]interface{}, 0) - disk := make(map[string]interface{}) - if autoScalingGroup.Autoscaling.Disk.Scalers.Capacity != nil { - diskCapacity := *autoScalingGroup.Autoscaling.Disk.Scalers.Capacity - disk["capacity_enabled"] = diskCapacity.Enabled - disk["free_space_less_than_percent"] = diskCapacity.FreeSpaceLessThanPercent - } - if autoScalingGroup.Autoscaling.Disk.Scalers.IO != nil { - diskIO := *autoScalingGroup.Autoscaling.Disk.Scalers.IO - disk["io_enabled"] = diskIO.Enabled - disk["io_over_period"] = diskIO.OverPeriod - disk["io_above_percent"] = diskIO.AbovePercent - } - if &autoScalingGroup.Autoscaling.Disk.Rate != nil { - - ip, _ := autoScalingGroup.Autoscaling.Disk.Rate.IncreasePercent.Float64() - disk["rate_increase_percent"] = int(ip) - disk["rate_period_seconds"] = autoScalingGroup.Autoscaling.Disk.Rate.PeriodSeconds - lpm, _ := autoScalingGroup.Autoscaling.Disk.Rate.LimitMBPerMember.Float64() - disk["rate_limit_mb_per_member"] = int(lpm) - disk["rate_units"] = autoScalingGroup.Autoscaling.Disk.Rate.Units - } - - disks = append(disks, disk) - as := map[string]interface{}{ - "memory": memorys, - "cpu": cpus, - "disk": disks, - } - result = append(result, as) - return result -} diff --git a/ibm/resource_ibm_database_cassandra_test.go b/ibm/resource_ibm_database_cassandra_test.go deleted file mode 100644 index d5fe0eb0e..000000000 --- a/ibm/resource_ibm_database_cassandra_test.go +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMCassandraDatabaseInstanceBasic(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceCassandraBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "36864"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceCassandraFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "38400"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceCassandraReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "36864"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMDatabaseInstance_Cassandra_Node(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceCassandraNodeBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), - - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceCassandraNodeFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12416"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceCassandraNodeReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceCassandraNodeScaleOut(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "4"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - //{ - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - //}, - }, - }) -} - -// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests - -func TestAccIBMDatabaseInstanceCassandraImport(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - serviceName := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" - resourceName := "ibm_database." + serviceName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceCassandraImport(databaseResourceGroup, serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "databases-for-cassandra"), - resource.TestCheckResourceAttr(resourceName, "plan", "enterprise"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "plan_validation"}, - }, - }, - }) -} - -// func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) etc in resource_ibm_database_postgresql_test.go - -func testAccCheckIBMDatabaseInstanceCassandraBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 36864 - members_disk_allocation_mb = 61440 - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 38400 - members_disk_allocation_mb = 61440 - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 36864 - members_disk_allocation_mb = 61440 - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraNodeBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 12288 - node_disk_allocation_mb = 20480 - node_cpu_allocation_count = 6 - - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraNodeFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 12416 - node_disk_allocation_mb = 20480 - node_cpu_allocation_count = 6 - - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraNodeReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 12288 - node_disk_allocation_mb = 20480 - node_cpu_allocation_count = 6 - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraNodeScaleOut(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - node_count = 4 - node_memory_allocation_mb = 12288 - node_disk_allocation_mb = 20480 - node_cpu_allocation_count = 6 - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceCassandraImport(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-cassandra" - plan = "enterprise" - location = "us-south" - - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - - } - - - - `, databaseResourceGroup, name) -} diff --git a/ibm/resource_ibm_database_elasticsearch_test.go b/ibm/resource_ibm_database_elasticsearch_test.go deleted file mode 100644 index 2d7dcf636..000000000 --- a/ibm/resource_ibm_database_elasticsearch_test.go +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMDatabaseInstance_Elasticsearch_Basic(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "15360"), - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "18432"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "18432"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - // { - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - // }, - }, - }) -} - -func TestAccIBMDatabaseInstance_Elasticsearch_Node(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "5120"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeScaleOut(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "4"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - ), - }, - //{ - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - //}, - }, - }) -} - -// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests - -func TestAccIBMDatabaseInstanceElasticsearchImport(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - serviceName := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" - resourceName := "ibm_database." + serviceName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceElasticsearchImport(databaseResourceGroup, serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "databases-for-elasticsearch"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "plan_validation"}, - }, - }, - }) -} - -// func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) etc in resource_ibm_database_postgresql_test.go - -func testAccCheckIBMDatabaseInstanceElasticsearchBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 3072 - members_disk_allocation_mb = 15360 - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 6144 - members_disk_allocation_mb = 18432 - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 3072 - members_disk_allocation_mb = 18432 - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchNodeBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 5120 - node_cpu_allocation_count = 3 - - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchNodeFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 6144 - node_cpu_allocation_count = 3 - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchNodeReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 6144 - node_cpu_allocation_count = 3 - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchNodeScaleOut(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 4 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 6144 - node_cpu_allocation_count = 3 - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceElasticsearchImport(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-elasticsearch" - plan = "standard" - location = "us-south" - - timeouts { - create = "120m" - update = "120m" - delete = "15m" - } - } - - `, databaseResourceGroup, name) -} diff --git a/ibm/resource_ibm_database_mogodb_enterprise_test.go b/ibm/resource_ibm_database_mogodb_enterprise_test.go deleted file mode 100644 index 5d092938a..000000000 --- a/ibm/resource_ibm_database_mogodb_enterprise_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMMongoDBEnterpriseDatabaseInstanceBasic(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-mongoEnterprise-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "43008"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public"), - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "86016"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "122880"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "mongodb"), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), - resource.TestCheckResourceAttr(name, "plan", "enterprise"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "43008"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "122880"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "plan_validation", "adminpassword", "connectionstrings.0.queryoptions"}, - }, - }, - }) -} - -func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-mongodb" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_disk_allocation_mb = 61440 - members_memory_allocation_mb = 43008 - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-mongodb" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 86016 - members_disk_allocation_mb = 122880 - members_cpu_allocation_count = 27 - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-mongodb" - plan = "enterprise" - location = "us-south" - adminpassword = "password12" - members_disk_allocation_mb = 122880 - members_memory_allocation_mb = 43008 - service_endpoints = "public" - tags = ["one:two"] - timeouts { - create = "480m" - update = "480m" - delete = "15m" - } - } - `, databaseResourceGroup, name) -} diff --git a/ibm/resource_ibm_database_postgresql_test.go b/ibm/resource_ibm_database_postgresql_test.go deleted file mode 100644 index 650bf8f16..000000000 --- a/ibm/resource_ibm_database_postgresql_test.go +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "reflect" - "regexp" - "strings" - "testing" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/models" -) - -func TestAccIBMDatabaseInstance_Postgres_Basic(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "10240"), - resource.TestCheckResourceAttr(name, "members_cpu_allocation_count", "0"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public"), - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "4096"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "14336"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "postgres"), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstancePostgresReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), - resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "14336"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - // { - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - // }, - }, - }) -} - -func TestAccIBMDatabaseInstance_Postgres_Node(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - testName := rnd - name := "ibm_database." + testName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstancePostgresNodeBasic(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "adminuser", "admin"), - resource.TestCheckResourceAttr(name, "node_count", "2"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "5120"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public"), - resource.TestCheckResourceAttr(name, "whitelist.#", "1"), - resource.TestCheckResourceAttr(name, "users.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstancePostgresNodeFullyspecified(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "2"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), - resource.TestCheckResourceAttr(name, "whitelist.#", "2"), - resource.TestCheckResourceAttr(name, "users.#", "2"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), - resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), - resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "postgres"), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), - resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstancePostgresNodeReduced(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "2"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - { - Config: testAccCheckIBMDatabaseInstancePostgresNodeScaleOut(databaseResourceGroup, testName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), - resource.TestCheckResourceAttr(name, "name", testName), - resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "node_count", "3"), - resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), - resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), - resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), - resource.TestCheckResourceAttr(name, "whitelist.#", "0"), - resource.TestCheckResourceAttr(name, "users.#", "0"), - resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), - resource.TestCheckResourceAttr(name, "tags.#", "1"), - ), - }, - // { - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - // }, - }, - }) -} - -// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests - -func TestAccIBMDatabaseInstancePostgresImport(t *testing.T) { - t.Parallel() - databaseResourceGroup := "default" - var databaseInstanceOne string - serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" - resourceName := "ibm_database." + serviceName - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup, serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "plan_validation"}, - }, - }, - }) -} - -func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_database" { - continue - } - - instanceID := rs.Primary.ID - - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsContClient.GetResourceInstance(&rsInst) - if err == nil { - if !reflect.DeepEqual(instance, models.ServiceInstance{}) && *instance.State == "active" { - return fmt.Errorf("Database still exists: %s", rs.Primary.ID) - } - } else { - if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if database (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) - } - } - } - return nil -} - -func testAccDatabaseInstanceManuallyDelete(tfDatabaseID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _ = testAccDatabaseInstanceManuallyDeleteUnwrapped(s, tfDatabaseID) - return nil - } -} - -func testAccDatabaseInstanceManuallyDeleteUnwrapped(s *terraform.State, tfDatabaseID *string) error { - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instance := *tfDatabaseID - var instanceID string - if strings.HasPrefix(instance, "crn") { - instanceID = instance - } else { - _, instanceID, _ = convertTftoCisTwoVar(instance) - } - recursive := true - deleteReq := rc.DeleteResourceInstanceOptions{ - ID: &instanceID, - Recursive: &recursive, - } - response, err := rsConClient.DeleteResourceInstance(&deleteReq) - if err != nil { - return fmt.Errorf("Error deleting resource instance: %s %s", err, response) - } - - _ = &resource.StateChangeConf{ - Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, - Target: []string{databaseInstanceRemovedStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return instance, databaseInstanceSuccessStatus, nil - } - return nil, "", err - } - if *instance.State == databaseInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed to delete: %v %s", instanceID, err, response) - } - return instance, *instance.State, nil - }, - Timeout: 90 * time.Second, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - if err != nil { - return fmt.Errorf( - "Error waiting for resource instance (%s) to be deleted: %s", instanceID, err) - } - return nil -} - -func testAccCheckIBMDatabaseInstanceExists(n string, tfDatabaseID *string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instanceID := rs.Primary.ID - - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsContClient.GetResourceInstance(&rsInst) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - *tfDatabaseID = "" - return nil - } - return fmt.Errorf("Error retrieving resource instance: %s %s", err, response) - } - if strings.Contains(*instance.State, "removed") { - *tfDatabaseID = "" - return nil - } - - *tfDatabaseID = instanceID - return nil - } -} - -func testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 2048 - members_disk_allocation_mb = 10240 - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 4096 - members_disk_allocation_mb = 14336 - members_cpu_allocation_count = 6 - service_endpoints = "public-and-private" - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - members_memory_allocation_mb = 2048 - members_disk_allocation_mb = 14336 - service_endpoints = "public" - tags = ["one:two"] - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresNodeBasic(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 2 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 7168 - node_cpu_allocation_count = 3 - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresNodeFullyspecified(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 2 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 7168 - node_cpu_allocation_count = 3 - service_endpoints = "public-and-private" - tags = ["one:two"] - users { - name = "user123" - password = "password12" - } - users { - name = "user124" - password = "password12" - } - whitelist { - address = "172.168.1.2/32" - description = "desc1" - } - whitelist { - address = "172.168.1.1/32" - description = "desc" - } - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresNodeReduced(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 2 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 7168 - node_cpu_allocation_count = 3 - service_endpoints = "public" - tags = ["one:two"] - } - `, databaseResourceGroup, name) -} -func testAccCheckIBMDatabaseInstancePostgresNodeScaleOut(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - adminpassword = "password12" - node_count = 3 - node_memory_allocation_mb = 1024 - node_disk_allocation_mb = 7168 - node_cpu_allocation_count = 3 - service_endpoints = "public" - tags = ["one:two"] - } - `, databaseResourceGroup, name) -} - -func testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup string, name string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "us-south" - } - `, databaseResourceGroup, name) -} diff --git a/ibm/resource_ibm_dns_reverse_record.go b/ibm/resource_ibm_dns_reverse_record.go deleted file mode 100644 index c2cf5f0ab..000000000 --- a/ibm/resource_ibm_dns_reverse_record.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strconv" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/softlayer/softlayer-go/services" - "github.com/softlayer/softlayer-go/sl" -) - -func resourceIBMDNSReverseRecord() *schema.Resource { - return &schema.Resource{ - Exists: resourceIBMDNSREVERSERecordExists, - Create: resourceIBMDNSREVERSERecordCreate, - Read: resourceIBMDNSREVERSERecordRead, - Update: resourceIBMDNSREVERSERecordUpdate, - Delete: resourceIBMDNSREVERSERecordDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - "ipaddress": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "IP Address", - }, - "hostname": { - Type: schema.TypeString, - Required: true, - Description: "Host name", - }, - "ttl": { - Type: schema.TypeInt, - Optional: true, - DefaultFunc: func() (interface{}, error) { - return 604800, nil - }, - Description: "TTL value", - }, - }, - } -} - -// Creates DNS Domain Reverse Record -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain/CreatePtrRecord -func resourceIBMDNSREVERSERecordCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetDnsDomainService(sess.SetRetries(0)) - Data := sl.String(d.Get("hostname").(string)) - Ttl := sl.Int(d.Get("ttl").(int)) - Ipaddress := sl.String(d.Get("ipaddress").(string)) - var id int - record, err := service.CreatePtrRecord(Ipaddress, Data, Ttl) - if record.Id != nil { - id = *record.Id - } - - if err != nil { - return fmt.Errorf("Error creating DNS Reverse %s", err) - } - d.SetId(fmt.Sprintf("%d", id)) - log.Printf("[INFO] Dns Reverse %s ", d.Id()) - return resourceIBMDNSREVERSERecordRead(d, meta) -} - -// Reads DNS Domain Reverse Record from SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/getObject -func resourceIBMDNSREVERSERecordRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetDnsDomainResourceRecordService(sess) - id, err := strconv.Atoi(d.Id()) - if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) - } - - _, nexterr := service.Id(id).GetObject() - if nexterr != nil { - return fmt.Errorf("Error retrieving DNS Reverse Record: %s", err) - } - return nil -} - -// Updates DNS Domain Reverse Record in SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/editObject -func resourceIBMDNSREVERSERecordUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetDnsDomainResourceRecordService(sess) - serviceNoRetry := services.GetDnsDomainResourceRecordService(sess.SetRetries(0)) - recordId, _ := strconv.Atoi(d.Id()) - record, err := service.Id(recordId).GetObject() - if err != nil { - return fmt.Errorf("Error retrieving DNS Reverse Record: %s", err) - } - if data, ok := d.GetOk("hostname"); ok && d.HasChange("hostname") { - record.Data = sl.String(data.(string)) - } - if ttl, ok := d.GetOk("ttl"); ok && d.HasChange("ttl") { - record.Ttl = sl.Int(ttl.(int)) - } - record.IsGatewayAddress = nil - _, err = serviceNoRetry.Id(recordId).EditObject(&record) - if err != nil { - return fmt.Errorf("Error editing DNS Reverse Record %d: %s", recordId, err) - } - return nil -} - -// Deletes DNS Domain Reverse Record in SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/deleteObject -func resourceIBMDNSREVERSERecordDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetDnsDomainResourceRecordService(sess) - id, err := strconv.Atoi(d.Id()) - if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) - } - _, err = service.Id(id).DeleteObject() - - if err != nil { - return fmt.Errorf("Error deleting DNS Reverse Record: %s", err) - } - return nil -} - -// Exists function is called by refresh -// if the entity is absent - it is deleted from the .tfstate file -func resourceIBMDNSREVERSERecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() - service := services.GetDnsDomainResourceRecordService(sess) - id, err := strconv.Atoi(d.Id()) - if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) - } - record, err := service.Id(id).GetObject() - if err != nil { - if apiErr, ok := err.(sl.Error); ok { - if apiErr.StatusCode == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error retrieving domain reverse record info: %s", err) - } - return record.Id != nil && *record.Id == id, nil -} diff --git a/ibm/resource_ibm_en_subscription.go b/ibm/resource_ibm_en_subscription.go deleted file mode 100644 index 6ff7c932a..000000000 --- a/ibm/resource_ibm_en_subscription.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" - "github.com/IBM/go-sdk-core/v5/core" -) - -func resourceIBMEnSubscription() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMEnSubscriptionCreate, - ReadContext: resourceIBMEnSubscriptionRead, - UpdateContext: resourceIBMEnSubscriptionUpdate, - DeleteContext: resourceIBMEnSubscriptionDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "instance_guid": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Unique identifier for IBM Cloud Event Notifications instance.", - }, - "name": { - Type: schema.TypeString, - Required: true, - Description: "Subscription name.", - }, - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Subscription description.", - }, - "destination_id": { - Type: schema.TypeString, - Required: true, - Description: "Destination ID.", - }, - "topic_id": { - Type: schema.TypeString, - Required: true, - Description: "Topic ID.", - }, - "attributes": { - Type: schema.TypeList, - MaxItems: 1, - Required: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "to": { - Type: schema.TypeList, - Optional: true, - Description: "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "add_notification_payload": { - Type: schema.TypeBool, - Optional: true, - Description: "Whether to add the notification payload to the email.", - }, - "reply_to": { - Type: schema.TypeString, - Optional: true, - Description: "The email address to reply to.", - }, - "signing_enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Signing webhook attributes.", - }, - }, - }, - }, - "subscription_id": { - Type: schema.TypeString, - Computed: true, - Description: "Subscription ID.", - }, - "destination_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of Destination Webhook.", - }, - "destination_name": { - Type: schema.TypeString, - Computed: true, - Description: "The Destintion name.", - }, - "topic_name": { - Type: schema.TypeString, - Computed: true, - Description: "Name of the topic.", - }, - "from": { - Type: schema.TypeString, - Computed: true, - Description: "From Email ID (it will be displayed only in case of smtp_ibm destination type).", - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "Last updated time.", - }, - }, - } -} - -func resourceIBMEnSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - options := &en.CreateSubscriptionOptions{} - - options.SetInstanceID(d.Get("instance_guid").(string)) - - options.SetName(d.Get("name").(string)) - options.SetTopicID(d.Get("topic_id").(string)) - options.SetDestinationID(d.Get("destination_id").(string)) - - if _, ok := d.GetOk("description"); ok { - options.SetDescription(d.Get("description").(string)) - } - - attributes, _ := attributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) - options.SetAttributes(&attributes) - - result, response, err := enClient.CreateSubscriptionWithContext(context, options) - if err != nil { - return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) - - return resourceIBMEnSubscriptionRead(context, d, meta) -} - -func resourceIBMEnSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - options := &en.GetSubscriptionOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - options.SetInstanceID(parts[0]) - options.SetID(parts[1]) - - result, response, err := enClient.GetSubscriptionWithContext(context, options) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) - } - - if err = d.Set("instance_guid", options.InstanceID); err != nil { - return diag.FromErr(fmt.Errorf("error setting instance_guid: %s", err)) - } - - if err = d.Set("subscription_id", result.ID); err != nil { - return diag.FromErr(fmt.Errorf("error setting instance_guid: %s", err)) - } - - if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) - } - - if result.Description != nil { - if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) - } - } - - if result.From != nil { - if err = d.Set("from", result.From); err != nil { - return diag.FromErr(fmt.Errorf("error setting from: %s", err)) - } - } - - if err = d.Set("destination_id", result.DestinationID); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_id: %s", err)) - } - - if err = d.Set("destination_type", result.DestinationType); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_type: %s", err)) - } - - if result.DestinationName != nil { - if err = d.Set("destination_name", result.DestinationName); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_name: %s", err)) - } - } - - if err = d.Set("topic_id", result.TopicID); err != nil { - return diag.FromErr(fmt.Errorf("error setting topic_id: %s", err)) - } - - if result.TopicName != nil { - if err = d.Set("topic_name", result.TopicName); err != nil { - return diag.FromErr(fmt.Errorf("error setting topic_name: %s", err)) - } - } - - if err = d.Set("updated_at", result.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) - } - - return nil -} - -func resourceIBMEnSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - options := &en.UpdateSubscriptionOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - options.SetInstanceID(parts[0]) - options.SetID(parts[1]) - - if ok := d.HasChanges("name", "description", "attributes"); ok { - options.SetName(d.Get("name").(string)) - - if _, ok := d.GetOk("description"); ok { - options.SetDescription(d.Get("description").(string)) - } - - _, attributes := attributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) - options.SetAttributes(&attributes) - - _, response, err := enClient.UpdateSubscriptionWithContext(context, options) - if err != nil { - return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) - } - - return resourceIBMEnSubscriptionRead(context, d, meta) - } - - return nil -} - -func resourceIBMEnSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() - if err != nil { - return diag.FromErr(err) - } - - options := &en.DeleteSubscriptionOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - options.SetInstanceID(parts[0]) - options.SetID(parts[1]) - - response, err := enClient.DeleteSubscriptionWithContext(context, options) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} - -func attributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributes) { - attributesCreate := en.SubscriptionCreateAttributes{} - attributesUpdate := en.SubscriptionUpdateAttributes{} - - if attributeMap["to"] != nil { - to := []string{} - for _, toItem := range attributeMap["to"].([]interface{}) { - to = append(to, toItem.(string)) - } - attributesCreate.To = to - attributesUpdate.To = to - } - - if attributeMap["add_notification_payload"] != nil { - attributesCreate.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) - attributesUpdate.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) - } - - if attributeMap["reply_to"] != nil { - attributesCreate.ReplyTo = core.StringPtr(attributeMap["reply_to"].(string)) - attributesUpdate.ReplyTo = core.StringPtr(attributeMap["reply_to"].(string)) - } - - if attributeMap["signing_enabled"] != nil { - attributesCreate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) - attributesUpdate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) - } - - return attributesCreate, attributesUpdate -} diff --git a/ibm/resource_ibm_function_action.go b/ibm/resource_ibm_function_action.go deleted file mode 100644 index f4bbd86a1..000000000 --- a/ibm/resource_ibm_function_action.go +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net/http" - "os" - "strings" - - "github.com/apache/openwhisk-client-go/whisk" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - funcActionName = "name" - funcActionNamespace = "namespace" - funcActionUsrDefAnnots = "user_defined_annotations" - funcActionUsrDefParams = "user_defined_parameters" -) - -func resourceIBMFunctionAction() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMFunctionActionCreate, - Read: resourceIBMFunctionActionRead, - Update: resourceIBMFunctionActionUpdate, - Delete: resourceIBMFunctionActionDelete, - Exists: resourceIBMFunctionActionExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - funcActionName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Name of action.", - ValidateFunc: InvokeValidator("ibm_function_action", funcActionName), - }, - funcActionNamespace: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "IBM Cloud function namespace.", - ValidateFunc: InvokeValidator("ibm_function_action", funcActionNamespace), - }, - "limits": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "timeout": { - Type: schema.TypeInt, - Optional: true, - Default: 60000, - Description: "The timeout LIMIT in milliseconds after which the action is terminated.", - }, - "memory": { - Type: schema.TypeInt, - Optional: true, - Default: 256, - Description: "The maximum memory LIMIT in MB for the action (default 256.", - }, - "log_size": { - Type: schema.TypeInt, - Optional: true, - Default: 10, - Description: "The maximum log size LIMIT in MB for the action.", - }, - }, - }, - }, - "exec": { - Type: schema.TypeList, - Required: true, - MaxItems: 1, - Description: "Execution info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "image": { - Type: schema.TypeString, - Optional: true, - Description: "Container image name when kind is 'blackbox'.", - ConflictsWith: []string{"exec.0.components"}, - }, - "init": { - Type: schema.TypeString, - Optional: true, - Description: "Optional zipfile reference.", - ConflictsWith: []string{"exec.0.image", "exec.0.components"}, - }, - "code": { - Type: schema.TypeString, - Computed: true, - Optional: true, - Description: "The code to execute.", - ConflictsWith: []string{"exec.0.components", "exec.0.code_path"}, - }, - "code_path": { - Type: schema.TypeString, - Optional: true, - Description: "The file path of code to execute.", - ConflictsWith: []string{"exec.0.components", "exec.0.code"}, - }, - "kind": { - Type: schema.TypeString, - Required: true, - Description: "The type of action. Possible values can be found here (https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-runtimes)", - }, - "main": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the action entry point (function or fully-qualified method name when applicable).", - ConflictsWith: []string{"exec.0.image", "exec.0.components"}, - }, - "components": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The List of fully qualified action.", - ConflictsWith: []string{"exec.0.image", "exec.0.code", "exec.0.code_path"}, - }, - }, - }, - }, - "publish": { - Type: schema.TypeBool, - Optional: true, - Description: "Action visibilty.", - }, - "version": { - Type: schema.TypeString, - Computed: true, - Description: "Semantic version of the item.", - }, - funcActionUsrDefAnnots: { - Type: schema.TypeString, - Optional: true, - Default: "[]", - Description: "Annotation values in KEY VALUE format.", - ValidateFunc: InvokeValidator("ibm_function_action", funcActionUsrDefAnnots), - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - funcActionUsrDefParams: { - Type: schema.TypeString, - Optional: true, - Default: "[]", - Description: "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the action.", - ValidateFunc: InvokeValidator("ibm_function_action", funcActionUsrDefParams), - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - "annotations": { - Type: schema.TypeString, - Computed: true, - Description: "All annotations set on action by user and those set by the IBM Cloud Function backend/API.", - }, - "parameters": { - Type: schema.TypeString, - Computed: true, - Description: "All paramters set on action by user and those set by the IBM Cloud Function backend/API.", - }, - "action_id": { - Type: schema.TypeString, - Computed: true, - }, - "target_endpoint_url": { - Type: schema.TypeString, - Computed: true, - Description: "Action target endpoint URL.", - }, - }, - } -} - -func resourceIBMFuncActionValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcActionName, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `^[^/*][a-zA-Z0-9/_@.-]`, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcActionNamespace, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcActionUsrDefAnnots, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Default: "[]", - Optional: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcActionUsrDefParams, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Optional: true}) - - ibmFuncActionResourceValidator := ResourceValidator{ResourceName: "ibm_function_action", Schema: validateSchema} - return &ibmFuncActionResourceValidator -} - -func resourceIBMFunctionActionCreate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - actionService := wskClient.Actions - name := d.Get("name").(string) - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(name); err != nil { - return NewQualifiedNameError(name, err) - } - - payload := whisk.Action{ - Name: qualifiedName.GetEntityName(), - Namespace: namespace, - } - - exec := d.Get("exec").([]interface{}) - payload.Exec = expandExec(exec) - - userDefinedAnnotations := d.Get("user_defined_annotations").(string) - payload.Annotations, err = expandAnnotations(userDefinedAnnotations) - if err != nil { - return err - } - - userDefinedParameters := d.Get("user_defined_parameters").(string) - payload.Parameters, err = expandParameters(userDefinedParameters) - if err != nil { - return err - } - - if v, ok := d.GetOk("limits"); ok { - payload.Limits = expandLimits(v.([]interface{})) - } - - if publish, ok := d.GetOk("publish"); ok { - p := publish.(bool) - payload.Publish = &p - } - - log.Println("[INFO] Creating IBM Cloud Function Action") - _, _, err = actionService.Insert(&payload, true) - - if err != nil { - return fmt.Errorf("Error creating IBM Cloud Function Action: %s", err) - } - - d.SetId(fmt.Sprintf("%s:%s", namespace, qualifiedName.GetEntityName())) - - return resourceIBMFunctionActionRead(d, meta) -} - -func resourceIBMFunctionActionRead(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := "" - actionID := "" - if len(parts) == 2 { - namespace = parts[0] - actionID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - actionID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, actionID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - actionService := wskClient.Actions - action, _, err := actionService.Get(actionID, true) - if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Action %s : %s", actionID, err) - } - d.Set("namespace", namespace) - d.Set("limits", flattenLimits(action.Limits)) - d.Set("exec", flattenExec(action.Exec, d)) - d.Set("publish", action.Publish) - d.Set("version", action.Version) - d.Set("action_id", action.Name) - annotations, err := flattenAnnotations(action.Annotations) - if err != nil { - return err - } - - d.Set("annotations", annotations) - parameters, err := flattenParameters(action.Parameters) - if err != nil { - return err - } - d.Set("parameters", parameters) - - temp := strings.Split(action.Namespace, "/") - pkgName := "" - if len(temp) == 2 { - pkgName = temp[1] - d.Set("name", fmt.Sprintf("%s/%s", pkgName, action.Name)) - c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ - Namespace: wskClient.Namespace, - AuthToken: wskClient.AuthToken, - Host: wskClient.Host, - AdditionalHeaders: wskClient.AdditionalHeaders, - }) - - pkg, _, err := c.Packages.Get(pkgName) - if err != nil { - return fmt.Errorf("Error retrieving package IBM Cloud Function package %s : %s", pkgName, err) - } - - userAnnotations, err := flattenAnnotations(filterInheritedAnnotations(pkg.Annotations, action.Annotations)) - if err != nil { - return err - } - - d.Set("user_defined_annotations", userAnnotations) - userParameters, err := flattenParameters(filterInheritedParameters(pkg.Parameters, action.Parameters)) - if err != nil { - return err - } - d.Set("user_defined_parameters", userParameters) - } else { - d.Set("name", action.Name) - userDefinedAnnotations, err := filterActionAnnotations(action.Annotations) - if err != nil { - return err - } - d.Set("user_defined_annotations", userDefinedAnnotations) - - userDefinedParameters, err := filterActionParameters(action.Parameters) - if err != nil { - return err - } - d.Set("user_defined_parameters", userDefinedParameters) - } - - targetUrl, err := action.ActionURL(wskClient.Config.Host, "/api", wskClient.Config.Version, pkgName) - if err != nil { - log.Printf( - "Error creating target endpoint URL for action (%s) targetURL : %s", d.Id(), err) - - } - d.Set("target_endpoint_url", targetUrl) - - return nil -} - -func resourceIBMFunctionActionUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - actionID := parts[1] - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - actionService := wskClient.Actions - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(actionID); err != nil { - return NewQualifiedNameError(actionID, err) - } - - payload := whisk.Action{ - Name: qualifiedName.GetEntityName(), - Namespace: namespace, - } - - ischanged := false - - if d.HasChange("publish") { - p := d.Get("publish").(bool) - payload.Publish = &p - } - - if d.HasChange("user_defined_parameters") { - var err error - payload.Parameters, err = expandParameters(d.Get("user_defined_parameters").(string)) - if err != nil { - return err - } - ischanged = true - } - - if d.HasChange("user_defined_annotations") { - var err error - payload.Annotations, err = expandAnnotations(d.Get("user_defined_annotations").(string)) - if err != nil { - return err - } - ischanged = true - } - - if d.HasChange("exec") { - exec := d.Get("exec").([]interface{}) - payload.Exec = expandExec(exec) - ischanged = true - } - - if d.HasChange("limits") { - limits := d.Get("limits").([]interface{}) - payload.Limits = expandLimits(limits) - ischanged = true - } - - if ischanged { - log.Println("[INFO] Update IBM Cloud Function Action") - _, _, err = actionService.Insert(&payload, true) - if err != nil { - return fmt.Errorf("Error updating IBM Cloud Function Action: %s", err) - } - } - - return resourceIBMFunctionActionRead(d, meta) -} - -func resourceIBMFunctionActionDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - actionID := parts[1] - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - actionService := wskClient.Actions - - _, err = actionService.Delete(actionID) - if err != nil { - return fmt.Errorf("Error deleting IBM Cloud Function Action: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMFunctionActionExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := cfIdParts(d.Id()) - if err != nil { - return false, err - } - - namespace := "" - actionID := "" - if len(parts) >= 2 { - namespace = parts[0] - actionID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - actionID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, actionID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return false, err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return false, err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return false, err - - } - - actionService := wskClient.Actions - - action, resp, err := actionService.Get(actionID, true) - if err != nil { - if resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with IBM Cloud Function Client : %s", err) - } - - temp := strings.Split(action.Namespace, "/") - var name string - - if len(temp) == 2 { - name = fmt.Sprintf("%s/%s", temp[1], action.Name) - } else { - name = action.Name - } - - return name == actionID, nil -} diff --git a/ibm/resource_ibm_function_namespace.go b/ibm/resource_ibm_function_namespace.go deleted file mode 100644 index 87364d152..000000000 --- a/ibm/resource_ibm_function_namespace.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strings" - - "github.com/IBM-Cloud/bluemix-go/api/functions" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - funcNamespaceName = "name" - funcNamespaceResGrpId = "resource_group_id" - funcNamespaceResPlanId = "resource_plan_id" - funcNamespaceDesc = "description" - funcNamespaceLoc = "location" -) - -func resourceIBMFunctionNamespace() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMFunctionNamespaceCreate, - Read: resourceIBMFunctionNamespaceRead, - Update: resourceIBMFunctionNamespaceUpdate, - Delete: resourceIBMFunctionNamespaceDelete, - Exists: resourceIBMFunctionNamespaceExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - funcNamespaceName: { - Type: schema.TypeString, - Required: true, - Description: "Name of namespace.", - ValidateFunc: InvokeValidator("ibm_function_namespace", funcNamespaceName), - }, - funcNamespaceDesc: { - Type: schema.TypeString, - Optional: true, - Description: "Namespace Description.", - }, - funcNamespaceResGrpId: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Resource Group ID.", - ValidateFunc: InvokeValidator("ibm_function_namespace", funcNamespaceResGrpId), - }, - funcNamespaceLoc: { - Type: schema.TypeString, - Computed: true, - Description: "Namespace Location.", - }, - }, - } -} - -func resourceIBMFuncNamespaceValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcNamespaceName, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcNamespaceResGrpId, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - - ibmFuncNamespaceResourceValidator := ResourceValidator{ResourceName: "ibm_function_namespace", Schema: validateSchema} - return &ibmFuncNamespaceResourceValidator -} - -func resourceIBMFunctionNamespaceCreate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - createNamespaceOptions := functions.CreateNamespaceOptions{} - - name := d.Get(funcNamespaceName).(string) - createNamespaceOptions.Name = &name - resourceGroupID := d.Get(funcNamespaceResGrpId).(string) - createNamespaceOptions.ResourceGroupID = &resourceGroupID - resourcePlanID := "functions-base-plan" - createNamespaceOptions.ResourcePlanID = &resourcePlanID - - if _, ok := d.GetOk(funcNamespaceDesc); ok { - description := d.Get(funcNamespaceDesc).(string) - createNamespaceOptions.Description = &description - } - - namespace, err := functionNamespaceAPI.Namespaces().CreateNamespace(createNamespaceOptions) - if err != nil { - return fmt.Errorf("Error Creating Namespace: %s", err) - } - - d.SetId(*namespace.ID) - log.Printf("[INFO] Created namespace (IAM) : %s", *namespace.Name) - - return resourceIBMFunctionNamespaceRead(d, meta) -} - -func resourceIBMFunctionNamespaceRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - id := d.Id() - - getOptions := functions.GetNamespaceOptions{ - ID: &id, - } - instance, err := functionNamespaceAPI.Namespaces().GetNamespace(getOptions) - if err != nil { - if strings.Contains(err.Error(), "404") { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting namesapce (IAM): %s", err) - } - - if instance.Name != nil { - d.Set(funcNamespaceName, *instance.Name) - } - - if instance.ResourceGroupID != nil { - d.Set(funcNamespaceResGrpId, *instance.ResourceGroupID) - } - - if instance.Location != nil { - d.Set(funcNamespaceLoc, *instance.Location) - } - if instance.Description != nil { - d.Set(funcNamespaceDesc, *instance.Description) - } - - return nil -} - -func resourceIBMFunctionNamespaceUpdate(d *schema.ResourceData, meta interface{}) error { - nsClient, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - ID := d.Id() - updateNamespaceOptions := functions.UpdateNamespaceOptions{} - if d.HasChange(funcNamespaceName) { - name := d.Get(funcNamespaceName).(string) - updateNamespaceOptions.Name = &name - } - - if d.HasChange(funcNamespaceDesc) { - description := d.Get(funcNamespaceDesc).(string) - updateNamespaceOptions.Description = &description - } - - updateNamespaceOptions.ID = &ID - namespace, err := nsClient.Namespaces().UpdateNamespace(updateNamespaceOptions) - if err != nil { - return fmt.Errorf("Error Updating Namespace: %s", err) - } - - log.Printf("[INFO] Updated namespace (IAM) : %s", *namespace.Name) - - return resourceIBMFunctionNamespaceRead(d, meta) -} - -func resourceIBMFunctionNamespaceDelete(d *schema.ResourceData, meta interface{}) error { - nsClient, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - ID := d.Id() - _, err = nsClient.Namespaces().DeleteNamespace(ID) - if err != nil { - return fmt.Errorf("Error Deleting Namespace: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMFunctionNamespaceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - nsClient, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return false, err - } - - ID := d.Id() - - getOptions := functions.GetNamespaceOptions{ - ID: &ID, - } - _, err = nsClient.Namespaces().GetNamespace(getOptions) - if err != nil { - if strings.Contains(err.Error(), "404") { - return false, nil - } - return false, fmt.Errorf("Error getting existing namesapce (IAM): %s", err) - } - - return true, nil - -} diff --git a/ibm/resource_ibm_function_package.go b/ibm/resource_ibm_function_package.go deleted file mode 100644 index 89b4dff10..000000000 --- a/ibm/resource_ibm_function_package.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net/http" - "os" - "strings" - - "github.com/apache/openwhisk-client-go/whisk" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - funcPkgNamespace = "namespace" - funcPkgName = "name" - funcPkgUsrDefAnnots = "user_defined_annotations" - funcPkgUsrDefParams = "user_defined_parameters" - funcPkgBindPkgName = "bind_package_name" -) - -func resourceIBMFunctionPackage() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMFunctionPackageCreate, - Read: resourceIBMFunctionPackageRead, - Update: resourceIBMFunctionPackageUpdate, - Delete: resourceIBMFunctionPackageDelete, - Exists: resourceIBMFunctionPackageExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - funcPkgNamespace: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "IBM Cloud function namespace.", - ValidateFunc: InvokeValidator("ibm_function_package", funcPkgNamespace), - }, - funcPkgName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Name of package.", - ValidateFunc: InvokeValidator("ibm_function_package", funcPkgName), - }, - "publish": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Package visibilty.", - }, - "version": { - Type: schema.TypeString, - Computed: true, - Description: "Semantic version of the item.", - }, - funcPkgUsrDefAnnots: { - Type: schema.TypeString, - Optional: true, - Description: "Annotation values in KEY VALUE format.", - Default: "[]", - ValidateFunc: InvokeValidator("ibm_function_package", funcPkgUsrDefAnnots), - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - funcPkgUsrDefParams: { - Type: schema.TypeString, - Optional: true, - Description: "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the package.", - ValidateFunc: InvokeValidator("ibm_function_package", funcPkgUsrDefParams), - Default: "[]", - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - "annotations": { - Type: schema.TypeString, - Computed: true, - Description: "All annotations set on package by user and those set by the IBM Cloud Function backend/API.", - }, - "parameters": { - Type: schema.TypeString, - Computed: true, - Description: "All parameters set on package by user and those set by the IBM Cloud Function backend/API.", - }, - funcPkgBindPkgName: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Name of package to be binded.", - ValidateFunc: InvokeValidator("ibm_function_package", funcPkgBindPkgName), - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - if o == "" { - return false - } - if strings.Compare(n, o) == 0 { - return true - } - return false - }, - }, - "package_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMFuncPackageValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcPkgName, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `\A([\w]|[\w][\w@ .-]*[\w@.-]+)\z`, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcPkgNamespace, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcPkgUsrDefAnnots, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Default: "[]", - Optional: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcPkgBindPkgName, - ValidateFunctionIdentifier: ValidateBindedPackageName, - Type: TypeString, - Optional: true}) - - ibmFuncPackageResourceValidator := ResourceValidator{ResourceName: "ibm_function_package", Schema: validateSchema} - return &ibmFuncPackageResourceValidator -} - -func resourceIBMFunctionPackageCreate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - packageService := wskClient.Packages - - name := d.Get("name").(string) - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(name); err != nil { - return NewQualifiedNameError(name, err) - } - - payload := whisk.Package{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - } - - userDefinedAnnotations := d.Get("user_defined_annotations").(string) - payload.Annotations, err = expandAnnotations(userDefinedAnnotations) - if err != nil { - return err - } - - userDefinedParameters := d.Get("user_defined_parameters").(string) - payload.Parameters, err = expandParameters(userDefinedParameters) - if err != nil { - return err - } - - if publish, ok := d.GetOk("publish"); ok { - p := publish.(bool) - payload.Publish = &p - } - - if v, ok := d.GetOk("bind_package_name"); ok { - var BindingQualifiedName = new(QualifiedName) - if BindingQualifiedName, err = NewQualifiedName(v.(string)); err != nil { - return NewQualifiedNameError(v.(string), err) - } - BindingPayload := whisk.Binding{ - Name: BindingQualifiedName.GetEntityName(), - Namespace: BindingQualifiedName.GetNamespace(), - } - payload.Binding = &BindingPayload - } - - log.Println("[INFO] Creating IBM CLoud Function package") - result, _, err := packageService.Insert(&payload, false) - if err != nil { - return fmt.Errorf("Error creating IBM CLoud Function package: %s", err) - } - - d.SetId(fmt.Sprintf("%s:%s", namespace, result.Name)) - - return resourceIBMFunctionPackageRead(d, meta) -} - -func resourceIBMFunctionPackageRead(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := "" - packageID := "" - if len(parts) == 2 { - namespace = parts[0] - packageID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - packageID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, packageID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - packageService := wskClient.Packages - - pkg, _, err := packageService.Get(packageID) - if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function package %s : %s", packageID, err) - } - d.Set("package_id", pkg.Name) - d.Set("name", pkg.Name) - d.Set("namespace", namespace) - d.Set("publish", pkg.Publish) - d.Set("version", pkg.Version) - annotations, err := flattenAnnotations(pkg.Annotations) - if err != nil { - return err - } - d.Set("annotations", annotations) - parameters, err := flattenParameters(pkg.Parameters) - if err != nil { - return err - } - d.Set("parameters", parameters) - if isEmpty(*pkg.Binding) { - - d.Set("user_defined_annotations", annotations) - d.Set("user_defined_parameters", parameters) - - } else { - d.Set("bind_package_name", fmt.Sprintf("/%s/%s", pkg.Binding.Namespace, pkg.Binding.Name)) - c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ - Namespace: pkg.Binding.Namespace, - AuthToken: wskClient.AuthToken, - Host: wskClient.Host, - AdditionalHeaders: wskClient.AdditionalHeaders, - }) - bindedPkg, _, err := c.Packages.Get(pkg.Binding.Name) - if err != nil { - return fmt.Errorf("Error retrieving Binded IBM Cloud Function package %s : %s", pkg.Binding.Name, err) - } - - userAnnotations, err := flattenAnnotations(filterInheritedAnnotations(bindedPkg.Annotations, pkg.Annotations)) - if err != nil { - return err - } - d.Set("user_defined_annotations", userAnnotations) - - userParameters, err := flattenParameters(filterInheritedParameters(bindedPkg.Parameters, pkg.Parameters)) - if err != nil { - return err - } - d.Set("user_defined_parameters", userParameters) - } - - return nil -} - -func resourceIBMFunctionPackageUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - packageService := wskClient.Packages - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(d.Get("name").(string)); err != nil { - return NewQualifiedNameError(d.Get("name").(string), err) - } - - payload := whisk.Package{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - } - ischanged := false - if d.HasChange("publish") { - p := d.Get("publish").(bool) - payload.Publish = &p - ischanged = true - } - - if d.HasChange("user_defined_parameters") { - var err error - payload.Parameters, err = expandParameters(d.Get("user_defined_parameters").(string)) - if err != nil { - return err - } - ischanged = true - } - - if d.HasChange("user_defined_annotations") { - var err error - payload.Annotations, err = expandAnnotations(d.Get("user_defined_annotations").(string)) - if err != nil { - return err - } - ischanged = true - } - - if ischanged { - log.Println("[INFO] Update IBM Cloud Function Package") - _, _, err = packageService.Insert(&payload, true) - if err != nil { - return fmt.Errorf("Error updating IBM Cloud Function Package: %s", err) - } - } - - return resourceIBMFunctionPackageRead(d, meta) -} - -func resourceIBMFunctionPackageDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - packageID := parts[1] - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - packageService := wskClient.Packages - - _, err = packageService.Delete(packageID) - if err != nil { - return fmt.Errorf("Error deleting IBM Cloud Function Package: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMFunctionPackageExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := cfIdParts(d.Id()) - if err != nil { - return false, err - } - - namespace := "" - packageID := "" - if len(parts) == 2 { - namespace = parts[0] - packageID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - packageID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, packageID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return false, err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return false, err - } - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return false, err - - } - - packageService := wskClient.Packages - - pkg, resp, err := packageService.Get(packageID) - if err != nil { - if resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with IBM Cloud Function Client : %s", err) - } - - return pkg.Name == packageID, nil -} diff --git a/ibm/resource_ibm_function_rule.go b/ibm/resource_ibm_function_rule.go deleted file mode 100644 index 73285d024..000000000 --- a/ibm/resource_ibm_function_rule.go +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "os" - "strings" - - "github.com/apache/openwhisk-client-go/whisk" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - funcRuleNamespace = "namespace" - funcRuleName = "name" -) - -func resourceIBMFunctionRule() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMFunctionRuleCreate, - Read: resourceIBMFunctionRuleRead, - Update: resourceIBMFunctionRuleUpdate, - Delete: resourceIBMFunctionRuleDelete, - Exists: resourceIBMFunctionRuleExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - funcRuleNamespace: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "IBM Cloud function namespace.", - ValidateFunc: InvokeValidator("ibm_function_rule", funcRuleNamespace), - }, - funcRuleName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Name of rule.", - ValidateFunc: InvokeValidator("ibm_function_rule", funcRuleName), - }, - "trigger_name": { - Type: schema.TypeString, - Required: true, - Description: "Name of trigger.", - }, - "action_name": { - Type: schema.TypeString, - Required: true, - Description: "Name of action.", - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - new := strings.Split(n, "/") - old := strings.Split(o, "/") - action_name_new := new[len(new)-1] - action_name_old := old[len(old)-1] - - if o == "" { - return false - } - if strings.HasPrefix(n, "/_") { - temp := strings.Replace(n, "/_", "/"+d.Get("namespace").(string), 1) - if strings.Compare(temp, o) == 0 { - return true - } - if strings.Compare(action_name_old, action_name_new) == 0 { - return true - } - - } - if !strings.HasPrefix(n, "/") { - if strings.HasPrefix(o, "/"+d.Get("namespace").(string)) { - return true - } - if strings.Compare(action_name_old, action_name_new) == 0 { - return true - } - } - return false - }, - }, - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of the rule.", - }, - "publish": { - Type: schema.TypeBool, - Computed: true, - Description: "Rule visbility.", - }, - "version": { - Type: schema.TypeString, - Computed: true, - Description: "Semantic version of the item.", - }, - "rule_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMFuncRuleValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcRuleName, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `\A([\w]|[\w][\w@ .-]*[\w@.-]+)\z`, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcRuleNamespace, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - - ibmFuncRuleResourceValidator := ResourceValidator{ResourceName: "ibm_function_rule", Schema: validateSchema} - return &ibmFuncRuleResourceValidator -} - -func resourceIBMFunctionRuleCreate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - ruleService := wskClient.Rules - - name := d.Get("name").(string) - - var qualifiedName = new(QualifiedName) - if qualifiedName, err = NewQualifiedName(name); err != nil { - return NewQualifiedNameError(name, err) - } - trigger := d.Get("trigger_name").(string) - action := d.Get("action_name").(string) - - triggerName := getQualifiedName(trigger, wskClient.Config.Namespace) - actionName := getQualifiedName(action, wskClient.Config.Namespace) - payload := whisk.Rule{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - Trigger: triggerName, - Action: actionName, - } - log.Println("[INFO] Creating IBM Cloud Function rule") - result, _, err := ruleService.Insert(&payload, false) - if err != nil { - return fmt.Errorf("Error creating IBM Cloud Function rule: %s", err) - } - - d.SetId(fmt.Sprintf("%s:%s", namespace, result.Name)) - - return resourceIBMFunctionRuleRead(d, meta) -} - -func resourceIBMFunctionRuleRead(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := "" - ruleID := "" - if len(parts) == 2 { - namespace = parts[0] - ruleID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - ruleID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, ruleID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - ruleService := wskClient.Rules - rule, _, err := ruleService.Get(ruleID) - if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function rule %s : %s", ruleID, err) - } - - d.Set("rule_id", rule.Name) - d.Set("name", rule.Name) - d.Set("publish", rule.Publish) - d.Set("namespace", namespace) - d.Set("version", rule.Version) - d.Set("status", rule.Status) - - path := rule.Action.(map[string]interface{})["path"] - d.Set("trigger_name", rule.Trigger.(map[string]interface{})["name"]) - actionName := rule.Action.(map[string]interface{})["name"] - d.Set("action_name", fmt.Sprintf("/%s/%s", path, actionName)) - d.SetId(fmt.Sprintf("%s:%s", namespace, rule.Name)) - return nil -} - -func resourceIBMFunctionRuleUpdate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - ruleService := wskClient.Rules - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(d.Get("name").(string)); err != nil { - return NewQualifiedNameError(d.Get("name").(string), err) - } - - payload := whisk.Rule{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - } - ischanged := false - - if d.HasChange("trigger_name") { - trigger := d.Get("trigger_name").(string) - payload.Trigger = getQualifiedName(trigger, wskClient.Config.Namespace) - ischanged = true - } - - if d.HasChange("action_name") { - action := d.Get("action_name").(string) - payload.Action = getQualifiedName(action, wskClient.Config.Namespace) - ischanged = true - } - - if ischanged { - log.Println("[INFO] Update IBM Cloud Function Rule") - result, _, err := ruleService.Insert(&payload, true) - if err != nil { - return fmt.Errorf("Error updating IBM Cloud Function Rule: %s", err) - } - _, _, err = ruleService.SetState(result.Name, "active") - if err != nil { - return fmt.Errorf("Error updating IBM Cloud Function Rule: %s", err) - } - } - - return resourceIBMFunctionRuleRead(d, meta) -} - -func resourceIBMFunctionRuleDelete(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - ruleID := parts[1] - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - ruleService := wskClient.Rules - - _, err = ruleService.Delete(ruleID) - if err != nil { - return fmt.Errorf("Error deleting IBM Cloud Function Rule: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMFunctionRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := cfIdParts(d.Id()) - if err != nil { - return false, err - } - - namespace := "" - ruleID := "" - if len(parts) == 2 { - namespace = parts[0] - ruleID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - ruleID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, ruleID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return false, err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return false, err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return false, err - - } - - ruleService := wskClient.Rules - - rule, resp, err := ruleService.Get(ruleID) - if err != nil { - if resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with IBM Cloud Function Client : %s", err) - } - return rule.Name == ruleID, nil -} diff --git a/ibm/resource_ibm_function_trigger.go b/ibm/resource_ibm_function_trigger.go deleted file mode 100644 index cadf3761f..000000000 --- a/ibm/resource_ibm_function_trigger.go +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net/http" - "os" - - "github.com/apache/openwhisk-client-go/whisk" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - funcTriggerNamespace = "namespace" - funcTriggerName = "name" - funcTriggerParams = "parameters" - funcTriggerUsrDefAnnots = "user_defined_annotations" - funcTriggerUsrDefParams = "user_defined_parameters" - - feedLifeCycleEvent = "lifecycleEvent" - feedTriggerName = "triggerName" - feedAuthKey = "authKey" - feedCreate = "CREATE" - feedDelete = "DELETE" -) - -func resourceIBMFunctionTrigger() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMFunctionTriggerCreate, - Read: resourceIBMFunctionTriggerRead, - Update: resourceIBMFunctionTriggerUpdate, - Delete: resourceIBMFunctionTriggerDelete, - Exists: resourceIBMFunctionTriggerExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - funcTriggerNamespace: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "IBM Cloud function namespace.", - ValidateFunc: InvokeValidator("ibm_function_trigger", funcTriggerNamespace), - }, - funcTriggerName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Name of Trigger.", - ValidateFunc: InvokeValidator("ibm_function_trigger", funcTriggerName), - }, - "feed": { - Type: schema.TypeList, - ForceNew: true, - Optional: true, - MaxItems: 1, - Description: "Trigger feed", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Trigger feed ACTION_NAME.", - }, - funcTriggerParams: { - Type: schema.TypeString, - Optional: true, - Default: "[]", - Description: "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the action invoke.", - ValidateFunc: InvokeValidator("ibm_function_trigger", funcTriggerParams), - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - if o == "" && n == "" { - return false - } - if o == "[]" { - return true - } - return false - }, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - }, - }, - }, - "publish": { - Type: schema.TypeBool, - Computed: true, - Description: "Trigger visbility.", - }, - "version": { - Type: schema.TypeString, - Computed: true, - Description: "Semantic version of the item.", - }, - funcTriggerUsrDefAnnots: { - Type: schema.TypeString, - Optional: true, - Description: "Annotation values in KEY VALUE format.", - Default: "[]", - ValidateFunc: InvokeValidator("ibm_function_trigger", funcTriggerUsrDefAnnots), - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - funcTriggerUsrDefParams: { - Type: schema.TypeString, - Optional: true, - Default: "[]", - Description: "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the trigger.", - ValidateFunc: InvokeValidator("ibm_function_trigger", funcTriggerUsrDefParams), - DiffSuppressFunc: suppressEquivalentJSON, - StateFunc: func(v interface{}) string { - json, _ := normalizeJSONString(v) - return json - }, - }, - "annotations": { - Type: schema.TypeString, - Computed: true, - Description: "All annotations set on trigger by user and those set by the IBM Cloud Function backend/API.", - }, - "parameters": { - Type: schema.TypeString, - Computed: true, - Description: "All parameters set on trigger by user and those set by the IBM Cloud Function backend/API.", - }, - "trigger_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMFuncTriggerValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcTriggerName, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `\A([\w]|[\w][\w@ .-]*[\w@.-]+)\z`, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcTriggerNamespace, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcTriggerUsrDefAnnots, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Default: "[]", - Optional: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcTriggerUsrDefParams, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Optional: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: funcTriggerParams, - ValidateFunctionIdentifier: ValidateJSONString, - Type: TypeString, - Default: "[]", - Optional: true}) - - ibmFuncTriggerResourceValidator := ResourceValidator{ResourceName: "ibm_function_trigger", Schema: validateSchema} - return &ibmFuncTriggerResourceValidator -} - -func resourceIBMFunctionTriggerCreate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - triggerService := wskClient.Triggers - feed := false - feedPayload := map[string]interface{}{} - name := d.Get("name").(string) - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(name); err != nil { - return NewQualifiedNameError(name, err) - } - - payload := whisk.Trigger{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - } - - userDefinedAnnotations := d.Get("user_defined_annotations").(string) - payload.Annotations, err = expandAnnotations(userDefinedAnnotations) - if err != nil { - return err - } - - userDefinedParameters := d.Get("user_defined_parameters").(string) - payload.Parameters, err = expandParameters(userDefinedParameters) - if err != nil { - return err - } - - if v, ok := d.GetOk("feed"); ok { - feed = true - value := v.([]interface{})[0].(map[string]interface{}) - feedPaylod := whisk.KeyValue{ - Key: "feed", - Value: value["name"], - } - feedArray := make([]whisk.KeyValue, 0, 1) - feedArray = append(feedArray, feedPaylod) - payload.Annotations = payload.Annotations.AppendKeyValueArr(feedArray) - } - - log.Println("[INFO] Creating IBM Cloud Function trigger") - result, _, err := triggerService.Insert(&payload, false) - if err != nil { - return fmt.Errorf("Error creating IBM Cloud Function trigger: %s", err) - } - - d.SetId(fmt.Sprintf("%s:%s", namespace, result.Name)) - - if feed { - feed := d.Get("feed").([]interface{})[0].(map[string]interface{}) - actionName := feed["name"].(string) - parameters := feed["parameters"].(string) - var err error - feedParameters, err := expandParameters(parameters) - if err != nil { - return err - } - for _, value := range feedParameters { - feedPayload[value.Key] = value.Value - } - var feedQualifiedName = new(QualifiedName) - - if feedQualifiedName, err = NewQualifiedName(actionName); err != nil { - _, _, delerr := triggerService.Delete(name) - if delerr != nil { - return fmt.Errorf("Error creating IBM Cloud Function trigger with feed: %s", err) - } - return NewQualifiedNameError(actionName, err) - } - - feedPayload[feedLifeCycleEvent] = feedCreate - feedPayload[feedAuthKey] = wskClient.Config.AuthToken - feedPayload[feedTriggerName] = fmt.Sprintf("/%s/%s", qualifiedName.GetNamespace(), name) - - c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ - AuthToken: wskClient.AuthToken, - Host: wskClient.Host, - AdditionalHeaders: wskClient.AdditionalHeaders, - }) - - if feedQualifiedName.GetNamespace() != namespace { - c.Config.Namespace = feedQualifiedName.GetNamespace() - } - actionService := c.Actions - _, _, err = actionService.Invoke(feedQualifiedName.GetEntityName(), feedPayload, true, true) - if err != nil { - _, _, delerr := triggerService.Delete(name) - if delerr != nil { - return fmt.Errorf("Error creating IBM Cloud Function trigger with feed: %s", err) - } - d.SetId("") - return fmt.Errorf("Error creating IBM Cloud Function trigger with feed: %s", err) - } - } - - d.SetId(fmt.Sprintf("%s:%s", namespace, result.Name)) - - return resourceIBMFunctionTriggerRead(d, meta) -} - -func resourceIBMFunctionTriggerRead(d *schema.ResourceData, meta interface{}) error { - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := "" - triggerID := "" - if len(parts) == 2 { - namespace = parts[0] - triggerID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - triggerID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, triggerID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - triggerService := wskClient.Triggers - - trigger, _, err := triggerService.Get(triggerID) - if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Trigger %s : %s", triggerID, err) - } - d.Set("trigger_id", trigger.Name) - d.Set("namespace", namespace) - d.Set("name", trigger.Name) - d.Set("publish", trigger.Publish) - d.Set("version", trigger.Version) - annotations, err := flattenAnnotations(trigger.Annotations) - if err != nil { - return err - } - d.Set("annotations", annotations) - parameters, err := flattenParameters(trigger.Parameters) - if err != nil { - return err - } - d.Set("parameters", parameters) - d.Set("user_defined_parameters", parameters) - - userDefinedAnnotations, err := filterTriggerAnnotations(trigger.Annotations) - if err != nil { - return err - } - d.Set("user_defined_annotations", userDefinedAnnotations) - - found := trigger.Annotations.FindKeyValue("feed") - - if found >= 0 { - d.Set("feed", flattenFeed(trigger.Annotations.GetValue("feed").(string))) - } - - return nil -} - -func resourceIBMFunctionTriggerUpdate(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - - namespace := parts[0] - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - triggerService := wskClient.Triggers - - name := d.Get("name").(string) - - var qualifiedName = new(QualifiedName) - - if qualifiedName, err = NewQualifiedName(name); err != nil { - return NewQualifiedNameError(name, err) - } - - payload := whisk.Trigger{ - Name: qualifiedName.GetEntityName(), - Namespace: qualifiedName.GetNamespace(), - } - ischanged := false - - if d.HasChange("user_defined_parameters") { - var err error - payload.Parameters, err = expandParameters(d.Get("user_defined_parameters").(string)) - if err != nil { - return err - } - ischanged = true - } - - if d.HasChange("user_defined_annotations") { - var err error - payload.Annotations, err = expandAnnotations(d.Get("user_defined_annotations").(string)) - if err != nil { - return err - } - ischanged = true - } - - if ischanged { - log.Println("[INFO] Update IBM Cloud Function Trigger") - - _, _, err = triggerService.Insert(&payload, true) - if err != nil { - return fmt.Errorf("Error updating IBM Cloud Function Trigger: %s", err) - } - } - - return resourceIBMFunctionTriggerRead(d, meta) -} - -func resourceIBMFunctionTriggerDelete(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return err - } - - parts, err := cfIdParts(d.Id()) - if err != nil { - return err - } - namespace := parts[0] - triggerID := parts[1] - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return err - - } - - triggerService := wskClient.Triggers - var qualifiedName = new(QualifiedName) - fmt.Println(qualifiedName) - if qualifiedName, err = NewQualifiedName(triggerID); err != nil { - return NewQualifiedNameError(triggerID, err) - } - trigger, _, err := triggerService.Get(triggerID) - if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Trigger %s : %s", triggerID, err) - } - found := trigger.Annotations.FindKeyValue("feed") - if found >= 0 { - actionName := trigger.Annotations.GetValue("feed").(string) - var feedQualifiedName = new(QualifiedName) - - if feedQualifiedName, err = NewQualifiedName(actionName); err != nil { - return NewQualifiedNameError(actionName, err) - } - - feedPayload := map[string]interface{}{ - feedLifeCycleEvent: feedDelete, - feedAuthKey: wskClient.Config.AuthToken, - feedTriggerName: fmt.Sprintf("/%s/%s", qualifiedName.GetNamespace(), triggerID), - } - - c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ - AuthToken: wskClient.AuthToken, - Host: wskClient.Host, - AdditionalHeaders: wskClient.AdditionalHeaders, - }) - if feedQualifiedName.GetNamespace() != namespace { - c.Config.Namespace = feedQualifiedName.GetNamespace() - } - - actionService := c.Actions - _, _, err = actionService.Invoke(feedQualifiedName.GetEntityName(), feedPayload, true, true) - if err != nil { - return fmt.Errorf("Error deleting IBM Cloud Function trigger with feed: %s", err) - - } - } - - _, _, err = triggerService.Delete(triggerID) - if err != nil { - return fmt.Errorf("Error deleting IBM Cloud Function Trigger: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMFunctionTriggerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := cfIdParts(d.Id()) - if err != nil { - return false, err - } - - namespace := "" - triggerID := "" - if len(parts) == 2 { - namespace = parts[0] - triggerID = parts[1] - } else { - namespace = os.Getenv("FUNCTION_NAMESPACE") - triggerID = parts[0] - d.SetId(fmt.Sprintf("%s:%s", namespace, triggerID)) - } - - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() - if err != nil { - return false, err - } - - bxSession, err := meta.(ClientSession).BluemixSession() - if err != nil { - return false, err - } - - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) - if err != nil { - return false, err - - } - - triggerService := wskClient.Triggers - trigger, resp, err := triggerService.Get(triggerID) - if err != nil { - if resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with IBM Cloud Function Client : %s", err) - } - return trigger.Name == triggerID, nil -} diff --git a/ibm/resource_ibm_iam_access_group.go b/ibm/resource_ibm_iam_access_group.go deleted file mode 100644 index bbc4ac3f9..000000000 --- a/ibm/resource_ibm_iam_access_group.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMAccessGroup() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMIAMAccessGroupCreate, - ReadContext: resourceIBMIAMAccessGroupRead, - UpdateContext: resourceIBMIAMAccessGroupUpdate, - DeleteContext: resourceIBMIAMAccessGroupDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the access group", - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the access group", - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "version": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMIAMAccessGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - name := d.Get("name").(string) - creatAccessGroupOptions := iamAccessGroupsClient.NewCreateAccessGroupOptions(userDetails.userAccount, name) - if des, ok := d.GetOk("description"); ok { - description := des.(string) - creatAccessGroupOptions.Description = &description - } - agrp, detailedResponse, err := iamAccessGroupsClient.CreateAccessGroup(creatAccessGroupOptions) - if err != nil || agrp == nil { - return diag.FromErr(fmt.Errorf("Error creating access group: %s. API Response: %s", err, detailedResponse)) - } - - d.SetId(*agrp.ID) - - return resourceIBMIAMAccessGroupRead(context, d, meta) -} - -func resourceIBMIAMAccessGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - agrpID := d.Id() - getAccessGroupOptions := iamAccessGroupsClient.NewGetAccessGroupOptions(agrpID) - agrp, detailedResponse, err := iamAccessGroupsClient.GetAccessGroup(getAccessGroupOptions) - if err != nil || agrp == nil { - if detailedResponse != nil && detailedResponse.StatusCode == 404 { - return nil - } - return diag.FromErr(fmt.Errorf("Error retrieving access group: %s. API Response: %s", err, detailedResponse)) - } - version := detailedResponse.GetHeaders().Get("etag") - d.Set("name", agrp.Name) - d.Set("description", agrp.Description) - d.Set("version", version) - - return nil -} - -func resourceIBMIAMAccessGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - agrpID := d.Id() - - hasChange := false - version := d.Get("version").(string) - updateAccessGroupOptions := iamAccessGroupsClient.NewUpdateAccessGroupOptions(agrpID, version) - - if d.HasChange("name") { - name := d.Get("name").(string) - updateAccessGroupOptions.Name = &name - hasChange = true - } - - if d.HasChange("description") { - description := d.Get("description").(string) - updateAccessGroupOptions.Description = &description - hasChange = true - } - - if hasChange { - agrp, detailedResponse, err := iamAccessGroupsClient.UpdateAccessGroup(updateAccessGroupOptions) - if err != nil || agrp == nil { - return diag.FromErr(fmt.Errorf("Error updating access group: %s. API Response: %s", err, detailedResponse)) - } - } - - return resourceIBMIAMAccessGroupRead(context, d, meta) - -} - -func resourceIBMIAMAccessGroupDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - agID := d.Id() - force := true - deleteAccessGroupOptions := iamAccessGroupsClient.NewDeleteAccessGroupOptions(agID) - deleteAccessGroupOptions.SetForce(force) - detailedResponse, err := iamAccessGroupsClient.DeleteAccessGroup(deleteAccessGroupOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("Error deleting access group: %s, API Response: %s", err, detailedResponse)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_iam_access_group_dynamic_rule.go b/ibm/resource_ibm_iam_access_group_dynamic_rule.go deleted file mode 100644 index ea55c00b2..000000000 --- a/ibm/resource_ibm_iam_access_group_dynamic_rule.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMDynamicRule() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMDynamicRuleCreate, - Read: resourceIBMIAMDynamicRuleRead, - Update: resourceIBMIAMDynamicRuleUpdate, - Delete: resourceIBMIAMDynamicRuleDelete, - Exists: resourceIBMIAMDynamicRuleExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "access_group_id": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier of the access group", - }, - - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the Rule", - }, - "expiration": { - Type: schema.TypeInt, - Required: true, - Description: "The expiration in hours", - ValidateFunc: validatePortRange(1, 24), - }, - "identity_provider": { - Type: schema.TypeString, - Required: true, - Description: "The realm name or identity proivider url", - }, - "conditions": { - Type: schema.TypeList, - Required: true, - Description: "conditions info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "claim": { - Type: schema.TypeString, - Required: true, - }, - "operator": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"EQUALS", "EQUALS_IGNORE_CASE", "IN", "NOT_EQUALS_IGNORE_CASE", "NOT_EQUALS", "CONTAINS"}), - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "rule_id": { - Type: schema.TypeString, - Computed: true, - Description: "id of the rule", - }, - }, - } -} - -func resourceIBMIAMDynamicRuleCreate(d *schema.ResourceData, meta interface{}) error { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - - grpID := d.Get("access_group_id").(string) - name := d.Get("name").(string) - realm := d.Get("identity_provider").(string) - expiration := int64(d.Get("expiration").(int)) - - var cond []interface{} - conditions := []iamaccessgroupsv2.RuleConditions{} - if res, ok := d.GetOk("conditions"); ok { - cond = res.([]interface{}) - for _, e := range cond { - r, _ := e.(map[string]interface{}) - value := fmt.Sprintf("\"%s\"", r["value"].(string)) - claim := r["claim"].(string) - operator := r["operator"].(string) - conditionParam := iamaccessgroupsv2.RuleConditions{ - Claim: &claim, - Operator: &operator, - Value: &value, - } - conditions = append(conditions, conditionParam) - } - } - - addAccessGroupRuleOptions := &iamaccessgroupsv2.AddAccessGroupRuleOptions{ - AccessGroupID: &grpID, - Name: &name, - RealmName: &realm, - Expiration: &expiration, - Conditions: conditions, - } - rule, detailedResponse, err := iamAccessGroupsClient.AddAccessGroupRule(addAccessGroupRuleOptions) - if err != nil || rule == nil { - return fmt.Errorf("Error adding rule to Access Group(%s) %s. API Response: %s", grpID, err, detailedResponse) - } - ruleID := rule.ID - d.SetId(fmt.Sprintf("%s/%s", grpID, *ruleID)) - - return resourceIBMIAMDynamicRuleRead(d, meta) -} - -func resourceIBMIAMDynamicRuleRead(d *schema.ResourceData, meta interface{}) error { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - grpID := parts[0] - ruleID := parts[1] - - getAccessGroupRuleOptions := &iamaccessgroupsv2.GetAccessGroupRuleOptions{ - AccessGroupID: &grpID, - RuleID: &ruleID, - } - rule, detailResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) - - if err != nil || rule == nil { - if detailResponse != nil && detailResponse.StatusCode == 404 { - d.SetId("") - return nil - } else { - return fmt.Errorf("Error retrieving access group Rules: %s. API Response: %s", err, detailResponse) - } - } - - d.Set("access_group_id", grpID) - d.Set("name", rule.Name) - d.Set("expiration", rule.Expiration) - d.Set("identity_provider", rule.RealmName) - d.Set("conditions", flattenConditions(rule.Conditions)) - d.Set("rule_id", rule.ID) - - return nil -} - -func resourceIBMIAMDynamicRuleUpdate(d *schema.ResourceData, meta interface{}) error { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - grpID := parts[0] - ruleID := parts[1] - getAccessGroupRuleOptions := iamAccessGroupsClient.NewGetAccessGroupRuleOptions(grpID, ruleID) - _, detailedResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) - if err != nil { - return fmt.Errorf("Error retrieving access group Rules: %s. API Response: %s", err, detailedResponse) - } - - etag := detailedResponse.GetHeaders().Get("etag") - realm := d.Get("identity_provider").(string) - expiration := int64(d.Get("expiration").(int)) - - var cond []interface{} - condition := []iamaccessgroupsv2.RuleConditions{} - if res, ok := d.GetOk("conditions"); ok { - cond = res.([]interface{}) - for _, e := range cond { - r, _ := e.(map[string]interface{}) - value := fmt.Sprintf("\"%s\"", r["value"].(string)) - claim := r["claim"].(string) - operator := r["operator"].(string) - conditionParam := iamaccessgroupsv2.RuleConditions{ - Claim: &claim, - Operator: &operator, - Value: &value, - } - condition = append(condition, conditionParam) - } - } - - replaceAccessGroupRuleOption := iamAccessGroupsClient.NewReplaceAccessGroupRuleOptions(grpID, ruleID, etag, expiration, realm, condition) - rule, detailedResponse, err := iamAccessGroupsClient.ReplaceAccessGroupRule(replaceAccessGroupRuleOption) - if err != nil || rule == nil { - return fmt.Errorf("Error replacing group(%s) rule(%s). API response: %s", grpID, ruleID, detailedResponse) - } - - return resourceIBMIAMDynamicRuleRead(d, meta) - -} - -func resourceIBMIAMDynamicRuleDelete(d *schema.ResourceData, meta interface{}) error { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - grpID := parts[0] - ruleID := parts[1] - removeAccessGroupRuleOptions := iamAccessGroupsClient.NewRemoveAccessGroupRuleOptions(grpID, ruleID) - detailedResponse, err := iamAccessGroupsClient.RemoveAccessGroupRule(removeAccessGroupRuleOptions) - if err != nil { - if detailedResponse != nil && detailedResponse.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting group(%s) rule(%s). API Response: %s", grpID, ruleID, detailedResponse) - } - - return nil -} - -func resourceIBMIAMDynamicRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return false, err - } - - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of accessGroupID/RuleID", d.Id()) - } - grpID := parts[0] - ruleID := parts[1] - - getAccessGroupRuleOptions := iamAccessGroupsClient.NewGetAccessGroupRuleOptions(grpID, ruleID) - rule, detailResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) - - if detailResponse != nil && detailResponse.StatusCode == 404 { - d.SetId("") - return false, nil - } - if err != nil || rule == nil { - return false, fmt.Errorf("Error getting group(%s) rule(%s). API response: %s", grpID, ruleID, detailResponse) - } - return *rule.AccessGroupID == grpID, nil -} diff --git a/ibm/resource_ibm_iam_access_group_members.go b/ibm/resource_ibm_iam_access_group_members.go deleted file mode 100644 index 79b370b70..000000000 --- a/ibm/resource_ibm_iam_access_group_members.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "log" - "time" - - "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMAccessGroupMembers() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMIAMAccessGroupMembersCreate, - ReadContext: resourceIBMIAMAccessGroupMembersRead, - UpdateContext: resourceIBMIAMAccessGroupMembersUpdate, - DeleteContext: resourceIBMIAMAccessGroupMembersDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "access_group_id": { - Type: schema.TypeString, - Required: true, - Description: "Unique identifier of the access group", - }, - - "ibm_ids": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - }, - - "iam_service_ids": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "members": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "iam_id": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func resourceIBMIAMAccessGroupMembersCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - grpID := d.Get("access_group_id").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := userDetails.userAccount - - var userids, serviceids []string - - users := expandStringList(d.Get("ibm_ids").(*schema.Set).List()) - services := expandStringList(d.Get("iam_service_ids").(*schema.Set).List()) - - if len(users) == 0 && len(services) == 0 { - return diag.FromErr(fmt.Errorf("ERROR] Provide either `ibm_ids` or `iam_service_ids`")) - - } - - userids, err = flattenUserIds(accountID, users, meta) - if err != nil { - return diag.FromErr(err) - } - - serviceids, err = flattenServiceIds(services, meta) - if err != nil { - return diag.FromErr(err) - } - - members := prepareMemberAddRequest(iamAccessGroupsClient, userids, serviceids) - - addMembersToAccessGroupOptions := iamAccessGroupsClient.NewAddMembersToAccessGroupOptions(grpID) - addMembersToAccessGroupOptions.SetMembers(members) - membership, detailResponse, err := iamAccessGroupsClient.AddMembersToAccessGroup(addMembersToAccessGroupOptions) - if err != nil || membership == nil { - return diag.FromErr(fmt.Errorf("Error adding members to group(%s). API response: %s", grpID, detailResponse)) - } - - d.SetId(fmt.Sprintf("%s/%s", grpID, time.Now().UTC().String())) - - return resourceIBMIAMAccessGroupMembersRead(context, d, meta) -} - -func resourceIBMIAMAccessGroupMembersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - parts, err := idParts(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - grpID := parts[0] - listAccessGroupMembersOptions := iamAccessGroupsClient.NewListAccessGroupMembersOptions(grpID) - offset := int64(0) - // lets fetch 100 in a single pagination - limit := int64(100) - listAccessGroupMembersOptions.SetLimit(limit) - members, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupMembers(listAccessGroupMembersOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group members: %s. API Response: %s", err, detailedResponse)) - } - allMembers := members.Members - totalMembers := intValue(members.TotalCount) - for len(allMembers) < totalMembers { - offset = offset + limit - listAccessGroupMembersOptions.SetOffset(offset) - members, detailedResponse, err = iamAccessGroupsClient.ListAccessGroupMembers(listAccessGroupMembersOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group members: %s. API Response: %s", err, detailedResponse)) - } - allMembers = append(allMembers, members.Members...) - } - - d.Set("access_group_id", grpID) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := userDetails.userAccount - - userManagement, err := meta.(ClientSession).UserManagementAPI() - if err != nil { - return diag.FromErr(err) - } - client := userManagement.UserInvite() - res, err := client.ListUsers(accountID) - if err != nil { - return diag.FromErr(err) - } - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - start := "" - allrecs := []iamidentityv1.ServiceID{} - var pg int64 = 100 - for { - listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ - AccountID: &userDetails.userAccount, - Pagesize: &pg, - } - if start != "" { - listServiceIDOptions.Pagetoken = &start - } - - serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp)) - } - start = GetNextIAM(serviceIDs.Next) - allrecs = append(allrecs, serviceIDs.Serviceids...) - if start == "" { - break - } - } - - d.Set("members", flattenAccessGroupMembers(allMembers, res, allrecs)) - ibmID, serviceID := flattenMembersData(allMembers, res, allrecs) - if len(ibmID) > 0 { - d.Set("ibm_ids", ibmID) - } - if len(serviceID) > 0 { - d.Set("iam_service_ids", serviceID) - } - return nil -} - -func resourceIBMIAMAccessGroupMembersUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - parts, err := idParts(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - grpID := parts[0] - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := userDetails.userAccount - - var removeUsers, addUsers, removeServiceids, addServiceids []string - o, n := d.GetChange("ibm_ids") - ou := o.(*schema.Set) - nu := n.(*schema.Set) - - removeUsers = expandStringList(ou.Difference(nu).List()) - addUsers = expandStringList(nu.Difference(ou).List()) - - os, ns := d.GetChange("iam_service_ids") - osi := os.(*schema.Set) - nsi := ns.(*schema.Set) - - removeServiceids = expandStringList(osi.Difference(nsi).List()) - addServiceids = expandStringList(nsi.Difference(osi).List()) - - if len(addUsers) > 0 || len(addServiceids) > 0 && !d.IsNewResource() { - var userids, serviceids []string - userids, err = flattenUserIds(accountID, addUsers, meta) - if err != nil { - return diag.FromErr(err) - } - - serviceids, err = flattenServiceIds(addServiceids, meta) - if err != nil { - return diag.FromErr(err) - } - members := prepareMemberAddRequest(iamAccessGroupsClient, userids, serviceids) - - addMembersToAccessGroupOptions := iamAccessGroupsClient.NewAddMembersToAccessGroupOptions(grpID) - addMembersToAccessGroupOptions.SetMembers(members) - membership, detailResponse, err := iamAccessGroupsClient.AddMembersToAccessGroup(addMembersToAccessGroupOptions) - if err != nil || membership == nil { - return diag.FromErr(fmt.Errorf("Error updating members to group(%s). API response: %s", grpID, detailResponse)) - } - - } - if len(removeUsers) > 0 || len(removeServiceids) > 0 && !d.IsNewResource() { - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - for _, u := range removeUsers { - ibmUniqueId, err := getIBMUniqueId(accountID, u, meta) - if err != nil { - return diag.FromErr(err) - } - removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, ibmUniqueId) - _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) - if err != nil { - return diag.FromErr(err) - } - - } - - for _, s := range removeServiceids { - getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ - ID: &s, - } - serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) - if err != nil || serviceID == nil { - return diag.FromErr(fmt.Errorf("ERROR] Error Getting Service Ids %s %s", err, resp)) - } - removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, *serviceID.IamID) - detailResponse, err := iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("Error removing members to group(%s). API Response: %s", grpID, detailResponse)) - } - - } - } - - return resourceIBMIAMAccessGroupMembersRead(context, d, meta) - -} - -func resourceIBMIAMAccessGroupMembersDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() - if err != nil { - return diag.FromErr(err) - } - - parts, err := idParts(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - grpID := parts[0] - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - users := expandStringList(d.Get("ibm_ids").(*schema.Set).List()) - - for _, name := range users { - - ibmUniqueID, err := getIBMUniqueId(userDetails.userAccount, name, meta) - if err != nil { - return diag.FromErr(err) - } - - removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, ibmUniqueID) - _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) - if err != nil { - return diag.FromErr(err) - } - - } - - services := expandStringList(d.Get("iam_service_ids").(*schema.Set).List()) - - for _, id := range services { - serviceID, err := getServiceID(id, meta) - if err != nil { - return diag.FromErr(err) - } - - removeMembersFromAccessGroupOptions := &iamaccessgroupsv2.RemoveMemberFromAccessGroupOptions{ - AccessGroupID: &grpID, - IamID: serviceID.IamID, - } - _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) - if err != nil { - return diag.FromErr(err) - } - } - - d.SetId("") - - return nil -} - -func prepareMemberAddRequest(iamAccessGroupsClient *iamaccessgroupsv2.IamAccessGroupsV2, userIds, serviceIds []string) (members []iamaccessgroupsv2.AddGroupMembersRequestMembersItem) { - members = make([]iamaccessgroupsv2.AddGroupMembersRequestMembersItem, len(userIds)+len(serviceIds)) - var i = 0 - userType := "user" - serviceType := "service" - for _, id := range userIds { - membersItem, err := iamAccessGroupsClient.NewAddGroupMembersRequestMembersItem(id, userType) - if err != nil { - log.Printf("Error in preparing membership data. %s", err) - } - members[i] = *membersItem - i++ - } - - for _, id := range serviceIds { - membersItem, err := iamAccessGroupsClient.NewAddGroupMembersRequestMembersItem(id, serviceType) - if err != nil || membersItem == nil { - log.Printf("Error in preparing membership data. %s", err) - } - members[i] = *membersItem - i++ - } - return -} - -func getServiceID(id string, meta interface{}) (iamidentityv1.ServiceID, error) { - serviceids := iamidentityv1.ServiceID{} - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return serviceids, err - } - getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ - ID: &id, - } - serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) - if err != nil || serviceID == nil { - return serviceids, fmt.Errorf("ERROR] Error Getting Service Ids %s %s", err, resp) - } - return *serviceID, nil -} diff --git a/ibm/resource_ibm_iam_access_group_members_test.go b/ibm/resource_ibm_iam_access_group_members_test.go deleted file mode 100644 index 353b8c060..000000000 --- a/ibm/resource_ibm_iam_access_group_members_test.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMAccessGroupMember_Basic(t *testing.T) { - - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - sname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - sname1 := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupMemberDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAccessGroupMemberBasic(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "1"), - ), - }, - { - Config: testAccCheckIBMIAMAccessGroupMemberAddServiceID(name, sname), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "2"), - ), - }, - { - Config: testAccCheckIBMIAMAccessGroupMemberAddAnotherServiceID(name, sname, sname1), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "3"), - ), - }, - { - Config: testAccCheckIBMIAMAccessGroupMemberRemoveUserAndSID(name, sname, sname1), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupMember_import(t *testing.T) { - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - sname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_access_group.accgroup" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupMemberDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAccessGroupMemberImport(name, sname), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "iam_ids", - "iam_service_ids", - }, - }, - }, - }) -} - -func testAccCheckIBMIAMAccessGroupMemberDestroy(s *terraform.State) error { - accClient, err := testAccProvider.Meta().(ClientSession).IAMAccessGroupsV2() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_access_group_members" { - continue - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - grpID := parts[0] - - // Try to find the members - listAccessGroupMembersOptions := &iamaccessgroupsv2.ListAccessGroupMembersOptions{ - AccessGroupID: &grpID, - } - _, detailResponse, err := accClient.ListAccessGroupMembers(listAccessGroupMembersOptions) - - if err != nil && detailResponse.StatusCode != 404 { - return fmt.Errorf("Error waiting for access group members (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMAccessGroupMemberBasic(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgroup" { - name = "%s" - } - - resource "ibm_iam_access_group_members" "accgroupmem" { - access_group_id = ibm_iam_access_group.accgroup.id - ibm_ids = ["%s"] - }`, name, IAMUser) -} - -func testAccCheckIBMIAMAccessGroupMemberAddServiceID(name, sname string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgroup" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_access_group_members" "accgroupmem" { - access_group_id = ibm_iam_access_group.accgroup.id - ibm_ids = ["%s"] - iam_service_ids = [ibm_iam_service_id.serviceID.id] - }`, name, sname, IAMUser) -} - -func testAccCheckIBMIAMAccessGroupMemberAddAnotherServiceID(name, sname, sname1 string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgroup" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID2" { - name = "%s" - } - - resource "ibm_iam_access_group_members" "accgroupmem" { - access_group_id = ibm_iam_access_group.accgroup.id - ibm_ids = ["%s"] - iam_service_ids = [ibm_iam_service_id.serviceID.id, ibm_iam_service_id.serviceID2.id] - }`, name, sname, sname1, IAMUser) -} - -func testAccCheckIBMIAMAccessGroupMemberRemoveUserAndSID(name, sname, sname1 string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgroup" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID2" { - name = "%s" - } - - resource "ibm_iam_access_group_members" "accgroupmem" { - access_group_id = ibm_iam_access_group.accgroup.id - iam_service_ids = [ibm_iam_service_id.serviceID.id] - }`, name, sname, sname1) -} - -func testAccCheckIBMIAMAccessGroupMemberImport(name, sname string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgroup" { - name = "%s" - } - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_access_group_members" "accgroupmem" { - access_group_id = ibm_iam_access_group.accgroup.id - ibm_ids = ["%s"] - iam_service_ids = [ibm_iam_service_id.serviceID.id] - }`, name, sname, IAMUser) -} diff --git a/ibm/resource_ibm_iam_access_group_policy.go b/ibm/resource_ibm_iam_access_group_policy.go deleted file mode 100644 index f52344ea6..000000000 --- a/ibm/resource_ibm_iam_access_group_policy.go +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMAccessGroupPolicy() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMAccessGroupPolicyCreate, - Read: resourceIBMIAMAccessGroupPolicyRead, - Update: resourceIBMIAMAccessGroupPolicyUpdate, - Delete: resourceIBMIAMAccessGroupPolicyDelete, - Exists: resourceIBMIAMAccessGroupPolicyExists, - Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - resources, resourceAttributes, err := importAccessGroupPolicy(d, meta) - if err != nil { - return nil, fmt.Errorf("Error reading resource ID: %s", err) - } - d.Set("resources", resources) - d.Set("resource_attributes", resourceAttributes) - return []*schema.ResourceData{d}, nil - }, - }, - - Schema: map[string]*schema.Schema{ - "access_group_id": { - Type: schema.TypeString, - Required: true, - Description: "ID of access group", - ForceNew: true, - }, - - "roles": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - - "resources": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"account_management", "resource_attributes"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Optional: true, - Description: "Service name of the policy definition", - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of resource instance of the policy definition", - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Description: "Region of the policy definition", - }, - - "resource_type": { - Type: schema.TypeString, - Optional: true, - Description: "Resource type of the policy definition", - }, - - "resource": { - Type: schema.TypeString, - Optional: true, - Description: "Resource of the policy definition", - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - - "attributes": { - Type: schema.TypeMap, - Optional: true, - Description: "Set resource attributes in the form of 'name=value,name=value....", - Elem: schema.TypeString, - }, - }, - }, - }, - - "resource_attributes": { - Type: schema.TypeSet, - Optional: true, - Description: "Set resource attributes.", - ConflictsWith: []string{"resources", "account_management"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of attribute.", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of attribute.", - }, - "operator": { - Type: schema.TypeString, - Optional: true, - Default: "stringEquals", - Description: "Operator of attribute.", - }, - }, - }, - }, - "account_management": { - Type: schema.TypeBool, - Default: false, - Optional: true, - Description: "Give access to all account management services", - ConflictsWith: []string{"resources", "resource_attributes"}, - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "version": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMIAMAccessGroupPolicyCreate(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - accessGroupId := d.Get("access_group_id").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - var policyOptions iampolicymanagementv1.CreatePolicyOptions - policyOptions, err = generatePolicyOptions(d, meta) - if err != nil { - return err - } - - // Keep configuring the policy options by adding subject part - accessGroupIdSubject := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{ - { - Name: core.StringPtr("access_group_id"), - Value: &accessGroupId, - }, - }, - } - - accountIdResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: &userDetails.userAccount, - } - - policyResource := &iampolicymanagementv1.PolicyResource{ - Attributes: append(policyOptions.Resources[0].Attributes, *accountIdResourceAttribute), - } - - createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( - "access", - []iampolicymanagementv1.PolicySubject{*accessGroupIdSubject}, - policyOptions.Roles, - []iampolicymanagementv1.PolicyResource{*policyResource}, - ) - - accessGroupPolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) - if err != nil || accessGroupPolicy == nil { - return fmt.Errorf("Error creating access group policy: %s\n%s", err, res) - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: accessGroupPolicy.ID, - } - - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || policy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil { - d.SetId(fmt.Sprintf("%s/%s", accessGroupId, *accessGroupPolicy.ID)) - return fmt.Errorf("Error fetching access group policy: %s\n%s", err, res) - } - d.SetId(fmt.Sprintf("%s/%s", accessGroupId, *accessGroupPolicy.ID)) - - return resourceIBMIAMAccessGroupPolicyRead(d, meta) -} - -func resourceIBMIAMAccessGroupPolicyRead(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - accessGroupId := parts[0] - accessGroupPolicyId := parts[1] - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: &accessGroupPolicyId, - } - accessGroupPolicy := &iampolicymanagementv1.Policy{} - res := &core.DetailedResponse{} - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - accessGroupPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || accessGroupPolicy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - accessGroupPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil || accessGroupPolicy == nil { - return fmt.Errorf("Error retrieving access group policy: %s\n%s", err, res) - } - - retrievedAttribute := getSubjectAttribute("access_group_id", accessGroupPolicy.Subjects[0]) - if accessGroupId != *retrievedAttribute { - return fmt.Errorf("Policy %s does not belong to access group %s, retrievedAttr: %s", accessGroupPolicyId, accessGroupId, *retrievedAttribute) - } - - d.Set("access_group_id", accessGroupId) - roles := make([]string, len(accessGroupPolicy.Roles)) - for i, role := range accessGroupPolicy.Roles { - roles[i] = *role.DisplayName - } - d.Set("roles", roles) - d.Set("version", res.Headers.Get("ETag")) - - if _, ok := d.GetOk("resources"); ok { - d.Set("resources", flattenPolicyResource(accessGroupPolicy.Resources)) - } - if _, ok := d.GetOk("resource_attributes"); ok { - d.Set("resource_attributes", flattenPolicyResourceAttributes(accessGroupPolicy.Resources)) - } - if len(accessGroupPolicy.Resources) > 0 { - if *getResourceAttribute("serviceType", accessGroupPolicy.Resources[0]) == "service" { - d.Set("account_management", false) - } - if *getResourceAttribute("serviceType", accessGroupPolicy.Resources[0]) == "platform_service" { - d.Set("account_management", true) - } - } - - return nil -} - -func resourceIBMIAMAccessGroupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - accessGroupId := parts[0] - accessGroupPolicyId := parts[1] - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - var policyOptions iampolicymanagementv1.CreatePolicyOptions - policyOptions, err = generatePolicyOptions(d, meta) - if err != nil { - return err - } - - accessGroupIdSubject := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{ - { - Name: core.StringPtr("access_group_id"), - Value: &accessGroupId, - }, - }, - } - - accountIdResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: &userDetails.userAccount, - } - - policyResource := &iampolicymanagementv1.PolicyResource{ - Attributes: append(policyOptions.Resources[0].Attributes, *accountIdResourceAttribute), - } - - updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( - accessGroupPolicyId, - d.Get("version").(string), - "access", - []iampolicymanagementv1.PolicySubject{*accessGroupIdSubject}, - policyOptions.Roles, - []iampolicymanagementv1.PolicyResource{*policyResource}, - ) - - _, res, err := iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) - if err != nil { - return fmt.Errorf("Error updating access group policy: %s\n%s", err, res) - } - } - - return resourceIBMIAMAccessGroupPolicyRead(d, meta) -} - -func resourceIBMIAMAccessGroupPolicyDelete(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - accessGroupPolicyId := parts[1] - - deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( - accessGroupPolicyId, - ) - - res, err := iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) - if err != nil { - return fmt.Errorf("Error deleting access group policy: %s\n%s", err, res) - } - - d.SetId("") - - return nil -} - -func resourceIBMIAMAccessGroupPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of accessGroupID/PolicyID", d.Id()) - } - - accessGroupPolicyId := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - accessGroupPolicyId, - ) - - accessGroupPolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || accessGroupPolicy == nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with the API: %s\n%s", err, resp) - } - - if accessGroupPolicy != nil && accessGroupPolicy.State != nil && *accessGroupPolicy.State == "deleted" { - return false, nil - } - - tempID := fmt.Sprintf("%s/%s", *getSubjectAttribute("access_group_id", accessGroupPolicy.Subjects[0]), *accessGroupPolicy.ID) - - return tempID == d.Id(), nil -} -func importAccessGroupPolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return nil, nil, err - } - - parts, err := idParts(d.Id()) - if err != nil { - return nil, nil, err - } - accgrpPolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - accgrpPolicyID, - ) - - accessGroupPolicy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return nil, nil, fmt.Errorf("Error retrieving access group policy: %s\n%s", err, res) - } - - resources := flattenPolicyResource(accessGroupPolicy.Resources) - resource_attributes := flattenPolicyResourceAttributes(accessGroupPolicy.Resources) - - return resources, resource_attributes, nil -} diff --git a/ibm/resource_ibm_iam_access_group_policy_test.go b/ibm/resource_ibm_iam_access_group_policy_test.go deleted file mode 100644 index 02a3a79e9..000000000 --- a/ibm/resource_ibm_iam_access_group_policy_test.go +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMAccessGroupPolicy_Basic(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyBasic(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyUpdateRole(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_Service(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyService(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyUpdateServiceAndRegion(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_ResourceInstance(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyResourceInstance(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "3"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_Resource_Group(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyResourceGroup(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "containers-kubernetes"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_Resource_Type(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyResourceType(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_import(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_access_group_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyImport(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"resources", "resource_attributes"}, - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_account_management(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_access_group_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyAccountManagement(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "account_management", "true"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_Attributese(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyAttributes(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "is"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_With_Resource_Attributes(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAccessGroupPolicyResourceAttributes(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), - ), - }, - { - Config: testAccCheckIBMIAMAccessGroupPolicyResourceAttributesUpdate(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAccessGroupPolicy_WithCustomRole(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMAccessGroupPolicyWithCustomRole(name, crName, displayName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMAccessGroupPolicyDestroy(s *terraform.State) error { - iamPolicyManagementClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_access_group_policy" { - continue - } - policyID := rs.Primary.ID - parts, err := idParts(policyID) - if err != nil { - return err - } - - accessGroupPolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - accessGroupPolicyID, - ) - - destroyedPolicy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err == nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Access group policy still exists: %s\n", rs.Primary.ID) - } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Error waiting for access group policy (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMAccessGroupPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - iamPolicyManagementClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - policyID := rs.Primary.ID - - parts, err := idParts(policyID) - if err != nil { - return err - } - - accessGroupPolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - accessGroupPolicyID, - ) - - policy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return fmt.Errorf("Error retrieving Policy %s err: %s", accessGroupPolicyID, err) - } - obj = *policy - return nil - } -} - -func testAccCheckIBMIAMAccessGroupPolicyBasic(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - tags = ["tag1"] - } - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyUpdateRole(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer", "Administrator"] - tags = ["tag1", "tag2"] - } - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyService(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - - resources { - service = "cloud-object-storage" - } - } - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyUpdateServiceAndRegion(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer", "Manager"] - - resources { - service = "kms" - } - } - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyResourceInstance(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } - } - - - `, name, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyResourceGroup(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } - } - - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyResourceType(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Administrator"] - - resources { - resource_type = "resource-group" - resource = data.ibm_resource_group.group.id - } - } - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyImport(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - } - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyAccountManagement(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Administrator"] - account_management = true - } - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyAttributes(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - - resources { - service = "is" - attributes = { - "vpcId" = "*" - } - } - } - - `, name) -} - -func testAccCheckIBMIAMAccessGroupPolicyWithCustomRole(name, crName, displayName string) string { - return fmt.Sprintf(` - - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_custom_role" "customrole" { - name = "%s" - display_name = "%s" - description = "role for test scenario1" - service = "kms" - actions = ["kms.secrets.rotate"] - } - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] - tags = ["tag1"] - resources { - service = "kms" - } - } - - `, name, crName, displayName) -} -func testAccCheckIBMIAMAccessGroupPolicyResourceAttributes(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - operator = "stringMatch" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} -func testAccCheckIBMIAMAccessGroupPolicyResourceAttributesUpdate(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_access_group" "accgrp" { - name = "%s" - } - - resource "ibm_iam_access_group_policy" "policy" { - access_group_id = ibm_iam_access_group.accgrp.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} diff --git a/ibm/resource_ibm_iam_authorization.policy_test.go b/ibm/resource_ibm_iam_authorization.policy_test.go deleted file mode 100644 index 06ad54b69..000000000 --- a/ibm/resource_ibm_iam_authorization.policy_test.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" -) - -func TestAccIBMIAMAuthorizationPolicy_Basic(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAuthorizationPolicyBasic(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "description", "Authorization Policy for test scenario"), - ), - }, - }, - }) -} - -func TestAccIBMIAMAuthorizationPolicy_Resource_Instance(t *testing.T) { - var conf iampolicymanagementv1.Policy - instanceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_authorization_policy.policy" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAuthorizationPolicyResourceInstance(instanceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -// TODO: Invalid authorizatoin header -func TestAccIBMIAMAuthorizationPolicy_Resource_Group(t *testing.T) { - var conf iampolicymanagementv1.Policy - sResourceGroup := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - tResourceGroup := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_authorization_policy.policy" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAuthorizationPolicyResourceGroup(sResourceGroup, tResourceGroup), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIBMIAMAuthorizationPolicy_ResourceType(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAuthorizationPolicyResourceType(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "is"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_resource_type", "load-balancer"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "cloudcerts"), - ), - }, - }, - }) -} -func TestAccIBMIAMAuthorizationPolicyDelegatorRole(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMAuthorizationPolicyDelegatorRole(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "databases-for-redis"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMAuthorizationPolicyDestroy(s *terraform.State) error { - iamPolicyManagementClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_authorization_policy" { - continue - } - - authPolicyID := rs.Primary.ID - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - authPolicyID, - ) - destroyedPolicy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err == nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Authorization policy still exists: %s\n", rs.Primary.ID) - } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Error waiting for authorization policy (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMAuthorizationPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - iamPolicyManagementClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - authPolicyID := rs.Primary.ID - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - authPolicyID, - ) - - policy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return fmt.Errorf("Error Getting Policy %s, %s", err, resp) - } - obj = *policy - return nil - } -} - -func testAccCheckIBMIAMAuthorizationPolicyBasic() string { - return ` - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "cloud-object-storage" - target_service_name = "kms" - roles = ["Reader"] - description = "Authorization Policy for test scenario" - } - ` -} - -func testAccCheckIBMIAMAuthorizationPolicyResourceInstance(instanceName string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance1" { - name = "%s" - service = "cloud-object-storage" - plan = "lite" - location = "global" - } - - resource "ibm_resource_instance" "instance2" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "cloud-object-storage" - source_resource_instance_id = ibm_resource_instance.instance1.id - target_service_name = "kms" - target_resource_instance_id = ibm_resource_instance.instance2.id - roles = ["Reader"] - } - - `, instanceName, instanceName) -} - -func testAccCheckIBMIAMAuthorizationPolicyResourceType() string { - return ` - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "is" - source_resource_type = "load-balancer" - target_service_name = "cloudcerts" - roles = ["Reader"] - } - ` -} -func testAccCheckIBMIAMAuthorizationPolicyDelegatorRole() string { - return ` - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "databases-for-redis" - target_service_name = "kms" - roles = ["Reader", "AuthorizationDelegator"] - } - ` -} - -func testAccCheckIBMIAMAuthorizationPolicyResourceGroup(sResourceGroup, tResourceGroup string) string { - return fmt.Sprintf(` - - resource "ibm_resource_group" "source_resource_group" { - name = "%s" - } - - resource "ibm_resource_group" "target_resource_group" { - name = "%s" - } - - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "cloud-object-storage" - source_resource_group_id = ibm_resource_group.source_resource_group.id - target_service_name = "kms" - target_resource_group_id = ibm_resource_group.target_resource_group.id - roles = ["Reader"] - } - - `, sResourceGroup, tResourceGroup) -} diff --git a/ibm/resource_ibm_iam_authorization_policy.go b/ibm/resource_ibm_iam_authorization_policy.go deleted file mode 100644 index 16c75d7a3..000000000 --- a/ibm/resource_ibm_iam_authorization_policy.go +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - - "github.com/IBM-Cloud/bluemix-go/models" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMAuthorizationPolicy() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMAuthorizationPolicyCreate, - Read: resourceIBMIAMAuthorizationPolicyRead, - Update: resourceIBMIAMAuthorizationPolicyUpdate, - Delete: resourceIBMIAMAuthorizationPolicyDelete, - Exists: resourceIBMIAMAuthorizationPolicyExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "source_service_name": { - Type: schema.TypeString, - Required: true, - Description: "The source service name", - ForceNew: true, - }, - - "target_service_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The target service name", - }, - - "roles": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - - "source_resource_instance_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The source resource instance Id", - }, - - "target_resource_instance_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The target resource instance Id", - }, - - "source_resource_group_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The source resource group Id", - }, - - "target_resource_group_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The target resource group Id", - }, - - "source_resource_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Resource type of source service", - }, - - "target_resource_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Resource type of target service", - }, - - "source_service_account": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "Account GUID of source service", - }, - - "version": { - Type: schema.TypeString, - Computed: true, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the Policy", - }, - }, - } -} - -func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interface{}) error { - sourceServiceName := d.Get("source_service_name").(string) - targetServiceName := d.Get("target_service_name").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - iampapClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - sourceServiceAccount := userDetails.userAccount - - if account, ok := d.GetOk("source_service_account"); ok { - sourceServiceAccount = account.(string) - } - - accountIdSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("accountId"), - Value: &sourceServiceAccount, - } - serviceNameSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("serviceName"), - Value: &sourceServiceName, - } - - policySubject := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*accountIdSubjectAttribute, *serviceNameSubjectAttribute}, - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(userDetails.userAccount), - Operator: core.StringPtr("stringEquals"), - } - - serviceNameResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceName"), - Value: core.StringPtr(targetServiceName), - Operator: core.StringPtr("stringEquals"), - } - - policyResource := &iampolicymanagementv1.PolicyResource{ - Attributes: []iampolicymanagementv1.ResourceAttribute{*accountIDResourceAttribute, *serviceNameResourceAttribute}, - } - - if sID, ok := d.GetOk("source_resource_instance_id"); ok { - serviceInstanceSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("serviceInstance"), - Value: core.StringPtr(sID.(string)), - } - policySubject.Attributes = append(policySubject.Attributes, serviceInstanceSubjectAttribute) - } - - if tID, ok := d.GetOk("target_resource_instance_id"); ok { - serviceInstanceResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceInstance"), - Value: core.StringPtr(tID.(string)), - } - policyResource.Attributes = append(policyResource.Attributes, serviceInstanceResourceAttribute) - } - - if sType, ok := d.GetOk("source_resource_type"); ok { - resourceTypeSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("resourceType"), - Value: core.StringPtr(sType.(string)), - } - policySubject.Attributes = append(policySubject.Attributes, resourceTypeSubjectAttribute) - } - - if tType, ok := d.GetOk("target_resource_type"); ok { - resourceTypeResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceType"), - Value: core.StringPtr(tType.(string)), - } - policyResource.Attributes = append(policyResource.Attributes, resourceTypeResourceAttribute) - } - - if sResGrpID, ok := d.GetOk("source_resource_group_id"); ok { - resourceGroupSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("resourceGroupId"), - Value: core.StringPtr(sResGrpID.(string)), - } - policySubject.Attributes = append(policySubject.Attributes, resourceGroupSubjectAttribute) - } - - if tResGrpID, ok := d.GetOk("target_resource_group_id"); ok { - resourceGroupResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceGroupId"), - Value: core.StringPtr(tResGrpID.(string)), - } - policyResource.Attributes = append(policyResource.Attributes, resourceGroupResourceAttribute) - } - - roles, err := getAuthorizationRolesByName(expandStringList(d.Get("roles").([]interface{})), sourceServiceName, targetServiceName, meta) - if err != nil { - return err - } - - createPolicyOptions := iampapClient.NewCreatePolicyOptions( - "authorization", - []iampolicymanagementv1.PolicySubject{*policySubject}, - roles, - []iampolicymanagementv1.PolicyResource{*policyResource}, - ) - - if description, ok := d.GetOk("description"); ok { - des := description.(string) - createPolicyOptions.Description = &des - } - - authPolicy, resp, err := iampapClient.CreatePolicy(createPolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error creating authorization policy: %s %s", err, resp) - } - - d.SetId(*authPolicy.ID) - - return resourceIBMIAMAuthorizationPolicyRead(d, meta) -} - -func resourceIBMIAMAuthorizationPolicyRead(d *schema.ResourceData, meta interface{}) error { - - iampapClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: core.StringPtr(d.Id()), - } - - authorizationPolicy, resp, err := iampapClient.GetPolicy(getPolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error retrieving authorizationPolicy: %s %s", err, resp) - } - roles := make([]string, len(authorizationPolicy.Roles)) - for i, role := range authorizationPolicy.Roles { - roles[i] = *role.DisplayName - } - if authorizationPolicy.Description != nil { - d.Set("description", *authorizationPolicy.Description) - } - d.Set("roles", roles) - source := authorizationPolicy.Subjects[0] - target := authorizationPolicy.Resources[0] - d.Set("source_service_name", getSubjectAttribute("serviceName", source)) - d.Set("target_service_name", getResourceAttribute("serviceName", target)) - d.Set("source_resource_instance_id", getSubjectAttribute("serviceInstance", source)) - d.Set("target_resource_instance_id", getResourceAttribute("serviceInstance", target)) - d.Set("source_resource_type", getSubjectAttribute("resourceType", source)) - d.Set("target_resource_type", getResourceAttribute("resourceType", target)) - d.Set("source_service_account", getSubjectAttribute("accountId", source)) - d.Set("source_resource_group_id", getSubjectAttribute("resourceGroupId", source)) - d.Set("target_resource_group_id", getResourceAttribute("resourceGroupId", target)) - return nil -} - -// Returns nil, because ibmcloud iam cli authoirization policy does not have an update command -func resourceIBMIAMAuthorizationPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMIAMAuthorizationPolicyDelete(d *schema.ResourceData, meta interface{}) error { - iampapClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - authorizationPolicyID := d.Id() - - deletePolicyOptions := &iampolicymanagementv1.DeletePolicyOptions{ - PolicyID: core.StringPtr(authorizationPolicyID), - } - resp, err := iampapClient.DeletePolicy(deletePolicyOptions) - if err != nil { - log.Printf( - "Error deleting authorization policy: %s, %s", err, resp) - } - - d.SetId("") - - return nil -} - -func resourceIBMIAMAuthorizationPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iampapClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: core.StringPtr(d.Id()), - } - authorizationPolicy, resp, err := iampapClient.GetPolicy(getPolicyOptions) - if err != nil || authorizationPolicy == nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("[ERROR] Error communicating with the API: %s\n%s", err, resp) - } - - if authorizationPolicy != nil && authorizationPolicy.State != nil && *authorizationPolicy.State == "deleted" { - return false, nil - } - - return *authorizationPolicy.ID == d.Id(), nil -} - -func getAuthorizationRolesByName(roleNames []string, sourceServiceName string, targetServiceName string, meta interface{}) ([]iampolicymanagementv1.PolicyRole, error) { - - iamClient, err := meta.(ClientSession).IAMAPI() - if err != nil { - return []iampolicymanagementv1.PolicyRole{}, err - } - iamRepo := iamClient.ServiceRoles() - roles, err := iamRepo.ListAuthorizationRoles(sourceServiceName, targetServiceName) - convertedRoles := convertRoleModels(roles) - if err != nil { - return []iampolicymanagementv1.PolicyRole{}, err - } - filteredRoles := []iampolicymanagementv1.PolicyRole{} - filteredRoles, err = getRolesFromRoleNames(roleNames, convertedRoles) - if err != nil { - return []iampolicymanagementv1.PolicyRole{}, err - } - return filteredRoles, nil -} - -// ConvertRoleModels will transform role models returned from "/v1/roles" to the model used by policy -func convertRoleModels(roles []models.PolicyRole) []iampolicymanagementv1.PolicyRole { - results := make([]iampolicymanagementv1.PolicyRole, len(roles)) - for i, r := range roles { - results[i] = iampolicymanagementv1.PolicyRole{ - RoleID: core.StringPtr(r.ID.String()), - DisplayName: core.StringPtr(r.DisplayName), - } - } - return results -} diff --git a/ibm/resource_ibm_iam_custom_role.go b/ibm/resource_ibm_iam_custom_role.go deleted file mode 100644 index 3223c8a96..000000000 --- a/ibm/resource_ibm_iam_custom_role.go +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - iamCRDisplayName = "display_name" - iamCRName = "name" - iamCRDescription = "description" - iamCRActions = "actions" - iamCRServiceName = "service" -) - -func resourceIBMIAMCustomRole() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMCustomRoleCreate, - Read: resourceIBMIAMCustomRoleRead, - Update: resourceIBMIAMCustomRoleUpdate, - Delete: resourceIBMIAMCustomRoleDelete, - Exists: resourceIBMIAMCustomRoleExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - iamCRDisplayName: { - Type: schema.TypeString, - Required: true, - Description: "Display Name of the Custom Role", - ValidateFunc: InvokeValidator("ibm_iam_custom_role", iamCRDisplayName), - }, - - iamCRName: { - Type: schema.TypeString, - Required: true, - Description: "The name of the custom Role", - ForceNew: true, - ValidateFunc: InvokeValidator("ibm_iam_custom_role", iamCRName), - }, - iamCRDescription: { - Type: schema.TypeString, - Optional: true, - Description: "The description of the role", - ValidateFunc: InvokeValidator("ibm_iam_custom_role", iamCRDescription), - }, - iamCRServiceName: { - Type: schema.TypeString, - Required: true, - Description: "The Service Name", - ForceNew: true, - }, - iamCRActions: { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The actions of the role", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "crn of the Custom Role", - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} - -func resourceIBMIAMCustomRoleValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: iamCRName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Z]{1}[A-Za-z0-9]{0,29}$`, - MinValueLength: 1, - MaxValueLength: 30}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: iamCRDisplayName, - ValidateFunctionIdentifier: StringLenBetween, - Type: TypeString, - Optional: true, - MinValueLength: 1, - MaxValueLength: 50}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: iamCRDescription, - ValidateFunctionIdentifier: StringLenBetween, - Type: TypeString, - Optional: true, - MinValueLength: 1, - MaxValueLength: 250}) - - ibmIAMCustomRoleResourceValidator := ResourceValidator{ResourceName: "ibm_iam_custom_role", Schema: validateSchema} - return &ibmIAMCustomRoleResourceValidator -} - -func resourceIBMIAMCustomRoleCreate(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - displayName := d.Get(iamCRDisplayName).(string) - name := d.Get(iamCRName).(string) - description := d.Get(iamCRDescription).(string) - serviceName := d.Get(iamCRServiceName).(string) - actionList := expandStringList(d.Get(iamCRActions).([]interface{})) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - roleOptions := &iampolicymanagementv1.CreateRoleOptions{ - DisplayName: &displayName, - Actions: actionList, - Name: &name, - AccountID: &userDetails.userAccount, - ServiceName: &serviceName, - Description: &description, - } - - role, response, err := iamPolicyManagementClient.CreateRole(roleOptions) - if err != nil || role == nil { - return fmt.Errorf("Error creating Custom Roles: %s\n%s", err, response) - } - - d.SetId(*role.ID) - - return resourceIBMIAMCustomRoleRead(d, meta) -} - -func resourceIBMIAMCustomRoleRead(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - roleID := d.Id() - roleOptions := &iampolicymanagementv1.GetRoleOptions{ - RoleID: &roleID, - } - - role, response, err := iamPolicyManagementClient.GetRole(roleOptions) - if err != nil || role == nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error retrieving Custom Roles: %s\n%s", err, response) - } - - d.Set(iamCRDisplayName, role.DisplayName) - d.Set(iamCRName, role.Name) - d.Set(iamCRDescription, role.Description) - d.Set(iamCRServiceName, role.ServiceName) - d.Set(iamCRActions, role.Actions) - d.Set("crn", role.CRN) - - d.Set(ResourceName, role.Name) - d.Set(ResourceCRN, role.CRN) - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - - d.Set(ResourceControllerURL, rcontroller+"/iam/roles") - - return nil -} - -func resourceIBMIAMCustomRoleUpdate(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - roleID := d.Id() - - updatedDescription := d.Get(iamCRDescription).(string) - updatedActions := expandStringList(d.Get(iamCRActions).([]interface{})) - updatedDisplayName := d.Get(iamCRDisplayName).(string) - - if d.HasChange("display_name") || d.HasChange("desciption") || d.HasChange("actions") { - roleGetOptions := &iampolicymanagementv1.GetRoleOptions{ - RoleID: &roleID, - } - - role, response, err := iamPolicyManagementClient.GetRole(roleGetOptions) - if err != nil || role == nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error retrieving Custom Roles: %s\n%s", err, response) - } - - roleETag := response.Headers.Get("ETag") - roleUpdateOptions := &iampolicymanagementv1.UpdateRoleOptions{ - RoleID: &roleID, - IfMatch: &roleETag, - DisplayName: &updatedDisplayName, - Description: &updatedDescription, - Actions: updatedActions, - } - - _, response, err = iamPolicyManagementClient.UpdateRole(roleUpdateOptions) - if err != nil { - return fmt.Errorf("Error updating Custom Roles: %s\n%s", err, response) - } - } - - return resourceIBMIAMCustomRoleRead(d, meta) -} - -func resourceIBMIAMCustomRoleDelete(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - roleID := d.Id() - roleDeleteOptions := &iampolicymanagementv1.DeleteRoleOptions{ - RoleID: &roleID, - } - - response, err := iamPolicyManagementClient.DeleteRole(roleDeleteOptions) - if err != nil && !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error deleting Custom Roles: %s\n%s", err, response) - } - - d.SetId("") - - return nil -} - -func resourceIBMIAMCustomRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - roleID := d.Id() - - roleGetOptions := &iampolicymanagementv1.GetRoleOptions{ - RoleID: &roleID, - } - - role, response, err := iamPolicyManagementClient.GetRole(roleGetOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error retrieving Custom Roles: %s\n%s", err, response) - } - - return *role.ID == roleID, nil -} diff --git a/ibm/resource_ibm_iam_service_policy.go b/ibm/resource_ibm_iam_service_policy.go deleted file mode 100644 index eea5ad7b1..000000000 --- a/ibm/resource_ibm_iam_service_policy.go +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMServicePolicy() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMServicePolicyCreate, - Read: resourceIBMIAMServicePolicyRead, - Update: resourceIBMIAMServicePolicyUpdate, - Delete: resourceIBMIAMServicePolicyDelete, - Exists: resourceIBMIAMServicePolicyExists, - Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - resources, resourceAttributes, err := importServicePolicy(d, meta) - if err != nil { - return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) - } - d.Set("resources", resources) - d.Set("resource_attributes", resourceAttributes) - return []*schema.ResourceData{d}, nil - }, - }, - - Schema: map[string]*schema.Schema{ - "iam_service_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"iam_service_id", "iam_id"}, - Description: "UUID of ServiceID", - ForceNew: true, - }, - "iam_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"iam_service_id", "iam_id"}, - Description: "IAM ID of ServiceID", - ForceNew: true, - }, - "roles": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - - "resources": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"account_management", "resource_attributes"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Optional: true, - Description: "Service name of the policy definition", - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of resource instance of the policy definition", - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Description: "Region of the policy definition", - }, - - "resource_type": { - Type: schema.TypeString, - Optional: true, - Description: "Resource type of the policy definition", - }, - - "resource": { - Type: schema.TypeString, - Optional: true, - Description: "Resource of the policy definition", - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - - "attributes": { - Type: schema.TypeMap, - Optional: true, - Description: "Set resource attributes in the form of 'name=value,name=value....", - Elem: schema.TypeString, - }, - }, - }, - }, - - "resource_attributes": { - Type: schema.TypeSet, - Optional: true, - Description: "Set resource attributes.", - ConflictsWith: []string{"resources", "account_management"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of attribute.", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of attribute.", - }, - "operator": { - Type: schema.TypeString, - Optional: true, - Default: "stringEquals", - Description: "Operator of attribute.", - }, - }, - }, - }, - "account_management": { - Type: schema.TypeBool, - Default: false, - Optional: true, - Description: "Give access to all account management services", - ConflictsWith: []string{"resources", "resource_attributes"}, - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the Policy", - }, - }, - } -} - -func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) error { - - var iamID string - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ - ID: &serviceIDUUID, - } - serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) - } - iamID = *serviceID.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - policyOptions, err := generatePolicyOptions(d, meta) - if err != nil { - return err - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &iamID, - } - - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(userDetails.userAccount), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - policyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if desc, ok := d.GetOk("description"); ok { - des := desc.(string) - createPolicyOptions.Description = &des - } - - servicePolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error creating servicePolicy: %s %s", err, res) - } - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - *servicePolicy.ID, - ) - - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || policy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil { - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID)) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", iamID, *servicePolicy.ID)) - } - return fmt.Errorf("[ERROR] Error fetching service policy: %s %s", err, res) - } - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID)) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", iamID, *servicePolicy.ID)) - } - - return resourceIBMIAMServicePolicyRead(d, meta) -} - -func resourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - serviceIDUUID := parts[0] - servicePolicyID := parts[1] - servicePolicy := &iampolicymanagementv1.Policy{} - res := &core.DetailedResponse{} - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - servicePolicyID, - ) - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - servicePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || servicePolicy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - servicePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil || servicePolicy == nil { - return fmt.Errorf("[ERROR] Error retrieving servicePolicy: %s %s", err, res) - } - if strings.HasPrefix(serviceIDUUID, "iam-") { - d.Set("iam_id", serviceIDUUID) - } else { - d.Set("iam_service_id", serviceIDUUID) - } - - roles := make([]string, len(servicePolicy.Roles)) - for i, role := range servicePolicy.Roles { - roles[i] = *role.DisplayName - } - d.Set("roles", roles) - - if _, ok := d.GetOk("resources"); ok { - d.Set("resources", flattenPolicyResource(servicePolicy.Resources)) - } - if _, ok := d.GetOk("resource_attributes"); ok { - d.Set("resource_attributes", flattenPolicyResourceAttributes(servicePolicy.Resources)) - } - if len(servicePolicy.Resources) > 0 { - if *getResourceAttribute("serviceType", servicePolicy.Resources[0]) == "service" { - d.Set("account_management", false) - } - if *getResourceAttribute("serviceType", servicePolicy.Resources[0]) == "platform_service" { - d.Set("account_management", true) - } - } - if servicePolicy.Description != nil { - d.Set("description", *servicePolicy.Description) - } - - return nil -} - -func resourceIBMIAMServicePolicyUpdate(d *schema.ResourceData, meta interface{}) error { - - if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") { - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - servicePolicyID := parts[1] - - var iamID string - if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - serviceIDUUID := v.(string) - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ - ID: &serviceIDUUID, - } - serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) - } - iamID = *serviceID.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - createPolicyOptions, err := generatePolicyOptions(d, meta) - if err != nil { - return err - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(userDetails.userAccount), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &iamID, - } - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - servicePolicyID, - ) - policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || policy == nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("[ERROR] Error retrieving Policy: %s\n%s", err, response) - } - - servicePolicyETag := response.Headers.Get("ETag") - updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( - servicePolicyID, - servicePolicyETag, - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - createPolicyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if desc, ok := d.GetOk("description"); ok { - des := desc.(string) - updatePolicyOptions.Description = &des - } - - _, _, err = iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error updating service policy: %s", err) - } - - } - - return resourceIBMIAMServicePolicyRead(d, meta) - -} - -func resourceIBMIAMServicePolicyDelete(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - servicePolicyID := parts[1] - - deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( - servicePolicyID, - ) - - _, err = iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting service policy: %s", err) - } - - d.SetId("") - - return nil -} - -func resourceIBMIAMServicePolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of serviceID(OR)iamID/PolicyID", d.Id()) - } - serviceIDUUID := parts[0] - servicePolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - servicePolicyID, - ) - - servicePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || servicePolicy == nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("[ERROR] Error communicating with the API: %s\n%s", err, resp) - } - - if servicePolicy != nil && servicePolicy.State != nil && *servicePolicy.State == "deleted" { - return false, nil - } - - tempID := fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID) - - return tempID == d.Id(), nil -} - -func importServicePolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return nil, nil, err - } - parts, err := idParts(d.Id()) - if err != nil { - return nil, nil, err - } - servicePolicyID := parts[1] - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - servicePolicyID, - ) - servicePolicy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return nil, nil, fmt.Errorf("[ERROR] Error retrieving servicePolicy: %s", err) - } - resources := flattenPolicyResource(servicePolicy.Resources) - resource_attributes := flattenPolicyResourceAttributes(servicePolicy.Resources) - return resources, resource_attributes, nil -} diff --git a/ibm/resource_ibm_iam_service_policy_test.go b/ibm/resource_ibm_iam_service_policy_test.go deleted file mode 100644 index a8dadfd5f..000000000 --- a/ibm/resource_ibm_iam_service_policy_test.go +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMServicePolicy_Basic(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyBasic(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Creation for test scenario"), - ), - }, - { - Config: testAccCheckIBMIAMServicePolicyUpdateRole(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Update for test scenario"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_With_Service(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyService(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - ), - }, - { - Config: testAccCheckIBMIAMServicePolicyUpdateServiceAndRegion(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.region", "us-south"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_With_ResourceInstance(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyResourceInstance(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "3"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_With_Resource_Group(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyResourceGroup(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "containers-kubernetes"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_With_Resource_Type(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyResourceType(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_import(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_service_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyImport(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"resources", "resource_attributes"}, - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_account_management(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_service_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyAccountManagement(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "account_management", "true"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicyWithCustomRole(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyWithCustomRole(name, crName, displayName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMServicePolicy_With_Resource_Attributes(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMServicePolicyResourceAttributes(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), - ), - }, - { - Config: testAccCheckIBMIAMServicePolicyResourceAttributesUpdate(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_service_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), - ), - }, - }, - }) -} -func testAccCheckIBMIAMServicePolicyDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_service_policy" { - continue - } - policyID := rs.Primary.ID - parts, err := idParts(policyID) - if err != nil { - return err - } - servicePolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - servicePolicyID, - ) - - // Try to find the key - destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) - - if err == nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) - } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMServicePolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - policyID := rs.Primary.ID - - parts, err := idParts(policyID) - if err != nil { - return err - } - servicePolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - servicePolicyID, - ) - - // Try to find the key - policy, _, err := rsContClient.GetPolicy(getPolicyOptions) - if err != nil { - return err - } - obj = *policy - return nil - } -} - -func testAccCheckIBMIAMServicePolicyBasic(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - tags = ["tag1"] - description = "IAM Service Policy Creation for test scenario" - } - - `, name) -} - -func testAccCheckIBMIAMServicePolicyUpdateRole(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer", "Manager"] - tags = ["tag1", "tag2"] - description = "IAM Service Policy Update for test scenario" - } - `, name) -} - -func testAccCheckIBMIAMServicePolicyService(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - - resources { - service = "cloudantnosqldb" - } - } - `, name) -} - -func testAccCheckIBMIAMServicePolicyUpdateServiceAndRegion(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer", "Manager"] - - resources { - service = "cloudantnosqldb" - region = "us-south" - } - } - `, name) -} - -func testAccCheckIBMIAMServicePolicyResourceInstance(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } - } - - - `, name, name) -} - -func testAccCheckIBMIAMServicePolicyResourceGroup(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } - } - - - `, name) -} - -func testAccCheckIBMIAMServicePolicyResourceType(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Administrator"] - - resources { - resource_type = "resource-group" - resource = data.ibm_resource_group.group.id - } - } - `, name) -} - -func testAccCheckIBMIAMServicePolicyImport(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - } - - `, name) -} - -func testAccCheckIBMIAMServicePolicyAccountManagement(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - account_management = true - } - - `, name) -} - -func testAccCheckIBMIAMServicePolicyWithCustomRole(name, crName, displayName string) string { - return fmt.Sprintf(` - - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - resource "ibm_iam_custom_role" "customrole" { - name = "%s" - display_name = "%s" - description = "role for test scenario1" - service = "kms" - actions = ["kms.secrets.rotate"] - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] - tags = ["tag1"] - resources { - service = "kms" - } - } - - `, name, crName, displayName) -} - -func testAccCheckIBMIAMServicePolicyResourceAttributes(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - operator = "stringMatch" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} -func testAccCheckIBMIAMServicePolicyResourceAttributesUpdate(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_service_id" "serviceID" { - name = "%s" - } - - resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} diff --git a/ibm/resource_ibm_iam_trusted_profile_link.go b/ibm/resource_ibm_iam_trusted_profile_link.go deleted file mode 100644 index ea0c2bc9a..000000000 --- a/ibm/resource_ibm_iam_trusted_profile_link.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -func resourceIBMIamTrustedProfileLink() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMIamTrustedProfileLinkCreate, - ReadContext: resourceIBMIamTrustedProfileLinkRead, - DeleteContext: resourceIBMIamTrustedProfileLinkDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "ID of the trusted profile.", - }, - "cr_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", - }, - "link": &schema.Schema{ - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - ForceNew: true, - Description: "Link details.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The CRN of the compute resource.", - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", - }, - }, - }, - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Optional name of the Link.", - }, - "link_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Unique identifier of this link.", - }, - "entity_tag": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "version of the claim rule.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the creation date in ISO format.", - }, - "modified_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "If set contains a date time string of the last modification date in ISO format.", - }, - }, - } -} - -func resourceIBMIamTrustedProfileLinkCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - - createLinkOptions := &iamidentityv1.CreateLinkOptions{} - profile := d.Get("profile_id").(string) - createLinkOptions.SetProfileID(profile) - createLinkOptions.SetCrType(d.Get("cr_type").(string)) - link := resourceIBMIamTrustedProfileLinkMapToCreateProfileLinkRequestLink(d.Get("link.0").(map[string]interface{})) - createLinkOptions.SetLink(&link) - if _, ok := d.GetOk("name"); ok { - createLinkOptions.SetName(d.Get("name").(string)) - } - - profileLink, response, err := iamIdentityClient.CreateLink(createLinkOptions) - if err != nil { - log.Printf("[DEBUG] CreateLink failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("CreateLink failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s", profile, *profileLink.ID)) - - return resourceIBMIamTrustedProfileLinkRead(context, d, meta) -} - -func resourceIBMIamTrustedProfileLinkMapToCreateProfileLinkRequestLink(createProfileLinkRequestLinkMap map[string]interface{}) iamidentityv1.CreateProfileLinkRequestLink { - createProfileLinkRequestLink := iamidentityv1.CreateProfileLinkRequestLink{} - - createProfileLinkRequestLink.CRN = core.StringPtr(createProfileLinkRequestLinkMap["crn"].(string)) - createProfileLinkRequestLink.Namespace = core.StringPtr(createProfileLinkRequestLinkMap["namespace"].(string)) - if createProfileLinkRequestLinkMap["name"] != nil { - createProfileLinkRequestLink.Name = core.StringPtr(createProfileLinkRequestLinkMap["name"].(string)) - } - - return createProfileLinkRequestLink -} - -func resourceIBMIamTrustedProfileLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - parts, err := idParts(d.Id()) - if err != nil { - return diag.FromErr(fmt.Errorf("Invalid ID %s", err)) - } - getLinkOptions := &iamidentityv1.GetLinkOptions{} - - getLinkOptions.SetProfileID(parts[0]) - getLinkOptions.SetLinkID(parts[1]) - - profileLink, response, err := iamIdentityClient.GetLink(getLinkOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetLink failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetLink failed %s\n%s", err, response)) - } - - if err = d.Set("profile_id", getLinkOptions.ProfileID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting profile_id: %s", err)) - } - if err = d.Set("cr_type", profileLink.CrType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cr_type: %s", err)) - } - linkMap := resourceIBMIamTrustedProfileLinkCreateProfileLinkRequestLinkToMap(*profileLink.Link) - if err = d.Set("link", []map[string]interface{}{linkMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting link: %s", err)) - } - if err = d.Set("name", profileLink.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("link_id", profileLink.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) - } - if err = d.Set("entity_tag", profileLink.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) - } - if err = d.Set("created_at", dateTimeToString(profileLink.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - if err = d.Set("modified_at", dateTimeToString(profileLink.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) - } - - return nil -} - -func resourceIBMIamTrustedProfileLinkCreateProfileLinkRequestLinkToMap(createProfileLinkRequestLink iamidentityv1.ProfileLinkLink) map[string]interface{} { - createProfileLinkRequestLinkMap := map[string]interface{}{} - - createProfileLinkRequestLinkMap["crn"] = createProfileLinkRequestLink.CRN - createProfileLinkRequestLinkMap["namespace"] = createProfileLinkRequestLink.Namespace - if createProfileLinkRequestLink.Name != nil { - createProfileLinkRequestLinkMap["name"] = createProfileLinkRequestLink.Name - } - - return createProfileLinkRequestLinkMap -} - -func resourceIBMIamTrustedProfileLinkDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return diag.FromErr(err) - } - parts, err := idParts(d.Id()) - if err != nil { - return diag.FromErr(fmt.Errorf("Invalid ID %s", err)) - } - - deleteLinkOptions := &iamidentityv1.DeleteLinkOptions{} - - deleteLinkOptions.SetProfileID(parts[0]) - deleteLinkOptions.SetLinkID(parts[1]) - - response, err := iamIdentityClient.DeleteLink(deleteLinkOptions) - if err != nil { - log.Printf("[DEBUG] DeleteLink failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("DeleteLink failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_iam_trusted_profile_policy.go b/ibm/resource_ibm_iam_trusted_profile_policy.go deleted file mode 100644 index b9b4eb6f3..000000000 --- a/ibm/resource_ibm_iam_trusted_profile_policy.go +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMTrustedProfilePolicy() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMTrustedProfilePolicyCreate, - Read: resourceIBMIAMTrustedProfilePolicyRead, - Update: resourceIBMIAMTrustedProfilePolicyUpdate, - Delete: resourceIBMIAMTrustedProfilePolicyDelete, - Exists: resourceIBMIAMTrustedProfilePolicyExists, - Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - resources, resourceAttributes, err := importTrustedProfilePolicy(d, meta) - if err != nil { - return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) - } - d.Set("resources", resources) - d.Set("resource_attributes", resourceAttributes) - return []*schema.ResourceData{d}, nil - }, - }, - - Schema: map[string]*schema.Schema{ - "profile_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"profile_id", "iam_id"}, - Description: "UUID of Trusted Profile", - ForceNew: true, - }, - "iam_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"profile_id", "iam_id"}, - Description: "IAM ID of Trusted Profile", - ForceNew: true, - }, - "roles": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - - "resources": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"account_management", "resource_attributes"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Optional: true, - Description: "Service name of the policy definition", - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of resource instance of the policy definition", - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Description: "Region of the policy definition", - }, - - "resource_type": { - Type: schema.TypeString, - Optional: true, - Description: "Resource type of the policy definition", - }, - - "resource": { - Type: schema.TypeString, - Optional: true, - Description: "Resource of the policy definition", - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - - "attributes": { - Type: schema.TypeMap, - Optional: true, - Description: "Set resource attributes in the form of 'name=value,name=value....", - Elem: schema.TypeString, - }, - }, - }, - }, - - "resource_attributes": { - Type: schema.TypeSet, - Optional: true, - Description: "Set resource attributes.", - ConflictsWith: []string{"resources", "account_management"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of attribute.", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of attribute.", - }, - "operator": { - Type: schema.TypeString, - Optional: true, - Default: "stringEquals", - Description: "Operator of attribute.", - }, - }, - }, - }, - "account_management": { - Type: schema.TypeBool, - Default: false, - Optional: true, - Description: "Give access to all account management services", - ConflictsWith: []string{"resources", "resource_attributes"}, - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the Policy", - }, - }, - } -} - -func resourceIBMIAMTrustedProfilePolicyCreate(d *schema.ResourceData, meta interface{}) error { - - var iamID string - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileIDUUID := v.(string) - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getProfileOptions := &iamidentityv1.GetProfileOptions{ - ProfileID: &profileIDUUID, - } - profileID, resp, err := iamClient.GetProfile(getProfileOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error] Error getting trusted profile ID %s %s", err, resp) - } - iamID = *profileID.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - policyOptions, err := generatePolicyOptions(d, meta) - if err != nil { - return err - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &iamID, - } - - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(userDetails.userAccount), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - policyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if desc, ok := d.GetOk("description"); ok { - des := desc.(string) - createPolicyOptions.Description = &des - } - - trustedProfilePolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error creating trustedProfilePolicy: %s %s", err, res) - } - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - *trustedProfilePolicy.ID, - ) - - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || policy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil { - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileIDUUID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID)) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", iamID, *trustedProfilePolicy.ID)) - } - return fmt.Errorf("[ERROR] Error fetching trusted profile policy: %s %s", err, res) - } - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileIDUUID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID)) - } else if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID := v.(string) - d.SetId(fmt.Sprintf("%s/%s", iamID, *trustedProfilePolicy.ID)) - } - - return resourceIBMIAMTrustedProfilePolicyRead(d, meta) -} - -func resourceIBMIAMTrustedProfilePolicyRead(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - profileIDUUID := parts[0] - trustedProfilePolicyID := parts[1] - trustedProfilePolicy := &iampolicymanagementv1.Policy{} - res := &core.DetailedResponse{} - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - trustedProfilePolicyID, - ) - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - trustedProfilePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || trustedProfilePolicy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - trustedProfilePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil || trustedProfilePolicy == nil { - return fmt.Errorf("[ERROR] Error retrieving trusted profile policy: %s %s", err, res) - } - if strings.HasPrefix(profileIDUUID, "iam-") { - d.Set("iam_id", profileIDUUID) - } else { - d.Set("profile_id", profileIDUUID) - } - - roles := make([]string, len(trustedProfilePolicy.Roles)) - for i, role := range trustedProfilePolicy.Roles { - roles[i] = *role.DisplayName - } - d.Set("roles", roles) - - if _, ok := d.GetOk("resources"); ok { - d.Set("resources", flattenPolicyResource(trustedProfilePolicy.Resources)) - } - if _, ok := d.GetOk("resource_attributes"); ok { - d.Set("resource_attributes", flattenPolicyResourceAttributes(trustedProfilePolicy.Resources)) - } - if len(trustedProfilePolicy.Resources) > 0 { - if *getResourceAttribute("serviceType", trustedProfilePolicy.Resources[0]) == "service" { - d.Set("account_management", false) - } - if *getResourceAttribute("serviceType", trustedProfilePolicy.Resources[0]) == "platform_service" { - d.Set("account_management", true) - } - } - if trustedProfilePolicy.Description != nil { - d.Set("description", *trustedProfilePolicy.Description) - } - - return nil -} - -func resourceIBMIAMTrustedProfilePolicyUpdate(d *schema.ResourceData, meta interface{}) error { - - if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") { - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - trustedProfilePolicyID := parts[1] - - var iamID string - if v, ok := d.GetOk("profile_id"); ok && v != nil { - profileIDUUID := v.(string) - - iamClient, err := meta.(ClientSession).IAMIdentityV1API() - if err != nil { - return err - } - getProfileIDOptions := iamidentityv1.GetProfileOptions{ - ProfileID: &profileIDUUID, - } - profileID, resp, err := iamClient.GetProfile(&getProfileIDOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error] Error getting trusted profile ID %s %s", err, resp) - } - iamID = *profileID.IamID - } - if v, ok := d.GetOk("iam_id"); ok && v != nil { - iamID = v.(string) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - createPolicyOptions, err := generatePolicyOptions(d, meta) - if err != nil { - return err - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(userDetails.userAccount), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &iamID, - } - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - trustedProfilePolicyID, - ) - policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || policy == nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("[ERROR] Error retrieving Policy: %s\n%s", err, response) - } - - trustedProfilePolicyETag := response.Headers.Get("ETag") - updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( - trustedProfilePolicyID, - trustedProfilePolicyETag, - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - createPolicyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if desc, ok := d.GetOk("description"); ok { - des := desc.(string) - updatePolicyOptions.Description = &des - } - - _, resp, err := iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error updating trusted profile policy: %s: %s", err, resp) - } - - } - - return resourceIBMIAMTrustedProfilePolicyRead(d, meta) - -} - -func resourceIBMIAMTrustedProfilePolicyDelete(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - trustedProfilePolicyID := parts[1] - - deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( - trustedProfilePolicyID, - ) - - resp, err := iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting trusted profile policy: %s %s", err, resp) - } - - d.SetId("") - - return nil -} - -func resourceIBMIAMTrustedProfilePolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of profileID(OR)iamID/PolicyID", d.Id()) - } - profileIDUUID := parts[0] - trustedProfilePolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - trustedProfilePolicyID, - ) - - trustedProfilePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || trustedProfilePolicy == nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("[ERROR] Error getting trusted profile policy: %s\n%s", err, resp) - } - - if trustedProfilePolicy != nil && trustedProfilePolicy.State != nil && *trustedProfilePolicy.State == "deleted" { - return false, nil - } - - tempID := fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID) - - return tempID == d.Id(), nil -} - -func importTrustedProfilePolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return nil, nil, err - } - parts, err := idParts(d.Id()) - if err != nil { - return nil, nil, err - } - trustedProfilePolicyID := parts[1] - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - trustedProfilePolicyID, - ) - trustedProfilePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return nil, nil, fmt.Errorf("[ERROR] Error retrieving trusted profile policy: %s %s", err, resp) - } - resources := flattenPolicyResource(trustedProfilePolicy.Resources) - resource_attributes := flattenPolicyResourceAttributes(trustedProfilePolicy.Resources) - return resources, resource_attributes, nil -} diff --git a/ibm/resource_ibm_iam_trusted_profile_policy_test.go b/ibm/resource_ibm_iam_trusted_profile_policy_test.go deleted file mode 100644 index ec4f2d2ba..000000000 --- a/ibm/resource_ibm_iam_trusted_profile_policy_test.go +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMTrustedProfilePolicyBasic(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyBasic(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "description", "IAM Trusted Profile Policy Creation for test scenario"), - ), - }, - { - Config: testAccCheckIBMIAMTrustedProfilePolicyUpdateRole(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "description", "IAM Trusted Profile Policy Update for test scenario"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_With_Service(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyService(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - ), - }, - { - Config: testAccCheckIBMIAMTrustedProfilePolicyUpdateServiceAndRegion(name), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.region", "us-south"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_With_ResourceInstance(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyResourceInstance(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "3"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Group(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyResourceGroup(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "containers-kubernetes"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Type(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyResourceType(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_import(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_trusted_profile_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyImport(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"resources", "resource_attributes"}, - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_account_management(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_trusted_profile_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyAccountManagement(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "account_management", "true"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicyWithCustomRole(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyWithCustomRole(name, crName, displayName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Attributes(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMTrustedProfilePolicyResourceAttributes(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_attributes.#", "2"), - ), - }, - { - Config: testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesUpdate(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_trusted_profile_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), - resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_attributes.#", "2"), - ), - }, - }, - }) -} -func testAccCheckIBMIAMTrustedProfilePolicyDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_trusted_profile_policy" { - continue - } - policyID := rs.Primary.ID - parts, err := idParts(policyID) - if err != nil { - return err - } - profilePolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - profilePolicyID, - ) - - // Try to find the key - destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) - - if err == nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) - } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMTrustedProfilePolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - policyID := rs.Primary.ID - - parts, err := idParts(policyID) - if err != nil { - return err - } - profilePolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - profilePolicyID, - ) - - // Try to find the key - policy, _, err := rsContClient.GetPolicy(getPolicyOptions) - if err != nil { - return err - } - obj = *policy - return nil - } -} - -func testAccCheckIBMIAMTrustedProfilePolicyBasic(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - tags = ["tag1"] - description = "IAM Trusted Profile Policy Creation for test scenario" - } - - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyUpdateRole(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer", "Manager"] - tags = ["tag1", "tag2"] - description = "IAM Trusted Profile Policy Update for test scenario" - } - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyService(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - - resources { - service = "cloudantnosqldb" - } - } - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyUpdateServiceAndRegion(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer", "Manager"] - - resources { - service = "cloudantnosqldb" - region = "us-south" - } - } - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyResourceInstance(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } - } - - - `, name, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyResourceGroup(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } - } - - - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyResourceType(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Administrator"] - - resources { - resource_type = "resource-group" - resource = data.ibm_resource_group.group.id - } - } - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyImport(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - } - - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyAccountManagement(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - account_management = true - } - - `, name) -} - -func testAccCheckIBMIAMTrustedProfilePolicyWithCustomRole(name, crName, displayName string) string { - return fmt.Sprintf(` - - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - resource "ibm_iam_custom_role" "customrole" { - name = "%s" - display_name = "%s" - description = "role for test scenario1" - service = "kms" - actions = ["kms.secrets.rotate"] - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] - tags = ["tag1"] - resources { - service = "kms" - } - } - - `, name, crName, displayName) -} - -func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributes(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - operator = "stringMatch" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} -func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesUpdate(name string) string { - return fmt.Sprintf(` - resource "ibm_iam_trusted_profile" "profileID" { - name = "%s" - } - - resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, name) -} diff --git a/ibm/resource_ibm_iam_user_policy.go b/ibm/resource_ibm_iam_user_policy.go deleted file mode 100644 index 1fa3a40f4..000000000 --- a/ibm/resource_ibm_iam_user_policy.go +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMIAMUserPolicy() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMIAMUserPolicyCreate, - Read: resourceIBMIAMUserPolicyRead, - Update: resourceIBMIAMUserPolicyUpdate, - Delete: resourceIBMIAMUserPolicyDelete, - Exists: resourceIBMIAMUserPolicyExists, - Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - resources, resourceAttributes, err := importServicePolicy(d, meta) - if err != nil { - return nil, fmt.Errorf("Error reading resource ID: %s", err) - } - d.Set("resources", resources) - d.Set("resource_attributes", resourceAttributes) - return []*schema.ResourceData{d}, nil - }, - }, - Schema: map[string]*schema.Schema{ - - "ibm_id": { - Description: "The ibm id or email of user", - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "roles": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Role names of the policy definition", - }, - - "resources": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"account_management", "resource_attributes"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service": { - Type: schema.TypeString, - Optional: true, - Description: "Service name of the policy definition", - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of resource instance of the policy definition", - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Description: "Region of the policy definition", - }, - - "resource_type": { - Type: schema.TypeString, - Optional: true, - Description: "Resource type of the policy definition", - }, - - "resource": { - Type: schema.TypeString, - Optional: true, - Description: "Resource of the policy definition", - }, - - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Description: "ID of the resource group.", - }, - - "attributes": { - Type: schema.TypeMap, - Optional: true, - Description: "Set resource attributes in the form of 'name=value,name=value....", - Elem: schema.TypeString, - }, - }, - }, - }, - - "resource_attributes": { - Type: schema.TypeSet, - Optional: true, - Description: "Set resource attributes.", - ConflictsWith: []string{"resources", "account_management"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of attribute.", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of attribute.", - }, - "operator": { - Type: schema.TypeString, - Optional: true, - Default: "stringEquals", - Description: "Operator of attribute.", - }, - }, - }, - }, - "account_management": { - Type: schema.TypeBool, - Default: false, - Optional: true, - Description: "Give access to all account management services", - ConflictsWith: []string{"resources", "resource_attributes"}, - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Description of the Policy", - }, - }, - } -} - -func resourceIBMIAMUserPolicyCreate(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - var policyOptions iampolicymanagementv1.CreatePolicyOptions - policyOptions, err = generatePolicyOptions(d, meta) - - if err != nil { - return err - } - - userEmail := d.Get("ibm_id").(string) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - - ibmUniqueID, err := getIBMUniqueId(accountID, userEmail, meta) - if err != nil { - return err - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &ibmUniqueID, - } - - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(accountID), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - policyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if description, ok := d.GetOk("description"); ok { - des := description.(string) - createPolicyOptions.Description = &des - } - - userPolicy, _, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) - - if err != nil { - return err - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: userPolicy.ID, - } - - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || policy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - _, _, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil { - d.SetId(fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID)) - return fmt.Errorf("error fetching user policy: %w", err) - } - d.SetId(fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID)) - - return resourceIBMIAMUserPolicyRead(d, meta) -} - -func resourceIBMIAMUserPolicyRead(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - userEmail := parts[0] - userPolicyID := parts[1] - - if err != nil { - return err - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: core.StringPtr(userPolicyID), - } - userPolicy := &iampolicymanagementv1.Policy{} - res := &core.DetailedResponse{} - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - userPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - - if err != nil || userPolicy == nil { - if res != nil && res.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - userPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) - } - if err != nil || userPolicy == nil { - return fmt.Errorf("Error retrieving userPolicy: %s %s", err, res) - } - d.Set("ibm_id", userEmail) - roles := make([]string, len(userPolicy.Roles)) - - for i, role := range userPolicy.Roles { - roles[i] = *role.DisplayName - } - d.Set("roles", roles) - if _, ok := d.GetOk("resources"); ok { - d.Set("resources", flattenPolicyResource(userPolicy.Resources)) - } - if _, ok := d.GetOk("resource_attributes"); ok { - d.Set("resource_attributes", flattenPolicyResourceAttributes(userPolicy.Resources)) - } - if len(userPolicy.Resources) > 0 { - if *getResourceAttribute("serviceType", userPolicy.Resources[0]) == "service" { - d.Set("account_management", false) - } - if *getResourceAttribute("serviceType", userPolicy.Resources[0]) == "platform_service" { - d.Set("account_management", true) - } - } - if userPolicy.Description != nil { - d.Set("description", *userPolicy.Description) - } - return nil -} - -func resourceIBMIAMUserPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - userEmail := parts[0] - userPolicyID := parts[1] - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - - createPolicyOptions, err := generatePolicyOptions(d, meta) - if err != nil { - return err - } - - ibmUniqueID, err := getIBMUniqueId(accountID, userEmail, meta) - if err != nil { - return err - } - - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), - Value: core.StringPtr(accountID), - Operator: core.StringPtr("stringEquals"), - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), - } - - subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("iam_id"), - Value: &ibmUniqueID, - } - policySubjects := &iampolicymanagementv1.PolicySubject{ - Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, - } - - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: &userPolicyID, - } - policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || policy == nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error retrieving Policy: %s\n%s", err, response) - } - - userPolicyETag := response.Headers.Get("ETag") - updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( - userPolicyID, - userPolicyETag, - "access", - []iampolicymanagementv1.PolicySubject{*policySubjects}, - createPolicyOptions.Roles, - []iampolicymanagementv1.PolicyResource{policyResources}, - ) - - if description, ok := d.GetOk("description"); ok { - des := description.(string) - updatePolicyOptions.Description = &des - } - - policy, _, err = iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) - if err != nil { - return fmt.Errorf("Error updating user policy: %s", err) - } - } - return resourceIBMIAMUserPolicyRead(d, meta) -} - -func resourceIBMIAMUserPolicyDelete(d *schema.ResourceData, meta interface{}) error { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - userPolicyID := parts[1] - - deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( - userPolicyID, - ) - _, err = iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func resourceIBMIAMUserPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return false, err - } - - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of userEmail/PolicyID", d.Id()) - } - userEmail := parts[0] - userPolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - userPolicyID, - ) - - userPolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil || userPolicy == nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with the API: %s\n%s", err, resp) - } - - if userPolicy != nil && userPolicy.State != nil && *userPolicy.State == "deleted" { - return false, nil - } - - tempID := fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID) - - return tempID == d.Id(), nil -} - -func importUserPolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return nil, nil, err - } - parts, err := idParts(d.Id()) - if err != nil { - return nil, nil, err - } - userPolicyID := parts[1] - - getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( - userPolicyID, - ) - userPolicy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) - if err != nil { - return nil, nil, fmt.Errorf("Error retrieving User Policy: %s", err) - } - resources := flattenPolicyResource(userPolicy.Resources) - resource_attributes := flattenPolicyResourceAttributes(userPolicy.Resources) - return resources, resource_attributes, nil -} diff --git a/ibm/resource_ibm_iam_user_policy_test.go b/ibm/resource_ibm_iam_user_policy_test.go deleted file mode 100644 index a8bc82982..000000000 --- a/ibm/resource_ibm_iam_user_policy_test.go +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 -package ibm - -import ( - "fmt" - "regexp" - "testing" - - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMUserPolicy_Basic(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyBasic(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "tags.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Creation for test scenario"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyUpdateRole(), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "tags.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Update for test scenario"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_With_Service(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyService(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyUpdateServiceAndRegion(), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "cloudantnosqldb"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.region", "us-south"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_With_ResourceInstance(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyResourceInstance(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "3"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_With_Resource_Group(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyResourceGroup(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "containers-kubernetes"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_With_Resource_Type(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyResourceType(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_import(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_user_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyImport(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - ), - }, - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"resources", "resource_attributes"}, - }, - }, - }) -} -func TestAccIBMIAMUserPolicy_With_Resource_Attributes(t *testing.T) { - var conf iampolicymanagementv1.Policy - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMUserPolicyResourceAttributes(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_attributes.#", "2"), - ), - }, - { - Config: testAccCheckIBMIAMUserPolicyResourceAttributesUpdate(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_attributes.#", "2"), - ), - }, - }, - }) -} -func TestAccIBMIAMUserPolicy_account_management(t *testing.T) { - var conf iampolicymanagementv1.Policy - name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_iam_user_policy.policy" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyAccountManagement(name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists(resourceName, conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "account_management", "true"), - ), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicy_Invalid_User(t *testing.T) { - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMIAMUserPolicyInvalidUser(), - ExpectError: regexp.MustCompile(`User test@in.ibm.com is not found`), - }, - }, - }) -} - -func TestAccIBMIAMUserPolicyWithCustomRole(t *testing.T) { - var conf iampolicymanagementv1.Policy - crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserPolicyWithCustomRole(crName, displayName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "kms"), - resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMUserPolicyDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_user_policy" { - continue - } - policyID := rs.Primary.ID - parts, err := idParts(policyID) - if err != nil { - return err - } - - userPolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - userPolicyID, - ) - - // Try to find the key - destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) - - if err == nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) - } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { - return fmt.Errorf("Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} - -func testAccCheckIBMIAMUserPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return err - } - - policyID := rs.Primary.ID - parts, err := idParts(policyID) - if err != nil { - return err - } - userPolicyID := parts[1] - - getPolicyOptions := rsContClient.NewGetPolicyOptions( - userPolicyID, - ) - - policy, _, err := rsContClient.GetPolicy(getPolicyOptions) - if err != nil { - return err - } - obj = *policy - return nil - } -} - -func testAccCheckIBMIAMUserPolicyBasic() string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - tags = ["tag1"] - description = "IAM User Policy Creation for test scenario" - } - - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyUpdateRole() string { - return fmt.Sprintf(` - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer", "Manager"] - tags = ["tag1", "tag2"] - description = "IAM User Policy Update for test scenario" - } - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyService() string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - - resources { - service = "cloudantnosqldb" - } - } - - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyUpdateServiceAndRegion() string { - return fmt.Sprintf(` - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer", "Manager"] - - resources { - service = "cloudantnosqldb" - region = "us-south" - } - } - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyResourceInstance(name string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Manager", "Viewer", "Administrator"] - - resources { - service = "kms" - resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) - } - } - - - `, name, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyResourceGroup() string { - return fmt.Sprintf(` - - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - - resources { - service = "containers-kubernetes" - resource_group_id = data.ibm_resource_group.group.id - } - } - - - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyResourceType() string { - return fmt.Sprintf(` - - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Administrator"] - - resources { - resource_type = "resource-group" - resource = data.ibm_resource_group.group.id - } - } - `, IAMUser) -} - -// TODO: do we need this test? It follows pattern of other policies, but has conflict with existing policy -func testAccCheckIBMIAMUserPolicyImport(name string) string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - } - - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyInvalidUser() string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "test@in.ibm.com" - roles = ["Viewer"] - } - - `) -} - -func testAccCheckIBMIAMUserPolicyAccountManagement(name string) string { - return fmt.Sprintf(` - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - account_management = true - } - - `, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyWithCustomRole(crName, displayName string) string { - return fmt.Sprintf(` - - resource "ibm_iam_custom_role" "customrole" { - name = "%s" - display_name = "%s" - description = "role for test scenario1" - service = "kms" - actions = ["kms.secrets.rotate"] - } - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] - resources { - service = "kms" - } - } - - `, crName, displayName, IAMUser) -} - -func testAccCheckIBMIAMUserPolicyResourceAttributes() string { - return fmt.Sprintf(` - - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - operator = "stringMatch" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - -`, IAMUser) -} -func testAccCheckIBMIAMUserPolicyResourceAttributesUpdate() string { - return fmt.Sprintf(` - resource "ibm_iam_user_policy" "policy" { - ibm_id = "%s" - roles = ["Viewer"] - resource_attributes { - name = "resource" - value = "test*" - operator = "stringMatch" - } - resource_attributes { - name = "serviceName" - value = "messagehub" - } - } - `, IAMUser) -} diff --git a/ibm/resource_ibm_iam_user_settings_test.go b/ibm/resource_ibm_iam_user_settings_test.go deleted file mode 100644 index bb7e3a145..000000000 --- a/ibm/resource_ibm_iam_user_settings_test.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMIAMUserSettings_Basic(t *testing.T) { - t.Skip() - var allowedIP string - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMIAMUserSettingsDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMIAMUserSettingsBasic(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMIAMUserSettingsExists("ibm_iam_user_settings.user_settings", allowedIP), - resource.TestCheckResourceAttr("ibm_iam_user_settings.user_settings", "allowed_ip_addresses.#", "2"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMIAMUserSettingsUpdate(), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_iam_user_settings.user_settings", "allowed_ip_addresses.#", "4"), - ), - }, - }, - }) -} - -func testAccCheckIBMIAMUserSettingsDestroy(s *terraform.State) error { - - userManagement, err := testAccProvider.Meta().(ClientSession).UserManagementAPI() - if err != nil { - return err - } - client := userManagement.UserInvite() - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_iam_user_settings" { - continue - } - - usermail := rs.Primary.ID - - userDetails, err := testAccProvider.Meta().(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - - iamID, err := getIBMUniqueId(accountID, usermail, testAccProvider.Meta()) - if err != nil { - return err - } - - UserSetting, UserSettingError := client.GetUserSettings(accountID, iamID) - if UserSettingError == nil && UserSetting.AllowedIPAddresses != "" { - return fmt.Errorf("Allowed IP setting still exists: %s", usermail) - } - } - - return nil -} - -func testAccCheckIBMIAMUserSettingsExists(n string, ip string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No ID is set") - } - - userManagement, err := testAccProvider.Meta().(ClientSession).UserManagementAPI() - if err != nil { - return err - } - - client := userManagement.UserInvite() - - usermail := rs.Primary.ID - - userDetails, err := testAccProvider.Meta().(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - - accountID := userDetails.userAccount - - iamID, err := getIBMUniqueId(accountID, usermail, testAccProvider.Meta()) - if err != nil { - return err - } - - UserSetting, UserSettingError := client.GetUserSettings(accountID, iamID) - if UserSettingError != nil { - return fmt.Errorf("ERROR in getting user settings: %s", rs.Primary.ID) - } - - ip = UserSetting.AllowedIPAddresses - return nil - } -} - -func testAccCheckIBMIAMUserSettingsBasic() string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_settings" "user_settings" { - iam_id = "%s" - allowed_ip_addresses = ["192.168.0.0","192.168.0.1"] - } - - `, IAMUser) -} - -func testAccCheckIBMIAMUserSettingsUpdate() string { - return fmt.Sprintf(` - - - resource "ibm_iam_user_settings" "user_settings" { - iam_id = "%s" - allowed_ip_addresses = ["192.168.0.2","192.168.0.3","192.168.0.4","192.168.0.5"] - } - - `, IAMUser) -} diff --git a/ibm/resource_ibm_is_floating_ip.go b/ibm/resource_ibm_is_floating_ip.go deleted file mode 100644 index 608096239..000000000 --- a/ibm/resource_ibm_is_floating_ip.go +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isFloatingIPAddress = "address" - isFloatingIPCRN = "crn" - isFloatingIPName = "name" - isFloatingIPStatus = "status" - isFloatingIPZone = "zone" - isFloatingIPTarget = "target" - isFloatingIPResourceGroup = "resource_group" - isFloatingIPTags = "tags" - - isFloatingIPPending = "pending" - isFloatingIPAvailable = "available" - isFloatingIPDeleting = "deleting" - isFloatingIPDeleted = "done" -) - -func resourceIBMISFloatingIP() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISFloatingIPCreate, - Read: resourceIBMISFloatingIPRead, - Update: resourceIBMISFloatingIPUpdate, - Delete: resourceIBMISFloatingIPDelete, - Exists: resourceIBMISFloatingIPExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - - if diff.HasChange(isFloatingIPTarget) { - if !diff.NewValueKnown(isFloatingIPTarget) { - diff.ForceNew(isFloatingIPTarget) - return nil - } - old, new := diff.GetChange(isFloatingIPTarget) - if old != "" || new != "" { - sess, err := vpcClient(v) - if err != nil { - return err - } - if checkIfZoneChanged(old.(string), new.(string), diff.Get(isFloatingIPZone).(string), sess) { - diff.ForceNew(isFloatingIPTarget) - } - } - } - return nil - }, - ), - ), - - Schema: map[string]*schema.Schema{ - isFloatingIPAddress: { - Type: schema.TypeString, - Computed: true, - Description: "Floating IP address", - }, - - isFloatingIPName: { - Type: schema.TypeString, - Required: true, - ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_floating_ip", isFloatingIPName), - Description: "Name of the floating IP", - }, - - isFloatingIPStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Floating IP status", - }, - - isFloatingIPZone: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - ConflictsWith: []string{isFloatingIPTarget}, - Description: "Zone name", - }, - - isFloatingIPTarget: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ConflictsWith: []string{isFloatingIPZone}, - Description: "Target info", - }, - - isFloatingIPResourceGroup: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - Description: "Resource group info", - }, - - isFloatingIPTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_floating_ip", "tag")}, - Set: resourceIBMVPCHash, - Description: "Floating IP tags", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - isFloatingIPCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func vpcClient(meta interface{}) (*vpcv1.VpcV1, error) { - sess, err := meta.(ClientSession).VpcV1API() - return sess, err -} - -func resourceIBMISFloatingIPValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isFloatingIPName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmISFloatingIPResourceValidator := ResourceValidator{ResourceName: "ibm_is_floating_ip", Schema: validateSchema} - return &ibmISFloatingIPResourceValidator -} - -func resourceIBMISFloatingIPCreate(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isFloatingIPName).(string) - err := fipCreate(d, meta, name) - if err != nil { - return err - } - - return resourceIBMISFloatingIPRead(d, meta) -} - -func fipCreate(d *schema.ResourceData, meta interface{}, name string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - floatingIPPrototype := &vpcv1.FloatingIPPrototype{ - Name: &name, - } - zone, target := "", "" - if zn, ok := d.GetOk(isFloatingIPZone); ok { - zone = zn.(string) - floatingIPPrototype.Zone = &vpcv1.ZoneIdentity{ - Name: &zone, - } - } - - if tgt, ok := d.GetOk(isFloatingIPTarget); ok { - target = tgt.(string) - floatingIPPrototype.Target = &vpcv1.FloatingIPByTargetNetworkInterfaceIdentity{ - ID: &target, - } - } - - if zone == "" && target == "" { - return fmt.Errorf("%s or %s need to be provided", isFloatingIPZone, isFloatingIPTarget) - } - - if rgrp, ok := d.GetOk(isFloatingIPResourceGroup); ok { - rg := rgrp.(string) - floatingIPPrototype.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - createFloatingIPOptions := &vpcv1.CreateFloatingIPOptions{ - FloatingIPPrototype: floatingIPPrototype, - } - - floatingip, response, err := sess.CreateFloatingIP(createFloatingIPOptions) - if err != nil { - return fmt.Errorf("[DEBUG] Floating IP err %s\n%s", err, response) - } - d.SetId(*floatingip.ID) - log.Printf("[INFO] Floating IP : %s[%s]", *floatingip.ID, *floatingip.Address) - _, err = isWaitForInstanceFloatingIP(sess, d.Id(), d) - if err != nil { - return err - } - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isFloatingIPTags); ok || v != "" { - oldList, newList := d.GetChange(isFloatingIPTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *floatingip.CRN) - if err != nil { - log.Printf( - "Error on create of vpc Floating IP (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMISFloatingIPRead(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - err := fipGet(d, meta, id) - if err != nil { - return err - } - - return nil -} - -func fipGet(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - getFloatingIPOptions := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - floatingip, response, err := sess.GetFloatingIP(getFloatingIPOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting Floating IP (%s): %s\n%s", id, err, response) - - } - d.Set(isFloatingIPName, *floatingip.Name) - d.Set(isFloatingIPAddress, *floatingip.Address) - d.Set(isFloatingIPStatus, *floatingip.Status) - d.Set(isFloatingIPZone, *floatingip.Zone.Name) - target, ok := floatingip.Target.(*vpcv1.FloatingIPTarget) - if ok { - d.Set(isFloatingIPTarget, target.ID) - } - tags, err := GetTagsUsingCRN(meta, *floatingip.CRN) - if err != nil { - log.Printf( - "Error on get of vpc Floating IP (%s) tags: %s", d.Id(), err) - } - d.Set(isFloatingIPTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/floatingIPs") - d.Set(ResourceName, *floatingip.Name) - d.Set(isFloatingIPCRN, *floatingip.CRN) - d.Set(ResourceCRN, *floatingip.CRN) - d.Set(ResourceStatus, *floatingip.Status) - if floatingip.ResourceGroup != nil { - d.Set(ResourceGroupName, floatingip.ResourceGroup.Name) - d.Set(isFloatingIPResourceGroup, floatingip.ResourceGroup.ID) - } - return nil -} - -func resourceIBMISFloatingIPUpdate(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - err := fipUpdate(d, meta, id) - if err != nil { - return err - } - return resourceIBMISFloatingIPRead(d, meta) -} - -func fipUpdate(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - if d.HasChange(isFloatingIPTags) { - options := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - fip, response, err := sess.GetFloatingIP(options) - if err != nil { - return fmt.Errorf("Error getting Floating IP: %s\n%s", err, response) - } - oldList, newList := d.GetChange(isFloatingIPTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *fip.CRN) - if err != nil { - log.Printf( - "Error on update of vpc Floating IP (%s) tags: %s", id, err) - } - } - hasChanged := false - options := &vpcv1.UpdateFloatingIPOptions{ - ID: &id, - } - floatingIPPatchModel := &vpcv1.FloatingIPPatch{} - if d.HasChange(isFloatingIPName) { - name := d.Get(isFloatingIPName).(string) - floatingIPPatchModel.Name = &name - hasChanged = true - floatingIPPatch, err := floatingIPPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for FloatingIPPatch: %s", err) - } - options.FloatingIPPatch = floatingIPPatch - } - - if d.HasChange(isFloatingIPTarget) { - target := d.Get(isFloatingIPTarget).(string) - floatingIPPatchModel.Target = &vpcv1.FloatingIPPatchTargetNetworkInterfaceIdentity{ - ID: &target, - } - hasChanged = true - floatingIPPatch, err := floatingIPPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for floatingIPPatch: %s", err) - } - options.FloatingIPPatch = floatingIPPatch - } - if hasChanged { - _, response, err := sess.UpdateFloatingIP(options) - if err != nil { - return fmt.Errorf("Error updating vpc Floating IP: %s\n%s", err, response) - } - } - return nil -} - -func resourceIBMISFloatingIPDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - err := fipDelete(d, meta, id) - if err != nil { - return err - } - return nil -} - -func fipDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - getFloatingIpOptions := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - _, response, err := sess.GetFloatingIP(getFloatingIpOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - - return fmt.Errorf("Error Getting Floating IP (%s): %s\n%s", id, err, response) - } - - options := &vpcv1.DeleteFloatingIPOptions{ - ID: &id, - } - response, err = sess.DeleteFloatingIP(options) - if err != nil { - return fmt.Errorf("Error Deleting Floating IP : %s\n%s", err, response) - } - _, err = isWaitForFloatingIPDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func resourceIBMISFloatingIPExists(d *schema.ResourceData, meta interface{}) (bool, error) { - id := d.Id() - exists, err := fipExists(d, meta, id) - return exists, err -} - -func fipExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - getFloatingIpOptions := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - _, response, err := sess.GetFloatingIP(getFloatingIpOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting floating IP: %s\n%s", err, response) - } - return true, nil -} - -func isWaitForFloatingIPDeleted(fip *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for FloatingIP (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isFloatingIPPending, isFloatingIPDeleting}, - Target: []string{"", isFloatingIPDeleted}, - Refresh: isFloatingIPDeleteRefreshFunc(fip, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isFloatingIPDeleteRefreshFunc(fip *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") - getfipoptions := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - FloatingIP, response, err := fip.GetFloatingIP(getfipoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return FloatingIP, isFloatingIPDeleted, nil - } - return FloatingIP, "", fmt.Errorf("Error Getting Floating IP: %s\n%s", err, response) - } - return FloatingIP, isFloatingIPDeleting, err - } -} - -func isWaitForInstanceFloatingIP(floatingipC *vpcv1.VpcV1, id string, d *schema.ResourceData) (interface{}, error) { - log.Printf("Waiting for floating IP (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isFloatingIPPending}, - Target: []string{isFloatingIPAvailable, ""}, - Refresh: isInstanceFloatingIPRefreshFunc(floatingipC, id), - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isInstanceFloatingIPRefreshFunc(floatingipC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - getfipoptions := &vpcv1.GetFloatingIPOptions{ - ID: &id, - } - instance, response, err := floatingipC.GetFloatingIP(getfipoptions) - if err != nil { - return nil, "", fmt.Errorf("Error Getting Floating IP for the instance: %s\n%s", err, response) - } - - if *instance.Status == "available" { - return instance, isFloatingIPAvailable, nil - } - - return instance, isFloatingIPPending, nil - } -} - -func checkIfZoneChanged(oldNic, newNic, currentZone string, floatingipC *vpcv1.VpcV1) bool { - var oldZone, newZone string - listInstancesOptions := &vpcv1.ListInstancesOptions{} - start := "" - allrecs := []vpcv1.Instance{} - for { - - if start != "" { - listInstancesOptions.Start = &start - } - - instances, _, err := floatingipC.ListInstances(listInstancesOptions) - if err != nil { - return false - } - start = GetNext(instances.Next) - allrecs = append(allrecs, instances.Instances...) - if start == "" { - break - } - } - for _, instance := range allrecs { - for _, nic := range instance.NetworkInterfaces { - if oldNic == *nic.ID { - oldZone = *instance.Zone.Name - } - if newNic == *nic.ID { - newZone = *instance.Zone.Name - } - } - } - if newZone != oldZone { - if oldZone == "" && newZone == currentZone { - return false - } - return true - } - return false -} diff --git a/ibm/resource_ibm_is_floating_ip_test.go b/ibm/resource_ibm_is_floating_ip_test.go deleted file mode 100644 index dd1ff5553..000000000 --- a/ibm/resource_ibm_is_floating_ip_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISFloatingIP_basic(t *testing.T) { - var ip string - vpcname := fmt.Sprintf("tfip-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfip-%d", acctest.RandIntRange(10, 100)) - instancename := fmt.Sprintf("tfip-instance-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tfip-sshname-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISFloatingIPDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISFloatingIPConfig(vpcname, subnetname, sshname, publicKey, instancename, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISFloatingIPExists("ibm_is_floating_ip.testacc_floatingip", ip), - resource.TestCheckResourceAttr( - "ibm_is_floating_ip.testacc_floatingip", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_floating_ip.testacc_floatingip", "zone", ISZoneName), - ), - }, - }, - }) -} - -func TestAccIBMISFloatingIP_NoTarget(t *testing.T) { - var ip string - name := fmt.Sprintf("tfip-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISFloatingIPDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISFloatingIPNoTargetConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISFloatingIPExists("ibm_is_floating_ip.testacc_floatingip", ip), - resource.TestCheckResourceAttr( - "ibm_is_floating_ip.testacc_floatingip", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_floating_ip.testacc_floatingip", "zone", ISZoneName), - ), - }, - }, - }) -} - -func testAccCheckIBMISFloatingIPDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_floating_ip" { - continue - } - - getfipoptions := &vpcv1.GetFloatingIPOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetFloatingIP(getfipoptions) - if err == nil { - return fmt.Errorf("Floating IP still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISFloatingIPExists(n, ip string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getfipoptions := &vpcv1.GetFloatingIPOptions{ - ID: &rs.Primary.ID, - } - foundip, _, err := sess.GetFloatingIP(getfipoptions) - if err != nil { - return err - } - ip = *foundip.ID - return nil - } -} - -func testAccCheckIBMISFloatingIPConfig(vpcname, subnetname, sshname, publicKey, instancename, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - port_speed = "100" - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - - resource "ibm_is_floating_ip" "testacc_floatingip" { - name = "%s" - target = ibm_is_instance.testacc_instance.primary_network_interface[0].id - } -`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, instancename, isImage, instanceProfileName, ISZoneName, name) -} - -func testAccCheckIBMISFloatingIPNoTargetConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_is_floating_ip" "testacc_floatingip" { - name = "%s" - zone = "%s" - } -`, name, ISZoneName) -} diff --git a/ibm/resource_ibm_is_instance.go b/ibm/resource_ibm_is_instance.go deleted file mode 100644 index 883f18ecf..000000000 --- a/ibm/resource_ibm_is_instance.go +++ /dev/null @@ -1,2352 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceName = "name" - IsInstanceCRN = "crn" - isInstanceKeys = "keys" - isInstanceTags = "tags" - isInstanceNetworkInterfaces = "network_interfaces" - isInstancePrimaryNetworkInterface = "primary_network_interface" - isInstanceNicName = "name" - isInstanceProfile = "profile" - isInstanceNicPortSpeed = "port_speed" - isInstanceNicAllowIPSpoofing = "allow_ip_spoofing" - isInstanceNicPrimaryIpv4Address = "primary_ipv4_address" - isInstanceNicSecondaryAddress = "secondary_addresses" - isInstanceNicSecurityGroups = "security_groups" - isInstanceNicSubnet = "subnet" - isInstanceNicFloatingIPs = "floating_ips" - isInstanceUserData = "user_data" - isInstanceVolumes = "volumes" - isInstanceVPC = "vpc" - isInstanceZone = "zone" - isInstanceBootVolume = "boot_volume" - isInstanceVolumeSnapshot = "snapshot" - isInstanceSourceTemplate = "instance_template" - isInstanceVolAttVolAutoDelete = "auto_delete_volume" - isInstanceVolAttVolBillingTerm = "billing_term" - isInstanceImage = "image" - isInstanceCPU = "vcpu" - isInstanceCPUArch = "architecture" - isInstanceCPUCores = "cores" - isInstanceCPUCount = "count" - isInstanceGpu = "gpu" - isInstanceGpuCores = "cores" - isInstanceGpuCount = "count" - isInstanceGpuManufacturer = "manufacturer" - isInstanceGpuMemory = "memory" - isInstanceGpuModel = "model" - isInstanceMemory = "memory" - isInstanceDisks = "disks" - isInstanceDedicatedHost = "dedicated_host" - isInstanceStatus = "status" - isInstanceStatusReasons = "status_reasons" - isInstanceStatusReasonsCode = "code" - isInstanceStatusReasonsMessage = "message" - isEnableCleanDelete = "wait_before_delete" - isInstanceProvisioning = "provisioning" - isInstanceProvisioningDone = "done" - isInstanceAvailable = "available" - isInstanceDeleting = "deleting" - isInstanceDeleteDone = "done" - isInstanceFailed = "failed" - - isInstanceActionStatusStopping = "stopping" - isInstanceActionStatusStopped = "stopped" - isInstanceStatusPending = "pending" - isInstanceStatusRunning = "running" - isInstanceStatusFailed = "failed" - - isInstanceBootAttachmentName = "name" - isInstanceBootSize = "size" - isInstanceBootIOPS = "iops" - isInstanceBootEncryption = "encryption" - isInstanceBootProfile = "profile" - - isInstanceVolumeAttachments = "volume_attachments" - isInstanceVolumeAttaching = "attaching" - isInstanceVolumeAttached = "attached" - isInstanceVolumeDetaching = "detaching" - isInstanceResourceGroup = "resource_group" - - isPlacementTargetDedicatedHost = "dedicated_host" - isPlacementTargetDedicatedHostGroup = "dedicated_host_group" - isInstancePlacementTarget = "placement_target" - isPlacementTargetPlacementGroup = "placement_group" -) - -func resourceIBMISInstance() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMisInstanceCreate, - Read: resourceIBMisInstanceRead, - Update: resourceIBMisInstanceUpdate, - Delete: resourceIBMisInstanceDelete, - Exists: resourceIBMisInstanceExists, - Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) (result []*schema.ResourceData, err error) { - log.Printf("[INFO] Instance (%s) importing", d.Id()) - id := d.Id() - instanceC, err := vpcClient(meta) - if err != nil { - return nil, err - } - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil, nil - } - return nil, fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - var volumes []string - volumes = make([]string, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - if volume.Volume != nil && *volume.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { - volumes = append(volumes, *volume.Volume.ID) - } - } - } - d.Set(isInstanceVolumes, newStringSet(schema.HashString, volumes)) - return []*schema.ResourceData{d}, nil - }, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - }, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - isInstanceName: { - Type: schema.TypeString, - Required: true, - ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_instance", isInstanceName), - Description: "Instance name", - }, - isInstanceVPC: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - Description: "VPC id", - }, - IsInstanceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "Crn for this Instance", - }, - - isInstanceSourceTemplate: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot"}, - ConflictsWith: []string{"boot_volume.0.snapshot"}, - Description: "Id of the instance template", - }, - isInstanceZone: { - Type: schema.TypeString, - ForceNew: true, - Computed: true, - Optional: true, - Description: "Zone name", - }, - - isInstanceProfile: { - Type: schema.TypeString, - ForceNew: false, - Computed: true, - Optional: true, - Description: "Profile info", - }, - - isPlacementTargetDedicatedHost: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHostGroup, isPlacementTargetPlacementGroup}, - Description: "Unique Identifier of the Dedicated Host where the instance will be placed", - }, - - isPlacementTargetDedicatedHostGroup: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetPlacementGroup}, - Description: "Unique Identifier of the Dedicated Host Group where the instance will be placed", - }, - - isPlacementTargetPlacementGroup: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetDedicatedHostGroup}, - Description: "Unique Identifier of the Placement Group for restricting the placement of the instance", - }, - - isInstanceKeys: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - DiffSuppressFunc: applyOnce, - Description: "SSH key Ids for the instance", - }, - - isInstanceTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_instance", "tag")}, - Set: resourceIBMVPCHash, - Description: "list of tags for the instance", - }, - - isEnableCleanDelete: { - Type: schema.TypeBool, - Optional: true, - Default: true, - DiffSuppressFunc: suppressEnableCleanDelete, - Description: "Enables stopping of instance before deleting and waits till deletion is complete", - }, - - isInstanceVolumeAttachments: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "volume_id": { - Type: schema.TypeString, - Computed: true, - }, - "volume_name": { - Type: schema.TypeString, - Computed: true, - }, - "volume_crn": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - isInstancePrimaryNetworkInterface: { - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Optional: true, - Computed: true, - Description: "Primary Network interface info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - isInstanceNicAllowIPSpoofing: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Indicates whether IP spoofing is allowed on this interface.", - }, - isInstanceNicName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceNicPortSpeed: { - Type: schema.TypeInt, - Optional: true, - DiffSuppressFunc: applyOnce, - Deprecated: "This field is deprected", - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - }, - }, - - isInstanceNetworkInterfaces: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - isInstanceNicAllowIPSpoofing: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Indicates whether IP spoofing is allowed on this interface.", - }, - isInstanceNicName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - }, - isInstanceNicSecurityGroups: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceNicSubnet: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - }, - }, - - isInstanceUserData: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Description: "User data given for the instance", - }, - - isInstanceImage: { - Type: schema.TypeString, - ForceNew: true, - Computed: true, - Optional: true, - ConflictsWith: []string{"boot_volume.0.snapshot"}, - AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot"}, - RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile}, - Description: "image id", - }, - - isInstanceBootVolume: { - Type: schema.TypeList, - DiffSuppressFunc: applyOnce, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceBootAttachmentName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_instance", isInstanceBootAttachmentName), - }, - - isInstanceVolumeSnapshot: { - Type: schema.TypeString, - RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceProfile, isInstanceKeys, isInstanceVPC}, - AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot"}, - ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate}, - Optional: true, - ForceNew: true, - }, - isInstanceBootEncryption: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceBootSize: { - Type: schema.TypeInt, - Computed: true, - }, - isInstanceBootIOPS: { - Type: schema.TypeInt, - Computed: true, - }, - isInstanceBootProfile: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - isInstanceVolumes: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "List of volumes", - }, - - isInstanceVolAttVolAutoDelete: { - Type: schema.TypeBool, - Optional: true, - Description: "Auto delete volume along with instance", - }, - - isInstanceResourceGroup: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - Description: "Instance resource group", - }, - - isInstanceCPU: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceCPUArch: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceCPUCount: { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - isInstanceGpu: { - Type: schema.TypeList, - Computed: true, - Description: "The virtual server instance GPU configuration", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceGpuCount: { - Type: schema.TypeInt, - Computed: true, - Description: "The number of GPUs assigned to the instance", - }, - isInstanceGpuMemory: { - Type: schema.TypeInt, - Computed: true, - Description: "The overall amount of GPU memory in GiB (gibibytes)", - }, - isInstanceGpuManufacturer: { - Type: schema.TypeString, - Computed: true, - Description: "The GPU manufacturer", - }, - isInstanceGpuModel: { - Type: schema.TypeString, - Computed: true, - Description: "The GPU model", - }, - }, - }, - }, - - isInstanceMemory: { - Type: schema.TypeInt, - Computed: true, - Description: "Instance memory", - }, - - isInstanceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "instance status", - }, - isInstanceStatusReasons: { - Type: schema.TypeList, - Computed: true, - Description: "The reasons for the current status (if any).", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceStatusReasonsCode: { - Type: schema.TypeString, - Computed: true, - Description: "A snake case string succinctly identifying the status reason", - }, - - isInstanceStatusReasonsMessage: { - Type: schema.TypeString, - Computed: true, - Description: "An explanation of the status reason", - }, - }, - }, - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - - "force_recovery_time": { - Description: "Define timeout to force the instances to start/stop in minutes.", - Type: schema.TypeInt, - Optional: true, - }, - isInstanceDisks: &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Collection of the instance's disks.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the disk was created.", - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this instance disk.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this instance disk.", - }, - "interface_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user-defined name for this disk.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - "size": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "The size of the disk in GB (gigabytes).", - }, - }, - }, - }, - isInstancePlacementTarget: &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions for the virtual server instance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this placement target.", - }, - "deleted": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Link to documentation about deleted resources.", - }, - }, - }, - }, - "href": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The URL for this placement target.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this placement target.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique user-defined name for this placement target.", - }, - "resource_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The type of resource referenced.", - }, - }, - }, - }, - }, - } -} - -func resourceIBMISInstanceValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceBootAttachmentName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - ibmISInstanceValidator := ResourceValidator{ResourceName: "ibm_is_instance", Schema: validateSchema} - return &ibmISInstanceValidator -} - -func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - instanceproto := &vpcv1.InstancePrototype{ - Image: &vpcv1.ImageIdentity{ - ID: &image, - }, - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.InstanceProfileIdentity{ - Name: &profile, - }, - Name: &name, - VPC: &vpcv1.VPCIdentity{ - ID: &vpcID, - }, - } - - if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { - dHostIdStr := dHostIdInf.(string) - dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ - ID: &dHostIdStr, - } - instanceproto.PlacementTarget = dHostPlaementTarget - } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { - dHostGrpIdStr := dHostGrpIdInf.(string) - dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ - ID: &dHostGrpIdStr, - } - instanceproto.PlacementTarget = dHostGrpPlaementTarget - } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { - placementGrpStr := placementGroupInf.(string) - placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ - ID: &placementGrpStr, - } - instanceproto.PlacementTarget = placementGrp - } - - if boot, ok := d.GetOk(isInstanceBootVolume); ok { - bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} - name, ok := bootvol[isInstanceBootAttachmentName] - namestr := name.(string) - if namestr != "" && ok { - volTemplate.Name = &namestr - } - enc, ok := bootvol[isInstanceBootEncryption] - encstr := enc.(string) - if ok && encstr != "" { - volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encstr, - } - } - - volprof := "general-purpose" - volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volprof, - } - deletebool := true - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ - DeleteVolumeOnInstanceDelete: &deletebool, - Volume: volTemplate, - } - - } - - if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { - primnic := primnicintf.([]interface{})[0].(map[string]interface{}) - subnetintf, _ := primnic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - var primnicobj = &vpcv1.NetworkInterfacePrototype{} - primnicobj.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, _ := primnic[isInstanceNicName] - namestr := name.(string) - if namestr != "" { - primnicobj.Name = &namestr - } - ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - primnicobj.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := primnic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - primnicobj.SecurityGroups = secgrpobjs - } - } - instanceproto.PrimaryNetworkInterface = primnicobj - } - - if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { - nics := nicsintf.([]interface{}) - var intfs []vpcv1.NetworkInterfacePrototype - for _, resource := range nics { - nic := resource.(map[string]interface{}) - nwInterface := &vpcv1.NetworkInterfacePrototype{} - subnetintf, _ := nic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - nwInterface.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, ok := nic[isInstanceNicName] - namestr := name.(string) - if ok && namestr != "" { - nwInterface.Name = &namestr - } - ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - nwInterface.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := nic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - nwInterface.SecurityGroups = secgrpobjs - } - } - intfs = append(intfs, *nwInterface) - } - instanceproto.NetworkInterfaces = intfs - } - - keySet := d.Get(isInstanceKeys).(*schema.Set) - if keySet.Len() != 0 { - keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) - for i, key := range keySet.List() { - keystr := key.(string) - keyobjs[i] = &vpcv1.KeyIdentity{ - ID: &keystr, - } - } - instanceproto.Keys = keyobjs - } - - if userdata, ok := d.GetOk(isInstanceUserData); ok { - userdatastr := userdata.(string) - instanceproto.UserData = &userdatastr - } - - if grp, ok := d.GetOk(isInstanceResourceGroup); ok { - grpstr := grp.(string) - instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &grpstr, - } - - } - - options := &vpcv1.CreateInstanceOptions{ - InstancePrototype: instanceproto, - } - - instance, response, err := sess.CreateInstance(options) - if err != nil { - log.Printf("[DEBUG] Instance err %s\n%s", err, response) - return err - } - d.SetId(*instance.ID) - - log.Printf("[INFO] Instance : %s", *instance.ID) - d.Set(isInstanceStatus, instance.Status) - - _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isInstanceTags); ok || v != "" { - oldList, newList := d.GetChange(isInstanceTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image, template string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - instanceproto := &vpcv1.InstancePrototypeInstanceBySourceTemplate{ - SourceTemplate: &vpcv1.InstanceTemplateIdentity{ - ID: &template, - }, - Name: &name, - } - - if profile != "" { - instanceproto.Profile = &vpcv1.InstanceProfileIdentity{ - Name: &profile, - } - } - if vpcID != "" { - instanceproto.VPC = &vpcv1.VPCIdentity{ - ID: &vpcID, - } - } - if zone != "" { - instanceproto.Zone = &vpcv1.ZoneIdentity{ - Name: &zone, - } - } - - if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { - dHostIdStr := dHostIdInf.(string) - dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ - ID: &dHostIdStr, - } - instanceproto.PlacementTarget = dHostPlaementTarget - } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { - dHostGrpIdStr := dHostGrpIdInf.(string) - dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ - ID: &dHostGrpIdStr, - } - instanceproto.PlacementTarget = dHostGrpPlaementTarget - } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { - placementGrpStr := placementGroupInf.(string) - placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ - ID: &placementGrpStr, - } - instanceproto.PlacementTarget = placementGrp - } - - if boot, ok := d.GetOk(isInstanceBootVolume); ok { - bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} - name, ok := bootvol[isInstanceBootAttachmentName] - namestr := name.(string) - if namestr != "" && ok { - volTemplate.Name = &namestr - } - enc, ok := bootvol[isInstanceBootEncryption] - encstr := enc.(string) - if ok && encstr != "" { - volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encstr, - } - } - - volprof := "general-purpose" - - volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volprof, - } - deletebool := true - - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ - DeleteVolumeOnInstanceDelete: &deletebool, - Volume: volTemplate, - } - } - - if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { - primnic := primnicintf.([]interface{})[0].(map[string]interface{}) - subnetintf, _ := primnic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - var primnicobj = &vpcv1.NetworkInterfacePrototype{} - primnicobj.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, _ := primnic[isInstanceNicName] - namestr := name.(string) - if namestr != "" { - primnicobj.Name = &namestr - } - ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - primnicobj.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := primnic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - primnicobj.SecurityGroups = secgrpobjs - } - } - instanceproto.PrimaryNetworkInterface = primnicobj - } - - if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { - nics := nicsintf.([]interface{}) - var intfs []vpcv1.NetworkInterfacePrototype - for _, resource := range nics { - nic := resource.(map[string]interface{}) - nwInterface := &vpcv1.NetworkInterfacePrototype{} - subnetintf, _ := nic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - nwInterface.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, ok := nic[isInstanceNicName] - namestr := name.(string) - if ok && namestr != "" { - nwInterface.Name = &namestr - } - ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - nwInterface.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := nic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - nwInterface.SecurityGroups = secgrpobjs - } - } - intfs = append(intfs, *nwInterface) - } - instanceproto.NetworkInterfaces = intfs - } - - keySet := d.Get(isInstanceKeys).(*schema.Set) - if keySet.Len() != 0 { - keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) - for i, key := range keySet.List() { - keystr := key.(string) - keyobjs[i] = &vpcv1.KeyIdentity{ - ID: &keystr, - } - } - instanceproto.Keys = keyobjs - } - - if userdata, ok := d.GetOk(isInstanceUserData); ok { - userdatastr := userdata.(string) - instanceproto.UserData = &userdatastr - } - - if grp, ok := d.GetOk(isInstanceResourceGroup); ok { - grpstr := grp.(string) - instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &grpstr, - } - - } - - options := &vpcv1.CreateInstanceOptions{ - InstancePrototype: instanceproto, - } - - instance, response, err := sess.CreateInstance(options) - if err != nil { - log.Printf("[DEBUG] Instance err %s\n%s", err, response) - return err - } - d.SetId(*instance.ID) - - log.Printf("[INFO] Instance : %s", *instance.ID) - d.Set(isInstanceStatus, instance.Status) - - _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isInstanceTags); ok || v != "" { - oldList, newList := d.GetChange(isInstanceTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - instanceproto := &vpcv1.InstancePrototypeInstanceByVolume{ - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.InstanceProfileIdentity{ - Name: &profile, - }, - Name: &name, - VPC: &vpcv1.VPCIdentity{ - ID: &vpcID, - }, - } - if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { - dHostIdStr := dHostIdInf.(string) - dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ - ID: &dHostIdStr, - } - instanceproto.PlacementTarget = dHostPlaementTarget - } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { - dHostGrpIdStr := dHostGrpIdInf.(string) - dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ - ID: &dHostGrpIdStr, - } - instanceproto.PlacementTarget = dHostGrpPlaementTarget - } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { - placementGrpStr := placementGroupInf.(string) - placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ - ID: &placementGrpStr, - } - instanceproto.PlacementTarget = placementGrp - } - - if boot, ok := d.GetOk(isInstanceBootVolume); ok { - bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumeAttachmentVolumePrototypeInstanceByVolumeContext{} - - name, ok := bootvol[isInstanceBootAttachmentName] - namestr := name.(string) - if namestr != "" && ok { - volTemplate.Name = &namestr - } - enc, ok := bootvol[isInstanceBootEncryption] - encstr := enc.(string) - if ok && encstr != "" { - volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encstr, - } - } - - volprof := "general-purpose" - volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volprof, - } - snapshotId, ok := bootvol[isInstanceVolumeSnapshot] - snapshotIdStr := snapshotId.(string) - if snapshotIdStr != "" && ok { - volTemplate.SourceSnapshot = &vpcv1.SnapshotIdentity{ - ID: &snapshotIdStr, - } - } - deletebool := true - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByVolumeContext{ - DeleteVolumeOnInstanceDelete: &deletebool, - Volume: volTemplate, - } - } - - if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { - primnic := primnicintf.([]interface{})[0].(map[string]interface{}) - subnetintf, _ := primnic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - var primnicobj = &vpcv1.NetworkInterfacePrototype{} - primnicobj.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, _ := primnic[isInstanceNicName] - namestr := name.(string) - if namestr != "" { - primnicobj.Name = &namestr - } - ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - primnicobj.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := primnic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - primnicobj.SecurityGroups = secgrpobjs - } - } - instanceproto.PrimaryNetworkInterface = primnicobj - } - - if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { - nics := nicsintf.([]interface{}) - var intfs []vpcv1.NetworkInterfacePrototype - for _, resource := range nics { - nic := resource.(map[string]interface{}) - nwInterface := &vpcv1.NetworkInterfacePrototype{} - subnetintf, _ := nic[isInstanceNicSubnet] - subnetintfstr := subnetintf.(string) - nwInterface.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - name, ok := nic[isInstanceNicName] - namestr := name.(string) - if ok && namestr != "" { - nwInterface.Name = &namestr - } - ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str - } - allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - nwInterface.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := nic[isInstanceNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - nwInterface.SecurityGroups = secgrpobjs - } - } - intfs = append(intfs, *nwInterface) - } - instanceproto.NetworkInterfaces = intfs - } - - keySet := d.Get(isInstanceKeys).(*schema.Set) - if keySet.Len() != 0 { - keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) - for i, key := range keySet.List() { - keystr := key.(string) - keyobjs[i] = &vpcv1.KeyIdentity{ - ID: &keystr, - } - } - instanceproto.Keys = keyobjs - } - - if userdata, ok := d.GetOk(isInstanceUserData); ok { - userdatastr := userdata.(string) - instanceproto.UserData = &userdatastr - } - - if grp, ok := d.GetOk(isInstanceResourceGroup); ok { - grpstr := grp.(string) - instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &grpstr, - } - - } - - options := &vpcv1.CreateInstanceOptions{ - InstancePrototype: instanceproto, - } - - instance, response, err := sess.CreateInstance(options) - if err != nil { - log.Printf("[DEBUG] Instance err %s\n%s", err, response) - return err - } - d.SetId(*instance.ID) - - log.Printf("[INFO] Instance : %s", *instance.ID) - d.Set(isInstanceStatus, instance.Status) - - _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isInstanceTags); ok || v != "" { - oldList, newList := d.GetChange(isInstanceTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMisInstanceCreate(d *schema.ResourceData, meta interface{}) error { - - profile := d.Get(isInstanceProfile).(string) - name := d.Get(isInstanceName).(string) - vpcID := d.Get(isInstanceVPC).(string) - zone := d.Get(isInstanceZone).(string) - image := d.Get(isInstanceImage).(string) - snapshot := d.Get("boot_volume.0.snapshot").(string) - template := d.Get(isInstanceSourceTemplate).(string) - - if snapshot != "" { - err := instanceCreateByVolume(d, meta, profile, name, vpcID, zone) - if err != nil { - return err - } - } else if template != "" { - err := instanceCreateByTemplate(d, meta, profile, name, vpcID, zone, image, template) - if err != nil { - return err - } - } else { - err := instanceCreateByImage(d, meta, profile, name, vpcID, zone, image) - if err != nil { - return err - } - } - - return resourceIBMisInstanceUpdate(d, meta) -} - -func isWaitForInstanceAvailable(instanceC *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { - log.Printf("Waiting for instance (%s) to be available.", id) - - communicator := make(chan interface{}) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isInstanceProvisioning}, - Target: []string{isInstanceStatusRunning, "available", "failed", ""}, - Refresh: isInstanceRefreshFunc(instanceC, id, d, communicator), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - if v, ok := d.GetOk("force_recovery_time"); ok { - forceTimeout := v.(int) - go isRestartStartAction(instanceC, id, d, forceTimeout, communicator) - } - - return stateConf.WaitForState() -} - -func isInstanceRefreshFunc(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, communicator chan interface{}) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - return nil, "", fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - d.Set(isInstanceStatus, *instance.Status) - - select { - case data := <-communicator: - return nil, "", data.(error) - default: - fmt.Println("no message sent") - } - - if *instance.Status == "available" || *instance.Status == "failed" || *instance.Status == "running" { - // let know the isRestartStartAction() to stop - close(communicator) - // taint the instance if status is failed - if *instance.Status == "failed" { - return instance, *instance.Status, fmt.Errorf("Instance (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted instance and attempt to create the instance again replacing the previous configuration", *instance.ID) - } - return instance, *instance.Status, nil - - } - return instance, isInstanceProvisioning, nil - } -} - -func isRestartStartAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int, communicator chan interface{}) { - subticker := time.NewTicker(time.Duration(forceTimeout) * time.Minute) - //subticker := time.NewTicker(time.Duration(forceTimeout) * time.Second) - for { - select { - - case <-subticker.C: - log.Println("Instance is still in starting state, force retry by restarting the instance.") - actiontype := "stop" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err := instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - communicator <- fmt.Errorf("Error retrying instance action start: %s\n%s", err, response) - return - } - waitTimeout := time.Duration(1) * time.Minute - _, _ = isWaitForInstanceActionStop(instanceC, waitTimeout, id, d) - actiontype = "start" - createinsactoptions = &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - communicator <- fmt.Errorf("Error retrying instance action start: %s\n%s", err, response) - return - } - case <-communicator: - // indicates refresh func is reached target and not proceed with the thread - subticker.Stop() - return - - } - } -} -func resourceIBMisInstanceRead(d *schema.ResourceData, meta interface{}) error { - - ID := d.Id() - - err := instanceGet(d, meta, ID) - if err != nil { - return err - } - return nil -} - -func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Instance: %s\n%s", err, response) - } - - d.Set(isInstanceName, *instance.Name) - if instance.Profile != nil { - d.Set(isInstanceProfile, *instance.Profile.Name) - } - cpuList := make([]map[string]interface{}, 0) - if instance.Vcpu != nil { - currentCPU := map[string]interface{}{} - currentCPU[isInstanceCPUArch] = *instance.Vcpu.Architecture - currentCPU[isInstanceCPUCount] = *instance.Vcpu.Count - cpuList = append(cpuList, currentCPU) - } - d.Set(isInstanceCPU, cpuList) - - d.Set(isInstanceMemory, *instance.Memory) - gpuList := make([]map[string]interface{}, 0) - if instance.Gpu != nil { - currentGpu := map[string]interface{}{} - currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer - currentGpu[isInstanceGpuModel] = instance.Gpu.Model - currentGpu[isInstanceGpuCount] = instance.Gpu.Count - currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory - gpuList = append(gpuList, currentGpu) - } - d.Set(isInstanceGpu, gpuList) - - if instance.PrimaryNetworkInterface != nil { - primaryNicList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID - currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: instance.PrimaryNetworkInterface.ID, - } - insnic, response, err := instanceC.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentPrimNic[isInstanceNicAllowIPSpoofing] = *insnic.AllowIPSpoofing - currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentPrimNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - - primaryNicList = append(primaryNicList, currentPrimNic) - d.Set(isInstancePrimaryNetworkInterface, primaryNicList) - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - if *intfc.ID != *instance.PrimaryNetworkInterface.ID { - currentNic := map[string]interface{}{} - currentNic["id"] = *intfc.ID - currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: intfc.ID, - } - insnic, response, err := instanceC.GetInstanceNetworkInterface(getnicoptions) - if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s\n%s", err, response) - } - currentNic[isInstanceNicAllowIPSpoofing] = *insnic.AllowIPSpoofing - currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID - if len(insnic.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(insnic.SecurityGroups); i++ { - secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) - } - currentNic[isInstanceNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfacesList = append(interfacesList, currentNic) - - } - } - - d.Set(isInstanceNetworkInterfaces, interfacesList) - } - - if instance.Image != nil { - d.Set(isInstanceImage, *instance.Image.ID) - } - - d.Set(isInstanceStatus, *instance.Status) - - //set the status reasons - if instance.StatusReasons != nil { - statusReasonsList := make([]map[string]interface{}, 0) - for _, sr := range instance.StatusReasons { - currentSR := map[string]interface{}{} - if sr.Code != nil && sr.Message != nil { - currentSR[isInstanceStatusReasonsCode] = *sr.Code - currentSR[isInstanceStatusReasonsMessage] = *sr.Message - statusReasonsList = append(statusReasonsList, currentSR) - } - } - d.Set(isInstanceStatusReasons, statusReasonsList) - } - - d.Set(isInstanceVPC, *instance.VPC.ID) - d.Set(isInstanceZone, *instance.Zone.Name) - - if instance.VolumeAttachments != nil { - volList := make([]map[string]interface{}, 0) - for _, volume := range instance.VolumeAttachments { - vol := map[string]interface{}{} - if volume.Volume != nil { - vol["id"] = *volume.ID - vol["volume_id"] = *volume.Volume.ID - vol["name"] = *volume.Name - vol["volume_name"] = *volume.Volume.Name - vol["volume_crn"] = *volume.Volume.CRN - volList = append(volList, vol) - } - } - d.Set(isInstanceVolumeAttachments, volList) - } - - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - if instance.BootVolumeAttachment.Volume != nil { - bootVol[isInstanceBootAttachmentName] = *instance.BootVolumeAttachment.Volume.Name - options := &vpcv1.GetVolumeOptions{ - ID: instance.BootVolumeAttachment.Volume.ID, - } - vol, response, err := instanceC.GetVolume(options) - if err != nil { - log.Printf("Error Getting Boot Volume (%s): %s\n%s", id, err, response) - } - if vol != nil { - bootVol[isInstanceBootSize] = *vol.Capacity - bootVol[isInstanceBootIOPS] = *vol.Iops - bootVol[isInstanceBootProfile] = *vol.Profile.Name - if vol.EncryptionKey != nil { - bootVol[isInstanceBootEncryption] = *vol.EncryptionKey.CRN - } - } - } - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceBootVolume, bootVolList) - } - tags, err := GetTagsUsingCRN(meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on get of resource Instance (%s) tags: %s", d.Id(), err) - } - d.Set(isInstanceTags, tags) - - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/compute/vs") - d.Set(ResourceName, *instance.Name) - d.Set(ResourceCRN, *instance.CRN) - d.Set(IsInstanceCRN, *instance.CRN) - d.Set(ResourceStatus, *instance.Status) - if instance.ResourceGroup != nil { - d.Set(isInstanceResourceGroup, *instance.ResourceGroup.ID) - d.Set(ResourceGroupName, *instance.ResourceGroup.Name) - } - - if instance.Disks != nil { - disks := []map[string]interface{}{} - for _, disksItem := range instance.Disks { - disksItemMap := resourceIbmIsInstanceInstanceDiskToMap(disksItem) - disks = append(disks, disksItemMap) - } - if err = d.Set(isInstanceDisks, disks); err != nil { - return fmt.Errorf("Error setting disks: %s", err) - } - } - - placementTarget := []map[string]interface{}{} - if instance.PlacementTarget != nil { - placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) - placementTarget = append(placementTarget, placementTargetMap) - } - if err = d.Set(isInstancePlacementTarget, placementTarget); err != nil { - return fmt.Errorf("Error setting placement_target: %s", err) - } - return nil -} - -func instanceUpdate(d *schema.ResourceData, meta interface{}) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - id := d.Id() - if d.HasChange(isInstanceVolumes) { - ovs, nvs := d.GetChange(isInstanceVolumes) - ov := ovs.(*schema.Set) - nv := nvs.(*schema.Set) - - remove := expandStringList(ov.Difference(nv).List()) - add := expandStringList(nv.Difference(ov).List()) - var volautoDelete bool - if volumeautodeleteIntf, ok := d.GetOk(isInstanceVolAttVolAutoDelete); ok && volumeautodeleteIntf != nil { - volautoDelete = volumeautodeleteIntf.(bool) - } - - if len(add) > 0 { - for i := range add { - createvolattoptions := &vpcv1.CreateInstanceVolumeAttachmentOptions{ - InstanceID: &id, - Volume: &vpcv1.VolumeAttachmentPrototypeVolume{ - ID: &add[i], - }, - DeleteVolumeOnInstanceDelete: &volautoDelete, - } - vol, _, err := instanceC.CreateInstanceVolumeAttachment(createvolattoptions) - if err != nil { - return fmt.Errorf("Error while attaching volume %q for instance %s: %q", add[i], d.Id(), err) - } - _, err = isWaitForInstanceVolumeAttached(instanceC, d, id, *vol.ID) - if err != nil { - return err - } - } - - } - if len(remove) > 0 { - for i := range remove { - listvolattoptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{ - InstanceID: &id, - } - vols, _, err := instanceC.ListInstanceVolumeAttachments(listvolattoptions) - if err != nil { - return err - } - for _, vol := range vols.VolumeAttachments { - if *vol.Volume.ID == remove[i] { - delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ - InstanceID: &id, - ID: vol.ID, - } - _, err := instanceC.DeleteInstanceVolumeAttachment(delvolattoptions) - if err != nil { - return fmt.Errorf("Error while removing volume %q for instance %s: %q", remove[i], d.Id(), err) - } - _, err = isWaitForInstanceVolumeDetached(instanceC, d, d.Id(), *vol.ID) - if err != nil { - return err - } - break - } - } - } - } - } - - if d.HasChange("primary_network_interface.0.security_groups") && !d.IsNewResource() { - ovs, nvs := d.GetChange("primary_network_interface.0.security_groups") - ov := ovs.(*schema.Set) - nv := nvs.(*schema.Set) - remove := expandStringList(ov.Difference(nv).List()) - add := expandStringList(nv.Difference(ov).List()) - if len(add) > 0 { - networkID := d.Get("primary_network_interface.0.id").(string) - for i := range add { - createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ - SecurityGroupID: &add[i], - ID: &networkID, - } - _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) - if err != nil { - return fmt.Errorf("Error while creating security group %q for primary network interface of instance %s\n%s: %q", add[i], d.Id(), err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - } - - } - if len(remove) > 0 { - networkID := d.Get("primary_network_interface.0.id").(string) - for i := range remove { - deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ - SecurityGroupID: &remove[i], - ID: &networkID, - } - response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) - if err != nil { - return fmt.Errorf("Error while removing security group %q for primary network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - } - } - } - - if (d.HasChange("primary_network_interface.0.allow_ip_spoofing") || d.HasChange("primary_network_interface.0.name")) && !d.IsNewResource() { - newName := d.Get("primary_network_interface.0.name").(string) - networkID := d.Get("primary_network_interface.0.id").(string) - allowIPSpoofing := d.Get("primary_network_interface.0.allow_ip_spoofing").(bool) - updatepnicfoptions := &vpcv1.UpdateInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: &networkID, - } - - networkInterfacePatchModel := &vpcv1.NetworkInterfacePatch{ - Name: &newName, - AllowIPSpoofing: &allowIPSpoofing, - } - networkInterfacePatch, err := networkInterfacePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for NetworkInterfacePatch: %s", err) - } - updatepnicfoptions.NetworkInterfacePatch = networkInterfacePatch - - _, response, err := instanceC.UpdateInstanceNetworkInterface(updatepnicfoptions) - if err != nil { - return fmt.Errorf("Error while updating name %s for primary network interface of instance %s\n%s: %q", newName, d.Id(), err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - } - - if d.HasChange(isInstanceNetworkInterfaces) && !d.IsNewResource() { - nics := d.Get(isInstanceNetworkInterfaces).([]interface{}) - for i := range nics { - securitygrpKey := fmt.Sprintf("network_interfaces.%d.security_groups", i) - networkNameKey := fmt.Sprintf("network_interfaces.%d.name", i) - ipSpoofingKey := fmt.Sprintf("network_interfaces.%d.allow_ip_spoofing", i) - if d.HasChange(securitygrpKey) { - ovs, nvs := d.GetChange(securitygrpKey) - ov := ovs.(*schema.Set) - nv := nvs.(*schema.Set) - remove := expandStringList(ov.Difference(nv).List()) - add := expandStringList(nv.Difference(ov).List()) - if len(add) > 0 { - networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) - networkID := d.Get(networkIDKey).(string) - for i := range add { - createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ - SecurityGroupID: &add[i], - ID: &networkID, - } - _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) - if err != nil { - return fmt.Errorf("Error while creating security group %q for network interface of instance %s\n%s: %q", add[i], d.Id(), err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - } - - } - if len(remove) > 0 { - networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) - networkID := d.Get(networkIDKey).(string) - for i := range remove { - deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ - SecurityGroupID: &remove[i], - ID: &networkID, - } - response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) - if err != nil { - return fmt.Errorf("Error while removing security group %q for network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - } - } - - } - - if d.HasChange(networkNameKey) || d.HasChange(ipSpoofingKey) { - newName := d.Get(networkNameKey).(string) - networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) - networkID := d.Get(networkIDKey).(string) - ipSpoofing := d.Get(ipSpoofingKey).(bool) - updatepnicfoptions := &vpcv1.UpdateInstanceNetworkInterfaceOptions{ - InstanceID: &id, - ID: &networkID, - } - - instancePatchModel := &vpcv1.NetworkInterfacePatch{ - Name: &newName, - AllowIPSpoofing: &ipSpoofing, - } - networkInterfacePatch, err := instancePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for NetworkInterfacePatch: %s", err) - } - updatepnicfoptions.NetworkInterfacePatch = networkInterfacePatch - - _, response, err := instanceC.UpdateInstanceNetworkInterface(updatepnicfoptions) - if err != nil { - return fmt.Errorf("Error while updating name %s for network interface of instance %s\n%s: %q", newName, d.Id(), err, response) - } - if err != nil { - return err - } - } - } - - } - - if d.HasChange(isInstanceName) && !d.IsNewResource() { - name := d.Get(isInstanceName).(string) - updnetoptions := &vpcv1.UpdateInstanceOptions{ - ID: &id, - } - - instancePatchModel := &vpcv1.InstancePatch{ - Name: &name, - } - instancePatch, err := instancePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) - } - updnetoptions.InstancePatch = instancePatch - - _, _, err = instanceC.UpdateInstance(updnetoptions) - if err != nil { - return err - } - } - - if d.HasChange(isInstanceProfile) && !d.IsNewResource() { - - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting Instance (%s): %s\n%s", id, err, response) - } - - if instance != nil && *instance.Status == "running" { - actiontype := "stop" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error Creating Instance Action: %s\n%s", err, response) - } - _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) - if err != nil { - return err - } - } - - updnetoptions := &vpcv1.UpdateInstanceOptions{ - ID: &id, - } - - instanceProfile := d.Get(isInstanceProfile).(string) - profile := &vpcv1.InstancePatchProfile{ - Name: &instanceProfile, - } - instancePatchModel := &vpcv1.InstancePatch{ - Profile: profile, - } - instancePatch, err := instancePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) - } - updnetoptions.InstancePatch = instancePatch - - _, response, err = instanceC.UpdateInstance(updnetoptions) - if err != nil { - return fmt.Errorf("Error in UpdateInstancePatch: %s\n%s", err, response) - } - - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error Creating Instance Action: %s\n%s", err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) - if err != nil { - return err - } - - } - - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - return fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - if d.HasChange(isInstanceTags) { - oldList, newList := d.GetChange(isInstanceTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on update of resource Instance (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMisInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - - err := instanceUpdate(d, meta) - if err != nil { - return err - } - - return resourceIBMisInstanceRead(d, meta) -} - -func instanceDelete(d *schema.ResourceData, meta interface{}, id string) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - - cleanDelete := d.Get(isEnableCleanDelete).(bool) - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - _, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting Instance (%s): %s\n%s", id, err, response) - } - - bootvolid := "" - - if cleanDelete { - actiontype := "stop" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error Creating Instance Action: %s\n%s", err, response) - } - _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutDelete), id, d) - if err != nil { - return err - } - listvolattoptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{ - InstanceID: &id, - } - vols, response, err := instanceC.ListInstanceVolumeAttachments(listvolattoptions) - if err != nil { - return fmt.Errorf("Error Listing volume attachments to the instance: %s\n%s", err, response) - } - for _, vol := range vols.VolumeAttachments { - if *vol.Type == "data" { - delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ - InstanceID: &id, - ID: vol.ID, - } - _, err := instanceC.DeleteInstanceVolumeAttachment(delvolattoptions) - if err != nil { - return fmt.Errorf("Error while removing volume Attachment %q for instance %s: %q", *vol.ID, d.Id(), err) - } - _, err = isWaitForInstanceVolumeDetached(instanceC, d, d.Id(), *vol.ID) - if err != nil { - return err - } - } - if *vol.Type == "boot" { - bootvolid = *vol.Volume.ID - } - } - } - deleteinstanceOptions := &vpcv1.DeleteInstanceOptions{ - ID: &id, - } - _, err = instanceC.DeleteInstance(deleteinstanceOptions) - if err != nil { - return err - } - if cleanDelete { - _, err = isWaitForInstanceDelete(instanceC, d, d.Id()) - if err != nil { - return err - } - if _, ok := d.GetOk(isInstanceBootVolume); ok { - _, err = isWaitForVolumeDeleted(instanceC, bootvolid, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - } - } - return nil -} - -func resourceIBMisInstanceDelete(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - err := instanceDelete(d, meta, id) - if err != nil { - return err - } - - d.SetId("") - return nil -} - -func instanceExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - instanceC, err := vpcClient(meta) - if err != nil { - return false, err - } - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - _, response, err := instanceC.GetInstance(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - return true, nil -} - -func resourceIBMisInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - id := d.Id() - - exists, err := instanceExists(d, meta, id) - return exists, err - -} - -func isWaitForInstanceDelete(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id string) (interface{}, error) { - - stateConf := &resource.StateChangeConf{ - Pending: []string{isInstanceDeleting, isInstanceAvailable}, - Target: []string{isInstanceDeleteDone, ""}, - Refresh: func() (interface{}, string, error) { - getinsoptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return instance, isInstanceDeleteDone, nil - } - return nil, "", fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - if *instance.Status == isInstanceFailed { - return instance, *instance.Status, fmt.Errorf("The instance %s failed to delete: %v", d.Id(), err) - } - return instance, isInstanceDeleting, nil - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isWaitForInstanceActionStop(instanceC *vpcv1.VpcV1, timeout time.Duration, id string, d *schema.ResourceData) (interface{}, error) { - communicator := make(chan interface{}) - stateConf := &resource.StateChangeConf{ - Pending: []string{isInstanceStatusRunning, isInstanceStatusPending, isInstanceActionStatusStopping}, - Target: []string{isInstanceActionStatusStopped, isInstanceStatusFailed, ""}, - Refresh: func() (interface{}, string, error) { - getinsoptions := &vpcv1.GetInstanceOptions{ - ID: &id, - } - instance, response, err := instanceC.GetInstance(getinsoptions) - if err != nil { - return nil, "", fmt.Errorf("Error Getting Instance: %s\n%s", err, response) - } - select { - case data := <-communicator: - return nil, "", data.(error) - default: - fmt.Println("no message sent") - } - if *instance.Status == isInstanceStatusFailed { - // let know the isRestartStopAction() to stop - close(communicator) - return instance, *instance.Status, fmt.Errorf("The instance %s failed to stop: %v", id, err) - } - return instance, *instance.Status, nil - }, - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - if v, ok := d.GetOk("force_recovery_time"); ok { - forceTimeout := v.(int) - go isRestartStopAction(instanceC, id, d, forceTimeout, communicator) - } - - return stateConf.WaitForState() -} - -func isRestartStopAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int, communicator chan interface{}) { - subticker := time.NewTicker(time.Duration(forceTimeout) * time.Minute) - //subticker := time.NewTicker(time.Duration(forceTimeout) * time.Second) - for { - select { - - case <-subticker.C: - log.Println("Instance is still in stopping state, retrying to stop with -force") - actiontype := "stop" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &id, - Type: &actiontype, - } - _, response, err := instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - communicator <- fmt.Errorf("Error retrying instance action stop: %s\n%s", err, response) - return - } - case <-communicator: - // indicates refresh func is reached target and not proceed with the thread) - subticker.Stop() - return - - } - } -} - -func isWaitForInstanceVolumeAttached(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id, volID string) (interface{}, error) { - log.Printf("Waiting for instance (%s) volume (%s) to be attached.", id, volID) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isInstanceVolumeAttaching}, - Target: []string{isInstanceVolumeAttached, ""}, - Refresh: isInstanceVolumeRefreshFunc(instanceC, id, volID), - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isInstanceVolumeRefreshFunc(instanceC *vpcv1.VpcV1, id, volID string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - getvolattoptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - InstanceID: &id, - ID: &volID, - } - vol, response, err := instanceC.GetInstanceVolumeAttachment(getvolattoptions) - if err != nil { - return nil, "", fmt.Errorf("Error Attaching volume: %s\n%s", err, response) - } - - if *vol.Status == isInstanceVolumeAttached { - return vol, isInstanceVolumeAttached, nil - } - - return vol, isInstanceVolumeAttaching, nil - } -} - -func isWaitForInstanceVolumeDetached(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id, volID string) (interface{}, error) { - - stateConf := &resource.StateChangeConf{ - Pending: []string{isInstanceVolumeAttached, isInstanceVolumeDetaching}, - Target: []string{isInstanceDeleteDone, ""}, - Refresh: func() (interface{}, string, error) { - getvolattoptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - InstanceID: &id, - ID: &volID, - } - vol, response, err := instanceC.GetInstanceVolumeAttachment(getvolattoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return vol, isInstanceDeleteDone, nil - } - return nil, "", fmt.Errorf("Error Detaching: %s\n%s", err, response) - } - if *vol.Status == isInstanceFailed { - return vol, *vol.Status, fmt.Errorf("The instance %s failed to detach volume %s: %v", d.Id(), volID, err) - } - return vol, isInstanceVolumeDetaching, nil - }, - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func resourceIbmIsInstanceInstanceDiskToMap(instanceDisk vpcv1.InstanceDisk) map[string]interface{} { - instanceDiskMap := map[string]interface{}{} - - instanceDiskMap["created_at"] = instanceDisk.CreatedAt.String() - instanceDiskMap["href"] = instanceDisk.Href - instanceDiskMap["id"] = instanceDisk.ID - instanceDiskMap["interface_type"] = instanceDisk.InterfaceType - instanceDiskMap["name"] = instanceDisk.Name - instanceDiskMap["resource_type"] = instanceDisk.ResourceType - instanceDiskMap["size"] = intValue(instanceDisk.Size) - - return instanceDiskMap -} - -func suppressEnableCleanDelete(k, old, new string, d *schema.ResourceData) bool { - // During import - if old == "" && d.Id() != "" { - return true - } - return false -} - -func resourceIbmIsInstanceInstancePlacementToMap(instancePlacement vpcv1.InstancePlacementTarget) map[string]interface{} { - instancePlacementMap := map[string]interface{}{} - - instancePlacementMap["crn"] = instancePlacement.CRN - if instancePlacement.Deleted != nil { - DeletedMap := resourceIbmIsInstanceDedicatedHostGroupReferenceDeletedToMap(*instancePlacement.Deleted) - instancePlacementMap["deleted"] = []map[string]interface{}{DeletedMap} - } - instancePlacementMap["href"] = instancePlacement.Href - instancePlacementMap["id"] = instancePlacement.ID - instancePlacementMap["name"] = instancePlacement.Name - instancePlacementMap["resource_type"] = instancePlacement.ResourceType - - return instancePlacementMap -} - -func resourceIbmIsInstanceDedicatedHostGroupReferenceDeletedToMap(dedicatedHostGroupReferenceDeleted vpcv1.DedicatedHostGroupReferenceDeleted) map[string]interface{} { - dedicatedHostGroupReferenceDeletedMap := map[string]interface{}{} - - dedicatedHostGroupReferenceDeletedMap["more_info"] = dedicatedHostGroupReferenceDeleted.MoreInfo - - return dedicatedHostGroupReferenceDeletedMap -} diff --git a/ibm/resource_ibm_is_instance_template.go b/ibm/resource_ibm_is_instance_template.go deleted file mode 100644 index 428f03cdb..000000000 --- a/ibm/resource_ibm_is_instance_template.go +++ /dev/null @@ -1,932 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceTemplateBootVolume = "boot_volume" - isInstanceTemplateCRN = "crn" - isInstanceTemplateVolAttVolAutoDelete = "auto_delete" - isInstanceTemplateVolAttVol = "volume" - isInstanceTemplateVolAttachmentName = "name" - isInstanceTemplateVolAttVolPrototype = "volume_prototype" - isInstanceTemplateVolAttVolCapacity = "capacity" - isInstanceTemplateVolAttVolIops = "iops" - isInstanceTemplateVolAttVolName = "name" - isInstanceTemplateVolAttVolBillingTerm = "billing_term" - isInstanceTemplateVolAttVolEncryptionKey = "encryption_key" - isInstanceTemplateVolAttVolType = "type" - isInstanceTemplateVolAttVolProfile = "profile" - isInstanceTemplateProvisioning = "provisioning" - isInstanceTemplateProvisioningDone = "done" - isInstanceTemplateAvailable = "available" - isInstanceTemplateDeleting = "deleting" - isInstanceTemplateDeleteDone = "done" - isInstanceTemplateFailed = "failed" - isInstanceTemplateBootName = "name" - isInstanceTemplateBootSize = "size" - isInstanceTemplateBootIOPS = "iops" - isInstanceTemplateBootEncryption = "encryption" - isInstanceTemplateBootProfile = "profile" - isInstanceTemplateVolumeAttaching = "attaching" - isInstanceTemplateVolumeAttached = "attached" - isInstanceTemplateVolumeDetaching = "detaching" - isInstanceTemplatePlacementTarget = "placement_target" - isInstanceTemplateDedicatedHost = "dedicated_host" - isInstanceTemplateDedicatedHostGroup = "dedicated_host_group" - isInstanceTemplateResourceType = "resource_type" - isInstanceTemplateVolumeDeleteOnInstanceDelete = "delete_volume_on_instance_delete" -) - -func resourceIBMISInstanceTemplate() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMisInstanceTemplateCreate, - Read: resourceIBMisInstanceTemplateRead, - Update: resourceIBMisInstanceTemplateUpdate, - Delete: resourceIBMisInstanceTemplateDelete, - Exists: resourceIBMisInstanceTemplateExists, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceVolumeAttachmentValidate(diff) - }), - ), - - Schema: map[string]*schema.Schema{ - isInstanceTemplateName: { - Type: schema.TypeString, - Required: true, - ForceNew: false, - ValidateFunc: validateISName, - Description: "Instance Template name", - }, - - isInstanceTemplateVPC: { - Type: schema.TypeString, - ForceNew: true, - Required: true, - Description: "VPC id", - }, - - isInstanceTemplateZone: { - Type: schema.TypeString, - ForceNew: true, - Required: true, - Description: "Zone name", - }, - - isInstanceTemplateProfile: { - Type: schema.TypeString, - ForceNew: true, - Required: true, - Description: "Profile info", - }, - - isInstanceTemplateKeys: { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - DiffSuppressFunc: applyOnce, - Description: "SSH key Ids for the instance template", - }, - - isPlacementTargetDedicatedHost: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHostGroup, isPlacementTargetPlacementGroup}, - Description: "Unique Identifier of the Dedicated Host where the instance will be placed", - }, - - isPlacementTargetDedicatedHostGroup: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetPlacementGroup}, - Description: "Unique Identifier of the Dedicated Host Group where the instance will be placed", - }, - - isPlacementTargetPlacementGroup: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetDedicatedHostGroup}, - Description: "Unique Identifier of the Placement Group for restricting the placement of the instance", - }, - - isInstanceTemplateVolumeAttachments: { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateVolumeDeleteOnInstanceDelete: { - Type: schema.TypeBool, - Required: true, - Description: "If set to true, when deleting the instance the volume will also be deleted.", - }, - isInstanceTemplateVolAttachmentName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_template", isInstanceTemplateVolAttachmentName), - Description: "The user-defined name for this volume attachment.", - }, - isInstanceTemplateVolAttVol: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The unique identifier for this volume.", - }, - isInstanceTemplateVolAttVolPrototype: { - Type: schema.TypeList, - MaxItems: 1, - MinItems: 1, - Optional: true, - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateVolAttVolIops: { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - Description: "The maximum I/O operations per second (IOPS) for the volume.", - }, - isInstanceTemplateVolAttVolProfile: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The globally unique name for the volume profile to use for this volume.", - }, - isInstanceTemplateVolAttVolCapacity: { - Type: schema.TypeInt, - Required: true, - ForceNew: true, - Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", - }, - isInstanceTemplateVolAttVolEncryptionKey: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", - }, - }, - }, - }, - }, - }, - }, - - isInstanceTemplatePrimaryNetworkInterface: { - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - Description: "Primary Network interface info", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicAllowIPSpoofing: { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - isInstanceTemplateNicName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - }, - }, - - isInstanceTemplateNetworkInterfaces: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateNicAllowIPSpoofing: { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - isInstanceTemplateNicName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateNicSecurityGroups: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - isInstanceTemplateNicSubnet: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - }, - }, - - isInstanceTemplateUserData: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Description: "User data given for the instance", - }, - - isInstanceTemplateCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for the instance", - }, - - isInstanceTemplateImage: { - Type: schema.TypeString, - ForceNew: true, - Required: true, - Description: "image name", - }, - - isInstanceTemplateBootVolume: { - Type: schema.TypeList, - DiffSuppressFunc: applyOnce, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isInstanceTemplateBootName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateBootEncryption: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - isInstanceTemplateBootSize: { - Type: schema.TypeInt, - Computed: true, - }, - isInstanceTemplateBootProfile: { - Type: schema.TypeString, - Computed: true, - }, - isInstanceTemplateVolumeDeleteOnInstanceDelete: { - Type: schema.TypeBool, - Optional: true, - Computed: true, - }, - }, - }, - }, - - isInstanceTemplateResourceGroup: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - Description: "Instance template resource group", - }, - - isInstanceTemplatePlacementTarget: { - Type: schema.TypeList, - Computed: true, - Description: "The placement restrictions for the virtual server instance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this placement target.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this placement target.", - }, - "href": { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this placement target.", - }, - }, - }, - }, - }, - } -} - -func resourceIBMISInstanceTemplateValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceTemplateVolAttachmentName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - ibmISInstanceTemplateValidator := ResourceValidator{ResourceName: "ibm_is_instance_template", Schema: validateSchema} - return &ibmISInstanceTemplateValidator -} - -func resourceIBMisInstanceTemplateCreate(d *schema.ResourceData, meta interface{}) error { - profile := d.Get(isInstanceTemplateProfile).(string) - name := d.Get(isInstanceTemplateName).(string) - vpcID := d.Get(isInstanceTemplateVPC).(string) - zone := d.Get(isInstanceTemplateZone).(string) - image := d.Get(isInstanceTemplateImage).(string) - - err := instanceTemplateCreate(d, meta, profile, name, vpcID, zone, image) - if err != nil { - return err - } - - return resourceIBMisInstanceTemplateRead(d, meta) -} - -func resourceIBMisInstanceTemplateRead(d *schema.ResourceData, meta interface{}) error { - ID := d.Id() - err := instanceTemplateGet(d, meta, ID) - if err != nil { - return err - } - return nil -} - -func resourceIBMisInstanceTemplateDelete(d *schema.ResourceData, meta interface{}) error { - - ID := d.Id() - - err := instanceTemplateDelete(d, meta, ID) - if err != nil { - return err - } - return nil -} - -func resourceIBMisInstanceTemplateUpdate(d *schema.ResourceData, meta interface{}) error { - - err := instanceTemplateUpdate(d, meta) - if err != nil { - return err - } - return resourceIBMisInstanceTemplateRead(d, meta) -} - -func resourceIBMisInstanceTemplateExists(d *schema.ResourceData, meta interface{}) (bool, error) { - ID := d.Id() - ok, err := instanceTemplateExists(d, meta, ID) - if err != nil { - return false, err - } - return ok, err -} - -func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - instanceproto := &vpcv1.InstanceTemplatePrototype{ - Image: &vpcv1.ImageIdentity{ - ID: &image, - }, - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.InstanceProfileIdentity{ - Name: &profile, - }, - Name: &name, - VPC: &vpcv1.VPCIdentity{ - ID: &vpcID, - }, - } - - if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { - dHostIdStr := dHostIdInf.(string) - dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ - ID: &dHostIdStr, - } - instanceproto.PlacementTarget = dHostPlaementTarget - } - - if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { - dHostGrpIdStr := dHostGrpIdInf.(string) - dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ - ID: &dHostGrpIdStr, - } - instanceproto.PlacementTarget = dHostGrpPlaementTarget - } - - if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { - placementGrpStr := placementGroupInf.(string) - placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ - ID: &placementGrpStr, - } - instanceproto.PlacementTarget = placementGrp - } - - // BOOT VOLUME ATTACHMENT for instance template - if boot, ok := d.GetOk(isInstanceTemplateBootVolume); ok { - bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} - name, ok := bootvol[isInstanceTemplateBootName] - namestr := name.(string) - if ok && namestr != "" { - volTemplate.Name = &namestr - } - - volcap := 100 - volcapint64 := int64(volcap) - volprof := "general-purpose" - volTemplate.Capacity = &volcapint64 - volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volprof, - } - - if encryption, ok := bootvol[isInstanceTemplateBootEncryption]; ok { - bootEncryption := encryption.(string) - if bootEncryption != "" { - volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &bootEncryption, - } - } - } - - var deleteVolumeOption bool - if deleteVolume, ok := bootvol[isInstanceTemplateVolumeDeleteOnInstanceDelete]; ok { - deleteVolumeOption = deleteVolume.(bool) - } - - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ - DeleteVolumeOnInstanceDelete: &deleteVolumeOption, - Volume: volTemplate, - } - } - - // Handle volume attachments - if volsintf, ok := d.GetOk(isInstanceTemplateVolumeAttachments); ok { - vols := volsintf.([]interface{}) - var intfs []vpcv1.VolumeAttachmentPrototypeInstanceContext - for _, resource := range vols { - vol := resource.(map[string]interface{}) - volInterface := &vpcv1.VolumeAttachmentPrototypeInstanceContext{} - deleteVolBool := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete].(bool) - volInterface.DeleteVolumeOnInstanceDelete = &deleteVolBool - attachmentnamestr := vol[isInstanceTemplateVolAttachmentName].(string) - volInterface.Name = &attachmentnamestr - volIdStr := vol[isInstanceTemplateVolAttVol].(string) - - if volIdStr != "" { - volInterface.Volume = &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ - ID: &volIdStr, - } - } else { - newvolintf := vol[isInstanceTemplateVolAttVolPrototype].([]interface{})[0] - newvol := newvolintf.(map[string]interface{}) - profileName := newvol[isInstanceTemplateVolAttVolProfile].(string) - capacity := int64(newvol[isInstanceTemplateVolAttVolCapacity].(int)) - - volPrototype := &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContext{ - Profile: &vpcv1.VolumeProfileIdentity{ - Name: &profileName, - }, - Capacity: &capacity, - } - iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) - encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) - - if iops != 0 { - volPrototype.Iops = &iops - } - - if encryptionKey != "" { - volPrototype.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encryptionKey, - } - } - volInterface.Volume = volPrototype - } - - intfs = append(intfs, *volInterface) - } - instanceproto.VolumeAttachments = intfs - } - - // Handle primary network interface - if primnicintf, ok := d.GetOk(isInstanceTemplatePrimaryNetworkInterface); ok { - primnic := primnicintf.([]interface{})[0].(map[string]interface{}) - subnetintf, _ := primnic[isInstanceTemplateNicSubnet] - subnetintfstr := subnetintf.(string) - var primnicobj = &vpcv1.NetworkInterfacePrototype{} - primnicobj.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - - if name, ok := primnic[isInstanceTemplateNicName]; ok { - namestr := name.(string) - if namestr != "" { - primnicobj.Name = &namestr - } - } - allowIPSpoofing, ok := primnic[isInstanceTemplateNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - primnicobj.AllowIPSpoofing = &allowIPSpoofingbool - } - - secgrpintf, ok := primnic[isInstanceTemplateNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - primnicobj.SecurityGroups = secgrpobjs - } - } - instanceproto.PrimaryNetworkInterface = primnicobj - - if IPAddress, ok := primnic[isInstanceTemplateNicPrimaryIpv4Address]; ok { - if PrimaryIpv4Address := IPAddress.(string); PrimaryIpv4Address != "" { - primnicobj.PrimaryIpv4Address = &PrimaryIpv4Address - } - } - } - - // Handle additional network interface - if nicsintf, ok := d.GetOk(isInstanceTemplateNetworkInterfaces); ok { - nics := nicsintf.([]interface{}) - var intfs []vpcv1.NetworkInterfacePrototype - for _, resource := range nics { - nic := resource.(map[string]interface{}) - nwInterface := &vpcv1.NetworkInterfacePrototype{} - subnetintf, _ := nic[isInstanceTemplateNicSubnet] - subnetintfstr := subnetintf.(string) - nwInterface.Subnet = &vpcv1.SubnetIdentity{ - ID: &subnetintfstr, - } - - name, ok := nic[isInstanceTemplateNicName] - namestr := name.(string) - if ok && namestr != "" { - nwInterface.Name = &namestr - } - allowIPSpoofing, ok := nic[isInstanceTemplateNicAllowIPSpoofing] - allowIPSpoofingbool := allowIPSpoofing.(bool) - if ok { - nwInterface.AllowIPSpoofing = &allowIPSpoofingbool - } - secgrpintf, ok := nic[isInstanceTemplateNicSecurityGroups] - if ok { - secgrpSet := secgrpintf.(*schema.Set) - if secgrpSet.Len() != 0 { - var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) - for i, secgrpIntf := range secgrpSet.List() { - secgrpIntfstr := secgrpIntf.(string) - secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &secgrpIntfstr, - } - } - nwInterface.SecurityGroups = secgrpobjs - } - } - if IPAddress, ok := nic[isInstanceTemplateNicPrimaryIpv4Address]; ok { - if PrimaryIpv4Address := IPAddress.(string); PrimaryIpv4Address != "" { - nwInterface.PrimaryIpv4Address = &PrimaryIpv4Address - } - } - intfs = append(intfs, *nwInterface) - } - instanceproto.NetworkInterfaces = intfs - } - - // Handle SSH Keys - keySet := d.Get(isInstanceTemplateKeys).(*schema.Set) - if keySet.Len() != 0 { - keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) - for i, key := range keySet.List() { - keystr := key.(string) - keyobjs[i] = &vpcv1.KeyIdentity{ - ID: &keystr, - } - } - instanceproto.Keys = keyobjs - } - - // Handle user data - if userdata, ok := d.GetOk(isInstanceTemplateUserData); ok { - userdatastr := userdata.(string) - instanceproto.UserData = &userdatastr - } - - // handle resource group - if grp, ok := d.GetOk(isInstanceTemplateResourceGroup); ok { - grpstr := grp.(string) - instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &grpstr, - } - - } - - options := &vpcv1.CreateInstanceTemplateOptions{ - InstanceTemplatePrototype: instanceproto, - } - - instanceIntf, response, err := sess.CreateInstanceTemplate(options) - if err != nil { - return fmt.Errorf("Error creating InstanceTemplate: %s\n%s", err, response) - } - instance := instanceIntf.(*vpcv1.InstanceTemplate) - d.SetId(*instance.ID) - return nil -} - -func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - getinsOptions := &vpcv1.GetInstanceTemplateOptions{ - ID: &ID, - } - instanceIntf, response, err := instanceC.GetInstanceTemplate(getinsOptions) - if err != nil { - return fmt.Errorf("Error Getting Instance template: %s\n%s", err, response) - } - instance := instanceIntf.(*vpcv1.InstanceTemplate) - d.Set(isInstanceTemplateName, *instance.Name) - d.Set(isInstanceTemplateCRN, *instance.CRN) - if instance.Profile != nil { - instanceProfileIntf := instance.Profile - identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) - d.Set(isInstanceTemplateProfile, *identity.Name) - } - - var placementTargetMap map[string]interface{} - if instance.PlacementTarget != nil { - placementTargetMap = resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - } - if err = d.Set(isInstanceTemplatePlacementTarget, []map[string]interface{}{placementTargetMap}); err != nil { - return fmt.Errorf("Error setting placement_target: %s", err) - } - - if instance.PrimaryNetworkInterface != nil { - primaryNicList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name - if instance.PrimaryNetworkInterface.PrimaryIpv4Address != nil { - currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address - } - subInf := instance.PrimaryNetworkInterface.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if instance.PrimaryNetworkInterface.AllowIPSpoofing != nil { - currentPrimNic[isInstanceTemplateNicAllowIPSpoofing] = *instance.PrimaryNetworkInterface.AllowIPSpoofing - } - if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { - secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] - subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*subnetIdentity.ID)) - } - currentPrimNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - primaryNicList = append(primaryNicList, currentPrimNic) - d.Set(isInstanceTemplatePrimaryNetworkInterface, primaryNicList) - } - - if instance.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instance.NetworkInterfaces { - currentNic := map[string]interface{}{} - currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address - } - if intfc.AllowIPSpoofing != nil { - currentNic[isInstanceTemplateNicAllowIPSpoofing] = *intfc.AllowIPSpoofing - } - subInf := intfc.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if len(intfc.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(intfc.SecurityGroups); i++ { - secGrpInf := intfc.SecurityGroups[i] - subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*subnetIdentity.ID)) - } - currentNic[isInstanceTemplateNicSecurityGroups] = newStringSet(schema.HashString, secgrpList) - } - interfacesList = append(interfacesList, currentNic) - } - d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) - } - - if instance.Image != nil { - imageInf := instance.Image - imageIdentity := imageInf.(*vpcv1.ImageIdentity) - d.Set(isInstanceTemplateImage, *imageIdentity.ID) - } - vpcInf := instance.VPC - vpcRef := vpcInf.(*vpcv1.VPCIdentity) - d.Set(isInstanceTemplateVPC, vpcRef.ID) - zoneInf := instance.Zone - zone := zoneInf.(*vpcv1.ZoneIdentity) - d.Set(isInstanceTemplateZone, *zone.Name) - - interfacesList := make([]map[string]interface{}, 0) - if instance.VolumeAttachments != nil { - for _, volume := range instance.VolumeAttachments { - volumeAttach := map[string]interface{}{} - volumeAttach[isInstanceTemplateVolAttName] = *volume.Name - volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - newVolumeArr := []map[string]interface{}{} - newVolume := map[string]interface{}{} - volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - if volumeInst.ID != nil { - volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID - } - - if volumeInst.Capacity != nil { - newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity - } - if volumeInst.Profile != nil { - profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) - newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name - } - - if volumeInst.Iops != nil { - newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops - } - if volumeInst.EncryptionKey != nil { - encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) - newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN - } - if len(newVolume) > 0 { - newVolumeArr = append(newVolumeArr, newVolume) - } - volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr - interfacesList = append(interfacesList, volumeAttach) - } - d.Set(isInstanceTemplateVolumeAttachments, interfacesList) - } - if instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - bootVol[isInstanceTemplateDeleteVolume] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete - if instance.BootVolumeAttachment.Volume != nil { - volumeIntf := instance.BootVolumeAttachment.Volume - bootVol[isInstanceTemplateBootName] = volumeIntf.Name - bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity - if volumeIntf.Profile != nil { - volProfIntf := volumeIntf.Profile - volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) - bootVol[isInstanceTemplateBootProfile] = volProfInst.Name - } - if volumeIntf.EncryptionKey != nil { - volEncryption := volumeIntf.EncryptionKey - volEncryptionIntf := volEncryption.(*vpcv1.EncryptionKeyIdentity) - bootVol[isInstanceTemplateBootEncryption] = volEncryptionIntf.CRN - } - } - - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceTemplateBootVolume, bootVolList) - } - - if instance.ResourceGroup != nil { - d.Set(isInstanceTemplateResourceGroup, instance.ResourceGroup.ID) - } - return nil -} - -func resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(instancePlacementTargetPrototype vpcv1.InstancePlacementTargetPrototype) map[string]interface{} { - instancePlacementTargetPrototypeMap := map[string]interface{}{} - - instancePlacementTargetPrototypeMap["id"] = instancePlacementTargetPrototype.ID - instancePlacementTargetPrototypeMap["crn"] = instancePlacementTargetPrototype.CRN - instancePlacementTargetPrototypeMap["href"] = instancePlacementTargetPrototype.Href - - return instancePlacementTargetPrototypeMap -} - -func instanceTemplateUpdate(d *schema.ResourceData, meta interface{}) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - ID := d.Id() - - if d.HasChange(isInstanceName) { - name := d.Get(isInstanceTemplateName).(string) - updnetoptions := &vpcv1.UpdateInstanceTemplateOptions{ - ID: &ID, - } - - instanceTemplatePatchModel := &vpcv1.InstanceTemplatePatch{ - Name: &name, - } - instanceTemplatePatch, err := instanceTemplatePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceTemplatePatch: %s", err) - } - updnetoptions.InstanceTemplatePatch = instanceTemplatePatch - - _, _, err = instanceC.UpdateInstanceTemplate(updnetoptions) - if err != nil { - return err - } - } - return nil -} - -func instanceTemplateDelete(d *schema.ResourceData, meta interface{}, ID string) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - - deleteinstanceTemplateOptions := &vpcv1.DeleteInstanceTemplateOptions{ - ID: &ID, - } - _, err = instanceC.DeleteInstanceTemplate(deleteinstanceTemplateOptions) - if err != nil { - return err - } - return nil -} - -func instanceTemplateExists(d *schema.ResourceData, meta interface{}, ID string) (bool, error) { - instanceC, err := vpcClient(meta) - if err != nil { - return false, err - } - getinsOptions := &vpcv1.GetInstanceTemplateOptions{ - ID: &ID, - } - _, response, err := instanceC.GetInstanceTemplate(getinsOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error Getting InstanceTemplate: %s\n%s", err, response) - } - return true, nil -} diff --git a/ibm/resource_ibm_is_instance_template_test.go b/ibm/resource_ibm_is_instance_template_test.go deleted file mode 100644 index 0ac51eb33..000000000 --- a/ibm/resource_ibm_is_instance_template_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISInstanceTemplate_basic(t *testing.T) { - randInt := acctest.RandIntRange(10, 100) - - publicKey := strings.TrimSpace(` - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 - `) - vpcName := fmt.Sprintf("tf-testvpc%d", randInt) - subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) - templateName := fmt.Sprintf("tf-testtemplate%d", randInt) - sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_is_instance_template.instancetemplate1", "name", templateName), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_template.instancetemplate1", "profile"), - ), - }, - }, - }) -} - -func TestAccIBMISInstanceTemplate_WithVolumeAttachment(t *testing.T) { - randInt := acctest.RandIntRange(10, 100) - - publicKey := strings.TrimSpace(` - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 - `) - vpcName := fmt.Sprintf("tf-testvpc%d", randInt) - subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) - templateName := fmt.Sprintf("tf-testtemplate%d", randInt) - volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) - sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_is_instance_template.instancetemplate1", "name", templateName), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_template.instancetemplate1", "profile"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceTemplateDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_instance_template" { - continue - } - - getInstanceTemplateOptions := vpcv1.GetInstanceTemplateOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetInstanceTemplate(&getInstanceTemplateOptions) - - if err == nil { - return fmt.Errorf("instance template still exists: %s", rs.Primary.ID) - } - } - return nil -} - -func testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { - return fmt.Sprintf(` - provider "ibm" { - generation = 2 - } - - resource "ibm_is_vpc" "vpc2" { - name = "%s" - } - - resource "ibm_is_subnet" "subnet2" { - name = "%s" - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - ipv4_cidr_block = "10.240.64.0/28" - } - - resource "ibm_is_ssh_key" "sshkey" { - name = "%s" - public_key = "%s" - } - - data "ibm_is_images" "is_images" { - } - - resource "ibm_is_instance_template" "instancetemplate1" { - name = "%s" - image = data.ibm_is_images.is_images.images.0.id - profile = "bx2-8x32" - - primary_network_interface { - subnet = ibm_is_subnet.subnet2.id - } - - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] - } - - - `, vpcName, subnetName, sshKeyName, publicKey, templateName) - -} - -func testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName string) string { - return fmt.Sprintf(` - provider "ibm" { - generation = 2 - } - - resource "ibm_is_vpc" "vpc2" { - name = "%s" - } - - resource "ibm_is_subnet" "subnet2" { - name = "%s" - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - ipv4_cidr_block = "10.240.64.0/28" - } - - resource "ibm_is_ssh_key" "sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance_template" "instancetemplate1" { - name = "%s" - image = "%s" - profile = "bx2-8x32" - - primary_network_interface { - subnet = ibm_is_subnet.subnet2.id - } - volume_attachments { - delete_volume_on_instance_delete = true - name = "%s" - volume_prototype { - iops = 9000 - profile = "general-purpose" - capacity = 100 - } - } - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] - } - - - `, vpcName, subnetName, sshKeyName, publicKey, templateName, isImage, volAttachName) - -} diff --git a/ibm/resource_ibm_is_instance_test.go b/ibm/resource_ibm_is_instance_test.go deleted file mode 100644 index e8cac9eb9..000000000 --- a/ibm/resource_ibm_is_instance_test.go +++ /dev/null @@ -1,801 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISInstance_basic(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - ), - }, - }, - }) -} - -func TestAccIBMISInstanceWithSecurityGroup_basic(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - secGrpName := fmt.Sprintf("tf-secgrp-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceWithSecurityGroupConfig(vpcname, subnetname, sshname, publicKey, secGrpName, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttrSet( - "ibm_is_instance.testacc_instance", "primary_network_interface.0.security_groups.#"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance.testacc_instance", "network_interfaces.0.security_groups.#"), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_profile(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, instanceProfileName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "profile", instanceProfileName), - ), - }, - - { - Config: testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, instanceProfileNameUpdate), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "profile", instanceProfileNameUpdate), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_basicwithipv4(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - ipv4address := "10.240.0.6" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceConfigwithipv4(vpcname, subnetname, sshname, publicKey, name, ipv4address), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "primary_network_interface.0.primary_ipv4_address", ipv4address), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_VolumeAutoDelete(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceVolumeAutoDelete(vpcname, subnetname, sshname, publicKey, volname, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "1"), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "auto_delete_volume", "true"), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_Volume(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volname, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "1"), - ), - }, - { - Config: testAccCheckIBMISInstanceVolumeUpdate(vpcname, subnetname, sshname, publicKey, volname, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "0"), - ), - }, - { - Config: testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volname, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "1"), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_Disk(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "disks.#", "1"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance.testacc_instance", "disks.0.name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance.testacc_instance", "disks.0.size"), - ), - }, - }, - }) -} - -func TestAccIBMISInstance_Placement(t *testing.T) { - var instance string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - dhostname := fmt.Sprintf("tf-dhost-%d", acctest.RandIntRange(10, 100)) - dhostgrpname := fmt.Sprintf("tf-dhostgrp-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstancePlacement(vpcname, subnetname, sshname, publicKey, volname, name, dhostname, dhostgrpname), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttrSet( - "data.ibm_is_dedicated_host.dhost", "instances.#"), - resource.TestCheckResourceAttr( - "data.ibm_is_dedicated_host.dhost", "instances.0.name", name), - ), - }, - }, - }) -} - -func TestAccIBMISInstanceSnapshotRestore_basic(t *testing.T) { - var instance, instanceRestore string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - snapshot := fmt.Sprintf("tf-snapshot-%d", acctest.RandIntRange(10, 100)) - vsiRestore := fmt.Sprintf("tf-instancerestore-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceSnapshotRestoreConfig(vpcname, subnetname, sshname, publicKey, name, snapshot, vsiRestore), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), - testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance_restore", instanceRestore), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_snapshot.testacc_snapshot", "name", snapshot), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance_restore", "zone", ISZoneName), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance_restore", "name", vsiRestore), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance_restore", "boot_volume.0.name", "boot-restore"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceDestroy(s *terraform.State) error { - - instanceC, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_instance" { - continue - } - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &rs.Primary.ID, - } - _, _, err := instanceC.GetInstance(getinsOptions) - - if err == nil { - return fmt.Errorf("instance still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISInstanceExists(n string, instance string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - instanceC, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &rs.Primary.ID, - } - foundins, _, err := instanceC.GetInstance(getinsOptions) - if err != nil { - return err - } - instance = *foundins.ID - return nil - } -} - -func testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceWithSecurityGroupConfig(vpcname, subnetname, sshname, publicKey, secgrpname, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - resource "ibm_is_security_group" "testacc_security_group" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - } - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - security_groups = [ibm_is_security_group.testacc_security_group.id] - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - security_groups = [ibm_is_security_group.testacc_security_group.id] - } - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, secgrpname, name, isImage, instanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceSnapshotRestoreConfig(vpcname, subnetname, sshname, publicKey, name, snapshot, insRestore string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - } - resource "ibm_is_snapshot" "testacc_snapshot" { - name = "%s" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id - } - - resource "ibm_is_instance" "testacc_instance_restore" { - name = "%s" - profile = "%s" - boot_volume { - name = "boot-restore" - snapshot = ibm_is_snapshot.testacc_snapshot.id - } - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - } - `, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, snapshot, insRestore, instanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, isInstanceProfileName string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, isInstanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceConfigwithipv4(vpcname, subnetname, sshname, publicKey, name, ipv4address string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - primary_ipv4_address = "%s" - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, instanceProfileName, ipv4address, ISZoneName) -} - -func testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volName, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_volume" "storage" { - name = "%s" - profile = "10iops-tier" - zone = "%s" - # capacity= 200 - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - volumes = [ibm_is_volume.storage.id] - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, volName, ISZoneName, name, isImage, instanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volName, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_volume" "storage" { - name = "%s" - profile = "10iops-tier" - zone = "%s" - # capacity= 200 - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - volumes = [ibm_is_volume.storage.id] - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, volName, ISZoneName, name, isImage, instanceDiskProfileName, ISZoneName) -} - -func testAccCheckIBMISInstancePlacement(vpcname, subnetname, sshname, publicKey, volName, name, dhostname, dhostgrpname string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_volume" "storage" { - name = "%s" - profile = "10iops-tier" - zone = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - dedicated_host_group = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - - } - data "ibm_is_dedicated_host" "dhost"{ - host_group = ibm_is_instance.testacc_instance.dedicated_host_group - name = "%s" - } - - `, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, volName, ISZoneName, name, isImage, instanceProfileName, dedicatedHostGroupID, ISZoneName, dedicatedHostName) -} - -func testAccCheckIBMISInstanceVolumeAutoDelete(vpcname, subnetname, sshname, publicKey, volName, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_volume" "storage" { - name = "%s" - profile = "10iops-tier" - zone = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - volumes = [ibm_is_volume.storage.id] - auto_delete_volume = true - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, volName, ISZoneName, name, isImage, instanceProfileName, ISZoneName) -} - -func testAccCheckIBMISInstanceVolumeUpdate(vpcname, subnetname, sshname, publicKey, volName, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_volume" "storage" { - name = "%s" - profile = "10iops-tier" - zone = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - -`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, volName, ISZoneName, name, isImage, instanceProfileName, ISZoneName) -} diff --git a/ibm/resource_ibm_is_instance_volume_attachment.go b/ibm/resource_ibm_is_instance_volume_attachment.go deleted file mode 100644 index 20f7e89f3..000000000 --- a/ibm/resource_ibm_is_instance_volume_attachment.go +++ /dev/null @@ -1,712 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isInstanceId = "instance" - isInstanceVolAttVol = "volume" - isInstanceVolAttId = "volume_attachment_id" - isInstanceVolAttIops = "volume_iops" - isInstanceExistingVolume = "existing" - isInstanceVolAttName = "name" - isInstanceVolAttVolume = "volume" - isInstanceVolumeDeleteOnInstanceDelete = "delete_volume_on_instance_delete" - isInstanceVolumeDeleteOnAttachmentDelete = "delete_volume_on_attachment_delete" - isInstanceVolCapacity = "capacity" - isInstanceVolIops = "iops" - isInstanceVolEncryptionKey = "encryption_key" - isInstanceVolProfile = "profile" -) - -func resourceIBMISInstanceVolumeAttachment() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMisInstanceVolumeAttachmentCreate, - Read: resourceIBMisInstanceVolumeAttachmentRead, - Update: resourceIBMisInstanceVolumeAttachmentUpdate, - Delete: resourceIBMisInstanceVolumeAttachmentDelete, - Exists: resourceIBMisInstanceVolumeAttachmentExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - }, - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceVolumeValidate(diff) - }), - ), - Schema: map[string]*schema.Schema{ - isInstanceId: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_instance_volume_attachment", isInstanceId), - Description: "Instance id", - }, - isInstanceVolAttId: { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for this volume attachment", - }, - - isInstanceVolAttName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolAttName), - Description: "The user-defined name for this volume attachment.", - }, - - isInstanceVolumeDeleteOnInstanceDelete: { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "If set to true, when deleting the instance the volume will also be deleted.", - }, - isInstanceVolumeDeleteOnAttachmentDelete: { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "If set to true, when deleting the attachment, the volume will also be deleted. Default value for this true.", - }, - isInstanceVolAttVol: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ConflictsWith: []string{isInstanceVolIops, isInstanceVolumeAttVolumeReferenceName, isInstanceVolProfile, isInstanceVolCapacity, isInstanceVolumeSnapshot}, - ValidateFunc: InvokeValidator("ibm_is_instance_volume_attachment", isInstanceName), - Description: "Instance id", - }, - - isInstanceVolIops: { - Type: schema.TypeInt, - Computed: true, - Optional: true, - ConflictsWith: []string{isInstanceVolAttVol}, - Description: "The maximum I/O operations per second (IOPS) for the volume.", - }, - - isInstanceVolumeAttVolumeReferenceName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolumeAttVolumeReferenceName), - Description: "The unique user-defined name for this volume", - }, - - isInstanceVolProfile: { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{isInstanceVolAttVol}, - Computed: true, - Description: "The globally unique name for the volume profile to use for this volume.", - }, - isInstanceVolCapacity: { - Type: schema.TypeInt, - Optional: true, - Computed: true, - AtLeastOneOf: []string{isInstanceVolAttVol, isInstanceVolCapacity, isInstanceVolumeSnapshot}, - ConflictsWith: []string{isInstanceVolAttVol}, - ValidateFunc: InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolCapacity), - Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", - }, - isInstanceVolEncryptionKey: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", - }, - isInstanceVolumeSnapshot: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - AtLeastOneOf: []string{isInstanceVolAttVol, isInstanceVolCapacity, isInstanceVolumeSnapshot}, - ConflictsWith: []string{isInstanceVolAttVol}, - Description: "The snapshot of the volume to be attached", - }, - isInstanceVolumeAttVolumeReferenceCrn: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this volume", - }, - isInstanceVolumeAttVolumeReferenceDeleted: { - Type: schema.TypeString, - Computed: true, - Description: "Link to documentation about deleted resources", - }, - isInstanceVolumeAttVolumeReferenceHref: { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this volume", - }, - - isInstanceVolumeAttDevice: { - Type: schema.TypeString, - Computed: true, - Description: "A unique identifier for the device which is exposed to the instance operating system", - }, - - isInstanceVolumeAttHref: { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this volume attachment", - }, - - isInstanceVolumeAttStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of this volume attachment, one of [ attached, attaching, deleting, detaching ]", - }, - - isInstanceVolumeAttType: { - Type: schema.TypeString, - Computed: true, - Description: "The type of volume attachment one of [ boot, data ]", - }, - }, - } -} - -func resourceIBMISInstanceVolumeAttachmentValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceId, - ValidateFunctionIdentifier: ValidateNoZeroValues, - Type: TypeString}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceVolAttName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceVolCapacity, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, - MinValue: "10", - MaxValue: "16000"}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isInstanceVolumeAttVolumeReferenceName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - ibmISInstanceVolumeAttachmentValidator := ResourceValidator{ResourceName: "ibm_is_instance_volume_attachment", Schema: validateSchema} - return &ibmISInstanceVolumeAttachmentValidator -} - -func instanceVolAttachmentCreate(d *schema.ResourceData, meta interface{}, instanceId string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - instanceVolAttproto := &vpcv1.CreateInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - } - volumeIdStr := "" - if volumeId, ok := d.GetOk(isInstanceVolAttVol); ok { - volumeIdStr = volumeId.(string) - } - if volumeIdStr != "" { - var volProtoVol = &vpcv1.VolumeAttachmentPrototypeVolumeVolumeIdentity{} - volProtoVol.ID = &volumeIdStr - instanceVolAttproto.Volume = volProtoVol - } else { - var volProtoVol = &vpcv1.VolumeAttachmentPrototypeVolumeVolumePrototypeInstanceContext{} - if volname, ok := d.GetOk(isInstanceVolumeAttVolumeReferenceName); ok { - volnamestr := volname.(string) - volProtoVol.Name = &volnamestr - } - - volProfileStr := "general-purpose" - if volProfile, ok := d.GetOk(isInstanceVolProfile); ok { - volProfileStr = volProfile.(string) - volProtoVol.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volProfileStr, - } - } else { - volProtoVol.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &volProfileStr, - } - } - volSnapshotStr := "" - if volSnapshot, ok := d.GetOk(isInstanceVolumeSnapshot); ok { - volSnapshotStr = volSnapshot.(string) - volProtoVol.SourceSnapshot = &vpcv1.SnapshotIdentity{ - ID: &volSnapshotStr, - } - } - encryptionCRNStr := "" - if encryptionCRN, ok := d.GetOk(isInstanceVolEncryptionKey); ok { - encryptionCRNStr = encryptionCRN.(string) - volProtoVol.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encryptionCRNStr, - } - } - var snapCapacity int64 - if volSnapshotStr != "" { - snapshotGet, _, err := sess.GetSnapshot(&vpcv1.GetSnapshotOptions{ - ID: &volSnapshotStr, - }) - if err != nil { - return fmt.Errorf("Error while getting snapshot details %q for instance %s: %q", volSnapshotStr, d.Id(), err) - } - snapCapacity = int64(int(*snapshotGet.MinimumCapacity)) - } - var volCapacityInt int64 - if volCapacity, ok := d.GetOk(isInstanceVolCapacity); ok { - volCapacityInt = int64(volCapacity.(int)) - if volCapacityInt != 0 && volCapacityInt > snapCapacity { - volProtoVol.Capacity = &volCapacityInt - } - } - var iops int64 - if volIops, ok := d.GetOk(isInstanceVolIops); ok { - iops = int64(volIops.(int)) - if iops != 0 { - volProtoVol.Iops = &iops - } - } - instanceVolAttproto.Volume = volProtoVol - } - - if autoDelete, ok := d.GetOk(isInstanceVolumeDeleteOnInstanceDelete); ok { - autoDeleteBool := autoDelete.(bool) - instanceVolAttproto.DeleteVolumeOnInstanceDelete = &autoDeleteBool - } - if name, ok := d.GetOk(isInstanceVolAttName); ok { - namestr := name.(string) - instanceVolAttproto.Name = &namestr - } - - isInstanceKey := "instance_key_" + instanceId - ibmMutexKV.Lock(isInstanceKey) - defer ibmMutexKV.Unlock(isInstanceKey) - - instanceVolAtt, response, err := sess.CreateInstanceVolumeAttachment(instanceVolAttproto) - if err != nil { - log.Printf("[DEBUG] Instance volume attachment create err %s\n%s", err, response) - return fmt.Errorf("Error while attaching volume for instance %s: %q", instanceId, err) - } - d.SetId(makeTerraformVolAttID(instanceId, *instanceVolAtt.ID)) - _, err = isWaitForInstanceVolumeAttached(sess, d, instanceId, *instanceVolAtt.ID) - if err != nil { - return err - } - log.Printf("[INFO] Instance (%s) volume attachment : %s", instanceId, *instanceVolAtt.ID) - return nil -} - -func resourceIBMisInstanceVolumeAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - instanceId := d.Get(isInstanceId).(string) - err := instanceVolAttachmentCreate(d, meta, instanceId) - if err != nil { - return err - } - return resourceIBMisInstanceVolumeAttachmentRead(d, meta) -} - -func resourceIBMisInstanceVolumeAttachmentRead(d *schema.ResourceData, meta interface{}) error { - instanceID, id, err := parseVolAttTerraformID(d.Id()) - if err != nil { - return err - } - err = instanceVolumeAttachmentGet(d, meta, instanceID, id) - if err != nil { - return err - } - return nil -} - -func instanceVolumeAttachmentGet(d *schema.ResourceData, meta interface{}, instanceId, id string) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - - getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - ID: &id, - } - volumeAtt, response, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Instance volume attachment : %s\n%s", err, response) - } - d.Set(isInstanceId, instanceId) - - if volumeAtt.Volume != nil { - d.Set(isInstanceVolumeAttVolumeReferenceName, *volumeAtt.Volume.Name) - d.Set(isInstanceVolumeAttVolumeReferenceCrn, *volumeAtt.Volume.CRN) - if volumeAtt.Volume.Deleted != nil { - d.Set(isInstanceVolumeAttVolumeReferenceDeleted, *volumeAtt.Volume.Deleted.MoreInfo) - } - d.Set(isInstanceVolumeAttVolumeReferenceHref, *volumeAtt.Volume.Href) - } - d.Set(isInstanceVolumeDeleteOnInstanceDelete, *volumeAtt.DeleteVolumeOnInstanceDelete) - d.Set(isInstanceVolAttName, *volumeAtt.Name) - if volumeAtt.Device != nil { - d.Set(isInstanceVolumeAttDevice, *volumeAtt.Device.ID) - } - d.Set(isInstanceVolumeAttHref, *volumeAtt.Href) - d.Set(isInstanceVolAttId, *volumeAtt.ID) - d.Set(isInstanceVolumeAttStatus, *volumeAtt.Status) - d.Set(isInstanceVolumeAttType, *volumeAtt.Type) - - volId := *volumeAtt.Volume.ID - getVolOptions := &vpcv1.GetVolumeOptions{ - ID: &volId, - } - volumeDetail, _, err := instanceC.GetVolume(getVolOptions) - if err != nil || volumeDetail == nil { - return fmt.Errorf("Error while getting volume details of volume %s ", id) - } - - d.Set(isInstanceVolAttVol, *volumeDetail.ID) - d.Set(isInstanceVolIops, *volumeDetail.Iops) - d.Set(isInstanceVolProfile, *volumeDetail.Profile.Name) - d.Set(isInstanceVolCapacity, *volumeDetail.Capacity) - if volumeDetail.EncryptionKey != nil { - d.Set(isInstanceVolEncryptionKey, *volumeDetail.EncryptionKey.CRN) - } - if volumeDetail.SourceSnapshot != nil { - d.Set(isInstanceVolumeSnapshot, *volumeDetail.SourceSnapshot.ID) - } - return nil -} - -func instanceVolAttUpdate(d *schema.ResourceData, meta interface{}) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - instanceId, id, err := parseVolAttTerraformID(d.Id()) - if err != nil { - return err - } - updateInstanceVolAttOptions := &vpcv1.UpdateInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - ID: &id, - } - flag := false - - // name && auto delete change - volAttNamePatchModel := &vpcv1.VolumeAttachmentPatch{} - if d.HasChange(isInstanceVolumeDeleteOnInstanceDelete) { - autoDelete := d.Get(isInstanceVolumeDeleteOnInstanceDelete).(bool) - volAttNamePatchModel.DeleteVolumeOnInstanceDelete = &autoDelete - flag = true - } - - if d.HasChange(isInstanceVolAttName) { - name := d.Get(isInstanceVolAttName).(string) - volAttNamePatchModel.Name = &name - flag = true - } - if flag { - volAttNamePatchModelAsPatch, err := volAttNamePatchModel.AsPatch() - if err != nil || volAttNamePatchModelAsPatch == nil { - return fmt.Errorf("Error Instance volume attachment (%s) as patch : %s", id, err) - } - updateInstanceVolAttOptions.VolumeAttachmentPatch = volAttNamePatchModelAsPatch - - instanceVolAttUpdate, response, err := instanceC.UpdateInstanceVolumeAttachment(updateInstanceVolAttOptions) - if err != nil || instanceVolAttUpdate == nil { - log.Printf("[DEBUG] Instance volume attachment updation err %s\n%s", err, response) - return err - } - } - - if d.HasChange(isInstanceVolumeAttVolumeReferenceName) { - newname := d.Get(isInstanceVolumeAttVolumeReferenceName).(string) - volid := d.Get(isInstanceVolAttVol).(string) - voloptions := &vpcv1.UpdateVolumeOptions{ - ID: &volid, - } - volumePatchModel := &vpcv1.VolumePatch{ - Name: &newname, - } - volumePatch, err := volumePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for VolumePatch: %s", err) - } - voloptions.VolumePatch = volumePatch - _, response, err := instanceC.UpdateVolume(voloptions) - if err != nil { - return fmt.Errorf("Error updating volume name : %s\n%s", err, response) - } - } - - // profile/iops update - - volId := "" - if volIdOk, ok := d.GetOk(isInstanceVolAttVol); ok { - volId = volIdOk.(string) - } - - if volId != "" && (d.HasChange(isInstanceVolIops) || d.HasChange(isInstanceVolProfile)) { - insId := d.Get(isInstanceId).(string) - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &insId, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error retrieving Instance (%s) : %s\n%s", insId, err, response) - } - - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &insId, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - return fmt.Errorf("Error starting Instance (%s) : %s\n%s", insId, err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, insId, d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - } - updateVolumeProfileOptions := &vpcv1.UpdateVolumeOptions{ - ID: &volId, - } - volumeProfilePatchModel := &vpcv1.VolumePatch{} - if d.HasChange(isInstanceVolProfile) { - profile := d.Get(isInstanceVolProfile).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &profile, - } - } else if d.HasChange(isVolumeIops) { - profile := d.Get(isInstanceVolProfile).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &profile, - } - iops := int64(d.Get(isVolumeIops).(int)) - volumeProfilePatchModel.Iops = &iops - } - - volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for volumeProfilePatch: %s", err) - } - updateVolumeProfileOptions.VolumePatch = volumeProfilePatch - _, response, err = instanceC.UpdateVolume(updateVolumeProfileOptions) - if err != nil { - return fmt.Errorf("Error updating volume profile/iops: %s\n%s", err, response) - } - isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) - } - - // capacity update - - if volId != "" && d.HasChange(isInstanceVolCapacity) { - - getvolumeoptions := &vpcv1.GetVolumeOptions{ - ID: &volId, - } - vol, response, err := instanceC.GetVolume(getvolumeoptions) - if err != nil { - return fmt.Errorf("Error Getting Volume (%s): %s\n%s", id, err, response) - } - - if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].Name == "" { - return fmt.Errorf("Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) - } - - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &instanceId, - } - instance, response, err := instanceC.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error retrieving Instance (%s) : %s\n%s", instanceId, err, response) - } - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &instanceId, - Type: &actiontype, - } - _, response, err = instanceC.CreateInstanceAction(createinsactoptions) - if err != nil { - return fmt.Errorf("Error starting Instance (%s) : %s\n%s", instanceId, err, response) - } - _, err = isWaitForInstanceAvailable(instanceC, instanceId, d.Timeout(schema.TimeoutCreate), d) - return fmt.Errorf("Error starting Instance (%s) : %s\n%s", instanceId, err, response) - } - capacity := int64(d.Get(isVolumeCapacity).(int)) - updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ - ID: &volId, - } - volumeCapacityPatchModel := &vpcv1.VolumePatch{} - volumeCapacityPatchModel.Capacity = &capacity - volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for volumeCapacityPatchModel: %s", err) - } - updateVolumeOptions.VolumePatch = volumeCapacityPatch - _, response, err = instanceC.UpdateVolume(updateVolumeOptions) - if err != nil { - return fmt.Errorf("Error updating volume capacity: %s\n%s", err, response) - } - _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - } - return nil -} - -func resourceIBMisInstanceVolumeAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - - err := instanceVolAttUpdate(d, meta) - if err != nil { - return err - } - return resourceIBMisInstanceVolumeAttachmentRead(d, meta) -} - -func instanceVolAttDelete(d *schema.ResourceData, meta interface{}, instanceId, id, volId string, volDelete bool) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err - } - - deleteInstanceVolAttOptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - ID: &id, - } - - isInstanceKey := "instance_key_" + instanceId - ibmMutexKV.Lock(isInstanceKey) - defer ibmMutexKV.Unlock(isInstanceKey) - - _, err = instanceC.DeleteInstanceVolumeAttachment(deleteInstanceVolAttOptions) - if err != nil { - return fmt.Errorf("Error while deleting volume attachment (%s) from instance (%s) : %q", id, instanceId, err) - } - _, err = isWaitForInstanceVolumeDetached(instanceC, d, instanceId, id) - - if err != nil { - return fmt.Errorf("Error while deleting volume attachment (%s) from instance (%s) on wait : %q", id, instanceId, err) - } - if volDelete { - deleteVolumeOptions := &vpcv1.DeleteVolumeOptions{ - ID: &volId, - } - response, err := instanceC.DeleteVolume(deleteVolumeOptions) - if err != nil { - return fmt.Errorf("Error while deleting volume : %s\n%s", err, response) - } - _, err = isWaitForVolumeDeleted(instanceC, volId, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - } - return nil -} - -func resourceIBMisInstanceVolumeAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - instanceId, id, err := parseVolAttTerraformID(d.Id()) - if err != nil { - return err - } - - volDelete := false - if volDeleteOk, ok := d.GetOk(isInstanceVolumeDeleteOnAttachmentDelete); ok { - volDelete = volDeleteOk.(bool) - } - volId := "" - if volIdOk, ok := d.GetOk(isInstanceVolAttVol); ok { - volId = volIdOk.(string) - } - - err = instanceVolAttDelete(d, meta, instanceId, id, volId, volDelete) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func resourceIBMisInstanceVolumeAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - instanceId, id, err := parseVolAttTerraformID(d.Id()) - if err != nil { - return false, err - } - exists, err := instanceVolAttExists(d, meta, instanceId, id) - return exists, err -} - -func instanceVolAttExists(d *schema.ResourceData, meta interface{}, instanceId, id string) (bool, error) { - instanceC, err := vpcClient(meta) - if err != nil { - return false, err - } - getinsvolattOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - ID: &id, - } - _, response, err := instanceC.GetInstanceVolumeAttachment(getinsvolattOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting Instance volume attachment: %s\n%s", err, response) - } - return true, nil -} - -func makeTerraformVolAttID(id1, id2 string) string { - // Include both instance id and volume attachment to create a unique Terraform id. As a bonus, - // we can extract the instance id as needed for API calls such as READ. - return fmt.Sprintf("%s/%s", id1, id2) -} - -func parseVolAttTerraformID(s string) (string, string, error) { - segments := strings.Split(s, "/") - if len(segments) != 2 { - return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) - } - if segments[0] == "" || segments[1] == "" { - return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) - } - return segments[0], segments[1], nil -} diff --git a/ibm/resource_ibm_is_instance_volume_attachment_test.go b/ibm/resource_ibm_is_instance_volume_attachment_test.go deleted file mode 100644 index 716da3f56..000000000 --- a/ibm/resource_ibm_is_instance_volume_attachment_test.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISInstanceVolumeAttachment_basic(t *testing.T) { - var instanceVolAtt string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - attName := fmt.Sprintf("tf-volatt-%d", acctest.RandIntRange(10, 100)) - autoDelete := true - volName := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - iops1 := int64(600) - iops2 := int64(900) - - capacity1 := int64(20) - capacity2 := int64(22) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity1, iops1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "name", attName), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity1)), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "iops", "600"), - ), - }, - { - Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity1, iops2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "name", attName), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity1)), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "iops", "900"), - ), - }, - - { - Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity2, iops2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "name", attName), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), - resource.TestCheckResourceAttr( - "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity2)), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceVolumeAttachmentDestroy(s *terraform.State) error { - - instanceC, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_instance_volume_attachment" { - continue - } - getinsvolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - ID: &rs.Primary.ID, - } - _, _, err := instanceC.GetInstanceVolumeAttachment(getinsvolAttOptions) - - if err == nil { - return fmt.Errorf("instance volume attachment still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISInstanceVolumeAttachmentExists(n string, instanceVolAtt string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - instanceId, id, err := parseVolAttTerraformID(rs.Primary.ID) - instanceC, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - ID: &id, - InstanceID: &instanceId, - } - foundins, _, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) - if err != nil { - return err - } - instanceVolAtt = *foundins.ID - return nil - } -} - -func testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName string, autoDelete bool, capacity, iops int64) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - } - resource "ibm_is_instance_volume_attachment" "testacc_att" { - instance = ibm_is_instance.testacc_instance.id - - name = "%s" - profile = "custom" - capacity = %d - iops = %d - - delete_volume_on_instance_delete = %t - volume_name = "%s" - } - - `, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, attName, capacity, iops, autoDelete, volName) -} diff --git a/ibm/resource_ibm_is_lb.go b/ibm/resource_ibm_is_lb.go deleted file mode 100644 index 90669682b..000000000 --- a/ibm/resource_ibm_is_lb.go +++ /dev/null @@ -1,755 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isLBName = "name" - isLBStatus = "status" - isLBCrn = "crn" - isLBTags = "tags" - isLBType = "type" - isLBSubnets = "subnets" - isLBHostName = "hostname" - isLBPublicIPs = "public_ips" - isLBPrivateIPs = "private_ips" - isLBListeners = "listeners" - isLBPools = "pools" - isLBOperatingStatus = "operating_status" - isLBDeleting = "deleting" - isLBDeleted = "done" - isLBProvisioning = "provisioning" - isLBProvisioningDone = "done" - isLBResourceGroup = "resource_group" - isLBProfile = "profile" - isLBRouteMode = "route_mode" - isLBLogging = "logging" - isLBSecurityGroups = "security_groups" - isLBSecurityGroupsSupported = "security_group_supported" -) - -func resourceIBMISLB() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISLBCreate, - Read: resourceIBMISLBRead, - Update: resourceIBMISLBUpdate, - Delete: resourceIBMISLBDelete, - Exists: resourceIBMISLBExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - }, - - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceRouteModeValidate(diff) - }), - ), - - Schema: map[string]*schema.Schema{ - - isLBName: { - Type: schema.TypeString, - Required: true, - ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_lb", isLBName), - Description: "Load Balancer name", - }, - - isLBType: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Default: "public", - ValidateFunc: InvokeValidator("ibm_is_lb", isLBType), - Description: "Load Balancer type", - }, - - isLBStatus: { - Type: schema.TypeString, - Computed: true, - }, - - isLBCrn: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this Load Balancer", - }, - - isLBOperatingStatus: { - Type: schema.TypeString, - Computed: true, - }, - - isLBPublicIPs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - isLBPrivateIPs: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - isLBSubnets: { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Load Balancer subnets list", - }, - - isLBSecurityGroups: { - Type: schema.TypeSet, - Computed: true, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Load Balancer securitygroups list", - ConflictsWith: []string{isLBProfile}, - }, - - isLBSecurityGroupsSupported: { - Type: schema.TypeBool, - Computed: true, - Description: "Security Group Supported for this Load Balancer", - }, - - isLBProfile: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "The profile to use for this load balancer.", - ValidateFunc: InvokeValidator("ibm_is_lb", isLBProfile), - ConflictsWith: []string{isLBLogging}, - }, - - isLBTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_lb", "tag")}, - Set: resourceIBMVPCHash, - }, - - isLBResourceGroup: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - }, - - isLBRouteMode: { - Type: schema.TypeBool, - ForceNew: true, - Optional: true, - Default: false, - Description: "Indicates whether route mode is enabled for this load balancer", - }, - - isLBHostName: { - Type: schema.TypeString, - Computed: true, - }, - - isLBLogging: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Logging of Load Balancer", - ConflictsWith: []string{isLBProfile}, - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func resourceIBMISLBValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - lbtype := "public, private" - isLBProfileAllowedValues := "network-fixed" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isLBName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isLBType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: lbtype}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isLBProfile, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: false, - AllowedValues: isLBProfileAllowedValues}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmISLBResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb", Schema: validateSchema} - return &ibmISLBResourceValidator -} - -func resourceIBMISLBCreate(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(isLBName).(string) - subnets := d.Get(isLBSubnets).(*schema.Set) - - var isLogging bool - if lbLogging, ok := d.GetOk(isLBLogging); ok { - isLogging = lbLogging.(bool) - } - - var securityGroups *schema.Set - if sg, ok := d.GetOk(isLBSecurityGroups); ok { - securityGroups = sg.(*schema.Set) - } - - // subnets := expandStringList((d.Get(isLBSubnets).(*schema.Set)).List()) - var lbType, rg string - isPublic := true - if types, ok := d.GetOk(isLBType); ok { - lbType = types.(string) - } - - if lbType == "private" { - isPublic = false - } - - if grp, ok := d.GetOk(isLBResourceGroup); ok { - rg = grp.(string) - } - - err := lbCreate(d, meta, name, lbType, rg, subnets, isPublic, isLogging, securityGroups) - if err != nil { - return err - } - - return resourceIBMISLBRead(d, meta) -} - -func lbCreate(d *schema.ResourceData, meta interface{}, name, lbType, rg string, subnets *schema.Set, isPublic, isLogging bool, securityGroups *schema.Set) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - options := &vpcv1.CreateLoadBalancerOptions{ - IsPublic: &isPublic, - Name: &name, - } - - if routeModeBool, ok := d.GetOk(isLBRouteMode); ok { - routeMode := routeModeBool.(bool) - options.RouteMode = &routeMode - } - - if subnets.Len() != 0 { - subnetobjs := make([]vpcv1.SubnetIdentityIntf, subnets.Len()) - for i, subnet := range subnets.List() { - subnetstr := subnet.(string) - subnetobjs[i] = &vpcv1.SubnetIdentity{ - ID: &subnetstr, - } - } - options.Subnets = subnetobjs - } - - if securityGroups != nil && securityGroups.Len() != 0 { - securityGroupobjs := make([]vpcv1.SecurityGroupIdentityIntf, securityGroups.Len()) - for i, securityGroup := range securityGroups.List() { - securityGroupstr := securityGroup.(string) - securityGroupobjs[i] = &vpcv1.SecurityGroupIdentity{ - ID: &securityGroupstr, - } - } - options.SecurityGroups = securityGroupobjs - } - - if rg != "" { - options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - if _, ok := d.GetOk(isLBProfile); ok { - profile := d.Get(isLBProfile).(string) - // Construct an instance of the LoadBalancerPoolIdentityByName model - loadBalancerProfileIdentityModel := new(vpcv1.LoadBalancerProfileIdentityByName) - loadBalancerProfileIdentityModel.Name = &profile - options.Profile = loadBalancerProfileIdentityModel - } else { - - dataPath := &vpcv1.LoadBalancerLoggingDatapath{ - Active: &isLogging, - } - loadBalancerLogging := &vpcv1.LoadBalancerLogging{ - Datapath: dataPath, - } - options.Logging = loadBalancerLogging - } - - lb, response, err := sess.CreateLoadBalancer(options) - if err != nil { - return fmt.Errorf("Error while creating Load Balancer err %s\n%s", err, response) - } - d.SetId(*lb.ID) - log.Printf("[INFO] Load Balancer : %s", *lb.ID) - _, err = isWaitForLBAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isLBTags); ok || v != "" { - oldList, newList := d.GetChange(isLBTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *lb.CRN) - if err != nil { - log.Printf( - "Error on create of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMISLBRead(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - err := lbGet(d, meta, id) - if err != nil { - return err - } - - return nil -} - -func lbGet(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ - ID: &id, - } - lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Load Balancer : %s\n%s", err, response) - } - d.Set(isLBName, *lb.Name) - if *lb.IsPublic { - d.Set(isLBType, "public") - } else { - d.Set(isLBType, "private") - } - if lb.RouteMode != nil { - d.Set(isLBRouteMode, *lb.RouteMode) - } - d.Set(isLBStatus, *lb.ProvisioningStatus) - d.Set(isLBCrn, *lb.CRN) - d.Set(isLBOperatingStatus, *lb.OperatingStatus) - publicIpList := make([]string, 0) - if lb.PublicIps != nil { - for _, ip := range lb.PublicIps { - if ip.Address != nil { - pubip := *ip.Address - publicIpList = append(publicIpList, pubip) - } - } - } - d.Set(isLBPublicIPs, publicIpList) - privateIpList := make([]string, 0) - if lb.PrivateIps != nil { - for _, ip := range lb.PrivateIps { - if ip.Address != nil { - prip := *ip.Address - privateIpList = append(privateIpList, prip) - } - } - } - d.Set(isLBPrivateIPs, privateIpList) - if lb.Subnets != nil { - subnetList := make([]string, 0) - for _, subnet := range lb.Subnets { - if subnet.ID != nil { - sub := *subnet.ID - subnetList = append(subnetList, sub) - } - } - d.Set(isLBSubnets, subnetList) - } - - d.Set(isLBSecurityGroupsSupported, false) - if lb.SecurityGroups != nil { - securitygroupList := make([]string, 0) - for _, SecurityGroup := range lb.SecurityGroups { - if SecurityGroup.ID != nil { - securityGroupID := *SecurityGroup.ID - securitygroupList = append(securitygroupList, securityGroupID) - } - } - d.Set(isLBSecurityGroups, securitygroupList) - d.Set(isLBSecurityGroupsSupported, true) - } - - if lb.Profile != nil { - profile := lb.Profile - if profile.Name != nil { - d.Set(isLBProfile, *lb.Profile.Name) - } - } else { - if lb.Logging != nil && lb.Logging.Datapath != nil && lb.Logging.Datapath.Active != nil { - d.Set(isLBLogging, *lb.Logging.Datapath.Active) - } - } - - d.Set(isLBResourceGroup, *lb.ResourceGroup.ID) - d.Set(isLBHostName, *lb.Hostname) - tags, err := GetTagsUsingCRN(meta, *lb.CRN) - if err != nil { - log.Printf( - "Error on get of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) - } - d.Set(isLBTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/loadBalancers") - d.Set(ResourceName, *lb.Name) - if lb.ResourceGroup != nil { - d.Set(ResourceGroupName, lb.ResourceGroup.Name) - } - return nil -} - -func resourceIBMISLBUpdate(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - name := "" - isLogging := false - hasChanged := false - hasChangedLog := false - var remove, add []string - hasChangedSecurityGroups := false - - if d.HasChange(isLBName) { - name = d.Get(isLBName).(string) - hasChanged = true - } - if d.HasChange(isLBLogging) { - isLogging = d.Get(isLBLogging).(bool) - hasChangedLog = true - } - if d.HasChange(isLBSecurityGroups) { - o, n := d.GetChange(isLBSecurityGroups) - oSecurityGroups := o.(*schema.Set) - nSecurityGroups := n.(*schema.Set) - remove = expandStringList(oSecurityGroups.Difference(nSecurityGroups).List()) - add = expandStringList(nSecurityGroups.Difference(oSecurityGroups).List()) - hasChangedSecurityGroups = true - } - - err := lbUpdate(d, meta, id, name, hasChanged, isLogging, hasChangedLog, hasChangedSecurityGroups, remove, add) - if err != nil { - return err - } - - return resourceIBMISLBRead(d, meta) -} - -func lbUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool, isLogging bool, hasChangedLog bool, hasChangedSecurityGroups bool, remove, add []string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - if d.HasChange(isLBTags) { - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ - ID: &id, - } - lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) - if err != nil { - return fmt.Errorf("Error getting Load Balancer : %s\n%s", err, response) - } - oldList, newList := d.GetChange(isLBTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *lb.CRN) - if err != nil { - log.Printf( - "Error on update of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) - } - } - if hasChanged { - updateLoadBalancerOptions := &vpcv1.UpdateLoadBalancerOptions{ - ID: &id, - } - loadBalancerPatchModel := &vpcv1.LoadBalancerPatch{ - Name: &name, - } - loadBalancerPatch, err := loadBalancerPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerPatch: %s", err) - } - updateLoadBalancerOptions.LoadBalancerPatch = loadBalancerPatch - - _, response, err := sess.UpdateLoadBalancer(updateLoadBalancerOptions) - if err != nil { - return fmt.Errorf("Error Updating vpc Load Balancer : %s\n%s", err, response) - } - } - if hasChangedLog { - updateLoadBalancerOptions := &vpcv1.UpdateLoadBalancerOptions{ - ID: &id, - } - dataPath := &vpcv1.LoadBalancerLoggingDatapath{ - Active: &isLogging, - } - loadBalancerLogging := &vpcv1.LoadBalancerLogging{ - Datapath: dataPath, - } - loadBalancerPatchModel := &vpcv1.LoadBalancerPatch{ - Logging: loadBalancerLogging, - } - loadBalancerPatch, err := loadBalancerPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerPatch: %s", err) - } - updateLoadBalancerOptions.LoadBalancerPatch = loadBalancerPatch - - _, response, err := sess.UpdateLoadBalancer(updateLoadBalancerOptions) - if err != nil { - return fmt.Errorf("Error Updating vpc Load Balancer : %s\n%s", err, response) - } - } - - if hasChangedSecurityGroups { - if len(add) > 0 { - for _, d := range add { - createSecurityGroupTargetBindingOptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{} - createSecurityGroupTargetBindingOptions.SecurityGroupID = &d - createSecurityGroupTargetBindingOptions.ID = &id - _, response, err := sess.CreateSecurityGroupTargetBinding(createSecurityGroupTargetBindingOptions) - if err != nil { - return fmt.Errorf("Error while creating Security Group Target Binding %s\n%s", err, response) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ - SecurityGroupID: &d, - ID: &id, - } - _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - continue - } - return fmt.Errorf("Error Getting Security Group Target for this load balancer (%s): %s\n%s", d, err, response) - } - deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(d, id) - response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) - if err != nil { - return fmt.Errorf("Error Deleting Security Group Target for this load balancer : %s\n%s", err, response) - } - } - } - } - return nil -} - -func resourceIBMISLBDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - err := lbDelete(d, meta, id) - if err != nil { - return err - } - - d.SetId("") - return nil -} - -func lbDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ - ID: &id, - } - _, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting vpc load balancer(%s): %s\n%s", id, err, response) - } - - deleteLoadBalancerOptions := &vpcv1.DeleteLoadBalancerOptions{ - ID: &id, - } - response, err = sess.DeleteLoadBalancer(deleteLoadBalancerOptions) - if err != nil { - return fmt.Errorf("Error Deleting vpc load balancer : %s\n%s", err, response) - } - _, err = isWaitForLBDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func isWaitForLBDeleted(lbc *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isLBDeleting}, - Target: []string{isLBDeleted, "failed"}, - Refresh: isLBDeleteRefreshFunc(lbc, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isLBDeleteRefreshFunc(lbc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ - ID: &id, - } - lb, response, err := lbc.GetLoadBalancer(getLoadBalancerOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return lb, isLBDeleted, nil - } - return nil, "failed", fmt.Errorf("The vpc load balancer %s failed to delete: %s\n%s", id, err, response) - } - return lb, isLBDeleting, nil - } -} - -func resourceIBMISLBExists(d *schema.ResourceData, meta interface{}) (bool, error) { - id := d.Id() - - exists, err := lbExists(d, meta, id) - return exists, err - -} - -func lbExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ - ID: &id, - } - _, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting vpc load balancer: %s\n%s", err, response) - } - return true, nil -} - -func isWaitForLBAvailable(sess *vpcv1.VpcV1, lbId string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for load balancer (%s) to be available.", lbId) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isLBProvisioning, "update_pending"}, - Target: []string{isLBProvisioningDone, ""}, - Refresh: isLBRefreshFunc(sess, lbId), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isLBRefreshFunc(sess *vpcv1.VpcV1, lbId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - getlboptions := &vpcv1.GetLoadBalancerOptions{ - ID: &lbId, - } - lb, response, err := sess.GetLoadBalancer(getlboptions) - if err != nil { - return nil, "", fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) - } - - if *lb.ProvisioningStatus == "active" || *lb.ProvisioningStatus == "failed" { - return lb, isLBProvisioningDone, nil - } - - return lb, isLBProvisioning, nil - } -} diff --git a/ibm/resource_ibm_is_lb_listener_test.go b/ibm/resource_ibm_is_lb_listener_test.go deleted file mode 100644 index 5dd3ccd34..000000000 --- a/ibm/resource_ibm_is_lb_listener_test.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISLBListener_basic(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) - lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) - - protocol1 := "http" - port1 := "8080" - - protocol2 := "tcp" - port2 := "9080" - - connLimit := "100" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBListenerDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBListenerConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", lbname), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "port", port1), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "accept_proxy_protocol", "true"), - ), - }, - - { - Config: testAccCheckIBMISLBListenerConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port2, protocol2, connLimit), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "port", port2), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol2), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "connection_limit", connLimit), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "accept_proxy_protocol", "false"), - ), - }, - }, - }) -} -func TestAccIBMISNLBRouteModeListener_basic(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) - lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) - - protocol1 := "tcp" - port1 := "1" - port2 := "65535" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBListenerDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISNLBRouteModeListenerConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", lbname), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "type", "private"), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "route_mode", "true"), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "port", port1), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "port_min", port1), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "port_max", port2), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), - ), - }, - }, - }) -} - -func TestAccIBMISLBListenerHttpRedirect_basic(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) - lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) - - protocol1 := "https" - port1 := "9086" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBListenerDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBListenerHttpsRedirectConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", lbname), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_status_code", "301"), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", "/example?doc=geta"), - ), - }, - { - Config: testAccCheckIBMISLBListenerHttpsRedirectConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", lbname), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_status_code", "303"), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", "/example?doc=updated"), - ), - }, - { - Config: testAccCheckIBMISLBListenerHttpsRedirectConfigRemove(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", lbname), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", ""), - resource.TestCheckResourceAttr( - "ibm_is_lb_listener.lb_listener2", "https_redirect_listener", ""), - ), - }, - }, - }) -} - -func testAccCheckIBMISLBListenerDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_lb_listener" { - continue - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - lbID := parts[0] - lbListenerID := parts[1] - getlblptions := &vpcv1.GetLoadBalancerListenerOptions{ - LoadBalancerID: &lbID, - ID: &lbListenerID, - } - _, _, err1 := sess.GetLoadBalancerListener(getlblptions) - if err1 == nil { - return fmt.Errorf("LB Listener still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISLBListenerExists(n, LBListener string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - lbID := parts[0] - lbListenerID := parts[1] - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getlblptions := &vpcv1.GetLoadBalancerListenerOptions{ - LoadBalancerID: &lbID, - ID: &lbListenerID, - } - foundLBListener, _, err := sess.GetLoadBalancerListener(getlblptions) - if err != nil { - return err - } - LBListener = *foundLBListener.ID - - return nil - } -} - -func testAccCheckIBMISLBListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_listener" "testacc_lb_listener" { - lb = "${ibm_is_lb.testacc_LB.id}" - port = %s - protocol = "%s" - accept_proxy_protocol = true - }`, vpcname, subnetname, zone, cidr, lbname, port, protocol) - -} - -func testAccCheckIBMISLBListenerHttpsRedirectConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_listener" "lb_listener1"{ - lb = ibm_is_lb.testacc_LB.id - port = "9086" - protocol = "https" - certificate_instance="%s" - } - - resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.testacc_LB.id - port = "9087" - protocol = "http" - https_redirect_listener = ibm_is_lb_listener.lb_listener1.listener_id - https_redirect_status_code = 301 - https_redirect_uri = "/example?doc=geta" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance) - -} - -func testAccCheckIBMISLBListenerHttpsRedirectConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_listener" "lb_listener1"{ - lb = ibm_is_lb.testacc_LB.id - port = "9086" - protocol = "https" - certificate_instance="%s" - } - - resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.testacc_LB.id - port = "9087" - protocol = "http" - https_redirect_listener = ibm_is_lb_listener.lb_listener1.listener_id - https_redirect_status_code = 303 - https_redirect_uri = "/example?doc=updated" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance) - -} - -func testAccCheckIBMISLBListenerHttpsRedirectConfigRemove(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_listener" "lb_listener1"{ - lb = ibm_is_lb.testacc_LB.id - port = "9086" - protocol = "https" - certificate_instance="%s" - } - - resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.testacc_LB.id - port = "9087" - protocol = "http" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance) - -} -func testAccCheckIBMISNLBRouteModeListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - profile = "network-fixed" - route_mode = true - type = "private" - } - resource "ibm_is_lb_listener" "testacc_lb_listener" { - lb = "${ibm_is_lb.testacc_LB.id}" - port = %s - protocol = "%s" -}`, vpcname, subnetname, zone, cidr, lbname, port, protocol) - -} - -func testAccCheckIBMISLBListenerConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol, connLimit string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_listener" "testacc_lb_listener" { - lb = "${ibm_is_lb.testacc_LB.id}" - port = %s - protocol = "%s" - connection_limit = %s - accept_proxy_protocol = false -}`, vpcname, subnetname, zone, cidr, lbname, port, protocol, connLimit) - -} diff --git a/ibm/resource_ibm_is_lb_pool_member_test.go b/ibm/resource_ibm_is_lb_pool_member_test.go deleted file mode 100644 index 3ec12ed7a..000000000 --- a/ibm/resource_ibm_is_lb_pool_member_test.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISLBPoolMember_basic(t *testing.T) { - var lb string - - vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) - poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) - port := "8080" - port1 := "9000" - address := "127.0.0.1" - address1 := "192.168.0.1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBPoolMemberDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, port, address), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_lb_mem", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_lb_mem", "port", port), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_lb_mem", "target_address", address), - ), - }, - - { - Config: testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, port1, address1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_lb_mem", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_lb_mem", "port", port1), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_lb_mem", "target_address", address1), - ), - }, - }, - }) -} - -func TestAccIBMISLBPoolMember_basic_network(t *testing.T) { - var lb string - - vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) - nlbPoolName := fmt.Sprintf("tfnlbpoolc%d", acctest.RandIntRange(10, 100)) - - nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) - nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) - - sshname := "terraform-test-ssh-key" - vsiName := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBPoolMemberDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBPoolMemberIDConfig( - vpcname, subnetname, ISZoneName, ISCIDR, sshname, IsImageName, - vsiName, nlbName, nlbPoolName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_nlb_mem", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_nlb_mem", "weight", "20"), - ), - }, - { - Config: testAccCheckIBMISLBPoolMemberIDConfig( - vpcname, subnetname, ISZoneName, ISCIDR, sshname, IsImageName, - vsiName, nlbName1, nlbPoolName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_nlb_mem", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb_pool_member.testacc_nlb_mem", "port", "8080"), - ), - }, - }, - }) -} - -func testAccCheckIBMISLBPoolMemberDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_lb_pool_member" { - continue - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - lbID := parts[0] - lbPoolID := parts[1] - lbPoolMemID := parts[2] - getlbpmoptions := &vpcv1.GetLoadBalancerPoolMemberOptions{ - LoadBalancerID: &lbID, - PoolID: &lbPoolID, - ID: &lbPoolMemID, - } - _, _, err1 := sess.GetLoadBalancerPoolMember(getlbpmoptions) - - if err1 == nil { - return fmt.Errorf("LB Pool member still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISLBPoolMemberExists(n, lbPoolMember string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - lbID := parts[0] - lbPoolID := parts[1] - lbPoolMemID := parts[2] - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getlbpmoptions := &vpcv1.GetLoadBalancerPoolMemberOptions{ - LoadBalancerID: &lbID, - PoolID: &lbPoolID, - ID: &lbPoolMemID, - } - foundLBPoolMember, _, err := sess.GetLoadBalancerPoolMember(getlbpmoptions) - if err != nil { - return err - } - lbPoolMember = *foundLBPoolMember.ID - - return nil - } -} - -func testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, zone, cidr, name, poolName, port, address string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - } - resource "ibm_is_lb_pool" "testacc_lb_pool" { - name = "%s" - lb = "${ibm_is_lb.testacc_LB.id}" - algorithm = "round_robin" - protocol = "http" - health_delay= 45 - health_retries = 5 - health_timeout = 30 - health_type = "tcp" - } - resource "ibm_is_lb_pool_member" "testacc_lb_mem" { - lb = "${ibm_is_lb.testacc_LB.id}" - pool = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" - port = "%s" - target_address = "%s" -}`, vpcname, subnetname, zone, cidr, name, poolName, port, address) -} - -func testAccCheckIBMISLBPoolMemberIDConfig(vpcname, subnetname, zone, cidr, sshname, - isImageName, vsiName, nlbName, nlbPoolName string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - data "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - } - data "ibm_is_image" "ds_image" { - name = "%s" - } - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = data.ibm_is_image.ds_image.id - profile = "%s" - primary_network_interface { - port_speed = "100" - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [data.ibm_is_ssh_key.testacc_sshkey.id] - } - resource "ibm_is_lb" "testacc_NLB" { - name = "%s" - subnets = ["${ibm_is_subnet.testacc_subnet.id}"] - profile = "network-fixed" - } - resource "ibm_is_lb_pool" "testacc_nlb_pool" { - name = "%s" - lb = "${ibm_is_lb.testacc_NLB.id}" - algorithm = "weighted_round_robin" - protocol = "tcp" - health_delay = 60 - health_retries = 5 - health_timeout = 30 - health_type = "tcp" - } - resource "ibm_is_lb_pool_member" "testacc_nlb_mem" { - lb = "${ibm_is_lb.testacc_NLB.id}" - pool = "${element(split("/",ibm_is_lb_pool.testacc_nlb_pool.id),1)}" - port = 8080 - weight = 20 - target_id = "${ibm_is_instance.testacc_instance.id}" - } -`, vpcname, subnetname, zone, cidr, sshname, isImageName, vsiName, - instanceProfileName, zone, nlbName, nlbPoolName) -} diff --git a/ibm/resource_ibm_is_lb_test.go b/ibm/resource_ibm_is_lb_test.go deleted file mode 100644 index ddc4e765f..000000000 --- a/ibm/resource_ibm_is_lb_test.go +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISLB_basic(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBConfig(vpcname, subnetname, ISZoneName, ISCIDR, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name), - resource.TestCheckResourceAttrSet( - "ibm_is_lb.testacc_LB", "hostname"), - ), - }, - - { - Config: testAccCheckIBMISLBConfig(vpcname, subnetname, ISZoneName, ISCIDR, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name1), - ), - }, - }, - }) -} - -func TestAccIBMISLB_basic_logging(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBLoggingCongig(vpcname, subnetname, ISZoneName, ISCIDR, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "logging", "true"), - ), - }, - }, - }) -} - -func TestAccIBMISLB_basic_securityGroups(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) - securityGroup := fmt.Sprintf("tflbsecuritygroup%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISLBSecurityGroupConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, securityGroup), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "logging", "false"), - ), - }, - }, - }) -} - -func TestAccIBMISLB_basic_network(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) - nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, ISZoneName, ISCIDR, nlbName), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "name", nlbName), - resource.TestCheckResourceAttrSet( - "ibm_is_lb.testacc_NLB", "hostname"), - ), - }, - - { - Config: testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, ISZoneName, ISCIDR, nlbName1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "name", nlbName1), - ), - }, - }, - }) -} - -func TestAccIBMISLB_basic_network_vnf(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) - nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) - nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) - routeModeTrue := true - routeModeFalse := false - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, ISZoneName, ISCIDR, nlbName, routeModeTrue), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "route_mode", fmt.Sprintf("%t", routeModeTrue)), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "profile", "network-fixed"), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "type", "private"), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "name", nlbName), - resource.TestCheckResourceAttrSet( - "ibm_is_lb.testacc_NLB", "hostname"), - ), - }, - - { - Config: testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, ISZoneName, ISCIDR, nlbName1, routeModeFalse), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "route_mode", fmt.Sprintf("%t", routeModeFalse)), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "profile", "network-fixed"), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "type", "private"), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_NLB", "name", nlbName1), - ), - }, - }, - }) -} - -func TestAccIBMISLB_basic_private(t *testing.T) { - var lb string - vpcname := fmt.Sprintf("tflbt-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tflb-create-name-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISLBDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, ISZoneName, ISCIDR, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name), - ), - }, - - { - Config: testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, ISZoneName, ISCIDR, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), - resource.TestCheckResourceAttr( - "ibm_is_lb.testacc_LB", "name", name1), - ), - }, - }, - }) -} - -func testAccCheckIBMISLBDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_lb" { - continue - } - - getlboptions := &vpcv1.GetLoadBalancerOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetLoadBalancer(getlboptions) - if err == nil { - return fmt.Errorf("LB still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISLBExists(n, lb string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getlboptions := &vpcv1.GetLoadBalancerOptions{ - ID: &rs.Primary.ID, - } - foundLB, _, err := sess.GetLoadBalancer(getlboptions) - if err != nil { - return err - } - lb = *foundLB.ID - - return nil - } -} - -func testAccCheckIBMISLBConfig(vpcname, subnetname, zone, cidr, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] -}`, vpcname, subnetname, zone, cidr, name) - -} - -func testAccCheckIBMISLBLoggingCongig(vpcname, subnetname, zone, cidr, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - logging = true -}`, vpcname, subnetname, zone, cidr, name) - -} - -func testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, zone, cidr, nlbName string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_NLB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - profile = "network-fixed" - }`, vpcname, subnetname, zone, cidr, nlbName) - -} - -func testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, zone, cidr, nlbName string, routeMode bool) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - resource "ibm_is_lb" "testacc_NLB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - profile = "network-fixed" - route_mode = %t - type = "private" - }`, vpcname, subnetname, zone, nlbName, routeMode) - -} - -func testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, zone, cidr, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - type = "private" -}`, vpcname, subnetname, zone, cidr, name) - -} - -func testAccCheckIBMISLBSecurityGroupConfig(vpcname, subnetname, zone, cidr, name, securityGroup string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_security_group" "testacc_security_group" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - } - resource "ibm_is_lb" "testacc_LB" { - name = "%s" - subnets = [ibm_is_subnet.testacc_subnet.id] - security_groups = [ibm_is_security_group.testacc_security_group.id] - logging = false -}`, vpcname, subnetname, zone, cidr, securityGroup, name) - -} diff --git a/ibm/resource_ibm_is_security_group.go b/ibm/resource_ibm_is_security_group.go deleted file mode 100644 index 5ba5ad27f..000000000 --- a/ibm/resource_ibm_is_security_group.go +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "reflect" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isSecurityGroupName = "name" - isSecurityGroupVPC = "vpc" - isSecurityGroupRules = "rules" - isSecurityGroupResourceGroup = "resource_group" - isSecurityGroupTags = "tags" - isSecurityGroupCRN = "crn" -) - -func resourceIBMISSecurityGroup() *schema.Resource { - - return &schema.Resource{ - Create: resourceIBMISSecurityGroupCreate, - Read: resourceIBMISSecurityGroupRead, - Update: resourceIBMISSecurityGroupUpdate, - Delete: resourceIBMISSecurityGroupDelete, - Exists: resourceIBMISSecurityGroupExists, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - - isSecurityGroupName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Security group name", - ValidateFunc: InvokeValidator("ibm_is_security_group", isSecurityGroupName), - }, - isSecurityGroupVPC: { - Type: schema.TypeString, - Required: true, - Description: "Security group's resource group id", - ForceNew: true, - }, - - isSecurityGroupTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_security_group", "tag")}, - Set: resourceIBMVPCHash, - Description: "List of tags", - }, - - isSecurityGroupCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - isSecurityGroupRules: { - Type: schema.TypeList, - Computed: true, - Description: "Security Rules", - Elem: &schema.Resource{ - Schema: makeIBMISSecurityRuleSchema(), - }, - }, - - isSecurityGroupResourceGroup: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "Resource Group ID", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func resourceIBMISSecurityGroupValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isSecurityGroupName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmISSecurityGroupResourceValidator := ResourceValidator{ResourceName: "ibm_is_security_group", Schema: validateSchema} - return &ibmISSecurityGroupResourceValidator -} - -func resourceIBMISSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - vpc := d.Get(isSecurityGroupVPC).(string) - - createSecurityGroupOptions := &vpcv1.CreateSecurityGroupOptions{ - VPC: &vpcv1.VPCIdentity{ - ID: &vpc, - }, - } - var rg, name string - if grp, ok := d.GetOk(isSecurityGroupResourceGroup); ok { - rg = grp.(string) - createSecurityGroupOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - if nm, ok := d.GetOk(isSecurityGroupName); ok { - name = nm.(string) - createSecurityGroupOptions.Name = &name - } - sg, response, err := sess.CreateSecurityGroup(createSecurityGroupOptions) - if err != nil { - return fmt.Errorf("Error while creating Security Group %s\n%s", err, response) - } - d.SetId(*sg.ID) - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isSecurityGroupTags); ok || v != "" { - oldList, newList := d.GetChange(isSecurityGroupTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *sg.CRN) - if err != nil { - log.Printf( - "Error while creating Security Group tags : %s\n%s", *sg.ID, err) - } - } - return resourceIBMISSecurityGroupRead(d, meta) -} - -func resourceIBMISSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - id := d.Id() - - getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ - ID: &id, - } - group, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Security Group : %s\n%s", err, response) - } - tags, err := GetTagsUsingCRN(meta, *group.CRN) - if err != nil { - log.Printf( - "Error getting Security Group tags : %s\n%s", d.Id(), err) - } - d.Set(isSecurityGroupTags, tags) - d.Set(isSecurityGroupCRN, *group.CRN) - d.Set(isSecurityGroupName, *group.Name) - d.Set(isSecurityGroupVPC, *group.VPC.ID) - rules := make([]map[string]interface{}, 0) - if len(group.Rules) > 0 { - for _, rule := range group.Rules { - switch reflect.TypeOf(rule).String() { - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": - { - rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) - r := make(map[string]interface{}) - if rule.Code != nil { - r[isSecurityGroupRuleCode] = int(*rule.Code) - } - if rule.Type != nil { - r[isSecurityGroupRuleType] = int(*rule.Type) - } - r[isSecurityGroupRuleDirection] = *rule.Direction - r[isSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.Protocol != nil { - r[isSecurityGroupRuleProtocol] = *rule.Protocol - } - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": - { - rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) - r := make(map[string]interface{}) - r[isSecurityGroupRuleDirection] = *rule.Direction - r[isSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.Protocol != nil { - r[isSecurityGroupRuleProtocol] = *rule.Protocol - } - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": - { - rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) - r := make(map[string]interface{}) - if rule.PortMin != nil { - r[isSecurityGroupRulePortMin] = int(*rule.PortMin) - } - if rule.PortMax != nil { - r[isSecurityGroupRulePortMax] = int(*rule.PortMax) - } - r[isSecurityGroupRuleDirection] = *rule.Direction - r[isSecurityGroupRuleIPVersion] = *rule.IPVersion - if rule.Protocol != nil { - r[isSecurityGroupRuleProtocol] = *rule.Protocol - } - remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) - if ok { - if remote != nil && reflect.ValueOf(remote).IsNil() == false { - if remote.ID != nil { - r[isSecurityGroupRuleRemote] = remote.ID - } else if remote.Address != nil { - r[isSecurityGroupRuleRemote] = remote.Address - } else if remote.CIDRBlock != nil { - r[isSecurityGroupRuleRemote] = remote.CIDRBlock - } - } - } - rules = append(rules, r) - } - } - } - } - d.Set(isSecurityGroupRules, rules) - d.SetId(*group.ID) - if group.ResourceGroup != nil { - d.Set(isSecurityGroupResourceGroup, group.ResourceGroup.ID) - d.Set(ResourceGroupName, group.ResourceGroup.Name) - } - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/securityGroups") - d.Set(ResourceName, *group.Name) - d.Set(ResourceCRN, *group.CRN) - return nil -} - -func resourceIBMISSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - id := d.Id() - name := "" - hasChanged := false - - if d.HasChange(isSecurityGroupTags) { - oldList, newList := d.GetChange(isSecurityGroupTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, d.Get(isSecurityGroupCRN).(string)) - if err != nil { - log.Printf( - "Error Updating Security Group tags: %s\n%s", d.Id(), err) - } - } - - if d.HasChange(isSecurityGroupName) { - name = d.Get(isSecurityGroupName).(string) - hasChanged = true - } else { - return resourceIBMISSecurityGroupRead(d, meta) - } - - if hasChanged { - updateSecurityGroupOptions := &vpcv1.UpdateSecurityGroupOptions{ - ID: &id, - } - securityGroupPatchModel := &vpcv1.SecurityGroupPatch{ - Name: &name, - } - securityGroupPatch, err := securityGroupPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for SecurityGroupPatch: %s", err) - } - updateSecurityGroupOptions.SecurityGroupPatch = securityGroupPatch - _, response, err := sess.UpdateSecurityGroup(updateSecurityGroupOptions) - if err != nil { - return fmt.Errorf("Error Updating Security Group : %s\n%s", err, response) - } - } - return resourceIBMISSecurityGroupRead(d, meta) -} - -func resourceIBMISSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - id := d.Id() - - getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ - ID: &id, - } - _, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting Security Group (%s): %s\n%s", id, err, response) - } - - start := "" - allrecs := []vpcv1.SecurityGroupTargetReferenceIntf{} - - for { - listSecurityGroupTargetsOptions := sess.NewListSecurityGroupTargetsOptions(id) - - groups, response, err := sess.ListSecurityGroupTargets(listSecurityGroupTargetsOptions) - if err != nil || groups == nil { - return fmt.Errorf("Error Getting Security Group Targets %s\n%s", err, response) - } - if *groups.TotalCount == int64(0) { - break - } - - start = GetNext(groups.Next) - allrecs = append(allrecs, groups.Targets...) - - if start == "" { - break - } - - } - - for _, securityGroupTargetReferenceIntf := range allrecs { - if securityGroupTargetReferenceIntf != nil { - securityGroupTargetReference := securityGroupTargetReferenceIntf.(*vpcv1.SecurityGroupTargetReference) - if securityGroupTargetReference != nil && securityGroupTargetReference.ID != nil { - - deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(id, *securityGroupTargetReference.ID) - response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) - if err != nil { - return fmt.Errorf("Error Deleting Security Group Targets : %s\n%s", err, response) - } - - } - } - } - - deleteSecurityGroupOptions := &vpcv1.DeleteSecurityGroupOptions{ - ID: &id, - } - response, err = sess.DeleteSecurityGroup(deleteSecurityGroupOptions) - if err != nil { - return fmt.Errorf("Error Deleting Security Group : %s\n%s", err, response) - } - d.SetId("") - return nil -} - -func resourceIBMISSecurityGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - id := d.Id() - - getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ - ID: &id, - } - _, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting Security Group: %s\n%s", err, response) - } - return true, nil -} - -func makeIBMISSecurityRuleSchema() map[string]*schema.Schema { - return map[string]*schema.Schema{ - - isSecurityGroupRuleDirection: { - Type: schema.TypeString, - Computed: true, - Description: "Direction of traffic to enforce, either inbound or outbound", - }, - - isSecurityGroupRuleIPVersion: { - Type: schema.TypeString, - Computed: true, - Description: "IP version: ipv4", - }, - - isSecurityGroupRuleRemote: { - Type: schema.TypeString, - Computed: true, - Description: "Security group id: an IP address, a CIDR block, or a single security group identifier", - }, - - isSecurityGroupRuleType: { - Type: schema.TypeInt, - Computed: true, - }, - - isSecurityGroupRuleCode: { - Type: schema.TypeInt, - Computed: true, - }, - - isSecurityGroupRulePortMin: { - Type: schema.TypeInt, - Computed: true, - }, - - isSecurityGroupRulePortMax: { - Type: schema.TypeInt, - Computed: true, - }, - - isSecurityGroupRuleProtocol: { - Type: schema.TypeString, - Computed: true, - }, - } -} diff --git a/ibm/resource_ibm_is_security_group_target.go b/ibm/resource_ibm_is_security_group_target.go deleted file mode 100644 index ef507df1f..000000000 --- a/ibm/resource_ibm_is_security_group_target.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isSecurityGroupTargetID = "target" - isSecurityGroupResourceType = "resource_type" -) - -func resourceIBMISSecurityGroupTarget() *schema.Resource { - - return &schema.Resource{ - Create: resourceIBMISSecurityGroupTargetCreate, - Read: resourceIBMISSecurityGroupTargetRead, - Delete: resourceIBMISSecurityGroupTargetDelete, - Exists: resourceIBMISSecurityGroupTargetExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - - "security_group": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Security group id", - }, - - isSecurityGroupTargetID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "security group target identifier", - ValidateFunc: InvokeValidator("ibm_is_security_group_target", isSecurityGroupTargetID), - }, - - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Security group target name", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this Security group target", - }, - - isSecurityGroupResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Resource Type", - }, - }, - } -} - -func resourceIBMISSecurityGroupTargetValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isSecurityGroupTargetID, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^[-0-9a-z_]+$`, - MinValueLength: 1, - MaxValueLength: 64}, - ValidateSchema{ - Identifier: "security_group", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^[-0-9a-z_]+$`, - MinValueLength: 1, - MaxValueLength: 64}) - - ibmISSecurityGroupResourceValidator := ResourceValidator{ResourceName: "ibm_is_security_group_target", Schema: validateSchema} - return &ibmISSecurityGroupResourceValidator -} - -func resourceIBMISSecurityGroupTargetCreate(d *schema.ResourceData, meta interface{}) error { - - sess, err := vpcClient(meta) - if err != nil { - return err - } - - securityGroupID := d.Get("security_group").(string) - targetID := d.Get(isSecurityGroupTargetID).(string) - - createSecurityGroupTargetBindingOptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{} - createSecurityGroupTargetBindingOptions.SecurityGroupID = &securityGroupID - createSecurityGroupTargetBindingOptions.ID = &targetID - - sg, response, err := sess.CreateSecurityGroupTargetBinding(createSecurityGroupTargetBindingOptions) - if err != nil || sg == nil { - return fmt.Errorf("error while creating Security Group Target Binding %s\n%s", err, response) - } - sgtarget := sg.(*vpcv1.SecurityGroupTargetReference) - d.SetId(fmt.Sprintf("%s/%s", securityGroupID, *sgtarget.ID)) - return resourceIBMISSecurityGroupTargetRead(d, meta) -} - -func resourceIBMISSecurityGroupTargetRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := vpcClient(meta) - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - securityGroupID := parts[0] - securityGroupTargetID := parts[1] - - getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ - SecurityGroupID: &securityGroupID, - ID: &securityGroupTargetID, - } - - data, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) - if err != nil || data == nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("error getting Security Group Target : %s\n%s", err, response) - } - - target := data.(*vpcv1.SecurityGroupTargetReference) - d.Set("name", *target.Name) - d.Set("crn", target.CRN) - if target.ResourceType != nil && *target.ResourceType != "" { - d.Set(isSecurityGroupResourceType, *target.ResourceType) - } - - return nil -} - -func resourceIBMISSecurityGroupTargetDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - securityGroupID := parts[0] - securityGroupTargetID := parts[1] - - getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ - SecurityGroupID: &securityGroupID, - ID: &securityGroupTargetID, - } - _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("error Getting Security Group Targets (%s): %s\n%s", securityGroupID, err, response) - } - deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(securityGroupID, securityGroupTargetID) - response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) - if err != nil { - return fmt.Errorf("error Deleting Security Group Targets : %s\n%s", err, response) - } - d.SetId("") - return nil -} - -func resourceIBMISSecurityGroupTargetExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - securityGroupID := parts[0] - securityGroupTargetID := parts[1] - - getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ - SecurityGroupID: &securityGroupID, - ID: &securityGroupTargetID, - } - - _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return false, nil - } - return false, fmt.Errorf("error getting Security Group Target : %s\n%s", err, response) - } - return true, nil - -} diff --git a/ibm/resource_ibm_is_security_group_test.go b/ibm/resource_ibm_is_security_group_test.go deleted file mode 100644 index 4ab6e5dec..000000000 --- a/ibm/resource_ibm_is_security_group_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISSecurityGroup_basic(t *testing.T) { - var securityGroup string - - vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfsg-createname-%d", acctest.RandIntRange(10, 100)) - //name2 := fmt.Sprintf("tfsg-updatename-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISSecurityGroupDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISsecurityGroupConfig(vpcname, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup), - resource.TestCheckResourceAttr( - "ibm_is_security_group.testacc_security_group", "name", name1), - resource.TestCheckResourceAttr( - "ibm_is_security_group.testacc_security_group", "tags.#", "2"), - ), - }, - { - Config: testAccCheckIBMISsecurityGroupConfigUpdate(vpcname, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup), - resource.TestCheckResourceAttr( - "ibm_is_security_group.testacc_security_group", "name", name1), - resource.TestCheckResourceAttr( - "ibm_is_security_group.testacc_security_group", "tags.#", "1"), - ), - }, - }, - }) -} - -func testAccCheckIBMISSecurityGroupDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_security_group" { - continue - } - - getsgoptions := &vpcv1.GetSecurityGroupOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetSecurityGroup(getsgoptions) - - if err == nil { - return fmt.Errorf("securitygroup still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISSecurityGroupExists(n, securityGroupID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getsgoptions := &vpcv1.GetSecurityGroupOptions{ - ID: &rs.Primary.ID, - } - foundsecurityGroup, _, err := sess.GetSecurityGroup(getsgoptions) - if err != nil { - return err - } - securityGroupID = *foundsecurityGroup.ID - return nil - } -} - -func testAccCheckIBMISsecurityGroupConfig(vpcname, name string) string { - return fmt.Sprintf(` -resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" -} - -resource "ibm_is_security_group" "testacc_security_group" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - tags = ["Tag1", "tag2"] -}`, vpcname, name) - -} - -func testAccCheckIBMISsecurityGroupConfigUpdate(vpcname, name string) string { - return fmt.Sprintf(` -resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" -} - -resource "ibm_is_security_group" "testacc_security_group" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - tags = ["tag1"] -}`, vpcname, name) - -} diff --git a/ibm/resource_ibm_is_snapshot.go b/ibm/resource_ibm_is_snapshot.go deleted file mode 100644 index 09f39a75a..000000000 --- a/ibm/resource_ibm_is_snapshot.go +++ /dev/null @@ -1,477 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isSnapshotName = "name" - isSnapshotResourceGroup = "resource_group" - isSnapshotSourceVolume = "source_volume" - isSnapshotSourceImage = "source_image" - isSnapshotUserTags = "user_tags" - isSnapshotCRN = "crn" - isSnapshotHref = "href" - isSnapshotEncryption = "encryption" - isSnapshotEncryptionKey = "encryption_key" - isSnapshotOperatingSystem = "operating_system" - isSnapshotLCState = "lifecycle_state" - isSnapshotMinCapacity = "minimum_capacity" - isSnapshotResourceType = "resource_type" - isSnapshotSize = "size" - isSnapshotBootable = "bootable" - isSnapshotDeleting = "deleting" - isSnapshotDeleted = "deleted" - isSnapshotAvailable = "stable" - isSnapshotFailed = "failed" - isSnapshotPending = "pending" - isSnapshotSuspended = "suspended" - isSnapshotUpdating = "updating" - isSnapshotWaiting = "waiting" -) - -func resourceIBMSnapshot() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISSnapshotCreate, - Read: resourceIBMISSnapshotRead, - Update: resourceIBMISSnapshotUpdate, - Delete: resourceIBMISSnapshotDelete, - Exists: resourceIBMISSnapshotExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - - isSnapshotName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_snapshot", isSnapshotName), - Description: "Snapshot name", - }, - - isSnapshotResourceGroup: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "Resource group info", - }, - - isSnapshotSourceVolume: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Snapshot source volume", - }, - - isSnapshotSourceImage: { - Type: schema.TypeString, - Computed: true, - Description: "If present, the image id from which the data on this volume was most directly provisioned.", - }, - - isSnapshotOperatingSystem: { - Type: schema.TypeString, - Computed: true, - Description: "The globally unique name for the operating system included in this image", - }, - - isSnapshotBootable: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", - }, - - isSnapshotLCState: { - Type: schema.TypeString, - Computed: true, - Description: "Snapshot lifecycle state", - }, - isSnapshotCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - isSnapshotEncryption: { - Type: schema.TypeString, - Computed: true, - Description: "Encryption type of the snapshot", - }, - isSnapshotEncryptionKey: { - Type: schema.TypeString, - Computed: true, - Description: "A reference to the root key used to wrap the data encryption key for the source volume.", - }, - - isSnapshotHref: { - Type: schema.TypeString, - Computed: true, - Description: "URL for the snapshot", - }, - - isSnapshotMinCapacity: { - Type: schema.TypeInt, - Computed: true, - Description: "Minimum capacity of the snapshot", - }, - isSnapshotResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type of the snapshot", - }, - - isSnapshotSize: { - Type: schema.TypeInt, - Computed: true, - Description: "The size of the snapshot", - }, - }, - } -} - -func resourceIBMISSnapshotValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isSnapshotName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - ibmISSnapshotResourceValidator := ResourceValidator{ResourceName: "ibm_is_snapshot", Schema: validateSchema} - return &ibmISSnapshotResourceValidator -} - -func resourceIBMISSnapshotCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - options := &vpcv1.CreateSnapshotOptions{} - if snapshotName, ok := d.GetOk(isSnapshotName); ok { - name := snapshotName.(string) - options.Name = &name - } - if sourceVolume, ok := d.GetOk(isSnapshotSourceVolume); ok { - sv := sourceVolume.(string) - options.SourceVolume = &vpcv1.VolumeIdentity{ - ID: &sv, - } - } - if grp, ok := d.GetOk(isVPCResourceGroup); ok { - rg := grp.(string) - options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - log.Printf("[DEBUG] Snapshot create") - - snapshot, response, err := sess.CreateSnapshot(options) - if err != nil || snapshot == nil { - return fmt.Errorf("Error creating Snapshot %s\n%s", err, response) - } - - d.SetId(*snapshot.ID) - log.Printf("[INFO] Snapshot : %s", *snapshot.ID) - - _, err = isWaitForSnapshotAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - - if err != nil { - return err - } - - return resourceIBMISSnapshotRead(d, meta) -} - -func isWaitForSnapshotAvailable(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Snapshot (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isSnapshotPending}, - Target: []string{isSnapshotAvailable, isSnapshotFailed}, - Refresh: isSnapshotRefreshFunc(sess, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isSnapshotRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - return nil, isSnapshotFailed, fmt.Errorf("Error getting Snapshot : %s\n%s", err, response) - } - - if *snapshot.LifecycleState == isSnapshotAvailable { - return snapshot, *snapshot.LifecycleState, nil - } else if *snapshot.LifecycleState == isSnapshotFailed { - return snapshot, *snapshot.LifecycleState, fmt.Errorf("Snapshot (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot and attempt to create the snapshot again replacing the previous configuration", *snapshot.ID) - } - - return snapshot, isSnapshotPending, nil - } -} - -func resourceIBMISSnapshotRead(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - err := snapshotGet(d, meta, id) - if err != nil { - return err - } - return nil -} - -func snapshotGet(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Snapshot : %s\n%s", err, response) - } - - d.SetId(*snapshot.ID) - d.Set(isSnapshotName, *snapshot.Name) - d.Set(isSnapshotHref, *snapshot.Href) - d.Set(isSnapshotCRN, *snapshot.CRN) - d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) - d.Set(isSnapshotSize, *snapshot.Size) - d.Set(isSnapshotEncryption, *snapshot.Encryption) - d.Set(isSnapshotLCState, *snapshot.LifecycleState) - d.Set(isSnapshotResourceType, *snapshot.ResourceType) - d.Set(isSnapshotBootable, *snapshot.Bootable) - if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { - d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) - } - if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { - d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) - } - - if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { - d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) - } - - if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { - d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) - } - return nil -} - -func resourceIBMISSnapshotUpdate(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - name := "" - hasChanged := false - - if d.HasChange(isSnapshotName) { - name = d.Get(isSnapshotName).(string) - hasChanged = true - } - err := snapshotUpdate(d, meta, id, name, hasChanged) - if err != nil { - return err - } - return resourceIBMISSnapshotRead(d, meta) -} - -func snapshotUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - if d.HasChange(isSnapshotName) { - updateSnapshotOptions := &vpcv1.UpdateSnapshotOptions{ - ID: &id, - } - snapshotPatchModel := &vpcv1.SnapshotPatch{ - Name: &name, - } - snapshotPatch, err := snapshotPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for SnapshotPatch: %s", err) - } - updateSnapshotOptions.SnapshotPatch = snapshotPatch - _, response, err := sess.UpdateSnapshot(updateSnapshotOptions) - if err != nil { - return fmt.Errorf("Error updating Snapshot : %s\n%s", err, response) - } - _, err = isWaitForSnapshotUpdate(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - } - return nil -} - -func isWaitForSnapshotUpdate(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Snapshot (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isSnapshotUpdating}, - Target: []string{isSnapshotAvailable, isSnapshotFailed}, - Refresh: isSnapshotUpdateRefreshFunc(sess, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - return stateConf.WaitForState() -} - -func isSnapshotUpdateRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - return nil, isSnapshotFailed, fmt.Errorf("Error getting Snapshot : %s\n%s", err, response) - } - - if *snapshot.LifecycleState == isSnapshotAvailable || *snapshot.LifecycleState == isSnapshotFailed { - return snapshot, *snapshot.LifecycleState, nil - } else if *snapshot.LifecycleState == isSnapshotFailed { - return snapshot, *snapshot.LifecycleState, fmt.Errorf("Snapshot (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot and attempt to create the snapshot again replacing the previous configuration", *snapshot.ID) - } - - return snapshot, isSnapshotUpdating, nil - } -} - -func resourceIBMISSnapshotDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - err := snapshotDelete(d, meta, id) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func snapshotDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - _, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Snapshot (%s): %s\n%s", id, err, response) - } - - deleteSnapshotOptions := &vpcv1.DeleteSnapshotOptions{ - ID: &id, - } - response, err = sess.DeleteSnapshot(deleteSnapshotOptions) - if err != nil { - return fmt.Errorf("Error deleting Snapshot : %s\n%s", err, response) - } - _, err = isWaitForSnapshotDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func isWaitForSnapshotDeleted(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Snapshot (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{isSnapshotDeleting}, - Target: []string{isSnapshotDeleted, isSnapshotFailed}, - Refresh: isSnapshotDeleteRefreshFunc(sess, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isSnapshotDeleteRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] Refresh function for Snapshot delete.") - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return snapshot, isSnapshotDeleted, nil - } - return nil, isSnapshotFailed, fmt.Errorf("The Snapshot %s failed to delete: %s\n%s", id, err, response) - } - return snapshot, *snapshot.LifecycleState, nil - } -} - -func resourceIBMISSnapshotExists(d *schema.ResourceData, meta interface{}) (bool, error) { - id := d.Id() - exists, err := snapshotExists(d, meta, id) - return exists, err -} - -func snapshotExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &id, - } - _, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting Snapshot: %s\n%s", err, response) - } - return true, nil -} diff --git a/ibm/resource_ibm_is_snapshot_test.go b/ibm/resource_ibm_is_snapshot_test.go deleted file mode 100644 index 04d38400f..000000000 --- a/ibm/resource_ibm_is_snapshot_test.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISSnapshot_basic(t *testing.T) { - var snapshot string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) - name2 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISSnapshotDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), - resource.TestCheckResourceAttr( - "ibm_is_snapshot.testacc_snapshot", "name", name1), - ), - }, - { - Config: testAccCheckIBMISSnapshotConfigUpdate(vpcname, subnetname, sshname, publicKey, volname, name, name2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), - resource.TestCheckResourceAttr( - "ibm_is_snapshot.testacc_snapshot", "name", name2), - ), - }, - }, - }) -} - -func testAccCheckIBMISSnapshotDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_snapshot" { - continue - } - - getSnapshotoptions := &vpcv1.GetSnapshotOptions{ - ID: &rs.Primary.ID, - } - snapshot, _, err := sess.GetSnapshot(getSnapshotoptions) - - if err == nil && *snapshot.LifecycleState != "deleted" { - return fmt.Errorf("snapshot still exists: %s", rs.Primary.ID) - } - } - return nil -} - -func testAccCheckIBMISSnapshotExists(n, sID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getSnapshotoptions := &vpcv1.GetSnapshotOptions{ - ID: &rs.Primary.ID, - } - snapshotID, _, err := sess.GetSnapshot(getSnapshotoptions) - if err != nil { - return err - } - sID = *snapshotID.ID - return nil - } -} - -func testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - } - resource "ibm_is_snapshot" "testacc_snapshot" { - name = "%s" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id -}`, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, sname) - -} - -func testAccCheckIBMISSnapshotConfigUpdate(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id - name = "eth1" - } - } - resource "ibm_is_snapshot" "testacc_snapshot" { - name = "%s" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id - } -`, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, sname) - -} diff --git a/ibm/resource_ibm_is_ssh_key.go b/ibm/resource_ibm_is_ssh_key.go deleted file mode 100644 index 9205ded07..000000000 --- a/ibm/resource_ibm_is_ssh_key.go +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isKeyName = "name" - IsKeyCRN = "crn" - isKeyPublicKey = "public_key" - isKeyType = "type" - isKeyFingerprint = "fingerprint" - isKeyLength = "length" - isKeyTags = "tags" - isKeyResourceGroup = "resource_group" -) - -func resourceIBMISSSHKey() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISSSHKeyCreate, - Read: resourceIBMISSSHKeyRead, - Update: resourceIBMISSSHKeyUpdate, - Delete: resourceIBMISSSHKeyDelete, - Exists: resourceIBMISSSHKeyExists, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - isKeyName: { - Type: schema.TypeString, - Required: true, - ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_security_group", isKeyName), - Description: "SSH Key name", - }, - - isKeyPublicKey: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "SSH Public key data", - }, - - isKeyType: { - Type: schema.TypeString, - Computed: true, - Description: "Key type", - }, - - isKeyFingerprint: { - Type: schema.TypeString, - Computed: true, - Description: "SSH key Fingerprint info", - }, - - isKeyLength: { - Type: schema.TypeInt, - Computed: true, - Description: "SSH key Length", - }, - isKeyTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_ssh_key", "tag")}, - Set: resourceIBMVPCHash, - Description: "List of tags for SSH key", - }, - - isKeyResourceGroup: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - Description: "Resource group ID", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - IsKeyCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func resourceIBMISSHKeyValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isKeyName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmISSSHKeyResourceValidator := ResourceValidator{ResourceName: "ibm_is_ssh_key", Schema: validateSchema} - return &ibmISSSHKeyResourceValidator -} - -func resourceIBMISSSHKeyCreate(d *schema.ResourceData, meta interface{}) error { - - log.Printf("[DEBUG] Key create") - name := d.Get(isKeyName).(string) - publickey := d.Get(isKeyPublicKey).(string) - - err := keyCreate(d, meta, name, publickey) - if err != nil { - return err - } - return resourceIBMISSSHKeyRead(d, meta) -} - -func keyCreate(d *schema.ResourceData, meta interface{}, name, publickey string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - options := &vpcv1.CreateKeyOptions{ - PublicKey: &publickey, - Name: &name, - } - - if rgrp, ok := d.GetOk(isKeyResourceGroup); ok { - rg := rgrp.(string) - options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - key, response, err := sess.CreateKey(options) - if err != nil { - return fmt.Errorf("[DEBUG] Create SSH Key %s\n%s", err, response) - } - d.SetId(*key.ID) - log.Printf("[INFO] Key : %s", *key.ID) - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isKeyTags); ok || v != "" { - oldList, newList := d.GetChange(isKeyTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *key.CRN) - if err != nil { - log.Printf( - "Error on create of vpc SSH Key (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMISSSHKeyRead(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - - err := keyGet(d, meta, id) - if err != nil { - return err - } - return nil -} - -func keyGet(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - options := &vpcv1.GetKeyOptions{ - ID: &id, - } - key, response, err := sess.GetKey(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting SSH Key (%s): %s\n%s", id, err, response) - } - d.Set(isKeyName, *key.Name) - d.Set(isKeyPublicKey, *key.PublicKey) - d.Set(isKeyType, *key.Type) - d.Set(isKeyFingerprint, *key.Fingerprint) - d.Set(isKeyLength, *key.Length) - tags, err := GetTagsUsingCRN(meta, *key.CRN) - if err != nil { - log.Printf( - "Error on get of vpc SSH Key (%s) tags: %s", d.Id(), err) - } - d.Set(isKeyTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/compute/sshKeys") - d.Set(ResourceName, *key.Name) - d.Set(ResourceCRN, *key.CRN) - d.Set(IsKeyCRN, *key.CRN) - if key.ResourceGroup != nil { - d.Set(ResourceGroupName, *key.ResourceGroup.Name) - d.Set(isKeyResourceGroup, *key.ResourceGroup.ID) - } - return nil -} - -func resourceIBMISSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - name := "" - hasChanged := false - - if d.HasChange(isKeyName) { - name = d.Get(isKeyName).(string) - hasChanged = true - } - - err := keyUpdate(d, meta, id, name, hasChanged) - if err != nil { - return err - } - return resourceIBMISSSHKeyRead(d, meta) -} - -func keyUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - if d.HasChange(isKeyTags) { - options := &vpcv1.GetKeyOptions{ - ID: &id, - } - key, response, err := sess.GetKey(options) - if err != nil { - return fmt.Errorf("Error getting SSH Key : %s\n%s", err, response) - } - oldList, newList := d.GetChange(isKeyTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *key.CRN) - if err != nil { - log.Printf( - "Error on update of resource vpc SSH Key (%s) tags: %s", id, err) - } - } - if hasChanged { - options := &vpcv1.UpdateKeyOptions{ - ID: &id, - } - keyPatchModel := &vpcv1.KeyPatch{ - Name: &name, - } - keyPatch, err := keyPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for KeyPatch: %s", err) - } - options.KeyPatch = keyPatch - _, response, err := sess.UpdateKey(options) - if err != nil { - return fmt.Errorf("Error updating vpc SSH Key: %s\n%s", err, response) - } - } - return nil -} - -func resourceIBMISSSHKeyDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - err := keyDelete(d, meta, id) - if err != nil { - return err - } - return nil -} - -func keyDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getKeyOptions := &vpcv1.GetKeyOptions{ - ID: &id, - } - _, response, err := sess.GetKey(getKeyOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error getting SSH Key (%s): %s\n%s", id, err, response) - } - - options := &vpcv1.DeleteKeyOptions{ - ID: &id, - } - response, err = sess.DeleteKey(options) - if err != nil { - return fmt.Errorf("Error deleting SSH Key : %s\n%s", err, response) - } - d.SetId("") - return nil -} - -func resourceIBMISSSHKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - id := d.Id() - - exists, err := keyExists(d, meta, id) - return exists, err -} - -func keyExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - options := &vpcv1.GetKeyOptions{ - ID: &id, - } - _, response, err := sess.GetKey(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting SSH Key: %s\n%s", err, response) - } - return true, nil -} diff --git a/ibm/resource_ibm_is_ssh_key_test.go b/ibm/resource_ibm_is_ssh_key_test.go deleted file mode 100644 index 75ea80057..000000000 --- a/ibm/resource_ibm_is_ssh_key_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISSSHKey_basic(t *testing.T) { - var key string - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - name := fmt.Sprintf("tfssh-createname-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: checkKeyDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISKeyConfig(publicKey, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISKeyExists("ibm_is_ssh_key.isExampleKey", key), - resource.TestCheckResourceAttr( - "ibm_is_ssh_key.isExampleKey", "name", name), - ), - }, - }, - }) -} - -func checkKeyDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_ssh_key" { - continue - } - - getkeyoptions := &vpcv1.GetKeyOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetKey(getkeyoptions) - if err == nil { - return fmt.Errorf("key still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISKeyExists(n, keyID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getkeyoptions := &vpcv1.GetKeyOptions{ - ID: &rs.Primary.ID, - } - foundkey, _, err := sess.GetKey(getkeyoptions) - if err != nil { - return err - } - keyID = *foundkey.ID - return nil - } -} - -func testAccCheckIBMISKeyConfig(publicKey, name string) string { - return fmt.Sprintf(` - resource "ibm_is_ssh_key" "isExampleKey" { - name = "%s" - public_key = "%s" - } - `, name, publicKey) -} diff --git a/ibm/resource_ibm_is_subnet_reserved_ip.go b/ibm/resource_ibm_is_subnet_reserved_ip.go deleted file mode 100644 index aa92e4990..000000000 --- a/ibm/resource_ibm_is_subnet_reserved_ip.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isReservedIPProvisioning = "provisioning" - isReservedIPProvisioningDone = "done" - isReservedIP = "reserved_ip" - isReservedIPTarget = "target" -) - -func resourceIBMISReservedIP() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISReservedIPCreate, - Read: resourceIBMISReservedIPRead, - Update: resourceIBMISReservedIPUpdate, - Delete: resourceIBMISReservedIPDelete, - Exists: resourceIBMISReservedIPExists, - Importer: &schema.ResourceImporter{}, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - /* - Request Parameters - ================== - These are mandatory req parameters - */ - isSubNetID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The subnet identifier.", - }, - isReservedIPAutoDelete: { - Type: schema.TypeBool, - Default: nil, - Computed: true, - Optional: true, - Description: "If set to true, this reserved IP will be automatically deleted", - }, - isReservedIPName: { - Type: schema.TypeString, - Computed: true, - Optional: true, - ValidateFunc: InvokeValidator("ibm_is_subnet_reserved_ip", isReservedIPName), - Description: "The user-defined or system-provided name for this reserved IP.", - }, - isReservedIPTarget: { - Type: schema.TypeString, - Computed: true, - Optional: true, - Description: "The unique identifier for target.", - }, - /* - Response Parameters - =================== - All of these are computed and an user doesn't need to provide - these from outside. - */ - - isReservedIPAddress: { - Type: schema.TypeString, - Computed: true, - Description: "The user-defined or system-provided name for this reserved IP.", - }, - isReservedIP: { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier of the reserved IP.", - }, - isReservedIPCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "The date and time that the reserved IP was created.", - }, - isReservedIPhref: { - Type: schema.TypeString, - Computed: true, - Description: "The URL for this reserved IP.", - }, - isReservedIPOwner: { - Type: schema.TypeString, - Computed: true, - Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", - }, - isReservedIPType: { - Type: schema.TypeString, - Computed: true, - Description: "The resource type.", - }, - }, - } -} -func resourceIBMISSubnetReservedIPValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isReservedIPName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - ibmISSubnetReservedIPCResourceValidator := ResourceValidator{ResourceName: "ibm_is_subnet_reserved_ip", Schema: validateSchema} - return &ibmISSubnetReservedIPCResourceValidator -} - -// resourceIBMISReservedIPCreate Creates a reserved IP given a subnet ID -func resourceIBMISReservedIPCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - subnetID := d.Get(isSubNetID).(string) - options := sess.NewCreateSubnetReservedIPOptions(subnetID) - - nameStr := "" - if name, ok := d.GetOk(isReservedIPName); ok { - nameStr = name.(string) - } - if nameStr != "" { - options.Name = &nameStr - } - - autoDeleteBool := d.Get(isReservedIPAutoDelete).(bool) - options.AutoDelete = &autoDeleteBool - if t, ok := d.GetOk(isReservedIPTarget); ok { - targetId := t.(string) - options.Target = &vpcv1.ReservedIPTargetPrototype{ - ID: &targetId, - } - } - rip, response, err := sess.CreateSubnetReservedIP(options) - if err != nil || response == nil || rip == nil { - return fmt.Errorf("Error creating the reserved IP: %s\n%s", err, response) - } - - // Set id for the reserved IP as combination of subnet ID and reserved IP ID - d.SetId(fmt.Sprintf("%s/%s", subnetID, *rip.ID)) - - return resourceIBMISReservedIPRead(d, meta) -} - -func resourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{}) error { - rip, err := get(d, meta) - if err != nil { - return err - } - - allIDs, err := idParts(d.Id()) - if err != nil { - return fmt.Errorf("The ID can not be split into subnet ID and reserved IP ID. %s", err) - } - subnetID := allIDs[0] - - if rip != nil { - d.Set(isReservedIPAddress, *rip.Address) - d.Set(isReservedIP, *rip.ID) - d.Set(isSubNetID, subnetID) - d.Set(isReservedIPAutoDelete, *rip.AutoDelete) - d.Set(isReservedIPCreatedAt, (*rip.CreatedAt).String()) - d.Set(isReservedIPhref, *rip.Href) - d.Set(isReservedIPName, *rip.Name) - d.Set(isReservedIPOwner, *rip.Owner) - d.Set(isReservedIPType, *rip.ResourceType) - if rip.Target != nil { - target, ok := rip.Target.(*vpcv1.ReservedIPTarget) - if ok { - d.Set(isReservedIPTarget, target.ID) - } - } - } - return nil -} - -func resourceIBMISReservedIPUpdate(d *schema.ResourceData, meta interface{}) error { - - // For updating the name - nameChanged := d.HasChange(isReservedIPName) - autoDeleteChanged := d.HasChange(isReservedIPAutoDelete) - - if nameChanged || autoDeleteChanged { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - allIDs, err := idParts(d.Id()) - if err != nil { - return err - } - subnetID := allIDs[0] - reservedIPID := allIDs[1] - - options := &vpcv1.UpdateSubnetReservedIPOptions{ - SubnetID: &subnetID, - ID: &reservedIPID, - } - - patch := new(vpcv1.ReservedIPPatch) - - if nameChanged { - name := d.Get(isReservedIPName).(string) - patch.Name = core.StringPtr(name) - } - - if autoDeleteChanged { - autoDelete := d.Get(isReservedIPAutoDelete).(bool) - patch.AutoDelete = core.BoolPtr(autoDelete) - } - - reservedIPPatch, err := patch.AsPatch() - if err != nil { - return fmt.Errorf("Error updating the reserved IP %s", err) - } - - options.ReservedIPPatch = reservedIPPatch - - _, response, err := sess.UpdateSubnetReservedIP(options) - if err != nil { - return fmt.Errorf("Error updating the reserved IP %s\n%s", err, response) - } - } - return resourceIBMISReservedIPRead(d, meta) -} - -func resourceIBMISReservedIPDelete(d *schema.ResourceData, meta interface{}) error { - - rip, err := get(d, meta) - if err != nil { - return err - } - if err == nil && rip == nil { - // If there is no such reserved IP, it can not be deleted - return nil - } - - sess, err := vpcClient(meta) - if err != nil { - return err - } - allIDs, err := idParts(d.Id()) - if err != nil { - return err - } - subnetID := allIDs[0] - reservedIPID := allIDs[1] - deleteOptions := sess.NewDeleteSubnetReservedIPOptions(subnetID, reservedIPID) - response, err := sess.DeleteSubnetReservedIP(deleteOptions) - if err != nil || response == nil { - return fmt.Errorf("Error deleting the reserverd ip %s in subnet %s, %s\n%s", reservedIPID, subnetID, err, response) - } - d.SetId("") - return nil -} - -func resourceIBMISReservedIPExists(d *schema.ResourceData, meta interface{}) (bool, error) { - rip, err := get(d, meta) - if err != nil { - return false, err - } - if err == nil && rip == nil { - return false, nil - } - return true, nil -} - -// get is a generic function that gets the reserved ip given subnet id and reserved ip -func get(d *schema.ResourceData, meta interface{}) (*vpcv1.ReservedIP, error) { - sess, err := vpcClient(meta) - if err != nil { - return nil, err - } - allIDs, err := idParts(d.Id()) - subnetID := allIDs[0] - reservedIPID := allIDs[1] - options := sess.NewGetSubnetReservedIPOptions(subnetID, reservedIPID) - rip, response, err := sess.GetSubnetReservedIP(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil, nil - } - return nil, fmt.Errorf("Error Getting Reserved IP : %s\n%s", err, response) - } - return rip, nil -} diff --git a/ibm/resource_ibm_is_subnet_reserved_ip_test.go b/ibm/resource_ibm_is_subnet_reserved_ip_test.go deleted file mode 100644 index df919bf08..000000000 --- a/ibm/resource_ibm_is_subnet_reserved_ip_test.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISSubnetReservedIPResource_basic(t *testing.T) { - var reservedIPID string - vpcName := fmt.Sprintf("tfresip-vpc-%d", acctest.RandIntRange(10, 100)) - subnetName := fmt.Sprintf("tfresip-subnet-%d", acctest.RandIntRange(10, 100)) - reservedIPName := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) - reservedIPName2 := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) - terraformTag := "ibm_is_subnet_reserved_ip.resIP1" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckisSubnetReservedIPDestroy, - Steps: []resource.TestStep{ - { - // Tests create - Config: testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, reservedIPName), - Check: resource.ComposeTestCheckFunc( - testAccCheckISSubnetReservedIPExists(terraformTag, &reservedIPID), - resource.TestCheckResourceAttr(terraformTag, isReservedIPName, reservedIPName), - ), - }, - { - // Tests Update - Config: testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, reservedIPName2), - Check: resource.ComposeTestCheckFunc( - testAccCheckISSubnetReservedIPExists(terraformTag, &reservedIPID), - resource.TestCheckResourceAttr(terraformTag, isReservedIPName, reservedIPName2), - ), - }, - }, - }) -} - -func testAccCheckisSubnetReservedIPDestroy(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_subnet_reserved_ip" { - continue - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - opt := sess.NewGetSubnetReservedIPOptions(parts[0], parts[1]) - _, response, err := sess.GetSubnetReservedIP(opt) - if err == nil { - return fmt.Errorf("Reserved IP still exists: %v", response) - } - } - return nil -} - -func testAccCheckISSubnetReservedIPExists(resIPName string, reservedIPID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[resIPName] - if !ok { - return fmt.Errorf("Not Found (reserved IP): %s", resIPName) - } - if rs.Primary.ID == "" { - return fmt.Errorf("No reserved IP ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - opt := sess.NewGetSubnetReservedIPOptions(parts[0], parts[1]) - result, response, err := sess.GetSubnetReservedIP(opt) - if err != nil { - return fmt.Errorf("Reserved IP does not exist: %s", response) - } - *reservedIPID = *result.ID - return nil - } -} - -func testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, resIPName string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "vpc1" { - name = "%s" - } - - resource "ibm_is_subnet" "subnet1" { - name = "%s" - vpc = ibm_is_vpc.vpc1.id - zone = "us-south-1" - total_ipv4_address_count = 256 - } - - resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { - name = "my-endpoint-gateway-1" - target { - name = "ibm-ntp-server" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.vpc1.id - } - - resource "ibm_is_subnet_reserved_ip" "resIP1" { - subnet = ibm_is_subnet.subnet1.id - name = "%s" - target = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id - } - `, vpcName, subnetName, resIPName) -} diff --git a/ibm/resource_ibm_is_virtual_endpoint_gateway.go b/ibm/resource_ibm_is_virtual_endpoint_gateway.go deleted file mode 100644 index cc561055b..000000000 --- a/ibm/resource_ibm_is_virtual_endpoint_gateway.go +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isVirtualEndpointGatewayName = "name" - isVirtualEndpointGatewayResourceType = "resource_type" - isVirtualEndpointGatewayCRN = "crn" - isVirtualEndpointGatewayResourceGroupID = "resource_group" - isVirtualEndpointGatewayCreatedAt = "created_at" - isVirtualEndpointGatewayIPs = "ips" - isVirtualEndpointGatewayIPsID = "id" - isVirtualEndpointGatewayIPsAddress = "address" - isVirtualEndpointGatewayIPsName = "name" - isVirtualEndpointGatewayIPsSubnet = "subnet" - isVirtualEndpointGatewayIPsResourceType = "resource_type" - isVirtualEndpointGatewayHealthState = "health_state" - isVirtualEndpointGatewayLifecycleState = "lifecycle_state" - isVirtualEndpointGatewayTarget = "target" - isVirtualEndpointGatewayTargetName = "name" - isVirtualEndpointGatewayTargetCRN = "crn" - isVirtualEndpointGatewayTargetResourceType = "resource_type" - isVirtualEndpointGatewayVpcID = "vpc" - isVirtualEndpointGatewayTags = "tags" -) - -func resourceIBMISEndpointGateway() *schema.Resource { - targetNameFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetName) - targetCRNFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetCRN) - return &schema.Resource{ - Create: resourceIBMisVirtualEndpointGatewayCreate, - Read: resourceIBMisVirtualEndpointGatewayRead, - Update: resourceIBMisVirtualEndpointGatewayUpdate, - Delete: resourceIBMisVirtualEndpointGatewayDelete, - Exists: resourceIBMisVirtualEndpointGatewayExists, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateISName, - Description: "Endpoint gateway name", - }, - isVirtualEndpointGatewayResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway resource type", - }, - isVirtualEndpointGatewayCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The CRN for this Endpoint gateway", - }, - isVirtualEndpointGatewayResourceGroupID: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - Description: "The resource group id", - }, - isVirtualEndpointGatewayCreatedAt: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway created date and time", - }, - isVirtualEndpointGatewayHealthState: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway health state", - }, - isVirtualEndpointGatewayLifecycleState: { - Type: schema.TypeString, - Computed: true, - Description: "Endpoint gateway lifecycle state", - }, - isVirtualEndpointGatewayIPs: { - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "Endpoint gateway IPs", - DiffSuppressFunc: applyOnce, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayIPsID: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The IPs id", - }, - isVirtualEndpointGatewayIPsName: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The IPs name", - }, - isVirtualEndpointGatewayIPsSubnet: { - Type: schema.TypeString, - Optional: true, - Description: "The Subnet id", - }, - isVirtualEndpointGatewayIPsResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "The VPE Resource Type", - }, - isVirtualEndpointGatewayIPsAddress: { - Type: schema.TypeString, - Computed: true, - Description: "The IP Address", - }, - }, - }, - }, - isVirtualEndpointGatewayTarget: { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Description: "Endpoint gateway target", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVirtualEndpointGatewayTargetName: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - AtLeastOneOf: []string{ - targetNameFmt, - targetCRNFmt, - }, - Description: "The target name", - }, - isVirtualEndpointGatewayTargetCRN: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - AtLeastOneOf: []string{ - targetNameFmt, - targetCRNFmt, - }, - Description: "The target crn", - }, - isVirtualEndpointGatewayTargetResourceType: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_is_virtual_endpoint_gateway", isVirtualEndpointGatewayTargetResourceType), - Description: "The target resource type", - }, - }, - }, - }, - isVirtualEndpointGatewayVpcID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The VPC id", - }, - isVirtualEndpointGatewayTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_virtual_endpoint_gateway", "tag")}, - Set: resourceIBMVPCHash, - Description: "List of tags for VPE", - }, - }, - } -} - -func resourceIBMISEndpointGatewayValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVirtualEndpointGatewayTargetResourceType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "provider_cloud_service, provider_infrastructure_service"}) - - ibmEndpointGatewayResourceValidator := ResourceValidator{ResourceName: "ibm_is_virtual_endpoint_gateway", Schema: validateSchema} - return &ibmEndpointGatewayResourceValidator -} - -func resourceIBMisVirtualEndpointGatewayCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - name := d.Get(isVirtualEndpointGatewayName).(string) - - // target opiton - targetOpt := &vpcv1.EndpointGatewayTargetPrototype{} - targetNameFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetName) - targetCRNFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetCRN) - targetResourceTypeFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetResourceType) - targetOpt.ResourceType = core.StringPtr(d.Get(targetResourceTypeFmt).(string)) - if v, ok := d.GetOk(targetNameFmt); ok { - targetOpt.Name = core.StringPtr(v.(string)) - } - if v, ok := d.GetOk(targetCRNFmt); ok { - targetOpt.CRN = core.StringPtr(v.(string)) - } - - // vpc option - vpcID := d.Get(isVirtualEndpointGatewayVpcID).(string) - vpcOpt := &vpcv1.VPCIdentity{ - ID: core.StringPtr(vpcID), - } - - // update option - opt := sess.NewCreateEndpointGatewayOptions(targetOpt, vpcOpt) - opt.SetName(name) - opt.SetTarget(targetOpt) - opt.SetVPC(vpcOpt) - - // IPs option - if ips, ok := d.GetOk(isVirtualEndpointGatewayIPs); ok { - opt.SetIps(expandIPs(ips.([]interface{}))) - } - - // Resource group option - if resourceGroup, ok := d.GetOk(isVirtualEndpointGatewayResourceGroupID); ok { - resourceGroupID := resourceGroup.(string) - - resourceGroupOpt := &vpcv1.ResourceGroupIdentity{ - ID: core.StringPtr(resourceGroupID), - } - opt.SetResourceGroup(resourceGroupOpt) - - } - result, response, err := sess.CreateEndpointGateway(opt) - if err != nil { - log.Printf("Create Endpoint Gateway failed: %v", response) - return fmt.Errorf("Create Endpoint Gateway failed %s\n%s", err, response) - } - - d.SetId(*result.ID) - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isVirtualEndpointGatewayTags); ok || v != "" { - oldList, newList := d.GetChange(isVirtualEndpointGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *result.CRN) - if err != nil { - log.Printf( - "Error on create of VPE (%s) tags: %s", d.Id(), err) - } - } - return resourceIBMisVirtualEndpointGatewayRead(d, meta) -} - -func resourceIBMisVirtualEndpointGatewayUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - if d.HasChange(isVirtualEndpointGatewayName) { - name := d.Get(isVirtualEndpointGatewayName).(string) - - // create option - endpointGatewayPatchModel := new(vpcv1.EndpointGatewayPatch) - endpointGatewayPatchModel.Name = core.StringPtr(name) - endpointGatewayPatchModelAsPatch, _ := endpointGatewayPatchModel.AsPatch() - opt := sess.NewUpdateEndpointGatewayOptions(d.Id(), endpointGatewayPatchModelAsPatch) - _, response, err := sess.UpdateEndpointGateway(opt) - if err != nil { - log.Printf("Update Endpoint Gateway failed: %v", response) - return fmt.Errorf("Update Endpoint Gateway failed : %s\n%s", err, response) - } - - } - if d.HasChange(isVirtualEndpointGatewayTags) { - opt := sess.NewGetEndpointGatewayOptions(d.Id()) - result, response, err := sess.GetEndpointGateway(opt) - if err != nil { - return fmt.Errorf("Error getting VPE: %s\n%s", err, response) - } - oldList, newList := d.GetChange(isVirtualEndpointGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *result.CRN) - if err != nil { - log.Printf( - "Error on update of VPE (%s) tags: %s", d.Id(), err) - } - } - return resourceIBMisVirtualEndpointGatewayRead(d, meta) -} - -func resourceIBMisVirtualEndpointGatewayRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - // read option - opt := sess.NewGetEndpointGatewayOptions(d.Id()) - result, response, err := sess.GetEndpointGateway(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("Get Endpoint Gateway failed: %v", response) - return fmt.Errorf("Get Endpoint Gateway failed %s\n%s", err, response) - } - d.Set(isVirtualEndpointGatewayName, result.Name) - d.Set(isVirtualEndpointGatewayHealthState, result.HealthState) - d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String()) - d.Set(isVirtualEndpointGatewayLifecycleState, result.LifecycleState) - d.Set(isVirtualEndpointGatewayResourceType, result.ResourceType) - d.Set(isVirtualEndpointGatewayCRN, result.CRN) - d.Set(isVirtualEndpointGatewayIPs, flattenIPs(result.Ips)) - d.Set(isVirtualEndpointGatewayResourceGroupID, result.ResourceGroup.ID) - d.Set(isVirtualEndpointGatewayTarget, - flattenEndpointGatewayTarget(result.Target.(*vpcv1.EndpointGatewayTarget))) - d.Set(isVirtualEndpointGatewayVpcID, result.VPC.ID) - tags, err := GetTagsUsingCRN(meta, *result.CRN) - if err != nil { - log.Printf( - "Error on get of VPE (%s) tags: %s", d.Id(), err) - } - d.Set(isVirtualEndpointGatewayTags, tags) - return nil -} - -func resourceIBMisVirtualEndpointGatewayDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - opt := sess.NewDeleteEndpointGatewayOptions(d.Id()) - response, err := sess.DeleteEndpointGateway(opt) - if err != nil { - log.Printf("Delete Endpoint Gateway failed: %v", response) - return fmt.Errorf("Delete Endpoint Gateway failed : %s\n%s", err, response) - } - return nil -} - -func resourceIBMisVirtualEndpointGatewayExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - - opt := sess.NewGetEndpointGatewayOptions(d.Id()) - _, response, err := sess.GetEndpointGateway(opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("Endpoint Gateway does not exist.") - return false, nil - } - log.Printf("Error : %s", response) - return false, err - } - return true, nil -} - -func expandIPs(ipsSet []interface{}) (ipsOptions []vpcv1.EndpointGatewayReservedIPIntf) { - ipsList := ipsSet - for _, item := range ipsList { - ips := item.(map[string]interface{}) - // IPs option - ipsID := ips[isVirtualEndpointGatewayIPsID].(string) - ipsName := ips[isVirtualEndpointGatewayIPsName].(string) - - // IPs subnet option - ipsSubnetID := ips[isVirtualEndpointGatewayIPsSubnet].(string) - - ipsSubnetOpt := &vpcv1.SubnetIdentity{ - ID: &ipsSubnetID, - } - - ipsOpt := &vpcv1.EndpointGatewayReservedIP{ - ID: core.StringPtr(ipsID), - Name: core.StringPtr(ipsName), - Subnet: ipsSubnetOpt, - } - ipsOptions = append(ipsOptions, ipsOpt) - } - return ipsOptions -} - -func flattenIPs(ipsList []vpcv1.ReservedIPReference) interface{} { - ipsListOutput := make([]interface{}, 0) - for _, item := range ipsList { - ips := make(map[string]interface{}, 0) - ips[isVirtualEndpointGatewayIPsID] = *item.ID - ips[isVirtualEndpointGatewayIPsName] = *item.Name - ips[isVirtualEndpointGatewayIPsResourceType] = *item.ResourceType - ips[isVirtualEndpointGatewayIPsAddress] = *item.Address - - ipsListOutput = append(ipsListOutput, ips) - } - return ipsListOutput -} - -func flattenEndpointGatewayTarget(target *vpcv1.EndpointGatewayTarget) interface{} { - targetSlice := []interface{}{} - targetOutput := map[string]string{} - if target == nil { - return targetOutput - } - if target.Name != nil { - targetOutput[isVirtualEndpointGatewayTargetName] = *target.Name - } - if target.CRN != nil { - targetOutput[isVirtualEndpointGatewayTargetCRN] = *target.CRN - } - if target.ResourceType != nil { - targetOutput[isVirtualEndpointGatewayTargetResourceType] = *target.ResourceType - } - targetSlice = append(targetSlice, targetOutput) - return targetSlice -} diff --git a/ibm/resource_ibm_is_virtual_endpoint_gateway_test.go b/ibm/resource_ibm_is_virtual_endpoint_gateway_test.go deleted file mode 100644 index 6608c3d8a..000000000 --- a/ibm/resource_ibm_is_virtual_endpoint_gateway_test.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISVirtualEndpointGateway_Basic(t *testing.T) { - var endpointGateway string - vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) - name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckisVirtualEndpointGatewayExists(name, &endpointGateway), - resource.TestCheckResourceAttr(name, "name", name1), - ), - }, - }, - }) -} - -func TestAccIBMISVirtualEndpointGateway_Import(t *testing.T) { - vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) - name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "name", name1), - ), - }, - { - ResourceName: name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIBMISVirtualEndpointGateway_FullySpecified(t *testing.T) { - var monitor string - vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) - name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, - Steps: []resource.TestStep{ - { - ExpectNonEmptyPlan: true, - Config: testAccCheckisVirtualEndpointGatewayConfigFullySpecified(vpcname1, subnetname1, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckisVirtualEndpointGatewayExists(name, &monitor), - resource.TestCheckResourceAttr(name, "name", name1), - ), - }, - }, - }) -} - -func TestAccIBMISVirtualEndpointGateway_CreateAfterManualDestroy(t *testing.T) { - t.Skip() - var monitorOne, monitorTwo string - vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) - name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckisVirtualEndpointGatewayExists(name, &monitorOne), - testAccisVirtualEndpointGatewayManuallyDelete(&monitorOne), - ), - }, - { - Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckisVirtualEndpointGatewayExists(name, &monitorTwo), - func(state *terraform.State) error { - if monitorOne == monitorTwo { - return fmt.Errorf("load balancer monitor id is unchanged even after we thought we deleted it ( %s )", - monitorTwo) - } - return nil - }, - ), - }, - }, - }) -} - -func testAccisVirtualEndpointGatewayManuallyDelete(tfEndpointGwID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() - if err != nil { - return err - } - tfEndpointGw := *tfEndpointGwID - opt := sess.NewDeleteEndpointGatewayOptions(tfEndpointGw) - response, err := sess.DeleteEndpointGateway(opt) - if err != nil { - return fmt.Errorf("Delete Endpoint Gateway failed: %v", response) - } - return nil - } -} - -func testAccCheckisVirtualEndpointGatewayDestroy(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_virtual_endpoint_gateway" { - continue - } - opt := sess.NewGetEndpointGatewayOptions(rs.Primary.ID) - _, response, err := sess.GetEndpointGateway(opt) - if err == nil { - return fmt.Errorf("Endpoint Gateway still exists: %v", response) - } - } - - return nil -} - -func testAccCheckisVirtualEndpointGatewayExists(n string, tfEndpointGwID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - if rs.Primary.ID == "" { - return fmt.Errorf("No endpoint gateway ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() - if err != nil { - return err - } - - opt := sess.NewGetEndpointGatewayOptions(rs.Primary.ID) - result, response, err := sess.GetEndpointGateway(opt) - if err != nil { - return fmt.Errorf("Endpoint Gateway does not exist: %s", response) - } - *tfEndpointGwID = *result.ID - return nil - } -} - -func testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1 string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default=true - } - resource "ibm_is_vpc" "testacc_vpc" { - name = "%[1]s" - resource_group = data.ibm_resource_group.test_acc.id - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%[2]s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%[3]s" - ipv4_cidr_block = "%[4]s" - resource_group = data.ibm_resource_group.test_acc.id - } - resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { - name = "%[5]s" - target { - name = "ibm-dns-server2" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.testacc_vpc.id - resource_group = data.ibm_resource_group.test_acc.id - }`, vpcname1, subnetname1, ISZoneName, ISCIDR, name1) -} - -func testAccCheckisVirtualEndpointGatewayConfigFullySpecified(vpcname1, subnetname1, name1 string) string { - return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default=true - } - resource "ibm_is_vpc" "testacc_vpc" { - name = "%[1]s" - resource_group = data.ibm_resource_group.test_acc.id - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%[2]s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%[3]s" - ipv4_cidr_block = "%[4]s" - resource_group = data.ibm_resource_group.test_acc.id - } - resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { - name = "%[5]s" - target { - name = "ibm-dns-server2" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.testacc_vpc.id - ips { - subnet = ibm_is_subnet.testacc_subnet.id - name = "test-reserved-ip1" - } - resource_group = data.ibm_resource_group.test_acc.id - }`, vpcname1, subnetname1, ISZoneName, ISCIDR, name1) -} diff --git a/ibm/resource_ibm_is_volume.go b/ibm/resource_ibm_is_volume.go deleted file mode 100644 index b5105fd64..000000000 --- a/ibm/resource_ibm_is_volume.go +++ /dev/null @@ -1,769 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - isVolumeName = "name" - isVolumeProfileName = "profile" - isVolumeZone = "zone" - isVolumeEncryptionKey = "encryption_key" - isVolumeEncryptionType = "encryption_type" - isVolumeCapacity = "capacity" - isVolumeIops = "iops" - isVolumeCrn = "crn" - isVolumeTags = "tags" - isVolumeStatus = "status" - isVolumeStatusReasons = "status_reasons" - isVolumeStatusReasonsCode = "code" - isVolumeStatusReasonsMessage = "message" - isVolumeDeleting = "deleting" - isVolumeDeleted = "done" - isVolumeProvisioning = "provisioning" - isVolumeProvisioningDone = "done" - isVolumeResourceGroup = "resource_group" - isVolumeSourceSnapshot = "source_snapshot" - isVolumeDeleteAllSnapshots = "delete_all_snapshots" -) - -func resourceIBMISVolume() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISVolumeCreate, - Read: resourceIBMISVolumeRead, - Update: resourceIBMISVolumeUpdate, - Delete: resourceIBMISVolumeDelete, - Exists: resourceIBMISVolumeExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceVolumeValidate(diff) - }), - ), - - Schema: map[string]*schema.Schema{ - - isVolumeName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_is_volume", isVolumeName), - Description: "Volume name", - }, - - isVolumeProfileName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_is_volume", isVolumeProfileName), - Description: "Volume profile name", - }, - - isVolumeZone: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Zone name", - }, - - isVolumeEncryptionKey: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Volume encryption key info", - }, - - isVolumeEncryptionType: { - Type: schema.TypeString, - Computed: true, - Description: "Volume encryption type info", - }, - - isVolumeCapacity: { - Type: schema.TypeInt, - Optional: true, - Default: 100, - ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_volume", isVolumeCapacity), - Description: "Volume capacity value", - }, - isVolumeResourceGroup: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Description: "Resource group name", - }, - isVolumeIops: { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_volume", isVolumeIops), - Description: "IOPS value for the Volume", - }, - isVolumeCrn: { - Type: schema.TypeString, - Computed: true, - Description: "CRN value for the volume instance", - }, - isVolumeStatus: { - Type: schema.TypeString, - Computed: true, - Description: "Volume status", - }, - - isVolumeStatusReasons: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - isVolumeStatusReasonsCode: { - Type: schema.TypeString, - Computed: true, - Description: "A snake case string succinctly identifying the status reason", - }, - - isVolumeStatusReasonsMessage: { - Type: schema.TypeString, - Computed: true, - Description: "An explanation of the status reason", - }, - }, - }, - }, - - isVolumeSourceSnapshot: { - Type: schema.TypeString, - Computed: true, - Description: "Identifier of the snapshot from which this volume was cloned", - }, - isVolumeDeleteAllSnapshots: { - Type: schema.TypeBool, - Optional: true, - Description: "Deletes all snapshots created from this volume", - }, - isVolumeTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_volume", "tag")}, - Set: resourceIBMVPCHash, - Description: "Tags for the volume instance", - }, - - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - }, - } -} - -func resourceIBMISVolumeValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVolumeName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVolumeProfileName, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "general-purpose, 5iops-tier, 10iops-tier, custom", - }) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVolumeCapacity, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, - MinValue: "10", - MaxValue: "16000"}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: isVolumeIops, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, - MinValue: "100", - MaxValue: "48000"}) - - ibmISVolumeResourceValidator := ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} - return &ibmISVolumeResourceValidator -} - -func resourceIBMISVolumeCreate(d *schema.ResourceData, meta interface{}) error { - - volName := d.Get(isVolumeName).(string) - profile := d.Get(isVolumeProfileName).(string) - zone := d.Get(isVolumeZone).(string) - var volCapacity int64 - if capacity, ok := d.GetOk(isVolumeCapacity); ok { - volCapacity = int64(capacity.(int)) - } else { - volCapacity = 100 - } - - err := volCreate(d, meta, volName, profile, zone, volCapacity) - if err != nil { - return err - } - - return resourceIBMISVolumeRead(d, meta) -} - -func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone string, volCapacity int64) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - options := &vpcv1.CreateVolumeOptions{ - VolumePrototype: &vpcv1.VolumePrototype{ - Name: &volName, - Capacity: &volCapacity, - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.VolumeProfileIdentity{ - Name: &profile, - }, - }, - } - volTemplate := options.VolumePrototype.(*vpcv1.VolumePrototype) - - if key, ok := d.GetOk(isVolumeEncryptionKey); ok { - encryptionKey := key.(string) - volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ - CRN: &encryptionKey, - } - } - - if rgrp, ok := d.GetOk(isVolumeResourceGroup); ok { - rg := rgrp.(string) - volTemplate.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - if i, ok := d.GetOk(isVolumeIops); ok { - iops := int64(i.(int)) - volTemplate.Iops = &iops - } - - vol, response, err := sess.CreateVolume(options) - if err != nil { - return fmt.Errorf("[DEBUG] Create volume err %s\n%s", err, response) - } - d.SetId(*vol.ID) - log.Printf("[INFO] Volume : %s", *vol.ID) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk(isVolumeTags); ok || v != "" { - oldList, newList := d.GetChange(isVolumeTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vol.CRN) - if err != nil { - log.Printf( - "Error on create of resource Volume (%s) tags: %s", d.Id(), err) - } - } - return nil -} - -func resourceIBMISVolumeRead(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - err := volGet(d, meta, id) - if err != nil { - return err - } - return nil -} - -func volGet(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - options := &vpcv1.GetVolumeOptions{ - ID: &id, - } - vol, response, err := sess.GetVolume(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting Volume (%s): %s\n%s", id, err, response) - } - d.SetId(*vol.ID) - d.Set(isVolumeName, *vol.Name) - d.Set(isVolumeProfileName, *vol.Profile.Name) - d.Set(isVolumeZone, *vol.Zone.Name) - if vol.EncryptionKey != nil { - d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) - } - if vol.Encryption != nil { - d.Set(isVolumeEncryptionType, vol.Encryption) - } - d.Set(isVolumeIops, *vol.Iops) - d.Set(isVolumeCapacity, *vol.Capacity) - d.Set(isVolumeCrn, *vol.CRN) - if vol.SourceSnapshot != nil { - d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) - } - d.Set(isVolumeStatus, *vol.Status) - //set the status reasons - if vol.StatusReasons != nil { - statusReasonsList := make([]map[string]interface{}, 0) - for _, sr := range vol.StatusReasons { - currentSR := map[string]interface{}{} - if sr.Code != nil && sr.Message != nil { - currentSR[isVolumeStatusReasonsCode] = *sr.Code - currentSR[isVolumeStatusReasonsMessage] = *sr.Message - statusReasonsList = append(statusReasonsList, currentSR) - } - } - d.Set(isVolumeStatusReasons, statusReasonsList) - } - tags, err := GetTagsUsingCRN(meta, *vol.CRN) - if err != nil { - log.Printf( - "Error on get of resource vpc volume (%s) tags: %s", d.Id(), err) - } - d.Set(isVolumeTags, tags) - controller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") - d.Set(ResourceName, *vol.Name) - d.Set(ResourceCRN, *vol.CRN) - d.Set(ResourceStatus, *vol.Status) - if vol.ResourceGroup != nil { - d.Set(ResourceGroupName, vol.ResourceGroup.Name) - d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) - } - return nil -} - -func resourceIBMISVolumeUpdate(d *schema.ResourceData, meta interface{}) error { - - id := d.Id() - name := "" - hasNameChanged := false - delete := false - - if delete_all_snapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && delete_all_snapshots.(bool) { - delete = true - } - - if d.HasChange(isVolumeName) { - name = d.Get(isVolumeName).(string) - hasNameChanged = true - } - - err := volUpdate(d, meta, id, name, hasNameChanged, delete) - if err != nil { - return err - } - return resourceIBMISVolumeRead(d, meta) -} - -func volUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasNameChanged, delete bool) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - var capacity int64 - if delete { - deleteAllSnapshots(sess, id) - } - - // tags update - if d.HasChange(isVolumeTags) { - options := &vpcv1.GetVolumeOptions{ - ID: &id, - } - vol, response, err := sess.GetVolume(options) - if err != nil { - return fmt.Errorf("Error getting Volume : %s\n%s", err, response) - } - oldList, newList := d.GetChange(isVolumeTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vol.CRN) - if err != nil { - log.Printf( - "Error on update of resource vpc volume (%s) tags: %s", id, err) - } - } - - options := &vpcv1.UpdateVolumeOptions{ - ID: &id, - } - - //name update - volumeNamePatchModel := &vpcv1.VolumePatch{} - if hasNameChanged { - volumeNamePatchModel.Name = &name - volumeNamePatch, err := volumeNamePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for volumeNamePatch: %s", err) - } - options.VolumePatch = volumeNamePatch - _, _, err = sess.UpdateVolume(options) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - } - - // profile/ iops update - if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) { - volumeProfilePatchModel := &vpcv1.VolumePatch{} - volId := d.Id() - getvoloptions := &vpcv1.GetVolumeOptions{ - ID: &volId, - } - vol, response, err := sess.GetVolume(getvoloptions) - if err != nil || vol == nil { - return fmt.Errorf("Error retrieving Volume (%s) details: %s\n%s", volId, err, response) - } - if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) < 1 { - return fmt.Errorf("Error updating Volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) - } - volAtt := &vol.VolumeAttachments[0] - insId := *volAtt.Instance.ID - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &insId, - } - instance, response, err := sess.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error retrieving Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) - } - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &insId, - Type: &actiontype, - } - _, response, err = sess.CreateInstanceAction(createinsactoptions) - if err != nil { - return fmt.Errorf("Error starting Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) - } - _, err = isWaitForInstanceAvailable(sess, insId, d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - } - if d.HasChange(isVolumeProfileName) { - profile := d.Get(isVolumeProfileName).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &profile, - } - } else if d.HasChange(isVolumeIops) { - profile := d.Get(isVolumeProfileName).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &profile, - } - iops := int64(d.Get(isVolumeIops).(int)) - volumeProfilePatchModel.Iops = &iops - } - - volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for VolumeProfilePatch: %s", err) - } - options.VolumePatch = volumeProfilePatch - _, response, err = sess.UpdateVolume(options) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - } - - // capacity update - if d.HasChange(isVolumeCapacity) { - id := d.Id() - getvolumeoptions := &vpcv1.GetVolumeOptions{ - ID: &id, - } - vol, response, err := sess.GetVolume(getvolumeoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting Volume (%s): %s\n%s", id, err, response) - } - if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].ID == "" { - return fmt.Errorf("Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) - } - insId := vol.VolumeAttachments[0].Instance.ID - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: insId, - } - instance, response, err := sess.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error retrieving Instance (%s) : %s\n%s", *insId, err, response) - } - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: insId, - Type: &actiontype, - } - _, response, err = sess.CreateInstanceAction(createinsactoptions) - if err != nil { - return fmt.Errorf("Error starting Instance (%s) : %s\n%s", *insId, err, response) - } - _, err = isWaitForInstanceAvailable(sess, *insId, d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - } - capacity = int64(d.Get(isVolumeCapacity).(int)) - volumeCapacityPatchModel := &vpcv1.VolumePatch{} - volumeCapacityPatchModel.Capacity = &capacity - - volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() - if err != nil { - return fmt.Errorf("Error calling asPatch for volumeCapacityPatch: %s", err) - } - options.VolumePatch = volumeCapacityPatch - _, response, err = sess.UpdateVolume(options) - if err != nil { - return fmt.Errorf("Error updating vpc volume: %s\n%s", err, response) - } - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - } - - return nil -} - -func resourceIBMISVolumeDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - err := volDelete(d, meta, id) - if err != nil { - return err - } - return nil -} - -func volDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getvoloptions := &vpcv1.GetVolumeOptions{ - ID: &id, - } - volDetails, response, err := sess.GetVolume(getvoloptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error getting Volume (%s): %s\n%s", id, err, response) - } - - if volDetails.VolumeAttachments != nil { - for _, volAtt := range volDetails.VolumeAttachments { - deleteVolumeAttachment := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ - InstanceID: volAtt.Instance.ID, - ID: volAtt.ID, - } - _, err := sess.DeleteInstanceVolumeAttachment(deleteVolumeAttachment) - if err != nil { - return fmt.Errorf("Error while removing volume attachment %q for instance %s: %q", *volAtt.ID, *volAtt.Instance.ID, err) - } - _, err = isWaitForInstanceVolumeDetached(sess, d, d.Id(), *volAtt.ID) - if err != nil { - return err - } - - } - } - - options := &vpcv1.DeleteVolumeOptions{ - ID: &id, - } - response, err = sess.DeleteVolume(options) - if err != nil { - return fmt.Errorf("Error deleting Volume : %s\n%s", err, response) - } - _, err = isWaitForVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - d.SetId("") - return nil -} - -func isWaitForVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isVolumeDeleting}, - Target: []string{"done", ""}, - Refresh: isVolumeDeleteRefreshFunc(vol, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - volgetoptions := &vpcv1.GetVolumeOptions{ - ID: &id, - } - vol, response, err := vol.GetVolume(volgetoptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return vol, isVolumeDeleted, nil - } - return vol, "", fmt.Errorf("Error getting Volume: %s\n%s", err, response) - } - return vol, isVolumeDeleting, err - } -} - -func resourceIBMISVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - id := d.Id() - - exists, err := volExists(d, meta, id) - return exists, err -} - -func volExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - options := &vpcv1.GetVolumeOptions{ - ID: &id, - } - _, response, err := sess.GetVolume(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error getting Volume: %s\n%s", err, response) - } - return true, nil -} - -func isWaitForVolumeAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Volume (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isVolumeProvisioning}, - Target: []string{isVolumeProvisioningDone, ""}, - Refresh: isVolumeRefreshFunc(client, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - volgetoptions := &vpcv1.GetVolumeOptions{ - ID: &id, - } - vol, response, err := client.GetVolume(volgetoptions) - if err != nil { - return nil, "", fmt.Errorf("Error getting volume: %s\n%s", err, response) - } - - if *vol.Status == "available" { - return vol, isVolumeProvisioningDone, nil - } - - return vol, isVolumeProvisioning, nil - } -} - -func deleteAllSnapshots(sess *vpcv1.VpcV1, id string) error { - delete_all_snapshots := new(vpcv1.DeleteSnapshotsOptions) - delete_all_snapshots.SourceVolumeID = &id - response, err := sess.DeleteSnapshots(delete_all_snapshots) - if err != nil { - return fmt.Errorf("Error deleting snapshots from volume %s\n%s", err, response) - } - return nil -} diff --git a/ibm/resource_ibm_is_vpc_routing_table.go b/ibm/resource_ibm_is_vpc_routing_table.go deleted file mode 100644 index 274df647c..000000000 --- a/ibm/resource_ibm_is_vpc_routing_table.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strings" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - rtID = "routing_table" - rtVpcID = "vpc" - rtName = "name" - rtRouteDirectLinkIngress = "route_direct_link_ingress" - rtRouteTransitGatewayIngress = "route_transit_gateway_ingress" - rtRouteVPCZoneIngress = "route_vpc_zone_ingress" - rtCreateAt = "created_at" - rtHref = "href" - rtIsDefault = "is_default" - rtResourceType = "resource_type" - rtLifecycleState = "lifecycle_state" - rtSubnets = "subnets" - rtDestination = "destination" - rtAction = "action" - rtNextHop = "next_hop" - rtZone = "zone" - rtOrigin = "origin" -) - -func resourceIBMISVPCRoutingTable() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISVPCRoutingTableCreate, - Read: resourceIBMISVPCRoutingTableRead, - Update: resourceIBMISVPCRoutingTableUpdate, - Delete: resourceIBMISVPCRoutingTableDelete, - Exists: resourceIBMISVPCRoutingTableExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - rtVpcID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The VPC identifier.", - }, - rtRouteDirectLinkIngress: { - Type: schema.TypeBool, - ForceNew: false, - Default: false, - Optional: true, - Description: "If set to true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", - }, - rtRouteTransitGatewayIngress: { - Type: schema.TypeBool, - ForceNew: false, - Default: false, - Optional: true, - Description: "If set to true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", - }, - rtRouteVPCZoneIngress: { - Type: schema.TypeBool, - ForceNew: false, - Default: false, - Optional: true, - Description: "If set to true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", - }, - rtName: { - Type: schema.TypeString, - Optional: true, - ForceNew: false, - Computed: true, - ValidateFunc: InvokeValidator("ibm_is_vpc_routing_table", rtName), - Description: "The user-defined name for this routing table.", - }, - rtID: { - Type: schema.TypeString, - Computed: true, - Description: "The routing table identifier.", - }, - rtHref: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table Href", - }, - rtResourceType: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table Resource Type", - }, - rtCreateAt: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table Created At", - }, - rtLifecycleState: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table Lifecycle State", - }, - rtIsDefault: { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether this is the default routing table for this VPC", - }, - rtSubnets: { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - rtName: { - Type: schema.TypeString, - Computed: true, - Description: "Subnet name", - }, - "id": { - Type: schema.TypeString, - Computed: true, - Description: "Subnet ID", - }, - }, - }, - }, - }, - } -} - -func resourceIBMISVPCRoutingTableValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - actionAllowedValues := "delegate, delegate_vpc, deliver, drop" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: rtName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: false, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: rtAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: false, - AllowedValues: actionAllowedValues}) - - ibmISVPCRoutingTableValidator := ResourceValidator{ResourceName: "ibm_is_vpc_routing_table", Schema: validateSchema} - return &ibmISVPCRoutingTableValidator -} - -func resourceIBMISVPCRoutingTableCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - vpcID := d.Get(rtVpcID).(string) - rtName := d.Get(rtName).(string) - - createVpcRoutingTableOptions := sess.NewCreateVPCRoutingTableOptions(vpcID) - createVpcRoutingTableOptions.SetName(rtName) - if _, ok := d.GetOk(rtRouteDirectLinkIngress); ok { - routeDirectLinkIngress := d.Get(rtRouteDirectLinkIngress).(bool) - createVpcRoutingTableOptions.RouteDirectLinkIngress = &routeDirectLinkIngress - } - if _, ok := d.GetOk(rtRouteTransitGatewayIngress); ok { - routeTransitGatewayIngress := d.Get(rtRouteTransitGatewayIngress).(bool) - createVpcRoutingTableOptions.RouteTransitGatewayIngress = &routeTransitGatewayIngress - } - if _, ok := d.GetOk(rtRouteVPCZoneIngress); ok { - routeVPCZoneIngress := d.Get(rtRouteVPCZoneIngress).(bool) - createVpcRoutingTableOptions.RouteVPCZoneIngress = &routeVPCZoneIngress - } - routeTable, response, err := sess.CreateVPCRoutingTable(createVpcRoutingTableOptions) - if err != nil { - log.Printf("[DEBUG] Create VPC Routing table err %s\n%s", err, response) - return err - } - - d.SetId(fmt.Sprintf("%s/%s", vpcID, *routeTable.ID)) - - return resourceIBMISVPCRoutingTableRead(d, meta) -} - -func resourceIBMISVPCRoutingTableRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(idSet[0], idSet[1]) - routeTable, response, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting VPC Routing table: %s\n%s", err, response) - } - - d.Set(rtID, routeTable.ID) - d.Set(rtName, routeTable.Name) - - d.Set(rtHref, routeTable.Href) - d.Set(rtLifecycleState, routeTable.LifecycleState) - d.Set(rtCreateAt, routeTable.CreatedAt.String()) - d.Set(rtResourceType, routeTable.ResourceType) - d.Set(rtRouteDirectLinkIngress, routeTable.RouteDirectLinkIngress) - d.Set(rtRouteTransitGatewayIngress, routeTable.RouteTransitGatewayIngress) - d.Set(rtRouteVPCZoneIngress, routeTable.RouteVPCZoneIngress) - d.Set(rtIsDefault, routeTable.IsDefault) - - subnets := make([]map[string]interface{}, 0) - - for _, s := range routeTable.Subnets { - subnet := make(map[string]interface{}) - subnet[ID] = *s.ID - subnet["name"] = *s.Name - subnets = append(subnets, subnet) - } - - d.Set(rtSubnets, subnets) - - return nil -} - -func resourceIBMISVPCRoutingTableUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - updateVpcRoutingTableOptions := new(vpcv1.UpdateVPCRoutingTableOptions) - updateVpcRoutingTableOptions.VPCID = &idSet[0] - updateVpcRoutingTableOptions.ID = &idSet[1] - // Construct an instance of the RoutingTablePatch model - routingTablePatchModel := new(vpcv1.RoutingTablePatch) - - if d.HasChange(rtName) { - name := d.Get(rtName).(string) - routingTablePatchModel.Name = core.StringPtr(name) - } - if d.HasChange(rtRouteDirectLinkIngress) { - routeDirectLinkIngress := d.Get(rtRouteDirectLinkIngress).(bool) - routingTablePatchModel.RouteDirectLinkIngress = core.BoolPtr(routeDirectLinkIngress) - } - if d.HasChange(rtRouteTransitGatewayIngress) { - routeTransitGatewayIngress := d.Get(rtRouteTransitGatewayIngress).(bool) - routingTablePatchModel.RouteTransitGatewayIngress = core.BoolPtr(routeTransitGatewayIngress) - } - if d.HasChange(rtRouteVPCZoneIngress) { - routeVPCZoneIngress := d.Get(rtRouteVPCZoneIngress).(bool) - routingTablePatchModel.RouteVPCZoneIngress = core.BoolPtr(routeVPCZoneIngress) - } - routingTablePatchModelAsPatch, asPatchErr := routingTablePatchModel.AsPatch() - if asPatchErr != nil { - return fmt.Errorf("Error calling asPatch for RoutingTablePatchModel: %s", asPatchErr) - } - updateVpcRoutingTableOptions.RoutingTablePatch = routingTablePatchModelAsPatch - _, response, err := sess.UpdateVPCRoutingTable(updateVpcRoutingTableOptions) - if err != nil { - log.Printf("[DEBUG] Update VPC Routing table err %s\n%s", err, response) - return err - } - return resourceIBMISVPCRoutingTableRead(d, meta) -} - -func resourceIBMISVPCRoutingTableDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - - deleteTableOptions := sess.NewDeleteVPCRoutingTableOptions(idSet[0], idSet[1]) - response, err := sess.DeleteVPCRoutingTable(deleteTableOptions) - if err != nil && response.StatusCode != 404 { - log.Printf("Error deleting VPC Routing table : %s", response) - return err - } - - d.SetId("") - return nil -} - -func resourceIBMISVPCRoutingTableExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - - idSet := strings.Split(d.Id(), "/") - if len(idSet) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of vpcID/routingTableID", d.Id()) - } - getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(idSet[0], idSet[1]) - _, response, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return false, nil - } - return false, fmt.Errorf("Error Getting VPC Routing table : %s\n%s", err, response) - } - return true, nil -} diff --git a/ibm/resource_ibm_is_vpc_routing_table_route.go b/ibm/resource_ibm_is_vpc_routing_table_route.go deleted file mode 100644 index 20d8a56e4..000000000 --- a/ibm/resource_ibm_is_vpc_routing_table_route.go +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net" - "strings" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - rID = "route_id" - rDestination = "destination" - rAction = "action" - rNextHop = "next_hop" - rName = "name" - rZone = "zone" -) - -func resourceIBMISVPCRoutingTableRoute() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMISVPCRoutingTableRouteCreate, - Read: resourceIBMISVPCRoutingTableRouteRead, - Update: resourceIBMISVPCRoutingTableRouteUpdate, - Delete: resourceIBMISVPCRoutingTableRouteDelete, - Exists: resourceIBMISVPCRoutingTableRouteExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - rtID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The routing table identifier.", - }, - rtVpcID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The VPC identifier.", - }, - rDestination: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The destination of the route.", - }, - rZone: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The zone to apply the route to. Traffic from subnets in this zone will be subject to this route.", - }, - rNextHop: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "If action is deliver, the next hop that packets will be delivered to. For other action values, its address will be 0.0.0.0.", - }, - rAction: { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: "deliver", - Description: "The action to perform with a packet matching the route.", - ValidateFunc: InvokeValidator("ibm_is_vpc_routing_table_route", rAction), - }, - rName: { - Type: schema.TypeString, - Optional: true, - ForceNew: false, - Computed: true, - Description: "The user-defined name for this route.", - ValidateFunc: InvokeValidator("ibm_is_vpc_routing_table_route", rName), - }, - rID: { - Type: schema.TypeString, - Computed: true, - Description: "The routing table route identifier.", - }, - rtHref: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table route Href", - }, - rtCreateAt: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table route Created At", - }, - rtLifecycleState: { - Type: schema.TypeString, - Computed: true, - Description: "Routing table route Lifecycle State", - }, - rtOrigin: { - Type: schema.TypeString, - Computed: true, - Description: "The origin of this route.", - }, - }, - } -} - -func resourceIBMISVPCRoutingTableRouteValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - actionAllowedValues := "delegate, delegate_vpc, deliver, drop" - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: rtName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: false, - Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, - MinValueLength: 1, - MaxValueLength: 63}) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: rAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: false, - AllowedValues: actionAllowedValues}) - - ibmVPCRoutingTableRouteValidator := ResourceValidator{ResourceName: "ibm_is_vpc_routing_table_route", Schema: validateSchema} - return &ibmVPCRoutingTableRouteValidator -} - -func resourceIBMISVPCRoutingTableRouteCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - vpcID := d.Get(rtVpcID).(string) - tableID := d.Get(rtID).(string) - destination := d.Get(rDestination).(string) - zone := d.Get(rZone).(string) - z := &vpcv1.ZoneIdentityByName{ - Name: core.StringPtr(zone), - } - - createVpcRoutingTableRouteOptions := sess.NewCreateVPCRoutingTableRouteOptions(vpcID, tableID, destination, z) - createVpcRoutingTableRouteOptions.SetZone(z) - createVpcRoutingTableRouteOptions.SetDestination(destination) - - if add, ok := d.GetOk(rNextHop); ok { - item := add.(string) - if net.ParseIP(item) == nil { - nhConnectionID := &vpcv1.RouteNextHopPrototypeVPNGatewayConnectionIdentity{ - ID: core.StringPtr(item), - } - createVpcRoutingTableRouteOptions.SetNextHop(nhConnectionID) - } else { - nh := &vpcv1.RouteNextHopPrototypeRouteNextHopIP{ - Address: core.StringPtr(item), - } - createVpcRoutingTableRouteOptions.SetNextHop(nh) - } - } - - if action, ok := d.GetOk(rAction); ok { - routeAction := action.(string) - createVpcRoutingTableRouteOptions.SetAction(routeAction) - } - - if name, ok := d.GetOk(rName); ok { - routeName := name.(string) - createVpcRoutingTableRouteOptions.SetName(routeName) - } - - route, response, err := sess.CreateVPCRoutingTableRoute(createVpcRoutingTableRouteOptions) - if err != nil { - log.Printf("[DEBUG] Create VPC Routing table route err %s\n%s", err, response) - return err - } - - d.SetId(fmt.Sprintf("%s/%s/%s", vpcID, tableID, *route.ID)) - d.Set(rID, *route.ID) - return resourceIBMISVPCRoutingTableRouteRead(d, meta) -} - -func resourceIBMISVPCRoutingTableRouteRead(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - getVpcRoutingTableRouteOptions := sess.NewGetVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) - route, response, err := sess.GetVPCRoutingTableRoute(getVpcRoutingTableRouteOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error Getting VPC Routing table route: %s\n%s", err, response) - } - - d.Set(rID, *route.ID) - d.Set(rName, *route.Name) - d.Set(rDestination, *route.Destination) - if route.NextHop != nil { - nexthop := route.NextHop.(*vpcv1.RouteNextHop) - if nexthop.Address != nil { - d.Set(rNextHop, *nexthop.Address) - } - if nexthop.ID != nil { - d.Set(rNextHop, *nexthop.ID) - } - } - if route.Zone != nil { - d.Set(rZone, *route.Zone.Name) - } - d.Set(rtHref, route.Href) - d.Set(rtLifecycleState, route.LifecycleState) - d.Set(rtCreateAt, route.CreatedAt.String()) - - return nil -} - -func resourceIBMISVPCRoutingTableRouteUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - if d.HasChange(rName) { - routePatch := make(map[string]interface{}) - updateVpcRoutingTableRouteOptions := sess.NewUpdateVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2], routePatch) - - // Construct an instance of the RoutePatch model - routePatchModel := new(vpcv1.RoutePatch) - name := d.Get(rName).(string) - routePatchModel.Name = &name - routePatchModelAsPatch, patchErr := routePatchModel.AsPatch() - - if patchErr != nil { - return fmt.Errorf("Error calling asPatch for VPC Routing Table Route Patch: %s", patchErr) - } - - updateVpcRoutingTableRouteOptions.RoutePatch = routePatchModelAsPatch - _, response, err := sess.UpdateVPCRoutingTableRoute(updateVpcRoutingTableRouteOptions) - if err != nil { - log.Printf("[DEBUG] Update VPC Routing table route err %s\n%s", err, response) - return err - } - } - - return resourceIBMISVPCRoutingTableRouteRead(d, meta) -} - -func resourceIBMISVPCRoutingTableRouteDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - idSet := strings.Split(d.Id(), "/") - deleteVpcRoutingTableRouteOptions := sess.NewDeleteVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) - response, err := sess.DeleteVPCRoutingTableRoute(deleteVpcRoutingTableRouteOptions) - if err != nil && response.StatusCode != 404 { - log.Printf("Error deleting VPC Routing table route : %s", response) - return err - } - - d.SetId("") - return nil -} - -func resourceIBMISVPCRoutingTableRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := vpcClient(meta) - if err != nil { - return false, err - } - - idSet := strings.Split(d.Id(), "/") - if len(idSet) != 3 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of vpcID/routingTableID/routeID", d.Id()) - } - getVpcRoutingTableRouteOptions := sess.NewGetVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) - _, response, err := sess.GetVPCRoutingTableRoute(getVpcRoutingTableRouteOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return false, nil - } - return false, fmt.Errorf("Error Getting VPC Routing table route : %s\n%s", err, response) - } - return true, nil -} diff --git a/ibm/resource_ibm_is_vpc_routing_table_test.go b/ibm/resource_ibm_is_vpc_routing_table_test.go deleted file mode 100644 index 668b9800f..000000000 --- a/ibm/resource_ibm_is_vpc_routing_table_test.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISVPCRoutingTable_basic(t *testing.T) { - var vpcRouteTables string - name1 := fmt.Sprintf("tfvpc-create-%d", acctest.RandIntRange(10, 100)) - routeTableName := fmt.Sprintf("tfvpcrt-create-%d", acctest.RandIntRange(10, 100)) - routeTableName1 := fmt.Sprintf("tfvpcrt-up-create-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISVPCRouteTableDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVPCRouteTableConfig(routeTableName, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), - resource.TestCheckResourceAttr( - "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName), - ), - }, - { - Config: testAccCheckIBMISVPCRouteTableConfig(routeTableName1, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), - resource.TestCheckResourceAttr( - "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName1), - ), - }, - }, - }) -} - -func testAccCheckIBMISVPCRouteTableDestroy(s *terraform.State) error { - //userDetails, _ := testAccProvider.Meta().(ClientSession).BluemixUserDetails() - - //sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_vpc_routing_table" { - continue - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - sess, err := vpcClient(testAccProvider.Meta()) - if err != nil { - return err - } - vpcID := parts[0] - routeTableID := parts[1] - getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(vpcID, routeTableID) - _, _, err = sess.GetVPCRoutingTable(getVpcRoutingTableOptions) - if err == nil { - return fmt.Errorf("Routing table still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISVPCRouteTableExists(n, vpcrouteTableID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - //sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - vpcID := parts[0] - routeTableID := parts[1] - sess, err := vpcClient(testAccProvider.Meta()) - getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(vpcID, routeTableID) - rtResponse, detail, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) - if err != nil { - return fmt.Errorf("Error Getting Flow log: %s\n%s", err, detail) - } - vpcrouteTableID = *rtResponse.ID - return nil - } -} - -func testAccCheckIBMISVPCRouteTableConfig(rtName, name string) string { - return fmt.Sprintf(` -resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" -} -resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { - depends_on = [ibm_is_vpc.testacc_vpc] - vpc = ibm_is_vpc.testacc_vpc.id - name = "%s" -}`, name, rtName) -} diff --git a/ibm/resource_ibm_is_vpn_gateway_connection_test.go b/ibm/resource_ibm_is_vpn_gateway_connection_test.go deleted file mode 100644 index 8ae5df2c0..000000000 --- a/ibm/resource_ibm_is_vpn_gateway_connection_test.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISVPNGatewayConnection_basic(t *testing.T) { - var VPNGatewayConnection string - vpcname1 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname1 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(10, 100)) - vpnname1 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(10, 100)) - - vpcname2 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname2 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(10, 100)) - vpnname2 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) - name2 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(10, 100)) - updname2 := fmt.Sprintf("tfvpngc-updatename-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISVPNGatewayConnectionDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISVPNGatewayConnectionConfig(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, name2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name1), - resource.TestCheckResourceAttrSet( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "gateway_connection"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMISVPNGatewayConnectionUpdate(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, updname2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", VPNGatewayConnection), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "name", updname2), - ), - }, - }, - }) -} - -func TestAccIBMISVPNGatewayConnection_route(t *testing.T) { - var VPNGatewayConnection string - vpcname1 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(100, 200)) - subnetname1 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(100, 200)) - vpnname1 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(100, 200)) - name1 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(100, 200)) - - vpcname2 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(100, 200)) - subnetname2 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(100, 200)) - vpnname2 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(100, 200)) - name2 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(100, 200)) - updname2 := fmt.Sprintf("tfvpngc-updatename-%d", acctest.RandIntRange(100, 200)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISVPNGatewayConnectionDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISVPNGatewayConnectionRouteConfig(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, name2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name1), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "mode", "route"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMISVPNGatewayConnectionRouteUpdate(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, updname2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", VPNGatewayConnection), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "name", updname2), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "mode", "route"), - ), - }, - }, - }) -} - -func testAccCheckIBMISVPNGatewayConnectionDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_vpn_gateway_connection" { - continue - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - gID := parts[0] - gConnID := parts[1] - - getvpngcoptions := &vpcv1.GetVPNGatewayConnectionOptions{ - VPNGatewayID: &gID, - ID: &gConnID, - } - _, _, err1 := sess.GetVPNGatewayConnection(getvpngcoptions) - - if err1 == nil { - return fmt.Errorf("VPNGatewayConnection still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISVPNGatewayConnectionExists(n, vpngcID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - - gID := parts[0] - gConnID := parts[1] - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getvpngcoptions := &vpcv1.GetVPNGatewayConnectionOptions{ - VPNGatewayID: &gID, - ID: &gConnID, - } - foundvpngcIntf, res, err := sess.GetVPNGatewayConnection(getvpngcoptions) - if err != nil { - return fmt.Errorf("Error Getting VPN Gateway connection: %s\n%s", err, res) - } - foundvpngc := foundvpngcIntf.(*vpcv1.VPNGatewayConnection) - vpngcID = *foundvpngc.ID - return nil - } -} - -func testAccCheckIBMISVPNGatewayConnectionConfig(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc1" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet1" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc1.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet1.id}" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" - preshared_key = "VPNDemoPassword" - local_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] - peer_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] - - } - - resource "ibm_is_vpc" "testacc_vpc2" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet2" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc2.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet2.id}" - mode = "policy" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" - preshared_key = "VPNDemoPassword" - local_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] - peer_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] - - } - - `, vpc1, subnet1, ISZoneName, ISCIDR, vpnname1, name1, vpc2, subnet2, ISZoneName, ISCIDR, vpnname2, name2) - -} - -func testAccCheckIBMISVPNGatewayConnectionUpdate(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc1" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet1" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc1.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet1.id}" - mode = "policy" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" - preshared_key = "VPNDemoPassword" - local_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] - peer_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] - - } - - resource "ibm_is_vpc" "testacc_vpc2" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet2" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc2.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - - resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet2.id}" - mode = "policy" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" - preshared_key = "VPNDemoPassword" - local_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] - peer_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] - - } - - `, vpc1, subnet1, ISZoneName, ISCIDR, vpnname1, name1, vpc2, subnet2, ISZoneName, ISCIDR, vpnname2, name2) - -} - -func testAccCheckIBMISVPNGatewayConnectionRouteConfig(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc1" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet1" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc1.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet1.id}" - mode = "route" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" - preshared_key = "VPNDemoPassword" - } - resource "ibm_is_vpc" "testacc_vpc2" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet2" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc2.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet2.id}" - mode = "route" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" - preshared_key = "VPNDemoPassword" - } - `, vpc1, subnet1, ISZoneName, ISCIDR, vpnname1, name1, vpc2, subnet2, ISZoneName, ISCIDR, vpnname2, name2) - -} - -func testAccCheckIBMISVPNGatewayConnectionRouteUpdate(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc1" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet1" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc1.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet1.id}" - mode = "route" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" - preshared_key = "VPNDemoPassword" - } - resource "ibm_is_vpc" "testacc_vpc2" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet2" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc2.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet2.id}" - mode = "route" - } - resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { - name = "%s" - vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" - peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" - preshared_key = "VPNDemoPassword" - } - `, vpc1, subnet1, ISZoneName, ISCIDR, vpnname1, name1, vpc2, subnet2, ISZoneName, ISCIDR, vpnname2, name2) - -} diff --git a/ibm/resource_ibm_is_vpn_gateway_test.go b/ibm/resource_ibm_is_vpn_gateway_test.go deleted file mode 100644 index 6f1759708..000000000 --- a/ibm/resource_ibm_is_vpn_gateway_test.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/IBM/vpc-go-sdk/vpcv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMISVPNGateway_basic(t *testing.T) { - var vpnGateway string - vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISVPNGatewayDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVPNGatewayConfig(vpcname, subnetname, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name1), - ), - }, - }, - }) -} - -func TestAccIBMISVPNGateway_route(t *testing.T) { - var vpnGateway string - vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMISVPNGatewayDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVPNGatewayRouteConfig(vpcname, subnetname, name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name1), - resource.TestCheckResourceAttr( - "ibm_is_vpn_gateway.testacc_vpnGateway", "mode", "route"), - ), - }, - }, - }) -} - -func testAccCheckIBMISVPNGatewayDestroy(s *terraform.State) error { - - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_vpn_gateway" { - continue - } - - getvpngcptions := &vpcv1.GetVPNGatewayConnectionOptions{ - ID: &rs.Primary.ID, - } - _, _, err := sess.GetVPNGatewayConnection(getvpngcptions) - - if err == nil { - return fmt.Errorf("vpnGateway still exists: %s", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckIBMISVPNGatewayExists(n, vpnGatewayID string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() - getvpngcptions := &vpcv1.GetVPNGatewayOptions{ - ID: &rs.Primary.ID, - } - foundvpnGatewayIntf, _, err := sess.GetVPNGateway(getvpngcptions) - if err != nil { - return err - } - foundvpnGateway := foundvpnGatewayIntf.(*vpcv1.VPNGateway) - vpnGatewayID = *foundvpnGateway.ID - return nil - } -} - -func testAccCheckIBMISVPNGatewayConfig(vpc, subnet, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet.id}" - mode = "policy" - }`, vpc, subnet, ISZoneName, ISCIDR, name) - -} - -func testAccCheckIBMISVPNGatewayRouteConfig(vpc, subnet, name string) string { - return fmt.Sprintf(` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = "${ibm_is_vpc.testacc_vpc.id}" - zone = "%s" - ipv4_cidr_block = "%s" - } - resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { - name = "%s" - subnet = "${ibm_is_subnet.testacc_subnet.id}" - mode = "route" - }`, vpc, subnet, ISZoneName, ISCIDR, name) - -} diff --git a/ibm/resource_ibm_kms_key.go b/ibm/resource_ibm_kms_key.go deleted file mode 100644 index 5b069e849..000000000 --- a/ibm/resource_ibm_kms_key.go +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "strconv" - "strings" - "time" - - kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func suppressKMSInstanceIDDiff(k, old, new string, d *schema.ResourceData) bool { - // TF currently uses GUID. So just check when instance crn is passed as input it has same GUID in it. - crnData := strings.Split(new, ":") - if len(crnData) > 3 { - instanceID := crnData[len(crnData)-3] - return instanceID == old - } - return false -} - -func resourceIBMKmskey() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMKmsKeyCreate, - Read: resourceIBMKmsKeyRead, - Update: resourceIBMKmsKeyUpdate, - Delete: resourceIBMKmsKeyDelete, - Exists: resourceIBMKmsKeyExists, - Importer: &schema.ResourceImporter{}, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Key protect or hpcs instance GUID or CRN", - DiffSuppressFunc: suppressKMSInstanceIDDiff, - }, - "key_ring_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: "default", - Description: "Key Ring for the Key", - }, - "key_id": { - Type: schema.TypeString, - Computed: true, - Description: "Key ID", - }, - "key_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Key name", - }, - "type": { - Type: schema.TypeString, - Computed: true, - Description: "type of service hs-crypto or kms", - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "public or private", - ForceNew: true, - }, - "standard_key": { - Type: schema.TypeBool, - Default: false, - Optional: true, - ForceNew: true, - Description: "Standard key type", - }, - "payload": { - Type: schema.TypeString, - Computed: true, - Optional: true, - ForceNew: true, - }, - "encrypted_nonce": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Only for imported root key", - }, - "iv_value": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Only for imported root key", - }, - "force_delete": { - Type: schema.TypeBool, - Optional: true, - Description: "set to true to force delete the key", - ForceNew: false, - Default: false, - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Crn of the key", - }, - "expiration_date": { - Type: schema.TypeString, - Optional: true, - Description: "The date the key material expires. The date format follows RFC 3339. You can set an expiration date on any key on its creation. A key moves into the Deactivated state within one hour past its expiration date, if one is assigned. If you create a key without specifying an expiration date, the key does not expire", - ForceNew: true, - }, - "policies": { - Type: schema.TypeList, - Deprecated: "Support for creating Policies with the key will soon be removed, Utilise the new resource for creating policies for the keys => ibm_kms_key_policies", - Optional: true, - Computed: true, - Description: "Creates or updates one or more policies for the specified key", - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "rotation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - AtLeastOneOf: []string{"policies.0.rotation", "policies.0.dual_auth_delete"}, - Description: "Specifies the key rotation time interval in months, with a minimum of 1, and a maximum of 12", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that created the policy.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the policy was created. The date format follows RFC 3339.", - }, - "updated_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that updated the policy.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", - }, - "interval_month": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(1, 12), - Description: "Specifies the key rotation time interval in months", - }, - }, - }, - }, - "dual_auth_delete": { - Type: schema.TypeList, - Optional: true, - Computed: true, - AtLeastOneOf: []string{"policies.0.rotation", "policies.0.dual_auth_delete"}, - Description: "Data associated with the dual authorization delete policy.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that created the policy.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the policy was created. The date format follows RFC 3339.", - }, - "updated_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that updated the policy.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", - }, - "enabled": { - Type: schema.TypeBool, - Required: true, - Description: "If set to true, Key Protect enables a dual authorization policy on a single key.", - }, - }, - }, - }, - }, - }, - }, - "instance_crn": { - Type: schema.TypeString, - Computed: true, - Description: "Key protect or hpcs instance CRN", - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - }, - } -} - -func resourceIBMKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - - kpAPI.Config.InstanceID = instanceID - - kpAPI.Config.KeyRing = d.Get("key_ring_id").(string) - - name := d.Get("key_name").(string) - standardKey := d.Get("standard_key").(bool) - - var expiration *time.Time - if es, ok := d.GetOk("expiration_date"); ok { - expiration_string := es.(string) - // parse string to required time format - expiration_time, err := time.Parse(time.RFC3339, expiration_string) - if err != nil { - return fmt.Errorf("Invalid time format (the date format follows RFC 3339): %s", err) - } - expiration = &expiration_time - } else { - expiration = nil - } - - var keyCRN string - if standardKey { - if v, ok := d.GetOk("payload"); ok { - //import standard key - payload := v.(string) - stkey, err := kpAPI.CreateImportedStandardKey(context.Background(), name, expiration, payload) - if err != nil { - return fmt.Errorf( - "Error while creating standard key with payload: %s", err) - } - keyCRN = stkey.CRN - d.SetId(keyCRN) - - } else { - //create standard key - stkey, err := kpAPI.CreateStandardKey(context.Background(), name, expiration) - if err != nil { - return fmt.Errorf( - "Error while creating standard key: %s", err) - } - keyCRN = stkey.CRN - d.SetId(keyCRN) - - } - } else { - if v, ok := d.GetOk("payload"); ok { - payload := v.(string) - encryptedNonce := d.Get("encrypted_nonce").(string) - iv := d.Get("iv_value").(string) - stkey, err := kpAPI.CreateImportedRootKey(context.Background(), name, expiration, payload, encryptedNonce, iv) - if err != nil { - return fmt.Errorf( - "Error while creating Root key with payload: %s", err) - } - keyCRN = stkey.CRN - d.SetId(keyCRN) - - } else { - stkey, err := kpAPI.CreateRootKey(context.Background(), name, expiration) - if err != nil { - return fmt.Errorf( - "Error while creating Root key: %s", err) - } - keyCRN = stkey.CRN - d.SetId(keyCRN) - } - } - return resourceIBMKmsKeyUpdate(d, meta) -} - -func resourceIBMKmsKeyRead(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - crn := d.Id() - crnData := strings.Split(crn, ":") - instanceCRN := fmt.Sprintf("%s::", strings.Split(crn, ":key:")[0]) - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - - kpAPI.Config.InstanceID = instanceID - // keyid := d.Id() - key, err := kpAPI.GetKey(context.Background(), keyid) - if err != nil { - kpError := err.(*kp.Error) - if kpError.StatusCode == 404 || kpError.StatusCode == 409 { - d.SetId("") - return nil - } - return fmt.Errorf("Get Key failed with error while reading policies: %s", err) - } else if key.State == 5 { //Refers to Deleted state of the Key - d.SetId("") - return nil - } - - policies, err := kpAPI.GetPolicies(context.Background(), keyid) - if err != nil && !strings.Contains(fmt.Sprint(err), "Unauthorized: The user does not have access to the specified resource") { - return fmt.Errorf("Failed to read policies: %s", err) - } - if len(policies) == 0 { - log.Printf("No Policy Configurations read\n") - } else { - d.Set("policies", flattenKeyPolicies(policies)) - } - d.Set("instance_id", instanceID) - d.Set("instance_crn", instanceCRN) - d.Set("key_id", keyid) - d.Set("standard_key", key.Extractable) - d.Set("payload", key.Payload) - d.Set("encrypted_nonce", key.EncryptedNonce) - d.Set("iv_value", key.IV) - d.Set("key_name", key.Name) - d.Set("crn", key.CRN) - if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { - d.Set("endpoint_type", "private") - } else { - d.Set("endpoint_type", "public") - } - d.Set("type", crnData[4]) - d.Set("force_delete", d.Get("force_delete").(bool)) - d.Set("key_ring_id", key.KeyRingID) - if key.Expiration != nil { - expiration := key.Expiration - d.Set("expiration_date", expiration.Format(time.RFC3339)) - } else { - d.Set("expiration_date", "") - } - d.Set(ResourceName, key.Name) - d.Set(ResourceCRN, key.CRN) - state := key.State - d.Set(ResourceStatus, strconv.Itoa(state)) - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - id := key.ID - crn1 := strings.TrimSuffix(key.CRN, ":key:"+id) - - d.Set(ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") - - return nil - -} - -func resourceIBMKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error { - - if d.HasChange("force_delete") { - d.Set("force_delete", d.Get("force_delete").(bool)) - } - if d.HasChange("policies") { - - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - - crn := d.Id() - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - key_id := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - err = handlePolicies(d, kpAPI, meta, key_id) - if err != nil { - return fmt.Errorf("Could not update policies: %s", err) - } - } - return resourceIBMKmsKeyRead(d, meta) - -} - -func resourceIBMKmsKeyDelete(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - crn := d.Id() - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - force := d.Get("force_delete").(bool) - f := kp.ForceOpt{ - Force: force, - } - - _, err1 := kpAPI.DeleteKey(context.Background(), keyid, kp.ReturnRepresentation, f) - if err1 != nil { - return fmt.Errorf( - "Error while deleting: %s", err1) - } - d.SetId("") - return nil - -} - -func resourceIBMKmsKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return false, err - } - - crn := d.Id() - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return false, fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return false, err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - _, err = kpAPI.GetKey(context.Background(), keyid) - if err != nil { - kpError := err.(*kp.Error) - if kpError.StatusCode == 404 { - return false, nil - } - return false, err - } - return true, nil - -} - -func handlePolicies(d *schema.ResourceData, kpAPI *kp.Client, meta interface{}, key_id string) error { - var setRotation, setDualAuthDelete, dualAuthEnable bool - var rotationInterval int - - if policyInfo, ok := d.GetOk("policies"); ok { - - policyDataList := policyInfo.([]interface{}) - policyData := policyDataList[0].(map[string]interface{}) - - if rpd, ok := policyData["rotation"]; ok { - rpdList := rpd.([]interface{}) - if len(rpdList) != 0 { - rotationInterval = rpdList[0].(map[string]interface{})["interval_month"].(int) - setRotation = true - } - } - if dadp, ok := policyData["dual_auth_delete"]; ok { - dadpList := dadp.([]interface{}) - if len(dadpList) != 0 { - dualAuthEnable = dadpList[0].(map[string]interface{})["enabled"].(bool) - setDualAuthDelete = true - } - } - - _, err := kpAPI.SetPolicies(context.Background(), key_id, setRotation, rotationInterval, setDualAuthDelete, dualAuthEnable) - if err != nil { - return fmt.Errorf("Error while creating policies: %s", err) - } - } - return nil -} - -//Construct KMS URL -func KmsEndpointURL(kpAPI *kp.Client, endpointType string, extensions map[string]interface{}) (*url.URL, error) { - - exturl := extensions["endpoints"].(map[string]interface{})["public"] - if endpointType == "private" || strings.Contains(kpAPI.Config.BaseURL, "private") { - exturl = extensions["endpoints"].(map[string]interface{})["private"] - } - endpointURL := fmt.Sprintf("%s/api/v2/keys", exturl.(string)) - - url1 := envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, endpointURL) - u, err := url.Parse(url1) - if err != nil { - return nil, fmt.Errorf("[ERROR] Error Parsing KMS EndpointURL") - } - return u, nil -} diff --git a/ibm/resource_ibm_kms_key_alias.go b/ibm/resource_ibm_kms_key_alias.go deleted file mode 100644 index 5041916f3..000000000 --- a/ibm/resource_ibm_kms_key_alias.go +++ /dev/null @@ -1,200 +0,0 @@ -package ibm - -import ( - "context" - "fmt" - "strings" - - kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMKmskeyAlias() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMKmsKeyAliasCreate, - Delete: resourceIBMKmsKeyAliasDelete, - Read: resourceIBMKmsKeyAliasRead, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - Description: "Key ID", - ForceNew: true, - DiffSuppressFunc: suppressKMSInstanceIDDiff, - }, - "alias": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Key protect or hpcs key alias name", - }, - "key_id": { - Type: schema.TypeString, - Required: true, - Description: "Key ID", - ForceNew: true, - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "public or private", - ForceNew: true, - }, - }, - } -} - -func resourceIBMKmsKeyAliasCreate(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - aliasName := d.Get("alias").(string) - keyID := d.Get("key_id").(string) - stkey, err := kpAPI.CreateKeyAlias(context.Background(), aliasName, keyID) - if err != nil { - return fmt.Errorf( - "Error while creating alias name for the key: %s", err) - } - key, err := kpAPI.GetKey(context.Background(), stkey.KeyID) - if err != nil { - return fmt.Errorf("Get Key failed with error: %s", err) - } - d.SetId(fmt.Sprintf("%s:alias:%s", stkey.Alias, key.CRN)) - - return resourceIBMKmsKeyAliasRead(d, meta) -} - -func resourceIBMKmsKeyAliasRead(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - id := strings.Split(d.Id(), ":alias:") - if len(id) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of keyAlias:alias:keyCRN", d.Id()) - } - crn := id[1] - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - key, err := kpAPI.GetKey(context.Background(), keyid) - if err != nil { - kpError := err.(*kp.Error) - if kpError.StatusCode == 404 || kpError.StatusCode == 409 { - d.SetId("") - return nil - } - return fmt.Errorf("Get Key failed with error while reading policies: %s", err) - } else if key.State == 5 { //Refers to Deleted state of the Key - d.SetId("") - return nil - } - d.Set("alias", id[0]) - d.Set("key_id", key.ID) - d.Set("instance_id", instanceID) - if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { - d.Set("endpoint_type", "private") - } else { - d.Set("endpoint_type", "public") - } - - return nil -} - -func resourceIBMKmsKeyAliasDelete(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - id := strings.Split(d.Id(), ":alias:") - crn := id[1] - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - err1 := kpAPI.DeleteKeyAlias(context.Background(), id[0], keyid) - if err1 != nil { - kpError := err1.(*kp.Error) - if kpError.StatusCode == 404 { - return nil - } else { - return fmt.Errorf(" failed to Destroy alias with error: %s", err1) - } - } - return nil -} diff --git a/ibm/resource_ibm_kms_key_policies.go b/ibm/resource_ibm_kms_key_policies.go deleted file mode 100644 index ec4a0804b..000000000 --- a/ibm/resource_ibm_kms_key_policies.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "net/url" - "strconv" - "strings" - "time" - - kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMKmskeyPolicies() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMKmsKeyPolicyCreate, - ReadContext: resourceIBMKmsKeyPolicyRead, - UpdateContext: resourceIBMKmsKeyPolicyUpdate, - DeleteContext: resourceIBMKmsKeyPolicyDelete, - Importer: &schema.ResourceImporter{}, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Key protect or hpcs instance GUID", - DiffSuppressFunc: suppressKMSInstanceIDDiff, - }, - "key_id": { - Type: schema.TypeString, - Required: true, - Description: "Key ID", - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "public or private", - ForceNew: true, - Default: "public", - }, - "rotation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - AtLeastOneOf: []string{"rotation", "dual_auth_delete"}, - Description: "Specifies the key rotation time interval in months, with a minimum of 1, and a maximum of 12", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that created the policy.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the policy was created. The date format follows RFC 3339.", - }, - "updated_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that updated the policy.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", - }, - "interval_month": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(1, 12), - Description: "Specifies the key rotation time interval in months", - }, - }, - }, - }, - "dual_auth_delete": { - Type: schema.TypeList, - Optional: true, - Computed: true, - AtLeastOneOf: []string{"rotation", "dual_auth_delete"}, - Description: "Data associated with the dual authorization delete policy.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that created the policy.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the policy was created. The date format follows RFC 3339.", - }, - "updated_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the resource that updated the policy.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", - }, - "enabled": { - Type: schema.TypeBool, - Required: true, - Description: "If set to true, Key Protect enables a dual authorization policy on a single key.", - }, - }, - }, - }, - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - }, - } -} -func resourceIBMKmsKeyPolicyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return diag.FromErr(err) - } - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - key_id := d.Get("key_id").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return diag.FromErr(err) - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return diag.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return diag.FromErr(err) - } - kpAPI.URL = URL - - kpAPI.Config.InstanceID = instanceID - - key, err := kpAPI.GetKey(context, key_id) - if err != nil { - return diag.Errorf("Get Key failed with error while creating policies: %s", err) - } - err = resourceHandlePolicies(context, d, kpAPI, meta, key_id) - if err != nil { - return diag.Errorf("Could not create policies: %s", err) - } - d.SetId(key.CRN) - return resourceIBMKmsKeyPolicyUpdate(context, d, meta) -} - -func resourceIBMKmsKeyPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return diag.FromErr(err) - } - crn := d.Id() - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - keyid := crnData[len(crnData)-1] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return diag.FromErr(err) - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return diag.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return diag.FromErr(err) - } - kpAPI.URL = URL - - kpAPI.Config.InstanceID = instanceID - key, err := kpAPI.GetKey(context, keyid) - if err != nil { - kpError := err.(*kp.Error) - if kpError.StatusCode == 404 || kpError.StatusCode == 409 { - d.SetId("") - return nil - } - return diag.Errorf("Get Key failed with error while reading policies: %s", err) - } else if key.State == 5 { //Refers to Deleted state of the Key - d.SetId("") - return nil - } - - d.Set("instance_id", instanceID) - d.Set("key_id", keyid) - if strings.Contains((kpAPI.URL).String(), "private") { - d.Set("endpoint_type", "private") - } else { - d.Set("endpoint_type", "public") - } - d.Set(ResourceName, key.Name) - d.Set(ResourceCRN, key.CRN) - state := key.State - d.Set(ResourceStatus, strconv.Itoa(state)) - rcontroller, err := getBaseController(meta) - if err != nil { - return diag.FromErr(err) - } - id := key.ID - crn1 := strings.TrimSuffix(key.CRN, ":key:"+id) - - d.Set(ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") - - policies, err := kpAPI.GetPolicies(context, keyid) - - if err != nil { - return diag.Errorf("Failed to read policies: %s", err) - } - if len(policies) == 0 { - log.Printf("No Policy Configurations read\n") - } else { - d.Set("rotation", flattenKeyIndividualPolicy("rotation", policies)) - d.Set("dual_auth_delete", flattenKeyIndividualPolicy("dual_auth_delete", policies)) - } - - return nil - -} - -func resourceIBMKmsKeyPolicyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - if d.HasChange("rotation") || d.HasChange("dual_auth_delete") { - - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return diag.FromErr(err) - } - - instanceID := d.Get("instance_id").(string) - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return diag.FromErr(err) - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return diag.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return diag.FromErr(err) - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - crn := d.Id() - crnData := strings.Split(crn, ":") - key_id := crnData[len(crnData)-1] - - err = resourceHandlePolicies(context, d, kpAPI, meta, key_id) - if err != nil { - resourceIBMKmsKeyRead(d, meta) - return diag.Errorf("Could not create policies: %s", err) - } - } - return resourceIBMKmsKeyPolicyRead(context, d, meta) - -} - -func resourceIBMKmsKeyPolicyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - //Do not support delete Policies - log.Println("Warning: `terraform destroy` does not remove the policies of the Key but only clears the state file. Key Policies get deleted when the associated key resource is destroyed.") - d.SetId("") - return nil - -} - -func resourceHandlePolicies(context context.Context, d *schema.ResourceData, kpAPI *kp.Client, meta interface{}, key_id string) error { - var setRotation, setDualAuthDelete, dualAuthEnable bool - var rotationInterval int - - if policyInfo, ok := d.GetOk("rotation"); ok { - rpdList := policyInfo.([]interface{}) - if len(rpdList) != 0 { - rotationInterval = rpdList[0].(map[string]interface{})["interval_month"].(int) - setRotation = true - } - } - if dadp, ok := d.GetOk("dual_auth_delete"); ok { - dadpList := dadp.([]interface{}) - if len(dadpList) != 0 { - dualAuthEnable = dadpList[0].(map[string]interface{})["enabled"].(bool) - setDualAuthDelete = true - } - } - _, err := kpAPI.SetPolicies(context, key_id, setRotation, rotationInterval, setDualAuthDelete, dualAuthEnable) - if err != nil { - return fmt.Errorf("Error while creating policies: %s", err) - } - return nil -} diff --git a/ibm/resource_ibm_kms_key_policies_test.go b/ibm/resource_ibm_kms_key_policies_test.go deleted file mode 100644 index 9b79cf120..000000000 --- a/ibm/resource_ibm_kms_key_policies_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package ibm - -import ( - "fmt" - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMKMSKeyPolicy_basic_check(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 3 - dual_auth_delete := false - rotation_interval_new := 5 - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, keyName, rotation_interval, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "3"), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, keyName, rotation_interval_new, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "5"), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_rotation_check(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 3 - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyRotationCheck(instanceName, keyName, rotation_interval), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "3"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_dualAuth_check(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - dual_auth_delete := false - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyDualAuthCheck(instanceName, keyName, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_invalid_interval_check(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 13 - dual_auth_delete := false - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, keyName, rotation_interval, dual_auth_delete), - ExpectError: regexp.MustCompile("must contain a valid int value should be in range(1, 12)"), - }, - }, - }) -} - -func testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, KeyName string, rotation_interval int, dual_auth_delete bool) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - } - resource "ibm_kms_key_policies" "Policy" { - instance_id = ibm_resource_instance.kp_instance.guid - key_id = ibm_kms_key.test.key_id - rotation { - interval_month = %d - } - dual_auth_delete { - enabled = %t - } - } -`, instanceName, KeyName, rotation_interval, dual_auth_delete) -} - -func testAccCheckIBMKmsKeyPolicyDualAuthCheck(instanceName, KeyName string, dual_auth_delete bool) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - } - resource "ibm_kms_key_policies" "Policy" { - instance_id = ibm_resource_instance.kp_instance.guid - key_id = ibm_kms_key.test.key_id - dual_auth_delete { - enabled = %t - } - } -`, instanceName, KeyName, dual_auth_delete) -} - -func testAccCheckIBMKmsKeyPolicyRotationCheck(instanceName, KeyName string, rotation_interval int) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - } - resource "ibm_kms_key_policies" "Policy" { - instance_id = ibm_resource_instance.kp_instance.guid - key_id = ibm_kms_key.test.key_id - rotation { - interval_month = %d - } - } - -`, instanceName, KeyName, rotation_interval) -} diff --git a/ibm/resource_ibm_kms_key_rings.go b/ibm/resource_ibm_kms_key_rings.go deleted file mode 100644 index 466244d89..000000000 --- a/ibm/resource_ibm_kms_key_rings.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "strings" - - kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMKmskeyRings() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMKmsKeyRingCreate, - Delete: resourceIBMKmsKeyRingDelete, - Read: resourceIBMKmsKeyRingRead, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - Description: "Key protect Instance GUID", - ForceNew: true, - DiffSuppressFunc: suppressKMSInstanceIDDiff, - }, - "key_ring_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "User defined unique ID for the key ring", - ValidateFunc: InvokeValidator("ibm_kms_key_rings", "key_ring_id"), - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), - Description: "public or private", - ForceNew: true, - }, - }, - } -} - -func resourceIBMKeyRingValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "key_ring_id", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^[a-zA-Z0-9-]*$`, - MinValueLength: 2, - MaxValueLength: 100}) - - ibmKeyRingResourceValidator := ResourceValidator{ResourceName: "ibm_kms_key_rings", Schema: validateSchema} - return &ibmKeyRingResourceValidator -} - -func resourceIBMKmsKeyRingCreate(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - keyRingID := d.Get("key_ring_id").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - instanceCRN := instanceData.CRN - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - - err = kpAPI.CreateKeyRing(context.Background(), keyRingID) - if err != nil { - return fmt.Errorf( - "Error while creating key ring : %s", err) - } - var keyRing string - keyRings, err2 := kpAPI.GetKeyRings(context.Background()) - if err2 != nil { - return fmt.Errorf( - "Error while fetching key ring : %s", err2) - } - for _, v := range keyRings.KeyRings { - if v.ID == keyRingID { - keyRing = v.ID - break - } - } - - d.SetId(fmt.Sprintf("%s:keyRing:%s", keyRing, *instanceCRN)) - - return resourceIBMKmsKeyRingRead(d, meta) -} - -func resourceIBMKmsKeyRingRead(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - id := strings.Split(d.Id(), ":keyRing:") - if len(id) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of keyRingID:keyRing:InstanceCRN", d.Id()) - } - crn := id[1] - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - _, err = kpAPI.GetKeyRings(context.Background()) - if err != nil { - kpError := err.(*kp.Error) - if kpError.StatusCode == 404 || kpError.StatusCode == 409 { - d.SetId("") - return nil - } - return fmt.Errorf("Get Key Rings failed with error: %s", err) - } - - d.Set("instance_id", instanceID) - if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { - d.Set("endpoint_type", "private") - } else { - d.Set("endpoint_type", "public") - } - d.Set("key_ring_id", id[0]) - return nil -} - -func resourceIBMKmsKeyRingDelete(d *schema.ResourceData, meta interface{}) error { - kpAPI, err := meta.(ClientSession).keyManagementAPI() - if err != nil { - return err - } - id := strings.Split(d.Id(), ":keyRing:") - crn := id[1] - crnData := strings.Split(crn, ":") - endpointType := d.Get("endpoint_type").(string) - instanceID := crnData[len(crnData)-3] - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(kpAPI, endpointType, extensions) - if err != nil { - return err - } - kpAPI.URL = URL - kpAPI.Config.InstanceID = instanceID - err1 := kpAPI.DeleteKeyRing(context.Background(), id[0]) - if err1 != nil { - kpError := err1.(*kp.Error) - if kpError.StatusCode == 404 || kpError.StatusCode == 409 { - return nil - } else { - return fmt.Errorf(" failed to Destroy key ring with error: %s", err1) - } - } - return nil - -} diff --git a/ibm/resource_ibm_kms_key_test.go b/ibm/resource_ibm_kms_key_test.go deleted file mode 100644 index 96948673c..000000000 --- a/ibm/resource_ibm_kms_key_test.go +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "math/rand" - "regexp" - "testing" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMKMSResource_basic(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - cosInstanceName := fmt.Sprintf("cos_%d", acctest.RandIntRange(10, 100)) - bucketName := fmt.Sprintf("bucket-test77") - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - payload := "LqMWNtSi3Snr4gFNO0PsFFLFRNs57mSXCQE7O2oE+g0=" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsResourceStandardConfig(instanceName, keyName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsResourceImportStandardConfig(instanceName, keyName, payload), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsResourceRootkeyWithCOSConfig(instanceName, keyName, cosInstanceName, bucketName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - ), - }, - }, - }) -} -func TestAccIBMKMSHPCSResource_basic(t *testing.T) { - t.Skip() - hpcskeyName := fmt.Sprintf("hpcs_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsResourceHpcsConfig(hpcsInstanceID, hpcskeyName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.hpcstest", "key_name", hpcskeyName), - ), - }, - }, - }) -} - -// Test for valid expiration date for create key operation -func TestAccIBMKMSResource_ValidExpDate(t *testing.T) { - - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - - hours := time.Duration(rand.Intn(24) + 1) - mins := time.Duration(rand.Intn(60) + 1) - sec := time.Duration(rand.Intn(60) + 1) - loc, _ := time.LoadLocation("UTC") - expirationDateValid := ((time.Now().In(loc).Add(time.Hour*hours + time.Minute*mins + time.Second*sec)).Format(time.RFC3339)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, keyName, expirationDateValid), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "expiration_date", expirationDateValid), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsCreateRootKeyConfig(instanceName, keyName, expirationDateValid), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "expiration_date", expirationDateValid), - ), - }, - }, - }) -} - -// Test for invalid expiration date for create key operation -func TestAccIBMKMSResource_InvalidExpDate(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - - hours := time.Duration(rand.Intn(24) + 1) - mins := time.Duration(rand.Intn(60) + 1) - sec := time.Duration(rand.Intn(60) + 1) - expirationDateInvalid := (time.Now().Add(time.Hour*hours + time.Minute*mins + time.Second*sec)).String() - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, keyName, expirationDateInvalid), - ExpectError: regexp.MustCompile("Invalid time format"), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsCreateRootKeyConfig(instanceName, keyName, expirationDateInvalid), - ExpectError: regexp.MustCompile("Invalid time format"), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_basic(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 3 - dual_auth_delete := false - rotation_interval_new := 5 - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, keyName, rotation_interval, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "3"), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, keyName, rotation_interval_new, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "5"), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_rotation(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 3 - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyRotation(instanceName, keyName, rotation_interval), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.rotation.0.interval_month", "3"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_dualAuth(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - dual_auth_delete := false - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyDualAuth(instanceName, keyName, dual_auth_delete), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key.test", "policies.0.dual_auth_delete.0.enabled", "false"), - ), - }, - }, - }) -} - -func TestAccIBMKMSKeyPolicy_invalid_interval(t *testing.T) { - instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) - rotation_interval := 13 - dual_auth_delete := false - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, keyName, rotation_interval, dual_auth_delete), - ExpectError: regexp.MustCompile("config is invalid:"), - }, - }, - }) -} - -func testAccCheckIBMKmsResourceStandardConfig(instanceName, KeyName string) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kms_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - resource "ibm_kms_key" "test" { - instance_id = "${ibm_resource_instance.kms_instance.guid}" - key_name = "%s" - standard_key = true - force_delete = true - } - -`, instanceName, KeyName) -} - -func testAccCheckIBMKmsResourceImportStandardConfig(instanceName, KeyName, payload string) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kms_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - resource "ibm_kms_key" "test" { - instance_id = "${ibm_resource_instance.kms_instance.guid}" - key_name = "%s" - standard_key = true - payload = "%s" - force_delete = true - } - -`, instanceName, KeyName, payload) -} - -func testAccCheckIBMKmsResourceRootkeyWithCOSConfig(instanceName, KeyName, cosInstanceName, bucketName string) string { - return fmt.Sprintf(` - provider "ibm" { - region = "us-south" - } - resource "ibm_resource_instance" "kms_instance1" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - resource "ibm_kms_key" "test" { - instance_id = "${ibm_resource_instance.kms_instance1.guid}" - key_name = "%s" - standard_key = false - force_delete = true - } - - resource "ibm_resource_instance" "cos_instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - } - - resource "ibm_iam_authorization_policy" "policy" { - source_service_name = "cloud-object-storage" - target_service_name = "kms" - roles = ["Reader"] - } - - resource "ibm_cos_bucket" "smart-us-south" { - depends_on = [ibm_iam_authorization_policy.policy] - bucket_name = "%s" - resource_instance_id = ibm_resource_instance.cos_instance.id - region_location = "us-south" - storage_class = "smart" - key_protect = ibm_kms_key.test.id - } - -`, instanceName, KeyName, cosInstanceName, bucketName) -} - -func testAccCheckIBMKmsResourceHpcsConfig(hpcsInstanceID, KeyName string) string { - return fmt.Sprintf(` - resource "ibm_kms_key" "hpcstest" { - instance_id = "%s" - key_name = "%s" - standard_key = true - force_delete = true - } - -`, hpcsInstanceID, KeyName) -} - -func testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, KeyName, expirationDate string) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kms_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - resource "ibm_kms_key" "test" { - instance_id = "${ibm_resource_instance.kms_instance.guid}" - key_name = "%s" - standard_key = true - force_delete = true - expiration_date = "%s" - } - -`, instanceName, KeyName, expirationDate) -} - -func testAccCheckIBMKmsCreateRootKeyConfig(instanceName, KeyName, expirationDate string) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kms_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - resource "ibm_kms_key" "test" { - instance_id = "${ibm_resource_instance.kms_instance.guid}" - key_name = "%s" - standard_key = false - force_delete = true - expiration_date = "%s" - } - -`, instanceName, KeyName, expirationDate) -} - -func testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, KeyName string, rotation_interval int, dual_auth_delete bool) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - policies { - rotation { - interval_month = %d - } - dual_auth_delete { - enabled = %t - } - } - } -`, instanceName, KeyName, rotation_interval, dual_auth_delete) -} - -func testAccCheckIBMKmsKeyPolicyRotation(instanceName, KeyName string, rotation_interval int) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - policies { - rotation { - interval_month = %d - } - } - } -`, instanceName, KeyName, rotation_interval) -} - -func testAccCheckIBMKmsKeyPolicyDualAuth(instanceName, KeyName string, dual_auth_delete bool) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "kp_instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - - resource "ibm_kms_key" "test" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "%s" - standard_key = false - policies { - dual_auth_delete { - enabled = %t - } - } - } -`, instanceName, KeyName, dual_auth_delete) -} diff --git a/ibm/resource_ibm_lb_vpx_ha.go b/ibm/resource_ibm_lb_vpx_ha.go deleted file mode 100644 index 10f2c6229..000000000 --- a/ibm/resource_ibm_lb_vpx_ha.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strconv" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/minsikl/netscaler-nitro-go/client" - dt "github.com/minsikl/netscaler-nitro-go/datatypes" - "github.com/minsikl/netscaler-nitro-go/op" -) - -func resourceIBMLbVpxHa() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMLbVpxHaCreate, - Read: resourceIBMLbVpxHaRead, - Update: resourceIBMLbVpxHaUpdate, - Delete: resourceIBMLbVpxHaDelete, - Exists: resourceIBMLbVpxHaExists, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - - "primary_id": { - Type: schema.TypeInt, - Required: true, - ForceNew: true, - Description: "primary ID", - }, - "secondary_id": { - Type: schema.TypeInt, - Required: true, - ForceNew: true, - Description: "Secondary ID", - }, - "stay_secondary": { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "Boolean value for stay secondary", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "Tags set for the resource", - }, - }, - } -} - -func configureHA(nClient1 *client.NitroClient, nClient2 *client.NitroClient, staySecondary bool) error { - // 1. VPX2 : Sync password - systemuserReq2 := dt.SystemuserReq{ - Systemuser: &dt.Systemuser{ - Username: op.String("root"), - Password: op.String(nClient1.Password), - }, - } - err := nClient2.Update(&systemuserReq2) - if err != nil { - return err - } - nClient2.Password = nClient1.Password - - // 2. VPX1 : Register hanode - hanodeReq1 := dt.HanodeReq{ - Hanode: &dt.Hanode{ - Id: op.String("2"), - Ipaddress: op.String(nClient2.IpAddress), - }, - } - - err = nClient1.Add(&hanodeReq1) - if err != nil { - return err - } - - // Wait 5 secs to make VPX1 a primary node. - time.Sleep(time.Second * 5) - - // 3. VPX2 : Register hanode - hanodeReq2 := dt.HanodeReq{ - Hanode: &dt.Hanode{ - Id: op.String("2"), - Ipaddress: op.String(nClient1.IpAddress), - }, - } - err = nClient2.Add(&hanodeReq2) - if err != nil { - return err - } - - // 4. VPX2 : Update STAYSECONDARY - stay := dt.HanodeReq{Hanode: &dt.Hanode{}} - if staySecondary { - stay.Hanode.Hastatus = op.String("STAYSECONDARY") - } else { - stay.Hanode.Hastatus = op.String("ENABLE") - } - err = nClient2.Update(&stay) - if err != nil { - return err - } - - // 5. VPX1 : Register rpcnode - nsrpcnode1 := dt.NsrpcnodeReq{ - Nsrpcnode: &dt.Nsrpcnode{ - Ipaddress: op.String(nClient1.IpAddress), - Password: op.String(nClient1.Password), - }, - } - err = nClient1.Update(&nsrpcnode1) - if err != nil { - return err - } - nsrpcnode1.Nsrpcnode.Ipaddress = op.String(nClient2.IpAddress) - err = nClient1.Update(&nsrpcnode1) - if err != nil { - return err - } - - // 6. VPX2 : Register rpcnode - nsrpcnode2 := dt.NsrpcnodeReq{ - Nsrpcnode: &dt.Nsrpcnode{ - Ipaddress: op.String(nClient1.IpAddress), - Password: op.String(nClient1.Password), - }, - } - err = nClient2.Update(&nsrpcnode2) - if err != nil { - return err - } - nsrpcnode2.Nsrpcnode.Ipaddress = op.String(nClient2.IpAddress) - err = nClient2.Update(&nsrpcnode2) - if err != nil { - return err - } - - // 7. VPX1 : Sync files - hafiles := dt.HafilesReq{ - Hafiles: &dt.Hafiles{ - Mode: []string{"all"}, - }, - } - err = nClient1.Add(&hafiles, "action=sync") - if err != nil { - return err - } - - return nil -} - -func deleteHA(nClient1 *client.NitroClient, nClient2 *client.NitroClient) error { - // 1. VPX2 : Delete hanode - err := nClient2.Delete(&dt.HanodeReq{}, "2") - if err != nil { - return err - } - - // 2. VPX1 : Delete hanode - err = nClient1.Delete(&dt.HanodeReq{}, "2") - if err != nil { - return err - } - return nil -} - -func parseHAId(id string) (int, int, error) { - if len(id) < 1 { - return 0, 0, fmt.Errorf("Failed to parse id : Unable to get netscaler Ids") - } - idList := strings.Split(id, ":") - if len(idList) != 2 || len(idList[0]) < 1 || len(idList[1]) < 1 { - return 0, 0, fmt.Errorf("Failed to parse id : Invalid HA ID") - } - primaryId, err := strconv.Atoi(idList[0]) - if err != nil { - return 0, 0, fmt.Errorf("Failed to parse id : Unable to get a primaryId %s", err) - } - secondaryId, err := strconv.Atoi(idList[1]) - if err != nil { - return 0, 0, fmt.Errorf("Failed to parse id : Unable to get a secondaryId %s", err) - } - return primaryId, secondaryId, nil -} - -func resourceIBMLbVpxHaCreate(d *schema.ResourceData, meta interface{}) error { - primaryId := d.Get("primary_id").(int) - secondaryId := d.Get("secondary_id").(int) - staySecondary := false - if stay, ok := d.GetOk("stay_secondary"); ok { - staySecondary = stay.(bool) - } - - nClientPrimary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), primaryId) - if err != nil { - return fmt.Errorf("Error getting primary netscaler information ID: %d", primaryId) - } - - nClientSecondary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), secondaryId) - if err != nil { - return fmt.Errorf("Error getting secondary netscaler information ID: %d", secondaryId) - } - - err = configureHA(nClientPrimary, nClientSecondary, staySecondary) - if err != nil { - return fmt.Errorf("Error configuration HA %s", err.Error()) - } - - d.SetId(fmt.Sprintf("%d:%d", primaryId, secondaryId)) - - log.Printf("[INFO] Netscaler HA ID: %s", d.Id()) - - return resourceIBMLbVpxHaRead(d, meta) -} - -func resourceIBMLbVpxHaRead(d *schema.ResourceData, meta interface{}) error { - primaryId, secondaryId, err := parseHAId(d.Id()) - if err != nil { - return fmt.Errorf("Error reading HA %s", err.Error()) - } - - nClientPrimary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), primaryId) - if err != nil { - return fmt.Errorf("Error getting primary netscaler information ID: %d", primaryId) - } - - nClientSecondary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), secondaryId) - if err != nil { - return fmt.Errorf("Error getting primary netscaler information ID: %d", primaryId) - } - - nClientSecondary.Password = nClientPrimary.Password - - res := dt.HanodeRes{} - err = nClientSecondary.Get(&res, "") - if err != nil { - fmt.Printf("Error getting hnode information : %s", err.Error()) - } - staySecondary := false - if *res.Hanode[0].Hastatus == "STAYSECONDARY" { - staySecondary = true - } - - d.Set("primary_id", primaryId) - d.Set("secondary_id", secondaryId) - d.Set("stay_secondary", staySecondary) - - return nil -} - -func resourceIBMLbVpxHaUpdate(d *schema.ResourceData, meta interface{}) error { - primaryId, secondaryId, err := parseHAId(d.Id()) - if err != nil { - return fmt.Errorf("Error deleting HA %s", err.Error()) - } - - nClientPrimary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), primaryId) - if err != nil { - return fmt.Errorf("Error getting primary netscaler information ID: %d", primaryId) - } - - nClientSecondary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), secondaryId) - if err != nil { - return fmt.Errorf("Error getting secondary netscaler information ID: %d", secondaryId) - } - - nClientSecondary.Password = nClientPrimary.Password - - staySecondary := false - if stay, ok := d.GetOk("stay_secondary"); ok { - staySecondary = stay.(bool) - } - - stay := dt.HanodeReq{Hanode: &dt.Hanode{}} - if staySecondary { - stay.Hanode.Hastatus = op.String("STAYSECONDARY") - } else { - stay.Hanode.Hastatus = op.String("ENABLE") - } - - err = nClientSecondary.Update(&stay) - if err != nil { - return err - } - - return nil -} - -func resourceIBMLbVpxHaDelete(d *schema.ResourceData, meta interface{}) error { - primaryId, secondaryId, err := parseHAId(d.Id()) - if err != nil { - return fmt.Errorf("Error deleting HA %s", err.Error()) - } - nClientPrimary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), primaryId) - if err != nil { - return fmt.Errorf("Error getting primary netscaler information ID: %d", primaryId) - } - nClientSecondary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), secondaryId) - if err != nil { - return fmt.Errorf("Error getting secondary netscaler information ID: %d", secondaryId) - } - - secondaryPassword := nClientSecondary.Password - nClientSecondary.Password = nClientPrimary.Password - err = deleteHA(nClientPrimary, nClientSecondary) - if err != nil { - return fmt.Errorf("Error deleting HA %s", err.Error()) - } - - // Restore password of the secondary VPX - systemuserReq := dt.SystemuserReq{ - Systemuser: &dt.Systemuser{ - Username: op.String("root"), - Password: op.String(secondaryPassword), - }, - } - err = nClientSecondary.Update(&systemuserReq) - if err != nil { - return err - } - - return nil -} - -func resourceIBMLbVpxHaExists(d *schema.ResourceData, meta interface{}) (bool, error) { - primaryId, _, err := parseHAId(d.Id()) - if err != nil { - return false, fmt.Errorf("Error reading HA %s", err.Error()) - } - - nClientPrimary, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), primaryId) - if err != nil { - return false, fmt.Errorf("Error getting primary netscaler information ID in Exist: %d", primaryId) - } - - res := dt.HanodeRes{} - err = nClientPrimary.Get(&res, "") - if err != nil { - return false, fmt.Errorf("Error getting hnode information in Exist: %s", err.Error()) - } - - if len(res.Hanode) < 2 { - return false, nil - } - - return true, nil -} diff --git a/ibm/resource_ibm_network_interface_sg_attachment_test.go b/ibm/resource_ibm_network_interface_sg_attachment_test.go deleted file mode 100644 index 6b8dcccc8..000000000 --- a/ibm/resource_ibm_network_interface_sg_attachment_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/softlayer/softlayer-go/services" -) - -func TestAccIBMNetworkInterfaceSGAttachment(t *testing.T) { - hostname := acctest.RandString(16) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckNetworkInterfaceSGAttachmentDestroy, - Steps: []resource.TestStep{ - { - Config: testAccTestAccIBMNetworkInterfaceSGAttachmentConfig(hostname), - Destroy: false, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "ibm_compute_vm_instance.tfuatvm", "hostname", hostname), - testAccCheckNetworkInterfaceSGAttachmentExists("ibm_network_interface_sg_attachment.ssh"), - testAccCheckNetworkInterfaceSGAttachmentExists("ibm_network_interface_sg_attachment.http"), - ), - }, - }, - }) -} - -func testAccCheckNetworkInterfaceSGAttachmentExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sgID, interfaceID, err := decomposeNetworkSGAttachmentID(rs.Primary.ID) - if err != nil { - return err - } - - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() - service := services.GetNetworkSecurityGroupService(sess) - bindings, err := service.Id(sgID).GetNetworkComponentBindings() - if err != nil { - return err - } - for _, b := range bindings { - if *b.NetworkComponentId == interfaceID { - return nil - } - } - return fmt.Errorf("No association found between security group %d and network interface %d", sgID, interfaceID) - } -} - -func testAccCheckNetworkInterfaceSGAttachmentDestroy(s *terraform.State) error { - service := services.GetNetworkSecurityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) - - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_network_interface_sg_attachment" { - continue - } - - sgID, interfaceID, err := decomposeNetworkSGAttachmentID(rs.Primary.ID) - if err != nil { - return err - } - - bindings, err := service.Id(sgID).GetNetworkComponentBindings() - if err != nil { - return err - } - for _, b := range bindings { - if *b.NetworkComponentId == interfaceID { - return fmt.Errorf("Association still exists between security group %d and network interface %d", sgID, interfaceID) - } - } - return nil - } - - return nil -} - -func testAccTestAccIBMNetworkInterfaceSGAttachmentConfig(hostname string) string { - v := fmt.Sprintf(` - data "ibm_security_group" "allowssh" { - name = "allow_ssh" - } - data "ibm_security_group" "allowhttp" { - name = "allow_http" - } - resource "ibm_compute_vm_instance" "tfuatvm" { - hostname = "%s" - domain = "tfvmuatsg.com" - os_reference_code = "DEBIAN_9_64" - datacenter = "wdc07" - network_speed = 10 - hourly_billing = true - private_network_only = false - cores = 1 - memory = 1024 - disks = [25, 10, 20] - dedicated_acct_host_only = true - local_disk = false - ipv6_enabled = true - secondary_ip_count = 4 - notes = "VM notes" - } - resource "ibm_network_interface_sg_attachment" "ssh" { - security_group_id = "${data.ibm_security_group.allowssh.id}" - network_interface_id = "${ibm_compute_vm_instance.tfuatvm.public_interface_id}" - } - resource "ibm_network_interface_sg_attachment" "http" { - security_group_id = "${data.ibm_security_group.allowhttp.id}" - network_interface_id = "${ibm_compute_vm_instance.tfuatvm.public_interface_id}" - } - `, hostname) - return v -} diff --git a/ibm/resource_ibm_org.go b/ibm/resource_ibm_org.go deleted file mode 100644 index 1e27e185c..000000000 --- a/ibm/resource_ibm_org.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/helpers" -) - -var ( - errManagerRoleAssociation = errors.New("please remove your email from the manager role and try again. " + - "This is done to avoid spurious diffs because a user creating an organization gets the manager role by default.") - - errUserRoleAssociation = errors.New("please remove your email from the user role and try again. " + - "This is done to avoid spurious diffs because a user creating an organization automatically gets the userrole by default.") -) - -func resourceIBMOrg() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMOrgCreate, - Read: resourceIBMOrgRead, - Delete: resourceIBMOrgDelete, - Update: resourceIBMOrgUpdate, - Exists: resourceIBMOrgExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": { - Description: "Org name, for example myorg@domain", - Type: schema.TypeString, - Required: true, - }, - "org_quota_definition_guid": { - Description: "Org quota guid", - Type: schema.TypeString, - Computed: true, - Optional: true, - }, - "billing_managers": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have billing manager role in this org, ex - user@example.com", - }, - "managers": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have manager role in this org, ex - user@example.com", - }, - "auditors": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have auditor role in this org, ex - user@example.com", - }, - "users": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have user role in this org, ex - user@example.com", - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - }, - } -} -func resourceIBMOrgCreate(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - orgAPI := cfAPI.Organizations() - orgName := d.Get("name").(string) - req := mccpv2.OrgCreateRequest{ - Name: orgName, - } - if orgQuotaDefinitionGUID, ok := d.GetOk("org_quota_definition_guid"); ok { - req.OrgQuotaDefinitionGUID = orgQuotaDefinitionGUID.(string) - } - orgFields, err := orgAPI.Create(req) - if err != nil { - return fmt.Errorf("Error creating organisation: %s", err) - } - orgGUID := orgFields.Metadata.GUID - d.SetId(orgGUID) - - return resourceIBMOrgUpdate(d, meta) -} - -func resourceIBMOrgRead(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - orgAPI := cfAPI.Organizations() - id := d.Id() - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - orgOwnerID := userDetails.userEmail - orgFields, err := orgAPI.Get(id) - if err != nil { - return fmt.Errorf("Error retrieving organisation: %s", err) - } - d.Set("name", orgFields.Entity.Name) - billingManager, err := orgAPI.ListBillingManager(id) - if err != nil { - return fmt.Errorf("Error retrieving billing manager in the org: %s", err) - } - managers, err := orgAPI.ListManager(id) - if err != nil { - return fmt.Errorf("Error retrieving managers in the org: %s", err) - } - auditors, err := orgAPI.ListAuditors(id) - if err != nil { - return fmt.Errorf("Error retrieving auditors in space: %s", err) - } - users, err := orgAPI.ListUsers(id) - if err != nil { - return fmt.Errorf("Error retrieving users in space: %s", err) - } - if len(auditors) > 0 { - d.Set("auditors", flattenOrgRole(auditors, "")) - } - if len(managers) > 0 { - d.Set("managers", flattenOrgRole(managers, orgOwnerID)) - } - if len(billingManager) > 0 { - d.Set("billing_managers", flattenOrgRole(billingManager, "")) - } - if len(users) > 0 { - d.Set("users", flattenOrgRole(users, orgOwnerID)) - } - if orgFields.Entity.OrgQuotaDefinitionGUID != "" { - d.Set("org_quota_definition_guid", orgFields.Entity.OrgQuotaDefinitionGUID) - } - return nil -} - -func resourceIBMOrgUpdate(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - orgAPI := cfAPI.Organizations() - id := d.Id() - - req := mccpv2.OrgUpdateRequest{} - if d.HasChange("name") { - req.Name = helpers.String(d.Get("name").(string)) - } - _, err = orgAPI.Update(id, req) - if err != nil { - return fmt.Errorf("Error updating organisation: %s", err) - } - err = updateOrgBillingManagers(orgAPI, id, d) - if err != nil { - return err - } - err = updateOrgManagers(meta, id, d) - if err != nil { - return err - } - err = updateOrgAuditors(orgAPI, id, d) - if err != nil { - return err - } - err = updateOrgUsers(meta, id, d) - if err != nil { - return err - } - - return resourceIBMOrgRead(d, meta) -} - -func resourceIBMOrgDelete(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - orgAPI := cfAPI.Organizations() - id := d.Id() - err = orgAPI.Delete(id, false) - if err != nil { - return fmt.Errorf("Error deleting organisation: %s", err) - } - d.SetId("") - return nil -} - -func resourceIBMOrgExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return false, err - } - id := d.Id() - org, err := cfClient.Organizations().Get(id) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - return org.Metadata.GUID == id, nil -} - -func updateOrgBillingManagers(api mccpv2.Organizations, orgGUID string, d *schema.ResourceData) error { - if !d.HasChange("billing_managers") { - return nil - } - var remove, add []string - o, n := d.GetChange("billing_managers") - os := o.(*schema.Set) - ns := n.(*schema.Set) - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - if len(add) > 0 { - for _, d := range add { - _, err := api.AssociateBillingManager(orgGUID, d) - if err != nil { - return fmt.Errorf("Error associating billing manager (%s) with org %s : %s", d, orgGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateBillingManager(orgGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating billing manager (%s) with org %s : %s", d, orgGUID, err) - } - } - } - return nil -} - -func updateOrgManagers(meta interface{}, orgGUID string, d *schema.ResourceData) error { - if !d.HasChange("managers") { - return nil - } - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - api := cfAPI.Organizations() - - var remove, add []string - o, n := d.GetChange("managers") - os := o.(*schema.Set) - ns := n.(*schema.Set) - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - orgOwnerID := userDetails.userEmail - - if len(add) > 0 { - for _, d := range add { - if d == orgOwnerID { - return fmt.Errorf("Error associating user (%s) with manager role, %v", d, errManagerRoleAssociation) - } - _, err := api.AssociateManager(orgGUID, d) - if err != nil { - return fmt.Errorf("Error associating manager (%s) with org %s : %s", d, orgGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateManager(orgGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating manager (%s) with org %s : %s", d, orgGUID, err) - } - } - } - return nil -} -func updateOrgAuditors(api mccpv2.Organizations, orgGUID string, d *schema.ResourceData) error { - if !d.HasChange("auditors") { - return nil - } - var remove, add []string - o, n := d.GetChange("auditors") - os := o.(*schema.Set) - ns := n.(*schema.Set) - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - if len(add) > 0 { - for _, d := range add { - _, err := api.AssociateAuditor(orgGUID, d) - if err != nil { - return fmt.Errorf("Error associating auditor (%s) with org %s : %s", d, orgGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateAuditor(orgGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating auditor (%s) with org %s : %s", d, orgGUID, err) - } - } - } - return nil -} - -func updateOrgUsers(meta interface{}, orgGUID string, d *schema.ResourceData) error { - if !d.HasChange("users") { - return nil - } - var remove, add []string - o, n := d.GetChange("users") - os := o.(*schema.Set) - ns := n.(*schema.Set) - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - cfAPI, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - api := cfAPI.Organizations() - if len(add) > 0 { - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - orgOwnerID := userDetails.userEmail - for _, d := range add { - if d == orgOwnerID { - return fmt.Errorf("Error associating user (%s) with User role, %v", d, errUserRoleAssociation) - } - _, err := api.AssociateUser(orgGUID, d) - if err != nil { - return fmt.Errorf("Error associating user (%s) with org %s : %s", d, orgGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateUser(orgGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating user (%s) with org %s : %s", d, orgGUID, err) - } - } - } - return nil -} diff --git a/ibm/resource_ibm_pi_capture.go b/ibm/resource_ibm_pi_capture.go deleted file mode 100644 index 949b71dc3..000000000 --- a/ibm/resource_ibm_pi_capture.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "log" - "time" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_p_vm_instances" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMPICapture() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPICaptureCreate, - Read: resourceIBMPICaptureRead, - Update: resourceIBMPICaptureUpdate, - Delete: resourceIBMPICaptureDelete, - //Exists: resourceIBMPICaptureExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: " Cloud Instance ID - This is the service_instance_id.", - }, - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Instance Name of the Power VM", - }, - - helpers.PIInstanceCaptureName: { - Type: schema.TypeString, - Required: true, - Description: "Name of the capture to create. Note : this must be unique", - }, - - helpers.PIInstanceCaptureDestination: { - Type: schema.TypeString, - Required: true, - Description: "Name of destination to store the image capture to", - ValidateFunc: validateAllowedStringValue([]string{"image-catalog", "cloud-storage", "both"}), - }, - - helpers.PIInstanceCaptureVolumeIds: { - Type: schema.TypeString, - Optional: true, - Description: "List of volume names that need to be passed in the input", - }, - - helpers.PIInstanceCaptureCloudStorageRegion: { - Type: schema.TypeString, - Optional: true, - Description: "List of Regions to use", - ValidateFunc: validateAllowedStringValue([]string{"us-south", "us-east", "us-de"}), - }, - - helpers.PIInstanceCaptureCloudStorageAccessKey: { - Type: schema.TypeString, - Optional: true, - Description: "Name of Cloud Storage Access Key", - }, - helpers.PIInstanceCaptureCloudStorageSecretKey: { - Type: schema.TypeString, - Optional: true, - Description: "Name of the Cloud Storage Secret Key", - }, - helpers.PIInstanceCaptureCloudStorageImagePath: { - Type: schema.TypeString, - Optional: true, - Description: "Name of the Image Path", - }, - }, - } -} - -func resourceIBMPICaptureCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - name := d.Get(helpers.PIInstanceName).(string) - capturename := d.Get(helpers.PIInstanceCaptureName).(string) - capturedestination := d.Get(helpers.PIInstanceCaptureDestination).(string) - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - - cloudstorageImagePath := d.Get(helpers.PIInstanceCaptureCloudStorageImagePath).(string) - if cloudstorageImagePath == "" { - log.Printf("CloudImagePath is not provided") - - } - - cloudstorageregion := d.Get(helpers.PIInstanceCaptureCloudStorageRegion).(string) - if cloudstorageregion == "" { - log.Printf("CloudStorageRegion is not provided") - } - - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - body := &models.PVMInstanceCapture{ - CaptureDestination: ptrToString(capturedestination), - CaptureName: ptrToString(capturename), - CaptureVolumeIds: nil, - CloudStorageAccessKey: "", - CloudStorageImagePath: cloudstorageImagePath, - //CloudStorageRegion: ptrToString(cloudstorageregion), - CloudStorageSecretKey: "", - } - - captureinfo, err := client.CaptureInstanceToImageCatalog(name, powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesCapturePostParams{ - Body: body, - }, createTimeOut) - - log.Printf("Printing the data from the capture %+v", &captureinfo) - - if err != nil { - return errors.New("The capture cannot be performed") - } - - // If this is an image catalog then we need to check what the status is - - imageClient := st.NewIBMPIImageClient(sess, powerinstanceid) - imagedata, err := imageClient.Get(d.Get(helpers.PIInstanceCaptureName).(string), powerinstanceid) - - if err != nil { - return err - } - log.Printf("Printing the data %s - %s", *imagedata.ImageID, imagedata.State) - - _, err = isWaitForImageCaptureAvailable(client, *imagedata.ImageID, powerinstanceid, d.Timeout(schema.TimeoutCreate)) - - //_, err = isWaitForIBMPIVolumeAvailable(client, d.Id(), powerinstanceid, d.Timeout(schema.TimeoutCreate)) - //if err != nil { - // return err - //} - return nil - //return resourceIBMPIVolumeAttachRead(d, meta) - -} - -func resourceIBMPICaptureRead(d *schema.ResourceData, meta interface{}) error { - - return nil -} - -func resourceIBMPICaptureUpdate(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - name := "" - if d.HasChange(helpers.PIVolumeAttachName) { - name = d.Get(helpers.PIVolumeAttachName).(string) - } - - size := float64(d.Get(helpers.PIVolumeSize).(float64)) - shareable := bool(d.Get(helpers.PIVolumeShareable).(bool)) - - volrequest, err := client.Update(d.Id(), name, size, shareable, powerinstanceid, postTimeOut) - if err != nil { - return err - } - - _, err = isWaitForIBMPIVolumeAvailable(client, *volrequest.VolumeID, powerinstanceid, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - - return resourceIBMPIVolumeRead(d, meta) -} - -func resourceIBMPICaptureDelete(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - err := client.Delete(d.Id(), powerinstanceid, deleteTimeOut) - if err != nil { - return err - } - - // wait for power volume states to be back as available. if it's attached it will be in-use - d.SetId("") - return nil -} - -func isWaitForImageCaptureAvailable(client *st.IBMPIInstanceClient, s string, s2 string, timeout time.Duration) (interface{}, error) { - - return nil, nil -} diff --git a/ibm/resource_ibm_pi_image.go b/ibm/resource_ibm_pi_image.go deleted file mode 100644 index 8b57dbfae..000000000 --- a/ibm/resource_ibm_pi_image.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func resourceIBMPIImage() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIImageCreate, - Read: resourceIBMPIImageRead, - Update: resourceIBMPIImageUpdate, - Delete: resourceIBMPIImageDelete, - Exists: resourceIBMPIImageExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PIImageName: { - Type: schema.TypeString, - Required: true, - Description: "Image name", - DiffSuppressFunc: applyOnce, - }, - - helpers.PIInstanceImageName: { - Type: schema.TypeString, - Required: true, - Description: "Instance image name", - DiffSuppressFunc: applyOnce, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "PI cloud instance ID", - }, - - // Computed Attribute - - "image_id": { - Type: schema.TypeString, - Computed: true, - Description: "Image ID", - }, - }, - } -} - -func resourceIBMPIImageCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - log.Printf("Failed to get the session") - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - name := d.Get(helpers.PIImageName).(string) - imageid := d.Get(helpers.PIInstanceImageName).(string) - - client := st.NewIBMPIImageClient(sess, powerinstanceid) - - imageResponse, err := client.Create(name, imageid, powerinstanceid) - if err != nil { - return err - } - - IBMPIImageID := imageResponse.ImageID - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, *IBMPIImageID)) - - _, err = isWaitForIBMPIImageAvailable(client, *IBMPIImageID, d.Timeout(schema.TimeoutCreate), powerinstanceid) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return err - } - - return resourceIBMPIImageRead(d, meta) -} - -func resourceIBMPIImageRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - imageC := st.NewIBMPIImageClient(sess, powerinstanceid) - imagedata, err := imageC.Get(parts[1], powerinstanceid) - - if err != nil { - return err - } - - imageid := *imagedata.ImageID - d.Set("image_id", imageid) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil - -} - -func resourceIBMPIImageUpdate(data *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMPIImageDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - imageC := st.NewIBMPIImageClient(sess, powerinstanceid) - err = imageC.Delete(parts[1], powerinstanceid) - - if err != nil { - return err - } - d.SetId("") - return nil - -} - -func resourceIBMPIImageExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of powerInstanceID/ImageID", d.Id()) - } - name := parts[1] - powerinstanceid := parts[0] - client := st.NewIBMPIImageClient(sess, powerinstanceid) - - image, err := client.Get(parts[1], powerinstanceid) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - return *image.ImageID == name, nil -} - -func isWaitForIBMPIImageAvailable(client *st.IBMPIImageClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - log.Printf("Waiting for Power Image (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIImageQueStatus}, - Target: []string{helpers.PIImageActiveStatus}, - Refresh: isIBMPIImageRefreshFunc(client, id, powerinstanceid), - Timeout: timeout, - Delay: 20 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isIBMPIImageRefreshFunc(client *st.IBMPIImageClient, id, powerinstanceid string) resource.StateRefreshFunc { - - log.Printf("Calling the isIBMPIImageRefreshFunc Refresh Function....") - return func() (interface{}, string, error) { - image, err := client.Get(id, powerinstanceid) - if err != nil { - return nil, "", err - } - - if image.State == "active" { - - return image, helpers.PIImageActiveStatus, nil - } - - return image, helpers.PIImageQueStatus, nil - } -} diff --git a/ibm/resource_ibm_pi_image_test.go b/ibm/resource_ibm_pi_image_test.go deleted file mode 100644 index 936089b63..000000000 --- a/ibm/resource_ibm_pi_image_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPIImagebasic(t *testing.T) { - - name := fmt.Sprintf("tf-pi-image-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIImageDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIImageConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIImageExists("ibm_pi_image.power_image"), - resource.TestCheckResourceAttr( - "ibm_pi_image.power_image", "pi_image_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPIImageDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_image" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPIImageClient(sess, powerinstanceid) - _, err = networkC.Get(parts[1], powerinstanceid) - if err == nil { - return fmt.Errorf("PI Image still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPIImageExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIImageClient(sess, powerinstanceid) - - image, err := client.Get(parts[1], powerinstanceid) - if err != nil { - return err - } - parts[1] = *image.ImageID - return nil - - } -} - -func testAccCheckIBMPIImageConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_pi_image" "power_image" { - pi_image_name = "%s" - pi_image_id = "cfc02954-8f6f-4e6b-96ae-40b24c90bd54" - pi_cloud_instance_id = "%s" - } - `, name, pi_cloud_instance_id) -} diff --git a/ibm/resource_ibm_pi_instance.go b/ibm/resource_ibm_pi_instance.go deleted file mode 100644 index 58a385024..000000000 --- a/ibm/resource_ibm_pi_instance.go +++ /dev/null @@ -1,1127 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "encoding/base64" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_p_vm_instances" - "github.com/IBM-Cloud/power-go-client/power/models" -) - -const ( - createTimeOut = 120 * time.Second - updateTimeOut = 120 * time.Second - postTimeOut = 60 * time.Second - getTimeOut = 60 * time.Second - deleteTimeOut = 60 * time.Second - //Added timeout values for warning and active status - warningTimeOut = 30 * time.Second - activeTimeOut = 2 * time.Minute - // power service instance capabilities - CUSTOM_VIRTUAL_CORES = "custom-virtualcores" - PIInstanceNetwork = "pi_network" - PIInstanceStoragePool = "pi_storage_pool" -) - -func resourceIBMPIInstance() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIInstanceCreate, - Read: resourceIBMPIInstanceRead, - Update: resourceIBMPIInstanceUpdate, - Delete: resourceIBMPIInstanceDelete, - Exists: resourceIBMPIInstanceExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(120 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "This is the Power Instance id that is assigned to the account", - }, - "status": { - Type: schema.TypeString, - Computed: true, - Description: "PI instance status", - }, - "pi_migratable": { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "set to true to enable migration of the PI instance", - }, - "migratable": { - Type: schema.TypeBool, - Computed: true, - Description: "set to true to enable migration of the PI instance", - Deprecated: "This field is deprecated, Use pi_migratable instead.", - }, - "min_processors": { - Type: schema.TypeFloat, - Computed: true, - Description: "Minimum number of the CPUs", - }, - "min_memory": { - Type: schema.TypeFloat, - Computed: true, - Description: "Minimum memory", - }, - "max_processors": { - Type: schema.TypeFloat, - Computed: true, - Description: "Maximum number of processors", - }, - "max_memory": { - Type: schema.TypeFloat, - Computed: true, - Description: "Maximum memory size", - }, - helpers.PIInstanceNetworkIds: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of Networks that have been configured for the account", - DiffSuppressFunc: applyOnce, - Deprecated: "Use pi_network instead", - ConflictsWith: []string{PIInstanceNetwork}, - }, - - helpers.PIInstanceVolumeIds: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - DiffSuppressFunc: applyOnce, - Description: "List of PI volumes", - }, - - helpers.PIInstanceUserData: { - Type: schema.TypeString, - Optional: true, - Description: "Base64 encoded data to be passed in for invoking a cloud init script", - }, - - helpers.PIInstanceStorageType: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Storage type for server deployment", - }, - PIInstanceStoragePool: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Storage Pool for server deployment; if provided then pi_affinity_policy and pi_storage_type will be ignored", - }, - PIAffinityPolicy: { - Type: schema.TypeString, - Optional: true, - Description: "Affinity policy for pvm instance being created; ignored if pi_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", - ValidateFunc: validateAllowedStringValue([]string{"affinity", "anti-affinity"}), - }, - PIAffinityVolume: { - Type: schema.TypeString, - Optional: true, - Description: "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", - ConflictsWith: []string{PIAffinityInstance}, - }, - PIAffinityInstance: { - Type: schema.TypeString, - Optional: true, - Description: "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", - ConflictsWith: []string{PIAffinityVolume}, - }, - PIAntiAffinityVolumes: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", - ConflictsWith: []string{PIAntiAffinityInstances}, - }, - PIAntiAffinityInstances: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", - ConflictsWith: []string{PIAntiAffinityVolumes}, - }, - - helpers.PIInstanceStorageConnection: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"vSCSI"}), - Description: "Storage Connectivity Group for server deployment", - }, - PIInstanceNetwork: { - Type: schema.TypeList, - // TODO: Once pi_network_ids is removed this will be a required field - Optional: true, - ConflictsWith: []string{helpers.PIInstanceNetworkIds}, - Computed: true, - DiffSuppressFunc: applyOnce, - Description: "List of one or more networks to attach to the instance", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "ip_address": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "mac_address": { - Type: schema.TypeString, - Computed: true, - }, - "network_id": { - Type: schema.TypeString, - Required: true, - }, - "network_name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "external_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "addresses": { - Deprecated: "Use pi_network instead", - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "ip": { - Type: schema.TypeString, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "network_id": { - Type: schema.TypeString, - Computed: true, - }, - "network_name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "external_ip": { - Type: schema.TypeString, - Computed: true, - }, - /*"version": { - Type: schema.TypeFloat, - Computed: true, - },*/ - }, - }, - }, - - "health_status": { - Type: schema.TypeString, - Computed: true, - Description: "PI Instance health status", - }, - "instance_id": { - Type: schema.TypeString, - Computed: true, - Description: "Instance ID", - }, - "pin_policy": { - Type: schema.TypeString, - Computed: true, - Description: "PIN Policy of the Instance", - }, - helpers.PIInstanceImageName: { - Type: schema.TypeString, - Required: true, - Description: "PI instance image name", - }, - helpers.PIInstanceProcessors: { - Type: schema.TypeFloat, - Required: true, - Description: "Processors count", - }, - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "PI Instance name", - }, - helpers.PIInstanceProcType: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"dedicated", "shared", "capped"}), - Description: "Instance processor type", - }, - helpers.PIInstanceSSHKeyName: { - Type: schema.TypeString, - Required: true, - Description: "SSH key name", - }, - helpers.PIInstanceMemory: { - Type: schema.TypeFloat, - Required: true, - Description: "Memory size", - }, - helpers.PIInstanceSystemType: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"s922", "e880", "e980"}), - Description: "PI Instance system type", - }, - helpers.PIInstanceReplicants: { - Type: schema.TypeFloat, - Optional: true, - Default: 1.0, - Description: "PI Instance replicas count", - }, - helpers.PIInstanceReplicationPolicy: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"affinity", "anti-affinity", "none"}), - Default: "none", - Description: "Replication policy for the PI Instance", - }, - helpers.PIInstanceReplicationScheme: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"prefix", "suffix"}), - Default: "suffix", - Description: "Replication scheme", - }, - helpers.PIInstanceProgress: { - Type: schema.TypeFloat, - Computed: true, - Description: "Progress of the operation", - }, - helpers.PIInstancePinPolicy: { - Type: schema.TypeString, - Optional: true, - Description: "Pin Policy of the instance", - Default: "none", - ValidateFunc: validateAllowedStringValue([]string{"none", "soft", "hard"}), - }, - - // "reboot_for_resource_change": { - // Type: schema.TypeString, - // Optional: true, - // Description: "Flag to be passed for CPU/Memory changes that require a reboot to take effect", - // }, - "operating_system": { - Type: schema.TypeString, - Computed: true, - Description: "Operating System", - }, - "os_type": { - Type: schema.TypeString, - Computed: true, - Description: "OS Type", - }, - helpers.PIInstanceHealthStatus: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"OK", "WARNING"}), - Default: "OK", - Description: "Allow the user to set the status of the lpar so that they can connect to it faster", - }, - helpers.PIVirtualCoresAssigned: { - Type: schema.TypeInt, - Optional: true, - Computed: true, - Description: "Virtual Cores Assigned to the PVMInstance", - }, - "max_virtual_cores": { - Type: schema.TypeInt, - Computed: true, - Description: "Maximum Virtual Cores Assigned to the PVMInstance", - }, - "min_virtual_cores": { - Type: schema.TypeInt, - Computed: true, - Description: "Minimum Virtual Cores Assigned to the PVMInstance", - }, - }, - } -} - -func resourceIBMPIInstanceCreate(d *schema.ResourceData, meta interface{}) error { - log.Printf("Now in the PowerVMCreate") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - name := d.Get(helpers.PIInstanceName).(string) - sshkey := d.Get(helpers.PIInstanceSSHKeyName).(string) - mem := d.Get(helpers.PIInstanceMemory).(float64) - procs := d.Get(helpers.PIInstanceProcessors).(float64) - systype := d.Get(helpers.PIInstanceSystemType).(string) - - var pvmNetworks []*models.PVMInstanceAddNetwork - // Either pi_network_ids or pi_network is provided - // TODO: Once pi_network_ids is removed pi_network will be a required field - if v, ok := d.GetOk(helpers.PIInstanceNetworkIds); ok { - networks := expandStringList(v.([]interface{})) - pvmNetworks = buildPVMNetworks(networks) - } - if v, ok := d.GetOk(PIInstanceNetwork); ok { - networksMap := v.([]interface{}) - pvmNetworks = expandPVMNetworks(networksMap) - } - if len(pvmNetworks) <= 0 { - return fmt.Errorf("one of pi_network_ids or pi_network must be configured") - } - - var volids []string - if v, ok := d.GetOk(helpers.PIInstanceVolumeIds); ok { - volids = expandStringList((v.(*schema.Set)).List()) - } - var replicants float64 - if r, ok := d.GetOk(helpers.PIInstanceReplicants); ok { - replicants = r.(float64) - } - var replicationpolicy string - if r, ok := d.GetOk(helpers.PIInstanceReplicationPolicy); ok { - replicationpolicy = r.(string) - } - var replicationNamingScheme string - if r, ok := d.GetOk(helpers.PIInstanceReplicationScheme); ok { - replicationNamingScheme = r.(string) - } - var migratable bool - if m, ok := d.GetOk("pi_migratable"); ok { - migratable = m.(bool) - } - imageid := d.Get(helpers.PIInstanceImageName).(string) - processortype := d.Get(helpers.PIInstanceProcType).(string) - - var pinpolicy string - if p, ok := d.GetOk(helpers.PIInstancePinPolicy); ok { - pinpolicy = p.(string) - if pinpolicy == "" { - pinpolicy = "none" - } - } - var instanceReadyStatus string - if r, ok := d.GetOk(helpers.PIInstanceHealthStatus); ok { - instanceReadyStatus = r.(string) - } - - var userData string - if u, ok := d.GetOk(helpers.PIInstanceUserData); ok { - userData = u.(string) - } - err = checkBase64(userData) - if err != nil { - log.Printf("Data is not base64 encoded") - return err - } - - //publicinterface := d.Get(helpers.PIInstancePublicNetwork).(bool) - body := &models.PVMInstanceCreate{ - //NetworkIds: networks, - Processors: &procs, - Memory: &mem, - ServerName: ptrToString(name), - SysType: systype, - KeyPairName: sshkey, - ImageID: ptrToString(imageid), - ProcType: ptrToString(processortype), - Replicants: replicants, - UserData: userData, - ReplicantNamingScheme: ptrToString(replicationNamingScheme), - ReplicantAffinityPolicy: ptrToString(replicationpolicy), - Networks: pvmNetworks, - Migratable: &migratable, - } - if len(volids) > 0 { - body.VolumeIds = volids - } - if d.Get(helpers.PIInstancePinPolicy) == "soft" || d.Get(helpers.PIInstancePinPolicy) == "hard" { - body.PinPolicy = models.PinPolicy(pinpolicy) - } - - var assignedVirtualCores int64 - if a, ok := d.GetOk(helpers.PIVirtualCoresAssigned); ok { - assignedVirtualCores = int64(a.(int)) - body.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} - } - - if st, ok := d.GetOk(helpers.PIInstanceStorageType); ok { - body.StorageType = st.(string) - } - if sp, ok := d.GetOk(PIInstanceStoragePool); ok { - body.StoragePool = sp.(string) - } - - if ap, ok := d.GetOk(PIAffinityPolicy); ok { - policy := ap.(string) - affinity := &models.StorageAffinity{ - AffinityPolicy: &policy, - } - - if policy == "affinity" { - if av, ok := d.GetOk(PIAffinityVolume); ok { - afvol := av.(string) - affinity.AffinityVolume = &afvol - } - if ai, ok := d.GetOk(PIAffinityInstance); ok { - afins := ai.(string) - affinity.AffinityPVMInstance = &afins - } - } else { - if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { - afvols := expandStringList(avs.([]interface{})) - affinity.AntiAffinityVolumes = afvols - } - if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { - afinss := expandStringList(ais.([]interface{})) - affinity.AntiAffinityPVMInstances = afinss - } - } - body.StorageAffinity = affinity - } - - if sc, ok := d.GetOk(helpers.PIInstanceStorageConnection); ok { - body.StorageConnection = sc.(string) - } - - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - pvm, err := client.Create(&p_cloud_p_vm_instances.PcloudPvminstancesPostParams{ - Body: body, - }, powerinstanceid, createTimeOut) - - if err != nil { - return fmt.Errorf("failed to provision %s", err) - } - - var pvminstanceids []string - if replicants > 1 { - log.Printf("We are in a multi create mode") - for i := 0; i < int(replicants); i++ { - truepvmid := (*pvm)[i].PvmInstanceID - pvminstanceids = append(pvminstanceids, fmt.Sprintf("%s", *truepvmid)) - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, *truepvmid)) - } - d.SetId(strings.Join(pvminstanceids, "/")) - } else { - truepvmid := (*pvm)[0].PvmInstanceID - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, *truepvmid)) - pvminstanceids = append(pvminstanceids, *truepvmid) - } - - for ids := range pvminstanceids { - _, err = isWaitForPIInstanceAvailable(client, pvminstanceids[ids], d.Timeout(schema.TimeoutCreate), powerinstanceid, instanceReadyStatus) - if err != nil { - return err - } - } - - return resourceIBMPIInstanceRead(d, meta) - -} - -func resourceIBMPIInstanceRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - powerC := st.NewIBMPIInstanceClient(sess, powerinstanceid) - powervmdata, err := powerC.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return fmt.Errorf("failed to get the instance %v", err) - } - - d.Set(helpers.PIInstanceMemory, powervmdata.Memory) - d.Set(helpers.PIInstanceProcessors, powervmdata.Processors) - if powervmdata.Status != nil { - d.Set("status", powervmdata.Status) - } - d.Set(helpers.PIInstanceProcType, powervmdata.ProcType) - if powervmdata.Migratable != nil { - d.Set("pi_migratable", powervmdata.Migratable) - } - d.Set("min_processors", powervmdata.Minproc) - d.Set(helpers.PIInstanceProgress, powervmdata.Progress) - if powervmdata.StorageType != nil { - d.Set(helpers.PIInstanceStorageType, powervmdata.StorageType) - } - d.Set(helpers.PIInstanceStoragePool, powervmdata.StoragePool) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - d.Set("instance_id", powervmdata.PvmInstanceID) - d.Set(helpers.PIInstanceName, powervmdata.ServerName) - d.Set(helpers.PIInstanceImageName, powervmdata.ImageID) - if _, ok := d.GetOk(helpers.PIInstanceNetworkIds); ok { - var networks []string - networks = make([]string, 0) - if powervmdata.Networks != nil { - for _, n := range powervmdata.Networks { - if n != nil { - networks = append(networks, n.NetworkID) - } - } - } - d.Set(helpers.PIInstanceNetworkIds, networks) - } else { - networksMap := []map[string]interface{}{} - if powervmdata.Networks != nil { - for _, n := range powervmdata.Networks { - if n != nil { - v := map[string]interface{}{ - "ip_address": n.IPAddress, - "mac_address": n.MacAddress, - "network_id": n.NetworkID, - "network_name": n.NetworkName, - "type": n.Type, - "external_ip": n.ExternalIP, - } - networksMap = append(networksMap, v) - } - } - } - d.Set(PIInstanceNetwork, networksMap) - } - - if powervmdata.VolumeIds != nil { - d.Set(helpers.PIInstanceVolumeIds, powervmdata.VolumeIds) - } - d.Set(helpers.PIInstanceSystemType, powervmdata.SysType) - d.Set("min_memory", powervmdata.Minmem) - d.Set("max_processors", powervmdata.Maxproc) - d.Set("max_memory", powervmdata.Maxmem) - d.Set("pin_policy", powervmdata.PinPolicy) - d.Set("operating_system", powervmdata.OperatingSystem) - if powervmdata.OsType != nil { - d.Set("os_type", powervmdata.OsType) - } - - if powervmdata.Addresses != nil { - pvmaddress := make([]map[string]interface{}, len(powervmdata.Addresses)) - for i, pvmip := range powervmdata.Addresses { - log.Printf("Now entering the powervm address space....") - - p := make(map[string]interface{}) - p["ip"] = pvmip.IP - p["network_name"] = pvmip.NetworkName - p["network_id"] = pvmip.NetworkID - p["macaddress"] = pvmip.MacAddress - p["type"] = pvmip.Type - p["external_ip"] = pvmip.ExternalIP - pvmaddress[i] = p - } - d.Set("addresses", pvmaddress) - } - - if powervmdata.Health != nil { - d.Set("health_status", powervmdata.Health.Status) - } - if powervmdata.VirtualCores.Assigned != nil { - d.Set(helpers.PIVirtualCoresAssigned, powervmdata.VirtualCores.Assigned) - } - if &powervmdata.VirtualCores.Max != nil { - d.Set("max_virtual_cores", powervmdata.VirtualCores.Max) - } - if &powervmdata.VirtualCores.Min != nil { - d.Set("min_virtual_cores", powervmdata.VirtualCores.Min) - } - - return nil - -} - -func resourceIBMPIInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - - name := d.Get(helpers.PIInstanceName).(string) - mem := d.Get(helpers.PIInstanceMemory).(float64) - procs := d.Get(helpers.PIInstanceProcessors).(float64) - processortype := d.Get(helpers.PIInstanceProcType).(string) - assignedVirtualCores := int64(d.Get(helpers.PIVirtualCoresAssigned).(int)) - - if d.Get("health_status") == "WARNING" { - return fmt.Errorf("the operation cannot be performed when the lpar health in the WARNING State") - } - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return fmt.Errorf("failed to get the session from the IBM Cloud Service") - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - // Check if cloud instance is capable of changing virtual cores - cloudInstanceClient := st.NewIBMPICloudInstanceClient(sess, powerinstanceid) - cloudInstance, err := cloudInstanceClient.Get(powerinstanceid) - if err != nil { - return fmt.Errorf("failed to get cloud instance %v", err) - } - cores_enabled := checkCloudInstanceCapability(cloudInstance, CUSTOM_VIRTUAL_CORES) - - if d.HasChange(helpers.PIInstanceName) { - body := &models.PVMInstanceUpdate{ - ServerName: name, - } - _, err = client.Update(parts[1], powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesPutParams{Body: body}, updateTimeOut) - if err != nil { - return fmt.Errorf("failed to update the lpar with the change for name %s", err) - } - _, err = isWaitForPIInstanceAvailable(client, parts[1], d.Timeout(schema.TimeoutUpdate), powerinstanceid, "OK") - if err != nil { - return err - } - } - - if d.HasChange(helpers.PIInstanceProcType) { - - // Stop the lpar - if d.Get("status") == "SHUTOFF" { - log.Printf("the lpar is in the shutoff state. Nothing to do . Moving on ") - } else { - err := stopLparForResourceChange(client, parts[1], powerinstanceid, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return err - } - } - - // Modify - log.Printf("At this point the lpar should be off. Executing the Processor Update Change") - updatebody := &models.PVMInstanceUpdate{ProcType: processortype} - if cores_enabled == true { - log.Printf("support for %s is enabled", CUSTOM_VIRTUAL_CORES) - updatebody.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} - } else { - log.Printf("no virtual cores support enabled for this customer..") - } - _, err = client.Update(parts[1], powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesPutParams{Body: updatebody}, updateTimeOut) - if err != nil { - return fmt.Errorf("failed to perform the modify operation on the pvm instance %v", err) - } - _, err = isWaitForPIInstanceStopped(client, parts[1], d.Timeout(schema.TimeoutUpdate), powerinstanceid) - if err != nil { - return err - } - - // Start the lpar - err := startLparAfterResourceChange(client, parts[1], powerinstanceid, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return err - } - } - - // Virtual core will be updated only if service instance capability is enabled - if d.HasChange(helpers.PIVirtualCoresAssigned) { - body := &models.PVMInstanceUpdate{ - VirtualCores: &models.VirtualCores{Assigned: &assignedVirtualCores}, - } - _, err = client.Update(parts[1], powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesPutParams{Body: body}, updateTimeOut) - if err != nil { - return fmt.Errorf("failed to update the lpar with the change for virtual cores %s", err) - } - _, err = isWaitForPIInstanceAvailable(client, parts[1], d.Timeout(schema.TimeoutUpdate), powerinstanceid, "OK") - if err != nil { - return err - } - } - - // Start of the change for Memory and Processors - if d.HasChange(helpers.PIInstanceMemory) || d.HasChange(helpers.PIInstanceProcessors) || d.HasChange("pi_migratable") { - - maxMemLpar := d.Get("max_memory").(float64) - maxCPULpar := d.Get("max_processors").(float64) - //log.Printf("the required memory is set to [%d] and current max memory is set to [%d] ", int(mem), int(maxMemLpar)) - - if mem > maxMemLpar || procs > maxCPULpar { - log.Printf("Will require a shutdown to perform the change") - } else { - log.Printf("maxMemLpar is set to %f", maxMemLpar) - log.Printf("maxCPULpar is set to %f", maxCPULpar) - } - - //if d.GetOkExists("reboot_for_resource_change") - - if mem > maxMemLpar || procs > maxCPULpar { - - err = performChangeAndReboot(client, parts[1], powerinstanceid, mem, procs) - if err != nil { - return err - } - - } else { - - body := &models.PVMInstanceUpdate{ - Memory: mem, - Processors: procs, - } - if m, ok := d.GetOk("pi_migratable"); ok { - migratable := m.(bool) - body.Migratable = &migratable - } - if cores_enabled { - log.Printf("support for %s is enabled", CUSTOM_VIRTUAL_CORES) - body.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} - } else { - log.Printf("no virtual cores support enabled for this customer..") - } - - _, err = client.Update(parts[1], powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesPutParams{Body: body}, updateTimeOut) - if err != nil { - return fmt.Errorf("failed to update the lpar with the change %v", err) - } - _, err = isWaitForPIInstanceAvailable(client, parts[1], d.Timeout(schema.TimeoutUpdate), powerinstanceid, "OK") - if err != nil { - return err - } - } - } - - return resourceIBMPIInstanceRead(d, meta) - -} - -func resourceIBMPIInstanceDelete(d *schema.ResourceData, meta interface{}) error { - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - err = client.Delete(parts[1], powerinstanceid, deleteTimeOut) - if err != nil { - return fmt.Errorf("failed to perform the delete action on the pvm instance %s", err) - } - - _, err = isWaitForPIInstanceDeleted(client, parts[1], d.Timeout(schema.TimeoutDelete), powerinstanceid) - if err != nil { - return err - } - - d.SetId("") - return nil -} - -// Exists - -func resourceIBMPIInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - log.Printf("Calling the PowerInstance Exists method") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - powerinstanceid := parts[0] - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - instance, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("error communicating with the API: %s", err) - } - - truepvmid := *instance.PvmInstanceID - return truepvmid == parts[1], nil -} - -func isWaitForPIInstanceDeleted(client *st.IBMPIInstanceClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIInstanceDeleting}, - Target: []string{helpers.PIInstanceNotFound}, - Refresh: isPIInstanceDeleteRefreshFunc(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - Timeout: 10 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceDeleteRefreshFunc(client *st.IBMPIInstanceClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - pvm, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - log.Printf("The power vm does not exist") - return pvm, helpers.PIInstanceNotFound, nil - - } - return pvm, helpers.PIInstanceDeleting, nil - - } -} - -func isWaitForPIInstanceAvailable(client *st.IBMPIInstanceClient, id string, timeout time.Duration, powerinstanceid string, instanceReadyStatus string) (interface{}, error) { - log.Printf("Waiting for PIInstance (%s) to be available and active ", id) - - var queryTimeOut time.Duration - - if instanceReadyStatus == "WARNING" { - queryTimeOut = warningTimeOut - } else { - queryTimeOut = activeTimeOut - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{"PENDING", helpers.PIInstanceBuilding, helpers.PIInstanceHealthWarning}, - Target: []string{helpers.PIInstanceAvailable, helpers.PIInstanceHealthOk, "ERROR", ""}, - Refresh: isPIInstanceRefreshFunc(client, id, powerinstanceid, instanceReadyStatus), - Delay: 10 * time.Second, - MinTimeout: queryTimeOut, - Timeout: 120 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceRefreshFunc(client *st.IBMPIInstanceClient, id, powerinstanceid, instanceReadyStatus string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - pvm, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - allowableStatus := instanceReadyStatus - if *pvm.Status == helpers.PIInstanceAvailable && (pvm.Health.Status == allowableStatus) { - return pvm, helpers.PIInstanceAvailable, nil - } - if *pvm.Status == "ERROR" { - return pvm, *pvm.Status, fmt.Errorf("Failed to create the lpar") - } - - return pvm, helpers.PIInstanceBuilding, nil - } -} - -func checkBase64(input string) error { - _, err := base64.StdEncoding.DecodeString(input) - if err != nil { - return fmt.Errorf("Failed to check if input is base64 %s", err) - } - return err - -} - -func isWaitForPIInstanceStopped(client *st.IBMPIInstanceClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - log.Printf("Waiting for PIInstance (%s) to be stopped and powered off ", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"STOPPING", "RESIZE", "VERIFY_RESIZE", helpers.PIInstanceHealthWarning}, - Target: []string{"OK", "SHUTOFF"}, - Refresh: isPIInstanceRefreshFuncOff(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 2 * time.Minute, // This is the time that the client will execute to check the status of the request - Timeout: 30 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceRefreshFuncOff(client *st.IBMPIInstanceClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - log.Printf("Calling the check Refresh status of the pvm [%s] for cloud instance id [%s ]", id, powerinstanceid) - pvm, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - if *pvm.Status == "SHUTOFF" && pvm.Health.Status == helpers.PIInstanceHealthOk { - return pvm, "SHUTOFF", nil - } - return pvm, "STOPPING", nil - } -} - -func stopLparForResourceChange(client *st.IBMPIInstanceClient, id, powerinstanceid string, stopUpdateTimeOut time.Duration) error { - body := &models.PVMInstanceAction{ - //Action: ptrToString("stop"), - Action: ptrToString("immediate-shutdown"), - } - _, err := client.Action(&p_cloud_p_vm_instances.PcloudPvminstancesActionPostParams{Body: body}, id, powerinstanceid, postTimeOut) - if err != nil { - return fmt.Errorf("failed to perform the stop action on the pvm instance %v", err) - } - - _, err = isWaitForPIInstanceStopped(client, id, stopUpdateTimeOut, powerinstanceid) - - return err -} - -// Start the lpar - -func startLparAfterResourceChange(client *st.IBMPIInstanceClient, id, powerinstanceid string, startUpdateTimeOut time.Duration) error { - body := &models.PVMInstanceAction{ - Action: ptrToString("start"), - } - _, err := client.Action(&p_cloud_p_vm_instances.PcloudPvminstancesActionPostParams{Body: body}, id, powerinstanceid, postTimeOut) - if err != nil { - return fmt.Errorf("failed to perform the start action on the pvm instance %v", err) - } - - _, err = isWaitForPIInstanceAvailable(client, id, startUpdateTimeOut, powerinstanceid, "OK") - - return err -} - -// Stop / Modify / Start only when the lpar is off limits - -func performChangeAndReboot(client *st.IBMPIInstanceClient, id, powerinstanceid string, mem, procs float64) error { - /* - These are the steps - 1. Stop the lpar - Check if the lpar is SHUTOFF - 2. Once the lpar is SHUTOFF - Make the cpu / memory change - DUring this time , you can check for RESIZE and VERIFY_RESIZE as the transition states - 3. If the change is successful , the lpar state will be back in SHUTOFF - 4. Once the LPAR state is SHUTOFF , initiate the start again and check for ACTIVE + OK - */ - //Execute the stop - - log.Printf("Callin the stop lpar for Resource Change code ..") - err := stopLparForResourceChange(client, id, powerinstanceid, 30) - if err != nil { - return err - } - - body := &models.PVMInstanceUpdate{ - Memory: mem, - Processors: procs, - } - - _, updateErr := client.Update(id, powerinstanceid, &p_cloud_p_vm_instances.PcloudPvminstancesPutParams{Body: body}, updateTimeOut) - if updateErr != nil { - return fmt.Errorf("failed to update the lpar with the change, %s", updateErr) - } - - _, err = isWaitforPIInstanceUpdate(client, id, 30, powerinstanceid) - if err != nil { - return fmt.Errorf("failed to get an update from the Service after the resource change, %s", err) - } - - // Now we can start the lpar - log.Printf("Calling the start lpar After the Resource Change code ..") - err = startLparAfterResourceChange(client, id, powerinstanceid, 30) - if err != nil { - return err - } - - return nil - -} - -func isWaitforPIInstanceUpdate(client *st.IBMPIInstanceClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - log.Printf("Waiting for PIInstance (%s) to be SHUTOFF AFTER THE RESIZE Due to DLPAR Operation ", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"RESIZE", "VERIFY_RESIZE"}, - Target: []string{"ACTIVE", "SHUTOFF", helpers.PIInstanceHealthOk}, - Refresh: isPIInstanceShutAfterResourceChange(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 5 * time.Minute, - Timeout: 60 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceShutAfterResourceChange(client *st.IBMPIInstanceClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - pvm, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - - if *pvm.Status == "SHUTOFF" && pvm.Health.Status == helpers.PIInstanceHealthOk { - log.Printf("The lpar is now off after the resource change...") - return pvm, "SHUTOFF", nil - } - - return pvm, "RESIZE", nil - } -} - -func buildPVMNetworks(networks []string) []*models.PVMInstanceAddNetwork { - var pvmNetworks []*models.PVMInstanceAddNetwork - - for i := 0; i < len(networks); i++ { - pvmInstanceNetwork := &models.PVMInstanceAddNetwork{ - //TODO : Enable the functionality to pass in ip address for the network - IPAddress: "", - NetworkID: ptrToString(string(networks[i])), - } - pvmNetworks = append(pvmNetworks, pvmInstanceNetwork) - - } - return pvmNetworks -} - -func expandPVMNetworks(networks []interface{}) []*models.PVMInstanceAddNetwork { - pvmNetworks := make([]*models.PVMInstanceAddNetwork, 0, len(networks)) - for _, v := range networks { - network := v.(map[string]interface{}) - pvmInstanceNetwork := &models.PVMInstanceAddNetwork{ - IPAddress: network["ip_address"].(string), - NetworkID: ptrToString(network["network_id"].(string)), - } - pvmNetworks = append(pvmNetworks, pvmInstanceNetwork) - } - return pvmNetworks -} - -func checkCloudInstanceCapability(cloudInstance *models.CloudInstance, custom_capability string) bool { - log.Printf("Checking for the following capability %s", custom_capability) - log.Printf("the instance features are %s", cloudInstance.Capabilities) - for _, v := range cloudInstance.Capabilities { - if v == custom_capability { - return true - } - } - return false -} diff --git a/ibm/resource_ibm_pi_instance_test.go b/ibm/resource_ibm_pi_instance_test.go deleted file mode 100644 index 0c3813f89..000000000 --- a/ibm/resource_ibm_pi_instance_test.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPIInstancebasic(t *testing.T) { - - name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIInstanceConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceExists("ibm_pi_instance.power_instance"), - resource.TestCheckResourceAttr( - "ibm_pi_instance.power_instance", "pi_instance_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPIInstanceDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_instance" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPIInstanceClient(sess, powerinstanceid) - _, err = networkC.Get(parts[1], powerinstanceid, getTimeOut) - if err == nil { - return fmt.Errorf("PI Instance still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPIInstanceExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - instance, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return err - } - parts[1] = *instance.PvmInstanceID - return nil - - } -} - -func testAccCheckIBMPIInstanceConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_pi_key" "key" { - pi_cloud_instance_id = "%[1]s" - pi_key_name = "%[2]s" - pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" - } - resource "ibm_pi_image" "power_image" { - pi_image_name = "%[2]s" - pi_image_id = "f31da27a-b634-45e5-913a-3f4d964e5a02" - pi_cloud_instance_id = "%[1]s" - } - resource "ibm_pi_network" "power_networks" { - pi_cloud_instance_id = "%[1]s" - pi_network_name = "%[2]s" - pi_network_type = "pub-vlan" - } - resource "ibm_pi_volume" "power_volume" { - pi_volume_size = 20 - pi_volume_name = "%[2]s" - pi_volume_type = "tier1" - pi_volume_shareable = true - pi_cloud_instance_id = "%[1]s" - } - resource "ibm_pi_instance" "power_instance" { - pi_memory = "4" - pi_processors = "2" - pi_instance_name = "%[2]s" - pi_proc_type = "shared" - pi_image_id = ibm_pi_image.power_image.image_id - pi_network_ids = [ibm_pi_network.power_networks.network_id] - pi_key_pair_name = ibm_pi_key.key.key_id - pi_sys_type = "s922" - pi_cloud_instance_id = "%[1]s" - pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] - } - `, pi_cloud_instance_id, name) -} - -func TestAccIBMPIInstanceNetwork(t *testing.T) { - instanceRes := "ibm_pi_instance.power_instance" - name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) - privateNetIP := "192.112.111.220" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccIBMPIInstanceNetworkConfig(name, privateNetIP), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceExists(instanceRes), - resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), - resource.TestCheckResourceAttrSet(instanceRes, "pi_network.0.network_id"), - resource.TestCheckResourceAttrSet(instanceRes, "pi_network.0.mac_address"), - resource.TestCheckResourceAttr(instanceRes, "pi_network.0.ip_address", privateNetIP), - ), - }, - }, - }) -} - -func testAccIBMPIInstanceNetworkConfig(name, privateNetIP string) string { - return fmt.Sprintf(` - resource "ibm_pi_key" "key" { - pi_cloud_instance_id = "%[1]s" - pi_key_name = "%[2]s" - pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArb2aK0mekAdbYdY9rwcmeNSxqVCwez3WZTYEq+1Nwju0x5/vQFPSD2Kp9LpKBbxx3OVLN4VffgGUJznz9DAr7veLkWaf3iwEil6U4rdrhBo32TuDtoBwiczkZ9gn1uJzfIaCJAJdnO80Kv9k0smbQFq5CSb9H+F5VGyFue/iVd5/b30MLYFAz6Jg1GGWgw8yzA4Gq+nO7HtyuA2FnvXdNA3yK/NmrTiPCdJAtEPZkGu9LcelkQ8y90ArlKfjtfzGzYDE4WhOufFxyWxciUePh425J2eZvElnXSdGha+FCfYjQcvqpCVoBAG70U4fJBGjB+HL/GpCXLyiYXPrSnzC9w==" - } - resource "ibm_pi_instance" "power_instance" { - pi_memory = "2" - pi_processors = "0.25" - pi_instance_name = "%[2]s" - pi_proc_type = "shared" - pi_image_id = "f4501cad-d0f4-4517-9eea-85402309d90d" - pi_key_pair_name = ibm_pi_key.key.key_id - pi_sys_type = "e980" - pi_storage_type = "tier3" - pi_cloud_instance_id = "%[1]s" - pi_network { - network_id = "tf-cloudconnection-23" - ip_address = "%[3]s" - } - } - `, pi_cloud_instance_id, name, privateNetIP) -} diff --git a/ibm/resource_ibm_pi_key.go b/ibm/resource_ibm_pi_key.go deleted file mode 100644 index dd9b70583..000000000 --- a/ibm/resource_ibm_pi_key.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func resourceIBMPIKey() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIKeyCreate, - Read: resourceIBMPIKeyRead, - Update: resourceIBMPIKeyUpdate, - Delete: resourceIBMPIKeyDelete, - Exists: resourceIBMPIKeyExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PIKeyName: { - Type: schema.TypeString, - Required: true, - Description: "Key name in the PI instance", - }, - - helpers.PIKey: { - Type: schema.TypeString, - Required: true, - Description: "PI instance key info", - }, - helpers.PIKeyDate: { - Type: schema.TypeString, - Computed: true, - Description: "Date info", - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "PI cloud instance ID", - }, - - "key_id": { - Type: schema.TypeString, - Computed: true, - Description: "Key ID in the PI instance", - }, - }, - } -} - -func resourceIBMPIKeyCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - name := d.Get(helpers.PIKeyName).(string) - sshkey := d.Get(helpers.PIKey).(string) - client := st.NewIBMPIKeyClient(sess, powerinstanceid) - - sshResponse, _, err := client.Create(name, sshkey, powerinstanceid) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return fmt.Errorf("Failed to create the key %v", err) - - } - - log.Printf("Printing the sshkey %+v", &sshResponse) - - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, name)) - return resourceIBMPIKeyRead(d, meta) -} - -func resourceIBMPIKeyRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return fmt.Errorf("Failed to obtain the key %v", err) - } - - powerinstanceid := parts[0] - sshkeyC := st.NewIBMPIKeyClient(sess, powerinstanceid) - sshkeydata, err := sshkeyC.Get(parts[1], powerinstanceid) - - if err != nil { - return err - } - - d.Set(helpers.PIKeyName, sshkeydata.Name) - d.Set(helpers.PIKey, sshkeydata.SSHKey) - d.Set(helpers.PIKeyDate, sshkeydata.CreationDate.String()) - d.Set("key_id", sshkeydata.Name) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil - -} - -func resourceIBMPIKeyUpdate(data *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMPIKeyDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - powerinstanceid := parts[0] - sshkeyC := st.NewIBMPIKeyClient(sess, powerinstanceid) - err = sshkeyC.Delete(parts[1], powerinstanceid) - - if err != nil { - return err - } - d.SetId("") - return nil -} - -func resourceIBMPIKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of powerInstanceID/keyName", d.Id()) - } - name := parts[1] - powerinstanceid := parts[0] - client := st.NewIBMPIKeyClient(sess, powerinstanceid) - - key, err := client.Get(parts[1], powerinstanceid) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - return *key.Name == name, nil -} diff --git a/ibm/resource_ibm_pi_key_test.go b/ibm/resource_ibm_pi_key_test.go deleted file mode 100644 index 3e3fd6129..000000000 --- a/ibm/resource_ibm_pi_key_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPIKey_basic(t *testing.T) { - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - name := fmt.Sprintf("tf-pi-sshkey-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIKeyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIKeyConfig(publicKey, name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIKeyExists("ibm_pi_key.key"), - resource.TestCheckResourceAttr( - "ibm_pi_key.key", "pi_key_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPIKeyDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_key" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - sshkeyC := st.NewIBMPIKeyClient(sess, powerinstanceid) - _, err = sshkeyC.Get(parts[1], powerinstanceid) - if err == nil { - return fmt.Errorf("PI key still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPIKeyExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIKeyClient(sess, powerinstanceid) - - key, err := client.Get(parts[1], powerinstanceid) - if err != nil { - return err - } - parts[1] = *key.Name - return nil - - } -} - -func testAccCheckIBMPIKeyConfig(publicKey, name string) string { - return fmt.Sprintf(` - resource "ibm_pi_key" "key" { - pi_cloud_instance_id = "%s" - pi_key_name = "%s" - pi_ssh_key = "%s" - } - `, pi_cloud_instance_id, name, publicKey) -} diff --git a/ibm/resource_ibm_pi_network.go b/ibm/resource_ibm_pi_network.go deleted file mode 100644 index 481d6c59d..000000000 --- a/ibm/resource_ibm_pi_network.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "net" - "strconv" - "time" - - "github.com/apparentlymart/go-cidr/cidr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" -) - -func resourceIBMPINetwork() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPINetworkCreate, - Read: resourceIBMPINetworkRead, - Update: resourceIBMPINetworkUpdate, - Delete: resourceIBMPINetworkDelete, - //Exists: resourceIBMPINetworkExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PINetworkType: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"vlan", "pub-vlan"}), - Description: "PI network type", - }, - - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - Description: "PI network name", - }, - helpers.PINetworkDNS: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of PI network DNS name", - }, - - helpers.PINetworkCidr: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "PI network CIDR", - }, - - helpers.PINetworkGateway: { - Type: schema.TypeString, - Optional: true, - Description: "PI network gateway", - }, - - helpers.PINetworkJumbo: { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "PI network enable MTU Jumbo option", - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "PI cloud instance ID", - }, - - //Computed Attributes - - "network_id": { - Type: schema.TypeString, - Computed: true, - Description: "PI network ID", - }, - "vlan_id": { - Type: schema.TypeFloat, - Computed: true, - Description: "VLAN Id value", - }, - }, - } -} - -func resourceIBMPINetworkCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkname := d.Get(helpers.PINetworkName).(string) - networktype := d.Get(helpers.PINetworkType).(string) - networkcidr := d.Get(helpers.PINetworkCidr).(string) - networkdns := expandStringList((d.Get(helpers.PINetworkDNS).(*schema.Set)).List()) - jumbo := d.Get(helpers.PINetworkJumbo).(bool) - - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - var networkgateway, firstip, lastip string - if networktype == "vlan" { - networkgateway, firstip, lastip, err = generateIPData(networkcidr) - if err != nil { - return err - } - } - networkResponse, err := client.Create(networkname, networktype, networkcidr, networkdns, networkgateway, firstip, lastip, jumbo, powerinstanceid, postTimeOut) - if err != nil { - return fmt.Errorf("failed to create the network %v", err) - } - - IBMPINetworkID := *networkResponse.NetworkID - - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, IBMPINetworkID)) - - _, err = isWaitForIBMPINetworkAvailable(client, IBMPINetworkID, d.Timeout(schema.TimeoutCreate), powerinstanceid) - if err != nil { - return err - } - - return resourceIBMPINetworkRead(d, meta) -} - -func resourceIBMPINetworkRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return err - } - - d.Set("network_id", networkdata.NetworkID) - d.Set(helpers.PINetworkCidr, networkdata.Cidr) - d.Set(helpers.PINetworkDNS, networkdata.DNSServers) - d.Set("vlan_id", networkdata.VlanID) - d.Set(helpers.PINetworkName, networkdata.Name) - d.Set(helpers.PINetworkType, networkdata.Type) - d.Set(helpers.PINetworkJumbo, networkdata.Jumbo) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil - -} - -func resourceIBMPINetworkUpdate(data *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMPINetworkDelete(d *schema.ResourceData, meta interface{}) error { - - log.Printf("Calling the network delete functions. ") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - err = networkC.Delete(parts[1], powerinstanceid, deleteTimeOut) - - if err != nil { - return err - } - d.SetId("") - return nil -} - -func resourceIBMPINetworkExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of powerInstanceID/NetworkID", d.Id()) - } - powerinstanceid := parts[0] - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - network, err := client.Get(parts[0], powerinstanceid, getTimeOut) - if err != nil { - - return false, err - } - return *network.NetworkID == parts[1], nil -} - -func isWaitForIBMPINetworkAvailable(client *st.IBMPINetworkClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PINetworkProvisioning}, - Target: []string{"NETWORK_READY"}, - Refresh: isIBMPINetworkRefreshFunc(client, id, powerinstanceid), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func isIBMPINetworkRefreshFunc(client *st.IBMPINetworkClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - network, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - - if &network.VlanID != nil { - return network, "NETWORK_READY", nil - } - - return network, helpers.PINetworkProvisioning, nil - } -} - -func generateIPData(cdir string) (gway, firstip, lastip string, err error) { - _, ipv4Net, err := net.ParseCIDR(cdir) - - if err != nil { - return "", "", "", err - } - - var subnetToSize = map[string]int{ - "21": 2048, - "22": 1024, - "23": 512, - "24": 256, - "25": 128, - "26": 64, - "27": 32, - "28": 16, - "29": 8, - "30": 4, - "31": 2, - } - - //subnetsize, _ := ipv4Net.Mask.Size() - - gateway, err := cidr.Host(ipv4Net, 1) - if err != nil { - log.Printf("Failed to get the gateway for this cidr passed in %s", cdir) - return "", "", "", err - } - ad := cidr.AddressCount(ipv4Net) - - convertedad := strconv.FormatUint(ad, 10) - // Powervc in wdc04 has to reserve 3 ip address hence we start from the 4th. This will be the default behaviour - firstusable, err := cidr.Host(ipv4Net, 4) - if err != nil { - log.Print(err) - return "", "", "", err - } - lastusable, err := cidr.Host(ipv4Net, subnetToSize[convertedad]-2) - if err != nil { - log.Print(err) - return "", "", "", err - } - return gateway.String(), firstusable.String(), lastusable.String(), nil - -} diff --git a/ibm/resource_ibm_pi_network_port.go b/ibm/resource_ibm_pi_network_port.go deleted file mode 100644 index 2b304bd18..000000000 --- a/ibm/resource_ibm_pi_network_port.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_networks" - "github.com/IBM-Cloud/power-go-client/power/models" -) - -func resourceIBMPINetworkPort() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPINetworkPortCreate, - Read: resourceIBMPINetworkPortRead, - Update: resourceIBMPINetworkPortUpdate, - Delete: resourceIBMPINetworkPortDelete, - //Exists: resourceIBMPINetworkExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - }, - - helpers.PINetworkPortDescription: { - Type: schema.TypeString, - Optional: true, - }, - - //Computed Attributes - - helpers.PINetworkPortIPAddress: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "portid": { - Type: schema.TypeString, - Computed: true, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "public_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceIBMPINetworkPortCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkname := d.Get(helpers.PINetworkName).(string) - description := d.Get(helpers.PINetworkPortDescription).(string) - - ipaddress := d.Get(helpers.PINetworkPortIPAddress).(string) - - nwportBody := &models.NetworkPortCreate{Description: description} - - if ipaddress != "" { - log.Printf("IP address provided. ") - nwportBody.IPAddress = ipaddress - } - - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - networkPortResponse, err := client.CreatePort(networkname, powerinstanceid, &p_cloud_networks.PcloudNetworksPortsPostParams{Body: nwportBody}, postTimeOut) - - if err != nil { - return err - } - - log.Printf("Printing the networkresponse %+v", &networkPortResponse) - - IBMPINetworkPortID := *networkPortResponse.PortID - - d.SetId(fmt.Sprintf("%s/%s/%s", powerinstanceid, IBMPINetworkPortID, networkname)) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return err - } - _, err = isWaitForIBMPINetworkPortAvailable(client, IBMPINetworkPortID, d.Timeout(schema.TimeoutCreate), powerinstanceid, networkname) - if err != nil { - return err - } - - return resourceIBMPINetworkPortRead(d, meta) -} - -func resourceIBMPINetworkPortRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - var powernetworkname string - if len(parts) > 2 { - powernetworkname = parts[2] - } else { - powernetworkname = d.Get(helpers.PINetworkName).(string) - d.SetId(fmt.Sprintf("%s/%s", d.Id(), powernetworkname)) - } - - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.GetPort(powernetworkname, powerinstanceid, parts[1], getTimeOut) - - if err != nil { - return err - } - - d.Set(helpers.PINetworkPortIPAddress, networkdata.IPAddress) - d.Set("macaddress", networkdata.MacAddress) - d.Set("status", networkdata.Status) - d.Set("portid", networkdata.PortID) - d.Set("public_ip", networkdata.ExternalIP) - - return nil - -} - -func resourceIBMPINetworkPortUpdate(data *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMPINetworkPortDelete(d *schema.ResourceData, meta interface{}) error { - - log.Printf("Calling the network delete functions. ") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - - if err != nil { - return err - } - var powernetworkname string - if len(parts) > 2 { - powernetworkname = parts[2] - } else { - powernetworkname = d.Get(helpers.PINetworkName).(string) - } - powerinstanceid := parts[0] - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - log.Printf("Calling the client %v", client) - - log.Printf("Calling the delete with the following params delete with cloudinstance -> (%s) and networkid --> (%s) and portid --> (%s) ", powerinstanceid, powernetworkname, parts[1]) - networkdata, err := client.DeletePort(powernetworkname, powerinstanceid, parts[1], deleteTimeOut) - - log.Printf("Response from the deleteport call %v", networkdata) - - if err != nil { - return err - } - d.SetId("") - return nil -} - -func isWaitForIBMPINetworkPortAvailable(client *st.IBMPINetworkClient, id string, timeout time.Duration, powerinstanceid, networkname string) (interface{}, error) { - log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PINetworkProvisioning}, - Target: []string{"DOWN"}, - Refresh: isIBMPINetworkPortRefreshFunc(client, id, powerinstanceid, networkname), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isIBMPINetworkPortRefreshFunc(client *st.IBMPINetworkClient, id, powerinstanceid, networkname string) resource.StateRefreshFunc { - - log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) - return func() (interface{}, string, error) { - network, err := client.GetPort(networkname, powerinstanceid, id, getTimeOut) - if err != nil { - return nil, "", err - } - - if &network.PortID != nil { - //if network.State == "available" { - log.Printf(" The port has been created with the following ip address and attached to an instance ") - return network, "DOWN", nil - } - - return network, helpers.PINetworkProvisioning, nil - } -} diff --git a/ibm/resource_ibm_pi_network_port_attach.go b/ibm/resource_ibm_pi_network_port_attach.go deleted file mode 100644 index dd07b70c5..000000000 --- a/ibm/resource_ibm_pi_network_port_attach.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMPINetworkPortAttach() *schema.Resource { - return &schema.Resource{ - - Create: resourceIBMPINetworkPortAttachCreate, - Read: resourceIBMPINetworkPortAttachRead, - Update: resourceIBMPINetworkPortAttachUpdate, - Delete: resourceIBMPINetworkPortAttachDelete, - //Exists: resourceIBMPINetworkExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - }, - Schema: map[string]*schema.Schema{ - - "port_id": { - Type: schema.TypeString, - Required: true, - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - }, - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Instance name to attach the network port to", - }, - - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - Description: "Network Name - This is the subnet name in the Cloud instance", - }, - - helpers.PINetworkPortDescription: { - Type: schema.TypeString, - Optional: true, - Description: "A human readable description for this network Port", - Default: "Port Created via Terraform", - }, - "public_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - } - -} - -func resourceIBMPINetworkPortAttachCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkname := d.Get(helpers.PINetworkName).(string) - portid := d.Get("port_id").(string) - instancename := d.Get(helpers.PIInstanceName).(string) - description := d.Get(helpers.PINetworkPortDescription).(string) - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - log.Printf("Printing the input to the resource powerinstance [%s] and network name [%s] and the portid [%s]", powerinstanceid, networkname, portid) - networkPortResponse, err := client.AttachPort(powerinstanceid, networkname, portid, description, instancename, postTimeOut) - - if err != nil { - return err - } - - log.Printf("Printing the networkresponse %+v", &networkPortResponse) - - IBMPINetworkPortID := *networkPortResponse.PortID - - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, IBMPINetworkPortID)) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return err - } - _, err = isWaitForIBMPINetworkPortAttachAvailable(client, IBMPINetworkPortID, d.Timeout(schema.TimeoutCreate), powerinstanceid, networkname) - if err != nil { - return err - } - - return resourceIBMPINetworkPortAttachRead(d, meta) -} - -func resourceIBMPINetworkPortAttachRead(d *schema.ResourceData, meta interface{}) error { - log.Printf("Calling ther Network Port Attach Read code") - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - fmt.Printf("failed to get a session from the IBM Cloud Service %v", err) - } - - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - powerinstanceid := parts[0] - powernetworkname := d.Get(helpers.PINetworkName).(string) - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - networkdata, err := networkC.GetPort(powernetworkname, powerinstanceid, parts[1], getTimeOut) - - d.Set("ipaddress", networkdata.IPAddress) - d.Set("macaddress", networkdata.MacAddress) - d.Set("status", networkdata.Status) - d.Set("portid", networkdata.PortID) - d.Set("pvminstance", networkdata.PvmInstance.Href) - d.Set("public_ip", networkdata.ExternalIP) - - return nil -} - -func resourceIBMPINetworkPortAttachUpdate(d *schema.ResourceData, meta interface{}) error { - log.Printf("Calling the attach update ") - return nil -} - -func resourceIBMPINetworkPortAttachDelete(d *schema.ResourceData, meta interface{}) error { - log.Printf("Detaching the network port from the Instance ") - - sess, err := meta.(ClientSession).IBMPISession() - - if err != nil { - fmt.Printf("failed to get a session from the IBM Cloud Service %v", err) - - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - powerinstanceid := parts[0] - powernetworkname := d.Get(helpers.PINetworkName).(string) - portid := d.Get("port_id").(string) - - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - log.Printf("Calling the network delete functions. ") - network, err := client.DetachPort(powerinstanceid, powernetworkname, portid, deleteTimeOut) - if err != nil { - return err - } - - log.Printf("Printing the networkresponse %+v", &network) - - //log.Printf("Printing the networkresponse %s", network.Status) - - d.SetId("") - return nil - -} - -func isWaitForIBMPINetworkPortAttachAvailable(client *st.IBMPINetworkClient, id string, timeout time.Duration, powerinstanceid, networkname string) (interface{}, error) { - log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PINetworkProvisioning}, - Target: []string{"ACTIVE"}, - Refresh: isIBMPINetworkPortAttachRefreshFunc(client, id, powerinstanceid, networkname), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isIBMPINetworkPortAttachRefreshFunc(client *st.IBMPINetworkClient, id, powerinstanceid, networkname string) resource.StateRefreshFunc { - - log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) - return func() (interface{}, string, error) { - network, err := client.GetPort(networkname, powerinstanceid, id, getTimeOut) - if err != nil { - return nil, "", err - } - - if &network.PortID != nil && &network.PvmInstance.PvmInstanceID != nil { - //if network.State == "available" { - log.Printf(" The port has been created with the following ip address and attached to an instance ") - return network, "ACTIVE", nil - } - - return network, helpers.PINetworkProvisioning, nil - } -} diff --git a/ibm/resource_ibm_pi_network_port_attach_test.go b/ibm/resource_ibm_pi_network_port_attach_test.go deleted file mode 100644 index 49d77568a..000000000 --- a/ibm/resource_ibm_pi_network_port_attach_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPINetworkPortAttachbasic(t *testing.T) { - t.Skip() - name := fmt.Sprintf("tf-pi-network-port-attach-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPINetworkPortAttachDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPINetworkPortAttachConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPINetworkPortAttachExists("ibm_pi_network_port_attach.power_network_port_attach"), - resource.TestCheckResourceAttr( - "ibm_pi_network_port_attach.power_network_port_attach", "pi_network_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPINetworkPortAttachDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_network_port_attach" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - _, err = networkC.GetPort(parts[2], parts[1], powerinstanceid, getTimeOut) - if err == nil { - return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPINetworkPortAttachExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - network, err := client.GetPort(parts[2], powerinstanceid, parts[1], getTimeOut) - if err != nil { - return err - } - parts[1] = *network.PortID - return nil - - } -} - -func testAccCheckIBMPINetworkPortAttachConfig(name string) string { - return testAccCheckIBMPINetworkPortConfig(name) + fmt.Sprintf(` - resource "ibm_pi_network_port_attach" "power_network_port_attach" { - pi_cloud_instance_id = "%s" - pi_network_name = ibm_pi_network.power_networks.pi_network_name - pi_network_port_description = "IP Reserved for Test UAT" - port_id=ibm_pi_network_port.power_network_port.id - } - `, pi_cloud_instance_id) -} diff --git a/ibm/resource_ibm_pi_network_port_test.go b/ibm/resource_ibm_pi_network_port_test.go deleted file mode 100644 index 10e1083fe..000000000 --- a/ibm/resource_ibm_pi_network_port_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPINetworkPortbasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-network-port-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPINetworkPortDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPINetworkPortConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPINetworkPortExists("ibm_pi_network_port.power_network_port"), - resource.TestCheckResourceAttr( - "ibm_pi_network_port.power_network_port", "pi_network_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPINetworkPortDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_network_port" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - _, err = networkC.GetPort(parts[2], parts[1], powerinstanceid, getTimeOut) - if err == nil { - return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPINetworkPortExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - network, err := client.GetPort(parts[2], powerinstanceid, parts[1], getTimeOut) - if err != nil { - return err - } - parts[1] = *network.PortID - return nil - - } -} - -func testAccCheckIBMPINetworkPortConfig(name string) string { - return testAccCheckIBMPINetworkConfig(name) + fmt.Sprintf(` - resource "ibm_pi_network_port" "power_network_port" { - pi_cloud_instance_id = "%s" - pi_network_name = ibm_pi_network.power_networks.pi_network_name - pi_network_port_description = "IP Reserved for Test UAT" - } - `, pi_cloud_instance_id) -} diff --git a/ibm/resource_ibm_pi_network_test.go b/ibm/resource_ibm_pi_network_test.go deleted file mode 100644 index 4b168eb4c..000000000 --- a/ibm/resource_ibm_pi_network_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPINetworkbasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-network-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPINetworkDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPINetworkConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), - resource.TestCheckResourceAttr( - "ibm_pi_network.power_networks", "pi_network_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPINetworkDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_network" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPINetworkClient(sess, powerinstanceid) - _, err = networkC.Get(parts[1], powerinstanceid, getTimeOut) - if err == nil { - return fmt.Errorf("PI Network still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPINetworkExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPINetworkClient(sess, powerinstanceid) - - network, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return err - } - parts[1] = *network.NetworkID - return nil - - } -} - -func testAccCheckIBMPINetworkConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_pi_network" "power_networks" { - pi_cloud_instance_id = "%s" - pi_network_name = "%s" - pi_network_type = "pub-vlan" - } - `, pi_cloud_instance_id, name) -} diff --git a/ibm/resource_ibm_pi_operations.go b/ibm/resource_ibm_pi_operations.go deleted file mode 100644 index c9eb3114d..000000000 --- a/ibm/resource_ibm_pi_operations.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_p_vm_instances" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "log" - "time" -) - -/* -Transition states - -The server can go from - -ACTIVE --> SHUTOFF -ACTIVE --> HARD-REBOOT -ACTIVE --> SOFT-REBOOT -SHUTOFF--> ACTIVE - - - - -*/ - -func resourceIBMPIIOperations() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIOperationsCreate, - Read: resourceIBMPIOperationsRead, - Update: resourceIBMPIOperationsUpdate, - Delete: resourceIBMPIOperationsDelete, - //Exists: resourceIBMPIOperationsExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "PI Cloud instnce id", - }, - - helpers.PIInstanceOperationStatus: { - Type: schema.TypeString, - Computed: true, - Description: "PI instance operation status", - }, - helpers.PIInstanceOperationServerName: { - Type: schema.TypeString, - Required: true, - Description: "PI instance Operation server name", - }, - - "addresses": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "ip": { - Type: schema.TypeString, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "networkid": { - Type: schema.TypeString, - Computed: true, - }, - "networkname": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - helpers.PIInstanceHealthStatus: { - Type: schema.TypeString, - Computed: true, - Description: "PI instance health status", - }, - - helpers.PIInstanceOperationType: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateAllowedStringValue([]string{"start", "stop", "hard-reboot", "soft-reboot", "immediate-shutdown"}), - Description: "PI instance operation type", - }, - - helpers.PIInstanceOperationProgress: { - Type: schema.TypeFloat, - Computed: true, - Description: "Progress of the operation", - }, - }, - } -} - -func resourceIBMPIOperationsCreate(d *schema.ResourceData, meta interface{}) error { - - log.Printf("Now in the Power Operations Code") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - operation := d.Get(helpers.PIInstanceOperationType).(string) - name := d.Get(helpers.PIInstanceOperationServerName).(string) - - body := &models.PVMInstanceAction{Action: ptrToString(operation)} - log.Printf("Calling the IBM PI Operations [ %s ] with on the instance with name [ %s ]", operation, name) - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - /* - TODO - To add a check if the action performed is applicable on the current state of the instance - */ - - pvmoperation, err := client.Action(&p_cloud_p_vm_instances.PcloudPvminstancesActionPostParams{ - Body: body, - }, name, powerinstanceid, 30*time.Second) - - if err != nil { - log.Printf("[DEBUG] err %s", err) - return fmt.Errorf("Failed to perform the operation on the instance %v", err) - - } else { - log.Printf("Executed the stop operation on the lpar") - } - - log.Printf("Printing the instance info %+v", &pvmoperation) - - if operation == "stop" || operation == "immediate-shutdown" { - var targetStatus = "SHUTOFF" - log.Printf("Calling the check opertion that was invoked [%s] to check for status [ %s ]", operation, targetStatus) - _, err = isWaitForPIInstanceOperationStatus(client, name, d.Timeout(schema.TimeoutCreate), powerinstanceid, operation, targetStatus) - if err != nil { - return err - } else { - log.Printf("Executed the start operation on the lpar") - } - - } - - if operation == "start" || operation == "soft-reboot" || operation == "hard-reboot" { - var targetStatus = "ACTIVE" - log.Printf("Calling the check opertion that was invoked [%s] to check for status [ %s ]", operation, targetStatus) - _, err = isWaitForPIInstanceOperationStatus(client, name, d.Timeout(schema.TimeoutCreate), powerinstanceid, operation, targetStatus) - if err != nil { - return err - } - - } - - return resourceIBMPIOperationsRead(d, meta) -} - -func resourceIBMPIOperationsRead(d *schema.ResourceData, meta interface{}) error { - - log.Printf("Calling the PowerOperations Read code..for instance name %s", d.Get(helpers.PIInstanceOperationServerName).(string)) - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - name := d.Get(helpers.PIInstanceOperationServerName).(string) - powerC := st.NewIBMPIInstanceClient(sess, powerinstanceid) - powervmdata, err := powerC.Get(name, powerinstanceid, getTimeOut) - - if err != nil { - return err - } - - d.Set("status", powervmdata.Status) - d.Set("progress", powervmdata.Progress) - - if powervmdata.Health != nil { - d.Set("healthstatus", powervmdata.Health.Status) - - } - - pvminstanceid := *powervmdata.PvmInstanceID - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, pvminstanceid)) - - return nil - -} - -func resourceIBMPIOperationsUpdate(d *schema.ResourceData, meta interface{}) error { - - return nil -} - -func resourceIBMPIOperationsDelete(data *schema.ResourceData, meta interface{}) error { - - return nil -} - -// Exists - -func resourceIBMPIOperationsExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - id := d.Id() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - instance, err := client.Get(d.Id(), powerinstanceid, getTimeOut) - if err != nil { - - return false, err - } - return instance.PvmInstanceID == &id, nil -} - -func isWaitForPIInstanceOperationStatus(client *st.IBMPIInstanceClient, name string, timeout time.Duration, powerinstanceid, operation, targetstatus string) (interface{}, error) { - - log.Printf("Waiting for the Operation [ %s ] to be performed on the instance with name [ %s ]", operation, name) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"ACTIVE", "SHUTOFF", "WARNING"}, - Target: []string{targetstatus}, - Refresh: isPIOperationsRefreshFunc(client, name, powerinstanceid, targetstatus), - Delay: 1 * time.Minute, - MinTimeout: 2 * time.Minute, - Timeout: 120 * time.Minute, - } - - return stateConf.WaitForState() - -} - -func isPIOperationsRefreshFunc(client *st.IBMPIInstanceClient, id, powerinstanceid, targetstatus string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - log.Printf("Waiting for the target status to be [ %s ]", targetstatus) - pvm, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - - if *pvm.Status == targetstatus && pvm.Health.Status == helpers.PIInstanceHealthOk { - log.Printf("The health status is now ok") - //if *pvm.Status == "active" ; if *pvm.Addresses[0].IP == nil { - return pvm, targetstatus, nil - //} - } - - return pvm, helpers.PIInstanceHealthWarning, nil - } -} diff --git a/ibm/resource_ibm_pi_snapshot.go b/ibm/resource_ibm_pi_snapshot.go deleted file mode 100644 index 44c6437b0..000000000 --- a/ibm/resource_ibm_pi_snapshot.go +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_p_vm_instances" - "github.com/IBM-Cloud/power-go-client/power/models" -) - -func resourceIBMPISnapshot() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPISnapshotCreate, - Read: resourceIBMPISnapshotRead, - Update: resourceIBMPISnapshotUpdate, - Delete: resourceIBMPISnapshotDelete, - Exists: resourceIBMPISnapshotExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - //Snapshots are created at the pvm instance level - - helpers.PISnapshotName: { - Type: schema.TypeString, - Required: true, - Description: "Unique name of the snapshot", - }, - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "Instance name / id of the pvm", - }, - - helpers.PIInstanceVolumeIds: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - DiffSuppressFunc: applyOnce, - Description: "List of PI volumes", - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: " Cloud Instance ID - This is the service_instance_id.", - }, - - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Snapshot description", - }, - // Computed Attributes - - helpers.PISnapshot: { - Type: schema.TypeString, - Computed: true, - Description: "Id of the snapshot", - }, - - "status": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - "volume_snapshots": { - Type: schema.TypeMap, - Computed: true, - }, - }, - } -} - -func resourceIBMPISnapshotCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - instanceid := d.Get(helpers.PIInstanceName).(string) - volids := expandStringList((d.Get(helpers.PIInstanceVolumeIds).(*schema.Set)).List()) - name := d.Get(helpers.PISnapshotName).(string) - description := d.Get("description").(string) - if d.Get(description) == "" { - description = "Testing from Terraform" - } - - client := st.NewIBMPIInstanceClient(sess, powerinstanceid) - - snapshotBody := &models.SnapshotCreate{Name: &name, Description: description} - - if len(volids) > 0 { - snapshotBody.VolumeIds = volids - } else { - log.Printf("no volumeids provided. Will snapshot the entire instance") - } - - snapshotResponse, err := client.CreatePvmSnapShot(&p_cloud_p_vm_instances.PcloudPvminstancesSnapshotsPostParams{ - Body: snapshotBody, - }, instanceid, powerinstanceid, createTimeOut) - - if err != nil { - log.Printf("[DEBUG] err %s", err) - return err - } - - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, *snapshotResponse.SnapshotID)) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return fmt.Errorf("failed to get the snapshotid %v", err) - } - - pisnapclient := st.NewIBMPISnapshotClient(sess, powerinstanceid) - _, err = isWaitForPIInstanceSnapshotAvailable(pisnapclient, *snapshotResponse.SnapshotID, d.Timeout(schema.TimeoutCreate), powerinstanceid) - if err != nil { - return err - } - - return resourceIBMPISnapshotRead(d, meta) -} - -func resourceIBMPISnapshotRead(d *schema.ResourceData, meta interface{}) error { - log.Printf("Calling the Snapshot Read function post create") - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - powerinstanceid := parts[0] - snapshot := st.NewIBMPISnapshotClient(sess, powerinstanceid) - snapshotdata, err := snapshot.Get(parts[1], powerinstanceid, getTimeOut) - - if err != nil { - return err - } - - d.Set(helpers.PISnapshotName, snapshotdata.Name) - d.Set(helpers.PISnapshot, *snapshotdata.SnapshotID) - d.Set("status", snapshotdata.Status) - d.Set("creation_date", snapshotdata.CreationDate.String()) - d.Set("volume_snapshots", snapshotdata.VolumeSnapshots) - d.Set("last_update_date", snapshotdata.LastUpdateDate.String()) - - return nil -} - -func resourceIBMPISnapshotUpdate(d *schema.ResourceData, meta interface{}) error { - - log.Printf("Calling the IBM Power Snapshot update call") - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPISnapshotClient(sess, powerinstanceid) - - if d.HasChange(helpers.PISnapshotName) || d.HasChange("description") { - name := d.Get(helpers.PISnapshotName).(string) - description := d.Get("description").(string) - snapshotBody := &models.SnapshotUpdate{Name: name, Description: description} - - _, err := client.Update(parts[1], powerinstanceid, snapshotBody, 60) - - if err != nil { - return fmt.Errorf("failed to update the snapshot request %v", err) - - } - - _, err = isWaitForPIInstanceSnapshotAvailable(client, parts[1], d.Timeout(schema.TimeoutCreate), powerinstanceid) - if err != nil { - return err - } - } - - return resourceIBMPISnapshotRead(d, meta) -} - -func resourceIBMPISnapshotDelete(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - - client := st.NewIBMPISnapshotClient(sess, powerinstanceid) - - snapshot, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return err - } - - log.Printf("The snapshot to be deleted is in the following state .. %s", snapshot.Status) - - snapshotdel_err := client.Delete(parts[1], powerinstanceid, deleteTimeOut) - if snapshotdel_err != nil { - return snapshotdel_err - } - - _, err = isWaitForPIInstanceSnapshotDeleted(client, parts[1], d.Timeout(schema.TimeoutDelete), powerinstanceid) - if err != nil { - return err - } - - d.SetId("") - return nil -} -func resourceIBMPISnapshotExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of powerInstanceID/SnapshotID", d.Id()) - } - powerinstanceid := parts[0] - client := st.NewIBMPISnapshotClient(sess, powerinstanceid) - - snapshotdelete, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - - log.Printf("Calling the existing function.. %s", *(snapshotdelete.SnapshotID)) - - volumeid := *snapshotdelete.SnapshotID - return volumeid == parts[1], nil -} - -func isWaitForPIInstanceSnapshotAvailable(client *st.IBMPISnapshotClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - - log.Printf("Waiting for PIInstance Snapshot (%s) to be available and active ", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"in_progress", "BUILD"}, - Target: []string{"available", "ACTIVE"}, - Refresh: isPIInstanceSnapshotRefreshFunc(client, id, powerinstanceid), - Delay: 30 * time.Second, - MinTimeout: 2 * time.Minute, - Timeout: 60 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceSnapshotRefreshFunc(client *st.IBMPISnapshotClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - snapshotInfo, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - - //if pvm.Health.Status == helpers.PIInstanceHealthOk { - if snapshotInfo.Status == "available" && snapshotInfo.PercentComplete == 100 { - log.Printf("The snapshot is now available") - return snapshotInfo, "available", nil - - } - return snapshotInfo, "in_progress", nil - } -} - -// Delete Snapshot - -func isWaitForPIInstanceSnapshotDeleted(client *st.IBMPISnapshotClient, id string, timeout time.Duration, powerinstanceid string) (interface{}, error) { - - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIInstanceDeleting}, - Target: []string{"Not Found"}, - Refresh: isPIInstanceSnapshotDeleteRefreshFunc(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - Timeout: 10 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isPIInstanceSnapshotDeleteRefreshFunc(client *st.IBMPISnapshotClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - snapshot, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - log.Printf("The snapshot is not found.") - return snapshot, helpers.PIInstanceNotFound, nil - - } - return snapshot, helpers.PIInstanceNotFound, nil - - } -} diff --git a/ibm/resource_ibm_pi_snapshot_test.go b/ibm/resource_ibm_pi_snapshot_test.go deleted file mode 100644 index acd1dfe1f..000000000 --- a/ibm/resource_ibm_pi_snapshot_test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { - - name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIInstanceSnapshotConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceSnapshotExists("ibm_pi_snapshot.power_snapshot"), - resource.TestCheckResourceAttr( - "ibm_pi_snapshot.power_snapshot", "pi_snap_shot_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_snapshot" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - networkC := st.NewIBMPISnapshotClient(sess, powerinstanceid) - _, err = networkC.Get(parts[1], powerinstanceid, getTimeOut) - if err == nil { - return fmt.Errorf("PI Instance Snapshot still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPISnapshotClient(sess, powerinstanceid) - - snapshot, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - return err - } - parts[1] = *snapshot.SnapshotID - return nil - - } -} - -func testAccCheckIBMPIInstanceSnapshotConfig(name string) string { - return testAccCheckIBMPIInstanceConfig(name) + fmt.Sprintf(` - resource "ibm_pi_snapshot" "power_snapshot"{ - depends_on=[ibm_pi_instance.power_instance] - pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name - pi_cloud_instance_id = "%s" - pi_snap_shot_name = "%s" - pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] - } - `, pi_cloud_instance_id, name) -} diff --git a/ibm/resource_ibm_pi_volume.go b/ibm/resource_ibm_pi_volume.go deleted file mode 100644 index e2e5f1761..000000000 --- a/ibm/resource_ibm_pi_volume.go +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_volumes" - "github.com/IBM-Cloud/power-go-client/power/models" -) - -const ( - /* Power Volume creation depends on response from PowerVC */ - volPostTimeOut = 180 * time.Second - volGetTimeOut = 180 * time.Second - volDeleteTimeOut = 180 * time.Second - PIAffinityPolicy = "pi_affinity_policy" - PIAffinityVolume = "pi_affinity_volume" - PIAffinityInstance = "pi_affinity_instance" - PIAntiAffinityInstances = "pi_anti_affinity_instances" - PIAntiAffinityVolumes = "pi_anti_affinity_volumes" -) - -func resourceIBMPIVolume() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIVolumeCreate, - Read: resourceIBMPIVolumeRead, - Update: resourceIBMPIVolumeUpdate, - Delete: resourceIBMPIVolumeDelete, - Exists: resourceIBMPIVolumeExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "Cloud Instance ID - This is the service_instance_id.", - }, - helpers.PIVolumeName: { - Type: schema.TypeString, - Required: true, - Description: "Volume Name to create", - }, - helpers.PIVolumeShareable: { - Type: schema.TypeBool, - Optional: true, - Description: "Flag to indicate if the volume can be shared across multiple instances?", - }, - helpers.PIVolumeSize: { - Type: schema.TypeFloat, - Required: true, - Description: "Size of the volume in GB", - }, - helpers.PIVolumeType: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"ssd", "standard", "tier1", "tier3"}), - Description: "Type of Disk, required if pi_affinity_policy and pi_volume_pool not provided, otherwise ignored", - }, - helpers.PIVolumePool: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Volume pool where the volume will be created; if provided then pi_volume_type and pi_affinity_policy values will be ignored", - }, - PIAffinityPolicy: { - Type: schema.TypeString, - Optional: true, - Description: "Affinity policy for data volume being created; ignored if pi_volume_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", - ValidateFunc: InvokeValidator("ibm_pi_volume", "pi_affinity"), - }, - PIAffinityVolume: { - Type: schema.TypeString, - Optional: true, - Description: "Volume (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", - ConflictsWith: []string{PIAffinityInstance}, - }, - PIAffinityInstance: { - Type: schema.TypeString, - Optional: true, - Description: "PVM Instance (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_volume is not provided", - ConflictsWith: []string{PIAffinityVolume}, - }, - PIAntiAffinityVolumes: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of volumes to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", - ConflictsWith: []string{PIAntiAffinityInstances}, - }, - PIAntiAffinityInstances: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of pvmInstances to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", - ConflictsWith: []string{PIAntiAffinityVolumes}, - }, - - // Computed Attributes - "volume_id": { - Type: schema.TypeString, - Computed: true, - Description: "Volume ID", - }, - "volume_status": { - Type: schema.TypeString, - Computed: true, - Description: "Volume status", - }, - - "delete_on_termination": { - Type: schema.TypeBool, - Computed: true, - Description: "Should the volume be deleted during termination", - }, - "wwn": { - Type: schema.TypeString, - Computed: true, - Description: "WWN Of the volume", - }, - }, - } -} -func resourceIBMPIVolumeValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "pi_affinity", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "affinity, anti-affinity"}) - ibmPIVolumeResourceValidator := ResourceValidator{ - ResourceName: "ibm_pi_volume", - Schema: validateSchema} - return &ibmPIVolumeResourceValidator -} -func resourceIBMPIVolumeCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - name := d.Get(helpers.PIVolumeName).(string) - volType := d.Get(helpers.PIVolumeType).(string) - size := float64(d.Get(helpers.PIVolumeSize).(float64)) - var shared bool - if v, ok := d.GetOk(helpers.PIVolumeShareable); ok { - shared = v.(bool) - } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - body := models.CreateDataVolume{ - Name: &name, - DiskType: volType, - Shareable: &shared, - Size: &size, - } - if v, ok := d.GetOk(helpers.PIVolumePool); ok { - volumePool := v.(string) - body.VolumePool = volumePool - } - if ap, ok := d.GetOk(PIAffinityPolicy); ok { - policy := ap.(string) - body.AffinityPolicy = &policy - - if policy == "affinity" { - if av, ok := d.GetOk(PIAffinityVolume); ok { - afvol := av.(string) - body.AffinityVolume = &afvol - } - if ai, ok := d.GetOk(PIAffinityInstance); ok { - afins := ai.(string) - body.AffinityPVMInstance = &afins - } - } else { - if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { - afvols := expandStringList(avs.([]interface{})) - body.AntiAffinityVolumes = afvols - } - if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { - afinss := expandStringList(ais.([]interface{})) - body.AntiAffinityPVMInstances = afinss - } - } - - } - - resquestParams := p_cloud_volumes.PcloudCloudinstancesVolumesPostParams{ - Body: &body, - CloudInstanceID: powerinstanceid, - } - - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - vol, err := client.CreateVolume(&resquestParams, powerinstanceid, volPostTimeOut) - if err != nil { - return fmt.Errorf("Failed to Create the volume %v", err) - } - - volumeid := *vol.VolumeID - d.SetId(fmt.Sprintf("%s/%s", powerinstanceid, volumeid)) - - _, err = isWaitForIBMPIVolumeAvailable(client, volumeid, powerinstanceid, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - - return resourceIBMPIVolumeRead(d, meta) -} - -func resourceIBMPIVolumeRead(d *schema.ResourceData, meta interface{}) error { - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - vol, err := client.Get(parts[1], powerinstanceid, volGetTimeOut) - if err != nil { - return fmt.Errorf("Failed to get the volume %v", err) - - } - d.Set(helpers.PIVolumeName, vol.Name) - d.Set(helpers.PIVolumeSize, vol.Size) - if vol.Shareable != nil { - d.Set(helpers.PIVolumeShareable, vol.Shareable) - } - d.Set(helpers.PIVolumeType, vol.DiskType) - d.Set(helpers.PIVolumePool, vol.VolumePool) - d.Set("volume_status", vol.State) - if vol.VolumeID != nil { - d.Set("volume_id", vol.VolumeID) - } - if vol.DeleteOnTermination != nil { - d.Set("delete_on_termination", vol.DeleteOnTermination) - } - d.Set("wwn", vol.Wwn) - d.Set(helpers.PICloudInstanceId, powerinstanceid) - - return nil -} - -func resourceIBMPIVolumeUpdate(d *schema.ResourceData, meta interface{}) error { - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - name := d.Get(helpers.PIVolumeName).(string) - size := float64(d.Get(helpers.PIVolumeSize).(float64)) - var shareable bool - if v, ok := d.GetOk(helpers.PIVolumeShareable); ok { - shareable = v.(bool) - } - - body := models.UpdateVolume{ - Name: &name, - Shareable: &shareable, - Size: size, - } - updateParams := p_cloud_volumes.PcloudCloudinstancesVolumesPutParams{ - Body: &body, - CloudInstanceID: powerinstanceid, - } - volrequest, err := client.UpdateVolume(&updateParams, parts[1], powerinstanceid, volPostTimeOut) - if err != nil { - return err - } - _, err = isWaitForIBMPIVolumeAvailable(client, *volrequest.VolumeID, powerinstanceid, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return err - } - - return resourceIBMPIVolumeRead(d, meta) -} - -func resourceIBMPIVolumeDelete(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - parts, err := idParts(d.Id()) - if err != nil { - return err - } - powerinstanceid := parts[0] - - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - voldeleteErr := client.DeleteVolume(parts[1], powerinstanceid, deleteTimeOut) - if voldeleteErr != nil { - return voldeleteErr - } - _, err = isWaitForIBMPIVolumeDeleted(client, parts[1], powerinstanceid, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err - } - d.SetId("") - return nil -} -func resourceIBMPIVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return false, err - } - parts, err := idParts(d.Id()) - if err != nil { - return false, err - } - if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of powerInstanceID/VolumeID", d.Id()) - } - powerinstanceid := parts[0] - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - vol, err := client.Get(parts[1], powerinstanceid, getTimeOut) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - - log.Printf("Calling the existing function.. %s", *(vol.VolumeID)) - - volumeid := *vol.VolumeID - return volumeid == parts[1], nil -} - -func isWaitForIBMPIVolumeAvailable(client *st.IBMPIVolumeClient, id, powerinstanceid string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Volume (%s) to be available.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIVolumeProvisioning}, - Target: []string{helpers.PIVolumeProvisioningDone}, - Refresh: isIBMPIVolumeRefreshFunc(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 2 * time.Minute, - Timeout: 30 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isIBMPIVolumeRefreshFunc(client *st.IBMPIVolumeClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - vol, err := client.Get(id, powerinstanceid, volGetTimeOut) - if err != nil { - return nil, "", err - } - - if vol.State == "available" { - return vol, helpers.PIVolumeProvisioningDone, nil - } - - return vol, helpers.PIVolumeProvisioning, nil - } -} - -func isWaitForIBMPIVolumeDeleted(client *st.IBMPIVolumeClient, id, powerinstanceid string, timeout time.Duration) (interface{}, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{"deleting", helpers.PIVolumeProvisioning}, - Target: []string{"deleted"}, - Refresh: isIBMPIVolumeDeleteRefreshFunc(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 2 * time.Minute, - Timeout: 30 * time.Minute, - } - return stateConf.WaitForState() -} - -func isIBMPIVolumeDeleteRefreshFunc(client *st.IBMPIVolumeClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - vol, err := client.Get(id, powerinstanceid, volGetTimeOut) - if err != nil { - if strings.Contains(err.Error(), "Resource not found") { - return vol, "deleted", nil - } - return nil, "", err - } - if vol == nil { - return vol, "deleted", nil - } - return vol, "deleting", nil - } -} diff --git a/ibm/resource_ibm_pi_volume_attach.go b/ibm/resource_ibm_pi_volume_attach.go deleted file mode 100644 index fe8ed7763..000000000 --- a/ibm/resource_ibm_pi_volume_attach.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "log" - "time" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - - /* Fix for PowerVC taking time to attach volume depending on load*/ - - attachVolumeTimeOut = 240 * time.Second -) - -func resourceIBMPIVolumeAttach() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMPIVolumeAttachCreate, - Read: resourceIBMPIVolumeAttachRead, - Update: resourceIBMPIVolumeAttachUpdate, - Delete: resourceIBMPIVolumeAttachDelete, - //Exists: resourceIBMPowerVolumeExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - - "volumeattachid": { - Type: schema.TypeString, - Computed: true, - ForceNew: true, - Optional: true, - Description: "Volume attachment ID", - }, - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: " Cloud Instance ID - This is the service_instance_id.", - }, - - helpers.PIVolumeAttachName: { - Type: schema.TypeString, - Required: true, - Description: "Name of the volume to attach. Note these volumes should have been created", - }, - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - Description: "PI Instance name", - }, - - helpers.PIVolumeAttachStatus: { - Type: schema.TypeString, - Computed: true, - Optional: true, - }, - helpers.PIVolumeShareable: { - Type: schema.TypeBool, - Computed: true, - Optional: true, - }, - }, - } -} - -func resourceIBMPIVolumeAttachCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).IBMPISession() - if err != nil { - return err - } - - name := d.Get(helpers.PIVolumeAttachName).(string) - servername := d.Get(helpers.PIInstanceName).(string) - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - volinfo, err := client.Get(name, powerinstanceid, getTimeOut) - - if err != nil { - return fmt.Errorf("The volume [ %s] cannot be attached since it's not available", name) - } - //log.Print("The volume info is %s", volinfo) - - if volinfo.State == "available" || *volinfo.Shareable == true { - log.Printf(" In the current state the volume can be attached to the instance ") - } - - if volinfo.State == "in-use" && *volinfo.Shareable == true { - - log.Printf("Volume State /Status is permitted and hence attaching the volume to the instance") - } - - if volinfo.State == helpers.PIVolumeAllowableAttachStatus && *volinfo.Shareable == false { - - return errors.New("The volume cannot be attached in the current state. The volume must be in the *available* state. No other states are permissible") - } - - resp, err := client.Attach(servername, name, powerinstanceid, attachVolumeTimeOut) - - if err != nil { - return err - } - log.Printf("Printing the resp %+v", resp) - - d.SetId(*volinfo.VolumeID) - if err != nil { - log.Printf("[DEBUG] err %s", err) - return err - } - - _, err = isWaitForIBMPIVolumeAttachAvailable(client, d.Id(), powerinstanceid, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - //return nil - return resourceIBMPIVolumeAttachRead(d, meta) -} - -func resourceIBMPIVolumeAttachRead(d *schema.ResourceData, meta interface{}) error { - sess, _ := meta.(ClientSession).IBMPISession() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - servername := d.Get(helpers.PIInstanceName).(string) - - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - vol, err := client.CheckVolumeAttach(powerinstanceid, servername, d.Id(), getTimeOut) - if err != nil { - return err - } - - //d.SetId(vol.ID.String()) - d.Set(helpers.PIVolumeAttachName, vol.Name) - d.Set(helpers.PIVolumeSize, vol.Size) - d.Set(helpers.PIVolumeShareable, vol.Shareable) - return nil -} - -func resourceIBMPIVolumeAttachUpdate(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - name := "" - if d.HasChange(helpers.PIVolumeAttachName) { - name = d.Get(helpers.PIVolumeAttachName).(string) - } - - size := float64(d.Get(helpers.PIVolumeSize).(float64)) - shareable := bool(d.Get(helpers.PIVolumeShareable).(bool)) - - volrequest, err := client.Update(d.Id(), name, size, shareable, powerinstanceid, postTimeOut) - if err != nil { - return err - } - - _, err = isWaitForIBMPIVolumeAttachAvailable(client, *volrequest.VolumeID, powerinstanceid, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - - return resourceIBMPIVolumeRead(d, meta) -} - -func resourceIBMPIVolumeAttachDelete(d *schema.ResourceData, meta interface{}) error { - - sess, _ := meta.(ClientSession).IBMPISession() - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - name := d.Get(helpers.PIVolumeAttachName).(string) - servername := d.Get(helpers.PIInstanceName).(string) - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - log.Printf("the id of the volume to detach is%s ", d.Id()) - _, err := client.Detach(servername, name, powerinstanceid, deleteTimeOut) - if err != nil { - return err - } - - // wait for power volume states to be back as available. if it's attached it will be in-use - d.SetId("") - return nil -} - -func isWaitForIBMPIVolumeAttachAvailable(client *st.IBMPIVolumeClient, id, powerinstanceid string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Volume (%s) to be available for attachment", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIVolumeProvisioning}, - Target: []string{helpers.PIVolumeAllowableAttachStatus}, - Refresh: isIBMPIVolumeAttachRefreshFunc(client, id, powerinstanceid), - Delay: 10 * time.Second, - MinTimeout: 2 * time.Minute, - Timeout: 10 * time.Minute, - } - - return stateConf.WaitForState() -} - -func isIBMPIVolumeAttachRefreshFunc(client *st.IBMPIVolumeClient, id, powerinstanceid string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - vol, err := client.Get(id, powerinstanceid, getTimeOut) - if err != nil { - return nil, "", err - } - - if vol.State == "in-use" { - return vol, helpers.PIVolumeAllowableAttachStatus, nil - } - - return vol, helpers.PIVolumeProvisioning, nil - } -} diff --git a/ibm/resource_ibm_pi_volume_test.go b/ibm/resource_ibm_pi_volume_test.go deleted file mode 100644 index 459e6a7b5..000000000 --- a/ibm/resource_ibm_pi_volume_test.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "errors" - "fmt" - "log" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPIVolumebasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-volume-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIVolumeDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIVolumeConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIVolumeExists("ibm_pi_volume.power_volume"), - resource.TestCheckResourceAttr( - "ibm_pi_volume.power_volume", "pi_volume_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPIVolumeDestroy(s *terraform.State) error { - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_volume" { - continue - } - parts, err := idParts(rs.Primary.ID) - powerinstanceid := parts[0] - volumeC := st.NewIBMPIVolumeClient(sess, powerinstanceid) - volume, err := volumeC.Get(parts[1], powerinstanceid, volGetTimeOut) - if err == nil { - log.Println("volume*****", volume.State) - return fmt.Errorf("PI Volume still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPIVolumeExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := testAccProvider.Meta().(ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := idParts(rs.Primary.ID) - if err != nil { - return err - } - powerinstanceid := parts[0] - client := st.NewIBMPIVolumeClient(sess, powerinstanceid) - - volume, err := client.Get(parts[1], powerinstanceid, volGetTimeOut) - if err != nil { - return err - } - parts[1] = *volume.VolumeID - return nil - - } -} - -func testAccCheckIBMPIVolumeConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_pi_volume" "power_volume"{ - pi_volume_size = 20 - pi_volume_name = "%s" - pi_volume_type = "tier1" - pi_volume_shareable = true - pi_cloud_instance_id = "%s" - } - `, name, pi_cloud_instance_id) -} - -func TestAccIBMPIVolumePool(t *testing.T) { - name := fmt.Sprintf("tf-pi-volume-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPIVolumeDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPIVolumePoolConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIVolumeExists("ibm_pi_volume.power_volume"), - resource.TestCheckResourceAttr( - "ibm_pi_volume.power_volume", "pi_volume_name", name), - resource.TestCheckResourceAttr( - "ibm_pi_volume.power_volume", "pi_volume_pool", "Tier3-Flash-1"), - ), - }, - }, - }) -} -func testAccCheckIBMPIVolumePoolConfig(name string) string { - return fmt.Sprintf(` - resource "ibm_pi_volume" "power_volume"{ - pi_volume_size = 20 - pi_volume_name = "%s" - pi_volume_pool = "Tier3-Flash-1" - pi_volume_shareable = true - pi_cloud_instance_id = "%s" - } - `, name, pi_cloud_instance_id) -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver.go b/ibm/resource_ibm_private_dns_custom_resolver.go deleted file mode 100644 index 84972125f..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver.go +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/IBM/networking-go-sdk/dnssvcsv1" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmDNSCustomResolver = "ibm_dns_custom_resolver" - pdnsCustomResolvers = "custom_resolvers" - pdnsCustomResolverLocations = "locations" - pdnsCRId = "custom_resolver_id" - pdnsCRName = "name" - pdnsCRDescription = "description" - pdnsCRHealth = "health" - pdnsCREnabled = "enabled" - pdnsCRCreatedOn = "created_on" - pdnsCRModifiedOn = "modified_on" - pdnsCRLocationId = "location_id" - pdnsCRLocationSubnetCrn = "subnet_crn" - pdnsCRLocationEnabled = "enabled" - pdnsCRLocationHealthy = "healthy" - pdnsCRLocationDnsServerIp = "dns_server_ip" - pdnsCustomResolverCritical = "CRITICAL" - pdnsCustomResolverDegraded = "DEGRADED" - pdnsCustomResolverHealthy = "HEALTHY" - pdnsCRHighAvailability = "high_availability" -) - -func resouceIBMPrivateDNSCustomResolver() *schema.Resource { - return &schema.Resource{ - CreateContext: resouceIBMPrivateDNSCustomResolverCreate, - ReadContext: resouceIBMPrivateDNSCustomResolverRead, - UpdateContext: resouceIBMPrivateDNSCustomResolverUpdate, - DeleteContext: resouceIBMPrivateDNSCustomResolverDelete, - Exists: resouceIBMPrivateDNSCustomResolverExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - pdnsInstanceID: { - Type: schema.TypeString, - Required: true, - Description: "Instance ID", - }, - - pdnsCRId: { - Type: schema.TypeString, - Computed: true, - Description: "Identifier of the custom resolver", - }, - pdnsCRName: { - Type: schema.TypeString, - Required: true, - Description: "Name of the custom resolver", - }, - pdnsCRDescription: { - Type: schema.TypeString, - Optional: true, - Description: "Descriptive text of the custom resolver.", - }, - pdnsCREnabled: { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Whether the custom resolver is enabled", - }, - pdnsCRHighAvailability: { - Type: schema.TypeBool, - Optional: true, - Default: true, - ForceNew: true, - Description: "Whether High Availability is enabled in custom resolver", - }, - pdnsCRHealth: { - Type: schema.TypeString, - Computed: true, - Description: "Healthy state of the custom resolver", - }, - pdnsCustomResolverLocations: { - Type: schema.TypeSet, - Description: "Locations on which the custom resolver will be running", - Optional: true, - DiffSuppressFunc: applyOnce, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - pdnsCRLocationId: { - Type: schema.TypeString, - Computed: true, - Description: "Location ID", - }, - pdnsCRLocationSubnetCrn: { - Type: schema.TypeString, - Required: true, - Description: "Subnet CRN", - }, - pdnsCRLocationEnabled: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Whether the location is enabled for the custom resolver", - }, - pdnsCRLocationHealthy: { - Type: schema.TypeBool, - Computed: true, - Description: "Whether the DNS server in this location is healthy or not.", - }, - pdnsCRLocationDnsServerIp: { - Type: schema.TypeString, - Computed: true, - Description: "The ip address of this dns server", - }, - }, - }, - }, - - pdnsCRCreatedOn: { - Type: schema.TypeString, - Computed: true, - Description: "Time when a custom resolver is created", - }, - - pdnsCRModifiedOn: { - Type: schema.TypeString, - Computed: true, - Description: "The recent time when a custom resolver is modified", - }, - }, - } -} - -func resouceIBMPrivateDNSCustomResolverCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - var crName, crDescription string - - // session options - crn := d.Get(pdnsInstanceID).(string) - if name, ok := d.GetOk(pdnsCRName); ok { - crName = name.(string) - } - if des, ok := d.GetOk(pdnsCRDescription); ok { - crDescription = des.(string) - } - - customResolverOption := sess.NewCreateCustomResolverOptions(crn) - customResolverOption.SetName(crName) - customResolverOption.SetDescription(crDescription) - - cr_highaval := d.Get(pdnsCRHighAvailability).(bool) - - crLocationCreate := false - if _, ok := d.GetOk(pdnsCustomResolverLocations); ok { - crLocationCreate = true - crLocations := d.Get(pdnsCustomResolverLocations).(*schema.Set) - if cr_highaval && crLocations.Len() <= 1 { - return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations. A maximum of four locations can be configured within the same subnet location.")) - } - customResolverOption.SetLocations(expandPdnsCRLocations(crLocations)) - } else { - if cr_highaval { - return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations. A maximum of four locations can be configured within the same subnet location.")) - } - } - - result, resp, err := sess.CreateCustomResolverWithContext(context, customResolverOption) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error reading the custom resolver %s:%s", err, resp)) - } - - d.SetId(convertCisToTfTwoVar(*result.ID, crn)) - d.Set(pdnsCRId, *result.ID) - - if crLocationCreate { - _, err = waitForPDNSCustomResolverHealthy(d, meta) - if err != nil { - return diag.FromErr(err) - } - return resouceIBMPrivateDNSCustomResolverUpdate(context, d, meta) - } - return resouceIBMPrivateDNSCustomResolverRead(context, d, meta) -} - -func resouceIBMPrivateDNSCustomResolverRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - customResolverID, crn, err := convertTftoCisTwoVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - opt := sess.NewGetCustomResolverOptions(crn, customResolverID) - result, response, err := sess.GetCustomResolverWithContext(context, opt) - - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("Error reading the custom resolver %s:%s", err, response)) - } - d.Set(pdnsInstanceID, crn) - d.Set(pdnsCRId, *result.ID) - d.Set(pdnsCRName, *result.Name) - d.Set(pdnsCRDescription, *result.Description) - d.Set(pdnsCRHealth, *result.Health) - d.Set(pdnsCREnabled, *result.Enabled) - d.Set(pdnsCustomResolverLocations, flattenPdnsCRLocations(result.Locations)) - - return nil -} - -func resouceIBMPrivateDNSCustomResolverUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - customResolverID, crn, err := convertTftoCisTwoVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - - if d.HasChange(pdnsCRName) || - d.HasChange(pdnsCRDescription) || - d.HasChange(pdnsCREnabled) { - - opt := sess.NewUpdateCustomResolverOptions(crn, customResolverID) - if name, ok := d.GetOk(pdnsCRName); ok { - crName := name.(string) - opt.SetName(crName) - } - if des, ok := d.GetOk(pdnsCRDescription); ok { - crDescription := des.(string) - opt.SetDescription(crDescription) - } - if enabled, ok := d.GetOkExists(pdnsCREnabled); ok { - crEnabled := enabled.(bool) - opt.SetEnabled(crEnabled) - } - - result, resp, err := sess.UpdateCustomResolverWithContext(context, opt) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error updating the custom resolver %s:%s", err, resp)) - } - - } - - return resouceIBMPrivateDNSCustomResolverRead(context, d, meta) -} - -func resouceIBMPrivateDNSCustomResolverDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - customResolverID, crn, err := convertTftoCisTwoVar(d.Id()) - if err != nil { - return diag.FromErr(err) - } - // Disable Cutsom Resolver before deleting - optEnabled := sess.NewUpdateCustomResolverOptions(crn, customResolverID) - optEnabled.SetEnabled(false) - result, resp, errEnabled := sess.UpdateCustomResolverWithContext(context, optEnabled) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error updating the custom resolver to disable before deleting %s:%s", errEnabled, resp)) - } - - opt := sess.NewDeleteCustomResolverOptions(crn, customResolverID) - response, err := sess.DeleteCustomResolverWithContext(context, opt) - - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return diag.FromErr(fmt.Errorf("Error deleting the custom resolver %s:%s", err, response)) - } - - d.SetId("") - return nil -} - -func resouceIBMPrivateDNSCustomResolverExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return false, err - } - - customResolverID, crn, err := convertTftoCisTwoVar(d.Id()) - if err != nil { - return false, err - } - opt := sess.NewGetCustomResolverOptions(crn, customResolverID) - _, response, err := sess.GetCustomResolver(opt) - - if err != nil { - if response != nil && response.StatusCode == 404 { - log.Printf("Custom Resolver does not exist.") - return false, nil - } - log.Printf("Custom Resolver failed: %v", response) - return false, err - } - return true, nil -} - -func flattenPdnsCRLocations(crLocation []dnssvcsv1.Location) interface{} { - flattened := make([]interface{}, 0) - for _, v := range crLocation { - customLocations := map[string]interface{}{ - pdnsCRLocationId: *v.ID, - pdnsCRLocationSubnetCrn: *v.SubnetCrn, - pdnsCRLocationEnabled: *v.Enabled, - pdnsCRLocationHealthy: *v.Healthy, - pdnsCRLocationDnsServerIp: *v.DnsServerIp, - } - flattened = append(flattened, customLocations) - } - return flattened -} - -func expandPdnsCRLocations(crLocList *schema.Set) (crLocations []dnssvcsv1.LocationInput) { - for _, iface := range crLocList.List() { - var locOpt dnssvcsv1.LocationInput - loc := iface.(map[string]interface{}) - locOpt.SubnetCrn = core.StringPtr(loc[pdnsCRLocationSubnetCrn].(string)) - if val, ok := loc[pdnsCRLocationEnabled]; ok { - locOpt.Enabled = core.BoolPtr(val.(bool)) - } - crLocations = append(crLocations, locOpt) - } - return -} - -func waitForPDNSCustomResolverHealthy(d *schema.ResourceData, meta interface{}) (interface{}, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return nil, err - } - - var customResolverID, crn string - - g := strings.SplitN(d.Id(), ":", -1) - if len(g) > 2 { - _, customResolverID, crn, _ = convertTfToCisThreeVar(d.Id()) - } else { - customResolverID, crn, _ = convertTftoCisTwoVar(d.Id()) - } - - opt := sess.NewGetCustomResolverOptions(crn, customResolverID) - - stateConf := &resource.StateChangeConf{ - Pending: []string{pdnsCustomResolverCritical, "false"}, - Target: []string{pdnsCustomResolverDegraded, pdnsCustomResolverHealthy, "true"}, - Refresh: func() (interface{}, string, error) { - res, detail, err := sess.GetCustomResolver(opt) - if err != nil { - if detail != nil && detail.StatusCode == 404 { - return nil, "", fmt.Errorf("The custom resolver %s does not exist anymore: %v", customResolverID, err) - } - return nil, "", fmt.Errorf("Get the custom resolver %s failed with resp code: %s, err: %v", customResolverID, detail, err) - } - return res, *res.Health, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 60 * time.Second, - } - - return stateConf.WaitForState() -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule.go b/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule.go deleted file mode 100644 index a91b76ee4..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - pdnsCRForwardRule = "ibm_dns_custom_resolver_forwarding_rule" - pdnsCRForwardRules = "rules" - pdnsCRFRResolverID = "resolver_id" - pdnsCRFRDesctiption = "description" - pdnsCRFRType = "type" - pdnsCRFRMatch = "match" - pdnsCRFRForwardTo = "forward_to" - pdnsCRFRRuleID = "rule_id" - pdnsCRFRCreatedOn = "created_on" - pdnsCRFRModifiedOn = "modified_on" -) - -func resourceIBMPrivateDNSForwardingRule() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIbmDnsCrForwardingRuleCreate, - ReadContext: resourceIbmDnsCrForwardingRuleRead, - UpdateContext: resourceIbmDnsCrForwardingRuleUpdate, - DeleteContext: resourceIbmDnsCrForwardingRuleDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - pdnsInstanceID: { - Type: schema.TypeString, - Required: true, - Description: "The unique identifier of a service instance.", - }, - pdnsCRFRResolverID: { - Type: schema.TypeString, - Required: true, - Description: "The unique identifier of a custom resolver.", - }, - pdnsCRFRDesctiption: { - Type: schema.TypeString, - Optional: true, - Description: "Descriptive text of the forwarding rule.", - }, - pdnsCRFRType: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator(pdnsCRForwardRule, "type"), - Description: "Type of the forwarding rule.", - }, - pdnsCRFRMatch: { - Type: schema.TypeString, - Optional: true, - Description: "The matching zone or hostname.", - }, - pdnsCRFRForwardTo: { - Type: schema.TypeList, - Optional: true, - Description: "The upstream DNS servers will be forwarded to.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - pdnsCRFRRuleID: { - Type: schema.TypeString, - Computed: true, - Description: "the time when a forwarding rule ID is created, RFC3339 format.", - }, - }, - } -} - -func resourceIBMPrivateDNSForwardingRuleValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "hostname, zone", - }, - ) - - resourceValidator := ResourceValidator{ResourceName: pdnsCRForwardRule, Schema: validateSchema} - return &resourceValidator -} - -func resourceIbmDnsCrForwardingRuleCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - dnsSvcsClient, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - instanceID := d.Get(pdnsInstanceID).(string) - resolverID := d.Get(pdnsCRFRResolverID).(string) - opt := dnsSvcsClient.NewCreateForwardingRuleOptions(instanceID, resolverID) - - if des, ok := d.GetOk(pdnsCRFRDesctiption); ok { - opt.SetDescription(des.(string)) - } - if t, ok := d.GetOk(pdnsCRFRType); ok { - opt.SetType(t.(string)) - } - if m, ok := d.GetOk(pdnsCRFRMatch); ok { - opt.SetMatch(m.(string)) - } - if _, ok := d.GetOk(pdnsCRFRForwardTo); ok { - opt.SetForwardTo(expandStringList(d.Get(pdnsCRFRForwardTo).([]interface{}))) - } - result, resp, err := dnsSvcsClient.CreateForwardingRuleWithContext(context, opt) - - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error creating the forwarding rules %s:%s", err, resp)) - } - d.SetId(convertCisToTfThreeVar(*result.ID, resolverID, instanceID)) - - return resourceIbmDnsCrForwardingRuleRead(context, d, meta) -} - -func resourceIbmDnsCrForwardingRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - dnsSvcsClient, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - ruleID, resolverID, instanceID, err := convertTfToCisThreeVar(d.Id()) - opt := dnsSvcsClient.NewGetForwardingRuleOptions(instanceID, resolverID, ruleID) - result, resp, err := dnsSvcsClient.GetForwardingRuleWithContext(context, opt) - - if err != nil || result == nil { - if resp != nil && resp.StatusCode == 404 { - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("Error reading the forwarding rules %s:%s", err, resp)) - } - d.Set(pdnsInstanceID, instanceID) - d.Set(pdnsCRFRResolverID, resolverID) - d.Set(pdnsCRFRRuleID, ruleID) - d.Set(pdnsCRFRDesctiption, *result.Description) - d.Set(pdnsCRFRType, *result.Type) - d.Set(pdnsCRFRMatch, *result.Match) - d.Set(pdnsCRFRForwardTo, result.ForwardTo) - return nil - -} -func resourceIbmDnsCrForwardingRuleUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - dnsSvcsClient, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - ruleID, resolverID, instanceID, err := convertTfToCisThreeVar(d.Id()) - - if err != nil { - return diag.FromErr(err) - } - - opt := dnsSvcsClient.NewUpdateForwardingRuleOptions(instanceID, resolverID, ruleID) - if d.HasChange(pdnsCRFRDesctiption) || - d.HasChange(pdnsCRFRMatch) || - d.HasChange(pdnsCRFRForwardTo) { - - if des, ok := d.GetOk(pdnsCRFRDesctiption); ok { - frdes := des.(string) - opt.SetDescription(frdes) - } - if ma, ok := d.GetOk(pdnsCRFRMatch); ok { - frmatch := ma.(string) - opt.SetMatch(frmatch) - } - if _, ok := d.GetOk(pdnsCRFRForwardTo); ok { - opt.SetForwardTo(expandStringList(d.Get(pdnsCRFRForwardTo).([]interface{}))) - } - - result, resp, err := dnsSvcsClient.UpdateForwardingRuleWithContext(context, opt) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error updating the forwarding rule %s:%s", err, resp)) - } - - } - return resourceIbmDnsCrForwardingRuleRead(context, d, meta) -} - -func resourceIbmDnsCrForwardingRuleDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - dnsSvcsClient, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - ruleID, resolverID, instanceID, err := convertTfToCisThreeVar(d.Id()) - opt := dnsSvcsClient.NewDeleteForwardingRuleOptions(instanceID, resolverID, ruleID) - response, err := dnsSvcsClient.DeleteForwardingRuleWithContext(context, opt) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return diag.FromErr(fmt.Errorf("Error deleting the Forwarding Rules %s:%s", err, response)) - } - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go b/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go deleted file mode 100644 index 08f67b16e..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPrivateDNSCustomResolverForwardingRule_basic(t *testing.T) { - typeVar := "zone" - match := "test.example.com" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIbmDnsCrForwardingRuleConfig(typeVar, match), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_forwarding_rule.dns_custom_resolver_forwarding_rule", "type", typeVar), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_forwarding_rule.dns_custom_resolver_forwarding_rule", "match", match), - ), - }, - }, - }) -} - -func testAccCheckIbmDnsCrForwardingRuleConfig(typeVar, match string) string { - return fmt.Sprintf(` - - resource "ibm_dns_custom_resolver" "test" { - name = "testpdnscustomresolver" - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - description = "new test CR Locations - TF" - high_availability = true - enabled = true - locations{ - subnet_crn = "crn:v1:bluemix:public:is:us-south-3:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0737-0d198509-3221-4162-b2d8-4a9326d3d7ad" - enabled = false - } - locations { - subnet_crn = "crn:v1:bluemix:public:is:us-south-2:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0727-f17967f2-2bbe-427c-bcf6-22f8c2395285" - enabled = true - } - } - resource "ibm_dns_custom_resolver_forwarding_rule" "dns_custom_resolver_forwarding_rule" { - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id - description = "Test Fw Rule" - type = "%s" - match = "%s" - forward_to = ["168.20.22.122"] - } - `, typeVar, match) -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver_location.go b/ibm/resource_ibm_private_dns_custom_resolver_location.go deleted file mode 100644 index 26d6f83a2..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver_location.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - ibmCRLocation = "ibm_dns_custom_resolver_location" - pdnsResolverID = "resolver_id" - pdnsCRLocationID = "location_id" - pdnsCRLocationSubnetCRN = "subnet_crn" - pdnsCRLocationEnable = "enabled" - pdnsCRLocationServerIP = "dns_server_ip" - pdnsCustomReolverEnabled = "cr_enabled" -) - -func resourceIBMPrivateDNSCRLocation() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMPrivateDNSLocationCreate, - ReadContext: resourceIBMPrivateDNSLocationRead, - UpdateContext: resourceIBMPrivateDNSLocationUpdate, - DeleteContext: resourceIBMPrivateDNSLocationDelete, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - pdnsInstanceID: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Instance ID", - }, - - pdnsResolverID: { - Type: schema.TypeString, - Required: true, - Description: "Custom Resolver ID", - }, - pdnsCRLocationID: { - Type: schema.TypeString, - Computed: true, - Description: "CRLocation ID", - }, - - pdnsCRLocationSubnetCRN: { - Type: schema.TypeString, - Required: true, - Description: "CRLocation Subnet CRN", - }, - - pdnsCRLocationEnable: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "CRLocation Enabled", - }, - - pdnsCRLocationHealthy: { - Type: schema.TypeBool, - Computed: true, - Description: "CRLocation Healthy", - }, - - pdnsCRLocationServerIP: { - Type: schema.TypeString, - Computed: true, - Description: "CRLocation Server IP", - }, - pdnsCustomReolverEnabled: { - Type: schema.TypeBool, - Optional: true, - Default: true, - DiffSuppressFunc: applyOnce, - }, - }, - } -} -func resourceIBMPrivateDNSLocationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - instanceID := d.Get(pdnsInstanceID).(string) - resolverID := d.Get(pdnsResolverID).(string) - - mk := "private_dns_resource_custom_resolver_location_" + instanceID + resolverID - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) - - opt := sess.NewAddCustomResolverLocationOptions(instanceID, resolverID) - - if subnetcrn, ok := d.GetOk(pdnsCRLocationSubnetCRN); ok { - opt.SetSubnetCrn(subnetcrn.(string)) - } - var enable_loc bool - if enable, ok := d.GetOkExists(pdnsCRLocationEnable); ok { - opt.SetEnabled(enable.(bool)) - enable_loc = enable.(bool) - } - if _, ok := d.GetOkExists(pdnsCustomReolverEnabled); ok { - optCr := sess.NewUpdateCustomResolverOptions(instanceID, resolverID) - optCr.SetEnabled(false) - resultCr, respCr, errCr := sess.UpdateCustomResolverWithContext(context, optCr) - if errCr != nil || resultCr == nil { - return diag.FromErr(fmt.Errorf("Error updating the custom resolver with cr_enable false %s:%s", errCr, respCr)) - } - } - result, resp, err := sess.AddCustomResolverLocationWithContext(context, opt) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error creating the custom resolver location %s:%s", err, resp)) - } - d.SetId(convertCisToTfThreeVar(*result.ID, resolverID, instanceID)) - - if cr_enable, ok := d.GetOkExists(pdnsCustomReolverEnabled); ok { - if cr_enable.(bool) && enable_loc { - _, err = waitForPDNSCustomResolverHealthy(d, meta) - if err != nil { - return diag.FromErr(err) - } - optCr := sess.NewUpdateCustomResolverOptions(instanceID, resolverID) - optCr.SetEnabled(cr_enable.(bool)) - resultCr, respCr, errCr := sess.UpdateCustomResolverWithContext(context, optCr) - if errCr != nil || resultCr == nil { - return diag.FromErr(fmt.Errorf("Error updating the custom resolver %s:%s", errCr, respCr)) - } - } - - } - return resourceIBMPrivateDNSLocationRead(context, d, meta) -} - -func resourceIBMPrivateDNSLocationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - return nil -} -func resourceIBMPrivateDNSLocationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - locationID, resolverID, instanceID, err := convertTfToCisThreeVar(d.Id()) - - mk := "private_dns_resource_custom_resolver_location_" + instanceID + resolverID - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) - - updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, resolverID, locationID) - - if d.HasChange(pdnsCRLocationSubnetCRN) || - d.HasChange(pdnsCRLocationEnable) { - if scrn, ok := d.GetOk(pdnsCRLocationSubnetCRN); ok { - updatelocation.SetSubnetCrn(scrn.(string)) - } - if e, ok := d.GetOkExists(pdnsCRLocationEnable); ok { - updatelocation.SetEnabled(e.(bool)) - } - result, resp, err := sess.UpdateCustomResolverLocationWithContext(context, updatelocation) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error updating the custom resolver location %s:%s", err, resp)) - } - } - return resourceIBMPrivateDNSLocationRead(context, d, meta) -} -func resourceIBMPrivateDNSLocationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() - if err != nil { - return diag.FromErr(err) - } - - locationID, resolverID, instanceID, err := convertTfToCisThreeVar(d.Id()) - delete_loc := true - if cr_enable, ok := d.GetOkExists(pdnsCustomReolverEnabled); ok { - if cr_enable.(bool) { - // Disable the Cutsom Resolver - optEnabled := sess.NewUpdateCustomResolverOptions(instanceID, resolverID) - optEnabled.SetEnabled(false) - - result, resp, errEnabled := sess.UpdateCustomResolverWithContext(context, optEnabled) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error Disable and Update the custom resolver %s:%s", errEnabled, resp)) - } - } else { - // Disable the Cutsom Resolver Location - updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, resolverID, locationID) - updatelocation.SetEnabled(false) - result, resp, err := sess.UpdateCustomResolverLocationWithContext(context, updatelocation) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error Disbale and updating the custom resolver location %s:%s", err, resp)) - } - } - } - // Disable Cutsom Resolver Location before deleting - updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, resolverID, locationID) - updatelocation.SetEnabled(false) - result, resp, err := sess.UpdateCustomResolverLocationWithContext(context, updatelocation) - if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error Disbale and updating the custom resolver location %s:%s", err, resp)) - } - - if delete_loc { - opt := sess.NewGetCustomResolverOptions(instanceID, resolverID) - result, _, _ := sess.GetCustomResolverWithContext(context, opt) - if len(result.Locations) > 1 { - deleteCRlocation := sess.NewDeleteCustomResolverLocationOptions(instanceID, resolverID, locationID) - resp, errDel := sess.DeleteCustomResolverLocationWithContext(context, deleteCRlocation) - if errDel != nil { - if resp != nil && resp.StatusCode == 404 { - return nil - } - return diag.FromErr(fmt.Errorf("Error Deleting the custom resolver location %s:%s", errDel, resp)) - } - } - } - - d.SetId("") - return nil -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver_location_test.go b/ibm/resource_ibm_private_dns_custom_resolver_location_test.go deleted file mode 100644 index aa505ed65..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver_location_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMPrivateDNSCustomResolverLocations_basic(t *testing.T) { - name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) - description := "new test CR Locations - TF" - subnet_crn := "crn:v1:bluemix:public:is:us-south-3:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0737-0d198509-3221-4162-b2d8-4a9326d3d7ad" - subnet_crn_new := "crn:v1:bluemix:public:is:us-south-2:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0727-f17967f2-2bbe-427c-bcf6-22f8c2395285" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPrivateDNSCRLocationsBasic(name, description, subnet_crn, subnet_crn_new), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "subnet_crn", subnet_crn), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "enabled", "true"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "cr_enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "cr_enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "subnet_crn", subnet_crn_new), - ), - }, - }, - }) -} - -func TestAccIBMPrivateDNSCustomResolverLocations_Import(t *testing.T) { - - name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) - description := "new test CR Locations - TF" - subnet_crn := "crn:v1:bluemix:public:is:us-south-3:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0737-0d198509-3221-4162-b2d8-4a9326d3d7ad" - subnet_crn_new := "crn:v1:bluemix:public:is:us-south-2:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0727-f17967f2-2bbe-427c-bcf6-22f8c2395285" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPrivateDNSCRLocationsBasic(name, description, subnet_crn, subnet_crn_new), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "subnet_crn", subnet_crn), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "enabled", "true"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test1", "cr_enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "cr_enabled", "false"), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver_location.test2", "subnet_crn", subnet_crn_new), - ), - }, - { - ResourceName: "ibm_dns_custom_resolver_location.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enabled", - "instance_id", - "resolver_id", - "subnet_crn", - }, - }, - }, - }) -} - -func testAccCheckIBMPrivateDNSCRLocationsBasic(name, description, subnet_crn, subnet_crn_new string) string { - return fmt.Sprintf(` - resource "ibm_dns_custom_resolver" "test" { - name = "%s" - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - description = "%s" - high_availability = false - enabled = false - } - resource "ibm_dns_custom_resolver_location" "test1" { - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id - subnet_crn = "%s" - enabled = true - cr_enabled = false - } - resource "ibm_dns_custom_resolver_location" "test2" { - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id - subnet_crn = "%s" - enabled = false - cr_enabled = false - } - `, name, description, subnet_crn, subnet_crn_new) -} diff --git a/ibm/resource_ibm_private_dns_custom_resolver_test.go b/ibm/resource_ibm_private_dns_custom_resolver_test.go deleted file mode 100644 index dd3d3626a..000000000 --- a/ibm/resource_ibm_private_dns_custom_resolver_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMPrivateDNSCustomResolver_basic(t *testing.T) { - var resultprivatedns string - name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) - description := "new test CR - TF" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPrivateDNSCustomResolverDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPrivateDNSCustomResolverBasic(name, description), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPrivateDNSCustomResolverExists("ibm_dns_custom_resolver.test", resultprivatedns), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "name", name), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "description", description), - ), - }, - }, - }) -} - -func TestAccIBMPrivateDNSCustomResolverImport(t *testing.T) { - var resultprivatedns string - name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) - description := "new test CR - TF" - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMPrivateDNSCustomResolverDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPrivateDNSCustomResolverBasic(name, description), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPrivateDNSCustomResolverExists("ibm_dns_custom_resolver.test", resultprivatedns), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "name", name), - resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "description", description), - ), - }, - { - ResourceName: "ibm_dns_custom_resolver.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "type"}, - }, - }, - }) -} - -func testAccCheckIBMPrivateDNSCustomResolverBasic(name, description string) string { - return fmt.Sprintf(` - resource "ibm_dns_custom_resolver" "test" { - name = "%s" - instance_id = "c9e23743-b039-4f33-ba8a-c3bf35e9b450" - description = "%s" - high_availability = false - enabled = true - locations { - subnet_crn = "crn:v1:bluemix:public:is:us-south-3:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0737-0d198509-3221-4162-b2d8-4a9326d3d7ad" - enabled = false - } - locations { - subnet_crn = "crn:v1:bluemix:public:is:us-south-2:a/bcf1865e99742d38d2d5fc3fb80a5496::subnet:0727-f17967f2-2bbe-427c-bcf6-22f8c2395285" - enabled = true - } - } - `, name, description) -} - -func testAccCheckIBMPrivateDNSCustomResolverDestroy(s *terraform.State) error { - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_dns_custom_resolver" { - continue - } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() - if err != nil { - return err - } - parts := rs.Primary.ID - partslist := strings.Split(parts, ":") - customResolverID := partslist[0] - crn := partslist[1] - - getCustomResolverOptions := pdnsClient.NewDeleteCustomResolverOptions(crn, customResolverID) - res, err := pdnsClient.DeleteCustomResolver(getCustomResolverOptions) - if err != nil { - if res != nil && res.StatusCode == 404 { - return nil - } - return fmt.Errorf("testAccCheckIBMPrivateDNSCustomResolverDestroy: Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - return nil -} - -func testAccCheckIBMPrivateDNSCustomResolverExists(n string, result string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() - if err != nil { - return err - } - parts := rs.Primary.ID - partslist := strings.Split(parts, ":") - customResolverID := partslist[0] - crn := partslist[1] - - getCustomResolverOptions := pdnsClient.NewGetCustomResolverOptions(crn, customResolverID) - r, res, err := pdnsClient.GetCustomResolver(getCustomResolverOptions) - - if err != nil { - if res != nil && res.StatusCode == 404 { - return nil - } - return fmt.Errorf("testAccCheckIBMPrivateDNSCustomResolverExists: Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) - } - - result = *r.ID - return nil - } -} diff --git a/ibm/resource_ibm_push_notification_chrome.go b/ibm/resource_ibm_push_notification_chrome.go deleted file mode 100644 index 780b3ea7f..000000000 --- a/ibm/resource_ibm_push_notification_chrome.go +++ /dev/null @@ -1,124 +0,0 @@ -package ibm - -import ( - "fmt" - - "github.com/IBM/push-notifications-go-sdk/pushservicev1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMPNApplicationChrome() *schema.Resource { - return &schema.Resource{ - Read: resourceApplicationChromeRead, - Create: resourceApplicationChromeCreate, - Update: resourceApplicationChromeUpdate, - Delete: resourceApplicationChromeDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "guid": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Unique guid of the push notification instance.", - }, - "server_key": { - Type: schema.TypeString, - Required: true, - Description: "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", - }, - "web_site_url": { - Type: schema.TypeString, - Required: true, - Description: "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", - }, - }, - } -} - -func resourceApplicationChromeCreate(d *schema.ResourceData, meta interface{}) error { - pnClient, err := meta.(ClientSession).PushServiceV1() - if err != nil { - return err - } - - serverKey := d.Get("server_key").(string) - websiteURL := d.Get("web_site_url").(string) - guid := d.Get("guid").(string) - - _, response, err := pnClient.SaveChromeWebConf(&pushservicev1.SaveChromeWebConfOptions{ - ApplicationID: &guid, - ApiKey: &serverKey, - WebSiteURL: &websiteURL, - }) - - if err != nil { - d.SetId("") - return fmt.Errorf("Error configuring chrome web platform: %s with response code %d", err, response.StatusCode) - } - d.SetId(guid) - - return resourceApplicationChromeRead(d, meta) -} - -func resourceApplicationChromeUpdate(d *schema.ResourceData, meta interface{}) error { - - if d.HasChanges("server_key", "web_site_url") { - return resourceApplicationChromeCreate(d, meta) - } - return nil -} - -func resourceApplicationChromeRead(d *schema.ResourceData, meta interface{}) error { - pnClient, err := meta.(ClientSession).PushServiceV1() - if err != nil { - return err - } - - guid := d.Id() - - chromeWebConf, response, err := pnClient.GetChromeWebConf(&pushservicev1.GetChromeWebConfOptions{ - ApplicationID: &guid, - }) - - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error fetching chrome web platform configuration: %s with response code %d", err, response.StatusCode) - } - - d.SetId(guid) - - if response.StatusCode == 200 { - d.Set("server_key", *chromeWebConf.ApiKey) - d.Set("web_site_url", *chromeWebConf.WebSiteURL) - } - return nil -} - -func resourceApplicationChromeDelete(d *schema.ResourceData, meta interface{}) error { - pnClient, err := meta.(ClientSession).PushServiceV1() - if err != nil { - return err - } - guid := d.Get("guid").(string) - - response, err := pnClient.DeleteChromeWebConf(&pushservicev1.DeleteChromeWebConfOptions{ - ApplicationID: &guid, - }) - - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error deleting chrome web platform configuration: %s with response code %d", err, response.StatusCode) - } - - d.SetId("") - - return nil - -} diff --git a/ibm/resource_ibm_resource_instance.go b/ibm/resource_ibm_resource_instance.go deleted file mode 100644 index 1a0ec627c..000000000 --- a/ibm/resource_ibm_resource_instance.go +++ /dev/null @@ -1,898 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "strconv" - "strings" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/models" -) - -const ( - rsInstanceSuccessStatus = "active" - rsInstanceProgressStatus = "in progress" - rsInstanceProvisioningStatus = "provisioning" - rsInstanceInactiveStatus = "inactive" - rsInstanceFailStatus = "failed" - rsInstanceRemovedStatus = "removed" - rsInstanceReclamation = "pending_reclamation" -) - -func resourceIBMResourceInstance() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMResourceInstanceCreate, - Read: resourceIBMResourceInstanceRead, - Update: resourceIBMResourceInstanceUpdate, - Delete: resourceIBMResourceInstanceDelete, - Exists: resourceIBMResourceInstanceExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "A name for the resource instance", - }, - - "service": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The name of the service offering like cloud-object-storage, kms etc", - }, - - "plan": { - Type: schema.TypeString, - Required: true, - Description: "The plan type of the service", - }, - - "location": { - Description: "The location where the instance available", - Required: true, - ForceNew: true, - Type: schema.TypeString, - }, - - "resource_group_id": { - Description: "The resource group id", - Optional: true, - ForceNew: true, - Type: schema.TypeString, - Computed: true, - }, - - "parameters": { - Type: schema.TypeMap, - Optional: true, - Description: "Arbitrary parameters to pass. Must be a JSON object", - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_resource_instance", "tag")}, - Set: resourceIBMVPCHash, - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of resource instance", - }, - - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "CRN of resource instance", - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "Guid of resource instance", - }, - - "service_endpoints": { - Description: "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "public-and-private"}), - }, - - "dashboard_url": { - Description: "Dashboard URL to access resource.", - Type: schema.TypeString, - Computed: true, - }, - - "plan_history": { - Description: "The plan history of the instance.", - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "resource_plan_id": { - Type: schema.TypeString, - Computed: true, - }, - "start_date": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "account_id": { - Description: "An alpha-numeric value identifying the account ID.", - Type: schema.TypeString, - Computed: true, - }, - - "resource_group_crn": { - Description: "The long ID (full CRN) of the resource group", - Type: schema.TypeString, - Computed: true, - }, - - "resource_id": { - Description: "The unique ID of the offering", - Type: schema.TypeString, - Computed: true, - }, - - "resource_plan_id": { - Description: "The unique ID of the plan associated with the offering", - Type: schema.TypeString, - Computed: true, - }, - - "target_crn": { - Description: "The full deployment CRN as defined in the global catalog", - Type: schema.TypeString, - Computed: true, - }, - - "state": { - Description: "The current state of the instance.", - Type: schema.TypeString, - Computed: true, - }, - - "type": { - Description: "The type of the instance, e.g. service_instance.", - Type: schema.TypeString, - Computed: true, - }, - - "sub_type": { - Description: "The sub-type of instance, e.g. cfaas .", - Type: schema.TypeString, - Computed: true, - }, - - "allow_cleanup": { - Description: "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", - Type: schema.TypeBool, - Computed: true, - }, - - "locked": { - Description: "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", - Type: schema.TypeBool, - Computed: true, - }, - - "last_operation": { - Type: schema.TypeMap, - Computed: true, - Description: "The status of the last operation requested on the instance", - }, - - "resource_aliases_url": { - Description: "The relative path to the resource aliases for the instance.", - Type: schema.TypeString, - Computed: true, - }, - - "resource_bindings_url": { - Description: "The relative path to the resource bindings for the instance.", - Type: schema.TypeString, - Computed: true, - }, - - "resource_keys_url": { - Description: "The relative path to the resource keys for the instance.", - Type: schema.TypeString, - Computed: true, - }, - - "created_at": { - Type: schema.TypeString, - Description: "The date when the instance was created.", - Computed: true, - }, - - "created_by": { - Type: schema.TypeString, - Description: "The subject who created the instance.", - Computed: true, - }, - - "update_at": { - Type: schema.TypeString, - Description: "The date when the instance was last updated.", - Computed: true, - }, - - "update_by": { - Type: schema.TypeString, - Description: "The subject who updated the instance.", - Computed: true, - }, - - "deleted_at": { - Type: schema.TypeString, - Description: "The date when the instance was deleted.", - Computed: true, - }, - - "deleted_by": { - Type: schema.TypeString, - Description: "The subject who deleted the instance.", - Computed: true, - }, - - "scheduled_reclaim_at": { - Type: schema.TypeString, - Description: "The date when the instance was scheduled for reclamation.", - Computed: true, - }, - - "scheduled_reclaim_by": { - Type: schema.TypeString, - Description: "The subject who initiated the instance reclamation.", - Computed: true, - }, - - "restored_at": { - Type: schema.TypeString, - Description: "The date when the instance under reclamation was restored.", - Computed: true, - }, - - "restored_by": { - Type: schema.TypeString, - Description: "The subject who restored the instance back from reclamation.", - Computed: true, - }, - - ResourceName: { - Type: schema.TypeString, - Computed: true, - Description: "The name of the resource", - }, - - ResourceCRN: { - Type: schema.TypeString, - Computed: true, - Description: "The crn of the resource", - }, - - ResourceStatus: { - Type: schema.TypeString, - Computed: true, - Description: "The status of the resource", - }, - - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "The resource group name in which resource is provisioned", - }, - ResourceControllerURL: { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", - }, - - "extensions": { - Type: schema.TypeMap, - Computed: true, - Description: "The extended metadata as a map associated with the resource instance.", - }, - }, - } -} - -func resourceIBMResourceInstanceValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmResourceInstanceResourceValidator := ResourceValidator{ResourceName: "ibm_resource_instance", Schema: validateSchema} - return &ibmResourceInstanceResourceValidator -} - -func resourceIBMResourceInstanceCreate(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - serviceName := d.Get("service").(string) - plan := d.Get("plan").(string) - name := d.Get("name").(string) - location := d.Get("location").(string) - - rsInst := rc.CreateResourceInstanceOptions{ - Name: &name, - } - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.FindByName(serviceName, true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - if metadata, ok := serviceOff[0].Metadata.(*models.ServiceResourceMetadata); ok { - if !metadata.Service.RCProvisionable { - return fmt.Errorf("%s cannot be provisioned by resource controller", serviceName) - } - } else { - return fmt.Errorf("Cannot create instance of resource %s\nUse 'ibm_service_instance' if the resource is a Cloud Foundry service", serviceName) - } - - servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - rsInst.ResourcePlanID = &servicePlan - - deployments, err := rsCatRepo.ListDeployments(servicePlan) - if err != nil { - return fmt.Errorf("Error retrieving deployment for plan %s : %s", plan, err) - } - if len(deployments) == 0 { - return fmt.Errorf("No deployment found for service plan : %s", plan) - } - deployments, supportedLocations := filterDeployments(deployments, location) - - if len(deployments) == 0 { - locationList := make([]string, 0, len(supportedLocations)) - for l := range supportedLocations { - locationList = append(locationList, l) - } - return fmt.Errorf("No deployment found for service plan %s at location %s.\nValid location(s) are: %q.\nUse 'ibm_service_instance' if the service is a Cloud Foundry service.", plan, location, locationList) - } - - rsInst.Target = &deployments[0].CatalogCRN - - if rsGrpID, ok := d.GetOk("resource_group_id"); ok { - rg := rsGrpID.(string) - rsInst.ResourceGroup = &rg - } else { - defaultRg, err := defaultResourceGroup(meta) - if err != nil { - return err - } - rsInst.ResourceGroup = &defaultRg - } - - params := map[string]interface{}{} - - if serviceEndpoints, ok := d.GetOk("service_endpoints"); ok { - params["service-endpoints"] = serviceEndpoints.(string) - } - - if parameters, ok := d.GetOk("parameters"); ok { - temp := parameters.(map[string]interface{}) - for k, v := range temp { - if v == "true" || v == "false" { - b, _ := strconv.ParseBool(v.(string)) - params[k] = b - } else if strings.HasPrefix(v.(string), "[") && strings.HasSuffix(v.(string), "]") { - //transform v.(string) to be []string - arrayString := v.(string) - trimLeft := strings.TrimLeft(arrayString, "[") - trimRight := strings.TrimRight(trimLeft, "]") - array := strings.Split(trimRight, ",") - result := []string{} - for _, a := range array { - result = append(result, strings.Trim(a, "\"")) - } - params[k] = result - } else { - params[k] = v - } - } - - } - - rsInst.Parameters = params - - //Start to create resource instance - instance, resp, err := rsConClient.CreateResourceInstance(&rsInst) - if err != nil { - log.Printf( - "Error when creating resource instance: %s, Instance info NAME->%s, LOCATION->%s, GROUP_ID->%s, PLAN_ID->%s", - err, *rsInst.Name, *rsInst.Target, *rsInst.ResourceGroup, *rsInst.ResourcePlanID) - return fmt.Errorf("Error when creating resource instance: %s with resp code: %s", err, resp) - } - - d.SetId(*instance.ID) - - _, err = waitForResourceInstanceCreate(d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for create resource instance (%s) to be succeeded: %s", d.Id(), err) - } - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk("tags"); ok || v != "" { - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) - } - } - - return resourceIBMResourceInstanceRead(d, meta) -} -func resourceIBMResourceInstanceRead(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - return fmt.Errorf("Error retrieving resource instance: %s with resp code: %s", err, resp) - } - - tags, err := GetTagsUsingCRN(meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on get of resource instance tags (%s) tags: %s", d.Id(), err) - } - d.Set("tags", tags) - d.Set("name", instance.Name) - d.Set("status", instance.State) - d.Set("resource_group_id", instance.ResourceGroupID) - if instance.CRN != nil { - location := strings.Split(*instance.CRN, ":") - if len(location) > 5 { - d.Set("location", location[5]) - } - } - d.Set("crn", instance.CRN) - d.Set("dashboard_url", instance.DashboardURL) - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.GetServiceName(*instance.ResourceID) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - d.Set("service", serviceOff) - - d.Set(ResourceName, instance.Name) - d.Set(ResourceCRN, instance.CRN) - d.Set(ResourceStatus, instance.State) - d.Set(ResourceGroupName, instance.ResourceGroupCRN) - - rcontroller, err := getBaseController(meta) - if err != nil { - return err - } - d.Set(ResourceControllerURL, rcontroller+"/services/") - - servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - d.Set("plan", servicePlan) - d.Set("guid", instance.GUID) - if instance.Parameters != nil { - if endpoint, ok := instance.Parameters["service-endpoints"]; ok { - d.Set("service_endpoints", endpoint) - } - } - - if len(instance.Extensions) == 0 { - d.Set("extensions", instance.Extensions) - } else { - d.Set("extensions", Flatten(instance.Extensions)) - } - d.Set("account_id", instance.AccountID) - d.Set("restored_by", instance.RestoredBy) - if instance.RestoredAt != nil { - d.Set("restored_at", instance.RestoredAt.String()) - } - d.Set("scheduled_reclaim_by", instance.ScheduledReclaimBy) - if instance.ScheduledReclaimAt != nil { - d.Set("scheduled_reclaim_at", instance.ScheduledReclaimAt.String()) - } - if instance.ScheduledReclaimAt != nil { - d.Set("deleted_at", instance.DeletedAt.String()) - } - d.Set("deleted_by", instance.DeletedBy) - if instance.UpdatedAt != nil { - d.Set("update_at", instance.UpdatedAt.String()) - } - if instance.CreatedAt != nil { - d.Set("created_at", instance.CreatedAt.String()) - } - d.Set("update_by", instance.UpdatedBy) - d.Set("created_by", instance.CreatedBy) - d.Set("resource_keys_url", instance.ResourceKeysURL) - d.Set("resource_bindings_url", instance.ResourceBindingsURL) - d.Set("resource_aliases_url", instance.ResourceAliasesURL) - if instance.LastOperation != nil { - d.Set("last_operation", Flatten(instance.LastOperation)) - } - d.Set("locked", instance.Locked) - d.Set("allow_cleanup", instance.AllowCleanup) - d.Set("type", instance.Type) - d.Set("state", instance.State) - d.Set("sub_type", instance.SubType) - d.Set("target_crn", instance.TargetCRN) - d.Set("resource_plan_id", instance.ResourcePlanID) - d.Set("resource_id", instance.ResourceID) - d.Set("resource_group_crn", instance.ResourceGroupCRN) - if instance.PlanHistory != nil { - d.Set("plan_history", flattenPlanHistory(instance.PlanHistory)) - } - - return nil -} - -func resourceIBMResourceInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - instanceID := d.Id() - - resourceInstanceUpdate := rc.UpdateResourceInstanceOptions{ - ID: &instanceID, - } - if d.HasChange("name") { - name := d.Get("name").(string) - resourceInstanceUpdate.Name = &name - } - - if d.HasChange("plan") { - plan := d.Get("plan").(string) - service := d.Get("service").(string) - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return err - } - rsCatRepo := rsCatClient.ResourceCatalog() - - serviceOff, err := rsCatRepo.FindByName(service, true) - if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) - } - - servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) - if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) - } - - resourceInstanceUpdate.ResourcePlanID = &servicePlan - - } - params := map[string]interface{}{} - - if d.HasChange("service_endpoints") { - endpoint := d.Get("service_endpoints").(string) - params["service-endpoints"] = endpoint - } - - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - if d.HasChange("parameters") { - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - return fmt.Errorf("Error retrieving resource instance: %s with resp code: %s", err, resp) - } - - if parameters, ok := d.GetOk("parameters"); ok { - temp := parameters.(map[string]interface{}) - for k, v := range temp { - if v == "true" || v == "false" { - b, _ := strconv.ParseBool(v.(string)) - params[k] = b - } else if strings.HasPrefix(v.(string), "[") && strings.HasSuffix(v.(string), "]") { - //transform v.(string) to be []string - arrayString := v.(string) - trimLeft := strings.TrimLeft(arrayString, "[") - trimRight := strings.TrimRight(trimLeft, "]") - array := strings.Split(trimRight, ",") - result := []string{} - for _, a := range array { - result = append(result, strings.Trim(a, "\"")) - } - params[k] = result - } else { - params[k] = v - } - } - } - serviceEndpoints := d.Get("service_endpoints").(string) - if serviceEndpoints != "" { - endpoint := d.Get("service_endpoints").(string) - params["service-endpoints"] = endpoint - } else if _, ok := instance.Parameters["service-endpoints"]; ok { - params["service-endpoints"] = instance.Parameters["service-endpoints"] - } - - } - if d.HasChange("service_endpoints") || d.HasChange("parameters") { - resourceInstanceUpdate.Parameters = params - } - - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - return fmt.Errorf("Error Getting resource instance: %s with resp code: %s", err, resp) - } - - if d.HasChange("tags") { - oldList, newList := d.GetChange(isVPCTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) - if err != nil { - log.Printf( - "Error on update of resource instance (%s) tags: %s", d.Id(), err) - } - } - - _, resp, err = rsConClient.UpdateResourceInstance(&resourceInstanceUpdate) - if err != nil { - return fmt.Errorf("Error updating resource instance: %s with resp code: %s", err, resp) - } - - _, err = waitForResourceInstanceUpdate(d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for update resource instance (%s) to be succeeded: %s", d.Id(), err) - } - - return resourceIBMResourceInstanceRead(d, meta) -} - -func resourceIBMResourceInstanceDelete(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - id := d.Id() - recursive := true - resourceInstanceDelete := rc.DeleteResourceInstanceOptions{ - ID: &id, - Recursive: &recursive, - } - - resp, error := rsConClient.DeleteResourceInstance(&resourceInstanceDelete) - if error != nil { - if resp != nil && resp.StatusCode == 410 { - return nil - } - return fmt.Errorf("Error deleting resource instance: %s with resp code: %s", error, resp) - } - - _, err = waitForResourceInstanceDelete(d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err) - } - - d.SetId("") - - return nil -} -func resourceIBMResourceInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("Error communicating with the API: %s with resp code: %s", err, resp) - } - if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, rsInstanceReclamation)) { - log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") - d.SetId("") - return false, nil - } - - return *instance.ID == instanceID, nil -} - -func waitForResourceInstanceCreate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus, rsInstanceProvisioningStatus}, - Target: []string{rsInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - return nil, "", fmt.Errorf("The resource instance %s does not exist anymore: %v", d.Id(), err) - } - return nil, "", fmt.Errorf("Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) - } - if *instance.State == rsInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed: %v", d.Id(), err) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func waitForResourceInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus}, - Target: []string{rsInstanceSuccessStatus}, - Refresh: func() (interface{}, string, error) { - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - return nil, "", fmt.Errorf("The resource instance %s does not exist anymore: %v", d.Id(), err) - } - return nil, "", fmt.Errorf("Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) - } - if *instance.State == rsInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed: %v", d.Id(), err) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutUpdate), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func waitForResourceInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - instanceID := d.Id() - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus, rsInstanceSuccessStatus}, - Target: []string{rsInstanceRemovedStatus, rsInstanceReclamation}, - Refresh: func() (interface{}, string, error) { - instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - return instance, rsInstanceSuccessStatus, nil - } - return nil, "", fmt.Errorf("Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) - } - if *instance.State == rsInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("The resource instance %s failed to delete: %v", d.Id(), err) - } - return instance, *instance.State, nil - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func filterDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { - supportedDeployments := []models.ServiceDeployment{} - supportedLocations := make(map[string]bool) - for _, d := range deployments { - if d.Metadata.RCCompatible { - deploymentLocation := d.Metadata.Deployment.Location - supportedLocations[deploymentLocation] = true - if deploymentLocation == location { - supportedDeployments = append(supportedDeployments, d) - } - } - } - return supportedDeployments, supportedLocations -} - -func flattenPlanHistory(keys []rc.PlanHistoryItem) []interface{} { - var out = make([]interface{}, len(keys), len(keys)) - for i, k := range keys { - m := make(map[string]interface{}) - m["resource_plan_id"] = k.ResourcePlanID - m["start_date"] = k.StartDate.String() - out[i] = m - } - return out -} diff --git a/ibm/resource_ibm_resource_instance_test.go b/ibm/resource_ibm_resource_instance_test.go deleted file mode 100644 index 28804eec1..000000000 --- a/ibm/resource_ibm_resource_instance_test.go +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "strings" - "testing" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccIBMResourceInstanceBasic(t *testing.T) { - serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) - updateName := fmt.Sprintf("tf-kms-%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMResourceInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMResourceInstanceBasic(serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMResourceInstanceExists("ibm_resource_instance.instance"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", serviceName), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), - ), - }, - { - Config: testAccCheckIBMResourceInstanceUpdateWithSameName(serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMResourceInstanceExists("ibm_resource_instance.instance"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", serviceName), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), - ), - }, - { - Config: testAccCheckIBMResourceInstanceUpdate(updateName), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", updateName), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), - ), - }, - { - Config: testAccCheckIBMResourceInstanceNewServiceType(updateName), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", updateName), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "kms"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "tiered-pricing"), - resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "us-south"), - ), - }, - }, - }) -} - -func TestAccIBMResourceInstanceImport(t *testing.T) { - serviceName := fmt.Sprintf("tf-ins-%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_resource_instance.instance" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMResourceInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMResourceInstanceBasic(serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMResourceInstanceExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "cloud-object-storage"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "global"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "parameters"}, - }, - }, - }) -} - -func TestAccIBMResourceInstanceWithServiceendpoints(t *testing.T) { - serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_resource_instance.instance" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMResourceInstanceDestroy, - Steps: []resource.TestStep{ - - { - Config: testAccCheckIBMResourceInstanceServiceendpoints(serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMResourceInstanceExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), - ), - }, - }, - }) -} - -func TestAccIBMResourceInstanceWithResourceGroup(t *testing.T) { - serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) - resourceName := "ibm_resource_instance.instance" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMResourceInstanceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMResourceInstanceWithResourceGroup(serviceName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMResourceInstanceExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "cloud-object-storage"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "global"), - ), - }, - }, - }) -} - -func testAccCheckIBMResourceInstanceDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_resource_instance" { - continue - } - - instanceID := rs.Primary.ID - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - // Try to find the key - instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) - - if err == nil { - if *instance.State == "active" { - return fmt.Errorf("Resource Instance still exists: %s", rs.Primary.ID) - } - } else { - if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if Resource Instance (%s) has been destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) - } - } - } - - return nil -} - -func testAccCheckIBMResourceInstanceExists(n string) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instanceID := rs.Primary.ID - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - _, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) - - if err != nil { - return fmt.Errorf("Get resource instance error: %s with resp code: %s", err, resp) - } - - return nil - } -} - -func testAccCheckIBMResourceInstanceBasic(serviceName string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - parameters = { - "HMAC" = true - } - - timeouts { - create = "15m" - update = "15m" - delete = "15m" - } - } - `, serviceName) -} - -func testAccCheckIBMResourceInstanceUpdateWithSameName(serviceName string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - parameters = { - "HMAC" = true - } - } - - `, serviceName) -} - -func testAccCheckIBMResourceInstanceUpdate(updateName string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - parameters = { - "HMAC" = true - } - } - `, updateName) -} - -func testAccCheckIBMResourceInstanceNewServiceType(updateName string) string { - return fmt.Sprintf(` - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "kms" - plan = "tiered-pricing" - location = "us-south" - } - `, updateName) -} - -func testAccCheckIBMResourceInstanceWithResourceGroup(serviceName string) string { - return fmt.Sprintf(` - - data "ibm_resource_group" "group" { - is_default=true - } - - resource "ibm_resource_instance" "instance" { - name = "%s" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = data.ibm_resource_group.group.id - parameters = { - "HMAC" = true - } - } - `, serviceName) -} - -func testAccCheckIBMResourceInstanceServiceendpoints(serviceName string) string { - return fmt.Sprintf(` - - resource "ibm_resource_instance" "instance" { - name = "%s" - location = "us-south" - service = "databases-for-postgresql" - plan = "standard" - parameters = { - members_memory_allocation_mb = "4096" - } - - //service_endpoints = "public-and-private" - timeouts { - create = "25m" - update = "15m" - delete = "15m" - } - } - - `, serviceName) -} diff --git a/ibm/resource_ibm_resource_key.go b/ibm/resource_ibm_resource_key.go deleted file mode 100644 index cd3147cab..000000000 --- a/ibm/resource_ibm_resource_key.go +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "encoding/json" - "fmt" - "log" - "strconv" - "strings" - "time" - - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" -) - -func resourceIBMResourceKey() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMResourceKeyCreate, - Read: resourceIBMResourceKeyRead, - Update: resourceIBMResourceKeyUpdate, - Delete: resourceIBMResourceKeyDelete, - Exists: resourceIBMResourceKeyExists, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The name of the resource key", - }, - - "role": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Name of the user role.Valid roles are Writer, Reader, Manager, Administrator, Operator, Viewer, Editor and Custom Roles.", - // ValidateFunc: validateRole, - }, - - "resource_instance_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The id of the resource instance for which to create resource key", - ConflictsWith: []string{"resource_alias_id"}, - }, - - "resource_alias_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The id of the resource alias for which to create resource key", - ConflictsWith: []string{"resource_instance_id"}, - }, - - "parameters": { - Type: schema.TypeMap, - Optional: true, - DiffSuppressFunc: applyOnce, - Description: "Arbitrary parameters to pass. Must be a JSON object", - }, - - "credentials": { - Description: "Credentials asociated with the key", - Type: schema.TypeMap, - Sensitive: true, - Computed: true, - }, - - "status": { - Type: schema.TypeString, - Computed: true, - Description: "Status of resource key", - }, - - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "crn of resource key", - }, - - "guid": { - Type: schema.TypeString, - Computed: true, - Description: "When you create a new key, a globally unique identifier (GUID) is assigned.", - }, - - "url": { - Type: schema.TypeString, - Computed: true, - Description: "When you created a new key, a relative URL path is created identifying the location of the key.", - }, - - "account_id": { - Type: schema.TypeString, - Computed: true, - Description: "An alpha-numeric value identifying the account ID.", - }, - - "resource_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "The short ID of the resource group.", - }, - - "source_crn": { - Type: schema.TypeString, - Computed: true, - Description: "The CRN of resource instance or alias associated to the key.", - }, - - "state": { - Type: schema.TypeString, - Computed: true, - Description: "The state of the key.", - }, - - "iam_compatible": { - Type: schema.TypeBool, - Computed: true, - Description: "Specifies whether the key’s credentials support IAM.", - }, - - "resource_instance_url": { - Type: schema.TypeString, - Computed: true, - Description: "The relative path to the resource.", - }, - - "created_at": { - Type: schema.TypeString, - Computed: true, - Description: "The date when the key was created.", - }, - - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "The date when the key was last updated.", - }, - - "deleted_at": { - Type: schema.TypeString, - Computed: true, - Description: "The date when the key was deleted.", - }, - - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The subject who created the key.", - }, - - "updated_by": { - Type: schema.TypeString, - Computed: true, - Description: "The subject who updated the key.", - }, - - "deleted_by": { - Type: schema.TypeString, - Computed: true, - Description: "The subject who deleted the key.", - }, - }, - } -} - -func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) error { - rsContClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - name := d.Get("name").(string) - role := d.Get("role").(string) - - var instanceID, aliasID string - if insID, ok := d.GetOk("resource_instance_id"); ok { - instanceID = insID.(string) - } - - if aliID, ok := d.GetOk("resource_alias_id"); ok { - aliasID = aliID.(string) - } - - if instanceID == "" && aliasID == "" { - return fmt.Errorf("Provide either `resource_instance_id` or `resource_alias_id`") - } - - keyParameters := rc.ResourceKeyPostParameters{} - - if parameters, ok := d.GetOk("parameters"); ok { - temp := parameters.(map[string]interface{}) - for k, v := range temp { - if v == "true" || v == "false" { - b, _ := strconv.ParseBool(v.(string)) - keyParameters.SetProperty(k, b) - } else { - keyParameters.SetProperty(k, v) - } - } - } - - resourceInstance, sourceCRN, err := getResourceInstanceAndCRN(d, meta) - if err != nil { - return fmt.Errorf("Error creating resource key when get instance and CRN: %s", err) - } - - serviceID := resourceInstance.ResourceID - - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() - if err != nil { - return fmt.Errorf("Error creating resource key when get ResourceCatalogAPI: %s", err) - } - - service, err := rsCatClient.ResourceCatalog().Get(*serviceID, true) - if err != nil { - return fmt.Errorf("Error creating resource key when get service: %s", err) - } - serviceRole, err := getRoleFromName(role, service.Name, meta) - if err != nil { - return fmt.Errorf("Error creating resource key when get role: %s", err) - } - - keyParameters.SetProperty("role_crn", serviceRole.RoleID) - - resourceKeyCreate := rc.CreateResourceKeyOptions{ - Name: &name, - Source: sourceCRN, - Role: serviceRole.RoleID, - Parameters: &keyParameters, - } - resourceKey, resp, err := rsContClient.CreateResourceKey(&resourceKeyCreate) - if err != nil { - return fmt.Errorf("Error creating resource key: %s with resp code: %s", err, resp) - } - - d.SetId(*resourceKey.ID) - - return resourceIBMResourceKeyRead(d, meta) -} - -func resourceIBMResourceKeyUpdate(d *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error { - rsContClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceKeyID := d.Id() - resourceKeyGet := rc.GetResourceKeyOptions{ - ID: &resourceKeyID, - } - - resourceKey, resp, err := rsContClient.GetResourceKey(&resourceKeyGet) - if err != nil || resourceKey == nil { - return fmt.Errorf("Error retrieving resource key: %s with resp : %s", err, resp) - } - var credInterface map[string]interface{} - cred, _ := json.Marshal(resourceKey.Credentials) - json.Unmarshal(cred, &credInterface) - d.Set("credentials", Flatten(credInterface)) - d.Set("name", *resourceKey.Name) - d.Set("status", *resourceKey.State) - if resourceKey.Credentials != nil && resourceKey.Credentials.IamRoleCRN != nil { - roleCrn := *resourceKey.Credentials.IamRoleCRN - roleName := roleCrn[strings.LastIndex(roleCrn, ":")+1:] - - // TODO.S: update client - if strings.Contains(roleCrn, ":customRole:") { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err == nil { - var resourceCRN string - if resourceKey.CRN != nil { - serviceName := strings.Split(*resourceKey.CRN, ":") - if len(serviceName) > 4 { - resourceCRN = serviceName[4] - } - } - listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ - AccountID: resourceKey.AccountID, - ServiceName: &resourceCRN, - } - roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) - roles := roleList.CustomRoles - if err == nil && len(roles) > 0 { - for _, role := range roles { - if *role.Name == roleName { - customRoleName := role.DisplayName - d.Set("role", customRoleName) - } - } - } - } - } else { - d.Set("role", roleName) - } - } - - sCrn := *resourceKey.SourceCRN - if sCrn != "" { - d.Set("resource_instance_id", sCrn) - } - - d.Set("crn", *resourceKey.CRN) - - d.Set("guid", *resourceKey.GUID) - d.Set("url", *resourceKey.URL) - d.Set("account_id", *resourceKey.AccountID) - d.Set("resource_group_id", *resourceKey.ResourceGroupID) - d.Set("source_crn", *resourceKey.SourceCRN) - d.Set("state", *resourceKey.State) - d.Set("iam_compatible", *resourceKey.IamCompatible) - d.Set("resource_instance_url", *resourceKey.ResourceInstanceURL) - if resourceKey.CreatedAt != nil { - d.Set("created_at", resourceKey.CreatedAt.String()) - } else { - d.Set("created_at", "") - } - if resourceKey.UpdatedAt != nil { - d.Set("updated_at", resourceKey.UpdatedAt.String()) - } else { - d.Set("updated_at", "") - } - if resourceKey.DeletedAt != nil { - d.Set("deleted_at", resourceKey.DeletedAt.String()) - } else { - d.Set("deleted_at", "") - } - d.Set("created_by", *resourceKey.CreatedBy) - d.Set("updated_by", *resourceKey.UpdatedBy) - d.Set("deleted_by", *resourceKey.DeletedBy) - - return nil -} - -func resourceIBMResourceKeyDelete(d *schema.ResourceData, meta interface{}) error { - rsContClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - - resourceKeyID := d.Id() - resourceKeyDelete := rc.DeleteResourceKeyOptions{ - ID: &resourceKeyID, - } - - resp, err := rsContClient.DeleteResourceKey(&resourceKeyDelete) - if err != nil { - return fmt.Errorf("Error deleting resource key: %s with resp code: %s", err, resp) - } - - d.SetId("") - - return nil -} - -func resourceIBMResourceKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - rsContClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return false, err - } - resourceKeyID := d.Id() - resourceKeyGet := rc.GetResourceKeyOptions{ - ID: &resourceKeyID, - } - - resourceKey, resp, err := rsContClient.GetResourceKey(&resourceKeyGet) - if err != nil { - if resp != nil && (resp.StatusCode == 404 || resp.StatusCode == 410) { - return false, nil - } - return false, fmt.Errorf("Error communicating with the API: %s with resp code: %s", err, resp) - } - if err == nil && *resourceKey.State == "removed" { - return false, nil - } - - return *resourceKey.ID == resourceKeyID, nil -} - -func getResourceInstanceAndCRN(d *schema.ResourceData, meta interface{}) (*rc.ResourceInstance, *string, error) { - rsContClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return nil, nil, err - } - if insID, ok := d.GetOk("resource_instance_id"); ok { - insIdString := insID.(string) - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &insIdString, - } - instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - log.Printf("Error when get resource instance in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) - return nil, nil, err - } - return instance, instance.CRN, nil - } - - aliasID := d.Get("resource_alias_id").(string) - resourceAliasGet := rc.GetResourceAliasOptions{ - ID: &aliasID, - } - alias, resp, err := rsContClient.GetResourceAlias(&resourceAliasGet) - if err != nil { - log.Printf("Error when get resource alias in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) - return nil, nil, err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: alias.ResourceInstanceID, - } - instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) - if err != nil { - log.Printf("Error when get resource instance in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) - return nil, nil, err - } - return instance, instance.CRN, nil - -} - -func getRoleFromName(roleName, serviceName string, meta interface{}) (iampolicymanagementv1.PolicyRole, error) { - - role := iampolicymanagementv1.PolicyRole{} - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - if err != nil { - return role, err - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return role, err - } - - listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ - AccountID: &userDetails.userAccount, - ServiceName: &serviceName, - } - - roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) - if err != nil { - return role, err - } - - roles := mapRoleListToPolicyRoles(*roleList) - - role, err = findRoleByName(roles, roleName) - if err != nil { - return iampolicymanagementv1.PolicyRole{}, err - } - return role, nil - -} - -func findRoleByName(supported []iampolicymanagementv1.PolicyRole, name string) (iampolicymanagementv1.PolicyRole, error) { - for _, role := range supported { - if role.DisplayName != nil { - if *role.DisplayName == name { - role.DisplayName = nil - return role, nil - } - } - } - supportedRoles := getSupportedRolesStr(supported) - return iampolicymanagementv1.PolicyRole{}, bmxerror.New("RoleDoesnotExist", - fmt.Sprintf("%s was not found. Valid roles are %s", name, supportedRoles)) - -} - -func getSupportedRolesStr(supported []iampolicymanagementv1.PolicyRole) string { - rolesStr := "" - for index, role := range supported { - if index != 0 { - rolesStr += ", " - } - if role.DisplayName != nil { - rolesStr += *role.DisplayName - } - } - return rolesStr -} diff --git a/ibm/resource_ibm_resource_tag.go b/ibm/resource_ibm_resource_tag.go deleted file mode 100644 index c9bfd906e..000000000 --- a/ibm/resource_ibm_resource_tag.go +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "os" - "regexp" - "strings" - - "github.com/IBM/platform-services-go-sdk/globaltaggingv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" -) - -const ( - resourceID = "resource_id" - tags = "tags" - resourceType = "resource_type" - tagType = "tag_type" - acccountID = "acccount_id" - service = "service" - crnRegex = "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$&'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" -) - -func resourceIBMResourceTag() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMResourceTagCreate, - Read: resourceIBMResourceTagRead, - Update: resourceIBMResourceTagUpdate, - Delete: resourceIBMResourceTagDelete, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - ), - - Schema: map[string]*schema.Schema{ - resourceID: { - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_resource_tag", resourceID), - Description: "CRN of the resource on which the tags should be attached", - }, - tags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_resource_tag", tags)}, - Set: resourceIBMVPCHash, - Description: "List of tags associated with resource instance", - }, - resourceType: { - Type: schema.TypeString, - Optional: true, - Description: "Resource type on which the tags should be attached", - }, - tagType: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"service", "access", "user"}), - Description: "Type of the tag. Only allowed values are: user, or service or access (default value : user)", - }, - acccountID: { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the account that owns the resources to be tagged (required if tag-type is set to service)", - }, - }, - } -} - -func resourceIBMResourceTagValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: resourceID, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Required: true, - Regexp: `^crn:v1(:[a-zA-Z0-9 \-\._~\*\+,;=!$&'\(\)\/\?#\[\]@]*){8}$|^[0-9]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: tags, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmResourceTagValidator := ResourceValidator{ResourceName: "ibm_resource_tag", Schema: validateSchema} - return &ibmResourceTagValidator -} - -func resourceIBMResourceTagCreate(d *schema.ResourceData, meta interface{}) error { - var rType, tType string - resources := []globaltaggingv1.Resource{} - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - accountID := userDetails.userAccount - - gtClient, err := meta.(ClientSession).GlobalTaggingAPIv1() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - - resourceID := d.Get(resourceID).(string) - if v, ok := d.GetOk(resourceType); ok && v != nil { - rType = v.(string) - } - - r := globaltaggingv1.Resource{ResourceID: ptrToString(resourceID), ResourceType: ptrToString(rType)} - resources = append(resources, r) - - var add []string - if v, ok := d.GetOk(tags); ok { - tags := v.(*schema.Set) - for _, t := range tags.List() { - add = append(add, fmt.Sprint(t)) - } - } - - schematicTags := os.Getenv("IC_ENV_TAGS") - var envTags []string - if schematicTags != "" { - envTags = strings.Split(schematicTags, ",") - add = append(add, envTags...) - } - - AttachTagOptions := &globaltaggingv1.AttachTagOptions{} - AttachTagOptions.Resources = resources - AttachTagOptions.TagNames = add - if v, ok := d.GetOk(tagType); ok && v != nil { - tType = v.(string) - AttachTagOptions.TagType = ptrToString(tType) - - if tType == service { - AttachTagOptions.AccountID = ptrToString(accountID) - } - } - - if len(add) > 0 { - _, resp, err := gtClient.AttachTag(AttachTagOptions) - if err != nil { - return fmt.Errorf("Error attaching resource tags : %v\n%s", resp, err) - } - } - - crn, err := regexp.Compile(crnRegex) - if err != nil { - return err - } - - if crn.MatchString(resourceID) { - d.SetId(resourceID) - } else { - d.SetId(fmt.Sprintf("%s/%s", resourceID, resourceType)) - } - - return resourceIBMResourceTagRead(d, meta) -} - -func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error { - var rID, rType, tType string - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - acctID := userDetails.userAccount - - crn, err := regexp.Compile(crnRegex) - if err != nil { - return err - } - - if crn.MatchString(d.Id()) { - rID = d.Id() - } else { - parts, err := vmIdParts(d.Id()) - if err != nil { - return err - } - if len(parts) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of resourceID/resourceType", d.Id()) - } - rID = parts[0] - rType = parts[1] - } - - if v, ok := d.GetOk(tagType); ok && v != nil { - tType = v.(string) - - if tType == service { - d.Set(acccountID, acctID) - } - } - - tagList, err := GetGlobalTagsUsingCRN(meta, rID, resourceType, tType) - if err != nil { - if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("Error getting resource tags for: %s with error : %s\n", rID, err) - } - - d.Set(resourceID, rID) - d.Set(resourceType, rType) - d.Set(tags, tagList) - - return nil -} - -func resourceIBMResourceTagUpdate(d *schema.ResourceData, meta interface{}) error { - var rID, rType, tType string - - crn, err := regexp.Compile(crnRegex) - if err != nil { - return err - } - - if crn.MatchString(d.Id()) { - rID = d.Id() - } else { - parts, err := vmIdParts(d.Id()) - if err != nil { - return err - } - rID = parts[0] - rType = parts[1] - } - - if v, ok := d.GetOk(tagType); ok && v != nil { - tType = v.(string) - } - - if _, ok := d.GetOk(tags); ok { - oldList, newList := d.GetChange(tags) - err := UpdateGlobalTagsUsingCRN(oldList, newList, meta, rID, rType, tType) - if err != nil { - return fmt.Errorf( - "Error on create of resource tags: %s", err) - } - } - - return resourceIBMResourceTagRead(d, meta) -} - -func resourceIBMResourceTagDelete(d *schema.ResourceData, meta interface{}) error { - var rID, rType string - - crn, err := regexp.Compile(crnRegex) - if err != nil { - return err - } - - if crn.MatchString(d.Id()) { - rID = d.Id() - } else { - parts, err := vmIdParts(d.Id()) - if err != nil { - return err - } - rID = parts[0] - rType = parts[1] - } - - gtClient, err := meta.(ClientSession).GlobalTaggingAPIv1() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - - var remove []string - removeTags := d.Get(tags).(*schema.Set) - remove = make([]string, len(removeTags.List())) - for i, v := range removeTags.List() { - remove[i] = fmt.Sprint(v) - } - - if len(remove) > 0 { - resources := []globaltaggingv1.Resource{} - r := globaltaggingv1.Resource{ResourceID: ptrToString(rID), ResourceType: ptrToString(rType)} - resources = append(resources, r) - - detachTagOptions := &globaltaggingv1.DetachTagOptions{ - Resources: resources, - TagNames: remove, - } - - _, resp, err := gtClient.DetachTag(detachTagOptions) - if err != nil { - return fmt.Errorf("Error detaching resource tags %v: %s\n%s", remove, err, resp) - } - for _, v := range remove { - delTagOptions := &globaltaggingv1.DeleteTagOptions{ - TagName: ptrToString(v), - } - _, resp, err := gtClient.DeleteTag(delTagOptions) - if err != nil { - return fmt.Errorf("Error deleting resource tag %v: %s\n%s", v, err, resp) - } - } - } - return nil -} diff --git a/ibm/resource_ibm_satellite_cluster_worker_pool.go b/ibm/resource_ibm_satellite_cluster_worker_pool.go deleted file mode 100644 index c03575df0..000000000 --- a/ibm/resource_ibm_satellite_cluster_worker_pool.go +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "strings" - "time" - - v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" - v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const workerPoolDesired = "deployed" - -func resourceIBMSatelliteClusterWorkerPool() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMSatelliteClusterWorkerPoolCreate, - Read: resourceIBMSatelliteClusterWorkerPoolRead, - Update: resourceIBMSatelliteClusterWorkerPoolUpdate, - Delete: resourceIBMSatelliteClusterWorkerPoolDelete, - Importer: &schema.ResourceImporter{}, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(120 * time.Minute), - Delete: schema.DefaultTimeout(90 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name for the worker pool", - }, - "cluster": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The unique name for the new IBM Cloud Satellite cluster", - }, - "flavor": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The flavor defines the amount of virtual CPU, memory, and disk space that is set up in each worker node", - }, - "disk_encryption": { - Type: schema.TypeBool, - Optional: true, - Description: "Disk encryption for worker node", - }, - "isolation": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "entitlement": { - Type: schema.TypeString, - Optional: true, - }, - "worker_count": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - Description: "Specify the desired number of workers per zone in this worker pool", - }, - "zones": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Description: "Zone info for worker pool", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Required: true, - Description: "Zone for the worker pool in a multizone cluster", - }, - }, - }, - }, - "worker_pool_labels": { - Type: schema.TypeMap, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Labels on all the workers in the worker pool", - }, - "host_labels": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, - Description: "Labels that describe a Satellite host", - }, - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "ID of the resource group.", - }, - }, - } -} - -func resourceIBMSatelliteClusterWorkerPoolCreate(d *schema.ResourceData, meta interface{}) error { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - targetEnv, err := getClusterTargetHeader(d, meta) - if err != nil { - return err - } - - createWorkerPoolOptions := &kubernetesserviceapiv1.CreateSatelliteWorkerPoolOptions{} - name := d.Get("name").(string) - createWorkerPoolOptions.Name = &name - - cluster := d.Get("cluster").(string) - createWorkerPoolOptions.Cluster = &cluster - - if v, ok := d.GetOk("resource_group_id"); ok { - pathParamsMap := map[string]string{ - "X-Auth-Resource-Group": v.(string), - } - createWorkerPoolOptions.Headers = pathParamsMap - } - - if v, ok := d.GetOk("worker_count"); ok { - workerCount := int64(v.(int)) - createWorkerPoolOptions.WorkerCount = &workerCount - } - - if v, ok := d.GetOk("zones"); ok { - z := v.(*schema.Set) - createWorkerPoolOptions.Zones = flattenSatelliteWorkerPoolZones(z) - } - - hostLabels := make(map[string]string) - if v, ok := d.GetOk("host_labels"); ok { - hl := v.(*schema.Set) - hostLabels = flattenHostLabels(hl.List()) - createWorkerPoolOptions.HostLabels = hostLabels - } else { - createWorkerPoolOptions.HostLabels = hostLabels - } - - labels := make(map[string]string) - if l, ok := d.GetOk("worker_pool_labels"); ok { - for k, v := range l.(map[string]interface{}) { - labels[k] = v.(string) - } - createWorkerPoolOptions.Labels = labels - } else { - createWorkerPoolOptions.Labels = labels - } - - if v, ok := d.GetOk("flavor"); ok { - flavor := v.(string) - createWorkerPoolOptions.Flavor = &flavor - } - - if v, ok := d.GetOk("disk_encryption"); ok { - diskEncryption := v.(bool) - createWorkerPoolOptions.DiskEncryption = &diskEncryption - } - - if v, ok := d.GetOk("isolation"); ok { - isolation := v.(string) - createWorkerPoolOptions.Isolation = &isolation - } - - instance, response, err := satClient.CreateSatelliteWorkerPool(createWorkerPoolOptions) - if err != nil { - return fmt.Errorf("Error Creating Satellite cluster worker pool: %s\n%s", err, response) - } - - d.SetId(fmt.Sprintf("%s/%s", cluster, *instance.WorkerPoolID)) - log.Printf("[INFO] Created satellite cluster worker pool: %s", *instance.WorkerPoolID) - - _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, cluster, *instance.WorkerPoolID, d.Timeout(schema.TimeoutCreate), targetEnv) - if err != nil { - return fmt.Errorf( - "Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) - } - - return resourceIBMSatelliteClusterWorkerPoolRead(d, meta) -} - -func resourceIBMSatelliteClusterWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - clusterID := parts[0] - workerPoolID := parts[1] - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{ - Cluster: &clusterID, - Workerpool: &workerPoolID, - } - - workerPool, response, err := satClient.GetWorkerPool(getWorkerPoolOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return err - } - - d.Set("name", workerPool.PoolName) - d.Set("cluster", clusterID) - d.Set("flavor", workerPool.Flavor) - d.Set("isolation", workerPool.Isolation) - d.Set("worker_count", workerPool.WorkerCount) - d.Set("worker_pool_labels", IgnoreSystemLabels(workerPool.Labels)) - d.Set("host_labels", flattenWorkerPoolHostLabels(workerPool.HostLabels)) - - var zones = make([]map[string]interface{}, 0) - for _, zone := range workerPool.Zones { - zoneInfo := map[string]interface{}{ - "id": *zone.ID, - } - zones = append(zones, zoneInfo) - } - - d.Set("zones", zones) - return nil -} - -func resourceIBMSatelliteClusterWorkerPoolUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - clusterNameOrID := parts[0] - workerPoolName := parts[1] - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - targetEnv, err := getClusterTargetHeader(d, meta) - if err != nil { - return err - } - - if d.HasChange("worker_pool_labels") { - labels := make(map[string]string) - if l, ok := d.GetOk("worker_pool_labels"); ok { - for k, v := range l.(map[string]interface{}) { - labels[k] = v.(string) - } - } - - wpots := &kubernetesserviceapiv1.V2SetWorkerPoolLabelsOptions{ - Cluster: &clusterNameOrID, - Workerpool: &workerPoolName, - Labels: labels, - } - response, err := satClient.V2SetWorkerPoolLabels(wpots) - if err != nil { - return fmt.Errorf( - "Error updating the labels: %s\n%s", err, response) - } - } - - if d.HasChange("worker_count") { - clusterNameOrID := d.Get("cluster").(string) - workerPoolName := d.Get("name").(string) - count := d.Get("worker_count").(int) - targetEnv, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return err - } - ClusterClient, err := meta.(ClientSession).ContainerAPI() - if err != nil { - return err - } - Env := v1.ClusterTargetHeader{ResourceGroup: targetEnv.ResourceGroup} - - err = ClusterClient.WorkerPools().ResizeWorkerPool(clusterNameOrID, workerPoolName, count, Env) - if err != nil { - return fmt.Errorf( - "Error updating the worker_count %d: %s", count, err) - } - } - - if d.HasChange("zones") { - clusterID := d.Get("cluster").(string) - workerPoolName := d.Get("name").(string) - - oldList, newList := d.GetChange("zones") - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - os := oldList.(*schema.Set) - ns := newList.(*schema.Set) - remove := os.Difference(ns).List() - add := ns.Difference(os).List() - if len(add) > 0 { - for _, zone := range add { - newZone := zone.(map[string]interface{}) - zID := newZone["id"].(string) - zoneOptions := &kubernetesserviceapiv1.CreateSatelliteWorkerPoolZoneOptions{ - Cluster: &clusterID, - Workerpool: &workerPoolName, - ID: &zID, - } - response, err := satClient.CreateSatelliteWorkerPoolZone(zoneOptions) - if err != nil { - return fmt.Errorf("Error Adding Worker Pool Zone : %s\n%s", err, response) - } - } - _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, clusterID, workerPoolName, d.Timeout(schema.TimeoutCreate), targetEnv) - if err != nil { - return fmt.Errorf( - "Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) - } - } - if len(remove) > 0 { - for _, zone := range remove { - oldZone := zone.(map[string]interface{}) - zID := oldZone["id"].(string) - zoneOptions := &kubernetesserviceapiv1.RemoveWorkerPoolZoneOptions{ - IdOrName: &clusterID, - PoolidOrName: &workerPoolName, - Zoneid: &zID, - } - response, err := satClient.RemoveWorkerPoolZone(zoneOptions) - if err != nil { - return fmt.Errorf("Error deleting Worker Pool Zone : %s\n%s", err, response) - } - } - } - } - return resourceIBMSatelliteClusterWorkerPoolRead(d, meta) -} - -func resourceIBMSatelliteClusterWorkerPoolDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - clusterID := parts[0] - workerPoolID := parts[1] - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - targetEnv, err := getVpcClusterTargetHeader(d, meta) - if err != nil { - return err - } - - wpOptions := &kubernetesserviceapiv1.RemoveWorkerPoolOptions{ - IdOrName: &clusterID, - PoolidOrName: &workerPoolID, - } - - response, err := satClient.RemoveWorkerPool(wpOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error Deleting Satellite Cluster WorkerPool: %s\n%s", err, response) - } - - _, err = WaitForSatelliteWorkerDelete(clusterID, workerPoolID, meta, d.Timeout(schema.TimeoutDelete), targetEnv) - if err != nil { - return fmt.Errorf( - "Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolID, clusterID, err) - } - - d.SetId("") - return nil -} - -// WaitForSatelliteWorkerPoolAvailable Waits for workerpool deployed -func WaitForSatelliteWorkerPoolAvailable(d *schema.ResourceData, meta interface{}, clusterNameOrID, workerPoolNameOrID string, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - clusterID := clusterNameOrID - workerPoolID := workerPoolNameOrID - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return nil, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{"provision_pending"}, - Target: []string{workerPoolDesired}, - Refresh: func() (interface{}, string, error) { - getWorkersOptions := &kubernetesserviceapiv1.GetWorkers1Options{ - Cluster: &clusterID, - XAuthResourceGroup: &target.ResourceGroup, - } - - workers, response, err := satClient.GetWorkers1(getWorkersOptions) - if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s\n%s", err, response) - } - - //Check active transactions - //Check for workerpool state to be deployed - //Done workerpool has two fields desiredState and actualState , so check for those 2 - for _, e := range workers { - if *e.PoolName == workerPoolID || *e.PoolID == workerPoolID { - if strings.Compare(*e.Lifecycle.ActualState, workerPoolDesired) != 0 { - log.Printf("worker: %s state: %s", *e.ID, *e.Lifecycle.ActualState) - return workers, "provision_pending", nil - } - } - } - return workers, workerPoolDesired, nil - }, - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - return stateConf.WaitForState() -} - -func WaitForSatelliteWorkerDelete(clusterNameOrID, workerPoolNameOrID string, meta interface{}, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return nil, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{"deleting"}, - Target: []string{workerDeleteState}, - Refresh: satelliteWorkerPoolDeleteStateRefreshFunc(satClient, clusterNameOrID, workerPoolNameOrID, target), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} - -func satelliteWorkerPoolDeleteStateRefreshFunc(satClient *kubernetesserviceapiv1.KubernetesServiceApiV1, clusterID, workerPoolNameOrID string, target v2.ClusterTargetHeader) resource.StateRefreshFunc { - - return func() (interface{}, string, error) { - - getWorkersOptions := &kubernetesserviceapiv1.GetWorkers1Options{ - Cluster: &clusterID, - XAuthResourceGroup: &target.ResourceGroup, - } - - workerFields, response, err := satClient.GetWorkers1(getWorkersOptions) - if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s\n%s", err, response) - } - //Done worker has two fields desiredState and actualState , so check for those 2 - for _, e := range workerFields { - if *e.PoolName == workerPoolNameOrID || *e.PoolID == workerPoolNameOrID { - if strings.Compare(*e.Lifecycle.ActualState, "deleted") != 0 { - log.Printf("Deleting worker %s", *e.ID) - return workerFields, "deleting", nil - } - } - } - return workerFields, workerDeleteState, nil - } -} diff --git a/ibm/resource_ibm_satellite_host.go b/ibm/resource_ibm_satellite_host.go deleted file mode 100644 index c6d452d7c..000000000 --- a/ibm/resource_ibm_satellite_host.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "log" - "time" - - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" -) - -const ( - hostCluster = "cluster" - hostLocation = "location" - hostID = "host_id" - hostState = "host_state" - hostLabels = "labels" - hostZone = "zone" - hostWorkerPool = "worker_pool" - hostProvider = "host_provider" - - rsHostNormalStatus = "normal" - rsHostProvisioningStatus = "provisioning" - rsHostReadyStatus = "ready" - rsHostUnknownStatus = "unknown" -) - -func resourceIBMSatelliteHost() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMSatelliteHostCreate, - Read: resourceIBMSatelliteHostRead, - Update: resourceIBMSatelliteHostUpdate, - Delete: resourceIBMSatelliteHostDelete, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(75 * time.Minute), - Read: schema.DefaultTimeout(75 * time.Minute), - Delete: schema.DefaultTimeout(45 * time.Minute), - Update: schema.DefaultTimeout(45 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - hostLocation: { - Type: schema.TypeString, - Required: true, - Description: "The name or ID of the Satellite location", - }, - hostCluster: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The name or ID of a Satellite location or cluster to assign the host to", - }, - hostID: { - Type: schema.TypeString, - Required: true, - Description: "The specific host ID to assign to a Satellite location or cluster", - }, - hostLabels: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "List of labels for the host", - }, - hostZone: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The zone within the cluster to assign the host to", - }, - hostWorkerPool: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The name or ID of the worker pool within the cluster to assign the host to", - }, - hostProvider: { - Type: schema.TypeString, - Optional: true, - Description: "Host Provider", - }, - hostState: { - Type: schema.TypeString, - Computed: true, - Description: "Health status of the host", - }, - }, - } -} - -func resourceIBMSatelliteHostCreate(d *schema.ResourceData, meta interface{}) error { - hostName := d.Get(hostID).(string) - location := d.Get(hostLocation).(string) - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - hostAssignOptions := &kubernetesserviceapiv1.CreateSatelliteAssignmentOptions{} - hostAssignOptions.Controller = ptrToString(location) - - if _, ok := d.GetOk(hostCluster); ok { - hostAssignOptions.Cluster = ptrToString(d.Get(hostCluster).(string)) - } else { - hostAssignOptions.Cluster = ptrToString(location) - } - hostAssignOptions.HostID = ptrToString(hostName) - - //Check host attached to location - hostStatus, err := waitForHostAttachment(hostName, location, d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for attaching host (%s) to be succeeded: %s", hostName, err) - } - - labels := make(map[string]string) - if _, ok := d.GetOk(hostLabels); ok { - l := d.Get(hostLabels).(*schema.Set) - labels = flattenHostLabels(l.List()) - hostAssignOptions.Labels = labels - } else { - hostAssignOptions.Labels = labels - } - - if _, ok := d.GetOk(hostWorkerPool); ok { - hostAssignOptions.Workerpool = ptrToString(d.Get(hostWorkerPool).(string)) - } - - if _, ok := d.GetOk(hostZone); ok { - hostAssignOptions.Zone = ptrToString(d.Get(hostZone).(string)) - } - - if hostStatus == rsHostReadyStatus { - _, response, err := satClient.CreateSatelliteAssignment(hostAssignOptions) - if err != nil { - return fmt.Errorf("Error Assigning Satellite Host: %s\n%s", err, response) - } - } - - d.SetId(fmt.Sprintf("%s/%s", location, hostName)) - - //Wait for host to reach normal state - _, err = waitForHostAttachment(hostName, location, d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for host (%s) to get normal state: %s", hostName, err) - } - - return resourceIBMSatelliteHostRead(d, meta) -} - -func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - if len(parts) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of location/hostName", d.Id()) - } - location := parts[0] - hostName := parts[1] - - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - hostOptions := &kubernetesserviceapiv1.GetSatelliteHostsOptions{ - Controller: &location, - } - hostList, resp, err := satClient.GetSatelliteHosts(hostOptions) - if err != nil { - if resp != nil && resp.StatusCode == 404 { - d.SetId("") - return nil - } - log.Println("resourceIBMSatelliteHostRead : error in getting hostlist :", err, resp) - return err - } - - for _, h := range hostList { - if hostName == *h.Name || hostName == *h.ID { - d.Set(hostLocation, location) - d.Set("host_id", hostName) - - if _, ok := d.GetOk(hostLabels); ok { - l := d.Get(hostLabels).(*schema.Set) - d.Set(hostLabels, l) - } - - if h.Health != nil { - d.Set(hostState, *h.Health.Status) - } - - if _, ok := d.GetOk(hostCluster); ok { - d.Set(hostCluster, d.Get(hostCluster).(string)) - } else { - d.Set(hostCluster, location) - } - - if h.Assignment != nil { - d.Set(hostWorkerPool, *h.Assignment.WorkerPoolName) - d.Set(hostZone, *h.Assignment.Zone) - } - } - } - - return nil -} - -func resourceIBMSatelliteHostUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - locationName := parts[0] - hostID := parts[1] - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - updateHostOptions := &kubernetesserviceapiv1.UpdateSatelliteHostOptions{} - updateHostOptions.Controller = &locationName - updateHostOptions.HostID = &hostID - - if v, ok := d.GetOk(hostState); ok && v != nil && v.(string) == rsHostReadyStatus { - labels := make(map[string]string) - if _, ok := d.GetOk(hostLabels); ok { - l := d.Get(hostLabels).(*schema.Set) - labels = flattenHostLabels(l.List()) - updateHostOptions.Labels = labels - } - response, err := satClient.UpdateSatelliteHost(updateHostOptions) - if err != nil { - return fmt.Errorf("Error Updating Satellite Host: %s\n%s", err, response) - } - } - - return resourceIBMSatelliteHostRead(d, meta) -} - -func resourceIBMSatelliteHostDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) - if err != nil { - return err - } - - location := parts[0] - hostID := parts[1] - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - removeSatHostOptions := &kubernetesserviceapiv1.RemoveSatelliteHostOptions{} - removeSatHostOptions.Controller = &location - removeSatHostOptions.HostID = &hostID - - response, err := satClient.RemoveSatelliteHost(removeSatHostOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil - } - return fmt.Errorf("Error Deleting Satellite Host: %s\n%s", err, response) - } - - d.SetId("") - return nil -} - -func waitForHostAttachment(hostName, location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return false, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{rsHostProvisioningStatus, rsHostUnknownStatus}, - Target: []string{rsHostReadyStatus, rsHostNormalStatus}, - Refresh: func() (interface{}, string, error) { - attachOptions := &kubernetesserviceapiv1.GetSatelliteHostsOptions{ - Controller: &location, - } - hostList, resp, err := satClient.GetSatelliteHosts(attachOptions) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() != 404 { - return nil, "", fmt.Errorf("The satellite host (%s) failed to attached: %v\n%s", hostName, err, resp) - } - } - - if hostList != nil { - for _, h := range hostList { - if h.Health != nil { - if (hostName == *h.Name) && (*h.Health.Status == rsHostNormalStatus || *h.Health.Status == rsHostReadyStatus) { - return *h.Health.Status, *h.Health.Status, err - } - } - } - } - return hostName, rsHostProvisioningStatus, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 60 * time.Second, - MinTimeout: 60 * time.Second, - } - - return stateConf.WaitForState() -} diff --git a/ibm/resource_ibm_satellite_location.go b/ibm/resource_ibm_satellite_location.go deleted file mode 100644 index 70156e44b..000000000 --- a/ibm/resource_ibm_satellite_location.go +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -const ( - satLocation = "location" - sateLocZone = "managed_from" - - isLocationDeleting = "deleting" - isLocationDeleteDone = "done" - isLocationDeploying = "deploying" - isLocationReady = "action required" - isLocationDeployFailed = "deploy_failed" -) - -func resourceIBMSatelliteLocation() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMSatelliteLocationCreate, - Read: resourceIBMSatelliteLocationRead, - Update: resourceIBMSatelliteLocationUpdate, - Delete: resourceIBMSatelliteLocationDelete, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return immutableResourceCustomizeDiff([]string{satLocation, sateLocZone, "resource_group_id", "zones"}, diff) - }, - ), - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - satLocation: { - Type: schema.TypeString, - Required: true, - Description: "A unique name for the new Satellite location", - }, - sateLocZone: { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - if o == "" { - return false - } else if o[0:3] == n[0:3] { - return true - } - return o == n - }, - Description: "The IBM Cloud metro from which the Satellite location is managed", - }, - "description": { - Type: schema.TypeString, - Optional: true, - Description: "A description of the new Satellite location", - }, - "logging_account_id": { - Type: schema.TypeString, - Optional: true, - Description: "The account ID for IBM Log Analysis with LogDNA log forwarding", - }, - "cos_config": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "COSBucket - IBM Cloud Object Storage bucket configuration details", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "bucket": { - Type: schema.TypeString, - Optional: true, - }, - "endpoint": { - Type: schema.TypeString, - Optional: true, - }, - "region": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "cos_credentials": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "COSAuthorization - IBM Cloud Object Storage authorization keys", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "access_key_id": { - Type: schema.TypeString, - Optional: true, - Description: "The HMAC secret access key ID", - }, - "secret_access_key": { - Type: schema.TypeString, - Optional: true, - Description: "The HMAC secret access key", - }, - }, - }, - }, - "zones": { - Type: schema.TypeSet, - Computed: true, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Description: "The names of at least three high availability zones to use for the location", - }, - "resource_group_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "ID of the resource group.", - }, - tags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_satellite_location", "tags")}, - Set: resourceIBMVPCHash, - Description: "List of tags associated with resource instance", - }, - ResourceGroupName: { - Type: schema.TypeString, - Computed: true, - Description: "Name of the resource group", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "Location CRN", - }, - "host_attached_count": { - Type: schema.TypeInt, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The total number of hosts that are attached to the Satellite location.", - }, - "host_available_count": { - Type: schema.TypeInt, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The available number of hosts that can be assigned to a cluster resource in the Satellite location.", - }, - "created_on": { - Type: schema.TypeString, - Computed: true, - Description: "Created Date", - }, - "ingress_hostname": { - Type: schema.TypeString, - Computed: true, - }, - "ingress_secret": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - }, - }, - } -} - -func resourceIBMSatelliteLocationValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tags", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, - Optional: true, - Regexp: `^[A-Za-z0-9:_ .-]+$`, - MinValueLength: 1, - MaxValueLength: 128}) - - ibmSatelliteLocationValidator := ResourceValidator{ResourceName: "ibm_satellite_location", Schema: validateSchema} - return &ibmSatelliteLocationValidator -} - -func resourceIBMSatelliteLocationCreate(d *schema.ResourceData, meta interface{}) error { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - createSatLocOptions := &kubernetesserviceapiv1.CreateSatelliteLocationOptions{} - satLocation := d.Get(satLocation).(string) - createSatLocOptions.Name = &satLocation - sateLocZone := d.Get(sateLocZone).(string) - createSatLocOptions.Location = &sateLocZone - - if v, ok := d.GetOk("cos_config"); ok { - createSatLocOptions.CosConfig = expandCosConfig(v.([]interface{})) - } - - if v, ok := d.GetOk("cos_credentials"); ok { - createSatLocOptions.CosCredentials = expandCosCredentials(v.([]interface{})) - } - - if v, ok := d.GetOk("logging_account_id"); ok { - logAccID := v.(string) - createSatLocOptions.LoggingAccountID = &logAccID - } - - if v, ok := d.GetOk("description"); ok { - desc := v.(string) - createSatLocOptions.Description = &desc - } - - if v, ok := d.GetOk("zones"); ok { - z := v.(*schema.Set) - createSatLocOptions.Zones = flatterSatelliteZones(z) - } - - if v, ok := d.GetOk("resource_group_id"); ok && v != nil { - pathParamsMap := map[string]string{ - "X-Auth-Resource-Group": v.(string), - } - createSatLocOptions.Headers = pathParamsMap - } - - instance, response, err := satClient.CreateSatelliteLocation(createSatLocOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error Creating Satellite Location: %s\n%s", err, response) - } - - d.SetId(*instance.ID) - log.Printf("[INFO] Created satellite location : %s", satLocation) - - v := os.Getenv("IC_ENV_TAGS") - if _, ok := d.GetOk("tags"); ok || v != "" { - oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) - if err != nil { - log.Printf( - "Error on create of ibm satellite location (%s) tags: %s", d.Id(), err) - } - } - - //Wait for location to be in ready state - _, err = waitForLocationToReady(*instance.ID, d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for location (%s) to reach ready state: %s", *instance.ID, err) - } - - return resourceIBMSatelliteLocationRead(d, meta) -} - -func resourceIBMSatelliteLocationRead(d *schema.ResourceData, meta interface{}) error { - ID := d.Id() - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ - Controller: &ID, - } - - instance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) - if err != nil || instance == nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return err - } - - d.Set(satLocation, *instance.Name) - if instance.Description != nil { - d.Set("description", *instance.Description) - } - - if instance.Datacenter != nil { - d.Set(sateLocZone, *instance.Datacenter) - } - - if instance.WorkerZones != nil { - d.Set("zones", instance.WorkerZones) - } - - if instance.ResourceGroup != nil { - d.Set("resource_group_id", instance.ResourceGroup) - } - - tags, err := GetTagsUsingCRN(meta, *instance.Crn) - if err != nil { - log.Printf( - "Error on get of ibm satellite location tags (%s) tags: %s", d.Id(), err) - } - d.Set("tags", tags) - d.Set("crn", *instance.Crn) - d.Set(ResourceGroupName, *instance.ResourceGroupName) - if instance.Hosts != nil { - d.Set("host_attached_count", *instance.Hosts.Total) - d.Set("host_available_count", *instance.Hosts.Available) - } - d.Set("created_on", *instance.CreatedDate) - if instance.Ingress != nil { - d.Set("ingress_hostname", *instance.Ingress.Hostname) - d.Set("ingress_secret", *instance.Ingress.SecretName) - } - - return nil -} - -func resourceIBMSatelliteLocationUpdate(d *schema.ResourceData, meta interface{}) error { - ID := d.Id() - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - v := os.Getenv("IC_ENV_TAGS") - if d.HasChange("tags") || v != "" { - oldList, newList := d.GetChange("tags") - getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ - Controller: &ID, - } - - instance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) - if err != nil || instance == nil { - return fmt.Errorf("Error retrieving satellite location: %s\n%s", err, response) - } - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) - if err != nil { - log.Printf( - "An error occured during update of instance (%s) tags: %s", ID, err) - } - } - return nil -} - -func resourceIBMSatelliteLocationDelete(d *schema.ResourceData, meta interface{}) error { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return err - } - - removeSatLocOptions := &kubernetesserviceapiv1.RemoveSatelliteLocationOptions{} - name := d.Get(satLocation).(string) - removeSatLocOptions.Controller = &name - - response, err := satClient.RemoveSatelliteLocation(removeSatLocOptions) - if err != nil && response.StatusCode != 404 { - return fmt.Errorf("Error Deleting Satellite Location: %s\n%s", err, response) - } - - //Wait for location to delete - _, err = waitForLocationDelete(name, d, meta) - if err != nil { - return fmt.Errorf( - "Error waiting for deleting location instance: %s", err) - } - - d.SetId("") - return nil -} - -func waitForLocationDelete(location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return false, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{isLocationDeleting, ""}, - Target: []string{isLocationDeleteDone}, - Refresh: func() (interface{}, string, error) { - getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationsOptions{} - locations, response, err := satClient.GetSatelliteLocations(getSatLocOptions) - if err != nil { - return nil, "", fmt.Errorf("Error Getting locations list to delete : %s\n%s", err, response) - } - - isExist := false - if locations != nil { - for _, loc := range locations { - if *loc.ID == location || *loc.Name == location { - isExist = true - return "", isLocationDeleting, nil - } - } - if isExist == false { - return location, isLocationDeleteDone, nil - } - } - return nil, "", fmt.Errorf("Failed to delete location : %s\n%s", err, response) - }, - Timeout: d.Timeout(schema.TimeoutDelete), - Delay: 60 * time.Second, - MinTimeout: 60 * time.Second, - } - - return stateConf.WaitForState() -} - -func waitForLocationToReady(loc string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() - if err != nil { - return false, err - } - - stateConf := &resource.StateChangeConf{ - Pending: []string{isLocationDeploying}, - Target: []string{isLocationReady, isLocationDeployFailed}, - Refresh: func() (interface{}, string, error) { - getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ - Controller: ptrToString(loc), - } - - var location *kubernetesserviceapiv1.MultishiftGetController - var response *core.DetailedResponse - var err error - err = resource.Retry(5*time.Minute, func() *resource.RetryError { - location, response, err = satClient.GetSatelliteLocation(getSatLocOptions) - if err != nil || location == nil { - if response != nil && response.StatusCode == 404 { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - - if isResourceTimeoutError(err) { - location, response, err = satClient.GetSatelliteLocation(getSatLocOptions) - } - - if location != nil && *location.State == isLocationDeployFailed { - return location, isLocationDeployFailed, fmt.Errorf("The location is in failed state: %s", d.Id()) - } - - if location != nil && *location.State == isLocationReady { - return location, isLocationReady, nil - } - return location, isLocationDeploying, nil - }, - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 60 * time.Second, - MinTimeout: 60 * time.Second, - } - - return stateConf.WaitForState() -} diff --git a/ibm/resource_ibm_scc_si_note.go b/ibm/resource_ibm_scc_si_note.go deleted file mode 100644 index da770a4cf..000000000 --- a/ibm/resource_ibm_scc_si_note.go +++ /dev/null @@ -1,1175 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/scc-go-sdk/findingsv1" -) - -func resourceIBMSccSiNote() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMSccSiNoteCreate, - ReadContext: resourceIBMSccSiNoteRead, - UpdateContext: resourceIBMSccSiNoteUpdate, - DeleteContext: resourceIBMSccSiNoteDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "account_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - }, - "provider_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "Part of the parent. This field contains the provider ID. For example: providers/{provider_id}.", - }, - "short_description": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "A one sentence description of your note.", - }, - "long_description": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "A more detailed description of your note.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_scc_si_note", "kind"), - Description: "The type of note. Use this field to filter notes and occurences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard.", - }, - "note_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The ID of the note.", - }, - "reported_by": &schema.Schema{ - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - Description: "The entity reporting a note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The id of this reporter.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The title of this reporter.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The url of this reporter.", - }, - }, - }, - }, - "related_url": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "label": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Label to describe usage of the URL.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The URL that you want to associate with the note.", - }, - }, - }, - }, - "shared": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "True if this note can be shared by multiple accounts.", - }, - "finding": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "FindingType provides details about a finding note.", - ExactlyOneOf: []string{"finding", "kpi", "card", "section"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "severity": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact.", - }, - "next_steps": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Common remediation steps for the finding of this type.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Title of this next step.", - }, - "url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL associated to this next steps.", - }, - }, - }, - }, - }, - }, - }, - "kpi": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "KpiType provides details about a KPI note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "aggregation_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The aggregation type of the KPI values. - SUM: A single-value metrics aggregation type that sums up numeric values that are extracted from KPI occurrences.", - }, - }, - }, - }, - "card": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "section": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The section this card belongs to.", - }, - "title": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The title of this card.", - }, - "subtitle": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The subtitle of this card.", - }, - "order": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ValidateFunc: InvokeValidator("ibm_scc_si_note", "order"), - Description: "The order of the card in which it will appear on SA dashboard in the mentioned section.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Required: true, - Description: "The finding note names associated to this card.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "requires_configuration": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "badge_text": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The text associated to the card's badge.", - }, - "badge_image": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The base64 content of the image associated to the card's badge.", - }, - "elements": &schema.Schema{ - Type: schema.TypeList, - Required: true, - Description: "The elements of this card.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "text": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The text of this card element.", - }, - "kind": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "NUMERIC", - Description: "Kind of element- NUMERIC: Single numeric value- BREAKDOWN: Breakdown of numeric values- TIME_SERIES: Time-series of numeric values.", - }, - "default_time_range": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "4d", - Description: "The default time range of this card element.", - }, - "value_type": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "label", - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "value_types": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "the value types associated to this card element.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kind": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Kind of element- KPI: Kind of value derived from a KPI occurrence.", - }, - "kpi_note_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the kpi note associated to the occurrence with the value for this card element value type.", - }, - "text": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "label", - Description: "The text of this element type.", - }, - "finding_note_names": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "the names of the finding note associated that act as filters for counting the occurrences.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "default_interval": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "d", - Description: "The default interval of the time series.", - }, - }, - }, - }, - }, - }, - }, - "section": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "Card provides details about a card kind of note.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "title": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The title of this section.", - }, - "image": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The image of this section.", - }, - }, - }, - }, - "create_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was created. This field can be used as a filter in list requests.", - }, - "update_time": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Output only. The time this note was last updated. This field can be used as a filter in list requests.", - }, - }, - } -} - -func resourceIBMSccSiNoteValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 2) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "kind", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: "CARD, CARD_CONFIGURED, FINDING, KPI, SECTION", - }, - ValidateSchema{ - Identifier: "order", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, - Required: false, - MinValue: "1", - MaxValue: "6"}, - ) - - resourceValidator := ResourceValidator{ResourceName: "ibm_scc_si_note", Schema: validateSchema} - return &resourceValidator -} - -func resourceIBMSccSiNoteCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return diag.FromErr(err) - } - - accountID := d.Get("account_id").(string) - log.Println(fmt.Sprintf("[DEBUG] using specified AccountID %s", accountID)) - if accountID == "" { - accountID = userDetails.userAccount - log.Println(fmt.Sprintf("[DEBUG] AccountID not spedified, using %s", accountID)) - } - findingsClient.AccountID = &accountID - - createNoteOptions := &findingsv1.CreateNoteOptions{} - - createNoteOptions.SetProviderID(d.Get("provider_id").(string)) - createNoteOptions.SetShortDescription(d.Get("short_description").(string)) - createNoteOptions.SetLongDescription(d.Get("long_description").(string)) - createNoteOptions.SetKind(d.Get("kind").(string)) - createNoteOptions.SetID(d.Get("note_id").(string)) - reportedBy := resourceIBMSccSiNoteMapToReporter(d.Get("reported_by.0").(map[string]interface{})) - createNoteOptions.SetReportedBy(&reportedBy) - if _, ok := d.GetOk("related_url"); ok { - var relatedURL []findingsv1.APINoteRelatedURL - for _, e := range d.Get("related_url").([]interface{}) { - value := e.(map[string]interface{}) - relatedURLItem := resourceIBMSccSiNoteMapToAPINoteRelatedURL(value) - relatedURL = append(relatedURL, relatedURLItem) - } - createNoteOptions.SetRelatedURL(relatedURL) - } - if _, ok := d.GetOk("shared"); ok { - createNoteOptions.SetShared(d.Get("shared").(bool)) - } - if _, ok := d.GetOk("finding"); ok { - finding := resourceIBMSccSiNoteMapToFindingType(d.Get("finding.0").(map[string]interface{})) - createNoteOptions.SetFinding(&finding) - } - if _, ok := d.GetOk("kpi"); ok { - kpi := resourceIBMSccSiNoteMapToKpiType(d.Get("kpi.0").(map[string]interface{})) - createNoteOptions.SetKpi(&kpi) - } - if _, ok := d.GetOk("card"); ok { - card := resourceIBMSccSiNoteMapToCard(d.Get("card.0").(map[string]interface{})) - createNoteOptions.SetCard(&card) - } - if _, ok := d.GetOk("section"); ok { - section := resourceIBMSccSiNoteMapToSection(d.Get("section.0").(map[string]interface{})) - createNoteOptions.SetSection(§ion) - } - - apiNote, response, err := findingsClient.CreateNoteWithContext(context, createNoteOptions) - if err != nil { - log.Printf("[DEBUG] CreateNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("CreateNoteWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s/%s/%s", accountID, *createNoteOptions.ProviderID, *apiNote.ID)) - - return resourceIBMSccSiNoteRead(context, d, meta) -} - -func resourceIBMSccSiNoteMapToReporter(reporterMap map[string]interface{}) findingsv1.Reporter { - reporter := findingsv1.Reporter{} - - reporter.ID = core.StringPtr(reporterMap["id"].(string)) - reporter.Title = core.StringPtr(reporterMap["title"].(string)) - if reporterMap["url"] != nil { - reporter.URL = core.StringPtr(reporterMap["url"].(string)) - } - - return reporter -} - -func resourceIBMSccSiNoteMapToAPINoteRelatedURL(apiNoteRelatedURLMap map[string]interface{}) findingsv1.APINoteRelatedURL { - apiNoteRelatedURL := findingsv1.APINoteRelatedURL{} - - apiNoteRelatedURL.Label = core.StringPtr(apiNoteRelatedURLMap["label"].(string)) - apiNoteRelatedURL.URL = core.StringPtr(apiNoteRelatedURLMap["url"].(string)) - - return apiNoteRelatedURL -} - -func resourceIBMSccSiNoteMapToFindingType(findingTypeMap map[string]interface{}) findingsv1.FindingType { - findingType := findingsv1.FindingType{} - - findingType.Severity = core.StringPtr(findingTypeMap["severity"].(string)) - if findingTypeMap["next_steps"] != nil { - nextSteps := []findingsv1.RemediationStep{} - for _, nextStepsItem := range findingTypeMap["next_steps"].([]interface{}) { - nextStepsItemModel := resourceIBMSccSiNoteMapToRemediationStep(nextStepsItem.(map[string]interface{})) - nextSteps = append(nextSteps, nextStepsItemModel) - } - findingType.NextSteps = nextSteps - } - - return findingType -} - -func resourceIBMSccSiNoteMapToRemediationStep(remediationStepMap map[string]interface{}) findingsv1.RemediationStep { - remediationStep := findingsv1.RemediationStep{} - - if remediationStepMap["title"] != nil { - remediationStep.Title = core.StringPtr(remediationStepMap["title"].(string)) - } - if remediationStepMap["url"] != nil { - remediationStep.URL = core.StringPtr(remediationStepMap["url"].(string)) - } - - return remediationStep -} - -func resourceIBMSccSiNoteMapToKpiType(kpiTypeMap map[string]interface{}) findingsv1.KpiType { - kpiType := findingsv1.KpiType{} - - kpiType.AggregationType = core.StringPtr(kpiTypeMap["aggregation_type"].(string)) - - return kpiType -} - -func resourceIBMSccSiNoteMapToCard(cardMap map[string]interface{}) findingsv1.Card { - card := findingsv1.Card{} - - card.Section = core.StringPtr(cardMap["section"].(string)) - card.Title = core.StringPtr(cardMap["title"].(string)) - card.Subtitle = core.StringPtr(cardMap["subtitle"].(string)) - if cardMap["order"] != nil && cardMap["order"].(int) > 0 { - card.Order = core.Int64Ptr(int64(cardMap["order"].(int))) - - } - findingNoteNames := []string{} - for _, findingNoteNamesItem := range cardMap["finding_note_names"].([]interface{}) { - findingNoteNames = append(findingNoteNames, findingNoteNamesItem.(string)) - } - card.FindingNoteNames = findingNoteNames - if cardMap["requires_configuration"] != nil { - card.RequiresConfiguration = core.BoolPtr(cardMap["requires_configuration"].(bool)) - } - if cardMap["badge_text"] != nil { - card.BadgeText = core.StringPtr(cardMap["badge_text"].(string)) - } - if cardMap["badge_image"] != nil { - card.BadgeImage = core.StringPtr(cardMap["badge_image"].(string)) - } - elements := []findingsv1.CardElementIntf{} - for _, elementsItem := range cardMap["elements"].([]interface{}) { - elementsItemModel := resourceIBMSccSiNoteMapToCardElement(elementsItem.(map[string]interface{})) - elements = append(elements, elementsItemModel) - } - card.Elements = elements - - return card -} - -func resourceIBMSccSiNoteMapToCardElement(cardElementMap map[string]interface{}) findingsv1.CardElementIntf { - cardElement := findingsv1.CardElement{} - - if cardElementMap["text"] != nil { - cardElement.Text = core.StringPtr(cardElementMap["text"].(string)) - } - if cardElementMap["kind"] != nil { - cardElement.Kind = core.StringPtr(cardElementMap["kind"].(string)) - } - if cardElementMap["default_time_range"] != nil { - cardElement.DefaultTimeRange = core.StringPtr(cardElementMap["default_time_range"].(string)) - } - - if cardElementMap["value_type"] != nil && len(cardElementMap["value_type"].([]interface{})) > 0 { - cardElementValueType := findingsv1.NumericCardElementValueType{} - - if cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["kind"] != nil { - cardElementValueType.Kind = core.StringPtr(cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["kind"].(string)) - } - if cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["text"] != nil { - cardElementValueType.Text = core.StringPtr(cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["text"].(string)) - } - if cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["kpi_note_name"] != nil && cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["kpi_note_name"] != "" { - cardElementValueType.KpiNoteName = core.StringPtr(cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["kpi_note_name"].(string)) - } - if cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["finding_note_names"] != nil && len(cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["finding_note_names"].([]interface{})) > 0 { - findingNoteNames := []string{} - for _, findingNoteNamesItem := range cardElementMap["value_type"].([]interface{})[0].(map[string]interface{})["finding_note_names"].([]interface{}) { - findingNoteNames = append(findingNoteNames, findingNoteNamesItem.(string)) - } - cardElementValueType.FindingNoteNames = findingNoteNames - } - cardElement.ValueType = &cardElementValueType - } - - if cardElementMap["value_types"] != nil { - valueTypes := []findingsv1.ValueTypeIntf{} - for _, valueTypesItem := range cardElementMap["value_types"].([]interface{}) { - valueTypesItemModel := resourceIBMSccSiNoteMapToValueType(valueTypesItem.(map[string]interface{})) - valueTypes = append(valueTypes, valueTypesItemModel) - } - cardElement.ValueTypes = valueTypes - } - if cardElementMap["default_interval"] != nil { - cardElement.DefaultInterval = core.StringPtr(cardElementMap["default_interval"].(string)) - } - - return &cardElement -} - -func resourceIBMSccSiNoteMapToNumericCardElementValueType(numericCardElementValueTypeMap map[string]interface{}) findingsv1.NumericCardElementValueType { - numericCardElementValueType := findingsv1.NumericCardElementValueType{} - - if numericCardElementValueTypeMap["kind"] != nil { - numericCardElementValueType.Kind = core.StringPtr(numericCardElementValueTypeMap["kind"].(string)) - } - if numericCardElementValueTypeMap["kpi_note_name"] != nil { - numericCardElementValueType.KpiNoteName = core.StringPtr(numericCardElementValueTypeMap["kpi_note_name"].(string)) - } - if numericCardElementValueTypeMap["text"] != nil { - numericCardElementValueType.Text = core.StringPtr(numericCardElementValueTypeMap["text"].(string)) - } - if numericCardElementValueTypeMap["finding_note_names"] != nil { - findingNoteNames := []string{} - for _, findingNoteNamesItem := range numericCardElementValueTypeMap["finding_note_names"].([]interface{}) { - findingNoteNames = append(findingNoteNames, findingNoteNamesItem.(string)) - } - numericCardElementValueType.FindingNoteNames = findingNoteNames - } - - return numericCardElementValueType -} - -func resourceIBMSccSiNoteMapToValueType(valueTypeMap map[string]interface{}) findingsv1.ValueTypeIntf { - valueType := findingsv1.ValueType{} - - if valueTypeMap["kind"] != nil { - valueType.Kind = core.StringPtr(valueTypeMap["kind"].(string)) - } - if valueTypeMap["kpi_note_name"] != nil && len(valueTypeMap["kpi_note_name"].(string)) > 0 { - valueType.KpiNoteName = core.StringPtr(valueTypeMap["kpi_note_name"].(string)) - } - if valueTypeMap["text"] != nil { - valueType.Text = core.StringPtr(valueTypeMap["text"].(string)) - } - if valueTypeMap["finding_note_names"] != nil { - findingNoteNames := []string{} - for _, findingNoteNamesItem := range valueTypeMap["finding_note_names"].([]interface{}) { - findingNoteNames = append(findingNoteNames, findingNoteNamesItem.(string)) - } - valueType.FindingNoteNames = findingNoteNames - } - - return &valueType -} - -func resourceIBMSccSiNoteMapToValueTypeFindingCountValueType(valueTypeFindingCountValueTypeMap map[string]interface{}) findingsv1.ValueTypeFindingCountValueType { - valueTypeFindingCountValueType := findingsv1.ValueTypeFindingCountValueType{} - - valueTypeFindingCountValueType.Kind = core.StringPtr(valueTypeFindingCountValueTypeMap["kind"].(string)) - findingNoteNames := []string{} - for _, findingNoteNamesItem := range valueTypeFindingCountValueTypeMap["finding_note_names"].([]interface{}) { - findingNoteNames = append(findingNoteNames, findingNoteNamesItem.(string)) - } - valueTypeFindingCountValueType.FindingNoteNames = findingNoteNames - valueTypeFindingCountValueType.Text = core.StringPtr(valueTypeFindingCountValueTypeMap["text"].(string)) - - return valueTypeFindingCountValueType -} - -func resourceIBMSccSiNoteMapToValueTypeKpiValueType(valueTypeKpiValueTypeMap map[string]interface{}) findingsv1.ValueTypeKpiValueType { - valueTypeKpiValueType := findingsv1.ValueTypeKpiValueType{} - - valueTypeKpiValueType.Kind = core.StringPtr(valueTypeKpiValueTypeMap["kind"].(string)) - valueTypeKpiValueType.KpiNoteName = core.StringPtr(valueTypeKpiValueTypeMap["kpi_note_name"].(string)) - valueTypeKpiValueType.Text = core.StringPtr(valueTypeKpiValueTypeMap["text"].(string)) - - return valueTypeKpiValueType -} - -func resourceIBMSccSiNoteMapToCardElementTimeSeriesCardElement(cardElementTimeSeriesCardElementMap map[string]interface{}) findingsv1.CardElementTimeSeriesCardElement { - cardElementTimeSeriesCardElement := findingsv1.CardElementTimeSeriesCardElement{} - - cardElementTimeSeriesCardElement.Text = core.StringPtr(cardElementTimeSeriesCardElementMap["text"].(string)) - if cardElementTimeSeriesCardElementMap["default_interval"] != nil { - cardElementTimeSeriesCardElement.DefaultInterval = core.StringPtr(cardElementTimeSeriesCardElementMap["default_interval"].(string)) - } - cardElementTimeSeriesCardElement.Kind = core.StringPtr(cardElementTimeSeriesCardElementMap["kind"].(string)) - if cardElementTimeSeriesCardElementMap["default_time_range"] != nil { - cardElementTimeSeriesCardElement.DefaultTimeRange = core.StringPtr(cardElementTimeSeriesCardElementMap["default_time_range"].(string)) - } - valueTypes := []findingsv1.ValueTypeIntf{} - for _, valueTypesItem := range cardElementTimeSeriesCardElementMap["value_types"].([]interface{}) { - valueTypesItemModel := resourceIBMSccSiNoteMapToValueType(valueTypesItem.(map[string]interface{})) - valueTypes = append(valueTypes, valueTypesItemModel) - } - cardElementTimeSeriesCardElement.ValueTypes = valueTypes - - return cardElementTimeSeriesCardElement -} - -func resourceIBMSccSiNoteMapToCardElementBreakdownCardElement(cardElementBreakdownCardElementMap map[string]interface{}) findingsv1.CardElementBreakdownCardElement { - cardElementBreakdownCardElement := findingsv1.CardElementBreakdownCardElement{} - - cardElementBreakdownCardElement.Text = core.StringPtr(cardElementBreakdownCardElementMap["text"].(string)) - cardElementBreakdownCardElement.Kind = core.StringPtr(cardElementBreakdownCardElementMap["kind"].(string)) - if cardElementBreakdownCardElementMap["default_time_range"] != nil { - cardElementBreakdownCardElement.DefaultTimeRange = core.StringPtr(cardElementBreakdownCardElementMap["default_time_range"].(string)) - } - valueTypes := []findingsv1.ValueTypeIntf{} - for _, valueTypesItem := range cardElementBreakdownCardElementMap["value_types"].([]interface{}) { - valueTypesItemModel := resourceIBMSccSiNoteMapToValueType(valueTypesItem.(map[string]interface{})) - valueTypes = append(valueTypes, valueTypesItemModel) - } - cardElementBreakdownCardElement.ValueTypes = valueTypes - - return cardElementBreakdownCardElement -} - -func resourceIBMSccSiNoteMapToCardElementNumericCardElement(cardElementNumericCardElementMap map[string]interface{}) findingsv1.CardElementNumericCardElement { - cardElementNumericCardElement := findingsv1.CardElementNumericCardElement{} - - cardElementNumericCardElement.Text = core.StringPtr(cardElementNumericCardElementMap["text"].(string)) - cardElementNumericCardElement.Kind = core.StringPtr(cardElementNumericCardElementMap["kind"].(string)) - if cardElementNumericCardElementMap["default_time_range"] != nil { - cardElementNumericCardElement.DefaultTimeRange = core.StringPtr(cardElementNumericCardElementMap["default_time_range"].(string)) - } - // TODO: handle ValueType of type NumericCardElementValueType -- not primitive type, not list - - return cardElementNumericCardElement -} - -func resourceIBMSccSiNoteMapToSection(sectionMap map[string]interface{}) findingsv1.Section { - section := findingsv1.Section{} - - section.Title = core.StringPtr(sectionMap["title"].(string)) - section.Image = core.StringPtr(sectionMap["image"].(string)) - - return section -} - -func resourceIBMSccSiNoteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - - getNoteOptions := &findingsv1.GetNoteOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - findingsClient.AccountID = &parts[0] - - d.Set("account_id", &parts[0]) - - getNoteOptions.SetProviderID(parts[1]) - getNoteOptions.SetNoteID(parts[2]) - - apiNote, response, err := findingsClient.GetNoteWithContext(context, getNoteOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetNoteWithContext failed %s\n%s", err, response)) - } - - if err = d.Set("provider_id", getNoteOptions.ProviderID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting provider_id: %s", err)) - } - if err = d.Set("short_description", apiNote.ShortDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) - } - if err = d.Set("long_description", apiNote.LongDescription); err != nil { - return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) - } - if err = d.Set("kind", apiNote.Kind); err != nil { - return diag.FromErr(fmt.Errorf("Error setting kind: %s", err)) - } - if err = d.Set("note_id", apiNote.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting note_id: %s", err)) - } - reportedByMap := resourceIBMSccSiNoteReporterToMap(*apiNote.ReportedBy) - if err = d.Set("reported_by", []map[string]interface{}{reportedByMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting reported_by: %s", err)) - } - if apiNote.RelatedURL != nil { - relatedURL := []map[string]interface{}{} - for _, relatedURLItem := range apiNote.RelatedURL { - relatedURLItemMap := resourceIBMSccSiNoteAPINoteRelatedURLToMap(relatedURLItem) - relatedURL = append(relatedURL, relatedURLItemMap) - } - if err = d.Set("related_url", relatedURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting related_url: %s", err)) - } - } - if err = d.Set("shared", apiNote.Shared); err != nil { - return diag.FromErr(fmt.Errorf("Error setting shared: %s", err)) - } - if apiNote.Finding != nil { - findingMap := resourceIBMSccSiNoteFindingTypeToMap(*apiNote.Finding) - if err = d.Set("finding", []map[string]interface{}{findingMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting finding: %s", err)) - } - } - if apiNote.Kpi != nil { - kpiMap := resourceIBMSccSiNoteKpiTypeToMap(*apiNote.Kpi) - if err = d.Set("kpi", []map[string]interface{}{kpiMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting kpi: %s", err)) - } - } - if apiNote.Card != nil { - cardIntf := d.Get("card") - cardMap := resourceIBMSccSiNoteCardToMap(*apiNote.Card, cardIntf) - if err = d.Set("card", []map[string]interface{}{cardMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting card: %s", err)) - } - } - if apiNote.Section != nil { - sectionMap := resourceIBMSccSiNoteSectionToMap(*apiNote.Section) - if err = d.Set("section", []map[string]interface{}{sectionMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting section: %s", err)) - } - } - if err = d.Set("create_time", dateTimeToString(apiNote.CreateTime)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting create_time: %s", err)) - } - if err = d.Set("update_time", dateTimeToString(apiNote.UpdateTime)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting update_time: %s", err)) - } - - return nil -} - -func resourceIBMSccSiNoteReporterToMap(reporter findingsv1.Reporter) map[string]interface{} { - reporterMap := map[string]interface{}{} - - reporterMap["id"] = reporter.ID - reporterMap["title"] = reporter.Title - if reporter.URL != nil { - reporterMap["url"] = reporter.URL - } - - return reporterMap -} - -func resourceIBMSccSiNoteAPINoteRelatedURLToMap(apiNoteRelatedURL findingsv1.APINoteRelatedURL) map[string]interface{} { - apiNoteRelatedURLMap := map[string]interface{}{} - - apiNoteRelatedURLMap["label"] = apiNoteRelatedURL.Label - apiNoteRelatedURLMap["url"] = apiNoteRelatedURL.URL - - return apiNoteRelatedURLMap -} - -func resourceIBMSccSiNoteFindingTypeToMap(findingType findingsv1.FindingType) map[string]interface{} { - findingTypeMap := map[string]interface{}{} - - findingTypeMap["severity"] = findingType.Severity - if findingType.NextSteps != nil { - nextSteps := []map[string]interface{}{} - for _, nextStepsItem := range findingType.NextSteps { - nextStepsItemMap := resourceIBMSccSiNoteRemediationStepToMap(nextStepsItem) - nextSteps = append(nextSteps, nextStepsItemMap) - // TODO: handle NextSteps of type TypeList -- list of non-primitive, not model items - } - findingTypeMap["next_steps"] = nextSteps - } - - return findingTypeMap -} - -func resourceIBMSccSiNoteRemediationStepToMap(remediationStep findingsv1.RemediationStep) map[string]interface{} { - remediationStepMap := map[string]interface{}{} - - if remediationStep.Title != nil { - remediationStepMap["title"] = remediationStep.Title - } - if remediationStep.URL != nil { - remediationStepMap["url"] = remediationStep.URL - } - - return remediationStepMap -} - -func resourceIBMSccSiNoteKpiTypeToMap(kpiType findingsv1.KpiType) map[string]interface{} { - kpiTypeMap := map[string]interface{}{} - - kpiTypeMap["aggregation_type"] = kpiType.AggregationType - - return kpiTypeMap -} - -func resourceIBMSccSiNoteCardToMap(card findingsv1.Card, cardIntf interface{}) map[string]interface{} { - cardMap := map[string]interface{}{} - - cardMap["section"] = card.Section - cardMap["title"] = card.Title - cardMap["subtitle"] = card.Subtitle - if card.Order != nil { - order := intValue(card.Order) - if order != 0 { - cardMap["order"] = intValue(card.Order) - } - } - cardMap["finding_note_names"] = card.FindingNoteNames - if card.RequiresConfiguration != nil { - cardMap["requires_configuration"] = card.RequiresConfiguration - } - if card.BadgeText != nil { - cardMap["badge_text"] = card.BadgeText - } - if card.BadgeImage != nil { - cardMap["badge_image"] = card.BadgeImage - } - elements := []map[string]interface{}{} - for i, elementsItem := range card.Elements { - var elemResource interface{} - if cardIntf != nil && len(cardIntf.([]interface{})) > 0 { - elemResource = cardIntf.([]interface{})[0].(map[string]interface{})["elements"].([]interface{})[i] - } - elementsItemMap := resourceIBMSccSiNoteCardElementToMap(elementsItem, elemResource) - elements = append(elements, elementsItemMap) - // TODO: handle Elements of type TypeList -- list of non-primitive, not model items - } - cardMap["elements"] = elements - - return cardMap -} - -func resourceIBMSccSiNoteCardElementToMap(cardElement findingsv1.CardElementIntf, elemResource interface{}) map[string]interface{} { - cardElementMap := map[string]interface{}{} - - switch v := cardElement.(type) { - case *findingsv1.CardElementNumericCardElement: - cardElementMap = resourceIBMSccSiNoteCardElementNumericCardElementToMap(*v, elemResource) - case *findingsv1.CardElementBreakdownCardElement: - cardElementMap = resourceIBMSccSiNoteCardElementBreakdownCardElementToMap(*v, elemResource) - case *findingsv1.CardElementTimeSeriesCardElement: - cardElementMap = resourceIBMSccSiNoteCardElementTimeSeriesCardElementToMap(*v, elemResource) - default: - log.Printf("[DEBUG] Unknown card element type") - } - - return cardElementMap -} - -func resourceIBMSccSiNoteNumericCardElementValueTypeToMap(numericCardElementValueType findingsv1.NumericCardElementValueType, elemResource interface{}) map[string]interface{} { - numericCardElementValueTypeMap := map[string]interface{}{} - - if numericCardElementValueType.Kind != nil { - numericCardElementValueTypeMap["kind"] = numericCardElementValueType.Kind - } - - if numericCardElementValueType.KpiNoteName != nil { - numericCardElementValueTypeMap["kpi_note_name"] = numericCardElementValueType.KpiNoteName - if elemResource != nil { - findingNoteNamesMap := make([]string, 0) - findingNoteNames := elemResource.(map[string]interface{})["finding_note_names"] - if findingNoteNames != nil { - for _, findingNoteName := range findingNoteNames.([]interface{}) { - findingNoteNamesMap = append(findingNoteNamesMap, findingNoteName.(string)) - } - numericCardElementValueTypeMap["finding_note_names"] = findingNoteNamesMap - } - } - } - - if numericCardElementValueType.FindingNoteNames != nil { - numericCardElementValueTypeMap["finding_note_names"] = numericCardElementValueType.FindingNoteNames - if elemResource != nil { - kpiNoteName := elemResource.(map[string]interface{})["kpi_note_name"] - if kpiNoteName != nil { - numericCardElementValueTypeMap["kpi_note_name"] = kpiNoteName - } - } - } - - if numericCardElementValueType.Text != nil { - numericCardElementValueTypeMap["text"] = numericCardElementValueType.Text - } - - return numericCardElementValueTypeMap -} - -func resourceIBMSccSiNoteValueTypeToMap(valueType findingsv1.ValueTypeIntf, elemResource interface{}) map[string]interface{} { - valueTypeMap := map[string]interface{}{} - - switch v := valueType.(type) { - - case *findingsv1.ValueTypeFindingCountValueType: - valueTypeMap["kind"] = v.Kind - valueTypeMap["finding_note_names"] = v.FindingNoteNames - valueTypeMap["text"] = v.Text - kpiNoteName := elemResource.(map[string]interface{})["kpi_note_name"] - if kpiNoteName == nil { - valueTypeMap["kpi_note_name"] = "" - } else { - valueTypeMap["kpi_note_name"] = kpiNoteName - } - case *findingsv1.ValueTypeKpiValueType: - valueTypeMap["kind"] = v.Kind - valueTypeMap["kpi_note_name"] = v.KpiNoteName - valueTypeMap["text"] = v.Text - findingNoteNames := elemResource.(map[string]interface{})["finding_note_names"] - if findingNoteNames == nil { - valueTypeMap["finding_note_names"] = []string{} - } else { - findingNoteNamesMap := make([]string, 0) - for _, findingNoteName := range findingNoteNames.([]interface{}) { - findingNoteNamesMap = append(findingNoteNamesMap, findingNoteName.(string)) - } - valueTypeMap["finding_note_names"] = findingNoteNamesMap - } - default: - log.Printf("[DEBUG] Unknown card element value_type type") - } - - return valueTypeMap -} - -func resourceIBMSccSiNoteValueTypeFindingCountValueTypeToMap(valueTypeFindingCountValueType findingsv1.ValueTypeFindingCountValueType) map[string]interface{} { - valueTypeFindingCountValueTypeMap := map[string]interface{}{} - - valueTypeFindingCountValueTypeMap["kind"] = valueTypeFindingCountValueType.Kind - valueTypeFindingCountValueTypeMap["finding_note_names"] = valueTypeFindingCountValueType.FindingNoteNames - valueTypeFindingCountValueTypeMap["text"] = valueTypeFindingCountValueType.Text - - return valueTypeFindingCountValueTypeMap -} - -func resourceIBMSccSiNoteValueTypeKpiValueTypeToMap(valueTypeKpiValueType findingsv1.ValueTypeKpiValueType) map[string]interface{} { - valueTypeKpiValueTypeMap := map[string]interface{}{} - - valueTypeKpiValueTypeMap["kind"] = valueTypeKpiValueType.Kind - valueTypeKpiValueTypeMap["kpi_note_name"] = valueTypeKpiValueType.KpiNoteName - valueTypeKpiValueTypeMap["text"] = valueTypeKpiValueType.Text - - return valueTypeKpiValueTypeMap -} - -func resourceIBMSccSiNoteCardElementTimeSeriesCardElementToMap(cardElementTimeSeriesCardElement findingsv1.CardElementTimeSeriesCardElement, elemResource interface{}) map[string]interface{} { - cardElementTimeSeriesCardElementMap := map[string]interface{}{} - - cardElementTimeSeriesCardElementMap["text"] = cardElementTimeSeriesCardElement.Text - if cardElementTimeSeriesCardElement.DefaultInterval != nil { - cardElementTimeSeriesCardElementMap["default_interval"] = cardElementTimeSeriesCardElement.DefaultInterval - } - cardElementTimeSeriesCardElementMap["kind"] = cardElementTimeSeriesCardElement.Kind - if cardElementTimeSeriesCardElement.DefaultTimeRange != nil { - cardElementTimeSeriesCardElementMap["default_time_range"] = cardElementTimeSeriesCardElement.DefaultTimeRange - } - valueTypes := []map[string]interface{}{} - for _, valueTypesItem := range cardElementTimeSeriesCardElement.ValueTypes { - valueTypesItemMap := resourceIBMSccSiNoteValueTypeToMap(valueTypesItem, elemResource) - valueTypes = append(valueTypes, valueTypesItemMap) - // TODO: handle ValueTypes of type TypeList -- list of non-primitive, not model items - } - cardElementTimeSeriesCardElementMap["value_types"] = valueTypes - - return cardElementTimeSeriesCardElementMap -} - -func resourceIBMSccSiNoteCardElementBreakdownCardElementToMap(cardElementBreakdownCardElement findingsv1.CardElementBreakdownCardElement, elemResource interface{}) map[string]interface{} { - cardElementBreakdownCardElementMap := map[string]interface{}{} - - cardElementBreakdownCardElementMap["text"] = cardElementBreakdownCardElement.Text - cardElementBreakdownCardElementMap["kind"] = cardElementBreakdownCardElement.Kind - if cardElementBreakdownCardElement.DefaultTimeRange != nil { - cardElementBreakdownCardElementMap["default_time_range"] = cardElementBreakdownCardElement.DefaultTimeRange - } - valueTypes := []map[string]interface{}{} - for i, valueTypesItem := range cardElementBreakdownCardElement.ValueTypes { - valueType := elemResource.(map[string]interface{})["value_types"].([]interface{})[i] - valueTypesItemMap := resourceIBMSccSiNoteValueTypeToMap(valueTypesItem, valueType) - valueTypes = append(valueTypes, valueTypesItemMap) - // TODO: handle ValueTypes of type TypeList -- list of non-primitive, not model items - } - cardElementBreakdownCardElementMap["value_types"] = valueTypes - - if elemResource != nil { - if elemResource.(map[string]interface{})["default_interval"] != nil { - cardElementBreakdownCardElementMap["default_interval"] = elemResource.(map[string]interface{})["default_interval"].(string) - } - } - - return cardElementBreakdownCardElementMap -} - -func resourceIBMSccSiNoteCardElementNumericCardElementToMap(cardElementNumericCardElement findingsv1.CardElementNumericCardElement, elemResource interface{}) map[string]interface{} { - cardElementNumericCardElementMap := map[string]interface{}{} - - cardElementNumericCardElementMap["text"] = cardElementNumericCardElement.Text - cardElementNumericCardElementMap["kind"] = cardElementNumericCardElement.Kind - if cardElementNumericCardElement.DefaultTimeRange != nil { - cardElementNumericCardElementMap["default_time_range"] = cardElementNumericCardElement.DefaultTimeRange - } - ValueTypeMap := resourceIBMSccSiNoteNumericCardElementValueTypeToMap(*cardElementNumericCardElement.ValueType, elemResource) - cardElementNumericCardElementMap["value_type"] = []map[string]interface{}{ValueTypeMap} - - if elemResource != nil { - if elemResource.(map[string]interface{})["default_interval"] != nil { - cardElementNumericCardElementMap["default_interval"] = elemResource.(map[string]interface{})["default_interval"].(string) - } - } - - return cardElementNumericCardElementMap -} - -func resourceIBMSccSiNoteSectionToMap(section findingsv1.Section) map[string]interface{} { - sectionMap := map[string]interface{}{} - - sectionMap["title"] = section.Title - sectionMap["image"] = section.Image - - return sectionMap -} - -func resourceIBMSccSiNoteUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - - updateNoteOptions := &findingsv1.UpdateNoteOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - findingsClient.AccountID = &parts[0] - - updateNoteOptions.SetProviderID(parts[1]) - updateNoteOptions.SetNoteID(parts[2]) - updateNoteOptions.SetProviderID(d.Get("provider_id").(string)) - updateNoteOptions.SetShortDescription(d.Get("short_description").(string)) - updateNoteOptions.SetLongDescription(d.Get("long_description").(string)) - updateNoteOptions.SetKind(d.Get("kind").(string)) - updateNoteOptions.SetID(d.Get("note_id").(string)) - reportedBy := resourceIBMSccSiNoteMapToReporter(d.Get("reported_by.0").(map[string]interface{})) - updateNoteOptions.SetReportedBy(&reportedBy) - if _, ok := d.GetOk("related_url"); ok { - var relatedURL []findingsv1.APINoteRelatedURL - for _, e := range d.Get("related_url").([]interface{}) { - value := e.(map[string]interface{}) - relatedURLItem := resourceIBMSccSiNoteMapToAPINoteRelatedURL(value) - relatedURL = append(relatedURL, relatedURLItem) - } - updateNoteOptions.SetRelatedURL(relatedURL) - } - if _, ok := d.GetOk("shared"); ok { - updateNoteOptions.SetShared(d.Get("shared").(bool)) - } - if _, ok := d.GetOk("finding"); ok { - finding := resourceIBMSccSiNoteMapToFindingType(d.Get("finding.0").(map[string]interface{})) - updateNoteOptions.SetFinding(&finding) - } - if _, ok := d.GetOk("kpi"); ok { - kpi := resourceIBMSccSiNoteMapToKpiType(d.Get("kpi.0").(map[string]interface{})) - updateNoteOptions.SetKpi(&kpi) - } - if _, ok := d.GetOk("card"); ok { - card := resourceIBMSccSiNoteMapToCard(d.Get("card.0").(map[string]interface{})) - updateNoteOptions.SetCard(&card) - } - if _, ok := d.GetOk("section"); ok { - section := resourceIBMSccSiNoteMapToSection(d.Get("section.0").(map[string]interface{})) - updateNoteOptions.SetSection(§ion) - } - - _, response, err := findingsClient.UpdateNoteWithContext(context, updateNoteOptions) - if err != nil { - log.Printf("[DEBUG] UpdateNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("UpdateNoteWithContext failed %s\n%s", err, response)) - } - - return resourceIBMSccSiNoteRead(context, d, meta) -} - -func resourceIBMSccSiNoteDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - findingsClient, err := meta.(ClientSession).FindingsV1() - if err != nil { - return diag.FromErr(err) - } - - deleteNoteOptions := &findingsv1.DeleteNoteOptions{} - - parts, err := sepIdParts(d.Id(), "/") - if err != nil { - return diag.FromErr(err) - } - - findingsClient.AccountID = &parts[0] - - deleteNoteOptions.SetProviderID(parts[1]) - deleteNoteOptions.SetNoteID(parts[2]) - - response, err := findingsClient.DeleteNoteWithContext(context, deleteNoteOptions) - if err != nil { - log.Printf("[DEBUG] DeleteNoteWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("DeleteNoteWithContext failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_scc_si_note_test.go b/ibm/resource_ibm_scc_si_note_test.go deleted file mode 100644 index 62399d3b3..000000000 --- a/ibm/resource_ibm_scc_si_note_test.go +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/scc-go-sdk/findingsv1" -) - -func TestAccIBMSccSiNoteCardNumeric(t *testing.T) { - var conf findingsv1.APINote - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "CARD" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteCardNumericBasic(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSccSiNoteExists("ibm_scc_si_note.scc_si_note", conf), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kind), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.section", "section"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.title", "title"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.subtitle", "subtitle"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.kind", "NUMERIC"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_type.0.kind", "FINDING_COUNT"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_type.0.finding_note_names.0", fmt.Sprintf("providers/%s/notes/note123", providerID)), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNoteCardBreakdown(t *testing.T) { - var conf findingsv1.APINote - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "CARD" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteCardBreakdownBasic(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSccSiNoteExists("ibm_scc_si_note.scc_si_note", conf), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kind), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.section", "section"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.title", "title"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.subtitle", "subtitle"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.kind", "BREAKDOWN"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_types.0.kind", "FINDING_COUNT"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_types.0.finding_note_names.0", fmt.Sprintf("providers/%s/notes/note123", providerID)), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNoteCardTimeSeries(t *testing.T) { - var conf findingsv1.APINote - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "CARD" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteCardTimeSeriesBasic(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSccSiNoteExists("ibm_scc_si_note.scc_si_note", conf), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kind), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.section", "section"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.title", "title"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.subtitle", "subtitle"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.kind", "TIME_SERIES"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_types.0.kind", "FINDING_COUNT"), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "card.0.elements.0.value_types.0.finding_note_names.0", fmt.Sprintf("providers/%s/notes/note123", providerID)), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNoteBasic(t *testing.T) { - var conf findingsv1.APINote - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "FINDING" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - shortDescriptionUpdate := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescriptionUpdate := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kindUpdate := "FINDING" - noteIDUpdate := noteID - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfigBasic(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSccSiNoteExists("ibm_scc_si_note.scc_si_note", conf), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kind), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteID), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfigBasic(scc_si_account, providerID, shortDescriptionUpdate, longDescriptionUpdate, kindUpdate, noteIDUpdate), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescriptionUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescriptionUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kindUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteIDUpdate), - ), - }, - }, - }) -} - -func TestAccIBMSccSiNoteAllArgs(t *testing.T) { - var conf findingsv1.APINote - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "FINDING" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - shared := "true" - shortDescriptionUpdate := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescriptionUpdate := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kindUpdate := "FINDING" - noteIDUpdate := noteID - sharedUpdate := "false" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfig(scc_si_account, providerID, shortDescription, longDescription, kind, noteID, shared), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSccSiNoteExists("ibm_scc_si_note.scc_si_note", conf), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescription), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kind), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "shared", shared), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfig(scc_si_account, providerID, shortDescriptionUpdate, longDescriptionUpdate, kindUpdate, noteIDUpdate, sharedUpdate), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "provider_id", providerID), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "short_description", shortDescriptionUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "long_description", longDescriptionUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "kind", kindUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "note_id", noteIDUpdate), - resource.TestCheckResourceAttr("ibm_scc_si_note.scc_si_note", "shared", sharedUpdate), - ), - }, - resource.TestStep{ - ResourceName: "ibm_scc_si_note.scc_si_note", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIBMSccSiNoteInvalid(t *testing.T) { - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "FINDING" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfigInvalid(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - ExpectError: regexp.MustCompile("Invalid combination of arguments"), - }, - }, - }) -} - -func TestAccIBMSccSiNoteEmpty(t *testing.T) { - providerID := fmt.Sprintf("tf_provider_id_%d", acctest.RandIntRange(10, 100)) - shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) - longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) - kind := "FINDING" - noteID := fmt.Sprintf("tf_note_id_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSccSiNoteDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccSiNoteConfigEmpty(scc_si_account, providerID, shortDescription, longDescription, kind, noteID), - ExpectError: regexp.MustCompile("Invalid combination of arguments"), - }, - }, - }) -} - -func testAccCheckIBMSccSiNoteCardNumericBasic(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - card { - section = "section" - title = "title" - subtitle = "subtitle" - finding_note_names = ["providers/%s/notes/note123"] - elements { - kind = "NUMERIC" - text = "text" - value_type { - finding_note_names = ["providers/%s/notes/note123"] - kind = "FINDING_COUNT" - } - } - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID, providerID, providerID) -} - -func testAccCheckIBMSccSiNoteCardBreakdownBasic(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - card { - section = "section" - title = "title" - subtitle = "subtitle" - finding_note_names = ["providers/%s/notes/note123"] - elements { - kind = "BREAKDOWN" - text = "text" - default_time_range = "3d" - value_types { - finding_note_names = ["providers/%s/notes/note123"] - kind = "FINDING_COUNT" - text = "text" - } - } - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID, providerID, providerID) -} - -func testAccCheckIBMSccSiNoteCardTimeSeriesBasic(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - card { - section = "section" - title = "title" - subtitle = "subtitle" - finding_note_names = ["providers/%s/notes/note123"] - elements { - kind = "TIME_SERIES" - text = "text" - default_interval = "3d" - default_time_range = "3d" - value_types { - finding_note_names = ["providers/%s/notes/note123"] - kind = "FINDING_COUNT" - text = "text" - } - } - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID, providerID, providerID) -} - -func testAccCheckIBMSccSiNoteConfigBasic(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID) -} - -func testAccCheckIBMSccSiNoteConfig(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string, shared string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - related_url { - label = "label" - url = "url" - } - shared = %s - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID, shared) -} - -func testAccCheckIBMSccSiNoteConfigInvalid(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - related_url { - label = "label" - url = "url" - } - finding { - severity = "LOW" - next_steps { - title = "title" - url = "url" - } - } - kpi { - aggregation_type = "SUM" - } - card { - section = "section" - title = "title" - subtitle = "subtitle" - order = 1 - finding_note_names = [ "finding_note_names" ] - badge_text = "badge_text" - badge_image = "badge_image" - elements { - text = "text" - kind = "NUMERIC" - default_time_range = "1d" - value_type { - kind = "KPI" - kpi_note_name = "kpi_note_name" - text = "text" - finding_note_names = [ "finding_note_names" ] - } - value_types { - kind = "KPI" - kpi_note_name = "kpi_note_name" - text = "text" - finding_note_names = [ "finding_note_names" ] - } - default_interval = "default_interval" - } - } - section { - title = "title" - image = "image" - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID) -} - -func testAccCheckIBMSccSiNoteConfigEmpty(accountID string, providerID string, shortDescription string, longDescription string, kind string, noteID string) string { - return fmt.Sprintf(` - - resource "ibm_scc_si_note" "scc_si_note" { - account_id = "%s" - provider_id = "%s" - short_description = "%s" - long_description = "%s" - kind = "%s" - note_id = "%s" - reported_by { - id = "id" - title = "title" - url = "url" - } - related_url { - label = "label" - url = "url" - } - } - `, accountID, providerID, shortDescription, longDescription, kind, noteID) -} - -func testAccCheckIBMSccSiNoteExists(n string, obj findingsv1.APINote) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - findingsClient, err := testAccProvider.Meta().(ClientSession).FindingsV1() - if err != nil { - return err - } - - getNoteOptions := &findingsv1.GetNoteOptions{} - - parts, err := sepIdParts(rs.Primary.ID, "/") - if err != nil { - return err - } - - findingsClient.AccountID = &parts[0] - - getNoteOptions.SetProviderID(parts[1]) - getNoteOptions.SetNoteID(parts[2]) - - apiNote, _, err := findingsClient.GetNote(getNoteOptions) - if err != nil { - return err - } - - obj = *apiNote - return nil - } -} - -func testAccCheckIBMSccSiNoteDestroy(s *terraform.State) error { - findingsClient, err := testAccProvider.Meta().(ClientSession).FindingsV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_scc_si_note" { - continue - } - - getNoteOptions := &findingsv1.GetNoteOptions{} - - parts, err := sepIdParts(rs.Primary.ID, "/") - if err != nil { - return err - } - - findingsClient.AccountID = &parts[0] - - getNoteOptions.SetProviderID(parts[1]) - getNoteOptions.SetNoteID(parts[2]) - - // Try to find the key - _, response, err := findingsClient.GetNote(getNoteOptions) - - if err == nil { - return fmt.Errorf("scc_si_note still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for scc_si_note (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_schematics_action.go b/ibm/resource_ibm_schematics_action.go deleted file mode 100644 index 4c1122426..000000000 --- a/ibm/resource_ibm_schematics_action.go +++ /dev/null @@ -1,1679 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/go-openapi/strfmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -const ( - actionName = "name" -) - -func resourceIBMSchematicsAction() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMSchematicsActionCreate, - ReadContext: resourceIBMSchematicsActionRead, - UpdateContext: resourceIBMSchematicsActionUpdate, - DeleteContext: resourceIBMSchematicsActionDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Action name (unique for an account).", - ValidateFunc: InvokeValidator("ibm_schematics_action", actionName), - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Action description.", - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator("ibm_schematics_action", "location"), - Description: "List of action locations supported by IBM Cloud Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics.", - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Resource-group name for an action. By default, action is created in default resource group.", - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Action tags.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "user_state": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "User defined status of the Schematics object.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "state": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "User defined states * `draft` Object can be modified, and can be used by jobs run by an author, during execution * `live` Object can be modified, and can be used by jobs during execution * `locked` Object cannot be modified, and can be used by jobs during execution * `disable` Object can be modified, and cannot be used by Jobs during execution.", - }, - "set_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Name of the user who set the state of an Object.", - }, - "set_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "When the user who set the state of an Object.", - }, - }, - }, - }, - "source_readme_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "URL of the `README` file, for the source.", - }, - "source": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Source of templates, playbooks, or controls.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "source_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Type of source for the Template.", - }, - "git": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Connection details to Git source.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "git_repo_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "URL to the GIT Repo that can be used to clone the template.", - ValidateFunc: validation.IsURLWithHTTPorHTTPS, - }, - "git_token": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Personal Access Token to connect to Git URLs.", - }, - "git_repo_folder": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the folder in the Git Repo, that contains the template.", - }, - "git_release": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the release tag, used to fetch the Git Repo.", - }, - "git_branch": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the branch, used to fetch the Git Repo.", - }, - }, - }, - }, - }, - }, - }, - "source_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator("ibm_schematics_action", "source_type"), - Description: "Type of source for the Template.", - }, - "command_parameter": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Schematics job command parameter (playbook-name, capsule-name or flow-name).", - }, - "bastion": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Complete target details with the user inputs and the system generated data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target name.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target type (`cluster`, `vsi`, `icd`, `vpc`).", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target description.", - }, - "resource_query": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Resource selection query string.", - }, - "credential_ref": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Override credential for each resource. Reference to credentials values, used by all the resources.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Target ID.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Targets creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who created the targets.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Targets updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "E-mail address of user who updated the targets.", - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - "resource_ids": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "Array of the resource IDs.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "targets_ini": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", - }, - "credentials": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "credentials of the Action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "action_inputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Input variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "action_outputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Output variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "settings": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Environment variables for an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "trigger_record_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "ID to the trigger.", - }, - "state": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Computed state of an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "status_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Status of automation (workspace or action).", - }, - "status_job_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Job id reference for this status.", - }, - "status_message": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Automation status message - to be displayed along with the status_code.", - }, - }, - }, - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - "x_github_token": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action Cloud Resource Name.", - }, - "account": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action account ID.", - }, - "source_created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action Playbook Source creation time.", - }, - "source_created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who created the Action Playbook Source.", - }, - "source_updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The action playbook updation time.", - }, - "source_updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of user who updated the action playbook source.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who created an action.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Action updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who updated an action.", - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Name of the namespace.", - }, - "playbook_names": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Playbook names retrieved from the respository.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - } -} - -func resourceIBMSchematicsActionValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "location", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "eu-de, eu-gb, us-east, us-south", - }, - ValidateSchema{ - Identifier: "source_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "external_scm, git_hub, git_hub_enterprise, git_lab, ibm_cloud_catalog, ibm_git_lab, local", - }, - ValidateSchema{ - Identifier: actionName, - ValidateFunctionIdentifier: StringLenBetween, - Type: TypeString, - MinValueLength: 1, - MaxValueLength: 65, - Optional: true, - }) - - resourceValidator := ResourceValidator{ResourceName: "ibm_schematics_action", Schema: validateSchema} - return &resourceValidator -} - -func resourceIBMSchematicsActionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - createActionOptions := &schematicsv1.CreateActionOptions{} - - if _, ok := d.GetOk("name"); ok { - createActionOptions.SetName(d.Get("name").(string)) - } - if _, ok := d.GetOk("description"); ok { - createActionOptions.SetDescription(d.Get("description").(string)) - } - if _, ok := d.GetOk("location"); ok { - createActionOptions.SetLocation(d.Get("location").(string)) - } - if _, ok := d.GetOk("resource_group"); ok { - createActionOptions.SetResourceGroup(d.Get("resource_group").(string)) - } - if _, ok := d.GetOk("tags"); ok { - createActionOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - } - if _, ok := d.GetOk("user_state"); ok { - userStateAttr := d.Get("user_state").([]interface{}) - if len(userStateAttr) > 0 { - userState := resourceIBMSchematicsActionMapToUserState(d.Get("user_state.0").(map[string]interface{})) - createActionOptions.SetUserState(&userState) - } - } - if _, ok := d.GetOk("source_readme_url"); ok { - createActionOptions.SetSourceReadmeURL(d.Get("source_readme_url").(string)) - } - if _, ok := d.GetOk("source"); ok { - sourceAttr := d.Get("source").([]interface{}) - if len(sourceAttr) > 0 { - source := resourceIBMSchematicsActionMapToExternalSource(d.Get("source.0").(map[string]interface{})) - createActionOptions.SetSource(&source) - } - } - if _, ok := d.GetOk("source_type"); ok { - createActionOptions.SetSourceType(d.Get("source_type").(string)) - } - if _, ok := d.GetOk("command_parameter"); ok { - createActionOptions.SetCommandParameter(d.Get("command_parameter").(string)) - } - if _, ok := d.GetOk("bastion"); ok { - bastionAttr := d.Get("bastion").([]interface{}) - if len(bastionAttr) > 0 { - bastion := resourceIBMSchematicsActionMapToTargetResourceset(d.Get("bastion.0").(map[string]interface{})) - createActionOptions.SetBastion(&bastion) - } - } - if _, ok := d.GetOk("targets_ini"); ok { - createActionOptions.SetTargetsIni(d.Get("targets_ini").(string)) - } - if _, ok := d.GetOk("credentials"); ok { - var credentials []schematicsv1.VariableData - for _, e := range d.Get("credentials").([]interface{}) { - value := e.(map[string]interface{}) - credentialsItem := resourceIBMSchematicsActionMapToVariableData(value) - credentials = append(credentials, credentialsItem) - } - createActionOptions.SetCredentials(credentials) - } - if _, ok := d.GetOk("action_inputs"); ok { - var inputs []schematicsv1.VariableData - for _, e := range d.Get("action_inputs").([]interface{}) { - value := e.(map[string]interface{}) - inputsItem := resourceIBMSchematicsActionMapToVariableData(value) - inputs = append(inputs, inputsItem) - } - createActionOptions.SetInputs(inputs) - } - if _, ok := d.GetOk("action_outputs"); ok { - var outputs []schematicsv1.VariableData - for _, e := range d.Get("action_outputs").([]interface{}) { - value := e.(map[string]interface{}) - outputsItem := resourceIBMSchematicsActionMapToVariableData(value) - outputs = append(outputs, outputsItem) - } - createActionOptions.SetOutputs(outputs) - } - if _, ok := d.GetOk("settings"); ok { - var settings []schematicsv1.VariableData - for _, e := range d.Get("settings").([]interface{}) { - value := e.(map[string]interface{}) - settingsItem := resourceIBMSchematicsActionMapToVariableData(value) - settings = append(settings, settingsItem) - } - createActionOptions.SetSettings(settings) - } - if _, ok := d.GetOk("trigger_record_id"); ok { - createActionOptions.SetTriggerRecordID(d.Get("trigger_record_id").(string)) - } - if _, ok := d.GetOk("state"); ok { - stateAttr := d.Get("state").([]interface{}) - if len(stateAttr) > 0 { - state := resourceIBMSchematicsActionMapToActionState(d.Get("state.0").(map[string]interface{})) - createActionOptions.SetState(&state) - } - } - if _, ok := d.GetOk("sys_lock"); ok { - sysLockAttr := d.Get("sys_lock").([]interface{}) - if len(sysLockAttr) > 0 { - sysLock := resourceIBMSchematicsActionMapToSystemLock(d.Get("sys_lock.0").(map[string]interface{})) - createActionOptions.SetSysLock(&sysLock) - } - } - if _, ok := d.GetOk("x_github_token"); ok { - createActionOptions.SetXGithubToken(d.Get("x_github_token").(string)) - } - - action, response, err := schematicsClient.CreateActionWithContext(context, createActionOptions) - if err != nil { - log.Printf("[DEBUG] CreateActionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*action.ID) - - return resourceIBMSchematicsActionRead(context, d, meta) -} - -func resourceIBMSchematicsActionMapToUserState(userStateMap map[string]interface{}) schematicsv1.UserState { - userState := schematicsv1.UserState{} - - if userStateMap["state"] != nil { - userState.State = core.StringPtr(userStateMap["state"].(string)) - } - if userStateMap["set_by"] != nil { - userState.SetBy = core.StringPtr(userStateMap["set_by"].(string)) - } - if userStateMap["set_at"] != nil { - setAt, err := strfmt.ParseDateTime(userStateMap["set_at"].(string)) - if err != nil { - userState.SetAt = &setAt - } - } - - return userState -} - -func resourceIBMSchematicsActionMapToExternalSource(externalSourceMap map[string]interface{}) schematicsv1.ExternalSource { - externalSource := schematicsv1.ExternalSource{} - - externalSource.SourceType = core.StringPtr(externalSourceMap["source_type"].(string)) - if externalSourceMap["git"] != nil { - externalSourceGit := resourceIBMSchematicsActionMapToExternalSourceGit(externalSourceMap["git"].([]interface{})[0].(map[string]interface{})) - externalSource.Git = &externalSourceGit - } - - return externalSource -} - -func resourceIBMSchematicsActionMapToExternalSourceGit(externalSourceGitMap map[string]interface{}) schematicsv1.ExternalSourceGit { - externalSourceGit := schematicsv1.ExternalSourceGit{} - - if externalSourceGitMap["git_repo_url"] != nil { - externalSourceGit.GitRepoURL = core.StringPtr(externalSourceGitMap["git_repo_url"].(string)) - } - if externalSourceGitMap["git_token"] != nil { - externalSourceGit.GitToken = core.StringPtr(externalSourceGitMap["git_token"].(string)) - } - if externalSourceGitMap["git_repo_folder"] != nil { - externalSourceGit.GitRepoFolder = core.StringPtr(externalSourceGitMap["git_repo_folder"].(string)) - } - if externalSourceGitMap["git_release"] != nil { - externalSourceGit.GitRelease = core.StringPtr(externalSourceGitMap["git_release"].(string)) - } - if externalSourceGitMap["git_branch"] != nil { - externalSourceGit.GitBranch = core.StringPtr(externalSourceGitMap["git_branch"].(string)) - } - - return externalSourceGit -} - -func resourceIBMSchematicsActionMapToTargetResourceset(targetResourcesetMap map[string]interface{}) schematicsv1.TargetResourceset { - targetResourceset := schematicsv1.TargetResourceset{} - - if targetResourcesetMap["name"] != nil { - targetResourceset.Name = core.StringPtr(targetResourcesetMap["name"].(string)) - } - if targetResourcesetMap["type"] != nil { - targetResourceset.Type = core.StringPtr(targetResourcesetMap["type"].(string)) - } - if targetResourcesetMap["description"] != nil { - targetResourceset.Description = core.StringPtr(targetResourcesetMap["description"].(string)) - } - if targetResourcesetMap["resource_query"] != nil { - targetResourceset.ResourceQuery = core.StringPtr(targetResourcesetMap["resource_query"].(string)) - } - if targetResourcesetMap["credential_ref"] != nil { - targetResourceset.CredentialRef = core.StringPtr(targetResourcesetMap["credential_ref"].(string)) - } - if targetResourcesetMap["id"] != nil { - targetResourceset.ID = core.StringPtr(targetResourcesetMap["id"].(string)) - } - if targetResourcesetMap["created_at"] != nil { - createdAt, err := strfmt.ParseDateTime(targetResourcesetMap["created_at"].(string)) - if err != nil { - targetResourceset.CreatedAt = &createdAt - } - } - if targetResourcesetMap["created_by"] != nil { - targetResourceset.CreatedBy = core.StringPtr(targetResourcesetMap["created_by"].(string)) - } - if targetResourcesetMap["updated_at"] != nil { - updatedAt, err := strfmt.ParseDateTime(targetResourcesetMap["updated_at"].(string)) - if err != nil { - targetResourceset.CreatedAt = &updatedAt - } - } - if targetResourcesetMap["updated_by"] != nil { - targetResourceset.UpdatedBy = core.StringPtr(targetResourcesetMap["updated_by"].(string)) - } - if targetResourcesetMap["sys_lock"] != nil && len(targetResourcesetMap["sys_lock"].([]interface{})) != 0 { - sysLock := resourceIBMSchematicsActionMapToSystemLock(targetResourcesetMap["sys_lock"].([]interface{})[0].(map[string]interface{})) - targetResourceset.SysLock = &sysLock - } - if targetResourcesetMap["resource_ids"] != nil { - resourceIds := []string{} - for _, resourceIdsItem := range targetResourcesetMap["resource_ids"].([]interface{}) { - resourceIds = append(resourceIds, resourceIdsItem.(string)) - } - targetResourceset.ResourceIds = resourceIds - } - - return targetResourceset -} - -func resourceIBMSchematicsActionMapToSystemLock(systemLockMap map[string]interface{}) schematicsv1.SystemLock { - systemLock := schematicsv1.SystemLock{} - - if systemLockMap["sys_locked"] != nil { - systemLock.SysLocked = core.BoolPtr(systemLockMap["sys_locked"].(bool)) - } - if systemLockMap["sys_locked_by"] != nil { - systemLock.SysLockedBy = core.StringPtr(systemLockMap["sys_locked_by"].(string)) - } - if systemLockMap["sys_locked_at"] != nil { - sysLockedAt, err := strfmt.ParseDateTime(systemLockMap["sys_locked_at"].(string)) - if err != nil { - systemLock.SysLockedAt = &sysLockedAt - } - } - - return systemLock -} - -func resourceIBMSchematicsActionMapToVariableData(variableDataMap map[string]interface{}) schematicsv1.VariableData { - variableData := schematicsv1.VariableData{} - - if variableDataMap["name"] != nil { - variableData.Name = core.StringPtr(variableDataMap["name"].(string)) - } - if variableDataMap["value"] != nil { - variableData.Value = core.StringPtr(variableDataMap["value"].(string)) - } - if variableDataMap["metadata"] != nil && len(variableDataMap["metadata"].([]interface{})) != 0 { - variableMetaData := resourceIBMSchematicsJobMapToVariableMetadata(variableDataMap["metadata"].([]interface{})[0].(map[string]interface{})) - variableData.Metadata = &variableMetaData - } - if variableDataMap["link"] != nil { - variableData.Link = core.StringPtr(variableDataMap["link"].(string)) - } - - return variableData -} - -func resourceIBMSchematicsActionMapToVariableMetadata(variableMetadataMap map[string]interface{}) schematicsv1.VariableMetadata { - variableMetadata := schematicsv1.VariableMetadata{} - - if variableMetadataMap["type"] != nil { - variableMetadata.Type = core.StringPtr(variableMetadataMap["type"].(string)) - } - if variableMetadataMap["aliases"] != nil { - aliases := []string{} - for _, aliasesItem := range variableMetadataMap["aliases"].([]interface{}) { - aliases = append(aliases, aliasesItem.(string)) - } - variableMetadata.Aliases = aliases - } - if variableMetadataMap["description"] != nil { - variableMetadata.Description = core.StringPtr(variableMetadataMap["description"].(string)) - } - if variableMetadataMap["default_value"] != nil { - variableMetadata.DefaultValue = core.StringPtr(variableMetadataMap["default_value"].(string)) - } - if variableMetadataMap["secure"] != nil { - variableMetadata.Secure = core.BoolPtr(variableMetadataMap["secure"].(bool)) - } - if variableMetadataMap["immutable"] != nil { - variableMetadata.Immutable = core.BoolPtr(variableMetadataMap["immutable"].(bool)) - } - if variableMetadataMap["hidden"] != nil { - variableMetadata.Hidden = core.BoolPtr(variableMetadataMap["hidden"].(bool)) - } - if variableMetadataMap["options"] != nil { - options := []string{} - for _, optionsItem := range variableMetadataMap["options"].([]interface{}) { - options = append(options, optionsItem.(string)) - } - variableMetadata.Options = options - } - if variableMetadataMap["min_value"] != nil { - variableMetadata.MinValue = core.Int64Ptr(int64(variableMetadataMap["min_value"].(int))) - } - if variableMetadataMap["max_value"] != nil { - variableMetadata.MaxValue = core.Int64Ptr(int64(variableMetadataMap["max_value"].(int))) - } - if variableMetadataMap["min_length"] != nil { - variableMetadata.MinLength = core.Int64Ptr(int64(variableMetadataMap["min_length"].(int))) - } - if variableMetadataMap["max_length"] != nil { - variableMetadata.MaxLength = core.Int64Ptr(int64(variableMetadataMap["max_length"].(int))) - } - if variableMetadataMap["matches"] != nil { - variableMetadata.Matches = core.StringPtr(variableMetadataMap["matches"].(string)) - } - if variableMetadataMap["position"] != nil { - variableMetadata.Position = core.Int64Ptr(int64(variableMetadataMap["position"].(int))) - } - if variableMetadataMap["group_by"] != nil { - variableMetadata.GroupBy = core.StringPtr(variableMetadataMap["group_by"].(string)) - } - if variableMetadataMap["source"] != nil { - variableMetadata.Source = core.StringPtr(variableMetadataMap["source"].(string)) - } - - return variableMetadata -} - -func resourceIBMSchematicsActionMapToActionState(actionStateMap map[string]interface{}) schematicsv1.ActionState { - actionState := schematicsv1.ActionState{} - - if actionStateMap["status_code"] != nil { - actionState.StatusCode = core.StringPtr(actionStateMap["status_code"].(string)) - } - if actionStateMap["status_job_id"] != nil { - actionState.StatusJobID = core.StringPtr(actionStateMap["status_job_id"].(string)) - } - if actionStateMap["status_message"] != nil { - actionState.StatusMessage = core.StringPtr(actionStateMap["status_message"].(string)) - } - - return actionState -} - -func resourceIBMSchematicsActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getActionOptions := &schematicsv1.GetActionOptions{} - - getActionOptions.SetActionID(d.Id()) - - action, response, err := schematicsClient.GetActionWithContext(context, getActionOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetActionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - if err = d.Set("name", action.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", action.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("location", action.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if err = d.Set("resource_group", action.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - if action.Tags != nil { - if err = d.Set("tags", action.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - } - if action.UserState != nil { - userStateMap := resourceIBMSchematicsActionUserStateToMap(*action.UserState) - if err = d.Set("user_state", []map[string]interface{}{userStateMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting user_state: %s", err)) - } - } - if err = d.Set("source_readme_url", action.SourceReadmeURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_readme_url: %s", err)) - } - if _, ok := d.GetOk("source"); ok { - if action.Source != nil { - sourceMap := resourceIBMSchematicsActionExternalSourceToMap(*action.Source) - if err = d.Set("source", []map[string]interface{}{sourceMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source: %s", err)) - } - } - } - if err = d.Set("source_type", action.SourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_type: %s", err)) - } - if err = d.Set("command_parameter", action.CommandParameter); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_parameter: %s", err)) - } - if _, ok := d.GetOk("bastion"); ok { - if action.Bastion != nil { - bastionMap := resourceIBMSchematicsActionTargetResourcesetToMap(*action.Bastion) - if err = d.Set("bastion", []map[string]interface{}{bastionMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting bastion: %s", err)) - } - } - } - if err = d.Set("targets_ini", action.TargetsIni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting targets_ini: %s", err)) - } - if action.Credentials != nil { - credentials := []map[string]interface{}{} - for _, credentialsItem := range action.Credentials { - credentialsItemMap := resourceIBMSchematicsActionVariableDataToMap(credentialsItem) - credentials = append(credentials, credentialsItemMap) - } - if err = d.Set("credentials", credentials); err != nil { - return diag.FromErr(fmt.Errorf("Error setting credentials: %s", err)) - } - } - if action.Inputs != nil { - inputs := []map[string]interface{}{} - for _, inputsItem := range action.Inputs { - inputsItemMap := resourceIBMSchematicsActionVariableDataToMap(inputsItem) - inputs = append(inputs, inputsItemMap) - } - if err = d.Set("action_inputs", inputs); err != nil { - return diag.FromErr(fmt.Errorf("Error setting action_inputs: %s", err)) - } - } - if action.Outputs != nil { - outputs := []map[string]interface{}{} - for _, outputsItem := range action.Outputs { - outputsItemMap := resourceIBMSchematicsActionVariableDataToMap(outputsItem) - outputs = append(outputs, outputsItemMap) - } - if err = d.Set("action_outputs", outputs); err != nil { - return diag.FromErr(fmt.Errorf("Error setting action_outputs: %s", err)) - } - } - if action.Settings != nil { - settings := []map[string]interface{}{} - for _, settingsItem := range action.Settings { - settingsItemMap := resourceIBMSchematicsActionVariableDataToMap(settingsItem) - settings = append(settings, settingsItemMap) - } - if err = d.Set("settings", settings); err != nil { - return diag.FromErr(fmt.Errorf("Error setting settings: %s", err)) - } - } - if err = d.Set("trigger_record_id", action.TriggerRecordID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting trigger_record_id: %s", err)) - } - if action.State != nil { - stateMap := resourceIBMSchematicsActionActionStateToMap(*action.State) - if err = d.Set("state", []map[string]interface{}{stateMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) - } - } - if action.SysLock != nil { - sysLockMap := resourceIBMSchematicsActionSystemLockToMap(*action.SysLock) - if err = d.Set("sys_lock", []map[string]interface{}{sysLockMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting sys_lock: %s", err)) - } - } - if err = d.Set("crn", action.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) - } - if err = d.Set("account", action.Account); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account: %s", err)) - } - if action.SourceCreatedAt != nil { - if err = d.Set("source_created_at", action.SourceCreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_created_at: %s", err)) - } - } - if err = d.Set("source_created_by", action.SourceCreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_created_by: %s", err)) - } - if action.SourceUpdatedAt != nil { - if err = d.Set("source_updated_at", action.SourceUpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_updated_at: %s", err)) - } - } - if err = d.Set("source_updated_by", action.SourceUpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_updated_by: %s", err)) - } - if action.CreatedAt != nil { - if err = d.Set("created_at", action.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - } - if err = d.Set("created_by", action.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) - } - if action.UpdatedAt != nil { - if err = d.Set("updated_at", action.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - } - if err = d.Set("updated_by", action.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) - } - if err = d.Set("namespace", action.Namespace); err != nil { - return diag.FromErr(fmt.Errorf("Error setting namespace: %s", err)) - } - if action.PlaybookNames != nil && len(action.PlaybookNames) > 0 { - if err = d.Set("playbook_names", action.PlaybookNames); err != nil { - return diag.FromErr(fmt.Errorf("Error setting playbook_names: %s", err)) - } - } else { - d.Set("playbook_names", []string{}) - } - - return nil -} - -func resourceIBMSchematicsActionUserStateToMap(userState schematicsv1.UserState) map[string]interface{} { - userStateMap := map[string]interface{}{} - - userStateMap["state"] = userState.State - userStateMap["set_by"] = userState.SetBy - userStateMap["set_at"] = userState.SetAt.String() - - return userStateMap -} - -func resourceIBMSchematicsActionExternalSourceToMap(externalSource schematicsv1.ExternalSource) map[string]interface{} { - externalSourceMap := map[string]interface{}{} - - externalSourceMap["source_type"] = externalSource.SourceType - if externalSource.Git != nil { - GitMap := resourceIBMSchematicsActionExternalSourceGitToMap(*externalSource.Git) - externalSourceMap["git"] = []map[string]interface{}{GitMap} - } - - return externalSourceMap -} - -func resourceIBMSchematicsActionExternalSourceGitToMap(externalSourceGit schematicsv1.ExternalSourceGit) map[string]interface{} { - externalSourceGitMap := map[string]interface{}{} - - externalSourceGitMap["git_repo_url"] = externalSourceGit.GitRepoURL - externalSourceGitMap["git_token"] = externalSourceGit.GitToken - externalSourceGitMap["git_repo_folder"] = externalSourceGit.GitRepoFolder - externalSourceGitMap["git_release"] = externalSourceGit.GitRelease - externalSourceGitMap["git_branch"] = externalSourceGit.GitBranch - - return externalSourceGitMap -} - -func resourceIBMSchematicsActionTargetResourcesetToMap(targetResourceset schematicsv1.TargetResourceset) map[string]interface{} { - targetResourcesetMap := map[string]interface{}{} - - targetResourcesetMap["name"] = targetResourceset.Name - targetResourcesetMap["type"] = targetResourceset.Type - targetResourcesetMap["description"] = targetResourceset.Description - targetResourcesetMap["resource_query"] = targetResourceset.ResourceQuery - targetResourcesetMap["credential_ref"] = targetResourceset.CredentialRef - targetResourcesetMap["id"] = targetResourceset.ID - targetResourcesetMap["created_at"] = targetResourceset.CreatedAt.String() - targetResourcesetMap["created_by"] = targetResourceset.CreatedBy - targetResourcesetMap["updated_at"] = targetResourceset.UpdatedAt.String() - targetResourcesetMap["updated_by"] = targetResourceset.UpdatedBy - if targetResourceset.SysLock != nil { - SysLockMap := resourceIBMSchematicsActionSystemLockToMap(*targetResourceset.SysLock) - targetResourcesetMap["sys_lock"] = []map[string]interface{}{SysLockMap} - } - if targetResourceset.ResourceIds != nil { - targetResourcesetMap["resource_ids"] = targetResourceset.ResourceIds - } - - return targetResourcesetMap -} - -func resourceIBMSchematicsActionSystemLockToMap(systemLock schematicsv1.SystemLock) map[string]interface{} { - systemLockMap := map[string]interface{}{} - - systemLockMap["sys_locked"] = systemLock.SysLocked - systemLockMap["sys_locked_by"] = systemLock.SysLockedBy - systemLockMap["sys_locked_at"] = systemLock.SysLockedAt.String() - - return systemLockMap -} - -func resourceIBMSchematicsActionVariableDataToMap(variableData schematicsv1.VariableData) map[string]interface{} { - variableDataMap := map[string]interface{}{} - - variableDataMap["name"] = variableData.Name - variableDataMap["value"] = variableData.Value - if variableData.Metadata != nil { - MetadataMap := resourceIBMSchematicsActionVariableMetadataToMap(*variableData.Metadata) - variableDataMap["metadata"] = []map[string]interface{}{MetadataMap} - } - variableDataMap["link"] = variableData.Link - - return variableDataMap -} - -func resourceIBMSchematicsActionVariableMetadataToMap(variableMetadata schematicsv1.VariableMetadata) map[string]interface{} { - variableMetadataMap := map[string]interface{}{} - - variableMetadataMap["type"] = variableMetadata.Type - if variableMetadata.Aliases != nil { - variableMetadataMap["aliases"] = variableMetadata.Aliases - } - variableMetadataMap["description"] = variableMetadata.Description - variableMetadataMap["default_value"] = variableMetadata.DefaultValue - variableMetadataMap["secure"] = variableMetadata.Secure - variableMetadataMap["immutable"] = variableMetadata.Immutable - variableMetadataMap["hidden"] = variableMetadata.Hidden - if variableMetadata.Options != nil { - variableMetadataMap["options"] = variableMetadata.Options - } - variableMetadataMap["min_value"] = intValue(variableMetadata.MinValue) - variableMetadataMap["max_value"] = intValue(variableMetadata.MaxValue) - variableMetadataMap["min_length"] = intValue(variableMetadata.MinLength) - variableMetadataMap["max_length"] = intValue(variableMetadata.MaxLength) - variableMetadataMap["matches"] = variableMetadata.Matches - variableMetadataMap["position"] = intValue(variableMetadata.Position) - variableMetadataMap["group_by"] = variableMetadata.GroupBy - variableMetadataMap["source"] = variableMetadata.Source - - return variableMetadataMap -} - -func resourceIBMSchematicsActionActionStateToMap(actionState schematicsv1.ActionState) map[string]interface{} { - actionStateMap := map[string]interface{}{} - - actionStateMap["status_code"] = actionState.StatusCode - actionStateMap["status_job_id"] = actionState.StatusJobID - actionStateMap["status_message"] = actionState.StatusMessage - - return actionStateMap -} - -func resourceIBMSchematicsActionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - updateActionOptions := &schematicsv1.UpdateActionOptions{} - - updateActionOptions.SetActionID(d.Id()) - - hasChange := false - - if d.HasChange("name") { - updateActionOptions.SetName(d.Get("name").(string)) - hasChange = true - } - if d.HasChange("description") { - updateActionOptions.SetDescription(d.Get("description").(string)) - hasChange = true - } - if d.HasChange("location") { - updateActionOptions.SetLocation(d.Get("location").(string)) - hasChange = true - } - if d.HasChange("resource_group") { - updateActionOptions.SetResourceGroup(d.Get("resource_group").(string)) - hasChange = true - } - if d.HasChange("tags") { - updateActionOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - hasChange = true - } - if d.HasChange("user_state") { - userStateAttr := d.Get("user_state").([]interface{}) - if len(userStateAttr) > 0 { - userState := resourceIBMSchematicsActionMapToUserState(d.Get("user_state.0").(map[string]interface{})) - updateActionOptions.SetUserState(&userState) - hasChange = true - } - } - if d.HasChange("source_readme_url") { - updateActionOptions.SetSourceReadmeURL(d.Get("source_readme_url").(string)) - hasChange = true - } - if d.HasChange("source") { - sourceAttr := d.Get("source").([]interface{}) - if len(sourceAttr) > 0 { - source := resourceIBMSchematicsActionMapToExternalSource(d.Get("source.0").(map[string]interface{})) - updateActionOptions.SetSource(&source) - hasChange = true - } - } - if d.HasChange("source_type") { - updateActionOptions.SetSourceType(d.Get("source_type").(string)) - hasChange = true - } - if d.HasChange("command_parameter") { - updateActionOptions.SetCommandParameter(d.Get("command_parameter").(string)) - hasChange = true - } - if d.HasChange("bastion") { - bastionAttr := d.Get("bastion").([]interface{}) - if len(bastionAttr) > 0 { - bastion := resourceIBMSchematicsActionMapToTargetResourceset(d.Get("bastion.0").(map[string]interface{})) - updateActionOptions.SetBastion(&bastion) - hasChange = true - } - } - if d.HasChange("targets_ini") { - updateActionOptions.SetTargetsIni(d.Get("targets_ini").(string)) - hasChange = true - } - if d.HasChange("credentials") { - var credentials []schematicsv1.VariableData - for _, e := range d.Get("credentials").([]interface{}) { - value := e.(map[string]interface{}) - credentialsItem := resourceIBMSchematicsActionMapToVariableData(value) - credentials = append(credentials, credentialsItem) - } - updateActionOptions.SetCredentials(credentials) - hasChange = true - } - if d.HasChange("action_inputs") { - var inputs []schematicsv1.VariableData - for _, e := range d.Get("action_inputs").([]interface{}) { - value := e.(map[string]interface{}) - inputsItem := resourceIBMSchematicsActionMapToVariableData(value) - inputs = append(inputs, inputsItem) - } - updateActionOptions.SetInputs(inputs) - hasChange = true - } - if d.HasChange("action_outputs") { - var outputs []schematicsv1.VariableData - for _, e := range d.Get("action_outputs").([]interface{}) { - value := e.(map[string]interface{}) - outputsItem := resourceIBMSchematicsActionMapToVariableData(value) - outputs = append(outputs, outputsItem) - } - updateActionOptions.SetOutputs(outputs) - hasChange = true - } - if d.HasChange("settings") { - var settings []schematicsv1.VariableData - for _, e := range d.Get("settings").([]interface{}) { - value := e.(map[string]interface{}) - settingsItem := resourceIBMSchematicsActionMapToVariableData(value) - settings = append(settings, settingsItem) - } - updateActionOptions.SetSettings(settings) - hasChange = true - } - if d.HasChange("trigger_record_id") { - updateActionOptions.SetTriggerRecordID(d.Get("trigger_record_id").(string)) - hasChange = true - } - if d.HasChange("state") { - stateAttr := d.Get("state").([]interface{}) - if len(stateAttr) > 0 { - state := resourceIBMSchematicsActionMapToActionState(d.Get("state.0").(map[string]interface{})) - updateActionOptions.SetState(&state) - hasChange = true - } - } - if d.HasChange("sys_lock") { - sysLockAttr := d.Get("sys_lock").([]interface{}) - if len(sysLockAttr) > 0 { - sysLock := resourceIBMSchematicsActionMapToSystemLock(d.Get("sys_lock.0").(map[string]interface{})) - updateActionOptions.SetSysLock(&sysLock) - hasChange = true - } - } - - if hasChange { - _, response, err := schematicsClient.UpdateActionWithContext(context, updateActionOptions) - if err != nil { - log.Printf("[DEBUG] UpdateActionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - } - - return resourceIBMSchematicsActionRead(context, d, meta) -} - -func resourceIBMSchematicsActionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - deleteActionOptions := &schematicsv1.DeleteActionOptions{} - - deleteActionOptions.SetActionID(d.Id()) - - response, err := schematicsClient.DeleteActionWithContext(context, deleteActionOptions) - if err != nil { - log.Printf("[DEBUG] DeleteActionWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_schematics_job.go b/ibm/resource_ibm_schematics_job.go deleted file mode 100644 index ae4cd8463..000000000 --- a/ibm/resource_ibm_schematics_job.go +++ /dev/null @@ -1,2050 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/go-openapi/strfmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func resourceIBMSchematicsJob() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMSchematicsJobCreate, - ReadContext: resourceIBMSchematicsJobRead, - UpdateContext: resourceIBMSchematicsJobUpdate, - DeleteContext: resourceIBMSchematicsJobDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "command_object": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_schematics_job", "command_object"), - Description: "Name of the Schematics automation resource.", - }, - "command_object_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Job command object ID (`workspace-id, action-id or control-id`).", - }, - "command_name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ValidateFunc: InvokeValidator("ibm_schematics_job", "command_name"), - Description: "Schematics job command name.", - }, - "command_parameter": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Schematics job command parameter (`playbook-name, capsule-name or flow-name`).", - }, - "command_options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Command line options for the command.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "job_inputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Job inputs used by an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "job_env_settings": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Environment variables used by the job while performing an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User defined tags, while running the job.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator("ibm_schematics_job", "location"), - Description: "List of action locations supported by IBM Cloud Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics.", - }, - "status": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Job Status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_job_status": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Action Job Status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Action name.", - }, - "status_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Status of the jobs.", - }, - "status_message": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Action job status message to be displayed along with the `action_status_code`.", - }, - "bastion_status_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Status of the resources.", - }, - "bastion_status_message": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Bastion status message to be displayed along with the `bastion_status_code`.", - }, - "targets_status_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Status of the resources.", - }, - "targets_status_message": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Aggregated status message for all target resources, to be displayed along with the `targets_status_code`.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Job status updation timestamp.", - }, - }, - }, - }, - }, - }, - }, - "data": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Job data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "job_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Type of the job.", - }, - "action_job_data": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Action Job data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Flow name.", - }, - "inputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Input variables data used by an action job.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "outputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Output variables data from an action job.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "settings": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Environment variables used by all the templates in an action.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the variable.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Value for the variable or reference to the value.", - }, - "metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "User editable metadata for the variables.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of the variable.", - }, - "aliases": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of aliases for the variable name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Description of the meta data.", - }, - "default_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Default value for the variable, if the override value is not specified.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable secure or sensitive ?.", - }, - "immutable": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the variable readonly ?.", - }, - "hidden": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If true, the variable will not be displayed on UI or CLI.", - }, - "options": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "min_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum value of the variable. Applicable for integer type.", - }, - "max_value": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum value of the variable. Applicable for integer type.", - }, - "min_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Minimum length of the variable value. Applicable for string type.", - }, - "max_length": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Maximum length of the variable value. Applicable for string type.", - }, - "matches": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Regex for the variable value.", - }, - "position": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Relative position of this variable in a list.", - }, - "group_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Display name of the group this variable belongs to.", - }, - "source": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Source of this meta-data.", - }, - }, - }, - }, - "link": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Reference link to the variable value By default the expression will point to self.value.", - }, - }, - }, - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Job status updation timestamp.", - }, - }, - }, - }, - }, - }, - }, - "bastion": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Complete target details with the user inputs and the system generated data.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target name.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target type (`cluster`, `vsi`, `icd`, `vpc`).", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Target description.", - }, - "resource_query": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Resource selection query string.", - }, - "credential_ref": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Override credential for each resource. Reference to credentials values, used by all the resources.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Target ID.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Targets creation time.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "E-mail address of the user who created the targets.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Targets updation time.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "E-mail address of user who updated the targets.", - }, - "sys_lock": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "System lock status.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "sys_locked": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Is the Workspace locked by the Schematic action ?.", - }, - "sys_locked_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Name of the user who performed the action, that lead to lock the Workspace.", - }, - "sys_locked_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "When the user performed the action that lead to lock the Workspace ?.", - }, - }, - }, - }, - "resource_ids": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "Array of the resource IDs.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "job_log_summary": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "Job log summary record.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "job_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Workspace ID.", - }, - "job_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Type of Job.", - }, - "log_start_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Job log start timestamp.", - }, - "log_analyzed_till": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Job log update timestamp.", - }, - "elapsed_time": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "Job log elapsed time (`log_analyzed_till - log_start_at`).", - }, - "log_errors": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "Job log errors.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "error_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Error code in the Log.", - }, - "error_msg": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Summary error message in the log.", - }, - "error_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of occurrence.", - }, - }, - }, - }, - "repo_download_job": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Repo download Job log summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "scanned_file_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "Number of files scanned.", - }, - "quarantined_file_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "Number of files quarantined.", - }, - "detected_filetype": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Detected template or data file type.", - }, - "inputs_count": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Number of inputs detected.", - }, - "outputs_count": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Number of outputs detected.", - }, - }, - }, - }, - "action_job": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Flow Job log summary.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "number of targets or hosts.", - }, - "task_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "number of tasks in playbook.", - }, - "play_count": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Computed: true, - Description: "number of plays in playbook.", - }, - "recap": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "Recap records.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "target": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of target or host name.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "ok": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of OK.", - }, - "changed": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of changed.", - }, - "failed": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of failed.", - }, - "skipped": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of skipped.", - }, - "unreachable": &schema.Schema{ - Type: schema.TypeFloat, - Optional: true, - Description: "Number of unreachable.", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job name, uniquely derived from the related action.", - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job description derived from the related action.", - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Resource group name derived from the related action.", - }, - "submitted_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job submission time.", - }, - "submitted_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "E-mail address of the user who submitted the job.", - }, - "start_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job start time.", - }, - "end_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job end time.", - }, - "duration": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Duration of job execution, for example, `40 sec`.", - }, - "targets_ini": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", - }, - "log_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job log store URL.", - }, - "state_store_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job state store URL.", - }, - "results_url": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job results store URL.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Job status updation timestamp.", - }, - }, - } -} - -func resourceIBMSchematicsJobValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "command_object", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "action, workspace", - }, - ValidateSchema{ - Identifier: "command_name", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "ansible_playbook_check, ansible_playbook_run, helm_install, helm_list, helm_show, opa_evaluate, terraform_init, terrform_apply, terrform_destroy, terrform_plan, terrform_refresh, terrform_show, terrform_taint, workspace_apply_flow, workspace_custom_flow, workspace_destroy_flow, workspace_init_flow, workspace_plan_flow, workspace_refresh_flow, workspace_show_flow", - }, - ValidateSchema{ - Identifier: "location", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Optional: true, - AllowedValues: "eu-de, eu-gb, us-east, us-south", - }) - - resourceValidator := ResourceValidator{ResourceName: "ibm_schematics_job", Schema: validateSchema} - return &resourceValidator -} - -func resourceIBMSchematicsJobCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - session, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - - iamRefreshToken := session.Config.IAMRefreshToken - - createJobOptions := &schematicsv1.CreateJobOptions{} - createJobOptions.SetRefreshToken(iamRefreshToken) - - if _, ok := d.GetOk("command_object"); ok { - createJobOptions.SetCommandObject(d.Get("command_object").(string)) - } - if _, ok := d.GetOk("command_object_id"); ok { - createJobOptions.SetCommandObjectID(d.Get("command_object_id").(string)) - } - if _, ok := d.GetOk("command_name"); ok { - createJobOptions.SetCommandName(d.Get("command_name").(string)) - } - if _, ok := d.GetOk("command_parameter"); ok { - createJobOptions.SetCommandParameter(d.Get("command_parameter").(string)) - } - if _, ok := d.GetOk("command_options"); ok { - createJobOptions.SetCommandOptions(d.Get("command_options").([]string)) - } - if _, ok := d.GetOk("job_inputs"); ok { - var inputs []schematicsv1.VariableData - for _, e := range d.Get("job_inputs").([]interface{}) { - value := e.(map[string]interface{}) - inputsItem := resourceIBMSchematicsJobMapToVariableData(value) - inputs = append(inputs, inputsItem) - } - createJobOptions.SetInputs(inputs) - } - if _, ok := d.GetOk("job_env_settings"); ok { - var settings []schematicsv1.VariableData - for _, e := range d.Get("job_env_settings").([]interface{}) { - value := e.(map[string]interface{}) - settingsItem := resourceIBMSchematicsJobMapToVariableData(value) - settings = append(settings, settingsItem) - } - createJobOptions.SetSettings(settings) - } - if _, ok := d.GetOk("tags"); ok { - createJobOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - } - if _, ok := d.GetOk("location"); ok { - createJobOptions.SetLocation(d.Get("location").(string)) - } - if _, ok := d.GetOk("status"); ok { - statusAttr := d.Get("status").([]interface{}) - if len(statusAttr) > 0 { - status := resourceIBMSchematicsJobMapToJobStatus(d.Get("status.0").(map[string]interface{})) - createJobOptions.SetStatus(&status) - } - } - if _, ok := d.GetOk("data"); ok { - dataAttr := d.Get("data").([]interface{}) - if len(dataAttr) > 0 { - data := resourceIBMSchematicsJobMapToJobData(d.Get("data.0").(map[string]interface{})) - createJobOptions.SetData(&data) - } - } - if _, ok := d.GetOk("bastion"); ok { - bastionAttr := d.Get("bastion").([]interface{}) - if len(bastionAttr) > 0 { - bastion := resourceIBMSchematicsJobMapToTargetResourceset(d.Get("bastion.0").(map[string]interface{})) - createJobOptions.SetBastion(&bastion) - } - } - if _, ok := d.GetOk("job_log_summary"); ok { - jobLogSummaryAttr := d.Get("job_log_summary").([]interface{}) - if len(jobLogSummaryAttr) > 0 { - logSummary := resourceIBMSchematicsJobMapToJobLogSummary(d.Get("job_log_summary.0").(map[string]interface{})) - createJobOptions.SetLogSummary(&logSummary) - } - } - - job, response, err := schematicsClient.CreateJobWithContext(context, createJobOptions) - if err != nil { - log.Printf("[DEBUG] CreateJobWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*job.ID) - - return resourceIBMSchematicsJobRead(context, d, meta) -} - -func resourceIBMSchematicsJobMapToVariableData(variableDataMap map[string]interface{}) schematicsv1.VariableData { - variableData := schematicsv1.VariableData{} - - if variableDataMap["name"] != nil { - variableData.Name = core.StringPtr(variableDataMap["name"].(string)) - } - if variableDataMap["value"] != nil { - variableData.Value = core.StringPtr(variableDataMap["value"].(string)) - } - if variableDataMap["metadata"] != nil && len(variableDataMap["metadata"].([]interface{})) != 0 { - variableMetaData := resourceIBMSchematicsJobMapToVariableMetadata(variableDataMap["metadata"].([]interface{})[0].(map[string]interface{})) - variableData.Metadata = &variableMetaData - } - if variableDataMap["link"] != nil { - variableData.Link = core.StringPtr(variableDataMap["link"].(string)) - } - - return variableData -} - -func resourceIBMSchematicsJobMapToVariableMetadata(variableMetadataMap map[string]interface{}) schematicsv1.VariableMetadata { - variableMetadata := schematicsv1.VariableMetadata{} - - if variableMetadataMap["type"] != nil { - variableMetadata.Type = core.StringPtr(variableMetadataMap["type"].(string)) - } - if variableMetadataMap["aliases"] != nil { - aliases := []string{} - for _, aliasesItem := range variableMetadataMap["aliases"].([]interface{}) { - aliases = append(aliases, aliasesItem.(string)) - } - variableMetadata.Aliases = aliases - } - if variableMetadataMap["description"] != nil { - variableMetadata.Description = core.StringPtr(variableMetadataMap["description"].(string)) - } - if variableMetadataMap["default_value"] != nil { - variableMetadata.DefaultValue = core.StringPtr(variableMetadataMap["default_value"].(string)) - } - if variableMetadataMap["secure"] != nil { - variableMetadata.Secure = core.BoolPtr(variableMetadataMap["secure"].(bool)) - } - if variableMetadataMap["immutable"] != nil { - variableMetadata.Immutable = core.BoolPtr(variableMetadataMap["immutable"].(bool)) - } - if variableMetadataMap["hidden"] != nil { - variableMetadata.Hidden = core.BoolPtr(variableMetadataMap["hidden"].(bool)) - } - if variableMetadataMap["options"] != nil { - options := []string{} - for _, optionsItem := range variableMetadataMap["options"].([]interface{}) { - options = append(options, optionsItem.(string)) - } - variableMetadata.Options = options - } - if variableMetadataMap["min_value"] != nil { - variableMetadata.MinValue = core.Int64Ptr(int64(variableMetadataMap["min_value"].(int))) - } - if variableMetadataMap["max_value"] != nil { - variableMetadata.MaxValue = core.Int64Ptr(int64(variableMetadataMap["max_value"].(int))) - } - if variableMetadataMap["min_length"] != nil { - variableMetadata.MinLength = core.Int64Ptr(int64(variableMetadataMap["min_length"].(int))) - } - if variableMetadataMap["max_length"] != nil { - variableMetadata.MaxLength = core.Int64Ptr(int64(variableMetadataMap["max_length"].(int))) - } - if variableMetadataMap["matches"] != nil { - variableMetadata.Matches = core.StringPtr(variableMetadataMap["matches"].(string)) - } - if variableMetadataMap["position"] != nil { - variableMetadata.Position = core.Int64Ptr(int64(variableMetadataMap["position"].(int))) - } - if variableMetadataMap["group_by"] != nil { - variableMetadata.GroupBy = core.StringPtr(variableMetadataMap["group_by"].(string)) - } - if variableMetadataMap["source"] != nil { - variableMetadata.Source = core.StringPtr(variableMetadataMap["source"].(string)) - } - - return variableMetadata -} - -func resourceIBMSchematicsJobMapToJobStatus(jobStatusMap map[string]interface{}) schematicsv1.JobStatus { - jobStatus := schematicsv1.JobStatus{} - - if jobStatusMap["action_job_status"] != nil { - actionJobStatus := resourceIBMSchematicsJobMapToJobStatusAction(jobStatusMap["action_job_status"].([]interface{})[0].(map[string]interface{})) - jobStatus.ActionJobStatus = &actionJobStatus - } - - return jobStatus -} - -func resourceIBMSchematicsJobMapToJobStatusAction(jobStatusActionMap map[string]interface{}) schematicsv1.JobStatusAction { - jobStatusAction := schematicsv1.JobStatusAction{} - - if jobStatusActionMap["action_name"] != nil { - jobStatusAction.ActionName = core.StringPtr(jobStatusActionMap["action_name"].(string)) - } - if jobStatusActionMap["status_code"] != nil { - jobStatusAction.StatusCode = core.StringPtr(jobStatusActionMap["status_code"].(string)) - } - if jobStatusActionMap["status_message"] != nil { - jobStatusAction.StatusMessage = core.StringPtr(jobStatusActionMap["status_message"].(string)) - } - if jobStatusActionMap["bastion_status_code"] != nil { - jobStatusAction.BastionStatusCode = core.StringPtr(jobStatusActionMap["bastion_status_code"].(string)) - } - if jobStatusActionMap["bastion_status_message"] != nil { - jobStatusAction.BastionStatusMessage = core.StringPtr(jobStatusActionMap["bastion_status_message"].(string)) - } - if jobStatusActionMap["targets_status_code"] != nil { - jobStatusAction.TargetsStatusCode = core.StringPtr(jobStatusActionMap["targets_status_code"].(string)) - } - if jobStatusActionMap["targets_status_message"] != nil { - jobStatusAction.TargetsStatusMessage = core.StringPtr(jobStatusActionMap["targets_status_message"].(string)) - } - if jobStatusActionMap["updated_at"] != nil { - updatedAt, err := strfmt.ParseDateTime(jobStatusActionMap["updated_at"].(string)) - if err != nil { - jobStatusAction.UpdatedAt = &updatedAt - } - } - - return jobStatusAction -} - -func resourceIBMSchematicsJobMapToJobData(jobDataMap map[string]interface{}) schematicsv1.JobData { - jobData := schematicsv1.JobData{} - - jobData.JobType = core.StringPtr(jobDataMap["job_type"].(string)) - if jobDataMap["action_job_data"] != nil { - actionJobData := resourceIBMSchematicsJobMapToJobDataAction(jobDataMap["action_job_data"].([]interface{})[0].(map[string]interface{})) - jobData.ActionJobData = &actionJobData - } - - return jobData -} - -func resourceIBMSchematicsJobMapToJobDataAction(jobDataActionMap map[string]interface{}) schematicsv1.JobDataAction { - jobDataAction := schematicsv1.JobDataAction{} - - if jobDataActionMap["action_name"] != nil { - jobDataAction.ActionName = core.StringPtr(jobDataActionMap["action_name"].(string)) - } - if jobDataActionMap["inputs"] != nil { - inputs := []schematicsv1.VariableData{} - for _, inputsItem := range jobDataActionMap["inputs"].([]interface{}) { - inputsItemModel := resourceIBMSchematicsJobMapToVariableData(inputsItem.(map[string]interface{})) - inputs = append(inputs, inputsItemModel) - } - jobDataAction.Inputs = inputs - } - if jobDataActionMap["outputs"] != nil { - outputs := []schematicsv1.VariableData{} - for _, outputsItem := range jobDataActionMap["outputs"].([]interface{}) { - outputsItemModel := resourceIBMSchematicsJobMapToVariableData(outputsItem.(map[string]interface{})) - outputs = append(outputs, outputsItemModel) - } - jobDataAction.Outputs = outputs - } - if jobDataActionMap["settings"] != nil { - settings := []schematicsv1.VariableData{} - for _, settingsItem := range jobDataActionMap["settings"].([]interface{}) { - settingsItemModel := resourceIBMSchematicsJobMapToVariableData(settingsItem.(map[string]interface{})) - settings = append(settings, settingsItemModel) - } - jobDataAction.Settings = settings - } - if jobDataActionMap["updated_at"] != nil { - - } - - return jobDataAction -} - -func resourceIBMSchematicsJobMapToTargetResourceset(targetResourcesetMap map[string]interface{}) schematicsv1.TargetResourceset { - targetResourceset := schematicsv1.TargetResourceset{} - - if targetResourcesetMap["name"] != nil { - targetResourceset.Name = core.StringPtr(targetResourcesetMap["name"].(string)) - } - if targetResourcesetMap["type"] != nil { - targetResourceset.Type = core.StringPtr(targetResourcesetMap["type"].(string)) - } - if targetResourcesetMap["description"] != nil { - targetResourceset.Description = core.StringPtr(targetResourcesetMap["description"].(string)) - } - if targetResourcesetMap["resource_query"] != nil { - targetResourceset.ResourceQuery = core.StringPtr(targetResourcesetMap["resource_query"].(string)) - } - if targetResourcesetMap["credential_ref"] != nil { - targetResourceset.CredentialRef = core.StringPtr(targetResourcesetMap["credential_ref"].(string)) - } - if targetResourcesetMap["id"] != nil { - targetResourceset.ID = core.StringPtr(targetResourcesetMap["id"].(string)) - } - if targetResourcesetMap["created_at"] != nil { - - } - if targetResourcesetMap["created_by"] != nil { - targetResourceset.CreatedBy = core.StringPtr(targetResourcesetMap["created_by"].(string)) - } - if targetResourcesetMap["updated_at"] != nil { - - } - if targetResourcesetMap["updated_by"] != nil { - targetResourceset.UpdatedBy = core.StringPtr(targetResourcesetMap["updated_by"].(string)) - } - if targetResourcesetMap["sys_lock"] != nil { - sysLock := resourceIBMSchematicsJobMapToSystemLock(targetResourcesetMap["sys_lock"].(map[string]interface{})) - targetResourceset.SysLock = &sysLock - } - if targetResourcesetMap["resource_ids"] != nil { - resourceIds := []string{} - for _, resourceIdsItem := range targetResourcesetMap["resource_ids"].([]interface{}) { - resourceIds = append(resourceIds, resourceIdsItem.(string)) - } - targetResourceset.ResourceIds = resourceIds - } - - return targetResourceset -} - -func resourceIBMSchematicsJobMapToSystemLock(systemLockMap map[string]interface{}) schematicsv1.SystemLock { - systemLock := schematicsv1.SystemLock{} - - if systemLockMap["sys_locked"] != nil { - systemLock.SysLocked = core.BoolPtr(systemLockMap["sys_locked"].(bool)) - } - if systemLockMap["sys_locked_by"] != nil { - systemLock.SysLockedBy = core.StringPtr(systemLockMap["sys_locked_by"].(string)) - } - if systemLockMap["sys_locked_at"] != nil { - - } - - return systemLock -} - -func resourceIBMSchematicsJobMapToJobLogSummary(jobLogSummaryMap map[string]interface{}) schematicsv1.JobLogSummary { - jobLogSummary := schematicsv1.JobLogSummary{} - - if jobLogSummaryMap["job_id"] != nil { - jobLogSummary.JobID = core.StringPtr(jobLogSummaryMap["job_id"].(string)) - } - if jobLogSummaryMap["job_type"] != nil { - jobLogSummary.JobType = core.StringPtr(jobLogSummaryMap["job_type"].(string)) - } - if jobLogSummaryMap["log_start_at"] != nil { - - } - if jobLogSummaryMap["log_analyzed_till"] != nil { - - } - if jobLogSummaryMap["elapsed_time"] != nil { - jobLogSummary.ElapsedTime = core.Float64Ptr(jobLogSummaryMap["elapsed_time"].(float64)) - } - if jobLogSummaryMap["log_errors"] != nil { - logErrors := []schematicsv1.JobLogSummaryLogErrorsItem{} - for _, logErrorsItem := range jobLogSummaryMap["log_errors"].([]interface{}) { - logErrorsItemModel := resourceIBMSchematicsJobMapToJobLogSummaryLogErrorsItem(logErrorsItem.(map[string]interface{})) - logErrors = append(logErrors, logErrorsItemModel) - } - jobLogSummary.LogErrors = logErrors - } - if jobLogSummaryMap["repo_download_job"] != nil { - repoDownloadJob := resourceIBMSchematicsJobMapToJobLogSummaryRepoDownloadJob(jobLogSummaryMap["repo_download_job"].([]interface{})[0].(map[string]interface{})) - jobLogSummary.RepoDownloadJob = &repoDownloadJob - } - if jobLogSummaryMap["action_job"] != nil { - actionJob := resourceIBMSchematicsJobMapToJobLogSummaryActionJob(jobLogSummaryMap["action_job"].([]interface{})[0].(map[string]interface{})) - jobLogSummary.ActionJob = &actionJob - } - - return jobLogSummary -} - -func resourceIBMSchematicsJobMapToJobLogSummaryLogErrorsItem(jobLogSummaryLogErrorsItemMap map[string]interface{}) schematicsv1.JobLogSummaryLogErrorsItem { - jobLogSummaryLogErrorsItem := schematicsv1.JobLogSummaryLogErrorsItem{} - - if jobLogSummaryLogErrorsItemMap["error_code"] != nil { - jobLogSummaryLogErrorsItem.ErrorCode = core.StringPtr(jobLogSummaryLogErrorsItemMap["error_code"].(string)) - } - if jobLogSummaryLogErrorsItemMap["error_msg"] != nil { - jobLogSummaryLogErrorsItem.ErrorMsg = core.StringPtr(jobLogSummaryLogErrorsItemMap["error_msg"].(string)) - } - if jobLogSummaryLogErrorsItemMap["error_count"] != nil { - jobLogSummaryLogErrorsItem.ErrorCount = core.Float64Ptr(jobLogSummaryLogErrorsItemMap["error_count"].(float64)) - } - - return jobLogSummaryLogErrorsItem -} - -func resourceIBMSchematicsJobMapToJobLogSummaryRepoDownloadJob(jobLogSummaryRepoDownloadJobMap map[string]interface{}) schematicsv1.JobLogSummaryRepoDownloadJob { - jobLogSummaryRepoDownloadJob := schematicsv1.JobLogSummaryRepoDownloadJob{} - - if jobLogSummaryRepoDownloadJobMap["scanned_file_count"] != nil { - jobLogSummaryRepoDownloadJob.ScannedFileCount = core.Float64Ptr(jobLogSummaryRepoDownloadJobMap["scanned_file_count"].(float64)) - } - if jobLogSummaryRepoDownloadJobMap["quarantined_file_count"] != nil { - jobLogSummaryRepoDownloadJob.QuarantinedFileCount = core.Float64Ptr(jobLogSummaryRepoDownloadJobMap["quarantined_file_count"].(float64)) - } - if jobLogSummaryRepoDownloadJobMap["detected_filetype"] != nil { - jobLogSummaryRepoDownloadJob.DetectedFiletype = core.StringPtr(jobLogSummaryRepoDownloadJobMap["detected_filetype"].(string)) - } - if jobLogSummaryRepoDownloadJobMap["inputs_count"] != nil { - jobLogSummaryRepoDownloadJob.InputsCount = core.StringPtr(jobLogSummaryRepoDownloadJobMap["inputs_count"].(string)) - } - if jobLogSummaryRepoDownloadJobMap["outputs_count"] != nil { - jobLogSummaryRepoDownloadJob.OutputsCount = core.StringPtr(jobLogSummaryRepoDownloadJobMap["outputs_count"].(string)) - } - - return jobLogSummaryRepoDownloadJob -} - -func resourceIBMSchematicsJobMapToJobLogSummaryActionJob(jobLogSummaryActionJobMap map[string]interface{}) schematicsv1.JobLogSummaryActionJob { - jobLogSummaryActionJob := schematicsv1.JobLogSummaryActionJob{} - - if jobLogSummaryActionJobMap["target_count"] != nil { - jobLogSummaryActionJob.TargetCount = core.Float64Ptr(jobLogSummaryActionJobMap["target_count"].(float64)) - } - if jobLogSummaryActionJobMap["task_count"] != nil { - jobLogSummaryActionJob.TaskCount = core.Float64Ptr(jobLogSummaryActionJobMap["task_count"].(float64)) - } - if jobLogSummaryActionJobMap["play_count"] != nil { - jobLogSummaryActionJob.PlayCount = core.Float64Ptr(jobLogSummaryActionJobMap["play_count"].(float64)) - } - if jobLogSummaryActionJobMap["recap"] != nil { - recap := resourceIBMSchematicsJobMapToJobLogSummaryActionJobRecap(jobLogSummaryActionJobMap["recap"].([]interface{})[0].(map[string]interface{})) - jobLogSummaryActionJob.Recap = &recap - } - - return jobLogSummaryActionJob -} - -func resourceIBMSchematicsJobMapToJobLogSummaryActionJobRecap(jobLogSummaryActionJobRecapMap map[string]interface{}) schematicsv1.JobLogSummaryActionJobRecap { - jobLogSummaryActionJobRecap := schematicsv1.JobLogSummaryActionJobRecap{} - - if jobLogSummaryActionJobRecapMap["target"] != nil { - target := []string{} - for _, targetItem := range jobLogSummaryActionJobRecapMap["target"].([]interface{}) { - target = append(target, targetItem.(string)) - } - jobLogSummaryActionJobRecap.Target = target - } - if jobLogSummaryActionJobRecapMap["ok"] != nil { - jobLogSummaryActionJobRecap.Ok = core.Float64Ptr(jobLogSummaryActionJobRecapMap["ok"].(float64)) - } - if jobLogSummaryActionJobRecapMap["changed"] != nil { - jobLogSummaryActionJobRecap.Changed = core.Float64Ptr(jobLogSummaryActionJobRecapMap["changed"].(float64)) - } - if jobLogSummaryActionJobRecapMap["failed"] != nil { - jobLogSummaryActionJobRecap.Failed = core.Float64Ptr(jobLogSummaryActionJobRecapMap["failed"].(float64)) - } - if jobLogSummaryActionJobRecapMap["skipped"] != nil { - jobLogSummaryActionJobRecap.Skipped = core.Float64Ptr(jobLogSummaryActionJobRecapMap["skipped"].(float64)) - } - if jobLogSummaryActionJobRecapMap["unreachable"] != nil { - jobLogSummaryActionJobRecap.Unreachable = core.Float64Ptr(jobLogSummaryActionJobRecapMap["unreachable"].(float64)) - } - - return jobLogSummaryActionJobRecap -} - -func resourceIBMSchematicsJobRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getJobOptions := &schematicsv1.GetJobOptions{} - - getJobOptions.SetJobID(d.Id()) - - job, response, err := schematicsClient.GetJobWithContext(context, getJobOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetJobWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - if err = d.Set("command_object", job.CommandObject); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_object: %s", err)) - } - if err = d.Set("command_object_id", job.CommandObjectID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_object_id: %s", err)) - } - if err = d.Set("command_name", job.CommandName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_name: %s", err)) - } - if _, ok := d.GetOk("command_parameter"); ok { - if err = d.Set("command_parameter", d.Get("command_parameter").(string)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_parameter: %s", err)) - } - } - if job.CommandOptions != nil { - if err = d.Set("command_options", job.CommandOptions); err != nil { - return diag.FromErr(fmt.Errorf("Error setting command_options: %s", err)) - } - } - if job.Inputs != nil { - inputs := []map[string]interface{}{} - for _, inputsItem := range job.Inputs { - inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) - inputs = append(inputs, inputsItemMap) - } - if err = d.Set("job_inputs", inputs); err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_inputs: %s", err)) - } - } - if job.Settings != nil { - settings := []map[string]interface{}{} - for _, settingsItem := range job.Settings { - settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) - settings = append(settings, settingsItemMap) - } - if err = d.Set("job_env_settings", settings); err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_env_settings: %s", err)) - } - } - if job.Tags != nil { - if err = d.Set("tags", job.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - } - if err = d.Set("location", job.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if job.Status != nil { - statusMap := resourceIBMSchematicsJobJobStatusToMap(*job.Status) - if err = d.Set("status", []map[string]interface{}{statusMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) - } - } - if job.Data != nil { - dataMap := resourceIBMSchematicsJobJobDataToMap(*job.Data) - if err = d.Set("data", []map[string]interface{}{dataMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting data: %s", err)) - } - } - if job.Bastion != nil { - bastionMap := resourceIBMSchematicsJobTargetResourcesetToMap(*job.Bastion) - if err = d.Set("bastion", []map[string]interface{}{bastionMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting bastion: %s", err)) - } - } - if job.LogSummary != nil { - logSummaryMap := resourceIBMSchematicsJobJobLogSummaryToMap(*job.LogSummary) - if err = d.Set("job_log_summary", []map[string]interface{}{logSummaryMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting job_log_summary: %s", err)) - } - } - if err = d.Set("name", job.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("description", job.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("resource_group", job.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - if err = d.Set("submitted_at", job.SubmittedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting submitted_at: %s", err)) - } - if err = d.Set("submitted_by", job.SubmittedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting submitted_by: %s", err)) - } - if err = d.Set("start_at", job.StartAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting start_at: %s", err)) - } - if err = d.Set("end_at", job.EndAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting end_at: %s", err)) - } - if err = d.Set("duration", job.Duration); err != nil { - return diag.FromErr(fmt.Errorf("Error setting duration: %s", err)) - } - if err = d.Set("targets_ini", job.TargetsIni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting targets_ini: %s", err)) - } - if err = d.Set("log_store_url", job.LogStoreURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting log_store_url: %s", err)) - } - if err = d.Set("state_store_url", job.StateStoreURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state_store_url: %s", err)) - } - if err = d.Set("results_url", job.ResultsURL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting results_url: %s", err)) - } - if err = d.Set("updated_at", job.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - - return nil -} - -func resourceIBMSchematicsJobVariableDataToMap(variableData schematicsv1.VariableData) map[string]interface{} { - variableDataMap := map[string]interface{}{} - - variableDataMap["name"] = variableData.Name - variableDataMap["value"] = variableData.Value - if variableData.Metadata != nil { - MetadataMap := resourceIBMSchematicsJobVariableMetadataToMap(*variableData.Metadata) - variableDataMap["metadata"] = []map[string]interface{}{MetadataMap} - } - variableDataMap["link"] = variableData.Link - - return variableDataMap -} - -func resourceIBMSchematicsJobVariableMetadataToMap(variableMetadata schematicsv1.VariableMetadata) map[string]interface{} { - variableMetadataMap := map[string]interface{}{} - - variableMetadataMap["type"] = variableMetadata.Type - if variableMetadata.Aliases != nil { - variableMetadataMap["aliases"] = variableMetadata.Aliases - } - variableMetadataMap["description"] = variableMetadata.Description - variableMetadataMap["default_value"] = variableMetadata.DefaultValue - variableMetadataMap["secure"] = variableMetadata.Secure - variableMetadataMap["immutable"] = variableMetadata.Immutable - variableMetadataMap["hidden"] = variableMetadata.Hidden - if variableMetadata.Options != nil { - variableMetadataMap["options"] = variableMetadata.Options - } - variableMetadataMap["min_value"] = intValue(variableMetadata.MinValue) - variableMetadataMap["max_value"] = intValue(variableMetadata.MaxValue) - variableMetadataMap["min_length"] = intValue(variableMetadata.MinLength) - variableMetadataMap["max_length"] = intValue(variableMetadata.MaxLength) - variableMetadataMap["matches"] = variableMetadata.Matches - variableMetadataMap["position"] = intValue(variableMetadata.Position) - variableMetadataMap["group_by"] = variableMetadata.GroupBy - variableMetadataMap["source"] = variableMetadata.Source - - return variableMetadataMap -} - -func resourceIBMSchematicsJobJobStatusToMap(jobStatus schematicsv1.JobStatus) map[string]interface{} { - jobStatusMap := map[string]interface{}{} - - if jobStatus.ActionJobStatus != nil { - ActionJobStatusMap := resourceIBMSchematicsJobJobStatusActionToMap(*jobStatus.ActionJobStatus) - jobStatusMap["action_job_status"] = []map[string]interface{}{ActionJobStatusMap} - } - - return jobStatusMap -} - -func resourceIBMSchematicsJobJobStatusActionToMap(jobStatusAction schematicsv1.JobStatusAction) map[string]interface{} { - jobStatusActionMap := map[string]interface{}{} - - jobStatusActionMap["action_name"] = jobStatusAction.ActionName - jobStatusActionMap["status_code"] = jobStatusAction.StatusCode - jobStatusActionMap["status_message"] = jobStatusAction.StatusMessage - jobStatusActionMap["bastion_status_code"] = jobStatusAction.BastionStatusCode - jobStatusActionMap["bastion_status_message"] = jobStatusAction.BastionStatusMessage - jobStatusActionMap["targets_status_code"] = jobStatusAction.TargetsStatusCode - jobStatusActionMap["targets_status_message"] = jobStatusAction.TargetsStatusMessage - jobStatusActionMap["updated_at"] = jobStatusAction.UpdatedAt.String() - - return jobStatusActionMap -} - -func resourceIBMSchematicsJobJobDataToMap(jobData schematicsv1.JobData) map[string]interface{} { - jobDataMap := map[string]interface{}{} - - jobDataMap["job_type"] = jobData.JobType - if jobData.ActionJobData != nil { - ActionJobDataMap := resourceIBMSchematicsJobJobDataActionToMap(*jobData.ActionJobData) - jobDataMap["action_job_data"] = []map[string]interface{}{ActionJobDataMap} - } - - return jobDataMap -} - -func resourceIBMSchematicsJobJobDataActionToMap(jobDataAction schematicsv1.JobDataAction) map[string]interface{} { - jobDataActionMap := map[string]interface{}{} - - jobDataActionMap["action_name"] = jobDataAction.ActionName - if jobDataAction.Inputs != nil { - inputs := []map[string]interface{}{} - for _, inputsItem := range jobDataAction.Inputs { - inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) - inputs = append(inputs, inputsItemMap) - // TODO: handle Inputs of type TypeList -- list of non-primitive, not model items - } - jobDataActionMap["inputs"] = inputs - } - if jobDataAction.Outputs != nil { - outputs := []map[string]interface{}{} - for _, outputsItem := range jobDataAction.Outputs { - outputsItemMap := resourceIBMSchematicsJobVariableDataToMap(outputsItem) - outputs = append(outputs, outputsItemMap) - // TODO: handle Outputs of type TypeList -- list of non-primitive, not model items - } - jobDataActionMap["outputs"] = outputs - } - if jobDataAction.Settings != nil { - settings := []map[string]interface{}{} - for _, settingsItem := range jobDataAction.Settings { - settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) - settings = append(settings, settingsItemMap) - // TODO: handle Settings of type TypeList -- list of non-primitive, not model items - } - jobDataActionMap["settings"] = settings - } - jobDataActionMap["updated_at"] = jobDataAction.UpdatedAt.String() - - return jobDataActionMap -} - -func resourceIBMSchematicsJobTargetResourcesetToMap(targetResourceset schematicsv1.TargetResourceset) map[string]interface{} { - targetResourcesetMap := map[string]interface{}{} - - targetResourcesetMap["name"] = targetResourceset.Name - targetResourcesetMap["type"] = targetResourceset.Type - targetResourcesetMap["description"] = targetResourceset.Description - targetResourcesetMap["resource_query"] = targetResourceset.ResourceQuery - targetResourcesetMap["credential_ref"] = targetResourceset.CredentialRef - targetResourcesetMap["id"] = targetResourceset.ID - targetResourcesetMap["created_at"] = targetResourceset.CreatedAt.String() - targetResourcesetMap["created_by"] = targetResourceset.CreatedBy - targetResourcesetMap["updated_at"] = targetResourceset.UpdatedAt.String() - targetResourcesetMap["updated_by"] = targetResourceset.UpdatedBy - if targetResourceset.SysLock != nil { - SysLockMap := resourceIBMSchematicsJobSystemLockToMap(*targetResourceset.SysLock) - targetResourcesetMap["sys_lock"] = []map[string]interface{}{SysLockMap} - } - if targetResourceset.ResourceIds != nil { - targetResourcesetMap["resource_ids"] = targetResourceset.ResourceIds - } - - return targetResourcesetMap -} - -func resourceIBMSchematicsJobSystemLockToMap(systemLock schematicsv1.SystemLock) map[string]interface{} { - systemLockMap := map[string]interface{}{} - - systemLockMap["sys_locked"] = systemLock.SysLocked - systemLockMap["sys_locked_by"] = systemLock.SysLockedBy - systemLockMap["sys_locked_at"] = systemLock.SysLockedAt.String() - - return systemLockMap -} - -func resourceIBMSchematicsJobJobLogSummaryToMap(jobLogSummary schematicsv1.JobLogSummary) map[string]interface{} { - jobLogSummaryMap := map[string]interface{}{} - - jobLogSummaryMap["job_id"] = jobLogSummary.JobID - jobLogSummaryMap["job_type"] = jobLogSummary.JobType - jobLogSummaryMap["log_start_at"] = jobLogSummary.LogStartAt.String() - jobLogSummaryMap["log_analyzed_till"] = jobLogSummary.LogAnalyzedTill.String() - jobLogSummaryMap["elapsed_time"] = jobLogSummary.ElapsedTime - if jobLogSummary.LogErrors != nil { - logErrors := []map[string]interface{}{} - for _, logErrorsItem := range jobLogSummary.LogErrors { - logErrorsItemMap := resourceIBMSchematicsJobJobLogSummaryLogErrorsItemToMap(logErrorsItem) - logErrors = append(logErrors, logErrorsItemMap) - // TODO: handle LogErrors of type TypeList -- list of non-primitive, not model items - } - jobLogSummaryMap["log_errors"] = logErrors - } - if jobLogSummary.RepoDownloadJob != nil { - RepoDownloadJobMap := resourceIBMSchematicsJobJobLogSummaryRepoDownloadJobToMap(*jobLogSummary.RepoDownloadJob) - jobLogSummaryMap["repo_download_job"] = []map[string]interface{}{RepoDownloadJobMap} - } - if jobLogSummary.ActionJob != nil { - ActionJobMap := resourceIBMSchematicsJobJobLogSummaryActionJobToMap(*jobLogSummary.ActionJob) - jobLogSummaryMap["action_job"] = []map[string]interface{}{ActionJobMap} - } - - return jobLogSummaryMap -} - -func resourceIBMSchematicsJobJobLogSummaryLogErrorsItemToMap(jobLogSummaryLogErrorsItem schematicsv1.JobLogSummaryLogErrorsItem) map[string]interface{} { - jobLogSummaryLogErrorsItemMap := map[string]interface{}{} - - jobLogSummaryLogErrorsItemMap["error_code"] = jobLogSummaryLogErrorsItem.ErrorCode - jobLogSummaryLogErrorsItemMap["error_msg"] = jobLogSummaryLogErrorsItem.ErrorMsg - jobLogSummaryLogErrorsItemMap["error_count"] = jobLogSummaryLogErrorsItem.ErrorCount - - return jobLogSummaryLogErrorsItemMap -} - -func resourceIBMSchematicsJobJobLogSummaryRepoDownloadJobToMap(jobLogSummaryRepoDownloadJob schematicsv1.JobLogSummaryRepoDownloadJob) map[string]interface{} { - jobLogSummaryRepoDownloadJobMap := map[string]interface{}{} - - jobLogSummaryRepoDownloadJobMap["scanned_file_count"] = jobLogSummaryRepoDownloadJob.ScannedFileCount - jobLogSummaryRepoDownloadJobMap["quarantined_file_count"] = jobLogSummaryRepoDownloadJob.QuarantinedFileCount - jobLogSummaryRepoDownloadJobMap["detected_filetype"] = jobLogSummaryRepoDownloadJob.DetectedFiletype - jobLogSummaryRepoDownloadJobMap["inputs_count"] = jobLogSummaryRepoDownloadJob.InputsCount - jobLogSummaryRepoDownloadJobMap["outputs_count"] = jobLogSummaryRepoDownloadJob.OutputsCount - - return jobLogSummaryRepoDownloadJobMap -} - -func resourceIBMSchematicsJobJobLogSummaryActionJobToMap(jobLogSummaryActionJob schematicsv1.JobLogSummaryActionJob) map[string]interface{} { - jobLogSummaryActionJobMap := map[string]interface{}{} - - jobLogSummaryActionJobMap["target_count"] = jobLogSummaryActionJob.TargetCount - jobLogSummaryActionJobMap["task_count"] = jobLogSummaryActionJob.TaskCount - jobLogSummaryActionJobMap["play_count"] = jobLogSummaryActionJob.PlayCount - if jobLogSummaryActionJob.Recap != nil { - RecapMap := resourceIBMSchematicsJobJobLogSummaryActionJobRecapToMap(*jobLogSummaryActionJob.Recap) - jobLogSummaryActionJobMap["recap"] = []map[string]interface{}{RecapMap} - } - - return jobLogSummaryActionJobMap -} - -func resourceIBMSchematicsJobJobLogSummaryActionJobRecapToMap(jobLogSummaryActionJobRecap schematicsv1.JobLogSummaryActionJobRecap) map[string]interface{} { - jobLogSummaryActionJobRecapMap := map[string]interface{}{} - - if jobLogSummaryActionJobRecap.Target != nil { - jobLogSummaryActionJobRecapMap["target"] = jobLogSummaryActionJobRecap.Target - } - jobLogSummaryActionJobRecapMap["ok"] = jobLogSummaryActionJobRecap.Ok - jobLogSummaryActionJobRecapMap["changed"] = jobLogSummaryActionJobRecap.Changed - jobLogSummaryActionJobRecapMap["failed"] = jobLogSummaryActionJobRecap.Failed - jobLogSummaryActionJobRecapMap["skipped"] = jobLogSummaryActionJobRecap.Skipped - jobLogSummaryActionJobRecapMap["unreachable"] = jobLogSummaryActionJobRecap.Unreachable - - return jobLogSummaryActionJobRecapMap -} - -func resourceIBMSchematicsJobUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - session, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - - iamRefreshToken := session.Config.IAMRefreshToken - - replaceJobOptions := &schematicsv1.ReplaceJobOptions{} - - replaceJobOptions.SetJobID(d.Id()) - replaceJobOptions.SetRefreshToken(iamRefreshToken) - - if _, ok := d.GetOk("command_object"); ok { - replaceJobOptions.SetCommandObject(d.Get("command_object").(string)) - } - if _, ok := d.GetOk("command_object_id"); ok { - replaceJobOptions.SetCommandObjectID(d.Get("command_object_id").(string)) - } - if _, ok := d.GetOk("command_name"); ok { - replaceJobOptions.SetCommandName(d.Get("command_name").(string)) - } - if _, ok := d.GetOk("command_parameter"); ok { - replaceJobOptions.SetCommandParameter(d.Get("command_parameter").(string)) - } - if _, ok := d.GetOk("command_options"); ok { - replaceJobOptions.SetCommandOptions(expandStringList(d.Get("command_options").([]interface{}))) - } - if _, ok := d.GetOk("job_inputs"); ok { - var inputs []schematicsv1.VariableData - for _, e := range d.Get("job_inputs").([]interface{}) { - value := e.(map[string]interface{}) - inputsItem := resourceIBMSchematicsJobMapToVariableData(value) - inputs = append(inputs, inputsItem) - } - replaceJobOptions.SetInputs(inputs) - } - if _, ok := d.GetOk("job_env_settings"); ok { - var settings []schematicsv1.VariableData - for _, e := range d.Get("job_env_settings").([]interface{}) { - value := e.(map[string]interface{}) - settingsItem := resourceIBMSchematicsJobMapToVariableData(value) - settings = append(settings, settingsItem) - } - replaceJobOptions.SetSettings(settings) - } - if _, ok := d.GetOk("tags"); ok { - replaceJobOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - } - if _, ok := d.GetOk("location"); ok { - replaceJobOptions.SetLocation(d.Get("location").(string)) - } - if _, ok := d.GetOk("status"); ok { - statusAttr := d.Get("status").([]interface{}) - if len(statusAttr) > 0 { - status := resourceIBMSchematicsJobMapToJobStatus(d.Get("status.0").(map[string]interface{})) - replaceJobOptions.SetStatus(&status) - } - } - if _, ok := d.GetOk("data"); ok { - dataAttr := d.Get("data").([]interface{}) - if len(dataAttr) > 0 { - data := resourceIBMSchematicsJobMapToJobData(d.Get("data.0").(map[string]interface{})) - replaceJobOptions.SetData(&data) - } - } - if _, ok := d.GetOk("bastion"); ok { - bastionAttr := d.Get("bastion").([]interface{}) - if len(bastionAttr) > 0 { - bastion := resourceIBMSchematicsJobMapToTargetResourceset(d.Get("bastion.0").(map[string]interface{})) - replaceJobOptions.SetBastion(&bastion) - } - } - if _, ok := d.GetOk("job_log_summary"); ok { - jobLogSummaryAttr := d.Get("job_log_summary").([]interface{}) - if len(jobLogSummaryAttr) > 0 { - logSummary := resourceIBMSchematicsJobMapToJobLogSummary(d.Get("job_log_summary.0").(map[string]interface{})) - replaceJobOptions.SetLogSummary(&logSummary) - } - } - - _, response, err := schematicsClient.ReplaceJobWithContext(context, replaceJobOptions) - if err != nil { - log.Printf("[DEBUG] ReplaceJobWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - return resourceIBMSchematicsJobRead(context, d, meta) -} - -func resourceIBMSchematicsJobDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - session, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - deleteJobOptions := &schematicsv1.DeleteJobOptions{} - - iamRefreshToken := session.Config.IAMRefreshToken - deleteJobOptions.SetRefreshToken(iamRefreshToken) - - deleteJobOptions.SetJobID(d.Id()) - - response, err := schematicsClient.DeleteJobWithContext(context, deleteJobOptions) - if err != nil { - log.Printf("[DEBUG] DeleteJobWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_schematics_workspace.go b/ibm/resource_ibm_schematics_workspace.go deleted file mode 100644 index bebc7d48d..000000000 --- a/ibm/resource_ibm_schematics_workspace.go +++ /dev/null @@ -1,1513 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/schematics-go-sdk/schematicsv1" - "github.com/go-openapi/strfmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -const ( - schematicsWorkspaceName = "name" - schematicsWorkspaceDescription = "description" - schematicsWorkspaceTemplateType = "template_type" -) - -func resourceIBMSchematicsWorkspace() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMSchematicsWorkspaceCreate, - ReadContext: resourceIBMSchematicsWorkspaceRead, - UpdateContext: resourceIBMSchematicsWorkspaceUpdate, - DeleteContext: resourceIBMSchematicsWorkspaceDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "applied_shareddata_ids": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of applied shared dataset id.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "catalog_ref": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "dry_run": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Dry run.", - }, - "item_icon_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the icon of the software template in the IBM Cloud catalog.", - }, - "item_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", - }, - "item_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the software that you chose to install from the IBM Cloud catalog.", - }, - "item_readme_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the readme file of the software template in the IBM Cloud catalog.", - }, - "item_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the software template in the IBM Cloud catalog.", - }, - "launch_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the dashboard to access your software.", - }, - "offering_version": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The version of the software template that you chose to install from the IBM Cloud catalog.", - }, - }, - }, - }, - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The description of the workspace.", - ValidateFunc: InvokeValidator("ibm_schematics_workspace", schematicsWorkspaceDescription), - }, - "location": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The location where you want to create your Schematics workspace and run Schematics actions. The location that you enter must match the API endpoint that you use. For example, if you use the Frankfurt API endpoint, you must specify `eu-de` as your location. If you use an API endpoint for a geography and you do not specify a location, Schematics determines the location based on availability.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The name of your workspace. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. When you create a workspace for your own Terraform template, consider including the microservice component that you set up with your Terraform template and the IBM Cloud environment where you want to deploy your resources in your name.", - ValidateFunc: InvokeValidator("ibm_schematics_workspace", schematicsWorkspaceName), - }, - "resource_group": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the resource group where you want to provision the workspace.", - }, - "shared_data": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "Information that is shared across templates in IBM Cloud catalog offerings. This information is not provided when you create a workspace from your own Terraform template.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cluster_created_on": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Cluster created on.", - }, - "cluster_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - "cluster_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Cluster name.", - }, - "cluster_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Cluster type.", - }, - "entitlement_keys": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "The entitlement key that you want to use to install IBM Cloud entitled software.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "namespace": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", - }, - "region": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - "resource_group_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", - }, - "worker_count": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Description: "Cluster worker count.", - }, - "worker_machine_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Cluster worker type.", - }, - }, - }, - }, - "tags": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "A list of tags that are associated with the workspace.", - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "template_env_settings": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "A list of environment variables that you want to apply during the execution of a bash script or Terraform action. This field must be provided as a list of key-value pairs, for example, **TF_LOG=debug**. Each entry will be a map with one entry where `key is the environment variable name and value is value`. You can define environment variables for IBM Cloud catalog offerings that are provisioned by using a bash script.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "template_git_folder": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The subfolder in your GitHub or GitLab repository where your Terraform template is stored.", - }, - "template_init_state_file": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The content of an existing Terraform statefile that you want to import in to your workspace. To get the content of a Terraform statefile for a specific Terraform template in an existing workspace, run `ibmcloud terraform state pull --id --template `.", - }, - "template_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The Terraform version that you want to use to run your Terraform code. Enter `terraform_v0.12` to use Terraform version 0.12, and `terraform_v0.11` to use Terraform version 0.11. Make sure that your Terraform config files are compatible with the Terraform version that you select.", - ValidateFunc: InvokeValidator("ibm_schematics_workspace", schematicsWorkspaceTemplateType), - }, - "template_uninstall_script_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Uninstall script name.", - }, - "template_values": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", - }, - "template_values_metadata": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Computed: true, - Description: "List of values metadata.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "template_inputs": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "VariablesRequest -.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The description of your input variable.", - }, - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The name of the variable.", - }, - "secure": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", - }, - "type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`, `object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", - }, - "use_default": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "Variable uses default value; and is not over-ridden.", - }, - "value": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", - }, - }, - }, - }, - "template_ref": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Workspace template ref.", - }, - "template_git_branch": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The branch in GitHub where your Terraform template is stored.", - }, - "template_git_release": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The release tag in GitHub of your Terraform template.", - }, - "template_git_repo_sha_value": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "Repo SHA value.", - }, - "template_git_repo_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the repository where the IBM Cloud catalog software template is stored.", - }, - "template_git_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to the GitHub or GitLab repository where your Terraform and public bit bucket template is stored. For more information of the environment variable syntax, see [Create workspace new](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-workspace-new).", - ValidateFunc: validation.IsURLWithHTTPorHTTPS, - }, - "template_git_has_uploadedgitrepotar": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "Has uploaded git repo tar", - }, - /*"template_type": &schema.Schema{ - Type: schema.TypeList, - Required: true, - Description: "List of Workspace type.", - Elem: &schema.Schema{Type: schema.TypeString}, - },*/ - "frozen": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Description: "If set to true, the workspace is frozen and changes to the workspace are disabled.", - }, - "frozen_at": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The timestamp when the workspace was frozen.", - }, - "frozen_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The user ID that froze the workspace.", - }, - "locked": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "If set to true, the workspace is locked and disabled for changes.", - }, - "locked_by": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The user ID that initiated a resource-related action, such as applying or destroying resources, that locked the workspace.", - }, - "locked_time": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The timestamp when the workspace was locked.", - }, - "x_github_token": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was created.", - }, - "created_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that created the workspace.", - }, - "crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Workspace CRN.", - }, - "last_health_check_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the last health check was performed by Schematics.", - }, - "runtime_data": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "Information about the provisioning engine, state file, and runtime logs.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "engine_cmd": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", - }, - "engine_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", - }, - "engine_version": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The version of the provisioning engine that was used.", - }, - "id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", - }, - "log_store_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", - }, - "output_values": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of Output values.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "resources": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Description: "List of resources.", - Elem: &schema.Schema{Type: schema.TypeMap}, - }, - "state_store_url": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion actions.", - }, - }, - }, - }, - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply actions to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy action was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The timestamp when the workspace was last updated.", - }, - "updated_by": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The user ID that updated the workspace.", - }, - "status_code": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The success or error code that was returned for the last plan, apply, or destroy action that ran against your workspace.", - }, - "status_msg": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The success or error message that was returned for the last plan, apply, or destroy action that ran against your workspace.", - }, - }, - } -} - -func resourceIBMSchematicsWorkspaceValidator() *ResourceValidator { - - validateSchema := make([]ValidateSchema, 0) - - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: schematicsWorkspaceName, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$`, - MinValueLength: 1, - MaxValueLength: 128, - Required: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: schematicsWorkspaceDescription, - ValidateFunctionIdentifier: StringLenBetween, - Type: TypeString, - MinValueLength: 0, - MaxValueLength: 2048, - Optional: true}) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: schematicsWorkspaceTemplateType, - ValidateFunctionIdentifier: ValidateRegexp, - Type: TypeString, - Regexp: `^terraform_v0\.(?:11|12|13)(?:\.\d+)?$`, - Default: "[]", - Optional: true}) - - ibmSchematicsWorkspaceResourceValidator := ResourceValidator{ResourceName: "ibm_schematics_workspace", Schema: validateSchema} - return &ibmSchematicsWorkspaceResourceValidator -} - -func resourceIBMSchematicsWorkspaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - createWorkspaceOptions := &schematicsv1.CreateWorkspaceOptions{} - - if _, ok := d.GetOk("applied_shareddata_ids"); ok { - createWorkspaceOptions.SetAppliedShareddataIds(expandStringList(d.Get("applied_shareddata_ids").([]interface{}))) - } - if _, ok := d.GetOk("catalog_ref"); ok { - catalogRefAttr := d.Get("catalog_ref").([]interface{}) - if len(catalogRefAttr) > 0 { - catalogRef := resourceIBMSchematicsWorkspaceMapToCatalogRef(d.Get("catalog_ref.0").(map[string]interface{})) - createWorkspaceOptions.SetCatalogRef(&catalogRef) - } - } - if _, ok := d.GetOk("description"); ok { - createWorkspaceOptions.SetDescription(d.Get("description").(string)) - } - if _, ok := d.GetOk("location"); ok { - createWorkspaceOptions.SetLocation(d.Get("location").(string)) - } - if _, ok := d.GetOk("name"); ok { - createWorkspaceOptions.SetName(d.Get("name").(string)) - } - if _, ok := d.GetOk("resource_group"); ok { - createWorkspaceOptions.SetResourceGroup(d.Get("resource_group").(string)) - } - if _, ok := d.GetOk("shared_data"); ok { - sharedDataAttr := d.Get("shared_data").([]interface{}) - if len(sharedDataAttr) > 0 { - sharedData := resourceIBMSchematicsWorkspaceMapToSharedTargetData(d.Get("shared_data.0").(map[string]interface{})) - createWorkspaceOptions.SetSharedData(&sharedData) - } - } - if _, ok := d.GetOk("tags"); ok { - createWorkspaceOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - } - - var templateData []schematicsv1.TemplateSourceDataRequest - - templateSourceDataRequestMap := map[string]interface{}{} - hasTemplateData := false - - if _, ok := d.GetOk("template_env_settings"); ok { - templateSourceDataRequestMap["env_values"] = d.Get("template_env_settings").([]interface{}) - hasTemplateData = true - } - if _, ok := d.GetOk("template_git_folder"); ok { - templateSourceDataRequestMap["folder"] = d.Get("template_git_folder").(string) - hasTemplateData = true - } - if _, ok := d.GetOk("template_init_state_file"); ok { - templateSourceDataRequestMap["init_state_file"] = d.Get("template_init_state_file").(string) - hasTemplateData = true - } - if _, ok := d.GetOk("template_type"); ok { - templateSourceDataRequestMap["type"] = d.Get("template_type").(string) - createWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) - hasTemplateData = true - } - if _, ok := d.GetOk("template_uninstall_script_name"); ok { - templateSourceDataRequestMap["uninstall_script_name"] = d.Get("template_uninstall_script_name").(string) - hasTemplateData = true - } - if _, ok := d.GetOk("template_values"); ok { - templateSourceDataRequestMap["values"] = d.Get("template_values").(string) - hasTemplateData = true - } - if _, ok := d.GetOk("template_values_metadata"); ok { - templateSourceDataRequestMap["values_metadata"] = d.Get("template_values_metadata").([]interface{}) - hasTemplateData = true - } - if _, ok := d.GetOk("template_inputs"); ok { - templateSourceDataRequestMap["variablestore"] = d.Get("template_inputs").([]interface{}) - hasTemplateData = true - } - if hasTemplateData { - templateDataItem := resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap) - templateData = append(templateData, templateDataItem) - createWorkspaceOptions.SetTemplateData(templateData) - } - if _, ok := d.GetOk("template_ref"); ok { - createWorkspaceOptions.SetTemplateRef(d.Get("template_ref").(string)) - } - - templateRepoRequestMap := map[string]interface{}{} - hasTemplateRepo := false - if _, ok := d.GetOk("template_git_branch"); ok { - templateRepoRequestMap["branch"] = d.Get("template_git_branch").(string) - hasTemplateRepo = true - } - if _, ok := d.GetOk("template_git_release"); ok { - templateRepoRequestMap["release"] = d.Get("template_git_release").(string) - hasTemplateRepo = true - } - if _, ok := d.GetOk("template_git_repo_sha_value"); ok { - templateRepoRequestMap["repo_sha_value"] = d.Get("template_git_repo_sha_value").(string) - hasTemplateRepo = true - } - if _, ok := d.GetOk("template_git_repo_url"); ok { - templateRepoRequestMap["repo_url"] = d.Get("template_git_repo_url").(string) - hasTemplateRepo = true - } - if _, ok := d.GetOk("template_git_url"); ok { - templateRepoRequestMap["url"] = d.Get("template_git_url").(string) - hasTemplateRepo = true - } - if _, ok := d.GetOk("template_git_has_uploadedgitrepotar"); ok { - templateRepoRequestMap["has_uploadedgitrepotar"] = d.Get("template_git_has_uploadedgitrepotar").(string) - hasTemplateRepo = true - } - if hasTemplateRepo { - templateRepo := resourceIBMSchematicsWorkspaceMapToTemplateRepoRequest(templateRepoRequestMap) - createWorkspaceOptions.SetTemplateRepo(&templateRepo) - } - - /*if _, ok := d.GetOk("template_type"); ok { - createWorkspaceOptions.SetType(expandStringList(d.Get("template_type").([]interface{}))) - }*/ - workspaceStatusRequestMap := map[string]interface{}{} - hasWorkspaceStatus := false - if _, ok := d.GetOk("frozen"); ok { - workspaceStatusRequestMap["frozen"] = d.Get("frozen").(bool) - hasWorkspaceStatus = true - } - if _, ok := d.GetOk("frozen_at"); ok { - workspaceStatusRequestMap["frozen_at"] = d.Get("frozen_at").(string) - hasWorkspaceStatus = true - } - if _, ok := d.GetOk("frozen_by"); ok { - workspaceStatusRequestMap["frozen_by"] = d.Get("frozen_by").(string) - hasWorkspaceStatus = true - } - if _, ok := d.GetOk("locked"); ok { - workspaceStatusRequestMap["locked"] = d.Get("locked").(bool) - hasWorkspaceStatus = true - } - if _, ok := d.GetOk("locked_by"); ok { - workspaceStatusRequestMap["locked_by"] = d.Get("locked_by").(string) - hasWorkspaceStatus = true - } - if _, ok := d.GetOk("locked_time"); ok { - workspaceStatusRequestMap["locked_time"] = d.Get("locked_time").(string) - hasWorkspaceStatus = true - } - if hasWorkspaceStatus { - workspaceStatus := resourceIBMSchematicsWorkspaceMapToWorkspaceStatusRequest(workspaceStatusRequestMap) - createWorkspaceOptions.SetWorkspaceStatus(&workspaceStatus) - } - - if _, ok := d.GetOk("x_github_token"); ok { - createWorkspaceOptions.SetXGithubToken(d.Get("x_github_token").(string)) - } - - workspaceResponse, response, err := schematicsClient.CreateWorkspaceWithContext(context, createWorkspaceOptions) - if err != nil { - log.Printf("[DEBUG] CreateWorkspaceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(*workspaceResponse.ID) - - return resourceIBMSchematicsWorkspaceRead(context, d, meta) -} - -func resourceIBMSchematicsWorkspaceMapToCatalogRef(catalogRefMap map[string]interface{}) schematicsv1.CatalogRef { - catalogRef := schematicsv1.CatalogRef{} - - if catalogRefMap["dry_run"] != nil { - catalogRef.DryRun = core.BoolPtr(catalogRefMap["dry_run"].(bool)) - } - if catalogRefMap["item_icon_url"] != nil { - catalogRef.ItemIconURL = core.StringPtr(catalogRefMap["item_icon_url"].(string)) - } - if catalogRefMap["item_id"] != nil { - catalogRef.ItemID = core.StringPtr(catalogRefMap["item_id"].(string)) - } - if catalogRefMap["item_name"] != nil { - catalogRef.ItemName = core.StringPtr(catalogRefMap["item_name"].(string)) - } - if catalogRefMap["item_readme_url"] != nil { - catalogRef.ItemReadmeURL = core.StringPtr(catalogRefMap["item_readme_url"].(string)) - } - if catalogRefMap["item_url"] != nil { - catalogRef.ItemURL = core.StringPtr(catalogRefMap["item_url"].(string)) - } - if catalogRefMap["launch_url"] != nil { - catalogRef.LaunchURL = core.StringPtr(catalogRefMap["launch_url"].(string)) - } - if catalogRefMap["offering_version"] != nil { - catalogRef.OfferingVersion = core.StringPtr(catalogRefMap["offering_version"].(string)) - } - - return catalogRef -} - -func resourceIBMSchematicsWorkspaceMapToSharedTargetData(sharedTargetDataMap map[string]interface{}) schematicsv1.SharedTargetData { - sharedTargetData := schematicsv1.SharedTargetData{} - - if sharedTargetDataMap["cluster_created_on"] != nil { - sharedTargetData.ClusterCreatedOn = core.StringPtr(sharedTargetDataMap["cluster_created_on"].(string)) - } - if sharedTargetDataMap["cluster_id"] != nil { - sharedTargetData.ClusterID = core.StringPtr(sharedTargetDataMap["cluster_id"].(string)) - } - if sharedTargetDataMap["cluster_name"] != nil { - sharedTargetData.ClusterName = core.StringPtr(sharedTargetDataMap["cluster_name"].(string)) - } - if sharedTargetDataMap["cluster_type"] != nil { - sharedTargetData.ClusterType = core.StringPtr(sharedTargetDataMap["cluster_type"].(string)) - } - if sharedTargetDataMap["entitlement_keys"] != nil { - entitlementKeys := []interface{}{} - for _, entitlementKeysItem := range sharedTargetDataMap["entitlement_keys"].([]interface{}) { - entitlementKeys = append(entitlementKeys, entitlementKeysItem.(interface{})) - } - sharedTargetData.EntitlementKeys = entitlementKeys - } - if sharedTargetDataMap["namespace"] != nil { - sharedTargetData.Namespace = core.StringPtr(sharedTargetDataMap["namespace"].(string)) - } - if sharedTargetDataMap["region"] != nil { - sharedTargetData.Region = core.StringPtr(sharedTargetDataMap["region"].(string)) - } - if sharedTargetDataMap["resource_group_id"] != nil { - sharedTargetData.ResourceGroupID = core.StringPtr(sharedTargetDataMap["resource_group_id"].(string)) - } - if sharedTargetDataMap["worker_count"] != nil { - sharedTargetData.WorkerCount = core.Int64Ptr(int64(sharedTargetDataMap["worker_count"].(int))) - } - if sharedTargetDataMap["worker_machine_type"] != nil { - sharedTargetData.WorkerMachineType = core.StringPtr(sharedTargetDataMap["worker_machine_type"].(string)) - } - - return sharedTargetData -} - -func resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap map[string]interface{}) schematicsv1.TemplateSourceDataRequest { - templateSourceDataRequest := schematicsv1.TemplateSourceDataRequest{} - - if templateSourceDataRequestMap["env_values"] != nil { - envValues := []interface{}{} - for _, envValuesItem := range templateSourceDataRequestMap["env_values"].([]interface{}) { - envValues = append(envValues, envValuesItem.(interface{})) - } - templateSourceDataRequest.EnvValues = envValues - } - if templateSourceDataRequestMap["folder"] != nil { - templateSourceDataRequest.Folder = core.StringPtr(templateSourceDataRequestMap["folder"].(string)) - } - if templateSourceDataRequestMap["init_state_file"] != nil { - templateSourceDataRequest.InitStateFile = core.StringPtr(templateSourceDataRequestMap["init_state_file"].(string)) - } - if templateSourceDataRequestMap["type"] != nil { - templateSourceDataRequest.Type = core.StringPtr(templateSourceDataRequestMap["type"].(string)) - } - if templateSourceDataRequestMap["uninstall_script_name"] != nil { - templateSourceDataRequest.UninstallScriptName = core.StringPtr(templateSourceDataRequestMap["uninstall_script_name"].(string)) - } - if templateSourceDataRequestMap["values"] != nil { - templateSourceDataRequest.Values = core.StringPtr(templateSourceDataRequestMap["values"].(string)) - } - if templateSourceDataRequestMap["values_metadata"] != nil { - valuesMetadata := []interface{}{} - for _, valuesMetadataItem := range templateSourceDataRequestMap["values_metadata"].([]interface{}) { - valuesMetadata = append(valuesMetadata, valuesMetadataItem.(interface{})) - } - templateSourceDataRequest.ValuesMetadata = valuesMetadata - } - if templateSourceDataRequestMap["variablestore"] != nil { - variablestore := []schematicsv1.WorkspaceVariableRequest{} - for _, variablestoreItem := range templateSourceDataRequestMap["variablestore"].([]interface{}) { - variablestoreItemModel := resourceIBMSchematicsWorkspaceMapToWorkspaceVariableRequest(variablestoreItem.(map[string]interface{})) - variablestore = append(variablestore, variablestoreItemModel) - } - templateSourceDataRequest.Variablestore = variablestore - } - - return templateSourceDataRequest -} - -func resourceIBMSchematicsWorkspaceMapToWorkspaceVariableRequest(workspaceVariableRequestMap map[string]interface{}) schematicsv1.WorkspaceVariableRequest { - workspaceVariableRequest := schematicsv1.WorkspaceVariableRequest{} - - if workspaceVariableRequestMap["description"] != nil { - workspaceVariableRequest.Description = core.StringPtr(workspaceVariableRequestMap["description"].(string)) - } - if workspaceVariableRequestMap["name"] != nil { - workspaceVariableRequest.Name = core.StringPtr(workspaceVariableRequestMap["name"].(string)) - } - if workspaceVariableRequestMap["secure"] != nil { - workspaceVariableRequest.Secure = core.BoolPtr(workspaceVariableRequestMap["secure"].(bool)) - } - if workspaceVariableRequestMap["type"] != nil { - workspaceVariableRequest.Type = core.StringPtr(workspaceVariableRequestMap["type"].(string)) - } - if workspaceVariableRequestMap["use_default"] != nil { - workspaceVariableRequest.UseDefault = core.BoolPtr(workspaceVariableRequestMap["use_default"].(bool)) - } - if workspaceVariableRequestMap["value"] != nil { - workspaceVariableRequest.Value = core.StringPtr(workspaceVariableRequestMap["value"].(string)) - } - - return workspaceVariableRequest -} - -func resourceIBMSchematicsWorkspaceMapToTemplateRepoRequest(templateRepoRequestMap map[string]interface{}) schematicsv1.TemplateRepoRequest { - templateRepoRequest := schematicsv1.TemplateRepoRequest{} - - if templateRepoRequestMap["branch"] != nil { - templateRepoRequest.Branch = core.StringPtr(templateRepoRequestMap["branch"].(string)) - } - if templateRepoRequestMap["release"] != nil { - templateRepoRequest.Release = core.StringPtr(templateRepoRequestMap["release"].(string)) - } - if templateRepoRequestMap["repo_sha_value"] != nil { - templateRepoRequest.RepoShaValue = core.StringPtr(templateRepoRequestMap["repo_sha_value"].(string)) - } - if templateRepoRequestMap["repo_url"] != nil { - templateRepoRequest.RepoURL = core.StringPtr(templateRepoRequestMap["repo_url"].(string)) - } - if templateRepoRequestMap["url"] != nil { - templateRepoRequest.URL = core.StringPtr(templateRepoRequestMap["url"].(string)) - } - - return templateRepoRequest -} - -func resourceIBMSchematicsWorkspaceMapToTemplateRepoUpdateRequest(templateRepoUpdateRequestMap map[string]interface{}) schematicsv1.TemplateRepoUpdateRequest { - templateRepoUpdateRequest := schematicsv1.TemplateRepoUpdateRequest{} - - if templateRepoUpdateRequestMap["branch"] != nil { - templateRepoUpdateRequest.Branch = core.StringPtr(templateRepoUpdateRequestMap["branch"].(string)) - } - if templateRepoUpdateRequestMap["release"] != nil { - templateRepoUpdateRequest.Release = core.StringPtr(templateRepoUpdateRequestMap["release"].(string)) - } - if templateRepoUpdateRequestMap["repo_sha_value"] != nil { - templateRepoUpdateRequest.RepoShaValue = core.StringPtr(templateRepoUpdateRequestMap["repo_sha_value"].(string)) - } - if templateRepoUpdateRequestMap["repo_url"] != nil { - templateRepoUpdateRequest.RepoURL = core.StringPtr(templateRepoUpdateRequestMap["repo_url"].(string)) - } - if templateRepoUpdateRequestMap["url"] != nil { - templateRepoUpdateRequest.URL = core.StringPtr(templateRepoUpdateRequestMap["url"].(string)) - } - - return templateRepoUpdateRequest -} - -func resourceIBMSchematicsWorkspaceMapToWorkspaceStatusRequest(workspaceStatusRequestMap map[string]interface{}) schematicsv1.WorkspaceStatusRequest { - workspaceStatusRequest := schematicsv1.WorkspaceStatusRequest{} - - if workspaceStatusRequestMap["frozen"] != nil { - workspaceStatusRequest.Frozen = core.BoolPtr(workspaceStatusRequestMap["frozen"].(bool)) - } - if workspaceStatusRequestMap["frozen_at"] != nil { - frozenAt, err := strfmt.ParseDateTime(workspaceStatusRequestMap["frozen_at"].(string)) - if err != nil { - workspaceStatusRequest.FrozenAt = &frozenAt - } - } - if workspaceStatusRequestMap["frozen_by"] != nil { - workspaceStatusRequest.FrozenBy = core.StringPtr(workspaceStatusRequestMap["frozen_by"].(string)) - } - if workspaceStatusRequestMap["locked"] != nil { - workspaceStatusRequest.Locked = core.BoolPtr(workspaceStatusRequestMap["locked"].(bool)) - } - if workspaceStatusRequestMap["locked_by"] != nil { - workspaceStatusRequest.LockedBy = core.StringPtr(workspaceStatusRequestMap["locked_by"].(string)) - } - if workspaceStatusRequestMap["locked_time"] != nil { - lockedTime, err := strfmt.ParseDateTime(workspaceStatusRequestMap["locked_time"].(string)) - if err != nil { - workspaceStatusRequest.LockedTime = &lockedTime - } - } - - return workspaceStatusRequest -} - -func resourceIBMSchematicsWorkspaceMapToWorkspaceStatusUpdateRequest(workspaceStatusUpdateRequestMap map[string]interface{}) schematicsv1.WorkspaceStatusUpdateRequest { - workspaceStatusUpdateRequest := schematicsv1.WorkspaceStatusUpdateRequest{} - - if workspaceStatusUpdateRequestMap["frozen"] != nil { - workspaceStatusUpdateRequest.Frozen = core.BoolPtr(workspaceStatusUpdateRequestMap["frozen"].(bool)) - } - if workspaceStatusUpdateRequestMap["frozen_at"] != nil { - frozenAt := workspaceStatusUpdateRequestMap["frozen_at"].(strfmt.DateTime) - workspaceStatusUpdateRequest.FrozenAt = &frozenAt - } - if workspaceStatusUpdateRequestMap["frozen_by"] != nil { - workspaceStatusUpdateRequest.FrozenBy = core.StringPtr(workspaceStatusUpdateRequestMap["frozen_by"].(string)) - } - if workspaceStatusUpdateRequestMap["locked"] != nil { - workspaceStatusUpdateRequest.Locked = core.BoolPtr(workspaceStatusUpdateRequestMap["locked"].(bool)) - } - if workspaceStatusUpdateRequestMap["locked_by"] != nil { - workspaceStatusUpdateRequest.LockedBy = core.StringPtr(workspaceStatusUpdateRequestMap["locked_by"].(string)) - } - if workspaceStatusUpdateRequestMap["locked_time"] != nil { - lockedTime := workspaceStatusUpdateRequestMap["locked_time"].(strfmt.DateTime) - workspaceStatusUpdateRequest.LockedTime = &lockedTime - } - - return workspaceStatusUpdateRequest -} - -func resourceIBMSchematicsWorkspaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} - - getWorkspaceOptions.SetWID(d.Id()) - - workspaceResponse, response, err := schematicsClient.GetWorkspaceWithContext(context, getWorkspaceOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetWorkspaceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - if workspaceResponse.AppliedShareddataIds != nil { - if err = d.Set("applied_shareddata_ids", workspaceResponse.AppliedShareddataIds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting applied_shareddata_ids: %s", err)) - } - } - if workspaceResponse.CatalogRef != nil { - catalogRefMap := resourceIBMSchematicsWorkspaceCatalogRefToMap(*workspaceResponse.CatalogRef) - if err = d.Set("catalog_ref", []map[string]interface{}{catalogRefMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting catalog_ref: %s", err)) - } - } - if err = d.Set("description", workspaceResponse.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) - } - if err = d.Set("location", workspaceResponse.Location); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) - } - if err = d.Set("name", workspaceResponse.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) - } - if err = d.Set("resource_group", workspaceResponse.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) - } - if _, ok := d.GetOk("shared_data"); ok { - if workspaceResponse.SharedData != nil { - sharedDataMap := resourceIBMSchematicsWorkspaceSharedTargetDataResponseToMap(*workspaceResponse.SharedData) - if err = d.Set("shared_data", []map[string]interface{}{sharedDataMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error reading shared_data: %s", err)) - } - } - } - if workspaceResponse.Tags != nil { - if err = d.Set("tags", workspaceResponse.Tags); err != nil { - return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) - } - } - if workspaceResponse.TemplateData != nil { - templateData := []map[string]interface{}{} - for _, templateDataItem := range workspaceResponse.TemplateData { - templateDataItemMap := resourceIBMSchematicsWorkspaceTemplateSourceDataResponseToMap(templateDataItem) - templateData = append(templateData, templateDataItemMap) - } - if err = d.Set("template_env_settings", templateData[0]["env_values"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading env_values: %s", err)) - } - if err = d.Set("template_git_folder", templateData[0]["folder"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading folder: %s", err)) - } - if err = d.Set("template_init_state_file", templateData[0]["init_state_file"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading init_state_file: %s", err)) - } - if err = d.Set("template_type", templateData[0]["type"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading type: %s", err)) - } - if err = d.Set("template_uninstall_script_name", templateData[0]["uninstall_script_name"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading uninstall_script_name: %s", err)) - } - if err = d.Set("template_values", templateData[0]["values"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading values: %s", err)) - } - if err = d.Set("template_values_metadata", templateData[0]["values_metadata"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading values_metadata: %s", err)) - } - if err = d.Set("template_inputs", templateData[0]["variablestore"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading variablestore: %s", err)) - } - - } - if err = d.Set("template_ref", workspaceResponse.TemplateRef); err != nil { - return diag.FromErr(fmt.Errorf("Error setting template_ref: %s", err)) - } - if workspaceResponse.TemplateRepo != nil { - templateRepoMap := resourceIBMSchematicsWorkspaceTemplateRepoResponseToMap(*workspaceResponse.TemplateRepo) - if err = d.Set("template_git_branch", templateRepoMap["branch"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading branch: %s", err)) - } - if err = d.Set("template_git_release", templateRepoMap["release"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading release: %s", err)) - } - if err = d.Set("template_git_repo_sha_value", templateRepoMap["repo_sha_value"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading repo_sha_value: %s", err)) - } - if err = d.Set("template_git_repo_url", templateRepoMap["repo_url"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading repo_url: %s", err)) - } - if err = d.Set("template_git_url", templateRepoMap["url"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading url: %s", err)) - } - if err = d.Set("template_git_has_uploadedgitrepotar", templateRepoMap["has_uploadedgitrepotar"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading has_uploadedgitrepotar: %s", err)) - } - } - /*if workspaceResponse.Type != nil { - if err = d.Set("template_type", workspaceResponse.Type); err != nil { - return fmt.Errorf("Error reading type: %s", err) - } - }*/ - if workspaceResponse.WorkspaceStatus != nil { - workspaceStatusMap := resourceIBMSchematicsWorkspaceWorkspaceStatusResponseToMap(*workspaceResponse.WorkspaceStatus) - if err = d.Set("frozen", workspaceStatusMap["frozen"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen: %s", err)) - } - if err = d.Set("frozen_at", workspaceStatusMap["frozen_at"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen_at: %s", err)) - } - if err = d.Set("frozen_by", workspaceStatusMap["frozen_by"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading frozen_by: %s", err)) - } - if err = d.Set("locked", workspaceStatusMap["locked"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked: %s", err)) - } - if err = d.Set("locked_by", workspaceStatusMap["locked_by"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked_by: %s", err)) - } - if err = d.Set("locked_time", workspaceStatusMap["locked_time"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading locked_time: %s", err)) - } - } - if workspaceResponse.CreatedAt != nil { - if err = d.Set("created_at", workspaceResponse.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error reading created_at: %s", err)) - } - } - if err = d.Set("created_by", workspaceResponse.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) - } - if err = d.Set("crn", workspaceResponse.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error reading crn: %s", err)) - } - if workspaceResponse.LastHealthCheckAt != nil { - if err = d.Set("last_health_check_at", workspaceResponse.LastHealthCheckAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error reading last_health_check_at: %s", err)) - } - } - if workspaceResponse.RuntimeData != nil { - runtimeData := []map[string]interface{}{} - for _, runtimeDataItem := range workspaceResponse.RuntimeData { - runtimeDataItemMap := resourceIBMSchematicsWorkspaceTemplateRunTimeDataResponseToMap(runtimeDataItem) - runtimeData = append(runtimeData, runtimeDataItemMap) - } - if err = d.Set("runtime_data", runtimeData); err != nil { - return diag.FromErr(fmt.Errorf("Error setting runtime_data: %s", err)) - } - } - if err = d.Set("status", workspaceResponse.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) - } - if workspaceResponse.UpdatedAt != nil { - if err = d.Set("updated_at", workspaceResponse.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error reading updated_at: %s", err)) - } - } - if err = d.Set("updated_by", workspaceResponse.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) - } - if workspaceResponse.WorkspaceStatusMsg != nil { - workspaceStatusMsgMap := resourceIBMSchematicsWorkspaceWorkspaceStatusMessageToMap(*workspaceResponse.WorkspaceStatusMsg) - if err = d.Set("status_code", workspaceStatusMsgMap["status_code"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading status_code: %s", err)) - } - if err = d.Set("status_msg", workspaceStatusMsgMap["status_msg"]); err != nil { - return diag.FromErr(fmt.Errorf("Error reading status_msg: %s", err)) - } - } - - return nil -} - -func resourceIBMSchematicsWorkspaceCatalogRefToMap(catalogRef schematicsv1.CatalogRef) map[string]interface{} { - catalogRefMap := map[string]interface{}{} - - catalogRefMap["dry_run"] = catalogRef.DryRun - catalogRefMap["item_icon_url"] = catalogRef.ItemIconURL - catalogRefMap["item_id"] = catalogRef.ItemID - catalogRefMap["item_name"] = catalogRef.ItemName - catalogRefMap["item_readme_url"] = catalogRef.ItemReadmeURL - catalogRefMap["item_url"] = catalogRef.ItemURL - catalogRefMap["launch_url"] = catalogRef.LaunchURL - catalogRefMap["offering_version"] = catalogRef.OfferingVersion - - return catalogRefMap -} - -func resourceIBMSchematicsWorkspaceSharedTargetDataToMap(sharedTargetData schematicsv1.SharedTargetData) map[string]interface{} { - sharedTargetDataMap := map[string]interface{}{} - - sharedTargetDataMap["cluster_created_on"] = sharedTargetData.ClusterCreatedOn - sharedTargetDataMap["cluster_id"] = sharedTargetData.ClusterID - sharedTargetDataMap["cluster_name"] = sharedTargetData.ClusterName - sharedTargetDataMap["cluster_type"] = sharedTargetData.ClusterType - if sharedTargetData.EntitlementKeys != nil { - entitlementKeys := []interface{}{} - for _, entitlementKeysItem := range sharedTargetData.EntitlementKeys { - entitlementKeys = append(entitlementKeys, entitlementKeysItem) - } - sharedTargetDataMap["entitlement_keys"] = entitlementKeys - } - sharedTargetDataMap["namespace"] = sharedTargetData.Namespace - sharedTargetDataMap["region"] = sharedTargetData.Region - sharedTargetDataMap["resource_group_id"] = sharedTargetData.ResourceGroupID - sharedTargetDataMap["worker_count"] = intValue(sharedTargetData.WorkerCount) - sharedTargetDataMap["worker_machine_type"] = sharedTargetData.WorkerMachineType - - return sharedTargetDataMap -} - -func resourceIBMSchematicsWorkspaceSharedTargetDataResponseToMap(sharedTargetData schematicsv1.SharedTargetDataResponse) map[string]interface{} { - sharedTargetDataResponseMap := map[string]interface{}{} - - sharedTargetDataResponseMap["cluster_id"] = sharedTargetData.ClusterID - sharedTargetDataResponseMap["cluster_name"] = sharedTargetData.ClusterName - if sharedTargetData.EntitlementKeys != nil { - entitlementKeys := []interface{}{} - for _, entitlementKeysItem := range sharedTargetData.EntitlementKeys { - entitlementKeys = append(entitlementKeys, entitlementKeysItem) - } - sharedTargetDataResponseMap["entitlement_keys"] = entitlementKeys - } - sharedTargetDataResponseMap["namespace"] = sharedTargetData.Namespace - sharedTargetDataResponseMap["region"] = sharedTargetData.Region - sharedTargetDataResponseMap["resource_group_id"] = sharedTargetData.ResourceGroupID - - return sharedTargetDataResponseMap -} - -func resourceIBMSchematicsWorkspaceTemplateSourceDataRequestToMap(templateSourceDataRequest schematicsv1.TemplateSourceDataRequest) map[string]interface{} { - templateSourceDataRequestMap := map[string]interface{}{} - - if templateSourceDataRequest.EnvValues != nil { - envValues := []interface{}{} - for _, envValuesItem := range templateSourceDataRequest.EnvValues { - envValues = append(envValues, envValuesItem) - } - templateSourceDataRequestMap["env_values"] = envValues - } - templateSourceDataRequestMap["folder"] = templateSourceDataRequest.Folder - templateSourceDataRequestMap["init_state_file"] = templateSourceDataRequest.InitStateFile - templateSourceDataRequestMap["type"] = templateSourceDataRequest.Type - templateSourceDataRequestMap["uninstall_script_name"] = templateSourceDataRequest.UninstallScriptName - templateSourceDataRequestMap["values"] = templateSourceDataRequest.Values - if templateSourceDataRequest.ValuesMetadata != nil { - valuesMetadata := []interface{}{} - for _, valuesMetadataItem := range templateSourceDataRequest.ValuesMetadata { - valuesMetadata = append(valuesMetadata, valuesMetadataItem) - } - templateSourceDataRequestMap["values_metadata"] = valuesMetadata - } - if templateSourceDataRequest.Variablestore != nil { - variablestore := []map[string]interface{}{} - for _, variablestoreItem := range templateSourceDataRequest.Variablestore { - variablestoreItemMap := resourceIBMSchematicsWorkspaceWorkspaceVariableRequestToMap(variablestoreItem) - variablestore = append(variablestore, variablestoreItemMap) - // TODO: handle Variablestore of type TypeList -- list of non-primitive, not model items - } - templateSourceDataRequestMap["variablestore"] = variablestore - } - - return templateSourceDataRequestMap -} - -func resourceIBMSchematicsWorkspaceTemplateSourceDataResponseToMap(templateSourceDataResponse schematicsv1.TemplateSourceDataResponse) map[string]interface{} { - templateSourceDataResponseMap := map[string]interface{}{} - - if templateSourceDataResponse.EnvValues != nil { - envValues := []map[string]interface{}{} - for _, envValuesItem := range templateSourceDataResponse.EnvValues { - flattenedEnvVals := map[string]interface{}{} - if envValuesItem.Name != nil { - flattenedEnvVals[*envValuesItem.Name] = envValuesItem.Value - } - - envValues = append(envValues, flattenedEnvVals) - } - templateSourceDataResponseMap["env_values"] = envValues - } - if templateSourceDataResponse.Type != nil { - templateSourceDataResponseMap["type"] = templateSourceDataResponse.Type - } - templateSourceDataResponseMap["folder"] = templateSourceDataResponse.Folder - templateSourceDataResponseMap["uninstall_script_name"] = templateSourceDataResponse.UninstallScriptName - templateSourceDataResponseMap["values"] = templateSourceDataResponse.Values - if templateSourceDataResponse.ValuesMetadata != nil { - valuesMetadata := []interface{}{} - for _, valuesMetadataItem := range templateSourceDataResponse.ValuesMetadata { - valuesMetadata = append(valuesMetadata, valuesMetadataItem) - } - templateSourceDataResponseMap["values_metadata"] = valuesMetadata - } - if templateSourceDataResponse.Variablestore != nil { - variablestore := []map[string]interface{}{} - for _, variablestoreItem := range templateSourceDataResponse.Variablestore { - variablestoreItemMap := resourceIBMSchematicsWorkspaceWorkspaceVariableResponseToMap(variablestoreItem) - variablestore = append(variablestore, variablestoreItemMap) - } - templateSourceDataResponseMap["variablestore"] = variablestore - } - - return templateSourceDataResponseMap -} - -func resourceIBMSchematicsWorkspaceWorkspaceVariableRequestToMap(workspaceVariableRequest schematicsv1.WorkspaceVariableRequest) map[string]interface{} { - workspaceVariableRequestMap := map[string]interface{}{} - - workspaceVariableRequestMap["description"] = workspaceVariableRequest.Description - workspaceVariableRequestMap["name"] = workspaceVariableRequest.Name - workspaceVariableRequestMap["secure"] = workspaceVariableRequest.Secure - workspaceVariableRequestMap["type"] = workspaceVariableRequest.Type - workspaceVariableRequestMap["use_default"] = workspaceVariableRequest.UseDefault - workspaceVariableRequestMap["value"] = workspaceVariableRequest.Value - - return workspaceVariableRequestMap -} - -func resourceIBMSchematicsWorkspaceWorkspaceVariableResponseToMap(workspaceVariableResponse schematicsv1.WorkspaceVariableResponse) map[string]interface{} { - workspaceVariableRequestMap := map[string]interface{}{} - - workspaceVariableRequestMap["description"] = workspaceVariableResponse.Description - workspaceVariableRequestMap["name"] = workspaceVariableResponse.Name - workspaceVariableRequestMap["secure"] = workspaceVariableResponse.Secure - workspaceVariableRequestMap["type"] = workspaceVariableResponse.Type - workspaceVariableRequestMap["value"] = workspaceVariableResponse.Value - - return workspaceVariableRequestMap -} - -func resourceIBMSchematicsWorkspaceTemplateRepoRequestToMap(templateRepoRequest schematicsv1.TemplateRepoRequest) map[string]interface{} { - templateRepoRequestMap := map[string]interface{}{} - - templateRepoRequestMap["branch"] = templateRepoRequest.Branch - templateRepoRequestMap["release"] = templateRepoRequest.Release - templateRepoRequestMap["repo_sha_value"] = templateRepoRequest.RepoShaValue - templateRepoRequestMap["repo_url"] = templateRepoRequest.RepoURL - templateRepoRequestMap["url"] = templateRepoRequest.URL - - return templateRepoRequestMap -} - -func resourceIBMSchematicsWorkspaceTemplateRepoResponseToMap(templateRepoResponse schematicsv1.TemplateRepoResponse) map[string]interface{} { - templateRepoResponseMap := map[string]interface{}{} - - templateRepoResponseMap["branch"] = templateRepoResponse.Branch - templateRepoResponseMap["release"] = templateRepoResponse.Release - templateRepoResponseMap["repo_sha_value"] = templateRepoResponse.RepoShaValue - templateRepoResponseMap["repo_url"] = templateRepoResponse.RepoURL - templateRepoResponseMap["url"] = templateRepoResponse.URL - templateRepoResponseMap["has_uploadedgitrepotar"] = templateRepoResponse.HasUploadedgitrepotar - - return templateRepoResponseMap -} - -func resourceIBMSchematicsWorkspaceWorkspaceStatusRequestToMap(workspaceStatusRequest schematicsv1.WorkspaceStatusRequest) map[string]interface{} { - workspaceStatusRequestMap := map[string]interface{}{} - - workspaceStatusRequestMap["frozen"] = workspaceStatusRequest.Frozen - workspaceStatusRequestMap["frozen_at"] = workspaceStatusRequest.FrozenAt.String() - workspaceStatusRequestMap["frozen_by"] = workspaceStatusRequest.FrozenBy - workspaceStatusRequestMap["locked"] = workspaceStatusRequest.Locked - workspaceStatusRequestMap["locked_by"] = workspaceStatusRequest.LockedBy - workspaceStatusRequestMap["locked_time"] = workspaceStatusRequest.LockedTime.String() - - return workspaceStatusRequestMap -} - -func resourceIBMSchematicsWorkspaceWorkspaceStatusResponseToMap(workspaceStatusResponse schematicsv1.WorkspaceStatusResponse) map[string]interface{} { - workspaceStatusResponseMap := map[string]interface{}{} - - workspaceStatusResponseMap["frozen"] = workspaceStatusResponse.Frozen - if workspaceStatusResponse.FrozenAt != nil { - workspaceStatusResponseMap["frozen_at"] = workspaceStatusResponse.FrozenAt.String() - } - workspaceStatusResponseMap["frozen_by"] = workspaceStatusResponse.FrozenBy - workspaceStatusResponseMap["locked"] = workspaceStatusResponse.Locked - workspaceStatusResponseMap["locked_by"] = workspaceStatusResponse.LockedBy - if workspaceStatusResponse.LockedTime != nil { - workspaceStatusResponseMap["locked_time"] = workspaceStatusResponse.LockedTime.String() - } - - return workspaceStatusResponseMap -} - -func resourceIBMSchematicsWorkspaceTemplateRunTimeDataResponseToMap(templateRunTimeDataResponse schematicsv1.TemplateRunTimeDataResponse) map[string]interface{} { - templateRunTimeDataResponseMap := map[string]interface{}{} - - templateRunTimeDataResponseMap["engine_cmd"] = templateRunTimeDataResponse.EngineCmd - templateRunTimeDataResponseMap["engine_name"] = templateRunTimeDataResponse.EngineName - templateRunTimeDataResponseMap["engine_version"] = templateRunTimeDataResponse.EngineVersion - templateRunTimeDataResponseMap["id"] = templateRunTimeDataResponse.ID - templateRunTimeDataResponseMap["log_store_url"] = templateRunTimeDataResponse.LogStoreURL - if templateRunTimeDataResponse.OutputValues != nil { - outputValues := []interface{}{} - for _, outputValuesItem := range templateRunTimeDataResponse.OutputValues { - outputValues = append(outputValues, outputValuesItem) - } - templateRunTimeDataResponseMap["output_values"] = outputValues - } - if templateRunTimeDataResponse.Resources != nil { - resources := []interface{}{} - for _, resourcesItem := range templateRunTimeDataResponse.Resources { - resources = append(resources, resourcesItem) - } - templateRunTimeDataResponseMap["resources"] = resources - } - templateRunTimeDataResponseMap["state_store_url"] = templateRunTimeDataResponse.StateStoreURL - - return templateRunTimeDataResponseMap -} - -func resourceIBMSchematicsWorkspaceWorkspaceStatusMessageToMap(workspaceStatusMessage schematicsv1.WorkspaceStatusMessage) map[string]interface{} { - workspaceStatusMessageMap := map[string]interface{}{} - - workspaceStatusMessageMap["status_code"] = workspaceStatusMessage.StatusCode - workspaceStatusMessageMap["status_msg"] = workspaceStatusMessage.StatusMsg - - return workspaceStatusMessageMap -} - -func resourceIBMSchematicsWorkspaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - updateWorkspaceOptions := &schematicsv1.UpdateWorkspaceOptions{} - - updateWorkspaceOptions.SetWID(d.Id()) - - hasChange := false - - if d.HasChange("catalog_ref") { - catalogRefAttr := d.Get("catalog_ref").([]interface{}) - if len(catalogRefAttr) > 0 { - catalogRef := resourceIBMSchematicsWorkspaceMapToCatalogRef(d.Get("catalog_ref.0").(map[string]interface{})) - updateWorkspaceOptions.SetCatalogRef(&catalogRef) - hasChange = true - } - } - if d.HasChange("description") { - updateWorkspaceOptions.SetDescription(d.Get("description").(string)) - hasChange = true - } - if d.HasChange("name") { - updateWorkspaceOptions.SetName(d.Get("name").(string)) - hasChange = true - } - if d.HasChange("shared_data") { - sharedDataAttr := d.Get("shared_data").([]interface{}) - if len(sharedDataAttr) > 0 { - sharedData := resourceIBMSchematicsWorkspaceMapToSharedTargetData(d.Get("shared_data.0").(map[string]interface{})) - updateWorkspaceOptions.SetSharedData(&sharedData) - hasChange = true - } - } - if d.HasChange("tags") { - updateWorkspaceOptions.SetTags(expandStringList(d.Get("tags").([]interface{}))) - hasChange = true - } - - var templateData []schematicsv1.TemplateSourceDataRequest - - templateSourceDataRequestMap := map[string]interface{}{} - hasTemplateData := false - - if d.HasChange("template_env_settings") { - templateSourceDataRequestMap["env_values"] = d.Get("template_env_settings").([]interface{}) - hasTemplateData = true - } - if d.HasChange("template_git_folder") { - templateSourceDataRequestMap["folder"] = d.Get("template_git_folder").(string) - hasTemplateData = true - } - if d.HasChange("template_init_state_file") { - templateSourceDataRequestMap["init_state_file"] = d.Get("template_init_state_file").(string) - hasTemplateData = true - } - if d.HasChange("template_type") { - templateSourceDataRequestMap["type"] = d.Get("template_type").(string) - updateWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) - hasTemplateData = true - } - if d.HasChange("template_uninstall_script_name") { - templateSourceDataRequestMap["uninstall_script_name"] = d.Get("template_uninstall_script_name").(string) - hasTemplateData = true - } - if d.HasChange("template_values") { - templateSourceDataRequestMap["values"] = d.Get("template_values").(string) - hasTemplateData = true - } - if d.HasChange("template_values_metadata") { - templateSourceDataRequestMap["values_metadata"] = d.Get("template_values_metadata").([]interface{}) - hasTemplateData = true - } - if d.HasChange("template_inputs") { - templateSourceDataRequestMap["variablestore"] = d.Get("template_inputs").([]interface{}) - hasTemplateData = true - } - if hasTemplateData { - templateDataItem := resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap) - templateData = append(templateData, templateDataItem) - updateWorkspaceOptions.SetTemplateData(templateData) - hasChange = true - } - - templateRepoRequestMap := map[string]interface{}{} - hasTemplateRepo := false - if d.HasChange("template_git_branch") { - templateRepoRequestMap["branch"] = d.Get("template_git_branch").(bool) - hasTemplateRepo = true - } - if d.HasChange("template_git_release") { - templateRepoRequestMap["release"] = d.Get("template_git_release").(string) - hasTemplateRepo = true - } - if d.HasChange("template_git_repo_sha_value") { - templateRepoRequestMap["repo_sha_value"] = d.Get("template_git_repo_sha_value").(string) - hasTemplateRepo = true - } - if d.HasChange("template_git_repo_url") { - templateRepoRequestMap["repo_url"] = d.Get("template_git_repo_url").(string) - hasTemplateRepo = true - } - if d.HasChange("template_git_url") { - templateRepoRequestMap["url"] = d.Get("template_git_url").(string) - hasTemplateRepo = true - } - if d.HasChange("template_git_has_uploadedgitrepotar") { - templateRepoRequestMap["has_uploadedgitrepotar"] = d.Get("template_git_has_uploadedgitrepotar").(string) - hasTemplateRepo = true - } - if hasTemplateRepo { - templateRepo := resourceIBMSchematicsWorkspaceMapToTemplateRepoUpdateRequest(templateRepoRequestMap) - updateWorkspaceOptions.SetTemplateRepo(&templateRepo) - hasChange = true - } - - if d.HasChange("template_type") { - updateWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) - hasChange = true - } - - workspaceStatusRequestMap := map[string]interface{}{} - workspaceStatus := false - if d.HasChange("frozen") { - workspaceStatusRequestMap["frozen"] = d.Get("frozen").(bool) - workspaceStatus = true - } - if d.HasChange("frozen_at") { - workspaceStatusRequestMap["frozen_at"] = d.Get("frozen_at").(string) - workspaceStatus = true - } - if d.HasChange("frozen_by") { - workspaceStatusRequestMap["frozen_by"] = d.Get("frozen_by").(string) - workspaceStatus = true - } - if d.HasChange("locked") { - workspaceStatusRequestMap["locked"] = d.Get("locked").(bool) - workspaceStatus = true - } - if d.HasChange("locked_by") { - workspaceStatusRequestMap["locked_by"] = d.Get("locked_by").(string) - workspaceStatus = true - } - if d.HasChange("locked_time") { - workspaceStatusRequestMap["locked_time"] = d.Get("locked_time").(string) - workspaceStatus = true - } - if workspaceStatus { - workspaceStatus := resourceIBMSchematicsWorkspaceMapToWorkspaceStatusUpdateRequest(workspaceStatusRequestMap) - updateWorkspaceOptions.SetWorkspaceStatus(&workspaceStatus) - hasChange = true - } - - if hasChange { - _, response, err := schematicsClient.UpdateWorkspaceWithContext(context, updateWorkspaceOptions) - if err != nil { - log.Printf("[DEBUG] UpdateWorkspaceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - } - - return resourceIBMSchematicsWorkspaceRead(context, d, meta) -} - -func resourceIBMSchematicsWorkspaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schematicsClient, err := meta.(ClientSession).SchematicsV1() - if err != nil { - return diag.FromErr(err) - } - - session, err := meta.(ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - - deleteWorkspaceOptions := &schematicsv1.DeleteWorkspaceOptions{} - - deleteWorkspaceOptions.SetWID(d.Id()) - - iamRefreshToken := session.Config.IAMRefreshToken - deleteWorkspaceOptions.SetRefreshToken(iamRefreshToken) - - _, response, err := schematicsClient.DeleteWorkspaceWithContext(context, deleteWorkspaceOptions) - if err != nil { - log.Printf("[DEBUG] DeleteWorkspaceWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId("") - - return nil -} diff --git a/ibm/resource_ibm_schematics_workspace_test.go b/ibm/resource_ibm_schematics_workspace_test.go deleted file mode 100644 index 7dd2d0f9a..000000000 --- a/ibm/resource_ibm_schematics_workspace_test.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM/schematics-go-sdk/schematicsv1" -) - -func TestAccIBMSchematicsWorkspaceBasic(t *testing.T) { - var conf schematicsv1.WorkspaceResponse - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSchematicsWorkspaceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSchematicsWorkspaceConfigBasic(), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), - ), - }, - }, - }) -} - -func TestAccIBMSchematicsWorkspaceAllArgs(t *testing.T) { - var conf schematicsv1.WorkspaceResponse - description := fmt.Sprintf("tf-acc-test-schematics-all-args_%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-acc-test-schematics_%d", acctest.RandIntRange(10, 100)) - templateType := "terraform_v0.12.20" - - descriptionUpdate := fmt.Sprintf("description_%d", acctest.RandIntRange(10, 100)) - nameUpdate := fmt.Sprintf("tf-acc-test-schematics_%d", acctest.RandIntRange(10, 100)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckIBMSchematicsWorkspaceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSchematicsWorkspaceConfig(description, name), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", description), - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", name), - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), - ), - }, - resource.TestStep{ - Config: testAccCheckIBMSchematicsWorkspaceConfig(descriptionUpdate, nameUpdate), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", descriptionUpdate), - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", nameUpdate), - resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), - resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), - ), - }, - resource.TestStep{ - ResourceName: "ibm_schematics_workspace.schematics_workspace", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckIBMSchematicsWorkspaceConfigBasic() string { - return fmt.Sprintf(` - - resource "ibm_schematics_workspace" "schematics_workspace" { - description = "tf-acc-test-schematics" - name = "tf-acc-test-schematics" - location = "us-east" - resource_group = "default" - template_type = "terraform_v0.12.20" - } - `) -} - -func testAccCheckIBMSchematicsWorkspaceConfig(description string, name string) string { - return fmt.Sprintf(` - - resource "ibm_schematics_workspace" "schematics_workspace" { - description = "%s" - location = "us-east" - name = "%s" - resource_group = "default" - template_type = "terraform_v0.12.20" - } - `, description, name) -} - -func testAccCheckIBMSchematicsWorkspaceExists(n string, obj schematicsv1.WorkspaceResponse) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() - if err != nil { - return err - } - - getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} - - getWorkspaceOptions.SetWID(rs.Primary.ID) - - workspaceResponse, _, err := schematicsClient.GetWorkspace(getWorkspaceOptions) - if err != nil { - return err - } - - obj = *workspaceResponse - return nil - } -} - -func testAccCheckIBMSchematicsWorkspaceDestroy(s *terraform.State) error { - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_schematics_workspace" { - continue - } - - getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} - - getWorkspaceOptions.SetWID(rs.Primary.ID) - - // Try to find the key - _, response, err := schematicsClient.GetWorkspace(getWorkspaceOptions) - - if err == nil { - return fmt.Errorf("schematics_workspace still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for schematics_workspace (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/ibm/resource_ibm_space.go b/ibm/resource_ibm_space.go deleted file mode 100644 index c0735442d..000000000 --- a/ibm/resource_ibm_space.go +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/helpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceIBMSpace() *schema.Resource { - return &schema.Resource{ - Create: resourceIBMSpaceCreate, - Read: resourceIBMSpaceRead, - Update: resourceIBMSpaceUpdate, - Delete: resourceIBMSpaceDelete, - Exists: resourceIBMSpaceExists, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name for the space", - }, - "org": { - Description: "The org this space belongs to", - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "auditors": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have auditor role in this space, ex - user@example.com", - }, - "managers": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have manager role in this space, ex - user@example.com", - }, - "developers": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "The IBMID of the users who will have developer role in this space, ex - user@example.com", - }, - "space_quota": { - Description: "The name of the Space Quota Definition", - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - }, - } -} - -func resourceIBMSpaceCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - org := d.Get("org").(string) - name := d.Get("name").(string) - - req := mccpv2.SpaceCreateRequest{ - Name: name, - } - - orgFields, err := cfClient.Organizations().FindByName(org, BluemixRegion) - if err != nil { - return fmt.Errorf("Error retrieving org: %s", err) - } - req.OrgGUID = orgFields.GUID - - if spaceQuota, ok := d.GetOk("space_quota"); ok { - quota, err := cfClient.SpaceQuotas().FindByName(spaceQuota.(string), orgFields.GUID) - if err != nil { - return fmt.Errorf("Error retrieving space quota: %s", err) - } - req.SpaceQuotaGUID = quota.GUID - } - - spaceAPI := cfClient.Spaces() - space, err := spaceAPI.Create(req) - if err != nil { - return fmt.Errorf("Error creating space: %s", err) - } - - spaceGUID := space.Metadata.GUID - d.SetId(spaceGUID) - - if developerSet := d.Get("developers").(*schema.Set); len(developerSet.List()) > 0 { - developers := expandStringList(developerSet.List()) - for _, d := range developers { - _, err := spaceAPI.AssociateDeveloper(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating developer %s with space %s : %s", d, spaceGUID, err) - } - } - } - - if auditorSet := d.Get("auditors").(*schema.Set); len(auditorSet.List()) > 0 { - auditors := expandStringList(auditorSet.List()) - for _, d := range auditors { - _, err := spaceAPI.AssociateAuditor(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating auditor %s with space %s : %s", d, spaceGUID, err) - } - } - - } - if managerSet := d.Get("managers").(*schema.Set); len(managerSet.List()) > 0 { - managers := expandStringList(managerSet.List()) - for _, d := range managers { - _, err := spaceAPI.AssociateManager(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating manager %s with space %s : %s", d, spaceGUID, err) - } - } - } - - return resourceIBMSpaceRead(d, meta) -} - -func resourceIBMSpaceRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - spaceGUID := d.Id() - - spaceAPI := cfClient.Spaces() - orgAPI := cfClient.Organizations() - spaceDetails, err := spaceAPI.Get(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving space: %s", err) - } - - auditors, err := spaceAPI.ListAuditors(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving auditors in the space: %s", err) - } - - managers, err := spaceAPI.ListManagers(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving managers in the space: %s", err) - } - - developers, err := spaceAPI.ListDevelopers(spaceGUID) - if err != nil { - return fmt.Errorf("Error retrieving developers in space: %s", err) - } - - d.Set("auditors", flattenSpaceRoleUsers(auditors)) - d.Set("managers", flattenSpaceRoleUsers(managers)) - d.Set("developers", flattenSpaceRoleUsers(developers)) - - if spaceDetails.Entity.SpaceQuotaGUID != "" { - sqAPI := cfClient.SpaceQuotas() - quota, err := sqAPI.Get(spaceDetails.Entity.SpaceQuotaGUID) - if err != nil { - return fmt.Errorf("Error retrieving quotas details for space: %s", err) - } - d.Set("space_quota", quota.Entity.Name) - } - d.Set("name", spaceDetails.Entity.Name) - org, err := orgAPI.Get(spaceDetails.Entity.OrgGUID) - if err != nil { - return fmt.Errorf("Error retrieving Organization details for space: %s", err) - } - d.Set("org", org.Entity.Name) - return nil -} - -func resourceIBMSpaceUpdate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - id := d.Id() - - req := mccpv2.SpaceUpdateRequest{} - if d.HasChange("name") { - req.Name = helpers.String(d.Get("name").(string)) - } - - api := cfClient.Spaces() - _, err = api.Update(id, req) - if err != nil { - return fmt.Errorf("Error updating space: %s", err) - } - - err = updateAuditors(api, id, d) - if err != nil { - return err - } - err = updateManagers(api, id, d) - if err != nil { - return err - } - err = updateDevelopers(api, id, d) - if err != nil { - return err - } - return resourceIBMSpaceRead(d, meta) -} - -func resourceIBMSpaceDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return err - } - id := d.Id() - - err = cfClient.Spaces().Delete(id, false) - if err != nil { - return fmt.Errorf("Error deleting space: %s", err) - } - - d.SetId("") - return nil -} - -func resourceIBMSpaceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() - if err != nil { - return false, err - } - id := d.Id() - - space, err := cfClient.Spaces().Get(id) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok { - if apiErr.StatusCode() == 404 { - return false, nil - } - } - return false, fmt.Errorf("Error communicating with the API: %s", err) - } - - return space.Metadata.GUID == id, nil -} - -func updateDevelopers(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { - if !d.HasChange("developers") { - return nil - } - var remove, add []string - o, n := d.GetChange("developers") - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - - if len(add) > 0 { - for _, d := range add { - _, err := api.AssociateDeveloper(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating developer %s with space %s : %s", d, spaceGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateDeveloper(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating developer %s with space %s : %s", d, spaceGUID, err) - } - } - } - return nil -} - -func updateManagers(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { - if !d.HasChange("managers") { - return nil - } - var remove, add []string - o, n := d.GetChange("managers") - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - - if len(add) > 0 { - for _, d := range add { - _, err := api.AssociateManager(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating manager %s with space %s : %s", d, spaceGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateManager(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating manager %s with space %s : %s", d, spaceGUID, err) - } - } - } - return nil -} -func updateAuditors(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { - if !d.HasChange("auditors") { - return nil - } - var remove, add []string - o, n := d.GetChange("auditors") - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove = expandStringList(os.Difference(ns).List()) - add = expandStringList(ns.Difference(os).List()) - - if len(add) > 0 { - for _, d := range add { - _, err := api.AssociateAuditor(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error associating auditor %s with space %s : %s", d, spaceGUID, err) - } - } - } - if len(remove) > 0 { - for _, d := range remove { - err := api.DisassociateAuditor(spaceGUID, d) - if err != nil { - return fmt.Errorf("Error dis-associating auditor %s with space %s : %s", d, spaceGUID, err) - } - } - } - return nil -} diff --git a/ibm/service/apigateway/README.md b/ibm/service/apigateway/README.md new file mode 100644 index 000000000..bfe779cbf --- /dev/null +++ b/ibm/service/apigateway/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider API Gateway + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the API Gateway resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/api_gateway_endpoint) +* IBM API Docs: [IBM API Docs for API Gateway](https://cloud.ibm.com/apidocs/api-gateway/apigw-endpoints-v1) +* IBM API Gateway SDK: [IBM SDK for API Gateway](https://github.com/IBM/apigateway-go-sdk/tree/master/apigatewaycontrollerapiv1) diff --git a/ibm/data_source_ibm_api_gateway.go b/ibm/service/apigateway/data_source_ibm_api_gateway.go similarity index 92% rename from ibm/data_source_ibm_api_gateway.go rename to ibm/service/apigateway/data_source_ibm_api_gateway.go index e4b3a12e8..5b15e8d82 100644 --- a/ibm/data_source_ibm_api_gateway.go +++ b/ibm/service/apigateway/data_source_ibm_api_gateway.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package apigateway import ( "encoding/json" "fmt" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" apigatewaysdk "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMApiGateway() *schema.Resource { +func DataSourceIBMApiGateway() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMApiGatewayRead, Schema: map[string]*schema.Schema{ @@ -111,11 +112,11 @@ func dataSourceIBMApiGateway() *schema.Resource { } func dataSourceIBMApiGatewayRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -127,7 +128,7 @@ func dataSourceIBMApiGatewayRead(d *schema.ResourceData, meta interface{}) error payload.ServiceInstanceCrn = &serviceInstanceCrn allendpoints, response, err := endpointservice.GetAllEndpoints(payload) if err != nil { - return fmt.Errorf("Error Getting All Endpoint: %s,%s", err, response) + return fmt.Errorf("[ERROR] Error Getting All Endpoint: %s,%s", err, response) } endpointsMap := make([]map[string]interface{}, 0, len(*allendpoints)) @@ -141,7 +142,7 @@ func dataSourceIBMApiGatewayRead(d *schema.ResourceData, meta interface{}) error swagger, err := endpointservice.GetEndpointSwagger(swaggerPayload) if err != nil { - return fmt.Errorf("Error Getting All Endpoint: %s,%s", err, swagger) + return fmt.Errorf("[ERROR] Error Getting All Endpoint: %s,%s", err, swagger) } doc := swagger.Result str, err := json.Marshal(doc) @@ -161,7 +162,7 @@ func dataSourceIBMApiGatewayRead(d *schema.ResourceData, meta interface{}) error } allsubscriptions, response, err := endpointservice.GetAllSubscriptions(SubscriptionPayload) if err != nil { - return fmt.Errorf("Error Getting All Endpoint: %s %s", err, response) + return fmt.Errorf("[ERROR] Error Getting All Endpoint: %s %s", err, response) } subscriptionMap := make([]map[string]interface{}, 0, len(*allsubscriptions)) for _, subscription := range *allsubscriptions { diff --git a/ibm/data_source_ibm_api_gateway_test.go b/ibm/service/apigateway/data_source_ibm_api_gateway_test.go similarity index 81% rename from ibm/data_source_ibm_api_gateway_test.go rename to ibm/service/apigateway/data_source_ibm_api_gateway_test.go index de2a7d815..5b286d75d 100644 --- a/ibm/data_source_ibm_api_gateway_test.go +++ b/ibm/service/apigateway/data_source_ibm_api_gateway_test.go @@ -1,22 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package apigateway_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAPIGatewayDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAPIGatewayDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -28,7 +29,7 @@ func TestAccIBMAPIGatewayDataSource_basic(t *testing.T) { } func testAccCheckIBMAPIGatewayDataSourceConfig() string { - return fmt.Sprintf(` + return ` resource "ibm_resource_instance" "apigateway"{ name = "testname" location = "global" @@ -37,6 +38,6 @@ func testAccCheckIBMAPIGatewayDataSourceConfig() string { } data "ibm_api_gateway" "apigateway" { service_instance_crn =ibm_resource_instance.apigateway.id - }`) + }` } diff --git a/ibm/resource_ibm_api_gateway_endpoint.go b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint.go similarity index 85% rename from ibm/resource_ibm_api_gateway_endpoint.go rename to ibm/service/apigateway/resource_ibm_api_gateway_endpoint.go index f79c41ab6..bbb99b66a 100644 --- a/ibm/resource_ibm_api_gateway_endpoint.go +++ b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package apigateway import ( "fmt" @@ -9,12 +9,13 @@ import ( "path" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" apigatewaysdk "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" "github.com/ghodss/yaml" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMApiGatewayEndPoint() *schema.Resource { +func ResourceIBMApiGatewayEndPoint() *schema.Resource { return &schema.Resource{ Create: resourceIBMApiGatewayEndPointCreate, @@ -84,11 +85,11 @@ func resourceIBMApiGatewayEndPoint() *schema.Resource { } func resourceIBMApiGatewayEndPointCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -133,7 +134,7 @@ func resourceIBMApiGatewayEndPointCreate(d *schema.ResourceData, meta interface{ } document = y2j } else { - return fmt.Errorf("File extension type must be json or yaml") + return fmt.Errorf("[ERROR] File extension type must be json or yaml") } } @@ -152,7 +153,7 @@ func resourceIBMApiGatewayEndPointCreate(d *schema.ResourceData, meta interface{ result, response, err := endpointservice.CreateEndpoint(payload) if err != nil { - return fmt.Errorf("Error creating Endpoint: %s,%s", err, response) + return fmt.Errorf("[ERROR] Error creating Endpoint: %s,%s", err, response) } d.SetId(fmt.Sprintf("%s//%s", *result.ServiceInstanceCrn, *result.ArtifactID)) @@ -161,11 +162,11 @@ func resourceIBMApiGatewayEndPointCreate(d *schema.ResourceData, meta interface{ } func resourceIBMApiGatewayEndPointGet(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -173,7 +174,7 @@ func resourceIBMApiGatewayEndPointGet(d *schema.ResourceData, meta interface{}) parts := d.Id() partslist := strings.Split(parts, "//") if len(partslist) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of instanceCRN//artifactID", d.Id()) + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of instanceCRN//artifactID", d.Id()) } serviceInstanceCrn := partslist[0] @@ -193,7 +194,7 @@ func resourceIBMApiGatewayEndPointGet(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error Getting Endpoint: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Endpoint: %s\n%s", err, response) } d.Set("service_instance_crn", serviceInstanceCrn) d.Set("endpoint_id", apiID) @@ -213,11 +214,11 @@ func resourceIBMApiGatewayEndPointGet(d *schema.ResourceData, meta interface{}) } func resourceIBMApiGatewayEndPointUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -270,7 +271,7 @@ func resourceIBMApiGatewayEndPointUpdate(d *schema.ResourceData, meta interface{ } document = y2j } else { - return fmt.Errorf("File extension type must be json or yaml") + return fmt.Errorf("[ERROR] File extension type must be json or yaml") } } @@ -303,14 +304,14 @@ func resourceIBMApiGatewayEndPointUpdate(d *schema.ResourceData, meta interface{ if d.HasChange("type") { actionType := d.Get("type").(string) - if managed == false && actionType == "share" { - return fmt.Errorf("Endpoint %s not managed", apiID) + if !managed && actionType == "share" { + return fmt.Errorf("[ERROR] Endpoint %s not managed", apiID) } actionPayload.Type = &actionType _, response, err := endpointservice.EndpointActions(actionPayload) if err != nil { - return fmt.Errorf("Error updating Endpoint Action: %s,%s", err, response) + return fmt.Errorf("[ERROR] Error updating Endpoint Action: %s,%s", err, response) } } @@ -340,7 +341,7 @@ func resourceIBMApiGatewayEndPointUpdate(d *schema.ResourceData, meta interface{ } document = y2j } else { - return fmt.Errorf("File extension type must be json or yaml") + return fmt.Errorf("[ERROR] File extension type must be json or yaml") } } @@ -355,17 +356,17 @@ func resourceIBMApiGatewayEndPointUpdate(d *schema.ResourceData, meta interface{ if update { _, response, err := endpointservice.UpdateEndpoint(payload) if err != nil { - return fmt.Errorf("Error updating Endpoint: %s,%s", err, response) + return fmt.Errorf("[ERROR] Error updating Endpoint: %s,%s", err, response) } } return resourceIBMApiGatewayEndPointGet(d, meta) } func resourceIBMApiGatewayEndPointDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -390,7 +391,7 @@ func resourceIBMApiGatewayEndPointDelete(d *schema.ResourceData, meta interface{ if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error deleting Endpoint: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting Endpoint: %s\n%s", err, response) } d.SetId("") @@ -398,11 +399,11 @@ func resourceIBMApiGatewayEndPointDelete(d *schema.ResourceData, meta interface{ } func resourceIBMApiGatewayEndPointExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return false, err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return false, err } @@ -410,7 +411,7 @@ func resourceIBMApiGatewayEndPointExists(d *schema.ResourceData, meta interface{ parts := d.Id() partslist := strings.Split(parts, "//") if len(partslist) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of instanceCRN//artifactID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of instanceCRN//artifactID", d.Id()) } serviceInstanceCrn := partslist[0] diff --git a/ibm/resource_ibm_api_gateway_endpoint_subscription.go b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription.go similarity index 82% rename from ibm/resource_ibm_api_gateway_endpoint_subscription.go rename to ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription.go index 77843a576..ecd3c5263 100644 --- a/ibm/resource_ibm_api_gateway_endpoint_subscription.go +++ b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package apigateway import ( "fmt" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" apigatewaysdk "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMApiGatewayEndpointSubscription() *schema.Resource { +func ResourceIBMApiGatewayEndpointSubscription() *schema.Resource { return &schema.Resource{ Create: resourceIBMApiGatewayEndpointSubscriptionCreate, @@ -41,7 +43,7 @@ func resourceIBMApiGatewayEndpointSubscription() *schema.Resource { "type": { Type: schema.TypeString, Required: true, - ValidateFunc: validateAllowedStringValue([]string{"external", "internal"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"external", "internal"}), Description: "Subscription type. Allowable values are external, internal", }, "client_secret": { @@ -66,11 +68,11 @@ func resourceIBMApiGatewayEndpointSubscription() *schema.Resource { } } func resourceIBMApiGatewayEndpointSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -114,7 +116,7 @@ func resourceIBMApiGatewayEndpointSubscriptionCreate(d *schema.ResourceData, met result, response, err := endpointservice.CreateSubscription(payload) if err != nil { - return fmt.Errorf("Error creating Subscription: %s %s", err, response) + return fmt.Errorf("[ERROR] Error creating Subscription: %s %s", err, response) } d.SetId(fmt.Sprintf("%s//%s", *result.ArtifactID, *result.ClientID)) @@ -122,11 +124,11 @@ func resourceIBMApiGatewayEndpointSubscriptionCreate(d *schema.ResourceData, met } func resourceIBMApiGatewayEndpointSubscriptionGet(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -134,7 +136,7 @@ func resourceIBMApiGatewayEndpointSubscriptionGet(d *schema.ResourceData, meta i parts := d.Id() partslist := strings.Split(parts, "//") if len(partslist) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of artifactID//clientID", d.Id()) + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of artifactID//clientID", d.Id()) } artifactID := partslist[0] clientID := partslist[1] @@ -153,7 +155,7 @@ func resourceIBMApiGatewayEndpointSubscriptionGet(d *schema.ResourceData, meta i d.SetId("") return nil } - return fmt.Errorf("Error Getting Subscription: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Subscription: %s\n%s", err, response) } d.Set("artifact_id", result.ArtifactID) d.Set("client_id", result.ClientID) @@ -169,11 +171,11 @@ func resourceIBMApiGatewayEndpointSubscriptionGet(d *schema.ResourceData, meta i } func resourceIBMApiGatewayEndpointSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -214,24 +216,24 @@ func resourceIBMApiGatewayEndpointSubscriptionUpdate(d *schema.ResourceData, met } _, SecretResponse, err := endpointservice.AddSubscriptionSecret(secretpayload) if err != nil { - return fmt.Errorf("Error Adding Secret to Subscription: %s,%s", err, SecretResponse) + return fmt.Errorf("[ERROR] Error Adding Secret to Subscription: %s,%s", err, SecretResponse) } } if update { _, response, err := endpointservice.UpdateSubscription(payload) if err != nil { - return fmt.Errorf("Error updating Subscription: %s,%s", err, response) + return fmt.Errorf("[ERROR] Error updating Subscription: %s,%s", err, response) } } return resourceIBMApiGatewayEndpointSubscriptionGet(d, meta) } func resourceIBMApiGatewayEndpointSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return err } @@ -253,7 +255,7 @@ func resourceIBMApiGatewayEndpointSubscriptionDelete(d *schema.ResourceData, met if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error deleting Subscription: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting Subscription: %s\n%s", err, response) } d.SetId("") @@ -261,18 +263,18 @@ func resourceIBMApiGatewayEndpointSubscriptionDelete(d *schema.ResourceData, met } func resourceIBMApiGatewayEndpointSubscriptionExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return false, err } - endpointservice, err := meta.(ClientSession).APIGateway() + endpointservice, err := meta.(conns.ClientSession).APIGateway() if err != nil { return false, err } parts := d.Id() partslist := strings.Split(parts, "//") if len(partslist) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of artifactID//clientID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of artifactID//clientID", d.Id()) } artifactID := partslist[0] clientID := partslist[1] diff --git a/ibm/resource_ibm_api_gateway_endpoint_subscription_test.go b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription_test.go similarity index 83% rename from ibm/resource_ibm_api_gateway_endpoint_subscription_test.go rename to ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription_test.go index 6529fa7eb..67921150b 100644 --- a/ibm/resource_ibm_api_gateway_endpoint_subscription_test.go +++ b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_subscription_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 - -package ibm +package apigateway_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + apigatewaysdk "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -18,11 +20,11 @@ func TestAccIBMAPIGatewaySubscription_Basic(t *testing.T) { var resultSubscription apigatewaysdk.V2Subscription name := fmt.Sprintf("tftest-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAPIGatewaySubscriptionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAPIGatewaySubscriptionBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMAPIGatewaySubscriptionExists("ibm_api_gateway_endpoint_subscription.subscription", resultSubscription), @@ -38,11 +40,11 @@ func testAccCheckIBMAPIGatewaySubscriptionDestroy(s *terraform.State) error { if rs.Type != "ibm_api_gateway_endpoint_subscription" { continue } - apiClient, err := testAccProvider.Meta().(ClientSession).APIGateway() + apiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).APIGateway() if err != nil { return err } - sess, err := testAccProvider.Meta().(ClientSession).BluemixSession() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -60,7 +62,7 @@ func testAccCheckIBMAPIGatewaySubscriptionDestroy(s *terraform.State) error { } _, _, err = apiClient.GetSubscription(&payload) if err != nil && !strings.Contains(err.Error(), "Not Found") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -69,18 +71,18 @@ func TestAccIBMAPIGatewaySubscriptionImport(t *testing.T) { var resultSubscription apigatewaysdk.V2Subscription name := fmt.Sprintf("tftest-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAPIGatewaySubscriptionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAPIGatewaySubscriptionBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMAPIGatewaySubscriptionExists("ibm_api_gateway_endpoint_subscription.subscription", resultSubscription), resource.TestCheckResourceAttr("ibm_api_gateway_endpoint_subscription.subscription", "name", name), ), }, - resource.TestStep{ + { ResourceName: "ibm_api_gateway_endpoint_subscription.subscription", ImportState: true, ImportStateVerify: true, @@ -101,7 +103,7 @@ func testAccCheckIBMAPIGatewaySubscriptionBasic(name string) string { service_instance_crn = ibm_resource_instance.apigateway.id name="test-endpoint" managed="true" - open_api_doc_name = "test-fixtures/SDK-test.json" + open_api_doc_name = "../../test-fixtures/SDK-test.json" } resource "ibm_api_gateway_endpoint_subscription" "subscription"{ artifact_id = ibm_api_gateway_endpoint.endpoint.endpoint_id @@ -119,11 +121,11 @@ func testAccCheckIBMAPIGatewaySubscriptionExists(n string, result apigatewaysdk. if !ok { return fmt.Errorf("Not found: %s", n) } - apiClient, err := testAccProvider.Meta().(ClientSession).APIGateway() + apiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).APIGateway() if err != nil { return err } - sess, err := testAccProvider.Meta().(ClientSession).BluemixSession() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } diff --git a/ibm/resource_ibm_api_gateway_endpoint_test.go b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_test.go similarity index 82% rename from ibm/resource_ibm_api_gateway_endpoint_test.go rename to ibm/service/apigateway/resource_ibm_api_gateway_endpoint_test.go index 95cb73a22..f15d7a910 100644 --- a/ibm/resource_ibm_api_gateway_endpoint_test.go +++ b/ibm/service/apigateway/resource_ibm_api_gateway_endpoint_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package apigateway_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + apigatewaysdk "github.com/IBM/apigateway-go-sdk/apigatewaycontrollerapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -18,11 +21,11 @@ func TestAccIBMAPIGatewayEndpoint_Basic(t *testing.T) { var resultendpoint apigatewaysdk.V2Endpoint name := fmt.Sprintf("tftest-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAPIGatewayEndpointDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAPIGatewayEndpointBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMAPIGatewayEndpointExists("ibm_api_gateway_endpoint.endpoint", resultendpoint), @@ -38,11 +41,11 @@ func testAccCheckIBMAPIGatewayEndpointDestroy(s *terraform.State) error { if rs.Type != "ibm_api_gateway_endpoint" { continue } - apiClient, err := testAccProvider.Meta().(ClientSession).APIGateway() + apiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).APIGateway() if err != nil { return err } - sess, err := testAccProvider.Meta().(ClientSession).BluemixSession() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -60,7 +63,7 @@ func testAccCheckIBMAPIGatewayEndpointDestroy(s *terraform.State) error { } _, _, err = apiClient.GetEndpoint(&payload) if err != nil && !strings.Contains(err.Error(), "Not Found") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -69,18 +72,18 @@ func TestAccIBMAPIGatewayEndpointImport(t *testing.T) { var resultendpoint apigatewaysdk.V2Endpoint name := fmt.Sprintf("tftest-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAPIGatewayEndpointDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAPIGatewayEndpointBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMAPIGatewayEndpointExists("ibm_api_gateway_endpoint.endpoint", resultendpoint), resource.TestCheckResourceAttr("ibm_api_gateway_endpoint.endpoint", "name", name), ), }, - resource.TestStep{ + { ResourceName: "ibm_api_gateway_endpoint.endpoint", ImportState: true, ImportStateVerify: true, @@ -103,7 +106,7 @@ func testAccCheckIBMAPIGatewayEndpointBasic(name string) string { service_instance_crn= ibm_resource_instance.apigateway.id name = "%s" managed="true" - open_api_doc_name="test-fixtures/SDK-test.json" + open_api_doc_name="../../test-fixtures/SDK-test.json" } `, name) } @@ -115,11 +118,11 @@ func testAccCheckIBMAPIGatewayEndpointExists(n string, result apigatewaysdk.V2En if !ok { return fmt.Errorf("Not found: %s", n) } - apiClient, err := testAccProvider.Meta().(ClientSession).APIGateway() + apiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).APIGateway() if err != nil { return err } - sess, err := testAccProvider.Meta().(ClientSession).BluemixSession() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } diff --git a/ibm/service/appconfiguration/README.md b/ibm/service/appconfiguration/README.md new file mode 100644 index 000000000..d78aea7a6 --- /dev/null +++ b/ibm/service/appconfiguration/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider APP Configuration + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the APP Configuration resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/app_config_environment) +* IBM API Docs: [IBM API Docs for APP Configuration](https://cloud.ibm.com/apidocs/app-configuration) +* IBM APP Configuration SDK: [IBM SDK for APP Configuration](https://github.com/IBM/appconfiguration-go-admin-sdk/tree/master/appconfigurationv1) diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_collection.go b/ibm/service/appconfiguration/data_source_ibm_app_config_collection.go new file mode 100644 index 000000000..576285584 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_collection.go @@ -0,0 +1,232 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration + +import ( + "fmt" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMAppConfigCollection() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigCollectionRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "collection_id": { + Type: schema.TypeString, + Required: true, + Description: "Collection Id of the collection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Collection name.", + }, + "include": { + Type: schema.TypeList, + Optional: true, + Description: "Include feature, property details in the response.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "expand": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to true, returns expanded view of the resource details.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Collection description.", + }, + "tags": { + Type: schema.TypeString, + Computed: true, + Description: "Tags associated with the collection.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the collection.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the collection data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Collection URL.", + }, + "features_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of features associated with the collection.", + }, + "properties_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of properties associated with the collection.", + }, + "features": { + Type: schema.TypeList, + Computed: true, + Description: "List of Features associated with the collection.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "feature_id": { + Type: schema.TypeString, + Computed: true, + Description: "feature id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Feature.", + }, + }, + }, + }, + "properties": { + Type: schema.TypeList, + Computed: true, + Description: "List of properties associated with the collection.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "property_id": { + Type: schema.TypeString, + Computed: true, + Description: "property id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Property.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigCollectionRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.GetCollectionOptions{} + + options.SetCollectionID(d.Get("collection_id").(string)) + + if _, ok := d.GetOk("include"); ok { + includes := []string{} + for _, includeItem := range d.Get("include").([]interface{}) { + includes = append(includes, includeItem.(string)) + } + options.SetInclude(includes) + } + if _, ok := d.GetOk("expand"); ok { + options.SetExpand(d.Get("expand").(bool)) + } + + result, response, err := appconfigClient.GetCollection(options) + if err != nil { + return fmt.Errorf("GetCollection failed %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s", guid, *result.CollectionID)) + if result.Name != nil { + if err = d.Set("name", result.Name); err != nil { + return fmt.Errorf("[ERROR] Error setting name: %s", err) + } + } + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return fmt.Errorf("[ERROR] Error setting description: %s", err) + } + } + if result.Tags != nil { + if err = d.Set("tags", result.Tags); err != nil { + return fmt.Errorf("[ERROR] Error setting tags: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + if result.Features != nil { + err = d.Set("features", dataSourceCollectionFlattenFeatures(result.Features)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting features %s", err) + } + } + if result.Properties != nil { + err = d.Set("properties", dataSourceCollectionFlattenProperties(result.Properties)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting properties %s", err) + } + } + + return nil +} + +func dataSourceCollectionFlattenFeatures(result []appconfigurationv1.FeatureOutput) (features []map[string]interface{}) { + for _, featuresItem := range result { + features = append(features, dataSourceCollectionFeaturesToMap(featuresItem)) + } + + return features +} + +func dataSourceCollectionFlattenProperties(result []appconfigurationv1.PropertyOutput) (properties []map[string]interface{}) { + for _, propertiesItem := range result { + properties = append(properties, dataSourceCollectionPropertiesToMap(propertiesItem)) + } + + return properties +} + +func dataSourceCollectionFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + return featuresMap +} + +func dataSourceCollectionPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + return propertiesMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_collection_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_collection_test.go new file mode 100644 index 000000000..5e32de02b --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_collection_test.go @@ -0,0 +1,63 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccIbmAppConfigCollectionDataSource(t *testing.T) { + collectionID := fmt.Sprintf("tf_collection_id_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tags := "development collection" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigCollectionDataSourceConfigBasic(instanceName, name, collectionID, description, tags), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "collection_id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "expand"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "tags"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "created_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collection.ibm_app_config_collection_data1", "updated_time"), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigCollectionDataSourceConfigBasic(instanceName, name, collectionID, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test487" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + + resource "ibm_app_config_collection" "app_config_collection_resource1" { + guid = ibm_resource_instance.app_config_terraform_test487.guid + name = "%s" + collection_id = "%s" + description = "%s" + tags = "%s" + } + + data "ibm_app_config_collection" "ibm_app_config_collection_data1" { + guid = ibm_app_config_collection.app_config_collection_resource1.guid + collection_id = ibm_app_config_collection.app_config_collection_resource1.collection_id + expand = "true" + } + `, instanceName, name, collectionID, description, tags) +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_collections.go b/ibm/service/appconfiguration/data_source_ibm_app_config_collections.go new file mode 100644 index 000000000..707e2adac --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_collections.go @@ -0,0 +1,371 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration + +import ( + "fmt" + "net/url" + "reflect" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" +) + +func DataSourceIBMAppConfigCollections() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigCollectionsRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "limit": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to retrieve.", + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Description: "Skipped number of records.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Total number of records.", + }, + "include": { + Type: schema.TypeList, + Optional: true, + Description: "Include feature, property details in the response.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "expand": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to true, returns expanded view of the resource details.", + }, + "collections": { + Type: schema.TypeList, + Computed: true, + Description: "Array of Features.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Collection name.", + }, + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Collection description.", + }, + "tags": { + Type: schema.TypeString, + Computed: true, + Description: "Tags associated with the collection.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the collection.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the collection data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Collection URL.", + }, + "features_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of features associated with the collection.", + }, + "properties_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of properties associated with the collection.", + }, + "features": { + Type: schema.TypeList, + Computed: true, + Description: "List of Features associated with the collection.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "feature_id": { + Type: schema.TypeString, + Computed: true, + Description: "feature id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Feature.", + }, + }, + }, + }, + "properties": { + Type: schema.TypeList, + Computed: true, + Description: "List of properties associated with the collection.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "property_id": { + Type: schema.TypeString, + Computed: true, + Description: "property id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Property.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigCollectionsRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.ListCollectionsOptions{} + + if _, ok := d.GetOk("expand"); ok { + options.SetExpand(d.Get("expand").(bool)) + } + if _, ok := d.GetOk("sort"); ok { + options.SetExpand(d.Get("sort").(bool)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetExpand(d.Get("tags").(bool)) + } + if _, ok := d.GetOk("include"); ok { + includes := []string{} + for _, includeItem := range d.Get("include").([]interface{}) { + includes = append(includes, includeItem.(string)) + } + options.SetInclude(includes) + } + if _, ok := d.GetOk("features"); ok { + features := []string{} + for _, featureItem := range d.Get("features").([]interface{}) { + features = append(features, featureItem.(string)) + } + options.SetFeatures(features) + } + if _, ok := d.GetOk("properties"); ok { + properties := []string{} + for _, propertieItem := range d.Get("properties").([]interface{}) { + properties = append(properties, propertieItem.(string)) + } + options.SetProperties(properties) + } + + var collectionsList *appconfigurationv1.CollectionList + var offset int64 + var limit int64 = 10 + var isLimit bool + finalList := []appconfigurationv1.Collection{} + + if _, ok := d.GetOk("limit"); ok { + isLimit = true + limit = int64(d.Get("limit").(int)) + } + options.SetLimit(limit) + if _, ok := d.GetOk("offset"); ok { + offset = int64(d.Get("offset").(int)) + } + for { + options.Offset = &offset + result, response, err := appconfigClient.ListCollections(options) + collectionsList = result + if err != nil { + return fmt.Errorf("ListCollections failed %s\n%s", err, response) + } + if isLimit { + offset = 0 + } else { + offset = dataSourceCollectionsListGetNext(result.Next) + } + finalList = append(finalList, result.Collections...) + if offset == 0 { + break + } + } + + collectionsList.Collections = finalList + + d.SetId(fmt.Sprintf("%s", guid)) + + if collectionsList.Collections != nil { + err = d.Set("collections", dataSourceCollectionListFlattenCollections(collectionsList.Collections)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting collections %s", err) + } + } + if collectionsList.Limit != nil { + if err = d.Set("limit", collectionsList.Limit); err != nil { + return fmt.Errorf("[ERROR] Error setting limit: %s", err) + } + } + if collectionsList.Offset != nil { + if err = d.Set("offset", collectionsList.Offset); err != nil { + return fmt.Errorf("[ERROR] Error setting offset: %s", err) + } + } + if collectionsList.TotalCount != nil { + if err = d.Set("total_count", collectionsList.TotalCount); err != nil { + return fmt.Errorf("[ERROR] Error setting total_count: %s", err) + } + } + + return nil +} + +func dataSourceCollectionListFlattenCollections(result []appconfigurationv1.Collection) (collections []map[string]interface{}) { + for _, collectionsItem := range result { + collections = append(collections, dataSourceCollectionsListCollectionsToMap(collectionsItem)) + } + return collections +} + +func dataSourceCollectionsListCollectionsToMap(collectionItem appconfigurationv1.Collection) (collectionsMap map[string]interface{}) { + collectionsMap = map[string]interface{}{} + + if collectionItem.Name != nil { + collectionsMap["name"] = collectionItem.Name + } + if collectionItem.CollectionID != nil { + collectionsMap["collection_id"] = collectionItem.CollectionID + } + if collectionItem.Description != nil { + collectionsMap["description"] = collectionItem.Description + } + if collectionItem.Tags != nil { + collectionsMap["tags"] = collectionItem.Tags + } + if collectionItem.CreatedTime != nil { + collectionsMap["created_time"] = collectionItem.CreatedTime.String() + } + if collectionItem.UpdatedTime != nil { + collectionsMap["updated_time"] = collectionItem.UpdatedTime.String() + } + if collectionItem.Href != nil { + collectionsMap["href"] = collectionItem.Href + } + if collectionItem.FeaturesCount != nil { + collectionsMap["features_count"] = collectionItem.FeaturesCount + } + if collectionItem.PropertiesCount != nil { + collectionsMap["properties_count"] = collectionItem.PropertiesCount + } + if collectionItem.Features != nil { + featuresList := []map[string]interface{}{} + for _, featuresItem := range collectionItem.Features { + featuresList = append(featuresList, dataSourceCollectionsListCollectionsFeaturesToMap(featuresItem)) + } + collectionsMap["features"] = featuresList + } + if collectionItem.Properties != nil { + propertiesList := []map[string]interface{}{} + for _, propertiesItem := range collectionItem.Properties { + propertiesList = append(propertiesList, dataSourceCollectionsListCollectionsPropertiesToMap(propertiesItem)) + } + collectionsMap["properties"] = propertiesList + } + + return collectionsMap +} + +func dataSourceCollectionsListCollectionsFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + return featuresMap +} + +func dataSourceCollectionsListCollectionsPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + return propertiesMap +} + +func dataSourceCollectionsListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} + +func dataSourceCollectionListFlattenPagination(result appconfigurationv1.PageHrefResponse) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCollectionsListURLToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCollectionsListURLToMap(urlItem appconfigurationv1.PageHrefResponse) (urlMap map[string]interface{}) { + urlMap = map[string]interface{}{} + + if urlItem.Href != nil { + urlMap["href"] = urlItem.Href + } + + return urlMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_collections_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_collections_test.go new file mode 100644 index 000000000..60d6e21b5 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_collections_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccIbmAppConfigCollectionsDataSource(t *testing.T) { + collectionID := fmt.Sprintf("tf_collection_id_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tags := "development collections" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigCollectionsDataSourceConfigBasic(instanceName, name, collectionID, description, tags), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "limit"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "offset"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "collections.#"), + resource.TestCheckResourceAttr("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.name", name), + resource.TestCheckResourceAttr("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.collection_id", collectionID), + resource.TestCheckResourceAttr("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.description", description), + resource.TestCheckResourceAttr("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.tags", tags), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.created_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_collections.app_config_collections_data2", "collections.0.updated_time"), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigCollectionsDataSourceConfigBasic(instanceName, name, collectionID, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test487" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + + resource "ibm_app_config_collection" "app_config_collection_resource2" { + guid = ibm_resource_instance.app_config_terraform_test487.guid + name = "%s" + collection_id = "%s" + description = "%s" + tags = "%s" + } + + data "ibm_app_config_collections" "app_config_collections_data2" { + guid = ibm_app_config_collection.app_config_collection_resource2.guid + expand = "true" + } + `, instanceName, name, collectionID, description, tags) +} diff --git a/ibm/data_source_ibm_app_config_environment.go b/ibm/service/appconfiguration/data_source_ibm_app_config_environment.go similarity index 85% rename from ibm/data_source_ibm_app_config_environment.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_environment.go index 29f31c38f..738f8f278 100644 --- a/ibm/data_source_ibm_app_config_environment.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_environment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" @@ -12,7 +12,7 @@ import ( "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" ) -func dataSourceIbmAppConfigEnvironment() *schema.Resource { +func DataSourceIBMAppConfigEnvironment() *schema.Resource { return &schema.Resource{ Read: dataSourceIbmAppConfigEnvironmentRead, @@ -96,37 +96,37 @@ func dataSourceIbmAppConfigEnvironmentRead(d *schema.ResourceData, meta interfac if result.Name != nil { if err = d.Set("name", result.Name); err != nil { - return fmt.Errorf("error setting name: %s", err) + return fmt.Errorf("[ERROR] Error setting name: %s", err) } } if result.Description != nil { if err = d.Set("description", result.Description); err != nil { - return fmt.Errorf("error setting description: %s", err) + return fmt.Errorf("[ERROR] Error setting description: %s", err) } } if result.Tags != nil { if err = d.Set("tags", result.Tags); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("[ERROR] Error setting tags: %s", err) } } if result.ColorCode != nil { if err = d.Set("color_code", result.ColorCode); err != nil { - return fmt.Errorf("error setting color_code: %s", err) + return fmt.Errorf("[ERROR] Error setting color_code: %s", err) } } if result.CreatedTime != nil { if err = d.Set("created_time", result.CreatedTime.String()); err != nil { - return fmt.Errorf("error setting created_time: %s", err) + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) } } if result.UpdatedTime != nil { if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { - return fmt.Errorf("error setting updated_time: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) } } if result.Href != nil { if err = d.Set("href", result.Href); err != nil { - return fmt.Errorf("error setting href: %s", err) + return fmt.Errorf("[ERROR] Error setting href: %s", err) } } return nil diff --git a/ibm/data_source_ibm_app_config_environment_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_environment_test.go similarity index 94% rename from ibm/data_source_ibm_app_config_environment_test.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_environment_test.go index e126423f8..554e205a2 100644 --- a/ibm/data_source_ibm_app_config_environment_test.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_environment_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIbmAppConfigEnvironmentDataSourceBasic(t *testing.T) { envName := fmt.Sprintf("env_%d", acctest.RandIntRange(10, 100)) environmentID := fmt.Sprintf("environment_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmAppConfigEnvironmentDataSourceConfigBasic(name, envName, environmentID, description, colorCode, tags), diff --git a/ibm/data_source_ibm_app_config_environments.go b/ibm/service/appconfiguration/data_source_ibm_app_config_environments.go similarity index 94% rename from ibm/data_source_ibm_app_config_environments.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_environments.go index 22d74d479..c9b3e2385 100644 --- a/ibm/data_source_ibm_app_config_environments.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_environments.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" @@ -15,7 +15,7 @@ import ( "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" ) -func dataSourceIbmAppConfigEnvironments() *schema.Resource { +func DataSourceIBMAppConfigEnvironments() *schema.Resource { return &schema.Resource{ Read: dataSourceIbmAppConfigEnvironmentsRead, @@ -219,48 +219,48 @@ func dataSourceIbmAppConfigEnvironmentsRead(d *schema.ResourceData, meta interfa if environmentList.Environments != nil { err = d.Set("environments", dataSourceEnvironmentListFlattenEnvironments(environmentList.Environments)) if err != nil { - return fmt.Errorf("error setting environments %s", err) + return fmt.Errorf("[ERROR] Error setting environments %s", err) } } if environmentList.TotalCount != nil { if err = d.Set("total_count", environmentList.TotalCount); err != nil { - return fmt.Errorf("error setting total_count: %s", err) + return fmt.Errorf("[ERROR] Error setting total_count: %s", err) } } if environmentList.Limit != nil { if err = d.Set("limit", environmentList.Limit); err != nil { - return fmt.Errorf("error setting limit: %s", err) + return fmt.Errorf("[ERROR] Error setting limit: %s", err) } } if environmentList.Offset != nil { if err = d.Set("offset", environmentList.Offset); err != nil { - return fmt.Errorf("error setting offset: %s", err) + return fmt.Errorf("[ERROR] Error setting offset: %s", err) } } if environmentList.First != nil { err = d.Set("first", dataSourceEnvironmentListFlattenPagination(*environmentList.First)) if err != nil { - return fmt.Errorf("error setting first %s", err) + return fmt.Errorf("[ERROR] Error setting first %s", err) } } if environmentList.Previous != nil { err = d.Set("previous", dataSourceEnvironmentListFlattenPagination(*environmentList.Previous)) if err != nil { - return fmt.Errorf("error setting previous %s", err) + return fmt.Errorf("[ERROR] Error setting previous %s", err) } } if environmentList.Last != nil { err = d.Set("last", dataSourceEnvironmentListFlattenPagination(*environmentList.Last)) if err != nil { - return fmt.Errorf("error setting last %s", err) + return fmt.Errorf("[ERROR] Error setting last %s", err) } } if environmentList.Next != nil { err = d.Set("next", dataSourceEnvironmentListFlattenPagination(*environmentList.Next)) if err != nil { - return fmt.Errorf("error setting next %s", err) + return fmt.Errorf("[ERROR] Error setting next %s", err) } } diff --git a/ibm/data_source_ibm_app_config_environments_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_environments_test.go similarity index 94% rename from ibm/data_source_ibm_app_config_environments_test.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_environments_test.go index a2dacbc43..a8bebc5d5 100644 --- a/ibm/data_source_ibm_app_config_environments_test.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_environments_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIbmAppConfigEnvironmentsDataSourceBasic(t *testing.T) { envName := fmt.Sprintf("env_%d", acctest.RandIntRange(10, 100)) environmentID := fmt.Sprintf("environment_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmAppConfigEnvironmentsDataSourceConfigBasic(name, envName, environmentID, description, colorCode, tags), diff --git a/ibm/data_source_ibm_app_config_feature.go b/ibm/service/appconfiguration/data_source_ibm_app_config_feature.go similarity index 85% rename from ibm/data_source_ibm_app_config_feature.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_feature.go index 0950d9b6c..795d60c09 100644 --- a/ibm/data_source_ibm_app_config_feature.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_feature.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" @@ -13,7 +13,7 @@ import ( "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" ) -func dataSourceIbmAppConfigFeature() *schema.Resource { +func DataSourceIBMAppConfigFeature() *schema.Resource { return &schema.Resource{ Read: dataSourceIbmAppConfigFeatureRead, @@ -78,6 +78,11 @@ func dataSourceIbmAppConfigFeature() *schema.Resource { Computed: true, Description: "Denotes if the targeting rules are specified for the feature flag.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Computed: true, + Description: "Rollout percentage of the feature.", + }, "segment_rules": { Type: schema.TypeList, Computed: true, @@ -111,6 +116,11 @@ func dataSourceIbmAppConfigFeature() *schema.Resource { Computed: true, Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Computed: true, + Description: "Rollout percentage for the segment rule.", + }, }, }, }, @@ -178,47 +188,52 @@ func dataSourceIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{}) d.SetId(fmt.Sprintf("%s/%s/%s", guid, *options.EnvironmentID, *result.FeatureID)) if result.Name != nil { if err = d.Set("name", result.Name); err != nil { - return fmt.Errorf("error setting name: %s", err) + return fmt.Errorf("[ERROR] Error setting name: %s", err) } } if result.Description != nil { if err = d.Set("description", result.Description); err != nil { - return fmt.Errorf("error setting description: %s", err) + return fmt.Errorf("[ERROR] Error setting description: %s", err) } } if result.Type != nil { if err = d.Set("type", result.Type); err != nil { - return fmt.Errorf("error setting type: %s", err) + return fmt.Errorf("[ERROR] Error setting type: %s", err) } } if result.Enabled != nil { if err = d.Set("enabled", result.Enabled); err != nil { - return fmt.Errorf("error setting enabled: %s", err) + return fmt.Errorf("[ERROR] Error setting enabled: %s", err) } } if result.Tags != nil { if err = d.Set("tags", result.Tags); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("[ERROR] Error setting tags: %s", err) + } + } + if result.RolloutPercentage != nil { + if err = d.Set("rollout_percentage", result.RolloutPercentage); err != nil { + return fmt.Errorf("[ERROR] Error setting rollout_percentage: %s", err) } } if result.SegmentExists != nil { if err = d.Set("segment_exists", result.SegmentExists); err != nil { - return fmt.Errorf("error setting segment_exists: %s", err) + return fmt.Errorf("[ERROR] Error setting segment_exists: %s", err) } } if result.CreatedTime != nil { if err = d.Set("created_time", result.CreatedTime.String()); err != nil { - return fmt.Errorf("error setting created_time: %s", err) + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) } } if result.UpdatedTime != nil { if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { - return fmt.Errorf("error setting updated_time: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) } } if result.Href != nil { if err = d.Set("href", result.Href); err != nil { - return fmt.Errorf("error setting href: %s", err) + return fmt.Errorf("[ERROR] Error setting href: %s", err) } } @@ -251,20 +266,20 @@ func dataSourceIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{}) if result.SegmentRules != nil { err = d.Set("segment_rules", dataSourceFeatureFlattenSegmentRules(result.SegmentRules)) if err != nil { - return fmt.Errorf("error setting segment_rules %s", err) + return fmt.Errorf("[ERROR] Error setting segment_rules %s", err) } } if result.Collections != nil { err = d.Set("collections", dataSourceFeatureFlattenCollections(result.Collections)) if err != nil { - return fmt.Errorf("error setting collections %s", err) + return fmt.Errorf("[ERROR] Error setting collections %s", err) } } return nil } -func dataSourceFeatureFlattenSegmentRules(result []appconfigurationv1.SegmentRule) (segmentRules []map[string]interface{}) { +func dataSourceFeatureFlattenSegmentRules(result []appconfigurationv1.FeatureSegmentRule) (segmentRules []map[string]interface{}) { for _, segmentRulesItem := range result { segmentRules = append(segmentRules, dataSourceFeatureSegmentRulesToMap(segmentRulesItem)) } @@ -272,7 +287,7 @@ func dataSourceFeatureFlattenSegmentRules(result []appconfigurationv1.SegmentRul return segmentRules } -func dataSourceFeatureSegmentRulesToMap(segmentRulesItem appconfigurationv1.SegmentRule) (segmentRulesMap map[string]interface{}) { +func dataSourceFeatureSegmentRulesToMap(segmentRulesItem appconfigurationv1.FeatureSegmentRule) (segmentRulesMap map[string]interface{}) { segmentRulesMap = map[string]interface{}{} if segmentRulesItem.Rules != nil { @@ -296,6 +311,9 @@ func dataSourceFeatureSegmentRulesToMap(segmentRulesItem appconfigurationv1.Segm if segmentRulesItem.Order != nil { segmentRulesMap["order"] = segmentRulesItem.Order } + if segmentRulesItem.RolloutPercentage != nil { + segmentRulesMap["rollout_percentage"] = segmentRulesItem.RolloutPercentage + } return segmentRulesMap } diff --git a/ibm/data_source_ibm_app_config_feature_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_feature_test.go similarity index 90% rename from ibm/data_source_ibm_app_config_feature_test.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_feature_test.go index 93e85b9a1..0f8cfffbd 100644 --- a/ibm/data_source_ibm_app_config_feature_test.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_feature_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIbmAppConfigFeatureDataSource(t *testing.T) { instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmAppConfigFeatureDataSourceConfigBasic(instanceName, name, environmentID, featureID, featureType, description, tags), @@ -40,6 +42,7 @@ func TestAccIbmAppConfigFeatureDataSource(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_app_config_feature.ibm_app_config_feature_data1", "created_time"), resource.TestCheckResourceAttrSet("data.ibm_app_config_feature.ibm_app_config_feature_data1", "updated_time"), resource.TestCheckResourceAttrSet("data.ibm_app_config_feature.ibm_app_config_feature_data1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_feature.ibm_app_config_feature_data1", "rollout_percentage"), ), }, }, @@ -52,7 +55,7 @@ func testAccCheckIbmAppConfigFeatureDataSourceConfigBasic(instanceName, name, en name = "%s" location = "us-south" service = "apprapp" - plan = "standard" + plan = "lite" } resource "ibm_app_config_feature" "app_config_feature_resource1" { @@ -65,6 +68,7 @@ func testAccCheckIbmAppConfigFeatureDataSourceConfigBasic(instanceName, name, en disabled_value = "false" description = "%s" tags = "%s" + rollout_percentage = "80" } data "ibm_app_config_feature" "ibm_app_config_feature_data1" { diff --git a/ibm/data_source_ibm_app_config_features.go b/ibm/service/appconfiguration/data_source_ibm_app_config_features.go similarity index 93% rename from ibm/data_source_ibm_app_config_features.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_features.go index 510f25270..ce64fe585 100644 --- a/ibm/data_source_ibm_app_config_features.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_features.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" @@ -15,7 +15,7 @@ import ( "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" ) -func dataSourceIbmAppConfigFeatures() *schema.Resource { +func DataSourceIBMAppConfigFeatures() *schema.Resource { return &schema.Resource{ Read: dataSourceIbmAppConfigFeaturesRead, @@ -119,6 +119,11 @@ func dataSourceIbmAppConfigFeatures() *schema.Resource { Computed: true, Description: "Tags associated with the feature.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Computed: true, + Description: "Rollout percentage of the feature.", + }, "segment_rules": { Type: schema.TypeList, Computed: true, @@ -152,6 +157,11 @@ func dataSourceIbmAppConfigFeatures() *schema.Resource { Computed: true, Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Computed: true, + Description: "Rollout percentage for the segment rule.", + }, }, }, }, @@ -340,48 +350,48 @@ func dataSourceIbmAppConfigFeaturesRead(d *schema.ResourceData, meta interface{} if featuresList.Features != nil { err = d.Set("features", dataSourceFeaturesListFlattenFeatures(featuresList.Features)) if err != nil { - return fmt.Errorf("error setting features %s", err) + return fmt.Errorf("[ERROR] Error setting features %s", err) } } if featuresList.TotalCount != nil { if err = d.Set("total_count", featuresList.TotalCount); err != nil { - return fmt.Errorf("error setting total_count: %s", err) + return fmt.Errorf("[ERROR] Error setting total_count: %s", err) } } if featuresList.Limit != nil { if err = d.Set("limit", featuresList.Limit); err != nil { - return fmt.Errorf("error setting limit: %s", err) + return fmt.Errorf("[ERROR] Error setting limit: %s", err) } } if featuresList.Offset != nil { if err = d.Set("offset", featuresList.Offset); err != nil { - return fmt.Errorf("error setting offset: %s", err) + return fmt.Errorf("[ERROR] Error setting offset: %s", err) } } if featuresList.First != nil { err = d.Set("first", dataSourceFeatureListFlattenPagination(*featuresList.First)) if err != nil { - return fmt.Errorf("error setting first %s", err) + return fmt.Errorf("[ERROR] Error setting first %s", err) } } if featuresList.Previous != nil { err = d.Set("previous", dataSourceFeatureListFlattenPagination(*featuresList.Previous)) if err != nil { - return fmt.Errorf("error setting previous %s", err) + return fmt.Errorf("[ERROR] Error setting previous %s", err) } } if featuresList.Last != nil { err = d.Set("last", dataSourceFeatureListFlattenPagination(*featuresList.Last)) if err != nil { - return fmt.Errorf("error setting last %s", err) + return fmt.Errorf("[ERROR] Error setting last %s", err) } } if featuresList.Next != nil { err = d.Set("next", dataSourceFeatureListFlattenPagination(*featuresList.Next)) if err != nil { - return fmt.Errorf("error setting next %s", err) + return fmt.Errorf("[ERROR] Error setting next %s", err) } } @@ -417,6 +427,9 @@ func dataSourceFeaturesListFeaturesToMap(featuresItem appconfigurationv1.Feature if featuresItem.Tags != nil { featuresMap["tags"] = featuresItem.Tags } + if featuresItem.RolloutPercentage != nil { + featuresMap["rollout_percentage"] = featuresItem.RolloutPercentage + } if featuresItem.SegmentRules != nil { segmentRulesList := []map[string]interface{}{} for _, segmentRulesItem := range featuresItem.SegmentRules { @@ -471,7 +484,7 @@ func dataSourceFeaturesListFeaturesToMap(featuresItem appconfigurationv1.Feature return featuresMap } -func dataSourceFeaturesListFeaturesSegmentRulesToMap(segmentRulesItem appconfigurationv1.SegmentRule) (segmentRulesMap map[string]interface{}) { +func dataSourceFeaturesListFeaturesSegmentRulesToMap(segmentRulesItem appconfigurationv1.FeatureSegmentRule) (segmentRulesMap map[string]interface{}) { segmentRulesMap = map[string]interface{}{} if segmentRulesItem.Rules != nil { @@ -495,6 +508,9 @@ func dataSourceFeaturesListFeaturesSegmentRulesToMap(segmentRulesItem appconfigu if segmentRulesItem.Order != nil { segmentRulesMap["order"] = segmentRulesItem.Order } + if segmentRulesItem.RolloutPercentage != nil { + segmentRulesMap["rollout_percentage"] = segmentRulesItem.RolloutPercentage + } return segmentRulesMap } diff --git a/ibm/data_source_ibm_app_config_features_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_features_test.go similarity index 92% rename from ibm/data_source_ibm_app_config_features_test.go rename to ibm/service/appconfiguration/data_source_ibm_app_config_features_test.go index b8dc34986..a6dc60779 100644 --- a/ibm/data_source_ibm_app_config_features_test.go +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_features_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIbmAppConfigFeaturesDataSourceBasic(t *testing.T) { instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmAppConfigFeaturesDataSourceConfigBasic(instanceName, name, environmentID, featureID, featureType, description, tags), @@ -48,7 +50,7 @@ func testAccCheckIbmAppConfigFeaturesDataSourceConfigBasic(instanceName, name, e name = "%s" location = "us-south" service = "apprapp" - plan = "standard" + plan = "lite" } resource "ibm_app_config_feature" "app_config_feature_resource2" { @@ -60,7 +62,8 @@ func testAccCheckIbmAppConfigFeaturesDataSourceConfigBasic(instanceName, name, e enabled_value = true disabled_value = false description = "%s" - tags = "%s" + tags = "%s" + rollout_percentage = "80" } data "ibm_app_config_features" "app_config_features_data2" { diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_properties.go b/ibm/service/appconfiguration/data_source_ibm_app_config_properties.go new file mode 100644 index 000000000..093706504 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_properties.go @@ -0,0 +1,439 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration + +import ( + "fmt" + "net/url" + "reflect" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" +) + +func DataSourceIBMAppConfigProperties() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigPropertiesRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "environment_id": { + Type: schema.TypeString, + Required: true, + Description: "Environment Id.", + }, + "sort": { + Type: schema.TypeString, + Optional: true, + Description: "Sort the feature details based on the specified attribute.", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Filter the resources to be returned based on the associated tags. Specify the parameter as a list of comma separated tags. Returns resources associated with any of the specified tags.", + }, + "collections": { + Type: schema.TypeList, + Optional: true, + Description: "Filter features by a list of comma separated collections.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "segments": { + Type: schema.TypeList, + Optional: true, + Description: "Filter features by a list of comma separated segments.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "expand": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to `true`, returns expanded view of the resource details.", + }, + "include": { + Type: schema.TypeList, + Optional: true, + Description: "Include the associated collections or targeting rules details in the response.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "limit": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + }, + "properties": { + Type: schema.TypeList, + Computed: true, + Description: "Array of properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "property_id": { + Type: schema.TypeString, + Computed: true, + Description: "Property id.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Property description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the Property (BOOLEAN, STRING, NUMERIC).", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "tags": { + Type: schema.TypeString, + Computed: true, + Description: "Tags associated with the property.", + }, + "segment_rules": { + Type: schema.TypeList, + Computed: true, + Description: "Specify the targeting rules that is used to set different property values for different segments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "Rules array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "segments": { + Type: schema.TypeList, + Computed: true, + Description: "List of segment ids that are used for targeting using the rule.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "order": { + Type: schema.TypeInt, + Computed: true, + Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + }, + }, + }, + }, + "segment_exists": { + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if the targeting rules are specified for the property.", + }, + "collections": { + Type: schema.TypeList, + Computed: true, + Description: "List of collection id representing the collections that are associated with the specified property.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the collection.", + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the property.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the property data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Property URL.", + }, + }, + }, + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of records returned in the current response.", + }, + }, + } +} + +func dataSourceIbmAppConfigPropertiesRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.ListPropertiesOptions{} + + options.SetEnvironmentID(d.Get("environment_id").(string)) + + if _, ok := d.GetOk("expand"); ok { + options.SetExpand(d.Get("expand").(bool)) + } + if _, ok := d.GetOk("sort"); ok { + options.SetSort(d.Get("sort").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + if _, ok := d.GetOk("collections"); ok { + collections := []string{} + for _, item := range d.Get("collections").([]interface{}) { + collections = append(collections, item.(string)) + } + options.SetCollections(collections) + } + if _, ok := d.GetOk("segments"); ok { + segments := []string{} + for _, item := range d.Get("segments").([]interface{}) { + segments = append(segments, item.(string)) + } + options.SetSegments(segments) + } + if _, ok := d.GetOk("include"); ok { + includes := []string{} + for _, item := range d.Get("include").([]interface{}) { + includes = append(includes, item.(string)) + } + options.SetInclude(includes) + } + + var propertiesList *appconfigurationv1.PropertiesList + var offset int64 + var limit int64 = 10 + var isLimit bool + + finalList := []appconfigurationv1.Property{} + if _, ok := d.GetOk("limit"); ok { + isLimit = true + limit = int64(d.Get("limit").(int)) + } + options.SetLimit(limit) + if _, ok := d.GetOk("offset"); ok { + offset = int64(d.Get("offset").(int)) + } + for { + options.Offset = &offset + result, response, err := appconfigClient.ListProperties(options) + propertiesList = result + if err != nil { + return fmt.Errorf("ListProperties failed %s\n%s", err, response) + } + if isLimit { + offset = 0 + } else { + offset = dataSourcePropertiesListGetNext(result.Next) + } + finalList = append(finalList, result.Properties...) + if offset == 0 { + break + } + } + + propertiesList.Properties = finalList + + d.SetId(fmt.Sprintf("%s/%s", guid, *options.EnvironmentID)) + + if propertiesList.Properties != nil { + err = d.Set("properties", dataSourcePropertiesListFlattenProperties(propertiesList.Properties)) + if err != nil { + return fmt.Errorf("error setting properties %s", err) + } + } + if propertiesList.TotalCount != nil { + if err = d.Set("total_count", propertiesList.TotalCount); err != nil { + return fmt.Errorf("error setting total_count: %s", err) + } + } + if propertiesList.Limit != nil { + if err = d.Set("limit", propertiesList.Limit); err != nil { + return fmt.Errorf("error setting limit: %s", err) + } + } + if propertiesList.Offset != nil { + if err = d.Set("offset", propertiesList.Offset); err != nil { + return fmt.Errorf("error setting offset: %s", err) + } + } + + return nil +} + +func dataSourcePropertiesListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} + +func dataSourcePropertiesListFlattenProperties(result []appconfigurationv1.Property) (properties []map[string]interface{}) { + for _, propertyItem := range result { + properties = append(properties, dataSourcePropertiesListPropertiesToMap(propertyItem)) + } + return properties +} + +func dataSourcePropertiesListPropertiesToMap(property appconfigurationv1.Property) (propertyMap map[string]interface{}) { + propertyMap = map[string]interface{}{} + + if property.Name != nil { + propertyMap["name"] = property.Name + } + if property.PropertyID != nil { + propertyMap["property_id"] = property.PropertyID + } + if property.Description != nil { + propertyMap["description"] = property.Description + } + if property.Type != nil { + propertyMap["type"] = property.Type + } + if property.Value != nil { + value := property.Value + switch value.(interface{}).(type) { + case string: + propertyMap["value"] = value.(string) + case float64: + propertyMap["value"] = fmt.Sprintf("%v", value) + case bool: + propertyMap["value"] = strconv.FormatBool(value.(bool)) + } + } + if property.Tags != nil { + propertyMap["tags"] = property.Tags + } + if property.SegmentExists != nil { + propertyMap["segment_exists"] = property.SegmentExists + } + if property.UpdatedTime != nil { + propertyMap["updated_time"] = property.UpdatedTime.String() + } + if property.CreatedTime != nil { + propertyMap["created_time"] = property.CreatedTime.String() + } + if property.Href != nil { + propertyMap["href"] = property.Href + } + if property.Collections != nil { + collectionsList := []map[string]interface{}{} + for _, collectionsItem := range property.Collections { + collectionsList = append(collectionsList, dataSourcePropertiesListPropertiesCollectionsToMap(collectionsItem)) + } + propertyMap["collections"] = collectionsList + } + if property.SegmentRules != nil { + segmentRulesList := []map[string]interface{}{} + for _, segmentRulesItem := range property.SegmentRules { + segmentRulesList = append(segmentRulesList, dataSourcePropertyListPropertiesSegmentRulesToMap(segmentRulesItem)) + } + propertyMap["segment_rules"] = segmentRulesList + } + return propertyMap +} + +func dataSourcePropertiesListPropertiesCollectionsToMap(collectionsItem appconfigurationv1.CollectionRef) (collectionsMap map[string]interface{}) { + collectionsMap = map[string]interface{}{} + + if collectionsItem.CollectionID != nil { + collectionsMap["collection_id"] = collectionsItem.CollectionID + } + if collectionsItem.Name != nil { + collectionsMap["name"] = collectionsItem.Name + } + + return collectionsMap +} + +func dataSourcePropertyListPropertiesSegmentRulesToMap(segmentRulesItem appconfigurationv1.SegmentRule) (segmentRulesMap map[string]interface{}) { + segmentRulesMap = map[string]interface{}{} + + if segmentRulesItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, rulesItem := range segmentRulesItem.Rules { + rulesList = append(rulesList, dataSourceListPropertiesSegmentRulesToMap(rulesItem)) + } + segmentRulesMap["rules"] = rulesList + } + if segmentRulesItem.Value != nil { + segmentValue := segmentRulesItem.Value + switch segmentValue.(interface{}).(type) { + case string: + segmentRulesMap["value"] = segmentValue.(string) + case float64: + segmentRulesMap["value"] = fmt.Sprintf("%v", segmentValue) + case bool: + segmentRulesMap["value"] = strconv.FormatBool(segmentValue.(bool)) + } + } + if segmentRulesItem.Order != nil { + segmentRulesMap["order"] = segmentRulesItem.Order + } + + return segmentRulesMap +} + +func dataSourceListPropertiesSegmentRulesToMap(rule appconfigurationv1.TargetSegments) map[string]interface{} { + ruleMap := map[string]interface{}{} + + ruleMap["segments"] = rule.Segments + + return ruleMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_properties_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_properties_test.go new file mode 100644 index 000000000..5c0c829d8 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_properties_test.go @@ -0,0 +1,69 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmAppConfigPropertiesDataSourceBasic(t *testing.T) { + propertyType := "BOOLEAN" + name := fmt.Sprintf("tf_test_%d", acctest.RandIntRange(10, 100)) + propertyID := fmt.Sprintf("tf_property_id_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tags := fmt.Sprintf("tf_tags_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigPropertiesDataSourceConfig(instanceName, name, propertyID, propertyType, description, tags), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.#"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.0.property_id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.0.description"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "properties.0.tags"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_properties.app_config_properties", "total_count"), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigPropertiesDataSourceConfig(instanceName, name, propertyID, propertyType, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test494" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_property" "app_config_properties_resource21" { + guid = ibm_resource_instance.app_config_terraform_test494.guid + environment_id = "dev" + name = "%s" + property_id = "%s" + type = "%s" + value = "false" + description = "%s" + tags = "%s" + } + data "ibm_app_config_properties" "app_config_properties" { + guid = ibm_app_config_property.app_config_properties_resource21.guid + environment_id = ibm_app_config_property.app_config_properties_resource21.environment_id + expand = true + } + `, instanceName, name, propertyID, propertyType, description, tags) +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_property.go b/ibm/service/appconfiguration/data_source_ibm_app_config_property.go new file mode 100644 index 000000000..a2e1d4e5d --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_property.go @@ -0,0 +1,286 @@ +package appconfiguration + +import ( + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" +) + +func DataSourceIBMAppConfigProperty() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigPropertyRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "environment_id": { + Type: schema.TypeString, + Required: true, + Description: "Environment Id.", + }, + "property_id": { + Type: schema.TypeString, + Required: true, + Description: "Property Id.", + }, + "include": { + Type: schema.TypeString, + Optional: true, + Description: "Include the associated collections in the response.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Property description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the Property (BOOLEAN, STRING, NUMERIC).", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "tags": { + Type: schema.TypeString, + Computed: true, + Description: "Tags associated with the property.", + }, + "segment_rules": { + Type: schema.TypeList, + Computed: true, + Description: "Specify the targeting rules that is used to set different property values for different segments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "Rules array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "segments": { + Type: schema.TypeList, + Computed: true, + Description: "List of segment ids that are used for targeting using the rule.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "order": { + Type: schema.TypeInt, + Computed: true, + Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + }, + }, + }, + }, + "segment_exists": { + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if the targeting rules are specified for the property.", + }, + "collections": { + Type: schema.TypeList, + Computed: true, + Description: "List of collection id representing the collections that are associated with the specified property.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the collection.", + }, + }, + }, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the property.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the property data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Property URL.", + }, + }, + } +} + +func dataSourceIbmAppConfigPropertyRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.GetPropertyOptions{} + + options.SetEnvironmentID(d.Get("environment_id").(string)) + options.SetPropertyID(d.Get("property_id").(string)) + + if _, ok := d.GetOk("include"); ok { + options.SetInclude(d.Get("include").(string)) + } + + property, response, err := appconfigClient.GetProperty(options) + + if err != nil { + return fmt.Errorf("GetProperty failed %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", guid, *options.EnvironmentID, *property.PropertyID)) + + if property.Name != nil { + if err = d.Set("name", property.Name); err != nil { + return fmt.Errorf("error setting name: %s", err) + } + } + if property.Description != nil { + if err = d.Set("description", property.Description); err != nil { + return fmt.Errorf("error setting description: %s", err) + } + } + if property.Type != nil { + if err = d.Set("type", property.Type); err != nil { + return fmt.Errorf("error setting type: %s", err) + } + } + if property.Value != nil { + value := property.Value + switch value.(interface{}).(type) { + case string: + d.Set("value", value.(string)) + case float64: + d.Set("value", fmt.Sprintf("%v", value)) + case bool: + d.Set("value", strconv.FormatBool(value.(bool))) + } + } + if property.Tags != nil { + if err = d.Set("tags", property.Tags); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + } + if property.SegmentRules != nil { + err = d.Set("segment_rules", dataSourcePropertyFlattenSegmentRules(property.SegmentRules)) + if err != nil { + return fmt.Errorf("error setting segment_rules %s", err) + } + } + if property.SegmentExists != nil { + if err = d.Set("segment_exists", property.SegmentExists); err != nil { + return fmt.Errorf("error setting segment_exists: %s", err) + } + } + if property.Collections != nil { + err = d.Set("collections", dataSourcePropertyFlattenCollections(property.Collections)) + if err != nil { + return fmt.Errorf("error setting collections %s", err) + } + } + if property.CreatedTime != nil { + if err = d.Set("created_time", property.CreatedTime.String()); err != nil { + return fmt.Errorf("error setting created_time: %s", err) + } + } + if property.UpdatedTime != nil { + if err = d.Set("updated_time", property.UpdatedTime.String()); err != nil { + return fmt.Errorf("error setting updated_time: %s", err) + } + } + if property.Href != nil { + if err = d.Set("href", property.Href); err != nil { + return fmt.Errorf("error setting href: %s", err) + } + } + return nil +} + +func dataSourcePropertyFlattenCollections(result []appconfigurationv1.CollectionRef) (collections []map[string]interface{}) { + for _, collectionsItem := range result { + collections = append(collections, dataSourcePropertyCollectionsToMap(collectionsItem)) + } + + return collections +} + +func dataSourcePropertyCollectionsToMap(collectionsItem appconfigurationv1.CollectionRef) (collectionsMap map[string]interface{}) { + collectionsMap = map[string]interface{}{} + + if collectionsItem.CollectionID != nil { + collectionsMap["collection_id"] = collectionsItem.CollectionID + } + if collectionsItem.Name != nil { + collectionsMap["name"] = collectionsItem.Name + } + + return collectionsMap +} + +func dataSourcePropertyFlattenSegmentRules(result []appconfigurationv1.SegmentRule) (segmentRules []map[string]interface{}) { + for _, segmentRulesItem := range result { + segmentRules = append(segmentRules, dataSourcePropertySegmentRulesToMap(segmentRulesItem)) + } + return segmentRules +} + +func dataSourcePropertySegmentRulesToMap(segmentRulesItem appconfigurationv1.SegmentRule) (segmentRulesMap map[string]interface{}) { + segmentRulesMap = map[string]interface{}{} + + if segmentRulesItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, rulesItem := range segmentRulesItem.Rules { + rulesList = append(rulesList, dataSourceFeatureSegmentRulesRulesToMap(rulesItem)) + } + segmentRulesMap["rules"] = rulesList + } + if segmentRulesItem.Value != nil { + segmentValue := segmentRulesItem.Value + switch segmentValue.(interface{}).(type) { + case string: + segmentRulesMap["value"] = segmentValue.(string) + case float64: + segmentRulesMap["value"] = fmt.Sprintf("%v", segmentValue) + case bool: + segmentRulesMap["value"] = strconv.FormatBool(segmentValue.(bool)) + } + } + if segmentRulesItem.Order != nil { + segmentRulesMap["order"] = segmentRulesItem.Order + } + + return segmentRulesMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_property_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_property_test.go new file mode 100644 index 000000000..27db8f1f4 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_property_test.go @@ -0,0 +1,72 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package appconfiguration_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmAppConfigPropertyDataSource(t *testing.T) { + environmentID := "dev" + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + propertyID := fmt.Sprintf("tf_property_id_%d", acctest.RandIntRange(10, 100)) + propertyType := "BOOLEAN" + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigPropertyDataSourceConfigBasic(instanceName, environmentID, name, propertyID, propertyType, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "environment_id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "property_id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "type"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "value"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "segment_rules.#"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "segment_exists"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "created_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "updated_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_property.ibm_app_config_property_data1", "href"), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigPropertyDataSourceConfigBasic(instanceName, environmentID, name, propertyID, propertyType, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test482" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_property" "app_config_property" { + guid = ibm_resource_instance.app_config_terraform_test482.guid + environment_id = "%s" + name = "%s" + property_id = "%s" + type = "%s" + value = "true" + description = "%s" + } + data "ibm_app_config_property" "ibm_app_config_property_data1" { + guid = ibm_resource_instance.app_config_terraform_test482.guid + environment_id = ibm_app_config_property.app_config_property.environment_id + property_id = ibm_app_config_property.app_config_property.property_id + include = "collections" + } + `, instanceName, environmentID, name, propertyID, propertyType, description) +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_segment.go b/ibm/service/appconfiguration/data_source_ibm_app_config_segment.go new file mode 100644 index 000000000..c27af0128 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_segment.go @@ -0,0 +1,265 @@ +package appconfiguration + +import ( + "fmt" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" +) + +func DataSourceIBMAppConfigSegment() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigSegmentRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "segment_id": { + Type: schema.TypeString, + Required: true, + Description: "Segment id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Segment name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Segment description.", + }, + "tags": { + Type: schema.TypeString, + Computed: true, + Description: "Tags associated with the segment.", + }, + "includes": { + Type: schema.TypeList, + Optional: true, + Description: "Include feature and property details in the response.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the segment.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the segment data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Segment flag URL.", + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "List of rules that determine if the entity belongs to the segment during feature / property evaluation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeList, + Computed: true, + Description: "List of values. Entities matching any of the given values will be considered to belong to the segment", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "attribute_name": { + Type: schema.TypeString, + Computed: true, + Description: "Attribute name.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator to be used for the evaluation if the entity belongs to the segment.", + }, + }, + }, + }, + "features": { + Type: schema.TypeList, + Computed: true, + Description: "List of Features associated with the segment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "feature_id": { + Type: schema.TypeString, + Computed: true, + Description: "feature id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Feature.", + }, + }, + }, + }, + "properties": { + Type: schema.TypeList, + Computed: true, + Description: "List of Features associated with the segment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "property_id": { + Type: schema.TypeString, + Computed: true, + Description: "property id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Property.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigSegmentRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return err + } + + options := &appconfigurationv1.GetSegmentOptions{} + options.SetSegmentID(d.Get("segment_id").(string)) + + if _, ok := d.GetOk("includes"); ok { + includes := []string{} + for _, segmentsItem := range d.Get("includes").([]interface{}) { + includes = append(includes, segmentsItem.(string)) + } + options.SetInclude(includes) + } + + result, response, err := appconfigClient.GetSegment(options) + if err != nil { + log.Printf("[DEBUG] GetSegment failed %s\n%s", err, response) + return err + } + + d.SetId(fmt.Sprintf("%s/%s", guid, *result.SegmentID)) + + if result.Name != nil { + if err = d.Set("name", result.Name); err != nil { + return fmt.Errorf("[ERROR] Error setting name: %s", err) + } + } + if result.SegmentID != nil { + if err = d.Set("segment_id", result.SegmentID); err != nil { + return fmt.Errorf("[ERROR] Error setting segment_id: %s", err) + } + } + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return fmt.Errorf("[ERROR] Error setting description: %s", err) + } + } + if result.Tags != nil { + if err = d.Set("tags", result.Tags); err != nil { + return fmt.Errorf("[ERROR] Error setting tags: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + if result.Rules != nil { + rulesList := []map[string]interface{}{} + for _, ruleItem := range result.Rules { + rulesList = append(rulesList, dataSourceSegmentListSegmentRulesToMap(ruleItem)) + if err = d.Set("rules", rulesList); err != nil { + return fmt.Errorf("[ERROR] Error setting rules %s", err) + } + } + } + if result.Features != nil { + err = d.Set("features", dataSourceSegmentFlattenFeatures(result.Features)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting features %s", err) + } + } + if result.Properties != nil { + err = d.Set("properties", dataSourceSegmentFlattenProperties(result.Properties)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting properties %s", err) + } + } + return nil +} + +func dataSourceSegmentListSegmentRulesToMap(segmentRulesItem appconfigurationv1.Rule) (segmentRulesMap map[string]interface{}) { + segmentRulesMap = map[string]interface{}{} + + segmentRulesMap["values"] = segmentRulesItem.Values + segmentRulesMap["attribute_name"] = segmentRulesItem.AttributeName + segmentRulesMap["operator"] = segmentRulesItem.Operator + + return segmentRulesMap +} + +func dataSourceSegmentFlattenFeatures(result []appconfigurationv1.FeatureOutput) (features []map[string]interface{}) { + for _, featuresItem := range result { + features = append(features, dataSourceSegmentFeaturesToMap(featuresItem)) + } + + return features +} + +func dataSourceSegmentFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + + return featuresMap +} + +func dataSourceSegmentFlattenProperties(result []appconfigurationv1.PropertyOutput) (properties []map[string]interface{}) { + for _, propertiesItem := range result { + properties = append(properties, dataSourceSegmentPropertiesToMap(propertiesItem)) + } + return properties +} + +func dataSourceSegmentPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + + return propertiesMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_segment_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_segment_test.go new file mode 100644 index 000000000..4d7ba04e0 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_segment_test.go @@ -0,0 +1,69 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" +) + +func TestAccIbmAppConfigSegmentDataSource(t *testing.T) { + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + segmentID := fmt.Sprintf("tf_segment_id_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tags := "development segment" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigSegmentDataSourceConfigBasic(instanceName, name, segmentID, description, tags), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "tags"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "segment_id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "created_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "updated_time"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segment.ibm_app_config_segment_data1", "href"), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigSegmentDataSourceConfigBasic(instanceName, name, segmentID, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test456" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_segment" "app_config_segment_resource1" { + guid = ibm_resource_instance.app_config_terraform_test456.guid + name = "%s" + segment_id = "%s" + rules { + attribute_name = "countary" + operator = "contains" + values = ["india", "UK"] + } + description = "%s" + tags = "%s" + } + + data "ibm_app_config_segment" "ibm_app_config_segment_data1" { + guid = ibm_app_config_segment.app_config_segment_resource1.guid + segment_id = ibm_app_config_segment.app_config_segment_resource1.segment_id + tags = ibm_app_config_segment.app_config_segment_resource1.tags + } + `, instanceName, name, segmentID, description, tags) +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_segments.go b/ibm/service/appconfiguration/data_source_ibm_app_config_segments.go new file mode 100644 index 000000000..084110938 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_segments.go @@ -0,0 +1,375 @@ +package appconfiguration + +import ( + "fmt" + "log" + "net/url" + "reflect" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" +) + +func DataSourceIBMAppConfigSegments() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigSegmentsRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Filter the resources to be returned based on the associated tags.", + }, + "sort": { + Type: schema.TypeString, + Optional: true, + Description: "Sort the segment details based on the specified attribute.", + }, + "include": { + Type: schema.TypeString, + Optional: true, + Description: "Segment details to include the associated rules in the response", + }, + "expand": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to `true`, returns expanded view of the resource details.", + }, + "limit": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + }, + "total_count": { + Type: schema.TypeInt, + Optional: true, + Description: "Total number of records.", + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + }, + "segments": { + Type: schema.TypeList, + Computed: true, + Description: "Array of Segments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Segment name.", + }, + "segment_id": { + Type: schema.TypeString, + Computed: true, + Description: "Segment id.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Segment description.", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Tags associated with the segments.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the segment.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the segment data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Segment URL..", + }, + "features": { + Type: schema.TypeList, + Computed: true, + Description: "List of Features associated with the segment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "feature_id": { + Type: schema.TypeString, + Computed: true, + Description: "feature id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Feature.", + }, + }, + }, + }, + "properties": { + Type: schema.TypeList, + Computed: true, + Description: "List of properties associated with the segment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "property_id": { + Type: schema.TypeString, + Computed: true, + Description: "property id.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Property.", + }, + }, + }, + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "List of rules that determine if the entity belongs to the segment during feature / property evaluation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeList, + Computed: true, + Description: "List of values. Entities matching any of the given values will be considered to belong to the segment", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "attribute_name": { + Type: schema.TypeString, + Computed: true, + Description: "Attribute name.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator to be used for the evaluation if the entity belongs to the segment.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigSegmentsRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.ListSegmentsOptions{} + + if _, ok := d.GetOk("expand"); ok { + options.SetExpand(d.Get("expand").(bool)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + if _, ok := d.GetOk("sort"); ok { + options.SetTags(d.Get("sort").(string)) + } + + if _, ok := d.GetOk("include"); ok { + options.SetInclude(d.Get("include").(string)) + } + + var segmentsList *appconfigurationv1.SegmentsList + var offset int64 + var limit int64 = 10 + var isLimit bool + + finalList := []appconfigurationv1.Segment{} + + if _, ok := d.GetOk("limit"); ok { + isLimit = true + limit = int64(d.Get("limit").(int)) + } + options.SetLimit(limit) + if _, ok := d.GetOk("offset"); ok { + offset = int64(d.Get("offset").(int)) + } + for { + options.Offset = &offset + result, response, err := appconfigClient.ListSegments(options) + segmentsList = result + if err != nil { + log.Printf("[DEBUG] ListSegments failed %s\n%s", err, response) + return fmt.Errorf("ListSegments failed %s\n%s", err, response) + } + if isLimit { + offset = 0 + } else { + offset = dataSourceSegmentsListGetNext(result.Next) + } + finalList = append(finalList, result.Segments...) + if offset == 0 { + break + } + } + + segmentsList.Segments = finalList + + d.SetId(fmt.Sprintf("%s", guid)) + + if segmentsList.Segments != nil { + err = d.Set("segments", dataSourceSegmentsListFlattenSegments(segmentsList.Segments)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting segments %s", err) + } + } + if segmentsList.Limit != nil { + if err = d.Set("limit", segmentsList.Limit); err != nil { + return fmt.Errorf("[ERROR] Error setting limit: %s", err) + } + } + if segmentsList.Offset != nil { + if err = d.Set("offset", segmentsList.Offset); err != nil { + return fmt.Errorf("[ERROR] Error setting offset: %s", err) + } + } + if segmentsList.TotalCount != nil { + if err = d.Set("total_count", segmentsList.TotalCount); err != nil { + return fmt.Errorf("[ERROR] Error setting total_count: %s", err) + } + } + return nil +} + +func dataSourceSegmentsListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} + +func dataSourceSegmentsListFlattenSegments(result []appconfigurationv1.Segment) (segments []map[string]interface{}) { + for _, segmentsItem := range result { + segments = append(segments, dataSourceSegmentsListSegmentsToMap(segmentsItem)) + } + return segments +} + +func dataSourceSegmentsListSegmentsToMap(segmentsItem appconfigurationv1.Segment) (segmentsMap map[string]interface{}) { + segmentsMap = map[string]interface{}{} + + if segmentsItem.Name != nil { + segmentsMap["name"] = segmentsItem.Name + } + if segmentsItem.SegmentID != nil { + segmentsMap["segment_id"] = segmentsItem.SegmentID + } + if segmentsItem.Description != nil { + segmentsMap["description"] = segmentsItem.Description + } + if segmentsItem.Tags != nil { + segmentsMap["tags"] = segmentsItem.Tags + } + if segmentsItem.CreatedTime != nil { + segmentsMap["created_time"] = segmentsItem.CreatedTime.String() + } + if segmentsItem.UpdatedTime != nil { + segmentsMap["updated_time"] = segmentsItem.UpdatedTime.String() + } + if segmentsItem.Href != nil { + segmentsMap["href"] = segmentsItem.Href + } + if segmentsItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, segmentRulesItem := range segmentsItem.Rules { + rulesList = append(rulesList, dataSourceSegmentsListSegmentRulesToMap(segmentRulesItem)) + } + segmentsMap["rules"] = rulesList + } + if segmentsItem.Features != nil { + featuresList := []map[string]interface{}{} + for _, segmentsItem := range segmentsItem.Features { + featuresList = append(featuresList, dataSourceSegmentsListSegmentsFeaturesToMap(segmentsItem)) + } + segmentsMap["features"] = featuresList + } + if segmentsItem.Properties != nil { + propertiesList := []map[string]interface{}{} + for _, segmentsItem := range segmentsItem.Properties { + propertiesList = append(propertiesList, dataSourcePropertiesListSegmentsPropertiesToMap(segmentsItem)) + } + segmentsMap["properties"] = propertiesList + } + + return segmentsMap +} + +func dataSourceSegmentsListSegmentRulesToMap(segmentRulesItem appconfigurationv1.Rule) (segmentRulesMap map[string]interface{}) { + segmentRulesMap = map[string]interface{}{} + + segmentRulesMap["values"] = segmentRulesItem.Values + segmentRulesMap["attribute_name"] = segmentRulesItem.AttributeName + segmentRulesMap["operator"] = segmentRulesItem.Operator + + return segmentRulesMap +} + +func dataSourceSegmentsListSegmentsFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + + return featuresMap +} + +func dataSourcePropertiesListSegmentsPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + + return propertiesMap +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_segments_test.go b/ibm/service/appconfiguration/data_source_ibm_app_config_segments_test.go new file mode 100644 index 000000000..9f6da3223 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_segments_test.go @@ -0,0 +1,71 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmAppConfigSegmentsDataSourceBasic(t *testing.T) { + + tags := "development segment" + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + segmentID := fmt.Sprintf("tf_segment_id_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigSegmentsDataSourceConfigBasic(instanceName, name, segmentID, description, tags), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "id"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "segments.#"), + resource.TestCheckResourceAttrSet("data.ibm_app_config_segments.app_config_segments_data2", "segments.0.segment_id"), + resource.TestCheckResourceAttr("data.ibm_app_config_segments.app_config_segments_data2", "segments.0.name", name), + resource.TestCheckResourceAttr("data.ibm_app_config_segments.app_config_segments_data2", "segments.0.segment_id", segmentID), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigSegmentsDataSourceConfigBasic(instanceName, name, segmentID, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test487" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + + resource "ibm_app_config_segment" "app_config_segment_resource2" { + guid = ibm_resource_instance.app_config_terraform_test487.guid + name = "%s" + segment_id = "%s" + rules { + attribute_name = "countary" + operator = "contains" + values = ["india", "UK"] + } + description = "%s" + tags = "%s" + } + + data "ibm_app_config_segments" "app_config_segments_data2" { + guid = ibm_app_config_segment.app_config_segment_resource2.guid + } + `, instanceName, name, segmentID, description, tags) +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_snapshot.go b/ibm/service/appconfiguration/data_source_ibm_app_config_snapshot.go new file mode 100644 index 000000000..bd03ec487 --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_snapshot.go @@ -0,0 +1,251 @@ +package appconfiguration + +import ( + "fmt" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMAppConfigSnapshot() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigSnapshotRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "git_config_id": { + Type: schema.TypeString, + Required: true, + Description: "Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + }, + "git_config_name": { + Type: schema.TypeString, + Computed: true, + Description: "Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + }, + "git_url": { + Type: schema.TypeString, + Computed: true, + Description: "Git url which will be used to connect to the github account.", + }, + "git_branch": { + Type: schema.TypeString, + Computed: true, + Description: "Branch name to which you need to write or update the configuration.", + }, + "git_file_path": { + Type: schema.TypeString, + Computed: true, + Description: "Git file path, this is a path where your configuration file will be written.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the git config.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the git config data.", + }, + "last_sync_time": { + Type: schema.TypeString, + Computed: true, + Description: "Latest time when the snapshot was synced to git.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Git config URL.", + }, + "collection": { + Type: schema.TypeList, + Computed: true, + Description: "Collection object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_name": { + Type: schema.TypeString, + Computed: true, + Description: "Collection name.", + }, + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + }, + }, + }, + "environment": { + Type: schema.TypeList, + Computed: true, + Description: "Environment object", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "environment_name": { + Type: schema.TypeString, + Computed: true, + Description: "Environment name.", + }, + "environment_id": { + Type: schema.TypeString, + Computed: true, + Description: "Environment id.", + }, + "color_code": { + Type: schema.TypeString, + Computed: true, + Description: "Environment color code.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigSnapshotRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.GetGitconfigOptions{} + options.SetGitConfigID(d.Get("git_config_id").(string)) + + result, response, err := appconfigClient.GetGitconfig(options) + + if err != nil { + return fmt.Errorf("GetGitconfig failed %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s", guid, *result.GitConfigID)) + + if result.GitConfigName != nil { + if err = d.Set("git_config_name", result.GitConfigName); err != nil { + return fmt.Errorf("[ERROR] Error setting git_config_name: %s", err) + } + } + if result.GitConfigID != nil { + if err = d.Set("git_config_id", result.GitConfigID); err != nil { + return fmt.Errorf("[ERROR] Error setting git_config_id: %s", err) + } + } + if result.GitURL != nil { + if err = d.Set("git_url", result.GitURL); err != nil { + return fmt.Errorf("[ERROR] Error setting git_url: %s", err) + } + } + if result.GitBranch != nil { + if err = d.Set("git_branch", result.GitBranch); err != nil { + return fmt.Errorf("[ERROR] Error setting git_branch: %s", err) + } + } + if result.GitFilePath != nil { + if err = d.Set("git_file_path", result.GitFilePath); err != nil { + return fmt.Errorf("[ERROR] Error setting git_file_path: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) + } + } + if result.LastSyncTime != nil { + if err = d.Set("last_sync_time", result.LastSyncTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting last_sync_time: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + if result.Collection != nil { + collectionItemMap := resourceIbmAppConfigSnapshotCollectionRefToMap(result.Collection) + if err = d.Set("collection", collectionItemMap); err != nil { + return fmt.Errorf("[ERROR] Error setting collection: %s", err) + } + } + if result.Environment != nil { + environmentItemMap := resourceIbmAppConfigSnapshotEnvironmentRefToMap(result.Environment) + if err = d.Set("environment", environmentItemMap); err != nil { + return fmt.Errorf("[ERROR] Error setting environment: %s", err) + } + } + return nil +} + +type CollectionRef map[string]interface{} + +type Collections struct { + Collection_name string `json:"name"` + Collection_id string `json:"collection_id"` +} + +func resourceIbmAppConfigSnapshotCollectionRefToMap(collectionRef interface{}) []CollectionRef { + collections := getSnapshotCollection(collectionRef) + collectionRefMap := CollectionRef{} + var collectionMap []CollectionRef + collectionRefMap["collection_id"] = collections.Collection_id + collectionRefMap["collection_name"] = collections.Collection_name + collectionMap = append(collectionMap, collectionRefMap) + return collectionMap +} + +func getSnapshotCollection(data interface{}) Collections { + m := data.(map[string]interface{}) + collection := Collections{} + if name, ok := m["name"].(string); ok { + collection.Collection_name = name + } + if id, ok := m["collection_id"].(string); ok { + collection.Collection_id = id + } + return collection +} + +type EnvironmentRef map[string]interface{} + +type Environments struct { + Environment_name string `json:"name"` + Environment_id string `json:"environment_id"` + Color_code string `json:"color_code"` +} + +func resourceIbmAppConfigSnapshotEnvironmentRefToMap(environmentRef interface{}) []EnvironmentRef { + environments := getSnapshotEnvironment(environmentRef) + environmentRefMap := EnvironmentRef{} + var environmentMap []EnvironmentRef + environmentRefMap["environment_id"] = environments.Environment_id + environmentRefMap["environment_name"] = environments.Environment_name + environmentRefMap["color_code"] = environments.Color_code + environmentMap = append(environmentMap, environmentRefMap) + return environmentMap +} + +func getSnapshotEnvironment(data interface{}) Environments { + m := data.(map[string]interface{}) + environment := Environments{} + if name, ok := m["name"].(string); ok { + environment.Environment_name = name + } + if id, ok := m["environment_id"].(string); ok { + environment.Environment_id = id + } + if color, ok := m["color_code"].(string); ok { + environment.Color_code = color + } + return environment +} diff --git a/ibm/service/appconfiguration/data_source_ibm_app_config_snapshots.go b/ibm/service/appconfiguration/data_source_ibm_app_config_snapshots.go new file mode 100644 index 000000000..68c5941df --- /dev/null +++ b/ibm/service/appconfiguration/data_source_ibm_app_config_snapshots.go @@ -0,0 +1,357 @@ +package appconfiguration + +import ( + "fmt" + "net/url" + "reflect" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" +) + +func DataSourceIBMAppConfigSnapshots() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIbmAppConfigSnapshotsRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "collection_id": { + Type: schema.TypeString, + Optional: true, + Description: "Filters the response based on the specified collection_id.", + }, + "environment_id": { + Type: schema.TypeString, + Optional: true, + Description: "Filters the response based on the specified environment_id.", + }, + "limit": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Description: "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Total number of records.", + }, + "git_config": { + Type: schema.TypeList, + Computed: true, + Description: "Array of git_config.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_config_name": { + Type: schema.TypeString, + Optional: true, + Description: "Git config name.", + }, + "git_config_id": { + Type: schema.TypeString, + Optional: true, + Description: "Git config id", + }, + "git_url": { + Type: schema.TypeString, + Optional: true, + Description: "Git url which will be used to connect to the github account", + }, + "git_branch": { + Type: schema.TypeString, + Optional: true, + Description: "Git url which will be used to connect to the github account", + }, + "git_file_path": { + Type: schema.TypeString, + Optional: true, + Description: "Git file path, this is a path where your configuration file will be written.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the git config.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the git config data.", + }, + "last_sync_time": { + Type: schema.TypeString, + Computed: true, + Description: "Latest time when the snapshot was synced to git.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Git config URL.", + }, + "collection": { + Type: schema.TypeList, + Computed: true, + Description: "Collection object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_name": { + Type: schema.TypeString, + Computed: true, + Description: "Collection name.", + }, + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + }, + }, + }, + "environment": { + Type: schema.TypeList, + Computed: true, + Description: "Environment object", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "environment_name": { + Type: schema.TypeString, + Computed: true, + Description: "Environment name.", + }, + "environment_id": { + Type: schema.TypeString, + Computed: true, + Description: "Environment id.", + }, + "color_code": { + Type: schema.TypeString, + Computed: true, + Description: "Environment color code.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmAppConfigSnapshotsRead(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.ListSnapshotsOptions{} + + if _, ok := d.GetOk("collection_id"); ok { + options.SetCollectionID(d.Get("collection_id").(string)) + } + if _, ok := d.GetOk("environment_id"); ok { + options.SetEnvironmentID(d.Get("environment_id").(string)) + } + if _, ok := d.GetOk("search"); ok { + options.SetSearch(d.Get("search").(string)) + } + if _, ok := d.GetOk("sort"); ok { + options.SetSort(d.Get("sort").(string)) + } + + var shapshotsList *appconfigurationv1.SnapshotsList + var offset int64 + var limit int64 = 10 + var isLimit bool + + finalList := []appconfigurationv1.SnapshotResponseGetApi{} + + if _, ok := d.GetOk("limit"); ok { + isLimit = true + limit = int64(d.Get("limit").(int)) + } + options.SetLimit(limit) + if _, ok := d.GetOk("offset"); ok { + offset = int64(d.Get("offset").(int)) + } + + for { + options.Offset = &offset + result, response, err := appconfigClient.ListSnapshots(options) + shapshotsList = result + if err != nil { + return fmt.Errorf("ListSnapshots failed %s\n%s", err, response) + } + if isLimit { + offset = 0 + } else { + offset = dataSourceSnapshotsListGetNext(result.Next) + } + finalList = append(finalList, result.Snapshot...) + if offset == 0 { + break + } + } + + shapshotsList.Snapshot = finalList + + d.SetId(fmt.Sprintf("%s", guid)) + + if shapshotsList.Snapshot != nil { + err = d.Set("git_config", dataSourceFeaturesListFlattenSnapshots(shapshotsList.Snapshot)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting git_config %s", err) + } + } + if shapshotsList.TotalCount != nil { + if err = d.Set("total_count", shapshotsList.TotalCount); err != nil { + return fmt.Errorf("[ERROR] Error setting total_count: %s", err) + } + } + if shapshotsList.Limit != nil { + if err = d.Set("limit", shapshotsList.Limit); err != nil { + return fmt.Errorf("[ERROR] Error setting limit: %s", err) + } + } + if shapshotsList.Offset != nil { + if err = d.Set("offset", shapshotsList.Offset); err != nil { + return fmt.Errorf("[ERROR] Error setting offset: %s", err) + } + } + + return nil +} + +func dataSourceSnapshotsListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} + +func dataSourceFeaturesListFlattenSnapshots(result []appconfigurationv1.SnapshotResponseGetApi) (snapshots []map[string]interface{}) { + for _, snapshotsItem := range result { + snapshots = append(snapshots, dataSourceSnapshotsListSnapshotsToMap(snapshotsItem)) + } + return snapshots +} + +func dataSourceSnapshotsListSnapshotsToMap(snapshotsItem appconfigurationv1.SnapshotResponseGetApi) (snapshotsMap map[string]interface{}) { + snapshotsMap = map[string]interface{}{} + + if snapshotsItem.GitConfigName != nil { + snapshotsMap["git_config_name"] = snapshotsItem.GitConfigName + } + if snapshotsItem.GitConfigID != nil { + snapshotsMap["git_config_id"] = snapshotsItem.GitConfigID + } + if snapshotsItem.GitURL != nil { + snapshotsMap["git_url"] = snapshotsItem.GitURL + } + if snapshotsItem.GitBranch != nil { + snapshotsMap["git_branch"] = snapshotsItem.GitBranch + } + if snapshotsItem.GitFilePath != nil { + snapshotsMap["git_file_path"] = snapshotsItem.GitFilePath + } + if snapshotsItem.CreatedTime != nil { + snapshotsMap["created_time"] = snapshotsItem.CreatedTime.String() + } + if snapshotsItem.UpdatedTime != nil { + snapshotsMap["updated_time"] = snapshotsItem.UpdatedTime.String() + } + if snapshotsItem.LastSyncTime != nil { + snapshotsMap["last_sync_time"] = snapshotsItem.LastSyncTime.String() + } + if snapshotsItem.Href != nil { + snapshotsMap["href"] = snapshotsItem.Href + } + + if snapshotsItem.Collection != nil { + collectionItemMap := resourceIbmAppConfigSnapshotsCollectionRefToMap(snapshotsItem.Collection) + snapshotsMap["collection"] = collectionItemMap + } + if snapshotsItem.Environment != nil { + environmentItemMap := resourceIbmAppConfigSnapshotsEnvironmentRefToMap(snapshotsItem.Environment) + snapshotsMap["environment"] = environmentItemMap + } + return snapshotsMap +} + +func resourceIbmAppConfigSnapshotsCollectionRefToMap(collectionRef interface{}) []CollectionRef { + collections := getSnapshotsCollection(collectionRef) + collectionRefMap := CollectionRef{} + var collectionMap []CollectionRef + collectionRefMap["collection_id"] = collections.Collection_id + collectionRefMap["collection_name"] = collections.Collection_name + collectionMap = append(collectionMap, collectionRefMap) + return collectionMap +} + +func getSnapshotsCollection(data interface{}) Collections { + m := data.(map[string]interface{}) + collection := Collections{} + if name, ok := m["name"].(string); ok { + collection.Collection_name = name + } + if id, ok := m["collection_id"].(string); ok { + collection.Collection_id = id + } + return collection +} + +func resourceIbmAppConfigSnapshotsEnvironmentRefToMap(environmentRef interface{}) []EnvironmentRef { + environments := getSnapshotsEnvironment(environmentRef) + environmentRefMap := EnvironmentRef{} + var environmentMap []EnvironmentRef + environmentRefMap["environment_id"] = environments.Environment_id + environmentRefMap["environment_name"] = environments.Environment_name + environmentRefMap["color_code"] = environments.Color_code + environmentMap = append(environmentMap, environmentRefMap) + return environmentMap +} + +func getSnapshotsEnvironment(data interface{}) Environments { + m := data.(map[string]interface{}) + environment := Environments{} + if name, ok := m["name"].(string); ok { + environment.Environment_name = name + } + if id, ok := m["environment_id"].(string); ok { + environment.Environment_id = id + } + if color, ok := m["color_code"].(string); ok { + environment.Color_code = color + } + return environment +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_collection.go b/ibm/service/appconfiguration/resource_ibm_app_config_collection.go new file mode 100644 index 000000000..5f4e88448 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_collection.go @@ -0,0 +1,292 @@ +package appconfiguration + +import ( + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMAppConfigCollection() *schema.Resource { + return &schema.Resource{ + Read: resourceIbmIbmAppConfigCollectiontRead, + Create: resourceIbmIbmAppConfigCollectiontCreate, + Update: resourceIbmIbmAppConfigCollectionUpdate, + Delete: resourceIbmIbmAppConfigCollectionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Collection name.", + }, + "collection_id": { + Type: schema.TypeString, + Required: true, + Description: "Collection Id.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Collection description", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Tags associated with the collection", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the collection.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the collection data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Collection URL.", + }, + "features_count": { + Type: schema.TypeString, + Computed: true, + Description: "Number of features associated with the collection.", + }, + "properties_count": { + Type: schema.TypeString, + Computed: true, + Description: "Number of properties associated with the collection.", + }, + }, + } +} + +func resourceIbmIbmAppConfigCollectiontCreate(d *schema.ResourceData, meta interface{}) error { + + guid := d.Get("guid").(string) + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + options := &appconfigurationv1.CreateCollectionOptions{} + options.SetName(d.Get("name").(string)) + options.SetCollectionID(d.Get("collection_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + + collection, response, err := appconfigClient.CreateCollection(options) + + if err != nil { + return fmt.Errorf("CreateCollection failed %s\n%s", err, response) + } + d.SetId(fmt.Sprintf("%s/%s", guid, *collection.CollectionID)) + + return resourceIbmIbmAppConfigCollectiontRead(d, meta) +} + +func resourceIbmIbmAppConfigCollectiontRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + if len(parts) != 2 { + return fmt.Errorf("Kindly check the id") + } + + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.GetCollectionOptions{} + options.SetCollectionID(parts[1]) + + result, response, err := appconfigClient.GetCollection(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + } + return fmt.Errorf("[DEBUG] GetCollection failed %s\n%s", err, response) + } + + d.Set("guid", parts[0]) + + if result.Name != nil { + if err = d.Set("name", result.Name); err != nil { + return fmt.Errorf("[ERROR] Error setting name: %s", err) + } + } + if result.CollectionID != nil { + if err = d.Set("collection_id", result.CollectionID); err != nil { + return fmt.Errorf("[ERROR] Error setting collection_id: %s", err) + } + } + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return fmt.Errorf("[ERROR] Error setting description: %s", err) + } + } + if result.Tags != nil { + if err = d.Set("tags", result.Tags); err != nil { + return fmt.Errorf("[ERROR] Error setting tags: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting createdTime: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updatedTime: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + if result.FeaturesCount != nil { + if err = d.Set("features_count", result.FeaturesCount); err != nil { + return fmt.Errorf("[ERROR] Error setting features_count: %s", err) + } + } + if result.FeaturesCount != nil { + if err = d.Set("features_count", result.FeaturesCount); err != nil { + return fmt.Errorf("[ERROR] Error setting features_count: %s", err) + } + } + if result.PropertiesCount != nil { + if err = d.Set("properties_count", result.PropertiesCount); err != nil { + return fmt.Errorf("[ERROR] Error setting properties_count: %s", err) + } + } + if result.Features != nil { + err = d.Set("features", resourceIbmAppConfigCollectionFeatureToMap(result.Features)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting features %s", err) + } + } + if result.Properties != nil { + err = d.Set("properties", resourceIbmAppConfigCollectionPropertiesToMap(result.Properties)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting properties %s", err) + } + } + + return nil +} + +func resourceIbmAppConfigCollectionFeatureToMap(result []appconfigurationv1.FeatureOutput) (features []map[string]interface{}) { + for _, featuresItem := range result { + features = append(features, resourceCollectionFeaturesToMap(featuresItem)) + } + return features +} + +func resourceIbmAppConfigCollectionPropertiesToMap(result []appconfigurationv1.PropertyOutput) (properties []map[string]interface{}) { + for _, propertiesItem := range result { + properties = append(properties, resourceCollectionPropertiesToMap(propertiesItem)) + } + return properties +} + +func resourceCollectionFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + return featuresMap +} + +func resourceCollectionPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + return propertiesMap +} + +func resourceIbmIbmAppConfigCollectionUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + options := &appconfigurationv1.UpdateCollectionOptions{} + + options.SetCollectionID(parts[1]) + + if ok := d.HasChanges("name", "description", "tags"); ok { + + if _, ok := d.GetOk("name"); ok { + options.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + + _, response, err := appconfigClient.UpdateCollection(options) + if err != nil { + return fmt.Errorf("UpdateCollection failed %s\n%s", err, response) + } + return resourceIbmIbmAppConfigCollectiontRead(d, meta) + } + return nil +} + +func resourceIbmIbmAppConfigCollectionDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.DeleteCollectionOptions{} + options.SetCollectionID(parts[1]) + + response, err := appconfigClient.DeleteCollection(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[DEBUG] DeleteCollection failed %s\n%s", err, response) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_collection_test.go b/ibm/service/appconfiguration/resource_ibm_app_config_collection_test.go new file mode 100644 index 000000000..bdc125f83 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_collection_test.go @@ -0,0 +1,133 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" +) + +func TestAccIbmIbmAppConfigCollectionBasic(t *testing.T) { + var conf appconfigurationv1.Collection + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + collectionId := fmt.Sprintf("tf_collection_id_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + tags := fmt.Sprintf("tags_%d", acctest.RandIntRange(10, 100)) + tagsUpdated := fmt.Sprintf("tags_updated_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmAppConfigCollectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigCollectionConfigBasic(instanceName, name, collectionId, description, tags), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmAppConfigCollectionExists("ibm_app_config_collection.ibm_app_config_collection_resource1", conf), + resource.TestCheckResourceAttrSet("ibm_app_config_collection.ibm_app_config_collection_resource1", "id"), + resource.TestCheckResourceAttrSet("ibm_app_config_collection.ibm_app_config_collection_resource1", "name"), + resource.TestCheckResourceAttrSet("ibm_app_config_collection.ibm_app_config_collection_resource1", "tags"), + resource.TestCheckResourceAttrSet("ibm_app_config_collection.ibm_app_config_collection_resource1", "collection_id"), + resource.TestCheckResourceAttrSet("ibm_app_config_collection.ibm_app_config_collection_resource1", "description"), + ), + }, + { + Config: testAccCheckIbmAppConfigCollectionConfigBasic(instanceName, nameUpdate, collectionId, descriptionUpdate, tagsUpdated), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_app_config_collection.ibm_app_config_collection_resource1", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_app_config_collection.ibm_app_config_collection_resource1", "tags", tagsUpdated), + resource.TestCheckResourceAttr("ibm_app_config_collection.ibm_app_config_collection_resource1", "description", descriptionUpdate), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigCollectionConfigBasic(name, envName, collectionID, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test456" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_collection" "ibm_app_config_collection_resource1" { + guid = ibm_resource_instance.app_config_terraform_test456.guid + name = "%s" + collection_id = "%s" + description = "%s" + tags = "%s" + }`, name, envName, collectionID, description, tags) +} + +func testAccCheckIbmAppConfigCollectionExists(n string, obj appconfigurationv1.Collection) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + + options := &appconfigurationv1.GetCollectionOptions{} + + options.SetCollectionID(parts[1]) + + result, _, err := appconfigClient.GetCollection(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIbmAppConfigCollectionDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_app_config_collection_resource1" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + options := &appconfigurationv1.GetCollectionOptions{} + + options.SetCollectionID(parts[1]) + + // Try to find the key + _, response, err := appconfigClient.GetCollection(options) + + if err == nil { + return fmt.Errorf("Collection still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for Collection (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/resource_ibm_app_config_environment.go b/ibm/service/appconfiguration/resource_ibm_app_config_environment.go similarity index 85% rename from ibm/resource_ibm_app_config_environment.go rename to ibm/service/appconfiguration/resource_ibm_app_config_environment.go index d947eb18c..5ca709a6e 100644 --- a/ibm/resource_ibm_app_config_environment.go +++ b/ibm/service/appconfiguration/resource_ibm_app_config_environment.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIbmAppConfigEnvironment() *schema.Resource { +func ResourceIBMAppConfigEnvironment() *schema.Resource { return &schema.Resource{ Read: resourceEnvironmentRead, Create: resourceEnvironmentCreate, @@ -70,16 +72,16 @@ func resourceIbmAppConfigEnvironment() *schema.Resource { } func getAppConfigClient(meta interface{}, guid string) (*appconfigurationv1.AppConfigurationV1, error) { - appconfigClient, err := meta.(ClientSession).AppConfigurationV1() + appconfigClient, err := meta.(conns.ClientSession).AppConfigurationV1() if err != nil { return nil, err } - bluemixSession, err := meta.(ClientSession).BluemixSession() + bluemixSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return nil, err } appConfigURL := fmt.Sprintf("https://%s.apprapp.cloud.ibm.com/apprapp/feature/v1/instances/%s", bluemixSession.Config.Region, guid) - url := envFallBack([]string{"IBMCLOUD_APP_CONFIG_API_ENDPOINT"}, appConfigURL) + url := conns.EnvFallBack([]string{"IBMCLOUD_APP_CONFIG_API_ENDPOINT"}, appConfigURL) appconfigClient.Service.Options.URL = url return appconfigClient, nil } @@ -115,7 +117,7 @@ func resourceEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { func resourceEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { if ok := d.HasChanges("name", "tags", "color_code", "description"); ok { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } @@ -148,7 +150,7 @@ func resourceEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceEnvironmentRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } @@ -170,49 +172,49 @@ func resourceEnvironmentRead(d *schema.ResourceData, meta interface{}) error { d.Set("guid", parts[0]) if result.Name != nil { if err = d.Set("name", result.Name); err != nil { - return fmt.Errorf("error setting name: %s", err) + return fmt.Errorf("[ERROR] Error setting name: %s", err) } } if result.EnvironmentID != nil { if err = d.Set("environment_id", result.EnvironmentID); err != nil { - return fmt.Errorf("error setting environment_id: %s", err) + return fmt.Errorf("[ERROR] Error setting environment_id: %s", err) } } if result.Description != nil { if err = d.Set("description", result.Description); err != nil { - return fmt.Errorf("error setting description: %s", err) + return fmt.Errorf("[ERROR] Error setting description: %s", err) } } if result.Tags != nil { if err = d.Set("tags", result.Tags); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("[ERROR] Error setting tags: %s", err) } } if result.ColorCode != nil { if err = d.Set("color_code", result.ColorCode); err != nil { - return fmt.Errorf("error setting color_code: %s", err) + return fmt.Errorf("[ERROR] Error setting color_code: %s", err) } } if result.CreatedTime != nil { if err = d.Set("created_time", result.CreatedTime.String()); err != nil { - return fmt.Errorf("error setting created_time: %s", err) + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) } } if result.UpdatedTime != nil { if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { - return fmt.Errorf("error setting updated_time: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) } } if result.Href != nil { if err = d.Set("href", result.Href); err != nil { - return fmt.Errorf("error setting href: %s", err) + return fmt.Errorf("[ERROR] Error setting href: %s", err) } } return nil } func resourceEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } diff --git a/ibm/resource_ibm_app_config_environment_test.go b/ibm/service/appconfiguration/resource_ibm_app_config_environment_test.go similarity index 79% rename from ibm/resource_ibm_app_config_environment_test.go rename to ibm/service/appconfiguration/resource_ibm_app_config_environment_test.go index f2f17075b..b06eb51c5 100644 --- a/ibm/resource_ibm_app_config_environment_test.go +++ b/ibm/service/appconfiguration/resource_ibm_app_config_environment_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -26,8 +30,8 @@ func TestAccIbmAppConfigEnvironmentBasic(t *testing.T) { environmentID := fmt.Sprintf("environment_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ { @@ -74,6 +78,20 @@ func testAccCheckIbmAppConfigEnvironmentConfigBasic(name, envName, environmentID guid = ibm_resource_instance.app_config_terraform_test454.guid }`, name, envName, environmentID, description, colorCode) } +func getAppConfigClient(meta interface{}, guid string) (*appconfigurationv1.AppConfigurationV1, error) { + appconfigClient, err := meta.(conns.ClientSession).AppConfigurationV1() + if err != nil { + return nil, err + } + bluemixSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return nil, err + } + appConfigURL := fmt.Sprintf("https://%s.apprapp.cloud.ibm.com/apprapp/feature/v1/instances/%s", bluemixSession.Config.Region, guid) + url := conns.EnvFallBack([]string{"IBMCLOUD_APP_CONFIG_API_ENDPOINT"}, appConfigURL) + appconfigClient.Service.Options.URL = url + return appconfigClient, nil +} func testAccCheckIbmAppConfigEnvironmentExists(n string, obj appconfigurationv1.Environment) resource.TestCheckFunc { @@ -83,12 +101,12 @@ func testAccCheckIbmAppConfigEnvironmentExists(n string, obj appconfigurationv1. return fmt.Errorf("Not found: %s", n) } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } - appconfigClient, err := getAppConfigClient(testAccProvider.Meta(), parts[0]) + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) if err != nil { return err } @@ -112,12 +130,12 @@ func testAccCheckIbmAppConfigEnvironmentDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } - appconfigClient, err := getAppConfigClient(testAccProvider.Meta(), parts[0]) + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) if err != nil { return err } @@ -130,7 +148,7 @@ func testAccCheckIbmAppConfigEnvironmentDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Environment still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for environment (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for environment (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_app_config_feature.go b/ibm/service/appconfiguration/resource_ibm_app_config_feature.go similarity index 83% rename from ibm/resource_ibm_app_config_feature.go rename to ibm/service/appconfiguration/resource_ibm_app_config_feature.go index e504af9eb..44ce667c1 100644 --- a/ibm/resource_ibm_app_config_feature.go +++ b/ibm/service/appconfiguration/resource_ibm_app_config_feature.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration import ( "fmt" "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" "github.com/IBM/go-sdk-core/v5/core" ) -func resourceIbmIbmAppConfigFeature() *schema.Resource { +func ResourceIBMIbmAppConfigFeature() *schema.Resource { return &schema.Resource{ Create: resourceIbmIbmAppConfigFeatureCreate, Read: resourceIbmIbmAppConfigFeatureRead, @@ -46,7 +48,7 @@ func resourceIbmIbmAppConfigFeature() *schema.Resource { "type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_app_config_feature", "type"), + ValidateFunc: validate.InvokeValidator("ibm_app_config_feature", "type"), Description: "Type of the feature (BOOLEAN, STRING, NUMERIC).", }, "enabled_value": { @@ -69,6 +71,11 @@ func resourceIbmIbmAppConfigFeature() *schema.Resource { Optional: true, Description: "Tags associated with the feature.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Optional: true, + Description: "Rollout percentage of the feature.", + }, "segment_rules": { Type: schema.TypeList, Optional: true, @@ -100,6 +107,11 @@ func resourceIbmIbmAppConfigFeature() *schema.Resource { Required: true, Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", }, + "rollout_percentage": { + Type: schema.TypeInt, + Optional: true, + Description: "Rollout percentage for the segment rule.", + }, }, }, }, @@ -159,7 +171,9 @@ func resourceIbmIbmAppConfigFeatureCreate(d *schema.ResourceData, meta interface options.SetEnabledValue(d.Get("enabled_value").(string)) options.SetEnvironmentID(d.Get("environment_id").(string)) options.SetDisabledValue(d.Get("disabled_value").(string)) - + if _, ok := d.GetOk("rollout_percentage"); ok { + options.SetRolloutPercentage(int64(d.Get("rollout_percentage").(int))) + } if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } @@ -168,7 +182,7 @@ func resourceIbmIbmAppConfigFeatureCreate(d *schema.ResourceData, meta interface } if _, ok := d.GetOk("segment_rules"); ok { - var segmentRules []appconfigurationv1.SegmentRule + var segmentRules []appconfigurationv1.FeatureSegmentRule for _, e := range d.Get("segment_rules").([]interface{}) { value := e.(map[string]interface{}) segmentRulesItem, err := resourceIbmAppConfigFeatureMapToSegmentRule(d, value) @@ -200,7 +214,7 @@ func resourceIbmIbmAppConfigFeatureCreate(d *schema.ResourceData, meta interface } func resourceIbmIbmAppConfigFeatureUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } @@ -213,7 +227,7 @@ func resourceIbmIbmAppConfigFeatureUpdate(d *schema.ResourceData, meta interface options.SetEnvironmentID(parts[1]) options.SetFeatureID(parts[2]) - if ok := d.HasChanges("name", "enabled_value", "disabled_value", "description", "tags", "segment_rules", "collections"); ok { + if ok := d.HasChanges("name", "enabled_value", "disabled_value", "description", "rollout_percentage", "tags", "segment_rules", "collections"); ok { options.SetName(d.Get("name").(string)) options.SetEnabledValue(d.Get("enabled_value").(string)) options.SetDisabledValue(d.Get("disabled_value").(string)) @@ -221,11 +235,14 @@ func resourceIbmIbmAppConfigFeatureUpdate(d *schema.ResourceData, meta interface if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("rollout_percentage"); ok { + options.SetRolloutPercentage(int64(d.Get("rollout_percentage").(int))) + } if _, ok := d.GetOk("tags"); ok { options.SetTags(d.Get("tags").(string)) } if _, ok := d.GetOk("segment_rules"); ok { - var segmentRules []appconfigurationv1.SegmentRule + var segmentRules []appconfigurationv1.FeatureSegmentRule for _, e := range d.Get("segment_rules").([]interface{}) { value := e.(map[string]interface{}) segmentRulesItem, err := resourceIbmAppConfigFeatureMapToSegmentRule(d, value) @@ -257,7 +274,7 @@ func resourceIbmIbmAppConfigFeatureUpdate(d *schema.ResourceData, meta interface } func resourceIbmIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } @@ -279,28 +296,33 @@ func resourceIbmIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{} d.Set("environment_id", parts[1]) if result.Name != nil { if err = d.Set("name", result.Name); err != nil { - return fmt.Errorf("error setting name: %s", err) + return fmt.Errorf("[ERROR] Error setting name: %s", err) } } if result.FeatureID != nil { if err = d.Set("feature_id", result.FeatureID); err != nil { - return fmt.Errorf("error setting feature_id: %s", err) + return fmt.Errorf("[ERROR] Error setting feature_id: %s", err) } } if result.Type != nil { if err = d.Set("type", result.Type); err != nil { - return fmt.Errorf("error setting type: %s", err) + return fmt.Errorf("[ERROR] Error setting type: %s", err) } } if result.Description != nil { if err = d.Set("description", result.Description); err != nil { - return fmt.Errorf("error setting description: %s", err) + return fmt.Errorf("[ERROR] Error setting description: %s", err) } + } + if result.RolloutPercentage != nil { + if err = d.Set("rollout_percentage", result.RolloutPercentage); err != nil { + return fmt.Errorf("[ERROR] Error setting rollout_percentage: %s", err) + } } if result.Tags != nil { if err = d.Set("tags", result.Tags); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("[ERROR] Error setting tags: %s", err) } } @@ -311,7 +333,7 @@ func resourceIbmIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{} segmentRules = append(segmentRules, segmentRulesItemMap) } if err = d.Set("segment_rules", segmentRules); err != nil { - return fmt.Errorf("error setting segment_rules: %s", err) + return fmt.Errorf("[ERROR] Error setting segment_rules: %s", err) } } if result.Collections != nil { @@ -321,32 +343,32 @@ func resourceIbmIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{} collections = append(collections, collectionsItemMap) } if err = d.Set("collections", collections); err != nil { - return fmt.Errorf("error setting collections: %s", err) + return fmt.Errorf("[ERROR] Error setting collections: %s", err) } } if result.SegmentExists != nil { if err = d.Set("segment_exists", result.SegmentExists); err != nil { - return fmt.Errorf("error setting segment_exists: %s", err) + return fmt.Errorf("[ERROR] Error setting segment_exists: %s", err) } } if result.CreatedTime != nil { if err = d.Set("created_time", result.CreatedTime.String()); err != nil { - return fmt.Errorf("error setting created_time: %s", err) + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) } } if result.UpdatedTime != nil { if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { - return fmt.Errorf("error setting updated_time: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) } } if result.Href != nil { if err = d.Set("href", result.Href); err != nil { - return fmt.Errorf("error setting href: %s", err) + return fmt.Errorf("[ERROR] Error setting href: %s", err) } } if result.Enabled != nil { if err = d.Set("enabled", result.Enabled); err != nil { - return fmt.Errorf("error setting enabled: %s", err) + return fmt.Errorf("[ERROR] Error setting enabled: %s", err) } } @@ -379,7 +401,7 @@ func resourceIbmIbmAppConfigFeatureRead(d *schema.ResourceData, meta interface{} } func resourceIbmIbmAppConfigFeatureDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil } @@ -406,24 +428,27 @@ func resourceIbmIbmAppConfigFeatureDelete(d *schema.ResourceData, meta interface return nil } -func resourceIbmAppConfigFeatureValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMAppConfigFeatureValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "BOOLEAN, NUMERIC, STRING", }, ) - resourceValidator := ResourceValidator{ResourceName: "ibm_app_config_feature", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ + ResourceName: "ibm_app_config_feature", + Schema: validateSchema, + } return &resourceValidator } // output -func resourceIbmAppConfigFeatureSegmentRuleToMap(segmentRule appconfigurationv1.SegmentRule) map[string]interface{} { +func resourceIbmAppConfigFeatureSegmentRuleToMap(segmentRule appconfigurationv1.FeatureSegmentRule) map[string]interface{} { segmentRuleMap := map[string]interface{}{} rules := []map[string]interface{}{} @@ -433,8 +458,8 @@ func resourceIbmAppConfigFeatureSegmentRuleToMap(segmentRule appconfigurationv1. } segmentRuleMap["rules"] = rules - segmentRuleMap["order"] = intValue(segmentRule.Order) - + segmentRuleMap["order"] = flex.IntValue(segmentRule.Order) + segmentRuleMap["rollout_percentage"] = flex.IntValue(segmentRule.RolloutPercentage) segmentValue := segmentRule.Value switch segmentValue.(interface{}).(type) { case string: @@ -462,8 +487,8 @@ func resourceIbmAppConfigFeatureCollectionRefToMap(collectionRef appconfiguratio } // input -func resourceIbmAppConfigFeatureMapToSegmentRule(d *schema.ResourceData, segmentRuleMap map[string]interface{}) (appconfigurationv1.SegmentRule, error) { - segmentRule := appconfigurationv1.SegmentRule{} +func resourceIbmAppConfigFeatureMapToSegmentRule(d *schema.ResourceData, segmentRuleMap map[string]interface{}) (appconfigurationv1.FeatureSegmentRule, error) { + segmentRule := appconfigurationv1.FeatureSegmentRule{} rules := []appconfigurationv1.TargetSegments{} for _, rulesItem := range segmentRuleMap["rules"].([]interface{}) { @@ -473,7 +498,7 @@ func resourceIbmAppConfigFeatureMapToSegmentRule(d *schema.ResourceData, segment segmentRule.Rules = rules segmentRule.Order = core.Int64Ptr(int64(segmentRuleMap["order"].(int))) - + segmentRule.RolloutPercentage = core.Int64Ptr(int64(segmentRuleMap["rollout_percentage"].(int))) ruleValue := segmentRuleMap["value"].(string) switch d.Get("type").(string) { case "STRING": diff --git a/ibm/resource_ibm_app_config_feature_test.go b/ibm/service/appconfiguration/resource_ibm_app_config_feature_test.go similarity index 80% rename from ibm/resource_ibm_app_config_feature_test.go rename to ibm/service/appconfiguration/resource_ibm_app_config_feature_test.go index 49012702a..9b8eadd90 100644 --- a/ibm/resource_ibm_app_config_feature_test.go +++ b/ibm/service/appconfiguration/resource_ibm_app_config_feature_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appconfiguration_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -27,8 +30,8 @@ func TestAccIbmIbmAppConfigFeatureBasic(t *testing.T) { tagsUpdated := fmt.Sprintf("tags_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmAppConfigFeatureDestroy, Steps: []resource.TestStep{ { @@ -43,6 +46,7 @@ func TestAccIbmIbmAppConfigFeatureBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_app_config_feature.ibm_app_config_feature_resource1", "description"), resource.TestCheckResourceAttrSet("ibm_app_config_feature.ibm_app_config_feature_resource1", "enabled_value"), resource.TestCheckResourceAttrSet("ibm_app_config_feature.ibm_app_config_feature_resource1", "disabled_value"), + resource.TestCheckResourceAttrSet("ibm_app_config_feature.ibm_app_config_feature_resource1", "rollout_percentage"), ), }, { @@ -63,18 +67,19 @@ func testAccCheckIbmAppConfigFeatureConfigBasic(name, envName, featureID, featur name = "%s" location = "us-south" service = "apprapp" - plan = "standard" + plan = "lite" } resource "ibm_app_config_feature" "ibm_app_config_feature_resource1" { - guid = ibm_resource_instance.app_config_terraform_test456.guid - name = "%s" - environment_id = "dev" - feature_id = "%s" - type = "%s" - enabled_value = true - disabled_value = false - description = "%s" - tags = "%s" + guid = ibm_resource_instance.app_config_terraform_test456.guid + name = "%s" + environment_id = "dev" + feature_id = "%s" + type = "%s" + enabled_value = true + disabled_value = false + description = "%s" + tags = "%s" + rollout_percentage = "80" }`, name, envName, featureID, featureType, description, tags) } @@ -85,11 +90,11 @@ func testAccCheckIbmAppConfigFeatureExists(n string, obj appconfigurationv1.Feat if !ok { return fmt.Errorf("Not found: %s", n) } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } - appconfigClient, err := getAppConfigClient(testAccProvider.Meta(), parts[0]) + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) if err != nil { return err } @@ -110,15 +115,16 @@ func testAccCheckIbmAppConfigFeatureExists(n string, obj appconfigurationv1.Feat } func testAccCheckIbmAppConfigFeatureDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_app_config_feature_resource1" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } - appconfigClient, err := getAppConfigClient(testAccProvider.Meta(), parts[0]) + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) if err != nil { return err } @@ -133,7 +139,7 @@ func testAccCheckIbmAppConfigFeatureDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Feature still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("error checking for Feature (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for Feature (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_property.go b/ibm/service/appconfiguration/resource_ibm_app_config_property.go new file mode 100644 index 000000000..b4487d248 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_property.go @@ -0,0 +1,487 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration + +import ( + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "log" + "strconv" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIbmAppConfigProperty() *schema.Resource { + return &schema.Resource{ + Create: resourceIbmIbmAppConfigPropertyCreate, + Read: resourceIbmIbmAppConfigPropertyRead, + Update: resourceIbmIbmAppConfigPropertyUpdate, + Delete: resourceIbmIbmAppConfigPropertyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "environment_id": { + Type: schema.TypeString, + Required: true, + Description: "Environment Id.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Property name.", + }, + "property_id": { + Type: schema.TypeString, + Required: true, + Description: "Property id.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "Type of the Property (BOOLEAN, STRING, NUMERIC).", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Property description.", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Tags associated with the property.", + }, + "format": { + Type: schema.TypeString, + Optional: true, + Description: "Format of the feature (TEXT, JSON, YAML).", + }, + "segment_rules": { + Type: schema.TypeList, + Optional: true, + Description: "Specify the targeting rules that is used to set different property values for different segments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rules": { + Type: schema.TypeList, + Required: true, + Description: "Rules array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "segments": { + Type: schema.TypeList, + Required: true, + Description: "List of segment ids that are used for targeting using the rule.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + }, + "order": { + Type: schema.TypeInt, + Required: true, + Description: "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + }, + }, + }, + }, + "collections": { + Type: schema.TypeList, + Optional: true, + Description: "List of collection id representing the collections that are associated with the specified property.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_id": { + Type: schema.TypeString, + Required: true, + Description: "Collection id.", + }, + }, + }, + }, + "segment_exists": { + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if the targeting rules are specified for the property.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the property.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the property data.", + }, + "evaluation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The last occurrence of the property value evaluation.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Property URL.", + }, + }, + } +} + +func resourceIbmIbmAppConfigPropertyCreate(d *schema.ResourceData, meta interface{}) error { + guid := d.Get("guid").(string) + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.CreatePropertyOptions{} + + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + options.SetEnvironmentID(d.Get("environment_id").(string)) + options.SetPropertyID(d.Get("property_id").(string)) + options.SetValue(d.Get("value").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + if _, ok := d.GetOk("format"); ok { + options.SetFormat(d.Get("format").(string)) + } + if _, ok := d.GetOk("collections"); ok { + var collections []appconfigurationv1.CollectionRef + for _, e := range d.Get("collections").([]interface{}) { + value := e.(map[string]interface{}) + collectionsItem := resourceIbmAppConfigPropertyMapToCollectionRef(value) + collections = append(collections, collectionsItem) + } + options.SetCollections(collections) + } + if _, ok := d.GetOk("segment_rules"); ok { + var segmentRules []appconfigurationv1.SegmentRule + for _, e := range d.Get("segment_rules").([]interface{}) { + value := e.(map[string]interface{}) + segmentRulesItem, err := resourceIbmAppConfigPropertyMapToSegmentRule(d, value) + if err != nil { + return err + } + segmentRules = append(segmentRules, segmentRulesItem) + } + options.SetSegmentRules(segmentRules) + } + + result, response, err := appconfigClient.CreateProperty(options) + if err != nil { + return fmt.Errorf("CreateProperty failed %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", guid, *options.EnvironmentID, *result.PropertyID)) + + return resourceIbmIbmAppConfigPropertyRead(d, meta) +} + +func resourceIbmIbmAppConfigPropertyRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + if len(parts) != 3 { + return fmt.Errorf("Kindly check the id") + } + + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.GetPropertyOptions{} + + options.SetEnvironmentID(parts[1]) + options.SetPropertyID(parts[2]) + + result, response, err := appconfigClient.GetProperty(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + } + return fmt.Errorf("[DEBUG] GetProperty failed %s\n%s", err, response) + } + + d.Set("guid", parts[0]) + d.Set("environment_id", parts[1]) + + if result.Name != nil { + if err = d.Set("name", result.Name); err != nil { + return fmt.Errorf("error setting name: %s", err) + } + } + if result.PropertyID != nil { + if err = d.Set("property_id", result.PropertyID); err != nil { + return fmt.Errorf("error setting property_id: %s", err) + } + } + if result.Type != nil { + if err = d.Set("type", result.Type); err != nil { + return fmt.Errorf("error setting type: %s", err) + } + } + if result.Value != nil { + value := result.Value + switch value.(interface{}).(type) { + case string: + d.Set("value", value.(string)) + case float64: + d.Set("value", fmt.Sprintf("%v", value)) + case bool: + d.Set("value", strconv.FormatBool(value.(bool))) + } + } + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return fmt.Errorf("error setting description: %s", err) + } + } + if result.Tags != nil { + if err = d.Set("tags", result.Tags); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + } + if result.SegmentExists != nil { + if err = d.Set("segment_exists", result.SegmentExists); err != nil { + return fmt.Errorf("error setting segment_exists: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("error setting created_time: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("error setting updated_time: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("error setting href: %s", err) + } + } + + if result.SegmentRules != nil { + segmentRules := []map[string]interface{}{} + for _, segmentRulesItem := range result.SegmentRules { + segmentRulesItemMap := resourceIbmAppConfigPropertySegmentRuleToMap(segmentRulesItem) + segmentRules = append(segmentRules, segmentRulesItemMap) + } + if err = d.Set("segment_rules", segmentRules); err != nil { + return fmt.Errorf("[ERROR] Error setting segment_rules: %s", err) + } + } + if result.Collections != nil { + collections := []map[string]interface{}{} + for _, collectionsItem := range result.Collections { + collectionsItemMap := resourceIbmAppConfigPropertyCollectionRefToMap(collectionsItem) + collections = append(collections, collectionsItemMap) + } + if err = d.Set("collections", collections); err != nil { + return fmt.Errorf("[ERROR] Error setting collections: %s", err) + } + } + return nil +} + +func resourceIbmIbmAppConfigPropertyUpdate(d *schema.ResourceData, meta interface{}) error { + if ok := d.HasChanges("name", "value", "description", "tags", "segment_rules", "collections"); ok { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + options := &appconfigurationv1.UpdatePropertyOptions{} + + options.SetEnvironmentID(parts[1]) + options.SetPropertyID(parts[2]) + + options.SetName(d.Get("name").(string)) + options.SetValue(d.Get("value").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + if _, ok := d.GetOk("collections"); ok { + var collections []appconfigurationv1.CollectionRef + for _, e := range d.Get("collections").([]interface{}) { + value := e.(map[string]interface{}) + collectionsItem := resourceIbmAppConfigPropertyMapToCollectionRef(value) + collections = append(collections, collectionsItem) + } + options.SetCollections(collections) + } + if _, ok := d.GetOk("segment_rules"); ok { + var segmentRules []appconfigurationv1.SegmentRule + for _, e := range d.Get("segment_rules").([]interface{}) { + value := e.(map[string]interface{}) + segmentRulesItem, err := resourceIbmAppConfigPropertyMapToSegmentRule(d, value) + if err != nil { + return err + } + segmentRules = append(segmentRules, segmentRulesItem) + } + options.SetSegmentRules(segmentRules) + } + _, response, err := appconfigClient.UpdateProperty(options) + if err != nil { + return fmt.Errorf("UpdateProperty failed %s\n%s", err, response) + } + + return resourceIbmIbmAppConfigPropertyRead(d, meta) + } + return nil +} + +func resourceIbmIbmAppConfigPropertyDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return fmt.Errorf("getAppConfigClient failed %s", err) + } + + options := &appconfigurationv1.DeletePropertyOptions{} + + options.SetEnvironmentID(parts[1]) + options.SetPropertyID(parts[2]) + + response, err := appconfigClient.DeleteProperty(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] DeleteProperty failed %s\n%s", err, response) + return err + } + + d.SetId("") + + return nil +} + +func resourceIbmAppConfigPropertyMapToCollectionRef(collectionRefMap map[string]interface{}) appconfigurationv1.CollectionRef { + collectionRef := appconfigurationv1.CollectionRef{} + collectionRef.CollectionID = core.StringPtr(collectionRefMap["collection_id"].(string)) + return collectionRef +} + +func resourceIbmAppConfigPropertyMapToSegmentRule(d *schema.ResourceData, segmentRuleMap map[string]interface{}) (appconfigurationv1.SegmentRule, error) { + segmentRule := appconfigurationv1.SegmentRule{} + + rules := []appconfigurationv1.TargetSegments{} + for _, rulesItem := range segmentRuleMap["rules"].([]interface{}) { + rulesItemModel := resourceIbmAppConfigPropertyMapToRule(rulesItem.(map[string]interface{})) + rules = append(rules, rulesItemModel) + } + segmentRule.Rules = rules + + segmentRule.Order = core.Int64Ptr(int64(segmentRuleMap["order"].(int))) + ruleValue := segmentRuleMap["value"].(string) + switch d.Get("type").(string) { + case "STRING": + segmentRule.Value = ruleValue + case "NUMERIC": + v, err := strconv.ParseFloat(ruleValue, 64) + if err != nil { + return segmentRule, fmt.Errorf("'value' parameter in 'segment_rules' has wrong value: %s", err) + } + segmentRule.Value = v + case "BOOLEAN": + if ruleValue == "false" { + segmentRule.Value = false + } else if ruleValue == "true" { + segmentRule.Value = true + } else { + return segmentRule, fmt.Errorf("'value' parameter in 'segment_rules' has wrong value") + } + } + + return segmentRule, nil +} + +func resourceIbmAppConfigPropertyMapToRule(ruleMap map[string]interface{}) appconfigurationv1.TargetSegments { + rule := appconfigurationv1.TargetSegments{} + + segments := []string{} + for _, segmentsItem := range ruleMap["segments"].([]interface{}) { + segments = append(segments, segmentsItem.(string)) + } + rule.Segments = segments + + return rule +} + +// output +func resourceIbmAppConfigPropertySegmentRuleToMap(segmentRule appconfigurationv1.SegmentRule) map[string]interface{} { + segmentRuleMap := map[string]interface{}{} + + rules := []map[string]interface{}{} + for _, rulesItem := range segmentRule.Rules { + rulesItemMap := resourceIbmAppConfigPropertyRuleToMap(rulesItem) + rules = append(rules, rulesItemMap) + } + + segmentRuleMap["rules"] = rules + segmentRuleMap["order"] = flex.IntValue(segmentRule.Order) + segmentValue := segmentRule.Value + switch segmentValue.(interface{}).(type) { + case string: + segmentRuleMap["value"] = segmentValue.(string) + case float64: + segmentRuleMap["value"] = fmt.Sprintf("%v", segmentValue) + case bool: + segmentRuleMap["value"] = strconv.FormatBool(segmentValue.(bool)) + } + + return segmentRuleMap +} + +func resourceIbmAppConfigPropertyRuleToMap(rule appconfigurationv1.TargetSegments) map[string]interface{} { + ruleMap := map[string]interface{}{} + ruleMap["segments"] = rule.Segments + return ruleMap +} + +func resourceIbmAppConfigPropertyCollectionRefToMap(collectionRef appconfigurationv1.CollectionRef) map[string]interface{} { + collectionRefMap := map[string]interface{}{} + collectionRefMap["collection_id"] = collectionRef.CollectionID + collectionRefMap["name"] = collectionRef.Name + return collectionRefMap +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_property_test.go b/ibm/service/appconfiguration/resource_ibm_app_config_property_test.go new file mode 100644 index 000000000..417be1bd9 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_property_test.go @@ -0,0 +1,145 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" +) + +func TestAccIbmIbmAppConfigPropertyBasic(t *testing.T) { + var conf appconfigurationv1.Property + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + propertyID := fmt.Sprintf("tf_property_id_%d", acctest.RandIntRange(10, 100)) + typeVar := "BOOLEAN" + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tags := fmt.Sprintf("tf_tags_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + tagsUpdate := fmt.Sprintf("tf_tags_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmAppConfigPropertyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigPropertyConfigBasic(instanceName, name, propertyID, typeVar, description, tags), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmAppConfigPropertyExists("ibm_app_config_property.ibm_app_config_property_resource1", conf), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "environment_id"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "name"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "property_id"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "type"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "description"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "tags"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "created_time"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "updated_time"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "href"), + resource.TestCheckResourceAttrSet("ibm_app_config_property.ibm_app_config_property_resource1", "segment_exists"), + ), + }, + { + Config: testAccCheckIbmAppConfigPropertyConfigBasic(instanceName, nameUpdate, propertyID, typeVar, descriptionUpdate, tagsUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_app_config_property.ibm_app_config_property_resource1", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_app_config_property.ibm_app_config_property_resource1", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_app_config_property.ibm_app_config_property_resource1", "tags", tagsUpdate), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigPropertyConfigBasic(instanceName, name, propertyID, typeVar, description, tags string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test476" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_property" "ibm_app_config_property_resource1" { + guid = ibm_resource_instance.app_config_terraform_test476.guid + environment_id = "dev" + name = "%s" + property_id = "%s" + type = "%s" + value = "false" + description = "%s" + tags = "%s" + }`, instanceName, name, propertyID, typeVar, description, tags) +} + +func testAccCheckIbmAppConfigPropertyExists(n string, obj appconfigurationv1.Property) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + options := &appconfigurationv1.GetPropertyOptions{} + + options.SetEnvironmentID(parts[1]) + options.SetPropertyID(parts[2]) + + property, _, err := appconfigClient.GetProperty(options) + if err != nil { + return err + } + + obj = *property + return nil + } +} + +func testAccCheckIbmAppConfigPropertyDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_app-config-property" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + options := &appconfigurationv1.GetPropertyOptions{} + + options.SetEnvironmentID(parts[1]) + options.SetPropertyID(parts[2]) + + // Try to find the key + _, response, err := appconfigClient.GetProperty(options) + + if err == nil { + return fmt.Errorf("app_config_property still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for app_config_property (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_segment.go b/ibm/service/appconfiguration/resource_ibm_app_config_segment.go new file mode 100644 index 000000000..ae3d356cc --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_segment.go @@ -0,0 +1,352 @@ +package appconfiguration + +import ( + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" +) + +func ResourceIBMIbmAppConfigSegment() *schema.Resource { + return &schema.Resource{ + Create: resourceIbmIbmAppConfigSegmentCreate, + Read: resourceIbmIbmAppConfigSegmentRead, + Update: resourceIbmIbmAppConfigSegmentUpdate, + Delete: resourceIbmIbmAppConfigSegmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Segment name.", + }, + "segment_id": { + Type: schema.TypeString, + Required: true, + Description: "Segment id.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Segment description.", + }, + "tags": { + Type: schema.TypeString, + Optional: true, + Description: "Tags associated with the segments.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the segment.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the segment data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Segment URL.", + }, + "rules": { + Type: schema.TypeList, + Required: true, + Description: "List of rules that determine if the entity belongs to the segment during feature / property evaluation. An entity is identified by an unique identifier and the attributes that it defines.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attribute_name": { + Type: schema.TypeString, + Required: true, + Description: "Attribute name.", + }, + "operator": { + Type: schema.TypeString, + Required: true, + Description: "Operator to be used for the evaluation if the entity belongs to the segment.", + }, + "values": { + Type: schema.TypeList, + Required: true, + Description: "List of values. Entities matching any of the given values will be considered to belong to the segment.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + } +} + +func resourceIbmIbmAppConfigSegmentCreate(d *schema.ResourceData, meta interface{}) error { + + guid := d.Get("guid").(string) + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return err + } + options := &appconfigurationv1.CreateSegmentOptions{} + options.SetName(d.Get("name").(string)) + options.SetSegmentID(d.Get("segment_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + + if _, ok := d.GetOk("rules"); ok { + var segmentRules []appconfigurationv1.Rule + for _, e := range d.Get("rules").([]interface{}) { + value := e.(map[string]interface{}) + segmentRulesItem, err := resourceIbmAppConfigMapToSegmentRule(value) + if err != nil { + return err + } + segmentRules = append(segmentRules, segmentRulesItem) + } + options.SetRules(segmentRules) + } + + segment, response, err := appconfigClient.CreateSegment(options) + + if err != nil { + log.Printf("CreateSegment failed %s\n%s", err, response) + return fmt.Errorf("CreateSegment failed %s\n%s", err, response) + } + d.SetId(fmt.Sprintf("%s/%s", guid, *segment.SegmentID)) + return resourceIbmIbmAppConfigSegmentRead(d, meta) +} + +func resourceIbmAppConfigMapToSegmentRule(segmentRuleMap map[string]interface{}) (appconfigurationv1.Rule, error) { + segmentRule := appconfigurationv1.Rule{} + + segmentRule.AttributeName = core.StringPtr(segmentRuleMap["attribute_name"].(string)) + segmentRule.Operator = core.StringPtr(segmentRuleMap["operator"].(string)) + var values []string + for _, rulesItem := range segmentRuleMap["values"].([]interface{}) { + values = append(values, rulesItem.(string)) + } + segmentRule.Values = values + return segmentRule, nil +} + +func resourceIbmIbmAppConfigSegmentRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + if len(parts) != 2 { + return fmt.Errorf("Kindly check the id") + } + + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + + options := &appconfigurationv1.GetSegmentOptions{} + options.SetSegmentID(parts[1]) + + result, response, err := appconfigClient.GetSegment(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + } + return fmt.Errorf("[DEBUG] GetSegment failed %s\n%s", err, response) + } + + d.Set("guid", parts[0]) + + if result.Name != nil { + if err = d.Set("name", result.Name); err != nil { + return fmt.Errorf("[ERROR] Error setting name: %s", err) + } + } + if result.SegmentID != nil { + if err = d.Set("segment_id", result.SegmentID); err != nil { + return fmt.Errorf("[ERROR] Error setting segment_id: %s", err) + } + } + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return fmt.Errorf("[ERROR] Error setting description: %s", err) + } + } + if result.Tags != nil { + if err = d.Set("tags", result.Tags); err != nil { + return fmt.Errorf("[ERROR] Error setting tags: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting createdTime: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updatedTime: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + if result.Rules != nil { + segmentRules := []map[string]interface{}{} + for _, ruleItem := range result.Rules { + segmentRulesItemMap := resourceIbmAppConfigSegmentRuleToMap(ruleItem) + segmentRules = append(segmentRules, segmentRulesItemMap) + } + if err = d.Set("rules", segmentRules); err != nil { + return fmt.Errorf("[ERROR] Error setting segment_rules: %s", err) + } + } + if result.Features != nil { + err = d.Set("features", resourceIbmAppConfigSegmentFeatureToMap(result.Features)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting features %s", err) + } + } + if result.Properties != nil { + err = d.Set("properties", resourceIbmAppConfigSegmentPropertiesToMap(result.Properties)) + if err != nil { + return fmt.Errorf("[ERROR] Error setting properties %s", err) + } + } + return nil +} + +func resourceIbmIbmAppConfigSegmentUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + options := &appconfigurationv1.UpdateSegmentOptions{} + + options.SetSegmentID(parts[1]) + + if ok := d.HasChanges("name", "description", "tags", "rules", "attribute_name", "operator", "values"); ok { + + if _, ok := d.GetOk("name"); ok { + options.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("tags"); ok { + options.SetTags(d.Get("tags").(string)) + } + if _, ok := d.GetOk("rules"); ok { + var segmentRules []appconfigurationv1.Rule + for _, e := range d.Get("rules").([]interface{}) { + value := e.(map[string]interface{}) + segmentRulesItem, err := resourceIbmAppConfigMapToSegmentRule(value) + if err != nil { + return err + } + segmentRules = append(segmentRules, segmentRulesItem) + } + options.SetRules(segmentRules) + } + + _, response, err := appconfigClient.UpdateSegment(options) + if err != nil { + log.Printf("[DEBUG] UpdateSegment %s\n%s", err, response) + return err + } + return resourceIbmIbmAppConfigSegmentRead(d, meta) + } + return nil +} + +func resourceIbmIbmAppConfigSegmentDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + + options := &appconfigurationv1.DeleteSegmentOptions{} + options.SetSegmentID(parts[1]) + + response, err := appconfigClient.DeleteSegment(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[DEBUG] DeleteSegment failed %s\n%s", err, response) + } + + d.SetId("") + + return nil +} + +func resourceIbmAppConfigSegmentRuleToMap(segmentRulesItem appconfigurationv1.Rule) (segmentRulesMap map[string]interface{}) { + segmentRulesMap = map[string]interface{}{} + + segmentRulesMap["values"] = segmentRulesItem.Values + segmentRulesMap["attribute_name"] = segmentRulesItem.AttributeName + segmentRulesMap["operator"] = segmentRulesItem.Operator + + return segmentRulesMap +} + +func resourceIbmAppConfigSegmentFeatureToMap(result []appconfigurationv1.FeatureOutput) (features []map[string]interface{}) { + for _, featuresItem := range result { + features = append(features, resourceSegmentFeaturesToMap(featuresItem)) + } + return features +} + +func resourceIbmAppConfigSegmentPropertiesToMap(result []appconfigurationv1.PropertyOutput) (properties []map[string]interface{}) { + for _, propertiesItem := range result { + properties = append(properties, resourceSegmentPropertiesToMap(propertiesItem)) + } + return properties +} + +func resourceSegmentFeaturesToMap(featuresItem appconfigurationv1.FeatureOutput) (featuresMap map[string]interface{}) { + featuresMap = map[string]interface{}{} + + if featuresItem.FeatureID != nil { + featuresMap["feature_id"] = featuresItem.FeatureID + } + if featuresItem.Name != nil { + featuresMap["name"] = featuresItem.Name + } + return featuresMap +} + +func resourceSegmentPropertiesToMap(propertiesItem appconfigurationv1.PropertyOutput) (propertiesMap map[string]interface{}) { + propertiesMap = map[string]interface{}{} + + if propertiesItem.PropertyID != nil { + propertiesMap["property_id"] = propertiesItem.PropertyID + } + if propertiesItem.Name != nil { + propertiesMap["name"] = propertiesItem.Name + } + + return propertiesMap +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_segment_test.go b/ibm/service/appconfiguration/resource_ibm_app_config_segment_test.go new file mode 100644 index 000000000..62f18a146 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_segment_test.go @@ -0,0 +1,132 @@ +package appconfiguration_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" + + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" +) + +func TestAccIbmIbmAppConfigSegmentBasic(t *testing.T) { + var conf appconfigurationv1.Segment + instanceName := fmt.Sprintf("tf_app_config_test_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + segmentID := fmt.Sprintf("tf_segment_id_%d", acctest.RandIntRange(10, 100)) + + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmAppConfigSegmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmAppConfigSegmentConfigBasic(instanceName, name, segmentID, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmAppConfigSegmentExists("ibm_app_config_segment.ibm_app_config_segment_resource1", conf), + resource.TestCheckResourceAttrSet("ibm_app_config_segment.ibm_app_config_segment_resource1", "id"), + resource.TestCheckResourceAttrSet("ibm_app_config_segment.ibm_app_config_segment_resource1", "name"), + resource.TestCheckResourceAttrSet("ibm_app_config_segment.ibm_app_config_segment_resource1", "segment_id"), + resource.TestCheckResourceAttrSet("ibm_app_config_segment.ibm_app_config_segment_resource1", "description"), + ), + }, + { + Config: testAccCheckIbmAppConfigSegmentConfigBasic(instanceName, nameUpdate, segmentID, descriptionUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_app_config_segment.ibm_app_config_segment_resource1", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_app_config_segment.ibm_app_config_segment_resource1", "description", descriptionUpdate), + ), + }, + }, + }) +} + +func testAccCheckIbmAppConfigSegmentConfigBasic(name, envName, segmentID, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "app_config_terraform_test456" { + name = "%s" + location = "us-south" + service = "apprapp" + plan = "lite" + } + resource "ibm_app_config_segment" "ibm_app_config_segment_resource1" { + guid = ibm_resource_instance.app_config_terraform_test456.guid + name = "%s" + segment_id = "%s" + rules { + attribute_name = "countary" + operator = "contains" + values = ["india", "UK"] + } + description = "%s" + + }`, name, envName, segmentID, description) +} + +func testAccCheckIbmAppConfigSegmentExists(n string, obj appconfigurationv1.Segment) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + + options := &appconfigurationv1.GetSegmentOptions{} + + options.SetSegmentID(parts[1]) + + result, _, err := appconfigClient.GetSegment(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIbmAppConfigSegmentDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_app_config_segment_resource1" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + appconfigClient, err := getAppConfigClient(acc.TestAccProvider.Meta(), parts[0]) + if err != nil { + return err + } + options := &appconfigurationv1.GetSegmentOptions{} + + options.SetSegmentID(parts[1]) + + // Try to find the key + _, response, err := appconfigClient.GetSegment(options) + + if err == nil { + return fmt.Errorf("Segment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for Segment (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/appconfiguration/resource_ibm_app_config_snapshot.go b/ibm/service/appconfiguration/resource_ibm_app_config_snapshot.go new file mode 100644 index 000000000..d5447b2b8 --- /dev/null +++ b/ibm/service/appconfiguration/resource_ibm_app_config_snapshot.go @@ -0,0 +1,307 @@ +package appconfiguration + +import ( + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/appconfiguration-go-admin-sdk/appconfigurationv1" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" +) + +func ResourceIBMIbmAppConfigSnapshot() *schema.Resource { + return &schema.Resource{ + Create: resourceIbmIbmAppConfigSnapshotCreate, + Read: resourceIbmIbmAppConfigSnapshotRead, + Update: resourceIbmIbmAppConfigSnapshotUpdate, + Delete: resourceIbmIbmAppConfigSnapshotDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + }, + "git_config_id": { + Type: schema.TypeString, + Required: true, + Description: "Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + }, + "git_config_name": { + Type: schema.TypeString, + Required: true, + Description: "Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + }, + "git_url": { + Type: schema.TypeString, + Required: true, + Description: "Git url which will be used to connect to the github account.", + }, + "git_branch": { + Type: schema.TypeString, + Required: true, + Description: "Branch name to which you need to write or update the configuration.", + }, + "git_file_path": { + Type: schema.TypeString, + Required: true, + Description: "Git file path, this is a path where your configuration file will be written.", + }, + "git_token": { + Type: schema.TypeString, + Sensitive: true, + Required: true, + Description: "Git token, this needs to be provided with enough permission to write and update the file.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the git config.", + }, + "collection_id": { + Type: schema.TypeString, + Required: true, + Description: "Collection id.", + }, + "action": { + Type: schema.TypeString, + Optional: true, + Description: "action promote", + }, + "environment_id": { + Type: schema.TypeString, + Required: true, + Description: "Environment id.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last modified time of the git config data.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Git config URL.", + }, + "collection": { + Type: schema.TypeList, + Computed: true, + Description: "Collection object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collection_name": { + Type: schema.TypeString, + Computed: true, + Description: "Collection name.", + }, + "collection_id": { + Type: schema.TypeString, + Computed: true, + Description: "Collection id.", + }, + }, + }, + }, + "environment": { + Type: schema.TypeList, + Computed: true, + Description: "Environment object", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "environment_name": { + Type: schema.TypeString, + Computed: true, + Description: "Environment name.", + }, + "environment_id": { + Type: schema.TypeString, + Computed: true, + Description: "Environment id.", + }, + "color_code": { + Type: schema.TypeString, + Computed: true, + Description: "Environment color code.", + }, + }, + }, + }, + }, + } +} + +func resourceIbmIbmAppConfigSnapshotCreate(d *schema.ResourceData, meta interface{}) error { + + guid := d.Get("guid").(string) + appconfigClient, err := getAppConfigClient(meta, guid) + if err != nil { + return err + } + options := &appconfigurationv1.CreateGitconfigOptions{} + + options.SetGitConfigName(d.Get("git_config_name").(string)) + options.SetGitConfigID(d.Get("git_config_id").(string)) + + options.SetCollectionID(d.Get("collection_id").(string)) + options.SetEnvironmentID(d.Get("environment_id").(string)) + options.SetGitURL(d.Get("git_url").(string)) + options.SetGitBranch(d.Get("git_branch").(string)) + options.SetGitFilePath(d.Get("git_file_path").(string)) + options.SetGitToken(d.Get("git_token").(string)) + + snapshot, response, err := appconfigClient.CreateGitconfig(options) + + if err != nil { + return fmt.Errorf("CreateGitconfig failed %s\n%s", err, response) + } + d.SetId(fmt.Sprintf("%s/%s", guid, *snapshot.GitConfigID)) + return resourceIbmIbmAppConfigSnapshotRead(d, meta) +} + +func resourceIbmIbmAppConfigSnapshotUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + + if ok := d.HasChanges("action"); ok { + option := &appconfigurationv1.PromoteGitconfigOptions{} + option.SetGitConfigID(parts[1]) + _, response, err := appconfigClient.PromoteGitconfig(option) + if err != nil { + log.Printf("[DEBUG] PromoteGitconfig %s\n%s", err, response) + return err + } + return resourceIbmIbmAppConfigSnapshotRead(d, meta) + } else { + if ok := d.HasChanges("git_config_name", "collection_id", "environment_id", "git_url", "git_branch", "git_file_path", "git_token"); ok { + options := &appconfigurationv1.UpdateGitconfigOptions{} + options.SetGitConfigID(parts[1]) + if _, ok := d.GetOk("git_config_name"); ok { + options.SetGitConfigName(d.Get("git_config_name").(string)) + } + if _, ok := d.GetOk("collection_id"); ok { + options.SetCollectionID(d.Get("collection_id").(string)) + } + if _, ok := d.GetOk("environment_id"); ok { + options.SetEnvironmentID(d.Get("environment_id").(string)) + } + if _, ok := d.GetOk("git_url"); ok { + options.SetGitURL(d.Get("git_url").(string)) + } + if _, ok := d.GetOk("git_branch"); ok { + options.SetGitBranch(d.Get("git_branch").(string)) + } + if _, ok := d.GetOk("git_file_path"); ok { + options.SetGitFilePath(d.Get("git_file_path").(string)) + } + if _, ok := d.GetOk("git_token"); ok { + options.SetGitToken(d.Get("git_token").(string)) + } + _, response, err := appconfigClient.UpdateGitconfig(options) + if err != nil { + log.Printf("[DEBUG] UpdateGitconfig %s\n%s", err, response) + return err + } + return resourceIbmIbmAppConfigSnapshotRead(d, meta) + } + } + return nil +} + +func resourceIbmIbmAppConfigSnapshotRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + if len(parts) != 2 { + return fmt.Errorf("Kindly check the id") + } + + options := &appconfigurationv1.GetGitconfigOptions{} + options.SetGitConfigID(parts[1]) + + result, response, err := appconfigClient.GetGitconfig(options) + if err != nil { + return fmt.Errorf("[DEBUG] GetGitconfigs failed %s\n%s", err, response) + } + + d.Set("guid", parts[0]) + d.Set("git_config_id", parts[1]) + if result.GitConfigName != nil { + if err = d.Set("git_config_name", result.GitConfigName); err != nil { + return fmt.Errorf("[ERROR] Error setting git_config_name: %s", err) + } + } + if result.GitConfigID != nil { + if err = d.Set("git_config_id", result.GitConfigID); err != nil { + return fmt.Errorf("[ERROR] Error setting git_config_id: %s", err) + } + } + if result.GitURL != nil { + if err = d.Set("git_url", result.GitURL); err != nil { + return fmt.Errorf("[ERROR] Error setting git_url: %s", err) + } + } + if result.GitBranch != nil { + if err = d.Set("git_branch", result.GitBranch); err != nil { + return fmt.Errorf("[ERROR] Error setting git_branch: %s", err) + } + } + if result.GitFilePath != nil { + if err = d.Set("git_file_path", result.GitFilePath); err != nil { + return fmt.Errorf("[ERROR] Error setting git_file_path: %s", err) + } + } + if result.CreatedTime != nil { + if err = d.Set("created_time", result.CreatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting created_time: %s", err) + } + } + if result.UpdatedTime != nil { + if err = d.Set("updated_time", result.UpdatedTime.String()); err != nil { + return fmt.Errorf("[ERROR] Error setting updated_time: %s", err) + } + } + if result.Href != nil { + if err = d.Set("href", result.Href); err != nil { + return fmt.Errorf("[ERROR] Error setting href: %s", err) + } + } + return nil +} + +func resourceIbmIbmAppConfigSnapshotDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil + } + appconfigClient, err := getAppConfigClient(meta, parts[0]) + if err != nil { + return err + } + + options := &appconfigurationv1.DeleteGitconfigOptions{} + options.SetGitConfigID(parts[1]) + + response, err := appconfigClient.DeleteGitconfig(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[DEBUG] DeleteGitconfig failed %s\n%s", err, response) + } + d.SetId("") + + return nil +} diff --git a/ibm/service/appid/README.md b/ibm/service/appid/README.md new file mode 100644 index 000000000..47a7cdb14 --- /dev/null +++ b/ibm/service/appid/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider APP ID Management + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the APP ID Management resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/appid_action_url) +* IBM API Docs: [IBM API Docs for APP ID Management](https://cloud.ibm.com/apidocs/app-id/management) +* IBM APP ID Management SDK: [IBM SDK for APP ID Management](https://github.com/IBM/appid-management-go-sdk/tree/main/appidmanagementv4) diff --git a/ibm/data_source_ibm_appid_action_url.go b/ibm/service/appid/data_source_ibm_appid_action_url.go similarity index 90% rename from ibm/data_source_ibm_appid_action_url.go rename to ibm/service/appid/data_source_ibm_appid_action_url.go index 77e80d691..3f510e69d 100644 --- a/ibm/data_source_ibm_appid_action_url.go +++ b/ibm/service/appid/data_source_ibm_appid_action_url.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func dataSourceIBMAppIDActionURL() *schema.Resource { +func DataSourceIBMAppIDActionURL() *schema.Resource { return &schema.Resource{ Description: "The custom url to redirect to when Cloud Directory action is executed.", ReadContext: dataSourceIBMAppIDActionURLRead, @@ -35,7 +37,7 @@ func dataSourceIBMAppIDActionURL() *schema.Resource { } func dataSourceIBMAppIDActionURLRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_action_url_test.go b/ibm/service/appid/data_source_ibm_appid_action_url_test.go similarity index 78% rename from ibm/data_source_ibm_appid_action_url_test.go rename to ibm/service/appid/data_source_ibm_appid_action_url_test.go index 29ba929ba..e36a2401f 100644 --- a/ibm/data_source_ibm_appid_action_url_test.go +++ b/ibm/service/appid/data_source_ibm_appid_action_url_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDActionURLDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDActionURLDataSourceConfig(appIDTenantID), + Config: setupAppIDActionURLDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_action_url.url", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_action_url.url", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_action_url.url", "action", "on_user_verified"), resource.TestCheckResourceAttr("data.ibm_appid_action_url.url", "url", "https://www.example.com/?user=verified"), ), diff --git a/ibm/data_source_ibm_appid_apm.go b/ibm/service/appid/data_source_ibm_appid_apm.go similarity index 96% rename from ibm/data_source_ibm_appid_apm.go rename to ibm/service/appid/data_source_ibm_appid_apm.go index d875cdb36..0768d55d9 100644 --- a/ibm/data_source_ibm_appid_apm.go +++ b/ibm/service/appid/data_source_ibm_appid_apm.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDAPM() *schema.Resource { +func DataSourceIBMAppIDAPM() *schema.Resource { return &schema.Resource{ Description: "AppID advanced password management configuration (available for graduated tier only)", ReadContext: dataSourceIBMAppIDAPMRead, @@ -99,7 +101,7 @@ func dataSourceIBMAppIDAPM() *schema.Resource { } func dataSourceIBMAppIDAPMRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_apm_test.go b/ibm/service/appid/data_source_ibm_appid_apm_test.go similarity index 89% rename from ibm/data_source_ibm_appid_apm_test.go rename to ibm/service/appid/data_source_ibm_appid_apm_test.go index a21d30c9c..af9247eeb 100644 --- a/ibm/data_source_ibm_appid_apm_test.go +++ b/ibm/service/appid/data_source_ibm_appid_apm_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDAPMDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDAPMDataSourceConfig(appIDTenantID), + Config: setupIBMAppIDAPMDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_apm.apm", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_apm.apm", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_apm.apm", "enabled", "true"), resource.TestCheckResourceAttr("data.ibm_appid_apm.apm", "prevent_password_with_username", "true"), resource.TestCheckResourceAttr("data.ibm_appid_apm.apm", "password_reuse.0.enabled", "true"), diff --git a/ibm/data_source_ibm_appid_application.go b/ibm/service/appid/data_source_ibm_appid_application.go similarity index 93% rename from ibm/data_source_ibm_appid_application.go rename to ibm/service/appid/data_source_ibm_appid_application.go index e731ac9c3..c5acc2579 100644 --- a/ibm/data_source_ibm_appid_application.go +++ b/ibm/service/appid/data_source_ibm_appid_application.go @@ -1,14 +1,16 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDApplication() *schema.Resource { +func DataSourceIBMAppIDApplication() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDApplicationRead, Schema: map[string]*schema.Schema{ @@ -57,7 +59,7 @@ func dataSourceIBMAppIDApplication() *schema.Resource { } func dataSourceIBMAppIDApplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_application_roles.go b/ibm/service/appid/data_source_ibm_appid_application_roles.go similarity index 92% rename from ibm/data_source_ibm_appid_application_roles.go rename to ibm/service/appid/data_source_ibm_appid_application_roles.go index 25d12c564..06f8bd63a 100644 --- a/ibm/data_source_ibm_appid_application_roles.go +++ b/ibm/service/appid/data_source_ibm_appid_application_roles.go @@ -1,14 +1,16 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDApplicationRoles() *schema.Resource { +func DataSourceIBMAppIDApplicationRoles() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDApplicationRolesRead, Schema: map[string]*schema.Schema{ @@ -46,7 +48,7 @@ func dataSourceIBMAppIDApplicationRoles() *schema.Resource { } func dataSourceIBMAppIDApplicationRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_application_roles_test.go b/ibm/service/appid/data_source_ibm_appid_application_roles_test.go similarity index 89% rename from ibm/data_source_ibm_appid_application_roles_test.go rename to ibm/service/appid/data_source_ibm_appid_application_roles_test.go index 2e7626e5a..bce20f91e 100644 --- a/ibm/data_source_ibm_appid_application_roles_test.go +++ b/ibm/service/appid/data_source_ibm_appid_application_roles_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -13,11 +15,11 @@ func TestAccIBMAppIDApplicationRolesDataSource_basic(t *testing.T) { roleName := fmt.Sprintf("tf_testacc_app_roles_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationRolesDataSourceConfig(appIDTenantID, appName, roleName), + Config: testAccCheckIBMAppIDApplicationRolesDataSourceConfig(acc.AppIDTenantID, appName, roleName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_application_roles.roles", "roles.#", "1"), resource.TestCheckResourceAttrPair("ibm_appid_role.role", "role_id", "data.ibm_appid_application_roles.roles", "roles.0.id"), diff --git a/ibm/data_source_ibm_appid_application_scopes.go b/ibm/service/appid/data_source_ibm_appid_application_scopes.go similarity index 89% rename from ibm/data_source_ibm_appid_application_scopes.go rename to ibm/service/appid/data_source_ibm_appid_application_scopes.go index 873c90dc3..d3a134220 100644 --- a/ibm/data_source_ibm_appid_application_scopes.go +++ b/ibm/service/appid/data_source_ibm_appid_application_scopes.go @@ -1,14 +1,16 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDApplicationScopes() *schema.Resource { +func DataSourceIBMAppIDApplicationScopes() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDApplicationScopesRead, Schema: map[string]*schema.Schema{ @@ -35,7 +37,7 @@ func dataSourceIBMAppIDApplicationScopes() *schema.Resource { } func dataSourceIBMAppIDApplicationScopesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_application_scopes_test.go b/ibm/service/appid/data_source_ibm_appid_application_scopes_test.go similarity index 89% rename from ibm/data_source_ibm_appid_application_scopes_test.go rename to ibm/service/appid/data_source_ibm_appid_application_scopes_test.go index a0833ad89..1b0af6739 100644 --- a/ibm/data_source_ibm_appid_application_scopes_test.go +++ b/ibm/service/appid/data_source_ibm_appid_application_scopes_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -12,11 +14,11 @@ func TestAccIBMAppIDApplicationScopesDataSource_basic(t *testing.T) { appName := fmt.Sprintf("tf_testacc_app_scopes_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationScopesDataSourceConfig(appIDTenantID, appName), + Config: testAccCheckIBMAppIDApplicationScopesDataSourceConfig(acc.AppIDTenantID, appName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_application_scopes.scopes", "scopes.#", "3"), resource.TestCheckResourceAttr("data.ibm_appid_application_scopes.scopes", "scopes.0", "scope1"), diff --git a/ibm/data_source_ibm_appid_application_test.go b/ibm/service/appid/data_source_ibm_appid_application_test.go similarity index 80% rename from ibm/data_source_ibm_appid_application_test.go rename to ibm/service/appid/data_source_ibm_appid_application_test.go index 7e1ff6d67..7d859d9d3 100644 --- a/ibm/data_source_ibm_appid_application_test.go +++ b/ibm/service/appid/data_source_ibm_appid_application_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -12,13 +14,13 @@ func TestAccIBMAppIDApplicationDataSource_basic(t *testing.T) { appName := fmt.Sprintf("tf_testacc_app_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationDataSourceConfig(appIDTenantID, appName), + Config: testAccCheckIBMAppIDApplicationDataSourceConfig(acc.AppIDTenantID, appName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_application.test_app", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_application.test_app", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_application.test_app", "name", appName), resource.TestCheckResourceAttr("data.ibm_appid_application.test_app", "type", "singlepageapp"), resource.TestCheckResourceAttrSet("data.ibm_appid_application.test_app", "client_id"), diff --git a/ibm/data_source_ibm_appid_applications.go b/ibm/service/appid/data_source_ibm_appid_applications.go similarity index 94% rename from ibm/data_source_ibm_appid_applications.go rename to ibm/service/appid/data_source_ibm_appid_applications.go index b80f91710..bd4c7a42f 100644 --- a/ibm/data_source_ibm_appid_applications.go +++ b/ibm/service/appid/data_source_ibm_appid_applications.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + "sort" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "sort" ) -func dataSourceIBMAppIDApplications() *schema.Resource { +func DataSourceIBMAppIDApplications() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDApplicationsRead, Schema: map[string]*schema.Schema{ @@ -66,7 +68,7 @@ func dataSourceIBMAppIDApplications() *schema.Resource { } func dataSourceIBMAppIDApplicationsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_applications_test.go b/ibm/service/appid/data_source_ibm_appid_applications_test.go similarity index 84% rename from ibm/data_source_ibm_appid_applications_test.go rename to ibm/service/appid/data_source_ibm_appid_applications_test.go index 4b7e19fbb..b2075b0d8 100644 --- a/ibm/data_source_ibm_appid_applications_test.go +++ b/ibm/service/appid/data_source_ibm_appid_applications_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -13,11 +15,11 @@ func TestAccIBMAppIDApplicationsDataSource_basic(t *testing.T) { appName2 := fmt.Sprintf("tf_testacc_app_2_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationsDataSourceConfig(appIDTenantID, appName1, appName2), + Config: testAccCheckIBMAppIDApplicationsDataSourceConfig(acc.AppIDTenantID, appName1, appName2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_applications.apps", "applications.#", "2"), resource.TestCheckResourceAttr("data.ibm_appid_applications.apps", "applications.0.name", appName1), diff --git a/ibm/data_source_ibm_appid_audit_status.go b/ibm/service/appid/data_source_ibm_appid_audit_status.go similarity index 85% rename from ibm/data_source_ibm_appid_audit_status.go rename to ibm/service/appid/data_source_ibm_appid_audit_status.go index 696f19d01..6f7525376 100644 --- a/ibm/data_source_ibm_appid_audit_status.go +++ b/ibm/service/appid/data_source_ibm_appid_audit_status.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDAuditStatus() *schema.Resource { +func DataSourceIBMAppIDAuditStatus() *schema.Resource { return &schema.Resource{ Description: "Tenant audit status", ReadContext: dataSourceIBMAppIDAuditStatusRead, @@ -27,7 +29,7 @@ func dataSourceIBMAppIDAuditStatus() *schema.Resource { } func dataSourceIBMAppIDAuditStatusRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/data_source_ibm_appid_audit_status_test.go b/ibm/service/appid/data_source_ibm_appid_audit_status_test.go new file mode 100644 index 000000000..ddb822c68 --- /dev/null +++ b/ibm/service/appid/data_source_ibm_appid_audit_status_test.go @@ -0,0 +1,43 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMAppIDAuditStatusDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupAppIDAuditStatusDataSourceConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_appid_audit_status.status", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_audit_status.status", "is_active", "true"), + ), + }, + }, + }) +} + +func setupAppIDAuditStatusDataSourceConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_audit_status" "status" { + tenant_id = "%s" + is_active = true + } + + data "ibm_appid_audit_status" "status" { + tenant_id = ibm_appid_audit_status.status.tenant_id + + depends_on = [ + ibm_appid_audit_status.status + ] + } + `, tenantID) +} diff --git a/ibm/data_source_ibm_appid_cloud_directory_template.go b/ibm/service/appid/data_source_ibm_appid_cloud_directory_template.go similarity index 93% rename from ibm/data_source_ibm_appid_cloud_directory_template.go rename to ibm/service/appid/data_source_ibm_appid_cloud_directory_template.go index 3d533d736..8c6a1d5e9 100644 --- a/ibm/data_source_ibm_appid_cloud_directory_template.go +++ b/ibm/service/appid/data_source_ibm_appid_cloud_directory_template.go @@ -1,8 +1,10 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -11,7 +13,7 @@ import ( var supportedAppIDCDTemplates = []string{"USER_VERIFICATION", "RESET_PASSWORD", "WELCOME", "PASSWORD_CHANGED", "MFA_VERIFICATION"} -func dataSourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { +func DataSourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDCloudDirectoryTemplateRead, Schema: map[string]*schema.Schema{ @@ -57,7 +59,7 @@ func dataSourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { } func dataSourceIBMAppIDCloudDirectoryTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_cloud_directory_template_test.go b/ibm/service/appid/data_source_ibm_appid_cloud_directory_template_test.go similarity index 85% rename from ibm/data_source_ibm_appid_cloud_directory_template_test.go rename to ibm/service/appid/data_source_ibm_appid_cloud_directory_template_test.go index 90e332c35..7112bcc7f 100644 --- a/ibm/data_source_ibm_appid_cloud_directory_template_test.go +++ b/ibm/service/appid/data_source_ibm_appid_cloud_directory_template_test.go @@ -1,11 +1,14 @@ -package ibm +package appid_test import ( b64 "encoding/base64" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "strings" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDCloudDirectoryTemplateDataSource_basic(t *testing.T) { @@ -15,13 +18,13 @@ func TestAccIBMAppIDCloudDirectoryTemplateDataSource_basic(t *testing.T) { subject := "Please Verify Your Email Address %%{user.displayName} TEST" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDCloudDirectoryTemplateDataSourceConfig(appIDTenantID, subject, htmlBody, textBody), + Config: setupAppIDCloudDirectoryTemplateDataSourceConfig(acc.AppIDTenantID, subject, htmlBody, textBody), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_template.test_tpl", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_template.test_tpl", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_template.test_tpl", "template_name", "USER_VERIFICATION"), resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_template.test_tpl", "subject", strings.Replace(subject, "%%", "%", 1)), resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_template.test_tpl", "html_body", htmlBody), diff --git a/ibm/data_source_ibm_appid_cloud_directory_user.go b/ibm/service/appid/data_source_ibm_appid_cloud_directory_user.go similarity index 96% rename from ibm/data_source_ibm_appid_cloud_directory_user.go rename to ibm/service/appid/data_source_ibm_appid_cloud_directory_user.go index 4e6b5e192..c851cab8a 100644 --- a/ibm/data_source_ibm_appid_cloud_directory_user.go +++ b/ibm/service/appid/data_source_ibm_appid_cloud_directory_user.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func dataSourceIBMAppIDCloudDirectoryUser() *schema.Resource { +func DataSourceIBMAppIDCloudDirectoryUser() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDCloudDirectoryUserRead, Schema: map[string]*schema.Schema{ @@ -96,7 +98,7 @@ func dataSourceIBMAppIDCloudDirectoryUser() *schema.Resource { } func dataSourceIBMAppIDCloudDirectoryUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_cloud_directory_user_test.go b/ibm/service/appid/data_source_ibm_appid_cloud_directory_user_test.go similarity index 91% rename from ibm/data_source_ibm_appid_cloud_directory_user_test.go rename to ibm/service/appid/data_source_ibm_appid_cloud_directory_user_test.go index 95b035180..603ad79ae 100644 --- a/ibm/data_source_ibm_appid_cloud_directory_user_test.go +++ b/ibm/service/appid/data_source_ibm_appid_cloud_directory_user_test.go @@ -1,11 +1,14 @@ -package ibm +package appid_test import ( "fmt" "strconv" "testing" + "time" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +19,11 @@ func TestAccIBMAppIDCloudDirectoryUserDataSource_basic(t *testing.T) { lockedUntil := time.Now().Add(time.Hour*2).UnixNano() / int64(time.Millisecond) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDCloudDirectoryUserDataSourceConfig(appIDTenantID, userName, email, lockedUntil), + Config: testAccCheckIBMAppIDCloudDirectoryUserDataSourceConfig(acc.AppIDTenantID, userName, email, lockedUntil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_user.user", "active", "false"), resource.TestCheckResourceAttr("data.ibm_appid_cloud_directory_user.user", "locked_until", strconv.Itoa(int(lockedUntil))), diff --git a/ibm/data_source_ibm_appid_idp_cloud_directory.go b/ibm/service/appid/data_source_ibm_appid_idp_cloud_directory.go similarity index 93% rename from ibm/data_source_ibm_appid_idp_cloud_directory.go rename to ibm/service/appid/data_source_ibm_appid_idp_cloud_directory.go index 404d0eae4..54ac05dad 100644 --- a/ibm/data_source_ibm_appid_idp_cloud_directory.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_cloud_directory.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPCloudDirectory() *schema.Resource { +func DataSourceIBMAppIDIDPCloudDirectory() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDIDPCloudDirectoryRead, Schema: map[string]*schema.Schema{ @@ -62,7 +64,7 @@ func dataSourceIBMAppIDIDPCloudDirectory() *schema.Resource { } func dataSourceIBMAppIDIDPCloudDirectoryRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_idp_cloud_directory_test.go b/ibm/service/appid/data_source_ibm_appid_idp_cloud_directory_test.go similarity index 88% rename from ibm/data_source_ibm_appid_idp_cloud_directory_test.go rename to ibm/service/appid/data_source_ibm_appid_idp_cloud_directory_test.go index fce5df64f..f55f69676 100644 --- a/ibm/data_source_ibm_appid_idp_cloud_directory_test.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_cloud_directory_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDIDPCloudDirectoryDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDCloudDirectoryIDPConfig(appIDTenantID), + Config: setupIBMAppIDCloudDirectoryIDPConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_cloud_directory.idp", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_idp_cloud_directory.idp", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_idp_cloud_directory.idp", "is_active", "true"), resource.TestCheckResourceAttr("data.ibm_appid_idp_cloud_directory.idp", "self_service_enabled", "false"), resource.TestCheckResourceAttr("data.ibm_appid_idp_cloud_directory.idp", "signup_enabled", "false"), diff --git a/ibm/data_source_ibm_appid_idp_custom.go b/ibm/service/appid/data_source_ibm_appid_idp_custom.go similarity index 88% rename from ibm/data_source_ibm_appid_idp_custom.go rename to ibm/service/appid/data_source_ibm_appid_idp_custom.go index cf7c41dcc..604063515 100644 --- a/ibm/data_source_ibm_appid_idp_custom.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_custom.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPCustom() *schema.Resource { +func DataSourceIBMAppIDIDPCustom() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDIDPCustomRead, Schema: map[string]*schema.Schema{ @@ -30,7 +32,7 @@ func dataSourceIBMAppIDIDPCustom() *schema.Resource { } func dataSourceIBMAppIDIDPCustomRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_idp_custom_test.go b/ibm/service/appid/data_source_ibm_appid_idp_custom_test.go similarity index 83% rename from ibm/data_source_ibm_appid_idp_custom_test.go rename to ibm/service/appid/data_source_ibm_appid_idp_custom_test.go index dc01ac45f..872ad15f6 100644 --- a/ibm/data_source_ibm_appid_idp_custom_test.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_custom_test.go @@ -1,23 +1,26 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "strings" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDIDPCustomDataSource_basic(t *testing.T) { publicKey := `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzb19EC2vJfTLaJTs3/4F\ndmoHnpYHJo4Q5SJYJK2YfclwRJc49zs1juoNGvXsUOsEi58PHarot3aAUpzBk8g9\n1RdDoovQDKBhMbT7BXP291qp5WQsvrv5W6xPoTbNONYPmAWTN75e3AvvvQElgv9N\n4BBkXZ962bf/OM1Ccm786laop9fC03D7vmUUypISPMZ61O6aA3dRI2JSvHh+VL4s\nEtXkZvLR7DvvWl4sl4oA5EvpYqw5/qbXTp4bnllfiQuCuwgYz/MH1mQA4qGWEVTN\nE4z3b0jsHNHVAzsPfB3Bnok/Zvgtxc3cjVlm3el+bie9O3vW1jFQf1JCke/qusj7\neQIDAQAB\n-----END PUBLIC KEY-----\n` resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDCustomIDPDataSourceConfig(appIDTenantID, publicKey), + Config: setupAppIDCustomIDPDataSourceConfig(acc.AppIDTenantID, publicKey), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_custom.idp", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_idp_custom.idp", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_idp_custom.idp", "is_active", "true"), resource.TestCheckResourceAttr("data.ibm_appid_idp_custom.idp", "public_key", strings.Replace(publicKey, "\\n", "\n", -1)), ), diff --git a/ibm/data_source_ibm_appid_idp_facebook.go b/ibm/service/appid/data_source_ibm_appid_idp_facebook.go similarity index 93% rename from ibm/data_source_ibm_appid_idp_facebook.go rename to ibm/service/appid/data_source_ibm_appid_idp_facebook.go index 381ae20e7..59deb692c 100644 --- a/ibm/data_source_ibm_appid_idp_facebook.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_facebook.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPFacebook() *schema.Resource { +func DataSourceIBMAppIDIDPFacebook() *schema.Resource { return &schema.Resource{ Description: "Returns the Facebook identity provider configuration.", ReadContext: dataSourceIBMAppIDIDPFacebookRead, @@ -52,7 +54,7 @@ func dataSourceIBMAppIDIDPFacebook() *schema.Resource { } func dataSourceIBMAppIDIDPFacebookRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_idp_facebook_test.go b/ibm/service/appid/data_source_ibm_appid_idp_facebook_test.go similarity index 79% rename from ibm/data_source_ibm_appid_idp_facebook_test.go rename to ibm/service/appid/data_source_ibm_appid_idp_facebook_test.go index bf91440c4..62dd6b5c6 100644 --- a/ibm/data_source_ibm_appid_idp_facebook_test.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_facebook_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccAppIDIDPFacebookDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDFacebookIDPDataSourceConfig(appIDTenantID), + Config: setupIBMAppIDFacebookIDPDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_facebook.fb", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_idp_facebook.fb", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_idp_facebook.fb", "config.0.application_id", "test_id"), resource.TestCheckResourceAttr("data.ibm_appid_idp_facebook.fb", "config.0.application_secret", "test_secret"), resource.TestCheckResourceAttrSet("data.ibm_appid_idp_facebook.fb", "redirect_url"), diff --git a/ibm/data_source_ibm_appid_idp_google.go b/ibm/service/appid/data_source_ibm_appid_idp_google.go similarity index 92% rename from ibm/data_source_ibm_appid_idp_google.go rename to ibm/service/appid/data_source_ibm_appid_idp_google.go index 0d0e93460..3522c787d 100644 --- a/ibm/data_source_ibm_appid_idp_google.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_google.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPGoogle() *schema.Resource { +func DataSourceIBMAppIDIDPGoogle() *schema.Resource { return &schema.Resource{ Description: "Returns the Google identity provider configuration.", ReadContext: dataSourceIBMAppIDIDPGoogleRead, @@ -51,7 +53,7 @@ func dataSourceIBMAppIDIDPGoogle() *schema.Resource { } func dataSourceIBMAppIDIDPGoogleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_idp_google_test.go b/ibm/service/appid/data_source_ibm_appid_idp_google_test.go similarity index 79% rename from ibm/data_source_ibm_appid_idp_google_test.go rename to ibm/service/appid/data_source_ibm_appid_idp_google_test.go index 803d78c09..f5db68290 100644 --- a/ibm/data_source_ibm_appid_idp_google_test.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_google_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccAppIDIDPGoogleDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDGoogleIDPDataSourceConfig(appIDTenantID), + Config: setupIBMAppIDGoogleIDPDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_google.gg", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_idp_google.gg", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_idp_google.gg", "config.0.application_id", "test_id"), resource.TestCheckResourceAttr("data.ibm_appid_idp_google.gg", "config.0.application_secret", "test_secret"), resource.TestCheckResourceAttrSet("data.ibm_appid_idp_google.gg", "redirect_url"), diff --git a/ibm/data_source_ibm_appid_idp_saml.go b/ibm/service/appid/data_source_ibm_appid_idp_saml.go similarity index 93% rename from ibm/data_source_ibm_appid_idp_saml.go rename to ibm/service/appid/data_source_ibm_appid_idp_saml.go index 4ec6e5ddd..71bf1f31f 100644 --- a/ibm/data_source_ibm_appid_idp_saml.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_saml.go @@ -1,13 +1,16 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPSAML() *schema.Resource { +func DataSourceIBMAppIDIDPSAML() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDIDPSAMLRead, Schema: map[string]*schema.Schema{ @@ -94,7 +97,7 @@ func dataSourceIBMAppIDIDPSAML() *schema.Resource { } func dataSourceIBMAppIDIDPSAMLRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -138,7 +141,7 @@ func flattenAppIDIDPSAMLConfig(config *appid.SAMLConfigParams) []interface{} { mConfig["sign_in_url"] = *config.SignInURL } - mConfig["certificates"] = flattenStringList(config.Certificates) + mConfig["certificates"] = flex.FlattenStringList(config.Certificates) if config.DisplayName != nil { mConfig["display_name"] = *config.DisplayName diff --git a/ibm/data_source_ibm_appid_idp_saml_metadata.go b/ibm/service/appid/data_source_ibm_appid_idp_saml_metadata.go similarity index 86% rename from ibm/data_source_ibm_appid_idp_saml_metadata.go rename to ibm/service/appid/data_source_ibm_appid_idp_saml_metadata.go index daeb2cf56..b64d7b816 100644 --- a/ibm/data_source_ibm_appid_idp_saml_metadata.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_saml_metadata.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDIDPSAMLMetadata() *schema.Resource { +func DataSourceIBMAppIDIDPSAMLMetadata() *schema.Resource { return &schema.Resource{ Description: "Retrieve SAML metadata", ReadContext: dataSourceIBMAppIDIDPSAMLMetadataRead, @@ -27,7 +29,7 @@ func dataSourceIBMAppIDIDPSAMLMetadata() *schema.Resource { } func dataSourceIBMAppIDIDPSAMLMetadataRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/data_source_ibm_appid_idp_saml_metadata_test.go b/ibm/service/appid/data_source_ibm_appid_idp_saml_metadata_test.go new file mode 100644 index 000000000..1ec41feb9 --- /dev/null +++ b/ibm/service/appid/data_source_ibm_appid_idp_saml_metadata_test.go @@ -0,0 +1,34 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMAppIDIDPSAMLMetadataDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupAppIDIDPSAMLMetadataDataSourceConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_appid_idp_saml_metadata.meta", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttrSet("data.ibm_appid_idp_saml_metadata.meta", "metadata"), + ), + }, + }, + }) +} + +func setupAppIDIDPSAMLMetadataDataSourceConfig(tenantID string) string { + return fmt.Sprintf(` + data "ibm_appid_idp_saml_metadata" "meta" { + tenant_id = "%s" + } + `, tenantID) +} diff --git a/ibm/data_source_ibm_appid_idp_saml_test.go b/ibm/service/appid/data_source_ibm_appid_idp_saml_test.go similarity index 93% rename from ibm/data_source_ibm_appid_idp_saml_test.go rename to ibm/service/appid/data_source_ibm_appid_idp_saml_test.go index 95dd866bb..4111b4f94 100644 --- a/ibm/data_source_ibm_appid_idp_saml_test.go +++ b/ibm/service/appid/data_source_ibm_appid_idp_saml_test.go @@ -1,23 +1,26 @@ -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" ) func TestAccIBMAppIDIDPSamlDataSource_basic(t *testing.T) { dispName := fmt.Sprintf("testacc_saml_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDIDPSAMLDataSourceConfig(appIDTenantID, dispName), + Config: testAccCheckIBMAppIDIDPSAMLDataSourceConfig(acc.AppIDTenantID, dispName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_idp_saml.test_saml", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_idp_saml.test_saml", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_idp_saml.test_saml", "is_active", "true"), resource.TestCheckResourceAttr("data.ibm_appid_idp_saml.test_saml", "config.0.entity_id", "https://test-saml-idp"), resource.TestCheckResourceAttr("data.ibm_appid_idp_saml.test_saml", "config.0.sign_in_url", "https://test-saml-idp/login"), diff --git a/ibm/data_source_ibm_appid_languages.go b/ibm/service/appid/data_source_ibm_appid_languages.go similarity index 87% rename from ibm/data_source_ibm_appid_languages.go rename to ibm/service/appid/data_source_ibm_appid_languages.go index 343727288..7d1bccfed 100644 --- a/ibm/data_source_ibm_appid_languages.go +++ b/ibm/service/appid/data_source_ibm_appid_languages.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDLanguages() *schema.Resource { +func DataSourceIBMAppIDLanguages() *schema.Resource { return &schema.Resource{ Description: "User localization configuration", ReadContext: dataSourceIBMAppIDLanguagesRead, @@ -30,7 +32,7 @@ func dataSourceIBMAppIDLanguages() *schema.Resource { } func dataSourceIBMAppIDLanguagesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_languages_test.go b/ibm/service/appid/data_source_ibm_appid_languages_test.go similarity index 81% rename from ibm/data_source_ibm_appid_languages_test.go rename to ibm/service/appid/data_source_ibm_appid_languages_test.go index 09cef4852..c569b28ab 100644 --- a/ibm/data_source_ibm_appid_languages_test.go +++ b/ibm/service/appid/data_source_ibm_appid_languages_test.go @@ -1,23 +1,26 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "strings" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDLanguagesDataSource_basic(t *testing.T) { languages := []string{"en", "es-ES", "fr-FR"} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDLanguagesDataSourceConfig(appIDTenantID, languages), + Config: setupIBMAppIDLanguagesDataSourceConfig(acc.AppIDTenantID, languages), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_languages.lang", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_languages.lang", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_languages.lang", "languages.#", "3"), resource.TestCheckResourceAttr("data.ibm_appid_languages.lang", "languages.0", "en"), resource.TestCheckResourceAttr("data.ibm_appid_languages.lang", "languages.1", "es-ES"), diff --git a/ibm/data_source_ibm_appid_mfa.go b/ibm/service/appid/data_source_ibm_appid_mfa.go similarity index 85% rename from ibm/data_source_ibm_appid_mfa.go rename to ibm/service/appid/data_source_ibm_appid_mfa.go index b84e00586..18e23dca6 100644 --- a/ibm/data_source_ibm_appid_mfa.go +++ b/ibm/service/appid/data_source_ibm_appid_mfa.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDMFA() *schema.Resource { +func DataSourceIBMAppIDMFA() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMAppIDMFARead, Schema: map[string]*schema.Schema{ @@ -26,7 +28,7 @@ func dataSourceIBMAppIDMFA() *schema.Resource { } func dataSourceIBMAppIDMFARead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_mfa_channel.go b/ibm/service/appid/data_source_ibm_appid_mfa_channel.go similarity index 92% rename from ibm/data_source_ibm_appid_mfa_channel.go rename to ibm/service/appid/data_source_ibm_appid_mfa_channel.go index 37e2c3174..edb15051d 100644 --- a/ibm/data_source_ibm_appid_mfa_channel.go +++ b/ibm/service/appid/data_source_ibm_appid_mfa_channel.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDMFAChannel() *schema.Resource { +func DataSourceIBMAppIDMFAChannel() *schema.Resource { return &schema.Resource{ Description: "Get MFA channel configuration", ReadContext: dataSourceIBMAppIDMFAChannelRead, @@ -54,7 +56,7 @@ func dataSourceIBMAppIDMFAChannel() *schema.Resource { } func dataSourceIBMAppIDMFAChannelRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_mfa_channel_test.go b/ibm/service/appid/data_source_ibm_appid_mfa_channel_test.go similarity index 82% rename from ibm/data_source_ibm_appid_mfa_channel_test.go rename to ibm/service/appid/data_source_ibm_appid_mfa_channel_test.go index 53f50753e..c9c7f1acf 100644 --- a/ibm/data_source_ibm_appid_mfa_channel_test.go +++ b/ibm/service/appid/data_source_ibm_appid_mfa_channel_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccAppIDMFAChannelDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMMFAChannelDataSourceConfig(appIDTenantID), + Config: setupIBMMFAChannelDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_mfa_channel.mf", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_mfa_channel.mf", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_mfa_channel.mf", "active", "sms"), resource.TestCheckResourceAttr("data.ibm_appid_mfa_channel.mf", "sms_config.#", "1"), resource.TestCheckResourceAttr("data.ibm_appid_mfa_channel.mf", "sms_config.0.key", "api_key"), diff --git a/ibm/service/appid/data_source_ibm_appid_mfa_test.go b/ibm/service/appid/data_source_ibm_appid_mfa_test.go new file mode 100644 index 000000000..281440237 --- /dev/null +++ b/ibm/service/appid/data_source_ibm_appid_mfa_test.go @@ -0,0 +1,41 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAppIDMFADataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupIBMMFADataSourceConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_appid_mfa.mf", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_mfa.mf", "is_active", "true"), + ), + }, + }, + }) +} + +func setupIBMMFADataSourceConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_mfa" "mf" { + tenant_id = "%s" + is_active = true + } + data "ibm_appid_mfa" "mf" { + tenant_id = ibm_appid_mfa.mf.tenant_id + depends_on = [ + ibm_appid_mfa.mf + ] + } + `, tenantID) +} diff --git a/ibm/data_source_ibm_appid_password_regex.go b/ibm/service/appid/data_source_ibm_appid_password_regex.go similarity index 90% rename from ibm/data_source_ibm_appid_password_regex.go rename to ibm/service/appid/data_source_ibm_appid_password_regex.go index 5baddbe56..e04a0a01f 100644 --- a/ibm/data_source_ibm_appid_password_regex.go +++ b/ibm/service/appid/data_source_ibm_appid_password_regex.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDPasswordRegex() *schema.Resource { +func DataSourceIBMAppIDPasswordRegex() *schema.Resource { return &schema.Resource{ Description: "The regular expression used by App ID for password strength validation", ReadContext: dataSourceIBMAppIDPasswordRegexRead, @@ -37,7 +39,7 @@ func dataSourceIBMAppIDPasswordRegex() *schema.Resource { } func dataSourceIBMAppIDPasswordRegexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_password_regex_test.go b/ibm/service/appid/data_source_ibm_appid_password_regex_test.go similarity index 78% rename from ibm/data_source_ibm_appid_password_regex_test.go rename to ibm/service/appid/data_source_ibm_appid_password_regex_test.go index c6633a91e..3a35b13b0 100644 --- a/ibm/data_source_ibm_appid_password_regex_test.go +++ b/ibm/service/appid/data_source_ibm_appid_password_regex_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDPasswordRegexDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupIBMAppIDPasswordRegexDataSourceConfig(appIDTenantID), + Config: setupIBMAppIDPasswordRegexDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_password_regex.rgx", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_password_regex.rgx", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_password_regex.rgx", "regex", "^(?:(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*)$"), resource.TestCheckResourceAttr("data.ibm_appid_password_regex.rgx", "error_message", "test error"), ), diff --git a/ibm/data_source_ibm_appid_redirect_urls.go b/ibm/service/appid/data_source_ibm_appid_redirect_urls.go similarity index 87% rename from ibm/data_source_ibm_appid_redirect_urls.go rename to ibm/service/appid/data_source_ibm_appid_redirect_urls.go index d95e32cad..66292a289 100644 --- a/ibm/data_source_ibm_appid_redirect_urls.go +++ b/ibm/service/appid/data_source_ibm_appid_redirect_urls.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDRedirectURLs() *schema.Resource { +func DataSourceIBMAppIDRedirectURLs() *schema.Resource { return &schema.Resource{ Description: "Redirect URIs that can be used as callbacks of App ID authentication flow", ReadContext: dataSourceIBMAppIDRedirectURLsRead, @@ -30,7 +32,7 @@ func dataSourceIBMAppIDRedirectURLs() *schema.Resource { } func dataSourceIBMAppIDRedirectURLsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_redirect_urls_test.go b/ibm/service/appid/data_source_ibm_appid_redirect_urls_test.go similarity index 82% rename from ibm/data_source_ibm_appid_redirect_urls_test.go rename to ibm/service/appid/data_source_ibm_appid_redirect_urls_test.go index 7a7e62327..c86739eec 100644 --- a/ibm/data_source_ibm_appid_redirect_urls_test.go +++ b/ibm/service/appid/data_source_ibm_appid_redirect_urls_test.go @@ -1,18 +1,21 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDRedirectURLsDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDRedirectURLsDataSourceConfig(appIDTenantID), + Config: testAccCheckIBMAppIDRedirectURLsDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_redirect_urls.urls", "urls.#", "3"), resource.TestCheckResourceAttr("data.ibm_appid_redirect_urls.urls", "urls.0", "https://test-url-1.com"), diff --git a/ibm/data_source_ibm_appid_role.go b/ibm/service/appid/data_source_ibm_appid_role.go similarity index 89% rename from ibm/data_source_ibm_appid_role.go rename to ibm/service/appid/data_source_ibm_appid_role.go index 9946c20a3..902f2b8e8 100644 --- a/ibm/data_source_ibm_appid_role.go +++ b/ibm/service/appid/data_source_ibm_appid_role.go @@ -1,14 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDRole() *schema.Resource { +func DataSourceIBMAppIDRole() *schema.Resource { return &schema.Resource{ Description: "A role is a collection of `scopes` that allow varying permissions to different types of app users", ReadContext: dataSourceIBMAppIDRoleRead, @@ -58,7 +61,7 @@ func dataSourceIBMAppIDRole() *schema.Resource { } func dataSourceIBMAppIDRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -96,7 +99,7 @@ func flattenAppIDRoleAccess(ra []appid.RoleAccessItem) []interface{} { for _, a := range ra { access := map[string]interface{}{ - "scopes": flattenStringList(a.Scopes), + "scopes": flex.FlattenStringList(a.Scopes), } if a.ApplicationID != nil { diff --git a/ibm/data_source_ibm_appid_role_test.go b/ibm/service/appid/data_source_ibm_appid_role_test.go similarity index 88% rename from ibm/data_source_ibm_appid_role_test.go rename to ibm/service/appid/data_source_ibm_appid_role_test.go index 4b3303541..b31847bc4 100644 --- a/ibm/data_source_ibm_appid_role_test.go +++ b/ibm/service/appid/data_source_ibm_appid_role_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,13 +16,13 @@ func TestAccIBMAppIDRoleDataSource_basic(t *testing.T) { description := "test role" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupRoleConfig(appIDTenantID, appName, roleName, description), + Config: setupRoleConfig(acc.AppIDTenantID, appName, roleName, description), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_role.role", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_role.role", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_role.role", "name", roleName), resource.TestCheckResourceAttr("data.ibm_appid_role.role", "description", description), resource.TestCheckResourceAttr("data.ibm_appid_role.role", "access.#", "1"), diff --git a/ibm/data_source_ibm_appid_roles.go b/ibm/service/appid/data_source_ibm_appid_roles.go similarity index 93% rename from ibm/data_source_ibm_appid_roles.go rename to ibm/service/appid/data_source_ibm_appid_roles.go index d8ac0726e..7f1ea4ac4 100644 --- a/ibm/data_source_ibm_appid_roles.go +++ b/ibm/service/appid/data_source_ibm_appid_roles.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + "sort" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "sort" ) -func dataSourceIBMAppIDRoles() *schema.Resource { +func DataSourceIBMAppIDRoles() *schema.Resource { return &schema.Resource{ Description: "A list of AppID roles", ReadContext: dataSourceIBMAppIDRolesRead, @@ -66,7 +68,7 @@ func dataSourceIBMAppIDRoles() *schema.Resource { } func dataSourceIBMAppIDRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_roles_test.go b/ibm/service/appid/data_source_ibm_appid_roles_test.go similarity index 88% rename from ibm/data_source_ibm_appid_roles_test.go rename to ibm/service/appid/data_source_ibm_appid_roles_test.go index 7d8b33495..38fe6018b 100644 --- a/ibm/data_source_ibm_appid_roles_test.go +++ b/ibm/service/appid/data_source_ibm_appid_roles_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -13,11 +15,11 @@ func TestAccIBMAppIDRolesDataSource_basic(t *testing.T) { roleName2 := fmt.Sprintf("tf_testacc_role_2_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDRolesConfig(appIDTenantID, roleName1, roleName2), + Config: setupAppIDRolesConfig(acc.AppIDTenantID, roleName1, roleName2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_roles.roles", "roles.#", "2"), resource.TestCheckResourceAttrSet("data.ibm_appid_roles.roles", "roles.0.role_id"), diff --git a/ibm/data_source_ibm_appid_theme_color.go b/ibm/service/appid/data_source_ibm_appid_theme_color.go similarity index 85% rename from ibm/data_source_ibm_appid_theme_color.go rename to ibm/service/appid/data_source_ibm_appid_theme_color.go index 7a23df4db..b62e8c90c 100644 --- a/ibm/data_source_ibm_appid_theme_color.go +++ b/ibm/service/appid/data_source_ibm_appid_theme_color.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDThemeColor() *schema.Resource { +func DataSourceIBMAppIDThemeColor() *schema.Resource { return &schema.Resource{ Description: "Colors of the App ID login widget", ReadContext: dataSourceIBMAppIDThemeColorRead, @@ -26,7 +28,7 @@ func dataSourceIBMAppIDThemeColor() *schema.Resource { } func dataSourceIBMAppIDThemeColorRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/data_source_ibm_appid_theme_color_test.go b/ibm/service/appid/data_source_ibm_appid_theme_color_test.go new file mode 100644 index 000000000..19b376154 --- /dev/null +++ b/ibm/service/appid/data_source_ibm_appid_theme_color_test.go @@ -0,0 +1,43 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccThemeColorDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupAppIDThemeColorDataSourceConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_appid_theme_color.color", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_theme_color.color", "header_color", "#000000"), + ), + }, + }, + }) +} + +func setupAppIDThemeColorDataSourceConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_theme_color" "color" { + tenant_id = "%s" + header_color = "#000000" + } + + data "ibm_appid_theme_color" "color" { + tenant_id = ibm_appid_theme_color.color.tenant_id + + depends_on = [ + ibm_appid_theme_color.color + ] + } + `, tenantID) +} diff --git a/ibm/data_source_ibm_appid_theme_text.go b/ibm/service/appid/data_source_ibm_appid_theme_text.go similarity index 87% rename from ibm/data_source_ibm_appid_theme_text.go rename to ibm/service/appid/data_source_ibm_appid_theme_text.go index 2b97116f4..b5597afe0 100644 --- a/ibm/data_source_ibm_appid_theme_text.go +++ b/ibm/service/appid/data_source_ibm_appid_theme_text.go @@ -1,13 +1,15 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDThemeText() *schema.Resource { +func DataSourceIBMAppIDThemeText() *schema.Resource { return &schema.Resource{ Description: "The theme texts of the App ID login widget", ReadContext: dataSourceIBMAppIDThemeTextRead, @@ -30,7 +32,7 @@ func dataSourceIBMAppIDThemeText() *schema.Resource { } func dataSourceIBMAppIDThemeTextRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_theme_text_test.go b/ibm/service/appid/data_source_ibm_appid_theme_text_test.go similarity index 77% rename from ibm/data_source_ibm_appid_theme_text_test.go rename to ibm/service/appid/data_source_ibm_appid_theme_text_test.go index d6cc27495..c857312cc 100644 --- a/ibm/data_source_ibm_appid_theme_text_test.go +++ b/ibm/service/appid/data_source_ibm_appid_theme_text_test.go @@ -1,20 +1,23 @@ -package ibm +package appid_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccThemeTextDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDThemeTextDataSourceConfig(appIDTenantID), + Config: setupAppIDThemeTextDataSourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_theme_text.text", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_theme_text.text", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_theme_text.text", "tab_title", "test title"), resource.TestCheckResourceAttr("data.ibm_appid_theme_text.text", "footnote", "test footnote"), ), diff --git a/ibm/data_source_ibm_appid_token_config.go b/ibm/service/appid/data_source_ibm_appid_token_config.go similarity index 96% rename from ibm/data_source_ibm_appid_token_config.go rename to ibm/service/appid/data_source_ibm_appid_token_config.go index 730a04124..c33cb2c00 100644 --- a/ibm/data_source_ibm_appid_token_config.go +++ b/ibm/service/appid/data_source_ibm_appid_token_config.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppIDTokenConfig() *schema.Resource { +func DataSourceIBMAppIDTokenConfig() *schema.Resource { return &schema.Resource{ Description: "`ibm_appid_token_config` data source can be used to retrieve the token configuration for specific AppID tenant. [Learn more.](https://cloud.ibm.com/docs/appid?topic=appid-customizing-tokens){target=_blank}", ReadContext: dataSourceIBMAppIDTokenConfigRead, @@ -115,7 +117,7 @@ func flattenTokenClaims(c []appid.TokenClaimMapping) []interface{} { } func dataSourceIBMAppIDTokenConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_token_config_test.go b/ibm/service/appid/data_source_ibm_appid_token_config_test.go similarity index 85% rename from ibm/data_source_ibm_appid_token_config_test.go rename to ibm/service/appid/data_source_ibm_appid_token_config_test.go index 07011f625..cab69fa7e 100644 --- a/ibm/data_source_ibm_appid_token_config_test.go +++ b/ibm/service/appid/data_source_ibm_appid_token_config_test.go @@ -1,26 +1,29 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/bluemix-go/helpers" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "gotest.tools/assert" - "testing" ) func TestAccIBMAppIDTokenConfigDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDTokenConfig(appIDTenantID), + Config: testAccCheckIBMAppIDTokenConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_appid_token_config.test_config", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("data.ibm_appid_token_config.test_config", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("data.ibm_appid_token_config.test_config", "access_token_expires_in", "7200"), resource.TestCheckResourceAttr("data.ibm_appid_token_config.test_config", "anonymous_access_enabled", "false"), resource.TestCheckResourceAttr("data.ibm_appid_token_config.test_config", "anonymous_token_expires_in", "7200"), @@ -63,7 +66,27 @@ func TestFlattenTokenClaims(t *testing.T) { assert.DeepEqual(t, actual, c.expected) } } +func flattenTokenClaims(c []appid.TokenClaimMapping) []interface{} { + var s []interface{} + for _, v := range c { + claim := map[string]interface{}{ + "source": *v.Source, + } + + if v.SourceClaim != nil { + claim["source_claim"] = *v.SourceClaim + } + + if v.DestinationClaim != nil { + claim["destination_claim"] = *v.DestinationClaim + } + + s = append(s, claim) + } + + return s +} func testAccCheckIBMAppIDTokenConfig(tenantID string) string { return fmt.Sprintf(` resource "ibm_appid_token_config" "test_config" { diff --git a/ibm/data_source_ibm_appid_user_roles.go b/ibm/service/appid/data_source_ibm_appid_user_roles.go similarity index 92% rename from ibm/data_source_ibm_appid_user_roles.go rename to ibm/service/appid/data_source_ibm_appid_user_roles.go index 135e119aa..9775967ab 100644 --- a/ibm/data_source_ibm_appid_user_roles.go +++ b/ibm/service/appid/data_source_ibm_appid_user_roles.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func dataSourceIBMAppIDUserRoles() *schema.Resource { +func DataSourceIBMAppIDUserRoles() *schema.Resource { return &schema.Resource{ Description: "Get a list of AppID user roles", ReadContext: dataSourceIBMAppIDUserRolesRead, @@ -48,7 +50,7 @@ func dataSourceIBMAppIDUserRoles() *schema.Resource { } func dataSourceIBMAppIDUserRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/data_source_ibm_appid_user_roles_test.go b/ibm/service/appid/data_source_ibm_appid_user_roles_test.go similarity index 86% rename from ibm/data_source_ibm_appid_user_roles_test.go rename to ibm/service/appid/data_source_ibm_appid_user_roles_test.go index 9b4e45f70..9e6526a75 100644 --- a/ibm/data_source_ibm_appid_user_roles_test.go +++ b/ibm/service/appid/data_source_ibm_appid_user_roles_test.go @@ -1,9 +1,11 @@ -package ibm +package appid_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -12,11 +14,11 @@ func TestAccIBMAppIDUserRolesRolesDataSource_basic(t *testing.T) { roleName := fmt.Sprintf("tf_testacc_role_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDUserRolesDataSourceConfig(appIDTenantID, roleName, appIDTestUserEmail), + Config: setupAppIDUserRolesDataSourceConfig(acc.AppIDTenantID, roleName, acc.AppIDTestUserEmail), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_appid_user_roles.roles", "roles.#", "1"), resource.TestCheckResourceAttrPair("data.ibm_appid_user_roles.roles", "roles.0.id", "ibm_appid_role.role", "role_id"), diff --git a/ibm/resource_ibm_appid_action_url.go b/ibm/service/appid/resource_ibm_appid_action_url.go similarity index 92% rename from ibm/resource_ibm_appid_action_url.go rename to ibm/service/appid/resource_ibm_appid_action_url.go index ac894ceb0..cf2328292 100644 --- a/ibm/resource_ibm_appid_action_url.go +++ b/ibm/service/appid/resource_ibm_appid_action_url.go @@ -1,17 +1,19 @@ -package ibm +package appid import ( "context" "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" - "strings" ) -func resourceIBMAppIDActionURL() *schema.Resource { +func ResourceIBMAppIDActionURL() *schema.Resource { return &schema.Resource{ Description: "The custom url to redirect to when Cloud Directory action is executed.", CreateContext: resourceIBMAppIDActionURLCreate, @@ -45,7 +47,7 @@ func resourceIBMAppIDActionURL() *schema.Resource { } func resourceIBMAppIDActionURLRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -87,7 +89,7 @@ func resourceIBMAppIDActionURLRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDActionURLCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -115,7 +117,7 @@ func resourceIBMAppIDActionURLCreate(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDActionURLDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_action_url_test.go b/ibm/service/appid/resource_ibm_appid_action_url_test.go similarity index 76% rename from ibm/resource_ibm_appid_action_url_test.go rename to ibm/service/appid/resource_ibm_appid_action_url_test.go index 62aca9fa0..af1409b49 100644 --- a/ibm/resource_ibm_appid_action_url_test.go +++ b/ibm/service/appid/resource_ibm_appid_action_url_test.go @@ -1,24 +1,28 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDActionURL_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDActionURLDestroy, Steps: []resource.TestStep{ { - Config: setupAppIDActionURLConfig(appIDTenantID), + Config: setupAppIDActionURLConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_action_url.url", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_action_url.url", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_action_url.url", "action", "on_reset_password"), resource.TestCheckResourceAttr("ibm_appid_action_url.url", "url", "https://www.example.com/psw-reset"), ), @@ -38,7 +42,7 @@ func setupAppIDActionURLConfig(tenantID string) string { } func testAccCheckIBMAppIDActionURLDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -62,7 +66,7 @@ func testAccCheckIBMAppIDActionURLDestroy(s *terraform.State) error { // when action URL is deleted it is returned as an empty string e.g. `{ actionUrl: "" }` if err != nil || (cfg.ActionURL != nil && *cfg.ActionURL != "") { - return fmt.Errorf("error checking if AppID action URL (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID action URL (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_apm.go b/ibm/service/appid/resource_ibm_appid_apm.go similarity index 97% rename from ibm/resource_ibm_appid_apm.go rename to ibm/service/appid/resource_ibm_appid_apm.go index 51e4a0354..9882a0a8c 100644 --- a/ibm/resource_ibm_appid_apm.go +++ b/ibm/service/appid/resource_ibm_appid_apm.go @@ -1,16 +1,18 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDAPM() *schema.Resource { +func ResourceIBMAppIDAPM() *schema.Resource { return &schema.Resource{ Description: "AppID advanced password management configuration (available for graduated tier only)", ReadContext: resourceIBMAppIDAPMRead, @@ -119,7 +121,7 @@ func resourceIBMAppIDAPM() *schema.Resource { } func resourceIBMAppIDAPMRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -170,7 +172,7 @@ func resourceIBMAppIDAPMRead(ctx context.Context, d *schema.ResourceData, meta i } func resourceIBMAppIDAPMCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -273,7 +275,7 @@ func expandAppIDAPMMinPasswordChangeInterval(chg []interface{}) *appid.ApmSchema } func resourceIBMAppIDAPMDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_apm_test.go b/ibm/service/appid/resource_ibm_appid_apm_test.go similarity index 87% rename from ibm/resource_ibm_appid_apm_test.go rename to ibm/service/appid/resource_ibm_appid_apm_test.go index 113f928fe..96d48bccc 100644 --- a/ibm/resource_ibm_appid_apm_test.go +++ b/ibm/service/appid/resource_ibm_appid_apm_test.go @@ -1,26 +1,30 @@ -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/bluemix-go/helpers" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/IBM/go-sdk-core/v5/core" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMAppIDAPM_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDAPMDestroy, Steps: []resource.TestStep{ { - Config: setupIBMAppIDAPMResourceConfig(appIDTenantID), + Config: setupIBMAppIDAPMResourceConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_apm.apm", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_apm.apm", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_apm.apm", "enabled", "true"), resource.TestCheckResourceAttr("ibm_appid_apm.apm", "prevent_password_with_username", "true"), resource.TestCheckResourceAttr("ibm_appid_apm.apm", "password_reuse.0.enabled", "true"), @@ -70,7 +74,7 @@ func setupIBMAppIDAPMResourceConfig(tenantID string) string { } func testAccCheckIBMAppIDAPMDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -88,7 +92,7 @@ func testAccCheckIBMAppIDAPMDestroy(s *terraform.State) error { }) if err != nil { - return fmt.Errorf("Error checking if AppID APM configuration was reset: %s", err) + return fmt.Errorf("[ERROR] Error checking if AppID APM configuration was reset: %s", err) } // verify that configuration is reset to defaults @@ -127,7 +131,7 @@ func testAccCheckIBMAppIDAPMDestroy(s *terraform.State) error { diff := cmp.Diff(config.AdvancedPasswordManagement, defaults) if config == nil || diff != "" { - return fmt.Errorf("Error checking if AppID APM configuration was reset: %s", diff) + return fmt.Errorf("[ERROR] Error checking if AppID APM configuration was reset: %s", diff) } } diff --git a/ibm/resource_ibm_appid_application.go b/ibm/service/appid/resource_ibm_appid_application.go similarity index 93% rename from ibm/resource_ibm_appid_application.go rename to ibm/service/appid/resource_ibm_appid_application.go index ed24bc215..a7be3fd13 100644 --- a/ibm/resource_ibm_appid_application.go +++ b/ibm/service/appid/resource_ibm_appid_application.go @@ -1,17 +1,19 @@ -package ibm +package appid import ( "context" "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" - "strings" ) -func resourceIBMAppIDApplication() *schema.Resource { +func ResourceIBMAppIDApplication() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDApplicationCreate, ReadContext: resourceIBMAppIDApplicationRead, @@ -71,7 +73,7 @@ func resourceIBMAppIDApplication() *schema.Resource { } func resourceIBMAppIDApplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -99,7 +101,7 @@ func resourceIBMAppIDApplicationCreate(ctx context.Context, d *schema.ResourceDa } func resourceIBMAppIDApplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -162,7 +164,7 @@ func resourceIBMAppIDApplicationRead(ctx context.Context, d *schema.ResourceData func resourceIBMAppIDApplicationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { if d.HasChange("name") { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -187,7 +189,7 @@ func resourceIBMAppIDApplicationUpdate(ctx context.Context, d *schema.ResourceDa } func resourceIBMAppIDApplicationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_application_roles.go b/ibm/service/appid/resource_ibm_appid_application_roles.go similarity index 88% rename from ibm/resource_ibm_appid_application_roles.go rename to ibm/service/appid/resource_ibm_appid_application_roles.go index 39018838d..a1d93d9ac 100644 --- a/ibm/resource_ibm_appid_application_roles.go +++ b/ibm/service/appid/resource_ibm_appid_application_roles.go @@ -1,16 +1,19 @@ -package ibm +package appid import ( "context" "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" - "strings" ) -func resourceIBMAppIDApplicationRoles() *schema.Resource { +func ResourceIBMAppIDApplicationRoles() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDApplicationRolesCreate, ReadContext: resourceIBMAppIDApplicationRolesRead, @@ -45,7 +48,7 @@ func resourceIBMAppIDApplicationRoles() *schema.Resource { } func resourceIBMAppIDApplicationRolesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -53,7 +56,7 @@ func resourceIBMAppIDApplicationRolesCreate(ctx context.Context, d *schema.Resou tenantID := d.Get("tenant_id").(string) clientID := d.Get("client_id").(string) - roles := expandStringList(d.Get("roles").([]interface{})) + roles := flex.ExpandStringList(d.Get("roles").([]interface{})) roleOpts := &appid.PutApplicationsRolesOptions{ TenantID: &tenantID, @@ -75,7 +78,7 @@ func resourceIBMAppIDApplicationRolesCreate(ctx context.Context, d *schema.Resou } func resourceIBMAppIDApplicationRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -125,7 +128,7 @@ func resourceIBMAppIDApplicationRolesRead(ctx context.Context, d *schema.Resourc } func resourceIBMAppIDApplicationRolesUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -133,7 +136,7 @@ func resourceIBMAppIDApplicationRolesUpdate(ctx context.Context, d *schema.Resou tenantID := d.Get("tenant_id").(string) clientID := d.Get("client_id").(string) - roles := expandStringList(d.Get("roles").([]interface{})) + roles := flex.ExpandStringList(d.Get("roles").([]interface{})) roleOpts := &appid.PutApplicationsRolesOptions{ TenantID: &tenantID, @@ -153,7 +156,7 @@ func resourceIBMAppIDApplicationRolesUpdate(ctx context.Context, d *schema.Resou } func resourceIBMAppIDApplicationRolesDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_application_roles_test.go b/ibm/service/appid/resource_ibm_appid_application_roles_test.go similarity index 79% rename from ibm/resource_ibm_appid_application_roles_test.go rename to ibm/service/appid/resource_ibm_appid_application_roles_test.go index d31bc212f..a0c157a7a 100644 --- a/ibm/resource_ibm_appid_application_roles_test.go +++ b/ibm/service/appid/resource_ibm_appid_application_roles_test.go @@ -1,13 +1,17 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDApplicationRoles_basic(t *testing.T) { @@ -15,12 +19,12 @@ func TestAccIBMAppIDApplicationRoles_basic(t *testing.T) { roleName := fmt.Sprintf("tf_testacc_app_roles_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDApplicationRolesDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationRolesConfig(appIDTenantID, appName, roleName), + Config: testAccCheckIBMAppIDApplicationRolesConfig(acc.AppIDTenantID, appName, roleName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_appid_application_roles.roles", "roles.#", "1"), resource.TestCheckResourceAttrPair("ibm_appid_role.role", "role_id", "ibm_appid_application_roles.roles", "roles.0"), @@ -51,7 +55,7 @@ func testAccCheckIBMAppIDApplicationRolesConfig(tenantID string, appName string, } func testAccCheckIBMAppIDApplicationRolesDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -74,7 +78,7 @@ func testAccCheckIBMAppIDApplicationRolesDestroy(s *terraform.State) error { }) if err == nil { - return fmt.Errorf("error checking if AppID application roles resource (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID application roles resource (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_application_scopes.go b/ibm/service/appid/resource_ibm_appid_application_scopes.go similarity index 88% rename from ibm/resource_ibm_appid_application_scopes.go rename to ibm/service/appid/resource_ibm_appid_application_scopes.go index 560570cb7..c951f3792 100644 --- a/ibm/resource_ibm_appid_application_scopes.go +++ b/ibm/service/appid/resource_ibm_appid_application_scopes.go @@ -1,16 +1,19 @@ -package ibm +package appid import ( "context" "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" - "strings" ) -func resourceIBMAppIDApplicationScopes() *schema.Resource { +func ResourceIBMAppIDApplicationScopes() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDApplicationScopesCreate, ReadContext: resourceIBMAppIDApplicationScopesRead, @@ -45,7 +48,7 @@ func resourceIBMAppIDApplicationScopes() *schema.Resource { } func resourceIBMAppIDApplicationScopesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -53,7 +56,7 @@ func resourceIBMAppIDApplicationScopesCreate(ctx context.Context, d *schema.Reso tenantID := d.Get("tenant_id").(string) clientID := d.Get("client_id").(string) - scopes := expandStringList(d.Get("scopes").([]interface{})) + scopes := flex.ExpandStringList(d.Get("scopes").([]interface{})) scopeOpts := &appid.PutApplicationsScopesOptions{ TenantID: &tenantID, @@ -73,7 +76,7 @@ func resourceIBMAppIDApplicationScopesCreate(ctx context.Context, d *schema.Reso } func resourceIBMAppIDApplicationScopesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -115,7 +118,7 @@ func resourceIBMAppIDApplicationScopesRead(ctx context.Context, d *schema.Resour } func resourceIBMAppIDApplicationScopesUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -123,7 +126,7 @@ func resourceIBMAppIDApplicationScopesUpdate(ctx context.Context, d *schema.Reso tenantID := d.Get("tenant_id").(string) clientID := d.Get("client_id").(string) - scopes := expandStringList(d.Get("scopes").([]interface{})) + scopes := flex.ExpandStringList(d.Get("scopes").([]interface{})) scopeOpts := &appid.PutApplicationsScopesOptions{ TenantID: &tenantID, @@ -141,7 +144,7 @@ func resourceIBMAppIDApplicationScopesUpdate(ctx context.Context, d *schema.Reso } func resourceIBMAppIDApplicationScopesDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_application_scopes_test.go b/ibm/service/appid/resource_ibm_appid_application_scopes_test.go similarity index 79% rename from ibm/resource_ibm_appid_application_scopes_test.go rename to ibm/service/appid/resource_ibm_appid_application_scopes_test.go index 7149e94ce..0f0f65d58 100644 --- a/ibm/resource_ibm_appid_application_scopes_test.go +++ b/ibm/service/appid/resource_ibm_appid_application_scopes_test.go @@ -1,25 +1,29 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDApplicationScopes_basic(t *testing.T) { appName := fmt.Sprintf("tf_testacc_app_scopes_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDApplicationScopesDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationScopesConfig(appIDTenantID, appName), + Config: testAccCheckIBMAppIDApplicationScopesConfig(acc.AppIDTenantID, appName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_appid_application_scopes.scopes", "scopes.#", "3"), resource.TestCheckResourceAttr("ibm_appid_application_scopes.scopes", "scopes.0", "scope1"), @@ -47,7 +51,7 @@ func testAccCheckIBMAppIDApplicationScopesConfig(tenantID string, name string) s } func testAccCheckIBMAppIDApplicationScopesDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -70,7 +74,7 @@ func testAccCheckIBMAppIDApplicationScopesDestroy(s *terraform.State) error { }) if err == nil { - return fmt.Errorf("error checking if AppID application scopes resource (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID application scopes resource (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_application_test.go b/ibm/service/appid/resource_ibm_appid_application_test.go similarity index 75% rename from ibm/resource_ibm_appid_application_test.go rename to ibm/service/appid/resource_ibm_appid_application_test.go index 13fa1a696..88abea5e6 100644 --- a/ibm/resource_ibm_appid_application_test.go +++ b/ibm/service/appid/resource_ibm_appid_application_test.go @@ -1,27 +1,31 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDApplication_basic(t *testing.T) { appName := fmt.Sprintf("tf_testacc_app_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDApplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDApplicationConfig(appIDTenantID, appName), + Config: testAccCheckIBMAppIDApplicationConfig(acc.AppIDTenantID, appName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_application.test_app", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_application.test_app", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_application.test_app", "name", appName), resource.TestCheckResourceAttr("ibm_appid_application.test_app", "type", "regularwebapp"), resource.TestCheckResourceAttrSet("ibm_appid_application.test_app", "client_id"), @@ -41,7 +45,7 @@ func testAccCheckIBMAppIDApplicationConfig(tenantID string, name string) string } func testAccCheckIBMAppIDApplicationDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -64,7 +68,7 @@ func testAccCheckIBMAppIDApplicationDestroy(s *terraform.State) error { }) if err == nil { - return fmt.Errorf("error checking if AppID application (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID application (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_audit_status.go b/ibm/service/appid/resource_ibm_appid_audit_status.go similarity index 90% rename from ibm/resource_ibm_appid_audit_status.go rename to ibm/service/appid/resource_ibm_appid_audit_status.go index f9979614a..9c7554950 100644 --- a/ibm/resource_ibm_appid_audit_status.go +++ b/ibm/service/appid/resource_ibm_appid_audit_status.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDAuditStatus() *schema.Resource { +func ResourceIBMAppIDAuditStatus() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDAuditStatusCreate, ReadContext: resourceIBMAppIDAuditStatusRead, @@ -35,7 +37,7 @@ func resourceIBMAppIDAuditStatus() *schema.Resource { } func resourceIBMAppIDAuditStatusRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -64,7 +66,7 @@ func resourceIBMAppIDAuditStatusRead(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDAuditStatusCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -93,7 +95,7 @@ func resourceIBMAppIDAuditStatusCreate(ctx context.Context, d *schema.ResourceDa } func resourceIBMAppIDAuditStatusDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_audit_status_test.go b/ibm/service/appid/resource_ibm_appid_audit_status_test.go new file mode 100644 index 000000000..ce69e9aa0 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_audit_status_test.go @@ -0,0 +1,66 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMAppIDAuditStatus_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDAuditStatusDestroy, + Steps: []resource.TestStep{ + { + Config: setupAppIDAuditStatusConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_audit_status.status", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_audit_status.status", "is_active", "true"), + ), + }, + }, + }) +} + +func testAccCheckIBMAppIDAuditStatusDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_audit_status" { + continue + } + + tenantID := rs.Primary.ID + + cfg, _, err := appIDClient.GetAuditStatus(&appid.GetAuditStatusOptions{ + TenantID: &tenantID, + }) + + // default for audit status is `false` + if err != nil || (cfg.IsActive != nil && *cfg.IsActive != false) { + return fmt.Errorf("[ERROR] Error checking if AppID audit status (%s) has been destroyed", rs.Primary.ID) + } + } + + return nil +} + +func setupAppIDAuditStatusConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_audit_status" "status" { + tenant_id = "%s" + is_active = true + } + `, tenantID) +} diff --git a/ibm/resource_ibm_appid_cloud_directory_template.go b/ibm/service/appid/resource_ibm_appid_cloud_directory_template.go similarity index 94% rename from ibm/resource_ibm_appid_cloud_directory_template.go rename to ibm/service/appid/resource_ibm_appid_cloud_directory_template.go index 2cf73a47e..b4ac7b4ce 100644 --- a/ibm/resource_ibm_appid_cloud_directory_template.go +++ b/ibm/service/appid/resource_ibm_appid_cloud_directory_template.go @@ -1,19 +1,21 @@ -package ibm +package appid import ( "context" b64 "encoding/base64" "fmt" + "log" + "strings" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" - "strings" ) -func resourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { +func ResourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDCloudDirectoryTemplateCreate, ReadContext: resourceIBMAppIDCloudDirectoryTemplateRead, @@ -68,7 +70,7 @@ func resourceIBMAppIDCloudDirectoryTemplate() *schema.Resource { } func resourceIBMAppIDCloudDirectoryTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -125,7 +127,7 @@ func resourceIBMAppIDCloudDirectoryTemplateRead(ctx context.Context, d *schema.R } func resourceIBMAppIDCloudDirectoryTemplateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -163,7 +165,7 @@ func resourceIBMAppIDCloudDirectoryTemplateCreate(ctx context.Context, d *schema } func resourceIBMAppIDCloudDirectoryTemplateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_cloud_directory_template_test.go b/ibm/service/appid/resource_ibm_appid_cloud_directory_template_test.go similarity index 83% rename from ibm/resource_ibm_appid_cloud_directory_template_test.go rename to ibm/service/appid/resource_ibm_appid_cloud_directory_template_test.go index bda56af6b..341bdbb69 100644 --- a/ibm/resource_ibm_appid_cloud_directory_template_test.go +++ b/ibm/service/appid/resource_ibm_appid_cloud_directory_template_test.go @@ -1,11 +1,14 @@ -package ibm +package appid_test import ( b64 "encoding/base64" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "strings" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppIDCloudDirectoryTemplate_basic(t *testing.T) { @@ -15,13 +18,13 @@ func TestAccIBMAppIDCloudDirectoryTemplate_basic(t *testing.T) { subject := "Please Verify Your Email Address %%{user.displayName} TEST" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: setupAppIDCloudDirectoryTemplateConfig(appIDTenantID, subject, htmlBody, textBody), + Config: setupAppIDCloudDirectoryTemplateConfig(acc.AppIDTenantID, subject, htmlBody, textBody), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_cloud_directory_template.test_tpl", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_cloud_directory_template.test_tpl", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_template.test_tpl", "template_name", "USER_VERIFICATION"), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_template.test_tpl", "subject", strings.Replace(subject, "%%", "%", 1)), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_template.test_tpl", "html_body", htmlBody), diff --git a/ibm/resource_ibm_appid_cloud_directory_user.go b/ibm/service/appid/resource_ibm_appid_cloud_directory_user.go similarity index 96% rename from ibm/resource_ibm_appid_cloud_directory_user.go rename to ibm/service/appid/resource_ibm_appid_cloud_directory_user.go index 7970a75f6..4cebe6e62 100644 --- a/ibm/resource_ibm_appid_cloud_directory_user.go +++ b/ibm/service/appid/resource_ibm_appid_cloud_directory_user.go @@ -1,4 +1,4 @@ -package ibm +package appid import ( "context" @@ -7,6 +7,7 @@ import ( "strings" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -14,7 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func resourceIBMAppIDCloudDirectoryUser() *schema.Resource { +func ResourceIBMAppIDCloudDirectoryUser() *schema.Resource { return &schema.Resource{ Description: "Manage AppID Cloud Directory user", CreateContext: resourceIBMAppIDCloudDirectoryUserCreate, @@ -126,7 +127,7 @@ func resourceIBMAppIDCloudDirectoryUser() *schema.Resource { } func resourceIBMAppIDCloudDirectoryUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -209,7 +210,7 @@ func resourceIBMAppIDCloudDirectoryUserRead(ctx context.Context, d *schema.Resou } func resourceIBMAppIDCloudDirectoryUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -250,7 +251,7 @@ func resourceIBMAppIDCloudDirectoryUserCreate(ctx context.Context, d *schema.Res } func resourceIBMAppIDCloudDirectoryUserDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -273,7 +274,7 @@ func resourceIBMAppIDCloudDirectoryUserDelete(ctx context.Context, d *schema.Res } func resourceIBMAppIDCloudDirectoryUserUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_cloud_directory_user_test.go b/ibm/service/appid/resource_ibm_appid_cloud_directory_user_test.go similarity index 80% rename from ibm/resource_ibm_appid_cloud_directory_user_test.go rename to ibm/service/appid/resource_ibm_appid_cloud_directory_user_test.go index 4a20265c0..effb3fc98 100644 --- a/ibm/resource_ibm_appid_cloud_directory_user_test.go +++ b/ibm/service/appid/resource_ibm_appid_cloud_directory_user_test.go @@ -1,15 +1,20 @@ -package ibm +package appid_test import ( "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "strconv" "strings" "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestAccIBMAppIDCloudDirectoryUser_basic(t *testing.T) { @@ -17,12 +22,12 @@ func TestAccIBMAppIDCloudDirectoryUser_basic(t *testing.T) { lockedUntil := time.Now().Add(time.Hour*2).UnixNano() / int64(time.Millisecond) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDCloudDirectoryUserDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDCloudDirectoryUserConfig(appIDTenantID, userName, appIDTestUserEmail, lockedUntil), + Config: testAccCheckIBMAppIDCloudDirectoryUserConfig(acc.AppIDTenantID, userName, acc.AppIDTestUserEmail, lockedUntil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "active", "false"), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "locked_until", strconv.Itoa(int(lockedUntil))), @@ -31,7 +36,7 @@ func TestAccIBMAppIDCloudDirectoryUser_basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "display_name", "Test TF User"), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "status", "PENDING"), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "email.#", "1"), - resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "email.0.value", appIDTestUserEmail), + resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "email.0.value", acc.AppIDTestUserEmail), resource.TestCheckResourceAttr("ibm_appid_cloud_directory_user.user", "email.0.primary", "true"), ), }, @@ -61,7 +66,7 @@ func testAccCheckIBMAppIDCloudDirectoryUserConfig(tenantID, userName, email stri } func testAccCheckIBMAppIDCloudDirectoryUserDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -84,7 +89,7 @@ func testAccCheckIBMAppIDCloudDirectoryUserDestroy(s *terraform.State) error { }) if err == nil { - return fmt.Errorf("error checking if AppID Cloud Directory user (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID Cloud Directory user (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_idp_cloud_directory.go b/ibm/service/appid/resource_ibm_appid_idp_cloud_directory.go similarity index 93% rename from ibm/resource_ibm_appid_idp_cloud_directory.go rename to ibm/service/appid/resource_ibm_appid_idp_cloud_directory.go index 89306da6e..91c969cee 100644 --- a/ibm/resource_ibm_appid_idp_cloud_directory.go +++ b/ibm/service/appid/resource_ibm_appid_idp_cloud_directory.go @@ -1,16 +1,19 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" ) -func resourceIBMAppIDIDPCloudDirectory() *schema.Resource { +func ResourceIBMAppIDIDPCloudDirectory() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDIDPCloudDirectoryCreate, ReadContext: resourceIBMAppIDIDPCloudDirectoryRead, @@ -76,7 +79,7 @@ func resourceIBMAppIDIDPCloudDirectory() *schema.Resource { } func resourceIBMAppIDIDPCloudDirectoryRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -129,7 +132,7 @@ func resourceIBMAppIDIDPCloudDirectoryRead(ctx context.Context, d *schema.Resour } func resourceIBMAppIDIDPCloudDirectoryCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -160,7 +163,7 @@ func resourceIBMAppIDIDPCloudDirectoryCreate(ctx context.Context, d *schema.Reso } if methods, ok := d.GetOk("identity_confirm_methods"); ok { - config.Config.Interactions.IdentityConfirmation.Methods = expandStringList(methods.([]interface{})) + config.Config.Interactions.IdentityConfirmation.Methods = flex.ExpandStringList(methods.([]interface{})) } _, resp, err := appIDClient.SetCloudDirectoryIDPWithContext(ctx, config) @@ -180,7 +183,7 @@ func resourceIBMAppIDIDPCloudDirectoryUpdate(ctx context.Context, d *schema.Reso } func resourceIBMAppIDIDPCloudDirectoryDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_idp_cloud_directory_test.go b/ibm/service/appid/resource_ibm_appid_idp_cloud_directory_test.go similarity index 84% rename from ibm/resource_ibm_appid_idp_cloud_directory_test.go rename to ibm/service/appid/resource_ibm_appid_idp_cloud_directory_test.go index e3b510419..eed0044a6 100644 --- a/ibm/resource_ibm_appid_idp_cloud_directory_test.go +++ b/ibm/service/appid/resource_ibm_appid_idp_cloud_directory_test.go @@ -1,25 +1,29 @@ -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/bluemix-go/helpers" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMAppIDIDPCloudDirectory_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDIDPCloudDirectoryDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDIDPCloudDirectoryConfig(appIDTenantID), + Config: testAccCheckIBMAppIDIDPCloudDirectoryConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_idp_cloud_directory.idp", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_idp_cloud_directory.idp", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_idp_cloud_directory.idp", "is_active", "true"), resource.TestCheckResourceAttr("ibm_appid_idp_cloud_directory.idp", "self_service_enabled", "false"), resource.TestCheckResourceAttr("ibm_appid_idp_cloud_directory.idp", "signup_enabled", "false"), @@ -55,7 +59,7 @@ func testAccCheckIBMAppIDIDPCloudDirectoryConfig(tenantID string) string { } func testAccCheckIBMAppIDIDPCloudDirectoryDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -73,7 +77,7 @@ func testAccCheckIBMAppIDIDPCloudDirectoryDestroy(s *terraform.State) error { }) if err != nil { - return fmt.Errorf("Error checking if AppID IDP Cloud Directory configuration was reset: %s", err) + return fmt.Errorf("[ERROR] Error checking if AppID IDP Cloud Directory configuration was reset: %s", err) } // verify that configuration is reset to defaults @@ -102,7 +106,7 @@ func testAccCheckIBMAppIDIDPCloudDirectoryDestroy(s *terraform.State) error { }, defaults) if config == nil || diff != "" { - return fmt.Errorf("Error checking if AppID IDP Cloud Directory configuration was reset: %s", diff) + return fmt.Errorf("[ERROR] Error checking if AppID IDP Cloud Directory configuration was reset: %s", diff) } } diff --git a/ibm/resource_ibm_appid_idp_custom.go b/ibm/service/appid/resource_ibm_appid_idp_custom.go similarity index 92% rename from ibm/resource_ibm_appid_idp_custom.go rename to ibm/service/appid/resource_ibm_appid_idp_custom.go index 06cde441e..348dc99ae 100644 --- a/ibm/resource_ibm_appid_idp_custom.go +++ b/ibm/service/appid/resource_ibm_appid_idp_custom.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDIDPCustom() *schema.Resource { +func ResourceIBMAppIDIDPCustom() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDIDPCustomCreate, ReadContext: resourceIBMAppIDIDPCustomRead, @@ -39,7 +41,7 @@ func resourceIBMAppIDIDPCustom() *schema.Resource { } func resourceIBMAppIDIDPCustomRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -75,7 +77,7 @@ func resourceIBMAppIDIDPCustomRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDIDPCustomCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -116,7 +118,7 @@ func appIDCustomIDPDefaults(tenantID string) *appid.SetCustomIDPOptions { } func resourceIBMAppIDIDPCustomDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_idp_custom_test.go b/ibm/service/appid/resource_ibm_appid_idp_custom_test.go similarity index 78% rename from ibm/resource_ibm_appid_idp_custom_test.go rename to ibm/service/appid/resource_ibm_appid_idp_custom_test.go index 073701b42..a6a3153d3 100644 --- a/ibm/resource_ibm_appid_idp_custom_test.go +++ b/ibm/service/appid/resource_ibm_appid_idp_custom_test.go @@ -1,26 +1,30 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDIDPCustom_basic(t *testing.T) { publicKey := `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzb19EC2vJfTLaJTs3/4F\ndmoHnpYHJo4Q5SJYJK2YfclwRJc49zs1juoNGvXsUOsEi58PHarot3aAUpzBk8g9\n1RdDoovQDKBhMbT7BXP291qp5WQsvrv5W6xPoTbNONYPmAWTN75e3AvvvQElgv9N\n4BBkXZ962bf/OM1Ccm786laop9fC03D7vmUUypISPMZ61O6aA3dRI2JSvHh+VL4s\nEtXkZvLR7DvvWl4sl4oA5EvpYqw5/qbXTp4bnllfiQuCuwgYz/MH1mQA4qGWEVTN\nE4z3b0jsHNHVAzsPfB3Bnok/Zvgtxc3cjVlm3el+bie9O3vW1jFQf1JCke/qusj7\neQIDAQAB\n-----END PUBLIC KEY-----\n` resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDIDPCustomDestroy, Steps: []resource.TestStep{ { - Config: setupAppIDCustomIDPConfig(appIDTenantID, publicKey), + Config: setupAppIDCustomIDPConfig(acc.AppIDTenantID, publicKey), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_idp_custom.idp", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_idp_custom.idp", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_idp_custom.idp", "is_active", "true"), resource.TestCheckResourceAttr("ibm_appid_idp_custom.idp", "public_key", strings.Replace(publicKey, "\\n", "\n", -1)), ), @@ -40,7 +44,7 @@ func setupAppIDCustomIDPConfig(tenantID string, publicKey string) string { } func testAccCheckIBMAppIDIDPCustomDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -58,7 +62,7 @@ func testAccCheckIBMAppIDIDPCustomDestroy(s *terraform.State) error { }) if err != nil || (cfg.IsActive != nil && *cfg.IsActive != false) { - return fmt.Errorf("error checking if AppID custom IDP configuration (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID custom IDP configuration (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_idp_facebook.go b/ibm/service/appid/resource_ibm_appid_idp_facebook.go similarity index 94% rename from ibm/resource_ibm_appid_idp_facebook.go rename to ibm/service/appid/resource_ibm_appid_idp_facebook.go index d4d8d0bdb..409ee60c8 100644 --- a/ibm/resource_ibm_appid_idp_facebook.go +++ b/ibm/service/appid/resource_ibm_appid_idp_facebook.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDIDPFacebook() *schema.Resource { +func ResourceIBMAppIDIDPFacebook() *schema.Resource { return &schema.Resource{ Description: "Update Facebook identity provider configuration.", CreateContext: resourceIBMAppIDIDPFacebookCreate, @@ -62,7 +64,7 @@ func resourceIBMAppIDIDPFacebook() *schema.Resource { } func resourceIBMAppIDIDPFacebookRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -102,7 +104,7 @@ func resourceIBMAppIDIDPFacebookRead(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDIDPFacebookCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -134,7 +136,7 @@ func resourceIBMAppIDIDPFacebookCreate(ctx context.Context, d *schema.ResourceDa } func resourceIBMAppIDIDPFacebookDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_idp_facebook_test.go b/ibm/service/appid/resource_ibm_appid_idp_facebook_test.go new file mode 100644 index 000000000..bf84d99b2 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_idp_facebook_test.go @@ -0,0 +1,76 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAppIDIDPFacebook_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDIDPFacebookDestroy, + Steps: []resource.TestStep{ + { + Config: setupIBMAppIDFacebookIDPConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "config.0.application_id", "test_id"), + resource.TestCheckResourceAttr("ibm_appid_idp_facebook.fb", "config.0.application_secret", "test_secret"), + resource.TestCheckResourceAttrSet("ibm_appid_idp_facebook.fb", "redirect_url"), + ), + }, + }, + }) +} + +func setupIBMAppIDFacebookIDPConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_idp_facebook" "fb" { + tenant_id = "%s" + is_active = true + + config { + application_id = "test_id" + application_secret = "test_secret" + } + } + `, tenantID) +} + +func testAccCheckIBMAppIDIDPFacebookDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_idp_facebook" { + continue + } + + tenantID := rs.Primary.ID + + config, _, err := appIDClient.GetFacebookIDP(&appid.GetFacebookIDPOptions{ + TenantID: &tenantID, + }) + + if err != nil { + return fmt.Errorf("[ERROR] Error checking if AppID Facebook IDP configuration was reset: %s", err) + } + + if config == nil || (config.IsActive != nil && *config.IsActive != false) { + return fmt.Errorf("[ERROR] Error checking if AppID Facebook IDP configuration was reset") + } + } + + return nil +} diff --git a/ibm/resource_ibm_appid_idp_google.go b/ibm/service/appid/resource_ibm_appid_idp_google.go similarity index 94% rename from ibm/resource_ibm_appid_idp_google.go rename to ibm/service/appid/resource_ibm_appid_idp_google.go index aea37d2f5..75e53dc28 100644 --- a/ibm/resource_ibm_appid_idp_google.go +++ b/ibm/service/appid/resource_ibm_appid_idp_google.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDIDPGoogle() *schema.Resource { +func ResourceIBMAppIDIDPGoogle() *schema.Resource { return &schema.Resource{ Description: "Update Google identity provider configuration.", CreateContext: resourceIBMAppIDIDPGoogleCreate, @@ -62,7 +64,7 @@ func resourceIBMAppIDIDPGoogle() *schema.Resource { } func resourceIBMAppIDIDPGoogleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -102,7 +104,7 @@ func resourceIBMAppIDIDPGoogleRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDIDPGoogleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -134,7 +136,7 @@ func resourceIBMAppIDIDPGoogleCreate(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDIDPGoogleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_idp_google_test.go b/ibm/service/appid/resource_ibm_appid_idp_google_test.go new file mode 100644 index 000000000..d87ac061e --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_idp_google_test.go @@ -0,0 +1,76 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAppIDIDPGoogle_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDIDPGoogleDestroy, + Steps: []resource.TestStep{ + { + Config: setupIBMAppIDGoogleIDPConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "config.0.application_id", "test_id"), + resource.TestCheckResourceAttr("ibm_appid_idp_google.gg", "config.0.application_secret", "test_secret"), + resource.TestCheckResourceAttrSet("ibm_appid_idp_google.gg", "redirect_url"), + ), + }, + }, + }) +} + +func setupIBMAppIDGoogleIDPConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_idp_google" "gg" { + tenant_id = "%s" + is_active = true + + config { + application_id = "test_id" + application_secret = "test_secret" + } + } + `, tenantID) +} + +func testAccCheckIBMAppIDIDPGoogleDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_idp_google" { + continue + } + + tenantID := rs.Primary.ID + + config, _, err := appIDClient.GetGoogleIDP(&appid.GetGoogleIDPOptions{ + TenantID: &tenantID, + }) + + if err != nil { + return fmt.Errorf("[ERROR] Error checking if AppID Google IDP configuration was reset: %s", err) + } + + if config == nil || (config.IsActive != nil && *config.IsActive != false) { + return fmt.Errorf("[ERROR] Error checking if AppID Google IDP configuration was reset") + } + } + + return nil +} diff --git a/ibm/resource_ibm_appid_idp_saml.go b/ibm/service/appid/resource_ibm_appid_idp_saml.go similarity index 94% rename from ibm/resource_ibm_appid_idp_saml.go rename to ibm/service/appid/resource_ibm_appid_idp_saml.go index 227605556..662da1255 100644 --- a/ibm/resource_ibm_appid_idp_saml.go +++ b/ibm/service/appid/resource_ibm_appid_idp_saml.go @@ -1,16 +1,19 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" ) -func resourceIBMAppIDIDPSAML() *schema.Resource { +func ResourceIBMAppIDIDPSAML() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDIDPSAMLCreate, ReadContext: resourceIBMAppIDIDPSAMLRead, @@ -111,7 +114,7 @@ func resourceIBMAppIDIDPSAML() *schema.Resource { } func resourceIBMAppIDIDPSAMLRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -147,7 +150,7 @@ func resourceIBMAppIDIDPSAMLRead(ctx context.Context, d *schema.ResourceData, me } func resourceIBMAppIDIDPSAMLCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -192,7 +195,7 @@ func expandAppIDIDPSAMLAuthNContext(ctx []interface{}) *appid.SAMLConfigParamsAu } if class, ok := mContext["class"]; ok { - authNContext.Class = expandStringList(class.([]interface{})) + authNContext.Class = flex.ExpandStringList(class.([]interface{})) } return authNContext @@ -251,7 +254,7 @@ func appIDIDPSAMLConfigDefaults(tenantID string) *appid.SetSAMLIDPOptions { } func resourceIBMAppIDIDPSAMLDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_idp_saml_test.go b/ibm/service/appid/resource_ibm_appid_idp_saml_test.go similarity index 88% rename from ibm/resource_ibm_appid_idp_saml_test.go rename to ibm/service/appid/resource_ibm_appid_idp_saml_test.go index 17d6181d9..99dd0d2b3 100644 --- a/ibm/resource_ibm_appid_idp_saml_test.go +++ b/ibm/service/appid/resource_ibm_appid_idp_saml_test.go @@ -1,28 +1,32 @@ -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/bluemix-go/helpers" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMAppIDIDPSaml_basic(t *testing.T) { dispName := fmt.Sprintf("testacc_saml_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDIDPSAMLDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDIDPSAMLConfig(appIDTenantID, dispName), + Config: testAccCheckIBMAppIDIDPSAMLConfig(acc.AppIDTenantID, dispName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_idp_saml.test_saml", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_idp_saml.test_saml", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_idp_saml.test_saml", "is_active", "true"), resource.TestCheckResourceAttr("ibm_appid_idp_saml.test_saml", "config.0.entity_id", "https://test-saml-idp"), resource.TestCheckResourceAttr("ibm_appid_idp_saml.test_saml", "config.0.sign_in_url", "https://test-saml-idp/login"), @@ -94,7 +98,7 @@ EOF } func testAccCheckIBMAppIDIDPSAMLDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -112,7 +116,7 @@ func testAccCheckIBMAppIDIDPSAMLDestroy(s *terraform.State) error { }) if err != nil { - return fmt.Errorf("Error checking if AppID IDP SAML configuration was reset: %s", err) + return fmt.Errorf("[ERROR] Error checking if AppID IDP SAML configuration was reset: %s", err) } // verify that configuration is reset to defaults @@ -127,7 +131,7 @@ func testAccCheckIBMAppIDIDPSAMLDestroy(s *terraform.State) error { }, defaults) if config == nil || diff != "" { - return fmt.Errorf("Error checking if AppID IDP SAML configuration was reset: %s", diff) + return fmt.Errorf("[ERROR] Error checking if AppID IDP SAML configuration was reset: %s", diff) } } diff --git a/ibm/resource_ibm_appid_languages.go b/ibm/service/appid/resource_ibm_appid_languages.go similarity index 86% rename from ibm/resource_ibm_appid_languages.go rename to ibm/service/appid/resource_ibm_appid_languages.go index 40a1ef674..dc3155423 100644 --- a/ibm/resource_ibm_appid_languages.go +++ b/ibm/service/appid/resource_ibm_appid_languages.go @@ -1,14 +1,17 @@ -package ibm +package appid import ( "context" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDLanguages() *schema.Resource { +func ResourceIBMAppIDLanguages() *schema.Resource { return &schema.Resource{ Description: "User localization configuration", CreateContext: resourceIBMAppIDLanguagesCreate, @@ -38,7 +41,7 @@ func resourceIBMAppIDLanguages() *schema.Resource { } func resourceIBMAppIDLanguagesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -67,14 +70,14 @@ func resourceIBMAppIDLanguagesRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDLanguagesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) } tenantID := d.Get("tenant_id").(string) - languages := expandStringList(d.Get("languages").([]interface{})) + languages := flex.ExpandStringList(d.Get("languages").([]interface{})) input := &appid.UpdateLocalizationOptions{ TenantID: &tenantID, @@ -93,7 +96,7 @@ func resourceIBMAppIDLanguagesCreate(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDLanguagesDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_languages_test.go b/ibm/service/appid/resource_ibm_appid_languages_test.go similarity index 75% rename from ibm/resource_ibm_appid_languages_test.go rename to ibm/service/appid/resource_ibm_appid_languages_test.go index 5b762163f..20f2658a2 100644 --- a/ibm/resource_ibm_appid_languages_test.go +++ b/ibm/service/appid/resource_ibm_appid_languages_test.go @@ -1,26 +1,30 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDLanguages_basic(t *testing.T) { languages := []string{"en", "es-ES", "fr-FR"} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDLanguagesDestroy, Steps: []resource.TestStep{ { - Config: setupIBMAppIDLanguagesConfig(appIDTenantID, languages), + Config: setupIBMAppIDLanguagesConfig(acc.AppIDTenantID, languages), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_languages.lang", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_languages.lang", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_languages.lang", "languages.#", "3"), resource.TestCheckResourceAttr("ibm_appid_languages.lang", "languages.0", "en"), resource.TestCheckResourceAttr("ibm_appid_languages.lang", "languages.1", "es-ES"), @@ -43,7 +47,7 @@ func setupIBMAppIDLanguagesConfig(tenantID string, languages []string) string { } func testAccCheckIBMAppIDLanguagesDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -61,12 +65,12 @@ func testAccCheckIBMAppIDLanguagesDestroy(s *terraform.State) error { }) if err != nil { - return fmt.Errorf("Error checking if AppID languages were reset: %s", err) + return fmt.Errorf("[ERROR] Error checking if AppID languages were reset: %s", err) } // verify that configuration is reset to defaults if config == nil || len(config.Languages) != 1 || (len(config.Languages) == 1 && config.Languages[0] != "en") { - return fmt.Errorf("Error checking if AppID languages were reset") + return fmt.Errorf("[ERROR] Error checking if AppID languages were reset") } } diff --git a/ibm/resource_ibm_appid_mfa.go b/ibm/service/appid/resource_ibm_appid_mfa.go similarity index 90% rename from ibm/resource_ibm_appid_mfa.go rename to ibm/service/appid/resource_ibm_appid_mfa.go index 67d54652f..74bd53554 100644 --- a/ibm/resource_ibm_appid_mfa.go +++ b/ibm/service/appid/resource_ibm_appid_mfa.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDMFA() *schema.Resource { +func ResourceIBMAppIDMFA() *schema.Resource { return &schema.Resource{ ReadContext: resourceIBMAppIDMFARead, CreateContext: resourceIBMAppIDMFACreate, @@ -35,7 +37,7 @@ func resourceIBMAppIDMFA() *schema.Resource { } func resourceIBMAppIDMFARead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -67,7 +69,7 @@ func resourceIBMAppIDMFARead(ctx context.Context, d *schema.ResourceData, meta i } func resourceIBMAppIDMFACreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -93,7 +95,7 @@ func resourceIBMAppIDMFACreate(ctx context.Context, d *schema.ResourceData, meta } func resourceIBMAppIDMFADelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_mfa_channel.go b/ibm/service/appid/resource_ibm_appid_mfa_channel.go similarity index 93% rename from ibm/resource_ibm_appid_mfa_channel.go rename to ibm/service/appid/resource_ibm_appid_mfa_channel.go index 093007a21..eeda8f2cd 100644 --- a/ibm/resource_ibm_appid_mfa_channel.go +++ b/ibm/service/appid/resource_ibm_appid_mfa_channel.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func resourceIBMAppIDMFAChannel() *schema.Resource { +func ResourceIBMAppIDMFAChannel() *schema.Resource { return &schema.Resource{ Description: "Update MFA channel configuration", ReadContext: resourceIBMAppIDMFAChannelRead, @@ -64,7 +66,7 @@ func resourceIBMAppIDMFAChannel() *schema.Resource { } func resourceIBMAppIDMFAChannelRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -104,7 +106,7 @@ func resourceIBMAppIDMFAChannelRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDMFAChannelCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -140,7 +142,7 @@ func resourceIBMAppIDMFAChannelCreate(ctx context.Context, d *schema.ResourceDat } func resourceIBMAppIDMFAChannelDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_mfa_channel_test.go b/ibm/service/appid/resource_ibm_appid_mfa_channel_test.go new file mode 100644 index 000000000..bb3e7c8d7 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_mfa_channel_test.go @@ -0,0 +1,81 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAppIDMFAChannel_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDMFAChannelDestroy, + Steps: []resource.TestStep{ + { + Config: setupIBMMFAChannelConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "active", "sms"), + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.#", "1"), + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.key", "api_key"), + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.secret", "api_secret"), + resource.TestCheckResourceAttr("ibm_appid_mfa_channel.mf", "sms_config.0.from", "+12223334444"), + ), + }, + }, + }) +} + +func setupIBMMFAChannelConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_mfa_channel" "mf" { + tenant_id = "%s" + active = "sms" + + sms_config { + key = "api_key" + secret = "api_secret" + from = "+12223334444" + } + } + `, tenantID) +} + +func testAccCheckIBMAppIDMFAChannelDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_mfa_channel" { + continue + } + + tenantID := rs.Primary.ID + + ch, _, err := appIDClient.ListChannels(&appid.ListChannelsOptions{ + TenantID: &tenantID, + }) + + if err != nil { + return fmt.Errorf("[ERROR] Error checking if AppID MFA channel configuration was reset: %s", err) + } + + for _, channel := range ch.Channels { + if *channel.IsActive && *channel.Type != "email" { + return fmt.Errorf("[ERROR] Error checking if AppID MFA channel configuration was reset") + } + } + } + + return nil +} diff --git a/ibm/service/appid/resource_ibm_appid_mfa_test.go b/ibm/service/appid/resource_ibm_appid_mfa_test.go new file mode 100644 index 000000000..b10fb6392 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_mfa_test.go @@ -0,0 +1,35 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAppIDMFA_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupIBMMFAConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_mfa.mf", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_mfa.mf", "is_active", "true"), + ), + }, + }, + }) +} + +func setupIBMMFAConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_mfa" "mf" { + tenant_id = "%s" + is_active = true + } + `, tenantID) +} diff --git a/ibm/resource_ibm_appid_password_regex.go b/ibm/service/appid/resource_ibm_appid_password_regex.go similarity index 92% rename from ibm/resource_ibm_appid_password_regex.go rename to ibm/service/appid/resource_ibm_appid_password_regex.go index e6d734864..979e477cd 100644 --- a/ibm/resource_ibm_appid_password_regex.go +++ b/ibm/service/appid/resource_ibm_appid_password_regex.go @@ -1,16 +1,18 @@ -package ibm +package appid import ( "context" b64 "encoding/base64" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDPasswordRegex() *schema.Resource { +func ResourceIBMAppIDPasswordRegex() *schema.Resource { return &schema.Resource{ Description: "The regular expression used by App ID for password strength validation", CreateContext: resourceIBMAppIDPasswordRegexCreate, @@ -47,7 +49,7 @@ func resourceIBMAppIDPasswordRegex() *schema.Resource { } func resourceIBMAppIDPasswordRegexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -87,7 +89,7 @@ func resourceIBMAppIDPasswordRegexRead(ctx context.Context, d *schema.ResourceDa } func resourceIBMAppIDPasswordRegexCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -121,7 +123,7 @@ func resourceIBMAppIDPasswordRegexUpdate(ctx context.Context, d *schema.Resource } func resourceIBMAppIDPasswordRegexDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_password_regex_test.go b/ibm/service/appid/resource_ibm_appid_password_regex_test.go new file mode 100644 index 000000000..e1ec21f95 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_password_regex_test.go @@ -0,0 +1,72 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMAppIDPasswordRegex_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDPasswordRegexDestroy, + Steps: []resource.TestStep{ + { + Config: setupIBMAppIDPasswordRegexConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "regex", "^(?:(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*)$"), + resource.TestCheckResourceAttr("ibm_appid_password_regex.rgx", "error_message", "test error"), + ), + }, + }, + }) +} + +func setupIBMAppIDPasswordRegexConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_password_regex" "rgx" { + tenant_id = "%s" + regex = "^(?:(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*)$" + error_message = "test error" + } + `, tenantID) +} + +func testAccCheckIBMAppIDPasswordRegexDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_password_regex" { + continue + } + + tenantID := rs.Primary.ID + + config, _, err := appIDClient.GetCloudDirectoryPasswordRegex(&appid.GetCloudDirectoryPasswordRegexOptions{ + TenantID: &tenantID, + }) + + if err != nil { + return fmt.Errorf("[ERROR] Error checking if AppID Password Regex was reset: %s", err) + } + + // verify that configuration is reset to defaults + if config == nil || (config.Base64EncodedRegex != nil && *config.Base64EncodedRegex != "") { + return fmt.Errorf("[ERROR] Error checking if AppID Password Regex was reset") + } + } + + return nil +} diff --git a/ibm/resource_ibm_appid_redirect_urls.go b/ibm/service/appid/resource_ibm_appid_redirect_urls.go similarity index 86% rename from ibm/resource_ibm_appid_redirect_urls.go rename to ibm/service/appid/resource_ibm_appid_redirect_urls.go index 472c2ef88..081d1f815 100644 --- a/ibm/resource_ibm_appid_redirect_urls.go +++ b/ibm/service/appid/resource_ibm_appid_redirect_urls.go @@ -1,13 +1,16 @@ -package ibm +package appid import ( "context" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMAppIDRedirectURLs() *schema.Resource { +func ResourceIBMAppIDRedirectURLs() *schema.Resource { return &schema.Resource{ Description: "Redirect URIs that can be used as callbacks of App ID authentication flow", CreateContext: resourceIBMAppIDRedirectURLsCreate, @@ -37,7 +40,7 @@ func resourceIBMAppIDRedirectURLs() *schema.Resource { } func resourceIBMAppIDRedirectURLsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -62,7 +65,7 @@ func resourceIBMAppIDRedirectURLsRead(ctx context.Context, d *schema.ResourceDat } func resourceIBMAppIDRedirectURLsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -71,7 +74,7 @@ func resourceIBMAppIDRedirectURLsCreate(ctx context.Context, d *schema.ResourceD tenantID := d.Get("tenant_id").(string) urls := d.Get("urls") - redirectURLs := expandStringList(urls.([]interface{})) + redirectURLs := flex.ExpandStringList(urls.([]interface{})) resp, err := appIDClient.UpdateRedirectUrisWithContext(ctx, &appid.UpdateRedirectUrisOptions{ TenantID: &tenantID, RedirectUrisArray: &appid.RedirectURIConfig{ @@ -88,7 +91,7 @@ func resourceIBMAppIDRedirectURLsCreate(ctx context.Context, d *schema.ResourceD } func resourceIBMAppIDRedirectURLsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -97,7 +100,7 @@ func resourceIBMAppIDRedirectURLsUpdate(ctx context.Context, d *schema.ResourceD tenantID := d.Get("tenant_id").(string) urls := d.Get("urls") - redirectURLs := expandStringList(urls.([]interface{})) + redirectURLs := flex.ExpandStringList(urls.([]interface{})) resp, err := appIDClient.UpdateRedirectUrisWithContext(ctx, &appid.UpdateRedirectUrisOptions{ TenantID: &tenantID, RedirectUrisArray: &appid.RedirectURIConfig{ @@ -113,7 +116,7 @@ func resourceIBMAppIDRedirectURLsUpdate(ctx context.Context, d *schema.ResourceD } func resourceIBMAppIDRedirectURLsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_redirect_urls_test.go b/ibm/service/appid/resource_ibm_appid_redirect_urls_test.go similarity index 75% rename from ibm/resource_ibm_appid_redirect_urls_test.go rename to ibm/service/appid/resource_ibm_appid_redirect_urls_test.go index f7ca5553c..2a42bf191 100644 --- a/ibm/resource_ibm_appid_redirect_urls_test.go +++ b/ibm/service/appid/resource_ibm_appid_redirect_urls_test.go @@ -1,21 +1,25 @@ -package ibm +package appid_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMAppIDRedirectURLs_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDRedirectURLsDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDRedirectURLsConfig(appIDTenantID), + Config: testAccCheckIBMAppIDRedirectURLsConfig(acc.AppIDTenantID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_appid_redirect_urls.urls", "urls.#", "3"), resource.TestCheckResourceAttr("ibm_appid_redirect_urls.urls", "urls.0", "https://test-url-1.com"), @@ -41,7 +45,7 @@ func testAccCheckIBMAppIDRedirectURLsConfig(tenantID string) string { } func testAccCheckIBMAppIDRedirectURLsDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -59,7 +63,7 @@ func testAccCheckIBMAppIDRedirectURLsDestroy(s *terraform.State) error { }) if err != nil || len(urls.RedirectUris) != 0 { - return fmt.Errorf("error checking if AppID redirect URLs resource (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID redirect URLs resource (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_role.go b/ibm/service/appid/resource_ibm_appid_role.go similarity index 94% rename from ibm/resource_ibm_appid_role.go rename to ibm/service/appid/resource_ibm_appid_role.go index f6dcdcdb6..66c72c149 100644 --- a/ibm/resource_ibm_appid_role.go +++ b/ibm/service/appid/resource_ibm_appid_role.go @@ -1,16 +1,18 @@ -package ibm +package appid import ( "context" "fmt" + "strings" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "strings" ) -func resourceIBMAppIDRole() *schema.Resource { +func ResourceIBMAppIDRole() *schema.Resource { return &schema.Resource{ Description: "A role is a collection of `scopes` that allow varying permissions to different types of app users", CreateContext: resourceIBMAppIDRoleCreate, @@ -67,7 +69,7 @@ func resourceIBMAppIDRole() *schema.Resource { } func resourceIBMAppIDRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -99,7 +101,7 @@ func resourceIBMAppIDRoleCreate(ctx context.Context, d *schema.ResourceData, met } func resourceIBMAppIDRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -141,7 +143,7 @@ func resourceIBMAppIDRoleRead(ctx context.Context, d *schema.ResourceData, meta } func resourceIBMAppIDRoleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -172,7 +174,7 @@ func resourceIBMAppIDRoleDelete(ctx context.Context, d *schema.ResourceData, met func resourceIBMAppIDRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { // AppID role resource does not support partial updates, all inputs should be included - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_role_test.go b/ibm/service/appid/resource_ibm_appid_role_test.go similarity index 82% rename from ibm/resource_ibm_appid_role_test.go rename to ibm/service/appid/resource_ibm_appid_role_test.go index f849d84f5..34defbdef 100644 --- a/ibm/resource_ibm_appid_role_test.go +++ b/ibm/service/appid/resource_ibm_appid_role_test.go @@ -1,13 +1,17 @@ -package ibm +package appid_test import ( "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "strings" - "testing" ) func TestAccIBMAppIDRole_basic(t *testing.T) { @@ -15,14 +19,14 @@ func TestAccIBMAppIDRole_basic(t *testing.T) { roleName := fmt.Sprintf("tf_testacc_role_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDRoleDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMAppIDRoleConfig(appIDTenantID, roleName, appName), + Config: testAccCheckIBMAppIDRoleConfig(acc.AppIDTenantID, roleName, appName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_appid_role.test_role", "tenant_id", appIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_role.test_role", "tenant_id", acc.AppIDTenantID), resource.TestCheckResourceAttr("ibm_appid_role.test_role", "name", roleName), resource.TestCheckResourceAttr("ibm_appid_role.test_role", "access.#", "1"), resource.TestCheckResourceAttrSet("ibm_appid_role.test_role", "access.0.application_id"), @@ -65,7 +69,7 @@ func testAccCheckIBMAppIDRoleConfig(tenantID string, roleName string, appName st } func testAccCheckIBMAppIDRoleDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -88,7 +92,7 @@ func testAccCheckIBMAppIDRoleDestroy(s *terraform.State) error { }) if err == nil { - return fmt.Errorf("error checking if AppID role (%s) has been destroyed", rs.Primary.ID) + return fmt.Errorf("[ERROR] Error checking if AppID role (%s) has been destroyed", rs.Primary.ID) } } diff --git a/ibm/resource_ibm_appid_theme_color.go b/ibm/service/appid/resource_ibm_appid_theme_color.go similarity index 90% rename from ibm/resource_ibm_appid_theme_color.go rename to ibm/service/appid/resource_ibm_appid_theme_color.go index 247f2a16f..ee05e0a28 100644 --- a/ibm/resource_ibm_appid_theme_color.go +++ b/ibm/service/appid/resource_ibm_appid_theme_color.go @@ -1,17 +1,19 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) const defaultHeaderColor = "#EEF2F5" // AppID default -func resourceIBMAppIDThemeColor() *schema.Resource { +func ResourceIBMAppIDThemeColor() *schema.Resource { return &schema.Resource{ Description: "Colors of the App ID login widget", CreateContext: resourceIBMAppIDThemeColorCreate, @@ -37,7 +39,7 @@ func resourceIBMAppIDThemeColor() *schema.Resource { } func resourceIBMAppIDThemeColorRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -69,7 +71,7 @@ func resourceIBMAppIDThemeColorRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDThemeColorCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -98,7 +100,7 @@ func resourceIBMAppIDThemeColorUpdate(ctx context.Context, d *schema.ResourceDat } func resourceIBMAppIDThemeColorDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_theme_color_test.go b/ibm/service/appid/resource_ibm_appid_theme_color_test.go new file mode 100644 index 000000000..09906c5ec --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_theme_color_test.go @@ -0,0 +1,66 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccThemeColor_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDThemeColorDestroy, + Steps: []resource.TestStep{ + { + Config: setupAppIDThemeColorConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_theme_color.color", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_theme_color.color", "header_color", "#000000"), + ), + }, + }, + }) +} + +func setupAppIDThemeColorConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_theme_color" "color" { + tenant_id = "%s" + header_color = "#000000" + } + `, tenantID) +} + +func testAccCheckIBMAppIDThemeColorDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_theme_color" { + continue + } + + tenantID := rs.Primary.ID + + cfg, _, err := appIDClient.GetThemeColor(&appid.GetThemeColorOptions{ + TenantID: &tenantID, + }) + + // AppID default default #EEF2F5 + if err != nil || (cfg.HeaderColor != nil && *cfg.HeaderColor != "#EEF2F5") { + return fmt.Errorf("[ERROR] Error checking if AppID theme color configuration (%s) has been reset", rs.Primary.ID) + } + } + + return nil +} diff --git a/ibm/resource_ibm_appid_theme_text.go b/ibm/service/appid/resource_ibm_appid_theme_text.go similarity index 90% rename from ibm/resource_ibm_appid_theme_text.go rename to ibm/service/appid/resource_ibm_appid_theme_text.go index 5bc8f6653..1424f1e4b 100644 --- a/ibm/resource_ibm_appid_theme_text.go +++ b/ibm/service/appid/resource_ibm_appid_theme_text.go @@ -1,15 +1,17 @@ -package ibm +package appid import ( "context" + "log" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" ) -func resourceIBMAppIDThemeText() *schema.Resource { +func ResourceIBMAppIDThemeText() *schema.Resource { return &schema.Resource{ Description: "Update theme texts of the App ID login widget", CreateContext: resourceIBMAppIDThemeTextCreate, @@ -36,7 +38,7 @@ func resourceIBMAppIDThemeText() *schema.Resource { } func resourceIBMAppIDThemeTextRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -72,7 +74,7 @@ func resourceIBMAppIDThemeTextRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDThemeTextCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -102,7 +104,7 @@ func resourceIBMAppIDThemeTextUpdate(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDThemeTextDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/appid/resource_ibm_appid_theme_text_test.go b/ibm/service/appid/resource_ibm_appid_theme_text_test.go new file mode 100644 index 000000000..157db8fd4 --- /dev/null +++ b/ibm/service/appid/resource_ibm_appid_theme_text_test.go @@ -0,0 +1,67 @@ +package appid_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccThemeText_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAppIDThemeTextDestroy, + Steps: []resource.TestStep{ + { + Config: setupAppIDThemeTextConfig(acc.AppIDTenantID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "tenant_id", acc.AppIDTenantID), + resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "tab_title", "resource test title"), + resource.TestCheckResourceAttr("ibm_appid_theme_text.text", "footnote", "resource test footnote"), + ), + }, + }, + }) +} + +func setupAppIDThemeTextConfig(tenantID string) string { + return fmt.Sprintf(` + resource "ibm_appid_theme_text" "text" { + tenant_id = "%s" + tab_title = "resource test title" + footnote = "resource test footnote" + } + `, tenantID) +} + +func testAccCheckIBMAppIDThemeTextDestroy(s *terraform.State) error { + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() + + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_appid_theme_text" { + continue + } + + tenantID := rs.Primary.ID + + cfg, _, err := appIDClient.GetThemeText(&appid.GetThemeTextOptions{ + TenantID: &tenantID, + }) + + if err != nil || (cfg.TabTitle != nil && *cfg.TabTitle != "Login") || (cfg.Footnote != nil && *cfg.Footnote != "Powered by App ID") { + return fmt.Errorf("[ERROR] Error checking if AppID theme text configuration (%s) has been reset", rs.Primary.ID) + } + } + + return nil +} diff --git a/ibm/resource_ibm_appid_token_config.go b/ibm/service/appid/resource_ibm_appid_token_config.go similarity index 96% rename from ibm/resource_ibm_appid_token_config.go rename to ibm/service/appid/resource_ibm_appid_token_config.go index 31024491b..dd2e482d0 100644 --- a/ibm/resource_ibm_appid_token_config.go +++ b/ibm/service/appid/resource_ibm_appid_token_config.go @@ -1,11 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package appid import ( "context" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -13,7 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func resourceIBMAppIDTokenConfig() *schema.Resource { +func ResourceIBMAppIDTokenConfig() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMAppIDTokenConfigCreate, ReadContext: resourceIBMAppIDTokenConfigRead, @@ -109,7 +111,7 @@ func resourceIBMAppIDTokenConfig() *schema.Resource { } func resourceIBMAppIDTokenConfigCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -133,7 +135,7 @@ func resourceIBMAppIDTokenConfigCreate(ctx context.Context, d *schema.ResourceDa func resourceIBMAppIDTokenConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -301,7 +303,7 @@ func tokenConfigDefaults(tenantID string) *appid.PutTokensConfigOptions { } func resourceIBMAppIDTokenConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appidClient, err := meta.(ClientSession).AppIDAPI() + appidClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_user_roles.go b/ibm/service/appid/resource_ibm_appid_user_roles.go similarity index 90% rename from ibm/resource_ibm_appid_user_roles.go rename to ibm/service/appid/resource_ibm_appid_user_roles.go index 57b873572..8b07ca82b 100644 --- a/ibm/resource_ibm_appid_user_roles.go +++ b/ibm/service/appid/resource_ibm_appid_user_roles.go @@ -1,16 +1,19 @@ -package ibm +package appid import ( "context" "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" - "strings" ) -func resourceIBMAppIDUserRoles() *schema.Resource { +func ResourceIBMAppIDUserRoles() *schema.Resource { return &schema.Resource{ Description: "Manage AppID user roles", ReadContext: resourceIBMAppIDUserRolesRead, @@ -44,7 +47,7 @@ func resourceIBMAppIDUserRoles() *schema.Resource { } func resourceIBMAppIDUserRolesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -83,7 +86,7 @@ func resourceIBMAppIDUserRolesRead(ctx context.Context, d *schema.ResourceData, } func resourceIBMAppIDUserRolesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) @@ -97,7 +100,7 @@ func resourceIBMAppIDUserRolesCreate(ctx context.Context, d *schema.ResourceData TenantID: &tenantID, ID: &subject, Roles: &appid.UpdateUserRolesParamsRoles{ - Ids: expandStringList(roleIds.List()), + Ids: flex.ExpandStringList(roleIds.List()), }, } @@ -113,7 +116,7 @@ func resourceIBMAppIDUserRolesCreate(ctx context.Context, d *schema.ResourceData } func resourceIBMAppIDUserRolesDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - appIDClient, err := meta.(ClientSession).AppIDAPI() + appIDClient, err := meta.(conns.ClientSession).AppIDAPI() if err != nil { return diag.FromErr(err) diff --git a/ibm/resource_ibm_appid_user_roles_test.go b/ibm/service/appid/resource_ibm_appid_user_roles_test.go similarity index 77% rename from ibm/resource_ibm_appid_user_roles_test.go rename to ibm/service/appid/resource_ibm_appid_user_roles_test.go index 292431228..6a0aeb759 100644 --- a/ibm/resource_ibm_appid_user_roles_test.go +++ b/ibm/service/appid/resource_ibm_appid_user_roles_test.go @@ -1,12 +1,16 @@ -package ibm +package appid_test import ( "fmt" - appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + appid "github.com/IBM/appid-management-go-sdk/appidmanagementv4" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,12 +19,12 @@ func TestAccIBMAppIDUserRolesRoles_basic(t *testing.T) { roleName := fmt.Sprintf("tf_testacc_role_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppIDUserRolesDestroy, Steps: []resource.TestStep{ { - Config: setupAppIDUserRolesConfig(appIDTenantID, roleName, appIDTestUserEmail), + Config: setupAppIDUserRolesConfig(acc.AppIDTenantID, roleName, acc.AppIDTestUserEmail), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_appid_user_roles.roles", "role_ids.#", "1"), resource.TestCheckResourceAttrPair("ibm_appid_user_roles.roles", "role_ids.0", "ibm_appid_role.role", "role_id"), @@ -58,7 +62,7 @@ func setupAppIDUserRolesConfig(tenantID string, roleName string, email string) s } func testAccCheckIBMAppIDUserRolesDestroy(s *terraform.State) error { - appIDClient, err := testAccProvider.Meta().(ClientSession).AppIDAPI() + appIDClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AppIDAPI() if err != nil { return err @@ -81,11 +85,11 @@ func testAccCheckIBMAppIDUserRolesDestroy(s *terraform.State) error { }) if err != nil { - return fmt.Errorf("error checking if AppID user roles have been destroyed: %s", err) + return fmt.Errorf("[ERROR] Error checking if AppID user roles have been destroyed: %s", err) } if roles.Roles != nil && len(roles.Roles) > 0 { - return fmt.Errorf("error checking if AppID user roles have been destroyed") + return fmt.Errorf("[ERROR] Error checking if AppID user roles have been destroyed") } } diff --git a/ibm/service/atracker/README.md b/ibm/service/atracker/README.md new file mode 100644 index 000000000..bdbca7c35 --- /dev/null +++ b/ibm/service/atracker/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Activity Tracker + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Activity Tracker resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/atracker_route) +* IBM API Docs: [IBM API Docs for Activity Tracker](https://cloud.ibm.com/apidocs/atracker) +* IBM Activity Tracker SDK: [IBM SDK for Activity Tracker](https://github.com/IBM/platform-services-go-sdk/tree/main/atrackerv2) diff --git a/ibm/service/atracker/atracker_utils.go b/ibm/service/atracker/atracker_utils.go new file mode 100644 index 000000000..9143863c8 --- /dev/null +++ b/ibm/service/atracker/atracker_utils.go @@ -0,0 +1,31 @@ +package atracker + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/atrackerv1" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +const ( + REDACTED_TEXT = "REDACTED" + BLOCKED_V1_RESOURCE = "v2_resource_exists_v1_api_is_not_accessible" +) + +func getAtrackerClients(meta interface{}) ( + atrackerClientv1 *atrackerv1.AtrackerV1, atrackerClientv2 *atrackerv2.AtrackerV2, err error) { + atrackerClientv1, err = meta.(conns.ClientSession).AtrackerV1() + if err != nil { + return + } + atrackerClientv2, err = meta.(conns.ClientSession).AtrackerV2() + if err != nil { + return + } + + _, err = meta.(conns.ClientSession).BluemixSession() + if err != nil { + return + } + + return atrackerClientv1, atrackerClientv2, nil +} diff --git a/ibm/data_source_ibm_atracker_endpoints.go b/ibm/service/atracker/data_source_ibm_atracker_endpoints.go similarity index 87% rename from ibm/data_source_ibm_atracker_endpoints.go rename to ibm/service/atracker/data_source_ibm_atracker_endpoints.go index 325481786..1c8c2b51c 100644 --- a/ibm/data_source_ibm_atracker_endpoints.go +++ b/ibm/service/atracker/data_source_ibm_atracker_endpoints.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package atracker import ( "context" @@ -15,33 +15,33 @@ import ( "github.com/IBM/platform-services-go-sdk/atrackerv1" ) -func dataSourceIBMAtrackerEndpoints() *schema.Resource { +func DataSourceIBMAtrackerEndpoints() *schema.Resource { return &schema.Resource{ - ReadContext: dataSourceIBMAtrackerEndpointsRead, - + ReadContext: dataSourceIBMAtrackerEndpointsRead, + DeprecationMessage: "use Settings instead", Schema: map[string]*schema.Schema{ - "api_endpoint": &schema.Schema{ + "api_endpoint": { Type: schema.TypeList, Computed: true, Description: "Activity Tracker API endpoint.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "public_url": &schema.Schema{ + "public_url": { Type: schema.TypeString, Computed: true, Description: "The public URL of Activity Tracker in a region.", }, - "public_enabled": &schema.Schema{ + "public_enabled": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether or not the public endpoint is enabled in the account.", }, - "private_url": &schema.Schema{ + "private_url": { Type: schema.TypeString, Computed: true, Description: "The private URL of Activity Tracker. This URL cannot be disabled.", }, - "private_enabled": &schema.Schema{ + "private_enabled": { Type: schema.TypeBool, Computed: true, Description: "The private endpoint is always enabled.", @@ -54,7 +54,7 @@ func dataSourceIBMAtrackerEndpoints() *schema.Resource { } func dataSourceIBMAtrackerEndpointsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - atrackerClient, err := meta.(ClientSession).AtrackerV1() + atrackerClient, _, err := getAtrackerClients(meta) if err != nil { return diag.FromErr(err) } @@ -72,7 +72,7 @@ func dataSourceIBMAtrackerEndpointsRead(context context.Context, d *schema.Resou if endpoints.APIEndpoint != nil { err = d.Set("api_endpoint", dataSourceEndpointsFlattenAPIEndpoint(*endpoints.APIEndpoint)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting api_endpoint %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting api_endpoint %s", err)) } } diff --git a/ibm/data_source_ibm_atracker_endpoints_test.go b/ibm/service/atracker/data_source_ibm_atracker_endpoints_test.go similarity index 80% rename from ibm/data_source_ibm_atracker_endpoints_test.go rename to ibm/service/atracker/data_source_ibm_atracker_endpoints_test.go index 46459b8d2..34e795b0f 100644 --- a/ibm/data_source_ibm_atracker_endpoints_test.go +++ b/ibm/service/atracker/data_source_ibm_atracker_endpoints_test.go @@ -1,21 +1,22 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package atracker_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAtrackerEndpointsDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAtrackerEndpointsDataSourceConfigBasic(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_atracker_endpoints.atracker_endpoints", "id"), @@ -27,8 +28,8 @@ func TestAccIBMAtrackerEndpointsDataSourceBasic(t *testing.T) { } func testAccCheckIBMAtrackerEndpointsDataSourceConfigBasic() string { - return fmt.Sprintf(` + return ` data "ibm_atracker_endpoints" "atracker_endpoints" { } - `) + ` } diff --git a/ibm/service/atracker/data_source_ibm_atracker_routes.go b/ibm/service/atracker/data_source_ibm_atracker_routes.go new file mode 100644 index 000000000..d7b130a08 --- /dev/null +++ b/ibm/service/atracker/data_source_ibm_atracker_routes.go @@ -0,0 +1,331 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/atrackerv1" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func DataSourceIBMAtrackerRoutes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMAtrackerRoutesRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the route.", + }, + "routes": { + Type: schema.TypeList, + Computed: true, + Description: "A list of route resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The uuid of the route resource.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the route.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the route resource.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "The version of the route.", + }, + "receive_global_events": { + Type: schema.TypeBool, + Computed: true, + Deprecated: "use rules.locations instead", + Description: "Indicates whether or not all global events should be forwarded to this region.", + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "The routing rules that will be evaluated in their order of the array. Once a rule is matched, the remaining rules in the route definition will be skipped.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_ids": { + Type: schema.TypeList, + Computed: true, + Description: "The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "locations": { + Type: schema.TypeList, + Computed: true, + Description: "Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "created": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use created_at instead", + Description: "The timestamp of the route creation time.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the route creation time.", + }, + "updated": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use updated_at instead", + Description: "The timestamp of the target last updated time.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the route last updated time.", + }, + "api_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The API version of the route.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMAtrackerRoutesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClientv1, atrackerClientv2, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + listRoutesOptions := &atrackerv2.ListRoutesOptions{} + + routeList, response, err := atrackerClientv2.ListRoutesWithContext(context, listRoutesOptions) + if err != nil { + log.Printf("[DEBUG] ListRoutesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListRoutesWithContext failed %s\n%s", err, response)) + } + // TODO: Remove after deprecation + if len(routeList.Routes) == 0 { + var routeListV1 *atrackerv1.RouteList + listRoutesOptionsV1 := &atrackerv1.ListRoutesOptions{} + routeListV1, response, err := atrackerClientv1.ListRoutesWithContext(context, listRoutesOptionsV1) + + if err != nil && response != nil && strings.Contains(response.String(), BLOCKED_V1_RESOURCE) { + return nil + } else if err != nil { + log.Printf("[DEBUG] ListRoutesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListRoutesWithContext failed %s\n%s", err, response)) + } + var matchRoutesV1 []atrackerv1.Route + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range routeListV1.Routes { + if *data.Name == name { + matchRoutesV1 = append(matchRoutesV1, data) + } + } + } else { + matchRoutesV1 = routeListV1.Routes + } + + routeListV1.Routes = matchRoutesV1 + if suppliedFilter { + if len(routeList.Routes) == 0 { + return diag.FromErr(fmt.Errorf("no Routes found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(DataSourceIBMAtrackerRoutesID(d)) + } + routesV1 := []map[string]interface{}{} + + if routeListV1.Routes != nil { + routeListV1.Routes = matchRoutesV1 + for _, modelItem := range routeListV1.Routes { + modelMap := dataSourceRouteListRoutesToMapV1(modelItem) + if err != nil { + return diag.FromErr(err) + } + routesV1 = append(routesV1, modelMap) + } + } + if err = d.Set("routes", routesV1); err != nil { + return diag.FromErr(fmt.Errorf("Error setting routes %s", err)) + } + return nil + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchRoutes []atrackerv2.Route + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range routeList.Routes { + if *data.Name == name { + matchRoutes = append(matchRoutes, data) + } + } + } else { + matchRoutes = routeList.Routes + } + routeList.Routes = matchRoutes + if suppliedFilter { + if len(routeList.Routes) == 0 { + return diag.FromErr(fmt.Errorf("no Routes found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(DataSourceIBMAtrackerRoutesID(d)) + } + + routes := []map[string]interface{}{} + if routeList.Routes != nil { + for _, modelItem := range routeList.Routes { + modelMap, err := dataSourceIBMAtrackerRoutesRouteToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + routes = append(routes, modelMap) + } + } + + if err = d.Set("routes", routes); err != nil { + return diag.FromErr(fmt.Errorf("Error setting routes %s", err)) + } + + return nil +} + +// DataSourceIBMAtrackerRoutesID returns a reasonable ID for the list. +func DataSourceIBMAtrackerRoutesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIBMAtrackerRoutesRouteToMap(model *atrackerv2.Route) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Rules != nil { + rules := []map[string]interface{}{} + for _, rulesItem := range model.Rules { + rulesItemMap, err := dataSourceIBMAtrackerRoutesRuleToMap(&rulesItem) + if err != nil { + return modelMap, err + } + rules = append(rules, rulesItemMap) + } + modelMap["rules"] = rules + } + if model.CreatedAt != nil { + modelMap["created_at"] = model.CreatedAt.String() + } + if model.UpdatedAt != nil { + modelMap["updated_at"] = model.UpdatedAt.String() + } + if model.APIVersion != nil { + modelMap["api_version"] = *model.APIVersion + } else { + modelMap["api_version"] = 1 + } + return modelMap, nil +} + +func dataSourceIBMAtrackerRoutesRuleToMap(model *atrackerv2.Rule) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TargetIds != nil { + modelMap["target_ids"] = model.TargetIds + } + if model.Locations != nil { + modelMap["locations"] = model.Locations + } + return modelMap, nil +} + +func dataSourceRouteListRoutesToMapV1(routesItem atrackerv1.Route) (routesMap map[string]interface{}) { + routesMap = map[string]interface{}{} + + if routesItem.ID != nil { + routesMap["id"] = routesItem.ID + } + if routesItem.Name != nil { + routesMap["name"] = routesItem.Name + } + if routesItem.CRN != nil { + routesMap["crn"] = routesItem.CRN + } + if routesItem.Version != nil { + routesMap["version"] = routesItem.Version + } + if routesItem.ReceiveGlobalEvents != nil { + routesMap["receive_global_events"] = routesItem.ReceiveGlobalEvents + } + if routesItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, rulesItem := range routesItem.Rules { + rulesList = append(rulesList, dataSourceRouteListRoutesRulesToMapV1(rulesItem)) + } + routesMap["rules"] = rulesList + } + if routesItem.Created != nil { + routesMap["created"] = routesItem.Created.String() + } + if routesItem.Updated != nil { + routesMap["updated"] = routesItem.Updated.String() + } + + return routesMap +} + +func dataSourceRouteListRoutesRulesToMapV1(rulesItem atrackerv1.Rule) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + + if rulesItem.TargetIds != nil { + rulesMap["target_ids"] = rulesItem.TargetIds + } + + return rulesMap +} diff --git a/ibm/data_source_ibm_atracker_routes_test.go b/ibm/service/atracker/data_source_ibm_atracker_routes_test.go similarity index 76% rename from ibm/data_source_ibm_atracker_routes_test.go rename to ibm/service/atracker/data_source_ibm_atracker_routes_test.go index 8c3dc3553..3162542d6 100644 --- a/ibm/data_source_ibm_atracker_routes_test.go +++ b/ibm/service/atracker/data_source_ibm_atracker_routes_test.go @@ -1,7 +1,7 @@ -// Copyright IBM Corp. 2021 All Rights Reserved. +// Copyright IBM Corp. 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package atracker_test import ( "fmt" @@ -9,30 +9,30 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" ) func TestAccIBMAtrackerRoutesDataSourceBasic(t *testing.T) { routeName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - routeReceiveGlobalEvents := "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMAtrackerRoutesDataSourceConfigBasic(routeName, routeReceiveGlobalEvents), + { + Config: testAccCheckIBMAtrackerRoutesDataSourceConfigBasic(routeName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_atracker_routes.atracker_routes", "id"), resource.TestCheckResourceAttrSet("data.ibm_atracker_routes.atracker_routes", "routes.#"), resource.TestCheckResourceAttr("data.ibm_atracker_routes.atracker_routes", "routes.0.name", routeName), - resource.TestCheckResourceAttr("data.ibm_atracker_routes.atracker_routes", "routes.0.receive_global_events", routeReceiveGlobalEvents), ), }, }, }) } -func testAccCheckIBMAtrackerRoutesDataSourceConfigBasic(routeName string, routeReceiveGlobalEvents string) string { +func testAccCheckIBMAtrackerRoutesDataSourceConfigBasic(routeName string) string { return fmt.Sprintf(` resource "ibm_atracker_target" "atracker_target" { name = "my-cos-target" @@ -47,14 +47,14 @@ func testAccCheckIBMAtrackerRoutesDataSourceConfigBasic(routeName string, routeR resource "ibm_atracker_route" "atracker_route" { name = "%s" - receive_global_events = %s rules { target_ids = [ ibm_atracker_target.atracker_target.id ] + locations = [ "us-south" ] } } data "ibm_atracker_routes" "atracker_routes" { name = ibm_atracker_route.atracker_route.name } - `, routeName, routeReceiveGlobalEvents) + `, routeName) } diff --git a/ibm/service/atracker/data_source_ibm_atracker_targets.go b/ibm/service/atracker/data_source_ibm_atracker_targets.go new file mode 100644 index 000000000..7be10a5a3 --- /dev/null +++ b/ibm/service/atracker/data_source_ibm_atracker_targets.go @@ -0,0 +1,487 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/atrackerv1" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func DataSourceIBMAtrackerTargets() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMAtrackerTargetsRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the target resource.", + }, + "targets": { + Type: schema.TypeList, + Computed: true, + Description: "A list of target resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The uuid of the target resource.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the target resource.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the target resource.", + }, + "target_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the target.", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "Included this optional field if you used it to create a target in a different region other than the one you are connected.", + }, + "encrypt_key": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use encryption_key instead", + Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + }, + "encryption_key": { + Type: schema.TypeString, + Sensitive: true, + Computed: true, + Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + }, + "cos_endpoint": { + Type: schema.TypeList, + Computed: true, + Description: "Property values for a Cloud Object Storage Endpoint.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "The host name of the Cloud Object Storage endpoint.", + }, + "target_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the Cloud Object Storage instance.", + }, + "bucket": { + Type: schema.TypeString, + Computed: true, + Description: "The bucket name under the Cloud Object Storage instance.", + }, + "api_key": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled.", + }, + "service_to_service_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey.", + }, + }, + }, + }, + "logdna_endpoint": { + Type: schema.TypeList, + Computed: true, + Description: "Property values for a LogDNA Endpoint.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the LogDNA instance.", + }, + "ingestion_key": { + Type: schema.TypeString, + Sensitive: true, + Computed: true, + Description: "The LogDNA ingestion key is used for routing logs to a specific LogDNA instance.", + }, + }, + }, + }, + "cos_write_status": { + Type: schema.TypeList, + Computed: true, + Deprecated: "use write_status instead", + Description: "The status of the write attempt with the provided cos_endpoint parameters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status such as failed or success.", + }, + "last_failure": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the failure.", + }, + "reason_for_last_failure": { + Type: schema.TypeString, + Computed: true, + Description: "Detailed description of the cause of the failure.", + }, + }, + }, + }, + "write_status": { + Type: schema.TypeList, + Computed: true, + Description: "The status of the write attempt to the target with the provided endpoint parameters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status such as failed or success.", + }, + "last_failure": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the failure.", + }, + "reason_for_last_failure": { + Type: schema.TypeString, + Computed: true, + Description: "Detailed description of the cause of the failure.", + }, + }, + }, + }, + "created": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use created_at instead", + Description: "The timestamp of the target creation time.", + }, + "updated": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use updated_at instead", + Description: "The timestamp of the target last updated time.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the target creation time.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the target last updated time.", + }, + "api_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The API version of the target.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMAtrackerTargetsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClientv1, atrackerClientv2, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + // TODO: Remove after deprecation + listTargetsOptions := &atrackerv1.ListTargetsOptions{} + targetListV1, responseV1, err := atrackerClientv1.ListTargetsWithContext(context, listTargetsOptions) + if err == nil { + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchTargets []atrackerv1.Target + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range targetListV1.Targets { + if *data.Name == name { + matchTargets = append(matchTargets, data) + } + } + } else { + matchTargets = targetListV1.Targets + } + targetListV1.Targets = matchTargets + + if suppliedFilter { + if len(targetListV1.Targets) == 0 { + return diag.FromErr(fmt.Errorf("no Targets found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(DataSourceIBMAtrackerTargetsID(d)) + } + + if targetListV1.Targets != nil { + err = d.Set("targets", dataSourceTargetListFlattenTargetsV1(targetListV1.Targets)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting targets %s", err)) + } + } + return nil + } else if err != nil && responseV1 != nil && strings.Contains(responseV1.String(), BLOCKED_V1_RESOURCE) { + listTargetsOptions := &atrackerv2.ListTargetsOptions{} + + targetList, response, err := atrackerClientv2.ListTargetsWithContext(context, listTargetsOptions) + if err != nil { + log.Printf("[DEBUG] ListTargetsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListTargetsWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchTargets []atrackerv2.Target + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range targetList.Targets { + if *data.Name == name { + matchTargets = append(matchTargets, data) + } + } + } else { + matchTargets = targetList.Targets + } + targetList.Targets = matchTargets + + if suppliedFilter { + if len(targetList.Targets) == 0 { + return diag.FromErr(fmt.Errorf("no Targets found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(DataSourceIBMAtrackerTargetsID(d)) + } + + targets := []map[string]interface{}{} + if targetList.Targets != nil { + for _, modelItem := range targetList.Targets { + modelMap, err := DataSourceIBMAtrackerTargetsTargetToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + targets = append(targets, modelMap) + } + } + if err = d.Set("targets", targets); err != nil { + return diag.FromErr(fmt.Errorf("Error setting targets %s", err)) + } + return nil + } + + log.Printf("[DEBUG] ListTargetsWithContext failed %s\n%s", err, responseV1) + return diag.FromErr(fmt.Errorf("ListTargetsWithContext failed %s\n%s", err, responseV1)) +} + +// DataSourceIBMAtrackerTargetsID returns a reasonable ID for the list. +func DataSourceIBMAtrackerTargetsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMAtrackerTargetsTargetToMap(model *atrackerv2.Target) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.TargetType != nil { + modelMap["target_type"] = *model.TargetType + } + if model.Region != nil { + modelMap["region"] = *model.Region + } + if model.CosEndpoint != nil { + cosEndpointMap, err := DataSourceIBMAtrackerTargetsCosEndpointToMap(model.CosEndpoint) + if err != nil { + return modelMap, err + } + modelMap["cos_endpoint"] = []map[string]interface{}{cosEndpointMap} + } + if model.LogdnaEndpoint != nil { + logdnaEndpointMap, err := DataSourceIBMAtrackerTargetsLogdnaEndpointToMap(model.LogdnaEndpoint) + if err != nil { + return modelMap, err + } + modelMap["logdna_endpoint"] = []map[string]interface{}{logdnaEndpointMap} + } + if model.WriteStatus != nil { + writeStatusMap, err := DataSourceIBMAtrackerTargetsWriteStatusToMap(model.WriteStatus) + if err != nil { + return modelMap, err + } + modelMap["write_status"] = []map[string]interface{}{writeStatusMap} + } + if model.CreatedAt != nil { + modelMap["created_at"] = model.CreatedAt.String() + } + if model.UpdatedAt != nil { + modelMap["updated_at"] = model.UpdatedAt.String() + } + if model.APIVersion != nil { + modelMap["api_version"] = *model.APIVersion + } + // TODO: Deprecated, to remove + modelMap["encryption_key"] = REDACTED_TEXT + return modelMap, nil +} + +func DataSourceIBMAtrackerTargetsCosEndpointToMap(model *atrackerv2.CosEndpoint) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Endpoint != nil { + modelMap["endpoint"] = *model.Endpoint + } + if model.TargetCRN != nil { + modelMap["target_crn"] = *model.TargetCRN + } + if model.Bucket != nil { + modelMap["bucket"] = *model.Bucket + } + if model.ServiceToServiceEnabled != nil { + modelMap["service_to_service_enabled"] = *model.ServiceToServiceEnabled + } + return modelMap, nil +} + +func DataSourceIBMAtrackerTargetsLogdnaEndpointToMap(model *atrackerv2.LogdnaEndpoint) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TargetCRN != nil { + modelMap["target_crn"] = *model.TargetCRN + } + return modelMap, nil +} + +func DataSourceIBMAtrackerTargetsWriteStatusToMap(model *atrackerv2.WriteStatus) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Status != nil { + modelMap["status"] = *model.Status + } + if model.LastFailure != nil { + modelMap["last_failure"] = model.LastFailure.String() + } + if model.ReasonForLastFailure != nil { + modelMap["reason_for_last_failure"] = *model.ReasonForLastFailure + } + return modelMap, nil +} + +func dataSourceTargetListFlattenTargetsV1(result []atrackerv1.Target) (targets []map[string]interface{}) { + for _, targetsItem := range result { + targets = append(targets, dataSourceTargetListTargetsToMapV1(targetsItem)) + } + + return targets +} + +func dataSourceTargetListTargetsToMapV1(targetsItem atrackerv1.Target) (targetsMap map[string]interface{}) { + targetsMap = map[string]interface{}{} + + if targetsItem.ID != nil { + targetsMap["id"] = targetsItem.ID + } + if targetsItem.Name != nil { + targetsMap["name"] = targetsItem.Name + } + if targetsItem.CRN != nil { + targetsMap["crn"] = targetsItem.CRN + } + if targetsItem.TargetType != nil { + targetsMap["target_type"] = targetsItem.TargetType + } + if targetsItem.EncryptKey != nil { + targetsMap["encrypt_key"] = targetsItem.EncryptKey + } + if targetsItem.CosEndpoint != nil { + cosEndpointList := []map[string]interface{}{} + cosEndpointMap := dataSourceTargetListTargetsCosEndpointToMapV1(*targetsItem.CosEndpoint) + cosEndpointList = append(cosEndpointList, cosEndpointMap) + targetsMap["cos_endpoint"] = cosEndpointList + } + if targetsItem.CosWriteStatus != nil { + cosWriteStatusList := []map[string]interface{}{} + cosWriteStatusMap := dataSourceTargetListTargetsCosWriteStatusToMapV1(*targetsItem.CosWriteStatus) + cosWriteStatusList = append(cosWriteStatusList, cosWriteStatusMap) + targetsMap["cos_write_status"] = cosWriteStatusList + } + if targetsItem.Created != nil { + targetsMap["created"] = targetsItem.Created.String() + } + if targetsItem.Updated != nil { + targetsMap["updated"] = targetsItem.Updated.String() + } + + return targetsMap +} + +func dataSourceTargetListTargetsCosEndpointToMapV1(cosEndpointItem atrackerv1.CosEndpoint) (cosEndpointMap map[string]interface{}) { + cosEndpointMap = map[string]interface{}{} + + if cosEndpointItem.Endpoint != nil { + cosEndpointMap["endpoint"] = cosEndpointItem.Endpoint + } + if cosEndpointItem.TargetCRN != nil { + cosEndpointMap["target_crn"] = cosEndpointItem.TargetCRN + } + if cosEndpointItem.Bucket != nil { + cosEndpointMap["bucket"] = cosEndpointItem.Bucket + } + if cosEndpointItem.APIKey != nil { + cosEndpointMap["api_key"] = cosEndpointItem.APIKey + } + + return cosEndpointMap +} + +func dataSourceTargetListTargetsCosWriteStatusToMapV1(cosWriteStatusItem atrackerv1.CosWriteStatus) (cosWriteStatusMap map[string]interface{}) { + cosWriteStatusMap = map[string]interface{}{} + + if cosWriteStatusItem.Status != nil { + cosWriteStatusMap["status"] = cosWriteStatusItem.Status + } + if cosWriteStatusItem.LastFailure != nil { + cosWriteStatusMap["last_failure"] = cosWriteStatusItem.LastFailure.String() + } + if cosWriteStatusItem.ReasonForLastFailure != nil { + cosWriteStatusMap["reason_for_last_failure"] = cosWriteStatusItem.ReasonForLastFailure + } + + return cosWriteStatusMap +} diff --git a/ibm/service/atracker/data_source_ibm_atracker_targets_test.go b/ibm/service/atracker/data_source_ibm_atracker_targets_test.go new file mode 100644 index 000000000..29689c54d --- /dev/null +++ b/ibm/service/atracker/data_source_ibm_atracker_targets_test.go @@ -0,0 +1,103 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMAtrackerTargetsDataSourceBasic(t *testing.T) { + targetName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + targetTargetType := "cloud_object_storage" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMAtrackerTargetsDataSourceConfigBasic(targetName, targetTargetType), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "id"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.#"), + resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.name", targetName), + resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.target_type", targetTargetType), + ), + }, + }, + }) +} + +func TestAccIBMAtrackerTargetsDataSourceAllArgs(t *testing.T) { + targetName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + targetTargetType := "cloud_object_storage" + targetRegion := "us-south" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMAtrackerTargetsDataSourceConfig(targetName, targetTargetType, targetRegion), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "id"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "name"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.#"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.0.id"), + resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.name", targetName), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.0.crn"), + resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.target_type", targetTargetType), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.0.encryption_key"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_atracker_targets.atracker_targets", "targets.0.updated_at"), + resource.TestCheckResourceAttr("data.ibm_atracker_targets.atracker_targets", "targets.0.api_version", "2"), + ), + }, + }, + }) +} + +func testAccCheckIBMAtrackerTargetsDataSourceConfigBasic(targetName string, targetTargetType string) string { + return fmt.Sprintf(` + resource "ibm_atracker_target" "atracker_target" { + name = "%s" + target_type = "%s" + cos_endpoint { + endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" + target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + bucket = "my-atracker-bucket" + api_key = "xxxxxxxxxxxxxx" + } + } + + data "ibm_atracker_targets" "atracker_targets" { + name = ibm_atracker_target.atracker_target.name + } + `, targetName, targetTargetType) +} + +func testAccCheckIBMAtrackerTargetsDataSourceConfig(targetName string, targetTargetType string, targetRegion string) string { + return fmt.Sprintf(` + resource "ibm_atracker_target" "atracker_target" { + name = "%s" + target_type = "%s" + cos_endpoint { + endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" + target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + bucket = "my-atracker-bucket" + api_key = "xxxxxxxxxxxxxx" + service_to_service_enabled = true + } + } + + data "ibm_atracker_targets" "atracker_targets" { + name = ibm_atracker_target.atracker_target.name + } + `, targetName, targetTargetType) +} diff --git a/ibm/service/atracker/resource_ibm_atracker_route.go b/ibm/service/atracker/resource_ibm_atracker_route.go new file mode 100644 index 000000000..83d967bad --- /dev/null +++ b/ibm/service/atracker/resource_ibm_atracker_route.go @@ -0,0 +1,399 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/atrackerv1" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func ResourceIBMAtrackerRoute() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMAtrackerRouteCreate, + ReadContext: resourceIBMAtrackerRouteRead, + UpdateContext: resourceIBMAtrackerRouteUpdate, + DeleteContext: resourceIBMAtrackerRouteDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_route", "name"), + Description: "The name of the route. The name must be 1000 characters or less and cannot include any special characters other than `(space) - . _ :`.", + }, + "receive_global_events": { + Type: schema.TypeBool, + Optional: true, + Deprecated: "use rules.locations instead", + Description: "Indicates whether or not all global events should be forwarded to this region.", + }, + "rules": { + Type: schema.TypeList, + Required: true, + Description: "Routing rules that will be evaluated in their order of the array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_ids": { + Type: schema.TypeSet, + Required: true, + Description: "The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions. ", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "locations": { + Type: schema.TypeSet, + Optional: true, + Description: "Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the route resource.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "The version of the route.", + }, + "created": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use created_at instead", + Description: "The timestamp of the route creation time.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the route creation time.", + }, + "updated": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use updated_at instead", + Description: "The timestamp of the route last updated time.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the route last updated time.", + }, + "api_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The API version of the route.", + }, + }, + } +} + +func ResourceIBMAtrackerRouteValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9 -._:]+$`, + MinValueLength: 1, + MaxValueLength: 1000, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_atracker_route", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMAtrackerRouteCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + createRouteOptions := &atrackerv2.CreateRouteOptions{} + + createRouteOptions.SetName(d.Get("name").(string)) + var rules []atrackerv2.RulePrototype + for _, e := range d.Get("rules").([]interface{}) { + value := e.(map[string]interface{}) + rulesItem := resourceIBMAtrackerRouteMapToRule(value, d.Get("receive_global_events").(bool)) + rules = append(rules, rulesItem) + } + + createRouteOptions.SetRules(rules) + + route, response, err := atrackerClient.CreateRouteWithContext(context, createRouteOptions) + if err != nil { + log.Printf("[DEBUG] CreateRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateRouteWithContext failed %s\n%s", err, response)) + } + + d.SetId(*route.ID) + d.Set("api_version", 2) + + return resourceIBMAtrackerRouteRead(context, d, meta) +} + +func resourceIBMAtrackerRouteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClientv1, atrackerClient, err := getAtrackerClients(meta) + // We need both route methods to ensure backwards compatibility and the ability to migrate + if err != nil { + return diag.FromErr(err) + } + + getRouteOptions := &atrackerv2.GetRouteOptions{} + getRouteOptions.SetID(d.Id()) + apiVersion := d.Get("api_version") + + // Try v2 first, otherwise try v1 + route, response, err := atrackerClient.GetRouteWithContext(context, getRouteOptions) + + if err != nil && response != nil && response.StatusCode != 404 { + log.Printf("[DEBUG] GetRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetRouteWithContext failed %s\n%s", err, response)) + } + if err == nil && response != nil { + if err = d.Set("name", route.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + rules := make([]map[string]interface{}, len(route.Rules), len(route.Rules)) + for i, rulesItem := range route.Rules { + rulesItemMap, _, _ := resourceIBMAtrackerRouteRulePrototypeToMap(&rulesItem) + rules[i] = rulesItemMap + } + if err = d.Set("rules", rules); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rules: %s", err)) + } + if err = d.Set("crn", route.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("version", flex.IntValue(route.Version)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(route.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(route.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("api_version", flex.IntValue(route.APIVersion)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting api_version: %s", err)) + } + d.Set("receive_global_events", false) + } else if apiVersion != 2 { + getRouteV1Options := &atrackerv1.GetRouteOptions{} + getRouteV1Options.SetID(d.Id()) + routeV1, responseV1, err := atrackerClientv1.GetRouteWithContext(context, getRouteV1Options) + if err != nil { + if response != nil && responseV1.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetRouteWithContext failed %s\n%s", err, responseV1) + return diag.FromErr(fmt.Errorf("GetRouteWithContext failed %s\n%s", err, responseV1)) + } + if err = d.Set("name", routeV1.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + rules := []map[string]interface{}{} + for _, rulesItem := range routeV1.Rules { + rulesItemMap, _ := resourceIBMAtrackerRouteRulePrototypeToMapV1(&rulesItem) + rules = append(rules, rulesItemMap) + } + if err = d.Set("rules", rules); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rules: %s", err)) + } + if err = d.Set("crn", routeV1.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("receive_global_events", routeV1.ReceiveGlobalEvents); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("version", flex.IntValue(routeV1.Version)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(routeV1.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(routeV1.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("api_version", 1); err != nil { + return diag.FromErr(fmt.Errorf("Error setting api_version: %s", err)) + } + } + + return nil +} + +func resourceIBMAtrackerRouteUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClientV1, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + apiVersion := d.Get("api_version").(int) + + if apiVersion > 1 { + replaceRouteOptions := &atrackerv2.ReplaceRouteOptions{} + + replaceRouteOptions.SetID(d.Id()) + replaceRouteOptions.SetName(d.Get("name").(string)) + + var rules []atrackerv2.RulePrototype = make([]atrackerv2.RulePrototype, 0) + for _, e := range d.Get("rules").([]interface{}) { + value := e.(map[string]interface{}) + rulesItem := resourceIBMAtrackerRouteMapToRule(value, d.Get("receive_global_events").(bool)) + rules = append(rules, rulesItem) + } + replaceRouteOptions.SetRules(rules) + + _, response, err := atrackerClient.ReplaceRouteWithContext(context, replaceRouteOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceRouteWithContext failed %s\n%s", err, response)) + } + return resourceIBMAtrackerRouteRead(context, d, meta) + } + // TODO: to remove once version 1 is fully deprecated + replaceRouteOptionsV1 := &atrackerv1.ReplaceRouteOptions{} + replaceRouteOptionsV1.SetID(d.Id()) + replaceRouteOptionsV1.SetName(d.Get("name").(string)) + replaceRouteOptionsV1.SetReceiveGlobalEvents(d.Get("receive_global_events").(bool)) + + var rules []atrackerv1.Rule = make([]atrackerv1.Rule, 0) + for _, e := range d.Get("rules").([]interface{}) { + value := e.(map[string]interface{}) + rulesItem := resourceIBMAtrackerRouteMapToRuleV1(value) + rules = append(rules, rulesItem) + } + replaceRouteOptionsV1.SetRules(rules) + + _, response, err := atrackerClientV1.ReplaceRouteWithContext(context, replaceRouteOptionsV1) + if err != nil { + log.Printf("[DEBUG] ReplaceRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceRouteWithContext failed %s\n%s", err, response)) + } + + return resourceIBMAtrackerRouteRead(context, d, meta) +} + +func resourceIBMAtrackerRouteDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClientV1, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + apiVersion := d.Get("api_version").(int) + + if apiVersion > 1 { + deleteRouteOptions := &atrackerv2.DeleteRouteOptions{} + + deleteRouteOptions.SetID(d.Id()) + + response, err := atrackerClient.DeleteRouteWithContext(context, deleteRouteOptions) + if err != nil { + log.Printf("[DEBUG] DeleteRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteRouteWithContext failed %s\n%s", err, response)) + } + } else { + deleteRouteOptions := &atrackerv1.DeleteRouteOptions{} + + deleteRouteOptions.SetID(d.Id()) + + response, err := atrackerClientV1.DeleteRouteWithContext(context, deleteRouteOptions) + if err != nil { + log.Printf("[DEBUG] DeleteRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteRouteWithContext failed %s\n%s", err, response)) + } + } + + d.SetId("") + + return nil +} + +func resourceIBMAtrackerRouteRulePrototypeToMap(ruleModel *atrackerv2.Rule) (map[string]interface{}, bool, error) { + receives_global_events := false + ruleMap := make(map[string]interface{}) + if ruleModel != nil { + ruleMap["target_ids"] = make([]string, len(ruleModel.TargetIds)) + if ruleModel.TargetIds != nil { + for i, target_id := range ruleModel.TargetIds { + ruleMap["target_ids"].([]string)[i] = target_id + } + } + + ruleMap["locations"] = make([]string, len(ruleModel.Locations)) + if ruleModel.Locations != nil { + for i, location := range ruleModel.Locations { + ruleMap["locations"].([]string)[i] = location + if strings.Contains(location, "*") || strings.Contains(location, "global") { + receives_global_events = true + } + } + } + return ruleMap, receives_global_events, nil + } + return ruleMap, false, nil +} + +func resourceIBMAtrackerRouteRulePrototypeToMapV1(model *atrackerv1.Rule) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["target_ids"] = model.TargetIds + return modelMap, nil +} + +func resourceIBMAtrackerRouteMapToRule(ruleMap map[string]interface{}, addGlobalFlag bool) atrackerv2.RulePrototype { + rule := atrackerv2.RulePrototype{} + + targetIds := make([]string, 0) + for _, targetIdsItem := range ruleMap["target_ids"].(*schema.Set).List() { + if targetIdsItem != nil { + targetIds = append(targetIds, targetIdsItem.(string)) + } + } + rule.TargetIds = targetIds + + locations := make([]string, 0) + globalDetected := false + for _, locationsItem := range ruleMap["locations"].(*schema.Set).List() { + if strings.Contains(locationsItem.(string), "*") || strings.Contains(locationsItem.(string), "global") { + globalDetected = true + } + locations = append(locations, locationsItem.(string)) + } + + if addGlobalFlag && !globalDetected { + locations = append(locations, "global") + } + rule.Locations = locations + + return rule +} + +func resourceIBMAtrackerRouteMapToRuleV1(ruleMap map[string]interface{}) atrackerv1.Rule { + rule := atrackerv1.Rule{} + + targetIds := []string{} + for _, targetIdsItem := range ruleMap["target_ids"].(*schema.Set).List() { + targetIds = append(targetIds, targetIdsItem.(string)) + } + rule.TargetIds = targetIds + + return rule +} diff --git a/ibm/service/atracker/resource_ibm_atracker_route_test.go b/ibm/service/atracker/resource_ibm_atracker_route_test.go new file mode 100644 index 000000000..ea29002c4 --- /dev/null +++ b/ibm/service/atracker/resource_ibm_atracker_route_test.go @@ -0,0 +1,126 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func TestAccIBMAtrackerRouteBasic(t *testing.T) { + var conf atrackerv2.Route + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAtrackerRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMAtrackerRouteConfigBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMAtrackerRouteExists("ibm_atracker_route.atracker_route", conf), + resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "name", name), + ), + }, + { + Config: testAccCheckIBMAtrackerRouteConfigBasic(nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_atracker_route.atracker_route", "name", nameUpdate), + ), + }, + { + ResourceName: "ibm_atracker_route.atracker_route", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMAtrackerRouteConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_atracker_target" "atracker_target" { + name = "my-cos-target" + target_type = "cloud_object_storage" + cos_endpoint { + endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" + target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + bucket = "my-atracker-bucket" + api_key = "xxxxxxxxxxxxxx" + } + } + + resource "ibm_atracker_route" "atracker_route" { + name = "%s" + rules { + target_ids = [ ibm_atracker_target.atracker_target.id ] + locations = [ "us-south" ] + } + } + `, name) +} + +func testAccCheckIBMAtrackerRouteExists(n string, obj atrackerv2.Route) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() + if err != nil { + return err + } + + getRouteOptions := &atrackerv2.GetRouteOptions{} + + getRouteOptions.SetID(rs.Primary.ID) + + route, _, err := atrackerClient.GetRoute(getRouteOptions) + if err != nil { + return err + } + + obj = *route + return nil + } +} + +func testAccCheckIBMAtrackerRouteDestroy(s *terraform.State) error { + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_atracker_route" { + continue + } + + getRouteOptions := &atrackerv2.GetRouteOptions{} + + getRouteOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := atrackerClient.GetRoute(getRouteOptions) + + if err == nil { + return fmt.Errorf("Activity Tracker Route still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for Activity Tracker Route (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/atracker/resource_ibm_atracker_settings.go b/ibm/service/atracker/resource_ibm_atracker_settings.go new file mode 100644 index 000000000..b92192292 --- /dev/null +++ b/ibm/service/atracker/resource_ibm_atracker_settings.go @@ -0,0 +1,247 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func ResourceIBMAtrackerSettings() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMAtrackerSettingsCreate, + ReadContext: resourceIBMAtrackerSettingsRead, + UpdateContext: resourceIBMAtrackerSettingsUpdate, + DeleteContext: resourceIBMAtrackerSettingsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "metadata_region_primary": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_settings", "metadata_region_primary"), + Description: "To store all your meta data in a single region.", + }, + "private_api_endpoint_only": { + Type: schema.TypeBool, + Required: true, + Description: "If you set this true then you cannot access api through public network.", + }, + "default_targets": { + Type: schema.TypeList, + Optional: true, + Description: "The target ID List. In the event that no routing rule causes the event to be sent to a target, these targets will receive the event.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "permitted_target_regions": { + Type: schema.TypeList, + Optional: true, + Description: "If present then only these regions may be used to define a target.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "metadata_region_backup": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_settings", "metadata_region_backup"), + Description: "Provide a back up region to store meta data.", + }, + "api_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest API version of targets or routes that customer might have under his or her account.", + }, + }, + } +} + +func ResourceIBMAtrackerSettingsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "metadata_region_primary", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9 -_]`, + MinValueLength: 3, + MaxValueLength: 256, + }, + validate.ValidateSchema{ + Identifier: "metadata_region_backup", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 -_]*`, + MinValueLength: 0, + MaxValueLength: 256, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_atracker_settings", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMAtrackerSettingsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClient, err := meta.(conns.ClientSession).AtrackerV2() + if err != nil { + return diag.FromErr(err) + } + + putSettingsOptions := &atrackerv2.PutSettingsOptions{} + + putSettingsOptions.SetMetadataRegionPrimary(d.Get("metadata_region_primary").(string)) + putSettingsOptions.SetPrivateAPIEndpointOnly(d.Get("private_api_endpoint_only").(bool)) + if _, ok := d.GetOk("default_targets"); ok { + putSettingsOptions.SetDefaultTargets(resourceInterfaceToStringArray(d.Get("default_targets").([]interface{}))) + } + if _, ok := d.GetOk("permitted_target_regions"); ok { + putSettingsOptions.SetPermittedTargetRegions(resourceInterfaceToStringArray(d.Get("permitted_target_regions").([]interface{}))) + } + if _, ok := d.GetOk("metadata_region_backup"); ok { + putSettingsOptions.SetMetadataRegionBackup(d.Get("metadata_region_backup").(string)) + } + + settings, response, err := atrackerClient.PutSettingsWithContext(context, putSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PutSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PutSettingsWithContext failed %s\n%s", err, response)) + } + + d.SetId(*settings.MetadataRegionPrimary) + + return resourceIBMAtrackerSettingsRead(context, d, meta) +} + +func resourceIBMAtrackerSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + getSettingsOptions := &atrackerv2.GetSettingsOptions{} + + settings, response, err := atrackerClient.GetSettingsWithContext(context, getSettingsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSettingsWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("metadata_region_primary", settings.MetadataRegionPrimary); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata_region_primary: %s", err)) + } + if err = d.Set("private_api_endpoint_only", settings.PrivateAPIEndpointOnly); err != nil { + return diag.FromErr(fmt.Errorf("Error setting private_api_endpoint_only: %s", err)) + } + if settings.DefaultTargets != nil { + if err = d.Set("default_targets", settings.DefaultTargets); err != nil { + return diag.FromErr(fmt.Errorf("Error setting default_targets: %s", err)) + } + } + if settings.PermittedTargetRegions != nil { + if err = d.Set("permitted_target_regions", settings.PermittedTargetRegions); err != nil { + return diag.FromErr(fmt.Errorf("Error setting permitted_target_regions: %s", err)) + } + } + if err = d.Set("metadata_region_backup", settings.MetadataRegionBackup); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata_region_backup: %s", err)) + } + if err = d.Set("api_version", flex.IntValue(settings.APIVersion)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting api_version: %s", err)) + } + + return nil +} + +func resourceIBMAtrackerSettingsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClient, err := meta.(conns.ClientSession).AtrackerV2() + if err != nil { + return diag.FromErr(err) + } + + putSettingsOptions := &atrackerv2.PutSettingsOptions{} + + hasChange := false + newMetaDataRegionPrimary := d.Get("metadata_region_primary").(string) + putSettingsOptions.SetMetadataRegionPrimary(newMetaDataRegionPrimary) + putSettingsOptions.SetPrivateAPIEndpointOnly(d.Get("private_api_endpoint_only").(bool)) + hasChange = hasChange || d.HasChange("metadata_region_primary") || d.HasChange("private_api_endpoint_only") || d.HasChange("metadata_region_primary") || d.HasChange("permitted_target_regions") || d.HasChange("default_targets") || d.HasChange("metadata_region_backup") + + if d.HasChange("metadata_region_primary") { + d.SetId(newMetaDataRegionPrimary) + } + putSettingsOptions.DefaultTargets = resourceInterfaceToStringArray(d.Get("default_targets").([]interface{})) + + putSettingsOptions.PermittedTargetRegions = resourceInterfaceToStringArray(d.Get("permitted_target_regions").([]interface{})) + + if d.HasChange("metadata_region_backup") { + putSettingsOptions.SetMetadataRegionBackup(d.Get("metadata_region_backup").(string)) + hasChange = true + } + + if hasChange { + setting, response, err := atrackerClient.PutSettingsWithContext(context, putSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PutSettingsWithContext failed %s\n%s", err, response) + log.Printf("[DEBUG] PutSettingsWithContext failed %v\n", putSettingsOptions) + return diag.FromErr(fmt.Errorf("PutSettingsWithContext failed %s\n%s", err, response)) + } + d.SetId(*setting.MetadataRegionPrimary) + } + + return resourceIBMAtrackerSettingsRead(context, d, meta) +} + +func resourceInterfaceToStringArray(resources []interface{}) (result []string) { + result = make([]string, 0) + for _, item := range resources { + if item != nil { + result = append(result, item.(string)) + } else { + result = append(result, "") + } + } + return result +} + +func resourceIBMAtrackerSettingsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + atrackerClient, err := meta.(conns.ClientSession).AtrackerV2() + if err != nil { + return diag.FromErr(err) + } + + // Retrieve old settings and put them for required fields. Remove all other fields + settings, getResponse, err := atrackerClient.GetSettingsWithContext(context, &atrackerv2.GetSettingsOptions{}) + if err != nil { + log.Printf("[DEBUG] PutSettingsWithContext with GetSettingsWithContext failed %s\n%s", err, getResponse) + return diag.FromErr(fmt.Errorf("GetSettingsWithContext failed %s\n%s", err, getResponse)) + } + putSettingsOptions := &atrackerv2.PutSettingsOptions{} + + putSettingsOptions.MetadataRegionPrimary = settings.MetadataRegionPrimary + putSettingsOptions.PrivateAPIEndpointOnly = settings.PrivateAPIEndpointOnly + putSettingsOptions.PermittedTargetRegions = []string{} + putSettingsOptions.DefaultTargets = []string{} + + _, response, err := atrackerClient.PutSettingsWithContext(context, putSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PutSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PutSettingsWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/atracker/resource_ibm_atracker_settings_test.go b/ibm/service/atracker/resource_ibm_atracker_settings_test.go new file mode 100644 index 000000000..07d7ad0ef --- /dev/null +++ b/ibm/service/atracker/resource_ibm_atracker_settings_test.go @@ -0,0 +1,123 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +func TestAccIBMAtrackerSettingsBasic(t *testing.T) { + var conf atrackerv2.Settings + metadataRegionPrimary := "us-east" + privateAPIEndpointOnly := "false" + metadataRegionPrimaryUpdate := "us-south" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMAtrackerSettingsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMAtrackerSettingsConfigBasic(metadataRegionPrimary, + "", privateAPIEndpointOnly), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMAtrackerSettingsExists("ibm_atracker_settings.atracker_settings", conf), + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_primary", metadataRegionPrimary), + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_backup", ""), + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "private_api_endpoint_only", privateAPIEndpointOnly), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMAtrackerSettingsConfigBasic(metadataRegionPrimaryUpdate, + metadataRegionPrimary, privateAPIEndpointOnly), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_primary", metadataRegionPrimaryUpdate), + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_backup", metadataRegionPrimary), + resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "private_api_endpoint_only", privateAPIEndpointOnly), + ), + }, + }, + }) +} + +func testAccCheckIBMAtrackerSettingsConfigBasic(metadataRegionPrimary string, + metadataRegionBackup string, privateAPIEndpointOnly string) string { + return fmt.Sprintf(` + resource "ibm_atracker_target" "atracker_target" { + name = "my-cos-target" + target_type = "cloud_object_storage" + cos_endpoint { + endpoint = "s3.private.us-east.cloud-object-storage.appdomain.cloud" + target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + bucket = "my-atracker-bucket" + api_key = "xxxxxxxxxxxxxx" # pragma: whitelist secret + service_to_service_enabled = false + } + } + + resource "ibm_atracker_settings" "atracker_settings" { + metadata_region_primary = "%s" + metadata_region_backup = "%s" + private_api_endpoint_only = %s + } + `, metadataRegionPrimary, + metadataRegionBackup, privateAPIEndpointOnly) +} + +func testAccCheckIBMAtrackerSettingsExists(n string, obj atrackerv2.Settings) resource.TestCheckFunc { + + return func(s *terraform.State) error { + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() + if err != nil { + return err + } + + getSettingsOptions := &atrackerv2.GetSettingsOptions{} + + settings, _, err := atrackerClient.GetSettings(getSettingsOptions) + if err != nil { + return err + } + + obj = *settings + return nil + } +} + +func testAccCheckIBMAtrackerSettingsDestroy(s *terraform.State) error { + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_atracker_settings" { + continue + } + + getSettingsOptions := &atrackerv2.GetSettingsOptions{} + + // Try to find the key + settings, response, err := atrackerClient.GetSettings(getSettingsOptions) + + if err == nil { + // Settings can never really truely be deleted (at least for MetaRegionPrimary) but the other fields will be cleared + if *settings.MetadataRegionPrimary == rs.Primary.ID && len(*&settings.DefaultTargets) == 0 && len(*&settings.DefaultTargets) == 0 { + return nil + } + return fmt.Errorf("[ERROR] Activity Tracker Settings still exists but other fields not deleted: %s, Targets: %v, PermittedRegions: %v", rs.Primary.ID, *&settings.DefaultTargets, *&settings.PermittedTargetRegions) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for Activity Tracker Settings (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/atracker/resource_ibm_atracker_target.go b/ibm/service/atracker/resource_ibm_atracker_target.go new file mode 100644 index 000000000..026d50f74 --- /dev/null +++ b/ibm/service/atracker/resource_ibm_atracker_target.go @@ -0,0 +1,500 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package atracker + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/atrackerv2" +) + +const COS_CRN_PARTS = 8 + +func ResourceIBMAtrackerTarget() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMAtrackerTargetCreate, + ReadContext: resourceIBMAtrackerTargetRead, + UpdateContext: resourceIBMAtrackerTargetUpdate, + DeleteContext: resourceIBMAtrackerTargetDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_target", "name"), + Description: "The name of the target. The name must be 1000 characters or less, and cannot include any special characters other than `(space) - . _ :`.", + }, + "target_type": { + Type: schema.TypeString, + DiffSuppressFunc: flex.ApplyOnce, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_target", "target_type"), + Description: "The type of the target. It can be cloud_object_storage or logdna. Based on this type you must include cos_endpoint or logdna_endpoint.", + }, + "cos_endpoint": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Property values for a Cloud Object Storage Endpoint.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Required: true, + Description: "The host name of the Cloud Object Storage endpoint.", + }, + "target_crn": { + Type: schema.TypeString, + Required: true, + Description: "The CRN of the Cloud Object Storage instance.", + }, + "bucket": { + Type: schema.TypeString, + Required: true, + Description: "The bucket name under the Cloud Object Storage instance.", + }, + "api_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled.", + DiffSuppressFunc: flex.ApplyOnce, + }, + "service_to_service_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: "ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey.", + }, + }, + }, + }, + "logdna_endpoint": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Property values for a LogDNA Endpoint.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_crn": { + Type: schema.TypeString, + Required: true, + Description: "The CRN of the LogDNA instance.", + }, + "ingestion_key": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "The LogDNA ingestion key is used for routing logs to a specific LogDNA instance.", + }, + }, + }, + }, + "region": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_atracker_target", "region"), + Description: "Include this optional field if you want to create a target in a different region other than the one you are connected.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the target resource.", + }, + "encrypt_key": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use encryption_key instead", + Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + }, + "encryption_key": { + Type: schema.TypeString, + Computed: true, + Description: "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + }, + "cos_write_status": { + Type: schema.TypeList, + Computed: true, + Deprecated: "use write_status instead", + Description: "The status of the write attempt with the provided cos_endpoint parameters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Optional: true, + Description: "The status such as failed or success.", + }, + "last_failure": { + Type: schema.TypeString, + Optional: true, + Description: "The timestamp of the failure.", + }, + "reason_for_last_failure": { + Type: schema.TypeString, + Optional: true, + Description: "Detailed description of the cause of the failure.", + }, + }, + }, + }, + "write_status": { + Type: schema.TypeList, + Computed: true, + Description: "The status of the write attempt to the target with the provided endpoint parameters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Required: true, + Description: "The status such as failed or success.", + }, + "last_failure": { + Type: schema.TypeString, + Optional: true, + Description: "The timestamp of the failure.", + }, + "reason_for_last_failure": { + Type: schema.TypeString, + Optional: true, + Description: "Detailed description of the cause of the failure.", + }, + }, + }, + }, + "created": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use created_at instead", + Description: "The timestamp of the target creation time.", + }, + "updated": { + Type: schema.TypeString, + Computed: true, + Deprecated: "use updated_at instead", + Description: "The timestamp of the target last updated time.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the target creation time.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp of the target last updated time.", + }, + "api_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The API version of the target.", + }, + }, + } +} + +func ResourceIBMAtrackerTargetValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9 -._:]+$`, + MinValueLength: 1, + MaxValueLength: 1000, + }, + validate.ValidateSchema{ + Identifier: "target_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "cloud_object_storage, logdna", + }, + validate.ValidateSchema{ + Identifier: "region", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 -._:]+$`, + MinValueLength: 3, + MaxValueLength: 1000, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_atracker_target", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMAtrackerTargetCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + createTargetOptions := &atrackerv2.CreateTargetOptions{} + + createTargetOptions.SetName(d.Get("name").(string)) + createTargetOptions.SetTargetType(d.Get("target_type").(string)) + if _, ok := d.GetOk("cos_endpoint"); ok { + cosEndpointModel, err := resourceIBMAtrackerTargetMapToCosEndpointPrototype(d.Get("cos_endpoint.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTargetOptions.SetCosEndpoint(cosEndpointModel) + } + if _, ok := d.GetOk("logdna_endpoint"); ok { + logdnaEndpointModel, err := resourceIBMAtrackerTargetMapToLogdnaEndpointPrototype(d.Get("logdna_endpoint.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTargetOptions.SetLogdnaEndpoint(logdnaEndpointModel) + } + if _, ok := d.GetOk("region"); ok { + createTargetOptions.SetRegion(d.Get("region").(string)) + } + + target, response, err := atrackerClient.CreateTargetWithContext(context, createTargetOptions) + if err != nil { + log.Printf("[DEBUG] CreateTargetWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTargetWithContext failed %s\n%s", err, response)) + } + + d.SetId(*target.ID) + + return resourceIBMAtrackerTargetRead(context, d, meta) +} + +func resourceIBMAtrackerTargetRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + getTargetOptions := &atrackerv2.GetTargetOptions{} + + getTargetOptions.SetID(d.Id()) + + target, response, err := atrackerClient.GetTargetWithContext(context, getTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTargetWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTargetWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("name", target.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("target_type", target.TargetType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting target_type: %s", err)) + } + // Don't report difference if the last parts of CRN are different + if target.CosEndpoint != nil { + cosEndpointMap, err := resourceIBMAtrackerTargetCosEndpointPrototypeToMap(target.CosEndpoint) + if cosInterface, ok := d.GetOk("cos_endpoint.0"); ok { + targetCrnExisting := cosInterface.(map[string]interface{})["target_crn"].(string) + targetCrnIncoming := cosEndpointMap["target_crn"].(*string) + if len(targetCrnExisting) > 0 && targetCrnIncoming != nil { + targetCrnExistingParts := strings.Split(targetCrnExisting, ":") + targetCrnIncomingParts := strings.Split(*targetCrnIncoming, ":") + isDifferent := false + for i := 0; i < COS_CRN_PARTS && len(targetCrnExistingParts) > COS_CRN_PARTS-1 && len(targetCrnIncomingParts) > COS_CRN_PARTS-1; i++ { + if targetCrnExistingParts[i] != targetCrnIncomingParts[i] { + isDifferent = true + } + } + if !isDifferent { + cosEndpointMap["target_crn"] = targetCrnExisting + } + } + } + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("cos_endpoint", []map[string]interface{}{cosEndpointMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cos_endpoint: %s", err)) + } + } + if target.LogdnaEndpoint != nil { + logdnaEndpointMap, err := resourceIBMAtrackerTargetLogdnaEndpointPrototypeToMap(target.LogdnaEndpoint) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("logdna_endpoint", []map[string]interface{}{logdnaEndpointMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting logdna_endpoint: %s", err)) + } + } + + if target.CRN != nil { + if err = d.Set("crn", target.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + } + + if _, exists := d.GetOk("region"); exists { + if target.Region != nil && len(*target.Region) > 0 { + d.Set("region", *target.Region) + if err = d.Set("region", *target.Region); err != nil { + return diag.FromErr(fmt.Errorf("Error setting region: %s", err)) + } + } + } + + writeStatusMap, err := resourceIBMAtrackerTargetWriteStatusToMap(target.WriteStatus) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("write_status", []map[string]interface{}{writeStatusMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting write_status: %s", err)) + } + + // TODO: will be removed + if err = d.Set("cos_write_status", []map[string]interface{}{writeStatusMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cos_write_status: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(target.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(target.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("api_version", flex.IntValue(target.APIVersion)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting api_version: %s", err)) + } + + return nil +} + +func resourceIBMAtrackerTargetUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + replaceTargetOptions := &atrackerv2.ReplaceTargetOptions{} + + replaceTargetOptions.SetID(d.Id()) + + hasChange := false + + if d.HasChange("name") || d.HasChange("cos_endpoint") || d.HasChange("region") || d.HasChange("logdna_endpoint") { + replaceTargetOptions.SetName(d.Get("name").(string)) + + _, hasCosEndpoint := d.GetOk("cos_endpoint.0") + if hasCosEndpoint { + cosEndpoint, err := resourceIBMAtrackerTargetMapToCosEndpointPrototype(d.Get("cos_endpoint.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceTargetOptions.SetCosEndpoint(cosEndpoint) + } + + _, hasLogDNAEndpoint := d.GetOk("logdna_endpoint.0") + if hasLogDNAEndpoint { + logdnaEndpoint, err := resourceIBMAtrackerTargetMapToLogdnaEndpointPrototype(d.Get("logdna_endpoint.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceTargetOptions.SetLogdnaEndpoint(logdnaEndpoint) + } + hasChange = true + } + + if hasChange { + _, response, err := atrackerClient.ReplaceTargetWithContext(context, replaceTargetOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceTargetWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceTargetWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMAtrackerTargetRead(context, d, meta) +} + +func resourceIBMAtrackerTargetDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, atrackerClient, err := getAtrackerClients(meta) + if err != nil { + return diag.FromErr(err) + } + + deleteTargetOptions := &atrackerv2.DeleteTargetOptions{} + + deleteTargetOptions.SetID(d.Id()) + + _, response, err := atrackerClient.DeleteTargetWithContext(context, deleteTargetOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTargetWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTargetWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMAtrackerTargetMapToCosEndpointPrototype(modelMap map[string]interface{}) (*atrackerv2.CosEndpointPrototype, error) { + model := &atrackerv2.CosEndpointPrototype{} + model.Endpoint = core.StringPtr(modelMap["endpoint"].(string)) + model.TargetCRN = core.StringPtr(modelMap["target_crn"].(string)) + model.Bucket = core.StringPtr(modelMap["bucket"].(string)) + if modelMap["api_key"] != nil && modelMap["api_key"].(string) != "" { + model.APIKey = core.StringPtr(modelMap["api_key"].(string)) + } + model.ServiceToServiceEnabled = core.BoolPtr(modelMap["service_to_service_enabled"].(bool)) + return model, nil +} + +func resourceIBMAtrackerTargetMapToLogdnaEndpointPrototype(modelMap map[string]interface{}) (*atrackerv2.LogdnaEndpointPrototype, error) { + model := &atrackerv2.LogdnaEndpointPrototype{} + model.TargetCRN = core.StringPtr(modelMap["target_crn"].(string)) + model.IngestionKey = core.StringPtr(modelMap["ingestion_key"].(string)) // pragma: whitelist secret + return model, nil +} + +func resourceIBMAtrackerTargetCosEndpointPrototypeToMap(model *atrackerv2.CosEndpoint) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["endpoint"] = model.Endpoint + modelMap["target_crn"] = model.TargetCRN + modelMap["bucket"] = model.Bucket + // TODO: remove after deprecation + modelMap["api_key"] = REDACTED_TEXT // pragma: whitelist secret + modelMap["service_to_service_enabled"] = model.ServiceToServiceEnabled + return modelMap, nil +} + +func resourceIBMAtrackerTargetLogdnaEndpointPrototypeToMap(model *atrackerv2.LogdnaEndpoint) (map[string]interface{}, error) { + + modelMap := make(map[string]interface{}) + modelMap["target_crn"] = model.TargetCRN + modelMap["ingestion_key"] = REDACTED_TEXT // pragma: whitelist secret + return modelMap, nil +} + +func resourceIBMAtrackerTargetWriteStatusToMap(model *atrackerv2.WriteStatus) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["status"] = model.Status + if model.LastFailure != nil { + modelMap["last_failure"] = model.LastFailure.String() + } + if model.ReasonForLastFailure != nil { + modelMap["reason_for_last_failure"] = model.ReasonForLastFailure + } + return modelMap, nil +} diff --git a/ibm/resource_ibm_atracker_target_test.go b/ibm/service/atracker/resource_ibm_atracker_target_test.go similarity index 78% rename from ibm/resource_ibm_atracker_target_test.go rename to ibm/service/atracker/resource_ibm_atracker_target_test.go index 16d33e1c9..d09a726f7 100644 --- a/ibm/resource_ibm_atracker_target_test.go +++ b/ibm/service/atracker/resource_ibm_atracker_target_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package atracker_test import ( "fmt" @@ -11,21 +11,23 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/IBM/platform-services-go-sdk/atrackerv1" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/atrackerv2" ) func TestAccIBMAtrackerTargetBasic(t *testing.T) { - var conf atrackerv1.Target + var conf atrackerv2.Target name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) targetType := "cloud_object_storage" nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAtrackerTargetDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAtrackerTargetConfigBasic(name, targetType), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAtrackerTargetExists("ibm_atracker_target.atracker_target", conf), @@ -33,15 +35,14 @@ func TestAccIBMAtrackerTargetBasic(t *testing.T) { resource.TestCheckResourceAttr("ibm_atracker_target.atracker_target", "target_type", targetType), ), }, - - resource.TestStep{ + { Config: testAccCheckIBMAtrackerTargetConfigBasic(nameUpdate, targetType), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_atracker_target.atracker_target", "name", nameUpdate), resource.TestCheckResourceAttr("ibm_atracker_target.atracker_target", "target_type", targetType), ), }, - resource.TestStep{ + { ResourceName: "ibm_atracker_target.atracker_target", ImportState: true, ImportStateVerify: true, @@ -61,12 +62,13 @@ func testAccCheckIBMAtrackerTargetConfigBasic(name string, targetType string) st target_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" bucket = "my-atracker-bucket" api_key = "xxxxxxxxxxxxxx" + service_to_service_enabled = false } } `, name, targetType) } -func testAccCheckIBMAtrackerTargetExists(n string, obj atrackerv1.Target) resource.TestCheckFunc { +func testAccCheckIBMAtrackerTargetExists(n string, obj atrackerv2.Target) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -74,12 +76,12 @@ func testAccCheckIBMAtrackerTargetExists(n string, obj atrackerv1.Target) resour return fmt.Errorf("Not found: %s", n) } - atrackerClient, err := testAccProvider.Meta().(ClientSession).AtrackerV1() + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() if err != nil { return err } - getTargetOptions := &atrackerv1.GetTargetOptions{} + getTargetOptions := &atrackerv2.GetTargetOptions{} getTargetOptions.SetID(rs.Primary.ID) @@ -94,7 +96,7 @@ func testAccCheckIBMAtrackerTargetExists(n string, obj atrackerv1.Target) resour } func testAccCheckIBMAtrackerTargetDestroy(s *terraform.State) error { - atrackerClient, err := testAccProvider.Meta().(ClientSession).AtrackerV1() + atrackerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AtrackerV2() if err != nil { return err } @@ -103,7 +105,7 @@ func testAccCheckIBMAtrackerTargetDestroy(s *terraform.State) error { continue } - getTargetOptions := &atrackerv1.GetTargetOptions{} + getTargetOptions := &atrackerv2.GetTargetOptions{} getTargetOptions.SetID(rs.Primary.ID) @@ -113,7 +115,7 @@ func testAccCheckIBMAtrackerTargetDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Activity Tracker Target still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for Activity Tracker Target (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for Activity Tracker Target (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/catalogmanagement/README.md b/ibm/service/catalogmanagement/README.md new file mode 100644 index 000000000..44642b14b --- /dev/null +++ b/ibm/service/catalogmanagement/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cm_catalog) +* IBM API Docs: [IBM API Docs for ]() +* IBM SDK: [IBM SDK for ](https://github.com/IBM/appconfiguration-go-admin-sdk/tree/master/catalogmanagementv1) diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_catalog.go b/ibm/service/catalogmanagement/data_source_ibm_cm_catalog.go new file mode 100644 index 000000000..6ad165080 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_catalog.go @@ -0,0 +1,710 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func DataSourceIBMCmCatalog() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCmCatalogRead, + + Schema: map[string]*schema.Schema{ + "catalog_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Catalog identifier.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique ID.", + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display Name in the requested language.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description in the requested language.", + }, + "short_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "catalog_icon_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for an icon associated with this catalog.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The url for this specific catalog.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN associated with the catalog.", + }, + "offerings_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL path to offerings.", + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of features associated with this catalog.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes whether a catalog is disabled.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date-time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date-time this catalog was last updated.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group id the catalog is owned by.", + }, + "owning_account": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Account that owns catalog.", + }, + "catalog_filters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Filters for account and catalog filters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "include_all": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "-> true - Include all of the public catalog when filtering. Further settings will specifically exclude some offerings. false - Exclude all of the public catalog when filtering. Further settings will specifically include some offerings.", + }, + "category_filters": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Filter against offering properties.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id_filters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Filter on offering ID's. There is an include filter and an exclule filter. Both can be set.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "include": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering filter terms.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter_terms": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "exclude": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering filter terms.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter_terms": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "syndication_settings": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "remove_related_components": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Remove related components.", + }, + "clusters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Syndication clusters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster region.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster name.", + }, + "resource_group_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Syndication type.", + }, + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Syndicated namespaces.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "all_namespaces": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Syndicated to all namespaces on cluster.", + }, + }, + }, + }, + "history": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Array of syndicated namespaces.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "clusters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Array of syndicated namespaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster region.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cluster name.", + }, + "resource_group_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Syndication type.", + }, + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Syndicated namespaces.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "all_namespaces": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Syndicated to all namespaces on cluster.", + }, + }, + }, + }, + "last_run": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time last syndicated.", + }, + }, + }, + }, + "authorization": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Array of syndicated namespaces.", + }, + "last_run": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time last updated.", + }, + }, + }, + }, + }, + }, + }, + "kind": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kind of catalog. Supported kinds are offering and vpe.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Catalog specific metadata.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMCmCatalogRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} + + getCatalogOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + + catalog, response, err := catalogManagementClient.GetCatalogWithContext(context, getCatalogOptions) + if err != nil { + log.Printf("[DEBUG] GetCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCatalogWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getCatalogOptions.CatalogIdentifier)) + + if err = d.Set("id", catalog.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + } + + if err = d.Set("rev", catalog.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + + if err = d.Set("label", catalog.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + + if catalog.LabelI18n != nil { + if err = d.Set("label_i18n", catalog.LabelI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting label_i18n %s", err)) + } + } + + if err = d.Set("short_description", catalog.ShortDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) + } + + if catalog.ShortDescriptionI18n != nil { + if err = d.Set("short_description_i18n", catalog.ShortDescriptionI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description_i18n %s", err)) + } + } + + if err = d.Set("catalog_icon_url", catalog.CatalogIconURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_icon_url: %s", err)) + } + + if err = d.Set("url", catalog.URL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + } + + if err = d.Set("crn", catalog.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("offerings_url", catalog.OfferingsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offerings_url: %s", err)) + } + + features := []map[string]interface{}{} + if catalog.Features != nil { + for _, modelItem := range catalog.Features { + modelMap, err := dataSourceIBMCmCatalogFeatureToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + features = append(features, modelMap) + } + } + if err = d.Set("features", features); err != nil { + return diag.FromErr(fmt.Errorf("Error setting features %s", err)) + } + + if err = d.Set("disabled", catalog.Disabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disabled: %s", err)) + } + + if err = d.Set("created", flex.DateTimeToString(catalog.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + + if err = d.Set("updated", flex.DateTimeToString(catalog.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + + if err = d.Set("resource_group_id", catalog.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("owning_account", catalog.OwningAccount); err != nil { + return diag.FromErr(fmt.Errorf("Error setting owning_account: %s", err)) + } + + catalogFilters := []map[string]interface{}{} + if catalog.CatalogFilters != nil { + modelMap, err := dataSourceIBMCmCatalogFiltersToMap(catalog.CatalogFilters) + if err != nil { + return diag.FromErr(err) + } + catalogFilters = append(catalogFilters, modelMap) + } + if err = d.Set("catalog_filters", catalogFilters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_filters %s", err)) + } + + syndicationSettings := []map[string]interface{}{} + if catalog.SyndicationSettings != nil { + modelMap, err := dataSourceIBMCmCatalogSyndicationResourceToMap(catalog.SyndicationSettings) + if err != nil { + return diag.FromErr(err) + } + syndicationSettings = append(syndicationSettings, modelMap) + } + if err = d.Set("syndication_settings", syndicationSettings); err != nil { + return diag.FromErr(fmt.Errorf("Error setting syndication_settings %s", err)) + } + + if err = d.Set("kind", catalog.Kind); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kind: %s", err)) + } + + if catalog.Metadata != nil { + convertedMap := make(map[string]interface{}, len(catalog.Metadata)) + for k, v := range catalog.Metadata { + convertedMap[k] = v + } + + if err = d.Set("metadata", flex.Flatten(convertedMap)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + } + } + + return nil +} + +func dataSourceIBMCmCatalogFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = *model.Title + } + if model.TitleI18n != nil { + titleI18nMap := make(map[string]interface{}, len(model.TitleI18n)) + for k, v := range model.TitleI18n { + titleI18nMap[k] = v + } + modelMap["title_i18n"] = flex.Flatten(titleI18nMap) + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogFiltersToMap(model *catalogmanagementv1.Filters) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.IncludeAll != nil { + modelMap["include_all"] = *model.IncludeAll + } + if model.CategoryFilters != nil { + categoryFiltersMap := make(map[string]interface{}, len(model.CategoryFilters)) + // for k, v := range model.CategoryFilters { + // // TODO: add code to handle a map of model instances! + // } + modelMap["category_filters"] = flex.Flatten(categoryFiltersMap) + } + if model.IDFilters != nil { + idFiltersMap, err := dataSourceIBMCmCatalogIDFilterToMap(model.IDFilters) + if err != nil { + return modelMap, err + } + modelMap["id_filters"] = []map[string]interface{}{idFiltersMap} + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogCategoryFilterToMap(model *catalogmanagementv1.CategoryFilter) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Include != nil { + modelMap["include"] = *model.Include + } + if model.Filter != nil { + filterMap, err := dataSourceIBMCmCatalogFilterTermsToMap(model.Filter) + if err != nil { + return modelMap, err + } + modelMap["filter"] = []map[string]interface{}{filterMap} + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogFilterTermsToMap(model *catalogmanagementv1.FilterTerms) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.FilterTerms != nil { + modelMap["filter_terms"] = model.FilterTerms + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogIDFilterToMap(model *catalogmanagementv1.IDFilter) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Include != nil { + includeMap, err := dataSourceIBMCmCatalogFilterTermsToMap(model.Include) + if err != nil { + return modelMap, err + } + modelMap["include"] = []map[string]interface{}{includeMap} + } + if model.Exclude != nil { + excludeMap, err := dataSourceIBMCmCatalogFilterTermsToMap(model.Exclude) + if err != nil { + return modelMap, err + } + modelMap["exclude"] = []map[string]interface{}{excludeMap} + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogSyndicationResourceToMap(model *catalogmanagementv1.SyndicationResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.RemoveRelatedComponents != nil { + modelMap["remove_related_components"] = *model.RemoveRelatedComponents + } + if model.Clusters != nil { + clusters := []map[string]interface{}{} + for _, clustersItem := range model.Clusters { + clustersItemMap, err := dataSourceIBMCmCatalogSyndicationClusterToMap(&clustersItem) + if err != nil { + return modelMap, err + } + clusters = append(clusters, clustersItemMap) + } + modelMap["clusters"] = clusters + } + if model.History != nil { + historyMap, err := dataSourceIBMCmCatalogSyndicationHistoryToMap(model.History) + if err != nil { + return modelMap, err + } + modelMap["history"] = []map[string]interface{}{historyMap} + } + if model.Authorization != nil { + authorizationMap, err := dataSourceIBMCmCatalogSyndicationAuthorizationToMap(model.Authorization) + if err != nil { + return modelMap, err + } + modelMap["authorization"] = []map[string]interface{}{authorizationMap} + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogSyndicationClusterToMap(model *catalogmanagementv1.SyndicationCluster) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Region != nil { + modelMap["region"] = *model.Region + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceGroupName != nil { + modelMap["resource_group_name"] = *model.ResourceGroupName + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Namespaces != nil { + modelMap["namespaces"] = model.Namespaces + } + if model.AllNamespaces != nil { + modelMap["all_namespaces"] = *model.AllNamespaces + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogSyndicationHistoryToMap(model *catalogmanagementv1.SyndicationHistory) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Namespaces != nil { + modelMap["namespaces"] = model.Namespaces + } + if model.Clusters != nil { + clusters := []map[string]interface{}{} + for _, clustersItem := range model.Clusters { + clustersItemMap, err := dataSourceIBMCmCatalogSyndicationClusterToMap(&clustersItem) + if err != nil { + return modelMap, err + } + clusters = append(clusters, clustersItemMap) + } + modelMap["clusters"] = clusters + } + if model.LastRun != nil { + modelMap["last_run"] = model.LastRun.String() + } + return modelMap, nil +} + +func dataSourceIBMCmCatalogSyndicationAuthorizationToMap(model *catalogmanagementv1.SyndicationAuthorization) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Token != nil { + modelMap["token"] = *model.Token + } + if model.LastRun != nil { + modelMap["last_run"] = model.LastRun.String() + } + return modelMap, nil +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_catalog_test.go b/ibm/service/catalogmanagement/data_source_ibm_cm_catalog_test.go new file mode 100644 index 000000000..ab7f6549c --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_catalog_test.go @@ -0,0 +1,77 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCmCatalogDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmCatalogDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog", "catalog_identifier"), + ), + }, + }, + }) +} + +func TestAccIBMCmCatalogDataSourceSimpleArgs(t *testing.T) { + catalogLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + catalogShortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmCatalogDataSourceConfig(catalogLabel, catalogShortDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog", "catalog_identifier"), + resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog", "label"), + resource.TestCheckResourceAttrSet("data.ibm_cm_catalog.cm_catalog", "short_description"), + ), + }, + }, + }) +} + +func testAccCheckIBMCmCatalogDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "basic-catalog-label-test" + kind = "offering" + } + + data "ibm_cm_catalog" "cm_catalog" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + } + `) +} + +func testAccCheckIBMCmCatalogDataSourceConfig(catalogLabel string, catalogShortDescription string) string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "%s" + short_description = "%s" + kind = "offering" + } + + data "ibm_cm_catalog" "cm_catalog" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + } + `, catalogLabel, catalogShortDescription) +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_offering.go b/ibm/service/catalogmanagement/data_source_ibm_cm_offering.go new file mode 100644 index 000000000..439734d19 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_offering.go @@ -0,0 +1,3996 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func DataSourceIBMCmOffering() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCmOfferingRead, + + Schema: map[string]*schema.Schema{ + "catalog_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Catalog identifier.", + }, + "offering_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Offering identifier. Provide this when an offering already exists and you wish to use it as a terraform resource.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The url for this specific offering.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The crn for this specific offering.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display Name in the requested language.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programmatic name of this offering.", + }, + "offering_icon_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for an icon associated with this offering.", + }, + "offering_docs_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for an additional docs with this offering.", + }, + "offering_support_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "[deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "keywords": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of keywords associated with offering, typically used to search for it.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "rating": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Repository info for offerings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "one_star_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "One start rating.", + }, + "two_star_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Two start rating.", + }, + "three_star_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Three start rating.", + }, + "four_star_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Four start rating.", + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was last updated.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Short description in the requested language.", + }, + "short_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description in the requested language.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "kinds": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Array of kind.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique ID.", + }, + "format_kind": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "content kind, e.g., helm, vm image.", + }, + "install_kind": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "install kind, e.g., helm, operator, terraform.", + }, + "target_kind": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "target cloud to install, e.g., iks, open_shift_iks.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "additional_features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was last updated.", + }, + "versions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of versions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique ID.", + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version's CRN.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of content type.", + }, + "flavor": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Version Flavor Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic name for this flavor.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Label for this flavor.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "index": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Order that this flavor should appear when listed for a single version.", + }, + }, + }, + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "hash of the content.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was last updated.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Offering ID.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Catalog ID.", + }, + "kind_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kind ID.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's repo URL.", + }, + "source_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's source URL (e.g git repo).", + }, + "tgz_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "File used to on-board this version.", + }, + "configuration": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of user solicited overrides.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Configuration key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Value type (string, boolean, int).", + }, + // "default_value": &schema.Schema{ + // Type: schema.TypeMap, + // Computed: true, + // Description: "The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`.", + // }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display name for configuration type.", + }, + "value_constraint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Constraint associated with value, e.g., for string type - regx:[a-z].", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key description.", + }, + "required": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is key required to install.", + }, + "options": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of options of type.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Hide values.", + }, + "custom_config": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Render type.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the widget type.", + }, + "grouping": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment).", + }, + "original_grouping": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Original grouping type for this configuration (3 types - Target, Resource, and Deployment).", + }, + "grouping_index": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Determines the order that this configuration item shows in that particular grouping.", + }, + "config_constraints": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Map of constraint parameters that will be passed to the custom widget.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "associations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of parameters that are associated with this configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Parameters for this association.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of this parameter.", + }, + "options_refresh": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Refresh options.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "type_metadata": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The original type, as found in the source being onboarded.", + }, + }, + }, + }, + "outputs": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of output values for this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Output key.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Output description.", + }, + }, + }, + }, + "iam_permissions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of IAM permissions that are required to consume this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Service name.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources for this permission.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource description.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "metadata": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Generic data to be included with content being onboarded. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version source URL.", + }, + "version_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version name.", + }, + "terraform_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Terraform version.", + }, + "validated_terraform_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version name.", + }, + "vsi_vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "VSI VPC version information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operating_system": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "operating_system": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "validation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Validation response.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "validated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of last successful validation.", + }, + "requested": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of last validation was requested.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current validation state - , in_progress, valid, invalid, expired.", + }, + "last_operation": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Last operation (e.g. submit_deployment, generate_installer, install_offering.", + }, + "target": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Any message needing to be conveyed as part of the validation job.", + }, + }, + }, + }, + "required_resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resource requirments for installation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of requirement.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value.", + }, + }, + }, + }, + "single_instance": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if single instance can be deployed to a given cluster.", + }, + "install": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Script information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "pre_install": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Optional pre-install instructions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "entitlement": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Entitlement license info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Provider name.", + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Provider ID.", + }, + "product_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Product ID.", + }, + "part_numbers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Image repository name.", + }, + }, + }, + }, + "licenses": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of licenses the product was built with.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "License ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "license name.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "type of license e.g., Apache xxx.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for the license text.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "License description.", + }, + }, + }, + }, + "image_manifest_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If set, denotes a url to a YAML file with list of container images used by this version.", + }, + "deprecated": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "read only field, indicating if this version is deprecated.", + }, + "package_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of the package used to create this version.", + }, + "state": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering state.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "current_entered": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of current request.", + }, + "pending": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "pending_requested": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of pending request.", + }, + "previous": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + }, + }, + }, + "version_locator": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dotted value of `catalogID`.`versionID`.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description for version.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "whitelisted_accounts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Whitelisted accounts for version.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_pull_key_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the image pull key to use from Offering.ImagePullKeys.", + }, + "deprecate_pending": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Deprecation information for an Offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deprecate_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date of deprecation.", + }, + "deprecate_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Deprecation state.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "solution_info": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Version Solution Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "architecture_diagrams": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Architecture diagrams for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "diagram": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering Media information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of this diagram.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Features - titles only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "cost_estimate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost estimate definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost estimate version.", + }, + "currency": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost estimate currency.", + }, + "projects": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost estimate projects.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Project name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Project metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "past_breakdown": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "breakdown": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "diff": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "past_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Past total hourly cost.", + }, + "past_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Past total monthly cost.", + }, + "diff_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Difference in total hourly cost.", + }, + "diff_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Difference in total monthly cost.", + }, + "time_generated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "When this estimate was generated.", + }, + }, + }, + }, + "dependencies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Dependencies for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - If not specified, assumes the Public Catalog.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - Offering ID - not required if name is set.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - Programmatic Offering name.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Required - Semver value or range.", + }, + "flavors": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Optional - List of dependent flavors in the specified range.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "is_consumable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is the version able to be shared.", + }, + }, + }, + }, + "plans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of plans.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "unique id.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display Name in the requested language.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programmatic name of this offering.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Short description in the requested language.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description in the requested language.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "additional_features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "the date'time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "the date'time this catalog was last updated.", + }, + "deployments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of deployments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "unique id.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display Name in the requested language.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programmatic name of this offering.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Short description in the requested language.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description in the requested language.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "the date'time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "the date'time this catalog was last updated.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "pc_managed": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Offering is managed by Partner Center.", + }, + "publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Offering has been approved to publish to permitted to IBM or Public Catalog.", + }, + "share_with_all": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes public availability of an Offering - if share_enabled is true.", + }, + "share_with_ibm": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes IBM employee availability of an Offering - if share_enabled is true.", + }, + "share_enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes sharing including access list availability of an Offering is enabled.", + }, + "publish_to_access_list": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of account IDs to add to this offering's access list.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "publish_to_ibm": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Whether you would like to publish this offering to IBM or not.", + }, + "publish_to_public": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Whether you would like to publish this offering to the public catalog or not.", + }, + "permit_request_ibm_public_publish": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Deprecated: "This argument is deprecated", + Description: "Is it permitted to request publishing to IBM or Public.", + }, + "ibm_publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Deprecated: "This argument is deprecated", + Description: "Indicates if this offering has been approved for use by all IBMers.", + }, + "public_publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Deprecated: "This argument is deprecated", + Description: "Indicates if this offering has been approved for use by all IBM Cloud users.", + }, + "public_original_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The original offering CRN that this publish entry came from.", + }, + "publish_public_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The crn of the public catalog entry of this offering.", + }, + "portal_approval_record": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The portal's approval record ID.", + }, + "portal_ui_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The portal UI URL.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the catalog containing this offering.", + }, + "catalog_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the catalog.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Map of metadata values for this offering.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "disclaimer": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A disclaimer for this offering.", + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determine if this offering should be displayed in the Consumption UI.", + }, + // "provider": &schema.Schema{ + // Type: schema.TypeString, + // Computed: true, + // Deprecated: "This argument is deprecated", + // Description: "Deprecated - Provider of this offering.", + // }, + "provider_info": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on the provider for this offering, or omitted if no provider information is given.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of this provider.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of this provider.", + }, + }, + }, + }, + "repo_info": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Repository info for offerings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Token for private repos.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Public or enterprise GitHub.", + }, + }, + }, + }, + "image_pull_keys": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Image pull keys for this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key value.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key description.", + }, + }, + }, + }, + "support": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering Support information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL to be displayed in the Consumption UI for getting support on this offering.", + }, + "process": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Support process as provided by an ISV.", + }, + "process_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "locations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of country codes indicating where support is provided.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "support_details": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of support options (e.g. email, phone, slack, other).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the current support detail.", + }, + "contact": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Contact for the current support detail.", + }, + "response_wait_time": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "availability": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Times when support is available.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "times": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of support times.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "day": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The day of the week, represented as an integer.", + }, + "start_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00).", + }, + "end_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00).", + }, + }, + }, + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Timezone (e.g. America/New_York).", + }, + "always_available": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is this support always available.", + }, + }, + }, + }, + }, + }, + }, + "support_escalation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Support escalation policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "escalation_wait_time": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "response_wait_time": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "contact": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Escalation contact.", + }, + }, + }, + }, + "support_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Support type for this product.", + }, + }, + }, + }, + "media": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of media items related to this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "deprecate_pending": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Deprecation information for an Offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deprecate_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date of deprecation.", + }, + "deprecate_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Deprecation state.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "product_kind": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The product kind. Valid values are module, solution, or empty string.", + }, + "badges": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of badges for this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the current badge.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display name for the current badge.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of the current badge.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "icon": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Icon for the current badge.", + }, + "authority": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authority for the current badge.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tag for the current badge.", + }, + "learn_more_links": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Learn more links for a badge.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "first_party": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "First party link.", + }, + "third_party": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Third party link.", + }, + }, + }, + }, + "constraints": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "An optional set of constraints indicating which versions in an Offering have this particular badge.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the current constraint.", + }, + "rule": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Rule for the current constraint.", + }, + }, + }, + }, + }, + }, + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "unique id.", + }, + }, + } +} + +func dataSourceIBMCmOfferingRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + getOfferingOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + getOfferingOptions.SetOfferingID(d.Get("offering_identifier").(string)) + + offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getOfferingOptions.CatalogIdentifier, *getOfferingOptions.OfferingID)) + + if err = d.Set("rev", offering.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + + if err = d.Set("offering_id", offering.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + + if err = d.Set("url", offering.URL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + } + + if err = d.Set("crn", offering.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("label", offering.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + + if offering.LabelI18n != nil { + if err = d.Set("label_i18n", offering.LabelI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting label_i18n %s", err)) + } + } + + if err = d.Set("name", offering.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("offering_icon_url", offering.OfferingIconURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_icon_url: %s", err)) + } + + if err = d.Set("offering_docs_url", offering.OfferingDocsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_docs_url: %s", err)) + } + + if err = d.Set("offering_support_url", offering.OfferingSupportURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_support_url: %s", err)) + } + + rating := []map[string]interface{}{} + if offering.Rating != nil { + modelMap, err := dataSourceIBMCmOfferingRatingToMap(offering.Rating) + if err != nil { + return diag.FromErr(err) + } + rating = append(rating, modelMap) + } + if err = d.Set("rating", rating); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rating %s", err)) + } + + if err = d.Set("created", flex.DateTimeToString(offering.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + + if err = d.Set("updated", flex.DateTimeToString(offering.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + + if err = d.Set("short_description", offering.ShortDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) + } + + if offering.ShortDescriptionI18n != nil { + if err = d.Set("short_description_i18n", offering.ShortDescriptionI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description_i18n %s", err)) + } + } + + if err = d.Set("long_description", offering.LongDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) + } + + if offering.LongDescriptionI18n != nil { + if err = d.Set("long_description_i18n", offering.LongDescriptionI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description_i18n %s", err)) + } + } + + features := []map[string]interface{}{} + if offering.Features != nil { + for _, modelItem := range offering.Features { + modelMap, err := dataSourceIBMCmOfferingFeatureToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + features = append(features, modelMap) + } + } + if err = d.Set("features", features); err != nil { + return diag.FromErr(fmt.Errorf("Error setting features %s", err)) + } + + kinds := []map[string]interface{}{} + if offering.Kinds != nil { + for _, modelItem := range offering.Kinds { + modelMap, err := dataSourceIBMCmOfferingKindToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + kinds = append(kinds, modelMap) + } + } + if err = d.Set("kinds", kinds); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kinds %s", err)) + } + + if err = d.Set("pc_managed", offering.PcManaged); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pc_managed: %s", err)) + } + + if err = d.Set("publish_approved", offering.PublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting publish_approved: %s", err)) + } + + if err = d.Set("share_with_all", offering.ShareWithAll); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_with_all: %s", err)) + } + + if err = d.Set("share_with_ibm", offering.ShareWithIBM); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_with_ibm: %s", err)) + } + + if err = d.Set("share_enabled", offering.ShareEnabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_enabled: %s", err)) + } + + if err = d.Set("permit_request_ibm_public_publish", offering.PermitRequestIBMPublicPublish); err != nil { + return diag.FromErr(fmt.Errorf("Error setting permit_request_ibm_public_publish: %s", err)) + } + + if err = d.Set("ibm_publish_approved", offering.IBMPublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_publish_approved: %s", err)) + } + + if err = d.Set("public_publish_approved", offering.PublicPublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting public_publish_approved: %s", err)) + } + + if err = d.Set("public_original_crn", offering.PublicOriginalCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting public_original_crn: %s", err)) + } + + if err = d.Set("publish_public_crn", offering.PublishPublicCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting publish_public_crn: %s", err)) + } + + if err = d.Set("portal_approval_record", offering.PortalApprovalRecord); err != nil { + return diag.FromErr(fmt.Errorf("Error setting portal_approval_record: %s", err)) + } + + if err = d.Set("portal_ui_url", offering.PortalUIURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting portal_ui_url: %s", err)) + } + + if err = d.Set("catalog_id", offering.CatalogID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) + } + + if err = d.Set("catalog_name", offering.CatalogName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_name: %s", err)) + } + + if offering.Metadata != nil { + convertedMap := make(map[string]interface{}, len(offering.Metadata)) + for k, v := range offering.Metadata { + convertedMap[k] = v + } + + if err = d.Set("metadata", flex.Flatten(convertedMap)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + } + } + + if err = d.Set("disclaimer", offering.Disclaimer); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disclaimer: %s", err)) + } + + if err = d.Set("hidden", offering.Hidden); err != nil { + return diag.FromErr(fmt.Errorf("Error setting hidden: %s", err)) + } + + // if err = d.Set("provider", offering.Provider); err != nil { + // return diag.FromErr(fmt.Errorf("Error setting provider: %s", err)) + // } + + providerInfo := []map[string]interface{}{} + if offering.ProviderInfo != nil { + modelMap, err := dataSourceIBMCmOfferingProviderInfoToMap(offering.ProviderInfo) + if err != nil { + return diag.FromErr(err) + } + providerInfo = append(providerInfo, modelMap) + } + if err = d.Set("provider_info", providerInfo); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provider_info %s", err)) + } + + repoInfo := []map[string]interface{}{} + if offering.RepoInfo != nil { + modelMap, err := dataSourceIBMCmOfferingRepoInfoToMap(offering.RepoInfo) + if err != nil { + return diag.FromErr(err) + } + repoInfo = append(repoInfo, modelMap) + } + if err = d.Set("repo_info", repoInfo); err != nil { + return diag.FromErr(fmt.Errorf("Error setting repo_info %s", err)) + } + + imagePullKeys := []map[string]interface{}{} + if offering.ImagePullKeys != nil { + for _, modelItem := range offering.ImagePullKeys { + modelMap, err := dataSourceIBMCmOfferingImagePullKeyToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + imagePullKeys = append(imagePullKeys, modelMap) + } + } + if err = d.Set("image_pull_keys", imagePullKeys); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_pull_keys %s", err)) + } + + support := []map[string]interface{}{} + if offering.Support != nil { + modelMap, err := dataSourceIBMCmOfferingSupportToMap(offering.Support) + if err != nil { + return diag.FromErr(err) + } + support = append(support, modelMap) + } + if err = d.Set("support", support); err != nil { + return diag.FromErr(fmt.Errorf("Error setting support %s", err)) + } + + media := []map[string]interface{}{} + if offering.Media != nil { + for _, modelItem := range offering.Media { + modelMap, err := dataSourceIBMCmOfferingMediaItemToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + media = append(media, modelMap) + } + } + if err = d.Set("media", media); err != nil { + return diag.FromErr(fmt.Errorf("Error setting media %s", err)) + } + + deprecatePending := []map[string]interface{}{} + if offering.DeprecatePending != nil { + modelMap, err := dataSourceIBMCmOfferingDeprecatePendingToMap(offering.DeprecatePending) + if err != nil { + return diag.FromErr(err) + } + deprecatePending = append(deprecatePending, modelMap) + } + if err = d.Set("deprecate_pending", deprecatePending); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deprecate_pending %s", err)) + } + + if err = d.Set("product_kind", offering.ProductKind); err != nil { + return diag.FromErr(fmt.Errorf("Error setting product_kind: %s", err)) + } + + badges := []map[string]interface{}{} + if offering.Badges != nil { + for _, modelItem := range offering.Badges { + modelMap, err := dataSourceIBMCmOfferingBadgeToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + badges = append(badges, modelMap) + } + } + if err = d.Set("badges", badges); err != nil { + return diag.FromErr(fmt.Errorf("Error setting badges %s", err)) + } + + return nil +} + +func dataSourceIBMCmOfferingRatingToMap(model *catalogmanagementv1.Rating) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.OneStarCount != nil { + modelMap["one_star_count"] = *model.OneStarCount + } + if model.TwoStarCount != nil { + modelMap["two_star_count"] = *model.TwoStarCount + } + if model.ThreeStarCount != nil { + modelMap["three_star_count"] = *model.ThreeStarCount + } + if model.FourStarCount != nil { + modelMap["four_star_count"] = *model.FourStarCount + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = *model.Title + } + if model.TitleI18n != nil { + titleI18nMap := make(map[string]interface{}, len(model.TitleI18n)) + for k, v := range model.TitleI18n { + titleI18nMap[k] = v + } + modelMap["title_i18n"] = flex.Flatten(titleI18nMap) + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingKindToMap(model *catalogmanagementv1.Kind) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.FormatKind != nil { + modelMap["format_kind"] = *model.FormatKind + } + if model.InstallKind != nil { + modelMap["install_kind"] = *model.InstallKind + } + if model.TargetKind != nil { + modelMap["target_kind"] = *model.TargetKind + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // k, v unused + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.AdditionalFeatures != nil { + additionalFeatures := []map[string]interface{}{} + for _, additionalFeaturesItem := range model.AdditionalFeatures { + additionalFeaturesItemMap, err := dataSourceIBMCmOfferingFeatureToMap(&additionalFeaturesItem) + if err != nil { + return modelMap, err + } + additionalFeatures = append(additionalFeatures, additionalFeaturesItemMap) + } + modelMap["additional_features"] = additionalFeatures + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.Versions != nil { + versions := []map[string]interface{}{} + for _, versionsItem := range model.Versions { + versionsItemMap, err := dataSourceIBMCmOfferingVersionToMap(&versionsItem) + if err != nil { + return modelMap, err + } + versions = append(versions, versionsItemMap) + } + modelMap["versions"] = versions + } + if model.Plans != nil { + plans := []map[string]interface{}{} + for _, plansItem := range model.Plans { + plansItemMap, err := dataSourceIBMCmOfferingPlanToMap(&plansItem) + if err != nil { + return modelMap, err + } + plans = append(plans, plansItemMap) + } + modelMap["plans"] = plans + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingVersionToMap(model *catalogmanagementv1.Version) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Rev != nil { + modelMap["rev"] = *model.Rev + } + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Flavor != nil { + flavorMap, err := dataSourceIBMCmOfferingFlavorToMap(model.Flavor) + if err != nil { + return modelMap, err + } + modelMap["flavor"] = []map[string]interface{}{flavorMap} + } + if model.Sha != nil { + modelMap["sha"] = *model.Sha + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.OfferingID != nil { + modelMap["offering_id"] = *model.OfferingID + } + if model.CatalogID != nil { + modelMap["catalog_id"] = *model.CatalogID + } + if model.KindID != nil { + modelMap["kind_id"] = *model.KindID + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.RepoURL != nil { + modelMap["repo_url"] = *model.RepoURL + } + if model.SourceURL != nil { + modelMap["source_url"] = *model.SourceURL + } + if model.TgzURL != nil { + modelMap["tgz_url"] = *model.TgzURL + } + if model.Configuration != nil { + configuration := []map[string]interface{}{} + for _, configurationItem := range model.Configuration { + configurationItemMap, err := dataSourceIBMCmOfferingConfigurationToMap(&configurationItem) + if err != nil { + return modelMap, err + } + configuration = append(configuration, configurationItemMap) + } + modelMap["configuration"] = configuration + } + if model.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range model.Outputs { + outputsItemMap, err := dataSourceIBMCmOfferingOutputToMap(&outputsItem) + if err != nil { + return modelMap, err + } + outputs = append(outputs, outputsItemMap) + } + modelMap["outputs"] = outputs + } + if model.IamPermissions != nil { + iamPermissions := []map[string]interface{}{} + for _, iamPermissionsItem := range model.IamPermissions { + iamPermissionsItemMap, err := dataSourceIBMCmOfferingIamPermissionToMap(&iamPermissionsItem) + if err != nil { + return modelMap, err + } + iamPermissions = append(iamPermissions, iamPermissionsItemMap) + } + modelMap["iam_permissions"] = iamPermissions + } + // if model.Metadata != nil { + // metadataSlice := []map[string]interface{}{model.Metadata} + // modelMap["metadata"] = metadataSlice + // } + metadata := []map[string]interface{}{} + if model.Metadata != nil { + var modelMapVSI map[string]interface{} + var err error + if model.Metadata["vsi_vpc"] != nil { + modelMapVSI, err = dataSourceIBMCmVersionMetadataVSIToMap(model.Metadata["vsi_vpc"].(map[string]interface{})) + if err != nil { + return nil, err + } + } + convertedMap := make(map[string]interface{}, len(model.Metadata)) + for k, v := range model.Metadata { + if k == "vsi_vpc" { + convertedMap[k] = []map[string]interface{}{modelMapVSI} + } else { + convertedMap[k] = v + } + } + metadata = append(metadata, convertedMap) + } + modelMap["metadata"] = metadata + if model.Validation != nil { + validationMap, err := dataSourceIBMCmOfferingValidationToMap(model.Validation) + if err != nil { + return modelMap, err + } + modelMap["validation"] = []map[string]interface{}{validationMap} + } + if model.RequiredResources != nil { + requiredResources := []map[string]interface{}{} + for _, requiredResourcesItem := range model.RequiredResources { + requiredResourcesItemMap, err := dataSourceIBMCmOfferingResourceToMap(&requiredResourcesItem) + if err != nil { + return modelMap, err + } + requiredResources = append(requiredResources, requiredResourcesItemMap) + } + modelMap["required_resources"] = requiredResources + } + if model.SingleInstance != nil { + modelMap["single_instance"] = *model.SingleInstance + } + if model.Install != nil { + installMap, err := dataSourceIBMCmOfferingScriptToMap(model.Install) + if err != nil { + return modelMap, err + } + modelMap["install"] = []map[string]interface{}{installMap} + } + if model.PreInstall != nil { + preInstall := []map[string]interface{}{} + for _, preInstallItem := range model.PreInstall { + preInstallItemMap, err := dataSourceIBMCmOfferingScriptToMap(&preInstallItem) + if err != nil { + return modelMap, err + } + preInstall = append(preInstall, preInstallItemMap) + } + modelMap["pre_install"] = preInstall + } + if model.Entitlement != nil { + entitlementMap, err := dataSourceIBMCmOfferingVersionEntitlementToMap(model.Entitlement) + if err != nil { + return modelMap, err + } + modelMap["entitlement"] = []map[string]interface{}{entitlementMap} + } + if model.Licenses != nil { + licenses := []map[string]interface{}{} + for _, licensesItem := range model.Licenses { + licensesItemMap, err := dataSourceIBMCmOfferingLicenseToMap(&licensesItem) + if err != nil { + return modelMap, err + } + licenses = append(licenses, licensesItemMap) + } + modelMap["licenses"] = licenses + } + if model.ImageManifestURL != nil { + modelMap["image_manifest_url"] = *model.ImageManifestURL + } + if model.Deprecated != nil { + modelMap["deprecated"] = *model.Deprecated + } + if model.PackageVersion != nil { + modelMap["package_version"] = *model.PackageVersion + } + if model.State != nil { + stateMap, err := dataSourceIBMCmOfferingStateToMap(model.State) + if err != nil { + return modelMap, err + } + modelMap["state"] = []map[string]interface{}{stateMap} + } + if model.VersionLocator != nil { + modelMap["version_locator"] = *model.VersionLocator + } + if model.LongDescription != nil { + modelMap["long_description"] = *model.LongDescription + } + if model.LongDescriptionI18n != nil { + longDescriptionI18nMap := make(map[string]interface{}, len(model.LongDescriptionI18n)) + for k, v := range model.LongDescriptionI18n { + longDescriptionI18nMap[k] = v + } + modelMap["long_description_i18n"] = flex.Flatten(longDescriptionI18nMap) + } + if model.WhitelistedAccounts != nil { + modelMap["whitelisted_accounts"] = model.WhitelistedAccounts + } + if model.ImagePullKeyName != nil { + modelMap["image_pull_key_name"] = *model.ImagePullKeyName + } + if model.DeprecatePending != nil { + deprecatePendingMap, err := dataSourceIBMCmOfferingDeprecatePendingToMap(model.DeprecatePending) + if err != nil { + return modelMap, err + } + modelMap["deprecate_pending"] = []map[string]interface{}{deprecatePendingMap} + } + if model.SolutionInfo != nil { + solutionInfoMap, err := dataSourceIBMCmOfferingSolutionInfoToMap(model.SolutionInfo) + if err != nil { + return modelMap, err + } + modelMap["solution_info"] = []map[string]interface{}{solutionInfoMap} + } + if model.IsConsumable != nil { + modelMap["is_consumable"] = *model.IsConsumable + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingFlavorToMap(model *catalogmanagementv1.Flavor) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Label != nil { + modelMap["label"] = *model.Label + } + if model.LabelI18n != nil { + labelI18nMap := make(map[string]interface{}, len(model.LabelI18n)) + for k, v := range model.LabelI18n { + labelI18nMap[k] = v + } + modelMap["label_i18n"] = flex.Flatten(labelI18nMap) + } + if model.Index != nil { + modelMap["index"] = *model.Index + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingConfigurationToMap(model *catalogmanagementv1.Configuration) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.DefaultValue != nil { + } + if model.DisplayName != nil { + modelMap["display_name"] = *model.DisplayName + } + if model.ValueConstraint != nil { + modelMap["value_constraint"] = *model.ValueConstraint + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.Required != nil { + modelMap["required"] = *model.Required + } + if model.Options != nil { + } + if model.Hidden != nil { + modelMap["hidden"] = *model.Hidden + } + if model.CustomConfig != nil { + customConfigMap, err := dataSourceIBMCmOfferingRenderTypeToMap(model.CustomConfig) + if err != nil { + return modelMap, err + } + modelMap["custom_config"] = []map[string]interface{}{customConfigMap} + } + if model.TypeMetadata != nil { + modelMap["type_metadata"] = *model.TypeMetadata + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingRenderTypeToMap(model *catalogmanagementv1.RenderType) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Grouping != nil { + modelMap["grouping"] = *model.Grouping + } + if model.OriginalGrouping != nil { + modelMap["original_grouping"] = *model.OriginalGrouping + } + if model.GroupingIndex != nil { + modelMap["grouping_index"] = *model.GroupingIndex + } + // if model.ConfigConstraints != nil { + // configConstraintsMap := make(map[string]interface{}, len(model.ConfigConstraints)) + // for k, v := range model.ConfigConstraints { + // } + // modelMap["config_constraints"] = flex.Flatten(configConstraintsMap) + // } + if model.Associations != nil { + associationsMap, err := dataSourceIBMCmOfferingRenderTypeAssociationsToMap(model.Associations) + if err != nil { + return modelMap, err + } + modelMap["associations"] = []map[string]interface{}{associationsMap} + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingRenderTypeAssociationsToMap(model *catalogmanagementv1.RenderTypeAssociations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Parameters != nil { + parameters := []map[string]interface{}{} + for _, parametersItem := range model.Parameters { + parametersItemMap, err := dataSourceIBMCmOfferingRenderTypeAssociationsParametersItemToMap(¶metersItem) + if err != nil { + return modelMap, err + } + parameters = append(parameters, parametersItemMap) + } + modelMap["parameters"] = parameters + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingRenderTypeAssociationsParametersItemToMap(model *catalogmanagementv1.RenderTypeAssociationsParametersItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.OptionsRefresh != nil { + modelMap["options_refresh"] = *model.OptionsRefresh + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingOutputToMap(model *catalogmanagementv1.Output) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingIamPermissionToMap(model *catalogmanagementv1.IamPermission) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ServiceName != nil { + modelMap["service_name"] = *model.ServiceName + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := dataSourceIBMCmOfferingIamResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingIamResourceToMap(model *catalogmanagementv1.IamResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingValidationToMap(model *catalogmanagementv1.Validation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Validated != nil { + modelMap["validated"] = model.Validated.String() + } + if model.Requested != nil { + modelMap["requested"] = model.Requested.String() + } + if model.State != nil { + modelMap["state"] = *model.State + } + if model.LastOperation != nil { + modelMap["last_operation"] = *model.LastOperation + } + if model.Target != nil { + targetMap := make(map[string]interface{}, len(model.Target)) + // for k, v := range model.Target { + // } + modelMap["target"] = flex.Flatten(targetMap) + } + if model.Message != nil { + modelMap["message"] = *model.Message + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingResourceToMap(model *catalogmanagementv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingScriptToMap(model *catalogmanagementv1.Script) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Instructions != nil { + modelMap["instructions"] = *model.Instructions + } + if model.InstructionsI18n != nil { + instructionsI18nMap := make(map[string]interface{}, len(model.InstructionsI18n)) + for k, v := range model.InstructionsI18n { + instructionsI18nMap[k] = v + } + modelMap["instructions_i18n"] = flex.Flatten(instructionsI18nMap) + } + if model.Script != nil { + modelMap["script"] = *model.Script + } + if model.ScriptPermission != nil { + modelMap["script_permission"] = *model.ScriptPermission + } + if model.DeleteScript != nil { + modelMap["delete_script"] = *model.DeleteScript + } + if model.Scope != nil { + modelMap["scope"] = *model.Scope + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingVersionEntitlementToMap(model *catalogmanagementv1.VersionEntitlement) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ProviderName != nil { + modelMap["provider_name"] = *model.ProviderName + } + if model.ProviderID != nil { + modelMap["provider_id"] = *model.ProviderID + } + if model.ProductID != nil { + modelMap["product_id"] = *model.ProductID + } + if model.PartNumbers != nil { + modelMap["part_numbers"] = model.PartNumbers + } + if model.ImageRepoName != nil { + modelMap["image_repo_name"] = *model.ImageRepoName + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingLicenseToMap(model *catalogmanagementv1.License) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingStateToMap(model *catalogmanagementv1.State) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Current != nil { + modelMap["current"] = *model.Current + } + if model.CurrentEntered != nil { + modelMap["current_entered"] = model.CurrentEntered.String() + } + if model.Pending != nil { + modelMap["pending"] = *model.Pending + } + if model.PendingRequested != nil { + modelMap["pending_requested"] = model.PendingRequested.String() + } + if model.Previous != nil { + modelMap["previous"] = *model.Previous + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingDeprecatePendingToMap(model *catalogmanagementv1.DeprecatePending) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.DeprecateDate != nil { + modelMap["deprecate_date"] = model.DeprecateDate.String() + } + if model.DeprecateState != nil { + modelMap["deprecate_state"] = *model.DeprecateState + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSolutionInfoToMap(model *catalogmanagementv1.SolutionInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ArchitectureDiagrams != nil { + architectureDiagrams := []map[string]interface{}{} + for _, architectureDiagramsItem := range model.ArchitectureDiagrams { + architectureDiagramsItemMap, err := dataSourceIBMCmOfferingArchitectureDiagramToMap(&architectureDiagramsItem) + if err != nil { + return modelMap, err + } + architectureDiagrams = append(architectureDiagrams, architectureDiagramsItemMap) + } + modelMap["architecture_diagrams"] = architectureDiagrams + } + if model.Features != nil { + features := []map[string]interface{}{} + for _, featuresItem := range model.Features { + featuresItemMap, err := dataSourceIBMCmOfferingFeatureToMap(&featuresItem) + if err != nil { + return modelMap, err + } + features = append(features, featuresItemMap) + } + modelMap["features"] = features + } + if model.CostEstimate != nil { + costEstimateMap, err := dataSourceIBMCmOfferingCostEstimateToMap(model.CostEstimate) + if err != nil { + return modelMap, err + } + modelMap["cost_estimate"] = []map[string]interface{}{costEstimateMap} + } + if model.Dependencies != nil { + dependencies := []map[string]interface{}{} + for _, dependenciesItem := range model.Dependencies { + dependenciesItemMap, err := dataSourceIBMCmOfferingDependencyToMap(&dependenciesItem) + if err != nil { + return modelMap, err + } + dependencies = append(dependencies, dependenciesItemMap) + } + modelMap["dependencies"] = dependencies + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingArchitectureDiagramToMap(model *catalogmanagementv1.ArchitectureDiagram) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Diagram != nil { + diagramMap, err := dataSourceIBMCmOfferingMediaItemToMap(model.Diagram) + if err != nil { + return modelMap, err + } + modelMap["diagram"] = []map[string]interface{}{diagramMap} + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingMediaItemToMap(model *catalogmanagementv1.MediaItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.APIURL != nil { + modelMap["api_url"] = *model.APIURL + } + if model.URLProxy != nil { + urlProxyMap, err := dataSourceIBMCmOfferingURLProxyToMap(model.URLProxy) + if err != nil { + return modelMap, err + } + modelMap["url_proxy"] = []map[string]interface{}{urlProxyMap} + } + if model.Caption != nil { + modelMap["caption"] = *model.Caption + } + if model.CaptionI18n != nil { + captionI18nMap := make(map[string]interface{}, len(model.CaptionI18n)) + for k, v := range model.CaptionI18n { + captionI18nMap[k] = v + } + modelMap["caption_i18n"] = flex.Flatten(captionI18nMap) + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.ThumbnailURL != nil { + modelMap["thumbnail_url"] = *model.ThumbnailURL + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingURLProxyToMap(model *catalogmanagementv1.URLProxy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Sha != nil { + modelMap["sha"] = *model.Sha + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingCostEstimateToMap(model *catalogmanagementv1.CostEstimate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Currency != nil { + modelMap["currency"] = *model.Currency + } + if model.Projects != nil { + projects := []map[string]interface{}{} + for _, projectsItem := range model.Projects { + projectsItemMap, err := dataSourceIBMCmOfferingProjectToMap(&projectsItem) + if err != nil { + return modelMap, err + } + projects = append(projects, projectsItemMap) + } + modelMap["projects"] = projects + } + if model.Summary != nil { + summaryMap, err := dataSourceIBMCmOfferingCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = *model.TotalHourlyCost + } + if model.TotalMonthlyCost != nil { + modelMap["total_monthly_cost"] = *model.TotalMonthlyCost + } + if model.PastTotalHourlyCost != nil { + modelMap["past_total_hourly_cost"] = *model.PastTotalHourlyCost + } + if model.PastTotalMonthlyCost != nil { + modelMap["past_total_monthly_cost"] = *model.PastTotalMonthlyCost + } + if model.DiffTotalHourlyCost != nil { + modelMap["diff_total_hourly_cost"] = *model.DiffTotalHourlyCost + } + if model.DiffTotalMonthlyCost != nil { + modelMap["diff_total_monthly_cost"] = *model.DiffTotalMonthlyCost + } + if model.TimeGenerated != nil { + modelMap["time_generated"] = model.TimeGenerated.String() + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingProjectToMap(model *catalogmanagementv1.Project) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.PastBreakdown != nil { + pastBreakdownMap, err := dataSourceIBMCmOfferingCostBreakdownToMap(model.PastBreakdown) + if err != nil { + return modelMap, err + } + modelMap["past_breakdown"] = []map[string]interface{}{pastBreakdownMap} + } + if model.Breakdown != nil { + breakdownMap, err := dataSourceIBMCmOfferingCostBreakdownToMap(model.Breakdown) + if err != nil { + return modelMap, err + } + modelMap["breakdown"] = []map[string]interface{}{breakdownMap} + } + if model.Diff != nil { + diffMap, err := dataSourceIBMCmOfferingCostBreakdownToMap(model.Diff) + if err != nil { + return modelMap, err + } + modelMap["diff"] = []map[string]interface{}{diffMap} + } + if model.Summary != nil { + summaryMap, err := dataSourceIBMCmOfferingCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingCostBreakdownToMap(model *catalogmanagementv1.CostBreakdown) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = *model.TotalHourlyCost + } + if model.TotalMonthlyCOst != nil { + modelMap["total_monthly_c_ost"] = *model.TotalMonthlyCOst + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := dataSourceIBMCmOfferingCostResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingCostResourceToMap(model *catalogmanagementv1.CostResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = *model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = *model.MonthlyCost + } + if model.CostComponents != nil { + costComponents := []map[string]interface{}{} + for _, costComponentsItem := range model.CostComponents { + costComponentsItemMap, err := dataSourceIBMCmOfferingCostComponentToMap(&costComponentsItem) + if err != nil { + return modelMap, err + } + costComponents = append(costComponents, costComponentsItemMap) + } + modelMap["cost_components"] = costComponents + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingCostComponentToMap(model *catalogmanagementv1.CostComponent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Unit != nil { + modelMap["unit"] = *model.Unit + } + if model.HourlyQuantity != nil { + modelMap["hourly_quantity"] = *model.HourlyQuantity + } + if model.MonthlyQuantity != nil { + modelMap["monthly_quantity"] = *model.MonthlyQuantity + } + if model.Price != nil { + modelMap["price"] = *model.Price + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = *model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = *model.MonthlyCost + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingCostSummaryToMap(model *catalogmanagementv1.CostSummary) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalDetectedResources != nil { + modelMap["total_detected_resources"] = *model.TotalDetectedResources + } + if model.TotalSupportedResources != nil { + modelMap["total_supported_resources"] = *model.TotalSupportedResources + } + if model.TotalUnsupportedResources != nil { + modelMap["total_unsupported_resources"] = *model.TotalUnsupportedResources + } + if model.TotalUsageBasedResources != nil { + modelMap["total_usage_based_resources"] = *model.TotalUsageBasedResources + } + if model.TotalNoPriceResources != nil { + modelMap["total_no_price_resources"] = *model.TotalNoPriceResources + } + if model.UnsupportedResourceCounts != nil { + unsupportedResourceCountsMap := make(map[string]interface{}, len(model.UnsupportedResourceCounts)) + for k, v := range model.UnsupportedResourceCounts { + unsupportedResourceCountsMap[k] = v + } + modelMap["unsupported_resource_counts"] = flex.Flatten(unsupportedResourceCountsMap) + } + if model.NoPriceResourceCounts != nil { + noPriceResourceCountsMap := make(map[string]interface{}, len(model.NoPriceResourceCounts)) + for k, v := range model.NoPriceResourceCounts { + noPriceResourceCountsMap[k] = v + } + modelMap["no_price_resource_counts"] = flex.Flatten(noPriceResourceCountsMap) + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingDependencyToMap(model *catalogmanagementv1.Dependency) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CatalogID != nil { + modelMap["catalog_id"] = *model.CatalogID + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Flavors != nil { + modelMap["flavors"] = model.Flavors + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingPlanToMap(model *catalogmanagementv1.Plan) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Label != nil { + modelMap["label"] = *model.Label + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ShortDescription != nil { + modelMap["short_description"] = *model.ShortDescription + } + if model.LongDescription != nil { + modelMap["long_description"] = *model.LongDescription + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.AdditionalFeatures != nil { + additionalFeatures := []map[string]interface{}{} + for _, additionalFeaturesItem := range model.AdditionalFeatures { + additionalFeaturesItemMap, err := dataSourceIBMCmOfferingFeatureToMap(&additionalFeaturesItem) + if err != nil { + return modelMap, err + } + additionalFeatures = append(additionalFeatures, additionalFeaturesItemMap) + } + modelMap["additional_features"] = additionalFeatures + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.Deployments != nil { + deployments := []map[string]interface{}{} + for _, deploymentsItem := range model.Deployments { + deploymentsItemMap, err := dataSourceIBMCmOfferingDeploymentToMap(&deploymentsItem) + if err != nil { + return modelMap, err + } + deployments = append(deployments, deploymentsItemMap) + } + modelMap["deployments"] = deployments + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingDeploymentToMap(model *catalogmanagementv1.Deployment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Label != nil { + modelMap["label"] = *model.Label + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ShortDescription != nil { + modelMap["short_description"] = *model.ShortDescription + } + if model.LongDescription != nil { + modelMap["long_description"] = *model.LongDescription + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingProviderInfoToMap(model *catalogmanagementv1.ProviderInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingRepoInfoToMap(model *catalogmanagementv1.RepoInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Token != nil { + modelMap["token"] = *model.Token + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingImagePullKeyToMap(model *catalogmanagementv1.ImagePullKey) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportToMap(model *catalogmanagementv1.Support) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Process != nil { + modelMap["process"] = *model.Process + } + if model.ProcessI18n != nil { + processI18nMap := make(map[string]interface{}, len(model.ProcessI18n)) + for k, v := range model.ProcessI18n { + processI18nMap[k] = v + } + modelMap["process_i18n"] = flex.Flatten(processI18nMap) + } + if model.Locations != nil { + modelMap["locations"] = model.Locations + } + if model.SupportDetails != nil { + supportDetails := []map[string]interface{}{} + for _, supportDetailsItem := range model.SupportDetails { + supportDetailsItemMap, err := dataSourceIBMCmOfferingSupportDetailToMap(&supportDetailsItem) + if err != nil { + return modelMap, err + } + supportDetails = append(supportDetails, supportDetailsItemMap) + } + modelMap["support_details"] = supportDetails + } + if model.SupportEscalation != nil { + supportEscalationMap, err := dataSourceIBMCmOfferingSupportEscalationToMap(model.SupportEscalation) + if err != nil { + return modelMap, err + } + modelMap["support_escalation"] = []map[string]interface{}{supportEscalationMap} + } + if model.SupportType != nil { + modelMap["support_type"] = *model.SupportType + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportDetailToMap(model *catalogmanagementv1.SupportDetail) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Contact != nil { + modelMap["contact"] = *model.Contact + } + if model.ResponseWaitTime != nil { + responseWaitTimeMap, err := dataSourceIBMCmOfferingSupportWaitTimeToMap(model.ResponseWaitTime) + if err != nil { + return modelMap, err + } + modelMap["response_wait_time"] = []map[string]interface{}{responseWaitTimeMap} + } + if model.Availability != nil { + availabilityMap, err := dataSourceIBMCmOfferingSupportAvailabilityToMap(model.Availability) + if err != nil { + return modelMap, err + } + modelMap["availability"] = []map[string]interface{}{availabilityMap} + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportWaitTimeToMap(model *catalogmanagementv1.SupportWaitTime) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportAvailabilityToMap(model *catalogmanagementv1.SupportAvailability) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Times != nil { + times := []map[string]interface{}{} + for _, timesItem := range model.Times { + timesItemMap, err := dataSourceIBMCmOfferingSupportTimeToMap(×Item) + if err != nil { + return modelMap, err + } + times = append(times, timesItemMap) + } + modelMap["times"] = times + } + if model.Timezone != nil { + modelMap["timezone"] = *model.Timezone + } + if model.AlwaysAvailable != nil { + modelMap["always_available"] = *model.AlwaysAvailable + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportTimeToMap(model *catalogmanagementv1.SupportTime) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Day != nil { + modelMap["day"] = *model.Day + } + if model.StartTime != nil { + modelMap["start_time"] = *model.StartTime + } + if model.EndTime != nil { + modelMap["end_time"] = *model.EndTime + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingSupportEscalationToMap(model *catalogmanagementv1.SupportEscalation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.EscalationWaitTime != nil { + escalationWaitTimeMap, err := dataSourceIBMCmOfferingSupportWaitTimeToMap(model.EscalationWaitTime) + if err != nil { + return modelMap, err + } + modelMap["escalation_wait_time"] = []map[string]interface{}{escalationWaitTimeMap} + } + if model.ResponseWaitTime != nil { + responseWaitTimeMap, err := dataSourceIBMCmOfferingSupportWaitTimeToMap(model.ResponseWaitTime) + if err != nil { + return modelMap, err + } + modelMap["response_wait_time"] = []map[string]interface{}{responseWaitTimeMap} + } + if model.Contact != nil { + modelMap["contact"] = *model.Contact + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingBadgeToMap(model *catalogmanagementv1.Badge) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Label != nil { + modelMap["label"] = *model.Label + } + if model.LabelI18n != nil { + labelI18nMap := make(map[string]interface{}, len(model.LabelI18n)) + for k, v := range model.LabelI18n { + labelI18nMap[k] = v + } + modelMap["label_i18n"] = flex.Flatten(labelI18nMap) + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + if model.Icon != nil { + modelMap["icon"] = *model.Icon + } + if model.Authority != nil { + modelMap["authority"] = *model.Authority + } + if model.Tag != nil { + modelMap["tag"] = *model.Tag + } + if model.LearnMoreLinks != nil { + learnMoreLinksMap, err := dataSourceIBMCmOfferingLearnMoreLinksToMap(model.LearnMoreLinks) + if err != nil { + return modelMap, err + } + modelMap["learn_more_links"] = []map[string]interface{}{learnMoreLinksMap} + } + if model.Constraints != nil { + constraints := []map[string]interface{}{} + for _, constraintsItem := range model.Constraints { + constraintsItemMap, err := dataSourceIBMCmOfferingConstraintToMap(&constraintsItem) + if err != nil { + return modelMap, err + } + constraints = append(constraints, constraintsItemMap) + } + modelMap["constraints"] = constraints + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingLearnMoreLinksToMap(model *catalogmanagementv1.LearnMoreLinks) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.FirstParty != nil { + modelMap["first_party"] = *model.FirstParty + } + if model.ThirdParty != nil { + modelMap["third_party"] = *model.ThirdParty + } + return modelMap, nil +} + +func dataSourceIBMCmOfferingConstraintToMap(model *catalogmanagementv1.Constraint) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Rule != nil { + } + return modelMap, nil +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance.go b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance.go new file mode 100644 index 000000000..ffc2263bc --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance.go @@ -0,0 +1,183 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func DataSourceIBMCmOfferingInstance() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCmOfferingInstanceRead, + + Schema: map[string]*schema.Schema{ + "instance_identifier": { + Type: schema.TypeString, + Required: true, + Description: "ID for this instance", + }, + "url": { + Type: schema.TypeString, + Computed: true, + Description: "url reference to this object.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "platform CRN for this instance.", + }, + "_rev": { + Type: schema.TypeString, + Computed: true, + Description: "Cloudant Revision for this instance", + }, + "label": { + Type: schema.TypeString, + Computed: true, + Description: "the label for this instance.", + }, + "catalog_id": { + Type: schema.TypeString, + Computed: true, + Description: "Catalog ID this instance was created from.", + }, + "offering_id": { + Type: schema.TypeString, + Computed: true, + Description: "Offering ID this instance was created from.", + }, + "kind_format": { + Type: schema.TypeString, + Computed: true, + Description: "the format this instance has (helm, operator, ova...).", + }, + "version": { + Type: schema.TypeString, + Computed: true, + Description: "The version this instance was installed from (not version id).", + }, + "cluster_id": { + Type: schema.TypeString, + Computed: true, + Description: "Cluster ID.", + }, + "cluster_region": { + Type: schema.TypeString, + Computed: true, + Description: "Cluster region (e.g., us-south).", + }, + "cluster_namespaces": { + Type: schema.TypeList, + Computed: true, + Description: "List of target namespaces to install into.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "cluster_all_namespaces": { + Type: schema.TypeBool, + Computed: true, + Description: "designate to install into all namespaces.", + }, + "schematics_workspace_id": { + Type: schema.TypeString, + Computed: true, + Description: "id of the schematics workspace, for offerings installed through schematics", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "id of the resource group", + }, + "install_plan": { + Type: schema.TypeString, + Computed: true, + Description: "install plan for the subscription of the operator- can be either Automatic or Manual. Required for operator bundles", + }, + "channel": { + Type: schema.TypeString, + Computed: true, + Description: "channel to target for the operator subscription. Required for operator bundles", + }, + }, + } +} + +func dataSourceIBMCmOfferingInstanceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getOfferingInstanceOptions := &catalogmanagementv1.GetOfferingInstanceOptions{} + + getOfferingInstanceOptions.SetInstanceIdentifier(d.Get("instance_identifier").(string)) + + offeringInstance, response, err := catalogManagementClient.GetOfferingInstanceWithContext(context, getOfferingInstanceOptions) + if err != nil { + log.Printf("[DEBUG] GetOfferingInstanceWithContext failed %s\n%s", err, response) + return diag.FromErr(err) + } + + d.SetId(*offeringInstance.ID) + + if err = d.Set("url", offeringInstance.URL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting url: %s", err)) + } + if err = d.Set("crn", offeringInstance.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("_rev", offeringInstance.Rev); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting _rev: %s", err)) + } + if err = d.Set("label", offeringInstance.Label); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting label: %s", err)) + } + if err = d.Set("catalog_id", offeringInstance.CatalogID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting catalog_id: %s", err)) + } + if err = d.Set("offering_id", offeringInstance.OfferingID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting offering_id: %s", err)) + } + if err = d.Set("kind_format", offeringInstance.KindFormat); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting kind_format: %s", err)) + } + if err = d.Set("version", offeringInstance.Version); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + if err = d.Set("cluster_id", offeringInstance.ClusterID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cluster_id: %s", err)) + } + if err = d.Set("cluster_region", offeringInstance.ClusterRegion); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cluster_region: %s", err)) + } + if err = d.Set("cluster_namespaces", offeringInstance.ClusterNamespaces); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cluster_namespaces: %s", err)) + } + if err = d.Set("cluster_all_namespaces", offeringInstance.ClusterAllNamespaces); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cluster_all_namespaces: %s", err)) + } + if err = d.Set("schematics_workspace_id", offeringInstance.SchematicsWorkspaceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting schematics_workspace_id: %s", err)) + } + if err = d.Set("resource_group_id", offeringInstance.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group_id: %s", err)) + } + if err = d.Set("install_plan", offeringInstance.InstallPlan); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting install_plan: %s", err)) + } + if err = d.Set("channel", offeringInstance.Channel); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting channel: %s", err)) + } + + return nil +} diff --git a/ibm/data_source_ibm_cm_offering_instance_test.go b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance_test.go similarity index 93% rename from ibm/data_source_ibm_cm_offering_instance_test.go rename to ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance_test.go index 7858c9842..bb0cc10d8 100644 --- a/ibm/data_source_ibm_cm_offering_instance_test.go +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_instance_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package catalogmanagement_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMCmOfferingInstanceDataSource(t *testing.T) { resourceGroupID := os.Getenv("CATMGMT_RGID") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCmOfferingInstanceDataSourceConfig(clusterId, clusterRegion, resourceGroupID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_cm_offering_instance.cm_offering_instance_data", "label"), diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_offering_test.go b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_test.go new file mode 100644 index 000000000..992e3c5a5 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_offering_test.go @@ -0,0 +1,105 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCmOfferingDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmOfferingDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "catalog_identifier"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "offering_identifier"), + ), + }, + }, + }) +} + +func TestAccIBMCmOfferingDataSourceSimpleArgs(t *testing.T) { + offeringLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + offeringName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + offeringOfferingIconURL := fmt.Sprintf("tf_offering_icon_url_%d", acctest.RandIntRange(10, 100)) + offeringShortDescription := fmt.Sprintf("tf_offering_icon_url_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmOfferingDataSourceConfig(offeringLabel, offeringName, offeringOfferingIconURL, offeringShortDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "catalog_identifier"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "offering_identifier"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "rev"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "url"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "label"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "offering_icon_url"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "created"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "updated"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "short_description"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "catalog_id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "catalog_name"), + resource.TestCheckResourceAttrSet("data.ibm_cm_offering.cm_offering", "support.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMCmOfferingDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_basic_catalog_label_for_offering_data_source" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + } + + data "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_offering.cm_offering.catalog_identifier + offering_identifier = ibm_cm_offering.cm_offering.offering_id + } + `) +} + +func testAccCheckIBMCmOfferingDataSourceConfig(offeringLabel string, offeringName string, offeringOfferingIconURL string, offeringShortDescription string) string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "catalog_%s" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "%s" + name = "%s" + offering_icon_url = "%s" + short_description = "%s" + } + + data "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_offering.cm_offering.catalog_identifier + offering_identifier = ibm_cm_offering.cm_offering.offering_id + } + `, offeringLabel, offeringLabel, offeringName, offeringOfferingIconURL, offeringShortDescription) +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_preset.go b/ibm/service/catalogmanagement/data_source_ibm_cm_preset.go new file mode 100644 index 000000000..78fa88a10 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_preset.go @@ -0,0 +1,87 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "encoding/json" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func DataSourceIBMCmPreset() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCmPresetRead, + + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the preset. Format is -:", + }, + "preset": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The map of preset values as a JSON string.", + }, + }, + } +} + +func dataSourceIBMCmPresetRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + presetID := d.Get("id").(string) + splitID := strings.Split(presetID, ":") + version := splitID[len(splitID)-1] + objectID := splitID[0] + splitID = strings.Split(presetID, "-") + catalogID := strings.Join(splitID[:5], "-") + + getObjectOptions := &catalogmanagementv1.GetObjectOptions{} + + getObjectOptions.SetCatalogIdentifier(catalogID) + getObjectOptions.SetObjectIdentifier(objectID) + + catalogObject, response, err := catalogManagementClient.GetObjectWithContext(context, getObjectOptions) + if err != nil { + log.Printf("[DEBUG] GetObjectWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetObjectWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", catalogID, objectID, version)) + + if catalogObject.Data == nil { + return diag.FromErr(fmt.Errorf("Error setting preset, object data is nil. %s", err)) + } + if catalogObject.Data["versions"] == nil { + return diag.FromErr(fmt.Errorf("Error setting preset, object data.versions is nil. %s", err)) + } + if catalogObject.Data["versions"].(map[string]interface{})[version] == nil { + return diag.FromErr(fmt.Errorf("Error setting preset, could not find preset with version %s. %s", version, err)) + } + if catalogObject.Data["versions"].(map[string]interface{})[version].(map[string]interface{})["preset"] == nil { + return diag.FromErr(fmt.Errorf("Error setting preset, preset field not found in version %s. %s", version, err)) + } + + presetMap, err := json.Marshal(catalogObject.Data["versions"].(map[string]interface{})[version].(map[string]interface{})["preset"]) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting preset, error with json marshal: %s", err)) + } + if err = d.Set("preset", string(presetMap)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting preset: %s", err)) + } + + return nil +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_preset_test.go b/ibm/service/catalogmanagement/data_source_ibm_cm_preset_test.go new file mode 100644 index 000000000..53df57101 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_preset_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCmPresetDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmPresetDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_preset.cm_preset", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_preset.cm_preset", "preset"), + ), + }, + }, + }) +} + +func testAccCheckIBMCmPresetDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_cm_preset" "cm_preset" { + id = + } + `) +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_version.go b/ibm/service/catalogmanagement/data_source_ibm_cm_version.go new file mode 100644 index 000000000..6d653fb50 --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_version.go @@ -0,0 +1,2482 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func DataSourceIBMCmVersion() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCmVersionRead, + + Schema: map[string]*schema.Schema{ + "version_loc_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "A dotted value of `catalogID`.`versionID`.", + }, + "version_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique ID.", + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version's CRN.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of content type.", + }, + "flavor": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Version Flavor Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Programmatic name for this flavor.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Label for this flavor.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "index": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Order that this flavor should appear when listed for a single version.", + }, + }, + }, + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "hash of the content.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was last updated.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Offering ID.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Catalog ID.", + }, + "kind_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kind ID.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's repo URL.", + }, + "source_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's source URL (e.g git repo).", + }, + "tgz_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "File used to on-board this version.", + }, + "configuration": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of user solicited overrides.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Configuration key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Value type (string, boolean, int).", + }, + // "default_value": &schema.Schema{ + // Type: schema.TypeMap, + // Computed: true, + // Description: "The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`.", + // }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Display name for configuration type.", + }, + "value_constraint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Constraint associated with value, e.g., for string type - regx:[a-z].", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key description.", + }, + "required": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is key required to install.", + }, + "options": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of options of type.", + Elem: &schema.Schema{ + Type: schema.TypeMap, + }, + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Hide values.", + }, + "custom_config": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Render type.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the widget type.", + }, + "grouping": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment).", + }, + "original_grouping": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Original grouping type for this configuration (3 types - Target, Resource, and Deployment).", + }, + "grouping_index": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Determines the order that this configuration item shows in that particular grouping.", + }, + "config_constraints": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Map of constraint parameters that will be passed to the custom widget.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "associations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of parameters that are associated with this configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Parameters for this association.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of this parameter.", + }, + "options_refresh": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Refresh options.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "type_metadata": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The original type, as found in the source being onboarded.", + }, + }, + }, + }, + "outputs": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of output values for this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Output key.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Output description.", + }, + }, + }, + }, + "iam_permissions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of IAM permissions that are required to consume this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Service name.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources for this permission.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource description.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "metadata": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Generic data to be included with content being onboarded. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version source URL.", + }, + "version_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version name.", + }, + "terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Terraform version.", + }, + "validated_terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version name.", + }, + "vsi_vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "VSI VPC version information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "validation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Validation response.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "validated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of last successful validation.", + }, + "requested": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of last validation was requested.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current validation state - , in_progress, valid, invalid, expired.", + }, + "last_operation": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Last operation (e.g. submit_deployment, generate_installer, install_offering.", + }, + "target": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Any message needing to be conveyed as part of the validation job.", + }, + }, + }, + }, + "required_resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resource requirments for installation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of requirement.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value.", + }, + }, + }, + }, + "single_instance": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if single instance can be deployed to a given cluster.", + }, + "install": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Script information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "pre_install": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Optional pre-install instructions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "entitlement": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Entitlement license info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Provider name.", + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Provider ID.", + }, + "product_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Product ID.", + }, + "part_numbers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "image_repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Image repository name.", + }, + }, + }, + }, + "licenses": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of licenses the product was built with.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "License ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "license name.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "type of license e.g., Apache xxx.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for the license text.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "License description.", + }, + }, + }, + }, + "image_manifest_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If set, denotes a url to a YAML file with list of container images used by this version.", + }, + "deprecated": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "read only field, indicating if this version is deprecated.", + }, + "package_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of the package used to create this version.", + }, + "state": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering state.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "current_entered": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of current request.", + }, + "pending": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "pending_requested": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time of pending request.", + }, + "previous": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + }, + }, + }, + "version_locator": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dotted value of `catalogID`.`versionID`.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description for version.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "whitelisted_accounts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Whitelisted accounts for version.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "image_pull_key_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the image pull key to use from Offering.ImagePullKeys.", + }, + "deprecate_pending": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Deprecation information for an Offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deprecate_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date of deprecation.", + }, + "deprecate_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Deprecation state.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "solution_info": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Version Solution Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "architecture_diagrams": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Architecture diagrams for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "diagram": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering Media information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of this diagram.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Features - titles only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "cost_estimate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost estimate definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost estimate version.", + }, + "currency": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost estimate currency.", + }, + "projects": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost estimate projects.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Project name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Project metadata.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "past_breakdown": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "breakdown": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "diff": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Resource metadata.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "No price resource counts.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "No price resource counts.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total hourly cost.", + }, + "total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Total monthly cost.", + }, + "past_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Past total hourly cost.", + }, + "past_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Past total monthly cost.", + }, + "diff_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Difference in total hourly cost.", + }, + "diff_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Difference in total monthly cost.", + }, + "time_generated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "When this estimate was generated.", + }, + }, + }, + }, + "dependencies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Dependencies for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - If not specified, assumes the Public Catalog.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - Offering ID - not required if name is set.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Optional - Programmatic Offering name.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Required - Semver value or range.", + }, + "flavors": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Optional - List of dependent flavors in the specified range.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "is_consumable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is the version able to be shared.", + }, + }, + } +} + +func dataSourceIBMCmVersionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + + getVersionOptions.SetVersionLocID(d.Get("version_loc_id").(string)) + + offering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) + if err != nil { + log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVersionWithContext failed %s\n%s", err, response)) + } + version := offering.Kinds[0].Versions[0] + + d.SetId(*getVersionOptions.VersionLocID) + + if err = d.Set("version_id", version.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_id: %s", err)) + } + + if err = d.Set("rev", version.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + + if err = d.Set("crn", version.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("version", version.Version); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + flavor := []map[string]interface{}{} + if version.Flavor != nil { + modelMap, err := dataSourceIBMCmVersionFlavorToMap(version.Flavor) + if err != nil { + return diag.FromErr(err) + } + flavor = append(flavor, modelMap) + } + if err = d.Set("flavor", flavor); err != nil { + return diag.FromErr(fmt.Errorf("Error setting flavor %s", err)) + } + + if err = d.Set("sha", version.Sha); err != nil { + return diag.FromErr(fmt.Errorf("Error setting sha: %s", err)) + } + + if err = d.Set("created", flex.DateTimeToString(version.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + + if err = d.Set("updated", flex.DateTimeToString(version.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + + if err = d.Set("offering_id", version.OfferingID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_id: %s", err)) + } + + if err = d.Set("catalog_id", version.CatalogID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) + } + + if err = d.Set("kind_id", version.KindID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kind_id: %s", err)) + } + + if err = d.Set("repo_url", version.RepoURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting repo_url: %s", err)) + } + + if err = d.Set("source_url", version.SourceURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_url: %s", err)) + } + + if err = d.Set("tgz_url", version.TgzURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tgz_url: %s", err)) + } + + configuration := []map[string]interface{}{} + if version.Configuration != nil { + for _, modelItem := range version.Configuration { + modelMap, err := dataSourceIBMCmVersionConfigurationToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + configuration = append(configuration, modelMap) + } + } + if err = d.Set("configuration", configuration); err != nil { + return diag.FromErr(fmt.Errorf("Error setting configuration %s", err)) + } + + outputs := []map[string]interface{}{} + if version.Outputs != nil { + for _, modelItem := range version.Outputs { + modelMap, err := dataSourceIBMCmVersionOutputToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + outputs = append(outputs, modelMap) + } + } + if err = d.Set("outputs", outputs); err != nil { + return diag.FromErr(fmt.Errorf("Error setting outputs %s", err)) + } + + iamPermissions := []map[string]interface{}{} + if version.IamPermissions != nil { + for _, modelItem := range version.IamPermissions { + modelMap, err := dataSourceIBMCmVersionIamPermissionToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + iamPermissions = append(iamPermissions, modelMap) + } + } + if err = d.Set("iam_permissions", iamPermissions); err != nil { + return diag.FromErr(fmt.Errorf("Error setting iam_permissions %s", err)) + } + + metadata := []map[string]interface{}{} + if version.Metadata != nil { + var modelMapVSI map[string]interface{} + if version.Metadata["vsi_vpc"] != nil { + modelMapVSI, err = dataSourceIBMCmVersionMetadataVSIToMap(version.Metadata["vsi_vpc"].(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + } + convertedMap := make(map[string]interface{}, len(version.Metadata)) + for k, v := range version.Metadata { + if k == "vsi_vpc" { + convertedMap[k] = []map[string]interface{}{modelMapVSI} + } else { + convertedMap[k] = v + } + } + metadata = append(metadata, convertedMap) + } + if err = d.Set("metadata", metadata); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + } + + validation := []map[string]interface{}{} + if version.Validation != nil { + modelMap, err := dataSourceIBMCmVersionValidationToMap(version.Validation) + if err != nil { + return diag.FromErr(err) + } + validation = append(validation, modelMap) + } + if err = d.Set("validation", validation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting validation %s", err)) + } + + requiredResources := []map[string]interface{}{} + if version.RequiredResources != nil { + for _, modelItem := range version.RequiredResources { + modelMap, err := dataSourceIBMCmVersionResourceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + requiredResources = append(requiredResources, modelMap) + } + } + if err = d.Set("required_resources", requiredResources); err != nil { + return diag.FromErr(fmt.Errorf("Error setting required_resources %s", err)) + } + + if err = d.Set("single_instance", version.SingleInstance); err != nil { + return diag.FromErr(fmt.Errorf("Error setting single_instance: %s", err)) + } + + install := []map[string]interface{}{} + if version.Install != nil { + modelMap, err := dataSourceIBMCmVersionScriptToMap(version.Install) + if err != nil { + return diag.FromErr(err) + } + install = append(install, modelMap) + } + if err = d.Set("install", install); err != nil { + return diag.FromErr(fmt.Errorf("Error setting install %s", err)) + } + + preInstall := []map[string]interface{}{} + if version.PreInstall != nil { + for _, modelItem := range version.PreInstall { + modelMap, err := dataSourceIBMCmVersionScriptToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + preInstall = append(preInstall, modelMap) + } + } + if err = d.Set("pre_install", preInstall); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pre_install %s", err)) + } + + entitlement := []map[string]interface{}{} + if version.Entitlement != nil { + modelMap, err := dataSourceIBMCmVersionVersionEntitlementToMap(version.Entitlement) + if err != nil { + return diag.FromErr(err) + } + entitlement = append(entitlement, modelMap) + } + if err = d.Set("entitlement", entitlement); err != nil { + return diag.FromErr(fmt.Errorf("Error setting entitlement %s", err)) + } + + licenses := []map[string]interface{}{} + if version.Licenses != nil { + for _, modelItem := range version.Licenses { + modelMap, err := dataSourceIBMCmVersionLicenseToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + licenses = append(licenses, modelMap) + } + } + if err = d.Set("licenses", licenses); err != nil { + return diag.FromErr(fmt.Errorf("Error setting licenses %s", err)) + } + + if err = d.Set("image_manifest_url", version.ImageManifestURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_manifest_url: %s", err)) + } + + if err = d.Set("deprecated", version.Deprecated); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deprecated: %s", err)) + } + + if err = d.Set("package_version", version.PackageVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting package_version: %s", err)) + } + + state := []map[string]interface{}{} + if version.State != nil { + modelMap, err := dataSourceIBMCmVersionStateToMap(version.State) + if err != nil { + return diag.FromErr(err) + } + state = append(state, modelMap) + } + if err = d.Set("state", state); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state %s", err)) + } + + if err = d.Set("version_locator", version.VersionLocator); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_locator: %s", err)) + } + + if err = d.Set("long_description", version.LongDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) + } + + if version.LongDescriptionI18n != nil { + if err = d.Set("long_description_i18n", version.LongDescriptionI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description_i18n: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description_i18n %s", err)) + } + } + + if err = d.Set("image_pull_key_name", version.ImagePullKeyName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_pull_key_name: %s", err)) + } + + deprecatePending := []map[string]interface{}{} + if version.DeprecatePending != nil { + modelMap, err := dataSourceIBMCmVersionDeprecatePendingToMap(version.DeprecatePending) + if err != nil { + return diag.FromErr(err) + } + deprecatePending = append(deprecatePending, modelMap) + } + if err = d.Set("deprecate_pending", deprecatePending); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deprecate_pending %s", err)) + } + + solutionInfo := []map[string]interface{}{} + if version.SolutionInfo != nil { + modelMap, err := dataSourceIBMCmVersionSolutionInfoToMap(version.SolutionInfo) + if err != nil { + return diag.FromErr(err) + } + solutionInfo = append(solutionInfo, modelMap) + } + if err = d.Set("solution_info", solutionInfo); err != nil { + return diag.FromErr(fmt.Errorf("Error setting solution_info %s", err)) + } + + if err = d.Set("is_consumable", version.IsConsumable); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_consumable: %s", err)) + } + + return nil +} + +func dataSourceIBMCmVersionFlavorToMap(model *catalogmanagementv1.Flavor) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Label != nil { + modelMap["label"] = *model.Label + } + if model.LabelI18n != nil { + labelI18nMap := make(map[string]interface{}, len(model.LabelI18n)) + for k, v := range model.LabelI18n { + labelI18nMap[k] = v + } + modelMap["label_i18n"] = flex.Flatten(labelI18nMap) + } + if model.Index != nil { + modelMap["index"] = *model.Index + } + return modelMap, nil +} + +func dataSourceIBMCmVersionConfigurationToMap(model *catalogmanagementv1.Configuration) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.DefaultValue != nil { + } + if model.DisplayName != nil { + modelMap["display_name"] = *model.DisplayName + } + if model.ValueConstraint != nil { + modelMap["value_constraint"] = *model.ValueConstraint + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.Required != nil { + modelMap["required"] = *model.Required + } + if model.Options != nil { + } + if model.Hidden != nil { + modelMap["hidden"] = *model.Hidden + } + if model.CustomConfig != nil { + customConfigMap, err := dataSourceIBMCmVersionRenderTypeToMap(model.CustomConfig) + if err != nil { + return modelMap, err + } + modelMap["custom_config"] = []map[string]interface{}{customConfigMap} + } + if model.TypeMetadata != nil { + modelMap["type_metadata"] = *model.TypeMetadata + } + return modelMap, nil +} + +func dataSourceIBMCmVersionRenderTypeToMap(model *catalogmanagementv1.RenderType) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Grouping != nil { + modelMap["grouping"] = *model.Grouping + } + if model.OriginalGrouping != nil { + modelMap["original_grouping"] = *model.OriginalGrouping + } + if model.GroupingIndex != nil { + modelMap["grouping_index"] = *model.GroupingIndex + } + // if model.ConfigConstraints != nil { + // configConstraintsMap := make(map[string]interface{}, len(model.ConfigConstraints)) + // for k, v := range model.ConfigConstraints { + // } + // modelMap["config_constraints"] = flex.Flatten(configConstraintsMap) + // } + if model.Associations != nil { + associationsMap, err := dataSourceIBMCmVersionRenderTypeAssociationsToMap(model.Associations) + if err != nil { + return modelMap, err + } + modelMap["associations"] = []map[string]interface{}{associationsMap} + } + return modelMap, nil +} + +func dataSourceIBMCmVersionRenderTypeAssociationsToMap(model *catalogmanagementv1.RenderTypeAssociations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Parameters != nil { + parameters := []map[string]interface{}{} + for _, parametersItem := range model.Parameters { + parametersItemMap, err := dataSourceIBMCmVersionRenderTypeAssociationsParametersItemToMap(¶metersItem) + if err != nil { + return modelMap, err + } + parameters = append(parameters, parametersItemMap) + } + modelMap["parameters"] = parameters + } + return modelMap, nil +} + +func dataSourceIBMCmVersionRenderTypeAssociationsParametersItemToMap(model *catalogmanagementv1.RenderTypeAssociationsParametersItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.OptionsRefresh != nil { + modelMap["options_refresh"] = *model.OptionsRefresh + } + return modelMap, nil +} + +func dataSourceIBMCmVersionOutputToMap(model *catalogmanagementv1.Output) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmVersionIamPermissionToMap(model *catalogmanagementv1.IamPermission) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ServiceName != nil { + modelMap["service_name"] = *model.ServiceName + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := dataSourceIBMCmVersionIamResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func dataSourceIBMCmVersionIamResourceToMap(model *catalogmanagementv1.IamResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + return modelMap, nil +} + +func dataSourceIBMCmVersionValidationToMap(model *catalogmanagementv1.Validation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Validated != nil { + modelMap["validated"] = model.Validated.String() + } + if model.Requested != nil { + modelMap["requested"] = model.Requested.String() + } + if model.State != nil { + modelMap["state"] = *model.State + } + if model.LastOperation != nil { + modelMap["last_operation"] = *model.LastOperation + } + if model.Target != nil { + targetMap := make(map[string]interface{}, len(model.Target)) + // for k, v := range model.Target { + // } + modelMap["target"] = flex.Flatten(targetMap) + } + if model.Message != nil { + modelMap["message"] = *model.Message + } + return modelMap, nil +} + +func dataSourceIBMCmVersionResourceToMap(model *catalogmanagementv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + } + return modelMap, nil +} + +func dataSourceIBMCmVersionScriptToMap(model *catalogmanagementv1.Script) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Instructions != nil { + modelMap["instructions"] = *model.Instructions + } + if model.InstructionsI18n != nil { + instructionsI18nMap := make(map[string]interface{}, len(model.InstructionsI18n)) + for k, v := range model.InstructionsI18n { + instructionsI18nMap[k] = v + } + modelMap["instructions_i18n"] = flex.Flatten(instructionsI18nMap) + } + if model.Script != nil { + modelMap["script"] = *model.Script + } + if model.ScriptPermission != nil { + modelMap["script_permission"] = *model.ScriptPermission + } + if model.DeleteScript != nil { + modelMap["delete_script"] = *model.DeleteScript + } + if model.Scope != nil { + modelMap["scope"] = *model.Scope + } + return modelMap, nil +} + +func dataSourceIBMCmVersionVersionEntitlementToMap(model *catalogmanagementv1.VersionEntitlement) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ProviderName != nil { + modelMap["provider_name"] = *model.ProviderName + } + if model.ProviderID != nil { + modelMap["provider_id"] = *model.ProviderID + } + if model.ProductID != nil { + modelMap["product_id"] = *model.ProductID + } + if model.PartNumbers != nil { + modelMap["part_numbers"] = model.PartNumbers + } + if model.ImageRepoName != nil { + modelMap["image_repo_name"] = *model.ImageRepoName + } + return modelMap, nil +} + +func dataSourceIBMCmVersionLicenseToMap(model *catalogmanagementv1.License) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmVersionStateToMap(model *catalogmanagementv1.State) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Current != nil { + modelMap["current"] = *model.Current + } + if model.CurrentEntered != nil { + modelMap["current_entered"] = model.CurrentEntered.String() + } + if model.Pending != nil { + modelMap["pending"] = *model.Pending + } + if model.PendingRequested != nil { + modelMap["pending_requested"] = model.PendingRequested.String() + } + if model.Previous != nil { + modelMap["previous"] = *model.Previous + } + return modelMap, nil +} + +func dataSourceIBMCmVersionDeprecatePendingToMap(model *catalogmanagementv1.DeprecatePending) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.DeprecateDate != nil { + modelMap["deprecate_date"] = model.DeprecateDate.String() + } + if model.DeprecateState != nil { + modelMap["deprecate_state"] = *model.DeprecateState + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + return modelMap, nil +} + +func dataSourceIBMCmVersionSolutionInfoToMap(model *catalogmanagementv1.SolutionInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ArchitectureDiagrams != nil { + architectureDiagrams := []map[string]interface{}{} + for _, architectureDiagramsItem := range model.ArchitectureDiagrams { + architectureDiagramsItemMap, err := dataSourceIBMCmVersionArchitectureDiagramToMap(&architectureDiagramsItem) + if err != nil { + return modelMap, err + } + architectureDiagrams = append(architectureDiagrams, architectureDiagramsItemMap) + } + modelMap["architecture_diagrams"] = architectureDiagrams + } + if model.Features != nil { + features := []map[string]interface{}{} + for _, featuresItem := range model.Features { + featuresItemMap, err := dataSourceIBMCmVersionFeatureToMap(&featuresItem) + if err != nil { + return modelMap, err + } + features = append(features, featuresItemMap) + } + modelMap["features"] = features + } + if model.CostEstimate != nil { + costEstimateMap, err := dataSourceIBMCmVersionCostEstimateToMap(model.CostEstimate) + if err != nil { + return modelMap, err + } + modelMap["cost_estimate"] = []map[string]interface{}{costEstimateMap} + } + if model.Dependencies != nil { + dependencies := []map[string]interface{}{} + for _, dependenciesItem := range model.Dependencies { + dependenciesItemMap, err := dataSourceIBMCmVersionDependencyToMap(&dependenciesItem) + if err != nil { + return modelMap, err + } + dependencies = append(dependencies, dependenciesItemMap) + } + modelMap["dependencies"] = dependencies + } + return modelMap, nil +} + +func dataSourceIBMCmVersionArchitectureDiagramToMap(model *catalogmanagementv1.ArchitectureDiagram) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Diagram != nil { + diagramMap, err := dataSourceIBMCmVersionMediaItemToMap(model.Diagram) + if err != nil { + return modelMap, err + } + modelMap["diagram"] = []map[string]interface{}{diagramMap} + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + return modelMap, nil +} + +func dataSourceIBMCmVersionMediaItemToMap(model *catalogmanagementv1.MediaItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.APIURL != nil { + modelMap["api_url"] = *model.APIURL + } + if model.URLProxy != nil { + urlProxyMap, err := dataSourceIBMCmVersionURLProxyToMap(model.URLProxy) + if err != nil { + return modelMap, err + } + modelMap["url_proxy"] = []map[string]interface{}{urlProxyMap} + } + if model.Caption != nil { + modelMap["caption"] = *model.Caption + } + if model.CaptionI18n != nil { + captionI18nMap := make(map[string]interface{}, len(model.CaptionI18n)) + for k, v := range model.CaptionI18n { + captionI18nMap[k] = v + } + modelMap["caption_i18n"] = flex.Flatten(captionI18nMap) + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.ThumbnailURL != nil { + modelMap["thumbnail_url"] = *model.ThumbnailURL + } + return modelMap, nil +} + +func dataSourceIBMCmVersionURLProxyToMap(model *catalogmanagementv1.URLProxy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Sha != nil { + modelMap["sha"] = *model.Sha + } + return modelMap, nil +} + +func dataSourceIBMCmVersionFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = *model.Title + } + if model.TitleI18n != nil { + titleI18nMap := make(map[string]interface{}, len(model.TitleI18n)) + for k, v := range model.TitleI18n { + titleI18nMap[k] = v + } + modelMap["title_i18n"] = flex.Flatten(titleI18nMap) + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.DescriptionI18n != nil { + descriptionI18nMap := make(map[string]interface{}, len(model.DescriptionI18n)) + for k, v := range model.DescriptionI18n { + descriptionI18nMap[k] = v + } + modelMap["description_i18n"] = flex.Flatten(descriptionI18nMap) + } + return modelMap, nil +} + +func dataSourceIBMCmVersionCostEstimateToMap(model *catalogmanagementv1.CostEstimate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Currency != nil { + modelMap["currency"] = *model.Currency + } + if model.Projects != nil { + projects := []map[string]interface{}{} + for _, projectsItem := range model.Projects { + projectsItemMap, err := dataSourceIBMCmVersionProjectToMap(&projectsItem) + if err != nil { + return modelMap, err + } + projects = append(projects, projectsItemMap) + } + modelMap["projects"] = projects + } + if model.Summary != nil { + summaryMap, err := dataSourceIBMCmVersionCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = *model.TotalHourlyCost + } + if model.TotalMonthlyCost != nil { + modelMap["total_monthly_cost"] = *model.TotalMonthlyCost + } + if model.PastTotalHourlyCost != nil { + modelMap["past_total_hourly_cost"] = *model.PastTotalHourlyCost + } + if model.PastTotalMonthlyCost != nil { + modelMap["past_total_monthly_cost"] = *model.PastTotalMonthlyCost + } + if model.DiffTotalHourlyCost != nil { + modelMap["diff_total_hourly_cost"] = *model.DiffTotalHourlyCost + } + if model.DiffTotalMonthlyCost != nil { + modelMap["diff_total_monthly_cost"] = *model.DiffTotalMonthlyCost + } + if model.TimeGenerated != nil { + modelMap["time_generated"] = model.TimeGenerated.String() + } + return modelMap, nil +} + +func dataSourceIBMCmVersionProjectToMap(model *catalogmanagementv1.Project) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.PastBreakdown != nil { + pastBreakdownMap, err := dataSourceIBMCmVersionCostBreakdownToMap(model.PastBreakdown) + if err != nil { + return modelMap, err + } + modelMap["past_breakdown"] = []map[string]interface{}{pastBreakdownMap} + } + if model.Breakdown != nil { + breakdownMap, err := dataSourceIBMCmVersionCostBreakdownToMap(model.Breakdown) + if err != nil { + return modelMap, err + } + modelMap["breakdown"] = []map[string]interface{}{breakdownMap} + } + if model.Diff != nil { + diffMap, err := dataSourceIBMCmVersionCostBreakdownToMap(model.Diff) + if err != nil { + return modelMap, err + } + modelMap["diff"] = []map[string]interface{}{diffMap} + } + if model.Summary != nil { + summaryMap, err := dataSourceIBMCmVersionCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + return modelMap, nil +} + +func dataSourceIBMCmVersionCostBreakdownToMap(model *catalogmanagementv1.CostBreakdown) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = *model.TotalHourlyCost + } + if model.TotalMonthlyCOst != nil { + modelMap["total_monthly_c_ost"] = *model.TotalMonthlyCOst + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := dataSourceIBMCmVersionCostResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func dataSourceIBMCmVersionCostResourceToMap(model *catalogmanagementv1.CostResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Metadata != nil { + metadataMap := make(map[string]interface{}, len(model.Metadata)) + // for k, v := range model.Metadata { + // } + modelMap["metadata"] = flex.Flatten(metadataMap) + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = *model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = *model.MonthlyCost + } + if model.CostComponents != nil { + costComponents := []map[string]interface{}{} + for _, costComponentsItem := range model.CostComponents { + costComponentsItemMap, err := dataSourceIBMCmVersionCostComponentToMap(&costComponentsItem) + if err != nil { + return modelMap, err + } + costComponents = append(costComponents, costComponentsItemMap) + } + modelMap["cost_components"] = costComponents + } + return modelMap, nil +} + +func dataSourceIBMCmVersionCostComponentToMap(model *catalogmanagementv1.CostComponent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Unit != nil { + modelMap["unit"] = *model.Unit + } + if model.HourlyQuantity != nil { + modelMap["hourly_quantity"] = *model.HourlyQuantity + } + if model.MonthlyQuantity != nil { + modelMap["monthly_quantity"] = *model.MonthlyQuantity + } + if model.Price != nil { + modelMap["price"] = *model.Price + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = *model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = *model.MonthlyCost + } + return modelMap, nil +} + +func dataSourceIBMCmVersionCostSummaryToMap(model *catalogmanagementv1.CostSummary) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalDetectedResources != nil { + modelMap["total_detected_resources"] = *model.TotalDetectedResources + } + if model.TotalSupportedResources != nil { + modelMap["total_supported_resources"] = *model.TotalSupportedResources + } + if model.TotalUnsupportedResources != nil { + modelMap["total_unsupported_resources"] = *model.TotalUnsupportedResources + } + if model.TotalUsageBasedResources != nil { + modelMap["total_usage_based_resources"] = *model.TotalUsageBasedResources + } + if model.TotalNoPriceResources != nil { + modelMap["total_no_price_resources"] = *model.TotalNoPriceResources + } + if model.UnsupportedResourceCounts != nil { + unsupportedResourceCountsMap := make(map[string]interface{}, len(model.UnsupportedResourceCounts)) + for k, v := range model.UnsupportedResourceCounts { + unsupportedResourceCountsMap[k] = v + } + modelMap["unsupported_resource_counts"] = flex.Flatten(unsupportedResourceCountsMap) + } + if model.NoPriceResourceCounts != nil { + noPriceResourceCountsMap := make(map[string]interface{}, len(model.NoPriceResourceCounts)) + for k, v := range model.NoPriceResourceCounts { + noPriceResourceCountsMap[k] = v + } + modelMap["no_price_resource_counts"] = flex.Flatten(noPriceResourceCountsMap) + } + return modelMap, nil +} + +func dataSourceIBMCmVersionDependencyToMap(model *catalogmanagementv1.Dependency) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CatalogID != nil { + modelMap["catalog_id"] = *model.CatalogID + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Version != nil { + modelMap["version"] = *model.Version + } + if model.Flavors != nil { + modelMap["flavors"] = model.Flavors + } + return modelMap, nil +} diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_version_test.go b/ibm/service/catalogmanagement/data_source_ibm_cm_version_test.go new file mode 100644 index 000000000..a07bb26ff --- /dev/null +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_version_test.go @@ -0,0 +1,79 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCmVersionDataSourceSimpleArgs(t *testing.T) { + versionZipurl := "https://github.com/IBM-Cloud/terraform-sample/archive/refs/tags/v1.1.0.tar.gz" + versionTargetVersion := "1.1.1" + versionIncludeConfig := "true" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmVersionDataSourceConfig(versionZipurl, versionTargetVersion, versionIncludeConfig), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "rev"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "version"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "sha"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "created"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "updated"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "offering_id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "catalog_id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "kind_id"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "repo_url"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "tgz_url"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "configuration.#"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "licenses.#"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "state.#"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "version_locator"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "long_description"), + resource.TestCheckResourceAttrSet("data.ibm_cm_version.cm_version", "is_consumable"), + ), + }, + }, + }) +} + +func testAccCheckIBMCmVersionDataSourceConfig(versionZipurl string, versionTargetVersion string, versionIncludeConfig string) string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "data_source_version_test_catalog_label" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "test_tf_offering_label_1" + name = "test_tf_offering_name_1" + offering_icon_url = "test.url.1" + tags = ["dev_ops"] + } + + resource "ibm_cm_version" "cm_version" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + zipurl = "%s" + target_version = "%s" + include_config = %s + install {} + } + + data "ibm_cm_version" "cm_version" { + version_loc_id = ibm_cm_version.cm_version.version_locator + } + `, versionZipurl, versionTargetVersion, versionIncludeConfig) +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_catalog.go b/ibm/service/catalogmanagement/resource_ibm_cm_catalog.go new file mode 100644 index 000000000..6b7410d70 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_catalog.go @@ -0,0 +1,1003 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func ResourceIBMCmCatalog() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCmCatalogCreate, + ReadContext: resourceIBMCmCatalogRead, + UpdateContext: resourceIBMCmCatalogUpdate, + DeleteContext: resourceIBMCmCatalogDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display Name in the requested language.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description in the requested language.", + }, + "short_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "catalog_icon_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for an icon associated with this catalog.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of features associated with this catalog.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Denotes whether a catalog is disabled.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group id the catalog is owned by.", + }, + "owning_account": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Account that owns catalog.", + }, + "catalog_filters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Filters for account and catalog filters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "include_all": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "-> true - Include all of the public catalog when filtering. Further settings will specifically exclude some offerings. false - Exclude all of the public catalog when filtering. Further settings will specifically include some offerings.", + }, + "category_filters": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Filter against offering properties.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "id_filters": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Filter on offering ID's. There is an include filter and an exclule filter. Both can be set.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "include": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering filter terms.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter_terms": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "exclude": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering filter terms.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter_terms": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "syndication_settings": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "remove_related_components": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Remove related components.", + }, + "clusters": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Syndication clusters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster region.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster name.", + }, + "resource_group_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource group ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Syndication type.", + }, + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Syndicated namespaces.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "all_namespaces": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Syndicated to all namespaces on cluster.", + }, + }, + }, + }, + "history": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Array of syndicated namespaces.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "clusters": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Array of syndicated namespaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster region.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cluster name.", + }, + "resource_group_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource group ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Syndication type.", + }, + "namespaces": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Syndicated namespaces.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "all_namespaces": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Syndicated to all namespaces on cluster.", + }, + }, + }, + }, + "last_run": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time last syndicated.", + }, + }, + }, + }, + "authorization": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Feature information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Array of syndicated namespaces.", + }, + "last_run": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time last updated.", + }, + }, + }, + }, + }, + }, + }, + "kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Kind of catalog. Supported kinds are offering and vpe.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Catalog specific metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The url for this specific catalog.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN associated with the catalog.", + }, + "offerings_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL path to offerings.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date-time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date-time this catalog was last updated.", + }, + }, + } +} + +func resourceIBMCmCatalogCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + createCatalogOptions := &catalogmanagementv1.CreateCatalogOptions{} + + if _, ok := d.GetOk("label"); ok { + createCatalogOptions.SetLabel(d.Get("label").(string)) + } + if _, ok := d.GetOk("label_i18n"); ok { + // TODO: Add code to handle map container: LabelI18n + } + if _, ok := d.GetOk("short_description"); ok { + createCatalogOptions.SetShortDescription(d.Get("short_description").(string)) + } + if _, ok := d.GetOk("short_description_i18n"); ok { + // TODO: Add code to handle map container: ShortDescriptionI18n + } + if _, ok := d.GetOk("catalog_icon_url"); ok { + createCatalogOptions.SetCatalogIconURL(d.Get("catalog_icon_url").(string)) + } + if _, ok := d.GetOk("tags"); ok { + createCatalogOptions.SetTags(SIToSS(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("features"); ok { + var features []catalogmanagementv1.Feature + for _, e := range d.Get("features").([]interface{}) { + value := e.(map[string]interface{}) + featuresItem, err := resourceIBMCmCatalogMapToFeature(value) + if err != nil { + return diag.FromErr(err) + } + features = append(features, *featuresItem) + } + createCatalogOptions.SetFeatures(features) + } + if _, ok := d.GetOk("disabled"); ok { + createCatalogOptions.SetDisabled(d.Get("disabled").(bool)) + } + if _, ok := d.GetOk("resource_group_id"); ok { + createCatalogOptions.SetResourceGroupID(d.Get("resource_group_id").(string)) + } + if _, ok := d.GetOk("owning_account"); ok { + createCatalogOptions.SetOwningAccount(d.Get("owning_account").(string)) + } + if _, ok := d.GetOk("catalog_filters"); ok { + catalogFiltersModel, err := resourceIBMCmCatalogMapToFilters(d.Get("catalog_filters.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createCatalogOptions.SetCatalogFilters(catalogFiltersModel) + } + if _, ok := d.GetOk("syndication_settings"); ok { + syndicationSettingsModel, err := resourceIBMCmCatalogMapToSyndicationResource(d.Get("syndication_settings.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createCatalogOptions.SetSyndicationSettings(syndicationSettingsModel) + } + if _, ok := d.GetOk("kind"); ok { + createCatalogOptions.SetKind(d.Get("kind").(string)) + } + if _, ok := d.GetOk("metadata"); ok { + // TODO: Add code to handle map container: Metadata + } + + catalog, response, err := catalogManagementClient.CreateCatalogWithContext(context, createCatalogOptions) + if err != nil { + log.Printf("[DEBUG] CreateCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateCatalogWithContext failed %s\n%s", err, response)) + } + + d.SetId(*catalog.ID) + + return resourceIBMCmCatalogRead(context, d, meta) +} + +func resourceIBMCmCatalogRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} + + getCatalogOptions.SetCatalogIdentifier(d.Id()) + + catalog, response, err := catalogManagementClient.GetCatalogWithContext(context, getCatalogOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCatalogWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("label", catalog.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + if catalog.LabelI18n != nil { + // TODO: handle LabelI18n of type TypeMap -- not primitive type, not list + } + if err = d.Set("short_description", catalog.ShortDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) + } + if catalog.ShortDescriptionI18n != nil { + // TODO: handle ShortDescriptionI18n of type TypeMap -- not primitive type, not list + } + if err = d.Set("catalog_icon_url", catalog.CatalogIconURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_icon_url: %s", err)) + } + if catalog.Tags != nil { + if err = d.Set("tags", catalog.Tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + } + features := []map[string]interface{}{} + if catalog.Features != nil { + for _, featuresItem := range catalog.Features { + featuresItemMap, err := resourceIBMCmCatalogFeatureToMap(&featuresItem) + if err != nil { + return diag.FromErr(err) + } + features = append(features, featuresItemMap) + } + } + if err = d.Set("features", features); err != nil { + return diag.FromErr(fmt.Errorf("Error setting features: %s", err)) + } + if err = d.Set("disabled", catalog.Disabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disabled: %s", err)) + } + if err = d.Set("resource_group_id", catalog.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("owning_account", catalog.OwningAccount); err != nil { + return diag.FromErr(fmt.Errorf("Error setting owning_account: %s", err)) + } + if catalog.CatalogFilters != nil { + catalogFiltersMap, err := resourceIBMCmCatalogFiltersToMap(catalog.CatalogFilters) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("catalog_filters", []map[string]interface{}{catalogFiltersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_filters: %s", err)) + } + } + if catalog.SyndicationSettings != nil { + syndicationSettingsMap, err := resourceIBMCmCatalogSyndicationResourceToMap(catalog.SyndicationSettings) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("syndication_settings", []map[string]interface{}{syndicationSettingsMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting syndication_settings: %s", err)) + } + } + if err = d.Set("kind", catalog.Kind); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kind: %s", err)) + } + if catalog.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- not primitive type, not list + } + if err = d.Set("rev", catalog.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + if err = d.Set("url", catalog.URL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + } + if err = d.Set("crn", catalog.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("offerings_url", catalog.OfferingsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offerings_url: %s", err)) + } + if err = d.Set("created", flex.DateTimeToString(catalog.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + if err = d.Set("updated", flex.DateTimeToString(catalog.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + + return nil +} + +func resourceIBMCmCatalogUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + replaceCatalogOptions := &catalogmanagementv1.ReplaceCatalogOptions{} + + replaceCatalogOptions.SetCatalogIdentifier(d.Id()) + replaceCatalogOptions.SetID(d.Id()) + if _, ok := d.GetOk("label"); ok { + replaceCatalogOptions.SetLabel(d.Get("label").(string)) + } + if _, ok := d.GetOk("label_i18n"); ok { + // TODO: Non-primitive types that are not models or lists + } + if _, ok := d.GetOk("short_description"); ok { + replaceCatalogOptions.SetShortDescription(d.Get("short_description").(string)) + } + if _, ok := d.GetOk("short_description_i18n"); ok { + // TODO: Non-primitive types that are not models or lists + } + if _, ok := d.GetOk("catalog_icon_url"); ok { + replaceCatalogOptions.SetCatalogIconURL(d.Get("catalog_icon_url").(string)) + } + if _, ok := d.GetOk("tags"); ok { + replaceCatalogOptions.SetTags(d.Get("tags").([]string)) + } + if _, ok := d.GetOk("features"); ok { + var features []catalogmanagementv1.Feature + for _, e := range d.Get("features").([]interface{}) { + value := e.(map[string]interface{}) + featuresItem, err := resourceIBMCmCatalogMapToFeature(value) + if err != nil { + return diag.FromErr(err) + } + features = append(features, *featuresItem) + } + replaceCatalogOptions.SetFeatures(features) + } + if _, ok := d.GetOk("disabled"); ok { + replaceCatalogOptions.SetDisabled(d.Get("disabled").(bool)) + } + if _, ok := d.GetOk("resource_group_id"); ok { + replaceCatalogOptions.SetResourceGroupID(d.Get("resource_group_id").(string)) + } + if _, ok := d.GetOk("owning_account"); ok { + replaceCatalogOptions.SetOwningAccount(d.Get("owning_account").(string)) + } + if _, ok := d.GetOk("catalog_filters"); ok { + catalogFilters, err := resourceIBMCmCatalogMapToFilters(d.Get("catalog_filters.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceCatalogOptions.SetCatalogFilters(catalogFilters) + } + if _, ok := d.GetOk("syndication_settings"); ok { + syndicationSettings, err := resourceIBMCmCatalogMapToSyndicationResource(d.Get("syndication_settings.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceCatalogOptions.SetSyndicationSettings(syndicationSettings) + } + if _, ok := d.GetOk("kind"); ok { + replaceCatalogOptions.SetKind(d.Get("kind").(string)) + } + if _, ok := d.GetOk("metadata"); ok { + // TODO: Non-primitive types that are not models or lists + } + + _, response, err := catalogManagementClient.ReplaceCatalogWithContext(context, replaceCatalogOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceCatalogWithContext failed %s\n%s", err, response)) + } + + return resourceIBMCmCatalogRead(context, d, meta) +} + +func resourceIBMCmCatalogDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + deleteCatalogOptions := &catalogmanagementv1.DeleteCatalogOptions{} + + deleteCatalogOptions.SetCatalogIdentifier(d.Id()) + + response, err := catalogManagementClient.DeleteCatalogWithContext(context, deleteCatalogOptions) + if err != nil { + log.Printf("[DEBUG] DeleteCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteCatalogWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCmCatalogMapToFeature(modelMap map[string]interface{}) (*catalogmanagementv1.Feature, error) { + model := &catalogmanagementv1.Feature{} + if modelMap["title"] != nil && modelMap["title"].(string) != "" { + model.Title = core.StringPtr(modelMap["title"].(string)) + } + if modelMap["title_i18n"] != nil { + // TODO: handle TitleI18n, map with entry type '' + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["description_i18n"] != nil { + // TODO: handle DescriptionI18n, map with entry type '' + } + return model, nil +} + +func resourceIBMCmCatalogMapToFilters(modelMap map[string]interface{}) (*catalogmanagementv1.Filters, error) { + model := &catalogmanagementv1.Filters{} + if modelMap["include_all"] != nil { + model.IncludeAll = core.BoolPtr(modelMap["include_all"].(bool)) + } + if modelMap["category_filters"] != nil { + // TODO: handle CategoryFilters, map with entry type 'CategoryFilter' + } + if modelMap["id_filters"] != nil && len(modelMap["id_filters"].([]interface{})) > 0 { + var IDFiltersModel *catalogmanagementv1.IDFilter + var err error + if modelMap["id_filters"].([]interface{})[0] != nil { + IDFiltersModel, err = resourceIBMCmCatalogMapToIDFilter(modelMap["id_filters"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + } + model.IDFilters = IDFiltersModel + } + return model, nil +} + +func resourceIBMCmCatalogMapToCategoryFilter(modelMap map[string]interface{}) (*catalogmanagementv1.CategoryFilter, error) { + model := &catalogmanagementv1.CategoryFilter{} + if modelMap["include"] != nil { + model.Include = core.BoolPtr(modelMap["include"].(bool)) + } + if modelMap["filter"] != nil && len(modelMap["filter"].([]interface{})) > 0 { + FilterModel, err := resourceIBMCmCatalogMapToFilterTerms(modelMap["filter"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Filter = FilterModel + } + return model, nil +} + +func resourceIBMCmCatalogMapToFilterTerms(modelMap map[string]interface{}) (*catalogmanagementv1.FilterTerms, error) { + model := &catalogmanagementv1.FilterTerms{} + if modelMap["filter_terms"] != nil { + filterTerms := []string{} + for _, filterTermsItem := range modelMap["filter_terms"].([]interface{}) { + filterTerms = append(filterTerms, filterTermsItem.(string)) + } + model.FilterTerms = filterTerms + } + return model, nil +} + +func resourceIBMCmCatalogMapToIDFilter(modelMap map[string]interface{}) (*catalogmanagementv1.IDFilter, error) { + model := &catalogmanagementv1.IDFilter{} + if modelMap["include"] != nil && len(modelMap["include"].([]interface{})) > 0 { + IncludeModel, err := resourceIBMCmCatalogMapToFilterTerms(modelMap["include"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Include = IncludeModel + } + if modelMap["exclude"] != nil && len(modelMap["exclude"].([]interface{})) > 0 { + ExcludeModel, err := resourceIBMCmCatalogMapToFilterTerms(modelMap["exclude"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Exclude = ExcludeModel + } + return model, nil +} + +func resourceIBMCmCatalogMapToSyndicationResource(modelMap map[string]interface{}) (*catalogmanagementv1.SyndicationResource, error) { + model := &catalogmanagementv1.SyndicationResource{} + if modelMap["remove_related_components"] != nil { + model.RemoveRelatedComponents = core.BoolPtr(modelMap["remove_related_components"].(bool)) + } + if modelMap["clusters"] != nil { + clusters := []catalogmanagementv1.SyndicationCluster{} + for _, clustersItem := range modelMap["clusters"].([]interface{}) { + clustersItemModel, err := resourceIBMCmCatalogMapToSyndicationCluster(clustersItem.(map[string]interface{})) + if err != nil { + return model, err + } + clusters = append(clusters, *clustersItemModel) + } + model.Clusters = clusters + } + if modelMap["history"] != nil && len(modelMap["history"].([]interface{})) > 0 { + var HistoryModel *catalogmanagementv1.SyndicationHistory + var err error + if modelMap["history"].([]interface{})[0] != nil { + HistoryModel, err = resourceIBMCmCatalogMapToSyndicationHistory(modelMap["history"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + } + model.History = HistoryModel + } + if modelMap["authorization"] != nil && len(modelMap["authorization"].([]interface{})) > 0 { + AuthorizationModel, err := resourceIBMCmCatalogMapToSyndicationAuthorization(modelMap["authorization"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Authorization = AuthorizationModel + } + return model, nil +} + +func resourceIBMCmCatalogMapToSyndicationCluster(modelMap map[string]interface{}) (*catalogmanagementv1.SyndicationCluster, error) { + model := &catalogmanagementv1.SyndicationCluster{} + if modelMap["region"] != nil && modelMap["region"].(string) != "" { + model.Region = core.StringPtr(modelMap["region"].(string)) + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["resource_group_name"] != nil && modelMap["resource_group_name"].(string) != "" { + model.ResourceGroupName = core.StringPtr(modelMap["resource_group_name"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["namespaces"] != nil { + namespaces := []string{} + for _, namespacesItem := range modelMap["namespaces"].([]interface{}) { + namespaces = append(namespaces, namespacesItem.(string)) + } + model.Namespaces = namespaces + } + if modelMap["all_namespaces"] != nil { + model.AllNamespaces = core.BoolPtr(modelMap["all_namespaces"].(bool)) + } + return model, nil +} + +func resourceIBMCmCatalogMapToSyndicationHistory(modelMap map[string]interface{}) (*catalogmanagementv1.SyndicationHistory, error) { + model := &catalogmanagementv1.SyndicationHistory{} + if modelMap["namespaces"] != nil { + namespaces := []string{} + for _, namespacesItem := range modelMap["namespaces"].([]interface{}) { + namespaces = append(namespaces, namespacesItem.(string)) + } + model.Namespaces = namespaces + } + if modelMap["clusters"] != nil { + clusters := []catalogmanagementv1.SyndicationCluster{} + for _, clustersItem := range modelMap["clusters"].([]interface{}) { + clustersItemModel, err := resourceIBMCmCatalogMapToSyndicationCluster(clustersItem.(map[string]interface{})) + if err != nil { + return model, err + } + clusters = append(clusters, *clustersItemModel) + } + model.Clusters = clusters + } + if modelMap["last_run"] != nil { + + } + return model, nil +} + +func resourceIBMCmCatalogMapToSyndicationAuthorization(modelMap map[string]interface{}) (*catalogmanagementv1.SyndicationAuthorization, error) { + model := &catalogmanagementv1.SyndicationAuthorization{} + if modelMap["token"] != nil && modelMap["token"].(string) != "" { + model.Token = core.StringPtr(modelMap["token"].(string)) + } + if modelMap["last_run"] != nil { + + } + return model, nil +} + +func resourceIBMCmCatalogFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = model.Title + } + if model.TitleI18n != nil { + // TODO: handle TitleI18n of type TypeMap -- container, not list + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmCatalogFiltersToMap(model *catalogmanagementv1.Filters) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.IncludeAll != nil { + modelMap["include_all"] = model.IncludeAll + } + if model.CategoryFilters != nil { + // TODO: handle CategoryFilters of type TypeMap -- container, not list + } + if model.IDFilters != nil { + idFiltersMap, err := resourceIBMCmCatalogIDFilterToMap(model.IDFilters) + if err != nil { + return modelMap, err + } + modelMap["id_filters"] = []map[string]interface{}{idFiltersMap} + } + return modelMap, nil +} + +func resourceIBMCmCatalogCategoryFilterToMap(model *catalogmanagementv1.CategoryFilter) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Include != nil { + modelMap["include"] = model.Include + } + if model.Filter != nil { + filterMap, err := resourceIBMCmCatalogFilterTermsToMap(model.Filter) + if err != nil { + return modelMap, err + } + modelMap["filter"] = []map[string]interface{}{filterMap} + } + return modelMap, nil +} + +func resourceIBMCmCatalogFilterTermsToMap(model *catalogmanagementv1.FilterTerms) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.FilterTerms != nil { + modelMap["filter_terms"] = model.FilterTerms + } + return modelMap, nil +} + +func resourceIBMCmCatalogIDFilterToMap(model *catalogmanagementv1.IDFilter) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Include != nil { + includeMap, err := resourceIBMCmCatalogFilterTermsToMap(model.Include) + if err != nil { + return modelMap, err + } + modelMap["include"] = []map[string]interface{}{includeMap} + } + if model.Exclude != nil { + excludeMap, err := resourceIBMCmCatalogFilterTermsToMap(model.Exclude) + if err != nil { + return modelMap, err + } + modelMap["exclude"] = []map[string]interface{}{excludeMap} + } + return modelMap, nil +} + +func resourceIBMCmCatalogSyndicationResourceToMap(model *catalogmanagementv1.SyndicationResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.RemoveRelatedComponents != nil { + modelMap["remove_related_components"] = model.RemoveRelatedComponents + } + if model.Clusters != nil { + clusters := []map[string]interface{}{} + for _, clustersItem := range model.Clusters { + clustersItemMap, err := resourceIBMCmCatalogSyndicationClusterToMap(&clustersItem) + if err != nil { + return modelMap, err + } + clusters = append(clusters, clustersItemMap) + } + modelMap["clusters"] = clusters + } + if model.History != nil { + historyMap, err := resourceIBMCmCatalogSyndicationHistoryToMap(model.History) + if err != nil { + return modelMap, err + } + modelMap["history"] = []map[string]interface{}{historyMap} + } + if model.Authorization != nil { + authorizationMap, err := resourceIBMCmCatalogSyndicationAuthorizationToMap(model.Authorization) + if err != nil { + return modelMap, err + } + modelMap["authorization"] = []map[string]interface{}{authorizationMap} + } + return modelMap, nil +} + +func resourceIBMCmCatalogSyndicationClusterToMap(model *catalogmanagementv1.SyndicationCluster) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Region != nil { + modelMap["region"] = model.Region + } + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.ResourceGroupName != nil { + modelMap["resource_group_name"] = model.ResourceGroupName + } + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Namespaces != nil { + modelMap["namespaces"] = model.Namespaces + } + if model.AllNamespaces != nil { + modelMap["all_namespaces"] = model.AllNamespaces + } + return modelMap, nil +} + +func resourceIBMCmCatalogSyndicationHistoryToMap(model *catalogmanagementv1.SyndicationHistory) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Namespaces != nil { + modelMap["namespaces"] = model.Namespaces + } + if model.Clusters != nil { + clusters := []map[string]interface{}{} + for _, clustersItem := range model.Clusters { + clustersItemMap, err := resourceIBMCmCatalogSyndicationClusterToMap(&clustersItem) + if err != nil { + return modelMap, err + } + clusters = append(clusters, clustersItemMap) + } + modelMap["clusters"] = clusters + } + if model.LastRun != nil { + modelMap["last_run"] = model.LastRun.String() + } + return modelMap, nil +} + +func resourceIBMCmCatalogSyndicationAuthorizationToMap(model *catalogmanagementv1.SyndicationAuthorization) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Token != nil { + modelMap["token"] = model.Token + } + if model.LastRun != nil { + modelMap["last_run"] = model.LastRun.String() + } + return modelMap, nil +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_catalog_test.go b/ibm/service/catalogmanagement/resource_ibm_cm_catalog_test.go new file mode 100644 index 000000000..f6f2662ed --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_catalog_test.go @@ -0,0 +1,144 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func TestAccIBMCmCatalogBasic(t *testing.T) { + var conf catalogmanagementv1.Catalog + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmCatalogDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmCatalogConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmCatalogExists("ibm_cm_catalog.cm_catalog", conf), + ), + }, + }, + }) +} + +func TestAccIBMCmCatalogSimpleArgs(t *testing.T) { + var conf catalogmanagementv1.Catalog + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmCatalogDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmCatalogConfig(label, shortDescription), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmCatalogExists("ibm_cm_catalog.cm_catalog", conf), + resource.TestCheckResourceAttr("ibm_cm_catalog.cm_catalog", "label", label), + resource.TestCheckResourceAttr("ibm_cm_catalog.cm_catalog", "short_description", shortDescription), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCmCatalogConfig(label, shortDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cm_catalog.cm_catalog", "label", label), + resource.TestCheckResourceAttr("ibm_cm_catalog.cm_catalog", "short_description", shortDescription), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cm_catalog.cm_catalog", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCmCatalogConfigBasic() string { + return fmt.Sprintf(` + + resource "ibm_cm_catalog" "cm_catalog" { + label = "basic-catalog-label-test" + kind = "offering" + } + `) +} + +func testAccCheckIBMCmCatalogConfig(label string, shortDescription string) string { + return fmt.Sprintf(` + + resource "ibm_cm_catalog" "cm_catalog" { + label = "%s" + kind = "offering" + short_description = "%s" + } + `, label, shortDescription) +} + +func testAccCheckIBMCmCatalogExists(n string, obj catalogmanagementv1.Catalog) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + + getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} + + getCatalogOptions.SetCatalogIdentifier(rs.Primary.ID) + + catalog, _, err := catalogManagementClient.GetCatalog(getCatalogOptions) + if err != nil { + return err + } + + obj = *catalog + return nil + } +} + +func testAccCheckIBMCmCatalogDestroy(s *terraform.State) error { + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cm_catalog" { + continue + } + + getCatalogOptions := &catalogmanagementv1.GetCatalogOptions{} + + getCatalogOptions.SetCatalogIdentifier(rs.Primary.ID) + + // Try to find the key + _, response, err := catalogManagementClient.GetCatalog(getCatalogOptions) + + if err == nil { + return fmt.Errorf("cm_catalog still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cm_catalog (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_offering.go b/ibm/service/catalogmanagement/resource_ibm_cm_offering.go new file mode 100644 index 000000000..b900697c1 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_offering.go @@ -0,0 +1,6058 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func ResourceIBMCmOffering() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCmOfferingCreate, + ReadContext: resourceIBMCmOfferingRead, + UpdateContext: resourceIBMCmOfferingUpdate, + DeleteContext: resourceIBMCmOfferingDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "catalog_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Catalog identifier.", + }, + "offering_identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Offering identifier. Provide this when an offering already exists and you wish to use it as a terraform resource.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The url for this specific offering.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The crn for this specific offering.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display Name in the requested language.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The programmatic name of this offering.", + }, + "offering_icon_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for an icon associated with this offering.", + }, + "offering_docs_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for an additional docs with this offering.", + }, + "offering_support_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "[deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "keywords": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of keywords associated with offering, typically used to search for it.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "rating": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Repository info for offerings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "one_star_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "One start rating.", + }, + "two_star_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Two start rating.", + }, + "three_star_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Three start rating.", + }, + "four_star_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Four start rating.", + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this catalog was last updated.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Short description in the requested language.", + }, + "short_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Long description in the requested language.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "kinds": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Array of kind.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique ID.", + }, + "format_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "content kind, e.g., helm, vm image.", + }, + "install_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "install kind, e.g., helm, operator, terraform.", + }, + "target_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "target cloud to install, e.g., iks, open_shift_iks.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "additional_features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The date and time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The date and time this catalog was last updated.", + }, + "versions": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of versions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique ID.", + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Cloudant revision.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version's CRN.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version of content type.", + }, + "flavor": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Version Flavor Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name for this flavor.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Label for this flavor.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "index": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Order that this flavor should appear when listed for a single version.", + }, + }, + }, + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "hash of the content.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The date and time this version was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The date and time this version was last updated.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Offering ID.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Catalog ID.", + }, + "kind_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Kind ID.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Content's repo URL.", + }, + "source_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Content's source URL (e.g git repo).", + }, + "tgz_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "File used to on-board this version.", + }, + "configuration": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of user solicited overrides.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Configuration key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Value type (string, boolean, int).", + }, + // "default_value": &schema.Schema{ + // Type: schema.TypeMap, + // Optional: true, + // Description: "The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`.", + // }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display name for configuration type.", + }, + "value_constraint": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Constraint associated with value, e.g., for string type - regx:[a-z].", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Key description.", + }, + "required": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Is key required to install.", + }, + "options": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of options of type.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Hide values.", + }, + "custom_config": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Render type.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "ID of the widget type.", + }, + "grouping": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment).", + }, + "original_grouping": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Original grouping type for this configuration (3 types - Target, Resource, and Deployment).", + }, + "grouping_index": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Determines the order that this configuration item shows in that particular grouping.", + }, + "config_constraints": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Map of constraint parameters that will be passed to the custom widget.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "associations": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "List of parameters that are associated with this configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameters": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Parameters for this association.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of this parameter.", + }, + "options_refresh": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Refresh options.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "type_metadata": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The original type, as found in the source being onboarded.", + }, + }, + }, + }, + "outputs": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of output values for this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Output key.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Output description.", + }, + }, + }, + }, + "iam_permissions": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of IAM permissions that are required to consume this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Service name.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources for this permission.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource description.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "metadata": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Generic data to be included with content being onboarded. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version source URL.", + }, + "version_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version name.", + }, + "terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Terraform version.", + }, + "validated_terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version name.", + }, + "vsi_vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "VSI VPC version information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "validation": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Validation response.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "validated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of last successful validation.", + }, + "requested": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of last validation was requested.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Current validation state - , in_progress, valid, invalid, expired.", + }, + "last_operation": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Last operation (e.g. submit_deployment, generate_installer, install_offering.", + }, + "target": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Any message needing to be conveyed as part of the validation job.", + }, + }, + }, + }, + "required_resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resource requirments for installation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of requirement.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value.", + }, + }, + }, + }, + "single_instance": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Denotes if single instance can be deployed to a given cluster.", + }, + "install": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Script information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "pre_install": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Optional pre-install instructions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "entitlement": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Entitlement license info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Provider name.", + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Provider ID.", + }, + "product_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Product ID.", + }, + "part_numbers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Image repository name.", + }, + }, + }, + }, + "licenses": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of licenses the product was built with.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "License ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "license name.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "type of license e.g., Apache xxx.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for the license text.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "License description.", + }, + }, + }, + }, + "image_manifest_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "If set, denotes a url to a YAML file with list of container images used by this version.", + }, + "deprecated": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "read only field, indicating if this version is deprecated.", + }, + "package_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version of the package used to create this version.", + }, + "state": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering state.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "current_entered": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of current request.", + }, + "pending": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "pending_requested": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of pending request.", + }, + "previous": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + }, + }, + }, + "version_locator": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A dotted value of `catalogID`.`versionID`.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Long description for version.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "whitelisted_accounts": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Whitelisted accounts for version.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_pull_key_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "ID of the image pull key to use from Offering.ImagePullKeys.", + }, + "deprecate_pending": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Deprecation information for an Offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deprecate_date": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date of deprecation.", + }, + "deprecate_state": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Deprecation state.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "solution_info": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Version Solution Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "architecture_diagrams": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Architecture diagrams for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "diagram": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering Media information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description of this diagram.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Features - titles only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "cost_estimate": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost estimate definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost estimate version.", + }, + "currency": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost estimate currency.", + }, + "projects": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost estimate projects.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Project name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Project metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "past_breakdown": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "breakdown": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "diff": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "past_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Past total hourly cost.", + }, + "past_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Past total monthly cost.", + }, + "diff_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Difference in total hourly cost.", + }, + "diff_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Difference in total monthly cost.", + }, + "time_generated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "When this estimate was generated.", + }, + }, + }, + }, + "dependencies": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Dependencies for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - If not specified, assumes the Public Catalog.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - Offering ID - not required if name is set.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - Programmatic Offering name.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Required - Semver value or range.", + }, + "flavors": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Optional - List of dependent flavors in the specified range.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "is_consumable": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Is the version able to be shared.", + }, + }, + }, + }, + "plans": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of plans.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "unique id.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display Name in the requested language.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The programmatic name of this offering.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Short description in the requested language.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Long description in the requested language.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "additional_features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of features associated with this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "the date'time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "the date'time this catalog was last updated.", + }, + "deployments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of deployments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "unique id.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display Name in the requested language.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The programmatic name of this offering.", + }, + "short_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Short description in the requested language.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Long description in the requested language.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "open ended metadata information.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of tags associated with this catalog.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "the date'time this catalog was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "the date'time this catalog was last updated.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "pc_managed": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Offering is managed by Partner Center.", + }, + "publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Offering has been approved to publish to permitted to IBM or Public Catalog.", + }, + "share_with_all": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Denotes public availability of an Offering - if share_enabled is true.", + }, + "share_with_ibm": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Denotes IBM employee availability of an Offering - if share_enabled is true.", + }, + "share_enabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Denotes sharing including access list availability of an Offering is enabled.", + }, + "publish_to_access_list": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of account IDs to add to this offering's access list.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "publish_to_ibm": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Whether you would like to publish this offering to IBM or not.", + }, + "publish_to_public": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Whether you would like to publish this offering to the public catalog or not.", + }, + "permit_request_ibm_public_publish": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Deprecated: "This argument is deprecated", + Description: "Is it permitted to request publishing to IBM or Public.", + }, + "ibm_publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Deprecated: "This argument is deprecated", + Description: "Indicates if this offering has been approved for use by all IBMers.", + }, + "public_publish_approved": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Deprecated: "This argument is deprecated", + Description: "Indicates if this offering has been approved for use by all IBM Cloud users.", + }, + "public_original_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The original offering CRN that this publish entry came from.", + }, + "publish_public_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The crn of the public catalog entry of this offering.", + }, + "portal_approval_record": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The portal's approval record ID.", + }, + "portal_ui_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The portal UI URL.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the catalog containing this offering.", + }, + "catalog_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the catalog.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Map of metadata values for this offering.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "disclaimer": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A disclaimer for this offering.", + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Determine if this offering should be displayed in the Consumption UI.", + }, + // "provider": &schema.Schema{ + // Type: schema.TypeString, + // Optional: true, + // Deprecated: "This argument is deprecated", + // Description: "Deprecated - Provider of this offering.", + // }, + "provider_info": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Information on the provider for this offering, or omitted if no provider information is given.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The id of this provider.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of this provider.", + }, + }, + }, + }, + "repo_info": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Repository info for offerings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Token for private repos.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Public or enterprise GitHub.", + }, + }, + }, + }, + "image_pull_keys": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image pull keys for this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Key name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Key value.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Key description.", + }, + }, + }, + }, + "support": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering Support information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL to be displayed in the Consumption UI for getting support on this offering.", + }, + "process": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Support process as provided by an ISV.", + }, + "process_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "locations": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of country codes indicating where support is provided.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "support_details": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of support options (e.g. email, phone, slack, other).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of the current support detail.", + }, + "contact": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Contact for the current support detail.", + }, + "response_wait_time": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "availability": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Times when support is available.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "times": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of support times.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "day": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The day of the week, represented as an integer.", + }, + "start_time": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00).", + }, + "end_time": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00).", + }, + }, + }, + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Timezone (e.g. America/New_York).", + }, + "always_available": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Is this support always available.", + }, + }, + }, + }, + }, + }, + }, + "support_escalation": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Support escalation policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "escalation_wait_time": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "response_wait_time": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Time descriptor.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Amount of time to wait in unit 'type'.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Valid values are hour or day.", + }, + }, + }, + }, + "contact": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Escalation contact.", + }, + }, + }, + }, + "support_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Support type for this product.", + }, + }, + }, + }, + "media": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of media items related to this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "deprecate_pending": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Deprecation information for an Offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deprecate_date": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date of deprecation.", + }, + "deprecate_state": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Deprecation state.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "product_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The product kind. Valid values are module, solution, or empty string.", + }, + "badges": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A list of badges for this offering.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "ID of the current badge.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display name for the current badge.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description of the current badge.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "icon": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Icon for the current badge.", + }, + "authority": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Authority for the current badge.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Tag for the current badge.", + }, + "learn_more_links": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Learn more links for a badge.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "first_party": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "First party link.", + }, + "third_party": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Third party link.", + }, + }, + }, + }, + "constraints": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "An optional set of constraints indicating which versions in an Offering have this particular badge.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of the current constraint.", + }, + "rule": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Rule for the current constraint.", + }, + }, + }, + }, + }, + }, + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "unique id.", + }, + }, + } +} + +func resourceIBMCmOfferingCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + if _, ok := d.GetOk("offering_identifier"); ok { + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + getOfferingOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + getOfferingOptions.SetOfferingID(d.Get("offering_identifier").(string)) + + offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *offering.CatalogID, *offering.ID)) + return resourceIBMCmOfferingRead(context, d, meta) + } + + createOfferingOptions := &catalogmanagementv1.CreateOfferingOptions{} + + createOfferingOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + if _, ok := d.GetOk("url"); ok { + createOfferingOptions.SetURL(d.Get("url").(string)) + } + if _, ok := d.GetOk("crn"); ok { + createOfferingOptions.SetCRN(d.Get("crn").(string)) + } + if _, ok := d.GetOk("label"); ok { + createOfferingOptions.SetLabel(d.Get("label").(string)) + } + if _, ok := d.GetOk("label_i18n"); ok { + // TODO: Add code to handle map container: LabelI18n + } + if _, ok := d.GetOk("name"); ok { + createOfferingOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("offering_icon_url"); ok { + createOfferingOptions.SetOfferingIconURL(d.Get("offering_icon_url").(string)) + } + if _, ok := d.GetOk("offering_docs_url"); ok { + createOfferingOptions.SetOfferingDocsURL(d.Get("offering_docs_url").(string)) + } + if _, ok := d.GetOk("offering_support_url"); ok { + createOfferingOptions.SetOfferingSupportURL(d.Get("offering_support_url").(string)) + } + if _, ok := d.GetOk("tags"); ok { + createOfferingOptions.SetTags(SIToSS(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("keywords"); ok { + createOfferingOptions.SetKeywords(SIToSS(d.Get("keywords").([]interface{}))) + } + if _, ok := d.GetOk("rating"); ok { + ratingModel, err := resourceIBMCmOfferingMapToRating(d.Get("rating.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetRating(ratingModel) + } + if _, ok := d.GetOk("created"); ok { + fmtDateTimeCreated, err := core.ParseDateTime(d.Get("created").(string)) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetCreated(&fmtDateTimeCreated) + } + if _, ok := d.GetOk("updated"); ok { + fmtDateTimeUpdated, err := core.ParseDateTime(d.Get("updated").(string)) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetUpdated(&fmtDateTimeUpdated) + } + if _, ok := d.GetOk("short_description"); ok { + createOfferingOptions.SetShortDescription(d.Get("short_description").(string)) + } + if _, ok := d.GetOk("short_description_i18n"); ok { + // TODO: Add code to handle map container: ShortDescriptionI18n + } + if _, ok := d.GetOk("long_description"); ok { + createOfferingOptions.SetLongDescription(d.Get("long_description").(string)) + } + if _, ok := d.GetOk("long_description_i18n"); ok { + // TODO: Add code to handle map container: LongDescriptionI18n + } + if _, ok := d.GetOk("features"); ok { + var features []catalogmanagementv1.Feature + for _, e := range d.Get("features").([]interface{}) { + value := e.(map[string]interface{}) + featuresItem, err := resourceIBMCmOfferingMapToFeature(value) + if err != nil { + return diag.FromErr(err) + } + features = append(features, *featuresItem) + } + createOfferingOptions.SetFeatures(features) + } + if _, ok := d.GetOk("kinds"); ok { + var kinds []catalogmanagementv1.Kind + for _, e := range d.Get("kinds").([]interface{}) { + value := e.(map[string]interface{}) + kindsItem, err := resourceIBMCmOfferingMapToKind(value) + if err != nil { + return diag.FromErr(err) + } + kinds = append(kinds, *kindsItem) + } + createOfferingOptions.SetKinds(kinds) + } + if _, ok := d.GetOk("pc_managed"); ok { + createOfferingOptions.SetPcManaged(d.Get("pc_managed").(bool)) + } + if _, ok := d.GetOk("publish_approved"); ok { + createOfferingOptions.SetPublishApproved(d.Get("publish_approved").(bool)) + } + if _, ok := d.GetOk("share_with_all"); ok { + createOfferingOptions.SetShareWithAll(d.Get("share_with_all").(bool)) + } + if _, ok := d.GetOk("share_with_ibm"); ok { + createOfferingOptions.SetShareWithIBM(d.Get("share_with_ibm").(bool)) + } + if _, ok := d.GetOk("share_enabled"); ok { + createOfferingOptions.SetShareEnabled(d.Get("share_enabled").(bool)) + } + if _, ok := d.GetOk("permit_request_ibm_public_publish"); ok { + createOfferingOptions.SetPermitRequestIBMPublicPublish(d.Get("permit_request_ibm_public_publish").(bool)) + } + if _, ok := d.GetOk("ibm_publish_approved"); ok { + createOfferingOptions.SetIBMPublishApproved(d.Get("ibm_publish_approved").(bool)) + } + if _, ok := d.GetOk("public_publish_approved"); ok { + createOfferingOptions.SetPublicPublishApproved(d.Get("public_publish_approved").(bool)) + } + if _, ok := d.GetOk("public_original_crn"); ok { + createOfferingOptions.SetPublicOriginalCRN(d.Get("public_original_crn").(string)) + } + if _, ok := d.GetOk("publish_public_crn"); ok { + createOfferingOptions.SetPublishPublicCRN(d.Get("publish_public_crn").(string)) + } + if _, ok := d.GetOk("portal_approval_record"); ok { + createOfferingOptions.SetPortalApprovalRecord(d.Get("portal_approval_record").(string)) + } + if _, ok := d.GetOk("portal_ui_url"); ok { + createOfferingOptions.SetPortalUIURL(d.Get("portal_ui_url").(string)) + } + if _, ok := d.GetOk("catalog_id"); ok { + createOfferingOptions.SetCatalogID(d.Get("catalog_id").(string)) + } + if _, ok := d.GetOk("catalog_name"); ok { + createOfferingOptions.SetCatalogName(d.Get("catalog_name").(string)) + } + if _, ok := d.GetOk("metadata"); ok { + // TODO: Add code to handle map container: Metadata + } + if _, ok := d.GetOk("disclaimer"); ok { + createOfferingOptions.SetDisclaimer(d.Get("disclaimer").(string)) + } + if _, ok := d.GetOk("hidden"); ok { + createOfferingOptions.SetHidden(d.Get("hidden").(bool)) + } + // if _, ok := d.GetOk("provider"); ok { + // createOfferingOptions.SetProvider(d.Get("provider").(string)) + // } + if _, ok := d.GetOk("provider_info"); ok { + providerInfoModel, err := resourceIBMCmOfferingMapToProviderInfo(d.Get("provider_info.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetProviderInfo(providerInfoModel) + } + if _, ok := d.GetOk("repo_info"); ok { + repoInfoModel, err := resourceIBMCmOfferingMapToRepoInfo(d.Get("repo_info.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetRepoInfo(repoInfoModel) + } + if _, ok := d.GetOk("image_pull_keys"); ok { + var imagePullKeys []catalogmanagementv1.ImagePullKey + for _, e := range d.Get("image_pull_keys").([]interface{}) { + value := e.(map[string]interface{}) + imagePullKeysItem, err := resourceIBMCmOfferingMapToImagePullKey(value) + if err != nil { + return diag.FromErr(err) + } + imagePullKeys = append(imagePullKeys, *imagePullKeysItem) + } + createOfferingOptions.SetImagePullKeys(imagePullKeys) + } + if _, ok := d.GetOk("support"); ok { + supportModel, err := resourceIBMCmOfferingMapToSupport(d.Get("support.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetSupport(supportModel) + } + if _, ok := d.GetOk("media"); ok { + var media []catalogmanagementv1.MediaItem + for _, e := range d.Get("media").([]interface{}) { + value := e.(map[string]interface{}) + mediaItem, err := resourceIBMCmOfferingMapToMediaItem(value) + if err != nil { + return diag.FromErr(err) + } + media = append(media, *mediaItem) + } + createOfferingOptions.SetMedia(media) + } + if _, ok := d.GetOk("deprecate_pending"); ok { + deprecatePendingModel, err := resourceIBMCmOfferingMapToDeprecatePending(d.Get("deprecate_pending.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createOfferingOptions.SetDeprecatePending(deprecatePendingModel) + } + if _, ok := d.GetOk("product_kind"); ok { + createOfferingOptions.SetProductKind(d.Get("product_kind").(string)) + } + if _, ok := d.GetOk("badges"); ok { + var badges []catalogmanagementv1.Badge + for _, e := range d.Get("badges").([]interface{}) { + value := e.(map[string]interface{}) + badgesItem, err := resourceIBMCmOfferingMapToBadge(value) + if err != nil { + return diag.FromErr(err) + } + badges = append(badges, *badgesItem) + } + createOfferingOptions.SetBadges(badges) + } + + offering, response, err := catalogManagementClient.CreateOfferingWithContext(context, createOfferingOptions) + if err != nil { + log.Printf("[DEBUG] CreateOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateOfferingWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createOfferingOptions.CatalogIdentifier, *offering.ID)) + + shareOffering := false + shareOfferingOptions := catalogmanagementv1.ShareOfferingOptions{} + shareOfferingOptions.SetCatalogIdentifier(*offering.CatalogID) + shareOfferingOptions.SetOfferingID(*offering.ID) + shareOfferingOptions.SetEnabled(true) + + if _, ok := d.GetOk("publish_to_access_list"); ok { + addOfferingAccessListOptions := catalogmanagementv1.AddOfferingAccessListOptions{} + addOfferingAccessListOptions.SetCatalogIdentifier(*offering.CatalogID) + addOfferingAccessListOptions.SetOfferingID(*offering.ID) + addOfferingAccessListOptions.SetAccesses(SIToSS(d.Get("publish_to_access_list").([]interface{}))) + _, response, err = catalogManagementClient.AddOfferingAccessListWithContext(context, &addOfferingAccessListOptions) + if err != nil { + log.Printf("[DEBUG] AddOfferingAccessListWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddOfferingAccessListWithContext failed %s\n%s", err, response)) + } + } + + if _, ok := d.GetOk("publish_to_ibm"); ok { + shareOffering = true + shareOfferingOptions.SetIBM(d.Get("publish_to_ibm").(bool)) + } + + if _, ok := d.GetOk("publish_to_public"); ok { + shareOffering = true + shareOfferingOptions.SetPublic(d.Get("publish_to_public").(bool)) + } + + if shareOffering { + _, response, err = catalogManagementClient.ShareOfferingWithContext(context, &shareOfferingOptions) + if err != nil { + log.Printf("[DEBUG] ShareOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ShareOfferingWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCmOfferingRead(context, d, meta) +} + +func resourceIBMCmOfferingRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getOfferingOptions.SetCatalogIdentifier(parts[0]) + getOfferingOptions.SetOfferingID(parts[1]) + + offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("catalog_identifier", getOfferingOptions.CatalogIdentifier); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_identifier: %s", err)) + } + if err = d.Set("url", offering.URL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + } + if err = d.Set("crn", offering.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("label", offering.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + if offering.LabelI18n != nil { + // TODO: handle LabelI18n of type TypeMap -- not primitive type, not list + } + if err = d.Set("name", offering.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("offering_icon_url", offering.OfferingIconURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_icon_url: %s", err)) + } + if err = d.Set("offering_docs_url", offering.OfferingDocsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_docs_url: %s", err)) + } + if err = d.Set("offering_support_url", offering.OfferingSupportURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_support_url: %s", err)) + } + // if offering.Tags != nil { + // if err = d.Set("tags", offering.Tags); err != nil { + // return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + // } + // } + if offering.Keywords != nil { + if err = d.Set("keywords", offering.Keywords); err != nil { + return diag.FromErr(fmt.Errorf("Error setting keywords: %s", err)) + } + } + if offering.Rating != nil { + ratingMap, err := resourceIBMCmOfferingRatingToMap(offering.Rating) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("rating", []map[string]interface{}{ratingMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rating: %s", err)) + } + } + if err = d.Set("created", flex.DateTimeToString(offering.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + if err = d.Set("updated", flex.DateTimeToString(offering.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + if err = d.Set("short_description", offering.ShortDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting short_description: %s", err)) + } + if offering.ShortDescriptionI18n != nil { + // TODO: handle ShortDescriptionI18n of type TypeMap -- not primitive type, not list + } + if err = d.Set("long_description", offering.LongDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) + } + if offering.LongDescriptionI18n != nil { + // TODO: handle LongDescriptionI18n of type TypeMap -- not primitive type, not list + } + features := []map[string]interface{}{} + if offering.Features != nil { + for _, featuresItem := range offering.Features { + featuresItemMap, err := resourceIBMCmOfferingFeatureToMap(&featuresItem) + if err != nil { + return diag.FromErr(err) + } + features = append(features, featuresItemMap) + } + } + if err = d.Set("features", features); err != nil { + return diag.FromErr(fmt.Errorf("Error setting features: %s", err)) + } + kinds := []map[string]interface{}{} + if offering.Kinds != nil { + for _, kindsItem := range offering.Kinds { + kindsItemMap, err := resourceIBMCmOfferingKindToMap(&kindsItem) + if err != nil { + return diag.FromErr(err) + } + kinds = append(kinds, kindsItemMap) + } + } + if err = d.Set("kinds", kinds); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kinds: %s", err)) + } + if err = d.Set("pc_managed", offering.PcManaged); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pc_managed: %s", err)) + } + if err = d.Set("publish_approved", offering.PublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting publish_approved: %s", err)) + } + if err = d.Set("share_with_all", offering.ShareWithAll); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_with_all: %s", err)) + } + if err = d.Set("share_with_ibm", offering.ShareWithIBM); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_with_ibm: %s", err)) + } + if err = d.Set("share_enabled", offering.ShareEnabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting share_enabled: %s", err)) + } + if err = d.Set("permit_request_ibm_public_publish", offering.PermitRequestIBMPublicPublish); err != nil { + return diag.FromErr(fmt.Errorf("Error setting permit_request_ibm_public_publish: %s", err)) + } + if err = d.Set("ibm_publish_approved", offering.IBMPublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_publish_approved: %s", err)) + } + if err = d.Set("public_publish_approved", offering.PublicPublishApproved); err != nil { + return diag.FromErr(fmt.Errorf("Error setting public_publish_approved: %s", err)) + } + if err = d.Set("public_original_crn", offering.PublicOriginalCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting public_original_crn: %s", err)) + } + if err = d.Set("publish_public_crn", offering.PublishPublicCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting publish_public_crn: %s", err)) + } + if err = d.Set("portal_approval_record", offering.PortalApprovalRecord); err != nil { + return diag.FromErr(fmt.Errorf("Error setting portal_approval_record: %s", err)) + } + if err = d.Set("portal_ui_url", offering.PortalUIURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting portal_ui_url: %s", err)) + } + if err = d.Set("catalog_id", offering.CatalogID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) + } + if err = d.Set("catalog_name", offering.CatalogName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_name: %s", err)) + } + if offering.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- not primitive type, not list + } + if err = d.Set("disclaimer", offering.Disclaimer); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disclaimer: %s", err)) + } + if err = d.Set("hidden", offering.Hidden); err != nil { + return diag.FromErr(fmt.Errorf("Error setting hidden: %s", err)) + } + // if err = d.Set("provider", offering.Provider); err != nil { + // return diag.FromErr(fmt.Errorf("Error setting provider: %s", err)) + // } + if offering.ProviderInfo != nil { + providerInfoMap, err := resourceIBMCmOfferingProviderInfoToMap(offering.ProviderInfo) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("provider_info", []map[string]interface{}{providerInfoMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provider_info: %s", err)) + } + } + if offering.RepoInfo != nil { + repoInfoMap, err := resourceIBMCmOfferingRepoInfoToMap(offering.RepoInfo) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("repo_info", []map[string]interface{}{repoInfoMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting repo_info: %s", err)) + } + } + imagePullKeys := []map[string]interface{}{} + if offering.ImagePullKeys != nil { + for _, imagePullKeysItem := range offering.ImagePullKeys { + imagePullKeysItemMap, err := resourceIBMCmOfferingImagePullKeyToMap(&imagePullKeysItem) + if err != nil { + return diag.FromErr(err) + } + imagePullKeys = append(imagePullKeys, imagePullKeysItemMap) + } + } + if err = d.Set("image_pull_keys", imagePullKeys); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_pull_keys: %s", err)) + } + if offering.Support != nil { + supportMap, err := resourceIBMCmOfferingSupportToMap(offering.Support) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("support", []map[string]interface{}{supportMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting support: %s", err)) + } + } + media := []map[string]interface{}{} + if offering.Media != nil { + for _, mediaItem := range offering.Media { + mediaItemMap, err := resourceIBMCmOfferingMediaItemToMap(&mediaItem) + if err != nil { + return diag.FromErr(err) + } + media = append(media, mediaItemMap) + } + } + if err = d.Set("media", media); err != nil { + return diag.FromErr(fmt.Errorf("Error setting media: %s", err)) + } + if offering.DeprecatePending != nil { + deprecatePendingMap, err := resourceIBMCmOfferingDeprecatePendingToMap(offering.DeprecatePending) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("deprecate_pending", []map[string]interface{}{deprecatePendingMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deprecate_pending: %s", err)) + } + } + if err = d.Set("product_kind", offering.ProductKind); err != nil { + return diag.FromErr(fmt.Errorf("Error setting product_kind: %s", err)) + } + badges := []map[string]interface{}{} + if offering.Badges != nil { + for _, badgesItem := range offering.Badges { + badgesItemMap, err := resourceIBMCmOfferingBadgeToMap(&badgesItem) + if err != nil { + return diag.FromErr(err) + } + badges = append(badges, badgesItemMap) + } + } + if err = d.Set("badges", badges); err != nil { + return diag.FromErr(fmt.Errorf("Error setting badges: %s", err)) + } + if err = d.Set("rev", offering.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + if err = d.Set("offering_id", offering.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_id: %s", err)) + } + + return nil +} + +func resourceIBMCmOfferingUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + updateOfferingOptions := &catalogmanagementv1.UpdateOfferingOptions{} + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getOfferingOptions.SetCatalogIdentifier(parts[0]) + getOfferingOptions.SetOfferingID(parts[1]) + offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + updateOfferingOptions.SetCatalogIdentifier(*offering.CatalogID) + updateOfferingOptions.SetOfferingID(*offering.ID) + ifMatch := fmt.Sprintf("\"%s\"", *offering.Rev) + updateOfferingOptions.IfMatch = &ifMatch + + hasChange := false + + if d.HasChange("label") { + var method string + if offering.Label == nil { + method = "add" + } else { + method = "replace" + } + path := "/label" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("label"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("label_i18n") { + var method string + if offering.LabelI18n == nil { + method = "add" + } else { + method = "replace" + } + path := "/label_i18n" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("label_i18n"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("name") { + var method string + if offering.Name == nil { + method = "add" + } else { + method = "replace" + } + path := "/name" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("name"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("offering_icon_url") { + var method string + if offering.OfferingIconURL == nil { + method = "add" + } else { + method = "replace" + } + path := "/offering_icon_url" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("offering_icon_url"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("offering_docs_url") { + var method string + if offering.OfferingDocsURL == nil { + method = "add" + } else { + method = "replace" + } + path := "/offering_docs_url" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("offering_docs_url"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("offering_support_url") { + var method string + if offering.OfferingSupportURL == nil { + method = "add" + } else { + method = "replace" + } + path := "/offering_support_url" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("offering_support_url"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("tags") { + var method string + if offering.Tags == nil { + method = "add" + } else { + method = "replace" + } + path := "/tags" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("tags"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("keywords") { + var method string + if offering.Keywords == nil { + method = "add" + } else { + method = "replace" + } + path := "/keywords" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("keywords"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("short_description") { + var method string + if offering.ShortDescription == nil { + method = "add" + } else { + method = "replace" + } + path := "/short_description" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("short_description"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("short_description_i18n") { + var method string + if offering.ShortDescriptionI18n == nil { + method = "add" + } else { + method = "replace" + } + path := "/short_description_i18n" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("short_description_i18n"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("long_description") { + var method string + if offering.LongDescription == nil { + method = "add" + } else { + method = "replace" + } + path := "/long_description" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("long_description"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("long_description_i18n") { + var method string + if offering.LongDescriptionI18n == nil { + method = "add" + } else { + method = "replace" + } + path := "/long_description_i18n" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("long_description_i18n"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("features") { + var method string + if offering.Features == nil { + method = "add" + } else { + method = "replace" + } + path := "/features" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("features"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("kinds") { + var method string + if offering.Kinds == nil { + method = "add" + } else { + method = "replace" + } + path := "/kinds" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("kinds"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("share_with_all") { + var method string + if offering.ShareWithAll == nil { + method = "add" + } else { + method = "replace" + } + path := "/share_with_all" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("share_with_all"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("share_with_ibm") { + var method string + if offering.ShareWithIBM == nil { + method = "add" + } else { + method = "replace" + } + path := "/share_with_ibm" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("share_with_ibm"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("share_enabled") { + var method string + if offering.ShareEnabled == nil { + method = "add" + } else { + method = "replace" + } + path := "/share_enabled" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("share_enabled"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("public_original_crn") { + var method string + if offering.PublicOriginalCRN == nil { + method = "add" + } else { + method = "replace" + } + path := "/public_original_crn" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("public_original_crn"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("publish_public_crn") { + var method string + if offering.PublishPublicCRN == nil { + method = "add" + } else { + method = "replace" + } + path := "/publish_public_crn" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("publish_public_crn"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("portal_approval_record") { + var method string + if offering.PortalApprovalRecord == nil { + method = "add" + } else { + method = "replace" + } + path := "/portal_approval_record" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("portal_approval_record"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("portal_ui_url") { + var method string + if offering.PortalUIURL == nil { + method = "add" + } else { + method = "replace" + } + path := "/portal_ui_url" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("portal_ui_url"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("metadata") { + var method string + if offering.Metadata == nil { + method = "add" + } else { + method = "replace" + } + path := "/metadata" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("metadata"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("disclaimer") { + var method string + if offering.Disclaimer == nil { + method = "add" + } else { + method = "replace" + } + path := "/disclaimer" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("disclaimer"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("hidden") { + var method string + if offering.Hidden == nil { + method = "add" + } else { + method = "replace" + } + path := "/hidden" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("hidden"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("provider") { + var method string + if offering.Provider == nil { + method = "add" + } else { + method = "replace" + } + path := "/provider" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("provider"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("provider_info") { + var method string + if offering.ProviderInfo == nil { + method = "add" + } else { + method = "replace" + } + path := "/provider_info" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("provider_info.0"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("image_pull_keys") { + var method string + if offering.ImagePullKeys == nil { + method = "add" + } else { + method = "replace" + } + path := "/image_pull_keys" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("image_pull_keys"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("support") { + var method string + if offering.Support == nil { + method = "add" + } else { + method = "replace" + } + path := "/support" + supportModel, err := resourceIBMCmOfferingMapToSupport(d.Get("support.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: supportModel, + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("media") { + var method string + if offering.Media == nil { + method = "add" + } else { + method = "replace" + } + path := "/media" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("media"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("product_kind") { + var method string + if offering.ProductKind == nil { + method = "add" + } else { + method = "replace" + } + path := "/product_kind" + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("product_kind"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + + publishStatusChanged := false + shareOfferingOptions := catalogmanagementv1.ShareOfferingOptions{} + shareOfferingOptions.SetCatalogIdentifier(*offering.CatalogID) + shareOfferingOptions.SetOfferingID(*offering.ID) + shareOfferingOptions.SetEnabled(true) + + if d.HasChange("publish_to_access_list") { + publishStatusChanged = true + addOfferingAccessListOptions := catalogmanagementv1.AddOfferingAccessListOptions{} + addOfferingAccessListOptions.SetCatalogIdentifier(*offering.CatalogID) + addOfferingAccessListOptions.SetOfferingID(*offering.ID) + addOfferingAccessListOptions.SetAccesses(SIToSS(d.Get("publish_to_access_list").([]interface{}))) + _, response, err = catalogManagementClient.AddOfferingAccessListWithContext(context, &addOfferingAccessListOptions) + if err != nil { + log.Printf("[DEBUG] AddOfferingAccessListWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddOfferingAccessListWithContext failed %s\n%s", err, response)) + } + } + + if d.HasChange("publish_to_ibm") { + publishStatusChanged = true + shareOfferingOptions.SetIBM(d.Get("publish_to_ibm").(bool)) + } + + if d.HasChange("publish_to_public") { + publishStatusChanged = true + shareOfferingOptions.SetPublic(d.Get("publish_to_public").(bool)) + } + + if publishStatusChanged { + _, response, err = catalogManagementClient.ShareOfferingWithContext(context, &shareOfferingOptions) + if err != nil { + log.Printf("[DEBUG] ShareOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ShareOfferingWithContext failed %s\n%s", err, response)) + } + } + + if hasChange { + _, response, err := catalogManagementClient.UpdateOfferingWithContext(context, updateOfferingOptions) + if err != nil { + log.Printf("[DEBUG] UpdateOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateOfferingWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCmOfferingRead(context, d, meta) +} + +func resourceIBMCmOfferingDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + deleteOfferingOptions := &catalogmanagementv1.DeleteOfferingOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteOfferingOptions.SetCatalogIdentifier(parts[0]) + deleteOfferingOptions.SetOfferingID(parts[1]) + + response, err := catalogManagementClient.DeleteOfferingWithContext(context, deleteOfferingOptions) + if err != nil { + log.Printf("[DEBUG] DeleteOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteOfferingWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCmOfferingMapToRating(modelMap map[string]interface{}) (*catalogmanagementv1.Rating, error) { + model := &catalogmanagementv1.Rating{} + if modelMap["one_star_count"] != nil { + model.OneStarCount = core.Int64Ptr(int64(modelMap["one_star_count"].(int))) + } + if modelMap["two_star_count"] != nil { + model.TwoStarCount = core.Int64Ptr(int64(modelMap["two_star_count"].(int))) + } + if modelMap["three_star_count"] != nil { + model.ThreeStarCount = core.Int64Ptr(int64(modelMap["three_star_count"].(int))) + } + if modelMap["four_star_count"] != nil { + model.FourStarCount = core.Int64Ptr(int64(modelMap["four_star_count"].(int))) + } + return model, nil +} + +func resourceIBMCmOfferingMapToFeature(modelMap map[string]interface{}) (*catalogmanagementv1.Feature, error) { + model := &catalogmanagementv1.Feature{} + if modelMap["title"] != nil && modelMap["title"].(string) != "" { + model.Title = core.StringPtr(modelMap["title"].(string)) + } + if modelMap["title_i18n"] != nil { + // TODO: handle TitleI18n, map with entry type '' + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["description_i18n"] != nil { + // TODO: handle DescriptionI18n, map with entry type '' + } + return model, nil +} + +func resourceIBMCmOfferingMapToKind(modelMap map[string]interface{}) (*catalogmanagementv1.Kind, error) { + model := &catalogmanagementv1.Kind{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["format_kind"] != nil && modelMap["format_kind"].(string) != "" { + model.FormatKind = core.StringPtr(modelMap["format_kind"].(string)) + } + if modelMap["install_kind"] != nil && modelMap["install_kind"].(string) != "" { + model.InstallKind = core.StringPtr(modelMap["install_kind"].(string)) + } + if modelMap["target_kind"] != nil && modelMap["target_kind"].(string) != "" { + model.TargetKind = core.StringPtr(modelMap["target_kind"].(string)) + } + if modelMap["metadata"] != nil { + // TODO: handle Metadata, map with entry type '' + } + if modelMap["tags"] != nil { + tags := []string{} + for _, tagsItem := range modelMap["tags"].([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + model.Tags = tags + } + if modelMap["additional_features"] != nil { + additionalFeatures := []catalogmanagementv1.Feature{} + for _, additionalFeaturesItem := range modelMap["additional_features"].([]interface{}) { + additionalFeaturesItemModel, err := resourceIBMCmOfferingMapToFeature(additionalFeaturesItem.(map[string]interface{})) + if err != nil { + return model, err + } + additionalFeatures = append(additionalFeatures, *additionalFeaturesItemModel) + } + model.AdditionalFeatures = additionalFeatures + } + if modelMap["created"] != nil { + + } + if modelMap["updated"] != nil { + + } + if modelMap["versions"] != nil { + versions := []catalogmanagementv1.Version{} + for _, versionsItem := range modelMap["versions"].([]interface{}) { + versionsItemModel, err := resourceIBMCmOfferingMapToVersion(versionsItem.(map[string]interface{})) + if err != nil { + return model, err + } + versions = append(versions, *versionsItemModel) + } + model.Versions = versions + } + if modelMap["plans"] != nil { + plans := []catalogmanagementv1.Plan{} + for _, plansItem := range modelMap["plans"].([]interface{}) { + plansItemModel, err := resourceIBMCmOfferingMapToPlan(plansItem.(map[string]interface{})) + if err != nil { + return model, err + } + plans = append(plans, *plansItemModel) + } + model.Plans = plans + } + return model, nil +} + +func resourceIBMCmOfferingMapToVersion(modelMap map[string]interface{}) (*catalogmanagementv1.Version, error) { + model := &catalogmanagementv1.Version{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["rev"] != nil && modelMap["rev"].(string) != "" { + model.Rev = core.StringPtr(modelMap["rev"].(string)) + } + if modelMap["crn"] != nil && modelMap["crn"].(string) != "" { + model.CRN = core.StringPtr(modelMap["crn"].(string)) + } + if modelMap["version"] != nil && modelMap["version"].(string) != "" { + model.Version = core.StringPtr(modelMap["version"].(string)) + } + if modelMap["flavor"] != nil && len(modelMap["flavor"].([]interface{})) > 0 { + FlavorModel, err := resourceIBMCmOfferingMapToFlavor(modelMap["flavor"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Flavor = FlavorModel + } + if modelMap["sha"] != nil && modelMap["sha"].(string) != "" { + model.Sha = core.StringPtr(modelMap["sha"].(string)) + } + if modelMap["created"] != nil { + + } + if modelMap["updated"] != nil { + + } + if modelMap["offering_id"] != nil && modelMap["offering_id"].(string) != "" { + model.OfferingID = core.StringPtr(modelMap["offering_id"].(string)) + } + if modelMap["catalog_id"] != nil && modelMap["catalog_id"].(string) != "" { + model.CatalogID = core.StringPtr(modelMap["catalog_id"].(string)) + } + if modelMap["kind_id"] != nil && modelMap["kind_id"].(string) != "" { + model.KindID = core.StringPtr(modelMap["kind_id"].(string)) + } + if modelMap["tags"] != nil { + tags := []string{} + for _, tagsItem := range modelMap["tags"].([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + model.Tags = tags + } + if modelMap["repo_url"] != nil && modelMap["repo_url"].(string) != "" { + model.RepoURL = core.StringPtr(modelMap["repo_url"].(string)) + } + if modelMap["source_url"] != nil && modelMap["source_url"].(string) != "" { + model.SourceURL = core.StringPtr(modelMap["source_url"].(string)) + } + if modelMap["tgz_url"] != nil && modelMap["tgz_url"].(string) != "" { + model.TgzURL = core.StringPtr(modelMap["tgz_url"].(string)) + } + if modelMap["configuration"] != nil { + configuration := []catalogmanagementv1.Configuration{} + for _, configurationItem := range modelMap["configuration"].([]interface{}) { + configurationItemModel, err := resourceIBMCmOfferingMapToConfiguration(configurationItem.(map[string]interface{})) + if err != nil { + return model, err + } + configuration = append(configuration, *configurationItemModel) + } + model.Configuration = configuration + } + if modelMap["outputs"] != nil { + outputs := []catalogmanagementv1.Output{} + for _, outputsItem := range modelMap["outputs"].([]interface{}) { + outputsItemModel, err := resourceIBMCmOfferingMapToOutput(outputsItem.(map[string]interface{})) + if err != nil { + return model, err + } + outputs = append(outputs, *outputsItemModel) + } + model.Outputs = outputs + } + if modelMap["iam_permissions"] != nil { + iamPermissions := []catalogmanagementv1.IamPermission{} + for _, iamPermissionsItem := range modelMap["iam_permissions"].([]interface{}) { + iamPermissionsItemModel, err := resourceIBMCmOfferingMapToIamPermission(iamPermissionsItem.(map[string]interface{})) + if err != nil { + return model, err + } + iamPermissions = append(iamPermissions, *iamPermissionsItemModel) + } + model.IamPermissions = iamPermissions + } + if modelMap["metadata"] != nil { + metadataModel := modelMap["metadata"].([]interface{})[0].(map[string]interface{}) + model.Metadata = metadataModel + // FlavorModel, err := resourceIBMCmOfferingMapToFlavor(modelMap["flavor"].([]interface{})[0].(map[string]interface{})) + // if err != nil { + // return model, err + // } + // model.Flavor = FlavorModel + } + if modelMap["validation"] != nil && len(modelMap["validation"].([]interface{})) > 0 { + ValidationModel, err := resourceIBMCmOfferingMapToValidation(modelMap["validation"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Validation = ValidationModel + } + if modelMap["required_resources"] != nil { + requiredResources := []catalogmanagementv1.Resource{} + for _, requiredResourcesItem := range modelMap["required_resources"].([]interface{}) { + requiredResourcesItemModel, err := resourceIBMCmOfferingMapToResource(requiredResourcesItem.(map[string]interface{})) + if err != nil { + return model, err + } + requiredResources = append(requiredResources, *requiredResourcesItemModel) + } + model.RequiredResources = requiredResources + } + if modelMap["single_instance"] != nil { + model.SingleInstance = core.BoolPtr(modelMap["single_instance"].(bool)) + } + if modelMap["install"] != nil && len(modelMap["install"].([]interface{})) > 0 { + InstallModel, err := resourceIBMCmOfferingMapToScript(modelMap["install"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Install = InstallModel + } + if modelMap["pre_install"] != nil { + preInstall := []catalogmanagementv1.Script{} + for _, preInstallItem := range modelMap["pre_install"].([]interface{}) { + preInstallItemModel, err := resourceIBMCmOfferingMapToScript(preInstallItem.(map[string]interface{})) + if err != nil { + return model, err + } + preInstall = append(preInstall, *preInstallItemModel) + } + model.PreInstall = preInstall + } + if modelMap["entitlement"] != nil && len(modelMap["entitlement"].([]interface{})) > 0 { + EntitlementModel, err := resourceIBMCmOfferingMapToVersionEntitlement(modelMap["entitlement"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Entitlement = EntitlementModel + } + if modelMap["licenses"] != nil { + licenses := []catalogmanagementv1.License{} + for _, licensesItem := range modelMap["licenses"].([]interface{}) { + licensesItemModel, err := resourceIBMCmOfferingMapToLicense(licensesItem.(map[string]interface{})) + if err != nil { + return model, err + } + licenses = append(licenses, *licensesItemModel) + } + model.Licenses = licenses + } + if modelMap["image_manifest_url"] != nil && modelMap["image_manifest_url"].(string) != "" { + model.ImageManifestURL = core.StringPtr(modelMap["image_manifest_url"].(string)) + } + if modelMap["deprecated"] != nil { + model.Deprecated = core.BoolPtr(modelMap["deprecated"].(bool)) + } + if modelMap["package_version"] != nil && modelMap["package_version"].(string) != "" { + model.PackageVersion = core.StringPtr(modelMap["package_version"].(string)) + } + if modelMap["state"] != nil && len(modelMap["state"].([]interface{})) > 0 { + StateModel, err := resourceIBMCmOfferingMapToState(modelMap["state"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.State = StateModel + } + if modelMap["version_locator"] != nil && modelMap["version_locator"].(string) != "" { + model.VersionLocator = core.StringPtr(modelMap["version_locator"].(string)) + } + if modelMap["long_description"] != nil && modelMap["long_description"].(string) != "" { + model.LongDescription = core.StringPtr(modelMap["long_description"].(string)) + } + if modelMap["long_description_i18n"] != nil { + // TODO: handle LongDescriptionI18n, map with entry type '' + } + if modelMap["whitelisted_accounts"] != nil { + whitelistedAccounts := []string{} + for _, whitelistedAccountsItem := range modelMap["whitelisted_accounts"].([]interface{}) { + whitelistedAccounts = append(whitelistedAccounts, whitelistedAccountsItem.(string)) + } + model.WhitelistedAccounts = whitelistedAccounts + } + if modelMap["image_pull_key_name"] != nil && modelMap["image_pull_key_name"].(string) != "" { + model.ImagePullKeyName = core.StringPtr(modelMap["image_pull_key_name"].(string)) + } + if modelMap["deprecate_pending"] != nil && len(modelMap["deprecate_pending"].([]interface{})) > 0 { + DeprecatePendingModel, err := resourceIBMCmOfferingMapToDeprecatePending(modelMap["deprecate_pending"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.DeprecatePending = DeprecatePendingModel + } + if modelMap["solution_info"] != nil && len(modelMap["solution_info"].([]interface{})) > 0 { + SolutionInfoModel, err := resourceIBMCmOfferingMapToSolutionInfo(modelMap["solution_info"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.SolutionInfo = SolutionInfoModel + } + if modelMap["is_consumable"] != nil { + model.IsConsumable = core.BoolPtr(modelMap["is_consumable"].(bool)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToFlavor(modelMap map[string]interface{}) (*catalogmanagementv1.Flavor, error) { + model := &catalogmanagementv1.Flavor{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["label"] != nil && modelMap["label"].(string) != "" { + model.Label = core.StringPtr(modelMap["label"].(string)) + } + if modelMap["label_i18n"] != nil { + // TODO: handle LabelI18n, map with entry type '' + } + if modelMap["index"] != nil { + model.Index = core.Int64Ptr(int64(modelMap["index"].(int))) + } + return model, nil +} + +func resourceIBMCmOfferingMapToConfiguration(modelMap map[string]interface{}) (*catalogmanagementv1.Configuration, error) { + model := &catalogmanagementv1.Configuration{} + if modelMap["key"] != nil && modelMap["key"].(string) != "" { + model.Key = core.StringPtr(modelMap["key"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["default_value"] != nil { + + } + if modelMap["display_name"] != nil && modelMap["display_name"].(string) != "" { + model.DisplayName = core.StringPtr(modelMap["display_name"].(string)) + } + if modelMap["value_constraint"] != nil && modelMap["value_constraint"].(string) != "" { + model.ValueConstraint = core.StringPtr(modelMap["value_constraint"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["required"] != nil { + model.Required = core.BoolPtr(modelMap["required"].(bool)) + } + // TODO: TypeMap undefined + // if modelMap["options"] != nil { + // options := []TypeMap{} + // for _, optionsItem := range modelMap["options"].([]interface{}) { + // options = append(options, optionsItem.(TypeMap)) + // } + // model.Options = options + // } + if modelMap["hidden"] != nil { + model.Hidden = core.BoolPtr(modelMap["hidden"].(bool)) + } + if modelMap["custom_config"] != nil && len(modelMap["custom_config"].([]interface{})) > 0 { + CustomConfigModel, err := resourceIBMCmOfferingMapToRenderType(modelMap["custom_config"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.CustomConfig = CustomConfigModel + } + if modelMap["type_metadata"] != nil && modelMap["type_metadata"].(string) != "" { + model.TypeMetadata = core.StringPtr(modelMap["type_metadata"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToRenderType(modelMap map[string]interface{}) (*catalogmanagementv1.RenderType, error) { + model := &catalogmanagementv1.RenderType{} + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["grouping"] != nil && modelMap["grouping"].(string) != "" { + model.Grouping = core.StringPtr(modelMap["grouping"].(string)) + } + if modelMap["original_grouping"] != nil && modelMap["original_grouping"].(string) != "" { + model.OriginalGrouping = core.StringPtr(modelMap["original_grouping"].(string)) + } + if modelMap["grouping_index"] != nil { + model.GroupingIndex = core.Int64Ptr(int64(modelMap["grouping_index"].(int))) + } + if modelMap["config_constraints"] != nil { + // TODO: handle ConfigConstraints, map with entry type '' + } + if modelMap["associations"] != nil && len(modelMap["associations"].([]interface{})) > 0 { + AssociationsModel, err := resourceIBMCmOfferingMapToRenderTypeAssociations(modelMap["associations"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Associations = AssociationsModel + } + return model, nil +} + +func resourceIBMCmOfferingMapToRenderTypeAssociations(modelMap map[string]interface{}) (*catalogmanagementv1.RenderTypeAssociations, error) { + model := &catalogmanagementv1.RenderTypeAssociations{} + if modelMap["parameters"] != nil { + parameters := []catalogmanagementv1.RenderTypeAssociationsParametersItem{} + for _, parametersItem := range modelMap["parameters"].([]interface{}) { + parametersItemModel, err := resourceIBMCmOfferingMapToRenderTypeAssociationsParametersItem(parametersItem.(map[string]interface{})) + if err != nil { + return model, err + } + parameters = append(parameters, *parametersItemModel) + } + model.Parameters = parameters + } + return model, nil +} + +func resourceIBMCmOfferingMapToRenderTypeAssociationsParametersItem(modelMap map[string]interface{}) (*catalogmanagementv1.RenderTypeAssociationsParametersItem, error) { + model := &catalogmanagementv1.RenderTypeAssociationsParametersItem{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["options_refresh"] != nil { + model.OptionsRefresh = core.BoolPtr(modelMap["options_refresh"].(bool)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToOutput(modelMap map[string]interface{}) (*catalogmanagementv1.Output, error) { + model := &catalogmanagementv1.Output{} + if modelMap["key"] != nil && modelMap["key"].(string) != "" { + model.Key = core.StringPtr(modelMap["key"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToIamPermission(modelMap map[string]interface{}) (*catalogmanagementv1.IamPermission, error) { + model := &catalogmanagementv1.IamPermission{} + if modelMap["service_name"] != nil && modelMap["service_name"].(string) != "" { + model.ServiceName = core.StringPtr(modelMap["service_name"].(string)) + } + if modelMap["role_crns"] != nil { + roleCrns := []string{} + for _, roleCrnsItem := range modelMap["role_crns"].([]interface{}) { + roleCrns = append(roleCrns, roleCrnsItem.(string)) + } + model.RoleCrns = roleCrns + } + if modelMap["resources"] != nil { + resources := []catalogmanagementv1.IamResource{} + for _, resourcesItem := range modelMap["resources"].([]interface{}) { + resourcesItemModel, err := resourceIBMCmOfferingMapToIamResource(resourcesItem.(map[string]interface{})) + if err != nil { + return model, err + } + resources = append(resources, *resourcesItemModel) + } + model.Resources = resources + } + return model, nil +} + +func resourceIBMCmOfferingMapToIamResource(modelMap map[string]interface{}) (*catalogmanagementv1.IamResource, error) { + model := &catalogmanagementv1.IamResource{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["role_crns"] != nil { + roleCrns := []string{} + for _, roleCrnsItem := range modelMap["role_crns"].([]interface{}) { + roleCrns = append(roleCrns, roleCrnsItem.(string)) + } + model.RoleCrns = roleCrns + } + return model, nil +} + +func resourceIBMCmOfferingMapToValidation(modelMap map[string]interface{}) (*catalogmanagementv1.Validation, error) { + model := &catalogmanagementv1.Validation{} + if modelMap["validated"] != nil { + + } + if modelMap["requested"] != nil { + + } + if modelMap["state"] != nil && modelMap["state"].(string) != "" { + model.State = core.StringPtr(modelMap["state"].(string)) + } + if modelMap["last_operation"] != nil && modelMap["last_operation"].(string) != "" { + model.LastOperation = core.StringPtr(modelMap["last_operation"].(string)) + } + if modelMap["target"] != nil { + // TODO: handle Target, map with entry type '' + } + if modelMap["message"] != nil && modelMap["message"].(string) != "" { + model.Message = core.StringPtr(modelMap["message"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToResource(modelMap map[string]interface{}) (*catalogmanagementv1.Resource, error) { + model := &catalogmanagementv1.Resource{} + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["value"] != nil { + + } + return model, nil +} + +func resourceIBMCmOfferingMapToScript(modelMap map[string]interface{}) (*catalogmanagementv1.Script, error) { + model := &catalogmanagementv1.Script{} + if modelMap["instructions"] != nil && modelMap["instructions"].(string) != "" { + model.Instructions = core.StringPtr(modelMap["instructions"].(string)) + } + if modelMap["instructions_i18n"] != nil { + // TODO: handle InstructionsI18n, map with entry type '' + } + if modelMap["script"] != nil && modelMap["script"].(string) != "" { + model.Script = core.StringPtr(modelMap["script"].(string)) + } + if modelMap["script_permission"] != nil && modelMap["script_permission"].(string) != "" { + model.ScriptPermission = core.StringPtr(modelMap["script_permission"].(string)) + } + if modelMap["delete_script"] != nil && modelMap["delete_script"].(string) != "" { + model.DeleteScript = core.StringPtr(modelMap["delete_script"].(string)) + } + if modelMap["scope"] != nil && modelMap["scope"].(string) != "" { + model.Scope = core.StringPtr(modelMap["scope"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToVersionEntitlement(modelMap map[string]interface{}) (*catalogmanagementv1.VersionEntitlement, error) { + model := &catalogmanagementv1.VersionEntitlement{} + if modelMap["provider_name"] != nil && modelMap["provider_name"].(string) != "" { + model.ProviderName = core.StringPtr(modelMap["provider_name"].(string)) + } + if modelMap["provider_id"] != nil && modelMap["provider_id"].(string) != "" { + model.ProviderID = core.StringPtr(modelMap["provider_id"].(string)) + } + if modelMap["product_id"] != nil && modelMap["product_id"].(string) != "" { + model.ProductID = core.StringPtr(modelMap["product_id"].(string)) + } + if modelMap["part_numbers"] != nil { + partNumbers := []string{} + for _, partNumbersItem := range modelMap["part_numbers"].([]interface{}) { + partNumbers = append(partNumbers, partNumbersItem.(string)) + } + model.PartNumbers = partNumbers + } + if modelMap["image_repo_name"] != nil && modelMap["image_repo_name"].(string) != "" { + model.ImageRepoName = core.StringPtr(modelMap["image_repo_name"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToLicense(modelMap map[string]interface{}) (*catalogmanagementv1.License, error) { + model := &catalogmanagementv1.License{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToState(modelMap map[string]interface{}) (*catalogmanagementv1.State, error) { + model := &catalogmanagementv1.State{} + if modelMap["current"] != nil && modelMap["current"].(string) != "" { + model.Current = core.StringPtr(modelMap["current"].(string)) + } + if modelMap["current_entered"] != nil { + + } + if modelMap["pending"] != nil && modelMap["pending"].(string) != "" { + model.Pending = core.StringPtr(modelMap["pending"].(string)) + } + if modelMap["pending_requested"] != nil { + + } + if modelMap["previous"] != nil && modelMap["previous"].(string) != "" { + model.Previous = core.StringPtr(modelMap["previous"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToDeprecatePending(modelMap map[string]interface{}) (*catalogmanagementv1.DeprecatePending, error) { + model := &catalogmanagementv1.DeprecatePending{} + if modelMap["deprecate_date"] != nil { + + } + if modelMap["deprecate_state"] != nil && modelMap["deprecate_state"].(string) != "" { + model.DeprecateState = core.StringPtr(modelMap["deprecate_state"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSolutionInfo(modelMap map[string]interface{}) (*catalogmanagementv1.SolutionInfo, error) { + model := &catalogmanagementv1.SolutionInfo{} + if modelMap["architecture_diagrams"] != nil { + architectureDiagrams := []catalogmanagementv1.ArchitectureDiagram{} + for _, architectureDiagramsItem := range modelMap["architecture_diagrams"].([]interface{}) { + architectureDiagramsItemModel, err := resourceIBMCmOfferingMapToArchitectureDiagram(architectureDiagramsItem.(map[string]interface{})) + if err != nil { + return model, err + } + architectureDiagrams = append(architectureDiagrams, *architectureDiagramsItemModel) + } + model.ArchitectureDiagrams = architectureDiagrams + } + if modelMap["features"] != nil { + features := []catalogmanagementv1.Feature{} + for _, featuresItem := range modelMap["features"].([]interface{}) { + featuresItemModel, err := resourceIBMCmOfferingMapToFeature(featuresItem.(map[string]interface{})) + if err != nil { + return model, err + } + features = append(features, *featuresItemModel) + } + model.Features = features + } + if modelMap["cost_estimate"] != nil && len(modelMap["cost_estimate"].([]interface{})) > 0 { + CostEstimateModel, err := resourceIBMCmOfferingMapToCostEstimate(modelMap["cost_estimate"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.CostEstimate = CostEstimateModel + } + if modelMap["dependencies"] != nil { + dependencies := []catalogmanagementv1.Dependency{} + for _, dependenciesItem := range modelMap["dependencies"].([]interface{}) { + dependenciesItemModel, err := resourceIBMCmOfferingMapToDependency(dependenciesItem.(map[string]interface{})) + if err != nil { + return model, err + } + dependencies = append(dependencies, *dependenciesItemModel) + } + model.Dependencies = dependencies + } + return model, nil +} + +func resourceIBMCmOfferingMapToArchitectureDiagram(modelMap map[string]interface{}) (*catalogmanagementv1.ArchitectureDiagram, error) { + model := &catalogmanagementv1.ArchitectureDiagram{} + if modelMap["diagram"] != nil && len(modelMap["diagram"].([]interface{})) > 0 { + DiagramModel, err := resourceIBMCmOfferingMapToMediaItem(modelMap["diagram"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Diagram = DiagramModel + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["description_i18n"] != nil { + // TODO: handle DescriptionI18n, map with entry type '' + } + return model, nil +} + +func resourceIBMCmOfferingMapToMediaItem(modelMap map[string]interface{}) (*catalogmanagementv1.MediaItem, error) { + model := &catalogmanagementv1.MediaItem{} + if modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if modelMap["api_url"] != nil && modelMap["api_url"].(string) != "" { + model.APIURL = core.StringPtr(modelMap["api_url"].(string)) + } + if modelMap["url_proxy"] != nil && len(modelMap["url_proxy"].([]interface{})) > 0 { + URLProxyModel, err := resourceIBMCmOfferingMapToURLProxy(modelMap["url_proxy"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.URLProxy = URLProxyModel + } + if modelMap["caption"] != nil && modelMap["caption"].(string) != "" { + model.Caption = core.StringPtr(modelMap["caption"].(string)) + } + if modelMap["caption_i18n"] != nil { + // TODO: handle CaptionI18n, map with entry type '' + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["thumbnail_url"] != nil && modelMap["thumbnail_url"].(string) != "" { + model.ThumbnailURL = core.StringPtr(modelMap["thumbnail_url"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToURLProxy(modelMap map[string]interface{}) (*catalogmanagementv1.URLProxy, error) { + model := &catalogmanagementv1.URLProxy{} + if modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if modelMap["sha"] != nil && modelMap["sha"].(string) != "" { + model.Sha = core.StringPtr(modelMap["sha"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToCostEstimate(modelMap map[string]interface{}) (*catalogmanagementv1.CostEstimate, error) { + model := &catalogmanagementv1.CostEstimate{} + if modelMap["version"] != nil && modelMap["version"].(string) != "" { + model.Version = core.StringPtr(modelMap["version"].(string)) + } + if modelMap["currency"] != nil && modelMap["currency"].(string) != "" { + model.Currency = core.StringPtr(modelMap["currency"].(string)) + } + if modelMap["projects"] != nil { + projects := []catalogmanagementv1.Project{} + for _, projectsItem := range modelMap["projects"].([]interface{}) { + projectsItemModel, err := resourceIBMCmOfferingMapToProject(projectsItem.(map[string]interface{})) + if err != nil { + return model, err + } + projects = append(projects, *projectsItemModel) + } + model.Projects = projects + } + if modelMap["summary"] != nil && len(modelMap["summary"].([]interface{})) > 0 { + SummaryModel, err := resourceIBMCmOfferingMapToCostSummary(modelMap["summary"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Summary = SummaryModel + } + if modelMap["total_hourly_cost"] != nil && modelMap["total_hourly_cost"].(string) != "" { + model.TotalHourlyCost = core.StringPtr(modelMap["total_hourly_cost"].(string)) + } + if modelMap["total_monthly_cost"] != nil && modelMap["total_monthly_cost"].(string) != "" { + model.TotalMonthlyCost = core.StringPtr(modelMap["total_monthly_cost"].(string)) + } + if modelMap["past_total_hourly_cost"] != nil && modelMap["past_total_hourly_cost"].(string) != "" { + model.PastTotalHourlyCost = core.StringPtr(modelMap["past_total_hourly_cost"].(string)) + } + if modelMap["past_total_monthly_cost"] != nil && modelMap["past_total_monthly_cost"].(string) != "" { + model.PastTotalMonthlyCost = core.StringPtr(modelMap["past_total_monthly_cost"].(string)) + } + if modelMap["diff_total_hourly_cost"] != nil && modelMap["diff_total_hourly_cost"].(string) != "" { + model.DiffTotalHourlyCost = core.StringPtr(modelMap["diff_total_hourly_cost"].(string)) + } + if modelMap["diff_total_monthly_cost"] != nil && modelMap["diff_total_monthly_cost"].(string) != "" { + model.DiffTotalMonthlyCost = core.StringPtr(modelMap["diff_total_monthly_cost"].(string)) + } + if modelMap["time_generated"] != nil { + + } + return model, nil +} + +func resourceIBMCmOfferingMapToProject(modelMap map[string]interface{}) (*catalogmanagementv1.Project, error) { + model := &catalogmanagementv1.Project{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["metadata"] != nil { + // TODO: handle Metadata, map with entry type '' + } + if modelMap["past_breakdown"] != nil && len(modelMap["past_breakdown"].([]interface{})) > 0 { + PastBreakdownModel, err := resourceIBMCmOfferingMapToCostBreakdown(modelMap["past_breakdown"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PastBreakdown = PastBreakdownModel + } + if modelMap["breakdown"] != nil && len(modelMap["breakdown"].([]interface{})) > 0 { + BreakdownModel, err := resourceIBMCmOfferingMapToCostBreakdown(modelMap["breakdown"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Breakdown = BreakdownModel + } + if modelMap["diff"] != nil && len(modelMap["diff"].([]interface{})) > 0 { + DiffModel, err := resourceIBMCmOfferingMapToCostBreakdown(modelMap["diff"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Diff = DiffModel + } + if modelMap["summary"] != nil && len(modelMap["summary"].([]interface{})) > 0 { + SummaryModel, err := resourceIBMCmOfferingMapToCostSummary(modelMap["summary"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Summary = SummaryModel + } + return model, nil +} + +func resourceIBMCmOfferingMapToCostBreakdown(modelMap map[string]interface{}) (*catalogmanagementv1.CostBreakdown, error) { + model := &catalogmanagementv1.CostBreakdown{} + if modelMap["total_hourly_cost"] != nil && modelMap["total_hourly_cost"].(string) != "" { + model.TotalHourlyCost = core.StringPtr(modelMap["total_hourly_cost"].(string)) + } + if modelMap["total_monthly_c_ost"] != nil && modelMap["total_monthly_c_ost"].(string) != "" { + model.TotalMonthlyCOst = core.StringPtr(modelMap["total_monthly_c_ost"].(string)) + } + if modelMap["resources"] != nil { + resources := []catalogmanagementv1.CostResource{} + for _, resourcesItem := range modelMap["resources"].([]interface{}) { + resourcesItemModel, err := resourceIBMCmOfferingMapToCostResource(resourcesItem.(map[string]interface{})) + if err != nil { + return model, err + } + resources = append(resources, *resourcesItemModel) + } + model.Resources = resources + } + return model, nil +} + +func resourceIBMCmOfferingMapToCostResource(modelMap map[string]interface{}) (*catalogmanagementv1.CostResource, error) { + model := &catalogmanagementv1.CostResource{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["metadata"] != nil { + // TODO: handle Metadata, map with entry type '' + } + if modelMap["hourly_cost"] != nil && modelMap["hourly_cost"].(string) != "" { + model.HourlyCost = core.StringPtr(modelMap["hourly_cost"].(string)) + } + if modelMap["monthly_cost"] != nil && modelMap["monthly_cost"].(string) != "" { + model.MonthlyCost = core.StringPtr(modelMap["monthly_cost"].(string)) + } + if modelMap["cost_components"] != nil { + costComponents := []catalogmanagementv1.CostComponent{} + for _, costComponentsItem := range modelMap["cost_components"].([]interface{}) { + costComponentsItemModel, err := resourceIBMCmOfferingMapToCostComponent(costComponentsItem.(map[string]interface{})) + if err != nil { + return model, err + } + costComponents = append(costComponents, *costComponentsItemModel) + } + model.CostComponents = costComponents + } + return model, nil +} + +func resourceIBMCmOfferingMapToCostComponent(modelMap map[string]interface{}) (*catalogmanagementv1.CostComponent, error) { + model := &catalogmanagementv1.CostComponent{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["unit"] != nil && modelMap["unit"].(string) != "" { + model.Unit = core.StringPtr(modelMap["unit"].(string)) + } + if modelMap["hourly_quantity"] != nil && modelMap["hourly_quantity"].(string) != "" { + model.HourlyQuantity = core.StringPtr(modelMap["hourly_quantity"].(string)) + } + if modelMap["monthly_quantity"] != nil && modelMap["monthly_quantity"].(string) != "" { + model.MonthlyQuantity = core.StringPtr(modelMap["monthly_quantity"].(string)) + } + if modelMap["price"] != nil && modelMap["price"].(string) != "" { + model.Price = core.StringPtr(modelMap["price"].(string)) + } + if modelMap["hourly_cost"] != nil && modelMap["hourly_cost"].(string) != "" { + model.HourlyCost = core.StringPtr(modelMap["hourly_cost"].(string)) + } + if modelMap["monthly_cost"] != nil && modelMap["monthly_cost"].(string) != "" { + model.MonthlyCost = core.StringPtr(modelMap["monthly_cost"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToCostSummary(modelMap map[string]interface{}) (*catalogmanagementv1.CostSummary, error) { + model := &catalogmanagementv1.CostSummary{} + if modelMap["total_detected_resources"] != nil { + model.TotalDetectedResources = core.Int64Ptr(int64(modelMap["total_detected_resources"].(int))) + } + if modelMap["total_supported_resources"] != nil { + model.TotalSupportedResources = core.Int64Ptr(int64(modelMap["total_supported_resources"].(int))) + } + if modelMap["total_unsupported_resources"] != nil { + model.TotalUnsupportedResources = core.Int64Ptr(int64(modelMap["total_unsupported_resources"].(int))) + } + if modelMap["total_usage_based_resources"] != nil { + model.TotalUsageBasedResources = core.Int64Ptr(int64(modelMap["total_usage_based_resources"].(int))) + } + if modelMap["total_no_price_resources"] != nil { + model.TotalNoPriceResources = core.Int64Ptr(int64(modelMap["total_no_price_resources"].(int))) + } + if modelMap["unsupported_resource_counts"] != nil { + // TODO: handle UnsupportedResourceCounts, map with entry type '' + } + if modelMap["no_price_resource_counts"] != nil { + // TODO: handle NoPriceResourceCounts, map with entry type '' + } + return model, nil +} + +func resourceIBMCmOfferingMapToDependency(modelMap map[string]interface{}) (*catalogmanagementv1.Dependency, error) { + model := &catalogmanagementv1.Dependency{} + if modelMap["catalog_id"] != nil && modelMap["catalog_id"].(string) != "" { + model.CatalogID = core.StringPtr(modelMap["catalog_id"].(string)) + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["version"] != nil && modelMap["version"].(string) != "" { + model.Version = core.StringPtr(modelMap["version"].(string)) + } + if modelMap["flavors"] != nil { + flavors := []string{} + for _, flavorsItem := range modelMap["flavors"].([]interface{}) { + flavors = append(flavors, flavorsItem.(string)) + } + model.Flavors = flavors + } + return model, nil +} + +func resourceIBMCmOfferingMapToPlan(modelMap map[string]interface{}) (*catalogmanagementv1.Plan, error) { + model := &catalogmanagementv1.Plan{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["label"] != nil && modelMap["label"].(string) != "" { + model.Label = core.StringPtr(modelMap["label"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["short_description"] != nil && modelMap["short_description"].(string) != "" { + model.ShortDescription = core.StringPtr(modelMap["short_description"].(string)) + } + if modelMap["long_description"] != nil && modelMap["long_description"].(string) != "" { + model.LongDescription = core.StringPtr(modelMap["long_description"].(string)) + } + if modelMap["metadata"] != nil { + // TODO: handle Metadata, map with entry type '' + } + if modelMap["tags"] != nil { + tags := []string{} + for _, tagsItem := range modelMap["tags"].([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + model.Tags = tags + } + if modelMap["additional_features"] != nil { + additionalFeatures := []catalogmanagementv1.Feature{} + for _, additionalFeaturesItem := range modelMap["additional_features"].([]interface{}) { + additionalFeaturesItemModel, err := resourceIBMCmOfferingMapToFeature(additionalFeaturesItem.(map[string]interface{})) + if err != nil { + return model, err + } + additionalFeatures = append(additionalFeatures, *additionalFeaturesItemModel) + } + model.AdditionalFeatures = additionalFeatures + } + if modelMap["created"] != nil { + + } + if modelMap["updated"] != nil { + + } + if modelMap["deployments"] != nil { + deployments := []catalogmanagementv1.Deployment{} + for _, deploymentsItem := range modelMap["deployments"].([]interface{}) { + deploymentsItemModel, err := resourceIBMCmOfferingMapToDeployment(deploymentsItem.(map[string]interface{})) + if err != nil { + return model, err + } + deployments = append(deployments, *deploymentsItemModel) + } + model.Deployments = deployments + } + return model, nil +} + +func resourceIBMCmOfferingMapToDeployment(modelMap map[string]interface{}) (*catalogmanagementv1.Deployment, error) { + model := &catalogmanagementv1.Deployment{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["label"] != nil && modelMap["label"].(string) != "" { + model.Label = core.StringPtr(modelMap["label"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["short_description"] != nil && modelMap["short_description"].(string) != "" { + model.ShortDescription = core.StringPtr(modelMap["short_description"].(string)) + } + if modelMap["long_description"] != nil && modelMap["long_description"].(string) != "" { + model.LongDescription = core.StringPtr(modelMap["long_description"].(string)) + } + if modelMap["metadata"] != nil { + // TODO: handle Metadata, map with entry type '' + } + if modelMap["tags"] != nil { + tags := []string{} + for _, tagsItem := range modelMap["tags"].([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + model.Tags = tags + } + if modelMap["created"] != nil { + + } + if modelMap["updated"] != nil { + + } + return model, nil +} + +func resourceIBMCmOfferingMapToProviderInfo(modelMap map[string]interface{}) (*catalogmanagementv1.ProviderInfo, error) { + model := &catalogmanagementv1.ProviderInfo{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToRepoInfo(modelMap map[string]interface{}) (*catalogmanagementv1.RepoInfo, error) { + model := &catalogmanagementv1.RepoInfo{} + if modelMap["token"] != nil && modelMap["token"].(string) != "" { + model.Token = core.StringPtr(modelMap["token"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToImagePullKey(modelMap map[string]interface{}) (*catalogmanagementv1.ImagePullKey, error) { + model := &catalogmanagementv1.ImagePullKey{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["value"] != nil && modelMap["value"].(string) != "" { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupport(modelMap map[string]interface{}) (*catalogmanagementv1.Support, error) { + model := &catalogmanagementv1.Support{} + if modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if modelMap["process"] != nil && modelMap["process"].(string) != "" { + model.Process = core.StringPtr(modelMap["process"].(string)) + } + if modelMap["process_i18n"] != nil { + // TODO: handle ProcessI18n, map with entry type '' + } + if modelMap["locations"] != nil { + locations := []string{} + for _, locationsItem := range modelMap["locations"].([]interface{}) { + locations = append(locations, locationsItem.(string)) + } + model.Locations = locations + } + if modelMap["support_details"] != nil { + supportDetails := []catalogmanagementv1.SupportDetail{} + for _, supportDetailsItem := range modelMap["support_details"].([]interface{}) { + supportDetailsItemModel, err := resourceIBMCmOfferingMapToSupportDetail(supportDetailsItem.(map[string]interface{})) + if err != nil { + return model, err + } + supportDetails = append(supportDetails, *supportDetailsItemModel) + } + model.SupportDetails = supportDetails + } + if modelMap["support_escalation"] != nil && len(modelMap["support_escalation"].([]interface{})) > 0 { + SupportEscalationModel, err := resourceIBMCmOfferingMapToSupportEscalation(modelMap["support_escalation"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.SupportEscalation = SupportEscalationModel + } + if modelMap["support_type"] != nil && modelMap["support_type"].(string) != "" { + model.SupportType = core.StringPtr(modelMap["support_type"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupportDetail(modelMap map[string]interface{}) (*catalogmanagementv1.SupportDetail, error) { + model := &catalogmanagementv1.SupportDetail{} + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["contact"] != nil && modelMap["contact"].(string) != "" { + model.Contact = core.StringPtr(modelMap["contact"].(string)) + } + if modelMap["response_wait_time"] != nil && len(modelMap["response_wait_time"].([]interface{})) > 0 { + ResponseWaitTimeModel, err := resourceIBMCmOfferingMapToSupportWaitTime(modelMap["response_wait_time"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ResponseWaitTime = ResponseWaitTimeModel + } + if modelMap["availability"] != nil && len(modelMap["availability"].([]interface{})) > 0 { + AvailabilityModel, err := resourceIBMCmOfferingMapToSupportAvailability(modelMap["availability"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Availability = AvailabilityModel + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupportWaitTime(modelMap map[string]interface{}) (*catalogmanagementv1.SupportWaitTime, error) { + model := &catalogmanagementv1.SupportWaitTime{} + if modelMap["value"] != nil { + model.Value = core.Int64Ptr(int64(modelMap["value"].(int))) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupportAvailability(modelMap map[string]interface{}) (*catalogmanagementv1.SupportAvailability, error) { + model := &catalogmanagementv1.SupportAvailability{} + if modelMap["times"] != nil { + times := []catalogmanagementv1.SupportTime{} + for _, timesItem := range modelMap["times"].([]interface{}) { + timesItemModel, err := resourceIBMCmOfferingMapToSupportTime(timesItem.(map[string]interface{})) + if err != nil { + return model, err + } + times = append(times, *timesItemModel) + } + model.Times = times + } + if modelMap["timezone"] != nil && modelMap["timezone"].(string) != "" { + model.Timezone = core.StringPtr(modelMap["timezone"].(string)) + } + if modelMap["always_available"] != nil { + model.AlwaysAvailable = core.BoolPtr(modelMap["always_available"].(bool)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupportTime(modelMap map[string]interface{}) (*catalogmanagementv1.SupportTime, error) { + model := &catalogmanagementv1.SupportTime{} + if modelMap["day"] != nil { + model.Day = core.Int64Ptr(int64(modelMap["day"].(int))) + } + if modelMap["start_time"] != nil && modelMap["start_time"].(string) != "" { + model.StartTime = core.StringPtr(modelMap["start_time"].(string)) + } + if modelMap["end_time"] != nil && modelMap["end_time"].(string) != "" { + model.EndTime = core.StringPtr(modelMap["end_time"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToSupportEscalation(modelMap map[string]interface{}) (*catalogmanagementv1.SupportEscalation, error) { + model := &catalogmanagementv1.SupportEscalation{} + if modelMap["escalation_wait_time"] != nil && len(modelMap["escalation_wait_time"].([]interface{})) > 0 { + EscalationWaitTimeModel, err := resourceIBMCmOfferingMapToSupportWaitTime(modelMap["escalation_wait_time"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.EscalationWaitTime = EscalationWaitTimeModel + } + if modelMap["response_wait_time"] != nil && len(modelMap["response_wait_time"].([]interface{})) > 0 { + ResponseWaitTimeModel, err := resourceIBMCmOfferingMapToSupportWaitTime(modelMap["response_wait_time"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ResponseWaitTime = ResponseWaitTimeModel + } + if modelMap["contact"] != nil && modelMap["contact"].(string) != "" { + model.Contact = core.StringPtr(modelMap["contact"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToBadge(modelMap map[string]interface{}) (*catalogmanagementv1.Badge, error) { + model := &catalogmanagementv1.Badge{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["label"] != nil && modelMap["label"].(string) != "" { + model.Label = core.StringPtr(modelMap["label"].(string)) + } + if modelMap["label_i18n"] != nil { + // TODO: handle LabelI18n, map with entry type '' + } + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["description_i18n"] != nil { + // TODO: handle DescriptionI18n, map with entry type '' + } + if modelMap["icon"] != nil && modelMap["icon"].(string) != "" { + model.Icon = core.StringPtr(modelMap["icon"].(string)) + } + if modelMap["authority"] != nil && modelMap["authority"].(string) != "" { + model.Authority = core.StringPtr(modelMap["authority"].(string)) + } + if modelMap["tag"] != nil && modelMap["tag"].(string) != "" { + model.Tag = core.StringPtr(modelMap["tag"].(string)) + } + if modelMap["learn_more_links"] != nil && len(modelMap["learn_more_links"].([]interface{})) > 0 { + LearnMoreLinksModel, err := resourceIBMCmOfferingMapToLearnMoreLinks(modelMap["learn_more_links"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.LearnMoreLinks = LearnMoreLinksModel + } + if modelMap["constraints"] != nil { + constraints := []catalogmanagementv1.Constraint{} + for _, constraintsItem := range modelMap["constraints"].([]interface{}) { + constraintsItemModel, err := resourceIBMCmOfferingMapToConstraint(constraintsItem.(map[string]interface{})) + if err != nil { + return model, err + } + constraints = append(constraints, *constraintsItemModel) + } + model.Constraints = constraints + } + return model, nil +} + +func resourceIBMCmOfferingMapToLearnMoreLinks(modelMap map[string]interface{}) (*catalogmanagementv1.LearnMoreLinks, error) { + model := &catalogmanagementv1.LearnMoreLinks{} + if modelMap["first_party"] != nil && modelMap["first_party"].(string) != "" { + model.FirstParty = core.StringPtr(modelMap["first_party"].(string)) + } + if modelMap["third_party"] != nil && modelMap["third_party"].(string) != "" { + model.ThirdParty = core.StringPtr(modelMap["third_party"].(string)) + } + return model, nil +} + +func resourceIBMCmOfferingMapToConstraint(modelMap map[string]interface{}) (*catalogmanagementv1.Constraint, error) { + model := &catalogmanagementv1.Constraint{} + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + // if modelMap["rule"] != nil { + + // } + return model, nil +} + +func resourceIBMCmOfferingRatingToMap(model *catalogmanagementv1.Rating) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.OneStarCount != nil { + modelMap["one_star_count"] = flex.IntValue(model.OneStarCount) + } + if model.TwoStarCount != nil { + modelMap["two_star_count"] = flex.IntValue(model.TwoStarCount) + } + if model.ThreeStarCount != nil { + modelMap["three_star_count"] = flex.IntValue(model.ThreeStarCount) + } + if model.FourStarCount != nil { + modelMap["four_star_count"] = flex.IntValue(model.FourStarCount) + } + return modelMap, nil +} + +func resourceIBMCmOfferingFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = model.Title + } + if model.TitleI18n != nil { + // TODO: handle TitleI18n of type TypeMap -- container, not list + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmOfferingKindToMap(model *catalogmanagementv1.Kind) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.FormatKind != nil { + modelMap["format_kind"] = model.FormatKind + } + if model.InstallKind != nil { + modelMap["install_kind"] = model.InstallKind + } + if model.TargetKind != nil { + modelMap["target_kind"] = model.TargetKind + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.AdditionalFeatures != nil { + additionalFeatures := []map[string]interface{}{} + for _, additionalFeaturesItem := range model.AdditionalFeatures { + additionalFeaturesItemMap, err := resourceIBMCmOfferingFeatureToMap(&additionalFeaturesItem) + if err != nil { + return modelMap, err + } + additionalFeatures = append(additionalFeatures, additionalFeaturesItemMap) + } + modelMap["additional_features"] = additionalFeatures + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.Versions != nil { + versions := []map[string]interface{}{} + for _, versionsItem := range model.Versions { + versionsItemMap, err := resourceIBMCmOfferingVersionToMap(&versionsItem) + if err != nil { + return modelMap, err + } + versions = append(versions, versionsItemMap) + } + modelMap["versions"] = versions + } + if model.Plans != nil { + plans := []map[string]interface{}{} + for _, plansItem := range model.Plans { + plansItemMap, err := resourceIBMCmOfferingPlanToMap(&plansItem) + if err != nil { + return modelMap, err + } + plans = append(plans, plansItemMap) + } + modelMap["plans"] = plans + } + return modelMap, nil +} + +func resourceIBMCmOfferingVersionToMap(model *catalogmanagementv1.Version) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Rev != nil { + modelMap["rev"] = model.Rev + } + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Flavor != nil { + flavorMap, err := resourceIBMCmOfferingFlavorToMap(model.Flavor) + if err != nil { + return modelMap, err + } + modelMap["flavor"] = []map[string]interface{}{flavorMap} + } + if model.Sha != nil { + modelMap["sha"] = model.Sha + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.OfferingID != nil { + modelMap["offering_id"] = model.OfferingID + } + if model.CatalogID != nil { + modelMap["catalog_id"] = model.CatalogID + } + if model.KindID != nil { + modelMap["kind_id"] = model.KindID + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.RepoURL != nil { + modelMap["repo_url"] = model.RepoURL + } + if model.SourceURL != nil { + modelMap["source_url"] = model.SourceURL + } + if model.TgzURL != nil { + modelMap["tgz_url"] = model.TgzURL + } + if model.Configuration != nil { + configuration := []map[string]interface{}{} + for _, configurationItem := range model.Configuration { + configurationItemMap, err := resourceIBMCmOfferingConfigurationToMap(&configurationItem) + if err != nil { + return modelMap, err + } + configuration = append(configuration, configurationItemMap) + } + modelMap["configuration"] = configuration + } + if model.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range model.Outputs { + outputsItemMap, err := resourceIBMCmOfferingOutputToMap(&outputsItem) + if err != nil { + return modelMap, err + } + outputs = append(outputs, outputsItemMap) + } + modelMap["outputs"] = outputs + } + if model.IamPermissions != nil { + iamPermissions := []map[string]interface{}{} + for _, iamPermissionsItem := range model.IamPermissions { + iamPermissionsItemMap, err := resourceIBMCmOfferingIamPermissionToMap(&iamPermissionsItem) + if err != nil { + return modelMap, err + } + iamPermissions = append(iamPermissions, iamPermissionsItemMap) + } + modelMap["iam_permissions"] = iamPermissions + } + metadata := []map[string]interface{}{} + if model.Metadata != nil { + var modelMapVSI map[string]interface{} + var err error + if model.Metadata["vsi_vpc"] != nil { + modelMapVSI, err = dataSourceIBMCmVersionMetadataVSIToMap(model.Metadata["vsi_vpc"].(map[string]interface{})) + if err != nil { + return modelMap, err + } + } + convertedMap := make(map[string]interface{}, len(model.Metadata)) + for k, v := range model.Metadata { + if k == "vsi_vpc" { + convertedMap[k] = []map[string]interface{}{modelMapVSI} + } else { + convertedMap[k] = v + } + } + metadata = append(metadata, convertedMap) + } + modelMap["metadata"] = metadata + + if model.Validation != nil { + validationMap, err := resourceIBMCmOfferingValidationToMap(model.Validation) + if err != nil { + return modelMap, err + } + modelMap["validation"] = []map[string]interface{}{validationMap} + } + if model.RequiredResources != nil { + requiredResources := []map[string]interface{}{} + for _, requiredResourcesItem := range model.RequiredResources { + requiredResourcesItemMap, err := resourceIBMCmOfferingResourceToMap(&requiredResourcesItem) + if err != nil { + return modelMap, err + } + requiredResources = append(requiredResources, requiredResourcesItemMap) + } + modelMap["required_resources"] = requiredResources + } + if model.SingleInstance != nil { + modelMap["single_instance"] = model.SingleInstance + } + if model.Install != nil { + installMap, err := resourceIBMCmOfferingScriptToMap(model.Install) + if err != nil { + return modelMap, err + } + modelMap["install"] = []map[string]interface{}{installMap} + } + if model.PreInstall != nil { + preInstall := []map[string]interface{}{} + for _, preInstallItem := range model.PreInstall { + preInstallItemMap, err := resourceIBMCmOfferingScriptToMap(&preInstallItem) + if err != nil { + return modelMap, err + } + preInstall = append(preInstall, preInstallItemMap) + } + modelMap["pre_install"] = preInstall + } + if model.Entitlement != nil { + entitlementMap, err := resourceIBMCmOfferingVersionEntitlementToMap(model.Entitlement) + if err != nil { + return modelMap, err + } + modelMap["entitlement"] = []map[string]interface{}{entitlementMap} + } + if model.Licenses != nil { + licenses := []map[string]interface{}{} + for _, licensesItem := range model.Licenses { + licensesItemMap, err := resourceIBMCmOfferingLicenseToMap(&licensesItem) + if err != nil { + return modelMap, err + } + licenses = append(licenses, licensesItemMap) + } + modelMap["licenses"] = licenses + } + if model.ImageManifestURL != nil { + modelMap["image_manifest_url"] = model.ImageManifestURL + } + if model.Deprecated != nil { + modelMap["deprecated"] = model.Deprecated + } + if model.PackageVersion != nil { + modelMap["package_version"] = model.PackageVersion + } + if model.State != nil { + stateMap, err := resourceIBMCmOfferingStateToMap(model.State) + if err != nil { + return modelMap, err + } + modelMap["state"] = []map[string]interface{}{stateMap} + } + if model.VersionLocator != nil { + modelMap["version_locator"] = model.VersionLocator + } + if model.LongDescription != nil { + modelMap["long_description"] = model.LongDescription + } + if model.LongDescriptionI18n != nil { + // TODO: handle LongDescriptionI18n of type TypeMap -- container, not list + } + if model.WhitelistedAccounts != nil { + modelMap["whitelisted_accounts"] = model.WhitelistedAccounts + } + if model.ImagePullKeyName != nil { + modelMap["image_pull_key_name"] = model.ImagePullKeyName + } + if model.DeprecatePending != nil { + deprecatePendingMap, err := resourceIBMCmOfferingDeprecatePendingToMap(model.DeprecatePending) + if err != nil { + return modelMap, err + } + modelMap["deprecate_pending"] = []map[string]interface{}{deprecatePendingMap} + } + if model.SolutionInfo != nil { + solutionInfoMap, err := resourceIBMCmOfferingSolutionInfoToMap(model.SolutionInfo) + if err != nil { + return modelMap, err + } + modelMap["solution_info"] = []map[string]interface{}{solutionInfoMap} + } + if model.IsConsumable != nil { + modelMap["is_consumable"] = model.IsConsumable + } + return modelMap, nil +} + +func resourceIBMCmOfferingFlavorToMap(model *catalogmanagementv1.Flavor) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Label != nil { + modelMap["label"] = model.Label + } + if model.LabelI18n != nil { + // TODO: handle LabelI18n of type TypeMap -- container, not list + } + if model.Index != nil { + modelMap["index"] = flex.IntValue(model.Index) + } + return modelMap, nil +} + +func resourceIBMCmOfferingConfigurationToMap(model *catalogmanagementv1.Configuration) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = model.Key + } + if model.Type != nil { + modelMap["type"] = model.Type + } + // if model.DefaultValue != nil { + // modelMap["default_value"] = model.DefaultValue + // } + if model.DisplayName != nil { + modelMap["display_name"] = model.DisplayName + } + if model.ValueConstraint != nil { + modelMap["value_constraint"] = model.ValueConstraint + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Required != nil { + modelMap["required"] = model.Required + } + if model.Options != nil { + options := []map[string]interface{}{} + for _, optionsItem := range model.Options { + options = append(options, optionsItem.(map[string]interface{})) + } + modelMap["options"] = options + } + if model.Hidden != nil { + modelMap["hidden"] = model.Hidden + } + if model.CustomConfig != nil { + customConfigMap, err := resourceIBMCmOfferingRenderTypeToMap(model.CustomConfig) + if err != nil { + return modelMap, err + } + modelMap["custom_config"] = []map[string]interface{}{customConfigMap} + } + if model.TypeMetadata != nil { + modelMap["type_metadata"] = model.TypeMetadata + } + return modelMap, nil +} + +func resourceIBMCmOfferingRenderTypeToMap(model *catalogmanagementv1.RenderType) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Grouping != nil { + modelMap["grouping"] = model.Grouping + } + if model.OriginalGrouping != nil { + modelMap["original_grouping"] = model.OriginalGrouping + } + if model.GroupingIndex != nil { + modelMap["grouping_index"] = flex.IntValue(model.GroupingIndex) + } + if model.ConfigConstraints != nil { + // TODO: handle ConfigConstraints of type TypeMap -- container, not list + } + if model.Associations != nil { + associationsMap, err := resourceIBMCmOfferingRenderTypeAssociationsToMap(model.Associations) + if err != nil { + return modelMap, err + } + modelMap["associations"] = []map[string]interface{}{associationsMap} + } + return modelMap, nil +} + +func resourceIBMCmOfferingRenderTypeAssociationsToMap(model *catalogmanagementv1.RenderTypeAssociations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Parameters != nil { + parameters := []map[string]interface{}{} + for _, parametersItem := range model.Parameters { + parametersItemMap, err := resourceIBMCmOfferingRenderTypeAssociationsParametersItemToMap(¶metersItem) + if err != nil { + return modelMap, err + } + parameters = append(parameters, parametersItemMap) + } + modelMap["parameters"] = parameters + } + return modelMap, nil +} + +func resourceIBMCmOfferingRenderTypeAssociationsParametersItemToMap(model *catalogmanagementv1.RenderTypeAssociationsParametersItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.OptionsRefresh != nil { + modelMap["options_refresh"] = model.OptionsRefresh + } + return modelMap, nil +} + +func resourceIBMCmOfferingOutputToMap(model *catalogmanagementv1.Output) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = model.Key + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmOfferingIamPermissionToMap(model *catalogmanagementv1.IamPermission) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ServiceName != nil { + modelMap["service_name"] = model.ServiceName + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := resourceIBMCmOfferingIamResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func resourceIBMCmOfferingIamResourceToMap(model *catalogmanagementv1.IamResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + return modelMap, nil +} + +func resourceIBMCmOfferingValidationToMap(model *catalogmanagementv1.Validation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Validated != nil { + modelMap["validated"] = model.Validated.String() + } + if model.Requested != nil { + modelMap["requested"] = model.Requested.String() + } + if model.State != nil { + modelMap["state"] = model.State + } + if model.LastOperation != nil { + modelMap["last_operation"] = model.LastOperation + } + if model.Target != nil { + // TODO: handle Target of type TypeMap -- container, not list + } + if model.Message != nil { + modelMap["message"] = model.Message + } + return modelMap, nil +} + +func resourceIBMCmOfferingResourceToMap(model *catalogmanagementv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Value != nil { + modelMap["value"] = model.Value + } + return modelMap, nil +} + +func resourceIBMCmOfferingScriptToMap(model *catalogmanagementv1.Script) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Instructions != nil { + modelMap["instructions"] = model.Instructions + } + if model.InstructionsI18n != nil { + // TODO: handle InstructionsI18n of type TypeMap -- container, not list + } + if model.Script != nil { + modelMap["script"] = model.Script + } + if model.ScriptPermission != nil { + modelMap["script_permission"] = model.ScriptPermission + } + if model.DeleteScript != nil { + modelMap["delete_script"] = model.DeleteScript + } + if model.Scope != nil { + modelMap["scope"] = model.Scope + } + return modelMap, nil +} + +func resourceIBMCmOfferingVersionEntitlementToMap(model *catalogmanagementv1.VersionEntitlement) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ProviderName != nil { + modelMap["provider_name"] = model.ProviderName + } + if model.ProviderID != nil { + modelMap["provider_id"] = model.ProviderID + } + if model.ProductID != nil { + modelMap["product_id"] = model.ProductID + } + if model.PartNumbers != nil { + modelMap["part_numbers"] = model.PartNumbers + } + if model.ImageRepoName != nil { + modelMap["image_repo_name"] = model.ImageRepoName + } + return modelMap, nil +} + +func resourceIBMCmOfferingLicenseToMap(model *catalogmanagementv1.License) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmOfferingStateToMap(model *catalogmanagementv1.State) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Current != nil { + modelMap["current"] = model.Current + } + if model.CurrentEntered != nil { + modelMap["current_entered"] = model.CurrentEntered.String() + } + if model.Pending != nil { + modelMap["pending"] = model.Pending + } + if model.PendingRequested != nil { + modelMap["pending_requested"] = model.PendingRequested.String() + } + if model.Previous != nil { + modelMap["previous"] = model.Previous + } + return modelMap, nil +} + +func resourceIBMCmOfferingDeprecatePendingToMap(model *catalogmanagementv1.DeprecatePending) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.DeprecateDate != nil { + modelMap["deprecate_date"] = model.DeprecateDate.String() + } + if model.DeprecateState != nil { + modelMap["deprecate_state"] = model.DeprecateState + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmOfferingSolutionInfoToMap(model *catalogmanagementv1.SolutionInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ArchitectureDiagrams != nil { + architectureDiagrams := []map[string]interface{}{} + for _, architectureDiagramsItem := range model.ArchitectureDiagrams { + architectureDiagramsItemMap, err := resourceIBMCmOfferingArchitectureDiagramToMap(&architectureDiagramsItem) + if err != nil { + return modelMap, err + } + architectureDiagrams = append(architectureDiagrams, architectureDiagramsItemMap) + } + modelMap["architecture_diagrams"] = architectureDiagrams + } + if model.Features != nil { + features := []map[string]interface{}{} + for _, featuresItem := range model.Features { + featuresItemMap, err := resourceIBMCmOfferingFeatureToMap(&featuresItem) + if err != nil { + return modelMap, err + } + features = append(features, featuresItemMap) + } + modelMap["features"] = features + } + if model.CostEstimate != nil { + costEstimateMap, err := resourceIBMCmOfferingCostEstimateToMap(model.CostEstimate) + if err != nil { + return modelMap, err + } + modelMap["cost_estimate"] = []map[string]interface{}{costEstimateMap} + } + if model.Dependencies != nil { + dependencies := []map[string]interface{}{} + for _, dependenciesItem := range model.Dependencies { + dependenciesItemMap, err := resourceIBMCmOfferingDependencyToMap(&dependenciesItem) + if err != nil { + return modelMap, err + } + dependencies = append(dependencies, dependenciesItemMap) + } + modelMap["dependencies"] = dependencies + } + return modelMap, nil +} + +func resourceIBMCmOfferingArchitectureDiagramToMap(model *catalogmanagementv1.ArchitectureDiagram) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Diagram != nil { + diagramMap, err := resourceIBMCmOfferingMediaItemToMap(model.Diagram) + if err != nil { + return modelMap, err + } + modelMap["diagram"] = []map[string]interface{}{diagramMap} + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmOfferingMediaItemToMap(model *catalogmanagementv1.MediaItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.APIURL != nil { + modelMap["api_url"] = model.APIURL + } + if model.URLProxy != nil { + urlProxyMap, err := resourceIBMCmOfferingURLProxyToMap(model.URLProxy) + if err != nil { + return modelMap, err + } + modelMap["url_proxy"] = []map[string]interface{}{urlProxyMap} + } + if model.Caption != nil { + modelMap["caption"] = model.Caption + } + if model.CaptionI18n != nil { + // TODO: handle CaptionI18n of type TypeMap -- container, not list + } + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.ThumbnailURL != nil { + modelMap["thumbnail_url"] = model.ThumbnailURL + } + return modelMap, nil +} + +func resourceIBMCmOfferingURLProxyToMap(model *catalogmanagementv1.URLProxy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Sha != nil { + modelMap["sha"] = model.Sha + } + return modelMap, nil +} + +func resourceIBMCmOfferingCostEstimateToMap(model *catalogmanagementv1.CostEstimate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Currency != nil { + modelMap["currency"] = model.Currency + } + if model.Projects != nil { + projects := []map[string]interface{}{} + for _, projectsItem := range model.Projects { + projectsItemMap, err := resourceIBMCmOfferingProjectToMap(&projectsItem) + if err != nil { + return modelMap, err + } + projects = append(projects, projectsItemMap) + } + modelMap["projects"] = projects + } + if model.Summary != nil { + summaryMap, err := resourceIBMCmOfferingCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = model.TotalHourlyCost + } + if model.TotalMonthlyCost != nil { + modelMap["total_monthly_cost"] = model.TotalMonthlyCost + } + if model.PastTotalHourlyCost != nil { + modelMap["past_total_hourly_cost"] = model.PastTotalHourlyCost + } + if model.PastTotalMonthlyCost != nil { + modelMap["past_total_monthly_cost"] = model.PastTotalMonthlyCost + } + if model.DiffTotalHourlyCost != nil { + modelMap["diff_total_hourly_cost"] = model.DiffTotalHourlyCost + } + if model.DiffTotalMonthlyCost != nil { + modelMap["diff_total_monthly_cost"] = model.DiffTotalMonthlyCost + } + if model.TimeGenerated != nil { + modelMap["time_generated"] = model.TimeGenerated.String() + } + return modelMap, nil +} + +func resourceIBMCmOfferingProjectToMap(model *catalogmanagementv1.Project) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.PastBreakdown != nil { + pastBreakdownMap, err := resourceIBMCmOfferingCostBreakdownToMap(model.PastBreakdown) + if err != nil { + return modelMap, err + } + modelMap["past_breakdown"] = []map[string]interface{}{pastBreakdownMap} + } + if model.Breakdown != nil { + breakdownMap, err := resourceIBMCmOfferingCostBreakdownToMap(model.Breakdown) + if err != nil { + return modelMap, err + } + modelMap["breakdown"] = []map[string]interface{}{breakdownMap} + } + if model.Diff != nil { + diffMap, err := resourceIBMCmOfferingCostBreakdownToMap(model.Diff) + if err != nil { + return modelMap, err + } + modelMap["diff"] = []map[string]interface{}{diffMap} + } + if model.Summary != nil { + summaryMap, err := resourceIBMCmOfferingCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + return modelMap, nil +} + +func resourceIBMCmOfferingCostBreakdownToMap(model *catalogmanagementv1.CostBreakdown) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = model.TotalHourlyCost + } + if model.TotalMonthlyCOst != nil { + modelMap["total_monthly_c_ost"] = model.TotalMonthlyCOst + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := resourceIBMCmOfferingCostResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func resourceIBMCmOfferingCostResourceToMap(model *catalogmanagementv1.CostResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = model.MonthlyCost + } + if model.CostComponents != nil { + costComponents := []map[string]interface{}{} + for _, costComponentsItem := range model.CostComponents { + costComponentsItemMap, err := resourceIBMCmOfferingCostComponentToMap(&costComponentsItem) + if err != nil { + return modelMap, err + } + costComponents = append(costComponents, costComponentsItemMap) + } + modelMap["cost_components"] = costComponents + } + return modelMap, nil +} + +func resourceIBMCmOfferingCostComponentToMap(model *catalogmanagementv1.CostComponent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Unit != nil { + modelMap["unit"] = model.Unit + } + if model.HourlyQuantity != nil { + modelMap["hourly_quantity"] = model.HourlyQuantity + } + if model.MonthlyQuantity != nil { + modelMap["monthly_quantity"] = model.MonthlyQuantity + } + if model.Price != nil { + modelMap["price"] = model.Price + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = model.MonthlyCost + } + return modelMap, nil +} + +func resourceIBMCmOfferingCostSummaryToMap(model *catalogmanagementv1.CostSummary) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalDetectedResources != nil { + modelMap["total_detected_resources"] = flex.IntValue(model.TotalDetectedResources) + } + if model.TotalSupportedResources != nil { + modelMap["total_supported_resources"] = flex.IntValue(model.TotalSupportedResources) + } + if model.TotalUnsupportedResources != nil { + modelMap["total_unsupported_resources"] = flex.IntValue(model.TotalUnsupportedResources) + } + if model.TotalUsageBasedResources != nil { + modelMap["total_usage_based_resources"] = flex.IntValue(model.TotalUsageBasedResources) + } + if model.TotalNoPriceResources != nil { + modelMap["total_no_price_resources"] = flex.IntValue(model.TotalNoPriceResources) + } + if model.UnsupportedResourceCounts != nil { + // TODO: handle UnsupportedResourceCounts of type TypeMap -- container, not list + } + if model.NoPriceResourceCounts != nil { + // TODO: handle NoPriceResourceCounts of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmOfferingDependencyToMap(model *catalogmanagementv1.Dependency) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CatalogID != nil { + modelMap["catalog_id"] = model.CatalogID + } + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Flavors != nil { + modelMap["flavors"] = model.Flavors + } + return modelMap, nil +} + +func resourceIBMCmOfferingPlanToMap(model *catalogmanagementv1.Plan) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Label != nil { + modelMap["label"] = model.Label + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.ShortDescription != nil { + modelMap["short_description"] = model.ShortDescription + } + if model.LongDescription != nil { + modelMap["long_description"] = model.LongDescription + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.AdditionalFeatures != nil { + additionalFeatures := []map[string]interface{}{} + for _, additionalFeaturesItem := range model.AdditionalFeatures { + additionalFeaturesItemMap, err := resourceIBMCmOfferingFeatureToMap(&additionalFeaturesItem) + if err != nil { + return modelMap, err + } + additionalFeatures = append(additionalFeatures, additionalFeaturesItemMap) + } + modelMap["additional_features"] = additionalFeatures + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + if model.Deployments != nil { + deployments := []map[string]interface{}{} + for _, deploymentsItem := range model.Deployments { + deploymentsItemMap, err := resourceIBMCmOfferingDeploymentToMap(&deploymentsItem) + if err != nil { + return modelMap, err + } + deployments = append(deployments, deploymentsItemMap) + } + modelMap["deployments"] = deployments + } + return modelMap, nil +} + +func resourceIBMCmOfferingDeploymentToMap(model *catalogmanagementv1.Deployment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Label != nil { + modelMap["label"] = model.Label + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.ShortDescription != nil { + modelMap["short_description"] = model.ShortDescription + } + if model.LongDescription != nil { + modelMap["long_description"] = model.LongDescription + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Created != nil { + modelMap["created"] = model.Created.String() + } + if model.Updated != nil { + modelMap["updated"] = model.Updated.String() + } + return modelMap, nil +} + +func resourceIBMCmOfferingProviderInfoToMap(model *catalogmanagementv1.ProviderInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + return modelMap, nil +} + +func resourceIBMCmOfferingRepoInfoToMap(model *catalogmanagementv1.RepoInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Token != nil { + modelMap["token"] = model.Token + } + if model.Type != nil { + modelMap["type"] = model.Type + } + return modelMap, nil +} + +func resourceIBMCmOfferingImagePullKeyToMap(model *catalogmanagementv1.ImagePullKey) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportToMap(model *catalogmanagementv1.Support) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Process != nil { + modelMap["process"] = model.Process + } + if model.ProcessI18n != nil { + // TODO: handle ProcessI18n of type TypeMap -- container, not list + } + if model.Locations != nil { + modelMap["locations"] = model.Locations + } + if model.SupportDetails != nil { + supportDetails := []map[string]interface{}{} + for _, supportDetailsItem := range model.SupportDetails { + supportDetailsItemMap, err := resourceIBMCmOfferingSupportDetailToMap(&supportDetailsItem) + if err != nil { + return modelMap, err + } + supportDetails = append(supportDetails, supportDetailsItemMap) + } + modelMap["support_details"] = supportDetails + } + if model.SupportEscalation != nil { + supportEscalationMap, err := resourceIBMCmOfferingSupportEscalationToMap(model.SupportEscalation) + if err != nil { + return modelMap, err + } + modelMap["support_escalation"] = []map[string]interface{}{supportEscalationMap} + } + if model.SupportType != nil { + modelMap["support_type"] = model.SupportType + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportDetailToMap(model *catalogmanagementv1.SupportDetail) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Contact != nil { + modelMap["contact"] = model.Contact + } + if model.ResponseWaitTime != nil { + responseWaitTimeMap, err := resourceIBMCmOfferingSupportWaitTimeToMap(model.ResponseWaitTime) + if err != nil { + return modelMap, err + } + modelMap["response_wait_time"] = []map[string]interface{}{responseWaitTimeMap} + } + if model.Availability != nil { + availabilityMap, err := resourceIBMCmOfferingSupportAvailabilityToMap(model.Availability) + if err != nil { + return modelMap, err + } + modelMap["availability"] = []map[string]interface{}{availabilityMap} + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportWaitTimeToMap(model *catalogmanagementv1.SupportWaitTime) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Value != nil { + modelMap["value"] = flex.IntValue(model.Value) + } + if model.Type != nil { + modelMap["type"] = model.Type + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportAvailabilityToMap(model *catalogmanagementv1.SupportAvailability) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Times != nil { + times := []map[string]interface{}{} + for _, timesItem := range model.Times { + timesItemMap, err := resourceIBMCmOfferingSupportTimeToMap(×Item) + if err != nil { + return modelMap, err + } + times = append(times, timesItemMap) + } + modelMap["times"] = times + } + if model.Timezone != nil { + modelMap["timezone"] = model.Timezone + } + if model.AlwaysAvailable != nil { + modelMap["always_available"] = model.AlwaysAvailable + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportTimeToMap(model *catalogmanagementv1.SupportTime) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Day != nil { + modelMap["day"] = flex.IntValue(model.Day) + } + if model.StartTime != nil { + modelMap["start_time"] = model.StartTime + } + if model.EndTime != nil { + modelMap["end_time"] = model.EndTime + } + return modelMap, nil +} + +func resourceIBMCmOfferingSupportEscalationToMap(model *catalogmanagementv1.SupportEscalation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.EscalationWaitTime != nil { + escalationWaitTimeMap, err := resourceIBMCmOfferingSupportWaitTimeToMap(model.EscalationWaitTime) + if err != nil { + return modelMap, err + } + modelMap["escalation_wait_time"] = []map[string]interface{}{escalationWaitTimeMap} + } + if model.ResponseWaitTime != nil { + responseWaitTimeMap, err := resourceIBMCmOfferingSupportWaitTimeToMap(model.ResponseWaitTime) + if err != nil { + return modelMap, err + } + modelMap["response_wait_time"] = []map[string]interface{}{responseWaitTimeMap} + } + if model.Contact != nil { + modelMap["contact"] = model.Contact + } + return modelMap, nil +} + +func resourceIBMCmOfferingBadgeToMap(model *catalogmanagementv1.Badge) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Label != nil { + modelMap["label"] = model.Label + } + if model.LabelI18n != nil { + // TODO: handle LabelI18n of type TypeMap -- container, not list + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + if model.Icon != nil { + modelMap["icon"] = model.Icon + } + if model.Authority != nil { + modelMap["authority"] = model.Authority + } + if model.Tag != nil { + modelMap["tag"] = model.Tag + } + if model.LearnMoreLinks != nil { + learnMoreLinksMap, err := resourceIBMCmOfferingLearnMoreLinksToMap(model.LearnMoreLinks) + if err != nil { + return modelMap, err + } + modelMap["learn_more_links"] = []map[string]interface{}{learnMoreLinksMap} + } + if model.Constraints != nil { + constraints := []map[string]interface{}{} + for _, constraintsItem := range model.Constraints { + constraintsItemMap, err := resourceIBMCmOfferingConstraintToMap(&constraintsItem) + if err != nil { + return modelMap, err + } + constraints = append(constraints, constraintsItemMap) + } + modelMap["constraints"] = constraints + } + return modelMap, nil +} + +func resourceIBMCmOfferingLearnMoreLinksToMap(model *catalogmanagementv1.LearnMoreLinks) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.FirstParty != nil { + modelMap["first_party"] = model.FirstParty + } + if model.ThirdParty != nil { + modelMap["third_party"] = model.ThirdParty + } + return modelMap, nil +} + +func resourceIBMCmOfferingConstraintToMap(model *catalogmanagementv1.Constraint) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + // if model.Rule != nil { + // modelMap["rule"] = model.Rule + // } + return modelMap, nil +} diff --git a/ibm/resource_ibm_cm_offering_instance.go b/ibm/service/catalogmanagement/resource_ibm_cm_offering_instance.go similarity index 83% rename from ibm/resource_ibm_cm_offering_instance.go rename to ibm/service/catalogmanagement/resource_ibm_cm_offering_instance.go index 735d79894..d24b22c9d 100644 --- a/ibm/resource_ibm_cm_offering_instance.go +++ b/ibm/service/catalogmanagement/resource_ibm_cm_offering_instance.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package catalogmanagement import ( "fmt" @@ -9,6 +9,8 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -22,7 +24,7 @@ const ( waitUntilInterval = 10 * time.Second ) -func resourceIBMCmOfferingInstance() *schema.Resource { +func ResourceIBMCmOfferingInstance() *schema.Resource { return &schema.Resource{ Create: resourceIBMCmOfferingInstanceCreate, Read: resourceIBMCmOfferingInstanceRead, @@ -38,78 +40,78 @@ func resourceIBMCmOfferingInstance() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "url reference to this object.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "platform CRN for this instance.", }, - "label": &schema.Schema{ + "label": { Type: schema.TypeString, Required: true, Description: "the label for this instance.", }, - "catalog_id": &schema.Schema{ + "catalog_id": { Type: schema.TypeString, Required: true, Description: "Catalog ID this instance was created from.", }, - "offering_id": &schema.Schema{ + "offering_id": { Type: schema.TypeString, Required: true, Description: "Offering ID this instance was created from.", }, - "kind_format": &schema.Schema{ + "kind_format": { Type: schema.TypeString, Required: true, Description: "the format this instance has (helm, operator, ova...).", }, - "version": &schema.Schema{ + "version": { Type: schema.TypeString, Required: true, Description: "The version this instance was installed from (not version id).", }, - "cluster_id": &schema.Schema{ + "cluster_id": { Type: schema.TypeString, Required: true, Description: "Cluster ID.", }, - "cluster_region": &schema.Schema{ + "cluster_region": { Type: schema.TypeString, Required: true, Description: "Cluster region (e.g., us-south).", }, - "cluster_namespaces": &schema.Schema{ + "cluster_namespaces": { Type: schema.TypeList, Required: true, Description: "List of target namespaces to install into.", Elem: &schema.Schema{Type: schema.TypeString}, }, - "cluster_all_namespaces": &schema.Schema{ + "cluster_all_namespaces": { Type: schema.TypeBool, Required: true, Description: "designate to install into all namespaces.", }, - "schematics_workspace_id": &schema.Schema{ + "schematics_workspace_id": { Type: schema.TypeString, Computed: true, Description: "id of the schematics workspace, for offerings installed through schematics", }, - "resource_group_id": &schema.Schema{ + "resource_group_id": { Type: schema.TypeString, Optional: true, Description: "id of the resource group", }, - "install_plan": &schema.Schema{ + "install_plan": { Type: schema.TypeString, Optional: true, Description: "install plan for the subscription of the operator- can be either automatic or manual. Required for operator bundles", }, - "channel": &schema.Schema{ + "channel": { Type: schema.TypeString, Optional: true, Description: "channel to target for the operator subscription. Required for operator bundles", @@ -117,7 +119,7 @@ func resourceIBMCmOfferingInstance() *schema.Resource { "wait_until_successful": { Type: schema.TypeBool, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Default: true, Description: "Whether to wait until the offering instance successfully provisions, or to return when accepted", }, @@ -126,12 +128,12 @@ func resourceIBMCmOfferingInstance() *schema.Resource { } func resourceIBMCmOfferingInstanceCreate(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return err } - rsConClient, err := meta.(ClientSession).BluemixSession() + rsConClient, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -165,7 +167,7 @@ func resourceIBMCmOfferingInstanceCreate(d *schema.ResourceData, meta interface{ createOfferingInstanceOptions.SetClusterRegion(d.Get("cluster_region").(string)) } if ns, ok := d.GetOk("cluster_namespaces"); ok { - list := expandStringList(ns.([]interface{})) + list := flex.ExpandStringList(ns.([]interface{})) createOfferingInstanceOptions.SetClusterNamespaces(list) } if _, ok := d.GetOk("cluster_all_namespaces"); ok { @@ -202,7 +204,7 @@ func resourceIBMCmOfferingInstanceCreate(d *schema.ResourceData, meta interface{ } func waitUntilSuccess(d *schema.ResourceData, meta interface{}) (interface{}, error) { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return nil, err } @@ -216,7 +218,7 @@ func waitUntilSuccess(d *schema.ResourceData, meta interface{}) (interface{}, er Refresh: func() (interface{}, string, error) { offeringInstance, _, err := catalogManagementClient.GetOfferingInstance(getOfferingInstanceOptions) if err != nil { - return nil, "", fmt.Errorf("Error retrieving offering instance: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving offering instance: %s", err) } return offeringInstance, *offeringInstance.LastOperation.State, nil @@ -230,7 +232,7 @@ func waitUntilSuccess(d *schema.ResourceData, meta interface{}) (interface{}, er } func resourceIBMCmOfferingInstanceRead(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return err } @@ -250,55 +252,55 @@ func resourceIBMCmOfferingInstanceRead(d *schema.ResourceData, meta interface{}) } if err = d.Set("url", offeringInstance.URL); err != nil { - return fmt.Errorf("Error setting url: %s", err) + return fmt.Errorf("[ERROR] Error setting url: %s", err) } if err = d.Set("crn", offeringInstance.CRN); err != nil { - return fmt.Errorf("Error setting crn: %s", err) + return fmt.Errorf("[ERROR] Error setting crn: %s", err) } if err = d.Set("label", offeringInstance.Label); err != nil { - return fmt.Errorf("Error setting label: %s", err) + return fmt.Errorf("[ERROR] Error setting label: %s", err) } if err = d.Set("catalog_id", offeringInstance.CatalogID); err != nil { - return fmt.Errorf("Error setting catalog_id: %s", err) + return fmt.Errorf("[ERROR] Error setting catalog_id: %s", err) } if err = d.Set("offering_id", offeringInstance.OfferingID); err != nil { - return fmt.Errorf("Error setting offering_id: %s", err) + return fmt.Errorf("[ERROR] Error setting offering_id: %s", err) } if err = d.Set("kind_format", offeringInstance.KindFormat); err != nil { - return fmt.Errorf("Error setting kind_format: %s", err) + return fmt.Errorf("[ERROR] Error setting kind_format: %s", err) } if err = d.Set("version", offeringInstance.Version); err != nil { - return fmt.Errorf("Error setting version: %s", err) + return fmt.Errorf("[ERROR] Error setting version: %s", err) } if err = d.Set("cluster_id", offeringInstance.ClusterID); err != nil { - return fmt.Errorf("Error setting cluster_id: %s", err) + return fmt.Errorf("[ERROR] Error setting cluster_id: %s", err) } if err = d.Set("cluster_region", offeringInstance.ClusterRegion); err != nil { - return fmt.Errorf("Error setting cluster_region: %s", err) + return fmt.Errorf("[ERROR] Error setting cluster_region: %s", err) } if offeringInstance.ClusterNamespaces != nil { if err = d.Set("cluster_namespaces", offeringInstance.ClusterNamespaces); err != nil { - return fmt.Errorf("Error setting cluster_namespaces: %s", err) + return fmt.Errorf("[ERROR] Error setting cluster_namespaces: %s", err) } } if err = d.Set("cluster_all_namespaces", offeringInstance.ClusterAllNamespaces); err != nil { - return fmt.Errorf("Error setting cluster_all_namespaces: %s", err) + return fmt.Errorf("[ERROR] Error setting cluster_all_namespaces: %s", err) } if err = d.Set("schematics_workspace_id", offeringInstance.SchematicsWorkspaceID); err != nil { - return fmt.Errorf("Error setting schematics_workspace_id: %s", err) + return fmt.Errorf("[ERROR] Error setting schematics_workspace_id: %s", err) } if err = d.Set("install_plan", offeringInstance.InstallPlan); err != nil { - return fmt.Errorf("Error setting install_plan: %s", err) + return fmt.Errorf("[ERROR] Error setting install_plan: %s", err) } if err = d.Set("channel", offeringInstance.Channel); err != nil { - return fmt.Errorf("Error setting channel: %s", err) + return fmt.Errorf("[ERROR] Error setting channel: %s", err) } return nil } func resourceIBMCmOfferingInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return err } @@ -313,7 +315,7 @@ func resourceIBMCmOfferingInstanceUpdate(d *schema.ResourceData, meta interface{ return err } - rsConClient, err := meta.(ClientSession).BluemixSession() + rsConClient, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -351,7 +353,7 @@ func resourceIBMCmOfferingInstanceUpdate(d *schema.ResourceData, meta interface{ putOfferingInstanceOptions.SetClusterRegion(d.Get("cluster_region").(string)) } if ns, ok := d.GetOk("cluster_namespaces"); ok { - list := expandStringList(ns.([]interface{})) + list := flex.ExpandStringList(ns.([]interface{})) putOfferingInstanceOptions.SetClusterNamespaces(list) } if _, ok := d.GetOk("cluster_all_namespaces"); ok { @@ -377,11 +379,11 @@ func resourceIBMCmOfferingInstanceUpdate(d *schema.ResourceData, meta interface{ } func resourceIBMCmOfferingInstanceDelete(d *schema.ResourceData, meta interface{}) error { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return err } - rsConClient, err := meta.(ClientSession).BluemixSession() + rsConClient, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -403,7 +405,7 @@ func resourceIBMCmOfferingInstanceDelete(d *schema.ResourceData, meta interface{ } func resourceIBMCmOfferingInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - catalogManagementClient, err := meta.(ClientSession).CatalogManagementV1() + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() if err != nil { return false, err } diff --git a/ibm/resource_ibm_cm_offering_instance_test.go b/ibm/service/catalogmanagement/resource_ibm_cm_offering_instance_test.go similarity index 82% rename from ibm/resource_ibm_cm_offering_instance_test.go rename to ibm/service/catalogmanagement/resource_ibm_cm_offering_instance_test.go index 7c8a070f2..dcbca5a50 100644 --- a/ibm/resource_ibm_cm_offering_instance_test.go +++ b/ibm/service/catalogmanagement/resource_ibm_cm_offering_instance_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package catalogmanagement_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,18 +21,18 @@ func TestAccIBMCmOfferingInstance(t *testing.T) { clusterRegion := os.Getenv("CATMGMT_CLUSTERREGION") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCmOfferingInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCmOfferingInstanceConfig(clusterId, clusterRegion), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_cm_offering_instance.cm_offering_instance", "label"), testAccCheckIBMCmOfferingInstanceExists("ibm_cm_offering_instance.cm_offering_instance"), ), }, - resource.TestStep{ + { ResourceName: "ibm_cm_offering_instance.cm_offering_instance", ImportState: true, ImportStateVerify: true, @@ -74,7 +77,7 @@ func testAccCheckIBMCmOfferingInstanceConfig(clusterId string, clusterRegion str } func testAccCheckIBMCmOfferingInstanceDestroy(s *terraform.State) error { - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() if err != nil { return err } @@ -91,9 +94,9 @@ func testAccCheckIBMCmOfferingInstanceDestroy(s *terraform.State) error { _, response, err := catalogManagementClient.GetOfferingInstance(getOfferingInstanceOptions) if err == nil { - return fmt.Errorf("A offering instance resource (provision instance of a catalog offering). still exists: %s", rs.Primary.ID) + return fmt.Errorf("[ERROR] A offering instance resource (provision instance of a catalog offering). still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for A offering instance resource (provision instance of a catalog offering). (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for A offering instance resource (provision instance of a catalog offering). (%s) has been destroyed: %s", rs.Primary.ID, err) } } @@ -108,7 +111,7 @@ func testAccCheckIBMCmOfferingInstanceExists(n string) resource.TestCheckFunc { return fmt.Errorf("Not found: %s", n) } - catalogManagementClient, err := testAccProvider.Meta().(ClientSession).CatalogManagementV1() + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() if err != nil { return err } diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_offering_test.go b/ibm/service/catalogmanagement/resource_ibm_cm_offering_test.go new file mode 100644 index 000000000..960d69147 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_offering_test.go @@ -0,0 +1,208 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func TestAccIBMCmOfferingBasic(t *testing.T) { + var conf catalogmanagementv1.Offering + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmOfferingDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmOfferingConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmOfferingExists("ibm_cm_offering.cm_offering", conf), + ), + }, + }, + }) +} + +func TestAccIBMCmOfferingSimpleArgs(t *testing.T) { + var conf catalogmanagementv1.Offering + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + shortDescription := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) + longDescription := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) + labelUpdate := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + shortDescriptionUpdate := fmt.Sprintf("tf_short_description_%d", acctest.RandIntRange(10, 100)) + longDescriptionUpdate := fmt.Sprintf("tf_long_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmOfferingDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmOfferingConfig(label, name, shortDescription, longDescription), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmOfferingExists("ibm_cm_offering.cm_offering", conf), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "label", label), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "name", name), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "short_description", shortDescription), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "long_description", longDescription), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCmOfferingConfig(labelUpdate, name, shortDescriptionUpdate, longDescriptionUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "label", labelUpdate), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "short_description", shortDescriptionUpdate), + resource.TestCheckResourceAttr("ibm_cm_offering.cm_offering", "long_description", longDescriptionUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cm_offering.cm_offering", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCmOfferingConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_tf_catalog_label_1" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + } + `) +} + +func testAccCheckIBMCmOfferingConfig(label string, name string, shortDescription string, longDescription string) string { + return fmt.Sprintf(` + + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_tf_catalog_label_2" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "%s" + name = "%s" + short_description = "%s" + long_description = "%s" + } + `, label, name, shortDescription, longDescription) +} + +func testAccCheckIBMCmOfferingExists(n string, obj catalogmanagementv1.Offering) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getOfferingOptions.SetCatalogIdentifier(parts[0]) + getOfferingOptions.SetOfferingID(parts[1]) + + offering, _, err := catalogManagementClient.GetOffering(getOfferingOptions) + if err != nil { + return err + } + + obj = *offering + return nil + } +} + +func testAccCheckIBMCmOfferingCreate(s *terraform.State) error { + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cm_offering" { + continue + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getOfferingOptions.SetCatalogIdentifier(parts[0]) + getOfferingOptions.SetOfferingID(parts[1]) + + // Try to find the key + _, response, err := catalogManagementClient.GetOffering(getOfferingOptions) + + if err == nil { + return fmt.Errorf("cm_offering still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cm_offering (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMCmOfferingDestroy(s *terraform.State) error { + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cm_offering" { + continue + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getOfferingOptions.SetCatalogIdentifier(parts[0]) + getOfferingOptions.SetOfferingID(parts[1]) + + // Try to find the key + _, response, err := catalogManagementClient.GetOffering(getOfferingOptions) + + if err == nil { + return fmt.Errorf("cm_offering still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cm_offering (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_validation.go b/ibm/service/catalogmanagement/resource_ibm_cm_validation.go new file mode 100644 index 000000000..5f8a94791 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_validation.go @@ -0,0 +1,443 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func ResourceIBMCmValidation() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCmValidationCreate, + ReadContext: resourceIBMCmValidationRead, + UpdateContext: resourceIBMCmValidationUpdate, + DeleteContext: resourceIBMCmValidationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "version_locator": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Version locator - the version that will be validated.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Validation region.", + }, + "override_values": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Description: "Override values during validation.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "environment_variables": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Environment variables to include in the schematics workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of the environment variable.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Value of the environment variable.", + }, + "secure": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If the environment variablel should be secure.", + }, + }, + }, + }, + "schematics": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ForceNew: true, + Description: "Other values to pass to the schematics workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name for the schematics workspace.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description for the schematics workspace.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The resource group ID.", + }, + "terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version of terraform to use in schematics.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region to use for the schematics installation.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of tags for the schematics workspace.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "validated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Data and time of last successful validation.", + }, + "requested": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Data and time of last validation request.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current validation state - , in_progress, valid, invalid, expired.", + }, + "last_operation": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Last operation (e.g. submit_deployment, generate_installer, install_offering.", + }, + "target": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Any message needing to be conveyed as part of the validation job.", + }, + "x_auth_refresh_token": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "Authentication token used to submit validation job.", + }, + "revalidate_if_validated": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: "If the version should be revalidated if it is already validated.", + }, + "mark_version_consumable": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If the version should be marked as consumable or \"ready to share\".", + }, + }, + } +} + +func resourceIBMCmValidationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + validateInstallOptions := &catalogmanagementv1.ValidateInstallOptions{} + var version catalogmanagementv1.Version + + if _, ok := d.GetOk("version_locator"); ok { + validateInstallOptions.SetVersionLocatorID(d.Get("version_locator").(string)) + validateInstallOptions.SetVersionLocID(d.Get("version_locator").(string)) + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + + getVersionOptions.SetVersionLocID(d.Get("version_locator").(string)) + + offering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVersionWithContext failed %s\n%s", err, response)) + } + + version = offering.Kinds[0].Versions[0] + } + + valid := "valid" + if version.Validation.State == &valid && d.Get("revalidate_if_validated") != true { + // version already validated and do not wish to revalidate + d.SetId(*validateInstallOptions.VersionLocID) + if _, ok := d.GetOk("mark_version_consumable"); ok && d.Get("mark_version_consumable").(bool) { + err = markVersionAsConsumable(version, context, meta) + if err != nil { + d.SetId("") + return diag.FromErr(err) + } + } + + return resourceIBMCmValidationRead(context, d, meta) + } + + if _, ok := d.GetOk("region"); ok { + validateInstallOptions.SetRegion(d.Get("region").(string)) + } + if _, ok := d.GetOk("override_values"); ok { + overridesModel, err := configureOverrides(d.Get("override_values").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + validateInstallOptions.SetOverrideValues(&overridesModel) + } + if _, ok := d.GetOk("environment_variables"); ok { + envsModel, err := envVariablesToDeployRequestBodyEnvVariables(d.Get("environment_variables").([]map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + validateInstallOptions.SetEnvironmentVariables(envsModel) + } + if _, ok := d.GetOk("schematics"); ok { + schematicsModel, err := schematicsMapToDeployRequestBodySchematics(d.Get("schematics").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + validateInstallOptions.SetSchematics(&schematicsModel) + } + if _, ok := d.GetOk("x_auth_refresh_token"); ok { + validateInstallOptions.SetXAuthRefreshToken(d.Get("x_auth_refresh_token").(string)) + } + + response, err := catalogManagementClient.ValidateInstallWithContext(context, validateInstallOptions) + if err != nil { + log.Printf("[DEBUG] ValidateInstallWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ValidateInstallWithContext failed %s\n%s", err, response)) + } + + d.SetId(*validateInstallOptions.VersionLocID) + + validationStatusOptions := &catalogmanagementv1.GetValidationStatusOptions{} + validationStatusOptions.SetVersionLocID(*validateInstallOptions.VersionLocID) + validationStatusOptions.SetXAuthRefreshToken(d.Get("x_auth_refresh_token").(string)) + result, response, err := catalogManagementClient.GetValidationStatusWithContext(context, validationStatusOptions) + if err != nil { + log.Printf("[DEBUG] GetValidationStatusWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetValidationStatusWithContext failed %s\n%s", err, response)) + } + + status := *result.State + + // Track progress of validation through schematics workspace status + // Do a GET every 5 seconds to check for an updated status + ticker := time.NewTicker(5 * time.Second) + for range ticker.C { + newStatus := *result.State + if status != newStatus { + status = newStatus + } + log.Printf("[DEBUG] Status is %s\n", status) + // Break from loop if installation is successful or fails + if status == "valid" || status == "invalid" || status == "expired" { + ticker.Stop() + break + } + + result, response, err = catalogManagementClient.GetValidationStatusWithContext(context, validationStatusOptions) + if err != nil { + log.Printf("[DEBUG] GetValidationStatusWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetValidationStatusWithContext failed %s\n%s", err, response)) + } + } + + // mark consumable if specified and validation passed + if _, ok := d.GetOk("mark_version_consumable"); ok && d.Get("mark_version_consumable").(bool) && status == "valid" { + err = markVersionAsConsumable(version, context, meta) + if err != nil { + d.SetId("") + return diag.FromErr(err) + } + } + + return resourceIBMCmValidationRead(context, d, meta) +} + +func resourceIBMCmValidationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + + getVersionOptions.SetVersionLocID(d.Id()) + + offering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVersionWithContext failed %s\n%s", err, response)) + } + + version := offering.Kinds[0].Versions[0] + + if err = d.Set("version_locator", version.VersionLocator); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_locator: %s", err)) + } + if version.Validation != nil && version.Validation.Validated != nil { + if err = d.Set("validated", version.Validation.Validated.String()); err != nil { + return diag.FromErr(fmt.Errorf("Error setting validation: %s", err)) + } + } + if version.Validation != nil && version.Validation.Requested != nil { + if err = d.Set("requested", version.Validation.Requested.String()); err != nil { + return diag.FromErr(fmt.Errorf("Error setting requested: %s", err)) + } + } + if version.Validation != nil && version.Validation.State != nil { + if err = d.Set("state", version.Validation.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + } + if version.Validation != nil && version.Validation.LastOperation != nil { + if err = d.Set("last_operation", version.Validation.LastOperation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_operation: %s", err)) + } + } + if version.Validation != nil && version.Validation.Message != nil { + if err = d.Set("message", version.Validation.Message); err != nil { + return diag.FromErr(fmt.Errorf("Error setting message: %s", err)) + } + } + // if version.Validation != nil && version.Validation.Target != nil { + // if err = d.Set("target", version.Validation.Target); err != nil { + // return diag.FromErr(fmt.Errorf("Error setting target: %s", err)) + // } + // } + + return nil +} + +func resourceIBMCmValidationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func resourceIBMCmValidationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func configureOverrides(overrides map[string]interface{}) (catalogmanagementv1.DeployRequestBodyOverrideValues, error) { + overridesModel := catalogmanagementv1.DeployRequestBodyOverrideValues{} + overridesModel.SetProperties(overrides) + if overrides["vsi_instance_name"] != nil && overrides["vsi_instance_name"].(string) != "" { + overridesModel.VsiInstanceName = core.StringPtr(overrides["vsi_instance_name"].(string)) + } + if overrides["vpc_profile"] != nil && overrides["vpc_profile"].(string) != "" { + overridesModel.VPCProfile = core.StringPtr(overrides["vpc_profile"].(string)) + } + if overrides["subnet_id"] != nil && overrides["subnet_id"].(string) != "" { + overridesModel.SubnetID = core.StringPtr(overrides["subnet_id"].(string)) + } + if overrides["vpc_id"] != nil && overrides["vpc_id"].(string) != "" { + overridesModel.VPCID = core.StringPtr(overrides["vpc_id"].(string)) + } + if overrides["subnet_zone"] != nil && overrides["subnet_zone"].(string) != "" { + overridesModel.SubnetZone = core.StringPtr(overrides["subnet_zone"].(string)) + } + if overrides["ssh_key_id"] != nil && overrides["ssh_key_id"].(string) != "" { + overridesModel.SSHKeyID = core.StringPtr(overrides["ssh_key_id"].(string)) + } + if overrides["vpc_region"] != nil && overrides["vpc_region"].(string) != "" { + overridesModel.VPCRegion = core.StringPtr(overrides["vpc_region"].(string)) + } + return overridesModel, nil +} + +func markVersionAsConsumable(version catalogmanagementv1.Version, context context.Context, meta interface{}) error { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + + consumableVersionOptions := catalogmanagementv1.ConsumableVersionOptions{} + consumableVersionOptions.SetVersionLocID(*version.VersionLocator) + + _, err = catalogManagementClient.ConsumableVersionWithContext(context, &consumableVersionOptions) + if err != nil { + return err + } + + return nil +} + +func envVariablesToDeployRequestBodyEnvVariables(envVariables []map[string]interface{}) ([]catalogmanagementv1.DeployRequestBodyEnvironmentVariablesItem, error) { + var modelArr []catalogmanagementv1.DeployRequestBodyEnvironmentVariablesItem + for _, envVar := range envVariables { + model := catalogmanagementv1.DeployRequestBodyEnvironmentVariablesItem{} + if envVar["name"] != nil && envVar["name"].(string) != "" { + model.Name = core.StringPtr(envVar["name"].(string)) + } + if envVar["value"] != nil { + model.Value = envVar["value"] + } + if envVar["secure"] != nil { + model.Secure = core.BoolPtr(envVar["secure"].(bool)) + } + modelArr = append(modelArr, model) + } + return modelArr, nil +} + +func schematicsMapToDeployRequestBodySchematics(schematicsMap map[string]interface{}) (catalogmanagementv1.DeployRequestBodySchematics, error) { + model := catalogmanagementv1.DeployRequestBodySchematics{} + if schematicsMap["name"] != nil && schematicsMap["name"].(string) != "" { + model.Name = core.StringPtr(schematicsMap["name"].(string)) + } + if schematicsMap["description"] != nil && schematicsMap["description"].(string) != "" { + model.Description = core.StringPtr(schematicsMap["description"].(string)) + } + if schematicsMap["resource_group_id"] != nil && schematicsMap["resource_group_id"].(string) != "" { + model.ResourceGroupID = core.StringPtr(schematicsMap["resource_group_id"].(string)) + } + if schematicsMap["terraform_version"] != nil && schematicsMap["terraform_version"].(string) != "" { + model.TerraformVersion = core.StringPtr(schematicsMap["terraform_version"].(string)) + } + if schematicsMap["region"] != nil && schematicsMap["region"].(string) != "" { + model.Region = core.StringPtr(schematicsMap["region"].(string)) + } + if schematicsMap["tags"] != nil && len(schematicsMap["tags"].([]interface{})) > 0 { + model.Tags = schematicsMap["name"].([]string) + } + return model, nil +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_version.go b/ibm/service/catalogmanagement/resource_ibm_cm_version.go new file mode 100644 index 000000000..12fcb6533 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_version.go @@ -0,0 +1,3135 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func ResourceIBMCmVersion() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCmVersionCreate, + ReadContext: resourceIBMCmVersionRead, + UpdateContext: resourceIBMCmVersionUpdate, + DeleteContext: resourceIBMCmVersionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "catalog_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Catalog identifier.", + }, + "offering_identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Offering identification.", + }, + "offering_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Offering identification.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Tags array.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "content": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Byte array representing the content to be imported. Only supported for OVA images at this time.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Name of version. Required for virtual server image for VPC.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display name of version. Required for virtual server image for VPC.", + }, + "install_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Install type. Example: instance. Required for virtual server image for VPC.", + }, + "target_kinds": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Deployment target of the content being onboarded. Current valid values are iks, roks, vcenter, power-iaas, terraform, and vpc-x86. Required for virtual server image for VPC.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "format_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Format of content being onboarded. Example: vsi-image. Required for virtual server image for VPC.", + }, + "product_kind": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Optional product kind for the software being onboarded. Valid values are software, module, or solution. Default value is software.", + }, + "import_sha": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "SHA256 fingerprint of the image file. Required for virtual server image for VPC.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "SHA256 fingerprint of the image file. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Semantic version of the software being onboarded. Required for virtual server image for VPC.", + }, + "flavor": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Version Flavor Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name for this flavor.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Label for this flavor.", + }, + "label_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "index": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Order that this flavor should appear when listed for a single version.", + }, + }, + }, + }, + "import_metadata": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Generic data to be included with content being onboarded. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + "metadata": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Generic data to be included with content being onboarded. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version source URL.", + }, + "version_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Version name.", + }, + "terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Terraform version.", + }, + "validated_terraform_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Validated terraform version.", + }, + "vsi_vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "VSI VPC version information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "operating_system": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Operating system included in this image. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dedicated_host_only": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC.", + }, + "vendor": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Vendor of the operating system. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Globally unique name for this operating system Required for virtual server image for VPC.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for this operating system. Required for virtual server image for VPC.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Unique, display-friendly name for the operating system. Required for virtual server image for VPC.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Software family for this operating system. Required for virtual server image for VPC.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Major release version of this operating system. Required for virtual server image for VPC.", + }, + "architecture": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Operating system architecture. Required for virtual server image for VPC.", + }, + }, + }, + }, + "file": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Details for the stored image file. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC.", + }, + }, + }, + }, + "minimum_provisioned_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC.", + }, + "images": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Image operating system. Required for virtual server image for VPC.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic ID of virtual server image. Required for virtual server image for VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Programmatic name of virtual server image. Required for virtual server image for VPC.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Region the virtual server image is available in. Required for virtual server image for VPC.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "working_directory": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Optional - The sub-folder within the specified tgz file that contains the software being onboarded.", + }, + "zipurl": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "URL path to zip location. If not specified, must provide content in the body of this call.", + }, + "target_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The semver value for this new version, if not found in the zip url package content.", + }, + "include_config": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: "Add all possible configuration values to this version when importing.", + }, + "is_vsi": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: "Indicates that the current terraform template is used to install a virtual server image.", + }, + "repotype": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The type of repository containing this version. Valid values are 'public_git' or 'enterprise_git'.", + }, + "x_auth_token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Authentication token used to access the specified zip file.", + }, + "rev": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloudant revision.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version's CRN.", + }, + "created": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was created.", + }, + "updated": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time this version was last updated.", + }, + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Catalog ID.", + }, + "kind_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kind ID.", + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's repo URL.", + }, + "source_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Content's source URL (e.g git repo).", + }, + "tgz_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "File used to on-board this version.", + }, + "configuration": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of user solicited overrides.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Configuration key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Value type (string, boolean, int).", + }, + // "default_value": &schema.Schema{ + // Type: schema.TypeMap, + // Optional: true, + // Description: "The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`.", + // }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Display name for configuration type.", + }, + "value_constraint": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Constraint associated with value, e.g., for string type - regx:[a-z].", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Key description.", + }, + "required": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Is key required to install.", + }, + "options": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of options of type.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Hide values.", + }, + "custom_config": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Render type.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "ID of the widget type.", + }, + "grouping": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment).", + }, + "original_grouping": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Original grouping type for this configuration (3 types - Target, Resource, and Deployment).", + }, + "grouping_index": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Determines the order that this configuration item shows in that particular grouping.", + }, + "config_constraints": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Map of constraint parameters that will be passed to the custom widget.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "associations": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "List of parameters that are associated with this configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameters": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Parameters for this association.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of this parameter.", + }, + "options_refresh": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Refresh options.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "type_metadata": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The original type, as found in the source being onboarded.", + }, + }, + }, + }, + "outputs": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of output values for this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Output key.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Output description.", + }, + }, + }, + }, + "iam_permissions": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of IAM permissions that are required to consume this version.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Service name.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources for this permission.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource description.", + }, + "role_crns": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Role CRNs for this permission.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "validation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Validation response.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "validated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of last successful validation.", + }, + "requested": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of last validation was requested.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Current validation state - , in_progress, valid, invalid, expired.", + }, + "last_operation": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Last operation (e.g. submit_deployment, generate_installer, install_offering.", + }, + "target": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Any message needing to be conveyed as part of the validation job.", + }, + }, + }, + }, + "required_resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Resource requirments for installation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of requirement.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value.", + }, + }, + }, + }, + "single_instance": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Denotes if single instance can be deployed to a given cluster.", + }, + "install": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Script information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "pre_install": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Optional pre-install instructions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instructions": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version.", + }, + "instructions_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that needs to be run post any pre-condition script.", + }, + "script_permission": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional iam permissions that are required on the target cluster to run this script.", + }, + "delete_script": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional script that if run will remove the installed version.", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional value indicating if this script is scoped to a namespace or the entire cluster.", + }, + }, + }, + }, + "entitlement": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Entitlement license info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Provider name.", + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Provider ID.", + }, + "product_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Product ID.", + }, + "part_numbers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Image repository name.", + }, + }, + }, + }, + "licenses": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of licenses the product was built with.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "License ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "license name.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "type of license e.g., Apache xxx.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL for the license text.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "License description.", + }, + }, + }, + }, + "image_manifest_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If set, denotes a url to a YAML file with list of container images used by this version.", + }, + "deprecated": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "read only field, indicating if this version is deprecated.", + }, + "package_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of the package used to create this version.", + }, + "state": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Offering state.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "current_entered": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of current request.", + }, + "pending": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + "pending_requested": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Date and time of pending request.", + }, + "previous": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "one of: new, validated, account-published, ibm-published, public-published.", + }, + }, + }, + }, + "version_locator": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dotted value of `catalogID`.`versionID`.", + }, + "long_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Long description for version.", + }, + "long_description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "image_pull_key_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the image pull key to use from Offering.ImagePullKeys.", + }, + "solution_info": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Version Solution Information. Only supported for Product kind Solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "architecture_diagrams": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Architecture diagrams for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "diagram": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering Media information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item.", + }, + "api_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "CM API specific URL of the specified media item.", + }, + "url_proxy": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Offering URL proxy information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URL of the specified media item being proxied.", + }, + "sha": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "SHA256 fingerprint of image.", + }, + }, + }, + }, + "caption": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Caption for this media item.", + }, + "caption_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type of this media item.", + }, + "thumbnail_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Thumbnail URL for this media item.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description of this diagram.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "features": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Features - titles only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "title": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Heading.", + }, + "title_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Feature description.", + }, + "description_i18n": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "A map of translated strings, by language code.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "cost_estimate": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost estimate definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost estimate version.", + }, + "currency": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost estimate currency.", + }, + "projects": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost estimate projects.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Project name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Project metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "past_breakdown": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "breakdown": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "diff": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost breakdown definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_c_ost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource name.", + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Resource metadata.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Monthly cost.", + }, + "cost_components": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Cost components.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component name.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component unit.", + }, + "hourly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly quantity.", + }, + "monthly_quantity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly quantity.", + }, + "price": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component price.", + }, + "hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component hourly cost.", + }, + "monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Cost component monthly cist.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "summary": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Cost summary definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "total_detected_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total detected resources.", + }, + "total_supported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total supported resources.", + }, + "total_unsupported_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total unsupported resources.", + }, + "total_usage_based_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total usage based resources.", + }, + "total_no_price_resources": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Total no price resources.", + }, + "unsupported_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "Unsupported resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "no_price_resource_counts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Description: "No price resource counts.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total hourly cost.", + }, + "total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Total monthly cost.", + }, + "past_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Past total hourly cost.", + }, + "past_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Past total monthly cost.", + }, + "diff_total_hourly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Difference in total hourly cost.", + }, + "diff_total_monthly_cost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Difference in total monthly cost.", + }, + "time_generated": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "When this estimate was generated.", + }, + }, + }, + }, + "dependencies": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Dependencies for this solution.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - If not specified, assumes the Public Catalog.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - Offering ID - not required if name is set.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Optional - Programmatic Offering name.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Required - Semver value or range.", + }, + "flavors": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Optional - List of dependent flavors in the specified range.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "is_consumable": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Is the version able to be shared.", + }, + "version_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Unique ID.", + }, + }, + } +} + +func resourceIBMCmVersionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + importOfferingVersionOptions := &catalogmanagementv1.ImportOfferingVersionOptions{} + + importOfferingVersionOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + importOfferingVersionOptions.SetOfferingID(d.Get("offering_identifier").(string)) + if _, ok := d.GetOk("tags"); ok { + importOfferingVersionOptions.SetTags(SIToSS(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("content"); ok { + importOfferingVersionOptions.SetContent([]byte(d.Get("content").(string))) + } + if _, ok := d.GetOk("name"); ok { + importOfferingVersionOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("label"); ok { + importOfferingVersionOptions.SetLabel(d.Get("label").(string)) + } + if _, ok := d.GetOk("install_kind"); ok { + importOfferingVersionOptions.SetInstallKind(d.Get("install_kind").(string)) + } + if _, ok := d.GetOk("target_kinds"); ok { + importOfferingVersionOptions.SetTargetKinds(SIToSS(d.Get("target_kinds").([]interface{}))) + } + if _, ok := d.GetOk("format_kind"); ok { + importOfferingVersionOptions.SetFormatKind(d.Get("format_kind").(string)) + } + if _, ok := d.GetOk("product_kind"); ok { + importOfferingVersionOptions.SetProductKind(d.Get("product_kind").(string)) + } + if _, ok := d.GetOk("import_sha"); ok { + importOfferingVersionOptions.SetSha(d.Get("import_sha").(string)) + } + if _, ok := d.GetOk("flavor"); ok { + flavorModel, err := resourceIBMCmVersionMapToFlavor(d.Get("flavor.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + importOfferingVersionOptions.SetFlavor(flavorModel) + } + if _, ok := d.GetOk("import_metadata"); ok { + metadataModel, err := resourceIBMCmVersionMapToImportOfferingBodyMetadata(d.Get("import_metadata.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + importOfferingVersionOptions.SetMetadata(metadataModel) + } + if _, ok := d.GetOk("working_directory"); ok { + importOfferingVersionOptions.SetWorkingDirectory(d.Get("working_directory").(string)) + } + if _, ok := d.GetOk("zipurl"); ok { + importOfferingVersionOptions.SetZipurl(d.Get("zipurl").(string)) + } + if _, ok := d.GetOk("target_version"); ok { + importOfferingVersionOptions.SetTargetVersion(d.Get("target_version").(string)) + importOfferingVersionOptions.SetVersion(d.Get("target_version").(string)) + } + if _, ok := d.GetOk("include_config"); ok { + importOfferingVersionOptions.SetIncludeConfig(d.Get("include_config").(bool)) + } + if _, ok := d.GetOk("is_vsi"); ok { + importOfferingVersionOptions.SetIsVsi(d.Get("is_vsi").(bool)) + } + if _, ok := d.GetOk("repotype"); ok { + importOfferingVersionOptions.SetRepotype(d.Get("repotype").(string)) + } + if _, ok := d.GetOk("x_auth_token"); ok { + importOfferingVersionOptions.SetXAuthToken(d.Get("x_auth_token").(string)) + } + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + getOfferingOptions.SetCatalogIdentifier(d.Get("catalog_identifier").(string)) + getOfferingOptions.SetOfferingID(d.Get("offering_identifier").(string)) + oldOffering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + offering, response, err := catalogManagementClient.ImportOfferingVersionWithContext(context, importOfferingVersionOptions) + if err != nil { + log.Printf("[DEBUG] ImportOfferingVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ImportOfferingVersionWithContext failed %s\n%s", err, response)) + } + + activeVersionID, err := getVersionFromOffering(*oldOffering, *offering) + if err != nil { + log.Printf("[DEBUG] getVersionFromOffering failed %s\n", err) + return diag.FromErr(fmt.Errorf("getVersionFromOffering failed %s\n", err)) + } + + var activeVersion catalogmanagementv1.Version + for _, k := range offering.Kinds { + for _, v := range k.Versions { + if v.ID == &activeVersionID { + activeVersion = v + } + } + } + + d.SetId(fmt.Sprintf("%s/%s", *offering.CatalogID, activeVersionID)) + + updateOfferingOptions := &catalogmanagementv1.UpdateOfferingOptions{} + + updateOfferingOptions.SetCatalogIdentifier(*offering.CatalogID) + updateOfferingOptions.SetOfferingID(*offering.ID) + ifMatch := fmt.Sprintf("\"%s\"", *offering.Rev) + updateOfferingOptions.IfMatch = &ifMatch + + hasChange := false + method := "replace" + + // find kind and version index + var kindIndex int + var versionIndex int + for i, kind := range offering.Kinds { + if kind.ID == activeVersion.KindID { + kindIndex = i + + if kind.Versions != nil && len(kind.Versions) > 0 { + for j, version := range kind.Versions { + if version.ID == activeVersion.ID { + versionIndex = j + } + } + } + } + } + + pathToVersion := fmt.Sprintf("/kinds/%d/versions/%d", kindIndex, versionIndex) + + if _, ok := d.GetOk("flavor"); ok { + if activeVersion.Flavor == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/flavor", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("flavor.0"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("tags"); ok { + if activeVersion.Tags == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/tags", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("tags"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("configuration"); ok { + if activeVersion.Configuration == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/configuration", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("configuration"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("iam_permissions"); ok { + if activeVersion.IamPermissions == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/iam_permissions", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("iam_permissions"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("install"); ok { + if activeVersion.Install == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/install", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("install.0"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("pre_install"); ok { + if activeVersion.PreInstall == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/pre_install", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("pre_install"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("licenses"); ok { + if activeVersion.Licenses == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/licenses", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("licenses"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("solution_info"); ok { + if activeVersion.SolutionInfo == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/solution_info", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("solution_info"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if _, ok := d.GetOk("is_consumable"); ok { + if activeVersion.IsConsumable == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/is_consumable", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("is_consumable"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + + if hasChange { + _, response, err := catalogManagementClient.UpdateOfferingWithContext(context, updateOfferingOptions) + if err != nil { + log.Printf("[DEBUG] UpdateOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateOfferingWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCmVersionRead(context, d, meta) +} + +func resourceIBMCmVersionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + + getVersionOptions.SetVersionLocID(strings.Replace(d.Id(), "/", ".", 1)) + + offering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVersionWithContext failed %s\n%s", err, response)) + } + + version := offering.Kinds[0].Versions[0] + + if err = d.Set("offering_id", version.OfferingID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offering_id: %s", err)) + } + if version.Tags != nil { + if err = d.Set("tags", version.Tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + } + if err = d.Set("sha", version.Sha); err != nil { + return diag.FromErr(fmt.Errorf("Error setting sha: %s", err)) + } + if err = d.Set("version", version.Version); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + if version.Flavor != nil { + flavorMap, err := resourceIBMCmVersionFlavorToMap(version.Flavor) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("flavor", []map[string]interface{}{flavorMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting flavor: %s", err)) + } + } + metadata := []map[string]interface{}{} + if version.Metadata != nil { + var modelMapVSI map[string]interface{} + if version.Metadata["vsi_vpc"] != nil { + modelMapVSI, err = dataSourceIBMCmVersionMetadataVSIToMap(version.Metadata["vsi_vpc"].(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + } + convertedMap := make(map[string]interface{}, len(version.Metadata)) + for k, v := range version.Metadata { + if k == "vsi_vpc" { + convertedMap[k] = []map[string]interface{}{modelMapVSI} + } else { + convertedMap[k] = v + } + } + metadata = append(metadata, convertedMap) + } + if err = d.Set("metadata", metadata); err != nil { + return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + } + if err = d.Set("rev", version.Rev); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + } + if err = d.Set("crn", version.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("created", flex.DateTimeToString(version.Created)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created: %s", err)) + } + if err = d.Set("updated", flex.DateTimeToString(version.Updated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated: %s", err)) + } + if err = d.Set("catalog_id", version.CatalogID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting catalog_id: %s", err)) + } + if err = d.Set("kind_id", version.KindID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting kind_id: %s", err)) + } + if err = d.Set("repo_url", version.RepoURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting repo_url: %s", err)) + } + if err = d.Set("source_url", version.SourceURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_url: %s", err)) + } + if err = d.Set("tgz_url", version.TgzURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tgz_url: %s", err)) + } + configuration := []map[string]interface{}{} + if version.Configuration != nil { + for _, configurationItem := range version.Configuration { + configurationItemMap, err := resourceIBMCmVersionConfigurationToMap(&configurationItem) + if err != nil { + return diag.FromErr(err) + } + configuration = append(configuration, configurationItemMap) + } + } + if err = d.Set("configuration", configuration); err != nil { + return diag.FromErr(fmt.Errorf("Error setting configuration: %s", err)) + } + outputs := []map[string]interface{}{} + if version.Outputs != nil { + for _, outputsItem := range version.Outputs { + outputsItemMap, err := resourceIBMCmVersionOutputToMap(&outputsItem) + if err != nil { + return diag.FromErr(err) + } + outputs = append(outputs, outputsItemMap) + } + } + if err = d.Set("outputs", outputs); err != nil { + return diag.FromErr(fmt.Errorf("Error setting outputs: %s", err)) + } + iamPermissions := []map[string]interface{}{} + if version.IamPermissions != nil { + for _, iamPermissionsItem := range version.IamPermissions { + iamPermissionsItemMap, err := resourceIBMCmVersionIamPermissionToMap(&iamPermissionsItem) + if err != nil { + return diag.FromErr(err) + } + iamPermissions = append(iamPermissions, iamPermissionsItemMap) + } + } + if err = d.Set("iam_permissions", iamPermissions); err != nil { + return diag.FromErr(fmt.Errorf("Error setting iam_permissions: %s", err)) + } + if version.Validation != nil { + validationMap, err := resourceIBMCmVersionValidationToMap(version.Validation) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("validation", []map[string]interface{}{validationMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting validation: %s", err)) + } + } + requiredResources := []map[string]interface{}{} + if version.RequiredResources != nil { + for _, requiredResourcesItem := range version.RequiredResources { + requiredResourcesItemMap, err := resourceIBMCmVersionResourceToMap(&requiredResourcesItem) + if err != nil { + return diag.FromErr(err) + } + requiredResources = append(requiredResources, requiredResourcesItemMap) + } + } + if err = d.Set("required_resources", requiredResources); err != nil { + return diag.FromErr(fmt.Errorf("Error setting required_resources: %s", err)) + } + if err = d.Set("single_instance", version.SingleInstance); err != nil { + return diag.FromErr(fmt.Errorf("Error setting single_instance: %s", err)) + } + if version.Install != nil { + installMap, err := resourceIBMCmVersionScriptToMap(version.Install) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("install", []map[string]interface{}{installMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting install: %s", err)) + } + } + preInstall := []map[string]interface{}{} + if version.PreInstall != nil { + for _, preInstallItem := range version.PreInstall { + preInstallItemMap, err := resourceIBMCmVersionScriptToMap(&preInstallItem) + if err != nil { + return diag.FromErr(err) + } + preInstall = append(preInstall, preInstallItemMap) + } + } + if err = d.Set("pre_install", preInstall); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pre_install: %s", err)) + } + if version.Entitlement != nil { + entitlementMap, err := resourceIBMCmVersionVersionEntitlementToMap(version.Entitlement) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("entitlement", []map[string]interface{}{entitlementMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting entitlement: %s", err)) + } + } + licenses := []map[string]interface{}{} + if version.Licenses != nil { + for _, licensesItem := range version.Licenses { + licensesItemMap, err := resourceIBMCmVersionLicenseToMap(&licensesItem) + if err != nil { + return diag.FromErr(err) + } + licenses = append(licenses, licensesItemMap) + } + } + if err = d.Set("licenses", licenses); err != nil { + return diag.FromErr(fmt.Errorf("Error setting licenses: %s", err)) + } + if err = d.Set("image_manifest_url", version.ImageManifestURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_manifest_url: %s", err)) + } + if err = d.Set("deprecated", version.Deprecated); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deprecated: %s", err)) + } + if err = d.Set("package_version", version.PackageVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting package_version: %s", err)) + } + if version.State != nil { + stateMap, err := resourceIBMCmVersionStateToMap(version.State) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("state", []map[string]interface{}{stateMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + } + if err = d.Set("version_locator", version.VersionLocator); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_locator: %s", err)) + } + if err = d.Set("long_description", version.LongDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description: %s", err)) + } + if err = d.Set("long_description_i18n", version.LongDescriptionI18n); err != nil { + return diag.FromErr(fmt.Errorf("Error setting long_description_i18n: %s", err)) + } + if err = d.Set("image_pull_key_name", version.ImagePullKeyName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_pull_key_name: %s", err)) + } + if version.SolutionInfo != nil { + solutionInfoMap, err := resourceIBMCmVersionSolutionInfoToMap(version.SolutionInfo) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("solution_info", []map[string]interface{}{solutionInfoMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting solution_info: %s", err)) + } + } + if err = d.Set("is_consumable", version.IsConsumable); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_consumable: %s", err)) + } + if err = d.Set("version_id", version.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_id: %s", err)) + } + + return nil +} + +func resourceIBMCmVersionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + getVersionOptions.SetVersionLocID(strings.Replace(d.Id(), "/", ".", 1)) + + partialOffering, response, err := catalogManagementClient.GetVersionWithContext(context, getVersionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVersionWithContext failed %s\n%s", err, response)) + } + activeVersion := partialOffering.Kinds[0].Versions[0] + + getOfferingOptions := &catalogmanagementv1.GetOfferingOptions{} + + getOfferingOptions.SetCatalogIdentifier(*partialOffering.CatalogID) + getOfferingOptions.SetOfferingID(*partialOffering.ID) + offering, response, err := catalogManagementClient.GetOfferingWithContext(context, getOfferingOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetOfferingWithContext failed %s\n%s", err, response)) + } + + updateOfferingOptions := &catalogmanagementv1.UpdateOfferingOptions{} + + updateOfferingOptions.SetCatalogIdentifier(*offering.CatalogID) + updateOfferingOptions.SetOfferingID(*offering.ID) + ifMatch := fmt.Sprintf("\"%s\"", *offering.Rev) + updateOfferingOptions.IfMatch = &ifMatch + + hasChange := false + method := "replace" + + // find kind and version index + var kindIndex int + var versionIndex int + for i, kind := range offering.Kinds { + if kind.ID == activeVersion.KindID { + kindIndex = i + + if kind.Versions != nil && len(kind.Versions) > 0 { + for j, version := range kind.Versions { + if version.ID == activeVersion.ID { + versionIndex = j + } + } + } + } + } + + pathToVersion := fmt.Sprintf("/kinds/%d/versions/%d", kindIndex, versionIndex) + + if d.HasChange("flavor") { + if activeVersion.Flavor == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/flavor", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("flavor.0"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("tags") { + if activeVersion.Tags == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/tags", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("tags"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("configuration") { + if activeVersion.Configuration == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/configuration", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("configuration"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("iam_permissions") { + if activeVersion.IamPermissions == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/iam_permissions", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("iam_permissions"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("install") { + if activeVersion.Install == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/install", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("install.0"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("pre_install") { + if activeVersion.PreInstall == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/pre_install", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("pre_install"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("licenses") { + if activeVersion.Licenses == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/licenses", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("licenses"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + if d.HasChange("solution_info") { + if activeVersion.SolutionInfo == nil { + method = "add" + } else { + method = "replace" + } + path := fmt.Sprintf("%s/solution_info", pathToVersion) + update := catalogmanagementv1.JSONPatchOperation{ + Op: &method, + Path: &path, + Value: d.Get("solution_info"), + } + updateOfferingOptions.Updates = append(updateOfferingOptions.Updates, update) + hasChange = true + } + + if hasChange { + _, response, err := catalogManagementClient.UpdateOfferingWithContext(context, updateOfferingOptions) + if err != nil { + log.Printf("[DEBUG] UpdateOfferingWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateOfferingWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCmVersionRead(context, d, meta) +} + +func resourceIBMCmVersionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + + deleteVersionOptions := &catalogmanagementv1.DeleteVersionOptions{} + + deleteVersionOptions.SetVersionLocID(strings.Replace(d.Id(), "/", ".", 1)) + + response, err := catalogManagementClient.DeleteVersionWithContext(context, deleteVersionOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteVersionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCmVersionMapToFlavor(modelMap map[string]interface{}) (*catalogmanagementv1.Flavor, error) { + model := &catalogmanagementv1.Flavor{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["label"] != nil && modelMap["label"].(string) != "" { + model.Label = core.StringPtr(modelMap["label"].(string)) + } + if modelMap["label_i18n"] != nil { + // TODO: handle LabelI18n, map with entry type '' + } + if modelMap["index"] != nil { + model.Index = core.Int64Ptr(int64(modelMap["index"].(int))) + } + return model, nil +} + +func resourceIBMCmVersionMapToImportOfferingBodyMetadata(modelMap map[string]interface{}) (*catalogmanagementv1.ImportOfferingBodyMetadata, error) { + model := &catalogmanagementv1.ImportOfferingBodyMetadata{} + if modelMap["operating_system"] != nil && len(modelMap["operating_system"].([]interface{})) > 0 { + OperatingSystemModel, err := resourceIBMCmVersionMapToImportOfferingBodyMetadataOperatingSystem(modelMap["operating_system"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.OperatingSystem = OperatingSystemModel + } + if modelMap["file"] != nil && len(modelMap["file"].([]interface{})) > 0 { + FileModel, err := resourceIBMCmVersionMapToImportOfferingBodyMetadataFile(modelMap["file"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.File = FileModel + } + if modelMap["minimum_provisioned_size"] != nil { + model.MinimumProvisionedSize = core.Int64Ptr(int64(modelMap["minimum_provisioned_size"].(int))) + } + if modelMap["images"] != nil { + images := []catalogmanagementv1.ImportOfferingBodyMetadataImagesItem{} + for _, imagesItem := range modelMap["images"].([]interface{}) { + imagesItemModel, err := resourceIBMCmVersionMapToImportOfferingBodyMetadataImagesItem(imagesItem.(map[string]interface{})) + if err != nil { + return model, err + } + images = append(images, *imagesItemModel) + } + model.Images = images + } + return model, nil +} + +func resourceIBMCmVersionMapToImportOfferingBodyMetadataOperatingSystem(modelMap map[string]interface{}) (*catalogmanagementv1.ImportOfferingBodyMetadataOperatingSystem, error) { + model := &catalogmanagementv1.ImportOfferingBodyMetadataOperatingSystem{} + if modelMap["dedicated_host_only"] != nil { + model.DedicatedHostOnly = core.BoolPtr(modelMap["dedicated_host_only"].(bool)) + } + if modelMap["vendor"] != nil && modelMap["vendor"].(string) != "" { + model.Vendor = core.StringPtr(modelMap["vendor"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + if modelMap["display_name"] != nil && modelMap["display_name"].(string) != "" { + model.DisplayName = core.StringPtr(modelMap["display_name"].(string)) + } + if modelMap["family"] != nil && modelMap["family"].(string) != "" { + model.Family = core.StringPtr(modelMap["family"].(string)) + } + if modelMap["version"] != nil && modelMap["version"].(string) != "" { + model.Version = core.StringPtr(modelMap["version"].(string)) + } + if modelMap["architecture"] != nil && modelMap["architecture"].(string) != "" { + model.Architecture = core.StringPtr(modelMap["architecture"].(string)) + } + return model, nil +} + +func resourceIBMCmVersionMapToImportOfferingBodyMetadataFile(modelMap map[string]interface{}) (*catalogmanagementv1.ImportOfferingBodyMetadataFile, error) { + model := &catalogmanagementv1.ImportOfferingBodyMetadataFile{} + if modelMap["size"] != nil { + model.Size = core.Int64Ptr(int64(modelMap["size"].(int))) + } + return model, nil +} + +func resourceIBMCmVersionMapToImportOfferingBodyMetadataImagesItem(modelMap map[string]interface{}) (*catalogmanagementv1.ImportOfferingBodyMetadataImagesItem, error) { + model := &catalogmanagementv1.ImportOfferingBodyMetadataImagesItem{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["region"] != nil && modelMap["region"].(string) != "" { + model.Region = core.StringPtr(modelMap["region"].(string)) + } + return model, nil +} + +func resourceIBMCmVersionFlavorToMap(model *catalogmanagementv1.Flavor) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Label != nil { + modelMap["label"] = model.Label + } + if model.LabelI18n != nil { + // TODO: handle LabelI18n of type TypeMap -- container, not list + } + if model.Index != nil { + modelMap["index"] = flex.IntValue(model.Index) + } + return modelMap, nil +} + +func dataSourceIBMCmVersionMetadataVSIToMap(model map[string]interface{}) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + + for k, v := range model { + if k == "operating_system" || k == "file" { + modelMap[k] = []map[string]interface{}{v.(map[string]interface{})} + } else { + modelMap[k] = v + } + } + + return modelMap, nil +} + +func resourceIBMCmVersionImportOfferingBodyMetadataOperatingSystemToMap(model *catalogmanagementv1.ImportOfferingBodyMetadataOperatingSystem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.DedicatedHostOnly != nil { + modelMap["dedicated_host_only"] = model.DedicatedHostOnly + } + if model.Vendor != nil { + modelMap["vendor"] = model.Vendor + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Href != nil { + modelMap["href"] = model.Href + } + if model.DisplayName != nil { + modelMap["display_name"] = model.DisplayName + } + if model.Family != nil { + modelMap["family"] = model.Family + } + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Architecture != nil { + modelMap["architecture"] = model.Architecture + } + return modelMap, nil +} + +func resourceIBMCmVersionImportOfferingBodyMetadataFileToMap(model *catalogmanagementv1.ImportOfferingBodyMetadataFile) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Size != nil { + modelMap["size"] = flex.IntValue(model.Size) + } + return modelMap, nil +} + +func resourceIBMCmVersionImportOfferingBodyMetadataImagesItemToMap(model *catalogmanagementv1.ImportOfferingBodyMetadataImagesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Region != nil { + modelMap["region"] = model.Region + } + return modelMap, nil +} + +func resourceIBMCmVersionConfigurationToMap(model *catalogmanagementv1.Configuration) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = model.Key + } + if model.Type != nil { + modelMap["type"] = model.Type + } + // if model.DefaultValue != nil { + // modelMap["default_value"] = model.DefaultValue + // } + if model.DisplayName != nil { + modelMap["display_name"] = model.DisplayName + } + if model.ValueConstraint != nil { + modelMap["value_constraint"] = model.ValueConstraint + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Required != nil { + modelMap["required"] = model.Required + } + if model.Options != nil { + options := []map[string]interface{}{} + for _, optionsItem := range model.Options { + options = append(options, optionsItem.(map[string]interface{})) + } + modelMap["options"] = options + } + if model.Hidden != nil { + modelMap["hidden"] = model.Hidden + } + if model.CustomConfig != nil { + customConfigMap, err := resourceIBMCmVersionRenderTypeToMap(model.CustomConfig) + if err != nil { + return modelMap, err + } + modelMap["custom_config"] = []map[string]interface{}{customConfigMap} + } + if model.TypeMetadata != nil { + modelMap["type_metadata"] = model.TypeMetadata + } + return modelMap, nil +} + +func resourceIBMCmVersionRenderTypeToMap(model *catalogmanagementv1.RenderType) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Grouping != nil { + modelMap["grouping"] = model.Grouping + } + if model.OriginalGrouping != nil { + modelMap["original_grouping"] = model.OriginalGrouping + } + if model.GroupingIndex != nil { + modelMap["grouping_index"] = flex.IntValue(model.GroupingIndex) + } + if model.ConfigConstraints != nil { + // TODO: handle ConfigConstraints of type TypeMap -- container, not list + } + if model.Associations != nil { + associationsMap, err := resourceIBMCmVersionRenderTypeAssociationsToMap(model.Associations) + if err != nil { + return modelMap, err + } + modelMap["associations"] = []map[string]interface{}{associationsMap} + } + return modelMap, nil +} + +func resourceIBMCmVersionRenderTypeAssociationsToMap(model *catalogmanagementv1.RenderTypeAssociations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Parameters != nil { + parameters := []map[string]interface{}{} + for _, parametersItem := range model.Parameters { + parametersItemMap, err := resourceIBMCmVersionRenderTypeAssociationsParametersItemToMap(¶metersItem) + if err != nil { + return modelMap, err + } + parameters = append(parameters, parametersItemMap) + } + modelMap["parameters"] = parameters + } + return modelMap, nil +} + +func resourceIBMCmVersionRenderTypeAssociationsParametersItemToMap(model *catalogmanagementv1.RenderTypeAssociationsParametersItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.OptionsRefresh != nil { + modelMap["options_refresh"] = model.OptionsRefresh + } + return modelMap, nil +} + +func resourceIBMCmVersionOutputToMap(model *catalogmanagementv1.Output) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = model.Key + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmVersionIamPermissionToMap(model *catalogmanagementv1.IamPermission) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ServiceName != nil { + modelMap["service_name"] = model.ServiceName + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := resourceIBMCmVersionIamResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func resourceIBMCmVersionIamResourceToMap(model *catalogmanagementv1.IamResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.RoleCrns != nil { + modelMap["role_crns"] = model.RoleCrns + } + return modelMap, nil +} + +func resourceIBMCmVersionValidationToMap(model *catalogmanagementv1.Validation) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Validated != nil { + modelMap["validated"] = model.Validated.String() + } + if model.Requested != nil { + modelMap["requested"] = model.Requested.String() + } + if model.State != nil { + modelMap["state"] = model.State + } + if model.LastOperation != nil { + modelMap["last_operation"] = model.LastOperation + } + if model.Target != nil { + // TODO: handle Target of type TypeMap -- container, not list + } + if model.Message != nil { + modelMap["message"] = model.Message + } + return modelMap, nil +} + +func resourceIBMCmVersionResourceToMap(model *catalogmanagementv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Value != nil { + modelMap["value"] = model.Value + } + return modelMap, nil +} + +func resourceIBMCmVersionScriptToMap(model *catalogmanagementv1.Script) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Instructions != nil { + modelMap["instructions"] = model.Instructions + } + if model.InstructionsI18n != nil { + // TODO: handle InstructionsI18n of type TypeMap -- container, not list + } + if model.Script != nil { + modelMap["script"] = model.Script + } + if model.ScriptPermission != nil { + modelMap["script_permission"] = model.ScriptPermission + } + if model.DeleteScript != nil { + modelMap["delete_script"] = model.DeleteScript + } + if model.Scope != nil { + modelMap["scope"] = model.Scope + } + return modelMap, nil +} + +func resourceIBMCmVersionVersionEntitlementToMap(model *catalogmanagementv1.VersionEntitlement) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ProviderName != nil { + modelMap["provider_name"] = model.ProviderName + } + if model.ProviderID != nil { + modelMap["provider_id"] = model.ProviderID + } + if model.ProductID != nil { + modelMap["product_id"] = model.ProductID + } + if model.PartNumbers != nil { + modelMap["part_numbers"] = model.PartNumbers + } + if model.ImageRepoName != nil { + modelMap["image_repo_name"] = model.ImageRepoName + } + return modelMap, nil +} + +func resourceIBMCmVersionLicenseToMap(model *catalogmanagementv1.License) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmVersionStateToMap(model *catalogmanagementv1.State) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Current != nil { + modelMap["current"] = model.Current + } + if model.CurrentEntered != nil { + modelMap["current_entered"] = model.CurrentEntered.String() + } + if model.Pending != nil { + modelMap["pending"] = model.Pending + } + if model.PendingRequested != nil { + modelMap["pending_requested"] = model.PendingRequested.String() + } + if model.Previous != nil { + modelMap["previous"] = model.Previous + } + return modelMap, nil +} + +func resourceIBMCmVersionDeprecatePendingToMap(model *catalogmanagementv1.DeprecatePending) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.DeprecateDate != nil { + modelMap["deprecate_date"] = model.DeprecateDate.String() + } + if model.DeprecateState != nil { + modelMap["deprecate_state"] = model.DeprecateState + } + if model.Description != nil { + modelMap["description"] = model.Description + } + return modelMap, nil +} + +func resourceIBMCmVersionSolutionInfoToMap(model *catalogmanagementv1.SolutionInfo) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ArchitectureDiagrams != nil { + architectureDiagrams := []map[string]interface{}{} + for _, architectureDiagramsItem := range model.ArchitectureDiagrams { + architectureDiagramsItemMap, err := resourceIBMCmVersionArchitectureDiagramToMap(&architectureDiagramsItem) + if err != nil { + return modelMap, err + } + architectureDiagrams = append(architectureDiagrams, architectureDiagramsItemMap) + } + modelMap["architecture_diagrams"] = architectureDiagrams + } + if model.Features != nil { + features := []map[string]interface{}{} + for _, featuresItem := range model.Features { + featuresItemMap, err := resourceIBMCmVersionFeatureToMap(&featuresItem) + if err != nil { + return modelMap, err + } + features = append(features, featuresItemMap) + } + modelMap["features"] = features + } + if model.CostEstimate != nil { + costEstimateMap, err := resourceIBMCmVersionCostEstimateToMap(model.CostEstimate) + if err != nil { + return modelMap, err + } + modelMap["cost_estimate"] = []map[string]interface{}{costEstimateMap} + } + if model.Dependencies != nil { + dependencies := []map[string]interface{}{} + for _, dependenciesItem := range model.Dependencies { + dependenciesItemMap, err := resourceIBMCmVersionDependencyToMap(&dependenciesItem) + if err != nil { + return modelMap, err + } + dependencies = append(dependencies, dependenciesItemMap) + } + modelMap["dependencies"] = dependencies + } + return modelMap, nil +} + +func resourceIBMCmVersionArchitectureDiagramToMap(model *catalogmanagementv1.ArchitectureDiagram) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Diagram != nil { + diagramMap, err := resourceIBMCmVersionMediaItemToMap(model.Diagram) + if err != nil { + return modelMap, err + } + modelMap["diagram"] = []map[string]interface{}{diagramMap} + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmVersionMediaItemToMap(model *catalogmanagementv1.MediaItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.APIURL != nil { + modelMap["api_url"] = model.APIURL + } + if model.URLProxy != nil { + urlProxyMap, err := resourceIBMCmVersionURLProxyToMap(model.URLProxy) + if err != nil { + return modelMap, err + } + modelMap["url_proxy"] = []map[string]interface{}{urlProxyMap} + } + if model.Caption != nil { + modelMap["caption"] = model.Caption + } + if model.CaptionI18n != nil { + // TODO: handle CaptionI18n of type TypeMap -- container, not list + } + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.ThumbnailURL != nil { + modelMap["thumbnail_url"] = model.ThumbnailURL + } + return modelMap, nil +} + +func resourceIBMCmVersionURLProxyToMap(model *catalogmanagementv1.URLProxy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Sha != nil { + modelMap["sha"] = model.Sha + } + return modelMap, nil +} + +func resourceIBMCmVersionFeatureToMap(model *catalogmanagementv1.Feature) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Title != nil { + modelMap["title"] = model.Title + } + if model.TitleI18n != nil { + // TODO: handle TitleI18n of type TypeMap -- container, not list + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.DescriptionI18n != nil { + // TODO: handle DescriptionI18n of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmVersionCostEstimateToMap(model *catalogmanagementv1.CostEstimate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Currency != nil { + modelMap["currency"] = model.Currency + } + if model.Projects != nil { + projects := []map[string]interface{}{} + for _, projectsItem := range model.Projects { + projectsItemMap, err := resourceIBMCmVersionProjectToMap(&projectsItem) + if err != nil { + return modelMap, err + } + projects = append(projects, projectsItemMap) + } + modelMap["projects"] = projects + } + if model.Summary != nil { + summaryMap, err := resourceIBMCmVersionCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = model.TotalHourlyCost + } + if model.TotalMonthlyCost != nil { + modelMap["total_monthly_cost"] = model.TotalMonthlyCost + } + if model.PastTotalHourlyCost != nil { + modelMap["past_total_hourly_cost"] = model.PastTotalHourlyCost + } + if model.PastTotalMonthlyCost != nil { + modelMap["past_total_monthly_cost"] = model.PastTotalMonthlyCost + } + if model.DiffTotalHourlyCost != nil { + modelMap["diff_total_hourly_cost"] = model.DiffTotalHourlyCost + } + if model.DiffTotalMonthlyCost != nil { + modelMap["diff_total_monthly_cost"] = model.DiffTotalMonthlyCost + } + if model.TimeGenerated != nil { + modelMap["time_generated"] = model.TimeGenerated.String() + } + return modelMap, nil +} + +func resourceIBMCmVersionProjectToMap(model *catalogmanagementv1.Project) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.PastBreakdown != nil { + pastBreakdownMap, err := resourceIBMCmVersionCostBreakdownToMap(model.PastBreakdown) + if err != nil { + return modelMap, err + } + modelMap["past_breakdown"] = []map[string]interface{}{pastBreakdownMap} + } + if model.Breakdown != nil { + breakdownMap, err := resourceIBMCmVersionCostBreakdownToMap(model.Breakdown) + if err != nil { + return modelMap, err + } + modelMap["breakdown"] = []map[string]interface{}{breakdownMap} + } + if model.Diff != nil { + diffMap, err := resourceIBMCmVersionCostBreakdownToMap(model.Diff) + if err != nil { + return modelMap, err + } + modelMap["diff"] = []map[string]interface{}{diffMap} + } + if model.Summary != nil { + summaryMap, err := resourceIBMCmVersionCostSummaryToMap(model.Summary) + if err != nil { + return modelMap, err + } + modelMap["summary"] = []map[string]interface{}{summaryMap} + } + return modelMap, nil +} + +func resourceIBMCmVersionCostBreakdownToMap(model *catalogmanagementv1.CostBreakdown) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalHourlyCost != nil { + modelMap["total_hourly_cost"] = model.TotalHourlyCost + } + if model.TotalMonthlyCOst != nil { + modelMap["total_monthly_c_ost"] = model.TotalMonthlyCOst + } + if model.Resources != nil { + resources := []map[string]interface{}{} + for _, resourcesItem := range model.Resources { + resourcesItemMap, err := resourceIBMCmVersionCostResourceToMap(&resourcesItem) + if err != nil { + return modelMap, err + } + resources = append(resources, resourcesItemMap) + } + modelMap["resources"] = resources + } + return modelMap, nil +} + +func resourceIBMCmVersionCostResourceToMap(model *catalogmanagementv1.CostResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Metadata != nil { + // TODO: handle Metadata of type TypeMap -- container, not list + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = model.MonthlyCost + } + if model.CostComponents != nil { + costComponents := []map[string]interface{}{} + for _, costComponentsItem := range model.CostComponents { + costComponentsItemMap, err := resourceIBMCmVersionCostComponentToMap(&costComponentsItem) + if err != nil { + return modelMap, err + } + costComponents = append(costComponents, costComponentsItemMap) + } + modelMap["cost_components"] = costComponents + } + return modelMap, nil +} + +func resourceIBMCmVersionCostComponentToMap(model *catalogmanagementv1.CostComponent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Unit != nil { + modelMap["unit"] = model.Unit + } + if model.HourlyQuantity != nil { + modelMap["hourly_quantity"] = model.HourlyQuantity + } + if model.MonthlyQuantity != nil { + modelMap["monthly_quantity"] = model.MonthlyQuantity + } + if model.Price != nil { + modelMap["price"] = model.Price + } + if model.HourlyCost != nil { + modelMap["hourly_cost"] = model.HourlyCost + } + if model.MonthlyCost != nil { + modelMap["monthly_cost"] = model.MonthlyCost + } + return modelMap, nil +} + +func resourceIBMCmVersionCostSummaryToMap(model *catalogmanagementv1.CostSummary) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TotalDetectedResources != nil { + modelMap["total_detected_resources"] = flex.IntValue(model.TotalDetectedResources) + } + if model.TotalSupportedResources != nil { + modelMap["total_supported_resources"] = flex.IntValue(model.TotalSupportedResources) + } + if model.TotalUnsupportedResources != nil { + modelMap["total_unsupported_resources"] = flex.IntValue(model.TotalUnsupportedResources) + } + if model.TotalUsageBasedResources != nil { + modelMap["total_usage_based_resources"] = flex.IntValue(model.TotalUsageBasedResources) + } + if model.TotalNoPriceResources != nil { + modelMap["total_no_price_resources"] = flex.IntValue(model.TotalNoPriceResources) + } + if model.UnsupportedResourceCounts != nil { + // TODO: handle UnsupportedResourceCounts of type TypeMap -- container, not list + } + if model.NoPriceResourceCounts != nil { + // TODO: handle NoPriceResourceCounts of type TypeMap -- container, not list + } + return modelMap, nil +} + +func resourceIBMCmVersionDependencyToMap(model *catalogmanagementv1.Dependency) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CatalogID != nil { + modelMap["catalog_id"] = model.CatalogID + } + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Version != nil { + modelMap["version"] = model.Version + } + if model.Flavors != nil { + modelMap["flavors"] = model.Flavors + } + return modelMap, nil +} + +func getVersionFromOffering(oldOffering catalogmanagementv1.Offering, newOffering catalogmanagementv1.Offering) (string, error) { + var oldVersionList []string + var newVersionList []string + + for _, kind := range oldOffering.Kinds { + // oldVersionList = append(oldVersionList, kind.Versions...) + for _, version := range kind.Versions { + oldVersionList = append(oldVersionList, *version.ID) + } + } + + for _, kind := range newOffering.Kinds { + // newVersionList = append(newVersionList, kind.Versions...) + for _, version := range kind.Versions { + newVersionList = append(newVersionList, *version.ID) + } + } + + for _, newVer := range newVersionList { + isOld := false + for _, oldVer := range oldVersionList { + if newVer == oldVer { + isOld = true + break + } + } + if !isOld { + return newVer, nil + } + } + return "", fmt.Errorf("error finding imported version") +} diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_version_test.go b/ibm/service/catalogmanagement/resource_ibm_cm_version_test.go new file mode 100644 index 000000000..310b77aa2 --- /dev/null +++ b/ibm/service/catalogmanagement/resource_ibm_cm_version_test.go @@ -0,0 +1,245 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package catalogmanagement_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" +) + +func TestAccIBMCmVersionBasic(t *testing.T) { + var conf catalogmanagementv1.Version + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmVersionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmVersionConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmVersionExists("ibm_cm_version.cm_version", conf), + ), + }, + }, + }) +} + +func TestAccIBMCmVersionSimpleArgs(t *testing.T) { + var conf catalogmanagementv1.Version + zipurl := "https://github.com/IBM-Cloud/terraform-sample/archive/refs/tags/v1.1.0.tar.gz" + targetVersion := "2.2.2" + includeConfig := "true" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmVersionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmVersionSimpleConfig(zipurl, targetVersion, includeConfig), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmVersionExists("ibm_cm_version.cm_version", conf), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "zipurl", zipurl), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "target_version", targetVersion), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "include_config", includeConfig), + ), + }, + }, + }) +} + +func TestAccIBMCmVersionVSI(t *testing.T) { + var conf catalogmanagementv1.Version + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + installKind := "instance" + sha := "64245e5f3f1e9c4048b18db3abd1450d4b6f9e263ac1b33df6fc1ae96fcbdebb" + targetVersion := "3.3.3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCmVersionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCmVersionVSIConfig(name, label, installKind, sha, targetVersion), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCmVersionExists("ibm_cm_version.cm_version", conf), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "name", name), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "label", label), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "install_kind", installKind), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "sha", sha), + resource.TestCheckResourceAttr("ibm_cm_version.cm_version", "target_version", targetVersion), + ), + }, + }, + }) +} + +func testAccCheckIBMCmVersionConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_tf_catalog_label_1" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "test_tf_offering_label_1" + name = "test_tf_offering_name_1" + offering_icon_url = "test.url.1" + tags = ["dev_ops"] + } + + resource "ibm_cm_version" "cm_version" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + zipurl = "https://github.com/IBM-Cloud/terraform-sample/archive/refs/tags/v1.1.0.tar.gz" + install {} + } + `) +} + +func testAccCheckIBMCmVersionSimpleConfig(zipurl string, targetVersion string, includeConfig string) string { + return fmt.Sprintf(` + + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_tf_catalog_label_2" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "test_tf_offering_label_2" + name = "test_tf_offering_name_2" + offering_icon_url = "test.url.2" + tags = ["dev_ops"] + } + + resource "ibm_cm_version" "cm_version" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + zipurl = "%s" + target_version = "%s" + include_config = %s + install {} + } + `, zipurl, targetVersion, includeConfig) +} + +func testAccCheckIBMCmVersionVSIConfig(name string, label string, installKind string, sha string, targetVersion string) string { + return fmt.Sprintf(` + + resource "ibm_cm_catalog" "cm_catalog" { + label = "test_tf_catalog_label_3" + kind = "offering" + } + + resource "ibm_cm_offering" "cm_offering" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "test_tf_offering_label_3" + name = "test_tf_offering_name_3" + offering_icon_url = "test.url.2" + tags = ["dev_ops"] + } + + resource "ibm_cm_version" "cm_version" { + name = "%s" + label = "%s" + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + tags = ["virtualservers"] + target_kinds = [ "vpc-x86" ] + install_kind = "%s" + import_sha = "%s" + target_version = "%s" + install {} + + import_metadata { + operating_system { + dedicated_host_only = false + vendor = "CentOS" + name = "centos-7-amd64" + href = "https://us-south-stage01.iaasdev.cloud.ibm.com/v1/operating_systems/centos-7-amd64" + display_name = "CentOS 7.x - Minimal Install (amd64)" + family = "CentOS" + version = "7.x - Minimal Install" + architecture = "amd64" + } + minimum_provisioned_size = 100 + file { + size = 1 + } + images { + id = "r134-7fafcc04-f09c-4959-bed5-f6b655409c7b" + name = "dubee-test-2" + region = "us-south" + } + } + } + `, name, label, installKind, sha, targetVersion) +} + +func testAccCheckIBMCmVersionExists(n string, obj catalogmanagementv1.Version) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + getVersionOptions.SetVersionLocID(strings.Replace(rs.Primary.ID, "/", ".", 1)) + + offering, _, err := catalogManagementClient.GetVersion(getVersionOptions) + version := offering.Kinds[0].Versions[0] + if err != nil { + return err + } + + obj = version + return nil + } +} + +func testAccCheckIBMCmVersionDestroy(s *terraform.State) error { + catalogManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CatalogManagementV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cm_version" { + continue + } + + getVersionOptions := &catalogmanagementv1.GetVersionOptions{} + getVersionOptions.SetVersionLocID(strings.Replace(rs.Primary.ID, "/", ".", 1)) + + // Try to find the key + _, response, err := catalogManagementClient.GetVersion(getVersionOptions) + + if err == nil { + return fmt.Errorf("cm_version still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cm_version (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/catalogmanagement/utils.go b/ibm/service/catalogmanagement/utils.go new file mode 100644 index 000000000..c7ad14495 --- /dev/null +++ b/ibm/service/catalogmanagement/utils.go @@ -0,0 +1,9 @@ +package catalogmanagement + +func SIToSS(i []interface{}) []string { + var ss []string + for _, iface := range i { + ss = append(ss, iface.(string)) + } + return ss +} diff --git a/ibm/service/cdtektonpipeline/README.md b/ibm/service/cdtektonpipeline/README.md new file mode 100644 index 000000000..f24f28c37 --- /dev/null +++ b/ibm/service/cdtektonpipeline/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cd_tekton_pipeline_definition) +* IBM API Docs: [IBM API Docs for ]() +* IBM SDK: [IBM SDK for ](https://github.com/IBM/appconfiguration-go-admin-sdk/tree/master/cdtektonpipelinev2) diff --git a/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline.go b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline.go new file mode 100644 index 000000000..9fa9ef98d --- /dev/null +++ b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline.go @@ -0,0 +1,1126 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func DataSourceIBMCdTektonPipeline() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdTektonPipelineRead, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of current instance.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "String.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Pipeline status.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID.", + }, + "toolchain": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Toolchain object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "UUID.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for the toolchain that contains the Tekton pipeline.", + }, + }, + }, + }, + "definitions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Definition list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scm_source": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "SCM source for Tekton pipeline definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the definition repository.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The path to the definition's yaml files.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the SCM repository service instance.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "UUID.", + }, + }, + }, + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tekton pipeline's environment properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property value.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Options for `single_select` property type. Only needed when using `single_select` property type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Standard RFC 3339 Date Time String.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Standard RFC 3339 Date Time String.", + }, + "triggers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tekton pipeline triggers list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Trigger type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Trigger name.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API URL for interacting with the trigger.", + }, + "event_listener": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID.", + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Trigger properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property value. Can be empty and should be omitted for `single_select` property type.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API URL for interacting with the trigger property.", + }, + }, + }, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Trigger tags array.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the worker. Computed based on the worker ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the worker. Computed based on the worker ID.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "max_concurrent_runs": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "SCM source repository for a Git trigger. Only needed for Git triggers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the repository to which the trigger is listening.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "pattern": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + "hook_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the webhook from the repo. Computed upon creation of the trigger.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the repository service instance.", + }, + }, + }, + }, + "events": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "push": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'push' Git webhook events.", + }, + "pull_request_closed": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'close pull request' Git webhook events.", + }, + "pull_request": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + }, + }, + }, + }, + "cron": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Only needed for timer triggers. Timezone for timer trigger.", + }, + "secret": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret type.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret value, not needed if secret type is `internal_validation`.", + }, + "source": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret location, not needed if secret type is `internal_validation`.", + }, + "key_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret name, not needed if type is `internal_validation`.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + }, + }, + }, + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Webhook URL that can be used to trigger pipeline runs.", + }, + }, + }, + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Default pipeline worker used to run the pipeline.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the worker. Computed based on the worker ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the worker. Computed based on the worker ID.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "runs_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for this pipeline showing the list of pipeline runs.", + }, + "build_number": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs.", + }, + "enable_slack_notifications": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain.", + }, + "enable_partial_cloning": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether this pipeline is enabled.", + }, + }, + } +} + +func dataSourceIBMCdTektonPipelineRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineOptions := &cdtektonpipelinev2.GetTektonPipelineOptions{} + + getTektonPipelineOptions.SetID(d.Get("pipeline_id").(string)) + + tektonPipeline, response, err := cdTektonPipelineClient.GetTektonPipelineWithContext(context, getTektonPipelineOptions) + if err != nil { + log.Printf("[DEBUG] GetTektonPipelineWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getTektonPipelineOptions.ID)) + + if err = d.Set("name", tektonPipeline.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("status", tektonPipeline.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + + if err = d.Set("resource_group_id", tektonPipeline.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + toolchain := []map[string]interface{}{} + if tektonPipeline.Toolchain != nil { + modelMap, err := dataSourceIBMCdTektonPipelineToolchainToMap(tektonPipeline.Toolchain) + if err != nil { + return diag.FromErr(err) + } + toolchain = append(toolchain, modelMap) + } + if err = d.Set("toolchain", toolchain); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain %s", err)) + } + + definitions := []map[string]interface{}{} + if tektonPipeline.Definitions != nil { + for _, modelItem := range tektonPipeline.Definitions { + modelMap, err := dataSourceIBMCdTektonPipelineDefinitionToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + definitions = append(definitions, modelMap) + } + } + if err = d.Set("definitions", definitions); err != nil { + return diag.FromErr(fmt.Errorf("Error setting definitions %s", err)) + } + + properties := []map[string]interface{}{} + if tektonPipeline.Properties != nil { + for _, modelItem := range tektonPipeline.Properties { + modelMap, err := dataSourceIBMCdTektonPipelinePropertyToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + properties = append(properties, modelMap) + } + } + if err = d.Set("properties", properties); err != nil { + return diag.FromErr(fmt.Errorf("Error setting properties %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(tektonPipeline.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(tektonPipeline.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + triggers := []map[string]interface{}{} + if tektonPipeline.Triggers != nil { + for _, modelItem := range tektonPipeline.Triggers { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerToMap(modelItem) + if err != nil { + return diag.FromErr(err) + } + triggers = append(triggers, modelMap) + } + } + if err = d.Set("triggers", triggers); err != nil { + return diag.FromErr(fmt.Errorf("Error setting triggers %s", err)) + } + + worker := []map[string]interface{}{} + if tektonPipeline.Worker != nil { + modelMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(tektonPipeline.Worker) + if err != nil { + return diag.FromErr(err) + } + worker = append(worker, modelMap) + } + if err = d.Set("worker", worker); err != nil { + return diag.FromErr(fmt.Errorf("Error setting worker %s", err)) + } + + if err = d.Set("runs_url", tektonPipeline.RunsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting runs_url: %s", err)) + } + + if err = d.Set("build_number", flex.IntValue(tektonPipeline.BuildNumber)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting build_number: %s", err)) + } + + if err = d.Set("enable_slack_notifications", tektonPipeline.EnableSlackNotifications); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enable_slack_notifications: %s", err)) + } + + if err = d.Set("enable_partial_cloning", tektonPipeline.EnablePartialCloning); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enable_partial_cloning: %s", err)) + } + + if err = d.Set("enabled", tektonPipeline.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + } + + return nil +} + +func dataSourceIBMCdTektonPipelineToolchainToMap(model *cdtektonpipelinev2.Toolchain) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineDefinitionToMap(model *cdtektonpipelinev2.Definition) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ScmSource != nil { + scmSourceMap, err := dataSourceIBMCdTektonPipelineDefinitionScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineDefinitionScmSourceToMap(model *cdtektonpipelinev2.DefinitionScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Branch != nil { + modelMap["branch"] = *model.Branch + } + if model.Tag != nil { + modelMap["tag"] = *model.Tag + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = *model.ServiceInstanceID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelinePropertyToMap(model *cdtektonpipelinev2.Property) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerToMap(model cdtektonpipelinev2.TriggerIntf) (map[string]interface{}, error) { + if _, ok := model.(*cdtektonpipelinev2.TriggerManualTrigger); ok { + return dataSourceIBMCdTektonPipelineTriggerManualTriggerToMap(model.(*cdtektonpipelinev2.TriggerManualTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerScmTrigger); ok { + return dataSourceIBMCdTektonPipelineTriggerScmTriggerToMap(model.(*cdtektonpipelinev2.TriggerScmTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerTimerTrigger); ok { + return dataSourceIBMCdTektonPipelineTriggerTimerTriggerToMap(model.(*cdtektonpipelinev2.TriggerTimerTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerGenericTrigger); ok { + return dataSourceIBMCdTektonPipelineTriggerGenericTriggerToMap(model.(*cdtektonpipelinev2.TriggerGenericTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.Trigger); ok { + modelMap := make(map[string]interface{}) + model := model.(*cdtektonpipelinev2.Trigger) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = *model.EventListener + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := dataSourceIBMCdTektonPipelineTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = *model.MaxConcurrentRuns + } + if model.Disabled != nil { + modelMap["disabled"] = *model.Disabled + } + if model.ScmSource != nil { + scmSourceMap, err := dataSourceIBMCdTektonPipelineTriggerScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + } + if model.Events != nil { + eventsMap, err := dataSourceIBMCdTektonPipelineEventsToMap(model.Events) + if err != nil { + return modelMap, err + } + modelMap["events"] = []map[string]interface{}{eventsMap} + } + if model.Cron != nil { + modelMap["cron"] = *model.Cron + } + if model.Timezone != nil { + modelMap["timezone"] = *model.Timezone + } + if model.Secret != nil { + secretMap, err := dataSourceIBMCdTektonPipelineGenericSecretToMap(model.Secret) + if err != nil { + return modelMap, err + } + modelMap["secret"] = []map[string]interface{}{secretMap} + } + if model.WebhookURL != nil { + modelMap["webhook_url"] = *model.WebhookURL + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized cdtektonpipelinev2.TriggerIntf subtype encountered") + } +} + +func dataSourceIBMCdTektonPipelineTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineWorkerToMap(model *cdtektonpipelinev2.Worker) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerScmSourceToMap(model *cdtektonpipelinev2.TriggerScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Branch != nil { + modelMap["branch"] = *model.Branch + } + if model.Pattern != nil { + modelMap["pattern"] = *model.Pattern + } + if model.BlindConnection != nil { + modelMap["blind_connection"] = *model.BlindConnection + } + if model.HookID != nil { + modelMap["hook_id"] = *model.HookID + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = *model.ServiceInstanceID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineEventsToMap(model *cdtektonpipelinev2.Events) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Push != nil { + modelMap["push"] = *model.Push + } + if model.PullRequestClosed != nil { + modelMap["pull_request_closed"] = *model.PullRequestClosed + } + if model.PullRequest != nil { + modelMap["pull_request"] = *model.PullRequest + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineGenericSecretToMap(model *cdtektonpipelinev2.GenericSecret) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Source != nil { + modelMap["source"] = *model.Source + } + if model.KeyName != nil { + modelMap["key_name"] = *model.KeyName + } + if model.Algorithm != nil { + modelMap["algorithm"] = *model.Algorithm + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerManualTriggerToMap(model *cdtektonpipelinev2.TriggerManualTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = *model.EventListener + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := dataSourceIBMCdTektonPipelineTriggerManualTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = *model.MaxConcurrentRuns + } + if model.Disabled != nil { + modelMap["disabled"] = *model.Disabled + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerManualTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerManualTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerScmTriggerToMap(model *cdtektonpipelinev2.TriggerScmTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = *model.EventListener + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := dataSourceIBMCdTektonPipelineTriggerScmTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = *model.MaxConcurrentRuns + } + if model.Disabled != nil { + modelMap["disabled"] = *model.Disabled + } + if model.ScmSource != nil { + scmSourceMap, err := dataSourceIBMCdTektonPipelineTriggerScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + } + if model.Events != nil { + eventsMap, err := dataSourceIBMCdTektonPipelineEventsToMap(model.Events) + if err != nil { + return modelMap, err + } + modelMap["events"] = []map[string]interface{}{eventsMap} + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerScmTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerScmTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerTimerTriggerToMap(model *cdtektonpipelinev2.TriggerTimerTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = *model.EventListener + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := dataSourceIBMCdTektonPipelineTriggerTimerTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = *model.MaxConcurrentRuns + } + if model.Disabled != nil { + modelMap["disabled"] = *model.Disabled + } + if model.Cron != nil { + modelMap["cron"] = *model.Cron + } + if model.Timezone != nil { + modelMap["timezone"] = *model.Timezone + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerTimerTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerTimerTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerGenericTriggerToMap(model *cdtektonpipelinev2.TriggerGenericTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = *model.EventListener + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := dataSourceIBMCdTektonPipelineTriggerGenericTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := dataSourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = *model.MaxConcurrentRuns + } + if model.Disabled != nil { + modelMap["disabled"] = *model.Disabled + } + if model.Secret != nil { + secretMap, err := dataSourceIBMCdTektonPipelineGenericSecretToMap(model.Secret) + if err != nil { + return modelMap, err + } + modelMap["secret"] = []map[string]interface{}{secretMap} + } + if model.WebhookURL != nil { + modelMap["webhook_url"] = *model.WebhookURL + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerGenericTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerGenericTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_definition.go b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_definition.go new file mode 100644 index 000000000..fff0617be --- /dev/null +++ b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_definition.go @@ -0,0 +1,123 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func DataSourceIBMCdTektonPipelineDefinition() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdTektonPipelineDefinitionRead, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The Tekton pipeline ID.", + }, + "definition_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The definition ID.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "SCM source for Tekton pipeline definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the definition repository.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The path to the definition's yaml files.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the SCM repository service instance.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMCdTektonPipelineDefinitionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineDefinitionOptions := &cdtektonpipelinev2.GetTektonPipelineDefinitionOptions{} + + getTektonPipelineDefinitionOptions.SetPipelineID(d.Get("pipeline_id").(string)) + getTektonPipelineDefinitionOptions.SetDefinitionID(d.Get("definition_id").(string)) + + definition, response, err := cdTektonPipelineClient.GetTektonPipelineDefinitionWithContext(context, getTektonPipelineDefinitionOptions) + if err != nil { + log.Printf("[DEBUG] GetTektonPipelineDefinitionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineDefinitionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getTektonPipelineDefinitionOptions.PipelineID, *getTektonPipelineDefinitionOptions.DefinitionID)) + + scmSource := []map[string]interface{}{} + if definition.ScmSource != nil { + modelMap, err := dataSourceIBMCdTektonPipelineDefinitionDefinitionScmSourceToMap(definition.ScmSource) + if err != nil { + return diag.FromErr(err) + } + scmSource = append(scmSource, modelMap) + } + if err = d.Set("scm_source", scmSource); err != nil { + return diag.FromErr(fmt.Errorf("Error setting scm_source %s", err)) + } + + return nil +} + +func dataSourceIBMCdTektonPipelineDefinitionDefinitionScmSourceToMap(model *cdtektonpipelinev2.DefinitionScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Branch != nil { + modelMap["branch"] = *model.Branch + } + if model.Tag != nil { + modelMap["tag"] = *model.Tag + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = *model.ServiceInstanceID + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_property.go b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_property.go new file mode 100644 index 000000000..b2b08c612 --- /dev/null +++ b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_property.go @@ -0,0 +1,107 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func DataSourceIBMCdTektonPipelineProperty() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdTektonPipelinePropertyRead, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The Tekton pipeline ID.", + }, + "property_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The property name.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property value.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Options for `single_select` property type. Only needed when using `single_select` property type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration.", + }, + }, + } +} + +func dataSourceIBMCdTektonPipelinePropertyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelinePropertyOptions := &cdtektonpipelinev2.GetTektonPipelinePropertyOptions{} + + getTektonPipelinePropertyOptions.SetPipelineID(d.Get("pipeline_id").(string)) + getTektonPipelinePropertyOptions.SetPropertyName(d.Get("property_name").(string)) + + property, response, err := cdTektonPipelineClient.GetTektonPipelinePropertyWithContext(context, getTektonPipelinePropertyOptions) + if err != nil { + log.Printf("[DEBUG] GetTektonPipelinePropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelinePropertyWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getTektonPipelinePropertyOptions.PipelineID, *getTektonPipelinePropertyOptions.PropertyName)) + + if err = d.Set("name", property.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("value", property.Value); err != nil { + return diag.FromErr(fmt.Errorf("Error setting value: %s", err)) + } + + if err = d.Set("type", property.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + if err = d.Set("path", property.Path); err != nil { + return diag.FromErr(fmt.Errorf("Error setting path: %s", err)) + } + + if property.Enum != nil { + if err = d.Set("enum", property.Enum); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enum: %s", err)) + } + } + + return nil +} diff --git a/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger.go b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger.go new file mode 100644 index 000000000..9bbcd160f --- /dev/null +++ b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger.go @@ -0,0 +1,473 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func DataSourceIBMCdTektonPipelineTrigger() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdTektonPipelineTriggerRead, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The Tekton pipeline ID.", + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The trigger ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Trigger type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Trigger name.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API URL for interacting with the trigger.", + }, + "event_listener": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Trigger properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property value. Can be empty and should be omitted for `single_select` property type.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API URL for interacting with the trigger property.", + }, + }, + }, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Trigger tags array.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the worker. Computed based on the worker ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the worker. Computed based on the worker ID.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "max_concurrent_runs": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "SCM source repository for a Git trigger. Only needed for Git triggers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL of the repository to which the trigger is listening.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "pattern": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + "hook_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the webhook from the repo. Computed upon creation of the trigger.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the repository service instance.", + }, + }, + }, + }, + "events": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "push": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'push' Git webhook events.", + }, + "pull_request_closed": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'close pull request' Git webhook events.", + }, + "pull_request": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + }, + }, + }, + }, + "cron": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Only needed for timer triggers. Timezone for timer trigger.", + }, + "secret": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret type.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret value, not needed if secret type is `internal_validation`.", + }, + "source": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret location, not needed if secret type is `internal_validation`.", + }, + "key_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Secret name, not needed if type is `internal_validation`.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + }, + }, + }, + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Webhook URL that can be used to trigger pipeline runs.", + }, + }, + } +} + +func dataSourceIBMCdTektonPipelineTriggerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerOptions := &cdtektonpipelinev2.GetTektonPipelineTriggerOptions{} + + getTektonPipelineTriggerOptions.SetPipelineID(d.Get("pipeline_id").(string)) + getTektonPipelineTriggerOptions.SetTriggerID(d.Get("trigger_id").(string)) + + TriggerIntf, response, err := cdTektonPipelineClient.GetTektonPipelineTriggerWithContext(context, getTektonPipelineTriggerOptions) + if err != nil { + log.Printf("[DEBUG] GetTektonPipelineTriggerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineTriggerWithContext failed %s\n%s", err, response)) + } + trigger := TriggerIntf.(*cdtektonpipelinev2.Trigger) + + d.SetId(fmt.Sprintf("%s/%s", *getTektonPipelineTriggerOptions.PipelineID, *getTektonPipelineTriggerOptions.TriggerID)) + + if err = d.Set("type", trigger.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + if err = d.Set("name", trigger.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("href", trigger.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("event_listener", trigger.EventListener); err != nil { + return diag.FromErr(fmt.Errorf("Error setting event_listener: %s", err)) + } + + if trigger.Tags != nil { + if err = d.Set("tags", trigger.Tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + } + + properties := []map[string]interface{}{} + if trigger.Properties != nil { + for _, modelItem := range trigger.Properties { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerTriggerPropertiesItemToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + properties = append(properties, modelMap) + } + } + if err = d.Set("properties", properties); err != nil { + return diag.FromErr(fmt.Errorf("Error setting properties %s", err)) + } + + worker := []map[string]interface{}{} + if trigger.Worker != nil { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerWorkerToMap(trigger.Worker) + if err != nil { + return diag.FromErr(err) + } + worker = append(worker, modelMap) + } + if err = d.Set("worker", worker); err != nil { + return diag.FromErr(fmt.Errorf("Error setting worker %s", err)) + } + + if err = d.Set("max_concurrent_runs", flex.IntValue(trigger.MaxConcurrentRuns)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting max_concurrent_runs: %s", err)) + } + + if err = d.Set("disabled", trigger.Disabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disabled: %s", err)) + } + + scmSource := []map[string]interface{}{} + if trigger.ScmSource != nil { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerTriggerScmSourceToMap(trigger.ScmSource) + if err != nil { + return diag.FromErr(err) + } + scmSource = append(scmSource, modelMap) + } + if err = d.Set("scm_source", scmSource); err != nil { + return diag.FromErr(fmt.Errorf("Error setting scm_source %s", err)) + } + + events := []map[string]interface{}{} + if trigger.Events != nil { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerEventsToMap(trigger.Events) + if err != nil { + return diag.FromErr(err) + } + events = append(events, modelMap) + } + if err = d.Set("events", events); err != nil { + return diag.FromErr(fmt.Errorf("Error setting events %s", err)) + } + + if err = d.Set("cron", trigger.Cron); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cron: %s", err)) + } + + if err = d.Set("timezone", trigger.Timezone); err != nil { + return diag.FromErr(fmt.Errorf("Error setting timezone: %s", err)) + } + + secret := []map[string]interface{}{} + if trigger.Secret != nil { + modelMap, err := dataSourceIBMCdTektonPipelineTriggerGenericSecretToMap(trigger.Secret) + if err != nil { + return diag.FromErr(err) + } + secret = append(secret, modelMap) + } + if err = d.Set("secret", secret); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret %s", err)) + } + + if err = d.Set("webhook_url", trigger.WebhookURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting webhook_url: %s", err)) + } + + return nil +} + +func dataSourceIBMCdTektonPipelineTriggerTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerWorkerToMap(model *cdtektonpipelinev2.Worker) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerTriggerScmSourceToMap(model *cdtektonpipelinev2.TriggerScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.URL != nil { + modelMap["url"] = *model.URL + } + if model.Branch != nil { + modelMap["branch"] = *model.Branch + } + if model.Pattern != nil { + modelMap["pattern"] = *model.Pattern + } + if model.BlindConnection != nil { + modelMap["blind_connection"] = *model.BlindConnection + } + if model.HookID != nil { + modelMap["hook_id"] = *model.HookID + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = *model.ServiceInstanceID + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerEventsToMap(model *cdtektonpipelinev2.Events) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Push != nil { + modelMap["push"] = *model.Push + } + if model.PullRequestClosed != nil { + modelMap["pull_request_closed"] = *model.PullRequestClosed + } + if model.PullRequest != nil { + modelMap["pull_request"] = *model.PullRequest + } + return modelMap, nil +} + +func dataSourceIBMCdTektonPipelineTriggerGenericSecretToMap(model *cdtektonpipelinev2.GenericSecret) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Source != nil { + modelMap["source"] = *model.Source + } + if model.KeyName != nil { + modelMap["key_name"] = *model.KeyName + } + if model.Algorithm != nil { + modelMap["algorithm"] = *model.Algorithm + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger_property.go b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger_property.go new file mode 100644 index 000000000..c3adc1a18 --- /dev/null +++ b/ibm/service/cdtektonpipeline/data_source_ibm_cd_tekton_pipeline_trigger_property.go @@ -0,0 +1,113 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func DataSourceIBMCdTektonPipelineTriggerProperty() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdTektonPipelineTriggerPropertyRead, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The Tekton pipeline ID.", + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The trigger ID.", + }, + "property_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The property name.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property value. Can be empty and should be omitted for `single_select` property type.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + }, + } +} + +func dataSourceIBMCdTektonPipelineTriggerPropertyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerPropertyOptions := &cdtektonpipelinev2.GetTektonPipelineTriggerPropertyOptions{} + + getTektonPipelineTriggerPropertyOptions.SetPipelineID(d.Get("pipeline_id").(string)) + getTektonPipelineTriggerPropertyOptions.SetTriggerID(d.Get("trigger_id").(string)) + getTektonPipelineTriggerPropertyOptions.SetPropertyName(d.Get("property_name").(string)) + + triggerProperty, response, err := cdTektonPipelineClient.GetTektonPipelineTriggerPropertyWithContext(context, getTektonPipelineTriggerPropertyOptions) + if err != nil { + log.Printf("[DEBUG] GetTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *getTektonPipelineTriggerPropertyOptions.PipelineID, *getTektonPipelineTriggerPropertyOptions.TriggerID, *getTektonPipelineTriggerPropertyOptions.PropertyName)) + + if err = d.Set("name", triggerProperty.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("value", triggerProperty.Value); err != nil { + return diag.FromErr(fmt.Errorf("Error setting value: %s", err)) + } + + if err = d.Set("type", triggerProperty.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + if err = d.Set("path", triggerProperty.Path); err != nil { + return diag.FromErr(fmt.Errorf("Error setting path: %s", err)) + } + + if triggerProperty.Enum != nil { + if err = d.Set("enum", triggerProperty.Enum); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enum: %s", err)) + } + } + + return nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline.go new file mode 100644 index 000000000..886e8a41a --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline.go @@ -0,0 +1,1154 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMCdTektonPipeline() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdTektonPipelineCreate, + ReadContext: resourceIBMCdTektonPipelineRead, + UpdateContext: resourceIBMCdTektonPipelineUpdate, + DeleteContext: resourceIBMCdTektonPipelineDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "enable_slack_notifications": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain.", + }, + "enable_partial_cloning": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work.", + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Worker object containing worker ID only. If omitted the IBM Managed shared workers are used by default.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "String.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "String.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Pipeline status.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID.", + }, + "toolchain": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Toolchain object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "UUID.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The CRN for the toolchain that contains the Tekton pipeline.", + }, + }, + }, + }, + "definitions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Definition list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scm_source": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "SCM source for Tekton pipeline definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "URL of the definition repository.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The path to the definition's yaml files.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the SCM repository service instance.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "UUID.", + }, + }, + }, + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tekton pipeline's environment properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressPipelinePropertyRawSecret, + Description: "Property value.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Options for `single_select` property type. Only needed when using `single_select` property type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Standard RFC 3339 Date Time String.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Standard RFC 3339 Date Time String.", + }, + "triggers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tekton pipeline triggers list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Trigger type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Trigger name.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "API URL for interacting with the trigger.", + }, + "event_listener": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID.", + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Trigger properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressTriggerPropertyRawSecret, + Description: "Property value. Can be empty and should be omitted for `single_select` property type.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "API URL for interacting with the trigger property.", + }, + }, + }, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Trigger tags array.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the worker. Computed based on the worker ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the worker. Computed based on the worker ID.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "max_concurrent_runs": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "SCM source repository for a Git trigger. Only needed for Git triggers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "URL of the repository to which the trigger is listening.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "pattern": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + "hook_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the webhook from the repo. Computed upon creation of the trigger.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the repository service instance.", + }, + }, + }, + }, + "events": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "push": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'push' Git webhook events.", + }, + "pull_request_closed": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'close pull request' Git webhook events.", + }, + "pull_request": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + }, + }, + }, + }, + "cron": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Only needed for timer triggers. Timezone for timer trigger.", + }, + "secret": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Secret type.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressGenericWebhookRawSecret, + Description: "Secret value, not needed if secret type is `internal_validation`.", + }, + "source": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Secret location, not needed if secret type is `internal_validation`.", + }, + "key_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Secret name, not needed if type is `internal_validation`.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + }, + }, + }, + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Webhook URL that can be used to trigger pipeline runs.", + }, + }, + }, + }, + "runs_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URL for this pipeline showing the list of pipeline runs.", + }, + "build_number": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Flag whether this pipeline is enabled.", + }, + }, + } +} + +func resourceIBMCdTektonPipelineCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + createTektonPipelineOptions := &cdtektonpipelinev2.CreateTektonPipelineOptions{} + + if _, ok := d.GetOk("enable_slack_notifications"); ok { + createTektonPipelineOptions.SetEnableSlackNotifications(d.Get("enable_slack_notifications").(bool)) + } + if _, ok := d.GetOk("enable_partial_cloning"); ok { + createTektonPipelineOptions.SetEnablePartialCloning(d.Get("enable_partial_cloning").(bool)) + } + if _, ok := d.GetOk("worker"); ok { + workerModel, err := resourceIBMCdTektonPipelineMapToWorkerWithID(d.Get("worker.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineOptions.SetWorker(workerModel) + } + + if _, ok := d.GetOk("pipeline_id"); ok { + createTektonPipelineOptions.SetID(d.Get("pipeline_id").(string)) + } + tektonPipeline, response, err := cdTektonPipelineClient.CreateTektonPipelineWithContext(context, createTektonPipelineOptions) + if err != nil { + log.Printf("[DEBUG] CreateTektonPipelineWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTektonPipelineWithContext failed %s\n%s", err, response)) + } + + d.SetId(*tektonPipeline.ID) + + return resourceIBMCdTektonPipelineRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineOptions := &cdtektonpipelinev2.GetTektonPipelineOptions{} + + getTektonPipelineOptions.SetID(d.Id()) + + tektonPipeline, response, err := cdTektonPipelineClient.GetTektonPipelineWithContext(context, getTektonPipelineOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTektonPipelineWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("enable_slack_notifications", tektonPipeline.EnableSlackNotifications); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enable_slack_notifications: %s", err)) + } + if err = d.Set("enable_partial_cloning", tektonPipeline.EnablePartialCloning); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enable_partial_cloning: %s", err)) + } + if tektonPipeline.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerWithIDToMap(tektonPipeline.Worker) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("worker", []map[string]interface{}{workerMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting worker: %s", err)) + } + } + if err = d.Set("pipeline_id", tektonPipeline.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pipeline_id: %s", err)) + } + if err = d.Set("name", tektonPipeline.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("status", tektonPipeline.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + if err = d.Set("resource_group_id", tektonPipeline.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + toolchainMap, err := resourceIBMCdTektonPipelineToolchainToMap(tektonPipeline.Toolchain) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("toolchain", []map[string]interface{}{toolchainMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain: %s", err)) + } + definitions := []map[string]interface{}{} + for _, definitionsItem := range tektonPipeline.Definitions { + definitionsItemMap, err := resourceIBMCdTektonPipelineDefinitionToMap(&definitionsItem) + if err != nil { + return diag.FromErr(err) + } + definitions = append(definitions, definitionsItemMap) + } + if err = d.Set("definitions", definitions); err != nil { + return diag.FromErr(fmt.Errorf("Error setting definitions: %s", err)) + } + properties := []map[string]interface{}{} + for _, propertiesItem := range tektonPipeline.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelinePropertyToMap(&propertiesItem) + if err != nil { + return diag.FromErr(err) + } + properties = append(properties, propertiesItemMap) + } + if err = d.Set("properties", properties); err != nil { + return diag.FromErr(fmt.Errorf("Error setting properties: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(tektonPipeline.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(tektonPipeline.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + triggers := []map[string]interface{}{} + for _, triggersItem := range tektonPipeline.Triggers { + triggersItemMap, err := resourceIBMCdTektonPipelineTriggerToMap(triggersItem) + if err != nil { + return diag.FromErr(err) + } + triggers = append(triggers, triggersItemMap) + } + if err = d.Set("triggers", triggers); err != nil { + return diag.FromErr(fmt.Errorf("Error setting triggers: %s", err)) + } + if err = d.Set("runs_url", tektonPipeline.RunsURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting runs_url: %s", err)) + } + if err = d.Set("build_number", flex.IntValue(tektonPipeline.BuildNumber)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting build_number: %s", err)) + } + if err = d.Set("enabled", tektonPipeline.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + } + + return nil +} + +func resourceIBMCdTektonPipelineUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + updateTektonPipelineOptions := &cdtektonpipelinev2.UpdateTektonPipelineOptions{} + + updateTektonPipelineOptions.SetID(d.Id()) + + hasChange := false + + patchVals := &cdtektonpipelinev2.TektonPipelinePatch{} + if d.HasChange("enable_slack_notifications") { + patchVals.EnableSlackNotifications = core.BoolPtr(d.Get("enable_slack_notifications").(bool)) + hasChange = true + } + if d.HasChange("enable_partial_cloning") { + patchVals.EnablePartialCloning = core.BoolPtr(d.Get("enable_partial_cloning").(bool)) + hasChange = true + } + if d.HasChange("worker") { + worker, err := resourceIBMCdTektonPipelineMapToWorkerWithID(d.Get("worker.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchVals.Worker = worker + hasChange = true + } + + if hasChange { + updateTektonPipelineOptions.TektonPipelinePatch, _ = patchVals.AsPatch() + _, response, err := cdTektonPipelineClient.UpdateTektonPipelineWithContext(context, updateTektonPipelineOptions) + if err != nil { + log.Printf("[DEBUG] UpdateTektonPipelineWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateTektonPipelineWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdTektonPipelineRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineOptions := &cdtektonpipelinev2.DeleteTektonPipelineOptions{} + + deleteTektonPipelineOptions.SetID(d.Id()) + + response, err := cdTektonPipelineClient.DeleteTektonPipelineWithContext(context, deleteTektonPipelineOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTektonPipelineWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTektonPipelineWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdTektonPipelineMapToWorkerWithID(modelMap map[string]interface{}) (*cdtektonpipelinev2.WorkerWithID, error) { + model := &cdtektonpipelinev2.WorkerWithID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func resourceIBMCdTektonPipelineWorkerWithIDToMap(model *cdtektonpipelinev2.Worker) (map[string]interface{}, error) { + // TODO we alter cdtektonpipelinev2.WorkerWithID to cdtektonpipelinev2.Worker in func params. Determine why and if we can fix it + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func resourceIBMCdTektonPipelineToolchainToMap(model *cdtektonpipelinev2.Toolchain) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func resourceIBMCdTektonPipelineDefinitionToMap(model *cdtektonpipelinev2.Definition) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + scmSourceMap, err := resourceIBMCdTektonPipelineDefinitionScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + if model.ID != nil { + modelMap["id"] = model.ID + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineDefinitionScmSourceToMap(model *cdtektonpipelinev2.DefinitionScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["url"] = model.URL + if model.Branch != nil { + modelMap["branch"] = model.Branch + } + if model.Tag != nil { + modelMap["tag"] = model.Tag + } + modelMap["path"] = model.Path + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = model.ServiceInstanceID + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelinePropertyToMap(model *cdtektonpipelinev2.Property) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerToMap(model cdtektonpipelinev2.TriggerIntf) (map[string]interface{}, error) { + if _, ok := model.(*cdtektonpipelinev2.TriggerManualTrigger); ok { + return resourceIBMCdTektonPipelineTriggerManualTriggerToMap(model.(*cdtektonpipelinev2.TriggerManualTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerScmTrigger); ok { + return resourceIBMCdTektonPipelineTriggerScmTriggerToMap(model.(*cdtektonpipelinev2.TriggerScmTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerTimerTrigger); ok { + return resourceIBMCdTektonPipelineTriggerTimerTriggerToMap(model.(*cdtektonpipelinev2.TriggerTimerTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.TriggerGenericTrigger); ok { + return resourceIBMCdTektonPipelineTriggerGenericTriggerToMap(model.(*cdtektonpipelinev2.TriggerGenericTrigger)) + } else if _, ok := model.(*cdtektonpipelinev2.Trigger); ok { + modelMap := make(map[string]interface{}) + model := model.(*cdtektonpipelinev2.Trigger) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Href != nil { + modelMap["href"] = model.Href + } + if model.EventListener != nil { + modelMap["event_listener"] = model.EventListener + } + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = flex.IntValue(model.MaxConcurrentRuns) + } + if model.Disabled != nil { + modelMap["disabled"] = model.Disabled + } + if model.ScmSource != nil { + scmSourceMap, err := resourceIBMCdTektonPipelineTriggerScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + } + if model.Events != nil { + eventsMap, err := resourceIBMCdTektonPipelineEventsToMap(model.Events) + if err != nil { + return modelMap, err + } + modelMap["events"] = []map[string]interface{}{eventsMap} + } + if model.Cron != nil { + modelMap["cron"] = model.Cron + } + if model.Timezone != nil { + modelMap["timezone"] = model.Timezone + } + if model.Secret != nil { + secretMap, err := resourceIBMCdTektonPipelineGenericSecretToMap(model.Secret) + if err != nil { + return modelMap, err + } + modelMap["secret"] = []map[string]interface{}{secretMap} + } + if model.WebhookURL != nil { + modelMap["webhook_url"] = model.WebhookURL + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized cdtektonpipelinev2.TriggerIntf subtype encountered") + } +} + +func resourceIBMCdTektonPipelineTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineWorkerToMap(model *cdtektonpipelinev2.Worker) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Type != nil { + modelMap["type"] = model.Type + } + modelMap["id"] = model.ID + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerScmSourceToMap(model *cdtektonpipelinev2.TriggerScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["url"] = model.URL + if model.Branch != nil { + modelMap["branch"] = model.Branch + } + if model.Pattern != nil { + modelMap["pattern"] = model.Pattern + } + if model.BlindConnection != nil { + modelMap["blind_connection"] = model.BlindConnection + } + if model.HookID != nil { + modelMap["hook_id"] = model.HookID + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = model.ServiceInstanceID + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineEventsToMap(model *cdtektonpipelinev2.Events) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Push != nil { + modelMap["push"] = model.Push + } + if model.PullRequestClosed != nil { + modelMap["pull_request_closed"] = model.PullRequestClosed + } + if model.PullRequest != nil { + modelMap["pull_request"] = model.PullRequest + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineGenericSecretToMap(model *cdtektonpipelinev2.GenericSecret) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Source != nil { + modelMap["source"] = model.Source + } + if model.KeyName != nil { + modelMap["key_name"] = model.KeyName + } + if model.Algorithm != nil { + modelMap["algorithm"] = model.Algorithm + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerManualTriggerToMap(model *cdtektonpipelinev2.TriggerManualTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["name"] = model.Name + if model.Href != nil { + modelMap["href"] = model.Href + } + modelMap["event_listener"] = model.EventListener + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerManualTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = flex.IntValue(model.MaxConcurrentRuns) + } + modelMap["disabled"] = model.Disabled + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerManualTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerManualTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerScmTriggerToMap(model *cdtektonpipelinev2.TriggerScmTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["name"] = model.Name + if model.Href != nil { + modelMap["href"] = model.Href + } + modelMap["event_listener"] = model.EventListener + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerScmTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = flex.IntValue(model.MaxConcurrentRuns) + } + modelMap["disabled"] = model.Disabled + if model.ScmSource != nil { + scmSourceMap, err := resourceIBMCdTektonPipelineTriggerScmSourceToMap(model.ScmSource) + if err != nil { + return modelMap, err + } + modelMap["scm_source"] = []map[string]interface{}{scmSourceMap} + } + if model.Events != nil { + eventsMap, err := resourceIBMCdTektonPipelineEventsToMap(model.Events) + if err != nil { + return modelMap, err + } + modelMap["events"] = []map[string]interface{}{eventsMap} + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerScmTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerScmTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerTimerTriggerToMap(model *cdtektonpipelinev2.TriggerTimerTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["name"] = model.Name + if model.Href != nil { + modelMap["href"] = model.Href + } + modelMap["event_listener"] = model.EventListener + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerTimerTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = flex.IntValue(model.MaxConcurrentRuns) + } + modelMap["disabled"] = model.Disabled + if model.Cron != nil { + modelMap["cron"] = model.Cron + } + if model.Timezone != nil { + modelMap["timezone"] = model.Timezone + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerTimerTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerTimerTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerGenericTriggerToMap(model *cdtektonpipelinev2.TriggerGenericTrigger) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["name"] = model.Name + if model.Href != nil { + modelMap["href"] = model.Href + } + modelMap["event_listener"] = model.EventListener + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Properties != nil { + properties := []map[string]interface{}{} + for _, propertiesItem := range model.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerGenericTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return modelMap, err + } + properties = append(properties, propertiesItemMap) + } + modelMap["properties"] = properties + } + if model.Tags != nil { + modelMap["tags"] = model.Tags + } + if model.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineWorkerToMap(model.Worker) + if err != nil { + return modelMap, err + } + modelMap["worker"] = []map[string]interface{}{workerMap} + } + if model.MaxConcurrentRuns != nil { + modelMap["max_concurrent_runs"] = flex.IntValue(model.MaxConcurrentRuns) + } + modelMap["disabled"] = model.Disabled + if model.Secret != nil { + secretMap, err := resourceIBMCdTektonPipelineGenericSecretToMap(model.Secret) + if err != nil { + return modelMap, err + } + modelMap["secret"] = []map[string]interface{}{secretMap} + } + if model.WebhookURL != nil { + modelMap["webhook_url"] = model.WebhookURL + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerGenericTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerGenericTriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_definition.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_definition.go new file mode 100644 index 000000000..1a6926b61 --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_definition.go @@ -0,0 +1,273 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMCdTektonPipelineDefinition() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdTektonPipelineDefinitionCreate, + ReadContext: resourceIBMCdTektonPipelineDefinitionRead, + UpdateContext: resourceIBMCdTektonPipelineDefinitionUpdate, + DeleteContext: resourceIBMCdTektonPipelineDefinitionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_definition", "pipeline_id"), + Description: "The Tekton pipeline ID.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "SCM source for Tekton pipeline definition.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "URL of the definition repository.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "tag": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The path to the definition's yaml files.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the SCM repository service instance.", + }, + }, + }, + }, + "definition_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "UUID.", + }, + }, + } +} + +func ResourceIBMCdTektonPipelineDefinitionValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "pipeline_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z]+$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_tekton_pipeline_definition", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdTektonPipelineDefinitionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + createTektonPipelineDefinitionOptions := &cdtektonpipelinev2.CreateTektonPipelineDefinitionOptions{} + + createTektonPipelineDefinitionOptions.SetPipelineID(d.Get("pipeline_id").(string)) + if _, ok := d.GetOk("scm_source"); ok { + scmSourceModel, err := resourceIBMCdTektonPipelineDefinitionMapToDefinitionScmSource(d.Get("scm_source.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineDefinitionOptions.SetScmSource(scmSourceModel) + } + + definition, response, err := cdTektonPipelineClient.CreateTektonPipelineDefinitionWithContext(context, createTektonPipelineDefinitionOptions) + if err != nil { + log.Printf("[DEBUG] CreateTektonPipelineDefinitionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTektonPipelineDefinitionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createTektonPipelineDefinitionOptions.PipelineID, *definition.ID)) + + return resourceIBMCdTektonPipelineDefinitionRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineDefinitionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineDefinitionOptions := &cdtektonpipelinev2.GetTektonPipelineDefinitionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineDefinitionOptions.SetPipelineID(parts[0]) + getTektonPipelineDefinitionOptions.SetDefinitionID(parts[1]) + + definition, response, err := cdTektonPipelineClient.GetTektonPipelineDefinitionWithContext(context, getTektonPipelineDefinitionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTektonPipelineDefinitionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineDefinitionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("pipeline_id", getTektonPipelineDefinitionOptions.PipelineID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pipeline_id: %s", err)) + } + if definition.ScmSource != nil { + scmSourceMap, err := resourceIBMCdTektonPipelineDefinitionDefinitionScmSourceToMap(definition.ScmSource) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("scm_source", []map[string]interface{}{scmSourceMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting scm_source: %s", err)) + } + } + if err = d.Set("definition_id", definition.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting definition_id: %s", err)) + } + + return nil +} + +func resourceIBMCdTektonPipelineDefinitionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelineDefinitionOptions := &cdtektonpipelinev2.ReplaceTektonPipelineDefinitionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelineDefinitionOptions.SetPipelineID(parts[0]) + replaceTektonPipelineDefinitionOptions.SetDefinitionID(parts[1]) + replaceTektonPipelineDefinitionOptions.SetID(parts[1]) + + hasChange := false + + if d.HasChange("pipeline_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "pipeline_id")) + } + if d.HasChange("scm_source") { + scmSource, err := resourceIBMCdTektonPipelineDefinitionMapToDefinitionScmSource(d.Get("scm_source.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceTektonPipelineDefinitionOptions.SetScmSource(scmSource) + hasChange = true + } + + if hasChange { + _, response, err := cdTektonPipelineClient.ReplaceTektonPipelineDefinitionWithContext(context, replaceTektonPipelineDefinitionOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceTektonPipelineDefinitionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceTektonPipelineDefinitionWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdTektonPipelineDefinitionRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineDefinitionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineDefinitionOptions := &cdtektonpipelinev2.DeleteTektonPipelineDefinitionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineDefinitionOptions.SetPipelineID(parts[0]) + deleteTektonPipelineDefinitionOptions.SetDefinitionID(parts[1]) + + response, err := cdTektonPipelineClient.DeleteTektonPipelineDefinitionWithContext(context, deleteTektonPipelineDefinitionOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTektonPipelineDefinitionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTektonPipelineDefinitionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdTektonPipelineDefinitionMapToDefinitionScmSource(modelMap map[string]interface{}) (*cdtektonpipelinev2.DefinitionScmSource, error) { + model := &cdtektonpipelinev2.DefinitionScmSource{} + model.URL = core.StringPtr(modelMap["url"].(string)) + if modelMap["branch"] != nil && modelMap["branch"].(string) != "" { + model.Branch = core.StringPtr(modelMap["branch"].(string)) + } + if modelMap["tag"] != nil && modelMap["tag"].(string) != "" { + model.Tag = core.StringPtr(modelMap["tag"].(string)) + } + model.Path = core.StringPtr(modelMap["path"].(string)) + if modelMap["service_instance_id"] != nil && modelMap["service_instance_id"].(string) != "" { + model.ServiceInstanceID = core.StringPtr(modelMap["service_instance_id"].(string)) + } + return model, nil +} + +func resourceIBMCdTektonPipelineDefinitionDefinitionScmSourceToMap(model *cdtektonpipelinev2.DefinitionScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["url"] = model.URL + if model.Branch != nil { + modelMap["branch"] = model.Branch + } + if model.Tag != nil { + modelMap["tag"] = model.Tag + } + modelMap["path"] = model.Path + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = model.ServiceInstanceID + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_property.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_property.go new file mode 100644 index 000000000..1530bdbdb --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_property.go @@ -0,0 +1,304 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func ResourceIBMCdTektonPipelineProperty() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdTektonPipelinePropertyCreate, + ReadContext: resourceIBMCdTektonPipelinePropertyRead, + UpdateContext: resourceIBMCdTektonPipelinePropertyUpdate, + DeleteContext: resourceIBMCdTektonPipelinePropertyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_property", "pipeline_id"), + Description: "The Tekton pipeline ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_property", "name"), + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressPipelinePropertyRawSecret, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_property", "value"), + Description: "Property value.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Options for `single_select` property type. Only needed when using `single_select` property type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_property", "type"), + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_property", "path"), + Description: "A dot notation path for `integration` type properties to select a value from the tool integration.", + }, + }, + } +} + +func ResourceIBMCdTektonPipelinePropertyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "pipeline_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z]+$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-zA-Z_.]{1,234}$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "value", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `.`, + MinValueLength: 1, + MaxValueLength: 4096, + }, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "appconfig, integration, secure, single_select, text", + }, + validate.ValidateSchema{ + Identifier: "path", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `.`, + MinValueLength: 1, + MaxValueLength: 4096, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_tekton_pipeline_property", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdTektonPipelinePropertyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + createTektonPipelinePropertiesOptions := &cdtektonpipelinev2.CreateTektonPipelinePropertiesOptions{} + + createTektonPipelinePropertiesOptions.SetPipelineID(d.Get("pipeline_id").(string)) + if _, ok := d.GetOk("name"); ok { + createTektonPipelinePropertiesOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("value"); ok { + createTektonPipelinePropertiesOptions.SetValue(d.Get("value").(string)) + } + if _, ok := d.GetOk("enum"); ok { + enumInterface := d.Get("enum").([]interface{}) + enum := make([]string, len(enumInterface)) + for i, v := range enumInterface { + enum[i] = fmt.Sprint(v) + } + createTektonPipelinePropertiesOptions.SetEnum(enum) + } + if _, ok := d.GetOk("type"); ok { + createTektonPipelinePropertiesOptions.SetType(d.Get("type").(string)) + } + if _, ok := d.GetOk("path"); ok { + createTektonPipelinePropertiesOptions.SetPath(d.Get("path").(string)) + } + + property, response, err := cdTektonPipelineClient.CreateTektonPipelinePropertiesWithContext(context, createTektonPipelinePropertiesOptions) + if err != nil { + log.Printf("[DEBUG] CreateTektonPipelinePropertiesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTektonPipelinePropertiesWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createTektonPipelinePropertiesOptions.PipelineID, *property.Name)) + + return resourceIBMCdTektonPipelinePropertyRead(context, d, meta) +} + +func resourceIBMCdTektonPipelinePropertyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelinePropertyOptions := &cdtektonpipelinev2.GetTektonPipelinePropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelinePropertyOptions.SetPipelineID(parts[0]) + getTektonPipelinePropertyOptions.SetPropertyName(parts[1]) + + property, response, err := cdTektonPipelineClient.GetTektonPipelinePropertyWithContext(context, getTektonPipelinePropertyOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTektonPipelinePropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelinePropertyWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("pipeline_id", getTektonPipelinePropertyOptions.PipelineID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pipeline_id: %s", err)) + } + if err = d.Set("name", property.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("value", property.Value); err != nil { + return diag.FromErr(fmt.Errorf("Error setting value: %s", err)) + } + if property.Enum != nil { + if err = d.Set("enum", property.Enum); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enum: %s", err)) + } + } + if err = d.Set("type", property.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("path", property.Path); err != nil { + return diag.FromErr(fmt.Errorf("Error setting path: %s", err)) + } + + return nil +} + +func resourceIBMCdTektonPipelinePropertyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelinePropertyOptions := &cdtektonpipelinev2.ReplaceTektonPipelinePropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelinePropertyOptions.SetPipelineID(parts[0]) + replaceTektonPipelinePropertyOptions.SetPropertyName(parts[1]) + replaceTektonPipelinePropertyOptions.SetName(d.Get("name").(string)) + replaceTektonPipelinePropertyOptions.SetType(d.Get("type").(string)) + + hasChange := false + + if d.HasChange("pipeline_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "pipeline_id")) + } + if d.HasChange("name") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "name")) + } + + if d.Get("type").(string) == "integration" { + if d.HasChange("value") || d.HasChange("path") { + replaceTektonPipelinePropertyOptions.SetValue(d.Get("value").(string)) + replaceTektonPipelinePropertyOptions.SetPath(d.Get("path").(string)) + hasChange = true + } + } else if d.Get("type").(string) == "single_select" { + if d.HasChange("enum") || d.HasChange("value") { + enumInterface := d.Get("enum").([]interface{}) + enum := make([]string, len(enumInterface)) + for i, v := range enumInterface { + enum[i] = fmt.Sprint(v) + } + replaceTektonPipelinePropertyOptions.SetEnum(enum) + replaceTektonPipelinePropertyOptions.SetValue(d.Get("value").(string)) + hasChange = true + } + } else { + if d.HasChange("value") { + replaceTektonPipelinePropertyOptions.SetValue(d.Get("value").(string)) + hasChange = true + } + } + + if hasChange { + _, response, err := cdTektonPipelineClient.ReplaceTektonPipelinePropertyWithContext(context, replaceTektonPipelinePropertyOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceTektonPipelinePropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceTektonPipelinePropertyWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdTektonPipelinePropertyRead(context, d, meta) +} + +func resourceIBMCdTektonPipelinePropertyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelinePropertyOptions := &cdtektonpipelinev2.DeleteTektonPipelinePropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelinePropertyOptions.SetPipelineID(parts[0]) + deleteTektonPipelinePropertyOptions.SetPropertyName(parts[1]) + + response, err := cdTektonPipelineClient.DeleteTektonPipelinePropertyWithContext(context, deleteTektonPipelinePropertyOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTektonPipelinePropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTektonPipelinePropertyWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_test.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_test.go new file mode 100644 index 000000000..79eb469e7 --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_test.go @@ -0,0 +1,183 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func TestAccIBMCdTektonPipelineBasic(t *testing.T) { + var conf cdtektonpipelinev2.TektonPipeline + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdTektonPipelineDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdTektonPipelineConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdTektonPipelineExists("ibm_cd_tekton_pipeline.cd_tekton_pipeline", conf), + ), + }, + }, + }) +} + +func TestAccIBMCdTektonPipelineAllArgs(t *testing.T) { + var conf cdtektonpipelinev2.TektonPipeline + enableSlackNotifications := "true" + enablePartialCloning := "true" + enableSlackNotificationsUpdate := "false" + enablePartialCloningUpdate := "false" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdTektonPipelineDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdTektonPipelineConfig(enableSlackNotifications, enablePartialCloning), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdTektonPipelineExists("ibm_cd_tekton_pipeline.cd_tekton_pipeline", conf), + resource.TestCheckResourceAttr("ibm_cd_tekton_pipeline.cd_tekton_pipeline", "enable_slack_notifications", enableSlackNotifications), + resource.TestCheckResourceAttr("ibm_cd_tekton_pipeline.cd_tekton_pipeline", "enable_partial_cloning", enablePartialCloning), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCdTektonPipelineConfig(enableSlackNotificationsUpdate, enablePartialCloningUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cd_tekton_pipeline.cd_tekton_pipeline", "enable_slack_notifications", enableSlackNotificationsUpdate), + resource.TestCheckResourceAttr("ibm_cd_tekton_pipeline.cd_tekton_pipeline", "enable_partial_cloning", enablePartialCloningUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cd_tekton_pipeline.cd_tekton_pipeline", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCdTektonPipelineConfigBasic() string { + rgID := acc.CdResourceGroupID + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + resource "ibm_cd_toolchain_tool_pipeline" "ibm_cd_toolchain_tool_pipeline" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "pipeline-name" + type = "tekton" + ui_pipeline = true + } + } + resource "ibm_cd_tekton_pipeline" "cd_tekton_pipeline" { + pipeline_id = ibm_cd_toolchain_tool_pipeline.ibm_cd_toolchain_tool_pipeline.tool_id + worker { + id = "public" + } + depends_on = [ + ibm_cd_toolchain_tool_pipeline.ibm_cd_toolchain_tool_pipeline + ] + } + `, tcName, rgID) +} + +func testAccCheckIBMCdTektonPipelineConfig(enableSlackNotifications string, enablePartialCloning string) string { + rgID := acc.CdResourceGroupID + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + resource "ibm_cd_toolchain_tool_pipeline" "ibm_cd_toolchain_tool_pipeline" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "pipeline-name" + type = "tekton" + ui_pipeline = true + } + } + resource "ibm_cd_tekton_pipeline" "cd_tekton_pipeline" { + pipeline_id = ibm_cd_toolchain_tool_pipeline.ibm_cd_toolchain_tool_pipeline.tool_id + enable_slack_notifications = %s + enable_partial_cloning = %s + worker { + id = "public" + } + depends_on = [ + ibm_cd_toolchain_tool_pipeline.ibm_cd_toolchain_tool_pipeline + ] + } + `, tcName, rgID, enableSlackNotifications, enablePartialCloning) +} + +func testAccCheckIBMCdTektonPipelineExists(n string, obj cdtektonpipelinev2.TektonPipeline) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + cdTektonPipelineClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return err + } + + getTektonPipelineOptions := &cdtektonpipelinev2.GetTektonPipelineOptions{} + + getTektonPipelineOptions.SetID(rs.Primary.ID) + + tektonPipeline, _, err := cdTektonPipelineClient.GetTektonPipeline(getTektonPipelineOptions) + if err != nil { + return err + } + + obj = *tektonPipeline + return nil + } +} + +func testAccCheckIBMCdTektonPipelineDestroy(s *terraform.State) error { + cdTektonPipelineClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cd_tekton_pipeline" { + continue + } + + getTektonPipelineOptions := &cdtektonpipelinev2.GetTektonPipelineOptions{} + + getTektonPipelineOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := cdTektonPipelineClient.GetTektonPipeline(getTektonPipelineOptions) + + if err == nil { + return fmt.Errorf("cd_tekton_pipeline still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cd_tekton_pipeline (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger.go new file mode 100644 index 000000000..605a9ecb6 --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger.go @@ -0,0 +1,804 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMCdTektonPipelineTrigger() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdTektonPipelineTriggerCreate, + ReadContext: resourceIBMCdTektonPipelineTriggerRead, + UpdateContext: resourceIBMCdTektonPipelineTriggerUpdate, + DeleteContext: resourceIBMCdTektonPipelineTriggerDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "pipeline_id"), + Description: "The Tekton pipeline ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "type"), + Description: "Trigger type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "name"), + Description: "Trigger name.", + }, + "event_listener": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "event_listener"), + Description: "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Trigger tags array.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "worker": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Name of the worker. Computed based on the worker ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type of the worker. Computed based on the worker ID.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "ID of the worker.", + }, + }, + }, + }, + "max_concurrent_runs": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + }, + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + }, + "secret": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Secret type.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressGenericWebhookRawSecret, + Description: "Secret value, not needed if secret type is `internal_validation`.", + }, + "source": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Secret location, not needed if secret type is `internal_validation`.", + }, + "key_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Secret name, not needed if type is `internal_validation`.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + }, + }, + }, + }, + "cron": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "cron"), + Description: "Only needed for timer triggers. Cron expression for timer trigger.", + }, + "timezone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger", "timezone"), + Description: "Only needed for timer triggers. Timezone for timer trigger.", + }, + "scm_source": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "SCM source repository for a Git trigger. Only needed for Git triggers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "URL of the repository to which the trigger is listening.", + }, + "branch": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + }, + "pattern": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + "hook_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the webhook from the repo. Computed upon creation of the trigger.", + }, + "service_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the repository service instance.", + }, + }, + }, + }, + "events": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "push": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'push' Git webhook events.", + }, + "pull_request_closed": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'close pull request' Git webhook events.", + }, + "pull_request": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Description: "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API URL for interacting with the trigger.", + }, + "properties": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Trigger properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressTriggerPropertyRawSecret, + Description: "Property value. Can be empty and should be omitted for `single_select` property type.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "API URL for interacting with the trigger property.", + }, + }, + }, + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Webhook URL that can be used to trigger pipeline runs.", + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID.", + }, + }, + } +} + +func ResourceIBMCdTektonPipelineTriggerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "pipeline_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z]+$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "generic, manual, scm, timer", + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "event_listener", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[-0-9a-zA-Z_.]{1,235}$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "cron", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$`, + MinValueLength: 5, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "timezone", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[-0-9a-zA-Z_., \/]{1,234}$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_tekton_pipeline_trigger", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdTektonPipelineTriggerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + createTektonPipelineTriggerOptions := &cdtektonpipelinev2.CreateTektonPipelineTriggerOptions{} + + createTektonPipelineTriggerOptions.SetPipelineID(d.Get("pipeline_id").(string)) + if _, ok := d.GetOk("type"); ok { + createTektonPipelineTriggerOptions.SetType(d.Get("type").(string)) + } + if _, ok := d.GetOk("name"); ok { + createTektonPipelineTriggerOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("event_listener"); ok { + createTektonPipelineTriggerOptions.SetEventListener(d.Get("event_listener").(string)) + } + if _, ok := d.GetOk("tags"); ok { + tags := []string{} + for _, tagsItem := range d.Get("tags").([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + createTektonPipelineTriggerOptions.SetTags(tags) + } + if _, ok := d.GetOk("worker"); ok { + workerModel, err := resourceIBMCdTektonPipelineTriggerMapToWorker(d.Get("worker.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineTriggerOptions.SetWorker(workerModel) + } + if _, ok := d.GetOk("max_concurrent_runs"); ok { + createTektonPipelineTriggerOptions.SetMaxConcurrentRuns(int64(d.Get("max_concurrent_runs").(int))) + } + if _, ok := d.GetOk("disabled"); ok { + createTektonPipelineTriggerOptions.SetDisabled(d.Get("disabled").(bool)) + } + if _, ok := d.GetOk("secret"); ok { + secretModel, err := resourceIBMCdTektonPipelineTriggerMapToGenericSecret(d.Get("secret.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineTriggerOptions.SetSecret(secretModel) + } + if _, ok := d.GetOk("cron"); ok { + createTektonPipelineTriggerOptions.SetCron(d.Get("cron").(string)) + } + if _, ok := d.GetOk("timezone"); ok { + createTektonPipelineTriggerOptions.SetTimezone(d.Get("timezone").(string)) + } + if _, ok := d.GetOk("scm_source"); ok { + scmSourceModel, err := resourceIBMCdTektonPipelineTriggerMapToTriggerScmSource(d.Get("scm_source.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineTriggerOptions.SetScmSource(scmSourceModel) + } + if _, ok := d.GetOk("events"); ok { + eventsModel, err := resourceIBMCdTektonPipelineTriggerMapToEvents(d.Get("events.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createTektonPipelineTriggerOptions.SetEvents(eventsModel) + } + + triggerIntf, response, err := cdTektonPipelineClient.CreateTektonPipelineTriggerWithContext(context, createTektonPipelineTriggerOptions) + if err != nil { + log.Printf("[DEBUG] CreateTektonPipelineTriggerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTektonPipelineTriggerWithContext failed %s\n%s", err, response)) + } + + trigger := triggerIntf.(*cdtektonpipelinev2.Trigger) + d.SetId(fmt.Sprintf("%s/%s", *createTektonPipelineTriggerOptions.PipelineID, *trigger.ID)) + + return resourceIBMCdTektonPipelineTriggerRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineTriggerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerOptions := &cdtektonpipelinev2.GetTektonPipelineTriggerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerOptions.SetPipelineID(parts[0]) + getTektonPipelineTriggerOptions.SetTriggerID(parts[1]) + + triggerIntf, response, err := cdTektonPipelineClient.GetTektonPipelineTriggerWithContext(context, getTektonPipelineTriggerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTektonPipelineTriggerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineTriggerWithContext failed %s\n%s", err, response)) + } + + trigger := triggerIntf.(*cdtektonpipelinev2.Trigger) + if err = d.Set("pipeline_id", getTektonPipelineTriggerOptions.PipelineID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pipeline_id: %s", err)) + } + if err = d.Set("type", trigger.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("name", trigger.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("event_listener", trigger.EventListener); err != nil { + return diag.FromErr(fmt.Errorf("Error setting event_listener: %s", err)) + } + if trigger.Tags != nil { + if err = d.Set("tags", trigger.Tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + } + if trigger.Worker != nil { + workerMap, err := resourceIBMCdTektonPipelineTriggerWorkerToMap(trigger.Worker) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("worker", []map[string]interface{}{workerMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting worker: %s", err)) + } + } + if err = d.Set("max_concurrent_runs", flex.IntValue(trigger.MaxConcurrentRuns)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting max_concurrent_runs: %s", err)) + } + if err = d.Set("disabled", trigger.Disabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting disabled: %s", err)) + } + if trigger.Secret != nil { + secretMap, err := resourceIBMCdTektonPipelineTriggerGenericSecretToMap(trigger.Secret) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("secret", []map[string]interface{}{secretMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret: %s", err)) + } + } + if err = d.Set("cron", trigger.Cron); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cron: %s", err)) + } + if err = d.Set("timezone", trigger.Timezone); err != nil { + return diag.FromErr(fmt.Errorf("Error setting timezone: %s", err)) + } + if trigger.ScmSource != nil { + scmSourceMap, err := resourceIBMCdTektonPipelineTriggerTriggerScmSourceToMap(trigger.ScmSource) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("scm_source", []map[string]interface{}{scmSourceMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting scm_source: %s", err)) + } + } + if trigger.Events != nil { + eventsMap, err := resourceIBMCdTektonPipelineTriggerEventsToMap(trigger.Events) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("events", []map[string]interface{}{eventsMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting events: %s", err)) + } + } + if err = d.Set("href", trigger.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + properties := []map[string]interface{}{} + if trigger.Properties != nil { + for _, propertiesItem := range trigger.Properties { + propertiesItemMap, err := resourceIBMCdTektonPipelineTriggerTriggerPropertiesItemToMap(&propertiesItem) + if err != nil { + return diag.FromErr(err) + } + properties = append(properties, propertiesItemMap) + } + } + if err = d.Set("properties", properties); err != nil { + return diag.FromErr(fmt.Errorf("Error setting properties: %s", err)) + } + if err = d.Set("webhook_url", trigger.WebhookURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting webhook_url: %s", err)) + } + if err = d.Set("trigger_id", trigger.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting trigger_id: %s", err)) + } + + return nil +} + +func resourceIBMCdTektonPipelineTriggerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + updateTektonPipelineTriggerOptions := &cdtektonpipelinev2.UpdateTektonPipelineTriggerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateTektonPipelineTriggerOptions.SetPipelineID(parts[0]) + updateTektonPipelineTriggerOptions.SetTriggerID(parts[1]) + + hasChange := false + + patchVals := &cdtektonpipelinev2.TriggerPatch{} + if d.HasChange("pipeline_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "pipeline_id")) + } + if d.HasChange("type") { + patchVals.Type = core.StringPtr(d.Get("type").(string)) + hasChange = true + } + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("event_listener") { + patchVals.EventListener = core.StringPtr(d.Get("event_listener").(string)) + hasChange = true + } + if d.HasChange("tags") { + tags := []string{} + for _, tagsItem := range d.Get("tags").([]interface{}) { + tags = append(tags, tagsItem.(string)) + } + patchVals.Tags = tags + hasChange = true + } + if d.HasChange("worker") { + worker, err := resourceIBMCdTektonPipelineTriggerMapToWorker(d.Get("worker.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchVals.Worker = worker + hasChange = true + } + if d.HasChange("max_concurrent_runs") { + patchVals.MaxConcurrentRuns = core.Int64Ptr(int64(d.Get("max_concurrent_runs").(int))) + hasChange = true + } + if d.HasChange("disabled") { + patchVals.Disabled = core.BoolPtr(d.Get("disabled").(bool)) + hasChange = true + } + if d.HasChange("secret") { + secret, err := resourceIBMCdTektonPipelineTriggerMapToGenericSecret(d.Get("secret.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchVals.Secret = secret + hasChange = true + } + if d.HasChange("cron") { + patchVals.Cron = core.StringPtr(d.Get("cron").(string)) + hasChange = true + } + if d.HasChange("timezone") { + patchVals.Timezone = core.StringPtr(d.Get("timezone").(string)) + hasChange = true + } + if d.HasChange("scm_source") { + scmSource, err := resourceIBMCdTektonPipelineTriggerMapToTriggerScmSource(d.Get("scm_source.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchVals.ScmSource = scmSource + hasChange = true + } + if d.HasChange("events") { + events, err := resourceIBMCdTektonPipelineTriggerMapToEvents(d.Get("events.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchVals.Events = events + hasChange = true + } + + if hasChange { + updateTektonPipelineTriggerOptions.TriggerPatch, _ = patchVals.AsPatch() + _, response, err := cdTektonPipelineClient.UpdateTektonPipelineTriggerWithContext(context, updateTektonPipelineTriggerOptions) + if err != nil { + log.Printf("[DEBUG] UpdateTektonPipelineTriggerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateTektonPipelineTriggerWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdTektonPipelineTriggerRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineTriggerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineTriggerOptions := &cdtektonpipelinev2.DeleteTektonPipelineTriggerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineTriggerOptions.SetPipelineID(parts[0]) + deleteTektonPipelineTriggerOptions.SetTriggerID(parts[1]) + + response, err := cdTektonPipelineClient.DeleteTektonPipelineTriggerWithContext(context, deleteTektonPipelineTriggerOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTektonPipelineTriggerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTektonPipelineTriggerWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdTektonPipelineTriggerMapToWorker(modelMap map[string]interface{}) (*cdtektonpipelinev2.Worker, error) { + model := &cdtektonpipelinev2.Worker{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func resourceIBMCdTektonPipelineTriggerMapToGenericSecret(modelMap map[string]interface{}) (*cdtektonpipelinev2.GenericSecret, error) { + model := &cdtektonpipelinev2.GenericSecret{} + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["value"] != nil && modelMap["value"].(string) != "" { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + if modelMap["source"] != nil && modelMap["source"].(string) != "" { + model.Source = core.StringPtr(modelMap["source"].(string)) + } + if modelMap["key_name"] != nil && modelMap["key_name"].(string) != "" { + model.KeyName = core.StringPtr(modelMap["key_name"].(string)) + } + if modelMap["algorithm"] != nil && modelMap["algorithm"].(string) != "" { + model.Algorithm = core.StringPtr(modelMap["algorithm"].(string)) + } + return model, nil +} + +func resourceIBMCdTektonPipelineTriggerMapToTriggerScmSource(modelMap map[string]interface{}) (*cdtektonpipelinev2.TriggerScmSource, error) { + model := &cdtektonpipelinev2.TriggerScmSource{} + model.URL = core.StringPtr(modelMap["url"].(string)) + if modelMap["branch"] != nil && modelMap["branch"].(string) != "" { + model.Branch = core.StringPtr(modelMap["branch"].(string)) + } + if modelMap["pattern"] != nil && modelMap["pattern"].(string) != "" { + model.Pattern = core.StringPtr(modelMap["pattern"].(string)) + } + return model, nil +} + +func resourceIBMCdTektonPipelineTriggerMapToEvents(modelMap map[string]interface{}) (*cdtektonpipelinev2.Events, error) { + model := &cdtektonpipelinev2.Events{} + if modelMap["push"] != nil { + model.Push = core.BoolPtr(modelMap["push"].(bool)) + } + if modelMap["pull_request_closed"] != nil { + model.PullRequestClosed = core.BoolPtr(modelMap["pull_request_closed"].(bool)) + } + if modelMap["pull_request"] != nil { + model.PullRequest = core.BoolPtr(modelMap["pull_request"].(bool)) + } + return model, nil +} + +func resourceIBMCdTektonPipelineTriggerWorkerToMap(model *cdtektonpipelinev2.Worker) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Type != nil { + modelMap["type"] = model.Type + } + modelMap["id"] = model.ID + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerGenericSecretToMap(model *cdtektonpipelinev2.GenericSecret) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Source != nil { + modelMap["source"] = model.Source + } + if model.KeyName != nil { + modelMap["key_name"] = model.KeyName + } + if model.Algorithm != nil { + modelMap["algorithm"] = model.Algorithm + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerTriggerScmSourceToMap(model *cdtektonpipelinev2.TriggerScmSource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["url"] = model.URL + if model.Branch != nil { + modelMap["branch"] = model.Branch + } + if model.Pattern != nil { + modelMap["pattern"] = model.Pattern + } + if model.BlindConnection != nil { + modelMap["blind_connection"] = model.BlindConnection + } + if model.HookID != nil { + modelMap["hook_id"] = model.HookID + } + if model.ServiceInstanceID != nil { + modelMap["service_instance_id"] = model.ServiceInstanceID + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerEventsToMap(model *cdtektonpipelinev2.Events) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Push != nil { + modelMap["push"] = model.Push + } + if model.PullRequestClosed != nil { + modelMap["pull_request_closed"] = model.PullRequestClosed + } + if model.PullRequest != nil { + modelMap["pull_request"] = model.PullRequest + } + return modelMap, nil +} + +func resourceIBMCdTektonPipelineTriggerTriggerPropertiesItemToMap(model *cdtektonpipelinev2.TriggerPropertiesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Enum != nil { + modelMap["enum"] = model.Enum + } + modelMap["type"] = model.Type + if model.Path != nil { + modelMap["path"] = model.Path + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} diff --git a/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger_property.go b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger_property.go new file mode 100644 index 000000000..1886ec79d --- /dev/null +++ b/ibm/service/cdtektonpipeline/resource_ibm_cd_tekton_pipeline_trigger_property.go @@ -0,0 +1,331 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtektonpipeline + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtektonpipelinev2" +) + +func ResourceIBMCdTektonPipelineTriggerProperty() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdTektonPipelineTriggerPropertyCreate, + ReadContext: resourceIBMCdTektonPipelineTriggerPropertyRead, + UpdateContext: resourceIBMCdTektonPipelineTriggerPropertyUpdate, + DeleteContext: resourceIBMCdTektonPipelineTriggerPropertyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "pipeline_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "pipeline_id"), + Description: "The Tekton pipeline ID.", + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "trigger_id"), + Description: "The trigger ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "name"), + Description: "Property name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressTriggerPropertyRawSecret, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "value"), + Description: "Property value.", + }, + "enum": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Options for `single_select` property type. Only needed for `single_select` property type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "type"), + Description: "Property type.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_tekton_pipeline_trigger_property", "path"), + Description: "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + }, + }, + } +} + +func ResourceIBMCdTektonPipelineTriggerPropertyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "pipeline_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z]+$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "trigger_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z]+$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-zA-Z_.]{1,234}$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "value", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `.`, + MinValueLength: 1, + MaxValueLength: 4096, + }, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "appconfig, integration, secure, single_select, text", + }, + validate.ValidateSchema{ + Identifier: "path", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `.`, + MinValueLength: 1, + MaxValueLength: 4096, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_tekton_pipeline_trigger_property", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdTektonPipelineTriggerPropertyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + createTektonPipelineTriggerPropertiesOptions := &cdtektonpipelinev2.CreateTektonPipelineTriggerPropertiesOptions{} + + createTektonPipelineTriggerPropertiesOptions.SetPipelineID(d.Get("pipeline_id").(string)) + createTektonPipelineTriggerPropertiesOptions.SetTriggerID(d.Get("trigger_id").(string)) + if _, ok := d.GetOk("name"); ok { + createTektonPipelineTriggerPropertiesOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("value"); ok { + createTektonPipelineTriggerPropertiesOptions.SetValue(d.Get("value").(string)) + } + if _, ok := d.GetOk("enum"); ok { + enumInterface := d.Get("enum").([]interface{}) + enum := make([]string, len(enumInterface)) + for i, v := range enumInterface { + enum[i] = fmt.Sprint(v) + } + createTektonPipelineTriggerPropertiesOptions.SetEnum(enum) + } + if _, ok := d.GetOk("type"); ok { + createTektonPipelineTriggerPropertiesOptions.SetType(d.Get("type").(string)) + } + if _, ok := d.GetOk("path"); ok { + createTektonPipelineTriggerPropertiesOptions.SetPath(d.Get("path").(string)) + } + + triggerProperty, response, err := cdTektonPipelineClient.CreateTektonPipelineTriggerPropertiesWithContext(context, createTektonPipelineTriggerPropertiesOptions) + if err != nil { + log.Printf("[DEBUG] CreateTektonPipelineTriggerPropertiesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTektonPipelineTriggerPropertiesWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *createTektonPipelineTriggerPropertiesOptions.PipelineID, *createTektonPipelineTriggerPropertiesOptions.TriggerID, *triggerProperty.Name)) + + return resourceIBMCdTektonPipelineTriggerPropertyRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineTriggerPropertyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerPropertyOptions := &cdtektonpipelinev2.GetTektonPipelineTriggerPropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTektonPipelineTriggerPropertyOptions.SetPipelineID(parts[0]) + getTektonPipelineTriggerPropertyOptions.SetTriggerID(parts[1]) + getTektonPipelineTriggerPropertyOptions.SetPropertyName(parts[2]) + + triggerProperty, response, err := cdTektonPipelineClient.GetTektonPipelineTriggerPropertyWithContext(context, getTektonPipelineTriggerPropertyOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("pipeline_id", getTektonPipelineTriggerPropertyOptions.PipelineID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pipeline_id: %s", err)) + } + if err = d.Set("trigger_id", getTektonPipelineTriggerPropertyOptions.TriggerID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting trigger_id: %s", err)) + } + if err = d.Set("name", triggerProperty.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("value", triggerProperty.Value); err != nil { + return diag.FromErr(fmt.Errorf("Error setting value: %s", err)) + } + if triggerProperty.Enum != nil { + if err = d.Set("enum", triggerProperty.Enum); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enum: %s", err)) + } + } + if err = d.Set("type", triggerProperty.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("path", triggerProperty.Path); err != nil { + return diag.FromErr(fmt.Errorf("Error setting path: %s", err)) + } + + return nil +} + +func resourceIBMCdTektonPipelineTriggerPropertyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelineTriggerPropertyOptions := &cdtektonpipelinev2.ReplaceTektonPipelineTriggerPropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + replaceTektonPipelineTriggerPropertyOptions.SetPipelineID(parts[0]) + replaceTektonPipelineTriggerPropertyOptions.SetTriggerID(parts[1]) + replaceTektonPipelineTriggerPropertyOptions.SetPropertyName(parts[2]) + replaceTektonPipelineTriggerPropertyOptions.SetName(d.Get("name").(string)) + replaceTektonPipelineTriggerPropertyOptions.SetType(d.Get("type").(string)) + + hasChange := false + + if d.HasChange("pipeline_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "pipeline_id")) + } + if d.HasChange("trigger_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "trigger_id")) + } + if d.HasChange("name") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "name")) + } + + if d.Get("type").(string) == "integration" { + if d.HasChange("value") || d.HasChange("path") { + replaceTektonPipelineTriggerPropertyOptions.SetValue(d.Get("value").(string)) + replaceTektonPipelineTriggerPropertyOptions.SetPath(d.Get("path").(string)) + hasChange = true + } + } else if d.Get("type").(string) == "single_select" { + if d.HasChange("enum") || d.HasChange("value") { + enumInterface := d.Get("enum").([]interface{}) + enum := make([]string, len(enumInterface)) + for i, v := range enumInterface { + enum[i] = fmt.Sprint(v) + } + replaceTektonPipelineTriggerPropertyOptions.SetEnum(enum) + replaceTektonPipelineTriggerPropertyOptions.SetValue(d.Get("value").(string)) + hasChange = true + } + } else { + if d.HasChange("value") { + replaceTektonPipelineTriggerPropertyOptions.SetValue(d.Get("value").(string)) + hasChange = true + } + } + + if hasChange { + _, response, err := cdTektonPipelineClient.ReplaceTektonPipelineTriggerPropertyWithContext(context, replaceTektonPipelineTriggerPropertyOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdTektonPipelineTriggerPropertyRead(context, d, meta) +} + +func resourceIBMCdTektonPipelineTriggerPropertyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdTektonPipelineClient, err := meta.(conns.ClientSession).CdTektonPipelineV2() + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineTriggerPropertyOptions := &cdtektonpipelinev2.DeleteTektonPipelineTriggerPropertyOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTektonPipelineTriggerPropertyOptions.SetPipelineID(parts[0]) + deleteTektonPipelineTriggerPropertyOptions.SetTriggerID(parts[1]) + deleteTektonPipelineTriggerPropertyOptions.SetPropertyName(parts[2]) + + response, err := cdTektonPipelineClient.DeleteTektonPipelineTriggerPropertyWithContext(context, deleteTektonPipelineTriggerPropertyOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTektonPipelineTriggerPropertyWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/cdtoolchain/README.md b/ibm/service/cdtoolchain/README.md new file mode 100644 index 000000000..00eaff473 --- /dev/null +++ b/ibm/service/cdtoolchain/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cd_toolchain_tool_sonarqube) +* IBM API Docs: [IBM API Docs for ]() +* IBM SDK: [IBM SDK for ](https://github.com/IBM/appconfiguration-go-admin-sdk/tree/master/cdtoolchainv2) diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain.go new file mode 100644 index 000000000..d313bef33 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain.go @@ -0,0 +1,150 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchain() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain description.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Account ID where toolchain can be found.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain region.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where toolchain can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI that can be used to retrieve toolchain.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain creation timestamp.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest toolchain update timestamp.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Identity that created the toolchain.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tags associated with the toolchain.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMCdToolchainRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolchainByIDOptions := &cdtoolchainv2.GetToolchainByIDOptions{} + + getToolchainByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + + toolchain, response, err := cdToolchainClient.GetToolchainByIDWithContext(context, getToolchainByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolchainByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolchainByIDWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getToolchainByIDOptions.ToolchainID)) + + if err = d.Set("name", toolchain.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("description", toolchain.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("account_id", toolchain.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + + if err = d.Set("location", toolchain.Location); err != nil { + return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + } + + if err = d.Set("resource_group_id", toolchain.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchain.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("href", toolchain.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(toolchain.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchain.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_by", toolchain.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + return nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_test.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_test.go new file mode 100644 index 000000000..7e5e87928 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_test.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCdToolchainDataSourceBasic(t *testing.T) { + getToolchainByIDResponseName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + getToolchainByIDResponseResourceGroupID := acc.CdResourceGroupID + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainDataSourceConfigBasic(getToolchainByIDResponseName, getToolchainByIDResponseResourceGroupID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "account_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "location"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "created_by"), + ), + }, + }, + }) +} + +func TestAccIBMCdToolchainDataSourceAllArgs(t *testing.T) { + getToolchainByIDResponseName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + getToolchainByIDResponseResourceGroupID := acc.CdResourceGroupID + getToolchainByIDResponseDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainDataSourceConfig(getToolchainByIDResponseName, getToolchainByIDResponseResourceGroupID, getToolchainByIDResponseDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "description"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "account_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "location"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain.cd_toolchain", "created_by"), + ), + }, + }, + }) +} + +func testAccCheckIBMCdToolchainDataSourceConfigBasic(getToolchainByIDResponseName string, getToolchainByIDResponseResourceGroupID string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + data "ibm_cd_toolchain" "cd_toolchain" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + } + `, getToolchainByIDResponseName, getToolchainByIDResponseResourceGroupID) +} + +func testAccCheckIBMCdToolchainDataSourceConfig(getToolchainByIDResponseName string, getToolchainByIDResponseResourceGroupID string, getToolchainByIDResponseDescription string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + description = "%s" + } + + data "ibm_cd_toolchain" "cd_toolchain" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + } + `, getToolchainByIDResponseName, getToolchainByIDResponseResourceGroupID, getToolchainByIDResponseDescription) +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig.go new file mode 100644 index 000000000..78183b042 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig.go @@ -0,0 +1,221 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolAppconfig() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolAppconfigRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01.", + }, + "environment_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "App Configuration environment.", + }, + "collection_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "App Configuration collection.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolAppconfigRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "appconfig" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolAppconfigToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + "environment_name": "environment-name", + "collection_name": "collection-name", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolAppconfig(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolAppconfigToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig_test.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig_test.go new file mode 100644 index 000000000..30a4332d5 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_appconfig_test.go @@ -0,0 +1,127 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCdToolchainToolAppconfigDataSourceBasic(t *testing.T) { + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + rgID := acc.CdResourceGroupID + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolAppconfigDataSourceConfigBasic(tcName, rgID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "toolchain_crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "referent.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "parameters.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "state"), + ), + }, + }, + }) +} + +func TestAccIBMCdToolchainToolAppconfigDataSourceAllArgs(t *testing.T) { + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + rgID := acc.CdResourceGroupID + getToolByIDResponseName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolAppconfigDataSourceConfig(tcName, rgID, getToolByIDResponseName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "toolchain_crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "referent.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "parameters.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig", "state"), + ), + }, + }, + }) +} + +func testAccCheckIBMCdToolchainToolAppconfigDataSourceConfigBasic(tcName string, rgID string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + region = "region" + resource_group = "resource-group" + instance_name = "instance-name" + environment_name = "environment-name" + collection_name = "collection-name" + } + } + + data "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + toolchain_id = ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig.toolchain_id + tool_id = ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig.tool_id + } + `, tcName, rgID) +} + +func testAccCheckIBMCdToolchainToolAppconfigDataSourceConfig(tcName string, rgID string, getToolByIDResponseName string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + region = "region" + resource_group = "resource-group" + instance_name = "instance-name" + environment_name = "environment-name" + collection_name = "collection-name" + } + name = "%s" + } + + data "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + toolchain_id = ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig.toolchain_id + tool_id = ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig.tool_id + } + `, tcName, rgID, getToolByIDResponseName) +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory.go new file mode 100644 index 000000000..8be31d54f --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory.go @@ -0,0 +1,236 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolArtifactory() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolArtifactoryRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL that you want to navigate to when you click the Artifactory integration tile.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Choose the type of repository for your Artifactory integration.", + }, + "user_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the User ID or email for your Artifactory repository.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type the API key for your Artifactory repository.", + }, + "release_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Artifactory release repository.", + }, + "mirror_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + }, + "snapshot_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Artifactory snapshot repository.", + }, + "repository_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the name of your artifactory repository where your docker images are located.", + }, + "repository_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of your artifactory repository where your docker images are located.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolArtifactoryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "artifactory" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolArtifactoryToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolArtifactory(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolArtifactoryToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory_test.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory_test.go new file mode 100644 index 000000000..a4219786d --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_artifactory_test.go @@ -0,0 +1,135 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCdToolchainToolArtifactoryDataSourceBasic(t *testing.T) { + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + rgID := acc.CdResourceGroupID + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolArtifactoryDataSourceConfigBasic(tcName, rgID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "toolchain_crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "referent.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "parameters.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "state"), + ), + }, + }, + }) +} + +func TestAccIBMCdToolchainToolArtifactoryDataSourceAllArgs(t *testing.T) { + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + rgID := acc.CdResourceGroupID + getToolByIDResponseName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolArtifactoryDataSourceConfig(tcName, rgID, getToolByIDResponseName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "toolchain_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "tool_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "toolchain_crn"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "referent.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "parameters.#"), + resource.TestCheckResourceAttrSet("data.ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory", "state"), + ), + }, + }, + }) +} + +func testAccCheckIBMCdToolchainToolArtifactoryDataSourceConfigBasic(tcName string, rgID string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + dashboard_url = "dashboard_url" + type = "npm" + user_id = "user_id" + token = "token" + release_url = "release_url" + mirror_url = "mirror_url" + snapshot_url = "snapshot_url" + repository_name = "repository_name" + repository_url = "repository_url" + } + } + + data "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + toolchain_id = ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory.toolchain_id + tool_id = ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory.tool_id + } + `, tcName, rgID) +} + +func testAccCheckIBMCdToolchainToolArtifactoryDataSourceConfig(tcName string, rgID string, getToolByIDResponseName string) string { + return fmt.Sprintf(` + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + dashboard_url = "dashboard_url" + type = "npm" + user_id = "user_id" + token = "token" + release_url = "release_url" + mirror_url = "mirror_url" + snapshot_url = "snapshot_url" + repository_name = "repository_name" + repository_url = "repository_url" + } + name = "%s" + } + + data "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + toolchain_id = ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory.toolchain_id + tool_id = ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory.tool_id + } + `, tcName, rgID, getToolByIDResponseName) +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_bitbucketgit.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_bitbucketgit.go new file mode 100644 index 000000000..518ed7412 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_bitbucketgit.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolBitbucketgit() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolBitbucketgitRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "e.g. https://api.bitbucket.org.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to enable Bitbucket Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolBitbucketgitRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "bitbucketgit" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolBitbucketgitToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolBitbucketgit(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolBitbucketgitToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_custom.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_custom.go new file mode 100644 index 000000000..dc3628ce5 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_custom.go @@ -0,0 +1,231 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolCustom() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolCustomRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the name of the tool that you are integrating; for example: Delivery Pipeline.", + }, + "lifecycle_phase": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool.", + }, + "image_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the icon to show on your tool integration's card.", + }, + "documentation_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your tool's documentation.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this specific tool integration; for example: My Build and Deploy Pipeline.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL that you want to navigate to when you click the tool integration card.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a description for the tool instance.", + }, + "additional_properties": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "(Advanced) Type any information that is needed to integrate with other tools in your toolchain.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolCustomRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "customtool" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolCustomToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "lifecycle_phase": "lifecyclePhase", + "image_url": "imageUrl", + "documentation_url": "documentationUrl", + "additional_properties": "additional-properties", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolCustom(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolCustomToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_devopsinsights.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_devopsinsights.go new file mode 100644 index 000000000..e83ec25bc --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_devopsinsights.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolDevopsinsights() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolDevopsinsightsRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolDevopsinsightsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "draservicebroker" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolDevopsinsightsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolDevopsinsightsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubconsolidated.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubconsolidated.go new file mode 100644 index 000000000..375117864 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubconsolidated.go @@ -0,0 +1,246 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolGithubconsolidated() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolGithubconsolidatedRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "e.g. https://api.github.example.com.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to enable GitHub Issues for lightweight issue tracking.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolGithubconsolidatedRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "githubconsolidated" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolGithubconsolidatedToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolGithubconsolidated(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolGithubconsolidatedToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubintegrated.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubintegrated.go new file mode 100644 index 000000000..606bdaf7c --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_githubintegrated.go @@ -0,0 +1,250 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolGithubintegrated() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolGithubintegratedRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "e.g. https://github.ibm.com/api/v3.", + }, + "legal": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to enable GitHub Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolGithubintegratedRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "github_integrated" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolGithubintegratedToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolGithubintegrated(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolGithubintegratedToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_gitlab.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_gitlab.go new file mode 100644 index 000000000..21be2f33e --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_gitlab.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolGitlab() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolGitlabRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "e.g. https://gitlab.example.com/api/v4.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to enable GitLab Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolGitlabRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "gitlab" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolGitlabToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolGitlab(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolGitlabToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hashicorpvault.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hashicorpvault.go new file mode 100644 index 000000000..a7fdfd1b5 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hashicorpvault.go @@ -0,0 +1,249 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolHashicorpvault() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolHashicorpvaultRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "server_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the server URL for your HashiCorp Vault instance.", + }, + "authentication_method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Choose the authentication method for your HashiCorp Vault instance.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type or select the authentication token for your HashiCorp Vault instance.", + }, + "role_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type or select the authentication role ID for your HashiCorp Vault instance.", + }, + "secret_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type or select the authentication secret ID for your HashiCorp Vault instance.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the mount path where your secrets are stored in your HashiCorp Vault instance.", + }, + "secret_filter": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance.", + }, + "default_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type or select the authentication username for your HashiCorp Vault instance.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type or select the authentication password for your HashiCorp Vault instance.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolHashicorpvaultRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "hashicorpvault" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolHashicorpvaultToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolHashicorpvault(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolHashicorpvaultToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hostedgit.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hostedgit.go new file mode 100644 index 000000000..bf2f9e49a --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_hostedgit.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolHostedgit() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolHostedgitRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "e.g. https://gitlab.example.com/api/v4.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to enable Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolHostedgitRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "hostedgit" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolHostedgitToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolHostedgit(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolHostedgitToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_jenkins.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_jenkins.go new file mode 100644 index 000000000..d42cc83d9 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_jenkins.go @@ -0,0 +1,211 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolJenkins() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolJenkinsRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain.", + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions.", + }, + "api_user_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance.", + }, + "api_token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolJenkinsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "jenkins" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolJenkinsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolJenkins(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolJenkinsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_keyprotect.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_keyprotect.go new file mode 100644 index 000000000..04de21483 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_keyprotect.go @@ -0,0 +1,209 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolKeyprotect() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolKeyprotectRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolKeyprotectRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "keyprotect" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolKeyprotectToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolKeyprotect(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolKeyprotectToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_nexus.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_nexus.go new file mode 100644 index 000000000..e7bfbddf9 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_nexus.go @@ -0,0 +1,226 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolNexus() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolNexusRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL that you want to navigate to when you click the Nexus integration tile.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Choose the type of repository for your Nexus integration.", + }, + "user_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the User ID or email for your Nexus repository.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type the password or authentication token for your Nexus repository.", + }, + "release_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Nexus release repository.", + }, + "mirror_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + }, + "snapshot_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL for your Nexus snapshot repository.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolNexusRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "nexus" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolNexusToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolNexus(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolNexusToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pagerduty.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pagerduty.go new file mode 100644 index 000000000..39b3abaac --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pagerduty.go @@ -0,0 +1,227 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolPagerduty() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolPagerdutyRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select whether to integrate at the account level with an API key or at the service level with an integration key.", + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key).", + }, + "service_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service.", + }, + "user_email": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user.", + }, + "user_phone": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default.", + }, + "service_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the PagerDuty service to post alerts to.", + }, + "service_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page.", + }, + "service_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "service_id.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolPagerdutyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "pagerduty" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolPagerdutyToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolPagerduty(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolPagerdutyToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pipeline.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pipeline.go new file mode 100644 index 000000000..f8d61afae --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_pipeline.go @@ -0,0 +1,198 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolPipeline() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolPipelineRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "ui_pipeline": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolPipelineRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "pipeline" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolPipelineToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolPipeline(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolPipelineToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_privateworker.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_privateworker.go new file mode 100644 index 000000000..923fee9ab --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_privateworker.go @@ -0,0 +1,204 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolPrivateworker() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolPrivateworkerRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain.", + }, + "worker_queue_credentials": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue.", + }, + "worker_queue_identifier": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolPrivateworkerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "private_worker" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolPrivateworkerToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "worker_queue_credentials": "workerQueueCredentials", + "worker_queue_identifier": "workerQueueIdentifier", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolPrivateworker(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolPrivateworkerToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_saucelabs.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_saucelabs.go new file mode 100644 index 000000000..30e4f97f5 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_saucelabs.go @@ -0,0 +1,196 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolSaucelabs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolSaucelabsRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the user name for your Sauce Labs account.", + }, + "key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolSaucelabsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "saucelabs" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolSaucelabsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolSaucelabs(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolSaucelabsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_secretsmanager.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_secretsmanager.go new file mode 100644 index 000000000..637105402 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_secretsmanager.go @@ -0,0 +1,209 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolSecretsmanager() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolSecretsmanagerRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolSecretsmanagerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "secretsmanager" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolSecretsmanagerToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolSecretsmanager(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolSecretsmanagerToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_securitycompliance.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_securitycompliance.go new file mode 100644 index 000000000..e6f8cb4ad --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_securitycompliance.go @@ -0,0 +1,233 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolSecuritycompliance() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolSecuritycomplianceRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Give this tool integration a name, for example: my-security-compliance.", + }, + "evidence_repo_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker.", + }, + "trigger_scan": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Enabling trigger validation scans provides details for a pipeline task to trigger a scan.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "evidence_namespace": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence.", + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once).", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + }, + "profile": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + }, + "trigger_info": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "trigger_info.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolSecuritycomplianceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "security_compliance" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolSecuritycomplianceToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + remapFields := map[string]string{ + "api_key": "api-key", + } + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolSecuritycompliance(), remapFields) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolSecuritycomplianceToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_slack.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_slack.go new file mode 100644 index 000000000..b125fc4ef --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_slack.go @@ -0,0 +1,221 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolSlack() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolSlackRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead.", + }, + "channel_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If you use a webhook, you must specify an existing Slack channel to post notifications to.", + }, + "team_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_.", + }, + "pipeline_start": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "pipeline_success": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "pipeline_fail": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "toolchain_bind": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "toolchain_unbind": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolSlackRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "slack" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolSlackToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolSlack(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolSlackToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_sonarqube.go b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_sonarqube.go new file mode 100644 index 000000000..bf936a1a0 --- /dev/null +++ b/ibm/service/cdtoolchain/data_source_ibm_cd_toolchain_tool_sonarqube.go @@ -0,0 +1,210 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func DataSourceIBMCdToolchainToolSonarqube() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCdToolchainToolSonarqubeRead, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the toolchain.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "ID of the tool bound to the toolchain.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool name.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain.", + }, + "user_login": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "If you are using an authentication token, leave this field empty.", + }, + "user_password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + }, + } +} + +func dataSourceIBMCdToolchainToolSonarqubeRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + getToolByIDOptions.SetToolchainID(d.Get("toolchain_id").(string)) + getToolByIDOptions.SetToolID(d.Get("tool_id").(string)) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if *toolchainTool.ToolTypeID != "sonarqube" { + return diag.FromErr(fmt.Errorf("Retrieved tool is not the correct type: %s", *toolchainTool.ToolTypeID)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getToolByIDOptions.ToolchainID, *getToolByIDOptions.ToolID)) + + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + referent := []map[string]interface{}{} + if toolchainTool.Referent != nil { + modelMap, err := dataSourceIBMCdToolchainToolSonarqubeToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + referent = append(referent, modelMap) + } + if err = d.Set("referent", referent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent %s", err)) + } + + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + parameters := []map[string]interface{}{} + if toolchainTool.Parameters != nil { + modelMap := GetParametersFromRead(toolchainTool.Parameters, DataSourceIBMCdToolchainToolSonarqube(), nil) + parameters = append(parameters, modelMap) + } + if err = d.Set("parameters", parameters); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters %s", err)) + } + + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + return nil +} + +func dataSourceIBMCdToolchainToolSonarqubeToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = *model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = *model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain.go new file mode 100644 index 000000000..46061dd63 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain.go @@ -0,0 +1,270 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchain() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainCreate, + ReadContext: resourceIBMCdToolchainRead, + UpdateContext: resourceIBMCdToolchainUpdate, + DeleteContext: resourceIBMCdToolchainDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain", "name"), + Description: "Toolchain name.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain", "resource_group_id"), + Description: "Resource group where toolchain will be created.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain", "description"), + Description: "Describes the toolchain.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Account ID where toolchain can be found.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain region.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI that can be used to retrieve toolchain.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Toolchain creation timestamp.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest toolchain update timestamp.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Identity that created the toolchain.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Tags associated with the toolchain.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ResourceIBMCdToolchainValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-f]{32}$`, + MinValueLength: 32, + MaxValueLength: 32, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^(.*?)$`, + MinValueLength: 0, + MaxValueLength: 500, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolchainOptions := &cdtoolchainv2.CreateToolchainOptions{} + + createToolchainOptions.SetName(d.Get("name").(string)) + createToolchainOptions.SetResourceGroupID(d.Get("resource_group_id").(string)) + if _, ok := d.GetOk("description"); ok { + createToolchainOptions.SetDescription(d.Get("description").(string)) + } + + toolchainPost, response, err := cdToolchainClient.CreateToolchainWithContext(context, createToolchainOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolchainWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolchainWithContext failed %s\n%s", err, response)) + } + + d.SetId(*toolchainPost.ID) + + return resourceIBMCdToolchainRead(context, d, meta) +} + +func resourceIBMCdToolchainRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolchainByIDOptions := &cdtoolchainv2.GetToolchainByIDOptions{} + + getToolchainByIDOptions.SetToolchainID(d.Id()) + + toolchain, response, err := cdToolchainClient.GetToolchainByIDWithContext(context, getToolchainByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolchainByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolchainByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("name", toolchain.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchain.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("description", toolchain.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("account_id", toolchain.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + if err = d.Set("location", toolchain.Location); err != nil { + return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + } + if err = d.Set("crn", toolchain.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("href", toolchain.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(toolchain.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchain.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_by", toolchain.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("tags", toolchain.Tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolchainOptions := &cdtoolchainv2.UpdateToolchainOptions{} + + updateToolchainOptions.SetToolchainID(d.Id()) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainPrototypePatch{} + if d.HasChange("resource_group_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "resource_group_id")) + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + if d.HasChange("description") { + newDescription := d.Get("description").(string) + patchVals.Description = &newDescription + hasChange = true + } + + if hasChange { + updateToolchainOptions.ToolchainPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolchainWithContext(context, updateToolchainOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolchainWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolchainWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainRead(context, d, meta) +} + +func resourceIBMCdToolchainDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolchainOptions := &cdtoolchainv2.DeleteToolchainOptions{} + + deleteToolchainOptions.SetToolchainID(d.Id()) + + response, err := cdToolchainClient.DeleteToolchainWithContext(context, deleteToolchainOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolchainWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolchainWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_test.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_test.go new file mode 100644 index 000000000..bde00fb20 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_test.go @@ -0,0 +1,161 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func TestAccIBMCdToolchainBasic(t *testing.T) { + var conf cdtoolchainv2.Toolchain + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + resourceGroupID := acc.CdResourceGroupID + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdToolchainDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainConfigBasic(name, resourceGroupID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdToolchainExists("ibm_cd_toolchain.cd_toolchain", conf), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "name", name), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "resource_group_id", resourceGroupID), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCdToolchainConfigBasic(nameUpdate, resourceGroupID), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "resource_group_id", resourceGroupID), + ), + }, + }, + }) +} + +func TestAccIBMCdToolchainAllArgs(t *testing.T) { + var conf cdtoolchainv2.Toolchain + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + resourceGroupID := acc.CdResourceGroupID + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdToolchainDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainConfig(name, resourceGroupID, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdToolchainExists("ibm_cd_toolchain.cd_toolchain", conf), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "name", name), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "resource_group_id", resourceGroupID), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "description", description), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCdToolchainConfig(nameUpdate, resourceGroupID, descriptionUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "resource_group_id", resourceGroupID), + resource.TestCheckResourceAttr("ibm_cd_toolchain.cd_toolchain", "description", descriptionUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cd_toolchain.cd_toolchain", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCdToolchainConfigBasic(name string, resourceGroupID string) string { + return fmt.Sprintf(` + + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + `, name, resourceGroupID) +} + +func testAccCheckIBMCdToolchainConfig(name string, resourceGroupID string, description string) string { + return fmt.Sprintf(` + + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + description = "%s" + } + `, name, resourceGroupID, description) +} + +func testAccCheckIBMCdToolchainExists(n string, obj cdtoolchainv2.Toolchain) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + cdToolchainClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdToolchainV2() + if err != nil { + return err + } + + getToolchainByIDOptions := &cdtoolchainv2.GetToolchainByIDOptions{} + + getToolchainByIDOptions.SetToolchainID(rs.Primary.ID) + + getToolchainByIDResponse, _, err := cdToolchainClient.GetToolchainByID(getToolchainByIDOptions) + if err != nil { + return err + } + + obj = *getToolchainByIDResponse + return nil + } +} + +func testAccCheckIBMCdToolchainDestroy(s *terraform.State) error { + cdToolchainClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdToolchainV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cd_toolchain" { + continue + } + + getToolchainByIDOptions := &cdtoolchainv2.GetToolchainByIDOptions{} + + getToolchainByIDOptions.SetToolchainID(rs.Primary.ID) + + // Try to find the key + _, response, err := cdToolchainClient.GetToolchainByID(getToolchainByIDOptions) + + if err == nil { + return fmt.Errorf("cd_toolchain still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cd_toolchain (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_appconfig.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_appconfig.go new file mode 100644 index 000000000..50270ec7e --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_appconfig.go @@ -0,0 +1,363 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolAppconfig() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolAppconfigCreate, + ReadContext: resourceIBMCdToolchainToolAppconfigRead, + UpdateContext: resourceIBMCdToolchainToolAppconfigUpdate, + DeleteContext: resourceIBMCdToolchainToolAppconfigDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_appconfig", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01.", + }, + "environment_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "App Configuration environment.", + }, + "collection_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "App Configuration collection.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_appconfig", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolAppconfigValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_appconfig", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolAppconfigCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("appconfig") + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + "environment_name": "environment-name", + "collection_name": "collection-name", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolAppconfig(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolAppconfigRead(context, d, meta) +} + +func resourceIBMCdToolchainToolAppconfigRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + "environment_name": "environment-name", + "collection_name": "collection-name", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolAppconfig(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolAppconfigToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolAppconfigUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + "environment_name": "environment-name", + "collection_name": "collection-name", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolAppconfig(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolAppconfigRead(context, d, meta) +} + +func resourceIBMCdToolchainToolAppconfigDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolAppconfigToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_artifactory.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_artifactory.go new file mode 100644 index 000000000..ddb3f6edd --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_artifactory.go @@ -0,0 +1,367 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolArtifactory() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolArtifactoryCreate, + ReadContext: resourceIBMCdToolchainToolArtifactoryRead, + UpdateContext: resourceIBMCdToolchainToolArtifactoryUpdate, + DeleteContext: resourceIBMCdToolchainToolArtifactoryDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_artifactory", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL that you want to navigate to when you click the Artifactory integration tile.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Choose the type of repository for your Artifactory integration.", + }, + "user_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the User ID or email for your Artifactory repository.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type the API key for your Artifactory repository.", + }, + "release_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Artifactory release repository.", + }, + "mirror_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + }, + "snapshot_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Artifactory snapshot repository.", + }, + "repository_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the name of your artifactory repository where your docker images are located.", + }, + "repository_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL of your artifactory repository where your docker images are located.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_artifactory", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolArtifactoryValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_artifactory", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolArtifactoryCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("artifactory") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolArtifactory(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolArtifactoryRead(context, d, meta) +} + +func resourceIBMCdToolchainToolArtifactoryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolArtifactory(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolArtifactoryToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolArtifactoryUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolArtifactory(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolArtifactoryRead(context, d, meta) +} + +func resourceIBMCdToolchainToolArtifactoryDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolArtifactoryToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_bitbucketgit.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_bitbucketgit.go new file mode 100644 index 000000000..4cbfd7bc9 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_bitbucketgit.go @@ -0,0 +1,432 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolBitbucketgit() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolBitbucketgitCreate, + ReadContext: resourceIBMCdToolchainToolBitbucketgitRead, + UpdateContext: resourceIBMCdToolchainToolBitbucketgitUpdate, + DeleteContext: resourceIBMCdToolchainToolBitbucketgitDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_bitbucketgit", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "e.g. https://api.bitbucket.org.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Select this check box to enable Bitbucket Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "initialization": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Select this check box to make this repository private.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_bitbucketgit", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolBitbucketgitValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_bitbucketgit", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolBitbucketgitCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("bitbucketgit") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolBitbucketgit(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolBitbucketgitRead(context, d, meta) +} + +func resourceIBMCdToolchainToolBitbucketgitRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolBitbucketgit(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolBitbucketgitToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolBitbucketgitUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolBitbucketgit(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolBitbucketgitRead(context, d, meta) +} + +func resourceIBMCdToolchainToolBitbucketgitDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolBitbucketgitToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_custom.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_custom.go new file mode 100644 index 000000000..c6f5478fb --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_custom.go @@ -0,0 +1,373 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolCustom() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolCustomCreate, + ReadContext: resourceIBMCdToolchainToolCustomRead, + UpdateContext: resourceIBMCdToolchainToolCustomUpdate, + DeleteContext: resourceIBMCdToolchainToolCustomDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_custom", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the name of the tool that you are integrating; for example: Delivery Pipeline.", + }, + "lifecycle_phase": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool.", + }, + "image_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL of the icon to show on your tool integration's card.", + }, + "documentation_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your tool's documentation.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this specific tool integration; for example: My Build and Deploy Pipeline.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the URL that you want to navigate to when you click the tool integration card.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type a description for the tool instance.", + }, + "additional_properties": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "(Advanced) Type any information that is needed to integrate with other tools in your toolchain.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_custom", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolCustomValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_custom", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolCustomCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("customtool") + remapFields := map[string]string{ + "lifecycle_phase": "lifecyclePhase", + "image_url": "imageUrl", + "documentation_url": "documentationUrl", + "additional_properties": "additional-properties", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolCustom(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolCustomRead(context, d, meta) +} + +func resourceIBMCdToolchainToolCustomRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "lifecycle_phase": "lifecyclePhase", + "image_url": "imageUrl", + "documentation_url": "documentationUrl", + "additional_properties": "additional-properties", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolCustom(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolCustomToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolCustomUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "lifecycle_phase": "lifecyclePhase", + "image_url": "imageUrl", + "documentation_url": "documentationUrl", + "additional_properties": "additional-properties", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolCustom(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolCustomRead(context, d, meta) +} + +func resourceIBMCdToolchainToolCustomDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolCustomToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_devopsinsights.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_devopsinsights.go new file mode 100644 index 000000000..09e5ce012 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_devopsinsights.go @@ -0,0 +1,293 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolDevopsinsights() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolDevopsinsightsCreate, + ReadContext: resourceIBMCdToolchainToolDevopsinsightsRead, + UpdateContext: resourceIBMCdToolchainToolDevopsinsightsUpdate, + DeleteContext: resourceIBMCdToolchainToolDevopsinsightsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_devopsinsights", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_devopsinsights", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolDevopsinsightsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_devopsinsights", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolDevopsinsightsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("draservicebroker") + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolDevopsinsightsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolDevopsinsightsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolDevopsinsightsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolDevopsinsightsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolDevopsinsightsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolDevopsinsightsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolDevopsinsightsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubconsolidated.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubconsolidated.go new file mode 100644 index 000000000..6cc610efb --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubconsolidated.go @@ -0,0 +1,445 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolGithubconsolidated() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolGithubconsolidatedCreate, + ReadContext: resourceIBMCdToolchainToolGithubconsolidatedRead, + UpdateContext: resourceIBMCdToolchainToolGithubconsolidatedUpdate, + DeleteContext: resourceIBMCdToolchainToolGithubconsolidatedDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_githubconsolidated", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "e.g. https://api.github.example.com.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Select this check box to enable GitHub Issues for lightweight issue tracking.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "initialization": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Select this check box to make this repository private.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_githubconsolidated", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolGithubconsolidatedValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_githubconsolidated", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolGithubconsolidatedCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("githubconsolidated") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolGithubconsolidated(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolGithubconsolidatedRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGithubconsolidatedRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolGithubconsolidated(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolGithubconsolidatedToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolGithubconsolidatedUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolGithubconsolidated(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolGithubconsolidatedRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGithubconsolidatedDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolGithubconsolidatedToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubintegrated.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubintegrated.go new file mode 100644 index 000000000..a49c0de8c --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_githubintegrated.go @@ -0,0 +1,451 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolGithubintegrated() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolGithubintegratedCreate, + ReadContext: resourceIBMCdToolchainToolGithubintegratedRead, + UpdateContext: resourceIBMCdToolchainToolGithubintegratedUpdate, + DeleteContext: resourceIBMCdToolchainToolGithubintegratedDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_githubintegrated", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "e.g. https://github.ibm.com/api/v3.", + }, + "legal": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Select this check box to enable GitHub Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "initialization": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "legal": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + ForceNew: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Select this check box to make this repository private.", + }, + "auto_init": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Select this checkbox to initialize this repository with a README.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_githubintegrated", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolGithubintegratedValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_githubintegrated", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolGithubintegratedCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("github_integrated") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolGithubintegrated(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolGithubintegratedRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGithubintegratedRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolGithubintegrated(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolGithubintegratedToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolGithubintegratedUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolGithubintegrated(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolGithubintegratedRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGithubintegratedDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolGithubintegratedToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_gitlab.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_gitlab.go new file mode 100644 index 000000000..59ab42a52 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_gitlab.go @@ -0,0 +1,432 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolGitlab() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolGitlabCreate, + ReadContext: resourceIBMCdToolchainToolGitlabRead, + UpdateContext: resourceIBMCdToolchainToolGitlabUpdate, + DeleteContext: resourceIBMCdToolchainToolGitlabDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_gitlab", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "e.g. https://gitlab.example.com/api/v4.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Select this check box to enable GitLab Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "initialization": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + ForceNew: true, + Description: "Select this check box to make this repository private.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_gitlab", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolGitlabValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_gitlab", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolGitlabCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("gitlab") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolGitlab(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolGitlabRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGitlabRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolGitlab(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolGitlabToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolGitlabUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolGitlab(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolGitlabRead(context, d, meta) +} + +func resourceIBMCdToolchainToolGitlabDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolGitlabToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hashicorpvault.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hashicorpvault.go new file mode 100644 index 000000000..e6c4ff0b9 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hashicorpvault.go @@ -0,0 +1,383 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolHashicorpvault() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolHashicorpvaultCreate, + ReadContext: resourceIBMCdToolchainToolHashicorpvaultRead, + UpdateContext: resourceIBMCdToolchainToolHashicorpvaultUpdate, + DeleteContext: resourceIBMCdToolchainToolHashicorpvaultDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_hashicorpvault", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "server_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the server URL for your HashiCorp Vault instance.", + }, + "authentication_method": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Choose the authentication method for your HashiCorp Vault instance.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type or select the authentication token for your HashiCorp Vault instance.", + }, + "role_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type or select the authentication role ID for your HashiCorp Vault instance.", + }, + "secret_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type or select the authentication secret ID for your HashiCorp Vault instance.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile.", + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the mount path where your secrets are stored in your HashiCorp Vault instance.", + }, + "secret_filter": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance.", + }, + "default_secret": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type or select the authentication username for your HashiCorp Vault instance.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type or select the authentication password for your HashiCorp Vault instance.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_hashicorpvault", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolHashicorpvaultValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_hashicorpvault", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolHashicorpvaultCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("hashicorpvault") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolHashicorpvault(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolHashicorpvaultRead(context, d, meta) +} + +func resourceIBMCdToolchainToolHashicorpvaultRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolHashicorpvault(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolHashicorpvaultToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolHashicorpvaultUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolHashicorpvault(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolHashicorpvaultRead(context, d, meta) +} + +func resourceIBMCdToolchainToolHashicorpvaultDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolHashicorpvaultToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hostedgit.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hostedgit.go new file mode 100644 index 000000000..ae733aa1b --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_hostedgit.go @@ -0,0 +1,427 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolHostedgit() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolHostedgitCreate, + ReadContext: resourceIBMCdToolchainToolHostedgitRead, + UpdateContext: resourceIBMCdToolchainToolHostedgitUpdate, + DeleteContext: resourceIBMCdToolchainToolHostedgitDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_hostedgit", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "git_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "api_root_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "e.g. https://gitlab.example.com/api/v4.", + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "token_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Integration token URL.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Select this check box to make this repository private.", + }, + "has_issues": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Select this check box to enable Issues for lightweight issue tracking.", + }, + "enable_traceability": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + }, + "integration_owner": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Select the user which git operations will be performed as.", + }, + }, + }, + }, + "initialization": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are linking to.", + }, + "source_repo_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Type the URL of the repository that you are forking or cloning.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "private_repo": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + ForceNew: true, + Description: "Select this check box to make this repository private.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_hostedgit", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolHostedgitValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_hostedgit", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolHostedgitCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("hostedgit") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolHostedgit(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolHostedgitRead(context, d, meta) +} + +func resourceIBMCdToolchainToolHostedgitRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolHostedgit(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolHostedgitToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolHostedgitUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolHostedgit(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolHostedgitRead(context, d, meta) +} + +func resourceIBMCdToolchainToolHostedgitDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolHostedgitToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_jenkins.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_jenkins.go new file mode 100644 index 000000000..e902103af --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_jenkins.go @@ -0,0 +1,342 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolJenkins() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolJenkinsCreate, + ReadContext: resourceIBMCdToolchainToolJenkinsRead, + UpdateContext: resourceIBMCdToolchainToolJenkinsUpdate, + DeleteContext: resourceIBMCdToolchainToolJenkinsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_jenkins", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain.", + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions.", + }, + "api_user_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance.", + }, + "api_token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_jenkins", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolJenkinsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_jenkins", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolJenkinsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("jenkins") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolJenkins(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolJenkinsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolJenkinsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolJenkins(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolJenkinsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolJenkinsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolJenkins(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolJenkinsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolJenkinsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolJenkinsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_keyprotect.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_keyprotect.go new file mode 100644 index 000000000..e7233ee75 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_keyprotect.go @@ -0,0 +1,347 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolKeyprotect() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolKeyprotectCreate, + ReadContext: resourceIBMCdToolchainToolKeyprotectRead, + UpdateContext: resourceIBMCdToolchainToolKeyprotectUpdate, + DeleteContext: resourceIBMCdToolchainToolKeyprotectDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_keyprotect", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_keyprotect", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolKeyprotectValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_keyprotect", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolKeyprotectCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("keyprotect") + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolKeyprotect(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolKeyprotectRead(context, d, meta) +} + +func resourceIBMCdToolchainToolKeyprotectRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolKeyprotect(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolKeyprotectToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolKeyprotectUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolKeyprotect(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolKeyprotectRead(context, d, meta) +} + +func resourceIBMCdToolchainToolKeyprotectDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolKeyprotectToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_nexus.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_nexus.go new file mode 100644 index 000000000..8a11b9b91 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_nexus.go @@ -0,0 +1,357 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolNexus() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolNexusCreate, + ReadContext: resourceIBMCdToolchainToolNexusRead, + UpdateContext: resourceIBMCdToolchainToolNexusUpdate, + DeleteContext: resourceIBMCdToolchainToolNexusDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_nexus", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL that you want to navigate to when you click the Nexus integration tile.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Choose the type of repository for your Nexus integration.", + }, + "user_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the User ID or email for your Nexus repository.", + }, + "token": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type the password or authentication token for your Nexus repository.", + }, + "release_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Nexus release repository.", + }, + "mirror_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + }, + "snapshot_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL for your Nexus snapshot repository.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_nexus", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolNexusValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_nexus", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolNexusCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("nexus") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolNexus(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolNexusRead(context, d, meta) +} + +func resourceIBMCdToolchainToolNexusRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolNexus(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolNexusToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolNexusUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolNexus(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolNexusRead(context, d, meta) +} + +func resourceIBMCdToolchainToolNexusDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolNexusToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pagerduty.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pagerduty.go new file mode 100644 index 000000000..6a5543f63 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pagerduty.go @@ -0,0 +1,360 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolPagerduty() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolPagerdutyCreate, + ReadContext: resourceIBMCdToolchainToolPagerdutyRead, + UpdateContext: resourceIBMCdToolchainToolPagerdutyUpdate, + DeleteContext: resourceIBMCdToolchainToolPagerdutyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_pagerduty", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Select whether to integrate at the account level with an API key or at the service level with an integration key.", + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key).", + }, + "service_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service.", + }, + "user_email": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user.", + }, + "user_phone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default.", + }, + "service_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Type the URL of the PagerDuty service to post alerts to.", + }, + "service_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page.", + }, + "service_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "service_id.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_pagerduty", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolPagerdutyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_pagerduty", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolPagerdutyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("pagerduty") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolPagerduty(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolPagerdutyRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPagerdutyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolPagerduty(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolPagerdutyToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolPagerdutyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolPagerduty(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolPagerdutyRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPagerdutyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolPagerdutyToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline.go new file mode 100644 index 000000000..1ac5062d8 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline.go @@ -0,0 +1,329 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolPipeline() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolPipelineCreate, + ReadContext: resourceIBMCdToolchainToolPipelineRead, + UpdateContext: resourceIBMCdToolchainToolPipelineUpdate, + DeleteContext: resourceIBMCdToolchainToolPipelineDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_pipeline", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "ui_pipeline": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_pipeline", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolPipelineValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_pipeline", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolPipelineCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("pipeline") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolPipeline(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolPipelineRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPipelineRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolPipeline(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolPipelineToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolPipelineUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolPipeline(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolPipelineRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPipelineDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolPipelineToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline_test.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline_test.go new file mode 100644 index 000000000..9ba3b6fe5 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_pipeline_test.go @@ -0,0 +1,180 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func TestAccIBMCdToolchainToolPipelineBasic(t *testing.T) { + var conf cdtoolchainv2.ToolchainTool + rgID := acc.CdResourceGroupID + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdToolchainToolPipelineDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolPipelineConfigBasic(tcName, rgID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdToolchainToolPipelineExists("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", conf), + resource.TestCheckResourceAttrSet("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", "toolchain_id"), + ), + }, + }, + }) +} + +func TestAccIBMCdToolchainToolPipelineAllArgs(t *testing.T) { + var conf cdtoolchainv2.ToolchainTool + rgID := acc.CdResourceGroupID + tcName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCdToolchainToolPipelineDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolPipelineConfig(tcName, rgID, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCdToolchainToolPipelineExists("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", conf), + resource.TestCheckResourceAttrSet("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", "toolchain_id"), + resource.TestCheckResourceAttr("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", "name", name), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCdToolchainToolPipelineConfig(tcName, rgID, nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", "toolchain_id"), + resource.TestCheckResourceAttr("ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", "name", nameUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCdToolchainToolPipelineConfigBasic(tcName string, rgID string) string { + return fmt.Sprintf(` + + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_pipeline" "cd_toolchain_tool_pipeline" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + type = "tekton" + ui_pipeline = true + } + } + `, tcName, rgID) +} + +func testAccCheckIBMCdToolchainToolPipelineConfig(tcName string, rgID string, name string) string { + return fmt.Sprintf(` + + resource "ibm_cd_toolchain" "cd_toolchain" { + name = "%s" + resource_group_id = "%s" + } + + resource "ibm_cd_toolchain_tool_pipeline" "cd_toolchain_tool_pipeline" { + toolchain_id = ibm_cd_toolchain.cd_toolchain.id + parameters { + name = "name" + type = "tekton" + ui_pipeline = true + } + name = "%s" + } + `, tcName, rgID, name) +} + +func testAccCheckIBMCdToolchainToolPipelineExists(n string, obj cdtoolchainv2.ToolchainTool) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + cdToolchainClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdToolchainV2() + if err != nil { + return err + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + getToolByIDResponse, _, err := cdToolchainClient.GetToolByID(getToolByIDOptions) + if err != nil { + return err + } + + obj = *getToolByIDResponse + return nil + } +} + +func testAccCheckIBMCdToolchainToolPipelineDestroy(s *terraform.State) error { + cdToolchainClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CdToolchainV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cd_toolchain_tool_pipeline" { + continue + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + // Try to find the key + _, response, err := cdToolchainClient.GetToolByID(getToolByIDOptions) + + if err == nil { + return fmt.Errorf("cd_toolchain_tool_pipeline still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cd_toolchain_tool_pipeline (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_privateworker.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_privateworker.go new file mode 100644 index 000000000..9bd5fa5f5 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_privateworker.go @@ -0,0 +1,343 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolPrivateworker() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolPrivateworkerCreate, + ReadContext: resourceIBMCdToolchainToolPrivateworkerRead, + UpdateContext: resourceIBMCdToolchainToolPrivateworkerUpdate, + DeleteContext: resourceIBMCdToolchainToolPrivateworkerDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_privateworker", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain.", + }, + "worker_queue_credentials": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue.", + }, + "worker_queue_identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_privateworker", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolPrivateworkerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_privateworker", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolPrivateworkerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("private_worker") + remapFields := map[string]string{ + "worker_queue_credentials": "workerQueueCredentials", + "worker_queue_identifier": "workerQueueIdentifier", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolPrivateworker(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolPrivateworkerRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPrivateworkerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "worker_queue_credentials": "workerQueueCredentials", + "worker_queue_identifier": "workerQueueIdentifier", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolPrivateworker(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolPrivateworkerToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolPrivateworkerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "worker_queue_credentials": "workerQueueCredentials", + "worker_queue_identifier": "workerQueueIdentifier", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolPrivateworker(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolPrivateworkerRead(context, d, meta) +} + +func resourceIBMCdToolchainToolPrivateworkerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolPrivateworkerToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_saucelabs.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_saucelabs.go new file mode 100644 index 000000000..cb28c36db --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_saucelabs.go @@ -0,0 +1,327 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolSaucelabs() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolSaucelabsCreate, + ReadContext: resourceIBMCdToolchainToolSaucelabsRead, + UpdateContext: resourceIBMCdToolchainToolSaucelabsUpdate, + DeleteContext: resourceIBMCdToolchainToolSaucelabsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_saucelabs", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "username": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the user name for your Sauce Labs account.", + }, + "key": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_saucelabs", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolSaucelabsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_saucelabs", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolSaucelabsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("saucelabs") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolSaucelabs(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolSaucelabsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSaucelabsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolSaucelabs(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolSaucelabsToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolSaucelabsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolSaucelabs(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolSaucelabsRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSaucelabsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolSaucelabsToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_secretsmanager.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_secretsmanager.go new file mode 100644 index 000000000..a31dbb2ea --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_secretsmanager.go @@ -0,0 +1,347 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolSecretsmanager() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolSecretsmanagerCreate, + ReadContext: resourceIBMCdToolchainToolSecretsmanagerRead, + UpdateContext: resourceIBMCdToolchainToolSecretsmanagerUpdate, + DeleteContext: resourceIBMCdToolchainToolSecretsmanagerDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_secretsmanager", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Enter a name for this tool integration. This name is displayed on your toolchain.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Region.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Resource group.", + }, + "instance_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_secretsmanager", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolSecretsmanagerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_secretsmanager", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolSecretsmanagerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("secretsmanager") + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolSecretsmanager(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolSecretsmanagerRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSecretsmanagerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolSecretsmanager(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolSecretsmanagerToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolSecretsmanagerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "resource_group": "resource-group", + "instance_name": "instance-name", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolSecretsmanager(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolSecretsmanagerRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSecretsmanagerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolSecretsmanagerToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_securitycompliance.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_securitycompliance.go new file mode 100644 index 000000000..a3534468d --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_securitycompliance.go @@ -0,0 +1,371 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolSecuritycompliance() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolSecuritycomplianceCreate, + ReadContext: resourceIBMCdToolchainToolSecuritycomplianceRead, + UpdateContext: resourceIBMCdToolchainToolSecuritycomplianceUpdate, + DeleteContext: resourceIBMCdToolchainToolSecuritycomplianceDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_securitycompliance", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Give this tool integration a name, for example: my-security-compliance.", + }, + "evidence_repo_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker.", + }, + "trigger_scan": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Enabling trigger validation scans provides details for a pipeline task to trigger a scan.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "evidence_namespace": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence.", + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once).", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + }, + "profile": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + }, + "trigger_info": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Computed: true, + Description: "trigger_info.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_securitycompliance", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolSecuritycomplianceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_securitycompliance", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolSecuritycomplianceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("security_compliance") + remapFields := map[string]string{ + "api_key": "api-key", + } + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolSecuritycompliance(), remapFields) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolSecuritycomplianceRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSecuritycomplianceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + remapFields := map[string]string{ + "api_key": "api-key", + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolSecuritycompliance(), remapFields) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolSecuritycomplianceToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolSecuritycomplianceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + remapFields := map[string]string{ + "api_key": "api-key", + } + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolSecuritycompliance(), remapFields) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolSecuritycomplianceRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSecuritycomplianceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolSecuritycomplianceToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_slack.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_slack.go new file mode 100644 index 000000000..71da89f87 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_slack.go @@ -0,0 +1,357 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolSlack() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolSlackCreate, + ReadContext: resourceIBMCdToolchainToolSlackRead, + UpdateContext: resourceIBMCdToolchainToolSlackUpdate, + DeleteContext: resourceIBMCdToolchainToolSlackDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_slack", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_token": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + Description: "Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead.", + }, + "channel_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "If you use a webhook, you must specify an existing Slack channel to post notifications to.", + }, + "team_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_.", + }, + "pipeline_start": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "pipeline_success": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "pipeline_fail": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "toolchain_bind": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "toolchain_unbind": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_slack", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolSlackValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_slack", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolSlackCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("slack") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolSlack(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolSlackRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSlackRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolSlack(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolSlackToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolSlackUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolSlack(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolSlackRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSlackDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolSlackToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_sonarqube.go b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_sonarqube.go new file mode 100644 index 000000000..27839f325 --- /dev/null +++ b/ibm/service/cdtoolchain/resource_ibm_cd_toolchain_tool_sonarqube.go @@ -0,0 +1,342 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cdtoolchain + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/continuous-delivery-go-sdk/cdtoolchainv2" +) + +func ResourceIBMCdToolchainToolSonarqube() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCdToolchainToolSonarqubeCreate, + ReadContext: resourceIBMCdToolchainToolSonarqubeRead, + UpdateContext: resourceIBMCdToolchainToolSonarqubeUpdate, + DeleteContext: resourceIBMCdToolchainToolSonarqubeDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "toolchain_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_sonarqube", "toolchain_id"), + Description: "ID of the toolchain to bind the tool to.", + }, + "parameters": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Unique key-value pairs representing parameters to be used to create the tool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain.", + }, + "dashboard_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain.", + }, + "user_login": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "If you are using an authentication token, leave this field empty.", + }, + "user_password": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.SuppressHashedRawSecret, + Sensitive: true, + }, + "blind_connection": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cd_toolchain_tool_sonarqube", "name"), + Description: "Name of tool.", + }, + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group where tool can be found.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool CRN.", + }, + "toolchain_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "CRN of toolchain which the tool is bound to.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI representing the tool.", + }, + "referent": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information on URIs to access this resource through the UI or API.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ui_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through the UI.", + }, + "api_href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "URI representing the this resource through an API.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Latest tool update timestamp.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Current configuration state of the tool.", + }, + "tool_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Tool ID.", + }, + }, + } +} + +func ResourceIBMCdToolchainToolSonarqubeValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "toolchain_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([^\x00-\x7F]|[a-zA-Z0-9-._ ])+$`, + MinValueLength: 0, + MaxValueLength: 128, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cd_toolchain_tool_sonarqube", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCdToolchainToolSonarqubeCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + createToolOptions := &cdtoolchainv2.CreateToolOptions{} + + createToolOptions.SetToolchainID(d.Get("toolchain_id").(string)) + createToolOptions.SetToolTypeID("sonarqube") + parametersModel := GetParametersForCreate(d, ResourceIBMCdToolchainToolSonarqube(), nil) + createToolOptions.SetParameters(parametersModel) + if _, ok := d.GetOk("name"); ok { + createToolOptions.SetName(d.Get("name").(string)) + } + + toolchainToolPost, response, err := cdToolchainClient.CreateToolWithContext(context, createToolOptions) + if err != nil { + log.Printf("[DEBUG] CreateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateToolWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createToolOptions.ToolchainID, *toolchainToolPost.ID)) + + return resourceIBMCdToolchainToolSonarqubeRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSonarqubeRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions := &cdtoolchainv2.GetToolByIDOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getToolByIDOptions.SetToolchainID(parts[0]) + getToolByIDOptions.SetToolID(parts[1]) + + toolchainTool, response, err := cdToolchainClient.GetToolByIDWithContext(context, getToolByIDOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetToolByIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetToolByIDWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("toolchain_id", toolchainTool.ToolchainID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_id: %s", err)) + } + parametersMap := GetParametersFromRead(toolchainTool.Parameters, ResourceIBMCdToolchainToolSonarqube(), nil) + if err = d.Set("parameters", []map[string]interface{}{parametersMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting parameters: %s", err)) + } + if err = d.Set("name", toolchainTool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("resource_group_id", toolchainTool.ResourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + } + if err = d.Set("crn", toolchainTool.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("toolchain_crn", toolchainTool.ToolchainCRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting toolchain_crn: %s", err)) + } + if err = d.Set("href", toolchainTool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + referentMap, err := resourceIBMCdToolchainToolSonarqubeToolModelReferentToMap(toolchainTool.Referent) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("referent", []map[string]interface{}{referentMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referent: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(toolchainTool.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("state", toolchainTool.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("tool_id", toolchainTool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tool_id: %s", err)) + } + + return nil +} + +func resourceIBMCdToolchainToolSonarqubeUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions := &cdtoolchainv2.UpdateToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateToolOptions.SetToolchainID(parts[0]) + updateToolOptions.SetToolID(parts[1]) + + hasChange := false + + patchVals := &cdtoolchainv2.ToolchainToolPrototypePatch{} + if d.HasChange("toolchain_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "toolchain_id")) + } + if d.HasChange("parameters") { + parameters := GetParametersForUpdate(d, ResourceIBMCdToolchainToolSonarqube(), nil) + patchVals.Parameters = parameters + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateToolOptions.ToolchainToolPrototypePatch, _ = patchVals.AsPatch() + _, response, err := cdToolchainClient.UpdateToolWithContext(context, updateToolOptions) + if err != nil { + log.Printf("[DEBUG] UpdateToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateToolWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMCdToolchainToolSonarqubeRead(context, d, meta) +} + +func resourceIBMCdToolchainToolSonarqubeDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cdToolchainClient, err := meta.(conns.ClientSession).CdToolchainV2() + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions := &cdtoolchainv2.DeleteToolOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteToolOptions.SetToolchainID(parts[0]) + deleteToolOptions.SetToolID(parts[1]) + + response, err := cdToolchainClient.DeleteToolWithContext(context, deleteToolOptions) + if err != nil { + log.Printf("[DEBUG] DeleteToolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteToolWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCdToolchainToolSonarqubeToolModelReferentToMap(model *cdtoolchainv2.ToolModelReferent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.UIHref != nil { + modelMap["ui_href"] = model.UIHref + } + if model.APIHref != nil { + modelMap["api_href"] = model.APIHref + } + return modelMap, nil +} diff --git a/ibm/service/cdtoolchain/toolchain_utils.go b/ibm/service/cdtoolchain/toolchain_utils.go new file mode 100644 index 000000000..c181655f5 --- /dev/null +++ b/ibm/service/cdtoolchain/toolchain_utils.go @@ -0,0 +1,64 @@ +package cdtoolchain + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func GetParametersForCreate(d *schema.ResourceData, resource *schema.Resource, remapFields map[string]string) map[string]interface{} { + params := make(map[string]interface{}) + + if _, ok := d.GetOk("parameters"); ok { + srcParams := d.Get("parameters.0").(map[string]interface{}) + parametersSchema := resource.Schema["parameters"].Elem.(*schema.Resource).Schema + for key, element := range parametersSchema { + if !element.Computed && srcParams[key] != nil { + params[getTargetField(key, remapFields)] = srcParams[key] + } + } + } + + if _, ok := d.GetOk("initialization"); ok { + srcInit := d.Get("initialization.0").(map[string]interface{}) + initSchema := resource.Schema["initialization"].Elem.(*schema.Resource).Schema + for key, _ := range initSchema { + if srcInit[key] != nil { + params[getTargetField(key, remapFields)] = srcInit[key] + } + } + } + + return params +} + +func GetParametersForUpdate(d *schema.ResourceData, resource *schema.Resource, remapFields map[string]string) map[string]interface{} { + params := make(map[string]interface{}) + srcParams := d.Get("parameters.0").(map[string]interface{}) + parametersSchema := resource.Schema["parameters"].Elem.(*schema.Resource).Schema + for key, element := range parametersSchema { + if !element.Computed && srcParams[key] != nil && d.HasChange("parameters.0."+key) { + params[getTargetField(key, remapFields)] = srcParams[key] + } + } + return params +} + +func GetParametersFromRead(readParams map[string]interface{}, resource *schema.Resource, remapFields map[string]string) map[string]interface{} { + params := make(map[string]interface{}) + parametersSchema := resource.Schema["parameters"].Elem.(*schema.Resource).Schema + for key := range parametersSchema { + readKey := getTargetField(key, remapFields) + if readParams[readKey] != nil { + params[key] = readParams[readKey] + } + } + return params +} + +func getTargetField(field string, remapFields map[string]string) string { + if remapFields != nil { + if val, ok := remapFields[field]; ok { + return val + } + } + return field +} diff --git a/ibm/service/certificatemanager/README.md b/ibm/service/certificatemanager/README.md new file mode 100644 index 000000000..24312adf0 --- /dev/null +++ b/ibm/service/certificatemanager/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Certificate Manager + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Certificate Manager resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/certificate_manager_import) +* IBM Docs: [IBM Docs for Certificate Manager](https://cloud.ibm.com/docs/certificate-manager?topic=certificate-manager-ordering-certificates) +* IBM Certificate Manager SDK: [IBM SDK for Certificate Manager](https://github.com/IBM-Cloud/bluemix-go/tree/master/api/certificatemanager) diff --git a/ibm/data_source_ibm_certificate_manager_certificate.go b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate.go similarity index 95% rename from ibm/data_source_ibm_certificate_manager_certificate.go rename to ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate.go index eec8208aa..ac43971b2 100644 --- a/ibm/data_source_ibm_certificate_manager_certificate.go +++ b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager import ( "fmt" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataIBMCertificateManagerCertificate() *schema.Resource { +func DataIBMCertificateManagerCertificate() *schema.Resource { return &schema.Resource{ Read: dataIBMCertificateManagerCertificateRead, Schema: map[string]*schema.Schema{ @@ -92,7 +93,7 @@ func dataIBMCertificateManagerCertificate() *schema.Resource { } } func dataIBMCertificateManagerCertificateRead(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_certificate_manager_certificate_test.go b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate_test.go similarity index 95% rename from ibm/data_source_ibm_certificate_manager_certificate_test.go rename to ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate_test.go index abfd7aa1f..1ad9277bc 100644 --- a/ibm/data_source_ibm_certificate_manager_certificate_test.go +++ b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificate_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,9 +16,9 @@ import ( func TestAccIBMCertificateManagerCertificateDataSource_Basic(t *testing.T) { cmsName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerCertificateDataSourceConfig_basic(cmsName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_certificate_manager_certificate.certificate", "id"), diff --git a/ibm/data_source_ibm_certificate_manager_certificates.go b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates.go similarity index 94% rename from ibm/data_source_ibm_certificate_manager_certificates.go rename to ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates.go index 018e25bb0..319499232 100644 --- a/ibm/data_source_ibm_certificate_manager_certificates.go +++ b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager import ( "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataIBMCertificateManagerCertificates() *schema.Resource { +func DataIBMCertificateManagerCertificates() *schema.Resource { return &schema.Resource{ Read: dataIBMCertificateManagerCertificatesRead, Schema: map[string]*schema.Schema{ @@ -84,7 +85,7 @@ func dataIBMCertificateManagerCertificates() *schema.Resource { } } func dataIBMCertificateManagerCertificatesRead(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_certificate_manager_certificates_test.go b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates_test.go similarity index 89% rename from ibm/data_source_ibm_certificate_manager_certificates_test.go rename to ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates_test.go index ed09d2172..d8f76cc06 100644 --- a/ibm/data_source_ibm_certificate_manager_certificates_test.go +++ b/ibm/service/certificatemanager/data_source_ibm_certificate_manager_certificates_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,9 +16,9 @@ import ( func TestAccIBMCertificateManagerCertificatesDataSource_Basic(t *testing.T) { cmsName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerCertificatesDataSourceConfig_basic(cmsName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_certificate_manager_certificates.certs", "id"), diff --git a/ibm/resource_ibm_certificate_manager_import.go b/ibm/service/certificatemanager/resource_ibm_certificate_manager_import.go similarity index 89% rename from ibm/resource_ibm_certificate_manager_import.go rename to ibm/service/certificatemanager/resource_ibm_certificate_manager_import.go index c96e98977..c1ff1e226 100644 --- a/ibm/resource_ibm_certificate_manager_import.go +++ b/ibm/service/certificatemanager/resource_ibm_certificate_manager_import.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager import ( "fmt" @@ -11,9 +11,10 @@ import ( "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) -func resourceIBMCertificateManagerImport() *schema.Resource { +func ResourceIBMCertificateManagerImport() *schema.Resource { return &schema.Resource{ Create: resourceIBMCertificateManagerImportCertificate, Read: resourceIBMCertificateManagerGet, @@ -83,7 +84,7 @@ func resourceIBMCertificateManagerImport() *schema.Resource { func resourceIBMCertificateManagerImportCertificate(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -117,13 +118,15 @@ func resourceIBMCertificateManagerImportCertificate(d *schema.ResourceData, meta return resourceIBMCertificateManagerUpdate(d, meta) } func resourceIBMCertificateManagerGet(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } certID := d.Id() certificatedata, err := cmService.Certificate().GetCertData(certID) - + if err != nil { + return fmt.Errorf("[ERROR] Error getting certificate during import: %s", err) + } cminstanceid := strings.Split(certID, ":certificate:") d.Set("certificate_manager_instance_id", cminstanceid[0]+"::") d.Set("name", certificatedata.Name) @@ -153,7 +156,7 @@ func resourceIBMCertificateManagerGet(d *schema.ResourceData, meta interface{}) } func resourceIBMCertificateManagerUpdate(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -192,14 +195,14 @@ func resourceIBMCertificateManagerUpdate(d *schema.ResourceData, meta interface{ return resourceIBMCertificateManagerGet(d, meta) } func resourceIBMCertificateManagerDelete(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } certID := d.Id() err = cmService.Certificate().DeleteCertificate(certID) if err != nil { - return fmt.Errorf("Error deleting Certificate: %s", err) + return fmt.Errorf("[ERROR] Error deleting Certificate: %s", err) } d.SetId("") @@ -207,7 +210,7 @@ func resourceIBMCertificateManagerDelete(d *schema.ResourceData, meta interface{ } func resourceIBMCertificateManagerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return false, err } @@ -221,7 +224,7 @@ func resourceIBMCertificateManagerExists(d *schema.ResourceData, meta interface{ return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error gettting certificate details in exists %s", err) } return true, nil diff --git a/ibm/resource_ibm_certificate_manager_import_test.go b/ibm/service/certificatemanager/resource_ibm_certificate_manager_import_test.go similarity index 87% rename from ibm/resource_ibm_certificate_manager_import_test.go rename to ibm/service/certificatemanager/resource_ibm_certificate_manager_import_test.go index d64c440b4..3b52d9c08 100644 --- a/ibm/resource_ibm_certificate_manager_import_test.go +++ b/ibm/service/certificatemanager/resource_ibm_certificate_manager_import_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,11 +23,11 @@ func TestAccIBMCertificateManager_Basic(t *testing.T) { name1 := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) name2 := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCertificateManagerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManager_basicImport(name1, name2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMExists("ibm_certificate_manager_import.cert", conf), @@ -41,7 +44,7 @@ func testAccCheckIBMCertificateManagerDestroy(s *terraform.State) error { continue } certID := rs.Primary.ID - cmClient, err := testAccProvider.Meta().(ClientSession).CertificateManagerAPI() + cmClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -49,7 +52,7 @@ func testAccCheckIBMCertificateManagerDestroy(s *terraform.State) error { _, err = certAPI.GetCertData(certID) if err != nil && !strings.Contains(err.Error(), "404") && !strings.Contains(err.Error(), "412") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -60,11 +63,11 @@ func TestAccIBMCertificateManager_Import(t *testing.T) { name1 := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) name2 := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCertificateManagerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManager_basicImport(name1, name2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMExists("ibm_certificate_manager_import.cert", conf), @@ -72,7 +75,7 @@ func TestAccIBMCertificateManager_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_certificate_manager_import.cert", ImportState: true, ImportStateVerify: true, @@ -129,7 +132,7 @@ func testAccCheckIBMCMExists(n string, obj models.CertificateGetData) resource.T return fmt.Errorf("Not found: %s", n) } - cmClient, err := testAccProvider.Meta().(ClientSession).CertificateManagerAPI() + cmClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } diff --git a/ibm/resource_ibm_certificate_manager_order.go b/ibm/service/certificatemanager/resource_ibm_certificate_manager_order.go similarity index 87% rename from ibm/resource_ibm_certificate_manager_order.go rename to ibm/service/certificatemanager/resource_ibm_certificate_manager_order.go index 72a3a550d..86fbf8b57 100644 --- a/ibm/resource_ibm_certificate_manager_order.go +++ b/ibm/service/certificatemanager/resource_ibm_certificate_manager_order.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager import ( "fmt" @@ -14,9 +14,11 @@ import ( "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMCertificateManagerOrder() *schema.Resource { +func ResourceIBMCertificateManagerOrder() *schema.Resource { return &schema.Resource{ Create: resourceIBMCertificateManagerOrderCertificate, Read: resourceIBMCertificateManagerRead, @@ -85,7 +87,7 @@ func resourceIBMCertificateManagerOrder() *schema.Resource { Optional: true, Default: "rsaEncryption 2048 bit", Description: "Keyalgorithm info", - ValidateFunc: validateAllowedStringValue([]string{"rsaEncryption 2048 bit", "rsaEncryption 4096 bit"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"rsaEncryption 2048 bit", "rsaEncryption 4096 bit"}), }, "auto_renew_enabled": { Type: schema.TypeBool, @@ -132,7 +134,7 @@ func resourceIBMCertificateManagerOrder() *schema.Resource { func resourceIBMCertificateManagerOrderCertificate(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -169,14 +171,13 @@ func resourceIBMCertificateManagerOrderCertificate(d *schema.ResourceData, meta _, err = waitForCertificateOrder(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for Ordering Certificate (%s) to be succeeded: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for Ordering Certificate (%s) to be succeeded: %s", d.Id(), err) } return resourceIBMCertificateManagerRead(d, meta) } func resourceIBMCertificateManagerRead(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -224,7 +225,7 @@ func resourceIBMCertificateManagerRead(d *schema.ResourceData, meta interface{}) } func resourceIBMCertificateManagerRenew(d *schema.ResourceData, meta interface{}) error { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -261,13 +262,12 @@ func resourceIBMCertificateManagerRenew(d *schema.ResourceData, meta interface{} } _, err = waitForCertificateRenew(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for Renew Certificate (%s) to be succeeded: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for Renew Certificate (%s) to be succeeded: %s", d.Id(), err) } return resourceIBMCertificateManagerRead(d, meta) } func waitForCertificateOrder(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return false, err } @@ -280,12 +280,12 @@ func waitForCertificateOrder(d *schema.ResourceData, meta interface{}) (interfac getcert, err := cmService.Certificate().GetMetaData(certID) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The certificate %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The certificate %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } if getcert.Status == "failed" { - return getcert, getcert.Status, fmt.Errorf("The certificate %s failed: %v", d.Id(), err) + return getcert, getcert.Status, fmt.Errorf("[ERROR] The certificate %s failed: %v", d.Id(), err) } return getcert, getcert.Status, nil }, @@ -297,7 +297,7 @@ func waitForCertificateOrder(d *schema.ResourceData, meta interface{}) (interfac return stateConf.WaitForState() } func waitForCertificateRenew(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cmService, err := meta.(ClientSession).CertificateManagerAPI() + cmService, err := meta.(conns.ClientSession).CertificateManagerAPI() if err != nil { return false, err } @@ -310,12 +310,12 @@ func waitForCertificateRenew(d *schema.ResourceData, meta interface{}) (interfac getcert, err := cmService.Certificate().GetMetaData(certID) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The certificate %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The certificate %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } if getcert.Status == "failed" { - return getcert, getcert.Status, fmt.Errorf("The certificate %s failed: %v", d.Id(), err) + return getcert, getcert.Status, fmt.Errorf("[ERROR] The certificate %s failed: %v", d.Id(), err) } return getcert, getcert.Status, nil }, diff --git a/ibm/resource_ibm_certificate_manager_order_test.go b/ibm/service/certificatemanager/resource_ibm_certificate_manager_order_test.go similarity index 91% rename from ibm/resource_ibm_certificate_manager_order_test.go rename to ibm/service/certificatemanager/resource_ibm_certificate_manager_order_test.go index 9b8b05063..9011aabb5 100644 --- a/ibm/resource_ibm_certificate_manager_order_test.go +++ b/ibm/service/certificatemanager/resource_ibm_certificate_manager_order_test.go @@ -1,14 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package certificatemanager_test import ( "fmt" "strings" "testing" + "time" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -22,18 +26,18 @@ func TestAccIBMCertificateManagerOrder_Import(t *testing.T) { updatedName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) cmsName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCertificateManagerOrderDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerOrder_basic(cmsName, orderName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMOrderExists("ibm_certificate_manager_order.cert", conf), resource.TestCheckResourceAttr("ibm_certificate_manager_order.cert", "name", orderName), ), }, - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerOrder_Update(cmsName, updatedName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMOrderExists("ibm_certificate_manager_order.cert", conf), @@ -42,7 +46,7 @@ func TestAccIBMCertificateManagerOrder_Import(t *testing.T) { resource.TestCheckResourceAttr("ibm_certificate_manager_order.cert", "renew_certificate", "true"), ), }, - resource.TestStep{ + { ResourceName: "ibm_certificate_manager_order.cert", ImportState: true, ImportStateVerify: true, @@ -59,11 +63,11 @@ func TestAccIBMCertificateManagerOrder_Basic(t *testing.T) { updatedName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) cmsName := fmt.Sprintf("tf-acc-test1-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCertificateManagerOrderDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerOrder_basic(cmsName, orderName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMOrderExists("ibm_certificate_manager_order.cert", conf), @@ -71,7 +75,7 @@ func TestAccIBMCertificateManagerOrder_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_certificate_manager_order.cert", "auto_renew_enabled", "false"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMCertificateManagerOrder_Update(cmsName, updatedName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCMOrderExists("ibm_certificate_manager_order.cert", conf), @@ -91,7 +95,7 @@ func testAccCheckIBMCertificateManagerOrderDestroy(s *terraform.State) error { continue } certID := rs.Primary.ID - cmClient, err := testAccProvider.Meta().(ClientSession).CertificateManagerAPI() + cmClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } @@ -99,7 +103,7 @@ func testAccCheckIBMCertificateManagerOrderDestroy(s *terraform.State) error { _, err = certAPI.GetCertData(certID) if err != nil && !strings.Contains(err.Error(), "404") && !strings.Contains(err.Error(), "412") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -180,7 +184,7 @@ func testAccCheckIBMCMOrderExists(n string, obj models.CertificateInfo) resource return fmt.Errorf("Not found: %s", n) } - cmClient, err := testAccProvider.Meta().(ClientSession).CertificateManagerAPI() + cmClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CertificateManagerAPI() if err != nil { return err } diff --git a/ibm/service/cis/README.md b/ibm/service/cis/README.md new file mode 100644 index 000000000..91c7dc5c6 --- /dev/null +++ b/ibm/service/cis/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Cloud Internet Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the CIS resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cis) +* IBM API Docs: [IBM API Docs for CIS](https://cloud.ibm.com/apidocs/cis) +* IBM CIS SDK: [IBM SDK for CIS](https://github.com/IBM/networking-go-sdk/) diff --git a/ibm/service/cis/data_source_ibm_cis.go b/ibm/service/cis/data_source_ibm_cis.go new file mode 100644 index 000000000..f96193afe --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis.go @@ -0,0 +1,195 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func DataSourceIBMCISInstance() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISInstanceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Resource instance name for example, my cis instance", + Type: schema.TypeString, + Required: true, + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the resource group in which the cis instance is present", + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier of resource instance", + }, + + "location": { + Description: "The location or the environment in which cis instance exists", + Type: schema.TypeString, + Computed: true, + }, + + "service": { + Description: "The name of the Cloud Internet Services offering, 'internet-svcs'", + Type: schema.TypeString, + Computed: true, + }, + + "plan": { + Description: "The plan type of the cis instance", + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Description: "The resource instance status", + Type: schema.TypeString, + Computed: true, + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} + +func dataSourceIBMCISInstanceRead(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() + if err != nil { + return err + } + rsAPI := rsConClient.ResourceServiceInstanceV2() + name := d.Get("name").(string) + + rsInstQuery := controllerv2.ServiceInstanceQuery{ + Name: name, + } + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rsInstQuery.ResourceGroupID = rsGrpID.(string) + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInstQuery.ResourceGroupID = defaultRg + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + if service, ok := d.GetOk("service"); ok { + + serviceOff, err := rsCatRepo.FindByName(service.(string), true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + rsInstQuery.ServiceID = serviceOff[0].ID + } + + var instances []models.ServiceInstanceV2 + + instances, err = rsAPI.ListInstances(rsInstQuery) + if err != nil { + return err + } + var filteredInstances []models.ServiceInstanceV2 + var location string + + if loc, ok := d.GetOk("location"); ok { + location = loc.(string) + for _, instance := range instances { + if flex.GetLocation(instance) == location { + filteredInstances = append(filteredInstances, instance) + } + } + } else { + filteredInstances = instances + } + + if len(filteredInstances) == 0 { + return fmt.Errorf("[ERROR] No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + + var instance models.ServiceInstanceV2 + + if len(filteredInstances) > 1 { + return fmt.Errorf("[ERROR] More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + instance = filteredInstances[0] + + d.SetId(instance.ID) + d.Set("status", instance.State) + d.Set("resource_group_id", instance.ResourceGroupID) + d.Set("location", instance.RegionID) + d.Set("guid", instance.Guid) + serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + d.Set("service", serviceOff) + + servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.Crn.String()) + d.Set(flex.ResourceStatus, instance.State) + d.Set(flex.ResourceGroupName, instance.ResourceGroupName) + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/internet-svcs/"+url.QueryEscape(instance.Crn.String())) + + return nil +} diff --git a/ibm/service/cis/data_source_ibm_cis_alert_webhooks.go b/ibm/service/cis/data_source_ibm_cis_alert_webhooks.go new file mode 100644 index 000000000..dd731d6c3 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_alert_webhooks.go @@ -0,0 +1,112 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cisWebhookList = "cis_webhooks" + +func DataSourceIBMCISWebhooks() *schema.Resource { + return &schema.Resource{ + Read: dataIBMCISWebhookRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_webhooks", + "cis_id"), + }, + cisWebhookList: { + Type: schema.TypeList, + Description: "Collection of Webhook details", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisWebhookID: { + Type: schema.TypeString, + Computed: true, + Description: "Webhook ID", + }, + cisWebhookName: { + Type: schema.TypeString, + Computed: true, + Description: "Webhook Name", + }, + cisWebhookURL: { + Type: schema.TypeString, + Computed: true, + Description: "Webhook URL", + }, + cisWebhookType: { + Type: schema.TypeString, + Computed: true, + Description: "Webhook Type", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISAlertWebhooksValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISAlertWebhooksValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_webhooks", + Schema: validateSchema} + return &iBMCISAlertWebhooksValidator +} +func dataIBMCISWebhookRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisWebhookSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the cisWebhookession %s", err) + } + crn := d.Get(cisID).(string) + sess.Crn = core.StringPtr(crn) + opt := sess.NewListWebhooksOptions() + + result, resp, err := sess.ListWebhooks(opt) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error Listing all Webhooks %q: %s %s", d.Id(), err, resp) + } + + webhooks := make([]map[string]interface{}, 0) + + for _, instance := range result.Result { + webhook := map[string]interface{}{} + webhook[cisWebhookID] = *instance.ID + webhook[cisWebhookName] = *instance.Name + webhook[cisWebhookURL] = *instance.URL + webhook[cisWebhookType] = *instance.Type + webhooks = append(webhooks, webhook) + } + d.SetId(dataSourcecisWebhookCheckID(d)) + d.Set(cisID, crn) + d.Set(cisWebhookList, webhooks) + return nil +} + +func dataSourcecisWebhookCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_alert_webhooks_test.go b/ibm/service/cis/data_source_ibm_cis_alert_webhooks_test.go new file mode 100644 index 000000000..3298aa20b --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_alert_webhooks_test.go @@ -0,0 +1,36 @@ +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisWebhookskDataSource_basic(t *testing.T) { + node := "data.ibm_cis_webhooks.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCisWebhooksDataSourceConfig("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "cis_webhooks.0.name"), + resource.TestCheckResourceAttrSet(node, "cis_webhooks.0.url"), + resource.TestCheckResourceAttrSet(node, "cis_webhooks.0.type"), + ), + }, + }, + }) +} + +func testAccCheckIBMCisWebhooksDataSourceConfig(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_webhooks" "%[1]s" { + cis_id = data.ibm_cis.cis.id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/service/cis/data_source_ibm_cis_alerts.go b/ibm/service/cis/data_source_ibm_cis_alerts.go new file mode 100644 index 000000000..58d33b458 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_alerts.go @@ -0,0 +1,191 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/networking-go-sdk/alertsv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisAlerts = "alert_policies" +) + +func DataSourceIBMCISAlert() *schema.Resource { + return &schema.Resource{ + Read: dataIBMCISAlertPolicyRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_alerts", + "cis_id"), + }, + cisAlerts: { + Type: schema.TypeList, + Computed: true, + Description: "Container for response information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisAlertID: { + Type: schema.TypeString, + Computed: true, + Description: "Policy ID", + }, + cisAlertName: { + Type: schema.TypeString, + Computed: true, + Description: "Policy name", + }, + cisAlertDescription: { + Type: schema.TypeString, + Computed: true, + Description: "Policy Description", + }, + cisAlertEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Is the alert policy active", + }, + cisAlertType: { + Type: schema.TypeString, + Computed: true, + Description: "Condition for the alert", + }, + cisAlertMechanisms: { + Type: schema.TypeList, + Computed: true, + Description: "Delivery mechanisms for the alert, can include an email, a webhook, or both.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisAlertEmail: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + cisAlertWebhook: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + }, + }, + }, + cisAlertFilters: { + Type: schema.TypeString, + Computed: true, + Description: "Filters based on filter type", + }, + cisAlertConditions: { + Type: schema.TypeString, + Computed: true, + Description: "Conditions based on filter type", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISAlertsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISAlertsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_alerts", + Schema: validateSchema} + return &iBMCISAlertsValidator +} +func dataIBMCISAlertPolicyRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisAlertsSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + sess.Crn = core.StringPtr(crn) + + opt := sess.NewGetAlertPoliciesOptions() + result, resp, err := sess.GetAlertPolicies(opt) + if err != nil { + log.Printf("[WARN] List all alerts failed: %v\n", resp) + return err + } + alertList := make([]map[string]interface{}, 0) + for _, alertObj := range result.Result { + alertOutput := map[string]interface{}{} + alertOutput[cisAlertID] = *alertObj.ID + alertOutput[cisAlertName] = *alertObj.Name + alertOutput[cisAlertDescription] = *alertObj.Description + alertOutput[cisAlertEnabled] = *alertObj.Enabled + alertOutput[cisAlertType] = *alertObj.AlertType + filterOpt, err := json.Marshal(alertObj.Filters) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling the created filters: %s", err) + } + alertOutput[cisAlertFilters] = string(filterOpt) + conditionsOpt, err := json.Marshal(alertObj.Conditions) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling the created Conditions: %s", err) + } + alertOutput[cisAlertConditions] = string(conditionsOpt) + alertOutput[cisAlertMechanisms] = dataflattenCISMechanism(*alertObj.Mechanisms) + alertList = append(alertList, alertOutput) + + } + d.SetId(dataSourceCISAlertsCheckID(d)) + d.Set(cisID, crn) + + d.Set(cisAlerts, alertList) + return nil +} +func dataSourceCISAlertsCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} +func dataflattenCISMechanism(Mechanism alertsv1.ListAlertPoliciesRespResultItemMechanisms) interface{} { + emailoutput := []string{} + webhookoutput := []string{} + + output := map[string]interface{}{} + flatten := []map[string]interface{}{} + + for _, mech := range Mechanism.Email { + emailoutput = append(emailoutput, *mech.ID) + } + + for _, mech := range Mechanism.Webhooks { + webhookoutput = append(webhookoutput, *mech.ID) + } + + output[cisAlertEmail] = emailoutput + output[cisAlertWebhook] = webhookoutput + + flatten = append(flatten, output) + + return flatten +} diff --git a/ibm/service/cis/data_source_ibm_cis_alerts_test.go b/ibm/service/cis/data_source_ibm_cis_alerts_test.go new file mode 100644 index 000000000..77ce82aa2 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_alerts_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisAlertsDataSource_Basic(t *testing.T) { + name := "data.ibm_cis_alerts.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisAlertsDataSource_basic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(name, "id"), + ), + }, + }, + }) +} +func testAccCheckCisAlertsDataSource_basic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_alerts" "%[1]s" { + cis_id = data.ibm_cis.cis.id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/data_source_ibm_cis_cache_settings.go b/ibm/service/cis/data_source_ibm_cis_cache_settings.go similarity index 89% rename from ibm/data_source_ibm_cis_cache_settings.go rename to ibm/service/cis/data_source_ibm_cis_cache_settings.go index 32f679509..5eee794d0 100644 --- a/ibm/data_source_ibm_cis_cache_settings.go +++ b/ibm/service/cis/data_source_ibm_cis_cache_settings.go @@ -1,17 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMCISCacheSetting() *schema.Resource { +func DataSourceIBMCISCacheSetting() *schema.Resource { return &schema.Resource{ Read: dataSourceCISCacheSettingsRead, Schema: map[string]*schema.Schema{ @@ -19,6 +22,9 @@ func dataSourceIBMCISCacheSetting() *schema.Resource { Type: schema.TypeString, Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_cache_settings", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -174,14 +180,32 @@ func dataSourceIBMCISCacheSetting() *schema.Resource { }, } } +func DataSourceIBMCISCacheSettingsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISCacheSettingValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_cache_settings", + Schema: validateSchema} + return &iBMCISCacheSettingValidator +} func dataSourceCISCacheSettingsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisCacheClientSession() + cisClient, err := meta.(conns.ClientSession).CisCacheClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneID = core.StringPtr(zoneID) diff --git a/ibm/data_source_ibm_cis_cache_settings_test.go b/ibm/service/cis/data_source_ibm_cis_cache_settings_test.go similarity index 78% rename from ibm/data_source_ibm_cis_cache_settings_test.go rename to ibm/service/cis/data_source_ibm_cis_cache_settings_test.go index 25fc655bf..e730fae8b 100644 --- a/ibm/data_source_ibm_cis_cache_settings_test.go +++ b/ibm/service/cis/data_source_ibm_cis_cache_settings_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,11 +15,11 @@ func TestAccIBMCisCacheSettingsDataSource_Basic(t *testing.T) { node := "data.ibm_cis_cache_settings.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckCisCacheSettingsDataSourceConfigBasic1("test", cisDomainStatic), + Config: testAccCheckCisCacheSettingsDataSourceConfigBasic1("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(node, "caching_level.0.value", "simplified"), resource.TestCheckResourceAttr(node, "development_mode.0.value", "on"), @@ -27,7 +28,7 @@ func TestAccIBMCisCacheSettingsDataSource_Basic(t *testing.T) { ), }, { - Config: testAccCheckCisCacheSettingsDataSourceConfigBasic2("test", cisDomainStatic), + Config: testAccCheckCisCacheSettingsDataSourceConfigBasic2("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(node, "caching_level.0.value", "aggressive"), resource.TestCheckResourceAttr(node, "development_mode.0.value", "off"), @@ -39,19 +40,19 @@ func TestAccIBMCisCacheSettingsDataSource_Basic(t *testing.T) { }) } -func testAccCheckCisCacheSettingsDataSourceConfigBasic1(id string, cisDomainStatic string) string { - return testAccCheckCisCacheSettingsConfigBasic1(id, cisDomainStatic) + fmt.Sprintf(` +func testAccCheckCisCacheSettingsDataSourceConfigBasic1(id string, CisDomainStatic string) string { + return testAccCheckCisCacheSettingsConfigBasic1(id, acc.CisDomainStatic) + ` data "ibm_cis_cache_settings" "test" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id } -`) +` } -func testAccCheckCisCacheSettingsDataSourceConfigBasic2(id string, cisDomainStatic string) string { - return testAccCheckCisCacheSettingsConfigBasic2(id, cisDomainStatic) + fmt.Sprintf(` +func testAccCheckCisCacheSettingsDataSourceConfigBasic2(id string, CisDomainStatic string) string { + return testAccCheckCisCacheSettingsConfigBasic2(id, acc.CisDomainStatic) + ` data "ibm_cis_cache_settings" "test" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id } -`) +` } diff --git a/ibm/data_source_ibm_cis_certificates.go b/ibm/service/cis/data_source_ibm_cis_certificates.go similarity index 77% rename from ibm/data_source_ibm_cis_certificates.go rename to ibm/service/cis/data_source_ibm_cis_certificates.go index f4e18eb93..96a86862e 100644 --- a/ibm/data_source_ibm_cis_certificates.go +++ b/ibm/service/cis/data_source_ibm_cis_certificates.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -24,14 +27,17 @@ const ( cisCertificateTypeDedicated = "dedicated" ) -func dataIBMCISCertificates() *schema.Resource { +func DataSourceIBMCISCertificates() *schema.Resource { return &schema.Resource{ Read: dataIBMCISCertificatesRead, Schema: map[string]*schema.Schema{ cisID: { Type: schema.TypeString, - Description: "CIS object id", + Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_certificates", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -107,13 +113,31 @@ func dataIBMCISCertificates() *schema.Resource { }, } } +func DataSourceIBMCISCertificatesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISCertificatesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_certificates", + Schema: validateSchema} + return &iBMCISCertificatesValidator +} func dataIBMCISCertificatesRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisSSLClientSession() + cisClient, err := meta.(conns.ClientSession).CisSSLClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewListCertificatesOptions() @@ -125,14 +149,14 @@ func dataIBMCISCertificatesRead(d *schema.ResourceData, meta interface{}) error certificatesList := make([]interface{}, 0) for _, instance := range result.Result { certificate := map[string]interface{}{} - certificate["id"] = convertCisToTfThreeVar(*instance.ID, zoneID, crn) + certificate["id"] = flex.ConvertCisToTfThreeVar(*instance.ID, zoneID, crn) certificate[cisCertificateOrderID] = *instance.ID certificate[cisCertificateOrderStatus] = *instance.Status if instance.PrimaryCertificate != nil { certificate[cisCertificatesPrimaryCertificate] = convertCISCertificatesObj(*instance.Type, instance.PrimaryCertificate) } - certificate[cisCertificateOrderHosts] = flattenStringList(instance.Hosts) + certificate[cisCertificateOrderHosts] = flex.FlattenStringList(instance.Hosts) certs := []interface{}{} for _, i := range instance.Certificates { @@ -141,7 +165,7 @@ func dataIBMCISCertificatesRead(d *schema.ResourceData, meta interface{}) error cert[cisCertificatesCertificatesID] = convertCISCertificatesObj(*instance.Type, i.ID) } cert[cisCertificatesCertificatesStatus] = *i.Status - cert[cisCertificatesCertificatesHosts] = flattenStringList(i.Hosts) + cert[cisCertificatesCertificatesHosts] = flex.FlattenStringList(i.Hosts) certs = append(certs, cert) } certificate[cisCertificatesType] = *instance.Type diff --git a/ibm/data_source_ibm_cis_certificates_test.go b/ibm/service/cis/data_source_ibm_cis_certificates_test.go similarity index 78% rename from ibm/data_source_ibm_cis_certificates_test.go rename to ibm/service/cis/data_source_ibm_cis_certificates_test.go index 44a25ee47..2cae37d81 100644 --- a/ibm/data_source_ibm_cis_certificates_test.go +++ b/ibm/service/cis/data_source_ibm_cis_certificates_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisCertificatesDataSource_basic(t *testing.T) { node := "data.ibm_cis_certificates.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisCertificatesDataSourceConfig(), @@ -28,9 +29,9 @@ func TestAccIBMCisCertificatesDataSource_basic(t *testing.T) { func testAccCheckIBMCisCertificatesDataSourceConfig() string { // status filter defaults to empty - return testAccCheckCisCertificateOrderConfigBasic() + fmt.Sprintf(` + return testAccCheckCisCertificateOrderConfigBasic() + ` data "ibm_cis_certificates" "test" { cis_id = ibm_cis_certificate_order.test.cis_id domain_id = ibm_cis_certificate_order.test.domain_id - }`) + }` } diff --git a/ibm/service/cis/data_source_ibm_cis_custom_certificates.go b/ibm/service/cis/data_source_ibm_cis_custom_certificates.go new file mode 100644 index 000000000..276921fa8 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_custom_certificates.go @@ -0,0 +1,163 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisCustomCertificates = "custom_certificates" +) + +func DataSourceIBMCISCustomCertificates() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISCustomCertificatesRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_custom_certificates", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisCustomCertificates: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + cisCertificateUploadCustomCertID: { + Type: schema.TypeString, + Computed: true, + }, + cisCertificateUploadBundleMethod: { + Type: schema.TypeString, + Description: "Certificate bundle method", + Computed: true, + }, + cisCertificateUploadHosts: { + Type: schema.TypeList, + Computed: true, + Description: "hosts which the certificate uploaded to", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + cisPageRulePriority: { + Type: schema.TypeInt, + Description: "Certificate priority", + Computed: true, + }, + cisCertificateUploadStatus: { + Type: schema.TypeString, + Description: "certificate status", + Computed: true, + }, + cisCertificateUploadIssuer: { + Type: schema.TypeString, + Description: "certificate issuer", + Computed: true, + }, + cisCertificateUploadSignature: { + Type: schema.TypeString, + Description: "certificate signature", + Computed: true, + }, + cisCertificateUploadUploadedOn: { + Type: schema.TypeString, + Description: "certificate uploaded date", + Computed: true, + }, + cisCertificateUploadModifiedOn: { + Type: schema.TypeString, + Description: "certificate modified date", + Computed: true, + }, + cisCertificateUploadExpiresOn: { + Type: schema.TypeString, + Description: "certificate expires date", + Computed: true, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISCustomCertificatesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISCustomCertificatesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_custom_certificates", + Schema: validateSchema} + return &iBMCISCustomCertificatesValidator +} + +func dataSourceIBMCISCustomCertificatesRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisSSLClientSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + opt := cisClient.NewListCustomCertificatesOptions() + result, resp, err := cisClient.ListCustomCertificates(opt) + if err != nil { + return fmt.Errorf("[ERROR] Failed to list custom certificates: %v", resp) + } + certsList := make([]map[string]interface{}, 0) + for _, r := range result.Result { + cert := map[string]interface{}{} + cert["id"] = flex.ConvertCisToTfThreeVar(*r.ID, zoneID, crn) + cert[cisCertificateUploadCustomCertID] = *r.ID + cert[cisCertificateUploadBundleMethod] = *r.BundleMethod + cert[cisCertificateUploadHosts] = flex.FlattenStringList(r.Hosts) + cert[cisCertificateUploadIssuer] = *r.Issuer + cert[cisCertificateUploadSignature] = *r.Signature + cert[cisCertificateUploadStatus] = *r.Status + cert[cisCertificateUploadPriority] = *r.Priority + cert[cisCertificateUploadUploadedOn] = *r.UploadedOn + cert[cisCertificateUploadModifiedOn] = *r.ModifiedOn + cert[cisCertificateUploadExpiresOn] = *r.ExpiresOn + certsList = append(certsList, cert) + } + d.SetId(dataSourceIBMCISCustomCertificatesID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisCustomCertificates, certsList) + return nil +} + +func dataSourceIBMCISCustomCertificatesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_custom_certificates_test.go b/ibm/service/cis/data_source_ibm_cis_custom_certificates_test.go similarity index 82% rename from ibm/data_source_ibm_cis_custom_certificates_test.go rename to ibm/service/cis/data_source_ibm_cis_custom_certificates_test.go index 65b3190ec..6963b7062 100644 --- a/ibm/data_source_ibm_cis_custom_certificates_test.go +++ b/ibm/service/cis/data_source_ibm_cis_custom_certificates_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ import ( func TestAccIBMCisCustomCertificatesDataSource_basic(t *testing.T) { node := "data.ibm_cis_custom_certificates.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisCustomCertificatesDataSourceConfig(), @@ -33,12 +35,12 @@ func testAccCheckIBMCisCustomCertificatesDataSourceConfig() string { certMgrInstanceName := fmt.Sprintf("testacc-cert-manager-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) domainName := fmt.Sprintf("%s.%s", - acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum), cisDomainStatic) + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum), acc.CisDomainStatic) return testAccCheckCisCertificateUploadConfigBasic(certMgrInstanceName, domainName) + - fmt.Sprintf(` + ` data "ibm_cis_custom_certificates" "test" { cis_id = ibm_cis_certificate_upload.test.cis_id domain_id = ibm_cis_certificate_upload.test.domain_id - }`) + }` } diff --git a/ibm/service/cis/data_source_ibm_cis_custom_pages.go b/ibm/service/cis/data_source_ibm_cis_custom_pages.go new file mode 100644 index 000000000..a2f841b48 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_custom_pages.go @@ -0,0 +1,157 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisCustomPages = "cis_custom_pages" +) + +func DataSourceIBMCISCustomPages() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISCustomPagesRead, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_custom_pages", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisCustomPages: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisCustomPageIdentifier: { + Type: schema.TypeString, + Description: "Custom page identifier", + Computed: true, + }, + cisCustomPageURL: { + Type: schema.TypeString, + Description: "Custom page url", + Computed: true, + }, + cisCustomPageState: { + Type: schema.TypeString, + Description: "Custom page state", + Computed: true, + }, + cisCustomPageDesc: { + Type: schema.TypeString, + Description: "Free text", + Computed: true, + }, + cisCustomPageRequiredTokens: { + Type: schema.TypeList, + Description: "Custom page state", + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + cisCustomPagePreviewTarget: { + Type: schema.TypeString, + Description: "Custom page preview target", + Computed: true, + }, + cisCustomPageCreatedOn: { + Type: schema.TypeString, + Description: "Custom page created date", + Computed: true, + }, + cisCustomPageModifiedOn: { + Type: schema.TypeString, + Description: "Custom page modified date", + Computed: true, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISCustomPagesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISCustomPagesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_custom_pages", + Schema: validateSchema} + return &iBMCISCustomPagesValidator +} +func dataSourceIBMCISCustomPagesRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisCustomPageClientSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + zoneID := d.Get(cisDomainID).(string) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + opt := cisClient.NewListZoneCustomPagesOptions() + + result, response, err := cisClient.ListZoneCustomPages(opt) + if err != nil { + log.Printf("List custom pages failed: %v", response) + return err + } + customPagesOutput := make([]map[string]interface{}, 0) + for _, instance := range result.Result { + customPage := make(map[string]interface{}) + customPage[cisCustomPageIdentifier] = *instance.ID + customPage[cisCustomPageState] = *instance.State + customPage[cisCustomPageDesc] = *instance.Description + customPage[cisCustomPagePreviewTarget] = *instance.PreviewTarget + customPage[cisCustomPageRequiredTokens] = flex.FlattenStringList(instance.RequiredTokens) + if instance.CreatedOn != nil { + customPage[cisCustomPageCreatedOn] = (*instance.CreatedOn).String() + } + if instance.ModifiedOn != nil { + customPage[cisCustomPageModifiedOn] = (*instance.ModifiedOn).String() + } + if instance.URL != nil { + customPage[cisCustomPageURL] = *instance.URL + } + + customPagesOutput = append(customPagesOutput, customPage) + } + d.SetId(dataSourceIBMCISCustomPageID(d)) + d.Set(cisCustomPages, customPagesOutput) + return nil +} + +func dataSourceIBMCISCustomPageID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_custom_pages_test.go b/ibm/service/cis/data_source_ibm_cis_custom_pages_test.go similarity index 77% rename from ibm/data_source_ibm_cis_custom_pages_test.go rename to ibm/service/cis/data_source_ibm_cis_custom_pages_test.go index e7a8de1a0..060e48b1a 100644 --- a/ibm/data_source_ibm_cis_custom_pages_test.go +++ b/ibm/service/cis/data_source_ibm_cis_custom_pages_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisCustomPagesDataSource_basic(t *testing.T) { node := "data.ibm_cis_custom_pages.test_custom_pages" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisCustomPagesDataSourceConfig(), @@ -29,10 +30,10 @@ func TestAccIBMCisCustomPagesDataSource_basic(t *testing.T) { func testAccCheckIBMCisCustomPagesDataSourceConfig() string { // status filter defaults to empty - return testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", cisDomainStatic) + - fmt.Sprintf(` + return testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", acc.CisDomainStatic) + + ` data "ibm_cis_custom_pages" "test_custom_pages" { cis_id = data.ibm_cis.cis.id domain_id = ibm_cis_dns_record.test.domain_id - }`) + }` } diff --git a/ibm/data_source_ibm_cis_dns_records.go b/ibm/service/cis/data_source_ibm_cis_dns_records.go similarity index 81% rename from ibm/data_source_ibm_cis_dns_records.go rename to ibm/service/cis/data_source_ibm_cis_dns_records.go index c5aa7c8dc..9643e8ab3 100644 --- a/ibm/data_source_ibm_cis_dns_records.go +++ b/ibm/service/cis/data_source_ibm_cis_dns_records.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" @@ -10,6 +10,9 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -19,7 +22,7 @@ const ( cisDNSRecordsExportFile = "file" ) -func dataSourceIBMCISDNSRecords() *schema.Resource { +func DataSourceIBMCISDNSRecords() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISDNSRecordsRead, Importer: &schema.ResourceImporter{}, @@ -32,6 +35,9 @@ func dataSourceIBMCISDNSRecords() *schema.Resource { Type: schema.TypeString, Required: true, Description: "DNS Zone CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_dns_records", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -122,26 +128,43 @@ func dataSourceIBMCISDNSRecords() *schema.Resource { }, } } +func DataSourceIBMCISDNSRecordsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISDNSRecordsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_dns_records", + Schema: validateSchema} + return &iBMCISDNSRecordsValidator +} func dataSourceIBMCISDNSRecordsRead(d *schema.ResourceData, meta interface{}) error { var ( crn string zoneID string records []map[string]interface{} ) - sess, err := meta.(ClientSession).CisDNSRecordClientSession() + sess, err := meta.(conns.ClientSession).CisDNSRecordClientSession() if err != nil { return err } // session options crn = d.Get(cisID).(string) - zoneID, _, _ = convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ = flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) sess.Crn = core.StringPtr(crn) sess.ZoneIdentifier = core.StringPtr(zoneID) if file, ok := d.GetOk(cisDNSRecordsExportFile); ok { - sess, err := meta.(ClientSession).CisDNSRecordBulkClientSession() + sess, err := meta.(conns.ClientSession).CisDNSRecordBulkClientSession() if err != nil { return err } @@ -181,7 +204,7 @@ func dataSourceIBMCISDNSRecordsRead(d *schema.ResourceData, meta interface{}) er records = make([]map[string]interface{}, 0) for _, instance := range result.Result { record := map[string]interface{}{} - record["id"] = convertCisToTfThreeVar(*instance.ID, zoneID, crn) + record["id"] = flex.ConvertCisToTfThreeVar(*instance.ID, zoneID, crn) record[cisDNSRecordID] = *instance.ID record[cisZoneName] = *instance.ZoneName record[cisDNSRecordCreatedOn] = *instance.CreatedOn diff --git a/ibm/data_source_ibm_cis_dns_records_test.go b/ibm/service/cis/data_source_ibm_cis_dns_records_test.go similarity index 86% rename from ibm/data_source_ibm_cis_dns_records_test.go rename to ibm/service/cis/data_source_ibm_cis_dns_records_test.go index 864591f11..9abe23a9b 100644 --- a/ibm/data_source_ibm_cis_dns_records_test.go +++ b/ibm/service/cis/data_source_ibm_cis_dns_records_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "bufio" @@ -10,6 +10,8 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) @@ -17,8 +19,8 @@ import ( func TestAccIBMCisDNSRecordsDataSource_basic(t *testing.T) { node := "data.ibm_cis_dns_records.test_dns_records" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisDNSRecordsDataSourceConfig(), @@ -36,13 +38,13 @@ func TestAccIBMCisDNSRecordsDataSource_basic(t *testing.T) { func testAccCheckIBMCisDNSRecordsDataSourceConfig() string { // status filter defaults to empty - return testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", cisDomainStatic) + - fmt.Sprintf(` + return testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", acc.CisDomainStatic) + + ` data "ibm_cis_dns_records" "test_dns_records" { cis_id = data.ibm_cis.cis.id domain_id = ibm_cis_dns_record.test.domain_id file = "/tmp/records.txt" - }`) + }` } func testAccCheckIBMCisDNSRecordsExportExists(file string) resource.TestCheckFunc { @@ -53,7 +55,7 @@ func testAccCheckIBMCisDNSRecordsExportExists(file string) resource.TestCheckFun } defer f.Close() - testStr := fmt.Sprintf("test.%s", cisDomainStatic) + testStr := fmt.Sprintf("test.%s", acc.CisDomainStatic) // Splits on newlines by default. scanner := bufio.NewScanner(f) diff --git a/ibm/service/cis/data_source_ibm_cis_domain.go b/ibm/service/cis/data_source_ibm_cis_domain.go new file mode 100644 index 000000000..ed5804ea5 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_domain.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMCISDomain() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISDomainRead, + + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_domain", + "cis_id"), + }, + cisDomain: { + Type: schema.TypeString, + Description: "CISzone - Domain", + Required: true, + }, + cisDomainType: { + Type: schema.TypeString, + Description: "CISzone - Domain Type", + Computed: true, + }, + cisDomainPaused: { + Type: schema.TypeBool, + Computed: true, + }, + cisDomainStatus: { + Type: schema.TypeString, + Computed: true, + }, + cisDomainNameServers: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + cisDomainOriginalNameServers: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + cisDomainID: { + Type: schema.TypeString, + Computed: true, + }, + cisDomainVerificationKey: { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + cisDomainCnameSuffix: { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + } +} +func DataSourceIBMCISDomainValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISDomainValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_domain", + Schema: validateSchema} + return &iBMCISDomainValidator +} +func dataSourceIBMCISDomainRead(d *schema.ResourceData, meta interface{}) error { + var zoneFound bool + cisClient, err := meta.(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + cisClient.Crn = core.StringPtr(crn) + zoneName := d.Get(cisDomain).(string) + + opt := cisClient.NewListZonesOptions() + opt.SetPage(1) // list all zones in one page + opt.SetPerPage(1000) // maximum allowed limit is 1000 per page + zones, resp, err := cisClient.ListZones(opt) + if err != nil { + log.Printf("dataSourcCISdomainRead - ListZones Failed %s\n", resp) + return err + } + + for _, zone := range zones.Result { + if *zone.Name == zoneName { + d.SetId(flex.ConvertCisToTfTwoVar(*zone.ID, crn)) + d.Set(cisID, crn) + d.Set(cisDomain, *zone.Name) + d.Set(cisDomainStatus, *zone.Status) + d.Set(cisDomainPaused, *zone.Paused) + d.Set(cisDomainNameServers, zone.NameServers) + d.Set(cisDomainOriginalNameServers, zone.OriginalNameServers) + d.Set(cisDomainID, *zone.ID) + d.Set(cisDomainType, *zone.Type) + + if cisDomainType == "partial" { + d.Set(cisDomainVerificationKey, *zone.VerificationKey) + d.Set(cisDomainCnameSuffix, *zone.CnameSuffix) + } + zoneFound = true + } + } + + if !zoneFound { + return fmt.Errorf("[ERROR] Given zone does not exist. Please specify correct domain") + } + + return nil +} diff --git a/ibm/data_source_ibm_cis_domain_test.go b/ibm/service/cis/data_source_ibm_cis_domain_test.go similarity index 81% rename from ibm/data_source_ibm_cis_domain_test.go rename to ibm/service/cis/data_source_ibm_cis_domain_test.go index a55b7cc05..d49a2ad79 100644 --- a/ibm/data_source_ibm_cis_domain_test.go +++ b/ibm/service/cis/data_source_ibm_cis_domain_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisDomainDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisDomainDataSourceConfigBasic1(), @@ -28,9 +30,9 @@ func TestAccIBMCisDomainDataSource_Basic(t *testing.T) { } func testAccCheckIBMCisDomainDataSourceConfigBasic1() string { - name := cisDomainStatic - instance := cisInstance - resourceGroup := cisResourceGroup + name := acc.CisDomainStatic + instance := acc.CisInstance + resourceGroup := acc.CisResourceGroup return fmt.Sprintf(` data "ibm_cis_domain" "cis_domain" { cis_id = data.ibm_cis.cis.id diff --git a/ibm/data_source_ibm_cis_edge_functions_actions.go b/ibm/service/cis/data_source_ibm_cis_edge_functions_actions.go similarity index 79% rename from ibm/data_source_ibm_cis_edge_functions_actions.go rename to ibm/service/cis/data_source_ibm_cis_edge_functions_actions.go index c65ec6909..6b79eccf1 100644 --- a/ibm/data_source_ibm_cis_edge_functions_actions.go +++ b/ibm/service/cis/data_source_ibm_cis_edge_functions_actions.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -24,7 +27,7 @@ const ( cisEdgeFunctionsActionModifiedOn = "modified_on" ) -func dataSourceIBMCISEdgeFunctionsActions() *schema.Resource { +func DataSourceIBMCISEdgeFunctionsActions() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISEdgeFunctionsActionsRead, Schema: map[string]*schema.Schema{ @@ -32,6 +35,9 @@ func dataSourceIBMCISEdgeFunctionsActions() *schema.Resource { Type: schema.TypeString, Required: true, Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_edge_functions_actions", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -101,21 +107,39 @@ func dataSourceIBMCISEdgeFunctionsActions() *schema.Resource { }, } } +func DataSourceIBMCISEdgeFunctionsActionsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISEdgeFunctionsActionsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_edge_functions_actions", + Schema: validateSchema} + return &iBMCISEdgeFunctionsActionsValidator +} func dataSourceIBMCISEdgeFunctionsActionsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisEdgeFunctionClientSession() + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewListEdgeFunctionsActionsOptions() result, _, err := cisClient.ListEdgeFunctionsActions(opt) if err != nil { - return fmt.Errorf("Error: %v", err) + return fmt.Errorf("[ERROR] Error: %v", err) } scriptInfo := make([]map[string]interface{}, 0) for _, script := range result.Result { diff --git a/ibm/data_source_ibm_cis_edge_functions_actions_test.go b/ibm/service/cis/data_source_ibm_cis_edge_functions_actions_test.go similarity index 84% rename from ibm/data_source_ibm_cis_edge_functions_actions_test.go rename to ibm/service/cis/data_source_ibm_cis_edge_functions_actions_test.go index 2fed5cb3f..da2c7be6c 100644 --- a/ibm/data_source_ibm_cis_edge_functions_actions_test.go +++ b/ibm/service/cis/data_source_ibm_cis_edge_functions_actions_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisEdgeFunctionsActionsDataSource_basic(t *testing.T) { node := "data.ibm_cis_edge_functions_actions.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisEdgeFunctionsActionsDataSourceConfig(), @@ -30,9 +31,9 @@ func testAccCheckIBMCisEdgeFunctionsActionsDataSourceConfig() string { testName := "tf-acctest-basic" scriptName := "sample_script" - return testAccCheckIBMCisEdgeFunctionsActionBasic(testName, scriptName) + fmt.Sprintf(` + return testAccCheckIBMCisEdgeFunctionsActionBasic(testName, scriptName) + ` data "ibm_cis_edge_functions_actions" "test" { cis_id = ibm_cis_edge_functions_action.tf-acctest-basic.cis_id domain_id = ibm_cis_edge_functions_action.tf-acctest-basic.domain_id - }`) + }` } diff --git a/ibm/service/cis/data_source_ibm_cis_edge_functions_triggers.go b/ibm/service/cis/data_source_ibm_cis_edge_functions_triggers.go new file mode 100644 index 000000000..74f726fc6 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_edge_functions_triggers.go @@ -0,0 +1,130 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cisEdgeFunctionsTriggers = "cis_edge_functions_triggers" + +func DataSourceIBMCISEdgeFunctionsTriggers() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISEdgeFunctionsTriggerRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_edge_functions_actions", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Domain ID", + DiffSuppressFunc: suppressDataDiff, + }, + cisEdgeFunctionsTriggers: { + Type: schema.TypeList, + Description: "List of edge functions triggers", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Edge function trigger id", + }, + cisEdgeFunctionsTriggerID: { + Type: schema.TypeString, + Computed: true, + Description: "Edge function trigger route id", + }, + cisEdgeFunctionsTriggerPattern: { + Type: schema.TypeString, + Computed: true, + Description: "Edge function trigger pattern", + }, + cisEdgeFunctionsTriggerActionName: { + Type: schema.TypeString, + Computed: true, + Description: "Edge function trigger script name", + }, + cisEdgeFunctionsTriggerRequestLimitFailOpen: { + Type: schema.TypeBool, + Computed: true, + Description: "Edge function trigger request limit fail open", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMCISEdgeFunctionsTriggersValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISEdgeFunctionsTriggersValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_edge_functions_triggers", + Schema: validateSchema} + return &iBMCISEdgeFunctionsTriggersValidator +} + +func dataSourceIBMCISEdgeFunctionsTriggerRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewListEdgeFunctionsTriggersOptions() + result, _, err := cisClient.ListEdgeFunctionsTriggers(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error listing edge functions triggers: %v", err) + } + triggerInfo := make([]map[string]interface{}, 0) + for _, trigger := range result.Result { + l := map[string]interface{}{} + l["id"] = flex.ConvertCisToTfThreeVar(*trigger.ID, zoneID, crn) + l[cisEdgeFunctionsTriggerID] = *trigger.ID + l[cisEdgeFunctionsTriggerPattern] = *trigger.Pattern + l[cisEdgeFunctionsTriggerRequestLimitFailOpen] = *trigger.RequestLimitFailOpen + if trigger.Script != nil { + l[cisEdgeFunctionsTriggerActionName] = *trigger.Script + } + triggerInfo = append(triggerInfo, l) + } + d.SetId(dataSourceIBMCISEdgeFunctionsTriggersID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisEdgeFunctionsTriggers, triggerInfo) + return nil +} + +func dataSourceIBMCISEdgeFunctionsTriggersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_edge_functions_triggers_test.go b/ibm/service/cis/data_source_ibm_cis_edge_functions_triggers_test.go similarity index 79% rename from ibm/data_source_ibm_cis_edge_functions_triggers_test.go rename to ibm/service/cis/data_source_ibm_cis_edge_functions_triggers_test.go index afb1b75ee..e4687376c 100644 --- a/ibm/data_source_ibm_cis_edge_functions_triggers_test.go +++ b/ibm/service/cis/data_source_ibm_cis_edge_functions_triggers_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisEdgeFunctionsTriggersDataSource_basic(t *testing.T) { node := "data.ibm_cis_edge_functions_triggers.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisEdgeFunctionsTriggersDataSourceConfig(), @@ -29,10 +31,10 @@ func TestAccIBMCisEdgeFunctionsTriggersDataSource_basic(t *testing.T) { func testAccCheckIBMCisEdgeFunctionsTriggersDataSourceConfig() string { testName := "test" scriptName := "sample_script" - pattern := fmt.Sprintf("example.%s/*", cisDomainStatic) - return testAccCheckIBMCisEdgeFunctionsTriggerBasic(testName, pattern, scriptName) + fmt.Sprintf(` + pattern := fmt.Sprintf("example.%s/*", acc.CisDomainStatic) + return testAccCheckIBMCisEdgeFunctionsTriggerBasic(testName, pattern, scriptName) + ` data "ibm_cis_edge_functions_triggers" "test" { cis_id = ibm_cis_edge_functions_trigger.test.cis_id domain_id = ibm_cis_edge_functions_trigger.test.domain_id - }`) + }` } diff --git a/ibm/service/cis/data_source_ibm_cis_filters.go b/ibm/service/cis/data_source_ibm_cis_filters.go new file mode 100644 index 000000000..90760f0bd --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_filters.go @@ -0,0 +1,125 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cisFiltersList = "cis_filters_list" + +func DataSourceIBMCISFilters() *schema.Resource { + return &schema.Resource{ + Read: dataIBMCISFiltersRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_filters", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisFiltersList: { + Type: schema.TypeList, + Description: "Collection of Filter detail", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisFilterPaused: { + Type: schema.TypeBool, + Computed: true, + Description: "Filter Paused", + }, + cisFilterID: { + Type: schema.TypeString, + Computed: true, + Description: "Filter ID", + }, + cisFilterExpression: { + Type: schema.TypeString, + Computed: true, + Description: "Filter Expression", + }, + cisFilterDescription: { + Type: schema.TypeString, + Computed: true, + Description: "Filter Description", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISFiltersValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISFiltersValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_filters", + Schema: validateSchema} + return &iBMCISFiltersValidator +} +func dataIBMCISFiltersRead(d *schema.ResourceData, meta interface{}) error { + + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while Getting IAM Access Token using BluemixSession %s", err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisFiltersSession %s", err) + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + + result, resp, err := cisClient.ListAllFilters(cisClient.NewListAllFiltersOptions(xAuthtoken, crn, zoneID)) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error Listing all filters %q: %s %s", d.Id(), err, resp) + } + + filtersList := make([]map[string]interface{}, 0) + + for _, filtersObj := range result.Result { + filtersOutput := map[string]interface{}{} + filtersOutput[cisFilterID] = *filtersObj.ID + filtersOutput[cisFilterDescription] = filtersObj.Description + filtersOutput[cisFilterExpression] = *filtersObj.Expression + filtersOutput[cisFilterPaused] = *filtersObj.Paused + filtersList = append(filtersList, filtersOutput) + } + d.SetId(dataSourceCISFiltersCheckID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisFiltersList, filtersList) + return nil +} + +func dataSourceCISFiltersCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_filters_test.go b/ibm/service/cis/data_source_ibm_cis_filters_test.go new file mode 100644 index 000000000..3799edc78 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_filters_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisFilterDataSource_Basic(t *testing.T) { + name := "data.ibm_cis_filter.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisFilterDataSource_basic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(name, "id"), + ), + }, + }, + }) +} +func testAccCheckCisFilterDataSource_basic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_filter" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/data_source_ibm_cis_firewall.go b/ibm/service/cis/data_source_ibm_cis_firewall.go similarity index 85% rename from ibm/data_source_ibm_cis_firewall.go rename to ibm/service/cis/data_source_ibm_cis_firewall.go index 6f41b9d39..709258439 100644 --- a/ibm/data_source_ibm_cis_firewall.go +++ b/ibm/service/cis/data_source_ibm_cis_firewall.go @@ -1,24 +1,30 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataIBMCISFirewallsRecord() *schema.Resource { +func DataSourceIBMCISFirewallsRecord() *schema.Resource { return &schema.Resource{ Read: dataIBMCISFirewallRecordRead, Schema: map[string]*schema.Schema{ cisID: { Type: schema.TypeString, - Description: "CIS object id", + Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_firewall", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -176,13 +182,31 @@ func dataIBMCISFirewallsRecord() *schema.Resource { }, } } +func DataSourceIBMCISFirewallsRecordValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISFirewallValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_firewall", + Schema: validateSchema} + return &iBMCISFirewallValidator +} func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) error { crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) firewallType := d.Get(cisFirewallType).(string) if firewallType == cisFirewallTypeLockdowns { - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -198,7 +222,7 @@ func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) erro for _, instance := range result.Result { configurationList := []interface{}{} for _, c := range instance.Configurations { - configuration := make(map[string]interface{}, 0) + configuration := make(map[string]interface{}) configuration[cisFirewallLockdownConfigurationsTarget] = c.Target configuration[cisFirewallLockdownConfigurationsValue] = c.Value configurationList = append(configurationList, configuration) @@ -218,7 +242,7 @@ func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) erro } d.Set(cisFirewallLockdown, lockdownList) } else if firewallType == cisFirewallTypeAccessRules { - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -237,7 +261,7 @@ func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) erro configuration[cisFirewallAccessRuleConfigurationTarget] = *instance.Configuration.Target configuration[cisFirewallAccessRuleConfigurationValue] = *instance.Configuration.Value configurations = append(configurations, configuration) - accessRule := make(map[string]interface{}, 0) + accessRule := make(map[string]interface{}) accessRule[cisFirewallAccessRuleID] = *instance.ID accessRule[cisFirewallAccessRuleMode] = *instance.Mode accessRule[cisFirewallAccessRuleNotes] = *instance.Notes @@ -246,7 +270,7 @@ func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) erro } d.Set(cisFirewallAccessRule, accessRuleList) } else if firewallType == cisFirewallTypeUARules { - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -265,7 +289,7 @@ func dataIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) erro configuration[cisFirewallUARuleConfigurationTarget] = *instance.Configuration.Target configuration[cisFirewallUARuleConfigurationValue] = *instance.Configuration.Value configurations = append(configurations, configuration) - uaRule := make(map[string]interface{}, 0) + uaRule := make(map[string]interface{}) uaRule[cisFirewallUARuleID] = *instance.ID uaRule[cisFirewallUARuleMode] = *instance.Mode uaRule[cisFirewallUARulePaused] = *instance.Paused diff --git a/ibm/service/cis/data_source_ibm_cis_firewall_rule.go b/ibm/service/cis/data_source_ibm_cis_firewall_rule.go new file mode 100644 index 000000000..e29e29956 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_firewall_rule.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMCISFirewallRules() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCISFirewallRulesRead, + + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "Full url-encoded cloud resource name (CRN) of resource instance.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_firewall_rules", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "Zone identifier of the zone for which firewall rules are listed.", + }, + cisFirewallrulesList: { + Type: schema.TypeList, + Computed: true, + Description: "Container for response information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisFirewallrulesID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the firewall rule.", + }, + cisFirewallrulesPaused: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the firewall rule is active.", + }, + cisFirewallrulesDescription: { + Type: schema.TypeString, + Computed: true, + Description: "To briefly describe the firewall rule, omitted from object if empty.", + }, + cisFirewallrulesAction: { + Type: schema.TypeString, + Computed: true, + Description: "The firewall action to perform, \"log\" action is only available for enterprise plan instances.", + }, + cisFilter: { + Type: schema.TypeMap, + Computed: true, + Description: "An existing filter.", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISFirewallRulesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISFirewallRulesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_firewall_rules", + Schema: validateSchema} + return &iBMCISFirewallRulesValidator +} +func dataSourceIBMCISFirewallRulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFirewallRulesSession() + if err != nil { + return diag.FromErr(err) + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + + result, resp, err := cisClient.ListAllFirewallRules(cisClient.NewListAllFirewallRulesOptions(xAuthtoken, crn, zoneID)) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing the firewall rules %s:%s", err, resp)) + } + + fwrList := make([]map[string]interface{}, 0) + + for _, instance := range result.Result { + firewallrules := map[string]interface{}{} + fr_filters := map[string]interface{}{} + firewallrules[cisFirewallrulesID] = *instance.ID + firewallrules[cisFirewallrulesPaused] = *instance.Paused + firewallrules[cisFirewallrulesDescription] = instance.Description + firewallrules[cisFirewallrulesAction] = *instance.Action + fr_filters[cisFilterID] = *instance.Filter.ID + if *instance.Filter.Paused { + fr_filters[cisFilterPaused] = "true" + } else { + fr_filters[cisFilterPaused] = "false" + } + fr_filters[cisFilterExpression] = *instance.Filter.Expression + fr_filters[cisFilterDescription] = instance.Filter.Description + firewallrules[cisFilter] = fr_filters + fwrList = append(fwrList, firewallrules) + } + d.SetId(dataSourceCISFirewallrulesCheckID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisFirewallrulesList, fwrList) + return nil +} +func dataSourceCISFirewallrulesCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_firewall_rule_test.go b/ibm/service/cis/data_source_ibm_cis_firewall_rule_test.go new file mode 100644 index 000000000..286b87843 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_firewall_rule_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisFirewallRulesDataSource_Basic(t *testing.T) { + name := "data.ibm_cis_firewall_rules.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmFirewallRulesDataSourceConfigBasic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(name, "id"), + ), + }, + }, + }) +} + +func testAccCheckIbmFirewallRulesDataSourceConfigBasic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_firewall_rules" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/data_source_ibm_cis_firewall_test.go b/ibm/service/cis/data_source_ibm_cis_firewall_test.go similarity index 85% rename from ibm/data_source_ibm_cis_firewall_test.go rename to ibm/service/cis/data_source_ibm_cis_firewall_test.go index e6673597f..edd695dd4 100644 --- a/ibm/data_source_ibm_cis_firewall_test.go +++ b/ibm/service/cis/data_source_ibm_cis_firewall_test.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisFirewallLockdownDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallLockdownDataSourceConfigBasic(), @@ -26,7 +27,7 @@ func TestAccIBMCisFirewallLockdownDataSource_Basic(t *testing.T) { func TestAccIBMCisFirewallAccessRuleDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallAccessRuleDataSourceConfigBasic(), @@ -40,7 +41,7 @@ func TestAccIBMCisFirewallAccessRuleDataSource_Basic(t *testing.T) { func TestAccIBMCisFirewallUARuleDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallUARuleDataSourceConfigBasic(), @@ -53,31 +54,31 @@ func TestAccIBMCisFirewallUARuleDataSource_Basic(t *testing.T) { } func testAccCheckIBMCisFirewallLockdownDataSourceConfigBasic() string { - return testAccCheckIBMCisFirewallLockdownBasic() + fmt.Sprintf(` + return testAccCheckIBMCisFirewallLockdownBasic() + ` data "ibm_cis_firewall" "lockdown"{ cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id firewall_type = "lockdowns" } - `) + ` } func testAccCheckIBMCisFirewallAccessRuleDataSourceConfigBasic() string { - return testAccCheckIBMCisFirewallAccessRuleBasic() + fmt.Sprintf(` + return testAccCheckIBMCisFirewallAccessRuleBasic() + ` data "ibm_cis_firewall" "access_rule"{ cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id firewall_type = "access_rules" } - `) + ` } func testAccCheckIBMCisFirewallUARuleDataSourceConfigBasic() string { - return testAccCheckIBMCisFirewallUARuleBasic() + fmt.Sprintf(` + return testAccCheckIBMCisFirewallUARuleBasic() + ` data "ibm_cis_firewall" "ua_rule"{ cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id firewall_type = "ua_rules" } - `) + ` } diff --git a/ibm/data_source_ibm_cis_global_load_balancers.go b/ibm/service/cis/data_source_ibm_cis_global_load_balancers.go similarity index 79% rename from ibm/data_source_ibm_cis_global_load_balancers.go rename to ibm/service/cis/data_source_ibm_cis_global_load_balancers.go index 94bd5d523..18f88d7ae 100644 --- a/ibm/data_source_ibm_cis_global_load_balancers.go +++ b/ibm/service/cis/data_source_ibm_cis_global_load_balancers.go @@ -1,25 +1,31 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const cisGLB = "cis_glb" -func dataSourceIBMCISGlbs() *schema.Resource { +func DataSourceIBMCISGlbs() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ cisID: { Type: schema.TypeString, Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_global_load_balancers", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -152,15 +158,33 @@ func dataSourceIBMCISGlbs() *schema.Resource { Importer: &schema.ResourceImporter{}, } } +func DataSourceIBMCISGlbsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISGLBsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_global_load_balancers", + Schema: validateSchema} + return &iBMCISGLBsValidator +} func dataSourceCISGlbsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneIdentifier = core.StringPtr(zoneID) @@ -176,12 +200,12 @@ func dataSourceCISGlbsRead(d *schema.ResourceData, meta interface{}) error { glbList := make([]map[string]interface{}, 0) for _, glbObj := range glbs { glbOutput := map[string]interface{}{} - glbOutput["id"] = convertCisToTfThreeVar(*glbObj.ID, zoneID, crn) + glbOutput["id"] = flex.ConvertCisToTfThreeVar(*glbObj.ID, zoneID, crn) glbOutput[cisGLBID] = *glbObj.ID glbOutput[cisGLBName] = *glbObj.Name - glbOutput[cisGLBDefaultPoolIDs] = convertCisToTfTwoVarSlice(glbObj.DefaultPools, crn) + glbOutput[cisGLBDefaultPoolIDs] = flex.ConvertCisToTfTwoVarSlice(glbObj.DefaultPools, crn) glbOutput[cisGLBDesc] = *glbObj.Description - glbOutput[cisGLBFallbackPoolID] = convertCisToTfTwoVar(*glbObj.FallbackPool, crn) + glbOutput[cisGLBFallbackPoolID] = flex.ConvertCisToTfTwoVar(*glbObj.FallbackPool, crn) glbOutput[cisGLBTTL] = *glbObj.TTL glbOutput[cisGLBSteeringPolicy] = *glbObj.SteeringPolicy glbOutput[cisGLBProxied] = *glbObj.Proxied @@ -212,7 +236,7 @@ func dataSourceCISGlbsCheckID(d *schema.ResourceData) string { func flattenDataSourcePopPools(pools interface{}, geoType string, cisID string) []interface{} { result := make([]interface{}, 0) for k, v := range pools.(map[string]interface{}) { - poolIds := convertCisToTfTwoVarSlice(expandStringList(v.([]interface{})), cisID) + poolIds := flex.ConvertCisToTfTwoVarSlice(flex.ExpandStringList(v.([]interface{})), cisID) pool := map[string]interface{}{ cisGLBPopPoolsPop: k, cisGLBPopPoolsPoolIDs: poolIds, @@ -225,7 +249,7 @@ func flattenDataSourcePopPools(pools interface{}, geoType string, cisID string) func flattenDataSourceRegionPools(pools interface{}, geoType string, cisID string) []interface{} { result := make([]interface{}, 0) for k, v := range pools.(map[string]interface{}) { - poolIds := convertCisToTfTwoVarSlice(expandStringList(v.([]interface{})), cisID) + poolIds := flex.ConvertCisToTfTwoVarSlice(flex.ExpandStringList(v.([]interface{})), cisID) pool := map[string]interface{}{ cisGLBRegionPoolsRegion: k, cisGLBRegionPoolsPoolIDs: poolIds, diff --git a/ibm/data_source_ibm_cis_global_load_balancers_test.go b/ibm/service/cis/data_source_ibm_cis_global_load_balancers_test.go similarity index 78% rename from ibm/data_source_ibm_cis_global_load_balancers_test.go rename to ibm/service/cis/data_source_ibm_cis_global_load_balancers_test.go index 1683bbbb9..5eeb391a9 100644 --- a/ibm/data_source_ibm_cis_global_load_balancers_test.go +++ b/ibm/service/cis/data_source_ibm_cis_global_load_balancers_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisGLBDataSource_basic(t *testing.T) { node := "data.ibm_cis_global_load_balancers.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisGLBDataSourceConfig(), @@ -29,9 +30,9 @@ func TestAccIBMCisGLBDataSource_basic(t *testing.T) { func testAccCheckIBMCisGLBDataSourceConfig() string { // status filter defaults to empty - return testAccCheckCisGlbConfigCisDSBasic("test", cisDomainStatic) + fmt.Sprintf(` + return testAccCheckCisGlbConfigCisDSBasic("test", acc.CisDomainStatic) + ` data "ibm_cis_global_load_balancers" "test" { cis_id = ibm_cis_global_load_balancer.test.cis_id domain_id = ibm_cis_global_load_balancer.test.domain_id - }`) + }` } diff --git a/ibm/data_source_ibm_cis_healthchecks.go b/ibm/service/cis/data_source_ibm_cis_healthchecks.go similarity index 83% rename from ibm/data_source_ibm_cis_healthchecks.go rename to ibm/service/cis/data_source_ibm_cis_healthchecks.go index 1f34c212a..a79e55eca 100644 --- a/ibm/data_source_ibm_cis_healthchecks.go +++ b/ibm/service/cis/data_source_ibm_cis_healthchecks.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +18,7 @@ const ( cisGLBHealthCheck = "cis_healthchecks" ) -func dataSourceIBMCISHealthChecks() *schema.Resource { +func DataSourceIBMCISHealthChecks() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISGLBHealthCheckRead, Importer: &schema.ResourceImporter{}, @@ -28,6 +31,9 @@ func dataSourceIBMCISHealthChecks() *schema.Resource { Type: schema.TypeString, Required: true, Description: "DNS Zone CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_healthchecks", + "cis_id"), }, cisGLBHealthCheck: { @@ -143,9 +149,27 @@ func dataSourceIBMCISHealthChecks() *schema.Resource { }, } } +func DataSourceIBMCISHealthChecksValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISHealthCheckValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_healthchecks", + Schema: validateSchema} + return &iBMCISHealthCheckValidator +} func dataSourceIBMCISGLBHealthCheckRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return err } @@ -164,7 +188,7 @@ func dataSourceIBMCISGLBHealthCheckRead(d *schema.ResourceData, meta interface{} monitors := make([]map[string]interface{}, 0) for _, instance := range result.Result { monitor := map[string]interface{}{} - monitor["id"] = convertCisToTfTwoVar(*instance.ID, crn) + monitor["id"] = flex.ConvertCisToTfTwoVar(*instance.ID, crn) monitor[cisID] = crn monitor[cisGLBHealthCheckID] = *instance.ID monitor[cisGLBHealthCheckDesc] = *instance.Description diff --git a/ibm/data_source_ibm_cis_healthchecks_test.go b/ibm/service/cis/data_source_ibm_cis_healthchecks_test.go similarity index 78% rename from ibm/data_source_ibm_cis_healthchecks_test.go rename to ibm/service/cis/data_source_ibm_cis_healthchecks_test.go index 0e8f32c24..da5a654b3 100644 --- a/ibm/data_source_ibm_cis_healthchecks_test.go +++ b/ibm/service/cis/data_source_ibm_cis_healthchecks_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisGLBHealthCheckDataSource_basic(t *testing.T) { node := "data.ibm_cis_healthchecks.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisGLBHealthCheckDataSourceConfig(), @@ -30,8 +31,8 @@ func TestAccIBMCisGLBHealthCheckDataSource_basic(t *testing.T) { func testAccCheckIBMCisGLBHealthCheckDataSourceConfig() string { // status filter defaults to empty - return testAccCheckCisHealthcheckConfigFullySpecified("test", cisDomainStatic) + fmt.Sprintf(` + return testAccCheckCisHealthcheckConfigFullySpecified("test", acc.CisDomainStatic) + ` data "ibm_cis_healthchecks" "test" { cis_id = ibm_cis_healthcheck.health_check.cis_id - }`) + }` } diff --git a/ibm/service/cis/data_source_ibm_cis_ip_addresses.go b/ibm/service/cis/data_source_ibm_cis_ip_addresses.go new file mode 100644 index 000000000..cd684a673 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_ip_addresses.go @@ -0,0 +1,59 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisIPv4CIDRs = "ipv4_cidrs" + cisIPv6CIDRs = "ipv6_cidrs" +) + +func DataSourceIBMCISIP() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISIPRead, + + Schema: map[string]*schema.Schema{ + cisIPv4CIDRs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + cisIPv6CIDRs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func dataSourceIBMCISIPRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisIPClientSession() + if err != nil { + return err + } + opt := cisClient.NewListIpsOptions() + result, response, err := cisClient.ListIps(opt) + if err != nil { + log.Printf("Failed to list IP addresses: %v", response) + return err + } + + d.Set(cisIPv4CIDRs, flex.FlattenStringList(result.Result.Ipv4Cidrs)) + d.Set(cisIPv6CIDRs, flex.FlattenStringList(result.Result.Ipv4Cidrs)) + d.SetId(dataSourceIBMCISIPID(d)) + return nil +} + +func dataSourceIBMCISIPID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_ip_addresses_test.go b/ibm/service/cis/data_source_ibm_cis_ip_addresses_test.go new file mode 100644 index 000000000..e66a782d3 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_ip_addresses_test.go @@ -0,0 +1,52 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "strconv" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMCisIPDataSource_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCisIPDataSourceConfigBasic, + Check: resource.ComposeTestCheckFunc( + testAccIBMCisIPAddrs("data.ibm_cis_ip_addresses.test_acc"), + ), + }, + }, + }) +} + +func testAccIBMCisIPAddrs(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + r := s.RootModule().Resources[n] + a := r.Primary.Attributes + + cidrs, _ := strconv.Atoi(a["ipv4_cidrs.#"]) + if cidrs == 0 { + return fmt.Errorf("[ERROR] No ipv4 cidrs returned") + } + cidrs, _ = strconv.Atoi(a["ipv6_cidrs.#"]) + if cidrs == 0 { + return fmt.Errorf("[ERROR] No ipv6 cidrs returned") + } + return nil + } +} + +const testAccCheckIBMCisIPDataSourceConfigBasic = ` +data "ibm_cis_ip_addresses" "test_acc" {} +` diff --git a/ibm/service/cis/data_source_ibm_cis_mtls.go b/ibm/service/cis/data_source_ibm_cis_mtls.go new file mode 100644 index 000000000..c11033170 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_mtls.go @@ -0,0 +1,158 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisMtlsOutput = "mtls_certificates" + cisMtlsCertID = "id" + cisMtlsCertName = "name" + cisMtlsCertFingerprint = "fingerprint" + cisMtlsCertAssociatedHostnames = "associated_hostnames" + cisMtlsCertCreatedAt = "created_at" + cisMtlsCertUpdatedAt = "updated_at" + cisMtlsCertExpiresOn = "expires_on" +) + +func DataSourceIBMCISMtls() *schema.Resource { + return &schema.Resource{ + ReadContext: dataIBMCISMtlsRead, + + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_mtlss", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisMtlsOutput: { + Type: schema.TypeList, + Computed: true, + Description: "Container for response information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisMtlsCertID: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate ID", + }, + cisMtlsCertName: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate name", + }, + cisMtlsCertFingerprint: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate Fingerprint", + }, + cisMtlsCertAssociatedHostnames: { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + Description: "Certificate Associated Hostnames", + }, + cisMtlsCertCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate Created At", + }, + cisMtlsCertUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate Updated At", + }, + cisMtlsCertExpiresOn: { + Type: schema.TypeString, + Computed: true, + Description: "Certificate Expires On", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISMtlsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISMtlsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_mtlss", + Schema: validateSchema} + return &iBMCISMtlsValidator +} + +func dataIBMCISMtlsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).CisMtlsSession() + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while getting the CisMtlsSession() %s %v", err, sess)) + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + sess.Crn = core.StringPtr(crn) + + opt := sess.NewListAccessCertificatesOptions(zoneID) + + result, resp, err := sess.ListAccessCertificates(opt) + if err != nil { + log.Printf("[WARN] List all certificates failed: %v\n", resp) + return diag.FromErr(err) + } + mtlsCertLists := make([]map[string]interface{}, 0) + for _, certObj := range result.Result { + mtlsCertList := map[string]interface{}{} + mtlsCertList[cisMtlsCertID] = *certObj.ID + mtlsCertList[cisMtlsCertName] = *certObj.Name + mtlsCertList[cisMtlsCertFingerprint] = *certObj.Fingerprint + mtlsCertList[cisMtlsCertAssociatedHostnames] = certObj.AssociatedHostnames + mtlsCertList[cisMtlsCertCreatedAt] = *certObj.CreatedAt + mtlsCertList[cisMtlsCertUpdatedAt] = *certObj.UpdatedAt + mtlsCertList[cisMtlsCertExpiresOn] = *certObj.ExpiresOn + + mtlsCertLists = append(mtlsCertLists, mtlsCertList) + + } + d.SetId(dataSourceCISMtlsCheckID(d)) + + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisMtlsOutput, mtlsCertLists) + + return nil +} +func dataSourceCISMtlsCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_mtls_app.go b/ibm/service/cis/data_source_ibm_cis_mtls_app.go new file mode 100644 index 000000000..eaf58149e --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_mtls_app.go @@ -0,0 +1,236 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMCISMtlsApp() *schema.Resource { + return &schema.Resource{ + ReadContext: dataIBMCISMtlsAppRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_mtls_apps", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + "mtls_access_apps": { + Type: schema.TypeList, + Computed: true, + Description: "Container for Access App Response.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "app_id": { + Type: schema.TypeString, + Computed: true, + Description: "Application ID", + }, + "app_name": { + Type: schema.TypeString, + Computed: true, + Description: "Application name", + }, + "app_domain": { + Type: schema.TypeString, + Computed: true, + Description: "Application Domain", + }, + "app_aud": { + Type: schema.TypeString, + Computed: true, + Description: "Application Aud", + }, + "allowed_idps": { + Type: schema.TypeList, + Computed: true, + Description: "List of allowed idps.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "auto_redirect_to_identity": { + Type: schema.TypeBool, + Computed: true, + Description: "Auto Redirect to Identity", + }, + "session_duration": { + Type: schema.TypeString, + Computed: true, + Description: "Session Duration", + }, + "app_type": { + Type: schema.TypeString, + Computed: true, + Description: "Application Type", + }, + "app_uid": { + Type: schema.TypeString, + Computed: true, + Description: "Application UID", + }, + "app_created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Application Created At", + }, + "app_updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Application Updated At", + }, + }, + }, + }, + "mtls_access_app_policies": { + Type: schema.TypeList, + Computed: true, + Description: "Access Policies Information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "policy_id": { + Type: schema.TypeString, + Computed: true, + Description: "Policy ID", + }, + "policy_name": { + Type: schema.TypeString, + Computed: true, + Description: "Policy name", + }, + "policy_decision": { + Type: schema.TypeString, + Computed: true, + Description: "Policy Decision", + }, + "policy_precedence": { + Type: schema.TypeInt, + Computed: true, + Description: "Policy Precedence", + }, + "policy_uid": { + Type: schema.TypeString, + Computed: true, + Description: "Policy UID", + }, + "policy_created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Application Created At", + }, + "policy_updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Application Updated At", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISMtlsAppValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISMTLSAppValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_mtls_apps", + Schema: validateSchema} + return &iBMCISMTLSAppValidator +} + +func dataIBMCISMtlsAppRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).CisMtlsSession() + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while getting the CisMtlsSession() %s %v", err, sess)) + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + sess.Crn = core.StringPtr(crn) + + opt := sess.NewListAccessApplicationsOptions(zoneID) + result, resp, err := sess.ListAccessApplications(opt) + if err != nil { + log.Printf("[WARN] List all Applications failed: %v\n", resp) + return diag.FromErr(err) + } + + mtlsAppLists := make([]map[string]interface{}, 0) + mtlsPolicyLists := make([]map[string]interface{}, 0) + for _, appObj := range result.Result { + mtlsAppList := map[string]interface{}{} + mtlsAppList["app_id"] = *appObj.ID + mtlsAppList["app_name"] = *appObj.Name + mtlsAppList["app_domain"] = *appObj.Domain + mtlsAppList["allowed_idps"] = appObj.AllowedIdps + mtlsAppList["auto_redirect_to_identity"] = appObj.AutoRedirectToIdentity + mtlsAppList["session_duration"] = appObj.SessionDuration + mtlsAppList["app_type"] = appObj.Type + mtlsAppList["app_uid"] = appObj.Uid + mtlsAppList["app_created_at"] = appObj.CreatedAt + mtlsAppList["app_updated_at"] = appObj.UpdatedAt + + PolicyOpt := sess.NewListAccessPoliciesOptions(zoneID, *appObj.ID) + PolicyResult, PolicyResp, PolicyErr := sess.ListAccessPolicies(PolicyOpt) + if PolicyErr != nil { + log.Printf("[WARN] List all Policies failed: %v\n", PolicyResp) + return diag.FromErr(PolicyErr) + } + + for _, PolicyObj := range PolicyResult.Result { + mtlsPolicyList := map[string]interface{}{} + mtlsPolicyList["policy_id"] = *PolicyObj.ID + mtlsPolicyList["policy_name"] = *PolicyObj.Name + mtlsPolicyList["policy_decision"] = *PolicyObj.Decision + mtlsPolicyList["policy_precedence"] = *PolicyObj.Precedence + mtlsPolicyList["policy_uid"] = *PolicyObj.Uid + mtlsPolicyList["policy_created_at"] = *PolicyObj.CreatedAt + mtlsPolicyList["policy_updated_at"] = *PolicyObj.UpdatedAt + + // TODO Include, Exclude and Require of Interface type + + mtlsPolicyLists = append(mtlsPolicyLists, mtlsPolicyList) + } + mtlsAppLists = append(mtlsAppLists, mtlsAppList) + + } + d.SetId(dataSourceCISMtlsAppCheckID(d)) + + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set("mtls_access_apps", mtlsAppLists) + d.Set("mtls_access_app_policies", mtlsPolicyLists) + + return nil +} +func dataSourceCISMtlsAppCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_mtls_app_test.go b/ibm/service/cis/data_source_ibm_cis_mtls_app_test.go new file mode 100644 index 000000000..55440955e --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_mtls_app_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisMtlsAppDataSource_Basic(t *testing.T) { + name := "data.ibm_cis_mtls_app.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisMtlsAppDataSource_basic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(name, "id"), + ), + }, + }, + }) +} +func testAccCheckCisMtlsAppDataSource_basic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_mtls_apps" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/service/cis/data_source_ibm_cis_mtls_test.go b/ibm/service/cis/data_source_ibm_cis_mtls_test.go new file mode 100644 index 000000000..b5eb9c61f --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_mtls_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisMtlsDataSource_Basic(t *testing.T) { + name := "data.ibm_cis_mtls.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisMtlsDataSource_basic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(name, "id"), + ), + }, + }, + }) +} +func testAccCheckCisMtlsDataSource_basic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_mtlss" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/service/cis/data_source_ibm_cis_origin_auth.go b/ibm/service/cis/data_source_ibm_cis_origin_auth.go new file mode 100644 index 000000000..7e32040b2 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_origin_auth.go @@ -0,0 +1,210 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + CisOriginAuthHostName = "hostname" + CisOriginAuthRequestType = "request_type" +) + +func DataSourceIBMCISOriginAuthPull() *schema.Resource { + return &schema.Resource{ + ReadContext: dataIBMCISOriginAuthRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_origin_auths", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + CisOriginAuthHostName: { + Type: schema.TypeString, + Description: "Associated CIS host name", + Optional: true, + Default: "no_host", + }, + CisOriginAuthRequestType: { + Type: schema.TypeString, + Description: "Associated CIS Request Type", + Optional: true, + Default: "zone_level", + }, + "origin_pull_settings_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "CIS origin auth settings enabled or disabled", + }, + "origin_pull_certs": { + Type: schema.TypeList, + Computed: true, + Description: "Certficate list", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert_id": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate id", + }, + + "certificate": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "CIS origin auth certificate detail", + }, + "cert_issuer": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate issue", + }, + "cert_signature": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate signature", + }, + "cert_status": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate active or not", + }, + "cert_expires_on": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate expiry time", + }, + "cert_uploaded_on": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate upldate time", + }, + "cert_serial_number": { + Type: schema.TypeString, + Computed: true, + Description: "CIS origin auth certificate Serial Number", + }, + }, + }, + }, + }, + } + +} +func DataSourceIBMCISOriginAuthPullValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISOriginAuthValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_origin_auths", + Schema: validateSchema} + return &iBMCISOriginAuthValidator +} + +func dataIBMCISOriginAuthRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).CisOrigAuthSession() + if err != nil { + return diag.FromErr(err) + } + + crn := d.Get(cisID).(string) + zoneID, _, _, _ := flex.ConvertTfToCisThreeVar(d.Get(cisDomainID).(string)) + sess.Crn = core.StringPtr(crn) + sess.ZoneIdentifier = core.StringPtr(zoneID) + + request_type := d.Get(CisOriginAuthRequestType).(string) + + if request_type == "zone_level" { + + // Get Zone Origin Pull Settings + zoneSettingsOpt := sess.NewGetZoneOriginPullSettingsOptions() + zoneSettingsResult, zoneSettingsResponse, zoneSettingsErr := sess.GetZoneOriginPullSettings(zoneSettingsOpt) + + if zoneSettingsErr != nil || zoneSettingsResponse == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Zone Level Origin Pull Settings: %s, Response: %s", zoneSettingsErr, zoneSettingsResponse)) + } + + zoneSettings := zoneSettingsResult.Result.Enabled + d.Set("origin_pull_settings_enabled", zoneSettings) + + // Get Zone Origin Pull Certificate List + zoneCertListOpt := sess.NewListZoneOriginPullCertificatesOptions() + zoneCertListResult, zoneCertListResponse, zoneCertListErr := sess.ListZoneOriginPullCertificates(zoneCertListOpt) + + if zoneCertListErr != nil || zoneCertListResponse == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Zone Level Origin Pull Settings: %s, Response: %s", zoneCertListErr, zoneCertListResponse)) + } + + zoneCertLists := make([]map[string]interface{}, 0) + zoneCertList := map[string]interface{}{} + + for _, certObj := range zoneCertListResult.Result { + + zoneCertList["cert_id"] = *certObj.ID + zoneCertList["certificate"] = *certObj.Certificate + zoneCertList["cert_issuer"] = *certObj.Issuer + zoneCertList["cert_signature"] = *certObj.Signature + zoneCertList["cert_status"] = *certObj.Status + zoneCertList["cert_expires_on"] = *certObj.ExpiresOn + zoneCertList["cert_uploaded_on"] = *certObj.UploadedOn + + } + zoneCertLists = append(zoneCertLists, zoneCertList) + d.Set("origin_pull_certs", zoneCertLists) + + } else if request_type == "per_hostname" { + + // Get Hostname Origin Pull Settings + hostname := d.Get(CisOriginAuthHostName).(string) + hostnameSettingsOpt := sess.NewGetHostnameOriginPullSettingsOptions(hostname) + hostnameSettingsOpt.SetHostname(hostname) + + hostnameSettingsResult, hostnameSettingsResponse, hostnameSettingsErr := sess.GetHostnameOriginPullSettings(hostnameSettingsOpt) + + if hostnameSettingsErr != nil || hostnameSettingsResponse == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Zone Level Origin Pull Settings: %s", hostnameSettingsErr)) + } + + hostnameSettings := hostnameSettingsResult.Result.Enabled + d.Set("origin_pull_settings_enabled", hostnameSettings) + } + + d.SetId(DataSourceIBMCISOriginAuthPullID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(CisOriginAuthRequestType, request_type) + return nil +} + +func DataSourceIBMCISOriginAuthPullID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/data_source_ibm_cis_origin_auth_test.go b/ibm/service/cis/data_source_ibm_cis_origin_auth_test.go new file mode 100644 index 000000000..e79bd1787 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_origin_auth_test.go @@ -0,0 +1,53 @@ +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisOrigAuthDataSource_basic(t *testing.T) { + node := "data.ibm_cis_origin_auths.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCisOrigAuthDataSourceZoneConfig("test"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "origin_pull_settings_enabled"), + resource.TestCheckResourceAttrSet(node, "origin_pull_certs_list.0.%"), + ), + }, + { + Config: testAccCheckIBMCisOrigAuthDataSourceHostnameConfig("test"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "origin_pull_settings_enabled"), + ), + }, + }, + }) +} + +func testAccCheckIBMCisOrigAuthDataSourceZoneConfig(id string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_origin_auths" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id) +} + +func testAccCheckIBMCisOrigAuthDataSourceHostnameConfig(id string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_origin_auths" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + request_type = "per_hostname" + hostname = data.ibm_cis_domain.cis_domain.domain + } +`, id) +} diff --git a/ibm/data_source_ibm_cis_origin_pools.go b/ibm/service/cis/data_source_ibm_cis_origin_pools.go similarity index 81% rename from ibm/data_source_ibm_cis_origin_pools.go rename to ibm/service/cis/data_source_ibm_cis_origin_pools.go index 9ca417e3f..8627a350b 100644 --- a/ibm/data_source_ibm_cis_origin_pools.go +++ b/ibm/service/cis/data_source_ibm_cis_origin_pools.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +18,7 @@ const ( cisOriginPools = "cis_origin_pools" ) -func dataSourceIBMCISOriginPools() *schema.Resource { +func DataSourceIBMCISOriginPools() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISGLBPoolsRead, Importer: &schema.ResourceImporter{}, @@ -28,6 +31,9 @@ func dataSourceIBMCISOriginPools() *schema.Resource { Type: schema.TypeString, Required: true, Description: "DNS Zone CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_origin_pools", + "cis_id"), }, cisOriginPools: { Type: schema.TypeList, @@ -141,9 +147,26 @@ func dataSourceIBMCISOriginPools() *schema.Resource { }, } } +func DataSourceIBMCISOriginPoolsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISOriginPoolsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_origin_pools", + Schema: validateSchema} + return &iBMCISOriginPoolsValidator +} func dataSourceIBMCISGLBPoolsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBPoolClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBPoolClientSession() if err != nil { return err } @@ -161,7 +184,7 @@ func dataSourceIBMCISGLBPoolsRead(d *schema.ResourceData, meta interface{}) erro pools := make([]map[string]interface{}, 0) for _, instance := range result.Result { pool := map[string]interface{}{} - pool["id"] = convertCisToTfTwoVar(*instance.ID, crn) + pool["id"] = flex.ConvertCisToTfTwoVar(*instance.ID, crn) pool[cisGLBPoolID] = *instance.ID pool[cisGLBPoolName] = *instance.Name pool[cisGLBPoolOrigins] = flattenOrigins(instance.Origins) diff --git a/ibm/service/cis/data_source_ibm_cis_origin_pools_test.go b/ibm/service/cis/data_source_ibm_cis_origin_pools_test.go new file mode 100644 index 000000000..082705e7f --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_origin_pools_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisPoolsDataSource_Basic(t *testing.T) { + node := "data.ibm_cis_origin_pools.test" + rnd := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCisPoolsDataSourceConfig(rnd, acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.id"), + resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.pool_id"), + resource.TestCheckResourceAttrSet(node, "cis_origin_pools.0.description"), + ), + }, + }, + }) +} + +func testAccCheckIBMCisPoolsDataSourceConfig(resourceID, CisDomainStatic string) string { + return testAccCheckCisPoolConfigCisDSBasic(resourceID, acc.CisDomainStatic) + ` + data "ibm_cis_origin_pools" "test" { + cis_id = ibm_cis_origin_pool.origin_pool.cis_id + } + ` +} diff --git a/ibm/service/cis/data_source_ibm_cis_page_rules.go b/ibm/service/cis/data_source_ibm_cis_page_rules.go new file mode 100644 index 000000000..041027dae --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_page_rules.go @@ -0,0 +1,209 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisPageRules = "cis_page_rules" +) + +func DataSourceIBMCISPageRules() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISPageRulesRead, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "DNS Zone CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_page_rules", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "DNS Zone ID", + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisPageRules: { + Type: schema.TypeList, + Description: "Collection of page rules detail", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Page rule identifier", + }, + cisPageRuleID: { + Type: schema.TypeString, + Computed: true, + }, + cisPageRulePriority: { + Type: schema.TypeInt, + Description: "Page rule priority", + Computed: true, + }, + cisPageRuleStatus: { + Type: schema.TypeString, + Description: "Page Rule status", + Computed: true, + }, + cisPageRuleTargets: { + Type: schema.TypeList, + Description: "Page rule targets", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisPageRuleTargetsTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Page rule target url", + }, + cisPageRuleTargetsConstraint: { + Type: schema.TypeList, + Computed: true, + Description: "Page rule constraint", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisPageRuleTargetsConstraintOperator: { + Type: schema.TypeString, + Computed: true, + Description: "Constraint operator", + }, + cisPageRuleTargetsConstraintValue: { + Type: schema.TypeString, + Computed: true, + Description: "Constraint value", + }, + }, + }, + }, + }, + }, + }, + cisPageRuleActions: { + Type: schema.TypeList, + Description: "Page rule actions", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisPageRuleActionsID: { + Type: schema.TypeString, + Computed: true, + Description: "Page rule target url", + }, + cisPageRuleActionsValue: { + Type: schema.TypeString, + Computed: true, + Description: "Page rule target url", + }, + cisPageRuleActionsValueURL: { + Type: schema.TypeString, + Computed: true, + Description: "Page rule actions value url", + }, + cisPageRuleActionsValueStatusCode: { + Type: schema.TypeInt, + Computed: true, + Description: "Page rule actions status code", + }, + cisPageRuleActionsMinifyCSS: { + Type: schema.TypeString, + Description: "Minify CSS value", + Computed: true, + }, + cisPageRuleActionsMinifyHTML: { + Type: schema.TypeString, + Description: "Minify HTML value", + Computed: true, + }, + cisPageRuleActionsMinifyJS: { + Type: schema.TypeString, + Description: "Minify JS value", + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISPageRulesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISPageRulesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_page_rules", + Schema: validateSchema} + return &iBMCISPageRulesValidator +} +func dataSourceIBMCISPageRulesRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisPageRuleClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + sess.Crn = core.StringPtr(crn) + sess.ZoneID = core.StringPtr(zoneID) + + opt := sess.NewListPageRulesOptions() + + result, resp, err := sess.ListPageRules(opt) + if err != nil { + log.Printf("Error listing page rules detail: %s", resp) + return err + } + + pageRules := make([]map[string]interface{}, 0) + for _, instance := range result.Result { + pageRule := map[string]interface{}{} + pageRule["id"] = flex.ConvertCisToTfThreeVar(*instance.ID, zoneID, crn) + pageRule[cisPageRuleID] = *instance.ID + pageRule[cisPageRulePriority] = *instance.Priority + pageRule[cisPageRuleStatus] = *instance.Status + pageRule[cisPageRuleTargets] = flattenCISPageRuleTargets(instance.Targets) + pageRule[cisPageRuleActions] = flattenCISPageRuleActions(instance.Actions) + pageRules = append(pageRules, pageRule) + } + d.SetId(dataSourceIBMCISPageRulesID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisPageRules, pageRules) + return nil +} + +func dataSourceIBMCISPageRulesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_page_rules_test.go b/ibm/service/cis/data_source_ibm_cis_page_rules_test.go similarity index 79% rename from ibm/data_source_ibm_cis_page_rules_test.go rename to ibm/service/cis/data_source_ibm_cis_page_rules_test.go index 706b52b82..b5baf3941 100644 --- a/ibm/data_source_ibm_cis_page_rules_test.go +++ b/ibm/service/cis/data_source_ibm_cis_page_rules_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisPageRuleDataSource_basic(t *testing.T) { node := "data.ibm_cis_page_rules.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisPageRuleDataSourceConfig(), @@ -29,9 +30,9 @@ func TestAccIBMCisPageRuleDataSource_basic(t *testing.T) { func testAccCheckIBMCisPageRuleDataSourceConfig() string { // status filter defaults to empty - return testAccCheckIBMCisPageRuleConfigBasic() + fmt.Sprintf(` + return testAccCheckIBMCisPageRuleConfigBasic() + ` data "ibm_cis_page_rules" "test" { cis_id = ibm_cis_page_rule.page_rule.cis_id domain_id = ibm_cis_page_rule.page_rule.domain_id - }`) + }` } diff --git a/ibm/data_source_ibm_cis_range_apps.go b/ibm/service/cis/data_source_ibm_cis_range_apps.go similarity index 77% rename from ibm/data_source_ibm_cis_range_apps.go rename to ibm/service/cis/data_source_ibm_cis_range_apps.go index 0f3a77fb2..aa7d75637 100644 --- a/ibm/data_source_ibm_cis_range_apps.go +++ b/ibm/service/cis/data_source_ibm_cis_range_apps.go @@ -1,19 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const cisRangeApps = "range_apps" -func dataSourceIBMCISRangeApps() *schema.Resource { +func DataSourceIBMCISRangeApps() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISRangeAppsRead, Schema: map[string]*schema.Schema{ @@ -21,6 +24,9 @@ func dataSourceIBMCISRangeApps() *schema.Resource { Type: schema.TypeString, Required: true, Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_range_apps", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -121,30 +127,48 @@ func dataSourceIBMCISRangeApps() *schema.Resource { }, } } +func DataSourceIBMCISRangeAppsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISRangeAppsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_range_apps", + Schema: validateSchema} + return &iBMCISRangeAppsValidator +} func dataSourceIBMCISRangeAppsRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRangeAppClientSession() + cisClient, err := meta.(conns.ClientSession).CisRangeAppClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewListRangeAppsOptions() result, resp, err := cisClient.ListRangeApps(opt) if err != nil { - return fmt.Errorf("Failed to list range applications: %v", resp) + return fmt.Errorf("[ERROR] Failed to list range applications: %v", resp) } apps := make([]map[string]interface{}, 0) for _, i := range result.Result { app := map[string]interface{}{} - app["id"] = convertCisToTfThreeVar(*i.ID, zoneID, crn) + app["id"] = flex.ConvertCisToTfThreeVar(*i.ID, zoneID, crn) app[cisRangeAppID] = *i.ID app[cisRangeAppProtocol] = *i.Protocol app[cisRangeAppDNS] = *i.Dns.Name app[cisRangeAppDNSType] = *i.Dns.Type - app[cisRangeAppOriginDirect] = flattenStringList(i.OriginDirect) + app[cisRangeAppOriginDirect] = flex.FlattenStringList(i.OriginDirect) app[cisRangeAppIPFirewall] = *i.IpFirewall app[cisRangeAppProxyProtocol] = *i.ProxyProtocol app[cisRangeAppEdgeIPsType] = *i.EdgeIps.Type diff --git a/ibm/data_source_ibm_cis_range_apps_test.go b/ibm/service/cis/data_source_ibm_cis_range_apps_test.go similarity index 79% rename from ibm/data_source_ibm_cis_range_apps_test.go rename to ibm/service/cis/data_source_ibm_cis_range_apps_test.go index a9478330a..13d9c1993 100644 --- a/ibm/data_source_ibm_cis_range_apps_test.go +++ b/ibm/service/cis/data_source_ibm_cis_range_apps_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisRangeAppsDataSource_basic(t *testing.T) { node := "data.ibm_cis_range_apps.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisRangeAppsDataSourceConfig(), @@ -28,9 +29,9 @@ func TestAccIBMCisRangeAppsDataSource_basic(t *testing.T) { } func testAccCheckIBMCisRangeAppsDataSourceConfig() string { - return testAccCheckCisRangeAppConfigBasic() + fmt.Sprintf(` + return testAccCheckCisRangeAppConfigBasic() + ` data "ibm_cis_range_apps" "test" { cis_id = ibm_cis_range_app.app.cis_id domain_id = ibm_cis_range_app.app.domain_id - }`) + }` } diff --git a/ibm/data_source_ibm_cis_rate_limit.go b/ibm/service/cis/data_source_ibm_cis_rate_limit.go similarity index 82% rename from ibm/data_source_ibm_cis_rate_limit.go rename to ibm/service/cis/data_source_ibm_cis_rate_limit.go index 4bac09aa4..560dbb2bb 100644 --- a/ibm/data_source_ibm_cis_rate_limit.go +++ b/ibm/service/cis/data_source_ibm_cis_rate_limit.go @@ -1,23 +1,29 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMCISRateLimit() *schema.Resource { +func DataSourceIBMCISRateLimit() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMCISRateLimitRead, Schema: map[string]*schema.Schema{ "cis_id": { Type: schema.TypeString, Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_rate_limit", + "cis_id"), }, "domain_id": { Type: schema.TypeString, @@ -181,20 +187,37 @@ func dataSourceIBMCISRateLimit() *schema.Resource { }, } } +func DataSourceIBMCISRateLimitValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISRateLimitValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_rate_limit", + Schema: validateSchema} + return &iBMCISRateLimitValidator +} func dataSourceIBMCISRateLimitRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisRLClientSession() + cisClient, err := meta.(conns.ClientSession).CisRLClientSession() if err != nil { return err } cisID := d.Get("cis_id").(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get("domain_id").(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get("domain_id").(string)) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewListAllZoneRateLimitsOptions() rateLimitRecord, resp, err := cisClient.ListAllZoneRateLimits(opt) if err != nil { - return fmt.Errorf("Failed to read RateLimit: %v", resp) + return fmt.Errorf("[ERROR] Failed to read RateLimit: %v", resp) } rules := make([]map[string]interface{}, 0) for _, r := range rateLimitRecord.Result { diff --git a/ibm/data_source_ibm_cis_rate_limit_test.go b/ibm/service/cis/data_source_ibm_cis_rate_limit_test.go similarity index 80% rename from ibm/data_source_ibm_cis_rate_limit_test.go rename to ibm/service/cis/data_source_ibm_cis_rate_limit_test.go index 596ea7240..80d305fff 100644 --- a/ibm/data_source_ibm_cis_rate_limit_test.go +++ b/ibm/service/cis/data_source_ibm_cis_rate_limit_test.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisRateLimitDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisRateLimitDataSourceConfigBasic1(), @@ -25,10 +26,10 @@ func TestAccIBMCisRateLimitDataSource_Basic(t *testing.T) { } func testAccCheckIBMCisRateLimitDataSourceConfigBasic1() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` data "ibm_cis_rate_limit" "ratelimit" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id } - `) + ` } diff --git a/ibm/data_source_ibm_cis_test.go b/ibm/service/cis/data_source_ibm_cis_test.go similarity index 80% rename from ibm/data_source_ibm_cis_test.go rename to ibm/service/cis/data_source_ibm_cis_test.go index 522ea25c9..dcd33bb1e 100644 --- a/ibm/data_source_ibm_cis_test.go +++ b/ibm/service/cis/data_source_ibm_cis_test.go @@ -1,23 +1,25 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisDataSource_basic(t *testing.T) { - instanceName := fmt.Sprintf(cisInstance) + instanceName := fmt.Sprintf(acc.CisInstance) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCisDataSourceConfig(instanceName), Destroy: true, Check: resource.ComposeTestCheckFunc( @@ -41,6 +43,6 @@ func testAccCheckIBMCisDataSourceConfig(instanceName string) string { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s" } - `, cisResourceGroup, instanceName) + `, acc.CisResourceGroup, instanceName) } diff --git a/ibm/service/cis/data_source_ibm_cis_waf_groups.go b/ibm/service/cis/data_source_ibm_cis_waf_groups.go new file mode 100644 index 000000000..c92cc14e3 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_waf_groups.go @@ -0,0 +1,149 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cisWAFGroups = "waf_groups" + +func DataSourceIBMCISWAFGroups() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISWAFGroupsRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_waf_groups", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Domain ID", + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisWAFGroupPackageID: { + Type: schema.TypeString, + Required: true, + Description: "WAF Rule package id", + }, + cisWAFGroups: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule group id", + }, + cisWAFGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule group id", + }, + cisWAFGroupMode: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule group mode on/off", + }, + cisWAFGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule group name", + }, + cisWAFGroupDesc: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule group description", + }, + cisWAFGroupRulesCount: { + Type: schema.TypeInt, + Computed: true, + Description: "WAF Rule group rules count", + }, + cisWAFGroupModifiedRulesCount: { + Type: schema.TypeInt, + Computed: true, + Description: "WAF Rule group modified rules count", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISWAFGroupsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISWAFGroupsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_waf_groups", + Schema: validateSchema} + return &iBMCISWAFGroupsValidator +} + +func dataSourceIBMCISWAFGroupsRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisWAFGroupClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneID = core.StringPtr(zoneID) + packageID, _, _, _ := flex.ConvertTfToCisThreeVar(d.Get(cisWAFGroupPackageID).(string)) + + opt := cisClient.NewListWafRuleGroupsOptions(packageID) + opt.SetPage(1) + opt.SetPerPage(100) + result, resp, err := cisClient.ListWafRuleGroups(opt) + if err != nil { + log.Printf("List waf rule groups failed: %s\n", resp) + return err + } + wafGroups := []interface{}{} + for _, i := range result.Result { + waf := map[string]interface{}{} + waf["id"] = flex.ConvertCisToTfFourVar(*i.ID, packageID, zoneID, crn) + waf[cisWAFGroupID] = *i.ID + waf[cisWAFGroupName] = *i.Name + waf[cisWAFGroupDesc] = *i.Description + waf[cisWAFGroupMode] = *i.Mode + waf[cisWAFGroupModifiedRulesCount] = *i.ModifiedRulesCount + waf[cisWAFGroupRulesCount] = *i.RulesCount + wafGroups = append(wafGroups, waf) + } + d.SetId(dataSourceIBMCISWAFGroupID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisWAFGroupPackageID, packageID) + d.Set(cisWAFGroups, wafGroups) + return nil +} + +func dataSourceIBMCISWAFGroupID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_waf_groups_test.go b/ibm/service/cis/data_source_ibm_cis_waf_groups_test.go similarity index 83% rename from ibm/data_source_ibm_cis_waf_groups_test.go rename to ibm/service/cis/data_source_ibm_cis_waf_groups_test.go index 1eb693975..1a2d52743 100644 --- a/ibm/data_source_ibm_cis_waf_groups_test.go +++ b/ibm/service/cis/data_source_ibm_cis_waf_groups_test.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisWAFGroupsDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisWAFGroupsDataSourceConfigBasic1(), @@ -26,11 +27,11 @@ func TestAccIBMCisWAFGroupsDataSource_Basic(t *testing.T) { } func testAccCheckIBMCisWAFGroupsDataSourceConfigBasic1() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` data "ibm_cis_waf_groups" "waf_groups" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id package_id = "c504870194831cd12c3fc0284f294abb" } - `) + ` } diff --git a/ibm/service/cis/data_source_ibm_cis_waf_packages.go b/ibm/service/cis/data_source_ibm_cis_waf_packages.go new file mode 100644 index 000000000..33eb4883f --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_waf_packages.go @@ -0,0 +1,134 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisWAFPackages = "waf_packages" +) + +func DataSourceIBMCISWAFPackages() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISWAFPackagesRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "DNS Zone CRN", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_waf_packages", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "CIS domain id", + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisWAFPackages: { + Type: schema.TypeList, + Description: "Collection of GLB Health check/monitor detail", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "CIS WAF package id", + }, + cisWAFPackageID: { + Type: schema.TypeString, + Computed: true, + Description: "WAF pakcage ID", + }, + cisWAFPackageName: { + Type: schema.TypeString, + Computed: true, + Description: "WAF pakcage name", + }, + cisWAFPackageDetectionMode: { + Type: schema.TypeString, + Computed: true, + Description: "WAF pakcage detection mode", + }, + cisWAFPackageDescription: { + Type: schema.TypeString, + Computed: true, + Description: "WAF pakcage description", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISWAFPackagesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISWAFPackagesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_waf_packages", + Schema: validateSchema} + return &iBMCISWAFPackagesValidator +} +func dataSourceIBMCISWAFPackagesRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisWAFPackageClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneID = core.StringPtr(zoneID) + + opt := cisClient.NewListWafPackagesOptions() + result, resp, err := cisClient.ListWafPackages(opt) + if err != nil { + log.Printf("Error listing waf packages detail: %s", resp) + return err + } + + packages := make([]interface{}, 0) + for _, instance := range result.Result { + packageDetail := make(map[string]interface{}) + packageDetail["id"] = flex.ConvertCisToTfThreeVar(*instance.ID, zoneID, crn) + packageDetail[cisWAFPackageID] = *instance.ID + packageDetail[cisWAFPackageName] = *instance.Name + packageDetail[cisWAFPackageDetectionMode] = *instance.DetectionMode + + if instance.Description != nil { + packageDetail[cisWAFPackageDescription] = *instance.Description + } + packages = append(packages, packageDetail) + } + d.SetId(dataSourceIBMCISWAFPackagesCheckID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisWAFPackages, packages) + return nil +} + +func dataSourceIBMCISWAFPackagesCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_waf_packages_test.go b/ibm/service/cis/data_source_ibm_cis_waf_packages_test.go similarity index 76% rename from ibm/data_source_ibm_cis_waf_packages_test.go rename to ibm/service/cis/data_source_ibm_cis_waf_packages_test.go index c5e5ab9e3..2f83e2b75 100644 --- a/ibm/data_source_ibm_cis_waf_packages_test.go +++ b/ibm/service/cis/data_source_ibm_cis_waf_packages_test.go @@ -1,19 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisWAFPackagesDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisWAFPackagesDataSourceConfig(), @@ -27,10 +28,10 @@ func TestAccIBMCisWAFPackagesDataSource_basic(t *testing.T) { } func testAccCheckIBMCisWAFPackagesDataSourceConfig() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` data "ibm_cis_waf_packages" "packages" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id } - `) + ` } diff --git a/ibm/service/cis/data_source_ibm_cis_waf_rules.go b/ibm/service/cis/data_source_ibm_cis_waf_rules.go new file mode 100644 index 000000000..cf6b80bb8 --- /dev/null +++ b/ibm/service/cis/data_source_ibm_cis_waf_rules.go @@ -0,0 +1,181 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cisWAFRules = "waf_rules" + +func DataSourceIBMCISWAFRules() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCISWAFRuleRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_waf_rules", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "CISzone - Domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisWAFRulePackageID: { + Type: schema.TypeString, + Description: "WAF rule package id", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisWAFRules: { + Type: schema.TypeList, + Description: "Collection of WAF Rules", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule id", + }, + cisWAFRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Rule id", + }, + cisWAFRulePackageID: { + Type: schema.TypeString, + Computed: true, + Description: "WAF Package id", + }, + cisWAFRuleMode: { + Type: schema.TypeString, + Computed: true, + Description: "CIS WAF Rule mode", + }, + cisWAFRuleDesc: { + Type: schema.TypeString, + Computed: true, + Description: "CIS WAF Rule descriptions", + }, + cisWAFRulePriority: { + Type: schema.TypeString, + Computed: true, + Description: "CIS WAF Rule Priority", + }, + cisWAFRuleGroup: { + Type: schema.TypeList, + Computed: true, + Description: "CIS WAF Rule group", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisWAFRuleGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "waf rule group id", + }, + cisWAFRuleGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "waf rule group name", + }, + }, + }, + }, + cisWAFRuleAllowedModes: { + Type: schema.TypeList, + Computed: true, + Description: "CIS WAF Rule allowed modes", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISWAFRulesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISWAFRulesValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_waf_rules", + Schema: validateSchema} + return &iBMCISWAFRulesValidator +} +func dataSourceIBMCISWAFRuleRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisWAFRuleClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneID = core.StringPtr(zoneID) + packageID, _, _, _ := flex.ConvertTfToCisThreeVar(d.Get(cisWAFRulePackageID).(string)) + + opt := cisClient.NewListWafRulesOptions(packageID) + opt.SetPage(1) + opt.SetPerPage(1000) + result, response, err := cisClient.ListWafRules(opt) + if err != nil { + log.Printf("List waf rules failed %s\n", response) + return err + } + rules := []interface{}{} + for _, i := range result.Result { + + groups := []interface{}{} + group := map[string]interface{}{} + group[cisWAFRuleGroupID] = *i.Group.ID + group[cisWAFRuleGroupName] = *i.Group.Name + groups = append(groups, group) + + rule := map[string]interface{}{} + rule["id"] = flex.ConvertCisToTfFourVar(*i.ID, *i.PackageID, zoneID, crn) + rule[cisWAFRuleID] = *i.ID + rule[cisWAFRulePackageID] = *i.PackageID + rule[cisWAFRuleMode] = *i.Mode + rule[cisWAFRuleDesc] = *i.Description + rule[cisWAFRulePriority] = *i.Priority + rule[cisWAFRuleGroup] = groups + rule[cisWAFRuleAllowedModes] = flex.FlattenStringList(i.AllowedModes) + + rules = append(rules, rule) + } + d.SetId(dataSourceIBMCISWAFRulesID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisWAFRulePackageID, packageID) + d.Set(cisWAFRules, rules) + return nil +} + +func dataSourceIBMCISWAFRulesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_cis_waf_rules_test.go b/ibm/service/cis/data_source_ibm_cis_waf_rules_test.go similarity index 81% rename from ibm/data_source_ibm_cis_waf_rules_test.go rename to ibm/service/cis/data_source_ibm_cis_waf_rules_test.go index 15a7beb00..93d374e2d 100644 --- a/ibm/data_source_ibm_cis_waf_rules_test.go +++ b/ibm/service/cis/data_source_ibm_cis_waf_rules_test.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisWAFRulesDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisWAFRulesDataSourceConfigBasic1(), @@ -25,11 +26,11 @@ func TestAccIBMCisWAFRulesDataSource_Basic(t *testing.T) { } func testAccCheckIBMCisWAFRulesDataSourceConfigBasic1() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` data "ibm_cis_waf_rules" "rules" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id package_id = "1e334934fd7ae32ad705667f8c1057aa" } - `) + ` } diff --git a/ibm/service/cis/datasource_ibm_cis_logpush_jobs.go b/ibm/service/cis/datasource_ibm_cis_logpush_jobs.go new file mode 100644 index 000000000..fc8aacd86 --- /dev/null +++ b/ibm/service/cis/datasource_ibm_cis_logpush_jobs.go @@ -0,0 +1,139 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisLogpushJobs = "logpush_job_pack" +) + +func DataSourceIBMCISLogPushJobs() *schema.Resource { + return &schema.Resource{ + Read: ResourceIBMCISLogpushJobsRead, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_cis_logpush_jobs", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisLogpushJobs: { + Type: schema.TypeList, + Computed: true, + Description: "logpush jobs information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisLogpushJobID: { + Type: schema.TypeInt, + Description: "Associated CIS domain ", + Computed: true, + }, + cisLogpushName: { + Type: schema.TypeString, + Computed: true, + Description: "Logpush Job Name", + }, + cisLogpushEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the logpush job enabled or not", + }, + cisLogpullOpt: { + Type: schema.TypeString, + Computed: true, + Description: "Configuration string", + }, + cisLogpushDestConf: { + Type: schema.TypeString, + Computed: true, + Description: "Uniquely identifies a resource (such as an s3 bucket) where data will be pushed.", + }, + cisLogpushDataset: { + Type: schema.TypeString, + Computed: true, + Description: "Dataset to be pulled", + }, + cisLogpushFreq: { + Type: schema.TypeString, + Computed: true, + Description: "The frequency at which CIS sends batches of logs to your destination", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMCISLogPushJobsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + iBMCISLogPushJobsValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_logpush_jobs", + Schema: validateSchema} + return &iBMCISLogPushJobsValidator +} +func ResourceIBMCISLogpushJobsRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisLogpushJobsSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + sess.Crn = core.StringPtr(crn) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + sess.ZoneID = core.StringPtr(zoneID) + opt := sess.NewGetLogpushJobsV2Options() + result, resp, err := sess.GetLogpushJobsV2(opt) + if err != nil { + log.Printf("[WARN] List all Logpush jobs failed: %v\n", resp) + return err + } + logPushList := make([]map[string]interface{}, 0) + for _, logpushObj := range result.Result { + logPushOpt := map[string]interface{}{} + logPushOpt[cisLogpushJobID] = int64(*logpushObj.ID) + logPushOpt[cisLogpushName] = *logpushObj.Name + logPushOpt[cisLogpullOpt] = *logpushObj.LogpullOptions + logPushOpt[cisLogpushEnabled] = *logpushObj.Enabled + logPushOpt[cisLogpushDataset] = *logpushObj.Dataset + logPushOpt[cisLogpushFreq] = *logpushObj.Frequency + logPushOpt[cisLogpushDestConf] = *logpushObj.DestinationConf + logPushList = append(logPushList, logPushOpt) + } + d.SetId(dataSourceCISLogpushJobsCheckID(d)) + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisLogpushJobs, logPushList) + return nil +} +func dataSourceCISLogpushJobsCheckID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/cis/datasource_ibm_cis_logpush_jobs_test.go b/ibm/service/cis/datasource_ibm_cis_logpush_jobs_test.go new file mode 100644 index 000000000..8098b57df --- /dev/null +++ b/ibm/service/cis/datasource_ibm_cis_logpush_jobs_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisLogpushJobsDataSource_Basic(t *testing.T) { + Name := "data.ibm_cis_logpush_jobs.test" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisLogpushJobsDataSource_basic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(Name, "id"), + ), + }, + }, + }) +} +func testAccCheckCisLogpushJobsDataSource_basic(id, CisDomainStatic string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + data "ibm_cis_logpush_jobs" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + } +`, id, acc.CisDomainStatic) +} diff --git a/ibm/service/cis/resource_ibm_cis.go b/ibm/service/cis/resource_ibm_cis.go new file mode 100644 index 000000000..178f21ff8 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis.go @@ -0,0 +1,575 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + "log" + "net/url" + "os" + "strings" + "time" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +const ( + CisInstanceSuccessStatus = "active" + CisInstanceProgressStatus = "in progress" + cisInstanceProvisioningStatus = "provisioning" + CisInstanceInactiveStatus = "inactive" + CisInstanceFailStatus = "failed" + CisInstanceRemovedStatus = "removed" + cisInstanceReclamation = "pending_reclamation" +) + +func ResourceIBMCISInstance() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISInstanceCreate, + Read: ResourceIBMCISInstanceRead, + Update: ResourceIBMCISInstanceUpdate, + Delete: ResourceIBMCISInstanceDelete, + Exists: ResourceIBMCISInstanceExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "A name for the resource instance", + }, + + "service": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the Cloud Internet Services offering", + }, + + "plan": { + Type: schema.TypeString, + Required: true, + Description: "The plan type of the service", + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier of resource instance", + }, + + "location": { + Description: "The location where the instance available", + Required: true, + ForceNew: true, + Type: schema.TypeString, + }, + + "resource_group_id": { + Description: "The resource group id", + Optional: true, + ForceNew: true, + Type: schema.TypeString, + Computed: true, + }, + + "parameters": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Description: "Arbitrary parameters to pass. Must be a JSON object", + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_cis", "tags")}, + Set: flex.ResourceIBMVPCHash, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of resource instance", + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} + +func ResourceIBMCISValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmCISResourceValidator := validate.ResourceValidator{ResourceName: "ibm_cis", Schema: validateSchema} + return &ibmCISResourceValidator +} + +// Replace with func wrapper for resourceIBMResourceInstanceCreate specifying serviceName := "internet-svcs" +func ResourceIBMCISInstanceCreate(d *schema.ResourceData, meta interface{}) error { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + serviceName := "internet-svcs" + plan := d.Get("plan").(string) + name := d.Get("name").(string) + location := d.Get("location").(string) + + rsInst := rc.CreateResourceInstanceOptions{ + Name: &name, + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(serviceName, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + rsInst.ResourcePlanID = &servicePlan + + deployments, err := rsCatRepo.ListDeployments(servicePlan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving deployment for plan %s : %s", plan, err) + } + if len(deployments) == 0 { + return fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan) + } + deployments, supportedLocations := filterCISDeployments(deployments, location) + + if len(deployments) == 0 { + locationList := make([]string, 0, len(supportedLocations)) + for l := range supportedLocations { + locationList = append(locationList, l) + } + return fmt.Errorf("[ERROR] No deployment found for service plan %s at location %s.\nValid location(s) are: %q", plan, location, locationList) + } + + rsInst.Target = &deployments[0].CatalogCRN + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rg := rsGrpID.(string) + rsInst.ResourceGroup = &rg + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInst.ResourceGroup = &defaultRg + } + + if parameters, ok := d.GetOk("parameters"); ok { + rsInst.Parameters = parameters.(map[string]interface{}) + } + + instance, response, err := rsConClient.CreateResourceInstance(&rsInst) + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource instance: %s %s", err, response) + } + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of ibm cis (%s) tags: %s", d.Id(), err) + } + } + + // Moved d.SetId(instance.ID) to after waiting for resource to finish creation. Otherwise Terraform initates depedent tasks too early. + // Original flow had SetId here as its required as input to waitForCISInstanceCreate + + _, err = waitForCISInstanceCreate(d, meta, *instance.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for create resource instance (%s) to be succeeded: %s", d.Id(), err) + } + + d.SetId(*instance.ID) + + return ResourceIBMCISInstanceRead(d, meta) +} + +func ResourceIBMCISInstanceRead(d *schema.ResourceData, meta interface{}) error { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + instanceID := d.Id() + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + log.Printf("[WARN] Removing record from state because it's not found via the API") + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) + } + if strings.Contains(*instance.State, "removed") { + log.Printf("[WARN] Removing instance from TF state because it's now in removed state") + d.SetId("") + return nil + } + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on get of ibm cis tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + d.Set("name", *instance.Name) + d.Set("status", *instance.State) + d.Set("resource_group_id", *instance.ResourceGroupID) + d.Set("parameters", flex.Flatten(instance.Parameters)) + if instance.CRN != nil { + location := strings.Split(*instance.CRN, ":") + if len(location) > 5 { + d.Set("location", location[5]) + } + } + d.Set("guid", *instance.GUID) + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + d.Set("service", "internet-svcs") + + servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.CRN) + d.Set(flex.ResourceStatus, *instance.State) + d.Set(flex.ResourceGroupName, *instance.ResourceGroupCRN) + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/internet-svcs/"+url.QueryEscape(*instance.CRN)) + + return nil +} + +func ResourceIBMCISInstanceUpdate(d *schema.ResourceData, meta interface{}) error { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + instanceID := d.Id() + + updateReq := rc.UpdateResourceInstanceOptions{ + ID: &instanceID, + } + if d.HasChange("name") { + name := d.Get("name").(string) + updateReq.Name = &name + } + + if d.HasChange("plan") { + plan := d.Get("plan").(string) + service := d.Get("service").(string) + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(service, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + + updateReq.ResourcePlanID = &servicePlan + + } + + if d.HasChange("tags") { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, instanceID) + if err != nil { + log.Printf( + "Error on update of CIS (%s) tags: %s", d.Id(), err) + } + } + + _, response, err := rsConClient.UpdateResourceInstance(&updateReq) + if err != nil { + return fmt.Errorf("[ERROR] Error updating resource instance: %s %s", err, response) + } + + _, err = waitForCISInstanceUpdate(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for update resource instance (%s) to be succeeded: %s", d.Id(), err) + } + + return ResourceIBMCISInstanceRead(d, meta) +} + +func ResourceIBMCISInstanceDelete(d *schema.ResourceData, meta interface{}) error { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + id := d.Id() + recursive := true + deleteReq := rc.DeleteResourceInstanceOptions{ + ID: &id, + Recursive: &recursive, + } + response, err := rsConClient.DeleteResourceInstance(&deleteReq) + if err != nil { + // If prior delete occurs, instance is not immediately deleted, but remains in "removed" state" + // RC 410 with "Gone" returned as error + if strings.Contains(err.Error(), "Gone") || + strings.Contains(err.Error(), "status code: 410") { + log.Printf("[WARN] Resource instance already deleted %s\n %s", err, response) + err = nil + } else { + return fmt.Errorf("[ERROR] Error deleting resource instance: %s %s", err, response) + } + } + + _, err = waitForCISInstanceDelete(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err) + } + + d.SetId("") + + return nil +} +func ResourceIBMCISInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error getting cis instance: %s %s", err, response) + } + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, cisInstanceReclamation)) { + log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") + d.SetId("") + return false, nil + } + + return *instance.ID == instanceID, nil +} + +func waitForCISInstanceCreate(d *schema.ResourceData, meta interface{}, instanceID string) (interface{}, error) { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + //instanceID := d.Id() + + stateConf := &resource.StateChangeConf{ + Pending: []string{CisInstanceProgressStatus, CisInstanceInactiveStatus, cisInstanceProvisioningStatus}, + Target: []string{CisInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %v %s", d.Id(), err, response) + } + return nil, "", err + } + if *instance.State == CisInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %v %s", d.Id(), err, response) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func waitForCISInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + + stateConf := &resource.StateChangeConf{ + Pending: []string{CisInstanceProgressStatus, CisInstanceInactiveStatus}, + Target: []string{CisInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %v %s", d.Id(), err, response) + } + return nil, "", err + } + if *instance.State == CisInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %v %s", d.Id(), err, response) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func waitForCISInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + stateConf := &resource.StateChangeConf{ + Pending: []string{CisInstanceProgressStatus, CisInstanceInactiveStatus, CisInstanceSuccessStatus}, + Target: []string{CisInstanceRemovedStatus, cisInstanceReclamation}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return instance, CisInstanceSuccessStatus, nil + } + return nil, "", err + } + if *instance.State == CisInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %v %s", d.Id(), err, response) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func filterCISDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { + supportedDeployments := []models.ServiceDeployment{} + supportedLocations := make(map[string]bool) + for _, d := range deployments { + if d.Metadata.RCCompatible { + deploymentLocation := d.Metadata.Deployment.Location + supportedLocations[deploymentLocation] = true + if deploymentLocation == location { + supportedDeployments = append(supportedDeployments, d) + } + } + } + return supportedDeployments, supportedLocations +} diff --git a/ibm/service/cis/resource_ibm_cis_alert.go b/ibm/service/cis/resource_ibm_cis_alert.go new file mode 100644 index 000000000..bf7906669 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_alert.go @@ -0,0 +1,418 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/networking-go-sdk/alertsv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmCISAlert = "ibm_cis_alert" + cisAlertID = "policy_id" + cisAlertName = "name" + cisAlertDescription = "description" + cisAlertEnabled = "enabled" + cisAlertType = "alert_type" + cisAlertMechanisms = "mechanisms" + cisAlertEmail = "email" + cisAlertEmailID = "email_id" + cisAlertWebhook = "webhooks" + cisAlertConditions = "conditions" + cisAlertFilters = "filters" + cisAlertFilterEnabled = "enabled" + cisAlertFilterPoolID = "pool_id" + cisAlertType1 = "dos_attack_l7" + cisAlertType2 = "g6_pool_toggle_alert" + cisAlertType3 = "clickhouse_alert_fw_anomaly" + cisAlertType4 = "clickhouse_alert_fw_ent_anomaly" +) + +func ResourceIBMCISAlert() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISAlertPolicyCreate, + Read: ResourceIBMCISAlertPolicyRead, + Update: ResourceIBMCISAlertPolicyUpdate, + Delete: ResourceIBMCISAlertPolicyDelete, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_alert", + "cis_id"), + }, + cisAlertID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the Alert Policy", + }, + cisAlertName: { + Type: schema.TypeString, + Required: true, + Description: "Policy name", + }, + cisAlertDescription: { + Type: schema.TypeString, + Optional: true, + Description: "Policy Description", + }, + cisAlertEnabled: { + Type: schema.TypeBool, + Required: true, + Description: "Is the alert policy active", + }, + cisAlertType: { + Type: schema.TypeString, + Required: true, + Description: "Condition for the alert", + }, + cisAlertMechanisms: { + Type: schema.TypeList, + Required: true, + Description: "Delivery mechanisms for the alert, can include an email, a webhook, or both.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisAlertEmail: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + cisAlertWebhook: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + }, + }, + }, + cisAlertFilters: { + Type: schema.TypeString, + Optional: true, + StateFunc: func(v interface{}) string { + json, err := flex.NormalizeJSONString(v) + if err != nil { + return fmt.Sprintf("%q", err.Error()) + } + return json + }, + Description: "Filters based on filter type", + }, + cisAlertConditions: { + Type: schema.TypeString, + Optional: true, + StateFunc: func(v interface{}) string { + json, err := flex.NormalizeJSONString(v) + if err != nil { + return fmt.Sprintf("%q", err.Error()) + } + return json + }, + Description: "Conditions based on filter type", + }, + }, + } +} +func ResourceIBMCISAlertValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISAlertValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_alert", + Schema: validateSchema} + return &ibmCISAlertValidator +} +func ResourceIBMCISAlertPolicyCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisAlertsSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisAlertsSession %s", err) + } + crn := d.Get(cisID).(string) + sess.Crn = core.StringPtr(crn) + + opt := sess.NewCreateAlertPolicyOptions() + + if name, ok := d.GetOk(cisAlertName); ok { + opt.SetName(name.(string)) + } + if description, ok := d.GetOk(cisAlertDescription); ok { + opt.SetDescription(description.(string)) + } + if enabled, ok := d.GetOk(cisAlertEnabled); ok { + opt.SetEnabled(enabled.(bool)) + } + if alertType, ok := d.GetOk(cisAlertType); ok { + opt.SetAlertType(alertType.(string)) + } + if retFilter, ok := d.GetOk(cisAlertFilters); ok { + var filter interface{} + json.Unmarshal([]byte(retFilter.(string)), &filter) + opt.Filters = filter + } + mechanismsOpt := &alertsv1.CreateAlertPolicyInputMechanisms{} + if mechanisms, ok := d.GetOk(cisAlertMechanisms); ok { + mechanism := mechanisms.([]interface{})[0].(map[string]interface{}) + webhook, ok := mechanism[cisAlertWebhook] + if ok { + webhookString := webhook.(*schema.Set) + if webhookString.Len() != 0 { + var webhookarray = make([]alertsv1.CreateAlertPolicyInputMechanismsWebhooksItem, webhookString.Len()) + for k, w := range webhookString.List() { + wString := w.(string) + webhookarray[k] = alertsv1.CreateAlertPolicyInputMechanismsWebhooksItem{ + ID: &wString, + } + } + mechanismsOpt.Webhooks = webhookarray + } + } + email, ok := mechanism[cisAlertEmail] + if ok { + emailString := email.(*schema.Set) + if emailString.Len() != 0 { + var emailarray = make([]alertsv1.CreateAlertPolicyInputMechanismsEmailItem, emailString.Len()) + for k, w := range emailString.List() { + wString := w.(string) + emailarray[k] = alertsv1.CreateAlertPolicyInputMechanismsEmailItem{ + ID: &wString, + } + } + mechanismsOpt.Email = emailarray + } + } + } + opt.Mechanisms = mechanismsOpt + result, resp, err := sess.CreateAlertPolicy(opt) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error creating Alert Policy %s %s", err, resp) + } + d.SetId(flex.ConvertCisToTfTwoVar(*result.Result.ID, crn)) + d.Set(cisAlertID, *result.Result.ID) + + return ResourceIBMCISAlertPolicyRead(d, meta) +} + +func ResourceIBMCISAlertPolicyRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisAlertsSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisAlertsSession %s", err) + } + + alertID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Error while ConvertTftoCisTwoVar %s", err) + } + sess.Crn = core.StringPtr(crn) + opt := sess.NewGetAlertPolicyOptions(alertID) + result, resp, err := sess.GetAlertPolicy(opt) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting alert policy detail %s, %s", err, resp) + } + + d.Set(cisID, crn) + d.Set(cisAlertID, *result.Result.ID) + d.Set(cisGLBPoolName, *result.Result.Name) + d.Set(cisAlertDescription, *result.Result.Description) + d.Set(cisAlertEnabled, *result.Result.Enabled) + d.Set(cisAlertType, *result.Result.AlertType) + d.Set(cisGLBPoolEnabled, *result.Result.Enabled) + if err := d.Set(cisAlertMechanisms, flattenCISMechanism(*result.Result.Mechanisms)); err != nil { + log.Printf("[WARN] Error setting mechanism for alert policies %q: %s", d.Id(), err) + } + + filterOpt, err := json.Marshal(result.Result.Filters) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling the created filters: %s", err) + } + if err = d.Set(cisAlertFilters, string(filterOpt)); err != nil { + return fmt.Errorf("[ERROR] Error setting the filters: %s", err) + } + conditionsOpt, err := json.Marshal(result.Result.Conditions) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling the created Conditions: %s", err) + } + if err = d.Set(cisAlertConditions, string(conditionsOpt)); err != nil { + return fmt.Errorf("[ERROR] Error setting the Conditions: %s", err) + } + return nil +} + +func ResourceIBMCISAlertPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisAlertsSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisAlertsSession %s", err) + } + + alertID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + + if err != nil { + return fmt.Errorf("[ERROR] Error while ConvertTftoCisTwoVar %s", err) + } + sess.Crn = core.StringPtr(crn) + + if d.HasChange(cisAlertName) || + d.HasChange(cisAlertEnabled) || + d.HasChange(cisAlertDescription) || + d.HasChange(cisAlertType) || + d.HasChange(cisAlertFilters) || + d.HasChange(cisAlertConditions) || + d.HasChange(cisAlertMechanisms) { + + opt := sess.NewUpdateAlertPolicyOptions(alertID) + if name, ok := d.GetOk(cisAlertName); ok { + opt.SetName(name.(string)) + } + if description, ok := d.GetOk(cisAlertDescription); ok { + opt.SetDescription(description.(string)) + } + if enabled, ok := d.GetOk(cisAlertEnabled); ok { + opt.SetEnabled(enabled.(bool)) + } + if alertType, ok := d.GetOk(cisAlertType); ok { + opt.SetAlertType(alertType.(string)) + + } + if retConditions, ok := d.GetOk(cisAlertConditions); ok { + var condition interface{} + json.Unmarshal([]byte(retConditions.(string)), &condition) + opt.Conditions = condition + } + + if retFilter, ok := d.GetOk(cisAlertFilters); ok { + var filter interface{} + json.Unmarshal([]byte(retFilter.(string)), &filter) + opt.Filters = filter + } + + mechanismsOpt := &alertsv1.UpdateAlertPolicyInputMechanisms{} + if mechanisms, ok := d.GetOk(cisAlertMechanisms); ok { + mechanism := mechanisms.([]interface{})[0].(map[string]interface{}) + webhook, ok := mechanism[cisAlertWebhook] + if ok { + webhookString := webhook.(*schema.Set) + if webhookString.Len() != 0 { + var webhookarray = make([]alertsv1.UpdateAlertPolicyInputMechanismsWebhooksItem, webhookString.Len()) + for k, w := range webhookString.List() { + wString := w.(string) + webhookarray[k] = alertsv1.UpdateAlertPolicyInputMechanismsWebhooksItem{ + ID: &wString, + } + } + mechanismsOpt.Webhooks = webhookarray + } + } + email, ok := mechanism[cisAlertEmail] + if ok { + emailString := email.(*schema.Set) + if emailString.Len() != 0 { + var emailarray = make([]alertsv1.UpdateAlertPolicyInputMechanismsEmailItem, emailString.Len()) + for k, w := range emailString.List() { + wString := w.(string) + emailarray[k] = alertsv1.UpdateAlertPolicyInputMechanismsEmailItem{ + ID: &wString, + } + } + mechanismsOpt.Email = emailarray + } + } + } + opt.Mechanisms = mechanismsOpt + + result, resp, err := sess.UpdateAlertPolicy(opt) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error while Update Alert Policy %s %s", err, resp) + } + } + + return nil +} +func ResourceIBMCISAlertPolicyDelete(d *schema.ResourceData, meta interface{}) error { + + sess, err := meta.(conns.ClientSession).CisAlertsSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisAlertsSession %s", err) + } + alertID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return err + } + sess.Crn = core.StringPtr(crn) + opt := sess.NewDeleteAlertPolicyOptions(alertID) + _, response, err := sess.DeleteAlertPolicy(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error deleting the alert %s:%s", err, response) + } + return nil +} +func getAlertMechanisms(s *schema.Set) interface{} { + var alertMechanisms []interface{} + for _, m := range s.List() { + switch m.(type) { + case alertsv1.CreateAlertPolicyInputMechanismsEmailItem: + email := m.(alertsv1.CreateAlertPolicyInputMechanismsEmailItem) + data := alertsv1.CreateAlertPolicyInputMechanismsEmailItem{ + ID: email.ID, + } + alertMechanisms = append(alertMechanisms, data) + case alertsv1.CreateAlertPolicyInputMechanismsWebhooksItem: + webhook := m.(alertsv1.CreateAlertPolicyInputMechanismsWebhooksItem) + data := alertsv1.CreateAlertPolicyInputMechanismsWebhooksItem{ + ID: webhook.ID, + } + alertMechanisms = append(alertMechanisms, data) + } + } + return alertMechanisms +} + +func flattenCISMechanism(Mechanism alertsv1.GetAlertPolicyRespResultMechanisms) interface{} { + emailoutput := []string{} + webhookoutput := []string{} + + output := map[string]interface{}{} + flatten := []map[string]interface{}{} + + for _, mech := range Mechanism.Email { + emailoutput = append(emailoutput, *mech.ID) + } + + for _, mech := range Mechanism.Webhooks { + webhookoutput = append(webhookoutput, *mech.ID) + } + + output[cisAlertEmail] = emailoutput + output[cisAlertWebhook] = webhookoutput + + flatten = append(flatten, output) + + return flatten +} diff --git a/ibm/service/cis/resource_ibm_cis_alert_test.go b/ibm/service/cis/resource_ibm_cis_alert_test.go new file mode 100644 index 000000000..e87b424fd --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_alert_test.go @@ -0,0 +1,170 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisAlert_Basic(t *testing.T) { + + alertname := "test-alert-policy" + alertdesc := "Description alert policy" + + alertnameUpdate := "test-alert-policy-update" + alertdescUpdate := "Description alert policy update" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisAlert_basic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cis_alert.test", "name", alertname), + resource.TestCheckResourceAttr("ibm_cis_alert.test", "description", alertdesc), + resource.TestCheckResourceAttr("ibm_cis_alert.test", "enabled", "true"), + resource.TestCheckResourceAttrSet("ibm_cis_alert.test", "filters"), + ), + }, + { + Config: testAccCheckCisAlert_update(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cis_alert.test", "name", alertnameUpdate), + resource.TestCheckResourceAttr("ibm_cis_alert.test", "description", alertdescUpdate), + resource.TestCheckResourceAttr("ibm_cis_alert.test", "enabled", "true"), + resource.TestCheckResourceAttrSet("ibm_cis_alert.test", "conditions"), + ), + }, + }, + }) +} +func testAccCheckCisAlert_basic() string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` + resource "ibm_cis_webhook" "test" { + cis_id = data.ibm_cis.cis.id + name = "test-Webhooks" + url = "https://hooks.slack.com/services/Ds3fdBFbV/1234568" + secret = "fBqWqLTwgx9aXuoOqLwenB6lIIyAYCvHJUowBS54Y3GC" + } + resource "ibm_cis_alert" "test" { + depends_on = [ibm_cis_webhook.test] + cis_id = data.ibm_cis.cis.id + name = "test-alert-policy" + description = "Description alert policy" + enabled = true + alert_type = "g6_pool_toggle_alert" + mechanisms { + email = ["mynotifications@email.com"] + webhooks = [ibm_cis_webhook.test.webhook_id] + } + filters =< is passed as input it is same as domai_id in the combination that is Set. - if strings.Split(new, ":")[0] == old { - return true - } - return false + return strings.Split(new, ":")[0] == old } func flattenData(inVal interface{}, zone string) map[string]string { outVal := make(map[string]string) diff --git a/ibm/resource_ibm_cis_dns_record_test.go b/ibm/service/cis/resource_ibm_cis_dns_record_test.go similarity index 77% rename from ibm/resource_ibm_cis_dns_record_test.go rename to ibm/service/cis/resource_ibm_cis_dns_record_test.go index d1c2b7061..d6d5164d6 100644 --- a/ibm/resource_ibm_cis_dns_record_test.go +++ b/ibm/service/cis/resource_ibm_cis_dns_record_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,16 +23,16 @@ func TestAccIBMCisDNSRecord_Basic(t *testing.T) { resourceName := fmt.Sprintf("ibm_cis_dns_record.%s", testName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisDNSRecordDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(resourceName, &record), resource.TestCheckResourceAttr( - resourceName, "name", testName+"."+cisDomainStatic), + resourceName, "name", testName+"."+acc.CisDomainStatic), resource.TestCheckResourceAttr( resourceName, "content", "192.168.0.10"), resource.TestCheckResourceAttr( @@ -46,18 +50,18 @@ func TestAccIBMCisDNSRecord_PTR(t *testing.T) { resourceName := fmt.Sprintf("ibm_cis_dns_record.%s", testName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisDNSRecordDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigPTR(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigPTR(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(resourceName, &record), resource.TestCheckResourceAttr( - resourceName, "name", "192.168.0.10."+cisDomainStatic), + resourceName, "name", "192.168.0.10."+acc.CisDomainStatic), resource.TestCheckResourceAttr( - resourceName, "content", testName+"."+cisDomainStatic), + resourceName, "content", testName+"."+acc.CisDomainStatic), resource.TestCheckResourceAttr( resourceName, "data.%", "0"), ), @@ -70,14 +74,14 @@ func TestAccIBMCisDNSRecord_import(t *testing.T) { name := "ibm_cis_dns_record.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "proxied", "false"), // default value - resource.TestCheckResourceAttr(name, "name", "test."+cisDomainStatic), + resource.TestCheckResourceAttr(name, "name", "test."+acc.CisDomainStatic), resource.TestCheckResourceAttr(name, "content", "192.168.0.10"), resource.TestCheckResourceAttr(name, "data.%", "0"), ), @@ -100,24 +104,24 @@ func TestAccIBMCisDNSRecord_CaseInsensitive(t *testing.T) { resourceName := fmt.Sprintf("ibm_cis_dns_record.%s", testName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisDNSRecordDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigCaseSensitive(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCaseSensitive(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(resourceName, &record), resource.TestCheckResourceAttr( - resourceName, "name", testName+"."+cisDomainStatic), + resourceName, "name", testName+"."+acc.CisDomainStatic), ), }, { - Config: testAccCheckIBMCisDNSRecordConfigCaseSensitive("tf-acctest-CASE-INSENSITIVE", cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCaseSensitive("tf-acctest-CASE-INSENSITIVE", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists("ibm_cis_dns_record.tf-acctest-CASE-INSENSITIVE", &record), resource.TestCheckResourceAttr( - "ibm_cis_dns_record.tf-acctest-CASE-INSENSITIVE", "name", "tf-acctest-case-insensitive."+cisDomainStatic), + "ibm_cis_dns_record.tf-acctest-CASE-INSENSITIVE", "name", "tf-acctest-case-insensitive."+acc.CisDomainStatic), ), }, }, @@ -131,17 +135,17 @@ func TestAccIBMCisDNSRecord_Apex(t *testing.T) { resourceName := fmt.Sprintf("ibm_cis_dns_record.%s", testName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisDNSRecordDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigApex(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigApex(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(resourceName, &record), resource.TestCheckResourceAttr( // @ is replaced by domain name by CIS - resourceName, "name", cisDomainStatic), + resourceName, "name", acc.CisDomainStatic), resource.TestCheckResourceAttr( resourceName, "content", "192.168.0.10"), ), @@ -159,12 +163,12 @@ func TestAccIBMCisDNSRecord_CreateAfterManualDestroy(t *testing.T) { afterCreate = "hello" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisDNSRecordDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(name, &afterCreate), testAccIBMCisManuallyDeleteDNSRecord(&afterCreate), @@ -172,7 +176,7 @@ func TestAccIBMCisDNSRecord_CreateAfterManualDestroy(t *testing.T) { ExpectNonEmptyPlan: true, }, { - Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, cisDomainStatic), + Config: testAccCheckIBMCisDNSRecordConfigCisDSBasic(testName, acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckIBMCisDNSRecordExists(name, &afterRecreate), testAccCheckIBMCisDNSRecordRecreated(&afterCreate, &afterRecreate), @@ -184,18 +188,18 @@ func TestAccIBMCisDNSRecord_CreateAfterManualDestroy(t *testing.T) { func testAccIBMCisManuallyDeleteDNSRecord(tfRecordID *string) resource.TestCheckFunc { return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisDNSRecordClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisDNSRecordClientSession() if err != nil { return err } tfRecord := *tfRecordID - recordID, zoneID, cisID, _ := convertTfToCisThreeVar(tfRecord) + recordID, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(tfRecord) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) delOpt := cisClient.NewDeleteDnsRecordOptions(recordID) _, _, err = cisClient.DeleteDnsRecord(delOpt) if err != nil { - return fmt.Errorf("Error deleting IBMCISDNS Record: %s", err) + return fmt.Errorf("[ERROR] Error deleting IBMCISDNS Record: %s", err) } return nil } @@ -211,7 +215,7 @@ func testAccCheckIBMCisDNSRecordRecreated(beforeID, afterID *string) resource.Te } func testAccCheckIBMCisDNSRecordDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisDNSRecordClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisDNSRecordClientSession() if err != nil { return err } @@ -220,7 +224,7 @@ func testAccCheckIBMCisDNSRecordDestroy(s *terraform.State) error { continue } - recordID, zoneID, cisID, _ := convertTfToCisThreeVar(rs.Primary.ID) + recordID, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) delOpt := cisClient.NewDeleteDnsRecordOptions(recordID) @@ -237,16 +241,19 @@ func testAccCheckIBMCisDNSRecordExists(n string, tfRecordID *string) resource.Te return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } - tfRecord := *tfRecordID - cisClient, err := testAccProvider.Meta().(ClientSession).CisDNSRecordClientSession() - recordID, zoneID, cisID, _ := convertTfToCisThreeVar(rs.Primary.ID) + // tfRecord := *tfRecordID + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisDNSRecordClientSession() + if err != nil { + return err + } + recordID, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewGetDnsRecordOptions(recordID) @@ -259,7 +266,7 @@ func testAccCheckIBMCisDNSRecordExists(n string, tfRecordID *string) resource.Te return fmt.Errorf("Record not found") } - tfRecord = convertCisToTfThreeVar(*foundRecord.Result.ID, zoneID, cisID) + tfRecord := flex.ConvertCisToTfThreeVar(*foundRecord.Result.ID, zoneID, cisID) *tfRecordID = tfRecord return nil } @@ -278,7 +285,7 @@ func testAccCheckIBMCisDNSRecordConfigCisDSBasic(resourceID string, cisDomain st `, resourceID) } -func testAccCheckIBMCisDNSRecordConfigPTR(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigPTR(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -287,10 +294,10 @@ func testAccCheckIBMCisDNSRecordConfigPTR(resourceID string, cisDomainStatic str content = "%[1]s.%[2]s" type = "PTR" } - `, resourceID, cisDomainStatic) + `, resourceID, acc.CisDomainStatic) } -func testAccCheckIBMCisDNSRecordConfigCaseSensitive(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigCaseSensitive(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -302,7 +309,7 @@ func testAccCheckIBMCisDNSRecordConfigCaseSensitive(resourceID string, cisDomain `, resourceID) } -func testAccCheckIBMCisDNSRecordConfigApex(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigApex(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -314,7 +321,7 @@ func testAccCheckIBMCisDNSRecordConfigApex(resourceID string, cisDomainStatic st `, resourceID) } -func testAccCheckIBMCisDNSRecordConfigLOC(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigLOC(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -339,7 +346,7 @@ func testAccCheckIBMCisDNSRecordConfigLOC(resourceID string, cisDomainStatic str `, resourceID) } -func testAccCheckIBMCisDNSRecordConfigSRV(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigSRV(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -358,7 +365,7 @@ func testAccCheckIBMCisDNSRecordConfigSRV(resourceID string, cisDomainStatic str `, resourceID) } -func testAccCheckIBMCisDNSRecordConfigProxied(resourceID string, cisDomainStatic string) string { +func testAccCheckIBMCisDNSRecordConfigProxied(resourceID string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_dns_record" "%[1]s" { cis_id = data.ibm_cis.cis.id diff --git a/ibm/service/cis/resource_ibm_cis_dns_records_import.go b/ibm/service/cis/resource_ibm_cis_dns_records_import.go new file mode 100644 index 000000000..e807f96e9 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_dns_records_import.go @@ -0,0 +1,132 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "log" + "os" + "strconv" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisDNSRecordsImportFile = "file" + cisDNSRecordsImportTotalRecordsParsed = "total_records_parsed" + cisDNSRecordsImportRecordsAdded = "records_added" +) + +func ResourceIBMCISDNSRecordsImport() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_dns_records_import", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisDNSRecordsImportFile: { + Type: schema.TypeString, + Description: "File to import", + Required: true, + ForceNew: true, + }, + cisDNSRecordsImportTotalRecordsParsed: { + Type: schema.TypeInt, + Description: "total records parsed", + Computed: true, + }, + cisDNSRecordsImportRecordsAdded: { + Type: schema.TypeInt, + Description: "added records count", + Computed: true, + }, + }, + + Create: resourceCISDNSRecordsImportUpdate, + Read: resourceCISDNSRecordsImportRead, + Update: resourceCISDNSRecordsImportRead, + Delete: resourceCISDNSRecordsImportDelete, + Importer: &schema.ResourceImporter{}, + } +} +func ResourceIBMCISDnsRecordsImportValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISDNSRecordsImportValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_dns_records_import", + Schema: validateSchema} + return &ibmCISDNSRecordsImportValidator +} +func resourceCISDNSRecordsImportUpdate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisDNSRecordBulkClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + file := d.Get(cisDNSRecordsImportFile).(string) + + f, err := os.Open(file) + if err != nil { + return err + } + opt := cisClient.NewPostDnsRecordsBulkOptions() + opt.SetFile(f) + result, response, err := cisClient.PostDnsRecordsBulk(opt) + if err != nil { + log.Printf("Error importing dns records: %v", response) + return err + } + id := fmt.Sprintf("%v:%v:%s:%s:%s", *result.Result.TotalRecordsParsed, + *result.Result.RecsAdded, file, zoneID, crn) + d.SetId(id) + + return nil + +} + +func resourceCISDNSRecordsImportRead(d *schema.ResourceData, meta interface{}) error { + idSplitStr := strings.SplitN(d.Id(), ":", 5) + parsed, _ := strconv.Atoi(idSplitStr[0]) + added, _ := strconv.Atoi(idSplitStr[1]) + file := idSplitStr[2] + zoneID := idSplitStr[3] + crn := idSplitStr[4] + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisDNSRecordsImportFile, file) + d.Set(cisDNSRecordsImportTotalRecordsParsed, parsed) + d.Set(cisDNSRecordsImportRecordsAdded, added) + return nil +} + +func resourceCISDNSRecordsImportDelete(d *schema.ResourceData, meta interface{}) error { + // Nothing to delete on CIS DNS Record import resource + d.SetId("") + return nil +} diff --git a/ibm/resource_ibm_cis_dns_records_import_test.go b/ibm/service/cis/resource_ibm_cis_dns_records_import_test.go similarity index 78% rename from ibm/resource_ibm_cis_dns_records_import_test.go rename to ibm/service/cis/resource_ibm_cis_dns_records_import_test.go index 5f9e6bf06..3876d13f9 100644 --- a/ibm/resource_ibm_cis_dns_records_import_test.go +++ b/ibm/service/cis/resource_ibm_cis_dns_records_import_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -15,11 +18,11 @@ import ( func TestAccIBMCisDNSRecordsImport_Basic(t *testing.T) { name := "ibm_cis_dns_records_import." + "test" - file := "test-fixtures/dns_records_import.txt" + file := "../../test-fixtures/dns_records_import.txt" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckCisDNSRecordsImportConfigBasic1(file), @@ -34,7 +37,7 @@ func TestAccIBMCisDNSRecordsImport_Basic(t *testing.T) { func testAccCheckCisDNSRecordsImportConfigBasic1(file string) string { return testAccCheckIBMCisDNSRecordConfigCisDSBasic( - "test-dns-record", cisDomainStatic) + + "test-dns-record", acc.CisDomainStatic) + fmt.Sprintf(` resource "ibm_cis_dns_records_import" "test" { cis_id = data.ibm_cis.cis.id @@ -45,17 +48,17 @@ func testAccCheckCisDNSRecordsImportConfigBasic1(file string) string { func testAccCheckIBMCisDNSRecordsImportRemoveImportedRecords(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisDNSRecordClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisDNSRecordClientSession() if err != nil { return err } rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } idSplitStr := strings.SplitN(rs.Primary.ID, ":", 5) zoneID := idSplitStr[3] diff --git a/ibm/service/cis/resource_ibm_cis_domain.go b/ibm/service/cis/resource_ibm_cis_domain.go new file mode 100644 index 000000000..eadc48282 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_domain.go @@ -0,0 +1,229 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisDomain = "domain" + cisDomainPaused = "paused" + cisDomainStatus = "status" + cisDomainNameServers = "name_servers" + cisDomainOriginalNameServers = "original_name_servers" + cisDomainType = "type" + cisDomainVerificationKey = "verification_key" + cisDomainCnameSuffix = "cname_suffix" + ibmCISDomain = "ibm_cis_domain" +) + +func ResourceIBMCISDomain() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_domain", + "cis_id"), + }, + cisDomain: { + Type: schema.TypeString, + Description: "CISzone - Domain", + Required: true, + }, + cisDomainType: { + Type: schema.TypeString, + Description: "CISzone - Domain Type", + Default: "full", + Optional: true, + ValidateFunc: validate.InvokeValidator(ibmCISDomain, + cisDomainType), + }, + cisDomainPaused: { + Type: schema.TypeBool, + Computed: true, + }, + cisDomainStatus: { + Type: schema.TypeString, + Computed: true, + }, + cisDomainNameServers: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + cisDomainOriginalNameServers: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + cisDomainID: { + Type: schema.TypeString, + Computed: true, + }, + cisDomainVerificationKey: { + Type: schema.TypeString, + Computed: true, + }, + cisDomainCnameSuffix: { + Type: schema.TypeString, + Computed: true, + }, + }, + Create: resourceCISdomainCreate, + Read: resourceCISdomainRead, + Exists: resourceCISdomainExists, + Update: resourceCISdomainUpdate, + Delete: resourceCISdomainDelete, + Importer: &schema.ResourceImporter{}, + } +} + +func resourceCISdomainCreate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + cisClient.Crn = core.StringPtr(crn) + zoneName := d.Get(cisDomain).(string) + zoneType := d.Get(cisDomainType).(string) + + opt := cisClient.NewCreateZoneOptions() + opt.SetName(zoneName) + opt.SetType(zoneType) + + result, resp, err := cisClient.CreateZone(opt) + if err != nil { + log.Printf("CreateZones Failed %s", resp) + return err + } + d.SetId(flex.ConvertCisToTfTwoVar(*result.Result.ID, crn)) + return resourceCISdomainRead(d, meta) +} + +func resourceCISdomainRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + opt := cisClient.NewGetZoneOptions(zoneID) + result, resp, err := cisClient.GetZone(opt) + if err != nil { + log.Printf("[WARN] Error getting zone %v\n", resp) + return err + } + d.Set(cisID, crn) + d.Set(cisDomainID, result.Result.ID) + d.Set(cisDomain, result.Result.Name) + d.Set(cisDomainStatus, result.Result.Status) + d.Set(cisDomainPaused, result.Result.Paused) + d.Set(cisDomainNameServers, result.Result.NameServers) + d.Set(cisDomainOriginalNameServers, result.Result.OriginalNameServers) + d.Set(cisDomainType, result.Result.Type) + + if cisDomainType == "partial" { + d.Set(cisDomainVerificationKey, result.Result.VerificationKey) + d.Set(cisDomainCnameSuffix, result.Result.CnameSuffix) + } + + return nil +} +func resourceCISdomainExists(d *schema.ResourceData, meta interface{}) (bool, error) { + cisClient, err := meta.(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return false, err + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + log.Println("resource exist :", d.Id()) + if err != nil { + return false, err + } + log.Println("resource exist :", d.Id()) + cisClient.Crn = core.StringPtr(crn) + opt := cisClient.NewGetZoneOptions(zoneID) + _, resp, err := cisClient.GetZone(opt) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + log.Printf("[WARN] zone is not found") + return false, nil + } + log.Printf("[WARN] Error getting zone %v\n", resp) + return false, err + } + return true, nil +} + +func resourceCISdomainUpdate(d *schema.ResourceData, meta interface{}) error { + return resourceCISdomainRead(d, meta) +} + +func resourceCISdomainDelete(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + log.Println("resource delete :", d.Id()) + + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + opt := cisClient.NewGetZoneOptions(zoneID) + _, resp, err := cisClient.GetZone(opt) + if err != nil { + log.Printf("[WARN] Error getting zone %v\n", resp) + return err + } + delOpt := cisClient.NewDeleteZoneOptions(zoneID) + _, resp, err = cisClient.DeleteZone(delOpt) + if err != nil { + log.Printf("[ERR] Error deleting zone %v\n", resp) + return err + } + return nil +} + +func ResourceIBMCISDomainValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainType, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "full, partial"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + + ibmCISDomainResourceValidator := validate.ResourceValidator{ + ResourceName: ibmCISDomain, + Schema: validateSchema} + return &ibmCISDomainResourceValidator +} diff --git a/ibm/service/cis/resource_ibm_cis_domain_settings.go b/ibm/service/cis/resource_ibm_cis_domain_settings.go new file mode 100644 index 000000000..a21bfc286 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_domain_settings.go @@ -0,0 +1,1438 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmCISDomainSettings = "ibm_cis_domain_settings" + cisDomainSettingsDNSSEC = "dnssec" + cisDomainSettingsWAF = "waf" + cisDomainSettingsSSL = "ssl" + cisDomainSettingsCertificateStatus = "certificate_status" + cisDomainSettingsMinTLSVersion = "min_tls_version" + cisDomainSettingsCNAMEFlattening = "cname_flattening" + cisDomainSettingsOpportunisticEncryption = "opportunistic_encryption" + cisDomainSettingsAutomaticHTPSRewrites = "automatic_https_rewrites" + cisDomainSettingsAlwaysUseHTTPS = "always_use_https" + cisDomainSettingsIPv6 = "ipv6" + cisDomainSettingsBrowserCheck = "browser_check" + cisDomainSettingsHotlinkProtection = "hotlink_protection" + cisDomainSettingsHTTP2 = "http2" + cisDomainSettingsImageLoadOptimization = "image_load_optimization" + cisDomainSettingsImageSizeOptimization = "image_size_optimization" + cisDomainSettingsIPGeoLocation = "ip_geolocation" + cisDomainSettingsOriginErrorPagePassThru = "origin_error_page_pass_thru" + cisDomainSettingsBrotli = "brotli" + cisDomainSettingsPseudoIPv4 = "pseudo_ipv4" + cisDomainSettingsPrefetchPreload = "prefetch_preload" + cisDomainSettingsResponseBuffering = "response_buffering" + cisDomainSettingsScriptLoadOptimisation = "script_load_optimization" + cisDomainSettingsServerSideExclude = "server_side_exclude" + cisDomainSettingsTLSClientAuth = "tls_client_auth" + cisDomainSettingsTrueClientIPHeader = "true_client_ip_header" + cisDomainSettingsWebSockets = "websockets" + cisDomainSettingsChallengeTTL = "challenge_ttl" + cisDomainSettingsMinify = "minify" + cisDomainSettingsMinifyCSS = "css" + cisDomainSettingsMinifyHTML = "html" + cisDomainSettingsMinifyJS = "js" + cisDomainSettingsSecurityHeader = "security_header" + cisDomainSettingsSecurityHeaderEnabled = "enabled" + cisDomainSettingsSecurityHeaderMaxAge = "max_age" + cisDomainSettingsSecurityHeaderIncludeSubdomains = "include_subdomains" + cisDomainSettingsSecurityHeaderNoSniff = "nosniff" + cisDomainSettingsMobileRedirect = "mobile_redirect" + cisDomainSettingsMobileRedirectStatus = "status" + cisDomainSettingsMobileRedirectMobileSubdomain = "mobile_subdomain" + cisDomainSettingsMobileRedirectStripURI = "strip_uri" + cisDomainSettingsMaxUpload = "max_upload" + cisDomainSettingsCipher = "cipher" + // cisDomainSettingsONOFFValidatorID = "on_off" + // cisDomainSettingsActiveDisableValidatorID = "active_disable" + cisDomainSettingsSSLSettingValidatorID = "ssl_setting" + cisDomainSettingsTLSVersionValidatorID = "tls_version" + cisDomainSettingsCNAMEFlattenValidatorID = "cname_flatten" + cisDomainSettingsImgSizeOptimizeValidatorID = "img_size_optimize" + cisDomainSettingsPseudoIPv4ValidatorID = "psuedo_ipv4" + cisDomainSettingsChallengeTTLValidatorID = "challenge_ttl" + cisDomainSettingsMaxUploadValidatorID = "max_upload" + cisDomainSettingsCipherValidatorID = "cipher" +) + +func ResourceIBMCISSettings() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator(ibmCISDomainSettings, + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisDomainSettingsDNSSEC: { + Type: schema.TypeString, + Description: "DNS Sec setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsDNSSEC), + }, + cisDomainSettingsWAF: { + Type: schema.TypeString, + Description: "WAF setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsWAF), + }, + cisDomainSettingsSSL: { + Type: schema.TypeString, + Description: "SSL/TLS setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsSSLSettingValidatorID), + }, + cisDomainSettingsCertificateStatus: { + Type: schema.TypeString, + Description: "Certificate status", + Computed: true, + Deprecated: "This field is deprecated", + }, + cisDomainSettingsMinTLSVersion: { + Type: schema.TypeString, + Description: "Minimum version of TLS required", + Optional: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsTLSVersionValidatorID), + Default: "1.1", + }, + cisDomainSettingsCNAMEFlattening: { + Type: schema.TypeString, + Description: "cname_flattening setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsCNAMEFlattenValidatorID), + }, + cisDomainSettingsOpportunisticEncryption: { + Type: schema.TypeString, + Description: "opportunistic_encryption setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsOpportunisticEncryption), + }, + cisDomainSettingsAutomaticHTPSRewrites: { + Type: schema.TypeString, + Description: "automatic_https_rewrites setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsAutomaticHTPSRewrites), + }, + cisDomainSettingsAlwaysUseHTTPS: { + Type: schema.TypeString, + Description: "always_use_https setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsAlwaysUseHTTPS), + }, + cisDomainSettingsIPv6: { + Type: schema.TypeString, + Description: "ipv6 setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsIPv6), + }, + cisDomainSettingsBrowserCheck: { + Type: schema.TypeString, + Description: "browser_check setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsBrowserCheck), + }, + cisDomainSettingsHotlinkProtection: { + Type: schema.TypeString, + Description: "hotlink_protection setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsHotlinkProtection), + }, + cisDomainSettingsHTTP2: { + Type: schema.TypeString, + Description: "http2 setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsHTTP2), + }, + cisDomainSettingsImageLoadOptimization: { + Type: schema.TypeString, + Description: "image_load_optimization setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsImageLoadOptimization), + }, + cisDomainSettingsImageSizeOptimization: { + Type: schema.TypeString, + Description: "image_size_optimization setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsImgSizeOptimizeValidatorID), + }, + cisDomainSettingsIPGeoLocation: { + Type: schema.TypeString, + Description: "ip_geolocation setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsIPGeoLocation), + }, + cisDomainSettingsOriginErrorPagePassThru: { + Type: schema.TypeString, + Description: "origin_error_page_pass_thru setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsOriginErrorPagePassThru), + }, + cisDomainSettingsBrotli: { + Type: schema.TypeString, + Description: "brotli setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsBrotli), + }, + cisDomainSettingsPseudoIPv4: { + Type: schema.TypeString, + Description: "pseudo_ipv4 setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsPseudoIPv4ValidatorID), + }, + cisDomainSettingsPrefetchPreload: { + Type: schema.TypeString, + Description: "prefetch_preload setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsPrefetchPreload), + }, + cisDomainSettingsResponseBuffering: { + Type: schema.TypeString, + Description: "response_buffering setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsResponseBuffering), + }, + cisDomainSettingsScriptLoadOptimisation: { + Type: schema.TypeString, + Description: "script_load_optimization setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsScriptLoadOptimisation), + }, + cisDomainSettingsServerSideExclude: { + Type: schema.TypeString, + Description: "server_side_exclude setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsServerSideExclude), + }, + cisDomainSettingsTLSClientAuth: { + Type: schema.TypeString, + Description: "tls_client_auth setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsTLSClientAuth), + }, + cisDomainSettingsTrueClientIPHeader: { + Type: schema.TypeString, + Description: "true_client_ip_header setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsTrueClientIPHeader), + }, + cisDomainSettingsWebSockets: { + Type: schema.TypeString, + Description: "websockets setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsWebSockets), + }, + cisDomainSettingsChallengeTTL: { + Type: schema.TypeInt, + Description: "Challenge TTL setting", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsChallengeTTLValidatorID), + }, + cisDomainSettingsMaxUpload: { + Type: schema.TypeInt, + Description: "Maximum upload", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsMaxUploadValidatorID), + }, + cisDomainSettingsCipher: { + Type: schema.TypeSet, + Description: "Cipher settings", + Optional: true, + Computed: true, + Set: schema.HashString, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsCipherValidatorID), + }, + }, + cisDomainSettingsMinify: { + Type: schema.TypeList, + Description: "Minify setting", + Optional: true, + Computed: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisDomainSettingsMinifyCSS: { + Type: schema.TypeString, + Description: "Minify CSS setting", + Required: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsMinifyCSS), + }, + cisDomainSettingsMinifyHTML: { + Type: schema.TypeString, + Description: "Minify HTML setting", + Required: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsMinifyHTML), + }, + cisDomainSettingsMinifyJS: { + Type: schema.TypeString, + Description: "Minify JS setting", + Required: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsMinifyJS), + }, + }, + }, + }, + cisDomainSettingsSecurityHeader: { + Type: schema.TypeList, + Description: "Security Header Setting", + Optional: true, + Computed: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisDomainSettingsSecurityHeaderEnabled: { + Type: schema.TypeBool, + Description: "security header enabled/disabled", + Required: true, + }, + cisDomainSettingsSecurityHeaderIncludeSubdomains: { + Type: schema.TypeBool, + Description: "security header subdomain included or not", + Required: true, + }, + cisDomainSettingsSecurityHeaderMaxAge: { + Type: schema.TypeInt, + Description: "security header max age", + Required: true, + }, + cisDomainSettingsSecurityHeaderNoSniff: { + Type: schema.TypeBool, + Description: "security header no sniff", + Required: true, + }, + }, + }, + }, + cisDomainSettingsMobileRedirect: { + Type: schema.TypeList, + Optional: true, + Computed: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + cisDomainSettingsMobileRedirectStatus: { + Type: schema.TypeString, + Description: "mobile redirect status", + Required: true, + ValidateFunc: validate.InvokeValidator( + ibmCISDomainSettings, + cisDomainSettingsMobileRedirectStatus), + }, + cisDomainSettingsMobileRedirectMobileSubdomain: { + Type: schema.TypeString, + Description: "Mobile redirect subdomain", + Optional: true, + Computed: true, + }, + cisDomainSettingsMobileRedirectStripURI: { + Type: schema.TypeBool, + Description: "mobile redirect strip URI", + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + + Create: resourceCISSettingsUpdate, + Read: resourceCISSettingsRead, + Update: resourceCISSettingsUpdate, + Delete: resourceCISSettingsDelete, + Importer: &schema.ResourceImporter{}, + } +} + +func ResourceIBMCISDomainSettingValidator() *validate.ResourceValidator { + + sslSetting := "off, flexible, full, strict, origin_pull" + tlsVersion := "1.1, 1.2, 1.3, 1.4" + cnameFlatten := "flatten_at_root, flatten_all, flatten_none" + imgSizeOptimize := "lossless, off, lossy" + pseudoIPv4 := "overwrite_header, off, add_header" + challengeTTL := "300, 900, 1800, 2700, 3600, 7200, 10800, 14400, 28800, 57600, 86400, 604800, 2592000, 31536000" + maxUpload := "100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500" + cipher := "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305, ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-CHACHA20-POLY1305, ECDHE-ECDSA-AES128-SHA256, ECDHE-ECDSA-AES128-SHA, ECDHE-RSA-AES128-SHA256, ECDHE-RSA-AES128-SHA, AES128-GCM-SHA256, AES128-SHA256, AES128-SHA, ECDHE-ECDSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-SHA384, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA, AES256-GCM-SHA384, AES256-SHA256, AES256-SHA, DES-CBC3-SHA, AEAD-AES128-GCM-SHA256, AEAD-AES256-GCM-SHA384, AEAD-CHACHA20-POLY1305-SHA256" + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsWAF, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsOpportunisticEncryption, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsAutomaticHTPSRewrites, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsAlwaysUseHTTPS, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsIPv6, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsBrowserCheck, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsHotlinkProtection, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsHTTP2, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsImageLoadOptimization, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsIPGeoLocation, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsOriginErrorPagePassThru, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsBrotli, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsPrefetchPreload, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsResponseBuffering, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsScriptLoadOptimisation, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsServerSideExclude, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsTLSClientAuth, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsTrueClientIPHeader, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsWebSockets, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsMinifyCSS, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsMinifyHTML, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsMinifyJS, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsMobileRedirectStatus, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "on, off"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsDNSSEC, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "active, disabled"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsSSLSettingValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: sslSetting}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsTLSVersionValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: tlsVersion}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsCNAMEFlattenValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: cnameFlatten}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsImgSizeOptimizeValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: imgSizeOptimize}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsPseudoIPv4ValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: pseudoIPv4}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsChallengeTTLValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedIntValue, + Type: validate.TypeInt, + Optional: true, + AllowedValues: challengeTTL}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsMaxUploadValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedIntValue, + Type: validate.TypeInt, + Optional: true, + AllowedValues: maxUpload}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisDomainSettingsCipherValidatorID, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: cipher}) + ibmCISDomainSettingResourceValidator := validate.ResourceValidator{ + ResourceName: ibmCISDomainSettings, + Schema: validateSchema} + return &ibmCISDomainSettingResourceValidator +} + +var settingsList = []string{ + cisDomainSettingsDNSSEC, + cisDomainSettingsWAF, + cisDomainSettingsSSL, + cisDomainSettingsMinTLSVersion, + cisDomainSettingsCNAMEFlattening, + cisDomainSettingsOpportunisticEncryption, + cisDomainSettingsAutomaticHTPSRewrites, + cisDomainSettingsAlwaysUseHTTPS, + cisDomainSettingsIPv6, + cisDomainSettingsBrowserCheck, + cisDomainSettingsHotlinkProtection, + cisDomainSettingsHTTP2, + cisDomainSettingsImageLoadOptimization, + cisDomainSettingsImageSizeOptimization, + cisDomainSettingsIPGeoLocation, + cisDomainSettingsOriginErrorPagePassThru, + cisDomainSettingsBrotli, + cisDomainSettingsPseudoIPv4, + cisDomainSettingsPrefetchPreload, + cisDomainSettingsResponseBuffering, + cisDomainSettingsScriptLoadOptimisation, + cisDomainSettingsServerSideExclude, + cisDomainSettingsTLSClientAuth, + cisDomainSettingsTrueClientIPHeader, + cisDomainSettingsWebSockets, + cisDomainSettingsChallengeTTL, + cisDomainSettingsMinify, + cisDomainSettingsSecurityHeader, + cisDomainSettingsMobileRedirect, + cisDomainSettingsMaxUpload, + cisDomainSettingsCipher, +} + +func resourceCISSettingsUpdate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisDomainSettingsClientSession() + if err != nil { + return err + } + + cisID := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(cisID) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + for _, item := range settingsList { + var err error + var resp *core.DetailedResponse + + switch item { + case cisDomainSettingsDNSSEC: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateZoneDnssecOptions() + opt.SetStatus(v.(string)) + _, resp, err = cisClient.UpdateZoneDnssec(opt) + } + } + case cisDomainSettingsWAF: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateWebApplicationFirewallOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateWebApplicationFirewall(opt) + } + } + case cisDomainSettingsSSL: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + cisClient, err := meta.(conns.ClientSession).CisSSLClientSession() + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(cisID) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + opt := cisClient.NewChangeSslSettingOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.ChangeSslSetting(opt) + } + } + + case cisDomainSettingsMinTLSVersion: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateMinTlsVersionOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateMinTlsVersion(opt) + } + } + case cisDomainSettingsBrotli: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateBrotliOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateBrotli(opt) + } + } + case cisDomainSettingsCNAMEFlattening: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateZoneCnameFlatteningOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateZoneCnameFlattening(opt) + } + } + case cisDomainSettingsOpportunisticEncryption: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateOpportunisticEncryptionOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateOpportunisticEncryption(opt) + } + } + case cisDomainSettingsAutomaticHTPSRewrites: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateAutomaticHttpsRewritesOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateAutomaticHttpsRewrites(opt) + } + } + case cisDomainSettingsAlwaysUseHTTPS: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateAlwaysUseHttpsOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateAlwaysUseHttps(opt) + } + } + case cisDomainSettingsIPv6: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateIpv6Options() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateIpv6(opt) + } + } + case cisDomainSettingsBrowserCheck: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateBrowserCheckOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateBrowserCheck(opt) + } + } + case cisDomainSettingsHotlinkProtection: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateHotlinkProtectionOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateHotlinkProtection(opt) + } + } + case cisDomainSettingsHTTP2: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateHttp2Options() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateHttp2(opt) + } + } + case cisDomainSettingsImageLoadOptimization: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateImageLoadOptimizationOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateImageLoadOptimization(opt) + } + } + case cisDomainSettingsImageSizeOptimization: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateImageSizeOptimizationOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateImageSizeOptimization(opt) + } + } + case cisDomainSettingsIPGeoLocation: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateIpGeolocationOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateIpGeolocation(opt) + } + } + case cisDomainSettingsOriginErrorPagePassThru: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateEnableErrorPagesOnOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateEnableErrorPagesOn(opt) + } + } + case cisDomainSettingsPseudoIPv4: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdatePseudoIpv4Options() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdatePseudoIpv4(opt) + } + } + case cisDomainSettingsPrefetchPreload: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdatePrefetchPreloadOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdatePrefetchPreload(opt) + } + } + case cisDomainSettingsResponseBuffering: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateResponseBufferingOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateResponseBuffering(opt) + } + } + case cisDomainSettingsScriptLoadOptimisation: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateScriptLoadOptimizationOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateScriptLoadOptimization(opt) + } + } + case cisDomainSettingsServerSideExclude: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateServerSideExcludeOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateServerSideExclude(opt) + } + } + case cisDomainSettingsTLSClientAuth: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateTlsClientAuthOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateTlsClientAuth(opt) + } + } + case cisDomainSettingsTrueClientIPHeader: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateTrueClientIpOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateTrueClientIp(opt) + } + } + case cisDomainSettingsWebSockets: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateWebSocketsOptions() + opt.SetValue(v.(string)) + _, resp, err = cisClient.UpdateWebSockets(opt) + } + } + case cisDomainSettingsChallengeTTL: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateChallengeTtlOptions() + opt.SetValue(int64(v.(int))) + _, resp, err = cisClient.UpdateChallengeTTL(opt) + } + } + case cisDomainSettingsMaxUpload: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + opt := cisClient.NewUpdateMaxUploadOptions() + opt.SetValue(int64(v.(int))) + _, resp, err = cisClient.UpdateMaxUpload(opt) + } + } + case cisDomainSettingsCipher: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + cipherValue := flex.ExpandStringList(v.(*schema.Set).List()) + opt := cisClient.NewUpdateCiphersOptions() + opt.SetValue(cipherValue) + _, resp, err = cisClient.UpdateCiphers(opt) + } + } + case cisDomainSettingsMinify: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + dataMap := v.([]interface{})[0].(map[string]interface{}) + css := dataMap[cisDomainSettingsMinifyCSS].(string) + html := dataMap[cisDomainSettingsMinifyHTML].(string) + js := dataMap[cisDomainSettingsMinifyJS].(string) + minifyVal, err := cisClient.NewMinifySettingValue(css, html, js) + if err != nil { + log.Println("Invalid minfiy setting values") + return err + } + opt := cisClient.NewUpdateMinifyOptions() + opt.SetValue(minifyVal) + _, resp, err = cisClient.UpdateMinify(opt) + } + } + case cisDomainSettingsSecurityHeader: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + dataMap := v.([]interface{})[0].(map[string]interface{}) + enabled := dataMap[cisDomainSettingsSecurityHeaderEnabled].(bool) + nosniff := dataMap[cisDomainSettingsSecurityHeaderNoSniff].(bool) + includeSubdomain := dataMap[cisDomainSettingsSecurityHeaderIncludeSubdomains].(bool) + maxAge := int64(dataMap[cisDomainSettingsSecurityHeaderMaxAge].(int)) + securityVal, err := cisClient.NewSecurityHeaderSettingValueStrictTransportSecurity( + enabled, maxAge, includeSubdomain, nosniff) + if err != nil { + log.Println("Invalid security header setting values") + return err + } + securityOpt, err := cisClient.NewSecurityHeaderSettingValue(securityVal) + if err != nil { + log.Println("Invalid security header setting options") + return err + } + opt := cisClient.NewUpdateSecurityHeaderOptions() + opt.SetValue(securityOpt) + _, resp, err = cisClient.UpdateSecurityHeader(opt) + } + } + case cisDomainSettingsMobileRedirect: + if d.HasChange(item) { + if v, ok := d.GetOk(item); ok { + dataMap := v.([]interface{})[0].(map[string]interface{}) + status := dataMap[cisDomainSettingsMobileRedirectStatus].(string) + mobileSubdomain := dataMap[cisDomainSettingsMobileRedirectMobileSubdomain].(string) + stripURI := dataMap[cisDomainSettingsMobileRedirectStripURI].(bool) + mobileOpt, err := cisClient.NewMobileRedirecSettingValue(status, mobileSubdomain, stripURI) + if err != nil { + log.Println("Invalid mobile redirect options") + return err + } + opt := cisClient.NewUpdateMobileRedirectOptions() + opt.SetValue(mobileOpt) + _, resp, err = cisClient.UpdateMobileRedirect(opt) + } + } + } + if err != nil { + if resp != nil && resp.StatusCode == 405 { + log.Printf("[WARN] Update %s : %s", item, err) + continue + } + log.Printf("Update settings Failed on %s, %v\n", item, resp) + return err + } + } + d.SetId(flex.ConvertCisToTfTwoVar(zoneID, cisID)) + return resourceCISSettingsRead(d, meta) +} + +func resourceCISSettingsRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisDomainSettingsClientSession() + if err != nil { + return err + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + for _, item := range settingsList { + var settingErr error + var settingResponse *core.DetailedResponse + switch item { + case cisDomainSettingsDNSSEC: + opt := cisClient.NewGetZoneDnssecOptions() + result, resp, err := cisClient.GetZoneDnssec(opt) + if err == nil { + d.Set(cisDomainSettingsDNSSEC, result.Result.Status) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsWAF: + opt := cisClient.NewGetWebApplicationFirewallOptions() + result, resp, err := cisClient.GetWebApplicationFirewall(opt) + if err == nil { + d.Set(cisDomainSettingsWAF, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsSSL: + cisClient, err := meta.(conns.ClientSession).CisSSLClientSession() + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + opt := cisClient.NewGetSslSettingOptions() + result, resp, err := cisClient.GetSslSetting(opt) + if err == nil { + d.Set(cisDomainSettingsSSL, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsBrotli: + opt := cisClient.NewGetBrotliOptions() + result, resp, err := cisClient.GetBrotli(opt) + if err == nil { + d.Set(cisDomainSettingsBrotli, result.Result.Value) + } + settingResponse = resp + + case cisDomainSettingsMinTLSVersion: + opt := cisClient.NewGetMinTlsVersionOptions() + result, resp, err := cisClient.GetMinTlsVersion(opt) + if err == nil { + d.Set(cisDomainSettingsMinTLSVersion, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsCNAMEFlattening: + opt := cisClient.NewGetZoneCnameFlatteningOptions() + result, resp, err := cisClient.GetZoneCnameFlattening(opt) + if err == nil { + d.Set(cisDomainSettingsCNAMEFlattening, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsOpportunisticEncryption: + opt := cisClient.NewGetOpportunisticEncryptionOptions() + result, resp, err := cisClient.GetOpportunisticEncryption(opt) + if err == nil { + d.Set(cisDomainSettingsOpportunisticEncryption, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsAutomaticHTPSRewrites: + opt := cisClient.NewGetAutomaticHttpsRewritesOptions() + result, resp, err := cisClient.GetAutomaticHttpsRewrites(opt) + if err == nil { + d.Set(cisDomainSettingsAutomaticHTPSRewrites, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsAlwaysUseHTTPS: + opt := cisClient.NewGetAlwaysUseHttpsOptions() + result, resp, err := cisClient.GetAlwaysUseHttps(opt) + if err == nil { + d.Set(cisDomainSettingsAlwaysUseHTTPS, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsIPv6: + opt := cisClient.NewGetIpv6Options() + result, resp, err := cisClient.GetIpv6(opt) + if err == nil { + d.Set(cisDomainSettingsIPv6, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsBrowserCheck: + opt := cisClient.NewGetBrowserCheckOptions() + result, resp, err := cisClient.GetBrowserCheck(opt) + if err == nil { + d.Set(cisDomainSettingsBrowserCheck, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsHotlinkProtection: + opt := cisClient.NewGetHotlinkProtectionOptions() + result, resp, err := cisClient.GetHotlinkProtection(opt) + if err == nil { + d.Set(cisDomainSettingsHotlinkProtection, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsHTTP2: + opt := cisClient.NewGetHttp2Options() + result, resp, err := cisClient.GetHttp2(opt) + if err == nil { + d.Set(cisDomainSettingsHTTP2, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsImageLoadOptimization: + opt := cisClient.NewGetImageLoadOptimizationOptions() + result, resp, err := cisClient.GetImageLoadOptimization(opt) + if err == nil { + d.Set(cisDomainSettingsImageLoadOptimization, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsImageSizeOptimization: + opt := cisClient.NewGetImageSizeOptimizationOptions() + result, resp, err := cisClient.GetImageSizeOptimization(opt) + if err == nil { + d.Set(cisDomainSettingsImageSizeOptimization, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsIPGeoLocation: + opt := cisClient.NewGetIpGeolocationOptions() + result, resp, err := cisClient.GetIpGeolocation(opt) + if err == nil { + d.Set(cisDomainSettingsIPGeoLocation, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsOriginErrorPagePassThru: + opt := cisClient.NewGetEnableErrorPagesOnOptions() + result, resp, err := cisClient.GetEnableErrorPagesOn(opt) + if err == nil { + d.Set(cisDomainSettingsOriginErrorPagePassThru, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsPseudoIPv4: + opt := cisClient.NewGetPseudoIpv4Options() + result, resp, err := cisClient.GetPseudoIpv4(opt) + if err == nil { + d.Set(cisDomainSettingsPseudoIPv4, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsPrefetchPreload: + opt := cisClient.NewGetPrefetchPreloadOptions() + result, resp, err := cisClient.GetPrefetchPreload(opt) + if err == nil { + d.Set(cisDomainSettingsPrefetchPreload, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsResponseBuffering: + opt := cisClient.NewGetResponseBufferingOptions() + result, resp, err := cisClient.GetResponseBuffering(opt) + if err == nil { + d.Set(cisDomainSettingsResponseBuffering, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsScriptLoadOptimisation: + opt := cisClient.NewGetScriptLoadOptimizationOptions() + result, resp, err := cisClient.GetScriptLoadOptimization(opt) + if err == nil { + d.Set(cisDomainSettingsScriptLoadOptimisation, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsServerSideExclude: + opt := cisClient.NewGetServerSideExcludeOptions() + result, resp, err := cisClient.GetServerSideExclude(opt) + if err == nil { + d.Set(cisDomainSettingsServerSideExclude, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsTLSClientAuth: + opt := cisClient.NewGetTlsClientAuthOptions() + result, resp, err := cisClient.GetTlsClientAuth(opt) + if err == nil { + d.Set(cisDomainSettingsTLSClientAuth, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsTrueClientIPHeader: + opt := cisClient.NewGetTrueClientIpOptions() + result, resp, err := cisClient.GetTrueClientIp(opt) + if err == nil { + d.Set(cisDomainSettingsTrueClientIPHeader, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsWebSockets: + opt := cisClient.NewGetWebSocketsOptions() + result, resp, err := cisClient.GetWebSockets(opt) + if err == nil { + d.Set(cisDomainSettingsWebSockets, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsChallengeTTL: + opt := cisClient.NewGetChallengeTtlOptions() + result, resp, err := cisClient.GetChallengeTTL(opt) + if err == nil { + d.Set(cisDomainSettingsChallengeTTL, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsMaxUpload: + opt := cisClient.NewGetMaxUploadOptions() + result, resp, err := cisClient.GetMaxUpload(opt) + if err == nil { + d.Set(cisDomainSettingsMaxUpload, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsCipher: + opt := cisClient.NewGetCiphersOptions() + result, resp, err := cisClient.GetCiphers(opt) + if err == nil { + d.Set(cisDomainSettingsCipher, result.Result.Value) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsMinify: + opt := cisClient.NewGetMinifyOptions() + result, resp, err := cisClient.GetMinify(opt) + if err == nil { + minify := result.Result.Value + value := map[string]string{ + cisDomainSettingsMinifyCSS: *minify.Css, + cisDomainSettingsMinifyHTML: *minify.HTML, + cisDomainSettingsMinifyJS: *minify.Js, + } + d.Set(cisDomainSettingsMinify, []interface{}{value}) + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsSecurityHeader: + opt := cisClient.NewGetSecurityHeaderOptions() + result, resp, err := cisClient.GetSecurityHeader(opt) + if err == nil { + + if result.Result.Value != nil && result.Result.Value.StrictTransportSecurity != nil { + + securityHeader := result.Result.Value.StrictTransportSecurity + value := map[string]interface{}{} + if securityHeader.Enabled != nil { + value[cisDomainSettingsSecurityHeaderEnabled] = *securityHeader.Enabled + } + if securityHeader.Nosniff != nil { + value[cisDomainSettingsSecurityHeaderNoSniff] = *securityHeader.Nosniff + } + if securityHeader.IncludeSubdomains != nil { + value[cisDomainSettingsSecurityHeaderIncludeSubdomains] = *securityHeader.IncludeSubdomains + } + if securityHeader.MaxAge != nil { + value[cisDomainSettingsSecurityHeaderMaxAge] = *securityHeader.MaxAge + } + d.Set(cisDomainSettingsSecurityHeader, []interface{}{value}) + } + } + settingResponse = resp + settingErr = err + + case cisDomainSettingsMobileRedirect: + opt := cisClient.NewGetMobileRedirectOptions() + result, resp, err := cisClient.GetMobileRedirect(opt) + if err == nil { + if result.Result.Value != nil { + + value := result.Result.Value + + uri := map[string]interface{}{} + if value.MobileSubdomain != nil { + uri[cisDomainSettingsMobileRedirectMobileSubdomain] = *value.MobileSubdomain + } + if value.Status != nil { + uri[cisDomainSettingsMobileRedirectStatus] = *value.Status + } + if value.StripURI != nil { + uri[cisDomainSettingsMobileRedirectStripURI] = *value.StripURI + } + d.Set(cisDomainSettingsMobileRedirect, []interface{}{uri}) + } + } + settingResponse = resp + settingErr = err + } + + if settingErr != nil { + if settingResponse != nil && settingResponse.StatusCode == 405 { + log.Printf("[WARN] Get %s. : %s", item, settingErr) + continue + } + log.Printf("Get settings failed on %s, %v\n", item, settingErr) + return settingErr + } + } + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + return nil +} + +func resourceCISSettingsDelete(d *schema.ResourceData, meta interface{}) error { + // Nothing to delete on CIS resource + d.SetId("") + return nil +} diff --git a/ibm/resource_ibm_cis_domain_settings_test.go b/ibm/service/cis/resource_ibm_cis_domain_settings_test.go similarity index 82% rename from ibm/resource_ibm_cis_domain_settings_test.go rename to ibm/service/cis/resource_ibm_cis_domain_settings_test.go index 9dfb78a93..14b230ecb 100644 --- a/ibm/resource_ibm_cis_domain_settings_test.go +++ b/ibm/service/cis/resource_ibm_cis_domain_settings_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,18 +16,18 @@ func TestAccIBMCisSettings_Basic(t *testing.T) { name := "ibm_cis_domain_settings." + "test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckCisSettingsConfigBasic3("test", cisDomainStatic), + Config: testAccCheckCisSettingsConfigBasic3("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "waf", "off"), resource.TestCheckResourceAttr(name, "min_tls_version", "1.1"), ), }, { - Config: testAccCheckCisSettingsConfigBasic1("test", cisDomainStatic), + Config: testAccCheckCisSettingsConfigBasic1("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "waf", "on"), resource.TestCheckResourceAttr(name, "ssl", "full"), @@ -33,7 +35,7 @@ func TestAccIBMCisSettings_Basic(t *testing.T) { ), }, { - Config: testAccCheckCisSettingsConfigBasic2("test", cisDomainStatic), + Config: testAccCheckCisSettingsConfigBasic2("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "waf", "off"), resource.TestCheckResourceAttr(name, "ssl", "flexible"), @@ -41,7 +43,7 @@ func TestAccIBMCisSettings_Basic(t *testing.T) { ), }, { - Config: testAccCheckCisSettingsConfigBasic4("test", cisDomainStatic), + Config: testAccCheckCisSettingsConfigBasic4("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "waf", "off"), resource.TestCheckResourceAttr(name, "ssl", "flexible"), @@ -55,11 +57,11 @@ func TestAccIBMCisSettings_Import(t *testing.T) { name := "ibm_cis_domain_settings." + "test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckCisSettingsConfigBasic4("test", cisDomainStatic), + Config: testAccCheckCisSettingsConfigBasic4("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "waf", "off"), resource.TestCheckResourceAttr(name, "ssl", "flexible"), @@ -74,7 +76,7 @@ func TestAccIBMCisSettings_Import(t *testing.T) { }) } -func testAccCheckCisSettingsConfigBasic3(id string, cisDomainStatic string) string { +func testAccCheckCisSettingsConfigBasic3(id string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_domain_settings" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -85,7 +87,7 @@ func testAccCheckCisSettingsConfigBasic3(id string, cisDomainStatic string) stri `, id) } -func testAccCheckCisSettingsConfigBasic1(id string, cisDomainStatic string) string { +func testAccCheckCisSettingsConfigBasic1(id string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_domain_settings" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -97,7 +99,7 @@ func testAccCheckCisSettingsConfigBasic1(id string, cisDomainStatic string) stri `, id) } -func testAccCheckCisSettingsConfigBasic2(id string, cisDomainStatic string) string { +func testAccCheckCisSettingsConfigBasic2(id string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_domain_settings" "%[1]s" { cis_id = data.ibm_cis.cis.id @@ -109,7 +111,7 @@ func testAccCheckCisSettingsConfigBasic2(id string, cisDomainStatic string) stri `, id) } -func testAccCheckCisSettingsConfigBasic4(id string, cisDomainStatic string) string { +func testAccCheckCisSettingsConfigBasic4(id string, CisDomainStatic string) string { return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` resource "ibm_cis_domain_settings" "%[1]s" { cis_id = data.ibm_cis.cis.id diff --git a/ibm/service/cis/resource_ibm_cis_domain_test.go b/ibm/service/cis/resource_ibm_cis_domain_test.go new file mode 100644 index 000000000..323c19dd7 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_domain_test.go @@ -0,0 +1,285 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "log" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMCisDomain_basic(t *testing.T) { + name := "ibm_cis_domain." + "cis_domain" + testDomain := uuid.New().String() + acc.CisDomainTest + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + // No requirement for CheckDestory of this resource as by reaching this test it must have already been deleted + // correctly during the resource destroy phase of test. The destroy of resource_ibm_cis used in testAccCheckCisPoolConfigBasic + // will fail if this resource is not correctly deleted. + Steps: []resource.TestStep{ + { + Config: testAccCheckCisDomainConfigCisRIbasic("test_acc", testDomain), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "domain", testDomain), + resource.TestCheckResourceAttr(name, "name_servers.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMCisPartialDomain_basic(t *testing.T) { + name := "ibm_cis_domain." + "cis_domain" + testPartialDomain := uuid.New().String() + ".test.com" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + // No requirement for CheckDestory of this resource as by reaching this test it must have already been deleted + // correctly during the resource destroy phase of test. The destroy of resource_ibm_cis used in testAccCheckCisPoolConfigBasic + // will fail if this resource is not correctly deleted. + Steps: []resource.TestStep{ + { + Config: testAccCheckCisPartialDomainConfigCisRIbasic("test_acc", testPartialDomain), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "domain", testPartialDomain), + resource.TestCheckResourceAttr(name, "type", "partial"), + ), + }, + }, + }) +} + +func TestAccIBMCisDomain_CreateAfterManualDestroy(t *testing.T) { + // Manual destroy of Domain resource + //t.Parallel() + t.Skip() + var zoneOne, zoneTwo string + name := "ibm_cis_domain." + "cis_domain" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckCisDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisDomainConfigCisRIbasic("test", acc.CisDomainTest), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisDomainExists(name, &zoneOne), + testAccCisDomainManuallyDelete(&zoneOne), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccCheckCisDomainConfigCisRIbasic("test", acc.CisDomainTest), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisDomainExists(name, &zoneTwo), + // No check for change in ID as CIS retains the same domainid across create/delete for a domain + ), + }, + }, + }) +} + +func TestAccIBMCisDomain_CreateAfterManualCisRIDestroy(t *testing.T) { + // Manual destroy of Domain resource & CIS Resource Instance + //t.Parallel() + t.Skip() + var zoneOne, zoneTwo string + name := "ibm_cis_domain." + "cis_domain" + testDomain := uuid.New().String() + acc.CisDomainTest + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckCisDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisDomainConfigCisRIbasic("test", testDomain), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisDomainExists(name, &zoneOne), + testAccCisDomainManuallyDelete(&zoneOne), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccCheckCisDomainConfigCisRIbasic("test", testDomain), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisDomainExists(name, &zoneTwo), + // No check for change in ID as CIS retains the same domainid across create/delete for a domain + ), + }, + }, + }) +} + +func TestAccIBMCisDomain_import(t *testing.T) { + name := "ibm_cis_domain.cis_domain" + testDomain := uuid.New().String() + acc.CisDomainTest + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisDomainConfigCisRIbasic("test_acc", testDomain), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "status", "pending"), + resource.TestCheckResourceAttr(name, "domain", testDomain), + resource.TestCheckResourceAttr(name, "name_servers.#", "2"), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes"}, + }, + }, + }) +} + +func testAccCisDomainManuallyDelete(tfZoneID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + tfZone := *tfZoneID + + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(tfZone) + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + delOpt := cisClient.NewDeleteZoneOptions(zoneID) + _, resp, err := cisClient.DeleteZone(delOpt) + if err != nil { + return fmt.Errorf("[ERR] Error deleting zone %v", resp) + } + return nil + } +} + +func testAccCheckCisDomainDestroy(s *terraform.State) error { + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cis_domain" { + continue + } + log.Println("check domain destroy : ", rs.Primary.ID) + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(rs.Primary.ID) + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + opt := cisClient.NewGetZoneOptions(zoneID) + _, _, err = cisClient.GetZone(opt) + if err == nil { + return fmt.Errorf("Domain still exists when destroying") + } + } + + return nil +} + +func testAccCheckCisDomainExists(n string, tfZoneID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("[ERROR] Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No Domain ID is set") + } + + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisZonesV1ClientSession() + if err != nil { + return err + } + zoneID, crn, _ := flex.ConvertTftoCisTwoVar(rs.Primary.ID) + if err != nil { + return err + } + cisClient.Crn = core.StringPtr(crn) + opt := cisClient.NewGetZoneOptions(zoneID) + foundZone, resp, err := cisClient.GetZone(opt) + if err != nil { + return fmt.Errorf("Domain does not exists: %v", resp) + } + *tfZoneID = flex.ConvertCisToTfTwoVar(*foundZone.Result.ID, crn) + return nil + } +} + +// func testAccCheckCisDomainConfigCisDS_basic(resourceName string, domain string) string { +// // Cis instance data source +// return testAccCheckCisInstanceDataSourceConfig_basic(CisResourceGroup, CisInstance) + fmt.Sprintf(` +// resource "ibm_cis_domain" "%[1]s" { +// cis_id = data.ibm_cis.testacc_ds_cis.id +// domain = "%[2]s" +// } +// `, resourceName, domain) +// } + +func testAccCheckCisDomainConfigCisRIbasic(resourceName string, domain string) string { + // Cis dynamically created resource instance + return testAccCheckIBMCisDataSourceConfig(acc.CisInstance) + fmt.Sprintf(` + resource "ibm_cis_domain" "cis_domain" { + cis_id = data.ibm_cis.cis.id + domain = "%[1]s" + } + `, domain) +} + +func testAccCheckCisPartialDomainConfigCisRIbasic(resourceName string, domain string) string { + // Cis dynamically created resource instance + return testAccCheckIBMCisDataSourceConfig(acc.CisInstance) + fmt.Sprintf(` + resource "ibm_cis_domain" "cis_domain" { + cis_id = data.ibm_cis.cis.id + domain = "%[1]s" + type = "partial" + } + `, domain) +} + +// func testAccCheckCisDomainDataSourceConfig_basic(resourceName string, domain string) string { +// return testAccCheckCisInstanceDataSourceConfig_basic(CisResourceGroup, CisInstance) + fmt.Sprintf(` +// data "ibm_cis_domain" "%[1]s" { +// cis_id = data.ibm_cis.testacc_ds_cis.id +// domain = "%[2]s" +// } +// `, resourceName, domain) +// } + +// func testAccCheckCisInstanceDataSourceConfig_basic(CisResourceGroup string, CisInstance string) string { +// // flex.DefaultResourceGroup from env vars +// //CisInstance from env vars +// return fmt.Sprintf(` +// data "ibm_resource_group" "test_acc" { +// name = "%[1]s" +// } + +// data "ibm_cis" "testacc_ds_cis" { +// resource_group_id = data.ibm_resource_group.test_acc.id +// name = "%[2]s" +// } +// `, CisResourceGroup, CisInstance) + +// } diff --git a/ibm/service/cis/resource_ibm_cis_edge_functions_action.go b/ibm/service/cis/resource_ibm_cis_edge_functions_action.go new file mode 100644 index 000000000..275ab45ab --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_edge_functions_action.go @@ -0,0 +1,187 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisEdgeFunctionsActionActionName = "action_name" + cisEdgeFunctionsActionScript = "script" +) + +func ResourceIBMCISEdgeFunctionsAction() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISEdgeFunctionsActionCreate, + Read: ResourceIBMCISEdgeFunctionsActionRead, + Update: ResourceIBMCISEdgeFunctionsActionUpdate, + Delete: ResourceIBMCISEdgeFunctionsActionDelete, + Exists: ResourceIBMCISEdgeFunctionsActionExists, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeValidator("ibm_cis_edge_functions_action", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Domain ID", + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisEdgeFunctionsActionActionName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Edge function action script name", + }, + cisEdgeFunctionsActionScript: { + Type: schema.TypeString, + Required: true, + Description: "Edge function action script", + }, + }, + } +} + +func ResourceIBMCISEdgeFunctionsActionValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISEdgeFunctionsActionValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_edge_functions_action", + Schema: validateSchema} + return &ibmCISEdgeFunctionsActionValidator +} + +func ResourceIBMCISEdgeFunctionsActionCreate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + scriptName := d.Get(cisEdgeFunctionsActionActionName).(string) + script := d.Get(cisEdgeFunctionsActionScript).(string) + r := ioutil.NopCloser(strings.NewReader(script)) + opt := cisClient.NewUpdateEdgeFunctionsActionOptions(scriptName) + opt.SetEdgeFunctionsAction(r) + + _, _, err = cisClient.UpdateEdgeFunctionsAction(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error: %v", err) + } + d.SetId(flex.ConvertCisToTfThreeVar(scriptName, zoneID, crn)) + return ResourceIBMCISEdgeFunctionsActionRead(d, meta) +} + +func ResourceIBMCISEdgeFunctionsActionUpdate(d *schema.ResourceData, meta interface{}) error { + if d.HasChange(cisEdgeFunctionsActionScript) { + return ResourceIBMCISEdgeFunctionsActionCreate(d, meta) + } + + return ResourceIBMCISEdgeFunctionsActionRead(d, meta) +} + +func ResourceIBMCISEdgeFunctionsActionRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + + scriptName, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewGetEdgeFunctionsActionOptions(scriptName) + result, resp, err := cisClient.GetEdgeFunctionsAction(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error: %v", resp) + } + + // read script content + content := []byte{} + p := make([]byte, 8) + for { + n, err := result.Read(p) + content = append(content, p[:n]...) + if err == io.EOF || n < 1 { + break + } + } + err = result.Close() + if err != nil { + return fmt.Errorf("[ERROR] Error in closing reader") + } + + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisEdgeFunctionsActionActionName, scriptName) + d.Set(cisEdgeFunctionsActionScript, string(content)) + return nil +} + +func ResourceIBMCISEdgeFunctionsActionExists(d *schema.ResourceData, meta interface{}) (bool, error) { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return false, fmt.Errorf("[ERROR] Error in creating CIS object") + } + + scriptName, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewGetEdgeFunctionsActionOptions(scriptName) + _, response, err := cisClient.GetEdgeFunctionsAction(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("Edge functions action script is not found") + return false, nil + } + return false, fmt.Errorf("[ERROR] Error: %v", response) + } + return true, nil +} + +func ResourceIBMCISEdgeFunctionsActionDelete(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return fmt.Errorf("[ERROR] Error in creating CIS object") + } + + scriptName, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewDeleteEdgeFunctionsActionOptions(scriptName) + _, response, err := cisClient.DeleteEdgeFunctionsAction(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error in edge function action script deletion: %v", response) + } + return nil +} diff --git a/ibm/resource_ibm_cis_edge_functions_action_test.go b/ibm/service/cis/resource_ibm_cis_edge_functions_action_test.go similarity index 82% rename from ibm/resource_ibm_cis_edge_functions_action_test.go rename to ibm/service/cis/resource_ibm_cis_edge_functions_action_test.go index 180f95d3d..00f26a719 100644 --- a/ibm/resource_ibm_cis_edge_functions_action_test.go +++ b/ibm/service/cis/resource_ibm_cis_edge_functions_action_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,8 +25,8 @@ func TestAccIBMCisEdgeFunctionsAction_Basic(t *testing.T) { content2 := "addEventListener('fetch', (event) => {\n\tevent.respondWith(handleRequest(event.request))\n})\n\n/**\n * Sample test function\n * @param {Request} request\n */\nasync function handleRequest(request) {\n\tconsole.log('Got request', request)\n\tconst response = await fetch(request)\n\treturn response;\n}" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsActionDestroy, Steps: []resource.TestStep{ { @@ -53,8 +57,8 @@ func TestAccIBMCisEdgeFunctionsAction_import(t *testing.T) { name := "ibm_cis_edge_functions_action.test" actionName := "sample_script" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsActionDestroy, Steps: []resource.TestStep{ { @@ -78,8 +82,8 @@ func TestAccIBMCisFunctionsAction_CreateAfterManualDestroy(t *testing.T) { scriptOne = "script_one" scriptTwo = "script_two" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsActionDestroy, Steps: []resource.TestStep{ { @@ -109,12 +113,12 @@ func TestAccIBMCisFunctionsAction_CreateAfterManualDestroy(t *testing.T) { func testAccCheckIBMCisEdgeFunctionsActionDelete(tfActionID *string) resource.TestCheckFunc { return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } - actionName, zoneID, cisID, err := convertTfToCisThreeVar(*tfActionID) + actionName, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(*tfActionID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewDeleteEdgeFunctionsActionOptions(actionName) @@ -127,16 +131,16 @@ func testAccCheckIBMCisEdgeFunctionsActionDelete(tfActionID *string) resource.Te } func testAccCheckIBMCisEdgeFunctionsActionDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_cis_edge_functions_action" { continue } - actionName, zoneID, cisID, err := convertTfToCisThreeVar(rs.Primary.ID) + actionName, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewGetEdgeFunctionsActionOptions(actionName) @@ -153,28 +157,28 @@ func testAccCheckIBMCisEdgeFunctionsActionExists(n string, tfRecordID *string) r return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } - tfRecord := *tfRecordID - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + // tfRecord := *tfRecordID + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } - actionName, zoneID, cisID, err := convertTfToCisThreeVar(rs.Primary.ID) + actionName, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewGetEdgeFunctionsActionOptions(actionName) _, resp, err := cisClient.GetEdgeFunctionsAction(opt) if err != nil { - return fmt.Errorf("Error: %v", resp) + return fmt.Errorf("[ERROR] Error: %v", resp) } - tfRecord = convertCisToTfThreeVar(actionName, zoneID, cisID) + tfRecord := flex.ConvertCisToTfThreeVar(actionName, zoneID, cisID) *tfRecordID = tfRecord return nil } diff --git a/ibm/service/cis/resource_ibm_cis_edge_functions_trigger.go b/ibm/service/cis/resource_ibm_cis_edge_functions_trigger.go new file mode 100644 index 000000000..77d4088bb --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_edge_functions_trigger.go @@ -0,0 +1,200 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisEdgeFunctionsTriggerID = "trigger_id" + cisEdgeFunctionsTriggerPattern = "pattern_url" + cisEdgeFunctionsTriggerActionName = "action_name" + cisEdgeFunctionsTriggerRequestLimitFailOpen = "request_limit_fail_open" +) + +func ResourceIBMCISEdgeFunctionsTrigger() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISEdgeFunctionsTriggerCreate, + Read: ResourceIBMCISEdgeFunctionsTriggerRead, + Update: ResourceIBMCISEdgeFunctionsTriggerUpdate, + Delete: ResourceIBMCISEdgeFunctionsTriggerDelete, + Exists: ResourceIBMCISEdgeFunctionsTriggerExists, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Intance CRN", + ValidateFunc: validate.InvokeValidator("ibm_cis_edge_functions_trigger", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Required: true, + Description: "CIS Domain ID", + DiffSuppressFunc: suppressDataDiff, + }, + cisEdgeFunctionsTriggerID: { + Type: schema.TypeString, + Computed: true, + Description: "CIS Edge Functions trigger route ID", + }, + cisEdgeFunctionsTriggerPattern: { + Type: schema.TypeString, + Required: true, + Description: "Edge function trigger pattern", + }, + cisEdgeFunctionsTriggerActionName: { + Type: schema.TypeString, + Optional: true, + Description: "Edge function trigger action name", + }, + cisEdgeFunctionsTriggerRequestLimitFailOpen: { + Type: schema.TypeBool, + Computed: true, + Description: "Edge function trigger request limit fail open", + }, + }, + } +} +func ResourceIBMCISEdgeFunctionsTriggerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISEdgeFunctionsTriggerValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_edge_functions_trigger", + Schema: validateSchema} + return &ibmCISEdgeFunctionsTriggerValidator +} + +func ResourceIBMCISEdgeFunctionsTriggerCreate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + opt := cisClient.NewCreateEdgeFunctionsTriggerOptions() + if action, ok := d.GetOk(cisEdgeFunctionsTriggerActionName); ok { + opt.SetScript(action.(string)) + } + pattern := d.Get(cisEdgeFunctionsTriggerPattern).(string) + opt.SetPattern(pattern) + + result, _, err := cisClient.CreateEdgeFunctionsTrigger(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error creating edge function trigger route : %v", err) + } + d.SetId(flex.ConvertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) + return ResourceIBMCISEdgeFunctionsTriggerRead(d, meta) +} + +func ResourceIBMCISEdgeFunctionsTriggerUpdate(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + + routeID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + if d.HasChange(cisEdgeFunctionsTriggerActionName) || + d.HasChange(cisEdgeFunctionsTriggerPattern) { + opt := cisClient.NewUpdateEdgeFunctionsTriggerOptions(routeID) + + if action, ok := d.GetOk(cisEdgeFunctionsTriggerActionName); ok { + opt.SetScript(action.(string)) + } + pattern := d.Get(cisEdgeFunctionsTriggerPattern).(string) + opt.SetPattern(pattern) + + _, _, err := cisClient.UpdateEdgeFunctionsTrigger(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error updating edge function trigger route : %v", err) + } + } + return ResourceIBMCISEdgeFunctionsTriggerRead(d, meta) +} + +func ResourceIBMCISEdgeFunctionsTriggerRead(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return err + } + + routeID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewGetEdgeFunctionsTriggerOptions(routeID) + result, resp, err := cisClient.GetEdgeFunctionsTrigger(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error: %v", resp) + } + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisEdgeFunctionsTriggerID, routeID) + d.Set(cisEdgeFunctionsTriggerActionName, result.Result.Script) + d.Set(cisEdgeFunctionsTriggerPattern, result.Result.Pattern) + d.Set(cisEdgeFunctionsTriggerRequestLimitFailOpen, result.Result.RequestLimitFailOpen) + return nil +} + +func ResourceIBMCISEdgeFunctionsTriggerExists(d *schema.ResourceData, meta interface{}) (bool, error) { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return false, err + } + + routeID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewGetEdgeFunctionsTriggerOptions(routeID) + _, response, err := cisClient.GetEdgeFunctionsTrigger(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("Edge functions trigger route is not found") + return false, nil + } + return false, fmt.Errorf("[ERROR] Error: %v", response) + } + return true, nil +} + +func ResourceIBMCISEdgeFunctionsTriggerDelete(d *schema.ResourceData, meta interface{}) error { + cisClient, err := meta.(conns.ClientSession).CisEdgeFunctionClientSession() + if err != nil { + return fmt.Errorf("[ERROR] Error in creating CIS object") + } + + routeID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + cisClient.Crn = core.StringPtr(crn) + cisClient.ZoneIdentifier = core.StringPtr(zoneID) + + opt := cisClient.NewDeleteEdgeFunctionsTriggerOptions(routeID) + _, response, err := cisClient.DeleteEdgeFunctionsTrigger(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error in edge function trigger route deletion: %v", response) + } + return nil +} diff --git a/ibm/resource_ibm_cis_edge_functions_trigger_test.go b/ibm/service/cis/resource_ibm_cis_edge_functions_trigger_test.go similarity index 78% rename from ibm/resource_ibm_cis_edge_functions_trigger_test.go rename to ibm/service/cis/resource_ibm_cis_edge_functions_trigger_test.go index a07f0f33b..7035aa2ab 100644 --- a/ibm/resource_ibm_cis_edge_functions_trigger_test.go +++ b/ibm/service/cis/resource_ibm_cis_edge_functions_trigger_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,12 +21,12 @@ func TestAccIBMCisEdgeFunctionsTrigger_Basic(t *testing.T) { testName := "test" resourceName := fmt.Sprintf("ibm_cis_edge_functions_trigger.%s", testName) actionName := "sample_script" - pattern1 := fmt.Sprintf("example.%s/*", cisDomainStatic) - pattern2 := fmt.Sprintf("example1.%s/*", cisDomainStatic) + pattern1 := fmt.Sprintf("example.%s/*", acc.CisDomainStatic) + pattern2 := fmt.Sprintf("example1.%s/*", acc.CisDomainStatic) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsActionDestroy, Steps: []resource.TestStep{ { @@ -52,11 +56,11 @@ func TestAccIBMCisEdgeFunctionsTrigger_import(t *testing.T) { name := "ibm_cis_edge_functions_trigger.test" actionName := "sample_script" - pattern := fmt.Sprintf("example.%s/*", cisDomainStatic) + pattern := fmt.Sprintf("example.%s/*", acc.CisDomainStatic) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsTriggerDestroy, Steps: []resource.TestStep{ { @@ -88,10 +92,10 @@ func TestAccIBMCisFunctionsTrigger_CreateAfterManualDestroy(t *testing.T) { name := "ibm_cis_edge_functions_trigger.test" scriptOne = "script_one" scriptTwo = "script_two" - pattern := fmt.Sprintf("example.%s/*", cisDomainStatic) + pattern := fmt.Sprintf("example.%s/*", acc.CisDomainStatic) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisEdgeFunctionsTriggerDestroy, Steps: []resource.TestStep{ { @@ -121,12 +125,12 @@ func TestAccIBMCisFunctionsTrigger_CreateAfterManualDestroy(t *testing.T) { func testAccCheckIBMCisEdgeFunctionsTriggerDelete(tfActionID *string) resource.TestCheckFunc { return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } - actionName, zoneID, cisID, _ := convertTfToCisThreeVar(*tfActionID) + actionName, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(*tfActionID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewDeleteEdgeFunctionsTriggerOptions(actionName) @@ -139,16 +143,16 @@ func testAccCheckIBMCisEdgeFunctionsTriggerDelete(tfActionID *string) resource.T } func testAccCheckIBMCisEdgeFunctionsTriggerDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_cis_edge_functions_trigger" { continue } - triggerID, zoneID, cisID, _ := convertTfToCisThreeVar(rs.Primary.ID) + triggerID, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewGetEdgeFunctionsTriggerOptions(triggerID) @@ -165,31 +169,31 @@ func testAccCheckIBMCisEdgeFunctionsTriggerExists(n string, tfRecordID *string) return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } - tfRecord := *tfRecordID - cisClient, err := testAccProvider.Meta().(ClientSession).CisEdgeFunctionClientSession() + // tfRecord := *tfRecordID + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisEdgeFunctionClientSession() if err != nil { - return fmt.Errorf("Error in creating CIS object") + return fmt.Errorf("[ERROR] Error in creating CIS object") } - triggerID, zoneID, cisID, _ := convertTfToCisThreeVar(rs.Primary.ID) + triggerID, zoneID, cisID, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) cisClient.Crn = core.StringPtr(cisID) cisClient.ZoneIdentifier = core.StringPtr(zoneID) opt := cisClient.NewGetEdgeFunctionsTriggerOptions(triggerID) result, resp, err := cisClient.GetEdgeFunctionsTrigger(opt) if err != nil { - return fmt.Errorf("Error: %v", resp) + return fmt.Errorf("[ERROR] Error: %v", resp) } if *result.Result.ID != triggerID { return fmt.Errorf("Trigger ID is not found") } - tfRecord = convertCisToTfThreeVar(*result.Result.ID, zoneID, cisID) + tfRecord := flex.ConvertCisToTfThreeVar(*result.Result.ID, zoneID, cisID) *tfRecordID = tfRecord return nil } diff --git a/ibm/service/cis/resource_ibm_cis_filter.go b/ibm/service/cis/resource_ibm_cis_filter.go new file mode 100644 index 000000000..b8776c7fe --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_filter.go @@ -0,0 +1,242 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/networking-go-sdk/filtersv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmCISFilters = "ibm_cis_filter" + cisFilterExpression = "expression" + cisFilterPaused = "paused" + cisFilterDescription = "description" + cisFilterID = "filter_id" +) + +func ResourceIBMCISFilter() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISFilterCreate, + Read: ResourceIBMCISFilterRead, + Update: ResourceIBMCISFilterUpdate, + Delete: ResourceIBMCISFilterDelete, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_filter", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisFilterPaused: { + Type: schema.TypeBool, + Optional: true, + Description: "Filter Paused", + }, + cisFilterID: { + Type: schema.TypeString, + Computed: true, + Description: "Filter ID", + }, + cisFilterExpression: { + Type: schema.TypeString, + Required: true, + Description: "Filter Expression", + }, + cisFilterDescription: { + Type: schema.TypeString, + Optional: true, + Description: "Filter Description", + ValidateFunc: validate.InvokeValidator(ibmCISFilters, cisFilterDescription), + }, + }, + } +} +func ResourceIBMCISFilterCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while Getting IAM Access Token using BluemixSession %s", err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisFiltersSession %s", err) + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + + var newfilter filtersv1.FilterInput + + if p, ok := d.GetOkExists(cisFilterPaused); ok { + paused := p.(bool) + newfilter.Paused = &paused + } + if des, ok := d.GetOk(cisFilterDescription); ok { + description := des.(string) + newfilter.Description = &description + } + if e, ok := d.GetOk(cisFilterExpression); ok { + expression := e.(string) + newfilter.Expression = &expression + } + + opt := cisClient.NewCreateFilterOptions(xAuthtoken, crn, zoneID) + + opt.SetFilterInput([]filtersv1.FilterInput{newfilter}) + + result, resp, err := cisClient.CreateFilter(opt) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error creating Filter for zone %q: %s %s", zoneID, err, resp) + } + d.SetId(flex.ConvertCisToTfThreeVar(*result.Result[0].ID, zoneID, crn)) + return ResourceIBMCISFilterRead(d, meta) + +} +func ResourceIBMCISFilterRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while Getting IAM Access Token using BluemixSession %s", err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisFiltersSession %s", err) + } + filterid, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return err + } + opt := cisClient.NewGetFilterOptions(xAuthtoken, crn, zoneID, filterid) + + result, response, err := cisClient.GetFilter(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("Error GetFilter not found ") + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error finding GetFilter %q: %s %s", d.Id(), err, response) + } + if result.Result != nil { + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisFilterID, result.Result.ID) + d.Set(cisFilterPaused, result.Result.Paused) + d.Set(cisFilterDescription, result.Result.Description) + d.Set(cisFilterExpression, result.Result.Expression) + } + return nil +} +func ResourceIBMCISFilterUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while Getting IAM Access Token using BluemixSession %s", err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return fmt.Errorf("[ERROR] Error while getting the CisFiltersSession %s", err) + } + + filterid, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return err + } + + if d.HasChange(cisFilterExpression) || + d.HasChange(cisFilterPaused) || + d.HasChange(cisFilterDescription) { + + var updatefilter filtersv1.FilterUpdateInput + updatefilter.ID = &filterid + + if p, ok := d.GetOkExists(cisFilterPaused); ok { + paused := p.(bool) + updatefilter.Paused = &paused + } + if des, ok := d.GetOk(cisFilterDescription); ok { + description := des.(string) + updatefilter.Description = &description + } + if e, ok := d.GetOk(cisFilterExpression); ok { + expression := e.(string) + updatefilter.Expression = &expression + } + + opt := cisClient.NewUpdateFiltersOptions(xAuthtoken, crn, zoneID) + + opt.SetFilterUpdateInput([]filtersv1.FilterUpdateInput{updatefilter}) + + result, resp, err := cisClient.UpdateFilters(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error updating Filter for zone %q: %s %s", zoneID, err, resp) + } + + if *result.Result[0].ID == "" { + return fmt.Errorf("[ERROR] Error failed to find id in Update response; resource was empty") + } + } + return ResourceIBMCISFilterRead(d, meta) +} +func ResourceIBMCISFilterDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + xAuthtoken := sess.Config.IAMAccessToken + cisClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return err + } + filterid, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return err + } + opt := cisClient.NewDeleteFiltersOptions(xAuthtoken, crn, zoneID, filterid) + _, _, err = cisClient.DeleteFilters(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Filter: %s", err) + } + + return nil +} +func ResourceIBMCISFilterValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisFilterDescription, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "Filter-creation"}) + + ibmCISFiltersResourceValidator := validate.ResourceValidator{ResourceName: ibmCISFilters, Schema: validateSchema} + return &ibmCISFiltersResourceValidator +} diff --git a/ibm/service/cis/resource_ibm_cis_filter_test.go b/ibm/service/cis/resource_ibm_cis_filter_test.go new file mode 100644 index 000000000..b2d599077 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_filter_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisFilter_Basic(t *testing.T) { + name := "ibm_cis_filter." + "test" + filterexp := "(http.request.uri eq \"/test-update?number=5\")" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisFilter_basic("test", acc.CisDomainStatic, "true", "Filter-creation", filterexp), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "description", "Filter-creation"), + resource.TestCheckResourceAttr(name, "expression", filterexp), + resource.TestCheckResourceAttr(name, "paused", "true"), + ), + }, + }, + }) +} + +func TestAccIBMCisFilter_Import(t *testing.T) { + name := "ibm_cis_filter." + "test" + filterexp := "(http.request.uri eq \"/test-update?number=5\")" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisFilter_basic("test", acc.CisDomainStatic, "true", "Filter-creation", filterexp), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "expression", filterexp), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func testAccCheckCisFilter_basic(id, CisDomainStatic, paused, description, expression string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + resource "ibm_cis_filter" "%[1]s" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + paused = "true" + description = "Filter-creation" + expression = "(http.request.uri eq \"/test-update?number=5\")" + } +`, id, acc.CisDomainStatic, paused, description, expression) +} diff --git a/ibm/resource_ibm_cis_firewall.go b/ibm/service/cis/resource_ibm_cis_firewall.go similarity index 82% rename from ibm/resource_ibm_cis_firewall.go rename to ibm/service/cis/resource_ibm_cis_firewall.go index b262f0fc3..4e1a6c4b8 100644 --- a/ibm/resource_ibm_cis_firewall.go +++ b/ibm/service/cis/resource_ibm_cis_firewall.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" cislockdownv1 "github.com/IBM/networking-go-sdk/zonelockdownv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -55,13 +58,13 @@ const ( cisFirewallUARuleConfigurationValue = "value" ) -func resourceIBMCISFirewallRecord() *schema.Resource { +func ResourceIBMCISFirewallRecord() *schema.Resource { return &schema.Resource{ - Create: resourceIBMCISFirewallRecordCreate, - Read: resourceIBMCISFirewallRecordRead, - Update: resourceIBMCISFirewallRecordUpdate, - Delete: resourceIBMCISFirewallRecordDelete, - Exists: resourceIBMCISFirewallRecordExists, + Create: ResourceIBMCISFirewallRecordCreate, + Read: ResourceIBMCISFirewallRecordRead, + Update: ResourceIBMCISFirewallRecordUpdate, + Delete: ResourceIBMCISFirewallRecordDelete, + Exists: ResourceIBMCISFirewallRecordExists, Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ @@ -70,6 +73,8 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Description: "CIS object id", Required: true, ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_firewall", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -83,7 +88,7 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Required: true, ForceNew: true, Description: "Type of firewall.Allowable values are access-rules,ua-rules,lockdowns", - ValidateFunc: InvokeValidator(ibmCISFirewall, cisFirewallType), + ValidateFunc: validate.InvokeValidator(ibmCISFirewall, cisFirewallType), }, cisFirewallLockdown: { @@ -133,7 +138,7 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Target type", - ValidateFunc: InvokeValidator( + ValidateFunc: validate.InvokeValidator( ibmCISFirewall, cisFirewallLockdownConfigurationsTarget), }, @@ -173,7 +178,7 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Access rule mode", - ValidateFunc: InvokeValidator(ibmCISFirewall, cisFirewallAccessRuleMode), + ValidateFunc: validate.InvokeValidator(ibmCISFirewall, cisFirewallAccessRuleMode), }, cisFirewallAccessRuleConfiguration: { Type: schema.TypeList, @@ -182,12 +187,12 @@ func resourceIBMCISFirewallRecord() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - cisFirewallUARuleConfigurationTarget: { + cisFirewallAccessRuleConfigurationTarget: { Type: schema.TypeString, Required: true, ForceNew: true, Description: "Target type", - ValidateFunc: InvokeValidator(ibmCISFirewall, + ValidateFunc: validate.InvokeValidator(ibmCISFirewall, cisFirewallAccessRuleConfigurationTarget), }, cisFirewallUARuleConfigurationValue: { @@ -232,7 +237,7 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Type: schema.TypeString, Required: true, Description: "user agent rule mode", - ValidateFunc: InvokeValidator(ibmCISFirewall, cisFirewallUARuleMode), + ValidateFunc: validate.InvokeValidator(ibmCISFirewall, cisFirewallUARuleMode), }, cisFirewallUARuleConfiguration: { Type: schema.TypeList, @@ -245,7 +250,7 @@ func resourceIBMCISFirewallRecord() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Target type", - ValidateFunc: InvokeValidator(ibmCISFirewall, + ValidateFunc: validate.InvokeValidator(ibmCISFirewall, cisFirewallUARuleConfigurationTarget), }, cisFirewallUARuleConfigurationValue: { @@ -263,64 +268,72 @@ func resourceIBMCISFirewallRecord() *schema.Resource { } } -func resourceIBMCISFirewallValidator() *ResourceValidator { +func ResourceIBMCISFirewallValidator() *validate.ResourceValidator { firewallTypes := "access_rules, ua_rules, lockdowns" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: firewallTypes}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallLockdownConfigurationsTarget, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "ip, ip_range"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallAccessRuleConfigurationTarget, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "ip, ip_range, asn, country"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallUARuleConfigurationTarget, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "ua"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallAccessRuleMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "block, challenge, whitelist, js_challenge"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisFirewallUARuleMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "block, challenge, js_challenge"}) - cisFirewallValidator := ResourceValidator{ResourceName: ibmCISHealthCheck, Schema: validateSchema} + cisFirewallValidator := validate.ResourceValidator{ResourceName: ibmCISHealthCheck, Schema: validateSchema} return &cisFirewallValidator } -func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{}) error { +func ResourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{}) error { crn := d.Get(cisID).(string) - zoneID, _, _ := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) firewallType := d.Get(cisFirewallType).(string) if firewallType == cisFirewallTypeLockdowns { // Firewall Type : Lockdowns - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -328,7 +341,7 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} opt := cisClient.NewCreateZoneLockdownRuleOptions() // not able to check bool variable availability - v, _ := lockdown[cisFirewallLockdownPaused] + v := lockdown[cisFirewallLockdownPaused] opt.SetPaused(v.(bool)) if v, ok := lockdown[cisFirewallLockdownDesc]; ok && v.(string) != "" { opt.SetDescription(v.(string)) @@ -336,7 +349,7 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} if v, ok := lockdown[cisFirewallLockdownPriority]; ok && v.(int) > 0 { opt.SetPriority(int64(v.(int))) } - urls := expandStringList(lockdown[cisFirewallLockdownURLs].([]interface{})) + urls := flex.ExpandStringList(lockdown[cisFirewallLockdownURLs].([]interface{})) configurations, err := expandLockdownsTypeConfiguration( lockdown[cisFirewallLockdownConfigurations].([]interface{})) if err != nil { @@ -352,11 +365,11 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} log.Printf("Create zone firewall lockdown failed: %v", response) return err } - d.SetId(convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) + d.SetId(flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) } else if firewallType == cisFirewallTypeAccessRules { - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -390,10 +403,10 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} log.Printf("Create zone firewall access rule failed: %v", response) return err } - d.SetId(convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) + d.SetId(flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) } else if firewallType == cisFirewallTypeUARules { - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -404,7 +417,7 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} mode := uaRule[cisFirewallUARuleMode].(string) configList := uaRule[cisFirewallUARuleConfiguration].([]interface{}) if len(configList) > 1 { - return fmt.Errorf("Only one configuration is allowed for %s type", firewallType) + return fmt.Errorf("[ERROR] Only one configuration is allowed for %s type", firewallType) } config := configList[0].(map[string]interface{}) target := config[cisFirewallLockdownConfigurationsTarget].(string) @@ -424,7 +437,7 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} opt.SetDescription(v.(string)) } // not able to check bool attribute availablity - v, _ := uaRule[cisFirewallUARulePaused] + v := uaRule[cisFirewallUARulePaused] opt.SetPaused(v.(bool)) result, response, err := cisClient.CreateZoneUserAgentRule(opt) @@ -432,18 +445,18 @@ func resourceIBMCISFirewallRecordCreate(d *schema.ResourceData, meta interface{} log.Printf("Create zone user agent rule failed: %v", response) return err } - d.SetId(convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) + d.SetId(flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn)) } - return resourceIBMCISFirewallRecordRead(d, meta) + return ResourceIBMCISFirewallRecordRead(d, meta) } -func resourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) error { - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(d.Id()) +func ResourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) error { + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(d.Id()) if firewallType == cisFirewallTypeLockdowns { // Firewall Type : Lockdowns - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -462,7 +475,7 @@ func resourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) lockdown := map[string]interface{}{} lockdown[cisFirewallLockdownID] = *result.Result.ID lockdown[cisFirewallLockdownPaused] = *result.Result.Paused - lockdown[cisFirewallLockdownURLs] = flattenStringList(result.Result.Urls) + lockdown[cisFirewallLockdownURLs] = flex.FlattenStringList(result.Result.Urls) lockdown[cisFirewallLockdownConfigurations] = flattenLockdownsTypeConfiguration(result.Result.Configurations) if result.Result.Description != nil { @@ -477,7 +490,7 @@ func resourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) } else if firewallType == cisFirewallTypeAccessRules { // Firewall Type : Zone Access firewall rules - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -509,7 +522,7 @@ func resourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) } else if firewallType == cisFirewallTypeUARules { // Firewall Type: User Agent access rules - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -547,9 +560,9 @@ func resourceIBMCISFirewallRecordRead(d *schema.ResourceData, meta interface{}) return nil } -func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{}) error { +func ResourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{}) error { - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(d.Id()) + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(d.Id()) if d.HasChange(cisFirewallLockdown) || d.HasChange(cisFirewallAccessRule) || @@ -559,14 +572,14 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} // Firewall Type : Lockdowns lockdown := d.Get(cisFirewallLockdown).([]interface{})[0].(map[string]interface{}) - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } opt := cisClient.NewUpdateLockdownRuleOptions(lockdownID) // not able to check bool variable availability - v, _ := lockdown[cisFirewallLockdownPaused] + v := lockdown[cisFirewallLockdownPaused] opt.SetPaused(v.(bool)) if v, ok := lockdown[cisFirewallLockdownDesc]; ok && v.(string) != "" { opt.SetDescription(v.(string)) @@ -574,7 +587,7 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} if v, ok := lockdown[cisFirewallLockdownPriority]; ok && v.(int) > 0 { opt.SetPriority(int64(v.(int))) } - urls := expandStringList(lockdown[cisFirewallLockdownURLs].([]interface{})) + urls := flex.ExpandStringList(lockdown[cisFirewallLockdownURLs].([]interface{})) configurations, err := expandLockdownsTypeConfiguration(lockdown[cisFirewallLockdownConfigurations].([]interface{})) if err != nil { return err @@ -595,7 +608,7 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} accessRule := d.Get(cisFirewallAccessRule).([]interface{})[0].(map[string]interface{}) // Firewall Type : Zone Access firewall rules - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -618,7 +631,7 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} } else if firewallType == cisFirewallTypeUARules { // Firewall Type: User Agent access rules uaRule := d.Get(cisFirewallUARule).([]interface{})[0].(map[string]interface{}) - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -644,7 +657,7 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} opt.SetDescription(v.(string)) } // not able to check bool attribute availablity - v, _ := uaRule[cisFirewallUARulePaused] + v := uaRule[cisFirewallUARulePaused] opt.SetPaused(v.(bool)) _, response, err := cisClient.UpdateUserAgentRule(opt) @@ -655,15 +668,15 @@ func resourceIBMCISFirewallRecordUpdate(d *schema.ResourceData, meta interface{} } } - return resourceIBMCISFirewallRecordRead(d, meta) + return ResourceIBMCISFirewallRecordRead(d, meta) } -func resourceIBMCISFirewallRecordDelete(d *schema.ResourceData, meta interface{}) error { - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(d.Id()) +func ResourceIBMCISFirewallRecordDelete(d *schema.ResourceData, meta interface{}) error { + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(d.Id()) if firewallType == cisFirewallTypeLockdowns { // Firewall Type : Lockdowns - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -682,7 +695,7 @@ func resourceIBMCISFirewallRecordDelete(d *schema.ResourceData, meta interface{} } else if firewallType == cisFirewallTypeAccessRules { // Firewall Type : Zone Access firewall rules - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -699,7 +712,7 @@ func resourceIBMCISFirewallRecordDelete(d *schema.ResourceData, meta interface{} } else if firewallType == cisFirewallTypeUARules { // Firewall Type: User Agent access rules - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -716,12 +729,12 @@ func resourceIBMCISFirewallRecordDelete(d *schema.ResourceData, meta interface{} return nil } -func resourceIBMCISFirewallRecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(d.Id()) +func ResourceIBMCISFirewallRecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(d.Id()) if firewallType == cisFirewallTypeLockdowns { // Firewall Type : Lockdowns - cisClient, err := meta.(ClientSession).CisLockdownClientSession() + cisClient, err := meta.(conns.ClientSession).CisLockdownClientSession() if err != nil { return false, err } @@ -744,7 +757,7 @@ func resourceIBMCISFirewallRecordExists(d *schema.ResourceData, meta interface{} } else if firewallType == cisFirewallTypeAccessRules { // Firewall Type : Zone Access firewall rules - cisClient, err := meta.(ClientSession).CisAccessRuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return false, err } @@ -765,7 +778,7 @@ func resourceIBMCISFirewallRecordExists(d *schema.ResourceData, meta interface{} } else if firewallType == cisFirewallTypeUARules { // Firewall Type: User Agent access rules - cisClient, err := meta.(ClientSession).CisUARuleClientSession() + cisClient, err := meta.(conns.ClientSession).CisUARuleClientSession() if err != nil { return false, err } diff --git a/ibm/service/cis/resource_ibm_cis_firewall_rules.go b/ibm/service/cis/resource_ibm_cis_firewall_rules.go new file mode 100644 index 000000000..09e06d52c --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_firewall_rules.go @@ -0,0 +1,304 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/networking-go-sdk/firewallrulesv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmCISFirewallrules = "ibm_cis_firewall_rules" + cisFirewallrulesID = "firewall_rule_id" + cisFilter = "filter" + cisFirewallrulesAction = "action" + cisFirewallrulesPaused = "paused" + cisFirewallrulesPriority = "priority" + cisFirewallrulesDescription = "description" + cisFirewallrulesList = "firewall_rules" +) + +func ResourceIBMCISFirewallrules() *schema.Resource { + return &schema.Resource{ + CreateContext: ResourceIBMCISFirewallrulesCreate, + ReadContext: ResourceIBMCISFirewallrulesRead, + UpdateContext: ResourceIBMCISFirewallrulesUpdate, + DeleteContext: ResourceIBMCISFirewallrulesDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_firewall_rules", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisFilterID: { + Type: schema.TypeString, + Required: true, + Description: "Firewallrules Existing FilterID", + }, + cisFirewallrulesAction: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator(ibmCISFirewallrules, cisFirewallrulesAction), + Description: "Firewallrules Action", + }, + cisFirewallrulesPriority: { + Type: schema.TypeInt, + Description: "Firewallrules Action", + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator(ibmCISFirewallrules, cisFirewallrulesPriority), + }, + cisFirewallrulesDescription: { + Type: schema.TypeString, + Optional: true, + Description: "Firewallrules Description", + ValidateFunc: validate.InvokeValidator(ibmCISFirewallrules, cisFirewallrulesDescription), + }, + cisFirewallrulesPaused: { + Type: schema.TypeBool, + Optional: true, + Description: "Firewallrules Paused", + }, + }, + } +} + +func ResourceIBMCISFirewallrulesCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFirewallRulesSession() + if err != nil { + return diag.FromErr(err) + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + + var newFirewallRules firewallrulesv1.FirewallRuleInput + + if a, ok := d.GetOk(cisFirewallrulesAction); ok { + action := a.(string) + newFirewallRules.Action = &action + } + if des, ok := d.GetOk(cisFilterDescription); ok { + description := des.(string) + newFirewallRules.Description = &description + } + if id, ok := d.GetOk(cisFilterID); ok { + filterID := id.(string) + filtersInterface := &firewallrulesv1.FirewallRuleInputFilter{ID: &filterID} + newFirewallRules.Filter = filtersInterface + } + if priority, ok := d.GetOk(cisFirewallrulesPriority); ok { + rulePriority := int64(priority.(int)) + newFirewallRules.Priority = &rulePriority + } + + opt := cisClient.NewCreateFirewallRulesOptions(xAuthtoken, crn, zoneID) + + opt.SetFirewallRuleInput([]firewallrulesv1.FirewallRuleInput{newFirewallRules}) + + result, _, err := cisClient.CreateFirewallRulesWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the %s", err)) + } + d.SetId(flex.ConvertCisToTfThreeVar(*result.Result[0].ID, zoneID, crn)) + + return ResourceIBMCISFirewallrulesRead(context, d, meta) + +} +func ResourceIBMCISFirewallrulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFirewallRulesSession() + if err != nil { + return diag.FromErr(err) + } + firwallruleID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + opt := cisClient.NewGetFirewallRuleOptions(xAuthtoken, crn, zoneID, firwallruleID) + + result, response, err := cisClient.GetFirewallRuleWithContext(context, opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the firewall rules %s:%s", err, response)) + } + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisFilterID, result.Result.Filter.ID) + d.Set(cisFirewallrulesAction, result.Result.Action) + d.Set(cisFirewallrulesPaused, result.Result.Paused) + d.Set(cisFilterDescription, result.Result.Description) + + return nil +} +func ResourceIBMCISFirewallrulesUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFirewallRulesSession() + if err != nil { + return diag.FromErr(err) + } + + firewallruleID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + if d.HasChange(cisFilterID) || + d.HasChange(cisFirewallrulesAction) || + d.HasChange(cisFirewallrulesPaused) || + d.HasChange(cisFilterDescription) || + d.HasChange(cisFirewallrulesPriority) { + + var updatefirewallrules firewallrulesv1.FirewallRulesUpdateInputItem + updatefirewallrules.ID = &firewallruleID + + if a, ok := d.GetOk(cisFirewallrulesAction); ok { + action := a.(string) + updatefirewallrules.Action = &action + } + if p, ok := d.GetOk(cisFirewallrulesPaused); ok { + paused := p.(bool) + updatefirewallrules.Paused = &paused + } + if des, ok := d.GetOk(cisFilterDescription); ok { + description := des.(string) + updatefirewallrules.Description = &description + } + if priority, ok := d.GetOk(cisFirewallrulesPriority); ok { + rulePriority := int64(priority.(int)) + updatefirewallrules.Priority = &rulePriority + } + if id, ok := d.GetOk(cisFilterID); ok { + filterid := id.(string) + filterUpdate, _ := cisClient.NewFirewallRulesUpdateInputItemFilter(filterid) + updatefirewallrules.Filter = filterUpdate + } + opt := cisClient.NewUpdateFirewllRulesOptions(xAuthtoken, crn, zoneID) + + opt.SetFirewallRulesUpdateInputItem([]firewallrulesv1.FirewallRulesUpdateInputItem{updatefirewallrules}) + + result, _, err := cisClient.UpdateFirewllRulesWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the firewall rules %s", err)) + } + } + return ResourceIBMCISFirewallrulesRead(context, d, meta) +} +func ResourceIBMCISFirewallrulesDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + xAuthtoken := sess.Config.IAMAccessToken + + cisClient, err := meta.(conns.ClientSession).CisFirewallRulesSession() + if err != nil { + return diag.FromErr(err) + } + + firewallruleid, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + opt := cisClient.NewDeleteFirewallRulesOptions(xAuthtoken, crn, zoneID, firewallruleid) + _, response, err := cisClient.DeleteFirewallRulesWithContext(context, opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting the custom resolver %s:%s", err, response)) + } + + if id, ok := d.GetOk(cisFilterID); ok { + + cisFilterClient, err := meta.(conns.ClientSession).CisFiltersSession() + if err != nil { + return nil + } + + filter_id := id.(string) + filterOpt := cisFilterClient.NewDeleteFiltersOptions(xAuthtoken, crn, zoneID, filter_id) + _, _, err = cisFilterClient.DeleteFilters(filterOpt) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting Filter: %s", err)) + } + } + + d.SetId("") + return nil +} +func ResourceIBMCISFirewallrulesValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisFirewallrulesAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "log, allow, challenge, js_challenge, block"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisFirewallrulesDescription, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "Firewallrules-creation"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: cisFirewallrulesPriority, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "2147483647"}) + ibmCISFirewallrulesResourceValidator := validate.ResourceValidator{ResourceName: ibmCISFirewallrules, Schema: validateSchema} + return &ibmCISFirewallrulesResourceValidator +} diff --git a/ibm/resource_ibm_cis_firewall_rules_test.go b/ibm/service/cis/resource_ibm_cis_firewall_rules_test.go similarity index 84% rename from ibm/resource_ibm_cis_firewall_rules_test.go rename to ibm/service/cis/resource_ibm_cis_firewall_rules_test.go index 2b76541ab..6f3c1b294 100644 --- a/ibm/resource_ibm_cis_firewall_rules_test.go +++ b/ibm/service/cis/resource_ibm_cis_firewall_rules_test.go @@ -1,19 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCisFirewallrules_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckCisFirewallrules_basic(), @@ -26,7 +27,7 @@ func TestAccIBMCisFirewallrules_Basic(t *testing.T) { }) } func testAccCheckCisFirewallrules_basic() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_filter" "test" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.domain_id @@ -42,5 +43,5 @@ func testAccCheckCisFirewallrules_basic() string { action = "allow" priority = 5 } -`) +` } diff --git a/ibm/resource_ibm_cis_firewall_test.go b/ibm/service/cis/resource_ibm_cis_firewall_test.go similarity index 80% rename from ibm/resource_ibm_cis_firewall_test.go rename to ibm/service/cis/resource_ibm_cis_firewall_test.go index 8b6f56035..65325719a 100644 --- a/ibm/resource_ibm_cis_firewall_test.go +++ b/ibm/service/cis/resource_ibm_cis_firewall_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "log" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,7 +23,7 @@ func TestAccIBMCisFirewall_Basic(t *testing.T) { name := "ibm_cis_firewall.lockdowns" resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisFirewallDestroy, Steps: []resource.TestStep{ { @@ -52,7 +56,7 @@ func TestAccIBMCisFirewallAccessRuleBasic(t *testing.T) { name := "ibm_cis_firewall.access_rules" resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisFirewallDestroy, Steps: []resource.TestStep{ { @@ -85,7 +89,7 @@ func TestAccIBMCisFirewallUARuleBasic(t *testing.T) { name := "ibm_cis_firewall.ua_rules" resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCisFirewallDestroy, Steps: []resource.TestStep{ { @@ -116,8 +120,8 @@ func TestAccIBMCisFirewallLockdown_Import(t *testing.T) { name := "ibm_cis_firewall.lockdowns" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallLockdownBasic(), @@ -141,8 +145,8 @@ func TestAccIBMCisFirewallAccessRule_Import(t *testing.T) { name := "ibm_cis_firewall.access_rules" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallAccessRuleBasic(), @@ -166,8 +170,8 @@ func TestAccIBMCisFirewallUARule_Import(t *testing.T) { name := "ibm_cis_firewall.ua_rules" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCisFirewallUARuleBasic(), @@ -192,10 +196,10 @@ func testAccCheckIBMCisFirewallDestroy(s *terraform.State) error { if rs.Type != "ibm_cis_firewall" { continue } - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(rs.Primary.ID) - if firewallType == cisFirewallTypeLockdowns { + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(rs.Primary.ID) + if firewallType == "lockdowns" { // Firewall Type : Lockdowns - cisClient, err := testAccProvider.Meta().(ClientSession).CisLockdownClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -209,10 +213,10 @@ func testAccCheckIBMCisFirewallDestroy(s *terraform.State) error { return fmt.Errorf("%s type rule still exists", firewallType) } - } else if firewallType == cisFirewallTypeAccessRules { + } else if firewallType == "access_rules" { // Firewall Type : Zone Access firewall rules - cisClient, err := testAccProvider.Meta().(ClientSession).CisAccessRuleClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -225,9 +229,9 @@ func testAccCheckIBMCisFirewallDestroy(s *terraform.State) error { return fmt.Errorf("%s type rule still exists", firewallType) } - } else if firewallType == cisFirewallTypeUARules { + } else if firewallType == "ua_rules" { // Firewall Type: User Agent access rules - cisClient, err := testAccProvider.Meta().(ClientSession).CisUARuleClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -250,18 +254,18 @@ func testAccCheckIBMCisFirewallExists(n string, tfRecordID *string) resource.Tes return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } tfRecord := *tfRecordID - firewallType, lockdownID, zoneID, crn, _ := convertTfToCisFourVar(rs.Primary.ID) - if firewallType == cisFirewallTypeLockdowns { + firewallType, lockdownID, zoneID, crn, _ := flex.ConvertTfToCisFourVar(rs.Primary.ID) + if firewallType == "lockdown" { // Firewall Type : Lockdowns - cisClient, err := testAccProvider.Meta().(ClientSession).CisLockdownClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisLockdownClientSession() if err != nil { return err } @@ -276,11 +280,11 @@ func testAccCheckIBMCisFirewallExists(n string, tfRecordID *string) resource.Tes log.Printf("Get zone firewall lockdown failed: %v", response) return err } - tfRecord = convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) - } else if firewallType == cisFirewallTypeAccessRules { + tfRecord = flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) + } else if firewallType == "access_rules" { // Firewall Type : Zone Access firewall rules - cisClient, err := testAccProvider.Meta().(ClientSession).CisAccessRuleClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisAccessRuleClientSession() if err != nil { return err } @@ -294,10 +298,10 @@ func testAccCheckIBMCisFirewallExists(n string, tfRecordID *string) resource.Tes log.Printf("Get zone firewall lockdown failed: %v", response) return err } - tfRecord = convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) - } else if firewallType == cisFirewallTypeUARules { + tfRecord = flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) + } else if firewallType == "ua_rules" { // Firewall Type: User Agent access rules - cisClient, err := testAccProvider.Meta().(ClientSession).CisUARuleClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisUARuleClientSession() if err != nil { return err } @@ -310,21 +314,21 @@ func testAccCheckIBMCisFirewallExists(n string, tfRecordID *string) resource.Tes log.Printf("Get zone user agent rule failed: %v", response) return err } - tfRecord = convertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) + tfRecord = flex.ConvertCisToTfFourVar(firewallType, *result.Result.ID, zoneID, crn) } if rs.Primary.ID != tfRecord { return fmt.Errorf("Firewall lockdown not found") } - // tfRecord = convertCisToTfFourVar(firewallType, foundRecord.ID, zoneID, cisID) + // tfRecord = flex.ConvertCisToTfFourVar(firewallType, foundRecord.ID, zoneID, cisID) *tfRecordID = tfRecord return nil } } func testAccCheckIBMCisFirewallLockdownBasic() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "lockdowns" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -337,11 +341,11 @@ func testAccCheckIBMCisFirewallLockdownBasic() string { value = "127.0.0.1" } } - }`) + }` } func testAccCheckIBMCisFirewallLockdownUpdate() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "lockdowns" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -354,11 +358,11 @@ func testAccCheckIBMCisFirewallLockdownUpdate() string { value = "127.0.0.3" } } - }`) + }` } func testAccCheckIBMCisFirewallAccessRuleBasic() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "access_rules" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -371,11 +375,11 @@ func testAccCheckIBMCisFirewallAccessRuleBasic() string { value = "192.168.1.3" } } - }`) + }` } func testAccCheckIBMCisFirewallAccessRuleUpdate() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "access_rules" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -388,11 +392,11 @@ func testAccCheckIBMCisFirewallAccessRuleUpdate() string { value = "192.168.1.3" } } - }`) + }` } func testAccCheckIBMCisFirewallUARuleBasic() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "ua_rules" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -404,11 +408,11 @@ func testAccCheckIBMCisFirewallUARuleBasic() string { value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4" } } - }`) + }` } func testAccCheckIBMCisFirewallUARuleUpdate() string { - return testAccCheckIBMCisDomainDataSourceConfigBasic1() + fmt.Sprintf(` + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` resource "ibm_cis_firewall" "ua_rules" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -420,5 +424,5 @@ func testAccCheckIBMCisFirewallUARuleUpdate() string { value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4" } } - }`) + }` } diff --git a/ibm/resource_ibm_cis_global_load_balancer.go b/ibm/service/cis/resource_ibm_cis_global_load_balancer.go similarity index 79% rename from ibm/resource_ibm_cis_global_load_balancer.go rename to ibm/service/cis/resource_ibm_cis_global_load_balancer.go index f46f5a38b..1f38ed1e3 100644 --- a/ibm/resource_ibm_cis_global_load_balancer.go +++ b/ibm/service/cis/resource_ibm_cis_global_load_balancer.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -32,13 +35,15 @@ const ( cisGLBModifiedOn = "modified_on" ) -func resourceIBMCISGlb() *schema.Resource { +func ResourceIBMCISGlb() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ cisID: { Type: schema.TypeString, Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_global_load_balancer", + "cis_id"), }, cisDomainID: { Type: schema.TypeString, @@ -85,7 +90,7 @@ func resourceIBMCISGlb() *schema.Resource { cisGLBSteeringPolicy: { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"off", "geo", "random", "dynamic_latency"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"off", "geo", "random", "dynamic_latency"}), Description: "Steering policy info", }, cisGLBProxied: { @@ -100,7 +105,7 @@ func resourceIBMCISGlb() *schema.Resource { Optional: true, Default: "none", // Set to cookie when proxy=true - ValidateFunc: validateAllowedStringValue([]string{"none", "cookie"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"none", "cookie"}), Description: "Session affinity info", }, cisGLBEnabled: { @@ -166,26 +171,41 @@ func resourceIBMCISGlb() *schema.Resource { Create: resourceCISGlbCreate, Read: resourceCISGlbRead, Update: resourceCISGlbUpdate, + Exists: resourceCISGlbExists, Delete: resourceCISGlbDelete, Importer: &schema.ResourceImporter{}, } } - +func ResourceIBMCISGlbValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISGlbValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_global_load_balancer", + Schema: validateSchema} + return &ibmCISGlbValidator +} func resourceCISGlbCreate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return err } crn := d.Get(cisID).(string) - zoneID, _, err := convertTftoCisTwoVar(d.Get(cisDomainID).(string)) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) cisClient.Crn = core.StringPtr(crn) cisClient.ZoneIdentifier = core.StringPtr(zoneID) - tfDefaultPoolIds := expandStringList(d.Get(cisGLBDefaultPoolIDs).(*schema.Set).List()) - defaultPoolIds, _, err := convertTfToCisTwoVarSlice(tfDefaultPoolIds) + tfDefaultPoolIds := flex.ExpandStringList(d.Get(cisGLBDefaultPoolIDs).(*schema.Set).List()) + defaultPoolIds, _, _ := flex.ConvertTfToCisTwoVarSlice(tfDefaultPoolIds) fbPoolID := d.Get(cisGLBFallbackPoolID).(string) - fallbackPool, _, err := convertTftoCisTwoVar(fbPoolID) + fallbackPool, _, _ := flex.ConvertTftoCisTwoVar(fbPoolID) opt := cisClient.NewCreateLoadBalancerOptions() opt.SetName(d.Get(cisGLBName).(string)) @@ -221,18 +241,18 @@ func resourceCISGlbCreate(d *schema.ResourceData, meta interface{}) error { log.Printf("Create GLB failed %s\n", resp) return err } - d.SetId(convertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) + d.SetId(flex.ConvertCisToTfThreeVar(*result.Result.ID, zoneID, crn)) return resourceCISGlbUpdate(d, meta) } func resourceCISGlbRead(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return err } // Extract CIS Ids from TF Id - glbID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) if err != nil { return err } @@ -252,9 +272,9 @@ func resourceCISGlbRead(d *schema.ResourceData, meta interface{}) error { d.Set(cisDomainID, zoneID) d.Set(cisGLBID, glbObj.ID) d.Set(cisGLBName, glbObj.Name) - d.Set(cisGLBDefaultPoolIDs, convertCisToTfTwoVarSlice(glbObj.DefaultPools, crn)) + d.Set(cisGLBDefaultPoolIDs, flex.ConvertCisToTfTwoVarSlice(glbObj.DefaultPools, crn)) d.Set(cisGLBDesc, glbObj.Description) - d.Set(cisGLBFallbackPoolID, convertCisToTfTwoVar(*glbObj.FallbackPool, crn)) + d.Set(cisGLBFallbackPoolID, flex.ConvertCisToTfTwoVar(*glbObj.FallbackPool, crn)) d.Set(cisGLBTTL, glbObj.TTL) d.Set(cisGLBSessionAffinity, glbObj.SessionAffinity) d.Set(cisGLBProxied, glbObj.Proxied) @@ -271,12 +291,12 @@ func resourceCISGlbRead(d *schema.ResourceData, meta interface{}) error { } func resourceCISGlbUpdate(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return err } // Extract CIS Ids from TF Id - glbID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) if err != nil { return err } @@ -289,10 +309,10 @@ func resourceCISGlbUpdate(d *schema.ResourceData, meta interface{}) error { d.HasChange(cisGLBTTL) || d.HasChange(cisGLBEnabled) || d.HasChange(cisGLBPopPools) || d.HasChange(cisGLBRegionPools) || d.HasChange(cisGLBSteeringPolicy) { - tfDefaultPools := expandStringList(d.Get(cisGLBDefaultPoolIDs).(*schema.Set).List()) - defaultPoolIds, _, err := convertTfToCisTwoVarSlice(tfDefaultPools) + tfDefaultPools := flex.ExpandStringList(d.Get(cisGLBDefaultPoolIDs).(*schema.Set).List()) + defaultPoolIds, _, _ := flex.ConvertTfToCisTwoVarSlice(tfDefaultPools) fbPoolID := d.Get(cisGLBFallbackPoolID).(string) - fallbackPool, _, _ := convertTftoCisTwoVar(fbPoolID) + fallbackPool, _, _ := flex.ConvertTftoCisTwoVar(fbPoolID) opt := cisClient.NewEditLoadBalancerOptions(glbID) opt.SetName(d.Get(cisGLBName).(string)) @@ -339,12 +359,12 @@ func resourceCISGlbUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceCISGlbDelete(d *schema.ResourceData, meta interface{}) error { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return err } // Extract CIS Ids from TF Id - glbID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) if err != nil { return err } @@ -362,12 +382,12 @@ func resourceCISGlbDelete(d *schema.ResourceData, meta interface{}) error { } func resourceCISGlbExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cisClient, err := meta.(ClientSession).CisGLBClientSession() + cisClient, err := meta.(conns.ClientSession).CisGLBClientSession() if err != nil { return false, err } // Extract CIS Ids from TF Id - glbID, zoneID, crn, err := convertTfToCisThreeVar(d.Id()) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) if err != nil { return false, err } @@ -394,8 +414,8 @@ func expandGeoPools(pool interface{}, geoType string) (map[string][]string, erro locationConfig := v.(map[string]interface{}) location := locationConfig[geoType].(string) if _, p := expandPool[location]; !p { - geoPools := expandStringList(locationConfig[cisGLBRegionPoolsPoolIDs].([]interface{})) - expandPool[location], _, _ = convertTfToCisTwoVarSlice(geoPools) + geoPools := flex.ExpandStringList(locationConfig[cisGLBRegionPoolsPoolIDs].([]interface{})) + expandPool[location], _, _ = flex.ConvertTfToCisTwoVarSlice(geoPools) } else { return nil, fmt.Errorf("duplicate entry specified for %s pool in location %q. "+ "each location must only be specified once", geoType, location) @@ -407,7 +427,7 @@ func expandGeoPools(pool interface{}, geoType string) (map[string][]string, erro func flattenPools(pools interface{}, geoType string, cisID string) []interface{} { result := make([]interface{}, 0) for k, v := range pools.(map[string]interface{}) { - poolIds := convertCisToTfTwoVarSlice(expandStringList(v.([]interface{})), cisID) + poolIds := flex.ConvertCisToTfTwoVarSlice(flex.ExpandStringList(v.([]interface{})), cisID) pool := map[string]interface{}{ geoType: k, cisGLBPopPoolsPoolIDs: poolIds, diff --git a/ibm/resource_ibm_cis_global_load_balancer_test.go b/ibm/service/cis/resource_ibm_cis_global_load_balancer_test.go similarity index 76% rename from ibm/resource_ibm_cis_global_load_balancer_test.go rename to ibm/service/cis/resource_ibm_cis_global_load_balancer_test.go index b2714d0d8..7e8d312c3 100644 --- a/ibm/resource_ibm_cis_global_load_balancer_test.go +++ b/ibm/service/cis/resource_ibm_cis_global_load_balancer_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis_test import ( "fmt" "log" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,12 +25,12 @@ func TestAccIBMCisGlb_Basic(t *testing.T) { name := "ibm_cis_global_load_balancer." + "test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCis(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckCisGlbDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckCisGlbConfigCisDSBasic("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigCisDSBasic("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckCisGlbExists(name, &glb), // dont check that specified values are set, this will be evident by lack of plan diff @@ -38,7 +42,7 @@ func TestAccIBMCisGlb_Basic(t *testing.T) { ), }, { - Config: testAccCheckCisGlbConfigCisDSUpdate("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigCisDSUpdate("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckCisGlbExists(name, &glb), // dont check that specified values are set, this will be evident by lack of plan diff @@ -60,12 +64,12 @@ func TestAccIBMCisGlb_CreateAfterManualDestroy(t *testing.T) { name := "ibm_cis_global_load_balancer." + "test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckCisGlbDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckCisGlbConfigCisDSBasic("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigCisDSBasic("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckCisGlbExists(name, &glbOne), testAccCisGlbManuallyDelete(&glbOne), @@ -73,7 +77,7 @@ func TestAccIBMCisGlb_CreateAfterManualDestroy(t *testing.T) { ExpectNonEmptyPlan: true, }, { - Config: testAccCheckCisGlbConfigCisDSBasic("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigCisDSBasic("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckCisGlbExists(name, &glbTwo), func(state *terraform.State) error { @@ -93,11 +97,11 @@ func TestAccIBMCisGlb_import(t *testing.T) { name := "ibm_cis_global_load_balancer.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckCisGlbConfigCisDSBasic("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigCisDSBasic("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "proxied", "false"), // default value ), @@ -117,11 +121,11 @@ func TestAccIBMCisGlb_SessionAffinity(t *testing.T) { name := "ibm_cis_global_load_balancer." + "test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckCisGlbConfigSessionAffinity("test", cisDomainStatic), + Config: testAccCheckCisGlbConfigSessionAffinity("test", acc.CisDomainStatic), Check: resource.ComposeTestCheckFunc( testAccCheckCisGlbExists(name, &glb), // explicitly verify that our session_affinity has been set @@ -133,7 +137,7 @@ func TestAccIBMCisGlb_SessionAffinity(t *testing.T) { } func testAccCheckCisGlbDestroy(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBClientSession() if err != nil { return err } @@ -141,7 +145,7 @@ func testAccCheckCisGlbDestroy(s *terraform.State) error { if rs.Type != "ibm_cis_global_load_balancer" { continue } - glbID, zoneID, crn, err := convertTfToCisThreeVar(rs.Primary.ID) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) if err != nil { return err } @@ -161,13 +165,13 @@ func testAccCheckCisGlbDestroy(s *terraform.State) error { func testAccCisGlbManuallyDelete(tfGlbID *string) resource.TestCheckFunc { return func(s *terraform.State) error { - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBClientSession() if err != nil { return err } tfGlb := *tfGlbID log.Printf("[WARN] Manually removing glb") - glbID, zoneID, crn, err := convertTfToCisThreeVar(tfGlb) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(tfGlb) if err != nil { return err } @@ -176,7 +180,7 @@ func testAccCisGlbManuallyDelete(tfGlbID *string) resource.TestCheckFunc { opt := cisClient.NewDeleteLoadBalancerOptions(glbID) _, _, err = cisClient.DeleteLoadBalancer(opt) if err != nil { - return fmt.Errorf("Error deleting IBMCISGlb Record: %s", err) + return fmt.Errorf("[ERROR] Error deleting IBMCISGlb Record: %s", err) } return nil } @@ -186,17 +190,17 @@ func testAccCheckCisGlbExists(n string, tfGlbID *string) resource.TestCheckFunc return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Load Balancer ID is set") + return fmt.Errorf("[ERROR] No Load Balancer ID is set") } - cisClient, err := testAccProvider.Meta().(ClientSession).CisGLBClientSession() + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBClientSession() if err != nil { return err } - glbID, zoneID, crn, err := convertTfToCisThreeVar(rs.Primary.ID) + glbID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(rs.Primary.ID) if err != nil { return err } @@ -209,7 +213,7 @@ func testAccCheckCisGlbExists(n string, tfGlbID *string) resource.TestCheckFunc if err != nil { return fmt.Errorf("Global Load balancer exists") } - *tfGlbID = convertCisToTfThreeVar(*result.Result.ID, zoneID, crn) + *tfGlbID = flex.ConvertCisToTfThreeVar(*result.Result.ID, zoneID, crn) return nil } } @@ -224,7 +228,7 @@ func testAccCheckCisGlbConfigCisDSBasic(id string, cisDomain string) string { default_pool_ids = [ibm_cis_origin_pool.origin_pool.id] steering_policy = "dynamic_latency" } - `, id, cisDomainStatic) + `, id, acc.CisDomainStatic) } func testAccCheckCisGlbConfigCisDSUpdate(id string, cisDomain string) string { @@ -245,11 +249,11 @@ func testAccCheckCisGlbConfigCisDSUpdate(id string, cisDomain string) string { pool_ids = [ibm_cis_origin_pool.origin_pool.id] } } - `, id, cisDomainStatic) + `, id, acc.CisDomainStatic) } -func testAccCheckCisGlbConfigSessionAffinity(id string, cisDomainStatic string) string { - return testAccCheckCisPoolConfigFullySpecified(id, cisDomainStatic) + fmt.Sprintf(` +func testAccCheckCisGlbConfigSessionAffinity(id string, CisDomainStatic string) string { + return testAccCheckCisPoolConfigFullySpecified(id, acc.CisDomainStatic) + fmt.Sprintf(` resource "ibm_cis_global_load_balancer" "%[1]s" { cis_id = data.ibm_cis.cis.id domain_id = data.ibm_cis_domain.cis_domain.id @@ -259,5 +263,5 @@ func testAccCheckCisGlbConfigSessionAffinity(id string, cisDomainStatic string) session_affinity = "cookie" steering_policy = "dynamic_latency" } - `, id, cisDomainStatic) + `, id, acc.CisDomainStatic) } diff --git a/ibm/resource_ibm_cis_healthcheck.go b/ibm/service/cis/resource_ibm_cis_healthcheck.go similarity index 81% rename from ibm/resource_ibm_cis_healthcheck.go rename to ibm/service/cis/resource_ibm_cis_healthcheck.go index 5dbebf1b6..25ac68c5c 100644 --- a/ibm/resource_ibm_cis_healthcheck.go +++ b/ibm/service/cis/resource_ibm_cis_healthcheck.go @@ -1,11 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cis import ( "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -32,7 +35,7 @@ const ( cisGLBHealthCheckHeadersValues = "values" ) -func resourceIBMCISHealthCheck() *schema.Resource { +func ResourceIBMCISHealthCheck() *schema.Resource { return &schema.Resource{ Create: resourceCISHealthCheckCreate, @@ -47,6 +50,8 @@ func resourceIBMCISHealthCheck() *schema.Resource { Type: schema.TypeString, Description: "CIS instance crn", Required: true, + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, + "cis_id"), }, cisGLBHealthCheckID: { Type: schema.TypeString, @@ -58,7 +63,7 @@ func resourceIBMCISHealthCheck() *schema.Resource { Description: "path", Optional: true, Default: "/", - ValidateFunc: validateURLPath, + ValidateFunc: validate.ValidateURLPath, }, cisGLBHealthCheckExpectedBody: { Type: schema.TypeString, @@ -81,35 +86,35 @@ func resourceIBMCISHealthCheck() *schema.Resource { Description: "type", Optional: true, Default: "http", - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckType), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckType), }, cisGLBHealthCheckMethod: { Type: schema.TypeString, Description: "method", Optional: true, Default: "GET", - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckMethod), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckMethod), }, cisGLBHealthCheckTimeout: { Type: schema.TypeInt, Description: "timeout", Optional: true, Default: 5, - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckTimeout), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckTimeout), }, cisGLBHealthCheckRetries: { Type: schema.TypeInt, Description: "retries", Optional: true, Default: 2, - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckRetries), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckRetries), }, cisGLBHealthCheckInterval: { Type: schema.TypeInt, Description: "interval", Optional: true, Default: 60, - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckInterval), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckInterval), }, cisGLBHealthCheckFollowRedirects: { Type: schema.TypeBool, @@ -136,7 +141,7 @@ func resourceIBMCISHealthCheck() *schema.Resource { Description: "port number", Computed: true, Optional: true, - ValidateFunc: InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckPort), + ValidateFunc: validate.InvokeValidator(ibmCISHealthCheck, cisGLBHealthCheckPort), }, cisGLBHealthCheckHeaders: { Type: schema.TypeSet, @@ -163,63 +168,71 @@ func resourceIBMCISHealthCheck() *schema.Resource { } } -func resourceIBMCISHealthCheckValidator() *ResourceValidator { +func ResourceIBMCISHealthCheckValidator() *validate.ResourceValidator { healthCheckTypes := "http, https, tcp" methods := "GET, HEAD" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ Identifier: cisGLBHealthCheckType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: healthCheckTypes}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisGLBHealthCheckMethod, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: methods}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisGLBHealthCheckTimeout, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "1", MaxValue: "10"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisGLBHealthCheckRetries, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "1", MaxValue: "3"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisGLBHealthCheckInterval, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "5", MaxValue: "3600"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: cisGLBHealthCheckPort, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "1", MaxValue: "65535"}) - cisHealthCheckValidator := ResourceValidator{ResourceName: ibmCISHealthCheck, Schema: validateSchema} + cisHealthCheckValidator := validate.ResourceValidator{ResourceName: ibmCISHealthCheck, Schema: validateSchema} return &cisHealthCheckValidator } func resourceCISHealthCheckCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return err } @@ -275,17 +288,17 @@ func resourceCISHealthCheckCreate(d *schema.ResourceData, meta interface{}) erro return err } log.Printf("global load balancer created successfully : %s", *result.Result.ID) - d.SetId(convertCisToTfTwoVar(*result.Result.ID, crn)) + d.SetId(flex.ConvertCisToTfTwoVar(*result.Result.ID, crn)) return resourceCISHealthCheckRead(d, meta) } func resourceCISHealthCheckRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return err } - monitorID, crn, err := convertTftoCisTwoVar(d.Id()) + monitorID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) if err != nil { return err } @@ -322,12 +335,12 @@ func resourceCISHealthCheckRead(d *schema.ResourceData, meta interface{}) error } func resourceCISHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return err } - monitorID, crn, err := convertTftoCisTwoVar(d.Id()) + monitorID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) if err != nil { return err } @@ -398,12 +411,12 @@ func resourceCISHealthCheckUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceCISHealthCheckDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return err } - monitorID, crn, err := convertTftoCisTwoVar(d.Id()) + monitorID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) if err != nil { return err } @@ -421,12 +434,12 @@ func resourceCISHealthCheckDelete(d *schema.ResourceData, meta interface{}) erro } func resourceCISHealthCheckExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).CisGLBHealthCheckClientSession() + sess, err := meta.(conns.ClientSession).CisGLBHealthCheckClientSession() if err != nil { return false, err } - monitorID, crn, err := convertTftoCisTwoVar(d.Id()) + monitorID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) if err != nil { return false, err } @@ -460,7 +473,7 @@ func expandLoadBalancerMonitorHeader(cfgSet interface{}) map[string][]string { for _, item := range cfgList { cfg := item.(map[string]interface{}) header[cfg[cisGLBHealthCheckHeadersHeader].(string)] = - expandStringList(cfg[cisGLBHealthCheckHeadersValues].(*schema.Set).List()) + flex.ExpandStringList(cfg[cisGLBHealthCheckHeadersValues].(*schema.Set).List()) } return header } @@ -470,7 +483,7 @@ func flattenLoadBalancerMonitorHeader(header map[string][]string) *schema.Set { for k, v := range header { cfg := map[string]interface{}{ cisGLBHealthCheckHeadersHeader: k, - cisGLBHealthCheckHeadersValues: schema.NewSet(schema.HashString, flattenStringList(v)), + cisGLBHealthCheckHeadersValues: schema.NewSet(schema.HashString, flex.FlattenStringList(v)), } flattened = append(flattened, cfg) } diff --git a/ibm/service/cis/resource_ibm_cis_healthcheck_test.go b/ibm/service/cis/resource_ibm_cis_healthcheck_test.go new file mode 100644 index 000000000..8f534d0d7 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_healthcheck_test.go @@ -0,0 +1,217 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMCisHealthcheck_Basic(t *testing.T) { + var monitor string + name := "ibm_cis_healthcheck.health_check" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + // No requirement for CheckDestory of this resource as by reaching this point it must have already been deleted from CIS. + Steps: []resource.TestStep{ + { + Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisHealthcheckExists(name, &monitor), + resource.TestCheckResourceAttr(name, "expected_body", "alive"), + ), + }, + }, + }) +} + +func TestAccIBMCisHealthcheck_import(t *testing.T) { + name := "ibm_cis_healthcheck.health_check" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckCisMonitorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "expected_body", "alive"), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes"}, + }, + }, + }) +} + +func TestAccIBMCisHealthcheck_FullySpecified(t *testing.T) { + var monitor string + name := "ibm_cis_healthcheck.health_check" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckCisMonitorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisHealthcheckConfigFullySpecified("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisHealthcheckExists(name, &monitor), + resource.TestCheckResourceAttr(name, "path", "/custom"), + resource.TestCheckResourceAttr(name, "retries", "3"), + resource.TestCheckResourceAttr(name, "expected_codes", "5xx"), + ), + }, + }, + }) +} + +func TestAccIBMCisHealthcheck_CreateAfterManualDestroy(t *testing.T) { + var monitorOne, monitorTwo string + name := "ibm_cis_healthcheck.health_check" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckCisMonitorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisHealthcheckExists(name, &monitorOne), + testAccCisMonitorManuallyDelete(&monitorOne), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccCheckCisHealthcheckConfigCisDSBasic("test", acc.CisDomainStatic), + Check: resource.ComposeTestCheckFunc( + testAccCheckCisHealthcheckExists(name, &monitorTwo), + func(state *terraform.State) error { + if monitorOne == monitorTwo { + return fmt.Errorf("load balancer monitor id is unchanged even after we thought we deleted it ( %s )", + monitorTwo) + } + return nil + }, + ), + }, + }, + }) +} + +func testAccCisMonitorManuallyDelete(tfMonitorID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBHealthCheckClientSession() + if err != nil { + return err + } + tfMonitor := *tfMonitorID + healthcheckID, cisID, _ := flex.ConvertTftoCisTwoVar(tfMonitor) + cisClient.Crn = core.StringPtr(cisID) + opt := cisClient.NewDeleteLoadBalancerMonitorOptions(healthcheckID) + _, _, err = cisClient.DeleteLoadBalancerMonitor(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting IBMCISMonitor Record: %s", err) + } + return nil + } +} + +func testAccCheckCisMonitorDestroy(s *terraform.State) error { + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBHealthCheckClientSession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cis_healthcheck" { + continue + } + healthcheckID, cisID, _ := flex.ConvertTftoCisTwoVar(rs.Primary.ID) + cisClient.Crn = core.StringPtr(cisID) + opt := cisClient.NewGetLoadBalancerMonitorOptions(healthcheckID) + _, _, err = cisClient.GetLoadBalancerMonitor(opt) + if err == nil { + return fmt.Errorf("Load balancer Monitor still exists") + } + } + + return nil +} + +func testAccCheckCisHealthcheckExists(n string, tfMonitorID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("[ERROR] Not found: %s", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No Load Balancer Monitor ID is set") + } + + cisClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CisGLBHealthCheckClientSession() + if err != nil { + return err + } + healthcheckID, cisID, _ := flex.ConvertTftoCisTwoVar(rs.Primary.ID) + cisClient.Crn = core.StringPtr(cisID) + opt := cisClient.NewGetLoadBalancerMonitorOptions(healthcheckID) + foundHealthcheck, _, err := cisClient.GetLoadBalancerMonitor(opt) + if err != nil { + return fmt.Errorf("Load balancer Monitor still exists") + } + *tfMonitorID = flex.ConvertCisToTfTwoVar(*foundHealthcheck.Result.ID, cisID) + return nil + } +} + +func testAccCheckCisHealthcheckConfigCisDSBasic(resourceID string, cisDomain string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` + resource "ibm_cis_healthcheck" "health_check" { + cis_id = data.ibm_cis.cis.id + expected_body = "alive" + expected_codes = "2xx" + } + ` +} + +func testAccCheckCisHealthcheckConfigFullySpecified(resourceID string, cisDomain string) string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` + resource "ibm_cis_healthcheck" "health_check" { + cis_id = data.ibm_cis.cis.id + expected_body = "dead" + expected_codes = "5xx" + method = "HEAD" + timeout = 9 + path = "/custom" + interval = 60 + retries = 3 + description = "this is a very weird load balancer" + headers { + header = "Host" + values = ["example.com", "example1.com"] + } + headers { + header = "Host1" + values = ["example3.com", "example11.com"] + } + } + ` +} diff --git a/ibm/service/cis/resource_ibm_cis_logpush_job.go b/ibm/service/cis/resource_ibm_cis_logpush_job.go new file mode 100644 index 000000000..8ccdccc1c --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_logpush_job.go @@ -0,0 +1,281 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis + +import ( + "encoding/json" + "fmt" + "log" + "strconv" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/networking-go-sdk/logpushjobsapiv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + cisLogpushJobID = "job_id" + cisLogpushName = "name" + cisLogpushEnabled = "enabled" + cisLogpullOpt = "logpull_options" + cisLogdna = "logdna" + cisLogpushDataset = "dataset" + cisLogpushFreq = "frequency" + cisLogpushDestConf = "destination_conf" +) + +func ResourceIBMCISLogPushJob() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMCISLogpushJobCreate, + Read: ResourceIBMCISLogpushJobRead, + Update: ResourceIBMCISLogpushJobUpdate, + Delete: ResourceIBMCISLogpushJobDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + cisID: { + Type: schema.TypeString, + Description: "CIS instance crn", + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cis_logpush_job", + "cis_id"), + }, + cisDomainID: { + Type: schema.TypeString, + Description: "Associated CIS domain", + Required: true, + DiffSuppressFunc: suppressDomainIDDiff, + }, + cisLogdna: { + Type: schema.TypeString, + Required: true, + Sensitive: true, + StateFunc: func(v interface{}) string { + json, err := flex.NormalizeJSONString(v) + if err != nil { + return fmt.Sprintf("%q", err.Error()) + } + return json + }, + Description: "Information to identify the LogDNA instance the data will be pushed.", + }, + cisLogpushName: { + Type: schema.TypeString, + Optional: true, + Description: "Logpush Job Name", + }, + cisLogpushEnabled: { + Type: schema.TypeBool, + Optional: true, + Description: "Whether the logpush job enabled or not", + }, + cisLogpullOpt: { + Type: schema.TypeString, + Optional: true, + Description: "Configuration string", + }, + cisLogpushDataset: { + Type: schema.TypeString, + Required: true, + Description: "Dataset to be pulled", + }, + cisLogpushFreq: { + Type: schema.TypeString, + Optional: true, + Description: "The frequency at which CIS sends batches of logs to your destination", + }, + cisLogpushJobID: { + Type: schema.TypeInt, + Description: "Associated CIS domain", + Computed: true, + }, + cisLogpushDestConf: { + Type: schema.TypeString, + Computed: true, + Description: "Uniquely identifies a resource (such as an s3 bucket) where data will be pushed.", + }, + }, + } +} +func ResourceIBMCISLogPushJobValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cis_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:internet-svcs"}, + Required: true}) + ibmCISLogPushValidator := validate.ResourceValidator{ + ResourceName: "ibm_cis_logpush_job", + Schema: validateSchema} + return &ibmCISLogPushValidator +} + +func ResourceIBMCISLogpushJobCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisLogpushJobsSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + sess.Crn = core.StringPtr(crn) + sess.ZoneID = core.StringPtr(zoneID) + + logpushJob := &logpushjobsapiv1.CreateLogpushJobV2RequestLogpushJobLogdnaReq{} + + if a, ok := d.GetOk(cisLogpushName); ok { + name := a.(string) + logpushJob.Name = &name + } + if e, ok := d.GetOk(cisLogpushEnabled); ok { + enabled := e.(bool) + logpushJob.Enabled = &enabled + } + if lp, ok := d.GetOk(cisLogpullOpt); ok { + logpullopt := lp.(string) + logpushJob.LogpullOptions = &logpullopt + } + if log, ok := d.GetOk(cisLogdna); ok { + var logDNA interface{} + json.Unmarshal([]byte(log.(string)), &logDNA) + logpushJob.Logdna = logDNA + } + if d, ok := d.GetOk(cisLogpushDataset); ok { + dataset := d.(string) + logpushJob.Dataset = &dataset + } + if f, ok := d.GetOk(cisLogpushFreq); ok { + freq := f.(string) + logpushJob.Frequency = &freq + } + options := &logpushjobsapiv1.CreateLogpushJobV2Options{ + CreateLogpushJobV2Request: logpushJob, + } + result, response, err := sess.CreateLogpushJobV2(options) + if err != nil { + log.Printf("[DEBUG] Instance err %s\n%s", err, response) + return err + } + JobID := strconv.Itoa(int(*result.Result.ID)) + + d.SetId(flex.ConvertCisToTfThreeVar(JobID, zoneID, crn)) + return ResourceIBMCISLogpushJobRead(d, meta) +} + +func ResourceIBMCISLogpushJobRead(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisLogpushJobsSession() + if err != nil { + return err + } + logpushID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Error Converting ConvertTfToCisThreeVar in Read") + } + JobID, _ := strconv.Atoi(logpushID) + sess.Crn = core.StringPtr(crn) + sess.ZoneID = core.StringPtr(zoneID) + + opt := sess.NewGetLogpushJobV2Options(int64(JobID)) + result, response, err := sess.GetLogpushJobV2(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error While Reading the Logpushjobs for LogDNA %s:%s", err, response) + } + d.Set(cisID, crn) + d.Set(cisDomainID, zoneID) + d.Set(cisLogpushJobID, int64(*result.Result.ID)) + d.Set(cisLogpushName, *result.Result.Name) + d.Set(cisLogpushEnabled, *result.Result.Enabled) + d.Set(cisLogpushDataset, *result.Result.Dataset) + d.Set(cisLogpushFreq, *result.Result.Frequency) + d.Set(cisLogpullOpt, *result.Result.LogpullOptions) + d.Set(cisLogpushDestConf, *result.Result.DestinationConf) + return nil +} +func ResourceIBMCISLogpushJobUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisLogpushJobsSession() + if err != nil { + return err + } + + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + sess.Crn = core.StringPtr(crn) + sess.ZoneID = core.StringPtr(zoneID) + + logpushID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + JobId, _ := strconv.Atoi(logpushID) + + if err != nil { + return fmt.Errorf("[ERROR] Error Converting ConvertTfToCisThreeVar in Update") + } + if d.HasChange(cisLogpushEnabled) || + d.HasChange(cisLogpullOpt) || + d.HasChange(cisLogdna) || + d.HasChange(cisLogpushFreq) { + + updateLogpushJob := &logpushjobsapiv1.UpdateLogpushJobV2RequestLogpushJobsUpdateLogdnaReq{} + + if e, ok := d.GetOk(cisLogpushEnabled); ok { + enabled := e.(bool) + updateLogpushJob.Enabled = &enabled + } + if lp, ok := d.GetOk(cisLogpullOpt); ok { + logpullopt := lp.(string) + updateLogpushJob.LogpullOptions = &logpullopt + } + if log, ok := d.GetOk(cisLogdna); ok { + var logDNA interface{} + json.Unmarshal([]byte(log.(string)), &logDNA) + updateLogpushJob.Logdna = logDNA + } + if f, ok := d.GetOk(cisLogpushFreq); ok { + freq := f.(string) + updateLogpushJob.Frequency = &freq + } + options := &logpushjobsapiv1.UpdateLogpushJobV2Options{ + JobID: core.Int64Ptr(int64(JobId)), + UpdateLogpushJobV2Request: updateLogpushJob, + } + result, resp, err := sess.UpdateLogpushJobV2(options) + if err != nil || result == nil { + return fmt.Errorf("[ERROR] Error While Updating the Logpushjobs for LogDNA %v, %v", err, resp) + } + } + return ResourceIBMCISLogpushJobRead(d, meta) +} +func ResourceIBMCISLogpushJobDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := meta.(conns.ClientSession).CisLogpushJobsSession() + if err != nil { + return err + } + crn := d.Get(cisID).(string) + zoneID, _, _ := flex.ConvertTftoCisTwoVar(d.Get(cisDomainID).(string)) + sess.Crn = core.StringPtr(crn) + sess.ZoneID = core.StringPtr(zoneID) + + logpushID, zoneID, crn, _ := flex.ConvertTfToCisThreeVar(d.Id()) + JobID, _ := strconv.Atoi(logpushID) + if err != nil { + return fmt.Errorf("[ERROR] Error Converting ConvertTfToCisThreeVar in Delete") + } + opt := sess.NewDeleteLogpushJobV2Options(int64(JobID)) + _, response, err := sess.DeleteLogpushJobV2(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error While Deleting the Logpushjob for LogDNA %s:%s", err, response) + } + d.SetId("") + return nil +} diff --git a/ibm/service/cis/resource_ibm_cis_logpush_job_test.go b/ibm/service/cis/resource_ibm_cis_logpush_job_test.go new file mode 100644 index 000000000..7df99e2d4 --- /dev/null +++ b/ibm/service/cis/resource_ibm_cis_logpush_job_test.go @@ -0,0 +1,57 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cis_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCisLogpushJobs_Basic(t *testing.T) { + + name := "MylogpushJob" + logpull_opt := "timestamps=rfc3339×tamps=rfc3339" + data_set := "http_requests" + freq := "low" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckCis(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckCisLogpushJobs_basic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cis_logpush_job.test", "name", name), + resource.TestCheckResourceAttr("ibm_cis_logpush_job.test", "enabled", "false"), + resource.TestCheckResourceAttr("ibm_cis_logpush_job.test", "logpull_options", logpull_opt), + resource.TestCheckResourceAttr("ibm_cis_logpush_job.test", "dataset", data_set), + resource.TestCheckResourceAttr("ibm_cis_logpush_job.test", "frequency", freq), + resource.TestCheckResourceAttrSet("ibm_cis_logpush_job.test", "logdna"), + ), + }, + }, + }) +} +func testAccCheckCisLogpushJobs_basic() string { + return testAccCheckIBMCisDomainDataSourceConfigBasic1() + ` + resource "ibm_cis_logpush_job" "test" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + name = "MylogpushJob" + enabled = false + logpull_options = "timestamps=rfc3339×tamps=rfc3339" + dataset = "http_requests" + frequency = "low" + logdna =< 2 && bm.PrimaryBackendNetworkComponent != nil { @@ -397,8 +398,8 @@ func dataSourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) storages := bm.AllowedNetworkStorage if len(storages) > 0 { - d.Set("block_storage_ids", flattenBlockStorageID(storages)) - d.Set("file_storage_ids", flattenFileStorageID(storages)) + d.Set("block_storage_ids", flex.FlattenBlockStorageID(storages)) + d.Set("file_storage_ids", flex.FlattenFileStorageID(storages)) } connInfo := map[string]string{"type": "ssh"} diff --git a/ibm/data_source_ibm_compute_bare_metal_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_bare_metal_test.go similarity index 94% rename from ibm/data_source_ibm_compute_bare_metal_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_bare_metal_test.go index 74cafb8e2..aa3d8edb6 100644 --- a/ibm/data_source_ibm_compute_bare_metal_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_bare_metal_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMComputeBareMetalDataSource_basic(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeBareMetalDataSourceConfigBasic(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/data_source_ibm_compute_image_template.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_image_template.go similarity index 78% rename from ibm/data_source_ibm_compute_image_template.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_image_template.go index ae5d3893b..6dde751f2 100644 --- a/ibm/data_source_ibm_compute_image_template.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_image_template.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMComputeImageTemplate() *schema.Resource { +func DataSourceIBMComputeImageTemplate() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMComputeImageTemplateRead, @@ -34,7 +35,7 @@ func dataSourceIBMComputeImageTemplate() *schema.Resource { } func dataSourceIBMComputeImageTemplateRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("name").(string) @@ -43,7 +44,7 @@ func dataSourceIBMComputeImageTemplateRead(d *schema.ResourceData, meta interfac Mask("id,name"). GetBlockDeviceTemplateGroups() if err != nil { - return fmt.Errorf("Error looking up image template [%s]: %s", name, err) + return fmt.Errorf("[ERROR] Error looking up image template [%s]: %s", name, err) } for _, imageTemplate := range imageTemplates { @@ -61,7 +62,7 @@ func dataSourceIBMComputeImageTemplateRead(d *schema.ResourceData, meta interfac Filter(filter.Path("name").Eq(name).Build()). GetPublicImages() if err != nil { - return fmt.Errorf("Error looking up image template [%s] among the public images: %s", name, err) + return fmt.Errorf("[ERROR] Error looking up image template [%s] among the public images: %s", name, err) } if len(pubImageTemplates) > 0 { @@ -70,5 +71,5 @@ func dataSourceIBMComputeImageTemplateRead(d *schema.ResourceData, meta interfac return nil } - return fmt.Errorf("Could not find image template with name [%s]", name) + return fmt.Errorf("[ERROR] Could not find image template with name [%s]", name) } diff --git a/ibm/data_source_ibm_compute_image_template_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_image_template_test.go similarity index 89% rename from ibm/data_source_ibm_compute_image_template_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_image_template_test.go index 089cfce2a..603c0488c 100644 --- a/ibm/data_source_ibm_compute_image_template_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_image_template_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMComputeImageTemplateDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ // Tests looking up private or shared images { diff --git a/ibm/data_source_ibm_compute_placement_group.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group.go similarity index 86% rename from ibm/data_source_ibm_compute_placement_group.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group.go index 5e96a5fb9..477f67a1f 100644 --- a/ibm/data_source_ibm_compute_placement_group.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "regexp" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMComputePlacementGroup() *schema.Resource { +func DataSourceIBMComputePlacementGroup() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMComputePlacementGroupRead, @@ -64,7 +65,7 @@ func dataSourceIBMComputePlacementGroup() *schema.Resource { } func dataSourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("name").(string) @@ -74,7 +75,7 @@ func dataSourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interfa Mask("id,name,rule[name],guests[id,domain,hostname],backendRouter[hostname,datacenter[name]]").GetPlacementGroups() if err != nil { - return fmt.Errorf("Error retrieving placement group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving placement group: %s", err) } grps := []datatypes.Virtual_PlacementGroup{} @@ -86,12 +87,10 @@ func dataSourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interfa } if len(grps) == 0 { - return fmt.Errorf("No placement group found with name [%s]", name) + return fmt.Errorf("[ERROR] No placement group found with name [%s]", name) } - var grp datatypes.Virtual_PlacementGroup - - grp = grps[0] + grp := grps[0] d.SetId(fmt.Sprintf("%d", *grp.Id)) d.Set("name", grp.Name) diff --git a/ibm/data_source_ibm_compute_placement_group_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group_test.go similarity index 89% rename from ibm/data_source_ibm_compute_placement_group_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group_test.go index e63861d31..8a1423174 100644 --- a/ibm/data_source_ibm_compute_placement_group_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_placement_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +18,11 @@ func TestAccIBMComputePlacementGroupDataSource_Basic(t *testing.T) { group1 := fmt.Sprintf("%s%s", "tfuatpgrp", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputePlacementGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupdsConfig(group1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/data_source_ibm_compute_reserved_capacity.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity.go similarity index 94% rename from ibm/data_source_ibm_compute_reserved_capacity.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity.go index 708be44a4..6010c69a2 100644 --- a/ibm/data_source_ibm_compute_reserved_capacity.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "context" @@ -10,6 +10,7 @@ import ( "sort" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -18,7 +19,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func dataSourceIBMComputeReservedCapacity() *schema.Resource { +func DataSourceIBMComputeReservedCapacity() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMComputeReservedCapacityRead, @@ -86,7 +87,7 @@ func dataSourceIBMComputeReservedCapacity() *schema.Resource { } func dataSourceIBMComputeReservedCapacityRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("name").(string) @@ -111,7 +112,7 @@ func dataSourceIBMComputeReservedCapacityRead(context context.Context, d *schema grp = mostRecentReservedCapacity(grps) } else { return diag.FromErr(fmt.Errorf( - "[Error] More than one reserved capacity found with name"+ + "[Error] More than one reserved capacity found with name "+ "matching [%s]. Set 'most_recent' to true in your configuration to force the most recent reserved capacity "+ "to be used", name)) } diff --git a/ibm/data_source_ibm_compute_reserved_capacity_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity_test.go similarity index 91% rename from ibm/data_source_ibm_compute_reserved_capacity_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity_test.go index a84698811..08ae77d55 100644 --- a/ibm/data_source_ibm_compute_reserved_capacity_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_reserved_capacity_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +18,11 @@ func TestAccIBMComputeReservedCapacityDataSource_Basic(t *testing.T) { group1 := fmt.Sprintf("%s%s", "tfuatreservedcapacity", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, //CheckDestroy: testAccCheckIBMComputeReservedCapacityDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeReservedCapacitydsConfig(group1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/data_source_ibm_compute_ssh_key.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key.go similarity index 86% rename from ibm/data_source_ibm_compute_ssh_key.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key.go index abe983723..62cb3a414 100644 --- a/ibm/data_source_ibm_compute_ssh_key.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key.go @@ -1,49 +1,50 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "sort" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMComputeSSHKey() *schema.Resource { +func DataSourceIBMComputeSSHKey() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMComputeSSHKeyRead, Schema: map[string]*schema.Schema{ - "label": &schema.Schema{ + "label": { Description: "The label associated with the ssh key", Type: schema.TypeString, Required: true, }, - "public_key": &schema.Schema{ + "public_key": { Description: "The public ssh key", Type: schema.TypeString, Computed: true, }, - "fingerprint": &schema.Schema{ + "fingerprint": { Description: "A sequence of bytes to authenticate or lookup a longer ssh key", Type: schema.TypeString, Computed: true, }, - "notes": &schema.Schema{ + "notes": { Description: "A small note about a ssh key to use at your discretion", Type: schema.TypeString, Computed: true, }, - "most_recent": &schema.Schema{ + "most_recent": { Description: "If true and multiple entries are found, the most recently created key is used. " + "If false, an error is returned", Type: schema.TypeBool, @@ -55,7 +56,7 @@ func dataSourceIBMComputeSSHKey() *schema.Resource { } func dataSourceIBMComputeSSHKeyRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) label := d.Get("label").(string) @@ -67,10 +68,10 @@ func dataSourceIBMComputeSSHKeyRead(d *schema.ResourceData, meta interface{}) er GetSshKeys() if err != nil { - return fmt.Errorf("Error retrieving SSH key: %s", err) + return fmt.Errorf("[ERROR] Error retrieving SSH key: %s", err) } if len(keys) == 0 { - return fmt.Errorf("No ssh key found with name [%s]", label) + return fmt.Errorf("[ERROR] No ssh key found with name [%s]", label) } var key datatypes.Security_Ssh_Key diff --git a/ibm/data_source_ibm_compute_ssh_key_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key_test.go similarity index 90% rename from ibm/data_source_ibm_compute_ssh_key_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key_test.go index 98f9aa007..6ca5e7fef 100644 --- a/ibm/data_source_ibm_compute_ssh_key_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_ssh_key_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,8 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -22,10 +24,10 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeSSHKeyDataSourceConfig(label, notes, publicKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_compute_ssh_key.testacc_ds_ssh_key", "public_key", publicKey), diff --git a/ibm/data_source_ibm_compute_vm_instance.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance.go similarity index 91% rename from ibm/data_source_ibm_compute_vm_instance.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance.go index 927f218e9..eab48a469 100644 --- a/ibm/data_source_ibm_compute_vm_instance.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance.go @@ -1,55 +1,56 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "sort" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMComputeVmInstance() *schema.Resource { +func DataSourceIBMComputeVmInstance() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMComputeVmInstanceRead, Schema: map[string]*schema.Schema{ - "hostname": &schema.Schema{ + "hostname": { Description: "The hostname of the virtual guest", Type: schema.TypeString, Required: true, }, - "domain": &schema.Schema{ + "domain": { Description: "The domain of the virtual guest", Type: schema.TypeString, Required: true, }, - "datacenter": &schema.Schema{ + "datacenter": { Description: "Datacenter in which the virtual guest is deployed", Type: schema.TypeString, Computed: true, }, - "cores": &schema.Schema{ + "cores": { Description: "Number of cpu cores", Type: schema.TypeInt, Computed: true, }, - "status": &schema.Schema{ + "status": { Description: "The VSI status", Type: schema.TypeString, Computed: true, }, - "last_known_power_state": &schema.Schema{ + "last_known_power_state": { Description: "The last known power state of a virtual guest in the event the guest is turned off outside of IMS or has gone offline.", Type: schema.TypeString, Computed: true, @@ -64,12 +65,12 @@ func dataSourceIBMComputeVmInstance() *schema.Resource { Computed: true, }, - "power_state": &schema.Schema{ + "power_state": { Description: "The current power state of a virtual guest.", Type: schema.TypeString, Computed: true, }, - "most_recent": &schema.Schema{ + "most_recent": { Description: "If true and multiple entries are found, the most recently created virtual guest is used. " + "If false, an error is returned", Type: schema.TypeBool, @@ -142,7 +143,7 @@ func dataSourceIBMComputeVmInstance() *schema.Resource { } func dataSourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) hostname := d.Get("hostname").(string) @@ -159,10 +160,10 @@ func dataSourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{} ).GetVirtualGuests() if err != nil { - return fmt.Errorf("Error retrieving virtual guest details for host %s: %s", hostname, err) + return fmt.Errorf("[ERROR] Error retrieving virtual guest details for host %s: %s", hostname, err) } if len(vgs) == 0 { - return fmt.Errorf("No virtual guest with hostname %s and domain %s", hostname, domain) + return fmt.Errorf("[ERROR] No virtual guest with hostname %s and domain %s", hostname, domain) } var vg datatypes.Virtual_Guest @@ -228,7 +229,7 @@ func dataSourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{} err = readSecondaryIPAddresses(d, meta, vg.PrimaryIpAddress) if err != nil { - return fmt.Errorf("Error retrieving virtual guest details for host %s: %s", hostname, err) + return fmt.Errorf("[ERROR] Error retrieving virtual guest details for host %s: %s", hostname, err) } return nil } diff --git a/ibm/data_source_ibm_compute_vm_instance_test.go b/ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance_test.go similarity index 89% rename from ibm/data_source_ibm_compute_vm_instance_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance_test.go index b41506bb7..341da1d85 100644 --- a/ibm/data_source_ibm_compute_vm_instance_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_compute_vm_instance_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMComputeVmInstanceDataSource_basic(t *testing.T) { domain := "ds.terraform.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeVmInstanceDataSourceConfigBasic(hostname, domain), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_compute_vm_instance.tf-vg-ds-acc-test", "power_state", "RUNNING"), diff --git a/ibm/service/classicinfrastructure/data_source_ibm_dns_domain.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain.go new file mode 100644 index 000000000..5e9137e2a --- /dev/null +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain.go @@ -0,0 +1,56 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package classicinfrastructure + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/softlayer/softlayer-go/filter" + "github.com/softlayer/softlayer-go/services" +) + +func DataSourceIBMDNSDomain() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMDNSDomainRead, + + Schema: map[string]*schema.Schema{ + "id": { + Description: "A domain record's internal identifier", + Type: schema.TypeInt, + Computed: true, + }, + + "name": { + Description: "The name of the domain", + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func dataSourceIBMDNSDomainRead(d *schema.ResourceData, meta interface{}) error { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetAccountService(sess) + + name := d.Get("name").(string) + + names, err := service. + Filter(filter.Build(filter.Path("domains.name").Eq(name))). + Mask("id,name"). + GetDomains() + + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving domain: %s", err) + } + + if len(names) == 0 { + return fmt.Errorf("[ERROR] No domain found with name [%s]", name) + } + + d.SetId(fmt.Sprintf("%d", *names[0].Id)) + return nil +} diff --git a/ibm/data_source_ibm_dns_domain_registration.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration.go similarity index 79% rename from ibm/data_source_ibm_dns_domain_registration.go rename to ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration.go index 563c0a137..60be38bd1 100644 --- a/ibm/data_source_ibm_dns_domain_registration.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration.go @@ -1,33 +1,35 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" - "log" ) -func dataSourceIBMDNSDomainRegistration() *schema.Resource { +func DataSourceIBMDNSDomainRegistration() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDNSDomainRegistrationRead, Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ + "id": { Description: "A domain registration record's internal identifier", Type: schema.TypeInt, Computed: true, }, - "name": &schema.Schema{ + "name": { Description: "The name of the domain registration", Type: schema.TypeString, Required: true, }, - "name_servers": &schema.Schema{ + "name_servers": { Description: "Custom name servers for the domain registration", Type: schema.TypeList, Computed: true, @@ -38,7 +40,7 @@ func dataSourceIBMDNSDomainRegistration() *schema.Resource { } func dataSourceIBMDNSDomainRegistrationRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("name").(string) @@ -48,11 +50,11 @@ func dataSourceIBMDNSDomainRegistrationRead(d *schema.ResourceData, meta interfa GetDomainRegistrations() if err != nil { - return fmt.Errorf("Error retrieving domain registration: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain registration: %s", err) } if len(names) == 0 { - return fmt.Errorf("No domain registration found with name [%s]", name) + return fmt.Errorf("[ERROR] No domain registration found with name [%s]", name) } log.Printf("names %v\n", names) @@ -77,7 +79,7 @@ func dataSourceIBMDNSDomainRegistrationRead(d *schema.ResourceData, meta interfa log.Printf("names %v\n", ns) if err != nil { - return fmt.Errorf("Error retrieving domain registration nameservers: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain registration nameservers: %s", err) } d.SetId(fmt.Sprintf("%d", dnsId)) diff --git a/ibm/data_source_ibm_dns_domain_registration_test.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration_test.go similarity index 82% rename from ibm/data_source_ibm_dns_domain_registration_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration_test.go index bd5102157..07c5a60f8 100644 --- a/ibm/data_source_ibm_dns_domain_registration_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_registration_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "regexp" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMDNSDomainRegistrationDataSource_Basic(t *testing.T) { @@ -15,10 +18,10 @@ func TestAccIBMDNSDomainRegistrationDataSource_Basic(t *testing.T) { var domainName = "wcpclouduk.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: fmt.Sprintf(testAccCheckIBMDNSDomainRegistrationDataSourceConfig_basic, domainName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_dns_domain_registration.wcpclouduk", "name", domainName), diff --git a/ibm/data_source_ibm_dns_domain_test.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_test.go similarity index 84% rename from ibm/data_source_ibm_dns_domain_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_dns_domain_test.go index bfbde862d..7eac5aca4 100644 --- a/ibm/data_source_ibm_dns_domain_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_domain_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMDNSDomainDataSource_Basic(t *testing.T) { var domainName = acctest.RandString(16) + ".com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: fmt.Sprintf(testAccCheckIBMDNSDomainDataSourceConfig_basic, domainName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_dns_domain.domain_id", "name", domainName), diff --git a/ibm/data_source_ibm_dns_secondary.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_secondary.go similarity index 77% rename from ibm/data_source_ibm_dns_secondary.go rename to ibm/service/classicinfrastructure/data_source_ibm_dns_secondary.go index 366e594d9..276852b0f 100644 --- a/ibm/data_source_ibm_dns_secondary.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_secondary.go @@ -1,22 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMDNSSecondary() *schema.Resource { +func DataSourceIBMDNSSecondary() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDNSSecondaryRead, Schema: map[string]*schema.Schema{ - "zone_name": &schema.Schema{ + "zone_name": { Description: "The name of the secondary", Type: schema.TypeString, Required: true, @@ -46,7 +47,7 @@ func dataSourceIBMDNSSecondary() *schema.Resource { } func dataSourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("zone_name").(string) @@ -56,11 +57,11 @@ func dataSourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) err GetSecondaryDomains() if err != nil { - return fmt.Errorf("Error retrieving secondary zone: %s", err) + return fmt.Errorf("[ERROR] Error retrieving secondary zone: %s", err) } if len(names) == 0 { - return fmt.Errorf("No secondary zone found with name: %s", name) + return fmt.Errorf("[ERROR] No secondary zone found with name: %s", name) } for _, zone := range names { @@ -75,6 +76,6 @@ func dataSourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) err } } - return fmt.Errorf("No secondary zone found with name: %s", name) + return fmt.Errorf("[ERROR] No secondary zone found with name: %s", name) } diff --git a/ibm/data_source_ibm_dns_secondary_test.go b/ibm/service/classicinfrastructure/data_source_ibm_dns_secondary_test.go similarity index 89% rename from ibm/data_source_ibm_dns_secondary_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_dns_secondary_test.go index 18b771a34..d21ef924d 100644 --- a/ibm/data_source_ibm_dns_secondary_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_dns_secondary_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,10 +20,10 @@ func TestAccIBMDNSSecondaryDataSource_Basic(t *testing.T) { var domainName1 = acctest.RandString(16) + ".com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: fmt.Sprintf(testAccCheckIBMDNSSecondaryDataSourceConfig_basic, domainName, domainName1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_dns_secondary.secondary_domain_id", "zone_name", domainName), @@ -40,10 +42,10 @@ func TestAccIBMDNSSecondaryDataSource_InvalidZone(t *testing.T) { var domainName1 = acctest.RandString(16) + ".com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: fmt.Sprintf(testAccCheckIBMDNSSecondaryDataSourceConfig_invlaid_zone, domainName, domainName1), ExpectError: regexp.MustCompile(fmt.Sprintf("No secondary zone found with name: %s", domainName1)), }, diff --git a/ibm/data_source_ibm_lbaas.go b/ibm/service/classicinfrastructure/data_source_ibm_lbaas.go similarity index 88% rename from ibm/data_source_ibm_lbaas.go rename to ibm/service/classicinfrastructure/data_source_ibm_lbaas.go index d1a33396c..2f55b2f16 100644 --- a/ibm/data_source_ibm_lbaas.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_lbaas.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMLbaas() *schema.Resource { +func DataSourceIBMLbaas() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMLbaasRead, @@ -172,7 +174,7 @@ func dataSourceIBMLbaas() *schema.Resource { func dataSourceIBMLbaasRead(d *schema.ResourceData, meta interface{}) error { name := d.Get("name").(string) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) lbs, err := service.Mask("datacenter,members,listeners.defaultPool,listeners.defaultPool.sessionAffinity,listeners.defaultPool.healthMonitor,healthMonitors,sslCiphers[name],useSystemPublicIpPool,isPublic,name,description,operatingStatus,address,uuid").Filter(filter.Build( filter.Path("name").Eq(name))).GetAllObjects() @@ -180,21 +182,21 @@ func dataSourceIBMLbaasRead(d *schema.ResourceData, meta interface{}) error { return err } if len(lbs) != 1 { - return fmt.Errorf("No load balancer with name: %s", name) + return fmt.Errorf("[ERROR] No load balancer with name: %s", name) } result := lbs[0] //Get statistics lbStat, err := service.GetLoadBalancerStatistics(result.Uuid) if err != nil { - return fmt.Errorf("Error retrieving load balancer statistics: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer statistics: %s", err) } //Get members health lbMembersHealth, err := service.GetLoadBalancerMemberHealth(result.Uuid) if err != nil { - return fmt.Errorf("Error retrieving load balancer members: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer members: %s", err) } - members := flattenServerInstances(result.Members) + members := flex.FlattenServerInstances(result.Members) for _, lbHealth := range lbMembersHealth { for _, lbMemHealth := range lbHealth.MembersHealth { @@ -226,10 +228,10 @@ func dataSourceIBMLbaasRead(d *schema.ResourceData, meta interface{}) error { d.Set("type", lbType) d.Set("status", result.OperatingStatus) d.Set("vip", result.Address) - d.Set("protocols", flattenProtocols(result.Listeners)) - d.Set("health_monitors", flattenHealthMonitors(result.Listeners)) + d.Set("protocols", flex.FlattenProtocols(result.Listeners)) + d.Set("health_monitors", flex.FlattenHealthMonitors(result.Listeners)) d.Set("server_instances", members) - d.Set("ssl_ciphers", flattenSSLCiphers(result.SslCiphers)) + d.Set("ssl_ciphers", flex.FlattenSSLCiphers(result.SslCiphers)) if *result.UseSystemPublicIpPool == 1 { d.Set("use_system_public_ip_pool", true) } else { diff --git a/ibm/data_source_ibm_lbaas_test.go b/ibm/service/classicinfrastructure/data_source_ibm_lbaas_test.go similarity index 91% rename from ibm/data_source_ibm_lbaas_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_lbaas_test.go index 4d96cd817..1d8f00b6d 100644 --- a/ibm/data_source_ibm_lbaas_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_lbaas_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,14 +16,14 @@ import ( func TestAccIBMLbaasDataSource_basic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasDataSourceConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "name", name), - resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "datacenter", lbaasDatacenter), + resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "protocols.0.backend_port", "80"), resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "protocols.0.backend_protocol", "HTTP"), resource.TestCheckResourceAttr("data.ibm_lbaas.tfacc_lbaas", "protocols.0.frontend_protocol", "HTTP"), @@ -80,5 +82,5 @@ data "ibm_lbaas" "tfacc_lbaas" { name = "${ibm_lbaas.lbaas.name}" depends_on = ["ibm_lbaas_server_instance_attachment.lbaas_member"] } -`, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } diff --git a/ibm/data_source_ibm_network_vlan.go b/ibm/service/classicinfrastructure/data_source_ibm_network_vlan.go similarity index 90% rename from ibm/data_source_ibm_network_vlan.go rename to ibm/service/classicinfrastructure/data_source_ibm_network_vlan.go index 0f4d7ff19..5d880d812 100644 --- a/ibm/data_source_ibm_network_vlan.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_network_vlan.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" "fmt" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMNetworkVlan() *schema.Resource { +func DataSourceIBMNetworkVlan() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMNetworkVlanRead, @@ -98,7 +99,7 @@ func dataSourceIBMNetworkVlan() *schema.Resource { } func dataSourceIBMNetworkVlanRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) name := d.Get("name").(string) @@ -133,9 +134,9 @@ func dataSourceIBMNetworkVlanRead(d *schema.ResourceData, meta interface{}) erro ). GetNetworkVlans() if err != nil { - return fmt.Errorf("Error obtaining VLAN id: %s", err) + return fmt.Errorf("[ERROR] Error obtaining VLAN id: %s", err) } else if len(networkVlans) == 0 { - return fmt.Errorf("No VLAN was found with the name '%s'", name) + return fmt.Errorf("[ERROR] No VLAN was found with the name '%s'", name) } vlan = &networkVlans[0] @@ -179,7 +180,7 @@ func dataSourceIBMNetworkVlanRead(d *schema.ResourceData, meta interface{}) erro } func getVlan(vlanNumber int, primaryRouterHostname string, name string, meta interface{}) (*datatypes.Network_Vlan, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) filters := filter.New(filter.Path("networkVlans.primaryRouter.hostname").Eq(primaryRouterHostname), filter.Path("networkVlans.vlanNumber").Eq(vlanNumber)) @@ -196,7 +197,7 @@ func getVlan(vlanNumber int, primaryRouterHostname string, name string, meta int GetNetworkVlans() if err != nil { - return &datatypes.Network_Vlan{}, fmt.Errorf("Error looking up Vlan: %s", err) + return &datatypes.Network_Vlan{}, fmt.Errorf("[ERROR] Error looking up Vlan: %s", err) } if len(networkVlans) < 1 { diff --git a/ibm/data_source_ibm_network_vlan_test.go b/ibm/service/classicinfrastructure/data_source_ibm_network_vlan_test.go similarity index 89% rename from ibm/data_source_ibm_network_vlan_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_network_vlan_test.go index 715e28f33..21cb33645 100644 --- a/ibm/data_source_ibm_network_vlan_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_network_vlan_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMNetworkVlanDataSource_Basic(t *testing.T) { name := fmt.Sprintf("terraformuat_vlan_%s", acctest.RandString(2)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMNetworkVlanDataSourceConfig(name), diff --git a/ibm/data_source_ibm_security_group.go b/ibm/service/classicinfrastructure/data_source_ibm_security_group.go similarity index 87% rename from ibm/data_source_ibm_security_group.go rename to ibm/service/classicinfrastructure/data_source_ibm_security_group.go index 146467e82..d16dc4c30 100644 --- a/ibm/data_source_ibm_security_group.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_security_group.go @@ -1,19 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "sort" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" "github.com/softlayer/softlayer-go/services" ) -func dataSourceIBMSecurityGroup() *schema.Resource { +func DataSourceIBMSecurityGroup() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMSecurityGroupRead, @@ -29,7 +30,7 @@ func dataSourceIBMSecurityGroup() *schema.Resource { Computed: true, Description: "The description of the security group", }, - "most_recent": &schema.Schema{ + "most_recent": { Description: "If true and multiple entries are found, the most recently created group is used. " + "If false, an error is returned", Type: schema.TypeBool, @@ -41,7 +42,7 @@ func dataSourceIBMSecurityGroup() *schema.Resource { } func dataSourceIBMSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() name := d.Get("name").(string) mostRecent := d.Get("most_recent").(bool) @@ -57,10 +58,10 @@ func dataSourceIBMSecurityGroupRead(d *schema.ResourceData, meta interface{}) er GetSecurityGroups() if err != nil { - return fmt.Errorf("Error retrieving Security group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Security group: %s", err) } if len(groups) == 0 { - return fmt.Errorf("No security group found with name [%s]", name) + return fmt.Errorf("[ERROR] No security group found with name [%s]", name) } var sg datatypes.Network_SecurityGroup diff --git a/ibm/data_source_ibm_security_group_test.go b/ibm/service/classicinfrastructure/data_source_ibm_security_group_test.go similarity index 89% rename from ibm/data_source_ibm_security_group_test.go rename to ibm/service/classicinfrastructure/data_source_ibm_security_group_test.go index b11f5726f..b061df94c 100644 --- a/ibm/data_source_ibm_security_group_test.go +++ b/ibm/service/classicinfrastructure/data_source_ibm_security_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/softlayer/softlayer-go/datatypes" @@ -19,8 +21,8 @@ func TestAccIBMSecurityGroupDataSource_basic(t *testing.T) { desc1 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMSecurityGroupDataSourceConfig(name1, desc1), diff --git a/ibm/resource_ibm_cdn.go b/ibm/service/classicinfrastructure/resource_ibm_cdn.go similarity index 92% rename from ibm/resource_ibm_cdn.go rename to ibm/service/classicinfrastructure/resource_ibm_cdn.go index 30096e6f9..c69cc9d17 100644 --- a/ibm/resource_ibm_cdn.go +++ b/ibm/service/classicinfrastructure/resource_ibm_cdn.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,8 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" @@ -17,7 +19,7 @@ import ( const str string = ".cdn.appdomain.cloud" -func resourceIBMCDN() *schema.Resource { +func ResourceIBMCDN() *schema.Resource { return &schema.Resource{ Create: resourceIBMCDNCreate, Read: resourceIBMCDNRead, @@ -26,13 +28,13 @@ func resourceIBMCDN() *schema.Resource { Exists: resourceIBMCDNExists, Schema: map[string]*schema.Schema{ - "host_name": &schema.Schema{ + "host_name": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "Host name", }, - "vendor_name": &schema.Schema{ + "vendor_name": { Type: schema.TypeString, Optional: true, Default: "akamai", @@ -40,50 +42,50 @@ func resourceIBMCDN() *schema.Resource { Description: "Vendor name", }, - "origin_type": &schema.Schema{ + "origin_type": { Type: schema.TypeString, Optional: true, Default: "HOST_SERVER", ForceNew: true, - ValidateFunc: validateAllowedStringValue([]string{"HOST_SERVER", "OBJECT_STORAGE"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"HOST_SERVER", "OBJECT_STORAGE"}), Description: "Origin type info", }, - "origin_address": &schema.Schema{ + "origin_address": { Type: schema.TypeString, Required: true, Description: "origin address info", }, - "bucket_name": &schema.Schema{ + "bucket_name": { Type: schema.TypeString, Optional: true, Description: "Bucket name", }, - "protocol": &schema.Schema{ + "protocol": { Type: schema.TypeString, Optional: true, Default: "HTTP", ForceNew: true, - ValidateFunc: validateAllowedStringValue([]string{"HTTP", "HTTPS", "HTTP_AND_HTTPS"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"HTTP", "HTTPS", "HTTP_AND_HTTPS"}), Description: "Protocol name", }, - "http_port": &schema.Schema{ + "http_port": { Type: schema.TypeInt, Optional: true, Default: 80, Description: "HTTP port number", }, - "status": &schema.Schema{ + "status": { Type: schema.TypeString, Computed: true, Description: "Status info of the CDN instance", }, - "https_port": &schema.Schema{ + "https_port": { Type: schema.TypeInt, Optional: true, Default: 443, Description: "HTTPS port number", }, - "cname": &schema.Schema{ + "cname": { Type: schema.TypeString, Computed: true, Optional: true, @@ -100,45 +102,45 @@ func resourceIBMCDN() *schema.Resource { }, Description: "cname info", }, - "header": &schema.Schema{ + "header": { Type: schema.TypeString, Optional: true, Computed: true, Description: "Header info", }, - "respect_headers": &schema.Schema{ + "respect_headers": { Type: schema.TypeBool, Optional: true, Default: true, Description: "respect headers info", }, - "file_extension": &schema.Schema{ + "file_extension": { Type: schema.TypeString, Optional: true, Description: "File extension info", }, - "certificate_type": &schema.Schema{ + "certificate_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"SHARED_SAN_CERT", "WILDCARD_CERT"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"SHARED_SAN_CERT", "WILDCARD_CERT"}), ForceNew: true, Description: "Certificate type", }, - "cache_key_query_rule": &schema.Schema{ + "cache_key_query_rule": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"include-all", "ignore-all", "ignore: space separated query-args", "include: space separated query-args"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"include-all", "ignore-all", "ignore: space separated query-args", "include: space separated query-args"}), Default: "include-all", Description: "query rule info", }, - "performance_configuration": &schema.Schema{ + "performance_configuration": { Type: schema.TypeString, Optional: true, Default: "General web delivery", ForceNew: true, Description: "performance configuration info", }, - "path": &schema.Schema{ + "path": { Type: schema.TypeString, Optional: true, Default: "/*", @@ -151,7 +153,7 @@ func resourceIBMCDN() *schema.Resource { func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { ///create session - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() ///get the value of all the parameters domain := d.Get("host_name").(string) vendorname := d.Get("vendor_name").(string) @@ -196,11 +198,11 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt1[0].UniqueId) - id, err := strconv.Atoi((d.Id())) + id, _ := strconv.Atoi((d.Id())) result1, err := service.VerifyDomainMapping(&id) log.Print("The status of domain mapping ", result1) return resourceIBMCDNRead(d, meta) @@ -224,7 +226,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt2[0].UniqueId) @@ -252,7 +254,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt3[0].UniqueId) @@ -277,7 +279,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt4[0].UniqueId) @@ -303,7 +305,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt5[0].UniqueId) @@ -330,7 +332,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { PerformanceConfiguration: sl.String(performanceconfiguration), }) if err != nil { - return fmt.Errorf("Error creating CDN: %s", err) + return fmt.Errorf("[ERROR] Error creating CDN: %s", err) } d.SetId(*receipt6[0].UniqueId) @@ -344,7 +346,7 @@ func resourceIBMCDNCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMCDNRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkCdnMarketplaceConfigurationMappingService(sess) cdnId := sl.String(d.Id()) ///read the changes in the remote resource and update in the local resource. @@ -380,7 +382,7 @@ func resourceIBMCDNRead(d *schema.ResourceData, meta interface{}) error { func resourceIBMCDNUpdate(d *schema.ResourceData, meta interface{}) error { /// Nothing to update for now. Not supported. - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() domain := d.Get("host_name").(string) vendorname := d.Get("vendor_name").(string) origintype := d.Get("origin_type").(string) @@ -573,7 +575,7 @@ func resourceIBMCDNUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMCDNDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkCdnMarketplaceConfigurationMappingService(sess) cdnId := sl.String(d.Id()) @@ -590,7 +592,7 @@ func resourceIBMCDNDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMCDNExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkCdnMarketplaceConfigurationMappingService(sess) cdnId := sl.String(d.Id()) ///check if the resource exists with the given id. @@ -603,7 +605,7 @@ func resourceIBMCDNExists(d *schema.ResourceData, meta interface{}) (bool, error return false, nil } } - return false, fmt.Errorf("Error retrieving CDN mapping info: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving CDN mapping info: %s", err) } return true, nil } diff --git a/ibm/resource_ibm_cdn_test.go b/ibm/service/classicinfrastructure/resource_ibm_cdn_test.go similarity index 83% rename from ibm/resource_ibm_cdn_test.go rename to ibm/service/classicinfrastructure/resource_ibm_cdn_test.go index 11d241356..f48e0d622 100644 --- a/ibm/resource_ibm_cdn_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_cdn_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" @@ -19,8 +22,8 @@ func TestAccIBMCDN_Basic(t *testing.T) { var cdn datatypes.Network_CdnMarketplace_Configuration_Mapping resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCDNDestroy, Steps: []resource.TestStep{ { @@ -43,7 +46,7 @@ func TestAccIBMCDN_Basic(t *testing.T) { } func testAccCheckIBMCDNDestroy(s *terraform.State) error { - service := services.GetNetworkCdnMarketplaceConfigurationMappingService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkCdnMarketplaceConfigurationMappingService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_cdn" { @@ -68,15 +71,15 @@ func testAccCheckIBMCDNExists(n string, cdn *datatypes.Network_CdnMarketplace_Co rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } cdnId := sl.String(rs.Primary.ID) - service := services.GetNetworkCdnMarketplaceConfigurationMappingService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkCdnMarketplaceConfigurationMappingService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundId, err := service.ListDomainMappingByUniqueId(cdnId) diff --git a/ibm/resource_ibm_compute_autoscale_group.go b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group.go similarity index 87% rename from ibm/resource_ibm_compute_autoscale_group.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group.go index f5783dac4..e533e6b62 100644 --- a/ibm/resource_ibm_compute_autoscale_group.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -36,7 +37,7 @@ var IBMComputeAutoScaleGroupObjectMask = []string{ "loadBalancers[healthCheck[healthCheckTypeId,type[keyname],attributes[value,type[id,keyname]]]]", } -func resourceIBMComputeAutoScaleGroup() *schema.Resource { +func ResourceIBMComputeAutoScaleGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeAutoScaleGroupCreate, Read: resourceIBMComputeAutoScaleGroupRead, @@ -135,7 +136,7 @@ func resourceIBMComputeAutoScaleGroup() *schema.Resource { // Otherwise a modified template parameter unnecessarily forces scale group drop/create func getModifiedVirtualGuestResource() *schema.Resource { - r := resourceIBMComputeVmInstance() + r := ResourceIBMComputeVmInstance() // wait_time_minutes is only used in virtual_guest resource. delete(r.Schema, "wait_time_minutes") delete(r.Schema, "reserved_capacity_id") @@ -220,14 +221,14 @@ func buildScaleVlansFromResourceData(v interface{}, meta interface{}) ([]datatyp func getVirtualGuestTemplate(vGuestTemplateList []interface{}, meta interface{}) (datatypes.Virtual_Guest, error) { if len(vGuestTemplateList) != 1 { return datatypes.Virtual_Guest{}, - errors.New("Only one virtual_guest_member_template can be provided") + errors.New("[ERROR] Only one virtual_guest_member_template can be provided") } // Retrieve the map of virtual_guest_member_template attributes vGuestMap := vGuestTemplateList[0].(map[string]interface{}) // Create an empty ResourceData instance for a IBM_Compute_VM_Instance resource - vGuestResourceData := resourceIBMComputeVmInstance().Data(nil) + vGuestResourceData := ResourceIBMComputeVmInstance().Data(nil) // For each item in the map, call Set on the ResourceData. This handles // validation and yields a completed ResourceData object @@ -236,7 +237,7 @@ func getVirtualGuestTemplate(vGuestTemplateList []interface{}, meta interface{}) err := vGuestResourceData.Set(k, v) if err != nil { return datatypes.Virtual_Guest{}, - fmt.Errorf("Error while parsing virtual_guest_member_template values: %s", err) + fmt.Errorf("[ERROR] Error while parsing virtual_guest_member_template values: %s", err) } } dc := vGuestResourceData.Get("datacenter").(string) @@ -249,17 +250,17 @@ func getVirtualGuestTemplate(vGuestTemplateList []interface{}, meta interface{}) } func resourceIBMComputeAutoScaleGroupCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() accountServiceNoRetry := services.GetScaleGroupService(sess.SetRetries(0)) virtualGuestTemplateOpts, err := getVirtualGuestTemplate(d.Get("virtual_guest_member_template").([]interface{}), meta) if err != nil { - return fmt.Errorf("Error while parsing virtual_guest_member_template values: %s", err) + return fmt.Errorf("[ERROR] Error while parsing virtual_guest_member_template values: %s", err) } scaleNetworkVlans, err := buildScaleVlansFromResourceData(d.Get("network_vlan_ids").(*schema.Set).List(), meta) if err != nil { - return fmt.Errorf("Error while parsing network vlan values: %s", err) + return fmt.Errorf("[ERROR] Error while parsing network vlan values: %s", err) } locationGroupRegionalId, err := getLocationGroupRegionalId(sess, d.Get("regional_group").(string)) @@ -285,12 +286,12 @@ func resourceIBMComputeAutoScaleGroupCreate(d *schema.ResourceData, meta interfa opts.LoadBalancers, err = buildLoadBalancers(d) if err != nil { - return fmt.Errorf("Error creating Scale Group: %s", err) + return fmt.Errorf("[ERROR] Error creating Scale Group: %s", err) } res, err := accountServiceNoRetry.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Scale Group: %s", err) + return fmt.Errorf("[ERROR] Error creating Scale Group: %s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -302,7 +303,7 @@ func resourceIBMComputeAutoScaleGroupCreate(d *schema.ResourceData, meta interfa _, err = waitForActiveStatus(d, meta) if err != nil { - return fmt.Errorf("Error waiting for scale group (%s) to become active: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for scale group (%s) to become active: %s", d.Id(), err) } return resourceIBMComputeAutoScaleGroupRead(d, meta) @@ -324,7 +325,7 @@ func buildLoadBalancers(d *schema.ResourceData, ids ...int) ([]datatypes.Scale_L isLoadBalancerEmpty = false healthCheckOpts, err := buildHealthCheckFromResourceData(healthCheck.(map[string]interface{})) if err != nil { - return []datatypes.Scale_LoadBalancer{}, fmt.Errorf("Error while parsing health check options: %s", err) + return []datatypes.Scale_LoadBalancer{}, fmt.Errorf("[ERROR] Error while parsing health check options: %s", err) } loadBalancers[0].HealthCheck = &healthCheckOpts } @@ -342,7 +343,7 @@ func buildLoadBalancers(d *schema.ResourceData, ids ...int) ([]datatypes.Scale_L } func resourceIBMComputeAutoScaleGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetScaleGroupService(sess) groupId, _ := strconv.Atoi(d.Id()) @@ -355,7 +356,7 @@ func resourceIBMComputeAutoScaleGroupRead(d *schema.ResourceData, meta interface return nil } - return fmt.Errorf("Error retrieving autoscale Group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving autoscale Group: %s", err) } d.Set("name", slGroupObj.Name) @@ -457,7 +458,7 @@ func populateMemberTemplateResourceData(template datatypes.Virtual_Guest) []map[ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() scaleGroupService := services.GetScaleGroupService(sess) scaleNetworkVlanService := services.GetScaleNetworkVlanService(sess) scaleLoadBalancerService := services.GetScaleLoadBalancerService(sess) @@ -465,14 +466,14 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa groupId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID. Must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID. Must be an integer: %s", err) } // Fetch the complete object from SoftLayer, update with current values from the configuration, and send the // whole thing back to SoftLayer (effectively, a PUT) groupObj, err := scaleGroupService.Id(groupId).Mask(strings.Join(IBMComputeAutoScaleGroupObjectMask, ",")).GetObject() if err != nil { - return fmt.Errorf("Error retrieving autoscale_group resource: %s", err) + return fmt.Errorf("[ERROR] Error retrieving autoscale_group resource: %s", err) } groupObj.Name = sl.String(d.Get("name").(string)) @@ -488,7 +489,7 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa groupObj.LoadBalancers, err = buildLoadBalancers(d) } if err != nil { - return fmt.Errorf("Error creating Scale Group: %s", err) + return fmt.Errorf("[ERROR] Error creating Scale Group: %s", err) } if d.HasChange("network_vlan_ids") { @@ -506,13 +507,13 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa Id(groupId). GetNetworkVlans() if err != nil { - return fmt.Errorf("Could not retrieve current vlans for scale group (%d): %s", groupId, err) + return fmt.Errorf("[ERROR] Could not retrieve current vlans for scale group (%d): %s", groupId, err) } for _, oldScaleVlan := range oldScaleVlans { _, err := scaleNetworkVlanService.Id(*oldScaleVlan.Id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting scale network vlan %d: %s", *oldScaleVlan.Id, err) + return fmt.Errorf("[ERROR] Error deleting scale network vlan %d: %s", *oldScaleVlan.Id, err) } } @@ -520,7 +521,7 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa scaleVlans, err := buildScaleVlansFromResourceData(newIds, meta) if err != nil { - return fmt.Errorf("Unable to parse network vlan options: %s", err) + return fmt.Errorf("[ERROR] Unable to parse network vlan options: %s", err) } groupObj.NetworkVlans = scaleVlans @@ -529,7 +530,7 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa if d.HasChange("virtual_guest_member_template") { virtualGuestTemplateOpts, err := getVirtualGuestTemplate(d.Get("virtual_guest_member_template").([]interface{}), meta) if err != nil { - return fmt.Errorf("Unable to parse virtual guest member template options: %s", err) + return fmt.Errorf("[ERROR] Unable to parse virtual guest member template options: %s", err) } groupObj.VirtualGuestMemberTemplate = &virtualGuestTemplateOpts @@ -537,14 +538,14 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa } _, err = scaleGroupServiceNoRetry.Id(groupId).EditObject(&groupObj) if err != nil { - return fmt.Errorf("Error received while editing autoscale_group: %s", err) + return fmt.Errorf("[ERROR] Error received while editing autoscale_group: %s", err) } // wait for scale group to become active _, err = waitForActiveStatus(d, meta) if err != nil { - return fmt.Errorf("Error waiting for scale group (%s) to become active: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for scale group (%s) to become active: %s", d.Id(), err) } // Delete a load balancer if there is the load balancer in a scale group @@ -552,7 +553,7 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa if len(currentLoadBalancers) > 0 && len(groupObj.LoadBalancers) <= 0 { _, err = scaleLoadBalancerService.Id(*currentLoadBalancers[0].Id).DeleteObject() if err != nil { - return fmt.Errorf("Error received while deleting loadbalancers: %s", err) + return fmt.Errorf("[ERROR] Error received while deleting loadbalancers: %s", err) } } @@ -560,18 +561,18 @@ func resourceIBMComputeAutoScaleGroupUpdate(d *schema.ResourceData, meta interfa } func resourceIBMComputeAutoScaleGroupDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() scaleGroupService := services.GetScaleGroupService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Error deleting scale group: %s", err) + return fmt.Errorf("[ERROR] Error deleting scale group: %s", err) } log.Printf("[INFO] Deleting scale group: %d", id) _, err = scaleGroupService.Id(id).ForceDeleteObject() if err != nil { - return fmt.Errorf("Error deleting scale group: %s", err) + return fmt.Errorf("[ERROR] Error deleting scale group: %s", err) } d.SetId("") @@ -580,13 +581,13 @@ func resourceIBMComputeAutoScaleGroupDelete(d *schema.ResourceData, meta interfa } func waitForActiveStatus(d *schema.ResourceData, meta interface{}) (interface{}, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() scaleGroupService := services.GetScaleGroupService(sess) log.Printf("Waiting for scale group (%s) to become active", d.Id()) id, err := strconv.Atoi(d.Id()) if err != nil { - return nil, fmt.Errorf("The scale group ID %s must be numeric", d.Id()) + return nil, fmt.Errorf("[ERROR] The scale group ID %s must be numeric", d.Id()) } stateConf := &resource.StateChangeConf{ @@ -599,7 +600,7 @@ func waitForActiveStatus(d *schema.ResourceData, meta interface{}) (interface{}, GetObject() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("The scale group %d does not exist anymore: %s", id, err) + return nil, "", fmt.Errorf("[ERROR] The scale group %d does not exist anymore: %s", id, err) } return result, "BUSY", nil // Retry @@ -643,12 +644,12 @@ func waitForActiveStatus(d *schema.ResourceData, meta interface{}) (interface{}, func resourceIBMComputeAutoScaleGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() scaleGroupService := services.GetScaleGroupService(sess) groupId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := scaleGroupService.Id(groupId).Mask("id").GetObject() @@ -658,7 +659,7 @@ func resourceIBMComputeAutoScaleGroupExists(d *schema.ResourceData, meta interfa return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute autoscale group: %s", err) } return result.Id != nil && *result.Id == groupId, nil } @@ -677,7 +678,7 @@ func getLocationGroupRegionalId(sess *session.Session, locationGroupRegionalName } if len(locationGroupRegionals) < 1 { - return -1, fmt.Errorf("Invalid location group regional: %s", locationGroupRegionalName) + return -1, fmt.Errorf("[ERROR] Invalid location group regional: %s", locationGroupRegionalName) } for _, locationGroupRegional := range locationGroupRegionals { @@ -686,5 +687,5 @@ func getLocationGroupRegionalId(sess *session.Session, locationGroupRegionalName } } - return -1, fmt.Errorf("Invalid regional_group_id: %s", locationGroupRegionalName) + return -1, fmt.Errorf("[ERROR] Invalid regional_group_id: %s", locationGroupRegionalName) } diff --git a/ibm/resource_ibm_compute_autoscale_group_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group_test.go similarity index 91% rename from ibm/resource_ibm_compute_autoscale_group_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group_test.go index 27de61aa4..96ee71314 100644 --- a/ibm/resource_ibm_compute_autoscale_group_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_group_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -18,6 +21,21 @@ import ( "github.com/softlayer/softlayer-go/services" ) +var IBMComputeAutoScaleGroupObjectMask = []string{ + "id", + "name", + "minimumMemberCount", + "maximumMemberCount", + "cooldown", + "status[keyName]", + "regionalGroup[id,name]", + "terminationPolicy[keyName]", + "virtualGuestMemberTemplate[blockDeviceTemplateGroup,primaryNetworkComponent[networkVlan[id]],primaryBackendNetworkComponent[networkVlan[id]]]", + "loadBalancers[id,port,virtualServerId,healthCheck[id]]", + "networkVlans[id,networkVlanId,networkVlan[vlanNumber,primaryRouter[hostname]]]", + "loadBalancers[healthCheck[healthCheckTypeId,type[keyname],attributes[value,type[id,keyname]]]]", +} + func TestAccIBMComputeAutoScaleGroup_Basic(t *testing.T) { var scalegroup datatypes.Scale_Group groupname := fmt.Sprintf("terraformuat_%d", acctest.RandIntRange(10, 100)) @@ -26,11 +44,11 @@ func TestAccIBMComputeAutoScaleGroup_Basic(t *testing.T) { updatedhostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeAutoScaleGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScaleGroupConfig_basic(groupname, hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScaleGroupExists("ibm_compute_autoscale_group.sample-http-cluster", &scalegroup), @@ -79,7 +97,7 @@ func TestAccIBMComputeAutoScaleGroup_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScaleGroupConfig_updated(updatedgroupname, updatedhostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScaleGroupExists("ibm_compute_autoscale_group.sample-http-cluster", &scalegroup), @@ -127,11 +145,11 @@ func TestAccIBMComputeAutoScaleGroupWithTag(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeAutoScaleGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScaleGroupWithTag(groupname, hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScaleGroupExists("ibm_compute_autoscale_group.sample-http-cluster", &scalegroup), @@ -152,7 +170,7 @@ func TestAccIBMComputeAutoScaleGroupWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScaleGroupWithUpdatedTag(groupname, hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScaleGroupExists("ibm_compute_autoscale_group.sample-http-cluster", &scalegroup), @@ -177,7 +195,7 @@ func TestAccIBMComputeAutoScaleGroupWithTag(t *testing.T) { } func testAccCheckIBMComputeAutoScaleGroupDestroy(s *terraform.State) error { - service := services.GetScaleGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetScaleGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_autoscale_group" { @@ -192,7 +210,7 @@ func testAccCheckIBMComputeAutoScaleGroupDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Auto Scale still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for Auto Scale (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for Auto Scale (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -228,7 +246,7 @@ func testAccCheckIBMComputeAutoScaleGroupExists(n string, scalegroup *datatypes. rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -237,7 +255,7 @@ func testAccCheckIBMComputeAutoScaleGroupExists(n string, scalegroup *datatypes. scalegroupId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetScaleGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetScaleGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundScaleGroup, err := service.Id(scalegroupId).Mask(strings.Join(IBMComputeAutoScaleGroupObjectMask, ",")).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_autoscale_policy.go b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy.go similarity index 85% rename from ibm/resource_ibm_compute_autoscale_policy.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy.go index efb825d80..5b5a2a8d9 100644 --- a/ibm/resource_ibm_compute_autoscale_policy.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "bytes" @@ -17,7 +17,7 @@ import ( "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) const ( @@ -39,7 +39,7 @@ var IBMComputeAutoScalePolicyObjectMask = []string{ "triggers", } -func resourceIBMComputeAutoScalePolicy() *schema.Resource { +func ResourceIBMComputeAutoScalePolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeAutoScalePolicyCreate, Read: resourceIBMComputeAutoScalePolicyRead, @@ -147,7 +147,7 @@ func resourceIBMComputeAutoScalePolicy() *schema.Resource { } func resourceIBMComputeAutoScalePolicyCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetScalePolicyService(sess.SetRetries(0)) var err error @@ -160,7 +160,7 @@ func resourceIBMComputeAutoScalePolicyCreate(d *schema.ResourceData, meta interf } if *opts.Cooldown < 0 || *opts.Cooldown > 864000 { - return fmt.Errorf("Error retrieving scalePolicy: %s", "cooldown must be between 0 seconds and 10 days.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "cooldown must be between 0 seconds and 10 days.") } opts.ScaleActions = []datatypes.Scale_Policy_Action_Scale{{ @@ -171,37 +171,37 @@ func resourceIBMComputeAutoScalePolicyCreate(d *schema.ResourceData, meta interf opts.ScaleActions[0].TypeId = sl.Int(1) if *opts.ScaleActions[0].Amount <= 0 { - return fmt.Errorf("Error retrieving scalePolicy: %s", "scale_amount should be greater than 0.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "scale_amount should be greater than 0.") } if *opts.ScaleActions[0].ScaleType != "ABSOLUTE" && *opts.ScaleActions[0].ScaleType != "RELATIVE" && *opts.ScaleActions[0].ScaleType != "PERCENT" { - return fmt.Errorf("Error retrieving scalePolicy: %s", "scale_type should be ABSOLUTE, RELATIVE, or PERCENT.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "scale_type should be ABSOLUTE, RELATIVE, or PERCENT.") } if _, ok := d.GetOk("triggers"); ok { err = validateTriggerTypes(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } opts.OneTimeTriggers, err = prepareOneTimeTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } opts.RepeatingTriggers, err = prepareRepeatingTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } opts.ResourceUseTriggers, err = prepareResourceUseTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } } res, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Scale Policy: %s $s", err) + return fmt.Errorf("[ERROR] Error creating Scale Policy: %s $s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -211,18 +211,18 @@ func resourceIBMComputeAutoScalePolicyCreate(d *schema.ResourceData, meta interf } func resourceIBMComputeAutoScalePolicyRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetScalePolicyService(sess) scalePolicyId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid scale policy ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid scale policy ID, must be an integer: %s", err) } log.Printf("[INFO] Reading Scale Polocy: %d", scalePolicyId) scalePolicy, err := service.Id(scalePolicyId).Mask(strings.Join(IBMComputeAutoScalePolicyObjectMask, ";")).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Scale Policy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Scale Policy: %s", err) } d.Set("name", scalePolicy.Name) @@ -242,19 +242,19 @@ func resourceIBMComputeAutoScalePolicyRead(d *schema.ResourceData, meta interfac func resourceIBMComputeAutoScalePolicyUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() scalePolicyService := services.GetScalePolicyService(sess) scalePolicyTriggerService := services.GetScalePolicyTriggerService(sess) scalePolicyServiceNoRetry := services.GetScalePolicyService(sess.SetRetries(0)) scalePolicyId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid scale policy ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid scale policy ID, must be an integer: %s", err) } scalePolicy, err := scalePolicyService.Id(scalePolicyId).Mask(strings.Join(IBMComputeAutoScalePolicyObjectMask, ";")).GetObject() if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } var template datatypes.Scale_Policy @@ -274,36 +274,36 @@ func resourceIBMComputeAutoScalePolicyUpdate(d *schema.ResourceData, meta interf if d.HasChange("scale_type") { template.ScaleActions[0].ScaleType = sl.String(d.Get("scale_type").(string)) if *template.ScaleActions[0].ScaleType != "ABSOLUTE" && *template.ScaleActions[0].ScaleType != "RELATIVE" && *template.ScaleActions[0].ScaleType != "PERCENT" { - return fmt.Errorf("Error retrieving scalePolicy: %s", "scale_type should be ABSOLUTE, RELATIVE, or PERCENT.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "scale_type should be ABSOLUTE, RELATIVE, or PERCENT.") } } if d.HasChange("scale_amount") { template.ScaleActions[0].Amount = sl.Int(d.Get("scale_amount").(int)) if *template.ScaleActions[0].Amount <= 0 { - return fmt.Errorf("Error retrieving scalePolicy: %s", "scale_amount should be greater than 0.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "scale_amount should be greater than 0.") } } if d.HasChange("cooldown") { template.Cooldown = sl.Int(d.Get("cooldown").(int)) if *template.Cooldown <= 0 || *template.Cooldown > 864000 { - return fmt.Errorf("Error retrieving scalePolicy: %s", "cooldown must be between 0 seconds and 10 days.") + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", "cooldown must be between 0 seconds and 10 days.") } } if _, ok := d.GetOk("triggers"); ok { template.OneTimeTriggers, err = prepareOneTimeTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } template.RepeatingTriggers, err = prepareRepeatingTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } template.ResourceUseTriggers, err = prepareResourceUseTriggers(d) if err != nil { - return fmt.Errorf("Error retrieving scalePolicy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving scalePolicy: %s", err) } } @@ -317,25 +317,25 @@ func resourceIBMComputeAutoScalePolicyUpdate(d *schema.ResourceData, meta interf _, err = scalePolicyServiceNoRetry.Id(scalePolicyId).EditObject(&template) if err != nil { - return fmt.Errorf("Error updating scalie policy: %s", err) + return fmt.Errorf("[ERROR] Error updating scalie policy: %s", err) } return nil } func resourceIBMComputeAutoScalePolicyDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetScalePolicyService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Error deleting scale policy: %s", err) + return fmt.Errorf("[ERROR] Error deleting scale policy: %s", err) } log.Printf("[INFO] Deleting scale policy: %d", id) _, err = service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting scale policy: %s", err) + return fmt.Errorf("[ERROR] Error deleting scale policy: %s", err) } d.SetId("") @@ -344,12 +344,12 @@ func resourceIBMComputeAutoScalePolicyDelete(d *schema.ResourceData, meta interf } func resourceIBMComputeAutoScalePolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetScalePolicyService(sess) policyId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(policyId).Mask("id").GetObject() if err != nil { @@ -358,7 +358,7 @@ func resourceIBMComputeAutoScalePolicyExists(d *schema.ResourceData, meta interf return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute autoscale policy: %s", err) } return result.Id != nil && *result.Id == policyId, nil @@ -370,7 +370,7 @@ func validateTriggerTypes(d *schema.ResourceData) error { trigger := triggerList.(map[string]interface{}) trigger_type := trigger["type"].(string) if trigger_type != "ONE_TIME" && trigger_type != "REPEATING" && trigger_type != "RESOURCE_USE" { - return fmt.Errorf("Invalid trigger type: %s", trigger_type) + return fmt.Errorf("[ERROR] Invalid trigger type: %s", trigger_type) } } return nil @@ -452,12 +452,12 @@ func prepareWatches(d *schema.Set) ([]datatypes.Scale_Policy_Trigger_ResourceUse watch.Metric = sl.String(watchMap["metric"].(string)) if *watch.Metric != "host.cpu.percent" && *watch.Metric != "host.network.backend.in.rate" && *watch.Metric != "host.network.backend.out.rate" && *watch.Metric != "host.network.frontend.in.rate" && *watch.Metric != "host.network.frontend.out.rate" { - return nil, fmt.Errorf("Invalid metric : %s", *watch.Metric) + return nil, fmt.Errorf("[ERROR] Invalid metric : %s", *watch.Metric) } watch.Operator = sl.String(watchMap["operator"].(string)) if *watch.Operator != ">" && *watch.Operator != "<" { - return nil, fmt.Errorf("Invalid operator : %s", *watch.Operator) + return nil, fmt.Errorf("[ERROR] Invalid operator : %s", *watch.Operator) } watch.Period = sl.Int(watchMap["period"].(int)) @@ -549,7 +549,7 @@ func resourceIBMComputeAutoScalePolicyTriggerHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%d-", watch["period"].(int))) } } - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func resourceIBMComputeAutoScalePolicyHandlerHash(v interface{}) int { @@ -559,5 +559,5 @@ func resourceIBMComputeAutoScalePolicyHandlerHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", watch["operator"].(string))) buf.WriteString(fmt.Sprintf("%s-", watch["value"].(string))) buf.WriteString(fmt.Sprintf("%d-", watch["period"].(int))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } diff --git a/ibm/resource_ibm_compute_autoscale_policy_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy_test.go similarity index 93% rename from ibm/resource_ibm_compute_autoscale_policy_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy_test.go index 2e52e841f..14195f6ef 100644 --- a/ibm/resource_ibm_compute_autoscale_policy_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_autoscale_policy_test.go @@ -1,15 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "strings" "testing" + "time" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,6 +21,18 @@ import ( "github.com/softlayer/softlayer-go/services" ) +var IBMComputeAutoScalePolicyObjectMask = []string{ + "cooldown", + "id", + "name", + "scaleActions", + "scaleGroupId", + "oneTimeTriggers", + "repeatingTriggers", + "resourceUseTriggers.watches", + "triggers", +} + func TestAccIBMComputeAutoScalePolicy_Basic(t *testing.T) { var scalepolicy datatypes.Scale_Policy groupname := fmt.Sprintf("terraformuat_%d", acctest.RandIntRange(10, 100)) @@ -25,11 +41,11 @@ func TestAccIBMComputeAutoScalePolicy_Basic(t *testing.T) { updatedpolicyname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeAutoScalePolicyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScalePolicyConfig_basic(groupname, hostname, policyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScalePolicyExists("ibm_compute_autoscale_policy.sample-http-cluster-policy", &scalepolicy), @@ -50,7 +66,7 @@ func TestAccIBMComputeAutoScalePolicy_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScalePolicyConfig_updated(groupname, hostname, updatedpolicyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScalePolicyExists("ibm_compute_autoscale_policy.sample-http-cluster-policy", &scalepolicy), @@ -80,11 +96,11 @@ func TestAccIBMComputeAutoScaleWithTag(t *testing.T) { policyname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeAutoScalePolicyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScalePolicyWithTag(groupname, hostname, policyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScalePolicyExists("ibm_compute_autoscale_policy.sample-http-cluster-policy", &scalepolicy), @@ -96,7 +112,7 @@ func TestAccIBMComputeAutoScaleWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeAutoScalePolicyWithUpdatedTag(groupname, hostname, policyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeAutoScalePolicyExists("ibm_compute_autoscale_policy.sample-http-cluster-policy", &scalepolicy), @@ -111,7 +127,7 @@ func TestAccIBMComputeAutoScaleWithTag(t *testing.T) { } func testAccCheckIBMComputeAutoScalePolicyDestroy(s *terraform.State) error { - service := services.GetScalePolicyService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetScalePolicyService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_autoscale_policy" { @@ -126,7 +142,7 @@ func testAccCheckIBMComputeAutoScalePolicyDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Auto Scale Policy still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for Auto Scale Policy (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for Auto Scale Policy (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -213,16 +229,16 @@ func testAccCheckIBMComputeAutoScalePolicyExists(n string, scalepolicy *datatype rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } scalepolicyId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetScalePolicyService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetScalePolicyService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundScalePolicy, err := service.Id(scalepolicyId).Mask(strings.Join(IBMComputeAutoScalePolicyObjectMask, ",")).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_bare_metal.go b/ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal.go similarity index 90% rename from ibm/resource_ibm_compute_bare_metal.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal.go index cb2ba12d2..ff01de9be 100644 --- a/ibm/resource_ibm_compute_bare_metal.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -21,7 +24,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeBareMetal() *schema.Resource { +func ResourceIBMComputeBareMetal() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeBareMetalCreate, Read: resourceIBMComputeBareMetalRead, @@ -105,7 +108,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Default: nil, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "tags": { @@ -120,7 +123,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Fixed config preset value", }, @@ -131,7 +134,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Computed: true, ForceNew: true, ConflictsWith: []string{"image_template_id"}, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "OS refernece code value", }, @@ -179,7 +182,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "TCP monitoring enabled if set as true", }, @@ -195,7 +198,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -203,7 +206,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -211,7 +214,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -219,7 +222,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -227,7 +230,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -235,7 +238,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -244,7 +247,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly/Hourly only @@ -253,7 +256,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly/Hourly only @@ -262,7 +265,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only. For controlling datacenter restricted port speed @@ -286,7 +289,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Optional: true, Computed: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Monthly only @@ -296,7 +299,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { ForceNew: true, //Sometime memory returns back as different. Since this resource is immutable at this point //and memory can't be really updated , suppress the change until we figure out how to handle it - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Computed: true, }, // Monthly only @@ -329,7 +332,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { }, }, }, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Quote based provisioning only @@ -337,7 +340,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Quote ID for Quote based provisioning", }, @@ -397,7 +400,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, - ValidateFunc: validateSecondaryIPCount, + ValidateFunc: validate.ValidateSecondaryIPCount, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { // secondary_ip_count is only used when a virtual_guest resource is created. if d.State() == nil { @@ -435,7 +438,7 @@ func resourceIBMComputeBareMetal() *schema.Resource { Description: "boolean value true if ipv6 static is enabled else false", }, - "global_identifier": &schema.Schema{ + "global_identifier": { Description: "The unique global identifier of the bare metal server", Type: schema.TypeString, Computed: true, @@ -489,7 +492,7 @@ func getBareMetalOrderFromResourceData(d *schema.ResourceData, meta interface{}) subnet := public_subnet.(string) subnetID, err := getSubnetID(subnet, meta) if err != nil { - return hardware, fmt.Errorf("Error determining id for subnet %s: %s", subnet, err) + return hardware, fmt.Errorf("[ERROR] Error determining id for subnet %s: %s", subnet, err) } hardware.PrimaryNetworkComponent.NetworkVlan.PrimarySubnetId = sl.Int(subnetID) @@ -499,7 +502,7 @@ func getBareMetalOrderFromResourceData(d *schema.ResourceData, meta interface{}) subnet := private_subnet.(string) subnetID, err := getSubnetID(subnet, meta) if err != nil { - return hardware, fmt.Errorf("Error determining id for subnet %s: %s", subnet, err) + return hardware, fmt.Errorf("[ERROR] Error determining id for subnet %s: %s", subnet, err) } hardware.PrimaryBackendNetworkComponent.NetworkVlan.PrimarySubnetId = sl.Int(subnetID) @@ -526,7 +529,7 @@ func getBareMetalOrderFromResourceData(d *schema.ResourceData, meta interface{}) } func resourceIBMComputeBareMetalCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() hwService := services.GetHardwareService(sess) var order datatypes.Container_Product_Order var err error @@ -601,14 +604,13 @@ func resourceIBMComputeBareMetalCreate(d *schema.ResourceData, meta interface{}) order, err = setCommonBareMetalOrderOptions(d, meta, order) if err != nil { - return fmt.Errorf( - "Encountered problem trying to configure bare metal server options: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to configure bare metal server options: %s", err) } log.Println("[INFO] Ordering bare metal server") orderReceipt, err := services.GetProductOrderService(sess.SetRetries(0)).PlaceOrder(&order, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error ordering bare metal server: %s\n%+v\n", err, order) + return fmt.Errorf("[ERROR] Error ordering bare metal server: %s\n%+v\n", err, order) } gID := *orderReceipt.OrderDetails.Hardware[0].GlobalIdentifier @@ -619,8 +621,7 @@ func resourceIBMComputeBareMetalCreate(d *schema.ResourceData, meta interface{}) // wait for machine availability bm, err := waitForBareMetalProvision(&hardware, d, meta, gID) if err != nil { - return fmt.Errorf( - "Error waiting for bare metal server (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for bare metal server (%s) to become ready: %s", d.Id(), err) } id := *bm.(datatypes.Hardware).Id @@ -636,11 +637,11 @@ func resourceIBMComputeBareMetalCreate(d *schema.ResourceData, meta interface{}) var storageIds []int if storageIdsSet := d.Get("file_storage_ids").(*schema.Set); len(storageIdsSet.List()) > 0 { - storageIds = expandIntList(storageIdsSet.List()) + storageIds = flex.ExpandIntList(storageIdsSet.List()) } if storageIdsSet := d.Get("block_storage_ids").(*schema.Set); len(storageIdsSet.List()) > 0 { - storageIds = append(storageIds, expandIntList(storageIdsSet.List())...) + storageIds = append(storageIds, flex.ExpandIntList(storageIdsSet.List())...) } if len(storageIds) > 0 { err := addAccessToStorageList(hwService.Id(id), id, storageIds, meta) @@ -661,11 +662,11 @@ func resourceIBMComputeBareMetalCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) error { - service := services.GetHardwareService(meta.(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).Mask( @@ -686,7 +687,7 @@ func resourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) e ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving bare metal server: %s", err) + return fmt.Errorf("[ERROR] Error retrieving bare metal server: %s", err) } d.Set("hostname", *result.Hostname) @@ -745,7 +746,7 @@ func resourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) e ).Id(id).GetBackendNetworkComponents() if err != nil { - return fmt.Errorf("Error retrieving bare metal server network: %s", err) + return fmt.Errorf("[ERROR] Error retrieving bare metal server network: %s", err) } if len(backendNetworkComponent) > 2 && result.PrimaryBackendNetworkComponent != nil { @@ -775,8 +776,8 @@ func resourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) e storages := result.AllowedNetworkStorage if len(storages) > 0 { - d.Set("block_storage_ids", flattenBlockStorageID(storages)) - d.Set("file_storage_ids", flattenFileStorageID(storages)) + d.Set("block_storage_ids", flex.FlattenBlockStorageID(storages)) + d.Set("file_storage_ids", flex.FlattenFileStorageID(storages)) } connInfo := map[string]string{"type": "ssh"} @@ -800,7 +801,7 @@ func resourceIBMComputeBareMetalRead(d *schema.ResourceData, meta interface{}) e func resourceIBMComputeBareMetalUpdate(d *schema.ResourceData, meta interface{}) error { id, _ := strconv.Atoi(d.Id()) - service := services.GetHardwareService(meta.(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(meta.(conns.ClientSession).SoftLayerSession()) if d.HasChange("tags") { err := setHardwareTags(id, d, meta) @@ -828,21 +829,21 @@ func resourceIBMComputeBareMetalDelete(d *schema.ResourceData, meta interface{}) } func deleteHardware(d dataRetriever, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetHardwareService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = waitForNoBareMetalActiveTransactions(id, meta) if err != nil { - return fmt.Errorf("Error deleting bare metal server while waiting for zero active transactions: %s", err) + return fmt.Errorf("[ERROR] Error deleting bare metal server while waiting for zero active transactions: %s", err) } billingItem, err := service.Id(id).GetBillingItem() if err != nil { - return fmt.Errorf("Error getting billing item for bare metal server: %s", err) + return fmt.Errorf("[ERROR] Error getting billing item for bare metal server: %s", err) } // Monthly bare metal servers only support an anniversary date cancellation option. @@ -851,24 +852,24 @@ func deleteHardware(d dataRetriever, meta interface{}) error { sl.Bool(d.Get("hourly_billing").(bool)), sl.Bool(true), sl.String("No longer required"), sl.String("Please cancel this server"), ) if err != nil { - return fmt.Errorf("Error canceling the bare metal server (%d): %s", id, err) + return fmt.Errorf("[ERROR] Error canceling the bare metal server (%d): %s", id, err) } return nil } func resourceIBMComputeBareMetalExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetHardwareService(meta.(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { if apiErr, ok := err.(sl.Error); !ok || apiErr.StatusCode != 404 { - return false, fmt.Errorf("Error trying to retrieve the Bare Metal server: %s", err) + return false, fmt.Errorf("[ERROR] Error trying to retrieve the Bare Metal server: %s", err) } } @@ -888,7 +889,7 @@ func waitForBareMetalProvision(hw *datatypes.Hardware, d *schema.ResourceData, m Pending: []string{"retry", "pending"}, Target: []string{"provisioned"}, Refresh: func() (interface{}, string, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) bms, err := service.Filter( filter.Build( @@ -908,7 +909,7 @@ func waitForBareMetalProvision(hw *datatypes.Hardware, d *schema.ResourceData, m Filter(filter.Build(filter.Path("publicSubnets.endPointIpAddress.hardware.id").Eq(bms[0].Id))). GetPublicSubnets() if err != nil { - return nil, "", fmt.Errorf("Error retrieving secondary ip address: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving secondary ip address: %s", err) } if len(secondarySubnetResult) == 0 { return datatypes.Hardware{}, "pending", nil @@ -929,7 +930,7 @@ func waitForBareMetalProvision(hw *datatypes.Hardware, d *schema.ResourceData, m func waitForNoBareMetalActiveTransactions(id int, meta interface{}) (interface{}, error) { log.Printf("Waiting for server (%d) to have zero active transactions", id) - service := services.GetHardwareServerService(meta.(ClientSession).SoftLayerSession()) + service := services.GetHardwareServerService(meta.(conns.ClientSession).SoftLayerSession()) stateConf := &resource.StateChangeConf{ Pending: []string{"retry", "active"}, @@ -956,19 +957,19 @@ func waitForNoBareMetalActiveTransactions(id int, meta interface{}) (interface{} } func setHardwareTags(id int, d dataRetriever, meta interface{}) error { - service := services.GetHardwareService(meta.(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(meta.(conns.ClientSession).SoftLayerSession()) tags := getTags(d) _, err := service.Id(id).SetTags(sl.String(tags)) if err != nil { - return fmt.Errorf("Could not set tags on bare metal server %d", id) + return fmt.Errorf("[ERROR] Could not set tags on bare metal server %d", id) } return nil } func setHardwareNotes(id int, d dataRetriever, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetHardwareServerService(sess) result, err := service.Id(id).GetObject() @@ -1032,11 +1033,11 @@ func getItemPriceId(items []datatypes.Product_Item, categoryCode string, keyName } } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find the matching item with categorycode %s and keyName %s. Available item(s) is(are) %s", categoryCode, keyName, availableItems) + fmt.Errorf("[ERROR] Could not find the matching item with categorycode %s and keyName %s. Available item(s) is(are) %s", categoryCode, keyName, availableItems) } func getMonthlyBareMetalOrder(d *schema.ResourceData, meta interface{}) (datatypes.Container_Product_Order, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Validate attributes for monthly bare metal server ordering. if d.Get("hourly_billing").(bool) { return datatypes.Container_Product_Order{}, fmt.Errorf("Monthly bare metal server only supports monthly billing.") @@ -1044,17 +1045,17 @@ func getMonthlyBareMetalOrder(d *schema.ResourceData, meta interface{}) (datatyp model, ok := d.GetOk("package_key_name") if !ok { - return datatypes.Container_Product_Order{}, fmt.Errorf("The attribute 'package_key_name' is not defined.") + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] The attribute 'package_key_name' is not defined.") } datacenter, ok := d.GetOk("datacenter") if !ok { - return datatypes.Container_Product_Order{}, fmt.Errorf("The attribute 'datacenter' is not defined.") + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] The attribute 'datacenter' is not defined.") } osKeyName, ok := d.GetOk("os_key_name") if !ok { - return datatypes.Container_Product_Order{}, fmt.Errorf("The attribute 'os_key_name' is not defined.") + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] The attribute 'os_key_name' is not defined.") } dc, err := location.GetDatacenterByName(sess, datacenter.(string), "id") @@ -1222,7 +1223,7 @@ func setMonthlyHourlyCommonOrder(d *schema.ResourceData, items []datatypes.Produ privateNetworkOnly := d.Get("private_network_only").(bool) if secondaryIPCount > 0 { if privateNetworkOnly { - return fmt.Errorf("Unable to configure public secondary addresses with a private_network_only option") + return fmt.Errorf("[ERROR] Unable to configure public secondary addresses with a private_network_only option") } keyName := strconv.Itoa(secondaryIPCount) + "_PUBLIC_IP_ADDRESSES" @@ -1235,7 +1236,7 @@ func setMonthlyHourlyCommonOrder(d *schema.ResourceData, items []datatypes.Produ if d.Get("ipv6_enabled").(bool) { if privateNetworkOnly { - return fmt.Errorf("Unable to configure a public IPv6 address with a private_network_only option") + return fmt.Errorf("[ERROR] Unable to configure a public IPv6 address with a private_network_only option") } keyName := "1_IPV6_ADDRESS" @@ -1248,7 +1249,7 @@ func setMonthlyHourlyCommonOrder(d *schema.ResourceData, items []datatypes.Produ if d.Get("ipv6_static_enabled").(bool) { if privateNetworkOnly { - return fmt.Errorf("Unable to configure a public static IPv6 address with a private_network_only option") + return fmt.Errorf("[ERROR] Unable to configure a public static IPv6 address with a private_network_only option") } keyName := "64_BLOCK_STATIC_PUBLIC_IPV6_ADDRESSES" @@ -1285,7 +1286,7 @@ func setCommonBareMetalOrderOptions(d *schema.ResourceData, meta interface{}, or subnet := public_subnet.(string) subnetId, err := getSubnetId(subnet, meta) if err != nil { - return datatypes.Container_Product_Order{}, fmt.Errorf("Error determining id for subnet %s: %s", subnet, err) + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] Error determining id for subnet %s: %s", subnet, err) } order.Hardware[0].PrimaryNetworkComponent.NetworkVlan.PrimarySubnetId = sl.Int(subnetId) @@ -1295,7 +1296,7 @@ func setCommonBareMetalOrderOptions(d *schema.ResourceData, meta interface{}, or subnet := private_subnet.(string) subnetId, err := getSubnetId(subnet, meta) if err != nil { - return datatypes.Container_Product_Order{}, fmt.Errorf("Error determining id for subnet %s: %s", subnet, err) + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] Error determining id for subnet %s: %s", subnet, err) } order.Hardware[0].PrimaryBackendNetworkComponent.NetworkVlan.PrimarySubnetId = sl.Int(subnetId) @@ -1388,7 +1389,7 @@ func findNetworkItemPriceId(items []datatypes.Product_Item, d dataRetriever) (da } } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find the network with %s, %s, %s, and private_network_only = %t", + fmt.Errorf("[ERROR] Could not find the network with %s, %s, %s, and private_network_only = %t", networkSpeedStr, redundantNetworkStr, unbondedNetworkStr, privateNetworkOnly) } @@ -1413,7 +1414,7 @@ func findMemoryItemPriceId(items []datatypes.Product_Item, d dataRetriever) (dat } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find the price item for %d GB memory. Available items are %s", memory, availableMemories) + fmt.Errorf("[ERROR] Could not find the price item for %d GB memory. Available items are %s", memory, availableMemories) } // Find a bare metal package object using a package key name @@ -1445,7 +1446,7 @@ func getPackageByModel(sess *session.Session, model string) (datatypes.Product_P } } - return datatypes.Product_Package{}, fmt.Errorf("No custom bare metal package key name for %s. Available package key name(s) is(are) %s", model, availableModels) + return datatypes.Product_Package{}, fmt.Errorf("[ERROR] No custom bare metal package key name for %s. Available package key name(s) is(are) %s", model, availableModels) } func getStorageGroupsFromResourceData(d dataRetriever) []datatypes.Container_Product_Order_Storage_Group { @@ -1474,14 +1475,6 @@ func getStorageGroupsFromResourceData(d dataRetriever) []datatypes.Container_Pro return storageGroups } -// Use this function for attributes which only should be applied in resource creation time. -func applyOnce(k, o, n string, d *schema.ResourceData) bool { - if len(d.Id()) == 0 { - return false - } - return true -} - func addCommomDefaultPrices(d *schema.ResourceData, meta interface{}, order datatypes.Container_Product_Order, items []datatypes.Product_Item) datatypes.Container_Product_Order { if !d.Get("tcp_monitoring").(bool) { diff --git a/ibm/resource_ibm_compute_bare_metal_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal_test.go similarity index 93% rename from ibm/resource_ibm_compute_bare_metal_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal_test.go index fc4152206..38453eb50 100644 --- a/ibm/resource_ibm_compute_bare_metal_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_bare_metal_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,8 +26,8 @@ func TestAccIBMComputeBareMetal_Basic(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -80,8 +83,8 @@ func TestAccIBMComputeBareMetal_With_IPV6(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -139,8 +142,8 @@ func TestAccIBMComputeBareMetal_With_Unbonded_Port_Speed(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -185,8 +188,8 @@ func TestAccIBMComputeBareMetal_With_Network_Storage_Access(t *testing.T) { configInstance := "ibm_compute_bare_metal.terraform-bm-storage-access" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -229,8 +232,8 @@ func TestAccSoftLayerBareMetalQuote_Basic(t *testing.T) { domain := "bm.quote.tfuat.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -260,8 +263,8 @@ func TestAccSoftLayerBareMetalCustom_Basic(t *testing.T) { domain := "bm.custom.tfuat.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -287,8 +290,8 @@ func TestAccSoftLayerBareMetalCustom_with_gpus(t *testing.T) { domain := "bm.custom.tfuat.gpus.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -314,8 +317,8 @@ func TestAccSoftLayerBareMetalCustom_with_monitoring_none(t *testing.T) { domain := "bm.custom.tfuat.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeBareMetalDestroy, Steps: []resource.TestStep{ { @@ -332,7 +335,7 @@ func TestAccSoftLayerBareMetalCustom_with_monitoring_none(t *testing.T) { } func testAccCheckIBMComputeBareMetalDestroy(s *terraform.State) error { - service := services.GetHardwareService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_bare_metal" { @@ -347,8 +350,7 @@ func testAccCheckIBMComputeBareMetalDestroy(s *terraform.State) error { // Wait if err != nil { if apiErr, ok := err.(sl.Error); !ok || apiErr.StatusCode != 404 { - return fmt.Errorf( - "Error waiting for bare metal (%d) to be destroyed: %s", + return fmt.Errorf("[ERROR] Error waiting for bare metal (%d) to be destroyed: %s", id, err) } } @@ -361,7 +363,7 @@ func testAccCheckIBMComputeBareMetalExists(n string, bareMetal *datatypes.Hardwa return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -374,7 +376,7 @@ func testAccCheckIBMComputeBareMetalExists(n string, bareMetal *datatypes.Hardwa return err } - service := services.GetHardwareService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetHardwareService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) bm, err := service.Id(id).GetObject() if err != nil { return err @@ -408,7 +410,7 @@ resource "ibm_compute_bare_metal" "terraform-acceptance-test-1" { tags = ["collectd"] notes = "baremetal notes" } -`, hostname, extendedHardwareTesting) +`, hostname, acc.ExtendedHardwareTesting) } func testAccCheckIBMComputeBareMetalConfig_update(hostname string) string { @@ -426,7 +428,7 @@ resource "ibm_compute_bare_metal" "terraform-acceptance-test-1" { fixed_config_preset = "S1270_32GB_1X1TBSATA_NORAID" tags = ["mesos-master"] } -`, hostname, extendedHardwareTesting) +`, hostname, acc.ExtendedHardwareTesting) } func testBareMetalAccessToStoragesBasic(hostname, domain string) string { diff --git a/ibm/resource_ibm_compute_dedicated_host.go b/ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host.go similarity index 82% rename from ibm/resource_ibm_compute_dedicated_host.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host.go index 94c605c6c..70e1b16d7 100644 --- a/ibm/resource_ibm_compute_dedicated_host.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -22,7 +23,7 @@ import ( var dedicatedHostPackageType = "DEDICATED_HOST" -func resourceIBMComputeDedicatedHost() *schema.Resource { +func ResourceIBMComputeDedicatedHost() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeDedicatedHostCreate, Read: resourceIBMComputeDedicatedHostRead, @@ -100,7 +101,7 @@ func resourceIBMComputeDedicatedHost() *schema.Resource { } func resourceIBMComputeDedicatedHostCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() pkg, err := product.GetPackageByType(sess, dedicatedHostPackageType) if err != nil { @@ -114,12 +115,12 @@ func resourceIBMComputeDedicatedHostCreate(d *schema.ResourceData, meta interfac // Lookup the data center ID dc, err := location.GetDatacenterByName(sess, datacenter) if err != nil { - return fmt.Errorf("No data centers matching %s could be found", datacenter) + return fmt.Errorf("[ERROR] No data centers matching %s could be found", datacenter) } rt, err := hardware.GetRouterByName(sess, router, "id") if err != nil { - return fmt.Errorf("Error creating dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error creating dedicated host: %s", err) } primaryBackendNetworkComponent := datatypes.Network_Component{ @@ -180,20 +181,19 @@ func resourceIBMComputeDedicatedHostCreate(d *schema.ResourceData, meta interfac _, err = services.GetProductOrderService(sess.SetRetries(0)). VerifyOrder(&productOrderContainer) if err != nil { - return fmt.Errorf("Error during creation of dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated host: %s", err) } //place order _, err = services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated host: %s", err) } // wait for machine availability dedicated, err := findDedicatedHostByOrderID(&hardware, d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for dedicated host (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for dedicated host (%s) to become ready: %s", d.Id(), err) } id := *dedicated.(datatypes.Virtual_DedicatedHost).Id @@ -202,11 +202,11 @@ func resourceIBMComputeDedicatedHostCreate(d *schema.ResourceData, meta interfac } func resourceIBMComputeDedicatedHostRead(d *schema.ResourceData, meta interface{}) error { - service := services.GetVirtualDedicatedHostService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualDedicatedHostService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).Mask( @@ -214,7 +214,7 @@ func resourceIBMComputeDedicatedHostRead(d *schema.ResourceData, meta interface{ ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error retrieving dedicated host: %s", err) } d.Set("hostname", result.Name) @@ -228,24 +228,24 @@ func resourceIBMComputeDedicatedHostRead(d *schema.ResourceData, meta interface{ func resourceIBMComputeDedicatedHostUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualDedicatedHostService(sess.SetRetries(0)) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { - return fmt.Errorf("Error retrieving dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error retrieving dedicated host: %s", err) } if d.HasChange("hostname") { result.Name = sl.String(d.Get("hostname").(string)) _, err = service.Id(id).EditObject(&result) if err != nil { - return fmt.Errorf("Couldn't update dedicated host: %s", err) + return fmt.Errorf("[ERROR] Could n't update dedicated host: %s", err) } } @@ -253,17 +253,17 @@ func resourceIBMComputeDedicatedHostUpdate(d *schema.ResourceData, meta interfac } func resourceIBMComputeDedicatedHostDelete(d *schema.ResourceData, meta interface{}) error { - service := services.GetVirtualDedicatedHostService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualDedicatedHostService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } ok, err := service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting dedicated host: %s", err) + return fmt.Errorf("[ERROR] Error deleting dedicated host: %s", err) } if !ok { @@ -276,10 +276,10 @@ func resourceIBMComputeDedicatedHostDelete(d *schema.ResourceData, meta interfac } func resourceIBMComputeDedicatedHostExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetVirtualDedicatedHostService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualDedicatedHostService(meta.(conns.ClientSession).SoftLayerSession()) dedicatedID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(dedicatedID).GetObject() @@ -289,7 +289,7 @@ func resourceIBMComputeDedicatedHostExists(d *schema.ResourceData, meta interfac return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute dedicated hosts: %s", err) } return result.Id != nil && *result.Id == dedicatedID, nil @@ -304,7 +304,7 @@ func findDedicatedHostByOrderID(d *datatypes.Hardware, r *schema.ResourceData, m Pending: []string{"retry", "pending"}, Target: []string{"provisioned"}, Refresh: func() (interface{}, string, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) dedicatedHosts, err := service.Filter( filter.Build( filter.Path("dedicatedHosts.name").Eq(hostname), diff --git a/ibm/resource_ibm_compute_dedicated_host_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host_test.go similarity index 91% rename from ibm/resource_ibm_compute_dedicated_host_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host_test.go index 5fea5cecc..b6888497a 100644 --- a/ibm/resource_ibm_compute_dedicated_host_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_dedicated_host_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -22,11 +25,11 @@ func TestAccIBMComputeDedicatedHost_Basic(t *testing.T) { updatedHostname := fmt.Sprintf("terraformuat_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputerDedicatedHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeDedicatedHostConfigBasic(hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeDedicatedHostExists("ibm_compute_dedicated_host.dedicatedHourly", &dedicatedHost), @@ -49,7 +52,7 @@ func TestAccIBMComputeDedicatedHost_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeDedicatedHostConfigUpdated(updatedHostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeDedicatedHostExists("ibm_compute_dedicated_host.dedicatedHourly", &dedicatedHost), @@ -80,11 +83,11 @@ func TestAccIBMComputerDedicatedHostWithTag(t *testing.T) { hostname := fmt.Sprintf("terraformuat_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputerDedicatedHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeDedicatedHostWithTag(hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeDedicatedHostExists("ibm_compute_dedicated_host.dedicatedMonthly", &dedicatedHost), @@ -109,7 +112,7 @@ func TestAccIBMComputerDedicatedHostWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeDedicatedHostWithUpdateTag(hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeDedicatedHostExists("ibm_compute_dedicated_host.dedicatedMonthly", &dedicatedHost), @@ -141,11 +144,11 @@ func TestAccIBMComputeDedicatedHostImport(t *testing.T) { var dedicatedHost datatypes.Virtual_DedicatedHost hostname := fmt.Sprintf("terraformuat_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputerDedicatedHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeDedicatedHostImport(hostname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeDedicatedHostExists("ibm_compute_dedicated_host.import", &dedicatedHost), @@ -168,7 +171,7 @@ func TestAccIBMComputeDedicatedHostImport(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_compute_dedicated_host.import", ImportState: true, ImportStateVerify: true, @@ -183,7 +186,7 @@ func TestAccIBMComputeDedicatedHostImport(t *testing.T) { } func testAccCheckIBMComputerDedicatedHostDestroy(s *terraform.State) error { - service := services.GetVirtualDedicatedHostService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualDedicatedHostService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_dedicated_host" { @@ -198,7 +201,7 @@ func testAccCheckIBMComputerDedicatedHostDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Dedicated host still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for dedicated host (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for dedicated host (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -210,16 +213,16 @@ func testAccCheckIBMComputeDedicatedHostExists(n string, dedicatedHost *datatype rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } dedicatedID, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetVirtualDedicatedHostService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualDedicatedHostService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) result, err := service.Id(dedicatedID).GetObject() if err != nil { return err diff --git a/ibm/resource_ibm_compute_monitor.go b/ibm/service/classicinfrastructure/resource_ibm_compute_monitor.go similarity index 85% rename from ibm/resource_ibm_compute_monitor.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_monitor.go index 764c25d49..c016d23b4 100644 --- a/ibm/resource_ibm_compute_monitor.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_monitor.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,13 +9,14 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeMonitor() *schema.Resource { +func ResourceIBMComputeMonitor() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeMonitorCreate, Read: resourceIBMComputeMonitorRead, @@ -77,7 +78,7 @@ func resourceIBMComputeMonitor() *schema.Resource { } func resourceIBMComputeMonitorCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() virtualGuestService := services.GetVirtualGuestService(sess) monitorService := services.GetNetworkMonitorVersion1QueryHostService(sess.SetRetries(0)) @@ -86,7 +87,7 @@ func resourceIBMComputeMonitorCreate(d *schema.ResourceData, meta interface{}) e if ipAddress == "" { virtualGuest, err := virtualGuestService.Id(guestId).GetObject() if err != nil { - return fmt.Errorf("Error looking up virtual guest %d: %s", guestId, err) + return fmt.Errorf("[ERROR] Error looking up virtual guest %d: %s", guestId, err) } if virtualGuest.PrimaryIpAddress == nil { @@ -111,7 +112,7 @@ func resourceIBMComputeMonitorCreate(d *schema.ResourceData, meta interface{}) e // Create a monitor res, err := monitorService.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Basic Monitor : %s", err) + return fmt.Errorf("[ERROR] Error creating Basic Monitor : %s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -126,7 +127,7 @@ func resourceIBMComputeMonitorCreate(d *schema.ResourceData, meta interface{}) e } func createNotifications(d *schema.ResourceData, meta interface{}, guestId int) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() virtualGuestService := services.GetVirtualGuestService(sess) notificationService := services.GetUserCustomerNotificationVirtualGuestService(sess.SetRetries(0)) @@ -134,7 +135,7 @@ func createNotifications(d *schema.ResourceData, meta interface{}, guestId int) // This represents a link between a monitored guest instance and a user account notificationLinks, err := virtualGuestService.Id(guestId).GetMonitoringUserNotification() if err != nil { - return fmt.Errorf("Error looking up user notifications for virtual guest %d", guestId) + return fmt.Errorf("[ERROR] Error looking up user notifications for virtual guest %d", guestId) } userNotificationOpts := datatypes.User_Customer_Notification_Virtual_Guest{ @@ -147,7 +148,7 @@ func createNotifications(d *schema.ResourceData, meta interface{}, guestId int) if !notificationExists(notificationLinks, userId.(int)) { _, err := notificationService.CreateObject(&userNotificationOpts) if err != nil { - return fmt.Errorf("Error creating notification for userID %d: %v", *userNotificationOpts.UserId, err) + return fmt.Errorf("[ERROR] Error creating notification for userID %d: %v", *userNotificationOpts.UserId, err) } } } @@ -167,7 +168,7 @@ func notificationExists(notificationLinks []datatypes.User_Customer_Notification func resourceIBMComputeMonitorRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkMonitorVersion1QueryHostService(sess) virtualGuestService := services.GetVirtualGuestService(sess) @@ -182,7 +183,7 @@ func resourceIBMComputeMonitorRead(d *schema.ResourceData, meta interface{}) err return nil } - return fmt.Errorf("Error retrieving Basic Monitor : %s", err) + return fmt.Errorf("[ERROR] Error retrieving Basic Monitor : %s", err) } guestId := *basicMonitor.GuestId @@ -195,7 +196,7 @@ func resourceIBMComputeMonitorRead(d *schema.ResourceData, meta interface{}) err notificationLinks, err := virtualGuestService.Id(guestId).GetMonitoringUserNotification() if err != nil { - return fmt.Errorf("Error looking up user notifications for virtual guest %d", guestId) + return fmt.Errorf("[ERROR] Error looking up user notifications for virtual guest %d", guestId) } notificationUserIds := schema.NewSet(func(v interface{}) int { return v.(int) }, make([]interface{}, 0, len(notificationLinks))) @@ -228,7 +229,7 @@ func resourceIBMComputeMonitorRead(d *schema.ResourceData, meta interface{}) err func resourceIBMComputeMonitorUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() serviceNoRetry := services.GetNetworkMonitorVersion1QueryHostService(sess.SetRetries(0)) service := services.GetNetworkMonitorVersion1QueryHostService(sess) @@ -237,7 +238,7 @@ func resourceIBMComputeMonitorUpdate(d *schema.ResourceData, meta interface{}) e basicMonitor, err := service.Id(basicMonitorId).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Basic Monitor : %s", err) + return fmt.Errorf("[ERROR] Error retrieving Basic Monitor : %s", err) } if d.HasChange("query_type_id") { basicMonitor.QueryTypeId = sl.Int(d.Get("query_type_id").(int)) @@ -251,7 +252,7 @@ func resourceIBMComputeMonitorUpdate(d *schema.ResourceData, meta interface{}) e _, err = serviceNoRetry.Id(basicMonitorId).EditObject(&basicMonitor) if err != nil { - return fmt.Errorf("Error editing Basic Monitor : %s", err) + return fmt.Errorf("[ERROR] Error editing Basic Monitor : %s", err) } // Will only create notification objects for user/vm relationships that @@ -265,7 +266,7 @@ func resourceIBMComputeMonitorUpdate(d *schema.ResourceData, meta interface{}) e } func resourceIBMComputeMonitorDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkMonitorVersion1QueryHostService(sess) // Delete the basic monitor @@ -274,7 +275,7 @@ func resourceIBMComputeMonitorDelete(d *schema.ResourceData, meta interface{}) e log.Printf("[INFO] Deleting Basic Monitor : %d", id) _, err = service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Basic Monitor : %s", err) + return fmt.Errorf("[ERROR] Error deleting Basic Monitor : %s", err) } d.SetId("") @@ -282,12 +283,12 @@ func resourceIBMComputeMonitorDelete(d *schema.ResourceData, meta interface{}) e } func resourceIBMComputeMonitorExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkMonitorVersion1QueryHostService(sess) basicMonitorId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(basicMonitorId).GetObject() @@ -297,7 +298,7 @@ func resourceIBMComputeMonitorExists(d *schema.ResourceData, meta interface{}) ( return false, nil } } - return false, fmt.Errorf("Error retrieving basic monitor info: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving basic monitor info: %s", err) } return *result.Id == basicMonitorId, nil } diff --git a/ibm/resource_ibm_compute_monitor_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_monitor_test.go similarity index 94% rename from ibm/resource_ibm_compute_monitor_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_monitor_test.go index 158d2ab7e..8ccc5ea44 100644 --- a/ibm/resource_ibm_compute_monitor_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_monitor_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -10,6 +10,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -35,8 +38,8 @@ func TestAccIBMComputeMonitor_Basic(t *testing.T) { notifiedUsers := []int{6575505} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeMonitorDestroy, Steps: []resource.TestStep{ { @@ -93,8 +96,8 @@ func TestAccIBMComputeMonitorWithTag(t *testing.T) { notifiedUsers := []int{6575505} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeMonitorDestroy, Steps: []resource.TestStep{ { @@ -129,7 +132,7 @@ func TestAccIBMComputeMonitorWithTag(t *testing.T) { } func testAccCheckIBMComputeMonitorDestroy(s *terraform.State) error { - service := services.GetNetworkMonitorVersion1QueryHostService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkMonitorVersion1QueryHostService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_monitor" { @@ -155,7 +158,7 @@ func testAccCheckIBMComputeMonitorExists(n string, basicMonitor *datatypes.Netwo rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -164,7 +167,7 @@ func testAccCheckIBMComputeMonitorExists(n string, basicMonitor *datatypes.Netwo basicMonitorId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkMonitorVersion1QueryHostService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkMonitorVersion1QueryHostService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundBasicMonitor, err := service.Id(basicMonitorId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_placement_group.go b/ibm/service/classicinfrastructure/resource_ibm_compute_placement_group.go similarity index 83% rename from ibm/resource_ibm_compute_placement_group.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_placement_group.go index 5397bf10a..c23463755 100644 --- a/ibm/resource_ibm_compute_placement_group.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_placement_group.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -12,6 +12,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/filter" @@ -21,7 +23,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputePlacementGroup() *schema.Resource { +func ResourceIBMComputePlacementGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputePlacementGroupCreate, Read: resourceIBMComputePlacementGroupRead, @@ -63,7 +65,7 @@ func resourceIBMComputePlacementGroup() *schema.Resource { Optional: true, Default: "SPREAD", ForceNew: true, - ValidateFunc: validateAllowedStringValue([]string{"SPREAD"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"SPREAD"}), Description: "Rule info", }, @@ -79,7 +81,7 @@ func resourceIBMComputePlacementGroup() *schema.Resource { } func resourceIBMComputePlacementGroupCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() name := d.Get("name").(string) datacenter := d.Get("datacenter").(string) pod := d.Get("pod").(string) @@ -91,7 +93,7 @@ func resourceIBMComputePlacementGroupCreate(d *schema.ResourceData, meta interfa // 1.Getting the router ID routerids, err := PodService.Filter(filter.Path("datacenterName").Eq(datacenter).Build()).Mask(podMask).GetAllObjects() if err != nil { - return fmt.Errorf("Encountered problem trying to get the router ID: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the router ID: %s", err) } var routerid int for _, iterate := range routerids { @@ -105,7 +107,7 @@ func resourceIBMComputePlacementGroupCreate(d *schema.ResourceData, meta interfa Mask("id,name"). Filter(filter.Path("name").Eq(rule).Build()).GetObject() if err != nil { - return fmt.Errorf("Encountered problem trying to get the placement group rule ID: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the placement group rule ID: %s", err) } opts := datatypes.Virtual_PlacementGroup{ @@ -118,7 +120,7 @@ func resourceIBMComputePlacementGroupCreate(d *schema.ResourceData, meta interfa pgrp, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Placement Group: %s", err) + return fmt.Errorf("[ERROR] Error creating Placement Group: %s", err) } d.SetId(strconv.Itoa(*pgrp.Id)) @@ -128,7 +130,7 @@ func resourceIBMComputePlacementGroupCreate(d *schema.ResourceData, meta interfa } func resourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualPlacementGroupService(sess) pgrpID, _ := strconv.Atoi(d.Id()) @@ -141,7 +143,7 @@ func resourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interface return nil } } - return fmt.Errorf("Error retrieving Placement Group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Placement Group: %s", err) } d.Set("name", pgrp.Name) @@ -156,7 +158,7 @@ func resourceIBMComputePlacementGroupRead(d *schema.ResourceData, meta interface } func resourceIBMComputePlacementGroupUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualPlacementGroupService(sess.SetRetries(0)) pgrpID, _ := strconv.Atoi(d.Id()) @@ -168,7 +170,7 @@ func resourceIBMComputePlacementGroupUpdate(d *schema.ResourceData, meta interfa _, err := service.Id(pgrpID).EditObject(&opts) if err != nil { - return fmt.Errorf("Error editing Placement Group: %s", err) + return fmt.Errorf("[ERROR] Error editing Placement Group: %s", err) } } @@ -177,12 +179,12 @@ func resourceIBMComputePlacementGroupUpdate(d *schema.ResourceData, meta interfa func resourceIBMComputePlacementGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualPlacementGroupService(sess) pgrpID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(pgrpID).GetObject() @@ -192,13 +194,13 @@ func resourceIBMComputePlacementGroupExists(d *schema.ResourceData, meta interfa return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute placement group: %s", err) } return result.Id != nil && *result.Id == pgrpID, nil } func resourceIBMComputePlacementGroupDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualPlacementGroupService(sess) pgrpID, err := strconv.Atoi(d.Id()) @@ -235,7 +237,7 @@ func resourceIBMComputePlacementGroupDelete(d *schema.ResourceData, meta interfa _, err = service.Id(pgrpID).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Placement Group: %s", err) + return fmt.Errorf("[ERROR] Error deleting Placement Group: %s", err) } return nil diff --git a/ibm/resource_ibm_compute_placement_group_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_placement_group_test.go similarity index 88% rename from ibm/resource_ibm_compute_placement_group_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_placement_group_test.go index 4edf58231..0c02d593f 100644 --- a/ibm/resource_ibm_compute_placement_group_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_placement_group_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,11 +26,11 @@ func TestAccIBMComputePlacementGroup_Basic(t *testing.T) { group2 := fmt.Sprintf("%s%s", "tfuatpgrp", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputePlacementGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupConfig(group1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputePlacementGroupExists("ibm_compute_placement_group.placementGroup", &group), @@ -42,7 +45,7 @@ func TestAccIBMComputePlacementGroup_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupUpdate(group2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputePlacementGroupExists("ibm_compute_placement_group.placementGroup", &group), @@ -66,11 +69,11 @@ func TestAccIBMComputePlacementGroupWithTag(t *testing.T) { group1 := fmt.Sprintf("%s%s", "tfuatpgrp", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputePlacementGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupWithTag(group1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputePlacementGroupExists("ibm_compute_placement_group.placementGroup", &group), @@ -85,7 +88,7 @@ func TestAccIBMComputePlacementGroupWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupWithUpdatedTag(group1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputePlacementGroupExists("ibm_compute_placement_group.placementGroup", &group), @@ -109,11 +112,11 @@ func TestAccIBMComputePlacementGroupImport(t *testing.T) { group1 := fmt.Sprintf("%s%s", "tfuatpgrp", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputePlacementGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputePlacementGroupConfig(group1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputePlacementGroupExists("ibm_compute_placement_group.placementGroup", &group), @@ -126,7 +129,7 @@ func TestAccIBMComputePlacementGroupImport(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_compute_placement_group.placementGroup", ImportState: true, ImportStateVerify: true, @@ -136,7 +139,7 @@ func TestAccIBMComputePlacementGroupImport(t *testing.T) { } func testAccCheckIBMComputePlacementGroupDestroy(s *terraform.State) error { - service := services.GetVirtualPlacementGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualPlacementGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_placement_group" { @@ -151,7 +154,7 @@ func testAccCheckIBMComputePlacementGroupDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Placement group still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for placement group (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for placement group (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -163,16 +166,16 @@ func testAccCheckIBMComputePlacementGroupExists(n string, pgrp *datatypes.Virtua rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } pgrpId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetVirtualPlacementGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualPlacementGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundpgrp, err := service.Id(pgrpId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_provisioning_hook.go b/ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook.go similarity index 78% rename from ibm/resource_ibm_compute_provisioning_hook.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook.go index a657ae38f..0e1bd2afc 100644 --- a/ibm/resource_ibm_compute_provisioning_hook.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,13 +9,14 @@ import ( "net/http" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeProvisioningHook() *schema.Resource { +func ResourceIBMComputeProvisioningHook() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeProvisioningHookCreate, Read: resourceIBMComputeProvisioningHookRead, @@ -25,13 +26,13 @@ func resourceIBMComputeProvisioningHook() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "Provision hook name", }, - "uri": &schema.Schema{ + "uri": { Type: schema.TypeString, Required: true, Description: "URI of the hook", @@ -49,7 +50,7 @@ func resourceIBMComputeProvisioningHook() *schema.Resource { } func resourceIBMComputeProvisioningHookCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetProvisioningHookService(sess.SetRetries(0)) opts := datatypes.Provisioning_Hook{ @@ -59,7 +60,7 @@ func resourceIBMComputeProvisioningHookCreate(d *schema.ResourceData, meta inter hook, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Provisioning Hook: %s", err) + return fmt.Errorf("[ERROR] Error creating Provisioning Hook: %s", err) } d.SetId(strconv.Itoa(*hook.Id)) @@ -69,7 +70,7 @@ func resourceIBMComputeProvisioningHookCreate(d *schema.ResourceData, meta inter } func resourceIBMComputeProvisioningHookRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetProvisioningHookService(sess) hookId, _ := strconv.Atoi(d.Id()) @@ -82,7 +83,7 @@ func resourceIBMComputeProvisioningHookRead(d *schema.ResourceData, meta interfa return nil } } - return fmt.Errorf("Error retrieving Provisioning Hook: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Provisioning Hook: %s", err) } d.Set("name", hook.Name) @@ -92,7 +93,7 @@ func resourceIBMComputeProvisioningHookRead(d *schema.ResourceData, meta interfa } func resourceIBMComputeProvisioningHookUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetProvisioningHookService(sess.SetRetries(0)) hookId, _ := strconv.Atoi(d.Id()) @@ -111,32 +112,32 @@ func resourceIBMComputeProvisioningHookUpdate(d *schema.ResourceData, meta inter _, err := service.Id(hookId).EditObject(&opts) if err != nil { - return fmt.Errorf("Error editing Provisioning Hook: %s", err) + return fmt.Errorf("[ERROR] Error editing Provisioning Hook: %s", err) } return nil } func resourceIBMComputeProvisioningHookDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetProvisioningHookService(sess) hookId, err := strconv.Atoi(d.Id()) log.Printf("[INFO] Deleting Provisioning Hook: %d", hookId) _, err = service.Id(hookId).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Provisioning Hook: %s", err) + return fmt.Errorf("[ERROR] Error deleting Provisioning Hook: %s", err) } return nil } func resourceIBMComputeProvisioningHookExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetProvisioningHookService(sess) hookId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(hookId).GetObject() @@ -146,7 +147,7 @@ func resourceIBMComputeProvisioningHookExists(d *schema.ResourceData, meta inter return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute provisioning hooks: %s", err) } return result.Id != nil && *result.Id == hookId, nil } diff --git a/ibm/resource_ibm_compute_provisioning_hook_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook_test.go similarity index 88% rename from ibm/resource_ibm_compute_provisioning_hook_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook_test.go index d71b98802..2ab136936 100644 --- a/ibm/resource_ibm_compute_provisioning_hook_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_provisioning_hook_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -24,11 +27,11 @@ func TestAccIBMComputeProvisioningHook_Basic(t *testing.T) { uri2 := "https://www.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeProvisioningHookDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeProvisioningHookConfig(hookName1, uri1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeProvisioningHookExists("ibm_compute_provisioning_hook.test-provisioning-hook", &hook), @@ -40,7 +43,7 @@ func TestAccIBMComputeProvisioningHook_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeProvisioningHookConfig(hookName2, uri2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeProvisioningHookExists("ibm_compute_provisioning_hook.test-provisioning-hook", &hook), @@ -61,11 +64,11 @@ func TestAccIBMComputeProvisioningHookWithTag(t *testing.T) { uri1 := "http://www.weather.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeProvisioningHookDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeProvisioningHookWithTag(hookName1, uri1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeProvisioningHookExists("ibm_compute_provisioning_hook.test-provisioning-hook", &hook), @@ -79,7 +82,7 @@ func TestAccIBMComputeProvisioningHookWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeProvisioningHookWithUpdatedTag(hookName1, uri1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeProvisioningHookExists("ibm_compute_provisioning_hook.test-provisioning-hook", &hook), @@ -96,7 +99,7 @@ func TestAccIBMComputeProvisioningHookWithTag(t *testing.T) { } func testAccCheckIBMComputeProvisioningHookDestroy(s *terraform.State) error { - service := services.GetProvisioningHookService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetProvisioningHookService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_provisioning_hook" { @@ -136,16 +139,16 @@ func testAccCheckIBMComputeProvisioningHookExists(n string, hook *datatypes.Prov rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } hookId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetProvisioningHookService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetProvisioningHookService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundHook, err := service.Id(hookId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_reserved_capacity.go b/ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity.go similarity index 85% rename from ibm/resource_ibm_compute_reserved_capacity.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity.go index 4ec929b3c..c5c3c9c55 100644 --- a/ibm/resource_ibm_compute_reserved_capacity.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "context" @@ -13,6 +13,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -25,7 +27,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeReservedCapacity() *schema.Resource { +func ResourceIBMComputeReservedCapacity() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMComputeReservedCapacityCreate, ReadContext: resourceIBMComputeReservedCapacityRead, @@ -33,6 +35,7 @@ func resourceIBMComputeReservedCapacity() *schema.Resource { DeleteContext: resourceIBMComputeReservedCapacityDelete, Exists: resourceIBMComputeReservedCapacityExists, Importer: &schema.ResourceImporter{}, + CustomizeDiff: resourceReservedCapacityValidate, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), @@ -81,12 +84,18 @@ func resourceIBMComputeReservedCapacity() *schema.Resource { Set: schema.HashString, Description: "List of tags", }, + "force_create": { + Type: schema.TypeBool, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Force the creation of reserved capacity with same name", + }, }, } } func resourceIBMComputeReservedCapacityCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() name := d.Get("name").(string) datacenter := d.Get("datacenter").(string) pod := d.Get("pod").(string) @@ -187,7 +196,7 @@ func findReservedCapacityByOrderID(name string, r *schema.ResourceData, meta int Pending: []string{"retry", "pending"}, Target: []string{"provisioned"}, Refresh: func() (interface{}, string, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) reservedCapacitys, err := service.Filter( filter.Build( filter.Path("reservedCapacityGroups.name").Eq(name), @@ -212,7 +221,7 @@ func findReservedCapacityByOrderID(name string, r *schema.ResourceData, meta int } func resourceIBMComputeReservedCapacityRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualReservedCapacityGroupService(sess) rgrpID, _ := strconv.Atoi(d.Id()) @@ -245,7 +254,7 @@ func resourceIBMComputeReservedCapacityRead(context context.Context, d *schema.R } func resourceIBMComputeReservedCapacityUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualReservedCapacityGroupService(sess) rgrpID, _ := strconv.Atoi(d.Id()) @@ -266,7 +275,7 @@ func resourceIBMComputeReservedCapacityUpdate(context context.Context, d *schema func resourceIBMComputeReservedCapacityExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualReservedCapacityGroupService(sess) rgrpID, err := strconv.Atoi(d.Id()) @@ -291,3 +300,22 @@ func resourceIBMComputeReservedCapacityDelete(context context.Context, d *schema d.SetId("") return nil } + +func resourceReservedCapacityValidate(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { + forceCreate := diff.Get("force_create").(bool) + if diff.Id() == "" && !forceCreate { + name := diff.Get("name").(string) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) + reservedCapacities, _ := service.Filter( + filter.Build( + filter.Path("reservedCapacityGroups.name").Eq(name), + ), + ).Mask("id,createDate").GetReservedCapacityGroups() + if len(reservedCapacities) > 0 { + return fmt.Errorf("reserved capacity exists with same name [%s] if you still want to provision with same name set force_create argument to true", name) + } + } + + return nil + +} diff --git a/ibm/resource_ibm_compute_reserved_capacity_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity_test.go similarity index 84% rename from ibm/resource_ibm_compute_reserved_capacity_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity_test.go index 5e03afdd7..c4e377489 100644 --- a/ibm/resource_ibm_compute_reserved_capacity_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_reserved_capacity_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,11 +26,11 @@ func TestAccIBMComputeReservedCapacity_Basic(t *testing.T) { group2 := fmt.Sprintf("%s%s", "tfuatreservedcapacity", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, //CheckDestroy: testAccCheckIBMComputeReservedCapacityDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeReservedCapacityConfig(group1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeReservedCapacityExists("ibm_compute_reserved_capacity.reservedCapacity", &group), @@ -42,7 +45,7 @@ func TestAccIBMComputeReservedCapacity_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeReservedCapacityUpdate(group2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeReservedCapacityExists("ibm_compute_reserved_capacity.reservedCapacity", &group), @@ -57,7 +60,7 @@ func TestAccIBMComputeReservedCapacity_Basic(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_compute_reserved_capacity.reservedCapacity", ImportState: true, ImportStateVerify: true, @@ -67,7 +70,7 @@ func TestAccIBMComputeReservedCapacity_Basic(t *testing.T) { } func testAccCheckIBMComputeReservedCapacityDestroy(s *terraform.State) error { - service := services.GetVirtualReservedCapacityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualReservedCapacityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_reserved_capacity" { @@ -82,7 +85,7 @@ func testAccCheckIBMComputeReservedCapacityDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Reserved Capacity still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for reserved capacity (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for reserved capacity (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -94,16 +97,16 @@ func testAccCheckIBMComputeReservedCapacityExists(n string, reservedcapacity *da rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } reservedcapacityId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetVirtualReservedCapacityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualReservedCapacityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundreservedcapacity, err := service.Id(reservedcapacityId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_ssh_key.go b/ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key.go similarity index 82% rename from ibm/resource_ibm_compute_ssh_key.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key.go index 3b299fbca..d26a6b371 100644 --- a/ibm/resource_ibm_compute_ssh_key.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "crypto/sha256" @@ -11,6 +11,7 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" @@ -18,7 +19,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeSSHKey() *schema.Resource { +func ResourceIBMComputeSSHKey() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeSSHKeyCreate, Read: resourceIBMComputeSSHKeyRead, @@ -69,7 +70,7 @@ func resourceIBMComputeSSHKey() *schema.Resource { } func resourceIBMComputeSSHKeyCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecuritySshKeyService(sess) // First check if the key exists by fingerprint @@ -126,7 +127,7 @@ func resourceIBMComputeSSHKeyCreate(d *schema.ResourceData, meta interface{}) er res, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating SSH Key: %s", err) + return fmt.Errorf("[ERROR] Error creating SSH Key: %s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -136,7 +137,7 @@ func resourceIBMComputeSSHKeyCreate(d *schema.ResourceData, meta interface{}) er } func resourceIBMComputeSSHKeyRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecuritySshKeyService(sess) keyID, _ := strconv.Atoi(d.Id()) @@ -148,7 +149,7 @@ func resourceIBMComputeSSHKeyRead(d *schema.ResourceData, meta interface{}) erro d.SetId("") return nil } - return fmt.Errorf("Error retrieving SSH key: %s", err) + return fmt.Errorf("[ERROR] Error retrieving SSH key: %s", err) } d.Set("label", key.Label) @@ -159,14 +160,14 @@ func resourceIBMComputeSSHKeyRead(d *schema.ResourceData, meta interface{}) erro } func resourceIBMComputeSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecuritySshKeyService(sess) keyID, _ := strconv.Atoi(d.Id()) key, err := service.Id(keyID).GetObject() if err != nil { - return fmt.Errorf("Error retrieving SSH key: %s", err) + return fmt.Errorf("[ERROR] Error retrieving SSH key: %s", err) } if d.HasChange("label") { @@ -179,24 +180,24 @@ func resourceIBMComputeSSHKeyUpdate(d *schema.ResourceData, meta interface{}) er _, err = service.Id(keyID).EditObject(&key) if err != nil { - return fmt.Errorf("Error editing SSH key: %s", err) + return fmt.Errorf("[ERROR] Error editing SSH key: %s", err) } return resourceIBMComputeSSHKeyRead(d, meta) } func resourceIBMComputeSSHKeyDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecuritySshKeyService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Error deleting SSH Key: %s", err) + return fmt.Errorf("[ERROR] Error deleting SSH Key: %s", err) } log.Printf("[INFO] Deleting SSH key: %d", id) _, err = service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting SSH key: %s", err) + return fmt.Errorf("[ERROR] Error deleting SSH key: %s", err) } d.SetId("") @@ -204,12 +205,12 @@ func resourceIBMComputeSSHKeyDelete(d *schema.ResourceData, meta interface{}) er } func resourceIBMComputeSSHKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecuritySshKeyService(sess) keyID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(keyID).GetObject() @@ -219,7 +220,7 @@ func resourceIBMComputeSSHKeyExists(d *schema.ResourceData, meta interface{}) (b return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute ssh key: %s", err) } return result.Id != nil && *result.Id == keyID, nil } @@ -227,11 +228,11 @@ func resourceIBMComputeSSHKeyExists(d *schema.ResourceData, meta interface{}) (b func computeSSHKeyFingerprint(key string) (fingerprint string, err error) { parts := strings.Fields(key) if len(parts) < 2 { - return "", fmt.Errorf("Invalid public key specified :%s\nPlease check the value of public_key", key) + return "", fmt.Errorf("[ERROR] Invalid public key specified :%s\nPlease check the value of public_key", key) } k, err := base64.StdEncoding.DecodeString(parts[1]) if err != nil { - return "", fmt.Errorf("Error decoding the public key: %s\nPlease check the value of public_key", err) + return "", fmt.Errorf("[ERROR] Error decoding the public key: %s\nPlease check the value of public_key", err) } fp := sha256.Sum256([]byte(k)) prints := make([]string, len(fp)) diff --git a/ibm/resource_ibm_compute_ssh_key_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key_test.go similarity index 91% rename from ibm/resource_ibm_compute_ssh_key_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key_test.go index d3631238b..ba8474089 100644 --- a/ibm/resource_ibm_compute_ssh_key_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_ssh_key_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -10,6 +10,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" @@ -31,8 +34,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeSSHKeyDestroy, Steps: []resource.TestStep{ { @@ -75,8 +78,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeSSHKeyDestroy, Steps: []resource.TestStep{ { @@ -113,7 +116,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE } func testAccCheckIBMComputeSSHKeyDestroy(s *terraform.State) error { - service := services.GetSecuritySshKeyService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetSecuritySshKeyService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_ssh_key" { @@ -138,7 +141,7 @@ func testAccCheckIBMComputeSSHKeyExists(n string, key *datatypes.Security_Ssh_Ke rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -147,7 +150,7 @@ func testAccCheckIBMComputeSSHKeyExists(n string, key *datatypes.Security_Ssh_Ke keyID, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetSecuritySshKeyService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetSecuritySshKeyService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundKey, err := service.Id(keyID).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_ssl_certificate.go b/ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate.go similarity index 82% rename from ibm/resource_ibm_compute_ssl_certificate.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate.go index c95a57eab..e3fbd6947 100644 --- a/ibm/resource_ibm_compute_ssl_certificate.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,13 +9,14 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMComputeSSLCertificate() *schema.Resource { +func ResourceIBMComputeSSLCertificate() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeSSLCertificateCreate, Read: resourceIBMComputeSSLCertificateRead, @@ -26,7 +27,7 @@ func resourceIBMComputeSSLCertificate() *schema.Resource { Schema: map[string]*schema.Schema{ - "certificate": &schema.Schema{ + "certificate": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -34,7 +35,7 @@ func resourceIBMComputeSSLCertificate() *schema.Resource { Description: "SSL Certifcate", }, - "intermediate_certificate": &schema.Schema{ + "intermediate_certificate": { Type: schema.TypeString, Optional: true, ForceNew: true, @@ -42,7 +43,7 @@ func resourceIBMComputeSSLCertificate() *schema.Resource { Description: "Intermediate certificate value", }, - "private_key": &schema.Schema{ + "private_key": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -51,49 +52,49 @@ func resourceIBMComputeSSLCertificate() *schema.Resource { Description: "SSL Private Key", }, - "common_name": &schema.Schema{ + "common_name": { Type: schema.TypeString, Computed: true, Description: "Common name", }, - "organization_name": &schema.Schema{ + "organization_name": { Type: schema.TypeString, Computed: true, Description: "Organization name", }, - "validity_begin": &schema.Schema{ + "validity_begin": { Type: schema.TypeString, Computed: true, Description: "Validity begins from", }, - "validity_days": &schema.Schema{ + "validity_days": { Type: schema.TypeInt, Computed: true, Description: "Validity days", }, - "validity_end": &schema.Schema{ + "validity_end": { Type: schema.TypeString, Computed: true, Description: "Validity ends before", }, - "key_size": &schema.Schema{ + "key_size": { Type: schema.TypeInt, Computed: true, Description: "SSL key size", }, - "create_date": &schema.Schema{ + "create_date": { Type: schema.TypeString, Computed: true, Description: "certificate creation date", }, - "modify_date": &schema.Schema{ + "modify_date": { Type: schema.TypeString, Computed: true, Description: "certificate modificatiob date", @@ -111,7 +112,7 @@ func resourceIBMComputeSSLCertificate() *schema.Resource { } func resourceIBMComputeSSLCertificateCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateService(sess.SetRetries(0)) template := datatypes.Security_Certificate{ @@ -125,7 +126,7 @@ func resourceIBMComputeSSLCertificateCreate(d *schema.ResourceData, meta interfa cert, err := service.CreateObject(&template) if err != nil { - return fmt.Errorf("Error creating Security Certificate: %s", err) + return fmt.Errorf("[ERROR] Error creating Security Certificate: %s", err) } d.SetId(fmt.Sprintf("%d", *cert.Id)) @@ -134,18 +135,18 @@ func resourceIBMComputeSSLCertificateCreate(d *schema.ResourceData, meta interfa } func resourceIBMComputeSSLCertificateRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } cert, err := service.Id(id).GetObject() if err != nil { - return fmt.Errorf("Unable to get Security Certificate: %s", err) + return fmt.Errorf("[ERROR] Unable to get Security Certificate: %s", err) } d.SetId(fmt.Sprintf("%d", *cert.Id)) @@ -178,24 +179,24 @@ func resourceIBMComputeSSLCertificateUpdate(d *schema.ResourceData, meta interfa } func resourceIBMComputeSSLCertificateDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateService(sess) id, err := strconv.Atoi(d.Id()) _, err = service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Security Certificate %d: %s", id, err) + return fmt.Errorf("[ERROR] Error deleting Security Certificate %d: %s", id, err) } return nil } func resourceIBMComputeSSLCertificateExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } cert, err := service.Id(id).GetObject() @@ -205,7 +206,7 @@ func resourceIBMComputeSSLCertificateExists(d *schema.ResourceData, meta interfa return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute ssl certificate: %s", err) } return cert.Id != nil && *cert.Id == id, nil } diff --git a/ibm/resource_ibm_compute_ssl_certificate_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate_test.go similarity index 97% rename from ibm/resource_ibm_compute_ssl_certificate_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate_test.go index a2c2aa59a..c4067890c 100644 --- a/ibm/resource_ibm_compute_ssl_certificate_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_ssl_certificate_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMComputeSSLCertificate_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeSSLCertificateConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -29,10 +31,10 @@ func TestAccIBMComputeSSLCertificate_Basic(t *testing.T) { func TestAccIBMComputeSSLCertificateWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeSSLCertificateConfigWithTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -44,7 +46,7 @@ func TestAccIBMComputeSSLCertificateWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeSSLCertificateWithUpdatedTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_compute_user.go b/ibm/service/classicinfrastructure/resource_ibm_compute_user.go similarity index 87% rename from ibm/resource_ibm_compute_user.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_user.go index 8d4c93d0e..e17d29562 100644 --- a/ibm/resource_ibm_compute_user.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_user.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "crypto/sha256" @@ -11,6 +11,7 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" @@ -20,7 +21,7 @@ import ( const userCustomerCancelStatus = 1021 -func resourceIBMComputeUser() *schema.Resource { +func ResourceIBMComputeUser() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeUserCreate, Read: resourceIBMComputeUserRead, @@ -30,69 +31,69 @@ func resourceIBMComputeUser() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "username": &schema.Schema{ + "username": { Type: schema.TypeString, Optional: true, Computed: true, Description: "user name", }, - "first_name": &schema.Schema{ + "first_name": { Type: schema.TypeString, Required: true, Description: "First name of the user", }, - "last_name": &schema.Schema{ + "last_name": { Type: schema.TypeString, Required: true, Description: "Last name of the user", }, - "email": &schema.Schema{ + "email": { Type: schema.TypeString, Required: true, Description: "email address of the user", }, - "company_name": &schema.Schema{ + "company_name": { Type: schema.TypeString, Required: true, Description: "comapany name", }, - "address1": &schema.Schema{ + "address1": { Type: schema.TypeString, Required: true, Description: "Address info of the user", }, - "address2": &schema.Schema{ + "address2": { Type: schema.TypeString, Optional: true, Description: "Address info of the user", }, - "city": &schema.Schema{ + "city": { Type: schema.TypeString, Required: true, Description: "City name", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Required: true, Description: "Satate name", }, - "country": &schema.Schema{ + "country": { Type: schema.TypeString, Required: true, Description: "Country name", }, - "timezone": &schema.Schema{ + "timezone": { Type: schema.TypeString, Required: true, Description: "time zone info", }, - "user_status": &schema.Schema{ + "user_status": { Type: schema.TypeString, Optional: true, Default: "ACTIVE", Description: "user status info", }, - "password": &schema.Schema{ + "password": { Type: schema.TypeString, Optional: true, Sensitive: true, @@ -102,27 +103,27 @@ func resourceIBMComputeUser() *schema.Resource { }, Description: "password for the user", }, - "permissions": &schema.Schema{ + "permissions": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, Description: "set of persmissions assigned for the user", }, - "has_api_key": &schema.Schema{ + "has_api_key": { Type: schema.TypeBool, Optional: true, Default: false, Description: "API Key info of the user", }, - "api_key": &schema.Schema{ + "api_key": { Type: schema.TypeString, Optional: true, Computed: true, Sensitive: true, Description: "API key for the user", }, - "ibm_id": &schema.Schema{ + "ibm_id": { Type: schema.TypeString, Computed: true, Description: "IBM ID of the user", @@ -163,7 +164,7 @@ func getPermissions(d *schema.ResourceData) []datatypes.User_Customer_CustomerPe } func resourceIBMComputeUserCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetUserCustomerService(sess) serviceNoRetry := services.GetUserCustomerService(sess.SetRetries(0)) @@ -207,7 +208,7 @@ func resourceIBMComputeUserCreate(d *schema.ResourceData, meta interface{}) erro res, err := serviceNoRetry.CreateObject(&opts, pass, nil) if err != nil { - return fmt.Errorf("Error creating IBM Cloud User: %s", err) + return fmt.Errorf("[ERROR] Error creating IBM Cloud User: %s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -227,12 +228,12 @@ func resourceIBMComputeUserCreate(d *schema.ResourceData, meta interface{}) erro _, err = service.RemoveBulkPortalPermission(defaultPortalPermissions, sl.Bool(true)) if err != nil { - return fmt.Errorf("Error removing default portal permissions for IBM Cloud User: %s", err) + return fmt.Errorf("[ERROR] Error removing default portal permissions for IBM Cloud User: %s", err) } _, err = service.AddBulkPortalPermission(permissions) if err != nil { - return fmt.Errorf("Error setting portal permissions for IBM Cloud User: %s", err) + return fmt.Errorf("[ERROR] Error setting portal permissions for IBM Cloud User: %s", err) } create_api_key_flag := d.Get("has_api_key").(bool) @@ -242,7 +243,7 @@ func resourceIBMComputeUserCreate(d *schema.ResourceData, meta interface{}) erro // and not the edit method. _, err = service.AddApiAuthenticationKey() if err != nil { - return fmt.Errorf("Error creating API key: %s", err) + return fmt.Errorf("[ERROR] Error creating API key: %s", err) } } @@ -250,7 +251,7 @@ func resourceIBMComputeUserCreate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMComputeUserRead(d *schema.ResourceData, meta interface{}) error { - service := services.GetUserCustomerService(meta.(ClientSession).SoftLayerSession()) + service := services.GetUserCustomerService(meta.(conns.ClientSession).SoftLayerSession()) userID, _ := strconv.Atoi(d.Id()) mask := strings.Join([]string{ @@ -281,7 +282,7 @@ func resourceIBMComputeUserRead(d *schema.ResourceData, meta interface{}) error return nil } - return fmt.Errorf("Error retrieving IBM Cloud User: %s", err) + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud User: %s", err) } d.Set("username", sluserObj.Username) @@ -321,7 +322,7 @@ func resourceIBMComputeUserRead(d *schema.ResourceData, meta interface{}) error func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetUserCustomerService(sess) serviceNoRetry := services.GetUserCustomerService(sess.SetRetries(0)) @@ -396,7 +397,7 @@ func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) erro _, err = serviceNoRetry.Id(sluid).EditObject(&userObj) if err != nil { - return fmt.Errorf("Error received while editing ibm_compute_user: %s", err) + return fmt.Errorf("[ERROR] Error received while editing ibm_compute_user: %s", err) } if d.HasChange("permissions") { @@ -422,13 +423,13 @@ func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) erro // 'remove' all old permissions _, err = service.RemoveBulkPortalPermission(oldPermissions, sl.Bool(true)) if err != nil { - return fmt.Errorf("Error received while removing old permissions from ibm_compute_user: %s", err) + return fmt.Errorf("[ERROR] Error received while removing old permissions from ibm_compute_user: %s", err) } // 'add' new permission set _, err = service.AddBulkPortalPermission(newPermissions) if err != nil { - return fmt.Errorf("Error received while assigning new permissions to ibm_compute_user: %s", err) + return fmt.Errorf("[ERROR] Error received while assigning new permissions to ibm_compute_user: %s", err) } } @@ -445,7 +446,7 @@ func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) erro if len(keys) == 0 { // means key does not exist, so create one. key, err := service.AddApiAuthenticationKey() if err != nil { - return fmt.Errorf("Error creating API key while editing ibm_compute_user resource: %s", err) + return fmt.Errorf("[ERROR] Error creating API key while editing ibm_compute_user resource: %s", err) } d.Set("api_key", key) @@ -457,12 +458,11 @@ func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) erro if len(keys) > 0 { success, err := service.RemoveApiAuthenticationKey(keys[0].Id) if err != nil { - return fmt.Errorf("Error deleting API key while editing ibm_compute_user resource: %s", err) + return fmt.Errorf("[ERROR] Error deleting API key while editing ibm_compute_user resource: %s", err) } if !success { - return fmt.Errorf( - "The API reported removal of the api key was not successful for %s", + return fmt.Errorf("[ERROR] The API reported removal of the api key was not successful for %s", d.Get("email").(string), ) } @@ -474,7 +474,7 @@ func resourceIBMComputeUserUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMComputeUserDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetUserCustomerService(sess) id, _ := strconv.Atoi(d.Id()) @@ -486,7 +486,7 @@ func resourceIBMComputeUserDelete(d *schema.ResourceData, meta interface{}) erro log.Printf("[INFO] Deleting IBM Cloud user: %d", id) _, err := service.Id(id).EditObject(&user) if err != nil { - return fmt.Errorf("Error deleting IBM Cloud user: %s", err) + return fmt.Errorf("[ERROR] Error deleting IBM Cloud user: %s", err) } d.SetId("") @@ -494,7 +494,7 @@ func resourceIBMComputeUserDelete(d *schema.ResourceData, meta interface{}) erro } func resourceIBMComputeUserExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetUserCustomerService(meta.(ClientSession).SoftLayerSession()) + service := services.GetUserCustomerService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) @@ -518,7 +518,7 @@ func getTimezoneIDByName(sess *session.Session, shortName string) (int, error) { } } - return -1, fmt.Errorf("Timezone %s could not be found", shortName) + return -1, fmt.Errorf("[ERROR] Timezone %s could not be found", shortName) } @@ -537,6 +537,6 @@ func getUserStatusIDByName(sess *session.Session, name string) (int, error) { } } - return -1, fmt.Errorf("User status %s could not be found", name) + return -1, fmt.Errorf("[ERROR] User status %s could not be found", name) } diff --git a/ibm/resource_ibm_compute_user_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_user_test.go similarity index 92% rename from ibm/resource_ibm_compute_user_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_user_test.go index 346d73150..5493492ab 100644 --- a/ibm/resource_ibm_compute_user_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_user_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "crypto/sha1" @@ -11,6 +11,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" @@ -18,16 +21,18 @@ import ( "github.com/softlayer/softlayer-go/session" ) +const userCustomerCancelStatus = 1021 + func TestAccIBMComputeUser_Basic(t *testing.T) { t.Skip() var user datatypes.User_Customer resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeUserDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeUserConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeUserExists("ibm_compute_user.testuser", &user), @@ -66,7 +71,7 @@ func TestAccIBMComputeUser_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeUserConfig_updated, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -113,11 +118,11 @@ func TestAccIBMComputeUserWithTag(t *testing.T) { var user datatypes.User_Customer resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMComputeUserDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMComputeUserWithTag, Check: resource.ComposeTestCheckFunc( testAccCheckIBMComputeUserExists("ibm_compute_user.testuser", &user), @@ -132,7 +137,7 @@ func TestAccIBMComputeUserWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMComputeUserWithUpdatedTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -150,7 +155,7 @@ func TestAccIBMComputeUserWithTag(t *testing.T) { } func testAccCheckIBMComputeUserDestroy(s *terraform.State) error { - client := services.GetUserCustomerService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + client := services.GetUserCustomerService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_user" { @@ -176,16 +181,16 @@ func testAccCheckIBMComputeUserExists(n string, user *datatypes.User_Customer) r rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } userID, _ := strconv.Atoi(rs.Primary.ID) - client := services.GetUserCustomerService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + client := services.GetUserCustomerService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundUser, err := client.Id(userID).GetObject() if err != nil { diff --git a/ibm/resource_ibm_compute_vm_instance.go b/ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance.go similarity index 88% rename from ibm/resource_ibm_compute_vm_instance.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance.go index 05a9adc5e..77788fd30 100644 --- a/ibm/resource_ibm_compute_vm_instance.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "bytes" @@ -16,7 +16,9 @@ import ( "strings" "time" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -31,7 +33,7 @@ import ( type storageIds []int func (s storageIds) Storages(meta interface{}) ([]datatypes.Network_Storage, error) { - storageService := services.GetNetworkStorageService(meta.(ClientSession).SoftLayerSession()) + storageService := services.GetNetworkStorageService(meta.(conns.ClientSession).SoftLayerSession()) storages := make([]datatypes.Network_Storage, len(s)) for i, id := range s { @@ -61,7 +63,7 @@ const ( retryDelayForModifyingStorageAccess = 10 * time.Second ) -func resourceIBMComputeVmInstance() *schema.Resource { +func ResourceIBMComputeVmInstance() *schema.Resource { return &schema.Resource{ Create: resourceIBMComputeVmInstanceCreate, Read: resourceIBMComputeVmInstanceRead, @@ -454,7 +456,7 @@ func resourceIBMComputeVmInstance() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, - ValidateFunc: validateSecondaryIPCount, + ValidateFunc: validate.ValidateSecondaryIPCount, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { // secondary_ip_count is only used when a virtual_guest resource is created. if d.State() == nil { @@ -507,7 +509,7 @@ func resourceIBMComputeVmInstance() *schema.Resource { "notes": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateNotes, + ValidateFunc: validate.ValidateNotes, }, "local_disk": { @@ -550,9 +552,9 @@ func resourceIBMComputeVmInstance() *schema.Resource { Optional: true, Computed: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, ConflictsWith: []string{"private_network_only", "public_bandwidth_unlimited"}, - ValidateFunc: validatePublicBandwidth, + ValidateFunc: validate.ValidatePublicBandwidth, }, // Monthly only @@ -562,7 +564,7 @@ func resourceIBMComputeVmInstance() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, ConflictsWith: []string{"private_network_only", "public_bandwidth_limited"}, }, @@ -570,7 +572,7 @@ func resourceIBMComputeVmInstance() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, // Quote based provisioning only @@ -581,17 +583,17 @@ func resourceIBMComputeVmInstance() *schema.Resource { Description: "Quote ID for Quote based provisioning", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", @@ -603,7 +605,7 @@ func resourceIBMComputeVmInstance() *schema.Resource { type vmMember map[string]interface{} func getSubnetID(subnet string, meta interface{}) (int, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) subnetInfo := strings.Split(subnet, "/") if len(subnetInfo) != 2 { @@ -625,7 +627,7 @@ func getSubnetID(subnet string, meta interface{}) (int, error) { GetSubnets() if err != nil { - return 0, fmt.Errorf("Error looking up Subnet: %s", err) + return 0, fmt.Errorf("[ERROR] Error looking up Subnet: %s", err) } if len(subnets) < 1 { @@ -642,7 +644,7 @@ func resourceIBMBulkVMHostHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", m["hostname"].(string))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func getNameForBlockDevice(i int) string { @@ -715,7 +717,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf // it is not using the default value. networkSpeed := d.Get("network_speed").(int) if networkSpeed == 0 { - networkSpeed = resourceIBMComputeVmInstance().Schema["network_speed"].Default.(int) + networkSpeed = ResourceIBMComputeVmInstance().Schema["network_speed"].Default.(int) } networkComponent := datatypes.Virtual_Guest_Network_Component{ @@ -751,16 +753,16 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if reservedGroupID, ok := d.GetOk("reserved_capacity_id"); ok { if *opts.HourlyBillingFlag || *opts.LocalDiskFlag { - return vms, fmt.Errorf("Unable to provision a reserved instance with a hourly_billing false or local_disk true") + return vms, fmt.Errorf("[ERROR] Unable to provision a reserved instance with a hourly_billing false or local_disk true") } grpID := reservedGroupID.(int) opts.ReservedCapacityGroup = &datatypes.Virtual_ReservedCapacityGroup{ Id: sl.Int(grpID), } - service := services.GetVirtualReservedCapacityGroupService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualReservedCapacityGroupService(meta.(conns.ClientSession).SoftLayerSession()) grp, err := service.Id(grpID).Mask("id,instances[id, billingItem[id, item[id,keyName]]]").GetObject() if err != nil { - return vms, fmt.Errorf("Error looking up reserved capacity: %s", err) + return vms, fmt.Errorf("[ERROR] Error looking up reserved capacity: %s", err) } capacityFlavor := *grp.Instances[0].BillingItem.Item.KeyName primaryDisks := d.Get("reserved_instance_primary_disk").(int) @@ -778,17 +780,17 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if reservedGroupName, ok := d.GetOk("reserved_capacity_name"); ok { if *opts.HourlyBillingFlag || *opts.LocalDiskFlag { - return vms, fmt.Errorf("Unable to provision a reserved instance with a hourly_billing false or local_disk true") + return vms, fmt.Errorf("[ERROR] Unable to provision a reserved instance with a hourly_billing false or local_disk true") } grpName := reservedGroupName.(string) - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) groups, err := service. Mask("id,name,instances[id,billingItem[id,item[id,keyName]]]"). Filter(filter.Path("reservedCapacityGroups.name").Eq(grpName).Build()). GetReservedCapacityGroups() if err != nil { - return vms, fmt.Errorf("Error looking up reserved capacity '%s': %s", grpName, err) + return vms, fmt.Errorf("[ERROR] Error looking up reserved capacity '%s': %s", grpName, err) } grps := []datatypes.Virtual_ReservedCapacityGroup{} for _, g := range groups { @@ -798,7 +800,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf } } if len(grps) == 0 { - return vms, fmt.Errorf("Error looking up reserved capacity '%s'", grpName) + return vms, fmt.Errorf("[ERROR] Error looking up reserved capacity '%s'", grpName) } grp := grps[0] @@ -821,24 +823,24 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if placementGroupID, ok := d.GetOk("placement_group_id"); ok { grpID := placementGroupID.(int) - service := services.GetVirtualPlacementGroupService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualPlacementGroupService(meta.(conns.ClientSession).SoftLayerSession()) grp, err := service.Id(grpID).Mask("id,name,backendRouter[datacenter[name]]").GetObject() if err != nil { - return vms, fmt.Errorf("Error looking up placement group: %s", err) + return vms, fmt.Errorf("[ERROR] Error looking up placement group: %s", err) } opts.PlacementGroupId = sl.Int(*grp.Id) } else if placementGroupName, ok := d.GetOk("placement_group_name"); ok { grpName := placementGroupName.(string) - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) groups, err := service. Mask("id,name,backendRouter[hostname,datacenter[name]]"). Filter(filter.Path("placementGroup.name").Eq(grpName).Build()). GetPlacementGroups() if err != nil { - return vms, fmt.Errorf("Error looking up placement group '%s': %s", grpName, err) + return vms, fmt.Errorf("[ERROR] Error looking up placement group '%s': %s", grpName, err) } grps := []datatypes.Virtual_PlacementGroup{} for _, g := range groups { @@ -848,7 +850,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf } } if len(grps) == 0 { - return vms, fmt.Errorf("Error looking up placement group '%s'", grpName) + return vms, fmt.Errorf("[ERROR] Error looking up placement group '%s'", grpName) } grp := grps[0] @@ -877,16 +879,16 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf } } else if dedicatedHostName, ok := d.GetOk("dedicated_host_name"); ok { hostName := dedicatedHostName.(string) - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) hosts, err := service. Mask("id"). Filter(filter.Path("dedicatedHosts.name").Eq(hostName).Build()). GetDedicatedHosts() if err != nil { - return vms, fmt.Errorf("Error looking up dedicated host '%s': %s", hostName, err) + return vms, fmt.Errorf("[ERROR] Error looking up dedicated host '%s': %s", hostName, err) } else if len(hosts) == 0 { - return vms, fmt.Errorf("Error looking up dedicated host '%s'", hostName) + return vms, fmt.Errorf("[ERROR] Error looking up dedicated host '%s'", hostName) } opts.DedicatedHost = &hosts[0] @@ -894,7 +896,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if transientFlag, ok := d.GetOk("transient"); ok { if !*opts.HourlyBillingFlag || *opts.LocalDiskFlag { - return vms, fmt.Errorf("Unable to provision a transient instance with a hourly_billing false or local_disk true") + return vms, fmt.Errorf("[ERROR] Unable to provision a transient instance with a hourly_billing false or local_disk true") } opts.TransientGuestFlag = sl.Bool(transientFlag.(bool)) } @@ -904,16 +906,15 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if imgID, ok := d.GetOk("image_id"); ok { imageID := imgID.(int) service := services. - GetVirtualGuestBlockDeviceTemplateGroupService(meta.(ClientSession).SoftLayerSession()) + GetVirtualGuestBlockDeviceTemplateGroupService(meta.(conns.ClientSession).SoftLayerSession()) image, err := service. Mask("id,globalIdentifier").Id(imageID). GetObject() if err != nil { - return vms, fmt.Errorf("Error looking up image %d: %s", imageID, err) + return vms, fmt.Errorf("[ERROR] Error looking up image %d: %s", imageID, err) } else if image.GlobalIdentifier == nil { - return vms, fmt.Errorf( - "Image template %d does not have a global identifier", imageID) + return vms, fmt.Errorf("[ERROR] Image template %d does not have a global identifier", imageID) } opts.BlockDeviceTemplateGroup = &datatypes.Virtual_Guest_Block_Device_Template_Group{ @@ -945,7 +946,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if publicSubnet != "" { primarySubnetID, err := getSubnetID(publicSubnet, meta) if err != nil { - return vms, fmt.Errorf("Error creating virtual guest: %s", err) + return vms, fmt.Errorf("[ERROR] Error creating virtual guest: %s", err) } primaryNetworkComponent.NetworkVlan.PrimarySubnetId = &primarySubnetID usePrimaryNetworkComponent = true @@ -981,7 +982,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf if privateSubnet != "" { primarySubnetID, err := getSubnetID(privateSubnet, meta) if err != nil { - return vms, fmt.Errorf("Error creating virtual guest: %s", err) + return vms, fmt.Errorf("[ERROR] Error creating virtual guest: %s", err) } primaryBackendNetworkComponent.NetworkVlan.PrimarySubnetId = &primarySubnetID usePrimaryBackendNetworkComponent = true @@ -1034,7 +1035,7 @@ func getVirtualGuestTemplateFromResourceData(d *schema.ResourceData, meta interf func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) var id int @@ -1056,11 +1057,11 @@ func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{} } if dcName == "" && len(retryOptions) == 0 { - return fmt.Errorf("Provide either `datacenter` or `datacenter_choice`") + return fmt.Errorf("[ERROR] Provide either `datacenter` or `datacenter_choice`") } if (d.Get("hostname").(string) == "" || d.Get("domain").(string) == "") && len(d.Get("bulk_vms").(*schema.Set).List()) == 0 { - return fmt.Errorf("Provide either `hostname` and `domain` or `bulk_vms`") + return fmt.Errorf("[ERROR] Provide either `hostname` and `domain` or `bulk_vms`") } if dcName != "" { @@ -1078,13 +1079,13 @@ func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{} receipt, err1 = placeOrder(d, meta, dcName, publicVlan, privateVlan, quote_id) } else if len(retryOptions) > 0 { - err := validateDatacenterOption(retryOptions, []string{"datacenter", "public_vlan_id", "private_vlan_id"}) + err := validate.ValidateDatacenterOption(retryOptions, []string{"datacenter", "public_vlan_id", "private_vlan_id"}) if err != nil { return err } for _, option := range retryOptions { if option == nil { - return fmt.Errorf("Provide a valid `datacenter_choice`") + return fmt.Errorf("[ERROR] Provide a valid `datacenter_choice`") } center := option.(map[string]interface{}) var publicVlan, privateVlan int @@ -1112,7 +1113,7 @@ func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{} } if err1 != nil { - return fmt.Errorf("Error ordering virtual guest: %s", err1) + return fmt.Errorf("[ERROR] Error ordering virtual guest: %s", err1) } var idStrings []string @@ -1149,11 +1150,11 @@ func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{} var storageIds []int if fileStorageSet := d.Get("file_storage_ids").(*schema.Set); len(fileStorageSet.List()) > 0 { - storageIds = expandIntList(fileStorageSet.List()) + storageIds = flex.ExpandIntList(fileStorageSet.List()) } if blockStorageSet := d.Get("block_storage_ids").(*schema.Set); len(blockStorageSet.List()) > 0 { - storageIds = append(storageIds, expandIntList(blockStorageSet.List())...) + storageIds = append(storageIds, flex.ExpandIntList(blockStorageSet.List())...) } if len(storageIds) > 0 { err := addAccessToStorageList(service.Id(id), id, storageIds, meta) @@ -1182,14 +1183,14 @@ func resourceIBMComputeVmInstanceCreate(d *schema.ResourceData, meta interface{} } func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) error { - service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) - parts, err := vmIdParts(d.Id()) + service := services.GetVirtualGuestService(meta.(conns.ClientSession).SoftLayerSession()) + parts, err := flex.VmIdParts(d.Id()) if err != nil { return err } id, err := strconv.Atoi(parts[0]) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).Mask( @@ -1214,7 +1215,7 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving virtual guest: %s", err) + return fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } if len(parts) == 1 { @@ -1225,7 +1226,7 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) for _, part := range parts { vmId, err := strconv.Atoi(part) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } vmResult, err := service.Id(vmId).Mask( "hostname,domain", @@ -1283,9 +1284,9 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) ), ) if result.OperatingSystemReferenceCode != nil && strings.HasPrefix(*result.OperatingSystemReferenceCode, "WIN") { - d.Set("disks", flattenDisksForWindows(result)) + d.Set("disks", flex.FlattenDisksForWindows(result)) } else { - d.Set("disks", flattenDisks(result)) + d.Set("disks", flex.FlattenDisks(result)) } d.Set("cores", *result.StartCpus) d.Set("memory", *result.MaxMemory) @@ -1394,12 +1395,12 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) } storages := result.AllowedNetworkStorage - d.Set("block_storage_ids", flattenBlockStorageID(storages)) - d.Set("file_storage_ids", flattenFileStorageID(storages)) + d.Set("block_storage_ids", flex.FlattenBlockStorageID(storages)) + d.Set("file_storage_ids", flex.FlattenFileStorageID(storages)) sshKeys := result.SshKeys if len(sshKeys) > 0 { - d.Set("ssh_key_ids", flattenSSHKeyIDs(sshKeys)) + d.Set("ssh_key_ids", flex.FlattenSSHKeyIDs(sshKeys)) } // Set connection info @@ -1417,9 +1418,9 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) } } - d.Set(ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/gen1/infrastructure/virtual-server/%s/details#main", d.Id())) - d.Set(ResourceName, *result.Hostname) - d.Set(ResourceStatus, *result.Status.Name) + d.Set(flex.ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/gen1/infrastructure/virtual-server/%s/details#main", d.Id())) + d.Set(flex.ResourceName, *result.Hostname) + d.Set(flex.ResourceStatus, *result.Status.Name) err = readSecondaryIPAddresses(d, meta, result.PrimaryIpAddress) return err } @@ -1427,7 +1428,7 @@ func resourceIBMComputeVmInstanceRead(d *schema.ResourceData, meta interface{}) func readSecondaryIPAddresses(d *schema.ResourceData, meta interface{}, primaryIPAddress *string) error { d.Set("secondary_ip_addresses", nil) if primaryIPAddress != nil { - secondarySubnetResult, err := services.GetAccountService(meta.(ClientSession).SoftLayerSession()). + secondarySubnetResult, err := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()). Mask("ipAddresses[id,ipAddress],subnetType"). Filter(filter.Build(filter.Path("publicSubnets.endPointIpAddress.ipAddress").Eq(*primaryIPAddress))). GetPublicSubnets() @@ -1453,21 +1454,21 @@ func readSecondaryIPAddresses(d *schema.ResourceData, meta interface{}, primaryI } func resourceIBMComputeVmInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) - parts, err := vmIdParts(d.Id()) + parts, err := flex.VmIdParts(d.Id()) if err != nil { return err } id, err := strconv.Atoi(parts[0]) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { - return fmt.Errorf("Error retrieving virtual guest: %s", err) + return fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } isChanged := false @@ -1488,7 +1489,7 @@ func resourceIBMComputeVmInstanceUpdate(d *schema.ResourceData, meta interface{} if isChanged { _, err = service.Id(id).EditObject(&result) if err != nil { - return fmt.Errorf("Couldn't update virtual guest: %s", err) + return fmt.Errorf("[ERROR] Could n't update virtual guest: %s", err) } } @@ -1567,13 +1568,13 @@ func resourceIBMComputeVmInstanceUpdate(d *schema.ResourceData, meta interface{} presetKeyName := d.Get("flavor_key_name").(string) _, err = virtual.UpgradeVirtualGuestWithPreset(sess.SetRetries(0), &result, presetKeyName, upgradeOptions) if err != nil { - return fmt.Errorf("Couldn't upgrade virtual guest: %s", err) + return fmt.Errorf("[ERROR] Could n't upgrade virtual guest: %s", err) } } else { _, err = virtual.UpgradeVirtualGuest(sess.SetRetries(0), &result, upgradeOptions) if err != nil { - return fmt.Errorf("Couldn't upgrade virtual guest: %s", err) + return fmt.Errorf("[ERROR] Could n't upgrade virtual guest: %s", err) } } @@ -1600,16 +1601,16 @@ func modifyStorageAccess(sam storageAccessModifier, deviceID int, meta interface os := o.(*schema.Set) ns := n.(*schema.Set) - remove = expandIntList(os.Difference(ns).List()) - add = expandIntList(ns.Difference(os).List()) + remove = flex.ExpandIntList(os.Difference(ns).List()) + add = flex.ExpandIntList(ns.Difference(os).List()) } if d.HasChange("block_storage_ids") { o, n := d.GetChange("block_storage_ids") os := o.(*schema.Set) ns := n.(*schema.Set) - remove = append(remove, expandIntList(os.Difference(ns).List())...) - add = append(add, expandIntList(ns.Difference(os).List())...) + remove = append(remove, flex.ExpandIntList(os.Difference(ns).List())...) + add = append(add, flex.ExpandIntList(ns.Difference(os).List())...) } if len(add) > 0 { @@ -1628,22 +1629,22 @@ func modifyStorageAccess(sam storageAccessModifier, deviceID int, meta interface } func resourceIBMComputeVmInstanceDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) - parts, err := vmIdParts(d.Id()) + parts, err := flex.VmIdParts(d.Id()) if err != nil { return err } for _, part := range parts { id, err := strconv.Atoi(part) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = WaitForNoActiveTransactions(id, d, d.Timeout(schema.TimeoutDelete), meta) if err != nil { - return fmt.Errorf("Error deleting virtual guest, couldn't wait for zero active transactions: %s", err) + return fmt.Errorf("[ERROR] Error deleting virtual guest, couldn't wait for zero active transactions: %s", err) } err = detachSecurityGroupNetworkComponentBindings(d, meta, id) if err != nil { @@ -1651,7 +1652,7 @@ func resourceIBMComputeVmInstanceDelete(d *schema.ResourceData, meta interface{} } ok, err := service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting virtual guest: %s", err) + return fmt.Errorf("[ERROR] Error deleting virtual guest: %s", err) } if !ok { @@ -1664,7 +1665,7 @@ func resourceIBMComputeVmInstanceDelete(d *schema.ResourceData, meta interface{} } func detachSecurityGroupNetworkComponentBindings(d *schema.ResourceData, meta interface{}, id int) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) publicSgIDs := d.Get("public_security_group_ids").(*schema.Set).List() privateSgIDS := d.Get("private_security_group_ids").(*schema.Set).List() @@ -1710,8 +1711,8 @@ func detachSecurityGroupNetworkComponentBindings(d *schema.ResourceData, meta in return nil } -//genID generates a random string to be used for the optional -//hostname +// genID generates a random string to be used for the optional +// hostname func genID() (interface{}, error) { numBytes := 8 bytes := make([]byte, numBytes) @@ -1732,24 +1733,24 @@ func genID() (interface{}, error) { func WaitForUpgradeTransactionsToAppear(d *schema.ResourceData, meta interface{}) (interface{}, error) { log.Printf("Waiting for server (%s) to have upgrade transactions", d.Id()) - parts, err := vmIdParts(d.Id()) + parts, err := flex.VmIdParts(d.Id()) if err != nil { return nil, err } id, err := strconv.Atoi(parts[0]) if err != nil { - return nil, fmt.Errorf("The instance ID %s must be numeric", d.Id()) + return nil, fmt.Errorf("[ERROR] The instance ID %s must be numeric", d.Id()) } stateConf := &resource.StateChangeConf{ Pending: []string{"retry", pendingUpgrade}, Target: []string{inProgressUpgrade}, Refresh: func() (interface{}, string, error) { - service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualGuestService(meta.(conns.ClientSession).SoftLayerSession()) transactions, err := service.Id(id).GetActiveTransactions() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Couldn't fetch active transactions: %s", err) + return nil, "", fmt.Errorf("[ERROR] Could n't fetch active transactions: %s", err) } return false, "retry", nil } @@ -1775,13 +1776,13 @@ func WaitForNoActiveTransactions(id int, d *schema.ResourceData, timeout time.Du Pending: []string{"retry", activeTransaction}, Target: []string{idleTransaction}, Refresh: func() (interface{}, string, error) { - service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualGuestService(meta.(conns.ClientSession).SoftLayerSession()) transactions, err := service.Id(id).GetActiveTransactions() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return nil, "", nil } - return false, "retry", fmt.Errorf("Couldn't get active transactions: %s", err) + return false, "retry", fmt.Errorf("[ERROR] Could n't get active transactions: %s", err) } if len(transactions) == 0 { return transactions, idleTransaction, nil @@ -1799,7 +1800,7 @@ func WaitForNoActiveTransactions(id int, d *schema.ResourceData, timeout time.Du // WaitForVirtualGuestAvailable Waits for virtual guest creation func WaitForVirtualGuestAvailable(id int, d *schema.ResourceData, meta interface{}) (interface{}, error) { log.Printf("Waiting for server (%s) to be available.", d.Id()) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"retry", virtualGuestProvisioning}, Target: []string{virtualGuestAvailable}, @@ -1820,7 +1821,7 @@ func virtualGuestStateRefreshFunc(sess *session.Session, instanceID int, d *sche result, err := service.Id(instanceID).Mask("activeTransaction,primaryBackendIpAddress,primaryIpAddress").GetObject() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving virtual guest: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } return false, "retry", nil } @@ -1849,7 +1850,7 @@ func virtualGuestStateRefreshFunc(sess *session.Session, instanceID int, d *sche Filter(filter.Build(filter.Path("publicSubnets.endPointIpAddress.virtualGuest.id").Eq(fmt.Sprintf("%d", instanceID)))). GetPublicSubnets() if err != nil { - return nil, "", fmt.Errorf("Error retrieving secondary ip address: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving secondary ip address: %s", err) } if len(secondarySubnetResult) == 0 { return result, virtualGuestProvisioning, nil @@ -1861,14 +1862,14 @@ func virtualGuestStateRefreshFunc(sess *session.Session, instanceID int, d *sche } func resourceIBMComputeVmInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) - parts, err := vmIdParts(d.Id()) + service := services.GetVirtualGuestService(meta.(conns.ClientSession).SoftLayerSession()) + parts, err := flex.VmIdParts(d.Id()) if err != nil { return false, err } guestID, err := strconv.Atoi(parts[0]) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(guestID).GetObject() @@ -1878,7 +1879,7 @@ func resourceIBMComputeVmInstanceExists(d *schema.ResourceData, meta interface{} return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting compute vm instance: %s", err) } return result.Id != nil && *result.Id == guestID, nil @@ -1900,10 +1901,10 @@ func getTags(d dataRetriever) string { } func setGuestTags(id int, tags string, meta interface{}) error { - service := services.GetVirtualGuestService(meta.(ClientSession).SoftLayerSession()) + service := services.GetVirtualGuestService(meta.(conns.ClientSession).SoftLayerSession()) _, err := service.Id(id).SetTags(sl.String(tags)) if err != nil { - return fmt.Errorf("Could not set tags on virtual guest %d", id) + return fmt.Errorf("[ERROR] Could not set tags on virtual guest %d", id) } return nil } @@ -1926,7 +1927,7 @@ func addAccessToStorageList(sam storageAccessModifier, deviceID int, ids storage time.Sleep(retryDelayForModifyingStorageAccess) continue } - return fmt.Errorf("Could not authorize Device %d, access to the following storages %q, %q", deviceID, ids, err) + return fmt.Errorf("[ERROR] Could not authorize Device %d, access to the following storages %q, %q", deviceID, ids, err) } log.Printf("[INFO] Device authorized to access %q", ids) break @@ -1947,7 +1948,7 @@ func removeAccessToStorageList(sam storageAccessModifier, deviceID int, ids stor time.Sleep(retryDelayForModifyingStorageAccess) continue } - return fmt.Errorf("Could not remove Device %d, access to the following storages %q, %q", deviceID, ids, err) + return fmt.Errorf("[ERROR] Could not remove Device %d, access to the following storages %q, %q", deviceID, ids, err) } log.Printf("[INFO] Devices's access to %q have been removed", ids) break @@ -1956,20 +1957,20 @@ func removeAccessToStorageList(sam storageAccessModifier, deviceID int, ids stor } func setNotes(id int, d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) if notes := d.Get("notes").(string); notes != "" { result, err := service.Id(id).GetObject() if err != nil { - return fmt.Errorf("Error retrieving virtual guest: %s", err) + return fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } result.Notes = sl.String(notes) _, err = service.Id(id).EditObject(&result) if err != nil { - return fmt.Errorf("Could not set note on virtual guest %d", id) + return fmt.Errorf("[ERROR] Could not set note on virtual guest %d", id) } } @@ -1977,7 +1978,7 @@ func setNotes(id int, d *schema.ResourceData, meta interface{}) error { } func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVlanID, privateVlanID, quote_id int) (datatypes.Container_Product_Order_Receipt, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetVirtualGuestService(sess) options, err := getVirtualGuestTemplateFromResourceData(d, meta, name, publicVlanID, privateVlanID, quote_id) @@ -2047,7 +2048,7 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla opts.OperatingSystemReferenceCode = sl.String("UBUNTU_LATEST") template, err = service.GenerateOrderTemplate(&opts) if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } // Remove temporary OS from actual order @@ -2068,13 +2069,13 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla // Build an order template with os_reference_code template, err = service.GenerateOrderTemplate(&opts) if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } } items, err := product.GetPackageProducts(sess, *template.PackageId, productItemMaskWithPriceLocationGroupID) if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } privateNetworkOnly := d.Get("private_network_only").(bool) @@ -2082,7 +2083,7 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla secondaryIPCount := d.Get("secondary_ip_count").(int) if secondaryIPCount > 0 { if privateNetworkOnly { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure public secondary addresses with a private_network_only option") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure public secondary addresses with a private_network_only option") } keyName := strconv.Itoa(secondaryIPCount) + "_PUBLIC_IP_ADDRESSES" price, err := getItemPriceId(items, "sec_ip_addresses", keyName) @@ -2094,22 +2095,22 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla if d.Get("ipv6_enabled").(bool) { if privateNetworkOnly { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure a public IPv6 address with a private_network_only option") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure a public IPv6 address with a private_network_only option") } price, err := getItemPriceId(items, "pri_ipv6_addresses", "1_IPV6_ADDRESS") if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } template.Prices = append(template.Prices, price) } if d.Get("ipv6_static_enabled").(bool) { if privateNetworkOnly { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure a public static IPv6 address with a private_network_only option") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure a public static IPv6 address with a private_network_only option") } price, err := getItemPriceId(items, "static_ipv6_addresses", "64_BLOCK_STATIC_PUBLIC_IPV6_ADDRESSES") if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } template.Prices = append(template.Prices, price) } @@ -2118,7 +2119,7 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla // Add public bandwidth limited if publicBandwidth, ok := d.GetOk("public_bandwidth_limited"); ok { if *opts.HourlyBillingFlag { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure a public bandwidth with a hourly_billing true") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure a public bandwidth with a hourly_billing true") } // Remove Default bandwidth price prices := make([]datatypes.Product_Item_Price, len(template.Prices)) @@ -2137,7 +2138,7 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla keyName := "BANDWIDTH_" + strconv.Itoa(publicBandwidth.(int)) + "_GB" price, err := getItemPriceId(items, "bandwidth", keyName) if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } template.Prices = append(template.Prices, price) } @@ -2146,7 +2147,7 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla publicUnlimitedBandwidth := d.Get("public_bandwidth_unlimited").(bool) if publicUnlimitedBandwidth { if *opts.HourlyBillingFlag { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure a public bandwidth with a hourly_billing true") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure a public bandwidth with a hourly_billing true") } networkSpeed := d.Get("network_speed").(int) if networkSpeed != 100 { @@ -2168,20 +2169,20 @@ func placeOrder(d *schema.ResourceData, meta interface{}, name string, publicVla template.Prices = prices[:i] price, err := getItemPriceId(items, "bandwidth", "BANDWIDTH_UNLIMITED_100_MBPS_UPLINK") if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } template.Prices = append(template.Prices, price) } if evault, ok := d.GetOk("evault"); ok { if *opts.HourlyBillingFlag { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Unable to configure a evault with hourly_billing true") + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Unable to configure a evault with hourly_billing true") } keyName := "EVAULT_" + strconv.Itoa(evault.(int)) + "_GB" price, err := getItemPriceId(items, "evault", keyName) if err != nil { - return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("Error generating order template: %s", err) + return datatypes.Container_Product_Order_Receipt{}, fmt.Errorf("[ERROR] Error generating order template: %s", err) } template.Prices = append(template.Prices, price) } diff --git a/ibm/resource_ibm_compute_vm_instance_test.go b/ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance_test.go similarity index 94% rename from ibm/resource_ibm_compute_vm_instance_test.go rename to ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance_test.go index 30c8ae2d7..124204e55 100644 --- a/ibm/resource_ibm_compute_vm_instance_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_compute_vm_instance_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -11,6 +11,10 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -36,8 +40,8 @@ func TestAccIBMComputeVMInstance_basic(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-acceptance-test-1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -155,8 +159,8 @@ func TestAccIBMComputeVMInstance_bulkvms(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-acceptance-test-1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -233,8 +237,8 @@ func TestAccIBMComputeVMInstanceWithFlavor(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-acceptance-test-1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -326,8 +330,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE configInstance := "ibm_compute_vm_instance.terraform-ssh-key" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -358,8 +362,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resourceName := "ibm_compute_vm_instance.terraform-ssh-key" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -388,8 +392,8 @@ func TestAccIBMComputeVMInstance_basic_import_WithFlavor(t *testing.T) { resourceName := "ibm_compute_vm_instance.terraform-acceptance-test-1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -417,8 +421,8 @@ func TestAccIBMComputeVMInstance_InvalidNotes(t *testing.T) { tags1 := "collectd" userMetadata1 := "{\\\"value\\\":\\\"newvalue\\\"}" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMComputeVMInstanceInvalidNotes(hostname, domain, networkSpeed1, cores1, memory1, userMetadata1, tags1), @@ -438,8 +442,8 @@ func TestAccIBMComputeVMInstance_BlockDeviceTemplateGroup(t *testing.T) { // Image Id of RightImage_Ubuntu_10.04_x64_v5.7.24 imageID := 15789 resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -462,8 +466,8 @@ func TestAccIBMComputeVMInstance_CustomImageMultipleDisks(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-acceptance-test-disks" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -492,8 +496,8 @@ func TestAccIBMComputeVMInstance_PostInstallScriptUri(t *testing.T) { domain := "pis.terraformvmuat.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -514,8 +518,8 @@ func TestAccIBMComputeVMInstance_WINDOWS_PostInstallScriptUri(t *testing.T) { domain := "terraformuat.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -536,8 +540,8 @@ func TestAccIBMComputeVMInstance_With_Network_Storage_Access(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-vsi-storage-access" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -580,8 +584,8 @@ func TestAccIBMComputeVMInstance_With_Public_Bandwidth_Limited(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-public-bandwidth" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -619,8 +623,8 @@ func TestAccIBMComputeVMInstance_With_Public_Bandwidth_Unlimited(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-public-bandwidth" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -646,8 +650,8 @@ func TestAccIBMComputeVMInstance_With_DedicatedHost_Name(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-vm-dedicatedhost" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -673,8 +677,8 @@ func TestAccIBMComputeVMInstance_With_DedicatedHost_ID(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-vm-dedicatedhost" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -705,8 +709,8 @@ func TestAccIBMComputeVMInstance_With_Security_Groups(t *testing.T) { configInstance := "ibm_compute_vm_instance.tfuatvmwithgroups" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -736,8 +740,8 @@ func TestAccIBMComputeVMInstance_With_Evault(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-evault" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -765,8 +769,8 @@ func TestAccIBMComputeVMInstance_With_Retry(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-retry" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testComputeInstanceWithRetry(hostname, domain), @@ -793,8 +797,8 @@ func TestAccIBMComputeVMInstance_With_Placement_group(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-pgroup" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -821,8 +825,8 @@ func TestAccIBMComputeVMInstance_With_Invalid_Retry(t *testing.T) { var errMsg = "\"test\" Invalid values are provided in `datacenter_choice`" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testComputeInstanceWithRetryInvalid(hostname, domain), @@ -846,8 +850,8 @@ func TestAccIBMComputeVMInstance_Transient(t *testing.T) { configInstance := "ibm_compute_vm_instance.terraform-transient" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccIBMComputeVMInstanceDestroy, Steps: []resource.TestStep{ { @@ -904,13 +908,13 @@ func TestAccIBMComputeVMInstance_Transient(t *testing.T) { } func testAccIBMComputeVMInstanceDestroy(s *terraform.State) error { - service := services.GetVirtualGuestService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualGuestService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_compute_vm_instance" { continue } - parts, err := vmIdParts(rs.Primary.ID) + parts, err := flex.VmIdParts(rs.Primary.ID) if err != nil { return err } @@ -923,8 +927,7 @@ func testAccIBMComputeVMInstanceDestroy(s *terraform.State) error { // Wait if err != nil && !strings.Contains(err.Error(), "404") { - return fmt.Errorf( - "Error waiting for virtual guest (%s) to be destroyed: %s", + return fmt.Errorf("[ERROR] Error waiting for virtual guest (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -937,13 +940,13 @@ func testAccIBMComputeVMInstanceExists(n string, guest *datatypes.Virtual_Guest) return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { return errors.New("No virtual guest ID is set") } - parts, err := vmIdParts(rs.Primary.ID) + parts, err := flex.VmIdParts(rs.Primary.ID) if err != nil { return err } @@ -954,7 +957,7 @@ func testAccIBMComputeVMInstanceExists(n string, guest *datatypes.Virtual_Guest) return err } - service := services.GetVirtualGuestService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetVirtualGuestService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) retrieveVirtGuest, err := service.Id(id).GetObject() if err != nil { @@ -978,7 +981,7 @@ func CheckStringSet(n string, name string, set []string) resource.TestCheckFunc return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } values := []string{} @@ -991,7 +994,7 @@ func CheckStringSet(n string, name string, set []string) resource.TestCheckFunc } if len(values) == 0 { - return fmt.Errorf("Could not find %s.%s", n, name) + return fmt.Errorf("[ERROR] Could not find %s.%s", n, name) } for _, s := range set { @@ -1349,7 +1352,7 @@ resource "ibm_compute_vm_instance" "terraform-vm-dedicatedhost" { disks = [25, 25, 100] dedicated_host_name = "%s" } -`, hostname, domain, dedicatedHostName) +`, hostname, domain, acc.DedicatedHostName) } func testComputeInstanceWithDedicatdHostID(hostname, domain string) (config string) { @@ -1366,7 +1369,7 @@ resource "ibm_compute_vm_instance" "terraform-vm-dedicatedhost" { disks = [25, 100, 25] dedicated_host_id = "%s" } -`, hostname, domain, dedicatedHostID) +`, hostname, domain, acc.DedicatedHostID) } func testAccIBMComputeVMInstanceConfigWithSecurityGroups(sgName1, sgDesc1, sgName2, sgDesc2, hostname string) string { diff --git a/ibm/resource_ibm_dns_domain.go b/ibm/service/classicinfrastructure/resource_ibm_dns_domain.go similarity index 80% rename from ibm/resource_ibm_dns_domain.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_domain.go index a58524858..792e7ac62 100644 --- a/ibm/resource_ibm_dns_domain.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_domain.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -9,13 +9,14 @@ import ( "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMDNSDomain() *schema.Resource { +func ResourceIBMDNSDomain() *schema.Resource { return &schema.Resource{ Exists: resourceIBMDNSDomainExists, Create: resourceIBMDNSDomainCreate, @@ -61,7 +62,7 @@ func resourceIBMDNSDomain() *schema.Resource { } func resourceIBMDNSDomainCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainService(sess.SetRetries(0)) // prepare creation parameters @@ -85,7 +86,7 @@ func resourceIBMDNSDomainCreate(d *schema.ResourceData, meta interface{}) error // create Dns_Domain object response, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Dns Domain: %s", err) + return fmt.Errorf("[ERROR] Error creating Dns Domain: %s", err) } // populate id @@ -98,7 +99,7 @@ func resourceIBMDNSDomainCreate(d *schema.ResourceData, meta interface{}) error } func resourceIBMDNSDomainRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainService(sess) dnsId, _ := strconv.Atoi(d.Id()) @@ -108,7 +109,7 @@ func resourceIBMDNSDomainRead(d *schema.ResourceData, meta interface{}) error { "id,name,updateDate,resourceRecords", ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Dns Domain %d: %s", dnsId, err) + return fmt.Errorf("[ERROR] Error retrieving Dns Domain %d: %s", dnsId, err) } // populate fields @@ -130,7 +131,7 @@ func resourceIBMDNSDomainRead(d *schema.ResourceData, meta interface{}) error { func resourceIBMDNSDomainUpdate(d *schema.ResourceData, meta interface{}) error { // If the target has been updated, find the corresponding dns record and update its data - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() domainService := services.GetDnsDomainService(sess) service := services.GetDnsDomainResourceRecordService(sess.SetRetries(0)) @@ -147,7 +148,7 @@ func resourceIBMDNSDomainUpdate(d *schema.ResourceData, meta interface{}) error "id,name,updateDate,resourceRecords", ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving DNS resource %d: %s", domainId, err) + return fmt.Errorf("[ERROR] Error retrieving DNS resource %d: %s", domainId, err) } // find a record with host @; that will have the current target. @@ -159,7 +160,7 @@ func resourceIBMDNSDomainUpdate(d *schema.ResourceData, meta interface{}) error } if record.Id == nil { - return fmt.Errorf("Could not find DNS target record for domain %s (%d)", + return fmt.Errorf("[ERROR] Could not find DNS target record for domain %s (%d)", sl.Get(domain.Name), sl.Get(domain.Id)) } @@ -168,7 +169,7 @@ func resourceIBMDNSDomainUpdate(d *schema.ResourceData, meta interface{}) error _, err = service.Id(*record.Id).EditObject(&record) if err != nil { - return fmt.Errorf("Error editing DNS target record for domain %s (%d): %s", + return fmt.Errorf("[ERROR] Error editing DNS target record for domain %s (%d): %s", sl.Get(domain.Name), sl.Get(domain.Id), err) } @@ -176,22 +177,22 @@ func resourceIBMDNSDomainUpdate(d *schema.ResourceData, meta interface{}) error } func resourceIBMDNSDomainDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainService(sess) dnsId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Error deleting Dns Domain: %s", err) + return fmt.Errorf("[ERROR] Error deleting Dns Domain: %s", err) } log.Printf("[INFO] Deleting Dns Domain: %d", dnsId) result, err := service.Id(dnsId).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Dns Domain: %s", err) + return fmt.Errorf("[ERROR] Error deleting Dns Domain: %s", err) } if !result { - return errors.New("Error deleting Dns Domain") + return errors.New("[ERROR] Error deleting Dns Domain") } d.SetId("") @@ -199,12 +200,12 @@ func resourceIBMDNSDomainDelete(d *schema.ResourceData, meta interface{}) error } func resourceIBMDNSDomainExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainService(sess) dnsId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(dnsId).GetObject() @@ -214,7 +215,7 @@ func resourceIBMDNSDomainExists(d *schema.ResourceData, meta interface{}) (bool, return false, nil } } - return false, fmt.Errorf("Error retrieving domain info: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving domain info: %s", err) } return result.Id != nil && *result.Id == dnsId, nil } diff --git a/ibm/resource_ibm_dns_domain_registration_nameservers.go b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers.go similarity index 84% rename from ibm/resource_ibm_dns_domain_registration_nameservers.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers.go index 0737b82e2..bf174e379 100644 --- a/ibm/resource_ibm_dns_domain_registration_nameservers.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( //"errors" @@ -9,11 +9,12 @@ import ( "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/services" ) -func resourceIBMDNSDomainRegistrationNameservers() *schema.Resource { +func ResourceIBMDNSDomainRegistrationNameservers() *schema.Resource { return &schema.Resource{ Create: resourceIBMDNSDomainRegistrationNSCreate, Read: resourceIBMDNSDomainRegistrationNSRead, @@ -25,7 +26,7 @@ func resourceIBMDNSDomainRegistrationNameservers() *schema.Resource { Required: true, Description: "DNS registration ID", }, - "name_servers": &schema.Schema{ + "name_servers": { Description: "Custom name servers for the domain registration", Type: schema.TypeSet, Required: true, @@ -33,7 +34,7 @@ func resourceIBMDNSDomainRegistrationNameservers() *schema.Resource { Type: schema.TypeString, }, }, - "original_name_servers": &schema.Schema{ + "original_name_servers": { Description: "Save of name servers prior to update", Type: schema.TypeSet, Computed: true, @@ -46,7 +47,7 @@ func resourceIBMDNSDomainRegistrationNameservers() *schema.Resource { } func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() nService := services.GetDnsDomainRegistrationService(sess) dnsId, _ := strconv.Atoi(d.Get("dns_registration_id").(string)) newNameServers := d.Get("name_servers").(*schema.Set).List() @@ -57,11 +58,11 @@ func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta inter GetDomainNameservers() if err != nil { - return fmt.Errorf("Error retrieving domain Registration NSCreate: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain Registration NSCreate: %s", err) } if len(dns_domain_nameservers) == 0 { - return fmt.Errorf("No domain found with id NSCreate [%d]", dnsId) + return fmt.Errorf("[ERROR] No domain found with id NSCreate [%d]", dnsId) } oldNameServers := make([]string, len(dns_domain_nameservers[0].Nameservers)) for i, elem := range dns_domain_nameservers[0].Nameservers { @@ -99,7 +100,7 @@ func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta inter nsUnlock_res, err := nService.Id(dnsId). UnlockDomain() if err != nil || nsUnlock_res != true { - return fmt.Errorf("Error unlocking domain registration record: %s", err) + return fmt.Errorf("[ERROR] Error unlocking domain registration record: %s", err) } nsAdd_res := false @@ -107,7 +108,7 @@ func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta inter AddNameserversToDomain(addNs) if err != nil || nsAdd_res != true { - return fmt.Errorf("Error Adding name servers to record: %s", err) + return fmt.Errorf("[ERROR] Error Adding name servers to record: %s", err) } // old NS to delete, if not found in new list @@ -133,7 +134,7 @@ func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta inter RemoveNameserversFromDomain(delNs) if err != nil || nsDel_res != true { - return fmt.Errorf("Error Deleting name servers from record: %s", err) + return fmt.Errorf("[ERROR] Error Deleting name servers from record: %s", err) } _, _ = nService.Id(dnsId).LockDomain() @@ -146,7 +147,7 @@ func resourceIBMDNSDomainRegistrationNSCreate(d *schema.ResourceData, meta inter } func resourceIBMDNSDomainRegistrationNSRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() dnsId, _ := strconv.Atoi(d.Id()) //service := services.GetDnsDomainService(sess) @@ -156,11 +157,11 @@ func resourceIBMDNSDomainRegistrationNSRead(d *schema.ResourceData, meta interfa GetDomainNameservers() if err != nil { - return fmt.Errorf("Error retrieving domain registration NSReaD: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain registration NSReaD: %s", err) } if len(dns_domain_nameservers) == 0 { - return fmt.Errorf("No domain found with id [%d]", dnsId) + return fmt.Errorf("[ERROR] No domain found with id [%d]", dnsId) } log.Printf("list %v\n", dns_domain_nameservers) @@ -172,7 +173,7 @@ func resourceIBMDNSDomainRegistrationNSRead(d *schema.ResourceData, meta interfa log.Printf("names %v\n", ns) if err != nil { - return fmt.Errorf("Error retrieving domain registration nameservers: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain registration nameservers: %s", err) } d.SetId(fmt.Sprintf("%d", dnsId)) @@ -188,7 +189,7 @@ func resourceIBMDNSDomainRegistrationNSUpdate(d *schema.ResourceData, meta inter // No delete on IBM Cloud func resourceIBMDNSDomainRegistrationNSDelete(d *schema.ResourceData, meta interface{}) error { // Exact reverse of create to restore name servers back to original values - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() nService := services.GetDnsDomainRegistrationService(sess) dnsId, _ := strconv.Atoi(d.Get("dns_registration_id").(string)) currentNameServers := d.Get("name_servers").(*schema.Set).List() @@ -223,7 +224,7 @@ func resourceIBMDNSDomainRegistrationNSDelete(d *schema.ResourceData, meta inter nsUnlock_res, err := nService.Id(dnsId). UnlockDomain() if err != nil || nsUnlock_res != true { - return fmt.Errorf("Error unlocking domain registration record: %s", err) + return fmt.Errorf("[ERROR] Error unlocking domain registration record: %s", err) } nsAdd_res := false @@ -231,7 +232,7 @@ func resourceIBMDNSDomainRegistrationNSDelete(d *schema.ResourceData, meta inter AddNameserversToDomain(addNs) if err != nil || nsAdd_res != true { - return fmt.Errorf("Error Adding name servers to record: %s", err) + return fmt.Errorf("[ERROR] Error Adding name servers to record: %s", err) } // current NS to delete, if not found in original list @@ -257,7 +258,7 @@ func resourceIBMDNSDomainRegistrationNSDelete(d *schema.ResourceData, meta inter RemoveNameserversFromDomain(delNs) if err != nil || nsDel_res != true { - return fmt.Errorf("Error Deleting name servers from record: %s", err) + return fmt.Errorf("[ERROR] Error Deleting name servers from record: %s", err) } _, _ = nService.Id(dnsId).LockDomain() diff --git a/ibm/resource_ibm_dns_domain_registration_nameservers_test.go b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers_test.go similarity index 80% rename from ibm/resource_ibm_dns_domain_registration_nameservers_test.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers_test.go index e43a3fafd..e38e9dbac 100644 --- a/ibm/resource_ibm_dns_domain_registration_nameservers_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_registration_nameservers_test.go @@ -1,18 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" "fmt" + "log" + "strconv" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" - "log" - "strconv" - "testing" ) func TestAccIBMDNSDomainRegistration_Nameservers_Basic(t *testing.T) { @@ -35,8 +39,8 @@ data "ibm_dns_domain_registration" "wcpclouduk" { var nameServer2 = "ns017.name.cloud.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: fmt.Sprintf(config, nameServer1, nameServer2, domainName1), @@ -56,11 +60,11 @@ func testAccCheckIBMDNSDomainRegistrationAttributes(n string, dns_reg *datatypes return func(s *terraform.State) error { // Get name servers from DNS to verify they have been set correctly - service := services.GetDnsDomainRegistrationService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainRegistrationService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -75,11 +79,11 @@ func testAccCheckIBMDNSDomainRegistrationAttributes(n string, dns_reg *datatypes GetDomainNameservers() if err != nil { - return fmt.Errorf("Error retrieving domain registration: %s", err) + return fmt.Errorf("[ERROR] Error retrieving domain registration: %s", err) } if len(dns_domain_nameservers) == 0 { - return fmt.Errorf("No domain found with id [%d]", dnsId) + return fmt.Errorf("[ERROR] No domain found with id [%d]", dnsId) } log.Printf("list %v\n", dns_domain_nameservers) @@ -104,7 +108,7 @@ func testAccCheckIBMDNSDomainRegistrationAttributes(n string, dns_reg *datatypes } if ns1Found != true || ns2Found != true { - return fmt.Errorf("Error domain registration nameservers not set as required: %v", ns) + return fmt.Errorf("[ERROR] Error domain registration nameservers not set as required: %v", ns) } return nil diff --git a/ibm/resource_ibm_dns_domain_test.go b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_test.go similarity index 90% rename from ibm/resource_ibm_dns_domain_test.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_domain_test.go index 7cf6f740f..93e7a4f34 100644 --- a/ibm/resource_ibm_dns_domain_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_domain_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,8 +24,8 @@ func TestAccIBMDNSDomain_Basic(t *testing.T) { var dns_domain datatypes.Dns_Domain resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -71,8 +74,8 @@ func TestAccIBMDNSDomainWithTag(t *testing.T) { var dns_domain datatypes.Dns_Domain resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -109,7 +112,7 @@ func TestAccIBMDNSDomainWithTag(t *testing.T) { } func testAccCheckIBMDNSDomainDestroy(s *terraform.State) error { - service := services.GetDnsDomainService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_dns_domain" { @@ -167,7 +170,7 @@ func saveIBMDNSDomainId(dns *datatypes.Dns_Domain, id_holder *int) resource.Test func testAccCheckIBMDNSDomainChanged(dns *datatypes.Dns_Domain) resource.TestCheckFunc { return func(s *terraform.State) error { - service := services.GetDnsDomainService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) _, err := service.Id(firstDnsId).Mask( "id,name,updateDate,resourceRecords", @@ -185,7 +188,7 @@ func testAccCheckIBMDNSDomainExists(n string, dns_domain *datatypes.Dns_Domain) rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -194,7 +197,7 @@ func testAccCheckIBMDNSDomainExists(n string, dns_domain *datatypes.Dns_Domain) dns_id, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetDnsDomainService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) found_domain, err := service.Id(dns_id).Mask( "id,name,updateDate,resourceRecords", ).GetObject() diff --git a/ibm/resource_ibm_dns_record.go b/ibm/service/classicinfrastructure/resource_ibm_dns_record.go similarity index 86% rename from ibm/resource_ibm_dns_record.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_record.go index de217f61b..507b3f093 100644 --- a/ibm/resource_ibm_dns_record.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_record.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,7 @@ import ( "strconv" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" @@ -30,7 +31,7 @@ func init() { upcaseRegexp, _ = regexp.Compile("[A-Z]") } -func resourceIBMDNSRecord() *schema.Resource { +func ResourceIBMDNSRecord() *schema.Resource { return &schema.Resource{ Exists: resourceIBMDNSRecordExists, Create: resourceIBMDNSRecordCreate, @@ -188,10 +189,10 @@ func resourceIBMDNSRecord() *schema.Resource { } } -// Creates DNS Domain Resource Record -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/createObject +// Creates DNS Domain Resource Record +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/createObject func resourceIBMDNSRecordCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainResourceRecordService(sess.SetRetries(0)) opts := datatypes.Dns_Domain_ResourceRecord{ @@ -266,7 +267,7 @@ func resourceIBMDNSRecordCreate(d *schema.ResourceData, meta interface{}) error } if err != nil { - return fmt.Errorf("Error creating DNS Resource %s Record: %s", *opts.Type, err) + return fmt.Errorf("[ERROR] Error creating DNS Resource %s Record: %s", *opts.Type, err) } d.SetId(fmt.Sprintf("%d", id)) @@ -276,19 +277,19 @@ func resourceIBMDNSRecordCreate(d *schema.ResourceData, meta interface{}) error return resourceIBMDNSRecordRead(d, meta) } -// Reads DNS Domain Resource Record from SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/getObject +// Reads DNS Domain Resource Record from SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/getObject func resourceIBMDNSRecordRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainResourceRecordService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { - return fmt.Errorf("Error retrieving DNS Resource Record: %s", err) + return fmt.Errorf("[ERROR] Error retrieving DNS Resource Record: %s", err) } // Required fields @@ -317,17 +318,17 @@ func resourceIBMDNSRecordRead(d *schema.ResourceData, meta interface{}) error { return nil } -// Updates DNS Domain Resource Record in SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/editObject +// Updates DNS Domain Resource Record in SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/editObject func resourceIBMDNSRecordUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainResourceRecordService(sess) serviceNoRetry := services.GetDnsDomainResourceRecordService(sess.SetRetries(0)) recordId, _ := strconv.Atoi(d.Id()) record, err := service.Id(recordId).GetObject() if err != nil { - return fmt.Errorf("Error retrieving DNS Resource Record: %s", err) + return fmt.Errorf("[ERROR] Error retrieving DNS Resource Record: %s", err) } recordType := d.Get("type").(string) @@ -405,27 +406,27 @@ func resourceIBMDNSRecordUpdate(d *schema.ResourceData, meta interface{}) error } if err != nil { - return fmt.Errorf("Error editing DNS Resource %s Record %d: %s", recordType, recordId, err) + return fmt.Errorf("[ERROR] Error editing DNS Resource %s Record %d: %s", recordType, recordId, err) } return nil } -// Deletes DNS Domain Resource Record in SL system -// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/deleteObject +// Deletes DNS Domain Resource Record in SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/deleteObject func resourceIBMDNSRecordDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainResourceRecordService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = service.Id(id).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting DNS Resource Record: %s", err) + return fmt.Errorf("[ERROR] Error deleting DNS Resource Record: %s", err) } return nil @@ -434,12 +435,12 @@ func resourceIBMDNSRecordDelete(d *schema.ResourceData, meta interface{}) error // Exists function is called by refresh // if the entity is absent - it is deleted from the .tfstate file func resourceIBMDNSRecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsDomainResourceRecordService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } record, err := service.Id(id).GetObject() @@ -449,7 +450,7 @@ func resourceIBMDNSRecordExists(d *schema.ResourceData, meta interface{}) (bool, return false, nil } } - return false, fmt.Errorf("Error retrieving domain record info: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving domain record info: %s", err) } return record.Id != nil && *record.Id == id, nil } diff --git a/ibm/resource_ibm_dns_record_test.go b/ibm/service/classicinfrastructure/resource_ibm_dns_record_test.go similarity index 94% rename from ibm/resource_ibm_dns_record_test.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_record_test.go index fa883c15f..cfa879531 100644 --- a/ibm/resource_ibm_dns_record_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_record_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -25,8 +28,8 @@ func TestAccIBMDNSRecord_Basic(t *testing.T) { host2 := acctest.RandString(10) + "ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -65,8 +68,8 @@ func TestAccIBMDNSRecord_Types(t *testing.T) { domainName := acctest.RandString(10) + "dnstest.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -103,8 +106,8 @@ func TestAccIBMDNSRecordWithTag(t *testing.T) { host1 := acctest.RandString(10) + "ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -146,8 +149,8 @@ func TestAccIBMDNSRecord_MX_PRIORITY(t *testing.T) { host1 := acctest.RandString(10) + "ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -178,8 +181,8 @@ func TestAccIBMDNSRecord_SRV_PRIORITY_ZERO(t *testing.T) { protocol := "_udp" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -207,7 +210,7 @@ func testAccCheckIBMDNSRecordExists(n string, dns_domain_record *datatypes.Dns_D rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -216,7 +219,7 @@ func testAccCheckIBMDNSRecordExists(n string, dns_domain_record *datatypes.Dns_D dns_id, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetDnsDomainResourceRecordService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainResourceRecordService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) found_domain_record, err := service.Id(dns_id).GetObject() if err != nil { diff --git a/ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record.go b/ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record.go new file mode 100644 index 000000000..f185fae99 --- /dev/null +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record.go @@ -0,0 +1,149 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package classicinfrastructure + +import ( + "fmt" + "log" + "strconv" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/softlayer/softlayer-go/services" + "github.com/softlayer/softlayer-go/sl" +) + +func ResourceIBMDNSReverseRecord() *schema.Resource { + return &schema.Resource{ + Exists: resourceIBMDNSREVERSERecordExists, + Create: resourceIBMDNSREVERSERecordCreate, + Read: resourceIBMDNSREVERSERecordRead, + Update: resourceIBMDNSREVERSERecordUpdate, + Delete: resourceIBMDNSREVERSERecordDelete, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + "ipaddress": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "IP Address", + }, + "hostname": { + Type: schema.TypeString, + Required: true, + Description: "Host name", + }, + "ttl": { + Type: schema.TypeInt, + Optional: true, + DefaultFunc: func() (interface{}, error) { + return 604800, nil + }, + Description: "TTL value", + }, + }, + } +} + +// Creates DNS Domain Reverse Record +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain/CreatePtrRecord +func resourceIBMDNSREVERSERecordCreate(d *schema.ResourceData, meta interface{}) error { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetDnsDomainService(sess.SetRetries(0)) + Data := sl.String(d.Get("hostname").(string)) + Ttl := sl.Int(d.Get("ttl").(int)) + Ipaddress := sl.String(d.Get("ipaddress").(string)) + var id int + record, err := service.CreatePtrRecord(Ipaddress, Data, Ttl) + if record.Id != nil { + id = *record.Id + } + + if err != nil { + return fmt.Errorf("[ERROR] Error creating DNS Reverse %s", err) + } + d.SetId(fmt.Sprintf("%d", id)) + log.Printf("[INFO] Dns Reverse %s ", d.Id()) + return resourceIBMDNSREVERSERecordRead(d, meta) +} + +// Reads DNS Domain Reverse Record from SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/getObject +func resourceIBMDNSREVERSERecordRead(d *schema.ResourceData, meta interface{}) error { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetDnsDomainResourceRecordService(sess) + id, err := strconv.Atoi(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) + } + + _, nexterr := service.Id(id).GetObject() + if nexterr != nil { + return fmt.Errorf("[ERROR] Error retrieving DNS Reverse Record: %s", err) + } + return nil +} + +// Updates DNS Domain Reverse Record in SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/editObject +func resourceIBMDNSREVERSERecordUpdate(d *schema.ResourceData, meta interface{}) error { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetDnsDomainResourceRecordService(sess) + serviceNoRetry := services.GetDnsDomainResourceRecordService(sess.SetRetries(0)) + recordId, _ := strconv.Atoi(d.Id()) + record, err := service.Id(recordId).GetObject() + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving DNS Reverse Record: %s", err) + } + if data, ok := d.GetOk("hostname"); ok && d.HasChange("hostname") { + record.Data = sl.String(data.(string)) + } + if ttl, ok := d.GetOk("ttl"); ok && d.HasChange("ttl") { + record.Ttl = sl.Int(ttl.(int)) + } + record.IsGatewayAddress = nil + _, err = serviceNoRetry.Id(recordId).EditObject(&record) + if err != nil { + return fmt.Errorf("[ERROR] Error editing DNS Reverse Record %d: %s", recordId, err) + } + return nil +} + +// Deletes DNS Domain Reverse Record in SL system +// https://sldn.softlayer.com/reference/services/SoftLayer_Dns_Domain_ResourceRecord/deleteObject +func resourceIBMDNSREVERSERecordDelete(d *schema.ResourceData, meta interface{}) error { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetDnsDomainResourceRecordService(sess) + id, err := strconv.Atoi(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) + } + _, err = service.Id(id).DeleteObject() + + if err != nil { + return fmt.Errorf("[ERROR] Error deleting DNS Reverse Record: %s", err) + } + return nil +} + +// Exists function is called by refresh +// if the entity is absent - it is deleted from the .tfstate file +func resourceIBMDNSREVERSERecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess := meta.(conns.ClientSession).SoftLayerSession() + service := services.GetDnsDomainResourceRecordService(sess) + id, err := strconv.Atoi(d.Id()) + if err != nil { + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) + } + record, err := service.Id(id).GetObject() + if err != nil { + if apiErr, ok := err.(sl.Error); ok { + if apiErr.StatusCode == 404 { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error retrieving domain reverse record info: %s", err) + } + return record.Id != nil && *record.Id == id, nil +} diff --git a/ibm/resource_ibm_dns_reverse_record_test.go b/ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record_test.go similarity index 85% rename from ibm/resource_ibm_dns_reverse_record_test.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record_test.go index 9d7655cd1..d16f32cb0 100644 --- a/ibm/resource_ibm_dns_reverse_record_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_reverse_record_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -10,6 +10,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -24,8 +27,8 @@ func TestAccIBMDNSReverseRecord_Basic(t *testing.T) { host2 := acctest.RandString(10) + "ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSDomainDestroy, Steps: []resource.TestStep{ { @@ -53,7 +56,7 @@ func testAccCheckIBMDNSReverseRecordExists(n string, dns_domain_record *datatype rs, ok := s.RootModule().Resources[n] log.Printf("inside reverse record exist function") if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -62,7 +65,7 @@ func testAccCheckIBMDNSReverseRecordExists(n string, dns_domain_record *datatype dns_id, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetDnsDomainResourceRecordService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsDomainResourceRecordService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) found_domain_record, err := service.Id(dns_id).GetObject() if err != nil { diff --git a/ibm/resource_ibm_dns_secondary.go b/ibm/service/classicinfrastructure/resource_ibm_dns_secondary.go similarity index 81% rename from ibm/resource_ibm_dns_secondary.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_secondary.go index b87e80247..fc05395f7 100644 --- a/ibm/resource_ibm_dns_secondary.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_secondary.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -9,13 +9,14 @@ import ( "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMDNSSecondary() *schema.Resource { +func ResourceIBMDNSSecondary() *schema.Resource { return &schema.Resource{ Exists: resourceIBMDNSSecondaryExists, Create: resourceIBMDNSSecondaryCreate, @@ -67,7 +68,7 @@ func resourceIBMDNSSecondary() *schema.Resource { } func resourceIBMDNSSecondaryCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsSecondaryService(sess) // prepare creation parameters @@ -80,7 +81,7 @@ func resourceIBMDNSSecondaryCreate(d *schema.ResourceData, meta interface{}) err // create Dns_Secondary object response, err := service.CreateObject(&opts) if err != nil { - return fmt.Errorf("Error creating Dns Secondary Zone: %s", err) + return fmt.Errorf("[ERROR] Error creating Dns Secondary Zone: %s", err) } // populate id @@ -93,7 +94,7 @@ func resourceIBMDNSSecondaryCreate(d *schema.ResourceData, meta interface{}) err } func resourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsSecondaryService(sess) dnsId, _ := strconv.Atoi(d.Id()) @@ -101,7 +102,7 @@ func resourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) error // retrieve remote object state dns_domain_secondary, err := service.Id(dnsId).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Dns Secondary Zone %d: %s", dnsId, err) + return fmt.Errorf("[ERROR] Error retrieving Dns Secondary Zone %d: %s", dnsId, err) } // populate fields @@ -115,7 +116,7 @@ func resourceIBMDNSSecondaryRead(d *schema.ResourceData, meta interface{}) error } func resourceIBMDNSSecondaryUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() domainId, _ := strconv.Atoi(d.Id()) hasChange := false @@ -135,7 +136,7 @@ func resourceIBMDNSSecondaryUpdate(d *schema.ResourceData, meta interface{}) err _, err := service.Id(domainId).EditObject(&opts) if err != nil { - return fmt.Errorf("Error editing DNS secondary zone (%d): %s", domainId, err) + return fmt.Errorf("[ERROR] Error editing DNS secondary zone (%d): %s", domainId, err) } } @@ -143,22 +144,22 @@ func resourceIBMDNSSecondaryUpdate(d *schema.ResourceData, meta interface{}) err } func resourceIBMDNSSecondaryDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsSecondaryService(sess) dnsId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Error deleting Dns Secondary Zone: %s", err) + return fmt.Errorf("[ERROR] Error deleting Dns Secondary Zone: %s", err) } log.Printf("[INFO] Deleting Dns Secondary Zone: %d", dnsId) result, err := service.Id(dnsId).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Dns Secondary Zone: %s", err) + return fmt.Errorf("[ERROR] Error deleting Dns Secondary Zone: %s", err) } if !result { - return errors.New("Error deleting Dns Secondary Zone") + return errors.New("[ERROR] Error deleting Dns Secondary Zone") } d.SetId("") @@ -166,12 +167,12 @@ func resourceIBMDNSSecondaryDelete(d *schema.ResourceData, meta interface{}) err } func resourceIBMDNSSecondaryExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetDnsSecondaryService(sess) dnsId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(dnsId).GetObject() diff --git a/ibm/resource_ibm_dns_secondary_test.go b/ibm/service/classicinfrastructure/resource_ibm_dns_secondary_test.go similarity index 88% rename from ibm/resource_ibm_dns_secondary_test.go rename to ibm/service/classicinfrastructure/resource_ibm_dns_secondary_test.go index d42fa0ecc..430b50926 100644 --- a/ibm/resource_ibm_dns_secondary_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_dns_secondary_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,8 +19,8 @@ import ( func TestAccIBMDnsSecondary_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSSecondaryDestroy, Steps: []resource.TestStep{ { @@ -47,8 +50,8 @@ func TestAccIBMDnsSecondary_Basic(t *testing.T) { func TestAccIBMDnsSecondary_Basic_Tags(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSSecondaryDestroy, Steps: []resource.TestStep{ { @@ -82,8 +85,8 @@ func TestAccIBMDnsSecondary_Basic_Tags(t *testing.T) { func TestAccIBMDnsSecondary_Import(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDNSSecondaryDestroy, Steps: []resource.TestStep{ { @@ -99,7 +102,7 @@ func TestAccIBMDnsSecondary_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_dns_secondary.dns-secondary-zone-1", ImportState: true, ImportStateVerify: true, @@ -113,16 +116,16 @@ func testAccCheckIBMDnsSecondaryZoneExists(n string) resource.TestCheckFunc { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } dnsId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetDnsSecondaryService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsSecondaryService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundSecondaryZone, err := service.Id(dnsId).GetObject() if err != nil { @@ -138,7 +141,7 @@ func testAccCheckIBMDnsSecondaryZoneExists(n string) resource.TestCheckFunc { } func testAccCheckIBMDNSSecondaryDestroy(s *terraform.State) error { - service := services.GetDnsSecondaryService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetDnsSecondaryService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_dns_secondary" { diff --git a/ibm/resource_ibm_firewall.go b/ibm/service/classicinfrastructure/resource_ibm_firewall.go similarity index 85% rename from ibm/resource_ibm_firewall.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall.go index 9615d8e5d..a9696963c 100644 --- a/ibm/resource_ibm_firewall.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,8 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -29,7 +31,7 @@ const ( multiVlanMask = "id,name,networkFirewall[id,customerManagedFlag,datacenter.name,billingItem[orderItem.order.id,activeChildren[categoryCode, description,id]],managementCredentials,firewallType],publicIpAddress.ipAddress,publicIpv6Address.ipAddress,publicVlan[id,primaryRouter.hostname],privateVlan[id,primaryRouter.hostname],privateIpAddress.ipAddress,insideVlans[id],memberCount,status.keyName" ) -func resourceIBMFirewall() *schema.Resource { +func ResourceIBMFirewall() *schema.Resource { return &schema.Resource{ Create: resourceIBMFirewallCreate, Read: resourceIBMFirewallRead, @@ -44,7 +46,7 @@ func resourceIBMFirewall() *schema.Resource { Optional: true, ForceNew: true, Default: "HARDWARE_FIREWALL_DEDICATED", - ValidateFunc: validateAllowedStringValue([]string{ + ValidateFunc: validate.ValidateAllowedStringValues([]string{ "HARDWARE_FIREWALL_DEDICATED", "FORTIGATE_SECURITY_APPLIANCE", }), @@ -96,7 +98,7 @@ func resourceIBMFirewall() *schema.Resource { } func resourceIBMFirewallCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() keyName := "HARDWARE_FIREWALL_DEDICATED" firewallType := d.Get("firewall_type").(string) @@ -133,7 +135,7 @@ func resourceIBMFirewallCreate(d *schema.ResourceData, meta interface{}) error { } if len(targetItems) == 0 { - return fmt.Errorf("No product items matching %s could be found", keyName) + return fmt.Errorf("[ERROR] No product items matching %s could be found", keyName) } productOrderContainer := datatypes.Container_Product_Order_Network_Protection_Firewall_Dedicated{ @@ -154,11 +156,11 @@ func resourceIBMFirewallCreate(d *schema.ResourceData, meta interface{}) error { receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall: %s", err) } vlan, _, _, err := findDedicatedFirewallByOrderId(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall: %s", err) } id := *vlan.NetworkVlanFirewall.Id @@ -182,7 +184,7 @@ func resourceIBMFirewallCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMFirewallRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, _ := strconv.Atoi(d.Id()) @@ -192,7 +194,7 @@ func resourceIBMFirewallRead(d *schema.ResourceData, meta interface{}) error { GetObject() if err != nil { - return fmt.Errorf("Error retrieving firewall information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving firewall information: %s", err) } d.Set("public_vlan_id", *fw.NetworkVlan.Id) @@ -221,7 +223,7 @@ func resourceIBMFirewallUpdate(d *schema.ResourceData, meta interface{}) error { fwID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid firewall ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid firewall ID, must be an integer: %s", err) } // Update tags @@ -236,7 +238,7 @@ func resourceIBMFirewallUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMFirewallDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwService := services.GetNetworkVlanFirewallService(sess) fwID, _ := strconv.Atoi(d.Id()) @@ -245,11 +247,11 @@ func resourceIBMFirewallDelete(d *schema.ResourceData, meta interface{}) error { billingItem, err := fwService.Id(fwID).GetBillingItem() if err != nil { - return fmt.Errorf("Error while looking up billing item associated with the firewall: %s", err) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the firewall: %s", err) } if billingItem.Id == nil { - return fmt.Errorf("Error while looking up billing item associated with the firewall: No billing item for ID:%d", fwID) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the firewall: No billing item for ID:%d", fwID) } success, err := services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() @@ -265,11 +267,11 @@ func resourceIBMFirewallDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMFirewallExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = services.GetNetworkVlanFirewallService(sess). @@ -280,7 +282,7 @@ func resourceIBMFirewallExists(d *schema.ResourceData, meta interface{}) (bool, if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving firewall information: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving firewall information: %s", err) } return true, nil @@ -338,7 +340,7 @@ func findDedicatedFirewallByOrderId(sess *session.Session, orderId int, d *schem } else if len(vlans) == 0 || len(firewalls) == 0 || *upgraderequest.Status.Name != "Complete" { return datatypes.Network_Vlan{}, "pending", nil } - return nil, "", fmt.Errorf("Expected one dedicated firewall: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one dedicated firewall: %s", err) }, Timeout: 2 * time.Hour, Delay: 10 * time.Second, @@ -356,13 +358,13 @@ func findDedicatedFirewallByOrderId(sess *session.Session, orderId int, d *schem return datatypes.Network_Vlan{}, datatypes.Network_Gateway{}, result, nil } return datatypes.Network_Vlan{}, datatypes.Network_Gateway{}, datatypes.Product_Upgrade_Request{}, - fmt.Errorf("Something went wrong while upgrading '%d'", orderId) + fmt.Errorf("[ERROR] Something went wrong while upgrading '%d'", orderId) } else if _, ok := d.GetOk("pod"); ok { if result, ok := pendingResult.(datatypes.Network_Gateway); ok { return datatypes.Network_Vlan{}, result, datatypes.Product_Upgrade_Request{}, nil } return datatypes.Network_Vlan{}, datatypes.Network_Gateway{}, datatypes.Product_Upgrade_Request{}, - fmt.Errorf("Cannot find Dedicated Firewall with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find Dedicated Firewall with order id '%d'", orderId) } var result, ok = pendingResult.(datatypes.Network_Vlan) @@ -371,14 +373,14 @@ func findDedicatedFirewallByOrderId(sess *session.Session, orderId int, d *schem } return datatypes.Network_Vlan{}, datatypes.Network_Gateway{}, datatypes.Product_Upgrade_Request{}, - fmt.Errorf("Cannot find Dedicated Firewall with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find Dedicated Firewall with order id '%d'", orderId) } func setFirewallTags(id int, tags string, meta interface{}) error { - service := services.GetNetworkVlanFirewallService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkVlanFirewallService(meta.(conns.ClientSession).SoftLayerSession()) _, err := service.Id(id).SetTags(sl.String(tags)) if err != nil { - return fmt.Errorf("Could not set tags on firewall %d", id) + return fmt.Errorf("[ERROR] Could not set tags on firewall %d", id) } return nil } diff --git a/ibm/resource_ibm_firewall_policy.go b/ibm/service/classicinfrastructure/resource_ibm_firewall_policy.go similarity index 86% rename from ibm/resource_ibm_firewall_policy.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall_policy.go index 61d1d42e3..35565de94 100644 --- a/ibm/resource_ibm_firewall_policy.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall_policy.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -12,6 +12,7 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" @@ -23,7 +24,7 @@ const ( aclMask = "name,firewallInterfaces[name,firewallContextAccessControlLists]" ) -func resourceIBMFirewallPolicy() *schema.Resource { +func ResourceIBMFirewallPolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMFirewallPolicyCreate, Read: resourceIBMFirewallPolicyRead, @@ -155,18 +156,18 @@ func getFirewallContextAccessControlListId(fwId int, sess *session.Session) (int return *fwInterface.FirewallContextAccessControlLists[0].Id, nil } } - return 0, fmt.Errorf("No firewallContextAccessControlListId.") + return 0, fmt.Errorf("[ERROR] No firewallContextAccessControlListId") } func resourceIBMFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwId := d.Get("firewall_id").(int) rules := prepareRules(d) fwContextACLId, err := getFirewallContextAccessControlListId(fwId, sess) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall rules: %s", err) } ruleTemplate := datatypes.Network_Firewall_Update_Request{ @@ -178,7 +179,7 @@ func resourceIBMFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) e _, err = services.GetNetworkFirewallUpdateRequestService(sess.SetRetries(0)).CreateObject(&ruleTemplate) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall rules: %s", err) } d.SetId(strconv.Itoa(fwId)) @@ -191,7 +192,7 @@ func resourceIBMFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) e } func resourceIBMFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwRulesID, _ := strconv.Atoi(d.Id()) @@ -201,7 +202,7 @@ func resourceIBMFirewallPolicyRead(d *schema.ResourceData, meta interface{}) err GetObject() if err != nil { - return fmt.Errorf("Error retrieving firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error retrieving firewall rules: %s", err) } rules := make([]map[string]interface{}, 0, len(fw.Rules)) @@ -259,17 +260,17 @@ func appendAnyOpenRule(rules []datatypes.Network_Firewall_Update_Request_Rule, p } func resourceIBMFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid firewall ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid firewall ID, must be an integer: %s", err) } rules := prepareRules(d) fwContextACLId, err := getFirewallContextAccessControlListId(fwId, sess) if err != nil { - return fmt.Errorf("Error during updating of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during updating of dedicated hardware firewall rules: %s", err) } ruleTemplate := datatypes.Network_Firewall_Update_Request{ @@ -281,7 +282,7 @@ func resourceIBMFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) e _, err = services.GetNetworkFirewallUpdateRequestService(sess.SetRetries(0)).CreateObject(&ruleTemplate) if err != nil { - return fmt.Errorf("Error during updating of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during updating of dedicated hardware firewall rules: %s", err) } time.Sleep(time.Minute) @@ -289,15 +290,15 @@ func resourceIBMFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) e } func resourceIBMFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid firewall ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid firewall ID, must be an integer: %s", err) } fwContextACLId, err := getFirewallContextAccessControlListId(fwId, sess) if err != nil { - return fmt.Errorf("Error during deleting of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during deleting of dedicated hardware firewall rules: %s", err) } ruleTemplate := datatypes.Network_Firewall_Update_Request{ @@ -316,7 +317,7 @@ func resourceIBMFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) e _, err = services.GetNetworkFirewallUpdateRequestService(sess.SetRetries(0)).CreateObject(&ruleTemplate) if err != nil { - return fmt.Errorf("Error during deleting of dedicated hardware firewall rules: %s", err) + return fmt.Errorf("[ERROR] Error during deleting of dedicated hardware firewall rules: %s", err) } time.Sleep(time.Minute) @@ -324,11 +325,11 @@ func resourceIBMFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) e } func resourceIBMFirewallPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwRulesID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } fw, err := services.GetNetworkVlanFirewallService(sess). @@ -342,7 +343,7 @@ func resourceIBMFirewallPolicyExists(d *schema.ResourceData, meta interface{}) ( return false, nil } } - return false, fmt.Errorf("Error retrieving firewall rules: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving firewall rules: %s", err) } if len(fw.Rules) == 0 { diff --git a/ibm/resource_ibm_firewall_policy_test.go b/ibm/service/classicinfrastructure/resource_ibm_firewall_policy_test.go similarity index 97% rename from ibm/resource_ibm_firewall_policy_test.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall_policy_test.go index 5c6955e39..81904e03c 100644 --- a/ibm/resource_ibm_firewall_policy_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall_policy_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ import ( func TestAccIBMFirewallPolicy_Basic(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewallPolicy_basic(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -66,7 +68,7 @@ func TestAccIBMFirewallPolicy_Basic(t *testing.T) { "ibm_firewall_policy.rules", "rules.2.protocol", "tcp"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMFirewallPolicy_update(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -102,10 +104,10 @@ func TestAccIBMFirewallPolicy_Basic(t *testing.T) { func TestAccIBMFirewallPolicyWithTag(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewallPolicyWithTag(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -126,7 +128,7 @@ func TestAccIBMFirewallPolicyWithTag(t *testing.T) { "ibm_firewall_policy.rules", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMFirewallPolicyWithUpdatedTag(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_firewall_shared.go b/ibm/service/classicinfrastructure/resource_ibm_firewall_shared.go similarity index 85% rename from ibm/resource_ibm_firewall_shared.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall_shared.go index 984dc1932..8c6df2c24 100644 --- a/ibm/resource_ibm_firewall_shared.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall_shared.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,8 @@ import ( "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -21,7 +23,7 @@ const ( FwHardwarePackageType = "ADDITIONAL_SERVICES_FIREWALL" ) -func resourceIBMFirewallShared() *schema.Resource { +func ResourceIBMFirewallShared() *schema.Resource { return &schema.Resource{ Create: resourceIBMFirewallSharedCreate, Read: resourceIBMFirewallSharedRead, @@ -44,7 +46,7 @@ func resourceIBMFirewallShared() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateAllowedStringValue([]string{"10MBPS_HARDWARE_FIREWALL", "20MBPS_HARDWARE_FIREWALL", "100MBPS_HARDWARE_FIREWALL", "1000MBPS_HARDWARE_FIREWALL", "200MBPS_HARDWARE_FIREWALL", "2000MBPS_HARDWARE_FIREWALL"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"10MBPS_HARDWARE_FIREWALL", "20MBPS_HARDWARE_FIREWALL", "100MBPS_HARDWARE_FIREWALL", "1000MBPS_HARDWARE_FIREWALL", "200MBPS_HARDWARE_FIREWALL", "2000MBPS_HARDWARE_FIREWALL"}), Description: "Firewall type", }, "virtual_instance_id": { @@ -66,9 +68,10 @@ func resourceIBMFirewallShared() *schema.Resource { } // keyName is in between:[10MBPS_HARDWARE_FIREWALL, 20MBPS_HARDWARE_FIREWALL, -// 100MBPS_HARDWARE_FIREWALL, 1000MBPS_HARDWARE_FIREWALL] +// +// 100MBPS_HARDWARE_FIREWALL, 1000MBPS_HARDWARE_FIREWALL] func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() keyName := d.Get("firewall_type").(string) @@ -82,7 +85,7 @@ func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) e } if virtualId == 0 && hardwareId == 0 { - return fmt.Errorf("Provide either `virtual_instance_id` or `hardware_instance_id`") + return fmt.Errorf("[ERROR] Provide either `virtual_instance_id` or `hardware_instance_id`") } //var productOrderContainer *string @@ -106,7 +109,7 @@ func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) e } if len(targetItems) == 0 { - return fmt.Errorf("No product items matching %s could be found", keyName) + return fmt.Errorf("[ERROR] No product items matching %s could be found", keyName) } masked := "id,firewallServiceComponent[id,status]" @@ -165,7 +168,7 @@ func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) e d.SetId(fmt.Sprintf("%d", idd)) if err != nil { - return fmt.Errorf("Error during creation of hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of hardware firewall: %s", err) } } @@ -225,7 +228,7 @@ func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) e d.SetId(fmt.Sprintf("%d", idd2)) log.Print(idd2) if err != nil { - return fmt.Errorf("Error during creation of hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of hardware firewall: %s", err) } } @@ -235,7 +238,7 @@ func resourceIBMFirewallSharedCreate(d *schema.ResourceData, meta interface{}) e } func resourceIBMFirewallSharedRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() firewall_type := (d.Get("firewall_type").(string)) d.Set("firewall_type", firewall_type) @@ -247,15 +250,15 @@ func resourceIBMFirewallSharedRead(d *schema.ResourceData, meta interface{}) err data, err := fservice.Id(fwID).Mask("billingItem.id").GetObject() d.Set("billing_item_id", *data.BillingItem.Id) if err != nil { - return fmt.Errorf("Error during creation of hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of hardware firewall: %s", err) } return nil } -//detach hardware firewall from particular machine +// detach hardware firewall from particular machine func resourceIBMFirewallSharedDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() idd2 := (d.Get("billing_item_id")).(int) success, err := services.GetBillingItemService(sess).Id(idd2).CancelService() @@ -270,9 +273,9 @@ func resourceIBMFirewallSharedDelete(d *schema.ResourceData, meta interface{}) e return nil } -//exists method +// exists method func resourceIBMFirewallSharedExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fservice := services.GetNetworkComponentFirewallService(sess) id, err := strconv.Atoi(d.Id()) response, err := fservice.Id(id).GetObject() diff --git a/ibm/resource_ibm_firewall_shared_test.go b/ibm/service/classicinfrastructure/resource_ibm_firewall_shared_test.go similarity index 83% rename from ibm/resource_ibm_firewall_shared_test.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall_shared_test.go index 362c61a73..937e7848a 100644 --- a/ibm/resource_ibm_firewall_shared_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall_shared_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/services" @@ -15,11 +18,11 @@ import ( func TestAccIBMFirewallShared_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMHardwareFirewallSharedDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewallShared_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -35,7 +38,7 @@ func TestAccIBMFirewallShared_Basic(t *testing.T) { } func testAccCheckIBMHardwareFirewallSharedDestroy(s *terraform.State) error { - service := services.GetNetworkComponentFirewallService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkComponentFirewallService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_hardware_firewall_shared" { diff --git a/ibm/resource_ibm_firewall_test.go b/ibm/service/classicinfrastructure/resource_ibm_firewall_test.go similarity index 93% rename from ibm/resource_ibm_firewall_test.go rename to ibm/service/classicinfrastructure/resource_ibm_firewall_test.go index a982f51c7..61f71773b 100644 --- a/ibm/resource_ibm_firewall_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_firewall_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMFirewall_Basic(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewall_basic(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -57,10 +59,10 @@ func TestAccIBMFirewall_FSA(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewall_FSA(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -106,10 +108,10 @@ func TestAccIBMFirewall_Tag(t *testing.T) { tags2 := "mesos-master" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMFirewallTag(hostname, tags1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -124,7 +126,7 @@ func TestAccIBMFirewall_Tag(t *testing.T) { ), ), }, - resource.TestStep{ + { Config: testAccCheckIBMFirewallUpdateTag(hostname, tags1, tags2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_ipsec_vpn.go b/ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn.go similarity index 82% rename from ibm/resource_ibm_ipsec_vpn.go rename to ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn.go index 4f85af9ef..157cd0165 100644 --- a/ibm/resource_ibm_ipsec_vpn.go +++ b/ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -21,7 +24,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMIPSecVPN() *schema.Resource { +func ResourceIBMIPSecVPN() *schema.Resource { return &schema.Resource{ Create: resourceIBMIPSecVpnCreate, Read: resourceIBMIPSecVPNRead, @@ -56,25 +59,25 @@ func resourceIBMIPSecVPN() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "MD5", - ValidateFunc: validateAuthProtocol, + ValidateFunc: validate.ValidateAuthProtocol, }, "encryption": { Type: schema.TypeString, Optional: true, Default: "3DES", - ValidateFunc: validateEncyptionProtocol, + ValidateFunc: validate.ValidateEncyptionProtocol, }, "diffie_hellman_group": { Type: schema.TypeInt, Optional: true, Default: 2, - ValidateFunc: validateDiffieHellmanGroup, + ValidateFunc: validate.ValidateDiffieHellmanGroup, }, "keylife": { Type: schema.TypeInt, Optional: true, Default: 14400, - ValidateFunc: validatekeylife, + ValidateFunc: validate.Validatekeylife, }, }, }, @@ -90,25 +93,25 @@ func resourceIBMIPSecVPN() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "MD5", - ValidateFunc: validateAuthProtocol, + ValidateFunc: validate.ValidateAuthProtocol, }, "encryption": { Type: schema.TypeString, Optional: true, Default: "3DES", - ValidateFunc: validateEncyptionProtocol, + ValidateFunc: validate.ValidateEncyptionProtocol, }, "diffie_hellman_group": { Type: schema.TypeInt, Optional: true, Default: 2, - ValidateFunc: validateDiffieHellmanGroup, + ValidateFunc: validate.ValidateDiffieHellmanGroup, }, "keylife": { Type: schema.TypeInt, Optional: true, Default: 3600, - ValidateFunc: validatekeylife, + ValidateFunc: validate.Validatekeylife, }, }, }, @@ -170,7 +173,7 @@ func resourceIBMIPSecVPN() *schema.Resource { }, "remote_ip_cidr": { Type: schema.TypeString, - ValidateFunc: validateCIDR, + ValidateFunc: validate.ValidateCIDR, Required: true, }, "account_id": { @@ -194,13 +197,13 @@ const ( ) func resourceIBMIPSecVpnCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() datacenter := d.Get("datacenter").(string) dc, err := location.GetDatacenterByName(sess, datacenter, "id") locationid := strconv.Itoa(*dc.Id) packageid := 0 if err != nil { - return fmt.Errorf("Datacenter not found") + return fmt.Errorf("[ERROR] Something not found") } locationservice := services.GetLocationService(sess) priceidds, _ := locationservice.Id(*dc.Id).GetPriceGroups() @@ -227,18 +230,18 @@ func resourceIBMIPSecVpnCreate(d *schema.ResourceData, meta interface{}) error { _, err = services.GetProductOrderService(sess.SetRetries(0)). VerifyOrder(&IPSecOrder) if err != nil { - return fmt.Errorf("Error during Verify order for Creating: %s", err) + return fmt.Errorf("[ERROR] Error during Verify order for Creating: %s", err) } //Calling place order receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&IPSecOrder, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during Place order for Creating: %s", err) + return fmt.Errorf("[ERROR] Error during Place order for Creating: %s", err) } vpn, _ := findIPSecVpnByOrderID(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of IPSec VPN: %s", err) + return fmt.Errorf("[ERROR] Error during creation of IPSec VPN: %s", err) } id := *vpn.Id d.SetId(fmt.Sprintf("%d", id)) @@ -267,7 +270,7 @@ func findIPSecVpnByOrderID(sess *session.Session, orderID int, d *schema.Resourc } else if len(vpn) == 0 { return datatypes.Network_Tunnel_Module_Context{}, "pending", nil } - return nil, "", fmt.Errorf("Expected one IPSec VPN: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one IPSec VPN: %s", err) }, Timeout: 2 * time.Hour, Delay: 10 * time.Second, @@ -286,32 +289,32 @@ func findIPSecVpnByOrderID(sess *session.Session, orderID int, d *schema.Resourc } return datatypes.Network_Tunnel_Module_Context{}, - fmt.Errorf("Cannot find IPSec Vpn with order id '%d'", orderID) + fmt.Errorf("[ERROR] Cannot find IPSec Vpn with order id '%d'", orderID) } func resourceIBMIPSecVPNRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vpnID, _ := strconv.Atoi(d.Id()) vpn, err := services.GetNetworkTunnelModuleContextService(sess). Id(vpnID).Mask(ipsecMask). GetObject() if err != nil { - return fmt.Errorf("Error retrieving firewall information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving firewall information: %s", err) } d.Set("name", *vpn.Name) d.Set("internal_peer_ip_address", *vpn.InternalPeerIpAddress) if vpn.Datacenter != nil { d.Set("datacenter", *vpn.Datacenter.Name) } - d.Set("phase_one", flattenPhaseOneAttributes(&vpn)) - d.Set("phase_two", flattenPhaseTwoAttributes(&vpn)) + d.Set("phase_one", flex.FlattenPhaseOneAttributes(&vpn)) + d.Set("phase_two", flex.FlattenPhaseTwoAttributes(&vpn)) fwID, err := strconv.Atoi(d.Id()) if vpn.AddressTranslations != nil { - d.Set("address_translation", flattenaddressTranslation(&vpn, fwID)) + d.Set("address_translation", flex.FlattenaddressTranslation(&vpn, fwID)) } if vpn.CustomerSubnets != nil { - d.Set("remote_subnet", flattenremoteSubnet(&vpn)) + d.Set("remote_subnet", flex.FlattenremoteSubnet(&vpn)) } if vpn.PresharedKey != nil { d.Set("preshared_key", *vpn.PresharedKey) @@ -332,11 +335,11 @@ func resourceIBMIPSecVPNRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMIPSecVPNExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = services.GetNetworkTunnelModuleContextService(sess). @@ -347,14 +350,14 @@ func resourceIBMIPSecVPNExists(d *schema.ResourceData, meta interface{}) (bool, if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving vpn information: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving vpn information: %s", err) } return true, nil } func resourceIBMIPSecVPNDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vpnService := services.GetNetworkTunnelModuleContextService(sess) vpnID, _ := strconv.Atoi(d.Id()) @@ -363,11 +366,11 @@ func resourceIBMIPSecVPNDelete(d *schema.ResourceData, meta interface{}) error { billingItem, err := vpnService.Id(vpnID).GetBillingItem() if err != nil { - return fmt.Errorf("Error while looking up billing item associated with the ipsecvpn: %s", err) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the ipsecvpn: %s", err) } if billingItem.Id == nil { - return fmt.Errorf("Error while looking up billing item associated with the ipsecvpn: No billing item for ID:%d", vpnID) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the ipsecvpn: No billing item for ID:%d", vpnID) } success, err := services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() @@ -383,11 +386,11 @@ func resourceIBMIPSecVPNDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vpnID, err := strconv.Atoi(d.Id()) var addresstranslation datatypes.Network_Tunnel_Module_Context_Address_Translation if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } vpn, err := services.GetNetworkTunnelModuleContextService(sess). @@ -395,7 +398,7 @@ func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { GetObject() if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } if d.HasChange("phase_one") { for _, e := range d.Get("phase_one").([]interface{}) { @@ -441,21 +444,21 @@ func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { subnetid := d.Get("internal_subnet_id").(int) _, err = services.GetNetworkTunnelModuleContextService(sess).AddPrivateSubnetToNetworkTunnel(&subnetid) if err != nil { - return fmt.Errorf("Unable to find object with id of: %s", err) + return fmt.Errorf("[ERROR] Unable to find object with id of: %s", err) } } if d.HasChange("remote_subnet_id") { subnetid := d.Get("remote_subnet_id").(int) _, err = services.GetNetworkTunnelModuleContextService(sess).AddCustomerSubnetToNetworkTunnel(&subnetid) if err != nil { - return fmt.Errorf("Unable to find object with id of: %s", err) + return fmt.Errorf("[ERROR] Unable to find object with id of: %s", err) } } if d.HasChange("service_subnet_id") { subnetid := d.Get("service_subnet_id").(int) _, err = services.GetNetworkTunnelModuleContextService(sess).AddServiceSubnetToNetworkTunnel(&subnetid) if err != nil { - return fmt.Errorf("Unable to find object with id of: %s", err) + return fmt.Errorf("[ERROR] Unable to find object with id of: %s", err) } } if d.HasChange("address_translation") { @@ -470,7 +473,7 @@ func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { } _, err = services.GetNetworkTunnelModuleContextService(sess).Id(vpnID).CreateAddressTranslation(&addresstranslation) if err != nil { - return fmt.Errorf("Unable to create the address translation: %s", err) + return fmt.Errorf("[ERROR] Unable to create the address translation: %s", err) } } if d.HasChange("remote_subnet") { @@ -487,11 +490,11 @@ func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { remoteSubnet.AccountId = &accountID subnet, err := services.GetNetworkCustomerSubnetService(sess).Id(vpnID).CreateObject(&remoteSubnet) if err != nil { - return fmt.Errorf("Some error occured creating the customer subnet resource %s", err) + return fmt.Errorf("[ERROR] Expected error occured creating the customer subnet resource %s", err) } _, err = services.GetNetworkTunnelModuleContextService(sess).Id(vpnID).AddCustomerSubnetToNetworkTunnel(subnet.Id) if err != nil { - return fmt.Errorf("Some error occured adding the customer subnet to the network tunnel module %s", err) + return fmt.Errorf("[ERROR] Expected error occured adding the customer subnet to the network tunnel module %s", err) } } @@ -500,12 +503,12 @@ func resourceIBMIPSecVPNUpdate(d *schema.ResourceData, meta interface{}) error { _, err = services.GetNetworkTunnelModuleContextService(sess).Id(vpnID).ApplyConfigurationsToDevice() if err != nil { - return fmt.Errorf("There is some erorr applying the configuration %s", err) + return fmt.Errorf("[ERROR] There is some erorr applying the configuration %s", err) } } else if _, ok := d.GetOk("remote_subnet"); ok { _, err = services.GetNetworkTunnelModuleContextService(sess).Id(vpnID).ApplyConfigurationsToDevice() if err != nil { - return fmt.Errorf("There is some erorr applying the configuration %s", err) + return fmt.Errorf("[ERROR] There is some erorr applying the configuration %s", err) } } diff --git a/ibm/resource_ibm_ipsec_vpn_test.go b/ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn_test.go similarity index 80% rename from ibm/resource_ibm_ipsec_vpn_test.go rename to ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn_test.go index 74b62e8a9..f5ef88731 100644 --- a/ibm/resource_ibm_ipsec_vpn_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_ipsec_vpn_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,45 +19,47 @@ import ( "github.com/softlayer/softlayer-go/sl" ) +const NOT_FOUND = "SoftLayer_Exception_Network_LBaaS_ObjectNotFound" + func TestAccIBMIPSec_Basic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIPSecConfig_basic(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "datacenter", ipsecDatacenter), + "ibm_ipsec.ipsec", "datacenter", acc.IpsecDatacenter), ), }, { Config: testAccCheckIBMIPSECConfig_update(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "datacenter", ipsecDatacenter), + "ibm_ipsec.ipsec", "datacenter", acc.IpsecDatacenter), resource.TestCheckResourceAttr( "ibm_ipsec.ipsec", "phase_one.#", "1"), resource.TestCheckResourceAttr( "ibm_ipsec.ipsec", "phase_two.#", "1"), resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "remote_subnet_id", customersubnetid), + "ibm_ipsec.ipsec", "remote_subnet_id", acc.Customersubnetid), resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "remote_subnet_id", customersubnetid)), + "ibm_ipsec.ipsec", "remote_subnet_id", acc.Customersubnetid)), }, { Config: testAccCheckIBMIPSECConfig_updatesubnet(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "datacenter", ipsecDatacenter), + "ibm_ipsec.ipsec", "datacenter", acc.IpsecDatacenter), resource.TestCheckResourceAttr( "ibm_ipsec.ipsec", "phase_one.#", "1"), resource.TestCheckResourceAttr( "ibm_ipsec.ipsec", "phase_two.#", "1"), resource.TestCheckResourceAttr( - "ibm_ipsec.ipsec", "Customer_Peer_IP", customerpeerip), + "ibm_ipsec.ipsec", "Customer_Peer_IP", acc.Customerpeerip), resource.TestCheckResourceAttr( "ibm_ipsec.ipsec", "remote_subnet.#", "1"), resource.TestCheckResourceAttr( @@ -67,11 +72,11 @@ func TestAccIBMIPSec_Basic(t *testing.T) { func TestAccIBMIPSec_InvalidEncryptionProtocol(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIPSECConfig_InvalidEncryptionProtocol, ExpectError: regexp.MustCompile("auth protocol can be DES or 3DES or AES128 or AES192 or AES256"), }, @@ -81,11 +86,11 @@ func TestAccIBMIPSec_InvalidEncryptionProtocol(t *testing.T) { func TestAccIBMIPSec_InvalidDiffieHellmanGroup(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIPSECConfig_InvalidDiffieHellmanGroup, ExpectError: regexp.MustCompile("auth protocol can be MD5 or SHA1 or SHA256"), }, @@ -95,11 +100,11 @@ func TestAccIBMIPSec_InvalidDiffieHellmanGroup(t *testing.T) { func TestAccIBMIPSec_InvalidAuthProtocol(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIPSECConfig_InvalidAuthProtocol, ExpectError: regexp.MustCompile("auth protocol can be MD5 or SHA1 or SHA256"), }, @@ -109,11 +114,11 @@ func TestAccIBMIPSec_InvalidAuthProtocol(t *testing.T) { func TestAccIBMIPSec_InvalidKeyLife(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIPSECConfig_InvalidKeyLife, ExpectError: regexp.MustCompile("keylife value can be between 120 and 172800"), }, @@ -122,7 +127,7 @@ func TestAccIBMIPSec_InvalidKeyLife(t *testing.T) { } func testAccCheckIBMIPSecDestroy(s *terraform.State) error { - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_ipsec_vpn" { @@ -131,14 +136,14 @@ func testAccCheckIBMIPSecDestroy(s *terraform.State) error { id, _ := strconv.Atoi(rs.Primary.ID) // Try to find the key - _, err = services.GetNetworkTunnelModuleContextService(sess). + _, err := services.GetNetworkTunnelModuleContextService(sess). Id(id). GetObject() if err == nil { return fmt.Errorf("ipsec vpn (%s) to be destroyed still exists", rs.Primary.ID) } else if apiErr, ok := err.(sl.Error); ok && apiErr.Exception != NOT_FOUND { - return fmt.Errorf("Error waiting for IPSec VPN (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for IPSec VPN (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -152,7 +157,7 @@ resource "ibm_ipsec_vpn" "ipsec" { datacenter = "%s" } -`, ipsecDatacenter) +`, acc.IpsecDatacenter) } func testAccCheckIBMIPSECConfig_update(name string) string { @@ -165,7 +170,7 @@ func testAccCheckIBMIPSECConfig_update(name string) string { remote_subnet_id = %s } -`, customerpeerip, customersubnetid) +`, acc.Customerpeerip, acc.Customersubnetid) } func testAccCheckIBMIPSECConfig_updatesubnet(name string) string { @@ -178,7 +183,7 @@ func testAccCheckIBMIPSECConfig_updatesubnet(name string) string { remote_subnet = [{Remote_ip_adress = "10.0.0.0",Remote_IP_CIDR = 22}] } -`, ipsecDatacenter, customerpeerip) +`, acc.IpsecDatacenter, acc.Customerpeerip) } const testAccCheckIBMIPSECConfig_InvalidEncryptionProtocol = `resource "ibm_ipsec_vpn" "ipsec" { diff --git a/ibm/resource_ibm_lb.go b/ibm/service/classicinfrastructure/resource_ibm_lb.go similarity index 85% rename from ibm/resource_ibm_lb.go rename to ibm/service/classicinfrastructure/resource_ibm_lb.go index 92ea4551a..2cfc1947e 100644 --- a/ibm/resource_ibm_lb.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -30,7 +31,7 @@ const ( "sslEnabledFlag,sslActiveFlag,loadBalancerHardware[datacenter[name]],ipAddress[ipAddress,subnetId],billingItem[upgradeItems[capacity]]" ) -func resourceIBMLb() *schema.Resource { +func ResourceIBMLb() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbCreate, Read: resourceIBMLbRead, @@ -109,7 +110,7 @@ func resourceIBMLb() *schema.Resource { func resourceIBMLbCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() connections := d.Get("connections").(int) haEnabled := d.Get("ha_enabled").(bool) @@ -179,7 +180,7 @@ func resourceIBMLbCreate(d *schema.ResourceData, meta interface{}) error { } if len(targetItems) == 0 { - return fmt.Errorf("No product items matching %s could be found", keyName) + return fmt.Errorf("[ERROR] No product items matching %s could be found", keyName) } //select prices with the required capacity @@ -207,12 +208,12 @@ func resourceIBMLbCreate(d *schema.ResourceData, meta interface{}) error { receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of load balancer: %s", err) + return fmt.Errorf("[ERROR] Error during creation of load balancer: %s", err) } loadBalancer, err := findLoadBalancerByOrderId(sess, *receipt.OrderId, dedicated, d) if err != nil { - return fmt.Errorf("Error during creation of load balancer: %s", err) + return fmt.Errorf("[ERROR] Error during creation of load balancer: %s", err) } d.SetId(fmt.Sprintf("%d", *loadBalancer.Id)) @@ -228,7 +229,7 @@ func resourceIBMLbCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipID, _ := strconv.Atoi(d.Id()) @@ -253,7 +254,7 @@ func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { if oldValue > 0 { if *vip.DedicatedFlag { - return fmt.Errorf("Error Updating load balancer connection limit: Upgrade for dedicated loadbalancer is not supported") + return fmt.Errorf("[ERROR] Error Updating load balancer connection limit: Upgrade for dedicated loadbalancer is not supported") } if vip.BillingItem.UpgradeItems[0].Capacity != nil { validUpgradeValue := vip.BillingItem.UpgradeItems[0].Capacity @@ -261,16 +262,16 @@ func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { _, err := services.GetNetworkApplicationDeliveryControllerLoadBalancerVirtualIpAddressService(sess). Id(vipID).UpgradeConnectionLimit() if err != nil { - return fmt.Errorf("Error Updating load balancer connection limit: %s", err) + return fmt.Errorf("[ERROR] Error Updating load balancer connection limit: %s", err) } } else { - return fmt.Errorf("Error Updating load balancer connection limit : Valid value to which connection limit can be upgraded is : %d ", int(*validUpgradeValue)) + return fmt.Errorf("[ERROR] Error Updating load balancer connection limit : Valid value to which connection limit can be upgraded is : %d ", int(*validUpgradeValue)) } } else { - return fmt.Errorf("Error Updating load balancer connection limit: No upgrade available, already it has maximum connection limit") + return fmt.Errorf("[ERROR] Error Updating load balancer connection limit: No upgrade available, already it has maximum connection limit") } } @@ -283,7 +284,7 @@ func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { _, err := services.GetNetworkApplicationDeliveryControllerLoadBalancerVirtualIpAddressService(sess). Id(vipID).StartSsl() if err != nil { - return fmt.Errorf("Error starting ssl acceleration for load balancer : %s", err) + return fmt.Errorf("[ERROR] Error starting ssl acceleration for load balancer : %s", err) } } else { @@ -291,7 +292,7 @@ func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { _, err := services.GetNetworkApplicationDeliveryControllerLoadBalancerVirtualIpAddressService(sess). Id(vipID).StopSsl() if err != nil { - return fmt.Errorf("Error stopping ssl acceleration for load balancer : %s", err) + return fmt.Errorf("[ERROR] Error stopping ssl acceleration for load balancer : %s", err) } } @@ -301,7 +302,7 @@ func resourceIBMLbUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipID, _ := strconv.Atoi(d.Id()) vip, err := services.GetNetworkApplicationDeliveryControllerLoadBalancerVirtualIpAddressService(sess). @@ -310,7 +311,7 @@ func resourceIBMLbRead(d *schema.ResourceData, meta interface{}) error { GetObject() if err != nil { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } d.Set("connections", getConnectionLimit(*vip.ConnectionLimit)) @@ -328,7 +329,7 @@ func resourceIBMLbRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipService := services.GetNetworkApplicationDeliveryControllerLoadBalancerVirtualIpAddressService(sess) vipID, _ := strconv.Atoi(d.Id()) @@ -337,7 +338,7 @@ func resourceIBMLbDelete(d *schema.ResourceData, meta interface{}) error { if certID > 0 { err := setLocalLBSecurityCert(sess, vipID, 0) if err != nil { - return fmt.Errorf("Remove certificate before deleting load balancer failed: %s", err) + return fmt.Errorf("[ERROR] Remove certificate before deleting load balancer failed: %s", err) } } @@ -357,11 +358,11 @@ func resourceIBMLbDelete(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("Error while looking up billing item associated with the load balancer: %s", err) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the load balancer: %s", err) } if billingItem.Id == nil { - return fmt.Errorf("Error while looking up billing item associated with the load balancer: No billing item for ID:%d", vipID) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the load balancer: No billing item for ID:%d", vipID) } success, err := services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() if err != nil { @@ -376,7 +377,7 @@ func resourceIBMLbDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipID, _ := strconv.Atoi(d.Id()) @@ -391,7 +392,7 @@ func resourceIBMLbExists(d *schema.ResourceData, meta interface{}) (bool, error) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting Network Application Delivery Controller LoadBalancer Virtual IpAddress Service: %s", err) } return true, nil } @@ -435,7 +436,7 @@ func findLoadBalancerByOrderId(sess *session.Session, orderId int, dedicated boo } else if len(lbs) == 0 { return datatypes.Network_Application_Delivery_Controller_LoadBalancer_VirtualIpAddress{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one load balancer: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one load balancer: %s", err) } }, Timeout: d.Timeout(schema.TimeoutCreate), @@ -457,7 +458,7 @@ func findLoadBalancerByOrderId(sess *session.Session, orderId int, dedicated boo } return datatypes.Network_Application_Delivery_Controller_LoadBalancer_VirtualIpAddress{}, - fmt.Errorf("Cannot find Application Delivery Controller Load Balancer with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find Application Delivery Controller Load Balancer with order id '%d'", orderId) } func setLocalLBSecurityCert(sess *session.Session, vipID int, certID int) error { @@ -483,7 +484,7 @@ func setLocalLBSecurityCert(sess *session.Session, vipID int, certID int) error ) if !success && err == nil { - return fmt.Errorf("Unable to remove ssl security certificate from load balancer") + return fmt.Errorf("[ERROR] Unable to remove ssl security certificate from load balancer") } return err diff --git a/ibm/resource_ibm_lb_service.go b/ibm/service/classicinfrastructure/resource_ibm_lb_service.go similarity index 91% rename from ibm/resource_ibm_lb_service.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_service.go index d8462ddbe..c60763436 100644 --- a/ibm/resource_ibm_lb_service.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_service.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -11,6 +11,7 @@ import ( "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -20,7 +21,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMLbService() *schema.Resource { +func ResourceIBMLbService() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbServiceCreate, Read: resourceIBMLbServiceRead, @@ -74,7 +75,7 @@ func resourceIBMLbService() *schema.Resource { } func resourceIBMLbServiceCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // SoftLayer Local LBs consist of a multi-level hierarchy of types. // (virtualIpAddress -> []virtualServer -> []serviceGroup -> []service) @@ -88,7 +89,7 @@ func resourceIBMLbServiceCreate(d *schema.ResourceData, meta interface{}) error GetObject() if err != nil { - return fmt.Errorf("Error retrieving load balancer service group from SoftLayer, %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer service group from SoftLayer, %s", err) } // Store the IDs for later use @@ -138,7 +139,7 @@ func resourceIBMLbServiceCreate(d *schema.ResourceData, meta interface{}) error err = updateLoadBalancerService(sess.SetRetries(0), vipID, &vip) if err != nil { - return fmt.Errorf("Error creating load balancer service: %s", err) + return fmt.Errorf("[ERROR] Error creating load balancer service: %s", err) } // Retrieve the newly created object, to obtain its ID @@ -151,7 +152,7 @@ func resourceIBMLbServiceCreate(d *schema.ResourceData, meta interface{}) error GetServices() if err != nil || len(svcs) == 0 { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } d.SetId(strconv.Itoa(*svcs[0].Id)) @@ -162,7 +163,7 @@ func resourceIBMLbServiceCreate(d *schema.ResourceData, meta interface{}) error } func resourceIBMLbServiceUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Using the ID stored in the config, find the IDs of the respective // serviceGroup, virtualServer and virtualIpAddress @@ -173,7 +174,7 @@ func resourceIBMLbServiceUpdate(d *schema.ResourceData, meta interface{}) error GetObject() if err != nil { - return fmt.Errorf("Error retrieving load balancer service group from SoftLayer, %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer service group from SoftLayer, %s", err) } // Store the IDs for later use @@ -225,14 +226,14 @@ func resourceIBMLbServiceUpdate(d *schema.ResourceData, meta interface{}) error err = updateLoadBalancerService(sess.SetRetries(0), vipID, &vip) if err != nil { - return fmt.Errorf("Error updating load balancer service: %s", err) + return fmt.Errorf("[ERROR] Error updating load balancer service: %s", err) } return resourceIBMLbServiceRead(d, meta) } func resourceIBMLbServiceRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() svcID, _ := strconv.Atoi(d.Id()) @@ -242,7 +243,7 @@ func resourceIBMLbServiceRead(d *schema.ResourceData, meta interface{}) error { GetObject() if err != nil { - return fmt.Errorf("Error retrieving service: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service: %s", err) } d.Set("ip_address_id", svc.IpAddressId) @@ -256,7 +257,7 @@ func resourceIBMLbServiceRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbServiceDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() svcID, _ := strconv.Atoi(d.Id()) @@ -295,14 +296,14 @@ func resourceIBMLbServiceDelete(d *schema.ResourceData, meta interface{}) error _, err := stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error deleting service: %s", err) + return fmt.Errorf("[ERROR] Error deleting service: %s", err) } return nil } func resourceIBMLbServiceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() svcID, _ := strconv.Atoi(d.Id()) @@ -317,7 +318,7 @@ func resourceIBMLbServiceExists(d *schema.ResourceData, meta interface{}) (bool, return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting lb service: %s", err) } return true, nil } @@ -335,7 +336,7 @@ func getHealthCheckTypeId(sess *session.Session, healthCheckTypeName string) (in } if len(healthCheckTypes) < 1 { - return -1, fmt.Errorf("Invalid health check type: %s", healthCheckTypeName) + return -1, fmt.Errorf("[ERROR] Invalid health check type: %s", healthCheckTypeName) } return *healthCheckTypes[0].Id, nil diff --git a/ibm/resource_ibm_lb_service_group.go b/ibm/service/classicinfrastructure/resource_ibm_lb_service_group.go similarity index 88% rename from ibm/resource_ibm_lb_service_group.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_service_group.go index d72934c1e..4f17df51e 100644 --- a/ibm/resource_ibm_lb_service_group.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_service_group.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -12,6 +12,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -21,7 +23,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMLbServiceGroup() *schema.Resource { +func ResourceIBMLbServiceGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbServiceGroupCreate, Read: resourceIBMLbServiceGroupRead, @@ -70,7 +72,7 @@ func resourceIBMLbServiceGroup() *schema.Resource { "timeout": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validateLBTimeout, + ValidateFunc: validate.ValidateLBTimeout, Description: "Timeout value", }, "tags": { @@ -85,7 +87,7 @@ func resourceIBMLbServiceGroup() *schema.Resource { } func resourceIBMLbServiceGroupCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipID := d.Get("load_balancer_id").(int) @@ -122,7 +124,7 @@ func resourceIBMLbServiceGroupCreate(d *schema.ResourceData, meta interface{}) e err = updateLoadBalancerService(sess.SetRetries(0), vipID, &vip) if err != nil { - return fmt.Errorf("Error creating load balancer service group: %s", err) + return fmt.Errorf("[ERROR] Error creating load balancer service group: %s", err) } // Retrieve the newly created object, to obtain its ID @@ -133,7 +135,7 @@ func resourceIBMLbServiceGroupCreate(d *schema.ResourceData, meta interface{}) e GetVirtualServers() if err != nil { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } d.SetId(strconv.Itoa(*vs[0].Id)) @@ -144,7 +146,7 @@ func resourceIBMLbServiceGroupCreate(d *schema.ResourceData, meta interface{}) e return resourceIBMLbServiceGroupRead(d, meta) } func resourceIBMLbServiceGroupUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipID := d.Get("load_balancer_id").(int) vsID, _ := strconv.Atoi(d.Id()) @@ -188,14 +190,14 @@ func resourceIBMLbServiceGroupUpdate(d *schema.ResourceData, meta interface{}) e err = updateLoadBalancerService(sess.SetRetries(0), vipID, &vip) if err != nil { - return fmt.Errorf("Error creating load balancer service group: %s", err) + return fmt.Errorf("[ERROR] Error creating load balancer service group: %s", err) } return resourceIBMLbServiceGroupRead(d, meta) } func resourceIBMLbServiceGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vsID, _ := strconv.Atoi(d.Id()) @@ -205,7 +207,7 @@ func resourceIBMLbServiceGroupRead(d *schema.ResourceData, meta interface{}) err GetObject() if err != nil { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } d.Set("allocation", vs.Allocation) @@ -220,7 +222,7 @@ func resourceIBMLbServiceGroupRead(d *schema.ResourceData, meta interface{}) err } func resourceIBMLbServiceGroupDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vsID, _ := strconv.Atoi(d.Id()) @@ -260,14 +262,14 @@ func resourceIBMLbServiceGroupDelete(d *schema.ResourceData, meta interface{}) e _, err := stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error deleting service: %s", err) + return fmt.Errorf("[ERROR] Error deleting service: %s", err) } return nil } func resourceIBMLbServiceGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vsID, _ := strconv.Atoi(d.Id()) @@ -282,7 +284,7 @@ func resourceIBMLbServiceGroupExists(d *schema.ResourceData, meta interface{}) ( return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting lb service group: %s", err) } return true, nil @@ -301,7 +303,7 @@ func getRoutingTypeId(sess *session.Session, routingTypeName string) (int, error } if len(routingTypes) < 1 { - return -1, fmt.Errorf("Invalid routing type: %s", routingTypeName) + return -1, fmt.Errorf("[ERROR] Invalid routing type: %s", routingTypeName) } return *routingTypes[0].Id, nil @@ -320,7 +322,7 @@ func getRoutingMethodId(sess *session.Session, routingMethodName string) (int, e } if len(routingMethods) < 1 { - return -1, fmt.Errorf("Invalid routing method: %s", routingMethodName) + return -1, fmt.Errorf("[ERROR] Invalid routing method: %s", routingMethodName) } return *routingMethods[0].Id, nil diff --git a/ibm/resource_ibm_lb_service_group_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_service_group_test.go similarity index 95% rename from ibm/resource_ibm_lb_service_group_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_service_group_test.go index 1256976b6..b4315ab85 100644 --- a/ibm/resource_ibm_lb_service_group_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_service_group_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMLbServiceGroup_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbServiceGroupConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -39,7 +41,7 @@ func TestAccIBMLbServiceGroup_Basic(t *testing.T) { "ibm_lb_service_group.test_service_group2", "load_balancer_id"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMLbServiceGroupConfig_WithUpdate, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -65,7 +67,7 @@ func TestAccIBMLbServiceGroup_Basic(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_lb_service_group.test_service_group1", ImportState: true, ImportStateVerify: true, @@ -79,10 +81,10 @@ func TestAccIBMLbServiceGroup_Basic(t *testing.T) { func TestAccIBMLbServiceGroupWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbServiceGroupWithTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_lb_service_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_service_test.go similarity index 95% rename from ibm/resource_ibm_lb_service_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_service_test.go index 1b4a3dd9d..a67e6f3ba 100644 --- a/ibm/resource_ibm_lb_service_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_service_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ import ( func TestAccBluemixIBMLbService_Basic(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckBluemixIBMLbServiceConfig_basic(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -32,7 +34,7 @@ func TestAccBluemixIBMLbService_Basic(t *testing.T) { "ibm_lb_service.test_service", "service_group_id"), ), }, - resource.TestStep{ + { ResourceName: "ibm_lb_service.test_service", ImportState: true, ImportStateVerify: true, @@ -44,10 +46,10 @@ func TestAccBluemixIBMLbService_Basic(t *testing.T) { func TestAccBluemixIBMLbServiceWithTag(t *testing.T) { hostname := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckBluemixIBMLbServiceWithTag(hostname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_lb_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_test.go similarity index 95% rename from ibm/resource_ibm_lb_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_test.go index 991594c9f..72882adfc 100644 --- a/ibm/resource_ibm_lb_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMLbShared_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbSharedConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -29,7 +31,7 @@ func TestAccIBMLbShared_Basic(t *testing.T) { "ibm_lb.testacc_foobar_lb", "ssl_enabled", "false"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMLbSharedConfig_UpgradeConnectionLimit, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -51,10 +53,10 @@ func TestAccIBMLbShared_Basic(t *testing.T) { func TestAccIBMLbDedicated_Basic(t *testing.T) { t.SkipNow() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbDedicatedConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -75,10 +77,10 @@ func TestAccIBMLbDedicated_Basic(t *testing.T) { func TestAccIBMLbSharedWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbSharedConfigWithTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -119,10 +121,10 @@ func TestAccIBMLbSharedWithTag(t *testing.T) { func TestAccIBMLbSSL_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbSSLConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -139,7 +141,7 @@ func TestAccIBMLbSSL_Basic(t *testing.T) { "ibm_lb.testacc_foobar_lb", "ssl_offload", "false"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMLbSSLConfig_update, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_lb_vpx.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx.go similarity index 85% rename from ibm/resource_ibm_lb_vpx.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx.go index 264604eff..fc21160e2 100644 --- a/ibm/resource_ibm_lb_vpx.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -28,7 +29,7 @@ const ( DELIMITER = "_" ) -func resourceIBMLbVpx() *schema.Resource { +func ResourceIBMLbVpx() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbVpxCreate, Read: resourceIBMLbVpxRead, @@ -142,12 +143,11 @@ func resourceIBMLbVpx() *schema.Resource { } func getSubnetId(subnet string, meta interface{}) (int, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) subnetInfo := strings.Split(subnet, "/") if len(subnetInfo) != 2 { - return 0, fmt.Errorf( - "Unable to parse the provided subnet: %s", subnet) + return 0, fmt.Errorf("[ERROR] Unable to parse the provided subnet: %s", subnet) } networkIdentifier := subnetInfo[0] @@ -164,7 +164,7 @@ func getSubnetId(subnet string, meta interface{}) (int, error) { GetSubnets() if err != nil { - return 0, fmt.Errorf("Error looking up Subnet: %s", err) + return 0, fmt.Errorf("[ERROR] Error looking up Subnet: %s", err) } if len(subnets) < 1 { @@ -180,7 +180,7 @@ func getVPXVersion(id int, sess *session.Session) (string, error) { getObjectResult, err := service.Id(id).Mask("description").GetObject() if err != nil { - return "", fmt.Errorf("Error retrieving VPX version: %s", err) + return "", fmt.Errorf("[ERROR] Error retrieving VPX version: %s", err) } return strings.Split(*getObjectResult.Description, " ")[3], nil @@ -219,7 +219,7 @@ func getPublicIpItemKeyName(ipCount int) string { } func findVPXPriceItems(version string, speed int, plan string, ipCount int, meta interface{}) ([]datatypes.Product_Item_Price, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Get VPX package type. productPackage, err := product.GetPackageByType(sess, "ADDITIONAL_SERVICES_APPLICATION_DELIVERY_APPLIANCE") @@ -275,7 +275,7 @@ func findVPXPriceItems(version string, speed int, plan string, ipCount int, meta } func findVPXByOrderId(orderId int, meta interface{}) (datatypes.Network_Application_Delivery_Controller, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, @@ -296,7 +296,7 @@ func findVPXByOrderId(orderId int, meta interface{}) (datatypes.Network_Applicat } else if len(vpxs) == 0 { return datatypes.Network_Application_Delivery_Controller{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one VPX: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one VPX: %s", err) } }, Timeout: 45 * time.Minute, @@ -317,7 +317,7 @@ func findVPXByOrderId(orderId int, meta interface{}) (datatypes.Network_Applicat } return datatypes.Network_Application_Delivery_Controller{}, - fmt.Errorf("Cannot find Application Delivery Controller with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find Application Delivery Controller with order id '%d'", orderId) } func prepareHardwareOptions(d *schema.ResourceData, meta interface{}) ([]datatypes.Hardware, error) { @@ -336,7 +336,7 @@ func prepareHardwareOptions(d *schema.ResourceData, meta interface{}) ([]datatyp if len(publicSubnet) > 0 { primarySubnetId, err := getSubnetId(publicSubnet, meta) if err != nil { - return nil, fmt.Errorf("Error creating network application delivery controller: %s", err) + return nil, fmt.Errorf("[ERROR] Error creating network application delivery controller: %s", err) } hardwareOpts[0].PrimaryNetworkComponent.NetworkVlan = &datatypes.Network_Vlan{ PrimarySubnetId: &primarySubnetId, @@ -356,7 +356,7 @@ func prepareHardwareOptions(d *schema.ResourceData, meta interface{}) ([]datatyp if len(privateSubnet) > 0 { primarySubnetId, err := getSubnetId(privateSubnet, meta) if err != nil { - return nil, fmt.Errorf("Error creating network application delivery controller: %s", err) + return nil, fmt.Errorf("[ERROR] Error creating network application delivery controller: %s", err) } hardwareOpts[0].PrimaryBackendNetworkComponent.NetworkVlan = &datatypes.Network_Vlan{ PrimarySubnetId: &primarySubnetId, @@ -366,7 +366,7 @@ func prepareHardwareOptions(d *schema.ResourceData, meta interface{}) ([]datatyp } func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() NADCService := services.GetNetworkApplicationDeliveryControllerService(sess) productOrderService := services.GetProductOrderService(sess.SetRetries(0)) var err error @@ -384,7 +384,7 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { meta) if err != nil { - return fmt.Errorf("Error Cannot find Application Delivery Controller prices '%s'.", err) + return fmt.Errorf("[ERROR] Error Cannot find Application Delivery Controller prices '%s'", err) } datacenter := d.Get("datacenter").(string) @@ -392,14 +392,14 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { if len(datacenter) > 0 { datacenter, err := location.GetDatacenterByName(sess, datacenter, "id") if err != nil { - return fmt.Errorf("Error creating network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error creating network application delivery controller: %s", err) } opts.Location = sl.String(strconv.Itoa(*datacenter.Id)) } opts.Hardware, err = prepareHardwareOptions(d, meta) if err != nil { - return fmt.Errorf("Error Cannot get hardware options '%s'.", err) + return fmt.Errorf("[ERROR] Error Cannot get hardware options '%s'", err) } log.Println("[INFO] Creating network application delivery controller") @@ -407,14 +407,14 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { receipt, err := productOrderService.PlaceOrder(&opts, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error creating network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error creating network application delivery controller: %s", err) } // Wait VPX provisioning VPX, err := findVPXByOrderId(*receipt.OrderId, meta) if err != nil { - return fmt.Errorf("Error creating network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error creating network application delivery controller: %s", err) } d.SetId(fmt.Sprintf("%d", *VPX.Id)) @@ -423,7 +423,7 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } // Wait Virtual IP provisioning @@ -432,7 +432,7 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { for vipWaitCount := 0; vipWaitCount < 270; vipWaitCount++ { getObjectResult, err := NADCService.Id(id).Mask("subnets[ipAddresses],password[password]").GetObject() if err != nil { - return fmt.Errorf("Error retrieving network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error retrieving network application delivery controller: %s", err) } ipCount := 0 @@ -449,7 +449,7 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { } if !IsVipReady { - return fmt.Errorf("Failed to create VIPs for Netscaler VPX ID: %d", id) + return fmt.Errorf("[ERROR] Failed to create VIPs for Netscaler VPX ID: %d", id) } // Wait while VPX service is initializing. GetLoadBalancers() internally calls REST API of VPX and returns @@ -469,7 +469,7 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { } if !IsRESTReady { - return fmt.Errorf("Failed to intialize VPX REST Service for Netscaler VPX ID: %d", id) + return fmt.Errorf("[ERROR] Failed to intialize VPX REST Service for Netscaler VPX ID: %d", id) } // Wait additional buffer time for VPX service. @@ -479,12 +479,12 @@ func resourceIBMLbVpxCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbVpxRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } getObjectResult, err := service. @@ -493,7 +493,7 @@ func resourceIBMLbVpxRead(d *schema.ResourceData, meta interface{}) error { GetObject() if err != nil { - return fmt.Errorf("Error retrieving network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error retrieving network application delivery controller: %s", err) } d.Set("name", *getObjectResult.Name) @@ -579,24 +579,24 @@ func resourceIBMLbVpxUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbVpxDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } billingItem, err := service.Id(id).GetBillingItem() if err != nil { - return fmt.Errorf("Error deleting network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error deleting network application delivery controller: %s", err) } if *billingItem.Id > 0 { billingItemService := services.GetBillingItemService(sess) deleted, err := billingItemService.Id(*billingItem.Id).CancelService() if err != nil { - return fmt.Errorf("Error deleting network application delivery controller: %s", err) + return fmt.Errorf("[ERROR] Error deleting network application delivery controller: %s", err) } if deleted { @@ -608,11 +608,11 @@ func resourceIBMLbVpxDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbVpxExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetNetworkApplicationDeliveryControllerService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkApplicationDeliveryControllerService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } nadc, err := service.Mask("id").Id(id).GetObject() if err != nil { @@ -621,7 +621,7 @@ func resourceIBMLbVpxExists(d *schema.ResourceData, meta interface{}) (bool, err return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting lb vpx: %s", err) } return nadc.Id != nil && *nadc.Id == id, nil } diff --git a/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha.go new file mode 100644 index 000000000..671c4f520 --- /dev/null +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha.go @@ -0,0 +1,356 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package classicinfrastructure + +import ( + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/minsikl/netscaler-nitro-go/client" + dt "github.com/minsikl/netscaler-nitro-go/datatypes" + "github.com/minsikl/netscaler-nitro-go/op" +) + +func ResourceIBMLbVpxHa() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMLbVpxHaCreate, + Read: resourceIBMLbVpxHaRead, + Update: resourceIBMLbVpxHaUpdate, + Delete: resourceIBMLbVpxHaDelete, + Exists: resourceIBMLbVpxHaExists, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + + "primary_id": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: "primary ID", + }, + "secondary_id": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: "Secondary ID", + }, + "stay_secondary": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Boolean value for stay secondary", + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Tags set for the resource", + }, + }, + } +} + +func configureHA(nClient1 *client.NitroClient, nClient2 *client.NitroClient, staySecondary bool) error { + // 1. VPX2 : Sync password + systemuserReq2 := dt.SystemuserReq{ + Systemuser: &dt.Systemuser{ + Username: op.String("root"), + Password: op.String(nClient1.Password), + }, + } + err := nClient2.Update(&systemuserReq2) + if err != nil { + return err + } + nClient2.Password = nClient1.Password + + // 2. VPX1 : Register hanode + hanodeReq1 := dt.HanodeReq{ + Hanode: &dt.Hanode{ + Id: op.String("2"), + Ipaddress: op.String(nClient2.IpAddress), + }, + } + + err = nClient1.Add(&hanodeReq1) + if err != nil { + return err + } + + // Wait 5 secs to make VPX1 a primary node. + time.Sleep(time.Second * 5) + + // 3. VPX2 : Register hanode + hanodeReq2 := dt.HanodeReq{ + Hanode: &dt.Hanode{ + Id: op.String("2"), + Ipaddress: op.String(nClient1.IpAddress), + }, + } + err = nClient2.Add(&hanodeReq2) + if err != nil { + return err + } + + // 4. VPX2 : Update STAYSECONDARY + stay := dt.HanodeReq{Hanode: &dt.Hanode{}} + if staySecondary { + stay.Hanode.Hastatus = op.String("STAYSECONDARY") + } else { + stay.Hanode.Hastatus = op.String("ENABLE") + } + err = nClient2.Update(&stay) + if err != nil { + return err + } + + // 5. VPX1 : Register rpcnode + nsrpcnode1 := dt.NsrpcnodeReq{ + Nsrpcnode: &dt.Nsrpcnode{ + Ipaddress: op.String(nClient1.IpAddress), + Password: op.String(nClient1.Password), + }, + } + err = nClient1.Update(&nsrpcnode1) + if err != nil { + return err + } + nsrpcnode1.Nsrpcnode.Ipaddress = op.String(nClient2.IpAddress) + err = nClient1.Update(&nsrpcnode1) + if err != nil { + return err + } + + // 6. VPX2 : Register rpcnode + nsrpcnode2 := dt.NsrpcnodeReq{ + Nsrpcnode: &dt.Nsrpcnode{ + Ipaddress: op.String(nClient1.IpAddress), + Password: op.String(nClient1.Password), + }, + } + err = nClient2.Update(&nsrpcnode2) + if err != nil { + return err + } + nsrpcnode2.Nsrpcnode.Ipaddress = op.String(nClient2.IpAddress) + err = nClient2.Update(&nsrpcnode2) + if err != nil { + return err + } + + // 7. VPX1 : Sync files + hafiles := dt.HafilesReq{ + Hafiles: &dt.Hafiles{ + Mode: []string{"all"}, + }, + } + err = nClient1.Add(&hafiles, "action=sync") + if err != nil { + return err + } + + return nil +} + +func deleteHA(nClient1 *client.NitroClient, nClient2 *client.NitroClient) error { + // 1. VPX2 : Delete hanode + err := nClient2.Delete(&dt.HanodeReq{}, "2") + if err != nil { + return err + } + + // 2. VPX1 : Delete hanode + err = nClient1.Delete(&dt.HanodeReq{}, "2") + if err != nil { + return err + } + return nil +} + +func parseHAId(id string) (int, int, error) { + if len(id) < 1 { + return 0, 0, fmt.Errorf("[ERROR] Failed to parse id : Unable to get netscaler Ids") + } + idList := strings.Split(id, ":") + if len(idList) != 2 || len(idList[0]) < 1 || len(idList[1]) < 1 { + return 0, 0, fmt.Errorf("[ERROR] Failed to parse id : Invalid HA ID") + } + primaryId, err := strconv.Atoi(idList[0]) + if err != nil { + return 0, 0, fmt.Errorf("[ERROR] Failed to parse id : Unable to get a primaryId %s", err) + } + secondaryId, err := strconv.Atoi(idList[1]) + if err != nil { + return 0, 0, fmt.Errorf("[ERROR] Failed to parse id : Unable to get a secondaryId %s", err) + } + return primaryId, secondaryId, nil +} + +func resourceIBMLbVpxHaCreate(d *schema.ResourceData, meta interface{}) error { + primaryId := d.Get("primary_id").(int) + secondaryId := d.Get("secondary_id").(int) + staySecondary := false + if stay, ok := d.GetOk("stay_secondary"); ok { + staySecondary = stay.(bool) + } + + nClientPrimary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), primaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary netscaler information ID: %d", primaryId) + } + + nClientSecondary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), secondaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting secondary netscaler information ID: %d", secondaryId) + } + + err = configureHA(nClientPrimary, nClientSecondary, staySecondary) + if err != nil { + return fmt.Errorf("[ERROR] Error configuration HA %s", err.Error()) + } + + d.SetId(fmt.Sprintf("%d:%d", primaryId, secondaryId)) + + log.Printf("[INFO] Netscaler HA ID: %s", d.Id()) + + return resourceIBMLbVpxHaRead(d, meta) +} + +func resourceIBMLbVpxHaRead(d *schema.ResourceData, meta interface{}) error { + primaryId, secondaryId, err := parseHAId(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Error reading HA %s", err.Error()) + } + + nClientPrimary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), primaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary netscaler information ID: %d", primaryId) + } + + nClientSecondary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), secondaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary netscaler information ID: %d", primaryId) + } + + nClientSecondary.Password = nClientPrimary.Password + + res := dt.HanodeRes{} + err = nClientSecondary.Get(&res, "") + if err != nil { + fmt.Printf("Error getting hnode information : %s", err.Error()) + } + staySecondary := false + if *res.Hanode[0].Hastatus == "STAYSECONDARY" { + staySecondary = true + } + + d.Set("primary_id", primaryId) + d.Set("secondary_id", secondaryId) + d.Set("stay_secondary", staySecondary) + + return nil +} + +func resourceIBMLbVpxHaUpdate(d *schema.ResourceData, meta interface{}) error { + primaryId, secondaryId, err := parseHAId(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting HA %s", err.Error()) + } + + nClientPrimary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), primaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary netscaler information ID: %d", primaryId) + } + + nClientSecondary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), secondaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting secondary netscaler information ID: %d", secondaryId) + } + + nClientSecondary.Password = nClientPrimary.Password + + staySecondary := false + if stay, ok := d.GetOk("stay_secondary"); ok { + staySecondary = stay.(bool) + } + + stay := dt.HanodeReq{Hanode: &dt.Hanode{}} + if staySecondary { + stay.Hanode.Hastatus = op.String("STAYSECONDARY") + } else { + stay.Hanode.Hastatus = op.String("ENABLE") + } + + err = nClientSecondary.Update(&stay) + if err != nil { + return err + } + + return nil +} + +func resourceIBMLbVpxHaDelete(d *schema.ResourceData, meta interface{}) error { + primaryId, secondaryId, err := parseHAId(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting HA %s", err.Error()) + } + nClientPrimary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), primaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary netscaler information ID: %d", primaryId) + } + nClientSecondary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), secondaryId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting secondary netscaler information ID: %d", secondaryId) + } + + secondaryPassword := nClientSecondary.Password + nClientSecondary.Password = nClientPrimary.Password + err = deleteHA(nClientPrimary, nClientSecondary) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting HA %s", err.Error()) + } + + // Restore password of the secondary VPX + systemuserReq := dt.SystemuserReq{ + Systemuser: &dt.Systemuser{ + Username: op.String("root"), + Password: op.String(secondaryPassword), + }, + } + err = nClientSecondary.Update(&systemuserReq) + if err != nil { + return err + } + + return nil +} + +func resourceIBMLbVpxHaExists(d *schema.ResourceData, meta interface{}) (bool, error) { + primaryId, _, err := parseHAId(d.Id()) + if err != nil { + return false, fmt.Errorf("[ERROR] Error reading HA %s", err.Error()) + } + + nClientPrimary, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), primaryId) + if err != nil { + return false, fmt.Errorf("[ERROR] Error getting primary netscaler information ID in Exist: %d", primaryId) + } + + res := dt.HanodeRes{} + err = nClientPrimary.Get(&res, "") + if err != nil { + return false, fmt.Errorf("[ERROR] Error getting hnode information in Exist: %s", err.Error()) + } + + if len(res.Hanode) < 2 { + return false, nil + } + + return true, nil +} diff --git a/ibm/resource_ibm_lb_vpx_ha_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha_test.go similarity index 95% rename from ibm/resource_ibm_lb_vpx_ha_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha_test.go index 175f82e3b..dd08e6111 100644 --- a/ibm/resource_ibm_lb_vpx_ha_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_ha_test.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMLbVpxHa_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMLbVpxHaConfig_basic, @@ -31,8 +33,8 @@ func TestAccIBMLbVpxHa_Basic(t *testing.T) { func TestAccIBMLbVpxHaWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMLbVpxHaWithTag, diff --git a/ibm/resource_ibm_lb_vpx_service.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service.go similarity index 77% rename from ibm/resource_ibm_lb_vpx_service.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service.go index bf6cdcdc4..1b309b9ec 100644 --- a/ibm/resource_ibm_lb_vpx_service.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" dt "github.com/minsikl/netscaler-nitro-go/datatypes" "github.com/minsikl/netscaler-nitro-go/op" @@ -39,7 +40,7 @@ var ( } ) -func resourceIBMLbVpxService() *schema.Resource { +func ResourceIBMLbVpxService() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbVpxServiceCreate, Read: resourceIBMLbVpxServiceRead, @@ -125,7 +126,7 @@ func parseServiceId(id string) (string, int, string, error) { vipId := parts[1] nacdId, err := strconv.Atoi(parts[0]) if err != nil { - return "", -1, "", fmt.Errorf("Error parsing vip id: %s", err) + return "", -1, "", fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } serviceName := "" @@ -161,12 +162,12 @@ func resourceIBMLbVpxServiceCreate(d *schema.ResourceData, meta interface{}) err _, nadcId, _, err := parseServiceId(vipId) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error creating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error creating Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -179,12 +180,12 @@ func resourceIBMLbVpxServiceCreate(d *schema.ResourceData, meta interface{}) err func resourceIBMLbVpxServiceRead(d *schema.ResourceData, meta interface{}) error { _, nadcId, _, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error Reading Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error Reading Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -197,12 +198,12 @@ func resourceIBMLbVpxServiceRead(d *schema.ResourceData, meta interface{}) error func resourceIBMLbVpxServiceUpdate(d *schema.ResourceData, meta interface{}) error { _, nadcId, _, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error updating Virtual IP Address: %s", err) + return fmt.Errorf("[ERROR] Error updating Virtual IP Address: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error updating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error updating Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -215,12 +216,12 @@ func resourceIBMLbVpxServiceUpdate(d *schema.ResourceData, meta interface{}) err func resourceIBMLbVpxServiceDelete(d *schema.ResourceData, meta interface{}) error { _, nadcId, _, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -233,12 +234,12 @@ func resourceIBMLbVpxServiceDelete(d *schema.ResourceData, meta interface{}) err func resourceIBMLbVpxServiceExists(d *schema.ResourceData, meta interface{}) (bool, error) { _, nadcId, _, err := parseServiceId(d.Id()) if err != nil { - return false, fmt.Errorf("Error in exists: %s", err) + return false, fmt.Errorf("[ERROR] Error in exists: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return false, fmt.Errorf("Error in exists: %s", err) + return false, fmt.Errorf("[ERROR] Error in exists: %s", err) } if version == VPX_VERSION_10_1 { @@ -250,14 +251,14 @@ func resourceIBMLbVpxServiceExists(d *schema.ResourceData, meta interface{}) (bo func resourceIBMLbVpxServiceCreate101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipId := d.Get("vip_id").(string) vipName, nadcId, _, err := parseServiceId(vipId) serviceName := d.Get("name").(string) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } lb_services := []datatypes.Network_LoadBalancer_Service{ @@ -281,7 +282,7 @@ func resourceIBMLbVpxServiceCreate101(d *schema.ResourceData, meta interface{}) _, err = network.GetNadcLbVipServiceByName(sess, nadcId, vipName, serviceName) if err == nil { - return fmt.Errorf("Error creating LoadBalancer Service: The service name '%s' is already used.", + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service: The service name '%s' is already used.", serviceName) } @@ -290,11 +291,11 @@ func resourceIBMLbVpxServiceCreate101(d *schema.ResourceData, meta interface{}) successFlag, err := updateVpxService(sess.SetRetries(0), nadcId, lbVip) if err != nil { - return fmt.Errorf("Error creating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service: %s", err) } if !successFlag { - return errors.New("Error creating LoadBalancer Service") + return errors.New("[ERROR] Error creating LoadBalancer Service") } d.SetId(fmt.Sprintf("%s:%s", vipId, serviceName)) @@ -304,19 +305,19 @@ func resourceIBMLbVpxServiceCreate101(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipId := d.Get("vip_id").(string) vipName, nadcId, _, err := parseServiceId(vipId) serviceName := d.Get("name").(string) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } nClient, err := getNitroClient(sess, nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } // Create a service @@ -334,13 +335,13 @@ func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) vip := dt.LbvserverRes{} err = nClient.Get(&vip, vipName) if err != nil { - return fmt.Errorf("Error creating LoadBalancer Service : %s", err) + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service : %s", err) } if vip.Lbvserver[0].ServiceType != nil { svcReq.Service.ServiceType = vip.Lbvserver[0].ServiceType } else { - return fmt.Errorf("Error creating LoadBalancer : type of VIP '%s' is null.", vipName) + return fmt.Errorf("[ERROR] Error creating LoadBalancer : type of VIP '%s' is null.", vipName) } // SSL offload @@ -353,7 +354,7 @@ func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) // Add the service err = nClient.Add(&svcReq) if err != nil { - return fmt.Errorf("Error creating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service: %s", err) } // Bind the virtual server and the service @@ -366,7 +367,7 @@ func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) err = nClient.Add(&lbvserverServiceBindingReq) if err != nil { - return fmt.Errorf("Error creating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service: %s", err) } // Bind Health_check monitor @@ -384,7 +385,7 @@ func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) err = nClient.Add(&serviceLbmonitorBindingReq) if err != nil { - return fmt.Errorf("Error creating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error creating LoadBalancer Service: %s", err) } d.SetId(fmt.Sprintf("%s:%s", vipId, serviceName)) @@ -393,16 +394,16 @@ func resourceIBMLbVpxServiceCreate105(d *schema.ResourceData, meta interface{}) } func resourceIBMLbVpxServiceRead101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipName, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } lbService, err := network.GetNadcLbVipServiceByName(sess, nadcId, vipName, serviceName) if err != nil { - return fmt.Errorf("Unable to get load balancer service %s: %s", serviceName, err) + return fmt.Errorf("[ERROR] Unable to get load balancer service %s: %s", serviceName, err) } d.Set("vip_id", strconv.Itoa(nadcId)+":"+vipName) @@ -419,12 +420,12 @@ func resourceIBMLbVpxServiceRead101(d *schema.ResourceData, meta interface{}) er func resourceIBMLbVpxServiceRead105(d *schema.ResourceData, meta interface{}) error { vipName, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } // Read a service @@ -464,16 +465,16 @@ func resourceIBMLbVpxServiceRead105(d *schema.ResourceData, meta interface{}) er func resourceIBMLbVpxServiceUpdate101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() vipName, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } lbService, err := network.GetNadcLbVipServiceByName(sess, nadcId, vipName, serviceName) if err != nil { - return fmt.Errorf("Unable to get load balancer service: %s", err) + return fmt.Errorf("[ERROR] Unable to get load balancer service: %s", err) } // copy current service @@ -507,11 +508,11 @@ func resourceIBMLbVpxServiceUpdate101(d *schema.ResourceData, meta interface{}) successFlag, err := updateVpxService(sess.SetRetries(0), nadcId, lbVip) if err != nil { - return fmt.Errorf("Error updating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error updating LoadBalancer Service: %s", err) } if !successFlag { - return errors.New("Error updating LoadBalancer Service") + return errors.New("[ERROR] Error updating LoadBalancer Service") } return nil @@ -520,12 +521,12 @@ func resourceIBMLbVpxServiceUpdate101(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceUpdate105(d *schema.ResourceData, meta interface{}) error { _, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } // Update a service @@ -548,7 +549,7 @@ func resourceIBMLbVpxServiceUpdate105(d *schema.ResourceData, meta interface{}) // Delete previous health_check err = nClient.Delete(&dt.ServiceLbmonitorBindingReq{}, serviceName, "args=monitor_name:"+*monitorName) if err != nil { - return fmt.Errorf("Error deleting monitor %s: %s", *monitorName, err) + return fmt.Errorf("[ERROR] Error deleting monitor %s: %s", *monitorName, err) } } @@ -567,7 +568,7 @@ func resourceIBMLbVpxServiceUpdate105(d *schema.ResourceData, meta interface{}) err = nClient.Add(&serviceLbmonitorBindingReq) if err != nil { - return fmt.Errorf("Error adding a monitor: %s", err) + return fmt.Errorf("[ERROR] Error adding a monitor: %s", err) } } @@ -588,7 +589,7 @@ func resourceIBMLbVpxServiceUpdate105(d *schema.ResourceData, meta interface{}) } if err != nil { - return fmt.Errorf("Error updating LoadBalancer Service: %s", err) + return fmt.Errorf("[ERROR] Error updating LoadBalancer Service: %s", err) } return nil @@ -597,10 +598,10 @@ func resourceIBMLbVpxServiceUpdate105(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceDelete101(d *schema.ResourceData, meta interface{}) error { vipName, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess) lbSvc := datatypes.Network_LoadBalancer_Service{ @@ -633,7 +634,7 @@ func resourceIBMLbVpxServiceDelete101(d *schema.ResourceData, meta interface{}) } if err != nil { - return fmt.Errorf("Error deleting LoadBalancer Service %s: %s", serviceName, err) + return fmt.Errorf("[ERROR] Error deleting LoadBalancer Service %s: %s", serviceName, err) } return nil @@ -642,18 +643,18 @@ func resourceIBMLbVpxServiceDelete101(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceDelete105(d *schema.ResourceData, meta interface{}) error { _, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return fmt.Errorf("Error parsing vip id: %s", err) + return fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } // Delete a service err = nClient.Delete(&dt.ServiceReq{}, serviceName) if err != nil { - return fmt.Errorf("Error deleting service %s: %s", serviceName, err) + return fmt.Errorf("[ERROR] Error deleting service %s: %s", serviceName, err) } return nil @@ -662,16 +663,16 @@ func resourceIBMLbVpxServiceDelete105(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceExists101(d *schema.ResourceData, meta interface{}) (bool, error) { vipName, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return false, fmt.Errorf("Error parsing vip id: %s", err) + return false, fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - lbService, err := network.GetNadcLbVipServiceByName(meta.(ClientSession).SoftLayerSession(), nadcId, vipName, serviceName) + lbService, err := network.GetNadcLbVipServiceByName(meta.(conns.ClientSession).SoftLayerSession(), nadcId, vipName, serviceName) if err != nil { if apiErr, ok := err.(sl.Error); ok { if apiErr.StatusCode == 404 { return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting lb vpx service: %s", err) } return *lbService.Name == serviceName, nil } @@ -679,12 +680,12 @@ func resourceIBMLbVpxServiceExists101(d *schema.ResourceData, meta interface{}) func resourceIBMLbVpxServiceExists105(d *schema.ResourceData, meta interface{}) (bool, error) { _, nadcId, serviceName, err := parseServiceId(d.Id()) if err != nil { - return false, fmt.Errorf("Error parsing vip id: %s", err) + return false, fmt.Errorf("[ERROR] Error parsing vip id: %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return false, fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return false, fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } svc := dt.ServiceRes{} @@ -692,7 +693,7 @@ func resourceIBMLbVpxServiceExists105(d *schema.ResourceData, meta interface{}) if err != nil && strings.Contains(err.Error(), "No Service") { return false, nil } else if err != nil { - return false, fmt.Errorf("Unable to get load balancer service %s: %s", serviceName, err) + return false, fmt.Errorf("[ERROR] Unable to get load balancer service %s: %s", serviceName, err) } return *svc.Service[0].Name == serviceName, nil diff --git a/ibm/resource_ibm_lb_vpx_service_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service_test.go similarity index 96% rename from ibm/resource_ibm_lb_vpx_service_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service_test.go index 73991747a..0586ec856 100644 --- a/ibm/resource_ibm_lb_vpx_service_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_service_test.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMLbVpxService_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMLbVpxServiceConfig_basic, @@ -37,8 +39,8 @@ func TestAccIBMLbVpxService_Basic(t *testing.T) { func TestAccIBMLbVpxService_Basic105(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMLbVpxServiceConfig_basic105, @@ -59,8 +61,8 @@ func TestAccIBMLbVpxService_Basic105(t *testing.T) { func TestAccIBMLbVpxServiceWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMLbVpxServiceWithTag, diff --git a/ibm/resource_ibm_lb_vpx_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_test.go similarity index 90% rename from ibm/resource_ibm_lb_vpx_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_test.go index b1e0437e5..3cfe2b995 100644 --- a/ibm/resource_ibm_lb_vpx_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" @@ -18,10 +21,10 @@ func TestAccIBMLbVpx_Basic(t *testing.T) { var nadc datatypes.Network_Application_Delivery_Controller resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbVpxConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckIBMLbVpxExists("ibm_lb_vpx.testacc_foobar_vpx", &nadc), @@ -49,10 +52,10 @@ func TestAccIBMLbVpxWithIPCount1(t *testing.T) { var nadc datatypes.Network_Application_Delivery_Controller resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbVpxWithIPCount1, Check: resource.ComposeTestCheckFunc( testAccCheckIBMLbVpxExists("ibm_lb_vpx.testacc_foobar_vpx", &nadc), @@ -80,10 +83,10 @@ func TestAccIBMLbVpxWithTag(t *testing.T) { var nadc datatypes.Network_Application_Delivery_Controller resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbVpxWithTag, Check: resource.ComposeTestCheckFunc( testAccCheckIBMLbVpxExists("ibm_lb_vpx.testacc_foobar_vpx", &nadc), @@ -136,16 +139,16 @@ func testAccCheckIBMLbVpxExists(n string, nadc *datatypes.Network_Application_De rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } nadcId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkApplicationDeliveryControllerService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkApplicationDeliveryControllerService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) found, err := service.Id(nadcId).GetObject() if err != nil { return err diff --git a/ibm/resource_ibm_lb_vpx_vip.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip.go similarity index 84% rename from ibm/resource_ibm_lb_vpx_vip.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip.go index adb6ac1d2..4a5fa41b3 100644 --- a/ibm/resource_ibm_lb_vpx_vip.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "encoding/base64" @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/helpers/network" @@ -56,7 +57,7 @@ var ( } ) -func resourceIBMLbVpxVip() *schema.Resource { +func ResourceIBMLbVpxVip() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbVpxVipCreate, Read: resourceIBMLbVpxVipRead, @@ -135,9 +136,9 @@ func resourceIBMLbVpxVip() *schema.Resource { } func resourceIBMLbVpxVipCreate(d *schema.ResourceData, meta interface{}) error { - version, err := getVPXVersion(d.Get("nad_controller_id").(int), meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(d.Get("nad_controller_id").(int), meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error creating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error creating Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -150,12 +151,12 @@ func resourceIBMLbVpxVipCreate(d *schema.ResourceData, meta interface{}) error { func resourceIBMLbVpxVipRead(d *schema.ResourceData, meta interface{}) error { nadcId, _, err := parseId(d.Id()) if err != nil { - return fmt.Errorf("Error Reading Virtual IP Address: %s", err) + return fmt.Errorf("[ERROR] Error Reading Virtual IP Address: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error Reading Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error Reading Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -168,12 +169,12 @@ func resourceIBMLbVpxVipRead(d *schema.ResourceData, meta interface{}) error { func resourceIBMLbVpxVipUpdate(d *schema.ResourceData, meta interface{}) error { nadcId, _, err := parseId(d.Id()) if err != nil { - return fmt.Errorf("Error updating Virtual IP Address: %s", err) + return fmt.Errorf("[ERROR] Error updating Virtual IP Address: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error updating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error updating Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -186,12 +187,12 @@ func resourceIBMLbVpxVipUpdate(d *schema.ResourceData, meta interface{}) error { func resourceIBMLbVpxVipDelete(d *schema.ResourceData, meta interface{}) error { nadcId, _, err := parseId(d.Id()) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address: %s", err) } if version == VPX_VERSION_10_1 { @@ -204,12 +205,12 @@ func resourceIBMLbVpxVipDelete(d *schema.ResourceData, meta interface{}) error { func resourceIBMLbVpxVipExists(d *schema.ResourceData, meta interface{}) (bool, error) { nadcId, _, err := parseId(d.Id()) if err != nil { - return false, fmt.Errorf("Error in exists: %s", err) + return false, fmt.Errorf("[ERROR] Error in exists: %s", err) } - version, err := getVPXVersion(nadcId, meta.(ClientSession).SoftLayerSession()) + version, err := getVPXVersion(nadcId, meta.(conns.ClientSession).SoftLayerSession()) if err != nil { - return false, fmt.Errorf("Error in exists: %s", err) + return false, fmt.Errorf("[ERROR] Error in exists: %s", err) } if version == VPX_VERSION_10_1 { @@ -221,17 +222,17 @@ func resourceIBMLbVpxVipExists(d *schema.ResourceData, meta interface{}) (bool, func parseId(id string) (int, string, error) { if len(id) < 1 { - return 0, "", fmt.Errorf("Failed to parse id %s: Unable to get a VIP ID", id) + return 0, "", fmt.Errorf("[ERROR] Failed to parse id %s: Unable to get a VIP ID", id) } idList := strings.Split(id, ":") if len(idList) != 2 || len(idList[0]) < 1 || len(idList[1]) < 1 { - return 0, "", fmt.Errorf("Failed to parse id %s: Invalid VIP ID", id) + return 0, "", fmt.Errorf("[ERROR] Failed to parse id %s: Invalid VIP ID", id) } nadcId, err := strconv.Atoi(idList[0]) if err != nil { - return 0, "", fmt.Errorf("Failed to parse id : Unable to get a VIP ID %s", err) + return 0, "", fmt.Errorf("[ERROR] Failed to parse id : Unable to get a VIP ID %s", err) } vipName := idList[1] @@ -240,10 +241,10 @@ func parseId(id string) (int, string, error) { func resourceIBMLbVpxVipCreate101(d *schema.ResourceData, meta interface{}) error { if _, ok := d.GetOk("security_certificate_id"); ok { - return fmt.Errorf("Error creating Virtual Ip Address: security_certificate_id is not supported with VPX 10.1.") + return fmt.Errorf("[ERROR] Error creating Virtual Ip Address: security_certificate_id is not supported with VPX 10.1.") } - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess.SetRetries(0)) nadcId := d.Get("nad_controller_id").(int) @@ -283,11 +284,11 @@ func resourceIBMLbVpxVipCreate101(d *schema.ResourceData, meta interface{}) erro } if err != nil { - return fmt.Errorf("Error creating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error creating Virtual Ip Address: %s", err) } if !successFlag { - return errors.New("Error creating Virtual Ip Address") + return errors.New("[ERROR] Error creating Virtual Ip Address") } d.SetId(fmt.Sprintf("%d:%s", nadcId, vipName)) @@ -299,9 +300,9 @@ func resourceIBMLbVpxVipCreate101(d *schema.ResourceData, meta interface{}) erro func resourceIBMLbVpxVipCreate105(d *schema.ResourceData, meta interface{}) error { nadcId := d.Get("nad_controller_id").(int) - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } vipName := d.Get("name").(string) @@ -334,9 +335,9 @@ func resourceIBMLbVpxVipCreate105(d *schema.ResourceData, meta interface{}) erro // security_certificated_id is only available when type is 'SSL' if securityCertificateId > 0 && vipType != "SSL" { - return fmt.Errorf("Error creating VIP : security_certificated_id is only available when type is 'SSL'") + return fmt.Errorf("[ERROR] Error creating VIP : security_certificated_id is only available when type is 'SSL'") } else if securityCertificateId == 0 && vipType == "SSL" { - return fmt.Errorf("Error creating VIP : 'SSL' type requires security_certificated_id.") + return fmt.Errorf("[ERROR] Error creating VIP : 'SSL' type requires security_certificated_id.") } @@ -351,7 +352,7 @@ func resourceIBMLbVpxVipCreate105(d *schema.ResourceData, meta interface{}) erro // Delete the previous security certificate. deleteSecurityCertificate(nClient, vipName, securityCertificateId) - err = configureSecurityCertificate(nClient, meta.(ClientSession).SoftLayerSession(), vipName, securityCertificateId) + err = configureSecurityCertificate(nClient, meta.(conns.ClientSession).SoftLayerSession(), vipName, securityCertificateId) if err != nil { // Rollback VIP creation and return an error. @@ -368,7 +369,7 @@ func resourceIBMLbVpxVipCreate105(d *schema.ResourceData, meta interface{}) erro } func resourceIBMLbVpxVipRead101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() nadcId, vipName, err := parseId(d.Id()) if err != nil { @@ -410,9 +411,9 @@ func resourceIBMLbVpxVipRead105(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("ibm_lb_vpx : %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } // Read a virtual server @@ -470,7 +471,7 @@ func resourceIBMLbVpxVipRead105(d *schema.ResourceData, meta interface{}) error } func resourceIBMLbVpxVipUpdate101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess.SetRetries(0)) nadcId := d.Get("nad_controller_id").(int) @@ -503,7 +504,7 @@ func resourceIBMLbVpxVipUpdate101(d *schema.ResourceData, meta interface{}) erro } if err != nil { - return fmt.Errorf("Error updating Virtual Ip Address: %s", err) + return fmt.Errorf("[ERROR] Error updating Virtual Ip Address: %s", err) } return resourceIBMLbVpxVipRead(d, meta) @@ -511,9 +512,9 @@ func resourceIBMLbVpxVipUpdate101(d *schema.ResourceData, meta interface{}) erro func resourceIBMLbVpxVipUpdate105(d *schema.ResourceData, meta interface{}) error { nadcId := d.Get("nad_controller_id").(int) - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error getting netscaler information ID: %d", nadcId) + return fmt.Errorf("[ERROR] Error getting netscaler information ID: %d", nadcId) } lbvserverReq := dt.LbvserverReq{ @@ -544,14 +545,14 @@ func resourceIBMLbVpxVipUpdate105(d *schema.ResourceData, meta interface{}) erro // Update the virtual server err = nClient.Update(&lbvserverReq) if err != nil { - return fmt.Errorf("Error updating Virtual Ip Address: " + err.Error()) + return fmt.Errorf("[ERROR] Error updating Virtual Ip Address: " + err.Error()) } return resourceIBMLbVpxVipRead(d, meta) } func resourceIBMLbVpxVipDelete101(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkApplicationDeliveryControllerService(sess) nadcId, vipName, err := parseId(d.Id()) @@ -584,7 +585,7 @@ func resourceIBMLbVpxVipDelete101(d *schema.ResourceData, meta interface{}) erro } if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address %s: %s", vipName, err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address %s: %s", vipName, err) } return nil @@ -596,15 +597,15 @@ func resourceIBMLbVpxVipDelete105(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("ibm_lb_vpx : %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address %s: %s", vipName, err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address %s: %s", vipName, err) } // Delete a virtual server err = nClient.Delete(&dt.LbvserverReq{}, vipName) if err != nil { - return fmt.Errorf("Error deleting Virtual Ip Address %s: %s", vipName, err) + return fmt.Errorf("[ERROR] Error deleting Virtual Ip Address %s: %s", vipName, err) } // Delete a security certificate @@ -617,7 +618,7 @@ func resourceIBMLbVpxVipDelete105(d *schema.ResourceData, meta interface{}) erro } func resourceIBMLbVpxVipExists101(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() nadcId, vipName, err := parseId(d.Id()) if err != nil { @@ -631,7 +632,7 @@ func resourceIBMLbVpxVipExists101(d *schema.ResourceData, meta interface{}) (boo return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting lb vip: %s", err) } return vip != nil && *vip.Name == vipName, nil } @@ -642,7 +643,7 @@ func resourceIBMLbVpxVipExists105(d *schema.ResourceData, meta interface{}) (boo return false, fmt.Errorf("ibm_lb_vpx : %s", err) } - nClient, err := getNitroClient(meta.(ClientSession).SoftLayerSession(), nadcId) + nClient, err := getNitroClient(meta.(conns.ClientSession).SoftLayerSession(), nadcId) if err != nil { return false, err } @@ -664,7 +665,7 @@ func getNitroClient(sess *session.Session, nadcId int) (*client.NitroClient, err service := services.GetNetworkApplicationDeliveryControllerService(sess) nadc, err := service.Id(nadcId).Mask("managementIpAddress,password[password]").GetObject() if err != nil { - return nil, fmt.Errorf("Error retrieving netscaler: %s", err) + return nil, fmt.Errorf("[ERROR] Error retrieving netscaler: %s", err) } return client.NewNitroClient("http", *nadc.ManagementIpAddress, dt.CONFIG, "root", *nadc.Password.Password, true), nil @@ -676,7 +677,7 @@ func configureSecurityCertificate(nClient *client.NitroClient, sess *session.Ses cert, err := service.Id(securityCertificateId).GetObject() if err != nil { - return fmt.Errorf("Unable to get Security Certificate: %s", err) + return fmt.Errorf("[ERROR] Unable to get Security Certificate: %s", err) } certName := vipName + "_" + strconv.Itoa(securityCertificateId) @@ -787,7 +788,7 @@ func getSecurityCertificateId(nClient *client.NitroClient, vipName string) (int, res := dt.SslcertkeyRes{} err := nClient.Get(&res, "") if err != nil { - return 0, fmt.Errorf("Error getting securityCertificateId information : %s", err.Error()) + return 0, fmt.Errorf("[ERROR] Error getting securityCertificateId information : %s", err.Error()) } //CertKey name is consisted of `vipName`_`securityCertificateId`. @@ -804,5 +805,5 @@ func getSecurityCertificateId(nClient *client.NitroClient, vipName string) (int, return securityCertificateId, nil } } - return 0, fmt.Errorf("Error getting securityCertificateId information : No security certificate for %s", vipName) + return 0, fmt.Errorf("[ERROR] Error getting securityCertificateId information : No security certificate for %s", vipName) } diff --git a/ibm/resource_ibm_lb_vpx_vip_test.go b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip_test.go similarity index 92% rename from ibm/resource_ibm_lb_vpx_vip_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip_test.go index 058e350ff..daa98bfe5 100644 --- a/ibm/resource_ibm_lb_vpx_vip_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lb_vpx_vip_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,8 +19,8 @@ import ( func TestAccIBMLbVpxVip_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbVpxVipDestroy, Steps: []resource.TestStep{ { @@ -49,8 +52,8 @@ func TestAccIBMLbVpxVip_Basic(t *testing.T) { func TestAccIBMLbVpxVipWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbVpxVipDestroy, Steps: []resource.TestStep{ { @@ -90,7 +93,7 @@ func TestAccIBMLbVpxVipWithTag(t *testing.T) { } func testAccCheckIBMLbVpxVipDestroy(s *terraform.State) error { - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_lb_vpx_vip" { diff --git a/ibm/resource_ibm_lbaas.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas.go similarity index 82% rename from ibm/resource_ibm_lbaas.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas.go index e61cbce9c..d2ff595b3 100644 --- a/ibm/resource_ibm_lbaas.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "bytes" @@ -10,7 +10,9 @@ import ( "strings" "time" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -50,7 +52,7 @@ func init() { } } -func resourceIBMLbaas() *schema.Resource { +func ResourceIBMLbaas() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbaasCreate, Read: resourceIBMLbaasRead, @@ -77,7 +79,7 @@ func resourceIBMLbaas() *schema.Resource { Default: "PUBLIC", ForceNew: true, Description: "Specifies if a load balancer is public or private", - ValidateFunc: validateAllowedStringValue([]string{"PUBLIC", "PRIVATE"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"PUBLIC", "PRIVATE"}), }, "datacenter": { Type: schema.TypeString, @@ -106,7 +108,7 @@ func resourceIBMLbaas() *schema.Resource { Type: schema.TypeBool, Optional: true, Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: `"in public loadbalancer - Public IP address allocation done by system public IP pool or public subnet."`, }, "protocols": { @@ -119,30 +121,30 @@ func resourceIBMLbaas() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Frontend protocol, one of 'TCP', 'HTTP', 'HTTPS'.", - ValidateFunc: validateAllowedStringValue([]string{"HTTP", "HTTPS", "TCP"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"HTTP", "HTTPS", "TCP"}), }, "frontend_port": { Type: schema.TypeInt, Required: true, Description: "Frontend Protocol port number. Should be in range (1, 65535)", - ValidateFunc: validatePortRange(1, 65535), + ValidateFunc: validate.ValidatePortRange(1, 65535), }, "backend_protocol": { Type: schema.TypeString, Required: true, Description: "Backend protocol, one of 'TCP', 'HTTP', 'HTTPS'.", - ValidateFunc: validateAllowedStringValue([]string{"HTTP", "HTTPS", "TCP"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"HTTP", "HTTPS", "TCP"}), }, "backend_port": { Type: schema.TypeInt, Required: true, Description: "Backend Protocol port number. Should be in range (1, 65535)", - ValidateFunc: validatePortRange(1, 65535), + ValidateFunc: validate.ValidatePortRange(1, 65535), }, "load_balancing_method": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"round_robin", "weighted_round_robin", "least_connection"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"round_robin", "weighted_round_robin", "least_connection"}), Default: "round_robin", Description: "Load balancing algorithm: 'round_robin', 'weighted_round_robin', 'least_connection'", }, @@ -150,13 +152,13 @@ func resourceIBMLbaas() *schema.Resource { Type: schema.TypeString, Optional: true, Description: "Session stickness. Valid values is SOURCE_IP and HTTP_COOKIE", - ValidateFunc: validateAllowedStringValue([]string{"SOURCE_IP", "HTTP_COOKIE"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"SOURCE_IP", "HTTP_COOKIE"}), }, "max_conn": { Type: schema.TypeInt, Optional: true, Description: "No. of connections the listener can accept. Should be between 1-64000", - ValidateFunc: validateMaxConn, + ValidateFunc: validate.ValidateMaxConn, }, "tls_certificate_id": { Type: schema.TypeInt, @@ -178,7 +180,7 @@ func resourceIBMLbaas() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, - //ValidateFunc: validateAllowedStringValue([]string{"ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-SHA384", "AES256-GCM-SHA384", "AES256-SHA256", "ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-SHA256", "AES128-GCM-SHA256", "AES128-SHA256"}), + //ValidateFunc: validate.ValidateAllowedStringValues([]string{"ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-SHA384", "AES256-GCM-SHA384", "AES256-SHA256", "ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-SHA256", "AES128-GCM-SHA256", "AES128-SHA256"}), }, "wait_time_minutes": { Type: schema.TypeInt, @@ -222,17 +224,17 @@ func resourceIBMLbaas() *schema.Resource { }, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", @@ -243,12 +245,12 @@ func resourceIBMLbaas() *schema.Resource { func resourceIBMLbaasCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Find price items productOrderContainer, err := buildLbaasLBProductOrderContainer(d, sess) if err != nil { - return fmt.Errorf("Error creating Load balancer: %s", err) + return fmt.Errorf("[ERROR] Error creating Load balancer: %s", err) } log.Println("[INFO] Creating Load Balancer") @@ -256,20 +258,20 @@ func resourceIBMLbaasCreate(d *schema.ResourceData, meta interface{}) error { _, err = services.GetProductOrderService(sess). VerifyOrder(productOrderContainer) if err != nil { - return fmt.Errorf("Error during creation of Load balancer: %s", err) + return fmt.Errorf("[ERROR] Error during creation of Load balancer: %s", err) } //place order _, err = services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of Load balancer: %s", err) + return fmt.Errorf("[ERROR] Error during creation of Load balancer: %s", err) } name := d.Get("name").(string) lbaasLB, err := findLbaasLBByOrderId(sess, name, d) if err != nil { - return fmt.Errorf("Error during creation of Load balancer: %s", err) + return fmt.Errorf("[ERROR] Error during creation of Load balancer: %s", err) } d.SetId(*lbaasLB.Uuid) @@ -278,12 +280,12 @@ func resourceIBMLbaasCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbaasRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) result, err := service.Mask("datacenter,members,listeners.defaultPool,listeners.defaultPool.sessionAffinity,listeners.defaultPool.healthMonitor,healthMonitors,sslCiphers[name],useSystemPublicIpPool,isPublic,name,description,operatingStatus,address").GetLoadBalancer(sl.String(d.Id())) if err != nil { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } var lbType string @@ -301,23 +303,23 @@ func resourceIBMLbaasRead(d *schema.ResourceData, meta interface{}) error { d.Set("type", lbType) d.Set("status", result.OperatingStatus) d.Set("vip", result.Address) - d.Set("health_monitors", flattenHealthMonitors(result.Listeners)) - d.Set("protocols", flattenProtocols(result.Listeners)) - d.Set("ssl_ciphers", flattenSSLCiphers(result.SslCiphers)) + d.Set("health_monitors", flex.FlattenHealthMonitors(result.Listeners)) + d.Set("protocols", flex.FlattenProtocols(result.Listeners)) + d.Set("ssl_ciphers", flex.FlattenSSLCiphers(result.SslCiphers)) if *result.UseSystemPublicIpPool == 1 { d.Set("use_system_public_ip_pool", true) } else { d.Set("use_system_public_ip_pool", false) } - d.Set(ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/network/loadbalancing/cloud/details/%s#Overview", d.Id())) - d.Set(ResourceName, *result.Name) - d.Set(ResourceStatus, *result.OperatingStatus) + d.Set(flex.ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/network/loadbalancing/cloud/details/%s#Overview", d.Id())) + d.Set(flex.ResourceName, *result.Name) + d.Set(flex.ResourceStatus, *result.OperatingStatus) return nil } func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess.SetRetries(0)) if d.HasChange("description") { @@ -332,7 +334,7 @@ func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { os := o.(*schema.Set) ns := n.(*schema.Set) - add, err := expandProtocols(ns.Difference(os).List()) + add, err := flex.ExpandProtocols(ns.Difference(os).List()) if err != nil { return err } @@ -347,24 +349,22 @@ func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { if len(removeList) > 0 { _, err := listenerService.DeleteLoadBalancerProtocols(sl.String(d.Id()), removeList) if err != nil { - return fmt.Errorf("Error removing protocols: %#v", err) + return fmt.Errorf("[ERROR] Error removing protocols: %#v", err) } _, err = waitForLbaasLBAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } } if len(add) > 0 { _, err := listenerService.UpdateLoadBalancerProtocols(sl.String(d.Id()), add) if err != nil { - return fmt.Errorf("Error adding protocols: %#v", err) + return fmt.Errorf("[ERROR] Error adding protocols: %#v", err) } _, err = waitForLbaasLBAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } } @@ -374,7 +374,7 @@ func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { service := services.GetNetworkLBaaSLoadBalancerService(sess.SetRetries(0)) supportedCiphers, err := services.GetNetworkLBaaSSSLCipherService(sess).Mask("id,name").GetAllObjects() if err != nil { - return fmt.Errorf("Error retreving list of ssl ciphers: %#v", err) + return fmt.Errorf("[ERROR] Error retreving list of ssl ciphers: %#v", err) } ciphers := make([]int, v.(*schema.Set).Len()) for i, v := range v.(*schema.Set).List() { @@ -387,12 +387,11 @@ func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { } _, err = service.UpdateSslCiphers(sl.String(d.Id()), ciphers) if err != nil { - return fmt.Errorf("Error updating ssl ciphers: %#v", err) + return fmt.Errorf("[ERROR] Error updating ssl ciphers: %#v", err) } _, err = waitForLbaasLBAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } } @@ -403,7 +402,7 @@ func resourceIBMLbaasUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLbaasDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) _, err := service.CancelLoadBalancer(sl.String(d.Id())) @@ -411,20 +410,19 @@ func resourceIBMLbaasDelete(d *schema.ResourceData, meta interface{}) error { if strings.Contains(err.Error(), "DELETE_PENDING") { log.Println("Deletion is already in progress, probably from previous runs") } else { - return fmt.Errorf("Error deleting load balancer: %s", err) + return fmt.Errorf("[ERROR] Error deleting load balancer: %s", err) } } _, err = waitForLbaasLBDelete(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to be deleted: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be deleted: %s", d.Id(), err) } d.SetId("") return nil } func resourceIBMLbaasExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) result, err := service.GetLoadBalancer(sl.String(d.Id())) @@ -432,7 +430,7 @@ func resourceIBMLbaasExists(d *schema.ResourceData, meta interface{}) (bool, err if apiErr, ok := err.(sl.Error); ok && (apiErr.StatusCode == 404 || apiErr.Exception == NOT_FOUND) { return false, nil } - return false, fmt.Errorf("Error retrieving load balancer: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } return result.Uuid != nil && *result.Uuid == d.Id(), nil } @@ -547,11 +545,11 @@ func findLbaasLBByOrderId(sess *session.Session, name string, d *schema.Resource } return nil, - fmt.Errorf("Cannot find a load balancer with name '%s' ", name) + fmt.Errorf("[ERROR] Cannot find a load balancer with name '%s' ", name) } func waitForLbaasLBAvailable(d *schema.ResourceData, meta interface{}) (interface{}, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) stateConf := &resource.StateChangeConf{ @@ -561,7 +559,7 @@ func waitForLbaasLBAvailable(d *schema.ResourceData, meta interface{}) (interfac lb, err := service.GetLoadBalancer(sl.String(d.Id())) if err != nil { if apiErr, ok := err.(sl.Error); ok && (apiErr.StatusCode == 404 || apiErr.Exception == NOT_FOUND) { - return nil, "", fmt.Errorf("The load balancer %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The load balancer %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } @@ -581,7 +579,7 @@ func waitForLbaasLBAvailable(d *schema.ResourceData, meta interface{}) (interfac } func waitForLbaasLBDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) stateConf := &resource.StateChangeConf{ @@ -620,7 +618,7 @@ func resourceIBMLBProtocolHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%d-", v.(int))) } - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func resourceIBMLBMemberHash(v interface{}) int { @@ -629,5 +627,5 @@ func resourceIBMLBMemberHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address"].(string))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } diff --git a/ibm/resource_ibm_lbaas_health_monitor.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor.go similarity index 81% rename from ibm/resource_ibm_lbaas_health_monitor.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor.go index 431bd36f8..a99762130 100644 --- a/ibm/resource_ibm_lbaas_health_monitor.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor.go @@ -1,18 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/services" "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMLbaasHealthMonitor() *schema.Resource { +func ResourceIBMLbaasHealthMonitor() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbaasHealthMonitorCreate, Read: resourceIBMLbaasHealthMonitorRead, @@ -25,41 +28,41 @@ func resourceIBMLbaasHealthMonitor() *schema.Resource { "protocol": { Type: schema.TypeString, Required: true, - ValidateFunc: validateAllowedStringValue([]string{"HTTP", "HTTPS", "TCP"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"HTTP", "HTTPS", "TCP"}), Description: "Protocol value", }, "port": { Type: schema.TypeInt, Required: true, - ValidateFunc: validatePortRange(1, 65535), + ValidateFunc: validate.ValidatePortRange(1, 65535), Description: "Port number", }, "interval": { Type: schema.TypeInt, Optional: true, Default: 5, - ValidateFunc: validateInterval, + ValidateFunc: validate.ValidateInterval, Description: "Interval value", }, "max_retries": { Type: schema.TypeInt, Optional: true, Default: 2, - ValidateFunc: validateMaxRetries, + ValidateFunc: validate.ValidateMaxRetries, Description: "Maximum retry counts", }, "timeout": { Type: schema.TypeInt, Optional: true, Default: 2, - ValidateFunc: validateTimeout, + ValidateFunc: validate.ValidateTimeout, Description: "Timeout in seconds", }, "url_path": { Type: schema.TypeString, Optional: true, Default: "/", - ValidateFunc: validateURLPath, + ValidateFunc: validate.ValidateURLPath, Description: "URL Path", }, "monitor_id": { @@ -79,7 +82,7 @@ func resourceIBMLbaasHealthMonitor() *schema.Resource { } func resourceIBMLbaasHealthMonitorCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() healthMonitorService := services.GetNetworkLBaaSHealthMonitorService(sess.SetRetries(0)) lbaasID := d.Get("lbaas_id").(string) @@ -98,27 +101,25 @@ func resourceIBMLbaasHealthMonitorCreate(d *schema.ResourceData, meta interface{ _, err := waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } _, err = healthMonitorService.UpdateLoadBalancerHealthMonitors(sl.String(lbaasID), healthMonitors) if err != nil { - return fmt.Errorf("Error adding health monitors: %#v", err) + return fmt.Errorf("[ERROR] Error adding health monitors: %#v", err) } _, err = waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } d.SetId(fmt.Sprintf("%s/%s", lbaasID, d.Get("monitor_id").(string))) return resourceIBMLbaasHealthMonitorRead(d, meta) } func resourceIBMLbaasHealthMonitorRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -127,7 +128,7 @@ func resourceIBMLbaasHealthMonitorRead(d *schema.ResourceData, meta interface{}) result, err := service.Mask("listeners.defaultPool.healthMonitor").GetLoadBalancer(sl.String(lbaasID)) if err != nil { - return fmt.Errorf("Error retrieving load balancer: %s", err) + return fmt.Errorf("[ERROR] Error retrieving load balancer: %s", err) } for _, i := range result.Listeners { if monitorID == *i.DefaultPool.HealthMonitor.Uuid { @@ -148,9 +149,9 @@ func resourceIBMLbaasHealthMonitorRead(d *schema.ResourceData, meta interface{}) } func resourceIBMLbaasHealthMonitorUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() healthMonitorService := services.GetNetworkLBaaSHealthMonitorService(sess.SetRetries(0)) - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -179,7 +180,7 @@ func resourceIBMLbaasHealthMonitorUpdate(d *schema.ResourceData, meta interface{ _, err := healthMonitorService.UpdateLoadBalancerHealthMonitors(sl.String(lbaasID), healthMonitors) if err != nil { - return fmt.Errorf("Error adding health monitors: %#v", err) + return fmt.Errorf("[ERROR] Error adding health monitors: %#v", err) } _, err = waitForLbaasLBActive(d, meta) if err != nil { diff --git a/ibm/resource_ibm_lbaas_health_monitor_test.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor_test.go similarity index 91% rename from ibm/resource_ibm_lbaas_health_monitor_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor_test.go index 47021705a..f5354591e 100644 --- a/ibm/resource_ibm_lbaas_health_monitor_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas_health_monitor_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ import ( func TestAccIBMLbaasHealthMonitor_Basic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitorConfig_basic(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -50,10 +52,10 @@ func TestAccIBMLbaasHealthMonitor_Basic(t *testing.T) { func TestAccIBMLbaasHealthMonitor_tcp(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitorConfig_tcp(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -80,10 +82,10 @@ func TestAccIBMLbaasHealthMonitor_tcp(t *testing.T) { func TestAccIBMLbaasHealthMonitor_InvalidInterval(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitor_InvalidInterval, ExpectError: regexp.MustCompile("must be between 2 and 60"), }, @@ -93,10 +95,10 @@ func TestAccIBMLbaasHealthMonitor_InvalidInterval(t *testing.T) { func TestAccIBMLbaasHealthMonitor_InvalidTimeout(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitor_Timeout, ExpectError: regexp.MustCompile("must be between 1 and 59"), }, @@ -106,10 +108,10 @@ func TestAccIBMLbaasHealthMonitor_InvalidTimeout(t *testing.T) { func TestAccIBMLbaasHealthMonitor_InvalidMaxRetries(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitor_MaxRetries, ExpectError: regexp.MustCompile("must be between 1 and 10"), }, @@ -119,10 +121,10 @@ func TestAccIBMLbaasHealthMonitor_InvalidMaxRetries(t *testing.T) { func TestAccIBMLbaasHealthMonitor_InvalidURLPath(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasHealthMonitor_URLPath, ExpectError: regexp.MustCompile("should start with"), }, @@ -207,7 +209,7 @@ resource "ibm_lbaas_health_monitor" "lbaas_hm" { lbaas_id = "${data.ibm_lbaas.ds_lbaas.id}" monitor_id = "${data.ibm_lbaas.ds_lbaas.health_monitors.0.monitor_id}" } -`, name, lbaasSubnetId) +`, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasHealthMonitorConfig_update(name string) string { @@ -238,7 +240,7 @@ resource "ibm_lbaas_health_monitor" "lbaas_hm" { lbaas_id = "${data.ibm_lbaas.ds_lbaas.id}" monitor_id = "${data.ibm_lbaas.ds_lbaas.health_monitors.0.monitor_id}" } -`, name, lbaasSubnetId) +`, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasHealthMonitorConfig_tcp(name string) string { @@ -266,7 +268,7 @@ resource "ibm_lbaas_health_monitor" "lbaas_tcp" { lbaas_id = "${data.ibm_lbaas.ds_lbaas.id}" monitor_id = "${data.ibm_lbaas.ds_lbaas.health_monitors.0.monitor_id}" } -`, name, lbaasSubnetId) +`, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasHealthMonitorConfig_tcp_update(name string) string { @@ -296,5 +298,5 @@ resource "ibm_lbaas_health_monitor" "lbaas_tcp" { lbaas_id = "${data.ibm_lbaas.ds_lbaas.id}" monitor_id = "${data.ibm_lbaas.ds_lbaas.health_monitors.0.monitor_id}" } -`, name, lbaasSubnetId) +`, name, acc.LbaasSubnetId) } diff --git a/ibm/resource_ibm_lbaas_server_instance_attachment.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment.go similarity index 80% rename from ibm/resource_ibm_lbaas_server_instance_attachment.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment.go index 3af7f52e0..bea2775b6 100644 --- a/ibm/resource_ibm_lbaas_server_instance_attachment.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -15,7 +17,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMLbaasServerInstanceAttachment() *schema.Resource { +func ResourceIBMLbaasServerInstanceAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMLbaasServerInstanceAttachmentCreate, Read: resourceIBMLbaasServerInstanceAttachmentRead, @@ -30,14 +32,14 @@ func resourceIBMLbaasServerInstanceAttachment() *schema.Resource { Description: "The Private IP address of a load balancer member.", Required: true, ForceNew: true, - ValidateFunc: validateIP, + ValidateFunc: validate.ValidateIP, }, "weight": { Type: schema.TypeInt, Description: "The weight of a load balancer member.", Computed: true, Optional: true, - ValidateFunc: validateWeight, + ValidateFunc: validate.ValidateWeight, }, "lbaas_id": { Type: schema.TypeString, @@ -55,7 +57,7 @@ func resourceIBMLbaasServerInstanceAttachment() *schema.Resource { } func resourceIBMLbaasServerInstanceAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) memberService := services.GetNetworkLBaaSMemberService(sess) privateIPAddress := d.Get("private_ip_address").(string) @@ -68,17 +70,15 @@ func resourceIBMLbaasServerInstanceAttachmentCreate(d *schema.ResourceData, meta members = append(members, *p) _, err := waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", d.Id(), err) } _, err = memberService.AddLoadBalancerMembers(sl.String(lbaasId), members) if err != nil { - return fmt.Errorf("Error adding server instances: %#v", err) + return fmt.Errorf("[ERROR] Error adding server instances: %#v", err) } _, err = waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } result, err := service.Mask("members").GetLoadBalancer(sl.String(lbaasId)) lbaasMembers := result.Members @@ -93,14 +93,13 @@ func resourceIBMLbaasServerInstanceAttachmentCreate(d *schema.ResourceData, meta } func resourceIBMLbaasServerInstanceAttachmentRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() memberService := services.GetNetworkLBaaSMemberService(sess) id := d.Id() memId, _ := strconv.Atoi(d.Id()) member, err := memberService.Id(memId).GetObject() if err != nil { - return fmt.Errorf( - "Error retrieving load balancer member(%s) : %s", id, err) + return fmt.Errorf("[ERROR] Error retrieving load balancer member(%s) : %s", id, err) } d.Set("private_ip_address", member.Address) d.Set("weight", member.Weight) @@ -110,7 +109,7 @@ func resourceIBMLbaasServerInstanceAttachmentRead(d *schema.ResourceData, meta i } func resourceIBMLbaasServerInstanceAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() memberService := services.GetNetworkLBaaSMemberService(sess) if d.HasChange("weight") { weight := d.Get("weight").(int) @@ -131,7 +130,7 @@ func resourceIBMLbaasServerInstanceAttachmentUpdate(d *schema.ResourceData, meta } _, err = memberService.UpdateLoadBalancerMembers(sl.String(lbaasId), members) if err != nil { - return fmt.Errorf("Error updating loadbalnacer: %#v", err) + return fmt.Errorf("[ERROR] Error updating loadbalnacer: %#v", err) } _, err = waitForLbaasLBActive(d, meta) if err != nil { @@ -145,7 +144,7 @@ func resourceIBMLbaasServerInstanceAttachmentUpdate(d *schema.ResourceData, meta } func resourceIBMLbaasServerInstanceAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() memberService := services.GetNetworkLBaaSMemberService(sess) memId, _ := strconv.Atoi(d.Id()) result, err := memberService.Id(memId).GetObject() @@ -153,36 +152,34 @@ func resourceIBMLbaasServerInstanceAttachmentExists(d *schema.ResourceData, meta if apiErr, ok := err.(sl.Error); ok && (apiErr.StatusCode == 404 || apiErr.Exception == NOT_FOUND) { return false, nil } - return false, fmt.Errorf("Error retrieving load balancer member: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving load balancer member: %s", err) } return result.Id != nil && *result.Id == memId, nil } func resourceIBMLbaasServerInstanceAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() memberService := services.GetNetworkLBaaSMemberService(sess) lbaasId := d.Get("lbaas_id").(string) removeList := make([]string, 0, 1) removeList = append(removeList, d.Get("uuid").(string)) _, err := waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", d.Id(), err) } _, err = memberService.DeleteLoadBalancerMembers(sl.String(lbaasId), removeList) if err != nil { - return fmt.Errorf("Error removing server instances: %#v", err) + return fmt.Errorf("[ERROR] Error removing server instances: %#v", err) } _, err = waitForLbaasLBActive(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } return nil } func waitForLbaasLBActive(d *schema.ResourceData, meta interface{}) (interface{}, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) lbaasId := d.Get("lbaas_id").(string) @@ -193,7 +190,7 @@ func waitForLbaasLBActive(d *schema.ResourceData, meta interface{}) (interface{} lb, err := service.GetLoadBalancer(sl.String(lbaasId)) if err != nil { if apiErr, ok := err.(sl.Error); ok && (apiErr.StatusCode == 404 || apiErr.Exception == NOT_FOUND) { - return nil, "", fmt.Errorf("The load balancer %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The load balancer %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } diff --git a/ibm/resource_ibm_lbaas_server_instance_attachment_test.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment_test.go similarity index 90% rename from ibm/resource_ibm_lbaas_server_instance_attachment_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment_test.go index 24cc97830..efc7adcee 100644 --- a/ibm/resource_ibm_lbaas_server_instance_attachment_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas_server_instance_attachment_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,11 +21,11 @@ import ( func TestAccIBMLbaasServerInstanceAttachment_Basic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasServerInstanceAttachmentDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasServerInstanceAttachmentConfig_basic(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -49,11 +52,11 @@ func TestAccIBMLbaasServerInstanceAttachment_Basic(t *testing.T) { func TestAccIBMLbaasServerInstanceAttachment_Dynamic_SI_Attachment(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasServerInstanceAttachmentDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasServerInstanceAttachmentConfig_lbaas_dynamic_association(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -61,7 +64,7 @@ func TestAccIBMLbaasServerInstanceAttachment_Dynamic_SI_Attachment(t *testing.T) resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), ), @@ -74,7 +77,7 @@ func TestAccIBMLbaasServerInstanceAttachment_Dynamic_SI_Attachment(t *testing.T) resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), ), @@ -87,7 +90,7 @@ func TestAccIBMLbaasServerInstanceAttachment_Dynamic_SI_Attachment(t *testing.T) resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), ), @@ -98,11 +101,11 @@ func TestAccIBMLbaasServerInstanceAttachment_Dynamic_SI_Attachment(t *testing.T) func TestAccIBMLbaasServerInstanceAttachment_InvalidWeight(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasServerInstanceAttachmentDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasServerInstanceAttachment_InvalidWeight, ExpectError: regexp.MustCompile("must be between 1 and 100"), }, @@ -112,11 +115,11 @@ func TestAccIBMLbaasServerInstanceAttachment_InvalidWeight(t *testing.T) { func TestAccIBMLbaasServerInstanceAttachment_InvalidIPAddress(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasServerInstanceAttachmentDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMLbaasServerInstanceAttachment_IPAddress, ExpectError: regexp.MustCompile("must be a valid ip address"), }, @@ -125,7 +128,7 @@ func TestAccIBMLbaasServerInstanceAttachment_InvalidIPAddress(t *testing.T) { } func testAccCheckIBMLbaasServerInstanceAttachmentDestroy(s *terraform.State) error { - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) for _, rs := range s.RootModule().Resources { @@ -139,7 +142,7 @@ func testAccCheckIBMLbaasServerInstanceAttachmentDestroy(s *terraform.State) err if err == nil { return fmt.Errorf("load balancer (%s) to be destroyed still exists", rs.Primary.ID) } else if apiErr, ok := err.(sl.Error); ok && apiErr.Exception != NOT_FOUND { - return fmt.Errorf("Error waiting for load balancer (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -210,7 +213,7 @@ resource "ibm_lbaas_server_instance_attachment" "lbaas_member2" { weight = 20 lbaas_id = "${ibm_lbaas.lbaas.id}" } -`, lbaasDatacenter, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasServerInstanceAttachmentConfig_lbaas_dynamic_association(name string) string { @@ -242,7 +245,7 @@ resource "ibm_lbaas_server_instance_attachment" "lbaas_member" { weight = 20 lbaas_id = "${ibm_lbaas.lbaas.id}" } -`, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasServerInstanceAttachmentConfig_lbaas_dynamic_association_attach(name string) string { @@ -274,7 +277,7 @@ resource "ibm_lbaas_server_instance_attachment" "lbaas_member" { weight = 40 lbaas_id = "${ibm_lbaas.lbaas.id}" } -`, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasServerInstanceAttachmentConfig_lbaas_dynamic_association_dettach(name string) string { @@ -306,7 +309,7 @@ resource "ibm_lbaas_server_instance_attachment" "lbaas_member" { weight = 40 lbaas_id = "${ibm_lbaas.lbaas.id}" } -`, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } func testAccCheckIBMLbaasServerInstanceAttachmentConfig_update(name string) string { @@ -356,5 +359,5 @@ resource "ibm_lbaas_server_instance_attachment" "lbaas_member2" { weight = 40 lbaas_id = "${ibm_lbaas.lbaas.id}" } -`, lbaasDatacenter, lbaasDatacenter, name, lbaasSubnetId) +`, acc.LbaasDatacenter, acc.LbaasDatacenter, name, acc.LbaasSubnetId) } diff --git a/ibm/resource_ibm_lbaas_test.go b/ibm/service/classicinfrastructure/resource_ibm_lbaas_test.go similarity index 93% rename from ibm/resource_ibm_lbaas_test.go rename to ibm/service/classicinfrastructure/resource_ibm_lbaas_test.go index 8ce560215..c21a2682d 100644 --- a/ibm/resource_ibm_lbaas_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_lbaas_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,8 +21,8 @@ import ( func TestAccIBMLbaas_Basic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -30,7 +33,7 @@ func TestAccIBMLbaas_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -45,7 +48,7 @@ func TestAccIBMLbaas_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "updated desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -62,7 +65,7 @@ func TestAccIBMLbaas_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "updated desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -77,7 +80,7 @@ func TestAccIBMLbaas_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "name", name), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -95,8 +98,8 @@ func TestAccIBMLbaas_Basic(t *testing.T) { func TestAccIBMLbaas_Private(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -107,7 +110,7 @@ func TestAccIBMLbaas_Private(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -122,7 +125,7 @@ func TestAccIBMLbaas_Private(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "updated desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -141,7 +144,7 @@ func TestAccIBMLbaas_Private(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "updated desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -159,8 +162,8 @@ func TestAccIBMLbaas_Private(t *testing.T) { func TestAccIBMLbaasWithMoreProtocols(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -171,7 +174,7 @@ func TestAccIBMLbaasWithMoreProtocols(t *testing.T) { resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "description", "desc-used for terraform uat"), resource.TestCheckResourceAttr( - "ibm_lbaas.lbaas", "datacenter", lbaasDatacenter), + "ibm_lbaas.lbaas", "datacenter", acc.LbaasDatacenter), resource.TestCheckResourceAttr( "ibm_lbaas.lbaas", "subnets.#", "1"), resource.TestCheckResourceAttr( @@ -187,8 +190,8 @@ func TestAccIBMLbaasWithMoreProtocols(t *testing.T) { func TestAccIBMLbaas_importBasic(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -208,8 +211,8 @@ func TestAccIBMLbaas_importBasic(t *testing.T) { func TestAccIBMLbaasInvalidProtocol(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -222,8 +225,8 @@ func TestAccIBMLbaasInvalidProtocol(t *testing.T) { func TestAccIBMLbaasInvalidPort(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -236,8 +239,8 @@ func TestAccIBMLbaasInvalidPort(t *testing.T) { func TestAccIBMLbaasInvalidMethod(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -250,8 +253,8 @@ func TestAccIBMLbaasInvalidMethod(t *testing.T) { func TestAccIBMLbaasInvalidMaxConn(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -265,8 +268,8 @@ func TestAccIBMLbaasInvalidMaxConn(t *testing.T) { func TestAccIBMLbaasCertificateWithHTTPInvalidConfig(t *testing.T) { name := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLbaasDestroy, Steps: []resource.TestStep{ { @@ -278,7 +281,7 @@ func TestAccIBMLbaasCertificateWithHTTPInvalidConfig(t *testing.T) { } func testAccCheckIBMLbaasDestroy(s *terraform.State) error { - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() service := services.GetNetworkLBaaSLoadBalancerService(sess) for _, rs := range s.RootModule().Resources { @@ -292,7 +295,7 @@ func testAccCheckIBMLbaasDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("load balancer (%s) to be destroyed still exists", rs.Primary.ID) } else if apiErr, ok := err.(sl.Error); ok && apiErr.Exception != NOT_FOUND { - return fmt.Errorf("Error waiting for load balancer (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -318,7 +321,7 @@ resource "ibm_lbaas" "lbaas" { } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } const testAccCheckIBMLbaasInvalidMaxConn = ` @@ -397,7 +400,7 @@ resource "ibm_lbaas" "lbaas" { description = "desc-used for terraform uat" subnets = ["%s"] } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigPrivate(name string) string { @@ -408,7 +411,7 @@ resource "ibm_lbaas" "lbaas" { subnets = ["%s"] type = "PRIVATE" } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigPrivateUpdate(name string) string { @@ -435,7 +438,7 @@ resource "ibm_lbaas" "lbaas" { } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigPrivateUpdateHTTPS(name string) string { @@ -528,7 +531,7 @@ resource "ibm_lbaas" "lbaas" { } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigMoreThanTwoProtocols(name string) string { @@ -564,7 +567,7 @@ resource "ibm_lbaas" "lbaas" { load_balancing_method = "round_robin" } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigUpdate(name string) string { @@ -583,7 +586,7 @@ resource "ibm_lbaas" "lbaas" { } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigUpdateHTTPS(name string) string { @@ -676,7 +679,7 @@ resource "ibm_lbaas" "lbaas" { } } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } func testAccCheckIBMLbaasConfigUpdateHTTPSSSLCiphers(name string) string { @@ -769,5 +772,5 @@ resource "ibm_lbaas" "lbaas" { } ssl_ciphers = ["ECDHE-RSA-AES256-GCM-SHA384","ECDHE-RSA-AES256-SHA384","ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-SHA256"] } -`, name, lbaasSubnetId) +`, name, acc.LbaasDatacenter) } diff --git a/ibm/resource_ibm_multi_vlan_firewall.go b/ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall.go similarity index 86% rename from ibm/resource_ibm_multi_vlan_firewall.go rename to ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall.go index 76cdcbc7d..8e3ddd44b 100644 --- a/ibm/resource_ibm_multi_vlan_firewall.go +++ b/ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" @@ -19,7 +21,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMMultiVlanFirewall() *schema.Resource { +func ResourceIBMMultiVlanFirewall() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkMultiVlanCreate, Read: resourceIBMMultiVlanFirewallRead, @@ -69,7 +71,7 @@ func resourceIBMMultiVlanFirewall() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateAllowedStringValue([]string{"FortiGate Firewall Appliance HA Option", "FortiGate Security Appliance"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"FortiGate Firewall Appliance HA Option", "FortiGate Security Appliance"}), Description: "Firewall type", }, @@ -123,7 +125,7 @@ const ( ) func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() name := d.Get("name").(string) FirewallType := d.Get("firewall_type").(string) datacenter := d.Get("datacenter").(string) @@ -135,7 +137,7 @@ func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) // 1.Getting the router ID routerids, err := PodService.Filter(filter.Path("datacenterName").Eq(datacenter).Build()).Mask(podMask).GetAllObjects() if err != nil { - return fmt.Errorf("Encountered problem trying to get the router ID: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the router ID: %s", err) } var routerid int for _, iterate := range routerids { @@ -147,7 +149,7 @@ func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) //2.Get the datacenter id dc, err := location.GetDatacenterByName(sess, datacenter, "id") if err != nil { - return fmt.Errorf("Encountered problem trying to get the Datacenter ID: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the Datacenter ID: %s", err) } locationservice := services.GetLocationService(sess) @@ -181,7 +183,7 @@ func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) for _, addon := range actualaddons { actualpriceid, err := product.GetPriceIDByPackageIdandLocationGroups(sess, listofpriceids, 863, addon) if err != nil || actualpriceid == 0 { - return fmt.Errorf("Encountered problem trying to get priceIds of items which have to be ordered: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get priceIds of items which have to be ordered: %s", err) } priceItem := datatypes.Product_Item_Price{ Id: &actualpriceid, @@ -213,17 +215,17 @@ func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) _, err = services.GetProductOrderService(sess.SetRetries(0)). VerifyOrder(&productOrderContainer) if err != nil { - return fmt.Errorf("Error during Verify order for Creating: %s", err) + return fmt.Errorf("[ERROR] Error during Verify order for Creating: %s", err) } //9.Calling place order receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during Place order for Creating: %s", err) + return fmt.Errorf("[ERROR] Error during Place order for Creating: %s", err) } _, vlan, _, err := findDedicatedFirewallByOrderId(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall: %s", err) } id := *vlan.NetworkFirewall.Id d.SetId(fmt.Sprintf("%d", id)) @@ -232,7 +234,7 @@ func resourceIBMNetworkMultiVlanCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMMultiVlanFirewallRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, _ := strconv.Atoi(d.Id()) @@ -243,7 +245,7 @@ func resourceIBMMultiVlanFirewallRead(d *schema.ResourceData, meta interface{}) Mask(multiVlanMask). GetNetworkGateways() if err != nil { - return fmt.Errorf("Error retrieving firewall information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving firewall information: %s", err) } d.Set("datacenter", *firewalls[0].NetworkFirewall.Datacenter.Name) if *firewalls[0].NetworkFirewall.CustomerManagedFlag && *firewalls[0].MemberCount == 1 { @@ -276,7 +278,7 @@ func resourceIBMMultiVlanFirewallRead(d *schema.ResourceData, meta interface{}) func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("addon_configuration") { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, _ := strconv.Atoi(d.Id()) old, new := d.GetChange("addon_configuration") oldaddons := old.([]interface{}) @@ -300,7 +302,7 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} Mask(multiVlanMask). GetNetworkGateways() if err != nil { - return fmt.Errorf("Some error occured while fetching the information of the Multi-Vlan Firewall") + return fmt.Errorf("[ERROR] Expected error occured while fetching the information of the Multi-Vlan Firewall") } for _, i := range remove { for _, j := range firewalls[0].NetworkFirewall.BillingItem.ActiveChildren { @@ -311,7 +313,7 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} customerNote := "No longer needed" billingitemservice, err := services.GetBillingItemService(sess).Id(*j.Id).CancelItem(&cancelimmediately, &cancelAssociatedBillingItems, &reason, &customerNote) if err != nil || !billingitemservice { - return fmt.Errorf("Error while cancelling the addon") + return fmt.Errorf("[ERROR] Error while cancelling the addon") } } } @@ -320,12 +322,12 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} if len(add) > 0 { datacentername, ok := d.GetOk("datacenter") if !ok { - return fmt.Errorf("The attribute datacenter is not defined") + return fmt.Errorf("[ERROR] The attribute datacenter is not defined") } //2.Get the datacenter id dc, err := location.GetDatacenterByName(sess, datacentername.(string), "id") if err != nil { - return fmt.Errorf("Datacenter not found") + return fmt.Errorf("[ERROR] Something not found") } locationservice := services.GetLocationService(sess) //3. get the pricegroups that the datacenter belongs to @@ -339,7 +341,7 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} for _, addon := range add { actualpriceid, err := product.GetPriceIDByPackageIdandLocationGroups(sess, listofpriceids, 863, addon) if err != nil || actualpriceid == 0 { - return fmt.Errorf("The addon or the firewall is not available for the datacenter you have selected. Please enter a different datacenter") + return fmt.Errorf("[ERROR] The addon or the firewall is not available for the datacenter you have selected. Please enter a different datacenter") } priceItem := datatypes.Product_Item_Price{ Id: &actualpriceid, @@ -372,18 +374,18 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} _, err = services.GetProductOrderService(sess.SetRetries(0)). VerifyOrder(&upgradeproductOrderContainer) if err != nil { - return fmt.Errorf("Error during Verify order for Updating: %s", err) + return fmt.Errorf("[ERROR] Error during Verify order for Updating: %s", err) } //9.Calling place order receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(&upgradeproductOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during Place order for Updating: %s", err) + return fmt.Errorf("[ERROR] Error during Place order for Updating: %s", err) } _, _, _, err = findDedicatedFirewallByOrderId(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of dedicated hardware firewall: %s", err) + return fmt.Errorf("[ERROR] Error during creation of dedicated hardware firewall: %s", err) } } } @@ -391,7 +393,7 @@ func resourceIBMMultiVlanFirewallUpdate(d *schema.ResourceData, meta interface{} } func resourceIBMMultiVLanFirewallExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() fwID, _ := strconv.Atoi(d.Id()) @@ -402,7 +404,7 @@ func resourceIBMMultiVLanFirewallExists(d *schema.ResourceData, meta interface{} Mask(multiVlanMask). GetNetworkGateways() if err != nil { - return false, fmt.Errorf("Error retrieving firewall information: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving firewall information: %s", err) } if firewalls[0].NetworkFirewall.BillingItem == nil { return false, nil @@ -410,8 +412,8 @@ func resourceIBMMultiVLanFirewallExists(d *schema.ResourceData, meta interface{} return true, nil } -//This function takes two lists and returns the difference between the two lists -//listdifference([1,2] [2,3]) = [1] +// This function takes two lists and returns the difference between the two lists +// listdifference([1,2] [2,3]) = [1] func listdifference(a, b []string) []string { mb := map[string]bool{} for _, x := range b { diff --git a/ibm/resource_ibm_multi_vlan_firewall_test.go b/ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall_test.go similarity index 91% rename from ibm/resource_ibm_multi_vlan_firewall_test.go rename to ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall_test.go index df414cf40..d1029af34 100644 --- a/ibm/resource_ibm_multi_vlan_firewall_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_multi_vlan_firewall_test.go @@ -1,21 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMMultiVlanFirewall_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMMultiVlanFirewallConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -39,10 +41,10 @@ func TestAccIBMMultiVlanFirewall_Basic(t *testing.T) { func TestAccIBMMultiVlanFirewallHA_Basic(t *testing.T) { t.SkipNow() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMMultiVlanFirewallHAConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -64,10 +66,10 @@ func TestAccIBMMultiVlanFirewallHA_Basic(t *testing.T) { } func TestAccIBMMultiVlanFirewall_InvalidFirewallType(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMMultiVlanFirewallFirewallTypeConfig_InvalidFirewallType, ExpectError: regexp.MustCompile("must contain a value from"), }, diff --git a/ibm/resource_ibm_network_gateway.go b/ibm/service/classicinfrastructure/resource_ibm_network_gateway.go similarity index 89% rename from ibm/resource_ibm_network_gateway.go rename to ibm/service/classicinfrastructure/resource_ibm_network_gateway.go index 7c7d1e8f0..b838d9300 100644 --- a/ibm/resource_ibm_network_gateway.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "bytes" @@ -13,7 +13,8 @@ import ( "strings" "time" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -28,7 +29,7 @@ import ( const highAvailability = "HA" const GATEWAY_APPLIANCE_CLUSTER = "NETWORK_GATEWAY_APPLIANCE_CLUSTER" -func resourceIBMNetworkGateway() *schema.Resource { +func ResourceIBMNetworkGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkGatewayCreate, Read: resourceIBMNetworkGatewayRead, @@ -50,7 +51,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeInt}, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "post_install_script_uri": { @@ -58,7 +59,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: nil, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "private_ip_address_id": { @@ -159,7 +160,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "package_key_name": { @@ -167,7 +168,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: "NETWORK_GATEWAY_APPLIANCE", ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "redundant_power_supply": { @@ -175,7 +176,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "process_key_name": { @@ -183,7 +184,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Default: "INTEL_SINGLE_XEON_1270_3_50", - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "os_key_name": { @@ -191,7 +192,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Default: "OS_VYATTA_5600_5_X_UP_TO_1GBPS_SUBSCRIPTION_EDITION_64_BIT", - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "redundant_network": { @@ -199,14 +200,14 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "unbonded_network": { Type: schema.TypeBool, Optional: true, Default: false, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "tags": { Type: schema.TypeSet, @@ -220,14 +221,14 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Default: 20000, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "memory": { Type: schema.TypeInt, Required: true, //Sometime memory returns back as different. Since this resource is immutable at this point //and memory can't be really updated , suppress the change until we figure out how to handle it - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, ForceNew: true, }, "storage_groups": { @@ -255,7 +256,7 @@ func resourceIBMNetworkGateway() *schema.Resource { }, }, }, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "ssh_key_ids": { @@ -263,7 +264,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeInt}, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "post_install_script_uri": { @@ -271,7 +272,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, Default: nil, ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "user_metadata": { @@ -285,7 +286,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "public_vlan_id": { @@ -293,7 +294,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "private_vlan_id": { @@ -301,7 +302,7 @@ func resourceIBMNetworkGateway() *schema.Resource { Optional: true, ForceNew: true, Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "public_ipv4_address": { @@ -364,7 +365,7 @@ func resourceIBMNetworkGateway() *schema.Resource { } func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() members := []gatewayMember{} for _, v := range d.Get("members").(*schema.Set).List() { m := v.(map[string]interface{}) @@ -373,7 +374,7 @@ func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) e if len(members) == 2 { if !areVlanCompatible(members) { - return fmt.Errorf("Members should have exactly same public and private vlan configuration," + + return fmt.Errorf("[ERROR] Members should have exactly same public and private vlan configuration," + "please check public_vlan_id and private_vlan_id property on individual members") } } @@ -381,13 +382,11 @@ func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) e //Build order for one member order, err := getMonthlyGatewayOrder(members[0], meta) if err != nil { - return fmt.Errorf( - "Encountered problem trying to get the Gateway order template: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the Gateway order template: %s", err) } err = setHardwareOptions(members[0], &order.Hardware[0]) if err != nil { - return fmt.Errorf( - "Encountered problem trying to configure Gateway options: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to configure Gateway options: %s", err) } // two members can be ordered together if they have same hardware configuration @@ -422,8 +421,7 @@ func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) e }) err = setHardwareOptions(members[1], &order.Hardware[1]) if err != nil { - return fmt.Errorf( - "Encountered problem trying to configure Gateway options: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to configure Gateway options: %s", err) } } @@ -500,20 +498,17 @@ func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) e _, err = services.GetProductOrderService(sess).VerifyOrder(&productOrder) if err != nil { - return fmt.Errorf( - "Encountered problem trying to verify the order: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to verify the order: %s", err) } orderReceipt, err := services.GetProductOrderService(sess.SetRetries(0)).PlaceOrder(&productOrder, sl.Bool(false)) if err != nil { - return fmt.Errorf( - "Encountered problem trying to place the order: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to place the order: %s", err) } gID := *orderReceipt.OrderDetails.OrderContainers[0].Hardware[0].GlobalIdentifier bm, err := waitForNetworkGatewayMemberProvision(&order.Hardware[0], meta, gID) if err != nil { - return fmt.Errorf( - "Error waiting for Gateway (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for Gateway (%s) to become ready: %s", d.Id(), err) } id := *bm.(datatypes.Hardware).NetworkGatewayMember.NetworkGatewayId @@ -534,8 +529,7 @@ func resourceIBMNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) e gID1 := *orderReceipt.OrderDetails.OrderContainers[0].Hardware[1].GlobalIdentifier bm, err := waitForNetworkGatewayMemberProvision(&order.Hardware[1], meta, gID1) if err != nil { - return fmt.Errorf( - "Error waiting for Gateway (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for Gateway (%s) to become ready: %s", d.Id(), err) } member2Id := *bm.(datatypes.Hardware).Id log.Printf("[INFO] Member 2 ID: %d", member2Id) @@ -580,14 +574,14 @@ func resourceIBMMemberHostHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", m["hostname"].(string))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func resourceIBMNetworkGatewayRead(d *schema.ResourceData, meta interface{}) error { - service := services.GetNetworkGatewayService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).Mask( "insideVlans,members,status,privateIpAddress[ipAddress],publicIpAddress[ipAddress]," + @@ -598,7 +592,7 @@ func resourceIBMNetworkGatewayRead(d *schema.ResourceData, meta interface{}) err "powerSupplyCount,primaryNetworkComponent[networkVlan],memoryCapacity,networkVlans[id,vlanNumber]]]", ).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Network Gateway: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Network Gateway: %s", err) } d.Set("name", result.Name) if result.PrivateIpAddress != nil { @@ -613,8 +607,8 @@ func resourceIBMNetworkGatewayRead(d *schema.ResourceData, meta interface{}) err d.Set("public_ipv6_address_id", result.PublicIpv6AddressId) d.Set("public_vlan_id", result.PublicVlanId) d.Set("status", result.Status.Name) - d.Set("members", flattenGatewayMembers(d, result.Members)) - d.Set("associated_vlans", flattenGatewayVlans(result.InsideVlans)) + d.Set("members", flex.FlattenGatewayMembers(d, result.Members)) + d.Set("associated_vlans", flex.FlattenGatewayVlans(result.InsideVlans)) //Set default connection info connInfo := map[string]string{"type": "ssh", "user": "vyatta"} @@ -629,28 +623,26 @@ func resourceIBMNetworkGatewayRead(d *schema.ResourceData, meta interface{}) err } func updateGatewayName(id int, name string, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkGatewayService(sess) _, err := service.Id(id).EditObject(&datatypes.Network_Gateway{ Name: sl.String(name), }) if err != nil { - return fmt.Errorf("Couldn't set the gateway name to %s", name) + return fmt.Errorf("[ERROR] Could n't set the gateway name to %s", name) } return err } func addGatewayMember(gwID int, member gatewayMember, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() order, err := getMonthlyGatewayOrder(member, meta) if err != nil { - return fmt.Errorf( - "Encountered problem trying to get the Gateway order template: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to get the Gateway order template: %s", err) } err = setHardwareOptions(member, &order.Hardware[0]) if err != nil { - return fmt.Errorf( - "Encountered problem trying to configure Gateway options: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to configure Gateway options: %s", err) } haOrder := datatypes.Container_Product_Order_Hardware_Server_Gateway_Appliance{} @@ -675,21 +667,18 @@ func addGatewayMember(gwID int, member gatewayMember, meta interface{}) error { _, err = services.GetProductOrderService(sess).VerifyOrder(&haOrder) if err != nil { - return fmt.Errorf( - "Encountered problem trying to verify the order: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to verify the order: %s", err) } orderReceipt, err := services.GetProductOrderService(sess.SetRetries(0)).PlaceOrder(&haOrder, sl.Bool(false)) if err != nil { - return fmt.Errorf( - "Encountered problem trying to place the order: %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to place the order: %s", err) } gID := *orderReceipt.OrderDetails.Hardware[0].GlobalIdentifier bm, err := waitForNetworkGatewayMemberProvision(&order.Hardware[0], meta, gID) if err != nil { - return fmt.Errorf( - "Error waiting for Gateway (%d) to become ready: %s", gwID, err) + return fmt.Errorf("[ERROR] Error waiting for Gateway (%d) to become ready: %s", gwID, err) } id := *bm.(datatypes.Hardware).Id log.Printf("[INFO] Newly added member ID: %d", id) @@ -711,10 +700,10 @@ func resourceIBMNetworkGatewayUpdate(d *schema.ResourceData, meta interface{}) e } func resourceIBMNetworkGatewayDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } service := services.GetNetworkGatewayService(sess) gw, err := service.Id(id).Mask("members[hardwareId]").GetObject() @@ -733,17 +722,17 @@ func resourceIBMNetworkGatewayDelete(d *schema.ResourceData, meta interface{}) e } func resourceIBMNetworkGatewayExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetNetworkGatewayService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { if apiErr, ok := err.(sl.Error); !ok || apiErr.StatusCode != 404 { - return false, fmt.Errorf("Error trying to retrieve Network Gateway: %s", err) + return false, fmt.Errorf("[ERROR] Error trying to retrieve Network Gateway: %s", err) } } @@ -751,7 +740,7 @@ func resourceIBMNetworkGatewayExists(d *schema.ResourceData, meta interface{}) ( } func getMonthlyGatewayOrder(d dataRetriever, meta interface{}) (datatypes.Container_Product_Order, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Validate attributes for network gateway ordering. model := d.Get("package_key_name") @@ -890,7 +879,7 @@ func getMonthlyGatewayOrder(d dataRetriever, meta interface{}) (datatypes.Contai privateNetworkOnly := d.Get("private_network_only").(bool) if d.Get("ipv6_enabled").(bool) { if privateNetworkOnly { - return datatypes.Container_Product_Order{}, fmt.Errorf("Unable to configure a public IPv6 address with a private_network_only option") + return datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] Unable to configure a public IPv6 address with a private_network_only option") } keyName := "1_IPV6_ADDRESS" price, err := getItemPriceId(items, "pri_ipv6_addresses", keyName) @@ -967,7 +956,7 @@ func getPackageByModelGateway(sess *session.Session, model string, isGateway boo return pkg, nil } } - return datatypes.Product_Package{}, fmt.Errorf("No Gateway package key name for %s. Available package key name(s) is(are) %s", model, availableModels) + return datatypes.Product_Package{}, fmt.Errorf("[ERROR] No Gateway package key name for %s. Available package key name(s) is(are) %s", model, availableModels) } func setHardwareOptions(m gatewayMember, hardware *datatypes.Hardware) error { public_vlan_id := m.Get("public_vlan_id").(int) @@ -1021,7 +1010,7 @@ func waitForNetworkGatewayMemberProvision(d *datatypes.Hardware, meta interface{ Pending: []string{"retry", "pending"}, Target: []string{"provisioned"}, Refresh: func() (interface{}, string, error) { - service := services.GetAccountService(meta.(ClientSession).SoftLayerSession()) + service := services.GetAccountService(meta.(conns.ClientSession).SoftLayerSession()) bms, err := service.Filter( filter.Build( filter.Path("hardware.globalIdentifier").Eq(globalIdentifier)), @@ -1060,8 +1049,8 @@ func setTagsAndNotes(m gatewayMember, meta interface{}) error { return nil } -//New types to resuse functions from other resources which does the same job -//Essentially mimic schema.ResourceData get functions +// New types to resuse functions from other resources which does the same job +// Essentially mimic schema.ResourceData get functions type dataRetriever interface { Get(string) interface{} GetOk(string) (interface{}, bool) diff --git a/ibm/resource_ibm_network_gateway_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_test.go similarity index 89% rename from ibm/resource_ibm_network_gateway_test.go rename to ibm/service/classicinfrastructure/resource_ibm_network_gateway_test.go index 433bf9c5f..ed2877f92 100644 --- a/ibm/resource_ibm_network_gateway_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -25,8 +28,8 @@ func TestAccIBMNetworkGateway_standalone(t *testing.T) { config := "ibm_network_gateway.standalone" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMNetworkGatewayDestroy, Steps: []resource.TestStep{ { @@ -56,8 +59,8 @@ func TestAccIBMNetworkGateway_ha_similar_members(t *testing.T) { config := "ibm_network_gateway.ha_same_conf" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMNetworkGatewayDestroy, Steps: []resource.TestStep{ { @@ -83,7 +86,7 @@ func testAccCheckIBMNetworkGatewayExists(n string, networkGateway *datatypes.Net return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -96,7 +99,7 @@ func testAccCheckIBMNetworkGatewayExists(n string, networkGateway *datatypes.Net return err } - service := services.GetNetworkGatewayService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) ng, err := service.Id(id).GetObject() if err != nil { return err @@ -114,7 +117,7 @@ func testAccCheckIBMNetworkGatewayExists(n string, networkGateway *datatypes.Net } } func testAccCheckIBMNetworkGatewayDestroy(s *terraform.State) error { - service := services.GetNetworkGatewayService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_network_gateway" { @@ -129,8 +132,7 @@ func testAccCheckIBMNetworkGatewayDestroy(s *terraform.State) error { // Wait if err != nil { if apiErr, ok := err.(sl.Error); !ok || apiErr.StatusCode != 404 { - return fmt.Errorf( - "Error waiting for Network Gateway (%d) to be destroyed: %s", + return fmt.Errorf("[ERROR] Error waiting for Network Gateway (%d) to be destroyed: %s", id, err) } } diff --git a/ibm/resource_ibm_network_gateway_vlan_attachment.go b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment.go similarity index 79% rename from ibm/resource_ibm_network_gateway_vlan_attachment.go rename to ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment.go index cd337ae02..1f6b39df7 100644 --- a/ibm/resource_ibm_network_gateway_vlan_attachment.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -16,7 +17,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMNetworkGatewayVlanAttachment() *schema.Resource { +func ResourceIBMNetworkGatewayVlanAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkGatewayVlanAttachmentCreate, Read: resourceIBMNetworkGatewayVlanAttachmentRead, @@ -53,7 +54,7 @@ func resourceIBMNetworkGatewayVlanAttachmentCreate(d *schema.ResourceData, meta networkVlanID := d.Get("network_vlan_id").(int) bypass := d.Get("bypass").(bool) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkGatewayService(sess) vlanService := services.GetNetworkGatewayVlanService(sess) result, err := service.Id(gatewayID).Mask( @@ -82,7 +83,7 @@ func resourceIBMNetworkGatewayVlanAttachmentCreate(d *schema.ResourceData, meta } vlan, err := vlanService.Id(*i.Id).GetObject() if err != nil { - return fmt.Errorf("Error trying to retrieve Network Gateway Vlan: %s", err) + return fmt.Errorf("[ERROR] Error trying to retrieve Network Gateway Vlan: %s", err) } d.SetId(fmt.Sprintf("%d", *vlan.Id)) d.Set("bypass", vlan.BypassFlag) @@ -112,15 +113,15 @@ func resourceIBMNetworkGatewayVlanAttachmentCreate(d *schema.ResourceData, meta } func resourceIBMNetworkGatewayVlanAttachmentRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } vlan, err := services.GetNetworkGatewayVlanService(sess).Id(id).GetObject() if err != nil { - return fmt.Errorf("Error trying to retrieve Network Gateway Vlan: %s", err) + return fmt.Errorf("[ERROR] Error trying to retrieve Network Gateway Vlan: %s", err) } d.Set("gateway_id", vlan.NetworkGatewayId) d.Set("network_vlan_id", vlan.NetworkVlanId) @@ -129,11 +130,11 @@ func resourceIBMNetworkGatewayVlanAttachmentRead(d *schema.ResourceData, meta in } func resourceIBMNetworkGatewayVlanAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkGatewayVlanService(sess) id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } if d.HasChange("bypass") { bypass := d.Get("bypass").(bool) @@ -160,15 +161,15 @@ func resourceIBMNetworkGatewayVlanAttachmentUpdate(d *schema.ResourceData, meta } func resourceIBMNetworkGatewayVlanAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - service := services.GetNetworkGatewayVlanService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayVlanService(meta.(conns.ClientSession).SoftLayerSession()) id, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(id).GetObject() if err != nil { if apiErr, ok := err.(sl.Error); !ok || apiErr.StatusCode != 404 { - return false, fmt.Errorf("Error trying to retrieve Network Gateway Vlan: %s", err) + return false, fmt.Errorf("[ERROR] Error trying to retrieve Network Gateway Vlan: %s", err) } } return result.Id != nil && *result.Id == id, nil @@ -178,9 +179,9 @@ func resourceIBMNetworkGatewayVlanAttachmentDelete(d *schema.ResourceData, meta id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } - vlan, err := services.GetNetworkGatewayVlanService(meta.(ClientSession).SoftLayerSession()).Id(id).GetObject() + vlan, err := services.GetNetworkGatewayVlanService(meta.(conns.ClientSession).SoftLayerSession()).Id(id).GetObject() err = resourceIBMNetworkGatewayVlanDissociate(d, meta) if err != nil { @@ -197,33 +198,31 @@ func resourceIBMNetworkGatewayVlanAttachmentDelete(d *schema.ResourceData, meta } func resourceIBMNetworkGatewayVlanAssociate(d *schema.ResourceData, meta interface{}, vlan datatypes.Network_Gateway_Vlan) (resp datatypes.Network_Gateway_Vlan, err error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() resp, err = services.GetNetworkGatewayVlanService(sess).CreateObject(&vlan) if err != nil { - return resp, fmt.Errorf( - "Encountered problem trying to associate the VLAN : %s", err) + return resp, fmt.Errorf("[ERROR] Encountered problem trying to associate the VLAN : %s", err) } return resp, nil } func resourceIBMNetworkGatewayVlanDissociate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } err = services.GetNetworkGatewayVlanService(sess).Id(id).DeleteObject() if err != nil { - return fmt.Errorf( - "Encountered problem trying to dissociate the VLAN : %s", err) + return fmt.Errorf("[ERROR] Encountered problem trying to dissociate the VLAN : %s", err) } return nil } func waitForNetworkGatewayActiveState(id int, meta interface{}) (interface{}, error) { log.Printf("Waiting for Gateway (%d) to be active", id) - service := services.GetNetworkGatewayService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkGatewayService(meta.(conns.ClientSession).SoftLayerSession()) stateConf := &resource.StateChangeConf{ Pending: []string{"updating"}, diff --git a/ibm/resource_ibm_network_gateway_vlan_attachment_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment_test.go similarity index 96% rename from ibm/resource_ibm_network_gateway_vlan_attachment_test.go rename to ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment_test.go index 85e804c52..8e1df8452 100644 --- a/ibm/resource_ibm_network_gateway_vlan_attachment_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_gateway_vlan_attachment_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMNetworkGatewayVlanAtachment_Basic(t *testing.T) { gatewayName := fmt.Sprintf("tfuatgw%s", acctest.RandString(12)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkGatewayVlanAttachment_basic(gatewayName, hostname1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -28,7 +30,7 @@ func TestAccIBMNetworkGatewayVlanAtachment_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkGatewayVlanAttachment_update(gatewayName, hostname1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -45,10 +47,10 @@ func TestAccIBMNetworkGatewayVlanAtachment_Import_Update(t *testing.T) { gatewayName := fmt.Sprintf("tfuatgw%s", acctest.RandString(12)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkGatewayVlanAttachment_import_update(gatewayName, hostname1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_network_interface_sg_attachment.go b/ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment.go similarity index 79% rename from ibm/resource_ibm_network_interface_sg_attachment.go rename to ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment.go index baaea90a2..6cdde8ce1 100644 --- a/ibm/resource_ibm_network_interface_sg_attachment.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/services" @@ -17,7 +18,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMNetworkInterfaceSGAttachment() *schema.Resource { +func ResourceIBMNetworkInterfaceSGAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkInterfaceSGAttachmentCreate, Read: resourceIBMNetworkInterfaceSGAttachmentRead, @@ -52,10 +53,10 @@ func resourceIBMNetworkInterfaceSGAttachment() *schema.Resource { func resourceIBMNetworkInterfaceSGAttachmentCreate(d *schema.ResourceData, meta interface{}) error { mk := "network_interface_sg_attachment_" + strconv.Itoa(d.Get("network_interface_id").(int)) - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) ncs := services.GetVirtualGuestNetworkComponentService(sess) @@ -84,7 +85,7 @@ func resourceIBMNetworkInterfaceSGAttachmentCreate(d *schema.ResourceData, meta } guest, err := ncs.Id(interfaceID).GetGuest() if err != nil { - return fmt.Errorf("Couldn't retrieve the virtual guest on interface %d", interfaceID) + return fmt.Errorf("[ERROR] Could n't retrieve the virtual guest on interface %d", interfaceID) } guestService := services.GetVirtualGuestService(sess) ok, err := guestService.Id(*guest.Id).RebootSoft() @@ -92,7 +93,7 @@ func resourceIBMNetworkInterfaceSGAttachmentCreate(d *schema.ResourceData, meta return err } if !ok { - return fmt.Errorf("Couldn't reboot the VSI %d", *guest.Id) + return fmt.Errorf("[ERROR] Could n't reboot the VSI %d", *guest.Id) } //Wait for security group to be ready again after reboot stateConf := &resource.StateChangeConf{ @@ -111,7 +112,7 @@ func resourceIBMNetworkInterfaceSGAttachmentCreate(d *schema.ResourceData, meta } func resourceIBMNetworkInterfaceSGAttachmentRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID, interfaceID, err := decomposeNetworkSGAttachmentID(d.Id()) if err != nil { @@ -126,14 +127,14 @@ func resourceIBMNetworkInterfaceSGAttachmentRead(d *schema.ResourceData, meta in return nil } } - return fmt.Errorf("No association found between security group %d and network interface %d", sgID, interfaceID) + return fmt.Errorf("[ERROR] No association found between security group %d and network interface %d", sgID, interfaceID) } func resourceIBMNetworkInterfaceSGAttachmentDelete(d *schema.ResourceData, meta interface{}) error { mk := "network_interface_sg_attachment_" + strconv.Itoa(d.Get("network_interface_id").(int)) - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) - sess := meta.(ClientSession).SoftLayerSession() + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID, interfaceID, err := decomposeNetworkSGAttachmentID(d.Id()) if err != nil { @@ -141,14 +142,14 @@ func resourceIBMNetworkInterfaceSGAttachmentDelete(d *schema.ResourceData, meta } _, err = service.Id(sgID).DetachNetworkComponents([]int{interfaceID}) if err != nil { - return fmt.Errorf("Error detaching network components from Security Group: %s", err) + return fmt.Errorf("[ERROR] Error detaching network components from Security Group: %s", err) } d.SetId("") return nil } func resourceIBMNetworkInterfaceSGAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID, interfaceID, err := decomposeNetworkSGAttachmentID(d.Id()) @@ -163,29 +164,29 @@ func resourceIBMNetworkInterfaceSGAttachmentExists(d *schema.ResourceData, meta return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting network component bindings: %s", err) } for _, b := range bindings { if *b.NetworkComponentId == interfaceID { return true, nil } } - return false, fmt.Errorf("No association found between security group %d and network interface %d", sgID, interfaceID) + return false, fmt.Errorf("[ERROR] No association found between security group %d and network interface %d", sgID, interfaceID) } func decomposeNetworkSGAttachmentID(attachmentID string) (sgID, interfaceID int, err error) { ids := strings.Split(attachmentID, "_") if len(ids) != 2 { - return -1, -1, fmt.Errorf("The ibm_network_interface_sg_attachment id must be of the form _ but it is %s", attachmentID) + return -1, -1, fmt.Errorf("[ERROR] The ibm_network_interface_sg_attachment id must be of the form _ but it is %s", attachmentID) } sgID, err = strconv.Atoi(ids[0]) if err != nil { - return -1, -1, fmt.Errorf("Not a valid security group ID, must be an integer: %s", err) + return -1, -1, fmt.Errorf("[ERROR] Not a valid security group ID, must be an integer: %s", err) } interfaceID, err = strconv.Atoi(ids[1]) if err != nil { - return -1, -1, fmt.Errorf("Not a valid network interface ID, must be an integer: %s", err) + return -1, -1, fmt.Errorf("[ERROR] Not a valid network interface ID, must be an integer: %s", err) } return } @@ -206,7 +207,7 @@ func securityGroupReadyRefreshStateFunc(sess *slsession.Session, ifcID int) reso func WaitForVSAvailable(d *schema.ResourceData, meta interface{}, timeout time.Duration) (interface{}, error) { interfaceID := d.Get("network_interface_id").(int) log.Printf("Waiting for server (%d) to be available.", interfaceID) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"retry", virtualGuestProvisioning}, Target: []string{virtualGuestAvailable}, @@ -225,7 +226,7 @@ func vsReadyRefreshStateFunc(sess *slsession.Session, ifcID int) resource.StateR guest, err := ncs.Id(ifcID).GetGuest() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving virtual guest: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } return false, "retry", nil } @@ -233,7 +234,7 @@ func vsReadyRefreshStateFunc(sess *slsession.Session, ifcID int) resource.StateR ready, err := guestService.Id(*guest.Id).GetStatus() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving virtual guest: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving virtual guest: %s", err) } return false, "retry", nil } diff --git a/ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment_test.go new file mode 100644 index 000000000..65de48fbe --- /dev/null +++ b/ibm/service/classicinfrastructure/resource_ibm_network_interface_sg_attachment_test.go @@ -0,0 +1,154 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package classicinfrastructure_test + +import ( + "errors" + "fmt" + "strconv" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/softlayer/softlayer-go/services" +) + +func TestAccIBMNetworkInterfaceSGAttachment(t *testing.T) { + hostname := acctest.RandString(16) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckNetworkInterfaceSGAttachmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTestAccIBMNetworkInterfaceSGAttachmentConfig(hostname), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_compute_vm_instance.tfuatvm", "hostname", hostname), + testAccCheckNetworkInterfaceSGAttachmentExists("ibm_network_interface_sg_attachment.ssh"), + testAccCheckNetworkInterfaceSGAttachmentExists("ibm_network_interface_sg_attachment.http"), + ), + }, + }, + }) +} +func decomposeNetworkSGAttachmentID(attachmentID string) (sgID, interfaceID int, err error) { + ids := strings.Split(attachmentID, "_") + if len(ids) != 2 { + return -1, -1, fmt.Errorf("[ERROR] The ibm_network_interface_sg_attachment id must be of the form _ but it is %s", attachmentID) + } + sgID, err = strconv.Atoi(ids[0]) + if err != nil { + return -1, -1, fmt.Errorf("[ERROR] Not a valid security group ID, must be an integer: %s", err) + } + + interfaceID, err = strconv.Atoi(ids[1]) + if err != nil { + return -1, -1, fmt.Errorf("[ERROR] Not a valid network interface ID, must be an integer: %s", err) + } + return +} +func testAccCheckNetworkInterfaceSGAttachmentExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("[ERROR] Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sgID, interfaceID, err := decomposeNetworkSGAttachmentID(rs.Primary.ID) + if err != nil { + return err + } + + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() + service := services.GetNetworkSecurityGroupService(sess) + bindings, err := service.Id(sgID).GetNetworkComponentBindings() + if err != nil { + return err + } + for _, b := range bindings { + if *b.NetworkComponentId == interfaceID { + return nil + } + } + return fmt.Errorf("[ERROR] No association found between security group %d and network interface %d", sgID, interfaceID) + } +} + +func testAccCheckNetworkInterfaceSGAttachmentDestroy(s *terraform.State) error { + service := services.GetNetworkSecurityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_network_interface_sg_attachment" { + continue + } + + sgID, interfaceID, err := decomposeNetworkSGAttachmentID(rs.Primary.ID) + if err != nil { + return err + } + + bindings, err := service.Id(sgID).GetNetworkComponentBindings() + if err != nil { + return err + } + for _, b := range bindings { + if *b.NetworkComponentId == interfaceID { + return fmt.Errorf("Association still exists between security group %d and network interface %d", sgID, interfaceID) + } + } + return nil + } + + return nil +} + +func testAccTestAccIBMNetworkInterfaceSGAttachmentConfig(hostname string) string { + v := fmt.Sprintf(` + data "ibm_security_group" "allowssh" { + name = "allow_ssh" + } + data "ibm_security_group" "allowhttp" { + name = "allow_http" + } + resource "ibm_compute_vm_instance" "tfuatvm" { + hostname = "%s" + domain = "tfvmuatsg.com" + os_reference_code = "DEBIAN_9_64" + datacenter = "wdc07" + network_speed = 10 + hourly_billing = true + private_network_only = false + cores = 1 + memory = 1024 + disks = [25, 10, 20] + dedicated_acct_host_only = true + local_disk = false + ipv6_enabled = true + secondary_ip_count = 4 + notes = "VM notes" + } + resource "ibm_network_interface_sg_attachment" "ssh" { + security_group_id = "${data.ibm_security_group.allowssh.id}" + network_interface_id = "${ibm_compute_vm_instance.tfuatvm.public_interface_id}" + } + resource "ibm_network_interface_sg_attachment" "http" { + security_group_id = "${data.ibm_security_group.allowhttp.id}" + network_interface_id = "${ibm_compute_vm_instance.tfuatvm.public_interface_id}" + } + `, hostname) + return v +} diff --git a/ibm/resource_ibm_network_public_ip.go b/ibm/service/classicinfrastructure/resource_ibm_network_public_ip.go similarity index 82% rename from ibm/resource_ibm_network_public_ip.go rename to ibm/service/classicinfrastructure/resource_ibm_network_public_ip.go index 460dbf030..5ff62ceed 100644 --- a/ibm/resource_ibm_network_public_ip.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_public_ip.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -27,7 +28,7 @@ const ( GlobalIpMask = "id,ipAddress[ipAddress,id,note],destinationIpAddress[ipAddress]" ) -func resourceIBMNetworkPublicIp() *schema.Resource { +func ResourceIBMNetworkPublicIp() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkPublicIpCreate, Read: resourceIBMNetworkPublicIpRead, @@ -40,19 +41,19 @@ func resourceIBMNetworkPublicIp() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "ip_address": &schema.Schema{ + "ip_address": { Type: schema.TypeString, Computed: true, Description: "IP Address", }, - "routes_to": &schema.Schema{ + "routes_to": { Type: schema.TypeString, Required: true, ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { address := v.(string) if net.ParseIP(address) == nil { - errors = append(errors, fmt.Errorf("Invalid IP format: %s", address)) + errors = append(errors, fmt.Errorf("[ERROR] Invalid IP format: %s", address)) } return }, @@ -82,7 +83,7 @@ func resourceIBMNetworkPublicIp() *schema.Resource { func resourceIBMNetworkPublicIpCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Find price items with AdditionalServicesGlobalIpAddresses productOrderContainer, err := buildGlobalIpProductOrderContainer(d, sess, AdditionalServicesGlobalIpAddressesPackageType) @@ -90,7 +91,7 @@ func resourceIBMNetworkPublicIpCreate(d *schema.ResourceData, meta interface{}) // Find price items with AdditionalServices productOrderContainer, err = buildGlobalIpProductOrderContainer(d, sess, AdditionalServicesPackageType) if err != nil { - return fmt.Errorf("Error creating network public ip: %s", err) + return fmt.Errorf("[ERROR] Error creating network public ip: %s", err) } } @@ -99,12 +100,12 @@ func resourceIBMNetworkPublicIpCreate(d *schema.ResourceData, meta interface{}) receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of network public ip: %s", err) + return fmt.Errorf("[ERROR] Error during creation of network public ip: %s", err) } globalIp, err := findGlobalIpByOrderId(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of network public ip: %s", err) + return fmt.Errorf("[ERROR] Error during creation of network public ip: %s", err) } d.SetId(fmt.Sprintf("%d", *globalIp.Id)) @@ -114,17 +115,17 @@ func resourceIBMNetworkPublicIpCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMNetworkPublicIpRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetIpAddressGlobalService(sess) globalIpId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid network public ip ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid network public ip ID, must be an integer: %s", err) } globalIp, err := service.Id(globalIpId).Mask(GlobalIpMask).GetObject() if err != nil { - return fmt.Errorf("Error retrieving network public Ip: %s", err) + return fmt.Errorf("[ERROR] Error retrieving network public Ip: %s", err) } d.Set("ip_address", *globalIp.IpAddress.IpAddress) @@ -138,12 +139,12 @@ func resourceIBMNetworkPublicIpRead(d *schema.ResourceData, meta interface{}) er } func resourceIBMNetworkPublicIpUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetIpAddressGlobalService(sess) globalIpId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid network public ip ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid network public ip ID, must be an integer: %s", err) } routes_to := d.Get("routes_to").(string) @@ -164,17 +165,17 @@ func resourceIBMNetworkPublicIpUpdate(d *schema.ResourceData, meta interface{}) _, err = service.Id(globalIpId).Route(sl.String(routes_to)) if err != nil { - return fmt.Errorf("Error editing network public Ip: %s", err) + return fmt.Errorf("[ERROR] Error editing network public Ip: %s", err) } // Update notes if d.HasChange("notes") { publicIp, err := service.Id(globalIpId).Mask(GlobalIpMask).GetObject() if err != nil { - return fmt.Errorf("Error updating network public Ip: %s", err) + return fmt.Errorf("[ERROR] Error updating network public Ip: %s", err) } err = updatePublicIPNotes(d, sess, publicIp) if err != nil { - return fmt.Errorf("Error editing network public Ip: %s", err) + return fmt.Errorf("[ERROR] Error editing network public Ip: %s", err) } } @@ -199,7 +200,7 @@ func resourceIBMNetworkPublicIpUpdate(d *schema.ResourceData, meta interface{}) pendingResult, err := stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for network public ip destination ip address to become active: %s", err) + return fmt.Errorf("[ERROR] Error waiting for network public ip destination ip address to become active: %s", err) } if _, ok := pendingResult.(datatypes.Network_Subnet_IpAddress_Global); ok { @@ -210,17 +211,17 @@ func resourceIBMNetworkPublicIpUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMNetworkPublicIpDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetIpAddressGlobalService(sess) globalIpId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid network public ip ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid network public ip ID, must be an integer: %s", err) } billingItem, err := service.Id(globalIpId).GetBillingItem() if err != nil { - return fmt.Errorf("Error deleting network public ip: %s", err) + return fmt.Errorf("[ERROR] Error deleting network public ip: %s", err) } if billingItem.Id == nil { @@ -233,12 +234,12 @@ func resourceIBMNetworkPublicIpDelete(d *schema.ResourceData, meta interface{}) } func resourceIBMNetworkPublicIpExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetIpAddressGlobalService(sess) globalIpId, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(globalIpId).GetObject() @@ -246,7 +247,7 @@ func resourceIBMNetworkPublicIpExists(d *schema.ResourceData, meta interface{}) if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving network public ip: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving network public ip: %s", err) } return result.Id != nil && *result.Id == globalIpId, nil } @@ -270,7 +271,7 @@ func findGlobalIpByOrderId(sess *session.Session, orderId int, d *schema.Resourc } else if len(globalIps) == 0 || len(globalIps) == 1 { return datatypes.Network_Subnet_IpAddress_Global{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one network public ip: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one network public ip: %s", err) } }, Timeout: d.Timeout(schema.TimeoutCreate), @@ -290,7 +291,7 @@ func findGlobalIpByOrderId(sess *session.Session, orderId int, d *schema.Resourc } return datatypes.Network_Subnet_IpAddress_Global{}, - fmt.Errorf("Cannot find network public ip with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find network public ip with order id '%d'", orderId) } func buildGlobalIpProductOrderContainer(d *schema.ResourceData, sess *session.Session, packageType string) ( @@ -325,7 +326,7 @@ func buildGlobalIpProductOrderContainer(d *schema.ResourceData, sess *session.Se if len(globalIpItems) == 0 { return &datatypes.Container_Product_Order_Network_Subnet{}, - fmt.Errorf("No product items matching %s could be found", globalIpKeyname) + fmt.Errorf("[ERROR] No product items matching %s could be found", globalIpKeyname) } productOrderContainer := datatypes.Container_Product_Order_Network_Subnet{ @@ -352,7 +353,7 @@ func updatePublicIPNotes(d *schema.ResourceData, sess *session.Session, publicIP Id(id). EditObject(&datatypes.Network_Subnet_IpAddress{Note: sl.String(notes)}) if err != nil { - return fmt.Errorf("Error adding note to network public IP (%d): %s", id, err) + return fmt.Errorf("[ERROR] Error adding note to network public IP (%d): %s", id, err) } } diff --git a/ibm/resource_ibm_network_public_ip_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_public_ip_test.go similarity index 93% rename from ibm/resource_ibm_network_public_ip_test.go rename to ibm/service/classicinfrastructure/resource_ibm_network_public_ip_test.go index 1917f6ef8..6ca57e8c6 100644 --- a/ibm/resource_ibm_network_public_ip_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_public_ip_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "regexp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -21,10 +24,10 @@ func TestAccIBMNetworkPublicIp_Basic(t *testing.T) { hostname2 := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpConfig_basic(hostname1, hostname2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMNetworkPublicIpExists("ibm_network_public_ip.test-global-ip"), @@ -36,7 +39,7 @@ func TestAccIBMNetworkPublicIp_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpConfig_updated(hostname1, hostname2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMResources("ibm_network_public_ip.test-global-ip", "routes_to", @@ -45,7 +48,7 @@ func TestAccIBMNetworkPublicIp_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpConfig_Ipv6Basic, Check: resource.ComposeTestCheckFunc( testAccCheckIBMNetworkPublicIpExists("ibm_network_public_ip.test-global-ip-3"), @@ -57,7 +60,7 @@ func TestAccIBMNetworkPublicIp_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpConfig_Ipv6Updated, Check: resource.ComposeTestCheckFunc( testAccCheckIBMResources("ibm_network_public_ip.test-global-ip-3", "routes_to", @@ -73,10 +76,10 @@ func TestAccIBMNetworkPublicIpWitTag(t *testing.T) { hostname1 := acctest.RandString(16) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpWithTag(hostname1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMNetworkPublicIpExists("ibm_network_public_ip.test-global-ip"), @@ -89,7 +92,7 @@ func TestAccIBMNetworkPublicIpWitTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkPublicIpWithUpdatedTag(hostname1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMResources("ibm_network_public_ip.test-global-ip", "routes_to", @@ -107,16 +110,16 @@ func testAccCheckIBMNetworkPublicIpExists(n string) resource.TestCheckFunc { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } globalIpId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkSubnetIpAddressGlobalService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkSubnetIpAddressGlobalService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundGlobalIp, err := service.Id(globalIpId).GetObject() if err != nil { @@ -135,12 +138,12 @@ func testAccCheckIBMResources(srcResource, srcKey, tgtResource, tgtKey string) r return func(s *terraform.State) error { sourceResource, ok := s.RootModule().Resources[srcResource] if !ok { - return fmt.Errorf("Not found: %s", srcResource) + return fmt.Errorf("[ERROR] Not found: %s", srcResource) } targetResource, ok := s.RootModule().Resources[tgtResource] if !ok { - return fmt.Errorf("Not found: %s", tgtResource) + return fmt.Errorf("[ERROR] Not found: %s", tgtResource) } if sourceResource.Primary.Attributes[srcKey] != targetResource.Primary.Attributes[tgtKey] { diff --git a/ibm/resource_ibm_network_vlan.go b/ibm/service/classicinfrastructure/resource_ibm_network_vlan.go similarity index 85% rename from ibm/resource_ibm_network_vlan.go rename to ibm/service/classicinfrastructure/resource_ibm_network_vlan.go index 8b0d8a893..8487949e8 100644 --- a/ibm/resource_ibm_network_vlan.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_vlan.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -12,6 +12,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -32,7 +35,7 @@ const ( "billingItem[recurringFee],guestNetworkComponentCount,subnets[networkIdentifier,cidr,subnetType],tagReferences[id,tag[name]]" ) -func resourceIBMNetworkVlan() *schema.Resource { +func ResourceIBMNetworkVlan() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkVlanCreate, Read: resourceIBMNetworkVlanRead, @@ -72,7 +75,7 @@ func resourceIBMNetworkVlan() *schema.Resource { "name": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateVLANName, + ValidateFunc: validate.ValidateVLANName, Description: "VLAN name", }, @@ -134,12 +137,12 @@ func resourceIBMNetworkVlan() *schema.Resource { Set: schema.HashString, Description: "List of tags", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", @@ -150,14 +153,14 @@ func resourceIBMNetworkVlan() *schema.Resource { func resourceIBMNetworkVlanCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() router := d.Get("router_hostname").(string) name := d.Get("name").(string) vlanType := d.Get("type").(string) if (vlanType == "PRIVATE" && len(router) > 0 && strings.Contains(router, "fcr")) || (vlanType == "PUBLIC" && len(router) > 0 && strings.Contains(router, "bcr")) { - return fmt.Errorf("Error creating vlan: mismatch between vlan_type '%s' and router_hostname '%s'", vlanType, router) + return fmt.Errorf("[ERROR] Error creating vlan: mismatch between vlan_type '%s' and router_hostname '%s'", vlanType, router) } // Find price items with AdditionalServicesNetworkVlan @@ -166,7 +169,7 @@ func resourceIBMNetworkVlanCreate(d *schema.ResourceData, meta interface{}) erro // Find price items with AdditionalServices productOrderContainer, err = buildVlanProductOrderContainer(d, sess, AdditionalServicesPackageType) if err != nil { - return fmt.Errorf("Error creating vlan: %s", err) + return fmt.Errorf("[ERROR] Error creating vlan: %s", err) } } @@ -175,19 +178,19 @@ func resourceIBMNetworkVlanCreate(d *schema.ResourceData, meta interface{}) erro receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of vlan: %s", err) + return fmt.Errorf("[ERROR] Error during creation of vlan: %s", err) } vlan, err := findVlanByOrderId(sess, *receipt.OrderId, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("Error finding VLAN order %d: %s", *receipt.OrderId, err) + return fmt.Errorf("[ERROR] Error finding VLAN order %d: %s", *receipt.OrderId, err) } if len(name) > 0 { _, err = services.GetNetworkVlanService(sess). Id(*vlan.Id).EditObject(&datatypes.Network_Vlan{Name: sl.String(name)}) if err != nil { - return fmt.Errorf("Error updating vlan: %s", err) + return fmt.Errorf("[ERROR] Error updating vlan: %s", err) } } @@ -207,18 +210,18 @@ func resourceIBMNetworkVlanCreate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMNetworkVlanRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkVlanService(sess) vlanId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid vlan ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid vlan ID, must be an integer: %s", err) } vlan, err := service.Id(vlanId).Mask(VlanMask).GetObject() if err != nil { - return fmt.Errorf("Error retrieving vlan: %s", err) + return fmt.Errorf("[ERROR] Error retrieving vlan: %s", err) } d.Set("vlan_number", *vlan.VlanNumber) @@ -278,19 +281,19 @@ func resourceIBMNetworkVlanRead(d *schema.ResourceData, meta interface{}) error } d.Set("tags", tags) } - d.Set(ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/network/vlans/%s", d.Id())) - d.Set(ResourceName, sl.Get(vlan.Name, "")) + d.Set(flex.ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/network/vlans/%s", d.Id())) + d.Set(flex.ResourceName, sl.Get(vlan.Name, "")) return nil } func resourceIBMNetworkVlanUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkVlanService(sess) vlanId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid vlan ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid vlan ID, must be an integer: %s", err) } opts := datatypes.Network_Vlan{} @@ -315,7 +318,7 @@ func resourceIBMNetworkVlanUpdate(d *schema.ResourceData, meta interface{}) erro _, err = service.Id(vlanId).EditObject(&opts) if err != nil { - return fmt.Errorf("Error updating vlan: %s", err) + return fmt.Errorf("[ERROR] Error updating vlan: %s", err) } } @@ -323,12 +326,12 @@ func resourceIBMNetworkVlanUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMNetworkVlanDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkVlanService(sess) vlanId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid vlan ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid vlan ID, must be an integer: %s", err) } const ( @@ -362,7 +365,7 @@ func resourceIBMNetworkVlanDelete(d *schema.ResourceData, meta interface{}) erro billingItem, err := service.Id(vlanId).GetBillingItem() if err != nil { - return fmt.Errorf("Error deleting vlan: %s", err) + return fmt.Errorf("[ERROR] Error deleting vlan: %s", err) } // VLANs which don't have billing items are managed by SoftLayer. They can't be deleted by @@ -382,12 +385,12 @@ func resourceIBMNetworkVlanDelete(d *schema.ResourceData, meta interface{}) erro } func resourceIBMNetworkVlanExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkVlanService(sess) vlanID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid vlan ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid vlan ID, must be an integer: %s", err) } result, err := service.Id(vlanID).Mask("id").GetObject() @@ -397,7 +400,7 @@ func resourceIBMNetworkVlanExists(d *schema.ResourceData, meta interface{}) (boo return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting network VLAN: %s", err) } return result.Id != nil && *result.Id == vlanID, nil } @@ -421,7 +424,7 @@ func findVlanByOrderId(sess *session.Session, orderId int, timeout time.Duration } else if len(vlans) == 0 { return []datatypes.Network_Vlan{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one vlan: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one vlan: %s", err) } }, Timeout: timeout, @@ -443,7 +446,7 @@ func findVlanByOrderId(sess *session.Session, orderId int, timeout time.Duration } return datatypes.Network_Vlan{}, - fmt.Errorf("Cannot find vlan with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find vlan with order id '%d'", orderId) } func buildVlanProductOrderContainer(d *schema.ResourceData, sess *session.Session, packageType string) ( @@ -489,7 +492,7 @@ func buildVlanProductOrderContainer(d *schema.ResourceData, sess *session.Sessio if len(vlanItems) == 0 { return &datatypes.Container_Product_Order_Network_Vlan{}, - fmt.Errorf("No product items matching %s could be found", vlanKeyname) + fmt.Errorf("[ERROR] No product items matching %s could be found", vlanKeyname) } productOrderContainer := datatypes.Container_Product_Order_Network_Vlan{ @@ -510,7 +513,7 @@ func buildVlanProductOrderContainer(d *schema.ResourceData, sess *session.Sessio productOrderContainer.RouterId = rt.Id if err != nil { return &datatypes.Container_Product_Order_Network_Vlan{}, - fmt.Errorf("Error creating vlan: %s", err) + fmt.Errorf("[ERROR] Error creating vlan: %s", err) } } @@ -518,10 +521,10 @@ func buildVlanProductOrderContainer(d *schema.ResourceData, sess *session.Sessio } func setVlanTags(id int, tags string, meta interface{}) error { - service := services.GetNetworkVlanService(meta.(ClientSession).SoftLayerSession()) + service := services.GetNetworkVlanService(meta.(conns.ClientSession).SoftLayerSession()) _, err := service.Id(id).SetTags(sl.String(tags)) if err != nil { - return fmt.Errorf("Could not set tags on vlan %d", id) + return fmt.Errorf("[ERROR] Could not set tags on vlan %d", id) } return nil } diff --git a/ibm/resource_ibm_network_vlan_spanning.go b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning.go similarity index 75% rename from ibm/resource_ibm_network_vlan_spanning.go rename to ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning.go index 0a492293b..282e4613c 100644 --- a/ibm/resource_ibm_network_vlan_spanning.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "math/rand" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/services" ) -func resourceIBMNetworkVlanSpan() *schema.Resource { +func ResourceIBMNetworkVlanSpan() *schema.Resource { return &schema.Resource{ Create: resourceIBMNetworkVlanSpanCreate, Read: resourceIBMNetworkVlanSpanRead, @@ -24,7 +26,7 @@ func resourceIBMNetworkVlanSpan() *schema.Resource { "vlan_spanning": { Type: schema.TypeString, Required: true, - ValidateFunc: validateAllowedStringValue([]string{"off", "on"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"off", "on"}), Description: "VLAN Spanning set to On or Off", }, }, @@ -32,13 +34,13 @@ func resourceIBMNetworkVlanSpan() *schema.Resource { } func resourceIBMNetworkVlanSpanRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) vlanSpan, err := service.GetNetworkVlanSpan() if err != nil { - return fmt.Errorf("Error retrieving vlan: %s", err) + return fmt.Errorf("[ERROR] Error retrieving vlan: %s", err) } if *vlanSpan.EnabledFlag == true { @@ -51,7 +53,7 @@ func resourceIBMNetworkVlanSpanRead(d *schema.ResourceData, meta interface{}) er } func resourceIBMNetworkVlanSpanCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) rnd := rand.Intn(8999999) + 1000000 @@ -66,7 +68,7 @@ func resourceIBMNetworkVlanSpanCreate(d *schema.ResourceData, meta interface{}) _, err := service.SetVlanSpan(&enabled) if err != nil { - return fmt.Errorf("Error settinging VLAN Spanning %s", err) + return fmt.Errorf("[ERROR] Error settinging VLAN Spanning %s", err) } d.SetId(strconv.Itoa(rnd)) @@ -74,7 +76,7 @@ func resourceIBMNetworkVlanSpanCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMNetworkVlanSpanUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetAccountService(sess) vlanSpanning := d.Get("vlan_spanning").(string) @@ -87,7 +89,7 @@ func resourceIBMNetworkVlanSpanUpdate(d *schema.ResourceData, meta interface{}) _, err := service.SetVlanSpan(&enabled) if err != nil { - return fmt.Errorf("Error settinging VLAN Spanning %s", err) + return fmt.Errorf("[ERROR] Error settinging VLAN Spanning %s", err) } return resourceIBMNetworkVlanSpanRead(d, meta) diff --git a/ibm/resource_ibm_network_vlan_spanning_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning_test.go similarity index 85% rename from ibm/resource_ibm_network_vlan_spanning_test.go rename to ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning_test.go index b4d24d9a3..ac18bb408 100644 --- a/ibm/resource_ibm_network_vlan_spanning_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_spanning_test.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMNetworkVlanSpan_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMNetworkVlanSpanOnConfigBasic, diff --git a/ibm/resource_ibm_network_vlan_test.go b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_test.go similarity index 93% rename from ibm/resource_ibm_network_vlan_test.go rename to ibm/service/classicinfrastructure/resource_ibm_network_vlan_test.go index ff365dc40..18512168d 100644 --- a/ibm/resource_ibm_network_vlan_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_network_vlan_test.go @@ -1,22 +1,24 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMNetworkVlan_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -32,7 +34,7 @@ func TestAccIBMNetworkVlan_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfig_name_update, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -47,10 +49,10 @@ func TestAccIBMNetworkVlan_With_Tag(t *testing.T) { tags1 := "collectd" tags2 := "mesos-master" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfigWithTag(tags1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -72,7 +74,7 @@ func TestAccIBMNetworkVlan_With_Tag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfigTagUpdate(tags1, tags2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -91,10 +93,10 @@ func TestAccIBMNetworkVlan_With_Tag(t *testing.T) { func TestAccIBMNetworkVlan_With_Multipe_Subnets(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfigMultipleSubnets(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -111,10 +113,10 @@ func TestAccIBMNetworkVlan_with_vm(t *testing.T) { domain := "vlan.tfmvmuat.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMNetworkVlanConfigWithVM(hostname, domain), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( diff --git a/ibm/resource_ibm_object_storage_account.go b/ibm/service/classicinfrastructure/resource_ibm_object_storage_account.go similarity index 93% rename from ibm/resource_ibm_object_storage_account.go rename to ibm/service/classicinfrastructure/resource_ibm_object_storage_account.go index fcea40e67..6eb48c8cf 100644 --- a/ibm/resource_ibm_object_storage_account.go +++ b/ibm/service/classicinfrastructure/resource_ibm_object_storage_account.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -10,6 +10,7 @@ import ( "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -19,7 +20,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMObjectStorageAccount() *schema.Resource { +func ResourceIBMObjectStorageAccount() *schema.Resource { return &schema.Resource{ Create: resourceIBMObjectStorageAccountCreate, Read: resourceIBMObjectStorageAccountRead, @@ -29,11 +30,11 @@ func resourceIBMObjectStorageAccount() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, }, - "local_note": &schema.Schema{ + "local_note": { Type: schema.TypeString, Optional: true, }, @@ -48,7 +49,7 @@ func resourceIBMObjectStorageAccount() *schema.Resource { } func resourceIBMObjectStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() accountService := services.GetAccountService(sess) // Check if an object storage account exists @@ -113,7 +114,7 @@ func WaitForOrderCompletion( var err error var completed bool - completed, billingOrderItem, err = order.CheckBillingOrderComplete(meta.(ClientSession).SoftLayerSession(), receipt) + completed, billingOrderItem, err = order.CheckBillingOrderComplete(meta.(conns.ClientSession).SoftLayerSession(), receipt) if err != nil { return nil, "", err } @@ -134,7 +135,7 @@ func WaitForOrderCompletion( } func resourceIBMObjectStorageAccountRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() accountService := services.GetAccountService(sess) accountName := d.Id() d.Set("name", accountName) diff --git a/ibm/resource_ibm_object_storage_account_test.go b/ibm/service/classicinfrastructure/resource_ibm_object_storage_account_test.go similarity index 85% rename from ibm/resource_ibm_object_storage_account_test.go rename to ibm/service/classicinfrastructure/resource_ibm_object_storage_account_test.go index aaef98181..2849050ad 100644 --- a/ibm/resource_ibm_object_storage_account_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_object_storage_account_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) @@ -15,11 +17,11 @@ func TestAccIBMObjectStorageAccount_Basic(t *testing.T) { var accountName string resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMObjectStorageAccountDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMObjectStorageAccountConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckIBMObjectStorageAccountExists("ibm_object_storage_account.testacc_foobar", &accountName), @@ -34,11 +36,11 @@ func TestAccIBMObjectStorageAccountWithTag(t *testing.T) { var accountName string resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMObjectStorageAccountDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMObjectStorageAccountWithTag, Check: resource.ComposeTestCheckFunc( testAccCheckIBMObjectStorageAccountExists("ibm_object_storage_account.testacc_foobar", &accountName), @@ -69,11 +71,11 @@ func testAccCheckIBMObjectStorageAccountExists(n string, accountName *string) re rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } *accountName = rs.Primary.ID @@ -86,7 +88,7 @@ func testAccCheckIBMObjectStorageAccountAttributes(accountName *string) resource return func(s *terraform.State) error { if *accountName == "" { - return fmt.Errorf("No object storage account name") + return fmt.Errorf("[ERROR] No object storage account name") } return nil diff --git a/ibm/resource_ibm_securitygroup.go b/ibm/service/classicinfrastructure/resource_ibm_securitygroup.go similarity index 79% rename from ibm/resource_ibm_securitygroup.go rename to ibm/service/classicinfrastructure/resource_ibm_securitygroup.go index 32dd96506..be897942f 100644 --- a/ibm/resource_ibm_securitygroup.go +++ b/ibm/service/classicinfrastructure/resource_ibm_securitygroup.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" @@ -15,7 +16,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMSecurityGroup() *schema.Resource { +func ResourceIBMSecurityGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMSecurityGroupCreate, Read: resourceIBMSecurityGroupRead, @@ -41,7 +42,7 @@ func resourceIBMSecurityGroup() *schema.Resource { } func resourceIBMSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess.SetRetries(0)) name := d.Get("name").(string) @@ -84,7 +85,7 @@ func resourceIBMSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er } res, err := service.CreateObject(sg) if err != nil { - return fmt.Errorf("Error creating Security Group: %s", err) + return fmt.Errorf("[ERROR] Error creating Security Group: %s", err) } d.SetId(strconv.Itoa(*res.Id)) @@ -94,7 +95,7 @@ func resourceIBMSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er } func resourceIBMSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) groupID, _ := strconv.Atoi(d.Id()) @@ -106,7 +107,7 @@ func resourceIBMSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro d.SetId("") return nil } - return fmt.Errorf("Error retrieving Security Group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Security Group: %s", err) } d.Set("name", group.Name) @@ -115,17 +116,17 @@ func resourceIBMSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro } func resourceIBMSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) groupID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } group, err := services.GetNetworkSecurityGroupService(sess).Id(groupID).GetObject() if err != nil { - return fmt.Errorf("Error retrieving Security Group: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Security Group: %s", err) } if d.HasChange("description") { @@ -137,23 +138,23 @@ func resourceIBMSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er } _, err = service.Id(groupID).EditObject(&group) if err != nil { - return fmt.Errorf("Error editing Security Group: %s", err) + return fmt.Errorf("[ERROR] Error editing Security Group: %s", err) } return resourceIBMSecurityGroupRead(d, meta) } func resourceIBMSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) groupID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } log.Printf("[INFO] Deleting Security Group: %d", groupID) _, err = service.Id(groupID).DeleteObject() if err != nil { - return fmt.Errorf("Error deleting Security Group: %s", err) + return fmt.Errorf("[ERROR] Error deleting Security Group: %s", err) } d.SetId("") @@ -161,12 +162,12 @@ func resourceIBMSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er } func resourceIBMSecurityGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) groupID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(groupID).GetObject() @@ -176,7 +177,7 @@ func resourceIBMSecurityGroupExists(d *schema.ResourceData, meta interface{}) (b return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting security group: %s", err) } return result.Id != nil && *result.Id == groupID, nil } diff --git a/ibm/resource_ibm_securitygroup_rule.go b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule.go similarity index 86% rename from ibm/resource_ibm_securitygroup_rule.go rename to ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule.go index 5f97763a1..616cb59dc 100644 --- a/ibm/resource_ibm_securitygroup_rule.go +++ b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/filter" @@ -15,7 +17,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMSecurityGroupRule() *schema.Resource { +func ResourceIBMSecurityGroupRule() *schema.Resource { return &schema.Resource{ Create: resourceIBMSecurityGroupRuleCreate, Read: resourceIBMSecurityGroupRuleRead, @@ -29,14 +31,14 @@ func resourceIBMSecurityGroupRule() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Direction of rule: ingress or egress", - ValidateFunc: validateSecurityRuleDirection, + ValidateFunc: validate.ValidateSecurityRuleDirection, }, "ether_type": { Type: schema.TypeString, Optional: true, Description: "IP version IPv4 or IPv6", Default: "IPv4", - ValidateFunc: validateSecurityRuleEtherType, + ValidateFunc: validate.ValidateSecurityRuleEtherType, }, "port_range_min": { Type: schema.TypeInt, @@ -58,14 +60,14 @@ func resourceIBMSecurityGroupRule() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"remote_group_id"}, - ValidateFunc: validateRemoteIP, + ValidateFunc: validate.ValidateRemoteIP, Description: "Remote IP Address", }, "protocol": { Type: schema.TypeString, Optional: true, Description: "icmp, tcp or udp", - ValidateFunc: validateSecurityRuleProtocol, + ValidateFunc: validate.ValidateSecurityRuleProtocol, }, "security_group_id": { Type: schema.TypeInt, @@ -107,7 +109,7 @@ func findMatchingRule(sgID int, rule *datatypes.Network_SecurityGroup_Rule, rules, err := service.Filter(filter.Build(filters...)).Id(sgID).GetRules() if err != nil { - return nil, fmt.Errorf("Error fetching information for Security Group Rule: %s", err) + return nil, fmt.Errorf("[ERROR] Error fetching information for Security Group Rule: %s", err) } log.Printf("[INFO] rules %v", rules) @@ -118,7 +120,7 @@ func findMatchingRule(sgID int, rule *datatypes.Network_SecurityGroup_Rule, } func resourceIBMSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID := d.Get("security_group_id").(int) @@ -177,7 +179,7 @@ func resourceIBMSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} log.Println("[INFO] creating security group rule") _, err = service.Id(sgID).AddRules(opts) if err != nil { - return fmt.Errorf("Error creating Security Group Rule: %s", err) + return fmt.Errorf("[ERROR] Error creating Security Group Rule: %s", err) } matchingrule, err = findMatchingRule(sgID, &sgrule, service) @@ -190,7 +192,7 @@ func resourceIBMSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} } func resourceIBMSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID := d.Get("security_group_id").(int) @@ -203,7 +205,7 @@ func resourceIBMSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error retrieving Security Group Rule: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Security Group Rule: %s", err) } if len(matchingrules) == 0 { @@ -236,13 +238,13 @@ func resourceIBMSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) } func resourceIBMSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) securityGroupID := d.Get("security_group_id").(int) matchingrules, err := service.Filter(filter.Build( filter.Path("rules.id").Eq(d.Id()))).Id(securityGroupID).GetRules() if err != nil { - return fmt.Errorf("Error retrieving Security Group Rule: %s", err) + return fmt.Errorf("[ERROR] Error retrieving Security Group Rule: %s", err) } if d.HasChange("direction") { matchingrules[0].Direction = sl.String(d.Get("direction").(string)) @@ -267,13 +269,13 @@ func resourceIBMSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface{} } _, err = service.Id(securityGroupID).EditRules([]datatypes.Network_SecurityGroup_Rule{matchingrules[0]}) if err != nil { - return fmt.Errorf("Couldn't update Security Group Rule: %s", err) + return fmt.Errorf("[ERROR] Could n't update Security Group Rule: %s", err) } return resourceIBMSecurityGroupRuleRead(d, meta) } func resourceIBMSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID := d.Get("security_group_id").(int) id, _ := strconv.Atoi(d.Id()) @@ -283,7 +285,7 @@ func resourceIBMSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{} d.SetId("") return nil } - return fmt.Errorf("Error deleting Security Group Rule: %s", err) + return fmt.Errorf("[ERROR] Error deleting Security Group Rule: %s", err) } d.SetId("") @@ -291,7 +293,7 @@ func resourceIBMSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{} } func resourceIBMSecurityGroupRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSecurityGroupService(sess) sgID := d.Get("security_group_id").(int) @@ -304,7 +306,7 @@ func resourceIBMSecurityGroupRuleExists(d *schema.ResourceData, meta interface{} d.SetId("") return false, nil } - return false, fmt.Errorf("Error retrieving Security Group Rule: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving Security Group Rule: %s", err) } if len(matchingrules) == 0 { diff --git a/ibm/resource_ibm_securitygroup_rule_test.go b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule_test.go similarity index 93% rename from ibm/resource_ibm_securitygroup_rule_test.go rename to ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule_test.go index 55bc7db52..b8bcb2312 100644 --- a/ibm/resource_ibm_securitygroup_rule_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_rule_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/services" @@ -20,8 +23,8 @@ func TestAccIBMSecurityGroupRule_basic(t *testing.T) { desc1 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSecurityGroupRuleDestroy, Steps: []resource.TestStep{ { @@ -68,8 +71,8 @@ func TestAccIBMSecurityGroupRule_with_remote_group(t *testing.T) { desc1 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSecurityGroupRuleDestroy, Steps: []resource.TestStep{ { @@ -100,8 +103,8 @@ func TestAccIBMSecurityGroupRule_with_remote_ip(t *testing.T) { desc1 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSecurityGroupRuleDestroy, Steps: []resource.TestStep{ { @@ -134,8 +137,8 @@ func TestAccIBMSecurityGroupRule_with_cross_refernce_another_security_group(t *t desc2 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSecurityGroupRuleDestroy, Steps: []resource.TestStep{ { @@ -158,7 +161,7 @@ func TestAccIBMSecurityGroupRule_with_cross_refernce_another_security_group(t *t } func testAccCheckIBMSecurityGroupRuleDestroy(s *terraform.State) error { - service := services.GetNetworkSecurityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkSecurityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_security_group_rule" { diff --git a/ibm/resource_ibm_securitygroup_test.go b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_test.go similarity index 84% rename from ibm/resource_ibm_securitygroup_test.go rename to ibm/service/classicinfrastructure/resource_ibm_securitygroup_test.go index 6952f1a02..853aa6a37 100644 --- a/ibm/resource_ibm_securitygroup_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_securitygroup_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/datatypes" @@ -26,8 +29,8 @@ func TestAccIBMSecurityGroup_basic(t *testing.T) { desc2 := fmt.Sprintf("terraformsguat_create_step_desc_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSecurityGroupDestroy, Steps: []resource.TestStep{ { @@ -56,7 +59,7 @@ func TestAccIBMSecurityGroup_basic(t *testing.T) { } func testAccCheckIBMSecurityGroupDestroy(s *terraform.State) error { - service := services.GetNetworkSecurityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkSecurityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_security_group" { @@ -81,7 +84,7 @@ func testAccCheckIBMSecurityGroupExists(n string, sg *datatypes.Network_Security rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { @@ -90,7 +93,7 @@ func testAccCheckIBMSecurityGroupExists(n string, sg *datatypes.Network_Security sgID, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkSecurityGroupService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkSecurityGroupService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundSG, err := service.Id(sgID).GetObject() if err != nil { diff --git a/ibm/resource_ibm_ssl_certificate.go b/ibm/service/classicinfrastructure/resource_ibm_ssl_certificate.go similarity index 88% rename from ibm/resource_ibm_ssl_certificate.go rename to ibm/service/classicinfrastructure/resource_ibm_ssl_certificate.go index 58267425a..70b006b0f 100644 --- a/ibm/resource_ibm_ssl_certificate.go +++ b/ibm/service/classicinfrastructure/resource_ibm_ssl_certificate.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( fmt "fmt" @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -27,7 +28,7 @@ const ( SSLMask = "id" ) -func resourceIBMSSLCertificate() *schema.Resource { +func ResourceIBMSSLCertificate() *schema.Resource { return &schema.Resource{ Create: resourceIBMSSLCertificateCreate, Read: resourceIBMSSLCertificateRead, @@ -43,7 +44,7 @@ func resourceIBMSSLCertificate() *schema.Resource { Description: "Server count", }, - "server_type": &schema.Schema{ + "server_type": { Type: schema.TypeString, Required: true, Description: "server type", @@ -61,7 +62,7 @@ func resourceIBMSSLCertificate() *schema.Resource { Description: "ssl type", }, - "certificate_signing_request": &schema.Schema{ + "certificate_signing_request": { Type: schema.TypeString, Required: true, Description: "certificate signing request info", @@ -74,7 +75,7 @@ func resourceIBMSSLCertificate() *schema.Resource { Description: "Renewal flag", }, - "order_approver_email_address": &schema.Schema{ + "order_approver_email_address": { Type: schema.TypeString, Required: true, Description: "Email address of the approver", @@ -130,51 +131,51 @@ func resourceIBMSSLCertificate() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "org_address_line1": &schema.Schema{ + "org_address_line1": { Type: schema.TypeString, Required: true, }, - "org_address_line2": &schema.Schema{ + "org_address_line2": { Type: schema.TypeString, Optional: true, }, - "org_city": &schema.Schema{ + "org_city": { Type: schema.TypeString, Required: true, }, - "org_country_code": &schema.Schema{ + "org_country_code": { Type: schema.TypeString, Required: true, }, - "org_postal_code": &schema.Schema{ + "org_postal_code": { Type: schema.TypeString, Required: true, }, - "org_state": &schema.Schema{ + "org_state": { Type: schema.TypeString, Required: true, }, }, }, }, - "org_organization_name": &schema.Schema{ + "org_organization_name": { Type: schema.TypeString, Required: true, Description: "Organization name", }, - "org_phone_number": &schema.Schema{ + "org_phone_number": { Type: schema.TypeString, Required: true, Description: "Organization phone number", }, - "org_fax_number": &schema.Schema{ + "org_fax_number": { Type: schema.TypeString, Optional: true, }, @@ -195,68 +196,68 @@ func resourceIBMSSLCertificate() *schema.Resource { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "tech_address_line1": &schema.Schema{ + "tech_address_line1": { Type: schema.TypeString, Optional: true, }, - "tech_address_line2": &schema.Schema{ + "tech_address_line2": { Type: schema.TypeString, Optional: true, }, - "tech_city": &schema.Schema{ + "tech_city": { Type: schema.TypeString, Optional: true, }, - "tech_country_code": &schema.Schema{ + "tech_country_code": { Type: schema.TypeString, Optional: true, }, - "tech_postal_code": &schema.Schema{ + "tech_postal_code": { Type: schema.TypeString, Optional: true, }, - "tech_state": &schema.Schema{ + "tech_state": { Type: schema.TypeString, Optional: true, }, }, }, }, - "tech_organization_name": &schema.Schema{ + "tech_organization_name": { Type: schema.TypeString, Required: true, }, - "tech_first_name": &schema.Schema{ + "tech_first_name": { Type: schema.TypeString, Required: true, }, - "tech_last_name": &schema.Schema{ + "tech_last_name": { Type: schema.TypeString, Required: true, }, - "tech_email_address": &schema.Schema{ + "tech_email_address": { Type: schema.TypeString, Required: true, }, - "tech_phone_number": &schema.Schema{ + "tech_phone_number": { Type: schema.TypeString, Required: true, }, - "tech_fax_number": &schema.Schema{ + "tech_fax_number": { Type: schema.TypeString, Optional: true, }, - "tech_title": &schema.Schema{ + "tech_title": { Type: schema.TypeString, Required: true, }, @@ -275,68 +276,68 @@ func resourceIBMSSLCertificate() *schema.Resource { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "billing_address_line1": &schema.Schema{ + "billing_address_line1": { Type: schema.TypeString, Optional: true, }, - "billing_address_line2": &schema.Schema{ + "billing_address_line2": { Type: schema.TypeString, Optional: true, }, - "billing_city": &schema.Schema{ + "billing_city": { Type: schema.TypeString, Optional: true, }, - "billing_country_code": &schema.Schema{ + "billing_country_code": { Type: schema.TypeString, Optional: true, }, - "billing_postal_code": &schema.Schema{ + "billing_postal_code": { Type: schema.TypeString, Optional: true, }, - "billing_state": &schema.Schema{ + "billing_state": { Type: schema.TypeString, Optional: true, }, }, }, }, - "billing_organization_name": &schema.Schema{ + "billing_organization_name": { Type: schema.TypeString, Optional: true, }, - "billing_first_name": &schema.Schema{ + "billing_first_name": { Type: schema.TypeString, Optional: true, }, - "billing_last_name": &schema.Schema{ + "billing_last_name": { Type: schema.TypeString, Optional: true, }, - "billing_email_address": &schema.Schema{ + "billing_email_address": { Type: schema.TypeString, Optional: true, }, - "billing_phone_number": &schema.Schema{ + "billing_phone_number": { Type: schema.TypeString, Optional: true, }, - "billing_fax_number": &schema.Schema{ + "billing_fax_number": { Type: schema.TypeString, Optional: true, }, - "billing_title": &schema.Schema{ + "billing_title": { Type: schema.TypeString, Optional: true, }, @@ -356,67 +357,67 @@ func resourceIBMSSLCertificate() *schema.Resource { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "admin_address_line1": &schema.Schema{ + "admin_address_line1": { Type: schema.TypeString, Optional: true, }, - "admin_address_line2": &schema.Schema{ + "admin_address_line2": { Type: schema.TypeString, Optional: true, }, - "admin_city": &schema.Schema{ + "admin_city": { Type: schema.TypeString, Optional: true, Default: "", }, - "admin_country_code": &schema.Schema{ + "admin_country_code": { Type: schema.TypeString, Optional: true, }, - "admin_postal_code": &schema.Schema{ + "admin_postal_code": { Type: schema.TypeString, Optional: true, }, - "admin_state": &schema.Schema{ + "admin_state": { Type: schema.TypeString, Optional: true, }, }, }, }, - "admin_organization_name": &schema.Schema{ + "admin_organization_name": { Type: schema.TypeString, Optional: true, }, - "admin_first_name": &schema.Schema{ + "admin_first_name": { Type: schema.TypeString, Optional: true, }, - "admin_last_name": &schema.Schema{ + "admin_last_name": { Type: schema.TypeString, Optional: true, }, - "admin_email_address": &schema.Schema{ + "admin_email_address": { Type: schema.TypeString, Optional: true, }, - "admin_phone_number": &schema.Schema{ + "admin_phone_number": { Type: schema.TypeString, Optional: true, }, - "admin_fax_number": &schema.Schema{ + "admin_fax_number": { Type: schema.TypeString, Optional: true, }, - "admin_title": &schema.Schema{ + "admin_title": { Type: schema.TypeString, Optional: true, }, @@ -427,7 +428,7 @@ func resourceIBMSSLCertificate() *schema.Resource { } } func resourceIBMSSLCertificateCreate(d *schema.ResourceData, m interface{}) error { - sess := m.(ClientSession).SoftLayerSession() + sess := m.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateRequestService(sess.SetRetries(0)) sslKeyName := sl.String(d.Get("ssl_type").(string)) pkg, err := product.GetPackageByType(sess, AdditionalServicesSSLCertificatePackageType) @@ -446,7 +447,7 @@ func resourceIBMSSLCertificateCreate(d *schema.ResourceData, m interface{}) erro } validCSR, err := service.ValidateCsr(sl.String(d.Get("certificate_signing_request").(string)), sl.Int(d.Get("validity_months").(int)), itemId, sl.String(d.Get("server_type").(string))) if err != nil { - return fmt.Errorf("Error during validation of CSR: %s", err) + return fmt.Errorf("[ERROR] Error during validation of CSR: %s", err) } if validCSR == true { productOrderContainer, err := buildSSLProductOrderContainer(d, sess, AdditionalServicesSSLCertificatePackageType) @@ -454,7 +455,7 @@ func resourceIBMSSLCertificateCreate(d *schema.ResourceData, m interface{}) erro // Find price items with AdditionalServices productOrderContainer, err = buildSSLProductOrderContainer(d, sess, AdditionalSSLServicesPackageType) if err != nil { - return fmt.Errorf("Error creating SSL certificate: %s", err) + return fmt.Errorf("[ERROR] Error creating SSL certificate: %s", err) } } log.Printf("[INFO] Creating SSL Certificate") @@ -469,7 +470,7 @@ func resourceIBMSSLCertificateCreate(d *schema.ResourceData, m interface{}) erro receipt, err := services.GetProductOrderService(sess).PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of ssl: %s", err) + return fmt.Errorf("[ERROR] Error during creation of ssl: %s", err) } ssl, err := findSSLByOrderId(sess, *receipt.OrderId) @@ -477,21 +478,21 @@ func resourceIBMSSLCertificateCreate(d *schema.ResourceData, m interface{}) erro return resourceIBMSSLCertificateRead(d, m) } else { log.Println("Provided CSR is not valid.") - return fmt.Errorf("Error while validating CSR: %s", err) + return fmt.Errorf("[ERROR] Error while validating CSR: %s", err) } } func resourceIBMSSLCertificateRead(d *schema.ResourceData, m interface{}) error { - sess := m.(ClientSession).SoftLayerSession() + sess := m.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateRequestService(sess) sslId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid SSL ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid SSL ID, must be an integer: %s", err) } ssl, err := service.Id(sslId).Mask(SSLMask).GetObject() if err != nil { - return fmt.Errorf("Error retrieving SSL: %s", err) + return fmt.Errorf("[ERROR] Error retrieving SSL: %s", err) } d.Set("certificate_signing_request", ssl.CertificateSigningRequest) return nil @@ -502,24 +503,24 @@ func resourceIBMSSLCertificateUpdate(d *schema.ResourceData, m interface{}) erro } func resourceIBMSSLCertificateDelete(d *schema.ResourceData, m interface{}) error { - sess := m.(ClientSession).SoftLayerSession() + sess := m.(conns.ClientSession).SoftLayerSession() service := services.GetSecurityCertificateService(sess) service1 := services.GetSecurityCertificateRequestService(sess) sslId, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid SSL ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid SSL ID, must be an integer: %s", err) } value, err := service1.Id(sslId).GetObject() if err != nil { - return fmt.Errorf("Not a valid Object ID: %s", err) + return fmt.Errorf("[ERROR] Not a valid Object ID: %s", err) } sslReqId := value.StatusId if *sslReqId == 49 || *sslReqId == 43 { deleteObject, err := service.Id(sslId).DeleteObject() if deleteObject == false { - return fmt.Errorf("Error deleting SSL: %s", err) + return fmt.Errorf("[ERROR] Error deleting SSL: %s", err) } else { d.SetId("") return nil @@ -527,7 +528,7 @@ func resourceIBMSSLCertificateDelete(d *schema.ResourceData, m interface{}) erro } else if *sslReqId == 50 { cancelObject, err := service1.Id(sslId).CancelSslOrder() if cancelObject == false { - return fmt.Errorf("Error deleting SSL: %s", err) + return fmt.Errorf("[ERROR] Error deleting SSL: %s", err) } else { d.SetId("") return nil @@ -787,7 +788,7 @@ func buildSSLProductOrderContainer(d *schema.ResourceData, sess *session1.Sessio if len(sslItems) == 0 { return &datatypes.Container_Product_Order_Security_Certificate{}, - fmt.Errorf("No product items matching %p could be found", sslKeyName) + fmt.Errorf("[ERROR] No product items matching %p could be found", sslKeyName) } sslContainer := datatypes.Container_Product_Order_Security_Certificate{ Container_Product_Order: datatypes.Container_Product_Order{ @@ -850,5 +851,5 @@ func findSSLByOrderId(sess *session1.Session, orderId int) (datatypes.Security_C } return datatypes.Security_Certificate_Request{}, - fmt.Errorf("Cannot find SSl with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find SSl with order id '%d'", orderId) } diff --git a/ibm/resource_ibm_ssl_certificate_test.go b/ibm/service/classicinfrastructure/resource_ibm_ssl_certificate_test.go similarity index 95% rename from ibm/resource_ibm_ssl_certificate_test.go rename to ibm/service/classicinfrastructure/resource_ibm_ssl_certificate_test.go index 074841a3a..7be131320 100644 --- a/ibm/resource_ibm_ssl_certificate_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_ssl_certificate_test.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMSSLCertificate_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccIBMSSLCertificateConfigBasic, diff --git a/ibm/resource_ibm_storage_block.go b/ibm/service/classicinfrastructure/resource_ibm_storage_block.go similarity index 88% rename from ibm/resource_ibm_storage_block.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_block.go index 03085be83..deb69d242 100644 --- a/ibm/resource_ibm_storage_block.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_block.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" "github.com/softlayer/softlayer-go/helpers/network" @@ -18,7 +20,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMStorageBlock() *schema.Resource { +func ResourceIBMStorageBlock() *schema.Resource { return &schema.Resource{ Create: resourceIBMStorageBlockCreate, Read: resourceIBMStorageBlockRead, @@ -232,12 +234,12 @@ func resourceIBMStorageBlock() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Description: "List of target Addresses", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", @@ -247,7 +249,7 @@ func resourceIBMStorageBlock() *schema.Resource { } func resourceIBMStorageBlockCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageType := d.Get("type").(string) iops := d.Get("iops").(float64) @@ -264,7 +266,7 @@ func resourceIBMStorageBlockCreate(d *schema.ResourceData, meta interface{}) err storageOrderContainer, err := buildStorageProductOrderContainer(sess, storageType, iops, capacity, snapshotCapacity, blockStorage, datacenter, hourlyBilling) if err != nil { - return fmt.Errorf("Error while creating storage:%s", err) + return fmt.Errorf("[ERROR] Error while creating storage:%s", err) } log.Println("[INFO] Creating storage") @@ -294,18 +296,18 @@ func resourceIBMStorageBlockCreate(d *schema.ResourceData, meta interface{}) err VolumeSize: &capacity, }, sl.Bool(false)) default: - return fmt.Errorf("Error during creation of storage: Invalid storageType %s", storageType) + return fmt.Errorf("[ERROR] Error during creation of storage: Invalid storageType %s", storageType) } if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } // Find the storage device blockStorage, err := findStorageByOrderId(sess, *receipt.OrderId, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *blockStorage.Id)) @@ -313,15 +315,14 @@ func resourceIBMStorageBlockCreate(d *schema.ResourceData, meta interface{}) err _, err = WaitForStorageAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for storage (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for storage (%s) to become ready: %s", d.Id(), err) } // SoftLayer changes the device ID after completion of provisioning. It is necessary to refresh device ID. blockStorage, err = findStorageByOrderId(sess, *receipt.OrderId, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *blockStorage.Id)) @@ -331,7 +332,7 @@ func resourceIBMStorageBlockCreate(d *schema.ResourceData, meta interface{}) err } func resourceIBMStorageBlockRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageId, _ := strconv.Atoi(d.Id()) storage, err := services.GetNetworkStorageService(sess). @@ -340,7 +341,7 @@ func resourceIBMStorageBlockRead(d *schema.ResourceData, meta interface{}) error GetObject() if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } storageType := strings.Fields(*storage.StorageType.Description)[0] @@ -348,7 +349,7 @@ func resourceIBMStorageBlockRead(d *schema.ResourceData, meta interface{}) error // Calculate IOPS iops, err := getIops(storage, storageType) if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } d.Set("type", storageType) @@ -430,17 +431,17 @@ func resourceIBMStorageBlockRead(d *schema.ResourceData, meta interface{}) error } d.Set("target_address", storage.IscsiTargetIpAddresses) - d.Set(ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/storage/block/%s", d.Id())) - d.Set(ResourceName, *storage.ServiceResourceName) + d.Set(flex.ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/storage/block/%s", d.Id())) + d.Set(flex.ResourceName, *storage.ServiceResourceName) return nil } func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } storage, err := services.GetNetworkStorageService(sess). @@ -449,14 +450,14 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err GetObject() if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } // Update allowed_ip_addresses if d.HasChange("allowed_ip_addresses") { err := updateAllowedIpAddresses(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -464,7 +465,7 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("allowed_subnets") { err := updateAllowedSubnets(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -472,7 +473,7 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("allowed_virtual_guest_ids") { err := updateAllowedVirtualGuestIds(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -480,7 +481,7 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("allowed_hardware_ids") { err := updateAllowedHardwareIds(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -488,7 +489,7 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("notes") { err := updateNotes(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -498,7 +499,7 @@ func resourceIBMStorageBlockUpdate(d *schema.ResourceData, meta interface{}) err modifyOrder, err := prepareModifyOrder(sess, storage, iops, size) if err != nil { - return fmt.Errorf("Error updating storage: %s", err) + return fmt.Errorf("[ERROR] Error updating storage: %s", err) } _, err = services.GetProductOrderService(sess.SetRetries(0)).PlaceOrder( diff --git a/ibm/resource_ibm_storage_block_test.go b/ibm/service/classicinfrastructure/resource_ibm_storage_block_test.go similarity index 95% rename from ibm/resource_ibm_storage_block_test.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_block_test.go index 8d031ec76..3dcf447f9 100644 --- a/ibm/resource_ibm_storage_block_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_block_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/services" @@ -16,10 +19,10 @@ import ( func TestAccIBMStorageBlock_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockConfig_basic, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -60,7 +63,7 @@ func TestAccIBMStorageBlock_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockConfig_update, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -81,10 +84,10 @@ func TestAccIBMStorageBlock_Basic(t *testing.T) { func TestAccIBMStorageBlockwithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockWithTag, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -108,7 +111,7 @@ func TestAccIBMStorageBlockwithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockWithUpdatedTag, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -124,10 +127,10 @@ func TestAccIBMStorageBlockwithTag(t *testing.T) { func TestAccIBMStorageBlock_hourly(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockConfig_hourly, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -172,7 +175,7 @@ func TestAccIBMStorageBlock_hourly(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageBlockConfig_hourly_update, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -191,16 +194,16 @@ func testAccCheckIBMStorageBlockExists(n string) resource.TestCheckFunc { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } storageId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkStorageService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkStorageService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundStorage, err := service.Id(storageId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_storage_evault.go b/ibm/service/classicinfrastructure/resource_ibm_storage_evault.go similarity index 82% rename from ibm/resource_ibm_storage_evault.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_evault.go index 55eec5775..122b65961 100644 --- a/ibm/resource_ibm_storage_evault.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_evault.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "fmt" @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -20,7 +21,7 @@ import ( "github.com/softlayer/softlayer-go/sl" ) -func resourceIBMStorageEvault() *schema.Resource { +func ResourceIBMStorageEvault() *schema.Resource { return &schema.Resource{ Create: resourceIBMStorageEvaultCreate, Read: resourceIBMStorageEvaultRead, @@ -93,12 +94,12 @@ const ( ) func resourceIBMStorageEvaultCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Find price items productOrderContainer, err := buildEvaultProductOrderContainer(d, sess) if err != nil { - return fmt.Errorf("Error creating evault: %s", err) + return fmt.Errorf("[ERROR] Error creating evault: %s", err) } log.Println("[INFO] Creating Evault") @@ -106,12 +107,12 @@ func resourceIBMStorageEvaultCreate(d *schema.ResourceData, meta interface{}) er receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of evault: %s", err) + return fmt.Errorf("[ERROR] Error during creation of evault: %s", err) } evaultStorage, err := findEvaultStorageByOrderID(d, meta, *receipt.OrderId) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *evaultStorage.Id)) @@ -120,15 +121,14 @@ func resourceIBMStorageEvaultCreate(d *schema.ResourceData, meta interface{}) er _, err = WaitForEvaultAvailable(d, meta, schema.TimeoutCreate) if err != nil { - return fmt.Errorf( - "Error waiting for evault (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for evault (%s) to become ready: %s", d.Id(), err) } // SoftLayer changes the device ID after completion of provisioning. It is necessary to refresh device ID. evaultStorage, err = findEvaultStorageByOrderID(d, meta, *receipt.OrderId) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *evaultStorage.Id)) @@ -152,7 +152,7 @@ func buildEvaultProductOrderContainer(d *schema.ResourceData, sess *session.Sess } if virtualID == 0 && hardwareID == 0 { - return &datatypes.Container_Product_Order{}, fmt.Errorf("Provide either `virtual_instance_id` or `hardware_instance_id`") + return &datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] Provide either `virtual_instance_id` or `hardware_instance_id`") } /*pkg, err := product.GetPackageByType(sess, "ADDITIONAL_PRODUCTS") @@ -169,7 +169,7 @@ func buildEvaultProductOrderContainer(d *schema.ResourceData, sess *session.Sess dc, err := location.GetDatacenterByName(sess, datacenter) if err != nil { return &datatypes.Container_Product_Order{}, - fmt.Errorf("No data centers matching %s could be found", datacenter) + fmt.Errorf("[ERROR] No data centers matching %s could be found", datacenter) } locationservice := services.GetLocationService(sess) @@ -189,7 +189,7 @@ func buildEvaultProductOrderContainer(d *schema.ResourceData, sess *session.Sess priceItems := []datatypes.Product_Item_Price{} actualpriceid, err := product.GetPriceIDByPackageIdandLocationGroups(sess, listofpriceids, 0, description) if err != nil || actualpriceid == 0 { - return &datatypes.Container_Product_Order{}, fmt.Errorf("The evault with the given capacity is not available for the datacenter you have selected. Please enter a different capacity : %s", err) + return &datatypes.Container_Product_Order{}, fmt.Errorf("[ERROR] The evault with the given capacity is not available for the datacenter you have selected. Please enter a different capacity : %s", err) } priceItem := datatypes.Product_Item_Price{ Id: &actualpriceid, @@ -223,7 +223,7 @@ func buildEvaultProductOrderContainer(d *schema.ResourceData, sess *session.Sess } func resourceIBMStorageEvaultRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() evaultID, _ := strconv.Atoi(d.Id()) @@ -232,7 +232,7 @@ func resourceIBMStorageEvaultRead(d *schema.ResourceData, meta interface{}) erro GetObject() if err != nil { - return fmt.Errorf("Error retrieving evault information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving evault information: %s", err) } d.Set("capacity", evault.CapacityGb) @@ -256,11 +256,11 @@ func resourceIBMStorageEvaultRead(d *schema.ResourceData, meta interface{}) erro func resourceIBMStorageEvaultUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("capacity") && !d.IsNewResource() { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() evaultID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } priceID, err := getEvaultUpgradePriceItem(d, sess) @@ -290,7 +290,7 @@ func resourceIBMStorageEvaultUpdate(d *schema.ResourceData, meta interface{}) er } func resourceIBMStorageEvaultDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() evaultService := services.GetNetworkStorageBackupEvaultService(sess) evaultID, _ := strconv.Atoi(d.Id()) @@ -298,11 +298,11 @@ func resourceIBMStorageEvaultDelete(d *schema.ResourceData, meta interface{}) er billingItem, err := evaultService.Id(evaultID).GetBillingItem() if err != nil { - return fmt.Errorf("Error while looking up billing item associated with the evault: %s", err) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the evault: %s", err) } if billingItem.Id == nil { - return fmt.Errorf("Error while looking up billing item associated with the evault: No billing item for ID:%d", evaultID) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the evault: No billing item for ID:%d", evaultID) } success, err := services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() @@ -318,7 +318,7 @@ func resourceIBMStorageEvaultDelete(d *schema.ResourceData, meta interface{}) er func findEvaultStorageByOrderID(d *schema.ResourceData, meta interface{}, orderId int) (datatypes.Network_Storage, error) { filterPath := "evaultNetworkStorage.billingItem.orderItem.order.id" - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, @@ -339,7 +339,7 @@ func findEvaultStorageByOrderID(d *schema.ResourceData, meta interface{}, orderI } else if len(storages) == 0 { return datatypes.Network_Storage{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one evault: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one evault: %s", err) } }, @@ -362,7 +362,7 @@ func findEvaultStorageByOrderID(d *schema.ResourceData, meta interface{}, orderI } return datatypes.Network_Storage{}, - fmt.Errorf("Cannot find evault with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find evault with order id '%d'", orderId) } // Waits for storage provisioning @@ -370,9 +370,9 @@ func WaitForEvaultAvailable(d *schema.ResourceData, meta interface{}, timeout st log.Printf("Waiting for evault (%s) to be available.", d.Id()) id, err := strconv.Atoi(d.Id()) if err != nil { - return nil, fmt.Errorf("The evault ID %s must be numeric", d.Id()) + return nil, fmt.Errorf("[ERROR] The evault ID %s must be numeric", d.Id()) } - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"retry", "provisioning"}, Target: []string{"available"}, @@ -382,7 +382,7 @@ func WaitForEvaultAvailable(d *schema.ResourceData, meta interface{}, timeout st result, err := service.Id(id).Mask("activeTransactionCount").GetObject() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving evault: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving evault: %s", err) } return false, "retry", nil } @@ -403,11 +403,11 @@ func WaitForEvaultAvailable(d *schema.ResourceData, meta interface{}, timeout st } func resourceIBMStorageEvaultExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() evaultID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = services.GetNetworkStorageBackupEvaultService(sess). @@ -418,7 +418,7 @@ func resourceIBMStorageEvaultExists(d *schema.ResourceData, meta interface{}) (b if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving evault information: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving evault information: %s", err) } return true, nil } @@ -431,7 +431,7 @@ func getEvaultUpgradePriceItem(d *schema.ResourceData, sess *session.Session) (i GetObject() if err != nil { - return 0, fmt.Errorf("Error retrieving evault information: %s", err) + return 0, fmt.Errorf("[ERROR] Error retrieving evault information: %s", err) } capacity := d.Get("capacity") @@ -447,6 +447,6 @@ func getEvaultUpgradePriceItem(d *schema.ResourceData, sess *session.Session) (i validCapacities[i] = int(*item.Capacity) } - return 0, fmt.Errorf("The given capacity is not a valid upgrade value. Valid capacity upgrades are: %d", validCapacities) + return 0, fmt.Errorf("[ERROR] The given capacity is not a valid upgrade value. Valid capacity upgrades are: %d", validCapacities) } diff --git a/ibm/resource_ibm_storage_evault_test.go b/ibm/service/classicinfrastructure/resource_ibm_storage_evault_test.go similarity index 89% rename from ibm/resource_ibm_storage_evault_test.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_evault_test.go index c72b6e757..7fcb38f8b 100644 --- a/ibm/resource_ibm_storage_evault_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_evault_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,10 +22,10 @@ func TestAccIBMStorageEvault_Basic(t *testing.T) { domain := "terraformuat.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageEvaultConfigBasic(hostname, domain), Check: resource.ComposeTestCheckFunc( testAccCheckIBMStorageEvaultExists("ibm_storage_evault.evault"), @@ -34,7 +37,7 @@ func TestAccIBMStorageEvault_Basic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_storage_evault.evault", "username"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageEvaultConfigUpdate(hostname, domain), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -54,10 +57,10 @@ func TestAccIBMStorageEvault_Import(t *testing.T) { domain := "terraformuat.ibm.com" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageEvaultConfigImport(hostname, domain), Check: resource.ComposeTestCheckFunc( testAccCheckIBMStorageEvaultExists("ibm_storage_evault.evault"), @@ -70,7 +73,7 @@ func TestAccIBMStorageEvault_Import(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_storage_evault.evault", "password"), ), }, - resource.TestStep{ + { ResourceName: "ibm_storage_evault.evault", ImportState: true, ImportStateVerify: true, @@ -84,11 +87,11 @@ func testAccCheckIBMStorageEvaultExists(n string) resource.TestCheckFunc { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } evaultID, err := strconv.Atoi(rs.Primary.ID) @@ -96,7 +99,7 @@ func testAccCheckIBMStorageEvaultExists(n string) resource.TestCheckFunc { return err } - service := services.GetNetworkStorageBackupEvaultService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkStorageBackupEvaultService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundEvault, err := service.Id(evaultID).GetObject() if err != nil { diff --git a/ibm/resource_ibm_storage_file.go b/ibm/service/classicinfrastructure/resource_ibm_storage_file.go similarity index 88% rename from ibm/resource_ibm_storage_file.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_file.go index d3dddf688..31ed4c65a 100644 --- a/ibm/resource_ibm_storage_file.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_file.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "bytes" @@ -12,7 +12,9 @@ import ( "strings" "time" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -65,7 +67,7 @@ var ( } ) -func resourceIBMStorageFile() *schema.Resource { +func ResourceIBMStorageFile() *schema.Resource { return &schema.Resource{ Create: resourceIBMStorageFileCreate, Read: resourceIBMStorageFileRead, @@ -86,7 +88,7 @@ func resourceIBMStorageFile() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateStorageType, + ValidateFunc: validate.ValidateStorageType, Description: "Storage type", }, @@ -179,7 +181,7 @@ func resourceIBMStorageFile() *schema.Resource { "schedule_type": { Type: schema.TypeString, Required: true, - ValidateFunc: validateScheduleType, + ValidateFunc: validate.ValidateScheduleType, Description: "schedule type", }, @@ -192,21 +194,21 @@ func resourceIBMStorageFile() *schema.Resource { "minute": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validateMinute(0, 59), + ValidateFunc: validate.ValidateMinute(0, 59), Description: "Time duration in minutes", }, "hour": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validateHour(0, 23), + ValidateFunc: validate.ValidateHour(0, 23), Description: "Time duration in hour", }, "day_of_week": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateDayOfWeek, + ValidateFunc: validate.ValidateDayOfWeek, Description: "Day of the week", }, @@ -237,17 +239,17 @@ func resourceIBMStorageFile() *schema.Resource { ForceNew: true, Description: "Hourly based billing type", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", @@ -257,7 +259,7 @@ func resourceIBMStorageFile() *schema.Resource { } func resourceIBMStorageFileCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageType := d.Get("type").(string) iops := d.Get("iops").(float64) @@ -273,7 +275,7 @@ func resourceIBMStorageFileCreate(d *schema.ResourceData, meta interface{}) erro storageOrderContainer, err = buildStorageProductOrderContainer(sess, storageType, iops, capacity, snapshotCapacity, fileStorage, datacenter, hourlyBilling) if err != nil { - return fmt.Errorf("Error while creating storage:%s", err) + return fmt.Errorf("[ERROR] Error while creating storage:%s", err) } log.Println("[INFO] Creating storage") @@ -296,18 +298,18 @@ func resourceIBMStorageFileCreate(d *schema.ResourceData, meta interface{}) erro }, sl.Bool(false)) default: - return fmt.Errorf("Error during creation of storage: Invalid storageType %s", storageType) + return fmt.Errorf("[ERROR] Error during creation of storage: Invalid storageType %s", storageType) } if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } // Find the storage device fileStorage, err := findStorageByOrderId(sess, *receipt.OrderId, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *fileStorage.Id)) @@ -315,15 +317,14 @@ func resourceIBMStorageFileCreate(d *schema.ResourceData, meta interface{}) erro _, err = WaitForStorageAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for storage (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for storage (%s) to become ready: %s", d.Id(), err) } // SoftLayer changes the device ID after completion of provisioning. It is necessary to refresh device ID. fileStorage, err = findStorageByOrderId(sess, *receipt.OrderId, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("Error during creation of storage: %s", err) + return fmt.Errorf("[ERROR] Error during creation of storage: %s", err) } d.SetId(fmt.Sprintf("%d", *fileStorage.Id)) @@ -333,7 +334,7 @@ func resourceIBMStorageFileCreate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMStorageFileRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageId, _ := strconv.Atoi(d.Id()) @@ -343,18 +344,18 @@ func resourceIBMStorageFileRead(d *schema.ResourceData, meta interface{}) error GetObject() if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } storageType, err := getStorageTypeFromKeyName(*storage.StorageType.KeyName) if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } // Calculate IOPS iops, err := getIops(storage, storageType) if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } d.Set("iops", iops) @@ -411,7 +412,7 @@ func resourceIBMStorageFileRead(d *schema.ResourceData, meta interface{}) error mountpoint, err := services.GetNetworkStorageService(sess).Id(storageId).GetFileNetworkMountAddress() if err != nil { - return fmt.Errorf("Error retrieving storage information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } d.Set("mountpoint", mountpoint) @@ -446,20 +447,20 @@ func resourceIBMStorageFileRead(d *schema.ResourceData, meta interface{}) error schds[i] = s } d.Set("snapshot_schedule", schds) - d.Set(ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/storage/file/%s", d.Id())) + d.Set(flex.ResourceControllerURL, fmt.Sprintf("https://cloud.ibm.com/classic/storage/file/%s", d.Id())) - d.Set(ResourceName, *storage.ServiceResourceName) + d.Set(flex.ResourceName, *storage.ServiceResourceName) - d.Set(ResourceStatus, *storage.VolumeStatus) + d.Set(flex.ResourceStatus, *storage.VolumeStatus) return nil } func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() id, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } storage, err := services.GetNetworkStorageService(sess). @@ -468,14 +469,14 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro GetObject() if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } // Update allowed_ip_addresses if d.HasChange("allowed_ip_addresses") { err := updateAllowedIpAddresses(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -483,7 +484,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("allowed_subnets") { err := updateAllowedSubnets(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -491,7 +492,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("allowed_virtual_guest_ids") { err := updateAllowedVirtualGuestIds(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -499,7 +500,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("allowed_hardware_ids") { err := updateAllowedHardwareIds(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -507,7 +508,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("notes") { err := updateNotes(d, sess, storage) if err != nil { - return fmt.Errorf("Error updating storage information: %s", err) + return fmt.Errorf("[ERROR] Error updating storage information: %s", err) } } @@ -515,7 +516,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("snapshot_schedule") { err := enableStorageSnapshot(d, sess, storage) if err != nil { - return fmt.Errorf("Error creating storage snapshot schedule: %s", err) + return fmt.Errorf("[ERROR] Error creating storage snapshot schedule: %s", err) } } @@ -525,7 +526,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro modifyOrder, err := prepareModifyOrder(sess, storage, iops, size) if err != nil { - return fmt.Errorf("Error updating storage: %s", err) + return fmt.Errorf("[ERROR] Error updating storage: %s", err) } _, err = services.GetProductOrderService(sess.SetRetries(0)).PlaceOrder( @@ -548,7 +549,7 @@ func resourceIBMStorageFileUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceIBMStorageFileDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageService := services.GetNetworkStorageService(sess) storageID, _ := strconv.Atoi(d.Id()) @@ -556,11 +557,11 @@ func resourceIBMStorageFileDelete(d *schema.ResourceData, meta interface{}) erro billingItem, err := storageService.Id(storageID).GetBillingItem() if err != nil { - return fmt.Errorf("Error while looking up billing item associated with the storage: %s", err) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the storage: %s", err) } if billingItem.Id == nil { - return fmt.Errorf("Error while looking up billing item associated with the storage: No billing item for ID:%d", storageID) + return fmt.Errorf("[ERROR] Error while looking up billing item associated with the storage: No billing item for ID:%d", storageID) } success, err := services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() @@ -575,11 +576,11 @@ func resourceIBMStorageFileDelete(d *schema.ResourceData, meta interface{}) erro } func resourceIBMStorageFileExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() storageID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } _, err = services.GetNetworkStorageService(sess). @@ -590,7 +591,7 @@ func resourceIBMStorageFileExists(d *schema.ResourceData, meta interface{}) (boo if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving storage information: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } return true, nil } @@ -684,7 +685,7 @@ func buildStorageProductOrderContainer( dc, err := location.GetDatacenterByName(sess, datacenter) if err != nil { return datatypes.Container_Product_Order{}, - fmt.Errorf("No data centers matching %s could be found", datacenter) + fmt.Errorf("[ERROR] No data centers matching %s could be found", datacenter) } productOrderContainer := datatypes.Container_Product_Order{ @@ -720,7 +721,7 @@ func findStorageByOrderId(sess *session.Session, orderId int, timeout time.Durat } else if len(storage) == 0 { return datatypes.Network_Storage{}, "pending", nil } else { - return nil, "", fmt.Errorf("Expected one Storage: %s", err) + return nil, "", fmt.Errorf("[ERROR] Expected one Storage: %s", err) } }, Timeout: timeout, @@ -742,7 +743,7 @@ func findStorageByOrderId(sess *session.Session, orderId int, timeout time.Durat } return datatypes.Network_Storage{}, - fmt.Errorf("Cannot find Storage with order id '%d'", orderId) + fmt.Errorf("[ERROR] Cannot find Storage with order id '%d'", orderId) } // Waits for storage provisioning @@ -750,9 +751,9 @@ func WaitForStorageAvailable(d *schema.ResourceData, meta interface{}) (interfac log.Printf("Waiting for storage (%s) to be available.", d.Id()) id, err := strconv.Atoi(d.Id()) if err != nil { - return nil, fmt.Errorf("The storage ID %s must be numeric", d.Id()) + return nil, fmt.Errorf("[ERROR] The storage ID %s must be numeric", d.Id()) } - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"retry", "provisioning"}, Target: []string{"available"}, @@ -762,7 +763,7 @@ func WaitForStorageAvailable(d *schema.ResourceData, meta interface{}) (interfac result, err := service.Id(id).Mask("activeTransactionCount").GetObject() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving storage: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving storage: %s", err) } return false, "retry", nil } @@ -819,7 +820,7 @@ func getIops(storage datatypes.Network_Storage, storageType string) (float64, er } case performanceType: if storage.Iops == nil { - return 0, fmt.Errorf("Failed to retrieve iops information.") + return 0, fmt.Errorf("[ERROR] Failed to retrieve iops information") } iops, err := strconv.Atoi(*storage.Iops) if err != nil { @@ -827,7 +828,7 @@ func getIops(storage datatypes.Network_Storage, storageType string) (float64, er } return float64(iops), nil } - return 0, fmt.Errorf("Invalid storage type %s", storageType) + return 0, fmt.Errorf("[ERROR] Invalid storage type %s", storageType) } func updateAllowedIpAddresses(d *schema.ResourceData, sess *session.Session, storage datatypes.Network_Storage) error { @@ -852,7 +853,7 @@ func updateAllowedIpAddresses(d *schema.ResourceData, sess *session.Session, sto return err } if len(ipObject) != 1 { - return fmt.Errorf("Number of IP address is %d", len(ipObject)) + return fmt.Errorf("[ERROR] Number of IP address is %d", len(ipObject)) } for { _, err = services.GetNetworkStorageService(sess). @@ -935,7 +936,7 @@ func updateAllowedSubnets(d *schema.ResourceData, sess *session.Session, storage return err } if len(subnetObject) != 1 { - return fmt.Errorf("Number of subnet is %d", len(subnetObject)) + return fmt.Errorf("[ERROR] Number of subnet is %d", len(subnetObject)) } _, err = services.GetNetworkStorageService(sess). Id(id). @@ -1139,7 +1140,7 @@ func updateNotes(d *schema.ResourceData, sess *session.Session, storage datatype Id(id). EditObject(&datatypes.Network_Storage{Notes: sl.String(notes)}) if err != nil { - return fmt.Errorf("Error adding note to storage (%d): %s", id, err) + return fmt.Errorf("[ERROR] Error adding note to storage (%d): %s", id, err) } } @@ -1153,7 +1154,7 @@ func getStorageTypeFromKeyName(key string) (string, error) { case "PERFORMANCE_FILE_STORAGE", "PERFORMANCE_BLOCK_STORAGE": return performanceType, nil } - return "", fmt.Errorf("Couldn't find storage type for key %s", key) + return "", fmt.Errorf("[ERROR] Could n't find storage type for key %s", key) } func resourceIBMFilSnapshotHash(v interface{}) int { @@ -1172,7 +1173,7 @@ func resourceIBMFilSnapshotHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%d-", m["retention_count"].(int))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func getPrice(prices []datatypes.Product_Item_Price, category, restrictionType string, restrictionValue int) datatypes.Product_Item_Price { @@ -1209,7 +1210,7 @@ func getPriceByCategory(productItems []datatypes.Product_Item, priceCategory str } return datatypes.Product_Item_Price{}, - fmt.Errorf("No product items matching with category %s could be found", priceCategory) + fmt.Errorf("[ERROR] No product items matching with category %s could be found", priceCategory) } func getSaaSPerformSpacePrice(productItems []datatypes.Product_Item, size int) (datatypes.Product_Item_Price, error) { @@ -1244,7 +1245,7 @@ func getSaaSPerformSpacePrice(productItems []datatypes.Product_Item, size int) ( } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find price for performance storage space") + fmt.Errorf("[ERROR] Could not find price for performance storage space") } @@ -1276,7 +1277,7 @@ func getSaaSPerformIOPSPrice(productItems []datatypes.Product_Item, size, iops i } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find price for iops for the given volume") + fmt.Errorf("[ERROR] Could not find price for iops for the given volume") } @@ -1317,7 +1318,7 @@ func getSaaSEnduranceSpacePrice(productItems []datatypes.Product_Item, size int, } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find price for endurance storage space") + fmt.Errorf("[ERROR] Could not find price for endurance storage space") } @@ -1343,7 +1344,7 @@ func getSaaSEnduranceTierPrice(productItems []datatypes.Product_Item, iops float } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find price for endurance tier level") + fmt.Errorf("[ERROR] Could not find price for endurance tier level") } @@ -1374,14 +1375,14 @@ func getSaaSSnapshotSpacePrice(productItems []datatypes.Product_Item, size int, } return datatypes.Product_Item_Price{}, - fmt.Errorf("Could not find price for snapshot space") + fmt.Errorf("[ERROR] Could not find price for snapshot space") } func prepareModifyOrder(sess *session.Session, originalVolume datatypes.Network_Storage, newIops float64, newSize int) (datatypes.Container_Product_Order_Network_Storage_AsAService, error) { // Verify that the origin volume has not been cancelled if originalVolume.BillingItem == nil { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("The volume has been cancelled; unable to modify volume.") + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] The volume has been cancelled; unable to modify volume") } // Get the appropriate package for the order ('storage_as_a_service' is currently used for modifying volumes) @@ -1406,22 +1407,22 @@ func prepareModifyOrder(sess *session.Session, originalVolume datatypes.Network_ if strings.Contains(volumeStorageType, "PERFORMANCE") { volumeIsPerformance = true if newSize == 0 && newIops == 0 { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("A size or IOPS value must be given to modify this performance volume.") + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] A size or IOPS value must be given to modify this performance volume") } if newSize == 0 { newSize = *originalVolume.CapacityGb } else if newIops == 0 { storageType, err := getStorageTypeFromKeyName(*originalVolume.StorageType.KeyName) if err != nil { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("Error retrieving storage information: %s", err) + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } iops, err := getIops(originalVolume, storageType) if err != nil { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("Error retrieving storage information: %s", err) + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } newIops = iops if newIops <= 0 { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("Cannot find volume's provisioned IOPS.") + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] Cannot find volume's provisioned IOPS") } } @@ -1447,7 +1448,7 @@ func prepareModifyOrder(sess *session.Session, originalVolume datatypes.Network_ } else if strings.Contains(volumeStorageType, "ENDURANCE") { volumeIsPerformance = false if newSize == 0 && newIops == 0 { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("A size or IOPS value must be given to modify this performance volume.") + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] A size or IOPS value must be given to modify this performance volume") } if newSize == 0 { newSize = *originalVolume.CapacityGb @@ -1476,7 +1477,7 @@ func prepareModifyOrder(sess *session.Session, originalVolume datatypes.Network_ targetItemPrices = append(targetItemPrices, price) } else { - return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("Volume does not have a valid storage type (with an appropriate keyName to indicate the volume is a PERFORMANCE or an ENDURANCE volume).") + return datatypes.Container_Product_Order_Network_Storage_AsAService{}, fmt.Errorf("[ERROR] Volume does not have a valid storage type (with an appropriate keyName to indicate the volume is a PERFORMANCE or an ENDURANCE volume)") } modifyOrder := datatypes.Container_Product_Order_Network_Storage_AsAService{ @@ -1508,7 +1509,7 @@ func findEnduranceTierIopsPerGb(originalVolume datatypes.Network_Storage) (iopsP } else if tier == "10_IOPS_PER_GB" { iopsPerGB = 10 } else { - return iopsPerGB, fmt.Errorf("Could not find tier IOPS per GB for this volume") + return iopsPerGB, fmt.Errorf("[ERROR] Could not find tier IOPS per GB for this volume") } return iopsPerGB, nil @@ -1520,11 +1521,11 @@ func WaitForStorageUpdate(d *schema.ResourceData, meta interface{}) (interface{} log.Printf("Waiting for storage (%s) to be updated.", d.Id()) id, err := strconv.Atoi(d.Id()) if err != nil { - return nil, fmt.Errorf("The storage ID %s must be numeric", d.Id()) + return nil, fmt.Errorf("[ERROR] The storage ID %s must be numeric", d.Id()) } size := d.Get("capacity").(int) iops := d.Get("iops").(float64) - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() stateConf := &resource.StateChangeConf{ Pending: []string{"provisioning"}, Target: []string{"available"}, @@ -1533,17 +1534,17 @@ func WaitForStorageUpdate(d *schema.ResourceData, meta interface{}) (interface{} result, err := service.Id(id).Mask(storageDetailMask).GetObject() if err != nil { if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { - return nil, "", fmt.Errorf("Error retrieving storage: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving storage: %s", err) } return result, "provisioning", nil } storageType, err := getStorageTypeFromKeyName(*result.StorageType.KeyName) if err != nil { - return nil, "", fmt.Errorf("Error retrieving storage information: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } temp, err := getIops(result, storageType) if err != nil { - return nil, "", fmt.Errorf("Error retrieving storage information: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving storage information: %s", err) } if *result.CapacityGb == size && iops == float64(temp) { return result, "available", nil diff --git a/ibm/resource_ibm_storage_file_test.go b/ibm/service/classicinfrastructure/resource_ibm_storage_file_test.go similarity index 94% rename from ibm/resource_ibm_storage_file_test.go rename to ibm/service/classicinfrastructure/resource_ibm_storage_file_test.go index 610955d94..c5e771b5c 100644 --- a/ibm/resource_ibm_storage_file_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_storage_file_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/services" @@ -17,10 +20,10 @@ import ( func TestAccIBMStorageFile_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageFileConfig_basic, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -51,7 +54,7 @@ func TestAccIBMStorageFile_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageFileConfig_update, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -65,7 +68,7 @@ func TestAccIBMStorageFile_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageFileConfig_enablesnapshot, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_storage_file.fs_endurance", "mountpoint"), @@ -73,7 +76,7 @@ func TestAccIBMStorageFile_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_storage_file.fs_endurance", "snapshot_schedule.#", "3"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageFileConfig_updatesnapshot, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_storage_file.fs_endurance", "mountpoint"), @@ -87,10 +90,10 @@ func TestAccIBMStorageFile_Basic(t *testing.T) { func TestAccIBMStorageFile_With_Hourly(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageFileConfigWithHourlyBilling, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -129,10 +132,10 @@ func TestAccIBMStorageFile_With_Hourly(t *testing.T) { func TestAccIBMStorageFileWithTag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageFileWithTag, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -153,7 +156,7 @@ func TestAccIBMStorageFileWithTag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMStorageFileWithUpdatedTag, Check: resource.ComposeTestCheckFunc( // Endurance Storage @@ -167,10 +170,10 @@ func TestAccIBMStorageFileWithTag(t *testing.T) { func TestAccIBMStorageTypeNASFTP(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMStorageNas_Ftp, ExpectError: regexp.MustCompile("contains an invalid storage type"), }, @@ -183,16 +186,16 @@ func testAccCheckIBMStorageFileExists(n string) resource.TestCheckFunc { rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("[ERROR] Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Record ID is set") + return fmt.Errorf("[ERROR] No Record ID is set") } storageId, _ := strconv.Atoi(rs.Primary.ID) - service := services.GetNetworkStorageService(testAccProvider.Meta().(ClientSession).SoftLayerSession()) + service := services.GetNetworkStorageService(acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession()) foundStorage, err := service.Id(storageId).GetObject() if err != nil { diff --git a/ibm/resource_ibm_subnet.go b/ibm/service/classicinfrastructure/resource_ibm_subnet.go similarity index 85% rename from ibm/resource_ibm_subnet.go rename to ibm/service/classicinfrastructure/resource_ibm_subnet.go index c8f2ba79f..4a1920462 100644 --- a/ibm/resource_ibm_subnet.go +++ b/ibm/service/classicinfrastructure/resource_ibm_subnet.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure import ( "errors" @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/softlayer/softlayer-go/datatypes" @@ -34,7 +35,7 @@ var ( } ) -func resourceIBMSubnet() *schema.Resource { +func ResourceIBMSubnet() *schema.Resource { return &schema.Resource{ Create: resourceIBMSubnetCreate, Read: resourceIBMSubnetRead, @@ -115,13 +116,13 @@ func resourceIBMSubnet() *schema.Resource { }, // Provides IP address/cidr format (ex. 10.10.10.10/28) - "subnet_cidr": &schema.Schema{ + "subnet_cidr": { Type: schema.TypeString, Computed: true, Description: "CIDR notation for the subnet", }, - "notes": &schema.Schema{ + "notes": { Type: schema.TypeString, Optional: true, Description: "Notes", @@ -139,12 +140,12 @@ func resourceIBMSubnet() *schema.Resource { } func resourceIBMSubnetCreate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() // Find price items with AdditionalServicesSubnetAddresses productOrderContainer, err := buildSubnetProductOrderContainer(d, sess) if err != nil { - return fmt.Errorf("Error creating subnet: %s", err) + return fmt.Errorf("[ERROR] Error creating subnet: %s", err) } log.Println("[INFO] Creating subnet") @@ -152,12 +153,12 @@ func resourceIBMSubnetCreate(d *schema.ResourceData, meta interface{}) error { receipt, err := services.GetProductOrderService(sess.SetRetries(0)). PlaceOrder(productOrderContainer, sl.Bool(false)) if err != nil { - return fmt.Errorf("Error during creation of subnet: %s", err) + return fmt.Errorf("[ERROR] Error during creation of subnet: %s", err) } Subnet, err := findSubnetByOrderID(sess, *receipt.OrderId, d) if err != nil { - return fmt.Errorf("Error during creation of subnet: %s", err) + return fmt.Errorf("[ERROR] Error during creation of subnet: %s", err) } d.SetId(fmt.Sprintf("%d", *Subnet.Id)) @@ -166,17 +167,17 @@ func resourceIBMSubnetCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMSubnetRead(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetService(sess) subnetID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid subnet ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid subnet ID, must be an integer: %s", err) } subnet, err := service.Id(subnetID).Mask(SubnetMask).GetObject() if err != nil { - return fmt.Errorf("Error retrieving a subnet: %s", err) + return fmt.Errorf("[ERROR] Error retrieving a subnet: %s", err) } if *subnet.AddressSpace == "PRIVATE" { @@ -186,14 +187,14 @@ func resourceIBMSubnetRead(d *schema.ResourceData, meta interface{}) error { } if subnet.SubnetType == nil { - return fmt.Errorf("Invalid vlan type: the subnet type is null") + return fmt.Errorf("[ERROR] Invalid vlan type: the subnet type is null") } if strings.Contains(*subnet.SubnetType, "STATIC") { d.Set("type", "Static") } else if strings.Contains(*subnet.SubnetType, "VLAN") { d.Set("type", "Portable") } else { - return fmt.Errorf("Invalid vlan type: %s", *subnet.SubnetType) + return fmt.Errorf("[ERROR] Invalid vlan type: %s", *subnet.SubnetType) } d.Set("ip_version", *subnet.Version) d.Set("capacity", *subnet.TotalIpAddresses) @@ -216,35 +217,35 @@ func resourceIBMSubnetRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMSubnetUpdate(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetService(sess) subnetID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid subnet ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid subnet ID, must be an integer: %s", err) } if d.HasChange("notes") { _, err = service.Id(subnetID).EditNote(sl.String(d.Get("notes").(string))) if err != nil { - return fmt.Errorf("Error updating subnet: %s", err) + return fmt.Errorf("[ERROR] Error updating subnet: %s", err) } } return resourceIBMSubnetRead(d, meta) } func resourceIBMSubnetDelete(d *schema.ResourceData, meta interface{}) error { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetService(sess) subnetID, err := strconv.Atoi(d.Id()) if err != nil { - return fmt.Errorf("Not a valid subnet ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid subnet ID, must be an integer: %s", err) } billingItem, err := service.Id(subnetID).GetBillingItem() if err != nil { - return fmt.Errorf("Error deleting subnet: %s", err) + return fmt.Errorf("[ERROR] Error deleting subnet: %s", err) } if billingItem.Id == nil { @@ -252,19 +253,19 @@ func resourceIBMSubnetDelete(d *schema.ResourceData, meta interface{}) error { } _, err = services.GetBillingItemService(sess).Id(*billingItem.Id).CancelService() if err != nil { - return fmt.Errorf("Error deleting subnet: %s", err) + return fmt.Errorf("[ERROR] Error deleting subnet: %s", err) } return err } func resourceIBMSubnetExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess := meta.(ClientSession).SoftLayerSession() + sess := meta.(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetService(sess) subnetID, err := strconv.Atoi(d.Id()) if err != nil { - return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return false, fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } result, err := service.Id(subnetID).GetObject() @@ -272,7 +273,7 @@ func resourceIBMSubnetExists(d *schema.ResourceData, meta interface{}) (bool, er if apiErr, ok := err.(sl.Error); ok && apiErr.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving subnet: %s", err) + return false, fmt.Errorf("[ERROR] Error retrieving subnet: %s", err) } return result.Id != nil && *result.Id == subnetID, nil } @@ -313,7 +314,7 @@ func findSubnetByOrderID(sess *session.Session, orderID int, d *schema.ResourceD } return datatypes.Network_Subnet{}, - fmt.Errorf("Cannot find a subnet with order id '%d'", orderID) + fmt.Errorf("[ERROR] Cannot find a subnet with order id '%d'", orderID) } func buildSubnetProductOrderContainer(d *schema.ResourceData, sess *session.Session) ( @@ -356,7 +357,7 @@ func buildSubnetProductOrderContainer(d *schema.ResourceData, sess *session.Sess if len(SubnetItems) == 0 { return &datatypes.Container_Product_Order_Network_Subnet{}, - fmt.Errorf("No product items matching with capacity %d could be found", capacity) + fmt.Errorf("[ERROR] No product items matching with capacity %d could be found", capacity) } productOrderContainer := datatypes.Container_Product_Order_Network_Subnet{ @@ -389,7 +390,7 @@ func buildSubnetProductOrderContainer(d *schema.ResourceData, sess *session.Sess } if productOrderContainer.EndPointIpAddressId == nil { return &datatypes.Container_Product_Order_Network_Subnet{}, - fmt.Errorf("Unable to find an ID of ipAddress: %s", endpointIPStr) + fmt.Errorf("[ERROR] Unable to find an ID of ipAddress: %s", endpointIPStr) } } return &productOrderContainer, nil @@ -399,7 +400,7 @@ func getVlanType(sess *session.Session, vlanID int) (string, error) { vlan, err := services.GetNetworkVlanService(sess).Id(vlanID).Mask(VlanMask).GetObject() if err != nil { - return "", fmt.Errorf("Error retrieving vlan: %s", err) + return "", fmt.Errorf("[ERROR] Error retrieving vlan: %s", err) } if vlan.PrimaryRouter != nil { @@ -409,5 +410,5 @@ func getVlanType(sess *session.Session, vlanID int) (string, error) { return "PRIVATE", nil } } - return "", fmt.Errorf("Unable to determine network") + return "", fmt.Errorf("[ERROR] Unable to determine network") } diff --git a/ibm/resource_ibm_subnet_test.go b/ibm/service/classicinfrastructure/resource_ibm_subnet_test.go similarity index 94% rename from ibm/resource_ibm_subnet_test.go rename to ibm/service/classicinfrastructure/resource_ibm_subnet_test.go index ace8378f1..9479677bc 100644 --- a/ibm/resource_ibm_subnet_test.go +++ b/ibm/service/classicinfrastructure/resource_ibm_subnet_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package classicinfrastructure_test import ( "fmt" @@ -10,6 +10,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/softlayer/softlayer-go/services" @@ -18,10 +21,10 @@ import ( func TestAccibmSubnet_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSubnetConfigBasic, Check: resource.ComposeTestCheckFunc( // Check portable IPv4 @@ -85,7 +88,7 @@ func TestAccibmSubnet_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMSubnetConfigNotesUpdate, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -101,10 +104,10 @@ func TestAccibmSubnet_Basic(t *testing.T) { func TestAccibmSubnet_With_Tag(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSubnetConfigWithTag, Check: resource.ComposeTestCheckFunc( // Check portable IPv4 @@ -126,7 +129,7 @@ func TestAccibmSubnet_With_Tag(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMSubnetConfigWithUpdatedTag, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -139,7 +142,7 @@ func TestAccibmSubnet_With_Tag(t *testing.T) { } func testAccCheckIBMSubnetDestroy(s *terraform.State) error { - sess := testAccProvider.Meta().(ClientSession).SoftLayerSession() + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() service := services.GetNetworkSubnetService(sess) for _, rs := range s.RootModule().Resources { @@ -149,7 +152,7 @@ func testAccCheckIBMSubnetDestroy(s *terraform.State) error { subnetID, err := strconv.Atoi(rs.Primary.ID) if err != nil { - return fmt.Errorf("Not a valid ID, must be an integer: %s", err) + return fmt.Errorf("[ERROR] Not a valid ID, must be an integer: %s", err) } // Try to find the key @@ -158,7 +161,7 @@ func testAccCheckIBMSubnetDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Subnet (%s) to be destroyed still exists", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for subnet (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for subnet (%s) to be destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/cloudant/README.md b/ibm/service/cloudant/README.md new file mode 100644 index 000000000..cb3c1a1bd --- /dev/null +++ b/ibm/service/cloudant/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Cloudant + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Cloudant resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cloudant) +* IBM API Docs: [IBM API Docs for Cloudant](https://cloud.ibm.com/apidocs/cloudant) +* IBM Cloudant SDK: [IBM SDK for Cloudant](https://github.com/IBM/cloudant-go-sdk/) diff --git a/ibm/data_source_ibm_cloudant.go b/ibm/service/cloudant/data_source_ibm_cloudant.go similarity index 91% rename from ibm/data_source_ibm_cloudant.go rename to ibm/service/cloudant/data_source_ibm_cloudant.go index e25d354d8..142174ec9 100644 --- a/ibm/data_source_ibm_cloudant.go +++ b/ibm/service/cloudant/data_source_ibm_cloudant.go @@ -1,19 +1,20 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudant import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcecontroller" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/cloudant-go-sdk/cloudantv1" ) -func dataSourceIBMCloudant() *schema.Resource { - riSchema := dataSourceIBMResourceInstance().Schema +func DataSourceIBMCloudant() *schema.Resource { + riSchema := resourcecontroller.DataSourceIBMResourceInstance().Schema riSchema["service"] = &schema.Schema{ Type: schema.TypeString, @@ -78,12 +79,12 @@ func dataSourceIBMCloudant() *schema.Resource { Description: "Configuration for CORS.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow_credentials": &schema.Schema{ + "allow_credentials": { Type: schema.TypeBool, Computed: true, Description: "Boolean value to allow authentication credentials. If set to true, browser requests must be done by using withCredentials = true.", }, - "origins": &schema.Schema{ + "origins": { Type: schema.TypeList, Computed: true, Description: "An array of strings that contain allowed origin domains. You have to specify the full URL including the protocol. It is recommended that only the HTTPS protocol is used. Subdomains count as separate domains, so you have to specify all subdomains used.", @@ -102,7 +103,7 @@ func dataSourceIBMCloudant() *schema.Resource { } func dataSourceIBMCloudantRead(d *schema.ResourceData, meta interface{}) error { - err := dataSourceIBMResourceInstanceRead(d, meta) + err := resourcecontroller.DataSourceIBMResourceInstanceRead(d, meta) if err != nil { return err } @@ -143,7 +144,7 @@ func dataSourceIBMCloudantRead(d *schema.ResourceData, meta interface{}) error { func setCloudantServerInformation(client *cloudantv1.CloudantV1, d *schema.ResourceData) error { serverInformation, err := readCloudantServerInformation(client) if err != nil { - return fmt.Errorf("Error retrieving server information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving server information: %s", err) } if serverInformation.Vendor != nil && serverInformation.Vendor.Version != nil { diff --git a/ibm/service/cloudant/data_source_ibm_cloudant_database.go b/ibm/service/cloudant/data_source_ibm_cloudant_database.go new file mode 100644 index 000000000..f62f10ad1 --- /dev/null +++ b/ibm/service/cloudant/data_source_ibm_cloudant_database.go @@ -0,0 +1,290 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudant + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/cloudant-go-sdk/cloudantv1" +) + +func DataSourceIBMCloudantDatabase() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCloudantDatabaseRead, + + Schema: map[string]*schema.Schema{ + "db": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Path parameter to specify the database name.", + }, + "instance_crn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Cloudant Instance CRN.", + }, + "cluster": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Database cluster information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "replicas": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of replicas of a database in a cluster.", + }, + "shards": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of shards in a database. Each shard is a partition of the hash value range.", + }, + "read_quorum": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Read quorum. The number of consistent copies of a document that need to be read before a successful reply.", + }, + "write_quorum": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Write quorum. The number of copies of a document that need to be written before a successful reply.", + }, + }, + }, + }, + "committed_update_seq": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An opaque string that describes the committed state of the database.", + }, + "compact_running": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "True if the database compaction routine is operating on this database.", + }, + "compacted_seq": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An opaque string that describes the compaction state of the database.", + }, + "disk_format_version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The version of the physical format used for the data when it is stored on disk.", + }, + "doc_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "A count of the documents in the specified database.", + }, + "doc_del_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Number of deleted documents.", + }, + "engine": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The engine used for the database.", + }, + "props": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The database properties.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "partitioned": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "The value is `true` for a partitioned database.", + }, + }, + }, + }, + "sizes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Database size information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "active": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The active size of the data in the database, in bytes.", + }, + "external": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total uncompressed size of the data in the database, in bytes.", + }, + "file": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total size of the database as stored on disk, in bytes.", + }, + }, + }, + }, + "update_seq": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An opaque string that describes the state of the database. Do not rely on this string for counting the number of updates.", + }, + "uuid": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the database.", + }, + }, + } +} + +func dataSourceIBMCloudantDatabaseRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + instanceCRN := d.Get("instance_crn").(string) + cUrl, err := GetCloudantInstanceUrl(instanceCRN, meta) + if err != nil { + return diag.FromErr(err) + } + + cloudantClient, err := GetCloudantClientForUrl(cUrl, meta) + if err != nil { + return diag.FromErr(err) + } + + dbName := d.Get("db").(string) + getDatabaseInformationOptions := cloudantClient.NewGetDatabaseInformationOptions(dbName) + + databaseInformation, response, err := cloudantClient.GetDatabaseInformationWithContext(context, getDatabaseInformationOptions) + if err != nil { + log.Printf("[DEBUG] GetDatabaseInformationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetDatabaseInformationWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMCloudantDatabaseID(d)) + + if databaseInformation.Cluster != nil { + err = d.Set("cluster", dataSourceDatabaseInformationFlattenCluster(*databaseInformation.Cluster)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting cluster %s", err)) + } + } + + if databaseInformation.CommittedUpdateSeq != nil { + d.Set("committed_update_seq", *databaseInformation.CommittedUpdateSeq) + } + if databaseInformation.CompactRunning != nil { + d.Set("compact_running", *databaseInformation.CompactRunning) + } + if databaseInformation.CompactedSeq != nil { + d.Set("compacted_seq", *databaseInformation.CompactedSeq) + } + if databaseInformation.DiskFormatVersion != nil { + d.Set("disk_format_version", *databaseInformation.DiskFormatVersion) + } + if databaseInformation.DocCount != nil { + d.Set("doc_count", *databaseInformation.DocCount) + } + if databaseInformation.DocDelCount != nil { + d.Set("doc_del_count", *databaseInformation.DocDelCount) + } + if databaseInformation.Engine != nil { + d.Set("engine", *databaseInformation.Engine) + } + if databaseInformation.Props != nil { + d.Set("props", dataSourceDatabaseInformationFlattenProps(*databaseInformation.Props)) + } + if databaseInformation.Sizes != nil { + d.Set("sizes", dataSourceDatabaseInformationFlattenSizes(*databaseInformation.Sizes)) + } + if databaseInformation.UpdateSeq != nil { + d.Set("update_seq", *databaseInformation.UpdateSeq) + } + if databaseInformation.UUID != nil { + d.Set("uuid", *databaseInformation.UUID) + } + + return nil +} + +// dataSourceIBMCloudantDatabaseID returns a reasonable ID for the list. +func dataSourceIBMCloudantDatabaseID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceDatabaseInformationFlattenCluster(result cloudantv1.DatabaseInformationCluster) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceDatabaseInformationClusterToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceDatabaseInformationClusterToMap(clusterItem cloudantv1.DatabaseInformationCluster) (clusterMap map[string]interface{}) { + clusterMap = map[string]interface{}{} + + if clusterItem.N != nil { + clusterMap["replicas"] = *clusterItem.N + } + if clusterItem.Q != nil { + clusterMap["shards"] = *clusterItem.Q + } + if clusterItem.R != nil { + clusterMap["read_quorum"] = *clusterItem.R + } + if clusterItem.W != nil { + clusterMap["write_quorum"] = *clusterItem.W + } + + return clusterMap +} + +func dataSourceDatabaseInformationFlattenProps(result cloudantv1.DatabaseInformationProps) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceDatabaseInformationPropsToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceDatabaseInformationPropsToMap(propsItem cloudantv1.DatabaseInformationProps) (propsMap map[string]interface{}) { + propsMap = map[string]interface{}{} + + if propsItem.Partitioned != nil { + propsMap["partitioned"] = *propsItem.Partitioned + } else { + propsMap["partitioned"] = false + } + + return propsMap +} + +func dataSourceDatabaseInformationFlattenSizes(result cloudantv1.ContentInformationSizes) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceDatabaseInformationSizesToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceDatabaseInformationSizesToMap(sizesItem cloudantv1.ContentInformationSizes) (sizesMap map[string]interface{}) { + sizesMap = map[string]interface{}{} + + if sizesItem.Active != nil { + sizesMap["active"] = *sizesItem.Active + } + if sizesItem.External != nil { + sizesMap["external"] = *sizesItem.External + } + if sizesItem.File != nil { + sizesMap["file"] = *sizesItem.File + } + + return sizesMap +} diff --git a/ibm/service/cloudant/data_source_ibm_cloudant_database_test.go b/ibm/service/cloudant/data_source_ibm_cloudant_database_test.go new file mode 100644 index 000000000..735df67cc --- /dev/null +++ b/ibm/service/cloudant/data_source_ibm_cloudant_database_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudant_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCloudantDatabaseDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCloudantDatabaseDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "db"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "cluster.#"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "compact_running"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "disk_format_version"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "doc_count"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "doc_del_count"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "props.#"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "sizes.#"), + resource.TestCheckResourceAttrSet("data.ibm_cloudant_database.cloudant_database", "update_seq"), + ), + }, + }, + }) +} + +func testAccCheckIBMCloudantDatabaseDataSourceConfigBasic() string { + return ` + data "ibm_resource_group" "cloudant" { + is_default=true + } + + resource "ibm_cloudant" "cloudant_instance" { + name = "pr01" + plan = "standard" + location = "us-south" + resource_group_id = data.ibm_resource_group.cloudant.id + } + + resource "ibm_cloudant_database" "cloudant_database" { + instance_crn = ibm_cloudant.cloudant_instance.crn + db = "db" + } + + data "ibm_cloudant_database" "cloudant_database" { + db = ibm_cloudant_database.cloudant_database.db + instance_crn = ibm_cloudant_database.cloudant_database.instance_crn + } + ` +} diff --git a/ibm/data_source_ibm_cloudant_test.go b/ibm/service/cloudant/data_source_ibm_cloudant_test.go similarity index 82% rename from ibm/data_source_ibm_cloudant_test.go rename to ibm/service/cloudant/data_source_ibm_cloudant_test.go index c04f50e54..c57847b5b 100644 --- a/ibm/data_source_ibm_cloudant_test.go +++ b/ibm/service/cloudant/data_source_ibm_cloudant_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudant_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,15 +20,15 @@ func TestAccIBMCloudantDataSource_basic(t *testing.T) { serviceName := fmt.Sprintf("terraform-test-%s", acctest.RandString(8)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCloudantDataSourceConfig(serviceName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "name", serviceName), resource.TestCheckResourceAttr(dataSourceName, "service", "cloudantnosqldb"), - resource.TestMatchResourceAttr(dataSourceName, ResourceControllerURL, regexp.MustCompile("services/cloudantnosqldb/crn%3A.+")), + resource.TestMatchResourceAttr(dataSourceName, flex.ResourceControllerURL, regexp.MustCompile("services/cloudantnosqldb/crn%3A.+")), resource.TestCheckResourceAttr(dataSourceName, "include_data_events", "false"), resource.TestCheckResourceAttr(dataSourceName, "capacity", "1"), resource.TestCheckResourceAttr(dataSourceName, "throughput.read", "20"), diff --git a/ibm/resource_ibm_cloudant.go b/ibm/service/cloudant/resource_ibm_cloudant.go similarity index 83% rename from ibm/resource_ibm_cloudant.go rename to ibm/service/cloudant/resource_ibm_cloudant.go index ddc68364b..ff89488e7 100644 --- a/ibm/resource_ibm_cloudant.go +++ b/ibm/service/cloudant/resource_ibm_cloudant.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudant import ( "context" @@ -11,6 +11,10 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcecontroller" + "github.com/IBM-Cloud/terraform-provider-ibm/version" rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,8 +26,8 @@ import ( iamidentity "github.com/IBM/platform-services-go-sdk/iamidentityv1" ) -func resourceIBMCloudant() *schema.Resource { - riSchema := resourceIBMResourceInstance().Schema +func ResourceIBMCloudant() *schema.Resource { + riSchema := resourcecontroller.ResourceIBMResourceInstance().Schema riSchema["service"] = &schema.Schema{ Type: schema.TypeString, @@ -87,13 +91,13 @@ func resourceIBMCloudant() *schema.Resource { Description: "Configuration for CORS.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow_credentials": &schema.Schema{ + "allow_credentials": { Type: schema.TypeBool, Optional: true, Default: true, Description: "Boolean value to allow authentication credentials. If set to true, browser requests must be done by using withCredentials = true.", }, - "origins": &schema.Schema{ + "origins": { Type: schema.TypeList, Required: true, Description: "An array of strings that contain allowed origin domains. You have to specify the full URL including the protocol. It is recommended that only the HTTPS protocol is used. Subdomains count as separate domains, so you have to specify all subdomains used.", @@ -111,8 +115,8 @@ func resourceIBMCloudant() *schema.Resource { Create: resourceIBMCloudantCreate, Read: resourceIBMCloudantRead, Update: resourceIBMCloudantUpdate, - Delete: resourceIBMResourceInstanceDelete, - Exists: resourceIBMResourceInstanceExists, + Delete: resourcecontroller.ResourceIBMResourceInstanceDelete, + Exists: resourcecontroller.ResourceIBMResourceInstanceExists, Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ @@ -123,7 +127,7 @@ func resourceIBMCloudant() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -171,7 +175,7 @@ func resourceIBMCloudantCreate(d *schema.ResourceData, meta interface{}) error { d.Set("parameters", params) } - err = resourceIBMResourceInstanceCreate(d, meta) + err = resourcecontroller.ResourceIBMResourceInstanceCreate(d, meta) if err != nil { return err } @@ -188,7 +192,7 @@ func resourceIBMCloudantCreate(d *schema.ResourceData, meta interface{}) error { if d.Get("include_data_events").(bool) { err := updateCloudantActivityTrackerEvents(client, d) if err != nil { - return fmt.Errorf("Error updating activity tracker events: %s", err) + return fmt.Errorf("[ERROR] Error updating activity tracker events: %s", err) } } @@ -196,20 +200,20 @@ func resourceIBMCloudantCreate(d *schema.ResourceData, meta interface{}) error { if d.Get("capacity").(int) > 1 { err := updateCloudantInstanceCapacity(client, d) if err != nil { - return fmt.Errorf("Error retrieving capacity throughput information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving capacity throughput information: %s", err) } } err = updateCloudantInstanceCors(client, d) if err != nil { - return fmt.Errorf("Error updating CORS settings: %s", err) + return fmt.Errorf("[ERROR] Error updating CORS settings: %s", err) } return resourceIBMCloudantRead(d, meta) } func resourceIBMCloudantRead(d *schema.ResourceData, meta interface{}) error { - err := resourceIBMResourceInstanceRead(d, meta) + err := resourcecontroller.ResourceIBMResourceInstanceRead(d, meta) if err != nil { return err } @@ -260,7 +264,7 @@ func resourceIBMCloudantUpdate(d *schema.ResourceData, meta interface{}) error { return err } - err = resourceIBMResourceInstanceUpdate(d, meta) + err = resourcecontroller.ResourceIBMResourceInstanceUpdate(d, meta) if err != nil { return err } @@ -273,21 +277,21 @@ func resourceIBMCloudantUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("include_data_events") { err := updateCloudantActivityTrackerEvents(client, d) if err != nil { - return fmt.Errorf("Error updating activity tracker events: %s", err) + return fmt.Errorf("[ERROR] Error updating activity tracker events: %s", err) } } if d.HasChange("capacity") { err := updateCloudantInstanceCapacity(client, d) if err != nil { - return fmt.Errorf("Error retrieving capacity throughput information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving capacity throughput information: %s", err) } } if d.HasChange("enable_cors") { err := updateCloudantInstanceCors(client, d) if err != nil { - return fmt.Errorf("Error updating CORS settings: %s", err) + return fmt.Errorf("[ERROR] Error updating CORS settings: %s", err) } } @@ -295,7 +299,7 @@ func resourceIBMCloudantUpdate(d *schema.ResourceData, meta interface{}) error { } func setCloudantLegacyCredentials(d *schema.ResourceData, meta interface{}) error { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return err } @@ -333,19 +337,19 @@ func setCloudantLegacyCredentials(d *schema.ResourceData, meta interface{}) erro } func setCloudantResourceControllerURL(d *schema.ResourceData, meta interface{}) error { - crn := d.Get(ResourceCRN).(string) - rcontroller, err := getBaseController(meta) + crn := d.Get(flex.ResourceCRN).(string) + rcontroller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, rcontroller+"/services/cloudantnosqldb/"+url.QueryEscape(crn)) + d.Set(flex.ResourceControllerURL, rcontroller+"/services/cloudantnosqldb/"+url.QueryEscape(crn)) return nil } func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.CloudantV1, error) { - session, err := meta.(ClientSession).BluemixSession() + session, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return nil, err } @@ -360,7 +364,7 @@ func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.Cl case "private": _, ok := extensions["endpoints.private"] if !ok { - return nil, fmt.Errorf("Missing endpoints.private in extensions") + return nil, fmt.Errorf("[ERROR] Missing endpoints.private in extensions") } endpoint = "https://" + extensions["endpoints.private"].(string) case "public-and-private": @@ -369,9 +373,18 @@ func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.Cl } } - endpoint = envFallBack([]string{"IBMCLOUD_CLOUDANT_ENDPOINT"}, endpoint) + endpoint = conns.EnvFallBack([]string{"IBMCLOUD_CLOUDANT_ENDPOINT"}, endpoint) if endpoint == "" { - return nil, fmt.Errorf("Missing endpoints.public in extensions") + return nil, fmt.Errorf("[ERROR] Missing endpoints.public in extensions") + } + + return GetCloudantClientForUrl(endpoint, meta) +} + +func GetCloudantClientForUrl(endpoint string, meta interface{}) (*cloudantv1.CloudantV1, error) { + session, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return nil, err } var authenticator core.Authenticator @@ -389,14 +402,14 @@ func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.Cl iamURL := iamidentity.DefaultServiceURL if visibility == "private" || visibility == "public-and-private" { if region == "us-south" || region == "us-east" { - iamURL = contructEndpoint(fmt.Sprintf("private.%s.iam", region), cloudEndpoint) + iamURL = conns.ContructEndpoint(fmt.Sprintf("private.%s.iam", region), "cloud.ibm.com") } else { - iamURL = contructEndpoint("private.iam", cloudEndpoint) + iamURL = conns.ContructEndpoint("private.iam", "cloud.ibm.com") } } authenticator = &core.IamAuthenticator{ ApiKey: apiKey, - URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL) + "/identity/token", + URL: conns.EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL) + "/identity/token", } } @@ -405,8 +418,9 @@ func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.Cl URL: endpoint, }) if err != nil { - return nil, fmt.Errorf("Error occured while configuring Cloudant service: %q", err) + return nil, fmt.Errorf("[ERROR] Error occured while configuring Cloudant service: %q", err) } + client.Service.SetUserAgent("cloudant-terraform/" + version.Version) return client, nil } @@ -414,7 +428,7 @@ func getCloudantClient(d *schema.ResourceData, meta interface{}) (*cloudantv1.Cl func setCloudantActivityTrackerEvents(client *cloudantv1.CloudantV1, d *schema.ResourceData) error { activityTrackerEvents, err := readCloudantActivityTrackerEvents(client) if err != nil { - return fmt.Errorf("Error retrieving activity tracker events: %s", err) + return fmt.Errorf("[ERROR] Error retrieving activity tracker events: %s", err) } if activityTrackerEvents.Types != nil { includeDataEvents := false @@ -457,7 +471,7 @@ func validateCloudantInstanceCapacity(d *schema.ResourceData) error { plan := d.Get("plan").(string) capacity := d.Get("capacity").(int) if capacity > 1 && plan == "lite" { - return fmt.Errorf("Setting capacity is not supported for your instance's plan.") + return fmt.Errorf("[ERROR] Setting capacity is not supported for your instance's plan") } return nil } @@ -465,13 +479,13 @@ func validateCloudantInstanceCapacity(d *schema.ResourceData) error { func setCloudantInstanceCapacity(client *cloudantv1.CloudantV1, d *schema.ResourceData) error { capacityThroughputInformation, err := readCloudantInstanceCapacity(client) if err != nil { - return fmt.Errorf("Error retrieving capacity throughput information: %s", err) + return fmt.Errorf("[ERROR] Error retrieving capacity throughput information: %s", err) } if capacityThroughputInformation.Current != nil && capacityThroughputInformation.Current.Throughput != nil { currentThroughput := capacityThroughputInformation.Current.Throughput // lite plan doesn't have "blocks" attr on broker's response - if d.Get("plan").(string) == "lite" { + if d.Get("plan").(string) == "lite" || currentThroughput.Blocks == nil { d.Set("capacity", 1) } else { blocks := int(*currentThroughput.Blocks) @@ -548,7 +562,7 @@ func validateCloudantInstanceCors(d *schema.ResourceData) error { allowCredentials := corsConfig["allow_credentials"].(bool) origins := corsConfig["origins"].([]interface{}) if !allowCredentials || len(origins) > 0 { - return fmt.Errorf("Setting \"cors_config\" conflicts with enable_cors set to false") + return fmt.Errorf("[ERROR] Setting \"cors_config\" conflicts with enable_cors set to false") } } return nil @@ -557,7 +571,7 @@ func validateCloudantInstanceCors(d *schema.ResourceData) error { func setCloudantInstanceCors(client *cloudantv1.CloudantV1, d *schema.ResourceData) error { corsInformation, err := readCloudantInstanceCors(client) if err != nil { - return fmt.Errorf("Error retrieving CORS config: %s", err) + return fmt.Errorf("[ERROR] Error retrieving CORS config: %s", err) } if corsInformation != nil { d.Set("enable_cors", corsInformation.EnableCors) @@ -593,7 +607,7 @@ func updateCloudantInstanceCors(client *cloudantv1.CloudantV1, d *schema.Resourc if enableCors && len(corsConfigRaw) > 0 { corsConfig := corsConfigRaw[0].(map[string]interface{}) allowCredentials = corsConfig["allow_credentials"].(bool) - origins = expandStringList(corsConfig["origins"].([]interface{})) + origins = flex.ExpandStringList(corsConfig["origins"].([]interface{})) } opts := client.NewPutCorsConfigurationOptions(origins) diff --git a/ibm/service/cloudant/resource_ibm_cloudant_database.go b/ibm/service/cloudant/resource_ibm_cloudant_database.go new file mode 100644 index 000000000..f94cc3773 --- /dev/null +++ b/ibm/service/cloudant/resource_ibm_cloudant_database.go @@ -0,0 +1,192 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudant + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func ResourceIBMCloudantDatabase() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCloudantDatabaseCreate, + ReadContext: resourceIBMCloudantDatabaseRead, + DeleteContext: resourceIBMCloudantDatabaseDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_crn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Cloudant Instance CRN.", + }, + "db": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Path parameter to specify the database name.", + }, + "partitioned": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Computed: true, + Description: "Query parameter to specify whether to enable database partitions when creating a database.", + }, + "shards": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The number of shards in the database. Each shard is a partition of the hash value range. You are encouraged to talk to support about appropriate values before changing this.", + }, + }, + } +} + +func resourceIBMCloudantDatabaseCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + instanceCRN := d.Get("instance_crn").(string) + cUrl, err := GetCloudantInstanceUrl(instanceCRN, meta) + if err != nil { + return diag.FromErr(err) + } + + cloudantClient, err := GetCloudantClientForUrl(cUrl, meta) + if err != nil { + return diag.FromErr(err) + } + + dbName := d.Get("db").(string) + putDatabaseOptions := cloudantClient.NewPutDatabaseOptions(dbName) + if _, ok := d.GetOk("partitioned"); ok { + putDatabaseOptions.SetPartitioned(d.Get("partitioned").(bool)) + } + if _, ok := d.GetOk("shards"); ok { + putDatabaseOptions.SetQ(int64(d.Get("shards").(int))) + } + + _, response, err := cloudantClient.PutDatabaseWithContext(context, putDatabaseOptions) + if err != nil { + log.Printf("[DEBUG] PutDatabaseWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PutDatabaseWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", instanceCRN, dbName)) + + return resourceIBMCloudantDatabaseRead(context, d, meta) +} + +func resourceIBMCloudantDatabaseRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + instanceCRN, dbName := strings.Join(parts[:len(parts)-1], "/"), parts[len(parts)-1] + cUrl, err := GetCloudantInstanceUrl(instanceCRN, meta) + if err != nil { + return diag.FromErr(err) + } + + cloudantClient, err := GetCloudantClientForUrl(cUrl, meta) + if err != nil { + return diag.FromErr(err) + } + + getDatabaseInformationOptions := cloudantClient.NewGetDatabaseInformationOptions(dbName) + + databaseInformation, response, err := cloudantClient.GetDatabaseInformationWithContext(context, getDatabaseInformationOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetDatabaseInformationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetDatabaseInformationWithContext failed %s\n%s", err, response)) + } + + d.Set("instance_crn", instanceCRN) + + if err = d.Set("db", *databaseInformation.DbName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting db: %s", err)) + } + + if err = d.Set("partitioned", databaseInformation.Props.Partitioned != nil); err != nil { + return diag.FromErr(fmt.Errorf("Error setting partitioned: %s", err)) + } + + if err = d.Set("shards", int(*databaseInformation.Cluster.Q)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting shards: %s", err)) + } + + return nil +} + +func resourceIBMCloudantDatabaseDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + instanceCRN, dbName := strings.Join(parts[:len(parts)-1], "/"), parts[len(parts)-1] + cUrl, err := GetCloudantInstanceUrl(instanceCRN, meta) + if err != nil { + return diag.FromErr(err) + } + + cloudantClient, err := GetCloudantClientForUrl(cUrl, meta) + if err != nil { + return diag.FromErr(err) + } + + deleteDatabaseOptions := cloudantClient.NewDeleteDatabaseOptions(dbName) + + _, response, err := cloudantClient.DeleteDatabaseWithContext(context, deleteDatabaseOptions) + if err != nil { + log.Printf("[DEBUG] DeleteDatabaseWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteDatabaseWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func GetCloudantInstanceUrl(instanceCRN string, meta interface{}) (string, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return "", err + } + + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: flex.PtrToString(instanceCRN), + } + + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + return "", fmt.Errorf("Error retrieving resource instance: %s with resp code: %s", err, resp) + } + + if instance.Extensions != nil { + instanceExtensionMap := flex.Flatten(instance.Extensions) + if instanceExtensionMap != nil { + cloudantInstanceUrl := "https://" + instanceExtensionMap["endpoints.public"] + cloudantInstanceUrl = conns.EnvFallBack([]string{"IBMCLOUD_CLOUDANT_API_ENDPOINT"}, cloudantInstanceUrl) + return cloudantInstanceUrl, nil + } + } + + return "", fmt.Errorf("Unable to get URL for cloudant instance") +} diff --git a/ibm/service/cloudant/resource_ibm_cloudant_database_test.go b/ibm/service/cloudant/resource_ibm_cloudant_database_test.go new file mode 100644 index 000000000..5ee3a8a81 --- /dev/null +++ b/ibm/service/cloudant/resource_ibm_cloudant_database_test.go @@ -0,0 +1,194 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudant_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cloudant" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/cloudant-go-sdk/cloudantv1" +) + +func TestAccIBMCloudantDatabaseBasic(t *testing.T) { + var conf cloudantv1.DatabaseInformation + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + db := fmt.Sprintf("tf_db_%d", acctest.RandIntRange(10, 100)) + dbUpdate := fmt.Sprintf("tf_db_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCloudantDatabaseDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCloudantDatabaseConfigBasic(instanceName, db), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCloudantDatabaseExists("ibm_cloudant_database.cloudant_database", conf), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "db", db), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCloudantDatabaseConfigBasic(instanceName, dbUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "db", dbUpdate), + ), + }, + }, + }) +} + +func TestAccIBMCloudantDatabaseAllArgs(t *testing.T) { + var conf cloudantv1.DatabaseInformation + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + db := fmt.Sprintf("tf_db_%d", acctest.RandIntRange(10, 100)) + partitioned := "true" + shards := "16" + dbUpdate := fmt.Sprintf("tf_db_%d", acctest.RandIntRange(10, 100)) + partitionedUpdate := "true" + shardsUpdate := "16" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCloudantDatabaseDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCloudantDatabaseConfig(instanceName, db, partitioned, shards), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCloudantDatabaseExists("ibm_cloudant_database.cloudant_database", conf), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "db", db), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "partitioned", partitioned), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "shards", shards), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCloudantDatabaseConfig(instanceName, dbUpdate, partitionedUpdate, shardsUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "db", dbUpdate), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "partitioned", partitionedUpdate), + resource.TestCheckResourceAttr("ibm_cloudant_database.cloudant_database", "shards", shardsUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cloudant_database.cloudant_database", + ImportState: true, + ImportStateVerify: true, ImportStateVerifyIgnore: []string{ + "partitioned", "shards"}, + }, + }, + }) +} + +func testAccCheckIBMCloudantDatabaseConfigBasic(instanceName, db string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "cloudant" { + is_default=true + } + + resource "ibm_cloudant" "cloudant_instance" { + name = "%s" + plan = "standard" + location = "us-south" + resource_group_id = data.ibm_resource_group.cloudant.id + } + + resource "ibm_cloudant_database" "cloudant_database" { + instance_crn = ibm_cloudant.cloudant_instance.crn + db = "%s" + } + `, instanceName, db) +} + +func testAccCheckIBMCloudantDatabaseConfig(instanceName, db string, partitioned string, shards string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "cloudant" { + is_default=true + } + + resource "ibm_cloudant" "cloudant_instance" { + name = "%s" + plan = "standard" + location = "us-south" + resource_group_id = data.ibm_resource_group.cloudant.id + } + + resource "ibm_cloudant_database" "cloudant_database" { + instance_crn = ibm_cloudant.cloudant_instance.crn + db = "%s" + partitioned = %s + shards = %s + } + `, instanceName, db, partitioned, shards) +} + +func testAccCheckIBMCloudantDatabaseExists(n string, obj cloudantv1.DatabaseInformation) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + instanceCRN := rs.Primary.Attributes["instance_crn"] + cUrl, err := cloudant.GetCloudantInstanceUrl(instanceCRN, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + cloudantClient, err := cloudant.GetCloudantClientForUrl(cUrl, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + dbName := rs.Primary.Attributes["db"] + getDatabaseInformationOptions := cloudantClient.NewGetDatabaseInformationOptions(dbName) + + documentResult, _, err := cloudantClient.GetDatabaseInformation(getDatabaseInformationOptions) + if err != nil { + return err + } + + obj = *documentResult + return nil + } +} + +func testAccCheckIBMCloudantDatabaseDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cloudant_database" { + continue + } + + instanceCRN := rs.Primary.Attributes["instance_crn"] + cUrl, err := cloudant.GetCloudantInstanceUrl(instanceCRN, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + cloudantClient, err := cloudant.GetCloudantClientForUrl(cUrl, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + dbName := rs.Primary.Attributes["db"] + getDatabaseInformationOptions := cloudantClient.NewGetDatabaseInformationOptions(dbName) + + // Try to find the key + _, _, err = cloudantClient.GetDatabaseInformation(getDatabaseInformationOptions) + if err == nil { + return fmt.Errorf("cloudant_database still exists: %s", rs.Primary.ID) + } + } + + return nil +} diff --git a/ibm/resource_ibm_cloudant_test.go b/ibm/service/cloudant/resource_ibm_cloudant_test.go similarity index 90% rename from ibm/resource_ibm_cloudant_test.go rename to ibm/service/cloudant/resource_ibm_cloudant_test.go index 887893db4..815d3f3c5 100644 --- a/ibm/resource_ibm_cloudant_test.go +++ b/ibm/service/cloudant/resource_ibm_cloudant_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudant_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,8 +26,8 @@ func TestAccIBMCloudant_basic(t *testing.T) { updateName := fmt.Sprintf("terraform-test-%s", acctest.RandString(8)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCloudantDestroy, Steps: []resource.TestStep{ { @@ -65,8 +68,8 @@ func TestAccIBMCloudant_import(t *testing.T) { serviceName := fmt.Sprintf("terraform-test-%s", acctest.RandString(8)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCloudantDestroy, Steps: []resource.TestStep{ { @@ -94,7 +97,7 @@ func TestAccIBMCloudant_import(t *testing.T) { } func testAccCheckIBMCloudantDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerAPI() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerAPI() if err != nil { return err } @@ -114,7 +117,7 @@ func testAccCheckIBMCloudantDestroy(s *terraform.State) error { } } else { if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if Resource Instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if Resource Instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } } @@ -130,7 +133,7 @@ func testAccCheckIBMCloudantExists(resourceName string, obj models.ServiceInstan return fmt.Errorf("Not found: %s", resourceName) } - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerAPI() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_account.go b/ibm/service/cloudfoundry/data_source_ibm_account.go similarity index 78% rename from ibm/data_source_ibm_account.go rename to ibm/service/cloudfoundry/data_source_ibm_account.go index 8b34bd1e0..712d262ce 100644 --- a/ibm/data_source_ibm_account.go +++ b/ibm/service/cloudfoundry/data_source_ibm_account.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAccount() *schema.Resource { +func DataSourceIBMAccount() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMAccountRead, @@ -48,27 +49,27 @@ func dataSourceIBMAccount() *schema.Resource { } func dataSourceIBMAccountRead(d *schema.ResourceData, meta interface{}) error { - bmxSess, err := meta.(ClientSession).BluemixSession() + bmxSess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } - accClient, err := meta.(ClientSession).BluemixAcccountAPI() + accClient, err := meta.(conns.ClientSession).BluemixAcccountAPI() if err != nil { return err } orgGUID := d.Get("org_guid").(string) account, err := accClient.Accounts().FindByOrg(orgGUID, bmxSess.Config.Region) if err != nil { - return fmt.Errorf("Error retrieving organisation: %s", err) + return fmt.Errorf("[ERROR] Error retrieving organisation: %s", err) } - accountv1Client, err := meta.(ClientSession).BluemixAcccountv1API() + accountv1Client, err := meta.(conns.ClientSession).BluemixAcccountv1API() if err != nil { return err } accountUsers, err := accountv1Client.Accounts().GetAccountUsers(account.GUID) if err != nil { - return fmt.Errorf("Error retrieving users in account: %s", err) + return fmt.Errorf("[ERROR] Error retrieving users in account: %s", err) } accountUsersMap := make([]map[string]string, 0, len(accountUsers)) for _, user := range accountUsers { diff --git a/ibm/data_source_ibm_account_test.go b/ibm/service/cloudfoundry/data_source_ibm_account_test.go similarity index 77% rename from ibm/data_source_ibm_account_test.go rename to ibm/service/cloudfoundry/data_source_ibm_account_test.go index 605955fef..f9c225c26 100644 --- a/ibm/data_source_ibm_account_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_account_test.go @@ -1,25 +1,27 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAccountDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAccountDataSourceConfig(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_org.testacc_ds_org", "org", cfOrganization), + resource.TestCheckResourceAttr("data.ibm_org.testacc_ds_org", "org", acc.CfOrganization), resource.TestCheckResourceAttrSet( "data.ibm_account.testacc_acc", "id"), ), @@ -37,6 +39,6 @@ data "ibm_org" "testacc_ds_org" { data "ibm_account" "testacc_acc" { org_guid = data.ibm_org.testacc_ds_org.id -}`, cfOrganization) +}`, acc.CfOrganization) } diff --git a/ibm/data_source_ibm_app.go b/ibm/service/cloudfoundry/data_source_ibm_app.go similarity index 90% rename from ibm/data_source_ibm_app.go rename to ibm/service/cloudfoundry/data_source_ibm_app.go index e3b396d64..efe3adf82 100644 --- a/ibm/data_source_ibm_app.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMApp() *schema.Resource { +func DataSourceIBMApp() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMAppRead, @@ -91,7 +93,7 @@ func dataSourceIBMApp() *schema.Resource { } func dataSourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -109,7 +111,7 @@ func dataSourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { if app.BuildPack != nil { d.Set("buildpack", app.BuildPack) } - d.Set("environment_json", Flatten(app.EnvironmentJSON)) + d.Set("environment_json", flex.Flatten(app.EnvironmentJSON)) d.Set("package_state", app.PackageState) d.Set("state", app.State) d.Set("instances", app.Instances) @@ -122,14 +124,14 @@ func dataSourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { return err } if len(route) > 0 { - d.Set("route_guid", flattenRoute(route)) + d.Set("route_guid", flex.FlattenRoute(route)) } svcBindings, err := appAPI.ListServiceBindings(app.GUID) if err != nil { return err } if len(svcBindings) > 0 { - d.Set("service_instance_guid", flattenServiceBindings(svcBindings)) + d.Set("service_instance_guid", flex.FlattenServiceBindings(svcBindings)) } return nil } diff --git a/ibm/service/cloudfoundry/data_source_ibm_app_domain_private.go b/ibm/service/cloudfoundry/data_source_ibm_app_domain_private.go new file mode 100644 index 000000000..37f94aab2 --- /dev/null +++ b/ibm/service/cloudfoundry/data_source_ibm_app_domain_private.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMAppDomainPrivate() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMAppDomainPrivateRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "The name of the private domain", + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func dataSourceIBMAppDomainPrivateRead(d *schema.ResourceData, meta interface{}) error { + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + domainName := d.Get("name").(string) + prdomain, err := cfAPI.PrivateDomains().FindByName(domainName) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving domain: %s", err) + } + d.SetId(prdomain.GUID) + return nil + +} diff --git a/ibm/data_source_ibm_app_domain_private_test.go b/ibm/service/cloudfoundry/data_source_ibm_app_domain_private_test.go similarity index 83% rename from ibm/data_source_ibm_app_domain_private_test.go rename to ibm/service/cloudfoundry/data_source_ibm_app_domain_private_test.go index ff818e970..0a99879d6 100644 --- a/ibm/data_source_ibm_app_domain_private_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app_domain_private_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMAppDomainPrivateDataSource_basic(t *testing.T) { name := fmt.Sprintf("terraform%d.com", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainPrivateDataSourceConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -43,6 +45,6 @@ func testAccCheckIBMAppDomainPrivateDataSourceConfig(name string) string { data "ibm_app_domain_private" "testacc_domain" { name = ibm_app_domain_private.domain.name - }`, cfOrganization, name) + }`, acc.CfOrganization, name) } diff --git a/ibm/service/cloudfoundry/data_source_ibm_app_domain_shared.go b/ibm/service/cloudfoundry/data_source_ibm_app_domain_shared.go new file mode 100644 index 000000000..71bb660d8 --- /dev/null +++ b/ibm/service/cloudfoundry/data_source_ibm_app_domain_shared.go @@ -0,0 +1,42 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMAppDomainShared() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMAppDomainSharedRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "The name of the shared domain", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateDomainName, + }, + }, + } +} + +func dataSourceIBMAppDomainSharedRead(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + domainName := d.Get("name").(string) + shdomain, err := cfClient.SharedDomains().FindByName(domainName) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving shared domain: %s", err) + } + d.SetId(shdomain.GUID) + return nil + +} diff --git a/ibm/data_source_ibm_app_domain_shared_test.go b/ibm/service/cloudfoundry/data_source_ibm_app_domain_shared_test.go similarity index 78% rename from ibm/data_source_ibm_app_domain_shared_test.go rename to ibm/service/cloudfoundry/data_source_ibm_app_domain_shared_test.go index b653498b3..dab8ef6c6 100644 --- a/ibm/data_source_ibm_app_domain_shared_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app_domain_shared_test.go @@ -1,22 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMAppDomainSharedDataSource_basic(t *testing.T) { t.Skip() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainSharedDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -28,10 +29,10 @@ func TestAccIBMAppDomainSharedDataSource_basic(t *testing.T) { } func testAccCheckIBMAppDomainSharedDataSourceConfig() string { - return fmt.Sprintf(` + return ` data "ibm_app_domain_shared" "testacc_domain" { name = "mybluemix.net" - }`) + }` } diff --git a/ibm/data_source_ibm_app_route.go b/ibm/service/cloudfoundry/data_source_ibm_app_route.go similarity index 75% rename from ibm/data_source_ibm_app_route.go rename to ibm/service/cloudfoundry/data_source_ibm_app_route.go index 37587bbc9..7d7ed0a9e 100644 --- a/ibm/data_source_ibm_app_route.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app_route.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" v2 "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMAppRoute() *schema.Resource { +func DataSourceIBMAppRoute() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMAppRouteRead, @@ -36,20 +38,20 @@ func dataSourceIBMAppRoute() *schema.Resource { Type: schema.TypeString, Optional: true, Description: "The path of the route", - ValidateFunc: validateRoutePath, + ValidateFunc: validate.ValidateRoutePath, }, "port": { Type: schema.TypeString, Optional: true, Description: "The port of the route", - ValidateFunc: validateRoutePort, + ValidateFunc: validate.ValidateRoutePort, }, }, } } func dataSourceIBMAppRouteRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -74,14 +76,14 @@ func dataSourceIBMAppRouteRead(d *schema.ResourceData, meta interface{}) error { } route, err := spaceAPI.ListRoutes(spaceGUID, params) if err != nil { - return fmt.Errorf("Error retrieving route: %s", err) + return fmt.Errorf("[ERROR] Error retrieving route: %s", err) } if len(route) == 0 { - return fmt.Errorf("No route satifies the given parameters") + return fmt.Errorf("[ERROR] No route satifies the given parameters") } if len(route) > 1 { - return fmt.Errorf("More than one route satifies the given parameters") + return fmt.Errorf("[ERROR] More than one route satifies the given parameters") } d.SetId(route[0].GUID) diff --git a/ibm/data_source_ibm_app_route_test.go b/ibm/service/cloudfoundry/data_source_ibm_app_route_test.go similarity index 85% rename from ibm/data_source_ibm_app_route_test.go rename to ibm/service/cloudfoundry/data_source_ibm_app_route_test.go index 4f47c6302..231e9e729 100644 --- a/ibm/data_source_ibm_app_route_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app_route_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMAppRouteDataSource_basic(t *testing.T) { host := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppRouteDataSourceConfig(host), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -53,6 +55,6 @@ func testAccCheckIBMAppRouteDataSourceConfig(host string) string { host = ibm_app_route.route.host path = ibm_app_route.route.path } - `, cfOrganization, cfSpace, host) + `, acc.CfOrganization, acc.CfSpace, host) } diff --git a/ibm/data_source_ibm_app_test.go b/ibm/service/cloudfoundry/data_source_ibm_app_test.go similarity index 91% rename from ibm/data_source_ibm_app_test.go rename to ibm/service/cloudfoundry/data_source_ibm_app_test.go index 6e6d91e4e..77d8b2302 100644 --- a/ibm/data_source_ibm_app_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_app_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,12 +21,12 @@ func TestAccIBMAppDataSource_Basic(t *testing.T) { svcName := fmt.Sprintf("tfsvc-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDataSourceBasic(routeHostName, svcName, appName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -76,7 +78,7 @@ func testAccCheckIBMAppDataSourceBasic(routeHost, serviceInstanceName, appName s resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -98,6 +100,6 @@ func testAccCheckIBMAppDataSourceBasic(routeHost, serviceInstanceName, appName s space_guid = data.ibm_space.space.id } -`, cfOrganization, cfSpace, routeHost, serviceInstanceName, appName) +`, acc.CfOrganization, acc.CfSpace, routeHost, serviceInstanceName, appName) return } diff --git a/ibm/data_source_ibm_org.go b/ibm/service/cloudfoundry/data_source_ibm_org.go similarity index 76% rename from ibm/data_source_ibm_org.go rename to ibm/service/cloudfoundry/data_source_ibm_org.go index 64b309697..0878c7370 100644 --- a/ibm/data_source_ibm_org.go +++ b/ibm/service/cloudfoundry/data_source_ibm_org.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMOrg() *schema.Resource { +func DataSourceIBMOrg() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMOrgRead, @@ -32,7 +33,7 @@ func dataSourceIBMOrg() *schema.Resource { } func dataSourceIBMOrgRead(d *schema.ResourceData, meta interface{}) error { - cfAPI, err := meta.(ClientSession).MccpAPI() + cfAPI, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -45,9 +46,9 @@ func dataSourceIBMOrgRead(d *schema.ResourceData, meta interface{}) error { org = v.(string) } - orgFields, err := orgAPI.FindByName(org, BluemixRegion) + orgFields, err := orgAPI.FindByName(org, conns.BluemixRegion) if err != nil { - return fmt.Errorf("Error retrieving organisation: %s", err) + return fmt.Errorf("[ERROR] Error retrieving organisation: %s", err) } d.SetId(orgFields.GUID) diff --git a/ibm/data_source_ibm_org_quota.go b/ibm/service/cloudfoundry/data_source_ibm_org_quota.go similarity index 92% rename from ibm/data_source_ibm_org_quota.go rename to ibm/service/cloudfoundry/data_source_ibm_org_quota.go index 036e5475b..cc6a9c47b 100644 --- a/ibm/data_source_ibm_org_quota.go +++ b/ibm/service/cloudfoundry/data_source_ibm_org_quota.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMOrgQuota() *schema.Resource { +func DataSourceIBMOrgQuota() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMOrgQuotaRead, @@ -79,7 +80,7 @@ func dataSourceIBMOrgQuota() *schema.Resource { } func dataSourceIBMOrgQuotaRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -87,7 +88,7 @@ func dataSourceIBMOrgQuotaRead(d *schema.ResourceData, meta interface{}) error { orgQuotaName := d.Get("name").(string) orgQuotaFields, err := orgQuotaAPI.FindByName(orgQuotaName) if err != nil { - return fmt.Errorf("Error retrieving org quota: %s", err) + return fmt.Errorf("[ERROR] Error retrieving org quota: %s", err) } d.SetId(orgQuotaFields.GUID) d.Set("app_instance_limit", orgQuotaFields.AppInstanceLimit) diff --git a/ibm/data_source_ibm_org_quota_test.go b/ibm/service/cloudfoundry/data_source_ibm_org_quota_test.go similarity index 80% rename from ibm/data_source_ibm_org_quota_test.go rename to ibm/service/cloudfoundry/data_source_ibm_org_quota_test.go index d94a5493e..5389955a2 100644 --- a/ibm/data_source_ibm_org_quota_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_org_quota_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ func TestAccIBMOrgQuotaDataSource_basic(t *testing.T) { name := "qIBM" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMOrgQuotaDataSourceConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_org_quota.testacc_ds_org_quota", "name", name), diff --git a/ibm/service/cloudfoundry/data_source_ibm_org_test.go b/ibm/service/cloudfoundry/data_source_ibm_org_test.go new file mode 100644 index 000000000..7b0e317e6 --- /dev/null +++ b/ibm/service/cloudfoundry/data_source_ibm_org_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMOrgDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMOrgDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_org.testacc_ds_org", "org", acc.CfOrganization), + ), + }, + }, + }) +} + +func testAccCheckIBMOrgDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_org" "testacc_ds_org" { + org = "%s" +}`, acc.CfOrganization) + +} diff --git a/ibm/data_source_ibm_service_instance.go b/ibm/service/cloudfoundry/data_source_ibm_service_instance.go similarity index 82% rename from ibm/data_source_ibm_service_instance.go rename to ibm/service/cloudfoundry/data_source_ibm_service_instance.go index 1b97b8c24..651496de4 100644 --- a/ibm/data_source_ibm_service_instance.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_instance.go @@ -1,15 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMServiceInstance() *schema.Resource { +func DataSourceIBMServiceInstance() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMServiceInstanceRead, @@ -64,7 +66,7 @@ func dataSourceIBMServiceInstance() *schema.Resource { } func dataSourceIBMServiceInstanceRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -78,13 +80,13 @@ func dataSourceIBMServiceInstanceRead(d *schema.ResourceData, meta interface{}) serviceInstance, err := siAPI.Get(inst.GUID, 1) if err != nil { - return fmt.Errorf("Error retrieving service: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service: %s", err) } d.SetId(serviceInstance.Metadata.GUID) serviceKeys := serviceInstance.Entity.ServiceKeys - d.Set("credentials", Flatten(serviceInstance.Entity.Credentials)) - d.Set("service_keys", flattenServiceInstanceCredentials(serviceKeys)) + d.Set("credentials", flex.Flatten(serviceInstance.Entity.Credentials)) + d.Set("service_keys", flex.FlattenServiceInstanceCredentials(serviceKeys)) d.Set("service_plan_guid", serviceInstance.Entity.ServicePlanGUID) return nil diff --git a/ibm/data_source_ibm_service_instance_test.go b/ibm/service/cloudfoundry/data_source_ibm_service_instance_test.go similarity index 90% rename from ibm/data_source_ibm_service_instance_test.go rename to ibm/service/cloudfoundry/data_source_ibm_service_instance_test.go index 3065e092a..2ffe3d3f6 100644 --- a/ibm/data_source_ibm_service_instance_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_instance_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,17 +19,17 @@ func TestAccIBMServiceInstanceDataSource_basic(t *testing.T) { serviceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: setupServiceInstanceConfig(serviceName, serviceKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_service_key.servicekey", "credentials.%", "3"), resource.TestCheckResourceAttr("ibm_service_instance.service", "service_keys.#", "0"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceInstanceDataSourceConfig(serviceName, serviceKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_service_instance.testacc_ds_service_instance", "name", serviceName), @@ -60,7 +62,7 @@ func setupServiceInstanceConfig(serviceName, serviceKey string) string { service_instance_guid = ibm_service_instance.service.id } -`, cfOrganization, cfSpace, serviceName, serviceKey) +`, acc.CfOrganization, acc.CfSpace, serviceName, serviceKey) } @@ -88,6 +90,6 @@ func testAccCheckIBMServiceInstanceDataSourceConfig(serviceName, serviceKey stri name = ibm_service_instance.service.name space_guid = data.ibm_space.spacedata.id } -`, cfOrganization, cfSpace, serviceName, serviceKey) +`, acc.CfOrganization, acc.CfSpace, serviceName, serviceKey) } diff --git a/ibm/data_source_ibm_service_key.go b/ibm/service/cloudfoundry/data_source_ibm_service_key.go similarity index 78% rename from ibm/data_source_ibm_service_key.go rename to ibm/service/cloudfoundry/data_source_ibm_service_key.go index 1bf75aa1e..6a63b0c18 100644 --- a/ibm/data_source_ibm_service_key.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_key.go @@ -1,15 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMServiceKey() *schema.Resource { +func DataSourceIBMServiceKey() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMServiceKeyRead, @@ -40,7 +42,7 @@ func dataSourceIBMServiceKey() *schema.Resource { } func dataSourceIBMServiceKeyRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -55,13 +57,13 @@ func dataSourceIBMServiceKeyRead(d *schema.ResourceData, meta interface{}) error } serviceInstance, err := siAPI.Get(inst.GUID) if err != nil { - return fmt.Errorf("Error retrieving service: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service: %s", err) } serviceKey, err := skAPI.FindByName(serviceInstance.Metadata.GUID, name) if err != nil { - return fmt.Errorf("Error retrieving service key: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service key: %s", err) } d.SetId(serviceKey.GUID) - d.Set("credentials", Flatten(serviceKey.Credentials)) + d.Set("credentials", flex.Flatten(serviceKey.Credentials)) return nil } diff --git a/ibm/data_source_ibm_service_key_test.go b/ibm/service/cloudfoundry/data_source_ibm_service_key_test.go similarity index 87% rename from ibm/data_source_ibm_service_key_test.go rename to ibm/service/cloudfoundry/data_source_ibm_service_key_test.go index 01f25d9e4..61e2b9210 100644 --- a/ibm/data_source_ibm_service_key_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_key_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMServiceKeyDataSource_basic(t *testing.T) { serviceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceKeyDataSourceConfig(serviceName, serviceKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_service_key.testacc_ds_service_key", "name", serviceKey), @@ -56,6 +58,6 @@ func testAccCheckIBMServiceKeyDataSourceConfig(serviceName, serviceKey string) s service_instance_name = ibm_service_instance.service.name space_guid = data.ibm_space.spacedata.id } -`, cfOrganization, cfSpace, serviceName, serviceKey) +`, acc.CfOrganization, acc.CfSpace, serviceName, serviceKey) } diff --git a/ibm/data_source_ibm_service_plan.go b/ibm/service/cloudfoundry/data_source_ibm_service_plan.go similarity index 76% rename from ibm/data_source_ibm_service_plan.go rename to ibm/service/cloudfoundry/data_source_ibm_service_plan.go index e018f55f4..67c5655d8 100644 --- a/ibm/data_source_ibm_service_plan.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_plan.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMServicePlan() *schema.Resource { +func DataSourceIBMServicePlan() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMServicePlanRead, @@ -30,7 +31,7 @@ func dataSourceIBMServicePlan() *schema.Resource { } func dataSourceIBMServicePlanRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -41,11 +42,11 @@ func dataSourceIBMServicePlanRead(d *schema.ResourceData, meta interface{}) erro plan := d.Get("plan").(string) serviceOff, err := soffAPI.FindByLabel(service) if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) } servicePlan, err := spAPI.FindPlanInServiceOffering(serviceOff.GUID, plan) if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) } d.SetId(servicePlan.GUID) diff --git a/ibm/data_source_ibm_service_plan_test.go b/ibm/service/cloudfoundry/data_source_ibm_service_plan_test.go similarity index 83% rename from ibm/data_source_ibm_service_plan_test.go rename to ibm/service/cloudfoundry/data_source_ibm_service_plan_test.go index 1ae049fca..3cd826038 100644 --- a/ibm/data_source_ibm_service_plan_test.go +++ b/ibm/service/cloudfoundry/data_source_ibm_service_plan_test.go @@ -1,22 +1,24 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMServicePlanDataSource_basic(t *testing.T) { t.Skip() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServicePlanDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_service_plan.testacc_ds_service_plan", "service", "cloudantNoSQLDB"), diff --git a/ibm/service/cloudfoundry/data_source_ibm_space.go b/ibm/service/cloudfoundry/data_source_ibm_space.go new file mode 100644 index 000000000..e6a9f4af4 --- /dev/null +++ b/ibm/service/cloudfoundry/data_source_ibm_space.go @@ -0,0 +1,108 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMSpace() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMSpaceRead, + + Schema: map[string]*schema.Schema{ + "space": { + Description: "Space name, for example dev", + Type: schema.TypeString, + Optional: true, + Deprecated: "use name instead", + ExactlyOneOf: []string{"space", "name"}, + }, + "name": { + Description: "Space name, for example dev", + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"space", "name"}, + }, + "org": { + Description: "The org this space belongs to", + Type: schema.TypeString, + Required: true, + }, + "auditors": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who have auditor role in this space, ex - user@example.com", + }, + "managers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who have manager role in this space, ex - user@example.com", + }, + "developers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who have developer role in this space, ex - user@example.com", + }, + }, + } +} + +func dataSourceIBMSpaceRead(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + orgAPI := cfClient.Organizations() + spaceAPI := cfClient.Spaces() + var space string + if v, ok := d.GetOk("name"); ok { + space = v.(string) + } + if v, ok := d.GetOk("space"); ok { + space = v.(string) + } + + org := d.Get("org").(string) + + orgFields, err := orgAPI.FindByName(org, conns.BluemixRegion) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving org: %s", err) + } + spaceFields, err := spaceAPI.FindByNameInOrg(orgFields.GUID, space, conns.BluemixRegion) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving space: %s", err) + } + + spaceGUID := spaceFields.GUID + d.SetId(spaceGUID) + + auditors, err := spaceAPI.ListAuditors(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving auditors in the space: %s", err) + } + + managers, err := spaceAPI.ListManagers(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving managers in the space: %s", err) + } + + developers, err := spaceAPI.ListDevelopers(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving developers in space: %s", err) + } + + d.Set("auditors", flex.FlattenSpaceRoleUsers(auditors)) + d.Set("managers", flex.FlattenSpaceRoleUsers(managers)) + d.Set("developers", flex.FlattenSpaceRoleUsers(developers)) + + return nil +} diff --git a/ibm/service/cloudfoundry/data_source_ibm_space_test.go b/ibm/service/cloudfoundry/data_source_ibm_space_test.go new file mode 100644 index 000000000..1779337d7 --- /dev/null +++ b/ibm/service/cloudfoundry/data_source_ibm_space_test.go @@ -0,0 +1,39 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSpaceDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSpaceDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_space.testacc_ds_space", "org", acc.CfOrganization), + resource.TestCheckResourceAttr("data.ibm_space.testacc_ds_space", "space", acc.CfSpace), + ), + }, + }, + }) +} + +func testAccCheckIBMSpaceDataSourceConfig() string { + return fmt.Sprintf(` +data "ibm_space" "testacc_ds_space" { + org = "%s" + space = "%s" +}`, acc.CfOrganization, acc.CfSpace) + +} diff --git a/ibm/resource_ibm_app.go b/ibm/service/cloudfoundry/resource_ibm_app.go similarity index 82% rename from ibm/resource_ibm_app.go rename to ibm/service/cloudfoundry/resource_ibm_app.go index f8d07ab2d..c0ddbd5d3 100644 --- a/ibm/resource_ibm_app.go +++ b/ibm/service/cloudfoundry/resource_ibm_app.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" @@ -11,11 +11,14 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" homedir "github.com/mitchellh/go-homedir" ) -func resourceIBMApp() *schema.Resource { +func ResourceIBMApp() *schema.Resource { return &schema.Resource{ Create: resourceIBMAppCreate, Read: resourceIBMAppRead, @@ -115,7 +118,7 @@ func resourceIBMApp() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "port", - ValidateFunc: validateAllowedStringValue([]string{"port", "process"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"port", "process"}), }, "health_check_timeout": { Description: "Timeout in seconds for health checking of an staged app when starting up.", @@ -127,7 +130,7 @@ func resourceIBMApp() *schema.Resource { } func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -183,7 +186,7 @@ func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { log.Println("[INFO] Creating Cloud Foundary Application") app, err := appAPI.Create(appCreatePayload) if err != nil { - return fmt.Errorf("Error creating app: %s", err) + return fmt.Errorf("[ERROR] Error creating app: %s", err) } appGUID := app.Metadata.GUID @@ -196,7 +199,7 @@ func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { for _, routeID := range v.List() { _, err := appAPI.BindRoute(appGUID, routeID.(string)) if err != nil { - return fmt.Errorf("Error binding route %s to app: %s", routeID.(string), err) + return fmt.Errorf("[ERROR] Error binding route %s to app: %s", routeID.(string), err) } } } @@ -209,7 +212,7 @@ func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { } _, err := sbAPI.Create(req) if err != nil { - return fmt.Errorf("Error binding service instance %s to app: %s", svcID.(string), err) + return fmt.Errorf("[ERROR] Error binding service instance %s to app: %s", svcID.(string), err) } } } @@ -221,7 +224,7 @@ func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { _, err = appAPI.Upload(appGUID, applicationZip) if err != nil { - return fmt.Errorf("Error uploading app bits: %s", err) + return fmt.Errorf("[ERROR] Error uploading app bits: %s", err) } err = restartApp(appGUID, d, meta) @@ -233,7 +236,7 @@ func resourceIBMAppCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -242,7 +245,7 @@ func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { appData, err := appAPI.Get(appGUID) if err != nil { - return fmt.Errorf("Error retrieving app details %s : %s", appGUID, err) + return fmt.Errorf("[ERROR] Error retrieving app details %s : %s", appGUID, err) } d.SetId(appData.Metadata.GUID) @@ -252,7 +255,7 @@ func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { d.Set("space_guid", appData.Entity.SpaceGUID) d.Set("disk_quota", appData.Entity.DiskQuota) d.Set("buildpack", appData.Entity.BuildPack) - d.Set("environment_json", Flatten(appData.Entity.EnvironmentJSON)) + d.Set("environment_json", flex.Flatten(appData.Entity.EnvironmentJSON)) d.Set("command", appData.Entity.Command) d.Set("health_check_type", appData.Entity.HealthCheckType) d.Set("health_check_http_endpoint", appData.Entity.HealthCheckHTTPEndpoint) @@ -263,7 +266,7 @@ func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { return err } if len(route) > 0 { - d.Set("route_guid", flattenRoute(route)) + d.Set("route_guid", flex.FlattenRoute(route)) } svcBindings, err := appAPI.ListServiceBindings(appGUID) @@ -271,7 +274,7 @@ func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { return err } if len(svcBindings) > 0 { - d.Set("service_instance_guid", flattenServiceBindings(svcBindings)) + d.Set("service_instance_guid", flex.FlattenServiceBindings(svcBindings)) } return nil @@ -279,7 +282,7 @@ func resourceIBMAppRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -346,7 +349,7 @@ func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { _, err = appAPI.Update(appGUID, appUpdatePayload) if err != nil { - return fmt.Errorf("Error updating application: %s", err) + return fmt.Errorf("[ERROR] Error updating application: %s", err) } //TODO find the digest of the zip and avoid upload if it is same if d.HasChange("app_path") || d.HasChange("app_version") { @@ -357,7 +360,7 @@ func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { log.Println("[DEBUG] Uploading application bits") _, err = appAPI.Upload(appGUID, appZipLoc) if err != nil { - return fmt.Errorf("Error uploading app: %s", err) + return fmt.Errorf("[ERROR] Error uploading app: %s", err) } restartRequired = true } @@ -379,7 +382,7 @@ func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { log.Println("[INFO] Waiting to see any previous staging is on or not") state, err := appAPI.WaitForAppStatus(v2.AppStagedState, appGUID, waitTimeout) if waitTimeout != 0 && (err != nil || state == v2.AppPendingState) { - return fmt.Errorf("The application is still in %s from last operations.Please try again after sometime by increasing timeout value %q", state, err) + return fmt.Errorf("[ERROR] The application is still in %s from last operations.Please try again after sometime by increasing timeout value %q", state, err) }*/ //If restage and restart both are required then we only need restage as that starts over everything @@ -399,7 +402,7 @@ func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { //and spin new ones, so we are waiting till they come up again state, err := appAPI.WaitForInstanceStatus(v2.AppRunningState, appGUID, waitTimeout) if waitTimeout != 0 && (err != nil || state != v2.AppRunningState) { - return fmt.Errorf("All applications instances aren't %s, Current status is %s, %q", v2.AppRunningState, state, err) + return fmt.Errorf("[ERROR] All applications instances aren't %s, Current status is %s, %q", v2.AppRunningState, state, err) } } @@ -407,7 +410,7 @@ func resourceIBMAppUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -416,7 +419,7 @@ func resourceIBMAppDelete(d *schema.ResourceData, meta interface{}) error { err = appAPI.Delete(id, false, true) if err != nil { - return fmt.Errorf("Error deleting app: %s", err) + return fmt.Errorf("[ERROR] Error deleting app: %s", err) } d.SetId("") @@ -424,7 +427,7 @@ func resourceIBMAppDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -438,7 +441,7 @@ func resourceIBMAppExists(d *schema.ResourceData, meta interface{}) (bool, error return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting app: %s", err) } return app.Metadata.GUID == id, nil @@ -450,14 +453,14 @@ func updateRouteGUID(appGUID string, appAPI v2.Apps, d *schema.ResourceData) (er or := ors.(*schema.Set) nr := nrs.(*schema.Set) - remove := expandStringList(or.Difference(nr).List()) - add := expandStringList(nr.Difference(or).List()) + remove := flex.ExpandStringList(or.Difference(nr).List()) + add := flex.ExpandStringList(nr.Difference(or).List()) if len(add) > 0 { for i := range add { _, err = appAPI.BindRoute(appGUID, add[i]) if err != nil { - return fmt.Errorf("Error while binding route %q to application %s: %q", add[i], appGUID, err) + return fmt.Errorf("[ERROR] Error while binding route %q to application %s: %q", add[i], appGUID, err) } } } @@ -465,7 +468,7 @@ func updateRouteGUID(appGUID string, appAPI v2.Apps, d *schema.ResourceData) (er for i := range remove { err = appAPI.UnBindRoute(appGUID, remove[i]) if err != nil { - return fmt.Errorf("Error while un-binding route %q from application %s: %q", add[i], appGUID, err) + return fmt.Errorf("[ERROR] Error while un-binding route %q from application %s: %q", add[i], appGUID, err) } } } @@ -474,7 +477,7 @@ func updateRouteGUID(appGUID string, appAPI v2.Apps, d *schema.ResourceData) (er } func updateServiceInstanceGUID(appGUID string, d *schema.ResourceData, meta interface{}) (restageRequired bool, err error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -484,8 +487,8 @@ func updateServiceInstanceGUID(appGUID string, d *schema.ResourceData, meta inte oss, nss := d.GetChange("service_instance_guid") os := oss.(*schema.Set) ns := nss.(*schema.Set) - remove := expandStringList(os.Difference(ns).List()) - add := expandStringList(ns.Difference(os).List()) + remove := flex.ExpandStringList(os.Difference(ns).List()) + add := flex.ExpandStringList(ns.Difference(os).List()) if len(add) > 0 { for i := range add { @@ -495,7 +498,7 @@ func updateServiceInstanceGUID(appGUID string, d *schema.ResourceData, meta inte } _, err = sbAPI.Create(sbPayload) if err != nil { - err = fmt.Errorf("Error while binding service instance %s to application %s: %q", add[i], appGUID, err) + err = fmt.Errorf("[ERROR] Error while binding service instance %s to application %s: %q", add[i], appGUID, err) return } restageRequired = true @@ -522,7 +525,7 @@ func updateServiceInstanceGUID(appGUID string, d *schema.ResourceData, meta inte } err = appAPI.DeleteServiceBindings(appGUID, sbIds...) if err != nil { - err = fmt.Errorf("Error while un-binding service instances %s to application %s: %q", remove, appGUID, err) + err = fmt.Errorf("[ERROR] Error while un-binding service instances %s to application %s: %q", remove, appGUID, err) return } } @@ -530,7 +533,7 @@ func updateServiceInstanceGUID(appGUID string, d *schema.ResourceData, meta inte return } func restartApp(appGUID string, d *schema.ResourceData, meta interface{}) error { - cfClient, _ := meta.(ClientSession).MccpAPI() + cfClient, _ := meta.(conns.ClientSession).MccpAPI() appAPI := cfClient.Apps() appUpdatePayload := v2.AppRequest{ @@ -539,13 +542,13 @@ func restartApp(appGUID string, d *schema.ResourceData, meta interface{}) error log.Println("[INFO] Stopping Application") _, err := appAPI.Update(appGUID, appUpdatePayload) if err != nil { - return fmt.Errorf("Error updating application status to %s %s", v2.AppStoppedState, err) + return fmt.Errorf("[ERROR] Error updating application status to %s %s", v2.AppStoppedState, err) } waitTimeout := time.Duration(d.Get("wait_time_minutes").(int)) * time.Minute log.Println("[INFO] Starting Application") status, err := appAPI.Start(appGUID, waitTimeout) if err != nil { - return fmt.Errorf("Error while starting application : %s", err) + return fmt.Errorf("[ERROR] Error while starting application : %s", err) } if waitTimeout != 0 { return checkAppStatus(status) @@ -554,14 +557,14 @@ func restartApp(appGUID string, d *schema.ResourceData, meta interface{}) error } func restageApp(appGUID string, d *schema.ResourceData, meta interface{}) error { - cfClient, _ := meta.(ClientSession).MccpAPI() + cfClient, _ := meta.(conns.ClientSession).MccpAPI() appAPI := cfClient.Apps() log.Println("[INFO] Restage Application") waitTimeout := time.Duration(d.Get("wait_time_minutes").(int)) * time.Minute status, err := appAPI.Restage(appGUID, waitTimeout) if err != nil { - return fmt.Errorf("Error while restaging application : %s", err) + return fmt.Errorf("[ERROR] Error while restaging application : %s", err) } if waitTimeout != 0 { return checkAppStatus(status) @@ -571,10 +574,10 @@ func restageApp(appGUID string, d *schema.ResourceData, meta interface{}) error func checkAppStatus(status *v2.AppState) error { if status.PackageState != v2.AppStagedState { - return fmt.Errorf("Applications couldn't be staged, current status is %s", status.PackageState) + return fmt.Errorf("[ERROR] Applications couldn't be staged, current status is %s", status.PackageState) } if status.InstanceState != v2.AppRunningState { - return fmt.Errorf("All applications instances aren't %s, Current status is %s", v2.AppRunningState, status.InstanceState) + return fmt.Errorf("[ERROR] All applications instances aren't %s, Current status is %s", v2.AppRunningState, status.InstanceState) } return nil } @@ -585,7 +588,7 @@ func processAppZipPath(path string) (string, error) { return path, fmt.Errorf("home directory in the given path %s couldn't be expanded", path) } if !helpers.FileExists(applicationZip) { - return path, fmt.Errorf("The given app path: %s doesn't exist", path) + return path, fmt.Errorf("[ERROR] The given app path: %s doesn't exist", path) } return applicationZip, nil } diff --git a/ibm/resource_ibm_app_domain_private.go b/ibm/service/cloudfoundry/resource_ibm_app_domain_private.go similarity index 78% rename from ibm/resource_ibm_app_domain_private.go rename to ibm/service/cloudfoundry/resource_ibm_app_domain_private.go index fa963879a..f645c04e9 100644 --- a/ibm/resource_ibm_app_domain_private.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_domain_private.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" v2 "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMAppDomainPrivate() *schema.Resource { +func ResourceIBMAppDomainPrivate() *schema.Resource { return &schema.Resource{ Create: resourceIBMAppDomainPrivateCreate, Read: resourceIBMAppDomainPrivateRead, @@ -27,7 +29,7 @@ func resourceIBMAppDomainPrivate() *schema.Resource { Required: true, ForceNew: true, Description: "The name of the domain", - ValidateFunc: validateDomainName, + ValidateFunc: validate.ValidateDomainName, }, "org_guid": { @@ -47,7 +49,7 @@ func resourceIBMAppDomainPrivate() *schema.Resource { } func resourceIBMAppDomainPrivateCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -61,7 +63,7 @@ func resourceIBMAppDomainPrivateCreate(d *schema.ResourceData, meta interface{}) prdomain, err := cfClient.PrivateDomains().Create(params) if err != nil { - return fmt.Errorf("Error creating private domain: %s", err) + return fmt.Errorf("[ERROR] Error creating private domain: %s", err) } d.SetId(prdomain.Metadata.GUID) @@ -75,7 +77,7 @@ func resourceIBMAppDomainPrivateUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMAppDomainPrivateRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -83,7 +85,7 @@ func resourceIBMAppDomainPrivateRead(d *schema.ResourceData, meta interface{}) e prdomain, err := cfClient.PrivateDomains().Get(prdomainGUID) if err != nil { - return fmt.Errorf("Error retrieving private domain: %s", err) + return fmt.Errorf("[ERROR] Error retrieving private domain: %s", err) } d.Set("name", prdomain.Entity.Name) d.Set("org_guid", prdomain.Entity.OwningOrganizationGUID) @@ -92,7 +94,7 @@ func resourceIBMAppDomainPrivateRead(d *schema.ResourceData, meta interface{}) e } func resourceIBMAppDomainPrivateDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -101,7 +103,7 @@ func resourceIBMAppDomainPrivateDelete(d *schema.ResourceData, meta interface{}) err = cfClient.PrivateDomains().Delete(prdomainGUID, false) if err != nil { - return fmt.Errorf("Error deleting private domain: %s", err) + return fmt.Errorf("[ERROR] Error deleting private domain: %s", err) } d.SetId("") @@ -110,7 +112,7 @@ func resourceIBMAppDomainPrivateDelete(d *schema.ResourceData, meta interface{}) } func resourceIBMAppDomainPrivateExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -123,7 +125,7 @@ func resourceIBMAppDomainPrivateExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting private app domains: %s", err) } return prdomain.Metadata.GUID == prdomainGUID, nil diff --git a/ibm/resource_ibm_app_domain_private_test.go b/ibm/service/cloudfoundry/resource_ibm_app_domain_private_test.go similarity index 85% rename from ibm/resource_ibm_app_domain_private_test.go rename to ibm/service/cloudfoundry/resource_ibm_app_domain_private_test.go index 03f656216..ee52dcd61 100644 --- a/ibm/resource_ibm_app_domain_private_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_domain_private_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -22,17 +25,17 @@ func TestAccIBMAppDomainPrivate_Basic(t *testing.T) { updateName := fmt.Sprintf("terraformnew%d.com", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainPrivate_basic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppDomainPrivateExists("ibm_app_domain_private.domain", &conf), resource.TestCheckResourceAttr("ibm_app_domain_private.domain", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppDomainPrivate_updateName(updateName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_app_domain_private.domain", "name", updateName), @@ -47,10 +50,10 @@ func TestAccIBMAppDomainPrivate_With_Tags(t *testing.T) { name := fmt.Sprintf("terraform%d.com", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainPrivate_with_tags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppDomainPrivateExists("ibm_app_domain_private.domain", &conf), @@ -58,7 +61,7 @@ func TestAccIBMAppDomainPrivate_With_Tags(t *testing.T) { resource.TestCheckResourceAttr("ibm_app_domain_private.domain", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppDomainPrivate_with_updated_tags(name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_app_domain_private.domain", "name", name), @@ -77,7 +80,7 @@ func testAccCheckIBMAppDomainPrivateExists(n string, obj *mccpv2.PrivateDomainFi return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -94,7 +97,7 @@ func testAccCheckIBMAppDomainPrivateExists(n string, obj *mccpv2.PrivateDomainFi } func testAccCheckIBMAppDomainPrivateDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -112,7 +115,7 @@ func testAccCheckIBMAppDomainPrivateDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("CF private domain still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for CF private domain (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for CF private domain (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -130,7 +133,7 @@ func testAccCheckIBMAppDomainPrivate_basic(name string) string { name = "%s" org_guid = data.ibm_org.orgdata.id } - `, cfOrganization, name) + `, acc.CfOrganization, name) } func testAccCheckIBMAppDomainPrivate_updateName(updateName string) string { @@ -144,7 +147,7 @@ func testAccCheckIBMAppDomainPrivate_updateName(updateName string) string { name = "%s" org_guid = data.ibm_org.orgdata.id } - `, cfOrganization, updateName) + `, acc.CfOrganization, updateName) } func testAccCheckIBMAppDomainPrivate_with_tags(name string) string { @@ -160,7 +163,7 @@ func testAccCheckIBMAppDomainPrivate_with_tags(name string) string { tags = ["one", "two"] } - `, cfOrganization, name) + `, acc.CfOrganization, name) } func testAccCheckIBMAppDomainPrivate_with_updated_tags(name string) string { @@ -175,5 +178,5 @@ func testAccCheckIBMAppDomainPrivate_with_updated_tags(name string) string { org_guid = data.ibm_org.orgdata.id tags = ["one", "two", "three"] } - `, cfOrganization, name) + `, acc.CfOrganization, name) } diff --git a/ibm/resource_ibm_app_domain_shared.go b/ibm/service/cloudfoundry/resource_ibm_app_domain_shared.go similarity index 79% rename from ibm/resource_ibm_app_domain_shared.go rename to ibm/service/cloudfoundry/resource_ibm_app_domain_shared.go index 0f4959264..75ee3a6ea 100644 --- a/ibm/resource_ibm_app_domain_shared.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_domain_shared.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" v2 "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMAppDomainShared() *schema.Resource { +func ResourceIBMAppDomainShared() *schema.Resource { return &schema.Resource{ Create: resourceIBMAppDomainSharedCreate, Read: resourceIBMAppDomainSharedRead, @@ -27,7 +29,7 @@ func resourceIBMAppDomainShared() *schema.Resource { Required: true, ForceNew: true, Description: "The name of the domain", - ValidateFunc: validateDomainName, + ValidateFunc: validate.ValidateDomainName, }, "router_group_guid": { @@ -48,7 +50,7 @@ func resourceIBMAppDomainShared() *schema.Resource { } func resourceIBMAppDomainSharedCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -62,7 +64,7 @@ func resourceIBMAppDomainSharedCreate(d *schema.ResourceData, meta interface{}) shdomain, err := cfClient.SharedDomains().Create(params) if err != nil { - return fmt.Errorf("Error creating shared domain: %s", err) + return fmt.Errorf("[ERROR] Error creating shared domain: %s", err) } d.SetId(shdomain.Metadata.GUID) @@ -76,7 +78,7 @@ func resourceIBMAppDomainSharedUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMAppDomainSharedRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -84,7 +86,7 @@ func resourceIBMAppDomainSharedRead(d *schema.ResourceData, meta interface{}) er shdomain, err := cfClient.SharedDomains().Get(shdomainGUID) if err != nil { - return fmt.Errorf("Error retrieving shared domain: %s", err) + return fmt.Errorf("[ERROR] Error retrieving shared domain: %s", err) } d.Set("name", shdomain.Entity.Name) d.Set("router_group_guid", shdomain.Entity.RouterGroupGUID) @@ -93,7 +95,7 @@ func resourceIBMAppDomainSharedRead(d *schema.ResourceData, meta interface{}) er } func resourceIBMAppDomainSharedDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -102,7 +104,7 @@ func resourceIBMAppDomainSharedDelete(d *schema.ResourceData, meta interface{}) err = cfClient.SharedDomains().Delete(shdomainGUID, false) if err != nil { - return fmt.Errorf("Error deleting shared domain: %s", err) + return fmt.Errorf("[ERROR] Error deleting shared domain: %s", err) } d.SetId("") @@ -111,7 +113,7 @@ func resourceIBMAppDomainSharedDelete(d *schema.ResourceData, meta interface{}) } func resourceIBMAppDomainSharedExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -124,7 +126,7 @@ func resourceIBMAppDomainSharedExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting shared domains: %s", err) } return shdomain.Metadata.GUID == shdomainGUID, nil diff --git a/ibm/resource_ibm_app_domain_shared_test.go b/ibm/service/cloudfoundry/resource_ibm_app_domain_shared_test.go similarity index 85% rename from ibm/resource_ibm_app_domain_shared_test.go rename to ibm/service/cloudfoundry/resource_ibm_app_domain_shared_test.go index 389ab2df0..c500b42ef 100644 --- a/ibm/resource_ibm_app_domain_shared_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_domain_shared_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,10 +24,10 @@ func TestAccIBMAppDomainShared_Basic(t *testing.T) { name := fmt.Sprintf("terraform%d.com", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainShared_basic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppDomainSharedExists("ibm_app_domain_shared.domain", &conf), @@ -41,10 +44,10 @@ func TestAccIBMAppDomainShared_With_Tags(t *testing.T) { name := fmt.Sprintf("terraform%d.com", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppDomainShared_with_tags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppDomainSharedExists("ibm_app_domain_shared.domain", &conf), @@ -52,7 +55,7 @@ func TestAccIBMAppDomainShared_With_Tags(t *testing.T) { resource.TestCheckResourceAttr("ibm_app_domain_shared.domain", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppDomainShared_with_updated_tags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppDomainSharedExists("ibm_app_domain_shared.domain", &conf), @@ -72,7 +75,7 @@ func testAccCheckIBMAppDomainSharedExists(n string, obj *mccpv2.SharedDomainFiel return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -89,7 +92,7 @@ func testAccCheckIBMAppDomainSharedExists(n string, obj *mccpv2.SharedDomainFiel } func testAccCheckIBMAppDomainSharedDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -107,7 +110,7 @@ func testAccCheckIBMAppDomainSharedDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("CF shared domain still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for CF shared domain (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for CF shared domain (%s) to be destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_app_route.go b/ibm/service/cloudfoundry/resource_ibm_app_route.go similarity index 82% rename from ibm/resource_ibm_app_route.go rename to ibm/service/cloudfoundry/resource_ibm_app_route.go index c77f541b1..511b1cae3 100644 --- a/ibm/resource_ibm_app_route.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_route.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" v2 "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMAppRoute() *schema.Resource { +func ResourceIBMAppRoute() *schema.Resource { return &schema.Resource{ Create: resourceIBMAppRouteCreate, Read: resourceIBMAppRouteRead, @@ -47,14 +49,14 @@ func resourceIBMAppRoute() *schema.Resource { Description: "The port of the route. Supported for domains of TCP router groups only.", Optional: true, Type: schema.TypeInt, - ValidateFunc: validateRoutePort, + ValidateFunc: validate.ValidateRoutePort, }, "path": { Description: "The path for a route as raw text.Paths must be between 2 and 128 characters.Paths must start with a forward slash '/'.Paths must not contain a '?'", Optional: true, Type: schema.TypeString, - ValidateFunc: validateRoutePath, + ValidateFunc: validate.ValidateRoutePath, }, "tags": { @@ -68,7 +70,7 @@ func resourceIBMAppRoute() *schema.Resource { } func resourceIBMAppRouteCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -95,7 +97,7 @@ func resourceIBMAppRouteCreate(d *schema.ResourceData, meta interface{}) error { route, err := cfClient.Routes().Create(params) if err != nil { - return fmt.Errorf("Error creating route: %s", err) + return fmt.Errorf("[ERROR] Error creating route: %s", err) } d.SetId(route.Metadata.GUID) @@ -104,7 +106,7 @@ func resourceIBMAppRouteCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppRouteRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -112,7 +114,7 @@ func resourceIBMAppRouteRead(d *schema.ResourceData, meta interface{}) error { route, err := cfClient.Routes().Get(routeGUID) if err != nil { - return fmt.Errorf("Error retrieving route: %s", err) + return fmt.Errorf("[ERROR] Error retrieving route: %s", err) } d.Set("host", route.Entity.Host) @@ -127,7 +129,7 @@ func resourceIBMAppRouteRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMAppRouteUpdate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -149,13 +151,13 @@ func resourceIBMAppRouteUpdate(d *schema.ResourceData, meta interface{}) error { _, err = cfClient.Routes().Update(routeGUID, params) if err != nil { - return fmt.Errorf("Error updating route: %s", err) + return fmt.Errorf("[ERROR] Error updating route: %s", err) } return resourceIBMAppRouteRead(d, meta) } func resourceIBMAppRouteDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -163,7 +165,7 @@ func resourceIBMAppRouteDelete(d *schema.ResourceData, meta interface{}) error { err = cfClient.Routes().Delete(routeGUID, false) if err != nil { - return fmt.Errorf("Error deleting route: %s", err) + return fmt.Errorf("[ERROR] Error deleting route: %s", err) } d.SetId("") @@ -171,7 +173,7 @@ func resourceIBMAppRouteDelete(d *schema.ResourceData, meta interface{}) error { return nil } func resourceIBMAppRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -184,7 +186,7 @@ func resourceIBMAppRouteExists(d *schema.ResourceData, meta interface{}) (bool, return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting app routes: %s", err) } return route.Metadata.GUID == routeGUID, nil diff --git a/ibm/resource_ibm_app_route_test.go b/ibm/service/cloudfoundry/resource_ibm_app_route_test.go similarity index 86% rename from ibm/resource_ibm_app_route_test.go rename to ibm/service/cloudfoundry/resource_ibm_app_route_test.go index b7dfc00ce..565b116fa 100644 --- a/ibm/resource_ibm_app_route_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_route_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -22,11 +25,11 @@ func TestAccIBMAppRoute_Basic(t *testing.T) { updateHost := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppRouteDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppRoute_basic(host), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppRouteExists("ibm_app_route.route", &conf), @@ -34,7 +37,7 @@ func TestAccIBMAppRoute_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_app_route.route", "path", "/app"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppRoute_updatePath(host), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppRouteExists("ibm_app_route.route", &conf), @@ -42,7 +45,7 @@ func TestAccIBMAppRoute_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_app_route.route", "path", "/app1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppRoute_updateHost(updateHost), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_app_route.route", "host", updateHost), @@ -58,18 +61,18 @@ func TestAccIBMAppRoute_With_Tags(t *testing.T) { host := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppRouteDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppRoute_with_tags(host), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppRouteExists("ibm_app_route.route", &conf), resource.TestCheckResourceAttr("ibm_app_route.route", "tags.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppRoute_with_updated_tags(host), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppRouteExists("ibm_app_route.route", &conf), @@ -81,7 +84,7 @@ func TestAccIBMAppRoute_With_Tags(t *testing.T) { } func testAccCheckIBMAppRouteDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -99,7 +102,7 @@ func testAccCheckIBMAppRouteDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("CF route still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for CF route (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for CF route (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -114,7 +117,7 @@ func testAccCheckIBMAppRouteExists(n string, obj *mccpv2.RouteFields) resource.T return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -148,7 +151,7 @@ func testAccCheckIBMAppRoute_basic(host string) string { host = "%s" path = "/app" } - `, cfOrganization, cfSpace, host) + `, acc.CfOrganization, acc.CfSpace, host) } func testAccCheckIBMAppRoute_updatePath(host string) string { @@ -169,7 +172,7 @@ func testAccCheckIBMAppRoute_updatePath(host string) string { host = "%s" path = "/app1" } - `, cfOrganization, cfSpace, host) + `, acc.CfOrganization, acc.CfSpace, host) } func testAccCheckIBMAppRoute_updateHost(updateHost string) string { @@ -189,7 +192,7 @@ func testAccCheckIBMAppRoute_updateHost(updateHost string) string { space_guid = data.ibm_space.spacedata.id host = "%s" } - `, cfOrganization, cfSpace, updateHost) + `, acc.CfOrganization, acc.CfSpace, updateHost) } func testAccCheckIBMAppRoute_with_tags(host string) string { @@ -211,7 +214,7 @@ func testAccCheckIBMAppRoute_with_tags(host string) string { path = "/app" tags = ["one"] } - `, cfOrganization, cfSpace, host) + `, acc.CfOrganization, acc.CfSpace, host) } func testAccCheckIBMAppRoute_with_updated_tags(host string) string { @@ -233,5 +236,5 @@ func testAccCheckIBMAppRoute_with_updated_tags(host string) string { path = "/app" tags = ["one", "two"] } - `, cfOrganization, cfSpace, host) + `, acc.CfOrganization, acc.CfSpace, host) } diff --git a/ibm/resource_ibm_app_test.go b/ibm/service/cloudfoundry/resource_ibm_app_test.go similarity index 89% rename from ibm/resource_ibm_app_test.go rename to ibm/service/cloudfoundry/resource_ibm_app_test.go index 7ee57d273..d77de2aec 100644 --- a/ibm/resource_ibm_app_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_app_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,12 +20,12 @@ import ( func TestAccIBMApp_Invalid_Application_Path(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppInvalidPath(name), ExpectError: regexp.MustCompile(`The given app path: doesn't exist`), }, @@ -36,19 +39,19 @@ func TestAccIBMApp_Basic(t *testing.T) { updatedName := fmt.Sprintf("terraform_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppCreate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), resource.TestCheckResourceAttr("ibm_app.app", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppUpdate(updatedName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_app.app", "name", updatedName), @@ -69,12 +72,12 @@ func TestAccIBMApp_with_routes(t *testing.T) { route2 := fmt.Sprintf("terraform-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppBindRoute(name, route1), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -86,7 +89,7 @@ func TestAccIBMApp_with_routes(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "route_guid.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppAddMultipleRoute(name, route1, route2), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -98,7 +101,7 @@ func TestAccIBMApp_with_routes(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "route_guid.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppUnBindRoute(name, route1, route2), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -123,12 +126,12 @@ func TestAccIBMApp_with_service_instances(t *testing.T) { serviceName2 := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppBindService(name, route, serviceName1), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -141,7 +144,7 @@ func TestAccIBMApp_with_service_instances(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "service_instance_guid.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppAddMultipleService(name, route, serviceName1, serviceName2), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -154,7 +157,7 @@ func TestAccIBMApp_with_service_instances(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "service_instance_guid.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppUnBindService(name, route, serviceName1, serviceName2), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -179,12 +182,12 @@ func TestAccIBMApp_With_Tags(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppCreate_With_Tags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -192,7 +195,7 @@ func TestAccIBMApp_With_Tags(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppCreate_With_Updated_Tags(name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_app.app", "name", name), @@ -208,12 +211,12 @@ func TestAccIBMApp_With_Health_Check(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMAppDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMAppWithHealthCheck(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -225,7 +228,7 @@ func TestAccIBMApp_With_Health_Check(t *testing.T) { resource.TestCheckResourceAttr("ibm_app.app", "health_check_timeout", "120"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMAppWithHealthCheckUpdate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMAppExists("ibm_app.app", &conf), @@ -242,7 +245,7 @@ func TestAccIBMApp_With_Health_Check(t *testing.T) { } func testAccCheckIBMAppDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -270,7 +273,7 @@ func testAccCheckIBMAppExists(n string, obj *mccpv2.AppFields) resource.TestChec return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -302,7 +305,7 @@ func testAccCheckIBMAppInvalidPath(name string) string { buildpack = "sdk-for-nodejs" } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -317,11 +320,11 @@ func testAccCheckIBMAppCreate(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 90 buildpack = "sdk-for-nodejs" } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -335,7 +338,7 @@ func testAccCheckIBMAppUpdate(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" disk_quota = 512 @@ -346,7 +349,7 @@ func testAccCheckIBMAppUpdate(name string) string { "test" = "test1" } } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -371,7 +374,7 @@ func testAccCheckIBMAppBindRoute(name, route1 string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -383,7 +386,7 @@ func testAccCheckIBMAppBindRoute(name, route1 string) string { "test" = "test1" } } -`, cfOrganization, cfSpace, route1, name) +`, acc.CfOrganization, acc.CfSpace, route1, name) } @@ -414,7 +417,7 @@ func testAccCheckIBMAppAddMultipleRoute(name, route1, route2 string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -427,7 +430,7 @@ func testAccCheckIBMAppAddMultipleRoute(name, route1, route2 string) string { "test" = "test1" } } -`, cfOrganization, cfSpace, route1, route2, name) +`, acc.CfOrganization, acc.CfSpace, route1, route2, name) } @@ -458,7 +461,7 @@ func testAccCheckIBMAppUnBindRoute(name, route1, route2 string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -472,7 +475,7 @@ func testAccCheckIBMAppUnBindRoute(name, route1, route2 string) string { "test" = "test1" } } -`, cfOrganization, cfSpace, route1, route2, name) +`, acc.CfOrganization, acc.CfSpace, route1, route2, name) } @@ -505,7 +508,7 @@ func testAccCheckIBMAppBindService(name, route1, serviceName string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -519,7 +522,7 @@ func testAccCheckIBMAppBindService(name, route1, serviceName string) string { "test" = "test1" } } -`, cfOrganization, cfSpace, route1, serviceName, name) +`, acc.CfOrganization, acc.CfSpace, route1, serviceName, name) } @@ -560,7 +563,7 @@ func testAccCheckIBMAppAddMultipleService(name, route, serviceName1, serviceName resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -575,7 +578,7 @@ func testAccCheckIBMAppAddMultipleService(name, route, serviceName1, serviceName "test" = "test1" } } -`, cfOrganization, cfSpace, route, serviceName1, serviceName2, name) +`, acc.CfOrganization, acc.CfSpace, route, serviceName1, serviceName2, name) } @@ -616,7 +619,7 @@ func testAccCheckIBMAppUnBindService(name, route1, serviceName1, serviceName2 st resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 20 buildpack = "sdk-for-nodejs" instances = 1 @@ -633,7 +636,7 @@ func testAccCheckIBMAppUnBindService(name, route1, serviceName1, serviceName2 st "floatval" = 0.67 } } -`, cfOrganization, cfSpace, route1, serviceName1, serviceName2, name) +`, acc.CfOrganization, acc.CfSpace, route1, serviceName1, serviceName2, name) } @@ -648,12 +651,12 @@ func testAccCheckIBMAppCreate_With_Tags(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 90 buildpack = "sdk-for-nodejs" tags = ["one", "two"] } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -668,12 +671,12 @@ func testAccCheckIBMAppCreate_With_Updated_Tags(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 90 buildpack = "sdk-for-nodejs" tags = ["one", "two", "three"] } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -687,14 +690,14 @@ func testAccCheckIBMAppWithHealthCheck(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 90 health_check_timeout = 120 instances = 1 disk_quota = 512 memory = 128 } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } @@ -708,13 +711,13 @@ func testAccCheckIBMAppWithHealthCheckUpdate(name string) string { resource "ibm_app" "app" { name = "%s" space_guid = data.ibm_space.space.id - app_path = "test-fixtures/app1.zip" + app_path = "../../test-fixtures/app1.zip" wait_time_minutes = 90 health_check_timeout = 180 instances = 1 disk_quota = 512 memory = 128 } -`, cfOrganization, cfSpace, name) +`, acc.CfOrganization, acc.CfSpace, name) } diff --git a/ibm/service/cloudfoundry/resource_ibm_org.go b/ibm/service/cloudfoundry/resource_ibm_org.go new file mode 100644 index 000000000..d559b95f0 --- /dev/null +++ b/ibm/service/cloudfoundry/resource_ibm_org.go @@ -0,0 +1,372 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry + +import ( + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +var ( + errManagerRoleAssociation = errors.New("[ERROR]please remove your email from the manager role and try again. " + + "This is done to avoid spurious diffs because a user creating an organization gets the manager role by default.") + + errUserRoleAssociation = errors.New("[ERROR]please remove your email from the user role and try again. " + + "This is done to avoid spurious diffs because a user creating an organization automatically gets the userrole by default.") +) + +func ResourceIBMOrg() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMOrgCreate, + Read: resourceIBMOrgRead, + Delete: resourceIBMOrgDelete, + Update: resourceIBMOrgUpdate, + Exists: resourceIBMOrgExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Org name, for example myorg@domain", + Type: schema.TypeString, + Required: true, + }, + "org_quota_definition_guid": { + Description: "Org quota guid", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "billing_managers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have billing manager role in this org, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "managers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have manager role in this org, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "auditors": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have auditor role in this org, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "users": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have user role in this org, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + } +} +func resourceIBMOrgCreate(d *schema.ResourceData, meta interface{}) error { + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + orgAPI := cfAPI.Organizations() + orgName := d.Get("name").(string) + req := mccpv2.OrgCreateRequest{ + Name: orgName, + } + if orgQuotaDefinitionGUID, ok := d.GetOk("org_quota_definition_guid"); ok { + req.OrgQuotaDefinitionGUID = orgQuotaDefinitionGUID.(string) + } + orgFields, err := orgAPI.Create(req) + if err != nil { + return fmt.Errorf("[ERROR] Error creating organisation: %s", err) + } + orgGUID := orgFields.Metadata.GUID + d.SetId(orgGUID) + + return resourceIBMOrgUpdate(d, meta) +} + +func resourceIBMOrgRead(d *schema.ResourceData, meta interface{}) error { + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + orgAPI := cfAPI.Organizations() + id := d.Id() + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + orgOwnerID := userDetails.UserEmail + orgFields, err := orgAPI.Get(id) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving organisation: %s", err) + } + d.Set("name", orgFields.Entity.Name) + billingManager, err := orgAPI.ListBillingManager(id) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving billing manager in the org: %s", err) + } + managers, err := orgAPI.ListManager(id) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving managers in the org: %s", err) + } + auditors, err := orgAPI.ListAuditors(id) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving auditors in space: %s", err) + } + users, err := orgAPI.ListUsers(id) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving users in space: %s", err) + } + if len(auditors) > 0 { + d.Set("auditors", flex.FlattenOrgRole(auditors, "")) + } + if len(managers) > 0 { + d.Set("managers", flex.FlattenOrgRole(managers, orgOwnerID)) + } + if len(billingManager) > 0 { + d.Set("billing_managers", flex.FlattenOrgRole(billingManager, "")) + } + if len(users) > 0 { + d.Set("users", flex.FlattenOrgRole(users, orgOwnerID)) + } + if orgFields.Entity.OrgQuotaDefinitionGUID != "" { + d.Set("org_quota_definition_guid", orgFields.Entity.OrgQuotaDefinitionGUID) + } + return nil +} + +func resourceIBMOrgUpdate(d *schema.ResourceData, meta interface{}) error { + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + orgAPI := cfAPI.Organizations() + id := d.Id() + + req := mccpv2.OrgUpdateRequest{} + if d.HasChange("name") { + req.Name = helpers.String(d.Get("name").(string)) + } + _, err = orgAPI.Update(id, req) + if err != nil { + return fmt.Errorf("[ERROR] Error updating organisation: %s", err) + } + err = updateOrgBillingManagers(orgAPI, id, d) + if err != nil { + return err + } + err = updateOrgManagers(meta, id, d) + if err != nil { + return err + } + err = updateOrgAuditors(orgAPI, id, d) + if err != nil { + return err + } + err = updateOrgUsers(meta, id, d) + if err != nil { + return err + } + + return resourceIBMOrgRead(d, meta) +} + +func resourceIBMOrgDelete(d *schema.ResourceData, meta interface{}) error { + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + orgAPI := cfAPI.Organizations() + id := d.Id() + err = orgAPI.Delete(id, false) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting organisation: %s", err) + } + d.SetId("") + return nil +} + +func resourceIBMOrgExists(d *schema.ResourceData, meta interface{}) (bool, error) { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return false, err + } + id := d.Id() + org, err := cfClient.Organizations().Get(id) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error getting Organization: %s", err) + } + return org.Metadata.GUID == id, nil +} + +func updateOrgBillingManagers(api mccpv2.Organizations, orgGUID string, d *schema.ResourceData) error { + if !d.HasChange("billing_managers") { + return nil + } + var remove, add []string + o, n := d.GetChange("billing_managers") + os := o.(*schema.Set) + ns := n.(*schema.Set) + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + if len(add) > 0 { + for _, d := range add { + _, err := api.AssociateBillingManager(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating billing manager (%s) with org %s : %s", d, orgGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateBillingManager(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating billing manager (%s) with org %s : %s", d, orgGUID, err) + } + } + } + return nil +} + +func updateOrgManagers(meta interface{}, orgGUID string, d *schema.ResourceData) error { + if !d.HasChange("managers") { + return nil + } + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + api := cfAPI.Organizations() + + var remove, add []string + o, n := d.GetChange("managers") + os := o.(*schema.Set) + ns := n.(*schema.Set) + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + orgOwnerID := userDetails.UserEmail + + if len(add) > 0 { + for _, d := range add { + if d == orgOwnerID { + return fmt.Errorf("[ERROR] Error associating user (%s) with manager role, %v", d, errManagerRoleAssociation) + } + _, err := api.AssociateManager(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating manager (%s) with org %s : %s", d, orgGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateManager(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating manager (%s) with org %s : %s", d, orgGUID, err) + } + } + } + return nil +} +func updateOrgAuditors(api mccpv2.Organizations, orgGUID string, d *schema.ResourceData) error { + if !d.HasChange("auditors") { + return nil + } + var remove, add []string + o, n := d.GetChange("auditors") + os := o.(*schema.Set) + ns := n.(*schema.Set) + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + if len(add) > 0 { + for _, d := range add { + _, err := api.AssociateAuditor(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating auditor (%s) with org %s : %s", d, orgGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateAuditor(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating auditor (%s) with org %s : %s", d, orgGUID, err) + } + } + } + return nil +} + +func updateOrgUsers(meta interface{}, orgGUID string, d *schema.ResourceData) error { + if !d.HasChange("users") { + return nil + } + var remove, add []string + o, n := d.GetChange("users") + os := o.(*schema.Set) + ns := n.(*schema.Set) + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + cfAPI, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + api := cfAPI.Organizations() + if len(add) > 0 { + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + orgOwnerID := userDetails.UserEmail + for _, d := range add { + if d == orgOwnerID { + return fmt.Errorf("[ERROR] Error associating user (%s) with User role, %v", d, errUserRoleAssociation) + } + _, err := api.AssociateUser(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating user (%s) with org %s : %s", d, orgGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateUser(orgGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating user (%s) with org %s : %s", d, orgGUID, err) + } + } + } + return nil +} diff --git a/ibm/resource_ibm_org_test.go b/ibm/service/cloudfoundry/resource_ibm_org_test.go similarity index 86% rename from ibm/resource_ibm_org_test.go rename to ibm/service/cloudfoundry/resource_ibm_org_test.go index fe8733add..338f0694c 100644 --- a/ibm/resource_ibm_org_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_org_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -20,18 +23,18 @@ func TestAccIBMOrg_Basic(t *testing.T) { updatedName := fmt.Sprintf("terraform_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMOrgDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMOrgCreate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMOrgExists("ibm_org.testacc_org", &conf), resource.TestCheckResourceAttr("ibm_org.testacc_org", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMOrgUpdate(updatedName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_org.testacc_org", "name", updatedName), @@ -47,18 +50,18 @@ func TestAccIBMOrg_Basic_Import(t *testing.T) { resourceName := "ibm_org.testacc_org" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMOrgDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMOrgCreate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMOrgExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "name", name), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -73,12 +76,12 @@ func TestAccIBMOrg_with_roles(t *testing.T) { updatedName := fmt.Sprintf("terraform_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMOrgDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMOrgCreateWithRoles(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMOrgExists("ibm_org.testacc_org", &conf), @@ -89,7 +92,7 @@ func TestAccIBMOrg_with_roles(t *testing.T) { resource.TestCheckResourceAttr("ibm_org.testacc_org", "users.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMOrgUpdateWithRoles(updatedName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_org.testacc_org", "name", updatedName), @@ -108,11 +111,11 @@ func TestAccIBMOrg_With_Tags(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMOrgDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMOrgWithTags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMOrgExists("ibm_org.testacc_org", &conf), @@ -120,7 +123,7 @@ func TestAccIBMOrg_With_Tags(t *testing.T) { resource.TestCheckResourceAttr("ibm_org.testacc_org", "tags.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMOrgWithUpdatedTags(name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_org.testacc_org", "tags.#", "2"), @@ -137,7 +140,7 @@ func testAccCheckIBMOrgExists(n string, obj *mccpv2.OrganizationFields) resource if !ok { return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -152,7 +155,7 @@ func testAccCheckIBMOrgExists(n string, obj *mccpv2.OrganizationFields) resource } func testAccCheckIBMOrgDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -164,7 +167,7 @@ func testAccCheckIBMOrgDestroy(s *terraform.State) error { _, err := cfClient.Organizations().Get(orgGUID) if err != nil { if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() != 404 { - return fmt.Errorf("Error waiting for Organization (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for Organization (%s) to be destroyed: %s", rs.Primary.ID, err) } } } @@ -195,7 +198,7 @@ func testAccCheckIBMOrgCreateWithRoles(name string) string { users = ["%s"] } -`, name, ibmid1, ibmid1, ibmid1, ibmid1) +`, name, acc.Ibmid1, acc.Ibmid1, acc.Ibmid1, acc.Ibmid1) } func testAccCheckIBMOrgUpdateWithRoles(updatedName string) string { @@ -208,7 +211,7 @@ func testAccCheckIBMOrgUpdateWithRoles(updatedName string) string { users = ["%s"] } -`, updatedName, ibmid2, ibmid2, ibmid1, ibmid2, ibmid2) +`, updatedName, acc.Ibmid2, acc.Ibmid2, acc.Ibmid1, acc.Ibmid2, acc.Ibmid2) } func testAccCheckIBMOrgWithTags(name string) string { diff --git a/ibm/resource_ibm_service_instance.go b/ibm/service/cloudfoundry/resource_ibm_service_instance.go similarity index 83% rename from ibm/resource_ibm_service_instance.go rename to ibm/service/cloudfoundry/resource_ibm_service_instance.go index 045dd889b..aeea18dbd 100644 --- a/ibm/resource_ibm_service_instance.go +++ b/ibm/service/cloudfoundry/resource_ibm_service_instance.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" @@ -11,6 +11,8 @@ import ( "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -21,7 +23,7 @@ const ( svcInstanceFailStatus = "failed" ) -func resourceIBMServiceInstance() *schema.Resource { +func ResourceIBMServiceInstance() *schema.Resource { return &schema.Resource{ Create: resourceIBMServiceInstanceCreate, Read: resourceIBMServiceInstanceRead, @@ -119,7 +121,7 @@ func resourceIBMServiceInstance() *schema.Resource { } func resourceIBMServiceInstanceCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -135,12 +137,12 @@ func resourceIBMServiceInstanceCreate(d *schema.ResourceData, meta interface{}) serviceOff, err := cfClient.ServiceOfferings().FindByLabel(serviceName) if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) } servicePlan, err := cfClient.ServicePlans().FindPlanInServiceOffering(serviceOff.GUID, plan) if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) } svcInst.PlanGUID = servicePlan.GUID @@ -165,22 +167,21 @@ func resourceIBMServiceInstanceCreate(d *schema.ResourceData, meta interface{}) service, err := cfClient.ServiceInstances().Create(svcInst) if err != nil { - return fmt.Errorf("Error creating service: %s", err) + return fmt.Errorf("[ERROR] Error creating service: %s", err) } d.SetId(service.Metadata.GUID) _, err = waitForServiceInstanceAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for create service (%s) to be succeeded: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for create service (%s) to be succeeded: %s", d.Id(), err) } return resourceIBMServiceInstanceRead(d, meta) } func resourceIBMServiceInstanceRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -189,15 +190,15 @@ func resourceIBMServiceInstanceRead(d *schema.ResourceData, meta interface{}) er service, err := cfClient.ServiceInstances().Get(serviceGUID, 1) if err != nil { - return fmt.Errorf("Error retrieving service: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service: %s", err) } servicePlanGUID := service.Entity.ServicePlanGUID d.Set("service_plan_guid", servicePlanGUID) d.Set("space_guid", service.Entity.SpaceGUID) serviceKeys := service.Entity.ServiceKeys - d.Set("service_keys", flattenServiceInstanceCredentials(serviceKeys)) - d.Set("credentials", Flatten(service.Entity.Credentials)) + d.Set("service_keys", flex.FlattenServiceInstanceCredentials(serviceKeys)) + d.Set("credentials", flex.Flatten(service.Entity.Credentials)) d.Set("tags", service.Entity.Tags) d.Set("name", service.Entity.Name) d.Set("dashboard_url", service.Entity.DashboardURL) @@ -214,7 +215,7 @@ func resourceIBMServiceInstanceRead(d *schema.ResourceData, meta interface{}) er } func resourceIBMServiceInstanceUpdate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -231,12 +232,12 @@ func resourceIBMServiceInstanceUpdate(d *schema.ResourceData, meta interface{}) service := d.Get("service").(string) serviceOff, err := cfClient.ServiceOfferings().FindByLabel(service) if err != nil { - return fmt.Errorf("Error retrieving service offering: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) } servicePlan, err := cfClient.ServicePlans().FindPlanInServiceOffering(serviceOff.GUID, plan) if err != nil { - return fmt.Errorf("Error retrieving plan: %s", err) + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) } updateReq.PlanGUID = helpers.String(servicePlan.GUID) @@ -253,20 +254,19 @@ func resourceIBMServiceInstanceUpdate(d *schema.ResourceData, meta interface{}) _, err = cfClient.ServiceInstances().Update(serviceGUID, updateReq) if err != nil { - return fmt.Errorf("Error updating service: %s", err) + return fmt.Errorf("[ERROR] Error updating service: %s", err) } _, err = waitForServiceInstanceAvailable(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for update service (%s) to be succeeded: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for update service (%s) to be succeeded: %s", d.Id(), err) } return resourceIBMServiceInstanceRead(d, meta) } func resourceIBMServiceInstanceDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -274,13 +274,12 @@ func resourceIBMServiceInstanceDelete(d *schema.ResourceData, meta interface{}) err = cfClient.ServiceInstances().Delete(id, true) if err != nil { - return fmt.Errorf("Error deleting service: %s", err) + return fmt.Errorf("[ERROR] Error deleting service: %s", err) } _, err = waitForServiceInstanceDelete(d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for service (%s) to be deleted: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for service (%s) to be deleted: %s", d.Id(), err) } d.SetId("") @@ -288,7 +287,7 @@ func resourceIBMServiceInstanceDelete(d *schema.ResourceData, meta interface{}) return nil } func resourceIBMServiceInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -301,7 +300,7 @@ func resourceIBMServiceInstanceExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting service instance: %s", err) } return service.Metadata.GUID == serviceGUID, nil @@ -324,7 +323,7 @@ func getServiceTags(d *schema.ResourceData) []string { } func waitForServiceInstanceAvailable(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -337,12 +336,12 @@ func waitForServiceInstanceAvailable(d *schema.ResourceData, meta interface{}) ( service, err := cfClient.ServiceInstances().Get(serviceGUID) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The service instance %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The service instance %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } if service.Entity.LastOperation.State == svcInstanceFailStatus { - return service, service.Entity.LastOperation.State, fmt.Errorf("The service instance %s failed: %v", d.Id(), err) + return service, service.Entity.LastOperation.State, fmt.Errorf("[ERROR] The service instance %s failed: %v", d.Id(), err) } return service, service.Entity.LastOperation.State, nil }, @@ -355,7 +354,7 @@ func waitForServiceInstanceAvailable(d *schema.ResourceData, meta interface{}) ( } func waitForServiceInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -372,7 +371,7 @@ func waitForServiceInstanceDelete(d *schema.ResourceData, meta interface{}) (int return nil, "", err } if service.Entity.LastOperation.State == svcInstanceFailStatus { - return service, service.Entity.LastOperation.State, fmt.Errorf("The service instance %s failed to delete: %v", d.Id(), err) + return service, service.Entity.LastOperation.State, fmt.Errorf("[ERROR] The service instance %s failed to delete: %v", d.Id(), err) } return service, service.Entity.LastOperation.State, nil }, diff --git a/ibm/resource_ibm_service_instance_test.go b/ibm/service/cloudfoundry/resource_ibm_service_instance_test.go similarity index 89% rename from ibm/resource_ibm_service_instance_test.go rename to ibm/service/cloudfoundry/resource_ibm_service_instance_test.go index b4593c3b6..5676b8c22 100644 --- a/ibm/resource_ibm_service_instance_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_service_instance_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -22,11 +25,11 @@ func TestAccIBMServiceInstance_Basic(t *testing.T) { updateName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_basic(serviceName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceInstanceExists("ibm_service_instance.service", &conf), @@ -36,7 +39,7 @@ func TestAccIBMServiceInstance_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_service_instance.service", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_updateWithSameName(serviceName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceInstanceExists("ibm_service_instance.service", &conf), @@ -46,7 +49,7 @@ func TestAccIBMServiceInstance_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_service_instance.service", "tags.#", "3"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_update(updateName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_service_instance.service", "name", updateName), @@ -55,7 +58,7 @@ func TestAccIBMServiceInstance_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_service_instance.service", "tags.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_newServiceType(updateName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_service_instance.service", "name", updateName), @@ -75,11 +78,11 @@ func TestAccIBMServiceInstance_import(t *testing.T) { resourceName := "ibm_service_instance.service" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_basic(serviceName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceInstanceExists(resourceName, &conf), @@ -89,7 +92,7 @@ func TestAccIBMServiceInstance_import(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.#", "2"), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -101,7 +104,7 @@ func TestAccIBMServiceInstance_import(t *testing.T) { } func testAccCheckIBMServiceInstanceDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -118,7 +121,7 @@ func testAccCheckIBMServiceInstanceDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("CF service still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for CF service (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for CF service (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -133,7 +136,7 @@ func testAccCheckIBMServiceInstanceExists(n string, obj *mccpv2.ServiceInstanceF return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -164,7 +167,7 @@ func testAccCheckIBMServiceInstance_basic(serviceName string) string { plan = "lite" tags = ["cluster-service", "cluster-bind"] } - `, cfSpace, cfOrganization, serviceName) + `, acc.CfSpace, acc.CfOrganization, serviceName) } func testAccCheckIBMServiceInstance_updateWithSameName(serviceName string) string { @@ -181,7 +184,7 @@ func testAccCheckIBMServiceInstance_updateWithSameName(serviceName string) strin plan = "lite" tags = ["cluster-service", "cluster-bind", "db"] } - `, cfSpace, cfOrganization, serviceName) + `, acc.CfSpace, acc.CfOrganization, serviceName) } func testAccCheckIBMServiceInstance_update(updateName string) string { @@ -198,7 +201,7 @@ func testAccCheckIBMServiceInstance_update(updateName string) string { plan = "lite" tags = ["cluster-service"] } - `, cfSpace, cfOrganization, updateName) + `, acc.CfSpace, acc.CfOrganization, updateName) } func testAccCheckIBMServiceInstance_newServiceType(updateName string) string { @@ -215,7 +218,7 @@ func testAccCheckIBMServiceInstance_newServiceType(updateName string) string { plan = "lite" tags = ["cluster-service"] } - `, cfSpace, cfOrganization, updateName) + `, acc.CfSpace, acc.CfOrganization, updateName) } func TestAccIBMServiceInstance_Discovery_Basic(t *testing.T) { @@ -224,11 +227,11 @@ func TestAccIBMServiceInstance_Discovery_Basic(t *testing.T) { serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_discovery_basic(serviceName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceInstanceExists("ibm_service_instance.service", &conf), @@ -238,7 +241,7 @@ func TestAccIBMServiceInstance_Discovery_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_service_instance.service", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceInstance_discovery_update(serviceName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceInstanceExists("ibm_service_instance.service", &conf), @@ -266,7 +269,7 @@ func testAccCheckIBMServiceInstance_discovery_basic(serviceName string) string { plan = "lite" tags = ["cluster-service", "cluster-bind"] } - `, cfSpace, cfOrganization, serviceName) + `, acc.CfSpace, acc.CfOrganization, serviceName) } func testAccCheckIBMServiceInstance_discovery_update(serviceName string) string { @@ -283,5 +286,5 @@ func testAccCheckIBMServiceInstance_discovery_update(serviceName string) string plan = "lite" tags = ["cluster-service", "cluster-bind", "db"] } - `, cfSpace, cfOrganization, serviceName) + `, acc.CfSpace, acc.CfOrganization, serviceName) } diff --git a/ibm/resource_ibm_service_key.go b/ibm/service/cloudfoundry/resource_ibm_service_key.go similarity index 81% rename from ibm/resource_ibm_service_key.go rename to ibm/service/cloudfoundry/resource_ibm_service_key.go index f4e46b2a3..db9c6001a 100644 --- a/ibm/resource_ibm_service_key.go +++ b/ibm/service/cloudfoundry/resource_ibm_service_key.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry import ( "fmt" "strconv" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMServiceKey() *schema.Resource { +func ResourceIBMServiceKey() *schema.Resource { return &schema.Resource{ Create: resourceIBMServiceKeyCreate, Read: resourceIBMServiceKeyRead, @@ -57,7 +59,7 @@ func resourceIBMServiceKey() *schema.Resource { } func resourceIBMServiceKeyCreate(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -81,7 +83,7 @@ func resourceIBMServiceKeyCreate(d *schema.ResourceData, meta interface{}) error serviceKey, err := cfClient.ServiceKeys().Create(serviceInstanceGUID, name, keyParams) if err != nil { - return fmt.Errorf("Error creating service key: %s", err) + return fmt.Errorf("[ERROR] Error creating service key: %s", err) } d.SetId(serviceKey.Metadata.GUID) @@ -95,7 +97,7 @@ func resourceIBMServiceKeyUpdate(d *schema.ResourceData, meta interface{}) error } func resourceIBMServiceKeyRead(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -103,9 +105,9 @@ func resourceIBMServiceKeyRead(d *schema.ResourceData, meta interface{}) error { serviceKey, err := cfClient.ServiceKeys().Get(serviceKeyGUID) if err != nil { - return fmt.Errorf("Error retrieving service key: %s", err) + return fmt.Errorf("[ERROR] Error retrieving service key: %s", err) } - d.Set("credentials", Flatten(serviceKey.Entity.Credentials)) + d.Set("credentials", flex.Flatten(serviceKey.Entity.Credentials)) d.Set("service_instance_guid", serviceKey.Entity.ServiceInstanceGUID) d.Set("name", serviceKey.Entity.Name) @@ -113,7 +115,7 @@ func resourceIBMServiceKeyRead(d *schema.ResourceData, meta interface{}) error { } func resourceIBMServiceKeyDelete(d *schema.ResourceData, meta interface{}) error { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -122,7 +124,7 @@ func resourceIBMServiceKeyDelete(d *schema.ResourceData, meta interface{}) error err = cfClient.ServiceKeys().Delete(serviceKeyGUID) if err != nil { - return fmt.Errorf("Error deleting service key: %s", err) + return fmt.Errorf("[ERROR] Error deleting service key: %s", err) } d.SetId("") @@ -131,7 +133,7 @@ func resourceIBMServiceKeyDelete(d *schema.ResourceData, meta interface{}) error } func resourceIBMServiceKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - cfClient, err := meta.(ClientSession).MccpAPI() + cfClient, err := meta.(conns.ClientSession).MccpAPI() if err != nil { return false, err } @@ -144,7 +146,7 @@ func resourceIBMServiceKeyExists(d *schema.ResourceData, meta interface{}) (bool return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting service key: %s", err) } return serviceKey.Metadata.GUID == serviceKeyGUID, nil diff --git a/ibm/resource_ibm_service_key_test.go b/ibm/service/cloudfoundry/resource_ibm_service_key_test.go similarity index 86% rename from ibm/resource_ibm_service_key_test.go rename to ibm/service/cloudfoundry/resource_ibm_service_key_test.go index 3e7511291..3192009df 100644 --- a/ibm/resource_ibm_service_key_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_service_key_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -22,11 +25,11 @@ func TestAccIBMServiceKey_Basic(t *testing.T) { serviceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceKey_basic(serviceName, serviceKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceKeyExists("ibm_service_key.serviceKey", &conf), @@ -45,11 +48,11 @@ func TestAccIBMServiceKey_With_Tags(t *testing.T) { serviceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceKey_with_tags(serviceName, serviceKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceKeyExists("ibm_service_key.serviceKey", &conf), @@ -57,7 +60,7 @@ func TestAccIBMServiceKey_With_Tags(t *testing.T) { resource.TestCheckResourceAttr("ibm_service_key.serviceKey", "tags.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMServiceKey_with_updated_tags(serviceName, serviceKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceKeyExists("ibm_service_key.serviceKey", &conf), @@ -75,11 +78,11 @@ func TestAccIBMServiceKey_Parameters(t *testing.T) { serviceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMServiceKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMServiceKey_parameters(serviceName, serviceKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMServiceKeyExists("ibm_service_key.serviceKey", &conf), @@ -100,7 +103,7 @@ func testAccCheckIBMServiceKeyExists(n string, obj *mccpv2.ServiceKeyFields) res return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -117,7 +120,7 @@ func testAccCheckIBMServiceKeyExists(n string, obj *mccpv2.ServiceKeyFields) res } func testAccCheckIBMServiceKeyDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -135,7 +138,7 @@ func testAccCheckIBMServiceKeyDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("CF service key still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for CF service key (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for CF service key (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -162,7 +165,7 @@ func testAccCheckIBMServiceKey_basic(serviceName, serviceKey string) string { name = "%s" service_instance_guid = ibm_service_instance.service.id } - `, cfSpace, cfOrganization, serviceName, serviceKey) + `, acc.CfSpace, acc.CfOrganization, serviceName, serviceKey) } func testAccCheckIBMServiceKey_with_tags(serviceName, serviceKey string) string { @@ -187,7 +190,7 @@ func testAccCheckIBMServiceKey_with_tags(serviceName, serviceKey string) string tags = ["one"] } - `, cfSpace, cfOrganization, serviceName, serviceKey) + `, acc.CfSpace, acc.CfOrganization, serviceName, serviceKey) } func testAccCheckIBMServiceKey_with_updated_tags(serviceName, serviceKey string) string { @@ -211,7 +214,7 @@ func testAccCheckIBMServiceKey_with_updated_tags(serviceName, serviceKey string) service_instance_guid = ibm_service_instance.service.id tags = ["one", "two"] } - `, cfSpace, cfOrganization, serviceName, serviceKey) + `, acc.CfSpace, acc.CfOrganization, serviceName, serviceKey) } func testAccCheckIBMServiceKey_parameters(serviceName, serviceKey string) string { @@ -237,5 +240,5 @@ func testAccCheckIBMServiceKey_parameters(serviceName, serviceKey string) string "HMAC" = true } } - `, cfSpace, cfOrganization, serviceName, serviceKey) + `, acc.CfSpace, acc.CfOrganization, serviceName, serviceKey) } diff --git a/ibm/service/cloudfoundry/resource_ibm_space.go b/ibm/service/cloudfoundry/resource_ibm_space.go new file mode 100644 index 000000000..3649e8a26 --- /dev/null +++ b/ibm/service/cloudfoundry/resource_ibm_space.go @@ -0,0 +1,352 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cloudfoundry + +import ( + "fmt" + + "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMSpace() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMSpaceCreate, + Read: resourceIBMSpaceRead, + Update: resourceIBMSpaceUpdate, + Delete: resourceIBMSpaceDelete, + Exists: resourceIBMSpaceExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name for the space", + }, + "org": { + Description: "The org this space belongs to", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "auditors": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have auditor role in this space, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "managers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have manager role in this space, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "developers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The IBMID of the users who will have developer role in this space, ex - user@example.com", + Set: flex.ResourceIBMVPCHash, + }, + "space_quota": { + Description: "The name of the Space Quota Definition", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + } +} + +func resourceIBMSpaceCreate(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + org := d.Get("org").(string) + name := d.Get("name").(string) + + req := mccpv2.SpaceCreateRequest{ + Name: name, + } + + orgFields, err := cfClient.Organizations().FindByName(org, conns.BluemixRegion) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving org: %s", err) + } + req.OrgGUID = orgFields.GUID + + if spaceQuota, ok := d.GetOk("space_quota"); ok { + quota, err := cfClient.SpaceQuotas().FindByName(spaceQuota.(string), orgFields.GUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving space quota: %s", err) + } + req.SpaceQuotaGUID = quota.GUID + } + + spaceAPI := cfClient.Spaces() + space, err := spaceAPI.Create(req) + if err != nil { + return fmt.Errorf("[ERROR] Error creating space: %s", err) + } + + spaceGUID := space.Metadata.GUID + d.SetId(spaceGUID) + + if developerSet := d.Get("developers").(*schema.Set); len(developerSet.List()) > 0 { + developers := flex.ExpandStringList(developerSet.List()) + for _, d := range developers { + _, err := spaceAPI.AssociateDeveloper(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating developer %s with space %s : %s", d, spaceGUID, err) + } + } + } + + if auditorSet := d.Get("auditors").(*schema.Set); len(auditorSet.List()) > 0 { + auditors := flex.ExpandStringList(auditorSet.List()) + for _, d := range auditors { + _, err := spaceAPI.AssociateAuditor(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating auditor %s with space %s : %s", d, spaceGUID, err) + } + } + + } + if managerSet := d.Get("managers").(*schema.Set); len(managerSet.List()) > 0 { + managers := flex.ExpandStringList(managerSet.List()) + for _, d := range managers { + _, err := spaceAPI.AssociateManager(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating manager %s with space %s : %s", d, spaceGUID, err) + } + } + } + + return resourceIBMSpaceRead(d, meta) +} + +func resourceIBMSpaceRead(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + spaceGUID := d.Id() + + spaceAPI := cfClient.Spaces() + orgAPI := cfClient.Organizations() + spaceDetails, err := spaceAPI.Get(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving space: %s", err) + } + + auditors, err := spaceAPI.ListAuditors(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving auditors in the space: %s", err) + } + + managers, err := spaceAPI.ListManagers(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving managers in the space: %s", err) + } + + developers, err := spaceAPI.ListDevelopers(spaceGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving developers in space: %s", err) + } + + d.Set("auditors", flex.FlattenSpaceRoleUsers(auditors)) + d.Set("managers", flex.FlattenSpaceRoleUsers(managers)) + d.Set("developers", flex.FlattenSpaceRoleUsers(developers)) + + if spaceDetails.Entity.SpaceQuotaGUID != "" { + sqAPI := cfClient.SpaceQuotas() + quota, err := sqAPI.Get(spaceDetails.Entity.SpaceQuotaGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving quotas details for space: %s", err) + } + d.Set("space_quota", quota.Entity.Name) + } + d.Set("name", spaceDetails.Entity.Name) + org, err := orgAPI.Get(spaceDetails.Entity.OrgGUID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving Organization details for space: %s", err) + } + d.Set("org", org.Entity.Name) + return nil +} + +func resourceIBMSpaceUpdate(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + id := d.Id() + + req := mccpv2.SpaceUpdateRequest{} + if d.HasChange("name") { + req.Name = helpers.String(d.Get("name").(string)) + } + + api := cfClient.Spaces() + _, err = api.Update(id, req) + if err != nil { + return fmt.Errorf("[ERROR] Error updating space: %s", err) + } + + err = updateAuditors(api, id, d) + if err != nil { + return err + } + err = updateManagers(api, id, d) + if err != nil { + return err + } + err = updateDevelopers(api, id, d) + if err != nil { + return err + } + return resourceIBMSpaceRead(d, meta) +} + +func resourceIBMSpaceDelete(d *schema.ResourceData, meta interface{}) error { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return err + } + id := d.Id() + + err = cfClient.Spaces().Delete(id, false) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting space: %s", err) + } + + d.SetId("") + return nil +} + +func resourceIBMSpaceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + cfClient, err := meta.(conns.ClientSession).MccpAPI() + if err != nil { + return false, err + } + id := d.Id() + + space, err := cfClient.Spaces().Get(id) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error getting space: %s", err) + } + + return space.Metadata.GUID == id, nil +} + +func updateDevelopers(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { + if !d.HasChange("developers") { + return nil + } + var remove, add []string + o, n := d.GetChange("developers") + os := o.(*schema.Set) + ns := n.(*schema.Set) + + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + + if len(add) > 0 { + for _, d := range add { + _, err := api.AssociateDeveloper(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating developer %s with space %s : %s", d, spaceGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateDeveloper(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating developer %s with space %s : %s", d, spaceGUID, err) + } + } + } + return nil +} + +func updateManagers(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { + if !d.HasChange("managers") { + return nil + } + var remove, add []string + o, n := d.GetChange("managers") + os := o.(*schema.Set) + ns := n.(*schema.Set) + + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + + if len(add) > 0 { + for _, d := range add { + _, err := api.AssociateManager(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating manager %s with space %s : %s", d, spaceGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateManager(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating manager %s with space %s : %s", d, spaceGUID, err) + } + } + } + return nil +} +func updateAuditors(api mccpv2.Spaces, spaceGUID string, d *schema.ResourceData) error { + if !d.HasChange("auditors") { + return nil + } + var remove, add []string + o, n := d.GetChange("auditors") + os := o.(*schema.Set) + ns := n.(*schema.Set) + + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + + if len(add) > 0 { + for _, d := range add { + _, err := api.AssociateAuditor(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error associating auditor %s with space %s : %s", d, spaceGUID, err) + } + } + } + if len(remove) > 0 { + for _, d := range remove { + err := api.DisassociateAuditor(spaceGUID, d) + if err != nil { + return fmt.Errorf("[ERROR] Error dis-associating auditor %s with space %s : %s", d, spaceGUID, err) + } + } + } + return nil +} diff --git a/ibm/resource_ibm_space_test.go b/ibm/service/cloudfoundry/resource_ibm_space_test.go similarity index 77% rename from ibm/resource_ibm_space_test.go rename to ibm/service/cloudfoundry/resource_ibm_space_test.go index f87d2614f..7cd0896f1 100644 --- a/ibm/resource_ibm_space_test.go +++ b/ibm/service/cloudfoundry/resource_ibm_space_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudfoundry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,24 +24,24 @@ func TestAccIBMSpace_Basic(t *testing.T) { updatedName := fmt.Sprintf("terraform_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSpaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSpaceCreate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSpaceExists("ibm_space.space", &conf), - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMSpaceUpdate(updatedName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "name", updatedName), ), }, @@ -52,20 +55,20 @@ func TestAccIBMSpace_Basic_Import(t *testing.T) { resourceName := "ibm_space.space" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSpaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSpaceCreate(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSpaceExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "org", cfOrganization), + resource.TestCheckResourceAttr(resourceName, "org", acc.CfOrganization), resource.TestCheckResourceAttr(resourceName, "name", name), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -80,16 +83,16 @@ func TestAccIBMSpace_with_roles(t *testing.T) { updatedName := fmt.Sprintf("terraform_updated_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSpaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSpaceCreateWithRoles(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSpaceExists("ibm_space.space", &conf), - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "name", name), resource.TestCheckResourceAttr("ibm_space.space", "auditors.#", "1"), resource.TestCheckResourceAttr("ibm_space.space", "managers.#", "1"), @@ -97,10 +100,10 @@ func TestAccIBMSpace_with_roles(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMSpaceUpdateWithRoles(updatedName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "name", updatedName), resource.TestCheckResourceAttr("ibm_space.space", "auditors.#", "1"), resource.TestCheckResourceAttr("ibm_space.space", "managers.#", "2"), @@ -116,25 +119,25 @@ func TestAccIBMSpace_With_Tags(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSpaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSpaceWithTags(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSpaceExists("ibm_space.space", &conf), - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "name", name), resource.TestCheckResourceAttr("ibm_space.space", "tags.#", "1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMSpaceWithUpdatedTags(name), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_space.space", "org", cfOrganization), + resource.TestCheckResourceAttr("ibm_space.space", "org", acc.CfOrganization), resource.TestCheckResourceAttr("ibm_space.space", "tags.#", "2"), ), }, @@ -150,7 +153,7 @@ func testAccCheckIBMSpaceExists(n string, obj *mccpv2.SpaceFields) resource.Test return fmt.Errorf("Not found: %s", n) } - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -167,7 +170,7 @@ func testAccCheckIBMSpaceExists(n string, obj *mccpv2.SpaceFields) resource.Test } func testAccCheckIBMSpaceDestroy(s *terraform.State) error { - cfClient, err := testAccProvider.Meta().(ClientSession).MccpAPI() + cfClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MccpAPI() if err != nil { return err } @@ -182,7 +185,7 @@ func testAccCheckIBMSpaceDestroy(s *terraform.State) error { if err != nil { if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() != 404 { - return fmt.Errorf("Error waiting for Space (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for Space (%s) to be destroyed: %s", rs.Primary.ID, err) } } } @@ -195,7 +198,7 @@ func testAccCheckIBMSpaceCreate(name string) string { resource "ibm_space" "space" { org = "%s" name = "%s" -}`, cfOrganization, name) +}`, acc.CfOrganization, name) } @@ -205,7 +208,7 @@ func testAccCheckIBMSpaceUpdate(updatedName string) string { resource "ibm_space" "space" { org = "%s" name = "%s" -}`, cfOrganization, updatedName) +}`, acc.CfOrganization, updatedName) } @@ -219,7 +222,7 @@ resource "ibm_space" "space" { managers = ["%s"] developers = ["%s"] } -`, cfOrganization, name, ibmid1, ibmid1, ibmid1) +`, acc.CfOrganization, name, acc.Ibmid1, acc.Ibmid1, acc.Ibmid1) } @@ -231,7 +234,7 @@ resource "ibm_space" "space" { auditors = ["%s"] managers = ["%s", "%s"] developers = ["%s"] -}`, cfOrganization, updatedName, ibmid2, ibmid2, ibmid1, ibmid2) +}`, acc.CfOrganization, updatedName, acc.Ibmid2, acc.Ibmid2, acc.Ibmid1, acc.Ibmid2) } @@ -242,7 +245,7 @@ resource "ibm_space" "space" { org = "%s" name = "%s" tags = ["one"] -}`, cfOrganization, name) +}`, acc.CfOrganization, name) } func testAccCheckIBMSpaceWithUpdatedTags(name string) string { @@ -252,6 +255,6 @@ resource "ibm_space" "space" { org = "%s" name = "%s" tags = ["one", "two"] -}`, cfOrganization, name) +}`, acc.CfOrganization, name) } diff --git a/ibm/service/cloudshell/README.md b/ibm/service/cloudshell/README.md new file mode 100644 index 000000000..93da9f96d --- /dev/null +++ b/ibm/service/cloudshell/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Cloud Shell + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Cloud Shell resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cloud_shell_account_settings) +* IBM API Docs: [IBM API Docs for Cloud Shell](https://cloud.ibm.com/apidocs/cloudshell) +* IBM Cloud Shell SDK: [IBM SDK for Cloud Shell](https://github.com/IBM/platform-services-go-sdk/tree/main/ibmcloudshellv1) diff --git a/ibm/data_source_ibm_cloud_shell_account_settings.go b/ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings.go similarity index 77% rename from ibm/data_source_ibm_cloud_shell_account_settings.go rename to ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings.go index fd45c246e..222f43319 100644 --- a/ibm/data_source_ibm_cloud_shell_account_settings.go +++ b/ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings.go @@ -1,71 +1,73 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudshell import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/ibmcloudshellv1" ) -func dataSourceIBMCloudShellAccountSettings() *schema.Resource { +func DataSourceIBMCloudShellAccountSettings() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMCloudShellAccountSettingsRead, Schema: map[string]*schema.Schema{ - "account_id": &schema.Schema{ + "account_id": { Type: schema.TypeString, Required: true, Description: "The account ID in which the account settings belong to.", }, - "rev": &schema.Schema{ + "rev": { Type: schema.TypeString, Computed: true, Description: "Unique revision number for the settings object.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeInt, Computed: true, Description: "Creation timestamp in Unix epoch time.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "IAM ID of creator.", }, - "default_enable_new_features": &schema.Schema{ + "default_enable_new_features": { Type: schema.TypeBool, Computed: true, Description: "You can choose which Cloud Shell features are available in the account and whether any new features are enabled as they become available. The feature settings apply only to the enabled Cloud Shell locations.", }, - "default_enable_new_regions": &schema.Schema{ + "default_enable_new_regions": { Type: schema.TypeBool, Computed: true, Description: "Set whether Cloud Shell is enabled in a specific location for the account. The location determines where user and session data are stored. By default, users are routed to the nearest available location.", }, - "enabled": &schema.Schema{ + "enabled": { Type: schema.TypeBool, Computed: true, Description: "When enabled, Cloud Shell is available to all users in the account.", }, - "features": &schema.Schema{ + "features": { Type: schema.TypeList, Computed: true, Description: "List of Cloud Shell features.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": &schema.Schema{ + "enabled": { Type: schema.TypeBool, Computed: true, Description: "State of the feature.", }, - "key": &schema.Schema{ + "key": { Type: schema.TypeString, Computed: true, Description: "Name of the feature.", @@ -73,18 +75,18 @@ func dataSourceIBMCloudShellAccountSettings() *schema.Resource { }, }, }, - "regions": &schema.Schema{ + "regions": { Type: schema.TypeList, Computed: true, Description: "List of Cloud Shell region settings.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": &schema.Schema{ + "enabled": { Type: schema.TypeBool, Computed: true, Description: "State of the region.", }, - "key": &schema.Schema{ + "key": { Type: schema.TypeString, Computed: true, Description: "Name of the region.", @@ -92,17 +94,17 @@ func dataSourceIBMCloudShellAccountSettings() *schema.Resource { }, }, }, - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "Type of api response object.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeInt, Computed: true, Description: "Timestamp of last update in Unix epoch time.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "IAM ID of last updater.", @@ -112,7 +114,7 @@ func dataSourceIBMCloudShellAccountSettings() *schema.Resource { } func dataSourceIBMCloudShellAccountSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmCloudShellClient, err := meta.(ClientSession).IBMCloudShellV1() + ibmCloudShellClient, err := meta.(conns.ClientSession).IBMCloudShellV1() if err != nil { return diag.FromErr(err) } @@ -129,45 +131,45 @@ func dataSourceIBMCloudShellAccountSettingsRead(context context.Context, d *sche d.SetId(*accountSettings.AccountID) if err = d.Set("rev", accountSettings.Rev); err != nil { - return diag.FromErr(fmt.Errorf("Error setting rev: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting rev: %s", err)) } - if err = d.Set("created_at", intValue(accountSettings.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + if err = d.Set("created_at", flex.IntValue(accountSettings.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", accountSettings.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if err = d.Set("default_enable_new_features", accountSettings.DefaultEnableNewFeatures); err != nil { - return diag.FromErr(fmt.Errorf("Error setting default_enable_new_features: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting default_enable_new_features: %s", err)) } if err = d.Set("default_enable_new_regions", accountSettings.DefaultEnableNewRegions); err != nil { - return diag.FromErr(fmt.Errorf("Error setting default_enable_new_regions: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting default_enable_new_regions: %s", err)) } if err = d.Set("enabled", accountSettings.Enabled); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enabled: %s", err)) } if accountSettings.Features != nil { err = d.Set("features", dataSourceAccountSettingsFlattenFeatures(accountSettings.Features)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting features %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting features %s", err)) } } if accountSettings.Regions != nil { err = d.Set("regions", dataSourceAccountSettingsFlattenRegions(accountSettings.Regions)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting regions %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting regions %s", err)) } } if err = d.Set("type", accountSettings.Type); err != nil { - return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } - if err = d.Set("updated_at", intValue(accountSettings.UpdatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + if err = d.Set("updated_at", flex.IntValue(accountSettings.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } if err = d.Set("updated_by", accountSettings.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) } return nil diff --git a/ibm/data_source_ibm_cloud_shell_account_settings_test.go b/ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings_test.go similarity index 90% rename from ibm/data_source_ibm_cloud_shell_account_settings_test.go rename to ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings_test.go index 2032888ee..717f95f3a 100644 --- a/ibm/data_source_ibm_cloud_shell_account_settings_test.go +++ b/ibm/service/cloudshell/data_source_ibm_cloud_shell_account_settings_test.go @@ -1,24 +1,26 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudshell_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCloudShellAccountSettingsDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCloudShell(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCloudShell(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Destroy: false, - Config: testAccCheckIBMCloudShellAccountSettingsDataSourceConfigBasic(cloudShellAccountID), + Config: testAccCheckIBMCloudShellAccountSettingsDataSourceConfigBasic(acc.CloudShellAccountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_cloud_shell_account_settings.cloud_shell_account_settings", "id"), resource.TestCheckResourceAttrSet("data.ibm_cloud_shell_account_settings.cloud_shell_account_settings", "account_id"), @@ -34,14 +36,14 @@ func TestAccIBMCloudShellAccountSettingsDataSourceAllArgs(t *testing.T) { accountSettingsEnabled := "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCloudShell(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCloudShell(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCloudShellAccountSettingsDataSourceConfig(cloudShellAccountID, accountSettingsDefaultEnableNewFeatures, accountSettingsDefaultEnableNewRegions, accountSettingsEnabled), + Config: testAccCheckIBMCloudShellAccountSettingsDataSourceConfig(acc.CloudShellAccountID, accountSettingsDefaultEnableNewFeatures, accountSettingsDefaultEnableNewRegions, accountSettingsEnabled), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_cloud_shell_account_settings.account_settings_after_update", "id", fmt.Sprintf("ac-%s", cloudShellAccountID)), - resource.TestCheckResourceAttr("data.ibm_cloud_shell_account_settings.account_settings_after_update", "account_id", cloudShellAccountID), + resource.TestCheckResourceAttr("data.ibm_cloud_shell_account_settings.account_settings_after_update", "id", fmt.Sprintf("ac-%s", acc.CloudShellAccountID)), + resource.TestCheckResourceAttr("data.ibm_cloud_shell_account_settings.account_settings_after_update", "account_id", acc.CloudShellAccountID), resource.TestCheckResourceAttrSet("data.ibm_cloud_shell_account_settings.account_settings_after_update", "rev"), resource.TestCheckResourceAttrSet("data.ibm_cloud_shell_account_settings.account_settings_after_update", "created_at"), resource.TestCheckResourceAttrSet("data.ibm_cloud_shell_account_settings.account_settings_after_update", "created_by"), diff --git a/ibm/resource_ibm_cloud_shell_account_settings.go b/ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings.go similarity index 93% rename from ibm/resource_ibm_cloud_shell_account_settings.go rename to ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings.go index 3d31a8c6b..e64c20075 100644 --- a/ibm/resource_ibm_cloud_shell_account_settings.go +++ b/ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudshell import ( "context" "fmt" "log" + "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -15,7 +18,7 @@ import ( "github.com/IBM/platform-services-go-sdk/ibmcloudshellv1" ) -func resourceIBMCloudShellAccountSettings() *schema.Resource { +func ResourceIBMCloudShellAccountSettings() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMCloudShellAccountSettingsCreate, ReadContext: resourceIBMCloudShellAccountSettingsRead, @@ -54,6 +57,7 @@ func resourceIBMCloudShellAccountSettings() *schema.Resource { "features": { Type: schema.TypeList, Optional: true, + Computed: true, Description: "List of Cloud Shell features.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -73,6 +77,7 @@ func resourceIBMCloudShellAccountSettings() *schema.Resource { "regions": { Type: schema.TypeList, Optional: true, + Computed: true, Description: "List of Cloud Shell region settings.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -119,7 +124,7 @@ func resourceIBMCloudShellAccountSettings() *schema.Resource { } func resourceIBMCloudShellAccountSettingsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmCloudShellClient, err := meta.(ClientSession).IBMCloudShellV1() + ibmCloudShellClient, err := meta.(conns.ClientSession).IBMCloudShellV1() if err != nil { return diag.FromErr(err) } @@ -196,14 +201,14 @@ func resourceIBMCloudShellAccountSettingsMapToRegionSetting(regionSettingMap map } func resourceIBMCloudShellAccountSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmCloudShellClient, err := meta.(ClientSession).IBMCloudShellV1() + ibmCloudShellClient, err := meta.(conns.ClientSession).IBMCloudShellV1() if err != nil { return diag.FromErr(err) } getAccountSettingsOptions := &ibmcloudshellv1.GetAccountSettingsOptions{} - getAccountSettingsOptions.SetAccountID(d.Id()) + getAccountSettingsOptions.SetAccountID(strings.TrimPrefix(d.Id(), "ac-")) accountSettings, response, err := ibmCloudShellClient.GetAccountSettingsWithContext(context, getAccountSettingsOptions) if err != nil { @@ -250,7 +255,7 @@ func resourceIBMCloudShellAccountSettingsRead(context context.Context, d *schema return diag.FromErr(fmt.Errorf("[ERROR] Error setting regions: %s", err)) } } - if err = d.Set("created_at", intValue(accountSettings.CreatedAt)); err != nil { + if err = d.Set("created_at", flex.IntValue(accountSettings.CreatedAt)); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", accountSettings.CreatedBy); err != nil { @@ -259,7 +264,7 @@ func resourceIBMCloudShellAccountSettingsRead(context context.Context, d *schema if err = d.Set("type", accountSettings.Type); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } - if err = d.Set("updated_at", intValue(accountSettings.UpdatedAt)); err != nil { + if err = d.Set("updated_at", flex.IntValue(accountSettings.UpdatedAt)); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } if err = d.Set("updated_by", accountSettings.UpdatedBy); err != nil { @@ -296,14 +301,14 @@ func resourceIBMCloudShellAccountSettingsRegionSettingToMap(regionSetting ibmclo } func resourceIBMCloudShellAccountSettingsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmCloudShellClient, err := meta.(ClientSession).IBMCloudShellV1() + ibmCloudShellClient, err := meta.(conns.ClientSession).IBMCloudShellV1() if err != nil { return diag.FromErr(err) } updateAccountSettingsOptions := &ibmcloudshellv1.UpdateAccountSettingsOptions{} - updateAccountSettingsOptions.SetAccountID(d.Id()) + updateAccountSettingsOptions.SetAccountID(strings.TrimPrefix(d.Id(), "ac-")) hasChange := false updateAccountSettingsOptions.SetRev(d.Get("rev").(string)) if d.HasChange("default_enable_new_features") { diff --git a/ibm/resource_ibm_cloud_shell_account_settings_test.go b/ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings_test.go similarity index 87% rename from ibm/resource_ibm_cloud_shell_account_settings_test.go rename to ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings_test.go index 8c692ab13..8724cf45e 100644 --- a/ibm/resource_ibm_cloud_shell_account_settings_test.go +++ b/ibm/service/cloudshell/resource_ibm_cloud_shell_account_settings_test.go @@ -1,24 +1,26 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cloudshell_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCloudShellAccountSettingsBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCloudShell(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCloudShell(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCloudShellAccountSettingsConfigBasic(cloudShellAccountID), + Config: testAccCheckIBMCloudShellAccountSettingsConfigBasic(acc.CloudShellAccountID), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings", "account_id", cloudShellAccountID), + resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings", "account_id", acc.CloudShellAccountID), ), }, }, @@ -38,14 +40,14 @@ func TestAccIBMCloudShellAccountSettingsAllArgs(t *testing.T) { regionJpTokUpdate := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCloudShell(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCloudShell(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMCloudShellAccountSettingsConfig("1", cloudShellAccountID, defaultEnableNewFeatures, defaultEnableNewRegions, enabled, featureWebPreview, regionJpTok), + Config: testAccCheckIBMCloudShellAccountSettingsConfig("1", acc.CloudShellAccountID, defaultEnableNewFeatures, defaultEnableNewRegions, enabled, featureWebPreview, regionJpTok), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "id", fmt.Sprintf("ac-%s", cloudShellAccountID)), - resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "account_id", cloudShellAccountID), + resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "id", fmt.Sprintf("ac-%s", acc.CloudShellAccountID)), + resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "account_id", acc.CloudShellAccountID), resource.TestCheckResourceAttrSet("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "rev"), resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "default_enable_new_features", defaultEnableNewFeatures), resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings1", "default_enable_new_regions", defaultEnableNewRegions), @@ -59,10 +61,10 @@ func TestAccIBMCloudShellAccountSettingsAllArgs(t *testing.T) { ), }, { - Config: testAccCheckIBMCloudShellAccountSettingsConfig("2", cloudShellAccountID, defaultEnableNewFeaturesUpdate, defaultEnableNewRegionsUpdate, enabledUpdate, featureWebPreviewUpdate, regionJpTokUpdate), + Config: testAccCheckIBMCloudShellAccountSettingsConfig("2", acc.CloudShellAccountID, defaultEnableNewFeaturesUpdate, defaultEnableNewRegionsUpdate, enabledUpdate, featureWebPreviewUpdate, regionJpTokUpdate), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "id", fmt.Sprintf("ac-%s", cloudShellAccountID)), - resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "account_id", cloudShellAccountID), + resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "id", fmt.Sprintf("ac-%s", acc.CloudShellAccountID)), + resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "account_id", acc.CloudShellAccountID), resource.TestCheckResourceAttrSet("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "rev"), resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "default_enable_new_features", defaultEnableNewFeaturesUpdate), resource.TestCheckResourceAttr("ibm_cloud_shell_account_settings.cloud_shell_account_settings2", "default_enable_new_regions", defaultEnableNewRegionsUpdate), diff --git a/ibm/service/contextbasedrestrictions/README.md b/ibm/service/contextbasedrestrictions/README.md new file mode 100644 index 000000000..7385146c6 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Context Based Restrictions + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Context Based Restrictions resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cbr_rule) +* IBM API Docs: [IBM API Docs for Context Based Restrictions](https://cloud.ibm.com/apidocs/context-based-restrictions) +* IBM Context Based Restrictions SDK: [IBM SDK for Context Based Restrictions](https://github.com/IBM/platform-services-go-sdk/tree/main/contextbasedrestrictionsv1) diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule.go new file mode 100644 index 000000000..ce0542725 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule.go @@ -0,0 +1,377 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func DataSourceIBMCbrRule() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCbrRuleRead, + + Schema: map[string]*schema.Schema{ + "rule_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of a rule.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule CRN.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the rule.", + }, + "contexts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The contexts this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute value.", + }, + }, + }, + }, + }, + }, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resources this rule apply to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute value.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute operator.", + }, + }, + }, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The optional resource tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The tag attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The tag attribute value.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The attribute operator.", + }, + }, + }, + }, + }, + }, + }, + "operations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The operations this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_types": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The API types this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_type_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "enforcement_mode": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The href link to the resource.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time the resource was created.", + }, + "created_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which created the resource.", + }, + "last_modified_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The last time the resource was modified.", + }, + "last_modified_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which modified the resource.", + }, + }, + } +} + +func dataSourceIBMCbrRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + getRuleOptions := &contextbasedrestrictionsv1.GetRuleOptions{} + + getRuleOptions.SetRuleID(d.Get("rule_id").(string)) + + rule, response, err := contextBasedRestrictionsClient.GetRuleWithContext(context, getRuleOptions) + if err != nil { + log.Printf("[DEBUG] GetRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetRuleWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getRuleOptions.RuleID)) + + if err = d.Set("crn", rule.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("description", rule.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + contexts := []map[string]interface{}{} + if rule.Contexts != nil { + for _, modelItem := range rule.Contexts { + modelMap, err := dataSourceIBMCbrRuleRuleContextToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + contexts = append(contexts, modelMap) + } + } + if err = d.Set("contexts", contexts); err != nil { + return diag.FromErr(fmt.Errorf("Error setting contexts %s", err)) + } + + resources := []map[string]interface{}{} + if rule.Resources != nil { + for _, modelItem := range rule.Resources { + modelMap, err := dataSourceIBMCbrRuleResourceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + resources = append(resources, modelMap) + } + } + if err = d.Set("resources", resources); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resources %s", err)) + } + + operations := []map[string]interface{}{} + if rule.Operations != nil { + modelMap, err := dataSourceIBMCbrRuleNewRuleOperationsToMap(rule.Operations) + if err != nil { + return diag.FromErr(err) + } + operations = append(operations, modelMap) + } + if err = d.Set("operations", operations); err != nil { + return diag.FromErr(fmt.Errorf("Error setting operations %s", err)) + } + + if err = d.Set("enforcement_mode", rule.EnforcementMode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enforcement_mode: %s", err)) + } + + if err = d.Set("href", rule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(rule.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("created_by_id", rule.CreatedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by_id: %s", err)) + } + + if err = d.Set("last_modified_at", flex.DateTimeToString(rule.LastModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_at: %s", err)) + } + + if err = d.Set("last_modified_by_id", rule.LastModifiedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_by_id: %s", err)) + } + + return nil +} + +func dataSourceIBMCbrRuleRuleContextToMap(model *contextbasedrestrictionsv1.RuleContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Attributes != nil { + attributes := []map[string]interface{}{} + for _, attributesItem := range model.Attributes { + attributesItemMap, err := dataSourceIBMCbrRuleRuleContextAttributeToMap(&attributesItem) + if err != nil { + return modelMap, err + } + attributes = append(attributes, attributesItemMap) + } + modelMap["attributes"] = attributes + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleRuleContextAttributeToMap(model *contextbasedrestrictionsv1.RuleContextAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleResourceToMap(model *contextbasedrestrictionsv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Attributes != nil { + attributes := []map[string]interface{}{} + for _, attributesItem := range model.Attributes { + attributesItemMap, err := dataSourceIBMCbrRuleResourceAttributeToMap(&attributesItem) + if err != nil { + return modelMap, err + } + attributes = append(attributes, attributesItemMap) + } + modelMap["attributes"] = attributes + } + if model.Tags != nil { + tags := []map[string]interface{}{} + for _, tagsItem := range model.Tags { + tagsItemMap, err := dataSourceIBMCbrRuleResourceTagAttributeToMap(&tagsItem) + if err != nil { + return modelMap, err + } + tags = append(tags, tagsItemMap) + } + modelMap["tags"] = tags + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleResourceAttributeToMap(model *contextbasedrestrictionsv1.ResourceAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Operator != nil { + modelMap["operator"] = *model.Operator + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleResourceTagAttributeToMap(model *contextbasedrestrictionsv1.ResourceTagAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Operator != nil { + modelMap["operator"] = *model.Operator + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleNewRuleOperationsToMap(model *contextbasedrestrictionsv1.NewRuleOperations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.APITypes != nil { + apiTypes := []map[string]interface{}{} + for _, apiTypesItem := range model.APITypes { + apiTypesItemMap, err := dataSourceIBMCbrRuleNewRuleOperationsAPITypesItemToMap(&apiTypesItem) + if err != nil { + return modelMap, err + } + apiTypes = append(apiTypes, apiTypesItemMap) + } + modelMap["api_types"] = apiTypes + } + return modelMap, nil +} + +func dataSourceIBMCbrRuleNewRuleOperationsAPITypesItemToMap(model *contextbasedrestrictionsv1.NewRuleOperationsAPITypesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.APITypeID != nil { + modelMap["api_type_id"] = *model.APITypeID + } + return modelMap, nil +} diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go new file mode 100644 index 000000000..b2fa07dd4 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go @@ -0,0 +1,137 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCbrRuleDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrRuleDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "rule_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "description"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "contexts.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "resources.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "created_by_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "last_modified_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "last_modified_by_id"), + ), + }, + }, + }) +} + +func TestAccIBMCbrRuleDataSourceAllArgs(t *testing.T) { + ruleDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + ruleEnforcementMode := "enabled" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrRuleDataSourceConfig(ruleDescription, ruleEnforcementMode), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "rule_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "description"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "contexts.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "resources.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "operations.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "enforcement_mode"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "created_by_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "last_modified_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_rule.cbr_rule", "last_modified_by_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMCbrRuleDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cbr_rule" "cbr_rule" { + description = "Test Rule Data Source Config Basic" + contexts { + attributes { + name = "networkZoneId" + value = "559052eb8f43302824e7ae490c0281eb" + } + } + resources { + attributes { + name = "accountId" + value = "12ab34cd56ef78ab90cd12ef34ab56cd" + } + attributes { + name = "serviceName" + value = "iam-groups" + } + } + } + data "ibm_cbr_rule" "cbr_rule" { + rule_id = ibm_cbr_rule.cbr_rule.id + } + `) +} + +func testAccCheckIBMCbrRuleDataSourceConfig(ruleDescription string, ruleEnforcementMode string) string { + return fmt.Sprintf(` + resource "ibm_cbr_rule" "cbr_rule" { + description = "%s" + contexts { + attributes { + name = "networkZoneId" + value = "559052eb8f43302824e7ae490c0281eb" + } + } + resources { + attributes { + name = "accountId" + value = "12ab34cd56ef78ab90cd12ef34ab56cd" + } + attributes { + name = "serviceName" + value = "containers-kubernetes" + } + tags { + name = "name" + value = "tag_name" + operator = "stringEquals" + } + } + operations { + api_types { + api_type_id = "crn:v1:bluemix:public:containers-kubernetes::::api-type:management" + } + } + enforcement_mode = "%s" + } + + data "ibm_cbr_rule" "cbr_rule" { + rule_id = ibm_cbr_rule.cbr_rule.id + } + `, ruleDescription, ruleEnforcementMode) +} diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone.go new file mode 100644 index 000000000..9357e4bb1 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone.go @@ -0,0 +1,363 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func DataSourceIBMCbrZone() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMCbrZoneRead, + + Schema: map[string]*schema.Schema{ + "zone_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of a zone.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The zone CRN.", + }, + "address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of addresses in the zone.", + }, + "excluded_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of excluded addresses in the zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the zone.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the account owning this zone.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the zone.", + }, + "addresses": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The list of addresses in the zone.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of address.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.", + }, + "ref": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A service reference value.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the account owning the service.", + }, + "service_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The service type.", + }, + "service_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The service name.", + }, + "service_instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The service instance.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The location.", + }, + }, + }, + }, + }, + }, + }, + "excluded": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of address.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The href link to the resource.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time the resource was created.", + }, + "created_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which created the resource.", + }, + "last_modified_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The last time the resource was modified.", + }, + "last_modified_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which modified the resource.", + }, + }, + } +} + +func dataSourceIBMCbrZoneRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + getZoneOptions := &contextbasedrestrictionsv1.GetZoneOptions{} + + getZoneOptions.SetZoneID(d.Get("zone_id").(string)) + + zone, response, err := contextBasedRestrictionsClient.GetZoneWithContext(context, getZoneOptions) + if err != nil { + log.Printf("[DEBUG] GetZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetZoneWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getZoneOptions.ZoneID)) + + if err = d.Set("crn", zone.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("address_count", flex.IntValue(zone.AddressCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting address_count: %s", err)) + } + + if err = d.Set("excluded_count", flex.IntValue(zone.ExcludedCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded_count: %s", err)) + } + + if err = d.Set("name", zone.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("account_id", zone.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + + if err = d.Set("description", zone.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + addresses := []map[string]interface{}{} + if zone.Addresses != nil { + for _, modelItem := range zone.Addresses { + modelMap, err := dataSourceIBMCbrZoneAddressToMap(modelItem) + if err != nil { + return diag.FromErr(err) + } + addresses = append(addresses, modelMap) + } + } + if err = d.Set("addresses", addresses); err != nil { + return diag.FromErr(fmt.Errorf("Error setting addresses %s", err)) + } + + excluded := []map[string]interface{}{} + if zone.Excluded != nil { + for _, modelItem := range zone.Excluded { + modelMap, err := dataSourceIBMCbrZoneAddressToMap(modelItem) + if err != nil { + return diag.FromErr(err) + } + excluded = append(excluded, modelMap) + } + } + if err = d.Set("excluded", excluded); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded %s", err)) + } + + if err = d.Set("href", zone.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(zone.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("created_by_id", zone.CreatedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by_id: %s", err)) + } + + if err = d.Set("last_modified_at", flex.DateTimeToString(zone.LastModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_at: %s", err)) + } + + if err = d.Set("last_modified_by_id", zone.LastModifiedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_by_id: %s", err)) + } + + return nil +} + +func dataSourceIBMCbrZoneAddressToMap(model contextbasedrestrictionsv1.AddressIntf) (map[string]interface{}, error) { + if _, ok := model.(*contextbasedrestrictionsv1.AddressIPAddress); ok { + return dataSourceIBMCbrZoneAddressIPAddressToMap(model.(*contextbasedrestrictionsv1.AddressIPAddress)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressIPAddressRange); ok { + return dataSourceIBMCbrZoneAddressIPAddressRangeToMap(model.(*contextbasedrestrictionsv1.AddressIPAddressRange)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressSubnet); ok { + return dataSourceIBMCbrZoneAddressSubnetToMap(model.(*contextbasedrestrictionsv1.AddressSubnet)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressVPC); ok { + return dataSourceIBMCbrZoneAddressVPCToMap(model.(*contextbasedrestrictionsv1.AddressVPC)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressServiceRef); ok { + return dataSourceIBMCbrZoneAddressServiceRefToMap(model.(*contextbasedrestrictionsv1.AddressServiceRef)) + } else if _, ok := model.(*contextbasedrestrictionsv1.Address); ok { + modelMap := make(map[string]interface{}) + model := model.(*contextbasedrestrictionsv1.Address) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + if model.Ref != nil { + refMap, err := dataSourceIBMCbrZoneServiceRefValueToMap(model.Ref) + if err != nil { + return modelMap, err + } + modelMap["ref"] = []map[string]interface{}{refMap} + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized contextbasedrestrictionsv1.AddressIntf subtype encountered") + } +} + +func dataSourceIBMCbrZoneServiceRefValueToMap(model *contextbasedrestrictionsv1.ServiceRefValue) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AccountID != nil { + modelMap["account_id"] = *model.AccountID + } + if model.ServiceType != nil { + modelMap["service_type"] = *model.ServiceType + } + if model.ServiceName != nil { + modelMap["service_name"] = *model.ServiceName + } + if model.ServiceInstance != nil { + modelMap["service_instance"] = *model.ServiceInstance + } + if model.Location != nil { + modelMap["location"] = *model.Location + } + return modelMap, nil +} + +func dataSourceIBMCbrZoneAddressIPAddressToMap(model *contextbasedrestrictionsv1.AddressIPAddress) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func dataSourceIBMCbrZoneAddressServiceRefToMap(model *contextbasedrestrictionsv1.AddressServiceRef) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Ref != nil { + refMap, err := dataSourceIBMCbrZoneServiceRefValueToMap(model.Ref) + if err != nil { + return modelMap, err + } + modelMap["ref"] = []map[string]interface{}{refMap} + } + return modelMap, nil +} + +func dataSourceIBMCbrZoneAddressSubnetToMap(model *contextbasedrestrictionsv1.AddressSubnet) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func dataSourceIBMCbrZoneAddressIPAddressRangeToMap(model *contextbasedrestrictionsv1.AddressIPAddressRange) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func dataSourceIBMCbrZoneAddressVPCToMap(model *contextbasedrestrictionsv1.AddressVPC) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go new file mode 100644 index 000000000..1a1e02764 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go @@ -0,0 +1,122 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMCbrZoneDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrZoneDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "zone_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "address_count"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded_count"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "account_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "description"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "addresses.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "created_by_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "last_modified_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "last_modified_by_id"), + ), + }, + }, + }) +} + +func TestAccIBMCbrZoneDataSourceAllArgs(t *testing.T) { + zoneName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + zoneAccountID := "12ab34cd56ef78ab90cd12ef34ab56cd" + zoneDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrZoneDataSourceConfig(zoneName, zoneAccountID, zoneDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "zone_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "address_count"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded_count"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "name"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "account_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "description"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "addresses.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "addresses.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "addresses.0.value"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded.#"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "excluded.0.value"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "href"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "created_by_id"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "last_modified_at"), + resource.TestCheckResourceAttrSet("data.ibm_cbr_zone.cbr_zone", "last_modified_by_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMCbrZoneDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cbr_zone" "cbr_zone" { + name = "Test Zone Data Source Config Basic" + description = "Test Zone Data Source Config Basic" + account_id = "12ab34cd56ef78ab90cd12ef34ab56cd" + addresses { + type = "ipRange" + value = "169.23.22.0-169.23.22.255" + } + } + + data "ibm_cbr_zone" "cbr_zone" { + zone_id = ibm_cbr_zone.cbr_zone.id + } + `) +} + +func testAccCheckIBMCbrZoneDataSourceConfig(zoneName string, zoneAccountID string, zoneDescription string) string { + return fmt.Sprintf(` + resource "ibm_cbr_zone" "cbr_zone" { + name = "%s" + account_id = "%s" + description = "%s" + addresses { + type = "ipRange" + value = "169.23.22.0-169.23.22.255" + } + excluded { + type = "ipAddress" + value = "169.23.22.10" + } + } + + data "ibm_cbr_zone" "cbr_zone" { + zone_id = ibm_cbr_zone.cbr_zone.id + } + `, zoneName, zoneAccountID, zoneDescription) +} diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go new file mode 100644 index 000000000..dfcbd65dd --- /dev/null +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go @@ -0,0 +1,653 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func ResourceIBMCbrRule() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCbrRuleCreate, + ReadContext: resourceIBMCbrRuleRead, + UpdateContext: resourceIBMCbrRuleUpdate, + DeleteContext: resourceIBMCbrRuleDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_rule", "description"), + Description: "The description of the rule.", + }, + "contexts": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The contexts this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The attribute value.", + }, + }, + }, + }, + }, + }, + }, + "resources": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The resources this rule apply to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attributes": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The resource attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The attribute value.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The attribute operator.", + }, + }, + }, + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "The optional resource tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The tag attribute name.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The tag attribute value.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The attribute operator.", + }, + }, + }, + }, + }, + }, + }, + "operations": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The operations this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_types": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The API types this rule applies to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_type_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "enforcement_mode": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "enabled", + ValidateFunc: validate.InvokeValidator("ibm_cbr_rule", "enforcement_mode"), + Description: "The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced.", + }, + "x_correlation_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_rule", "x_correlation_id"), + Description: "The supplied or generated value of this header is logged for a request and repeated in a response header for the corresponding response. The same value is used for downstream requests and retries of those requests. If a value of this headers is not supplied in a request, the service generates a random (version 4) UUID.", + }, + "transaction_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_rule", "transaction_id"), + Description: "The `Transaction-Id` header behaves as the `X-Correlation-Id` header. It is supported for backward compatibility with other IBM platform services that support the `Transaction-Id` header only. If both `X-Correlation-Id` and `Transaction-Id` are provided, `X-Correlation-Id` has the precedence over `Transaction-Id`.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The href link to the resource.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time the resource was created.", + }, + "created_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which created the resource.", + }, + "last_modified_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The last time the resource was modified.", + }, + "last_modified_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which modified the resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMCbrRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[\x20-\xFE]*$`, + MinValueLength: 0, + MaxValueLength: 300, + }, + validate.ValidateSchema{ + Identifier: "enforcement_mode", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "disabled, enabled, report", + }, + validate.ValidateSchema{ + Identifier: "x_correlation_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 ,\-_]+$`, + MinValueLength: 1, + MaxValueLength: 1024, + }, + validate.ValidateSchema{ + Identifier: "transaction_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 ,\-_]+$`, + MinValueLength: 1, + MaxValueLength: 1024, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cbr_rule", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCbrRuleCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + createRuleOptions := &contextbasedrestrictionsv1.CreateRuleOptions{} + + if _, ok := d.GetOk("description"); ok { + createRuleOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("contexts"); ok { + var contexts []contextbasedrestrictionsv1.RuleContext + for _, e := range d.Get("contexts").([]interface{}) { + value := e.(map[string]interface{}) + contextsItem, err := resourceIBMCbrRuleMapToRuleContext(value) + if err != nil { + return diag.FromErr(err) + } + contexts = append(contexts, *contextsItem) + } + createRuleOptions.SetContexts(contexts) + } + if _, ok := d.GetOk("resources"); ok { + var resources []contextbasedrestrictionsv1.Resource + for _, e := range d.Get("resources").([]interface{}) { + value := e.(map[string]interface{}) + resourcesItem, err := resourceIBMCbrRuleMapToResource(value) + if err != nil { + return diag.FromErr(err) + } + resources = append(resources, *resourcesItem) + } + createRuleOptions.SetResources(resources) + } + if _, ok := d.GetOk("operations"); ok { + operationsModel, err := resourceIBMCbrRuleMapToNewRuleOperations(d.Get("operations.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createRuleOptions.SetOperations(operationsModel) + } + if _, ok := d.GetOk("enforcement_mode"); ok { + createRuleOptions.SetEnforcementMode(d.Get("enforcement_mode").(string)) + } + if _, ok := d.GetOk("x_correlation_id"); ok { + createRuleOptions.SetXCorrelationID(d.Get("x_correlation_id").(string)) + } + if _, ok := d.GetOk("transaction_id"); ok { + createRuleOptions.SetTransactionID(d.Get("transaction_id").(string)) + } + + rule, response, err := contextBasedRestrictionsClient.CreateRuleWithContext(context, createRuleOptions) + if err != nil { + log.Printf("[DEBUG] CreateRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateRuleWithContext failed %s\n%s", err, response)) + } + + d.SetId(*rule.ID) + + return resourceIBMCbrRuleRead(context, d, meta) +} + +func resourceIBMCbrRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + getRuleOptions := &contextbasedrestrictionsv1.GetRuleOptions{} + + getRuleOptions.SetRuleID(d.Id()) + + rule, response, err := contextBasedRestrictionsClient.GetRuleWithContext(context, getRuleOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetRuleWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("x_correlation_id", getRuleOptions.XCorrelationID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting x_correlation_id: %s", err)) + } + if err = d.Set("transaction_id", getRuleOptions.TransactionID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting transaction_id: %s", err)) + } + if err = d.Set("description", rule.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + contexts := []map[string]interface{}{} + if rule.Contexts != nil { + for _, contextsItem := range rule.Contexts { + contextsItemMap, err := resourceIBMCbrRuleRuleContextToMap(&contextsItem) + if err != nil { + return diag.FromErr(err) + } + contexts = append(contexts, contextsItemMap) + } + } + if err = d.Set("contexts", contexts); err != nil { + return diag.FromErr(fmt.Errorf("Error setting contexts: %s", err)) + } + resources := []map[string]interface{}{} + if rule.Resources != nil { + for _, resourcesItem := range rule.Resources { + resourcesItemMap, err := resourceIBMCbrRuleResourceToMap(&resourcesItem) + if err != nil { + return diag.FromErr(err) + } + resources = append(resources, resourcesItemMap) + } + } + if err = d.Set("resources", resources); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resources: %s", err)) + } + if rule.Operations != nil { + operationsMap, err := resourceIBMCbrRuleNewRuleOperationsToMap(rule.Operations) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("operations", []map[string]interface{}{operationsMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting operations: %s", err)) + } + } + if err = d.Set("enforcement_mode", rule.EnforcementMode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enforcement_mode: %s", err)) + } + if err = d.Set("crn", rule.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("href", rule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(rule.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("created_by_id", rule.CreatedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by_id: %s", err)) + } + if err = d.Set("last_modified_at", flex.DateTimeToString(rule.LastModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_at: %s", err)) + } + if err = d.Set("last_modified_by_id", rule.LastModifiedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_by_id: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMCbrRuleUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + replaceRuleOptions := &contextbasedrestrictionsv1.ReplaceRuleOptions{} + + replaceRuleOptions.SetRuleID(d.Id()) + if _, ok := d.GetOk("description"); ok { + replaceRuleOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("contexts"); ok { + var contexts []contextbasedrestrictionsv1.RuleContext + for _, e := range d.Get("contexts").([]interface{}) { + value := e.(map[string]interface{}) + contextsItem, err := resourceIBMCbrRuleMapToRuleContext(value) + if err != nil { + return diag.FromErr(err) + } + contexts = append(contexts, *contextsItem) + } + replaceRuleOptions.SetContexts(contexts) + } + if _, ok := d.GetOk("resources"); ok { + var resources []contextbasedrestrictionsv1.Resource + for _, e := range d.Get("resources").([]interface{}) { + value := e.(map[string]interface{}) + resourcesItem, err := resourceIBMCbrRuleMapToResource(value) + if err != nil { + return diag.FromErr(err) + } + resources = append(resources, *resourcesItem) + } + replaceRuleOptions.SetResources(resources) + } + if _, ok := d.GetOk("operations"); ok { + operations, err := resourceIBMCbrRuleMapToNewRuleOperations(d.Get("operations.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + replaceRuleOptions.SetOperations(operations) + } + if _, ok := d.GetOk("enforcement_mode"); ok { + replaceRuleOptions.SetEnforcementMode(d.Get("enforcement_mode").(string)) + } + if _, ok := d.GetOk("x_correlation_id"); ok { + replaceRuleOptions.SetXCorrelationID(d.Get("x_correlation_id").(string)) + } + if _, ok := d.GetOk("transaction_id"); ok { + replaceRuleOptions.SetTransactionID(d.Get("transaction_id").(string)) + } + replaceRuleOptions.SetIfMatch(d.Get("version").(string)) + + _, response, err := contextBasedRestrictionsClient.ReplaceRuleWithContext(context, replaceRuleOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceRuleWithContext failed %s\n%s", err, response)) + } + + return resourceIBMCbrRuleRead(context, d, meta) +} + +func resourceIBMCbrRuleDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + deleteRuleOptions := &contextbasedrestrictionsv1.DeleteRuleOptions{} + + deleteRuleOptions.SetRuleID(d.Id()) + + response, err := contextBasedRestrictionsClient.DeleteRuleWithContext(context, deleteRuleOptions) + if err != nil { + log.Printf("[DEBUG] DeleteRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteRuleWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCbrRuleMapToRuleContext(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.RuleContext, error) { + model := &contextbasedrestrictionsv1.RuleContext{} + attributes := []contextbasedrestrictionsv1.RuleContextAttribute{} + for _, attributesItem := range modelMap["attributes"].([]interface{}) { + attributesItemModel, err := resourceIBMCbrRuleMapToRuleContextAttribute(attributesItem.(map[string]interface{})) + if err != nil { + return model, err + } + attributes = append(attributes, *attributesItemModel) + } + model.Attributes = attributes + return model, nil +} + +func resourceIBMCbrRuleMapToRuleContextAttribute(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.RuleContextAttribute, error) { + model := &contextbasedrestrictionsv1.RuleContextAttribute{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMCbrRuleMapToResource(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.Resource, error) { + model := &contextbasedrestrictionsv1.Resource{} + attributes := []contextbasedrestrictionsv1.ResourceAttribute{} + for _, attributesItem := range modelMap["attributes"].([]interface{}) { + attributesItemModel, err := resourceIBMCbrRuleMapToResourceAttribute(attributesItem.(map[string]interface{})) + if err != nil { + return model, err + } + attributes = append(attributes, *attributesItemModel) + } + model.Attributes = attributes + if modelMap["tags"] != nil { + tags := []contextbasedrestrictionsv1.ResourceTagAttribute{} + for _, tagsItem := range modelMap["tags"].([]interface{}) { + tagsItemModel, err := resourceIBMCbrRuleMapToResourceTagAttribute(tagsItem.(map[string]interface{})) + if err != nil { + return model, err + } + tags = append(tags, *tagsItemModel) + } + model.Tags = tags + } + return model, nil +} + +func resourceIBMCbrRuleMapToResourceAttribute(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.ResourceAttribute, error) { + model := &contextbasedrestrictionsv1.ResourceAttribute{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + if modelMap["operator"] != nil && modelMap["operator"].(string) != "" { + model.Operator = core.StringPtr(modelMap["operator"].(string)) + } + return model, nil +} + +func resourceIBMCbrRuleMapToResourceTagAttribute(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.ResourceTagAttribute, error) { + model := &contextbasedrestrictionsv1.ResourceTagAttribute{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + if modelMap["operator"] != nil && modelMap["operator"].(string) != "" { + model.Operator = core.StringPtr(modelMap["operator"].(string)) + } + return model, nil +} + +func resourceIBMCbrRuleMapToNewRuleOperations(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.NewRuleOperations, error) { + model := &contextbasedrestrictionsv1.NewRuleOperations{} + apiTypes := []contextbasedrestrictionsv1.NewRuleOperationsAPITypesItem{} + for _, apiTypesItem := range modelMap["api_types"].([]interface{}) { + apiTypesItemModel, err := resourceIBMCbrRuleMapToNewRuleOperationsAPITypesItem(apiTypesItem.(map[string]interface{})) + if err != nil { + return model, err + } + apiTypes = append(apiTypes, *apiTypesItemModel) + } + model.APITypes = apiTypes + return model, nil +} + +func resourceIBMCbrRuleMapToNewRuleOperationsAPITypesItem(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.NewRuleOperationsAPITypesItem, error) { + model := &contextbasedrestrictionsv1.NewRuleOperationsAPITypesItem{} + model.APITypeID = core.StringPtr(modelMap["api_type_id"].(string)) + return model, nil +} + +func resourceIBMCbrRuleRuleContextToMap(model *contextbasedrestrictionsv1.RuleContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + attributes := []map[string]interface{}{} + for _, attributesItem := range model.Attributes { + attributesItemMap, err := resourceIBMCbrRuleRuleContextAttributeToMap(&attributesItem) + if err != nil { + return modelMap, err + } + attributes = append(attributes, attributesItemMap) + } + modelMap["attributes"] = attributes + return modelMap, nil +} + +func resourceIBMCbrRuleRuleContextAttributeToMap(model *contextbasedrestrictionsv1.RuleContextAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + return modelMap, nil +} + +func resourceIBMCbrRuleResourceToMap(model *contextbasedrestrictionsv1.Resource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + attributes := []map[string]interface{}{} + for _, attributesItem := range model.Attributes { + attributesItemMap, err := resourceIBMCbrRuleResourceAttributeToMap(&attributesItem) + if err != nil { + return modelMap, err + } + attributes = append(attributes, attributesItemMap) + } + modelMap["attributes"] = attributes + if model.Tags != nil { + tags := []map[string]interface{}{} + for _, tagsItem := range model.Tags { + tagsItemMap, err := resourceIBMCbrRuleResourceTagAttributeToMap(&tagsItem) + if err != nil { + return modelMap, err + } + tags = append(tags, tagsItemMap) + } + modelMap["tags"] = tags + } + return modelMap, nil +} + +func resourceIBMCbrRuleResourceAttributeToMap(model *contextbasedrestrictionsv1.ResourceAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + if model.Operator != nil { + modelMap["operator"] = model.Operator + } + return modelMap, nil +} + +func resourceIBMCbrRuleResourceTagAttributeToMap(model *contextbasedrestrictionsv1.ResourceTagAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + if model.Operator != nil { + modelMap["operator"] = model.Operator + } + return modelMap, nil +} + +func resourceIBMCbrRuleNewRuleOperationsToMap(model *contextbasedrestrictionsv1.NewRuleOperations) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + apiTypes := []map[string]interface{}{} + for _, apiTypesItem := range model.APITypes { + apiTypesItemMap, err := resourceIBMCbrRuleNewRuleOperationsAPITypesItemToMap(&apiTypesItem) + if err != nil { + return modelMap, err + } + apiTypes = append(apiTypes, apiTypesItemMap) + } + modelMap["api_types"] = apiTypes + return modelMap, nil +} + +func resourceIBMCbrRuleNewRuleOperationsAPITypesItemToMap(model *contextbasedrestrictionsv1.NewRuleOperationsAPITypesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["api_type_id"] = model.APITypeID + return modelMap, nil +} diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go new file mode 100644 index 000000000..8434734ae --- /dev/null +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go @@ -0,0 +1,191 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func TestAccIBMCbrRuleBasic(t *testing.T) { + var conf contextbasedrestrictionsv1.Rule + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCbrRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrRuleConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCbrRuleExists("ibm_cbr_rule.cbr_rule", conf), + ), + }, + }, + }) +} + +func TestAccIBMCbrRuleAllArgs(t *testing.T) { + var conf contextbasedrestrictionsv1.Rule + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + enforcementMode := "enabled" + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + enforcementModeUpdate := "report" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCbrRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrRuleConfig(description, enforcementMode), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCbrRuleExists("ibm_cbr_rule.cbr_rule", conf), + resource.TestCheckResourceAttr("ibm_cbr_rule.cbr_rule", "description", description), + resource.TestCheckResourceAttr("ibm_cbr_rule.cbr_rule", "enforcement_mode", enforcementMode), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCbrRuleConfig(descriptionUpdate, enforcementModeUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cbr_rule.cbr_rule", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_cbr_rule.cbr_rule", "enforcement_mode", enforcementModeUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cbr_rule.cbr_rule", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCbrRuleConfigBasic() string { + return fmt.Sprintf(` + + resource "ibm_cbr_rule" "cbr_rule" { + description = "test rule config basic" + contexts { + attributes { + name = "networkZoneId" + value = "559052eb8f43302824e7ae490c0281eb" + } + } + resources { + attributes { + name = "accountId" + value = "12ab34cd56ef78ab90cd12ef34ab56cd" + } + attributes { + name = "serviceName" + value = "user-management" + } + tags { + name = "tag_name" + value = "tag_value" + } + } + enforcement_mode = "disabled" + } + `) +} + +func testAccCheckIBMCbrRuleConfig(description string, enforcementMode string) string { + return fmt.Sprintf(` + + resource "ibm_cbr_rule" "cbr_rule" { + description = "%s" + contexts { + attributes { + name = "networkZoneId" + value = "559052eb8f43302824e7ae490c0281eb" + } + } + resources { + attributes { + name = "accountId" + value = "12ab34cd56ef78ab90cd12ef34ab56cd" + } + attributes { + name = "serviceName" + value = "containers-kubernetes" + } + tags { + name = "name" + value = "value" + operator = "stringEquals" + } + } + operations { + api_types { + api_type_id = "crn:v1:bluemix:public:containers-kubernetes::::api-type:management" + } + } + enforcement_mode = "%s" + } + `, description, enforcementMode) +} + +func testAccCheckIBMCbrRuleExists(n string, obj contextbasedrestrictionsv1.Rule) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + contextBasedRestrictionsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return err + } + + getRuleOptions := &contextbasedrestrictionsv1.GetRuleOptions{} + + getRuleOptions.SetRuleID(rs.Primary.ID) + + rule, _, err := contextBasedRestrictionsClient.GetRule(getRuleOptions) + if err != nil { + return err + } + + obj = *rule + return nil + } +} + +func testAccCheckIBMCbrRuleDestroy(s *terraform.State) error { + contextBasedRestrictionsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cbr_rule" { + continue + } + + getRuleOptions := &contextbasedrestrictionsv1.GetRuleOptions{} + + getRuleOptions.SetRuleID(rs.Primary.ID) + + // Try to find the key + _, response, err := contextBasedRestrictionsClient.GetRule(getRuleOptions) + + if err == nil { + return fmt.Errorf("cbr_rule still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cbr_rule (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go new file mode 100644 index 000000000..d525000ca --- /dev/null +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go @@ -0,0 +1,632 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func ResourceIBMCbrZone() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMCbrZoneCreate, + ReadContext: resourceIBMCbrZoneRead, + UpdateContext: resourceIBMCbrZoneUpdate, + DeleteContext: resourceIBMCbrZoneDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_zone", "name"), + Description: "The name of the zone.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_zone", "account_id"), + Description: "The id of the account owning this zone.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_zone", "description"), + Description: "The description of the zone.", + }, + "addresses": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The list of addresses in the zone.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of address.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The IP address.", + }, + "ref": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "A service reference value.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The id of the account owning the service.", + }, + "service_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The service type.", + }, + "service_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The service name.", + }, + "service_instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The service instance.", + }, + "location": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The location.", + }, + }, + }, + }, + }, + }, + }, + "excluded": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of address.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The IP address.", + }, + }, + }, + }, + "x_correlation_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_zone", "x_correlation_id"), + Description: "The supplied or generated value of this header is logged for a request and repeated in a response header for the corresponding response. The same value is used for downstream requests and retries of those requests. If a value of this headers is not supplied in a request, the service generates a random (version 4) UUID.", + }, + "transaction_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cbr_zone", "transaction_id"), + Description: "The `Transaction-Id` header behaves as the `X-Correlation-Id` header. It is supported for backward compatibility with other IBM platform services that support the `Transaction-Id` header only. If both `X-Correlation-Id` and `Transaction-Id` are provided, `X-Correlation-Id` has the precedence over `Transaction-Id`.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The zone CRN.", + }, + "address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of addresses in the zone.", + }, + "excluded_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of excluded addresses in the zone.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The href link to the resource.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time the resource was created.", + }, + "created_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which created the resource.", + }, + "last_modified_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The last time the resource was modified.", + }, + "last_modified_by_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which modified the resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMCbrZoneValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 \-_]+$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + validate.ValidateSchema{ + Identifier: "account_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9\-]+$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[\x20-\xFE]*$`, + MinValueLength: 0, + MaxValueLength: 300, + }, + validate.ValidateSchema{ + Identifier: "x_correlation_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 ,\-_]+$`, + MinValueLength: 1, + MaxValueLength: 1024, + }, + validate.ValidateSchema{ + Identifier: "transaction_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9 ,\-_]+$`, + MinValueLength: 1, + MaxValueLength: 1024, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cbr_zone", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMCbrZoneCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + createZoneOptions := &contextbasedrestrictionsv1.CreateZoneOptions{} + + if _, ok := d.GetOk("name"); ok { + createZoneOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("account_id"); ok { + createZoneOptions.SetAccountID(d.Get("account_id").(string)) + } + if _, ok := d.GetOk("description"); ok { + createZoneOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("addresses"); ok { + var addresses []contextbasedrestrictionsv1.AddressIntf + for _, e := range d.Get("addresses").([]interface{}) { + value := e.(map[string]interface{}) + addressesItem, err := resourceIBMCbrZoneMapToAddress(value) + if err != nil { + return diag.FromErr(err) + } + addresses = append(addresses, addressesItem) + } + createZoneOptions.SetAddresses(addresses) + } + if _, ok := d.GetOk("excluded"); ok { + var excluded []contextbasedrestrictionsv1.AddressIntf + for _, e := range d.Get("excluded").([]interface{}) { + value := e.(map[string]interface{}) + excludedItem, err := resourceIBMCbrZoneMapToAddress(value) + if err != nil { + return diag.FromErr(err) + } + excluded = append(excluded, excludedItem) + } + createZoneOptions.SetExcluded(excluded) + } + if _, ok := d.GetOk("x_correlation_id"); ok { + createZoneOptions.SetXCorrelationID(d.Get("x_correlation_id").(string)) + } + if _, ok := d.GetOk("transaction_id"); ok { + createZoneOptions.SetTransactionID(d.Get("transaction_id").(string)) + } + + zone, response, err := contextBasedRestrictionsClient.CreateZoneWithContext(context, createZoneOptions) + if err != nil { + log.Printf("[DEBUG] CreateZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateZoneWithContext failed %s\n%s", err, response)) + } + + d.SetId(*zone.ID) + + return resourceIBMCbrZoneRead(context, d, meta) +} + +func resourceIBMCbrZoneRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + getZoneOptions := &contextbasedrestrictionsv1.GetZoneOptions{} + + getZoneOptions.SetZoneID(d.Id()) + + zone, response, err := contextBasedRestrictionsClient.GetZoneWithContext(context, getZoneOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetZoneWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("x_correlation_id", getZoneOptions.XCorrelationID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting x_correlation_id: %s", err)) + } + if err = d.Set("transaction_id", getZoneOptions.TransactionID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting transaction_id: %s", err)) + } + if err = d.Set("name", zone.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("account_id", zone.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + if err = d.Set("description", zone.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + addresses := []map[string]interface{}{} + if zone.Addresses != nil { + for _, addressesItem := range zone.Addresses { + addressesItemMap, err := resourceIBMCbrZoneAddressToMap(addressesItem) + if err != nil { + return diag.FromErr(err) + } + addresses = append(addresses, addressesItemMap) + } + } + if err = d.Set("addresses", addresses); err != nil { + return diag.FromErr(fmt.Errorf("Error setting addresses: %s", err)) + } + excluded := []map[string]interface{}{} + if zone.Excluded != nil { + for _, excludedItem := range zone.Excluded { + excludedItemMap, err := resourceIBMCbrZoneAddressToMap(excludedItem) + if err != nil { + return diag.FromErr(err) + } + excluded = append(excluded, excludedItemMap) + } + } + if err = d.Set("excluded", excluded); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded: %s", err)) + } + if err = d.Set("crn", zone.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("address_count", flex.IntValue(zone.AddressCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting address_count: %s", err)) + } + if err = d.Set("excluded_count", flex.IntValue(zone.ExcludedCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded_count: %s", err)) + } + if err = d.Set("href", zone.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(zone.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("created_by_id", zone.CreatedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by_id: %s", err)) + } + if err = d.Set("last_modified_at", flex.DateTimeToString(zone.LastModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_at: %s", err)) + } + if err = d.Set("last_modified_by_id", zone.LastModifiedByID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_modified_by_id: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMCbrZoneUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + replaceZoneOptions := &contextbasedrestrictionsv1.ReplaceZoneOptions{} + + replaceZoneOptions.SetZoneID(d.Id()) + if _, ok := d.GetOk("name"); ok { + replaceZoneOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("account_id"); ok { + replaceZoneOptions.SetAccountID(d.Get("account_id").(string)) + } + if _, ok := d.GetOk("description"); ok { + replaceZoneOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("addresses"); ok { + var addresses []contextbasedrestrictionsv1.AddressIntf + for _, e := range d.Get("addresses").([]interface{}) { + value := e.(map[string]interface{}) + addressesItem, err := resourceIBMCbrZoneMapToAddress(value) + if err != nil { + return diag.FromErr(err) + } + addresses = append(addresses, addressesItem) + } + replaceZoneOptions.SetAddresses(addresses) + } + if _, ok := d.GetOk("excluded"); ok { + var excluded []contextbasedrestrictionsv1.AddressIntf + for _, e := range d.Get("excluded").([]interface{}) { + value := e.(map[string]interface{}) + excludedItem, err := resourceIBMCbrZoneMapToAddress(value) + if err != nil { + return diag.FromErr(err) + } + excluded = append(excluded, excludedItem) + } + replaceZoneOptions.SetExcluded(excluded) + } + if _, ok := d.GetOk("x_correlation_id"); ok { + replaceZoneOptions.SetXCorrelationID(d.Get("x_correlation_id").(string)) + } + if _, ok := d.GetOk("transaction_id"); ok { + replaceZoneOptions.SetTransactionID(d.Get("transaction_id").(string)) + } + replaceZoneOptions.SetIfMatch(d.Get("version").(string)) + + _, response, err := contextBasedRestrictionsClient.ReplaceZoneWithContext(context, replaceZoneOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceZoneWithContext failed %s\n%s", err, response)) + } + + return resourceIBMCbrZoneRead(context, d, meta) +} + +func resourceIBMCbrZoneDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + contextBasedRestrictionsClient, err := meta.(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return diag.FromErr(err) + } + + deleteZoneOptions := &contextbasedrestrictionsv1.DeleteZoneOptions{} + + deleteZoneOptions.SetZoneID(d.Id()) + + response, err := contextBasedRestrictionsClient.DeleteZoneWithContext(context, deleteZoneOptions) + if err != nil { + log.Printf("[DEBUG] DeleteZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteZoneWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMCbrZoneMapToAddress(modelMap map[string]interface{}) (contextbasedrestrictionsv1.AddressIntf, error) { + discValue, ok := modelMap["type"] + if ok { + if discValue == "ipAddress" { + return resourceIBMCbrZoneMapToAddressIPAddress(modelMap) + } else if discValue == "ipRange" { + return resourceIBMCbrZoneMapToAddressIPAddressRange(modelMap) + } else if discValue == "subnet" { + return resourceIBMCbrZoneMapToAddressSubnet(modelMap) + } else if discValue == "vpc" { + return resourceIBMCbrZoneMapToAddressVPC(modelMap) + } else if discValue == "serviceRef" { + return resourceIBMCbrZoneMapToAddressServiceRef(modelMap) + } else { + return nil, fmt.Errorf("unexpected value for discriminator property 'type' found in map: '%s'", discValue) + } + } else { + return nil, fmt.Errorf("discriminator property 'type' not found in map") + } +} + +func resourceIBMCbrZoneMapToServiceRefValue(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.ServiceRefValue, error) { + model := &contextbasedrestrictionsv1.ServiceRefValue{} + model.AccountID = core.StringPtr(modelMap["account_id"].(string)) + if modelMap["service_type"] != nil && modelMap["service_type"].(string) != "" { + model.ServiceType = core.StringPtr(modelMap["service_type"].(string)) + } + if modelMap["service_name"] != nil && modelMap["service_name"].(string) != "" { + model.ServiceName = core.StringPtr(modelMap["service_name"].(string)) + } + if modelMap["service_instance"] != nil && modelMap["service_instance"].(string) != "" { + model.ServiceInstance = core.StringPtr(modelMap["service_instance"].(string)) + } + if modelMap["location"] != nil && modelMap["location"].(string) != "" { + model.Location = core.StringPtr(modelMap["location"].(string)) + } + return model, nil +} + +func resourceIBMCbrZoneMapToAddressIPAddress(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.AddressIPAddress, error) { + model := &contextbasedrestrictionsv1.AddressIPAddress{} + model.Type = core.StringPtr(modelMap["type"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMCbrZoneMapToAddressServiceRef(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.AddressServiceRef, error) { + model := &contextbasedrestrictionsv1.AddressServiceRef{} + model.Type = core.StringPtr(modelMap["type"].(string)) + RefModel, err := resourceIBMCbrZoneMapToServiceRefValue(modelMap["ref"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Ref = RefModel + return model, nil +} + +func resourceIBMCbrZoneMapToAddressSubnet(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.AddressSubnet, error) { + model := &contextbasedrestrictionsv1.AddressSubnet{} + model.Type = core.StringPtr(modelMap["type"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMCbrZoneMapToAddressIPAddressRange(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.AddressIPAddressRange, error) { + model := &contextbasedrestrictionsv1.AddressIPAddressRange{} + model.Type = core.StringPtr(modelMap["type"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMCbrZoneMapToAddressVPC(modelMap map[string]interface{}) (*contextbasedrestrictionsv1.AddressVPC, error) { + model := &contextbasedrestrictionsv1.AddressVPC{} + model.Type = core.StringPtr(modelMap["type"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMCbrZoneAddressToMap(model contextbasedrestrictionsv1.AddressIntf) (map[string]interface{}, error) { + if _, ok := model.(*contextbasedrestrictionsv1.AddressIPAddress); ok { + return resourceIBMCbrZoneAddressIPAddressToMap(model.(*contextbasedrestrictionsv1.AddressIPAddress)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressIPAddressRange); ok { + return resourceIBMCbrZoneAddressIPAddressRangeToMap(model.(*contextbasedrestrictionsv1.AddressIPAddressRange)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressSubnet); ok { + return resourceIBMCbrZoneAddressSubnetToMap(model.(*contextbasedrestrictionsv1.AddressSubnet)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressVPC); ok { + return resourceIBMCbrZoneAddressVPCToMap(model.(*contextbasedrestrictionsv1.AddressVPC)) + } else if _, ok := model.(*contextbasedrestrictionsv1.AddressServiceRef); ok { + return resourceIBMCbrZoneAddressServiceRefToMap(model.(*contextbasedrestrictionsv1.AddressServiceRef)) + } else if _, ok := model.(*contextbasedrestrictionsv1.Address); ok { + modelMap := make(map[string]interface{}) + model := model.(*contextbasedrestrictionsv1.Address) + if model.Type != nil { + modelMap["type"] = model.Type + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Ref != nil { + refMap, err := resourceIBMCbrZoneServiceRefValueToMap(model.Ref) + if err != nil { + return modelMap, err + } + modelMap["ref"] = []map[string]interface{}{refMap} + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized contextbasedrestrictionsv1.AddressIntf subtype encountered") + } +} + +func resourceIBMCbrZoneServiceRefValueToMap(model *contextbasedrestrictionsv1.ServiceRefValue) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["account_id"] = model.AccountID + if model.ServiceType != nil { + modelMap["service_type"] = model.ServiceType + } + if model.ServiceName != nil { + modelMap["service_name"] = model.ServiceName + } + if model.ServiceInstance != nil { + modelMap["service_instance"] = model.ServiceInstance + } + if model.Location != nil { + modelMap["location"] = model.Location + } + return modelMap, nil +} + +func resourceIBMCbrZoneAddressIPAddressToMap(model *contextbasedrestrictionsv1.AddressIPAddress) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["value"] = model.Value + return modelMap, nil +} + +func resourceIBMCbrZoneAddressServiceRefToMap(model *contextbasedrestrictionsv1.AddressServiceRef) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + refMap, err := resourceIBMCbrZoneServiceRefValueToMap(model.Ref) + if err != nil { + return modelMap, err + } + modelMap["ref"] = []map[string]interface{}{refMap} + return modelMap, nil +} + +func resourceIBMCbrZoneAddressSubnetToMap(model *contextbasedrestrictionsv1.AddressSubnet) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["value"] = model.Value + return modelMap, nil +} + +func resourceIBMCbrZoneAddressIPAddressRangeToMap(model *contextbasedrestrictionsv1.AddressIPAddressRange) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["value"] = model.Value + return modelMap, nil +} + +func resourceIBMCbrZoneAddressVPCToMap(model *contextbasedrestrictionsv1.AddressVPC) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["value"] = model.Value + return modelMap, nil +} diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go new file mode 100644 index 000000000..9910b0788 --- /dev/null +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go @@ -0,0 +1,168 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package contextbasedrestrictions_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/contextbasedrestrictionsv1" +) + +func TestAccIBMCbrZoneBasic(t *testing.T) { + var conf contextbasedrestrictionsv1.Zone + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCbrZoneDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrZoneConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCbrZoneExists("ibm_cbr_zone.cbr_zone", conf), + ), + }, + }, + }) +} + +func TestAccIBMCbrZoneAllArgs(t *testing.T) { + var conf contextbasedrestrictionsv1.Zone + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + accountID := fmt.Sprintf("12ab34cd56ef78ab90cd12ef34ab56cd") + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + accountIDUpdate := fmt.Sprintf("12ab34cd56ef78ab90cd12ef34ab56cd") + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCbrZoneDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCbrZoneConfig(name, accountID, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCbrZoneExists("ibm_cbr_zone.cbr_zone", conf), + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "name", name), + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "account_id", accountID), + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "description", description), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCbrZoneConfig(nameUpdate, accountIDUpdate, descriptionUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "account_id", accountIDUpdate), + resource.TestCheckResourceAttr("ibm_cbr_zone.cbr_zone", "description", descriptionUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_cbr_zone.cbr_zone", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMCbrZoneConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_cbr_zone" "cbr_zone" { + name = "Test Zone Resource Config Basic" + description = "Test Zone Resource Config Basic" + account_id = "12ab34cd56ef78ab90cd12ef34ab56cd" + addresses { + type = "ipRange" + value = "169.23.22.0-169.23.22.255" + } + } + `) +} + +func testAccCheckIBMCbrZoneConfig(name string, accountID string, description string) string { + return fmt.Sprintf(` + resource "ibm_cbr_zone" "cbr_zone" { + name = "%s" + description = "%s" + account_id = "%s" + addresses { + type = "ipRange" + value = "169.23.22.0-169.23.22.255" + } + excluded { + type = "ipAddress" + value = "169.23.22.10" + } + addresses { + type = "serviceRef" + ref { + service_name = "user-management" + account_id = "%s" + } + } + } + `, name, description, accountID, accountID) +} + +func testAccCheckIBMCbrZoneExists(n string, obj contextbasedrestrictionsv1.Zone) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + contextBasedRestrictionsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return err + } + + getZoneOptions := &contextbasedrestrictionsv1.GetZoneOptions{} + + getZoneOptions.SetZoneID(rs.Primary.ID) + + zone, _, err := contextBasedRestrictionsClient.GetZone(getZoneOptions) + if err != nil { + return err + } + + obj = *zone + return nil + } +} + +func testAccCheckIBMCbrZoneDestroy(s *terraform.State) error { + contextBasedRestrictionsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContextBasedRestrictionsV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_cbr_zone" { + continue + } + + getZoneOptions := &contextbasedrestrictionsv1.GetZoneOptions{} + + getZoneOptions.SetZoneID(rs.Primary.ID) + + // Try to find the key + _, response, err := contextBasedRestrictionsClient.GetZone(getZoneOptions) + + if err == nil { + return fmt.Errorf("cbr_zone still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for cbr_zone (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/cos/README.md b/ibm/service/cos/README.md new file mode 100644 index 000000000..98644d0cd --- /dev/null +++ b/ibm/service/cos/README.md @@ -0,0 +1,13 @@ +# Terraform IBM Provider Object Storage + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the COS resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cos_bucket) +* IBM API Docs: [IBM API Docs for COS](https://cloud.ibm.com/apidocs/cos/cos-compatibility) +* IBM API Docs: [IBM API Docs for COS Config](https://cloud.ibm.com/apidocs/cos/cos-configuration) +* IBM COS SDK: [IBM SDK for COS Config](github.com/IBM/ibm-cos-sdk-go-config) +* IBM COS SDK: [IBM SDK for COS](https://github.com/IBM/ibm-cos-sdk-go/) diff --git a/ibm/service/cos/data_source_ibm_cos_bucket.go b/ibm/service/cos/data_source_ibm_cos_bucket.go new file mode 100644 index 000000000..c271f3870 --- /dev/null +++ b/ibm/service/cos/data_source_ibm_cos_bucket.go @@ -0,0 +1,656 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cos + +import ( + "fmt" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" + "github.com/IBM/ibm-cos-sdk-go/aws" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" + "github.com/IBM/ibm-cos-sdk-go/aws/session" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var bucketTypes = []string{"single_site_location", "region_location", "cross_region_location"} + +func DataSourceIBMCosBucket() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMCosBucketRead, + + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + }, + "bucket_type": { + Type: schema.TypeString, + // ValidateFunc: validate.ValidateAllowedStringValues(bucketTypes), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_cos_bucket", "bucket_type"), + Optional: true, + RequiredWith: []string{"bucket_region"}, + ConflictsWith: []string{"satellite_location_id"}, + }, + "bucket_region": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"bucket_type"}, + ConflictsWith: []string{"satellite_location_id"}, + }, + "resource_instance_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_cos_bucket", "resource_instance_id"), + }, + "satellite_location_id": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"bucket_type", "bucket_region"}, + ExactlyOneOf: []string{"satellite_location_id", "bucket_region"}, + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + // ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "direct"}), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_cos_bucket", "endpoint_type"), + Description: "public or private", + ConflictsWith: []string{"satellite_location_id"}, + Default: "public", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "CRN of resource instance", + }, + "key_protect": { + Type: schema.TypeString, + Computed: true, + Description: "CRN of the key you want to use data at rest encryption", + }, + "single_site_location": { + Type: schema.TypeString, + Computed: true, + }, + "region_location": { + Type: schema.TypeString, + Computed: true, + }, + "cross_region_location": { + Type: schema.TypeString, + Computed: true, + }, + "storage_class": { + Type: schema.TypeString, + Computed: true, + }, + "s3_endpoint_public": { + Type: schema.TypeString, + Computed: true, + Description: "Public endpoint for the COS bucket", + }, + "s3_endpoint_private": { + Type: schema.TypeString, + Computed: true, + Description: "Private endpoint for the COS bucket", + }, + "s3_endpoint_direct": { + Type: schema.TypeString, + Computed: true, + Description: "Direct endpoint for the COS bucket", + }, + "allowed_ip": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of IPv4 or IPv6 addresses ", + }, + "activity_tracking": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_data_events": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, all object read events will be sent to Activity Tracker.", + }, + "write_data_events": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, all object write events will be sent to Activity Tracker.", + }, + "activity_tracker_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The instance of Activity Tracker that will receive object event data", + }, + }, + }, + }, + "metrics_monitoring": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "usage_metrics_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Usage metrics will be sent to the monitoring service.", + }, + "request_metrics_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Request metrics will be sent to the monitoring service.", + }, + "metrics_monitoring_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", + }, + }, + }, + }, + "abort_incomplete_multipart_upload_days": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "days_after_initiation": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, + "archive_rule": { + Type: schema.TypeList, + Computed: true, + Description: "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an archive rule for a bucket", + }, + "days": { + Type: schema.TypeInt, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "expire_rule": { + Type: schema.TypeList, + Computed: true, + Description: "Enable configuration expire_rule to COS Bucket", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an archive rule for a bucket", + }, + "date": { + Type: schema.TypeString, + Computed: true, + Description: "Specifies the date when the specific rule action takes effect.", + }, + "days": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "expired_object_delete_marker": { + Type: schema.TypeBool, + Computed: true, + Description: "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", + }, + }, + }, + }, + "retention_rule": { + Type: schema.TypeList, + Computed: true, + Description: "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "If an object is stored in the bucket without specifying a custom retention period.", + }, + "maximum": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum duration of time an object can be kept unmodified in the bucket.", + }, + "minimum": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum duration of time an object must be kept unmodified in the bucket", + }, + "permanent": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable the permanent retention policy on the bucket", + }, + }, + }, + }, + "object_versioning": { + Type: schema.TypeList, + Computed: true, + Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or suspend the versioning for objects in the bucket", + }, + }, + }, + }, + "noncurrent_version_expiration": { + Type: schema.TypeList, + Computed: true, + Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an expire rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "noncurrent_days": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, + "replication_rule": { + Type: schema.TypeList, + Computed: true, + Description: "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "A unique identifier for the rule. The maximum value is 255 characters.", + }, + "priority": { + Type: schema.TypeInt, + Computed: true, + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an replication rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "deletemarker_replication_status": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether to replicate delete markers. It should be either Enable or Disable", + }, + "destination_bucket_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + }, + }, + }, + }, + "hard_quota": { + Type: schema.TypeInt, + Computed: true, + Description: "sets a maximum amount of storage (in bytes) available for a bucket", + }, + }, + } +} + +func DataSourceIBMCosBucketValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_instance_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:cloud-object-storage"}}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "bucket_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "single_site_location,region_location,cross_region_location", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "endpoint_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "public,private,direct", + }) + + ibmCOSBucketDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_cos_bucket", Schema: validateSchema} + return &ibmCOSBucketDataSourceValidator +} +func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error { + var s3Conf *aws.Config + rsConClient, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + bucketName := d.Get("bucket_name").(string) + serviceID := d.Get("resource_instance_id").(string) + bucketType := d.Get("bucket_type").(string) + bucketRegion := d.Get("bucket_region").(string) + endpointType := d.Get("endpoint_type").(string) + + var satlc_id, apiEndpoint, apiEndpointPrivate, directApiEndpoint string + + if satlc, ok := d.GetOk("satellite_location_id"); ok { + satlc_id = satlc.(string) + satloc_guid := strings.Split(serviceID, ":") + bucketsatcrn := satloc_guid[7] + serviceID = bucketsatcrn + bucketType = "sl" + } + + if bucketType == "sl" { + apiEndpoint = SelectSatlocCosApi(bucketType, serviceID, satlc_id) + + } else { + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(bucketLocationConvert(bucketType), bucketRegion) + if endpointType == "private" { + apiEndpoint = apiEndpointPrivate + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + if apiEndpoint == "" { + return fmt.Errorf("[ERROR] The endpoint doesn't exists for given location %s and endpoint type %s", bucketRegion, endpointType) + } + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + headInput := &s3.HeadBucketInput{ + Bucket: aws.String(bucketName), + } + err = s3Client.WaitUntilBucketExists(headInput) + if err != nil { + return fmt.Errorf("failed waiting for bucket %s to be created, %v", + bucketName, err) + } + + if bucketType != "sl" { + bucketLocationInput := &s3.GetBucketLocationInput{ + Bucket: aws.String(bucketName), + } + bucketLocationConstraint, err := s3Client.GetBucketLocation(bucketLocationInput) + if err != nil { + return err + } + bLocationConstraint := *bucketLocationConstraint.LocationConstraint + + if singleSiteLocationRegex.MatchString(bLocationConstraint) { + d.Set("single_site_location", strings.Split(bLocationConstraint, "-")[0]) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) + } + if regionLocationRegex.MatchString(bLocationConstraint) { + d.Set("region_location", fmt.Sprintf("%s-%s", strings.Split(bLocationConstraint, "-")[0], strings.Split(bLocationConstraint, "-")[1])) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[2]) + } + if crossRegionLocationRegex.MatchString(bLocationConstraint) { + d.Set("cross_region_location", strings.Split(bLocationConstraint, "-")[0]) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) + } + } else { + d.Set("satellite_location_id", satlc_id) + } + + head, err := s3Client.HeadBucket(headInput) + if err != nil { + return err + } + bucketID := fmt.Sprintf("%s:%s:%s:meta:%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName, bucketLocationConvert(bucketType), bucketRegion, endpointType) + d.SetId(bucketID) + d.Set("key_protect", head.IBMSSEKPCrkId) + bucketCRN := fmt.Sprintf("%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName) + d.Set("crn", bucketCRN) + d.Set("resource_instance_id", serviceID) + d.Set("s3_endpoint_public", apiEndpoint) + d.Set("s3_endpoint_private", apiEndpointPrivate) + d.Set("s3_endpoint_direct", directApiEndpoint) + + getBucketConfigOptions := &resourceconfigurationv1.GetBucketConfigOptions{ + Bucket: &bucketName, + } + + sess, err := meta.(conns.ClientSession).CosConfigV1API() + if err != nil { + return err + } + + if endpointType == "private" { + sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") + } + + if bucketType == "sl" { + satconfig := fmt.Sprintf("https://config.%s.%s.cloud-object-storage.appdomain.cloud/v1", serviceID, satlc_id) + + sess.SetServiceURL(satconfig) + + } + + bucketPtr, response, err := sess.GetBucketConfig(getBucketConfigOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error in getting bucket info rule: %s\n%s", err, response) + } + + if bucketPtr != nil { + if bucketPtr.Firewall != nil { + d.Set("allowed_ip", flex.FlattenStringList(bucketPtr.Firewall.AllowedIp)) + } + if bucketPtr.ActivityTracking != nil { + d.Set("activity_tracking", flex.FlattenActivityTrack(bucketPtr.ActivityTracking)) + } + if bucketPtr.MetricsMonitoring != nil { + d.Set("metrics_monitoring", flex.FlattenMetricsMonitor(bucketPtr.MetricsMonitoring)) + } + if bucketPtr.HardQuota != nil { + d.Set("hard_quota", bucketPtr.HardQuota) + } + + } + + // Read the lifecycle configuration + + gInput := &s3.GetBucketLifecycleConfigurationInput{ + Bucket: aws.String(bucketName), + } + + lifecycleptr, err := s3Client.GetBucketLifecycleConfiguration(gInput) + + if (err != nil && !strings.Contains(err.Error(), "NoSuchLifecycleConfiguration: The lifecycle configuration does not exist")) && (err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied")) { + return err + } + + if lifecycleptr != nil { + if len(lifecycleptr.Rules) > 0 { + archiveRules := flex.ArchiveRuleGet(lifecycleptr.Rules) + expireRules := flex.ExpireRuleGet(lifecycleptr.Rules) + nc_expRules := flex.Nc_exp_RuleGet(lifecycleptr.Rules) + abort_mpuRules := flex.Abort_mpu_RuleGet(lifecycleptr.Rules) + if len(archiveRules) > 0 { + d.Set("archive_rule", archiveRules) + } + if len(expireRules) > 0 { + d.Set("expire_rule", expireRules) + } + if len(nc_expRules) > 0 { + d.Set("noncurrent_version_expiration", nc_expRules) + } + if len(abort_mpuRules) > 0 { + d.Set("abort_incomplete_multipart_upload_days", abort_mpuRules) + } + } + } + + // Read the retention policy + retentionInput := &s3.GetBucketProtectionConfigurationInput{ + Bucket: aws.String(bucketName), + } + retentionptr, err := s3Client.GetBucketProtectionConfiguration(retentionInput) + + if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + + if retentionptr != nil { + retentionRules := flex.RetentionRuleGet(retentionptr.ProtectionConfiguration) + if len(retentionRules) > 0 { + d.Set("retention_rule", retentionRules) + } + } + + // Get the object Versioning + versionInput := &s3.GetBucketVersioningInput{ + Bucket: aws.String(bucketName), + } + versionPtr, err := s3Client.GetBucketVersioning(versionInput) + + if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + if versionPtr != nil { + versioningData := flex.FlattenCosObejctVersioning(versionPtr) + if len(versioningData) > 0 { + d.Set("object_versioning", versioningData) + } + } + + // Get the replication rules + getBucketReplicationInput := &s3.GetBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + replicationptr, err := s3Client.GetBucketReplication(getBucketReplicationInput) + + if err != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") && !strings.Contains(err.Error(), "The replication configuration was not found") { + return err + } + + if replicationptr != nil { + replicationRules := flex.ReplicationRuleGet(replicationptr.ReplicationConfiguration) + if len(replicationRules) > 0 { + d.Set("replication_rule", replicationRules) + } + } + + return nil +} + +func bucketLocationConvert(locationtype string) string { + if locationtype == "cross_region_location" { + return "crl" + } + if locationtype == "region_location" { + return "rl" + } + if locationtype == "single_site_location" { + return "ssl" + } + return "" +} diff --git a/ibm/data_source_ibm_cos_bucket_object.go b/ibm/service/cos/data_source_ibm_cos_bucket_object.go similarity index 92% rename from ibm/data_source_ibm_cos_bucket_object.go rename to ibm/service/cos/data_source_ibm_cos_bucket_object.go index 6eb1f409b..9fc057e88 100644 --- a/ibm/data_source_ibm_cos_bucket_object.go +++ b/ibm/service/cos/data_source_ibm_cos_bucket_object.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cos import ( "bytes" @@ -11,13 +11,15 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/ibm-cos-sdk-go/aws" "github.com/IBM/ibm-cos-sdk-go/service/s3" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMCosBucketObject() *schema.Resource { +func DataSourceIBMCosBucketObject() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMCosBucketObjectRead, @@ -50,7 +52,7 @@ func dataSourceIBMCosBucketObject() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "direct"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "direct"}), Description: "COS endpoint type: public, private, direct", Default: "public", }, @@ -89,7 +91,7 @@ func dataSourceIBMCosBucketObjectRead(ctx context.Context, d *schema.ResourceDat bucketLocation := d.Get("bucket_location").(string) endpointType := d.Get("endpoint_type").(string) - bxSession, err := m.(ClientSession).BluemixSession() + bxSession, err := m.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } diff --git a/ibm/data_source_ibm_cos_bucket_object_test.go b/ibm/service/cos/data_source_ibm_cos_bucket_object_test.go similarity index 91% rename from ibm/data_source_ibm_cos_bucket_object_test.go rename to ibm/service/cos/data_source_ibm_cos_bucket_object_test.go index b0b2bfeab..ae6d1f4b0 100644 --- a/ibm/data_source_ibm_cos_bucket_object_test.go +++ b/ibm/service/cos/data_source_ibm_cos_bucket_object_test.go @@ -1,23 +1,25 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cos_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCOSBucketObjectDataSource_basic(t *testing.T) { name := "tf-testacc-cos" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCOS(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCOS(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccIBMCOSBucketObjectDataSourceConfig_basic(name, cosCRN), + Config: testAccIBMCOSBucketObjectDataSourceConfig_basic(name, acc.CosCRN), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_cos_bucket_object.testacc", "id"), resource.TestCheckResourceAttrSet("data.ibm_cos_bucket_object.testacc", "body"), diff --git a/ibm/service/cos/resource_ibm_cos_bucket.go b/ibm/service/cos/resource_ibm_cos_bucket.go new file mode 100644 index 000000000..e43aa2c3b --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_bucket.go @@ -0,0 +1,1639 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cos + +import ( + "context" + "fmt" + "log" + "regexp" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" + "github.com/IBM/ibm-cos-sdk-go/aws" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" + "github.com/IBM/ibm-cos-sdk-go/aws/session" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var singleSiteLocation = []string{ + "ams03", "che01", "hkg02", "mel01", "mex01", + "mil01", "mon01", "osl01", "par01", "sjc04", "sao01", + "seo01", "sng01", "tor01", +} + +var regionLocation = []string{ + "au-syd", "ca-tor", "eu-de", "eu-gb", "jp-tok", "jp-osa", "us-east", "us-south", "br-sao", +} + +var crossRegionLocation = []string{ + "us", "eu", "ap", +} + +var storageClass = []string{ + "standard", "vault", "cold", "smart", "flex", "onerate_active", +} + +var singleSiteLocationRegex = regexp.MustCompile("^[a-z]{3}[0-9][0-9]-[a-z]{4,8}$") +var regionLocationRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{2,5}[0-9]?-[a-z]{4,8}$") +var crossRegionLocationRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{4,8}$") + +const ( + keyAlgorithm = "AES256" +) + +func caseDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { + return strings.ToUpper(old) == strings.ToUpper(new) +} + +func resourceinstanceidDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { + if old != "" && strings.Contains(new, old) { + return true + } + return false +} +func ResourceIBMCOSBucket() *schema.Resource { + return &schema.Resource{ + Read: resourceIBMCOSBucketRead, + Create: resourceIBMCOSBucketCreate, + Update: resourceIBMCOSBucketUpdate, + Delete: resourceIBMCOSBucketDelete, + Exists: resourceIBMCOSBucketExists, + Importer: &schema.ResourceImporter{}, + CustomizeDiff: resourceExpiryValidate, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "COS Bucket name", + }, + "resource_instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "resource instance ID", + DiffSuppressFunc: resourceinstanceidDiffSuppress, + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "resource_instance_id"), + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "CRN of resource instance", + }, + "key_protect": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "CRN of the key you want to use data at rest encryption", + }, + "satellite_location_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"cross_region_location", "single_site_location", "region_location"}, + Description: "Provide satellite location info.", + }, + "single_site_location": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "single_site_location"), + ForceNew: true, + ConflictsWith: []string{"region_location", "cross_region_location", "satellite_location_id"}, + Description: "single site location info", + }, + "region_location": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"cross_region_location", "single_site_location", "satellite_location_id"}, + Description: "Region Location info.", + }, + "cross_region_location": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "cross_region_location"), + ForceNew: true, + ConflictsWith: []string{"region_location", "single_site_location", "satellite_location_id"}, + Description: "Cros region location info", + }, + "storage_class": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "Storage class info", + ConflictsWith: []string{"satellite_location_id"}, + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "storage_class"), + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + Description: "public or private", + ConflictsWith: []string{"satellite_location_id"}, + DiffSuppressFunc: flex.ApplyOnce, + Default: "public", + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "endpoint_type"), + }, + "s3_endpoint_public": { + Type: schema.TypeString, + Computed: true, + Description: "Public endpoint for the COS bucket", + }, + "s3_endpoint_private": { + Type: schema.TypeString, + Computed: true, + Description: "Private endpoint for the COS bucket", + }, + "s3_endpoint_direct": { + Type: schema.TypeString, + Computed: true, + Description: "Direct endpoint for the COS bucket", + }, + "allowed_ip": { + Type: schema.TypeList, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + ConflictsWith: []string{"satellite_location_id"}, + Description: "List of IPv4 or IPv6 addresses ", + }, + "activity_tracking": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enables sending log data to Activity Tracker and LogDNA to provide visibility into object read and write events", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "read_data_events": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If set to true, all object read events will be sent to Activity Tracker.", + }, + "write_data_events": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If set to true, all object write events will be sent to Activity Tracker.", + }, + "activity_tracker_crn": { + Type: schema.TypeString, + Required: true, + Description: "The instance of Activity Tracker that will receive object event data", + }, + }, + }, + }, + "metrics_monitoring": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enables sending metrics to IBM Cloud Monitoring.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "usage_metrics_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Usage metrics will be sent to the monitoring service.", + }, + "request_metrics_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Request metrics will be sent to the monitoring service.", + }, + "metrics_monitoring_crn": { + Type: schema.TypeString, + Required: true, + Description: "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", + }, + }, + }, + }, + "abort_incomplete_multipart_upload_days": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enable abort incomplete multipart upload to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "days_after_initiation": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validate.ValidateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, + "archive_rule": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule.Archive rules allow you to set a specific time frame after which objects transition to the archive. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an archive rule for a bucket", + }, + "days": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(0, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_cos_bucket", "type"), + DiffSuppressFunc: caseDiffSuppress, + Description: "Specifies the storage class/archive type to which you want the object to transition. It can be Glacier or Accelerated", + }, + }, + }, + }, + "expire_rule": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1000, + Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an expire rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "date": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidBucketLifecycleTimestamp, + Description: "Specify a rule to expire the current version of objects in bucket after a specific date.", + }, + "days": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validate.ValidateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + "expired_object_delete_marker": { + Type: schema.TypeBool, + Optional: true, + Description: "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", + }, + }, + }, + }, + "retention_rule": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(0, 365243), + Description: "If an object is stored in the bucket without specifying a custom retention period.", + ForceNew: false, + }, + "maximum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(0, 365243), + Description: "Maximum duration of time an object can be kept unmodified in the bucket.", + ForceNew: false, + }, + "minimum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(0, 365243), + Description: "Minimum duration of time an object must be kept unmodified in the bucket", + ForceNew: false, + }, + "permanent": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable or disable the permanent retention policy on the bucket", + }, + }, + }, + }, + "object_versioning": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"retention_rule"}, + Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable or suspend the versioning for objects in the bucket", + }, + }, + }, + }, + "noncurrent_version_expiration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an expire rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "noncurrent_days": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validate.ValidateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, + "hard_quota": { + Type: schema.TypeInt, + Optional: true, + Description: "sets a maximum amount of storage (in bytes) available for a bucket", + }, + "force_delete": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "COS buckets need to be empty before they can be deleted. force_delete option empty the bucket and delete it.", + }, + }, + } +} +func ResourceIBMCOSBucketValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_instance_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^crn:.+:.+:.+:.+:.+:a\/[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\:\:$`, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:cloud-object-storage"}}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "single_site_location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "ams03,che01,hkg02,mel01,mex01,mil01,mon01,osl01,par01,sjc04,sao01,seo01,sng01,tor01", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cross_region_location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "us,eu,ap", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "storage_class", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "standard,vault,cold,smart,flex,onerate_active", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "endpoint_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "public,private,direct", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "GLACIER,ACCELERATED,Glacier,Accelerated,glacier,accelerated", + }) + + ibmCOSBucketResourceValidator := validate.ResourceValidator{ResourceName: "ibm_cos_bucket", Schema: validateSchema} + return &ibmCOSBucketResourceValidator +} + +func archiveRuleList(archiveList []interface{}) []*s3.LifecycleRule { + var archive_status, archiveStorageClass, rule_id string + var days int64 + var rules []*s3.LifecycleRule + + for _, l := range archiveList { + archiveMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := archiveMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if archive_statusSet, exist := archiveMap["enable"]; exist { + archiveStatusEnabled := archive_statusSet.(bool) + if archiveStatusEnabled == true { + archive_status = "Enabled" + } else { + archive_status = "Disabled" + } + } + //Days + if daysarchiveSet, exist := archiveMap["days"]; exist { + daysarchive := int64(daysarchiveSet.(int)) + days = daysarchive + } + //Archive Type + if archiveStorgaeClassSet, exist := archiveMap["type"]; exist { + archiveType := archiveStorgaeClassSet.(string) + archiveStorageClass = archiveType + } + + archive_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(archive_status), + Filter: &s3.LifecycleRuleFilter{}, + Transitions: []*s3.Transition{ + { + Days: aws.Int64(days), + StorageClass: aws.String(archiveStorageClass), + }, + }, + } + + rules = append(rules, &archive_rule) + } + return rules +} + +func nc_expRuleList(nc_expList []interface{}) []*s3.LifecycleRule { + var nc_exp_prefix, nc_exp_status, rule_id string + var nc_days int64 + var rules []*s3.LifecycleRule + + for _, l := range nc_expList { + nc_expMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := nc_expMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if nc_exp_statusSet, exist := nc_expMap["enable"]; exist { + nc_expStatusEnabled := nc_exp_statusSet.(bool) + if nc_expStatusEnabled == true { + nc_exp_status = "Enabled" + } else { + nc_exp_status = "Disabled" + } + } + //Days + if nc_exp_daySet, exist := nc_expMap["noncurrent_days"]; exist { + nc_exp_days := int64(nc_exp_daySet.(int)) + nc_days = nc_exp_days + } + //Expire Prefix + if nc_expPrefixClassSet, exist := nc_expMap["prefix"]; exist { + prefix_check := nc_expPrefixClassSet.(string) + nc_exp_prefix = prefix_check + } + + nc_exp_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(nc_exp_status), + Filter: &s3.LifecycleRuleFilter{ + Prefix: aws.String(nc_exp_prefix), + }, + NoncurrentVersionExpiration: &s3.NoncurrentVersionExpiration{ + NoncurrentDays: aws.Int64(nc_days), + }, + } + rules = append(rules, &nc_exp_rule) + } + return rules +} + +func abortmpuRuleList(abortmpuList []interface{}) []*s3.LifecycleRule { + var abort_mpu_prefix, abort_mpu_status, rule_id string + var abort_mpu_days_init int64 + var rules []*s3.LifecycleRule + + for _, l := range abortmpuList { + abortmpuMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := abortmpuMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if abort_mpu_statusSet, exist := abortmpuMap["enable"]; exist { + abort_mpuStatusEnabled := abort_mpu_statusSet.(bool) + if abort_mpuStatusEnabled == true { + abort_mpu_status = "Enabled" + } else { + abort_mpu_status = "Disabled" + } + } + //Days + if abort_mpu_daySet, exist := abortmpuMap["days_after_initiation"]; exist { + abort_mpu_days := int64(abort_mpu_daySet.(int)) + abort_mpu_days_init = abort_mpu_days + } + //Expire Prefix + if abort_mpuPrefixClassSet, exist := abortmpuMap["prefix"]; exist { + prefix_check := abort_mpuPrefixClassSet.(string) + abort_mpu_prefix = prefix_check + } + + abort_mpu_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(abort_mpu_status), + Filter: &s3.LifecycleRuleFilter{ + Prefix: aws.String(abort_mpu_prefix), + }, + AbortIncompleteMultipartUpload: &s3.AbortIncompleteMultipartUpload{ + DaysAfterInitiation: aws.Int64(abort_mpu_days_init), + }, + } + rules = append(rules, &abort_mpu_rule) + } + return rules +} + +func expireRuleList(expireList []interface{}) []*s3.LifecycleRule { + var expire_prefix, expire_status, rule_id string + var expire_date time.Time + var days int64 + var expired_object_del_marker bool + var rules []*s3.LifecycleRule + + for _, l := range expireList { + expireMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := expireMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if expire_statusSet, exist := expireMap["enable"]; exist { + expireStatusEnabled := expire_statusSet.(bool) + if expireStatusEnabled == true { + expire_status = "Enabled" + } else { + expire_status = "Disabled" + } + } + //Days + if daysexpireSet, exist := expireMap["days"]; exist { + daysexpire := int64(daysexpireSet.(int)) + days = daysexpire + } + //Date + if dateexpireSet, exist := expireMap["date"]; exist { + expiredatevalue := dateexpireSet.(string) + expire_date, _ = time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", expiredatevalue)) + } + //Expire Prefix + if expirePrefixClassSet, exist := expireMap["prefix"]; exist { + prefix := expirePrefixClassSet.(string) + expire_prefix = prefix + } + // Expired Object Delete Marker + if expireObjectDelMarkerSet, exist := expireMap["expired_object_delete_marker"]; exist { + expired_object_del_marker = expireObjectDelMarkerSet.(bool) + } + var i *s3.LifecycleExpiration + + if expired_object_del_marker == true { + i = &s3.LifecycleExpiration{ + ExpiredObjectDeleteMarker: aws.Bool(expired_object_del_marker), + } + } else if days > 0 { + i = &s3.LifecycleExpiration{ + Days: aws.Int64(days), + } + } else if !expire_date.IsZero() { + i = &s3.LifecycleExpiration{ + Date: aws.Time(expire_date), + } + } + expire_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(expire_status), + Filter: &s3.LifecycleRuleFilter{ + Prefix: aws.String(expire_prefix), + }, + + Expiration: i, + } + rules = append(rules, &expire_rule) + } + return rules +} + +func resourceIBMCOSBucketUpdate(d *schema.ResourceData, meta interface{}) error { + var s3Conf *aws.Config + rsConClient, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + bucketName := parseBucketId(d.Id(), "bucketName") + serviceID := parseBucketId(d.Id(), "serviceID") + endpointType := parseBucketId(d.Id(), "endpointType") + bLocation := parseBucketId(d.Id(), "bLocation") + apiType := parseBucketId(d.Id(), "apiType") + if apiType == "sl" { + satloc_guid := strings.Split(serviceID, ":") + bucketsatcrn := satloc_guid[0] + serviceID = bucketsatcrn + } + + var apiEndpoint, apiEndpointPrivate, directApiEndpoint string + + if apiType == "sl" { + apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) + } else { + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + if endpointType == "private" { + apiEndpoint = apiEndpointPrivate + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint)).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint)).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + //// Update the lifecycle (Archive or Expire or Non Current version or Abort incomplete Multipart Upload) + if d.HasChange("archive_rule") || d.HasChange("expire_rule") || d.HasChange("noncurrent_version_expiration") || d.HasChange("abort_incomplete_multipart_upload_days") { + var archive, archive_ok = d.GetOk("archive_rule") + var expire, expire_ok = d.GetOk("expire_rule") + var noncurrentverexp, nc_exp_ok = d.GetOk("noncurrent_version_expiration") + var abortmpu, abort_mpu_ok = d.GetOk("abort_incomplete_multipart_upload_days") + var rules []*s3.LifecycleRule + if archive_ok || expire_ok || nc_exp_ok || abort_mpu_ok { + if archive_ok { + rules = append(rules, archiveRuleList(archive.([]interface{}))...) + } + if nc_exp_ok { + rules = append(rules, nc_expRuleList(noncurrentverexp.([]interface{}))...) + } + if abort_mpu_ok { + rules = append(rules, abortmpuRuleList(abortmpu.([]interface{}))...) + } + if expire_ok { + rules = append(rules, expireRuleList(expire.([]interface{}))...) + } + lInput := &s3.PutBucketLifecycleConfigurationInput{ + Bucket: aws.String(bucketName), + LifecycleConfiguration: &s3.LifecycleConfiguration{ + Rules: rules, + }, + } + + _, err := s3Client.PutBucketLifecycleConfiguration(lInput) + if err != nil { + return fmt.Errorf("failed to update the lifecyle rule on COS bucket %s, %v", bucketName, err) + } + + } else { + DelInput := &s3.DeleteBucketLifecycleInput{ + Bucket: aws.String(bucketName), + } + + delarchive, _ := s3Client.DeleteBucketLifecycleRequest(DelInput) + err := delarchive.Send() + if err != nil { + return err + } + } + } + + //// Update the Retention policy + if d.HasChange("retention_rule") { + var defaultretention, minretention, maxretention int64 + var permanentretention bool + if retention, ok := d.GetOk("retention_rule"); ok { + retentionList := retention.([]interface{}) + if len(retentionList) > 1 { + return fmt.Errorf("Can not more than 1 retention policy") + } + for _, l := range retentionList { + retentionMap, _ := l.(map[string]interface{}) + //Default Days + if defaultretentionSet, exist := retentionMap["default"]; exist { + defaultdays := int64(defaultretentionSet.(int)) + defaultretention = defaultdays + } + //Maximum Days + if maxretentionSet, exist := retentionMap["maximum"]; exist { + maxdays := int64(maxretentionSet.(int)) + maxretention = maxdays + } + //Minimum Days + if minretentionSet, exist := retentionMap["minimum"]; exist { + mindays := int64(minretentionSet.(int)) + minretention = mindays + } + //Permanent Retention Enable/Disable + if permanentretentionSet, exist := retentionMap["permanent"]; exist { + permanentretention = permanentretentionSet.(bool) + } + } + // PUT BUCKET PROTECTION CONFIGURATION + pInput := &s3.PutBucketProtectionConfigurationInput{ + Bucket: aws.String(bucketName), + ProtectionConfiguration: &s3.ProtectionConfiguration{ + DefaultRetention: &s3.BucketProtectionDefaultRetention{ + Days: aws.Int64(defaultretention), + }, + MaximumRetention: &s3.BucketProtectionMaximumRetention{ + Days: aws.Int64(maxretention), + }, + MinimumRetention: &s3.BucketProtectionMinimumRetention{ + Days: aws.Int64(minretention), + }, + Status: aws.String("Retention"), + EnablePermanentRetention: aws.Bool(permanentretention), + }, + } + _, err := s3Client.PutBucketProtectionConfiguration(pInput) + if err != nil { + return fmt.Errorf("failed to update the retention rule on COS bucket %s, %v", bucketName, err) + } + } + } + + //update the object versioning (object versioning) + if d.HasChange("object_versioning") { + versioningConf := &s3.VersioningConfiguration{} + if versioning, ok := d.GetOk("object_versioning"); ok { + versioningList := versioning.([]interface{}) + for _, l := range versioningList { + versioningMap, _ := l.(map[string]interface{}) + //Status Enable/Disable + if object_versioning_statusSet, exist1 := versioningMap["enable"]; exist1 { + versioningStatusEnabled := object_versioning_statusSet.(bool) + if versioningStatusEnabled == true { + versioningConf.Status = aws.String("Enabled") + } else { + versioningConf.Status = aws.String("Suspended") + } + } + } + } else { + versioningConf.Status = aws.String("Suspended") + } + // PUT BUCKET Object Versioning + input := &s3.PutBucketVersioningInput{ + Bucket: aws.String(bucketName), + VersioningConfiguration: versioningConf, + } + + _, err := s3Client.PutBucketVersioning(input) + if err != nil { + return fmt.Errorf("failed to update the object versioning on COS bucket %s, %v", bucketName, err) + } + } + + sess, err := meta.(conns.ClientSession).CosConfigV1API() + if err != nil { + return err + } + if endpointType == "private" { + sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") + } + + if apiType == "sl" { + satconfig := fmt.Sprintf("https://config.%s.%s.cloud-object-storage.appdomain.cloud/v1", serviceID, bLocation) + + sess.SetServiceURL(satconfig) + } + + hasChanged := false + updateBucketConfigOptions := &resourceconfigurationv1.UpdateBucketConfigOptions{} + + //BucketName + bucketName = d.Get("bucket_name").(string) + updateBucketConfigOptions.Bucket = &bucketName + + if d.HasChange("hard_quota") { + hasChanged = true + updateBucketConfigOptions.HardQuota = aws.Int64(int64(d.Get("hard_quota").(int))) + } + + if d.HasChange("allowed_ip") { + firewall := &resourceconfigurationv1.Firewall{} + var ips = make([]string, 0) + if ip, ok := d.GetOk("allowed_ip"); ok && ip != nil { + for _, i := range ip.([]interface{}) { + ips = append(ips, i.(string)) + } + firewall.AllowedIp = ips + } else { + firewall.AllowedIp = []string{} + } + hasChanged = true + updateBucketConfigOptions.Firewall = firewall + } + + if d.HasChange("activity_tracking") { + activityTracker := &resourceconfigurationv1.ActivityTracking{} + if activity, ok := d.GetOk("activity_tracking"); ok { + activitylist := activity.([]interface{}) + for _, l := range activitylist { + activityMap, _ := l.(map[string]interface{}) + + //Read event - as its optional check for existence + if readEvent := activityMap["read_data_events"]; readEvent != nil { + readSet := readEvent.(bool) + activityTracker.ReadDataEvents = &readSet + } + + //Write Event - as its optional check for existence + if writeEvent := activityMap["write_data_events"]; writeEvent != nil { + writeSet := writeEvent.(bool) + activityTracker.WriteDataEvents = &writeSet + } + + //crn - Required field + crn := activityMap["activity_tracker_crn"].(string) + activityTracker.ActivityTrackerCrn = &crn + } + } + hasChanged = true + updateBucketConfigOptions.ActivityTracking = activityTracker + } + + if d.HasChange("metrics_monitoring") { + metricsMonitor := &resourceconfigurationv1.MetricsMonitoring{} + if metrics, ok := d.GetOk("metrics_monitoring"); ok { + metricslist := metrics.([]interface{}) + for _, l := range metricslist { + metricsMap, _ := l.(map[string]interface{}) + + //metrics enabled - as its optional check for existence + if metricsSet := metricsMap["usage_metrics_enabled"]; metricsSet != nil { + metrics := metricsSet.(bool) + metricsMonitor.UsageMetricsEnabled = &metrics + } + // request metrics enabled - as its optional check for existence + if metricsSet := metricsMap["request_metrics_enabled"]; metricsSet != nil { + metrics := metricsSet.(bool) + metricsMonitor.RequestMetricsEnabled = &metrics + } + //crn - Required field + crn := metricsMap["metrics_monitoring_crn"].(string) + metricsMonitor.MetricsMonitoringCrn = &crn + } + } + hasChanged = true + updateBucketConfigOptions.MetricsMonitoring = metricsMonitor + } + + if hasChanged { + response, err := sess.UpdateBucketConfig(updateBucketConfigOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Update COS Bucket: %s\n%s", err, response) + } + } + + return resourceIBMCOSBucketRead(d, meta) +} + +func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { + var s3Conf *aws.Config + rsConClient, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + bucketName := parseBucketId(d.Id(), "bucketName") + serviceID := parseBucketId(d.Id(), "serviceID") + endpointType := parseBucketId(d.Id(), "endpointType") + apiType := parseBucketId(d.Id(), "apiType") + bLocation := parseBucketId(d.Id(), "bLocation") + + //split satellite resource instance id to get the 1st value + if apiType == "sl" { + satloc_guid := strings.Split(serviceID, ":") + bucketsatcrn := satloc_guid[0] + serviceID = bucketsatcrn + } + + var apiEndpoint, apiEndpointPrivate, directApiEndpoint string + + if apiType == "sl" { + apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) + } else { + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + if endpointType == "private" { + apiEndpoint = apiEndpointPrivate + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + + if err != nil { + + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" && apiKey == "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + headInput := &s3.HeadBucketInput{ + Bucket: aws.String(bucketName), + } + + err = s3Client.WaitUntilBucketExists(headInput) + if err != nil { + return fmt.Errorf("failed waiting for bucket %s to be created, %v", + bucketName, err) + } + + bucketOutput, err := s3Client.ListBucketsExtended(&s3.ListBucketsExtendedInput{}) + + if err != nil { + return err + } + + if apiType != "sl" { + var bLocationConstraint string + for _, b := range bucketOutput.Buckets { + if *b.Name == bucketName { + bLocationConstraint = *b.LocationConstraint + } + } + + if singleSiteLocationRegex.MatchString(bLocationConstraint) { + d.Set("single_site_location", strings.Split(bLocationConstraint, "-")[0]) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) + } + if regionLocationRegex.MatchString(bLocationConstraint) { + d.Set("region_location", fmt.Sprintf("%s-%s", strings.Split(bLocationConstraint, "-")[0], strings.Split(bLocationConstraint, "-")[1])) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[2]) + } + if crossRegionLocationRegex.MatchString(bLocationConstraint) { + d.Set("cross_region_location", strings.Split(bLocationConstraint, "-")[0]) + d.Set("storage_class", strings.Split(bLocationConstraint, "-")[1]) + } + } else { + d.Set("satellite_location_id", bLocation) + + } + + bucketCRN := fmt.Sprintf("%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName) + d.Set("crn", bucketCRN) + d.Set("resource_instance_id", serviceID) + d.Set("bucket_name", bucketName) + d.Set("s3_endpoint_public", apiEndpoint) + d.Set("s3_endpoint_private", apiEndpointPrivate) + d.Set("s3_endpoint_direct", directApiEndpoint) + if endpointType != "" { + d.Set("endpoint_type", endpointType) + } + + getBucketConfigOptions := &resourceconfigurationv1.GetBucketConfigOptions{ + Bucket: &bucketName, + } + + sess, err := meta.(conns.ClientSession).CosConfigV1API() + if err != nil { + return err + } + if endpointType == "private" { + sess.SetServiceURL("https://config.private.cloud-object-storage.cloud.ibm.com/v1") + } + + if apiType == "sl" { + + satconfig := fmt.Sprintf("https://config.%s.%s.cloud-object-storage.appdomain.cloud/v1", serviceID, bLocation) + + sess.SetServiceURL(satconfig) + } + + bucketPtr, response, err := sess.GetBucketConfig(getBucketConfigOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error in getting bucket info rule: %s\n%s", err, response) + } + + if bucketPtr != nil { + + if bucketPtr.Firewall != nil { + d.Set("allowed_ip", flex.FlattenStringList(bucketPtr.Firewall.AllowedIp)) + } else { + + d.Set("allowed_ip", []string{}) + } + if bucketPtr.ActivityTracking != nil { + d.Set("activity_tracking", flex.FlattenActivityTrack(bucketPtr.ActivityTracking)) + } else { + + d.Set("activity_tracking", []interface{}{}) + } + + if bucketPtr.MetricsMonitoring != nil { + d.Set("metrics_monitoring", flex.FlattenMetricsMonitor(bucketPtr.MetricsMonitoring)) + } else { + + d.Set("metrics_monitoring", []interface{}{}) + } + if bucketPtr.HardQuota != nil { + d.Set("hard_quota", bucketPtr.HardQuota) + } else { + d.Set("hard_quota", 0) + } + } + // Read the lifecycle configuration (archive & expiration or non current version or abort incomplete multipart upload) + + gInput := &s3.GetBucketLifecycleConfigurationInput{ + Bucket: aws.String(bucketName), + } + + lifecycleptr, err := s3Client.GetBucketLifecycleConfiguration(gInput) + + if (err != nil && !strings.Contains(err.Error(), "NoSuchLifecycleConfiguration: The lifecycle configuration does not exist")) && (err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied")) { + return err + } + if lifecycleptr != nil { + archiveRules := flex.ArchiveRuleGet(lifecycleptr.Rules) + expireRules := flex.ExpireRuleGet(lifecycleptr.Rules) + nc_expRules := flex.Nc_exp_RuleGet(lifecycleptr.Rules) + abort_mpuRules := flex.Abort_mpu_RuleGet(lifecycleptr.Rules) + if len(archiveRules) > 0 { + d.Set("archive_rule", archiveRules) + } + if len(expireRules) > 0 { + d.Set("expire_rule", expireRules) + } + if len(nc_expRules) > 0 { + d.Set("noncurrent_version_expiration", nc_expRules) + } + if len(abort_mpuRules) > 0 { + d.Set("abort_incomplete_multipart_upload_days", abort_mpuRules) + } + } + + // Read retention rule + retentionInput := &s3.GetBucketProtectionConfigurationInput{ + Bucket: aws.String(bucketName), + } + retentionptr, err := s3Client.GetBucketProtectionConfiguration(retentionInput) + + if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + + if retentionptr != nil { + retentionRules := flex.RetentionRuleGet(retentionptr.ProtectionConfiguration) + if len(retentionRules) > 0 { + d.Set("retention_rule", retentionRules) + } + } + + // Read Object versioning + versionInput := &s3.GetBucketVersioningInput{ + Bucket: aws.String(bucketName), + } + + versionPtr, err := s3Client.GetBucketVersioning(versionInput) + + if err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + if versionPtr != nil { + versioningData := flex.FlattenCosObejctVersioning(versionPtr) + + if len(versioningData) > 0 { + d.Set("object_versioning", versioningData) + } else { + d.Set("object_versioning", nil) + } + } + return nil +} + +func resourceIBMCOSBucketCreate(d *schema.ResourceData, meta interface{}) error { + var s3Conf *aws.Config + rsConClient, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + bucketName := d.Get("bucket_name").(string) + storageClass := d.Get("storage_class").(string) + var bLocation string + var apiType string + var satlc_id string + serviceID := d.Get("resource_instance_id").(string) + + //satlc_id := d.GetOK("satellite_location_id") + if satlc, ok := d.GetOk("satellite_location_id"); ok { + satlc_id = satlc.(string) + satloc_guid := strings.Split(serviceID, ":") + bucketsatcrn := satloc_guid[7] + serviceID = bucketsatcrn + } + + if bucketLocation, ok := d.GetOk("cross_region_location"); ok { + bLocation = bucketLocation.(string) + apiType = "crl" + } + if bucketLocation, ok := d.GetOk("region_location"); ok { + bLocation = bucketLocation.(string) + apiType = "rl" + } + if bucketLocation, ok := d.GetOk("single_site_location"); ok { + bLocation = bucketLocation.(string) + apiType = "ssl" + } + //Add satellite location id + if bucketLocation, ok := d.GetOk("satellite_location_id"); ok { + bLocation = bucketLocation.(string) + apiType = "sl" + } + if bLocation == "" { + return fmt.Errorf("Provide either `cross_region_location` or `region_location` or `single_site_location` or `satellite_location_id`") + } + + lConstraint := fmt.Sprintf("%s-%s", bLocation, storageClass) + + var endpointType = d.Get("endpoint_type").(string) + + var apiEndpoint, privateApiEndpoint, directApiEndpoint string + if apiType == "sl" { + + apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) + + } else { + apiEndpoint, privateApiEndpoint, directApiEndpoint = SelectCosApi(apiType, bLocation) + if endpointType == "private" { + apiEndpoint = privateApiEndpoint + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + + if apiEndpoint == "" { + return fmt.Errorf("[ERROR] The endpoint doesn't exists for given location %s and endpoint type %s", bLocation, endpointType) + } + + var create *s3.CreateBucketInput + if satlc_id != "" || storageClass == "" { + create = &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + } + } else { + create = &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + CreateBucketConfiguration: &s3.CreateBucketConfiguration{ + LocationConstraint: aws.String(lConstraint), + }, + } + } + + if keyprotect, ok := d.GetOk("key_protect"); ok { + create.IBMSSEKPCustomerRootKeyCrn = aws.String(keyprotect.(string)) + create.IBMSSEKPEncryptionAlgorithm = aws.String(keyAlgorithm) + } + + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" && apiKey == "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + _, err = s3Client.CreateBucket(create) + + if err != nil { + return err + } + // Generating a fake id which contains every information about to get the bucket via s3 api + bucketID := fmt.Sprintf("%s:%s:%s:meta:%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName, apiType, bLocation, endpointType) + d.SetId(bucketID) + + return resourceIBMCOSBucketUpdate(d, meta) + +} + +func resourceIBMCOSBucketDelete(d *schema.ResourceData, meta interface{}) error { + var s3Conf *aws.Config + rsConClient, _ := meta.(conns.ClientSession).BluemixSession() + bucketName := parseBucketId(d.Id(), "bucketName") + serviceID := d.Get("resource_instance_id").(string) + + var bLocation string + var apiType string + if bucketLocation, ok := d.GetOk("cross_region_location"); ok { + bLocation = bucketLocation.(string) + apiType = "crl" + } + if bucketLocation, ok := d.GetOk("region_location"); ok { + bLocation = bucketLocation.(string) + apiType = "rl" + } + if bucketLocation, ok := d.GetOk("single_site_location"); ok { + bLocation = bucketLocation.(string) + apiType = "ssl" + } + + if bucketLocation, ok := d.GetOk("satellite_location_id"); ok { + bLocation = bucketLocation.(string) + apiType = "sl" + } + + endpointType := parseBucketId(d.Id(), "endpointType") + + var apiEndpoint, apiEndpointPrivate, directApiEndpoint string + + if apiType == "sl" { + + apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) + + } else { + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + if endpointType == "private" { + apiEndpoint = apiEndpointPrivate + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + + if apiEndpoint == "" { + return fmt.Errorf("[ERROR] The endpoint doesn't exists for given location %s and endpoint type %s", bLocation, endpointType) + } + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" && apiKey == "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + delete := &s3.DeleteBucketInput{ + Bucket: aws.String(bucketName), + } + _, err = s3Client.DeleteBucket(delete) + + if err != nil && strings.Contains(err.Error(), "BucketNotEmpty") { + if delbucket, ok := d.GetOk("force_delete"); ok { + if delbucket.(bool) { + // Use a S3 service client that can handle multiple slashes in URIs. + // While ibm_cos_bucket_object resources cannot create these object + // keys, other AWS services and applications using the COS Bucket can. + + // bucket may have things delete them + log.Printf("[DEBUG] COS Bucket attempting to forceDelete %+v", err) + + // Delete everything including locked objects. + // Don't ignore any object errors or we could recurse infinitely. + err = deleteAllCOSObjectVersions(s3Client, bucketName, "", false, false) + + if err != nil { + return fmt.Errorf("[ERROR] Error COS Bucket force_delete: %s", err) + } + + // this line recurses until all objects are deleted or an error is returned + return resourceIBMCOSBucketDelete(d, meta) + } + } + } + if err != nil { + return fmt.Errorf("[ERROR] Error deleting COS Bucket (%s): %s", d.Id(), err) + } + + return nil +} + +func resourceIBMCOSBucketExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + var s3Conf *aws.Config + rsConClient, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return false, err + } + bucket_meta := strings.Split(d.Id(), ":meta:") + if len(bucket_meta) < 2 || len(strings.Split(bucket_meta[1], ":")) < 2 { + return false, fmt.Errorf("[ERROR] Error parsing bucket ID. Bucket ID format must be: $CRN:meta:$buckettype:$bucketlocation") + } + + bucketName := parseBucketId(d.Id(), "bucketName") + serviceID := parseBucketId(d.Id(), "serviceID") + + apiType := parseBucketId(d.Id(), "apiType") + bLocation := parseBucketId(d.Id(), "bLocation") + endpointType := parseBucketId(d.Id(), "endpointType") + + if apiType == "sl" { + satloc_guid := strings.Split(serviceID, ":") + bucketsatcrn := satloc_guid[0] + serviceID = bucketsatcrn + } + + var apiEndpoint, apiEndpointPrivate, directApiEndpoint string + + if apiType == "sl" { + + apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) + + } else { + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + if endpointType == "private" { + apiEndpoint = apiEndpointPrivate + } + if endpointType == "direct" { + apiEndpoint = directApiEndpoint + } + + } + + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + + if apiEndpoint == "" { + return false, fmt.Errorf("[ERROR] The endpoint doesn't exists for given endpoint type %s", endpointType) + } + authEndpoint, err := rsConClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return false, err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + + apiKey := rsConClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, serviceID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsConClient.Config.IAMAccessToken + if iamAccessToken != "" && apiKey == "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsConClient.Config.IAMAccessToken, + RefreshToken: rsConClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, serviceID)).WithS3ForcePathStyle(true) + } + + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + bucketList, err := s3Client.ListBuckets(&s3.ListBucketsInput{}) + if err != nil { + return false, err + } + for _, bucket := range bucketList.Buckets { + if *bucket.Name == bucketName { + return true, nil + } + } + return false, nil +} + +func SelectCosApi(apiType string, bLocation string) (string, string, string) { + if apiType == "crl" { + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + } + if apiType == "rl" { + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + } + if apiType == "ssl" { + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + } + return "", "", "" +} + +// /Satellite ENdpoint configuration +func SelectSatlocCosApi(apiType string, serviceID string, bLocation string) string { + if apiType == "sl" { + return fmt.Sprintf("s3.%s.%s.cloud-object-storage.appdomain.cloud", serviceID, bLocation) + } + return "" +} + +func parseBucketId(id string, info string) string { + crn := strings.Split(id, ":meta:")[0] + meta := strings.Split(id, ":meta:")[1] + + if info == "bucketName" { + return strings.Split(crn, ":bucket:")[1] + } + if info == "serviceID" { + return fmt.Sprintf("%s::", strings.Split(crn, ":bucket:")[0]) + } + if info == "apiType" { + return strings.Split(meta, ":")[0] + } + if info == "bLocation" { + return strings.Split(meta, ":")[1] + } + if info == "endpointType" { + s := strings.Split(meta, ":") + if len(s) > 2 { + return strings.Split(meta, ":")[2] + } + return "" + + } + return "" +} + +func resourceExpiryValidate(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { + if expire, ok := diff.GetOk("expire_rule"); ok { + expire_list := expire.([]interface{}) + for _, l := range expire_list { + expireMap, _ := l.(map[string]interface{}) + ctr := 0 + if val, days_exist := expireMap["days"]; days_exist && val.(int) != 0 { + ctr++ + } + if val, date_exist := expireMap["date"]; date_exist && val != "" { + ctr++ + } + if val, expired_object_delete_marker_exist := expireMap["expired_object_delete_marker"]; expired_object_delete_marker_exist && val.(bool) != false { + ctr++ + } + if ctr > 1 { + return fmt.Errorf("[ERROR] The expiry 3 action elements (Days, Date, ExpiredObjectDeleteMarker) are all mutually exclusive. These can not be used with each other. Please set one expiry element on the same rule of expiration.") + } + } + } + return nil +} diff --git a/ibm/resource_ibm_cos_bucket_object.go b/ibm/service/cos/resource_ibm_cos_bucket_object.go similarity index 91% rename from ibm/resource_ibm_cos_bucket_object.go rename to ibm/service/cos/resource_ibm_cos_bucket_object.go index 36034f28a..53161d1f1 100644 --- a/ibm/resource_ibm_cos_bucket_object.go +++ b/ibm/service/cos/resource_ibm_cos_bucket_object.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cos import ( "bytes" @@ -16,6 +16,8 @@ import ( "time" bxsession "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/ibm-cos-sdk-go/aws" "github.com/IBM/ibm-cos-sdk-go/aws/awserr" "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" @@ -26,7 +28,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMCOSBucketObject() *schema.Resource { +func ResourceIBMCOSBucketObject() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMCOSBucketObjectCreate, ReadContext: resourceIBMCOSBucketObjectRead, @@ -88,7 +90,7 @@ func resourceIBMCOSBucketObject() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private", "direct"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "direct"}), Description: "COS endpoint type: public, private, direct", Default: "public", }, @@ -136,7 +138,7 @@ func resourceIBMCOSBucketObjectCreate(ctx context.Context, d *schema.ResourceDat bucketLocation := d.Get("bucket_location").(string) endpointType := d.Get("endpoint_type").(string) - bxSession, err := m.(ClientSession).BluemixSession() + bxSession, err := m.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } @@ -155,7 +157,7 @@ func resourceIBMCOSBucketObjectCreate(ctx context.Context, d *schema.ResourceDat return diag.FromErr(err) } if exists { - return diag.FromErr(fmt.Errorf("error COS bucket (%s) object (%s) already exists", bucketName, objectKey)) + return diag.FromErr(fmt.Errorf("[ERROR] Error COS bucket (%s) object (%s) already exists", bucketName, objectKey)) } var body io.ReadSeeker @@ -167,14 +169,14 @@ func resourceIBMCOSBucketObjectCreate(ctx context.Context, d *schema.ResourceDat content := v.(string) contentRaw, err := base64.StdEncoding.DecodeString(content) if err != nil { - return diag.FromErr(fmt.Errorf("error decoding content_base64: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error decoding content_base64: %s", err)) } body = bytes.NewReader(contentRaw) } else if v, ok := d.GetOk("content_file"); ok { path := v.(string) file, err := os.Open(path) if err != nil { - return diag.FromErr(fmt.Errorf("error opening COS object file (%s): %s", path, err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error opening COS object file (%s): %s", path, err)) } body = file @@ -193,7 +195,7 @@ func resourceIBMCOSBucketObjectCreate(ctx context.Context, d *schema.ResourceDat } if _, err := s3Client.PutObject(putInput); err != nil { - return diag.FromErr(fmt.Errorf("error putting object (%s) in COS bucket (%s): %s", objectKey, bucketName, err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error putting object (%s) in COS bucket (%s): %s", objectKey, bucketName, err)) } objectID := getObjectId(bucketCRN, objectKey, bucketLocation) @@ -214,7 +216,7 @@ func resourceIBMCOSBucketObjectRead(ctx context.Context, d *schema.ResourceData, d.Set("bucket_crn", bucketCRN) d.Set("bucket_location", bucketLocation) - bxSession, err := m.(ClientSession).BluemixSession() + bxSession, err := m.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } @@ -292,7 +294,7 @@ func resourceIBMCOSBucketObjectUpdate(ctx context.Context, d *schema.ResourceDat bucketLocation := d.Get("bucket_location").(string) endpointType := d.Get("endpoint_type").(string) - bxSession, err := m.(ClientSession).BluemixSession() + bxSession, err := m.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } @@ -311,14 +313,14 @@ func resourceIBMCOSBucketObjectUpdate(ctx context.Context, d *schema.ResourceDat content := v.(string) contentRaw, err := base64.StdEncoding.DecodeString(content) if err != nil { - return diag.FromErr(fmt.Errorf("error decoding content_base64: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error decoding content_base64: %s", err)) } body = bytes.NewReader(contentRaw) } else if v, ok := d.GetOk("content_file"); ok { path := v.(string) file, err := os.Open(path) if err != nil { - return diag.FromErr(fmt.Errorf("error opening COS object file (%s): %s", path, err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error opening COS object file (%s): %s", path, err)) } body = file @@ -339,7 +341,7 @@ func resourceIBMCOSBucketObjectUpdate(ctx context.Context, d *schema.ResourceDat } if _, err := s3Client.PutObject(putInput); err != nil { - return diag.FromErr(fmt.Errorf("error putting object (%s) in COS bucket (%s): %s", objectKey, bucketName, err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error putting object (%s) in COS bucket (%s): %s", objectKey, bucketName, err)) } objectID := getObjectId(bucketCRN, objectKey, bucketLocation) @@ -357,7 +359,7 @@ func resourceIBMCOSBucketObjectDelete(ctx context.Context, d *schema.ResourceDat bucketLocation := d.Get("bucket_location").(string) endpointType := d.Get("endpoint_type").(string) - bxSession, err := m.(ClientSession).BluemixSession() + bxSession, err := m.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } @@ -400,7 +402,7 @@ func getS3Client(bxSession *bxsession.Session, bucketLocation string, endpointTy var s3Conf *aws.Config apiEndpoint := getCosEndpoint(bucketLocation, endpointType) - apiEndpoint = envFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) if apiEndpoint == "" { return nil, fmt.Errorf("the endpoint doesn't exists for given location %s and endpoint type %s", bucketLocation, endpointType) } @@ -558,7 +560,7 @@ func deleteAllCOSObjectVersions(conn *s3.S3, bucketName, key string, force, igno if lastErr != nil { if !ignoreObjectErrors { - return fmt.Errorf("error deleting at least one object version, last error: %s", lastErr) + return fmt.Errorf("[ERROR] Error deleting at least one object version, last error: %s", lastErr) } lastErr = nil @@ -594,7 +596,7 @@ func deleteAllCOSObjectVersions(conn *s3.S3, bucketName, key string, force, igno if lastErr != nil { if !ignoreObjectErrors { - return fmt.Errorf("error deleting at least one object delete marker, last error: %s", lastErr) + return fmt.Errorf("[ERROR] Error deleting at least one object delete marker, last error: %s", lastErr) } lastErr = nil diff --git a/ibm/resource_ibm_cos_bucket_object_test.go b/ibm/service/cos/resource_ibm_cos_bucket_object_test.go similarity index 95% rename from ibm/resource_ibm_cos_bucket_object_test.go rename to ibm/service/cos/resource_ibm_cos_bucket_object_test.go index b4d92d3ff..e31d301c3 100644 --- a/ibm/resource_ibm_cos_bucket_object_test.go +++ b/ibm/service/cos/resource_ibm_cos_bucket_object_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package cos_test import ( "encoding/base64" @@ -9,19 +9,21 @@ import ( "io/ioutil" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMCOSBucketObject_basic(t *testing.T) { name := fmt.Sprintf("tf-testacc-cos-%d", acctest.RandIntRange(10, 100)) - instanceCRN := cosCRN + instanceCRN := acc.CosCRN objectBody := "Acceptance Testing" - objectFile := "test-fixtures/cosObject.json" + objectFile := "../../test-fixtures/cosObject.json" objectFileBody, _ := ioutil.ReadFile(objectFile) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckCOS(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckCOS(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccIBMCOSBucketObjectConfig_plaintext(name, instanceCRN, objectBody), diff --git a/ibm/service/cos/resource_ibm_cos_bucket_test.go b/ibm/service/cos/resource_ibm_cos_bucket_test.go new file mode 100644 index 000000000..1248957b9 --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_bucket_test.go @@ -0,0 +1,2534 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package cos_test + +import ( + "errors" + "fmt" + "regexp" + "strings" + "testing" + + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cos" + + "github.com/IBM/ibm-cos-sdk-go/aws" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" + "github.com/IBM/ibm-cos-sdk-go/aws/session" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "gotest.tools/assert" +) + +var singleSiteLocation = []string{ + "ams03", "che01", "hkg02", "mel01", "mex01", + "mil01", "mon01", "osl01", "par01", "sjc04", "sao01", + "seo01", "sng01", "tor01", +} + +var regionLocation = []string{ + "au-syd", "ca-tor", "eu-de", "eu-gb", "jp-tok", "jp-osa", "us-east", "us-south", "br-sao", +} + +var crossRegionLocation = []string{ + "us", "eu", "ap", +} + +var storageClass = []string{ + "standard", "vault", "cold", "smart", "onerate_active", +} + +var singleSiteLocationRegex = regexp.MustCompile("^[a-z]{3}[0-9][0-9]-[a-z_a-z]{4,14}$") +var regionLocationRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{2,5}[0-9]?-[a-z_a-z]{4,14}$") +var crossRegionLocationRegex = regexp.MustCompile("^[a-z]{2}-[a-z_a-z]{4,14}$") + +func TestAccIBMCosBucket_Basic(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "eu" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + { + Config: testAccCheckIBMCosBucket_updateWithSameName(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_AllowedIP(t *testing.T) { + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + allowedIp1 := "103.208.71.79" + allowedIp2 := "172.30.8.121" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_allowedip(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, allowedIp1, allowedIp2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "allowed_ip.#", "2"), + ), + }, + { + Config: testAccCheckIBMCosBucket_allowedipremoved(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "allowed_ip.#", "0"), + ), + }, + }, + }) + +} + +func TestAccIBMCosBucket_Direct(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "eu" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_direct(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + }, + }) +} +func TestAccIBMCosBucket_ActivityTracker_Monitor(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + activityServiceName := fmt.Sprintf("activity_tracker_%d", acctest.RandIntRange(10, 100)) + monitorServiceName := fmt.Sprintf("metrics_monitor_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("tf-bucket%d", acctest.RandIntRange(10, 100)) + bucketRegion := "ams03" + bucketClass := "standard" + bucketRegionType := "single_site_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance2", "ibm_cos_bucket.bucket2", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "single_site_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "activity_tracking.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "metrics_monitoring.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance2", "ibm_cos_bucket.bucket2", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "single_site_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "activity_tracking.#", "0"), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket2", "metrics_monitoring.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Archive_Expiration(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("tf-bucket%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + arch_ruleId := "my-rule-id-bucket-arch" + arch_enable := true + archiveDays := 1 + ruleType := "GLACIER" + exp_ruleId := "my-rule-id-bucket-expire" + exp_enable := true + expireDays := 1 + prefix := "prefix/" + archDaysUpdate := 3 + expDaysUpdate := 2 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_archive_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archiveDays, ruleType, exp_ruleId, exp_enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_archive_expire_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archDaysUpdate, ruleType, exp_ruleId, exp_enable, expDaysUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.0.days", fmt.Sprintf("%d", archDaysUpdate)), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.days", fmt.Sprintf("%d", expDaysUpdate)), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_archive_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, arch_ruleId, arch_enable, archiveDays, ruleType, exp_ruleId, exp_enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "0"), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Archive(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-arch" + enable := true + archiveDays := 1 + ruleType := "GLACIER" + archiveDaysUpdate := 3 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_archive(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDays, ruleType), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_archive_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDaysUpdate, ruleType), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.0.days", fmt.Sprintf("%d", archiveDaysUpdate)), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_archive(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, archiveDays, ruleType), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "archive_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Expiredays(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-expiredays" + enable := true + expireDays := 2 + prefix := "prefix/" + expireDaysUpdate := 3 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_expiredays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_expire_updateDays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDaysUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.days", fmt.Sprintf("%d", expireDaysUpdate)), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_expiredays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Expiredate(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-expiredate" + enable := true + expireDate := "2021-11-28" + prefix := "" + expireDateUpdate := "2021-11-30" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_expiredate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_expire_updateDate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDateUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.date", expireDateUpdate), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_expiredate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Expireddeletemarker(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-expireddeletemarker" + enable := true + prefix := "" + expiredObjectDeleteMarker := false + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_expiredeletemarker(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expiredObjectDeleteMarker, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_AbortIncompeleteMPU(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-abortmpu" + enable := true + prefix := "" + daysAfterInitiation := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_abortincompletempu(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_abortincompletempu(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_noncurrentversion(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-ncversion" + enable := true + prefix := "" + noncurrentDays := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_noncurrentversion(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_noncurrentversion(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Retention(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "jp-tok" + bucketClass := "standard" + bucketRegionType := "region_location" + default_retention := 0 + maximum_retention := 1 + minimum_retention := 0 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_retention(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, default_retention, maximum_retention, minimum_retention), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "retention_rule.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Object_Versioning(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-east" + bucketClass := "standard" + bucketRegionType := "region_location" + enable := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_object_versioning(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, enable), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "object_versioning.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Hard_Quota(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + hardQuota := 1024 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_hard_quota(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, hardQuota), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "hard_quota", fmt.Sprintf("%d", hardQuota)), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Smart_Type(t *testing.T) { + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "eu" + bucketClass := "smart" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + { + Config: testAccCheckIBMCosBucket_updateWithSameName(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_import(t *testing.T) { + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "eu" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_basic(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "cross_region_location", bucketRegion), + ), + }, + { + ResourceName: "ibm_cos_bucket.bucket", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "parameters", "force_delete"}, + }, + }, + }) +} + +// Satellite location +func TestAccIBMCosBucket_Satellite(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_basic_sat(serviceName, bucketName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + ), + }, + { + Config: testAccCheckIBMCosBucket_sat_updateWithSameName(serviceName, bucketName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_Expiredays(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + ruleId := "my-rule-id-bucket-expiredays" + enable := true + expireDays := 2 + prefix := "prefix/" + expireDaysUpdate := 3 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_expiredays_satellite(bucketName, bucketRegion, ruleId, enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_expire_updateDays_satellite(bucketName, bucketRegion, ruleId, enable, expireDaysUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.days", fmt.Sprintf("%d", expireDaysUpdate)), + ), + }, + { + Config: testAccCheckIBMCosBucket_update_expiredays_satellite(bucketName, bucketRegion, ruleId, enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_Expiredate(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + ruleId := "my-rule-id-bucket-expiredate" + enable := true + expireDate := "2021-11-28" + prefix := "" + expireDateUpdate := "2021-11-30" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_sat_expiredate(bucketName, bucketRegion, ruleId, enable, expireDate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_sat_expire_updateDate(bucketName, bucketRegion, ruleId, enable, expireDateUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.date", expireDateUpdate), + ), + }, + { + Config: testAccCheckIBMCosBucket_sat_update_expiredate(bucketName, bucketRegion, ruleId, enable, expireDate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_Expireddeletemarker(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + ruleId := "my-rule-id-bucket-expireddeletemarker" + enable := true + prefix := "" + expiredObjectDeleteMarker := false + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_sat_expiredeletemarker(bucketName, bucketRegion, ruleId, enable, expiredObjectDeleteMarker, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_AbortIncompeleteMPU(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + ruleId := "my-rule-id-bucket-abortmpu" + enable := true + prefix := "" + daysAfterInitiation := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_sat_abortincompletempu(bucketName, bucketRegion, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_sat_update_abortincompletempu(bucketName, bucketRegion, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_noncurrentversion(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + ruleId := "my-rule-id-bucket-ncversion" + enable := true + prefix := "" + noncurrentDays := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_sat_noncurrentversion(bucketName, bucketRegion, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "1"), + ), + }, + { + Config: testAccCheckIBMCosBucket_sat_update_noncurrentversion(bucketName, bucketRegion, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Satellite_Object_Versioning(t *testing.T) { + + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := acc.Satellite_location_id + ResourceInstanceId := acc.Satellite_Resource_instance_id + enable := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_sat_object_versioning(bucketName, bucketRegion, enable), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucket_Satellite_Exists(ResourceInstanceId, "ibm_cos_bucket.bucket", bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "object_versioning.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_OneRate_With_Storageclass(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "onerate_active" + bucketRegionType := "region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_Onerate_With_Storageclass(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_OneRate_Without_Storage_class(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketRegionType := "region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_Onerate_Without_Storage_class(serviceName, bucketName, bucketRegionType, bucketRegion), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + ), + }, + }, + }) +} +func TestAccIBMCosBucket_OneRate_With_Invalid_Storageclass(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "invalidstorageclass" + bucketRegionType := "region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_Onerate_With_Invalid_Storageclass(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + ExpectError: regexp.MustCompile("\"storage_class\" must contain a value from \\[\\]string{\"standard\", \"vault\", \"cold\", \"smart\", \"flex\", \"onerate_active\"}, got \"invalidstorageclass\""), + }, + }, + }) +} + +func TestAccIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type1(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type1(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + ExpectError: regexp.MustCompile("InvalidLocationConstraint: Storage class not allowed for one rate user"), + }, + }, + }) +} +func TestAccIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type2(t *testing.T) { + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "onerate_active" + bucketRegionType := "region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type2(serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass), + ExpectError: regexp.MustCompile("InvalidLocationConstraint: Storage class not allowed for standard or cloud lite user"), + }, + }, + }) +} +func testAccCheckIBMCosBucketDestroy(s *terraform.State) error { + + var s3Conf *aws.Config + var apiEndpoint string + var resourceInstance string + for _, rs := range s.RootModule().Resources { + if rs.Type == "ibm_cos_bucket" { + apiEndpoint = rs.Primary.Attributes["s3_endpoint_public"] + } + if rs.Type == "ibm_resource_instance" && rs.Primary.Attributes["service"] == "cloud-object-storage" { + resourceInstance = rs.Primary.Attributes["crn"] + + } + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + authEndpoint, err := rsContClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsContClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, resourceInstance)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsContClient.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsContClient.Config.IAMAccessToken, + RefreshToken: rsContClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, resourceInstance)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + bucketList, _ := s3Client.ListBuckets(&s3.ListBucketsInput{}) + if len(bucketList.Buckets) > 0 { + return errors.New("Bucket still exists") + + } + return nil +} + +// COS Satellite +func testAccCheckIBMCosBucket_Satellite_Exists(resource string, bucket string, region string, bucketname string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + var s3Conf *aws.Config + + bucket, ok := s.RootModule().Resources[bucket] + if !ok { + return fmt.Errorf("Bucket Not found: %s", bucket) + } + + satloc_guid := strings.Split(resource, ":") + bucketsatcrn := satloc_guid[7] + resource = bucketsatcrn + + var rt string + + rt = "sl" + + apiEndpoint := cos.SelectSatlocCosApi(rt, resource, region) + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + authEndpoint, err := rsContClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsContClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, resource)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsContClient.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsContClient.Config.IAMAccessToken, + RefreshToken: rsContClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, resource)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + bucketList, _ := s3Client.ListBuckets(&s3.ListBucketsInput{}) + for _, bucket := range bucketList.Buckets { + bn := *bucket.Name + if bn == bucketname { + return nil + } + } + return errors.New("bucket does not exist") + } +} + +// / IBMCLOUD +func testAccCheckIBMCosBucketExists(resource string, bucket string, regiontype string, region string, bucketname string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + var s3Conf *aws.Config + resourceInstance, ok := s.RootModule().Resources[resource] + + if !ok { + return fmt.Errorf("Not found: %s", resource) + } + + bucket, ok := s.RootModule().Resources[bucket] + + if !ok { + return fmt.Errorf("Not found: %s", bucket) + } + + var rt string + if regiontype == "single_site_location" { + rt = "ssl" + } + if regiontype == "region_location" { + rt = "rl" + } + if regiontype == "cross_region_location" { + rt = "crl" + } + + apiEndpoint, _, _ := cos.SelectCosApi(rt, region) + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + authEndpoint, err := rsContClient.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := rsContClient.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, resourceInstance.Primary.ID)).WithS3ForcePathStyle(true) + } + iamAccessToken := rsContClient.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: rsContClient.Config.IAMAccessToken, + RefreshToken: rsContClient.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, resourceInstance.Primary.ID)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + s3Client := s3.New(s3Sess, s3Conf) + + bucketList, _ := s3Client.ListBuckets(&s3.ListBucketsInput{}) + for _, bucket := range bucketList.Buckets { + bn := *bucket.Name + if bn == bucketname { + return nil + } + } + return errors.New("bucket does not exist") + } +} +func TestAccIBMCOSKP(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKeyProtectRootkeyWithCOSBucket(instanceName, keyName, serviceName, bucketName, bucketRegion, bucketClass), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + ), + }, + }, + }) +} + +func TestAccIBMCOSHPCS(t *testing.T) { + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMHPCSRootkeyWithCOSBucket(keyName, serviceName, bucketName, bucketRegion, bucketClass), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "key_protect", acc.HpcsRootKeyCrn), + ), + }, + }, + }) +} + +func testAccCheckIBMCosBucket_basic(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + cross_region_location = "%s" + } + + + `, serviceName, bucketName, storageClass, region) +} + +func testAccCheckIBMCosBucket_Onerate_With_Storageclass(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + region_location = "%s" + } + + + `, serviceName, bucketName, storageClass, region) +} + +func testAccCheckIBMCosBucket_Onerate_Without_Storage_class(serviceName string, bucketName string, regiontype string, region string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + } + + `, serviceName, bucketName, region) +} + +func testAccCheckIBMCosBucket_Onerate_With_Invalid_Storageclass(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + region_location = "%s" + } + + `, serviceName, bucketName, storageClass, region) +} + +func testAccCheckIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type1(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + region_location = "%s" + } + + `, serviceName, bucketName, storageClass, region) +} +func testAccCheckIBMCosBucket_COS_Plan_Storageclass_Mismatch_Type2(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + region_location = "%s" + } + + `, serviceName, bucketName, storageClass, region) +} + +func testAccCheckIBMCosBucket_allowedip(serviceName string, bucketName string, regiontype string, region string, storageClass string, allowedIp1 string, allowedIp2 string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + cross_region_location = "%s" + allowed_ip = ["%s","%s"] + } + + `, serviceName, bucketName, storageClass, region, allowedIp1, allowedIp2) +} + +func testAccCheckIBMCosBucket_allowedipremoved(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + cross_region_location = "%s" + + } + + + `, serviceName, bucketName, storageClass, region) +} +func testAccCheckIBMCosBucket_direct(serviceName string, bucketName string, regiontype string, region string, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + cross_region_location = "%s" + endpoint_type= "direct" + } + + + `, serviceName, bucketName, storageClass, region) +} +func testAccCheckIBMCosBucket_updateWithSameName(serviceName string, bucketName string, regiontype string, region, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + storage_class = "%s" + cross_region_location = "%s" + } + `, serviceName, bucketName, storageClass, region) +} + +func testAccCheckIBMCosBucket_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, regiontype, region, storageClass string) string { + + return fmt.Sprintf(` + + data "ibm_resource_group" "cos_group" { + is_default=true + } + resource "ibm_resource_instance" "instance2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + resource "ibm_resource_instance" "activity_tracker2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "logdnaat" + plan = "7-day" + location = "us-south" + } + resource "ibm_resource_instance" "metrics_monitor2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "sysdig-monitor" + plan = "graduated-tier" + location = "us-south" + parameters = { + default_receiver = true + } + } + resource "ibm_cos_bucket" "bucket2" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance2.id + single_site_location = "%s" + storage_class = "%s" + activity_tracking { + read_data_events = true + write_data_events = true + activity_tracker_crn = ibm_resource_instance.activity_tracker2.id + } + metrics_monitoring { + usage_metrics_enabled = true + request_metrics_enabled = true + metrics_monitoring_crn = ibm_resource_instance.metrics_monitor2.id + } + } + `, cosServiceName, activityServiceName, monitorServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_update_activityTracker_monitor(cosServiceName, activityServiceName, monitorServiceName, bucketName, regiontype, region, storageClass string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_resource_instance" "activity_tracker2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "logdnaat" + plan = "7-day" + location = "us-south" + } + + resource "ibm_resource_instance" "metrics_monitor2" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "sysdig-monitor" + plan = "graduated-tier" + location = "us-south" + parameters = { + default_receiver = true + } + } + resource "ibm_cos_bucket" "bucket2" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance2.id + single_site_location = "%s" + storage_class = "%s" + } + `, cosServiceName, activityServiceName, monitorServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_archive(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDays int, ruleType string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + archive_rule { + rule_id = "%s" + enable = true + days = %d + type = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, archiveDays, ruleType) +} + +func testAccCheckIBMCosBucket_archive_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDaysUpdate int, ruleType string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + archive_rule { + rule_id = "%s" + enable = true + days = %d + type = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, archiveDaysUpdate, ruleType) +} + +func testAccCheckIBMCosBucket_update_archive(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, archiveDays int, ruleType string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_expiredays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDays, prefix) +} + +func testAccCheckIBMCosBucket_expire_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDaysUpdate int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDaysUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_expiredays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_expiredate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDate, prefix) +} + +func testAccCheckIBMCosBucket_expire_updateDate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDateUpdate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDateUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_expiredate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_expiredeletemarker(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expiredObjectDeleteMarker bool, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + expired_object_delete_marker = true + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, prefix) +} + +func testAccCheckIBMCosBucket_archive_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archiveDays int, ruleType string, exp_ruleId string, exp_enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + archive_rule { + rule_id = "%s" + enable = true + days = %d + type = "%s" + } + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, arch_ruleId, archiveDays, ruleType, exp_ruleId, expireDays, prefix) + +} +func testAccCheckIBMCosBucket_archive_expire_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archDaysUpdate int, ruleType string, exp_ruleId string, exp_enable bool, expDaysUpdate int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + archive_rule { + rule_id = "%s" + enable = true + days = %d + type = "%s" + } + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, arch_ruleId, archDaysUpdate, ruleType, exp_ruleId, expDaysUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_archive_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archiveDays int, ruleType string, exp_ruleId string, exp_enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_retention(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, default_retention int, maximum_retention int, minimum_retention int) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + name = "Default" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + retention_rule { + default = %d + maximum = %d + minimum = %d + permanent = false + } + } + `, cosServiceName, bucketName, region, storageClass, default_retention, maximum_retention, minimum_retention) +} + +func testAccCheckIBMCosBucket_object_versioning(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, enable bool) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + name = "Default" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + object_versioning { + enable = true + } + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_hard_quota(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, hardQuota int) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + name = "Default" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + hard_quota = %d + } + `, cosServiceName, bucketName, region, storageClass, hardQuota) +} + +func testAccCheckIBMCosBucket_abortincompletempu(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, daysAfterInitiation, prefix) +} + +func testAccCheckIBMCosBucket_abortincompletempu_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiationUpdate int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, daysAfterInitiationUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_abortincompletempu(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_noncurrentversion(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + noncurrent_version_expiration { + rule_id = "%s" + enable = true + noncurrent_days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, noncurrentDays, prefix) +} + +func testAccCheckIBMCosBucket_update_noncurrentversion(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +//Satellite + +func testAccCheckIBMCosBucket_basic_sat(serviceName string, bucketName string) string { + return fmt.Sprintf(` + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + + + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} +func testAccCheckIBMCosBucket_sat_updateWithSameName(serviceName string, bucketName string) string { + + return fmt.Sprintf(` + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMCosBucket_sat_expiredeletemarker(bucketName string, region string, ruleId string, enable bool, expiredObjectDeleteMarker bool, prefix string) string { + + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + expire_rule { + rule_id = "%s" + enable = true + expired_object_delete_marker = true + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, prefix) +} + +func testAccCheckIBMCosBucket_sat_abortincompletempu(bucketName string, region string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, daysAfterInitiation, prefix) +} + +func testAccCheckIBMCosBucket_sat_abortincompletempu_updateDays(bucketName string, region string, ruleId string, enable bool, daysAfterInitiationUpdate int, prefix string) string { + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, daysAfterInitiationUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_sat_update_abortincompletempu(bucketName string, region string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMCosBucket_sat_noncurrentversion(bucketName string, region string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + noncurrent_version_expiration { + rule_id = "%s" + enable = true + noncurrent_days = %d + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, noncurrentDays, prefix) +} + +func testAccCheckIBMCosBucket_sat_update_noncurrentversion(bucketName string, region string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMCosBucket_sat_expiredate(bucketName string, region string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, expireDate, prefix) +} + +func testAccCheckIBMCosBucket_sat_expire_updateDate(bucketName string, region string, ruleId string, enable bool, expireDateUpdate string, prefix string) string { + + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, expireDateUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_sat_update_expiredate(bucketName string, region string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMCosBucket_sat_object_versioning(bucketName string, region string, enable bool) string { + + return fmt.Sprintf(` + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + object_versioning { + enable = true + } + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMCosBucket_expiredays_satellite(bucketName string, region string, ruleId string, enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, expireDays, prefix) +} + +func testAccCheckIBMCosBucket_expire_updateDays_satellite(bucketName string, region string, ruleId string, enable bool, expireDaysUpdate int, prefix string) string { + + return fmt.Sprintf(` + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + expire_rule { + rule_id = "%s" + enable = true + days = %d + prefix = "%s" + } + } + + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id, ruleId, expireDaysUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_expiredays_satellite(bucketName string, region string, ruleId string, enable bool, expireDays int, prefix string) string { + + return fmt.Sprintf(` + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = "%s" + satellite_location_id = "%s" + } + `, bucketName, acc.Satellite_Resource_instance_id, acc.Satellite_location_id) +} + +func testAccCheckIBMKeyProtectRootkeyWithCOSBucket(instanceName, KeyName, serviceName, bucketName, bucketRegion, bucketClass string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + resource "ibm_resource_instance" "kms_instance1" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "ibm_iam_authorization_policy" "policy1" { + source_service_name = "cloud-object-storage" + target_service_name = "kms" + roles = ["Reader"] + } + resource "ibm_kms_key" "test" { + instance_id = "${ibm_resource_instance.kms_instance1.guid}" + key_name = "%s" + standard_key = false + force_delete = true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "bucket" { + depends_on = [ibm_iam_authorization_policy.policy1] + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + cross_region_location = "%s" + storage_class = "%s" + key_protect = ibm_kms_key.test.id + } +`, instanceName, KeyName, serviceName, bucketName, bucketRegion, bucketClass) +} + +func testAccCheckIBMHPCSRootkeyWithCOSBucket(KeyName, serviceName, bucketName, bucketRegion, bucketClass string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default=true + } + resource "ibm_iam_authorization_policy" "policy1" { + source_service_name = "cloud-object-storage" + target_service_name = "hs-crypto" + roles = ["Reader"] + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "bucket" { + depends_on = [ibm_iam_authorization_policy.policy1] + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + key_protect = "%s" + } +`, serviceName, bucketName, bucketRegion, bucketClass, acc.HpcsRootKeyCrn) +} + +func TestSingleSiteLocationRegex(t *testing.T) { + var re = singleSiteLocationRegex + for _, singleSite := range singleSiteLocation { + for _, sc := range storageClass { + assert.Equal(t, re.MatchString(singleSite+"-"+sc), true) + } + } + + for _, region := range regionLocation { + assert.Equal(t, re.MatchString(region+"-standard"), false) + } + + for _, crossRegion := range crossRegionLocation { + assert.Equal(t, re.MatchString(crossRegion+"-standard"), false) + } +} + +func TestRegionLocationRegex(t *testing.T) { + var re = regionLocationRegex + for _, singleSite := range singleSiteLocation { + assert.Equal(t, re.MatchString(singleSite+"-standard"), false) + } + + for _, region := range regionLocation { + for _, sc := range storageClass { + assert.Equal(t, re.MatchString(region+"-"+sc), true) + // test numeric suffix + assert.Equal(t, re.MatchString(region+"2-"+sc), true) + } + } + + for _, crossRegion := range crossRegionLocation { + assert.Equal(t, re.MatchString(crossRegion+"-standard"), false) + } +} + +func TestCrossRegionLocationRegex(t *testing.T) { + var re = crossRegionLocationRegex + for _, singleSite := range singleSiteLocation { + assert.Equal(t, re.MatchString(singleSite+"-standard"), false) + } + + for _, region := range regionLocation { + assert.Equal(t, re.MatchString(region+"-standard"), false) + } + + for _, crossRegion := range crossRegionLocation { + for _, sc := range storageClass { + assert.Equal(t, re.MatchString(crossRegion+"-"+sc), true) + } + } +} diff --git a/ibm/service/cos/resource_ibm_cos_replication_configuration.go b/ibm/service/cos/resource_ibm_cos_replication_configuration.go new file mode 100644 index 000000000..f3bce17dd --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_replication_configuration.go @@ -0,0 +1,396 @@ +package cos + +import ( + "bytes" + "fmt" + "strings" + "time" + + bxsession "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/ibm-cos-sdk-go/aws" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" + "github.com/IBM/ibm-cos-sdk-go/aws/session" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + validation "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceIBMCOSBucketReplicationConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMCOSBucketReplicationConfigurationCreate, + Read: resourceIBMCOSBucketReplicationConfigurationRead, + Update: resourceIBMCOSBucketReplicationConfigurationUpdate, + Delete: resourceIBMCOSBucketReplicationConfigurationDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "bucket_crn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "COS bucket CRN", + }, + "bucket_location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "COS bucket location", + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "direct"}), + Description: "COS endpoint type: public, private, direct", + Default: "public", + }, + "replication_rule": { + Type: schema.TypeSet, + Required: true, + MaxItems: 1000, + Description: "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringLenBetween(0, 255), + Description: "A unique identifier for the rule. The maximum value is 255 characters.", + }, + "priority": { + Type: schema.TypeInt, + Optional: true, + Description: "A priority is associated with each rule. There may be cases where multiple rules may be applicable to an object that is uploaded. ", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an replication rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "deletemarker_replication_status": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether to replicate delete markers. It should be either Enable or Disable", + }, + "destination_bucket_crn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateRegexps(`^crn:.+:.+:.+:.+:.+:a\/[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}:bucket:[a-z-A-Z]*[0-9]*$`), + Description: "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + }, + }, + }, + Set: resourceIBMCOSReplicationReuleHash, + }, + }, + } +} + +func replicationRuleSet(replicateList []interface{}) []*s3.ReplicationRule { + + var rules []*s3.ReplicationRule + for _, l := range replicateList { + bkt_replication_rule := s3.ReplicationRule{} + replicateMap, _ := l.(map[string]interface{}) + + //Rule ID + if rule_idSet, exist := replicateMap["rule_id"]; exist { + id := rule_idSet.(string) + bkt_replication_rule.ID = aws.String(id) + } + + //Status Enable/Disable + if statusSet, exist := replicateMap["enable"]; exist { + StatusEnabled := statusSet.(bool) + if StatusEnabled == true { + bkt_replication_rule.Status = aws.String("Enabled") + } else { + bkt_replication_rule.Status = aws.String("Disabled") + } + } + //Days + if priorSet, exist := replicateMap["priority"]; exist { + replicate_priority := int64(priorSet.(int)) + bkt_replication_rule.Priority = aws.Int64(replicate_priority) + } + //Replication Prefix + if PrefixClassSet, exist := replicateMap["prefix"]; exist { + prefix_check := PrefixClassSet.(string) + bkt_replication_rule.Filter = &s3.ReplicationRuleFilter{Prefix: aws.String(prefix_check)} + + } + //DeleteMarkerReplicationStatus + if delMarkerStatusSet, exist := replicateMap["deletemarker_replication_status"]; exist { + del_marker_status_value := delMarkerStatusSet.(bool) + if del_marker_status_value == true { + bkt_replication_rule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{Status: aws.String("Enabled")} + } else { + bkt_replication_rule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{Status: aws.String("Disabled")} + } + } + //Destination CRN + if dest_bucket_CrnSet, exist := replicateMap["destination_bucket_crn"]; exist { + dest_bucketcrn_value := dest_bucket_CrnSet.(string) + bkt_replication_rule.Destination = &s3.Destination{Bucket: aws.String(dest_bucketcrn_value)} + } + + rules = append(rules, &bkt_replication_rule) + + } + return rules +} + +func resourceIBMCOSBucketReplicationConfigurationCreate(d *schema.ResourceData, meta interface{}) error { + bucketCRN := d.Get("bucket_crn").(string) + bucketName := strings.Split(bucketCRN, ":bucket:")[1] + instanceCRN := fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + + bucketLocation := d.Get("bucket_location").(string) + endpointType := d.Get("endpoint_type").(string) + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + var rules []*s3.ReplicationRule + + replication, ok := d.GetOk("replication_rule") + if ok { + rules = append(rules, replicationRuleSet(replication.(*schema.Set).List())...) + + } + putBucketReplicationInput := &s3.PutBucketReplicationInput{ + Bucket: aws.String(bucketName), + ReplicationConfiguration: &s3.ReplicationConfiguration{ + Rules: rules, + }, + } + + _, err = s3Client.PutBucketReplication(putBucketReplicationInput) + + if err != nil { + return fmt.Errorf("failed to create the replication rule on COS bucket %s, %v", bucketName, err) + } + + //Generating a fake id which contains every information about to get the bucket via s3 api + bktID := fmt.Sprintf("%s:%s:%s:meta:%s:%s", strings.Replace(instanceCRN, "::", "", -1), "bucket", bucketName, bucketLocation, endpointType) + d.SetId(bktID) + + return resourceIBMCOSBucketReplicationConfigurationRead(d, meta) +} + +func resourceIBMCOSBucketReplicationConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + bucketCRN := d.Get("bucket_crn").(string) + bucketName := strings.Split(bucketCRN, ":bucket:")[1] + instanceCRN := fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + + bucketLocation := d.Get("bucket_location").(string) + endpointType := d.Get("endpoint_type").(string) + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + if d.HasChange("replication_rule") { + var rules []*s3.ReplicationRule + + replication, ok := d.GetOk("replication_rule") + if ok { + rules = append(rules, replicationRuleSet(replication.(*schema.Set).List())...) + + } + putBucketReplication := &s3.PutBucketReplicationInput{ + Bucket: aws.String(bucketName), + ReplicationConfiguration: &s3.ReplicationConfiguration{ + Rules: rules, + }, + } + + _, err = s3Client.PutBucketReplication(putBucketReplication) + + if err != nil { + return fmt.Errorf("failed to update the replication rule on COS bucket %s, %v", bucketName, err) + } + + } + return resourceIBMCOSBucketReplicationConfigurationRead(d, meta) +} + +func resourceIBMCOSBucketReplicationConfigurationRead(d *schema.ResourceData, meta interface{}) error { + + bucketCRN := parseBucketReplId(d.Id(), "bucketCRN") + bucketName := parseBucketReplId(d.Id(), "bucketName") + bucketLocation := parseBucketReplId(d.Id(), "bucketLocation") + instanceCRN := parseBucketReplId(d.Id(), "instanceCRN") + endpointType := parseBucketReplId(d.Id(), "endpointType") + + d.Set("bucket_crn", bucketCRN) + d.Set("bucket_location", bucketLocation) + if endpointType != "" { + d.Set("endpoint_type", endpointType) + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + getBucketReplicationInput := &s3.GetBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + replicationptr, err := s3Client.GetBucketReplication(getBucketReplicationInput) + + if err != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + + if replicationptr != nil { + replicationRules := flex.ReplicationRuleGet(replicationptr.ReplicationConfiguration) + if len(replicationRules) > 0 { + d.Set("replication_rule", replicationRules) + } + } + + return nil +} + +func resourceIBMCOSBucketReplicationConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + bucketName := parseBucketReplId(d.Id(), "bucketName") + bucketLocation := parseBucketReplId(d.Id(), "bucketLocation") + instanceCRN := parseBucketReplId(d.Id(), "instanceCRN") + endpointType := parseBucketReplId(d.Id(), "endpointType") + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + deleteBucketReplicationInput := &s3.DeleteBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + _, err = s3Client.DeleteBucketReplication(deleteBucketReplicationInput) + + if err != nil { + return err + } + return nil +} + +func parseBucketReplId(id string, info string) string { + bucketCRN := strings.Split(id, ":meta:")[0] + meta := strings.Split(id, ":meta:")[1] + + if info == "bucketName" { + return strings.Split(bucketCRN, ":bucket:")[1] + } + if info == "instanceCRN" { + return fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + } + if info == "bucketCRN" { + return bucketCRN + } + if info == "bucketLocation" { + return strings.Split(meta, ":")[0] + } + if info == "endpointType" { + return strings.Split(meta, ":")[1] + } + + return parseBucketId(bucketCRN, info) +} + +func getCosEndpointType(bucketLocation string, endpointType string) string { + if bucketLocation != "" { + switch endpointType { + case "public": + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + case "private": + return fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + case "direct": + return fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + default: + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + } + } + return "" +} + +func getS3ClientSession(bxSession *bxsession.Session, bucketLocation string, endpointType string, instanceCRN string) (*s3.S3, error) { + var s3Conf *aws.Config + + apiEndpoint := getCosEndpointType(bucketLocation, endpointType) + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + if apiEndpoint == "" { + return nil, fmt.Errorf("the endpoint doesn't exists for given location %s and endpoint type %s", bucketLocation, endpointType) + } + + authEndpoint, err := bxSession.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return nil, err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := bxSession.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, instanceCRN)).WithS3ForcePathStyle(true) + } + iamAccessToken := bxSession.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: bxSession.Config.IAMAccessToken, + RefreshToken: bxSession.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, instanceCRN)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + return s3.New(s3Sess, s3Conf), nil +} + +func resourceIBMCOSReplicationReuleHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", + m["destination_bucket_crn"].(string))) + + return conns.String(buf.String()) +} diff --git a/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go b/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go new file mode 100644 index 000000000..bc344293b --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go @@ -0,0 +1,163 @@ +package cos_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Replication features +func TestAccIBMCosBucket_Bucket_Replication(t *testing.T) { + + accountID := acc.IBM_AccountID_REPL + cosServiceNameSrc := fmt.Sprintf("cos_instance_src_%d", acctest.RandIntRange(10, 100)) + cosServiceNameDest := fmt.Sprintf("cos_instance_dest_%d", acctest.RandIntRange(10, 100)) + bucketNameSrc := fmt.Sprintf("terraform-testacc-src-%d", acctest.RandIntRange(10, 100)) + bucketNameDest := fmt.Sprintf("terraform-testacc-dest-%d", acctest.RandIntRange(10, 100)) + bucketRegionSrc := "us-south" + bucketRegionDest := "us-south" + bucketClassSrc := "standard" + bucketClassDest := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-replication" + enable := true + prefix := "" + priority := 1 + deletemarker_replication_status := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_replication(accountID, cosServiceNameSrc, cosServiceNameDest, bucketNameSrc, bucketNameDest, bucketRegionType, bucketRegionSrc, bucketRegionDest, bucketClassSrc, bucketClassDest, ruleId, enable, priority, deletemarker_replication_status, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "bucket_name", bucketNameSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "bucket_name", bucketNameDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "storage_class", bucketClassSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "storage_class", bucketClassDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "region_location", bucketRegionSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "region_location", bucketRegionDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "object_versioning.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "object_versioning.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket_replication_rule.cos_bucket_repl", "replication_rule.#", "1"), + ), + }, + }, + }) +} + +// create cos instance & buckets for source and destination and enable replication rule after iam authorization policy set on resource attributes.. +func testAccCheckIBMCosBucket_replication(accountID, cosServiceNameSrc string, cosServiceNameDest string, bucketNameSrc string, bucketNameDest string, regiontype string, regionSrc string, regionDest string, storageClassSrc string, storageClassDest string, ruleId string, enable bool, priority int, deletemarker_replication_status bool, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + resource "ibm_resource_instance" "cos_instance_source" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "%s" + storage_class = "%s" + object_versioning { + enable = true + } + } + resource "ibm_resource_instance" "cos_instance_destination" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "%s" + storage_class = "%s" + object_versioning { + enable = true + } + } + + resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "%s" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "%s" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } + } + resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "%s" + enable = true + prefix = "%s" + priority = 1 + deletemarker_replication_status = true + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } + } + + `, cosServiceNameSrc, bucketNameSrc, regionSrc, storageClassSrc, cosServiceNameDest, bucketNameDest, regionDest, storageClassDest, accountID, accountID, ruleId, prefix) +} diff --git a/ibm/service/database/README.md b/ibm/service/database/README.md new file mode 100644 index 000000000..0970b05e9 --- /dev/null +++ b/ibm/service/database/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Cloud Databases + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Cloud Databases resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database) +* IBM API Docs: [IBM API Docs for Cloud Databases](https://cloud.ibm.com/apidocs/cloud-databases-api/cloud-databases-api-v4) +* IBM Cloud Databases SDK: [IBM SDK for Cloud Databases](https://github.com/IBM-Cloud/bluemix-go/tree/master/api/icd/icdv4) diff --git a/ibm/service/database/data_source_ibm_database.go b/ibm/service/database/data_source_ibm_database.go new file mode 100644 index 000000000..42263b8f7 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database.go @@ -0,0 +1,823 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/url" + "path/filepath" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func DataSourceIBMDatabaseInstance() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMDatabaseInstanceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Resource instance name for example, my Database instance", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database", + "name"), + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the resource group in which the Database instance is present", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database", + "resource_group_id"), + }, + + "location": { + Description: "The location or the region in which the Database instance exists", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database", + "location"), + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier of resource instance", + }, + + "service": { + Description: "The name of the Cloud Database service", + Type: schema.TypeString, + Optional: true, + }, + "plan": { + Description: "The plan type of the Database instance", + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Description: "The resource instance status", + Type: schema.TypeString, + Computed: true, + }, + "adminuser": { + Description: "The admin user id for the instance", + Type: schema.TypeString, + Computed: true, + }, + "adminpassword": { + Description: "The admin user id for the instance", + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "version": { + Description: "The database version to provision if specified", + Type: schema.TypeString, + Computed: true, + }, + "members_memory_allocation_mb": { + Description: "Memory allocation required for cluster", + Type: schema.TypeInt, + Computed: true, + Deprecated: "This field is deprecated please use groups", + }, + "members_disk_allocation_mb": { + Description: "Disk allocation required for cluster", + Type: schema.TypeInt, + Computed: true, + Deprecated: "This field is deprecated please use groups", + }, + "platform_options": { + Description: "Platform-specific options for this deployment.r", + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_protect_key_id": { + Description: "Key protect key id", + Type: schema.TypeString, + Computed: true, + Deprecated: "This field is deprecated and has been replaced by disk_encryption_key_crn", + }, + "disk_encryption_key_crn": { + Description: "Disk encryption key crn", + Type: schema.TypeString, + Computed: true, + }, + "backup_encryption_key_crn": { + Description: "Backup encryption key crn", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "users": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Description: "User name", + Type: schema.TypeString, + Computed: true, + }, + "password": { + Description: "User password", + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + "cert_file_path": { + Description: "The absolute path to certificate PEM file", + Type: schema.TypeString, + Computed: true, + }, + "connectionstrings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Description: "User name", + Type: schema.TypeString, + Computed: true, + }, + "composed": { + Description: "Connection string", + Type: schema.TypeString, + Computed: true, + }, + "scheme": { + Description: "DB scheme", + Type: schema.TypeString, + Computed: true, + }, + "certname": { + Description: "Certificate Name", + Type: schema.TypeString, + Computed: true, + }, + "certbase64": { + Description: "Certificate in base64 encoding", + Type: schema.TypeString, + Computed: true, + }, + "bundlename": { + Description: "Cassandra Bundle Name", + Type: schema.TypeString, + Computed: true, + }, + "bundlebase64": { + Description: "Cassandra base64 encoding", + Type: schema.TypeString, + Computed: true, + }, + "password": { + Description: "Password", + Type: schema.TypeString, + Computed: true, + }, + "queryoptions": { + Description: "DB query options", + Type: schema.TypeString, + Computed: true, + }, + "database": { + Description: "DB name", + Type: schema.TypeString, + Computed: true, + }, + "path": { + Description: "DB path", + Type: schema.TypeString, + Computed: true, + }, + "hosts": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": { + Description: "DB host name", + Type: schema.TypeString, + Computed: true, + }, + "port": { + Description: "DB port", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + Deprecated: "This field is deprecated, please use ibm_database_connection instead", + }, + "whitelist": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Description: "Whitelist IP address in CIDR notation", + Type: schema.TypeString, + Computed: true, + }, + "description": { + Description: "Unique white list description", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Description: "Scaling group name", + Type: schema.TypeString, + Computed: true, + }, + "count": { + Description: "Count of scaling groups for the instance", + Type: schema.TypeInt, + Computed: true, + }, + "memory": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The units memory is allocated in.", + }, + "allocation_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The current memory allocation for a group instance", + }, + "minimum_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum memory size for a group instance", + }, + "step_size_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The step size memory increases or decreases in.", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the memory size adjustable.", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can memory scale down as well as up.", + }, + }, + }, + }, + "cpu": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The .", + }, + "allocation_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The current cpu allocation count", + }, + "minimum_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum number of cpus allowed", + }, + "step_size_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of CPUs allowed to step up or down by", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Are the number of CPUs adjustable", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can the number of CPUs be scaled down as well as up", + }, + }, + }, + }, + "disk": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The units disk is allocated in", + }, + "allocation_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The current disk allocation", + }, + "minimum_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum disk size allowed", + }, + "step_size_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The step size disk increases or decreases in", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the disk size adjustable", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can the disk size be scaled down as well as up", + }, + }, + }, + }, + }, + }, + }, + "auto_scaling": { + Type: schema.TypeList, + Description: "ICD Auto Scaling", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disk": { + Type: schema.TypeList, + Description: "Disk Auto Scaling", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity_enabled": { + Description: "Auto Scaling Scalar: Capacity Enabled", + Type: schema.TypeBool, + Computed: true, + }, + "free_space_remaining_percent": { + Description: "Auto Scaling Scalar: Capacity Free Space Remaining Percent", + Type: schema.TypeInt, + Computed: true, + }, + "free_space_less_than_percent": { + Description: "Auto Scaling Scalar: Capacity Free Space Less Than Percent", + Type: schema.TypeInt, + Computed: true, + }, + "io_enabled": { + Description: "Auto Scaling Scalar: IO Utilization Enabled", + Type: schema.TypeBool, + Computed: true, + }, + + "io_over_period": { + Description: "Auto Scaling Scalar: IO Utilization Over Period", + Type: schema.TypeString, + Computed: true, + }, + "io_above_percent": { + Description: "Auto Scaling Scalar: IO Utilization Above Percent", + Type: schema.TypeInt, + Computed: true, + }, + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_mb_per_member": { + Description: "Auto Scaling Rate: Limit mb per member", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_count_per_member": { + Description: "Auto Scaling Rate: Limit count per number", + Type: schema.TypeInt, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "memory": { + Type: schema.TypeList, + Description: "Memory Auto Scaling", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "io_enabled": { + Description: "Auto Scaling Scalar: IO Utilization Enabled", + Type: schema.TypeBool, + Computed: true, + }, + + "io_over_period": { + Description: "Auto Scaling Scalar: IO Utilization Over Period", + Type: schema.TypeString, + Computed: true, + }, + "io_above_percent": { + Description: "Auto Scaling Scalar: IO Utilization Above Percent", + Type: schema.TypeInt, + Computed: true, + }, + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_mb_per_member": { + Description: "Auto Scaling Rate: Limit mb per member", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_count_per_member": { + Description: "Auto Scaling Rate: Limit count per number", + Type: schema.TypeInt, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "cpu": { + Type: schema.TypeList, + Description: "CPU Auto Scaling", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_mb_per_member": { + Description: "Auto Scaling Rate: Limit mb per member", + Type: schema.TypeInt, + Computed: true, + }, + "rate_limit_count_per_member": { + Description: "Auto Scaling Rate: Limit count per number", + Type: schema.TypeInt, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "configuration_schema": { + Type: schema.TypeString, + Computed: true, + Description: "The configuration schema in JSON format", + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} + +func DataSourceIBMDatabaseInstanceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:name"}}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "region", + Optional: true}) + + iBMDatabaseInstanceValidator := validate.ResourceValidator{ResourceName: "ibm_database", Schema: validateSchema} + return &iBMDatabaseInstanceValidator +} + +func dataSourceIBMDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() + if err != nil { + return err + } + rsAPI := rsConClient.ResourceServiceInstanceV2() + name := d.Get("name").(string) + + rsInstQuery := controllerv2.ServiceInstanceQuery{ + Name: name, + } + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rsInstQuery.ResourceGroupID = rsGrpID.(string) + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInstQuery.ResourceGroupID = defaultRg + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + if service, ok := d.GetOk("service"); ok { + + serviceOff, err := rsCatRepo.FindByName(service.(string), true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving database offering: %s", err) + } + + rsInstQuery.ServiceID = serviceOff[0].ID + } + + var instances []models.ServiceInstanceV2 + + instances, err = rsAPI.ListInstances(rsInstQuery) + if err != nil { + return err + } + var filteredInstances []models.ServiceInstanceV2 + var location string + + if loc, ok := d.GetOk("location"); ok { + location = loc.(string) + for _, instance := range instances { + if flex.GetLocation(instance) == location { + filteredInstances = append(filteredInstances, instance) + } + } + } else { + filteredInstances = instances + } + + if len(filteredInstances) == 0 { + return fmt.Errorf("[ERROR] No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or database", name) + } + + var instance models.ServiceInstanceV2 + + if len(filteredInstances) > 1 { + return fmt.Errorf( + "More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or database", name) + } + instance = filteredInstances[0] + + d.SetId(instance.ID) + + err = flex.GetTags(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error on get of resource instance (%s) tags: %s", d.Id(), err) + } + + d.Set("name", instance.Name) + d.Set("status", instance.State) + d.Set("resource_group_id", instance.ResourceGroupID) + d.Set("location", instance.RegionID) + d.Set("guid", instance.Guid) + + serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + d.Set("service", serviceOff) + + servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.Crn.String()) + d.Set(flex.ResourceStatus, instance.State) + d.Set(flex.ResourceGroupName, instance.ResourceGroupName) + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/services/"+url.QueryEscape(instance.Crn.String())) + + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return fmt.Errorf("[ERROR] Error getting database client settings: %s", err) + } + + icdId := flex.EscapeUrlParm(instance.ID) + cdb, err := icdClient.Cdbs().GetCdb(icdId) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err) + } + return fmt.Errorf("[ERROR] Error getting database config for: %s with error %s\n", icdId, err) + } + d.Set("adminuser", cdb.AdminUser) + d.Set("version", cdb.Version) + if &cdb.PlatformOptions != nil { + d.Set("platform_options", flex.ExpandPlatformOptions(cdb.PlatformOptions)) + } + + groupList, err := icdClient.Groups().GetGroups(icdId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting database groups: %s", err) + } + d.Set("groups", flex.FlattenIcdGroups(groupList)) + d.Set("members_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb) + d.Set("members_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb) + + autoSclaingGroup, err := icdClient.AutoScaling().GetAutoScaling(icdId, "member") + if err != nil { + return fmt.Errorf("[ERROR] Error getting database groups: %s", err) + } + d.Set("auto_scaling", flattenICDAutoScalingGroup(autoSclaingGroup)) + + whitelist, err := icdClient.Whitelists().GetWhitelist(icdId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting database whitelist: %s", err) + } + d.Set("whitelist", flex.FlattenWhitelist(whitelist)) + + connectionEndpoint := "public" + if instance.Parameters != nil { + if endpoint, ok := instance.Parameters["service-endpoints"]; ok { + if endpoint == "private" { + connectionEndpoint = "private" + } + } + + } + + var connectionStrings []flex.CsEntry + //ICD does not implement a GetUsers API. Users populated from tf configuration. + tfusers := d.Get("users").(*schema.Set) + users := flex.ExpandUsers(tfusers) + user := icdv4.User{ + UserName: cdb.AdminUser, + } + users = append(users, user) + for _, user := range users { + userName := user.UserName + csEntry, err := getConnectionString(d, userName, connectionEndpoint, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error getting user connection string for user (%s): %s", userName, err) + } + connectionStrings = append(connectionStrings, csEntry) + } + d.Set("connectionstrings", flex.FlattenConnectionStrings(connectionStrings)) + + connStr := connectionStrings[0] + certFile, err := filepath.Abs(connStr.CertName + ".pem") + if err != nil { + return fmt.Errorf("[ERROR] Error generating certificate file path: %s", err) + } + content, err := base64.StdEncoding.DecodeString(connStr.CertBase64) + if err != nil { + return fmt.Errorf("[ERROR] Error decoding certificate content: %s", err) + } + if err := ioutil.WriteFile(certFile, content, 0644); err != nil { + return fmt.Errorf("[ERROR] Error writing certificate to file: %s", err) + } + d.Set("cert_file_path", certFile) + if serviceOff == "databases-for-postgresql" || serviceOff == "databases-for-redis" || serviceOff == "databases-for-enterprisedb" { + configSchema, err := icdClient.Configurations().GetConfiguration(icdId) + if err != nil { + return fmt.Errorf("[ERROR] Error getting database (%s) configuration schema : %s", icdId, err) + } + s, err := json.Marshal(configSchema) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling the database configuration schema: %s", err) + } + + if err = d.Set("configuration_schema", string(s)); err != nil { + return fmt.Errorf("[ERROR] Error setting the database configuration schema: %s", err) + } + } + + return nil +} diff --git a/ibm/service/database/data_source_ibm_database_backup.go b/ibm/service/database/data_source_ibm_database_backup.go new file mode 100644 index 000000000..17b63cea5 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_backup.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseBackup() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMDatabaseBackupRead, + + Schema: map[string]*schema.Schema{ + "backup_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Backup ID.", + }, + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the deployment this backup relates to.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of backup.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of this backup.", + }, + "is_downloadable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is this backup available to download?.", + }, + "is_restorable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Can this backup be used to restore an instance?.", + }, + "download_link": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI which is currently available for file downloading.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when this backup was created.", + }, + }, + } +} + +func DataSourceIBMDatabaseBackupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + getBackupInfoOptions := &clouddatabasesv5.GetBackupInfoOptions{} + + getBackupInfoOptions.SetBackupID(d.Get("backup_id").(string)) + + backup, response, err := cloudDatabasesClient.GetBackupInfoWithContext(context, getBackupInfoOptions) + if err != nil { + log.Printf("[DEBUG] GetBackupInfoWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetBackupInfoWithContext failed %s\n%s", err, response)) + } + + d.SetId(*backup.Backup.ID) + + if err = d.Set("backup_id", backup.Backup.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + } + + if err = d.Set("deployment_id", backup.Backup.DeploymentID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deployment_id: %s", err)) + } + + if err = d.Set("type", backup.Backup.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + if err = d.Set("status", backup.Backup.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + + if err = d.Set("is_downloadable", backup.Backup.IsDownloadable); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_downloadable: %s", err)) + } + + if err = d.Set("is_restorable", backup.Backup.IsRestorable); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_restorable: %s", err)) + } + + if err = d.Set("download_link", backup.Backup.DownloadLink); err != nil { + return diag.FromErr(fmt.Errorf("Error setting download_link: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(backup.Backup.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + return nil +} diff --git a/ibm/service/database/data_source_ibm_database_backup_test.go b/ibm/service/database/data_source_ibm_database_backup_test.go new file mode 100644 index 000000000..5ffa8de76 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_backup_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMDatabaseBackupDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMDatabaseBackupDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_backup.database_backup", "deployment_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_backup.database_backup", "backup_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_backup.database_backup", "is_downloadable"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseBackupDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_database_backup" "database_backup" { + backup_id = "%[1]s" + } + `, acc.IcdDbBackupId) +} diff --git a/ibm/service/database/data_source_ibm_database_backups.go b/ibm/service/database/data_source_ibm_database_backups.go new file mode 100644 index 000000000..a1dfa7f4d --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_backups.go @@ -0,0 +1,193 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseBackups() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMDatabaseBackupsRead, + + Schema: map[string]*schema.Schema{ + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "ID of the deployment this backup relates to.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_backups", + "deployment_id"), + }, + "backups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "An array of backups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backup_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of this backup.", + }, + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the deployment this backup relates to.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of backup.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of this backup.", + }, + "is_downloadable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is this backup available to download?.", + }, + "is_restorable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Can this backup be used to restore an instance?.", + }, + "download_link": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "URI which is currently available for file downloading.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when this backup was created.", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMDatabaseBackupsValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "deployment_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Optional: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMDatabaseBackupsValidator := validate.ResourceValidator{ResourceName: "ibm_database_backups", Schema: validateSchema} + return &iBMDatabaseBackupsValidator +} + +func DataSourceIBMDatabaseBackupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + listDeploymentBackupsOptions := &clouddatabasesv5.ListDeploymentBackupsOptions{} + listDeploymentBackupsOptions.SetID(d.Get("deployment_id").(string)) + + backups, response, err := cloudDatabasesClient.ListDeploymentBackupsWithContext(context, listDeploymentBackupsOptions) + if err != nil { + log.Printf("[DEBUG] ListDeploymentBackupsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListDeploymentBackupsWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchBackups []clouddatabasesv5.Backup + var deploymentID string + var suppliedFilter bool + + if v, ok := d.GetOk("deployment_id"); ok { + deploymentID = v.(string) + suppliedFilter = true + for _, data := range backups.Backups { + if *data.DeploymentID == deploymentID { + matchBackups = append(matchBackups, data) + } + } + } else { + matchBackups = backups.Backups + } + backups.Backups = matchBackups + + if suppliedFilter { + if len(backups.Backups) == 0 { + return diag.FromErr(fmt.Errorf("no Backups found with deploymentID %s", deploymentID)) + } + d.SetId(deploymentID) + } else { + d.SetId(DataSourceIBMDatabaseBackupsID(d)) + } + + backups2 := []map[string]interface{}{} + if backups.Backups != nil { + for _, modelItem := range backups.Backups { + modelMap, err := DataSourceIBMDatabaseBackupsBackupToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + backups2 = append(backups2, modelMap) + } + } + if err = d.Set("backups", backups2); err != nil { + return diag.FromErr(fmt.Errorf("Error setting backups %s", err)) + } + + return nil +} + +// DataSourceIBMDatabaseBackupsID returns a reasonable ID for the list. +func DataSourceIBMDatabaseBackupsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMDatabaseBackupsBackupToMap(model *clouddatabasesv5.Backup) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["backup_id"] = *model.ID + } + if model.DeploymentID != nil { + modelMap["deployment_id"] = *model.DeploymentID + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Status != nil { + modelMap["status"] = *model.Status + } + if model.IsDownloadable != nil { + modelMap["is_downloadable"] = *model.IsDownloadable + } + if model.IsRestorable != nil { + modelMap["is_restorable"] = *model.IsRestorable + } + if model.DownloadLink != nil { + modelMap["download_link"] = *model.DownloadLink + } + if model.CreatedAt != nil { + modelMap["created_at"] = model.CreatedAt.String() + } + return modelMap, nil +} diff --git a/ibm/service/database/data_source_ibm_database_backups_test.go b/ibm/service/database/data_source_ibm_database_backups_test.go new file mode 100644 index 000000000..e92bbbe8a --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_backups_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMDatabaseBackupsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMDatabaseBackupsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_backups.database_backups", "deployment_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseBackupsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_database_backups" "database_backups" { + deployment_id = "%[1]s" + } + `, acc.IcdDbDeploymentId) +} diff --git a/ibm/service/database/data_source_ibm_database_connection.go b/ibm/service/database/data_source_ibm_database_connection.go new file mode 100644 index 000000000..9ecf433de --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_connection.go @@ -0,0 +1,2235 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseConnection() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMDatabaseConnectionRead, + + Schema: map[string]*schema.Schema{ + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Deployment ID.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_connection", + "deployment_id"), + }, + "user_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "User type.", + }, + "user_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "User ID.", + }, + "endpoint_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Endpoint Type. The endpoint must be enabled on the deployment before its connection information can be fetched.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_connection", + "endpoint_type"), + }, + "postgres": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + "database": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the database to use in the URI connection.", + }, + }, + }, + }, + "cli": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "CLI Connection.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "environment": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "A map of environment variables for a CLI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "bin": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the executable the CLI should run.", + }, + "arguments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Sets of arguments to call the executable with. The outer array corresponds to a possible way to call the CLI; the inner array is the set of arguments to use with that call.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + }, + }, + }, + "rediss": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + "database": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Number of the database to use in the URI connection.", + }, + }, + }, + }, + "https": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "amqps": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "mqtts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "stomp_ssl": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "grpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "mongodb": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + "database": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the database to use in the URI connection.", + }, + "replica_set": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the replica set to use in the URI connection.", + }, + }, + }, + }, + "bi_connector": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "analytics": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "ops_manager": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + "mysql": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + "database": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the database to use in the URI connection.", + }, + }, + }, + }, + "secure": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "bundle": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "bundle_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate bundle.", + }, + }, + }, + }, + }, + }, + }, + "emp": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of connection being described.", + }, + "composed": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "scheme": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Scheme/protocol for URI connection.", + }, + "hosts": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Hostname for connection.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Port number for connection.", + }, + }, + }, + }, + "path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Path for URI connection.", + }, + "query_options": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Query options to add to the URI connection.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Authentication data for Connection String.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Authentication method for this credential.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Username part of credential.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Password part of credential.", + }, + }, + }, + }, + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name associated with the certificate.", + }, + "certificate_base64": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Base64 encoded version of the certificate.", + }, + }, + }, + }, + "ssl": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates ssl is required for the connection.", + }, + "browser_accessible": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates the address is accessible by browser.", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMDatabaseConnectionValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "deployment_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:id"}}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "endpoint_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "public, private, public-and-private"}) + + iBMDatabaseConnectionsValidator := validate.ResourceValidator{ResourceName: "ibm_database_connection", Schema: validateSchema} + return &iBMDatabaseConnectionsValidator +} + +func DataSourceIBMDatabaseConnectionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + getConnectionOptions := &clouddatabasesv5.GetConnectionOptions{} + + getConnectionOptions.SetID(d.Get("deployment_id").(string)) + getConnectionOptions.SetUserType(d.Get("user_type").(string)) + getConnectionOptions.SetUserID(d.Get("user_id").(string)) + getConnectionOptions.SetEndpointType(d.Get("endpoint_type").(string)) + + connection, response, err := cloudDatabasesClient.GetConnectionWithContext(context, getConnectionOptions) + if err != nil { + log.Printf("[DEBUG] GetConnectionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetConnectionWithContext failed %s\n%s", err, response)) + } + + d.SetId(DataSourceIBMDatabaseConnectionID(d)) + conn := connection.Connection.(*clouddatabasesv5.Connection) + + postgres := []map[string]interface{}{} + if conn.Postgres != nil { + modelMap, err := DataSourceIBMDatabaseConnectionPostgreSQLConnectionURIToMap(conn.Postgres) + if err != nil { + return diag.FromErr(err) + } + postgres = append(postgres, modelMap) + } + if err = d.Set("postgres", postgres); err != nil { + return diag.FromErr(fmt.Errorf("Error setting postgres %s", err)) + } + + cli := []map[string]interface{}{} + if conn.Cli != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionCliToMap(conn.Cli) + if err != nil { + return diag.FromErr(err) + } + cli = append(cli, modelMap) + } + if err = d.Set("cli", cli); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cli %s", err)) + } + + rediss := []map[string]interface{}{} + if conn.Rediss != nil { + modelMap, err := DataSourceIBMDatabaseConnectionRedisConnectionURIToMap(conn.Rediss) + if err != nil { + return diag.FromErr(err) + } + rediss = append(rediss, modelMap) + } + if err = d.Set("rediss", rediss); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rediss %s", err)) + } + + https := []map[string]interface{}{} + if conn.HTTPS != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.HTTPS) + if err != nil { + return diag.FromErr(err) + } + https = append(https, modelMap) + } + if err = d.Set("https", https); err != nil { + return diag.FromErr(fmt.Errorf("Error setting https %s", err)) + } + + amqps := []map[string]interface{}{} + if conn.Amqps != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.Amqps) + if err != nil { + return diag.FromErr(err) + } + amqps = append(amqps, modelMap) + } + if err = d.Set("amqps", amqps); err != nil { + return diag.FromErr(fmt.Errorf("Error setting amqps %s", err)) + } + + mqtts := []map[string]interface{}{} + if conn.Mqtts != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.Mqtts) + if err != nil { + return diag.FromErr(err) + } + mqtts = append(mqtts, modelMap) + } + if err = d.Set("mqtts", mqtts); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mqtts %s", err)) + } + + stompSsl := []map[string]interface{}{} + if conn.StompSsl != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.StompSsl) + if err != nil { + return diag.FromErr(err) + } + stompSsl = append(stompSsl, modelMap) + } + if err = d.Set("stomp_ssl", stompSsl); err != nil { + return diag.FromErr(fmt.Errorf("Error setting stomp_ssl %s", err)) + } + + grpc := []map[string]interface{}{} + if conn.Grpc != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.Grpc) + if err != nil { + return diag.FromErr(err) + } + grpc = append(grpc, modelMap) + } + if err = d.Set("grpc", grpc); err != nil { + return diag.FromErr(fmt.Errorf("Error setting grpc %s", err)) + } + + mongodb := []map[string]interface{}{} + if conn.Mongodb != nil { + modelMap, err := DataSourceIBMDatabaseConnectionMongoDbConnectionURIToMap(conn.Mongodb) + if err != nil { + return diag.FromErr(err) + } + mongodb = append(mongodb, modelMap) + } + if err = d.Set("mongodb", mongodb); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mongodb %s", err)) + } + + biConnector := []map[string]interface{}{} + if conn.BiConnector != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.BiConnector) + if err != nil { + return diag.FromErr(err) + } + biConnector = append(biConnector, modelMap) + } + if err = d.Set("bi_connector", biConnector); err != nil { + return diag.FromErr(fmt.Errorf("Error setting bi_connector %s", err)) + } + + analytics := []map[string]interface{}{} + if conn.Analytics != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.Analytics) + if err != nil { + return diag.FromErr(err) + } + analytics = append(analytics, modelMap) + } + if err = d.Set("analytics", analytics); err != nil { + return diag.FromErr(fmt.Errorf("Error setting analytics %s", err)) + } + + opsManager := []map[string]interface{}{} + if conn.OpsManager != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.OpsManager) + if err != nil { + return diag.FromErr(err) + } + opsManager = append(opsManager, modelMap) + } + if err = d.Set("ops_manager", opsManager); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ops_manager %s", err)) + } + + mysql := []map[string]interface{}{} + if conn.Mysql != nil { + modelMap, err := DataSourceIBMDatabaseConnectionMySQLConnectionURIToMap(conn.Mysql) + if err != nil { + return diag.FromErr(err) + } + mysql = append(mysql, modelMap) + } + if err = d.Set("mysql", mysql); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mysql %s", err)) + } + + secure := []map[string]interface{}{} + if conn.Secure != nil { + modelMap, err := DataSourceIBMDatabaseConnectionDataStaxConnectionURIToMap(conn.Secure) + if err != nil { + return diag.FromErr(err) + } + secure = append(secure, modelMap) + } + if err = d.Set("secure", secure); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secure %s", err)) + } + + emp := []map[string]interface{}{} + if conn.Emp != nil { + modelMap, err := DataSourceIBMDatabaseConnectionConnectionURIToMap(conn.Emp) + if err != nil { + return diag.FromErr(err) + } + emp = append(emp, modelMap) + } + if err = d.Set("emp", emp); err != nil { + return diag.FromErr(fmt.Errorf("Error setting emp %s", err)) + } + + return nil +} + +// DataSourceIBMDatabaseConnectionID returns a reasonable ID for the list. +func DataSourceIBMDatabaseConnectionID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMDatabaseConnectionPostgreSQLConnectionURIToMap(model *clouddatabasesv5.PostgreSQLConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Scheme != nil { + modelMap["scheme"] = *model.Scheme + } + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.QueryOptions != nil { + queryOptionsMap := make(map[string]interface{}, len(model.QueryOptions)) + for _, _ = range model.QueryOptions { + } + modelMap["query_options"] = flex.Flatten(queryOptionsMap) + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + if model.Ssl != nil { + modelMap["ssl"] = *model.Ssl + } + if model.BrowserAccessible != nil { + modelMap["browser_accessible"] = *model.BrowserAccessible + } + if model.Database != nil { + modelMap["database"] = *model.Database + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionHostToMap(model *clouddatabasesv5.ConnectionHost) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Hostname != nil { + modelMap["hostname"] = *model.Hostname + } + if model.Port != nil { + modelMap["port"] = *model.Port + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model *clouddatabasesv5.ConnectionAuthentication) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Method != nil { + modelMap["method"] = *model.Method + } + if model.Username != nil { + modelMap["username"] = *model.Username + } + if model.Password != nil { + modelMap["password"] = *model.Password + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model *clouddatabasesv5.ConnectionCertificate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.CertificateBase64 != nil { + modelMap["certificate_base64"] = *model.CertificateBase64 + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionCliToMap(model *clouddatabasesv5.ConnectionCli) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Environment != nil { + environmentMap := make(map[string]interface{}, len(model.Environment)) + for _, _ = range model.Environment { + } + modelMap["environment"] = flex.Flatten(environmentMap) + } + if model.Bin != nil { + modelMap["bin"] = *model.Bin + } + if model.Arguments != nil { + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionRedisConnectionURIToMap(model *clouddatabasesv5.RedisConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Scheme != nil { + modelMap["scheme"] = *model.Scheme + } + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.QueryOptions != nil { + queryOptionsMap := make(map[string]interface{}, len(model.QueryOptions)) + for _, _ = range model.QueryOptions { + } + modelMap["query_options"] = flex.Flatten(queryOptionsMap) + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + if model.Ssl != nil { + modelMap["ssl"] = *model.Ssl + } + if model.BrowserAccessible != nil { + modelMap["browser_accessible"] = *model.BrowserAccessible + } + if model.Database != nil { + modelMap["database"] = *model.Database + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionURIToMap(model *clouddatabasesv5.ConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Scheme != nil { + modelMap["scheme"] = *model.Scheme + } + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.QueryOptions != nil { + queryOptionsMap := make(map[string]interface{}, len(model.QueryOptions)) + for _, _ = range model.QueryOptions { + } + modelMap["query_options"] = flex.Flatten(queryOptionsMap) + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + if model.Ssl != nil { + modelMap["ssl"] = *model.Ssl + } + if model.BrowserAccessible != nil { + modelMap["browser_accessible"] = *model.BrowserAccessible + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionMongoDbConnectionURIToMap(model *clouddatabasesv5.MongoDbConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Scheme != nil { + modelMap["scheme"] = *model.Scheme + } + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.QueryOptions != nil { + queryOptionsMap := make(map[string]interface{}, len(model.QueryOptions)) + for _, _ = range model.QueryOptions { + } + modelMap["query_options"] = flex.Flatten(queryOptionsMap) + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + if model.Ssl != nil { + modelMap["ssl"] = *model.Ssl + } + if model.BrowserAccessible != nil { + modelMap["browser_accessible"] = *model.BrowserAccessible + } + if model.Database != nil { + modelMap["database"] = *model.Database + } + if model.ReplicaSet != nil { + modelMap["replica_set"] = *model.ReplicaSet + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionMySQLConnectionURIToMap(model *clouddatabasesv5.MySQLConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Composed != nil { + modelMap["composed"] = model.Composed + } + if model.Scheme != nil { + modelMap["scheme"] = *model.Scheme + } + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Path != nil { + modelMap["path"] = *model.Path + } + if model.QueryOptions != nil { + queryOptionsMap := make(map[string]interface{}, len(model.QueryOptions)) + for _, _ = range model.QueryOptions { + } + modelMap["query_options"] = flex.Flatten(queryOptionsMap) + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Certificate != nil { + certificateMap, err := DataSourceIBMDatabaseConnectionConnectionCertificateToMap(model.Certificate) + if err != nil { + return modelMap, err + } + modelMap["certificate"] = []map[string]interface{}{certificateMap} + } + if model.Ssl != nil { + modelMap["ssl"] = *model.Ssl + } + if model.BrowserAccessible != nil { + modelMap["browser_accessible"] = *model.BrowserAccessible + } + if model.Database != nil { + modelMap["database"] = *model.Database + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionDataStaxConnectionURIToMap(model *clouddatabasesv5.DataStaxConnectionURI) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Hosts != nil { + hosts := []map[string]interface{}{} + for _, hostsItem := range model.Hosts { + hostsItemMap, err := DataSourceIBMDatabaseConnectionConnectionHostToMap(&hostsItem) + if err != nil { + return modelMap, err + } + hosts = append(hosts, hostsItemMap) + } + modelMap["hosts"] = hosts + } + if model.Authentication != nil { + authenticationMap, err := DataSourceIBMDatabaseConnectionConnectionAuthenticationToMap(model.Authentication) + if err != nil { + return modelMap, err + } + modelMap["authentication"] = []map[string]interface{}{authenticationMap} + } + if model.Bundle != nil { + bundleMap, err := DataSourceIBMDatabaseConnectionConnectionBundleToMap(model.Bundle) + if err != nil { + return modelMap, err + } + modelMap["bundle"] = []map[string]interface{}{bundleMap} + } + return modelMap, nil +} + +func DataSourceIBMDatabaseConnectionConnectionBundleToMap(model *clouddatabasesv5.ConnectionBundle) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.BundleBase64 != nil { + modelMap["bundle_base64"] = *model.BundleBase64 + } + return modelMap, nil +} diff --git a/ibm/service/database/data_source_ibm_database_connection_test.go b/ibm/service/database/data_source_ibm_database_connection_test.go new file mode 100644 index 000000000..9130574e4 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_connection_test.go @@ -0,0 +1,68 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMDatabaseConnectionDataSourceBasic(t *testing.T) { + testName := fmt.Sprintf("tf-Pgress-%s", acctest.RandString(16)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresql(testName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_connection.database_connection", "deployment_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_connection.database_connection", "user_type"), + resource.TestCheckResourceAttrSet("data.ibm_database_connection.database_connection", "user_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_connection.database_connection", "endpoint_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseDataSourceConfig2(name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + } + + data "ibm_database" "%[1]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = ibm_database.db.name + } + + resource "ibm_database" "db" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[1]s" + service = "databases-for-postgresql" + plan = "standard" + location = "au-syd" + tags = ["one:two"] + } + + `, name) +} + +func testAccCheckIBMDatabaseInstancePostgresql(name string) string { + return testAccCheckIBMDatabaseDataSourceConfig2(name) + ` + data "ibm_database_connection" "database_connection" { + deployment_id = ibm_database.db.id + user_type = "database" + user_id = "user_id" + endpoint_type = "public" + } + ` +} diff --git a/ibm/service/database/data_source_ibm_database_point_in_time_recovery.go b/ibm/service/database/data_source_ibm_database_point_in_time_recovery.go new file mode 100644 index 000000000..85c49a9ac --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_point_in_time_recovery.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabasePointInTimeRecovery() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMDatabasePointInTimeRecoveryRead, + + Schema: map[string]*schema.Schema{ + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Deployment ID.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_point_in_time_recovery", + "deployment_id"), + }, + "earliest_point_in_time_recovery_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func DataSourceIBMDatabasePointInTimeRecoveryValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "deployment_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMDatabasePointInTimeRecoveryValidator := validate.ResourceValidator{ResourceName: "ibm_database_point_in_time_recovery", Schema: validateSchema} + return &iBMDatabasePointInTimeRecoveryValidator +} + +func DataSourceIBMDatabasePointInTimeRecoveryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + getPitrDataOptions := &clouddatabasesv5.GetPitrDataOptions{} + + getPitrDataOptions.SetID(d.Get("deployment_id").(string)) + + pointInTimeRecoveryData, response, err := cloudDatabasesClient.GetPitrDataWithContext(context, getPitrDataOptions) + if err != nil { + log.Printf("[DEBUG] GetPitrDataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetPitrDataWithContext failed %s\n%s", err, response)) + } + + d.SetId(d.Get("deployment_id").(string)) + + if pointInTimeRecoveryData.PointInTimeRecoveryData.EarliestPointInTimeRecoveryTime != nil { + pitr := pointInTimeRecoveryData.PointInTimeRecoveryData.EarliestPointInTimeRecoveryTime + if err = d.Set("earliest_point_in_time_recovery_time", pitr); err != nil { + return diag.FromErr(fmt.Errorf("Error setting earliest_point_in_time_recovery_time: %s", err)) + } + } + + return nil +} diff --git a/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go b/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go new file mode 100644 index 000000000..43f0cd691 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDatabasePointInTimeRecoveryDataSourceBasic(t *testing.T) { + testName := fmt.Sprintf("tf-Pgress-%s", acctest.RandString(16)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMDatabasePitrDataSourceConfigBasic(testName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_point_in_time_recovery.database_pitr", "deployment_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseDataSourceConfig3(name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + } + + data "ibm_database" "%[1]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = ibm_database.db.name + } + + resource "ibm_database" "db" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[1]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[2]s" + tags = ["one:two"] + } + + `, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabasePitrDataSourceConfigBasic(name string) string { + return testAccCheckIBMDatabaseDataSourceConfig3(name) + ` + data "ibm_database_point_in_time_recovery" "database_pitr" { + deployment_id = ibm_database.db.id + } + ` +} diff --git a/ibm/service/database/data_source_ibm_database_remotes.go b/ibm/service/database/data_source_ibm_database_remotes.go new file mode 100644 index 000000000..081fc80f9 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_remotes.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseRemotes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMDatabaseRemotesRead, + + Schema: map[string]*schema.Schema{ + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Deployment ID.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_remotes", + "deployment_id"), + }, + "leader": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Leader ID, if applicable.", + }, + "replicas": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Replica IDs, if applicable.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} +func DataSourceIBMDatabaseRemotesValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "deployment_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMDatabaseRemotesValidator := validate.ResourceValidator{ResourceName: "ibm_database_remotes", Schema: validateSchema} + return &iBMDatabaseRemotesValidator +} + +func dataSourceIBMDatabaseRemotesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + listRemotesOptions := &clouddatabasesv5.ListRemotesOptions{} + + listRemotesOptions.SetID(d.Get("deployment_id").(string)) + + remotes, response, err := cloudDatabasesClient.ListRemotesWithContext(context, listRemotesOptions) + if err != nil { + log.Printf("[DEBUG] ListRemotesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListRemotesWithContext failed %s\n%s", err, response)) + } + + d.SetId(d.Get("deployment_id").(string)) + + if remotes.Remotes.Leader != nil { + if err = d.Set("leader", remotes.Remotes.Leader); err != nil { + return diag.FromErr(fmt.Errorf("Error setting leader: %s", err)) + } + } + + if remotes.Remotes.Replicas != nil { + if err = d.Set("replicas", remotes.Remotes.Replicas); err != nil { + return diag.FromErr(fmt.Errorf("Error setting replicas: %s", err)) + } + } + + return nil +} diff --git a/ibm/service/database/data_source_ibm_database_remotes_test.go b/ibm/service/database/data_source_ibm_database_remotes_test.go new file mode 100644 index 000000000..7b8cd000b --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_remotes_test.go @@ -0,0 +1,91 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDatabaseRemotesDataSourceBasic(t *testing.T) { + + testName := fmt.Sprintf("tf-Pgress-%s", acctest.RandString(16)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseRemotesDataSourceConfigBasic(testName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_remotes.database_remotes", "deployment_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_remotes.database_remotes_replica", "deployment_id"), + resource.TestCheckResourceAttr("data.ibm_database_remotes.database_remotes", "leader", ""), + resource.TestCheckResourceAttrSet("data.ibm_database_remotes.database_remotes_replica", "leader"), + resource.TestCheckResourceAttrSet("data.ibm_database_remotes.database_remotes", "replicas.#"), + ), + }, + }, + }, + ) +} + +func testAccCheckIBMDatabaseDataSourceConfig4(name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + } + data "ibm_database" "%[1]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = ibm_database.db.name + } + resource "ibm_database" "db" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[1]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[2]s" + tags = ["one:two"] + } + + resource "ibm_database" "db_replica" { + resource_group_id = data.ibm_resource_group.test_acc.id + remote_leader_id = ibm_database.db.id + name = "%[1]s-replica" + service = "databases-for-postgresql" + plan = "standard" + location = "%[2]s" + tags = ["one:two"] + + depends_on = [ + ibm_database.db, + ] + } + + `, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseRemotesDataSourceConfigBasic(name string) string { + return testAccCheckIBMDatabaseDataSourceConfig4(name) + ` + data "ibm_database_remotes" "database_remotes_replica" { + deployment_id = ibm_database.db_replica.id + + depends_on = [ + ibm_database.db_replica, + ] + } + + data "ibm_database_remotes" "database_remotes" { + deployment_id = ibm_database.db.id + + depends_on = [ + ibm_database.db_replica, + ] + } + ` +} diff --git a/ibm/service/database/data_source_ibm_database_task.go b/ibm/service/database/data_source_ibm_database_task.go new file mode 100644 index 000000000..9cce2ed47 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_task.go @@ -0,0 +1,110 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseTask() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMDatabaseTaskRead, + + Schema: map[string]*schema.Schema{ + "task_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Task ID.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Human-readable description of the task.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the task.", + }, + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the deployment the task is being performed on.", + }, + "progress_percent": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Indicator as percentage of progress of the task.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the task was created.", + }, + }, + } +} + +func dataSourceIBMDatabaseTaskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + getTaskOptions := &clouddatabasesv5.GetTaskOptions{} + + getTaskOptions.SetID(d.Get("task_id").(string)) + + task, response, err := cloudDatabasesClient.GetTaskWithContext(context, getTaskOptions) + + if err != nil { + return diag.FromErr(fmt.Errorf("GetTaskWithContext failed %s\n%s", err, response)) + } + + d.SetId(*task.Task.ID) + + if err = d.Set("task_id", task.Task.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + } + + if task.Task.Description != nil { + if err = d.Set("description", task.Task.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + } + + if task.Task.Status != nil { + if err = d.Set("status", task.Task.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + } + + if task.Task.DeploymentID != nil { + if err = d.Set("deployment_id", task.Task.DeploymentID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting deployment_id: %s", err)) + } + } + + if task.Task.ProgressPercent != nil { + if err = d.Set("progress_percent", task.Task.ProgressPercent); err != nil { + return diag.FromErr(fmt.Errorf("Error setting progress_percent: %s", err)) + } + } + + if task.Task.CreatedAt != nil { + if err = d.Set("created_at", flex.DateTimeToString(task.Task.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + } + + return nil +} diff --git a/ibm/service/database/data_source_ibm_database_task_test.go b/ibm/service/database/data_source_ibm_database_task_test.go new file mode 100644 index 000000000..cf83a99e4 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_task_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDatabaseTaskDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMDatabaseTaskDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "task_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "description"), + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "status"), + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "deployment_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "progress_percent"), + resource.TestCheckResourceAttrSet("data.ibm_database_task.database_task", "created_at"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseTaskDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_database_task" "database_task" { + task_id = "%[1]s" + } + `, acc.IcdDbTaskId) +} diff --git a/ibm/service/database/data_source_ibm_database_tasks.go b/ibm/service/database/data_source_ibm_database_tasks.go new file mode 100644 index 000000000..9847f91ca --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_tasks.go @@ -0,0 +1,176 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" +) + +func DataSourceIBMDatabaseTasks() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMDatabaseTasksRead, + + Schema: map[string]*schema.Schema{ + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Deployment ID.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_database_tasks", + "deployment_id"), + }, + "tasks": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "task_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the task.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Human-readable description of the task.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the task.", + }, + "deployment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the deployment the task is being performed on.", + }, + "progress_percent": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Indicator as percentage of progress of the task.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the task was created.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMDatabaseTasksValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "deployment_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cloud-database", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMDatabaseTasksValidator := validate.ResourceValidator{ResourceName: "ibm_database_tasks", Schema: validateSchema} + return &iBMDatabaseTasksValidator +} + +func dataSourceIBMDatabaseTasksRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + listDeploymentTasksOptions := &clouddatabasesv5.ListDeploymentTasksOptions{} + + listDeploymentTasksOptions.SetID(d.Get("deployment_id").(string)) + + tasks, response, err := cloudDatabasesClient.ListDeploymentTasksWithContext(context, listDeploymentTasksOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("ListDeploymentTasksWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchTasks []clouddatabasesv5.Task + var deploymentID string + var suppliedFilter bool + + if v, ok := d.GetOk("deployment_id"); ok { + deploymentID = v.(string) + suppliedFilter = true + for _, data := range tasks.Tasks { + if *data.DeploymentID == deploymentID { + matchTasks = append(matchTasks, data) + } + } + } else { + matchTasks = tasks.Tasks + } + tasks.Tasks = matchTasks + + if suppliedFilter { + if len(tasks.Tasks) == 0 { + return diag.FromErr(fmt.Errorf("no Tasks found with deploymentID %s", deploymentID)) + } + d.SetId(deploymentID) + } else { + d.SetId(DataSourceIBMDatabaseTasksID(d)) + } + + tasks2 := []map[string]interface{}{} + if tasks.Tasks != nil { + for _, modelItem := range tasks.Tasks { + modelMap, err := DataSourceIBMDatabaseTasksTaskToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + tasks2 = append(tasks2, modelMap) + } + } + if err = d.Set("tasks", tasks2); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tasks %s", err)) + } + + return nil +} + +// DataSourceIBMDatabaseTasksID returns a reasonable ID for the list. +func DataSourceIBMDatabaseTasksID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMDatabaseTasksTaskToMap(model *clouddatabasesv5.Task) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["task_id"] = *model.ID + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.Status != nil { + modelMap["status"] = *model.Status + } + if model.DeploymentID != nil { + modelMap["deployment_id"] = *model.DeploymentID + } + if model.ProgressPercent != nil { + modelMap["progress_percent"] = *model.ProgressPercent + } + if model.CreatedAt != nil { + modelMap["created_at"] = model.CreatedAt.String() + } + return modelMap, nil +} diff --git a/ibm/service/database/data_source_ibm_database_tasks_test.go b/ibm/service/database/data_source_ibm_database_tasks_test.go new file mode 100644 index 000000000..96419a152 --- /dev/null +++ b/ibm/service/database/data_source_ibm_database_tasks_test.go @@ -0,0 +1,39 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDatabaseTasksDataSourceBasic(t *testing.T) { + testName := fmt.Sprintf("tf-Pgress-%s", acctest.RandString(16)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMDatabaseTasksDataSourceConfigBasic(testName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_database_tasks.database_tasks", "deployment_id"), + resource.TestCheckResourceAttrSet("data.ibm_database_tasks.database_tasks", "tasks.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseTasksDataSourceConfigBasic(name string) string { + return fmt.Sprintf(` + data "ibm_database_tasks" "database_tasks" { + deployment_id = "%[1]s" + } + `, acc.IcdDbDeploymentId) +} diff --git a/ibm/data_source_ibm_database_test.go b/ibm/service/database/data_source_ibm_database_test.go similarity index 88% rename from ibm/data_source_ibm_database_test.go rename to ibm/service/database/data_source_ibm_database_test.go index 2d393e6b9..16e02ce51 100644 --- a/ibm/data_source_ibm_database_test.go +++ b/ibm/service/database/data_source_ibm_database_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -20,8 +22,8 @@ func TestAccIBMDatabaseDataSource_basic(t *testing.T) { resourceName := "ibm_database.db" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDatabaseDataSourceConfig(databaseResourceGroup, testName), @@ -32,7 +34,7 @@ func TestAccIBMDatabaseDataSource_basic(t *testing.T) { resource.TestCheckResourceAttr(dataName, "name", testName), resource.TestCheckResourceAttr(dataName, "service", "databases-for-postgresql"), resource.TestCheckResourceAttr(dataName, "plan", "standard"), - resource.TestCheckResourceAttr(dataName, "location", "us-south"), + resource.TestCheckResourceAttr(dataName, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(dataName, "adminuser", "admin"), resource.TestCheckResourceAttr(dataName, "members_memory_allocation_mb", "2048"), resource.TestCheckResourceAttr(dataName, "members_disk_allocation_mb", "10240"), @@ -65,9 +67,9 @@ func testAccCheckIBMDatabaseDataSourceConfig(databaseResourceGroup string, name name = "%[2]s" service = "databases-for-postgresql" plan = "standard" - location = "us-south" + location = "%[3]s" tags = ["one:two"] } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } diff --git a/ibm/service/database/resource_ibm_database.go b/ibm/service/database/resource_ibm_database.go new file mode 100644 index 000000000..800f9c5ec --- /dev/null +++ b/ibm/service/database/resource_ibm_database.go @@ -0,0 +1,2969 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net/url" + "os" + "reflect" + "regexp" + "sort" + "strings" + "time" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + validation "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + // "github.com/IBM-Cloud/bluemix-go/api/globaltagging/globaltaggingv3" + "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/cloud-databases-go-sdk/clouddatabasesv5" + "github.com/IBM/go-sdk-core/v5/core" +) + +const ( + databaseInstanceSuccessStatus = "active" + databaseInstanceProvisioningStatus = "provisioning" + databaseInstanceProgressStatus = "in progress" + databaseInstanceInactiveStatus = "inactive" + databaseInstanceFailStatus = "failed" + databaseInstanceRemovedStatus = "removed" + databaseInstanceReclamation = "pending_reclamation" +) + +const ( + databaseTaskSuccessStatus = "completed" + databaseTaskProgressStatus = "running" + databaseTaskFailStatus = "failed" +) + +type userChange struct { + Old, New map[string]interface{} +} + +func retry(f func() error) (err error) { + attempts := 3 + + for i := 0; ; i++ { + sleep := time.Duration(10*i*i) * time.Second + time.Sleep(sleep) + + err = f() + if err == nil { + return nil + } + + if i == attempts { + return err + } + + log.Println("retrying after error:", err) + } +} +func retryTask(f func() (icdv4.Task, error)) (task icdv4.Task, err error) { + attempts := 3 + + for i := 0; ; i++ { + sleep := time.Duration(5*i) * time.Second + time.Sleep(sleep) + + task, err = f() + if err == nil { + return task, nil + } + + if i == attempts { + return task, nil + } + + log.Println("retrying after error:", err) + } +} + +func ResourceIBMDatabaseInstance() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMDatabaseInstanceCreate, + ReadContext: resourceIBMDatabaseInstanceRead, + UpdateContext: resourceIBMDatabaseInstanceUpdate, + DeleteContext: resourceIBMDatabaseInstanceDelete, + Exists: resourceIBMDatabaseInstanceExists, + + CustomizeDiff: customdiff.All( + resourceIBMDatabaseInstanceDiff, + checkV5Groups), + + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Resource instance name for example, my Database instance", + Type: schema.TypeString, + Required: true, + }, + + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + Description: "The id of the resource group in which the Database instance is present", + ValidateFunc: validate.InvokeValidator( + "ibm_database", + "resource_group_id"), + }, + + "location": { + Description: "The location or the region in which Database instance exists", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator( + "ibm_database", + "location"), + }, + + "service": { + Description: "The name of the Cloud Internet database service", + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_database", "service"), + }, + "plan": { + Description: "The plan type of the Database instance", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_database", "plan"), + ForceNew: true, + }, + + "status": { + Description: "The resource instance status", + Type: schema.TypeString, + Computed: true, + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier of resource instance", + }, + + "adminuser": { + Description: "The admin user id for the instance", + Type: schema.TypeString, + Computed: true, + }, + "adminpassword": { + Description: "The admin user password for the instance", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(10, 32), + Sensitive: true, + // DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // return true + // }, + }, + "configuration": { + Type: schema.TypeString, + Optional: true, + StateFunc: func(v interface{}) string { + json, err := flex.NormalizeJSONString(v) + if err != nil { + return fmt.Sprintf("%q", err.Error()) + } + return json + }, + Description: "The configuration in JSON format", + }, + "configuration_schema": { + Type: schema.TypeString, + Computed: true, + Description: "The configuration schema in JSON format", + }, + "version": { + Description: "The database version to provision if specified", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "members_memory_allocation_mb": { + Description: "Memory allocation required for cluster", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "members_disk_allocation_mb": { + Description: "Disk allocation required for cluster", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "members_cpu_allocation_count": { + Description: "CPU allocation required for cluster", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"node_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "node_count": { + Description: "Total number of nodes in the cluster", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "node_memory_allocation_mb": { + Description: "Memory allocation per node", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "node_disk_allocation_mb": { + Description: "Disk allocation per node", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "node_cpu_allocation_count": { + Description: "CPU allocation per node", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count", "group"}, + Deprecated: "use group instead", + }, + "plan_validation": { + Description: "For elasticsearch and postgres perform database parameter validation during the plan phase. Otherwise, database parameter validation happens in apply phase.", + Type: schema.TypeBool, + Optional: true, + Default: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + if o == "" { + return true + } + return false + }, + }, + "service_endpoints": { + Description: "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", + Type: schema.TypeString, + Optional: true, + Default: "public", + ValidateFunc: validate.InvokeValidator("ibm_database", "service_endpoints"), + }, + "backup_id": { + Description: "The CRN of backup source database", + Type: schema.TypeString, + Optional: true, + }, + "remote_leader_id": { + Description: "The CRN of leader database", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + }, + "key_protect_instance": { + Description: "The CRN of Key protect instance", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "key_protect_key": { + Description: "The CRN of Key protect key", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "backup_encryption_key_crn": { + Description: "The Backup Encryption Key CRN", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_database", "tags")}, + Set: flex.ResourceIBMVPCHash, + }, + "point_in_time_recovery_deployment_id": { + Description: "The CRN of source instance", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + }, + "point_in_time_recovery_time": { + Description: "The point in time recovery time stamp of the deployed instance", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + }, + "users": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Description: "User name", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(5, 32), + }, + "password": { + Description: "User password", + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(10, 32), + }, + "type": { + Description: "User type", + Type: schema.TypeString, + Default: "database", + Optional: true, + Sensitive: false, + ValidateFunc: validation.StringInSlice([]string{"database", "ops_manager", "read_only_replica"}, false), + }, + "role": { + Description: "User role. Only available for ops_manager user type.", + Type: schema.TypeString, + Optional: true, + Sensitive: false, + ValidateFunc: validation.StringInSlice([]string{"group_read_only", "group_data_access_admin"}, false), + }, + }, + }, + }, + "connectionstrings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Description: "User name", + Type: schema.TypeString, + Computed: true, + }, + "composed": { + Description: "Connection string", + Type: schema.TypeString, + Computed: true, + }, + "scheme": { + Description: "DB scheme", + Type: schema.TypeString, + Computed: true, + }, + "certname": { + Description: "Certificate Name", + Type: schema.TypeString, + Computed: true, + }, + "certbase64": { + Description: "Certificate in base64 encoding", + Type: schema.TypeString, + Computed: true, + }, + "bundlename": { + Description: "Cassandra Bundle Name", + Type: schema.TypeString, + Computed: true, + }, + "bundlebase64": { + Description: "Cassandra base64 encoding", + Type: schema.TypeString, + Computed: true, + }, + "password": { + Description: "Password", + Type: schema.TypeString, + Computed: true, + }, + "queryoptions": { + Description: "DB query options", + Type: schema.TypeString, + Computed: true, + }, + "database": { + Description: "DB name", + Type: schema.TypeString, + Computed: true, + }, + "path": { + Description: "DB path", + Type: schema.TypeString, + Computed: true, + }, + "hosts": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": { + Description: "DB host name", + Type: schema.TypeString, + Computed: true, + }, + "port": { + Description: "DB port", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + Deprecated: "This field is deprecated, please use ibm_database_connection instead", + }, + "whitelist": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Description: "Whitelist IP address in CIDR notation", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateCIDR, + }, + "description": { + Description: "Unique white list description", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 32), + }, + }, + }, + }, + "group": { + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"members_memory_allocation_mb", "members_disk_allocation_mb", "members_cpu_allocation_count", "node_memory_allocation_mb", "node_disk_allocation_mb", "node_cpu_allocation_count", "node_count"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Required: true, + Type: schema.TypeString, + ValidateFunc: validate.InvokeValidator("ibm_database", "group_id"), + }, + "members": { + Optional: true, + Type: schema.TypeSet, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_count": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "memory": { + Optional: true, + Type: schema.TypeSet, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_mb": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "disk": { + Optional: true, + Type: schema.TypeSet, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_mb": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "cpu": { + Optional: true, + Type: schema.TypeSet, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_count": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Description: "Scaling group name", + Type: schema.TypeString, + Computed: true, + }, + "count": { + Description: "Count of scaling groups for the instance", + Type: schema.TypeInt, + Computed: true, + }, + "memory": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The units memory is allocated in.", + }, + "allocation_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The current memory allocation for a group instance", + }, + "minimum_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum memory size for a group instance", + }, + "step_size_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The step size memory increases or decreases in.", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the memory size adjustable.", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can memory scale down as well as up.", + }, + }, + }, + }, + "cpu": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The .", + }, + "allocation_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The current cpu allocation count", + }, + "minimum_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum number of cpus allowed", + }, + "step_size_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of CPUs allowed to step up or down by", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Are the number of CPUs adjustable", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can the number of CPUs be scaled down as well as up", + }, + }, + }, + }, + "disk": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "units": { + Type: schema.TypeString, + Computed: true, + Description: "The units disk is allocated in", + }, + "allocation_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The current disk allocation", + }, + "minimum_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum disk size allowed", + }, + "step_size_mb": { + Type: schema.TypeInt, + Computed: true, + Description: "The step size disk increases or decreases in", + }, + "is_adjustable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the disk size adjustable", + }, + "can_scale_down": { + Type: schema.TypeBool, + Computed: true, + Description: "Can the disk size be scaled down as well as up", + }, + }, + }, + }, + }, + }, + }, + "auto_scaling": { + Type: schema.TypeList, + Description: "ICD Auto Scaling", + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disk": { + Type: schema.TypeList, + Description: "Disk Auto Scaling", + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity_enabled": { + Description: "Auto Scaling Scalar: Capacity Enabled", + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "free_space_less_than_percent": { + Description: "Auto Scaling Scalar: Capacity Free Space Less Than Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "io_enabled": { + Description: "Auto Scaling Scalar: IO Utilization Enabled", + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "io_over_period": { + Description: "Auto Scaling Scalar: IO Utilization Over Period", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "io_above_percent": { + Description: "Auto Scaling Scalar: IO Utilization Above Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_limit_mb_per_member": { + Description: "Auto Scaling Rate: Limit mb per member", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + "memory": { + Type: schema.TypeList, + Description: "Memory Auto Scaling", + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "io_enabled": { + Description: "Auto Scaling Scalar: IO Utilization Enabled", + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "io_over_period": { + Description: "Auto Scaling Scalar: IO Utilization Over Period", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "io_above_percent": { + Description: "Auto Scaling Scalar: IO Utilization Above Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_limit_mb_per_member": { + Description: "Auto Scaling Rate: Limit mb per member", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + "cpu": { + Type: schema.TypeList, + Description: "CPU Auto Scaling", + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rate_increase_percent": { + Description: "Auto Scaling Rate: Increase Percent", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_period_seconds": { + Description: "Auto Scaling Rate: Period Seconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_limit_count_per_member": { + Description: "Auto Scaling Rate: Limit count per number", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "rate_units": { + Description: "Auto Scaling Rate: Units ", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} +func ResourceIBMICDValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "region", + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + AllowedValues: "databases-for-etcd, databases-for-postgresql, databases-for-redis, databases-for-elasticsearch, databases-for-mongodb, messages-for-rabbitmq, databases-for-mysql, databases-for-cassandra, databases-for-enterprisedb", + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "plan", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + AllowedValues: "standard, enterprise", + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_endpoints", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + AllowedValues: "public, private, public-and-private", + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "group_id", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + AllowedValues: "member, analytics, bi_connector, search", + Required: true}) + + ibmICDResourceValidator := validate.ResourceValidator{ResourceName: "ibm_database", Schema: validateSchema} + return &ibmICDResourceValidator +} + +type Params struct { + Version string `json:"version,omitempty"` + KeyProtectKey string `json:"disk_encryption_key_crn,omitempty"` + BackUpEncryptionCRN string `json:"backup_encryption_key_crn,omitempty"` + Memory int `json:"members_memory_allocation_mb,omitempty"` + Disk int `json:"members_disk_allocation_mb,omitempty"` + CPU int `json:"members_cpu_allocation_count,omitempty"` + KeyProtectInstance string `json:"disk_encryption_instance_crn,omitempty"` + ServiceEndpoints string `json:"service-endpoints,omitempty"` + BackupID string `json:"backup-id,omitempty"` + RemoteLeaderID string `json:"remote_leader_id,omitempty"` + PITRDeploymentID string `json:"point_in_time_recovery_deployment_id,omitempty"` + PITRTimeStamp string `json:"point_in_time_recovery_time,omitempty"` +} + +type Group struct { + ID string + Members *GroupResource + Memory *GroupResource + Disk *GroupResource + CPU *GroupResource +} + +type GroupResource struct { + Units string + Allocation int + Minimum int + Maximum int + StepSize int + IsAdjustable bool + IsOptional bool + CanScaleDown bool +} + +func getDefaultScalingGroups(_service string, _plan string, meta interface{}) (groups []clouddatabasesv5.Group, err error) { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return groups, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) + } + + re := regexp.MustCompile("(?:messages|databases)-for-([a-z]+)") + match := re.FindStringSubmatch(_service) + + if match == nil { + return groups, fmt.Errorf("[ERROR] Error invalid service name: %s", _service) + } + + service := match[1] + + if service == "cassandra" { + service = "datastax_enterprise_full" + } + + if service == "mongodb" && _plan == "enterprise" { + service = "mongodbee" + } + + getDefaultScalingGroupsOptions := cloudDatabasesClient.NewGetDefaultScalingGroupsOptions(service) + + getDefaultScalingGroupsResponse, _, err := cloudDatabasesClient.GetDefaultScalingGroups(getDefaultScalingGroupsOptions) + if err != nil { + return groups, err + } + + return getDefaultScalingGroupsResponse.Groups, nil +} + +func getDatabaseServiceDefaults(service string, meta interface{}) (*icdv4.Group, error) { + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return nil, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) + } + + var dbType string + if service == "databases-for-cassandra" { + dbType = "datastax_enterprise_full" + } else if strings.HasPrefix(service, "messages-for-") { + dbType = service[len("messages-for-"):] + } else { + dbType = service[len("databases-for-"):] + } + + groupDefaults, err := icdClient.Groups().GetDefaultGroups(dbType) + if err != nil { + return nil, fmt.Errorf("ICD API is down for plan validation, set plan_validation=false %s", err) + } + return &groupDefaults.Groups[0], nil +} + +func getInitialNodeCount(service string, plan string, meta interface{}) (int, error) { + groups, err := getDefaultScalingGroups(service, plan, meta) + + if err != nil { + return 0, err + } + + for _, g := range groups { + if *g.ID == "member" { + return int(*g.Members.MinimumCount), nil + } + } + + return 0, fmt.Errorf("getInitialNodeCount failed for member group") +} + +func getGroups(instanceID string, meta interface{}) (groups []clouddatabasesv5.Group, err error) { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return nil, err + } + + listDeploymentScalingGroupsOptions := &clouddatabasesv5.ListDeploymentScalingGroupsOptions{ + ID: &instanceID, + } + + groupsResponse, _, err := cloudDatabasesClient.ListDeploymentScalingGroups(listDeploymentScalingGroupsOptions) + if err != nil { + return groups, err + } + + return groupsResponse.Groups, nil +} + +// V5 Groups +func checkGroupScaling(groupId string, resourceName string, value int, resource *GroupResource, nodeCount int) error { + if nodeCount == 0 { + nodeCount = 1 + } + if resource.StepSize == 0 { + return fmt.Errorf("%s group must have members scaled > 0 before scaling %s", groupId, resourceName) + } + if value < resource.Minimum/nodeCount || value > resource.Maximum/nodeCount || value%(resource.StepSize/nodeCount) != 0 { + if !(value == 0 && resource.IsOptional) { + return fmt.Errorf("%s group %s must be >= %d and <= %d in increments of %d", groupId, resourceName, resource.Minimum/nodeCount, resource.Maximum/nodeCount, resource.StepSize/nodeCount) + } + } + if value != resource.Allocation/nodeCount && !resource.IsAdjustable { + return fmt.Errorf("%s can not change %s value after create", groupId, resourceName) + } + if value < resource.Allocation/nodeCount && !resource.CanScaleDown { + return fmt.Errorf("can not scale %s group %s below %d to %d", groupId, resourceName, resource.Allocation/nodeCount, value) + } + return nil +} + +func checkGroupValue(name string, limits GroupResource, divider int, diff *schema.ResourceDiff) error { + if diff.HasChange(name) { + oldSetting, newSetting := diff.GetChange(name) + old := oldSetting.(int) + new := newSetting.(int) + + if new < limits.Minimum/divider || new > limits.Maximum/divider || new%(limits.StepSize/divider) != 0 { + if !(new == 0 && limits.IsOptional) { + return fmt.Errorf("%s must be >= %d and <= %d in increments of %d", name, limits.Minimum/divider, limits.Maximum/divider/divider, limits.StepSize/divider) + } + } + if old != new && !limits.IsAdjustable { + return fmt.Errorf("%s can not change value after create", name) + } + if new < old && !limits.CanScaleDown { + return fmt.Errorf("%s can not scale down from %d to %d", name, old, new) + } + return nil + } + return nil +} + +type CountLimit struct { + Units string + AllocationCount int + MinimumCount int + MaximumCount int + StepSizeCount int + IsAdjustable bool + IsOptional bool + CanScaleDown bool +} + +func checkCountValue(name string, limits CountLimit, divider int, diff *schema.ResourceDiff) error { + groupLimit := GroupResource{ + Units: limits.Units, + Allocation: limits.AllocationCount, + Minimum: limits.MinimumCount, + Maximum: limits.MaximumCount, + StepSize: limits.StepSizeCount, + IsAdjustable: limits.IsAdjustable, + IsOptional: limits.IsOptional, + CanScaleDown: limits.CanScaleDown, + } + return checkGroupValue(name, groupLimit, divider, diff) +} + +type MbLimit struct { + Units string + AllocationMb int + MinimumMb int + MaximumMb int + StepSizeMb int + IsAdjustable bool + IsOptional bool + CanScaleDown bool +} + +func checkMbValue(name string, limits MbLimit, divider int, diff *schema.ResourceDiff) error { + groupLimit := GroupResource{ + Units: limits.Units, + Allocation: limits.AllocationMb, + Minimum: limits.MinimumMb, + Maximum: limits.MaximumMb, + StepSize: limits.StepSizeMb, + IsAdjustable: limits.IsAdjustable, + IsOptional: limits.IsOptional, + CanScaleDown: limits.CanScaleDown, + } + return checkGroupValue(name, groupLimit, divider, diff) +} + +func resourceIBMDatabaseInstanceDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) (err error) { + err = flex.ResourceTagsCustomizeDiff(diff) + if err != nil { + return err + } + + service := diff.Get("service").(string) + planPhase := diff.Get("plan_validation").(bool) + + if service == "databases-for-postgresql" || + service == "databases-for-elasticsearch" || + service == "databases-for-cassandra" || + service == "databases-for-enterprisedb" { + if planPhase { + groupDefaults, err := getDatabaseServiceDefaults(service, meta) + if err != nil { + return err + } + + err = checkMbValue("members_memory_allocation_mb", MbLimit(groupDefaults.Memory), 1, diff) + if err != nil { + return err + } + + err = checkMbValue("members_disk_allocation_mb", MbLimit(groupDefaults.Disk), 1, diff) + if err != nil { + return err + } + + err = checkCountValue("members_cpu_allocation_count", CountLimit(groupDefaults.Cpu), 1, diff) + if err != nil { + return err + } + + err = checkCountValue("node_count", CountLimit(groupDefaults.Members), 1, diff) + if err != nil { + return err + } + + var divider = groupDefaults.Members.MinimumCount + err = checkMbValue("node_memory_allocation_mb", MbLimit(groupDefaults.Memory), divider, diff) + if err != nil { + return err + } + + err = checkMbValue("node_disk_allocation_mb", MbLimit(groupDefaults.Disk), divider, diff) + if err != nil { + return err + } + + if diff.HasChange("node_cpu_allocation_count") { + err = checkCountValue("node_cpu_allocation_count", CountLimit(groupDefaults.Cpu), divider, diff) + if err != nil { + return err + } + } else if diff.HasChange("node_count") { + if _, ok := diff.GetOk("node_cpu_allocation_count"); !ok { + _, newSetting := diff.GetChange("node_count") + min := groupDefaults.Cpu.MinimumCount / divider + if newSetting != min { + return fmt.Errorf("node_cpu_allocation_count must be set when node_count is greater then the minimum %d", min) + } + } + } + } + } else if diff.HasChange("node_count") || diff.HasChange("node_memory_allocation_mb") || diff.HasChange("node_disk_allocation_mb") || diff.HasChange("node_cpu_allocation_count") { + return fmt.Errorf("[ERROR] node_count, node_memory_allocation_mb, node_disk_allocation_mb, node_cpu_allocation_count only supported for postgresql, elasticsearch and cassandra") + } + + return nil +} + +// Replace with func wrapper for resourceIBMResourceInstanceCreate specifying serviceName := "database......." +func resourceIBMDatabaseInstanceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return diag.FromErr(err) + } + + serviceName := d.Get("service").(string) + plan := d.Get("plan").(string) + name := d.Get("name").(string) + location := d.Get("location").(string) + + rsInst := rc.CreateResourceInstanceOptions{ + Name: &name, + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return diag.FromErr(err) + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(serviceName, true) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving database service offering: %s", err)) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving plan: %s", err)) + } + rsInst.ResourcePlanID = &servicePlan + + deployments, err := rsCatRepo.ListDeployments(servicePlan) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving deployment for plan %s : %s", plan, err)) + } + if len(deployments) == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan)) + } + deployments, supportedLocations := filterDatabaseDeployments(deployments, location) + + if len(deployments) == 0 { + locationList := make([]string, 0, len(supportedLocations)) + for l := range supportedLocations { + locationList = append(locationList, l) + } + return diag.FromErr(fmt.Errorf("[ERROR] No deployment found for service plan %s at location %s.\nValid location(s) are: %q", plan, location, locationList)) + } + catalogCRN := deployments[0].CatalogCRN + rsInst.Target = &catalogCRN + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rgID := rsGrpID.(string) + rsInst.ResourceGroup = &rgID + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return diag.FromErr(err) + } + rsInst.ResourceGroup = &defaultRg + } + + initialNodeCount, err := getInitialNodeCount(serviceName, plan, meta) + if err != nil { + return diag.FromErr(err) + } + + params := Params{} + if group, ok := d.GetOk("group"); ok { + groups := expandGroups(group.(*schema.Set).List()) + var memberGroup *Group + for _, g := range groups { + if g.ID == "member" { + memberGroup = g + break + } + } + + if memberGroup != nil { + if memberGroup.Memory != nil { + params.Memory = memberGroup.Memory.Allocation * initialNodeCount + } + + if memberGroup.Disk != nil { + params.Disk = memberGroup.Disk.Allocation * initialNodeCount + } + + if memberGroup.CPU != nil { + params.CPU = memberGroup.CPU.Allocation * initialNodeCount + } + } + } + if memory, ok := d.GetOk("members_memory_allocation_mb"); ok { + params.Memory = memory.(int) + } + if memory, ok := d.GetOk("node_memory_allocation_mb"); ok { + params.Memory = memory.(int) * initialNodeCount + } + if disk, ok := d.GetOk("members_disk_allocation_mb"); ok { + params.Disk = disk.(int) + } + if disk, ok := d.GetOk("node_disk_allocation_mb"); ok { + params.Disk = disk.(int) * initialNodeCount + } + if cpu, ok := d.GetOk("members_cpu_allocation_count"); ok { + params.CPU = cpu.(int) + } + if cpu, ok := d.GetOk("node_cpu_allocation_count"); ok { + params.CPU = cpu.(int) * initialNodeCount + } + if version, ok := d.GetOk("version"); ok { + params.Version = version.(string) + } + if keyProtect, ok := d.GetOk("key_protect_key"); ok { + params.KeyProtectKey = keyProtect.(string) + } + if keyProtectInstance, ok := d.GetOk("key_protect_instance"); ok { + params.KeyProtectInstance = keyProtectInstance.(string) + } + if backupID, ok := d.GetOk("backup_id"); ok { + params.BackupID = backupID.(string) + } + if backUpEncryptionKey, ok := d.GetOk("backup_encryption_key_crn"); ok { + params.BackUpEncryptionCRN = backUpEncryptionKey.(string) + } + if remoteLeader, ok := d.GetOk("remote_leader_id"); ok { + params.RemoteLeaderID = remoteLeader.(string) + } + if pitrID, ok := d.GetOk("point_in_time_recovery_deployment_id"); ok { + params.PITRDeploymentID = pitrID.(string) + } + if pitrTime, ok := d.GetOk("point_in_time_recovery_time"); ok { + params.PITRTimeStamp = pitrTime.(string) + } + serviceEndpoint := d.Get("service_endpoints").(string) + params.ServiceEndpoints = serviceEndpoint + parameters, _ := json.Marshal(params) + var raw map[string]interface{} + json.Unmarshal(parameters, &raw) + //paramString := string(parameters[:]) + rsInst.Parameters = raw + + instance, response, err := rsConClient.CreateResourceInstance(&rsInst) + if err != nil { + return diag.FromErr( + fmt.Errorf("[ERROR] Error creating database instance: %s %s", err, response)) + } + d.SetId(*instance.ID) + + _, err = waitForDatabaseInstanceCreate(d, meta, *instance.ID) + if err != nil { + return diag.FromErr( + fmt.Errorf( + "[ERROR] Error waiting for create database instance (%s) to complete: %s", *instance.ID, err)) + } + + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(err) + } + + if node_count, ok := d.GetOk("node_count"); ok { + if initialNodeCount != node_count { + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + err = horizontalScale(d, meta, icdClient) + if err != nil { + return diag.FromErr(err) + } + } + } + + if group, ok := d.GetOk("group"); ok { + groups := expandGroups(group.(*schema.Set).List()) + groupsResponse, err := getGroups(*instance.ID, meta) + if err != nil { + return diag.FromErr(err) + } + currentGroups := normalizeGroups(groupsResponse) + + for _, g := range groups { + groupScaling := &clouddatabasesv5.GroupScaling{} + var currentGroup *Group + var nodeCount int + + for _, cg := range currentGroups { + if cg.ID == g.ID { + currentGroup = &cg + nodeCount = currentGroup.Members.Allocation + } + } + + if g.ID == "member" && (g.Members == nil || g.Members.Allocation == nodeCount) { + // No Horizontal Scaling needed + continue + } + + if g.Members != nil && g.Members.Allocation != currentGroup.Members.Allocation { + groupScaling.Members = &clouddatabasesv5.GroupScalingMembers{AllocationCount: core.Int64Ptr(int64(g.Members.Allocation))} + nodeCount = g.Members.Allocation + } + if g.Memory != nil && g.Memory.Allocation*nodeCount != currentGroup.Memory.Allocation { + groupScaling.Memory = &clouddatabasesv5.GroupScalingMemory{AllocationMb: core.Int64Ptr(int64(g.Memory.Allocation * nodeCount))} + } + if g.Disk != nil && g.Disk.Allocation*nodeCount != currentGroup.Disk.Allocation { + groupScaling.Disk = &clouddatabasesv5.GroupScalingDisk{AllocationMb: core.Int64Ptr(int64(g.Disk.Allocation * nodeCount))} + } + if g.CPU != nil && g.CPU.Allocation*nodeCount != currentGroup.CPU.Allocation { + groupScaling.CPU = &clouddatabasesv5.GroupScalingCPU{AllocationCount: core.Int64Ptr(int64(g.CPU.Allocation * nodeCount))} + } + + if groupScaling.Members != nil || groupScaling.Memory != nil || groupScaling.Disk != nil || groupScaling.CPU != nil { + setDeploymentScalingGroupOptions := &clouddatabasesv5.SetDeploymentScalingGroupOptions{ + ID: instance.ID, + GroupID: &g.ID, + Group: groupScaling, + } + + setDeploymentScalingGroupResponse, _, err := cloudDatabasesClient.SetDeploymentScalingGroup(setDeploymentScalingGroupOptions) + + taskIDLink := *setDeploymentScalingGroupResponse.Task.ID + + _, err = waitForDatabaseTaskComplete(taskIDLink, d, meta, d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return diag.FromErr(err) + } + } + } + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of ibm database (%s) tags: %s", d.Id(), err) + } + } + + instanceID := *instance.ID + icdId := flex.EscapeUrlParm(instanceID) + + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + if pw, ok := d.GetOk("adminpassword"); ok { + adminPassword := pw.(string) + + getDeploymentInfoOptions := &clouddatabasesv5.GetDeploymentInfoOptions{ + ID: core.StringPtr(instanceID), + } + getDeploymentInfoResponse, response, err := cloudDatabasesClient.GetDeploymentInfo(getDeploymentInfoOptions) + + if err != nil { + if response.StatusCode == 404 { + return diag.FromErr(fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err)) + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database config while updating adminpassword for: %s with error %s", instanceID, err)) + } + deployment := getDeploymentInfoResponse.Deployment + + adminUser := deployment.AdminUsernames["database"] + + user := &clouddatabasesv5.APasswordSettingUser{ + Password: &adminPassword, + } + + changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + ID: core.StringPtr(instanceID), + UserType: core.StringPtr("database"), + Username: core.StringPtr(adminUser), + User: user, + } + + changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %s\n%s", *changeUserPasswordOptions.Username, err, response)) + } + + taskID := *changeUserPasswordResponse.Task.ID + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database admin password: %s", err)) + } + } + + if wl, ok := d.GetOk("whitelist"); ok { + whitelist := flex.ExpandWhitelist(wl.(*schema.Set)) + for _, wlEntry := range whitelist { + whitelistReq := icdv4.WhitelistReq{ + WhitelistEntry: icdv4.WhitelistEntry{ + Address: wlEntry.Address, + Description: wlEntry.Description, + }, + } + task, err := icdClient.Whitelists().CreateWhitelist(icdId, whitelistReq) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database whitelist entry: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for update of database (%s) whitelist task to complete: %s", icdId, err)) + } + } + } + if cpuRecord, ok := d.GetOk("auto_scaling.0.cpu"); ok { + params := icdv4.AutoscalingSetGroup{} + cpuBody, err := expandICDAutoScalingGroup(d, cpuRecord, "cpu") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting cpuBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.CPU = &cpuBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database cpu auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) cpu auto_scaling group update task to complete: %s", icdId, err)) + } + + } + if diskRecord, ok := d.GetOk("auto_scaling.0.disk"); ok { + params := icdv4.AutoscalingSetGroup{} + diskBody, err := expandICDAutoScalingGroup(d, diskRecord, "disk") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting diskBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.Disk = &diskBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database disk auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) disk auto_scaling group update task to complete: %s", icdId, err)) + } + + } + if memoryRecord, ok := d.GetOk("auto_scaling.0.memory"); ok { + params := icdv4.AutoscalingSetGroup{} + memoryBody, err := expandICDAutoScalingGroup(d, memoryRecord, "memory") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting memoryBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.Memory = &memoryBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database memory auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) memory auto_scaling group update task to complete: %s", icdId, err)) + } + } + + if userList, ok := d.GetOk("users"); ok { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + for _, user := range userList.(*schema.Set).List() { + userEl := user.(map[string]interface{}) + createDatabaseUserRequestUserModel := &clouddatabasesv5.User{ + Username: core.StringPtr(userEl["name"].(string)), + Password: core.StringPtr(userEl["password"].(string)), + } + + // User Role only for ops_manager user type + if userEl["type"].(string) == "ops_manager" && userEl["role"].(string) != "" { + createDatabaseUserRequestUserModel.Role = core.StringPtr(userEl["role"].(string)) + } + + instanceId := d.Id() + createDatabaseUserOptions := &clouddatabasesv5.CreateDatabaseUserOptions{ + ID: &instanceId, + UserType: core.StringPtr(userEl["type"].(string)), + User: createDatabaseUserRequestUserModel, + } + + createDatabaseUserResponse, response, err := cloudDatabasesClient.CreateDatabaseUser(createDatabaseUserOptions) + + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDatabaseUser (%s) failed %s\n%s", userEl["name"], err, response)) + } + + taskID := *createDatabaseUserResponse.Task.ID + + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for update of database (%s) user (%s) create task to complete: %s", d.Id(), userEl["name"], err)) + } + } + } + + return resourceIBMDatabaseInstanceRead(context, d, meta) +} + +func resourceIBMDatabaseInstanceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return diag.FromErr(err) + } + + instanceID := d.Id() + connectionEndpoint := "public" + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + log.Printf("[WARN] Removing record from state because it's not found via the API") + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response)) + } + if strings.Contains(*instance.State, "removed") { + log.Printf("[WARN] Removing instance from TF state because it's now in removed state") + d.SetId("") + return nil + } + + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on get of ibm Database tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + d.Set("name", *instance.Name) + d.Set("status", *instance.State) + d.Set("resource_group_id", *instance.ResourceGroupID) + if instance.CRN != nil { + location := strings.Split(*instance.CRN, ":") + if len(location) > 5 { + d.Set("location", location[5]) + } + } + d.Set("guid", *instance.GUID) + + if instance.Parameters != nil { + if endpoint, ok := instance.Parameters["service-endpoints"]; ok { + if endpoint == "private" { + connectionEndpoint = "private" + } + d.Set("service_endpoints", endpoint) + } + + } + + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.CRN) + d.Set(flex.ResourceStatus, *instance.State) + d.Set(flex.ResourceGroupName, *instance.ResourceGroupCRN) + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return diag.FromErr(err) + } + d.Set(flex.ResourceControllerURL, rcontroller+"/services/"+url.QueryEscape(*instance.CRN)) + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return diag.FromErr(err) + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.GetServiceName(*instance.ResourceID) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving service offering: %s", err)) + } + + d.Set("service", serviceOff) + + servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving plan: %s", err)) + } + d.Set("plan", servicePlan) + + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + icdId := flex.EscapeUrlParm(instanceID) + + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + getDeploymentInfoOptions := &clouddatabasesv5.GetDeploymentInfoOptions{ + ID: core.StringPtr(instanceID), + } + getDeploymentInfoResponse, response, err := cloudDatabasesClient.GetDeploymentInfo(getDeploymentInfoOptions) + + if err != nil { + if response.StatusCode == 404 { + return diag.FromErr(fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err)) + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database config while updating adminpassword for: %s with error %s", instanceID, err)) + } + + deployment := getDeploymentInfoResponse.Deployment + + d.Set("adminuser", deployment.AdminUsernames["database"]) + d.Set("version", deployment.Version) + + groupList, err := icdClient.Groups().GetGroups(icdId) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database groups: %s", err)) + } + if groupList.Groups[0].Members.AllocationCount == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] This database appears to have have 0 members. Unable to proceed")) + } + + d.Set("groups", flex.FlattenIcdGroups(groupList)) + d.Set("node_count", groupList.Groups[0].Members.AllocationCount) + + d.Set("members_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb) + d.Set("node_memory_allocation_mb", groupList.Groups[0].Memory.AllocationMb/groupList.Groups[0].Members.AllocationCount) + + d.Set("members_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb) + d.Set("node_disk_allocation_mb", groupList.Groups[0].Disk.AllocationMb/groupList.Groups[0].Members.AllocationCount) + + d.Set("members_cpu_allocation_count", groupList.Groups[0].Cpu.AllocationCount) + d.Set("node_cpu_allocation_count", groupList.Groups[0].Cpu.AllocationCount/groupList.Groups[0].Members.AllocationCount) + + autoSclaingGroup, err := icdClient.AutoScaling().GetAutoScaling(icdId, "member") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database autoscaling groups: %s", err)) + } + d.Set("auto_scaling", flattenICDAutoScalingGroup(autoSclaingGroup)) + + whitelist, err := icdClient.Whitelists().GetWhitelist(icdId) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database whitelist: %s", err)) + } + d.Set("whitelist", flex.FlattenWhitelist(whitelist)) + + var connectionStrings []flex.CsEntry + //ICD does not implement a GetUsers API. Users populated from tf configuration. + tfusers := d.Get("users").(*schema.Set) + users := flex.ExpandUsers(tfusers) + user := icdv4.User{ + UserName: deployment.AdminUsernames["database"], + } + users = append(users, user) + for _, user := range users { + userName := user.UserName + csEntry, err := getConnectionString(d, userName, connectionEndpoint, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting user connection string for user (%s): %s", userName, err)) + } + connectionStrings = append(connectionStrings, csEntry) + } + d.Set("connectionstrings", flex.FlattenConnectionStrings(connectionStrings)) + + if serviceOff == "databases-for-postgresql" || serviceOff == "databases-for-redis" || serviceOff == "databases-for-enterprisedb" { + configSchema, err := icdClient.Configurations().GetConfiguration(icdId) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database (%s) configuration schema : %s", icdId, err)) + } + s, err := json.Marshal(configSchema) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error marshalling the database configuration schema: %s", err)) + } + + if err = d.Set("configuration_schema", string(s)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting the database configuration schema: %s", err)) + } + } + return nil +} + +func resourceIBMDatabaseInstanceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return diag.FromErr(err) + } + + instanceID := d.Id() + updateReq := rc.UpdateResourceInstanceOptions{ + ID: &instanceID, + } + update := false + if d.HasChange("name") { + name := d.Get("name").(string) + updateReq.Name = &name + update = true + } + if d.HasChange("service_endpoints") { + params := Params{} + params.ServiceEndpoints = d.Get("service_endpoints").(string) + parameters, _ := json.Marshal(params) + var raw map[string]interface{} + json.Unmarshal(parameters, &raw) + updateReq.Parameters = raw + update = true + } + + if update { + _, response, err := rsConClient.UpdateResourceInstance(&updateReq) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating resource instance: %s %s", err, response)) + } + + _, err = waitForDatabaseInstanceUpdate(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for update of resource instance (%s) to complete: %s", d.Id(), err)) + } + } + + if d.HasChange("tags") { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, instanceID) + if err != nil { + log.Printf( + "[ERROR] Error on update of Database (%s) tags: %s", d.Id(), err) + } + } + + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + icdId := flex.EscapeUrlParm(instanceID) + + if d.HasChange("node_count") { + err = horizontalScale(d, meta, icdClient) + if err != nil { + return diag.FromErr(err) + } + } + if d.HasChange("configuration") { + service := d.Get("service").(string) + if service == "databases-for-postgresql" || service == "databases-for-redis" || service == "databases-for-enterprisedb" { + if s, ok := d.GetOk("configuration"); ok { + var configuration interface{} + json.Unmarshal([]byte(s.(string)), &configuration) + configPayload := icdv4.ConfigurationReq{Configuration: configuration} + task, err := icdClient.Configurations().UpdateConfiguration(icdId, configPayload) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database (%s) configuration: %s", icdId, err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) configuration update task to complete: %s", icdId, err)) + } + } + + } else { + return diag.FromErr(fmt.Errorf("[ERROR] given database type %s is not configurable", service)) + } + + } + + if d.HasChange("members_memory_allocation_mb") || d.HasChange("members_disk_allocation_mb") || d.HasChange("members_cpu_allocation_count") || d.HasChange("node_memory_allocation_mb") || d.HasChange("node_disk_allocation_mb") || d.HasChange("node_cpu_allocation_count") { + params := icdv4.GroupReq{} + if d.HasChange("members_memory_allocation_mb") { + memory := d.Get("members_memory_allocation_mb").(int) + memoryReq := icdv4.MemoryReq{AllocationMb: memory} + params.GroupBdy.Memory = &memoryReq + } + if d.HasChange("node_memory_allocation_mb") || d.HasChange("node_count") { + memory := d.Get("node_memory_allocation_mb").(int) + count := d.Get("node_count").(int) + memoryReq := icdv4.MemoryReq{AllocationMb: memory * count} + params.GroupBdy.Memory = &memoryReq + } + if d.HasChange("members_disk_allocation_mb") { + disk := d.Get("members_disk_allocation_mb").(int) + diskReq := icdv4.DiskReq{AllocationMb: disk} + params.GroupBdy.Disk = &diskReq + } + if d.HasChange("node_disk_allocation_mb") || d.HasChange("node_count") { + disk := d.Get("node_disk_allocation_mb").(int) + count := d.Get("node_count").(int) + diskReq := icdv4.DiskReq{AllocationMb: disk * count} + params.GroupBdy.Disk = &diskReq + } + if d.HasChange("members_cpu_allocation_count") { + cpu := d.Get("members_cpu_allocation_count").(int) + cpuReq := icdv4.CpuReq{AllocationCount: cpu} + params.GroupBdy.Cpu = &cpuReq + } + if d.HasChange("node_cpu_allocation_mb") || d.HasChange("node_count") { + cpu := d.Get("node_cpu_allocation_count").(int) + count := d.Get("node_count").(int) + CpuReq := icdv4.CpuReq{AllocationCount: cpu * count} + params.GroupBdy.Cpu = &CpuReq + } + + task, err := icdClient.Groups().UpdateGroup(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database scaling group: %s", err)) + } + + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) scaling group update task to complete: %s", icdId, err)) + } + } + + if d.HasChange("group") { + oldGroup, newGroup := d.GetChange("group") + if oldGroup == nil { + oldGroup = new(schema.Set) + } + if newGroup == nil { + newGroup = new(schema.Set) + } + + os := oldGroup.(*schema.Set) + ns := newGroup.(*schema.Set) + + groupChanges := expandGroups(ns.Difference(os).List()) + + groupsResponse, err := getGroups(instanceID, meta) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error geting group (%s) scaling group update task to complete: %s", icdId, err)) + } + + currentGroups := normalizeGroups(groupsResponse) + + for _, group := range groupChanges { + groupScaling := &clouddatabasesv5.GroupScaling{} + var currentGroup *Group + for _, g := range currentGroups { + if g.ID == group.ID { + currentGroup = &g + break + } + } + + if currentGroup == nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] (%s) group does not exist: %s", icdId, err)) + } + nodeCount := currentGroup.Members.Allocation + + if group.Members != nil && group.Members.Allocation != currentGroup.Members.Allocation { + groupScaling.Members = &clouddatabasesv5.GroupScalingMembers{AllocationCount: core.Int64Ptr(int64(group.Members.Allocation))} + nodeCount = group.Members.Allocation + } + if group.Memory != nil && group.Memory.Allocation*nodeCount != currentGroup.Memory.Allocation { + groupScaling.Memory = &clouddatabasesv5.GroupScalingMemory{AllocationMb: core.Int64Ptr(int64(group.Memory.Allocation * nodeCount))} + } + if group.Disk != nil && group.Disk.Allocation*nodeCount != currentGroup.Disk.Allocation { + groupScaling.Disk = &clouddatabasesv5.GroupScalingDisk{AllocationMb: core.Int64Ptr(int64(group.Disk.Allocation * nodeCount))} + } + if group.CPU != nil && group.CPU.Allocation*nodeCount != currentGroup.CPU.Allocation { + groupScaling.CPU = &clouddatabasesv5.GroupScalingCPU{AllocationCount: core.Int64Ptr(int64(group.CPU.Allocation * nodeCount))} + } + + if groupScaling.Members != nil || groupScaling.Memory != nil || groupScaling.Disk != nil || groupScaling.CPU != nil { + setDeploymentScalingGroupOptions := &clouddatabasesv5.SetDeploymentScalingGroupOptions{ + ID: &instanceID, + GroupID: &group.ID, + Group: groupScaling, + } + + setDeploymentScalingGroupResponse, response, err := cloudDatabasesClient.SetDeploymentScalingGroup(setDeploymentScalingGroupOptions) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] SetDeploymentScalingGroup (%s) failed %s\n%s", group.ID, err, response)) + } + + // API may return HTTP 204 No Content if no change made + if response.StatusCode == 200 { + taskIDLink := *setDeploymentScalingGroupResponse.Task.ID + + _, err = waitForDatabaseTaskComplete(taskIDLink, d, meta, d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return diag.FromErr(err) + } + } + } + } + } + + if d.HasChange("auto_scaling.0.cpu") { + cpuRecord := d.Get("auto_scaling.0.cpu") + params := icdv4.AutoscalingSetGroup{} + cpuBody, err := expandICDAutoScalingGroup(d, cpuRecord, "cpu") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting cpuBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.CPU = &cpuBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database cpu auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) cpu auto_scaling group update task to complete: %s", icdId, err)) + } + + } + if d.HasChange("auto_scaling.0.disk") { + diskRecord := d.Get("auto_scaling.0.disk") + params := icdv4.AutoscalingSetGroup{} + diskBody, err := expandICDAutoScalingGroup(d, diskRecord, "disk") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting diskBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.Disk = &diskBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database disk auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) disk auto_scaling group update task to complete: %s", icdId, err)) + } + + } + if d.HasChange("auto_scaling.0.memory") { + memoryRecord := d.Get("auto_scaling.0.memory") + params := icdv4.AutoscalingSetGroup{} + memoryBody, err := expandICDAutoScalingGroup(d, memoryRecord, "memory") + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error in getting memoryBody from expandICDAutoScalingGroup %s", err)) + } + params.Autoscaling.Memory = &memoryBody + task, err := icdClient.AutoScaling().SetAutoScaling(icdId, "member", params) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database memory auto_scaling group: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) memory auto_scaling group update task to complete: %s", icdId, err)) + } + } + + if d.HasChange("adminpassword") { + adminUser := d.Get("adminuser").(string) + password := d.Get("adminpassword").(string) + user := &clouddatabasesv5.APasswordSettingUser{ + Password: &password, + } + + changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + ID: core.StringPtr(instanceID), + UserType: core.StringPtr("database"), + Username: core.StringPtr(adminUser), + User: user, + } + + changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %s\n%s", *changeUserPasswordOptions.Username, err, response)) + } + + taskID := *changeUserPasswordResponse.Task.ID + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database admin password: %s", err)) + } + } + + if d.HasChange("whitelist") { + oldList, newList := d.GetChange("whitelist") + if oldList == nil { + oldList = new(schema.Set) + } + if newList == nil { + newList = new(schema.Set) + } + os := oldList.(*schema.Set) + ns := newList.(*schema.Set) + remove := os.Difference(ns).List() + add := ns.Difference(os).List() + + if len(add) > 0 { + for _, entry := range add { + newEntry := entry.(map[string]interface{}) + wlEntry := icdv4.WhitelistEntry{ + Address: newEntry["address"].(string), + Description: newEntry["description"].(string), + } + whitelistReq := icdv4.WhitelistReq{ + WhitelistEntry: wlEntry, + } + task, err := icdClient.Whitelists().CreateWhitelist(icdId, whitelistReq) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating database whitelist entry %v : %s", wlEntry.Address, err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) whitelist create task to complete for entry %s : %s", icdId, wlEntry.Address, err)) + } + + } + + } + + if len(remove) > 0 { + for _, entry := range remove { + newEntry := entry.(map[string]interface{}) + wlEntry := icdv4.WhitelistEntry{ + Address: newEntry["address"].(string), + Description: newEntry["description"].(string), + } + ipAddress := wlEntry.Address + task, err := icdClient.Whitelists().DeleteWhitelist(icdId, ipAddress) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting database whitelist entry: %s", err)) + } + _, err = waitForDatabaseTaskComplete(task.Id, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) whitelist delete task to complete for ipAddress %s : %s", icdId, ipAddress, err)) + } + + } + } + } + + if d.HasChange("users") { + cloudDatabasesClient, err := meta.(conns.ClientSession).CloudDatabasesV5() + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting database client settings: %s", err)) + } + + oldUsers, newUsers := d.GetChange("users") + userChanges := make(map[string]*userChange) + userKey := func(raw map[string]interface{}) string { + if raw["role"].(string) != "" { + return fmt.Sprintf("%s-%s-%s", raw["type"].(string), raw["role"].(string), raw["name"].(string)) + } else { + return fmt.Sprintf("%s-%s", raw["type"].(string), raw["name"].(string)) + } + } + + for _, raw := range oldUsers.(*schema.Set).List() { + user := raw.(map[string]interface{}) + k := userKey(user) + userChanges[k] = &userChange{Old: user} + } + + for _, raw := range newUsers.(*schema.Set).List() { + user := raw.(map[string]interface{}) + k := userKey(user) + if _, ok := userChanges[k]; !ok { + userChanges[k] = &userChange{} + } + userChanges[k].New = user + } + + for _, change := range userChanges { + // Update Database User password only + if change.Old != nil && change.New != nil { + // No change + if change.Old["password"].(string) == change.New["password"].(string) { + continue + } + + passwordSettingUser := &clouddatabasesv5.APasswordSettingUser{ + Password: core.StringPtr(change.New["password"].(string)), + } + + changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + ID: &instanceID, + UserType: core.StringPtr(change.New["type"].(string)), + Username: core.StringPtr(change.New["name"].(string)), + User: passwordSettingUser, + } + + changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + + if response.StatusCode != 404 { + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %s\n%s", *changeUserPasswordOptions.Username, err, response)) + } + + taskID := *changeUserPasswordResponse.Task.ID + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) user (%s) password update task to complete: %s", instanceID, *changeUserPasswordOptions.Username, err)) + } + + continue + } + + // User not found, need to reCreate user + change.Old = nil + } + + // Delete Old User + if change.Old != nil { + deleteDatabaseUserOptions := &clouddatabasesv5.DeleteDatabaseUserOptions{ + ID: &instanceID, + UserType: core.StringPtr(change.Old["type"].(string)), + Username: core.StringPtr(change.Old["name"].(string)), + } + + deleteDatabaseUserResponse, response, err := cloudDatabasesClient.DeleteDatabaseUser(deleteDatabaseUserOptions) + + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] DeleteDatabaseUser (%s) failed %s\n%s", *deleteDatabaseUserOptions.Username, err, response)) + + } + + taskID := *deleteDatabaseUserResponse.Task.ID + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) user (%s) delete task to complete: %s", icdId, *deleteDatabaseUserOptions.Username, err)) + } + } + + // Create New User + if change.New != nil { + userEntry := &clouddatabasesv5.User{ + Username: core.StringPtr(change.New["name"].(string)), + Password: core.StringPtr(change.New["password"].(string)), + } + + // User Role only for ops_manager user type + if change.New["type"].(string) == "ops_manager" && change.New["role"].(string) != "" { + userEntry.Role = core.StringPtr(change.New["role"].(string)) + } + + createDatabaseUserOptions := &clouddatabasesv5.CreateDatabaseUserOptions{ + ID: &instanceID, + UserType: core.StringPtr(change.New["type"].(string)), + User: userEntry, + } + + createDatabaseUserResponse, response, err := cloudDatabasesClient.CreateDatabaseUser(createDatabaseUserOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] CreateDatabaseUser (%s) failed %s\n%s", *userEntry.Username, err, response)) + } + + taskID := *createDatabaseUserResponse.Task.ID + _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for database (%s) user (%s) create task to complete: %s", instanceID, *userEntry.Username, err)) + } + } + } + } + + return resourceIBMDatabaseInstanceRead(context, d, meta) +} + +func horizontalScale(d *schema.ResourceData, meta interface{}, icdClient icdv4.ICDServiceAPI) error { + params := icdv4.GroupReq{} + + icdId := flex.EscapeUrlParm(d.Id()) + + members := d.Get("node_count").(int) + membersReq := icdv4.MembersReq{AllocationCount: members} + params.GroupBdy.Members = &membersReq + + _, err := icdClient.Groups().UpdateGroup(icdId, "member", params) + + if err != nil { + return fmt.Errorf("[ERROR] Error updating database scaling group: %s", err) + } + + // ScaleOut is handled with an ICD API call, however, the check is is on the instance status + _, err = waitForDatabaseInstanceUpdate(d, meta) + if err != nil { + return fmt.Errorf( + "[ERROR] Error waiting for database (%s) horizontal scale to complete: %s", d.Id(), err) + } + + return nil +} + +func getConnectionString(d *schema.ResourceData, userName, connectionEndpoint string, meta interface{}) (flex.CsEntry, error) { + csEntry := flex.CsEntry{} + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return csEntry, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) + } + + icdId := d.Id() + connection, err := icdClient.Connections().GetConnection(icdId, userName, connectionEndpoint) + if err != nil { + return csEntry, fmt.Errorf("[ERROR] Error getting database user connection string via ICD API: %s", err) + } + + service := d.Get("service") + dbConnection := icdv4.Uri{} + var cassandraConnection icdv4.CassandraUri + + switch service { + case "databases-for-postgresql": + dbConnection = connection.Postgres + case "databases-for-redis": + dbConnection = connection.Rediss + case "databases-for-mongodb": + dbConnection = connection.Mongo + case "databases-for-mysql": + dbConnection = connection.Mysql + case "databases-for-elasticsearch": + dbConnection = connection.Https + case "databases-for-cassandra": + cassandraConnection = connection.Secure + case "databases-for-etcd": + dbConnection = connection.Grpc + case "messages-for-rabbitmq": + dbConnection = connection.Amqps + case "databases-for-enterprisedb": + dbConnection = connection.Postgres + default: + return csEntry, fmt.Errorf("[ERROR] Unrecognised database type during connection string lookup: %s", service) + } + + if !reflect.DeepEqual(cassandraConnection, icdv4.CassandraUri{}) { + csEntry = flex.CsEntry{ + Name: userName, + Hosts: cassandraConnection.Hosts, + BundleName: cassandraConnection.Bundle.Name, + BundleBase64: cassandraConnection.Bundle.BundleBase64, + } + } else { + csEntry = flex.CsEntry{ + Name: userName, + Password: "", + // Populate only first 'composed' connection string as an example + Composed: dbConnection.Composed[0], + CertName: dbConnection.Certificate.Name, + CertBase64: dbConnection.Certificate.CertificateBase64, + Hosts: dbConnection.Hosts, + Scheme: dbConnection.Scheme, + Path: dbConnection.Path, + QueryOptions: dbConnection.QueryOptions.(map[string]interface{}), + } + + // Postgres DB name is of type string, Redis is json.Number, others are nil + if dbConnection.Database != nil { + switch v := dbConnection.Database.(type) { + default: + return csEntry, fmt.Errorf("Unexpected data type: %T", v) + case json.Number: + csEntry.Database = dbConnection.Database.(json.Number).String() + case string: + csEntry.Database = dbConnection.Database.(string) + } + } else { + csEntry.Database = "" + } + } + + return csEntry, nil +} + +func resourceIBMDatabaseInstanceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return diag.FromErr(err) + } + id := d.Id() + recursive := true + deleteReq := rc.DeleteResourceInstanceOptions{ + Recursive: &recursive, + ID: &id, + } + response, err := rsConClient.DeleteResourceInstance(&deleteReq) + if err != nil { + // If prior delete occurs, instance is not immediately deleted, but remains in "removed" state" + // RC 410 with "Gone" returned as error + if strings.Contains(err.Error(), "Gone") || + strings.Contains(err.Error(), "status code: 410") { + log.Printf("[WARN] Resource instance already deleted %s\n ", err) + err = nil + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting resource instance: %s %s ", err, response)) + } + } + + _, err = waitForDatabaseInstanceDelete(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf( + "[ERROR] Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err)) + } + + d.SetId("") + + return nil +} +func resourceIBMDatabaseInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error getting database: %s %s", err, response) + } + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, databaseInstanceReclamation)) { + log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") + d.SetId("") + return false, nil + } + + return *instance.ID == instanceID, nil +} + +func waitForICDReady(meta interface{}, instanceID string) error { + icdId := flex.EscapeUrlParm(instanceID) + icdClient, clientErr := meta.(conns.ClientSession).ICDAPI() + if clientErr != nil { + return fmt.Errorf("[ERROR] Error getting database client settings: %s", clientErr) + } + + // Wait for ICD Interface + err := retry(func() (err error) { + _, cdbErr := icdClient.Cdbs().GetCdb(icdId) + if cdbErr != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return fmt.Errorf("[ERROR] The database instance was not found in the region set for the Provider, or the default of us-south. Specify the correct region in the provider definition, or create a provider alias for the correct region. %v", err) + } + return fmt.Errorf("[ERROR] Error getting database config for: %s with error %s\n", icdId, err) + } + return nil + }) + if err != nil { + return err + } + return nil +} + +func waitForDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}, instanceID string) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceProvisioningStatus}, + Target: []string{databaseInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil || instance == nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %s %s", d.Id(), err, response) + } + return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) + } + if *instance.State == databaseInstanceFailStatus { + return *instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %s %s", d.Id(), err, response) + } + return *instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + waitErr := waitForICDReady(meta, instanceID) + if waitErr != nil { + return false, fmt.Errorf("[ERROR] Error ICD interface not ready after create: %s with error %s\n", instanceID, waitErr) + + } + + return stateConf.WaitForState() +} + +func waitForDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + + stateConf := &resource.StateChangeConf{ + Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus}, + Target: []string{databaseInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %s %s", d.Id(), err, response) + } + return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) + } + if *instance.State == databaseInstanceFailStatus { + return *instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %s %s", d.Id(), err, response) + } + return *instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + waitErr := waitForICDReady(meta, instanceID) + if waitErr != nil { + return false, fmt.Errorf("[ERROR] Error ICD interface not ready after update: %s with error %s\n", instanceID, waitErr) + + } + + return stateConf.WaitForState() +} + +func waitForDatabaseTaskComplete(taskId string, d *schema.ResourceData, meta interface{}, t time.Duration) (bool, error) { + icdClient, err := meta.(conns.ClientSession).ICDAPI() + if err != nil { + return false, fmt.Errorf("[ERROR] Error getting database client settings: %s", err) + } + delayDuration := 5 * time.Second + + timeout := time.After(t) + delay := time.Tick(delayDuration) + innerTask := icdv4.Task{} + + for { + select { + case <-timeout: + return false, fmt.Errorf("[Error] Time out waiting for database task to complete") + case <-delay: + innerTask, err = icdClient.Tasks().GetTask(flex.EscapeUrlParm(taskId)) + if err != nil { + return false, fmt.Errorf("[ERROR] The ICD Get task on database update errored: %v", err) + } + if innerTask.Status == "failed" { + return false, fmt.Errorf("[Error] Database task failed") + } + // Completed status could be returned as "" due to interaction between bluemix-go and icd task response + // Otherwise Running an queued + if innerTask.Status == "completed" || innerTask.Status == "" { + return true, nil + } + } + } +} + +func waitForDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + stateConf := &resource.StateChangeConf{ + Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, + Target: []string{databaseInstanceRemovedStatus, databaseInstanceReclamation}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return instance, databaseInstanceSuccessStatus, nil + } + return nil, "", fmt.Errorf("[ERROR] GetResourceInstance on %s failed with error %s %s", d.Id(), err, response) + } + if *instance.State == databaseInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %s %s", d.Id(), err, response) + } + return *instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func filterDatabaseDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { + supportedDeployments := []models.ServiceDeployment{} + supportedLocations := make(map[string]bool) + for _, d := range deployments { + if d.Metadata.RCCompatible { + deploymentLocation := d.Metadata.Deployment.Location + supportedLocations[deploymentLocation] = true + if deploymentLocation == location { + supportedDeployments = append(supportedDeployments, d) + } + } + } + return supportedDeployments, supportedLocations +} + +func expandICDAutoScalingGroup(d *schema.ResourceData, asRecord interface{}, asType string) (asgBody icdv4.ASGBody, err error) { + + asgRecord := asRecord.([]interface{})[0].(map[string]interface{}) + asgCapacity := icdv4.CapacityBody{} + if _, ok := asgRecord["capacity_enabled"]; ok { + asgCapacity.Enabled = asgRecord["capacity_enabled"].(bool) + asgBody.Scalers.Capacity = &asgCapacity + } + if _, ok := asgRecord["free_space_less_than_percent"]; ok { + asgCapacity.FreeSpaceLessThanPercent = asgRecord["free_space_less_than_percent"].(int) + asgBody.Scalers.Capacity = &asgCapacity + } + + // IO Payload + asgIO := icdv4.IOBody{} + if _, ok := asgRecord["io_enabled"]; ok { + asgIO.Enabled = asgRecord["io_enabled"].(bool) + asgBody.Scalers.IO = &asgIO + } + if _, ok := asgRecord["io_over_period"]; ok { + asgIO.OverPeriod = asgRecord["io_over_period"].(string) + asgBody.Scalers.IO = &asgIO + } + if _, ok := asgRecord["io_above_percent"]; ok { + asgIO.AbovePercent = asgRecord["io_above_percent"].(int) + asgBody.Scalers.IO = &asgIO + } + + // Rate Payload + asgRate := icdv4.RateBody{} + if _, ok := asgRecord["rate_increase_percent"]; ok { + asgRate.IncreasePercent = asgRecord["rate_increase_percent"].(int) + asgBody.Rate = asgRate + } + if _, ok := asgRecord["rate_period_seconds"]; ok { + asgRate.PeriodSeconds = asgRecord["rate_period_seconds"].(int) + asgBody.Rate = asgRate + } + if _, ok := asgRecord["rate_limit_mb_per_member"]; ok { + asgRate.LimitMBPerMember = asgRecord["rate_limit_mb_per_member"].(int) + asgBody.Rate = asgRate + } + if _, ok := asgRecord["rate_limit_count_per_member"]; ok { + asgRate.LimitCountPerMember = asgRecord["rate_limit_count_per_member"].(int) + asgBody.Rate = asgRate + } + if _, ok := asgRecord["rate_units"]; ok { + asgRate.Units = asgRecord["rate_units"].(string) + asgBody.Rate = asgRate + } + + return asgBody, nil +} + +func flattenICDAutoScalingGroup(autoScalingGroup icdv4.AutoscalingGetGroup) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + + memorys := make([]map[string]interface{}, 0) + memory := make(map[string]interface{}) + + if autoScalingGroup.Autoscaling.Memory.Scalers.IO != nil { + memoryIO := *autoScalingGroup.Autoscaling.Memory.Scalers.IO + memory["io_enabled"] = memoryIO.Enabled + memory["io_over_period"] = memoryIO.OverPeriod + memory["io_above_percent"] = memoryIO.AbovePercent + } + if &autoScalingGroup.Autoscaling.Memory.Rate != nil { + ip, _ := autoScalingGroup.Autoscaling.Memory.Rate.IncreasePercent.Float64() + memory["rate_increase_percent"] = int(ip) + memory["rate_period_seconds"] = autoScalingGroup.Autoscaling.Memory.Rate.PeriodSeconds + lmp, _ := autoScalingGroup.Autoscaling.Memory.Rate.LimitMBPerMember.Float64() + memory["rate_limit_mb_per_member"] = int(lmp) + memory["rate_units"] = autoScalingGroup.Autoscaling.Memory.Rate.Units + } + memorys = append(memorys, memory) + + cpus := make([]map[string]interface{}, 0) + cpu := make(map[string]interface{}) + + if &autoScalingGroup.Autoscaling.CPU.Rate != nil { + + ip, _ := autoScalingGroup.Autoscaling.CPU.Rate.IncreasePercent.Float64() + cpu["rate_increase_percent"] = int(ip) + cpu["rate_period_seconds"] = autoScalingGroup.Autoscaling.CPU.Rate.PeriodSeconds + cpu["rate_limit_count_per_member"] = autoScalingGroup.Autoscaling.CPU.Rate.LimitCountPerMember + cpu["rate_units"] = autoScalingGroup.Autoscaling.CPU.Rate.Units + } + cpus = append(cpus, cpu) + + disks := make([]map[string]interface{}, 0) + disk := make(map[string]interface{}) + if autoScalingGroup.Autoscaling.Disk.Scalers.Capacity != nil { + diskCapacity := *autoScalingGroup.Autoscaling.Disk.Scalers.Capacity + disk["capacity_enabled"] = diskCapacity.Enabled + disk["free_space_less_than_percent"] = diskCapacity.FreeSpaceLessThanPercent + } + if autoScalingGroup.Autoscaling.Disk.Scalers.IO != nil { + diskIO := *autoScalingGroup.Autoscaling.Disk.Scalers.IO + disk["io_enabled"] = diskIO.Enabled + disk["io_over_period"] = diskIO.OverPeriod + disk["io_above_percent"] = diskIO.AbovePercent + } + if &autoScalingGroup.Autoscaling.Disk.Rate != nil { + + ip, _ := autoScalingGroup.Autoscaling.Disk.Rate.IncreasePercent.Float64() + disk["rate_increase_percent"] = int(ip) + disk["rate_period_seconds"] = autoScalingGroup.Autoscaling.Disk.Rate.PeriodSeconds + lpm, _ := autoScalingGroup.Autoscaling.Disk.Rate.LimitMBPerMember.Float64() + disk["rate_limit_mb_per_member"] = int(lpm) + disk["rate_units"] = autoScalingGroup.Autoscaling.Disk.Rate.Units + } + + disks = append(disks, disk) + as := map[string]interface{}{ + "memory": memorys, + "cpu": cpus, + "disk": disks, + } + result = append(result, as) + return result +} + +func normalizeGroups(_groups []clouddatabasesv5.Group) (groups []Group) { + groups = make([]Group, len(_groups)) + for _, g := range _groups { + group := Group{ID: *g.ID} + + group.Members = &GroupResource{ + Units: *g.Members.Units, + Allocation: int(*g.Members.AllocationCount), + Minimum: int(*g.Members.MinimumCount), + Maximum: int(*g.Members.MaximumCount), + StepSize: int(*g.Members.StepSizeCount), + IsAdjustable: *g.Members.IsAdjustable, + IsOptional: *g.Members.IsOptional, + CanScaleDown: *g.Members.CanScaleDown, + } + + group.Memory = &GroupResource{ + Units: *g.Memory.Units, + Allocation: int(*g.Memory.AllocationMb), + Minimum: int(*g.Memory.MinimumMb), + Maximum: int(*g.Memory.MaximumMb), + StepSize: int(*g.Memory.StepSizeMb), + IsAdjustable: *g.Memory.IsAdjustable, + IsOptional: *g.Memory.IsOptional, + CanScaleDown: *g.Memory.CanScaleDown, + } + + group.Disk = &GroupResource{ + Units: *g.Disk.Units, + Allocation: int(*g.Disk.AllocationMb), + Minimum: int(*g.Disk.MinimumMb), + Maximum: int(*g.Disk.MaximumMb), + StepSize: int(*g.Disk.StepSizeMb), + IsAdjustable: *g.Disk.IsAdjustable, + IsOptional: *g.Disk.IsOptional, + CanScaleDown: *g.Disk.CanScaleDown, + } + + group.CPU = &GroupResource{ + Units: *g.CPU.Units, + Allocation: int(*g.CPU.AllocationCount), + Minimum: int(*g.CPU.MinimumCount), + Maximum: int(*g.CPU.MaximumCount), + StepSize: int(*g.CPU.StepSizeCount), + IsAdjustable: *g.CPU.IsAdjustable, + IsOptional: *g.CPU.IsOptional, + CanScaleDown: *g.CPU.CanScaleDown, + } + + groups = append(groups, group) + } + + return groups +} + +func expandGroups(_groups []interface{}) []*Group { + if len(_groups) == 0 { + return nil + } + + groups := make([]*Group, 0, len(_groups)) + + for _, groupRaw := range _groups { + if tfGroup, ok := groupRaw.(map[string]interface{}); ok { + group := Group{ID: tfGroup["group_id"].(string)} + + if membersSet, ok := tfGroup["members"].(*schema.Set); ok { + members := membersSet.List() + if len(members) != 0 { + group.Members = &GroupResource{Allocation: members[0].(map[string]interface{})["allocation_count"].(int)} + } + } + + if memorySet, ok := tfGroup["memory"].(*schema.Set); ok { + memory := memorySet.List() + if len(memory) != 0 { + group.Memory = &GroupResource{Allocation: memory[0].(map[string]interface{})["allocation_mb"].(int)} + } + } + + if diskSet, ok := tfGroup["disk"].(*schema.Set); ok { + disk := diskSet.List() + if len(disk) != 0 { + group.Disk = &GroupResource{Allocation: disk[0].(map[string]interface{})["allocation_mb"].(int)} + } + } + + if cpuSet, ok := tfGroup["cpu"].(*schema.Set); ok { + cpu := cpuSet.List() + if len(cpu) != 0 { + group.CPU = &GroupResource{Allocation: cpu[0].(map[string]interface{})["allocation_count"].(int)} + } + } + + groups = append(groups, &group) + } + } + + // analytics must be created before bi_connector + sortPriority := map[string]int{ + "members": 10, + "analytics": 2, + "bi_connector": 1, + } + + sort.SliceStable(groups, func(i, j int) bool { + return sortPriority[groups[i].ID] > sortPriority[groups[j].ID] + }) + + return groups +} + +func checkV5Groups(_ context.Context, diff *schema.ResourceDiff, meta interface{}) (err error) { + instanceID := diff.Id() + service := diff.Get("service").(string) + plan := diff.Get("plan").(string) + + if group, ok := diff.GetOk("group"); ok { + var currentGroups []Group + var groupList []clouddatabasesv5.Group + var groupIds []string + + if instanceID != "" { + groupList, err = getGroups(instanceID, meta) + } else { + groupList, err = getDefaultScalingGroups(service, plan, meta) + } + + if err != nil { + return err + } + + currentGroups = normalizeGroups(groupList) + + tfGroups := expandGroups(group.(*schema.Set).List()) + + // Check group_ids are unique + groupIds = make([]string, 0, len(tfGroups)) + for _, g := range tfGroups { + groupIds = append(groupIds, g.ID) + } + + for n1, i1 := range groupIds { + for n2, i2 := range groupIds { + if i1 == i2 && n1 != n2 { + return fmt.Errorf("found 2 or more instances of group with group_id %v", i1) + } + } + } + + // Get default or current group scaling values + for _, group := range tfGroups { + if group == nil { + break + } + groupId := group.ID + var groupDefaults *Group + for _, g := range currentGroups { + if g.ID == groupId { + groupDefaults = &g + break + } + } + + // set current nodeCount + nodeCount := groupDefaults.Members.Allocation + + if group.Members != nil { + err = checkGroupScaling(groupId, "members", group.Members.Allocation, groupDefaults.Members, 1) + if err != nil { + return err + } + } + + if group.Memory != nil { + err = checkGroupScaling(groupId, "memory", group.Memory.Allocation, groupDefaults.Memory, nodeCount) + if err != nil { + return err + } + } + + if group.Disk != nil { + err = checkGroupScaling(groupId, "disk", group.Disk.Allocation, groupDefaults.Disk, nodeCount) + if err != nil { + return err + } + } + + if group.CPU != nil { + err = checkGroupScaling(groupId, "cpu", group.CPU.Allocation, groupDefaults.CPU, nodeCount) + if err != nil { + return err + } + } + } + } + + return nil +} diff --git a/ibm/service/database/resource_ibm_database_cassandra_test.go b/ibm/service/database/resource_ibm_database_cassandra_test.go new file mode 100644 index 000000000..c59e94464 --- /dev/null +++ b/ibm/service/database/resource_ibm_database_cassandra_test.go @@ -0,0 +1,782 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMCassandraDatabaseInstanceBasic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Datastax-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceCassandraBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "36864"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "38400"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "36864"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMDatabaseInstance_Cassandra_Node(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Datastax-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceCassandraNodeBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraNodeFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12416"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraNodeReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraNodeScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "4"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + //{ + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + //}, + }, + }) +} + +func TestAccIBMDatabaseInstance_Cassandra_Group(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Datastax-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceCassandraGroupBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "36864"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "18"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraGroupFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12416"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "37248"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "18"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraGroupReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "36864"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "18"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceCassandraGroupScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "4"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "12288"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "20480"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "6"), + resource.TestCheckResourceAttr(name, "groups.0.count", "4"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "49152"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "81920"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "24"), + resource.TestCheckResourceAttr(name, "groups.1.count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + }, + }) +} + +// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests + +func TestAccIBMDatabaseInstanceCassandraImport(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Datastax-%d", acctest.RandIntRange(10, 100)) + //serviceName := "test_acc" + resourceName := "ibm_database." + serviceName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceCassandraImport(databaseResourceGroup, serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "databases-for-cassandra"), + resource.TestCheckResourceAttr(resourceName, "plan", "enterprise"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "plan_validation"}, + }, + }, + }) +} + +// func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) etc in resource_ibm_database_postgresql_test.go + +func testAccCheckIBMDatabaseInstanceCassandraBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 36864 + members_disk_allocation_mb = 61440 + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 38400 + members_disk_allocation_mb = 61440 + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 36864 + members_disk_allocation_mb = 61440 + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraNodeBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 12288 + node_disk_allocation_mb = 20480 + node_cpu_allocation_count = 6 + + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraNodeFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + version = "5.1" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 12416 + node_disk_allocation_mb = 20480 + node_cpu_allocation_count = 6 + + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraNodeReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + version = "5.1" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 12288 + node_disk_allocation_mb = 20480 + node_cpu_allocation_count = 6 + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraNodeScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + node_count = 4 + node_memory_allocation_mb = 12288 + node_disk_allocation_mb = 20480 + node_cpu_allocation_count = 6 + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraGroupBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + version = "5.1" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 12288 + } + disk { + allocation_mb = 20480 + } + cpu { + allocation_count = 6 + } + } + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraGroupFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + version = "5.1" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 12416 + } + disk { + allocation_mb = 20480 + } + cpu { + allocation_count = 6 + } + } + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraGroupReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + version = "5.1" + location = "%[3]s" + adminpassword = "password12" + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 12288 + } + disk { + allocation_mb = 20480 + } + cpu { + allocation_count = 6 + } + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraGroupScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + version = "5.1" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 4 + } + memory { + allocation_mb = 12288 + } + disk { + allocation_mb = 20480 + } + cpu { + allocation_count = 6 + } + } + + group { + group_id = "search" + members { + allocation_count = 3 + } + } + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceCassandraImport(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-cassandra" + plan = "enterprise" + location = "%[3]s" + + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} diff --git a/ibm/resource_ibm_database_edb_test.go b/ibm/service/database/resource_ibm_database_edb_test.go similarity index 91% rename from ibm/resource_ibm_database_edb_test.go rename to ibm/service/database/resource_ibm_database_edb_test.go index ee63dc6c4..e6603953c 100644 --- a/ibm/resource_ibm_database_edb_test.go +++ b/ibm/service/database/resource_ibm_database_edb_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIBMEDBDatabaseInstanceBasic(t *testing.T) { name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -32,7 +34,7 @@ func TestAccIBMEDBDatabaseInstanceBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-enterprisedb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "adminuser", "admin"), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), @@ -53,7 +55,7 @@ func TestAccIBMEDBDatabaseInstanceBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-enterprisedb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "92160"), resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), @@ -76,7 +78,7 @@ func TestAccIBMEDBDatabaseInstanceBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-enterprisedb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "92160"), resource.TestCheckResourceAttr(name, "whitelist.#", "0"), @@ -107,7 +109,7 @@ func testAccCheckIBMDatabaseInstanceEDBBasic(databaseResourceGroup string, name name = "%[2]s" service = "databases-for-enterprisedb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 61440 @@ -126,7 +128,7 @@ func testAccCheckIBMDatabaseInstanceEDBBasic(databaseResourceGroup string, name delete = "15m" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceEDBFullyspecified(databaseResourceGroup string, name string) string { @@ -140,7 +142,7 @@ func testAccCheckIBMDatabaseInstanceEDBFullyspecified(databaseResourceGroup stri name = "%[2]s" service = "databases-for-enterprisedb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 6144 members_disk_allocation_mb = 92160 @@ -169,7 +171,7 @@ func testAccCheckIBMDatabaseInstanceEDBFullyspecified(databaseResourceGroup stri delete = "15m" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceEDBReduced(databaseResourceGroup string, name string) string { @@ -183,7 +185,7 @@ func testAccCheckIBMDatabaseInstanceEDBReduced(databaseResourceGroup string, nam name = "%[2]s" service = "databases-for-enterprisedb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 92160 @@ -195,5 +197,5 @@ func testAccCheckIBMDatabaseInstanceEDBReduced(databaseResourceGroup string, nam delete = "15m" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } diff --git a/ibm/service/database/resource_ibm_database_elasticsearch_test.go b/ibm/service/database/resource_ibm_database_elasticsearch_test.go new file mode 100644 index 000000000..288d27453 --- /dev/null +++ b/ibm/service/database/resource_ibm_database_elasticsearch_test.go @@ -0,0 +1,827 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDatabaseInstance_Elasticsearch_Basic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "15360"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "18432"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "18432"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchGroupMigration(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "18432"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + // { + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + // }, + }, + }) +} + +func TestAccIBMDatabaseInstance_Elasticsearch_Node(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "5120"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchNodeScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "4"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + //{ + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + //}, + }, + }) +} + +func TestAccIBMDatabaseInstance_Elasticsearch_Group(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchGroupBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "5120"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.database", ""), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchGroupFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "18432"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "9"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchGroupReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "18432"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "9"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchGroupScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "4"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.count", "4"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "4096"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "24576"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "12"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + ), + }, + //{ + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + //}, + }, + }) +} + +// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests + +func TestAccIBMDatabaseInstanceElasticsearchImport(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) + //serviceName := "test_acc" + resourceName := "ibm_database." + serviceName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceElasticsearchImport(databaseResourceGroup, serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "databases-for-elasticsearch"), + resource.TestCheckResourceAttr(resourceName, "plan", "standard"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "plan_validation"}, + }, + }, + }) +} + +// func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) etc in resource_ibm_database_postgresql_test.go + +func testAccCheckIBMDatabaseInstanceElasticsearchBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 3072 + members_disk_allocation_mb = 15360 + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 6144 + members_disk_allocation_mb = 18432 + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 3072 + members_disk_allocation_mb = 18432 + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchGroupMigration(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 6144 + } + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchNodeBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 5120 + node_cpu_allocation_count = 3 + + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchNodeFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 6144 + node_cpu_allocation_count = 3 + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchNodeReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 6144 + node_cpu_allocation_count = 3 + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchNodeScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 4 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 6144 + node_cpu_allocation_count = 3 + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchGroupBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 5120 + } + cpu { + allocation_count = 3 + } + } + + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchGroupFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 6144 + } + cpu { + allocation_count = 3 + } + } + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchGroupReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 6144 + } + cpu { + allocation_count = 3 + } + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchGroupScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + members { + allocation_count = 4 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 6144 + } + cpu { + allocation_count = 3 + } + } + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceElasticsearchImport(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-elasticsearch" + plan = "standard" + location = "%[3]s" + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + + `, databaseResourceGroup, name, acc.IcdDbRegion) +} diff --git a/ibm/resource_ibm_database_etcd_test.go b/ibm/service/database/resource_ibm_database_etcd_test.go similarity index 88% rename from ibm/resource_ibm_database_etcd_test.go rename to ibm/service/database/resource_ibm_database_etcd_test.go index 38400ecff..a408753eb 100644 --- a/ibm/resource_ibm_database_etcd_test.go +++ b/ibm/service/database/resource_ibm_database_etcd_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIBMDatabaseInstance_Etcd_Basic(t *testing.T) { name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -32,7 +34,7 @@ func TestAccIBMDatabaseInstance_Etcd_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-etcd"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "adminuser", "root"), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), @@ -52,7 +54,7 @@ func TestAccIBMDatabaseInstance_Etcd_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-etcd"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "64512"), resource.TestCheckResourceAttr(name, "whitelist.#", "2"), @@ -66,7 +68,7 @@ func TestAccIBMDatabaseInstance_Etcd_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-etcd"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "64512"), resource.TestCheckResourceAttr(name, "whitelist.#", "0"), @@ -89,8 +91,8 @@ func TestAccIBMDatabaseInstanceEtcdImport(t *testing.T) { resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -100,7 +102,7 @@ func TestAccIBMDatabaseInstanceEtcdImport(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", serviceName), resource.TestCheckResourceAttr(resourceName, "service", "databases-for-etcd"), resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), ), }, { @@ -128,7 +130,7 @@ func testAccCheckIBMDatabaseInstanceEtcdBasic(databaseResourceGroup string, name name = "%[2]s" service = "databases-for-etcd" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 61440 @@ -141,7 +143,7 @@ func testAccCheckIBMDatabaseInstanceEtcdBasic(databaseResourceGroup string, name description = "desc1" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceEtcdFullyspecified(databaseResourceGroup string, name string) string { @@ -156,7 +158,7 @@ func testAccCheckIBMDatabaseInstanceEtcdFullyspecified(databaseResourceGroup str name = "%[2]s" service = "databases-for-etcd" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 6144 members_disk_allocation_mb = 64512 @@ -178,7 +180,7 @@ func testAccCheckIBMDatabaseInstanceEtcdFullyspecified(databaseResourceGroup str } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceEtcdReduced(databaseResourceGroup string, name string) string { @@ -193,12 +195,12 @@ func testAccCheckIBMDatabaseInstanceEtcdReduced(databaseResourceGroup string, na name = "%[2]s" service = "databases-for-etcd" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 64512 } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceEtcdImport(databaseResourceGroup string, name string) string { @@ -213,7 +215,7 @@ func testAccCheckIBMDatabaseInstanceEtcdImport(databaseResourceGroup string, nam name = "%[2]s" service = "databases-for-etcd" plan = "standard" - location = "us-south" + location = "%[3]s" } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } diff --git a/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go b/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go new file mode 100644 index 000000000..29cf99dc3 --- /dev/null +++ b/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go @@ -0,0 +1,294 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "regexp" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMMongoDBEnterpriseDatabaseInstanceBasic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-mongoEnterprise-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "43008"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "86016"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "122880"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "users.1.type", "ops_manager"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "mongodb"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "43008"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "122880"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "plan_validation", "adminpassword", "connectionstrings.0.queryoptions"}, + }, + }, + }) +} + +func TestAccIBMMongoDBEnterpriseDatabaseInstanceGroupBasic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-mongoEnterprise-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceMongoDBEnterpriseGroupBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), + resource.TestCheckResourceAttr(name, "plan", "enterprise"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "43008"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.name", "admin"), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.1.count", "1"), + resource.TestCheckResourceAttr(name, "groups.2.count", "1"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mongodb" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_disk_allocation_mb = 61440 + members_memory_allocation_mb = 43008 + tags = ["one:two"] + users { + name = "user123" + password = "password12" + type = "database" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mongodb" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 86016 + members_disk_allocation_mb = 122880 + members_cpu_allocation_count = 27 + tags = ["one:two"] + users { + name = "user123" + password = "password12" + type = "database" + } + users { + name = "user124" + password = "password12$password" + type = "ops_manager" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mongodb" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + members_disk_allocation_mb = 122880 + members_memory_allocation_mb = 43008 + service_endpoints = "public" + tags = ["one:two"] + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceMongoDBEnterpriseGroupBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mongodb" + plan = "enterprise" + location = "%[3]s" + adminpassword = "password12" + tags = ["one:two"] + + group { + group_id = "member" + + memory { + allocation_mb = 14336 + } + disk { + allocation_mb = 20480 + } + } + + group { + group_id = "bi_connector" + + members { + allocation_count = 1 + } + } + + group { + group_id = "analytics" + + members { + allocation_count = 1 + } + } + + timeouts { + create = "4h" + update = "4h" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} diff --git a/ibm/resource_ibm_database_mongodb_test.go b/ibm/service/database/resource_ibm_database_mongodb_test.go similarity index 89% rename from ibm/resource_ibm_database_mongodb_test.go rename to ibm/service/database/resource_ibm_database_mongodb_test.go index b6c4ca42e..3e88e53f2 100644 --- a/ibm/resource_ibm_database_mongodb_test.go +++ b/ibm/service/database/resource_ibm_database_mongodb_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIBMDatabaseInstanceMongodbBasic(t *testing.T) { name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -32,7 +34,7 @@ func TestAccIBMDatabaseInstanceMongodbBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "adminuser", "admin"), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "30720"), @@ -51,7 +53,7 @@ func TestAccIBMDatabaseInstanceMongodbBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "30720"), resource.TestCheckResourceAttr(name, "whitelist.#", "2"), @@ -68,7 +70,7 @@ func TestAccIBMDatabaseInstanceMongodbBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-mongodb"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "30720"), resource.TestCheckResourceAttr(name, "whitelist.#", "0"), @@ -96,8 +98,8 @@ func TestAccIBMDatabaseInstanceMongodbImport(t *testing.T) { resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -107,7 +109,7 @@ func TestAccIBMDatabaseInstanceMongodbImport(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", serviceName), resource.TestCheckResourceAttr(resourceName, "service", "databases-for-mongodb"), resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), ), }, { @@ -132,7 +134,7 @@ func testAccCheckIBMDatabaseInstanceMongodbBasic(databaseResourceGroup string, n name = "%[2]s" service = "databases-for-mongodb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 30720 @@ -145,7 +147,7 @@ func testAccCheckIBMDatabaseInstanceMongodbBasic(databaseResourceGroup string, n description = "desc1" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceMongodbFullyspecified(databaseResourceGroup string, name string) string { @@ -159,7 +161,7 @@ func testAccCheckIBMDatabaseInstanceMongodbFullyspecified(databaseResourceGroup name = "%[2]s" service = "databases-for-mongodb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 6144 members_disk_allocation_mb = 30720 @@ -180,7 +182,7 @@ func testAccCheckIBMDatabaseInstanceMongodbFullyspecified(databaseResourceGroup description = "desc" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceMongodbReduced(databaseResourceGroup string, name string) string { @@ -194,13 +196,13 @@ func testAccCheckIBMDatabaseInstanceMongodbReduced(databaseResourceGroup string, name = "%[2]s" service = "databases-for-mongodb" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 30720 } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceMongodbImport(databaseResourceGroup string, name string) string { @@ -215,8 +217,8 @@ func testAccCheckIBMDatabaseInstanceMongodbImport(databaseResourceGroup string, name = "%[2]s" service = "databases-for-mongodb" plan = "standard" - location = "us-south" + location = "%[3]s" } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } diff --git a/ibm/service/database/resource_ibm_database_mysql_test.go b/ibm/service/database/resource_ibm_database_mysql_test.go new file mode 100644 index 000000000..4f1cd5063 --- /dev/null +++ b/ibm/service/database/resource_ibm_database_mysql_test.go @@ -0,0 +1,158 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "regexp" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMMysqlDatabaseInstanceBasic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-mysql-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstanceMysqlBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mysql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "61440"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstanceMysqlFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-mysql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "92160"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "mysql"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "plan_validation", "adminpassword"}, + }, + }, + }) +} + +func testAccCheckIBMDatabaseInstanceMysqlBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mysql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 3072 + members_disk_allocation_mb = 61440 + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceMysqlFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-mysql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 6144 + members_disk_allocation_mb = 92160 + members_cpu_allocation_count = 12 + service_endpoints = "public-and-private" + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} diff --git a/ibm/service/database/resource_ibm_database_postgresql_test.go b/ibm/service/database/resource_ibm_database_postgresql_test.go new file mode 100644 index 000000000..082d9090d --- /dev/null +++ b/ibm/service/database/resource_ibm_database_postgresql_test.go @@ -0,0 +1,954 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package database_test + +import ( + "fmt" + "reflect" + "regexp" + "strings" + "testing" + + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" +) + +const ( + databaseInstanceSuccessStatus = "active" + databaseInstanceProvisioningStatus = "provisioning" + databaseInstanceProgressStatus = "in progress" + databaseInstanceInactiveStatus = "inactive" + databaseInstanceFailStatus = "failed" + databaseInstanceRemovedStatus = "removed" + databaseInstanceReclamation = "pending_reclamation" +) + +func TestAccIBMDatabaseInstancePostgresBasic(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "10240"), + resource.TestCheckResourceAttr(name, "members_cpu_allocation_count", "0"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "4096"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "14336"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "postgres"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + // { + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + // }, + }, + }) +} + +func TestAccIBMDatabaseInstancePostgresGroupMigration(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupDeprecated(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "groups.0.count", "2"), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "10240"), + resource.TestCheckResourceAttr(name, "members_cpu_allocation_count", "6"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupMigrated(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "groups.0.count", "2"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "10240"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "6"), + ), + }, + }, + }) +} + +func TestAccIBMDatabaseInstancePostgresNode(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresNodeBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "node_count", "2"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "5120"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresNodeFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "2"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "postgres"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresNodeReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "2"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresNodeScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "node_count", "3"), + resource.TestCheckResourceAttr(name, "node_memory_allocation_mb", "1024"), + resource.TestCheckResourceAttr(name, "node_disk_allocation_mb", "7168"), + resource.TestCheckResourceAttr(name, "node_cpu_allocation_count", "3"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + // { + // ResourceName: name, + // ImportState: true, + // ImportStateVerify: true, + // }, + }, + }) +} + +func TestAccIBMDatabaseInstancePostgresGroup(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_database." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "adminuser", "admin"), + resource.TestCheckResourceAttr(name, "groups.0.count", "2"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "10240"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "6"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "whitelist.#", "1"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.1.name", "admin"), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.1.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupFullyspecified(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "groups.0.count", "2"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2304"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "14336"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "6"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), + resource.TestCheckResourceAttr(name, "whitelist.#", "2"), + resource.TestCheckResourceAttr(name, "users.#", "2"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "3"), + resource.TestCheckResourceAttr(name, "connectionstrings.2.name", "admin"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.hosts.#", "1"), + resource.TestCheckResourceAttr(name, "connectionstrings.0.scheme", "postgres"), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certname", regexp.MustCompile("[-a-z0-9]*")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.certbase64", regexp.MustCompile("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")), + resource.TestMatchResourceAttr(name, "connectionstrings.0.database", regexp.MustCompile("[-a-z0-9]+")), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupReduced(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "groups.0.count", "2"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "14336"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "6"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + { + Config: testAccCheckIBMDatabaseInstancePostgresGroupScaleOut(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "groups.0.count", "3"), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "3072"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "21504"), + resource.TestCheckResourceAttr(name, "groups.0.cpu.0.allocation_count", "9"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + resource.TestCheckResourceAttr(name, "users.#", "0"), + resource.TestCheckResourceAttr(name, "connectionstrings.#", "1"), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + }, + }) +} + +// TestAccIBMDatabaseInstance_CreateAfterManualDestroy not required as tested by resource_instance tests + +func TestAccIBMDatabaseInstancePostgresImport(t *testing.T) { + t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + //serviceName := "test_acc" + resourceName := "ibm_database." + serviceName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup, serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(resourceName, "plan", "standard"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "plan_validation"}, + }, + }, + }) +} + +func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_database" { + continue + } + + instanceID := rs.Primary.ID + + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsContClient.GetResourceInstance(&rsInst) + if err == nil { + if !reflect.DeepEqual(instance, models.ServiceInstance{}) && *instance.State == "active" { + return fmt.Errorf("Database still exists: %s", rs.Primary.ID) + } + } else { + if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if database (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) + } + } + } + return nil +} + +func testAccDatabaseInstanceManuallyDelete(tfDatabaseID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _ = testAccDatabaseInstanceManuallyDeleteUnwrapped(s, tfDatabaseID) + return nil + } +} + +func testAccDatabaseInstanceManuallyDeleteUnwrapped(s *terraform.State, tfDatabaseID *string) error { + rsConClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instance := *tfDatabaseID + var instanceID string + if strings.HasPrefix(instance, "crn") { + instanceID = instance + } else { + _, instanceID, _ = flex.ConvertTftoCisTwoVar(instance) + } + recursive := true + deleteReq := rc.DeleteResourceInstanceOptions{ + ID: &instanceID, + Recursive: &recursive, + } + response, err := rsConClient.DeleteResourceInstance(&deleteReq) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting resource instance: %s %s", err, response) + } + + _ = &resource.StateChangeConf{ + Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, + Target: []string{databaseInstanceRemovedStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return instance, databaseInstanceSuccessStatus, nil + } + return nil, "", err + } + if *instance.State == databaseInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %v %s", instanceID, err, response) + } + return instance, *instance.State, nil + }, + Timeout: 90 * time.Second, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for resource instance (%s) to be deleted: %s", instanceID, err) + } + return nil +} + +func testAccCheckIBMDatabaseInstanceExists(n string, tfDatabaseID *string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instanceID := rs.Primary.ID + + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsContClient.GetResourceInstance(&rsInst) + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + *tfDatabaseID = "" + return nil + } + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) + } + if strings.Contains(*instance.State, "removed") { + *tfDatabaseID = "" + return nil + } + + *tfDatabaseID = instanceID + return nil + } +} + +func testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 2048 + members_disk_allocation_mb = 10240 + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 4096 + members_disk_allocation_mb = 14336 + members_cpu_allocation_count = 6 + service_endpoints = "public-and-private" + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + members_memory_allocation_mb = 2048 + members_disk_allocation_mb = 14336 + service_endpoints = "public" + tags = ["one:two"] + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupDeprecated(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + service_endpoints = "public" + tags = ["one:two"] + + members_memory_allocation_mb = 2048 + members_disk_allocation_mb = 10240 + members_cpu_allocation_count = 6 + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupMigrated(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + service_endpoints = "public" + tags = ["one:two"] + + group { + group_id = "member" + + memory { + allocation_mb = 1024 + } + + disk { + allocation_mb = 5120 + } + + cpu { + allocation_count = 3 + } + + members { + allocation_count = 2 + } + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresNodeBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 2 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 5120 + node_cpu_allocation_count = 3 + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresNodeFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 2 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 7168 + node_cpu_allocation_count = 3 + service_endpoints = "public-and-private" + tags = ["one:two"] + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresNodeReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 2 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 7168 + node_cpu_allocation_count = 3 + service_endpoints = "public" + tags = ["one:two"] + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} +func testAccCheckIBMDatabaseInstancePostgresNodeScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + node_count = 3 + node_memory_allocation_mb = 1024 + node_disk_allocation_mb = 7168 + node_cpu_allocation_count = 3 + service_endpoints = "public" + tags = ["one:two"] + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupBasic(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + tags = ["one:two"] + group { + group_id = "member" + members { + allocation_count = 2 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 5120 + } + cpu { + allocation_count = 3 + } + } + users { + name = "user123" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupFullyspecified(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + service_endpoints = "public-and-private" + tags = ["one:two"] + group { + group_id = "member" + members { + allocation_count = 2 + } + memory { + allocation_mb = 1152 + } + disk { + allocation_mb = 7168 + } + cpu { + allocation_count = 3 + } + } + users { + name = "user123" + password = "password12" + } + users { + name = "user124" + password = "password12" + } + whitelist { + address = "172.168.1.2/32" + description = "desc1" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupReduced(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + service_endpoints = "public" + tags = ["one:two"] + group { + group_id = "member" + members { + allocation_count = 2 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 7168 + } + cpu { + allocation_count = 3 + } + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresGroupScaleOut(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + group { + group_id = "member" + members { + allocation_count = 3 + } + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 7168 + } + cpu { + allocation_count = 3 + } + } + service_endpoints = "public" + tags = ["one:two"] + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + # name = "%[1]s" + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-postgresql" + plan = "standard" + location = "%[3]s" + } + `, databaseResourceGroup, name, acc.IcdDbRegion) +} diff --git a/ibm/resource_ibm_database_rabbitmq_test.go b/ibm/service/database/resource_ibm_database_rabbitmq_test.go similarity index 89% rename from ibm/resource_ibm_database_rabbitmq_test.go rename to ibm/service/database/resource_ibm_database_rabbitmq_test.go index 81e5ff1df..0c84ff85b 100644 --- a/ibm/resource_ibm_database_rabbitmq_test.go +++ b/ibm/service/database/resource_ibm_database_rabbitmq_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -20,8 +22,8 @@ func TestAccIBMDatabaseInstance_Rabbitmq_Basic(t *testing.T) { name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -31,7 +33,7 @@ func TestAccIBMDatabaseInstance_Rabbitmq_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "messages-for-rabbitmq"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "adminuser", "admin"), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "3072"), @@ -50,7 +52,7 @@ func TestAccIBMDatabaseInstance_Rabbitmq_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "messages-for-rabbitmq"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "whitelist.#", "2"), @@ -66,7 +68,7 @@ func TestAccIBMDatabaseInstance_Rabbitmq_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "messages-for-rabbitmq"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "3072"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "6144"), resource.TestCheckResourceAttr(name, "whitelist.#", "0"), @@ -94,8 +96,8 @@ func TestAccIBMDatabaseInstanceRabbitmqImport(t *testing.T) { resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -105,7 +107,7 @@ func TestAccIBMDatabaseInstanceRabbitmqImport(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", serviceName), resource.TestCheckResourceAttr(resourceName, "service", "messages-for-rabbitmq"), resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), ), }, { @@ -133,7 +135,7 @@ func testAccCheckIBMDatabaseInstanceRabbitmqBasic(databaseResourceGroup string, name = "%[2]s" service = "messages-for-rabbitmq" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 3072 @@ -146,7 +148,7 @@ func testAccCheckIBMDatabaseInstanceRabbitmqBasic(databaseResourceGroup string, description = "desc1" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRabbitmqFullyspecified(databaseResourceGroup string, name string) string { @@ -161,7 +163,7 @@ func testAccCheckIBMDatabaseInstanceRabbitmqFullyspecified(databaseResourceGroup name = "%[2]s" service = "messages-for-rabbitmq" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 6144 members_disk_allocation_mb = 6144 @@ -183,7 +185,7 @@ func testAccCheckIBMDatabaseInstanceRabbitmqFullyspecified(databaseResourceGroup } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRabbitmqReduced(databaseResourceGroup string, name string) string { @@ -198,12 +200,12 @@ func testAccCheckIBMDatabaseInstanceRabbitmqReduced(databaseResourceGroup string name = "%[2]s" service = "messages-for-rabbitmq" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 3072 members_disk_allocation_mb = 6144 } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRabbitmqImport(databaseResourceGroup string, name string) string { @@ -218,7 +220,7 @@ func testAccCheckIBMDatabaseInstanceRabbitmqImport(databaseResourceGroup string, name = "%[2]s" service = "messages-for-rabbitmq" plan = "standard" - location = "us-south" + location = "%[3]s" } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } diff --git a/ibm/resource_ibm_database_redis_test.go b/ibm/service/database/resource_ibm_database_redis_test.go similarity index 79% rename from ibm/resource_ibm_database_redis_test.go rename to ibm/service/database/resource_ibm_database_redis_test.go index 20fb0b373..483986a34 100644 --- a/ibm/resource_ibm_database_redis_test.go +++ b/ibm/service/database/resource_ibm_database_redis_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package database_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -21,8 +23,8 @@ func TestAccIBMDatabaseInstance_Redis_Basic(t *testing.T) { name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -32,7 +34,7 @@ func TestAccIBMDatabaseInstance_Redis_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-redis"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "adminuser", "admin"), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "2048"), @@ -49,8 +51,8 @@ func TestAccIBMDatabaseInstance_Redis_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-redis"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), - resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "4096"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2304"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "4096"), resource.TestCheckResourceAttr(name, "whitelist.#", "2"), ), @@ -61,12 +63,24 @@ func TestAccIBMDatabaseInstance_Redis_Basic(t *testing.T) { resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-redis"), resource.TestCheckResourceAttr(name, "plan", "standard"), - resource.TestCheckResourceAttr(name, "location", "us-south"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(name, "members_memory_allocation_mb", "2048"), resource.TestCheckResourceAttr(name, "members_disk_allocation_mb", "4096"), resource.TestCheckResourceAttr(name, "whitelist.#", "0"), ), }, + { + Config: testAccCheckIBMDatabaseInstanceRedisGroupMigration(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "databases-for-redis"), + resource.TestCheckResourceAttr(name, "plan", "standard"), + resource.TestCheckResourceAttr(name, "location", acc.IcdDbRegion), + resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2048"), + resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "4096"), + resource.TestCheckResourceAttr(name, "whitelist.#", "0"), + ), + }, }, }) } @@ -78,12 +92,11 @@ func TestAccIBMDatabaseInstanceRedisImport(t *testing.T) { databaseResourceGroup := "default" var databaseInstanceOne string serviceName := fmt.Sprintf("tf-redis-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -93,7 +106,7 @@ func TestAccIBMDatabaseInstanceRedisImport(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", serviceName), resource.TestCheckResourceAttr(resourceName, "service", "databases-for-redis"), resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", "us-south"), + resource.TestCheckResourceAttr(resourceName, "location", acc.IcdDbRegion), resource.TestCheckResourceAttr(resourceName, "auto_scaling.#", "1"), resource.TestCheckResourceAttr(resourceName, "auto_scaling.0.disk.0.capacity_enabled", "true"), resource.TestCheckResourceAttr(resourceName, "auto_scaling.0.memory.0.io_enabled", "true"), @@ -123,8 +136,8 @@ func TestAccIBMDatabaseInstanceRedisKP_Encrypt(t *testing.T) { // name := "ibm_database." + testName resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy, Steps: []resource.TestStep{ { @@ -149,13 +162,13 @@ func testAccCheckIBMDatabaseInstanceRedisBasic(databaseResourceGroup string, nam is_default = true # name = "%[1]s" } - + resource "ibm_database" "%[2]s" { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s" service = "databases-for-redis" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 2048 members_disk_allocation_mb = 2048 @@ -164,7 +177,7 @@ func testAccCheckIBMDatabaseInstanceRedisBasic(databaseResourceGroup string, nam description = "desc1" } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRedisFullyspecified(databaseResourceGroup string, name string) string { @@ -172,16 +185,16 @@ func testAccCheckIBMDatabaseInstanceRedisFullyspecified(databaseResourceGroup st data "ibm_resource_group" "test_acc" { is_default = true # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { + } + + resource "ibm_database" "%[2]s" { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s" service = "databases-for-redis" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" - members_memory_allocation_mb = 4096 + members_memory_allocation_mb = 2304 members_disk_allocation_mb = 4096 whitelist { address = "172.168.1.2/32" @@ -191,8 +204,8 @@ func testAccCheckIBMDatabaseInstanceRedisFullyspecified(databaseResourceGroup st address = "172.168.1.1/32" description = "desc" } - } - `, databaseResourceGroup, name) + } + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRedisReduced(databaseResourceGroup string, name string) string { @@ -201,18 +214,46 @@ func testAccCheckIBMDatabaseInstanceRedisReduced(databaseResourceGroup string, n is_default = true # name = "%[1]s" } - + resource "ibm_database" "%[2]s" { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s" service = "databases-for-redis" plan = "standard" - location = "us-south" + location = "%[3]s" adminpassword = "password12" members_memory_allocation_mb = 2048 members_disk_allocation_mb = 4096 } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) +} + +func testAccCheckIBMDatabaseInstanceRedisGroupMigration(databaseResourceGroup string, name string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default = true + } + + resource "ibm_database" "%[2]s" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "%[2]s" + service = "databases-for-redis" + plan = "standard" + location = "%[3]s" + adminpassword = "password12" + + group { + group_id = "member" + + memory { + allocation_mb = 1024 + } + disk { + allocation_mb = 2048 + } + } + } + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRedisImport(databaseResourceGroup string, name string) string { @@ -221,13 +262,13 @@ func testAccCheckIBMDatabaseInstanceRedisImport(databaseResourceGroup string, na is_default = true # name = "%[1]s" } - + resource "ibm_database" "%[2]s" { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s" service = "databases-for-redis" plan = "standard" - location = "us-south" + location = "%[3]s" auto_scaling { cpu { rate_increase_percent = 20 @@ -257,7 +298,7 @@ func testAccCheckIBMDatabaseInstanceRedisImport(databaseResourceGroup string, na } } } - `, databaseResourceGroup, name) + `, databaseResourceGroup, name, acc.IcdDbRegion) } func testAccCheckIBMDatabaseInstanceRedisKPEncrypt(databaseResourceGroup string, kpInstanceName, kpKeyName, kpByokName, name string) string { return fmt.Sprintf(` @@ -269,7 +310,7 @@ func testAccCheckIBMDatabaseInstanceRedisKPEncrypt(databaseResourceGroup string, name = "%s" service = "kms" plan = "tiered-pricing" - location = "us-south" + location = "%[3]s" } resource "ibm_kp_key" "test" { key_protect_id = ibm_resource_instance.kp_instance.guid @@ -286,10 +327,15 @@ func testAccCheckIBMDatabaseInstanceRedisKPEncrypt(databaseResourceGroup string, name = "%s" service = "databases-for-redis" plan = "standard" - location = "us-south" + location = "%[3]s" key_protect_instance = ibm_resource_instance.kp_instance.guid key_protect_key = ibm_kp_key.test.id backup_encryption_key_crn = ibm_kp_key.test1.id + timeouts { + create = "480m" + update = "480m" + delete = "15m" + } } - `, databaseResourceGroup, kpInstanceName, kpKeyName, kpByokName, name) + `, databaseResourceGroup, kpInstanceName, kpKeyName, kpByokName, name, acc.IcdDbRegion) } diff --git a/ibm/service/directlink/README.md b/ibm/service/directlink/README.md new file mode 100644 index 000000000..e7533cfaa --- /dev/null +++ b/ibm/service/directlink/README.md @@ -0,0 +1,12 @@ +# Terraform IBM Provider Direct Link Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the DL resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/dl_gateway) +* IBM API Docs: [IBM API Docs for DL](https://cloud.ibm.com/apidocs/direct_link) +* IBM DL SDK: [IBM SDK for DL](https://github.com/IBM/networking-go-sdk/tree/master/directlinkv1) +* IBM DL SDK: [IBM SDK for DL Provider](https://github.com/IBM/networking-go-sdk/tree/master/directlinkproviderv2) diff --git a/ibm/service/directlink/constants.go b/ibm/service/directlink/constants.go new file mode 100644 index 000000000..426707560 --- /dev/null +++ b/ibm/service/directlink/constants.go @@ -0,0 +1,94 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink + +const ( + dlGatewaysVirtualConnections = "gateway_vcs" + dlVCNetworkAccount = "network_account" + dlVCNetworkId = "network_id" + dlVCName = "name" + dlVCType = "type" + dlVCCreatedAt = "created_at" + dlVCStatus = "status" + dlGatewayId = "gateway" + ID = "id" + dlVirtualConnectionId = "virtual_connection_id" + dlVirtualConnectionName = "virtual_connection_name" + dlVirtualConnectionType = "virtual_connection_type" + dlActive = "active" + dlAsPrepends = "as_prepends" + dlAuthenticationKey = "authentication_key" + dlBfdInterval = "bfd_interval" + dlBfdMultiplier = "bfd_multiplier" + dlBfdStatus = "bfd_status" + dlBfdStatusUpdatedAt = "bfd_status_updated_at" + dlBgpAsn = "bgp_asn" + dlBgpBaseCidr = "bgp_base_cidr" + dlBgpCerCidr = "bgp_cer_cidr" + dlBgpIbmAsn = "bgp_ibm_asn" + dlBgpIbmCidr = "bgp_ibm_cidr" + dlBgpStatus = "bgp_status" + dlCarrierName = "carrier_name" + dlChangeRequest = "change_request" + dlCipherSuite = "cipher_suite" + dlCompletionNoticeRejectReason = "completion_notice_reject_reason" + dlConfidentialityOffset = "confidentiality_offset" + dlGatewayProvisioning = "configuring" + dlConnectionMode = "connection_mode" + dlCreatedAt = "created_at" + dlGatewayProvisioningRejected = "create_rejected" + dlCrossConnectRouter = "cross_connect_router" + dlCrn = "crn" + dlCryptographicAlgorithm = "cryptographic_algorithm" + dlCustomerName = "customer_name" + dlFallbackCak = "fallback_cak" + dlGlobal = "global" + dlKeyServerPriority = "key_server_priority" + dlLength = "length" + dlLoaRejectReason = "loa_reject_reason" + dlLocationDisplayName = "location_display_name" + dlLocationName = "location_name" + dlLinkStatus = "link_status" + dlMacSecConfig = "macsec_config" + dlMetered = "metered" + dlName = "name" + dlOperationalStatus = "operational_status" + dlPolicy = "policy" + dlPort = "port" + dlPrimaryCak = "primary_cak" + dlProviderAPIManaged = "provider_api_managed" + dlGatewayProvisioningDone = "provisioned" + dlResourceGroup = "resource_group" + dlSakExpiryTime = "sak_expiry_time" + dlSpeedMbps = "speed_mbps" + dlMacSecConfigStatus = "status" + dlTags = "tags" + dlType = "type" + dlUpdatedAt = "updated_at" + dlVlan = "vlan" + dlWindowSize = "window_size" + customerAccountID = "customer_account_id" + dlRouteReports = "route_reports" + dlPrefix = "prefix" + dlRouteReportNextHop = "next_hop" + dlGatewayRoutes = "gateway_routes" + dlOnPremRoutes = "on_prem_routes" + dlOverlappingRoutes = "overlapping_routes" + dlRoutes = "routes" + dlRouteReportStatus = "status" + dlVirtualConnectionRoutes = "virtual_connection_routes" + dlId = "id" + dlRouteReportPending = "pending" + dlRouteReportComplete = "complete" + dlRouteReportId = "route_report_id" + dlResourceId = "id" +) + +func NewInt64Pointer(v int64) *int64 { + return &v +} + +func NewStrPointer(v string) *string { + return &v +} diff --git a/ibm/data_source_ibm_dl_gateway.go b/ibm/service/directlink/data_source_ibm_dl_gateway.go similarity index 86% rename from ibm/data_source_ibm_dl_gateway.go rename to ibm/service/directlink/data_source_ibm_dl_gateway.go index c31ab5945..6ff97a4bc 100644 --- a/ibm/data_source_ibm_dl_gateway.go +++ b/ibm/service/directlink/data_source_ibm_dl_gateway.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -17,7 +19,7 @@ const ( dlActiveCak = "active_cak" ) -func dataSourceIBMDLGateway() *schema.Resource { +func DataSourceIBMDLGateway() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDLGatewayRead, Schema: map[string]*schema.Schema{ @@ -25,7 +27,7 @@ func dataSourceIBMDLGateway() *schema.Resource { Type: schema.TypeString, Required: true, Description: "The unique user-defined name for this gateway", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlName), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlName), }, dlGatewaysVirtualConnections: { @@ -73,6 +75,45 @@ func dataSourceIBMDLGateway() *schema.Resource { }, }, + dlAsPrepends: { + Type: schema.TypeList, + Computed: true, + Description: "List of AS Prepend configuration information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was created", + }, + ID: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was created", + }, + dlLength: { + Type: schema.TypeInt, + Computed: true, + Description: "Number of times the ASN to appended to the AS Path", + }, + dlPolicy: { + Type: schema.TypeString, + Computed: true, + Description: "Route type this AS Prepend applies to", + }, + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes.", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was updated", + }, + }, + }, + }, dlAuthenticationKey: { Type: schema.TypeString, Computed: true, @@ -293,7 +334,7 @@ func dataSourceIBMDLGateway() *schema.Resource { } func dataSourceIBMDLGatewayVirtualConnectionsRead(d *schema.ResourceData, meta interface{}) error { - directLink, err := meta.(ClientSession).DirectlinkV1API() + directLink, err := meta.(conns.ClientSession).DirectlinkV1API() if err != nil { return err @@ -303,7 +344,7 @@ func dataSourceIBMDLGatewayVirtualConnectionsRead(d *schema.ResourceData, meta i listVcOptions.SetGatewayID(dlGatewayId) listGatewayVirtualConnections, response, err := directLink.ListGatewayVirtualConnections(listVcOptions) if err != nil { - return fmt.Errorf("Error while listing directlink gateway's virtual connections XXX %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while listing directlink gateway's virtual connections XXX %s\n%s", err, response) } gatewayVCs := make([]map[string]interface{}, 0) for _, instance := range listGatewayVirtualConnections.VirtualConnections { @@ -444,6 +485,25 @@ func dataSourceIBMDLGatewayRead(d *schema.ResourceData, meta interface{}) error d.Set(dlBfdStatusUpdatedAt, instance.BfdConfig.BfdStatusUpdatedAt.String()) } } + + asPrependList := make([]map[string]interface{}, 0) + if len(instance.AsPrepends) > 0 { + for _, asPrepend := range instance.AsPrepends { + asPrependItem := map[string]interface{}{} + asPrependItem[dlResourceId] = asPrepend.ID + asPrependItem[dlLength] = asPrepend.Length + asPrependItem[dlPrefix] = asPrepend.Prefix + asPrependItem[dlPolicy] = asPrepend.Policy + asPrependItem[dlCreatedAt] = asPrepend.CreatedAt.String() + asPrependItem[dlUpdatedAt] = asPrepend.UpdatedAt.String() + + asPrependList = append(asPrependList, asPrependItem) + } + + } + + d.Set(dlAsPrepends, asPrependList) + dtype := *instance.Type if dtype == "dedicated" { if instance.MacsecConfig != nil { @@ -517,8 +577,7 @@ func dataSourceIBMDLGatewayRead(d *schema.ResourceData, meta interface{}) error } if !found { - return fmt.Errorf( - "Error Gateway with name (%s) not found ", dlGatewayName) + return fmt.Errorf("[ERROR] Error Gateway with name (%s) not found ", dlGatewayName) } return dataSourceIBMDLGatewayVirtualConnectionsRead(d, meta) } diff --git a/ibm/data_source_ibm_dl_gateway_test.go b/ibm/service/directlink/data_source_ibm_dl_gateway_test.go similarity index 90% rename from ibm/data_source_ibm_dl_gateway_test.go rename to ibm/service/directlink/data_source_ibm_dl_gateway_test.go index 4ffa0aa80..7da75d8b8 100644 --- a/ibm/data_source_ibm_dl_gateway_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_gateway_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,8 +20,8 @@ func TestAccIBMDLGatewayDataSource_basic(t *testing.T) { carriername := fmt.Sprintf("carrier-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLGatewayVCsDataSourceConfig(gatewayname, custname, carriername), diff --git a/ibm/data_source_ibm_dl_gateways.go b/ibm/service/directlink/data_source_ibm_dl_gateways.go similarity index 87% rename from ibm/data_source_ibm_dl_gateways.go rename to ibm/service/directlink/data_source_ibm_dl_gateways.go index 896db3cc0..441c30de2 100644 --- a/ibm/data_source_ibm_dl_gateways.go +++ b/ibm/service/directlink/data_source_ibm_dl_gateways.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "log" @@ -16,7 +16,7 @@ const ( dlGatewaysId = "id" ) -func dataSourceIBMDLGateways() *schema.Resource { +func DataSourceIBMDLGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDLGatewaysRead, Schema: map[string]*schema.Schema{ @@ -31,6 +31,45 @@ func dataSourceIBMDLGateways() *schema.Resource { Computed: true, Description: "Id of the data source gateways", }, + dlAsPrepends: { + Type: schema.TypeList, + Computed: true, + Description: "List of AS Prepend configuration information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was created", + }, + ID: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was created", + }, + dlLength: { + Type: schema.TypeInt, + Computed: true, + Description: "Number of times the ASN to appended to the AS Path", + }, + dlPolicy: { + Type: schema.TypeString, + Computed: true, + Description: "Route type this AS Prepend applies to", + }, + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes.", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was updated", + }, + }, + }, + }, dlAuthenticationKey: { Type: schema.TypeString, Computed: true, @@ -362,6 +401,23 @@ func dataSourceIBMDLGatewaysRead(d *schema.ResourceData, meta interface{}) error } } + asPrependList := make([]map[string]interface{}, 0) + if len(instance.AsPrepends) > 0 { + for _, asPrepend := range instance.AsPrepends { + asPrependItem := map[string]interface{}{} + asPrependItem[dlResourceId] = asPrepend.ID + asPrependItem[dlLength] = asPrepend.Length + asPrependItem[dlPrefix] = asPrepend.Prefix + asPrependItem[dlPolicy] = asPrepend.Policy + asPrependItem[dlCreatedAt] = asPrepend.CreatedAt.String() + asPrependItem[dlUpdatedAt] = asPrepend.UpdatedAt.String() + + asPrependList = append(asPrependList, asPrependItem) + } + + } + gateway[dlAsPrepends] = asPrependList + dtype := *instance.Type if dtype == "dedicated" { if instance.MacsecConfig != nil { diff --git a/ibm/data_source_ibm_dl_gateways_test.go b/ibm/service/directlink/data_source_ibm_dl_gateways_test.go similarity index 90% rename from ibm/data_source_ibm_dl_gateways_test.go rename to ibm/service/directlink/data_source_ibm_dl_gateways_test.go index 63ab3bb64..8cfb118fa 100644 --- a/ibm/data_source_ibm_dl_gateways_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_gateways_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIBMDLGatewaysDataSource_basic(t *testing.T) { carriername := fmt.Sprintf("carrier-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLGatewaysDataSourceConfig(gatewayname, custname, carriername), diff --git a/ibm/data_source_ibm_dl_locations.go b/ibm/service/directlink/data_source_ibm_dl_locations.go similarity index 92% rename from ibm/data_source_ibm_dl_locations.go rename to ibm/service/directlink/data_source_ibm_dl_locations.go index 50f7e410e..94b9a2c03 100644 --- a/ibm/data_source_ibm_dl_locations.go +++ b/ibm/service/directlink/data_source_ibm_dl_locations.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "time" ) const ( @@ -25,14 +28,14 @@ const ( dlProvisionEnabled = "provision_enabled" ) -func dataSourceIBMDLLocations() *schema.Resource { +func DataSourceIBMDLLocations() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDLOfferingLocationsRead, Schema: map[string]*schema.Schema{ dlOfferingType: { Type: schema.TypeString, Required: true, - ValidateFunc: validateAllowedStringValue([]string{"dedicated", "connect"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"dedicated", "connect"}), Description: "The Direct Link offering type. Current supported values (dedicated and connect).", }, dlLocations: { @@ -108,7 +111,7 @@ func dataSourceIBMDLLocations() *schema.Resource { } func dataSourceIBMDLOfferingLocationsRead(d *schema.ResourceData, meta interface{}) error { - directLink, err := meta.(ClientSession).DirectlinkV1API() + directLink, err := meta.(conns.ClientSession).DirectlinkV1API() if err != nil { return err } @@ -116,7 +119,7 @@ func dataSourceIBMDLOfferingLocationsRead(d *schema.ResourceData, meta interface listOfferingTypeLocationsOptions.SetOfferingType(d.Get(dlOfferingType).(string)) listLocations, response, err := directLink.ListOfferingTypeLocations(listOfferingTypeLocationsOptions) if err != nil { - return fmt.Errorf("Error while listing directlink gateway's locations %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while listing directlink gateway's locations %s\n%s", err, response) } locations := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_dl_locations_test.go b/ibm/service/directlink/data_source_ibm_dl_locations_test.go similarity index 82% rename from ibm/data_source_ibm_dl_locations_test.go rename to ibm/service/directlink/data_source_ibm_dl_locations_test.go index 39beec74d..7a4db0b48 100644 --- a/ibm/data_source_ibm_dl_locations_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_locations_test.go @@ -1,20 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMDLLocationsDataSource_basic(t *testing.T) { node := "data.ibm_dl_locations.test_dl_locations" offeringType := "dedicated" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLOfferingLocationsDataSourceConfig(offeringType), diff --git a/ibm/data_source_ibm_dl_offering_speeds.go b/ibm/service/directlink/data_source_ibm_dl_offering_speeds.go similarity index 79% rename from ibm/data_source_ibm_dl_offering_speeds.go rename to ibm/service/directlink/data_source_ibm_dl_offering_speeds.go index e00c971df..f0ac003b7 100644 --- a/ibm/data_source_ibm_dl_offering_speeds.go +++ b/ibm/service/directlink/data_source_ibm_dl_offering_speeds.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -19,7 +21,7 @@ const ( dlMeteringCapabilities = "capabilities" ) -func dataSourceIBMDLOfferingSpeeds() *schema.Resource { +func DataSourceIBMDLOfferingSpeeds() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDLOfferingSpeedsRead, Schema: map[string]*schema.Schema{ @@ -27,7 +29,7 @@ func dataSourceIBMDLOfferingSpeeds() *schema.Resource { Type: schema.TypeString, Required: true, Description: "The Direct Link offering type", - ValidateFunc: InvokeDataSourceValidator("ibm_dl_offering_speeds", dlOfferingType), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_dl_offering_speeds", dlOfferingType), }, dlSpeeds: { Type: schema.TypeList, @@ -76,7 +78,7 @@ func dataSourceIBMDLOfferingSpeedsRead(d *schema.ResourceData, meta interface{}) for _, instance := range listSpeeds.Speeds { speed := map[string]interface{}{} if instance.Capabilities != nil { - speed[dlMeteringCapabilities] = flattenStringList(instance.Capabilities) + speed[dlMeteringCapabilities] = flex.FlattenStringList(instance.Capabilities) } if instance.LinkSpeed != nil { speed[dlLinkSpeed] = *instance.LinkSpeed @@ -96,19 +98,19 @@ func dataSourceIBMDLOfferingSpeedsID(d *schema.ResourceData) string { return time.Now().UTC().String() } -func datasourceIBMDLOfferingSpeedsValidator() *ResourceValidator { +func DataSourceIBMDLOfferingSpeedsValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) dlTypeAllowedValues := "dedicated, connect" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlOfferingType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: dlTypeAllowedValues}) - ibmDLOfferingSpeedsDatasourceValidator := ResourceValidator{ResourceName: "ibm_dl_offering_speeds", Schema: validateSchema} + ibmDLOfferingSpeedsDatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_dl_offering_speeds", Schema: validateSchema} return &ibmDLOfferingSpeedsDatasourceValidator } diff --git a/ibm/data_source_ibm_dl_offering_speeds_test.go b/ibm/service/directlink/data_source_ibm_dl_offering_speeds_test.go similarity index 85% rename from ibm/data_source_ibm_dl_offering_speeds_test.go rename to ibm/service/directlink/data_source_ibm_dl_offering_speeds_test.go index e141916ee..a396e5725 100644 --- a/ibm/data_source_ibm_dl_offering_speeds_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_offering_speeds_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +16,8 @@ func TestAccIBMDLOfferingSpeedsDataSource_basic(t *testing.T) { node2 := "data.ibm_dl_offering_speeds.test2" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLOfferingSpeedsDataSourceConfig(), @@ -32,7 +33,7 @@ func TestAccIBMDLOfferingSpeedsDataSource_basic(t *testing.T) { } func testAccCheckIBMDLOfferingSpeedsDataSourceConfig() string { - return fmt.Sprintf(` + return ` data "ibm_dl_offering_speeds" "test1" { offering_type = "dedicated" } @@ -40,5 +41,5 @@ func testAccCheckIBMDLOfferingSpeedsDataSourceConfig() string { data "ibm_dl_offering_speeds" "test2" { offering_type = "connect" } - `) + ` } diff --git a/ibm/data_source_ibm_dl_port.go b/ibm/service/directlink/data_source_ibm_dl_port.go similarity index 91% rename from ibm/data_source_ibm_dl_port.go rename to ibm/service/directlink/data_source_ibm_dl_port.go index 8d0524e71..204e4b889 100644 --- a/ibm/data_source_ibm_dl_port.go +++ b/ibm/service/directlink/data_source_ibm_dl_port.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMDirectLinkPort() *schema.Resource { +func DataSourceIBMDirectLinkPort() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDirectLinkPortRead, Schema: map[string]*schema.Schema{ @@ -57,7 +58,7 @@ func dataSourceIBMDirectLinkPort() *schema.Resource { func dataSourceIBMDirectLinkPortRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).DirectlinkV1API() + sess, err := meta.(conns.ClientSession).DirectlinkV1API() if err != nil { return err } diff --git a/ibm/data_source_ibm_dl_port_test.go b/ibm/service/directlink/data_source_ibm_dl_port_test.go similarity index 82% rename from ibm/data_source_ibm_dl_port_test.go rename to ibm/service/directlink/data_source_ibm_dl_port_test.go index b5daf249f..872d9e382 100644 --- a/ibm/data_source_ibm_dl_port_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_port_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMDLPortDataSource_basic(t *testing.T) { name := "dl_port" resName := "data.ibm_dl_port.test_dl_port" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLPortDataSourceConfig(name), diff --git a/ibm/data_source_ibm_dl_ports.go b/ibm/service/directlink/data_source_ibm_dl_ports.go similarity index 92% rename from ibm/data_source_ibm_dl_ports.go rename to ibm/service/directlink/data_source_ibm_dl_ports.go index 7c0186335..ab8372780 100644 --- a/ibm/data_source_ibm_dl_ports.go +++ b/ibm/service/directlink/data_source_ibm_dl_ports.go @@ -1,9 +1,11 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" dl "github.com/IBM/networking-go-sdk/directlinkv1" "log" @@ -23,7 +25,7 @@ const ( dlProviderName = "provider_name" ) -func dataSourceIBMDirectLinkPorts() *schema.Resource { +func DataSourceIBMDirectLinkPorts() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDirectLinkPortsRead, @@ -89,7 +91,7 @@ func dataSourceIBMDirectLinkPorts() *schema.Resource { func dataSourceIBMDirectLinkPortsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).DirectlinkV1API() + sess, err := meta.(conns.ClientSession).DirectlinkV1API() if err != nil { return err } @@ -112,7 +114,7 @@ func dataSourceIBMDirectLinkPortsRead(d *schema.ResourceData, meta interface{}) log.Println("[WARN] Error listing dl ports", resp, err) return err } - start = GetNext(response.Next) + start = flex.GetNext(response.Next) allrecs = append(allrecs, response.Ports...) if start == "" { break diff --git a/ibm/data_source_ibm_dl_ports_test.go b/ibm/service/directlink/data_source_ibm_dl_ports_test.go similarity index 81% rename from ibm/data_source_ibm_dl_ports_test.go rename to ibm/service/directlink/data_source_ibm_dl_ports_test.go index 72169cef0..d9354f503 100644 --- a/ibm/data_source_ibm_dl_ports_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_ports_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMDLPortsDataSource_basic(t *testing.T) { name := "dl_ports" resName := "data.ibm_dl_ports.test_dl_ports" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLPortsDataSourceConfig(name), diff --git a/ibm/data_source_ibm_dl_provider_gateways.go b/ibm/service/directlink/data_source_ibm_dl_provider_gateways.go similarity index 97% rename from ibm/data_source_ibm_dl_provider_gateways.go rename to ibm/service/directlink/data_source_ibm_dl_provider_gateways.go index 22545ad76..9bc7cb948 100644 --- a/ibm/data_source_ibm_dl_provider_gateways.go +++ b/ibm/service/directlink/data_source_ibm_dl_provider_gateways.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( - dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "log" "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const ( @@ -15,7 +17,7 @@ const ( dlProviderGatewaysID = "id" ) -func dataSourceIBMDirectLinkProviderGateways() *schema.Resource { +func DataSourceIBMDirectLinkProviderGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDirectLinkProviderGatewaysRead, @@ -146,7 +148,7 @@ func dataSourceIBMDirectLinkProviderGatewaysRead(d *schema.ResourceData, meta in log.Println("[WARN] Error listing dl provider gateways", providerGateways, resp, err) return err } - start = GetNext(providerGateways.Next) + start = flex.GetNext(providerGateways.Next) allrecs = append(allrecs, providerGateways.Gateways...) if start == "" { break diff --git a/ibm/data_source_ibm_dl_provider_gateways_test.go b/ibm/service/directlink/data_source_ibm_dl_provider_gateways_test.go similarity index 81% rename from ibm/data_source_ibm_dl_provider_gateways_test.go rename to ibm/service/directlink/data_source_ibm_dl_provider_gateways_test.go index 4642b2f8f..e656814aa 100644 --- a/ibm/data_source_ibm_dl_provider_gateways_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_provider_gateways_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMDLProviderGWsDataSource_basic(t *testing.T) { name := "dl_provider_gws" resName := "data.ibm_dl_provider_gateways.test_dl_provider_gws" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLProviderGWsDataSourceConfig(name), diff --git a/ibm/data_source_ibm_dl_provider_ports.go b/ibm/service/directlink/data_source_ibm_dl_provider_ports.go similarity index 91% rename from ibm/data_source_ibm_dl_provider_ports.go rename to ibm/service/directlink/data_source_ibm_dl_provider_ports.go index 1b90c2438..03cf4e8b0 100644 --- a/ibm/data_source_ibm_dl_provider_ports.go +++ b/ibm/service/directlink/data_source_ibm_dl_provider_ports.go @@ -1,16 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( - dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "log" "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMDirectLinkProviderPorts() *schema.Resource { +func DataSourceIBMDirectLinkProviderPorts() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDirectLinkProviderPortsRead, @@ -67,7 +70,7 @@ func dataSourceIBMDirectLinkProviderPorts() *schema.Resource { } func directlinkProviderClient(meta interface{}) (*dlProviderV2.DirectLinkProviderV2, error) { - sess, err := meta.(ClientSession).DirectlinkProviderV2API() + sess, err := meta.(conns.ClientSession).DirectlinkProviderV2API() return sess, err } func dataSourceIBMDirectLinkProviderPortsRead(d *schema.ResourceData, meta interface{}) error { @@ -88,7 +91,7 @@ func dataSourceIBMDirectLinkProviderPortsRead(d *schema.ResourceData, meta inter log.Println("[WARN] Error listing dl provider ports", ports, resp, err) return err } - start = GetNext(ports.Next) + start = flex.GetNext(ports.Next) allrecs = append(allrecs, ports.Ports...) if start == "" { break diff --git a/ibm/data_source_ibm_dl_provider_ports_test.go b/ibm/service/directlink/data_source_ibm_dl_provider_ports_test.go similarity index 82% rename from ibm/data_source_ibm_dl_provider_ports_test.go rename to ibm/service/directlink/data_source_ibm_dl_provider_ports_test.go index fbc99b484..1061d0a43 100644 --- a/ibm/data_source_ibm_dl_provider_ports_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_provider_ports_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMDLProviderPortsDataSource_basic(t *testing.T) { name := "dl_provider_ports" resName := "data.ibm_dl_provider_ports.test_dl_provider_ports" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLProviderPortsDataSourceConfig(name), diff --git a/ibm/service/directlink/data_source_ibm_dl_route_report.go b/ibm/service/directlink/data_source_ibm_dl_route_report.go new file mode 100644 index 000000000..f900cda03 --- /dev/null +++ b/ibm/service/directlink/data_source_ibm_dl_route_report.go @@ -0,0 +1,271 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink + +import ( + "fmt" + "log" + + "github.com/IBM/networking-go-sdk/directlinkv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + dlRouteReport = "route_report" +) + +func DataSourceIBMDLRouteReport() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMDLRouteReportRead, + Schema: map[string]*schema.Schema{ + dlGatewayId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The Direct Link gateway identifier", + }, + dlRouteReport: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Id of the route report", + }, + dlGatewayRoutes: { + Type: schema.TypeList, + Description: "List of gateway routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for gateway routes", + }, + }, + }, + }, + dlOnPremRoutes: { + Type: schema.TypeList, + Description: "List of onprem routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for onprem routes", + }, + dlRouteReportNextHop: { + Type: schema.TypeString, + Computed: true, + Description: "Next Hop address", + }, + }, + }, + }, + dlOverlappingRoutes: { + Type: schema.TypeList, + Description: "List of overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "overlapping routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + dlType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of route", + }, + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + }, + }, + }, + }, + }, + }, + dlVirtualConnectionRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual Connection Routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + dlVirtualConnectionType: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection type", + }, + dlVirtualConnectionName: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection name", + }, + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual connection routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + }, + }, + }, + }, + }, + }, + dlRouteReportStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Route report status", + }, + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time report was created", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time resource was created", + }, + }, + } +} + +func dataSourceIBMDLRouteReportRead(d *schema.ResourceData, meta interface{}) error { + directLink, err := directlinkClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(dlGatewayId).(string) + routeReportId := d.Get(dlRouteReport).(string) + + log.Println("[Info] fetching DL Route Reports GW ID:", gatewayId, " and report ID: ", routeReportId) + + getGatewayRouteReportOptionsModel := &directlinkv1.GetGatewayRouteReportOptions{GatewayID: &gatewayId, ID: &routeReportId} + report, response, err := directLink.GetGatewayRouteReport(getGatewayRouteReportOptionsModel) + if err != nil { + log.Println("[DEBUG] Error fetching DL Route Reports for gateway:", gatewayId, "with response code:", response.StatusCode, " and err: ", err) + return fmt.Errorf("[ERROR] Error fetching DL Route Reports: %s with response code %d", err, response.StatusCode) + } + + if report == nil { + return fmt.Errorf("error fetching route report for gateway: %s and route report: %s with response code: %d", gatewayId, routeReportId, response.StatusCode) + } else if report.ID != nil { + d.SetId(*report.ID) + } + + if report.Status != nil { + log.Println("[Info] fetching DL Route Reports status:", *report.Status) + d.Set(dlRouteReportStatus, *report.Status) + } + + // Build Gateway Routes + gatewayRoutes := make([]map[string]interface{}, 0) + if report.GatewayRoutes != nil { + for _, gatewayRoute := range report.GatewayRoutes { + route := map[string]interface{}{} + route[dlPrefix] = gatewayRoute.Prefix + gatewayRoutes = append(gatewayRoutes, route) + } + + } + log.Println("[Info] Length DL Gateway Reports: ", len(gatewayRoutes)) + d.Set(dlGatewayRoutes, gatewayRoutes) + + // Build onPrem Routes + onPremRoutes := make([]map[string]interface{}, 0) + if report.OnPremRoutes != nil { + for _, onPremRoute := range report.OnPremRoutes { + route := map[string]interface{}{} + route[dlPrefix] = onPremRoute.Prefix + onPremRoutes = append(onPremRoutes, route) + } + + } + + log.Println("[Info] Length DL Route Reports onprem routes:", len(onPremRoutes)) + d.Set(dlOnPremRoutes, onPremRoutes) + + // Build Overlapping Routes + overlappingRoutesCollection := make([]map[string]interface{}, 0) + if report.OverlappingRoutes != nil && len(report.OverlappingRoutes) > 0 { + + for _, o := range report.OverlappingRoutes { + overlappingRouteItem := map[string]interface{}{} + routes := make([]map[string]interface{}, 0) + for _, r := range o.Routes { + overlappingRoute := map[string]interface{}{} + route := r.(*directlinkv1.RouteReportOverlappingRoute) + overlappingRoute[dlPrefix] = route.Prefix + overlappingRoute[dlType] = route.Type + overlappingRoute[dlVirtualConnectionId] = route.VirtualConnectionID + + routes = append(routes, overlappingRoute) + } + overlappingRouteItem[dlRoutes] = routes + + overlappingRoutesCollection = append(overlappingRoutesCollection, overlappingRouteItem) + } + } + + log.Println("[INFO] Length DL overlapping routes", len(overlappingRoutesCollection)) + d.Set(dlOverlappingRoutes, overlappingRoutesCollection) + + // Build connection routes + virtualConnectionRoutes := make([]map[string]interface{}, 0) + if report.VirtualConnectionRoutes != nil { + for _, c := range report.VirtualConnectionRoutes { + conn := map[string]interface{}{} + conn[dlVirtualConnectionId] = c.VirtualConnectionID + conn[dlVirtualConnectionName] = c.VirtualConnectionName + conn[dlVirtualConnectionType] = c.VirtualConnectionType + + connectionRoutes := make([]map[string]interface{}, 0) + for _, r := range c.Routes { + routes := map[string]interface{}{} + routes[dlPrefix] = r.Prefix + connectionRoutes = append(connectionRoutes, routes) + } + + conn[dlRoutes] = connectionRoutes + virtualConnectionRoutes = append(virtualConnectionRoutes, conn) + } + } + + log.Println("[Info] Length DL Route Reports connection routes:", len(virtualConnectionRoutes)) + d.Set(dlVirtualConnectionRoutes, virtualConnectionRoutes) + + // Add the created and updated dates + if report.CreatedAt != nil { + d.Set(dlCreatedAt, report.CreatedAt.String()) + } + if report.UpdatedAt != nil { + d.Set(dlUpdatedAt, report.UpdatedAt.String()) + } + + return nil +} diff --git a/ibm/service/directlink/data_source_ibm_dl_route_report_test.go b/ibm/service/directlink/data_source_ibm_dl_route_report_test.go new file mode 100644 index 000000000..1caf194d2 --- /dev/null +++ b/ibm/service/directlink/data_source_ibm_dl_route_report_test.go @@ -0,0 +1,59 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDLRouteReportDataSource_basic(t *testing.T) { + node := "data.ibm_dl_route_report.dl_route_report" + gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDLRouteReportDataSourceConfig(gatewayname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(node, "status", "complete"), + ), + }, + }, + }) +} + +func testAccCheckIBMDLRouteReportDataSourceConfig(gatewayname string) string { + return fmt.Sprintf(` + data "ibm_dl_ports" "ds_dlports" { + } + + resource ibm_dl_gateway test_dl_gateway { + bgp_asn = 64999 + global = true + metered = false + name = "%s" + speed_mbps = 1000 + type = "connect" + port = data.ibm_dl_ports.ds_dlports.ports[0].port_id + } + + resource ibm_dl_route_report dl_route_report { + gateway = ibm_dl_gateway.test_dl_gateway.id + } + + data "ibm_dl_route_report" "dl_route_report" { + gateway = ibm_dl_gateway.test_dl_gateway.id + route_report= ibm_dl_route_report.dl_route_report.route_report_id + } + + `, gatewayname) +} diff --git a/ibm/service/directlink/data_source_ibm_dl_route_reports.go b/ibm/service/directlink/data_source_ibm_dl_route_reports.go new file mode 100644 index 000000000..5e44d7f97 --- /dev/null +++ b/ibm/service/directlink/data_source_ibm_dl_route_reports.go @@ -0,0 +1,282 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink + +import ( + "log" + "time" + + "github.com/IBM/networking-go-sdk/directlinkv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMDLRouteReports() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMDLRouteReportsRead, + Schema: map[string]*schema.Schema{ + dlGatewayId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The Direct Link gateway identifier", + }, + dlRouteReports: { + Type: schema.TypeList, + Description: "List of route reports for a gateway", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlId: { + Type: schema.TypeString, + Computed: true, + Description: "Id of the route report", + }, + dlGatewayRoutes: { + Type: schema.TypeList, + Description: "List of gateway routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for gateway routes", + }, + }, + }, + }, + dlOnPremRoutes: { + Type: schema.TypeList, + Description: "List of onprem routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for onprem routes", + }, + dlRouteReportNextHop: { + Type: schema.TypeString, + Computed: true, + Description: "Next Hop address", + }, + }, + }, + }, + dlOverlappingRoutes: { + Type: schema.TypeList, + Description: "List of overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "overlapping routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + dlType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of route", + }, + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + }, + }, + }, + }, + }, + }, + dlVirtualConnectionRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual Connection Routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + dlVirtualConnectionType: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection type", + }, + dlVirtualConnectionName: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection name", + }, + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual connection routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + }, + }, + }, + }, + }, + }, + dlRouteReportStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Route report status", + }, + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time report was created", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time resource was created", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMDLRouteReportsRead(d *schema.ResourceData, meta interface{}) error { + directLink, err := directlinkClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(dlGatewayId).(string) + + listGatewayRouteReportsOptionsModel := &directlinkv1.ListGatewayRouteReportsOptions{GatewayID: &gatewayId} + routeReportsList, response, err := directLink.ListGatewayRouteReports(listGatewayRouteReportsOptionsModel) + if err != nil { + log.Println("[WARN] Error listing DL Route Reports", response, err) + return err + } + + routeReports := make([]map[string]interface{}, 0) + for _, instance := range routeReportsList.RouteReports { + routeReport := map[string]interface{}{} + if instance.ID != nil { + routeReport[dlId] = *instance.ID + } + if instance.Status != nil { + routeReport[dlRouteReportStatus] = *instance.Status + } + + // Build Gateway Routes + gatewayRoutes := make([]map[string]interface{}, 0) + if instance.GatewayRoutes != nil { + for _, gatewayRoute := range instance.GatewayRoutes { + route := map[string]interface{}{} + route[dlPrefix] = gatewayRoute.Prefix + gatewayRoutes = append(gatewayRoutes, route) + } + + } + + log.Println("[INFO] length DL Gateway Routes", len(gatewayRoutes)) + routeReport[dlGatewayRoutes] = gatewayRoutes + + // Build onPrem Routes + onPremRoutes := make([]map[string]interface{}, 0) + if instance.OnPremRoutes != nil { + for _, onPremRoute := range instance.OnPremRoutes { + route := map[string]interface{}{} + route[dlPrefix] = onPremRoute.Prefix + onPremRoutes = append(onPremRoutes, route) + } + + } + + log.Println("[INFO] length DL Onprem routes", len(onPremRoutes)) + routeReport[dlOnPremRoutes] = onPremRoutes + + // Build Overlapping Routes + overlappingRoutesCollection := make([]map[string]interface{}, 0) + if instance.OverlappingRoutes != nil && len(instance.OverlappingRoutes) > 0 { + + for _, o := range instance.OverlappingRoutes { + overlappingRouteItem := map[string]interface{}{} + routes := make([]map[string]interface{}, 0) + for _, r := range o.Routes { + overlappingRoute := map[string]interface{}{} + route := r.(*directlinkv1.RouteReportOverlappingRoute) + overlappingRoute[dlPrefix] = route.Prefix + overlappingRoute[dlType] = route.Type + overlappingRoute[dlVirtualConnectionId] = route.VirtualConnectionID + + routes = append(routes, overlappingRoute) + } + overlappingRouteItem[dlRoutes] = routes + + overlappingRoutesCollection = append(overlappingRoutesCollection, overlappingRouteItem) + } + } + + log.Println("[INFO] length DL overlapping routes", len(overlappingRoutesCollection)) + routeReport[dlOverlappingRoutes] = overlappingRoutesCollection + + // Build connection routes + virtualConnectionRoutes := make([]map[string]interface{}, 0) + if instance.VirtualConnectionRoutes != nil { + for _, c := range instance.VirtualConnectionRoutes { + conn := map[string]interface{}{} + conn[dlVirtualConnectionId] = c.VirtualConnectionID + conn[dlVirtualConnectionName] = c.VirtualConnectionName + conn[dlVirtualConnectionType] = c.VirtualConnectionType + + connectionRoutes := make([]map[string]interface{}, 0) + for _, r := range c.Routes { + routes := map[string]interface{}{} + routes[dlPrefix] = r.Prefix + connectionRoutes = append(connectionRoutes, routes) + } + + conn[dlRoutes] = connectionRoutes + virtualConnectionRoutes = append(virtualConnectionRoutes, conn) + } + } + + log.Println("[INFO] length DL connection routes", len(virtualConnectionRoutes)) + routeReport[dlVirtualConnectionRoutes] = virtualConnectionRoutes + + // Add the created and updated dates + if instance.CreatedAt != nil { + routeReport[dlCreatedAt] = instance.CreatedAt.String() + } + if instance.UpdatedAt != nil { + routeReport[dlUpdatedAt] = instance.UpdatedAt.String() + } + + routeReports = append(routeReports, routeReport) + + } + d.Set(dlRouteReports, routeReports) + d.SetId(dataSourceIBMDirectLinkGatewayRouteReportsID(d)) + return nil +} + +// dataSourceIBMDirectLinkGatewayRouteReportsID returns a reasonable ID for a directlink gateways list. +func dataSourceIBMDirectLinkGatewayRouteReportsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/directlink/data_source_ibm_dl_route_reports_test.go b/ibm/service/directlink/data_source_ibm_dl_route_reports_test.go new file mode 100644 index 000000000..4acd65549 --- /dev/null +++ b/ibm/service/directlink/data_source_ibm_dl_route_reports_test.go @@ -0,0 +1,58 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMDLRouteReportsDataSource_basic(t *testing.T) { + node := "data.ibm_dl_route_reports.test_dl_reports" + gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDLRouteReportsDataSourceConfig(gatewayname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "route_reports.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMDLRouteReportsDataSourceConfig(gatewayname string) string { + return fmt.Sprintf(` + data "ibm_dl_ports" "ds_dlports" { + } + + resource ibm_dl_gateway test_dl_gateway { + bgp_asn = 64999 + global = true + metered = false + name = "%s" + speed_mbps = 1000 + type = "connect" + port = data.ibm_dl_ports.ds_dlports.ports[0].port_id + } + + resource ibm_dl_route_report dl_route_report { + gateway = ibm_dl_gateway.test_dl_gateway.id + } + + data "ibm_dl_route_reports" "test_dl_reports" { + gateway = ibm_dl_route_report.dl_route_report.gateway + } + + `, gatewayname) +} diff --git a/ibm/data_source_ibm_dl_routers.go b/ibm/service/directlink/data_source_ibm_dl_routers.go similarity index 78% rename from ibm/data_source_ibm_dl_routers.go rename to ibm/service/directlink/data_source_ibm_dl_routers.go index 4b87904cd..440f1d639 100644 --- a/ibm/data_source_ibm_dl_routers.go +++ b/ibm/service/directlink/data_source_ibm_dl_routers.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -19,7 +21,7 @@ const ( dlMacsecCapabilities = "capabilities" ) -func dataSourceIBMDLRouters() *schema.Resource { +func DataSourceIBMDLRouters() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMDLRoutersRead, Schema: map[string]*schema.Schema{ @@ -27,7 +29,7 @@ func dataSourceIBMDLRouters() *schema.Resource { Type: schema.TypeString, Required: true, Description: "The Direct Link offering type", - ValidateFunc: InvokeDataSourceValidator("ibm_dl_routers", dlOfferingType), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_dl_routers", dlOfferingType), }, dlLocation: { Type: schema.TypeString, @@ -77,14 +79,14 @@ func dataSourceIBMDLRoutersRead(d *schema.ResourceData, meta interface{}) error listRouters, detail, err := directLink.ListOfferingTypeLocationCrossConnectRouters(listRoutersOptionsModel) if err != nil { - return fmt.Errorf("Error Getting Direct Link Location Cross Connect Routers: %s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error Getting Direct Link Location Cross Connect Routers: %s\n%s", err, detail) } routers := make([]map[string]interface{}, 0) for _, instance := range listRouters.CrossConnectRouters { route := map[string]interface{}{} if instance.Capabilities != nil { - route[dlMacsecCapabilities] = flattenStringList(instance.Capabilities) + route[dlMacsecCapabilities] = flex.FlattenStringList(instance.Capabilities) } if instance.RouterName != nil { route[dlRouterName] = *instance.RouterName @@ -104,19 +106,19 @@ func dataSourceIBMDLRoutersID(d *schema.ResourceData) string { return time.Now().UTC().String() } -func datasourceIBMDLRoutersValidator() *ResourceValidator { +func DataSourceIBMDLRoutersValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) dlTypeAllowedValues := "dedicated" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlOfferingType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: dlTypeAllowedValues}) - ibmDLRoutersDatasourceValidator := ResourceValidator{ResourceName: "ibm_dl_routers", Schema: validateSchema} + ibmDLRoutersDatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_dl_routers", Schema: validateSchema} return &ibmDLRoutersDatasourceValidator } diff --git a/ibm/data_source_ibm_dl_routers_test.go b/ibm/service/directlink/data_source_ibm_dl_routers_test.go similarity index 84% rename from ibm/data_source_ibm_dl_routers_test.go rename to ibm/service/directlink/data_source_ibm_dl_routers_test.go index a7ab4c3b0..a9a6fba79 100644 --- a/ibm/data_source_ibm_dl_routers_test.go +++ b/ibm/service/directlink/data_source_ibm_dl_routers_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMDLRoutersDataSource_basic(t *testing.T) { node := "data.ibm_dl_routers.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMDLRoutersDataSourceConfig(), diff --git a/ibm/resource_ibm_dl_gateway.go b/ibm/service/directlink/resource_ibm_dl_gateway.go similarity index 82% rename from ibm/resource_ibm_dl_gateway.go rename to ibm/service/directlink/resource_ibm_dl_gateway.go index a5076be52..d5149511d 100644 --- a/ibm/resource_ibm_dl_gateway.go +++ b/ibm/service/directlink/resource_ibm_dl_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "context" @@ -12,64 +12,16 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -const ( - dlActive = "active" - dlAuthenticationKey = "authentication_key" - dlBfdInterval = "bfd_interval" - dlBfdMultiplier = "bfd_multiplier" - dlBfdStatus = "bfd_status" - dlBfdStatusUpdatedAt = "bfd_status_updated_at" - dlBgpAsn = "bgp_asn" - dlBgpBaseCidr = "bgp_base_cidr" - dlBgpCerCidr = "bgp_cer_cidr" - dlBgpIbmAsn = "bgp_ibm_asn" - dlBgpIbmCidr = "bgp_ibm_cidr" - dlBgpStatus = "bgp_status" - dlCarrierName = "carrier_name" - dlChangeRequest = "change_request" - dlCipherSuite = "cipher_suite" - dlCompletionNoticeRejectReason = "completion_notice_reject_reason" - dlConfidentialityOffset = "confidentiality_offset" - dlGatewayProvisioning = "configuring" - dlConnectionMode = "connection_mode" - dlCreatedAt = "created_at" - dlGatewayProvisioningRejected = "create_rejected" - dlCrossConnectRouter = "cross_connect_router" - dlCrn = "crn" - dlCryptographicAlgorithm = "cryptographic_algorithm" - dlCustomerName = "customer_name" - dlFallbackCak = "fallback_cak" - dlGlobal = "global" - dlKeyServerPriority = "key_server_priority" - dlLoaRejectReason = "loa_reject_reason" - dlLocationDisplayName = "location_display_name" - dlLocationName = "location_name" - dlLinkStatus = "link_status" - dlMacSecConfig = "macsec_config" - dlMetered = "metered" - dlName = "name" - dlOperationalStatus = "operational_status" - dlPort = "port" - dlPrimaryCak = "primary_cak" - dlProviderAPIManaged = "provider_api_managed" - dlGatewayProvisioningDone = "provisioned" - dlResourceGroup = "resource_group" - dlSakExpiryTime = "sak_expiry_time" - dlSpeedMbps = "speed_mbps" - dlMacSecConfigStatus = "status" - dlTags = "tags" - dlType = "type" - dlVlan = "vlan" - dlWindowSize = "window_size" -) - -func resourceIBMDLGateway() *schema.Resource { +func ResourceIBMDLGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMdlGatewayCreate, Read: resourceIBMdlGatewayRead, @@ -86,7 +38,7 @@ func resourceIBMDLGateway() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -97,19 +49,66 @@ func resourceIBMDLGateway() *schema.Resource { ForceNew: false, Description: "BGP MD5 authentication key", }, + dlAsPrepends: { + Type: schema.TypeList, + Optional: true, + ForceNew: false, + Description: "List of AS Prepend configuration information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was created", + }, + dlResourceId: { + Type: schema.TypeString, + Optional: true, + ForceNew: false, + Computed: true, + Description: "The unique identifier for this AS Prepend", + }, + dlLength: { + Type: schema.TypeInt, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlLength), + Description: "Number of times the ASN to appended to the AS Path", + }, + dlPolicy: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlPolicy), + Description: "Route type this AS Prepend applies to", + }, + dlPrefix: { + Type: schema.TypeString, + Optional: true, + ForceNew: false, + Description: "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time AS Prepend was updated", + }, + }, + }, + }, dlBfdInterval: { Type: schema.TypeInt, Optional: true, ForceNew: false, Description: "BFD Interval", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlBfdInterval), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlBfdInterval), }, dlBfdMultiplier: { Type: schema.TypeInt, Optional: true, ForceNew: false, Description: "BFD Multiplier", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlBfdMultiplier), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlBfdMultiplier), }, dlBfdStatus: { Type: schema.TypeString, @@ -132,7 +131,7 @@ func resourceIBMDLGateway() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: false, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "BGP base CIDR", }, dlPort: { @@ -149,7 +148,7 @@ func resourceIBMDLGateway() *schema.Resource { Optional: true, ForceNew: false, Description: "Type of services this Gateway is attached to. Mode transit means this Gateway will be attached to Transit Gateway Service and direct means this Gateway will be attached to vpc or classic connection", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlConnectionMode), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlConnectionMode), }, dlCrossConnectRouter: { Type: schema.TypeString, @@ -181,7 +180,7 @@ func resourceIBMDLGateway() *schema.Resource { Required: true, ForceNew: false, Description: "The unique user-defined name for this gateway", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlName), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlName), // ValidateFunc: validateRegexpLen(1, 63, "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$"), }, dlCarrierName: { @@ -209,8 +208,8 @@ func resourceIBMDLGateway() *schema.Resource { Required: true, ForceNew: true, Description: "Gateway type", - ValidateFunc: InvokeValidator("ibm_dl_gateway", dlType), - // ValidateFunc: validateAllowedStringValue([]string{"dedicated", "connect"}), + ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlType), + // ValidateFunc: validate.ValidateAllowedStringValues([]string{"dedicated", "connect"}), }, dlMacSecConfig: { Type: schema.TypeList, @@ -376,35 +375,35 @@ func resourceIBMDLGateway() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_dl_gateway", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_dl_gateway", dlTags)}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the direct link gateway", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -413,67 +412,84 @@ func resourceIBMDLGateway() *schema.Resource { } } -func resourceIBMDLGatewayValidator() *ResourceValidator { +func ResourceIBMDLGatewayValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) dlTypeAllowedValues := "dedicated, connect" dlConnectionModeAllowedValues := "direct, transit" + dlPolicyAllowedValues := "export, import" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: dlTypeAllowedValues}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlConnectionMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: dlConnectionModeAllowedValues}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlBfdInterval, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "300", MaxValue: "255000"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlBfdMultiplier, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Required: true, MinValue: "1", MaxValue: "255"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: dlPolicy, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: dlPolicyAllowedValues}) - ibmISDLGatewayResourceValidator := ResourceValidator{ResourceName: "ibm_dl_gateway", Schema: validateSchema} + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: dlLength, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Required: true, + MinValue: "3", + MaxValue: "10"}) + + ibmISDLGatewayResourceValidator := validate.ResourceValidator{ResourceName: "ibm_dl_gateway", Schema: validateSchema} return &ibmISDLGatewayResourceValidator } func directlinkClient(meta interface{}) (*directlinkv1.DirectLinkV1, error) { - sess, err := meta.(ClientSession).DirectlinkV1API() + sess, err := meta.(conns.ClientSession).DirectlinkV1API() return sess, err } @@ -508,13 +524,27 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error bfdConfig.Multiplier = &multiplier } + asPrependsCreateItems := make([]directlinkv1.AsPrependTemplate, 0) + if asPrependsInput, ok := d.GetOk(dlAsPrepends); ok { + asPrependsItems := asPrependsInput.([]interface{}) + + for _, asPrependItem := range asPrependsItems { + i := asPrependItem.(map[string]interface{}) + asPrependsCreateItems = append(asPrependsCreateItems, directlinkv1.AsPrependTemplate{ + Length: NewInt64Pointer(int64(i[dlLength].(int))), + Policy: NewStrPointer(i[dlPolicy].(string)), + Prefix: NewStrPointer(i[dlPrefix].(string)), + }) + } + } + if dtype == "dedicated" { var crossConnectRouter, carrierName, locationName, customerName string if _, ok := d.GetOk(dlCarrierName); ok { carrierName = d.Get(dlCarrierName).(string) // gatewayTemplateModel.CarrierName = &carrierName } else { - err = fmt.Errorf("Error creating gateway, %s is a required field", dlCarrierName) + err = fmt.Errorf("[ERROR] Error creating gateway, %s is a required field", dlCarrierName) log.Printf("%s is a required field", dlCarrierName) return err } @@ -522,7 +552,7 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error crossConnectRouter = d.Get(dlCrossConnectRouter).(string) // gatewayTemplateModel.CrossConnectRouter = &crossConnectRouter } else { - err = fmt.Errorf("Error creating gateway, %s is a required field", dlCrossConnectRouter) + err = fmt.Errorf("[ERROR] Error creating gateway, %s is a required field", dlCrossConnectRouter) log.Printf("%s is a required field", dlCrossConnectRouter) return err } @@ -530,7 +560,7 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error locationName = d.Get(dlLocationName).(string) //gatewayTemplateModel.LocationName = &locationName } else { - err = fmt.Errorf("Error creating gateway, %s is a required field", dlLocationName) + err = fmt.Errorf("[ERROR] Error creating gateway, %s is a required field", dlLocationName) log.Printf("%s is a required field", dlLocationName) return err } @@ -538,7 +568,7 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error customerName = d.Get(dlCustomerName).(string) //gatewayTemplateModel.CustomerName = &customerName } else { - err = fmt.Errorf("Error creating gateway, %s is a required field", dlCustomerName) + err = fmt.Errorf("[ERROR] Error creating gateway, %s is a required field", dlCustomerName) log.Printf("%s is a required field", dlCustomerName) return err } @@ -603,6 +633,10 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error gatewayDedicatedTemplateModel.BfdConfig = &bfdConfig } + if len(asPrependsCreateItems) > 0 { + gatewayDedicatedTemplateModel.AsPrepends = asPrependsCreateItems + } + createGatewayOptionsModel.GatewayTemplate = gatewayDedicatedTemplateModel } else if dtype == "connect" { @@ -648,10 +682,14 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error gatewayConnectTemplateModel.BfdConfig = &bfdConfig } + if len(asPrependsCreateItems) > 0 { + gatewayConnectTemplateModel.AsPrepends = asPrependsCreateItems + } + createGatewayOptionsModel.GatewayTemplate = gatewayConnectTemplateModel } else { - err = fmt.Errorf("Error creating direct link connect gateway, %s is a required field", dlPort) + err = fmt.Errorf("[ERROR] Error creating direct link connect gateway, %s is a required field", dlPort) return err } } @@ -681,7 +719,7 @@ func resourceIBMdlGatewayCreate(d *schema.ResourceData, meta interface{}) error v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(dlTags); ok || v != "" { oldList, newList := d.GetChange(dlTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *gateway.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *gateway.Crn) if err != nil { log.Printf( "Error on create of resource direct link gateway %s (%s) tags: %s", dtype, d.Id(), err) @@ -713,7 +751,7 @@ func resourceIBMdlGatewayRead(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting Direct Link Gateway (%s Template): %s\n%s", dtype, err, response) + return fmt.Errorf("[ERROR] Error Getting Direct Link Gateway (%s Template): %s\n%s", dtype, err, response) } if instance.Name != nil { d.Set(dlName, *instance.Name) @@ -787,6 +825,24 @@ func resourceIBMdlGatewayRead(d *schema.ResourceData, meta interface{}) error { if instance.ConnectionMode != nil { d.Set(dlConnectionMode, *instance.ConnectionMode) } + + asPrependList := make([]map[string]interface{}, 0) + if len(instance.AsPrepends) > 0 { + for _, asPrepend := range instance.AsPrepends { + asPrependItem := map[string]interface{}{} + asPrependItem[dlResourceId] = asPrepend.ID + asPrependItem[dlLength] = asPrepend.Length + asPrependItem[dlPrefix] = asPrepend.Prefix + asPrependItem[dlPolicy] = asPrepend.Policy + asPrependItem[dlCreatedAt] = asPrepend.CreatedAt.String() + asPrependItem[dlUpdatedAt] = asPrepend.UpdatedAt.String() + + asPrependList = append(asPrependList, asPrependItem) + } + + } + d.Set(dlAsPrepends, asPrependList) + if dtype == "dedicated" { if instance.MacsecConfig != nil { macsecList := make([]map[string]interface{}, 0) @@ -842,24 +898,24 @@ func resourceIBMdlGatewayRead(d *schema.ResourceData, meta interface{}) error { gatewayChangeRequest := gatewayChangeRequestIntf.(*directlinkv1.GatewayChangeRequest) d.Set(dlChangeRequest, *gatewayChangeRequest.Type) } - tags, err := GetTagsUsingCRN(meta, *instance.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *instance.Crn) if err != nil { log.Printf( "Error on get of resource direct link gateway (%s) tags: %s", d.Id(), err) } d.Set(dlTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/interconnectivity/direct-link") - d.Set(ResourceName, *instance.Name) - d.Set(ResourceCRN, *instance.Crn) - d.Set(ResourceStatus, *instance.OperationalStatus) + d.Set(flex.ResourceControllerURL, controller+"/interconnectivity/direct-link") + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.Crn) + d.Set(flex.ResourceStatus, *instance.OperationalStatus) if instance.ResourceGroup != nil { rg := instance.ResourceGroup d.Set(dlResourceGroup, *rg.ID) - d.Set(ResourceGroupName, *rg.ID) + d.Set(flex.ResourceGroupName, *rg.ID) } //Show the BFD Config parameters if set @@ -902,7 +958,7 @@ func isDirectLinkRefreshFunc(client *directlinkv1.DirectLinkV1, id string) resou } instance, response, err := client.GetGateway(getOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Direct Link: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Direct Link: %s\n%s", err, response) } if *instance.OperationalStatus == "provisioned" || *instance.OperationalStatus == "failed" || *instance.OperationalStatus == "create_rejected" { return instance, dlGatewayProvisioningDone, nil @@ -935,7 +991,7 @@ func resourceIBMdlGatewayUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChange(dlTags) { oldList, newList := d.GetChange(dlTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) if err != nil { log.Printf( "Error on update of resource direct link gateway (%s) tags: %s", *instance.ID, err) @@ -1101,7 +1157,7 @@ func resourceIBMdlGatewayExists(d *schema.ResourceData, meta interface{}) (bool, d.SetId("") return false, nil } - return false, fmt.Errorf("Error Getting Direct Link Gateway : %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Direct Link Gateway : %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_dl_gateway_test.go b/ibm/service/directlink/resource_ibm_dl_gateway_test.go similarity index 86% rename from ibm/resource_ibm_dl_gateway_test.go rename to ibm/service/directlink/resource_ibm_dl_gateway_test.go index 3bfda92d6..cd97ec71c 100644 --- a/ibm/resource_ibm_dl_gateway_test.go +++ b/ibm/service/directlink/resource_ibm_dl_gateway_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "errors" @@ -9,6 +9,9 @@ import ( "log" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -23,8 +26,8 @@ func TestAccIBMDLGateway_basic(t *testing.T) { carriername := fmt.Sprintf("carrier-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDLGatewayDestroy, // Delete test case Steps: []resource.TestStep{ { @@ -53,8 +56,8 @@ func TestAccIBMDLGatewayConnect_basic(t *testing.T) { connectgatewayname := fmt.Sprintf("gateway-connect-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDLGatewayDestroy, // Delete test case Steps: []resource.TestStep{ @@ -107,6 +110,10 @@ func testAccCheckIBMDLConnectGatewayConfig(gatewayname string) string { } `, gatewayname) } +func directlinkClient(meta interface{}) (*directlinkv1.DirectLinkV1, error) { + sess, err := meta.(conns.ClientSession).DirectlinkV1API() + return sess, err +} func testAccCheckIBMDLGatewayExists(n string, instance string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -117,7 +124,7 @@ func testAccCheckIBMDLGatewayExists(n string, instance string) resource.TestChec if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - directLink, err := directlinkClient(testAccProvider.Meta()) + directLink, err := directlinkClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -126,7 +133,7 @@ func testAccCheckIBMDLGatewayExists(n string, instance string) resource.TestChec } instance1, response, err := directLink.GetGateway(getOptions) if err != nil { - return fmt.Errorf("Error Getting Direct Link Gateway (Dedicated Template): %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Direct Link Gateway (Dedicated Template): %s\n%s", err, response) } instance = *instance1.ID return nil @@ -134,7 +141,7 @@ func testAccCheckIBMDLGatewayExists(n string, instance string) resource.TestChec } func testAccCheckIBMDLGatewayDestroy(s *terraform.State) error { - directLink, err := directlinkClient(testAccProvider.Meta()) + directLink, err := directlinkClient(acc.TestAccProvider.Meta()) if err != nil { return err } diff --git a/ibm/resource_ibm_dl_gateway_virtual_connection.go b/ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection.go similarity index 82% rename from ibm/resource_ibm_dl_gateway_virtual_connection.go rename to ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection.go index 1eda4e9c0..911ac91be 100644 --- a/ibm/resource_ibm_dl_gateway_virtual_connection.go +++ b/ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection.go @@ -1,31 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -const ( - dlGatewaysVirtualConnections = "gateway_vcs" - dlVCNetworkAccount = "network_account" - dlVCNetworkId = "network_id" - dlVCName = "name" - dlVCType = "type" - dlVCCreatedAt = "created_at" - dlVCStatus = "status" - dlGatewayId = "gateway" - ID = "id" - dlVirtualConnectionId = "virtual_connection_id" -) - -func resourceIBMDLGatewayVC() *schema.Resource { +func ResourceIBMDLGatewayVC() *schema.Resource { return &schema.Resource{ Create: resourceIBMdlGatewayVCCreate, Read: resourceIBMdlGatewayVCRead, @@ -51,14 +40,14 @@ func resourceIBMDLGatewayVC() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_dl_virtual_connection", dlVCType), + ValidateFunc: validate.InvokeValidator("ibm_dl_virtual_connection", dlVCType), Description: "The type of virtual connection.Allowable values (classic,vpc)", }, dlVCName: { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_dl_virtual_connection", dlVCName), + ValidateFunc: validate.InvokeValidator("ibm_dl_virtual_connection", dlVCName), Description: "The user-defined name for this virtual connection. Virtualconnection names are unique within a gateway. This is the name of thevirtual connection itself, the network being connected may have its ownname attribute", }, dlVCNetworkId: { @@ -90,7 +79,7 @@ func resourceIBMDLGatewayVC() *schema.Resource { Description: "The Direct Gateway virtual connection identifier", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the Direct link gateway", @@ -98,28 +87,28 @@ func resourceIBMDLGatewayVC() *schema.Resource { }, } } -func resourceIBMdlGatewayVCValidator() *ResourceValidator { +func ResourceIBMDLGatewayVCValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) vcType := "classic, vpc" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlVCType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: vcType}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlVCName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) - ibmDLGatewayVCResourceValidator := ResourceValidator{ResourceName: "ibm_dl_virtual_connection", Schema: validateSchema} + ibmDLGatewayVCResourceValidator := validate.ResourceValidator{ResourceName: "ibm_dl_virtual_connection", Schema: validateSchema} return &ibmDLGatewayVCResourceValidator } @@ -160,7 +149,7 @@ func resourceIBMdlGatewayVCRead(d *schema.ResourceData, meta interface{}) error if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -177,7 +166,7 @@ func resourceIBMdlGatewayVCRead(d *schema.ResourceData, meta interface{}) error d.SetId("") return nil } - return fmt.Errorf("Error Getting Directlink Gateway Connection (%s): %s\n%s", ID, err, response) + return fmt.Errorf("[ERROR] Error Getting Directlink Gateway Connection (%s): %s\n%s", ID, err, response) } if instance.Name != nil { @@ -205,9 +194,9 @@ func resourceIBMdlGatewayVCRead(d *schema.ResourceData, meta interface{}) error } dlgw, response, err := directLink.GetGateway(getGatewayOptions) if err != nil { - return fmt.Errorf("Error Getting Direct Link Gateway (Dedicated Template): %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Direct Link Gateway (Dedicated Template): %s\n%s", err, response) } - d.Set(RelatedCRN, *dlgw.Crn) + d.Set(flex.RelatedCRN, *dlgw.Crn) return nil } @@ -217,7 +206,7 @@ func resourceIBMdlGatewayVCUpdate(d *schema.ResourceData, meta interface{}) erro if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -261,7 +250,7 @@ func resourceIBMdlGatewayVCDelete(d *schema.ResourceData, meta interface{}) erro if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -288,12 +277,12 @@ func resourceIBMdlGatewayVCExists(d *schema.ResourceData, meta interface{}) (boo if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of gatewayID/gatewayVCID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of gatewayID/gatewayVCID", d.Id()) } gatewayId := parts[0] ID := parts[1] @@ -308,7 +297,7 @@ func resourceIBMdlGatewayVCExists(d *schema.ResourceData, meta interface{}) (boo d.SetId("") return false, nil } - return false, fmt.Errorf("Error Getting Direct Link Gateway (Dedicated Template) Virtual Connection: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Direct Link Gateway (Dedicated Template) Virtual Connection: %s\n%s", err, response) } if response.StatusCode == 404 { diff --git a/ibm/resource_ibm_dl_gateway_virtual_connection_test.go b/ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection_test.go similarity index 91% rename from ibm/resource_ibm_dl_gateway_virtual_connection_test.go rename to ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection_test.go index b0c58e550..d404d1742 100644 --- a/ibm/resource_ibm_dl_gateway_virtual_connection_test.go +++ b/ibm/service/directlink/resource_ibm_dl_gateway_virtual_connection_test.go @@ -1,15 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/directlinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMDLGatewayVC_basic(t *testing.T) { @@ -23,12 +27,12 @@ func TestAccIBMDLGatewayVC_basic(t *testing.T) { updvcName := fmt.Sprintf("vc-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDLGatewayVCDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { //Create test case Config: testAccCheckIBMDLGatewayVCConfig(vctype, vcName, gatewayname, custname, carriername, vpcname), @@ -38,7 +42,7 @@ func TestAccIBMDLGatewayVC_basic(t *testing.T) { ), }, //update - resource.TestStep{ + { Config: testAccCheckIBMDLGatewayVCUpdate(vctype, updvcName, gatewayname, custname, carriername, vpcname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMDLGatewayVCExists("ibm_dl_virtual_connection.test_dl_gateway_vc", virtualConnection), @@ -84,7 +88,7 @@ func testAccCheckIBMDLGatewayVCConfig(vctype, vcName, gatewayname, custname, car } func testAccCheckIBMDLGatewayVCDestroy(s *terraform.State) error { - directLink, err := directlinkClient(testAccProvider.Meta()) + directLink, err := directlinkClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -93,7 +97,7 @@ func testAccCheckIBMDLGatewayVCDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -115,7 +119,7 @@ func testAccCheckIBMDLGatewayVCDestroy(s *terraform.State) error { func testAccCheckIBMDLGatewayVCExists(n string, vc string) resource.TestCheckFunc { return func(s *terraform.State) error { - directLink, err := directlinkClient(testAccProvider.Meta()) + directLink, err := directlinkClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -123,7 +127,7 @@ func testAccCheckIBMDLGatewayVCExists(n string, vc string) resource.TestCheckFun if !ok { return fmt.Errorf("Not found: %s", n) } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -187,18 +191,18 @@ func TestAccIBMDLGatewayVCImport(t *testing.T) { vctype := "vpc" vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDLGatewayVCDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMDLGatewayVCConfig(vctype, vcName, gatewayname, custname, carriername, vpcname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMDLGatewayVCExists("ibm_dl_virtual_connection.test_dl_gateway_vc", virtualConnection), resource.TestCheckResourceAttr("ibm_dl_virtual_connection.test_dl_gateway_vc", "name", vcName), ), }, - resource.TestStep{ + { ResourceName: "ibm_dl_virtual_connection.test_dl_gateway_vc", ImportState: true, ImportStateVerify: true, diff --git a/ibm/resource_ibm_dl_provider_gateway.go b/ibm/service/directlink/resource_ibm_dl_provider_gateway.go similarity index 81% rename from ibm/resource_ibm_dl_provider_gateway.go rename to ibm/service/directlink/resource_ibm_dl_provider_gateway.go index 07bd6674b..73fa81f4a 100644 --- a/ibm/resource_ibm_dl_provider_gateway.go +++ b/ibm/service/directlink/resource_ibm_dl_provider_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink import ( "context" @@ -9,15 +9,13 @@ import ( "log" "os" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -const ( - customerAccountID = "customer_account_id" -) - -func resourceIBMDLProviderGateway() *schema.Resource { +func ResourceIBMDLProviderGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMdlProviderGatewayCreate, Read: resourceIBMdlProviderGatewayRead, @@ -27,7 +25,7 @@ func resourceIBMDLProviderGateway() *schema.Resource { Importer: &schema.ResourceImporter{}, CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -75,10 +73,9 @@ func resourceIBMDLProviderGateway() *schema.Resource { Required: true, ForceNew: false, Description: "The unique user-defined name for this gateway", - ValidateFunc: InvokeValidator("ibm_dl_provider_gateway", dlName), + ValidateFunc: validate.InvokeValidator("ibm_dl_provider_gateway", dlName), // ValidateFunc: validateRegexpLen(1, 63, "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$"), }, - dlSpeedMbps: { Type: schema.TypeInt, Required: true, @@ -90,7 +87,7 @@ func resourceIBMDLProviderGateway() *schema.Resource { Required: true, ForceNew: true, Description: "Customer IBM Cloud account ID for the new gateway. A gateway object containing the pending create request will become available in the specified account.", - ValidateFunc: InvokeValidator("ibm_dl_provider_gateway", customerAccountID), + ValidateFunc: validate.InvokeValidator("ibm_dl_provider_gateway", customerAccountID), }, dlOperationalStatus: { Type: schema.TypeString, @@ -109,6 +106,7 @@ func resourceIBMDLProviderGateway() *schema.Resource { }, dlVlan: { Type: schema.TypeInt, + Optional: true, Computed: true, Description: "VLAN allocated for this gateway", }, @@ -121,35 +119,35 @@ func resourceIBMDLProviderGateway() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_dl_provider_gateway", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_dl_provider_gateway", dlTags)}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the direct link gateway", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -158,39 +156,39 @@ func resourceIBMDLProviderGateway() *schema.Resource { } } -func resourceIBMDLProviderGatewayValidator() *ResourceValidator { +func ResourceIBMDLProviderGatewayValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: customerAccountID, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^[0-9a-f]+$`, MinValueLength: 1, MaxValueLength: 32}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: dlName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: dlTags, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISDLGatewayResourceValidator := ResourceValidator{ResourceName: "ibm_dl_provider_gateway", Schema: validateSchema} + ibmISDLGatewayResourceValidator := validate.ResourceValidator{ResourceName: "ibm_dl_provider_gateway", Schema: validateSchema} return &ibmISDLGatewayResourceValidator } @@ -203,8 +201,8 @@ func resourceIBMdlProviderGatewayCreate(d *schema.ResourceData, meta interface{} speed := int64(d.Get(dlSpeedMbps).(int)) custAccountID := d.Get(customerAccountID).(string) bgpAsn := int64(d.Get(dlBgpAsn).(int)) - var portID string - portID = d.Get(dlPort).(string) + // var portID string + portID := d.Get(dlPort).(string) portIdentity, _ := directLink.NewProviderGatewayPortIdentity(portID) gatewayOptions := directLink.NewCreateProviderGatewayOptions(bgpAsn, custAccountID, name, portIdentity, speed) if _, ok := d.GetOk(dlBgpIbmCidr); ok { @@ -218,6 +216,12 @@ func resourceIBMdlProviderGatewayCreate(d *schema.ResourceData, meta interface{} } + if _, ok := d.GetOk(dlVlan); ok { + vlan := int64(d.Get(dlVlan).(int)) + gatewayOptions.Vlan = &vlan + + } + gateway, response, err := directLink.CreateProviderGateway(gatewayOptions) if err != nil { log.Printf("[DEBUG] Create Direct Link Provider Gateway err %s\n%s", err, response) @@ -230,7 +234,7 @@ func resourceIBMdlProviderGatewayCreate(d *schema.ResourceData, meta interface{} v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(dlTags); ok || v != "" { oldList, newList := d.GetChange(dlTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *gateway.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *gateway.Crn) if err != nil { log.Printf( "Error on create of resource direct link Provider gateway (%s) tags: %s", d.Id(), err) @@ -261,7 +265,7 @@ func resourceIBMdlProviderGatewayRead(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error Getting Direct Link Gateway (%s Template): %s\n%s", dtype, err, response) + return fmt.Errorf("[ERROR] Error Getting Direct Link Gateway (%s Template): %s\n%s", dtype, err, response) } if instance.Name != nil { d.Set(dlName, *instance.Name) @@ -278,7 +282,6 @@ func resourceIBMdlProviderGatewayRead(d *schema.ResourceData, meta interface{}) if instance.BgpIbmAsn != nil { d.Set(dlBgpIbmAsn, *instance.BgpIbmAsn) } - if instance.BgpCerCidr != nil { d.Set(dlBgpCerCidr, *instance.BgpCerCidr) } @@ -311,20 +314,20 @@ func resourceIBMdlProviderGatewayRead(d *schema.ResourceData, meta interface{}) if instance.CreatedAt != nil { d.Set(dlCreatedAt, instance.CreatedAt.String()) } - tags, err := GetTagsUsingCRN(meta, *instance.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *instance.Crn) if err != nil { log.Printf( "Error on get of resource direct link gateway (%s) tags: %s", d.Id(), err) } d.Set(dlTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/interconnectivity/direct-link") - d.Set(ResourceName, *instance.Name) - d.Set(ResourceCRN, *instance.Crn) - d.Set(ResourceStatus, *instance.OperationalStatus) + d.Set(flex.ResourceControllerURL, controller+"/interconnectivity/direct-link") + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.Crn) + d.Set(flex.ResourceStatus, *instance.OperationalStatus) return nil } @@ -341,12 +344,15 @@ func resourceIBMdlProviderGatewayUpdate(d *schema.ResourceData, meta interface{} log.Printf("[INFO] Calling getgateway provider api") instance, response, err := directLink.GetProviderGateway(getOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting provider gateway %s, %s", err, response) + } updateGatewayOptionsModel := directLink.NewUpdateProviderGatewayOptions(ID) if d.HasChange(dlTags) { oldList, newList := d.GetChange(dlTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) if err != nil { log.Printf( "Error on update of resource direct link gateway dedicated (%s) tags: %s", *instance.ID, err) @@ -373,7 +379,10 @@ func resourceIBMdlProviderGatewayUpdate(d *schema.ResourceData, meta interface{} bgpIbmCidr := d.Get(dlBgpIbmCidr).(string) updateGatewayOptionsModel.BgpIbmCidr = &bgpIbmCidr } - + if d.HasChange(dlVlan) { + vlan := int64(d.Get(dlVlan).(int)) + updateGatewayOptionsModel.Vlan = &vlan + } _, response, err = directLink.UpdateProviderGateway(updateGatewayOptionsModel) if err != nil { log.Printf("[DEBUG] Update Direct Link Provider Gateway err %s\n%s", err, response) @@ -419,7 +428,7 @@ func resourceIBMdlProviderGatewayExists(d *schema.ResourceData, meta interface{} d.SetId("") return false, nil } - return false, fmt.Errorf("Error Getting Direct Link Provider Gateway : %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Direct Link Provider Gateway : %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_dl_provider_gateway_test.go b/ibm/service/directlink/resource_ibm_dl_provider_gateway_test.go similarity index 78% rename from ibm/resource_ibm_dl_provider_gateway_test.go rename to ibm/service/directlink/resource_ibm_dl_provider_gateway_test.go index 88b19b335..749220c99 100644 --- a/ibm/resource_ibm_dl_provider_gateway_test.go +++ b/ibm/service/directlink/resource_ibm_dl_provider_gateway_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package directlink_test import ( "errors" @@ -9,6 +9,10 @@ import ( "log" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,8 +25,8 @@ func TestAccIBMDLProviderGateway_basic(t *testing.T) { custAccID := "3f455c4c574447adbc14bda52f80e62f" // bbsdldv1 account resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMDLProviderGatewayDestroy, // Delete test case Steps: []resource.TestStep{ { @@ -49,11 +53,15 @@ func testAccCheckIBMDLProviderGatewayConfig(gatewayname, custAccID string) strin customer_account_id = "%s" speed_mbps = 1000 port = data.ibm_dl_provider_ports.test_ds_dl_ports.ports[0].port_id + vlan = 25 } `, gatewayname, custAccID) } - +func directlinkProviderClient(meta interface{}) (*dlProviderV2.DirectLinkProviderV2, error) { + sess, err := meta.(conns.ClientSession).DirectlinkProviderV2API() + return sess, err +} func testAccCheckIBMDLProviderGatewayExists(n string, instance string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -63,7 +71,7 @@ func testAccCheckIBMDLProviderGatewayExists(n string, instance string) resource. if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - directLink, err := directlinkProviderClient(testAccProvider.Meta()) + directLink, err := directlinkProviderClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -72,7 +80,7 @@ func testAccCheckIBMDLProviderGatewayExists(n string, instance string) resource. instance1, response, err := directLink.GetProviderGateway(getOptions) if err != nil { - return fmt.Errorf("Error Getting Direct Link Provider Gateway: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Direct Link Provider Gateway: %s\n%s", err, response) } instance = *instance1.ID return nil @@ -80,7 +88,7 @@ func testAccCheckIBMDLProviderGatewayExists(n string, instance string) resource. } func testAccCheckIBMDLProviderGatewayDestroy(s *terraform.State) error { - directLink, err := directlinkProviderClient(testAccProvider.Meta()) + directLink, err := directlinkProviderClient(acc.TestAccProvider.Meta()) if err != nil { return err } diff --git a/ibm/service/directlink/resource_ibm_dl_route_report.go b/ibm/service/directlink/resource_ibm_dl_route_report.go new file mode 100644 index 000000000..45edd2ce3 --- /dev/null +++ b/ibm/service/directlink/resource_ibm_dl_route_report.go @@ -0,0 +1,383 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink + +import ( + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/directlinkv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMDLGatewayRouteReport() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMdlGatewayRouteReportCreate, + Read: resourceIBMDLRouteReportRead, + Delete: resourceIBMdlGatewayRouteReportDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + dlGatewayId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The Direct Link gateway identifier", + }, + dlRouteReportId: { + Type: schema.TypeString, + Computed: true, + Description: "Id of the route report", + }, + dlGatewayRoutes: { + Type: schema.TypeList, + Description: "List of gateway routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for gateway routes", + }, + }, + }, + }, + dlOnPremRoutes: { + Type: schema.TypeList, + Description: "List of onprem routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for onprem routes", + }, + dlRouteReportNextHop: { + Type: schema.TypeString, + Computed: true, + Description: "Next Hop address", + }, + }, + }, + }, + dlOverlappingRoutes: { + Type: schema.TypeList, + Description: "List of overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "overlapping routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + dlType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of route", + }, + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + }, + }, + }, + }, + }, + }, + dlVirtualConnectionRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual Connection Routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlVirtualConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection ID", + }, + dlVirtualConnectionType: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection type", + }, + dlVirtualConnectionName: { + Type: schema.TypeString, + Computed: true, + Description: "Virtual connection name", + }, + dlRoutes: { + Type: schema.TypeList, + Computed: true, + Description: "Virtual connection routes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + dlPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "Prefix for overlapping routes", + }, + }, + }, + }, + }, + }, + }, + dlRouteReportStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Route report status", + }, + dlCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time report was created", + }, + dlUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time resource was created", + }, + }, + } +} + +func resourceIBMdlGatewayRouteReportCreate(d *schema.ResourceData, meta interface{}) error { + directLink, err := directlinkClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(dlGatewayId).(string) + createGatewayRouteReportOptionsModel := &directlinkv1.CreateGatewayRouteReportOptions{GatewayID: &gatewayId} + routeReport, response, err := directLink.CreateGatewayRouteReport(createGatewayRouteReportOptionsModel) + if err != nil { + log.Println("[DEBUG] Create Route Report for DirectLink gateway", gatewayId, "err: ", err, " with response code:", response.StatusCode) + return fmt.Errorf("[ERROR] Create Route Report for DirectLink gateway(%s) err: %s with response code: %d", gatewayId, err, response.StatusCode) + } + + if routeReport == nil { + return fmt.Errorf("error creating route report for gateway: %s with response code: %d", gatewayId, response.StatusCode) + } else if routeReport.ID != nil { + d.SetId(fmt.Sprintf("%s/%s", gatewayId, *routeReport.ID)) + d.Set(dlRouteReportId, *routeReport.ID) + } + + isWaitForDirectLinkGatewayRouteReportCompleted(directLink, d.Id(), d.Timeout(schema.TimeoutCreate)) + + return resourceIBMDLRouteReportRead(d, meta) +} + +func isWaitForDirectLinkGatewayRouteReportCompleted(client *directlinkv1.DirectLinkV1, ID string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for direct link route report to be completed for (%s) ", ID) + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", dlRouteReportPending}, + Target: []string{dlRouteReportComplete, ""}, + Refresh: isDirectLinkGatewayRouteReportRefreshFunc(client, ID), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} +func isDirectLinkGatewayRouteReportRefreshFunc(client *directlinkv1.DirectLinkV1, ID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + parts, err := flex.IdParts(ID) + if err != nil { + return nil, "", fmt.Errorf("error getting ID for directlink route report: %s", err) + } + + gatewayId := parts[0] + routeReportId := parts[1] + + getOptions := &directlinkv1.GetGatewayRouteReportOptions{ + GatewayID: &gatewayId, + ID: &routeReportId, + } + routeReport, response, err := client.GetGatewayRouteReport(getOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] error fetching directlink route report: %s\n%s", err, response) + } + if *routeReport.Status == "complete" { + return routeReport, dlRouteReportComplete, nil + } + return routeReport, dlRouteReportPending, nil + } +} + +func resourceIBMDLRouteReportRead(d *schema.ResourceData, meta interface{}) error { + directLink, err := directlinkClient(meta) + if err != nil { + return err + } + + log.Println("[Info] Fetching DL Route Report GW ID:") + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + gatewayId := parts[0] + routeReportId := parts[1] + + log.Println("[Info] Fetching DL Route Report GW ID:", gatewayId, " and Report ID: ", routeReportId) + + getGatewayRouteReportOptionsModel := &directlinkv1.GetGatewayRouteReportOptions{GatewayID: &gatewayId, ID: &routeReportId} + report, response, err := directLink.GetGatewayRouteReport(getGatewayRouteReportOptionsModel) + + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Println("[ERROR] Unable to fetch route report for directlink gateway with err:", err) + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error fetching DL Route Reports for gateway(%s) err: %s with response code %d", gatewayId, err, response.StatusCode) + } + + if report == nil { + return fmt.Errorf("error fetching route report for gateway: %s and route report: %s with response code: %d", gatewayId, routeReportId, response.StatusCode) + } + + if report.Status != nil { + log.Println("[Info] Fetching DL Route Reports status:", *report.Status) + d.Set(dlRouteReportStatus, *report.Status) + } + + // Build Gateway Routes + gatewayRoutes := make([]map[string]interface{}, 0) + if report.GatewayRoutes != nil { + for _, gatewayRoute := range report.GatewayRoutes { + route := map[string]interface{}{} + route[dlPrefix] = gatewayRoute.Prefix + gatewayRoutes = append(gatewayRoutes, route) + } + } + + log.Println("[Info] Length DL Gateway Reports: ", len(gatewayRoutes)) + d.Set(dlGatewayRoutes, gatewayRoutes) + + // Build onPrem Routes + onPremRoutes := make([]map[string]interface{}, 0) + if report.OnPremRoutes != nil { + for _, onPremRoute := range report.OnPremRoutes { + route := map[string]interface{}{} + route[dlPrefix] = onPremRoute.Prefix + onPremRoutes = append(onPremRoutes, route) + } + + } + + log.Println("[Info] Length DL Route Reports onprem routes:", len(onPremRoutes)) + d.Set(dlOnPremRoutes, onPremRoutes) + + // Build Overlapping Routes + overlappingRoutesCollection := make([]map[string]interface{}, 0) + if report.OverlappingRoutes != nil && len(report.OverlappingRoutes) > 0 { + + for _, o := range report.OverlappingRoutes { + overlappingRouteItem := map[string]interface{}{} + routes := make([]map[string]interface{}, 0) + for _, r := range o.Routes { + overlappingRoute := map[string]interface{}{} + route := r.(*directlinkv1.RouteReportOverlappingRoute) + overlappingRoute[dlPrefix] = route.Prefix + overlappingRoute[dlType] = route.Type + overlappingRoute[dlVirtualConnectionId] = route.VirtualConnectionID + + routes = append(routes, overlappingRoute) + } + overlappingRouteItem[dlRoutes] = routes + + overlappingRoutesCollection = append(overlappingRoutesCollection, overlappingRouteItem) + } + } + + log.Println("[INFO] Length DL overlapping routes", len(overlappingRoutesCollection)) + d.Set(dlOverlappingRoutes, overlappingRoutesCollection) + + // Build connection routes + virtualConnectionRoutes := make([]map[string]interface{}, 0) + if report.VirtualConnectionRoutes != nil { + for _, c := range report.VirtualConnectionRoutes { + conn := map[string]interface{}{} + conn[dlVirtualConnectionId] = c.VirtualConnectionID + conn[dlVirtualConnectionName] = c.VirtualConnectionName + conn[dlVirtualConnectionType] = c.VirtualConnectionType + + connectionRoutes := make([]map[string]interface{}, 0) + for _, r := range c.Routes { + routes := map[string]interface{}{} + routes[dlPrefix] = r.Prefix + connectionRoutes = append(connectionRoutes, routes) + } + + conn[dlRoutes] = connectionRoutes + virtualConnectionRoutes = append(virtualConnectionRoutes, conn) + } + } + + log.Println("[Info] Length DL Route Reports connection routes:", len(virtualConnectionRoutes)) + d.Set(dlVirtualConnectionRoutes, virtualConnectionRoutes) + + // Add the created and updated dates + if report.CreatedAt != nil { + d.Set(dlCreatedAt, report.CreatedAt.String()) + } + if report.UpdatedAt != nil { + d.Set(dlUpdatedAt, report.UpdatedAt.String()) + } + + return nil +} + +func resourceIBMdlGatewayRouteReportDelete(d *schema.ResourceData, meta interface{}) error { + + directLink, err := directlinkClient(meta) + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + gatewayId := parts[0] + routeReportId := parts[1] + + delOptions := directLink.NewDeleteGatewayRouteReportOptions(gatewayId, routeReportId) + response, err := directLink.DeleteGatewayRouteReport(delOptions) + + if err != nil { + if response.StatusCode == 404 { + return nil + } + + log.Printf("Error deleting Direct Link Route Report : %s", response) + return err + } + + d.SetId("") + return nil +} diff --git a/ibm/service/directlink/resource_ibm_dl_route_report_test.go b/ibm/service/directlink/resource_ibm_dl_route_report_test.go new file mode 100644 index 000000000..e4136049c --- /dev/null +++ b/ibm/service/directlink/resource_ibm_dl_route_report_test.go @@ -0,0 +1,118 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package directlink_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/directlinkv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMDLRouteReportResource_basic(t *testing.T) { + var dlRouteReport string + node := "ibm_dl_route_report.dl_route_report" + gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDLRouteReportDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMDLRouteReportResourceConfig(gatewayname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMDLGatewayRouteReportExists(node, dlRouteReport), + resource.TestCheckResourceAttrSet(node, "route_report_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMDLRouteReportResourceConfig(gatewayname string) string { + return fmt.Sprintf(` + data "ibm_dl_ports" "ds_dlports" { + } + + resource ibm_dl_gateway test_dl_gateway { + bgp_asn = 64999 + global = true + metered = false + name = "%s" + speed_mbps = 1000 + type = "connect" + port = data.ibm_dl_ports.ds_dlports.ports[0].port_id + } + + resource ibm_dl_route_report dl_route_report { + gateway = ibm_dl_gateway.test_dl_gateway.id + } + + `, gatewayname) +} + +func testAccCheckIBMDLRouteReportDestroy(s *terraform.State) error { + client, err := directlinkClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_dl_route_report" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + ID := parts[1] + + getGatewayRouteReportOptions := &directlinkv1.GetGatewayRouteReportOptions{} + getGatewayRouteReportOptions.SetGatewayID(gatewayId) + getGatewayRouteReportOptions.SetID(ID) + _, _, err = client.GetGatewayRouteReport(getGatewayRouteReportOptions) + if err == nil { + return fmt.Errorf(" DL gateway route report still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMDLGatewayRouteReportExists(n string, vc string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client, err := directlinkClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + ID := parts[1] + + getGatewayRouteReportOptions := &directlinkv1.GetGatewayRouteReportOptions{ + ID: &ID, + GatewayID: &gatewayId, + } + r, response, err := client.GetGatewayRouteReport(getGatewayRouteReportOptions) + if err != nil { + return fmt.Errorf("testAccCheckIBMDLGatewayRouteReportExists: Error Getting DL Gateway Route Report: %s\n%s", err, response) + } + + vc = *r.ID + return nil + } +} diff --git a/ibm/service/dnsservices/README.md b/ibm/service/dnsservices/README.md new file mode 100644 index 000000000..2c96d0d8f --- /dev/null +++ b/ibm/service/dnsservices/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider DNS Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the DNS Services resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/dns_custom_resolver) +* IBM API Docs: [IBM API Docs for DNS Services](https://cloud.ibm.com/apidocs/dns-svcs) +* IBM DNS Services SDK: [IBM SDK for DNS Services](https://github.com/IBM/networking-go-sdk/tree/master/dnssvcsv1) diff --git a/ibm/data_source_ibm_private_dns_custom_resolver.go b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver.go similarity index 91% rename from ibm/data_source_ibm_private_dns_custom_resolver.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver.go index c0a430061..49733eeab 100644 --- a/ibm/data_source_ibm_private_dns_custom_resolver.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "context" "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMDNSCustomResolver() *schema.Resource { +func DataSourceIBMPrivateDNSCustomResolver() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMDNSCustomResolverRead, @@ -88,7 +89,7 @@ func dataSourceIBMDNSCustomResolver() *schema.Resource { } func dataSourceIBMDNSCustomResolverRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return diag.FromErr(err) } @@ -97,7 +98,7 @@ func dataSourceIBMDNSCustomResolverRead(context context.Context, d *schema.Resou opt := sess.NewListCustomResolversOptions(instanceID) result, resp, err := sess.ListCustomResolversWithContext(context, opt) if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error listing the custom resolvers %s:%s", err, resp)) + return diag.FromErr(fmt.Errorf("[ERROR] Error listing the custom resolvers %s:%s", err, resp)) } customResolvers := make([]interface{}, 0) diff --git a/ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go similarity index 90% rename from ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go index 96b741f85..25bcabd67 100644 --- a/ibm/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "context" "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMPrivateDNSForwardingRules() *schema.Resource { +func DataSourceIBMPrivateDNSForwardingRules() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmDnsCrForwardingRulesRead, @@ -68,7 +69,7 @@ func dataSourceIBMPrivateDNSForwardingRules() *schema.Resource { } func dataSourceIbmDnsCrForwardingRulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return diag.FromErr(err) } @@ -79,7 +80,7 @@ func dataSourceIbmDnsCrForwardingRulesRead(context context.Context, d *schema.Re result, resp, err := sess.ListForwardingRulesWithContext(context, opt) if err != nil || result == nil { - return diag.FromErr(fmt.Errorf("Error listing the forwarding rules %s:%s", err, resp)) + return diag.FromErr(fmt.Errorf("[ERROR] Error listing the forwarding rules %s:%s", err, resp)) } forwardRules := make([]interface{}, 0) diff --git a/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go new file mode 100644 index 000000000..9cf6eec66 --- /dev/null +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_forwarding_rules_test.go @@ -0,0 +1,88 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPrivateDNSCustomResolverForwardingRulesDataSource_basic(t *testing.T) { + forwardingRuleDescription := "test-forward-rule" + forwardingRuleType := "zone" + forwardingRuleMatch := "test.example.com" + node := "data.ibm_dns_custom_resolver_forwarding_rules.test-fr" + vpcname := fmt.Sprintf("d-fr-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("d-fr-subnet-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmDnsCrForwardingRulesDataSourceConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, forwardingRuleDescription, forwardingRuleType, forwardingRuleMatch), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "rules.0.description"), + resource.TestCheckResourceAttrSet(node, "rules.0.type"), + resource.TestCheckResourceAttrSet(node, "rules.0.match"), + ), + }, + }, + }) +} + +func testAccCheckIbmDnsCrForwardingRulesDataSourceConfig(vpcname, subnetname, zone, cidr, forwardingRuleDescription, forwardingRuleType string, forwardingRuleMatch string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "testpdnscustomresolver" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR - TF" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + resource "ibm_dns_custom_resolver_forwarding_rule" "dns_custom_resolver_forwarding_rule" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + description = "Test Fw Rule" + type = "%s" + match = "%s" + forward_to = ["168.20.22.122"] + } + data "ibm_dns_custom_resolver_forwarding_rules" "test-fr" { + depends_on = [ibm_dns_custom_resolver.test] + instance_id = ibm_dns_custom_resolver.test.instance_id + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + } + `, vpcname, subnetname, zone, cidr, forwardingRuleType, forwardingRuleMatch) +} diff --git a/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_test.go new file mode 100644 index 000000000..e6691e905 --- /dev/null +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_custom_resolver_test.go @@ -0,0 +1,78 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPrivateDNSCustomResolverDataSource_basic(t *testing.T) { + node := "data.ibm_dns_custom_resolvers.test-cr" + crname := fmt.Sprintf("tf-pdns-custom-resolver-%d", acctest.RandIntRange(100, 200)) + crdescription := fmt.Sprintf("tf-pdns-custom-resolver-tf-test%d", acctest.RandIntRange(100, 200)) + vpcname := fmt.Sprintf("d-cr-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("d-cr-loc-subnet-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSCustomResolverDataSourceConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, crname, crdescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.name"), + resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.description"), + resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.enabled"), + resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.locations.0.subnet_crn"), + resource.TestCheckResourceAttrSet(node, "custom_resolvers.0.locations.0.enabled"), + ), + }, + }, + }) +} + +func testAccCheckIBMPrivateDNSCustomResolverDataSourceConfig(vpcname, subnetname, zone, cidr, crname, crdescription string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "%s" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "%s" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + data "ibm_dns_custom_resolvers" "test-cr" { + depends_on = [ibm_dns_custom_resolver.test] + instance_id = ibm_dns_custom_resolver.test.instance_id + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, crname, crdescription) +} diff --git a/ibm/data_source_ibm_private_dns_glb_monitors.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors.go similarity index 94% rename from ibm/data_source_ibm_private_dns_glb_monitors.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors.go index 537d3bd98..4d34b1209 100644 --- a/ibm/data_source_ibm_private_dns_glb_monitors.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( pdnsGLBMonitors = "dns_glb_monitors" ) -func dataSourceIBMPrivateDNSGLBMonitors() *schema.Resource { +func DataSourceIBMPrivateDNSGLBMonitors() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSGLBMonitorsRead, @@ -130,7 +131,7 @@ func dataSourceIBMPrivateDNSGLBMonitors() *schema.Resource { func dataSourceIBMPrivateDNSGLBMonitorsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -138,7 +139,7 @@ func dataSourceIBMPrivateDNSGLBMonitorsRead(d *schema.ResourceData, meta interfa listDNSGLBMonitorions := sess.NewListMonitorsOptions(instanceID) availableGLBMonitors, detail, err := sess.ListMonitors(listDNSGLBMonitorions) if err != nil { - return fmt.Errorf("Error reading list of pdns GLB monitors:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of pdns GLB monitors:%s\n%s", err, detail) } dnsMonitors := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_private_dns_glb_monitors_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors_test.go similarity index 93% rename from ibm/data_source_ibm_private_dns_glb_monitors_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors_test.go index dda0a1f20..1373fb9f0 100644 --- a/ibm/data_source_ibm_private_dns_glb_monitors_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_monitors_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIBMPrivateDNSGlbMonitorsDataSource_basic(t *testing.T) { moniname := fmt.Sprintf("tf-monitorname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPrivateDNSGlbMonitordDataSConfig(vpcname, riname, zonename, moniname), diff --git a/ibm/data_source_ibm_private_dns_glb_pools.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools.go similarity index 95% rename from ibm/data_source_ibm_private_dns_glb_pools.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools.go index 56ccb5f63..e06017a31 100644 --- a/ibm/data_source_ibm_private_dns_glb_pools.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( pdnsGLBPools = "dns_glb_pools" ) -func dataSourceIBMPrivateDNSGLBPools() *schema.Resource { +func DataSourceIBMPrivateDNSGLBPools() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSGLBPoolsRead, Schema: map[string]*schema.Schema{ @@ -140,7 +141,7 @@ func dataSourceIBMPrivateDNSGLBPools() *schema.Resource { func dataSourceIBMPrivateDNSGLBPoolsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -148,7 +149,7 @@ func dataSourceIBMPrivateDNSGLBPoolsRead(d *schema.ResourceData, meta interface{ listDNSGLBPooloptions := sess.NewListPoolsOptions(instanceID) availableGLBPools, detail, err := sess.ListPools(listDNSGLBPooloptions) if err != nil { - return fmt.Errorf("Error reading list of pdns GLB pools:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of pdns GLB pools:%s\n%s", err, detail) } d.Set(pdnsInstanceID, instanceID) dnsPools := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_private_dns_glb_pools_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools_test.go similarity index 93% rename from ibm/data_source_ibm_private_dns_glb_pools_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools_test.go index 834260d8b..6e93483b4 100644 --- a/ibm/data_source_ibm_private_dns_glb_pools_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glb_pools_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIBMPrivateDNSGlbPoolsDataSource_basic(t *testing.T) { poolname := fmt.Sprintf("tf-poolname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPrivateDNSGlbPoolsDataSourceConfig(vpcname, riname, zonename, poolname), diff --git a/ibm/data_source_ibm_private_dns_glbs.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glbs.go similarity index 93% rename from ibm/data_source_ibm_private_dns_glbs.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glbs.go index c5b67193d..745b52859 100644 --- a/ibm/data_source_ibm_private_dns_glbs.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glbs.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( pdnsGLBs = "dns_glbs" ) -func dataSourceIBMPrivateDNSGLBs() *schema.Resource { +func DataSourceIBMPrivateDNSGLBs() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSGLBsRead, @@ -121,7 +122,7 @@ func dataSourceIBMPrivateDNSGLBs() *schema.Resource { func dataSourceIBMPrivateDNSGLBsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -130,7 +131,7 @@ func dataSourceIBMPrivateDNSGLBsRead(d *schema.ResourceData, meta interface{}) e listDNSGLBs := sess.NewListLoadBalancersOptions(instanceID, zoneID) availableGLBs, detail, err := sess.ListLoadBalancers(listDNSGLBs) if err != nil { - return fmt.Errorf("Error reading list of pdns GLB load balancers:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of pdns GLB load balancers:%s\n%s", err, detail) } dnslbs := make([]interface{}, 0) diff --git a/ibm/data_source_ibm_private_dns_glbs_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_glbs_test.go similarity index 94% rename from ibm/data_source_ibm_private_dns_glbs_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_glbs_test.go index f003744b0..d8b85154c 100644 --- a/ibm/data_source_ibm_private_dns_glbs_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_glbs_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIBMPrivateDNSGlbLoadBalancersDataSource_basic(t *testing.T) { lbname := fmt.Sprintf("tf-lbname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPrivateDNSGlbLoadBalancerdDataSConfig(riname, zonename, poolname, lbname), diff --git a/ibm/data_source_ibm_private_dns_permitted_network.go b/ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network.go similarity index 92% rename from ibm/data_source_ibm_private_dns_permitted_network.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network.go index 3171743c5..8f0395c84 100644 --- a/ibm/data_source_ibm_private_dns_permitted_network.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( pdnsPermittedNetworks = "dns_permitted_networks" ) -func dataSourceIBMPrivateDNSPermittedNetworks() *schema.Resource { +func DataSourceIBMPrivateDNSPermittedNetworks() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSPermittedNetworksRead, @@ -96,7 +97,7 @@ func dataSourceIBMPrivateDNSPermittedNetworks() *schema.Resource { } func dataSourceIBMPrivateDNSPermittedNetworksRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -106,7 +107,7 @@ func dataSourceIBMPrivateDNSPermittedNetworksRead(d *schema.ResourceData, meta i listPermittedNetworkOptions := sess.NewListPermittedNetworksOptions(instanceID, dnsZoneID) availablePermittedNetworks, detail, err := sess.ListPermittedNetworks(listPermittedNetworkOptions) if err != nil { - return fmt.Errorf("Error reading list of pdns permitted networks:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of pdns permitted networks:%s\n%s", err, detail) } permittedNetworks := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_private_dns_permitted_network_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network_test.go similarity index 92% rename from ibm/data_source_ibm_private_dns_permitted_network_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network_test.go index 38f12d912..8ba498586 100644 --- a/ibm/data_source_ibm_private_dns_permitted_network_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_permitted_network_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMPrivateDNSNetworkDataSource_basic(t *testing.T) { vpcname := fmt.Sprintf("tfc-vpc-name-%d", acctest.RandIntRange(10, 100)) zonename := fmt.Sprintf("tf-dnszone-%d.com", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMpDNSPermittedNetworksDataSourceConfig(riname, vpcname, zonename), diff --git a/ibm/data_source_ibm_private_dns_resource_records.go b/ibm/service/dnsservices/data_source_ibm_private_dns_resource_records.go similarity index 87% rename from ibm/data_source_ibm_private_dns_resource_records.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_resource_records.go index 79f6fd486..f96f27a5d 100644 --- a/ibm/data_source_ibm_private_dns_resource_records.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_resource_records.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "encoding/json" "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +16,7 @@ const ( pdnsResourceRecords = "dns_resource_records" ) -func dataSourceIBMPrivateDNSResourceRecords() *schema.Resource { +func DataSourceIBMPrivateDNSResourceRecords() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSResourceRecordsRead, Schema: map[string]*schema.Schema{ @@ -69,7 +70,7 @@ func dataSourceIBMPrivateDNSResourceRecords() *schema.Resource { func dataSourceIBMPrivateDNSResourceRecordsRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -78,7 +79,7 @@ func dataSourceIBMPrivateDNSResourceRecordsRead(d *schema.ResourceData, meta int listDNSResRecOptions := sess.NewListResourceRecordsOptions(instanceID, DnszoneID) availableDNSResRecs, detail, err := sess.ListResourceRecords(listDNSResRecOptions) if err != nil { - return fmt.Errorf("Error reading list of pdns resource records:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of pdns resource records:%s\n%s", err, detail) } dnsResRecs := make([]map[string]interface{}, 0) for _, instance := range availableDNSResRecs.ResourceRecords { @@ -89,7 +90,7 @@ func dataSourceIBMPrivateDNSResourceRecordsRead(d *schema.ResourceData, meta int // Marshal the rdata map into a JSON string rData, err := json.Marshal(instance.Rdata) if err != nil { - return fmt.Errorf("Error reading rdata map of dns resource records:%s", err) + return fmt.Errorf("[ERROR] Error reading rdata map of dns resource records:%s", err) } jsonStr := string(rData) dnsRecord[pdnsRdata] = jsonStr diff --git a/ibm/data_source_ibm_private_dns_resource_records_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_resource_records_test.go similarity index 94% rename from ibm/data_source_ibm_private_dns_resource_records_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_resource_records_test.go index 46df8d8e1..ec2b23380 100644 --- a/ibm/data_source_ibm_private_dns_resource_records_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_resource_records_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,8 +20,8 @@ func TestAccIBMPrivateDNSResourceRecordsDataSource_basic(t *testing.T) { vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) recname := fmt.Sprintf("tf-recname-%d.com", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPrivateDNSResourceRecordsDataSourceConfig(riname, zonename, vpcname, recname), diff --git a/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones.go b/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones.go new file mode 100644 index 000000000..d1f74aae3 --- /dev/null +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones.go @@ -0,0 +1,134 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + pdnsSecondaryZones = "secondary_zones" + pdnsSZResolverID = "resolver_id" + pdnsSZId = "secondary_zone_id" + pdnsSZDescription = "description" + pdnsSZZone = "zone" + pdnsSZEnabled = "enabled" + pdnsSZTransferFrom = "transfer_from" + pdnsSZCreatedOn = "created_on" + pdnsSZModifiedOn = "modified_on" + pdnsSZOffset = "offset" + pdnsSZLimit = "limit" +) + +func DataSourceIBMPrivateDNSSecondaryZones() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMDNSSecondaryZonesRead, + + Schema: map[string]*schema.Schema{ + pdnsInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "The GUID of the DNS Services instance.", + }, + pdnsSZResolverID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of a custom resolver.", + }, + pdnsSecondaryZones: { + Type: schema.TypeList, + Description: "List of Secondary Zones", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + pdnsSZId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier of the Secondary Zone", + }, + pdnsSZDescription: { + Type: schema.TypeString, + Computed: true, + Description: "Descriptive text of the secondary zone.", + }, + pdnsSZZone: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the zone.", + }, + pdnsSZEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Enable/Disable the secondary zone.", + }, + pdnsSZTransferFrom: { + Type: schema.TypeList, + Computed: true, + Description: "The addresses of DNS servers where the secondary zone data is transferred from.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + pdnsSZCreatedOn: { + Type: schema.TypeString, + Computed: true, + Description: "Time when a secondary zone is created", + }, + + pdnsSZModifiedOn: { + Type: schema.TypeString, + Computed: true, + Description: "The recent time when a secondary zone is modified", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMDNSSecondaryZonesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + instanceID := d.Get(pdnsInstanceID).(string) + resolverID := d.Get(pdnsSZResolverID).(string) + + opt := sess.NewListSecondaryZonesOptions(instanceID, resolverID) + + result, resp, err := sess.ListSecondaryZonesWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing the Secondary Zones %s:%s", err, resp)) + } + + secondaryZones := make([]interface{}, 0) + for _, instance := range result.SecondaryZones { + secondaryZone := map[string]interface{}{} + secondaryZone[pdnsSZId] = *instance.ID + secondaryZone[pdnsSZDescription] = *instance.Description + secondaryZone[pdnsSZZone] = *instance.Zone + secondaryZone[pdnsSZEnabled] = *instance.Enabled + secondaryZone[pdnsSZTransferFrom] = instance.TransferFrom + secondaryZone[pdnsSZCreatedOn] = *instance.CreatedOn + secondaryZone[pdnsSZModifiedOn] = *instance.ModifiedOn + + secondaryZones = append(secondaryZones, secondaryZone) + } + d.SetId(dataSourceIBMPrivateDNSSecondaryZoneID(d)) + d.Set(pdnsInstanceID, instanceID) + d.Set(pdnsSZResolverID, resolverID) + d.Set(pdnsSecondaryZones, secondaryZones) + return nil +} + +func dataSourceIBMPrivateDNSSecondaryZoneID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones_test.go new file mode 100644 index 000000000..8dda6afb8 --- /dev/null +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_secondary_zones_test.go @@ -0,0 +1,84 @@ +package dnsservices_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPrivateDNSCustomResolverSecondaryZonesDataSource_basic(t *testing.T) { + szDescription := "test-secondary-zone" + node := "data.ibm_dns_custom_resolver_secondary_zones.test-sz" + szzone := fmt.Sprintf("tf-secondaryzone-%d.com", acctest.RandIntRange(100, 200)) + vpcname := fmt.Sprintf("d-sz-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("d-sz-subnet-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmDnsCrSecondaryZonesDataSourceConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, szDescription, szzone), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(node, "secondary_zones.0.description"), + resource.TestCheckResourceAttrSet(node, "secondary_zones.0.zone"), + resource.TestCheckResourceAttrSet(node, "secondary_zones.0.enabled"), + ), + }, + }, + }) +} + +func testAccCheckIbmDnsCrSecondaryZonesDataSourceConfig(vpcname, subnetname, zone, cidr, szDescription, szzone string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "rg" { + is_default = "true" + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "testpdnscustomresolver" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR - TF" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + resource "ibm_dns_custom_resolver_secondary_zone" "test" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + description = "%s" + zone = "%s" + enabled = true + transfer_from = ["10.0.0.8"] + } + data "ibm_dns_custom_resolver_secondary_zones" "test-sz" { + depends_on = [ibm_dns_custom_resolver_secondary_zone.test] + instance_id = ibm_dns_custom_resolver.test.instance_id + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + } + `, vpcname, subnetname, zone, cidr, szDescription, szzone) +} diff --git a/ibm/data_source_ibm_private_dns_zones.go b/ibm/service/dnsservices/data_source_ibm_private_dns_zones.go similarity index 91% rename from ibm/data_source_ibm_private_dns_zones.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_zones.go index 603875a33..b91af1e75 100644 --- a/ibm/data_source_ibm_private_dns_zones.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_zones.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( pdnsZones = "dns_zones" ) -func dataSourceIBMPrivateDNSZones() *schema.Resource { +func DataSourceIBMPrivateDNSZones() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMPrivateDNSZonesRead, Schema: map[string]*schema.Schema{ @@ -78,7 +79,7 @@ func dataSourceIBMPrivateDNSZones() *schema.Resource { func dataSourceIBMPrivateDNSZonesRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -86,7 +87,7 @@ func dataSourceIBMPrivateDNSZonesRead(d *schema.ResourceData, meta interface{}) listDNSZonesOptions := sess.NewListDnszonesOptions(instanceID) availableDNSZones, detail, err := sess.ListDnszones(listDNSZonesOptions) if err != nil { - return fmt.Errorf("Error reading list of dns zones:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of dns zones:%s\n%s", err, detail) } dnsZones := make([]map[string]interface{}, 0) for _, instance := range availableDNSZones.Dnszones { diff --git a/ibm/data_source_ibm_private_dns_zones_test.go b/ibm/service/dnsservices/data_source_ibm_private_dns_zones_test.go similarity index 90% rename from ibm/data_source_ibm_private_dns_zones_test.go rename to ibm/service/dnsservices/data_source_ibm_private_dns_zones_test.go index a8c86fd15..4a3f47733 100644 --- a/ibm/data_source_ibm_private_dns_zones_test.go +++ b/ibm/service/dnsservices/data_source_ibm_private_dns_zones_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMPrivateDNSZonesDataSource_basic(t *testing.T) { riname := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(100, 200)) zonename := fmt.Sprintf("tf-dnszone-%d.com", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPrivateDNSZonesDataSourceConfig(riname, zonename), diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver.go new file mode 100644 index 000000000..37d008baa --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver.go @@ -0,0 +1,690 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/dnssvcsv1" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmDNSCustomResolver = "ibm_dns_custom_resolver" + pdnsCustomResolvers = "custom_resolvers" + pdnsCustomResolverLocations = "locations" + pdnsCRId = "custom_resolver_id" + pdnsCRName = "name" + pdnsCRDescription = "description" + pdnsCRHealth = "health" + pdnsCREnabled = "enabled" + pdnsCRCreatedOn = "created_on" + pdnsCRModifiedOn = "modified_on" + pdnsCRLocationId = "location_id" + pdnsCRLocationSubnetCrn = "subnet_crn" + pdnsCRLocationEnabled = "enabled" + pdnsCRLocationHealthy = "healthy" + pdnsCRLocationDnsServerIp = "dns_server_ip" + pdnsCustomResolverCritical = "CRITICAL" + pdnsCustomResolverDegraded = "DEGRADED" + pdnsCustomResolverHealthy = "HEALTHY" + pdnsCRHighAvailability = "high_availability" +) + +func ResourceIBMPrivateDNSCustomResolver() *schema.Resource { + return &schema.Resource{ + CreateContext: resouceIBMPrivateDNSCustomResolverCreate, + ReadContext: resouceIBMPrivateDNSCustomResolverRead, + UpdateContext: resouceIBMPrivateDNSCustomResolverUpdate, + DeleteContext: resouceIBMPrivateDNSCustomResolverDelete, + Exists: resouceIBMPrivateDNSCustomResolverExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + pdnsInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "Instance ID", + }, + + pdnsCRId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the custom resolver", + }, + pdnsCRName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the custom resolver", + }, + pdnsCRDescription: { + Type: schema.TypeString, + Optional: true, + Description: "Descriptive text of the custom resolver.", + }, + pdnsCREnabled: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Whether the custom resolver is enabled", + }, + pdnsCRHighAvailability: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Whether High Availability is enabled in custom resolver", + }, + pdnsCRHealth: { + Type: schema.TypeString, + Computed: true, + Description: "Healthy state of the custom resolver", + }, + pdnsCustomResolverLocations: { + Type: schema.TypeList, + Description: "Locations on which the custom resolver will be running", + Optional: true, + MaxItems: 3, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + pdnsCRLocationId: { + Type: schema.TypeString, + Computed: true, + Description: "Location ID", + }, + pdnsCRLocationSubnetCrn: { + Type: schema.TypeString, + Required: true, + Description: "Subnet CRN", + }, + pdnsCRLocationEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Whether the location is enabled for the custom resolver", + }, + pdnsCRLocationHealthy: { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the DNS server in this location is healthy or not.", + }, + pdnsCRLocationDnsServerIp: { + Type: schema.TypeString, + Computed: true, + Description: "The ip address of this dns server", + }, + }, + }, + }, + pdnsCRForwardRules: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + pdnsCRFRRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the forwarding rule.", + }, + pdnsCRFRDesctiption: { + Type: schema.TypeString, + Computed: true, + Description: "Descriptive text of the forwarding rule.", + }, + pdnsCRFRType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of the forwarding rule.", + }, + pdnsCRFRMatch: { + Type: schema.TypeString, + Computed: true, + Description: "The matching zone or hostname.", + }, + pdnsCRFRForwardTo: { + Type: schema.TypeList, + Computed: true, + Description: "The upstream DNS servers will be forwarded to.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + pdnsCRCreatedOn: { + Type: schema.TypeString, + Computed: true, + Description: "Time when a custom resolver is created", + }, + + pdnsCRModifiedOn: { + Type: schema.TypeString, + Computed: true, + Description: "The recent time when a custom resolver is modified", + }, + }, + } +} + +type location struct { + locationId string + subnet string + enabled bool +} + +func resouceIBMPrivateDNSCustomResolverCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + var crName, crDescription string + + // session options + crn := d.Get(pdnsInstanceID).(string) + if name, ok := d.GetOk(pdnsCRName); ok { + crName = name.(string) + } + if des, ok := d.GetOk(pdnsCRDescription); ok { + crDescription = des.(string) + } + + customResolverOption := sess.NewCreateCustomResolverOptions(crn) + customResolverOption.SetName(crName) + customResolverOption.SetDescription(crDescription) + + cr_highaval := d.Get(pdnsCRHighAvailability).(bool) + + var loc_enable bool + cr_enable := d.Get(pdnsCREnabled) + + // Validation + if _, ok := d.GetOk(pdnsCustomResolverLocations); ok { + var expandcrLocations []dnssvcsv1.LocationInput + crLocations := d.Get(pdnsCustomResolverLocations).([]interface{}) + if len(crLocations) > 3 { + return diag.FromErr(fmt.Errorf("A custom resolver can have a maximum of three locations, either within the same subnet or in different subnets.")) + } + if cr_highaval && len(crLocations) <= 1 { + return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations. A maximum of three locations can be configured within the same subnet location.")) + } + expandcrLocations, loc_enable = expandPdnsCRLocations(crLocations) + if cr_enable.(bool) && !loc_enable { + return diag.FromErr(fmt.Errorf("The Custom resolver cannot be enabled. There should be atleast one enabled location.")) + } + customResolverOption.SetLocations(expandcrLocations) + } else { + if cr_highaval { + return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations. A maximum of three locations can be configured within the same subnet location.")) + } else if cr_enable.(bool) { + return diag.FromErr(fmt.Errorf("The Custom resolver cannot be enabled. There should be atleast one enabled location.")) + } + } + + // Create a custom resolver + result, resp, err := sess.CreateCustomResolverWithContext(context, customResolverOption) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %s:%s", err, resp)) + } + + d.SetId(flex.ConvertCisToTfTwoVar(*result.ID, crn)) + d.Set(pdnsCRId, *result.ID) + + // Enable Custom resolver + if cr_enable.(bool) { + err := PDNSCustomResolverEnable(meta, crn, *result.ID) + if err != nil { + return err + } + } + return resouceIBMPrivateDNSCustomResolverRead(context, d, meta) +} + +func resouceIBMPrivateDNSCustomResolverRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + customResolverID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + opt := sess.NewGetCustomResolverOptions(crn, customResolverID) + result, response, err := sess.GetCustomResolverWithContext(context, opt) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %s:%s", err, response)) + } + fwopt := sess.NewListForwardingRulesOptions(crn, customResolverID) + + fwresult, fwresp, fwerr := sess.ListForwardingRulesWithContext(context, fwopt) + if fwerr != nil || fwresult == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing the forwarding rules %s:%s", fwerr, fwresp)) + } + + forwardRules := make([]interface{}, 0) + for _, instance := range fwresult.ForwardingRules { + forwardRule := map[string]interface{}{} + forwardRule[pdnsCRFRRuleID] = *instance.ID + forwardRule[pdnsCRFRDesctiption] = *instance.Description + forwardRule[pdnsCRFRType] = *instance.Type + forwardRule[pdnsCRFRMatch] = *instance.Match + forwardRule[pdnsCRFRForwardTo] = instance.ForwardTo + forwardRules = append(forwardRules, forwardRule) + } + d.Set(pdnsInstanceID, crn) + d.Set(pdnsCRId, *result.ID) + d.Set(pdnsCRName, *result.Name) + d.Set(pdnsCRDescription, *result.Description) + d.Set(pdnsCRHealth, *result.Health) + d.Set(pdnsCREnabled, *result.Enabled) + d.Set(pdnsCustomResolverLocations, flattenPdnsCRLocations(result.Locations)) + d.Set(pdnsCRForwardRules, forwardRules) + return nil +} + +func resouceIBMPrivateDNSCustomResolverUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + resolverID, instanceID, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + var loc_enable, cr_enable, cr_highaval bool + + if enable_cr, ok := d.GetOk(pdnsCREnabled); ok { + cr_enable = enable_cr.(bool) + } + if highaval, ok := d.GetOk(pdnsCRHighAvailability); ok { + cr_highaval = highaval.(bool) + } + var oldRaw, newRaw interface{} + + if d.HasChange(pdnsCRName) || + d.HasChange(pdnsCRDescription) || + d.HasChange(pdnsCREnabled) || + d.HasChange(pdnsCRHighAvailability) { + + // Validation + if _, ok := d.GetOk(pdnsCustomResolverLocations); ok { + var expandcrLocations []dnssvcsv1.LocationInput + crLocations := d.Get(pdnsCustomResolverLocations).([]interface{}) + if len(crLocations) > 3 { + return diag.FromErr(fmt.Errorf("A custom resolver can have a maximum of three locations, either within the same subnet or in different subnets.")) + } + if cr_highaval && len(crLocations) <= 1 { + return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations .A maximum of three locations can be configured within the same subnet location.")) + } + expandcrLocations, loc_enable = expandPdnsCRLocations(crLocations) + if cr_enable && !loc_enable { + return diag.FromErr(fmt.Errorf("The Custom resolver cannot be enabled. There should be atleast one enabled location.")) + } + fmt.Print("expandcrLocations", expandcrLocations) + } else { + if cr_highaval { + return diag.FromErr(fmt.Errorf("To meet high availability status, configure custom resolvers with a minimum of two resolver locations. A maximum of three locations can be configured within the same subnet location.")) + } else if cr_enable { + return diag.FromErr(fmt.Errorf("The Custom resolver cannot be enabled. There should be atleast one enabled location.")) + } + } + + opt := sess.NewUpdateCustomResolverOptions(instanceID, resolverID) + if name, ok := d.GetOk(pdnsCRName); ok { + crName := name.(string) + opt.SetName(crName) + } + if des, ok := d.GetOk(pdnsCRDescription); ok { + crDescription := des.(string) + opt.SetDescription(crDescription) + } + if !cr_enable { + opt.SetEnabled(false) + } + result, resp, err := sess.UpdateCustomResolverWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the custom resolver %s:%s", err, resp)) + } + + } + + if d.HasChange(pdnsCustomResolverLocations) { + + oldRaw, newRaw = d.GetChange(pdnsCustomResolverLocations) + + newState := stateprocess(newRaw) + oldState := stateprocess(oldRaw) + + // Delete Custom Resolver Location. + for _, oldloc := range oldState { + locationIdExists := false + for _, newloc := range newState { + if oldloc.locationId == newloc.locationId { + locationIdExists = true + break + } + } + if !locationIdExists { + if oldloc.enabled { + err := PDNSCustomResolverDisableLocation(meta, instanceID, resolverID, oldloc.locationId) + if err != nil { + return err + } + } + err := deleteCRLocation(meta, instanceID, resolverID, oldloc.locationId) + if err != nil { + return err + } + } + } + + for _, newLoc := range newState { + // Add new custom resolver locations + if strings.Contains(newLoc.locationId, "NEW0") { + locationID, err := addCRLocation(meta, instanceID, resolverID, newLoc.subnet) + if err != nil || locationID == "" { + return err + } + if newLoc.enabled { + err := PDNSCustomResolverEnableLocation(meta, instanceID, resolverID, locationID) + if err != nil { + return err + } + } + } else { + // Update Location + locationIdExists := false + for _, oldLoc := range oldState { + if oldLoc.locationId == newLoc.locationId { + locationIdExists = true + if !(oldLoc.subnet == newLoc.subnet) { + // Update location subnet crn. + // Disable location before changing the subnet. + err := PDNSCustomResolverDisableLocation(meta, instanceID, resolverID, newLoc.locationId) + if err != nil { + return err + } + errSub := updateLocationSubnet(meta, instanceID, resolverID, newLoc.locationId, newLoc.subnet) + if errSub != nil { + return errSub + } + if newLoc.enabled { + err := PDNSCustomResolverEnableLocation(meta, instanceID, resolverID, newLoc.locationId) + if err != nil { + return err + } + } + } else if newLoc.enabled != oldLoc.enabled { + // Update location enable/disable + if newLoc.enabled { + err := PDNSCustomResolverEnableLocation(meta, instanceID, resolverID, newLoc.locationId) + if err != nil { + return err + } + } else { + err := PDNSCustomResolverDisableLocation(meta, instanceID, resolverID, newLoc.locationId) + if err != nil { + return err + } + } + } + } + } + if !locationIdExists { + return diag.FromErr(fmt.Errorf("[ERROR] The custom resolver location %s does not exist anymore: %v", newLoc.locationId, err)) + } + } + } + } + + if d.HasChange(pdnsCREnabled) { + if cr_enable { + err := PDNSCustomResolverEnable(meta, instanceID, resolverID) + if err != nil { + return err + } + } + } + + return resouceIBMPrivateDNSCustomResolverRead(context, d, meta) +} + +func resouceIBMPrivateDNSCustomResolverDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + customResolverID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return diag.FromErr(err) + } + // Disable Cutsom Resolver before deleting + optEnabled := sess.NewUpdateCustomResolverOptions(crn, customResolverID) + optEnabled.SetEnabled(false) + result, resp, errEnabled := sess.UpdateCustomResolverWithContext(context, optEnabled) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the custom resolver to disable before deleting %s:%s", errEnabled, resp)) + } + + opt := sess.NewDeleteCustomResolverOptions(crn, customResolverID) + response, err := sess.DeleteCustomResolverWithContext(context, opt) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting the custom resolver %s:%s", err, response)) + } + + d.SetId("") + return nil +} + +func resouceIBMPrivateDNSCustomResolverExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return false, err + } + + customResolverID, crn, err := flex.ConvertTftoCisTwoVar(d.Id()) + if err != nil { + return false, err + } + opt := sess.NewGetCustomResolverOptions(crn, customResolverID) + _, response, err := sess.GetCustomResolver(opt) + + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("Custom Resolver does not exist.") + return false, nil + } + log.Printf("Custom Resolver failed: %v", response) + return false, err + } + return true, nil +} + +func flattenPdnsCRLocations(crLocation []dnssvcsv1.Location) interface{} { + flattened := make([]interface{}, 0) + for _, v := range crLocation { + customLocations := map[string]interface{}{ + pdnsCRLocationId: *v.ID, + pdnsCRLocationSubnetCrn: *v.SubnetCrn, + pdnsCRLocationEnabled: *v.Enabled, + pdnsCRLocationHealthy: *v.Healthy, + pdnsCRLocationDnsServerIp: *v.DnsServerIp, + } + flattened = append(flattened, customLocations) + } + return flattened +} + +func expandPdnsCRLocations(crLocList []interface{}) (crLocations []dnssvcsv1.LocationInput, loc_enable bool) { + for _, iface := range crLocList { + var locOpt dnssvcsv1.LocationInput + loc := iface.(map[string]interface{}) + locOpt.SubnetCrn = core.StringPtr(loc[pdnsCRLocationSubnetCrn].(string)) + if val, ok := loc[pdnsCRLocationEnabled]; ok { + if val.(bool) { + loc_enable = true + } + locOpt.Enabled = core.BoolPtr(val.(bool)) + } + crLocations = append(crLocations, locOpt) + } + return crLocations, loc_enable +} + +func PDNSCustomResolverEnable(meta interface{}, instanceID string, customResolverID string) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + MaxTimeout := 600 + SleepTime := 20 + + for SleepTime < MaxTimeout { + opt := sess.NewUpdateCustomResolverOptions(instanceID, customResolverID) + opt.SetEnabled(true) + result, _, err := sess.UpdateCustomResolver(opt) + if err != nil || result == nil { + time.Sleep(20 * time.Second) + SleepTime = SleepTime + 20 + } else { + return nil + } + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Enabling the Custom resolver : MaxTimeout")) +} + +func PDNSCustomResolverEnableLocation(meta interface{}, instanceID string, customResolverID string, locationID string) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + MaxTimeout := 600 + SleepTime := 20 + + for SleepTime < MaxTimeout { + updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, customResolverID, locationID) + updatelocation.SetEnabled(true) + result, _, err := sess.UpdateCustomResolverLocation(updatelocation) + if err != nil || result == nil { + time.Sleep(20 * time.Second) + SleepTime = SleepTime + 20 + } else { + return nil + } + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Enabling the Custom resolver location : MaxTimeout")) +} + +func PDNSCustomResolverDisableLocation(meta interface{}, instanceID string, customResolverID string, locationID string) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, customResolverID, locationID) + updatelocation.SetEnabled(false) + result, resp, err := sess.UpdateCustomResolverLocation(updatelocation) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Disabling the custom resolver location %s:%s", err, resp)) + } + return nil +} + +func deleteCRLocation(meta interface{}, instanceID string, customResolverID string, locationID string) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + deleteCRlocation := sess.NewDeleteCustomResolverLocationOptions(instanceID, customResolverID, locationID) + resp, errDel := sess.DeleteCustomResolverLocation(deleteCRlocation) + if errDel != nil { + if resp != nil && resp.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Deleting the custom resolver location %s:%s", errDel, resp)) + } + return nil +} + +func addCRLocation(meta interface{}, instanceID string, customResolverID string, subnet string) (string, diag.Diagnostics) { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return "", diag.FromErr(err) + } + opt := sess.NewAddCustomResolverLocationOptions(instanceID, customResolverID) + opt.SetSubnetCrn(subnet) + opt.SetEnabled(false) + result, resp, err := sess.AddCustomResolverLocation(opt) + locationID := *result.ID + if err != nil || result == nil { + return "", diag.FromErr(fmt.Errorf("[ERROR] Error creating the custom resolver location %s:%s", err, resp)) + } + return locationID, nil +} + +func updateLocationSubnet(meta interface{}, instanceID string, customResolverID string, locationID string, subnet string) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, customResolverID, locationID) + updatelocation.SetSubnetCrn(subnet) + updatelocation.SetEnabled(false) + result, resp, err := sess.UpdateCustomResolverLocation(updatelocation) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Disable and updating the custom resolver location %s:%s", err, resp)) + } + return nil +} + +func stateprocess(Raw interface{}) (State []location) { + new_LocationId := 0 + for _, loc := range Raw.([]interface{}) { + temp_loc := loc.(map[string]interface{}) + newlocationId := (temp_loc["location_id"]).(string) + newLocation := location{} + // Add a constant marker for new locations. + if len(newlocationId) == 0 { + new_LocationId = new_LocationId + 1 + new_LocationName := "NEW0" + strconv.Itoa(new_LocationId) + newLocation = location{locationId: new_LocationName, subnet: (temp_loc["subnet_crn"]).(string), enabled: temp_loc["enabled"].(bool)} + } else { + newLocation = location{locationId: newlocationId, subnet: (temp_loc["subnet_crn"]).(string), enabled: temp_loc["enabled"].(bool)} + } + State = append(State, newLocation) + } + return State +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule.go new file mode 100644 index 000000000..416005891 --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule.go @@ -0,0 +1,211 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices + +import ( + "context" + "fmt" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + pdnsCRForwardRule = "ibm_dns_custom_resolver_forwarding_rule" + pdnsCRForwardRules = "rules" + pdnsCRFRResolverID = "resolver_id" + pdnsCRFRDesctiption = "description" + pdnsCRFRType = "type" + pdnsCRFRMatch = "match" + pdnsCRFRForwardTo = "forward_to" + pdnsCRFRRuleID = "rule_id" + pdnsCRFRCreatedOn = "created_on" + pdnsCRFRModifiedOn = "modified_on" +) + +func ResourceIBMPrivateDNSForwardingRule() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmDnsCrForwardingRuleCreate, + ReadContext: resourceIbmDnsCrForwardingRuleRead, + UpdateContext: resourceIbmDnsCrForwardingRuleUpdate, + DeleteContext: resourceIbmDnsCrForwardingRuleDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + pdnsInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of a service instance.", + }, + pdnsCRFRResolverID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of a custom resolver.", + }, + pdnsCRFRDesctiption: { + Type: schema.TypeString, + Optional: true, + Description: "Descriptive text of the forwarding rule.", + }, + pdnsCRFRType: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator(pdnsCRForwardRule, pdnsCRFRType), + Description: "Type of the forwarding rule.", + }, + pdnsCRFRMatch: { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "The matching zone or hostname.", + }, + pdnsCRFRForwardTo: { + Type: schema.TypeList, + Optional: true, + Description: "The upstream DNS servers will be forwarded to.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + pdnsCRFRRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "the time when a forwarding rule ID is created, RFC3339 format.", + }, + }, + } +} + +func ResourceIBMPrivateDNSForwardingRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "hostname, zone, Default", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: pdnsCRForwardRule, Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmDnsCrForwardingRuleCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + dnsSvcsClient, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + instanceID := d.Get(pdnsInstanceID).(string) + resolverID := d.Get(pdnsCRFRResolverID).(string) + opt := dnsSvcsClient.NewCreateForwardingRuleOptions(instanceID, resolverID) + + if des, ok := d.GetOk(pdnsCRFRDesctiption); ok { + opt.SetDescription(des.(string)) + } + if t, ok := d.GetOk(pdnsCRFRType); ok { + opt.SetType(t.(string)) + } + if m, ok := d.GetOk(pdnsCRFRMatch); ok { + opt.SetMatch(m.(string)) + } + if _, ok := d.GetOk(pdnsCRFRForwardTo); ok { + opt.SetForwardTo(flex.ExpandStringList(d.Get(pdnsCRFRForwardTo).([]interface{}))) + } + result, resp, err := dnsSvcsClient.CreateForwardingRuleWithContext(context, opt) + + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating the forwarding rules %s:%s", err, resp)) + } + d.SetId(flex.ConvertCisToTfThreeVar(*result.ID, resolverID, instanceID)) + + return resourceIbmDnsCrForwardingRuleRead(context, d, meta) +} + +func resourceIbmDnsCrForwardingRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + dnsSvcsClient, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + ruleID, resolverID, instanceID, err := flex.ConvertTfToCisThreeVar(d.Id()) + opt := dnsSvcsClient.NewGetForwardingRuleOptions(instanceID, resolverID, ruleID) + result, resp, err := dnsSvcsClient.GetForwardingRuleWithContext(context, opt) + + if err != nil || result == nil { + if resp != nil && resp.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the forwarding rules %s:%s", err, resp)) + } + d.Set(pdnsInstanceID, instanceID) + d.Set(pdnsCRFRResolverID, resolverID) + d.Set(pdnsCRFRRuleID, ruleID) + d.Set(pdnsCRFRDesctiption, *result.Description) + d.Set(pdnsCRFRType, *result.Type) + d.Set(pdnsCRFRMatch, *result.Match) + d.Set(pdnsCRFRForwardTo, result.ForwardTo) + return nil + +} +func resourceIbmDnsCrForwardingRuleUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + dnsSvcsClient, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + ruleID, resolverID, instanceID, err := flex.ConvertTfToCisThreeVar(d.Id()) + + if err != nil { + return diag.FromErr(err) + } + opt := dnsSvcsClient.NewUpdateForwardingRuleOptions(instanceID, resolverID, ruleID) + + if d.HasChange(pdnsCRFRDesctiption) || + d.HasChange(pdnsCRFRMatch) || + d.HasChange(pdnsCRFRForwardTo) { + if des, ok := d.GetOk(pdnsCRFRDesctiption); ok { + frdesc := des.(string) + opt.SetDescription(frdesc) + } + if _, ok := d.GetOk(pdnsCRFRForwardTo); ok { + opt.SetForwardTo(flex.ExpandStringList(d.Get(pdnsCRFRForwardTo).([]interface{}))) + } + if ty, ok := d.GetOk(pdnsCRFRType); ok { + crtype := ty.(string) + if strings.ToLower(crtype) == "Default" { + if match, ok := d.GetOk(pdnsCRFRMatch); ok { + frmatch := match.(string) + opt.SetMatch(frmatch) + } + } + } + result, resp, err := dnsSvcsClient.UpdateForwardingRuleWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the forwarding rule %s:%s", err, resp)) + } + + } + return resourceIbmDnsCrForwardingRuleRead(context, d, meta) +} + +func resourceIbmDnsCrForwardingRuleDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + dnsSvcsClient, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + ruleID, resolverID, instanceID, err := flex.ConvertTfToCisThreeVar(d.Id()) + opt := dnsSvcsClient.NewDeleteForwardingRuleOptions(instanceID, resolverID, ruleID) + response, err := dnsSvcsClient.DeleteForwardingRuleWithContext(context, opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting the Forwarding Rules %s:%s", err, response)) + } + d.SetId("") + return nil +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go new file mode 100644 index 000000000..e34ab97b2 --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_forwarding_rule_test.go @@ -0,0 +1,80 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPrivateDNSCustomResolverForwardingRule_basic(t *testing.T) { + typeVar := "zone" + match := "test.example.com" + vpcname := fmt.Sprintf("fr-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("fr-subnet-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmDnsCrForwardingRuleConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, typeVar, match), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_dns_custom_resolver_forwarding_rule.dns_custom_resolver_forwarding_rule", "type", typeVar), + resource.TestCheckResourceAttr("ibm_dns_custom_resolver_forwarding_rule.dns_custom_resolver_forwarding_rule", "match", match), + ), + }, + }, + }) +} + +func testAccCheckIbmDnsCrForwardingRuleConfig(vpcname, subnetname, zone, cidr, typeVar, match string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "testpdnscustomresolver" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR - TF" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + resource "ibm_dns_custom_resolver_forwarding_rule" "dns_custom_resolver_forwarding_rule" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + description = "Test Fw Rule" + type = "%s" + match = "%s" + forward_to = ["168.20.22.122"] + } + `, vpcname, subnetname, zone, cidr, typeVar, match) +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location.go new file mode 100644 index 000000000..463ef3137 --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location.go @@ -0,0 +1,261 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + ibmCRLocation = "ibm_dns_custom_resolver_location" + pdnsResolverID = "resolver_id" + pdnsCRLocationID = "location_id" + pdnsCRLocationSubnetCRN = "subnet_crn" + pdnsCRLocationEnable = "enabled" + pdnsCRLocationServerIP = "dns_server_ip" + pdnsCustomReolverEnabled = "cr_enabled" +) + +func ResourceIBMPrivateDNSCRLocation() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPrivateDNSLocationCreate, + ReadContext: resourceIBMPrivateDNSLocationRead, + UpdateContext: resourceIBMPrivateDNSLocationUpdate, + DeleteContext: resourceIBMPrivateDNSLocationDelete, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + pdnsInstanceID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance ID", + }, + + pdnsResolverID: { + Type: schema.TypeString, + Required: true, + Description: "Custom Resolver ID", + }, + pdnsCRLocationID: { + Type: schema.TypeString, + Computed: true, + Description: "CRLocation ID", + }, + + pdnsCRLocationSubnetCRN: { + Type: schema.TypeString, + Required: true, + Description: "CRLocation Subnet CRN", + }, + + pdnsCRLocationEnable: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "CRLocation Enabled", + }, + + pdnsCRLocationHealthy: { + Type: schema.TypeBool, + Computed: true, + Description: "CRLocation Healthy", + }, + + pdnsCRLocationServerIP: { + Type: schema.TypeString, + Computed: true, + Description: "CRLocation Server IP", + }, + pdnsCustomReolverEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: true, + DiffSuppressFunc: flex.ApplyOnce, + }, + }, + DeprecationMessage: "Resource ibm_dns_custom_resolver_location is deprecated. Using the deprecated resource can cause an outage. If you have used the `ibm_dns_custom_resolver_location` resource, change it to the composite Custom Resolver [ibm_dns_custom_resolver] resource before running terraform apply.", + } +} +func resourceIBMPrivateDNSLocationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + instanceID := d.Get(pdnsInstanceID).(string) + resolverID := d.Get(pdnsResolverID).(string) + + mk := "private_dns_resource_custom_resolver_location_" + instanceID + resolverID + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + + opt := sess.NewAddCustomResolverLocationOptions(instanceID, resolverID) + + if subnetcrn, ok := d.GetOk(pdnsCRLocationSubnetCRN); ok { + opt.SetSubnetCrn(subnetcrn.(string)) + } + var enable_loc, cr_enable bool + if enable, ok := d.GetOkExists(pdnsCRLocationEnable); ok { + opt.SetEnabled(enable.(bool)) + enable_loc = enable.(bool) + } + if enable_cr, ok := d.GetOkExists(pdnsCustomReolverEnabled); ok { + cr_enable = enable_cr.(bool) + } + // if location enabled is false, CR cannot be enabled, fail here + if !enable_loc && cr_enable { + return diag.FromErr(fmt.Errorf("[ERROR]The custom resolver location is not enabled, hence cannot add location. Also, cannot enable the custom resolver")) + } + + if enable_loc { + // Fetch the Custom Resolver and check the enabled attribute + optCr := sess.NewGetCustomResolverOptions(instanceID, resolverID) + cr_result, response, err := sess.GetCustomResolver(optCr) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %v:%v", err, response)) + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %v:%v", err, response)) + } + // Disable the Custom Resolver location and add it, otherwise you will get API error: + // "Not allowed to create enabled location while custom resolver is enabled." + if *cr_result.Enabled { + opt.SetEnabled(false) + } + } + + result, resp, err := sess.AddCustomResolverLocationWithContext(context, opt) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating the custom resolver location %s:%s", err, resp)) + } + locationID := *result.ID + d.SetId(flex.ConvertCisToTfThreeVar(locationID, resolverID, instanceID)) + + if cr_enable && enable_loc { + err := PDNSCustomResolverEnableLocation(meta, instanceID, resolverID, locationID) + if err != nil { + return err + } + } + + if cr_enable && enable_loc { + err := PDNSCustomResolverEnable(meta, instanceID, resolverID) + if err != nil { + return err + } + } else if !cr_enable { + optCr := sess.NewUpdateCustomResolverOptions(instanceID, resolverID) + optCr.SetEnabled(false) + resultCr, respCr, errCr := sess.UpdateCustomResolverWithContext(context, optCr) + if errCr != nil || resultCr == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the custom resolver with cr_enable false %s:%s", errCr, respCr)) + } + } + return resourceIBMPrivateDNSLocationRead(context, d, meta) +} + +func resourceIBMPrivateDNSLocationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} +func resourceIBMPrivateDNSLocationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + locationID, resolverID, instanceID, err := flex.ConvertTfToCisThreeVar(d.Id()) + + mk := "private_dns_resource_custom_resolver_location_" + instanceID + resolverID + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + + updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, resolverID, locationID) + + if d.HasChange(pdnsCRLocationSubnetCRN) || + d.HasChange(pdnsCRLocationEnable) { + if scrn, ok := d.GetOk(pdnsCRLocationSubnetCRN); ok { + updatelocation.SetSubnetCrn(scrn.(string)) + } + if e, ok := d.GetOkExists(pdnsCRLocationEnable); ok { + updatelocation.SetEnabled(e.(bool)) + } + result, resp, err := sess.UpdateCustomResolverLocationWithContext(context, updatelocation) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating the custom resolver location %s:%s", err, resp)) + } + } + return resourceIBMPrivateDNSLocationRead(context, d, meta) +} + +func resourceIBMPrivateDNSLocationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + locationID, resolverID, instanceID, _ := flex.ConvertTfToCisThreeVar(d.Id()) + opt := sess.NewGetCustomResolverOptions(instanceID, resolverID) + cr_result, response, err := sess.GetCustomResolver(opt) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %v:%v", err, response)) + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading the custom resolver %v:%v", err, response)) + } + + crLocations := cr_result.Locations + locationIdFound := false + enabledLocation := false + enabledAnotherLocation := false + for _, v := range crLocations { + if *v.ID == locationID { + locationIdFound = true + if *v.Enabled { + enabledLocation = true + } + } else { + if *v.Enabled { + enabledAnotherLocation = true + } + } + } + + if !locationIdFound { + d.SetId("") + return nil + } + // Location is enabled + if enabledLocation { + if *cr_result.Enabled { + if !enabledAnotherLocation || (len(crLocations) == 1) { + // Custom Resolver is Enabled, fail here + return diag.FromErr(fmt.Errorf("[ERROR] Error Deleting the custom resolver location. Custom resolver is enabled, it needs atleast one enabled location")) + } + } + // Disable the Custom Resolver Location + updatelocation := sess.NewUpdateCustomResolverLocationOptions(instanceID, resolverID, locationID) + updatelocation.SetEnabled(false) + result, resp, err := sess.UpdateCustomResolverLocationWithContext(context, updatelocation) + if err != nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Disable and updating the custom resolver location %s:%s", err, resp)) + } + } + deleteCRlocation := sess.NewDeleteCustomResolverLocationOptions(instanceID, resolverID, locationID) + resp, errDel := sess.DeleteCustomResolverLocationWithContext(context, deleteCRlocation) + if errDel != nil { + if resp != nil && resp.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Deleting the custom resolver location %s:%s", errDel, resp)) + } + d.SetId("") + return nil +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location_test.go new file mode 100644 index 000000000..37a87c886 --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_location_test.go @@ -0,0 +1,107 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPrivateDNSCustomResolverLocations_basic(t *testing.T) { + + vpcname := fmt.Sprintf("cr-loc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("cr-loc-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) + description := "new test CR Locations - TF" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSCRLocationsBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "enabled", "false"), + ), + }, + }, + }) +} + +func TestAccIBMPrivateDNSCustomResolverLocations_Import(t *testing.T) { + + name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) + description := "new test CR Locations - TF" + vpcname := fmt.Sprintf("cr-loc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("cr-loc-subnet-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSCRLocationsBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "enabled", "false"), + ), + }, + { + ResourceName: "ibm_dns_custom_resolver.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "enabled", + "instance_id", + }, + }, + }, + }) +} + +func testAccCheckIBMPrivateDNSCRLocationsBasic(vpcname, subnetname, zone, cidr, name, description string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "%s" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "%s" + high_availability = false + enabled = false + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = false + } + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = false + } + } + `, vpcname, subnetname, zone, cidr, name, description) + +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone.go new file mode 100644 index 000000000..db76221cb --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone.go @@ -0,0 +1,244 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices + +import ( + "context" + "fmt" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + pdnsSecondaryZoneID = "secondary_zone_id" + pdnsSecondaryZoneZone = "zone" + pdnsSecondaryZoneTransferFrom = "transfer_from" + pdnsSecondaryZoneEnabled = "enabled" + pdnsSecondaryZoneDescription = "description" + pdnsSecondaryZoneCreatedOn = "created_on" + pdnsSecondaryZoneModifiedOn = "modified_on" +) + +func ResourceIBMPrivateDNSSecondaryZone() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPrivateDNSSecondaryZoneCreate, + ReadContext: resourceIBMPrivateDNSSecondaryZoneRead, + UpdateContext: resourceIBMPrivateDNSSecondaryZoneUpdate, + DeleteContext: resourceIBMPrivateDNSSecondaryZoneDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + pdnsInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of a service instance.", + }, + pdnsResolverID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of a custom resolver.", + }, + pdnsSecondaryZoneID: { + Type: schema.TypeString, + Computed: true, + Description: "Secondary Zone ID", + }, + + pdnsSecondaryZoneZone: { + Type: schema.TypeString, + Required: true, + Description: "The name of the zone.", + }, + + pdnsSecondaryZoneTransferFrom: { + Type: schema.TypeList, + Required: true, + Description: "The addresses of DNS servers where the secondary zone data should be transferred from", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + pdnsSecondaryZoneEnabled: { + Type: schema.TypeBool, + Required: true, + Description: "Enable/Disable the secondary zone", + }, + + pdnsSecondaryZoneDescription: { + Type: schema.TypeString, + Optional: true, + Description: "Descriptive text of the secondary zone", + }, + + pdnsSecondaryZoneCreatedOn: { + Type: schema.TypeString, + Computed: true, + Description: "Secondary Zone Creation date", + }, + + pdnsSecondaryZoneModifiedOn: { + Type: schema.TypeString, + Computed: true, + Description: "Secondary Zone Modification date", + }, + }, + } +} + +func resourceIBMPrivateDNSSecondaryZoneCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + instanceID := d.Get(pdnsInstanceID).(string) + resolverID := d.Get(pdnsResolverID).(string) + description := d.Get(pdnsSecondaryZoneDescription).(string) + zone := d.Get(pdnsSecondaryZoneZone).(string) + enabled := d.Get(pdnsSecondaryZoneEnabled).(bool) + transferFrom := flex.ExpandStringList(d.Get(pdnsSecondaryZoneTransferFrom).([]interface{})) + + createSecondaryZoneOptions := sess.NewCreateSecondaryZoneOptions(instanceID, resolverID) + + createSecondaryZoneOptions.SetZone(zone) + createSecondaryZoneOptions.SetDescription(description) + createSecondaryZoneOptions.SetEnabled(enabled) + createSecondaryZoneOptions.SetTransferFrom(transferFrom) + + mk := "private_dns_secondary_zone_" + instanceID + resolverID + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + + resource, response, err := sess.CreateSecondaryZone(createSecondaryZoneOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating DNS Services secondary zone:%s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", instanceID, resolverID, *resource.ID)) + return resourceIBMPrivateDNSSecondaryZoneRead(ctx, d, meta) +} + +func resourceIBMPrivateDNSSecondaryZoneRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + idSet := strings.Split(d.Id(), "/") + if len(idSet) < 3 { + return diag.FromErr(fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/resolverID/secondaryZoneID", d.Id())) + } + instanceID := idSet[0] + resolverID := idSet[1] + secondaryZoneID := idSet[2] + getSecondaryZoneOptions := sess.NewGetSecondaryZoneOptions(instanceID, resolverID, secondaryZoneID) + resource, response, err := sess.GetSecondaryZone(getSecondaryZoneOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading DNS Services secondary zone:%s\n%s", err, response)) + } + + transferFrom := []string{} + for _, value := range resource.TransferFrom { + values := strings.Split(value, ":") + transferFrom = append(transferFrom, values[0]) + } + d.Set(pdnsInstanceID, idSet[0]) + d.Set(pdnsResolverID, idSet[1]) + d.Set(pdnsSecondaryZoneDescription, *resource.Description) + d.Set(pdnsSecondaryZoneZone, *resource.Zone) + d.Set(pdnsSecondaryZoneTransferFrom, transferFrom) + d.Set(pdnsSecondaryZoneID, *resource.ID) + d.Set(pdnsSecondaryZoneCreatedOn, resource.CreatedOn) + d.Set(pdnsSecondaryZoneModifiedOn, resource.ModifiedOn) + d.Set(pdnsSecondaryZoneEnabled, *resource.Enabled) + + return nil +} + +func resourceIBMPrivateDNSSecondaryZoneUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + + idSet := strings.Split(d.Id(), "/") + if len(idSet) < 3 { + return diag.FromErr(fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/resolverID/secondaryZoneID", d.Id())) + } + instanceID := idSet[0] + resolverID := idSet[1] + secondaryZoneID := idSet[2] + + // Check DNS zone is present + getZoneOptions := sess.NewGetSecondaryZoneOptions(instanceID, resolverID, secondaryZoneID) + _, response, err := sess.GetSecondaryZone(getZoneOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching secondary zone:%s\n%s", err, response)) + } + + // Update DNS zone if attributes has any change + if d.HasChange(pdnsSecondaryZoneTransferFrom) || + d.HasChange(pdnsSecondaryZoneDescription) || + d.HasChange(pdnsSecondaryZoneEnabled) { + updateSecondaryZoneOptions := sess.NewUpdateSecondaryZoneOptions(instanceID, resolverID, secondaryZoneID) + transferFrom := flex.ExpandStringList(d.Get(pdnsSecondaryZoneTransferFrom).([]interface{})) + description := d.Get(pdnsSecondaryZoneDescription).(string) + enabled := d.Get(pdnsSecondaryZoneEnabled).(bool) + updateSecondaryZoneOptions.SetTransferFrom(transferFrom) + updateSecondaryZoneOptions.SetDescription(description) + updateSecondaryZoneOptions.SetEnabled(enabled) + + mk := "private_dns_secondary_zone_" + instanceID + resolverID + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + + _, response, err := sess.UpdateSecondaryZone(updateSecondaryZoneOptions) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating DNS Services zone:%s\n%s", err, response)) + } + } + + return resourceIBMPrivateDNSSecondaryZoneRead(ctx, d, meta) +} + +func resourceIBMPrivateDNSSecondaryZoneDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return diag.FromErr(err) + } + idSet := strings.Split(d.Id(), "/") + if len(idSet) < 3 { + return diag.FromErr(fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/resolverID/secondaryZoneID", d.Id())) + } + instanceID := idSet[0] + resolverID := idSet[1] + secondaryZoneID := idSet[2] + deleteSecondaryZoneOptions := sess.NewDeleteSecondaryZoneOptions(instanceID, resolverID, secondaryZoneID) + + mk := "private_dns_secondary_zone_" + instanceID + resolverID + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) + response, err := sess.DeleteSecondaryZone(deleteSecondaryZoneOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error reading DNS Services secondary zone:%s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone_test.go new file mode 100644 index 000000000..c4557f394 --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_secondary_zone_test.go @@ -0,0 +1,124 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMPrivateDNSSecondaryZone_basic(t *testing.T) { + vpcname := fmt.Sprintf("seczone-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("seczone-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("seczone-cr-%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) + description := "new test CR - TF" + + resource.Test(t, resource.TestCase{ + PreCheck: func() {}, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPrivateDNSSecondaryZoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSSecondaryZoneResource(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_dns_custom_resolver_secondary_zone.test", "zone", "seczone-terraform-plugin-test.com"), + ), + }, + }, + }) +} + +func testAccCheckIBMPrivateDNSSecondaryZoneDestroy(s *terraform.State) error { + // conn := testAccProvider.Meta().(*sdk.Client) + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_dns_secondary_zone" { + continue + } + if rs.Primary.ID == "" { + return fmt.Errorf("No resource primary ID is set") + } + + partslist := strings.Split(rs.Primary.ID, "/") + if len(partslist) < 3 { + return fmt.Errorf("Invalid resource primary ID. Must contain 3 parts.") + } + instanceID := partslist[0] + customResolverID := partslist[1] + secondaryZoneID := partslist[2] + getSecondaryZoneOptions := pdnsClient.NewGetSecondaryZoneOptions( + instanceID, + customResolverID, + secondaryZoneID, + ) + _, _, err := pdnsClient.GetSecondaryZone(getSecondaryZoneOptions) + if err != nil { + return fmt.Errorf("testAccCheckIBMPrivateDNSZoneDestroy: Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + return nil +} + +func testAccCheckIBMPrivateDNSSecondaryZoneResource(vpcname, subnetname, zone, cidr, name, description string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "%s" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "%s" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + + resource "ibm_dns_zone" "pdns-1-zone" { + name = "seczone-terraform-plugin-test.com" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "testdescription" + label = "testlabel" + } + + resource "ibm_dns_custom_resolver_secondary_zone" "test" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + description = "seczone terraform plugin test" + zone = "seczone-terraform-plugin-test.com" + enabled = false + transfer_from = ["10.0.0.8"] + } + `, vpcname, subnetname, zone, cidr, name, description) +} diff --git a/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_test.go new file mode 100644 index 000000000..4fb4d5e6d --- /dev/null +++ b/ibm/service/dnsservices/resource_ibm_private_dns_custom_resolver_test.go @@ -0,0 +1,137 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package dnsservices_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMPrivateDNSCustomResolver_basic(t *testing.T) { + var resultprivatedns string + vpcname := fmt.Sprintf("cr-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("cr-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) + description := "new test CR - TF" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSCustomResolverBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPrivateDNSCustomResolverExists("ibm_dns_custom_resolver.test", resultprivatedns), + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "name", name), + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "description", description), + ), + }, + }, + }) +} + +func TestAccIBMPrivateDNSCustomResolverImport(t *testing.T) { + var resultprivatedns string + vpcname := fmt.Sprintf("cr-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("cr-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("testpdnscustomresolver%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)) + description := "new test CR - TF" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPrivateDNSCustomResolverBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPrivateDNSCustomResolverExists("ibm_dns_custom_resolver.test", resultprivatedns), + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "name", name), + resource.TestCheckResourceAttr("ibm_dns_custom_resolver.test", "description", description), + ), + }, + { + ResourceName: "ibm_dns_custom_resolver.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "type"}, + }, + }, + }) +} + +func testAccCheckIBMPrivateDNSCustomResolverBasic(vpcname, subnetname, zone, cidr, name, description string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "rg" { + is_default = true + } + resource "ibm_is_vpc" "test-pdns-cr-vpc" { + name = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "%s" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + resource_group = data.ibm_resource_group.rg.id + } + resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" + } + resource "ibm_dns_custom_resolver" "test" { + name = "%s" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "%s" + high_availability = false + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + } + `, vpcname, subnetname, zone, cidr, name, description) +} + +func testAccCheckIBMPrivateDNSCustomResolverExists(n string, result string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() + if err != nil { + return err + } + parts := rs.Primary.ID + partslist := strings.Split(parts, ":") + customResolverID := partslist[0] + crn := partslist[1] + + getCustomResolverOptions := pdnsClient.NewGetCustomResolverOptions(crn, customResolverID) + r, res, err := pdnsClient.GetCustomResolver(getCustomResolverOptions) + + if err != nil { + if res != nil && res.StatusCode == 404 { + return nil + } + return fmt.Errorf("testAccCheckIBMPrivateDNSCustomResolverExists: Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + } + + result = *r.ID + return nil + } +} diff --git a/ibm/resource_ibm_private_dns_glb.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb.go similarity index 88% rename from ibm/resource_ibm_private_dns_glb.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb.go index 6ca04eae9..80d4d62dd 100644 --- a/ibm/resource_ibm_private_dns_glb.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/networking-go-sdk/dnssvcsv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -32,7 +34,7 @@ const ( pdnsGLBDeleted = "done" ) -func resourceIBMPrivateDNSGLB() *schema.Resource { +func ResourceIBMPrivateDNSGLB() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSGLBCreate, Read: resourceIBMPrivateDNSGLBRead, @@ -144,7 +146,7 @@ func resourceIBMPrivateDNSGLB() *schema.Resource { } func resourceIBMPrivateDNSGLBCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -155,7 +157,7 @@ func resourceIBMPrivateDNSGLBCreate(d *schema.ResourceData, meta interface{}) er lbname := d.Get(pdnsGLBName).(string) createlbOptions.SetName(lbname) createlbOptions.SetFallbackPool(d.Get(pdnsGLBFallbackPool).(string)) - createlbOptions.SetDefaultPools(expandStringList(d.Get(pdnsGLBDefaultPool).([]interface{}))) + createlbOptions.SetDefaultPools(flex.ExpandStringList(d.Get(pdnsGLBDefaultPool).([]interface{}))) if description, ok := d.GetOk(pdnsGLBDescription); ok { createlbOptions.SetDescription(description.(string)) @@ -186,7 +188,7 @@ func resourceIBMPrivateDNSGLBCreate(d *schema.ResourceData, meta interface{}) er } func resourceIBMPrivateDNSGLBRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -195,7 +197,7 @@ func resourceIBMPrivateDNSGLBRead(d *schema.ResourceData, meta interface{}) erro getlbOptions := sess.NewGetLoadBalancerOptions(idset[0], idset[1], idset[2]) presponse, resp, err := sess.GetLoadBalancer(getlbOptions) if err != nil { - return fmt.Errorf("Error fetching pdns GLB :%s\n%s", err, resp) + return fmt.Errorf("[ERROR] Error fetching pdns GLB :%s\n%s", err, resp) } response := *presponse @@ -216,7 +218,7 @@ func resourceIBMPrivateDNSGLBRead(d *schema.ResourceData, meta interface{}) erro } func resourceIBMPrivateDNSGLBUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -235,7 +237,7 @@ func resourceIBMPrivateDNSGLBUpdate(d *schema.ResourceData, meta interface{}) er updatelbOptions.SetName(d.Get(pdnsGLBName).(string)) updatelbOptions.SetFallbackPool(d.Get(pdnsGLBFallbackPool).(string)) - updatelbOptions.SetDefaultPools(expandStringList(d.Get(pdnsGLBDefaultPool).([]interface{}))) + updatelbOptions.SetDefaultPools(flex.ExpandStringList(d.Get(pdnsGLBDefaultPool).([]interface{}))) if description, ok := d.GetOk(pdnsGLBDescription); ok { updatelbOptions.SetDescription(description.(string)) @@ -257,7 +259,7 @@ func resourceIBMPrivateDNSGLBUpdate(d *schema.ResourceData, meta interface{}) er _, detail, err := sess.UpdateLoadBalancer(updatelbOptions) if err != nil { - return fmt.Errorf("Error updating pdns GLB :%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error updating pdns GLB :%s\n%s", err, detail) } } @@ -265,7 +267,7 @@ func resourceIBMPrivateDNSGLBUpdate(d *schema.ResourceData, meta interface{}) er } func resourceIBMPrivateDNSGLBDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -274,7 +276,7 @@ func resourceIBMPrivateDNSGLBDelete(d *schema.ResourceData, meta interface{}) er deletelbOptions := sess.NewDeleteLoadBalancerOptions(idset[0], idset[1], idset[2]) response, err := sess.DeleteLoadBalancer(deletelbOptions) if err != nil { - return fmt.Errorf("Error deleting pdns GLB :%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns GLB :%s\n%s", err, response) } _, err = isWaitForLoadBalancerDeleted(sess, d, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -284,13 +286,13 @@ func resourceIBMPrivateDNSGLBDelete(d *schema.ResourceData, meta interface{}) er } func resourceIBMPrivateDNSGLBExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idset := strings.Split(d.Id(), "/") if len(idset) < 3 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/zoneID/glbID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/zoneID/glbID", d.Id()) } getlbOptions := sess.NewGetLoadBalancerOptions(idset[0], idset[1], idset[2]) @@ -312,7 +314,7 @@ func expandPDNSGlbAZPools(azpool interface{}) ([]dnssvcsv1.LoadBalancerAzPoolsIt for _, v := range azpools { locationConfig := v.(map[string]interface{}) avzone := locationConfig[pdnsGLBAvailabilityZone].(string) - pools := expandStringList(locationConfig[pdnsGLBAZPoolsPools].([]interface{})) + pools := flex.ExpandStringList(locationConfig[pdnsGLBAZPoolsPools].([]interface{})) aZItem := dnssvcsv1.LoadBalancerAzPoolsItem{ AvailabilityZone: &avzone, Pools: pools, @@ -327,7 +329,7 @@ func flattenPDNSGlbAZpool(azpool []dnssvcsv1.LoadBalancerAzPoolsItem) interface{ for _, v := range azpool { cfg := map[string]interface{}{ pdnsGLBAvailabilityZone: *v.AvailabilityZone, - pdnsGLBAZPoolsPools: flattenStringList(v.Pools), + pdnsGLBAZPoolsPools: flex.FlattenStringList(v.Pools), } flattened = append(flattened, cfg) } @@ -366,7 +368,7 @@ func isVLoadBalancerDeleteRefreshFunc(LoadBalancer *dnssvcsv1.DnsSvcsV1, d *sche if response != nil && response.StatusCode == 404 { return "", pdnsGLBDeleted, nil } - return "", "", fmt.Errorf("Error Getting PDNS Load Balancer : %s\n%s", err, response) + return "", "", fmt.Errorf("[ERROR] Error Getting PDNS Load Balancer : %s\n%s", err, response) } return LoadBalancer, pdnsGLBDeleting, err diff --git a/ibm/resource_ibm_private_dns_glb_monitor.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor.go similarity index 86% rename from ibm/resource_ibm_private_dns_glb_monitor.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor.go index 294516fdb..e0472f121 100644 --- a/ibm/resource_ibm_private_dns_glb_monitor.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/dnssvcsv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -34,7 +37,7 @@ const ( pdnsGlbMonitorModifiedOn = "modified_on" ) -func resourceIBMPrivateDNSGLBMonitor() *schema.Resource { +func ResourceIBMPrivateDNSGLBMonitor() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSGLBMonitorCreate, Read: resourceIBMPrivateDNSGLBMonitorRead, @@ -79,7 +82,7 @@ func resourceIBMPrivateDNSGLBMonitor() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "HTTP", - ValidateFunc: InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorType), + ValidateFunc: validate.InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorType), Description: "The protocol to use for the health check", }, @@ -115,7 +118,7 @@ func resourceIBMPrivateDNSGLBMonitor() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorMethod), + ValidateFunc: validate.InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorMethod), Description: "The method to use for the health check", }, @@ -161,7 +164,7 @@ func resourceIBMPrivateDNSGLBMonitor() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, - ValidateFunc: InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorExpectedCodes), + ValidateFunc: validate.InvokeValidator(ibmDNSGlbMonitor, pdnsGlbMonitorExpectedCodes), Description: "The expected HTTP response code or code range of the health check. This parameter is only valid for HTTP and HTTPS", }, @@ -186,39 +189,39 @@ func resourceIBMPrivateDNSGLBMonitor() *schema.Resource { } } -func resourceIBMPrivateDNSGLBMonitorValidator() *ResourceValidator { +func ResourceIBMPrivateDNSGLBMonitorValidator() *validate.ResourceValidator { monitorCheckTypes := "HTTP, HTTPS, TCP" methods := "GET, HEAD" expectedcode := "200,201,202,203,204,205,206,207,208,226,2xx" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: pdnsGlbMonitorType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: monitorCheckTypes}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: pdnsGlbMonitorMethod, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: methods}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: pdnsGlbMonitorExpectedCodes, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: expectedcode}) - dnsMonitorValidator := ResourceValidator{ResourceName: ibmDNSGlbMonitor, Schema: validateSchema} + dnsMonitorValidator := validate.ResourceValidator{ResourceName: ibmDNSGlbMonitor, Schema: validateSchema} return &dnsMonitorValidator } func resourceIBMPrivateDNSGLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -267,7 +270,7 @@ func resourceIBMPrivateDNSGLBMonitorCreate(d *schema.ResourceData, meta interfac response, detail, err := sess.CreateMonitor(createMonitorOptions) if err != nil { - return fmt.Errorf("Error creating pdns GLB monitor:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error creating pdns GLB monitor:%s\n%s", err, detail) } d.SetId(fmt.Sprintf("%s/%s", instanceID, *response.ID)) @@ -280,7 +283,7 @@ func expandPDNSGLBMonitorsHeader(header interface{}) ([]dnssvcsv1.HealthcheckHea for _, v := range headers { locationConfig := v.(map[string]interface{}) hname := locationConfig[pdnsGlbMonitorHeadersName].(string) - headers := expandStringList(locationConfig[pdnsGlbMonitorHeadersValue].([]interface{})) + headers := flex.ExpandStringList(locationConfig[pdnsGlbMonitorHeadersValue].([]interface{})) headerItem := dnssvcsv1.HealthcheckHeader{ Name: &hname, Value: headers, @@ -291,7 +294,7 @@ func expandPDNSGLBMonitorsHeader(header interface{}) ([]dnssvcsv1.HealthcheckHea } func resourceIBMPrivateDNSGLBMonitorRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -300,7 +303,7 @@ func resourceIBMPrivateDNSGLBMonitorRead(d *schema.ResourceData, meta interface{ getMonitorOptions := sess.NewGetMonitorOptions(idset[0], idset[1]) response, detail, err := sess.GetMonitor(getMonitorOptions) if err != nil { - return fmt.Errorf("Error fetching pdns GLB Monitor:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error fetching pdns GLB Monitor:%s\n%s", err, detail) } d.Set(pdnsInstanceID, idset[0]) d.Set(pdnsGlbMonitorID, response.ID) @@ -348,7 +351,7 @@ func flattenDataSourceLoadBalancerHeader(header []dnssvcsv1.HealthcheckHeader) i for _, v := range header { cfg := map[string]interface{}{ pdnsGlbMonitorHeadersName: v.Name, - pdnsGlbMonitorHeadersValue: flattenStringList(v.Value), + pdnsGlbMonitorHeadersValue: flex.FlattenStringList(v.Value), } flattened = append(flattened, cfg) } @@ -356,7 +359,7 @@ func flattenDataSourceLoadBalancerHeader(header []dnssvcsv1.HealthcheckHeader) i } func resourceIBMPrivateDNSGLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -422,7 +425,7 @@ func resourceIBMPrivateDNSGLBMonitorUpdate(d *schema.ResourceData, meta interfac _, detail, err := sess.UpdateMonitor(updateMonitorOptions) if err != nil { - return fmt.Errorf("Error updating pdns GLB Monitor:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error updating pdns GLB Monitor:%s\n%s", err, detail) } } @@ -430,7 +433,7 @@ func resourceIBMPrivateDNSGLBMonitorUpdate(d *schema.ResourceData, meta interfac } func resourceIBMPrivateDNSGLBMonitorDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -441,7 +444,7 @@ func resourceIBMPrivateDNSGLBMonitorDelete(d *schema.ResourceData, meta interfac response, err := sess.DeleteMonitor(DeleteMonitorOptions) if err != nil { - return fmt.Errorf("Error deleting pdns GLB Monitor:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns GLB Monitor:%s\n%s", err, response) } d.SetId("") @@ -449,14 +452,14 @@ func resourceIBMPrivateDNSGLBMonitorDelete(d *schema.ResourceData, meta interfac } func resourceIBMPrivateDNSGLBMonitorExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idset := strings.Split(d.Id(), "/") if len(idset) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/monitorID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/monitorID", d.Id()) } getMonitorOptions := sess.NewGetMonitorOptions(idset[0], idset[1]) diff --git a/ibm/resource_ibm_private_dns_glb_monitor_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor_test.go similarity index 93% rename from ibm/resource_ibm_private_dns_glb_monitor_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor_test.go index cab5b463e..5e51e0a8a 100644 --- a/ibm/resource_ibm_private_dns_glb_monitor_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb_monitor_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +20,8 @@ func TestAccIBMPrivateDNSGlbMonitor_Basic(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnspn%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbMonitorDestroy, Steps: []resource.TestStep{ { @@ -52,8 +55,8 @@ func TestAccIBMPrivateDNSGlbMonitorImport(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbMonitorDestroy, Steps: []resource.TestStep{ { @@ -195,7 +198,7 @@ func testAccCheckIBMPrivateDNSGlbMonitorDestroy(s *terraform.State) error { if rs.Type != "ibm_dns_glb_monitor" { continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -222,8 +225,7 @@ func testAccCheckIBMPrivateDNSGlbMonitorExists(n string, result string) resource if !ok { return fmt.Errorf("Not found: %s", n) } - - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/resource_ibm_private_dns_glb_pool.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb_pool.go similarity index 86% rename from ibm/resource_ibm_private_dns_glb_pool.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb_pool.go index 58a96551c..72ccd26e6 100644 --- a/ibm/resource_ibm_private_dns_glb_pool.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb_pool.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/go-sdk-core/v5/core" dns "github.com/IBM/networking-go-sdk/dnssvcsv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -40,7 +42,7 @@ const ( pdnsGlbPoolDeleted = "deleted" ) -func resourceIBMPrivateDNSGLBPool() *schema.Resource { +func ResourceIBMPrivateDNSGLBPool() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSGLBPoolCreate, @@ -143,10 +145,9 @@ func resourceIBMPrivateDNSGLBPool() *schema.Resource { Description: "The notification channel,It is a webhook url", }, pdnsGlbPoolRegion: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: InvokeValidator(ibmDNSGlbPool, pdnsGlbPoolRegion), - Description: "Health check region of VSIs", + Type: schema.TypeString, + Optional: true, + Description: "Health check region of VSIs", }, pdnsGlbPoolSubnet: { Type: schema.TypeList, @@ -170,23 +171,8 @@ func resourceIBMPrivateDNSGLBPool() *schema.Resource { } } -func resourceIBMPrivateDNSGLBPoolValidator() *ResourceValidator { - regions := "us-south,us-east,eu-gb,eu-du,au-syd,jp-tok" - - validateSchema := make([]ValidateSchema, 0) - validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: pdnsGlbPoolRegion, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, - Required: true, - AllowedValues: regions}) - dnsPoolValidator := ResourceValidator{ResourceName: ibmDNSGlbPool, Schema: validateSchema} - return &dnsPoolValidator -} - func resourceIBMPrivateDNSGLBPoolCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -207,7 +193,7 @@ func resourceIBMPrivateDNSGLBPoolCreate(d *schema.ResourceData, meta interface{} CreatePoolOptions.SetHealthyOriginsThreshold(int64(threshold.(int))) } if monitor, ok := d.GetOk(pdnsGlbPoolMonitor); ok { - monitorID, _, _ := convertTftoCisTwoVar(monitor.(string)) + monitorID, _, _ := flex.ConvertTftoCisTwoVar(monitor.(string)) CreatePoolOptions.SetMonitor(monitorID) } if chanel, ok := d.GetOk(pdnsGlbPoolChannel); ok { @@ -217,7 +203,7 @@ func resourceIBMPrivateDNSGLBPoolCreate(d *schema.ResourceData, meta interface{} CreatePoolOptions.SetHealthcheckRegion(region.(string)) } if subnets, ok := d.GetOk(pdnsGlbPoolSubnet); ok { - CreatePoolOptions.SetHealthcheckSubnets(expandStringList(subnets.([]interface{}))) + CreatePoolOptions.SetHealthcheckSubnets(flex.ExpandStringList(subnets.([]interface{}))) } poolorigins := d.Get(pdnsGlbPoolOrigins).(*schema.Set) @@ -234,7 +220,7 @@ func resourceIBMPrivateDNSGLBPoolCreate(d *schema.ResourceData, meta interface{} } func resourceIBMPrivateDNSGLBPoolRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -243,7 +229,7 @@ func resourceIBMPrivateDNSGLBPoolRead(d *schema.ResourceData, meta interface{}) getPoolOptions := sess.NewGetPoolOptions(idset[0], idset[1]) presponse, resp, err := sess.GetPool(getPoolOptions) if err != nil { - return fmt.Errorf("Error fetching pdns GLB Pool:%s\n%s", err, resp) + return fmt.Errorf("[ERROR] Error fetching pdns GLB Pool:%s\n%s", err, resp) } response := *presponse @@ -282,7 +268,7 @@ func flattenPDNSGlbPoolOrigins(list []dns.Origin) []map[string]interface{} { } func resourceIBMPrivateDNSGLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -312,7 +298,7 @@ func resourceIBMPrivateDNSGLBPoolUpdate(d *schema.ResourceData, meta interface{} updatePoolOptions.SetHealthyOriginsThreshold(int64(threshold.(int))) } if monitor, ok := d.GetOk(pdnsGlbPoolMonitor); ok { - monitorID, _, _ := convertTftoCisTwoVar(monitor.(string)) + monitorID, _, _ := flex.ConvertTftoCisTwoVar(monitor.(string)) updatePoolOptions.SetMonitor(monitorID) } if chanel, ok := d.GetOk(pdnsGlbPoolChannel); ok { @@ -322,7 +308,7 @@ func resourceIBMPrivateDNSGLBPoolUpdate(d *schema.ResourceData, meta interface{} updatePoolOptions.SetHealthcheckRegion(region.(string)) } if _, ok := d.GetOk(pdnsGlbPoolSubnet); ok { - updatePoolOptions.SetHealthcheckSubnets(expandStringList(d.Get(pdnsGlbPoolSubnet).([]interface{}))) + updatePoolOptions.SetHealthcheckSubnets(flex.ExpandStringList(d.Get(pdnsGlbPoolSubnet).([]interface{}))) } if _, ok := d.GetOk(pdnsGlbPoolOrigins); ok { poolorigins := d.Get(pdnsGlbPoolOrigins).(*schema.Set) @@ -331,7 +317,7 @@ func resourceIBMPrivateDNSGLBPoolUpdate(d *schema.ResourceData, meta interface{} } _, detail, err := sess.UpdatePool(updatePoolOptions) if err != nil { - return fmt.Errorf("Error updating pdns GLB Pool:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error updating pdns GLB Pool:%s\n%s", err, detail) } } @@ -339,7 +325,7 @@ func resourceIBMPrivateDNSGLBPoolUpdate(d *schema.ResourceData, meta interface{} } func resourceIBMPrivateDNSGLBPoolDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -348,7 +334,7 @@ func resourceIBMPrivateDNSGLBPoolDelete(d *schema.ResourceData, meta interface{} DeletePoolOptions := sess.NewDeletePoolOptions(idset[0], idset[1]) response, err := sess.DeletePool(DeletePoolOptions) if err != nil { - return fmt.Errorf("Error deleting pdns GLB Pool:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns GLB Pool:%s\n%s", err, response) } _, err = waitForPDNSGlbPoolDelete(d, meta) if err != nil { @@ -359,14 +345,14 @@ func resourceIBMPrivateDNSGLBPoolDelete(d *schema.ResourceData, meta interface{} } func resourceIBMPrivateDNSGLBPoolExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idset := strings.Split(d.Id(), "/") if len(idset) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/poolID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/poolID", d.Id()) } getPoolOptions := sess.NewGetPoolOptions(idset[0], idset[1]) @@ -395,7 +381,7 @@ func expandPDNSGlbPoolOrigins(originsList *schema.Set) (origins []dns.OriginInpu } func waitForPDNSGlbPoolDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - cisClient, err := meta.(ClientSession).PrivateDNSClientSession() + cisClient, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return nil, err } @@ -408,11 +394,11 @@ func waitForPDNSGlbPoolDelete(d *schema.ResourceData, meta interface{}) (interfa _, detail, err := cisClient.GetPool(getPoolOptions) if err != nil { if detail != nil && detail.StatusCode == 404 { - return detail, clusterDeleted, nil + return detail, "deleted", nil } return nil, "", err } - return detail, clusterDeletePending, nil + return detail, "deleting", nil }, Timeout: d.Timeout(schema.TimeoutDelete), Delay: 60 * time.Second, diff --git a/ibm/resource_ibm_private_dns_glb_pool_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb_pool_test.go similarity index 93% rename from ibm/resource_ibm_private_dns_glb_pool_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb_pool_test.go index 7dfc3c3b8..0d155e75d 100644 --- a/ibm/resource_ibm_private_dns_glb_pool_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb_pool_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +20,8 @@ func TestAccIBMPrivateDNSGlbPool_Basic(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnspn%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbPoolDestroy, Steps: []resource.TestStep{ { @@ -47,8 +50,8 @@ func TestAccIBMPrivateDNSGlbPoolImport(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbPoolDestroy, Steps: []resource.TestStep{ { @@ -194,7 +197,7 @@ func testAccCheckIBMPrivateDNSGlbPoolDestroy(s *terraform.State) error { continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -223,7 +226,7 @@ func testAccCheckIBMGlbPoolExists(n string, result string) resource.TestCheckFun return fmt.Errorf("Not found: %s", n) } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/resource_ibm_private_dns_glb_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_glb_test.go similarity index 93% rename from ibm/resource_ibm_private_dns_glb_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_glb_test.go index a5b73b002..89758c855 100644 --- a/ibm/resource_ibm_private_dns_glb_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_glb_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,8 +22,8 @@ func TestAccIBMPrivateDNSGlbLoadBalancer_Basic(t *testing.T) { newName := fmt.Sprintf("Test-load-balancer.%s", name) updateName := fmt.Sprintf("Update-load-balancer.%s", name) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbDestroy, Steps: []resource.TestStep{ { @@ -47,8 +50,8 @@ func TestAccIBMPrivateDNSGlboadBalancerImport(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSGlbMonitorDestroy, Steps: []resource.TestStep{ { @@ -181,7 +184,7 @@ func testAccCheckIBMPrivateDNSGlbDestroy(s *terraform.State) error { if rs.Type != "ibm_dns_glb" { continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -209,7 +212,7 @@ func testAccCheckIBMPrivateDNSGlbLoadBalancerExists(n string, result *string) re return fmt.Errorf("Not found: %s", n) } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/resource_ibm_private_dns_permitted_network.go b/ibm/service/dnsservices/resource_ibm_private_dns_permitted_network.go similarity index 81% rename from ibm/resource_ibm_private_dns_permitted_network.go rename to ibm/service/dnsservices/resource_ibm_private_dns_permitted_network.go index 69d635085..679c31fce 100644 --- a/ibm/resource_ibm_private_dns_permitted_network.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_permitted_network.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -25,7 +27,7 @@ var allowedNetworkTypes = []string{ "vpc", } -func resourceIBMPrivateDNSPermittedNetwork() *schema.Resource { +func ResourceIBMPrivateDNSPermittedNetwork() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSPermittedNetworkCreate, Read: resourceIBMPrivateDNSPermittedNetworkRead, @@ -64,7 +66,7 @@ func resourceIBMPrivateDNSPermittedNetwork() *schema.Resource { Optional: true, ForceNew: true, Default: "vpc", - ValidateFunc: validateAllowedStringValue([]string{"vpc"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"vpc"}), Description: "Network Type", }, @@ -97,7 +99,7 @@ func resourceIBMPrivateDNSPermittedNetwork() *schema.Resource { } func resourceIBMPrivateDNSPermittedNetworkCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -107,8 +109,8 @@ func resourceIBMPrivateDNSPermittedNetworkCreate(d *schema.ResourceData, meta in vpcCRN := d.Get(pdnsVpcCRN).(string) nwType := d.Get(pdnsNetworkType).(string) mk := "private_dns_permitted_network_" + instanceID + zoneID - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) createPermittedNetworkOptions := sess.NewCreatePermittedNetworkOptions(instanceID, zoneID) permittedNetworkCrn, err := sess.NewPermittedNetworkVpc(vpcCRN) @@ -120,7 +122,7 @@ func resourceIBMPrivateDNSPermittedNetworkCreate(d *schema.ResourceData, meta in createPermittedNetworkOptions.SetType(nwType) response, detail, err := sess.CreatePermittedNetwork(createPermittedNetworkOptions) if err != nil { - return fmt.Errorf("Error creating pdns permitted network:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error creating pdns permitted network:%s\n%s", err, detail) } d.SetId(fmt.Sprintf("%s/%s/%s", instanceID, zoneID, *response.ID)) @@ -129,7 +131,7 @@ func resourceIBMPrivateDNSPermittedNetworkCreate(d *schema.ResourceData, meta in } func resourceIBMPrivateDNSPermittedNetworkRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -139,7 +141,7 @@ func resourceIBMPrivateDNSPermittedNetworkRead(d *schema.ResourceData, meta inte response, detail, err := sess.GetPermittedNetwork(getPermittedNetworkOptions) if err != nil { - return fmt.Errorf("Error reading pdns permitted network:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading pdns permitted network:%s\n%s", err, detail) } d.Set(pdnsInstanceID, idSet[0]) @@ -155,20 +157,20 @@ func resourceIBMPrivateDNSPermittedNetworkRead(d *schema.ResourceData, meta inte } func resourceIBMPrivateDNSPermittedNetworkDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } idSet := strings.Split(d.Id(), "/") mk := "private_dns_permitted_network_" + idSet[0] + idSet[1] - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) deletePermittedNetworkOptions := sess.NewDeletePermittedNetworkOptions(idSet[0], idSet[1], idSet[2]) _, response, err := sess.DeletePermittedNetwork(deletePermittedNetworkOptions) if err != nil { - return fmt.Errorf("Error deleting pdns permitted network:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns permitted network:%s\n%s", err, response) } d.SetId("") @@ -176,19 +178,19 @@ func resourceIBMPrivateDNSPermittedNetworkDelete(d *schema.ResourceData, meta in } func resourceIBMPrivateDNSPermittedNetworkExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idSet := strings.Split(d.Id(), "/") if len(idSet) < 3 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/zoneID/permittedNetworkID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/zoneID/permittedNetworkID", d.Id()) } mk := "private_dns_permitted_network_" + idSet[0] + idSet[1] - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) getPermittedNetworkOptions := sess.NewGetPermittedNetworkOptions(idSet[0], idSet[1], idSet[2]) _, response, err := sess.GetPermittedNetwork(getPermittedNetworkOptions) if err != nil { diff --git a/ibm/resource_ibm_private_dns_permitted_network_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_permitted_network_test.go similarity index 90% rename from ibm/resource_ibm_private_dns_permitted_network_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_permitted_network_test.go index 1418729e8..91d6dab31 100644 --- a/ibm/resource_ibm_private_dns_permitted_network_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_permitted_network_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +20,8 @@ func TestAccIBMPrivateDNSPermittedNetwork_Basic(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnspn%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSPermittedNetworkDestroy, Steps: []resource.TestStep{ { @@ -36,8 +39,8 @@ func TestAccIBMPrivateDNSPermittedNetworkImport(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSPermittedNetworkDestroy, Steps: []resource.TestStep{ { @@ -95,7 +98,7 @@ func testAccCheckIBMPrivateDNSPermittedNetworkDestroy(s *terraform.State) error continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -124,7 +127,7 @@ func testAccCheckIBMPrivateDNSPermittedNetworkExists(n string, result string) re return fmt.Errorf("Not found: %s", n) } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/resource_ibm_private_dns_resource_record.go b/ibm/service/dnsservices/resource_ibm_private_dns_resource_record.go similarity index 81% rename from ibm/resource_ibm_private_dns_resource_record.go rename to ibm/service/dnsservices/resource_ibm_private_dns_resource_record.go index 114e39d73..d9c52ec6f 100644 --- a/ibm/resource_ibm_private_dns_resource_record.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_resource_record.go @@ -1,19 +1,32 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" + "math/rand" + "regexp" "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) var allowedPrivateDomainRecordTypes = []string{ "A", "AAAA", "CNAME", "MX", "PTR", "SRV", "TXT", } +var ipv6Regexp *regexp.Regexp +var upcaseRegexp *regexp.Regexp + +func init() { + ipv6Regexp, _ = regexp.Compile( + "[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}:" + + "[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}:[a-zA-Z0-9]{4}", + ) + upcaseRegexp, _ = regexp.Compile("[A-Z]") +} const ( pdnsResourceRecordID = "resource_record_id" @@ -35,7 +48,7 @@ func caseDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { return strings.ToUpper(old) == strings.ToUpper(new) } -func resourceIBMPrivateDNSResourceRecord() *schema.Resource { +func ResourceIBMPrivateDNSResourceRecord() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSResourceRecordCreate, Read: resourceIBMPrivateDNSResourceRecordRead, @@ -186,7 +199,7 @@ func resourceIBMPrivateDNSResourceRecord() *schema.Resource { } func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -225,31 +238,31 @@ func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta inte case "A": resourceRecordAData, err := sess.NewResourceRecordInputRdataRdataARecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record A data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record A data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordAData) case "AAAA": resourceRecordAaaaData, err := sess.NewResourceRecordInputRdataRdataAaaaRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Aaaa data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Aaaa data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordAaaaData) case "CNAME": resourceRecordCnameData, err := sess.NewResourceRecordInputRdataRdataCnameRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Cname data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Cname data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordCnameData) case "PTR": resourceRecordPtrData, err := sess.NewResourceRecordInputRdataRdataPtrRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Ptr data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Ptr data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordPtrData) case "TXT": resourceRecordTxtData, err := sess.NewResourceRecordInputRdataRdataTxtRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Txt data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Txt data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordTxtData) case "MX": @@ -258,7 +271,7 @@ func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta inte } resourceRecordMxData, err := sess.NewResourceRecordInputRdataRdataMxRecord(rdata, int64(preference)) if err != nil { - return fmt.Errorf("Error creating pdns resource record Mx data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Mx data:%s", err) } createResourceRecordOptions.SetRdata(resourceRecordMxData) case "SRV": @@ -273,7 +286,7 @@ func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta inte } resourceRecordSrvData, err := sess.NewResourceRecordInputRdataRdataSrvRecord(int64(port), int64(priority), rdata, int64(weight)) if err != nil { - return fmt.Errorf("Error creating pdns resource record Srv data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Srv data:%s", err) } if v, ok := d.GetOk(pdnsSrvService); ok { service = v.(string) @@ -285,12 +298,14 @@ func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta inte createResourceRecordOptions.SetService(service) createResourceRecordOptions.SetProtocol(protocol) } - mk := "private_dns_resource_record_" + instanceID + zoneID - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + rand.Seed(time.Now().UnixNano()) + randI := fmt.Sprint(rand.Intn(50)) + mk := "private_dns_resource_record_" + instanceID + zoneID + randI + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) response, detail, err := sess.CreateResourceRecord(createResourceRecordOptions) if err != nil { - return fmt.Errorf("Error creating pdns resource record:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error creating pdns resource record:%s\n%s", err, detail) } d.SetId(fmt.Sprintf("%s/%s/%s", instanceID, zoneID, *response.ID)) @@ -300,14 +315,14 @@ func resourceIBMPrivateDNSResourceRecordCreate(d *schema.ResourceData, meta inte func resourceIBMPrivateDNSResourceRecordRead(d *schema.ResourceData, meta interface{}) error { idSet := strings.Split(d.Id(), "/") - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } getResourceRecordOptions := sess.NewGetResourceRecordOptions(idSet[0], idSet[1], idSet[2]) response, detail, err := sess.GetResourceRecord(getResourceRecordOptions) if err != nil { - return fmt.Errorf("Error reading pdns resource record:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading pdns resource record:%s\n%s", err, detail) } // extract the record name by removing zone details @@ -370,14 +385,15 @@ func resourceIBMPrivateDNSResourceRecordRead(d *schema.ResourceData, meta interf func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta interface{}) error { idSet := strings.Split(d.Id(), "/") - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } - - mk := "private_dns_resource_record_" + idSet[0] + idSet[1] - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + rand.Seed(time.Now().UnixNano()) + randI := fmt.Sprint(rand.Intn(50)) + mk := "private_dns_resource_record_" + idSet[0] + idSet[1] + randI + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) updateResourceRecordOptions := sess.NewUpdateResourceRecordOptions(idSet[0], idSet[1], idSet[2]) @@ -401,7 +417,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte rdata = d.Get(pdnsRdata).(string) resourceRecordAData, err := sess.NewResourceRecordUpdateInputRdataRdataARecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record A data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record A data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordAData) @@ -410,7 +426,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte rdata = d.Get(pdnsRdata).(string) resourceRecordAaaaData, err := sess.NewResourceRecordUpdateInputRdataRdataAaaaRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Aaaa data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Aaaa data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordAaaaData) @@ -419,7 +435,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte rdata = d.Get(pdnsRdata).(string) resourceRecordCnameData, err := sess.NewResourceRecordUpdateInputRdataRdataCnameRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Cname data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Cname data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordCnameData) @@ -431,7 +447,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte rdata = d.Get(pdnsRdata).(string) resourceRecordTxtData, err := sess.NewResourceRecordUpdateInputRdataRdataTxtRecord(rdata) if err != nil { - return fmt.Errorf("Error creating pdns resource record Txt data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Txt data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordTxtData) @@ -442,7 +458,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte resourceRecordMxData, err := sess.NewResourceRecordUpdateInputRdataRdataMxRecord(rdata, int64(preference)) if err != nil { - return fmt.Errorf("Error creating pdns resource record Mx data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Mx data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordMxData) @@ -455,7 +471,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte resourceRecordSrvData, err := sess.NewResourceRecordUpdateInputRdataRdataSrvRecord(int64(port), int64(priority), rdata, int64(weight)) if err != nil { - return fmt.Errorf("Error creating pdns resource record Srv data:%s", err) + return fmt.Errorf("[ERROR] Error creating pdns resource record Srv data:%s", err) } updateResourceRecordOptions.SetRdata(resourceRecordSrvData) @@ -467,7 +483,7 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte _, detail, err := sess.UpdateResourceRecord(updateResourceRecordOptions) if err != nil { - return fmt.Errorf("Error updating pdns resource record:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error updating pdns resource record:%s\n%s", err, detail) } } @@ -477,18 +493,19 @@ func resourceIBMPrivateDNSResourceRecordUpdate(d *schema.ResourceData, meta inte func resourceIBMPrivateDNSResourceRecordDelete(d *schema.ResourceData, meta interface{}) error { idSet := strings.Split(d.Id(), "/") - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } - + rand.Seed(time.Now().UnixNano()) + randI := fmt.Sprint(rand.Intn(50)) deleteResourceRecordOptions := sess.NewDeleteResourceRecordOptions(idSet[0], idSet[1], idSet[2]) - mk := "private_dns_resource_record_" + idSet[0] + idSet[1] - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + mk := "private_dns_resource_record_" + idSet[0] + idSet[1] + randI + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) response, err := sess.DeleteResourceRecord(deleteResourceRecordOptions) if err != nil { - return fmt.Errorf("Error deleting pdns resource record:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns resource record:%s\n%s", err, response) } d.SetId("") @@ -496,19 +513,21 @@ func resourceIBMPrivateDNSResourceRecordDelete(d *schema.ResourceData, meta inte } func resourceIBMPrivateDNSResourceRecordExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idSet := strings.Split(d.Id(), "/") if len(idSet) < 3 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/zoneID/recordID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/zoneID/recordID", d.Id()) } + rand.Seed(time.Now().UnixNano()) + randI := fmt.Sprint(rand.Intn(50)) getResourceRecordOptions := sess.NewGetResourceRecordOptions(idSet[0], idSet[1], idSet[2]) - mk := "private_dns_resource_record_" + idSet[0] + idSet[1] - ibmMutexKV.Lock(mk) - defer ibmMutexKV.Unlock(mk) + mk := "private_dns_resource_record_" + idSet[0] + idSet[1] + randI + conns.IbmMutexKV.Lock(mk) + defer conns.IbmMutexKV.Unlock(mk) _, response, err := sess.GetResourceRecord(getResourceRecordOptions) if err != nil { diff --git a/ibm/resource_ibm_private_dns_resource_record_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_resource_record_test.go similarity index 95% rename from ibm/resource_ibm_private_dns_resource_record_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_resource_record_test.go index 77c110d5a..73fa92aeb 100644 --- a/ibm/resource_ibm_private_dns_resource_record_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_resource_record_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +20,8 @@ func TestAccIBMPrivateDNSResourceRecord_Basic(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnsresourcerecord%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSResourceRecordDestroy, Steps: []resource.TestStep{ { @@ -43,8 +46,8 @@ func TestAccIBMPrivateDNSResourceRecordImport(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSResourceRecordDestroy, Steps: []resource.TestStep{ { @@ -286,7 +289,7 @@ func testAccCheckIBMPrivateDNSResourceRecordDestroy(s *terraform.State) error { if rs.Type != "ibm_dns_resource_record" { continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -312,7 +315,7 @@ func testAccCheckIBMPrivateDNSResourceRecordExists(n string, result *string) res if !ok { return fmt.Errorf("Not found: %s", n) } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/resource_ibm_private_dns_zones.go b/ibm/service/dnsservices/resource_ibm_private_dns_zones.go similarity index 84% rename from ibm/resource_ibm_private_dns_zones.go rename to ibm/service/dnsservices/resource_ibm_private_dns_zones.go index 54d0f440f..dd5cc2f51 100644 --- a/ibm/resource_ibm_private_dns_zones.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_zones.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices import ( "fmt" "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -22,7 +23,7 @@ const ( pdnsZoneID = "zone_id" ) -func resourceIBMPrivateDNSZone() *schema.Resource { +func ResourceIBMPrivateDNSZone() *schema.Resource { return &schema.Resource{ Create: resourceIBMPrivateDNSZoneCreate, Read: resourceIBMPrivateDNSZoneRead, @@ -94,7 +95,7 @@ func resourceIBMPrivateDNSZone() *schema.Resource { } func resourceIBMPrivateDNSZoneCreate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -120,7 +121,7 @@ func resourceIBMPrivateDNSZoneCreate(d *schema.ResourceData, meta interface{}) e createZoneOptions.SetLabel(zoneLabel) response, detail, err := sess.CreateDnszone(createZoneOptions) if err != nil { - return fmt.Errorf("Error creating pdns zone:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error creating pdns zone:%s\n%s", err, detail) } d.SetId(fmt.Sprintf("%s/%s", *response.InstanceID, *response.ID)) @@ -130,7 +131,7 @@ func resourceIBMPrivateDNSZoneCreate(d *schema.ResourceData, meta interface{}) e } func resourceIBMPrivateDNSZoneRead(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -139,7 +140,7 @@ func resourceIBMPrivateDNSZoneRead(d *schema.ResourceData, meta interface{}) err getZoneOptions := sess.NewGetDnszoneOptions(idSet[0], idSet[1]) response, detail, err := sess.GetDnszone(getZoneOptions) if err != nil { - return fmt.Errorf("Error fetching pdns zone:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error fetching pdns zone:%s\n%s", err, detail) } d.Set(pdnsZoneID, response.ID) @@ -155,7 +156,7 @@ func resourceIBMPrivateDNSZoneRead(d *schema.ResourceData, meta interface{}) err } func resourceIBMPrivateDNSZoneUpdate(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -166,7 +167,7 @@ func resourceIBMPrivateDNSZoneUpdate(d *schema.ResourceData, meta interface{}) e getZoneOptions := sess.NewGetDnszoneOptions(idSet[0], idSet[1]) _, response, err := sess.GetDnszone(getZoneOptions) if err != nil { - return fmt.Errorf("Error fetching pdns zone:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching pdns zone:%s\n%s", err, response) } // Update DNS zone if attributes has any change @@ -181,7 +182,7 @@ func resourceIBMPrivateDNSZoneUpdate(d *schema.ResourceData, meta interface{}) e _, detail, err := sess.UpdateDnszone(updateZoneOptions) if err != nil { - return fmt.Errorf("Error updating pdns zone:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error updating pdns zone:%s\n%s", err, detail) } } @@ -189,7 +190,7 @@ func resourceIBMPrivateDNSZoneUpdate(d *schema.ResourceData, meta interface{}) e } func resourceIBMPrivateDNSZoneDelete(d *schema.ResourceData, meta interface{}) error { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -199,7 +200,7 @@ func resourceIBMPrivateDNSZoneDelete(d *schema.ResourceData, meta interface{}) e deleteZoneOptions := sess.NewDeleteDnszoneOptions(idSet[0], idSet[1]) response, err := sess.DeleteDnszone(deleteZoneOptions) if err != nil { - return fmt.Errorf("Error deleting pdns zone:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting pdns zone:%s\n%s", err, response) } d.SetId("") @@ -208,14 +209,14 @@ func resourceIBMPrivateDNSZoneDelete(d *schema.ResourceData, meta interface{}) e func resourceIBMPrivateDNSZoneExists(d *schema.ResourceData, meta interface{}) (bool, error) { - sess, err := meta.(ClientSession).PrivateDNSClientSession() + sess, err := meta.(conns.ClientSession).PrivateDNSClientSession() if err != nil { return false, err } idSet := strings.Split(d.Id(), "/") if len(idSet) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of InstanceID/zoneID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of InstanceID/zoneID", d.Id()) } getZoneOptions := sess.NewGetDnszoneOptions(idSet[0], idSet[1]) _, response, err := sess.GetDnszone(getZoneOptions) diff --git a/ibm/resource_ibm_private_dns_zones_test.go b/ibm/service/dnsservices/resource_ibm_private_dns_zones_test.go similarity index 88% rename from ibm/resource_ibm_private_dns_zones_test.go rename to ibm/service/dnsservices/resource_ibm_private_dns_zones_test.go index 56b6d804c..fe72a038c 100644 --- a/ibm/resource_ibm_private_dns_zones_test.go +++ b/ibm/service/dnsservices/resource_ibm_private_dns_zones_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package dnsservices_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +20,8 @@ func TestAccIBMPrivateDNSZone_Basic(t *testing.T) { var resultprivatedns string name := fmt.Sprintf("testpdnszone%s.com", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSZoneDestroy, Steps: []resource.TestStep{ { @@ -38,8 +41,8 @@ func TestAccIBMPrivateDNSZoneImport(t *testing.T) { //var resultendpoint apigatewaysdk.V2Endpoint //name := fmt.Sprintf("tftest-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPrivateDNSZoneDestroy, Steps: []resource.TestStep{ { @@ -87,7 +90,7 @@ func testAccCheckIBMPrivateDNSZoneDestroy(s *terraform.State) error { if rs.Type != "ibm_dns_zone" { continue } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } @@ -113,7 +116,7 @@ func testAccCheckIBMPrivateDNSZoneExists(n string, result string) resource.TestC if !ok { return fmt.Errorf("Not found: %s", n) } - pdnsClient, err := testAccProvider.Meta().(ClientSession).PrivateDNSClientSession() + pdnsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PrivateDNSClientSession() if err != nil { return err } diff --git a/ibm/service/enterprise/README.md b/ibm/service/enterprise/README.md new file mode 100644 index 000000000..fbc143a49 --- /dev/null +++ b/ibm/service/enterprise/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Enterprise Management + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Enterprise resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/enterprise) +* IBM API Docs: [IBM API Docs for Enterprise](https://cloud.ibm.com/apidocs/enterprise-apis/enterprise) +* IBM Enterprise SDK: [IBM SDK for Enterprise](https://github.com/IBM/platform-services-go-sdk/tree/main/enterprisemanagementv1) diff --git a/ibm/data_source_ibm_enterprise_account_groups.go b/ibm/service/enterprise/data_source_ibm_enterprise_account_groups.go similarity index 89% rename from ibm/data_source_ibm_enterprise_account_groups.go rename to ibm/service/enterprise/data_source_ibm_enterprise_account_groups.go index 74859bf6d..fd6078fd6 100644 --- a/ibm/data_source_ibm_enterprise_account_groups.go +++ b/ibm/service/enterprise/data_source_ibm_enterprise_account_groups.go @@ -1,109 +1,112 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "log" "net/url" "reflect" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func dataSourceIbmEnterpriseAccountGroups() *schema.Resource { +func DataSourceIBMEnterpriseAccountGroups() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmEnterpriseAccountGroupsRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The name of the account group.", - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "account_groups": &schema.Schema{ + "account_groups": { Type: schema.TypeList, Computed: true, Description: "A list of account groups.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the account group.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The account group ID.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the account group.", }, - "parent": &schema.Schema{ + "parent": { Type: schema.TypeString, Computed: true, Description: "The CRN of the parent of the account group.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise account ID.", }, - "enterprise_id": &schema.Schema{ + "enterprise_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise ID that the account group is a part of.", }, - "enterprise_path": &schema.Schema{ + "enterprise_path": { Type: schema.TypeString, Computed: true, Description: "The path from the enterprise to this particular account group.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The name of the account group.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the account group.", }, - "primary_contact_iam_id": &schema.Schema{ + "primary_contact_iam_id": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the primary contact of the account group.", }, - "primary_contact_email": &schema.Schema{ + "primary_contact_email": { Type: schema.TypeString, Computed: true, Description: "The email address of the primary contact of the account group.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account group was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the account group.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account group was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the account group.", @@ -128,7 +131,7 @@ func getEnterpriseNext(next *string) (string, error) { } func dataSourceIbmEnterpriseAccountGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -184,7 +187,7 @@ func dataSourceIbmEnterpriseAccountGroupsRead(context context.Context, d *schema if allRecs != nil { err = d.Set("account_groups", dataSourceListEnterpriseAccountGroupsResponseFlattenResources(allRecs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resources %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resources %s", err)) } } diff --git a/ibm/data_source_ibm_enterprise_account_groups_test.go b/ibm/service/enterprise/data_source_ibm_enterprise_account_groups_test.go similarity index 91% rename from ibm/data_source_ibm_enterprise_account_groups_test.go rename to ibm/service/enterprise/data_source_ibm_enterprise_account_groups_test.go index ef57c752c..3d20fc8ad 100644 --- a/ibm/data_source_ibm_enterprise_account_groups_test.go +++ b/ibm/service/enterprise/data_source_ibm_enterprise_account_groups_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,10 +20,10 @@ func TestAccIbmAccountGroupsDataSourceBasic(t *testing.T) { //accountGroupPrimaryContactIamID := fmt.Sprintf("primary_contact_iam_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmAccountGroupsDataSourceConfigBasic(accountGroupName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_enterprise_account_groups.account_groups", "id"), diff --git a/ibm/data_source_ibm_enterprise_accounts.go b/ibm/service/enterprise/data_source_ibm_enterprise_accounts.go similarity index 88% rename from ibm/data_source_ibm_enterprise_accounts.go rename to ibm/service/enterprise/data_source_ibm_enterprise_accounts.go index c5bf482ef..76386ed8f 100644 --- a/ibm/data_source_ibm_enterprise_accounts.go +++ b/ibm/service/enterprise/data_source_ibm_enterprise_accounts.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" @@ -9,110 +9,112 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func dataSourceIbmEnterpriseAccounts() *schema.Resource { +func DataSourceIBMEnterpriseAccounts() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmEnterpriseAccountsRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The name of the account.", - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "accounts": &schema.Schema{ + "accounts": { Type: schema.TypeList, Computed: true, Description: "A list of accounts.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the account.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The account ID.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the account.", }, - "parent": &schema.Schema{ + "parent": { Type: schema.TypeString, Computed: true, Description: "The CRN of the parent of the account.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise account ID.", }, - "enterprise_id": &schema.Schema{ + "enterprise_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise ID that the account is a part of.", }, - "enterprise_path": &schema.Schema{ + "enterprise_path": { Type: schema.TypeString, Computed: true, Description: "The path from the enterprise to this particular account.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The name of the account.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the account.", }, - "owner_iam_id": &schema.Schema{ + "owner_iam_id": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the owner of the account.", }, - "paid": &schema.Schema{ + "paid": { Type: schema.TypeBool, Computed: true, Description: "The type of account - whether it is free or paid.", }, - "owner_email": &schema.Schema{ + "owner_email": { Type: schema.TypeString, Computed: true, Description: "The email address of the owner of the account.", }, - "is_enterprise_account": &schema.Schema{ + "is_enterprise_account": { Type: schema.TypeBool, Computed: true, Description: "The flag to indicate whether the account is an enterprise account or not.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the account.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the account.", @@ -125,7 +127,7 @@ func dataSourceIbmEnterpriseAccounts() *schema.Resource { } func dataSourceIbmEnterpriseAccountsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -183,7 +185,7 @@ func dataSourceIbmEnterpriseAccountsRead(context context.Context, d *schema.Reso if allRecs != nil { err = d.Set("accounts", dataSourceListEnterpriseAccountsResponseFlattenResources(allRecs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resources %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resources %s", err)) } } diff --git a/ibm/data_source_ibm_enterprise_accounts_test.go b/ibm/service/enterprise/data_source_ibm_enterprise_accounts_test.go similarity index 90% rename from ibm/data_source_ibm_enterprise_accounts_test.go rename to ibm/service/enterprise/data_source_ibm_enterprise_accounts_test.go index 009c23686..03029b3b2 100644 --- a/ibm/data_source_ibm_enterprise_accounts_test.go +++ b/ibm/service/enterprise/data_source_ibm_enterprise_accounts_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIbmAccountsDataSourceBasic(t *testing.T) { accountName := fmt.Sprintf("name_%d", acctest.RandIntRange(10, 100)) //accountOwnerIamID := fmt.Sprintf("owner_iam_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmAccountsDataSourceConfigBasic(accountName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_enterprise_accounts.accounts", "id"), diff --git a/ibm/data_source_ibm_enterprises.go b/ibm/service/enterprise/data_source_ibm_enterprises.go similarity index 88% rename from ibm/data_source_ibm_enterprises.go rename to ibm/service/enterprise/data_source_ibm_enterprises.go index 3a547c8a5..2e7466d9b 100644 --- a/ibm/data_source_ibm_enterprises.go +++ b/ibm/service/enterprise/data_source_ibm_enterprises.go @@ -1,6 +1,6 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" @@ -8,90 +8,92 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func dataSourceIbmEnterprises() *schema.Resource { +func DataSourceIBMEnterprises() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmEnterprisesRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The name of the enterprise.", - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "enterprises": &schema.Schema{ + "enterprises": { Type: schema.TypeList, Computed: true, Description: "A list of enterprise objects.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the enterprise.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The enterprise ID.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise account ID.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the enterprise.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The name of the enterprise.", }, - "domain": &schema.Schema{ + "domain": { Type: schema.TypeString, Computed: true, Description: "The domain of the enterprise.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the enterprise.", }, - "primary_contact_iam_id": &schema.Schema{ + "primary_contact_iam_id": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the primary contact of the enterprise, such as `IBMid-0123ABC`.", }, - "primary_contact_email": &schema.Schema{ + "primary_contact_email": { Type: schema.TypeString, Computed: true, Description: "The email of the primary contact of the enterprise.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the enterprise was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the enterprise.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the enterprise was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the enterprise.", @@ -104,7 +106,7 @@ func dataSourceIbmEnterprises() *schema.Resource { } func dataSourceIbmEnterprisesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -148,7 +150,7 @@ func dataSourceIbmEnterprisesRead(context context.Context, d *schema.ResourceDat if listEnterprisesResponse.Resources != nil { err = d.Set("enterprises", dataSourceListEnterprisesResponseFlattenResources(listEnterprisesResponse.Resources)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resources %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resources %s", err)) } } diff --git a/ibm/data_source_ibm_enterprises_test.go b/ibm/service/enterprise/data_source_ibm_enterprises_test.go similarity index 93% rename from ibm/data_source_ibm_enterprises_test.go rename to ibm/service/enterprise/data_source_ibm_enterprises_test.go index 9b20a68e0..d2e9dd0e3 100644 --- a/ibm/data_source_ibm_enterprises_test.go +++ b/ibm/service/enterprise/data_source_ibm_enterprises_test.go @@ -1,11 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIbmEnterprisesDataSourceBasic(t *testing.T) { //enterprisePrimaryContactIamID := fmt.Sprintf("primary_contact_iam_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterprisesDataSourceConfigBasic(enterpriseName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_enterprises.enterprises", "id"), @@ -39,10 +41,10 @@ func TestAccIbmEnterprisesDataSourceAllArgs(t *testing.T) { enterpriseDomain := fmt.Sprintf("enterprise_domain_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterprisesDataSourceConfig(enterpriseName, enterpriseDomain), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_enterprises.enterprises", "id"), diff --git a/ibm/resource_ibm_enterprise.go b/ibm/service/enterprise/resource_ibm_enterprise.go similarity index 78% rename from ibm/resource_ibm_enterprise.go rename to ibm/service/enterprise/resource_ibm_enterprise.go index 3135d23ea..25f90769f 100644 --- a/ibm/resource_ibm_enterprise.go +++ b/ibm/service/enterprise/resource_ibm_enterprise.go @@ -1,20 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func resourceIbmEnterprise() *schema.Resource { +func ResourceIBMEnterprise() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmEnterpriseCreate, ReadContext: resourceIbmEnterpriseRead, @@ -27,69 +30,69 @@ func resourceIbmEnterprise() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, Schema: map[string]*schema.Schema{ - "source_account_id": &schema.Schema{ + "source_account_id": { Type: schema.TypeString, Required: true, Description: "The ID of the account that is used to create the enterprise.", ForceNew: true, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "The name of the enterprise. This field must have 3 - 60 characters.", - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "primary_contact_iam_id": &schema.Schema{ + "primary_contact_iam_id": { Type: schema.TypeString, Required: true, Description: "The IAM ID of the enterprise primary contact, such as `IBMid-0123ABC`. The IAM ID must already exist.", }, - "domain": &schema.Schema{ + "domain": { Type: schema.TypeString, Optional: true, Description: "A domain or subdomain for the enterprise, such as `example.com` or `my.example.com`.", }, - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the enterprise.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise account ID.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the enterprise.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the enterprise.", }, - "primary_contact_email": &schema.Schema{ + "primary_contact_email": { Type: schema.TypeString, Computed: true, Description: "The email of the primary contact of the enterprise.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the enterprise was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the enterprise.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the enterprise was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the enterprise.", @@ -99,7 +102,7 @@ func resourceIbmEnterprise() *schema.Resource { } func resourceIbmEnterpriseCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -120,7 +123,7 @@ func resourceIbmEnterpriseCreate(context context.Context, d *schema.ResourceData } func resourceIbmEnterpriseRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -140,50 +143,50 @@ func resourceIbmEnterpriseRead(context context.Context, d *schema.ResourceData, } //if err = d.Set("source_account_id", enterprise.); err != nil { - // return diag.FromErr(fmt.Errorf("Error setting source_account_id: %s", err)) + // return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_account_id: %s", err)) //} if err = d.Set("name", enterprise.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("primary_contact_iam_id", enterprise.PrimaryContactIamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting primary_contact_iam_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_contact_iam_id: %s", err)) } if err = d.Set("domain", enterprise.Domain); err != nil { - return diag.FromErr(fmt.Errorf("Error setting domain: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting domain: %s", err)) } if err = d.Set("url", enterprise.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting url: %s", err)) } if err = d.Set("enterprise_account_id", enterprise.EnterpriseAccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_account_id: %s", err)) } if err = d.Set("crn", enterprise.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("state", enterprise.State); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) } if err = d.Set("primary_contact_email", enterprise.PrimaryContactEmail); err != nil { - return diag.FromErr(fmt.Errorf("Error setting primary_contact_email: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_contact_email: %s", err)) } if err = d.Set("created_at", enterprise.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", enterprise.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if err = d.Set("updated_at", enterprise.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } if err = d.Set("updated_by", enterprise.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) } return nil } func resourceIbmEnterpriseUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_enterprise_account.go b/ibm/service/enterprise/resource_ibm_enterprise_account.go similarity index 79% rename from ibm/resource_ibm_enterprise_account.go rename to ibm/service/enterprise/resource_ibm_enterprise_account.go index 14452969a..18da15444 100644 --- a/ibm/resource_ibm_enterprise_account.go +++ b/ibm/service/enterprise/resource_ibm_enterprise_account.go @@ -1,21 +1,24 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" "errors" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func resourceIbmEnterpriseAccount() *schema.Resource { +func ResourceIBMEnterpriseAccount() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmEnterpriseAccountCreate, ReadContext: resourceIbmEnterpriseAccountRead, @@ -28,93 +31,93 @@ func resourceIbmEnterpriseAccount() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, Schema: map[string]*schema.Schema{ - "parent": &schema.Schema{ + "parent": { Type: schema.TypeString, Required: true, Description: "The CRN of the parent under which the account will be created. The parent can be an existing account group or the enterprise itself.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The name of the account. This field must have 3 - 60 characters.", ForceNew: true, - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "owner_iam_id": &schema.Schema{ + "owner_iam_id": { Type: schema.TypeString, Optional: true, Description: "The IAM ID of the account owner, such as `IBMid-0123ABC`. The IAM ID must already exist.", ForceNew: true, }, - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the account.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the account.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Optional: true, Computed: true, Description: "The enterprise account ID.", }, - "enterprise_id": &schema.Schema{ + "enterprise_id": { Type: schema.TypeString, Optional: true, Computed: true, Description: "The enterprise ID that the account is a part of.", }, - "account_id": &schema.Schema{ + "account_id": { Type: schema.TypeString, Optional: true, Computed: true, Description: "The source account id of account to be imported", }, - "enterprise_path": &schema.Schema{ + "enterprise_path": { Type: schema.TypeString, Computed: true, Description: "The path from the enterprise to this particular account.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the account.", }, - "paid": &schema.Schema{ + "paid": { Type: schema.TypeBool, Computed: true, Description: "The type of account - whether it is free or paid.", }, - "owner_email": &schema.Schema{ + "owner_email": { Type: schema.TypeString, Computed: true, Description: "The email address of the owner of the account.", }, - "is_enterprise_account": &schema.Schema{ + "is_enterprise_account": { Type: schema.TypeBool, Computed: true, Description: "The flag to indicate whether the account is an enterprise account or not.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the account.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the account.", @@ -143,7 +146,7 @@ func checkCreateAccount(d *schema.ResourceData) bool { } func resourceIbmEnterpriseAccountCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -171,16 +174,16 @@ func resourceIbmEnterpriseAccountCreate(context context.Context, d *schema.Resou d.SetId(*createAccountResponse.AccountID) } else { - err := errors.New("Required Parameters are missing." + + err := errors.New("[ERROR] Required Parameters are missing." + "Please input parent,name,owner_iam_id for creating a new account in enterprise." + - "Input enterprise_id and enterprise_account_id for importing an existing account to enterprise.") + "Input enterprise_id and enterprise_account_id for importing an existing account to enterprise") return diag.FromErr(err) } return resourceIbmEnterpriseAccountRead(context, d, meta) } func resourceIbmEnterpriseAccountRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -200,66 +203,66 @@ func resourceIbmEnterpriseAccountRead(context context.Context, d *schema.Resourc } if err = d.Set("parent", account.Parent); err != nil { - return diag.FromErr(fmt.Errorf("Error setting parent: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting parent: %s", err)) } if err = d.Set("name", account.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("owner_iam_id", account.OwnerIamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting owner_iam_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting owner_iam_id: %s", err)) } if err = d.Set("account_id", account.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) } if err = d.Set("url", account.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting url: %s", err)) } if err = d.Set("crn", account.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("enterprise_account_id", account.EnterpriseAccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_account_id: %s", err)) } if err = d.Set("enterprise_id", account.EnterpriseID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_id: %s", err)) } if err = d.Set("enterprise_path", account.EnterprisePath); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_path: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_path: %s", err)) } if err = d.Set("state", account.State); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) } if err = d.Set("paid", account.Paid); err != nil { - return diag.FromErr(fmt.Errorf("Error setting paid: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting paid: %s", err)) } if err = d.Set("owner_email", account.OwnerEmail); err != nil { - return diag.FromErr(fmt.Errorf("Error setting owner_email: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting owner_email: %s", err)) } if err = d.Set("is_enterprise_account", account.IsEnterpriseAccount); err != nil { - return diag.FromErr(fmt.Errorf("Error setting is_enterprise_account: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting is_enterprise_account: %s", err)) } if err = d.Set("created_at", account.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", account.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if account.UpdatedAt != nil { if err = d.Set("updated_at", account.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } } if account.UpdatedBy != nil { if err = d.Set("updated_by", account.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) } } return nil } func resourceIbmEnterpriseAccountUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_enterprise_account_group.go b/ibm/service/enterprise/resource_ibm_enterprise_account_group.go similarity index 78% rename from ibm/resource_ibm_enterprise_account_group.go rename to ibm/service/enterprise/resource_ibm_enterprise_account_group.go index 09936dee9..cbec6c2f6 100644 --- a/ibm/resource_ibm_enterprise_account_group.go +++ b/ibm/service/enterprise/resource_ibm_enterprise_account_group.go @@ -1,6 +1,6 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise import ( "context" @@ -8,13 +8,15 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) -func resourceIbmEnterpriseAccountGroup() *schema.Resource { +func ResourceIBMEnterpriseAccountGroup() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmEnterpriseAccountGroupCreate, ReadContext: resourceIbmEnterpriseAccountGroupRead, @@ -27,74 +29,74 @@ func resourceIbmEnterpriseAccountGroup() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, Schema: map[string]*schema.Schema{ - "parent": &schema.Schema{ + "parent": { Type: schema.TypeString, Required: true, Description: "The CRN of the parent under which the account group will be created. The parent can be an existing account group or the enterprise itself.", ForceNew: true, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "The name of the account group. This field must have 3 - 60 characters.", - ValidateFunc: validateAllowedEnterpriseNameValue(), + ValidateFunc: validate.ValidateAllowedEnterpriseNameValue(), }, - "primary_contact_iam_id": &schema.Schema{ + "primary_contact_iam_id": { Type: schema.TypeString, Required: true, Description: "The IAM ID of the primary contact for this account group, such as `IBMid-0123ABC`. The IAM ID must already exist.", }, - "url": &schema.Schema{ + "url": { Type: schema.TypeString, Computed: true, Description: "The URL of the account group.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) of the account group.", }, - "enterprise_account_id": &schema.Schema{ + "enterprise_account_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise account ID.", }, - "enterprise_id": &schema.Schema{ + "enterprise_id": { Type: schema.TypeString, Computed: true, Description: "The enterprise ID that the account group is a part of.", }, - "enterprise_path": &schema.Schema{ + "enterprise_path": { Type: schema.TypeString, Computed: true, Description: "The path from the enterprise to this particular account group.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The state of the account group.", }, - "primary_contact_email": &schema.Schema{ + "primary_contact_email": { Type: schema.TypeString, Computed: true, Description: "The email address of the primary contact of the account group.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account group was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that created the account group.", }, - "updated_at": &schema.Schema{ + "updated_at": { Type: schema.TypeString, Computed: true, Description: "The time stamp at which the account group was last updated.", }, - "updated_by": &schema.Schema{ + "updated_by": { Type: schema.TypeString, Computed: true, Description: "The IAM ID of the user or service that updated the account group.", @@ -104,7 +106,7 @@ func resourceIbmEnterpriseAccountGroup() *schema.Resource { } func resourceIbmEnterpriseAccountGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -127,7 +129,7 @@ func resourceIbmEnterpriseAccountGroupCreate(context context.Context, d *schema. } func resourceIbmEnterpriseAccountGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } @@ -147,49 +149,49 @@ func resourceIbmEnterpriseAccountGroupRead(context context.Context, d *schema.Re } log.Printf("[DEBUG] GetAccountGroupWithContext testing %s", response) if err = d.Set("parent", accountGroup.Parent); err != nil { - return diag.FromErr(fmt.Errorf("Error setting parent: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting parent: %s", err)) } if err = d.Set("name", accountGroup.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("primary_contact_iam_id", accountGroup.PrimaryContactIamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting primary_contact_iam_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_contact_iam_id: %s", err)) } if err = d.Set("url", accountGroup.URL); err != nil { - return diag.FromErr(fmt.Errorf("Error setting url: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting url: %s", err)) } if err = d.Set("crn", accountGroup.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("enterprise_account_id", accountGroup.EnterpriseAccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_account_id: %s", err)) } if err = d.Set("enterprise_id", accountGroup.EnterpriseID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_id: %s", err)) } if err = d.Set("enterprise_path", accountGroup.EnterprisePath); err != nil { - return diag.FromErr(fmt.Errorf("Error setting enterprise_path: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enterprise_path: %s", err)) } if err = d.Set("state", accountGroup.State); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) } if err = d.Set("primary_contact_email", accountGroup.PrimaryContactEmail); err != nil { - return diag.FromErr(fmt.Errorf("Error setting primary_contact_email: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_contact_email: %s", err)) } if err = d.Set("created_at", accountGroup.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", accountGroup.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if accountGroup.UpdatedAt != nil { if err = d.Set("updated_at", accountGroup.UpdatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } } if accountGroup.UpdatedBy != nil { if err = d.Set("updated_by", accountGroup.UpdatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) } } @@ -197,7 +199,7 @@ func resourceIbmEnterpriseAccountGroupRead(context context.Context, d *schema.Re } func resourceIbmEnterpriseAccountGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enterpriseManagementClient, err := meta.(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := meta.(conns.ClientSession).EnterpriseManagementV1() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_enterprise_account_group_test.go b/ibm/service/enterprise/resource_ibm_enterprise_account_group_test.go similarity index 89% rename from ibm/resource_ibm_enterprise_account_group_test.go rename to ibm/service/enterprise/resource_ibm_enterprise_account_group_test.go index bdba436a3..427e68dd7 100644 --- a/ibm/resource_ibm_enterprise_account_group_test.go +++ b/ibm/service/enterprise/resource_ibm_enterprise_account_group_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,10 +26,10 @@ func TestAccIbmEnterpriseAccountGroupBasic(t *testing.T) { //primaryContactIamIDUpdate := fmt.Sprintf("primary_contact_iam_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseAccountGroupConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmEnterpriseAccountGroupExists("ibm_enterprise_account_group.enterprise_account_group", conf), @@ -35,7 +38,7 @@ func TestAccIbmEnterpriseAccountGroupBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_enterprise_account_group.enterprise_account_group", "primary_contact_iam_id"), ), }, - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseAccountGroupConfigBasic(nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_enterprise_account_group.enterprise_account_group", "parent"), @@ -43,7 +46,7 @@ func TestAccIbmEnterpriseAccountGroupBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_enterprise_account_group.enterprise_account_group", "primary_contact_iam_id"), ), }, - resource.TestStep{ + { ResourceName: "ibm_enterprise_account_group.enterprise_account_group", ImportState: true, ImportStateVerify: true, @@ -72,7 +75,7 @@ func testAccCheckIbmEnterpriseAccountGroupExists(n string, obj enterprisemanagem return fmt.Errorf("Not found: %s", n) } - enterpriseManagementClient, err := testAccProvider.Meta().(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EnterpriseManagementV1() if err != nil { return err } diff --git a/ibm/resource_ibm_enterprise_account_test.go b/ibm/service/enterprise/resource_ibm_enterprise_account_test.go similarity index 86% rename from ibm/resource_ibm_enterprise_account_test.go rename to ibm/service/enterprise/resource_ibm_enterprise_account_test.go index d5eac36f7..f7ec873bf 100644 --- a/ibm/resource_ibm_enterprise_account_test.go +++ b/ibm/service/enterprise/resource_ibm_enterprise_account_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" "github.com/IBM/platform-services-go-sdk/enterprisemanagementv1" ) @@ -21,10 +25,10 @@ func TestAccIbmEnterpriseAccountBasic(t *testing.T) { //parentUpdate := fmt.Sprintf("parent_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseAccountConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmEnterpriseAccountExists("ibm_enterprise_account.enterprise_account", conf), @@ -33,7 +37,7 @@ func TestAccIbmEnterpriseAccountBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_enterprise_account.enterprise_account", "owner_iam_id"), ), }, - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseAccountConfigUpdateBasic(name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_enterprise_account.enterprise_account", "parent"), @@ -41,7 +45,7 @@ func TestAccIbmEnterpriseAccountBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_enterprise_account.enterprise_account", "owner_iam_id"), ), }, - resource.TestStep{ + { ResourceName: "ibm_enterprise_account.enterprise_account", ImportState: true, ImportStateVerify: true, @@ -50,20 +54,23 @@ func TestAccIbmEnterpriseAccountBasic(t *testing.T) { }) } -/* To run this test case ensure the IC_API_KEY belongs to an enterprise. -ACCOUNT_TO_BE_IMPORTED should invite enterprise and grant relevant iam policies before running this test case" */ +/* + To run this test case ensure the IC_API_KEY belongs to an enterprise. + +ACCOUNT_TO_BE_IMPORTED should invite enterprise and grant relevant iam policies before running this test case" +*/ func TestAccIbmEnterpriseImportAccountBasic(t *testing.T) { var conf enterprisemanagementv1.Account resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterpriseAccountImport(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterpriseAccountImport(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmAccountsDataSourceConfigImportBasic(account_to_be_imported), + { + Config: testAccCheckIbmAccountsDataSourceConfigImportBasic(acc.Account_to_be_imported), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmEnterpriseAccountExists("ibm_enterprise_account.enterprise_account_import", conf), resource.TestCheckResourceAttrSet("ibm_enterprise_account.enterprise_account_import", "parent"), - resource.TestCheckResourceAttr("ibm_enterprise_account.enterprise_account_import", "account_id", account_to_be_imported), + resource.TestCheckResourceAttr("ibm_enterprise_account.enterprise_account_import", "account_id", acc.Account_to_be_imported), resource.TestCheckResourceAttrSet("ibm_enterprise_account.enterprise_account_import", "owner_iam_id"), ), }, @@ -116,7 +123,7 @@ func testAccCheckIbmEnterpriseAccountExists(n string, obj enterprisemanagementv1 return fmt.Errorf("Not found: %s", n) } - enterpriseManagementClient, err := testAccProvider.Meta().(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EnterpriseManagementV1() if err != nil { return err } diff --git a/ibm/resource_ibm_enterprise_test.go b/ibm/service/enterprise/resource_ibm_enterprise_test.go similarity index 91% rename from ibm/resource_ibm_enterprise_test.go rename to ibm/service/enterprise/resource_ibm_enterprise_test.go index b8e19e508..7487b1cb9 100644 --- a/ibm/resource_ibm_enterprise_test.go +++ b/ibm/service/enterprise/resource_ibm_enterprise_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package enterprise_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -24,10 +27,10 @@ func TestAccIbmEnterpriseBasic(t *testing.T) { //primaryContactIamIDUpdate := fmt.Sprintf("primary_contact_iam_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmEnterpriseExists("ibm_enterprise.enterprise", conf), @@ -36,7 +39,7 @@ func TestAccIbmEnterpriseBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_enterprise.enterprise", "primary_contact_iam_id"), ), }, - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseConfigBasic(nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_enterprise.enterprise", "source_account_id"), @@ -59,10 +62,10 @@ func TestAccIbmEnterpriseAllArgs(t *testing.T) { domainUpdate := fmt.Sprintf("tf_updated_test_domain_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEnterprise(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEnterprise(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseConfig(name, domain), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmEnterpriseExists("ibm_enterprise.enterprise", conf), @@ -72,7 +75,7 @@ func TestAccIbmEnterpriseAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_enterprise.enterprise", "domain", domain), ), }, - resource.TestStep{ + { Config: testAccCheckIbmEnterpriseConfig(nameUpdate, domainUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet("ibm_enterprise.enterprise", "source_account_id"), @@ -81,7 +84,7 @@ func TestAccIbmEnterpriseAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_enterprise.enterprise", "domain", domainUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_enterprise.enterprise", ImportState: true, ImportStateVerify: true, @@ -124,7 +127,7 @@ func testAccCheckIbmEnterpriseExists(n string, obj enterprisemanagementv1.Enterp return fmt.Errorf("Not found: %s", n) } - enterpriseManagementClient, err := testAccProvider.Meta().(ClientSession).EnterpriseManagementV1() + enterpriseManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EnterpriseManagementV1() if err != nil { return err } diff --git a/ibm/service/eventnotification/README.md b/ibm/service/eventnotification/README.md new file mode 100644 index 000000000..2a42d3119 --- /dev/null +++ b/ibm/service/eventnotification/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Event Notifications + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Event Notification resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_destination) +* IBM API Docs: [IBM API Docs for Event Notification](https://cloud.ibm.com/apidocs/event-notifications/event-notifications) +* IBM Event Notification SDK: [IBM SDK for Event Notification](https://github.com/IBM/event-notifications-go-admin-sdk/tree/main/eventnotificationsv1) diff --git a/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription.go b/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription.go new file mode 100644 index 000000000..f83275452 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription.go @@ -0,0 +1,107 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnFCMSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnFCMSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnFCMSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from %s", err)) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription_test.go b/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription_test.go new file mode 100644 index 000000000..b2da85917 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_FCM_subscription_test.go @@ -0,0 +1,87 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnFCMSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFCMSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_androidn.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_android.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnFCMSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + resource "ibm_en_destination_android" "en_destination_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_destination_name_02944" + type = "push_android" + description = "tf_destinatios_description_0364" + config { + params { + sender_id = "sender id value" + server_key = "server key value" + } + } + } + + resource "ibm_en_subscription_android" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = ibm_en_fcm_destination.en_destination_resource_4.destination_id + } + + data "ibm_en_subscription_android" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_android.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription.go b/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription.go new file mode 100644 index 000000000..f74693fdc --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription.go @@ -0,0 +1,151 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnWebhookSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnWebhookSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "signing_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Signing webhook attributes.", + }, + "additional_properties": { + Type: schema.TypeMap, + Computed: true, + Description: "Additional attributes.", + Elem: &schema.Schema{ + Type: schema.TypeList, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnWebhookSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enWebhookSubscriptionFlattenAttributes(result.Attributes)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + return nil +} + +func enWebhookSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + finalMap := enWebhookSubscriptionToMap(attributes) + finalList = append(finalList, finalMap) + + return finalList +} + +func enWebhookSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + if attributeItem.SigningEnabled != nil { + attributeMap["signing_enabled"] = attributeItem.SigningEnabled + } + + attributeMap["additional_properties"] = attributeItem.GetProperties() + + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription_test.go b/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription_test.go new file mode 100644 index 000000000..0f3a3bb5d --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_Webhook_subscription_test.go @@ -0,0 +1,90 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnWebhookSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnWebhookSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_webhook.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnWebhookSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + resource "ibm_en_destination_webhook" "en_destination_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_destination_name_02944" + type = "webhook" + description = "tf_destinatios_description_0364" + config { + params { + verb = "POST" + url = "https://demo.webhook.com" + } + } + } + + resource "ibm_en_subscription_webhook" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = ibm_en_webhook_destination.en_destination_resource_4.destination_id + attributes { + signing_enabled = true + } + } + + data "ibm_en_subscription_webhook" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_webhook.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/data_source_ibm_en_destination.go b/ibm/service/eventnotification/data_source_ibm_en_destination.go similarity index 81% rename from ibm/data_source_ibm_en_destination.go rename to ibm/service/eventnotification/data_source_ibm_en_destination.go index a93624a53..5a37fb8b6 100644 --- a/ibm/data_source_ibm_en_destination.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func dataSourceIBMEnDestination() *schema.Resource { +func DataSourceIBMEnDestination() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMEnDestinationRead, @@ -105,11 +107,12 @@ func dataSourceIBMEnDestination() *schema.Resource { }, }, }, + DeprecationMessage: "This data source will be deprecated. A new data source ibm_en_destination_webhook will replace the existing ibm_en_destination data source", } } func dataSourceIBMEnDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -127,39 +130,39 @@ func dataSourceIBMEnDestinationRead(context context.Context, d *schema.ResourceD d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if result.Description != nil { if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } } if err = d.Set("type", result.Type); err != nil { - return diag.FromErr(fmt.Errorf("error setting type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } if result.Config != nil { err = d.Set("config", enDestinationFlattenConfig(*result.Config)) if err != nil { - return diag.FromErr(fmt.Errorf("error setting config %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) } } if result.SubscriptionNames != nil { err = d.Set("subscription_names", result.SubscriptionNames) if err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_names %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) } } - if err = d.Set("updated_at", dateTimeToString(result.UpdatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } - if err = d.Set("subscription_count", intValue(result.SubscriptionCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_count: %s", err)) + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) } return nil diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go b/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go new file mode 100644 index 000000000..46bfd877f --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go @@ -0,0 +1,238 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnAPNSDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnAPNSDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type push_ios.", + }, + "certificate_content_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Certificate Content Type to be set p8/p12.", + }, + "certificate": { + Type: schema.TypeString, + Computed: true, + Description: "The Certificate File.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Certificate Type for IOS, the values are p8/p12.", + }, + "is_sandbox": { + Type: schema.TypeBool, + Computed: true, + Description: "The flag to determine sandbox or production environment.", + }, + "password": { + Type: schema.TypeString, + Computed: true, + Description: "The Password for APNS Certificate in case of P12 certificate", + }, + "key_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Key ID In case of P8 Certificate", + }, + "team_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Team ID In case of P8 Certificate", + }, + "bundle_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnAPNSDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("certificate_content_type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting certificate content type: %s", err)) + } + + if err = d.Set("certificate", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting certifiacte: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enAPNSDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enAPNSDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enAPNSDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enAPNSDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enAPNSDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enAPNSDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.CertType != nil { + paramsMap["cert_type"] = params.CertType + } + if params.IsSandbox != nil { + paramsMap["is_sandbox"] = params.IsSandbox + } + if params.Password != nil { + paramsMap["password"] = params.Password + } + if params.KeyID != nil { + paramsMap["key_id"] = params.KeyID + } + if params.TeamID != nil { + paramsMap["team_id"] = params.TeamID + } + if params.BundleID != nil { + paramsMap["bundle_id"] = params.BundleID + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_apns_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_apns_test.go new file mode 100644 index 000000000..4036b2ccb --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_apns_test.go @@ -0,0 +1,71 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnAPNSDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnAPNSDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_ios.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnAPNSDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_ios" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + name = "%s" + type = "push_ios" + certificate_content_type = "p12" + certificate = "${path.module}/cert.p12" + description = "%s" + config { + params { + cert_type = "p12" + is_sandbox = true + password = "certpassword" + } + } + } + + data "ibm_en_destination_ios" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_ios.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go new file mode 100644 index 000000000..cc07afa48 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go @@ -0,0 +1,189 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnChromeDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnChromeDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type push_chrome.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + Description: "The api key for chrome app authorization", + }, + "website_url": { + Type: schema.TypeString, + Optional: true, + Description: "The website url", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnChromeDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enChromeDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enChromeDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enChromeDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enChromeDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enChromeDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enChromeDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.APIKey != nil { + paramsMap["api_key"] = params.APIKey + } + if params.WebsiteURL != nil { + paramsMap["website_url"] = params.WebsiteURL + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_chrome_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome_test.go new file mode 100644 index 000000000..f9795705f --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome_test.go @@ -0,0 +1,69 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnChromeDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnChromeDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_chrome.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnChromeDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_chrome" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + name = "%s" + type = "push_chrome" + description = "%s" + config { + params { + api_key = "vvshlgwwfvjj" + website_url = "https://testweb.com" + + } + } + } + + data "ibm_en_destination_chrome" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_chrome.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go new file mode 100644 index 000000000..ee0cccb06 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go @@ -0,0 +1,188 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnFCMDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnFCMDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type push_android.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sender_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Sender_id value for FCM project.", + }, + "server_key": { + Type: schema.TypeString, + Computed: true, + Description: "The Server_key value for FCM project.", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnFCMDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enFCMDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enFCMDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enFCMDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enFCMDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enFCMDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enFCMDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.SenderID != nil { + paramsMap["sender_id"] = params.SenderID + } + if params.ServerKey != nil { + paramsMap["server_key"] = params.ServerKey + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_fcm_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm_test.go new file mode 100644 index 000000000..d62008943 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm_test.go @@ -0,0 +1,68 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnFCMDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFCMDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_android.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnFCMDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_android" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + name = "%s" + type = "push_android" + description = "%s" + config { + params { + sender_id = "fcm sender id" + server_key = "fcm server key" + } + } + } + + data "ibm_en_destination_android" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_android.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go new file mode 100644 index 000000000..799ba729a --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go @@ -0,0 +1,180 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnFirefoxDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnFirefoxDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type push_firefox.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "website_url": { + Type: schema.TypeString, + Optional: true, + Description: "The website url", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnFirefoxDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enFirefoxDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enFirefoxDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enFirefoxDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enFirefoxDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enFirefoxDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enFirefoxDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.WebsiteURL != nil { + paramsMap["website_url"] = params.WebsiteURL + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_firefox_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox_test.go new file mode 100644 index 000000000..dae3f6807 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox_test.go @@ -0,0 +1,66 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnFirefoxDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFirefoxDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_firefox.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnFirefoxDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_firefox" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + name = "%s" + description = "%s" + config { + params { + website_url = "https://testweb.com" + } + } + } + + data "ibm_en_destination_firefox" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_firefox.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go b/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go new file mode 100644 index 000000000..d81fd9304 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go @@ -0,0 +1,220 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSafariDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSafariDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type push_ios.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Certificate Type for IOS, the values are p8/p12.", + }, + "password": { + Type: schema.TypeString, + Computed: true, + Description: "The Password for APNS Certificate in case of P12 certificate", + }, + "url_format_string": { + Type: schema.TypeString, + Computed: true, + Description: "The Key ID In case of P8 Certificate", + }, + "website_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Team ID In case of P8 Certificate", + }, + "website_push_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + "website_url": { + Type: schema.TypeString, + Computed: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnSafariDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enSafariDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enSafariDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enSafariDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enSafariDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enSafariDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enSafariDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.CertType != nil { + paramsMap["cert_type"] = params.CertType + } + if params.Password != nil { + paramsMap["password"] = params.Password + } + if params.URLFormatString != nil { + paramsMap["url_format_string"] = params.URLFormatString + } + if params.WebsiteName != nil { + paramsMap["website_name"] = params.WebsiteName + } + if params.WebsitePushID != nil { + paramsMap["website_push_id"] = params.WebsitePushID + } + if params.WebsiteURL != nil { + paramsMap["website_url"] = params.WebsiteURL + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_safari_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_safari_test.go new file mode 100644 index 000000000..afb30c5bb --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_safari_test.go @@ -0,0 +1,85 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnSafariDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSafariDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_safari.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnSafariDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_safari" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_safari" + certificate = "${path.module}/cert.p12" + icon_16x16 = "${path.module}/safariicon.png" + icon_16x16_2x = "${path.module}/safariicon.png" + icon_32x32 = "${path.module}/safariicon.png" + icon_32x32_2x = "${path.module}/safariicon.png" + icon_128x128 = "${path.module}/safariicon.png" + icon_128x128_2x = "${path.module}/safariicon.png" + icon_16x16_content_type = "png" + icon_16x16_2x_content_type = "png" + icon_32x32_content_type = "png" + icon_32x32_2x_content_type = "png" + icon_128x128_content_type = "png" + icon_128x128_2x_content_type = "png" + description = "%s" + config { + params { + cert_type = "p12" + password = "certpassword" + website_name = "NodeJS Starter Application" + url_format_string = "https://ensafaripush.mybluemix.net" + website_push_id = "web.net.mybluemix.ensafaripush" + website_url = "https://ensafaripush.mybluemix.net" + } + } + } + + data "ibm_en_destination_safari" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_safari.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go b/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go new file mode 100644 index 000000000..2c0d8ba67 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go @@ -0,0 +1,179 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSlackDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSlackDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type slack.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: "Slack webhook url", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnSlackDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enSlackDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enSlackDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enSlackDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enSlackDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enSlackDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enSlackDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.URL != nil { + paramsMap["url"] = params.URL + } + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_slack_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_slack_test.go new file mode 100644 index 000000000..c759511bd --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_slack_test.go @@ -0,0 +1,67 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnSlackDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSlackDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_slack.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnSlackDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_slack" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "slack" + description = "%s" + config { + params { + url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk" + } + } + } + + data "ibm_en_destination_slack" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_slack.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/data_source_ibm_en_destination_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_test.go similarity index 93% rename from ibm/data_source_ibm_en_destination_test.go rename to ibm/service/eventnotification/data_source_ibm_en_destination_test.go index 574226de0..41cb5d782 100644 --- a/ibm/data_source_ibm_en_destination_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMEnDestinationDataSourceBasic(t *testing.T) { instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnDestinationDataSourceConfigBasic(instanceName, name, description), diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go new file mode 100644 index 000000000..4be249ff8 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go @@ -0,0 +1,210 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnWebhookDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnWebhookDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type Webhook.", + }, + "config": { + Type: schema.TypeList, + Computed: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: "URL of webhook.", + }, + "verb": { + Type: schema.TypeString, + Computed: true, + Description: "HTTP method of webhook.", + }, + "custom_headers": { + Type: schema.TypeMap, + Computed: true, + Description: "Custom headers (Key-Value pair) for webhook call.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "sensitive_headers": { + Type: schema.TypeList, + Computed: true, + Description: "List of sensitive headers from custom headers.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnWebhookDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enWebhookDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enWebhookDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enWebhookDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enWebhookDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enWebhookDestinationConfigParamsToMap(paramsItem en.DestinationConfigParamsIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigParams) + + if params.URL != nil { + paramsMap["url"] = params.URL + } + if params.Verb != nil { + paramsMap["verb"] = params.Verb + } + if params.CustomHeaders != nil { + paramsMap["custom_headers"] = params.CustomHeaders + } + if params.SensitiveHeaders != nil { + paramsMap["sensitive_headers"] = params.SensitiveHeaders + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_webhook_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook_test.go new file mode 100644 index 000000000..a137c21f2 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook_test.go @@ -0,0 +1,68 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnWebhookDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnWebhookDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.iibm_en_destination_webhook.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_webhook.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnWebhookDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_webhook" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + name = "%s" + type = "webhook" + description = "%s" + config { + params { + verb = "POST" + url = "https://demo.webhook.com" + } + } + } + + data "ibm_en_destination_webhook" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_webhook.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/data_source_ibm_en_destinations.go b/ibm/service/eventnotification/data_source_ibm_en_destinations.go similarity index 83% rename from ibm/data_source_ibm_en_destinations.go rename to ibm/service/eventnotification/data_source_ibm_en_destinations.go index e71e9851b..b8f417317 100644 --- a/ibm/data_source_ibm_en_destinations.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destinations.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func dataSourceIBMEnDestinations() *schema.Resource { +func DataSourceIBMEnDestinations() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMEnDestinationsRead, @@ -85,7 +87,7 @@ func dataSourceIBMEnDestinations() *schema.Resource { } func dataSourceIBMEnDestinationsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -99,7 +101,7 @@ func dataSourceIBMEnDestinationsRead(context context.Context, d *schema.Resource } var destinationList *en.DestinationList - finalList := []en.DestinationLisItem{} + finalList := []en.DestinationListItem{} var offset int64 = 0 var limit int64 = 100 @@ -130,20 +132,20 @@ func dataSourceIBMEnDestinationsRead(context context.Context, d *schema.Resource d.SetId(fmt.Sprintf("destinations/%s", *options.InstanceID)) - if err = d.Set("total_count", intValue(destinationList.TotalCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting total_count: %s", err)) + if err = d.Set("total_count", flex.IntValue(destinationList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } if destinationList.Destinations != nil { if err = d.Set("destinations", enFlattenDestinationsList(destinationList.Destinations)); err != nil { - return diag.FromErr(fmt.Errorf("error setting destinations %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destinations %s", err)) } } return nil } -func enFlattenDestinationsList(result []en.DestinationLisItem) (destinations []map[string]interface{}) { +func enFlattenDestinationsList(result []en.DestinationListItem) (destinations []map[string]interface{}) { for _, destinationsItem := range result { destinations = append(destinations, enDestinationListToMap(destinationsItem)) } @@ -151,7 +153,7 @@ func enFlattenDestinationsList(result []en.DestinationLisItem) (destinations []m return destinations } -func enDestinationListToMap(destinationItem en.DestinationLisItem) (destination map[string]interface{}) { +func enDestinationListToMap(destinationItem en.DestinationListItem) (destination map[string]interface{}) { destination = map[string]interface{}{} if destinationItem.ID != nil { @@ -173,7 +175,7 @@ func enDestinationListToMap(destinationItem en.DestinationLisItem) (destination destination["subscription_names"] = destinationItem.SubscriptionNames } if destinationItem.UpdatedAt != nil { - destination["updated_at"] = dateTimeToString(destinationItem.UpdatedAt) + destination["updated_at"] = flex.DateTimeToString(destinationItem.UpdatedAt) } return destination diff --git a/ibm/data_source_ibm_en_destinations_test.go b/ibm/service/eventnotification/data_source_ibm_en_destinations_test.go similarity index 93% rename from ibm/data_source_ibm_en_destinations_test.go rename to ibm/service/eventnotification/data_source_ibm_en_destinations_test.go index 21ed8db62..3aa41370a 100644 --- a/ibm/data_source_ibm_en_destinations_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destinations_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMEnDestinationsDataSourceBasic(t *testing.T) { instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnDestinationDatasourceConfig(instanceName, name, description), diff --git a/ibm/service/eventnotification/data_source_ibm_en_slack_subscription.go b/ibm/service/eventnotification/data_source_ibm_en_slack_subscription.go new file mode 100644 index 000000000..33ca714ac --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_slack_subscription.go @@ -0,0 +1,141 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSlackSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSlackSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attachment_color": { + Type: schema.TypeString, + Optional: true, + Description: "attachment color code", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnSlackSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enSlackSubscriptionFlattenAttributes(result.Attributes)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + return nil +} + +func enSlackSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + finalMap := enSlackSubscriptionToMap(attributes) + finalList = append(finalList, finalMap) + + return finalList +} + +func enSlackSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + if attributeItem.AttachmentColor != nil { + attributeMap["attachment_color"] = attributeItem.AttachmentColor + } + + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_slack_subscription_test.go b/ibm/service/eventnotification/data_source_ibm_en_slack_subscription_test.go new file mode 100644 index 000000000..391665174 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_slack_subscription_test.go @@ -0,0 +1,89 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnSlackSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSlackSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_slack.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnSlackSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + resource "ibm_en_destination_slack" "en_destination_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_destination_name_02944" + type = "slack" + description = "tf_destinatios_description_0364" + config { + params { + url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk" + } + } + } + + resource "ibm_en_subscription_slack" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = ibm_en_destination_slack.en_destination_resource_4.destination_id + attributes { + attachment_color = "#0000FF" + } + } + + data "ibm_en_subscription_slack" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_slack.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_source.go b/ibm/service/eventnotification/data_source_ibm_en_source.go new file mode 100644 index 000000000..70d5f8956 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_source.go @@ -0,0 +1,94 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSource() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSourceRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "source_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Source.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Source name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Source description.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "The Source enable flag.", + }, + }, + } +} + +func dataSourceIBMEnSourceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSourceOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("source_id").(string)) + + result, response, err := enClient.GetSourceWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSource failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("enabled", result.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enabled flag: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription.go b/ibm/service/eventnotification/data_source_ibm_en_subscription.go new file mode 100644 index 000000000..b4cfde2b0 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription.go @@ -0,0 +1,284 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of destination.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The destination name.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Topic name.", + }, + "from": { + Type: schema.TypeString, + Computed: true, + Description: "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "add_notification_payload": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to add the notification payload to the email.", + }, + "signing_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Signing webhook attributes.", + }, + "additionalproperties": { + Type: schema.TypeList, + Computed: true, + Description: "Additional attributes for sms and webhook subscription.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "to": { + Type: schema.TypeList, + Computed: true, + Description: "The phone number to send the SMS to.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "additional_properties": { + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "Additional attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reply_to_mail": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "reply_to_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "from_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + "to": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "invited": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "unsubscribed": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address which should be unsubscribed from smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + DeprecationMessage: "This data source would be deprecated. For subscription data sources for email, sms, webhook destination kindly use ibm_en_subscription_email, ibm_en_subscription_sms, ibm_en_subscription_webhook subscription data sources", + } +} + +func dataSourceIBMEnSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if result.DestinationType != nil { + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + } + destinationtype := d.Get("destination_type").(string) + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enSubscriptionFlattenAttributes(result.Attributes, destinationtype)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from %s", err)) + } + } + + return nil +} + +func enSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf, destinationtype string) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + destination_type := destinationtype + + finalMap := enSubscriptionToMap(attributes, destination_type) + finalList = append(finalList, finalMap) + + return finalList +} + +func enSubscriptionToMap(attributeItem *en.SubscriptionAttributes, destinationtype string) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + if attributeItem.AddNotificationPayload != nil { + attributeMap["add_notification_payload"] = attributeItem.AddNotificationPayload + } + + if attributeItem.SigningEnabled != nil { + attributeMap["signing_enabled"] = attributeItem.SigningEnabled + } + + if destinationtype == "smtp_ibm" { + + prop := []map[string]interface{}{} + + b := attributeItem.GetProperties() + m := make(map[string]interface{}) + if len(b) > 0 { + for k, v := range b { + m[k] = v + } + } + prop = append(prop, m) + attributeMap["additional_properties"] = prop + } else if destinationtype == "sms_ibm" { + prop := []map[string]interface{}{} + + b := attributeItem.GetProperties() + m := make(map[string]interface{}) + if len(b) > 0 { + for k, v := range b { + m[k] = v + } + } + prop = append(prop, m) + attributeMap["additionalproperties"] = prop + } + + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_email.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_email.go new file mode 100644 index 000000000..86c524d98 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_email.go @@ -0,0 +1,196 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnEmailSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnEmailSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "add_notification_payload": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to add the notification payload to the email.", + }, + "additional_properties": { + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "Additional attributes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reply_to_mail": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "reply_to_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + "from_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address username of source email address.", + }, + "to": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The email id list to whom send the mail.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "invited": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The email id to be invited", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "unsubscribed": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address which should be unsubscribed from smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnEmailSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enEmailSubscriptionFlattenAttributes(result.Attributes)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + return nil +} + +func enEmailSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + finalMap := enEmailSubscriptionToMap(attributes) + finalList = append(finalList, finalMap) + + return finalList +} + +func enEmailSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + prop := []map[string]interface{}{} + + b := attributeItem.GetProperties() + m := make(map[string]interface{}) + if len(b) > 0 { + for k, v := range b { + m[k] = v + } + } + prop = append(prop, m) + attributeMap["additional_properties"] = prop + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_email_test.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_email_test.go new file mode 100644 index 000000000..ab8f5dd7d --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_email_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnEmailSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnEmailSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_email.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnEmailSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + + resource "ibm_en_subscription_email" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = "Set Email Destination ID" + attributes { + add_notification_payload = true + reply_to_mail = "en@ibm.com" + reply_to_name = "EYS ORG" + from_name="ABC ORG" + to = ["testmail@gmail.com"] + + } + } + + data "ibm_en_subscription_email" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_email.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_sms.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_sms.go new file mode 100644 index 000000000..d948c1235 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_sms.go @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnSMSSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnSMSSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Description: "The additional attributes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "additional_properties": { + Type: schema.TypeList, + Computed: true, + Description: "Additional attributes for sms and webhook subscription.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "to": { + Type: schema.TypeList, + Computed: true, + Description: "The phone number to send the SMS to.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnSMSSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enSMSSubscriptionFlattenAttributes(result.Attributes)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + return nil +} + +func enSMSSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + finalMap := enSMSSubscriptionToMap(attributes) + finalList = append(finalList, finalMap) + + return finalList +} + +func enSMSSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + prop := []map[string]interface{}{} + + b := attributeItem.GetProperties() + m := make(map[string]interface{}) + if len(b) > 0 { + for k, v := range b { + m[k] = v + } + } + prop = append(prop, m) + attributeMap["additional_properties"] = prop + + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_sms_test.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_sms_test.go new file mode 100644 index 000000000..55c89e543 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_sms_test.go @@ -0,0 +1,78 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnSMSSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSMSSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_sms.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnSMSSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + + resource "ibm_en_subscription_sms" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = "Set SMS Destination ID" + attributes { + to = ["+16382922821", "+18976569023"] + } + } + + data "ibm_en_subscription_sms" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_sms.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/data_source_ibm_en_subscription_test.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_test.go similarity index 95% rename from ibm/data_source_ibm_en_subscription_test.go rename to ibm/service/eventnotification/data_source_ibm_en_subscription_test.go index 74b57c0e5..97e0a3dda 100644 --- a/ibm/data_source_ibm_en_subscription_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMEnSubscriptionDataSourceAllArgs(t *testing.T) { description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnSubscriptionDataSourceConfig(instanceName, name, description), @@ -75,7 +77,6 @@ func testAccCheckIBMEnSubscriptionDataSourceConfig(instanceName, name, descripti topic_id = ibm_en_topic.en_topic_resource_4.topic_id destination_id = ibm_en_destination.en_destination_resource_4.destination_id attributes { - add_notification_payload = true signing_enabled = true } } diff --git a/ibm/data_source_ibm_en_subscriptions.go b/ibm/service/eventnotification/data_source_ibm_en_subscriptions.go similarity index 90% rename from ibm/data_source_ibm_en_subscriptions.go rename to ibm/service/eventnotification/data_source_ibm_en_subscriptions.go index c567b05e9..a43bdf5b3 100644 --- a/ibm/data_source_ibm_en_subscriptions.go +++ b/ibm/service/eventnotification/data_source_ibm_en_subscriptions.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func dataSourceIBMEnSubscriptions() *schema.Resource { +func DataSourceIBMEnSubscriptions() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMEnSubscriptionsRead, @@ -92,7 +94,7 @@ func dataSourceIBMEnSubscriptions() *schema.Resource { } func dataSourceIBMEnSubscriptionsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -137,14 +139,14 @@ func dataSourceIBMEnSubscriptionsRead(context context.Context, d *schema.Resourc d.SetId(fmt.Sprintf("subscriptions_%s", d.Get("instance_guid").(string))) - if err = d.Set("total_count", intValue(subscriptionList.TotalCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting total_count: %s", err)) + if err = d.Set("total_count", flex.IntValue(subscriptionList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } if subscriptionList.Subscriptions != nil { err = d.Set("subscriptions", enFlattenSubscriptionList(subscriptionList.Subscriptions)) if err != nil { - return diag.FromErr(fmt.Errorf("error setting subscriptions %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscriptions %s", err)) } } diff --git a/ibm/data_source_ibm_en_subscriptions_test.go b/ibm/service/eventnotification/data_source_ibm_en_subscriptions_test.go similarity index 95% rename from ibm/data_source_ibm_en_subscriptions_test.go rename to ibm/service/eventnotification/data_source_ibm_en_subscriptions_test.go index 035833a13..98ce7e93a 100644 --- a/ibm/data_source_ibm_en_subscriptions_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_subscriptions_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMEnSubscriptionsDataSourceBasic(t *testing.T) { description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnSubscriptionsDataSourceConfigBasic(instanceName, name, description), diff --git a/ibm/service/eventnotification/data_source_ibm_en_topic.go b/ibm/service/eventnotification/data_source_ibm_en_topic.go new file mode 100644 index 000000000..f7baa9826 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_topic.go @@ -0,0 +1,318 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnTopic() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnTopicRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Topic.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the topic.", + }, + "source_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of sources.", + }, + "sources": { + Type: schema.TypeList, + Computed: true, + Description: "List of sources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the source.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the source.", + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "List of rules.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the rule is enabled or not.", + }, + "event_type_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Event type filter.", + }, + "notification_filter": { + Type: schema.TypeString, + Computed: true, + Description: "Notification filter.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last time the topic was updated.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Autogenerated rule ID.", + }, + }, + }, + }, + }, + }, + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscriptions": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of destination.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last time the topic was updated.", + }, + }, + } +} + +func dataSourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetTopicOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("topic_id").(string)) + + result, response, err := enClient.GetTopicWithContext(context, options) + + if err != nil { + return diag.FromErr(fmt.Errorf("GetTopicWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + d.Set("topic_id", options.ID) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("source_count", flex.IntValue(result.SourceCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_count: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + // if result.Sources != nil { + // err = d.Set("sources", dataSourceTopicFlattenSources(result.Sources)) + // if err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error setting sources %s", err)) + // } + // } + + if result.Subscriptions != nil { + err = d.Set("subscriptions", enFlattenSubscriptions(result.Subscriptions)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscriptions %s", err)) + } + } + + return nil +} + +// func dataSourceTopicFlattenSources(result []en.TopicSourcesItem) (sources []map[string]interface{}) { +// sources = []map[string]interface{}{} + +// for _, sourcesItem := range result { +// sources = append(sources, dataSourceTopicSourcesToMap(sourcesItem)) +// } + +// return sources +// } + +// func dataSourceTopicSourcesToMap(sourcesItem en.TopicSourcesItem) (sourcesMap map[string]interface{}) { +// sourcesMap = map[string]interface{}{} + +// if sourcesItem.ID != nil { +// sourcesMap["id"] = sourcesItem.ID +// } +// if sourcesItem.Name != nil { +// sourcesMap["name"] = sourcesItem.Name +// } + +// if sourcesItem.Rules != nil { +// rulesList := []map[string]interface{}{} +// for _, rulesItem := range sourcesItem.Rules { +// rulesList = append(rulesList, enRulesToMap(rulesItem)) +// } +// sourcesMap["rules"] = rulesList +// } + +// return sourcesMap +// } + +// func enRulesToMap(rulesItem en.RulesGet) (rulesMap map[string]interface{}) { +// rulesMap = map[string]interface{}{} + +// if rulesItem.ID != nil { +// rulesMap["id"] = rulesItem.ID +// } + +// if rulesItem.Enabled != nil { +// rulesMap["enabled"] = rulesItem.Enabled +// } + +// if rulesItem.EventTypeFilter != nil { +// rulesMap["event_type_filter"] = rulesItem.EventTypeFilter +// } + +// if rulesItem.NotificationFilter != nil { +// rulesMap["notification_filter"] = rulesItem.NotificationFilter +// } + +// if rulesItem.UpdatedAt != nil { +// rulesMap["updated_at"] = rulesItem.UpdatedAt +// } + +// return rulesMap +// } + +func enFlattenSubscriptions(subscriptionList []en.SubscriptionListItem) (subscriptions []map[string]interface{}) { + subscriptions = []map[string]interface{}{} + + for _, subscription := range subscriptionList { + subscriptions = append(subscriptions, enSubscriptionsToMap(subscription)) + } + + return subscriptions +} + +func enSubscriptionsToMap(subscription en.SubscriptionListItem) (subscriptionsMap map[string]interface{}) { + subscriptionsMap = map[string]interface{}{} + + if subscription.ID != nil { + subscriptionsMap["id"] = subscription.ID + } + + if subscription.Name != nil { + subscriptionsMap["name"] = subscription.Name + } + + if subscription.Description != nil { + subscriptionsMap["description"] = subscription.Description + } + + if subscription.UpdatedAt != nil { + subscriptionsMap["updated_at"] = subscription.UpdatedAt + } + + if subscription.DestinationType != nil { + subscriptionsMap["destination_type"] = subscription.DestinationType + } + + if subscription.DestinationID != nil { + subscriptionsMap["destination_id"] = subscription.DestinationID + } + + if subscription.TopicID != nil { + subscriptionsMap["topic_id"] = subscription.TopicID + } + + return subscriptionsMap +} diff --git a/ibm/data_source_ibm_en_topic_test.go b/ibm/service/eventnotification/data_source_ibm_en_topic_test.go similarity index 92% rename from ibm/data_source_ibm_en_topic_test.go rename to ibm/service/eventnotification/data_source_ibm_en_topic_test.go index d939c0551..da12c6845 100644 --- a/ibm/data_source_ibm_en_topic_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_topic_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMEnTopicDataSourceBasic(t *testing.T) { name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnTopicDataSourceConfigBasic(instanceName, name, description), diff --git a/ibm/data_source_ibm_en_topics.go b/ibm/service/eventnotification/data_source_ibm_en_topics.go similarity index 88% rename from ibm/data_source_ibm_en_topics.go rename to ibm/service/eventnotification/data_source_ibm_en_topics.go index 1ff5c182e..74d4d66d4 100644 --- a/ibm/data_source_ibm_en_topics.go +++ b/ibm/service/eventnotification/data_source_ibm_en_topics.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func dataSourceIBMEnTopics() *schema.Resource { +func DataSourceIBMEnTopics() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMEnTopicsRead, @@ -80,7 +82,7 @@ func dataSourceIBMEnTopics() *schema.Resource { } func dataSourceIBMEnTopicsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -124,14 +126,14 @@ func dataSourceIBMEnTopicsRead(context context.Context, d *schema.ResourceData, d.SetId(fmt.Sprintf("topics_%s", d.Get("instance_guid").(string))) - if err = d.Set("total_count", intValue(topicList.TotalCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting total_count: %s", err)) + if err = d.Set("total_count", flex.IntValue(topicList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } if topicList.Topics != nil { err = d.Set("topics", enTopicListFlatten(topicList.Topics)) if err != nil { - return diag.FromErr(fmt.Errorf("error setting topics %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topics %s", err)) } } diff --git a/ibm/data_source_ibm_en_topics_test.go b/ibm/service/eventnotification/data_source_ibm_en_topics_test.go similarity index 92% rename from ibm/data_source_ibm_en_topics_test.go rename to ibm/service/eventnotification/data_source_ibm_en_topics_test.go index 5a2a29358..a2a8e3ed7 100644 --- a/ibm/data_source_ibm_en_topics_test.go +++ b/ibm/service/eventnotification/data_source_ibm_en_topics_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMEnTopicsDataSourceBasic(t *testing.T) { name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMEnTopicsDataSourceConfigBasic(instanceName, name, description), diff --git a/ibm/service/eventnotification/resource_ibm_en_FCM_subscription.go b/ibm/service/eventnotification/resource_ibm_en_FCM_subscription.go new file mode 100644 index 000000000..391f1b0f4 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_FCM_subscription.go @@ -0,0 +1,254 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnFCMSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnFCMSubscriptionCreate, + ReadContext: resourceIBMEnFCMSubscriptionRead, + UpdateContext: resourceIBMEnFCMSubscriptionUpdate, + DeleteContext: resourceIBMEnFCMSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destintion name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnFCMSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnFCMSubscriptionRead(context, d, meta) +} + +func resourceIBMEnFCMSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnFCMSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnFCMSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnFCMSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_FCM_subscription_test.go b/ibm/service/eventnotification/resource_ibm_en_FCM_subscription_test.go new file mode 100644 index 000000000..121120791 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_FCM_subscription_test.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnFCMSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnFCMSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFCMSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnFCMSubscriptionExists("ibm_en_subscription_android.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_android.en_subscription_resource_1", "subscription_id"), + ), + }, + { + Config: testAccCheckIBMEnFCMSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_android.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_android.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_android.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnFCMSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + resource "ibm_en_destination_android" "en_destination_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_destination_name_02983" + type = "push_android" + description = "tf_destinatios_description_0364" + config { + params { + sender_id = "sender id value" + server_key = "server key value" + } + } + } + + resource "ibm_en_subscription_android" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = ibm_en_destination_android.en_destination_resource_2.destination_id + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnFCMSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnFCMSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/resource_ibm_en_destination.go b/ibm/service/eventnotification/resource_ibm_en_destination.go similarity index 78% rename from ibm/resource_ibm_en_destination.go rename to ibm/service/eventnotification/resource_ibm_en_destination.go index d36de656f..32002f6e6 100644 --- a/ibm/resource_ibm_en_destination.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -14,7 +17,7 @@ import ( en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func resourceIBMEnDestination() *schema.Resource { +func ResourceIBMEnDestination() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMEnDestinationCreate, ReadContext: resourceIBMEnDestinationRead, @@ -37,7 +40,7 @@ func resourceIBMEnDestination() *schema.Resource { "type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_en_destination", "type"), + ValidateFunc: validate.InvokeValidator("ibm_en_destination", "type"), Description: "The type of Destination Webhook.", }, "description": { @@ -60,12 +63,12 @@ func resourceIBMEnDestination() *schema.Resource { Schema: map[string]*schema.Schema{ "url": { Type: schema.TypeString, - Required: true, + Optional: true, Description: "URL of webhook.", }, "verb": { Type: schema.TypeString, - Required: true, + Optional: true, Description: "HTTP method of webhook.", }, "custom_headers": { @@ -108,28 +111,29 @@ func resourceIBMEnDestination() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, }, + DeprecationMessage: "This resource will be deprecated. A new resource ibm_en_destination_webhook will replace the existing ibm_en_destination resource ", } } -func resourceIBMEnDestinationValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 1) +func ResourceIBMEnDestinationValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "webhook", MinValueLength: 1, }, ) - resourceValidator := ResourceValidator{ResourceName: "ibm_en_destination", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_en_destination", Schema: validateSchema} return &resourceValidator } func resourceIBMEnDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -159,14 +163,14 @@ func resourceIBMEnDestinationCreate(context context.Context, d *schema.ResourceD } func resourceIBMEnDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.GetDestinationOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -184,43 +188,43 @@ func resourceIBMEnDestinationRead(context context.Context, d *schema.ResourceDat } if err = d.Set("instance_guid", options.InstanceID); err != nil { - return diag.FromErr(fmt.Errorf("error setting instance_guid: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) } if err = d.Set("destination_id", options.ID); err != nil { - return diag.FromErr(fmt.Errorf("error setting destination_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) } if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("type", result.Type); err != nil { - return diag.FromErr(fmt.Errorf("error setting type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if result.Config != nil { err = d.Set("config", enDestinationFlattenConfig(*result.Config)) if err != nil { - return diag.FromErr(fmt.Errorf("error setting config %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) } } - if err = d.Set("updated_at", dateTimeToString(result.UpdatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } - if err = d.Set("subscription_count", intValue(result.SubscriptionCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_count: %s", err)) + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) } if result.Config != nil { if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_names: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) } } @@ -228,14 +232,14 @@ func resourceIBMEnDestinationRead(context context.Context, d *schema.ResourceDat } func resourceIBMEnDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.UpdateDestinationOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -265,14 +269,14 @@ func resourceIBMEnDestinationUpdate(context context.Context, d *schema.ResourceD } func resourceIBMEnDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.DeleteDestinationOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -319,7 +323,6 @@ func destinationConfigMapToDestinationConfig(configParams map[string]interface{} } params.SensitiveHeaders = sensitiveHeaders } - destinationConfig := new(en.DestinationConfig) destinationConfig.Params = params return *destinationConfig diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_apns.go b/ibm/service/eventnotification/resource_ibm_en_destination_apns.go new file mode 100644 index 000000000..62dfa0be5 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_apns.go @@ -0,0 +1,385 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnAPNSDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnAPNSDestinationCreate, + ReadContext: resourceIBMEnAPNSDestinationRead, + UpdateContext: resourceIBMEnAPNSDestinationUpdate, + DeleteContext: resourceIBMEnAPNSDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination type push_ios.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "certificate_content_type": { + Type: schema.TypeString, + Required: true, + Description: "The Certificate Content Type to be set p8/p12.", + }, + "certificate": { + Type: schema.TypeString, + Required: true, + Description: "The Certificate File.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert_type": { + Type: schema.TypeString, + Required: true, + Description: "The Certificate Type for IOS, the values are p8/p12.", + }, + "is_sandbox": { + Type: schema.TypeBool, + Required: true, + Description: "The flag to determine sandbox or production environment.", + }, + "password": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + Description: "The Password for APNS Certificate in case of P12 certificate", + }, + "key_id": { + Type: schema.TypeString, + Optional: true, + Description: "The Key ID In case of P8 Certificate", + }, + "team_id": { + Type: schema.TypeString, + Optional: true, + Description: "The Team ID In case of P8 Certificate", + }, + "bundle_id": { + Type: schema.TypeString, + Optional: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnAPNSDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + + options.SetType(d.Get("type").(string)) + + options.SetCertificateContentType(d.Get("certificate_content_type").(string)) + + certificatetype := d.Get("certificate_content_type").(string) + + if c, ok := d.GetOk("certificate"); ok { + path := c.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening Certificate file (%s): %s", path, err)) + } + + certificate := file + options.SetCertificate(certificate) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing Certificate file (%s): %s", path, err) + } + }() + } + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := APNSdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), certificatetype) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnAPNSDestinationRead(context, d, meta) +} + +func resourceIBMEnAPNSDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enAPNSDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + } + + return nil +} + +func resourceIBMEnAPNSDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "certificate", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + certificatetype := d.Get("certificate_content_type").(string) + + if c, ok := d.GetOk("certificate"); ok { + path := c.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening Certificate file (%s): %s", path, err)) + } + + certificate := file + options.SetCertificate(certificate) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing Certificate file (%s): %s", path, err) + } + }() + } + + if _, ok := d.GetOk("config"); ok { + config := APNSdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), certificatetype) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnAPNSDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnAPNSDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func APNSdestinationConfigMapToDestinationConfig(configParams map[string]interface{}, certificatetype string) en.DestinationConfig { + params := new(en.DestinationConfigParams) + if certificatetype == "p8" { + if configParams["cert_type"] != nil { + params.CertType = core.StringPtr(configParams["cert_type"].(string)) + } + + if configParams["is_sandbox"] != nil { + params.IsSandbox = core.BoolPtr(configParams["is_sandbox"].(bool)) + } + + if configParams["key_id"] != nil { + params.KeyID = core.StringPtr(configParams["key_id"].(string)) + } + + if configParams["team_id"] != nil { + params.TeamID = core.StringPtr(configParams["team_id"].(string)) + } + + if configParams["bundle_id"] != nil { + params.BundleID = core.StringPtr(configParams["bundle_id"].(string)) + } + + } + + if certificatetype == "p12" { + if configParams["cert_type"] != nil { + params.CertType = core.StringPtr(configParams["cert_type"].(string)) + } + + if configParams["is_sandbox"] != nil { + params.IsSandbox = core.BoolPtr(configParams["is_sandbox"].(bool)) + } + + if configParams["password"] != nil { + params.Password = core.StringPtr(configParams["password"].(string)) + } + + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go new file mode 100644 index 000000000..e9def031c --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go @@ -0,0 +1,151 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnAPNSDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnAPNSDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnAPNSDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnAPNSDestinationExists("ibm_en_apns_destination.en_destination_resource_apns", config), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "type", "push_ios"), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "description", description), + ), + }, + { + Config: testAccCheckIBMEnAPNSDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "type", "push_ios"), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_ios.en_destination_resource_apns", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnAPNSDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_ios" "en_destination_resource_apns" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_ios" + certificate_content_type = "p12" + certificate = "${path.module}/cert.p12" + description = "%s" + config { + params { + cert_type = "p12" + is_sandbox = true + password = "certpassword" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnAPNSDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnAPNSDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go b/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go new file mode 100644 index 000000000..6758dd77c --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go @@ -0,0 +1,283 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnChromeDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnChromeDestinationCreate, + ReadContext: resourceIBMEnChromeDestinationRead, + UpdateContext: resourceIBMEnChromeDestinationUpdate, + DeleteContext: resourceIBMEnChromeDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination type push_chrome.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + Description: "The api key for chrome app authorization", + }, + "website_url": { + Type: schema.TypeString, + Optional: true, + Description: "The website url", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnChromeDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + + options.SetType(d.Get("type").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := ChromedestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnChromeDestinationRead(context, d, meta) +} + +func resourceIBMEnChromeDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enChromeDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + } + + return nil +} + +func resourceIBMEnChromeDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + if _, ok := d.GetOk("config"); ok { + config := ChromedestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnChromeDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnChromeDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func ChromedestinationConfigMapToDestinationConfig(configParams map[string]interface{}) en.DestinationConfig { + params := new(en.DestinationConfigParams) + if configParams["api_key"] != nil { + params.APIKey = core.StringPtr(configParams["api_key"].(string)) + } + + if configParams["website_url"] != nil { + params.WebsiteURL = core.StringPtr(configParams["website_url"].(string)) + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go new file mode 100644 index 000000000..0162cfb17 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnChromeDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnChromeDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnChromeDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnChromeDestinationExists("ibm_en_destination_chrome.en_destination_resource_1", config), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "type", "push_chrome"), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "description", description), + ), + }, + { + Config: testAccCheckIBMEnChromeDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "type", "push_chrome"), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_chrome.en_destination_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnChromeDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_chrome" "en_destination_resource_1" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_chrome" + description = "%s" + config { + params { + api_key = "vvshlgwwfvjj" + website_url = "https://testweb.com" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnChromeDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnChromeDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go b/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go new file mode 100644 index 000000000..0f1a3e6f9 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go @@ -0,0 +1,284 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnFCMDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnFCMDestinationCreate, + ReadContext: resourceIBMEnFCMDestinationRead, + UpdateContext: resourceIBMEnFCMDestinationUpdate, + DeleteContext: resourceIBMEnFCMDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination push_android.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sender_id": { + Type: schema.TypeString, + Required: true, + Description: "The Sender_id value for FCM project.", + }, + "server_key": { + Type: schema.TypeString, + Required: true, + Description: "The Server_key value for FCM project.", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnFCMDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := FCMdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnFCMDestinationRead(context, d, meta) +} + +func resourceIBMEnFCMDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enFCMDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + + } + + return nil +} + +func resourceIBMEnFCMDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("config"); ok { + config := FCMdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnFCMDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnFCMDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func FCMdestinationConfigMapToDestinationConfig(configParams map[string]interface{}, destinationtype string) en.DestinationConfig { + params := new(en.DestinationConfigParams) + + if configParams["sender_id"] != nil { + params.SenderID = core.StringPtr(configParams["sender_id"].(string)) + } + + if configParams["server_key"] != nil { + params.ServerKey = core.StringPtr(configParams["server_key"].(string)) + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go new file mode 100644 index 000000000..d92715e1d --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnFCMDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnFCMDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFCMDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnFCMDestinationExists("ibm_en_destination_android.en_destination_resource_fcm", config), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "description", description), + ), + }, + { + Config: testAccCheckIBMEnFCMDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "type", "push_android"), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_android.en_destination_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnFCMDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_android" "en_destination_resource_fcm" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_android" + description = "%s" + config { + params { + sender_id = "FCM_sender_id_value" + server_key = "FCM_Server_key_value" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnFCMDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnFCMDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_fcm" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go b/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go new file mode 100644 index 000000000..83304d7c0 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go @@ -0,0 +1,274 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnFirefoxDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnFirefoxDestinationCreate, + ReadContext: resourceIBMEnFirefoxDestinationRead, + UpdateContext: resourceIBMEnFirefoxDestinationUpdate, + DeleteContext: resourceIBMEnFirefoxDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination type push_firefox.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "website_url": { + Type: schema.TypeString, + Optional: true, + Description: "The website url", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnFirefoxDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + + options.SetType(d.Get("type").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := firefoxdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnFirefoxDestinationRead(context, d, meta) +} + +func resourceIBMEnFirefoxDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enFirefoxDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + } + + return nil +} + +func resourceIBMEnFirefoxDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + if _, ok := d.GetOk("config"); ok { + config := firefoxdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnFirefoxDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnFirefoxDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func firefoxdestinationConfigMapToDestinationConfig(configParams map[string]interface{}) en.DestinationConfig { + params := new(en.DestinationConfigParams) + + if configParams["website_url"] != nil { + params.WebsiteURL = core.StringPtr(configParams["website_url"].(string)) + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go new file mode 100644 index 000000000..9ad3a8735 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go @@ -0,0 +1,147 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnFirefoxDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnFirefoxDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnFirefoxDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnFirefoxDestinationExists("ibm_en_destination_firefox.en_destination_resource_1", config), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "type", "push_firefox"), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "description", description), + ), + }, + { + Config: testAccCheckIBMEnFirefoxDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "type", "push_firefox"), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_firefox.en_destination_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnFirefoxDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_firefox" "en_destination_resource_1" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_firefox" + description = "%s" + config { + params { + website_url = "https://testweb.com" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnFirefoxDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnFirefoxDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_safari.go b/ibm/service/eventnotification/resource_ibm_en_destination_safari.go new file mode 100644 index 000000000..7bea4249b --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_safari.go @@ -0,0 +1,647 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnSafariDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSafariDestinationCreate, + ReadContext: resourceIBMEnSafariDestinationRead, + UpdateContext: resourceIBMEnSafariDestinationUpdate, + DeleteContext: resourceIBMEnSafariDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination type push_ios.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "certificate": { + Type: schema.TypeString, + Required: true, + Description: "The Certificate File.", + }, + "icon_16x16": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_16x16_2x": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_32x32": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_32x32_2x": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_128x128": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_128x128_2x": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_16x16_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_16x16_2x_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_32x32_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_32x32_2x_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_128x128_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "icon_128x128_2x_content_type": { + Type: schema.TypeString, + Optional: true, + Description: "The Certificate File.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert_type": { + Type: schema.TypeString, + Required: true, + Description: "The Certificate Type for IOS, the values are p8/p12.", + }, + "password": { + Type: schema.TypeString, + Sensitive: true, + Required: true, + Description: "The Password for APNS Certificate in case of P12 certificate", + }, + "url_format_string": { + Type: schema.TypeString, + Optional: true, + Description: "The Key ID In case of P8 Certificate", + }, + "website_name": { + Type: schema.TypeString, + Optional: true, + Description: "The Team ID In case of P8 Certificate", + }, + "website_push_id": { + Type: schema.TypeString, + Optional: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + "website_url": { + Type: schema.TypeString, + Optional: true, + Description: "The Bundle ID In case of P8 Certificate", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnSafariDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + + options.SetType(d.Get("type").(string)) + + // options.SetCertificateContentType(d.Get("certificate_content_type").(string)) + if _, ok := d.GetOk("icon_16x16_content_type"); ok { + options.SetIcon16x16ContentType(d.Get("icon_16x16_content_type").(string)) + } + if _, ok := d.GetOk("icon_16x16_2x_content_type"); ok { + options.SetIcon16x162xContentType(d.Get("icon_16x16_2x_content_type").(string)) + } + if _, ok := d.GetOk("icon_32x32_content_type"); ok { + options.SetIcon32x32ContentType(d.Get("icon_32x32_content_type").(string)) + } + if _, ok := d.GetOk("icon_32x32_2x_content_type"); ok { + options.SetIcon32x322xContentType(d.Get("icon_32x32_2x_content_type").(string)) + } + if _, ok := d.GetOk("icon_128x128_content_type"); ok { + options.SetIcon128x128ContentType(d.Get("icon_128x128_content_type").(string)) + } + if _, ok := d.GetOk("icon_128x128_2x_content_type"); ok { + options.SetIcon128x1282xContentType(d.Get("icon_128x128_2x_content_type").(string)) + } + + // certificatetype := d.Get("certificate_content_type").(string) + + if c, ok := d.GetOk("certificate"); ok { + path := c.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening Certificate file (%s): %s", path, err)) + } + + certificate := file + options.SetCertificate(certificate) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing Certificate file (%s): %s", path, err) + } + }() + } + + if i16, ok := d.GetOk("icon_16x16"); ok { + path := i16.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon16_16 := file + options.SetIcon16x16(icon16_16) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i162x, ok := d.GetOk("icon_16x16_2x"); ok { + path := i162x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon16_16_2x := file + options.SetIcon16x162x(icon16_16_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i32, ok := d.GetOk("icon_32x32"); ok { + path := i32.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon32_32 := file + options.SetIcon32x32(icon32_32) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i322x, ok := d.GetOk("icon_32x32_2x"); ok { + path := i322x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon32_32_2x := file + options.SetIcon32x322x(icon32_32_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i128, ok := d.GetOk("icon_128x128"); ok { + path := i128.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon128_128 := file + options.SetIcon128x128(icon128_128) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i1282x, ok := d.GetOk("icon_128x128_2x"); ok { + path := i1282x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon128_128_2x := file + options.SetIcon128x1282x(icon128_128_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := SafaridestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSafariDestinationRead(context, d, meta) +} + +func resourceIBMEnSafariDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enSafariDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + } + + return nil +} + +func resourceIBMEnSafariDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "certificate", "icon_16x16", "icon_16x16_2x", "icon_32x32", "icon_32x32_2x", "icon_128x128", "icon_128x128_2x", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + // certificatetype := d.Get("certificate_content_type").(string) + + if c, ok := d.GetOk("certificate"); ok { + path := c.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening Certificate file (%s): %s", path, err)) + } + + certificate := file + options.SetCertificate(certificate) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing Certificate file (%s): %s", path, err) + } + }() + } + + if i16, ok := d.GetOk("icon_16x16"); ok { + path := i16.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon16_16 := file + options.SetIcon16x16(icon16_16) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i162x, ok := d.GetOk("icon_16x16_2x"); ok { + path := i162x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon16_16_2x := file + options.SetIcon16x162x(icon16_16_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i32, ok := d.GetOk("icon_32x32"); ok { + path := i32.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon32_32 := file + options.SetIcon32x32(icon32_32) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i322x, ok := d.GetOk("icon_32x32_2x"); ok { + path := i322x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon32_32_2x := file + options.SetIcon32x322x(icon32_32_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i128, ok := d.GetOk("icon_128x128"); ok { + path := i128.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon128_128 := file + options.SetIcon128x128(icon128_128) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + + if i1282x, ok := d.GetOk("icon_128x128_2x"); ok { + path := i1282x.(string) + file, err := os.Open(path) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error opening icon file (%s): %s", path, err)) + } + + icon128_128_2x := file + options.SetIcon128x1282x(icon128_128_2x) + defer func() { + err := file.Close() + if err != nil { + log.Printf("[WARN] Failed closing icon file (%s): %s", path, err) + } + }() + } + if _, ok := d.GetOk("config"); ok { + config := SafaridestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSafariDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSafariDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func SafaridestinationConfigMapToDestinationConfig(configParams map[string]interface{}) en.DestinationConfig { + params := new(en.DestinationConfigParams) + if configParams["cert_type"] != nil { + params.CertType = core.StringPtr(configParams["cert_type"].(string)) + } + + if configParams["password"] != nil { + params.Password = core.StringPtr(configParams["password"].(string)) + } + + if configParams["url_format_string"] != nil { + params.URLFormatString = core.StringPtr(configParams["url_format_string"].(string)) + } + + if configParams["website_name"] != nil { + params.WebsiteName = core.StringPtr(configParams["website_name"].(string)) + } + + if configParams["website_push_id"] != nil { + params.WebsitePushID = core.StringPtr(configParams["website_push_id"].(string)) + } + + if configParams["website_url"] != nil { + params.WebsiteURL = core.StringPtr(configParams["website_url"].(string)) + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go new file mode 100644 index 000000000..464bbcbcc --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go @@ -0,0 +1,165 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnSafariDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSafariDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSafariDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnSafariDestinationExists("ibm_en_destination_safari.en_destination_resource_safari", config), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "type", "push_safari"), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "description", description), + ), + }, + { + Config: testAccCheckIBMEnSafariDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "type", "push_safari"), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_safari.en_destination_resource_safari", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnSafariDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_safari" "en_destination_resource_safari" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "push_safari" + certificate = "${path.module}/cert.p12" + icon_16x16 = "${path.module}/safariicon.png" + icon_16x16_2x = "${path.module}/safariicon.png" + icon_32x32 = "${path.module}/safariicon.png" + icon_32x32_2x = "${path.module}/safariicon.png" + icon_128x128 = "${path.module}/safariicon.png" + icon_128x128_2x = "${path.module}/safariicon.png" + icon_16x16_content_type = "png" + icon_16x16_2x_content_type = "png" + icon_32x32_content_type = "png" + icon_32x32_2x_content_type = "png" + icon_128x128_content_type = "png" + icon_128x128_2x_content_type = "png" + description = "%s" + config { + params { + cert_type = "p12" + password = "certpassword" + website_name = "NodeJS Starter Application" + url_format_string = "https://ensafaripush.mybluemix.net" + website_push_id = "web.net.mybluemix.ensafaripush" + website_url = "https://ensafaripush.mybluemix.net" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnSafariDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnSafariDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_safari" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_slack.go b/ibm/service/eventnotification/resource_ibm_en_destination_slack.go new file mode 100644 index 000000000..140f5c2a3 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_slack.go @@ -0,0 +1,274 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnSlackDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSlackDestinationCreate, + ReadContext: resourceIBMEnSlackDestinationRead, + UpdateContext: resourceIBMEnSlackDestinationUpdate, + DeleteContext: resourceIBMEnSlackDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination Webhook.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + Description: "Slack webhook url.", + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnSlackDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := SlackdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSlackDestinationRead(context, d, meta) +} + +func resourceIBMEnSlackDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + + } + + return nil +} + +func resourceIBMEnSlackDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("config"); ok { + config := SlackdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSlackDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSlackDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func SlackdestinationConfigMapToDestinationConfig(configParams map[string]interface{}, destinationtype string) en.DestinationConfig { + params := new(en.DestinationConfigParams) + if configParams["url"] != nil { + params.URL = core.StringPtr(configParams["url"].(string)) + } + + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go new file mode 100644 index 000000000..e7dc23565 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go @@ -0,0 +1,147 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnSlackDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSlackDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSlackDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnSlackDestinationExists("ibm_en_destination_slack.en_destination_resource_1", config), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "type", "slack"), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "description", description), + ), + }, + { + Config: testAccCheckIBMEnSlackDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "type", "slack"), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_slack.en_destination_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnSlackDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_slack" "en_destination_resource_1" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "slack" + description = "%s" + config { + params { + url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnSlackDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnSlackDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/resource_ibm_en_destination_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_test.go similarity index 84% rename from ibm/resource_ibm_en_destination_test.go rename to ibm/service/eventnotification/resource_ibm_en_destination_test.go index 00d15d06c..95b5e511b 100644 --- a/ibm/resource_ibm_en_destination_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,8 +27,8 @@ func TestAccIBMEnDestinationAllArgs(t *testing.T) { newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEnDestinationDestroy, Steps: []resource.TestStep{ { @@ -85,14 +89,14 @@ func testAccCheckIBMEnDestinationExists(n string, obj en.Destination) resource.T return fmt.Errorf("Not found: %s", n) } - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } options := &en.GetDestinationOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -111,7 +115,7 @@ func testAccCheckIBMEnDestinationExists(n string, obj en.Destination) resource.T } func testAccCheckIBMEnDestinationDestroy(s *terraform.State) error { - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } @@ -122,7 +126,7 @@ func testAccCheckIBMEnDestinationDestroy(s *terraform.State) error { options := &en.GetDestinationOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -136,7 +140,7 @@ func testAccCheckIBMEnDestinationDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go b/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go new file mode 100644 index 000000000..de47d5f36 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go @@ -0,0 +1,310 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnWebhookDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnWebhookDestinationCreate, + ReadContext: resourceIBMEnWebhookDestinationRead, + UpdateContext: resourceIBMEnWebhookDestinationUpdate, + DeleteContext: resourceIBMEnWebhookDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination Webhook.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Payload describing a destination configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + Description: "URL of webhook.", + }, + "verb": { + Type: schema.TypeString, + Required: true, + Description: "HTTP method of webhook.", + }, + "custom_headers": { + Type: schema.TypeMap, + Optional: true, + Description: "Custom headers (Key-Value pair) for webhook call.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "sensitive_headers": { + Type: schema.TypeList, + Optional: true, + Description: "List of sensitive headers from custom headers.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnWebhookDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("config"); ok { + config := WebhookdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnWebhookDestinationRead(context, d, meta) +} + +func resourceIBMEnWebhookDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + + } + + return nil +} + +func resourceIBMEnWebhookDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "config"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + destinationtype := d.Get("type").(string) + if _, ok := d.GetOk("config"); ok { + config := WebhookdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + options.SetConfig(&config) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnWebhookDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnWebhookDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func WebhookdestinationConfigMapToDestinationConfig(configParams map[string]interface{}, destinationtype string) en.DestinationConfig { + params := new(en.DestinationConfigParams) + if configParams["url"] != nil { + params.URL = core.StringPtr(configParams["url"].(string)) + } + + if configParams["verb"] != nil { + params.Verb = core.StringPtr(configParams["verb"].(string)) + } + + if configParams["custom_headers"] != nil { + var customHeaders = make(map[string]string) + for k, v := range configParams["custom_headers"].(map[string]interface{}) { + customHeaders[k] = v.(string) + } + params.CustomHeaders = customHeaders + } + + if configParams["sensitive_headers"] != nil { + sensitiveHeaders := []string{} + for _, sensitiveHeadersItem := range configParams["sensitive_headers"].([]interface{}) { + sensitiveHeaders = append(sensitiveHeaders, sensitiveHeadersItem.(string)) + } + params.SensitiveHeaders = sensitiveHeaders + } + destinationConfig := new(en.DestinationConfig) + destinationConfig.Params = params + return *destinationConfig +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go new file mode 100644 index 000000000..c9a25af9d --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnWebhookDestinationAllArgs(t *testing.T) { + var config en.Destination + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnWebhookDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnWebhookDestinationConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnWebhookDestinationExists("ibm_en_destination_webhook.en_destination_resource_1", config), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "description", description), + ), + }, + { + Config: testAccCheckIBMEnWebhookDestinationConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_destination_webhook.en_destination_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnWebhookDestinationConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_webhook" "en_destination_resource_1" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "webhook" + description = "%s" + config { + params { + verb = "POST" + url = "https://demo.webhook.com" + } + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnWebhookDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetDestination(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnWebhookDestinationDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetDestination(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_source.go b/ibm/service/eventnotification/resource_ibm_en_source.go new file mode 100644 index 000000000..4c6f73604 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_source.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnSource() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSourceCreate, + ReadContext: resourceIBMEnSourceRead, + UpdateContext: resourceIBMEnSourceUpdate, + DeleteContext: resourceIBMEnSourceDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Source name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Source description.", + }, + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "The enabled flag for source", + }, + "source_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnSourceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSourcesOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + options.SetEnabled(d.Get("enabled").(bool)) + + result, response, err := enClient.CreateSourcesWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSourcesWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSourceRead(context, d, meta) +} + +func resourceIBMEnSourceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSourceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSourceWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSourceWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("source_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if err = d.Set("enabled", result.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enabled: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnSourceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSourceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "enabled"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + options.SetEnabled(d.Get("enabled").(bool)) + + _, response, err := enClient.UpdateSourceWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSourceWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSourceRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSourceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSourceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSourceWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSourceWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription.go b/ibm/service/eventnotification/resource_ibm_en_subscription.go new file mode 100644 index 000000000..928769439 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription.go @@ -0,0 +1,405 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMEnSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSubscriptionCreate, + ReadContext: resourceIBMEnSubscriptionRead, + UpdateContext: resourceIBMEnSubscriptionUpdate, + DeleteContext: resourceIBMEnSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "to": { + Type: schema.TypeList, + Optional: true, + Description: "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "add_notification_payload": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to add the notification payload to the email.", + }, + "reply_to": { + Type: schema.TypeString, + Optional: true, + Description: "The email address to reply to.", + }, + "reply_to_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the email address user to reply to.", + }, + "from_name": { + Type: schema.TypeString, + Optional: true, + Description: "The email address from.", + }, + "signing_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: "Signing webhook attributes.", + }, + "remove": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address to remove the recepient from smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination Webhook.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destintion name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "from": { + Type: schema.TypeString, + Computed: true, + Description: "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + DeprecationMessage: "This resource will be deprecated. To create subscription for email, sms, webhook destination kindly use ibm_en_subscription_email, ibm_en_subscription_sms, ibm_en_subscription_webhook subscription resources", + } +} + +func resourceIBMEnSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes, _ := attributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSubscriptionRead(context, d, meta) +} + +func resourceIBMEnSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + destinationtype := d.Get("destination_type").(string) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + if destinationtype == "smtp_ibm" { + attributes := attributesMapToEmailAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + } else { + _, attributes := attributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + } + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func attributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributes) { + attributesCreate := en.SubscriptionCreateAttributes{} + attributesUpdate := en.SubscriptionUpdateAttributes{} + + if attributeMap["to"] != nil { + to := []string{} + for _, toItem := range attributeMap["to"].([]interface{}) { + to = append(to, toItem.(string)) + } + attributesCreate.To = to + attributesUpdate.To = to + } + + if attributeMap["add_notification_payload"] != nil { + attributesCreate.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) + attributesUpdate.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) + } + + if attributeMap["reply_to"] != nil { + attributesCreate.ReplyToMail = core.StringPtr(attributeMap["reply_to"].(string)) + } + + if attributeMap["signing_enabled"] != nil { + attributesCreate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) + attributesUpdate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) + } + + if attributeMap["reply_to_name"] != nil { + attributesCreate.ReplyToName = core.StringPtr(attributeMap["reply_to_name"].(string)) + } + + if attributeMap["from_name"] != nil { + attributesCreate.FromName = core.StringPtr(attributeMap["from_name"].(string)) + } + + return attributesCreate, attributesUpdate +} + +func attributesMapToEmailAttributes(attributeMap map[string]interface{}) en.SubscriptionUpdateAttributesEmailUpdateAttributes { + updateattributes := en.SubscriptionUpdateAttributesEmailUpdateAttributes{} + + addemail := new(en.EmailUpdateAttributesTo) + if attributeMap["to"] != nil { + to := []string{} + for _, toItem := range attributeMap["to"].([]interface{}) { + to = append(to, toItem.(string)) + } + addemail.Add = to + } + updateattributes.To = addemail + + if attributeMap["add_notification_payload"] != nil { + updateattributes.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) + } + + if attributeMap["reply_to"] != nil { + updateattributes.ReplyToMail = core.StringPtr(attributeMap["reply_to"].(string)) + } + + if attributeMap["reply_to_name"] != nil { + updateattributes.ReplyToName = core.StringPtr(attributeMap["reply_to_name"].(string)) + } + + if attributeMap["from_name"] != nil { + updateattributes.FromName = core.StringPtr(attributeMap["from_name"].(string)) + } + + if attributeMap["remove"] != nil { + removed := []string{} + for _, removedItem := range attributeMap["remove"].([]interface{}) { + removed = append(removed, removedItem.(string)) + } + addemail.Remove = removed + } + unsubscribed := new(en.EmailUpdateAttributesUnsubscribed) + if attributeMap["unsubscribed"] != nil { + unsubscribe := []string{} + for _, unsubscribeItem := range attributeMap["unsubscribed"].([]interface{}) { + unsubscribe = append(unsubscribe, unsubscribeItem.(string)) + } + unsubscribed.Remove = unsubscribe + } + updateattributes.Unsubscribed = unsubscribed + + return updateattributes +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_email.go b/ibm/service/eventnotification/resource_ibm_en_subscription_email.go new file mode 100644 index 000000000..556a589de --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_email.go @@ -0,0 +1,399 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMEnEmailSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnEmailSubscriptionCreate, + ReadContext: resourceIBMEnEmailSubscriptionRead, + UpdateContext: resourceIBMEnEmailSubscriptionUpdate, + DeleteContext: resourceIBMEnEmailSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "to": { + Type: schema.TypeList, + Optional: true, + Description: "The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "add_notification_payload": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to add the notification payload to the email.", + }, + "reply_to_mail": { + Type: schema.TypeString, + Optional: true, + Description: "The email address to reply to.", + }, + "reply_to_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the email address user to reply to.", + }, + "from_name": { + Type: schema.TypeString, + Optional: true, + Description: "The email address from which email is sourced.", + }, + "invited": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address send the invite to in case of smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "unsubscribed": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address which should be unsubscribed from smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "add": { + Type: schema.TypeList, + Optional: true, + Description: "The Email address which should be added to smtp_ibm.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destintion name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "from": { + Type: schema.TypeString, + Computed: true, + Description: "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnEmailSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes := EmailattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnEmailSubscriptionRead(context, d, meta) +} + +func resourceIBMEnEmailSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnEmailSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes := EmailattributesupdateMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnEmailSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnEmailSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func EmailattributesMapToAttributes(attributeMap map[string]interface{}) en.SubscriptionCreateAttributes { + attributesCreate := en.SubscriptionCreateAttributes{} + if attributeMap["to"] != nil { + to := []string{} + for _, toItem := range attributeMap["to"].([]interface{}) { + to = append(to, toItem.(string)) + } + attributesCreate.To = to + } + + if attributeMap["add_notification_payload"] != nil { + attributesCreate.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) + } + + if attributeMap["reply_to_mail"] != nil { + attributesCreate.ReplyToMail = core.StringPtr(attributeMap["reply_to_mail"].(string)) + } + + if attributeMap["reply_to_name"] != nil { + attributesCreate.ReplyToName = core.StringPtr(attributeMap["reply_to_name"].(string)) + } + + if attributeMap["from_name"] != nil { + attributesCreate.FromName = core.StringPtr(attributeMap["from_name"].(string)) + } + + return attributesCreate +} + +func EmailattributesupdateMapToAttributes(attributeMap map[string]interface{}) en.SubscriptionUpdateAttributesEmailUpdateAttributes { + updateattributes := en.SubscriptionUpdateAttributesEmailUpdateAttributes{} + + addemail := new(en.EmailUpdateAttributesTo) + if attributeMap["add"] != nil { + to := []string{} + for _, toItem := range attributeMap["add"].([]interface{}) { + to = append(to, toItem.(string)) + } + addemail.Add = to + } + updateattributes.To = addemail + + if attributeMap["add_notification_payload"] != nil { + updateattributes.AddNotificationPayload = core.BoolPtr(attributeMap["add_notification_payload"].(bool)) + } + + if attributeMap["reply_to_mail"] != nil { + updateattributes.ReplyToMail = core.StringPtr(attributeMap["reply_to_mail"].(string)) + } + + if attributeMap["reply_to_name"] != nil { + updateattributes.ReplyToName = core.StringPtr(attributeMap["reply_to_name"].(string)) + } + + if attributeMap["from_name"] != nil { + updateattributes.FromName = core.StringPtr(attributeMap["from_name"].(string)) + } + + if attributeMap["invited"] != nil { + invited := []string{} + for _, invitedItem := range attributeMap["invited"].([]interface{}) { + invited = append(invited, invitedItem.(string)) + } + updateattributes.Invited = invited + } + + unsubscribed := new(en.EmailUpdateAttributesUnsubscribed) + if attributeMap["unsubscribed"] != nil { + unsubscribe := []string{} + for _, unsubscribeItem := range attributeMap["unsubscribed"].([]interface{}) { + unsubscribe = append(unsubscribe, unsubscribeItem.(string)) + } + addemail.Remove = unsubscribe + unsubscribed.Remove = unsubscribe + } + updateattributes.Unsubscribed = unsubscribed + + return updateattributes +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_email_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_email_test.go new file mode 100644 index 000000000..b88ff834f --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_email_test.go @@ -0,0 +1,169 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnEmailSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnEmailSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnEmailSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnEmailSubscriptionExists("ibm_en_subscription_email.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "subscription_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.#"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.0.reply_to_mail"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.0.reply_to_name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.0.from_name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.0.add_notification_payload"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_email.en_subscription_resource_1", "attributes.0.to"), + ), + }, + { + Config: testAccCheckIBMEnEmailSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_email.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_email.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_email.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnEmailSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + + resource "ibm_en_subscription_email" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = "set email destination id" + attributes { + add_notification_payload = true + reply_to_mail = "en@ibm.com" + reply_to_name = "EYS ORG" + from_name="ABC ORG" + to = ["testmail@gmail.com"] + + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnEmailSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnEmailSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_slack.go b/ibm/service/eventnotification/resource_ibm_en_subscription_slack.go new file mode 100644 index 000000000..0739589fb --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_slack.go @@ -0,0 +1,287 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMEnSlackSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSlackSubscriptionCreate, + ReadContext: resourceIBMEnSlackSubscriptionRead, + UpdateContext: resourceIBMEnSlackSubscriptionUpdate, + DeleteContext: resourceIBMEnSlackSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attachment_color": { + Type: schema.TypeString, + Optional: true, + Description: "attachment color code", + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destintion name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnSlackSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes, _ := slackattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSlackSubscriptionRead(context, d, meta) +} + +func resourceIBMEnSlackSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnSlackSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + _, attributes := slackattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSlackSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSlackSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func slackattributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributesSlackAttributes) { + attributesCreate := en.SubscriptionCreateAttributes{} + attributesUpdate := en.SubscriptionUpdateAttributesSlackAttributes{} + + if attributeMap["attachment_color"] != nil { + attributesCreate.AttachmentColor = core.StringPtr(attributeMap["attachment_color"].(string)) + attributesUpdate.AttachmentColor = core.StringPtr(attributeMap["attachment_color"].(string)) + } + + return attributesCreate, attributesUpdate +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_slack_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_slack_test.go new file mode 100644 index 000000000..56275ad5a --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_slack_test.go @@ -0,0 +1,171 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnSlackSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSlackSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSlackSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnSlackSubscriptionExists("ibm_en_subscription_slack.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "subscription_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "attributes.#"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_slack.en_subscription_resource_1", "attributes.0.signing_enabled"), + ), + }, + { + Config: testAccCheckIBMEnSlackSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_slack.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_slack.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_slack.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnSlackSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + resource "ibm_en_destination_slack" "en_destination_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_destination_name_02983" + type = "slack" + description = "tf_destinatios_description_0364" + config { + params { + "url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk"" + } + } + } + + resource "ibm_en_subscription_slack" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = ibm_en_destination_slack.en_webhook_destination_resource_2.destination_id + attributes { + attachment_color = "#0000FF" + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnSlackSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnSlackSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_sms.go b/ibm/service/eventnotification/resource_ibm_en_subscription_sms.go new file mode 100644 index 000000000..f8d2be12e --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_sms.go @@ -0,0 +1,291 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnSMSSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnSMSSubscriptionCreate, + ReadContext: resourceIBMEnSMSSubscriptionRead, + UpdateContext: resourceIBMEnSMSSubscriptionUpdate, + DeleteContext: resourceIBMEnSMSSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "to": { + Type: schema.TypeList, + Optional: true, + Description: "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destination name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnSMSSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes, _ := SMSattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSMSSubscriptionRead(context, d, meta) +} + +func resourceIBMEnSMSSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnSMSSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + _, attributes := SMSattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSMSSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnSMSSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func SMSattributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributesSmsAttributes) { + attributesCreate := en.SubscriptionCreateAttributes{} + attributesUpdate := en.SubscriptionUpdateAttributesSmsAttributes{} + + if attributeMap["to"] != nil { + to := []string{} + for _, toItem := range attributeMap["to"].([]interface{}) { + to = append(to, toItem.(string)) + } + attributesCreate.To = to + attributesUpdate.To = to + } + + return attributesCreate, attributesUpdate +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go new file mode 100644 index 000000000..f0fba2bae --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go @@ -0,0 +1,160 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnSMSSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSMSSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnSMSSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnSMSSubscriptionExists("ibm_en_subscription_sms.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "subscription_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "attributes.#"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "attributes.0.to"), + ), + }, + { + Config: testAccCheckIBMEnSMSSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_sms.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_sms.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_sms.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnSMSSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + + resource "ibm_en_subscription_sms" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = "set sms destination id" + attributes { + to = ["+16382922821", "+18976569023"] + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnSMSSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnSMSSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/resource_ibm_en_subscription_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_test.go similarity index 88% rename from ibm/resource_ibm_en_subscription_test.go rename to ibm/service/eventnotification/resource_ibm_en_subscription_test.go index 7ae5b5c1f..b9533d798 100644 --- a/ibm/resource_ibm_en_subscription_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,8 +27,8 @@ func TestAccIBMEnSubscriptionAllArgs(t *testing.T) { newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEnSubscriptionDestroy, Steps: []resource.TestStep{ { @@ -95,7 +99,6 @@ func testAccCheckIBMEnSubscriptionConfig(instanceName, name, description string) topic_id = ibm_en_topic.en_topic_resource_2.topic_id destination_id = ibm_en_destination.en_destination_resource_2.destination_id attributes { - add_notification_payload = true signing_enabled = true } } @@ -110,14 +113,14 @@ func testAccCheckIBMEnSubscriptionExists(n string, obj en.Subscription) resource return fmt.Errorf("Not found: %s", n) } - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } options := &en.GetSubscriptionOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -136,7 +139,7 @@ func testAccCheckIBMEnSubscriptionExists(n string, obj en.Subscription) resource } func testAccCheckIBMEnSubscriptionDestroy(s *terraform.State) error { - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } @@ -148,7 +151,7 @@ func testAccCheckIBMEnSubscriptionDestroy(s *terraform.State) error { options := &en.GetSubscriptionOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -162,7 +165,7 @@ func testAccCheckIBMEnSubscriptionDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_webhook.go b/ibm/service/eventnotification/resource_ibm_en_subscription_webhook.go new file mode 100644 index 000000000..595008702 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_webhook.go @@ -0,0 +1,288 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMEnWebhookSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnWebhookSubscriptionCreate, + ReadContext: resourceIBMEnWebhookSubscriptionRead, + UpdateContext: resourceIBMEnWebhookSubscriptionUpdate, + DeleteContext: resourceIBMEnWebhookSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "signing_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Signing webhook attributes.", + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destintion name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnWebhookSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes, _ := webhookattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnWebhookSubscriptionRead(context, d, meta) +} + +func resourceIBMEnWebhookSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("destination_type", result.DestinationType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnWebhookSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + _, attributes := webhookattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnWebhookSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnWebhookSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func webhookattributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributesWebhookAttributes) { + attributesCreate := en.SubscriptionCreateAttributes{} + attributesUpdate := en.SubscriptionUpdateAttributesWebhookAttributes{} + + if attributeMap["signing_enabled"] != nil { + attributesCreate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) + attributesUpdate.SigningEnabled = core.BoolPtr(attributeMap["signing_enabled"].(bool)) + } + + return attributesCreate, attributesUpdate +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_webhook_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_webhook_test.go new file mode 100644 index 000000000..825ed4e39 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_webhook_test.go @@ -0,0 +1,172 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnWebhookSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnWebhookSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnWebhookSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnWebhookSubscriptionExists("ibm_en_subscription_webhook.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "subscription_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "attributes.#"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_webhook.en_subscription_resource_1", "attributes.0.signing_enabled"), + ), + }, + { + Config: testAccCheckIBMEnWebhookSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_webhook.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_webhook.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_webhook.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnWebhookSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + resource "ibm_en_destination_webhook" "en_destination_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_destination_name_02983" + type = "webhook" + description = "tf_destinatios_description_0364" + config { + params { + verb = "POST" + url = "https://demo.webhook.com" + } + } + } + + resource "ibm_en_subscription_webhook" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = ibm_en_destination_webhook.en_webhook_destination_resource_2.destination_id + attributes { + signing_enabled = true + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnWebhookSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnWebhookSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/resource_ibm_en_topic.go b/ibm/service/eventnotification/resource_ibm_en_topic.go similarity index 88% rename from ibm/resource_ibm_en_topic.go rename to ibm/service/eventnotification/resource_ibm_en_topic.go index 1ba30ea6c..d55c75b1a 100644 --- a/ibm/resource_ibm_en_topic.go +++ b/ibm/service/eventnotification/resource_ibm_en_topic.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -14,7 +16,7 @@ import ( "github.com/IBM/go-sdk-core/v5/core" ) -func resourceIBMEnTopic() *schema.Resource { +func ResourceIBMEnTopic() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMEnTopicCreate, ReadContext: resourceIBMEnTopicRead, @@ -148,7 +150,7 @@ func resourceIBMEnTopic() *schema.Resource { } func resourceIBMEnTopicCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } @@ -184,14 +186,14 @@ func resourceIBMEnTopicCreate(context context.Context, d *schema.ResourceData, m } func resourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.GetTopicOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -214,11 +216,11 @@ func resourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, met d.Set("topic_id", result.ID) if err = d.Set("name", result.Name); err != nil { - return diag.FromErr(fmt.Errorf("error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("description", result.Description); err != nil { - return diag.FromErr(fmt.Errorf("error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if result.Sources != nil { @@ -228,20 +230,20 @@ func resourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, met sources = append(sources, sourcesItemMap) } if err = d.Set("sources", sources); err != nil { - return diag.FromErr(fmt.Errorf("error setting sources: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sources: %s", err)) } } if err = d.Set("updated_at", result.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("error setting updated_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } - if err = d.Set("source_count", intValue(result.SourceCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting source_count: %s", err)) + if err = d.Set("source_count", flex.IntValue(result.SourceCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_count: %s", err)) } - if err = d.Set("subscription_count", intValue(result.SubscriptionCount)); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscription_count: %s", err)) + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) } subscriptions := []map[string]interface{}{} @@ -251,21 +253,21 @@ func resourceIBMEnTopicRead(context context.Context, d *schema.ResourceData, met } if err = d.Set("subscriptions", subscriptions); err != nil { - return diag.FromErr(fmt.Errorf("error setting subscriptions: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscriptions: %s", err)) } return nil } func resourceIBMEnTopicUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.ReplaceTopicOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -299,14 +301,14 @@ func resourceIBMEnTopicUpdate(context context.Context, d *schema.ResourceData, m } func resourceIBMEnTopicDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - enClient, err := meta.(ClientSession).EventNotificationsApiV1() + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() if err != nil { return diag.FromErr(err) } options := &en.DeleteTopicOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -362,7 +364,7 @@ func resourceIBMEnTopicMapToRules(rulesMap map[string]interface{}) en.Rules { return rules } -func enTopicUpdateSourcesItemToMap(source en.TopicSourcesItem) map[string]interface{} { +func enTopicUpdateSourcesItemToMap(source en.SourcesListItem) map[string]interface{} { sourceMap := map[string]interface{}{} if source.ID != nil { diff --git a/ibm/resource_ibm_en_topic_test.go b/ibm/service/eventnotification/resource_ibm_en_topic_test.go similarity index 83% rename from ibm/resource_ibm_en_topic_test.go rename to ibm/service/eventnotification/resource_ibm_en_topic_test.go index 92fa338db..0edac899d 100644 --- a/ibm/resource_ibm_en_topic_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_topic_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,8 +27,8 @@ func TestAccIBMEnTopicAllArgs(t *testing.T) { descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEnTopicDestroy, Steps: []resource.TestStep{ { @@ -76,14 +80,14 @@ func testAccCheckIBMEnTopicExists(n string, obj en.Topic) resource.TestCheckFunc return fmt.Errorf("Not found: %s", n) } - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } options := &en.GetTopicOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -102,7 +106,7 @@ func testAccCheckIBMEnTopicExists(n string, obj en.Topic) resource.TestCheckFunc } func testAccCheckIBMEnTopicDestroy(s *terraform.State) error { - enClient, err := testAccProvider.Meta().(ClientSession).EventNotificationsApiV1() + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err } @@ -113,7 +117,7 @@ func testAccCheckIBMEnTopicDestroy(s *terraform.State) error { options := &en.GetTopicOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -127,7 +131,7 @@ func testAccCheckIBMEnTopicDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("en_topic still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for en_topic (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for en_topic (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/eventstreams/README.md b/ibm/service/eventstreams/README.md new file mode 100644 index 000000000..0e054addb --- /dev/null +++ b/ibm/service/eventstreams/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Event Streams + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Event Streams resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/event_streams_schema) +* IBM API Docs: [IBM API Docs for Event Streams](https://cloud.ibm.com/apidocs/event-streams/adminrest) +* IBM Event Streams SDK: [IBM SDK for Event Streams](https://github.com/IBM/eventstreams-go-sdk/tree/main/pkg) diff --git a/ibm/data_source_ibm_event_streams_schema.go b/ibm/service/eventstreams/data_source_ibm_event_streams_schema.go similarity index 88% rename from ibm/data_source_ibm_event_streams_schema.go rename to ibm/service/eventstreams/data_source_ibm_event_streams_schema.go index a25e78fc9..efc9aa7f9 100644 --- a/ibm/data_source_ibm_event_streams_schema.go +++ b/ibm/service/eventstreams/data_source_ibm_event_streams_schema.go @@ -1,24 +1,25 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM/eventstreams-go-sdk/pkg/schemaregistryv1" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMEventStreamsSchema() *schema.Resource { +func DataSourceIBMEventStreamsSchema() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMEventStreamsSchemaRead, Schema: map[string]*schema.Schema{ - "resource_instance_id": &schema.Schema{ + "resource_instance_id": { Type: schema.TypeString, Required: true, Description: "The ID or CRN of the Event Streams service instance", @@ -28,7 +29,7 @@ func dataSourceIBMEventStreamsSchema() *schema.Resource { Computed: true, Description: "The API endpoint for interacting with an Event Streams REST API", }, - "schema_id": &schema.Schema{ + "schema_id": { Type: schema.TypeString, Required: true, Description: "The unique ID to be assigned to the schema.", @@ -38,7 +39,7 @@ func dataSourceIBMEventStreamsSchema() *schema.Resource { } func dataSourceIBMEventStreamsSchemaRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schemaregistryClient, err := meta.(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := meta.(conns.ClientSession).ESschemaRegistrySession() if err != nil { log.Printf("[DEBUG] dataSourceIBMEventStreamsSchemaRead schemaregistryClient err %s", err) return diag.FromErr(err) diff --git a/ibm/data_source_ibm_event_streams_schema_test.go b/ibm/service/eventstreams/data_source_ibm_event_streams_schema_test.go similarity index 91% rename from ibm/data_source_ibm_event_streams_schema_test.go rename to ibm/service/eventstreams/data_source_ibm_event_streams_schema_test.go index 3ec78300d..4ee7aeb3e 100644 --- a/ibm/data_source_ibm_event_streams_schema_test.go +++ b/ibm/service/eventstreams/data_source_ibm_event_streams_schema_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ var ( func TestAccIBMEventStreamsSchemaDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaDataSourceConfigBasic(MZREnterpriseInstanceName, mySchemaID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_resource_instance.es_instance", "extensions.kafka_http_url"), @@ -28,7 +30,7 @@ func TestAccIBMEventStreamsSchemaDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_event_streams_schema.es_schema", "id"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaDataSourceConfigBasic(SZREnterpriseInstanceName, mySchemaID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_resource_instance.es_instance", "extensions.kafka_http_url"), diff --git a/ibm/data_source_ibm_event_streams_topic.go b/ibm/service/eventstreams/data_source_ibm_event_streams_topic.go similarity index 91% rename from ibm/data_source_ibm_event_streams_topic.go rename to ibm/service/eventstreams/data_source_ibm_event_streams_topic.go index f0534c5aa..bfa4b67e0 100644 --- a/ibm/data_source_ibm_event_streams_topic.go +++ b/ibm/service/eventstreams/data_source_ibm_event_streams_topic.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams import ( "fmt" @@ -10,11 +10,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMEventStreamsTopic() *schema.Resource { +func DataSourceIBMEventStreamsTopic() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMEventStreamsTopicRead, Schema: map[string]*schema.Schema{ - "resource_instance_id": &schema.Schema{ + "resource_instance_id": { Type: schema.TypeString, Required: true, Description: "The CRN of the Event Streams instance", @@ -30,17 +30,17 @@ func dataSourceIBMEventStreamsTopic() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Description: "Kafka brokers addresses for interacting with Kafka native API", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Description: "The name of the topic", Required: true, }, - "partitions": &schema.Schema{ + "partitions": { Type: schema.TypeInt, Description: "The number of partitions of the topic", Computed: true, }, - "config": &schema.Schema{ + "config": { Type: schema.TypeMap, Description: "The configuration parameters of the topic.", Computed: true, diff --git a/ibm/data_source_ibm_event_streams_topic_test.go b/ibm/service/eventstreams/data_source_ibm_event_streams_topic_test.go similarity index 96% rename from ibm/data_source_ibm_event_streams_topic_test.go rename to ibm/service/eventstreams/data_source_ibm_event_streams_topic_test.go index c73eb6866..727eb35e5 100644 --- a/ibm/data_source_ibm_event_streams_topic_test.go +++ b/ibm/service/eventstreams/data_source_ibm_event_streams_topic_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,9 +21,9 @@ var ( func TestAccIBMEventStreamsTopicDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - Providers: testAccProviders, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicDataSourceConfigBasic(MZREnterpriseInstanceName, topicName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_resource_instance.es_instance", "extensions.kafka_brokers_sasl.0"), @@ -32,7 +34,7 @@ func TestAccIBMEventStreamsTopicDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_event_streams_topic.es_topic", "kafka_http_url"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicDataSourceConfigBasic(SZREnterpriseInstanceName, topicName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_resource_instance.es_instance", "extensions.kafka_brokers_sasl.0"), @@ -43,7 +45,7 @@ func TestAccIBMEventStreamsTopicDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_event_streams_topic.es_topic", "kafka_http_url"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicDataSourceConfigBasic(standardInstanceName, topicName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_resource_instance.es_instance", "extensions.kafka_brokers_sasl.0"), diff --git a/ibm/resource_ibm_event_streams_schema.go b/ibm/service/eventstreams/resource_ibm_event_streams_schema.go similarity index 92% rename from ibm/resource_ibm_event_streams_schema.go rename to ibm/service/eventstreams/resource_ibm_event_streams_schema.go index 3a989c4ef..7d4865eb9 100644 --- a/ibm/resource_ibm_event_streams_schema.go +++ b/ibm/service/eventstreams/resource_ibm_event_streams_schema.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams import ( "context" @@ -10,13 +10,15 @@ import ( "log" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/eventstreams-go-sdk/pkg/schemaregistryv1" "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMEventStreamsSchema() *schema.Resource { +func ResourceIBMEventStreamsSchema() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMEventStreamsSchemaCreate, ReadContext: resourceIBMEventStreamsSchemaRead, @@ -25,7 +27,7 @@ func resourceIBMEventStreamsSchema() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "resource_instance_id": &schema.Schema{ + "resource_instance_id": { Type: schema.TypeString, Description: "The ID or the CRN of the Event Streams service instance", Required: true, @@ -36,11 +38,11 @@ func resourceIBMEventStreamsSchema() *schema.Resource { Computed: true, Description: "The API endpoint for interacting with an Event Streams REST API", }, - "schema": &schema.Schema{ + "schema": { Type: schema.TypeString, Required: true, StateFunc: func(v interface{}) string { - json, err := normalizeJSONString(v) + json, err := flex.NormalizeJSONString(v) if err != nil { return fmt.Sprintf("%q", err.Error()) } @@ -49,7 +51,7 @@ func resourceIBMEventStreamsSchema() *schema.Resource { ValidateFunc: validateAvroSchema, Description: "The schema in JSON format", }, - "schema_id": &schema.Schema{ + "schema_id": { Type: schema.TypeString, Optional: true, Computed: true, @@ -94,7 +96,7 @@ func (Bytes) _type() string { return "bytes" } func (String) _type() string { return "string" } func validateAvroSchema(v interface{}, k string) (ws []string, errors []error) { - if _, err := normalizeJSONString(v); err != nil { + if _, err := flex.NormalizeJSONString(v); err != nil { errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) } var j interface{} @@ -171,7 +173,7 @@ func validateName(s map[string]interface{}, t string) error { } func resourceIBMEventStreamsSchemaCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schemaregistryClient, err := meta.(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := meta.(conns.ClientSession).ESschemaRegistrySession() if err != nil { return diag.FromErr(err) } @@ -203,7 +205,7 @@ func resourceIBMEventStreamsSchemaCreate(context context.Context, d *schema.Reso } func resourceIBMEventStreamsSchemaRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schemaregistryClient, err := meta.(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := meta.(conns.ClientSession).ESschemaRegistrySession() if err != nil { return diag.FromErr(err) } @@ -231,11 +233,11 @@ func resourceIBMEventStreamsSchemaRead(context context.Context, d *schema.Resour s, err := json.Marshal(avroSchema) if err != nil { - return diag.FromErr(fmt.Errorf("error marshalling the created schema: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error marshalling the created schema: %s", err)) } if err = d.Set("schema", string(s)); err != nil { - return diag.FromErr(fmt.Errorf("error setting the schema: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting the schema: %s", err)) } d.Set("resource_instance_id", instanceCRN) d.Set("schema_id", schemaID) @@ -244,7 +246,7 @@ func resourceIBMEventStreamsSchemaRead(context context.Context, d *schema.Resour } func resourceIBMEventStreamsSchemaUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schemaregistryClient, err := meta.(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := meta.(conns.ClientSession).ESschemaRegistrySession() if err != nil { return diag.FromErr(err) } @@ -276,7 +278,7 @@ func resourceIBMEventStreamsSchemaUpdate(context context.Context, d *schema.Reso } func resourceIBMEventStreamsSchemaDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - schemaregistryClient, err := meta.(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := meta.(conns.ClientSession).ESschemaRegistrySession() if err != nil { return diag.FromErr(err) } @@ -331,7 +333,7 @@ func getInstanceURL(d *schema.ResourceData, meta interface{}) (string, string, e } func getInstanceDetails(crn string, meta interface{}) (*resourcecontrollerv2.ResourceInstance, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { log.Printf("[DEBUG] getInstanceURL ResourceControllerAPI err %s", err) return nil, err diff --git a/ibm/resource_ibm_event_streams_schema_test.go b/ibm/service/eventstreams/resource_ibm_event_streams_schema_test.go similarity index 86% rename from ibm/resource_ibm_event_streams_schema_test.go rename to ibm/service/eventstreams/resource_ibm_event_streams_schema_test.go index e68ba7077..be31c72f9 100644 --- a/ibm/resource_ibm_event_streams_schema_test.go +++ b/ibm/service/eventstreams/resource_ibm_event_streams_schema_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,11 +23,11 @@ func TestAccIBMEventStreamsSchemaBasic(t *testing.T) { var conf map[string]interface{} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsSchemaDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaConfigBasicWithExistingInstance(SZREnterpriseInstanceName, "szr"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsSchemaExists("ibm_event_streams_schema.es_schema", conf, ""), @@ -34,7 +37,7 @@ func TestAccIBMEventStreamsSchemaBasic(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_event_streams_schema.es_schema", "schema_id"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaConfigBasicWithExistingInstance(MZREnterpriseInstanceName, "mzr"), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsSchemaExists("ibm_event_streams_schema.es_schema", conf, ""), @@ -52,11 +55,11 @@ func TestAccIBMEventStreamsSchemaAllArgs(t *testing.T) { var conf map[string]interface{} schemaID := fmt.Sprintf("tf_schema_id_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsSchemaDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaWithSchemaIDWithExistingInstance(MZREnterpriseInstanceName, schemaID), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsSchemaExists("ibm_event_streams_schema.es_schema", conf, schemaID), @@ -73,11 +76,11 @@ func TestAccIBMEventStreamsSchemaAllArgs(t *testing.T) { func TestAccIBMEventStreamsSchemaImport(t *testing.T) { var conf map[string]interface{} resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsSchemaDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsSchemaWithSchemaIDWithExistingInstance(MZREnterpriseInstanceName, schemaID), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsSchemaExists("ibm_event_streams_schema.es_schema", conf, schemaID), @@ -85,7 +88,7 @@ func TestAccIBMEventStreamsSchemaImport(t *testing.T) { resource.TestCheckResourceAttr("ibm_event_streams_schema.es_schema", "schema_id", schemaID), ), }, - resource.TestStep{ + { ResourceName: "ibm_event_streams_schema.es_schema", ImportState: true, ImportStateVerify: true, @@ -160,7 +163,7 @@ func testAccCheckIBMEventStreamsSchemaExists(n string, obj map[string]interface{ return fmt.Errorf("Not found: %s", n) } - schemaregistryClient, err := testAccProvider.Meta().(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ESschemaRegistrySession() if err != nil { return err } @@ -172,7 +175,7 @@ func testAccCheckIBMEventStreamsSchemaExists(n string, obj map[string]interface{ } if schemaID != "" { if !strings.HasSuffix(id, schemaID) { - return fmt.Errorf("Invalid id: %s and schemaID %s", id, schemaID) + return fmt.Errorf("[ERROR] Invalid id: %s and schemaID %s", id, schemaID) } } @@ -190,7 +193,7 @@ func testAccCheckIBMEventStreamsSchemaExists(n string, obj map[string]interface{ } func testAccCheckIBMEventStreamsSchemaDestroy(s *terraform.State) error { - schemaregistryClient, err := testAccProvider.Meta().(ClientSession).ESschemaRegistrySession() + schemaregistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ESschemaRegistrySession() if err != nil { return err } @@ -209,7 +212,7 @@ func testAccCheckIBMEventStreamsSchemaDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("event_streams_schema still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for event_streams_schema (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for event_streams_schema (%s) has been destroyed: %s", rs.Primary.ID, err) } } @@ -230,3 +233,14 @@ func TestGetSchemaID(t *testing.T) { gotSchemaID := getSchemaID(id) assert.Equal(t, schemaID, gotSchemaID) } + +func getUniqueSchemaID(instanceCRN string, schemaID string) string { + crnSegments := strings.Split(instanceCRN, ":") + crnSegments[8] = "schema" + crnSegments[9] = schemaID + return strings.Join(crnSegments, ":") +} + +func getSchemaID(id string) string { + return strings.Split(id, ":")[9] +} diff --git a/ibm/resource_ibm_event_streams_topic.go b/ibm/service/eventstreams/resource_ibm_event_streams_topic.go similarity index 86% rename from ibm/resource_ibm_event_streams_topic.go rename to ibm/service/eventstreams/resource_ibm_event_streams_topic.go index 8029f4732..9df1bf102 100644 --- a/ibm/resource_ibm_event_streams_topic.go +++ b/ibm/service/eventstreams/resource_ibm_event_streams_topic.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams import ( "fmt" @@ -10,6 +10,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/Shopify/sarama" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -42,7 +44,7 @@ var ( } ) -func resourceIBMEventStreamsTopic() *schema.Resource { +func ResourceIBMEventStreamsTopic() *schema.Resource { return &schema.Resource{ Exists: resourceIBMEventStreamsTopicExists, Create: resourceIBMEventStreamsTopicCreate, @@ -51,7 +53,7 @@ func resourceIBMEventStreamsTopic() *schema.Resource { Delete: resourceIBMEventStreamsTopicDelete, Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "resource_instance_id": &schema.Schema{ + "resource_instance_id": { Type: schema.TypeString, Description: "The CRN of the Event Streams instance", Required: true, @@ -98,10 +100,21 @@ func resourceIBMEventStreamsTopicExists(d *schema.ResourceData, meta interface{} return false, err } topicName := d.Get("name").(string) - topics, err := adminClient.DescribeTopics([]string{topicName}) - if err != nil || len(topics) != 1 { - log.Printf("[DEBUG] resourceIBMEventStreamsTopicExists DescribeTopics err %s", err) - return false, err + topicsMetadata, err := adminClient.DescribeTopics([]string{topicName}) + if err != nil { + descErr := fmt.Errorf("[ERROR] Error describing topic %s : %v", topicName, err) + log.Printf("[DEBUG] resourceIBMEventStreamsTopicExists DescribeTopics err %v", descErr) + return false, descErr + } + if len(topicsMetadata) == 0 { + descErr := fmt.Errorf("no metadata was returned for topic %s", topicName) + log.Printf("[DEBUG] resourceIBMEventStreamsTopicExists DescribeTopics err %v", descErr) + return false, descErr + } + if topicsMetadata[0].Err != sarama.ErrNoError { + metadataErr := topicsMetadata[0].Err + log.Printf("[DEBUG] resourceIBMEventStreamsTopicExists DescribeTopics err %v", metadataErr) + return false, metadataErr } log.Printf("[INFO] resourceIBMEventStreamsTopicExists topic %s exists", topicName) return true, nil @@ -123,7 +136,20 @@ func resourceIBMEventStreamsTopicCreate(d *schema.ResourceData, meta interface{} } err = adminClient.CreateTopic(topicName, &topicDetail, false) if err != nil { - log.Printf("[DEBUG] resourceIBMEventStreamsTopicCreate CreateTopic err %s", err) + if kafkaErr, ok := err.(*sarama.TopicError); ok { + if kafkaErr != nil && kafkaErr.Err == sarama.ErrTopicAlreadyExists { + exists, err := resourceIBMEventStreamsTopicExists(d, meta) + if err != nil { + log.Printf("[DEBUG] resourceIBMEventStreamsTopicCreate resourceIBMEventStreamsTopicExists err %s", err) + return err + } + if exists { + d.SetId(getTopicID(instanceCRN, topicName)) + return resourceIBMEventStreamsTopicRead(d, meta) + } + } + } + log.Printf("[ERROR] resourceIBMEventStreamsTopicCreate CreateTopic err %s", err) return err } log.Printf("[INFO] resourceIBMEventStreamsTopicCreate CreateTopic: topic is %s, detail is %v", topicName, topicDetail) @@ -225,7 +251,7 @@ func resourceIBMEventStreamsTopicDelete(d *schema.ResourceData, meta interface{} } func createSaramaAdminClient(d *schema.ResourceData, meta interface{}) (sarama.ClusterAdmin, string, error) { - bxSession, err := meta.(ClientSession).BluemixSession() + bxSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { log.Printf("[DEBUG] createSaramaAdminClient BluemixSession err %s", err) return nil, "", err @@ -255,7 +281,7 @@ func createSaramaAdminClient(d *schema.ResourceData, meta interface{}) (sarama.C adminURL := instance.Extensions["kafka_http_url"].(string) d.Set("kafka_http_url", adminURL) log.Printf("[INFO] createSaramaAdminClient kafka_http_url is set to %s", adminURL) - brokerAddress := expandStringList(instance.Extensions["kafka_brokers_sasl"].([]interface{})) + brokerAddress := flex.ExpandStringList(instance.Extensions["kafka_brokers_sasl"].([]interface{})) d.Set("kafka_brokers_sasl", brokerAddress) log.Printf("[INFO] createSaramaAdminClient kafka_brokers_sasl is set to %s", brokerAddress) tenantID := strings.TrimPrefix(strings.Split(adminURL, ".")[0], "https://") @@ -284,7 +310,7 @@ func createSaramaAdminClient(d *schema.ResourceData, meta interface{}) (sarama.C func topicDetail2Config(topicConfigEntries map[string]*string) map[string]*string { configs := map[string]*string{} for key, value := range topicConfigEntries { - if indexOf(key, allowedTopicConfigs) != -1 { + if flex.IndexOf(key, allowedTopicConfigs) != -1 { configs[key] = value } } diff --git a/ibm/resource_ibm_event_streams_topic_test.go b/ibm/service/eventstreams/resource_ibm_event_streams_topic_test.go similarity index 92% rename from ibm/resource_ibm_event_streams_topic_test.go rename to ibm/service/eventstreams/resource_ibm_event_streams_topic_test.go index 2849b9710..da48089b2 100644 --- a/ibm/resource_ibm_event_streams_topic_test.go +++ b/ibm/service/eventstreams/resource_ibm_event_streams_topic_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package eventstreams_test import ( "fmt" @@ -11,6 +11,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -31,11 +34,11 @@ func TestAccIBMEventStreamsTopicResourceBasic(t *testing.T) { retentionMs := 3600000 segmentBytes := 10485760 resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicWithoutConfig(instanceName, serviceName, planID, location, topicName, partitions), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -48,7 +51,7 @@ func TestAccIBMEventStreamsTopicResourceBasic(t *testing.T) { resource.TestCheckResourceAttr("ibm_event_streams_topic.es_topic", "partitions", strconv.Itoa(partitions)), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicWithConfig(instanceName, serviceName, planID, location, topicName, partitions, cleanupPolicy, retentionBytes, retentionMs, segmentBytes), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -79,10 +82,10 @@ func TestAccIBMEventStreamsTopicResourceWithExistingInstance(t *testing.T) { retentionMs := 3600000 segmentBytes := 10485760 resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicWithExistingInstanceWithoutConfig(existingInstanceName, topicName, partitions), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -96,7 +99,7 @@ func TestAccIBMEventStreamsTopicResourceWithExistingInstance(t *testing.T) { resource.TestCheckResourceAttr("ibm_event_streams_topic.es_topic", "partitions", strconv.Itoa(partitions)), ), }, - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicWithExistingInstanceWithConfig(existingInstanceName, topicName, partitions, cleanupPolicy, retentionBytes, retentionMs, segmentBytes), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -125,11 +128,11 @@ func TestAccIBMEventStreamsTopicImport(t *testing.T) { topicName := fmt.Sprintf("es_topic_%d", acctest.RandInt()) partitions := 1 resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsTopicWithoutConfig(instanceName, serviceName, planID, location, topicName, partitions), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -137,7 +140,7 @@ func TestAccIBMEventStreamsTopicImport(t *testing.T) { resource.TestCheckResourceAttr("ibm_event_streams_topic.es_topic", "partitions", strconv.Itoa(partitions)), ), }, - resource.TestStep{ + { ResourceName: "ibm_event_streams_topic.es_topic", ImportState: true, ImportStateVerify: true, @@ -161,11 +164,11 @@ func TestAccIBMEventStreamsEnterprise(t *testing.T) { "kms_key_crn": "crn:v1:staging:public:kms:us-south:a/6db1b0d0b5c54ee5c201552547febcd8:0aa69b09-941b-41b2-bbf9-9f9f0f6a6f79:key:dd37a0b6-eff4-4708-8459-e29ae0a8f256", //preprod-byok-customer-key from KMS instance keyprotect-preprod-customer-keys } resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMEventStreamsInstanceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMEventStreamsEnterpriseWithParameters(instanceName, serviceName, planID, location, topicName, partitions, parameters), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEventStreamsTopicExists("ibm_event_streams_topic.es_topic", topicName), @@ -301,7 +304,7 @@ func createEventStreamsTopicResourceWithConfig(createInstance bool, topicName st } func testAccCheckIBMEventStreamsInstanceDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerAPI() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerAPI() if err != nil { return err } @@ -318,7 +321,7 @@ func testAccCheckIBMEventStreamsInstanceDestroy(s *terraform.State) error { } } else { if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } } @@ -334,7 +337,7 @@ func testAccCheckIBMEventStreamsTopicExists(n, topicName string) resource.TestCh } topicID := rs.Primary.ID if topicID == "" { - return fmt.Errorf("No topic ID is set") + return fmt.Errorf("[ERROR] No topic ID is set") } if strings.HasSuffix(topicID, topicName) { return nil @@ -363,3 +366,21 @@ func TestGetTopicName(t *testing.T) { gotTopicName := getTopicName(topicID) assert.Equal(t, mytopicName, gotTopicName) } + +func getTopicID(instanceCRN string, topicName string) string { + crnSegments := strings.Split(instanceCRN, ":") + crnSegments[8] = "topic" + crnSegments[9] = topicName + return strings.Join(crnSegments, ":") +} + +func getTopicName(topicID string) string { + return strings.Split(topicID, ":")[9] +} + +func getInstanceCRN(topicID string) string { + crnSegments := strings.Split(topicID, ":") + crnSegments[8] = "" + crnSegments[9] = "" + return strings.Join(crnSegments, ":") +} diff --git a/ibm/service/functions/README.md b/ibm/service/functions/README.md new file mode 100644 index 000000000..1f71084f3 --- /dev/null +++ b/ibm/service/functions/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Cloud Functions + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Cloud Functions resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/function_action) +* IBM API Docs: [IBM API Docs for Cloud Functions](https://cloud.ibm.com/docs/openwhisk?topic=openwhisk-actions_over) +* IBM Cloud Functions SDK: [IBM SDK for Cloud Functions](https://github.com/apache/openwhisk-client-go/tree/master/whisk) diff --git a/ibm/data_source_ibm_function_action.go b/ibm/service/functions/data_source_ibm_function_action.go similarity index 86% rename from ibm/data_source_ibm_function_action.go rename to ibm/service/functions/data_source_ibm_function_action.go index 1e77a124f..e9bb3f306 100644 --- a/ibm/data_source_ibm_function_action.go +++ b/ibm/service/functions/data_source_ibm_function_action.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions import ( "fmt" "log" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMFunctionAction() *schema.Resource { +func DataSourceIBMFunctionAction() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMFunctionActionRead, @@ -123,17 +125,17 @@ func dataSourceIBMFunctionAction() *schema.Resource { } func dataSourceIBMFunctionActionRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := meta.(ClientSession).BluemixSession() + bxSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -144,7 +146,7 @@ func dataSourceIBMFunctionActionRead(d *schema.ResourceData, meta interface{}) e action, _, err := actionService.Get(name, true) if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Action %s : %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function Action %s : %s", name, err) } temp := strings.Split(action.Namespace, "/") @@ -159,18 +161,18 @@ func dataSourceIBMFunctionActionRead(d *schema.ResourceData, meta interface{}) e } d.Set("namespace", namespace) - d.Set("limits", flattenLimits(action.Limits)) - d.Set("exec", flattenExec(action.Exec, d)) + d.Set("limits", flex.FlattenLimits(action.Limits)) + d.Set("exec", flex.FlattenExec(action.Exec, d)) d.Set("publish", action.Publish) d.Set("version", action.Version) d.Set("action_id", action.Name) - annotations, err := flattenAnnotations(action.Annotations) + annotations, err := flex.FlattenAnnotations(action.Annotations) if err != nil { log.Printf( "An error occured during reading of action (%s) annotations : %s", d.Id(), err) } d.Set("annotations", annotations) - parameters, err := flattenParameters(action.Parameters) + parameters, err := flex.FlattenParameters(action.Parameters) if err != nil { log.Printf( "An error occured during reading of action (%s) parameters : %s", d.Id(), err) diff --git a/ibm/data_source_ibm_function_action_test.go b/ibm/service/functions/data_source_ibm_function_action_test.go similarity index 85% rename from ibm/data_source_ibm_function_action_test.go rename to ibm/service/functions/data_source_ibm_function_action_test.go index 1efd77af1..464cc648a 100644 --- a/ibm/data_source_ibm_function_action_test.go +++ b/ibm/service/functions/data_source_ibm_function_action_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,11 +19,11 @@ func TestAccFunctionActionDataSourceBasic(t *testing.T) { namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckFunctionActionDataSource(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_function_action.pythonzip", "name", name), @@ -43,7 +45,7 @@ func testAccCheckFunctionActionDataSource(name, namespace string) string { exec { kind = "python:3" - code = base64encode("test-fixtures/pythonaction.zip") + code = base64encode("../../test-fixtures/pythonaction.zip") } } diff --git a/ibm/data_source_ibm_function_namespace.go b/ibm/service/functions/data_source_ibm_function_namespace.go similarity index 80% rename from ibm/data_source_ibm_function_namespace.go rename to ibm/service/functions/data_source_ibm_function_namespace.go index 6ffea0ab4..c627bbd8a 100644 --- a/ibm/data_source_ibm_function_namespace.go +++ b/ibm/service/functions/data_source_ibm_function_namespace.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions import ( "fmt" @@ -9,9 +9,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM-Cloud/bluemix-go/api/functions" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func dataSourceIBMFunctionNamespace() *schema.Resource { +func DataSourceIBMFunctionNamespace() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMFunctionNamespaceRead, Schema: map[string]*schema.Schema{ @@ -19,7 +21,7 @@ func dataSourceIBMFunctionNamespace() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Name of namespace.", - ValidateFunc: InvokeValidator("ibm_function_namespace", funcNamespaceName), + ValidateFunc: validate.InvokeValidator("ibm_function_namespace", funcNamespaceName), }, funcNamespaceDesc: { Type: schema.TypeString, @@ -41,7 +43,7 @@ func dataSourceIBMFunctionNamespace() *schema.Resource { } func dataSourceIBMFunctionNamespaceRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } @@ -87,5 +89,5 @@ func dataSourceIBMFunctionNamespaceRead(d *schema.ResourceData, meta interface{} } } - return fmt.Errorf("No cloud function namespace found with name [%s]", name) + return fmt.Errorf("[ERROR] No cloud function namespace found with name [%s]", name) } diff --git a/ibm/data_source_ibm_function_namespace_test.go b/ibm/service/functions/data_source_ibm_function_namespace_test.go similarity index 88% rename from ibm/data_source_ibm_function_namespace_test.go rename to ibm/service/functions/data_source_ibm_function_namespace_test.go index f4b63314f..6ba8e5a38 100644 --- a/ibm/data_source_ibm_function_namespace_test.go +++ b/ibm/service/functions/data_source_ibm_function_namespace_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +18,11 @@ func TestAccFunctionNamespaceDataSourceBasic(t *testing.T) { resourceGroupName := "default" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckFunctionNamespaceDataSource(name, resourceGroupName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_function_namespace.namespace", "name", name), diff --git a/ibm/data_source_ibm_function_package.go b/ibm/service/functions/data_source_ibm_function_package.go similarity index 77% rename from ibm/data_source_ibm_function_package.go rename to ibm/service/functions/data_source_ibm_function_package.go index 9e4c35fa4..ac49ad657 100644 --- a/ibm/data_source_ibm_function_package.go +++ b/ibm/service/functions/data_source_ibm_function_package.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMFunctionPackage() *schema.Resource { +func DataSourceIBMFunctionPackage() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMFunctionPackageRead, @@ -64,17 +66,17 @@ func dataSourceIBMFunctionPackage() *schema.Resource { } func dataSourceIBMFunctionPackageRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := meta.(ClientSession).BluemixSession() + bxSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -84,7 +86,7 @@ func dataSourceIBMFunctionPackageRead(d *schema.ResourceData, meta interface{}) name := d.Get("name").(string) pkg, _, err := packageService.Get(name) if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function package %s : %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function package %s : %s", name, err) } d.SetId(pkg.Name) @@ -93,20 +95,20 @@ func dataSourceIBMFunctionPackageRead(d *schema.ResourceData, meta interface{}) d.Set("publish", pkg.Publish) d.Set("version", pkg.Version) d.Set("package_id", pkg.Name) - annotations, err := flattenAnnotations(pkg.Annotations) + annotations, err := flex.FlattenAnnotations(pkg.Annotations) if err != nil { log.Printf( "An error occured during reading of package (%s) annotations : %s", d.Id(), err) } d.Set("annotations", annotations) - parameters, err := flattenParameters(pkg.Parameters) + parameters, err := flex.FlattenParameters(pkg.Parameters) if err != nil { log.Printf( "An error occured during reading of package (%s) parameters : %s", d.Id(), err) } d.Set("parameters", parameters) - if !isEmpty(*pkg.Binding) { + if !flex.IsEmpty(*pkg.Binding) { d.Set("bind_package_name", fmt.Sprintf("/%s/%s", pkg.Binding.Namespace, pkg.Binding.Name)) } return nil diff --git a/ibm/data_source_ibm_function_package_test.go b/ibm/service/functions/data_source_ibm_function_package_test.go similarity index 89% rename from ibm/data_source_ibm_function_package_test.go rename to ibm/service/functions/data_source_ibm_function_package_test.go index 2492d66ee..39016b1ba 100644 --- a/ibm/data_source_ibm_function_package_test.go +++ b/ibm/service/functions/data_source_ibm_function_package_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +18,11 @@ func TestAccFunctionPackageDataSourceBasic(t *testing.T) { name := fmt.Sprintf("terraform_package_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckFunctionPackageDataSource(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_function_package.package", "name", name), diff --git a/ibm/data_source_ibm_function_rule.go b/ibm/service/functions/data_source_ibm_function_rule.go similarity index 81% rename from ibm/data_source_ibm_function_rule.go rename to ibm/service/functions/data_source_ibm_function_rule.go index f44bf6c94..727f0432e 100644 --- a/ibm/data_source_ibm_function_rule.go +++ b/ibm/service/functions/data_source_ibm_function_rule.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMFunctionRule() *schema.Resource { +func DataSourceIBMFunctionRule() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMFunctionRuleRead, @@ -59,17 +60,17 @@ func dataSourceIBMFunctionRule() *schema.Resource { } func dataSourceIBMFunctionRuleRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := meta.(ClientSession).BluemixSession() + bxSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -80,7 +81,7 @@ func dataSourceIBMFunctionRuleRead(d *schema.ResourceData, meta interface{}) err rule, _, err := ruleService.Get(name) if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Rule %s : %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function Rule %s : %s", name, err) } d.SetId(rule.Name) diff --git a/ibm/data_source_ibm_function_rule_test.go b/ibm/service/functions/data_source_ibm_function_rule_test.go similarity index 91% rename from ibm/data_source_ibm_function_rule_test.go rename to ibm/service/functions/data_source_ibm_function_rule_test.go index f0235dc66..1a71a4c50 100644 --- a/ibm/data_source_ibm_function_rule_test.go +++ b/ibm/service/functions/data_source_ibm_function_rule_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,11 +21,11 @@ func TestAccFunctionRuleDataSourceBasic(t *testing.T) { namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckFunctionRuleDataSource(actionName, triggerName, name, namespace), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_function_rule.rule", "name", name), @@ -46,7 +48,7 @@ func testAccCheckFunctionRuleDataSource(actionName, triggerName, name, namespace namespace = "%s" exec { kind = "nodejs:10" - code = file("test-fixtures/hellonode.js") + code = file("../../test-fixtures/hellonode.js") } } diff --git a/ibm/data_source_ibm_function_trigger.go b/ibm/service/functions/data_source_ibm_function_trigger.go similarity index 76% rename from ibm/data_source_ibm_function_trigger.go rename to ibm/service/functions/data_source_ibm_function_trigger.go index 3cfedcfca..e9876e218 100644 --- a/ibm/data_source_ibm_function_trigger.go +++ b/ibm/service/functions/data_source_ibm_function_trigger.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMFunctionTrigger() *schema.Resource { +func DataSourceIBMFunctionTrigger() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMFunctionTriggerRead, @@ -56,17 +58,17 @@ func dataSourceIBMFunctionTrigger() *schema.Resource { } func dataSourceIBMFunctionTriggerRead(d *schema.ResourceData, meta interface{}) error { - functionNamespaceAPI, err := meta.(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := meta.(ClientSession).BluemixSession() + bxSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } namespace := d.Get("namespace").(string) - wskClient, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -77,7 +79,7 @@ func dataSourceIBMFunctionTriggerRead(d *schema.ResourceData, meta interface{}) trigger, _, err := triggerService.Get(name) if err != nil { - return fmt.Errorf("Error retrieving IBM Cloud Function Trigger %s : %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function Trigger %s : %s", name, err) } d.SetId(trigger.Name) @@ -86,14 +88,14 @@ func dataSourceIBMFunctionTriggerRead(d *schema.ResourceData, meta interface{}) d.Set("publish", trigger.Publish) d.Set("version", trigger.Version) d.Set("trigger_id", trigger.Name) - annotations, err := flattenAnnotations(trigger.Annotations) + annotations, err := flex.FlattenAnnotations(trigger.Annotations) if err != nil { log.Printf( "An error occured during reading of trigger (%s) annotations : %s", d.Id(), err) } d.Set("annotations", annotations) - parameters, err := flattenParameters(trigger.Parameters) + parameters, err := flex.FlattenParameters(trigger.Parameters) if err != nil { log.Printf( "An error occured during reading of trigger (%s) parameters : %s", d.Id(), err) diff --git a/ibm/data_source_ibm_function_trigger_test.go b/ibm/service/functions/data_source_ibm_function_trigger_test.go similarity index 89% rename from ibm/data_source_ibm_function_trigger_test.go rename to ibm/service/functions/data_source_ibm_function_trigger_test.go index eedd663e3..3b23fade9 100644 --- a/ibm/data_source_ibm_function_trigger_test.go +++ b/ibm/service/functions/data_source_ibm_function_trigger_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" "os" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,11 +19,11 @@ func TestAccFunctionTriggerDataSourceBasic(t *testing.T) { namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckFunctionTriggerDataSource(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_function_trigger.trigger", "name", name), diff --git a/ibm/service/functions/qualified_name.go b/ibm/service/functions/qualified_name.go new file mode 100644 index 000000000..105195868 --- /dev/null +++ b/ibm/service/functions/qualified_name.go @@ -0,0 +1,195 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package functions + +import ( + "errors" + "fmt" + "os" + "strings" +) + +type QualifiedName struct { + namespace string // namespace. does not include leading '/'. may be "" (i.e. default namespace) + packageName string // package. may be "". does not include leading/trailing '/' + entity string // entity. should not be "" + EntityName string // pkg+entity +} + +// Imported code from openwhisk cli https://github.com/apache/incubator-openwhisk/tree/26146368f1dd07f817062e662db64c73a8d486d6/tools/cli/go-whisk-cli/commands +/////////////////////////// +// QualifiedName Methods // +/////////////////////////// + +// GetFullQualifiedName() returns a full qualified name in proper string format +// +// from qualifiedName with proper syntax. +// +// Example: /namespace/[package/]entity +func (qualifiedName *QualifiedName) GetFullQualifiedName() string { + output := []string{} + + if len(qualifiedName.GetNamespace()) > 0 { + output = append(output, "/", qualifiedName.GetNamespace(), "/") + } + if len(qualifiedName.GetPackageName()) > 0 { + output = append(output, qualifiedName.GetPackageName(), "/") + } + output = append(output, qualifiedName.GetEntity()) + + return strings.Join(output, "") +} + +// GetPackageName() returns the package name from qualifiedName without a +// +// leading '/' +func (qualifiedName *QualifiedName) GetPackageName() string { + return qualifiedName.packageName +} + +// GetEntityName() returns the entity name ([package/]entity) of qualifiedName +// +// without a leading '/' +func (qualifiedName *QualifiedName) GetEntityName() string { + return qualifiedName.EntityName +} + +// GetEntity() returns the name of entity in qualifiedName without a leading '/' +func (qualifiedName *QualifiedName) GetEntity() string { + return qualifiedName.entity +} + +// GetNamespace() returns the name of the namespace in qualifiedName without +// +// a leading '/' +func (qualifiedName *QualifiedName) GetNamespace() string { + return qualifiedName.namespace +} + +// NewQualifiedName(name) initializes and constructs a (possibly fully qualified) +// +// QualifiedName struct. +// +// NOTE: If the given qualified name is None, then this is a default qualified +// name and it is resolved from properties. +// NOTE: If the namespace is missing from the qualified name, the namespace +// is also resolved from the property file. +// +// Examples: +// +// foo => qualifiedName {namespace: "_", entityName: foo} +// pkg/foo => qualifiedName {namespace: "_", entityName: pkg/foo} +// /ns/foo => qualifiedName {namespace: ns, entityName: foo} +// /ns/pkg/foo => qualifiedName {namespace: ns, entityName: pkg/foo} +func NewQualifiedName(name string) (*QualifiedName, error) { + qualifiedName := new(QualifiedName) + + // If name has a preceding delimiter (/), or if it has two delimiters with a + // leading non-empty string, then it contains a namespace. Otherwise the name + // does not specify a namespace, so default the namespace to the namespace + // value set in the properties file; if that is not set, use "_" + name = addLeadSlash(name) + parts := strings.Split(name, "/") + if strings.HasPrefix(name, "/") { + qualifiedName.namespace = parts[1] + + if len(parts) < 2 || len(parts) > 4 { + return qualifiedName, qualifiedNameNotSpecifiedErr() + } + + for i := 1; i < len(parts); i++ { + if len(parts[i]) == 0 || parts[i] == "." { + return qualifiedName, qualifiedNameNotSpecifiedErr() + } + } + + qualifiedName.EntityName = strings.Join(parts[2:], "/") + if len(parts) == 4 { + qualifiedName.packageName = parts[2] + } + qualifiedName.entity = parts[len(parts)-1] + } else { + if len(name) == 0 || name == "." { + return qualifiedName, qualifiedNameNotSpecifiedErr() + } + + qualifiedName.entity = parts[len(parts)-1] + if len(parts) == 2 { + qualifiedName.packageName = parts[0] + } + qualifiedName.EntityName = name + qualifiedName.namespace = getNamespaceFromProp() + } + + return qualifiedName, nil +} + +///////////////////// +// Error Functions // +///////////////////// + +// qualifiedNameNotSpecifiedErr() returns generic whisk error for +// +// invalid qualified names detected while building a new +// QualifiedName struct. +func qualifiedNameNotSpecifiedErr() error { + return errors.New("[ERROR] valid qualified name must be specified") +} + +// NewQualifiedNameError(entityName, err) returns specific whisk error +// +// for invalid qualified names. +func NewQualifiedNameError(entityName string, err error) error { + errorMsg := fmt.Sprintf("%s is not a alid qualified name %s", entityName, err) + return errors.New(errorMsg) +} + +/////////////////////////// +// Helper/Misc Functions // +/////////////////////////// + +// addLeadSlash(name) returns a (possibly fully qualified) resource name, +// +// inserting a leading '/' if it is of 3 parts (namespace/package/action) +// and lacking the leading '/'. +func addLeadSlash(name string) string { + parts := strings.Split(name, "/") + if len(parts) == 3 && parts[0] != "" { + name = "/" + name + } + return name +} + +// getNamespaceFromProp() returns a namespace from Properties if one exists, +// +// else defaults to returning "_" +func getNamespaceFromProp() string { + namespace := os.Getenv("FUNCTION_NAMESPACE") + return namespace +} + +// getQualifiedName(name, namespace) returns a fully qualified name given a +// +// (possibly fully qualified) resource name and optional namespace. +// +// Examples: +// +// (foo, None) => /_/foo +// (pkg/foo, None) => /_/pkg/foo +// (foo, ns) => /ns/foo +// (/ns/pkg/foo, None) => /ns/pkg/foo +// (/ns/pkg/foo, otherns) => /ns/pkg/foo +func getQualifiedName(name string, namespace string) string { + name = addLeadSlash(name) + if strings.HasPrefix(name, "/") { + return name + } else if strings.HasPrefix(namespace, "/") { + return fmt.Sprintf("%s/%s", namespace, name) + } else { + if len(namespace) == 0 { + namespace = getNamespaceFromProp() + } + return fmt.Sprintf("/%s/%s", namespace, name) + } +} diff --git a/ibm/service/functions/resource_ibm_function_action.go b/ibm/service/functions/resource_ibm_function_action.go new file mode 100644 index 000000000..bba6ee6b0 --- /dev/null +++ b/ibm/service/functions/resource_ibm_function_action.go @@ -0,0 +1,576 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package functions + +import ( + "fmt" + "log" + "net/http" + "os" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/apache/openwhisk-client-go/whisk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + funcActionName = "name" + funcActionNamespace = "namespace" + funcActionUsrDefAnnots = "user_defined_annotations" + funcActionUsrDefParams = "user_defined_parameters" +) + +func ResourceIBMFunctionAction() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMFunctionActionCreate, + Read: resourceIBMFunctionActionRead, + Update: resourceIBMFunctionActionUpdate, + Delete: resourceIBMFunctionActionDelete, + Exists: resourceIBMFunctionActionExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + funcActionName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of action.", + ValidateFunc: validate.InvokeValidator("ibm_function_action", funcActionName), + }, + funcActionNamespace: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "IBM Cloud function namespace.", + ValidateFunc: validate.InvokeValidator("ibm_function_action", funcActionNamespace), + }, + "limits": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "timeout": { + Type: schema.TypeInt, + Optional: true, + Default: 60000, + Description: "The timeout LIMIT in milliseconds after which the action is terminated.", + }, + "memory": { + Type: schema.TypeInt, + Optional: true, + Default: 256, + Description: "The maximum memory LIMIT in MB for the action (default 256.", + }, + "log_size": { + Type: schema.TypeInt, + Optional: true, + Default: 10, + Description: "The maximum log size LIMIT in MB for the action.", + }, + }, + }, + }, + "exec": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Description: "Execution info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "image": { + Type: schema.TypeString, + Optional: true, + Description: "Container image name when kind is 'blackbox'.", + ConflictsWith: []string{"exec.0.components"}, + }, + "init": { + Type: schema.TypeString, + Optional: true, + Description: "Optional zipfile reference.", + ConflictsWith: []string{"exec.0.image", "exec.0.components"}, + }, + "code": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "The code to execute.", + ConflictsWith: []string{"exec.0.components", "exec.0.code_path"}, + }, + "code_path": { + Type: schema.TypeString, + Optional: true, + Description: "The file path of code to execute.", + ConflictsWith: []string{"exec.0.components", "exec.0.code"}, + }, + "kind": { + Type: schema.TypeString, + Required: true, + Description: "The type of action. Possible values can be found here (https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-runtimes)", + }, + "main": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the action entry point (function or fully-qualified method name when applicable).", + ConflictsWith: []string{"exec.0.image", "exec.0.components"}, + }, + "components": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The List of fully qualified action.", + ConflictsWith: []string{"exec.0.image", "exec.0.code", "exec.0.code_path"}, + }, + }, + }, + }, + "publish": { + Type: schema.TypeBool, + Optional: true, + Description: "Action visibilty.", + }, + "version": { + Type: schema.TypeString, + Computed: true, + Description: "Semantic version of the item.", + }, + funcActionUsrDefAnnots: { + Type: schema.TypeString, + Optional: true, + Default: "[]", + Description: "Annotation values in KEY VALUE format.", + ValidateFunc: validate.InvokeValidator("ibm_function_action", funcActionUsrDefAnnots), + DiffSuppressFunc: flex.SuppressEquivalentJSON, + StateFunc: func(v interface{}) string { + json, _ := flex.NormalizeJSONString(v) + return json + }, + }, + funcActionUsrDefParams: { + Type: schema.TypeString, + Optional: true, + Default: "[]", + Description: "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the action.", + ValidateFunc: validate.InvokeValidator("ibm_function_action", funcActionUsrDefParams), + DiffSuppressFunc: flex.SuppressEquivalentJSON, + StateFunc: func(v interface{}) string { + json, _ := flex.NormalizeJSONString(v) + return json + }, + }, + "annotations": { + Type: schema.TypeString, + Computed: true, + Description: "All annotations set on action by user and those set by the IBM Cloud Function backend/API.", + }, + "parameters": { + Type: schema.TypeString, + Computed: true, + Description: "All paramters set on action by user and those set by the IBM Cloud Function backend/API.", + }, + "action_id": { + Type: schema.TypeString, + Computed: true, + }, + "target_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "Action target endpoint URL.", + }, + }, + } +} + +func ResourceIBMFuncActionValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: funcActionName, + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Regexp: `^[^/*][a-zA-Z0-9/_@.-]`, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: funcActionNamespace, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: funcActionUsrDefAnnots, + ValidateFunctionIdentifier: validate.ValidateJSONString, + Type: validate.TypeString, + Default: "[]", + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: funcActionUsrDefParams, + ValidateFunctionIdentifier: validate.ValidateJSONString, + Type: validate.TypeString, + Optional: true}) + + ibmFuncActionResourceValidator := validate.ResourceValidator{ResourceName: "ibm_function_action", Schema: validateSchema} + return &ibmFuncActionResourceValidator +} + +func resourceIBMFunctionActionCreate(d *schema.ResourceData, meta interface{}) error { + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + namespace := d.Get("namespace").(string) + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + actionService := wskClient.Actions + name := d.Get("name").(string) + + var qualifiedName = new(QualifiedName) + + if qualifiedName, err = NewQualifiedName(name); err != nil { + return NewQualifiedNameError(name, err) + } + + payload := whisk.Action{ + Name: qualifiedName.GetEntityName(), + Namespace: namespace, + } + + exec := d.Get("exec").([]interface{}) + payload.Exec = flex.ExpandExec(exec) + + userDefinedAnnotations := d.Get("user_defined_annotations").(string) + payload.Annotations, err = flex.ExpandAnnotations(userDefinedAnnotations) + if err != nil { + return err + } + + userDefinedParameters := d.Get("user_defined_parameters").(string) + payload.Parameters, err = flex.ExpandParameters(userDefinedParameters) + if err != nil { + return err + } + + if v, ok := d.GetOk("limits"); ok { + payload.Limits = flex.ExpandLimits(v.([]interface{})) + } + + if publish, ok := d.GetOk("publish"); ok { + p := publish.(bool) + payload.Publish = &p + } + + log.Println("[INFO] Creating IBM Cloud Function Action") + _, _, err = actionService.Insert(&payload, true) + + if err != nil { + return fmt.Errorf("[ERROR] Error creating IBM Cloud Function Action: %s", err) + } + + d.SetId(fmt.Sprintf("%s:%s", namespace, qualifiedName.GetEntityName())) + + return resourceIBMFunctionActionRead(d, meta) +} + +func resourceIBMFunctionActionRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return err + } + + namespace := "" + actionID := "" + if len(parts) == 2 { + namespace = parts[0] + actionID = parts[1] + } else { + namespace = os.Getenv("FUNCTION_NAMESPACE") + actionID = parts[0] + d.SetId(fmt.Sprintf("%s:%s", namespace, actionID)) + } + + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + actionService := wskClient.Actions + action, _, err := actionService.Get(actionID, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function Action %s : %s", actionID, err) + } + d.Set("namespace", namespace) + d.Set("limits", flex.FlattenLimits(action.Limits)) + d.Set("exec", flex.FlattenExec(action.Exec, d)) + d.Set("publish", action.Publish) + d.Set("version", action.Version) + d.Set("action_id", action.Name) + annotations, err := flex.FlattenAnnotations(action.Annotations) + if err != nil { + return err + } + + d.Set("annotations", annotations) + parameters, err := flex.FlattenParameters(action.Parameters) + if err != nil { + return err + } + d.Set("parameters", parameters) + + temp := strings.Split(action.Namespace, "/") + pkgName := "" + if len(temp) == 2 { + pkgName = temp[1] + d.Set("name", fmt.Sprintf("%s/%s", pkgName, action.Name)) + c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ + Namespace: wskClient.Namespace, + AuthToken: wskClient.AuthToken, + Host: wskClient.Host, + AdditionalHeaders: wskClient.AdditionalHeaders, + }) + if err != nil { + return err + } + pkg, _, err := c.Packages.Get(pkgName) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving package IBM Cloud Function package %s : %s", pkgName, err) + } + + userAnnotations, err := flex.FlattenAnnotations(flex.FilterInheritedAnnotations(pkg.Annotations, action.Annotations)) + if err != nil { + return err + } + + d.Set("user_defined_annotations", userAnnotations) + userParameters, err := flex.FlattenParameters(flex.FilterInheritedParameters(pkg.Parameters, action.Parameters)) + if err != nil { + return err + } + d.Set("user_defined_parameters", userParameters) + } else { + d.Set("name", action.Name) + userDefinedAnnotations, err := flex.FilterActionAnnotations(action.Annotations) + if err != nil { + return err + } + d.Set("user_defined_annotations", userDefinedAnnotations) + + userDefinedParameters, err := flex.FilterActionParameters(action.Parameters) + if err != nil { + return err + } + d.Set("user_defined_parameters", userDefinedParameters) + } + + targetUrl, err := action.ActionURL(wskClient.Config.Host, "/api", wskClient.Config.Version, pkgName) + if err != nil { + log.Printf( + "Error creating target endpoint URL for action (%s) targetURL : %s", d.Id(), err) + + } + d.Set("target_endpoint_url", targetUrl) + + return nil +} + +func resourceIBMFunctionActionUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return err + } + + namespace := parts[0] + actionID := parts[1] + + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + actionService := wskClient.Actions + + var qualifiedName = new(QualifiedName) + + if qualifiedName, err = NewQualifiedName(actionID); err != nil { + return NewQualifiedNameError(actionID, err) + } + + payload := whisk.Action{ + Name: qualifiedName.GetEntityName(), + Namespace: namespace, + } + + ischanged := false + + if d.HasChange("publish") { + p := d.Get("publish").(bool) + payload.Publish = &p + } + + if d.HasChange("user_defined_parameters") { + var err error + payload.Parameters, err = flex.ExpandParameters(d.Get("user_defined_parameters").(string)) + if err != nil { + return err + } + ischanged = true + } + + if d.HasChange("user_defined_annotations") { + var err error + payload.Annotations, err = flex.ExpandAnnotations(d.Get("user_defined_annotations").(string)) + if err != nil { + return err + } + ischanged = true + } + + if d.HasChange("exec") { + exec := d.Get("exec").([]interface{}) + payload.Exec = flex.ExpandExec(exec) + ischanged = true + } + + if d.HasChange("limits") { + limits := d.Get("limits").([]interface{}) + payload.Limits = flex.ExpandLimits(limits) + ischanged = true + } + + if ischanged { + log.Println("[INFO] Update IBM Cloud Function Action") + _, _, err = actionService.Insert(&payload, true) + if err != nil { + return fmt.Errorf("[ERROR] Error updating IBM Cloud Function Action: %s", err) + } + } + + return resourceIBMFunctionActionRead(d, meta) +} + +func resourceIBMFunctionActionDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return err + } + + namespace := parts[0] + actionID := parts[1] + + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + actionService := wskClient.Actions + + _, err = actionService.Delete(actionID) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting IBM Cloud Function Action: %s", err) + } + + d.SetId("") + return nil +} + +func resourceIBMFunctionActionExists(d *schema.ResourceData, meta interface{}) (bool, error) { + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return false, err + } + + namespace := "" + actionID := "" + if len(parts) >= 2 { + namespace = parts[0] + actionID = parts[1] + } else { + namespace = os.Getenv("FUNCTION_NAMESPACE") + actionID = parts[0] + d.SetId(fmt.Sprintf("%s:%s", namespace, actionID)) + } + + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return false, err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return false, err + } + + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return false, err + + } + + actionService := wskClient.Actions + + action, resp, err := actionService.Get(actionID, true) + if err != nil { + if resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error communicating with IBM Cloud Function Client : %s", err) + } + + temp := strings.Split(action.Namespace, "/") + var name string + + if len(temp) == 2 { + name = fmt.Sprintf("%s/%s", temp[1], action.Name) + } else { + name = action.Name + } + + return name == actionID, nil +} diff --git a/ibm/resource_ibm_function_action_test.go b/ibm/service/functions/resource_ibm_function_action_test.go similarity index 89% rename from ibm/resource_ibm_function_action_test.go rename to ibm/service/functions/resource_ibm_function_action_test.go index d92ce46dd..0d33be5a0 100644 --- a/ibm/resource_ibm_function_action_test.go +++ b/ibm/service/functions/resource_ibm_function_action_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" @@ -9,6 +9,10 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/apache/openwhisk-client-go/whisk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,12 +26,12 @@ func TestAccIAMFunctionAction_NodeJS(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionNodeJS(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodehello", &conf), @@ -48,12 +52,12 @@ func TestAccIAMFunctionAction_NodeJSWithParams(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionNodeJSWithParams(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodehellowithparameter", &conf), @@ -74,12 +78,12 @@ func TestAccIAMFunctionAction_NodeJSZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionNodeJSZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodezip", &conf), @@ -100,12 +104,12 @@ func TestAccIAMFunctionAction_Python(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionPython(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.pythonhello", &conf), @@ -126,12 +130,12 @@ func TestAccIAMFunctionAction_PythonZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionPythonZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.pythonzip", &conf), @@ -152,12 +156,12 @@ func TestAccIAMFunctionAction_PHP(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionPHP(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.phphello", &conf), @@ -178,12 +182,12 @@ func TestAccIAMFunctionAction_PHPZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionPHPZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.phpzip", &conf), @@ -204,12 +208,12 @@ func TestAccIAMFunctionAction_Swift(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionSwift(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.swifthello", &conf), @@ -230,12 +234,12 @@ func TestAccIAMFunctionAction_Sequence(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionSequence(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.sequence", &conf), @@ -256,12 +260,12 @@ func TestAccIAMFunctionAction_Basic(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.action", &conf), @@ -275,7 +279,7 @@ func TestAccIAMFunctionAction_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.action", &conf), @@ -297,12 +301,12 @@ func TestAccIAMFunctionAction_Import(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionActionImport(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.import", &conf), @@ -313,7 +317,7 @@ func TestAccIAMFunctionAction_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_function_action.import", ImportState: true, ImportStateVerify: true, @@ -327,12 +331,12 @@ func TestAccCFFunctionAction_NodeJS(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionNodeJS(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodehello", &conf), @@ -353,11 +357,11 @@ func TestAccCFFunctionAction_NodeJSWithParams(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionNodeJSWithParams(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodehellowithparameter", &conf), @@ -378,12 +382,12 @@ func TestAccCFFunctionAction_NodeJSZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionNodeJSZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.nodezip", &conf), @@ -404,12 +408,12 @@ func TestAccCFFunctionAction_Python(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionPython(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.pythonhello", &conf), @@ -430,12 +434,12 @@ func TestAccCFFunctionAction_PythonZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionPythonZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.pythonzip", &conf), @@ -456,12 +460,12 @@ func TestAccCFFunctionAction_PHP(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionPHP(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.phphello", &conf), @@ -482,12 +486,12 @@ func TestAccCFFunctionAction_PHPZip(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionPHPZip(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.phpzip", &conf), @@ -508,12 +512,12 @@ func TestAccCFFunctionAction_Swift(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionSwift(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.swifthello", &conf), @@ -534,12 +538,12 @@ func TestAccCFFunctionAction_Sequence(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionSequence(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.sequence", &conf), @@ -560,12 +564,12 @@ func TestAccCFFunctionAction_Basic(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.action", &conf), @@ -579,7 +583,7 @@ func TestAccCFFunctionAction_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckCFFunctionActionUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.action", &conf), @@ -601,12 +605,12 @@ func TestAccCFFunctionAction_Import(t *testing.T) { name := fmt.Sprintf("terraform_action_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionActionImport(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionActionExists("ibm_function_action.import", &conf), @@ -617,7 +621,7 @@ func TestAccCFFunctionAction_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_function_action.import", ImportState: true, ImportStateVerify: true, @@ -634,24 +638,24 @@ func testAccCheckFunctionActionExists(n string, obj *whisk.Action) resource.Test return fmt.Errorf("Not found: %s", n) } - parts, err := cfIdParts(rs.Primary.ID) + parts, err := flex.CfIdParts(rs.Primary.ID) if err != nil { return err } namespace := parts[0] name := parts[1] - functionNamespaceAPI, err := testAccProvider.Meta().(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := acc.TestAccProvider.Meta().(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := testAccProvider.Meta().(ClientSession).BluemixSession() + bxSession, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } - client, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + client, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -668,12 +672,12 @@ func testAccCheckFunctionActionExists(n string, obj *whisk.Action) resource.Test } func testAccCheckFunctionActionDestroy(s *terraform.State) error { - functionNamespaceAPI, err := testAccProvider.Meta().(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := acc.TestAccProvider.Meta().(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := testAccProvider.Meta().(ClientSession).BluemixSession() + bxSession, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -683,14 +687,14 @@ func testAccCheckFunctionActionDestroy(s *terraform.State) error { continue } - parts, err := cfIdParts(rs.Primary.ID) + parts, err := flex.CfIdParts(rs.Primary.ID) if err != nil { return err } namespace := parts[0] name := parts[1] - client, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + client, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil && strings.Contains(err.Error(), "is not in the list of entitled namespaces") { return nil } @@ -702,7 +706,7 @@ func testAccCheckFunctionActionDestroy(s *terraform.State) error { if err != nil { if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() != 404 { - return fmt.Errorf("Error waiting for IBM Cloud Function Action (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for IBM Cloud Function Action (%s) to be destroyed: %s", rs.Primary.ID, err) } } } @@ -726,7 +730,7 @@ func testAccCheckIAMFunctionActionNodeJS(name, namespace string) string { namespace = ibm_function_namespace.namespace.name exec { kind = "nodejs:10" - code = file("test-fixtures/hellonode.js") + code = file("../../test-fixtures/hellonode.js") } } @@ -752,7 +756,7 @@ func testAccCheckIAMFunctionActionNodeJSWithParams(name, namespace string) strin namespace = ibm_function_namespace.namespace.name exec { kind = "nodejs:10" - code = file("test-fixtures/hellonodewithparameter.js") + code = file("../../test-fixtures/hellonodewithparameter.js") } user_defined_parameters = <= 0 { + d.Set("feed", flex.FlattenFeed(trigger.Annotations.GetValue("feed").(string))) + } + + return nil +} + +func resourceIBMFunctionTriggerUpdate(d *schema.ResourceData, meta interface{}) error { + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return err + } + + namespace := parts[0] + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + triggerService := wskClient.Triggers + + name := d.Get("name").(string) + + var qualifiedName = new(QualifiedName) + + if qualifiedName, err = NewQualifiedName(name); err != nil { + return NewQualifiedNameError(name, err) + } + + payload := whisk.Trigger{ + Name: qualifiedName.GetEntityName(), + Namespace: qualifiedName.GetNamespace(), + } + ischanged := false + + if d.HasChange("user_defined_parameters") { + var err error + payload.Parameters, err = flex.ExpandParameters(d.Get("user_defined_parameters").(string)) + if err != nil { + return err + } + ischanged = true + } + + if d.HasChange("user_defined_annotations") { + var err error + payload.Annotations, err = flex.ExpandAnnotations(d.Get("user_defined_annotations").(string)) + if err != nil { + return err + } + ischanged = true + } + + if ischanged { + log.Println("[INFO] Update IBM Cloud Function Trigger") + + _, _, err = triggerService.Insert(&payload, true) + if err != nil { + return fmt.Errorf("[ERROR] Error updating IBM Cloud Function Trigger: %s", err) + } + } + + return resourceIBMFunctionTriggerRead(d, meta) +} + +func resourceIBMFunctionTriggerDelete(d *schema.ResourceData, meta interface{}) error { + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return err + } + namespace := parts[0] + triggerID := parts[1] + + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return err + + } + + triggerService := wskClient.Triggers + var qualifiedName = new(QualifiedName) + fmt.Println(qualifiedName) + if qualifiedName, err = NewQualifiedName(triggerID); err != nil { + return NewQualifiedNameError(triggerID, err) + } + trigger, _, err := triggerService.Get(triggerID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving IBM Cloud Function Trigger %s : %s", triggerID, err) + } + found := trigger.Annotations.FindKeyValue("feed") + if found >= 0 { + actionName := trigger.Annotations.GetValue("feed").(string) + var feedQualifiedName = new(QualifiedName) + + if feedQualifiedName, err = NewQualifiedName(actionName); err != nil { + return NewQualifiedNameError(actionName, err) + } + + feedPayload := map[string]interface{}{ + feedLifeCycleEvent: feedDelete, + feedAuthKey: wskClient.Config.AuthToken, + feedTriggerName: fmt.Sprintf("/%s/%s", qualifiedName.GetNamespace(), triggerID), + } + + c, err := whisk.NewClient(http.DefaultClient, &whisk.Config{ + AuthToken: wskClient.AuthToken, + Host: wskClient.Host, + AdditionalHeaders: wskClient.AdditionalHeaders, + }) + if err != nil { + return err + } + if feedQualifiedName.GetNamespace() != namespace { + c.Config.Namespace = feedQualifiedName.GetNamespace() + } + + actionService := c.Actions + _, _, err = actionService.Invoke(feedQualifiedName.GetEntityName(), feedPayload, true, true) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting IBM Cloud Function trigger with feed: %s", err) + + } + } + + _, _, err = triggerService.Delete(triggerID) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting IBM Cloud Function Trigger: %s", err) + } + + d.SetId("") + return nil +} + +func resourceIBMFunctionTriggerExists(d *schema.ResourceData, meta interface{}) (bool, error) { + parts, err := flex.CfIdParts(d.Id()) + if err != nil { + return false, err + } + + namespace := "" + triggerID := "" + if len(parts) == 2 { + namespace = parts[0] + triggerID = parts[1] + } else { + namespace = os.Getenv("FUNCTION_NAMESPACE") + triggerID = parts[0] + d.SetId(fmt.Sprintf("%s:%s", namespace, triggerID)) + } + + functionNamespaceAPI, err := meta.(conns.ClientSession).FunctionIAMNamespaceAPI() + if err != nil { + return false, err + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return false, err + } + + wskClient, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + if err != nil { + return false, err + + } + + triggerService := wskClient.Triggers + trigger, resp, err := triggerService.Get(triggerID) + if err != nil { + if resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error communicating with IBM Cloud Function Client : %s", err) + } + return trigger.Name == triggerID, nil +} diff --git a/ibm/resource_ibm_function_trigger_test.go b/ibm/service/functions/resource_ibm_function_trigger_test.go similarity index 91% rename from ibm/resource_ibm_function_trigger_test.go rename to ibm/service/functions/resource_ibm_function_trigger_test.go index 737ad4d1e..f71297f3e 100644 --- a/ibm/resource_ibm_function_trigger_test.go +++ b/ibm/service/functions/resource_ibm_function_trigger_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package functions_test import ( "fmt" @@ -9,6 +9,10 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/apache/openwhisk-client-go/whisk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,12 +26,12 @@ func TestAccIAMFunctionTrigger_Basic(t *testing.T) { name := fmt.Sprintf("terraform_trigger_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionTriggerCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.trigger", &conf), @@ -38,7 +42,7 @@ func TestAccIAMFunctionTrigger_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIAMFunctionTriggerUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.trigger", &conf), @@ -56,12 +60,12 @@ func TestAccIAMFunctionTrigger_Feed_Basic(t *testing.T) { name := fmt.Sprintf("terraform_trigger_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionTriggerFeedCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.feedtrigger", &conf), @@ -73,7 +77,7 @@ func TestAccIAMFunctionTrigger_Feed_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIAMFunctionTriggerFeedUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.feedtrigger", &conf), @@ -92,12 +96,12 @@ func TestAccIAMFunctionTrigger_Import(t *testing.T) { name := fmt.Sprintf("terraform_trigger_%d", acctest.RandIntRange(10, 100)) namespace := fmt.Sprintf("namespace_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIAMFunctionTriggerImport(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.import", &conf), @@ -108,7 +112,7 @@ func TestAccIAMFunctionTrigger_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_function_trigger.import", ImportState: true, ImportStateVerify: true, @@ -123,12 +127,12 @@ func TestAccCFFunctionTrigger_Basic(t *testing.T) { namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionTriggerCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.trigger", &conf), @@ -139,7 +143,7 @@ func TestAccCFFunctionTrigger_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckCFFunctionTriggerUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.trigger", &conf), @@ -157,12 +161,12 @@ func TestAccCFFunctionTrigger_Feed_Basic(t *testing.T) { name := fmt.Sprintf("terraform_trigger_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionTriggerFeedCreate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.feedtrigger", &conf), @@ -174,7 +178,7 @@ func TestAccCFFunctionTrigger_Feed_Basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckCFFunctionTriggerFeedUpdate(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.feedtrigger", &conf), @@ -193,12 +197,12 @@ func TestAccCFFunctionTrigger_Import(t *testing.T) { name := fmt.Sprintf("terraform_trigger_%d", acctest.RandIntRange(10, 100)) namespace := os.Getenv("IBM_FUNCTION_NAMESPACE") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckFunctionTriggerDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckCFFunctionTriggerImport(name, namespace), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckFunctionTriggerExists("ibm_function_trigger.import", &conf), @@ -209,7 +213,7 @@ func TestAccCFFunctionTrigger_Import(t *testing.T) { ), }, - resource.TestStep{ + { ResourceName: "ibm_function_trigger.import", ImportState: true, ImportStateVerify: true, @@ -226,7 +230,7 @@ func testAccCheckFunctionTriggerExists(n string, obj *whisk.Trigger) resource.Te return fmt.Errorf("Not found: %s", n) } - parts, err := cfIdParts(rs.Primary.ID) + parts, err := flex.CfIdParts(rs.Primary.ID) if err != nil { return err } @@ -234,17 +238,17 @@ func testAccCheckFunctionTriggerExists(n string, obj *whisk.Trigger) resource.Te namespace := parts[0] name := parts[1] - functionNamespaceAPI, err := testAccProvider.Meta().(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := acc.TestAccProvider.Meta().(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := testAccProvider.Meta().(ClientSession).BluemixSession() + bxSession, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } - client, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + client, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil { return err @@ -261,12 +265,12 @@ func testAccCheckFunctionTriggerExists(n string, obj *whisk.Trigger) resource.Te } func testAccCheckFunctionTriggerDestroy(s *terraform.State) error { - functionNamespaceAPI, err := testAccProvider.Meta().(ClientSession).FunctionIAMNamespaceAPI() + functionNamespaceAPI, err := acc.TestAccProvider.Meta().(conns.ClientSession).FunctionIAMNamespaceAPI() if err != nil { return err } - bxSession, err := testAccProvider.Meta().(ClientSession).BluemixSession() + bxSession, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { return err } @@ -276,14 +280,14 @@ func testAccCheckFunctionTriggerDestroy(s *terraform.State) error { continue } - parts, err := cfIdParts(rs.Primary.ID) + parts, err := flex.CfIdParts(rs.Primary.ID) if err != nil { return err } namespace := parts[0] name := parts[1] - client, err := setupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) + client, err := conns.SetupOpenWhiskClientConfig(namespace, bxSession, functionNamespaceAPI) if err != nil && strings.Contains(err.Error(), "is not in the list of entitled namespaces") { return nil } @@ -294,7 +298,7 @@ func testAccCheckFunctionTriggerDestroy(s *terraform.State) error { if err != nil { if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() != 404 { - return fmt.Errorf("Error waiting for IBM Cloud Function Trigger (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for IBM Cloud Function Trigger (%s) to be destroyed: %s", rs.Primary.ID, err) } } } diff --git a/ibm/service/globaltagging/README.md b/ibm/service/globaltagging/README.md new file mode 100644 index 000000000..0370bf405 --- /dev/null +++ b/ibm/service/globaltagging/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Global Tagging + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Global tagging resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_tag) +* IBM API Docs: [IBM API Docs for Global tagging](https://cloud.ibm.com/apidocs/tagging) +* IBM Global tagging SDK: [IBM SDK for Global tagging](https://github.com/IBM/platform-services-go-sdk/tree/main/globaltaggingv1) diff --git a/ibm/service/globaltagging/data_source_ibm_resource_tag.go b/ibm/service/globaltagging/data_source_ibm_resource_tag.go new file mode 100644 index 000000000..07f8240e0 --- /dev/null +++ b/ibm/service/globaltagging/data_source_ibm_resource_tag.go @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package globaltagging + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMResourceTag() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMResourceTagRead, + + Schema: map[string]*schema.Schema{ + "resource_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_resource_tag", "resource_id"), + Description: "CRN of the resource on which the tags should be attached", + }, + "tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_resource_tag", tags)}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags associated with resource instance", + }, + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type on which the tags should be fetched", + }, + "tag_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_resource_tag", "tag_type"), + Description: "Tag type on which the tags should be fetched", + Default: "user", + }, + }, + } +} + +func dataSourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error { + var rID, rType string + + if r, ok := d.GetOk("resource_id"); ok && r != nil { + rID = r.(string) + } + if v, ok := d.GetOk(resourceType); ok && v != nil { + rType = v.(string) + } + tType := "" + if t, ok := d.GetOk("tag_type"); ok && t != nil { + tType = t.(string) + } + + tags, err := flex.GetGlobalTagsUsingCRN(meta, rID, rType, tType) + if err != nil { + return fmt.Errorf("[ERROR] Error on get of resource tags (%s) tags: %s", d.Id(), err) + } + + d.SetId(time.Now().UTC().String()) + d.Set("resource_id", rID) + d.Set("resource_type", rType) + d.Set("tags", tags) + d.Set("tag_type", tType) + return nil +} diff --git a/ibm/service/globaltagging/data_source_ibm_resource_tag_test.go b/ibm/service/globaltagging/data_source_ibm_resource_tag_test.go new file mode 100644 index 000000000..bea958263 --- /dev/null +++ b/ibm/service/globaltagging/data_source_ibm_resource_tag_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package globaltagging_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccResourceTagDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + managed_from := "wdc04" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + + { + Config: testAccCheckResourceTagReadDataSource(name, managed_from), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_resource_tag.read_tag", "tags.#", "2"), + ), + }, + }, + }) +} +func TestAccResourceTagDataSourceTagType(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckResourceTagwithTagType(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_resource_tag.access_tags", "id"), + resource.TestCheckResourceAttrSet("data.ibm_resource_tag.tags", "id"), + ), + }, + }, + }) +} +func testAccCheckResourceTagwithTagType() string { + return fmt.Sprintf(` + + data "ibm_resource_tag" "access_tags" { + tag_type ="access" + } + data "ibm_resource_tag" "tags" { + } +`) +} + +func testAccCheckResourceTagReadDataSource(name, managed_from string) string { + return fmt.Sprintf(` + + resource "ibm_satellite_location" "location" { + location = "%s" + managed_from = "%s" + description = "satellite service" + zones = ["us-east-1", "us-east-2", "us-east-3"] + } + + data "ibm_satellite_location" "get_location" { + location = ibm_satellite_location.location.id + } + + resource "ibm_resource_tag" "tag" { + resource_id = data.ibm_satellite_location.get_location.crn + tags = ["env:dev", "cpu:4"] + } + + data "ibm_resource_tag" "read_tag" { + resource_id = ibm_resource_tag.tag.resource_id + } +`, name, managed_from) +} diff --git a/ibm/service/globaltagging/resource_ibm_resource_tag.go b/ibm/service/globaltagging/resource_ibm_resource_tag.go new file mode 100644 index 000000000..c205ed360 --- /dev/null +++ b/ibm/service/globaltagging/resource_ibm_resource_tag.go @@ -0,0 +1,330 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package globaltagging + +import ( + "context" + "fmt" + "os" + "regexp" + "strings" + + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +const ( + resourceID = "resource_id" + tags = "tags" + resourceType = "resource_type" + tagType = "tag_type" + acccountID = "acccount_id" + service = "service" + crnRegex = "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$&'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" +) + +func ResourceIBMResourceTag() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMResourceTagCreate, + Read: resourceIBMResourceTagRead, + Update: resourceIBMResourceTagUpdate, + Delete: resourceIBMResourceTagDelete, + Importer: &schema.ResourceImporter{}, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: map[string]*schema.Schema{ + resourceID: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_resource_tag", resourceID), + Description: "CRN of the resource on which the tags should be attached", + }, + tags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_resource_tag", tags)}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags associated with resource instance", + }, + resourceType: { + Type: schema.TypeString, + Optional: true, + Description: "Resource type on which the tags should be attached", + }, + tagType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_resource_tag", tagType), + Description: "Type of the tag. Only allowed values are: user, or service or access (default value : user)", + }, + acccountID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the account that owns the resources to be tagged (required if tag-type is set to service)", + }, + }, + } +} + +func ResourceIBMResourceTagValidator() *validate.ResourceValidator { + tagTypeAllowedValues := "service,access,user" + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: resourceID, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^crn:v1(:[a-zA-Z0-9 \-\._~\*\+,;=!$&'\(\)\/\?#\[\]@]*){8}$|^[0-9]+$`, + MinValueLength: 1, + MaxValueLength: 1024}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: tags, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tag_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: tagTypeAllowedValues}) + + ibmResourceTagValidator := validate.ResourceValidator{ResourceName: "ibm_resource_tag", Schema: validateSchema} + return &ibmResourceTagValidator +} + +func resourceIBMResourceTagCreate(d *schema.ResourceData, meta interface{}) error { + var rType, tType string + resources := []globaltaggingv1.Resource{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + accountID := userDetails.UserAccount + + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() + if err != nil { + return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + + resourceID := d.Get(resourceID).(string) + if v, ok := d.GetOk(resourceType); ok && v != nil { + rType = v.(string) + } + + r := globaltaggingv1.Resource{ResourceID: flex.PtrToString(resourceID), ResourceType: flex.PtrToString(rType)} + resources = append(resources, r) + + var add []string + if v, ok := d.GetOk(tags); ok { + tags := v.(*schema.Set) + for _, t := range tags.List() { + add = append(add, fmt.Sprint(t)) + } + } + + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + add = append(add, envTags...) + } + + AttachTagOptions := &globaltaggingv1.AttachTagOptions{} + AttachTagOptions.Resources = resources + AttachTagOptions.TagNames = add + if v, ok := d.GetOk(tagType); ok && v != nil { + tType = v.(string) + AttachTagOptions.TagType = flex.PtrToString(tType) + + if tType == service { + AttachTagOptions.AccountID = flex.PtrToString(accountID) + } + } + + if len(add) > 0 { + _, resp, err := gtClient.AttachTag(AttachTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error attaching resource tags : %v\n%s", resp, err) + } + } + + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } + + if crn.MatchString(resourceID) { + d.SetId(resourceID) + } else { + d.SetId(fmt.Sprintf("%s/%s", resourceID, resourceType)) + } + + return resourceIBMResourceTagRead(d, meta) +} + +func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error { + var rID, rType, tType string + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + acctID := userDetails.UserAccount + + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } + + if crn.MatchString(d.Id()) { + rID = d.Id() + } else { + parts, err := flex.VmIdParts(d.Id()) + if err != nil { + return err + } + if len(parts) < 2 { + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of resourceID/resourceType", d.Id()) + } + rID = parts[0] + rType = parts[1] + } + + if v, ok := d.GetOk(tagType); ok && v != nil { + tType = v.(string) + + if tType == service { + d.Set(acccountID, acctID) + } + } + + tagList, err := flex.GetGlobalTagsUsingCRN(meta, rID, resourceType, tType) + if err != nil { + if apierr, ok := err.(bmxerror.RequestFailure); ok && apierr.StatusCode() == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting resource tags for: %s with error : %s", rID, err) + } + + d.Set(resourceID, rID) + d.Set(resourceType, rType) + d.Set(tags, tagList) + + return nil +} + +func resourceIBMResourceTagUpdate(d *schema.ResourceData, meta interface{}) error { + var rID, rType, tType string + + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } + + if crn.MatchString(d.Id()) { + rID = d.Id() + } else { + parts, err := flex.VmIdParts(d.Id()) + if err != nil { + return err + } + rID = parts[0] + rType = parts[1] + } + + if v, ok := d.GetOk(tagType); ok && v != nil { + tType = v.(string) + } + + if _, ok := d.GetOk(tags); ok { + oldList, newList := d.GetChange(tags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, rID, rType, tType) + if err != nil { + return fmt.Errorf("[ERROR] Error on create of resource tags: %s", err) + } + } + + return resourceIBMResourceTagRead(d, meta) +} + +func resourceIBMResourceTagDelete(d *schema.ResourceData, meta interface{}) error { + var rID, rType string + + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } + + if crn.MatchString(d.Id()) { + rID = d.Id() + } else { + parts, err := flex.VmIdParts(d.Id()) + if err != nil { + return err + } + rID = parts[0] + rType = parts[1] + } + + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() + if err != nil { + return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } + + var remove []string + removeTags := d.Get(tags).(*schema.Set) + remove = make([]string, len(removeTags.List())) + for i, v := range removeTags.List() { + remove[i] = fmt.Sprint(v) + } + + if len(remove) > 0 { + resources := []globaltaggingv1.Resource{} + r := globaltaggingv1.Resource{ResourceID: flex.PtrToString(rID), ResourceType: flex.PtrToString(rType)} + resources = append(resources, r) + + detachTagOptions := &globaltaggingv1.DetachTagOptions{ + Resources: resources, + TagNames: remove, + } + + _, resp, err := gtClient.DetachTag(detachTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error detaching resource tags %v: %s\n%s", remove, err, resp) + } + for _, v := range remove { + delTagOptions := &globaltaggingv1.DeleteTagOptions{ + TagName: flex.PtrToString(v), + } + _, resp, err := gtClient.DeleteTag(delTagOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting resource tag %v: %s\n%s", v, err, resp) + } + } + } + return nil +} diff --git a/ibm/resource_ibm_resource_tag_test.go b/ibm/service/globaltagging/resource_ibm_resource_tag_test.go similarity index 81% rename from ibm/resource_ibm_resource_tag_test.go rename to ibm/service/globaltagging/resource_ibm_resource_tag_test.go index 196d4ced4..41a999598 100644 --- a/ibm/resource_ibm_resource_tag_test.go +++ b/ibm/service/globaltagging/resource_ibm_resource_tag_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package globaltagging_test import ( "fmt" @@ -9,6 +9,8 @@ import ( "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,18 +21,18 @@ func TestAccResourceTag_Basic(t *testing.T) { managed_from := "wdc04" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckResourceTagCreate(name, managed_from), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckResourceTagExists("ibm_resource_tag.tag"), resource.TestCheckResourceAttr("ibm_resource_tag.tag", "tags.#", "2"), ), }, - resource.TestStep{ + { ResourceName: "ibm_resource_tag.tag", ImportState: true, ImportStateVerify: true, @@ -46,7 +48,7 @@ func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { if !ok { return fmt.Errorf("Not found: %s", n) } - + crnRegex := "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$&'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" crn, err := regexp.Compile(crnRegex) if err != nil { return err @@ -55,13 +57,13 @@ func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { if crn.MatchString(rs.Primary.ID) { resourceID = rs.Primary.ID } else { - parts, err := vmIdParts(rs.Primary.ID) + parts, err := flex.VmIdParts(rs.Primary.ID) if err != nil { return err } resourceID = parts[0] } - _, err = GetGlobalTagsUsingCRN(testAccProvider.Meta(), resourceID, "", "") + _, err = flex.GetGlobalTagsUsingCRN(acc.TestAccProvider.Meta(), resourceID, "", "") if err != nil { log.Printf( "Error on get of resource tags (%s) : %s", resourceID, err) diff --git a/ibm/service/hpcs/README.md b/ibm/service/hpcs/README.md new file mode 100644 index 000000000..2d89ec995 --- /dev/null +++ b/ibm/service/hpcs/README.md @@ -0,0 +1,10 @@ +# Terraform IBM Provider HPCS + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the HPCS resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/hpcs) +* IBM HPCS TKE SDK: [IBM SDK for HPCS TKE](https://github.com/IBM/ibm-hpcs-tke-sdk) diff --git a/ibm/data_source_ibm_hpcs.go b/ibm/service/hpcs/data_source_ibm_hpcs.go similarity index 94% rename from ibm/data_source_ibm_hpcs.go rename to ibm/service/hpcs/data_source_ibm_hpcs.go index bb8b5930b..db08f58a2 100644 --- a/ibm/data_source_ibm_hpcs.go +++ b/ibm/service/hpcs/data_source_ibm_hpcs.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package hpcs import ( "context" @@ -15,9 +15,11 @@ import ( "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" ) -func dataSourceIBMHPCS() *schema.Resource { +func DataSourceIBMHPCS() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMHPCSRead, @@ -157,7 +159,7 @@ func dataSourceIBMHPCS() *schema.Resource { } func dataSourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - rsConClient, err := meta.(ClientSession).ResourceControllerAPIV2() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() if err != nil { return diag.FromErr(err) } @@ -171,14 +173,14 @@ func dataSourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta if rsGrpID, ok := d.GetOk("resource_group_id"); ok { rsInstQuery.ResourceGroupID = rsGrpID.(string) } else { - defaultRg, err := defaultResourceGroup(meta) + defaultRg, err := flex.DefaultResourceGroup(meta) if err != nil { return diag.FromErr(err) } rsInstQuery.ResourceGroupID = defaultRg } - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() if err != nil { return diag.FromErr(err) } @@ -206,7 +208,7 @@ func dataSourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta if loc, ok := d.GetOk("location"); ok { location = loc.(string) for _, instance := range instances { - if getLocation(instance) == location { + if flex.GetLocation(instance) == location { filteredInstances = append(filteredInstances, instance) } } @@ -240,10 +242,10 @@ func dataSourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta if len(instance.Extensions) == 0 { d.Set("extensions", instance.Extensions) } else { - d.Set("extensions", Flatten(instance.Extensions)) + d.Set("extensions", flex.Flatten(instance.Extensions)) } if instance.Parameters != nil { - instanceParameters := Flatten(instance.Parameters) + instanceParameters := flex.Flatten(instance.Parameters) if endpoint, ok := instanceParameters["allowed_network"]; ok { if endpoint != "private-only" { diff --git a/ibm/service/hpcs/data_source_ibm_hpcs_key_template.go b/ibm/service/hpcs/data_source_ibm_hpcs_key_template.go new file mode 100644 index 000000000..b8860bb4b --- /dev/null +++ b/ibm/service/hpcs/data_source_ibm_hpcs_key_template.go @@ -0,0 +1,309 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func DataSourceIbmKeyTemplate() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIbmKeyTemplateRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "template_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "UUID of the template.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Reference to a vault.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the referenced vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Version of the key template. Every time the key template is updated, the version will be updated automatically.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the key template.", + }, + "key": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Properties describing the properties of the managed key.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The algorithm of the key.", + }, + "activation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key activation date can be provided as a period definition (e.g. PY1 means 1 year).", + }, + "expiration_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Key expiration date can be provided as a period definition (e.g. PY1 means 1 year).", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The state that the key will be in after generation.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of the key template.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key template was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key template was updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key template.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that updated the key.", + }, + "keystores": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Which keystore group to distribute the key to.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of keystore.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + } +} + +func DataSourceIbmKeyTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getKeyTemplateOptions := &ukov4.GetKeyTemplateOptions{} + + region := d.Get("region").(string) + instance_id := d.Get("instance_id").(string) + vault_id := d.Get("uko_vault").(string) + template_id := d.Get("template_id").(string) + getKeyTemplateOptions.SetID(template_id) + getKeyTemplateOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + template, response, err := ukoClient.GetKeyTemplateWithContext(context, getKeyTemplateOptions) + if err != nil { + log.Printf("[DEBUG] GetKeyTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetKeyTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, d.Get("uko_vault").(string), *getKeyTemplateOptions.ID)) + + vault := []map[string]interface{}{} + if template.Vault != nil { + modelMap, err := DataSourceIbmKeyTemplateVaultReferenceToMap(template.Vault) + if err != nil { + return diag.FromErr(err) + } + vault = append(vault, modelMap) + } + if err = d.Set("vault", vault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault %s", err)) + } + + if err = d.Set("version", flex.IntValue(template.Version)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + if err = d.Set("name", template.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + key := []map[string]interface{}{} + if template.Key != nil { + modelMap, err := DataSourceIbmKeyTemplateKeyPropertiesToMap(template.Key) + if err != nil { + return diag.FromErr(err) + } + key = append(key, modelMap) + } + if err = d.Set("key", key); err != nil { + return diag.FromErr(fmt.Errorf("Error setting key %s", err)) + } + + if err = d.Set("description", template.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(template.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(template.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_by", template.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("updated_by", template.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + + keystores := []map[string]interface{}{} + if template.Keystores != nil { + for _, modelItem := range template.Keystores { + modelMap, err := DataSourceIbmKeyTemplateKeystoresPropertiesToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + keystores = append(keystores, modelMap) + } + } + if err = d.Set("keystores", keystores); err != nil { + return diag.FromErr(fmt.Errorf("Error setting keystores %s", err)) + } + + if err = d.Set("href", template.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + return nil +} + +func DataSourceIbmKeyTemplateVaultReferenceToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func DataSourceIbmKeyTemplateKeyPropertiesToMap(model *ukov4.KeyProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Size != nil { + modelMap["size"] = *model.Size + } + if model.Algorithm != nil { + modelMap["algorithm"] = *model.Algorithm + } + if model.ActivationDate != nil { + modelMap["activation_date"] = *model.ActivationDate + } + if model.ExpirationDate != nil { + modelMap["expiration_date"] = *model.ExpirationDate + } + if model.State != nil { + modelMap["state"] = *model.State + } + return modelMap, nil +} + +func DataSourceIbmKeyTemplateKeystoresPropertiesToMap(model *ukov4.KeystoresProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Group != nil { + modelMap["group"] = *model.Group + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + return modelMap, nil +} diff --git a/ibm/service/hpcs/data_source_ibm_hpcs_keystore.go b/ibm/service/hpcs/data_source_ibm_hpcs_keystore.go new file mode 100644 index 000000000..0815fb204 --- /dev/null +++ b/ibm/service/hpcs/data_source_ibm_hpcs_keystore.go @@ -0,0 +1,366 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func DataSourceIbmKeystore() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIbmKeystoreRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "keystore_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "UUID of the keystore.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Reference to a vault.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the referenced vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the target keystore. It can be changed in the future.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of the keystore.", + }, + "groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "List of groups that this keystore belongs to.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of keystore.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the target keystore was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the target keystore was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the key.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + "aws_region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS Region.", + }, + "aws_access_key_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The access key id used for connecting to this instance of AWS KMS.", + }, + "aws_secret_access_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The secret access key used for connecting to this instance of AWS KMS.", + }, + "azure_service_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Service name of the key vault instance from the Azure portal.", + }, + "azure_resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Resource group in Azure.", + }, + "azure_location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Location of the Azure Key Vault.", + }, + "azure_service_principal_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure service principal client ID.", + }, + "azure_service_principal_password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Azure service principal password.", + }, + "azure_tenant": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure tenant that the Key Vault is associated with,.", + }, + "azure_subscription_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID in Azure.", + }, + "azure_environment": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure environment, usually 'Azure'.", + }, + "ibm_api_endpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "API endpoint of the IBM Cloud keystore.", + }, + "ibm_iam_endpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Endpoint of the IAM service for this IBM Cloud keystore.", + }, + "ibm_api_key": &schema.Schema{ // pragma: allowlist secret + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The IBM Cloud API key to be used for connecting to this IBM Cloud keystore.", + }, + "ibm_instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The instance ID of the IBM Cloud keystore.", + }, + "ibm_variant": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Possible IBM Cloud KMS variants.", + }, + "ibm_key_ring": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The key ring of an IBM Cloud KMS Keystore.", + }, + }, + } +} + +func DataSourceIbmKeystoreRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getKeystoreOptions := &ukov4.GetKeystoreOptions{} + + region := d.Get("region").(string) + instance_id := d.Get("instance_id").(string) + vault_id := d.Get("uko_vault").(string) + keystore_id := d.Get("keystore_id").(string) + getKeystoreOptions.SetID(keystore_id) + getKeystoreOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + keystoreIntf, response, err := ukoClient.GetKeystoreWithContext(context, getKeystoreOptions) + keystore := keystoreIntf.(*ukov4.Keystore) + if err != nil { + log.Printf("[DEBUG] GetKeystoreWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetKeystoreWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, vault_id, *getKeystoreOptions.ID)) + + vault := []map[string]interface{}{} + if keystore.Vault != nil { + modelMap, err := DataSourceIbmKeystoreVaultReferenceToMap(keystore.Vault) + if err != nil { + return diag.FromErr(err) + } + vault = append(vault, modelMap) + } + if err = d.Set("vault", vault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault %s", err)) + } + + if err = d.Set("name", keystore.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("description", keystore.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("type", keystore.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(keystore.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(keystore.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_by", keystore.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("updated_by", keystore.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + + if err = d.Set("href", keystore.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("aws_region", keystore.AwsRegion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_region: %s", err)) + } + + if err = d.Set("aws_access_key_id", keystore.AwsAccessKeyID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_access_key_id: %s", err)) + } + + if err = d.Set("aws_secret_access_key", keystore.AwsSecretAccessKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_secret_access_key: %s", err)) + } + + if err = d.Set("azure_service_name", keystore.AzureServiceName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_name: %s", err)) + } + + if err = d.Set("azure_resource_group", keystore.AzureResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_resource_group: %s", err)) + } + + if err = d.Set("azure_location", keystore.AzureLocation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_location: %s", err)) + } + + if err = d.Set("azure_service_principal_client_id", keystore.AzureServicePrincipalClientID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_principal_client_id: %s", err)) + } + + if err = d.Set("azure_service_principal_password", keystore.AzureServicePrincipalPassword); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_principal_password: %s", err)) + } + + if err = d.Set("azure_tenant", keystore.AzureTenant); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_tenant: %s", err)) + } + + if err = d.Set("azure_subscription_id", keystore.AzureSubscriptionID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_subscription_id: %s", err)) + } + + if err = d.Set("azure_environment", keystore.AzureEnvironment); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_environment: %s", err)) + } + + if err = d.Set("ibm_api_endpoint", keystore.IbmApiEndpoint); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_api_endpoint: %s", err)) + } + + if err = d.Set("ibm_iam_endpoint", keystore.IbmIamEndpoint); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_iam_endpoint: %s", err)) + } + + if err = d.Set("ibm_api_key", keystore.IbmApiKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_api_key: %s", err)) // pragma: allowlist secret + } + + if err = d.Set("ibm_instance_id", keystore.IbmInstanceID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_instance_id: %s", err)) + } + + if err = d.Set("ibm_variant", keystore.IbmVariant); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_variant: %s", err)) + } + + if err = d.Set("ibm_key_ring", keystore.IbmKeyRing); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_key_ring: %s", err)) + } + + return nil +} + +func DataSourceIbmKeystoreVaultReferenceToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} diff --git a/ibm/service/hpcs/data_source_ibm_hpcs_managed_key.go b/ibm/service/hpcs/data_source_ibm_hpcs_managed_key.go new file mode 100644 index 000000000..8d0e5937f --- /dev/null +++ b/ibm/service/hpcs/data_source_ibm_hpcs_managed_key.go @@ -0,0 +1,522 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func DataSourceIbmManagedKey() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIbmManagedKeyRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "key_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "UUID of the key.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Reference to a vault.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the referenced vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "template": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Reference to a key template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the key template.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of the managed key.", + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The label of the key.", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The state of the key.", + }, + "size": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The algorithm of the key.", + }, + "verification_patterns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of verification patterns of the key (e.g. public key hash for RSA keys).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The method used for calculating the verification pattern.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The calculated value.", + }, + }, + }, + }, + "activation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "First day when the key is active.", + }, + "expiration_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Last day when the key is active.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Key-value pairs associated with the key.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of a tag.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Value of a tag.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the key.", + }, + "referenced_keystores": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "referenced keystores.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the target keystore.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of keystore.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "instances": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "key instances.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "label_in_keystore": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The label of the key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the key instance.", + }, + "keystore": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Description of properties of a key within the context of keystores.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of keystore.", + }, + }, + }, + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + } +} + +func DataSourceIbmManagedKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getManagedKeyOptions := &ukov4.GetManagedKeyOptions{} + + region := d.Get("region").(string) + instance_id := d.Get("instance_id").(string) + vault_id := d.Get("uko_vault").(string) + key_id := d.Get("key_id").(string) + getManagedKeyOptions.SetID(key_id) + getManagedKeyOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + managedKey, response, err := ukoClient.GetManagedKeyWithContext(context, getManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] GetManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetManagedKeyWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, vault_id, *getManagedKeyOptions.ID)) + + vault := []map[string]interface{}{} + if managedKey.Vault != nil { + modelMap, err := DataSourceIbmManagedKeyVaultReferenceToMap(managedKey.Vault) + if err != nil { + return diag.FromErr(err) + } + vault = append(vault, modelMap) + } + if err = d.Set("vault", vault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault %s", err)) + } + + template := []map[string]interface{}{} + if managedKey.Template != nil { + modelMap, err := DataSourceIbmManagedKeyTemplateReferenceToMap(managedKey.Template) + if err != nil { + return diag.FromErr(err) + } + template = append(template, modelMap) + } + if err = d.Set("template", template); err != nil { + return diag.FromErr(fmt.Errorf("Error setting template %s", err)) + } + + if err = d.Set("description", managedKey.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("label", managedKey.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + + if err = d.Set("state", managedKey.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + if err = d.Set("size", managedKey.Size); err != nil { + return diag.FromErr(fmt.Errorf("Error setting size: %s", err)) + } + + if err = d.Set("algorithm", managedKey.Algorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting algorithm: %s", err)) + } + + verificationPatterns := []map[string]interface{}{} + if managedKey.VerificationPatterns != nil { + for _, modelItem := range managedKey.VerificationPatterns { + modelMap, err := DataSourceIbmManagedKeyKeyVerificationPatternToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + verificationPatterns = append(verificationPatterns, modelMap) + } + } + if err = d.Set("verification_patterns", verificationPatterns); err != nil { + return diag.FromErr(fmt.Errorf("Error setting verification_patterns %s", err)) + } + + if err = d.Set("activation_date", flex.DateToString(managedKey.ActivationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting activation_date: %s", err)) + } + + if err = d.Set("expiration_date", flex.DateToString(managedKey.ExpirationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting expiration_date: %s", err)) + } + + tags := []map[string]interface{}{} + if managedKey.Tags != nil { + for _, modelItem := range managedKey.Tags { + modelMap, err := DataSourceIbmManagedKeyTagToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + tags = append(tags, modelMap) + } + } + if err = d.Set("tags", tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(managedKey.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(managedKey.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_by", managedKey.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("updated_by", managedKey.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + + referencedKeystores := []map[string]interface{}{} + if managedKey.ReferencedKeystores != nil { + for _, modelItem := range managedKey.ReferencedKeystores { + modelMap, err := DataSourceIbmManagedKeyTargetKeystoreReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + referencedKeystores = append(referencedKeystores, modelMap) + } + } + if err = d.Set("referenced_keystores", referencedKeystores); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referenced_keystores %s", err)) + } + + instances := []map[string]interface{}{} + if managedKey.Instances != nil { + for _, modelItem := range managedKey.Instances { + modelMap, err := DataSourceIbmManagedKeyKeyInstanceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + instances = append(instances, modelMap) + } + } + if err = d.Set("instances", instances); err != nil { + return diag.FromErr(fmt.Errorf("Error setting instances %s", err)) + } + + if err = d.Set("href", managedKey.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + return nil +} + +func DataSourceIbmManagedKeyVaultReferenceToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyTemplateReferenceToMap(model *ukov4.TemplateReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyKeyVerificationPatternToMap(model *ukov4.KeyVerificationPattern) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Method != nil { + modelMap["method"] = *model.Method + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyTagToMap(model *ukov4.Tag) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyTargetKeystoreReferenceToMap(model *ukov4.TargetKeystoreReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyKeyInstanceToMap(model *ukov4.KeyInstance) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.LabelInKeystore != nil { + modelMap["label_in_keystore"] = *model.LabelInKeystore + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Keystore != nil { + keystoreMap, err := DataSourceIbmManagedKeyInstanceInKeystoreToMap(model.Keystore) + if err != nil { + return modelMap, err + } + modelMap["keystore"] = []map[string]interface{}{keystoreMap} + } + return modelMap, nil +} + +func DataSourceIbmManagedKeyInstanceInKeystoreToMap(model *ukov4.InstanceInKeystore) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Group != nil { + modelMap["group"] = *model.Group + } + if model.Type != nil { + modelMap["type"] = *model.Type + } + return modelMap, nil +} diff --git a/ibm/data_source_ibm_hpcs_test.go b/ibm/service/hpcs/data_source_ibm_hpcs_test.go similarity index 83% rename from ibm/data_source_ibm_hpcs_test.go rename to ibm/service/hpcs/data_source_ibm_hpcs_test.go index fd976b049..48903528b 100644 --- a/ibm/data_source_ibm_hpcs_test.go +++ b/ibm/service/hpcs/data_source_ibm_hpcs_test.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package hpcs_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMHPCSDatasourceBasic(t *testing.T) { instanceName := "test-hpcs" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMHPCSDatasourceConfig(instanceName), diff --git a/ibm/service/hpcs/data_source_ibm_hpcs_vault.go b/ibm/service/hpcs/data_source_ibm_hpcs_vault.go new file mode 100644 index 000000000..84160fa40 --- /dev/null +++ b/ibm/service/hpcs/data_source_ibm_hpcs_vault.go @@ -0,0 +1,135 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func DataSourceIbmVault() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIbmVaultRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "vault_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "UUID of the vault.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the vault.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Description of the vault.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the vault was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the vault was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the vault.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + } +} + +func DataSourceIbmVaultRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getVaultOptions := &ukov4.GetVaultOptions{} + + region := d.Get("region").(string) + instance_id := d.Get("instance_id").(string) + vault_id := d.Get("vault_id").(string) + + getVaultOptions.SetID(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + vault, response, err := ukoClient.GetVaultWithContext(context, getVaultOptions) + if err != nil { + log.Printf("[DEBUG] GetVaultWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVaultWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, vault_id, *getVaultOptions.ID)) + + if err = d.Set("name", vault.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("description", vault.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(vault.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(vault.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("created_by", vault.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("updated_by", vault.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + + if err = d.Set("href", vault.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + return nil +} diff --git a/ibm/resource_ibm_hpcs.go b/ibm/service/hpcs/resource_ibm_hpcs.go similarity index 86% rename from ibm/resource_ibm_hpcs.go rename to ibm/service/hpcs/resource_ibm_hpcs.go index 2967bf024..2aa544f11 100644 --- a/ibm/resource_ibm_hpcs.go +++ b/ibm/service/hpcs/resource_ibm_hpcs.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package hpcs import ( "bytes" @@ -22,10 +22,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM-Cloud/bluemix-go/models" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcecontroller" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMHPCS() *schema.Resource { +func ResourceIBMHPCS() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMHPCSCreate, ReadContext: resourceIBMHPCSRead, @@ -41,10 +44,10 @@ func resourceIBMHPCS() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return immutableResourceCustomizeDiff([]string{"units", "failover_units", "location", "resource_group_id", "service"}, diff) + return flex.ImmutableResourceCustomizeDiff([]string{"units", "failover_units", "location", "resource_group_id", "service"}, diff) }, func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -91,14 +94,14 @@ func resourceIBMHPCS() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: validateAllowedStringValue([]string{"public-and-private", "private-only"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public-and-private", "private-only"}), }, "tags": { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_hpcs", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_hpcs", "tags")}, + Set: flex.ResourceIBMVPCHash, }, "status": { Type: schema.TypeString, @@ -306,29 +309,30 @@ func resourceIBMHPCS() *schema.Resource { } type HPCSParams struct { - Units int `json:"units,omitempty"` - FailoverUnits int `json:"failover_units,omitempty"` - ServiceEndpoints string `json:"allowed_network,omitempty"` + Units int `json:"units,omitempty"` + FailoverUnits int `json:"failover_units,omitempty"` + RequiresRecoveryUnits bool `json:"requires_recovery_units,omitempty"` + ServiceEndpoints string `json:"allowed_network,omitempty"` } -func resourceIBMHPCSValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMHPCSValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmResourceInstanceResourceValidator := ResourceValidator{ResourceName: "ibm_hpcs", Schema: validateSchema} + ibmResourceInstanceResourceValidator := validate.ResourceValidator{ResourceName: "ibm_hpcs", Schema: validateSchema} return &ibmResourceInstanceResourceValidator } func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return diag.FromErr(err) } @@ -342,7 +346,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta Name: &name, } // Fetch Service Plan ID using Global Catalog APIs - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() if err != nil { return diag.FromErr(err) } @@ -375,7 +379,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta if len(deployments) == 0 { return diag.FromErr(fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan)) } - deployments, supportedLocations := filterDeployments(deployments, location) + deployments, supportedLocations := resourcecontroller.FilterDeployments(deployments, location) if len(deployments) == 0 { locationList := make([]string, 0, len(supportedLocations)) for l := range supportedLocations { @@ -390,7 +394,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta rg := rsGrpID.(string) rsInst.ResourceGroup = &rg } else { - defaultRg, err := defaultResourceGroup(meta) + defaultRg, err := flex.DefaultResourceGroup(meta) if err != nil { return diag.FromErr(err) } @@ -408,6 +412,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta if serviceEndpoint, ok := d.GetOk("service_endpoints"); ok { params.ServiceEndpoints = serviceEndpoint.(string) } + params.RequiresRecoveryUnits = true // Convert HPCSParams srtuct to map parameters, _ := json.Marshal(params) var raw map[string]interface{} @@ -430,7 +435,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk("tags"); ok || v != "" { oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) if err != nil { log.Printf( "[ERROR] Error on create of HPCS instance (%s) tags: %s", d.Id(), err) @@ -440,7 +445,7 @@ func resourceIBMHPCSCreate(context context.Context, d *schema.ResourceData, meta return resourceIBMHPCSUpdate(context, d, meta) } func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return diag.FromErr(err) } @@ -457,7 +462,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i } return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving HPCS instance: %s with resp code: %s", err, resp)) } - if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, rsInstanceReclamation)) { + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, resourcecontroller.RsInstanceReclamation)) { log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") d.SetId("") return nil @@ -475,7 +480,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i d.Set("state", instance.State) d.Set("service", strings.Split(instanceID, ":")[4]) //Set tags - tags, err := GetTagsUsingCRN(meta, *instance.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) if err != nil { log.Printf( "[ERROR] Error on get of HPCS instance tags (%s) tags: %s", d.Id(), err) @@ -489,7 +494,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i } } // Set Service Plan - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() if err != nil { return diag.FromErr(err) } @@ -502,7 +507,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i d.Set("plan", servicePlan) // Set Instance parameters if instance.Parameters != nil { - instanceParameters := Flatten(instance.Parameters) + instanceParameters := flex.Flatten(instance.Parameters) if endpoint, ok := instanceParameters["allowed_network"]; ok { if endpoint != "private-only" { @@ -531,7 +536,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i if len(instance.Extensions) == 0 { d.Set("extensions", instance.Extensions) } else { - d.Set("extensions", Flatten(instance.Extensions)) + d.Set("extensions", flex.Flatten(instance.Extensions)) } d.Set("restored_by", instance.RestoredBy) d.Set("scheduled_reclaim_by", instance.ScheduledReclaimBy) @@ -576,7 +581,7 @@ func resourceIBMHPCSRead(context context.Context, d *schema.ResourceData, meta i } func resourceIBMHPCSUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return diag.FromErr(err) } @@ -594,7 +599,7 @@ func resourceIBMHPCSUpdate(context context.Context, d *schema.ResourceData, meta if d.HasChange("plan") { plan := d.Get("plan").(string) service := d.Get("service").(string) - rsCatClient, err := meta.(ClientSession).ResourceCatalogAPI() + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() if err != nil { return diag.FromErr(err) } @@ -615,7 +620,7 @@ func resourceIBMHPCSUpdate(context context.Context, d *schema.ResourceData, meta } if d.HasChange("service_endpoints") { - params := Params{} + params := HPCSParams{} params.ServiceEndpoints = d.Get("service_endpoints").(string) parameters, _ := json.Marshal(params) var raw map[string]interface{} @@ -631,8 +636,8 @@ func resourceIBMHPCSUpdate(context context.Context, d *schema.ResourceData, meta return diag.FromErr(fmt.Errorf("[ERROR] Error Getting HPCS instance: %s with resp code: %s", err, resp)) } if d.HasChange("tags") { - oldList, newList := d.GetChange(isVPCTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) if err != nil { log.Printf( "[ERROR] Error on update of HPCS instance (%s) tags: %s", d.Id(), err) @@ -712,7 +717,7 @@ func expandHSMConfig(d *schema.ResourceData, meta interface{}) tkesdk.HsmConfig return hsmConfig } func resourceIBMHPCSDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return diag.FromErr(err) } @@ -765,7 +770,7 @@ func resourceIBMHPCSDelete(context context.Context, d *schema.ResourceData, meta return nil } func waitForHPCSInstanceCreate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return false, err } @@ -775,8 +780,8 @@ func waitForHPCSInstanceCreate(d *schema.ResourceData, meta interface{}) (interf } stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus, rsInstanceProvisioningStatus}, - Target: []string{rsInstanceSuccessStatus}, + Pending: []string{resourcecontroller.RsInstanceProgressStatus, resourcecontroller.RsInstanceInactiveStatus, resourcecontroller.RsInstanceProvisioningStatus}, + Target: []string{resourcecontroller.RsInstanceSuccessStatus}, Refresh: func() (interface{}, string, error) { instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) if err != nil { @@ -785,7 +790,7 @@ func waitForHPCSInstanceCreate(d *schema.ResourceData, meta interface{}) (interf } return nil, "", fmt.Errorf("[ERROR] Get on HPCS instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) } - if *instance.State == rsInstanceFailStatus { + if *instance.State == resourcecontroller.RsInstanceFailStatus { return instance, *instance.State, fmt.Errorf("[ERROR] The status of HPCS instance %s failed: %v", d.Id(), err) } return instance, *instance.State, nil @@ -799,7 +804,7 @@ func waitForHPCSInstanceCreate(d *schema.ResourceData, meta interface{}) (interf } func waitForHPCSInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return false, err } @@ -809,8 +814,8 @@ func waitForHPCSInstanceUpdate(d *schema.ResourceData, meta interface{}) (interf } stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus}, - Target: []string{rsInstanceSuccessStatus}, + Pending: []string{resourcecontroller.RsInstanceProgressStatus, resourcecontroller.RsInstanceInactiveStatus}, + Target: []string{resourcecontroller.RsInstanceSuccessStatus}, Refresh: func() (interface{}, string, error) { instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) if err != nil { @@ -819,7 +824,7 @@ func waitForHPCSInstanceUpdate(d *schema.ResourceData, meta interface{}) (interf } return nil, "", fmt.Errorf("[ERROR] Get the HPCS instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) } - if *instance.State == rsInstanceFailStatus { + if *instance.State == resourcecontroller.RsInstanceFailStatus { return instance, *instance.State, fmt.Errorf("[ERROR] The status of HPCS instance %s failed: %v", d.Id(), err) } return instance, *instance.State, nil @@ -833,7 +838,7 @@ func waitForHPCSInstanceUpdate(d *schema.ResourceData, meta interface{}) (interf } func waitForHPCSInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() if err != nil { return false, err } @@ -842,17 +847,17 @@ func waitForHPCSInstanceDelete(d *schema.ResourceData, meta interface{}) (interf ID: &instanceID, } stateConf := &resource.StateChangeConf{ - Pending: []string{rsInstanceProgressStatus, rsInstanceInactiveStatus, rsInstanceSuccessStatus}, - Target: []string{rsInstanceRemovedStatus, rsInstanceReclamation}, + Pending: []string{resourcecontroller.RsInstanceProgressStatus, resourcecontroller.RsInstanceInactiveStatus, resourcecontroller.RsInstanceSuccessStatus}, + Target: []string{resourcecontroller.RsInstanceRemovedStatus, resourcecontroller.RsInstanceReclamation}, Refresh: func() (interface{}, string, error) { instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) if err != nil { if resp != nil && resp.StatusCode == 404 { - return instance, rsInstanceSuccessStatus, nil + return instance, resourcecontroller.RsInstanceSuccessStatus, nil } return nil, "", fmt.Errorf("[ERROR] Get on HPCS instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) } - if *instance.State == rsInstanceFailStatus { + if *instance.State == resourcecontroller.RsInstanceFailStatus { return instance, *instance.State, fmt.Errorf("[ERROR] HPCS instance %s failed to delete: %v", d.Id(), err) } return instance, *instance.State, nil @@ -871,7 +876,7 @@ func resourceIBMHPCSAdminHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", a["key"].(string))) buf.WriteString(fmt.Sprintf("%s-", a["token"].(string))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } func validateHSM(hsmInfo []tkesdk.HsmInfo) bool { update := false @@ -888,11 +893,11 @@ func validateHSM(hsmInfo []tkesdk.HsmInfo) bool { func hsmClient(d *schema.ResourceData, meta interface{}) (tkesdk.CommonInputs, error) { ci := tkesdk.CommonInputs{} // Bluemix Session to get Oauth tokens - bluemixSession, err := meta.(ClientSession).BluemixSession() + bluemixSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return ci, err } - err = refreshToken(bluemixSession) + err = conns.RefreshToken(bluemixSession) if err != nil { return ci, fmt.Errorf("[ERROR] Error Refreshing Authentication Token: %s", err) } @@ -901,9 +906,9 @@ func hsmClient(d *schema.ResourceData, meta interface{}) (tkesdk.CommonInputs, e serviceEndpoint = e.(string) } ci.Region = d.Get("location").(string) - ci.ApiEndpoint = envFallBack([]string{"IBMCLOUD_HPCS_TKE_ENDPOINT"}, "cloud.ibm.com") + ci.ApiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_HPCS_TKE_ENDPOINT"}, "cloud.ibm.com") if bluemixSession.Config.Visibility == "private" || bluemixSession.Config.Visibility == "public-and-private" || serviceEndpoint == "private-only" { - ci.ApiEndpoint = envFallBack([]string{"IBMCLOUD_HPCS_TKE_ENDPOINT"}, "private.cloud.ibm.com") + ci.ApiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_HPCS_TKE_ENDPOINT"}, "private.cloud.ibm.com") } ci.AuthToken = bluemixSession.Config.IAMAccessToken diff --git a/ibm/service/hpcs/resource_ibm_hpcs_key_template.go b/ibm/service/hpcs/resource_ibm_hpcs_key_template.go new file mode 100644 index 000000000..9f56359d1 --- /dev/null +++ b/ibm/service/hpcs/resource_ibm_hpcs_key_template.go @@ -0,0 +1,479 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func ResourceIbmKeyTemplate() *schema.Resource { + return &schema.Resource{ + CreateContext: ResourceIbmKeyTemplateCreate, + ReadContext: ResourceIbmKeyTemplateRead, + UpdateContext: ResourceIbmKeyTemplateUpdate, + DeleteContext: ResourceIbmKeyTemplateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "ID of the Vault where the entity is to be created in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_key_template", "name"), + Description: "Name of the template, it will be referenced when creating managed keys.", + }, + "key": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Properties describing the properties of the managed key.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The algorithm of the key.", + }, + "activation_date": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Key activation date can be provided as a period definition (e.g. PY1 means 1 year).", + }, + "expiration_date": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Key expiration date can be provided as a period definition (e.g. PY1 means 1 year).", + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The state that the key will be in after generation.", + }, + }, + }, + }, + "keystores": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "An array describing the type and group of target keystores the managed key is to be installed in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Which keystore group to distribute the key to.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type of keystore.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_key_template", "description"), + Description: "Description of the key template.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key template was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key template was updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key template.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that updated the key.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + } +} + +func ResourceIbmKeyTemplateValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[A-Za-z][A-Za-z0-9-]*$`, + MinValueLength: 1, + MaxValueLength: 30, + }, + validate.ValidateSchema{ + Identifier: "region", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao", + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `(.|\\n)*`, + MinValueLength: 0, + MaxValueLength: 200, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_hpcs_key_template", Schema: validateSchema} + return &resourceValidator +} + +func ResourceIbmKeyTemplateCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + instance_id := d.Get("instance_id").(string) + region := d.Get("region").(string) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + createKeyTemplateOptions := &ukov4.CreateKeyTemplateOptions{} + + createKeyTemplateOptions.SetUKOVault(d.Get("uko_vault").(string)) + vaultModel, err := ResourceIbmKeyTemplateMapToVaultReferenceInCreationRequest(d.Get("vault.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createKeyTemplateOptions.SetVault(vaultModel) + createKeyTemplateOptions.SetName(d.Get("name").(string)) + keyModel, err := ResourceIbmKeyTemplateMapToKeyProperties(d.Get("key.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createKeyTemplateOptions.SetKey(keyModel) + var keystores []ukov4.KeystoresProperties + for _, e := range d.Get("keystores").([]interface{}) { + value := e.(map[string]interface{}) + keystoresItem, err := ResourceIbmKeyTemplateMapToKeystoresProperties(value) + if err != nil { + return diag.FromErr(err) + } + keystores = append(keystores, *keystoresItem) + } + createKeyTemplateOptions.SetKeystores(keystores) + if _, ok := d.GetOk("description"); ok { + createKeyTemplateOptions.SetDescription(d.Get("description").(string)) + } + + template, response, err := ukoClient.CreateKeyTemplateWithContext(context, createKeyTemplateOptions) + if err != nil { + log.Printf("[DEBUG] CreateKeyTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateKeyTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, d.Get("uko_vault").(string), *template.ID)) + + return ResourceIbmKeyTemplateRead(context, d, meta) +} + +func ResourceIbmKeyTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getKeyTemplateOptions := &ukov4.GetKeyTemplateOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + template_id := id[3] + getKeyTemplateOptions.SetID(template_id) + getKeyTemplateOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + template, response, err := ukoClient.GetKeyTemplateWithContext(context, getKeyTemplateOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetKeyTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetKeyTemplateWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("uko_vault", getKeyTemplateOptions.UKOVault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting uko_vault: %s", err)) + } + vaultMap, err := ResourceIbmKeyTemplateVaultReferenceInCreationRequestToMap(template.Vault) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("vault", []map[string]interface{}{vaultMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault: %s", err)) + } + if err = d.Set("name", template.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + keyMap, err := ResourceIbmKeyTemplateKeyPropertiesToMap(template.Key) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("key", []map[string]interface{}{keyMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting key: %s", err)) + } + keystores := []map[string]interface{}{} + for _, keystoresItem := range template.Keystores { + keystoresItemMap, err := ResourceIbmKeyTemplateKeystoresPropertiesToMap(&keystoresItem) + if err != nil { + return diag.FromErr(err) + } + keystores = append(keystores, keystoresItemMap) + } + if err = d.Set("keystores", keystores); err != nil { + return diag.FromErr(fmt.Errorf("Error setting keystores: %s", err)) + } + if err = d.Set("description", template.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(template.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(template.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_by", template.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("updated_by", template.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + if err = d.Set("href", template.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func ResourceIbmKeyTemplateUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + updateKeyTemplateOptions := &ukov4.UpdateKeyTemplateOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + template_id := id[3] + updateKeyTemplateOptions.SetID(template_id) + updateKeyTemplateOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + hasChange := false + + if d.HasChange("key") || d.HasChange("keystores") { + keyprops, err := ResourceIbmKeyTemplateMapToKeyProperties(d.Get("key.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + var key *ukov4.KeyPropertiesUpdate + key.Size = keyprops.Size + key.ActivationDate = keyprops.ActivationDate + key.ExpirationDate = keyprops.ExpirationDate + key.State = keyprops.State + updateKeyTemplateOptions.SetKey(key) + // TODO: handle Keystores of type TypeList -- not primitive, not model + hasChange = true + } + if d.HasChange("description") { + updateKeyTemplateOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + + // Etag support + updateKeyTemplateOptions.SetIfMatch(d.Get("version").(string)) + + if hasChange { + _, response, err := ukoClient.UpdateKeyTemplateWithContext(context, updateKeyTemplateOptions) + if err != nil { + log.Printf("[DEBUG] UpdateKeyTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateKeyTemplateWithContext failed %s\n%s", err, response)) + } + } + + return ResourceIbmKeyTemplateRead(context, d, meta) +} + +func ResourceIbmKeyTemplateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + deleteKeyTemplateOptions := &ukov4.DeleteKeyTemplateOptions{} + + // Etag support + deleteKeyTemplateOptions.SetIfMatch(d.Get("version").(string)) + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + template_id := id[3] + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + deleteKeyTemplateOptions.SetID(template_id) + deleteKeyTemplateOptions.SetUKOVault(vault_id) + + response, err := ukoClient.DeleteKeyTemplateWithContext(context, deleteKeyTemplateOptions) + if err != nil { + log.Printf("[DEBUG] DeleteKeyTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteKeyTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func ResourceIbmKeyTemplateMapToVaultReferenceInCreationRequest(modelMap map[string]interface{}) (*ukov4.VaultReferenceInCreationRequest, error) { + model := &ukov4.VaultReferenceInCreationRequest{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIbmKeyTemplateMapToKeyProperties(modelMap map[string]interface{}) (*ukov4.KeyProperties, error) { + model := &ukov4.KeyProperties{} + model.Size = core.StringPtr(modelMap["size"].(string)) + model.Algorithm = core.StringPtr(modelMap["algorithm"].(string)) + model.ActivationDate = core.StringPtr(modelMap["activation_date"].(string)) + model.ExpirationDate = core.StringPtr(modelMap["expiration_date"].(string)) + model.State = core.StringPtr(modelMap["state"].(string)) + return model, nil +} + +func ResourceIbmKeyTemplateMapToKeystoresProperties(modelMap map[string]interface{}) (*ukov4.KeystoresProperties, error) { + model := &ukov4.KeystoresProperties{} + model.Group = core.StringPtr(modelMap["group"].(string)) + model.Type = core.StringPtr(modelMap["type"].(string)) + return model, nil +} + +func ResourceIbmKeyTemplateVaultReferenceInCreationRequestToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func ResourceIbmKeyTemplateKeyPropertiesToMap(model *ukov4.KeyProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["size"] = model.Size + modelMap["algorithm"] = model.Algorithm + modelMap["activation_date"] = model.ActivationDate + modelMap["expiration_date"] = model.ExpirationDate + modelMap["state"] = model.State + return modelMap, nil +} + +func ResourceIbmKeyTemplateKeystoresPropertiesToMap(model *ukov4.KeystoresProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["group"] = model.Group + modelMap["type"] = model.Type + return modelMap, nil +} diff --git a/ibm/service/hpcs/resource_ibm_hpcs_keystore.go b/ibm/service/hpcs/resource_ibm_hpcs_keystore.go new file mode 100644 index 000000000..75395c62f --- /dev/null +++ b/ibm/service/hpcs/resource_ibm_hpcs_keystore.go @@ -0,0 +1,1123 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func ResourceIbmKeystore() *schema.Resource { + return &schema.Resource{ + CreateContext: ResourceIbmKeystoreCreate, + ReadContext: ResourceIbmKeystoreRead, + UpdateContext: ResourceIbmKeystoreUpdate, + DeleteContext: ResourceIbmKeystoreDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "aws_region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "AWS Region.", + }, + "aws_access_key_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The access key id used for connecting to this instance of AWS KMS.", + }, + "aws_secret_access_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The secret access key used for connecting to this instance of AWS KMS.", + }, + "azure_service_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Service name of the key vault instance from the Azure portal.", + }, + "azure_resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Resource group in Azure.", + }, + "azure_location": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Location of the Azure Key Vault.", + }, + "azure_service_principal_client_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Azure service principal client ID.", + }, + "azure_service_principal_password": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "Azure service principal password.", + }, + "azure_tenant": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Azure tenant that the Key Vault is associated with,.", + }, + "azure_subscription_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Subscription ID in Azure.", + }, + "azure_environment": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Azure environment, usually 'Azure'.", + }, + "ibm_variant": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Possible IBM Cloud KMS variants.", + }, + "ibm_api_endpoint": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "API endpoint of the IBM Cloud keystore.", + }, + "ibm_iam_endpoint": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Endpoint of the IAM service for this IBM Cloud keystore.", + }, + "ibm_api_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The IBM Cloud API key to be used for connecting to this IBM Cloud keystore.", + }, + "ibm_instance_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The instance ID of the IBM Cloud keystore.", + }, + "ibm_key_ring": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The key ring of an IBM Cloud KMS Keystore.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "Reference to a vault.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Name of the referenced vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Name of the target keystore. It can be changed in the future.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Description of the keystore.", + }, + "groups": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "List of groups that this keystore belongs to.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type of keystore.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the target keystore was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the target keystore was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the key.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIbmKeystoreValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "region", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_hpcs_keystore", Schema: validateSchema} + return &resourceValidator +} + +func ResourceIbmKeystoreCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + instance_id := d.Get("instance_id").(string) + region := d.Get("region").(string) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + createKeystoreOptions := &ukov4.CreateKeystoreOptions{} + + createKeystoreOptions.SetUKOVault(d.Get("uko_vault").(string)) + + // Instead of setting keystore body this way, we need to get every value of d and create a keystore body with those parameters + keystoreBodyModel, err := ResourceIbmKeystoreMapToKeystoreCreationRequest(DKeystoreToKeystoreBody(d).(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createKeystoreOptions.SetKeystoreBody(keystoreBodyModel) + + keystoreIntf, response, err := ukoClient.CreateKeystoreWithContext(context, createKeystoreOptions) + if err != nil { + log.Printf("[DEBUG] CreateKeystoreWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateKeystoreWithContext failed %s\n%s", err, response)) + } + + keystore := keystoreIntf.(*ukov4.Keystore) + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, d.Get("uko_vault").(string), *keystore.ID)) + + return ResourceIbmKeystoreRead(context, d, meta) +} + +func ResourceIbmKeystoreRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getKeystoreOptions := &ukov4.GetKeystoreOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + keystore_id := id[3] + getKeystoreOptions.SetID(keystore_id) + getKeystoreOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + keystoreIntf, response, err := ukoClient.GetKeystoreWithContext(context, getKeystoreOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetKeystoreWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetKeystoreWithContext failed %s\n%s", err, response)) + } + + keystore := keystoreIntf.(*ukov4.Keystore) + if err = d.Set("uko_vault", getKeystoreOptions.UKOVault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting uko_vault: %s", err)) + } + // TODO: handle argument of type KeystoreCreationRequest + if keystore.Vault != nil { + vaultMap, err := ResourceIbmKeystoreVaultReferenceToMap(keystore.Vault) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("vault", []map[string]interface{}{vaultMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault: %s", err)) + } + } + if err = d.Set("name", keystore.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("description", keystore.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if keystore.Groups != nil { + if err = d.Set("groups", keystore.Groups); err != nil { + return diag.FromErr(fmt.Errorf("Error setting groups: %s", err)) + } + } + if err = d.Set("type", keystore.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(keystore.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(keystore.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_by", keystore.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("updated_by", keystore.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + if err = d.Set("href", keystore.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("aws_region", keystore.AwsRegion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_region: %s", err)) + } + if err = d.Set("aws_access_key_id", keystore.AwsAccessKeyID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_access_key_id: %s", err)) + } + if err = d.Set("aws_secret_access_key", keystore.AwsSecretAccessKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting aws_secret_access_key: %s", err)) + } + if err = d.Set("azure_service_name", keystore.AzureServiceName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_name: %s", err)) + } + if err = d.Set("azure_resource_group", keystore.AzureResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_resource_group: %s", err)) + } + if err = d.Set("azure_location", keystore.AzureLocation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_location: %s", err)) + } + if err = d.Set("azure_service_principal_client_id", keystore.AzureServicePrincipalClientID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_principal_client_id: %s", err)) + } + if err = d.Set("azure_service_principal_password", keystore.AzureServicePrincipalPassword); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_service_principal_password: %s", err)) + } + if err = d.Set("azure_tenant", keystore.AzureTenant); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_tenant: %s", err)) + } + if err = d.Set("azure_subscription_id", keystore.AzureSubscriptionID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_subscription_id: %s", err)) + } + if err = d.Set("azure_environment", keystore.AzureEnvironment); err != nil { + return diag.FromErr(fmt.Errorf("Error setting azure_environment: %s", err)) + } + if err = d.Set("ibm_api_endpoint", keystore.IbmApiEndpoint); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_api_endpoint: %s", err)) + } + if err = d.Set("ibm_iam_endpoint", keystore.IbmIamEndpoint); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_iam_endpoint: %s", err)) + } + if err = d.Set("ibm_api_key", keystore.IbmApiKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_api_key: %s", err)) // pragma: allowlist secret + } + if err = d.Set("ibm_instance_id", keystore.IbmInstanceID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_instance_id: %s", err)) + } + if err = d.Set("ibm_variant", keystore.IbmVariant); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_variant: %s", err)) + } + if err = d.Set("ibm_key_ring", keystore.IbmKeyRing); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ibm_key_ring: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func ResourceIbmKeystoreUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + updateKeystoreOptions := &ukov4.UpdateKeystoreOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + keystore_id := id[3] + updateKeystoreOptions.SetID(keystore_id) + updateKeystoreOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + hasChange := false + + // if d.HasChange() for every parameter, then again, create a keystore body out of the new parameters + + if d.HasChange("uko_vault") || DHasChanges(d) { + updateKeystoreOptions.SetUKOVault(d.Get("uko_vault").(string)) + keystoreBody := ukov4.KeystoreUpdateRequestIntf(DKeystoreToKeystoreBodyUpdate(d)) + updateKeystoreOptions.SetKeystoreBody(keystoreBody) + hasChange = true + } + + updateKeystoreOptions.SetIfMatch(d.Get("version").(string)) + + if hasChange { + _, response, err := ukoClient.UpdateKeystoreWithContext(context, updateKeystoreOptions) + if err != nil { + log.Printf("[DEBUG] UpdateKeystoreWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateKeystoreWithContext failed %s\n%s", err, response)) + } + } + + return ResourceIbmKeystoreRead(context, d, meta) +} + +func ResourceIbmKeystoreDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + deleteKeystoreOptions := &ukov4.DeleteKeystoreOptions{} + + // Etag support + deleteKeystoreOptions.SetIfMatch(d.Get("version").(string)) + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + keystore_id := id[3] + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + deleteKeystoreOptions.SetID(keystore_id) + deleteKeystoreOptions.SetUKOVault(vault_id) + + response, err := ukoClient.DeleteKeystoreWithContext(context, deleteKeystoreOptions) + if err != nil { + log.Printf("[DEBUG] DeleteKeystoreWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteKeystoreWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequest(modelMap map[string]interface{}) (ukov4.KeystoreCreationRequestIntf, error) { + discValue, ok := modelMap["type"] + if ok { + if discValue == "aws_kms" { + return ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeAwsKmsCreate(modelMap) + } else if discValue == "azure_key_vault" { + return ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeAzureCreate(modelMap) + } else if discValue == "ibm_cloud_kms" { + return ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate(modelMap) + } else { + return nil, fmt.Errorf("unexpected value for discriminator property 'type' found in map: '%s'", discValue) + } + } else { + return nil, fmt.Errorf("discriminator property 'type' not found in map") + } +} + +func ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap map[string]interface{}) (*ukov4.VaultReferenceInCreationRequest, error) { + model := &ukov4.VaultReferenceInCreationRequest{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeAwsKmsCreate(modelMap map[string]interface{}) (*ukov4.KeystoreCreationRequestKeystoreTypeAwsKmsCreate, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeAwsKmsCreate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + model.Name = core.StringPtr(modelMap["name"].(string)) + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + model.AwsRegion = core.StringPtr(modelMap["aws_region"].(string)) + model.AwsAccessKeyID = core.StringPtr(modelMap["aws_access_key_id"].(string)) + model.AwsSecretAccessKey = core.StringPtr(modelMap["aws_secret_access_key"].(string)) + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate(modelMap map[string]interface{}) (ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateIntf, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + model.IbmVariant = core.StringPtr(modelMap["ibm_variant"].(string)) + if modelMap["name"] != nil { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + if modelMap["ibm_api_endpoint"] != nil { + model.IbmApiEndpoint = core.StringPtr(modelMap["ibm_api_endpoint"].(string)) + } + if modelMap["ibm_iam_endpoint"] != nil { + model.IbmIamEndpoint = core.StringPtr(modelMap["ibm_iam_endpoint"].(string)) + } + if modelMap["ibm_api_key"] != nil { + model.IbmApiKey = core.StringPtr(modelMap["ibm_api_key"].(string)) + } + if modelMap["ibm_instance_id"] != nil { + model.IbmInstanceID = core.StringPtr(modelMap["ibm_instance_id"].(string)) + } + if modelMap["ibm_key_ring"] != nil { + model.IbmKeyRing = core.StringPtr(modelMap["ibm_key_ring"].(string)) + } + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate(modelMap map[string]interface{}) (*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + model.Name = core.StringPtr(modelMap["name"].(string)) + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + model.IbmApiEndpoint = core.StringPtr(modelMap["ibm_api_endpoint"].(string)) + model.IbmIamEndpoint = core.StringPtr(modelMap["ibm_iam_endpoint"].(string)) + model.IbmApiKey = core.StringPtr(modelMap["ibm_api_key"].(string)) + model.IbmInstanceID = core.StringPtr(modelMap["ibm_instance_id"].(string)) + model.IbmVariant = core.StringPtr(modelMap["ibm_variant"].(string)) + if modelMap["ibm_key_ring"] != nil { + model.IbmKeyRing = core.StringPtr(modelMap["ibm_key_ring"].(string)) + } + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate(modelMap map[string]interface{}) (ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateIntf, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + model.IbmVariant = core.StringPtr(modelMap["ibm_variant"].(string)) + model.Name = core.StringPtr(modelMap["name"].(string)) + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate(modelMap map[string]interface{}) (*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + model.IbmVariant = core.StringPtr(modelMap["ibm_variant"].(string)) + if modelMap["name"] != nil { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + return model, nil +} + +func ResourceIbmKeystoreMapToKeystoreCreationRequestKeystoreTypeAzureCreate(modelMap map[string]interface{}) (*ukov4.KeystoreCreationRequestKeystoreTypeAzureCreate, error) { + model := &ukov4.KeystoreCreationRequestKeystoreTypeAzureCreate{} + model.Type = core.StringPtr(modelMap["type"].(string)) + VaultModel, err := ResourceIbmKeystoreMapToVaultReferenceInCreationRequest(modelMap["vault"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Vault = VaultModel + if modelMap["name"] != nil { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["groups"] != nil { + groups := []string{} + for _, groupsItem := range modelMap["groups"].([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + model.Groups = groups + } + model.AzureServiceName = core.StringPtr(modelMap["azure_service_name"].(string)) + model.AzureResourceGroup = core.StringPtr(modelMap["azure_resource_group"].(string)) + model.AzureLocation = core.StringPtr(modelMap["azure_location"].(string)) + model.AzureServicePrincipalClientID = core.StringPtr(modelMap["azure_service_principal_client_id"].(string)) + model.AzureServicePrincipalPassword = core.StringPtr(modelMap["azure_service_principal_password"].(string)) + model.AzureTenant = core.StringPtr(modelMap["azure_tenant"].(string)) + model.AzureSubscriptionID = core.StringPtr(modelMap["azure_subscription_id"].(string)) + model.AzureEnvironment = core.StringPtr(modelMap["azure_environment"].(string)) + return model, nil +} + +func ResourceIbmKeystoreKeystoreCreationRequestToMap(model ukov4.KeystoreCreationRequestIntf) (map[string]interface{}, error) { + if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeAwsKmsCreate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeAwsKmsCreateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeAwsKmsCreate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeAzureCreate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeAzureCreateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeAzureCreate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequest); ok { + modelMap := make(map[string]interface{}) + model := model.(*ukov4.KeystoreCreationRequest) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + if model.AwsRegion != nil { + modelMap["aws_region"] = model.AwsRegion + } + if model.AwsAccessKeyID != nil { + modelMap["aws_access_key_id"] = model.AwsAccessKeyID + } + if model.AwsSecretAccessKey != nil { + modelMap["aws_secret_access_key"] = model.AwsSecretAccessKey + } + if model.AzureServiceName != nil { + modelMap["azure_service_name"] = model.AzureServiceName + } + if model.AzureResourceGroup != nil { + modelMap["azure_resource_group"] = model.AzureResourceGroup + } + if model.AzureLocation != nil { + modelMap["azure_location"] = model.AzureLocation + } + if model.AzureServicePrincipalClientID != nil { + modelMap["azure_service_principal_client_id"] = model.AzureServicePrincipalClientID + } + if model.AzureServicePrincipalPassword != nil { + modelMap["azure_service_principal_password"] = model.AzureServicePrincipalPassword + } + if model.AzureTenant != nil { + modelMap["azure_tenant"] = model.AzureTenant + } + if model.AzureSubscriptionID != nil { + modelMap["azure_subscription_id"] = model.AzureSubscriptionID + } + if model.AzureEnvironment != nil { + modelMap["azure_environment"] = model.AzureEnvironment + } + if model.IbmVariant != nil { + modelMap["ibm_variant"] = model.IbmVariant + } + if model.IbmApiEndpoint != nil { + modelMap["ibm_api_endpoint"] = model.IbmApiEndpoint + } + if model.IbmIamEndpoint != nil { + modelMap["ibm_iam_endpoint"] = model.IbmIamEndpoint + } + if model.IbmApiKey != nil { + modelMap["ibm_api_key"] = model.IbmApiKey + } + if model.IbmInstanceID != nil { + modelMap["ibm_instance_id"] = model.IbmInstanceID + } + if model.IbmKeyRing != nil { + modelMap["ibm_key_ring"] = model.IbmKeyRing + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized ukov4.KeystoreCreationRequestIntf subtype encountered") + } +} + +func ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model *ukov4.VaultReferenceInCreationRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeAwsKmsCreateToMap(model *ukov4.KeystoreCreationRequestKeystoreTypeAwsKmsCreate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + modelMap["name"] = model.Name + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + modelMap["aws_region"] = model.AwsRegion + modelMap["aws_access_key_id"] = model.AwsAccessKeyID + modelMap["aws_secret_access_key"] = model.AwsSecretAccessKey // pragma: allowlist secret + return modelMap, nil +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateToMap(model ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateIntf) (map[string]interface{}, error) { + if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate); ok { + modelMap := make(map[string]interface{}) + model := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreate) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + modelMap["ibm_variant"] = model.IbmVariant + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + if model.IbmApiEndpoint != nil { + modelMap["ibm_api_endpoint"] = model.IbmApiEndpoint + } + if model.IbmIamEndpoint != nil { + modelMap["ibm_iam_endpoint"] = model.IbmIamEndpoint + } + if model.IbmApiKey != nil { + modelMap["ibm_api_key"] = model.IbmApiKey + } + if model.IbmInstanceID != nil { + modelMap["ibm_instance_id"] = model.IbmInstanceID + } + if model.IbmKeyRing != nil { + modelMap["ibm_key_ring"] = model.IbmKeyRing + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateIntf subtype encountered") + } +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreateToMap(model *ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsCreate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + modelMap["name"] = model.Name + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + modelMap["ibm_api_endpoint"] = model.IbmApiEndpoint + modelMap["ibm_iam_endpoint"] = model.IbmIamEndpoint + modelMap["ibm_api_key"] = model.IbmApiKey // pragma: allowlist secret + modelMap["ibm_instance_id"] = model.IbmInstanceID + modelMap["ibm_variant"] = model.IbmVariant + if model.IbmKeyRing != nil { + modelMap["ibm_key_ring"] = model.IbmKeyRing + } + return modelMap, nil +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateToMap(model ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateIntf) (map[string]interface{}, error) { + if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate); ok { + return ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdateToMap(model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate)) + } else if _, ok := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate); ok { + modelMap := make(map[string]interface{}) + model := model.(*ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreate) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + modelMap["ibm_variant"] = model.IbmVariant + modelMap["name"] = model.Name + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateIntf subtype encountered") + } +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdateToMap(model *ukov4.KeystoreCreationRequestKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalExternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalCreateKeystoreTypeIbmCloudKmsInternalUpdateKeystoreTypeBaseUpdate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + modelMap["ibm_variant"] = model.IbmVariant + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + return modelMap, nil +} + +func ResourceIbmKeystoreKeystoreCreationRequestKeystoreTypeAzureCreateToMap(model *ukov4.KeystoreCreationRequestKeystoreTypeAzureCreate) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + vaultMap, err := ResourceIbmKeystoreVaultReferenceInCreationRequestToMap(model.Vault) + if err != nil { + return modelMap, err + } + modelMap["vault"] = []map[string]interface{}{vaultMap} + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Groups != nil { + modelMap["groups"] = model.Groups + } + modelMap["azure_service_name"] = model.AzureServiceName + modelMap["azure_resource_group"] = model.AzureResourceGroup + modelMap["azure_location"] = model.AzureLocation + modelMap["azure_service_principal_client_id"] = model.AzureServicePrincipalClientID + modelMap["azure_service_principal_password"] = model.AzureServicePrincipalPassword // pragma: allowlist secret + modelMap["azure_tenant"] = model.AzureTenant + modelMap["azure_subscription_id"] = model.AzureSubscriptionID + modelMap["azure_environment"] = model.AzureEnvironment + return modelMap, nil +} + +func ResourceIbmKeystoreVaultReferenceToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func DKeystoreToKeystoreBody(d *schema.ResourceData) interface{} { + keystoreBody := make(map[string]interface{}) + keystoreType := d.Get("type").(string) + + keystoreBody["type"] = keystoreType + keystoreBody["name"] = d.Get("name").(string) + keystoreBody["vault"] = d.Get("vault").([]interface{}) + keystoreBody["description"] = d.Get("description").(string) + keystoreBody["groups"] = d.Get("groups").([]interface{}) + if keystoreType == "aws_kms" { + keystoreBody["aws_region"] = d.Get("aws_region").(string) + keystoreBody["aws_access_key_id"] = d.Get("aws_access_key_id").(string) + keystoreBody["aws_secret_access_key"] = d.Get("aws_secret_access_key").(string) + } else if keystoreType == "azure_key_vault" { + keystoreBody["azure_service_name"] = d.Get("azure_service_name").(string) + keystoreBody["azure_resource_group"] = d.Get("azure_resource_group").(string) + keystoreBody["azure_location"] = d.Get("azure_location").(string) + keystoreBody["azure_service_principal_client_id"] = d.Get("azure_service_principal_client_id").(string) + keystoreBody["azure_service_principal_password"] = d.Get("azure_service_principal_password").(string) + keystoreBody["azure_tenant"] = d.Get("azure_tenant").(string) + keystoreBody["azure_subscription_id"] = d.Get("azure_subscription_id").(string) + keystoreBody["azure_environment"] = d.Get("azure_environment").(string) + } else if keystoreType == "ibm_cloud_kms" { + ibm_variant := d.Get("ibm_variant").(string) + keystoreBody["ibm_variant"] = ibm_variant + if ibm_variant != "internal" { + keystoreBody["ibm_api_endpoint"] = d.Get("ibm_api_endpoint").(string) + keystoreBody["ibm_iam_endpoint"] = d.Get("ibm_iam_endpoint").(string) + keystoreBody["ibm_api_key"] = d.Get("ibm_api_key").(string) + keystoreBody["ibm_instance_id"] = d.Get("ibm_instance_id").(string) + keystoreBody["ibm_key_ring"] = d.Get("ibm_key_ring").(string) + } + } + + return keystoreBody +} + +func DKeystoreToKeystoreBodyUpdate(d *schema.ResourceData) *ukov4.KeystoreUpdateRequest { + var keystoreBody ukov4.KeystoreUpdateRequest + + if d.Get("name") != nil && d.Get("name") != "" { + keystoreBody.Name = core.StringPtr(d.Get("name").(string)) + } + if d.Get("description") != nil && d.Get("description") != "" { + keystoreBody.Description = core.StringPtr(d.Get("description").(string)) + } + if d.Get("groups") != nil { + groups := []string{} + for _, groupsItem := range d.Get("groups").([]interface{}) { + groups = append(groups, groupsItem.(string)) + } + keystoreBody.Groups = groups + } + if d.Get("aws_region") != nil && d.Get("aws_region") != "" { + keystoreBody.AwsRegion = core.StringPtr(d.Get("aws_region").(string)) + } + if d.Get("aws_access_key_id") != nil && d.Get("aws_access_key_id") != "" { + keystoreBody.AwsAccessKeyID = core.StringPtr(d.Get("aws_access_key_id").(string)) + } + if d.Get("aws_secret_access_key") != nil && d.Get("aws_secret_access_key") != "" { + keystoreBody.AwsSecretAccessKey = core.StringPtr(d.Get("aws_secret_access_key").(string)) + } + if d.Get("azure_service_name") != nil && d.Get("azure_service_name") != "" { + keystoreBody.AzureServiceName = core.StringPtr(d.Get("azure_service_name").(string)) + } + if d.Get("azure_resource_group") != nil && d.Get("azure_resource_group") != "" { + keystoreBody.AzureResourceGroup = core.StringPtr(d.Get("azure_resource_group").(string)) + } + if d.Get("azure_location") != nil && d.Get("azure_location") != "" { + keystoreBody.AzureLocation = core.StringPtr(d.Get("azure_location").(string)) + } + if d.Get("azure_service_principal_client_id") != nil && d.Get("azure_service_principal_client_id") != "" { + keystoreBody.AzureServicePrincipalClientID = core.StringPtr(d.Get("azure_service_principal_client_id").(string)) + } + if d.Get("azure_service_principal_password") != nil && d.Get("azure_service_principal_password") != "" { + keystoreBody.AzureServicePrincipalPassword = core.StringPtr(d.Get("azure_service_principal_password").(string)) + } + if d.Get("azure_tenant") != nil && d.Get("azure_tenant") != "" { + keystoreBody.AzureTenant = core.StringPtr(d.Get("azure_tenant").(string)) + } + if d.Get("azure_subscription_id") != nil && d.Get("azure_subscription_id") != "" { + keystoreBody.AzureSubscriptionID = core.StringPtr(d.Get("azure_subscription_id").(string)) + } + if d.Get("azure_environment") != nil && d.Get("azure_environment") != "" { + keystoreBody.AzureEnvironment = core.StringPtr(d.Get("azure_environment").(string)) + } + if d.Get("ibm_api_endpoint") != nil && d.Get("ibm_api_endpoint") != "" { + keystoreBody.IbmApiEndpoint = core.StringPtr(d.Get("ibm_api_endpoint").(string)) + } + if d.Get("ibm_iam_endpoint") != nil && d.Get("ibm_iam_endpoint") != "" { + keystoreBody.IbmIamEndpoint = core.StringPtr(d.Get("ibm_iam_endpoint").(string)) + } + if d.Get("ibm_api_key") != nil && d.Get("ibm_api_key") != "" { + keystoreBody.IbmApiKey = core.StringPtr(d.Get("ibm_api_key").(string)) + } + if d.Get("ibm_instance_id") != nil && d.Get("ibm_instance_id") != "" { + keystoreBody.IbmInstanceID = core.StringPtr(d.Get("ibm_instance_id").(string)) + } + if d.Get("ibm_key_ring") != nil && d.Get("ibm_key_ring") != "" { + keystoreBody.IbmKeyRing = core.StringPtr(d.Get("ibm_key_ring").(string)) + } + + return &keystoreBody +} + +func DHasChanges(d *schema.ResourceData) bool { + if d.HasChange("type") { + return true + } + if d.HasChange("vault") { + return true + } + if d.HasChange("description") { + return true + } + if d.HasChange("groups") { + return true + } + if d.HasChange("aws_region") { + return true + } + if d.HasChange("aws_access_key_id") { + return true + } + if d.HasChange("aws_secret_access_key") { + return true + } + if d.HasChange("azure_service_name") { + return true + } + if d.HasChange("azure_resource_group") { + return true + } + if d.HasChange("azure_location") { + return true + } + if d.HasChange("azure_service_principal_client_id") { + return true + } + if d.HasChange("azure_service_principal_password") { + return true + } + if d.HasChange("azure_tenant") { + return true + } + if d.HasChange("azure_subscription_id") { + return true + } + if d.HasChange("azure_environment") { + return true + } + if d.HasChange("ibm_variant") { + return true + } + if d.HasChange("ibm_api_endpoint") { + return true + } + if d.HasChange("ibm_iam_endpoint") { + return true + } + if d.HasChange("ibm_api_key") { + return true + } + if d.HasChange("ibm_instance_id") { + return true + } + if d.HasChange("ibm_key_ring") { + return true + } + return false +} diff --git a/ibm/service/hpcs/resource_ibm_hpcs_managed_key.go b/ibm/service/hpcs/resource_ibm_hpcs_managed_key.go new file mode 100644 index 000000000..3d3d7f933 --- /dev/null +++ b/ibm/service/hpcs/resource_ibm_hpcs_managed_key.go @@ -0,0 +1,762 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func ResourceIbmManagedKey() *schema.Resource { + return &schema.Resource{ + CreateContext: ResourceIbmManagedKeyCreate, + ReadContext: ResourceIbmManagedKeyRead, + UpdateContext: ResourceIbmManagedKeyUpdate, + DeleteContext: ResourceIbmManagedKeyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "uko_vault": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The UUID of the Vault in which the update is to take place.", + }, + "key_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the key.", + }, + "template_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_managed_key", "template_name"), + Description: "Name of the key template to use when creating a key.", + }, + "vault": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "ID of the Vault where the entity is to be created in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + }, + }, + }, + "label": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_managed_key", "label"), + Description: "The label of the key.", + }, + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Key-value pairs associated with the key.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Name of a tag.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Value of a tag.", + }, + }, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_managed_key", "description"), + Description: "Description of the managed key.", + }, + "template": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Reference to a key template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Name of the key template.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "The state of the key.", + }, + "size": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The algorithm of the key.", + }, + "verification_patterns": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A list of verification patterns of the key (e.g. public key hash for RSA keys).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The method used for calculating the verification pattern.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The calculated value.", + }, + }, + }, + }, + "activation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "First day when the key is active.", + }, + "expiration_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Last day when the key is active.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the key was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the key.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the key.", + }, + "referenced_keystores": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "referenced keystores.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Name of the target keystore.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type of keystore.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + }, + }, + }, + "instances": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "key instances.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + }, + "label_in_keystore": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The label of the key.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Type of the key instance.", + }, + "keystore": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Description of properties of a key within the context of keystores.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type of keystore.", + }, + }, + }, + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIbmManagedKeyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "template_name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[A-Za-z][A-Za-z0-9-]+$`, + MinValueLength: 1, + MaxValueLength: 30, + }, + validate.ValidateSchema{ + Identifier: "region", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao", + }, + validate.ValidateSchema{ + Identifier: "label", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[A-Za-z0-9._ -]+$`, + MinValueLength: 1, + MaxValueLength: 100, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `(.|\\n)*`, + MinValueLength: 0, + MaxValueLength: 200, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_hpcs_managed_key", Schema: validateSchema} + return &resourceValidator +} + +func ResourceIbmManagedKeyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + instance_id := d.Get("instance_id").(string) + region := d.Get("region").(string) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + createManagedKeyOptions := &ukov4.CreateManagedKeyOptions{} + + uko_vault := d.Get("uko_vault").(string) + createManagedKeyOptions.SetUKOVault(uko_vault) + createManagedKeyOptions.SetTemplateName(d.Get("template_name").(string)) + vaultModel, err := ResourceIbmManagedKeyMapToVaultReferenceInCreationRequest(d.Get("vault.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createManagedKeyOptions.SetVault(vaultModel) + createManagedKeyOptions.SetLabel(d.Get("label").(string)) + if _, ok := d.GetOk("tags"); ok { + var tags []ukov4.Tag + for _, e := range d.Get("tags").([]interface{}) { + value := e.(map[string]interface{}) + tagsItem, err := ResourceIbmManagedKeyMapToTag(value) + if err != nil { + return diag.FromErr(err) + } + tags = append(tags, *tagsItem) + } + createManagedKeyOptions.SetTags(tags) + } + if _, ok := d.GetOk("description"); ok { + createManagedKeyOptions.SetDescription(d.Get("description").(string)) + } + + managedKey, response, err := ukoClient.CreateManagedKeyWithContext(context, createManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] CreateManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateManagedKeyWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s/%s", region, instance_id, uko_vault, *managedKey.ID)) + + return ResourceIbmManagedKeyRead(context, d, meta) +} + +func ResourceIbmManagedKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getManagedKeyOptions := &ukov4.GetManagedKeyOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + key_id := id[3] + getManagedKeyOptions.SetID(key_id) + getManagedKeyOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + managedKey, response, err := ukoClient.GetManagedKeyWithContext(context, getManagedKeyOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetManagedKeyWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("uko_vault", getManagedKeyOptions.UKOVault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting uko_vault: %s", err)) + } + d.Set("key_id", key_id) + vaultMap, err := ResourceIbmManagedKeyVaultReferenceInCreationRequestToMap(managedKey.Vault) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("vault", []map[string]interface{}{vaultMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault: %s", err)) + } + if err = d.Set("label", managedKey.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + tags := []map[string]interface{}{} + if managedKey.Tags != nil { + for _, tagsItem := range managedKey.Tags { + tagsItemMap, err := ResourceIbmManagedKeyTagToMap(&tagsItem) + if err != nil { + return diag.FromErr(err) + } + tags = append(tags, tagsItemMap) + } + } + if err = d.Set("tags", tags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tags: %s", err)) + } + if err = d.Set("description", managedKey.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + templateMap, err := ResourceIbmManagedKeyTemplateReferenceToMap(managedKey.Template) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("template", []map[string]interface{}{templateMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting template: %s", err)) + } + if err = d.Set("state", managedKey.State); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("size", managedKey.Size); err != nil { + return diag.FromErr(fmt.Errorf("Error setting size: %s", err)) + } + if err = d.Set("algorithm", managedKey.Algorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting algorithm: %s", err)) + } + verificationPatterns := []map[string]interface{}{} + if managedKey.VerificationPatterns != nil { + for _, verificationPatternsItem := range managedKey.VerificationPatterns { + verificationPatternsItemMap, err := ResourceIbmManagedKeyKeyVerificationPatternToMap(&verificationPatternsItem) + if err != nil { + return diag.FromErr(err) + } + verificationPatterns = append(verificationPatterns, verificationPatternsItemMap) + } + } + if err = d.Set("verification_patterns", verificationPatterns); err != nil { + return diag.FromErr(fmt.Errorf("Error setting verification_patterns: %s", err)) + } + if err = d.Set("activation_date", flex.DateToString(managedKey.ActivationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting activation_date: %s", err)) + } + if err = d.Set("expiration_date", flex.DateToString(managedKey.ExpirationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting expiration_date: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(managedKey.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(managedKey.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_by", managedKey.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("updated_by", managedKey.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + referencedKeystores := []map[string]interface{}{} + for _, referencedKeystoresItem := range managedKey.ReferencedKeystores { + referencedKeystoresItemMap, err := ResourceIbmManagedKeyTargetKeystoreReferenceToMap(&referencedKeystoresItem) + if err != nil { + return diag.FromErr(err) + } + referencedKeystores = append(referencedKeystores, referencedKeystoresItemMap) + } + if err = d.Set("referenced_keystores", referencedKeystores); err != nil { + return diag.FromErr(fmt.Errorf("Error setting referenced_keystores: %s", err)) + } + instances := []map[string]interface{}{} + for _, instancesItem := range managedKey.Instances { + instancesItemMap, err := ResourceIbmManagedKeyKeyInstanceToMap(&instancesItem) + if err != nil { + return diag.FromErr(err) + } + instances = append(instances, instancesItemMap) + } + if err = d.Set("instances", instances); err != nil { + return diag.FromErr(fmt.Errorf("Error setting instances: %s", err)) + } + if err = d.Set("href", managedKey.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func ResourceIbmManagedKeyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + updateManagedKeyOptions := &ukov4.UpdateManagedKeyOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + key_id := id[3] + updateManagedKeyOptions.SetID(key_id) + updateManagedKeyOptions.SetUKOVault(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + hasChange := false + + if d.HasChange("uko_vault") || d.HasChange("label") { + updateManagedKeyOptions.SetUKOVault(d.Get("uko_vault").(string)) + if err != nil { + return diag.FromErr(err) + } + updateManagedKeyOptions.SetLabel(d.Get("label").(string)) + hasChange = true + } + if d.HasChange("tags") { + // TODO: handle Tags of type TypeList -- not primitive, not model + hasChange = true + } + if d.HasChange("description") { + updateManagedKeyOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + etag := d.Get("version").(string) + updateManagedKeyOptions.SetIfMatch(etag) + + if hasChange { + _, response, err := ukoClient.UpdateManagedKeyWithContext(context, updateManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] UpdateManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateManagedKeyWithContext failed %s\n%s", err, response)) + } + etag = response.Headers.Get("Etag") + } + + // Support for changing state + if d.HasChange("state") { + prevIntf, newIntf := d.GetChange("state") + prev := prevIntf.(string) + new := newIntf.(string) + if new == "deactivated" { + if prev == "active" { + deactivateManagedKeyOptions := &ukov4.DeactivateManagedKeyOptions{} + + deactivateManagedKeyOptions.SetIfMatch(etag) + deactivateManagedKeyOptions.SetID(key_id) + deactivateManagedKeyOptions.SetUKOVault(vault_id) + + _, response, err := ukoClient.DeactivateManagedKeyWithContext(context, deactivateManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] DeactivateManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeactivateManagedKeyWithContext failed %s\n%s", err, response)) + } + } else { + return diag.FromErr(fmt.Errorf("Deactivate managed key failed: Cannot deactivate key not in active state")) + } + } else if new == "destroyed" { + if prev == "deactivated" { + destroyManagedKeyOptions := &ukov4.DestroyManagedKeyOptions{} + + destroyManagedKeyOptions.SetIfMatch(etag) + destroyManagedKeyOptions.SetID(key_id) + destroyManagedKeyOptions.SetUKOVault(vault_id) + + _, response, err := ukoClient.DestroyManagedKeyWithContext(context, destroyManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] DestroyManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DestroyManagedKeyWithContext failed %s\n%s", err, response)) + } + } else { + return diag.FromErr(fmt.Errorf("Destroy managed key failed: Cannot destroy key not in deactivated state")) + } + } else if new == "active" { + if prev == "deactivated" || prev == "pre_activation" { + activateManagedKeyOptions := &ukov4.ActivateManagedKeyOptions{} + + activateManagedKeyOptions.SetIfMatch(etag) + activateManagedKeyOptions.SetID(key_id) + activateManagedKeyOptions.SetUKOVault(vault_id) + + _, response, err := ukoClient.ActivateManagedKeyWithContext(context, activateManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] ActivateManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ActivateManagedKeyWithContext failed %s\n%s", err, response)) + } + } else { + return diag.FromErr(fmt.Errorf("Activate managed key failed: Cannot activate key not in deactivated or pre_activation state")) + } + } + } + + return ResourceIbmManagedKeyRead(context, d, meta) +} + +func ResourceIbmManagedKeyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + // Don't allow deleting of non-destroyed keys + if d.Get("state") != "destroyed" { + return diag.FromErr(fmt.Errorf("Delete Key failed: Cannot delete key that is not destroyed")) + } + + // Etag support + etag := d.Get("version").(string) + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + key_id := id[3] + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + deleteManagedKeyOptions := &ukov4.DeleteManagedKeyOptions{} + + deleteManagedKeyOptions.SetIfMatch(etag) + deleteManagedKeyOptions.SetID(key_id) + deleteManagedKeyOptions.SetUKOVault(vault_id) + + response, err := ukoClient.DeleteManagedKeyWithContext(context, deleteManagedKeyOptions) + if err != nil { + log.Printf("[DEBUG] DeleteManagedKeyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteManagedKeyWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func ResourceIbmManagedKeyMapToVaultReferenceInCreationRequest(modelMap map[string]interface{}) (*ukov4.VaultReferenceInCreationRequest, error) { + model := &ukov4.VaultReferenceInCreationRequest{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIbmManagedKeyMapToTag(modelMap map[string]interface{}) (*ukov4.Tag, error) { + model := &ukov4.Tag{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func ResourceIbmManagedKeyVaultReferenceInCreationRequestToMap(model *ukov4.VaultReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func ResourceIbmManagedKeyTagToMap(model *ukov4.Tag) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + return modelMap, nil +} + +func ResourceIbmManagedKeyTemplateReferenceToMap(model *ukov4.TemplateReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func ResourceIbmManagedKeyKeyVerificationPatternToMap(model *ukov4.KeyVerificationPattern) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["method"] = model.Method + modelMap["value"] = model.Value + return modelMap, nil +} + +func ResourceIbmManagedKeyTargetKeystoreReferenceToMap(model *ukov4.TargetKeystoreReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + modelMap["type"] = model.Type + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil +} + +func ResourceIbmManagedKeyKeyInstanceToMap(model *ukov4.KeyInstance) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["label_in_keystore"] = model.LabelInKeystore + if model.Type != nil { + modelMap["type"] = model.Type + } + keystoreMap, err := ResourceIbmManagedKeyInstanceInKeystoreToMap(model.Keystore) + if err != nil { + return modelMap, err + } + modelMap["keystore"] = []map[string]interface{}{keystoreMap} + return modelMap, nil +} + +func ResourceIbmManagedKeyInstanceInKeystoreToMap(model *ukov4.InstanceInKeystore) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["group"] = model.Group + modelMap["type"] = model.Type + return modelMap, nil +} diff --git a/ibm/resource_ibm_hpcs_test.go b/ibm/service/hpcs/resource_ibm_hpcs_test.go similarity index 83% rename from ibm/resource_ibm_hpcs_test.go rename to ibm/service/hpcs/resource_ibm_hpcs_test.go index 0db2390ab..7ac0c1ff4 100644 --- a/ibm/resource_ibm_hpcs_test.go +++ b/ibm/service/hpcs/resource_ibm_hpcs_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package hpcs_test import ( "fmt" @@ -10,6 +10,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/resourcecontroller" rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,8 +25,8 @@ func TestAccIBMHPCSInstanceBasic(t *testing.T) { name := "ibm_hpcs.hpcs" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckHPCS(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckHPCS(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMHPCSInstanceDestroy, Steps: []resource.TestStep{ { @@ -65,7 +68,7 @@ func TestAccIBMHPCSInstanceBasic(t *testing.T) { } func testAccCheckIBMHPCSInstanceDestroy(s *terraform.State) error { - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() + rsConClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() if err != nil { return err } @@ -80,13 +83,13 @@ func testAccCheckIBMHPCSInstanceDestroy(s *terraform.State) error { } instance, response, err := rsConClient.GetResourceInstance(&rsInst) if err == nil { - if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, rsInstanceReclamation)) { + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, resourcecontroller.RsInstanceReclamation)) { log.Printf("[WARN]Returning nil because it's in removed or pending_reclamation state") return nil } return fmt.Errorf("Instance still exists: %s", rs.Primary.ID) } else if strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) } } return nil @@ -100,7 +103,7 @@ func testAccCheckIBMHPCSInstanceExists(n string, tfHPCSID string) resource.TestC return fmt.Errorf("Not found: %s", n) } - rsConClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() + rsConClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() if err != nil { return err } @@ -115,7 +118,7 @@ func testAccCheckIBMHPCSInstanceExists(n string, tfHPCSID string) resource.TestC tfHPCSID = "" return nil } - return fmt.Errorf("Error retrieving resource instance: %s %s", err, response) + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) } if strings.Contains(*instance.State, "removed") { tfHPCSID = "" @@ -142,7 +145,7 @@ func testAccCheckIBMHPCSInstanceBasic(name string) string { token = "%s" } } - `, name, hpcsAdmin1, hpcsToken1) + `, name, acc.HpcsAdmin1, acc.HpcsToken1) } func testAccCheckIBMHPCSInstanceAdminUpdate(name string) string { return fmt.Sprintf(` @@ -164,7 +167,7 @@ func testAccCheckIBMHPCSInstanceAdminUpdate(name string) string { token = "%s" } } - `, name, hpcsAdmin1, hpcsToken1, hpcsAdmin2, hpcsToken2) + `, name, acc.HpcsAdmin1, acc.HpcsToken1, acc.HpcsAdmin2, acc.HpcsToken2) } func testAccCheckIBMHPCSInstanceAdminDelete(name string) string { return fmt.Sprintf(` @@ -181,7 +184,7 @@ func testAccCheckIBMHPCSInstanceAdminDelete(name string) string { token = "%s" } } - `, name, hpcsAdmin1, hpcsToken1) + `, name, acc.HpcsAdmin1, acc.HpcsToken1) } func testAccCheckIBMHPCSInstanceUnitsUpdate(name string) string { return fmt.Sprintf(` @@ -198,5 +201,5 @@ func testAccCheckIBMHPCSInstanceUnitsUpdate(name string) string { token = "%s" } } - `, name, hpcsAdmin1, hpcsToken1) + `, name, acc.HpcsAdmin1, acc.HpcsToken1) } diff --git a/ibm/service/hpcs/resource_ibm_hpcs_vault.go b/ibm/service/hpcs/resource_ibm_hpcs_vault.go new file mode 100644 index 000000000..9e3460633 --- /dev/null +++ b/ibm/service/hpcs/resource_ibm_hpcs_vault.go @@ -0,0 +1,353 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package hpcs + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" +) + +func ResourceIbmVault() *schema.Resource { + return &schema.Resource{ + CreateContext: ResourceIbmVaultCreate, + ReadContext: ResourceIbmVaultRead, + UpdateContext: ResourceIbmVaultUpdate, + DeleteContext: ResourceIbmVaultDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the UKO instance this resource exists in.", + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The region of the UKO instance this resource exists in.", + }, + "vault_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ID of the vault.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_vault", "name"), + Description: "A human-readable name to assign to your vault. To protect your privacy, do not use personal data, such as your name or location.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_hpcs_vault", "description"), + Description: "Description of the vault.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the vault was created.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Date and time when the vault was last updated.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that created the vault.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user that last updated the vault.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A URL that uniquely identifies your cloud resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIbmVaultValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[A-Za-z][A-Za-z0-9#@!$% '_-]*$`, + MinValueLength: 1, + MaxValueLength: 100, + }, + validate.ValidateSchema{ + Identifier: "region", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao", + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `(.|\\n)*`, + MinValueLength: 0, + MaxValueLength: 200, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_hpcs_vault", Schema: validateSchema} + return &resourceValidator +} + +func ResourceIbmVaultCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + instance_id := d.Get("instance_id").(string) + region := d.Get("region").(string) + + createVaultOptions := &ukov4.CreateVaultOptions{} + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + createVaultOptions.SetName(d.Get("name").(string)) + if _, ok := d.GetOk("description"); ok { + createVaultOptions.SetDescription(d.Get("description").(string)) + } + + vault, response, err := ukoClient.CreateVaultWithContext(context, createVaultOptions) + if err != nil { + log.Printf("[DEBUG] CreateVaultWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateVaultWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", region, instance_id, *vault.ID)) + + return ResourceIbmVaultRead(context, d, meta) +} + +func ResourceIbmVaultRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + getVaultOptions := &ukov4.GetVaultOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + getVaultOptions.SetID(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + vault, response, err := ukoClient.GetVaultWithContext(context, getVaultOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVaultWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVaultWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("vault_id", vault.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vault ID: %s", err)) + } + if err = d.Set("name", vault.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("description", vault.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vault.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(vault.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("created_by", vault.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("updated_by", vault.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + if err = d.Set("href", vault.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func ResourceIbmVaultUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + updateVaultOptions := &ukov4.UpdateVaultOptions{} + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + updateVaultOptions.SetID(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + hasChange := false + + if d.HasChange("name") { + updateVaultOptions.SetName(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("description") { + updateVaultOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + + // Etag support + updateVaultOptions.SetIfMatch(d.Get("version").(string)) + + if hasChange { + _, response, err := ukoClient.UpdateVaultWithContext(context, updateVaultOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVaultWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateVaultWithContext failed %s\n%s", err, response)) + } + } + + return ResourceIbmVaultRead(context, d, meta) +} + +func ResourceIbmVaultDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ukoClient, err := meta.(conns.ClientSession).UkoV4() + if err != nil { + return diag.FromErr(err) + } + + deleteVaultOptions := &ukov4.DeleteVaultOptions{} + + // Etag support + deleteVaultOptions.SetIfMatch(d.Get("version").(string)) + + id := strings.Split(d.Id(), "/") + region := id[0] + instance_id := id[1] + vault_id := id[2] + deleteVaultOptions.SetID(vault_id) + + url, err := getUkoUrl(context, region, instance_id, ukoClient) + if err != nil { + return diag.FromErr(err) + } + ukoClient.SetServiceURL(url) + + response, err := ukoClient.DeleteVaultWithContext(context, deleteVaultOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVaultWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteVaultWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func getUkoUrl(context context.Context, region string, instance_id string, ukoClient *ukov4.UkoV4) (string, error) { + + // Get url + pathParamsMap := map[string]string{ + "id": instance_id, + } + + var brokerUrl string + if v := os.Getenv("IBMCLOUD_HPCS_UKO_URL"); v != "" { + if strings.Contains(v, "https://") { + return v, nil + } else { + return fmt.Sprintf("https://%s/", v), nil + } + } else { + brokerUrl = fmt.Sprintf("https://%s.broker.hs-crypto.cloud.ibm.com", region) + } + + builder := core.NewRequestBuilder(core.GET) + builder = builder.WithContext(context) + builder.EnableGzipCompression = ukoClient.GetEnableGzipCompression() + _, err := builder.ResolveRequestURL(brokerUrl, + `/crypto_v2/instances/{id}`, pathParamsMap) + if err != nil { + return "", err + } + builder.AddHeader("Accept", "application/json") + + request, err := builder.Build() + if err != nil { + return "", err + } + + var rawResponse map[string]json.RawMessage + _, err = ukoClient.Service.Request(request, &rawResponse) + if err != nil { + return "", err + } + + var uko *map[string]string + if rawResponse != nil { + err = core.UnmarshalPrimitive(rawResponse, "uko", &uko) + if err != nil { + return "", err + } + url := (*uko)["public"] + log.Printf(url) + return "https://" + url, nil + } + + return "", fmt.Errorf("Could not get response") +} diff --git a/ibm/service/iamaccessgroup/README.md b/ibm/service/iamaccessgroup/README.md new file mode 100644 index 000000000..febb8aacf --- /dev/null +++ b/ibm/service/iamaccessgroup/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider IAM Access Group + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the IAM Access Group resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_access_group) +* IBM API Docs: [IBM API Docs for IAM Access Group](https://cloud.ibm.com/apidocs/iam-access-groups) +* IBM IAM Access Group SDK: [IBM SDK for IAM Access Group](https://github.com/IBM/platform-services-go-sdk/tree/main/iamaccessgroupsv2) diff --git a/ibm/service/iamaccessgroup/data_source_ibm_iam_access_group.go b/ibm/service/iamaccessgroup/data_source_ibm_iam_access_group.go new file mode 100644 index 000000000..8645bb998 --- /dev/null +++ b/ibm/service/iamaccessgroup/data_source_ibm_iam_access_group.go @@ -0,0 +1,280 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIAMAccessGroup() *schema.Resource { + return &schema.Resource{ + Read: dataIBMIAMAccessGroupRead, + Schema: map[string]*schema.Schema{ + "access_group_name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the access group", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_access_group", + "access_group_name"), + }, + "groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the access group", + }, + "ibm_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "iam_service_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "iam_profile_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the Rule", + }, + "expiration": { + Type: schema.TypeInt, + Computed: true, + Description: "The expiration in hours", + }, + "identity_provider": { + Type: schema.TypeString, + Computed: true, + Description: "The realm name or identity proivider url", + }, + "conditions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "claim": { + Type: schema.TypeString, + Computed: true, + }, + "operator": { + Type: schema.TypeString, + Computed: true, + }, + "value": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "id of the rule", + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMIAMAccessGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_group_name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:access_group", "resolved_to:name"}, + Optional: true}) + + iBMIAMAccessGroupValidator := validate.ResourceValidator{ResourceName: "ibm_iam_access_group", Schema: validateSchema} + return &iBMIAMAccessGroupValidator +} + +func dataIBMIAMAccessGroupRead(d *schema.ResourceData, meta interface{}) error { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() + if err != nil { + return err + } + client := userManagement.UserInvite() + res, err := client.ListUsers(accountID) + if err != nil { + return err + } + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + + start := "" + allrecs := []iamidentityv1.ServiceID{} + var pg int64 = 100 + for { + listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ + AccountID: &userDetails.UserAccount, + Pagesize: &pg, + } + if start != "" { + listServiceIDOptions.Pagetoken = &start + } + + serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) + } + start = flex.GetNextIAM(serviceIDs.Next) + allrecs = append(allrecs, serviceIDs.Serviceids...) + if start == "" { + break + } + } + + profileStart := "" + allprofiles := []iamidentityv1.TrustedProfile{} + var plimit int64 = 100 + for { + listProfilesOptions := iamidentityv1.ListProfilesOptions{ + AccountID: &userDetails.UserAccount, + Pagesize: &plimit, + } + if profileStart != "" { + listProfilesOptions.Pagetoken = &profileStart + } + + profileIDs, resp, err := iamClient.ListProfiles(&listProfilesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error listing Trusted Profiles %s %s", err, resp) + } + profileStart = flex.GetNextIAM(profileIDs.Next) + allprofiles = append(allprofiles, profileIDs.Profiles...) + if profileStart == "" { + break + } + } + offset := int64(0) + limit := int64(100) + listAccessGroupOption := iamAccessGroupsClient.NewListAccessGroupsOptions(accountID) + listAccessGroupOption.Limit = &plimit + listAccessGroupOption.Offset = &offset + retreivedGroups, detailedResponse, err := iamAccessGroupsClient.ListAccessGroups(listAccessGroupOption) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving access groups: %s. API Response is: %s", err, detailedResponse) + } + + if len(retreivedGroups.Groups) == 0 { + return fmt.Errorf("[ERROR] No access group in account") + } + allGroups := retreivedGroups.Groups + + totalGroups := flex.IntValue(retreivedGroups.TotalCount) + for len(allGroups) < totalGroups { + offset = offset + limit + listAccessGroupOption.SetOffset(offset) + retreivedGroups, detailedResponse, err := iamAccessGroupsClient.ListAccessGroups(listAccessGroupOption) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving access groups: %s. API Response is: %s", err, detailedResponse) + } + + allGroups = append(allGroups, retreivedGroups.Groups...) + } + var agName string + var matchGroups []iamaccessgroupsv2.Group + if v, ok := d.GetOk("access_group_name"); ok { + agName = v.(string) + for _, grpData := range allGroups { + if *grpData.Name == agName { + matchGroups = append(matchGroups, grpData) + } + } + } else { + matchGroups = allGroups + } + if len(matchGroups) == 0 { + return fmt.Errorf("[ERROR] No Access Groups with name %s in Account", agName) + } + + grpMap := make([]map[string]interface{}, 0, len(matchGroups)) + + for _, grp := range matchGroups { + accessGroupMembersListOptions := iamAccessGroupsClient.NewListAccessGroupMembersOptions(*grp.ID) + members, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupMembers(accessGroupMembersListOptions) + if err != nil { + log.Printf("Error retrieving access group members: %s.API Response: %s", err, detailedResponse) + } + + accessGroupRulesListOptions := iamAccessGroupsClient.NewListAccessGroupRulesOptions(*grp.ID) + rules, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupRules(accessGroupRulesListOptions) + if err != nil { + log.Printf("Error retrieving access group rules: %s. API Response: %s", err, detailedResponse) + } + ibmID, serviceID, profileID := flex.FlattenMembersData(members.Members, res, allrecs, allprofiles) + + grpInstance := map[string]interface{}{ + "id": grp.ID, + "name": grp.Name, + "description": grp.Description, + "ibm_ids": ibmID, + "iam_service_ids": serviceID, + "iam_profile_ids": profileID, + "rules": flex.FlattenAccessGroupRules(rules), + } + + grpMap = append(grpMap, grpInstance) + + } + + d.SetId(accountID) + d.Set("groups", grpMap) + d.Set("access_group_name", agName) + + return nil +} diff --git a/ibm/data_source_ibm_iam_access_group_test.go b/ibm/service/iamaccessgroup/data_source_ibm_iam_access_group_test.go similarity index 85% rename from ibm/data_source_ibm_iam_access_group_test.go rename to ibm/service/iamaccessgroup/data_source_ibm_iam_access_group_test.go index 8a2647424..dad96c0b3 100644 --- a/ibm/data_source_ibm_iam_access_group_test.go +++ b/ibm/service/iamaccessgroup/data_source_ibm_iam_access_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamaccessgroup_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMIAMAccessGroupDataSource_Basic(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMIAMAccessGroupDataSourceConfig(name), diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group.go new file mode 100644 index 000000000..a2c059baf --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup + +import ( + "context" + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "time" +) + +func ResourceIBMIAMAccessGroup() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIAMAccessGroupCreate, + ReadContext: resourceIBMIAMAccessGroupRead, + UpdateContext: resourceIBMIAMAccessGroupUpdate, + DeleteContext: resourceIBMIAMAccessGroupDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the access group", + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the access group", + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "version": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceIBMIAMAccessGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get("name").(string) + creatAccessGroupOptions := iamAccessGroupsClient.NewCreateAccessGroupOptions(userDetails.UserAccount, name) + if des, ok := d.GetOk("description"); ok { + description := des.(string) + creatAccessGroupOptions.Description = &description + } + agrp, detailedResponse, err := iamAccessGroupsClient.CreateAccessGroup(creatAccessGroupOptions) + if err != nil || agrp == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating access group: %s. API Response: %s", err, detailedResponse)) + } + + d.SetId(*agrp.ID) + + return resourceIBMIAMAccessGroupRead(context, d, meta) +} + +func resourceIBMIAMAccessGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + agrpID := d.Id() + getAccessGroupOptions := iamAccessGroupsClient.NewGetAccessGroupOptions(agrpID) + var agrp *iamaccessgroupsv2.Group + var detailedResponse *core.DetailedResponse + err = resource.RetryContext(context, 5*time.Second, func() *resource.RetryError { + agrp, detailedResponse, err = iamAccessGroupsClient.GetAccessGroup(getAccessGroupOptions) + if err != nil || agrp == nil { + if detailedResponse != nil && detailedResponse.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + agrp, detailedResponse, err = iamAccessGroupsClient.GetAccessGroup(getAccessGroupOptions) + } + if err != nil || agrp == nil || detailedResponse == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group: %s. API Response: %s", err, detailedResponse)) + } + version := detailedResponse.GetHeaders().Get("etag") + d.Set("name", agrp.Name) + d.Set("description", agrp.Description) + d.Set("version", version) + + return nil +} + +func resourceIBMIAMAccessGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + agrpID := d.Id() + + hasChange := false + version := d.Get("version").(string) + updateAccessGroupOptions := iamAccessGroupsClient.NewUpdateAccessGroupOptions(agrpID, version) + + if d.HasChange("name") { + name := d.Get("name").(string) + updateAccessGroupOptions.Name = &name + hasChange = true + } + + if d.HasChange("description") { + description := d.Get("description").(string) + updateAccessGroupOptions.Description = &description + hasChange = true + } + + if hasChange { + agrp, detailedResponse, err := iamAccessGroupsClient.UpdateAccessGroup(updateAccessGroupOptions) + if err != nil || agrp == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating access group: %s. API Response: %s", err, detailedResponse)) + } + } + + return resourceIBMIAMAccessGroupRead(context, d, meta) + +} + +func resourceIBMIAMAccessGroupDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + agID := d.Id() + force := true + deleteAccessGroupOptions := iamAccessGroupsClient.NewDeleteAccessGroupOptions(agID) + deleteAccessGroupOptions.SetForce(force) + detailedResponse, err := iamAccessGroupsClient.DeleteAccessGroup(deleteAccessGroupOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting access group: %s, API Response: %s", err, detailedResponse)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings.go new file mode 100644 index 000000000..d7897b3bb --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings.go @@ -0,0 +1,86 @@ +package iamaccessgroup + +import ( + "context" + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMAccessGroupAccountSettings() *schema.Resource { + return &schema.Resource{ + ReadContext: resourceIBMIAMAccessGroupAccountSettingGet, + UpdateContext: resourceIBMIAMAccessGroupAccountSettingSet, + CreateContext: resourceIBMIAMAccessGroupAccountSettingSet, + DeleteContext: resourceIBMIAMAccessGroupAccountSettingUnSet, + Importer: &schema.ResourceImporter{}, + Schema: map[string]*schema.Schema{ + "public_access_enabled": { + Type: schema.TypeBool, + Required: true, + Description: "Flag to enable/disable public access groups", + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the account", + }, + }, + } +} + +func resourceIBMIAMAccessGroupAccountSettingGet(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + getAccessGroupOptions := iamAccessGroupsClient.NewGetAccountSettingsOptions(userDetails.UserAccount) + accountSetting, detailedResponse, err := iamAccessGroupsClient.GetAccountSettings(getAccessGroupOptions) + if err != nil || accountSetting == nil { + if detailedResponse != nil && detailedResponse.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group account setting: %s. API Response: %s", err, detailedResponse)) + } + d.SetId(*accountSetting.AccountID) + d.Set("public_access_enabled", accountSetting.PublicAccessEnabled) + d.Set("account_id", accountSetting.AccountID) + return nil +} + +func resourceIBMIAMAccessGroupAccountSettingSet(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + updateAccountSettingsOptions := iamAccessGroupsClient.NewUpdateAccountSettingsOptions(userDetails.UserAccount) + publicAccessEnabled := d.Get("public_access_enabled").(bool) + updateAccountSettingsOptions.PublicAccessEnabled = core.BoolPtr(publicAccessEnabled) + accountSetting, detailedResponse, err := iamAccessGroupsClient.UpdateAccountSettings(updateAccountSettingsOptions) + if err != nil || accountSetting == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating access public account setting: %s. API Response: %s", err, detailedResponse)) + } + d.SetId(*accountSetting.AccountID) + d.Set("public_access_enabled", *accountSetting.PublicAccessEnabled) + return resourceIBMIAMAccessGroupAccountSettingGet(context, d, meta) +} + +func resourceIBMIAMAccessGroupAccountSettingUnSet(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // DELETE NOT SUPPORTED + d.SetId("") + return nil +} diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings_test.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings_test.go new file mode 100644 index 000000000..c918cf0e8 --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_account_settings_test.go @@ -0,0 +1,112 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup_test + +import ( + "fmt" + iamaccessgroups "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMAccessGroupAccountSettingsBasic(t *testing.T) { + var conf iamaccessgroups.AccountSettings + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIamAccessGroupAccountSettingsConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIamAccountSettingsExists("ibm_iam_access_group_account_settings.iam_access_group_account_settings", conf), + ), + }, + { + Config: testAccCheckIbmIamAccessGroupAccountSettingsConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc(), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupAccountSettingsUpdates(t *testing.T) { + var conf iamaccessgroups.AccountSettings + publicAccessEnabled := "false" + publicAccessEnabledUpdated := "true" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIamAccessGroupAccountSettingsConfig(publicAccessEnabled), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIamAccountSettingsExists("ibm_iam_access_group_account_settings.iam_access_group_account_settings", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group_account_settings.iam_access_group_account_settings", "public_access_enabled", publicAccessEnabled), + ), + }, + { + Config: testAccCheckIbmIamAccessGroupAccountSettingsConfig(publicAccessEnabledUpdated), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group_account_settings.iam_access_group_account_settings", "public_access_enabled", publicAccessEnabledUpdated), + ), + }, + { + ResourceName: "ibm_iam_access_group_account_settings.iam_access_group_account_settings", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIbmIamAccessGroupAccountSettingsConfigBasic() string { + return ` + + resource "ibm_iam_access_group_account_settings" "iam_access_group_account_settings" { + public_access_enabled = true + } + ` +} + +func testAccCheckIbmIamAccessGroupAccountSettingsConfig(publicAccessEnabled string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group_account_settings" "iam_access_group_account_settings" { + public_access_enabled = %s + } + `, publicAccessEnabled) +} + +func testAccCheckIbmIamAccountSettingsExists(n string, obj iamaccessgroups.AccountSettings) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + iamAccessGroupsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + + getAccountSettingsOptions := iamAccessGroupsClient.NewGetAccountSettingsOptions(rs.Primary.ID) + + accountSettingsResponse, _, err := iamAccessGroupsClient.GetAccountSettings(getAccountSettingsOptions) + if err != nil { + return err + } + + obj = *accountSettingsResponse + + return nil + } +} diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule.go new file mode 100644 index 000000000..58de87c98 --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule.go @@ -0,0 +1,283 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMDynamicRule() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMDynamicRuleCreate, + Read: resourceIBMIAMDynamicRuleRead, + Update: resourceIBMIAMDynamicRuleUpdate, + Delete: resourceIBMIAMDynamicRuleDelete, + Exists: resourceIBMIAMDynamicRuleExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "access_group_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier of the access group", + ValidateFunc: validate.InvokeValidator("ibm_iam_access_group_dynamic_rule", + "access_group_id"), + }, + + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the Rule", + }, + "expiration": { + Type: schema.TypeInt, + Required: true, + Description: "The expiration in hours", + ValidateFunc: validate.ValidatePortRange(1, 24), + }, + "identity_provider": { + Type: schema.TypeString, + Required: true, + Description: "The realm name or identity proivider url", + }, + "conditions": { + Type: schema.TypeList, + Required: true, + Description: "conditions info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "claim": { + Type: schema.TypeString, + Required: true, + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"EQUALS", "EQUALS_IGNORE_CASE", "IN", "NOT_EQUALS_IGNORE_CASE", "NOT_EQUALS", "CONTAINS"}), + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "id of the rule", + }, + }, + } +} +func ResourceIBMIAMDynamicRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:access_group", "resolved_to:id"}, + Optional: true}) + + iBMIAMDynamicRuleValidator := validate.ResourceValidator{ResourceName: "ibm_iam_access_group_dynamic_rule", Schema: validateSchema} + return &iBMIAMDynamicRuleValidator +} + +func resourceIBMIAMDynamicRuleCreate(d *schema.ResourceData, meta interface{}) error { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + + grpID := d.Get("access_group_id").(string) + name := d.Get("name").(string) + realm := d.Get("identity_provider").(string) + expiration := int64(d.Get("expiration").(int)) + + var cond []interface{} + conditions := []iamaccessgroupsv2.RuleConditions{} + if res, ok := d.GetOk("conditions"); ok { + cond = res.([]interface{}) + for _, e := range cond { + r, _ := e.(map[string]interface{}) + value := fmt.Sprintf("\"%s\"", r["value"].(string)) + claim := r["claim"].(string) + operator := r["operator"].(string) + conditionParam := iamaccessgroupsv2.RuleConditions{ + Claim: &claim, + Operator: &operator, + Value: &value, + } + conditions = append(conditions, conditionParam) + } + } + + addAccessGroupRuleOptions := &iamaccessgroupsv2.AddAccessGroupRuleOptions{ + AccessGroupID: &grpID, + Name: &name, + RealmName: &realm, + Expiration: &expiration, + Conditions: conditions, + } + rule, detailedResponse, err := iamAccessGroupsClient.AddAccessGroupRule(addAccessGroupRuleOptions) + if err != nil || rule == nil { + return fmt.Errorf("[ERROR] Error adding rule to Access Group(%s) %s. API Response: %s", grpID, err, detailedResponse) + } + ruleID := rule.ID + d.SetId(fmt.Sprintf("%s/%s", grpID, *ruleID)) + + return resourceIBMIAMDynamicRuleRead(d, meta) +} + +func resourceIBMIAMDynamicRuleRead(d *schema.ResourceData, meta interface{}) error { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + grpID := parts[0] + ruleID := parts[1] + + getAccessGroupRuleOptions := &iamaccessgroupsv2.GetAccessGroupRuleOptions{ + AccessGroupID: &grpID, + RuleID: &ruleID, + } + rule, detailResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) + + if err != nil || rule == nil { + if detailResponse != nil && detailResponse.StatusCode == 404 { + d.SetId("") + return nil + } else { + return fmt.Errorf("[ERROR] Error retrieving access group Rules: %s. API Response: %s", err, detailResponse) + } + } + + d.Set("access_group_id", grpID) + d.Set("name", rule.Name) + d.Set("expiration", rule.Expiration) + d.Set("identity_provider", rule.RealmName) + d.Set("conditions", flex.FlattenConditions(rule.Conditions)) + d.Set("rule_id", rule.ID) + + return nil +} + +func resourceIBMIAMDynamicRuleUpdate(d *schema.ResourceData, meta interface{}) error { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + grpID := parts[0] + ruleID := parts[1] + getAccessGroupRuleOptions := iamAccessGroupsClient.NewGetAccessGroupRuleOptions(grpID, ruleID) + _, detailedResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving access group Rules: %s. API Response: %s", err, detailedResponse) + } + + etag := detailedResponse.GetHeaders().Get("etag") + realm := d.Get("identity_provider").(string) + expiration := int64(d.Get("expiration").(int)) + + var cond []interface{} + condition := []iamaccessgroupsv2.RuleConditions{} + if res, ok := d.GetOk("conditions"); ok { + cond = res.([]interface{}) + for _, e := range cond { + r, _ := e.(map[string]interface{}) + value := fmt.Sprintf("\"%s\"", r["value"].(string)) + claim := r["claim"].(string) + operator := r["operator"].(string) + conditionParam := iamaccessgroupsv2.RuleConditions{ + Claim: &claim, + Operator: &operator, + Value: &value, + } + condition = append(condition, conditionParam) + } + } + + replaceAccessGroupRuleOption := iamAccessGroupsClient.NewReplaceAccessGroupRuleOptions(grpID, ruleID, etag, expiration, realm, condition) + rule, detailedResponse, err := iamAccessGroupsClient.ReplaceAccessGroupRule(replaceAccessGroupRuleOption) + if err != nil || rule == nil { + return fmt.Errorf("[ERROR] Error replacing group(%s) rule(%s). API response: %s", grpID, ruleID, detailedResponse) + } + + return resourceIBMIAMDynamicRuleRead(d, meta) + +} + +func resourceIBMIAMDynamicRuleDelete(d *schema.ResourceData, meta interface{}) error { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + grpID := parts[0] + ruleID := parts[1] + removeAccessGroupRuleOptions := iamAccessGroupsClient.NewRemoveAccessGroupRuleOptions(grpID, ruleID) + detailedResponse, err := iamAccessGroupsClient.RemoveAccessGroupRule(removeAccessGroupRuleOptions) + if err != nil { + if detailedResponse != nil && detailedResponse.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting group(%s) rule(%s). API Response: %s", grpID, ruleID, detailedResponse) + } + + return nil +} + +func resourceIBMIAMDynamicRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return false, err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of accessGroupID/RuleID", d.Id()) + } + grpID := parts[0] + ruleID := parts[1] + + getAccessGroupRuleOptions := iamAccessGroupsClient.NewGetAccessGroupRuleOptions(grpID, ruleID) + rule, detailResponse, err := iamAccessGroupsClient.GetAccessGroupRule(getAccessGroupRuleOptions) + + if detailResponse != nil && detailResponse.StatusCode == 404 { + d.SetId("") + return false, nil + } + if err != nil || rule == nil { + return false, fmt.Errorf("[ERROR] Error getting group(%s) rule(%s). API response: %s", grpID, ruleID, detailResponse) + } + return *rule.AccessGroupID == grpID, nil +} diff --git a/ibm/resource_ibm_iam_access_group_dynamic_rule_test.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule_test.go similarity index 86% rename from ibm/resource_ibm_iam_access_group_dynamic_rule_test.go rename to ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule_test.go index 2bcdd08eb..7deeae265 100644 --- a/ibm/resource_ibm_iam_access_group_dynamic_rule_test.go +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_dynamic_rule_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamaccessgroup_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,11 +26,11 @@ func TestAccIBMIAMDynamicRule_Basic(t *testing.T) { operator := "CONTAINS" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMDynamicRuleDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMDynamicRuleBasic(agname, name, identityProvider, claim, operator, expiration), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_access_group_dynamic_rule.accgroup", "name", name), @@ -47,18 +51,18 @@ func TestAccIBMIAMDynamicRuleimport(t *testing.T) { resourceName := "ibm_iam_access_group_dynamic_rule.accgroup" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMDynamicRuleDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMDynamicRuleMultiple(agname, name, identityProvider, claim, operator, expiration), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "identity_provider", identityProvider), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -68,7 +72,7 @@ func TestAccIBMIAMDynamicRuleimport(t *testing.T) { } func testAccCheckIBMIAMDynamicRuleDestroy(s *terraform.State) error { - accClient, err := testAccProvider.Meta().(ClientSession).IAMAccessGroupsV2() + accClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() if err != nil { return err @@ -78,7 +82,7 @@ func testAccCheckIBMIAMDynamicRuleDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -96,7 +100,7 @@ func testAccCheckIBMIAMDynamicRuleDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Dynamic rule still exists: %s", rs.Primary.ID) } else if detailResponse.StatusCode != 404 { - return fmt.Errorf("Error waiting for Dynamic rule (%s) to be destroyed: %s", ruleID, err) + return fmt.Errorf("[ERROR] Error waiting for Dynamic rule (%s) to be destroyed: %s", ruleID, err) } } diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members.go new file mode 100644 index 000000000..76b36a3ba --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members.go @@ -0,0 +1,554 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMAccessGroupMembers() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIAMAccessGroupMembersCreate, + ReadContext: resourceIBMIAMAccessGroupMembersRead, + UpdateContext: resourceIBMIAMAccessGroupMembersUpdate, + DeleteContext: resourceIBMIAMAccessGroupMembersDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "access_group_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier of the access group", + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_iam_access_group_members", + "access_group_id"), + }, + + "ibm_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + }, + + "iam_service_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "iam_profile_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "members": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "iam_id": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func ResourceIBMIAMAccessGroupMembersValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:access_group", "resolved_to:id"}, + Optional: true}) + + iBMIAMAccessGroupMembersValidator := validate.ResourceValidator{ResourceName: "ibm_iam_access_group_members", Schema: validateSchema} + return &iBMIAMAccessGroupMembersValidator +} +func resourceIBMIAMAccessGroupMembersCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + grpID := d.Get("access_group_id").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + accountID := userDetails.UserAccount + + var userids, serviceids, profileids []string + + users := flex.ExpandStringList(d.Get("ibm_ids").(*schema.Set).List()) + services := flex.ExpandStringList(d.Get("iam_service_ids").(*schema.Set).List()) + profiles := flex.ExpandStringList(d.Get("iam_profile_ids").(*schema.Set).List()) + + if len(users) == 0 && len(services) == 0 && len(profiles) == 0 { + return diag.FromErr(fmt.Errorf("ERROR] Provide either `ibm_ids` or `iam_service_ids` or `iam_profile_ids`")) + + } + + userids, err = flex.FlattenUserIds(accountID, users, meta) + if err != nil { + return diag.FromErr(err) + } + + serviceids, err = FlattenServiceIds(services, meta) + if err != nil { + return diag.FromErr(err) + } + + profileids, err = FlattenProfileIds(profiles, meta) + if err != nil { + return diag.FromErr(err) + } + + members := prepareMemberAddRequest(iamAccessGroupsClient, userids, serviceids, profileids) + + addMembersToAccessGroupOptions := iamAccessGroupsClient.NewAddMembersToAccessGroupOptions(grpID) + addMembersToAccessGroupOptions.SetMembers(members) + membership, detailResponse, err := iamAccessGroupsClient.AddMembersToAccessGroup(addMembersToAccessGroupOptions) + if err != nil || membership == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error adding members to group(%s). API response: %s", grpID, detailResponse)) + } + + d.SetId(fmt.Sprintf("%s/%s", grpID, time.Now().UTC().String())) + + return resourceIBMIAMAccessGroupMembersRead(context, d, meta) +} + +func resourceIBMIAMAccessGroupMembersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + grpID := parts[0] + listAccessGroupMembersOptions := iamAccessGroupsClient.NewListAccessGroupMembersOptions(grpID) + offset := int64(0) + // lets fetch 100 in a single pagination + limit := int64(100) + listAccessGroupMembersOptions.SetLimit(limit) + members, detailedResponse, err := iamAccessGroupsClient.ListAccessGroupMembers(listAccessGroupMembersOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group members: %s. API Response: %s", err, detailedResponse)) + } + allMembers := members.Members + totalMembers := flex.IntValue(members.TotalCount) + for len(allMembers) < totalMembers { + offset = offset + limit + listAccessGroupMembersOptions.SetOffset(offset) + members, detailedResponse, err = iamAccessGroupsClient.ListAccessGroupMembers(listAccessGroupMembersOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving access group members: %s. API Response: %s", err, detailedResponse)) + } + allMembers = append(allMembers, members.Members...) + } + + d.Set("access_group_id", grpID) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + accountID := userDetails.UserAccount + + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() + if err != nil { + return diag.FromErr(err) + } + client := userManagement.UserInvite() + res, err := client.ListUsers(accountID) + if err != nil { + return diag.FromErr(err) + } + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []iamidentityv1.ServiceID{} + var pg int64 = 100 + for { + listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ + AccountID: &userDetails.UserAccount, + Pagesize: &pg, + } + if start != "" { + listServiceIDOptions.Pagetoken = &start + } + + serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp)) + } + start = flex.GetNextIAM(serviceIDs.Next) + allrecs = append(allrecs, serviceIDs.Serviceids...) + if start == "" { + break + } + } + + profileStart := "" + allprofiles := []iamidentityv1.TrustedProfile{} + var plimit int64 = 100 + for { + listProfilesOptions := iamidentityv1.ListProfilesOptions{ + AccountID: &userDetails.UserAccount, + Pagesize: &plimit, + } + if profileStart != "" { + listProfilesOptions.Pagetoken = &profileStart + } + + profileIDs, resp, err := iamClient.ListProfiles(&listProfilesOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing Trusted Profiles %s %s", err, resp)) + } + profileStart = flex.GetNextIAM(profileIDs.Next) + allprofiles = append(allprofiles, profileIDs.Profiles...) + if profileStart == "" { + break + } + } + + d.Set("members", flex.FlattenAccessGroupMembers(allMembers, res, allrecs)) + ibmID, serviceID, profileID := flex.FlattenMembersData(allMembers, res, allrecs, allprofiles) + if len(ibmID) > 0 { + d.Set("ibm_ids", ibmID) + } + if len(serviceID) > 0 { + d.Set("iam_service_ids", serviceID) + } + if len(profileID) > 0 { + d.Set("iam_profile_ids", profileID) + } + return nil +} + +func resourceIBMIAMAccessGroupMembersUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + grpID := parts[0] + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + accountID := userDetails.UserAccount + + var removeUsers, addUsers, removeServiceids, addServiceids, removeProfileids, addProfileids []string + o, n := d.GetChange("ibm_ids") + ou := o.(*schema.Set) + nu := n.(*schema.Set) + + removeUsers = flex.ExpandStringList(ou.Difference(nu).List()) + addUsers = flex.ExpandStringList(nu.Difference(ou).List()) + + os, ns := d.GetChange("iam_service_ids") + osi := os.(*schema.Set) + nsi := ns.(*schema.Set) + + removeServiceids = flex.ExpandStringList(osi.Difference(nsi).List()) + addServiceids = flex.ExpandStringList(nsi.Difference(osi).List()) + + op, np := d.GetChange("iam_profile_ids") + opi := op.(*schema.Set) + npi := np.(*schema.Set) + + removeProfileids = flex.ExpandStringList(opi.Difference(npi).List()) + addProfileids = flex.ExpandStringList(npi.Difference(opi).List()) + + if len(addUsers) > 0 || len(addServiceids) > 0 || len(addProfileids) > 0 && !d.IsNewResource() { + var userids, serviceids, profileids []string + userids, err = flex.FlattenUserIds(accountID, addUsers, meta) + if err != nil { + return diag.FromErr(err) + } + + serviceids, err = FlattenServiceIds(addServiceids, meta) + if err != nil { + return diag.FromErr(err) + } + + profileids, err = FlattenProfileIds(addProfileids, meta) + if err != nil { + return diag.FromErr(err) + } + + members := prepareMemberAddRequest(iamAccessGroupsClient, userids, serviceids, profileids) + + addMembersToAccessGroupOptions := iamAccessGroupsClient.NewAddMembersToAccessGroupOptions(grpID) + addMembersToAccessGroupOptions.SetMembers(members) + membership, detailResponse, err := iamAccessGroupsClient.AddMembersToAccessGroup(addMembersToAccessGroupOptions) + if err != nil || membership == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating members to group(%s). API response: %s", grpID, detailResponse)) + } + + } + if len(removeUsers) > 0 || len(removeServiceids) > 0 || len(removeProfileids) > 0 && !d.IsNewResource() { + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + for _, u := range removeUsers { + ibmUniqueId, err := flex.GetIBMUniqueId(accountID, u, meta) + if err != nil { + return diag.FromErr(err) + } + removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, ibmUniqueId) + _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(err) + } + + } + + for _, s := range removeServiceids { + getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ + ID: &s, + } + serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) + if err != nil || serviceID == nil { + return diag.FromErr(fmt.Errorf("ERROR] Error Getting Service Ids %s %s", err, resp)) + } + removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, *serviceID.IamID) + detailResponse, err := iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error removing members to group(%s). API Response: %s", grpID, detailResponse)) + } + + } + + for _, p := range removeProfileids { + getProfileOptions := iamidentityv1.GetProfileOptions{ + ProfileID: &p, + } + profileID, resp, err := iamClient.GetProfile(&getProfileOptions) + if err != nil || profileID == nil { + return diag.FromErr(fmt.Errorf("ERROR] Error Getting Profile Ids %s %s", err, resp)) + } + removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, *profileID.IamID) + detailResponse, err := iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error removing members to group(%s). API Response: %s", grpID, detailResponse)) + } + + } + } + + return resourceIBMIAMAccessGroupMembersRead(context, d, meta) + +} + +func resourceIBMIAMAccessGroupMembersDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + grpID := parts[0] + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + users := flex.ExpandStringList(d.Get("ibm_ids").(*schema.Set).List()) + + for _, name := range users { + + ibmUniqueID, err := flex.GetIBMUniqueId(userDetails.UserAccount, name, meta) + if err != nil { + return diag.FromErr(err) + } + + removeMembersFromAccessGroupOptions := iamAccessGroupsClient.NewRemoveMemberFromAccessGroupOptions(grpID, ibmUniqueID) + _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(err) + } + + } + + services := flex.ExpandStringList(d.Get("iam_service_ids").(*schema.Set).List()) + + for _, id := range services { + serviceID, err := getServiceID(id, meta) + if err != nil { + return diag.FromErr(err) + } + + removeMembersFromAccessGroupOptions := &iamaccessgroupsv2.RemoveMemberFromAccessGroupOptions{ + AccessGroupID: &grpID, + IamID: serviceID.IamID, + } + _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(err) + } + } + + profiles := flex.ExpandStringList(d.Get("iam_profile_ids").(*schema.Set).List()) + + for _, id := range profiles { + profileID, err := getProfileID(id, meta) + if err != nil { + return diag.FromErr(err) + } + + removeMembersFromAccessGroupOptions := &iamaccessgroupsv2.RemoveMemberFromAccessGroupOptions{ + AccessGroupID: &grpID, + IamID: profileID.IamID, + } + _, err = iamAccessGroupsClient.RemoveMemberFromAccessGroup(removeMembersFromAccessGroupOptions) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + + return nil +} + +func prepareMemberAddRequest(iamAccessGroupsClient *iamaccessgroupsv2.IamAccessGroupsV2, userIds, serviceIds, profileIds []string) (members []iamaccessgroupsv2.AddGroupMembersRequestMembersItem) { + members = make([]iamaccessgroupsv2.AddGroupMembersRequestMembersItem, len(userIds)+len(serviceIds)+len(profileIds)) + var i = 0 + userType := "user" + serviceType := "service" + profileType := "profile" + + for _, id := range userIds { + membersItem, err := iamAccessGroupsClient.NewAddGroupMembersRequestMembersItem(id, userType) + if err != nil { + log.Printf("Error in preparing membership data. %s", err) + } + members[i] = *membersItem + i++ + } + + for _, id := range serviceIds { + membersItem, err := iamAccessGroupsClient.NewAddGroupMembersRequestMembersItem(id, serviceType) + if err != nil || membersItem == nil { + log.Printf("Error in preparing membership data. %s", err) + } + members[i] = *membersItem + i++ + } + + for _, id := range profileIds { + membersItem, err := iamAccessGroupsClient.NewAddGroupMembersRequestMembersItem(id, profileType) + if err != nil || membersItem == nil { + log.Printf("Error in preparing membership data. %s", err) + } + members[i] = *membersItem + i++ + } + return +} +func getServiceID(id string, meta interface{}) (iamidentityv1.ServiceID, error) { + serviceids := iamidentityv1.ServiceID{} + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return serviceids, err + } + getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ + ID: &id, + } + serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) + if err != nil || serviceID == nil { + return serviceids, fmt.Errorf("ERROR] Error Getting Service Ids %s %s", err, resp) + } + return *serviceID, nil +} + +func FlattenServiceIds(services []string, meta interface{}) ([]string, error) { + serviceids := make([]string, len(services)) + for i, id := range services { + serviceID, err := getServiceID(id, meta) + if err != nil { + return nil, err + } + serviceids[i] = *serviceID.IamID + } + return serviceids, nil +} + +func FlattenProfileIds(profiles []string, meta interface{}) ([]string, error) { + profileids := make([]string, len(profiles)) + for i, id := range profiles { + profileID, err := getProfileID(id, meta) + if err != nil { + return nil, err + } + profileids[i] = *profileID.IamID + } + return profileids, nil +} + +func getProfileID(id string, meta interface{}) (iamidentityv1.TrustedProfile, error) { + profileids := iamidentityv1.TrustedProfile{} + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return profileids, err + } + getProfileOptions := iamidentityv1.GetProfileOptions{ + ProfileID: &id, + } + profileID, resp, err := iamClient.GetProfile(&getProfileOptions) + if err != nil || profileID == nil { + return profileids, fmt.Errorf("ERROR] Error Getting Profile Ids %s %s", err, resp) + } + return *profileID, nil +} diff --git a/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members_test.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members_test.go new file mode 100644 index 000000000..8d82e7868 --- /dev/null +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_members_test.go @@ -0,0 +1,303 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamaccessgroup_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMAccessGroupMember_Basic(t *testing.T) { + + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + sname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + sname1 := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + pname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + pname1 := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupMemberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupMemberBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupMemberAddServiceID(name, sname), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupMemberAddAnotherServiceID(name, sname, sname1), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "3"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupMemberAddProfileID(name, sname, sname1, pname), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "4"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupMemberAddAnotherProfileID(name, sname, sname1, pname, pname1), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "5"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupMemberRemoveUserSIDAndProfileID(name, sname, sname1, pname, pname1), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_members.accgroupmem", "members.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupMember_import(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + sname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + pname := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_access_group.accgroup" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupMemberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupMemberImport(name, sname, pname), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "iam_ids", + "iam_service_ids", + "iam_profile_ids", + }, + }, + }, + }) +} + +func testAccCheckIBMIAMAccessGroupMemberDestroy(s *terraform.State) error { + accClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_access_group_members" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + grpID := parts[0] + + // Try to find the members + listAccessGroupMembersOptions := &iamaccessgroupsv2.ListAccessGroupMembersOptions{ + AccessGroupID: &grpID, + } + _, detailResponse, err := accClient.ListAccessGroupMembers(listAccessGroupMembersOptions) + + if err != nil && detailResponse.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error waiting for access group members (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMAccessGroupMemberBasic(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + }`, name, acc.IAMUser) +} + +func testAccCheckIBMIAMAccessGroupMemberAddServiceID(name, sname string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + iam_service_ids = [ibm_iam_service_id.serviceID.id] + }`, name, sname, acc.IAMUser) +} + +func testAccCheckIBMIAMAccessGroupMemberAddAnotherServiceID(name, sname, sname1 string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID2" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + iam_service_ids = [ibm_iam_service_id.serviceID.id, ibm_iam_service_id.serviceID2.id] + }`, name, sname, sname1, acc.IAMUser) +} + +func testAccCheckIBMIAMAccessGroupMemberAddProfileID(name, sname, sname1, pname string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID2" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + iam_service_ids = [ibm_iam_service_id.serviceID.id, ibm_iam_service_id.serviceID2.id] + iam_profile_ids = [ibm_iam_trusted_profile.profileID.id] + }`, name, sname, sname1, pname, acc.IAMUser) +} + +func testAccCheckIBMIAMAccessGroupMemberAddAnotherProfileID(name, sname, sname1, pname, pname1 string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID2" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID2" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + iam_service_ids = [ibm_iam_service_id.serviceID.id, ibm_iam_service_id.serviceID2.id] + iam_profile_ids = [ibm_iam_trusted_profile.profileID.id, ibm_iam_trusted_profile.profileID2.id] + }`, name, sname, sname1, pname, pname1, acc.IAMUser) +} + +func testAccCheckIBMIAMAccessGroupMemberRemoveUserSIDAndProfileID(name, sname, sname1, pname, pname1 string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID2" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID2" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + iam_service_ids = [ibm_iam_service_id.serviceID.id] + iam_profile_ids = [ibm_iam_trusted_profile.profileID.id] + }`, name, sname, sname1, pname, pname1) +} + +func testAccCheckIBMIAMAccessGroupMemberImport(name, sname, pname string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgroup" { + name = "%s" + } + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_access_group_members" "accgroupmem" { + access_group_id = ibm_iam_access_group.accgroup.id + ibm_ids = ["%s"] + iam_service_ids = [ibm_iam_service_id.serviceID.id] + iam_profile_ids = [ibm_iam_trusted_profile.profileID.id] + }`, name, sname, pname, acc.IAMUser) +} diff --git a/ibm/resource_ibm_iam_access_group_test.go b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_test.go similarity index 87% rename from ibm/resource_ibm_iam_access_group_test.go rename to ibm/service/iamaccessgroup/resource_ibm_iam_access_group_test.go index 3ac6feb5e..9be0d83c4 100644 --- a/ibm/resource_ibm_iam_access_group_test.go +++ b/ibm/service/iamaccessgroup/resource_ibm_iam_access_group_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamaccessgroup_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,11 +22,11 @@ func TestAccIBMIAMAccessGroup_Basic(t *testing.T) { updateName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMAccessGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMAccessGroupBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMAccessGroupExists("ibm_iam_access_group.accgroup", conf), @@ -31,7 +34,7 @@ func TestAccIBMIAMAccessGroup_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMAccessGroupUpdateWithSameName(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMAccessGroupExists("ibm_iam_access_group.accgroup", conf), @@ -40,7 +43,7 @@ func TestAccIBMIAMAccessGroup_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "tags.#", "3"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMAccessGroupUpdate(updateName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_access_group.accgroup", "name", updateName), @@ -58,11 +61,11 @@ func TestAccIBMIAMAccessGroup_import(t *testing.T) { resourceName := "ibm_iam_access_group.accgroup" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMAccessGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMAccessGroupTag(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMAccessGroupExists(resourceName, conf), @@ -70,7 +73,7 @@ func TestAccIBMIAMAccessGroup_import(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "AccessGroup for test scenario2"), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -80,7 +83,7 @@ func TestAccIBMIAMAccessGroup_import(t *testing.T) { } func testAccCheckIBMIAMAccessGroupDestroy(s *terraform.State) error { - accClient, err := testAccProvider.Meta().(ClientSession).IAMAccessGroupsV2() + accClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() if err != nil { return err } @@ -95,12 +98,11 @@ func testAccCheckIBMIAMAccessGroupDestroy(s *terraform.State) error { getAccessGroupOptions := &iamaccessgroupsv2.GetAccessGroupOptions{ AccessGroupID: &agID, } - _, detailResponse, _ := accClient.GetAccessGroup(getAccessGroupOptions) - + _, detailResponse, err := accClient.GetAccessGroup(getAccessGroupOptions) if err == nil { return fmt.Errorf("Access group still exists: %s", rs.Primary.ID) } else if detailResponse.StatusCode != 404 { - return fmt.Errorf("Error waiting for access group (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for access group (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -115,7 +117,7 @@ func testAccCheckIBMIAMAccessGroupExists(n string, obj iamaccessgroupsv2.Group) return fmt.Errorf("Not found: %s", n) } - accClient, err := testAccProvider.Meta().(ClientSession).IAMAccessGroupsV2() + accClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() if err != nil { return err } diff --git a/ibm/service/iamidentity/README.md b/ibm/service/iamidentity/README.md new file mode 100644 index 000000000..8f5383382 --- /dev/null +++ b/ibm/service/iamidentity/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider IAM Identity Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the IAM Identity Services resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_account_settings) +* IBM API Docs: [IBM API Docs for IAM Identity Services](https://cloud.ibm.com/apidocs/iam-identity-token-api) +* IBM IAM Identity Services SDK: [IBM SDK for IAM Identity Services](https://github.com/IBM/platform-services-go-sdk/tree/main/iamidentityv1) diff --git a/ibm/data_source_ibm_iam_account_settings.go b/ibm/service/iamidentity/data_source_ibm_iam_account_settings.go similarity index 78% rename from ibm/data_source_ibm_iam_account_settings.go rename to ibm/service/iamidentity/data_source_ibm_iam_account_settings.go index 378c124f4..1fbe2ed65 100644 --- a/ibm/data_source_ibm_iam_account_settings.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_account_settings.go @@ -1,87 +1,88 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/iamidentityv1" ) -func dataSourceIBMIAMAccountSettings() *schema.Resource { +func DataSourceIBMIAMAccountSettings() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIamAccountSettingsRead, Schema: map[string]*schema.Schema{ - "include_history": &schema.Schema{ + "include_history": { Type: schema.TypeBool, Optional: true, Default: false, Description: "Defines if the entity history is included in the response.", }, - "account_id": &schema.Schema{ + "account_id": { Type: schema.TypeString, Computed: true, Description: "Unique ID of the account.", }, - "restrict_create_service_id": &schema.Schema{ + "restrict_create_service_id": { Type: schema.TypeString, Computed: true, Description: "Defines whether or not creating a Service Id is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", }, - "restrict_create_platform_apikey": &schema.Schema{ + "restrict_create_platform_apikey": { Type: schema.TypeString, Computed: true, Description: "Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", }, - "allowed_ip_addresses": &schema.Schema{ + "allowed_ip_addresses": { Type: schema.TypeString, Computed: true, Description: "Defines the IP addresses and subnets from which IAM tokens can be created for the account.", }, - "entity_tag": &schema.Schema{ + "entity_tag": { Type: schema.TypeString, Computed: true, Description: "Version of the account settings.", }, - "mfa": &schema.Schema{ + "mfa": { Type: schema.TypeString, Computed: true, Description: "Defines the MFA trait for the account. Valid values: * NONE - No MFA trait set * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users.", }, - "history": &schema.Schema{ + "history": { Type: schema.TypeList, Computed: true, Description: "History of the Account Settings.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "timestamp": &schema.Schema{ + "timestamp": { Type: schema.TypeString, Computed: true, Description: "Timestamp when the action was triggered.", }, - "iam_id": &schema.Schema{ + "iam_id": { Type: schema.TypeString, Computed: true, Description: "IAM ID of the identity which triggered the action.", }, - "iam_id_account": &schema.Schema{ + "iam_id_account": { Type: schema.TypeString, Computed: true, Description: "Account of the identity which triggered the action.", }, - "action": &schema.Schema{ + "action": { Type: schema.TypeString, Computed: true, Description: "Action of the history entry.", }, - "params": &schema.Schema{ + "params": { Type: schema.TypeList, Computed: true, Description: "Params of the history entry.", @@ -89,7 +90,7 @@ func dataSourceIBMIAMAccountSettings() *schema.Resource { Type: schema.TypeString, }, }, - "message": &schema.Schema{ + "message": { Type: schema.TypeString, Computed: true, Description: "Message which summarizes the executed action.", @@ -97,17 +98,17 @@ func dataSourceIBMIAMAccountSettings() *schema.Resource { }, }, }, - "session_expiration_in_seconds": &schema.Schema{ + "session_expiration_in_seconds": { Type: schema.TypeString, Computed: true, Description: "Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default.", }, - "session_invalidation_in_seconds": &schema.Schema{ + "session_invalidation_in_seconds": { Type: schema.TypeString, Computed: true, Description: "Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default.", }, - "max_sessions_per_identity": &schema.Schema{ + "max_sessions_per_identity": { Type: schema.TypeString, Computed: true, Description: "Defines the max allowed sessions per identity required by the account. Value values: * Any whole number greater than '0' * NOT_SET - To unset account setting and use service default.", @@ -117,7 +118,7 @@ func dataSourceIBMIAMAccountSettings() *schema.Resource { } func dataSourceIbmIamAccountSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -125,12 +126,12 @@ func dataSourceIbmIamAccountSettingsRead(context context.Context, d *schema.Reso getAccountSettingsOptions := &iamidentityv1.GetAccountSettingsOptions{} getAccountSettingsOptions.SetIncludeHistory(d.Get("include_history").(bool)) - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return diag.FromErr(err) } - getAccountSettingsOptions.SetAccountID(userDetails.userAccount) + getAccountSettingsOptions.SetAccountID(userDetails.UserAccount) accountSettingsResponse, response, err := iamIdentityClient.GetAccountSettings(getAccountSettingsOptions) if err != nil { @@ -138,41 +139,41 @@ func dataSourceIbmIamAccountSettingsRead(context context.Context, d *schema.Reso return diag.FromErr(err) } - d.SetId(userDetails.userAccount) + d.SetId(userDetails.UserAccount) if err = d.Set("account_id", accountSettingsResponse.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) } if err = d.Set("restrict_create_service_id", accountSettingsResponse.RestrictCreateServiceID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting restrict_create_service_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting restrict_create_service_id: %s", err)) } if err = d.Set("restrict_create_platform_apikey", accountSettingsResponse.RestrictCreatePlatformApikey); err != nil { - return diag.FromErr(fmt.Errorf("Error setting restrict_create_platform_apikey: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting restrict_create_platform_apikey: %s", err)) } if err = d.Set("allowed_ip_addresses", accountSettingsResponse.AllowedIPAddresses); err != nil { - return diag.FromErr(fmt.Errorf("Error setting allowed_ip_addresses: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allowed_ip_addresses: %s", err)) } if err = d.Set("entity_tag", accountSettingsResponse.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) } if err = d.Set("mfa", accountSettingsResponse.Mfa); err != nil { - return diag.FromErr(fmt.Errorf("Error setting mfa: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting mfa: %s", err)) } if accountSettingsResponse.History != nil { err = d.Set("history", dataSourceAccountSettingsResponseFlattenHistory(accountSettingsResponse.History)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting history %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting history %s", err)) } } if err = d.Set("session_expiration_in_seconds", accountSettingsResponse.SessionExpirationInSeconds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting session_expiration_in_seconds: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting session_expiration_in_seconds: %s", err)) } if err = d.Set("session_invalidation_in_seconds", accountSettingsResponse.SessionInvalidationInSeconds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting session_invalidation_in_seconds: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting session_invalidation_in_seconds: %s", err)) } if err = d.Set("max_sessions_per_identity", accountSettingsResponse.MaxSessionsPerIdentity); err != nil { - return diag.FromErr(fmt.Errorf("Error setting max_sessions_per_identity: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting max_sessions_per_identity: %s", err)) } return nil diff --git a/ibm/data_source_ibm_iam_account_settings_test.go b/ibm/service/iamidentity/data_source_ibm_iam_account_settings_test.go similarity index 90% rename from ibm/data_source_ibm_iam_account_settings_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_account_settings_test.go index 92b94018c..57b146da6 100644 --- a/ibm/data_source_ibm_iam_account_settings_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_account_settings_test.go @@ -1,21 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMIAMAccountSettingsDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsDataSourceConfigBasic(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_account_settings.iam_account_settings", "id"), diff --git a/ibm/service/iamidentity/data_source_ibm_iam_api_key.go b/ibm/service/iamidentity/data_source_ibm_iam_api_key.go new file mode 100644 index 000000000..f78b45325 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_api_key.go @@ -0,0 +1,132 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamApiKey() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmIamApiKeyRead, + + Schema: map[string]*schema.Schema{ + "apikey_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique ID of the API key.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678'.", + }, + "locked": { + Type: schema.TypeBool, + Computed: true, + Description: "The API key cannot be changed if set to true.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the user or service which created the API key.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the API key. The name is not checked for uniqueness. Therefore multiple names with the same value can exist. Access is done via the UUID of the API key.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The optional description of the API key. The 'description' property is only available if a description was provided during a create of an API key.", + }, + "iam_id": { + Type: schema.TypeString, + Computed: true, + Description: "The iam_id that this API key authenticates.", + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the account that this API key authenticates for.", + }, + }, + } +} + +func dataSourceIbmIamApiKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + getApiKeyOptions := &iamidentityv1.GetAPIKeyOptions{} + + getApiKeyOptions.SetID(d.Get("apikey_id").(string)) + + apiKey, response, err := iamIdentityClient.GetAPIKey(getApiKeyOptions) + if err != nil { + log.Printf("[DEBUG] GetApiKey failed %s\n%s", err, response) + return diag.FromErr(err) + } + + d.SetId(*apiKey.ID) + + if err = d.Set("entity_tag", apiKey.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) + } + if err = d.Set("crn", apiKey.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("locked", apiKey.Locked); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting locked: %s", err)) + } + if err = d.Set("created_at", apiKey.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", apiKey.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("modified_at", apiKey.ModifiedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) + } + if err = d.Set("name", apiKey.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", apiKey.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("iam_id", apiKey.IamID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting iam_id: %s", err)) + } + if err = d.Set("account_id", apiKey.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) + } + + return nil +} diff --git a/ibm/data_source_ibm_iam_api_key_test.go b/ibm/service/iamidentity/data_source_ibm_iam_api_key_test.go similarity index 93% rename from ibm/data_source_ibm_iam_api_key_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_api_key_test.go index 6185fd079..70d03a5ea 100644 --- a/ibm/data_source_ibm_iam_api_key_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_api_key_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIbmIamApiKeyDataSourceBasic(t *testing.T) { apiKeyName := fmt.Sprintf("name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyDataSourceConfigBasic(apiKeyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_api_key.iam_api_key", "apikey_id"), @@ -45,10 +47,10 @@ func TestAccIbmIamApiKeyDataSourceAllArgs(t *testing.T) { apiKeyStoreValue := "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyDataSourceConfig(apiKeyName, apiKeyDescription, apiKeyStoreValue), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_api_key.iam_api_key", "apikey_id"), diff --git a/ibm/data_source_ibm_iam_auth_token.go b/ibm/service/iamidentity/data_source_ibm_iam_auth_token.go similarity index 85% rename from ibm/data_source_ibm_iam_auth_token.go rename to ibm/service/iamidentity/data_source_ibm_iam_auth_token.go index b6d41286b..3bfc69211 100644 --- a/ibm/data_source_ibm_iam_auth_token.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_auth_token.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMIAMAuthToken() *schema.Resource { +func DataSourceIBMIAMAuthToken() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMIAMAuthTokenRead, @@ -38,7 +39,7 @@ func dataSourceIBMIAMAuthToken() *schema.Resource { } func dataSourceIBMIAMAuthTokenRead(d *schema.ResourceData, meta interface{}) error { - bmxSess, err := meta.(ClientSession).BluemixSession() + bmxSess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return err } diff --git a/ibm/service/iamidentity/data_source_ibm_iam_service_id.go b/ibm/service/iamidentity/data_source_ibm_iam_service_id.go new file mode 100644 index 000000000..e5b44d406 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_service_id.go @@ -0,0 +1,154 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIAMServiceID() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMServiceIDRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Name of the serviceID", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_service_id", + "name"), + }, + + "service_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + + "bound_to": { + Description: "bound to of the serviceID", + Type: schema.TypeString, + Computed: true, + Deprecated: "bound_to attribute in service_ids list has been deprecated", + }, + + "crn": { + Description: "CRN of the serviceID", + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Description: "description of the serviceID", + Type: schema.TypeString, + Computed: true, + }, + + "version": { + Description: "Version of the serviceID", + Type: schema.TypeString, + Computed: true, + }, + + "locked": { + Description: "lock state of the serviceID", + Type: schema.TypeBool, + Computed: true, + }, + + "iam_id": { + Description: "The IAM ID of the serviceID", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMIAMServiceIDValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:service_id", "resolved_to:name"}, + Required: true}) + + iBMIAMServiceIDValidator := validate.ResourceValidator{ResourceName: "ibm_iam_service_id", Schema: validateSchema} + return &iBMIAMServiceIDValidator +} + +func dataSourceIBMIAMServiceIDRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get("name").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + + start := "" + allrecs := []iamidentityv1.ServiceID{} + var pg int64 = 100 + for { + listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ + AccountID: &userDetails.UserAccount, + Pagesize: &pg, + Name: &name, + } + if start != "" { + listServiceIDOptions.Pagetoken = &start + } + + serviceIDs, resp, err := iamClient.ListServiceIds(&listServiceIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) + } + start = flex.GetNextIAM(serviceIDs.Next) + allrecs = append(allrecs, serviceIDs.Serviceids...) + if start == "" { + break + } + } + if len(allrecs) == 0 { + return fmt.Errorf("[ERROR] No serviceID found with name [%s]", name) + + } + + serviceIDListMap := make([]map[string]interface{}, 0, len(allrecs)) + for _, serviceID := range allrecs { + l := map[string]interface{}{ + "id": serviceID.ID, + // "bound_to": serviceID.BoundTo, + "version": serviceID.EntityTag, + "description": serviceID.Description, + "crn": serviceID.CRN, + "locked": serviceID.Locked, + "iam_id": serviceID.IamID, + } + serviceIDListMap = append(serviceIDListMap, l) + } + d.SetId(name) + d.Set("service_ids", serviceIDListMap) + return nil +} diff --git a/ibm/data_source_ibm_iam_service_id_test.go b/ibm/service/iamidentity/data_source_ibm_iam_service_id_test.go similarity index 88% rename from ibm/data_source_ibm_iam_service_id_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_service_id_test.go index 75da1fbf8..00ef54cb8 100644 --- a/ibm/data_source_ibm_iam_service_id_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_service_id_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMIAMServiceIDDataSource_basic(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMIAMServiceIDDataSourceConfig(name), @@ -34,8 +36,8 @@ func TestAccIBMIAMServiceIDDataSource_same_name(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMIAMServiceIDDataSourceSameName(name), diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile.go new file mode 100644 index 000000000..61ff80cd1 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile.go @@ -0,0 +1,231 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfile() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the trusted profile to get.", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile", + "profile_id"), + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The optional description of the trusted profile. The 'description' property is only available if a description was provided during a create of a trusted profile.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "iam_id": { + Type: schema.TypeString, + Computed: true, + Description: "The iam_id of this trusted profile.", + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the account that this trusted profile belong to.", + }, + "ims_account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "IMS acount ID of the trusted profile.", + }, + "ims_user_id": { + Type: schema.TypeInt, + Computed: true, + Description: "IMS user ID of the trusted profile.", + }, + "history": { + Type: schema.TypeList, + Computed: true, + Description: "History of the trusted profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "timestamp": { + Type: schema.TypeString, + Computed: true, + Description: "Timestamp when the action was triggered.", + }, + "iam_id": { + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the identity which triggered the action.", + }, + "iam_id_account": { + Type: schema.TypeString, + Computed: true, + Description: "Account of the identity which triggered the action.", + }, + "action": { + Type: schema.TypeString, + Computed: true, + Description: "Action of the history entry.", + }, + "params": { + Type: schema.TypeList, + Computed: true, + Description: "Params of the history entry.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "Message which summarizes the executed action.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIamTrustedProfileValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIamTrustedProfileValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile", Schema: validateSchema} + return &iBMIamTrustedProfileValidator +} + +func dataSourceIBMIamTrustedProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + getProfileOptions := &iamidentityv1.GetProfileOptions{} + + getProfileOptions.SetProfileID(d.Get("profile_id").(string)) + + trustedProfile, response, err := iamIdentityClient.GetProfile(getProfileOptions) + if err != nil { + log.Printf("[DEBUG] GetProfile failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetProfile failed %s\n%s", err, response)) + } + + d.SetId(*trustedProfile.ID) + + if err = d.Set("entity_tag", trustedProfile.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) + } + if err = d.Set("crn", trustedProfile.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("name", trustedProfile.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", trustedProfile.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(trustedProfile.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("modified_at", flex.DateTimeToString(trustedProfile.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) + } + if err = d.Set("iam_id", trustedProfile.IamID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting iam_id: %s", err)) + } + if err = d.Set("account_id", trustedProfile.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) + } + if err = d.Set("ims_account_id", flex.IntValue(trustedProfile.ImsAccountID)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ims_account_id: %s", err)) + } + if err = d.Set("ims_user_id", flex.IntValue(trustedProfile.ImsUserID)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ims_user_id: %s", err)) + } + + err = d.Set("history", dataSourceTrustedProfileFlattenHistory(trustedProfile.History)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting history %s", err)) + } + + return nil +} + +func dataSourceTrustedProfileFlattenHistory(result []iamidentityv1.EnityHistoryRecord) (history []map[string]interface{}) { + for _, historyItem := range result { + history = append(history, dataSourceTrustedProfileHistoryToMap(historyItem)) + } + + return history +} + +func dataSourceTrustedProfileHistoryToMap(historyItem iamidentityv1.EnityHistoryRecord) (historyMap map[string]interface{}) { + historyMap = map[string]interface{}{} + + if historyItem.Timestamp != nil { + historyMap["timestamp"] = historyItem.Timestamp + } + if historyItem.IamID != nil { + historyMap["iam_id"] = historyItem.IamID + } + if historyItem.IamIDAccount != nil { + historyMap["iam_id_account"] = historyItem.IamIDAccount + } + if historyItem.Action != nil { + historyMap["action"] = historyItem.Action + } + if historyItem.Params != nil { + historyMap["params"] = historyItem.Params + } + if historyItem.Message != nil { + historyMap["message"] = historyItem.Message + } + + return historyMap +} diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule.go new file mode 100644 index 000000000..721c98c07 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule.go @@ -0,0 +1,194 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfileClaimRule() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileClaimRuleRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the trusted profile.", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile_claim_rule", + "profile_id"), + }, + "rule_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the claim rule to get.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "version of the claim rule.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The optional claim rule name.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the Calim rule, either 'Profile-SAML' or 'Profile-CR'.", + }, + "realm_name": { + Type: schema.TypeString, + Computed: true, + Description: "The realm name of the Idp this claim rule applies to.", + }, + "expiration": { + Type: schema.TypeInt, + Computed: true, + Description: "Session expiration in seconds.", + }, + "cr_type": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA.", + }, + "conditions": { + Type: schema.TypeList, + Computed: true, + Description: "Conditions of this claim rule.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "claim": { + Type: schema.TypeString, + Computed: true, + Description: "The claim to evaluate against.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "The stringified JSON value that the claim is compared to using the operator.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIamTrustedProfileClaimRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIamTrustedProfileClaimRuleValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_claim_rule", Schema: validateSchema} + return &iBMIamTrustedProfileClaimRuleValidator +} + +func dataSourceIBMIamTrustedProfileClaimRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + getClaimRuleOptions := &iamidentityv1.GetClaimRuleOptions{} + + getClaimRuleOptions.SetProfileID(d.Get("profile_id").(string)) + getClaimRuleOptions.SetRuleID(d.Get("rule_id").(string)) + + profileClaimRule, response, err := iamIdentityClient.GetClaimRule(getClaimRuleOptions) + if err != nil { + log.Printf("[DEBUG] GetClaimRule failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetClaimRule failed %s\n%s", err, response)) + } + d.SetId(fmt.Sprintf("%s/%s", *getClaimRuleOptions.ProfileID, *profileClaimRule.ID)) + if err = d.Set("entity_tag", profileClaimRule.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(profileClaimRule.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("modified_at", flex.DateTimeToString(profileClaimRule.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) + } + if err = d.Set("name", profileClaimRule.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("type", profileClaimRule.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("realm_name", profileClaimRule.RealmName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting realm_name: %s", err)) + } + if err = d.Set("expiration", flex.IntValue(profileClaimRule.Expiration)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting expiration: %s", err)) + } + if err = d.Set("cr_type", profileClaimRule.CrType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cr_type: %s", err)) + } + + if profileClaimRule.Conditions != nil { + err = d.Set("conditions", dataSourceProfileClaimRuleFlattenConditions(profileClaimRule.Conditions)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting conditions %s", err)) + } + } + + return nil +} + +func dataSourceProfileClaimRuleFlattenConditions(result []iamidentityv1.ProfileClaimRuleConditions) (conditions []map[string]interface{}) { + for _, conditionsItem := range result { + conditions = append(conditions, dataSourceProfileClaimRuleConditionsToMap(conditionsItem)) + } + + return conditions +} + +func dataSourceProfileClaimRuleConditionsToMap(conditionsItem iamidentityv1.ProfileClaimRuleConditions) (conditionsMap map[string]interface{}) { + conditionsMap = map[string]interface{}{} + + if conditionsItem.Claim != nil { + conditionsMap["claim"] = conditionsItem.Claim + } + if conditionsItem.Operator != nil { + conditionsMap["operator"] = conditionsItem.Operator + } + if conditionsItem.Value != nil { + conditionsMap["value"] = conditionsItem.Value + } + + return conditionsMap +} diff --git a/ibm/data_source_ibm_iam_trusted_profile_claim_rule_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule_test.go similarity index 92% rename from ibm/data_source_ibm_iam_trusted_profile_claim_rule_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule_test.go index 0226a3b38..b9fba49f1 100644 --- a/ibm/data_source_ibm_iam_trusted_profile_claim_rule_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_claim_rule_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMIAMTrustedProfileClaimRuleDataSourceBasic(t *testing.T) { profileClaimRuleProfileID := fmt.Sprintf("tf_profile_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckIAMTrustedProfile(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckIAMTrustedProfile(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileClaimRuleDataSourceConfigBasic(profileClaimRuleProfileID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", "id"), @@ -37,10 +39,10 @@ func TestAccIBMIAMTrustedProfileClaimRuleDataSourceAllArgs(t *testing.T) { profileClaimRuleProfileID := fmt.Sprintf("tf_profile_id_%d", acctest.RandIntRange(10, 100)) profileClaimRuleName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckIAMTrustedProfile(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckIAMTrustedProfile(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileClaimRuleDataSourceConfig(profileClaimRuleProfileID, profileClaimRuleName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", "id"), @@ -77,7 +79,7 @@ func testAccCheckIBMIamTrustedProfileClaimRuleDataSourceConfigBasic(profileClaim profile_id = ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule.profile_id rule_id = ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule.rule_id } - `, profileClaimRuleProfileID, realmName) + `, profileClaimRuleProfileID, acc.RealmName) } func testAccCheckIBMIamTrustedProfileClaimRuleDataSourceConfig(profileClaimRuleProfileID string, profileClaimRuleName string) string { diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link.go new file mode 100644 index 000000000..7aa528bf5 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link.go @@ -0,0 +1,170 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfileLink() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileLinkRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the trusted profile.", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile_link", + "profile_id"), + }, + "link_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the link.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "version of the claim rule.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name of the Link.", + }, + "cr_type": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + }, + "link": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the compute resource.", + }, + "namespace": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIamTrustedProfileLinkValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIamTrustedProfileLinkValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_link", Schema: validateSchema} + return &iBMIamTrustedProfileLinkValidator +} + +func dataSourceIBMIamTrustedProfileLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + getLinkOptions := &iamidentityv1.GetLinkOptions{} + + getLinkOptions.SetProfileID(d.Get("profile_id").(string)) + getLinkOptions.SetLinkID(d.Get("link_id").(string)) + + profileLink, response, err := iamIdentityClient.GetLink(getLinkOptions) + if err != nil { + log.Printf("[DEBUG] GetLink failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLink failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getLinkOptions.ProfileID, *getLinkOptions.LinkID)) + if err = d.Set("entity_tag", profileLink.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(profileLink.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("modified_at", flex.DateTimeToString(profileLink.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) + } + if err = d.Set("name", profileLink.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("cr_type", profileLink.CrType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cr_type: %s", err)) + } + + if profileLink.Link != nil { + err = d.Set("link", dataSourceProfileLinkFlattenLink(*profileLink.Link)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting link %s", err)) + } + } + + return nil +} + +func dataSourceProfileLinkFlattenLink(result iamidentityv1.ProfileLinkLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceProfileLinkLinkToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceProfileLinkLinkToMap(linkItem iamidentityv1.ProfileLinkLink) (linkMap map[string]interface{}) { + linkMap = map[string]interface{}{} + + if linkItem.CRN != nil { + linkMap["crn"] = linkItem.CRN + } + if linkItem.Namespace != nil { + linkMap["namespace"] = linkItem.Namespace + } + if linkItem.Name != nil { + linkMap["name"] = linkItem.Name + } + + return linkMap +} diff --git a/ibm/data_source_ibm_iam_trusted_profile_link_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link_test.go similarity index 91% rename from ibm/data_source_ibm_iam_trusted_profile_link_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link_test.go index c6d0b87b8..47fc32206 100644 --- a/ibm/data_source_ibm_iam_trusted_profile_link_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_link_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMIAMTrustedProfileLinkDataSourceBasic(t *testing.T) { profileLinkCrType := "IKS_SA" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileLinkDataSourceConfigBasic(profileLinkProfileName, profileLinkCrType), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_link.iam_trusted_profile_link", "id"), @@ -42,10 +44,10 @@ func TestAccIBMIAMTrustedProfileLinkDataSourceAllArgs(t *testing.T) { profileLinkName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileLinkDataSourceConfig(profileLinkProfileName, profileLinkCrType, profileLinkName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_link.iam_trusted_profile_link", "id"), @@ -82,7 +84,7 @@ func testAccCheckIBMIamTrustedProfileLinkDataSourceConfigBasic(profileLinkProfil profile_id = ibm_iam_trusted_profile_link.iam_trusted_profile_link.profile_id link_id = ibm_iam_trusted_profile_link.iam_trusted_profile_link.link_id } - `, profileLinkProfileName, profileLinkCrType, iksSa) + `, profileLinkProfileName, profileLinkCrType, acc.IksSa) } func testAccCheckIBMIamTrustedProfileLinkDataSourceConfig(profileLinkProfileName string, profileLinkCrType string, profileLinkName string) string { @@ -105,5 +107,5 @@ func testAccCheckIBMIamTrustedProfileLinkDataSourceConfig(profileLinkProfileName profile_id = ibm_iam_trusted_profile_link.iam_trusted_profile_link.profile_id link_id = ibm_iam_trusted_profile_link.iam_trusted_profile_link.link_id } - `, profileLinkProfileName, profileLinkCrType, iksSa, profileLinkName) + `, profileLinkProfileName, profileLinkCrType, acc.IksSa, profileLinkName) } diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links.go new file mode 100644 index 000000000..5bb9d20bd --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links.go @@ -0,0 +1,199 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfileLinks() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileLinkListRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the trusted profile.", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile_links", + "profile_id"), + }, + "links": { + Type: schema.TypeList, + Computed: true, + Description: "List of links to a trusted profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "the unique identifier of the claim rule.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "version of the claim rule.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Optional name of the Link.", + }, + "cr_type": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + }, + "link": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the compute resource.", + }, + "namespace": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIamTrustedProfileLinksValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIamTrustedProfileLinksValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_links", Schema: validateSchema} + return &iBMIamTrustedProfileLinksValidator +} + +func dataSourceIBMIamTrustedProfileLinkListRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + listLinkOptions := &iamidentityv1.ListLinksOptions{} + + listLinkOptions.SetProfileID(d.Get("profile_id").(string)) + + profileLinkList, response, err := iamIdentityClient.ListLinks(listLinkOptions) + if err != nil { + log.Printf("[DEBUG] ListLink failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLink failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIamTrustedProfileLinkListID(d)) + + if profileLinkList.Links != nil { + err = d.Set("links", dataSourceProfileLinkListFlattenLinks(profileLinkList.Links)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting links %s", err)) + } + } + + return nil +} + +// dataSourceIBMIamTrustedProfileLinkListID returns a reasonable ID for the list. +func dataSourceIBMIamTrustedProfileLinkListID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceProfileLinkListFlattenLinks(result []iamidentityv1.ProfileLink) (links []map[string]interface{}) { + for _, linksItem := range result { + links = append(links, dataSourceProfileLinkListLinksToMap(linksItem)) + } + + return links +} + +func dataSourceProfileLinkListLinksToMap(linksItem iamidentityv1.ProfileLink) (linksMap map[string]interface{}) { + linksMap = map[string]interface{}{} + + if linksItem.ID != nil { + linksMap["id"] = linksItem.ID + } + if linksItem.EntityTag != nil { + linksMap["entity_tag"] = linksItem.EntityTag + } + if linksItem.CreatedAt != nil { + linksMap["created_at"] = linksItem.CreatedAt.String() + } + if linksItem.ModifiedAt != nil { + linksMap["modified_at"] = linksItem.ModifiedAt.String() + } + if linksItem.Name != nil { + linksMap["name"] = linksItem.Name + } + if linksItem.CrType != nil { + linksMap["cr_type"] = linksItem.CrType + } + if linksItem.Link != nil { + linkList := []map[string]interface{}{} + linkMap := dataSourceProfileLinkListLinksLinkToMap(*linksItem.Link) + linkList = append(linkList, linkMap) + linksMap["link"] = linkList + } + + return linksMap +} + +func dataSourceProfileLinkListLinksLinkToMap(linkItem iamidentityv1.ProfileLinkLink) (linkMap map[string]interface{}) { + linkMap = map[string]interface{}{} + + if linkItem.CRN != nil { + linkMap["crn"] = linkItem.CRN + } + if linkItem.Namespace != nil { + linkMap["namespace"] = linkItem.Namespace + } + if linkItem.Name != nil { + linkMap["name"] = linkItem.Name + } + + return linkMap +} diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links_test.go new file mode 100644 index 000000000..932397830 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_links_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIamTrustedProfileLinksDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIamTrustedProfileLinksDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_links.iam_trusted_profile_links", "id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_links.iam_trusted_profile_links", "profile_id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_links.iam_trusted_profile_links", "links.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIamTrustedProfileLinksDataSourceConfigBasic() string { + return ` + data "ibm_iam_trusted_profile_links" "iam_trusted_profile_links" { + profile_id = "profile_id" + } + ` +} diff --git a/ibm/data_source_ibm_iam_trusted_profile_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_test.go similarity index 94% rename from ibm/data_source_ibm_iam_trusted_profile_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_test.go index 3cd6d183b..863b793de 100644 --- a/ibm/data_source_ibm_iam_trusted_profile_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profile_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMIAMTrustedProfileDataSourceBasic(t *testing.T) { trustedProfileName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileDataSourceConfigBasic(trustedProfileName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile.iam_trusted_profile", "id"), @@ -40,10 +42,10 @@ func TestAccIBMIAMTrustedProfileDataSourceAllArgs(t *testing.T) { trustedProfileDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileDataSourceConfig(trustedProfileName, trustedProfileDescription), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile.iam_trusted_profile", "id"), diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles.go new file mode 100644 index 000000000..2de33c094 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles.go @@ -0,0 +1,311 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileListRead, + + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Optional: true, + Description: "Account ID to query for trusted profiles.", + }, + "name": { + Description: "Name of the profile", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profiles", + "name"), + }, + "include_history": { + Description: "Defines if the entity history is included in the response. Default is false", + Type: schema.TypeBool, + Optional: true, + }, + "profiles": { + Type: schema.TypeList, + Computed: true, + Description: "List of trusted profiles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "the unique identifier of the trusted profile. Example:'Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The optional description of the trusted profile. The 'description' property is only available if a description was provided during a create of a trusted profile.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "iam_id": { + Type: schema.TypeString, + Computed: true, + Description: "The iam_id of this trusted profile.", + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the account that this trusted profile belong to.", + }, + "ims_account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "IMS acount ID of the trusted profile.", + }, + "ims_user_id": { + Type: schema.TypeInt, + Computed: true, + Description: "IMS user ID of the trusted profile.", + }, + "history": { + Type: schema.TypeList, + Computed: true, + Description: "History of the trusted profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "timestamp": { + Type: schema.TypeString, + Computed: true, + Description: "Timestamp when the action was triggered.", + }, + "iam_id": { + Type: schema.TypeString, + Computed: true, + Description: "IAM ID of the identity which triggered the action.", + }, + "iam_id_account": { + Type: schema.TypeString, + Computed: true, + Description: "Account of the identity which triggered the action.", + }, + "action": { + Type: schema.TypeString, + Computed: true, + Description: "Action of the history entry.", + }, + "params": { + Type: schema.TypeList, + Computed: true, + Description: "Params of the history entry.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "Message which summarizes the executed action.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIamTrustedProfilesValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:name"}, + Optional: true}) + + iBMIamTrustedProfilesValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profiles", Schema: validateSchema} + return &iBMIamTrustedProfilesValidator +} + +func dataSourceIBMIamTrustedProfileListRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []iamidentityv1.TrustedProfile{} + accountID := userDetails.UserAccount + for { + listProfileOptions := &iamidentityv1.ListProfilesOptions{} + + if v, ok := d.GetOk("account_id"); ok { + listProfileOptions.SetAccountID(v.(string)) + } else { + listProfileOptions.SetAccountID(accountID) + } + + if v, ok := d.GetOk("name"); ok { + listProfileOptions.SetName(v.(string)) + } + + if v, ok := d.GetOk("include_history"); ok { + listProfileOptions.SetIncludeHistory(v.(bool)) + } + + listProfileOptions.SetPagesize(int64(100)) + + if start != "" { + listProfileOptions.Pagetoken = &start + } + + trustedProfiles, response, err := iamIdentityClient.ListProfiles(listProfileOptions) + if err != nil { + log.Printf("[DEBUG] ListProfile failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListProfile failed %s\n%s", err, response)) + } + start = flex.GetNextIAM(trustedProfiles.Next) + allrecs = append(allrecs, trustedProfiles.Profiles...) + if start == "" { + break + } + } + if len(allrecs) == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] No profiles found [%s]", accountID)) + + } + + d.SetId(dataSourceIBMIamTrustedProfileListID(d)) + + d.Set("profiles", dataSourceTrustedProfilesListFlattenProfiles(allrecs)) + + return nil +} + +// dataSourceIBMIamTrustedProfileListID returns a reasonable ID for the list. +func dataSourceIBMIamTrustedProfileListID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceTrustedProfilesListFlattenProfiles(result []iamidentityv1.TrustedProfile) (profiles []map[string]interface{}) { + for _, profilesItem := range result { + profiles = append(profiles, dataSourceTrustedProfilesListProfilesToMap(profilesItem)) + } + + return profiles +} + +func dataSourceTrustedProfilesListProfilesToMap(profilesItem iamidentityv1.TrustedProfile) (profilesMap map[string]interface{}) { + profilesMap = map[string]interface{}{} + + if profilesItem.ID != nil { + profilesMap["id"] = profilesItem.ID + } + if profilesItem.EntityTag != nil { + profilesMap["entity_tag"] = profilesItem.EntityTag + } + if profilesItem.CRN != nil { + profilesMap["crn"] = profilesItem.CRN + } + if profilesItem.Name != nil { + profilesMap["name"] = profilesItem.Name + } + if profilesItem.Description != nil { + profilesMap["description"] = profilesItem.Description + } + if profilesItem.CreatedAt != nil { + profilesMap["created_at"] = profilesItem.CreatedAt.String() + } + if profilesItem.ModifiedAt != nil { + profilesMap["modified_at"] = profilesItem.ModifiedAt.String() + } + if profilesItem.IamID != nil { + profilesMap["iam_id"] = profilesItem.IamID + } + if profilesItem.AccountID != nil { + profilesMap["account_id"] = profilesItem.AccountID + } + if profilesItem.ImsAccountID != nil { + profilesMap["ims_account_id"] = profilesItem.ImsAccountID + } + if profilesItem.ImsUserID != nil { + profilesMap["ims_user_id"] = profilesItem.ImsUserID + } + if profilesItem.History != nil { + historyList := []map[string]interface{}{} + for _, historyItem := range profilesItem.History { + historyList = append(historyList, dataSourceTrustedProfilesListProfilesHistoryToMap(historyItem)) + } + profilesMap["history"] = historyList + } + + return profilesMap +} + +func dataSourceTrustedProfilesListProfilesHistoryToMap(historyItem iamidentityv1.EnityHistoryRecord) (historyMap map[string]interface{}) { + historyMap = map[string]interface{}{} + + if historyItem.Timestamp != nil { + historyMap["timestamp"] = historyItem.Timestamp + } + if historyItem.IamID != nil { + historyMap["iam_id"] = historyItem.IamID + } + if historyItem.IamIDAccount != nil { + historyMap["iam_id_account"] = historyItem.IamIDAccount + } + if historyItem.Action != nil { + historyMap["action"] = historyItem.Action + } + if historyItem.Params != nil { + historyMap["params"] = historyItem.Params + } + if historyItem.Message != nil { + historyMap["message"] = historyItem.Message + } + + return historyMap +} diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules.go new file mode 100644 index 000000000..79b0c7069 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules.go @@ -0,0 +1,224 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func DataSourceIBMIamTrustedProfileClaimRules() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIamTrustedProfileClaimRuleListRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the trusted profile.", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile_claim_rules", + "profile_id"), + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Description: "List of claim rules.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "the unique identifier of the claim rule.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "version of the claim rule.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The optional claim rule name.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the Calim rule, either 'Profile-SAML' or 'Profile-CR'.", + }, + "realm_name": { + Type: schema.TypeString, + Computed: true, + Description: "The realm name of the Idp this claim rule applies to.", + }, + "expiration": { + Type: schema.TypeInt, + Computed: true, + Description: "Session expiration in seconds.", + }, + "cr_type": { + Type: schema.TypeString, + Computed: true, + Description: "The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA.", + }, + "conditions": { + Type: schema.TypeList, + Computed: true, + Description: "Conditions of this claim rule.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "claim": { + Type: schema.TypeString, + Computed: true, + Description: "The claim to evaluate against.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "The stringified JSON value that the claim is compared to using the operator.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func DataSourceIBMIamTrustedProfileClaimRulesValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIamTrustedProfileClaimRulesValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_claim_rules", Schema: validateSchema} + return &iBMIamTrustedProfileClaimRulesValidator +} + +func dataSourceIBMIamTrustedProfileClaimRuleListRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + listClaimRulesOptions := &iamidentityv1.ListClaimRulesOptions{} + + listClaimRulesOptions.SetProfileID(d.Get("profile_id").(string)) + + profileClaimRuleList, response, err := iamIdentityClient.ListClaimRules(listClaimRulesOptions) + if err != nil { + log.Printf("[DEBUG] ListClaimRules failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListClaimRules failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIamTrustedProfileClaimRuleListID(d)) + + if profileClaimRuleList.Rules != nil { + err = d.Set("rules", dataSourceProfileClaimRuleListFlattenRules(profileClaimRuleList.Rules)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting rules %s", err)) + } + } + + return nil +} + +// dataSourceIBMIamTrustedProfileClaimRuleListID returns a reasonable ID for the list. +func dataSourceIBMIamTrustedProfileClaimRuleListID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceProfileClaimRuleListFlattenRules(result []iamidentityv1.ProfileClaimRule) (rules []map[string]interface{}) { + for _, rulesItem := range result { + rules = append(rules, dataSourceProfileClaimRuleListRuleToMap(rulesItem)) + } + + return rules +} + +func dataSourceProfileClaimRuleListRuleToMap(rulesItem iamidentityv1.ProfileClaimRule) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + + if rulesItem.ID != nil { + rulesMap["id"] = rulesItem.ID + } + if rulesItem.EntityTag != nil { + rulesMap["entity_tag"] = rulesItem.EntityTag + } + if rulesItem.CreatedAt != nil { + rulesMap["created_at"] = rulesItem.CreatedAt.String() + } + if rulesItem.ModifiedAt != nil { + rulesMap["modified_at"] = rulesItem.ModifiedAt.String() + } + if rulesItem.Name != nil { + rulesMap["name"] = rulesItem.Name + } + if rulesItem.Type != nil { + rulesMap["type"] = rulesItem.Type + } + if rulesItem.RealmName != nil { + rulesMap["realm_name"] = rulesItem.RealmName + } + if rulesItem.Expiration != nil { + rulesMap["expiration"] = rulesItem.Expiration + } + if rulesItem.CrType != nil { + rulesMap["cr_type"] = rulesItem.CrType + } + if rulesItem.Conditions != nil { + conditionsList := []map[string]interface{}{} + for _, conditionsItem := range rulesItem.Conditions { + conditionsList = append(conditionsList, dataSourceProfileClaimRuleListRulesConditionsToMap(conditionsItem)) + } + rulesMap["conditions"] = conditionsList + } + + return rulesMap +} + +func dataSourceProfileClaimRuleListRulesConditionsToMap(conditionsItem iamidentityv1.ProfileClaimRuleConditions) (conditionsMap map[string]interface{}) { + conditionsMap = map[string]interface{}{} + + if conditionsItem.Claim != nil { + conditionsMap["claim"] = conditionsItem.Claim + } + if conditionsItem.Operator != nil { + conditionsMap["operator"] = conditionsItem.Operator + } + if conditionsItem.Value != nil { + conditionsMap["value"] = conditionsItem.Value + } + + return conditionsMap +} diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules_test.go new file mode 100644 index 000000000..403951b06 --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_claim_rules_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIamTrustedProfilesClaimRulesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIamTrustedProfilesClaimRulesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_claim_rules.iam_trusted_profile_claim_rules", "id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_claim_rules.iam_trusted_profile_claim_rules", "profile_id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profile_claim_rules.iam_trusted_profile_claim_rules", "rules.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIamTrustedProfilesClaimRulesDataSourceConfigBasic() string { + return ` + data "ibm_iam_trusted_profile_claim_rules" "iam_trusted_profile_claim_rules" { + profile_id = "profile_id" + } + ` +} diff --git a/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_test.go b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_test.go new file mode 100644 index 000000000..591cf9e2c --- /dev/null +++ b/ibm/service/iamidentity/data_source_ibm_iam_trusted_profiles_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIamTrustedProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIamTrustedProfilesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profiles.iam_trusted_profiles", "id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profiles.iam_trusted_profiles", "account_id"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profiles.iam_trusted_profiles", "name"), + resource.TestCheckResourceAttrSet("data.ibm_iam_trusted_profiles.iam_trusted_profiles", "profiles.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIamTrustedProfilesDataSourceConfigBasic() string { + return ` + data "ibm_iam_trusted_profiles" "iam_trusted_profiles" { + name = "name" + } + ` +} diff --git a/ibm/data_source_ibm_iam_user_profile.go b/ibm/service/iamidentity/data_source_ibm_iam_user_profile.go similarity index 90% rename from ibm/data_source_ibm_iam_user_profile.go rename to ibm/service/iamidentity/data_source_ibm_iam_user_profile.go index 8005fde4c..f2cbabea7 100644 --- a/ibm/data_source_ibm_iam_user_profile.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_user_profile.go @@ -1,15 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMIAMUserProfile() *schema.Resource { +func DataSourceIBMIAMUserProfile() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMIAMUserProfileRead, @@ -85,7 +87,7 @@ func dataSourceIBMIAMUserProfile() *schema.Resource { } func dataSourceIBMIAMUserProfileRead(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -98,7 +100,7 @@ func dataSourceIBMIAMUserProfileRead(d *schema.ResourceData, meta interface{}) e return err } - iamID, err := getIBMUniqueId(accountID, userEmail, meta) + iamID, err := flex.GetIBMUniqueId(accountID, userEmail, meta) if err != nil { return err } diff --git a/ibm/data_source_ibm_iam_user_profile_test.go b/ibm/service/iamidentity/data_source_ibm_iam_user_profile_test.go similarity index 86% rename from ibm/data_source_ibm_iam_user_profile_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_user_profile_test.go index e77db63b0..e6f7cdc20 100644 --- a/ibm/data_source_ibm_iam_user_profile_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_user_profile_test.go @@ -1,22 +1,24 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMIAMUserProfileDataSource_Basic(t *testing.T) { t.Skip() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMUserProfileDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_iam_user_profile.user_profile", "allowed_ip_addresses.#", "2"), @@ -41,6 +43,6 @@ func testAccCheckIBMIAMUserProfileDataSourceConfig() string { iam_id = ibm_iam_user_settings.user_settings.iam_id } -`, IAMUser) +`, acc.IAMUser) } diff --git a/ibm/data_source_ibm_iam_users.go b/ibm/service/iamidentity/data_source_ibm_iam_users.go similarity index 90% rename from ibm/data_source_ibm_iam_users.go rename to ibm/service/iamidentity/data_source_ibm_iam_users.go index b54888113..4dd5a8272 100644 --- a/ibm/data_source_ibm_iam_users.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_users.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMIAMUsers() *schema.Resource { +func DataSourceIBMIAMUsers() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMIAMUsersRead, @@ -87,18 +88,18 @@ func dataSourceIBMIAMUsers() *schema.Resource { } func dataSourceIBMIAMUsersRead(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } client := userManagement.UserInvite() - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount if err != nil { return err diff --git a/ibm/data_source_ibm_iam_users_test.go b/ibm/service/iamidentity/data_source_ibm_iam_users_test.go similarity index 77% rename from ibm/data_source_ibm_iam_users_test.go rename to ibm/service/iamidentity/data_source_ibm_iam_users_test.go index 252cc6835..8df35606e 100644 --- a/ibm/data_source_ibm_iam_users_test.go +++ b/ibm/service/iamidentity/data_source_ibm_iam_users_test.go @@ -1,22 +1,23 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMIAMUsersDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMUsersDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_iam_users.users_profiles", "users.#"), @@ -27,11 +28,11 @@ func TestAccIBMIAMUsersDataSource_Basic(t *testing.T) { } func testAccCheckIBMIAMUsersDataSourceConfig() string { - return fmt.Sprintf(` + return ` data "ibm_iam_users" "users_profiles"{ } -`) +` } diff --git a/ibm/resource_ibm_iam_account_settings.go b/ibm/service/iamidentity/resource_ibm_iam_account_settings.go similarity index 80% rename from ibm/resource_ibm_iam_account_settings.go rename to ibm/service/iamidentity/resource_ibm_iam_account_settings.go index 3d46c5cd5..b7947b6e3 100644 --- a/ibm/resource_ibm_iam_account_settings.go +++ b/ibm/service/iamidentity/resource_ibm_iam_account_settings.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -21,7 +23,7 @@ const ( mfa = "mfa" ) -func resourceIbmIamAccountSettings() *schema.Resource { +func ResourceIBMIAMAccountSettings() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmIamAccountSettingsCreate, ReadContext: resourceIbmIamAccountSettingsRead, @@ -30,83 +32,83 @@ func resourceIbmIamAccountSettings() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "include_history": &schema.Schema{ + "include_history": { Type: schema.TypeBool, Optional: true, Default: false, Description: "Defines if the entity history is included in the response.", }, - "restrict_create_service_id": &schema.Schema{ + "restrict_create_service_id": { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator(accountSettings, restrictCreateServiceId), + ValidateFunc: validate.InvokeValidator(accountSettings, "restrict_create_service_id"), Description: "Defines whether or not creating a Service Id is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", }, - "restrict_create_platform_apikey": &schema.Schema{ + "restrict_create_platform_apikey": { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator(accountSettings, restrictCreateApiKey), + ValidateFunc: validate.InvokeValidator(accountSettings, "restrict_create_platform_apikey"), Description: "Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", }, - "allowed_ip_addresses": &schema.Schema{ + "allowed_ip_addresses": { Type: schema.TypeString, Optional: true, Description: "Defines the IP addresses and subnets from which IAM tokens can be created for the account.", }, - "entity_tag": &schema.Schema{ + "entity_tag": { Type: schema.TypeString, Optional: true, Computed: true, Description: "Version of the account settings.", }, - "mfa": &schema.Schema{ + "mfa": { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator(accountSettings, mfa), + ValidateFunc: validate.InvokeValidator(accountSettings, "mfa"), Description: "Defines the MFA trait for the account. Valid values: * NONE - No MFA trait set * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users.", }, - "if_match": &schema.Schema{ + "if_match": { Type: schema.TypeString, Optional: true, Default: "*", Description: "Version of the account settings to be updated. Specify the version that you retrieved as entity_tag (ETag header) when reading the account. This value helps identifying parallel usage of this API. Pass * to indicate to update any version available. This might result in stale updates.", }, - "history": &schema.Schema{ + "history": { Type: schema.TypeList, Computed: true, Description: "History of the Account Settings.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "timestamp": &schema.Schema{ + "timestamp": { Type: schema.TypeString, Required: true, Description: "Timestamp when the action was triggered.", }, - "iam_id": &schema.Schema{ + "iam_id": { Type: schema.TypeString, Required: true, Description: "IAM ID of the identity which triggered the action.", }, - "iam_id_account": &schema.Schema{ + "iam_id_account": { Type: schema.TypeString, Required: true, Description: "Account of the identity which triggered the action.", }, - "action": &schema.Schema{ + "action": { Type: schema.TypeString, Required: true, Description: "Action of the history entry.", }, - "params": &schema.Schema{ + "params": { Type: schema.TypeList, Required: true, Description: "Params of the history entry.", Elem: &schema.Schema{Type: schema.TypeString}, }, - "message": &schema.Schema{ + "message": { Type: schema.TypeString, Required: true, Description: "Message which summarizes the executed action.", @@ -114,19 +116,19 @@ func resourceIbmIamAccountSettings() *schema.Resource { }, }, }, - "session_expiration_in_seconds": &schema.Schema{ + "session_expiration_in_seconds": { Type: schema.TypeString, Optional: true, Computed: true, Description: "Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default.", }, - "session_invalidation_in_seconds": &schema.Schema{ + "session_invalidation_in_seconds": { Type: schema.TypeString, Optional: true, Computed: true, Description: "Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default.", }, - "max_sessions_per_identity": &schema.Schema{ + "max_sessions_per_identity": { Type: schema.TypeString, Optional: true, Computed: true, @@ -136,51 +138,51 @@ func resourceIbmIamAccountSettings() *schema.Resource { } } -func resourceIBMIAMAccountSettingsValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMIAMAccountSettingsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) restrict_values := "RESTRICTED, NOT_RESTRICTED, NOT_SET" mfa_values := "NONE, TOTP, TOTP4ALL, LEVEL1, LEVEL2, LEVEL3" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: restrictCreateServiceId, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: restrict_values}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: restrictCreateApiKey, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: restrict_values}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: mfa, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: mfa_values}) - ibmIAMAccountSettingsValidator := ResourceValidator{ResourceName: "ibm_iam_account_settings", Schema: validateSchema} + ibmIAMAccountSettingsValidator := validate.ResourceValidator{ResourceName: "ibm_iam_account_settings", Schema: validateSchema} return &ibmIAMAccountSettingsValidator } func resourceIbmIamAccountSettingsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } getAccountSettingsOptions := &iamidentityv1.GetAccountSettingsOptions{} - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return diag.FromErr(err) } - getAccountSettingsOptions.SetAccountID(userDetails.userAccount) + getAccountSettingsOptions.SetAccountID(userDetails.UserAccount) if _, ok := d.GetOk("include_history"); ok { getAccountSettingsOptions.SetIncludeHistory(d.Get("include_history").(bool)) } @@ -191,13 +193,13 @@ func resourceIbmIamAccountSettingsCreate(context context.Context, d *schema.Reso return diag.FromErr(err) } - d.SetId(fmt.Sprintf("%s", *accountSettingsResponse.AccountID)) + d.SetId(*accountSettingsResponse.AccountID) return resourceIbmIamAccountSettingsUpdate(context, d, meta) } func resourceIbmIamAccountSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -218,19 +220,19 @@ func resourceIbmIamAccountSettingsRead(context context.Context, d *schema.Resour } if err = d.Set("restrict_create_service_id", accountSettingsResponse.RestrictCreateServiceID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting restrict_create_service_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting restrict_create_service_id: %s", err)) } if err = d.Set("restrict_create_platform_apikey", accountSettingsResponse.RestrictCreatePlatformApikey); err != nil { - return diag.FromErr(fmt.Errorf("Error setting restrict_create_platform_apikey: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting restrict_create_platform_apikey: %s", err)) } if err = d.Set("allowed_ip_addresses", accountSettingsResponse.AllowedIPAddresses); err != nil { - return diag.FromErr(fmt.Errorf("Error setting allowed_ip_addresses: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allowed_ip_addresses: %s", err)) } if err = d.Set("entity_tag", accountSettingsResponse.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) } if err = d.Set("mfa", accountSettingsResponse.Mfa); err != nil { - return diag.FromErr(fmt.Errorf("Error setting mfa: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting mfa: %s", err)) } if accountSettingsResponse.History != nil { history := []map[string]interface{}{} @@ -239,17 +241,17 @@ func resourceIbmIamAccountSettingsRead(context context.Context, d *schema.Resour history = append(history, historyItemMap) } if err = d.Set("history", history); err != nil { - return diag.FromErr(fmt.Errorf("Error setting history: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting history: %s", err)) } } if err = d.Set("session_expiration_in_seconds", accountSettingsResponse.SessionExpirationInSeconds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting session_expiration_in_seconds: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting session_expiration_in_seconds: %s", err)) } if err = d.Set("session_invalidation_in_seconds", accountSettingsResponse.SessionInvalidationInSeconds); err != nil { - return diag.FromErr(fmt.Errorf("Error setting session_invalidation_in_seconds: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting session_invalidation_in_seconds: %s", err)) } if err = d.Set("max_sessions_per_identity", accountSettingsResponse.MaxSessionsPerIdentity); err != nil { - return diag.FromErr(fmt.Errorf("Error setting max_sessions_per_identity: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting max_sessions_per_identity: %s", err)) } return nil @@ -269,7 +271,7 @@ func resourceIbmIamAccountSettingsEnityHistoryRecordToMap(enityHistoryRecord iam } func resourceIbmIamAccountSettingsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_iam_account_settings_test.go b/ibm/service/iamidentity/resource_ibm_iam_account_settings_test.go similarity index 89% rename from ibm/resource_ibm_iam_account_settings_test.go rename to ibm/service/iamidentity/resource_ibm_iam_account_settings_test.go index a1fbe7451..6ab1b490f 100644 --- a/ibm/resource_ibm_iam_account_settings_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_account_settings_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -27,16 +30,16 @@ func TestAccIBMIAMAccountSettingsBasic(t *testing.T) { var conf iamidentityv1.AccountSettingsResponse resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsConfigBasic(), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIamAccountSettingsExists("ibm_iam_account_settings.iam_account_settings", conf), ), }, - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsConfigBasic(), Check: resource.ComposeAggregateTestCheckFunc(), }, @@ -50,23 +53,23 @@ func TestAccIBMIAMAccountSettingsAllArgs(t *testing.T) { includeHistoryUpdate := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsConfig(includeHistory), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIamAccountSettingsExists("ibm_iam_account_settings.iam_account_settings", conf), resource.TestCheckResourceAttr("ibm_iam_account_settings.iam_account_settings", "include_history", includeHistory), ), }, - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsConfig(includeHistoryUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_account_settings.iam_account_settings", "include_history", includeHistoryUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_iam_account_settings.iam_account_settings", ImportState: true, ImportStateVerify: false, @@ -79,10 +82,10 @@ func TestAccIBMIAMAccountSettingsUpdate(t *testing.T) { var conf iamidentityv1.AccountSettingsResponse resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamAccountSettingsUpdateConfig(), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIamAccountSettingsExists("ibm_iam_account_settings.iam_account_settings", conf), @@ -99,11 +102,11 @@ func TestAccIBMIAMAccountSettingsUpdate(t *testing.T) { } func testAccCheckIbmIamAccountSettingsConfigBasic() string { - return fmt.Sprintf(` + return ` resource "ibm_iam_account_settings" "iam_account_settings" { } - `) + ` } func testAccCheckIbmIamAccountSettingsConfig(includeHistory string) string { @@ -146,7 +149,7 @@ func testAccCheckIbmIamAccountSettingsExists(n string, obj iamidentityv1.Account return fmt.Errorf("Not found: %s", n) } - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -166,8 +169,3 @@ func testAccCheckIbmIamAccountSettingsExists(n string, obj iamidentityv1.Account return nil } } - -func testAccCheckIbmIamAccountSettingsDestroy(s *terraform.State) error { - // NOT SUPPORTED - return nil -} diff --git a/ibm/resource_ibm_iam_api_key.go b/ibm/service/iamidentity/resource_ibm_iam_api_key.go similarity index 80% rename from ibm/resource_ibm_iam_api_key.go rename to ibm/service/iamidentity/resource_ibm_iam_api_key.go index e4abd518d..326e8ac3f 100644 --- a/ibm/resource_ibm_iam_api_key.go +++ b/ibm/service/iamidentity/resource_ibm_iam_api_key.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/iamidentityv1" ) -func resourceIbmIamApiKey() *schema.Resource { +func ResourceIBMIAMApiKey() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmIamApiKeyCreate, ReadContext: resourceIbmIamApiKeyRead, @@ -23,81 +25,81 @@ func resourceIbmIamApiKey() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "Name of the API key. The name is not checked for uniqueness. Therefore multiple names with the same value can exist. Access is done via the UUID of the API key.", }, - "iam_id": &schema.Schema{ + "iam_id": { Type: schema.TypeString, Computed: true, Description: "The iam_id that this API key authenticates.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, Description: "The optional description of the API key. The 'description' property is only available if a description was provided during a create of an API key.", }, - "account_id": &schema.Schema{ + "account_id": { Type: schema.TypeString, Computed: true, Description: "The account ID of the API key.", }, - "apikey": &schema.Schema{ + "apikey": { Type: schema.TypeString, Optional: true, Computed: true, Sensitive: true, Description: "You can optionally passthrough the API key value for this API key. If passed, NO validation of that apiKey value is done, i.e. the value can be non-URL safe. If omitted, the API key management will create an URL safe opaque API key value. The value of the API key is checked for uniqueness. Please ensure enough variations when passing in this value.", }, - "store_value": &schema.Schema{ + "store_value": { Type: schema.TypeBool, Optional: true, Description: "Send true or false to set whether the API key value is retrievable in the future by using the Get details of an API key request. If you create an API key for a user, you must specify `false` or omit the value. We don't allow storing of API keys for users.", }, - "file": &schema.Schema{ + "file": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "File where api key is to be stored", }, - "entity_lock": &schema.Schema{ + "entity_lock": { Type: schema.TypeString, Optional: true, Default: "false", Description: "Indicates if the API key is locked for further write operations. False by default.", }, - "apikey_id": &schema.Schema{ + "apikey_id": { Type: schema.TypeString, Computed: true, Description: "Unique identifier of this API Key.", }, - "entity_tag": &schema.Schema{ + "entity_tag": { Type: schema.TypeString, Computed: true, Description: "Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678'.", }, - "locked": &schema.Schema{ + "locked": { Type: schema.TypeBool, Computed: true, Description: "The API key cannot be changed if set to true.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the creation date in ISO format.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "IAM ID of the user or service which created the API key.", }, - "modified_at": &schema.Schema{ + "modified_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the last modification date in ISO format.", @@ -107,19 +109,19 @@ func resourceIbmIamApiKey() *schema.Resource { } func resourceIbmIamApiKeyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } createApiKeyOptions := &iamidentityv1.CreateAPIKeyOptions{} - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return diag.FromErr(err) } - iamID := userDetails.userID - accountID := userDetails.userAccount + iamID := userDetails.UserID + accountID := userDetails.UserAccount createApiKeyOptions.SetName(d.Get("name").(string)) createApiKeyOptions.SetIamID(iamID) @@ -157,7 +159,7 @@ func resourceIbmIamApiKeyCreate(context context.Context, d *schema.ResourceData, } func resourceIbmIamApiKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -177,44 +179,44 @@ func resourceIbmIamApiKeyRead(context context.Context, d *schema.ResourceData, m } if err = d.Set("name", apiKey.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("iam_id", apiKey.IamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting iam_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting iam_id: %s", err)) } if err = d.Set("description", apiKey.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if err = d.Set("account_id", apiKey.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) } if err = d.Set("locked", apiKey.Locked); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_lock: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_lock: %s", err)) } if err = d.Set("apikey_id", apiKey.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) } if err = d.Set("entity_tag", apiKey.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) } if err = d.Set("crn", apiKey.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("created_at", apiKey.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("created_by", apiKey.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if err = d.Set("modified_at", apiKey.ModifiedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) } return nil } func resourceIbmIamApiKeyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -237,7 +239,7 @@ func resourceIbmIamApiKeyUpdate(context context.Context, d *schema.ResourceData, } func resourceIbmIamApiKeyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_iam_api_key_test.go b/ibm/service/iamidentity/resource_ibm_iam_api_key_test.go similarity index 86% rename from ibm/resource_ibm_iam_api_key_test.go rename to ibm/service/iamidentity/resource_ibm_iam_api_key_test.go index b6f0e3170..c29f99d77 100644 --- a/ibm/resource_ibm_iam_api_key_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_api_key_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,18 +23,18 @@ func TestAccIbmIamApiKeyBasic(t *testing.T) { nameUpdate := fmt.Sprintf("name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIamApiKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIamApiKeyExists("ibm_iam_api_key.iam_api_key", conf), resource.TestCheckResourceAttr("ibm_iam_api_key.iam_api_key", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyConfigBasic(nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_api_key.iam_api_key", "name", nameUpdate), @@ -51,11 +54,11 @@ func TestAccIbmIamApiKeyAllArgs(t *testing.T) { storeValueUpdate := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIamApiKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyConfig(name, description, storeValue), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIamApiKeyExists("ibm_iam_api_key.iam_api_key", conf), @@ -64,7 +67,7 @@ func TestAccIbmIamApiKeyAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_api_key.iam_api_key", "store_value", storeValue), ), }, - resource.TestStep{ + { Config: testAccCheckIbmIamApiKeyConfig(nameUpdate, descriptionUpdate, storeValueUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_api_key.iam_api_key", "name", nameUpdate), @@ -72,7 +75,7 @@ func TestAccIbmIamApiKeyAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_api_key.iam_api_key", "store_value", storeValueUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_iam_api_key.iam_api_key", ImportState: true, ImportStateVerify: true, @@ -109,7 +112,7 @@ func testAccCheckIbmIamApiKeyExists(n string, obj iamidentityv1.APIKey) resource return fmt.Errorf("Not found: %s", n) } - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -129,7 +132,7 @@ func testAccCheckIbmIamApiKeyExists(n string, obj iamidentityv1.APIKey) resource } func testAccCheckIbmIamApiKeyDestroy(s *terraform.State) error { - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -148,7 +151,7 @@ func testAccCheckIbmIamApiKeyDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("iam_api_key still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for iam_api_key (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for iam_api_key (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_iam_service_api_key.go b/ibm/service/iamidentity/resource_ibm_iam_service_api_key.go similarity index 81% rename from ibm/resource_ibm_iam_service_api_key.go rename to ibm/service/iamidentity/resource_ibm_iam_service_api_key.go index df986516e..a2d076f5a 100644 --- a/ibm/resource_ibm_iam_service_api_key.go +++ b/ibm/service/iamidentity/resource_ibm_iam_service_api_key.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "encoding/json" @@ -10,12 +10,15 @@ import ( "log" "strconv" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/platform-services-go-sdk/iamidentityv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" homedir "github.com/mitchellh/go-homedir" ) -func resourceIBMIAMServiceAPIKey() *schema.Resource { +func ResourceIBMIAMServiceAPIKey() *schema.Resource { return &schema.Resource{ Create: resourceIBMIAMServiceAPIkeyCreate, Read: resourceIBMIAMServiceAPIKeyRead, @@ -43,6 +46,8 @@ func resourceIBMIAMServiceAPIKey() *schema.Resource { Required: true, ForceNew: true, Description: "The service iam_id that this API key authenticates", + ValidateFunc: validate.InvokeValidator("ibm_iam_service_api_key", + "iam_service_id"), }, "account_id": { @@ -63,21 +68,21 @@ func resourceIBMIAMServiceAPIKey() *schema.Resource { "locked": { Type: schema.TypeBool, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "The API key cannot be changed if set to true", }, "store_value": { Type: schema.TypeBool, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Boolean value deciding whether API key value is retrievable in the future", }, "file": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "File where api key is to be stored", }, @@ -113,6 +118,20 @@ func resourceIBMIAMServiceAPIKey() *schema.Resource { }, } } +func ResourceIBMIAMServiceAPIKeyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "iam_service_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:service_id", "resolved_to:id"}, + Required: true}) + + iBMIAMServiceAPIKeyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_service_api_key", Schema: validateSchema} + return &iBMIAMServiceAPIKeyValidator +} type APIKey struct { Name string @@ -123,7 +142,7 @@ type APIKey struct { } func resourceIBMIAMServiceAPIkeyCreate(d *schema.ResourceData, meta interface{}) error { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -141,11 +160,11 @@ func resourceIBMIAMServiceAPIkeyCreate(d *schema.ResourceData, meta interface{}) createAPIKeyOptions.Description = &desString } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return err } - createAPIKeyOptions.AccountID = &userDetails.userAccount + createAPIKeyOptions.AccountID = &userDetails.UserAccount if key, ok := d.GetOk("apikey"); ok { apikeyString := key.(string) @@ -180,7 +199,7 @@ func resourceIBMIAMServiceAPIkeyCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMIAMServiceAPIKeyRead(d *schema.ResourceData, meta interface{}) error { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -237,7 +256,7 @@ func resourceIBMIAMServiceAPIKeyRead(d *schema.ResourceData, meta interface{}) e func resourceIBMIAMServiceAPIKeyUpdate(d *schema.ResourceData, meta interface{}) error { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -282,7 +301,7 @@ func resourceIBMIAMServiceAPIKeyUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMIAMServiceAPIKeyDelete(d *schema.ResourceData, meta interface{}) error { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -315,7 +334,7 @@ func resourceIBMIAMServiceAPIKeyDelete(d *schema.ResourceData, meta interface{}) } func resourceIBMIAMServiceAPIKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return false, err } @@ -330,7 +349,7 @@ func resourceIBMIAMServiceAPIKeyExists(d *schema.ResourceData, meta interface{}) if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error retrieving Service API Key: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error retrieving Service API Key: %s\n%s", err, response) } return *apiKey.ID == apiKeyID, nil } @@ -338,7 +357,7 @@ func resourceIBMIAMServiceAPIKeyExists(d *schema.ResourceData, meta interface{}) func saveToFile(apiKey *iamidentityv1.APIKey, filePath string) error { outputFilePath, err := homedir.Expand(filePath) if err != nil { - return fmt.Errorf("Error generating API Key file path: %s", err) + return fmt.Errorf("[ERROR] Error generating API Key file path: %s", err) } key := &APIKey{ @@ -353,7 +372,7 @@ func saveToFile(apiKey *iamidentityv1.APIKey, filePath string) error { key.Description = "" } - out, err := json.MarshalIndent(key, "", "\t") + out, _ := json.MarshalIndent(key, "", "\t") err = ioutil.WriteFile(outputFilePath, out, 0666) if err == nil { diff --git a/ibm/resource_ibm_iam_service_api_key_test.go b/ibm/service/iamidentity/resource_ibm_iam_service_api_key_test.go similarity index 91% rename from ibm/resource_ibm_iam_service_api_key_test.go rename to ibm/service/iamidentity/resource_ibm_iam_service_api_key_test.go index 69a2dcfd4..3da10c5da 100644 --- a/ibm/resource_ibm_iam_service_api_key_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_service_api_key_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -21,18 +24,18 @@ func TestAccIBMIAMServiceAPIKey_Basic(t *testing.T) { updateName := fmt.Sprintf("terraform_iam_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMServiceAPIKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMServiceAPIKeyBasic(serviceName, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMServiceAPIKeyExists("ibm_iam_service_api_key.testacc_apiKey", apiKey), resource.TestCheckResourceAttr("ibm_iam_service_api_key.testacc_apiKey", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMServiceAPIKeyUpdateWithSameName(serviceName, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMServiceAPIKeyExists("ibm_iam_service_api_key.testacc_apiKey", apiKey), @@ -40,7 +43,7 @@ func TestAccIBMIAMServiceAPIKey_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_service_api_key.testacc_apiKey", "description", "Service API Key for test scenario1"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMServiceAPIKeyUpdate(serviceName, updateName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_service_api_key.testacc_apiKey", "name", updateName), @@ -58,11 +61,11 @@ func TestAccIBMIAMServiceAPIKey_import(t *testing.T) { resourceName := "ibm_iam_service_api_key.testacc_apiKey" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMServiceAPIKeyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMServiceAPIKeyImport(serviceName, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMServiceAPIKeyExists(resourceName, apiKey), @@ -70,7 +73,7 @@ func TestAccIBMIAMServiceAPIKey_import(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Service API Key for test scenario2"), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -80,7 +83,7 @@ func TestAccIBMIAMServiceAPIKey_import(t *testing.T) { } func testAccCheckIBMIAMServiceAPIKeyDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -110,7 +113,7 @@ func testAccCheckIBMIAMServiceAPIKeyExists(n string, apiKey string) resource.Tes return fmt.Errorf("Not found: %s", n) } - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } diff --git a/ibm/resource_ibm_iam_service_id.go b/ibm/service/iamidentity/resource_ibm_iam_service_id.go similarity index 83% rename from ibm/resource_ibm_iam_service_id.go rename to ibm/service/iamidentity/resource_ibm_iam_service_id.go index 9b0529975..c269a677e 100644 --- a/ibm/resource_ibm_iam_service_id.go +++ b/ibm/service/iamidentity/resource_ibm_iam_service_id.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" + "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM/platform-services-go-sdk/iamidentityv1" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMIAMServiceID() *schema.Resource { +func ResourceIBMIAMServiceID() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMIAMServiceIDCreate, ReadContext: resourceIBMIAMServiceIDRead, @@ -66,21 +68,21 @@ func resourceIBMIAMServiceID() *schema.Resource { } func resourceIBMIAMServiceIDCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } name := d.Get("name").(string) - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return diag.FromErr(err) } createServiceIDOptions := iamidentityv1.CreateServiceIDOptions{ Name: &name, - AccountID: &userDetails.userAccount, + AccountID: &userDetails.UserAccount, } if d, ok := d.GetOk("description"); ok { @@ -91,7 +93,7 @@ func resourceIBMIAMServiceIDCreate(context context.Context, d *schema.ResourceDa serviceID, resp, err := iamIdentityClient.CreateServiceID(&createServiceIDOptions) if err != nil || serviceID == nil { log.Printf("Error creating serviceID: %s, %s", err, resp) - return diag.FromErr(err) + return diag.FromErr(fmt.Errorf("[ERROR] Error creating serviceID: %s %s", err, resp)) } d.SetId(*serviceID.ID) @@ -99,7 +101,7 @@ func resourceIBMIAMServiceIDCreate(context context.Context, d *schema.ResourceDa } func resourceIBMIAMServiceIDRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -114,7 +116,7 @@ func resourceIBMIAMServiceIDRead(context context.Context, d *schema.ResourceData return nil } log.Printf("Error retrieving serviceID: %s %s", err, resp) - return diag.FromErr(err) + return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving serviceID: %s %s", err, resp)) } if serviceID.Name != nil { d.Set("name", *serviceID.Name) @@ -139,7 +141,7 @@ func resourceIBMIAMServiceIDRead(context context.Context, d *schema.ResourceData func resourceIBMIAMServiceIDUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -168,7 +170,7 @@ func resourceIBMIAMServiceIDUpdate(context context.Context, d *schema.ResourceDa _, resp, err := iamIdentityClient.UpdateServiceID(&updateServiceIDOptions) if err != nil { log.Printf("Error updating serviceID: %s, %s", err, resp) - return diag.FromErr(err) + return diag.FromErr(fmt.Errorf("[ERROR] Error updating serviceID: %s %s", err, resp)) } } @@ -177,7 +179,7 @@ func resourceIBMIAMServiceIDUpdate(context context.Context, d *schema.ResourceDa } func resourceIBMIAMServiceIDDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -189,7 +191,7 @@ func resourceIBMIAMServiceIDDelete(context context.Context, d *schema.ResourceDa resp, err := iamIdentityClient.DeleteServiceID(&deleteServiceIDOptions) if err != nil { log.Printf("Error deleting serviceID: %s %s", err, resp) - return diag.FromErr(err) + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting serviceID: %s %s", err, resp)) } d.SetId("") diff --git a/ibm/resource_ibm_iam_service_id_test.go b/ibm/service/iamidentity/resource_ibm_iam_service_id_test.go similarity index 87% rename from ibm/resource_ibm_iam_service_id_test.go rename to ibm/service/iamidentity/resource_ibm_iam_service_id_test.go index 674d88197..4b33f0157 100644 --- a/ibm/resource_ibm_iam_service_id_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_service_id_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,8 +22,8 @@ func TestAccIBMIAMServiceID_Basic(t *testing.T) { updateName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMServiceIDDestroy, Steps: []resource.TestStep{ { @@ -58,8 +61,8 @@ func TestAccIBMIAMServiceID_import(t *testing.T) { resourceName := "ibm_iam_service_id.serviceID" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMServiceIDDestroy, Steps: []resource.TestStep{ { @@ -80,7 +83,7 @@ func TestAccIBMIAMServiceID_import(t *testing.T) { } func testAccCheckIBMIAMServiceIDDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -98,7 +101,7 @@ func testAccCheckIBMIAMServiceIDDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("ServiceID still exists: %s %s", rs.Primary.ID, resp) } else if resp.StatusCode != 404 { - return fmt.Errorf("Error waiting for serviceID (%s) to be destroyed: %s %s", rs.Primary.ID, err, resp) + return fmt.Errorf("[ERROR] Error waiting for serviceID (%s) to be destroyed: %s %s", rs.Primary.ID, err, resp) } } @@ -113,7 +116,7 @@ func testAccCheckIBMIAMServiceIDExists(n string, obj string) resource.TestCheckF return fmt.Errorf("Not found: %s", n) } - rsContClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -123,7 +126,7 @@ func testAccCheckIBMIAMServiceIDExists(n string, obj string) resource.TestCheckF } serviceID, resp, err := rsContClient.GetServiceID(&getServiceIDOptions) if err != nil { - return fmt.Errorf("Error retrieving serviceID: %s %s", err, resp) + return fmt.Errorf("[ERROR] Error retrieving serviceID: %s %s", err, resp) } obj = *serviceID.ID diff --git a/ibm/resource_ibm_iam_trusted_profile.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile.go similarity index 80% rename from ibm/resource_ibm_iam_trusted_profile.go rename to ibm/service/iamidentity/resource_ibm_iam_trusted_profile.go index df1f5ae4b..0d4e73aaf 100644 --- a/ibm/resource_ibm_iam_trusted_profile.go +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/platform-services-go-sdk/iamidentityv1" ) -func resourceIBMIamTrustedProfile() *schema.Resource { +func ResourceIBMIAMTrustedProfile() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMIamTrustedProfileCreate, ReadContext: resourceIBMIamTrustedProfileRead, @@ -23,94 +25,94 @@ func resourceIBMIamTrustedProfile() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", }, - "account_id": &schema.Schema{ + "account_id": { Type: schema.TypeString, Computed: true, Description: "The account ID of the trusted profile.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, Description: "The optional description of the trusted profile. The 'description' property is only available if a description was provided during creation of trusted profile.", }, - "profile_id": &schema.Schema{ + "profile_id": { Type: schema.TypeString, Computed: true, Description: "Unique identifier of this trusted profile.", }, - "entity_tag": &schema.Schema{ + "entity_tag": { Type: schema.TypeString, Computed: true, Description: "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the creation date in ISO format.", }, - "modified_at": &schema.Schema{ + "modified_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the last modification date in ISO format.", }, - "iam_id": &schema.Schema{ + "iam_id": { Type: schema.TypeString, Computed: true, Description: "The iam_id of this trusted profile.", }, - "ims_account_id": &schema.Schema{ + "ims_account_id": { Type: schema.TypeInt, Computed: true, Description: "IMS acount ID of the trusted profile.", }, - "ims_user_id": &schema.Schema{ + "ims_user_id": { Type: schema.TypeInt, Computed: true, Description: "IMS user ID of the trusted profile.", }, - "history": &schema.Schema{ + "history": { Type: schema.TypeList, Computed: true, Description: "History of the trusted profile.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "timestamp": &schema.Schema{ + "timestamp": { Type: schema.TypeString, Computed: true, Description: "Timestamp when the action was triggered.", }, - "iam_id": &schema.Schema{ + "iam_id": { Type: schema.TypeString, Computed: true, Description: "IAM ID of the identity which triggered the action.", }, - "iam_id_account": &schema.Schema{ + "iam_id_account": { Type: schema.TypeString, Computed: true, Description: "Account of the identity which triggered the action.", }, - "action": &schema.Schema{ + "action": { Type: schema.TypeString, Computed: true, Description: "Action of the history entry.", }, - "params": &schema.Schema{ + "params": { Type: schema.TypeList, Computed: true, Description: "Params of the history entry.", Elem: &schema.Schema{Type: schema.TypeString}, }, - "message": &schema.Schema{ + "message": { Type: schema.TypeString, Computed: true, Description: "Message which summarizes the executed action.", @@ -123,19 +125,19 @@ func resourceIBMIamTrustedProfile() *schema.Resource { } func resourceIBMIamTrustedProfileCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } createProfileOptions := &iamidentityv1.CreateProfileOptions{} - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return diag.FromErr(err) } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount createProfileOptions.SetName(d.Get("name").(string)) createProfileOptions.SetAccountID(accountID) @@ -155,7 +157,7 @@ func resourceIBMIamTrustedProfileCreate(context context.Context, d *schema.Resou } func resourceIBMIamTrustedProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -175,37 +177,37 @@ func resourceIBMIamTrustedProfileRead(context context.Context, d *schema.Resourc } if err = d.Set("name", trustedProfile.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("account_id", trustedProfile.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account_id: %s", err)) } if err = d.Set("description", trustedProfile.Description); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if err = d.Set("profile_id", trustedProfile.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) } if err = d.Set("entity_tag", trustedProfile.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) } if err = d.Set("crn", trustedProfile.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } - if err = d.Set("created_at", dateTimeToString(trustedProfile.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + if err = d.Set("created_at", flex.DateTimeToString(trustedProfile.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } - if err = d.Set("modified_at", dateTimeToString(trustedProfile.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) + if err = d.Set("modified_at", flex.DateTimeToString(trustedProfile.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) } if err = d.Set("iam_id", trustedProfile.IamID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting iam_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting iam_id: %s", err)) } - if err = d.Set("ims_account_id", intValue(trustedProfile.ImsAccountID)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ims_account_id: %s", err)) + if err = d.Set("ims_account_id", flex.IntValue(trustedProfile.ImsAccountID)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ims_account_id: %s", err)) } - if err = d.Set("ims_user_id", intValue(trustedProfile.ImsUserID)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ims_user_id: %s", err)) + if err = d.Set("ims_user_id", flex.IntValue(trustedProfile.ImsUserID)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ims_user_id: %s", err)) } history := []map[string]interface{}{} if trustedProfile.History != nil { @@ -215,7 +217,7 @@ func resourceIBMIamTrustedProfileRead(context context.Context, d *schema.Resourc } } if err = d.Set("history", history); err != nil { - return diag.FromErr(fmt.Errorf("Error setting history: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting history: %s", err)) } return nil @@ -275,7 +277,7 @@ func resourceIBMIamTrustedProfileEnityHistoryRecordToMap(enityHistoryRecord iami } func resourceIBMIamTrustedProfileUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -299,7 +301,7 @@ func resourceIBMIamTrustedProfileUpdate(context context.Context, d *schema.Resou } func resourceIBMIamTrustedProfileDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_iam_trusted_profile_claim_rule.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule.go similarity index 79% rename from ibm/resource_ibm_iam_trusted_profile_claim_rule.go rename to ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule.go index cfc0a5534..98c6f02d0 100644 --- a/ibm/resource_ibm_iam_trusted_profile_claim_rule.go +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -20,7 +23,7 @@ const ( iamClaimRuleOperator = "operator" ) -func resourceIBMIamTrustedProfileClaimRule() *schema.Resource { +func ResourceIBMIAMTrustedProfileClaimRule() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMIamTrustedProfileClaimRuleCreate, ReadContext: resourceIBMIamTrustedProfileClaimRuleRead, @@ -29,41 +32,43 @@ func resourceIBMIamTrustedProfileClaimRule() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "profile_id": &schema.Schema{ + "profile_id": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "ID of the trusted profile to create a claim rule.", + ValidateFunc: validate.InvokeValidator("ibm_iam_trusted_profile_claim_rule", + "profile_id"), }, - "rule_id": &schema.Schema{ + "rule_id": { Type: schema.TypeString, Computed: true, Description: "Unique identifier of this claim rule.", }, - iamClaimRuleType: &schema.Schema{ + iamClaimRuleType: { Type: schema.TypeString, Required: true, Description: "Type of the calim rule, either 'Profile-SAML' or 'Profile-CR'.", - ValidateFunc: validateAllowedStringValue([]string{"Profile-SAML", "Profile-CR"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"Profile-SAML", "Profile-CR"}), }, - "conditions": &schema.Schema{ + "conditions": { Type: schema.TypeList, Required: true, Description: "Conditions of this claim rule.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "claim": &schema.Schema{ + "claim": { Type: schema.TypeString, Required: true, Description: "The claim to evaluate against.", }, - iamClaimRuleOperator: &schema.Schema{ + iamClaimRuleOperator: { Type: schema.TypeString, Required: true, Description: "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", - ValidateFunc: validateAllowedStringValue([]string{"EQUALS", "NOT_EQUALS", "EQUALS_IGNORE_CASE", "NOT_EQUALS_IGNORE_CASE", "CONTAINS", "IN"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"EQUALS", "NOT_EQUALS", "EQUALS_IGNORE_CASE", "NOT_EQUALS_IGNORE_CASE", "CONTAINS", "IN"}), }, - "value": &schema.Schema{ + "value": { Type: schema.TypeString, Required: true, Description: "The stringified JSON value that the claim is compared to using the operator.", @@ -71,37 +76,37 @@ func resourceIBMIamTrustedProfileClaimRule() *schema.Resource { }, }, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "Name of the claim rule to be created or updated.", }, - "realm_name": &schema.Schema{ + "realm_name": { Type: schema.TypeString, Optional: true, Description: "The realm name of the Idp this claim rule applies to. This field is required only if the type is specified as 'Profile-SAML'.", }, - "cr_type": &schema.Schema{ + "cr_type": { Type: schema.TypeString, Optional: true, Description: "The compute resource type the rule applies to, required only if type is specified as 'Profile-CR'. Valid values are VSI, IKS_SA, ROKS_SA.", }, - "expiration": &schema.Schema{ + "expiration": { Type: schema.TypeInt, Optional: true, Description: "Session expiration in seconds, only required if type is 'Profile-SAML'.", }, - "entity_tag": &schema.Schema{ + "entity_tag": { Type: schema.TypeString, Computed: true, Description: "version of the claim rule.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the creation date in ISO format.", }, - "modified_at": &schema.Schema{ + "modified_at": { Type: schema.TypeString, Computed: true, Description: "If set contains a date time string of the last modification date in ISO format.", @@ -109,9 +114,23 @@ func resourceIBMIamTrustedProfileClaimRule() *schema.Resource { }, } } +func ResourceIBMIAMTrustedProfileClaimRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIAMTrustedProfileClaimRuleValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_claim_rule", Schema: validateSchema} + return &iBMIAMTrustedProfileClaimRuleValidator +} func resourceIBMIamTrustedProfileClaimRuleCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } @@ -203,13 +222,13 @@ func resourceIBMIamTrustedProfileClaimRuleMapToResponseContext(responseContextMa } func resourceIBMIamTrustedProfileClaimRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("Invalid ID %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Invalid ID %s", err)) } getClaimRuleOptions := &iamidentityv1.GetClaimRuleOptions{} @@ -227,10 +246,10 @@ func resourceIBMIamTrustedProfileClaimRuleRead(context context.Context, d *schem } if err = d.Set("profile_id", getClaimRuleOptions.ProfileID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting profile_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile_id: %s", err)) } if err = d.Set("type", profileClaimRule.Type); err != nil { - return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } conditions := []map[string]interface{}{} for _, conditionsItem := range profileClaimRule.Conditions { @@ -238,31 +257,31 @@ func resourceIBMIamTrustedProfileClaimRuleRead(context context.Context, d *schem conditions = append(conditions, conditionsItemMap) } if err = d.Set("conditions", conditions); err != nil { - return diag.FromErr(fmt.Errorf("Error setting conditions: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting conditions: %s", err)) } if err = d.Set("name", profileClaimRule.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("rule_id", profileClaimRule.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting rule_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting rule_id: %s", err)) } if err = d.Set("realm_name", profileClaimRule.RealmName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting realm_name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting realm_name: %s", err)) } if err = d.Set("cr_type", profileClaimRule.CrType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cr_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cr_type: %s", err)) } - if err = d.Set("expiration", intValue(profileClaimRule.Expiration)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting expiration: %s", err)) + if err = d.Set("expiration", flex.IntValue(profileClaimRule.Expiration)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting expiration: %s", err)) } if err = d.Set("entity_tag", profileClaimRule.EntityTag); err != nil { - return diag.FromErr(fmt.Errorf("Error setting entity_tag: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) } - if err = d.Set("created_at", dateTimeToString(profileClaimRule.CreatedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + if err = d.Set("created_at", flex.DateTimeToString(profileClaimRule.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } - if err = d.Set("modified_at", dateTimeToString(profileClaimRule.ModifiedAt)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) + if err = d.Set("modified_at", flex.DateTimeToString(profileClaimRule.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) } return nil @@ -319,13 +338,13 @@ func resourceIBMIamTrustedProfileClaimRuleResponseContextToMap(responseContext i } func resourceIBMIamTrustedProfileClaimRuleUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("Invalid ID %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Invalid ID %s", err)) } updateClaimRuleOptions := &iamidentityv1.UpdateClaimRuleOptions{} @@ -364,13 +383,13 @@ func resourceIBMIamTrustedProfileClaimRuleUpdate(context context.Context, d *sch } func resourceIBMIamTrustedProfileClaimRuleDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - iamIdentityClient, err := meta.(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() if err != nil { return diag.FromErr(err) } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("Invalid ID %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Invalid ID %s", err)) } deleteClaimRuleOptions := &iamidentityv1.DeleteClaimRuleOptions{} diff --git a/ibm/resource_ibm_iam_trusted_profile_claim_rule_test.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule_test.go similarity index 84% rename from ibm/resource_ibm_iam_trusted_profile_claim_rule_test.go rename to ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule_test.go index 0593177c4..8fef38ecb 100644 --- a/ibm/resource_ibm_iam_trusted_profile_claim_rule_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_claim_rule_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,11 +23,11 @@ func TestAccIBMIAMTrustedProfileClaimRuleBasic(t *testing.T) { profileName := fmt.Sprintf("tf_profile_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckIAMTrustedProfile(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckIAMTrustedProfile(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileClaimRuleDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileClaimRuleConfigBasic(profileName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileClaimRuleExists("ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", conf), @@ -39,11 +43,11 @@ func TestAccIBMIAMTrustedProfileClaimRuleAllArgs(t *testing.T) { profileName := fmt.Sprintf("tf_profile_%d", acctest.RandIntRange(10, 100)) name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckIAMTrustedProfile(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckIAMTrustedProfile(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileClaimRuleDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileClaimRuleConfig(profileName, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileClaimRuleExists("ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", conf), @@ -52,7 +56,7 @@ func TestAccIBMIAMTrustedProfileClaimRuleAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", "cr_type", "IKS_SA"), ), }, - resource.TestStep{ + { ResourceName: "ibm_iam_trusted_profile_claim_rule.iam_trusted_profile_claim_rule", ImportState: true, ImportStateVerify: true, @@ -78,7 +82,7 @@ func testAccCheckIBMIamTrustedProfileClaimRuleConfigBasic(profileName string) st value = "\"cloud-docs-dev\"" } } - `, profileName, realmName) + `, profileName, acc.RealmName) } func testAccCheckIBMIamTrustedProfileClaimRuleConfig(profileName string, name string) string { @@ -108,14 +112,14 @@ func testAccCheckIBMIamTrustedProfileClaimRuleExists(n string, obj iamidentityv1 return fmt.Errorf("Not found: %s", n) } - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } getClaimRuleOptions := &iamidentityv1.GetClaimRuleOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -134,7 +138,7 @@ func testAccCheckIBMIamTrustedProfileClaimRuleExists(n string, obj iamidentityv1 } func testAccCheckIBMIamTrustedProfileClaimRuleDestroy(s *terraform.State) error { - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -145,7 +149,7 @@ func testAccCheckIBMIamTrustedProfileClaimRuleDestroy(s *terraform.State) error getClaimRuleOptions := &iamidentityv1.GetClaimRuleOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -159,7 +163,7 @@ func testAccCheckIBMIamTrustedProfileClaimRuleDestroy(s *terraform.State) error if err == nil { return fmt.Errorf("iam_trusted_profile_claim_rule still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for iam_trusted_profile_claim_rule (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for iam_trusted_profile_claim_rule (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link.go new file mode 100644 index 000000000..2cd94d67c --- /dev/null +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link.go @@ -0,0 +1,243 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" +) + +func ResourceIBMIAMTrustedProfileLink() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIamTrustedProfileLinkCreate, + ReadContext: resourceIBMIamTrustedProfileLinkRead, + DeleteContext: resourceIBMIamTrustedProfileLinkDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "ID of the trusted profile.", + ValidateFunc: validate.InvokeValidator("ibm_iam_trusted_profile_link", + "profile_id"), + }, + "cr_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + }, + "link": { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + ForceNew: true, + Description: "Link details.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Required: true, + Description: "The CRN of the compute resource.", + }, + "namespace": { + Type: schema.TypeString, + Optional: true, + Description: "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Optional name of the Link.", + }, + "link_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier of this link.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "version of the claim rule.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the creation date in ISO format.", + }, + "modified_at": { + Type: schema.TypeString, + Computed: true, + Description: "If set contains a date time string of the last modification date in ISO format.", + }, + }, + } +} + +func ResourceIBMIAMTrustedProfileLinkValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIAMTrustedProfileLinkValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_link", Schema: validateSchema} + return &iBMIAMTrustedProfileLinkValidator +} + +func resourceIBMIamTrustedProfileLinkCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + + createLinkOptions := &iamidentityv1.CreateLinkOptions{} + profile := d.Get("profile_id").(string) + createLinkOptions.SetProfileID(profile) + createLinkOptions.SetCrType(d.Get("cr_type").(string)) + link := resourceIBMIamTrustedProfileLinkMapToCreateProfileLinkRequestLink(d.Get("link.0").(map[string]interface{})) + createLinkOptions.SetLink(&link) + if _, ok := d.GetOk("name"); ok { + createLinkOptions.SetName(d.Get("name").(string)) + } + + profileLink, response, err := iamIdentityClient.CreateLink(createLinkOptions) + if err != nil { + log.Printf("[DEBUG] CreateLink failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateLink failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", profile, *profileLink.ID)) + + return resourceIBMIamTrustedProfileLinkRead(context, d, meta) +} + +func resourceIBMIamTrustedProfileLinkMapToCreateProfileLinkRequestLink(createProfileLinkRequestLinkMap map[string]interface{}) iamidentityv1.CreateProfileLinkRequestLink { + createProfileLinkRequestLink := iamidentityv1.CreateProfileLinkRequestLink{} + + createProfileLinkRequestLink.CRN = core.StringPtr(createProfileLinkRequestLinkMap["crn"].(string)) + createProfileLinkRequestLink.Namespace = core.StringPtr(createProfileLinkRequestLinkMap["namespace"].(string)) + if createProfileLinkRequestLinkMap["name"] != nil { + createProfileLinkRequestLink.Name = core.StringPtr(createProfileLinkRequestLinkMap["name"].(string)) + } + + return createProfileLinkRequestLink +} + +func resourceIBMIamTrustedProfileLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Invalid ID %s", err)) + } + getLinkOptions := &iamidentityv1.GetLinkOptions{} + + getLinkOptions.SetProfileID(parts[0]) + getLinkOptions.SetLinkID(parts[1]) + + profileLink, response, err := iamIdentityClient.GetLink(getLinkOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetLink failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLink failed %s\n%s", err, response)) + } + + if err = d.Set("profile_id", getLinkOptions.ProfileID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile_id: %s", err)) + } + if err = d.Set("cr_type", profileLink.CrType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cr_type: %s", err)) + } + linkMap := resourceIBMIamTrustedProfileLinkCreateProfileLinkRequestLinkToMap(*profileLink.Link) + if err = d.Set("link", []map[string]interface{}{linkMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting link: %s", err)) + } + if err = d.Set("name", profileLink.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("link_id", profileLink.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) + } + if err = d.Set("entity_tag", profileLink.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting entity_tag: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(profileLink.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("modified_at", flex.DateTimeToString(profileLink.ModifiedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_at: %s", err)) + } + + return nil +} + +func resourceIBMIamTrustedProfileLinkCreateProfileLinkRequestLinkToMap(createProfileLinkRequestLink iamidentityv1.ProfileLinkLink) map[string]interface{} { + createProfileLinkRequestLinkMap := map[string]interface{}{} + + createProfileLinkRequestLinkMap["crn"] = createProfileLinkRequestLink.CRN + createProfileLinkRequestLinkMap["namespace"] = createProfileLinkRequestLink.Namespace + if createProfileLinkRequestLink.Name != nil { + createProfileLinkRequestLinkMap["name"] = createProfileLinkRequestLink.Name + } + + return createProfileLinkRequestLinkMap +} + +func resourceIBMIamTrustedProfileLinkDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + iamIdentityClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Invalid ID %s", err)) + } + + deleteLinkOptions := &iamidentityv1.DeleteLinkOptions{} + + deleteLinkOptions.SetProfileID(parts[0]) + deleteLinkOptions.SetLinkID(parts[1]) + + response, err := iamIdentityClient.DeleteLink(deleteLinkOptions) + if err != nil { + log.Printf("[DEBUG] DeleteLink failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteLink failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/resource_ibm_iam_trusted_profile_link_test.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link_test.go similarity index 82% rename from ibm/resource_ibm_iam_trusted_profile_link_test.go rename to ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link_test.go index 19b8f229d..8da814680 100644 --- a/ibm/resource_ibm_iam_trusted_profile_link_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_link_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,11 +24,11 @@ func TestAccIBMIAMTrustedProfileLinkBasic(t *testing.T) { crType := "IKS_SA" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileLinkDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileLinkConfigBasic(profileName, crType), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileLinkExists("ibm_iam_trusted_profile_link.iam_trusted_profile_link", conf), @@ -42,11 +46,11 @@ func TestAccIBMIAMTrustedProfileLinkAllArgs(t *testing.T) { name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileLinkDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileLinkConfig(profileName, crType, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileLinkExists("ibm_iam_trusted_profile_link.iam_trusted_profile_link", conf), @@ -54,7 +58,7 @@ func TestAccIBMIAMTrustedProfileLinkAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_trusted_profile_link.iam_trusted_profile_link", "name", name), ), }, - resource.TestStep{ + { ResourceName: "ibm_iam_trusted_profile_link.iam_trusted_profile_link", ImportState: true, ImportStateVerify: true, @@ -77,7 +81,7 @@ func testAccCheckIBMIamTrustedProfileLinkConfigBasic(profileName string, crType name = "name" } } - `, profileName, crType, iksSa) + `, profileName, crType, acc.IksSa) } func testAccCheckIBMIamTrustedProfileLinkConfig(profileName string, crType string, name string) string { @@ -95,7 +99,7 @@ func testAccCheckIBMIamTrustedProfileLinkConfig(profileName string, crType strin } name = "%s" } - `, profileName, crType, iksSa, name) + `, profileName, crType, acc.IksSa, name) } func testAccCheckIBMIamTrustedProfileLinkExists(n string, obj iamidentityv1.ProfileLink) resource.TestCheckFunc { @@ -106,14 +110,14 @@ func testAccCheckIBMIamTrustedProfileLinkExists(n string, obj iamidentityv1.Prof return fmt.Errorf("Not found: %s", n) } - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } getLinkOptions := &iamidentityv1.GetLinkOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -132,7 +136,7 @@ func testAccCheckIBMIamTrustedProfileLinkExists(n string, obj iamidentityv1.Prof } func testAccCheckIBMIamTrustedProfileLinkDestroy(s *terraform.State) error { - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -143,7 +147,7 @@ func testAccCheckIBMIamTrustedProfileLinkDestroy(s *terraform.State) error { getLinkOptions := &iamidentityv1.GetLinkOptions{} - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -157,7 +161,7 @@ func testAccCheckIBMIamTrustedProfileLinkDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("iam_trusted_profile_link still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for iam_trusted_profile_link (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for iam_trusted_profile_link (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_iam_trusted_profile_test.go b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_test.go similarity index 86% rename from ibm/resource_ibm_iam_trusted_profile_test.go rename to ibm/service/iamidentity/resource_ibm_iam_trusted_profile_test.go index 991b27f00..958eca399 100644 --- a/ibm/resource_ibm_iam_trusted_profile_test.go +++ b/ibm/service/iamidentity/resource_ibm_iam_trusted_profile_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,18 +23,18 @@ func TestAccIBMIAMTrustedProfileBasic(t *testing.T) { nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileExists("ibm_iam_trusted_profile.iam_trusted_profile", conf), resource.TestCheckResourceAttr("ibm_iam_trusted_profile.iam_trusted_profile", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileConfigBasic(nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_trusted_profile.iam_trusted_profile", "name", nameUpdate), @@ -49,11 +52,11 @@ func TestAccIBMIAMTrustedProfileAllArgs(t *testing.T) { descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIamTrustedProfileDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileConfig(name, description), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIamTrustedProfileExists("ibm_iam_trusted_profile.iam_trusted_profile", conf), @@ -61,14 +64,14 @@ func TestAccIBMIAMTrustedProfileAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_trusted_profile.iam_trusted_profile", "description", description), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIamTrustedProfileConfig(nameUpdate, descriptionUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_trusted_profile.iam_trusted_profile", "name", nameUpdate), resource.TestCheckResourceAttr("ibm_iam_trusted_profile.iam_trusted_profile", "description", descriptionUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_iam_trusted_profile.iam_trusted_profile", ImportState: true, ImportStateVerify: true, @@ -104,7 +107,7 @@ func testAccCheckIBMIamTrustedProfileExists(n string, obj iamidentityv1.TrustedP return fmt.Errorf("Not found: %s", n) } - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -124,7 +127,7 @@ func testAccCheckIBMIamTrustedProfileExists(n string, obj iamidentityv1.TrustedP } func testAccCheckIBMIamTrustedProfileDestroy(s *terraform.State) error { - iamIdentityClient, err := testAccProvider.Meta().(ClientSession).IAMIdentityV1API() + iamIdentityClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMIdentityV1API() if err != nil { return err } @@ -143,7 +146,7 @@ func testAccCheckIBMIamTrustedProfileDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("iam_trusted_profile still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for iam_trusted_profile (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for iam_trusted_profile (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_iam_user_settings.go b/ibm/service/iamidentity/resource_ibm_iam_user_settings.go similarity index 79% rename from ibm/resource_ibm_iam_user_settings.go rename to ibm/service/iamidentity/resource_ibm_iam_user_settings.go index c10cd0acd..9f32986d3 100644 --- a/ibm/resource_ibm_iam_user_settings.go +++ b/ibm/service/iamidentity/resource_ibm_iam_user_settings.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iamidentity import ( "fmt" "strings" v2 "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -16,7 +18,7 @@ const ( iamUserSettingAllowedIPAddresses = "allowed_ip_addresses" ) -func resourceIBMUserSettings() *schema.Resource { +func ResourceIBMIAMUserSettings() *schema.Resource { return &schema.Resource{ Create: resourceIBMIAMUserSettingsCreate, Read: resourceIBMIAMUserSettingsRead, @@ -46,7 +48,7 @@ func resourceIBMUserSettings() *schema.Resource { } func resourceIBMIAMUserSettingsCreate(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -60,7 +62,7 @@ func resourceIBMIAMUserSettingsCreate(d *schema.ResourceData, meta interface{}) return err } - iamID, err := getIBMUniqueId(accountID, userEmail, meta) + iamID, err := flex.GetIBMUniqueId(accountID, userEmail, meta) if err != nil { return err } @@ -79,7 +81,7 @@ func resourceIBMIAMUserSettingsCreate(d *schema.ResourceData, meta interface{}) _, UserSettingError := client.ManageUserSettings(accountID, iamID, UserSettingsPayload) if UserSettingError != nil && !strings.Contains(UserSettingError.Error(), "EmptyResponseBody") { - return fmt.Errorf("Error occured during user settings: %s", UserSettingError) + return fmt.Errorf("[ERROR] Error occured during user settings: %s", UserSettingError) } d.SetId(userEmail) @@ -88,15 +90,15 @@ func resourceIBMIAMUserSettingsCreate(d *schema.ResourceData, meta interface{}) } func getUserAccountID(d *schema.ResourceData, meta interface{}) (string, error) { - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return "", err } - return userDetails.userAccount, nil + return userDetails.UserAccount, nil } func resourceIBMIAMUserSettingsRead(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -107,7 +109,7 @@ func resourceIBMIAMUserSettingsRead(d *schema.ResourceData, meta interface{}) er return err } - iamID, err := getIBMUniqueId(accountID, d.Id(), meta) + iamID, err := flex.GetIBMUniqueId(accountID, d.Id(), meta) if err != nil { return err } @@ -126,7 +128,7 @@ func resourceIBMIAMUserSettingsRead(d *schema.ResourceData, meta interface{}) er func resourceIBMIAMUserSettingsUpdate(d *schema.ResourceData, meta interface{}) error { // validate change - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -137,7 +139,7 @@ func resourceIBMIAMUserSettingsUpdate(d *schema.ResourceData, meta interface{}) return err } - iamID, err := getIBMUniqueId(accountID, d.Id(), meta) + iamID, err := flex.GetIBMUniqueId(accountID, d.Id(), meta) if err != nil { return err } @@ -161,7 +163,7 @@ func resourceIBMIAMUserSettingsUpdate(d *schema.ResourceData, meta interface{}) if hasChanged { _, UserSettingError := client.ManageUserSettings(accountID, iamID, userSettingPayload) if UserSettingError != nil && !strings.Contains(UserSettingError.Error(), "EmptyResponseBody") { - return fmt.Errorf("Error occured during user settings: %s", UserSettingError) + return fmt.Errorf("[ERROR] Error occured during user settings: %s", UserSettingError) } } @@ -169,7 +171,7 @@ func resourceIBMIAMUserSettingsUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMIAMUserSettingsDelete(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -180,7 +182,7 @@ func resourceIBMIAMUserSettingsDelete(d *schema.ResourceData, meta interface{}) return err } - iamID, err := getIBMUniqueId(accountID, d.Id(), meta) + iamID, err := flex.GetIBMUniqueId(accountID, d.Id(), meta) if err != nil { return err } @@ -189,14 +191,14 @@ func resourceIBMIAMUserSettingsDelete(d *schema.ResourceData, meta interface{}) _, UserSettingError := client.ManageUserSettings(accountID, iamID, userSettingPayload) if UserSettingError != nil && !strings.Contains(UserSettingError.Error(), "EmptyResponseBody") { - return fmt.Errorf("Error occured during user settings: %s", UserSettingError) + return fmt.Errorf("[ERROR] Error occured during user settings: %s", UserSettingError) } return nil } func resourceIBMIAMUserSettingsExists(d *schema.ResourceData, meta interface{}) (bool, error) { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return false, err } @@ -207,7 +209,7 @@ func resourceIBMIAMUserSettingsExists(d *schema.ResourceData, meta interface{}) return false, err } - iamID, err := getIBMUniqueId(accountID, d.Id(), meta) + iamID, err := flex.GetIBMUniqueId(accountID, d.Id(), meta) if err != nil { return false, err } diff --git a/ibm/service/iamidentity/resource_ibm_iam_user_settings_test.go b/ibm/service/iamidentity/resource_ibm_iam_user_settings_test.go new file mode 100644 index 000000000..00a7387aa --- /dev/null +++ b/ibm/service/iamidentity/resource_ibm_iam_user_settings_test.go @@ -0,0 +1,146 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iamidentity_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMUserSettings_Basic(t *testing.T) { + t.Skip() + var allowedIP string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserSettingsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserSettingsBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserSettingsExists("ibm_iam_user_settings.user_settings", allowedIP), + resource.TestCheckResourceAttr("ibm_iam_user_settings.user_settings", "allowed_ip_addresses.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMUserSettingsUpdate(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_user_settings.user_settings", "allowed_ip_addresses.#", "4"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMUserSettingsDestroy(s *terraform.State) error { + + userManagement, err := acc.TestAccProvider.Meta().(conns.ClientSession).UserManagementAPI() + if err != nil { + return err + } + client := userManagement.UserInvite() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_user_settings" { + continue + } + + usermail := rs.Primary.ID + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + iamID, err := flex.GetIBMUniqueId(accountID, usermail, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + UserSetting, UserSettingError := client.GetUserSettings(accountID, iamID) + if UserSettingError == nil && UserSetting.AllowedIPAddresses != "" { + return fmt.Errorf("Allowed IP setting still exists: %s", usermail) + } + } + + return nil +} + +func testAccCheckIBMIAMUserSettingsExists(n string, ip string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No ID is set") + } + + userManagement, err := acc.TestAccProvider.Meta().(conns.ClientSession).UserManagementAPI() + if err != nil { + return err + } + + client := userManagement.UserInvite() + + usermail := rs.Primary.ID + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + iamID, err := flex.GetIBMUniqueId(accountID, usermail, acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + UserSetting, UserSettingError := client.GetUserSettings(accountID, iamID) + if UserSettingError != nil { + return fmt.Errorf("ERROR in getting user settings: %s", rs.Primary.ID) + } + + ip = UserSetting.AllowedIPAddresses + return nil + } +} + +func testAccCheckIBMIAMUserSettingsBasic() string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_settings" "user_settings" { + iam_id = "%s" + allowed_ip_addresses = ["192.168.0.0","192.168.0.1"] + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserSettingsUpdate() string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_settings" "user_settings" { + iam_id = "%s" + allowed_ip_addresses = ["192.168.0.2","192.168.0.3","192.168.0.4","192.168.0.5"] + } + + `, acc.IAMUser) +} diff --git a/ibm/service/iampolicy/README.md b/ibm/service/iampolicy/README.md new file mode 100644 index 000000000..c966cf944 --- /dev/null +++ b/ibm/service/iampolicy/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider IAM Policy Management + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the IAM Policy Management resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_access_group_policy) +* IBM API Docs: [IBM API Docs for IAM Policy Management](https://cloud.ibm.com/apidocs/iam-policy-management) +* IBM IAM Policy Management SDK: [IBM SDK for IAM Policy Management](https://github.com/IBM/platform-services-go-sdk/tree/main/iampolicymanagementv1) diff --git a/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy.go b/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy.go new file mode 100644 index 000000000..3b31a39de --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy.go @@ -0,0 +1,220 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Data source to find all the policies for an access group in a particular account +func DataSourceIBMIAMAccessGroupPolicy() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMAccessGroupPolicyRead, + + Schema: map[string]*schema.Schema{ + "access_group_id": { + Description: "ID of access group", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_access_group_policy", + "access_group_id"), + }, + "sort": { + Description: "Sort query for policies", + Type: schema.TypeString, + Optional: true, + }, + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + "policies": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Computed: true, + Description: "Service name of the policy definition", + }, + "resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "ID of resource instance of the policy definition", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "Region of the policy definition", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of the policy definition", + }, + "resource": { + Type: schema.TypeString, + Computed: true, + Description: "Resource of the policy definition", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the resource group.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, + "attributes": { + Type: schema.TypeMap, + Computed: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + "resource_tags": { + Type: schema.TypeSet, + Computed: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator of attribute.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the Policy", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIAMAccessGroupPolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:access_group", "resolved_to:id"}, + Required: true}) + + iBMIAMAccessGroupPolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_access_group_policy", Schema: validateSchema} + return &iBMIAMAccessGroupPolicyValidator +} + +func dataSourceIBMIAMAccessGroupPolicyRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + accessGroupId := d.Get("access_group_id").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(accountID), + AccessGroupID: core.StringPtr(accessGroupId), + Type: core.StringPtr("access"), + } + + if v, ok := d.GetOk("sort"); ok { + listPoliciesOptions.Sort = core.StringPtr(v.(string)) + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + listPoliciesOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policyList, resp, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) + + if err != nil || resp == nil { + return fmt.Errorf("Error listing access group policies: %s, %s", err, resp) + } + + policies := policyList.Policies + accessGroupPolicies := make([]map[string]interface{}, 0, len(policies)) + for _, policy := range policies { + roles := make([]string, len(policy.Roles)) + for i, role := range policy.Roles { + roles[i] = *role.DisplayName + } + resources := flex.FlattenPolicyResource(policy.Resources) + p := map[string]interface{}{ + "id": fmt.Sprintf("%s/%s", accessGroupId, *policy.ID), + "roles": roles, + "resources": resources, + "resource_tags": flex.FlattenPolicyResourceTags(policy.Resources), + } + if policy.Description != nil { + p["description"] = policy.Description + } + accessGroupPolicies = append(accessGroupPolicies, p) + } + d.SetId(accessGroupId) + + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + + d.Set("policies", accessGroupPolicies) + + return nil +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy_test.go b/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy_test.go new file mode 100644 index 000000000..55a0a2dc0 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_access_group_policy_test.go @@ -0,0 +1,170 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIAMAccessGroupPolicyDataSource_Basic(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_access_group_policy.testacc_ds_access_group_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicyDataSource_Multiple_Policies(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyDataSourceMultiplePolicies(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_access_group_policy.testacc_ds_access_group_policy", "policies.#"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicyDataSourceSpecificAttributesConfig(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyDataSourceSpecificAttributesConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_access_group_policy.testacc_ds_access_group_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMAccessGroupPolicyDataSourceConfig(name string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_access_group" "accgrp" { + name = "%s" +} + +resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_iam_access_group_policy" "testacc_ds_access_group_policy" { + access_group_id = ibm_iam_access_group_policy.policy.access_group_id +} +`, name, name) + +} + +func testAccCheckIBMIAMAccessGroupPolicyDataSourceMultiplePolicies(name string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_access_group" "accgrp" { + name = "%s" +} + +resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Manager", "Viewer", "Administrator"] + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_iam_access_group_policy" "policy1" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } +} + + +data "ibm_iam_access_group_policy" "testacc_ds_access_group_policy" { + access_group_id = ibm_iam_access_group_policy.policy.access_group_id + sort = "-id" +}`, name, name) + +} + +func testAccCheckIBMIAMAccessGroupPolicyDataSourceSpecificAttributesConfig(name string) string { + return fmt.Sprintf(` + + +resource "ibm_iam_access_group" "accgrp" { + name = "%s" +} + +resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Manager", "Viewer", "Administrator"] + + resource_attributes { + name = "serviceName" + value = "containers-kubernetes" + } + resource_attributes { + name = "namespace" + value = "test" + } +} + +data "ibm_iam_access_group_policy" "testacc_ds_access_group_policy" { + access_group_id = ibm_iam_access_group_policy.policy.access_group_id +} +`, name) + +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies.go b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies.go new file mode 100644 index 000000000..86220c737 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Data source to find all the authorization policies in a particular account +func DataSourceIBMIAMAuthorizationPolicies() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMAuthorizationPoliciesRead, + + Schema: map[string]*schema.Schema{ + "account_id": { + Description: "The unique ID of an account", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "sort": { + Description: "Sort query for policies", + Type: schema.TypeString, + Optional: true, + }, + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + "policies": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + + "source_service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The source service name", + }, + + "target_service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The target service name", + }, + + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "source_resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "The source resource instance Id", + }, + + "target_resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "The target resource instance Id", + }, + + "source_resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The source resource group Id", + }, + + "target_resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The target resource group Id", + }, + + "source_resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of source service", + }, + + "target_resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of target service", + }, + + "source_service_account": { + Type: schema.TypeString, + Computed: true, + Description: "Account GUID of source service", + }, + + "version": { + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the Policy", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIAMAuthorizationPoliciesRead(d *schema.ResourceData, meta interface{}) error { + var accountID string + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + if account, ok := d.GetOk("account_id"); ok && account.(string) != "" { + accountID = account.(string) + } else { + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + accountID = userDetails.UserAccount + } + + listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(accountID), + Type: core.StringPtr("authorization"), + } + + if v, ok := d.GetOk("sort"); ok { + listPoliciesOptions.Sort = core.StringPtr(v.(string)) + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + listPoliciesOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policyList, resp, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) + + if err != nil || resp == nil { + return fmt.Errorf("[ERROR] Error listing authorization policies: %s, %s", err, resp) + } + + policies := policyList.Policies + + authorizationPolicies := make([]map[string]interface{}, 0, len(policies)) + for _, policy := range policies { + roles := make([]string, len(policy.Roles)) + for i, role := range policy.Roles { + roles[i] = *role.DisplayName + } + source := policy.Subjects[0] + target := policy.Resources[0] + + p := map[string]interface{}{ + "id": fmt.Sprintf("%s/%s", accountID, *policy.ID), + "roles": roles, + "source_service_name": *flex.GetSubjectAttribute("serviceName", source), + "target_service_name": *flex.GetResourceAttribute("serviceName", target), + "source_resource_instance_id": *flex.GetSubjectAttribute("serviceInstance", source), + "target_resource_instance_id": *flex.GetResourceAttribute("serviceInstance", target), + "source_resource_type": *flex.GetSubjectAttribute("resourceType", source), + "target_resource_type": *flex.GetResourceAttribute("resourceType", target), + "source_service_account": *flex.GetSubjectAttribute("accountId", source), + "source_resource_group_id": *flex.GetSubjectAttribute("resourceGroupId", source), + "target_resource_group_id": *flex.GetResourceAttribute("resourceGroupId", target), + } + if policy.Description != nil { + p["description"] = *policy.Description + } + authorizationPolicies = append(authorizationPolicies, p) + } + + d.SetId(time.Now().UTC().String()) + d.Set("account_id", accountID) + + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + + d.Set("policies", authorizationPolicies) + + return nil +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go new file mode 100644 index 000000000..213b185ac --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go @@ -0,0 +1,80 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIAMAuthorizationPoliciesDataSource_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPoliciesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_authorization_policies.testacc_ds_authorization_policies", "id"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAuthorizationPoliciesDataSource_Multiple_Policies(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPoliciesDataSourceMultiplePolicies(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("ibm_iam_authorization_policy.policy", "id"), + ), + }, + { + Config: testAccCheckIBMIAMAuthorizationPoliciesDataSourceConfigSort(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_authorization_policies.testacc_ds_authorization_policies", "policies.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMAuthorizationPoliciesDataSourceConfig() string { + return ` + data "ibm_iam_authorization_policies" "testacc_ds_authorization_policies" { + }` +} + +func testAccCheckIBMIAMAuthorizationPoliciesDataSourceConfigSort() string { + return ` + data "ibm_iam_authorization_policies" "testacc_ds_authorization_policies" { + sort = "-id" + }` +} + +func testAccCheckIBMIAMAuthorizationPoliciesDataSourceMultiplePolicies() string { + return ` + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "databases-for-redis" + target_service_name = "kms" + roles = ["Reader", "Authorization Delegator"] + } + + resource "ibm_iam_authorization_policy" "policy1" { + source_service_name = "is" + source_resource_type = "load-balancer" + target_service_name = "cloudcerts" + roles = ["Reader"] + } + ` +} diff --git a/ibm/data_source_ibm_iam_role_actions.go b/ibm/service/iampolicy/data_source_ibm_iam_role_actions.go similarity index 78% rename from ibm/data_source_ibm_iam_role_actions.go rename to ibm/service/iampolicy/data_source_ibm_iam_role_actions.go index 133c829ee..941874107 100644 --- a/ibm/data_source_ibm_iam_role_actions.go +++ b/ibm/service/iampolicy/data_source_ibm_iam_role_actions.go @@ -1,15 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy import ( + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "strings" ) -func datasourceIBMIAMRoleAction() *schema.Resource { +func DataSourceIBMIAMRoleAction() *schema.Resource { return &schema.Resource{ Read: datasourceIBMIAMRoleActionRead, @@ -55,7 +58,7 @@ func datasourceIBMIAMRoleAction() *schema.Resource { } func datasourceIBMIAMRoleActionRead(d *schema.ResourceData, meta interface{}) error { - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return err } @@ -73,10 +76,10 @@ func datasourceIBMIAMRoleActionRead(d *schema.ResourceData, meta interface{}) er } serviceRoles := roleList.ServiceRoles - d.Set("reader", flattenActionbyDisplayName("Reader", serviceRoles)) - d.Set("manager", flattenActionbyDisplayName("Manager", serviceRoles)) - d.Set("reader_plus", flattenActionbyDisplayName("ReaderPlus", serviceRoles)) - d.Set("writer", flattenActionbyDisplayName("Writer", serviceRoles)) + d.Set("reader", flex.FlattenActionbyDisplayName("Reader", serviceRoles)) + d.Set("manager", flex.FlattenActionbyDisplayName("Manager", serviceRoles)) + d.Set("reader_plus", flex.FlattenActionbyDisplayName("ReaderPlus", serviceRoles)) + d.Set("writer", flex.FlattenActionbyDisplayName("Writer", serviceRoles)) d.Set("actions", flattenRoleActions(serviceRoles)) return nil diff --git a/ibm/data_source_ibm_iam_role_actions_test.go b/ibm/service/iampolicy/data_source_ibm_iam_role_actions_test.go similarity index 92% rename from ibm/data_source_ibm_iam_role_actions_test.go rename to ibm/service/iampolicy/data_source_ibm_iam_role_actions_test.go index 77b70cef6..ee4f57f57 100644 --- a/ibm/data_source_ibm_iam_role_actions_test.go +++ b/ibm/service/iampolicy/data_source_ibm_iam_role_actions_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,10 +20,10 @@ func TestAccIBMIAMRoleDataSourceAction_basic(t *testing.T) { name := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMRoleActionConfig(name, displayName, serviceName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_iam_role_actions.test", "service", serviceName), @@ -41,10 +43,10 @@ func TestAccIBMIAMRoleDataSourceAction_withServiceSpecificRoleActions(t *testing name := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMCustomServiceRoleActionsConfig(name, displayName, serviceName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_iam_role_actions.example", "service", serviceName), diff --git a/ibm/service/iampolicy/data_source_ibm_iam_roles.go b/ibm/service/iampolicy/data_source_ibm_iam_roles.go new file mode 100644 index 000000000..a593f5ebd --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_roles.go @@ -0,0 +1,87 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIAMRole() *schema.Resource { + return &schema.Resource{ + Read: datasourceIBMIAMRoleRead, + + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "The Service Name", + ForceNew: true, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } + +} + +func datasourceIBMIAMRoleRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + var serviceName string + var customRoles []iampolicymanagementv1.CustomRole + var serviceRoles, systemRoles []iampolicymanagementv1.Role + + listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ + AccountID: &userDetails.UserAccount, + } + + if service, ok := d.GetOk("service"); ok { + serviceName = service.(string) + listRoleOptions.ServiceName = &serviceName + } + roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) + if err != nil { + return err + } + customRoles = roleList.CustomRoles + serviceRoles = roleList.ServiceRoles + systemRoles = roleList.SystemRoles + + d.SetId(userDetails.UserAccount) + + roles := append(flex.FlattenRoleData(systemRoles, "platform"), append(flex.FlattenRoleData(serviceRoles, "service"), flex.FlattenCustomRoleData(customRoles, "custom")...)...) + + d.Set("roles", roles) + + return nil +} diff --git a/ibm/data_source_ibm_iam_roles_test.go b/ibm/service/iampolicy/data_source_ibm_iam_roles_test.go similarity index 86% rename from ibm/data_source_ibm_iam_roles_test.go rename to ibm/service/iampolicy/data_source_ibm_iam_roles_test.go index 9974d5e5c..71a0f3987 100644 --- a/ibm/data_source_ibm_iam_roles_test.go +++ b/ibm/service/iampolicy/data_source_ibm_iam_roles_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMIAMRoleDataSourcebasic(t *testing.T) { name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMRoleConfig(name, serviceName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_iam_roles.test", "service", serviceName), diff --git a/ibm/service/iampolicy/data_source_ibm_iam_service_policy.go b/ibm/service/iampolicy/data_source_ibm_iam_service_policy.go new file mode 100644 index 000000000..f45365f75 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_service_policy.go @@ -0,0 +1,256 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" +) + +// Data source to find all the policies for a serviceID +func DataSourceIBMIAMServicePolicy() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMServicePolicyRead, + + Schema: map[string]*schema.Schema{ + "iam_service_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "UUID of ServiceID", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_service_policy", + "iam_service_id"), + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "IAM ID of ServiceID", + }, + "sort": { + Description: "Sort query for policies", + Type: schema.TypeString, + Optional: true, + }, + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + "policies": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Computed: true, + Description: "Service name of the policy definition", + }, + "resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "ID of resource instance of the policy definition", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "Region of the policy definition", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of the policy definition", + }, + "resource": { + Type: schema.TypeString, + Computed: true, + Description: "Resource of the policy definition", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the resource group.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, + "attributes": { + Type: schema.TypeMap, + Computed: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + "resource_tags": { + Type: schema.TypeSet, + Computed: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator of attribute.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the Policy", + }, + }, + }, + }, + }, + } +} +func DataSourceIBMIAMServicePolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "iam_service_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:service_id", "resolved_to:id"}, + Optional: true}) + + iBMIAMServicePolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_service_policy", Schema: validateSchema} + return &iBMIAMServicePolicyValidator +} + +func dataSourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) error { + + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + + serviceIDUUID := v.(string) + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ + ID: &serviceIDUUID, + } + serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) + if err != nil || resp == nil { + return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) + } + iamID = *serviceID.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(userDetails.UserAccount), + IamID: core.StringPtr(iamID), + Type: core.StringPtr("access"), + } + + if v, ok := d.GetOk("sort"); ok { + listPoliciesOptions.Sort = core.StringPtr(v.(string)) + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + listPoliciesOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policyList, resp, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) + + if err != nil { + return fmt.Errorf("Error listing service policies: %s, %s", err, resp) + } + + policies := policyList.Policies + servicePolicies := make([]map[string]interface{}, 0, len(policies)) + for _, policy := range policies { + roles := make([]string, len(policy.Roles)) + for i, role := range policy.Roles { + roles[i] = *role.DisplayName + } + resources := flex.FlattenPolicyResource(policy.Resources) + p := map[string]interface{}{ + "roles": roles, + "resources": resources, + "resource_tags": flex.FlattenPolicyResourceTags(policy.Resources), + } + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", serviceIDUUID, *policy.ID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", iamID, *policy.ID) + } + if policy.Description != nil { + p["description"] = policy.Description + } + servicePolicies = append(servicePolicies, p) + } + + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + d.SetId(serviceIDUUID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(iamID) + } + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + d.Set("policies", servicePolicies) + return nil +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_service_policy_test.go b/ibm/service/iampolicy/data_source_ibm_iam_service_policy_test.go new file mode 100644 index 000000000..dc19dbfb8 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_service_policy_test.go @@ -0,0 +1,172 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIAMServicePolicyDataSource_Basic(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_service_policy.testacc_ds_service_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicyDataSource_Multiple_Policies(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyDataSourceMultiplePolicies(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_service_policy.testacc_ds_service_policy", "policies.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicyDataSourceServiceSpecificAttributesConfig(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyDataSourceServiceSpecificAttributesConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_service_policy.testacc_ds_service_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMServicePolicyDataSourceConfig(name string) string { + return fmt.Sprintf(` + +resource "ibm_iam_service_id" "serviceID" { + name = "%s" + description = "Service ID for test" +} + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_iam_service_policy" "testacc_ds_service_policy" { + iam_service_id = ibm_iam_service_policy.policy.iam_service_id +}`, name, name) + +} + +func testAccCheckIBMIAMServicePolicyDataSourceMultiplePolicies(name string) string { + return fmt.Sprintf(` + +resource "ibm_iam_service_id" "serviceID" { + name = "%s" + description = "Service ID for test" +} + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_iam_service_policy" "policy1" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } +} + + +data "ibm_iam_service_policy" "testacc_ds_service_policy" { + iam_service_id = ibm_iam_service_policy.policy.iam_service_id + sort = "id" +}`, name, name) + +} + +func testAccCheckIBMIAMServicePolicyDataSourceServiceSpecificAttributesConfig(name string) string { + return fmt.Sprintf(` + +resource "ibm_iam_service_id" "serviceID" { + name = "%s" + description = "Service ID for test" +} + +resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Manager", "Viewer", "Administrator"] + + resource_attributes { + name = "serviceName" + value = "containers-kubernetes" + } + resource_attributes { + name = "namespace" + value = "test" + } + +} + +data "ibm_iam_service_policy" "testacc_ds_service_policy" { + iam_service_id = ibm_iam_service_policy.policy.iam_service_id +}`, name) + +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy.go b/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy.go new file mode 100644 index 000000000..d0188f93a --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy.go @@ -0,0 +1,257 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" +) + +// Data source to find all the policies for a trusted profile +func DataSourceIBMIAMTrustedProfilePolicy() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMTrustedProfilePolicyRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"profile_id", "iam_id"}, + Description: "UUID of trusted profile", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_iam_trusted_profile_policy", + "profile_id"), + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"profile_id", "iam_id"}, + Description: "IAM ID of trusted profile", + }, + "sort": { + Description: "Sort query for policies", + Type: schema.TypeString, + Optional: true, + }, + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + "policies": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Computed: true, + Description: "Service name of the policy definition", + }, + "resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "ID of resource instance of the policy definition", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "Region of the policy definition", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of the policy definition", + }, + "resource": { + Type: schema.TypeString, + Computed: true, + Description: "Resource of the policy definition", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the resource group.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, + "attributes": { + Type: schema.TypeMap, + Computed: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + "resource_tags": { + Type: schema.TypeSet, + Computed: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator of attribute.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the Policy", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIAMTrustedProfilePolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIAMTrustedProfilePolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_policy", Schema: validateSchema} + return &iBMIAMTrustedProfilePolicyValidator +} + +func dataSourceIBMIAMTrustedProfilePolicyRead(d *schema.ResourceData, meta interface{}) error { + + var iamID string + if v, ok := d.GetOk("profile_id"); ok && v != nil { + + profileUUID := v.(string) + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getprofileOptions := iamidentityv1.GetProfileOptions{ + ProfileID: &profileUUID, + } + profile, resp, err := iamClient.GetProfile(&getprofileOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting profile ID %s %s", err, resp) + } + iamID = *profile.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(userDetails.UserAccount), + IamID: core.StringPtr(iamID), + Type: core.StringPtr("access"), + } + + if v, ok := d.GetOk("sort"); ok { + listPoliciesOptions.Sort = core.StringPtr(v.(string)) + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + listPoliciesOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policyList, resp, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) + + if err != nil || resp == nil { + return fmt.Errorf("Error listing trusted profile policies: %s, %s", err, resp) + } + + policies := policyList.Policies + profilePolicies := make([]map[string]interface{}, 0, len(policies)) + for _, policy := range policies { + roles := make([]string, len(policy.Roles)) + for i, role := range policy.Roles { + roles[i] = *role.DisplayName + } + resources := flex.FlattenPolicyResource(policy.Resources) + p := map[string]interface{}{ + "roles": roles, + "resources": resources, + "resource_tags": flex.FlattenPolicyResourceTags(policy.Resources), + } + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileUUID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", profileUUID, *policy.ID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", iamID, *policy.ID) + } + if policy.Description != nil { + p["description"] = policy.Description + } + profilePolicies = append(profilePolicies, p) + } + + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileUUID := v.(string) + d.SetId(profileUUID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(iamID) + } + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + d.Set("policies", profilePolicies) + return nil +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy_test.go b/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy_test.go new file mode 100644 index 000000000..5d96ebb8f --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_trusted_profile_policy_test.go @@ -0,0 +1,169 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIAMTrustedProfilePolicyDataSource_Basic(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_trusted_profile_policy.policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicyDataSource_Multiple_Policies(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyDataSourceMultiplePolicies(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_trusted_profile_policy.policy", "policies.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicyDataSourceServiceSpecificAttributesConfig(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyDataSourceServiceSpecificAttributesConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_trusted_profile_policy.policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMTrustedProfilePolicyDataSourceConfig(name string) string { + return fmt.Sprintf(` + +resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + description = "Profile ID for test" +} + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile_policy.policy.profile_id +}`, name, name) + +} + +func testAccCheckIBMIAMTrustedProfilePolicyDataSourceMultiplePolicies(name string) string { + return fmt.Sprintf(` + +resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + description = "Profile ID for test" +} + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_iam_trusted_profile_policy" "policy1" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } +} + +data "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile_policy.policy.profile_id + sort = "id" +}`, name, name) + +} + +func testAccCheckIBMIAMTrustedProfilePolicyDataSourceServiceSpecificAttributesConfig(name string) string { + return fmt.Sprintf(` +resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + description = "Profile ID for test" +} + +resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Manager", "Viewer", "Administrator"] + + resource_attributes { + name = "serviceName" + value = "containers-kubernetes" + } + resource_attributes { + name = "namespace" + value = "test" + } +} + +data "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile_policy.policy.profile_id +}`, name) + +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_user_policy.go b/ibm/service/iampolicy/data_source_ibm_iam_user_policy.go new file mode 100644 index 000000000..784b43f84 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_user_policy.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Data source to find all the policies for a user in a particular account +func DataSourceIBMIAMUserPolicy() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIAMUserPolicyRead, + + Schema: map[string]*schema.Schema{ + "ibm_id": { + Description: "The ibm id or email of user", + Type: schema.TypeString, + Required: true, + }, + "sort": { + Description: "Sort query for policies", + Type: schema.TypeString, + Optional: true, + }, + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + "policies": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Computed: true, + Description: "Service name of the policy definition", + }, + "resource_instance_id": { + Type: schema.TypeString, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "ID of resource instance of the policy definition", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "Region of the policy definition", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of the policy definition", + }, + "resource": { + Type: schema.TypeString, + Computed: true, + Description: "Resource of the policy definition", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the resource group.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, + "attributes": { + Type: schema.TypeMap, + Computed: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + "resource_tags": { + Type: schema.TypeSet, + Computed: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: "Operator of attribute.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the Policy", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIAMUserPolicyRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + userEmail := d.Get("ibm_id").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + ibmUniqueID, err := flex.GetIBMUniqueId(accountID, userEmail, meta) + if err != nil { + return err + } + + listPoliciesOptions := &iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(accountID), + IamID: core.StringPtr(ibmUniqueID), + Type: core.StringPtr("access"), + } + + if v, ok := d.GetOk("sort"); ok { + listPoliciesOptions.Sort = core.StringPtr(v.(string)) + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + listPoliciesOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policyList, resp, err := iamPolicyManagementClient.ListPolicies(listPoliciesOptions) + + if err != nil || resp == nil { + return fmt.Errorf("Error listing user policies: %s, %s", err, resp) + } + + policies := policyList.Policies + userPolicies := make([]map[string]interface{}, 0, len(policies)) + for _, policy := range policies { + roles := make([]string, len(policy.Roles)) + for i, role := range policy.Roles { + roles[i] = *role.DisplayName + } + resources := flex.FlattenPolicyResource(policy.Resources) + p := map[string]interface{}{ + "id": fmt.Sprintf("%s/%s", userEmail, *policy.ID), + "roles": roles, + "resources": resources, + "resource_tags": flex.FlattenPolicyResourceTags(policy.Resources), + } + if policy.Description != nil { + p["description"] = policy.Description + } + userPolicies = append(userPolicies, p) + } + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + d.SetId(userEmail) + d.Set("policies", userPolicies) + + return nil +} diff --git a/ibm/service/iampolicy/data_source_ibm_iam_user_policy_test.go b/ibm/service/iampolicy/data_source_ibm_iam_user_policy_test.go new file mode 100644 index 000000000..0814e8284 --- /dev/null +++ b/ibm/service/iampolicy/data_source_ibm_iam_user_policy_test.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// TODO: test fails locally using test env because it returns 3 policies (even existing test) +func TestAccIBMIAMUserPolicyDataSource_Basic(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_user_policy.testacc_ds_user_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicyDataSource_Multiple_Policies(t *testing.T) { + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyDataSourceMultiplePolicies(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_iam_user_policy.testacc_ds_user_policy", "policies.#"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicyDataSource_Service_Specific_Attributes(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyDataSourceServiceSpecificAttributesConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_iam_user_policy.testacc_ds_user_policy", "policies.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMUserPolicyDataSourceConfig(name string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_iam_user_policy" "testacc_ds_user_policy" { + ibm_id = ibm_iam_user_policy.policy.ibm_id +} +`, name, acc.IAMUser) + +} + +func testAccCheckIBMIAMUserPolicyDataSourceMultiplePolicies(name string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } +} + +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_iam_user_policy" "policy1" { + ibm_id = "%s" + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } +} + + +data "ibm_iam_user_policy" "testacc_ds_user_policy" { + ibm_id = ibm_iam_user_policy.policy.ibm_id + sort = "-id" +}`, name, acc.IAMUser, acc.IAMUser) + +} + +func testAccCheckIBMIAMUserPolicyDataSourceServiceSpecificAttributesConfig() string { + return fmt.Sprintf(` + +resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + resource_attributes { + name = "serviceName" + value = "containers-kubernetes" + } + resource_attributes { + name = "namespace" + value = "test" + } +} + +data "ibm_iam_user_policy" "testacc_ds_user_policy" { + ibm_id = ibm_iam_user_policy.policy.ibm_id +} +`, acc.IAMUser) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go new file mode 100644 index 000000000..61d2bd63a --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go @@ -0,0 +1,560 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMAccessGroupPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMAccessGroupPolicyCreate, + Read: resourceIBMIAMAccessGroupPolicyRead, + Update: resourceIBMIAMAccessGroupPolicyUpdate, + Delete: resourceIBMIAMAccessGroupPolicyDelete, + Exists: resourceIBMIAMAccessGroupPolicyExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + resources, resourceAttributes, err := importAccessGroupPolicy(d, meta) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) + } + d.Set("resources", resources) + d.Set("resource_attributes", resourceAttributes) + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "access_group_id": { + Type: schema.TypeString, + Required: true, + Description: "ID of access group", + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_iam_access_group_policy", + "access_group_id"), + }, + + "roles": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "resources": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"account_management", "resource_attributes"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "Service name of the policy definition", + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of resource instance of the policy definition", + }, + + "region": { + Type: schema.TypeString, + Optional: true, + Description: "Region of the policy definition", + }, + + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type of the policy definition", + }, + + "resource": { + Type: schema.TypeString, + Optional: true, + Description: "Resource of the policy definition", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + + "service_type": { + Type: schema.TypeString, + Optional: true, + Description: "Service type of the policy definition", + }, + + "attributes": { + Type: schema.TypeMap, + Optional: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + + "resource_attributes": { + Type: schema.TypeSet, + Optional: true, + Description: "Set resource attributes.", + ConflictsWith: []string{"resources", "account_management"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + "account_management": { + Type: schema.TypeBool, + Default: false, + Optional: true, + Description: "Give access to all account management services", + ConflictsWith: []string{"resources", "resource_attributes"}, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "resource_tags": { + Type: schema.TypeSet, + Optional: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the Policy", + }, + + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + + "version": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIAMAccessGroupPolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:access_group", "resolved_to:id"}, + Required: true}) + + iBMIAMAccessGroupPolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_access_group_policy", Schema: validateSchema} + return &iBMIAMAccessGroupPolicyValidator +} + +func resourceIBMIAMAccessGroupPolicyCreate(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + accessGroupId := d.Get("access_group_id").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + var policyOptions iampolicymanagementv1.CreatePolicyOptions + policyOptions, err = flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + // Keep configuring the policy options by adding subject part + accessGroupIdSubject := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{ + { + Name: core.StringPtr("access_group_id"), + Value: &accessGroupId, + }, + }, + } + + accountIdResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: &userDetails.UserAccount, + } + + policyResource := &iampolicymanagementv1.PolicyResource{ + Attributes: append(policyOptions.Resources[0].Attributes, *accountIdResourceAttribute), + Tags: flex.SetTags(d), + } + + createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( + "access", + []iampolicymanagementv1.PolicySubject{*accessGroupIdSubject}, + policyOptions.Roles, + []iampolicymanagementv1.PolicyResource{*policyResource}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + createPolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + accessGroupPolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) + if err != nil || accessGroupPolicy == nil { + return fmt.Errorf("[ERROR] Error creating access group policy: %s\n%s", err, res) + } + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: accessGroupPolicy.ID, + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || policy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil { + d.SetId(fmt.Sprintf("%s/%s", accessGroupId, *accessGroupPolicy.ID)) + return fmt.Errorf("[ERROR] Error fetching access group policy: %s\n%s", err, res) + } + d.SetId(fmt.Sprintf("%s/%s", accessGroupId, *accessGroupPolicy.ID)) + + return resourceIBMIAMAccessGroupPolicyRead(d, meta) +} + +func resourceIBMIAMAccessGroupPolicyRead(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + accessGroupId := parts[0] + accessGroupPolicyId := parts[1] + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: &accessGroupPolicyId, + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + accessGroupPolicy := &iampolicymanagementv1.Policy{} + res := &core.DetailedResponse{} + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + accessGroupPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || accessGroupPolicy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + accessGroupPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil || accessGroupPolicy == nil || res == nil { + return fmt.Errorf("[ERROR] Error retrieving access group policy: %s\n%s", err, res) + } + + retrievedAttribute := flex.GetSubjectAttribute("access_group_id", accessGroupPolicy.Subjects[0]) + if accessGroupId != *retrievedAttribute { + return fmt.Errorf("[ERROR] Policy %s does not belong to access group %s, retrievedAttr: %s", accessGroupPolicyId, accessGroupId, *retrievedAttribute) + } + + d.Set("access_group_id", accessGroupId) + roles := make([]string, len(accessGroupPolicy.Roles)) + for i, role := range accessGroupPolicy.Roles { + roles[i] = *role.DisplayName + } + d.Set("roles", roles) + d.Set("version", res.Headers.Get("ETag")) + + if _, ok := d.GetOk("resources"); ok { + d.Set("resources", flex.FlattenPolicyResource(accessGroupPolicy.Resources)) + } + if _, ok := d.GetOk("resource_attributes"); ok { + d.Set("resource_attributes", flex.FlattenPolicyResourceAttributes(accessGroupPolicy.Resources)) + } + + if _, ok := d.GetOk("resource_tags"); ok { + d.Set("resource_tags", flex.FlattenPolicyResourceTags(accessGroupPolicy.Resources)) + } + + if len(accessGroupPolicy.Resources) > 0 { + if *flex.GetResourceAttribute("serviceType", accessGroupPolicy.Resources[0]) == "service" { + d.Set("account_management", false) + } + if *flex.GetResourceAttribute("serviceType", accessGroupPolicy.Resources[0]) == "platform_service" { + d.Set("account_management", true) + } + } + + if accessGroupPolicy.Description != nil { + d.Set("description", *accessGroupPolicy.Description) + } + + if len(res.Headers["Transaction-Id"]) > 0 && res.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", res.Headers["Transaction-Id"][0]) + } + + return nil +} + +func resourceIBMIAMAccessGroupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") || d.HasChange("resource_tags") { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + accessGroupId := parts[0] + accessGroupPolicyId := parts[1] + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + var policyOptions iampolicymanagementv1.CreatePolicyOptions + policyOptions, err = flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + accessGroupIdSubject := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{ + { + Name: core.StringPtr("access_group_id"), + Value: &accessGroupId, + }, + }, + } + + accountIdResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: &userDetails.UserAccount, + } + + policyResource := &iampolicymanagementv1.PolicyResource{ + Attributes: append(policyOptions.Resources[0].Attributes, *accountIdResourceAttribute), + Tags: flex.SetTags(d), + } + + updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( + accessGroupPolicyId, + d.Get("version").(string), + "access", + []iampolicymanagementv1.PolicySubject{*accessGroupIdSubject}, + policyOptions.Roles, + []iampolicymanagementv1.PolicyResource{*policyResource}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + updatePolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + updatePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + _, res, err := iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating access group policy: %s\n%s", err, res) + } + } + + return resourceIBMIAMAccessGroupPolicyRead(d, meta) +} + +func resourceIBMIAMAccessGroupPolicyDelete(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + accessGroupPolicyId := parts[1] + + deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( + accessGroupPolicyId, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + deletePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + res, err := iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting access group policy: %s\n%s", err, res) + } + + d.SetId("") + + return nil +} + +func resourceIBMIAMAccessGroupPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of accessGroupID/PolicyID", d.Id()) + } + + accessGroupPolicyId := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + accessGroupPolicyId, + ) + + accessGroupPolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || accessGroupPolicy == nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting access group policy: %s\n%s", err, resp) + } + + if accessGroupPolicy != nil && accessGroupPolicy.State != nil && *accessGroupPolicy.State == "deleted" { + return false, nil + } + + tempID := fmt.Sprintf("%s/%s", *flex.GetSubjectAttribute("access_group_id", accessGroupPolicy.Subjects[0]), *accessGroupPolicy.ID) + + return tempID == d.Id(), nil +} +func importAccessGroupPolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, nil, err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil, nil, err + } + accgrpPolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + accgrpPolicyID, + ) + + accessGroupPolicy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return nil, nil, fmt.Errorf("[ERROR] Error retrieving access group policy: %s\n%s", err, res) + } + + resources := flex.FlattenPolicyResource(accessGroupPolicy.Resources) + resource_attributes := flex.FlattenPolicyResourceAttributes(accessGroupPolicy.Resources) + d.Set("resource_tags", flex.FlattenPolicyResourceTags(accessGroupPolicy.Resources)) + + return resources, resource_attributes, nil +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go new file mode 100644 index 000000000..87cb13932 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go @@ -0,0 +1,830 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMAccessGroupPolicy_Basic(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupPolicyUpdateRole(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Service(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyService(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupPolicyUpdateServiceAndRegion(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_ServiceType(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyServiceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service_type", "service"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_ResourceInstance(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceInstance(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "3"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Resource_Group(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceGroup(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "containers-kubernetes"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Resource_Type(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_import(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_access_group_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyImport(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"resources", "resource_attributes", "transaction_id"}, + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_account_management(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_access_group_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyAccountManagement(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "account_management", "true"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Attributese(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyAttributes(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resources.0.service", "is"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Resource_Attributes(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceAttributes(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceAttributesUpdate(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Service_Specific_Roles(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyServiceSpecificRoles(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_WithCustomRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyWithCustomRole(name, crName, displayName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Resource_Tags(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupPolicyUpdateResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAccessGroupPolicy_With_Transaction_Id(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupPolicyTransactionId(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "transaction_id", "terrformAccessGroupPolicy"), + ), + }, + { + Config: testAccCheckIBMIAMAccessGroupPolicyTransactionIdUpdate(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "transaction_id", "terrformAccessGroupPolicyUpdate"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMAccessGroupPolicyDestroy(s *terraform.State) error { + iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_access_group_policy" { + continue + } + policyID := rs.Primary.ID + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + + accessGroupPolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + accessGroupPolicyID, + ) + + destroyedPolicy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err == nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("Access group policy still exists: %s\n", rs.Primary.ID) + } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("[ERROR] Error waiting for access group policy (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMAccessGroupPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + policyID := rs.Primary.ID + + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + + accessGroupPolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + accessGroupPolicyID, + ) + + policy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving Policy %s err: %s", accessGroupPolicyID, err) + } + obj = *policy + return nil + } +} + +func testAccCheckIBMIAMAccessGroupPolicyBasic(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + tags = ["tag1"] + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyUpdateRole(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer", "Administrator"] + tags = ["tag1", "tag2"] + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyService(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "cloud-object-storage" + } + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyServiceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyUpdateServiceAndRegion(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer", "Manager"] + + resources { + service = "kms" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyResourceInstance(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } + } + + + `, name, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyResourceGroup(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } + } + + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyResourceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Administrator"] + + resources { + resource_type = "resource-group" + resource = data.ibm_resource_group.group.id + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyImport(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyAccountManagement(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Administrator"] + account_management = true + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyAttributes(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "is" + attributes = { + "vpcId" = "*" + } + } + } + + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyWithCustomRole(name, crName, displayName string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_custom_role" "customrole" { + name = "%s" + display_name = "%s" + description = "role for test scenario1" + service = "kms" + actions = ["kms.secrets.rotate"] + } + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] + tags = ["tag1"] + resources { + service = "kms" + } + } + + `, name, crName, displayName) +} +func testAccCheckIBMIAMAccessGroupPolicyResourceAttributes(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} +func testAccCheckIBMIAMAccessGroupPolicyResourceAttributesUpdate(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyServiceSpecificRoles(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Satellite Link Administrator"] + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "satellite" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyTransactionId(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + transaction_id = "terrformAccessGroupPolicy" + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyResourceTags(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resource_tags { + name = "one" + value = "terrformupdate" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyUpdateResourceTags(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resource_tags { + name = "one" + value = "terrformupdate" + } + resource_tags { + name = "two" + value = "terrformupdate" + } + } + `, name) +} + +func testAccCheckIBMIAMAccessGroupPolicyTransactionIdUpdate(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + transaction_id = "terrformAccessGroupPolicyUpdate" + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go new file mode 100644 index 000000000..77bef4bab --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go @@ -0,0 +1,526 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMAuthorizationPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMAuthorizationPolicyCreate, + Read: resourceIBMIAMAuthorizationPolicyRead, + Update: resourceIBMIAMAuthorizationPolicyUpdate, + Delete: resourceIBMIAMAuthorizationPolicyDelete, + Exists: resourceIBMIAMAuthorizationPolicyExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "source_service_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"source_service_name", "subject_attributes"}, + Description: "The source service name", + ForceNew: true, + }, + + "target_service_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"target_service_name", "resource_attributes"}, + ForceNew: true, + Description: "The target service name", + }, + + "roles": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "source_resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"subject_attributes"}, + Description: "The source resource instance Id", + }, + + "target_resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"resource_attributes"}, + Description: "The target resource instance Id", + }, + + "source_resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"subject_attributes"}, + Description: "The source resource group Id", + ValidateFunc: validate.InvokeValidator("ibm_iam_authorization_policy", + "source_resource_group_id"), + }, + + "target_resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"resource_attributes"}, + Description: "The target resource group Id", + ValidateFunc: validate.InvokeValidator("ibm_iam_authorization_policy", + "target_resource_group_id"), + }, + + "source_resource_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"subject_attributes"}, + Description: "Resource type of source service", + }, + + "target_resource_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"resource_attributes"}, + Description: "Resource type of target service", + }, + + "source_service_account": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"subject_attributes"}, + Description: "Account GUID of source service", + }, + + "subject_attributes": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Set subject attributes.", + ConflictsWith: []string{"source_resource_instance_id", "source_resource_group_id", "source_resource_type", "source_service_account"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + }, + }, + }, + + "resource_attributes": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Set resource attributes.", + ConflictsWith: []string{"target_resource_instance_id", "target_resource_group_id", "target_resource_type"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + + "version": { + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the Policy", + }, + + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + }, + } +} + +func ResourceIBMIAMAuthorizationPolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "source_resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "target_resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + + iBMIAMAuthorizationPolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_authorization_policy", Schema: validateSchema} + return &iBMIAMAuthorizationPolicyValidator +} +func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interface{}) error { + + var sourceServiceName, targetServiceName string + policyType := "authorization" + policySubject := &iampolicymanagementv1.PolicySubject{} + policyResource := &iampolicymanagementv1.PolicyResource{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + iampapClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + // check subject_attributes exists + if attributes, ok := d.GetOk("subject_attributes"); ok { + for _, attribute := range attributes.(*schema.Set).List() { + a := attribute.(map[string]interface{}) + name := a["name"].(string) + value := a["value"].(string) + if name == "serviceName" { + sourceServiceName = value + } + at := iampolicymanagementv1.SubjectAttribute{ + Name: &name, + Value: &value, + } + policySubject.Attributes = append(policySubject.Attributes, at) + } + } else { + + sourceServiceName = d.Get("source_service_name").(string) + + serviceNameSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("serviceName"), + Value: &sourceServiceName, + } + policySubject.Attributes = append(policySubject.Attributes, *serviceNameSubjectAttribute) + + sourceServiceAccount := userDetails.UserAccount + if account, ok := d.GetOk("source_service_account"); ok { + sourceServiceAccount = account.(string) + } + + accountIdSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("accountId"), + Value: &sourceServiceAccount, + } + + policySubject.Attributes = append(policySubject.Attributes, *accountIdSubjectAttribute) + + if sID, ok := d.GetOk("source_resource_instance_id"); ok { + serviceInstanceSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("serviceInstance"), + Value: core.StringPtr(sID.(string)), + } + policySubject.Attributes = append(policySubject.Attributes, serviceInstanceSubjectAttribute) + } + + if sType, ok := d.GetOk("source_resource_type"); ok { + resourceTypeSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("resourceType"), + Value: core.StringPtr(sType.(string)), + } + policySubject.Attributes = append(policySubject.Attributes, resourceTypeSubjectAttribute) + } + + if sResGrpID, ok := d.GetOk("source_resource_group_id"); ok { + resourceGroupSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("resourceGroupId"), + Value: core.StringPtr(sResGrpID.(string)), + } + policySubject.Attributes = append(policySubject.Attributes, resourceGroupSubjectAttribute) + } + } + + // check resource_attributes exists + if attributes, ok := d.GetOk("resource_attributes"); ok { + for _, attribute := range attributes.(*schema.Set).List() { + a := attribute.(map[string]interface{}) + name := a["name"].(string) + value := a["value"].(string) + operator := a["operator"].(string) + if name == "serviceName" { + targetServiceName = value + } + at := iampolicymanagementv1.ResourceAttribute{ + Name: &name, + Value: &value, + Operator: &operator, + } + policyResource.Attributes = append(policyResource.Attributes, at) + } + } else { + targetServiceName = d.Get("target_service_name").(string) + serviceNameResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceName"), + Value: core.StringPtr(targetServiceName), + Operator: core.StringPtr("stringEquals"), + } + policyResource.Attributes = append(policyResource.Attributes, *serviceNameResourceAttribute) + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(userDetails.UserAccount), + Operator: core.StringPtr("stringEquals"), + } + + policyResource.Attributes = append(policyResource.Attributes, *accountIDResourceAttribute) + + if tID, ok := d.GetOk("target_resource_instance_id"); ok { + serviceInstanceResourceAttribute := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("serviceInstance"), + Value: core.StringPtr(tID.(string)), + } + policyResource.Attributes = append(policyResource.Attributes, serviceInstanceResourceAttribute) + } + + if tType, ok := d.GetOk("target_resource_type"); ok { + resourceTypeResourceAttribute := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("resourceType"), + Value: core.StringPtr(tType.(string)), + } + policyResource.Attributes = append(policyResource.Attributes, resourceTypeResourceAttribute) + } + + if tResGrpID, ok := d.GetOk("target_resource_group_id"); ok { + resourceGroupResourceAttribute := iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("resourceGroupId"), + Value: core.StringPtr(tResGrpID.(string)), + } + policyResource.Attributes = append(policyResource.Attributes, resourceGroupResourceAttribute) + } + } + + listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ + ServiceName: &targetServiceName, + SourceServiceName: &sourceServiceName, + PolicyType: &policyType, + } + roleList, resp, err := iampapClient.ListRoles(listRoleOptions) + + if err != nil || roleList == nil { + return fmt.Errorf("[ERROR] Error in listing roles %s, %s", err, resp) + } + + policyRoles := flex.MapRoleListToPolicyRoles(*roleList) + roles, err := flex.GetRolesFromRoleNames(flex.ExpandStringList(d.Get("roles").([]interface{})), policyRoles) + + if err != nil { + return err + } + + createPolicyOptions := iampapClient.NewCreatePolicyOptions( + "authorization", + []iampolicymanagementv1.PolicySubject{*policySubject}, + roles, + []iampolicymanagementv1.PolicyResource{*policyResource}, + ) + + if description, ok := d.GetOk("description"); ok { + des := description.(string) + createPolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + authPolicy, resp, err := iampapClient.CreatePolicy(createPolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error creating authorization policy: %s %s", err, resp) + } + + d.SetId(*authPolicy.ID) + + return resourceIBMIAMAuthorizationPolicyRead(d, meta) +} + +func resourceIBMIAMAuthorizationPolicyRead(d *schema.ResourceData, meta interface{}) error { + + iampapClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: core.StringPtr(d.Id()), + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + authorizationPolicy, resp, err := iampapClient.GetPolicy(getPolicyOptions) + if err != nil || resp == nil { + return fmt.Errorf("[ERROR] Error retrieving authorizationPolicy: %s %s", err, resp) + } + roles := make([]string, len(authorizationPolicy.Roles)) + for i, role := range authorizationPolicy.Roles { + roles[i] = *role.DisplayName + } + if authorizationPolicy.Description != nil { + d.Set("description", *authorizationPolicy.Description) + } + if len(resp.Headers["Transaction-Id"]) > 0 && resp.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) + } + d.Set("roles", roles) + source := authorizationPolicy.Subjects[0] + target := authorizationPolicy.Resources[0] + + d.Set("resource_attributes", setAuthorizationResourceAttributes(target)) + d.Set("target_resource_instance_id", flex.GetResourceAttribute("serviceInstance", target)) + d.Set("target_resource_type", flex.GetResourceAttribute("resourceType", target)) + d.Set("target_resource_group_id", flex.GetResourceAttribute("resourceGroupId", target)) + d.Set("target_service_name", flex.GetResourceAttribute("serviceName", target)) + + d.Set("subject_attributes", setAuthorizationSubjectAttributes(source)) + d.Set("source_service_name", flex.GetSubjectAttribute("serviceName", source)) + d.Set("source_resource_instance_id", flex.GetSubjectAttribute("serviceInstance", source)) + d.Set("source_resource_type", flex.GetSubjectAttribute("resourceType", source)) + d.Set("source_service_account", flex.GetSubjectAttribute("accountId", source)) + d.Set("source_resource_group_id", flex.GetSubjectAttribute("resourceGroupId", source)) + + return nil +} + +// Returns nil, because ibmcloud iam cli authorization policy does not have an update command +func resourceIBMIAMAuthorizationPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceIBMIAMAuthorizationPolicyDelete(d *schema.ResourceData, meta interface{}) error { + iampapClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + authorizationPolicyID := d.Id() + + deletePolicyOptions := &iampolicymanagementv1.DeletePolicyOptions{ + PolicyID: core.StringPtr(authorizationPolicyID), + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + deletePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + resp, err := iampapClient.DeletePolicy(deletePolicyOptions) + if err != nil { + log.Printf( + "Error deleting authorization policy: %s, %s", err, resp) + } + + d.SetId("") + + return nil +} + +func resourceIBMIAMAuthorizationPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iampapClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: core.StringPtr(d.Id()), + } + authorizationPolicy, resp, err := iampapClient.GetPolicy(getPolicyOptions) + if err != nil || authorizationPolicy == nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting authorisation policy: %s\n%s", err, resp) + } + + if authorizationPolicy != nil && authorizationPolicy.State != nil && *authorizationPolicy.State == "deleted" { + return false, nil + } + + return *authorizationPolicy.ID == d.Id(), nil +} + +func setAuthorizationResourceAttributes(list iampolicymanagementv1.PolicyResource) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + for _, attribute := range list.Attributes { + l := map[string]interface{}{ + "name": attribute.Name, + "value": attribute.Value, + "operator": attribute.Operator, + } + result = append(result, l) + } + return result +} + +func setAuthorizationSubjectAttributes(list iampolicymanagementv1.PolicySubject) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + for _, attribute := range list.Attributes { + l := map[string]interface{}{ + "name": attribute.Name, + "value": attribute.Value, + } + result = append(result, l) + } + return result +} diff --git a/ibm/resource_ibm_iam_authorization_policy_detach.go b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_detach.go similarity index 83% rename from ibm/resource_ibm_iam_authorization_policy_detach.go rename to ibm/service/iampolicy/resource_ibm_iam_authorization_policy_detach.go index 77d39166a..b42ec4f15 100644 --- a/ibm/resource_ibm_iam_authorization_policy_detach.go +++ b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_detach.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMIAMAuthorizationPolicyDetach() *schema.Resource { +func ResourceIBMIAMAuthorizationPolicyDetach() *schema.Resource { return &schema.Resource{ Create: resourceIBMIAMAuthorizationPolicyDetachCreate, Read: resourceIBMIAMAuthorizationPolicyDetachRead, @@ -29,7 +30,7 @@ func resourceIBMIAMAuthorizationPolicyDetach() *schema.Resource { } func resourceIBMIAMAuthorizationPolicyDetachCreate(d *schema.ResourceData, meta interface{}) error { - iampapClient, err := meta.(ClientSession).IAMPolicyManagementV1API() + iampapClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return err } @@ -40,7 +41,7 @@ func resourceIBMIAMAuthorizationPolicyDetachCreate(d *schema.ResourceData, meta ) _, err = iampapClient.DeletePolicy(deletePolicyOptions) if err != nil { - return fmt.Errorf("Error detaching authorization policy: %s", err) + return fmt.Errorf("[ERROR] Error detaching authorization policy: %s", err) } d.SetId(time.Now().UTC().String()) diff --git a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go new file mode 100644 index 000000000..9887afdb7 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go @@ -0,0 +1,370 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" +) + +func TestAccIBMIAMAuthorizationPolicy_Basic(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "description", "Authorization Policy for test scenario"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAuthorizationPolicy_Resource_Instance(t *testing.T) { + var conf iampolicymanagementv1.Policy + instanceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_authorization_policy.policy" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyResourceInstance(instanceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"transaction_id"}, + }, + }, + }) +} + +// TODO: Invalid authorizatoin header +func TestAccIBMIAMAuthorizationPolicy_Resource_Group(t *testing.T) { + var conf iampolicymanagementv1.Policy + sResourceGroup := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + tResourceGroup := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_authorization_policy.policy" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyResourceGroup(sResourceGroup, tResourceGroup), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIBMIAMAuthorizationPolicy_ResourceType(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyResourceType(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "is"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_resource_type", "load-balancer"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "cloudcerts"), + ), + }, + }, + }) +} +func TestAccIBMIAMAuthorizationPolicyDelegatorRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyDelegatorRole(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "databases-for-redis"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAuthorizationPolicy_ResourceAttributes(t *testing.T) { + var conf iampolicymanagementv1.Policy + sServiceInstance := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + tServiceInstance := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyResourceAttributes(sServiceInstance, tServiceInstance, acc.Tg_cross_network_account_id, acc.Tg_cross_network_account_id), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttrSet("ibm_iam_authorization_policy.policy", "id"), + ), + }, + }, + }) +} + +func TestAccIBMIAMAuthorizationPolicy_With_Transaction_id(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicyTransactionId(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "databases-for-redis"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "kms"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "transaction_id", "terrformAuthorizationPolicy"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMAuthorizationPolicyDestroy(s *terraform.State) error { + iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_authorization_policy" { + continue + } + + authPolicyID := rs.Primary.ID + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + authPolicyID, + ) + destroyedPolicy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err == nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("Authorization policy still exists: %s\n", rs.Primary.ID) + } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("[ERROR] Error waiting for authorization policy (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMAuthorizationPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + authPolicyID := rs.Primary.ID + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + authPolicyID, + ) + + policy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Policy %s, %s", err, resp) + } + obj = *policy + return nil + } +} + +func testAccCheckIBMIAMAuthorizationPolicyBasic() string { + return ` + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "cloud-object-storage" + target_service_name = "kms" + roles = ["Reader"] + description = "Authorization Policy for test scenario" + } + ` +} + +func testAccCheckIBMIAMAuthorizationPolicyResourceInstance(instanceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance1" { + name = "%s" + service = "cloud-object-storage" + plan = "lite" + location = "global" + } + + resource "ibm_resource_instance" "instance2" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "cloud-object-storage" + source_resource_instance_id = ibm_resource_instance.instance1.id + target_service_name = "kms" + target_resource_instance_id = ibm_resource_instance.instance2.id + roles = ["Reader"] + } + + `, instanceName, instanceName) +} + +func testAccCheckIBMIAMAuthorizationPolicyResourceType() string { + return ` + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "is" + source_resource_type = "load-balancer" + target_service_name = "cloudcerts" + roles = ["Reader"] + } + ` +} +func testAccCheckIBMIAMAuthorizationPolicyDelegatorRole() string { + return ` + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "databases-for-redis" + target_service_name = "kms" + roles = ["Reader", "Authorization Delegator"] + } + ` +} + +func testAccCheckIBMIAMAuthorizationPolicyResourceGroup(sResourceGroup, tResourceGroup string) string { + return fmt.Sprintf(` + + resource "ibm_resource_group" "source_resource_group" { + name = "%s" + } + + resource "ibm_resource_group" "target_resource_group" { + name = "%s" + } + + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "cloud-object-storage" + source_resource_group_id = ibm_resource_group.source_resource_group.id + target_service_name = "kms" + target_resource_group_id = ibm_resource_group.target_resource_group.id + roles = ["Reader"] + } + + `, sResourceGroup, tResourceGroup) +} + +func testAccCheckIBMIAMAuthorizationPolicyResourceAttributes(sServiceInstance, tServiceInstance, sAccountID, tAccountID string) string { + + return fmt.Sprintf(` + + resource "ibm_resource_instance" "cos" { + name = "%s" + service = "cloud-object-storage" + plan = "lite" + location = "global" + } + + resource "ibm_resource_instance" "kms" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "ibm_iam_authorization_policy" "policy" { + roles = ["Reader"] + subject_attributes { + name = "accountId" + value = "%s" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos.id + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceName" + value = "kms" + } + resource_attributes { + name = "accountId" + value = "%s" + } + resource_attributes { + name = "serviceInstance" + value = ibm_resource_instance.kms.id + } + } + `, sServiceInstance, tServiceInstance, sAccountID, tAccountID) +} + +func testAccCheckIBMIAMAuthorizationPolicyTransactionId() string { + return ` + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "databases-for-redis" + target_service_name = "kms" + roles = ["Reader", "Authorization Delegator"] + transaction_id = "terrformAuthorizationPolicy" + } + ` +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_custom_role.go b/ibm/service/iampolicy/resource_ibm_iam_custom_role.go new file mode 100644 index 000000000..116f2ef29 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_custom_role.go @@ -0,0 +1,286 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + iamCRDisplayName = "display_name" + iamCRName = "name" + iamCRDescription = "description" + iamCRActions = "actions" + iamCRServiceName = "service" +) + +func ResourceIBMIAMCustomRole() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMCustomRoleCreate, + Read: resourceIBMIAMCustomRoleRead, + Update: resourceIBMIAMCustomRoleUpdate, + Delete: resourceIBMIAMCustomRoleDelete, + Exists: resourceIBMIAMCustomRoleExists, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + iamCRDisplayName: { + Type: schema.TypeString, + Required: true, + Description: "Display Name of the Custom Role", + ValidateFunc: validate.InvokeValidator("ibm_iam_custom_role", iamCRDisplayName), + }, + + iamCRName: { + Type: schema.TypeString, + Required: true, + Description: "The name of the custom Role", + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_iam_custom_role", iamCRName), + }, + iamCRDescription: { + Type: schema.TypeString, + Optional: true, + Description: "The description of the role", + ValidateFunc: validate.InvokeValidator("ibm_iam_custom_role", iamCRDescription), + }, + iamCRServiceName: { + Type: schema.TypeString, + Required: true, + Description: "The Service Name", + ForceNew: true, + }, + iamCRActions: { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The actions of the role", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "crn of the Custom Role", + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} + +func ResourceIBMIAMCustomRoleValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: iamCRName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Z]{1}[A-Za-z0-9]{0,29}$`, + MinValueLength: 1, + MaxValueLength: 30}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: iamCRDisplayName, + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + Optional: true, + MinValueLength: 1, + MaxValueLength: 50}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: iamCRDescription, + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + Optional: true, + MinValueLength: 1, + MaxValueLength: 250}) + + ibmIAMCustomRoleResourceValidator := validate.ResourceValidator{ResourceName: "ibm_iam_custom_role", Schema: validateSchema} + return &ibmIAMCustomRoleResourceValidator +} + +func resourceIBMIAMCustomRoleCreate(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + displayName := d.Get(iamCRDisplayName).(string) + name := d.Get(iamCRName).(string) + description := d.Get(iamCRDescription).(string) + serviceName := d.Get(iamCRServiceName).(string) + actionList := flex.ExpandStringList(d.Get(iamCRActions).([]interface{})) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + roleOptions := &iampolicymanagementv1.CreateRoleOptions{ + DisplayName: &displayName, + Actions: actionList, + Name: &name, + AccountID: &userDetails.UserAccount, + ServiceName: &serviceName, + Description: &description, + } + + role, response, err := iamPolicyManagementClient.CreateRole(roleOptions) + if err != nil || role == nil { + return fmt.Errorf("[ERROR] Error creating Custom Roles: %s\n%s", err, response) + } + + d.SetId(*role.ID) + + return resourceIBMIAMCustomRoleRead(d, meta) +} + +func resourceIBMIAMCustomRoleRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + roleID := d.Id() + roleOptions := &iampolicymanagementv1.GetRoleOptions{ + RoleID: &roleID, + } + + role, response, err := iamPolicyManagementClient.GetRole(roleOptions) + if err != nil || role == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error retrieving Custom Roles: %s\n%s", err, response) + } + + d.Set(iamCRDisplayName, role.DisplayName) + d.Set(iamCRName, role.Name) + d.Set(iamCRDescription, role.Description) + d.Set(iamCRServiceName, role.ServiceName) + d.Set(iamCRActions, role.Actions) + d.Set("crn", role.CRN) + + d.Set(flex.ResourceName, role.Name) + d.Set(flex.ResourceCRN, role.CRN) + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + + d.Set(flex.ResourceControllerURL, rcontroller+"/iam/roles") + + return nil +} + +func resourceIBMIAMCustomRoleUpdate(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + roleID := d.Id() + + updatedDescription := d.Get(iamCRDescription).(string) + updatedActions := flex.ExpandStringList(d.Get(iamCRActions).([]interface{})) + updatedDisplayName := d.Get(iamCRDisplayName).(string) + + if d.HasChange("display_name") || d.HasChange("description") || d.HasChange("actions") { + roleGetOptions := &iampolicymanagementv1.GetRoleOptions{ + RoleID: &roleID, + } + + role, response, err := iamPolicyManagementClient.GetRole(roleGetOptions) + if err != nil || role == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error retrieving Custom Roles: %s\n%s", err, response) + } + + roleETag := response.Headers.Get("ETag") + roleUpdateOptions := &iampolicymanagementv1.UpdateRoleOptions{ + RoleID: &roleID, + IfMatch: &roleETag, + DisplayName: &updatedDisplayName, + Description: &updatedDescription, + Actions: updatedActions, + } + + _, response, err = iamPolicyManagementClient.UpdateRole(roleUpdateOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating Custom Roles: %s\n%s", err, response) + } + } + + return resourceIBMIAMCustomRoleRead(d, meta) +} + +func resourceIBMIAMCustomRoleDelete(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + roleID := d.Id() + roleDeleteOptions := &iampolicymanagementv1.DeleteRoleOptions{ + RoleID: &roleID, + } + + response, err := iamPolicyManagementClient.DeleteRole(roleDeleteOptions) + if err != nil && !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error deleting Custom Roles: %s\n%s", err, response) + } + + d.SetId("") + + return nil +} + +func resourceIBMIAMCustomRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + roleID := d.Id() + + roleGetOptions := &iampolicymanagementv1.GetRoleOptions{ + RoleID: &roleID, + } + + role, response, err := iamPolicyManagementClient.GetRole(roleGetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error retrieving Custom Roles: %s\n%s", err, response) + } + + return *role.ID == roleID, nil +} diff --git a/ibm/resource_ibm_iam_custom_role_test.go b/ibm/service/iampolicy/resource_ibm_iam_custom_role_test.go similarity index 77% rename from ibm/resource_ibm_iam_custom_role_test.go rename to ibm/service/iampolicy/resource_ibm_iam_custom_role_test.go index 4ae2879ca..f248f295e 100644 --- a/ibm/resource_ibm_iam_custom_role_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_custom_role_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -21,11 +25,11 @@ func TestAccIBMIAMCustomRole_Basic(t *testing.T) { updateDisplayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMCustomRoleDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMCustomRoleBasic(name, displayName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMCustomRoleExists("ibm_iam_custom_role.customrole", conf), @@ -33,7 +37,7 @@ func TestAccIBMIAMCustomRole_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_custom_role.customrole", "display_name", displayName), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMCustomRoleUpdateWithSameName(name, displayName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMCustomRoleExists("ibm_iam_custom_role.customrole", conf), @@ -42,7 +46,7 @@ func TestAccIBMIAMCustomRole_Basic(t *testing.T) { resource.TestCheckResourceAttr("ibm_iam_custom_role.customrole", "display_name", displayName), ), }, - resource.TestStep{ + { Config: testAccCheckIBMIAMCustomRoleUpdate(name, updateDisplayName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_iam_custom_role.customrole", "display_name", updateDisplayName), @@ -52,7 +56,33 @@ func TestAccIBMIAMCustomRole_Basic(t *testing.T) { }, }) } +func testAccCheckIBMIAMAccessGroupDestroy(s *terraform.State) error { + accClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMAccessGroupsV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_access_group" { + continue + } + + agID := rs.Primary.ID + // Try to find the key + getAccessGroupOptions := &iamaccessgroupsv2.GetAccessGroupOptions{ + AccessGroupID: &agID, + } + _, detailResponse, _ := accClient.GetAccessGroup(getAccessGroupOptions) + + if err == nil { + return fmt.Errorf("Access group still exists: %s", rs.Primary.ID) + } else if detailResponse.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error waiting for access group (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} func TestAccIBMIAMCustomRole_import(t *testing.T) { var conf iampolicymanagementv1.CustomRole name := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) @@ -60,11 +90,11 @@ func TestAccIBMIAMCustomRole_import(t *testing.T) { resourceName := "ibm_iam_custom_role.customrole" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMIAMAccessGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMIAMCustomRoleMultipleAction(name, displayName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMIAMCustomRoleExists(resourceName, conf), @@ -72,7 +102,7 @@ func TestAccIBMIAMCustomRole_import(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Custom Role for test scenario2"), ), }, - resource.TestStep{ + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -82,7 +112,7 @@ func TestAccIBMIAMCustomRole_import(t *testing.T) { } func testAccCheckIBMIAMCustomRoleDestroy(s *terraform.State) error { - roleClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() + roleClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return err } @@ -102,7 +132,7 @@ func testAccCheckIBMIAMCustomRoleDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Custom Role still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error waiting for Custom Role (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for Custom Role (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -117,7 +147,7 @@ func testAccCheckIBMIAMCustomRoleExists(n string, obj iampolicymanagementv1.Cust return fmt.Errorf("Not found: %s", n) } - roleClient, err := testAccProvider.Meta().(ClientSession).IAMPolicyManagementV1API() + roleClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return err } @@ -128,7 +158,7 @@ func testAccCheckIBMIAMCustomRoleExists(n string, obj iampolicymanagementv1.Cust customrole, _, err := roleClient.GetRole(getRoleOptions) if err != nil { - return fmt.Errorf("Error retrieving Custom Role %s err: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error retrieving Custom Role %s err: %s", rs.Primary.ID, err) } obj = *customrole diff --git a/ibm/service/iampolicy/resource_ibm_iam_service_policy.go b/ibm/service/iampolicy/resource_ibm_iam_service_policy.go new file mode 100644 index 000000000..bb87223ac --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_service_policy.go @@ -0,0 +1,632 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMServicePolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMServicePolicyCreate, + Read: resourceIBMIAMServicePolicyRead, + Update: resourceIBMIAMServicePolicyUpdate, + Delete: resourceIBMIAMServicePolicyDelete, + Exists: resourceIBMIAMServicePolicyExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + resources, resourceAttributes, err := importServicePolicy(d, meta) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) + } + d.Set("resources", resources) + d.Set("resource_attributes", resourceAttributes) + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "iam_service_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "UUID of ServiceID", + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_iam_service_policy", + "iam_service_id"), + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "IAM ID of ServiceID", + ForceNew: true, + }, + "roles": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "resources": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"account_management", "resource_attributes"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "Service name of the policy definition", + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of resource instance of the policy definition", + }, + + "region": { + Type: schema.TypeString, + Optional: true, + Description: "Region of the policy definition", + }, + + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type of the policy definition", + }, + + "resource": { + Type: schema.TypeString, + Optional: true, + Description: "Resource of the policy definition", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + + "service_type": { + Type: schema.TypeString, + Optional: true, + Description: "Service type of the policy definition", + }, + + "attributes": { + Type: schema.TypeMap, + Optional: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + + "resource_attributes": { + Type: schema.TypeSet, + Optional: true, + Description: "Set resource attributes.", + ConflictsWith: []string{"resources", "account_management"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + "account_management": { + Type: schema.TypeBool, + Default: false, + Optional: true, + Description: "Give access to all account management services", + ConflictsWith: []string{"resources", "resource_attributes"}, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "resource_tags": { + Type: schema.TypeSet, + Optional: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the Policy", + }, + + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + }, + } +} + +func ResourceIBMIAMServicePolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "iam_service_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:service_id", "resolved_to:id"}, + Optional: true}) + + iBMIAMServicePolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_service_policy", Schema: validateSchema} + return &iBMIAMServicePolicyValidator +} + +func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) error { + + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ + ID: &serviceIDUUID, + } + serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) + } + iamID = *serviceID.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + policyOptions, err := flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &iamID, + } + + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(userDetails.UserAccount), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + policyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + createPolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + servicePolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error creating servicePolicy: %s %s", err, res) + } + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + *servicePolicy.ID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || policy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil { + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID)) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", iamID, *servicePolicy.ID)) + } + return fmt.Errorf("[ERROR] Error fetching service policy: %s %s", err, res) + } + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID)) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", iamID, *servicePolicy.ID)) + } + + return resourceIBMIAMServicePolicyRead(d, meta) +} + +func resourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + serviceIDUUID := parts[0] + servicePolicyID := parts[1] + servicePolicy := &iampolicymanagementv1.Policy{} + res := &core.DetailedResponse{} + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + servicePolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + servicePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || servicePolicy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + servicePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil || servicePolicy == nil || res == nil { + return fmt.Errorf("[ERROR] Error retrieving servicePolicy: %s %s", err, res) + } + if strings.HasPrefix(serviceIDUUID, "iam-") { + d.Set("iam_id", serviceIDUUID) + } else { + d.Set("iam_service_id", serviceIDUUID) + } + + roles := make([]string, len(servicePolicy.Roles)) + for i, role := range servicePolicy.Roles { + roles[i] = *role.DisplayName + } + d.Set("roles", roles) + + if _, ok := d.GetOk("resources"); ok { + d.Set("resources", flex.FlattenPolicyResource(servicePolicy.Resources)) + } + if _, ok := d.GetOk("resource_attributes"); ok { + d.Set("resource_attributes", flex.FlattenPolicyResourceAttributes(servicePolicy.Resources)) + } + + if _, ok := d.GetOk("resource_tags"); ok { + d.Set("resource_tags", flex.FlattenPolicyResourceTags(servicePolicy.Resources)) + } + + if len(servicePolicy.Resources) > 0 { + if *flex.GetResourceAttribute("serviceType", servicePolicy.Resources[0]) == "service" { + d.Set("account_management", false) + } + if *flex.GetResourceAttribute("serviceType", servicePolicy.Resources[0]) == "platform_service" { + d.Set("account_management", true) + } + } + if servicePolicy.Description != nil { + d.Set("description", *servicePolicy.Description) + } + + if len(res.Headers["Transaction-Id"]) > 0 && res.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", res.Headers["Transaction-Id"][0]) + } + + return nil +} + +func resourceIBMIAMServicePolicyUpdate(d *schema.ResourceData, meta interface{}) error { + + if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") || d.HasChange("resource_tags") { + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + servicePolicyID := parts[1] + + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getServiceIDOptions := iamidentityv1.GetServiceIDOptions{ + ID: &serviceIDUUID, + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getServiceIDOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + serviceID, resp, err := iamClient.GetServiceID(&getServiceIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error] Error Getting Service Id %s %s", err, resp) + } + iamID = *serviceID.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + createPolicyOptions, err := flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(userDetails.UserAccount), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &iamID, + } + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + servicePolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || policy == nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error retrieving Policy: %s\n%s", err, response) + } + + servicePolicyETag := response.Headers.Get("ETag") + updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( + servicePolicyID, + servicePolicyETag, + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + createPolicyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + updatePolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + updatePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + _, _, err = iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating service policy: %s", err) + } + + } + + return resourceIBMIAMServicePolicyRead(d, meta) + +} + +func resourceIBMIAMServicePolicyDelete(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + servicePolicyID := parts[1] + + deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( + servicePolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + deletePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + _, err = iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting service policy: %s", err) + } + + d.SetId("") + + return nil +} + +func resourceIBMIAMServicePolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of serviceID(OR)iamID/PolicyID", d.Id()) + } + serviceIDUUID := parts[0] + servicePolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + servicePolicyID, + ) + + servicePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || servicePolicy == nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting service policy: %s\n%s", err, resp) + } + + if servicePolicy != nil && servicePolicy.State != nil && *servicePolicy.State == "deleted" { + return false, nil + } + + tempID := fmt.Sprintf("%s/%s", serviceIDUUID, *servicePolicy.ID) + + return tempID == d.Id(), nil +} + +func importServicePolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, nil, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil, nil, err + } + servicePolicyID := parts[1] + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + servicePolicyID, + ) + servicePolicy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return nil, nil, fmt.Errorf("[ERROR] Error retrieving servicePolicy: %s", err) + } + resources := flex.FlattenPolicyResource(servicePolicy.Resources) + resource_attributes := flex.FlattenPolicyResourceAttributes(servicePolicy.Resources) + d.Set("resource_tags", flex.FlattenPolicyResourceTags(servicePolicy.Resources)) + return resources, resource_attributes, nil +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go new file mode 100644 index 000000000..8a6b64c94 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go @@ -0,0 +1,752 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMServicePolicy_Basic(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Creation for test scenario"), + ), + }, + { + Config: testAccCheckIBMIAMServicePolicyUpdateRole(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Update for test scenario"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Service(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyService(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMServicePolicyUpdateServiceAndRegion(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.region", "us-south"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_ServiceType(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyServiceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service_type", "service"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_ResourceInstance(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceInstance(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "3"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Resource_Group(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceGroup(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resources.0.service", "containers-kubernetes"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Resource_Type(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_import(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_service_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyImport(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"resources", "resource_attributes", "transaction_id"}, + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_account_management(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_service_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyAccountManagement(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "account_management", "true"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicyWithCustomRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyWithCustomRole(name, crName, displayName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Resource_Attributes(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceAttributes(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMServicePolicyResourceAttributesUpdate(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Resource_Tags(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Creation for test scenario"), + ), + }, + { + Config: testAccCheckIBMIAMServicePolicyUpdateResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "description", "IAM Service Policy Update for test scenario"), + ), + }, + }, + }) +} + +func TestAccIBMIAMServicePolicy_With_Transaction_Id(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceTransactionId(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "transaction_id", "terrformServicePolicy")), + }, + { + Config: testAccCheckIBMIAMServicePolicyResourceTransactionIdUpdate(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "transaction_id", "terrformServicePolicyUpdate"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMServicePolicyDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_service_policy" { + continue + } + policyID := rs.Primary.ID + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + servicePolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + servicePolicyID, + ) + + // Try to find the key + destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) + + if err == nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) + } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("[ERROR] Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMServicePolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + policyID := rs.Primary.ID + + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + servicePolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + servicePolicyID, + ) + + // Try to find the key + policy, _, err := rsContClient.GetPolicy(getPolicyOptions) + if err != nil { + return err + } + obj = *policy + return nil + } +} + +func testAccCheckIBMIAMServicePolicyBasic(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + tags = ["tag1"] + description = "IAM Service Policy Creation for test scenario" + } + + `, name) +} + +func testAccCheckIBMIAMServicePolicyUpdateRole(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer", "Manager"] + tags = ["tag1", "tag2"] + description = "IAM Service Policy Update for test scenario" + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyService(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resources { + service = "cloudantnosqldb" + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyServiceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyUpdateServiceAndRegion(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer", "Manager"] + + resources { + service = "cloudantnosqldb" + region = "us-south" + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyResourceInstance(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } + } + + + `, name, name) +} + +func testAccCheckIBMIAMServicePolicyResourceGroup(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } + } + + + `, name) +} + +func testAccCheckIBMIAMServicePolicyResourceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Administrator"] + + resources { + resource_type = "resource-group" + resource = data.ibm_resource_group.group.id + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyImport(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + } + + `, name) +} + +func testAccCheckIBMIAMServicePolicyAccountManagement(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + account_management = true + } + + `, name) +} + +func testAccCheckIBMIAMServicePolicyWithCustomRole(name, crName, displayName string) string { + return fmt.Sprintf(` + + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + resource "ibm_iam_custom_role" "customrole" { + name = "%s" + display_name = "%s" + description = "role for test scenario1" + service = "kms" + actions = ["kms.secrets.rotate"] + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] + tags = ["tag1"] + resources { + service = "kms" + } + } + + `, name, crName, displayName) +} + +func testAccCheckIBMIAMServicePolicyResourceAttributes(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} +func testAccCheckIBMIAMServicePolicyResourceAttributesUpdate(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyResourceTags(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resource_tags { + name = "one" + value = "Terraform" + } + description = "IAM Service Policy Creation for test scenario" + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyUpdateResourceTags(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + + resource_tags { + name = "one" + value = "Terraform" + } + resource_tags { + name = "two" + value = "TerraformUpdate" + } + description = "IAM Service Policy Update for test scenario" + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyResourceTransactionId(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + transaction_id = "terrformServicePolicy" + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + +func testAccCheckIBMIAMServicePolicyResourceTransactionIdUpdate(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + transaction_id = "terrformServicePolicyUpdate" + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy.go b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy.go new file mode 100644 index 000000000..76c67c889 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy.go @@ -0,0 +1,626 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMTrustedProfilePolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMTrustedProfilePolicyCreate, + Read: resourceIBMIAMTrustedProfilePolicyRead, + Update: resourceIBMIAMTrustedProfilePolicyUpdate, + Delete: resourceIBMIAMTrustedProfilePolicyDelete, + Exists: resourceIBMIAMTrustedProfilePolicyExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + resources, resourceAttributes, err := importTrustedProfilePolicy(d, meta) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) + } + d.Set("resources", resources) + d.Set("resource_attributes", resourceAttributes) + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"profile_id", "iam_id"}, + Description: "UUID of Trusted Profile", + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_iam_trusted_profile_policy", + "profile_id"), + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"profile_id", "iam_id"}, + Description: "IAM ID of Trusted Profile", + ForceNew: true, + }, + "roles": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "resources": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"account_management", "resource_attributes"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "Service name of the policy definition", + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of resource instance of the policy definition", + }, + + "region": { + Type: schema.TypeString, + Optional: true, + Description: "Region of the policy definition", + }, + + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type of the policy definition", + }, + + "resource": { + Type: schema.TypeString, + Optional: true, + Description: "Resource of the policy definition", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + + "service_type": { + Type: schema.TypeString, + Optional: true, + Description: "Service type of the policy definition", + }, + + "attributes": { + Type: schema.TypeMap, + Optional: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + + "resource_attributes": { + Type: schema.TypeSet, + Optional: true, + Description: "Set resource attributes.", + ConflictsWith: []string{"resources", "account_management"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + "account_management": { + Type: schema.TypeBool, + Default: false, + Optional: true, + Description: "Give access to all account management services", + ConflictsWith: []string{"resources", "resource_attributes"}, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "resource_tags": { + Type: schema.TypeSet, + Optional: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the Policy", + }, + + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + }, + } +} + +func ResourceIBMIAMTrustedProfilePolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "iam", + CloudDataRange: []string{"service:trusted_profile", "resolved_to:id"}, + Required: true}) + + iBMIAMTrustedProfilePolicyValidator := validate.ResourceValidator{ResourceName: "ibm_iam_trusted_profile_policy", Schema: validateSchema} + return &iBMIAMTrustedProfilePolicyValidator +} + +func resourceIBMIAMTrustedProfilePolicyCreate(d *schema.ResourceData, meta interface{}) error { + + var iamID string + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileIDUUID := v.(string) + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getProfileOptions := &iamidentityv1.GetProfileOptions{ + ProfileID: &profileIDUUID, + } + profileID, resp, err := iamClient.GetProfile(getProfileOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error] Error getting trusted profile ID %s %s", err, resp) + } + iamID = *profileID.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + policyOptions, err := flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &iamID, + } + + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(userDetails.UserAccount), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + policyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + createPolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + trustedProfilePolicy, res, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error creating trustedProfilePolicy: %s %s", err, res) + } + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + *trustedProfilePolicy.ID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || policy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + _, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil { + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileIDUUID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID)) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", iamID, *trustedProfilePolicy.ID)) + } + return fmt.Errorf("[ERROR] Error fetching trusted profile policy: %s %s", err, res) + } + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileIDUUID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID)) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", iamID, *trustedProfilePolicy.ID)) + } + + return resourceIBMIAMTrustedProfilePolicyRead(d, meta) +} + +func resourceIBMIAMTrustedProfilePolicyRead(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + profileIDUUID := parts[0] + trustedProfilePolicyID := parts[1] + trustedProfilePolicy := &iampolicymanagementv1.Policy{} + res := &core.DetailedResponse{} + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + trustedProfilePolicyID, + ) + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + trustedProfilePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || trustedProfilePolicy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + trustedProfilePolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil || trustedProfilePolicy == nil || res == nil { + return fmt.Errorf("[ERROR] Error retrieving trusted profile policy: %s %s", err, res) + } + if strings.HasPrefix(profileIDUUID, "iam-") { + d.Set("iam_id", profileIDUUID) + } else { + d.Set("profile_id", profileIDUUID) + } + + roles := make([]string, len(trustedProfilePolicy.Roles)) + for i, role := range trustedProfilePolicy.Roles { + roles[i] = *role.DisplayName + } + d.Set("roles", roles) + + if _, ok := d.GetOk("resources"); ok { + d.Set("resources", flex.FlattenPolicyResource(trustedProfilePolicy.Resources)) + } + if _, ok := d.GetOk("resource_attributes"); ok { + d.Set("resource_attributes", flex.FlattenPolicyResourceAttributes(trustedProfilePolicy.Resources)) + } + + if _, ok := d.GetOk("resource_tags"); ok { + d.Set("resource_tags", flex.FlattenPolicyResourceTags(trustedProfilePolicy.Resources)) + } + + if len(trustedProfilePolicy.Resources) > 0 { + if *flex.GetResourceAttribute("serviceType", trustedProfilePolicy.Resources[0]) == "service" { + d.Set("account_management", false) + } + if *flex.GetResourceAttribute("serviceType", trustedProfilePolicy.Resources[0]) == "platform_service" { + d.Set("account_management", true) + } + } + if trustedProfilePolicy.Description != nil { + d.Set("description", *trustedProfilePolicy.Description) + } + if len(res.Headers["Transaction-Id"]) > 0 && res.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", res.Headers["Transaction-Id"][0]) + } + + return nil +} + +func resourceIBMIAMTrustedProfilePolicyUpdate(d *schema.ResourceData, meta interface{}) error { + + if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") || d.HasChange("resource_tags") { + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + trustedProfilePolicyID := parts[1] + + var iamID string + if v, ok := d.GetOk("profile_id"); ok && v != nil { + profileIDUUID := v.(string) + + iamClient, err := meta.(conns.ClientSession).IAMIdentityV1API() + if err != nil { + return err + } + getProfileIDOptions := iamidentityv1.GetProfileOptions{ + ProfileID: &profileIDUUID, + } + profileID, resp, err := iamClient.GetProfile(&getProfileIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error] Error getting trusted profile ID %s %s", err, resp) + } + iamID = *profileID.IamID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + createPolicyOptions, err := flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(userDetails.UserAccount), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &iamID, + } + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + trustedProfilePolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || policy == nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error retrieving Policy: %s\n%s", err, response) + } + + trustedProfilePolicyETag := response.Headers.Get("ETag") + updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( + trustedProfilePolicyID, + trustedProfilePolicyETag, + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + createPolicyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if desc, ok := d.GetOk("description"); ok { + des := desc.(string) + updatePolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + updatePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + _, resp, err := iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating trusted profile policy: %s: %s", err, resp) + } + + } + + return resourceIBMIAMTrustedProfilePolicyRead(d, meta) + +} + +func resourceIBMIAMTrustedProfilePolicyDelete(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + trustedProfilePolicyID := parts[1] + + deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( + trustedProfilePolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + deletePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + resp, err := iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting trusted profile policy: %s %s", err, resp) + } + + d.SetId("") + + return nil +} + +func resourceIBMIAMTrustedProfilePolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of profileID(OR)iamID/PolicyID", d.Id()) + } + profileIDUUID := parts[0] + trustedProfilePolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + trustedProfilePolicyID, + ) + + trustedProfilePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || trustedProfilePolicy == nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting trusted profile policy: %s\n%s", err, resp) + } + + if trustedProfilePolicy != nil && trustedProfilePolicy.State != nil && *trustedProfilePolicy.State == "deleted" { + return false, nil + } + + tempID := fmt.Sprintf("%s/%s", profileIDUUID, *trustedProfilePolicy.ID) + + return tempID == d.Id(), nil +} + +func importTrustedProfilePolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, nil, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil, nil, err + } + trustedProfilePolicyID := parts[1] + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + trustedProfilePolicyID, + ) + trustedProfilePolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return nil, nil, fmt.Errorf("[ERROR] Error retrieving trusted profile policy: %s %s", err, resp) + } + resources := flex.FlattenPolicyResource(trustedProfilePolicy.Resources) + resource_attributes := flex.FlattenPolicyResourceAttributes(trustedProfilePolicy.Resources) + d.Set("resource_tags", flex.FlattenPolicyResourceTags(trustedProfilePolicy.Resources)) + return resources, resource_attributes, nil +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go new file mode 100644 index 000000000..360d9f321 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go @@ -0,0 +1,712 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMTrustedProfilePolicyBasic(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyBasic(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "description", "IAM Trusted Profile Policy Creation for test scenario"), + ), + }, + { + Config: testAccCheckIBMIAMTrustedProfilePolicyUpdateRole(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "description", "IAM Trusted Profile Policy Update for test scenario"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Service(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyService(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMTrustedProfilePolicyUpdateServiceAndRegion(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.region", "us-south"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_ServiceType(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyServiceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service_type", "service"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_ResourceInstance(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceInstance(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "3"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Group(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceGroup(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "containers-kubernetes"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Type(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceType(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_import(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_trusted_profile_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyImport(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"resources", "resource_attributes", "transaction_id"}, + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_account_management(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_trusted_profile_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyAccountManagement(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "account_management", "true"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicyWithCustomRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyWithCustomRole(name, crName, displayName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Attributes(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceAttributes(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_attributes.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesUpdate(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Tags(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMTrustedProfilePolicyUpdateResourceTags(name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMTrustedProfilePolicy_With_Transaction_Id(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyTransactionId(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "transaction_id", "terrformTrustedPolicy"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMTrustedProfilePolicyDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_trusted_profile_policy" { + continue + } + policyID := rs.Primary.ID + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + profilePolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + profilePolicyID, + ) + + // Try to find the key + destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) + + if err == nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) + } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("[ERROR] Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMTrustedProfilePolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + policyID := rs.Primary.ID + + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + profilePolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + profilePolicyID, + ) + + // Try to find the key + policy, _, err := rsContClient.GetPolicy(getPolicyOptions) + if err != nil { + return err + } + obj = *policy + return nil + } +} + +func testAccCheckIBMIAMTrustedProfilePolicyBasic(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + tags = ["tag1"] + description = "IAM Trusted Profile Policy Creation for test scenario" + } + + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyUpdateRole(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer", "Manager"] + tags = ["tag1", "tag2"] + description = "IAM Trusted Profile Policy Update for test scenario" + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyService(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + + resources { + service = "cloudantnosqldb" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyServiceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyUpdateServiceAndRegion(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer", "Manager"] + + resources { + service = "cloudantnosqldb" + region = "us-south" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyResourceInstance(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } + } + + + `, name, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyResourceGroup(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } + } + + + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyResourceType(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Administrator"] + + resources { + resource_type = "resource-group" + resource = data.ibm_resource_group.group.id + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyImport(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + } + + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyAccountManagement(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + account_management = true + } + + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyWithCustomRole(name, crName, displayName string) string { + return fmt.Sprintf(` + + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + resource "ibm_iam_custom_role" "customrole" { + name = "%s" + display_name = "%s" + description = "role for test scenario1" + service = "kms" + actions = ["kms.secrets.rotate"] + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] + tags = ["tag1"] + resources { + service = "kms" + } + } + + `, name, crName, displayName) +} + +func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributes(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} +func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesUpdate(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyResourceTags(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + resource_tags { + name = "one" + value = "Terraform" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyTransactionId(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + transaction_id = "terrformTrustedPolicy" + + resources { + service = "cloudantnosqldb" + } + } + `, name) +} + +func testAccCheckIBMIAMTrustedProfilePolicyUpdateResourceTags(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + resource_tags { + name = "one" + value = "Terraform" + } + resource_tags { + name = "two" + value = "TerraformUpdate" + } + } + `, name) +} diff --git a/ibm/resource_ibm_iam_user_invite.go b/ibm/service/iampolicy/resource_ibm_iam_user_invite.go similarity index 88% rename from ibm/resource_ibm_iam_user_invite.go rename to ibm/service/iampolicy/resource_ibm_iam_user_invite.go index 36e37835b..4fac34cd6 100644 --- a/ibm/resource_ibm_iam_user_invite.go +++ b/ibm/service/iampolicy/resource_ibm_iam_user_invite.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package iampolicy import ( "fmt" @@ -11,6 +11,9 @@ import ( "github.com/IBM-Cloud/bluemix-go/api/iampap/iampapv1" v2 "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" @@ -129,7 +132,7 @@ var superUser = []string{"HARDWARE_VIEW", var permissionSets = map[string][]string{NOACCESS: noAccess, VIEWONLY: viewOnly, BASICUSER: basicUser, SUPERUSER: superUser} -func resourceIBMUserInvite() *schema.Resource { +func ResourceIBMIAMUserInvite() *schema.Resource { return &schema.Resource{ Create: resourceIBMIAMInviteUsers, Read: resourceIBMIAMGetUsers, @@ -144,6 +147,7 @@ func resourceIBMUserInvite() *schema.Resource { Type: schema.TypeSet, Required: true, Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, }, "access_groups": { Description: "access group ids to associate the inviting user", @@ -298,6 +302,11 @@ func resourceIBMUserInvite() *schema.Resource { Computed: true, Description: "ID of the resource group.", }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, "attributes": { Type: schema.TypeMap, @@ -383,7 +392,11 @@ func resourceIBMUserInvite() *schema.Resource { Computed: true, Description: "ID of the resource group.", }, - + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "Service type of the policy definition", + }, "attributes": { Type: schema.TypeMap, Computed: true, @@ -411,7 +424,7 @@ func resourceIBMUserInvite() *schema.Resource { Type: schema.TypeString, Optional: true, Description: "permission set for claasic infrastructure", - ValidateFunc: validateAllowedStringValue([]string{NOACCESS, VIEWONLY, BASICUSER, SUPERUSER}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{NOACCESS, VIEWONLY, BASICUSER, SUPERUSER}), }, "permissions": { @@ -470,20 +483,20 @@ func resourceIBMUserInvite() *schema.Resource { } func resourceIBMIAMInviteUsers(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } client := userManagement.UserInvite() usersSet := d.Get("users").(*schema.Set) - usersList := flattenUsersSet(usersSet) + usersList := flex.FlattenUsersSet(usersSet) users := make([]v2.User, 0) for _, user := range usersList { users = append(users, v2.User{Email: user, AccountRole: MEMBER}) } if len(users) == 0 { - return fmt.Errorf("Users email not provided") + return fmt.Errorf("[ERROR] Users email not provided") } var accessGroups = make([]string, 0) if data, ok := d.GetOk("access_groups"); ok { @@ -536,16 +549,16 @@ func resourceIBMIAMInviteUsers(d *schema.ResourceData, meta interface{}) error { } func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } Client := userManagement.UserInvite() - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return err } - iamAccessGroupsClient, err := meta.(ClientSession).IAMAccessGroupsV2() + iamAccessGroupsClient, err := meta.(conns.ClientSession).IAMAccessGroupsV2() if err != nil { return err } @@ -581,7 +594,7 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { policies := policyList.Policies if err != nil { - return fmt.Errorf("Error retrieving user policies: %s", err) + return fmt.Errorf("[ERROR] Error retrieving user policies: %s", err) } userPolicies := make([]map[string]interface{}, 0, len(policies)) for _, policy := range policies { @@ -591,13 +604,15 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { roles[i] = *role.DisplayName } //populate policy resources - resources := flattenPolicyResource(policy.Resources) + // userResources := make([]map[string]interface{}, 0) + userResources := flex.FlattenPolicyResource(policy.Resources) p := map[string]interface{}{ "id": policy.ID, "roles": roles, - "resources": resources, + "resources": userResources, } userPolicies = append(userPolicies, p) + } listAccessGroupOptions := &iamaccessgroupsv2.ListAccessGroupsOptions{ @@ -606,7 +621,7 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { } retreivedGroups, _, err := iamAccessGroupsClient.ListAccessGroups(listAccessGroupOptions) if err != nil { - return fmt.Errorf("Error retrieving access groups: %s", err) + return fmt.Errorf("[ERROR] Error retrieving access groups: %s", err) } accGroupList := make([]map[string]interface{}, 0, len(retreivedGroups.Groups)) @@ -618,7 +633,7 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { }) accgrpPolicy := policyList.Policies if err != nil { - return fmt.Errorf("Error retrieving access group policy: %s", err) + return fmt.Errorf("[ERROR] Error retrieving access group policy: %s", err) } //Fetch access group policies @@ -630,17 +645,17 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { roles[i] = *role.DisplayName } //populate policy resources - resources := flattenPolicyResource(policy.Resources) + grpResources := flex.FlattenPolicyResource(policy.Resources) p := map[string]interface{}{ "id": policy.ID, "roles": roles, - "resources": resources, + "resources": grpResources, } grpPolicies = append(grpPolicies, p) } //populate name & policies of a access group agInfo := map[string]interface{}{ - "name": grpData.Name, + "name": *grpData.Name, "policies": grpPolicies, } //add agInfo to list of access groups @@ -661,7 +676,7 @@ func resourceIBMIAMGetUsers(d *schema.ResourceData, meta interface{}) error { func resourceIBMIAMUpdateUserProfile(d *schema.ResourceData, meta interface{}) error { // validate change - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -677,8 +692,8 @@ func resourceIBMIAMUpdateUserProfile(d *schema.ResourceData, meta interface{}) e old := ousrs.(*schema.Set) new := nusrs.(*schema.Set) - removed := expandStringList(old.Difference(new).List()) - added := expandStringList(new.Difference(old).List()) + removed := flex.ExpandStringList(old.Difference(new).List()) + added := flex.ExpandStringList(new.Difference(old).List()) //Update the added users if len(added) > 0 { @@ -687,7 +702,7 @@ func resourceIBMIAMUpdateUserProfile(d *schema.ResourceData, meta interface{}) e users = append(users, v2.User{Email: user, AccountRole: MEMBER}) } if len(users) == 0 { - return fmt.Errorf("Users email not provided") + return fmt.Errorf("[ERROR] Users email not provided") } var accessPolicies []v2.UserPolicy @@ -738,7 +753,7 @@ func resourceIBMIAMUpdateUserProfile(d *schema.ResourceData, meta interface{}) e for _, user := range removed { IAMID, err := getUserIAMID(d, meta, user) if err != nil { - return fmt.Errorf("User's IAM ID not found: %s", err.Error()) + return fmt.Errorf("[ERROR] User's IAM ID not found: %s", err.Error()) } Err := Client.RemoveUsers(accountID, IAMID) if Err != nil { @@ -753,7 +768,7 @@ func resourceIBMIAMUpdateUserProfile(d *schema.ResourceData, meta interface{}) e } func resourceIBMIAMRemoveUser(d *schema.ResourceData, meta interface{}) error { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return err } @@ -765,12 +780,12 @@ func resourceIBMIAMRemoveUser(d *schema.ResourceData, meta interface{}) error { } usersSet := d.Get("users").(*schema.Set) - usersList := flattenUsersSet(usersSet) + usersList := flex.FlattenUsersSet(usersSet) for _, user := range usersList { IAMID, err := getUserIAMID(d, meta, user) if err != nil { - return fmt.Errorf("User's IAM ID not found: %s", err.Error()) + return fmt.Errorf("[ERROR] User's IAM ID not found: %s", err.Error()) } Err := Client.RemoveUsers(accountID, IAMID) if Err != nil { @@ -781,7 +796,7 @@ func resourceIBMIAMRemoveUser(d *schema.ResourceData, meta interface{}) error { } func resourceIBMIAMGetUserProfileExists(d *schema.ResourceData, meta interface{}) (bool, error) { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return false, err } @@ -793,7 +808,7 @@ func resourceIBMIAMGetUserProfileExists(d *schema.ResourceData, meta interface{} } usersSet := d.Get("users").(*schema.Set) - usersList := flattenUsersSet(usersSet) + usersList := flex.FlattenUsersSet(usersSet) res, err := Client.ListUsers(accountID) if err != nil { @@ -816,16 +831,16 @@ func resourceIBMIAMGetUserProfileExists(d *schema.ResourceData, meta interface{} // getAccountID returns accountID func getAccountID(d *schema.ResourceData, meta interface{}) (string, error) { - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return "", err } - return userDetails.userAccount, nil + return userDetails.UserAccount, nil } // getUserIAMID ... func getUserIAMID(d *schema.ResourceData, meta interface{}, user string) (string, error) { - userManagement, err := meta.(ClientSession).UserManagementAPI() + userManagement, err := meta.(conns.ClientSession).UserManagementAPI() if err != nil { return "", err } @@ -854,19 +869,22 @@ func getInfraPermissions(d *schema.ResourceData, meta interface{}) []string { var infraPermissions = make([]string, 0) if data, ok := d.GetOk("classic_infra_roles"); ok { for _, resource := range data.([]interface{}) { - d := resource.(map[string]interface{}) - if permissions, ok := d["permissions"]; ok && permissions != nil { - for _, value := range permissions.([]interface{}) { - infraPermissions = append(infraPermissions, fmt.Sprintf("%v", value)) + if resource != nil { + d := resource.(map[string]interface{}) + if permissions, ok := d["permissions"]; ok && permissions != nil { + for _, value := range permissions.([]interface{}) { + infraPermissions = append(infraPermissions, fmt.Sprintf("%v", value)) + } } - } - if permissionSet, ok := d["permission_set"]; ok && permissionSet != nil { - if permissions, ok := permissionSets[permissionSet.(string)]; ok { - for _, permission := range permissions { - infraPermissions = append(infraPermissions, permission) + if permissionSet, ok := d["permission_set"]; ok && permissionSet != nil { + if permissions, ok := permissionSets[permissionSet.(string)]; ok { + for _, permission := range permissions { + infraPermissions = append(infraPermissions, permission) + } } } } + } return infraPermissions } @@ -956,7 +974,7 @@ func getPolicies(d *schema.ResourceData, meta interface{}, policies []interface{ if r, ok := r["attributes"]; ok { for k, v := range r.(map[string]interface{}) { - resourceAttributes = setResourceAttribute(core.StringPtr(k), v.(*string), resourceAttributes) + resourceAttributes = flex.SetResourceAttribute(core.StringPtr(k), v.(*string), resourceAttributes) } } @@ -996,30 +1014,30 @@ func getPolicies(d *schema.ResourceData, meta interface{}, policies []interface{ policyResource.Attributes = resourceAttributes - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { return policyList, err } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return policyList, err } listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ - AccountID: &userDetails.userAccount, + AccountID: &userDetails.UserAccount, ServiceName: &serviceName, } roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) - roles := mapRoleListToPolicyRoles(*roleList) + roles := flex.MapRoleListToPolicyRoles(*roleList) if err != nil { return policyList, err } var policyRoles = make([]iampolicymanagementv1.PolicyRole, 0) if userRoles, ok := p["roles"]; ok { - policyRoles, err = getRolesFromRoleNames(expandStringList(userRoles.([]interface{})), roles) + policyRoles, err = flex.GetRolesFromRoleNames(flex.ExpandStringList(userRoles.([]interface{})), roles) if err != nil { return policyList, err } @@ -1055,12 +1073,12 @@ func convertIPMResourcesToV1(resource iampolicymanagementv1.PolicyResource) []ia func getCloudFoundryRoles(d *schema.ResourceData, meta interface{}) ([]v2.OrgRole, error) { cloudFoundryRoles := make([]v2.OrgRole, 0) if data, ok := d.GetOk("cloud_foundry_roles"); ok { - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return nil, err } usersSet := d.Get("users").(*schema.Set) - usersList := flattenUsersSet(usersSet) + usersList := flex.FlattenUsersSet(usersSet) for _, d := range data.([]interface{}) { orgRole := v2.OrgRole{} role := d.(map[string]interface{}) diff --git a/ibm/service/iampolicy/resource_ibm_iam_user_policy.go b/ibm/service/iampolicy/resource_ibm_iam_user_policy.go new file mode 100644 index 000000000..6173c0810 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_user_policy.go @@ -0,0 +1,554 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package iampolicy + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIAMUserPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMIAMUserPolicyCreate, + Read: resourceIBMIAMUserPolicyRead, + Update: resourceIBMIAMUserPolicyUpdate, + Delete: resourceIBMIAMUserPolicyDelete, + Exists: resourceIBMIAMUserPolicyExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + resources, resourceAttributes, err := importUserPolicy(d, meta) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error reading resource ID: %s", err) + } + d.Set("resources", resources) + d.Set("resource_attributes", resourceAttributes) + return []*schema.ResourceData{d}, nil + }, + }, + Schema: map[string]*schema.Schema{ + + "ibm_id": { + Description: "The ibm id or email of user", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "roles": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Role names of the policy definition", + }, + + "resources": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"account_management", "resource_attributes"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "Service name of the policy definition", + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of resource instance of the policy definition", + }, + + "region": { + Type: schema.TypeString, + Optional: true, + Description: "Region of the policy definition", + }, + + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type of the policy definition", + }, + + "resource": { + Type: schema.TypeString, + Optional: true, + Description: "Resource of the policy definition", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + + "service_type": { + Type: schema.TypeString, + Optional: true, + Description: "Service type of the policy definition", + }, + + "attributes": { + Type: schema.TypeMap, + Optional: true, + Description: "Set resource attributes in the form of 'name=value,name=value....", + Elem: schema.TypeString, + }, + }, + }, + }, + + "resource_attributes": { + Type: schema.TypeSet, + Optional: true, + Description: "Set resource attributes.", + ConflictsWith: []string{"resources", "account_management"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + "account_management": { + Type: schema.TypeBool, + Default: false, + Optional: true, + Description: "Give access to all account management services", + ConflictsWith: []string{"resources", "resource_attributes"}, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "resource_tags": { + Type: schema.TypeSet, + Optional: true, + Description: "Set access management tags.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of attribute.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of attribute.", + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "stringEquals", + Description: "Operator of attribute.", + }, + }, + }, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the Policy", + }, + + "transaction_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Set transactionID for debug", + }, + }, + } +} + +func resourceIBMIAMUserPolicyCreate(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + var policyOptions iampolicymanagementv1.CreatePolicyOptions + policyOptions, err = flex.GeneratePolicyOptions(d, meta) + + if err != nil { + return err + } + + userEmail := d.Get("ibm_id").(string) + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + ibmUniqueID, err := flex.GetIBMUniqueId(accountID, userEmail, meta) + if err != nil { + return err + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &ibmUniqueID, + } + + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(accountID), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(policyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + createPolicyOptions := iamPolicyManagementClient.NewCreatePolicyOptions( + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + policyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if description, ok := d.GetOk("description"); ok { + des := description.(string) + createPolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + userPolicy, resp, err := iamPolicyManagementClient.CreatePolicy(createPolicyOptions) + if err != nil { + return fmt.Errorf("Error creating user policies: %s, %s", err, resp) + } + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: userPolicy.ID, + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + policy, res, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || policy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + _, _, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil { + d.SetId(fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID)) + return fmt.Errorf("[ERROR] Error fetching user policy: %w", err) + } + d.SetId(fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID)) + + return resourceIBMIAMUserPolicyRead(d, meta) +} + +func resourceIBMIAMUserPolicyRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + userEmail := parts[0] + userPolicyID := parts[1] + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: core.StringPtr(userPolicyID), + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + userPolicy := &iampolicymanagementv1.Policy{} + res := &core.DetailedResponse{} + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + userPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + + if err != nil || userPolicy == nil { + if res != nil && res.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + userPolicy, res, err = iamPolicyManagementClient.GetPolicy(getPolicyOptions) + } + if err != nil || userPolicy == nil || res == nil { + return fmt.Errorf("[ERROR] Error retrieving userPolicy: %s %s", err, res) + } + d.Set("ibm_id", userEmail) + roles := make([]string, len(userPolicy.Roles)) + + for i, role := range userPolicy.Roles { + roles[i] = *role.DisplayName + } + d.Set("roles", roles) + if _, ok := d.GetOk("resources"); ok { + d.Set("resources", flex.FlattenPolicyResource(userPolicy.Resources)) + } + if _, ok := d.GetOk("resource_attributes"); ok { + d.Set("resource_attributes", flex.FlattenPolicyResourceAttributes(userPolicy.Resources)) + } + + if _, ok := d.GetOk("resource_tags"); ok { + d.Set("resource_tags", flex.FlattenPolicyResourceTags(userPolicy.Resources)) + } + + if len(userPolicy.Resources) > 0 { + if *flex.GetResourceAttribute("serviceType", userPolicy.Resources[0]) == "service" { + d.Set("account_management", false) + } + if *flex.GetResourceAttribute("serviceType", userPolicy.Resources[0]) == "platform_service" { + d.Set("account_management", true) + } + } + if userPolicy.Description != nil { + d.Set("description", *userPolicy.Description) + } + if len(res.Headers["Transaction-Id"]) > 0 && res.Headers["Transaction-Id"][0] != "" { + d.Set("transaction_id", res.Headers["Transaction-Id"][0]) + } + + return nil +} + +func resourceIBMIAMUserPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("resource_attributes") || d.HasChange("account_management") || d.HasChange("description") || d.HasChange("resource_tags") { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + userEmail := parts[0] + userPolicyID := parts[1] + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + + createPolicyOptions, err := flex.GeneratePolicyOptions(d, meta) + if err != nil { + return err + } + + ibmUniqueID, err := flex.GetIBMUniqueId(accountID, userEmail, meta) + if err != nil { + return err + } + + accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ + Name: core.StringPtr("accountId"), + Value: core.StringPtr(accountID), + Operator: core.StringPtr("stringEquals"), + } + + policyResources := iampolicymanagementv1.PolicyResource{ + Attributes: append(createPolicyOptions.Resources[0].Attributes, *accountIDResourceAttribute), + Tags: flex.SetTags(d), + } + + subjectAttribute := &iampolicymanagementv1.SubjectAttribute{ + Name: core.StringPtr("iam_id"), + Value: &ibmUniqueID, + } + policySubjects := &iampolicymanagementv1.PolicySubject{ + Attributes: []iampolicymanagementv1.SubjectAttribute{*subjectAttribute}, + } + + getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ + PolicyID: &userPolicyID, + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + policy, response, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || policy == nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error retrieving Policy: %s\n%s", err, response) + } + + userPolicyETag := response.Headers.Get("ETag") + updatePolicyOptions := iamPolicyManagementClient.NewUpdatePolicyOptions( + userPolicyID, + userPolicyETag, + "access", + []iampolicymanagementv1.PolicySubject{*policySubjects}, + createPolicyOptions.Roles, + []iampolicymanagementv1.PolicyResource{policyResources}, + ) + + if description, ok := d.GetOk("description"); ok { + des := description.(string) + updatePolicyOptions.Description = &des + } + + if transactionID, ok := d.GetOk("transaction_id"); ok { + updatePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + _, resp, err := iamPolicyManagementClient.UpdatePolicy(updatePolicyOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating user policy: %s, %s", err, resp) + } + } + return resourceIBMIAMUserPolicyRead(d, meta) +} + +func resourceIBMIAMUserPolicyDelete(d *schema.ResourceData, meta interface{}) error { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + userPolicyID := parts[1] + + deletePolicyOptions := iamPolicyManagementClient.NewDeletePolicyOptions( + userPolicyID, + ) + + if transactionID, ok := d.GetOk("transaction_id"); ok { + deletePolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) + } + + _, err = iamPolicyManagementClient.DeletePolicy(deletePolicyOptions) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func resourceIBMIAMUserPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return false, err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of userEmail/PolicyID", d.Id()) + } + userEmail := parts[0] + userPolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + userPolicyID, + ) + + userPolicy, resp, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil || userPolicy == nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting user policy: %s\n%s", err, resp) + } + + if userPolicy != nil && userPolicy.State != nil && *userPolicy.State == "deleted" { + return false, nil + } + + tempID := fmt.Sprintf("%s/%s", userEmail, *userPolicy.ID) + + return tempID == d.Id(), nil +} + +func importUserPolicy(d *schema.ResourceData, meta interface{}) (interface{}, interface{}, error) { + + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, nil, err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil, nil, err + } + userPolicyID := parts[1] + + getPolicyOptions := iamPolicyManagementClient.NewGetPolicyOptions( + userPolicyID, + ) + userPolicy, _, err := iamPolicyManagementClient.GetPolicy(getPolicyOptions) + if err != nil { + return nil, nil, fmt.Errorf("[ERROR] Error retrieving User Policy: %s", err) + } + resources := flex.FlattenPolicyResource(userPolicy.Resources) + resource_attributes := flex.FlattenPolicyResourceAttributes(userPolicy.Resources) + d.Set("resource_tags", flex.FlattenPolicyResourceTags(userPolicy.Resources)) + return resources, resource_attributes, nil +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go new file mode 100644 index 000000000..bb193f3f7 --- /dev/null +++ b/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go @@ -0,0 +1,707 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package iampolicy_test + +import ( + "fmt" + "regexp" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMIAMUserPolicy_Basic(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Creation for test scenario"), + ), + }, + { + Config: testAccCheckIBMIAMUserPolicyUpdateRole(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Update for test scenario"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_Service(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyService(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + ), + }, + { + Config: testAccCheckIBMIAMUserPolicyUpdateServiceAndRegion(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.region", "us-south"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_ServiceType(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyServiceType(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service_type", "service"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_ResourceInstance(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceInstance(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "3"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_Resource_Group(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceGroup(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "containers-kubernetes"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_Resource_Type(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceType(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_import(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_user_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyImport(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"resources", "resource_attributes", "transaction_id"}, + }, + }, + }) +} +func TestAccIBMIAMUserPolicy_With_Resource_Attributes(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceAttributes(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_attributes.#", "2"), + ), + }, + { + Config: testAccCheckIBMIAMUserPolicyResourceAttributesUpdate(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} +func TestAccIBMIAMUserPolicy_account_management(t *testing.T) { + var conf iampolicymanagementv1.Policy + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_iam_user_policy.policy" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyAccountManagement(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists(resourceName, conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "account_management", "true"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_Invalid_User(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyInvalidUser(), + ExpectError: regexp.MustCompile(`User test@in.ibm.com is not found`), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicyWithCustomRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + crName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + displayName := fmt.Sprintf("Terraform%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyWithCustomRole(crName, displayName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "kms"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicyWithSpecificServiceRole(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyWithServiceSpecificRole(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resources.0.service", "cloudantnosqldb"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "3"), + ), + }, + }, + }) +} + +func TestAccIBMIAMUserPolicy_With_Resource_Tags(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMUserPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceTags(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "1"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Creation for test scenario"), + ), + }, + { + Config: testAccCheckIBMIAMUserPolicyResourceTagsUpdate(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_tags.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "roles.#", "2"), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "description", "IAM User Policy Update for test scenario"), + ), + }, + }, + }) + +} + +func TestAccIBMIAMUserPolicy_With_Transaction_Id(t *testing.T) { + var conf iampolicymanagementv1.Policy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyTransactionId(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "transaction_id", "terrformUserPolicy"), + ), + }, + }, + }) +} + +func testAccCheckIBMIAMUserPolicyDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_iam_user_policy" { + continue + } + policyID := rs.Primary.ID + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + + userPolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + userPolicyID, + ) + + // Try to find the key + destroyedPolicy, response, err := rsContClient.GetPolicy(getPolicyOptions) + + if err == nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("User policy still exists: %s\n", rs.Primary.ID) + } else if response.StatusCode != 404 && destroyedPolicy.State != nil && *destroyedPolicy.State != "deleted" { + return fmt.Errorf("[ERROR] Error waiting for user policy (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMIAMUserPolicyExists(n string, obj iampolicymanagementv1.Policy) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return err + } + + policyID := rs.Primary.ID + parts, err := flex.IdParts(policyID) + if err != nil { + return err + } + userPolicyID := parts[1] + + getPolicyOptions := rsContClient.NewGetPolicyOptions( + userPolicyID, + ) + + policy, _, err := rsContClient.GetPolicy(getPolicyOptions) + if err != nil { + return err + } + obj = *policy + return nil + } +} + +func testAccCheckIBMIAMUserPolicyBasic() string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + tags = ["tag1"] + description = "IAM User Policy Creation for test scenario" + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyUpdateRole() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer", "Manager"] + tags = ["tag1", "tag2"] + description = "IAM User Policy Update for test scenario" + } + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyService() string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + + resources { + service = "cloudantnosqldb" + } + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyWithServiceSpecificRole() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = [ "Monitor", "Reader", "Viewer"] + resources { + service = "cloudantnosqldb" + } + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyServiceType() string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyUpdateServiceAndRegion() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer", "Manager"] + + resources { + service = "cloudantnosqldb" + region = "us-south" + } + } + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceInstance(name string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Manager", "Viewer", "Administrator"] + + resources { + service = "kms" + resource_instance_id = element(split(":", ibm_resource_instance.instance.id), 7) + } + } + + + `, name, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceGroup() string { + return fmt.Sprintf(` + + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + + resources { + service = "containers-kubernetes" + resource_group_id = data.ibm_resource_group.group.id + } + } + + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceType() string { + return fmt.Sprintf(` + + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Administrator"] + + resources { + resource_type = "resource-group" + resource = data.ibm_resource_group.group.id + } + } + `, acc.IAMUser) +} + +// TODO: do we need this test? It follows pattern of other policies, but has conflict with existing policy +func testAccCheckIBMIAMUserPolicyImport(name string) string { + return fmt.Sprintf(` + + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyInvalidUser() string { + return ` + + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "test@in.ibm.com" + roles = ["Viewer"] + } + + ` +} + +func testAccCheckIBMIAMUserPolicyAccountManagement(name string) string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + account_management = true + } + + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyWithCustomRole(crName, displayName string) string { + return fmt.Sprintf(` + + resource "ibm_iam_custom_role" "customrole" { + name = "%s" + display_name = "%s" + description = "role for test scenario1" + service = "kms" + actions = ["kms.secrets.rotate"] + } + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = [ibm_iam_custom_role.customrole.display_name,"Viewer"] + resources { + service = "kms" + } + } + + `, crName, displayName, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceAttributes() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + +`, acc.IAMUser) +} +func testAccCheckIBMIAMUserPolicyResourceAttributesUpdate() string { + return fmt.Sprintf(` + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test*" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceTags() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + description = "IAM User Policy Creation for test scenario" + resources { + service_type = "service" + } + + resource_tags { + name = "test" + value = "terraform" + } + } + +`, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyResourceTagsUpdate() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer", "Manager"] + description = "IAM User Policy Update for test scenario" + resources { + service_type = "service" + } + + resource_tags { + name = "test" + value = "terraform" + } + resource_tags { + name = "two" + value = "terrformupdate" + } + } + `, acc.IAMUser) +} + +func testAccCheckIBMIAMUserPolicyTransactionId() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + transaction_id = "terrformUserPolicy" + resources { + service = "cloudantnosqldb" + } + } + + `, acc.IAMUser) +} diff --git a/ibm/service/kms/README.md b/ibm/service/kms/README.md new file mode 100644 index 000000000..ae263f08e --- /dev/null +++ b/ibm/service/kms/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Key Management Service + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the KMS resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key) +* IBM API Docs: [IBM API Docs for KMS](https://cloud.ibm.com/apidocs/key-protect) +* IBM KMS SDK: [IBM SDK for KMS](https://github.com/IBM/keyprotect-go-client) diff --git a/ibm/data_source_ibm_kms_key.go b/ibm/service/kms/data_source_ibm_kms_key.go similarity index 81% rename from ibm/data_source_ibm_kms_key.go rename to ibm/service/kms/data_source_ibm_kms_key.go index 4556b7923..87eea4566 100644 --- a/ibm/data_source_ibm_kms_key.go +++ b/ibm/service/kms/data_source_ibm_kms_key.go @@ -1,20 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms import ( "context" "fmt" "log" - "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMKMSkey() *schema.Resource { +func DataSourceIBMKMSkey() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMKMSKeyRead, @@ -49,7 +49,7 @@ func dataSourceIBMKMSkey() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), Description: "public or private", Default: "public", }, @@ -174,38 +174,11 @@ func dataSourceIBMKMSkey() *schema.Resource { } func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyManagementAPI() + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + api, _, err := populateKPClient(d, meta, instanceID) if err != nil { return err } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(api, endpointType, extensions) - if err != nil { - return err - } - api.URL = URL - - api.Config.InstanceID = instanceID var totalKeys []kp.Key if v, ok := d.GetOk("key_name"); ok { @@ -220,8 +193,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { if limitVal == 0 { keys, err := api.GetKeys(context.Background(), 0, offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } retreivedKeys := keys.Keys totalKeys = append(totalKeys, retreivedKeys...) @@ -232,8 +204,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { if (limitVal - offset) < pageSize { keys, err := api.GetKeys(context.Background(), (limitVal - offset), offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } retreivedKeys := keys.Keys totalKeys = append(totalKeys, retreivedKeys...) @@ -241,8 +212,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { } else { keys, err := api.GetKeys(context.Background(), pageSize, offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } numOfKeysFetched := keys.Metadata.NumberOfKeys retreivedKeys := keys.Keys @@ -258,7 +228,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { } if len(totalKeys) == 0 { - return fmt.Errorf("No keys in instance %s", instanceID) + return fmt.Errorf("[ERROR] No keys in instance %s", instanceID) } var keyName string var matchKeys []kp.Key @@ -273,7 +243,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { matchKeys = totalKeys } if len(matchKeys) == 0 { - return fmt.Errorf("No keys with name %s in instance %s", keyName, instanceID) + return fmt.Errorf("[ERROR] No keys with name %s in instance %s", keyName, instanceID) } keyMap := make([]map[string]interface{}, 0, len(matchKeys)) @@ -288,12 +258,12 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { keyInstance["key_ring_id"] = key.KeyRingID policies, err := api.GetPolicies(context.Background(), key.ID) if err != nil { - return fmt.Errorf("Failed to read policies: %s", err) + return fmt.Errorf("[ERROR] Failed to read policies: %s", err) } if len(policies) == 0 { log.Printf("No Policy Configurations read\n") } else { - keyInstance["policies"] = flattenKeyPolicies(policies) + keyInstance["policies"] = flex.FlattenKeyPolicies(policies) } keyMap = append(keyMap, keyInstance) @@ -304,8 +274,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { } else if v, ok := d.GetOk("key_id"); ok { key, err := api.GetKey(context.Background(), v.(string)) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } keyMap := make([]map[string]interface{}, 0, 1) keyInstance := make(map[string]interface{}) @@ -317,12 +286,12 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { keyInstance["key_ring_id"] = key.KeyRingID policies, err := api.GetPolicies(context.Background(), key.ID) if err != nil { - return fmt.Errorf("Failed to read policies: %s", err) + return fmt.Errorf("[ERROR] Failed to read policies: %s", err) } if len(policies) == 0 { log.Printf("No Policy Configurations read\n") } else { - keyInstance["policies"] = flattenKeyPolicies(policies) + keyInstance["policies"] = flex.FlattenKeyPolicies(policies) } keyMap = append(keyMap, keyInstance) @@ -333,8 +302,7 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { aliasName := d.Get("alias").(string) key, err := api.GetKey(context.Background(), aliasName) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } keyMap := make([]map[string]interface{}, 0, 1) keyInstance := make(map[string]interface{}) @@ -346,12 +314,12 @@ func dataSourceIBMKMSKeyRead(d *schema.ResourceData, meta interface{}) error { keyInstance["key_ring_id"] = key.KeyRingID policies, err := api.GetPolicies(context.Background(), key.ID) if err != nil { - return fmt.Errorf("Failed to read policies: %s", err) + return fmt.Errorf("[ERROR] Failed to read policies: %s", err) } if len(policies) == 0 { log.Printf("No Policy Configurations read\n") } else { - keyInstance["policies"] = flattenKeyPolicies(policies) + keyInstance["policies"] = flex.FlattenKeyPolicies(policies) } keyMap = append(keyMap, keyInstance) diff --git a/ibm/data_source_ibm_kms_key_policies.go b/ibm/service/kms/data_source_ibm_kms_key_policies.go similarity index 79% rename from ibm/data_source_ibm_kms_key_policies.go rename to ibm/service/kms/data_source_ibm_kms_key_policies.go index 103f7d718..f9f02734c 100644 --- a/ibm/data_source_ibm_kms_key_policies.go +++ b/ibm/service/kms/data_source_ibm_kms_key_policies.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms import ( "context" "log" - "strings" //kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMKMSkeyPolicies() *schema.Resource { +func DataSourceIBMKMSkeyPolicies() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMKMSKeyPoliciesRead, @@ -27,14 +28,21 @@ func dataSourceIBMKMSkeyPolicies() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), Description: "public or private", Default: "public", }, "key_id": { - Type: schema.TypeString, - Required: true, - Description: "Key ID of the Key", + Type: schema.TypeString, + Optional: true, + Description: "Key ID of the Key", + ExactlyOneOf: []string{"key_id", "alias"}, + }, + "alias": { + Type: schema.TypeString, + Optional: true, + Description: "Alias of the Key", + ExactlyOneOf: []string{"key_id", "alias"}, }, "policies": { Type: schema.TypeList, @@ -86,7 +94,7 @@ func dataSourceIBMKMSkeyPolicies() *schema.Resource { "interval_month": { Type: schema.TypeInt, Required: true, - ValidateFunc: validateAllowedRangeInt(1, 12), + ValidateFunc: validate.ValidateAllowedRangeInt(1, 12), Description: "Specifies the key rotation time interval in months", }, }, @@ -146,40 +154,27 @@ func dataSourceIBMKMSkeyPolicies() *schema.Resource { } func dataSourceIBMKMSKeyPoliciesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - api, err := meta.(ClientSession).keyManagementAPI() + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + api, _, err := populateKPClient(d, meta, instanceID) if err != nil { return diag.FromErr(err) } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } endpointType := d.Get("endpoint_type").(string) - key_id := d.Get("key_id").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return diag.FromErr(err) - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return diag.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) + var id string + if v, ok := d.GetOk("key_id"); ok { + id = v.(string) + d.Set("key_id", id) } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(api, endpointType, extensions) - if err != nil { - return diag.FromErr(err) + if v, ok := d.GetOk("alias"); ok { + id = v.(string) + key, err := api.GetKey(context, id) + if err != nil { + return diag.Errorf("Failed to get Key: %s", err) + } + d.Set("alias", id) + d.Set("key_id", key.ID) } - api.URL = URL - - api.Config.InstanceID = instanceID - policies, err := api.GetPolicies(context, key_id) + policies, err := api.GetPolicies(context, id) if err != nil { return diag.Errorf("Failed to read policies: %s", err) } @@ -187,14 +182,11 @@ func dataSourceIBMKMSKeyPoliciesRead(context context.Context, d *schema.Resource if len(policies) == 0 { log.Printf("No Policy Configurations read\n") } else { - d.Set("policies", flattenKeyPolicies(policies)) + d.Set("policies", flex.FlattenKeyPolicies(policies)) } - d.SetId(instanceID) - d.Set("key_id", key_id) d.Set("instance_id", instanceID) d.Set("endpoint_type", endpointType) return nil - } diff --git a/ibm/data_source_ibm_kms_key_policies_test.go b/ibm/service/kms/data_source_ibm_kms_key_policies_test.go similarity index 81% rename from ibm/data_source_ibm_kms_key_policies_test.go rename to ibm/service/kms/data_source_ibm_kms_key_policies_test.go index 99464b71c..96d9453f7 100644 --- a/ibm/data_source_ibm_kms_key_policies_test.go +++ b/ibm/service/kms/data_source_ibm_kms_key_policies_test.go @@ -1,9 +1,10 @@ -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,15 +16,15 @@ func TestAccIBMKmsDataSourceKeyPolicy_basicNew(t *testing.T) { interval_month := 3 enabled := false resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsDataSourceKeyPolicyConfigNew(instanceName, keyName, interval_month, enabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("data.ibm_kms_key_policies.test", "keys.0.rotation.0.interval_month", "3"), - resource.TestCheckResourceAttr("data.ibm_kms_key_policies.test", "keys.0.dual_auth_delete.0.enabled", "false"), + resource.TestCheckResourceAttr("data.ibm_kms_key_policies.test", "policies.0.rotation.0.interval_month", "3"), + resource.TestCheckResourceAttr("data.ibm_kms_key_policies.test", "policies.0.dual_auth_delete.0.enabled", "false"), ), }, }, @@ -47,7 +48,7 @@ func testAccCheckIBMKmsDataSourceKeyPolicyConfigNew(instanceName, keyName string } resource "ibm_kms_key_policies" "test2" { instance_id = "${ibm_kms_key.test.instance_id}" - key_id = "ibm_kms_key.test.key_id" + key_id = "${ibm_kms_key.test.key_id}" rotation { interval_month = %d } @@ -56,8 +57,8 @@ func testAccCheckIBMKmsDataSourceKeyPolicyConfigNew(instanceName, keyName string } } data "ibm_kms_key_policies" "test" { - instance_id = "${ibm_kms_key.test.instance_id}" - key_id = "${ibm_kms_key.test.key_id}" + instance_id = "${ibm_kms_key_policies.test2.instance_id}" + key_id = "${ibm_kms_key_policies.test2.key_id}" } `, instanceName, keyName, interval_month, enabled) } diff --git a/ibm/service/kms/data_source_ibm_kms_key_rings.go b/ibm/service/kms/data_source_ibm_kms_key_rings.go new file mode 100644 index 000000000..c3b6bb048 --- /dev/null +++ b/ibm/service/kms/data_source_ibm_kms_key_rings.go @@ -0,0 +1,95 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kms + +import ( + "context" + "fmt" + + //kp "github.com/IBM/keyprotect-go-client" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMKMSkeyRings() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMKMSKeyRingsRead, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "Key protect or hpcs instance GUID", + DiffSuppressFunc: suppressKMSInstanceIDDiff, + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "public or private", + Default: "public", + }, + "key_rings": { + Type: schema.TypeList, + Computed: true, + Description: "Key Rings for a particualer instance", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "creation_date": { + Type: schema.TypeString, + Computed: true, + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMKMSKeyRingsRead(d *schema.ResourceData, meta interface{}) error { + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + api, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + endpointType := d.Get("endpoint_type").(string) + keys, err := api.GetKeyRings(context.Background()) + if err != nil || keys == nil { + return fmt.Errorf("[ERROR] Get Key Rings failed with error: %s", err) + } + if keys == nil || keys.KeyRings == nil || len(keys.KeyRings) == 0 { + return fmt.Errorf("[ERROR] No key Rings in instance %s", instanceID) + } + + keyRingMap := make([]map[string]interface{}, 0, len(keys.KeyRings)) + + for _, keyRing := range keys.KeyRings { + keyInstance := make(map[string]interface{}) + + keyInstance["id"] = keyRing.ID + keyInstance["created_by"] = keyRing.CreatedBy + if keyRing.CreationDate != nil { + keyInstance["creation_date"] = keyRing.CreationDate.String() + } + keyRingMap = append(keyRingMap, keyInstance) + + } + + d.SetId(instanceID) + d.Set("key_rings", keyRingMap) + d.Set("instance_id", instanceID) + d.Set("endpoint_type", endpointType) + + return nil + +} diff --git a/ibm/data_source_ibm_kms_key_rings_test.go b/ibm/service/kms/data_source_ibm_kms_key_rings_test.go similarity index 87% rename from ibm/data_source_ibm_kms_key_rings_test.go rename to ibm/service/kms/data_source_ibm_kms_key_rings_test.go index 89b1a8027..03583fd48 100644 --- a/ibm/data_source_ibm_kms_key_rings_test.go +++ b/ibm/service/kms/data_source_ibm_kms_key_rings_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,13 +19,13 @@ func TestAccIBMKMSKeyRingDataSource_basic(t *testing.T) { keyRing := fmt.Sprintf("keyRing%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsKeyRingDataSourceConfig(instanceName, keyRing), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_kms_key_rings.test2", "key_ring_id", keyRing), + resource.TestCheckResourceAttr("data.ibm_kms_key_rings.test2", "key_rings.1.id", keyRing), ), }, }, diff --git a/ibm/data_source_ibm_kms_key_test.go b/ibm/service/kms/data_source_ibm_kms_key_test.go similarity index 89% rename from ibm/data_source_ibm_kms_key_test.go rename to ibm/service/kms/data_source_ibm_kms_key_test.go index 6bc3cda51..44298ba21 100644 --- a/ibm/data_source_ibm_kms_key_test.go +++ b/ibm/service/kms/data_source_ibm_kms_key_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMKMSKeyDataSource_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsKeyDataSourceConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -36,10 +38,10 @@ func TestAccIBMKMSKeyDataSource_Key(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsKeyDataSourceKeyConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_kms_key.test", "keys.0.name", keyName), @@ -56,11 +58,11 @@ func TestAccIBMKMSKeyDataSourceHPCS_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsKeyDataSourceHpcsConfig(hpcsInstanceID, keyName), + { + Config: testAccCheckIBMKmsKeyDataSourceHpcsConfig(acc.HpcsInstanceID, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), ), @@ -76,10 +78,10 @@ func TestAccIBMKmsDataSourceKeyPolicy_basic(t *testing.T) { interval_month := 3 enabled := false resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsDataSourceKeyPolicyConfig(instanceName, keyName, interval_month, enabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -150,7 +152,7 @@ func testAccCheckIBMKmsKeyDataSourceConfig(instanceName, keyName string) string `, instanceName, keyName) } -func testAccCheckIBMKmsKeyDataSourceHpcsConfig(hpcsInstanceID, KeyName string) string { +func testAccCheckIBMKmsKeyDataSourceHpcsConfig(hpcsInstanceID string, KeyName string) string { return fmt.Sprintf(` resource "ibm_kms_key" "test" { instance_id = "%s" @@ -163,7 +165,7 @@ func testAccCheckIBMKmsKeyDataSourceHpcsConfig(hpcsInstanceID, KeyName string) s key_name = "${ibm_kms_key.test.key_name}" } -`, hpcsInstanceID, KeyName) +`, acc.HpcsInstanceID, KeyName) } func testAccCheckIBMKmsDataSourceKeyPolicyConfig(instanceName, keyName string, interval_month int, enabled bool) string { diff --git a/ibm/data_source_ibm_kms_keys.go b/ibm/service/kms/data_source_ibm_kms_keys.go similarity index 82% rename from ibm/data_source_ibm_kms_keys.go rename to ibm/service/kms/data_source_ibm_kms_keys.go index 19586f138..557c26d01 100644 --- a/ibm/data_source_ibm_kms_keys.go +++ b/ibm/service/kms/data_source_ibm_kms_keys.go @@ -1,20 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms import ( "context" "fmt" "log" - "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" kp "github.com/IBM/keyprotect-go-client" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMKMSkeys() *schema.Resource { +func DataSourceIBMKMSkeys() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMKMSKeysRead, @@ -50,7 +50,7 @@ func dataSourceIBMKMSkeys() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateAllowedStringValue([]string{"public", "private"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), Description: "public or private", ForceNew: true, Default: "public", @@ -167,45 +167,17 @@ func dataSourceIBMKMSkeys() *schema.Resource { } func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyManagementAPI() + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + api, _, err := populateKPClient(d, meta, instanceID) if err != nil { return err } - - instanceID := d.Get("instance_id").(string) - CrnInstanceID := strings.Split(instanceID, ":") - if len(CrnInstanceID) > 3 { - instanceID = CrnInstanceID[len(CrnInstanceID)-3] - } - endpointType := d.Get("endpoint_type").(string) - - rsConClient, err := meta.(ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - resourceInstanceGet := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) - if err != nil || instanceData == nil { - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) - } - extensions := instanceData.Extensions - URL, err := KmsEndpointURL(api, endpointType, extensions) - if err != nil { - return err - } - api.URL = URL - - api.Config.InstanceID = instanceID var totalKeys []kp.Key if v, ok := d.GetOk("alias"); ok { aliasName := v.(string) key, err := api.GetKey(context.Background(), aliasName) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } keyMap := make([]map[string]interface{}, 0, 1) keyInstance := make(map[string]interface{}) @@ -221,8 +193,7 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { } else if v, ok := d.GetOk("key_id"); ok { key, err := api.GetKey(context.Background(), v.(string)) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } keyMap := make([]map[string]interface{}, 0, 1) keyInstance := make(map[string]interface{}) @@ -234,12 +205,12 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { keyInstance["key_ring_id"] = key.KeyRingID policies, err := api.GetPolicies(context.Background(), key.ID) if err != nil { - return fmt.Errorf("Failed to read policies: %s", err) + return fmt.Errorf("[ERROR] Failed to read policies: %s", err) } if len(policies) == 0 { log.Printf("No Policy Configurations read\n") } else { - keyInstance["policies"] = flattenKeyPolicies(policies) + keyInstance["policies"] = flex.FlattenKeyPolicies(policies) } keyMap = append(keyMap, keyInstance) @@ -259,8 +230,7 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { { keys, err := api.GetKeys(context.Background(), 0, offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } retreivedKeys := keys.Keys totalKeys = append(totalKeys, retreivedKeys...) @@ -272,8 +242,7 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { if (limitVal - offset) < pageSize { keys, err := api.GetKeys(context.Background(), (limitVal - offset), offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } retreivedKeys := keys.Keys totalKeys = append(totalKeys, retreivedKeys...) @@ -281,8 +250,7 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { } else { keys, err := api.GetKeys(context.Background(), pageSize, offset) if err != nil { - return fmt.Errorf( - "Get Keys failed with error: %s", err) + return fmt.Errorf("[ERROR] Get Keys failed with error: %s", err) } numOfKeysFetched := keys.Metadata.NumberOfKeys retreivedKeys := keys.Keys @@ -310,7 +278,7 @@ func dataSourceIBMKMSKeysRead(d *schema.ResourceData, meta interface{}) error { } if len(matchKeys) == 0 { - return fmt.Errorf("No keys with name %s in instance %s", keyName, instanceID) + return fmt.Errorf("[ERROR] No keys with name %s in instance %s", keyName, instanceID) } keyMap := make([]map[string]interface{}, 0, len(matchKeys)) diff --git a/ibm/data_source_ibm_kms_keys_test.go b/ibm/service/kms/data_source_ibm_kms_keys_test.go similarity index 90% rename from ibm/data_source_ibm_kms_keys_test.go rename to ibm/service/kms/data_source_ibm_kms_keys_test.go index 7128c63ca..6eb147aff 100644 --- a/ibm/data_source_ibm_kms_keys_test.go +++ b/ibm/service/kms/data_source_ibm_kms_keys_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMKMSDataSource_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsDataSourceConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -35,11 +37,11 @@ func TestAccIBMKMSHPCSDataSource_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsDataSourceHpcsConfig(hpcsInstanceID, keyName), + { + Config: testAccCheckIBMKmsDataSourceHpcsConfig(acc.HpcsInstanceID, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), ), @@ -54,10 +56,10 @@ func TestAccIBMKMSKeyDataSource_Keys(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsKeyDataSourceKeysConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_kms_key.test", "keys.0.name", keyName), @@ -76,10 +78,10 @@ func TestAccIBMKmsDataSourceKeysPolicy_basic(t *testing.T) { interval_month := 3 enabled := false resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsDataSourceKeysPolicyConfig(instanceName, keyName, interval_month, enabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -161,7 +163,7 @@ func testAccCheckIBMKmsDataSourceHpcsConfig(hpcsInstanceID, KeyName string) stri instance_id = "${ibm_kms_key.test.instance_id}" } -`, hpcsInstanceID, KeyName) +`, acc.HpcsInstanceID, KeyName) } func testAccCheckIBMKmsDataSourceKeysPolicyConfig(instanceName, keyName string, interval_month int, enabled bool) string { diff --git a/ibm/data_source_ibm_kp_key.go b/ibm/service/kms/data_source_ibm_kp_key.go similarity index 93% rename from ibm/data_source_ibm_kp_key.go rename to ibm/service/kms/data_source_ibm_kp_key.go index 70b8b9615..27385da12 100644 --- a/ibm/data_source_ibm_kp_key.go +++ b/ibm/service/kms/data_source_ibm_kp_key.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" kp "github.com/IBM/keyprotect-go-client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMkey() *schema.Resource { +func DataSourceIBMkey() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMKeyRead, @@ -54,7 +55,7 @@ func dataSourceIBMkey() *schema.Resource { } func dataSourceIBMKeyRead(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyProtectAPI() + api, err := meta.(conns.ClientSession).KeyProtectAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_kp_key_test.go b/ibm/service/kms/data_source_ibm_kp_key_test.go similarity index 88% rename from ibm/data_source_ibm_kp_key_test.go rename to ibm/service/kms/data_source_ibm_kp_key_test.go index 175892a16..934117788 100644 --- a/ibm/data_source_ibm_kp_key_test.go +++ b/ibm/service/kms/data_source_ibm_kp_key_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +18,10 @@ func TestAccIBMKpDataSource_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKpDataSourceConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kp_key.test", "key_name", keyName), diff --git a/ibm/service/kms/resource_ibm_kms_key.go b/ibm/service/kms/resource_ibm_kms_key.go new file mode 100644 index 000000000..29d4336e3 --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key.go @@ -0,0 +1,417 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kms + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + kp "github.com/IBM/keyprotect-go-client" + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func suppressKMSInstanceIDDiff(k, old, new string, d *schema.ResourceData) bool { + // TF currently uses GUID. So just check when instance crn is passed as input it has same GUID in it. + return old == getInstanceIDFromCRN(new) +} + +// Get Instance ID from CRN +func getInstanceIDFromCRN(crn string) string { + crnSegments := strings.Split(crn, ":") + if len(crnSegments) > 3 { + return crnSegments[len(crnSegments)-3] + } + return crn +} + +func ResourceIBMKmskey() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMKmsKeyCreate, + Read: resourceIBMKmsKeyRead, + Update: resourceIBMKmsKeyUpdate, + Delete: resourceIBMKmsKeyDelete, + Exists: resourceIBMKmsKeyExists, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Key protect or hpcs instance GUID or CRN", + DiffSuppressFunc: suppressKMSInstanceIDDiff, + }, + "key_ring_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "default", + Description: "Key Ring for the Key", + }, + "key_id": { + Type: schema.TypeString, + Computed: true, + Description: "Key ID", + }, + "key_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Key name", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "type of service hs-crypto or kms", + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "public or private", + ForceNew: true, + }, + "standard_key": { + Type: schema.TypeBool, + Default: false, + Optional: true, + ForceNew: true, + Description: "Standard key type", + }, + "payload": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "encrypted_nonce": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Only for imported root key", + }, + "iv_value": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Only for imported root key", + }, + "force_delete": { + Type: schema.TypeBool, + Optional: true, + Description: "set to true to force delete the key", + ForceNew: false, + Default: false, + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Crn of the key", + }, + "expiration_date": { + Type: schema.TypeString, + Optional: true, + Description: "The date the key material expires. The date format follows RFC 3339. You can set an expiration date on any key on its creation. A key moves into the Deactivated state within one hour past its expiration date, if one is assigned. If you create a key without specifying an expiration date, the key does not expire", + ForceNew: true, + }, + "instance_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Key protect or hpcs instance CRN", + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} + +func resourceIBMKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + + kpAPI.Config.KeyRing = d.Get("key_ring_id").(string) + + name := d.Get("key_name").(string) + standardKey := d.Get("standard_key").(bool) + + var expiration *time.Time + if es, ok := d.GetOk("expiration_date"); ok { + expiration_string := es.(string) + // parse string to required time format + expiration_time, err := time.Parse(time.RFC3339, expiration_string) + if err != nil { + return fmt.Errorf("[ERROR] Invalid time format (the date format follows RFC 3339): %s", err) + } + expiration = &expiration_time + } else { + expiration = nil + } + + var keyCRN string + if standardKey { + if v, ok := d.GetOk("payload"); ok { + //import standard key + payload := v.(string) + stkey, err := kpAPI.CreateImportedStandardKey(context.Background(), name, expiration, payload) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating standard key with payload: %s", err) + } + keyCRN = stkey.CRN + d.SetId(keyCRN) + + } else { + //create standard key + stkey, err := kpAPI.CreateStandardKey(context.Background(), name, expiration) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating standard key: %s", err) + } + keyCRN = stkey.CRN + d.SetId(keyCRN) + + } + } else { + if v, ok := d.GetOk("payload"); ok { + payload := v.(string) + encryptedNonce := d.Get("encrypted_nonce").(string) + iv := d.Get("iv_value").(string) + stkey, err := kpAPI.CreateImportedRootKey(context.Background(), name, expiration, payload, encryptedNonce, iv) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating Root key with payload: %s", err) + } + keyCRN = stkey.CRN + d.SetId(keyCRN) + + } else { + stkey, err := kpAPI.CreateRootKey(context.Background(), name, expiration) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating Root key: %s", err) + } + keyCRN = stkey.CRN + d.SetId(keyCRN) + } + } + return resourceIBMKmsKeyUpdate(d, meta) +} + +func resourceIBMKmsKeyRead(d *schema.ResourceData, meta interface{}) error { + instanceCRN, instanceID, keyid := getInstanceAndKeyDataFromCRN(d.Id()) + + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + // keyid := d.Id() + key, err := kpAPI.GetKey(context.Background(), keyid) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 || kpError.StatusCode == 409 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Get Key failed with error while reading Key: %s", err) + } else if key.State == 5 { //Refers to Deleted state of the Key + d.SetId("") + return nil + } + + err = setKeyDetails(d, meta, instanceID, instanceCRN, key, kpAPI) + if err != nil { + return err + } + + return nil + +} + +func resourceIBMKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error { + + if d.HasChange("force_delete") { + d.Set("force_delete", d.Get("force_delete").(bool)) + } + return resourceIBMKmsKeyRead(d, meta) + +} + +func resourceIBMKmsKeyDelete(d *schema.ResourceData, meta interface{}) error { + _, instanceID, keyid := getInstanceAndKeyDataFromCRN(d.Id()) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + + force := d.Get("force_delete").(bool) + f := kp.ForceOpt{ + Force: force, + } + + _, err1 := kpAPI.DeleteKey(context.Background(), keyid, kp.ReturnRepresentation, f) + if err1 != nil { + return fmt.Errorf("[ERROR] Error while deleting: %s", err1) + } + d.SetId("") + return nil + +} + +func resourceIBMKmsKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + _, instanceID, keyid := getInstanceAndKeyDataFromCRN(d.Id()) + + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return false, err + } + + _, err = kpAPI.GetKey(context.Background(), keyid) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 { + return false, nil + } + return false, err + } + return true, nil + +} + +// Populate KP Client using info from schema +func populateKPClient(d *schema.ResourceData, meta interface{}, instanceID string) (kpAPI *kp.Client, instanceCRN *string, err error) { + kpAPI, err = meta.(conns.ClientSession).KeyManagementAPI() + if err != nil { + return nil, nil, err + } + + endpointType := d.Get("endpoint_type").(string) + + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return nil, nil, err + } + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil || instanceData == nil { + return nil, nil, fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) + } + extensions := instanceData.Extensions + kpAPI.URL, err = KmsEndpointURL(kpAPI, endpointType, extensions) + if err != nil { + return nil, nil, err + } + + kpAPI.Config.InstanceID = instanceID + return kpAPI, instanceData.CRN, nil +} + +// Set Key Details in the schema +func setKeyDetails(d *schema.ResourceData, meta interface{}, instanceID string, instanceCRN string, key *kp.Key, kpAPI *kp.Client) error { + d.Set("instance_id", instanceID) + d.Set("instance_crn", instanceCRN) + d.Set("key_id", key.ID) + d.Set("standard_key", key.Extractable) + d.Set("payload", key.Payload) + d.Set("encrypted_nonce", key.EncryptedNonce) + d.Set("iv_value", key.IV) + d.Set("key_name", key.Name) + d.Set("crn", key.CRN) + if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { + d.Set("endpoint_type", "private") + } else { + d.Set("endpoint_type", "public") + } + d.Set("type", strings.Split(d.Id(), ":")[4]) + if d.Get("force_delete") != nil { + d.Set("force_delete", d.Get("force_delete").(bool)) + } + d.Set("key_ring_id", key.KeyRingID) + if key.Expiration != nil { + expiration := key.Expiration + d.Set("expiration_date", expiration.Format(time.RFC3339)) + } else { + d.Set("expiration_date", "") + } + d.Set(flex.ResourceName, key.Name) + d.Set(flex.ResourceCRN, key.CRN) + state := key.State + d.Set(flex.ResourceStatus, strconv.Itoa(state)) + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + id := key.ID + crn1 := strings.TrimSuffix(key.CRN, ":key:"+id) + + d.Set(flex.ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") + + return nil +} + +// Extract Instance and Key related info from crn +func getInstanceAndKeyDataFromCRN(crn string) (instanceCRN string, instanceID string, keyID string) { + crnData := strings.Split(crn, ":") + instanceCRN = fmt.Sprintf("%s::", strings.Split(crn, ":key:")[0]) + keyID = crnData[len(crnData)-1] + instanceID = crnData[len(crnData)-3] + return instanceCRN, instanceID, keyID +} + +// Construct KMS URL +func KmsEndpointURL(kpAPI *kp.Client, endpointType string, extensions map[string]interface{}) (*url.URL, error) { + + exturl := extensions["endpoints"].(map[string]interface{})["public"] + if endpointType == "private" || strings.Contains(kpAPI.Config.BaseURL, "private") { + exturl = extensions["endpoints"].(map[string]interface{})["private"] + } + endpointURL := fmt.Sprintf("%s/api/v2/keys", exturl.(string)) + + url1 := conns.EnvFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, endpointURL) + u, err := url.Parse(url1) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error Parsing KMS EndpointURL") + } + return u, nil +} diff --git a/ibm/service/kms/resource_ibm_kms_key_alias.go b/ibm/service/kms/resource_ibm_kms_key_alias.go new file mode 100644 index 000000000..6cd7b7856 --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key_alias.go @@ -0,0 +1,140 @@ +package kms + +import ( + "context" + "fmt" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + kp "github.com/IBM/keyprotect-go-client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMKmskeyAlias() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMKmsKeyAliasCreate, + Delete: resourceIBMKmsKeyAliasDelete, + Read: resourceIBMKmsKeyAliasRead, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "Key ID", + ForceNew: true, + DiffSuppressFunc: suppressKMSInstanceIDDiff, + }, + "alias": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Key protect or hpcs key alias name", + }, + "key_id": { + Type: schema.TypeString, + Optional: true, + Description: "Key ID", + ForceNew: true, + ExactlyOneOf: []string{"key_id", "existing_alias"}, + }, + "existing_alias": { + Type: schema.TypeString, + Optional: true, + Description: "Existing Alias of the Key", + ForceNew: true, + ExactlyOneOf: []string{"key_id", "existing_alias"}, + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "public or private", + ForceNew: true, + }, + }, + } +} + +func resourceIBMKmsKeyAliasCreate(d *schema.ResourceData, meta interface{}) error { + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + + aliasName := d.Get("alias").(string) + var id string + if v, ok := d.GetOk("key_id"); ok { + id = v.(string) + d.Set("key_id", id) + } + if v, ok := d.GetOk("existing_alias"); ok { + id = v.(string) + } + stkey, err := kpAPI.CreateKeyAlias(context.Background(), aliasName, id) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating alias name for the key: %s", err) + } + key, err := kpAPI.GetKey(context.Background(), stkey.KeyID) + if err != nil { + return fmt.Errorf("[ERROR] Get Key failed with error: %s", err) + } + d.SetId(fmt.Sprintf("%s:alias:%s", stkey.Alias, key.CRN)) + + return resourceIBMKmsKeyAliasRead(d, meta) +} + +func resourceIBMKmsKeyAliasRead(d *schema.ResourceData, meta interface{}) error { + id := strings.Split(d.Id(), ":alias:") + if len(id) < 2 { + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of keyAlias:alias:keyCRN", d.Id()) + } + _, instanceID, keyid := getInstanceAndKeyDataFromCRN(id[1]) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + key, err := kpAPI.GetKey(context.Background(), keyid) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 || kpError.StatusCode == 409 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Get Key failed with error while reading policies: %s", err) + } else if key.State == 5 { //Refers to Deleted state of the Key + d.SetId("") + return nil + } + d.Set("alias", id[0]) + d.Set("key_id", key.ID) + d.Set("instance_id", instanceID) + if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { + d.Set("endpoint_type", "private") + } else { + d.Set("endpoint_type", "public") + } + + return nil +} + +func resourceIBMKmsKeyAliasDelete(d *schema.ResourceData, meta interface{}) error { + id := strings.Split(d.Id(), ":alias:") + _, instanceID, keyid := getInstanceAndKeyDataFromCRN(id[1]) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + err1 := kpAPI.DeleteKeyAlias(context.Background(), id[0], keyid) + if err1 != nil { + kpError := err1.(*kp.Error) + if kpError.StatusCode == 404 { + return nil + } else { + return fmt.Errorf(" failed to Destroy alias with error: %s", err1) + } + } + return nil +} diff --git a/ibm/resource_ibm_kms_key_alias_test.go b/ibm/service/kms/resource_ibm_kms_key_alias_test.go similarity index 75% rename from ibm/resource_ibm_kms_key_alias_test.go rename to ibm/service/kms/resource_ibm_kms_key_alias_test.go index 31c7bf8ae..6bb751502 100644 --- a/ibm/resource_ibm_kms_key_alias_test.go +++ b/ibm/service/kms/resource_ibm_kms_key_alias_test.go @@ -1,10 +1,12 @@ -package ibm +package kms_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +19,10 @@ func TestAccIBMKMSResource_Key_Alias_Name(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasConfig(instanceName, keyName, aliasName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), @@ -39,10 +41,10 @@ func TestAccIBMKMSResource_Key_Alias_Key(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasDuplicateConfig(instanceName, keyName, aliasName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -53,27 +55,29 @@ func TestAccIBMKMSResource_Key_Alias_Key(t *testing.T) { }) } -func TestAccIBMKMSResource_Key_Alias_Key_Duplicacy(t *testing.T) { - instanceName := fmt.Sprintf("tf_kms_%d", acctest.RandIntRange(10, 100)) - // cosInstanceName := fmt.Sprintf("cos_%d", acctest.RandIntRange(10, 100)) - // bucketName := fmt.Sprintf("bucket-test77") - aliasName := fmt.Sprintf("alias_%d", acctest.RandIntRange(10, 100)) - keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) +// TODO: The following test case needs more debugging - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMKmsResourceAliasDuplicateConfig(instanceName, keyName, aliasName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), - resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), - ), - }, - }, - }) -} +// func TestAccIBMKMSResource_Key_Alias_Key_Duplicacy(t *testing.T) { +// instanceName := fmt.Sprintf("tf_kms_%d", acctest.RandIntRange(10, 100)) +// // cosInstanceName := fmt.Sprintf("cos_%d", acctest.RandIntRange(10, 100)) +// // bucketName := fmt.Sprintf("bucket-test77") +// aliasName := fmt.Sprintf("alias_%d", acctest.RandIntRange(10, 100)) +// keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + +// resource.Test(t, resource.TestCase{ +// PreCheck: func() { acc.TestAccPreCheck(t) }, +// Providers: acc.TestAccProviders, +// Steps: []resource.TestStep{ +// { +// Config: testAccCheckIBMKmsResourceAliasDuplicateConfig(instanceName, keyName, aliasName), +// Check: resource.ComposeTestCheckFunc( +// resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), +// resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), +// ), +// }, +// }, +// }) +// } func TestAccIBMKMSResource_Key_Alias_Key_Check(t *testing.T) { instanceName := fmt.Sprintf("tf_kms_%d", acctest.RandIntRange(10, 100)) @@ -85,30 +89,40 @@ func TestAccIBMKMSResource_Key_Alias_Key_Check(t *testing.T) { keyName2 := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasTwo(instanceName, keyName, aliasName, aliasName2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), ), }, - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasOne(instanceName, keyName, aliasName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), ), }, - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasOne(instanceName, keyName2, aliasName2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName2), resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName2), ), }, + // TODO: The following test case needs more debugging + // { + // Config: testAccCheckIBMKmsResourceAliasWithExistingAlias(instanceName, keyName, aliasName, aliasName2), + // Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + // resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias", "alias", aliasName), + // resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias2", "existing_alias", aliasName), + // resource.TestCheckResourceAttr("ibm_kms_key_alias.testAlias2", "alias", aliasName2), + // ), + // }, }, }) } @@ -126,10 +140,10 @@ func TestAccIBMKMSResource_Key_Alias_Key_Limit(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceAliasLimitConfig(instanceName, keyName, aliasName, aliasName2, aliasName3, aliasName4, aliasName5, aliasName6), ExpectError: regexp.MustCompile("(KEY_ALIAS_QUOTA_ERR)"), }, @@ -184,7 +198,7 @@ func testAccCheckIBMKmsResourceAliasDuplicateConfig(instanceName, KeyName, alias } resource "ibm_kms_key_alias" "testAlias2" { instance_id = "${ibm_resource_instance.kms_instance.guid}" - alias = "${ibm_kms_key_alias.testAlias2.alias}" + alias = ibm_kms_key_alias.testAlias.alias key_id = "${ibm_kms_key.test.key_id}" } @@ -219,6 +233,34 @@ func testAccCheckIBMKmsResourceAliasTwo(instanceName, KeyName, aliasName, aliasN `, instanceName, KeyName, aliasName, aliasName2) } +func testAccCheckIBMKmsResourceAliasWithExistingAlias(instanceName, KeyName, aliasName, aliasName2 string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kms_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "ibm_kms_key" "test" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + key_name = "%s" + standard_key = true + force_delete = true + } + resource "ibm_kms_key_alias" "testAlias" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + alias = "%s" + key_id = "${ibm_kms_key.test.key_id}" + } + resource "ibm_kms_key_alias" "testAlias2" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + alias = "%s" + existing_alias = "${ibm_kms_key_alias.testAlias.alias}" + } + +`, instanceName, KeyName, aliasName, aliasName2) +} + func testAccCheckIBMKmsResourceAliasOne(instanceName, KeyName, aliasName string) string { return fmt.Sprintf(` resource "ibm_resource_instance" "kms_instance" { diff --git a/ibm/service/kms/resource_ibm_kms_key_policies.go b/ibm/service/kms/resource_ibm_kms_key_policies.go new file mode 100644 index 000000000..660822a39 --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key_policies.go @@ -0,0 +1,328 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kms + +import ( + "context" + "fmt" + "log" + "net/url" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + kp "github.com/IBM/keyprotect-go-client" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMKmskeyPolicies() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMKmsKeyPolicyCreate, + ReadContext: resourceIBMKmsKeyPolicyRead, + UpdateContext: resourceIBMKmsKeyPolicyUpdate, + DeleteContext: resourceIBMKmsKeyPolicyDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Key protect or hpcs instance GUID", + DiffSuppressFunc: suppressKMSInstanceIDDiff, + }, + "key_id": { + Type: schema.TypeString, + Optional: true, + Description: "Key ID", + ExactlyOneOf: []string{"key_id", "alias"}, + }, + "alias": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"key_id", "alias"}, + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "public or private", + ForceNew: true, + Default: "public", + }, + "rotation": { + Type: schema.TypeList, + Optional: true, + Computed: true, + AtLeastOneOf: []string{"rotation", "dual_auth_delete"}, + Description: "Specifies the key rotation time interval in months, with a minimum of 1, and a maximum of 12", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the resource that created the policy.", + }, + "creation_date": { + Type: schema.TypeString, + Computed: true, + Description: "The date the policy was created. The date format follows RFC 3339.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the resource that updated the policy.", + }, + "last_update_date": { + Type: schema.TypeString, + Computed: true, + Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + }, + "interval_month": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(1, 12), + Description: "Specifies the key rotation time interval in months", + }, + }, + }, + }, + "dual_auth_delete": { + Type: schema.TypeList, + Optional: true, + Computed: true, + AtLeastOneOf: []string{"rotation", "dual_auth_delete"}, + Description: "Data associated with the dual authorization delete policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the resource that created the policy.", + }, + "creation_date": { + Type: schema.TypeString, + Computed: true, + Description: "The date the policy was created. The date format follows RFC 3339.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the resource that updated the policy.", + }, + "last_update_date": { + Type: schema.TypeString, + Computed: true, + Description: "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + }, + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "If set to true, Key Protect enables a dual authorization policy on a single key.", + }, + }, + }, + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + }, + } +} +func resourceIBMKmsKeyPolicyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + var id string + if v, ok := d.GetOk("key_id"); ok { + id = v.(string) + // d.Set("key_id", id) + } + if v, ok := d.GetOk("alias"); ok { + id = v.(string) + } + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return diag.FromErr(err) + } + key, err := kpAPI.GetKey(context, id) + if err != nil { + return diag.Errorf("Get Key failed with error while creating policies: %s", err) + } + err = resourceHandlePolicies(context, d, kpAPI, meta, id) + if err != nil { + return diag.Errorf("Could not create policies: %s", err) + } + d.SetId(key.CRN) + return resourceIBMKmsKeyPolicyRead(context, d, meta) +} + +func resourceIBMKmsKeyPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + _, instanceID, keyid := getInstanceAndKeyDataFromCRN(d.Id()) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return diag.FromErr(err) + } + key, err := kpAPI.GetKey(context, keyid) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 || kpError.StatusCode == 409 { + d.SetId("") + return nil + } + return diag.Errorf("Get Key failed with error while reading policies: %s", err) + } else if key.State == 5 { //Refers to Deleted state of the Key + d.SetId("") + return nil + } + + d.Set("instance_id", instanceID) + d.Set("key_id", keyid) + if strings.Contains((kpAPI.URL).String(), "private") { + d.Set("endpoint_type", "private") + } else { + d.Set("endpoint_type", "public") + } + d.Set(flex.ResourceName, key.Name) + d.Set(flex.ResourceCRN, key.CRN) + state := key.State + d.Set(flex.ResourceStatus, strconv.Itoa(state)) + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return diag.FromErr(err) + } + id := key.ID + crn1 := strings.TrimSuffix(key.CRN, ":key:"+id) + + d.Set(flex.ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") + + policies, err := kpAPI.GetPolicies(context, keyid) + + if err != nil { + return diag.Errorf("Failed to read policies: %s", err) + } + if len(policies) == 0 { + log.Printf("No Policy Configurations read\n") + } else { + d.Set("rotation", flex.FlattenKeyIndividualPolicy("rotation", policies)) + d.Set("dual_auth_delete", flex.FlattenKeyIndividualPolicy("dual_auth_delete", policies)) + } + + return nil + +} + +func resourceIBMKmsKeyPolicyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + if d.HasChange("rotation") || d.HasChange("dual_auth_delete") { + + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return diag.FromErr(err) + } + _, _, key_id := getInstanceAndKeyDataFromCRN(d.Id()) + + err = resourceHandlePolicies(context, d, kpAPI, meta, key_id) + if err != nil { + return diag.Errorf("Could not create policies: %s", err) + } + } + return resourceIBMKmsKeyPolicyRead(context, d, meta) + +} + +func resourceIBMKmsKeyPolicyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + //Do not support delete Policies + log.Println("Warning: `terraform destroy` does not remove the policies of the Key but only clears the state file. Key Policies get deleted when the associated key resource is destroyed.") + d.SetId("") + return nil + +} + +func resourceHandlePolicies(context context.Context, d *schema.ResourceData, kpAPI *kp.Client, meta interface{}, key_id string) error { + var setRotation, setDualAuthDelete, dualAuthEnable bool + var rotationInterval int + + policy := getPolicyFromSchema(d) + + if policy.Rotation != nil { + setRotation = true + rotationInterval = policy.Rotation.Interval + } + if policy.DualAuth != nil { + setDualAuthDelete = true + dualAuthEnable = *policy.DualAuth.Enabled + } + _, err := kpAPI.SetPolicies(context, key_id, setRotation, rotationInterval, setDualAuthDelete, dualAuthEnable) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating policies: %s", err) + } + return nil +} + +func getPolicyFromSchema(d *schema.ResourceData) kp.Policy { + var policy kp.Policy + if rotationPolicyInfo, ok := d.GetOk("rotation"); ok { + rotationPolicyList := rotationPolicyInfo.([]interface{}) + if len(rotationPolicyList) != 0 { + rotationPolicyMap := rotationPolicyList[0].(map[string]interface{}) + policy.Rotation = &kp.Rotation{ + Interval: rotationPolicyMap["interval_month"].(int), + } + } + } + if dualAuthPolicyInfo, ok := d.GetOk("dual_auth_delete"); ok { + dualAuthPolicyList := dualAuthPolicyInfo.([]interface{}) + if len(dualAuthPolicyList) != 0 { + enabled := dualAuthPolicyList[0].(map[string]interface{})["enabled"].(bool) + policy.DualAuth = &kp.DualAuth{ + Enabled: &enabled, + } + } + } + return policy +} diff --git a/ibm/service/kms/resource_ibm_kms_key_policies_test.go b/ibm/service/kms/resource_ibm_kms_key_policies_test.go new file mode 100644 index 000000000..80738deaa --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key_policies_test.go @@ -0,0 +1,226 @@ +package kms_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMKMSKeyPolicy_basic_check(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + rotation_interval := 3 + dual_auth_delete := false + rotation_interval_new := 5 + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, keyName, rotation_interval, dual_auth_delete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "rotation.0.interval_month", "3"), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "dual_auth_delete.0.enabled", "false"), + ), + }, + { + Config: testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, keyName, rotation_interval_new, dual_auth_delete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "rotation.0.interval_month", "5"), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "dual_auth_delete.0.enabled", "false"), + ), + }, + }, + }) +} + +func TestAccIBMKMSKeyPolicy_rotation_check(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + rotation_interval := 3 + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsKeyPolicyRotationCheck(instanceName, keyName, rotation_interval), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "rotation.0.interval_month", "3"), + ), + }, + }, + }) +} + +func TestAccIBMKMSKeyPolicy_dualAuth_check(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + dual_auth_delete := false + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsKeyPolicyDualAuthCheck(instanceName, keyName, dual_auth_delete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "dual_auth_delete.0.enabled", "false"), + ), + }, + }, + }) +} + +func TestAccIBMKMSKeyPolicy_dualAuth_check_with_Alias(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + aliasName := fmt.Sprintf("alias_%d", acctest.RandIntRange(10, 100)) + dual_auth_delete := false + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsKeyPolicyDualAuthCheckWithAlias(instanceName, keyName, aliasName, dual_auth_delete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key_alias.alias_test", "alias", aliasName), + resource.TestCheckResourceAttr("ibm_kms_key_policies.Policy", "dual_auth_delete.0.enabled", "false"), + ), + }, + }, + }) +} + +// This test is invalid as ibm_kms_key does not support policies anymore + +// func TestAccIBMKMSKeyPolicy_invalid_interval_check(t *testing.T) { +// instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) +// keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) +// rotation_interval := 13 +// dual_auth_delete := false +// resource.Test(t, resource.TestCase{ +// PreCheck: func() { acc.TestAccPreCheck(t) }, +// Providers: acc.TestAccProviders, +// Steps: []resource.TestStep{ +// { +// Config: testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, keyName, rotation_interval, dual_auth_delete), +// ExpectError: regexp.MustCompile("must contain a valid int value should be in range(1, 12)"), +// }, +// }, +// }) +// } + +func testAccCheckIBMKmsKeyPolicyStandardConfigCheck(instanceName, KeyName string, rotation_interval int, dual_auth_delete bool) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kp_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kp_instance.guid + key_name = "%s" + standard_key = false + } + resource "ibm_kms_key_policies" "Policy" { + instance_id = ibm_resource_instance.kp_instance.guid + key_id = ibm_kms_key.test.key_id + rotation { + interval_month = %d + } + dual_auth_delete { + enabled = %t + } + } +`, instanceName, KeyName, rotation_interval, dual_auth_delete) +} + +func testAccCheckIBMKmsKeyPolicyDualAuthCheck(instanceName, KeyName string, dual_auth_delete bool) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kp_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kp_instance.guid + key_name = "%s" + standard_key = false + } + resource "ibm_kms_key_policies" "Policy" { + instance_id = ibm_resource_instance.kp_instance.guid + key_id = ibm_kms_key.test.key_id + dual_auth_delete { + enabled = %t + } + } +`, instanceName, KeyName, dual_auth_delete) +} + +func testAccCheckIBMKmsKeyPolicyDualAuthCheckWithAlias(instanceName, KeyName string, alias string, dual_auth_delete bool) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kp_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kp_instance.guid + key_name = "%s" + standard_key = false + } + + resource "ibm_kms_key_alias" "alias_test" { + instance_id = ibm_resource_instance.kp_instance.guid + alias = "%s" + key_id = ibm_kms_key.test.key_id + } + + resource "ibm_kms_key_policies" "Policy" { + instance_id = ibm_resource_instance.kp_instance.guid + alias = ibm_kms_key_alias.alias_test.alias + dual_auth_delete { + enabled = %t + } + } +`, instanceName, KeyName, alias, dual_auth_delete) +} + +func testAccCheckIBMKmsKeyPolicyRotationCheck(instanceName, KeyName string, rotation_interval int) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kp_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + + resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kp_instance.guid + key_name = "%s" + standard_key = false + } + resource "ibm_kms_key_policies" "Policy" { + instance_id = ibm_resource_instance.kp_instance.guid + key_id = ibm_kms_key.test.key_id + rotation { + interval_month = %d + } + } + +`, instanceName, KeyName, rotation_interval) +} diff --git a/ibm/service/kms/resource_ibm_kms_key_rings.go b/ibm/service/kms/resource_ibm_kms_key_rings.go new file mode 100644 index 000000000..e152afbc3 --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key_rings.go @@ -0,0 +1,145 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kms + +import ( + "context" + "fmt" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + kp "github.com/IBM/keyprotect-go-client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMKmskeyRings() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMKmsKeyRingCreate, + Delete: resourceIBMKmsKeyRingDelete, + Read: resourceIBMKmsKeyRingRead, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "Key protect Instance GUID", + ForceNew: true, + DiffSuppressFunc: suppressKMSInstanceIDDiff, + }, + "key_ring_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "User defined unique ID for the key ring", + ValidateFunc: validate.InvokeValidator("ibm_kms_key_rings", "key_ring_id"), + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "public or private", + ForceNew: true, + }, + }, + } +} + +func ResourceIBMKeyRingValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "key_ring_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-]*$`, + MinValueLength: 2, + MaxValueLength: 100}) + + ibmKeyRingResourceValidator := validate.ResourceValidator{ResourceName: "ibm_kms_key_rings", Schema: validateSchema} + return &ibmKeyRingResourceValidator +} + +func resourceIBMKmsKeyRingCreate(d *schema.ResourceData, meta interface{}) error { + instanceID := getInstanceIDFromCRN(d.Get("instance_id").(string)) + keyRingID := d.Get("key_ring_id").(string) + kpAPI, instanceCRN, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + + err = kpAPI.CreateKeyRing(context.Background(), keyRingID) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating key ring : %s", err) + } + var keyRing string + keyRings, err := kpAPI.GetKeyRings(context.Background()) + if err != nil { + return fmt.Errorf("[ERROR] Error while fetching key ring : %s", err) + } + for _, v := range keyRings.KeyRings { + if v.ID == keyRingID { + keyRing = v.ID + break + } + } + + d.SetId(fmt.Sprintf("%s:keyRing:%s", keyRing, *instanceCRN)) + + return resourceIBMKmsKeyRingRead(d, meta) +} + +func resourceIBMKmsKeyRingRead(d *schema.ResourceData, meta interface{}) error { + id := strings.Split(d.Id(), ":keyRing:") + if len(id) < 2 { + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of keyRingID:keyRing:InstanceCRN", d.Id()) + } + instanceID := getInstanceIDFromCRN(id[1]) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + _, err = kpAPI.GetKeyRings(context.Background()) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 || kpError.StatusCode == 409 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Get Key Rings failed with error: %s", err) + } + + d.Set("instance_id", instanceID) + if strings.Contains((kpAPI.URL).String(), "private") || strings.Contains(kpAPI.Config.BaseURL, "private") { + d.Set("endpoint_type", "private") + } else { + d.Set("endpoint_type", "public") + } + d.Set("key_ring_id", id[0]) + return nil +} + +func resourceIBMKmsKeyRingDelete(d *schema.ResourceData, meta interface{}) error { + id := strings.Split(d.Id(), ":keyRing:") + instanceID := getInstanceIDFromCRN(id[1]) + kpAPI, _, err := populateKPClient(d, meta, instanceID) + if err != nil { + return err + } + err = kpAPI.DeleteKeyRing(context.Background(), id[0]) + if err != nil { + kpError := err.(*kp.Error) + if kpError.StatusCode == 404 || kpError.StatusCode == 409 { + return nil + } else { + return fmt.Errorf(" failed to Destroy key ring with error: %s", err) + } + } + return nil + +} diff --git a/ibm/resource_ibm_kms_key_rings_test.go b/ibm/service/kms/resource_ibm_kms_key_rings_test.go similarity index 89% rename from ibm/resource_ibm_kms_key_rings_test.go rename to ibm/service/kms/resource_ibm_kms_key_rings_test.go index 1778c2eaa..d871144c4 100644 --- a/ibm/resource_ibm_kms_key_rings_test.go +++ b/ibm/service/kms/resource_ibm_kms_key_rings_test.go @@ -1,10 +1,12 @@ -package ibm +package kms_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ func TestAccIBMKMSResource_Key_Ring_Name(t *testing.T) { keyRing := fmt.Sprintf("keyRing%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceKeyRingConfig(instanceName, keyRing), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key_rings.test", "key_ring_id", keyRing), @@ -33,10 +35,10 @@ func TestAccIBMKMSResource_Key_Ring_Key(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceKeyRingKeyConfig(instanceName, keyRing, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), @@ -53,10 +55,10 @@ func TestAccIBMKMSResource_Key_Ring_Not_Exist(t *testing.T) { keyRing := fmt.Sprintf("keyRing%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKmsResourceKeyRingExistConfig(instanceName, keyName, keyRing), ExpectError: regexp.MustCompile("KEY_RING_NOT_FOUND_ERR:"), }, @@ -94,7 +96,7 @@ func testAccCheckIBMKmsResourceKeyRingKeyConfig(instanceName, keyRing, keyName s resource "ibm_kms_key" "test" { instance_id = ibm_resource_instance.kms_instance.guid key_name = "%s" - key_ring_id = ibm_kms_key_rings.key_ring.key_ring_id} + key_ring_id = ibm_kms_key_rings.key_ring.key_ring_id standard_key = true force_delete = true } diff --git a/ibm/service/kms/resource_ibm_kms_key_test.go b/ibm/service/kms/resource_ibm_kms_key_test.go new file mode 100644 index 000000000..856719dde --- /dev/null +++ b/ibm/service/kms/resource_ibm_kms_key_test.go @@ -0,0 +1,330 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kms_test + +import ( + "fmt" + "math/rand" + "regexp" + "testing" + + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMKMSResource_basic(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + cosInstanceName := fmt.Sprintf("cos_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("bucket_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + payload := "LqMWNtSi3Snr4gFNO0PsFFLFRNs57mSXCQE7O2oE+g0=" + resourceName := "ibm_kms_key" + standard_key := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsResourceConfig(instanceName, resourceName, keyName, standard_key), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + ), + }, + { + Config: testAccCheckIBMKmsResourceImportStandardConfig(instanceName, resourceName, keyName, payload), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + ), + }, + { + Config: testAccCheckIBMKmsResourceRootkeyWithCOSConfig(instanceName, resourceName, keyName, cosInstanceName, bucketName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + ), + }, + }, + }) +} +func TestAccIBMKMSHPCSResource_basic(t *testing.T) { + t.Skip() + hpcskeyName := fmt.Sprintf("hpcs_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsResourceHpcsConfig(acc.HpcsInstanceID, hpcskeyName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.hpcstest", "key_name", hpcskeyName), + ), + }, + }, + }) +} + +// Test for valid expiration date for create key operation +func TestAccIBMKMSResource_ValidExpDate(t *testing.T) { + + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + + hours := time.Duration(rand.Intn(24) + 1) + mins := time.Duration(rand.Intn(60) + 1) + sec := time.Duration(rand.Intn(60) + 1) + loc, _ := time.LoadLocation("UTC") + expirationDateValid := ((time.Now().In(loc).Add(time.Hour*hours + time.Minute*mins + time.Second*sec)).Format(time.RFC3339)) + resourceName := "ibm_kms_key" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, resourceName, keyName, expirationDateValid), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key.test", "expiration_date", expirationDateValid), + ), + }, + { + Config: testAccCheckIBMKmsCreateRootKeyConfig(instanceName, resourceName, keyName, expirationDateValid), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_kms_key.test", "key_name", keyName), + resource.TestCheckResourceAttr("ibm_kms_key.test", "expiration_date", expirationDateValid), + ), + }, + }, + }) +} + +// Test for invalid expiration date for create key operation +func TestAccIBMKMSResource_InvalidExpDate(t *testing.T) { + instanceName := fmt.Sprintf("kms_%d", acctest.RandIntRange(10, 100)) + keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) + + hours := time.Duration(rand.Intn(24) + 1) + mins := time.Duration(rand.Intn(60) + 1) + sec := time.Duration(rand.Intn(60) + 1) + expirationDateInvalid := (time.Now().Add(time.Hour*hours + time.Minute*mins + time.Second*sec)).String() + resourceName := "ibm_kms_key" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, resourceName, keyName, expirationDateInvalid), + ExpectError: regexp.MustCompile("Invalid time format"), + }, + { + Config: testAccCheckIBMKmsCreateRootKeyConfig(instanceName, resourceName, keyName, expirationDateInvalid), + ExpectError: regexp.MustCompile("Invalid time format"), + }, + }, + }) +} + +func testAccCheckIBMKmsResourceConfig(instanceName, resource, KeyName string, standard_key bool) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kms_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "%s" "test" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + key_name = "%s" + standard_key = %t + force_delete = true + } +`, instanceName, resource, KeyName, standard_key) +} + +func testAccCheckIBMKmsResourceImportStandardConfig(instanceName, resource, KeyName, payload string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kms_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "%s" "test" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + key_name = "%s" + standard_key = true + payload = "%s" + force_delete = true + } + +`, instanceName, resource, KeyName, payload) +} + +func testAccCheckIBMKmsResourceRootkeyWithCOSConfig(instanceName, resource, KeyName, cosInstanceName, bucketName string) string { + return fmt.Sprintf(` + provider "ibm" { + region = "us-south" + } + resource "ibm_resource_instance" "kms_instance1" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "%s" "test" { + instance_id = "${ibm_resource_instance.kms_instance1.guid}" + key_name = "%s" + standard_key = false + force_delete = true + } + + resource "ibm_resource_instance" "cos_instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "cloud-object-storage" + target_service_name = "kms" + roles = ["Reader"] + } + resource "ibm_cos_bucket" "smart-us-south" { + depends_on = [ibm_iam_authorization_policy.policy] + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "smart" + key_protect = ibm_kms_key.test.id + } +`, instanceName, resource, KeyName, cosInstanceName, bucketName) +} + +func testAccCheckIBMKmsResourceHpcsConfig(hpcsInstanceID, KeyName string) string { + return fmt.Sprintf(` + resource "ibm_kms_key" "hpcstest" { + instance_id = "%s" + key_name = "%s" + standard_key = true + force_delete = true + } + +`, acc.HpcsInstanceID, KeyName) +} + +func testAccCheckIBMKmsCreateStandardKeyConfig(instanceName, resource, KeyName, expirationDate string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kms_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "%s" "test" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + key_name = "%s" + standard_key = true + force_delete = true + expiration_date = "%s" + } +`, instanceName, resource, KeyName, expirationDate) +} + +func testAccCheckIBMKmsCreateRootKeyConfig(instanceName, resource, KeyName, expirationDate string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "kms_instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + resource "%s" "test" { + instance_id = "${ibm_resource_instance.kms_instance.guid}" + key_name = "%s" + standard_key = false + force_delete = true + expiration_date = "%s" + } +`, instanceName, resource, KeyName, expirationDate) +} + +// This test is invalid as ibm_kms_key does not support policies anymore + +// func testAccCheckIBMKmsKeyPolicyStandardConfig(instanceName, KeyName string, rotation_interval int, dual_auth_delete bool) string { +// return fmt.Sprintf(` +// resource "ibm_resource_instance" "kp_instance" { +// name = "%s" +// service = "kms" +// plan = "tiered-pricing" +// location = "us-south" +// } + +// resource "ibm_kms_key" "test" { +// instance_id = ibm_resource_instance.kp_instance.guid +// key_name = "%s" +// standard_key = false +// policies { +// rotation { +// interval_month = %d +// } +// dual_auth_delete { +// enabled = %t +// } +// } +// } +// `, instanceName, KeyName, rotation_interval, dual_auth_delete) +// } + +// This test is invalid as ibm_kms_key does not support policies anymore + +// func testAccCheckIBMKmsKeyPolicyRotation(instanceName, KeyName string, rotation_interval int) string { +// return fmt.Sprintf(` +// resource "ibm_resource_instance" "kp_instance" { +// name = "%s" +// service = "kms" +// plan = "tiered-pricing" +// location = "us-south" +// } + +// resource "ibm_kms_key" "test" { +// instance_id = ibm_resource_instance.kp_instance.guid +// key_name = "%s" +// standard_key = false +// policies { +// rotation { +// interval_month = %d +// } +// } +// } +// `, instanceName, KeyName, rotation_interval) +// } + +// This test is invalid as ibm_kms_key does not support policies anymore + +// func testAccCheckIBMKmsKeyPolicyDualAuth(instanceName, resource, KeyName string, dual_auth_delete bool) string { +// return fmt.Sprintf(` +// resource "ibm_resource_instance" "kp_instance" { +// name = "%s" +// service = "kms" +// plan = "tiered-pricing" +// location = "us-south" +// } + +// resource "%s" "test" { +// instance_id = ibm_resource_instance.kp_instance.guid +// key_name = "%s" +// standard_key = false +// policies { +// dual_auth_delete { +// enabled = %t +// } +// } +// } +// `, instanceName, resource, KeyName, dual_auth_delete) +// } diff --git a/ibm/resource_ibm_kp_key.go b/ibm/service/kms/resource_ibm_kp_key.go similarity index 88% rename from ibm/resource_ibm_kp_key.go rename to ibm/service/kms/resource_ibm_kp_key.go index 52bdec04d..78bdaf404 100644 --- a/ibm/resource_ibm_kp_key.go +++ b/ibm/service/kms/resource_ibm_kp_key.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms import ( "context" @@ -11,11 +11,13 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" kp "github.com/IBM/keyprotect-go-client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMkey() *schema.Resource { +func ResourceIBMkey() *schema.Resource { return &schema.Resource{ Create: resourceIBMKeyCreate, Read: resourceIBMKeyRead, @@ -82,30 +84,30 @@ func resourceIBMkey() *schema.Resource { Computed: true, Description: "Crn of the key", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", @@ -115,7 +117,7 @@ func resourceIBMkey() *schema.Resource { } func resourceIBMKeyCreate(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyProtectAPI() + api, err := meta.(conns.ClientSession).KeyProtectAPI() if err != nil { return err } @@ -174,7 +176,7 @@ func resourceIBMKeyCreate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMKeyRead(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyProtectAPI() + api, err := meta.(conns.ClientSession).KeyProtectAPI() if err != nil { return err } @@ -198,20 +200,20 @@ func resourceIBMKeyRead(d *schema.ResourceData, meta interface{}) error { d.Set("key_name", key.Name) d.Set("crn", key.CRN) - d.Set(ResourceName, key.Name) - d.Set(ResourceCRN, key.CRN) + d.Set(flex.ResourceName, key.Name) + d.Set(flex.ResourceCRN, key.CRN) state := key.State - d.Set(ResourceStatus, strconv.Itoa(state)) + d.Set(flex.ResourceStatus, strconv.Itoa(state)) - rcontroller, err := getBaseController(meta) + rcontroller, err := flex.GetBaseController(meta) if err != nil { return err } id := key.ID crn1 := strings.TrimSuffix(key.CRN, ":key:"+id) - d.Set(ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") + d.Set(flex.ResourceControllerURL, rcontroller+"/services/kms/"+url.QueryEscape(crn1)+"%3A%3A") return nil @@ -227,7 +229,7 @@ func resourceIBMKeyUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMKeyDelete(d *schema.ResourceData, meta interface{}) error { - api, err := meta.(ClientSession).keyProtectAPI() + api, err := meta.(conns.ClientSession).KeyProtectAPI() if err != nil { return err } @@ -252,7 +254,7 @@ func resourceIBMKeyDelete(d *schema.ResourceData, meta interface{}) error { } func resourceIBMKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - api, err := meta.(ClientSession).keyProtectAPI() + api, err := meta.(conns.ClientSession).KeyProtectAPI() if err != nil { return false, err } diff --git a/ibm/resource_ibm_kp_key_test.go b/ibm/service/kms/resource_ibm_kp_key_test.go similarity index 88% rename from ibm/resource_ibm_kp_key_test.go rename to ibm/service/kms/resource_ibm_kp_key_test.go index f4544c127..61b8c9d95 100644 --- a/ibm/resource_ibm_kp_key_test.go +++ b/ibm/service/kms/resource_ibm_kp_key_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kms_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,10 +18,10 @@ func TestAccIBMKpResource_basic(t *testing.T) { keyName := fmt.Sprintf("key_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMKpResourceConfig(instanceName, keyName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("ibm_kp_key.test", "key_name", keyName), diff --git a/ibm/service/kubernetes/README.md b/ibm/service/kubernetes/README.md new file mode 100644 index 000000000..2152dfe7a --- /dev/null +++ b/ibm/service/kubernetes/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Kubernetes Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Kubernetes Services resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/container_addons) +* IBM API Docs: [IBM API Docs for Kubernetes Services](https://containers.cloud.ibm.com/global/swagger-global-api/) +* IBM Kubernetes Services SDK: [IBM SDK for Kubernetes Services](https://github.com/IBM-Cloud/bluemix-go/tree/master/api/container) diff --git a/ibm/data_source_ibm_container_addons.go b/ibm/service/kubernetes/data_source_ibm_container_addons.go similarity index 82% rename from ibm/data_source_ibm_container_addons.go rename to ibm/service/kubernetes/data_source_ibm_container_addons.go index d0d114600..dc0b61ac6 100644 --- a/ibm/data_source_ibm_container_addons.go +++ b/ibm/service/kubernetes/data_source_ibm_container_addons.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -9,9 +9,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func datasourceIBMContainerAddOns() *schema.Resource { +func DataSourceIBMContainerAddOns() *schema.Resource { return &schema.Resource{ Read: datasourceIBMContainerAddOnsRead, @@ -20,6 +22,9 @@ func datasourceIBMContainerAddOns() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Cluster Name or ID", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_addons", + "cluster"), }, "resource_group_id": { Type: schema.TypeString, @@ -94,8 +99,22 @@ func datasourceIBMContainerAddOns() *schema.Resource { }, } } +func DataSourceIBMContainerAddOnsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerAddOnsValidator := validate.ResourceValidator{ResourceName: "ibm_container_addons", Schema: validateSchema} + return &iBMContainerAddOnsValidator +} func datasourceIBMContainerAddOnsRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_container_addons_test.go b/ibm/service/kubernetes/data_source_ibm_container_addons_test.go similarity index 79% rename from ibm/data_source_ibm_container_addons_test.go rename to ibm/service/kubernetes/data_source_ibm_container_addons_test.go index de21f0f63..4efa2e197 100644 --- a/ibm/data_source_ibm_container_addons_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_addons_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMContainerAddOnsDataSource_basic(t *testing.T) { name := fmt.Sprintf("tf-cluster-addon-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerAddOnsDataSourceConfig(name), @@ -29,9 +31,9 @@ func TestAccIBMContainerAddOnsDataSource_basic(t *testing.T) { } func testAccCheckIBMContainerAddOnsDataSourceConfig(name string) string { - return testAccCheckIBMContainerAddOnsBasic(name) + fmt.Sprintf(` + return testAccCheckIBMContainerAddOnsBasic(name) + ` data "ibm_container_addons" "addons" { cluster= ibm_container_addons.addons.cluster } -`) +` } diff --git a/ibm/data_source_ibm_container_alb.go b/ibm/service/kubernetes/data_source_ibm_container_alb.go similarity index 91% rename from ibm/data_source_ibm_container_alb.go rename to ibm/service/kubernetes/data_source_ibm_container_alb.go index 3df8ab424..164f03232 100644 --- a/ibm/data_source_ibm_container_alb.go +++ b/ibm/service/kubernetes/data_source_ibm_container_alb.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerALB() *schema.Resource { +func DataSourceIBMContainerALB() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerALBRead, @@ -57,7 +58,7 @@ func dataSourceIBMContainerALB() *schema.Resource { } func dataSourceIBMContainerALBRead(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).ContainerAPI() + albClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_container_alb_cert.go b/ibm/service/kubernetes/data_source_ibm_container_alb_cert.go similarity index 75% rename from ibm/data_source_ibm_container_alb_cert.go rename to ibm/service/kubernetes/data_source_ibm_container_alb_cert.go index cf740525d..8c47760cf 100644 --- a/ibm/data_source_ibm_container_alb_cert.go +++ b/ibm/service/kubernetes/data_source_ibm_container_alb_cert.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerALBCert() *schema.Resource { +func DataSourceIBMContainerALBCert() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerALBCertRead, @@ -24,6 +26,9 @@ func dataSourceIBMContainerALBCert() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Cluster ID", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_alb_cert", + "cluster_id"), }, "secret_name": { Type: schema.TypeString, @@ -77,8 +82,22 @@ func dataSourceIBMContainerALBCert() *schema.Resource { } } +func DataSourceIBMContainerALBCertValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerALBCertValidator := validate.ResourceValidator{ResourceName: "ibm_container_alb_cert", Schema: validateSchema} + return &iBMContainerALBCertValidator +} func dataSourceIBMContainerALBCertRead(d *schema.ResourceData, meta interface{}) error { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } diff --git a/ibm/service/kubernetes/data_source_ibm_container_bind_service.go b/ibm/service/kubernetes/data_source_ibm_container_bind_service.go new file mode 100644 index 000000000..359c0bb62 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_bind_service.go @@ -0,0 +1,101 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerBindService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMContainerBindServiceRead, + + Schema: map[string]*schema.Schema{ + "cluster_name_id": { + Type: schema.TypeString, + Required: true, + Description: "Cluster name or ID", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_bind_service", + "cluster_name_id"), + }, + "service_instance_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"service_instance_name"}, + Description: "Service instance ID", + }, + "service_instance_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"service_instance_id"}, + Description: "serivice instance name", + }, + "namespace_id": { + Type: schema.TypeString, + Required: true, + Description: "namespace ID", + }, + "service_key_name": { + Type: schema.TypeString, + Computed: true, + Description: "Key info", + }, + }, + } +} +func DataSourceIBMContainerBindServiceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_name_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerBindServiceValidator := validate.ResourceValidator{ResourceName: "ibm_container_bind_service", Schema: validateSchema} + return &iBMContainerBindServiceValidator +} + +func dataSourceIBMContainerBindServiceRead(d *schema.ResourceData, meta interface{}) error { + csClient, err := meta.(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + + clusterNameID := d.Get("cluster_name_id").(string) + namespaceID := d.Get("namespace_id").(string) + var serviceInstanceNameID string + if serviceInstanceName, ok := d.GetOk("service_instance_name"); ok { + serviceInstanceNameID = serviceInstanceName.(string) + } else if serviceInstanceID, ok := d.GetOk("service_instance_id"); ok { + serviceInstanceNameID = serviceInstanceID.(string) + } else { + return fmt.Errorf("[ERROR] Please set either service_instance_name or service_instance_id") + } + + targetEnv, err := getClusterTargetHeader(d, meta) + if err != nil { + return err + } + + boundService, err := csClient.Clusters().FindServiceBoundToCluster(clusterNameID, serviceInstanceNameID, namespaceID, targetEnv) + if err != nil { + return err + } + d.Set("namespace_id", boundService.Namespace) + d.Set("service_instance_name", boundService.ServiceName) + d.Set("service_instance_id", boundService.ServiceID) + d.Set("service_key_name", boundService.ServiceKeyName) + d.SetId(fmt.Sprintf("%s/%s/%s", clusterNameID, serviceInstanceNameID, namespaceID)) + return nil +} diff --git a/ibm/data_source_ibm_container_cluster.go b/ibm/service/kubernetes/data_source_ibm_container_cluster.go similarity index 80% rename from ibm/data_source_ibm_container_cluster.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster.go index 3265244c4..a35f784d9 100644 --- a/ibm/data_source_ibm_container_cluster.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster.go @@ -1,16 +1,20 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" + "log" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerCluster() *schema.Resource { +func DataSourceIBMContainerCluster() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerClusterRead, @@ -27,6 +31,9 @@ func dataSourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, Optional: true, ExactlyOneOf: []string{"cluster_name_id", "name"}, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_cluster", + "name"), }, "worker_count": { Description: "Number of workers", @@ -171,7 +178,7 @@ func dataSourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "all", - ValidateFunc: validateAllowedStringValue([]string{"private", "public", "all"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"private", "public", "all"}), }, "albs": { Type: schema.TypeList, @@ -308,31 +315,36 @@ func dataSourceIBMContainerCluster() *schema.Resource { Computed: true, Description: "email id of the key owner", }, - ResourceControllerURL: { + "image_security_enforcement": { + Type: schema.TypeBool, + Computed: true, + Description: "True if image security enforcement is enabled", + }, + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -341,8 +353,22 @@ func dataSourceIBMContainerCluster() *schema.Resource { } } +func DataSourceIBMContainerClusterValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Optional: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerClusterValidator := validate.ResourceValidator{ResourceName: "ibm_container_cluster", Schema: validateSchema} + return &iBMContainerClusterValidator +} func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -366,11 +392,11 @@ func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) } clusterFields, err := csAPI.Find(name, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving cluster: %s", err) } workerFields, err := wrkAPI.List(name, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } workers := make([]string, len(workerFields)) for i, worker := range workerFields { @@ -382,7 +408,7 @@ func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) if listBoundedServices { servicesBoundToCluster, err := csAPI.ListServicesBoundToCluster(name, "", targetEnv) if err != nil { - return fmt.Errorf("Error retrieving services bound to cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving services bound to cluster: %s", err) } for _, service := range servicesBoundToCluster { boundedService := make(map[string]interface{}) @@ -396,25 +422,25 @@ func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) workerPools, err := workerPoolsAPI.ListWorkerPools(name, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving worker pools of the cluster %s: %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving worker pools of the cluster %s: %s", name, err) } albs, err := albsAPI.ListClusterALBs(name, targetEnv) if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") && !strings.Contains(err.Error(), "The specified cluster is a free cluster.") { - return fmt.Errorf("Error retrieving alb's of the cluster %s: %s", name, err) + return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", name, err) } filterType := d.Get("alb_type").(string) - filteredAlbs := flattenAlbs(albs, filterType) + filteredAlbs := flex.FlattenAlbs(albs, filterType) d.SetId(clusterFields.ID) d.Set("worker_count", clusterFields.WorkerCount) d.Set("workers", workers) d.Set("region", clusterFields.Region) d.Set("bounded_services", boundedServices) - d.Set("vlans", flattenVlans(clusterFields.Vlans)) + d.Set("vlans", flex.FlattenVlans(clusterFields.Vlans)) d.Set("is_trusted", clusterFields.IsTrusted) - d.Set("worker_pools", flattenWorkerPools(workerPools)) + d.Set("worker_pools", flex.FlattenWorkerPools(workerPools)) d.Set("albs", filteredAlbs) d.Set("resource_group_id", clusterFields.ResourceGroupID) d.Set("public_service_endpoint", clusterFields.PublicServiceEndpointEnabled) @@ -426,23 +452,24 @@ func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) d.Set("ingress_hostname", clusterFields.IngressHostname) d.Set("ingress_secret", clusterFields.IngressSecretName) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") apikeyAPI := csClient.Apikeys() apikeyConfig, err := apikeyAPI.GetApiKeyInfo(name, targetEnv) if err != nil { - return err + log.Printf("[ERROR] Error in GetApiKeyInfo, %s", err) } d.Set("api_key_id", apikeyConfig.ID) d.Set("api_key_owner_name", apikeyConfig.Name) d.Set("api_key_owner_email", apikeyConfig.Email) - d.Set(ResourceName, clusterFields.Name) - d.Set(ResourceCRN, clusterFields.CRN) - d.Set(ResourceStatus, clusterFields.State) - d.Set(ResourceGroupName, clusterFields.ResourceGroupName) + d.Set("image_security_enforcement", clusterFields.ImageSecurityEnabled) + d.Set(flex.ResourceName, clusterFields.Name) + d.Set(flex.ResourceCRN, clusterFields.CRN) + d.Set(flex.ResourceStatus, clusterFields.State) + d.Set(flex.ResourceGroupName, clusterFields.ResourceGroupName) return nil } diff --git a/ibm/service/kubernetes/data_source_ibm_container_cluster_config.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_config.go new file mode 100644 index 000000000..b3d8be3a0 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_config.go @@ -0,0 +1,252 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "fmt" + "log" + "path/filepath" + "regexp" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + homedir "github.com/mitchellh/go-homedir" + + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func DataSourceIBMContainerClusterConfig() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMContainerClusterConfigRead, + + Schema: map[string]*schema.Schema{ + + "org_guid": { + Description: "The bluemix organization guid this cluster belongs to", + Type: schema.TypeString, + Optional: true, + Deprecated: "This field is deprecated", + }, + "space_guid": { + Description: "The bluemix space guid this cluster belongs to", + Type: schema.TypeString, + Optional: true, + Deprecated: "This field is deprecated", + }, + "account_guid": { + Description: "The bluemix account guid this cluster belongs to", + Type: schema.TypeString, + Optional: true, + Deprecated: "This field is deprecated", + }, + "region": { + Type: schema.TypeString, + Optional: true, + Description: "The cluster region", + Deprecated: "This field is deprecated", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + "cluster_name_id": { + Description: "The name/id of the cluster", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_cluster_config", + "cluster_name_id"), + }, + "config_dir": { + Description: "The directory where the cluster config to be downloaded. Default is home directory ", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "download": { + Description: "If set to false will not download the config, otherwise they are downloaded each time but onto the same path for a given cluster name/id", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "admin": { + Description: "If set to true will download the config for admin", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "network": { + Description: "If set to true will download the Calico network config with the Admin config", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "config_file_path": { + Description: "The absolute path to the kubernetes config yml file ", + Type: schema.TypeString, + Computed: true, + }, + "calico_config_file_path": { + Description: "The absolute path to the calico network config file ", + Type: schema.TypeString, + Computed: true, + }, + "admin_key": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "admin_certificate": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "ca_certificate": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "host": { + Type: schema.TypeString, + Computed: true, + }, + "token": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + } +} +func DataSourceIBMContainerClusterConfigValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_name_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerClusterConfigValidator := validate.ResourceValidator{ResourceName: "ibm_container_cluster_config", Schema: validateSchema} + return &iBMContainerClusterConfigValidator +} + +func dataSourceIBMContainerClusterConfigRead(d *schema.ResourceData, meta interface{}) error { + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + csAPI := csClient.Clusters() + name := d.Get("cluster_name_id").(string) + download := d.Get("download").(bool) + admin := d.Get("admin").(bool) + configDir := d.Get("config_dir").(string) + network := d.Get("network").(bool) + + clusterId := "Cluster_Config_" + name + conns.IbmMutexKV.Lock(clusterId) + defer conns.IbmMutexKV.Unlock(clusterId) + + if len(configDir) == 0 { + configDir, err = homedir.Dir() + if err != nil { + return fmt.Errorf("[ERROR] Error fetching homedir: %s", err) + } + } + configDir, _ = filepath.Abs(configDir) + + var configPath string + if !download { + log.Println("Skipping download of the cluster config", "Going to check if it already exists") + expectedDir := v1.ComputeClusterConfigDir(configDir, name, admin) + configPath = filepath.Join(expectedDir, "config.yml") + if !helpers.FileExists(configPath) { + return fmt.Errorf(`[ERROR] Couldn't find the cluster config at expected path %s. Please set "download" to true to download the new config`, configPath) + } + d.Set("config_file_path", configPath) + + } else { + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + if network { + // For the Network config we need to gather the certs so we must override the admin value + var calicoConfigFilePath string + var clusterKeyDetails v1.ClusterKeyInfo + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + calicoConfigFilePath, clusterKeyDetails, err = csAPI.StoreConfigDetail(name, configDir, admin || true, network, targetEnv) + if err != nil { + log.Printf("[DEBUG] Failed to fetch cluster config err %s", err) + if strings.Contains(err.Error(), "Could not login to openshift account runtime error:") { + return resource.RetryableError(err) + } + if intermittentUserLookupFailure, _ := regexp.MatchString("Error: lookup of user for \"(.+)\" failed", err.Error()); intermittentUserLookupFailure { + // Intermittent error resulting from synchronisation delay + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + if conns.IsResourceTimeoutError(err) { + calicoConfigFilePath, clusterKeyDetails, err = csAPI.StoreConfigDetail(name, configDir, admin || true, network, targetEnv) + } + if err != nil { + return fmt.Errorf("[ERROR] Error downloading the cluster config [%s]: %s", name, err) + } + d.Set("calico_config_file_path", calicoConfigFilePath) + d.Set("admin_key", clusterKeyDetails.AdminKey) + d.Set("admin_certificate", clusterKeyDetails.Admin) + d.Set("ca_certificate", clusterKeyDetails.ClusterCACertificate) + d.Set("host", clusterKeyDetails.Host) + d.Set("token", clusterKeyDetails.Token) + d.Set("config_file_path", clusterKeyDetails.FilePath) + + } else { + var clusterKeyDetails v1.ClusterKeyInfo + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + clusterKeyDetails, err = csAPI.GetClusterConfigDetail(name, configDir, admin, targetEnv) + if err != nil { + log.Printf("[DEBUG] Failed to fetch cluster config err %s", err) + if strings.Contains(err.Error(), "Could not login to openshift account runtime error:") { + return resource.RetryableError(err) + } + if intermittentUserLookupFailure, _ := regexp.MatchString("Error: lookup of user for \"(.+)\" failed", err.Error()); intermittentUserLookupFailure { + // Intermittent error resulting from synchronisation delay + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + if conns.IsResourceTimeoutError(err) { + clusterKeyDetails, err = csAPI.GetClusterConfigDetail(name, configDir, admin, targetEnv) + } + if err != nil { + return fmt.Errorf("[ERROR] Error downloading the cluster config [%s]: %s", name, err) + } + d.Set("admin_key", clusterKeyDetails.AdminKey) + d.Set("admin_certificate", clusterKeyDetails.Admin) + d.Set("ca_certificate", clusterKeyDetails.ClusterCACertificate) + d.Set("host", clusterKeyDetails.Host) + d.Set("token", clusterKeyDetails.Token) + d.Set("config_file_path", clusterKeyDetails.FilePath) + } + } + + d.SetId(name) + d.Set("config_dir", configDir) + return nil +} diff --git a/ibm/data_source_ibm_container_cluster_config_test.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_config_test.go similarity index 86% rename from ibm/data_source_ibm_container_cluster_config_test.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_config_test.go index 657d864f6..6cb0f9d97 100644 --- a/ibm/data_source_ibm_container_cluster_config_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_config_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/mitchellh/go-homedir" @@ -19,8 +21,8 @@ func TestAccIBMContainer_ClusterConfigDataSourceBasic(t *testing.T) { } clusterName := fmt.Sprintf("tf-cluster-config-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterDataSourceConfig(clusterName), @@ -41,8 +43,8 @@ func TestAccIBMContainer_ClusterConfigCalicoDataSourceBasic(t *testing.T) { } clusterName := fmt.Sprintf("tf-cluster-config-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterCalicoConfigDataSource(clusterName), @@ -72,7 +74,7 @@ resource "ibm_container_cluster" "testacc_cluster" { data "ibm_container_cluster_config" "testacc_ds_cluster" { cluster_name_id = ibm_container_cluster.testacc_cluster.id -}`, clustername, datacenter, machineType, publicVlanID, privateVlanID) +}`, clustername, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterCalicoConfigDataSource(clustername string) string { @@ -90,5 +92,5 @@ resource "ibm_container_cluster" "testacc_cluster" { data "ibm_container_cluster_config" "testacc_ds_cluster" { cluster_name_id = ibm_container_cluster.testacc_cluster.id network = true -}`, clustername, datacenter, machineType, publicVlanID, privateVlanID) +}`, clustername, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } diff --git a/ibm/data_source_ibm_container_cluster_test.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_test.go similarity index 89% rename from ibm/data_source_ibm_container_cluster_test.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_test.go index eb2f9ace5..07a1b5252 100644 --- a/ibm/data_source_ibm_container_cluster_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "strconv" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,8 +19,8 @@ func TestAccIBMContainerClusterDataSource_basic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) serviceName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterDataSource(clusterName, serviceName), @@ -49,13 +51,13 @@ func testAccIBMClusterVlansCheck(n string) resource.TestCheckFunc { return err } if vlansSize < 1 { - return fmt.Errorf("No subnets found") + return fmt.Errorf("[ERROR] No subnets found") } return nil } } func testAccCheckIBMContainerClusterDataSource(clusterName, serviceName string) string { - return testAccCheckIBMContainerBindServiceBasic(clusterName, serviceName) + fmt.Sprintf(` + return testAccCheckIBMContainerBindServiceBasic(clusterName, serviceName) + ` data "ibm_container_cluster" "testacc_ds_cluster" { cluster_name_id = ibm_container_cluster.testacc_cluster.id } @@ -64,5 +66,5 @@ func testAccCheckIBMContainerClusterDataSource(clusterName, serviceName string) service_instance_id = ibm_container_bind_service.bind_service.service_instance_id namespace_id = "default" } - `) + ` } diff --git a/ibm/data_source_ibm_container_cluster_versions.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_versions.go similarity index 92% rename from ibm/data_source_ibm_container_cluster_versions.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_versions.go index 68a5d3c40..348cb791c 100644 --- a/ibm/data_source_ibm_container_cluster_versions.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_versions.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerClusterVersions() *schema.Resource { +func DataSourceIBMContainerClusterVersions() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerClusterVersionsRead, @@ -61,7 +62,7 @@ func dataSourceIBMContainerClusterVersions() *schema.Resource { } func dataSourceIBMContainerClusterVersionsRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_container_cluster_versions_test.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_versions_test.go similarity index 82% rename from ibm/data_source_ibm_container_cluster_versions_test.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_versions_test.go index 7193b8cac..cb1906e4f 100644 --- a/ibm/data_source_ibm_container_cluster_versions_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_versions_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMContainerClusterVersionsDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterVersionsDataSource(), @@ -31,5 +33,5 @@ func testAccCheckIBMContainerClusterVersionsDataSource() string { data "ibm_container_cluster_versions" "versions" { region = "%s" } -`, csRegion) +`, acc.CsRegion) } diff --git a/ibm/data_source_ibm_container_cluster_worker.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_worker.go similarity index 85% rename from ibm/data_source_ibm_container_cluster_worker.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_worker.go index 3dd10f179..24d7fac8e 100644 --- a/ibm/data_source_ibm_container_cluster_worker.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_worker.go @@ -1,15 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerClusterWorker() *schema.Resource { +func DataSourceIBMContainerClusterWorker() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerClusterWorkerRead, @@ -74,7 +76,7 @@ func dataSourceIBMContainerClusterWorker() *schema.Resource { Optional: true, Description: "ID of the resource group.", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", @@ -84,7 +86,7 @@ func dataSourceIBMContainerClusterWorker() *schema.Resource { } func dataSourceIBMContainerClusterWorkerRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -98,7 +100,7 @@ func dataSourceIBMContainerClusterWorkerRead(d *schema.ResourceData, meta interf workerFields, err := wrkAPI.Get(workerID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving worker: %s", err) + return fmt.Errorf("[ERROR] Error retrieving worker: %s", err) } d.SetId(workerFields.ID) @@ -108,11 +110,11 @@ func dataSourceIBMContainerClusterWorkerRead(d *schema.ResourceData, meta interf d.Set("public_vlan", workerFields.PublicVlan) d.Set("private_ip", workerFields.PrivateIP) d.Set("public_ip", workerFields.PublicIP) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") return nil } diff --git a/ibm/data_source_ibm_container_cluster_worker_test.go b/ibm/service/kubernetes/data_source_ibm_container_cluster_worker_test.go similarity index 83% rename from ibm/data_source_ibm_container_cluster_worker_test.go rename to ibm/service/kubernetes/data_source_ibm_container_cluster_worker_test.go index 20c3c2daa..5eab0a08d 100644 --- a/ibm/data_source_ibm_container_cluster_worker_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster_worker_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ import ( func TestAccIBMContainerWorkerDataSource_basic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterWorkerDataSourceConfig(clusterName), @@ -48,5 +50,5 @@ data "ibm_container_cluster" "testacc_ds_cluster" { data "ibm_container_cluster_worker" "testacc_ds_worker" { worker_id = data.ibm_container_cluster.testacc_ds_cluster.workers[0] } -`, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host.go new file mode 100644 index 000000000..b392c5a06 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerDedicatedHost() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerDedicatedHostRead, + Schema: map[string]*schema.Schema{ + "host_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the dedicated host", + }, + "host_pool_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the dedicated host pool the dedicated host is associated with", + }, + "flavor": { + Type: schema.TypeString, + Computed: true, + Description: "The flavor of the dedicated host", + }, + "placement_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Describes if the placement on the dedicated host is enabled", + }, + "life_cycle": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actual_state": { + Type: schema.TypeString, + Computed: true, + }, + "desired_state": { + Type: schema.TypeString, + Computed: true, + }, + "message": { + Type: schema.TypeString, + Computed: true, + }, + "message_date": { + Type: schema.TypeString, + Computed: true, + }, + "message_details": { + Type: schema.TypeString, + Computed: true, + }, + "message_details_date": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Description: "The resources of the dedicated host", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "consumed": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "workers": { + Type: schema.TypeList, + Computed: true, + Description: "The workers of the dedicated host", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Computed: true, + }, + "flavor": { + Type: schema.TypeString, + Computed: true, + }, + "worker_id": { + Type: schema.TypeString, + Computed: true, + }, + "worker_pool_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + Description: "The zone of the dedicated host", + }, + }, + } +} +func dataSourceIBMContainerDedicatedHostRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + hostID := d.Get("host_id").(string) + hostPoolID := d.Get("host_pool_id").(string) + id := fmt.Sprintf("%s/%s", hostPoolID, hostID) + + if err := getIBMContainerDedicatedHost(id, d, meta); err != nil { + return diag.Errorf("[ERROR] getIBMContainerDedicatedHost failed: %v", err) + } + + d.SetId(id) + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor.go new file mode 100644 index 000000000..4a20fe7ad --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMContainerDedicatedHostFlavor() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerDedicatedHostFlavorRead, + Schema: map[string]*schema.Schema{ + "zone": { + Type: schema.TypeString, + Required: true, + Description: "The zone of the dedicated host flavor", + }, + "host_flavor_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the dedicated host flavor", + }, + "flavor_class": { + Type: schema.TypeString, + Computed: true, + Description: "The class of the dedicated host flavor", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "The region of the dedicated host flavor", + }, + "deprecated": { + Type: schema.TypeBool, + Computed: true, + Description: "Describes if the dedicated host flavor is deprecated", + }, + "max_vcpus": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum available vcpus in the dedicated host flavor", + }, + "max_memory": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum available memory in the dedicated host flavor", + }, + "instance_storage": { + Type: schema.TypeList, + Computed: true, + Description: "The instance storage of the dedicated host flavor", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "count": { + Type: schema.TypeInt, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + } +} +func dataSourceIBMContainerDedicatedHostFlavorRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + flavorID := d.Get("host_flavor_id").(string) + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostFlavorAPI := client.DedicatedHostFlavor() + targetEnv := v2.ClusterTargetHeader{} + + dedicatedHostFlavors, err := dedicatedHostFlavorAPI.ListDedicatedHostFlavors(d.Get("zone").(string), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] Listing dedicated host flavors in zone %s failed: %v", d.Get("zone").(string), err) + } + + var dedicatedHostFlavor *v2.GetDedicatedHostFlavor + + for _, dh := range dedicatedHostFlavors { + if dh.ID == flavorID { + dedicatedHostFlavor = &dh + break + } + } + + if dedicatedHostFlavor == nil { + return diag.Errorf("[ERROR] Dedicated host flavor is not found, id : %s", d.Get("id").(string)) + } + + d.SetId(dedicatedHostFlavor.ID) + d.Set("flavor_class", dedicatedHostFlavor.FlavorClass) + d.Set("region", dedicatedHostFlavor.Region) + d.Set("deprecated", dedicatedHostFlavor.Deprecated) + d.Set("max_vcpus", dedicatedHostFlavor.MaxVCPUs) + d.Set("max_memory", dedicatedHostFlavor.MaxMemory) + + instanceStorage := make([]map[string]interface{}, len(dedicatedHostFlavor.InstanceStorage)) + for i, is := range dedicatedHostFlavor.InstanceStorage { + instanceStorage[i] = map[string]interface{}{ + "count": is.Count, + "size": is.Size, + } + } + d.Set("instance_storage", instanceStorage) + + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor_test.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor_test.go new file mode 100644 index 000000000..7c2c4a274 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavor_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerDedicatedHostFlavorDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostFlavorDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavor.test_dhost_flavor", "flavor_class", "bx2d"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavor.test_dhost_flavor", "region", "us-south"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavor.test_dhost_flavor", "deprecated", "false"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavor.test_dhost_flavor", "max_vcpus", "152"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavor.test_dhost_flavor", "max_memory", "0"), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostFlavorDataSourceConfig() string { + return ` + data "ibm_container_dedicated_host_flavor" "test_dhost_flavor" { + host_flavor_id = "bx2d.host.152x608" + zone = "us-south-2" + } +` +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors.go new file mode 100644 index 000000000..98cab72df --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors.go @@ -0,0 +1,120 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMContainerDedicatedHostFlavors() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerDedicatedHostFlavorsRead, + Schema: map[string]*schema.Schema{ + "zone": { + Type: schema.TypeString, + Required: true, + Description: "The zone of the dedicated host flavors", + }, + "host_flavors": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_flavor_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the dedicated host flavor", + }, + "flavor_class": { + Type: schema.TypeString, + Computed: true, + Description: "The class of the dedicated host flavor", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "The region of the dedicated host flavor", + }, + "deprecated": { + Type: schema.TypeBool, + Computed: true, + Description: "Describes if the dedicated host flavor is deprecated", + }, + "max_vcpus": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum available vcpus in the dedicated host flavor", + }, + "max_memory": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum available memory in the dedicated host flavor", + }, + "instance_storage": { + Type: schema.TypeList, + Computed: true, + Description: "The instance storage of the dedicated host flavor", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "count": { + Type: schema.TypeInt, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func dataSourceIBMContainerDedicatedHostFlavorsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostFlavorsAPI := client.DedicatedHostFlavor() + targetEnv := v2.ClusterTargetHeader{} + + dedicatedHostFlavors, err := dedicatedHostFlavorsAPI.ListDedicatedHostFlavors(d.Get("zone").(string), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] Listing dedicated host flavors in zone %s failed: %v", d.Get("zone").(string), err) + } + + flavors := make([]interface{}, len(dedicatedHostFlavors)) + + for j, dh := range dedicatedHostFlavors { + instanceStorage := make([]map[string]interface{}, len(dh.InstanceStorage)) + for i, is := range dh.InstanceStorage { + instanceStorage[i] = map[string]interface{}{ + "count": is.Count, + "size": is.Size, + } + } + flavors[j] = map[string]interface{}{ + "host_flavor_id": dh.ID, + "flavor_class": dh.FlavorClass, + "region": dh.Region, + "deprecated": dh.Deprecated, + "max_vcpus": dh.MaxVCPUs, + "max_memory": dh.MaxMemory, + "instance_storage": instanceStorage, + } + } + + d.SetId(d.Get("zone").(string)) + d.Set("host_flavors", flavors) + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors_test.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors_test.go new file mode 100644 index 000000000..51cb1fa79 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_flavors_test.go @@ -0,0 +1,44 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerDedicatedHostFlavorsDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostFlavorsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.#", "1"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.host_flavor_id"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.flavor_class"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.region"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.deprecated"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.max_vcpus"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.max_memory"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.instance_storage.#", "1"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.instance_storage.0.count"), + resource.TestCheckResourceAttrSet("data.ibm_container_dedicated_host_flavors.test_dhost_flavors", "host_flavors.0.instance_storage.0.size"), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostFlavorsDataSourceConfig() string { + return ` + data "ibm_container_dedicated_host_flavors" "test_dhost_flavors" { + zone = "us-south-2" + } +` +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool.go new file mode 100644 index 000000000..3fb87af2d --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool.go @@ -0,0 +1,110 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerDedicatedHostPool() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerDedicatedHostPoolRead, + Schema: map[string]*schema.Schema{ + "host_pool_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the dedicated host pool", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the dedicated host pool", + }, + "metro": { + Type: schema.TypeString, + Computed: true, + Description: "The metro to create the dedicated host pool in", + }, + "flavor_class": { + Type: schema.TypeString, + Computed: true, + Description: "The flavor class of the dedicated host pool", + }, + "host_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The count of the hosts under the dedicated host pool", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "The state of the dedicated host pool", + }, + "zones": { + Type: schema.TypeList, + Computed: true, + Description: "The zones of the dedicated host pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "host_count": { + Type: schema.TypeInt, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "worker_pools": { + Type: schema.TypeList, + Computed: true, + Description: "The worker pools of the dedicated host pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Computed: true, + }, + "worker_pool_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMContainerDedicatedHostPoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + hostPoolID := d.Get("host_pool_id").(string) + err := getIBMContainerDedicatedHostPool(hostPoolID, d, meta) + if err != nil { + return diag.Errorf("[ERROR] Error retrieving host pool details %v", err) + } + + d.SetId(hostPoolID) + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool_test.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool_test.go new file mode 100644 index 000000000..306b3370c --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_pool_test.go @@ -0,0 +1,42 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerDedicatedHostPoolDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-dedicated-host-pool-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostPoolDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_pool.test_dhostpool_2", "name", name), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_pool.test_dhostpool_2", "metro", "dal"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_pool.test_dhostpool_2", "flavor_class", "bx2d"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_pool.test_dhostpool_2", "host_count", "0"), + resource.TestCheckResourceAttr("data.ibm_container_dedicated_host_pool.test_dhostpool_2", "state", "created"), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostPoolDataSourceConfig(name string) string { + return testAccCheckIBMContainerDedicatedHostPoolBasic(name) + ` + data "ibm_container_dedicated_host_pool" "test_dhostpool_2" { + host_pool_id = ibm_container_dedicated_host_pool.test_dhostpool.id + } +` +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_test.go b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_test.go new file mode 100644 index 000000000..5740c83c2 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_dedicated_host_test.go @@ -0,0 +1,48 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerDedicatedHostDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-dedicated-host-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_container_dedicated_host.test_dhost_2", "placement_enabled", "true"), + resource.TestCheckResourceAttrSet( + "data.ibm_container_dedicated_host.test_dhost_2", "id"), + resource.TestCheckResourceAttr( + "data.ibm_container_dedicated_host.test_dhost_2", "life_cycle.#", "1"), + resource.TestCheckResourceAttr( + "data.ibm_container_dedicated_host.test_dhost_2", "resources.#", "1"), + resource.TestCheckResourceAttr( + "data.ibm_container_dedicated_host.test_dhost_2", "workers.#", "0"), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostDataSourceConfig(name string) string { + return testAccCheckIBMContainerDedicatedHostBasic(name) + ` + data "ibm_container_dedicated_host" "test_dhost_2" { + host_id = ibm_container_dedicated_host.test_dhost.host_id + host_pool_id = ibm_container_dedicated_host.test_dhost.host_pool_id + } +` +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_nlb_dns.go b/ibm/service/kubernetes/data_source_ibm_container_nlb_dns.go new file mode 100644 index 000000000..f525659a3 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_nlb_dns.go @@ -0,0 +1,120 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerNLBDNS() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerNLBDNSRead, + + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + Description: "A unique name of the cluster", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_nlb_dns", + "cluster"), + }, + "nlb_config": { + Type: schema.TypeList, + Computed: true, + Description: "List of nlb config of cluster", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the secret.", + }, + "secret_status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Secret.", + }, + "cluster": { + Type: schema.TypeString, + Computed: true, + Description: "Cluster Id.", + }, + "dns_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of DNS.", + }, + "lb_hostname": { + Type: schema.TypeString, + Computed: true, + Description: "Host Name of load Balancer.", + }, + "nlb_ips": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: " NLB IPs.", + }, + "nlb_sub_domain": { + Type: schema.TypeString, + Computed: true, + Description: "NLB Sub-Domain.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: " Nlb Type.", + }, + "secret_namespace": { + Type: schema.TypeString, + Computed: true, + Description: "Namespace of Secret.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMContainerNLBDNSValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerNLBDNSValidator := validate.ResourceValidator{ResourceName: "ibm_container_nlb_dns", Schema: validateSchema} + return &iBMContainerNLBDNSValidator +} +func dataSourceIBMContainerNLBDNSRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + name := d.Get("cluster").(string) + + kubeClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + + nlbData, err := kubeClient.NlbDns().GetNLBDNSList(name) + if err != nil || nlbData == nil || len(nlbData) < 1 { + return diag.FromErr(fmt.Errorf("[ERROR] Error Listing NLB DNS (%s): %s", name, err)) + } + d.SetId(name) + d.Set("cluster", name) + d.Set("nlb_config", flex.FlattenNlbConfigs(nlbData)) + return nil +} diff --git a/ibm/data_source_ibm_container_nlb_dns_test.go b/ibm/service/kubernetes/data_source_ibm_container_nlb_dns_test.go similarity index 78% rename from ibm/data_source_ibm_container_nlb_dns_test.go rename to ibm/service/kubernetes/data_source_ibm_container_nlb_dns_test.go index f71172fa1..0f94e4349 100644 --- a/ibm/data_source_ibm_container_nlb_dns_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_nlb_dns_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ import ( func TestAccIBMContainerNLBDNSDatasourceBasic(t *testing.T) { name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerNLBDNSDataSourceConfig(name), @@ -28,9 +30,9 @@ func TestAccIBMContainerNLBDNSDatasourceBasic(t *testing.T) { } func testAccCheckIBMContainerNLBDNSDataSourceConfig(name string) string { - return testAccCheckIBMContainerVpcClusterBasic(name) + fmt.Sprintf(` + return testAccCheckIBMContainerVpcClusterBasic(name) + ` data "ibm_container_nlb_dns" "dns" { cluster = ibm_container_vpc_cluster.cluster.id } -`) +` } diff --git a/ibm/service/kubernetes/data_source_ibm_container_storage_attachment.go b/ibm/service/kubernetes/data_source_ibm_container_storage_attachment.go new file mode 100644 index 000000000..7b8c70ca9 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_storage_attachment.go @@ -0,0 +1,122 @@ +package kubernetes + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMContainerVpcWorkerVolumeAttachmentRead, + + Schema: map[string]*schema.Schema{ + "volume_attachment_id": { + Type: schema.TypeString, + Required: true, + Description: "The volume attachment ID", + }, + + "cluster": { + Type: schema.TypeString, + Required: true, + Description: "Cluster name or ID", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_nlb_dns", + "cluster"), + }, + + "worker": { + Type: schema.TypeString, + Required: true, + Description: "Worker node ID", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "ID of the resource group.", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_nlb_dns", + "resource_group_id"), + }, + + "volume": { + Type: schema.TypeString, + Computed: true, + Description: "Volume ID", + }, + + "volume_attachment_name": { + Type: schema.TypeString, + Computed: true, + Description: "Volume attachment name", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Volume attachment status", + }, + "volume_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of volume", + }, + }, + } +} +func DataSourceIBMContainerVpcWorkerVolumeAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Optional: true, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVpcWorkerVolumeAttachmentValidator := validate.ResourceValidator{ResourceName: "ibm_container_nlb_dns", Schema: validateSchema} + return &iBMContainerVpcWorkerVolumeAttachmentValidator +} + +func dataSourceIBMContainerVpcWorkerVolumeAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + + workersAPI := wpClient.Workers() + target, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return diag.FromErr(err) + } + + clusterNameorID := d.Get("cluster").(string) + volumeAttachmentID := d.Get("volume_attachment_id").(string) + workerID := d.Get("worker").(string) + + volume, err := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, target) + if err != nil { + return diag.FromErr(err) + } + d.Set("volume_attachment_name", volume.Name) + d.Set("status", volume.Status) + d.Set("volume_type", volume.Type) + d.SetId(fmt.Sprintf("%s/%s/%s", clusterNameorID, workerID, volumeAttachmentID)) + return nil +} diff --git a/ibm/data_source_ibm_container_storage_attachment_test.go b/ibm/service/kubernetes/data_source_ibm_container_storage_attachment_test.go similarity index 89% rename from ibm/data_source_ibm_container_storage_attachment_test.go rename to ibm/service/kubernetes/data_source_ibm_container_storage_attachment_test.go index 46fcb02a2..624fc042f 100644 --- a/ibm/data_source_ibm_container_storage_attachment_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_storage_attachment_test.go @@ -1,9 +1,11 @@ -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ func TestAccIBMContainerVpcClusterWorkerVolumeAttachmentDatasource(t *testing.T) volumeName := fmt.Sprintf("terraformvpcvol-%d", randint) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerVpcClusterWorkerVolumeAttachDatasource_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName), @@ -36,12 +38,12 @@ func TestAccIBMContainerVpcClusterWorkerVolumeAttachmentDatasource(t *testing.T) func testAccCheckIBMContainerVpcClusterWorkerVolumeAttachDatasource_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName string) string { return testAccCheckIBMContainerVpcClusterWorkerVolumeAttach_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName) + - fmt.Sprintf(` + ` data "ibm_container_storage_attachment" "volume_attach_data"{ volume_attachment_id = ibm_container_storage_attachment.volume_attach.volume_attachment_id cluster = ibm_container_vpc_cluster.cluster.id worker = data.ibm_container_vpc_cluster.cluster.workers[0] } -`) +` } diff --git a/ibm/data_source_ibm_container_vpc_alb.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_alb.go similarity index 91% rename from ibm/data_source_ibm_container_vpc_alb.go rename to ibm/service/kubernetes/data_source_ibm_container_vpc_alb.go index 8acd1f639..41f7307c8 100644 --- a/ibm/data_source_ibm_container_vpc_alb.go +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_alb.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerVPCClusterALB() *schema.Resource { +func DataSourceIBMContainerVPCClusterALB() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerVpcALBRead, Schema: map[string]*schema.Schema{ @@ -66,7 +67,7 @@ func dataSourceIBMContainerVPCClusterALB() *schema.Resource { } func dataSourceIBMContainerVpcALBRead(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).VpcContainerAPI() + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } diff --git a/ibm/data_source_ibm_container_vpc_alb_test.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_alb_test.go similarity index 80% rename from ibm/data_source_ibm_container_vpc_alb_test.go rename to ibm/service/kubernetes/data_source_ibm_container_vpc_alb_test.go index ed5f4367b..8d64b1270 100644 --- a/ibm/data_source_ibm_container_vpc_alb_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_alb_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMContainerVPCClusterALBDataSource_basic(t *testing.T) { enable := true name := fmt.Sprintf("tf-vpc-alb-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerVPCClusterALBDataSourceConfig(enable, name), @@ -29,9 +31,9 @@ func TestAccIBMContainerVPCClusterALBDataSource_basic(t *testing.T) { } func testAccCheckIBMContainerVPCClusterALBDataSourceConfig(enable bool, name string) string { - return testAccCheckIBMVpcContainerALBBasic(enable, name) + fmt.Sprintf(` + return testAccCheckIBMVpcContainerALBBasic(enable, name) + ` data "ibm_container_vpc_cluster_alb" "testacc_ds_alb" { alb_id = ibm_container_vpc_cluster.cluster.albs.0.id } -`) +` } diff --git a/ibm/data_source_ibm_container_vpc_cluster.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go similarity index 78% rename from ibm/data_source_ibm_container_vpc_cluster.go rename to ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go index 315126334..332a06ee5 100644 --- a/ibm/data_source_ibm_container_vpc_cluster.go +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go @@ -1,13 +1,16 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" "log" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +18,7 @@ const ( _OPENSHIFT = "_openshift" ) -func dataSourceIBMContainerVPCCluster() *schema.Resource { +func DataSourceIBMContainerVPCCluster() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerClusterVPCRead, @@ -32,6 +35,9 @@ func dataSourceIBMContainerVPCCluster() *schema.Resource { Type: schema.TypeString, Optional: true, ExactlyOneOf: []string{"cluster_name_id", "name"}, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_vpc_cluster", + "name"), }, "worker_count": { Description: "Number of workers", @@ -68,6 +74,10 @@ func dataSourceIBMContainerVPCCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "host_pool_id": { + Type: schema.TypeString, + Computed: true, + }, "labels": { Type: schema.TypeMap, Computed: true, @@ -115,7 +125,7 @@ func dataSourceIBMContainerVPCCluster() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "all", - ValidateFunc: validateAllowedStringValue([]string{"private", "public", "all"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"private", "public", "all"}), }, "albs": { Type: schema.TypeList, @@ -252,32 +262,36 @@ func dataSourceIBMContainerVPCCluster() *schema.Resource { Computed: true, Description: "email id of the key owner", }, - - ResourceControllerURL: { + "image_security_enforcement": { + Type: schema.TypeBool, + Computed: true, + Description: "True if image security enforcement is enabled", + }, + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -286,8 +300,22 @@ func dataSourceIBMContainerVPCCluster() *schema.Resource { } } +func DataSourceIBMContainerVPCClusterValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Optional: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVPCClusterValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_cluster", Schema: validateSchema} + return &iBMContainerVPCClusterValidator +} func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -308,7 +336,7 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface cls, err := csClient.Clusters().GetCluster(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving container vpc cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving container vpc cluster: %s", err) } d.SetId(cls.ID) @@ -336,7 +364,7 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface workerFields, err := csClient.Workers().ListWorkers(clusterID, false, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } workers := make([]string, len(workerFields)) for i, worker := range workerFields { @@ -348,33 +376,33 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface //Get worker pools pools, err := csClient.WorkerPools().ListWorkerPools(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving worker pools for container vpc cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving worker pools for container vpc cluster: %s", err) } - d.Set("worker_pools", flattenVpcWorkerPools(pools)) + d.Set("worker_pools", flex.FlattenVpcWorkerPools(pools)) if !strings.HasSuffix(cls.MasterKubeVersion, _OPENSHIFT) { albs, err := csClient.Albs().ListClusterAlbs(clusterID, targetEnv) if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") { - return fmt.Errorf("Error retrieving alb's of the cluster %s: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", clusterID, err) } filterType := d.Get("alb_type").(string) - filteredAlbs := flattenVpcAlbs(albs, filterType) + filteredAlbs := flex.FlattenVpcAlbs(albs, filterType) d.Set("albs", filteredAlbs) } - tags, err := GetTagsUsingCRN(meta, cls.CRN) + tags, err := flex.GetTagsUsingCRN(meta, cls.CRN) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) } d.Set("tags", tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - csClientv1, err := meta.(ClientSession).ContainerAPI() + csClientv1, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -399,11 +427,12 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface d.Set("api_key_owner_email", apikeyConfig.Email) } } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") - d.Set(ResourceName, cls.Name) - d.Set(ResourceCRN, cls.CRN) - d.Set(ResourceStatus, cls.State) - d.Set(ResourceGroupName, cls.ResourceGroupName) + d.Set("image_security_enforcement", cls.ImageSecurityEnabled) + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceName, cls.Name) + d.Set(flex.ResourceCRN, cls.CRN) + d.Set(flex.ResourceStatus, cls.State) + d.Set(flex.ResourceGroupName, cls.ResourceGroupName) return nil } diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_test.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_test.go new file mode 100644 index 000000000..09273aaa2 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_test.go @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerVPCClusterDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterDataSource(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster.testacc_ds_cluster", "id"), + resource.TestCheckResourceAttrSet("data.ibm_container_cluster_config.testacc_ds_cluster", "id"), + ), + }, + }, + }) +} + +func TestAccIBMContainerVPCClusterDataSource_DedicatedHost(t *testing.T) { + clusterName := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + hostPoolID := acc.HostPoolID + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterDataSourceDedicatedHost( + clusterName, + acc.IksClusterVpcID, + "bx2d.4x16", + acc.IksClusterSubnetID, + acc.IksClusterResourceGroupID, + hostPoolID, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_vpc_cluster.testacc_cluster_dedicatedhost", "worker_pools.0.host_pool_id", hostPoolID), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerVPCClusterDataSource(name string) string { + return testAccCheckIBMContainerVpcClusterBasic(name) + ` +data "ibm_container_vpc_cluster" "testacc_ds_cluster" { + cluster_name_id = ibm_container_vpc_cluster.cluster.id +} +data "ibm_container_cluster_config" "testacc_ds_cluster" { + cluster_name_id = ibm_container_vpc_cluster.cluster.id + } +` +} + +func testAccCheckIBMContainerVPCClusterDataSourceDedicatedHost(name, vpcID, flavor, subnetID, rgroupID, hostpoolID string) string { + return testAccCheckIBMContainerVpcClusterDedicatedHostSetting(name, vpcID, flavor, subnetID, rgroupID, hostpoolID) + ` +data "ibm_container_vpc_cluster" "testacc_cluster_dedicatedhost" { + name = ibm_container_vpc_cluster.testacc_dhost_vpc_cluster.name +} +` +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker.go new file mode 100644 index 000000000..81ed36a2c --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker.go @@ -0,0 +1,146 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerVPCClusterWorker() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMContainerVPCClusterWorkerRead, + + Schema: map[string]*schema.Schema{ + "worker_id": { + Description: "ID of the worker", + Type: schema.TypeString, + Required: true, + }, + "cluster_name_id": { + Description: "Name or ID of the cluster", + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_vpc_cluster_worker", + "cluster_name_id"), + }, + "flavor": { + Description: "flavor of the worker", + Type: schema.TypeString, + Computed: true, + }, + "kube_version": { + Description: "kube version of the worker", + Type: schema.TypeString, + Computed: true, + }, + "state": { + Description: "State of the worker", + Type: schema.TypeString, + Computed: true, + }, + "pool_id": { + Description: "worker pool id", + Type: schema.TypeString, + Computed: true, + }, + "pool_name": { + Description: "worker pool name", + Type: schema.TypeString, + Computed: true, + }, + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cidr": { + Type: schema.TypeString, + Computed: true, + }, + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + "host_pool_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the dedicated host pool this worker is associated with", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + }, + }, + } +} +func DataSourceIBMContainerVPCClusterWorkerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_name_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVPCClusterWorkerValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_cluster_worker", Schema: validateSchema} + return &iBMContainerVPCClusterWorkerValidator +} + +func dataSourceIBMContainerVPCClusterWorkerRead(d *schema.ResourceData, meta interface{}) error { + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + + wrkAPI := csClient.Workers() + workerID := d.Get("worker_id").(string) + clusterID := d.Get("cluster_name_id").(string) + + workerFields, err := wrkAPI.Get(clusterID, workerID, targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving worker: %s", err) + } + + d.SetId(workerFields.ID) + d.Set("flavor", workerFields.Flavor) + d.Set("kube_version", workerFields.KubeVersion.Actual) + d.Set("state", workerFields.Health.State) + d.Set("pool_id", workerFields.PoolID) + d.Set("pool_name", workerFields.PoolName) + d.Set("host_pool_id", workerFields.HostPoolID) + d.Set("network_interfaces", flex.FlattenNetworkInterfaces(workerFields.NetworkInterfaces)) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") + + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker_test.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker_test.go new file mode 100644 index 000000000..4c1d9775f --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster_worker_test.go @@ -0,0 +1,71 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerVPCClusterWorkerDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterWorkerDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster_worker.testacc_ds_worker", "id"), + ), + }, + }, + }) +} + +func TestAccIBMContainerVPCClusterWorkerDataSource_dedicatedhost(t *testing.T) { + clusterName := acc.ClusterName + hostpoolID := acc.HostPoolID + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterWorkerDataSourceDedicatedHostConfig(clusterName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_vpc_cluster_worker.dhost_vpc_worker", "host_pool_id", hostpoolID), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerVPCClusterWorkerDataSourceConfig(name string) string { + return testAccCheckIBMVpcContainerWorkerPoolBasic(name) + ` + data "ibm_container_vpc_cluster" "testacc_ds_cluster" { + cluster_name_id = ibm_container_vpc_cluster.cluster.id + } + data "ibm_container_vpc_cluster_worker" "testacc_ds_worker" { + cluster_name_id = ibm_container_vpc_cluster.cluster.id + worker_id = data.ibm_container_vpc_cluster.testacc_ds_cluster.workers[0] + } +` +} + +func testAccCheckIBMContainerVPCClusterWorkerDataSourceDedicatedHostConfig(clusterName string) string { + return fmt.Sprintf(` + data "ibm_container_vpc_cluster" "dhost_vpc_cluster" { + cluster_name_id = "%s" + } + data "ibm_container_vpc_cluster_worker" "dhost_vpc_worker" { + cluster_name_id = "%s" + worker_id = data.ibm_container_vpc_cluster.dhost_vpc_cluster.workers[0] + } + `, clusterName, clusterName) +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool.go new file mode 100644 index 000000000..1f90a2866 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool.go @@ -0,0 +1,144 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMContainerVpcClusterWorkerPool() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMContainerVpcClusterWorkerPoolRead, + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + Description: "Cluster name", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_vpc_cluster_worker_pool", + "cluster"), + }, + "worker_pool_name": { + Type: schema.TypeString, + Required: true, + Description: "worker pool name", + }, + "flavor": { + Type: schema.TypeString, + Computed: true, + }, + "zones": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "labels": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + }, + "worker_count": { + Type: schema.TypeInt, + Computed: true, + }, + "isolation": { + Type: schema.TypeString, + Computed: true, + }, + "host_pool_id": { + Type: schema.TypeString, + Computed: true, + }, + "kms_instance_id": { + Type: schema.TypeString, + Computed: true, + }, + "crk": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} +func DataSourceIBMContainerVpcClusterWorkerPoolValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVpcClusterWorkerPoolValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_cluster_worker_pool", Schema: validateSchema} + return &iBMContainerVpcClusterWorkerPoolValidator +} +func dataSourceIBMContainerVpcClusterWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + clusterName := d.Get("cluster").(string) + workerPoolName := d.Get("worker_pool_name").(string) + workerPoolsAPI := wpClient.WorkerPools() + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + + workerPool, err := workerPoolsAPI.GetWorkerPool(clusterName, workerPoolName, targetEnv) + if err != nil { + return err + } + + var zones = make([]map[string]interface{}, 0) + for _, zone := range workerPool.Zones { + for _, subnet := range zone.Subnets { + zoneInfo := map[string]interface{}{ + "name": zone.ID, + "subnet_id": subnet.ID, + } + zones = append(zones, zoneInfo) + } + } + d.Set("worker_pool_name", workerPool.PoolName) + d.Set("flavor", workerPool.Flavor) + d.Set("worker_count", workerPool.WorkerCount) + d.Set("labels", workerPool.Labels) + d.Set("zones", zones) + d.Set("cluster", clusterName) + d.Set("vpc_id", workerPool.VpcID) + d.Set("isolation", workerPool.Isolation) + d.Set("resource_group_id", targetEnv.ResourceGroup) + d.Set("host_pool_id", workerPool.HostPoolID) + if workerPool.WorkerVolumeEncryption != nil { + d.Set("kms_instance_id", workerPool.WorkerVolumeEncryption.KmsInstanceID) + d.Set("crk", workerPool.WorkerVolumeEncryption.WorkerVolumeCRKID) + } + d.SetId(workerPool.ID) + return nil +} diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool_test.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool_test.go new file mode 100644 index 000000000..deeafe771 --- /dev/null +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_worker_pool_test.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMContainerVPCClusterWorkerPoolDataSource_basic(t *testing.T) { + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster_worker_pool.testacc_ds_worker_pool", "id"), + ), + }, + }, + }) +} + +func TestAccIBMContainerVPCClusterWorkerPoolDataSource_dedicatedhost(t *testing.T) { + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + hostpoolID := acc.HostPoolID + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfigDedicatedHost(name, hostpoolID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_container_vpc_worker_pool.vpc_worker_pool", "host_pool_id", hostpoolID), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfig(name string) string { + return testAccCheckIBMVpcContainerWorkerPoolBasic(name) + ` + data "ibm_container_vpc_cluster_worker_pool" "testacc_ds_worker_pool" { + cluster = "${ibm_container_vpc_cluster.cluster.id}" + worker_pool_name = "${ibm_container_vpc_worker_pool.test_pool.worker_pool_name}" + } +` +} + +func TestAccIBMContainerVPCClusterWorkerPoolDataSourceEnvvar(t *testing.T) { + name := fmt.Sprintf("tf-vpc-wp-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceEnvvar(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_container_vpc_cluster_worker_pool.testacc_ds_worker_pool", "id"), + resource.TestCheckResourceAttr("data.ibm_container_vpc_cluster_worker_pool.testacc_ds_worker_pool", "crk", acc.CrkID), + resource.TestCheckResourceAttr("data.ibm_container_vpc_cluster_worker_pool.testacc_ds_worker_pool", "kms_instance_id", acc.KmsInstanceID), + ), + }, + }, + }) +} + +func testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceConfigDedicatedHost(name, hostpoolID string) string { + return testAccCheckIBMVpcContainerWorkerPoolDedicatedHostCreate( + acc.ClusterName, name, "bx2d.4x16", acc.IksClusterSubnetID, acc.IksClusterVpcID, acc.IksClusterResourceGroupID, hostpoolID) + ` + data "ibm_container_vpc_worker_pool" "vpc_worker_pool" { + cluster = "${ibm_container_vpc_worker_pool.vpc_worker_pool.cluster}" + worker_pool_name = "${ibm_container_vpc_worker_pool.vpc_worker_pool.worker_pool_name}" + depends_on = [ + ibm_container_vpc_worker_pool.vpc_worker_pool + ] + } +` +} + +func testAccCheckIBMContainerVPCClusterWorkerPoolDataSourceEnvvar(name string) string { + return testAccCheckIBMVpcContainerWorkerPoolEnvvar(name) + ` + data "ibm_container_vpc_cluster_worker_pool" "testacc_ds_worker_pool" { + cluster = "${ibm_container_vpc_worker_pool.test_pool.cluster}" + worker_pool_name = "${ibm_container_vpc_worker_pool.test_pool.worker_pool_name}" + } +` +} diff --git a/ibm/data_source_ibm_container_worker_pool.go b/ibm/service/kubernetes/data_source_ibm_container_worker_pool.go similarity index 75% rename from ibm/data_source_ibm_container_worker_pool.go rename to ibm/service/kubernetes/data_source_ibm_container_worker_pool.go index 8ef9e3339..6c8d5982e 100644 --- a/ibm/data_source_ibm_container_worker_pool.go +++ b/ibm/service/kubernetes/data_source_ibm_container_worker_pool.go @@ -1,15 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMContainerWorkerPool() *schema.Resource { +func DataSourceIBMContainerWorkerPool() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMContainerWorkerPoolRead, @@ -18,6 +21,9 @@ func dataSourceIBMContainerWorkerPool() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Name or ID of the cluster", + ValidateFunc: validate.InvokeDataSourceValidator( + "ibm_container_worker_pool", + "cluster"), }, "worker_pool_name": { @@ -103,9 +109,22 @@ func dataSourceIBMContainerWorkerPool() *schema.Resource { }, } } - +func DataSourceIBMContainerWorkerPoolValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerWorkerPoolValidator := validate.ResourceValidator{ResourceName: "ibm_container_worker_pool", Schema: validateSchema} + return &iBMContainerWorkerPoolValidator +} func dataSourceIBMContainerWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -141,7 +160,7 @@ func dataSourceIBMContainerWorkerPoolRead(d *schema.ResourceData, meta interface if workerPool.Labels != nil { d.Set("labels", workerPool.Labels) } - d.Set("zones", flattenZones(workerPool.Zones)) + d.Set("zones", flex.FlattenZones(workerPool.Zones)) if strings.Contains(machineType, "encrypted") { d.Set("disk_encryption", true) } else { diff --git a/ibm/data_source_ibm_container_worker_pool_test.go b/ibm/service/kubernetes/data_source_ibm_container_worker_pool_test.go similarity index 84% rename from ibm/data_source_ibm_container_worker_pool_test.go rename to ibm/service/kubernetes/data_source_ibm_container_worker_pool_test.go index 2dcd32d9e..37653de40 100644 --- a/ibm/data_source_ibm_container_worker_pool_test.go +++ b/ibm/service/kubernetes/data_source_ibm_container_worker_pool_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMContainerWorkerPoolDataSource_basic(t *testing.T) { workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerWorkerPoolDataSourceConfig(clusterName, workerPoolName), @@ -57,5 +59,5 @@ resource "ibm_container_worker_pool" "test_pool" { data "ibm_container_worker_pool" "testacc_ds_worker_pool"{ worker_pool_name = ibm_container_worker_pool.test_pool.worker_pool_name cluster = ibm_container_cluster.testacc_cluster.id -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeVersion, workerPoolName, machineType) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeVersion, workerPoolName, acc.MachineType) } diff --git a/ibm/resource_ibm_container_addons.go b/ibm/service/kubernetes/resource_ibm_container_addons.go similarity index 88% rename from ibm/resource_ibm_container_addons.go rename to ibm/service/kubernetes/resource_ibm_container_addons.go index e071f4819..b67493cc7 100644 --- a/ibm/resource_ibm_container_addons.go +++ b/ibm/service/kubernetes/resource_ibm_container_addons.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "bytes" @@ -15,10 +15,12 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMContainerAddOns() *schema.Resource { +func ResourceIBMContainerAddOns() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerAddOnsCreate, Read: resourceIBMContainerAddOnsRead, @@ -36,6 +38,9 @@ func resourceIBMContainerAddOns() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Cluster Name or ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_addons", + "cluster"), }, "resource_group_id": { Type: schema.TypeString, @@ -114,8 +119,22 @@ func resourceIBMContainerAddOns() *schema.Resource { }, } } +func ResourceIBMContainerAddOnsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerAddOnsValidator := validate.ResourceValidator{ResourceName: "ibm_container_addons", Schema: validateSchema} + return &iBMContainerAddOnsValidator +} func resourceIBMContainerAddOnsCreate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -162,7 +181,7 @@ func expandAddOns(d *schema.ResourceData, meta interface{}, cluster string, targ } } if len(existingAddons) > 0 { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return addOns, err } @@ -174,13 +193,13 @@ func expandAddOns(d *schema.ResourceData, meta interface{}, cluster string, targ if existAddon.Name == ao["name"].(string) { exist = true if existAddon.Version != ao["version"].(string) { - if (ao["version"].(string) == existAddon.TargetVersion) && (StringContains(existAddon.AllowedUpgradeVersion, ao["version"].(string))) { + if flex.StringContains(existAddon.AllowedUpgradeVersion, ao["version"].(string)) { // This block upgrates addon version if addon has `allowed_upgrade_versions` err := updateAddOnVersion(d, meta, ao, cluster, targetEnv) if err != nil { return addOns, err } - } else if (ao["version"].(string) == existAddon.TargetVersion) && (!StringContains(existAddon.AllowedUpgradeVersion, ao["version"].(string))) { + } else if (ao["version"].(string) == existAddon.TargetVersion) && (!flex.StringContains(existAddon.AllowedUpgradeVersion, ao["version"].(string))) { // This block reinstalls addons that dont have upgradation capability //Uninstall AddOn with old version rmParams := v1.ConfigureAddOns{} @@ -232,7 +251,7 @@ func expandAddOns(d *schema.ResourceData, meta interface{}, cluster string, targ return addOns, nil } func updateAddOnVersion(d *schema.ResourceData, meta interface{}, u map[string]interface{}, cluster string, targetEnv v1.ClusterTargetHeader) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -255,7 +274,7 @@ func updateAddOnVersion(d *schema.ResourceData, meta interface{}, u map[string]i return nil } func resourceIBMContainerAddOnsRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -314,7 +333,7 @@ func flattenAddOns(result []v1.AddOn) (resp *schema.Set, err error) { return schema.NewSet(resourceIBMContainerAddonsHash, addOns), nil } func resourceIBMContainerAddOnsUpdate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -341,7 +360,7 @@ func resourceIBMContainerAddOnsUpdate(d *schema.ResourceData, meta interface{}) for _, oA := range os.List() { oldPack := oA.(map[string]interface{}) if (strings.Compare(newPack["name"].(string), oldPack["name"].(string)) == 0) && (strings.Compare(newPack["version"].(string), oldPack["version"].(string)) != 0) { - if (newPack["version"].(string) == oldPack["target_version"].(string)) && (StringContains(expandStringList(oldPack["allowed_upgrade_versions"].([]interface{})), newPack["version"].(string))) { + if flex.StringContains(flex.ExpandStringList(oldPack["allowed_upgrade_versions"].([]interface{})), newPack["version"].(string)) { // This block upgrates addon version if addon has `allowed_upgrade_versions` err := updateAddOnVersion(d, meta, newPack, cluster, targetEnv) if err != nil { @@ -349,7 +368,7 @@ func resourceIBMContainerAddOnsUpdate(d *schema.ResourceData, meta interface{}) } ns.Remove(nA) os.Remove(oA) - } else if (newPack["version"].(string) == oldPack["target_version"].(string)) && (!StringContains(expandStringList(oldPack["allowed_upgrade_versions"].([]interface{})), newPack["version"].(string))) { + } else if (newPack["version"].(string) == oldPack["target_version"].(string)) && (!flex.StringContains(flex.ExpandStringList(oldPack["allowed_upgrade_versions"].([]interface{})), newPack["version"].(string))) { // This block reinstalls addons that dont have upgradation capability //Uninstall AddOn with old version rmParams := v1.ConfigureAddOns{} @@ -438,7 +457,7 @@ func resourceIBMContainerAddOnsUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMContainerAddOnsDelete(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -463,7 +482,7 @@ func resourceIBMContainerAddOnsDelete(d *schema.ResourceData, meta interface{}) return nil } func waitForContainerAddOns(d *schema.ResourceData, meta interface{}, cluster, timeout string) (interface{}, error) { - addOnClient, err := meta.(ClientSession).ContainerAPI() + addOnClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } @@ -499,7 +518,7 @@ func waitForContainerAddOns(d *schema.ResourceData, meta interface{}, cluster, t } func resourceIBMContainerAddOnsExists(d *schema.ResourceData, meta interface{}) (bool, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } @@ -518,7 +537,7 @@ func resourceIBMContainerAddOnsExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("[ERROR] Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container addons: %s", err) } return true, nil @@ -530,5 +549,5 @@ func resourceIBMContainerAddonsHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", a["name"].(string))) buf.WriteString(fmt.Sprintf("%s-", a["version"].(string))) - return hashcode.String(buf.String()) + return conns.String(buf.String()) } diff --git a/ibm/resource_ibm_container_addons_test.go b/ibm/service/kubernetes/resource_ibm_container_addons_test.go similarity index 89% rename from ibm/resource_ibm_container_addons_test.go rename to ibm/service/kubernetes/resource_ibm_container_addons_test.go index 7cb9ebcef..22ba25036 100644 --- a/ibm/resource_ibm_container_addons_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_addons_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,8 +22,8 @@ func TestAccIBMContainerAddOns_Basic(t *testing.T) { name := fmt.Sprintf("tf-cluster-addon-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerAddOnsDestroy, Steps: []resource.TestStep{ { @@ -54,7 +57,7 @@ func testAccCheckIBMContainerAddOnsDestroy(s *terraform.State) error { targetEnv := v1.ClusterTargetHeader{ Region: "us-south", } - csClient, err := testAccProvider.Meta().(ClientSession).ContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -64,7 +67,7 @@ func testAccCheckIBMContainerAddOnsDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("AddOns still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if AddOns (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if AddOns (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil diff --git a/ibm/resource_ibm_container_alb.go b/ibm/service/kubernetes/resource_ibm_container_alb.go similarity index 83% rename from ibm/resource_ibm_container_alb.go rename to ibm/service/kubernetes/resource_ibm_container_alb.go index 9e00bdaea..58e7978d7 100644 --- a/ibm/resource_ibm_container_alb.go +++ b/ibm/service/kubernetes/resource_ibm_container_alb.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -13,9 +13,10 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) -func resourceIBMContainerALB() *schema.Resource { +func ResourceIBMContainerALB() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerALBCreate, Read: resourceIBMContainerALBRead, @@ -71,6 +72,16 @@ func resourceIBMContainerALB() *schema.Resource { Computed: true, Description: "ALB name", }, + "replicas": { + Type: schema.TypeString, + Computed: true, + Description: "Desired number of ALB replicas.", + }, + "resize": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicate whether resizing should be done", + }, "zone": { Type: schema.TypeString, Computed: true, @@ -86,7 +97,7 @@ func resourceIBMContainerALB() *schema.Resource { } func resourceIBMContainerALBCreate(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).ContainerAPI() + albClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -98,7 +109,7 @@ func resourceIBMContainerALBCreate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("disable_deployment"); ok { disableDeployment = v.(bool) } else { - return fmt.Errorf("Provide either `enable` or `disable_deployment`") + return fmt.Errorf("[ERROR] Provide either `enable` or `disable_deployment`") } numOfInstances := "2" @@ -116,8 +127,7 @@ func resourceIBMContainerALBCreate(d *schema.ResourceData, meta interface{}) err _, err = waitForClusterAvailable(d, meta, albID) if err != nil { - return fmt.Errorf( - "Error waiting for cluster resources availabilty (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster resources availabilty (%s) : %s", d.Id(), err) } albAPI := albClient.Albs() @@ -132,15 +142,14 @@ func resourceIBMContainerALBCreate(d *schema.ResourceData, meta interface{}) err d.SetId(albID) _, err = waitForContainerALB(d, meta, albID, schema.TimeoutCreate, enable, disableDeployment) if err != nil { - return fmt.Errorf( - "Error waiting for create resource alb (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for create resource alb (%s) : %s", d.Id(), err) } return resourceIBMContainerALBRead(d, meta) } func resourceIBMContainerALBRead(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).ContainerAPI() + albClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -170,7 +179,7 @@ func resourceIBMContainerALBRead(d *schema.ResourceData, meta interface{}) error } func resourceIBMContainerALBUpdate(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).ContainerAPI() + albClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -192,8 +201,7 @@ func resourceIBMContainerALBUpdate(d *schema.ResourceData, meta interface{}) err _, err = waitForClusterAvailable(d, meta, albID) if err != nil { - return fmt.Errorf( - "Error waiting for cluster resources availabilty (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster resources availabilty (%s) : %s", d.Id(), err) } err = albAPI.ConfigureALB(albID, params, disableDeployment, targetEnv) @@ -202,8 +210,7 @@ func resourceIBMContainerALBUpdate(d *schema.ResourceData, meta interface{}) err } _, err = waitForContainerALB(d, meta, albID, schema.TimeoutUpdate, enable, disableDeployment) if err != nil { - return fmt.Errorf( - "Error waiting for updating resource alb (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for updating resource alb (%s) : %s", d.Id(), err) } } @@ -211,7 +218,7 @@ func resourceIBMContainerALBUpdate(d *schema.ResourceData, meta interface{}) err } func waitForContainerALB(d *schema.ResourceData, meta interface{}, albID, timeout string, enable, disableDeployment bool) (interface{}, error) { - albClient, err := meta.(ClientSession).ContainerAPI() + albClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } @@ -227,16 +234,16 @@ func waitForContainerALB(d *schema.ResourceData, meta interface{}, albID, timeou alb, err := albClient.Albs().GetALB(albID, targetEnv) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The resource alb %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The resource alb %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } if enable { - if alb.Enable == false { + if !alb.Enable { return alb, "pending", nil } } else if disableDeployment { - if alb.Enable == true { + if alb.Enable { return alb, "pending", nil } } @@ -258,7 +265,7 @@ func resourceIBMContainerALBDelete(d *schema.ResourceData, meta interface{}) err // WaitForWorkerAvailable Waits for worker creation func waitForClusterAvailable(d *schema.ResourceData, meta interface{}, albID string) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -294,7 +301,7 @@ func getAlbTargetHeader(d *schema.ResourceData, meta interface{}) (v1.ClusterTar region = v.(string) } - sess, err := meta.(ClientSession).BluemixSession() + sess, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return v1.ClusterTargetHeader{}, err } diff --git a/ibm/resource_ibm_container_alb_cert.go b/ibm/service/kubernetes/resource_ibm_container_alb_cert.go similarity index 81% rename from ibm/resource_ibm_container_alb_cert.go rename to ibm/service/kubernetes/resource_ibm_container_alb_cert.go index da8bcad53..e96683ed7 100644 --- a/ibm/resource_ibm_container_alb_cert.go +++ b/ibm/service/kubernetes/resource_ibm_container_alb_cert.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -13,9 +13,12 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMContainerALBCert() *schema.Resource { +func ResourceIBMContainerALBCert() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerALBCertCreate, Read: resourceIBMContainerALBCertRead, @@ -41,6 +44,9 @@ func resourceIBMContainerALBCert() *schema.Resource { Required: true, ForceNew: true, Description: "Cluster ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_alb_cert", + "cluster_id"), }, "secret_name": { Type: schema.TypeString, @@ -96,9 +102,22 @@ func resourceIBMContainerALBCert() *schema.Resource { }, } } - +func ResourceIBMContainerALBCertValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerALBCertValidator := validate.ResourceValidator{ResourceName: "ibm_container_alb_cert", Schema: validateSchema} + return &iBMContainerALBCertValidator +} func resourceIBMContainerALBCertCreate(d *schema.ResourceData, meta interface{}) error { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -128,19 +147,18 @@ func resourceIBMContainerALBCertCreate(d *schema.ResourceData, meta interface{}) d.SetId(fmt.Sprintf("%s/%s/%s", cluster, secretName, response.Namespace)) _, err = waitForContainerALBCert(d, meta, schema.TimeoutCreate) if err != nil { - return fmt.Errorf( - "Error waiting for create resource alb cert (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for create resource alb cert (%s) : %s", d.Id(), err) } return resourceIBMContainerALBCertRead(d, meta) } func resourceIBMContainerALBCertRead(d *schema.ResourceData, meta interface{}) error { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -172,14 +190,14 @@ func resourceIBMContainerALBCertRead(d *schema.ResourceData, meta interface{}) e } func resourceIBMContainerALBCertDelete(d *schema.ResourceData, meta interface{}) error { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } ingressAPI := ingressClient.Ingresses() - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -208,11 +226,11 @@ func resourceIBMContainerALBCertDelete(d *schema.ResourceData, meta interface{}) } func waitForALBCertDelete(d *schema.ResourceData, meta interface{}, timeout string) (interface{}, error) { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -249,11 +267,11 @@ func waitForALBCertDelete(d *schema.ResourceData, meta interface{}, timeout stri } func resourceIBMContainerALBCertUpdate(d *schema.ResourceData, meta interface{}) error { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -282,20 +300,19 @@ func resourceIBMContainerALBCertUpdate(d *schema.ResourceData, meta interface{}) _, err = waitForContainerALBCert(d, meta, schema.TimeoutUpdate) if err != nil { - return fmt.Errorf( - "Error waiting for updating resource alb cert (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for updating resource alb cert (%s) : %s", d.Id(), err) } } return resourceIBMContainerALBCertRead(d, meta) } func resourceIBMContainerALBCertExists(d *schema.ResourceData, meta interface{}) (bool, error) { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -315,18 +332,18 @@ func resourceIBMContainerALBCertExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting ingress secret: %s", err) } return ingressSecretConfig.Cluster == clusterID && ingressSecretConfig.Name == secretName, nil } func waitForContainerALBCert(d *schema.ResourceData, meta interface{}, timeout string) (interface{}, error) { - ingressClient, err := meta.(ClientSession).VpcContainerAPI() + ingressClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -351,7 +368,7 @@ func waitForContainerALBCert(d *schema.ResourceData, meta interface{}, timeout s } if alb.Status != "created" { if strings.Contains(alb.Status, "failed") { - return alb, "failed", fmt.Errorf("The resource alb cert %s failed: %v", d.Id(), err) + return alb, "failed", fmt.Errorf("[ERROR] The resource alb cert %s failed: %v", d.Id(), err) } if alb.Status == "updated" { diff --git a/ibm/resource_ibm_container_alb_cert_test.go b/ibm/service/kubernetes/resource_ibm_container_alb_cert_test.go similarity index 79% rename from ibm/resource_ibm_container_alb_cert_test.go rename to ibm/service/kubernetes/resource_ibm_container_alb_cert_test.go index abd8fefe1..3779f9ab6 100644 --- a/ibm/resource_ibm_container_alb_cert_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_alb_cert_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,8 +22,8 @@ func TestAccIBMContainerALBCert_Basic(t *testing.T) { secretName := fmt.Sprintf("tf-container-alb-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerALBCertDestroy, Steps: []resource.TestStep{ { @@ -28,7 +32,7 @@ func TestAccIBMContainerALBCert_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_container_alb_cert.cert", "secret_name", secretName), resource.TestCheckResourceAttr( - "ibm_container_alb_cert.cert", "cert_crn", certCRN), + "ibm_container_alb_cert.cert", "cert_crn", acc.CertCRN), resource.TestCheckResourceAttr( "ibm_container_alb_cert.cert", "namespace", "ibm-cert-store"), ), @@ -39,7 +43,7 @@ func TestAccIBMContainerALBCert_Basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_container_alb_cert.cert", "secret_name", secretName), resource.TestCheckResourceAttr( - "ibm_container_alb_cert.cert", "cert_crn", updatedCertCRN), + "ibm_container_alb_cert.cert", "cert_crn", acc.UpdatedCertCRN), resource.TestCheckResourceAttr( "ibm_container_alb_cert.cert", "namespace", "ibm-cert-store"), ), @@ -60,7 +64,7 @@ func testAccCheckIBMContainerALBCertDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -70,7 +74,7 @@ func testAccCheckIBMContainerALBCertDestroy(s *terraform.State) error { if len(parts) > 2 && len(parts[2]) > 0 { namespace = parts[2] } - ingressClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + ingressClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -80,7 +84,7 @@ func testAccCheckIBMContainerALBCertDestroy(s *terraform.State) error { if err == nil && &resp != nil && resp.Status == "deleted" { return nil } else if err == nil || !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -104,7 +108,7 @@ resource "ibm_container_alb_cert" "cert" { secret_name = "%s" cluster_id = ibm_container_cluster.testacc_cluster.id namespace = "ibm-cert-store" -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, certCRN, secretName) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.CertCRN, secretName) } func testAccCheckIBMContainerALBCertUpdate(clusterName, secretName string) string { @@ -125,5 +129,5 @@ resource "ibm_container_alb_cert" "cert" { secret_name = "%s" cluster_id = ibm_container_cluster.testacc_cluster.id namespace = "ibm-cert-store" -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, updatedCertCRN, secretName) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.UpdatedCertCRN, secretName) } diff --git a/ibm/service/kubernetes/resource_ibm_container_alb_create.go b/ibm/service/kubernetes/resource_ibm_container_alb_create.go new file mode 100644 index 000000000..a6d0baaf9 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_alb_create.go @@ -0,0 +1,198 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMContainerAlbCreate() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMContainerClassicAlbCreate, + Read: resourceIBMContainerALBRead, + Update: resourceIBMContainerALBUpdate, + Delete: resourceIBMContainerALBDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + //post req + "enable": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "If set to true, the ALB is enabled by default.", + }, + "ingress_image": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The type of Ingress image that you want to use for your ALB deployment.", + }, + "ip": { + Type: schema.TypeString, + Optional: true, + //ForceNew: true, + Description: "The IP address that you want to assign to the ALB.", + }, + "nlb_version": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The version of the network load balancer that you want to use for the ALB.", + }, + "alb_type": { + Type: schema.TypeString, + Required: true, + //ForceNew: true, + Description: "The type of ALB that you want to create.", + }, + "vlan_id": { + Type: schema.TypeString, + Required: true, + //ForceNew: true, + Description: "The VLAN ID that you want to use for your ALBs.", + }, + "zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The zone where you want to deploy the ALB.", + }, + "cluster": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the cluster that the ALB belongs to.", + ValidateFunc: validate.InvokeValidator( + "ibm_container_alb_create", + "cluster"), + }, + + //response + "alb_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the application load balancer (ALB).", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "ALB name", + }, + "disable_deployment": { + Type: schema.TypeBool, + Computed: true, + Description: "Set to true if ALB needs to be disabled", + }, + "user_ip": { + Type: schema.TypeString, + Computed: true, + Description: "IP assigned by the user", + }, + "replicas": { + Type: schema.TypeString, + Computed: true, + Description: "number of instances", + }, + "resize": { + Type: schema.TypeBool, + Computed: true, + Description: "resize", + }, + }, + } +} + +func resourceIBMContainerClassicAlbCreate(d *schema.ResourceData, meta interface{}) error { + log.Println("resourceIBMContainerClassicAlbCreate") + albClient, err := meta.(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + albAPI := albClient.Albs() + + // "cluster":"string" //mandatory + // "enableByDefault": true, + // "ingressImage": "string", + // "ip": "string", + // "nlbVersion": "string", + // "type": "string", //mandatory + // "vlanID": "string", //mandatory + // "zone": "string" //mandatory + + params := v1.CreateALB{} + + if v, ok := d.GetOkExists("alb_type"); ok { + params.Type = v.(string) + } + + if v, ok := d.GetOkExists("vlan_id"); ok { + params.VlanID = v.(string) + } + + if v, ok := d.GetOkExists("zone"); ok { + params.Zone = v.(string) + } + + if v, ok := d.GetOk("enable"); ok { + params.EnableByDefault = v.(bool) + } + + if v, ok := d.GetOk("ingress_image"); ok { + params.IngressImage = v.(string) + } + + if v, ok := d.GetOk("ip"); ok { + params.IP = v.(string) + } + + if v, ok := d.GetOk("nlb_version"); ok { + params.NLBVersion = v.(string) + } + var cluster string + if v, ok := d.GetOkExists("cluster"); ok { + cluster = v.(string) + } + + targetEnv, err := getAlbTargetHeader(d, meta) + if err != nil { + return err + } + + //v1.AlbCreateResp + albResp, err := albAPI.CreateALB(params, cluster, targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error creating ALb to the cluster %s", err) + } + + d.SetId(albResp.Alb) + return nil +} + +func ResourceIBMContainerAlbCreateValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerAlbCreateValidator := validate.ResourceValidator{ResourceName: "ibm_container_alb_create", Schema: validateSchema} + return &iBMContainerAlbCreateValidator +} diff --git a/ibm/service/kubernetes/resource_ibm_container_alb_create_test.go b/ibm/service/kubernetes/resource_ibm_container_alb_create_test.go new file mode 100644 index 000000000..4b12db996 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_alb_create_test.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMContainerALB_Create(t *testing.T) { + clusterName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerALBCreateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerALBCreate(clusterName, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_container_alb_create.alb", "enable", "true"), + resource.TestCheckResourceAttr("ibm_container_alb_create.alb", "alb_type", "private"), + resource.TestCheckResourceAttr("ibm_container_alb_create.alb", "vlan_id", acc.PrivateVlanID), + resource.TestCheckResourceAttr("ibm_container_alb_create.alb", "zone", acc.Zone), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckIBMContainerALBCreateDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_alb_create" { + continue + } + + albID := rs.Primary.ID + targetEnv := v1.ClusterTargetHeader{ + Region: "us-south", + } + + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + albAPI := csClient.Albs() + resp, err := albAPI.GetALB(albID, targetEnv) + + if err == nil { + return fmt.Errorf("Instance still exists: %s, values: %v", rs.Primary.ID, resp) + } else if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + return nil +} + +// you need to set up the followings +// IBM_PUBLIC_VLAN_ID +// IBM_PRIVATE_VLAN_ID +// IBM_DATACENTER +// IBM_WORKER_POOL_ZONE + +func testAccCheckIBMContainerALBCreate(clusterName string, enable bool) string { + config := fmt.Sprintf(`resource "ibm_container_cluster" "testacc_cluster" { + name = "%s" + datacenter = "%s" + default_pool_size = 1 + machine_type = "%s" + hardware = "shared" + public_vlan_id = "%s" + private_vlan_id = "%s" + timeouts { + create = "120m" + update = "120m" + } +} + +resource "ibm_container_alb_create" "alb" { + cluster=ibm_container_cluster.testacc_cluster.name + enable = "%t" + alb_type = "private" + vlan_id = ibm_container_cluster.testacc_cluster.private_vlan_id + zone = "%s" +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, enable, acc.Zone) + fmt.Println(config) + return config +} diff --git a/ibm/resource_ibm_container_alb_test.go b/ibm/service/kubernetes/resource_ibm_container_alb_test.go similarity index 80% rename from ibm/resource_ibm_container_alb_test.go rename to ibm/service/kubernetes/resource_ibm_container_alb_test.go index e6bab5f1b..98ee4232d 100644 --- a/ibm/resource_ibm_container_alb_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_alb_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -18,8 +21,8 @@ func TestAccIBMContainerALB_Basic(t *testing.T) { clusterName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerALBDestroy, Steps: []resource.TestStep{ { @@ -51,7 +54,7 @@ func testAccCheckIBMContainerALBDestroy(s *terraform.State) error { Region: "us-south", } - csClient, err := testAccProvider.Meta().(ClientSession).ContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -61,7 +64,7 @@ func testAccCheckIBMContainerALBDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Instance still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil @@ -86,5 +89,5 @@ resource "ibm_container_cluster" "testacc_cluster" { resource "ibm_container_alb" "alb" { alb_id = ibm_container_cluster.testacc_cluster.albs[0].id enable = "%t" -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, enable) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, enable) } diff --git a/ibm/resource_ibm_container_api_key_reset.go b/ibm/service/kubernetes/resource_ibm_container_api_key_reset.go similarity index 85% rename from ibm/resource_ibm_container_api_key_reset.go rename to ibm/service/kubernetes/resource_ibm_container_api_key_reset.go index 9461f5232..9b35aee55 100644 --- a/ibm/resource_ibm_container_api_key_reset.go +++ b/ibm/service/kubernetes/resource_ibm_container_api_key_reset.go @@ -1,15 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMContainerAPIKeyReset() *schema.Resource { +func ResourceIBMContainerAPIKeyReset() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerAPIKeyResetUpdate, Read: resourceIBMContainerAPIKeyResetRead, @@ -42,7 +44,7 @@ func resourceIBMContainerAPIKeyReset() *schema.Resource { func resourceIBMContainerAPIKeyResetUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("reset_api_key") { - apikeyClient, err := meta.(ClientSession).ContainerAPI() + apikeyClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -58,7 +60,7 @@ func resourceIBMContainerAPIKeyResetUpdate(d *schema.ResourceData, meta interfac return err } if targetEnv.ResourceGroup == "" { - defaultRg, err := defaultResourceGroup(meta) + defaultRg, err := flex.DefaultResourceGroup(meta) if err != nil { return err } diff --git a/ibm/resource_ibm_container_bind_service.go b/ibm/service/kubernetes/resource_ibm_container_bind_service.go similarity index 77% rename from ibm/resource_ibm_container_bind_service.go rename to ibm/service/kubernetes/resource_ibm_container_bind_service.go index bd5fca1c2..a2fe02250 100644 --- a/ibm/resource_ibm_container_bind_service.go +++ b/ibm/service/kubernetes/resource_ibm_container_bind_service.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -9,9 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMContainerBindService() *schema.Resource { +func ResourceIBMContainerBindService() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerBindServiceCreate, Read: resourceIBMContainerBindServiceRead, @@ -25,6 +28,9 @@ func resourceIBMContainerBindService() *schema.Resource { ForceNew: true, Required: true, Description: "Cluster name or ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_bind_service", + "cluster_name_id"), }, "service_instance_name": { Type: schema.TypeString, @@ -90,7 +96,7 @@ func resourceIBMContainerBindService() *schema.Resource { Optional: true, Description: "ID of the resource group.", ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "tags": { Type: schema.TypeSet, @@ -102,18 +108,32 @@ func resourceIBMContainerBindService() *schema.Resource { }, } } +func ResourceIBMContainerBindServiceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_name_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerBindServiceValidator := validate.ResourceValidator{ResourceName: "ibm_container_bind_service", Schema: validateSchema} + return &iBMContainerBindServiceValidator +} func getClusterTargetHeader(d *schema.ResourceData, meta interface{}) (v1.ClusterTargetHeader, error) { - _, err := meta.(ClientSession).BluemixSession() + _, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return v1.ClusterTargetHeader{}, err } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return v1.ClusterTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v1.ClusterTargetHeader{ AccountID: accountID, @@ -128,7 +148,7 @@ func getClusterTargetHeader(d *schema.ResourceData, meta interface{}) (v1.Cluste } func resourceIBMContainerBindServiceCreate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -140,7 +160,7 @@ func resourceIBMContainerBindServiceCreate(d *schema.ResourceData, meta interfac } else if serviceInstanceID, ok := d.GetOk("service_instance_id"); ok { serviceInstanceNameID = serviceInstanceID.(string) } else { - return fmt.Errorf("Please set either service_instance_name or service_instance_id") + return fmt.Errorf("[ERROR] Please set either service_instance_name or service_instance_id") } bindService := v1.ServiceBindRequest{ @@ -175,16 +195,16 @@ func resourceIBMContainerBindServiceUpdate(d *schema.ResourceData, meta interfac } func resourceIBMContainerBindServiceRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } if len(parts) < 3 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterNameID/serviceInstanceNameID/namespaceID", d.Id()) + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterNameID/serviceInstanceNameID/namespaceID", d.Id()) } clusterNameID := parts[0] serviceInstanceNameID := parts[1] @@ -210,11 +230,11 @@ func resourceIBMContainerBindServiceRead(d *schema.ResourceData, meta interface{ } func resourceIBMContainerBindServiceDelete(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -228,7 +248,7 @@ func resourceIBMContainerBindServiceDelete(d *schema.ResourceData, meta interfac err = csClient.Clusters().UnBindService(clusterNameID, namespace, serviceInstanceNameID, targetEnv) if err != nil { - return fmt.Errorf("Error unbinding service: %s", err) + return fmt.Errorf("[ERROR] Error unbinding service: %s", err) } return nil } diff --git a/ibm/resource_ibm_container_bind_service_test.go b/ibm/service/kubernetes/resource_ibm_container_bind_service_test.go similarity index 87% rename from ibm/resource_ibm_container_bind_service_test.go rename to ibm/service/kubernetes/resource_ibm_container_bind_service_test.go index 05df8b375..f17e83a7e 100644 --- a/ibm/resource_ibm_container_bind_service_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_bind_service_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMContainerBindServiceBasic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-bind-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerBindServiceBasic(clusterName, serviceName), @@ -63,5 +65,5 @@ resource "ibm_container_bind_service" "bind_service" { namespace_id = "default" role = "Writer" } - `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, serviceName) + `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, serviceName) } diff --git a/ibm/resource_ibm_container_cluster.go b/ibm/service/kubernetes/resource_ibm_container_cluster.go similarity index 84% rename from ibm/resource_ibm_container_cluster.go rename to ibm/service/kubernetes/resource_ibm_container_cluster.go index c3fa47a43..0f1266a84 100644 --- a/ibm/resource_ibm_container_cluster.go +++ b/ibm/service/kubernetes/resource_ibm_container_cluster.go @@ -1,7 +1,7 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "context" @@ -18,6 +18,9 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) const ( @@ -47,7 +50,7 @@ const ( const PUBLIC_SUBNET_TYPE = "public" -func resourceIBMContainerCluster() *schema.Resource { +func ResourceIBMContainerCluster() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerClusterCreate, Read: resourceIBMContainerClusterRead, @@ -64,7 +67,7 @@ func resourceIBMContainerCluster() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -121,7 +124,7 @@ func resourceIBMContainerCluster() *schema.Resource { Optional: true, Default: 0, Description: "Number of worker nodes", - ValidateFunc: validateWorkerNum, + ValidateFunc: validate.ValidateWorkerNum, Deprecated: "This field is deprecated", }, @@ -130,7 +133,7 @@ func resourceIBMContainerCluster() *schema.Resource { Optional: true, Default: 1, Description: "The size of the default worker pool", - ValidateFunc: validateWorkerNum, + ValidateFunc: validate.ValidateWorkerNum, }, "labels": { @@ -160,9 +163,9 @@ func resourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", - ValidateFunc: InvokeValidator( + ValidateFunc: validate.InvokeValidator( "ibm_container_cluster", - "worker_taints"), + "effect"), }, }, }, @@ -250,7 +253,7 @@ func resourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateFunc: validateAllowedStringValue([]string{hardwareShared, hardwareDedicated}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{hardwareShared, hardwareDedicated}), Description: "Hardware type", }, @@ -258,7 +261,7 @@ func resourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, Optional: true, Deprecated: "This field is deprecated", - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "public_vlan_id": { Type: schema.TypeString, @@ -296,7 +299,7 @@ func resourceIBMContainerCluster() *schema.Resource { "entitlement": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", }, @@ -310,7 +313,7 @@ func resourceIBMContainerCluster() *schema.Resource { Type: schema.TypeString, Optional: true, Default: ingressReady, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, ValidateFunc: validation.StringInSlice([]string{masterNodeReady, oneWorkerNodeReady, ingressReady}, true), Description: "wait_till can be configured for Master Ready, One worker Ready or Ingress Ready", }, @@ -344,14 +347,14 @@ func resourceIBMContainerCluster() *schema.Resource { Optional: true, ForceNew: true, Default: false, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Boolean value set to true when subnet creation is not required.", }, "is_trusted": { Type: schema.TypeBool, Optional: true, Deprecated: "This field is deprecated", - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "server_url": { Type: schema.TypeString, @@ -377,7 +380,7 @@ func resourceIBMContainerCluster() *schema.Resource { "type": { Type: schema.TypeString, Required: true, - ValidateFunc: validateAllowedStringValue([]string{"slack"}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{"slack"}), }, "url": { Type: schema.TypeString, @@ -399,7 +402,7 @@ func resourceIBMContainerCluster() *schema.Resource { Optional: true, Description: "ID of the resource group.", Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "org_guid": { @@ -429,8 +432,8 @@ func resourceIBMContainerCluster() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_container_cluster", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_container_cluster", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the resource", }, @@ -563,7 +566,7 @@ func resourceIBMContainerCluster() *schema.Resource { "gateway_enabled": { Type: schema.TypeBool, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Default: false, Description: "Set true for gateway enabled clusters", }, @@ -572,32 +575,37 @@ func resourceIBMContainerCluster() *schema.Resource { Computed: true, Description: "CRN of resource instance", }, - - ResourceControllerURL: { + "image_security_enforcement": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Set true to enable image security enforcement policies", + }, + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -606,32 +614,36 @@ func resourceIBMContainerCluster() *schema.Resource { } } -func resourceIBMContainerClusterValidator() *ResourceValidator { +func ResourceIBMContainerClusterValidator() *validate.ResourceValidator { tainteffects := "NoSchedule,PreferNoSchedule,NoExecute" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}, - ValidateSchema{ - Identifier: "worker_taints", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "effect", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: tainteffects}) - ibmContainerClusterResourceValidator := ResourceValidator{ResourceName: "ibm_container_cluster", Schema: validateSchema} + ibmContainerClusterResourceValidator := validate.ResourceValidator{ResourceName: "ibm_container_cluster", Schema: validateSchema} return &ibmContainerClusterResourceValidator } func resourceIBMContainerClusterCreate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + csClientV2, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -652,6 +664,7 @@ func resourceIBMContainerClusterCreate(d *schema.ResourceData, meta interface{}) case hardwareShared: hardware = isolationPublic } + imageSecurityEnabled := d.Get("image_security_enforcement").(bool) params := v1.ClusterCreateRequest{ Name: name, @@ -682,10 +695,10 @@ func resourceIBMContainerClusterCreate(d *schema.ResourceData, meta interface{}) params.PrivateEndpointEnabled = v.(bool) params.GatewayEnabled = gatewayEnabled } else { - return fmt.Errorf("set private_service_endpoint to true for gateway_enabled clusters") + return fmt.Errorf("[ERROR] set private_service_endpoint to true for gateway_enabled clusters") } } else { - return fmt.Errorf("set private_service_endpoint to true for gateway_enabled clusters") + return fmt.Errorf("[ERROR] set private_service_endpoint to true for gateway_enabled clusters") } } if v, ok := d.GetOk("kube_version"); ok { @@ -709,6 +722,17 @@ func resourceIBMContainerClusterCreate(d *schema.ResourceData, meta interface{}) } d.SetId(cls.ID) + targetEnvV2, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + if imageSecurityEnabled { + err = csClientV2.Clusters().EnableImageSecurityEnforcement(cls.ID, targetEnvV2) + if err != nil { + return err + } + } + _, err = waitForClusterMasterAvailable(d, meta) if err != nil { return err @@ -725,7 +749,7 @@ func resourceIBMContainerClusterCreate(d *schema.ResourceData, meta interface{}) } func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -741,12 +765,12 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e clusterID := d.Id() cls, err := csClient.Clusters().Find(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving armada cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving armada cluster: %s", err) } workerFields, err := wrkAPI.List(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } workerCount := 0 workers := []map[string]string{} @@ -781,14 +805,14 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e if poolContains { workersByPool, err := wrkAPI.ListByWorkerPool(clusterID, poolName, false, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers of default worker pool for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers of default worker pool for cluster: %s", err) } // to get the private and public vlan IDs of the gateway enabled cluster. if poolName == computeWorkerPool { gatewayWorkersByPool, err := wrkAPI.ListByWorkerPool(clusterID, gatewayWorkerpool, false, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers of default worker pool for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers of default worker pool for cluster: %s", err) } d.Set("public_vlan_id", gatewayWorkersByPool[0].PublicVlan) d.Set("private_vlan_id", gatewayWorkersByPool[0].PrivateVlan) @@ -823,7 +847,7 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e if err != nil { return err } - d.Set("labels", IgnoreSystemLabels(defaultWorkerPool.Labels)) + d.Set("labels", flex.IgnoreSystemLabels(defaultWorkerPool.Labels)) zones := defaultWorkerPool.Zones for _, zone := range zones { if zone.ID == cls.DataCenter { @@ -831,13 +855,13 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e break } } - d.Set("worker_pools", flattenWorkerPools(workerPools)) + d.Set("worker_pools", flex.FlattenWorkerPools(workerPools)) } albs, err := albsAPI.ListClusterALBs(clusterID, targetEnv) if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") && !strings.Contains(err.Error(), "The specified cluster is a free cluster.") { - return fmt.Errorf("Error retrieving alb's of the cluster %s: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", clusterID, err) } d.Set("name", cls.Name) @@ -854,34 +878,40 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e } else { d.Set("kube_version", strings.Split(cls.MasterKubeVersion, "_")[0]) } - d.Set("albs", flattenAlbs(albs, "all")) + d.Set("albs", flex.FlattenAlbs(albs, "all")) d.Set("resource_group_id", cls.ResourceGroupID) d.Set("public_service_endpoint", cls.PublicServiceEndpointEnabled) d.Set("private_service_endpoint", cls.PrivateServiceEndpointEnabled) d.Set("public_service_endpoint_url", cls.PublicServiceEndpointURL) d.Set("private_service_endpoint_url", cls.PrivateServiceEndpointURL) d.Set("crn", cls.CRN) - tags, err := GetTagsUsingCRN(meta, cls.CRN) + tags, err := flex.GetTagsUsingCRN(meta, cls.CRN) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) } d.Set("tags", tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") - d.Set(ResourceName, cls.Name) - d.Set(ResourceCRN, cls.CRN) - d.Set(ResourceStatus, cls.State) - d.Set(ResourceGroupName, cls.ResourceGroupName) + d.Set("image_security_enforcement", cls.ImageSecurityEnabled) + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceName, cls.Name) + d.Set(flex.ResourceCRN, cls.CRN) + d.Set(flex.ResourceStatus, cls.State) + d.Set(flex.ResourceGroupName, cls.ResourceGroupName) return nil } func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + + csClientV2, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -891,6 +921,11 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) return err } + targetEnvV2, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + subnetAPI := csClient.Subnets() whkAPI := csClient.WebHooks() wrkAPI := csClient.Workers() @@ -916,8 +951,7 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) } _, err = WaitForClusterVersionUpdate(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) } } // "update_all_workers" deafult is false, enable to true when all worker nodes to be updated @@ -926,7 +960,7 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) if updateAllWorkers || d.HasChange("patch_version") || d.HasChange("retry_patch_version") { workerFields, err := wrkAPI.List(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } waitForWorkerUpdate := d.Get("wait_for_worker_update").(bool) @@ -943,14 +977,13 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) err = wrkAPI.Update(clusterID, w.ID, params, targetEnv) if err != nil { d.Set("patch_version", nil) - return fmt.Errorf("Error updating worker %s: %s", w.ID, err) + return fmt.Errorf("[ERROR] Error updating worker %s: %s", w.ID, err) } if waitForWorkerUpdate { _, err = WaitForWorkerAvailable(d, meta, targetEnv) if err != nil { d.Set("patch_version", nil) - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } } @@ -1022,18 +1055,15 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) poolSize := d.Get("default_pool_size").(int) err = workerPoolsAPI.ResizeWorkerPool(clusterID, poolName, poolSize, targetEnv) if err != nil { - return fmt.Errorf( - "Error updating the default_pool_size %d: %s", poolSize, err) + return fmt.Errorf("[ERROR] Error updating the default_pool_size %d: %s", poolSize, err) } _, err = WaitForWorkerAvailable(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } else { - return fmt.Errorf( - "The default worker pool does not exist. Use ibm_container_worker_pool and ibm_container_worker_pool_zone attachment resources to make changes to your cluster, such as adding zones, adding worker nodes, or updating worker nodes..") + return fmt.Errorf("[ERROR] The default worker pool does not exist. Use ibm_container_worker_pool and ibm_container_worker_pool_zone attachment resources to make changes to your cluster, such as adding zones, adding worker nodes, or updating worker nodes") } } @@ -1062,18 +1092,15 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) } err = workerPoolsAPI.UpdateLabelsWorkerPool(clusterID, poolName, labels, targetEnv) if err != nil { - return fmt.Errorf( - "Error updating the labels %s", err) + return fmt.Errorf("[ERROR] Error updating the labels %s", err) } _, err = WaitForWorkerAvailable(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } else { - return fmt.Errorf( - "The default worker pool does not exist. Use ibm_container_worker_pool and ibm_container_worker_pool_zone attachment resources to make changes to your cluster, such as adding zones, adding worker nodes, or updating worker nodes..") + return fmt.Errorf("[ERROR] The default worker pool does not exist. Use ibm_container_worker_pool and ibm_container_worker_pool_zone attachment resources to make changes to your cluster, such as adding zones, adding worker nodes, or updating worker nodes") } } if d.HasChange("taints") { @@ -1098,7 +1125,7 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return err } - ClusterClient, err := meta.(ClientSession).VpcContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -1140,21 +1167,19 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) count := oldCount - newCount workerFields, err := wrkAPI.List(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } for i := 0; i < count; i++ { err := wrkAPI.Delete(clusterID, workerFields[i].ID, targetEnv) if err != nil { - return fmt.Errorf( - "Error deleting workers of cluster (%s): %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error deleting workers of cluster (%s): %s", d.Id(), err) } } } _, err = WaitForWorkerAvailable(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } @@ -1169,23 +1194,22 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) if strings.Compare(newPack["version"].(string), oldPack["version"].(string)) != 0 { cluster, err := clusterAPI.Find(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving cluster %s: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error retrieving cluster %s: %s", clusterID, err) } if newPack["version"].(string) != strings.Split(cluster.MasterKubeVersion, "_")[0] { - return fmt.Errorf("Worker version %s should match the master kube version %s", newPack["version"].(string), strings.Split(cluster.MasterKubeVersion, "_")[0]) + return fmt.Errorf("[ERROR] Worker version %s should match the master kube version %s", newPack["version"].(string), strings.Split(cluster.MasterKubeVersion, "_")[0]) } params := v1.WorkerUpdateParam{ Action: "update", } err = wrkAPI.Update(clusterID, oldPack["id"].(string), params, targetEnv) if err != nil { - return fmt.Errorf("Error updating worker %s: %s", oldPack["id"].(string), err) + return fmt.Errorf("[ERROR] Error updating worker %s: %s", oldPack["id"].(string), err) } _, err = WaitForWorkerAvailable(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } } @@ -1222,7 +1246,7 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) var publicSubnetAdded bool noSubnet := d.Get("no_subnet").(bool) publicVlanID := d.Get("public_vlan_id").(string) - if noSubnet == false && publicVlanID != "" { + if !noSubnet && publicVlanID != "" { publicSubnetAdded = true } if d.HasChange("subnet_id") { @@ -1262,8 +1286,7 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) if publicSubnetAdded && d.Get("wait_till").(string) == ingressReady { _, err = WaitForSubnetAvailable(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for initializing ingress hostname and secret: %s", err) + return fmt.Errorf("[ERROR] Error waiting for initializing ingress hostname and secret: %s", err) } } @@ -1272,9 +1295,9 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) oldList, newList := d.GetChange("tags") cluster, err := clusterAPI.Find(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving cluster %s: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error retrieving cluster %s: %s", clusterID, err) } - err = UpdateTagsUsingCRN(oldList, newList, meta, cluster.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, cluster.CRN) if err != nil { log.Printf( "An error occured during update of instance (%s) tags: %s", clusterID, err) @@ -1282,6 +1305,18 @@ func resourceIBMContainerClusterUpdate(d *schema.ResourceData, meta interface{}) } + if d.HasChange("image_security_enforcement") && !d.IsNewResource() { + var imageSecurity bool + if v, ok := d.GetOk("image_security_enforcement"); ok { + imageSecurity = v.(bool) + } + if imageSecurity { + csClientV2.Clusters().EnableImageSecurityEnforcement(clusterID, targetEnvV2) + } else { + csClientV2.Clusters().DisableImageSecurityEnforcement(clusterID, targetEnvV2) + } + } + return resourceIBMContainerClusterRead(d, meta) } @@ -1290,7 +1325,7 @@ func getID(d *schema.ResourceData, meta interface{}, clusterID string, oldWorker if err != nil { return "", err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return "", err } @@ -1317,7 +1352,7 @@ func getID(d *schema.ResourceData, meta interface{}, clusterID string, oldWorker } } - return "", fmt.Errorf("Unable to get ID of worker") + return "", fmt.Errorf("[ERROR] Unable to get ID of worker") } func resourceIBMContainerClusterDelete(d *schema.ResourceData, meta interface{}) error { @@ -1326,7 +1361,7 @@ func resourceIBMContainerClusterDelete(d *schema.ResourceData, meta interface{}) if err != nil { return err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -1334,7 +1369,7 @@ func resourceIBMContainerClusterDelete(d *schema.ResourceData, meta interface{}) forceDeleteStorage := d.Get("force_delete_storage").(bool) err = csClient.Clusters().Delete(clusterID, targetEnv, forceDeleteStorage) if err != nil { - return fmt.Errorf("Error deleting cluster: %s", err) + return fmt.Errorf("[ERROR] Error deleting cluster: %s", err) } _, err = waitForClusterDelete(d, meta) if err != nil { @@ -1348,7 +1383,7 @@ func waitForClusterDelete(d *schema.ResourceData, meta interface{}) (interface{} if err != nil { return nil, err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1377,7 +1412,7 @@ func waitForClusterDelete(d *schema.ResourceData, meta interface{}) (interface{} // WaitForClusterAvailable Waits for cluster creation func WaitForClusterAvailable(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1400,7 +1435,7 @@ func clusterStateRefreshFunc(client v1.Clusters, instanceID string, target v1.Cl return func() (interface{}, string, error) { clusterFields, err := client.FindWithOutShowResourcesCompatible(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving cluster: %s", err) } // Check active transactions log.Println("Checking cluster") @@ -1419,7 +1454,7 @@ func waitForClusterMasterAvailable(d *schema.ResourceData, meta interface{}) (in if err != nil { return nil, err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1431,7 +1466,7 @@ func waitForClusterMasterAvailable(d *schema.ResourceData, meta interface{}) (in Refresh: func() (interface{}, string, error) { clusterFields, err := csClient.Clusters().FindWithOutShowResourcesCompatible(clusterID, targetEnv) if err != nil { - return nil, "", fmt.Errorf("Error retrieving cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving cluster: %s", err) } if clusterFields.MasterStatus == ready { @@ -1453,7 +1488,7 @@ func waitForClusterOneWorkerAvailable(d *schema.ResourceData, meta interface{}) if err != nil { return nil, err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1483,7 +1518,7 @@ func waitForClusterOneWorkerAvailable(d *schema.ResourceData, meta interface{}) wrkAPI := csClient.Workers() workersByPool, err := wrkAPI.ListByWorkerPool(clusterID, poolName, false, targetEnv) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers of default worker pool for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers of default worker pool for cluster: %s", err) } if len(workersByPool) == 0 { return workersByPool, "provisioning", nil @@ -1508,7 +1543,7 @@ func waitForClusterOneWorkerAvailable(d *schema.ResourceData, meta interface{}) // WaitForWorkerAvailable Waits for worker creation func WaitForWorkerAvailable(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1531,7 +1566,7 @@ func workerStateRefreshFunc(client v1.Workers, instanceID string, target v1.Clus return func() (interface{}, string, error) { workerFields, err := client.List(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } log.Println("Checking workers...") //Done worker has two fields State and Status , so check for those 2 @@ -1547,7 +1582,7 @@ func workerStateRefreshFunc(client v1.Workers, instanceID string, target v1.Clus } func WaitForClusterCreation(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1561,7 +1596,7 @@ func WaitForClusterCreation(d *schema.ResourceData, meta interface{}, target v1. workerFields, err := csClient.Workers().List(ClusterID, target) log.Println("Total workers: ", len(workerFields)) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } log.Println("Checking workers...") //verifying for atleast sing node to be in normal state @@ -1582,7 +1617,7 @@ func WaitForClusterCreation(d *schema.ResourceData, meta interface{}, target v1. } func WaitForSubnetAvailable(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1605,7 +1640,7 @@ func subnetStateRefreshFunc(client v1.Clusters, instanceID string, d *schema.Res return func() (interface{}, string, error) { cluster, err := client.FindWithOutShowResourcesCompatible(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving cluster: %s", err) } if cluster.IngressHostname == "" || cluster.IngressSecretName == "" { return cluster, subnetProvisioning, nil @@ -1616,7 +1651,7 @@ func subnetStateRefreshFunc(client v1.Clusters, instanceID string, d *schema.Res // WaitForClusterVersionUpdate Waits for cluster creation func WaitForClusterVersionUpdate(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -1640,7 +1675,7 @@ func clusterVersionRefreshFunc(client v1.Clusters, instanceID string, d *schema. return func() (interface{}, string, error) { clusterFields, err := client.FindWithOutShowResourcesCompatible(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving cluster: %s", err) } // Check active transactions kubeversion := d.Get("kube_version").(string) @@ -1656,7 +1691,7 @@ func clusterVersionRefreshFunc(client v1.Clusters, instanceID string, d *schema. func resourceIBMContainerClusterExists(d *schema.ResourceData, meta interface{}) (bool, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } @@ -1672,7 +1707,7 @@ func resourceIBMContainerClusterExists(d *schema.ResourceData, meta interface{}) return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container cluster: %s", err) } return cls.ID == clusterID, nil } diff --git a/ibm/resource_ibm_container_cluster_feature.go b/ibm/service/kubernetes/resource_ibm_container_cluster_feature.go similarity index 77% rename from ibm/resource_ibm_container_cluster_feature.go rename to ibm/service/kubernetes/resource_ibm_container_cluster_feature.go index bce5e8429..d1079a132 100644 --- a/ibm/resource_ibm_container_cluster_feature.go +++ b/ibm/service/kubernetes/resource_ibm_container_cluster_feature.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -12,6 +12,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) const ( @@ -21,7 +24,7 @@ const ( reloadAction = "reload" ) -func resourceIBMContainerClusterFeature() *schema.Resource { +func ResourceIBMContainerClusterFeature() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerClusterFeatureCreate, Read: resourceIBMContainerClusterFeatureRead, @@ -40,6 +43,9 @@ func resourceIBMContainerClusterFeature() *schema.Resource { Required: true, ForceNew: true, Description: "Cluster name of ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_cluster_feature", + "cluster"), }, "public_service_endpoint": { @@ -83,12 +89,27 @@ func resourceIBMContainerClusterFeature() *schema.Resource { Optional: true, Description: "ID of the resource group.", Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, }, } } +func ResourceIBMContainerClusterFeatureValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerClusterFeatureValidator := validate.ResourceValidator{ResourceName: "ibm_container_cluster_feature", Schema: validateSchema} + return &iBMContainerClusterFeatureValidator +} + func resourceIBMContainerClusterFeatureCreate(d *schema.ResourceData, meta interface{}) error { cluster := d.Get("cluster").(string) @@ -101,7 +122,7 @@ func resourceIBMContainerClusterFeatureCreate(d *schema.ResourceData, meta inter return err } } else { - return fmt.Errorf("The `private_service_endpoint` can not be disabled") + return fmt.Errorf("[ERROR] The `private_service_endpoint` can not be disabled") } d.SetId(cluster) err := reloadCluster(cluster, d.Timeout(schema.TimeoutCreate), d, meta) @@ -132,13 +153,13 @@ func resourceIBMContainerClusterFeatureCreate(d *schema.ResourceData, meta inter } if !isOptionSet { - return fmt.Errorf("Provide either `public_service_endpoint` or `private_service_endpoint` or both.") + return fmt.Errorf("[ERROR] Provide either `public_service_endpoint` or `private_service_endpoint` or both") } return resourceIBMContainerClusterFeatureRead(d, meta) } func reloadCluster(cluster string, timeout time.Duration, d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -159,21 +180,19 @@ func reloadCluster(cluster string, timeout time.Duration, d *schema.ResourceData log.Printf("Waiting for cluster (%s) to be available.", cluster) _, err = WaitForClusterAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for cluster (%s) to become ready: %s", cluster, err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to become ready: %s", cluster, err) } log.Printf("Waiting for workers (%s) to be available.", cluster) _, err = WaitForWorkerAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", cluster, err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", cluster, err) } params := v1.UpdateWorkerCommand{ Action: reloadAction, } workerFields, err := csClient.Workers().List(cluster, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving workers for cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } workers := make([]string, len(workerFields)) for i, worker := range workerFields { @@ -185,13 +204,11 @@ func reloadCluster(cluster string, timeout time.Duration, d *schema.ResourceData } _, err = WaitForClusterAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to become ready: %s", d.Id(), err) } _, err = WaitForWorkerAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } } } @@ -200,7 +217,7 @@ func reloadCluster(cluster string, timeout time.Duration, d *schema.ResourceData } func updateCluster(cluster, actionCmd string, timeout time.Duration, d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -214,14 +231,12 @@ func updateCluster(cluster, actionCmd string, timeout time.Duration, d *schema.R log.Printf("Waiting for cluster (%s) to be available.", cluster) _, err = WaitForClusterAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to become ready: %s", d.Id(), err) } log.Printf("Waiting for workers (%s) to be available.", cluster) _, err = WaitForWorkerAvailableForFeatureUpdate(cluster, timeout, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to become ready: %s", d.Id(), err) } log.Printf("Calling update with action cmd %s", actionCmd) err = csClient.Clusters().Update(cluster, params, targetEnv) @@ -234,7 +249,7 @@ func updateCluster(cluster, actionCmd string, timeout time.Duration, d *schema.R } func resourceIBMContainerClusterFeatureRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -246,7 +261,7 @@ func resourceIBMContainerClusterFeatureRead(d *schema.ResourceData, meta interfa } cls, err := csClient.Clusters().Find(clusterID, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving armada cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving armada cluster: %s", err) } d.Set("cluster", clusterID) @@ -275,7 +290,7 @@ func resourceIBMContainerClusterFeatureUpdate(d *schema.ResourceData, meta inter return err } } else { - return fmt.Errorf("The `private_service_endpoint` can not be disabled") + return fmt.Errorf("[ERROR] The `private_service_endpoint` can not be disabled") } err := reloadCluster(cluster, d.Timeout(schema.TimeoutUpdate), d, meta) if err != nil { @@ -305,7 +320,7 @@ func resourceIBMContainerClusterFeatureUpdate(d *schema.ResourceData, meta inter } if !isOptionSet { - return fmt.Errorf("Provide either `public_service_endpoint` or `private_service_endpoint` or both.") + return fmt.Errorf("[ERROR] Provide either `public_service_endpoint` or `private_service_endpoint` or both") } return resourceIBMContainerClusterFeatureRead(d, meta) @@ -313,7 +328,7 @@ func resourceIBMContainerClusterFeatureUpdate(d *schema.ResourceData, meta inter // WaitForClusterAvailable Waits for cluster creation func WaitForClusterAvailableForFeatureUpdate(cluster string, timeout time.Duration, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -333,7 +348,7 @@ func WaitForClusterAvailableForFeatureUpdate(cluster string, timeout time.Durati } func WaitForWorkerAvailableForFeatureUpdate(cluster string, timeout time.Duration, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } diff --git a/ibm/resource_ibm_container_cluster_feature_test.go b/ibm/service/kubernetes/resource_ibm_container_cluster_feature_test.go similarity index 87% rename from ibm/resource_ibm_container_cluster_feature_test.go rename to ibm/service/kubernetes/resource_ibm_container_cluster_feature_test.go index 53e43604e..741e590c2 100644 --- a/ibm/resource_ibm_container_cluster_feature_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_cluster_feature_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMContainerClusterFeature_Basic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMContainerClusterFeatureBasic(clusterName), @@ -62,7 +64,7 @@ resource "ibm_container_cluster_feature" "feature" { timeouts { create = "720m" } -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterFeatureUpdate(clusterName string) string { @@ -87,5 +89,5 @@ resource "ibm_container_cluster_feature" "feature" { timeouts { update = "720m" } -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } diff --git a/ibm/resource_ibm_container_cluster_test.go b/ibm/service/kubernetes/resource_ibm_container_cluster_test.go similarity index 79% rename from ibm/resource_ibm_container_cluster_test.go rename to ibm/service/kubernetes/resource_ibm_container_cluster_test.go index a76e61630..de6aaa134 100644 --- a/ibm/resource_ibm_container_cluster_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_cluster_test.go @@ -1,7 +1,7 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -19,8 +22,8 @@ import ( func TestAccIBMContainerCluster_basic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -81,8 +84,8 @@ func TestAccIBMContainerClusterKmsEnable(t *testing.T) { kmsInstanceName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) rootKeyName := fmt.Sprintf("rootKey-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -101,8 +104,8 @@ func TestAccIBMContainerClusterKmsEnable(t *testing.T) { func TestAccIBMContainerClusterWithWorkerNumZero(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -116,8 +119,8 @@ func TestAccIBMContainerClusterWithWorkerNumZero(t *testing.T) { func TestAccIBMContainerClusterDiskEnc(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -136,8 +139,8 @@ func TestAccIBMContainerClusterDiskEnc(t *testing.T) { func TestAccIBMContainerClusterPrivateSubnet(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -160,8 +163,8 @@ func TestAccIBMContainerClusterPrivateSubnet(t *testing.T) { func TestAccIBMContainerClusterPrivateAndPublicSubnet(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerClusterDestroy, Steps: []resource.TestStep{ { @@ -181,8 +184,28 @@ func TestAccIBMContainerClusterPrivateAndPublicSubnet(t *testing.T) { }) } +func TestAccIBMContainerClusterImageSecuritySetting(t *testing.T) { + clusterName := fmt.Sprintf("tf-cluster-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerClusterImageSecuritySetting(clusterName, "true"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_cluster.testacc_cluster", "name", clusterName), + resource.TestCheckResourceAttr( + "ibm_container_cluster.testacc_cluster", "image_security_enforcement", "true"), + ), + }, + }, + }) +} + func testAccCheckIBMContainerClusterDestroy(s *terraform.State) error { - csClient, err := testAccProvider.Meta().(ClientSession).ContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -197,7 +220,7 @@ func testAccCheckIBMContainerClusterDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Cluster still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -228,7 +251,7 @@ resource "ibm_container_cluster" "testacc_cluster" { update = "720m" } -} `, clusterName, datacenter, kubeVersion, machineType, publicVlanID, privateVlanID) +} `, clusterName, acc.Datacenter, acc.KubeVersion, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterKmsEnable(clusterName, kmsInstanceName, rootKeyName string) string { @@ -267,7 +290,7 @@ func testAccCheckIBMContainerClusterKmsEnable(clusterName, kmsInstanceName, root } } -`, kmsInstanceName, rootKeyName, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +`, kmsInstanceName, rootKeyName, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterWithWorkerNumZero(clusterName string) string { @@ -281,7 +304,7 @@ resource "ibm_container_cluster" "testacc_cluster" { public_vlan_id = "%s" private_vlan_id = "%s" no_subnet = true -} `, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +} `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterDiskEnc(clusterName string) string { @@ -295,7 +318,7 @@ resource "ibm_container_cluster" "testacc_cluster" { private_vlan_id = "%s" disk_encryption = false wait_till = "MasterNodeReady" -} `, clusterName, datacenter, machineType, publicVlanID, privateVlanID) +} `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterUpdate(clusterName string) string { @@ -322,7 +345,7 @@ resource "ibm_container_cluster" "testacc_cluster" { create = "720m" update = "720m" } -} `, clusterName, datacenter, kubeUpdateVersion, machineType, publicVlanID, privateVlanID) +} `, clusterName, acc.Datacenter, acc.KubeUpdateVersion, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID) } func testAccCheckIBMContainerClusterPrivateAndPublicSubnet(clusterName string) string { @@ -338,7 +361,7 @@ resource "ibm_container_cluster" "testacc_cluster" { private_vlan_id = "%s" no_subnet = true subnet_id = ["%s", "%s"] -} `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, privateSubnetID, publicSubnetID) +} `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.PrivateSubnetID, acc.PublicSubnetID) } func testAccCheckIBMContainerClusterPrivateSubnet(clusterName string) string { @@ -353,5 +376,19 @@ resource "ibm_container_cluster" "testacc_cluster" { private_vlan_id = "%s" no_subnet = true subnet_id = ["%s"] -} `, clusterName, datacenter, machineType, publicVlanID, privateVlanID, privateSubnetID) +} `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.PrivateSubnetID) +} + +func testAccCheckIBMContainerClusterImageSecuritySetting(clusterName string, imageSecuritySetting string) string { + return fmt.Sprintf(` + +resource "ibm_container_cluster" "testacc_cluster" { + name = "%s" + datacenter = "%s" + machine_type = "%s" + hardware = "shared" + public_vlan_id = "%s" + private_vlan_id = "%s" + image_security_enforcement = %s +} `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, imageSecuritySetting) } diff --git a/ibm/service/kubernetes/resource_ibm_container_dedicated_host.go b/ibm/service/kubernetes/resource_ibm_container_dedicated_host.go new file mode 100644 index 000000000..4aa7ea5c6 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_dedicated_host.go @@ -0,0 +1,504 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + created = "created" + creating = "creating" + createFailed = "create_failed" + createPending = "create_pending" + deleted = "deleted" + deleting = "deleting" + deleteFailed = "delete_failed" + + DedicatedHostStateCreatePending = createPending + DedicatedHostStateCreating = creating + DedicatedHostStateCreated = created + DedicatedHostStateCreateFailed = createFailed + DedicatedHostStateDeleting = deleting + DedicatedHostStateDeleted = deleted + DedicatedHostStateDeleteFailed = deleteFailed +) + +func ResourceIBMContainerDedicatedHost() *schema.Resource { + + return &schema.Resource{ + CreateContext: resourceIBMContainerDedicatedHostCreate, + ReadContext: resourceIBMContainerDedicatedHostRead, + UpdateContext: resourceIBMContainerDedicatedHostUpdate, + DeleteContext: resourceIBMContainerDedicatedHostDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(time.Minute * 40), + Read: schema.DefaultTimeout(time.Minute * 10), + Update: schema.DefaultTimeout(time.Minute * 15), + Delete: schema.DefaultTimeout(time.Minute * 40), + }, + + Schema: map[string]*schema.Schema{ + "flavor": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The flavor of the dedicated host", + }, + "host_pool_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the dedicated host pool the dedicated host is associated with", + }, + "zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The zone of the dedicated host", + }, + "placement_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Enables/disables placement on the dedicated host", + }, + "host_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the dedicated host", + }, + "life_cycle": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actual_state": { + Type: schema.TypeString, + Computed: true, + }, + "desired_state": { + Type: schema.TypeString, + Computed: true, + }, + "message": { + Type: schema.TypeString, + Computed: true, + }, + "message_date": { + Type: schema.TypeString, + Computed: true, + }, + "message_details": { + Type: schema.TypeString, + Computed: true, + }, + "message_details_date": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Description: "The resources of the dedicated host", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "consumed": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "workers": { + Type: schema.TypeList, + Computed: true, + Description: "The workers of the dedicated host", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Computed: true, + }, + "flavor": { + Type: schema.TypeString, + Computed: true, + }, + "worker_id": { + Type: schema.TypeString, + Computed: true, + }, + "worker_pool_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourceIBMContainerDedicatedHostCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostAPI := client.DedicatedHost() + targetEnv := v2.ClusterTargetHeader{} + + hostPoolID := d.Get("host_pool_id").(string) + + params := v2.CreateDedicatedHostRequest{ + Flavor: d.Get("flavor").(string), + HostPoolID: hostPoolID, + Zone: d.Get("zone").(string), + } + + res, err := dedicatedHostAPI.CreateDedicatedHost(params, targetEnv) + if err != nil { + return diag.Errorf("[ERROR] CreateDedicatedHost failed: %v", err) + } + hostID := res.ID + d.SetId(fmt.Sprintf("%s/%s", hostPoolID, hostID)) + + dh, err := waitForDedicatedHostAvailable(ctx, dedicatedHostAPI, hostID, hostPoolID, d.Timeout(schema.TimeoutCreate), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostAvailable failed: %v", err) + } + + dedicatedHost, ok := dh.(v2.GetDedicatedHostResponse) + if !ok { + return diag.Errorf("[ERROR] waitForDedicatedHostAvailable response is faulty: %v", dh) + } + + setDedicatedHostFields(d, dedicatedHost) + + placement, ok := d.GetOk("placement_enabled") + if ok && dedicatedHost.PlacementEnabled != placement.(bool) { + req := v2.UpdateDedicatedHostPlacementRequest{ + HostPoolID: hostPoolID, + HostID: hostID, + } + if placement.(bool) { + if err = dedicatedHostAPI.EnableDedicatedHostPlacement(req, targetEnv); err != nil { + return diag.Errorf("[ERROR] EnableDedicatedHostPlacement failed: %v", err) + } + } else { + if err = dedicatedHostAPI.DisableDedicatedHostPlacement(req, targetEnv); err != nil { + return diag.Errorf("[ERROR] DisableDedicatedHostPlacement failed: %v", err) + } + } + _, err = waitForDedicatedHostPlacement(ctx, dedicatedHostAPI, hostID, hostPoolID, placement.(bool), d.Timeout(schema.TimeoutCreate), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostPlacement failed: %v", err) + } + d.Set("placement_enabled", placement) + } + + return nil +} + +func resourceIBMContainerDedicatedHostRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + if err := getIBMContainerDedicatedHost(id, d, meta); err != nil { + return diag.Errorf("[ERROR] getIBMContainerDedicatedHost failed: %v", err) + } + return nil +} + +func getIBMContainerDedicatedHost(id string, d *schema.ResourceData, meta interface{}) error { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + dedicatedHostAPI := client.DedicatedHost() + targetEnv := v2.ClusterTargetHeader{} + + // : + m := strings.Split(id, "/") + if len(m) < 2 || m[0] == "" || m[1] == "" { + return fmt.Errorf("[ERROR] unexpected format of ID (%s), the expected format is /", id) + } + hostPoolID := m[0] + hostID := m[1] + + dedicatedHost, err := dedicatedHostAPI.GetDedicatedHost(hostID, hostPoolID, targetEnv) + + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + d.SetId("") + return nil + } + } + return fmt.Errorf("[ERROR] Error getting container dedicatedhost: %s", err) + } + + d.Set("host_pool_id", hostPoolID) + setDedicatedHostFields(d, dedicatedHost) + + return nil +} + +func resourceIBMContainerDedicatedHostUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostAPI := client.DedicatedHost() + targetEnv := v2.ClusterTargetHeader{} + + id := d.Id() + // / + m := strings.Split(id, "/") + if len(m) < 2 || m[0] == "" || m[1] == "" { + return diag.Errorf("[ERROR] unexpected format of ID (%s), the expected format is /", id) + } + hostPoolID := m[0] + hostID := m[1] + + if d.HasChange("placement_enabled") { + placement := d.Get("placement_enabled").(bool) + req := v2.UpdateDedicatedHostPlacementRequest{ + HostPoolID: hostPoolID, + HostID: hostID, + } + if placement { + if err = dedicatedHostAPI.EnableDedicatedHostPlacement(req, targetEnv); err != nil { + return diag.Errorf("[ERROR] EnableDedicatedHostPlacement failed: %v", err) + } + } else { + if err = dedicatedHostAPI.DisableDedicatedHostPlacement(req, targetEnv); err != nil { + return diag.Errorf("[ERROR] DisableDedicatedHostPlacement failed: %v", err) + } + } + _, err = waitForDedicatedHostPlacement(ctx, dedicatedHostAPI, hostID, hostPoolID, placement, d.Timeout(schema.TimeoutUpdate), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostPlacement failed: %v", err) + } + d.Set("placement_enabled", placement) + } + return nil +} + +func resourceIBMContainerDedicatedHostDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostAPI := client.DedicatedHost() + targetEnv := v2.ClusterTargetHeader{} + + id := d.Id() + // / + m := strings.Split(id, "/") + if len(m) < 2 || m[0] == "" || m[1] == "" { + return diag.Errorf("[ERROR] unexpected format of ID (%s), the expected format is /", id) + } + hostPoolID := m[0] + hostID := m[1] + + placementParams := v2.UpdateDedicatedHostPlacementRequest{ + HostID: hostID, + HostPoolID: hostPoolID, + } + + if err = dedicatedHostAPI.DisableDedicatedHostPlacement(placementParams, targetEnv); err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + log.Printf("[DEBUG] DedicatedHostDelete: DisableDedicatedHostPlacement couldn't find dedicated host with host pool id %s and host id %s", hostPoolID, hostID) + return nil + } + } + return diag.Errorf("[ERROR] DisableDedicatedHostPlacement failed: %v", err) + } + + _, err = waitForDedicatedHostPlacement(ctx, dedicatedHostAPI, hostID, hostPoolID, false, d.Timeout(schema.TimeoutDelete), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostPlacement failed: %v", err) + } + + params := v2.RemoveDedicatedHostRequest{ + HostID: hostID, + HostPoolID: hostPoolID, + } + + if err = dedicatedHostAPI.RemoveDedicatedHost(params, targetEnv); err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + log.Printf("[DEBUG] RemoveDedicatedHost couldn't find dedicated host with host pool id %s and host id %s", hostPoolID, hostID) + return nil + } + } + return diag.Errorf("[ERROR] RemoveDedicatedHost failed: %v", err) + } + + _, err = waitForDedicatedHostRemove(ctx, dedicatedHostAPI, hostID, hostPoolID, d.Timeout(schema.TimeoutUpdate), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostRemove failed: %v", err) + } + + return nil +} + +func waitForDedicatedHostAvailable(ctx context.Context, dedicatedHostAPI v2.DedicatedHost, hostID, hostPoolID string, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + + log.Printf("[DEBUG] Waiting for the dedicated host (%s) for hostpool (%s) to be available.", hostID, hostPoolID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{DedicatedHostStateCreatePending, DedicatedHostStateCreating}, + Target: []string{DedicatedHostStateCreated}, + Refresh: dedicatedHostStateRefreshFunc(dedicatedHostAPI, hostID, hostPoolID, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func waitForDedicatedHostRemove(ctx context.Context, dedicatedHostAPI v2.DedicatedHost, hostID, hostPoolID string, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + + log.Printf("[DEBUG] Waiting for the dedicated host (%s) for hostpool (%s) to be removed.", hostID, hostPoolID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{DedicatedHostStateCreated, DedicatedHostStateDeleting}, + Target: []string{DedicatedHostStateDeleted}, + Refresh: dedicatedHostStateRefreshFunc(dedicatedHostAPI, hostID, hostPoolID, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func dedicatedHostStateRefreshFunc(dedicatedHostAPI v2.DedicatedHost, hostID, hostPoolID string, target v2.ClusterTargetHeader) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + dedicatedHost, err := dedicatedHostAPI.GetDedicatedHost(hostID, hostPoolID, target) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error retrieving dedicated host: %s", err) + + } + return dedicatedHost, dedicatedHost.Lifecycle.ActualState, nil + } +} + +func waitForDedicatedHostPlacement(ctx context.Context, dedicatedHostAPI v2.DedicatedHost, hostID, hostPoolID string, placement bool, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + placementStr := strconv.FormatBool(placement) + + log.Printf("[DEBUG] Waiting for the dedicated host (%s) for hostpool (%s) placement to be %s.", hostID, hostPoolID, placementStr) + + pendingStr := strconv.FormatBool(!placement) + + stateConf := &resource.StateChangeConf{ + Pending: []string{pendingStr}, + Target: []string{placementStr}, + Refresh: dedicatedHostPlacementRefreshFunc(dedicatedHostAPI, hostID, hostPoolID, target), + Timeout: timeout, + Delay: 2 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func dedicatedHostPlacementRefreshFunc(dedicatedHostAPI v2.DedicatedHost, hostID, hostPoolID string, target v2.ClusterTargetHeader) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + dedicatedHost, err := dedicatedHostAPI.GetDedicatedHost(hostID, hostPoolID, target) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error retrieving dedicated host: %s", err) + + } + return dedicatedHost, strconv.FormatBool(dedicatedHost.PlacementEnabled), nil + } +} + +func setDedicatedHostFields(d *schema.ResourceData, dedicatedHost v2.GetDedicatedHostResponse) { + d.Set("flavor", dedicatedHost.Flavor) + d.Set("zone", dedicatedHost.Zone) + d.Set("placement_enabled", dedicatedHost.PlacementEnabled) + d.Set("host_id", dedicatedHost.ID) + + life_cycle := []interface{}{map[string]interface{}{ + "actual_state": dedicatedHost.Lifecycle.ActualState, + "desired_state": dedicatedHost.Lifecycle.DesiredState, + "message": dedicatedHost.Lifecycle.Message, + "message_date": dedicatedHost.Lifecycle.MessageDate, + "message_details": dedicatedHost.Lifecycle.MessageDetails, + "message_details_date": dedicatedHost.Lifecycle.MessageDetailsDate, + }} + d.Set("life_cycle", life_cycle) + + capacity := []interface{}{map[string]interface{}{ + "memory_bytes": dedicatedHost.Resources.Capacity.MemoryBytes, + "vcpu": dedicatedHost.Resources.Capacity.VCPU, + }} + consumed := []interface{}{map[string]interface{}{ + "memory_bytes": dedicatedHost.Resources.Consumed.MemoryBytes, + "vcpu": dedicatedHost.Resources.Consumed.VCPU, + }} + resources := []interface{}{map[string]interface{}{ + "capacity": capacity, + "consumed": consumed, + }} + d.Set("resources", resources) + + workers := make([]map[string]interface{}, len(dedicatedHost.Workers)) + for i, w := range dedicatedHost.Workers { + workers[i] = map[string]interface{}{ + "cluster_id": w.ClusterID, + "flavor": w.Flavor, + "worker_id": w.WorkerID, + "worker_pool_id": w.WorkerPoolID, + } + } + d.Set("workers", workers) +} diff --git a/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool.go b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool.go new file mode 100644 index 000000000..ef2b78d2a --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool.go @@ -0,0 +1,301 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + DedicatedHostPoolStateCreated = created + DedicatedHostPoolStateCreating = creating + DedicatedHostPoolStateDeleting = deleting + DedicatedHostPoolStateDeleted = deleted +) + +func ResourceIBMContainerDedicatedHostPool() *schema.Resource { + + return &schema.Resource{ + CreateContext: resourceIBMContainerDedicatedHostPoolCreate, + ReadContext: resourceIBMContainerDedicatedHostPoolRead, + DeleteContext: resourceIBMContainerDedicatedHostPoolDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(time.Minute * 10), + Read: schema.DefaultTimeout(time.Minute * 10), + Delete: schema.DefaultTimeout(time.Minute * 10), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the dedicated host pool", + }, + "metro": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The metro to create the dedicated host pool in", + }, + "flavor_class": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The flavor class of the dedicated host pool", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "ID of the resource group.", + }, + "host_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The count of the hosts under the dedicated host pool", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "The state of the dedicated host pool", + }, + "zones": { + Type: schema.TypeList, + Computed: true, + Description: "The zones of the dedicated host pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "capacity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "memory_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + + "vcpu": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "host_count": { + Type: schema.TypeInt, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "worker_pools": { + Type: schema.TypeList, + Computed: true, + Description: "The worker pools of the dedicated host pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Computed: true, + }, + "worker_pool_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourceIBMContainerDedicatedHostPoolCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostPoolAPI := client.DedicatedHostPool() + targetEnv := v2.ClusterTargetHeader{} + + if rg, ok := d.GetOk("resource_group_id"); ok { + targetEnv.ResourceGroup = rg.(string) + } + + params := v2.CreateDedicatedHostPoolRequest{ + FlavorClass: d.Get("flavor_class").(string), + Metro: d.Get("metro").(string), + Name: d.Get("name").(string), + } + + res, err := dedicatedHostPoolAPI.CreateDedicatedHostPool(params, targetEnv) + if err != nil { + return diag.Errorf("[ERROR] Error creating host pool %v", err) + } + + d.SetId(res.ID) + + dhp, err := waitForDedicatedHostPoolAvailable(ctx, dedicatedHostPoolAPI, res.ID, d.Timeout(schema.TimeoutCreate), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostPoolAvailable failed: %v", err) + } + + setDedicatedHostPoolFields(dhp.(v2.GetDedicatedHostPoolResponse), d) + + return nil +} + +func resourceIBMContainerDedicatedHostPoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + err := getIBMContainerDedicatedHostPool(d.Id(), d, meta) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + d.SetId("") + return nil + } + } + return diag.Errorf("[ERROR] Error retrieving host pool details %v", err) + } + return nil +} + +func getIBMContainerDedicatedHostPool(hostPoolID string, d *schema.ResourceData, meta interface{}) error { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + dedicatedHostPoolAPI := client.DedicatedHostPool() + targetEnv := v2.ClusterTargetHeader{} + + dedicatedHostPool, err := dedicatedHostPoolAPI.GetDedicatedHostPool(hostPoolID, targetEnv) + if err != nil { + return err + } + + setDedicatedHostPoolFields(dedicatedHostPool, d) + + return nil +} + +func setDedicatedHostPoolFields(dedicatedHostPool v2.GetDedicatedHostPoolResponse, d *schema.ResourceData) { + d.Set("name", dedicatedHostPool.Name) + d.Set("metro", dedicatedHostPool.Metro) + d.Set("flavor_class", dedicatedHostPool.FlavorClass) + d.Set("host_count", dedicatedHostPool.HostCount) + d.Set("state", dedicatedHostPool.State) + + zones := make([]map[string]interface{}, len(dedicatedHostPool.Zones)) + for i, zone := range dedicatedHostPool.Zones { + zones[i] = map[string]interface{}{ + "capacity": []interface{}{map[string]interface{}{ + "memory_bytes": zone.Capacity.MemoryBytes, + "vcpu": zone.Capacity.VCPU, + }}, + "host_count": zone.HostCount, + "zone": zone.Zone, + } + } + d.Set("zones", zones) + + workerpools := make([]map[string]interface{}, len(dedicatedHostPool.WorkerPools)) + for i, wpool := range dedicatedHostPool.WorkerPools { + workerpools[i] = map[string]interface{}{ + "cluster_id": wpool.ClusterID, + "worker_pool_id": wpool.WorkerPoolID, + } + } + d.Set("worker_pools", workerpools) +} + +func resourceIBMContainerDedicatedHostPoolDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + dedicatedHostPoolAPI := client.DedicatedHostPool() + targetEnv := v2.ClusterTargetHeader{} + + hostPoolID := d.Id() + + params := v2.RemoveDedicatedHostPoolRequest{ + HostPoolID: hostPoolID, + } + + if err := dedicatedHostPoolAPI.RemoveDedicatedHostPool(params, targetEnv); err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + log.Printf("[DEBUG] RemoveDedicatedHostPool couldn't find dedicated host pool with id %s", hostPoolID) + return nil + } + } + return diag.Errorf("[ERROR] Error removing host pool %v", err) + } + + _, err = waitForDedicatedHostPoolRemove(ctx, dedicatedHostPoolAPI, hostPoolID, d.Timeout(schema.TimeoutDelete), targetEnv) + if err != nil { + return diag.Errorf("[ERROR] waitForDedicatedHostPoolRemove failed: %v", err) + } + + return nil +} + +func waitForDedicatedHostPoolAvailable(ctx context.Context, dedicatedHostPoolAPI v2.DedicatedHostPool, hostPoolID string, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + + log.Printf("[DEBUG] Waiting for the dedicated hostpool (%s) to be available.", hostPoolID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{DedicatedHostPoolStateCreating}, + Target: []string{DedicatedHostPoolStateCreated}, + Refresh: dedicatedHostPoolStateRefreshFunc(dedicatedHostPoolAPI, hostPoolID, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func waitForDedicatedHostPoolRemove(ctx context.Context, dedicatedHostPoolAPI v2.DedicatedHostPool, hostPoolID string, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + + log.Printf("[DEBUG] Waiting for the dedicated hostpool (%s) to be removed.", hostPoolID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{DedicatedHostPoolStateCreated, DedicatedHostPoolStateDeleting}, + Target: []string{DedicatedHostPoolStateDeleted}, + Refresh: dedicatedHostPoolStateRefreshFunc(dedicatedHostPoolAPI, hostPoolID, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func dedicatedHostPoolStateRefreshFunc(dedicatedHostPoolAPI v2.DedicatedHostPool, hostPoolID string, target v2.ClusterTargetHeader) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + dedicatedHostPool, err := dedicatedHostPoolAPI.GetDedicatedHostPool(hostPoolID, target) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error retrieving dedicated host pool: %s", err) + + } + return dedicatedHostPool, dedicatedHostPool.State, nil + } +} diff --git a/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool_test.go b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool_test.go new file mode 100644 index 000000000..db1859ef1 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_pool_test.go @@ -0,0 +1,100 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMContainerDedicatedHostPoolBasic(t *testing.T) { + + dedicatedHostPoolName := fmt.Sprintf("tf-dedicated-host-pool-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerDedicatedHostPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostPoolBasic(dedicatedHostPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "name", dedicatedHostPoolName), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "metro", "dal"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "flavor_class", "bx2d"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "host_count", "0"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "state", "created"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host_pool.test_dhostpool", "zones.#", "0"), + ), + }, + { + ResourceName: "ibm_container_dedicated_host_pool.test_dhostpool", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostPoolDestroy(s *terraform.State) error { + + client, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + dedicatedHostPoolAPI := client.DedicatedHostPool() + targetEnv := v2.ClusterTargetHeader{} + + var retryCounter int = 0 + var returnErr error = nil + for retryCounter < 2 { + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_dedicated_host_pool" { + continue + } + + dhp, err := dedicatedHostPoolAPI.GetDedicatedHostPool(rs.Primary.ID, targetEnv) + + if err == nil { + if dhp.State != "deleted" { + returnErr = fmt.Errorf("Dedicated host pool still exists: %s", rs.Primary.ID) + continue + } + return nil + } else if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error waiting for dedicated host pool (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + retryCounter++ + time.Sleep(time.Second) + } + + return returnErr +} + +func testAccCheckIBMContainerDedicatedHostPoolBasic(dedicatedHostPoolName string) string { + return fmt.Sprintf(` +resource "ibm_container_dedicated_host_pool" "test_dhostpool" { + name = "%s" + flavor_class = "bx2d" + metro = "dal" +} +`, dedicatedHostPoolName) +} diff --git a/ibm/service/kubernetes/resource_ibm_container_dedicated_host_test.go b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_test.go new file mode 100644 index 000000000..3beffc63c --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_dedicated_host_test.go @@ -0,0 +1,146 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMContainerDedicatedHostBasic(t *testing.T) { + + dedicatedHostPoolName := fmt.Sprintf("tf-dedicated-host-pool-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerDedicatedHostBasic(dedicatedHostPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "placement_enabled", "true"), + resource.TestCheckResourceAttrSet( + "ibm_container_dedicated_host.test_dhost", "id"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "life_cycle.#", "1"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "resources.#", "1"), + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "workers.#", "0"), + ), + }, + { + Config: testAccCheckIBMContainerDedicatedHostDisable(dedicatedHostPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "placement_enabled", "false"), + ), + }, + { + Config: testAccCheckIBMContainerDedicatedHostEnable(dedicatedHostPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_dedicated_host.test_dhost", "placement_enabled", "true"), + ), + }, + { + ResourceName: "ibm_container_dedicated_host.test_dhost", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMContainerDedicatedHostDestroy(s *terraform.State) error { + + client, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + dedicatedHostAPI := client.DedicatedHost() + targetEnv := v2.ClusterTargetHeader{} + + var ( + dhostID string + dhostPoolID string + ) + + for _, rs := range s.RootModule().Resources { + if rs.Type == "ibm_container_dedicated_host" { + dhostID = rs.Primary.ID + } else if rs.Type == "ibm_container_dedicated_host_pool" { + dhostPoolID = rs.Primary.ID + } + } + + var retryCounter int = 0 + var returnErr error = nil + for retryCounter < 2 { + dhp, err := dedicatedHostAPI.GetDedicatedHost(dhostID, dhostPoolID, targetEnv) + if err == nil { + if dhp.Lifecycle.ActualState != "deleted" { + returnErr = fmt.Errorf("Dedicated host still exists, dhostid %s, dhostpoolid %s", dhostID, dhostPoolID) + continue + } + return nil + } else { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 { + return nil + } + } + returnErr = err + } + + retryCounter++ + time.Sleep(time.Second) + } + + return returnErr +} + +func testAccCheckIBMContainerDedicatedHostBasic(dedicatedHostPoolName string) string { + return testAccCheckIBMContainerDedicatedHostPoolBasic(dedicatedHostPoolName) + ` +resource "ibm_container_dedicated_host" "test_dhost" { + flavor = "bx2d.host.152x608" + host_pool_id = ibm_container_dedicated_host_pool.test_dhostpool.id + zone = "us-south-2" +} +` +} + +func testAccCheckIBMContainerDedicatedHostDisable(dedicatedHostPoolName string) string { + return testAccCheckIBMContainerDedicatedHostPoolBasic(dedicatedHostPoolName) + ` +resource "ibm_container_dedicated_host" "test_dhost" { + flavor = "bx2d.host.152x608" + host_pool_id = ibm_container_dedicated_host_pool.test_dhostpool.id + zone = "us-south-2" + placement_enabled = "false" +} +` +} + +func testAccCheckIBMContainerDedicatedHostEnable(dedicatedHostPoolName string) string { + return testAccCheckIBMContainerDedicatedHostPoolBasic(dedicatedHostPoolName) + ` +resource "ibm_container_dedicated_host" "test_dhost" { + flavor = "bx2d.host.152x608" + host_pool_id = ibm_container_dedicated_host_pool.test_dhostpool.id + zone = "us-south-2" + placement_enabled = "true" +} +` +} diff --git a/ibm/service/kubernetes/resource_ibm_container_nlb_dns.go b/ibm/service/kubernetes/resource_ibm_container_nlb_dns.go new file mode 100644 index 000000000..0d5b2ca3f --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_nlb_dns.go @@ -0,0 +1,256 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMContainerNlbDns() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmContainerNlbDnsCreate, + ReadContext: resourceIbmContainerNlbDnsRead, + UpdateContext: resourceIbmContainerNlbDnsUpdate, + DeleteContext: resourceIbmContainerNlbDnsDelete, + + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name or ID of the cluster. To list the clusters that you have access to, use the `GET /v1/clusters` API or run `ibmcloud ks cluster ls`.", + ValidateFunc: validate.InvokeValidator( + "ibm_container_nlb_dns", + "cluster"), + }, + "nlb_host": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "nlb_ips": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "nlb_dns_type": { + Type: schema.TypeString, + Computed: true, + }, + "nlb_monitor_state": { + Type: schema.TypeString, + Computed: true, + }, + "nlb_ssl_secret_name": { + Type: schema.TypeString, + Computed: true, + }, + "nlb_ssl_secret_status": { + Type: schema.TypeString, + Computed: true, + }, + "nlb_type": { + Type: schema.TypeString, + Computed: true, + }, + "secret_namespace": { + Type: schema.TypeString, + Computed: true, + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "The ID of the resource group that the cluster is in. To check the resource group ID of the cluster, use the GET /v1/clusters/idOrName API. To list available resource group IDs, run ibmcloud resource groups.", + }, + }, + } +} + +func ResourceIBMContainerNlbDnsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerNlbDnsValidator := validate.ResourceValidator{ResourceName: "ibm_container_nlb_dns", Schema: validateSchema} + return &iBMContainerNlbDnsValidator +} + +func resourceIbmContainerNlbDnsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + registerDNSWithIPOptions := &kubernetesserviceapiv1.UpdateDNSWithIPOptions{} + registerDNSWithIPOptions.SetIdOrName(d.Get("cluster").(string)) + + if res, ok := d.GetOk("resource_group_id"); ok { + header := map[string]string{} + header["X-Auth-Resource-Group"] = res.(string) + registerDNSWithIPOptions.SetHeaders(header) + } + if _, ok := d.GetOk("nlb_host"); ok { + registerDNSWithIPOptions.SetNlbHost(d.Get("nlb_host").(string)) + } + if _, ok := d.GetOk("nlb_ips"); ok { + ips := []string{} + for _, segmentsItem := range d.Get("nlb_ips").(*schema.Set).List() { + ips = append(ips, segmentsItem.(string)) + } + registerDNSWithIPOptions.SetNlbIPArray(ips) + } + response, err := satClient.UpdateDNSWithIPWithContext(context, registerDNSWithIPOptions) + if err != nil { + log.Printf("[DEBUG] RegisterDNSWithIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RegisterDNSWithIPWithContext failed %s\n%s", err, response)) + } + + d.SetId(*registerDNSWithIPOptions.IdOrName) + + return resourceIbmContainerNlbDnsRead(context, d, meta) +} + +func resourceIbmContainerNlbDnsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + kubeClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + + nlbData, err := kubeClient.NlbDns().GetNLBDNSList(d.Id()) + if err != nil || nlbData == nil || len(nlbData) < 1 { + return diag.FromErr(fmt.Errorf("[ERROR] Error Listing NLB DNS (%s): %s", d.Id(), err)) + } + + if nlbData != nil { + for _, nlbConfig := range nlbData { + if err = d.Set("cluster", d.Id()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cluster: %s", err)) + } + if err = d.Set("nlb_dns_type", nlbConfig.Nlb.DnsType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting nlb_dns_type: %s", err)) + } + if err = d.Set("nlb_host", nlbConfig.Nlb.NlbSubdomain); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting nlb_host: %s", err)) + } + if err = d.Set("nlb_ssl_secret_name", nlbConfig.SecretName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting nlb_ssl_secret_name: %s", err)) + } + if err = d.Set("nlb_ssl_secret_status", nlbConfig.SecretStatus); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting nlb_ssl_secret_status: %s", err)) + } + if err = d.Set("nlb_type", nlbConfig.Nlb.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting nlb_type: %s", err)) + } + if err = d.Set("secret_namespace", nlbConfig.Nlb.SecretNamespace); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting secret_namespace: %s", err)) + } + } + } + + return nil +} + +func resourceIbmContainerNlbDnsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + updateDNSWithIPOptions := &kubernetesserviceapiv1.UpdateDNSWithIPOptions{} + + updateDNSWithIPOptions.SetIdOrName(d.Id()) + nlbHost := d.Get("nlb_host").(string) + + updateDNSWithIPOptions.NlbHost = flex.PtrToString(nlbHost) + + if d.HasChange("nlb_ips") { + var remove, add []string + o, n := d.GetChange("nlb_ips") + os := o.(*schema.Set) + ns := n.(*schema.Set) + + remove = flex.ExpandStringList(os.Difference(ns).List()) + add = flex.ExpandStringList(ns.Difference(os).List()) + + if len(remove) > 0 { + unregisterDNSWithIPOptions := &kubernetesserviceapiv1.UnregisterDNSWithIPOptions{} + unregisterDNSWithIPOptions.SetIdOrName(d.Id()) + unregisterDNSWithIPOptions.SetNlbHost(nlbHost) + for _, r := range remove { + unregisterDNSWithIPOptions.SetNlbIP(r) + response, err := satClient.UnregisterDNSWithIPWithContext(context, unregisterDNSWithIPOptions) + if err != nil { + log.Printf("[DEBUG] UnregisterDNSWithIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UnregisterDNSWithIPWithContext failed %s\n%s", err, response)) + } + } + } + + if len(add) > 0 { + if res, ok := d.GetOk("resource_group_id"); ok { + header := map[string]string{} + header["X-Auth-Resource-Group"] = res.(string) + updateDNSWithIPOptions.SetHeaders(header) + } + updateDNSWithIPOptions.SetNlbIPArray(add) + response, err := satClient.UpdateDNSWithIPWithContext(context, updateDNSWithIPOptions) + if err != nil { + log.Printf("[DEBUG] RegisterDNSWithIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RegisterDNSWithIPWithContext failed %s\n%s", err, response)) + } + } + } + + return resourceIbmContainerNlbDnsRead(context, d, meta) +} + +func resourceIbmContainerNlbDnsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + unregisterDNSWithIPOptions := &kubernetesserviceapiv1.UnregisterDNSWithIPOptions{} + unregisterDNSWithIPOptions.SetIdOrName(d.Id()) + if res, ok := d.GetOk("resource_group_id"); ok { + header := map[string]string{} + header["X-Auth-Resource-Group"] = res.(string) + unregisterDNSWithIPOptions.SetHeaders(header) + } + if nlbHost, ok := d.GetOk("nlb_host"); ok && nlbHost != nil { + unregisterDNSWithIPOptions.SetNlbHost(nlbHost.(string)) + } + + if ips, ok := d.GetOk("nlb_ips"); ok && ips != nil { + for _, i := range ips.(*schema.Set).List() { + unregisterDNSWithIPOptions.SetNlbIP(i.(string)) + response, err := satClient.UnregisterDNSWithIPWithContext(context, unregisterDNSWithIPOptions) + if err != nil { + log.Printf("[DEBUG] UnregisterDNSWithIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UnregisterDNSWithIPWithContext failed %s\n%s", err, response)) + } + } + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/kubernetes/resource_ibm_container_nlb_dns_test.go b/ibm/service/kubernetes/resource_ibm_container_nlb_dns_test.go new file mode 100644 index 000000000..92dd3a53b --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_nlb_dns_test.go @@ -0,0 +1,77 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIbmContainerNlbDnsBasic(t *testing.T) { + var conf kubernetesserviceapiv1.NlbVPCListConfig + clusterIps := "[ \"168.1.1.1\", \"168.1.1.2\", \"168.1.1.3\" ]" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmContainerNlbDnsConfigBasic(clusterIps), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmContainerNlbDnsExists("ibm_container_nlb_dns.container_nlb_dns", conf), + resource.TestCheckResourceAttr("ibm_container_nlb_dns.container_nlb_dns", "cluster", acc.ClusterName), + resource.TestCheckResourceAttr("ibm_container_nlb_dns.container_nlb_dns", "nlb_ips.#", "3"), + ), + }, + }, + }) +} + +func testAccCheckIbmContainerNlbDnsConfigBasic(clusterIps string) string { + return fmt.Sprintf(` + + data "ibm_container_nlb_dns" "dns" { + cluster = "%s" + } + + resource "ibm_container_nlb_dns" "container_nlb_dns" { + cluster = data.ibm_container_nlb_dns.dns.cluster + nlb_host = data.ibm_container_nlb_dns.dns.nlb_config.0.nlb_sub_domain + nlb_ips = %s + } + `, acc.ClusterName, clusterIps) +} + +func testAccCheckIbmContainerNlbDnsExists(n string, obj kubernetesserviceapiv1.NlbVPCListConfig) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + getNlbDNSListOptions := &kubernetesserviceapiv1.GetNlbDNSListOptions{} + getNlbDNSListOptions.Cluster = flex.PtrToString(rs.Primary.ID) + + nlbConfigList, _, err := satClient.GetNlbDNSList(getNlbDNSListOptions) + if err != nil { + return err + } + + obj = nlbConfigList[0] + return nil + } +} diff --git a/ibm/resource_ibm_container_storage_attachment.go b/ibm/service/kubernetes/resource_ibm_container_storage_attachment.go similarity index 76% rename from ibm/resource_ibm_container_storage_attachment.go rename to ibm/service/kubernetes/resource_ibm_container_storage_attachment.go index 19f100d24..ce6872902 100644 --- a/ibm/resource_ibm_container_storage_attachment.go +++ b/ibm/service/kubernetes/resource_ibm_container_storage_attachment.go @@ -1,4 +1,4 @@ -package ibm +package kubernetes import ( "context" @@ -8,6 +8,9 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -25,7 +28,7 @@ const ( volumeAttachReclamation = "pending_reclamation" ) -func resourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { +func ResourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMContainerVpcWorkerVolumeAttachmentCreate, @@ -51,6 +54,9 @@ func resourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { Required: true, ForceNew: true, Description: "Cluster name or ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_storage_attachment", + "cluster"), }, "worker": { @@ -93,10 +99,24 @@ func resourceIBMContainerVpcWorkerVolumeAttachment() *schema.Resource { }, } } +func ResourceIBMContainerVpcWorkerVolumeAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVpcWorkerVolumeAttachmentValidator := validate.ResourceValidator{ResourceName: "ibm_container_storage_attachment", Schema: validateSchema} + return &iBMContainerVpcWorkerVolumeAttachmentValidator +} func resourceIBMContainerVpcWorkerVolumeAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return diag.FromErr(err) } @@ -130,7 +150,7 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentCreate(context context.Context } func resourceIBMContainerVpcWorkerVolumeAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return diag.FromErr(err) } @@ -141,7 +161,7 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentRead(context context.Context, return diag.FromErr(err) } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return diag.FromErr(err) } @@ -149,21 +169,22 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentRead(context context.Context, workerID := parts[1] volumeAttachmentID := parts[2] - volume, err := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, target) + volumeAttachment, err := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, target) if err != nil { return diag.FromErr(err) } d.Set("cluster", clusterNameorID) d.Set("worker", workerID) + d.Set("volume", volumeAttachment.Volume.Id) d.Set("volume_attachment_id", volumeAttachmentID) - d.Set("volume_attachment_name", volume.Name) - d.Set("status", volume.Status) - d.Set("volume_type", volume.Type) + d.Set("volume_attachment_name", volumeAttachment.Name) + d.Set("status", volumeAttachment.Status) + d.Set("volume_type", volumeAttachment.Type) return nil } func resourceIBMContainerVpcWorkerVolumeAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return diag.FromErr(err) } @@ -174,7 +195,7 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentDelete(context context.Context return diag.FromErr(err) } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return diag.FromErr(err) } @@ -194,13 +215,12 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentDelete(context context.Context d.SetId("") return nil } - return diag.FromErr(fmt.Errorf("Failed to delete the volume attachment: %s", deleteErr)) + return diag.FromErr(fmt.Errorf("[ERROR] Failed to delete the volume attachment: %s", deleteErr)) } _, err = waitForStorageAttachmentDelete(d, meta) if err != nil { - return diag.FromErr(fmt.Errorf( - "Error waiting for storage attachment (%s) to be deleted: %s", d.Id(), err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for storage attachment (%s) to be deleted: %s", d.Id(), err)) } d.SetId("") @@ -208,7 +228,7 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentDelete(context context.Context } func resourceIBMContainerVpcWorkerVolumeAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } @@ -219,7 +239,7 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentExists(d *schema.ResourceData, return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -234,13 +254,13 @@ func resourceIBMContainerVpcWorkerVolumeAttachmentExists(d *schema.ResourceData, return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", getErr) + return false, fmt.Errorf("[ERROR] Error getting storage attachement: %s", getErr) } return true, nil } func waitforVolumetoAttach(d *schema.ResourceData, meta interface{}) (interface{}, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -252,7 +272,7 @@ func waitforVolumetoAttach(d *schema.ResourceData, meta interface{}) (interface{ return nil, trgetErr } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil, err } @@ -285,7 +305,7 @@ func waitforVolumetoAttach(d *schema.ResourceData, meta interface{}) (interface{ } func waitForStorageAttachmentDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -297,7 +317,7 @@ func waitForStorageAttachmentDelete(d *schema.ResourceData, meta interface{}) (i return nil, trgetErr } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return nil, err } @@ -315,9 +335,9 @@ func waitForStorageAttachmentDelete(d *schema.ResourceData, meta interface{}) (i if apiErr.StatusCode() == 404 { return volume, "removed", nil } - return nil, "", fmt.Errorf("Reading volume attach %s failed with resp code: %s, err: %v", d.Id(), volume, getErr) + return nil, "", fmt.Errorf("[ERROR] Reading volume attach %s failed with resp code: %s, err: %v", d.Id(), volume, getErr) } - return nil, "", fmt.Errorf("Reading volume attach failed: %s", getErr) + return nil, "", fmt.Errorf("[ERROR] Reading volume attach failed: %s", getErr) } return volume, "inprogress", nil }, diff --git a/ibm/service/kubernetes/resource_ibm_container_storage_attachment_test.go b/ibm/service/kubernetes/resource_ibm_container_storage_attachment_test.go new file mode 100644 index 000000000..e9a756020 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_storage_attachment_test.go @@ -0,0 +1,140 @@ +package kubernetes_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMContainerVpcClusterWorkerVolumeAttachment_Basic(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + clusterName := fmt.Sprintf("terraformcluster-%d", randInt) + vpc := fmt.Sprintf("terraformvpc-%d", randInt) + subnet := fmt.Sprintf("terraformsubnet-%d", randInt) + flavor := "cx2.2x4" + zone := "us-south" + workerCount := "1" + volumeName := fmt.Sprintf("terraformvpcvol-%d", randInt) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcWorkerStorageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVpcClusterWorkerVolumeAttach_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_storage_attachment.volume_attach", "status", "attached"), + ), + }, + { + ResourceName: "ibm_container_storage_attachment.volume_attach", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMContainerVpcClusterWorkerVolumeAttach_basic(zone, vpc, subnet, clusterName, flavor, workerCount, volumeName string) string { + return fmt.Sprintf(` + provider "ibm" { + region ="%s" + } + data "ibm_resource_group" "resource_group" { + is_default = "true" + } + resource "ibm_is_vpc" "vpc" { + name = "%s" + resource_group = data.ibm_resource_group.resource_group.id + } + resource "ibm_is_subnet" "subnet" { + name = "%s" + vpc = ibm_is_vpc.vpc.id + zone = "%s-1" + total_ipv4_address_count = 256 + resource_group = data.ibm_resource_group.resource_group.id + } + + resource "ibm_container_vpc_cluster" "cluster" { + name = "%s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "%s" + worker_count = %s + wait_till = "OneWorkerNodeReady" + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = ibm_is_subnet.subnet.id + name = "%s-1" + } + worker_labels = { + "test" = "test-default-pool" + "test1" = "test-default-pool1" + "test2" = "test-default-pool2" + } + + } + + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "10iops-tier" + zone = "%s-1" + # capacity = 200 + resource_group = data.ibm_resource_group.resource_group.id + } + + data "ibm_container_vpc_cluster" "cluster" { + name = ibm_container_vpc_cluster.cluster.id + } + + resource "ibm_container_storage_attachment" "volume_attach"{ + volume = ibm_is_volume.storage.id + cluster = ibm_container_vpc_cluster.cluster.id + worker = data.ibm_container_vpc_cluster.cluster.workers[0] + }`, zone, vpc, subnet, zone, clusterName, flavor, workerCount, zone, volumeName, zone) +} + +func testAccCheckIBMContainerVpcWorkerStorageDestroy(s *terraform.State) error { + + wpClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + workersAPI := wpClient.Workers() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_vpc_worker_storgae" { + continue + } + + targetEnv := getVpcClusterTargetHeaderTestACC() + // Try to find the key + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + clusterNameorID := parts[0] + workerID := parts[1] + volumeAttachmentID := parts[2] + + _, attchmentErr := workersAPI.GetStorageAttachment(clusterNameorID, workerID, volumeAttachmentID, targetEnv) + + if attchmentErr == nil { + return fmt.Errorf("[ERROR] Volume attachment still exists: %s", rs.Primary.ID) + } else if !strings.Contains(attchmentErr.Error(), "404") { + return fmt.Errorf("[ERROR] Error waiting for volume attachment (%s) to be destroyed: %s", rs.Primary.ID, attchmentErr) + } + } + + return nil +} diff --git a/ibm/resource_ibm_container_vpc_alb.go b/ibm/service/kubernetes/resource_ibm_container_vpc_alb.go similarity index 85% rename from ibm/resource_ibm_container_vpc_alb.go rename to ibm/service/kubernetes/resource_ibm_container_vpc_alb.go index 71b7b7e92..79f827a19 100644 --- a/ibm/resource_ibm_container_vpc_alb.go +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_alb.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -10,14 +10,16 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMContainerVpcALB() *schema.Resource { +func ResourceIBMContainerVpcALB() *schema.Resource { return &schema.Resource{ - Create: resourceIBMContainerVpcALBCreate, + Create: resourceIBMContainerVpcALBEnable, Read: resourceIBMContainerVpcALBRead, Update: resourceIBMContainerVpcALBUpdate, Delete: resourceIBMContainerVpcALBDelete, @@ -91,15 +93,15 @@ func resourceIBMContainerVpcALB() *schema.Resource { "resource_group_id": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "ID of the resource group.", }, }, } } -func resourceIBMContainerVpcALBCreate(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).VpcContainerAPI() +func resourceIBMContainerVpcALBEnable(d *schema.ResourceData, meta interface{}) error { + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -110,13 +112,12 @@ func resourceIBMContainerVpcALBCreate(d *schema.ResourceData, meta interface{}) } else if v, ok := d.GetOkExists("disable_deployment"); ok { disableDeployment = v.(bool) } else { - return fmt.Errorf("Provide either `enable` or `disable_deployment`") + return fmt.Errorf("[ERROR] Provide either `enable` or `disable_deployment`") } _, err = waitForVpcClusterAvailable(d, meta, albID, schema.TimeoutCreate) if err != nil { - return fmt.Errorf( - "Error waiting for cluster resource availabilty (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster resource availabilty (%s) : %s", d.Id(), err) } params := v2.AlbConfig{ @@ -145,15 +146,14 @@ func resourceIBMContainerVpcALBCreate(d *schema.ResourceData, meta interface{}) d.SetId(albID) _, err = waitForVpcContainerALB(d, meta, albID, schema.TimeoutCreate, enable, disableDeployment) if err != nil { - return fmt.Errorf( - "Error waiting for create resource alb (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for create resource alb (%s) : %s", d.Id(), err) } return resourceIBMContainerVpcALBRead(d, meta) } func resourceIBMContainerVpcALBRead(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).VpcContainerAPI() + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -184,7 +184,7 @@ func resourceIBMContainerVpcALBRead(d *schema.ResourceData, meta interface{}) er } func resourceIBMContainerVpcALBUpdate(d *schema.ResourceData, meta interface{}) error { - albClient, err := meta.(ClientSession).VpcContainerAPI() + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -197,8 +197,7 @@ func resourceIBMContainerVpcALBUpdate(d *schema.ResourceData, meta interface{}) _, err = waitForVpcClusterAvailable(d, meta, albID, schema.TimeoutCreate) if err != nil { - return fmt.Errorf( - "Error waiting for cluster resource availabilty (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster resource availabilty (%s) : %s", d.Id(), err) } params := v2.AlbConfig{ @@ -222,8 +221,7 @@ func resourceIBMContainerVpcALBUpdate(d *schema.ResourceData, meta interface{}) _, err = waitForVpcContainerALB(d, meta, albID, schema.TimeoutUpdate, enable, disableDeployment) if err != nil { - return fmt.Errorf( - "Error waiting for updating resource alb (%s) : %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for updating resource alb (%s) : %s", d.Id(), err) } } @@ -231,7 +229,7 @@ func resourceIBMContainerVpcALBUpdate(d *schema.ResourceData, meta interface{}) } func waitForVpcContainerALB(d *schema.ResourceData, meta interface{}, albID, timeout string, enable, disableDeployment bool) (interface{}, error) { - albClient, err := meta.(ClientSession).VpcContainerAPI() + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } @@ -243,16 +241,16 @@ func waitForVpcContainerALB(d *schema.ResourceData, meta interface{}, albID, tim alb, err := albClient.Albs().GetAlb(albID, targetEnv) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return nil, "", fmt.Errorf("The resource alb %s does not exist anymore: %v", d.Id(), err) + return nil, "", fmt.Errorf("[ERROR] The resource alb %s does not exist anymore: %v", d.Id(), err) } return nil, "", err } if enable { - if alb.Enable == false { + if !alb.Enable { return alb, "pending", nil } } else if disableDeployment { - if alb.Enable == true { + if alb.Enable { return alb, "pending", nil } } @@ -273,7 +271,7 @@ func resourceIBMContainerVpcALBDelete(d *schema.ResourceData, meta interface{}) } func waitForVpcClusterAvailable(d *schema.ResourceData, meta interface{}, albID, timeout string) (interface{}, error) { - albClient, err := meta.(ClientSession).VpcContainerAPI() + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create.go b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create.go new file mode 100644 index 000000000..ad949d4cf --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create.go @@ -0,0 +1,157 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "time" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMContainerVpcAlbCreateNew() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMContainerVpcAlbCreate, + Read: resourceIBMContainerVpcALBRead, + Update: resourceIBMContainerVpcALBUpdate, + Delete: resourceIBMContainerVpcALBDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The type of ALB that you want to create.", + }, + "zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The zone where you want to deploy the ALB.", + }, + "cluster": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the cluster that the ALB belongs to.", + ValidateFunc: validate.InvokeValidator( + "ibm_container_vpc_alb_create", + "cluster"), + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the resource group.", + }, + "enable": { + Type: schema.TypeBool, + Optional: true, + Description: "Enable the ALB instance in the cluster", + }, + //response + "alb_id": { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Description: "The ID of the application load balancer (ALB).", + }, + + //get + "alb_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the ALB", + }, + "disable_deployment": { + Type: schema.TypeBool, + Computed: true, + Description: "Disable the ALB instance in the cluster", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "ALB name", + }, + "load_balancer_hostname": { + Type: schema.TypeString, + Computed: true, + Description: "Load balancer host name", + }, + "resize": { + Type: schema.TypeBool, + Computed: true, + Description: "boolean value to resize the albs", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "ALB state", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of the ALB", + }, + }, + } +} + +func resourceIBMContainerVpcAlbCreate(d *schema.ResourceData, meta interface{}) error { + + albClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + albAPI := albClient.Albs() + + params := v2.AlbCreateReq{} + + if v, ok := d.GetOkExists("cluster"); ok { + params.Cluster = v.(string) + } + + if v, ok := d.GetOkExists("type"); ok { + params.Type = v.(string) + } + + if v, ok := d.GetOkExists("zone"); ok { + params.ZoneAlb = v.(string) + } + + if v, ok := d.GetOk("enable"); ok { + params.EnableByDefault = v.(bool) + } + + targetEnv, _ := getVpcClusterTargetHeader(d, meta) + + //v2.AlbCreateResp + albResp, err := albAPI.CreateAlb(params, targetEnv) + if err != nil { + return err + } + + d.SetId(albResp.Alb) + return nil +} +func ResourceIBMContainerVpcAlbCreateNewValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerVpcAlbCreateNewValidator := validate.ResourceValidator{ResourceName: "ibm_container_nlb_dns", Schema: validateSchema} + return &iBMContainerVpcAlbCreateNewValidator +} diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create_test.go b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create_test.go new file mode 100644 index 000000000..9495f511c --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_create_test.go @@ -0,0 +1,113 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "log" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" +) + +func TestAccIBMContainerVPCClusterALBCreate(t *testing.T) { + name := fmt.Sprintf("tf-vpc-alb-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMVpcContainerALBCreateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMVpcContainerALBCreate(true, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_container_vpc_alb_create.alb", "enable", "true"), + resource.TestCheckResourceAttr("ibm_container_vpc_alb_create.alb", "zone", "us-south-1"), + resource.TestCheckResourceAttr("ibm_container_vpc_alb_create.alb", "type", "private"), + ), + }, + }, + }) +} + +func testAccCheckIBMVpcContainerALBCreateDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type == "ibm_container_vpc_alb_create" { + albID := rs.Primary.ID + targetEnv := v2.ClusterTargetHeader{ + ResourceGroup: acc.IksClusterResourceGroupID, + } + + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + albAPI := csClient.Albs() + albconfig, err := albAPI.GetAlb(albID, targetEnv) + if err != nil { + return err + } + log.Println("[WARN] No API to delete ALB : ", albconfig) + } + if rs.Type == "ibm_container_vpc_cluster" { + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + targetEnv := v2.ClusterTargetHeader{ + ResourceGroup: acc.IksClusterResourceGroupID, + } + // Try to find the key + _, err = csClient.Clusters().GetCluster(rs.Primary.ID, targetEnv) + + if err == nil { + log.Printf("[DEBUG] ibm_container_vpc_cluster Cluster still exists: %s", rs.Primary.ID) + return fmt.Errorf("Cluster still exists: %s", rs.Primary.ID) + } else if !strings.Contains(err.Error(), "404") { + log.Printf("[DEBUG] ibm_container_vpc_cluster Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) + } + log.Println("[DEBUG] ibm_container_vpc_cluster deleted") + } + + } + return nil +} + +// You need to set up: +// IBM_CLUSTER_VPC_ID +// IBM_CLUSTER_VPC_SUBNET_ID +// IBM_CLUSTER_VPC_RESOURCE_GROUP_ID +func testAccCheckIBMVpcContainerALBCreate(enable bool, name string) string { + config := fmt.Sprintf(` + + resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = "%[3]s" + flavor = "cx2.2x4" + worker_count = 1 + resource_group_id = "%[4]s" + zones { + subnet_id = "%[5]s" + name = "us-south-1" + } + } + resource ibm_container_vpc_alb_create alb { + cluster = ibm_container_vpc_cluster.cluster.id + type = "private" + zone = "us-south-1" + resource_group_id = "%[4]s" + enable = "%[2]t" + } + `, name, enable, acc.IksClusterVpcID, acc.IksClusterResourceGroupID, acc.IksClusterSubnetID) + fmt.Println(config) + return config +} diff --git a/ibm/resource_ibm_container_vpc_alb_test.go b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_test.go similarity index 85% rename from ibm/resource_ibm_container_vpc_alb_test.go rename to ibm/service/kubernetes/resource_ibm_container_vpc_alb_test.go index 3f132a9c1..1c0388fad 100644 --- a/ibm/resource_ibm_container_vpc_alb_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_alb_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,8 +21,8 @@ import ( func TestAccIBMContainerVPCClusterALBBasic(t *testing.T) { name := fmt.Sprintf("tf-vpc-alb-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMVpcContainerALBDestroy, Steps: []resource.TestStep{ { @@ -49,7 +52,7 @@ func testAccCheckIBMVpcContainerALBDestroy(s *terraform.State) error { albID := rs.Primary.ID targetEnv := v2.ClusterTargetHeader{} - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -59,7 +62,7 @@ func testAccCheckIBMVpcContainerALBDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Instance still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking if instance (%s) has been destroyed: %s", rs.Primary.ID, err) } } return nil diff --git a/ibm/resource_ibm_container_vpc_cluster.go b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go similarity index 83% rename from ibm/resource_ibm_container_vpc_cluster.go rename to ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go index c05c3d725..136c30c09 100644 --- a/ibm/resource_ibm_container_vpc_cluster.go +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go @@ -1,7 +1,7 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "context" @@ -20,6 +20,9 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) const ( @@ -32,7 +35,7 @@ const ( ingressReady = "IngressReady" ) -func resourceIBMContainerVpcCluster() *schema.Resource { +func ResourceIBMContainerVpcCluster() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerVpcClusterCreate, Read: resourceIBMContainerVpcClusterRead, @@ -43,7 +46,7 @@ func resourceIBMContainerVpcCluster() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -60,7 +63,7 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - Description: "The cluster name", + Description: "The cluster name", }, "vpc_id": { @@ -215,9 +218,9 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", - ValidateFunc: InvokeValidator( + ValidateFunc: validate.InvokeValidator( "ibm_container_vpc_cluster", - "worker_taints"), + "effect"), }, }, }, @@ -233,8 +236,8 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_container_vpc_cluster", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_container_vpc_cluster", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags for the resources", }, @@ -242,7 +245,7 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Type: schema.TypeString, Optional: true, Default: ingressReady, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, ValidateFunc: validation.StringInSlice([]string{masterNodeReady, oneWorkerNodeReady, ingressReady}, true), Description: "wait_till can be configured for Master Ready, One worker Ready or Ingress Ready", }, @@ -250,14 +253,14 @@ func resourceIBMContainerVpcCluster() *schema.Resource { "entitlement": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", }, "cos_instance_crn": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "A standard cloud object storage instance CRN to back up the internal registry in your OpenShift on VPC Gen 2 cluster", }, @@ -268,10 +271,24 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Description: "Force the removal of a cluster and its persistent storage. Deleted data cannot be recovered", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, - Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + }, + "kms_instance_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Instance ID for boot volume encryption", + RequiredWith: []string{"crk"}, + }, + "crk": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Root Key ID for boot volume encryption", + RequiredWith: []string{"kms_instance_id"}, }, //Get Cluster info Request @@ -350,7 +367,7 @@ func resourceIBMContainerVpcCluster() *schema.Resource { "crn": { Type: schema.TypeString, Computed: true, - Description: "CRN of resource instance", + Description: "CRN of resource instance", }, "ingress_hostname": { @@ -363,28 +380,42 @@ func resourceIBMContainerVpcCluster() *schema.Resource { Sensitive: true, }, - ResourceName: { + "image_security_enforcement": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Set true to enable image security enforcement policies", + }, + + "host_pool_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The ID of the cluster's associated host pool", + }, + + flex.ResourceName: { Type: schema.TypeString, Computed: true, - Description: "The name of the resource", + Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, - Description: "The crn of the resource", + Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, - Description: "The status of the resource", + Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, - Description: "The resource group name in which resource is provisioned", + Description: "The resource group name in which resource is provisioned", }, }, @@ -396,26 +427,26 @@ func resourceIBMContainerVpcCluster() *schema.Resource { } } -func resourceIBMContainerVpcClusterValidator() *ResourceValidator { +func ResourceIBMContainerVpcClusterValidator() *validate.ResourceValidator { tainteffects := "NoSchedule,PreferNoSchedule,NoExecute" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}, - ValidateSchema{ - Identifier: "worker_taints", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "effect", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: tainteffects}) - ibmContainerVpcClusteresourceValidator := ResourceValidator{ResourceName: "ibm_container_vpc_cluster", Schema: validateSchema} + ibmContainerVpcClusteresourceValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_cluster", Schema: validateSchema} return &ibmContainerVpcClusteresourceValidator } @@ -423,7 +454,7 @@ func resourceIBMContainerVpcClusterCreate(d *schema.ResourceData, meta interface vpcProvider := "vpc-gen2" - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -439,6 +470,7 @@ func resourceIBMContainerVpcClusterCreate(d *schema.ResourceData, meta interface vpcID := d.Get("vpc_id").(string) flavor := d.Get("flavor").(string) workerCount := d.Get("worker_count").(int) + imageSecurityEnabled := d.Get("image_security_enforcement").(bool) // timeoutStage will define the timeout stage var timeoutStage string @@ -468,6 +500,19 @@ func resourceIBMContainerVpcClusterCreate(d *schema.ResourceData, meta interface Zones: zonesList, } + if hpid, ok := d.GetOk("host_pool_id"); ok { + workerpool.HostPoolID = hpid.(string) + } + + if v, ok := d.GetOk("kms_instance_id"); ok { + crk := d.Get("crk").(string) + wve := v2.WorkerVolumeEncryption{ + KmsInstanceID: v.(string), + WorkerVolumeCRKID: crk, + } + workerpool.WorkerVolumeEncryption = &wve + } + if l, ok := d.GetOk("worker_labels"); ok { labels := make(map[string]string) for k, v := range l.(map[string]interface{}) { @@ -502,11 +547,19 @@ func resourceIBMContainerVpcClusterCreate(d *schema.ResourceData, meta interface } cls, err := csClient.Clusters().Create(params, targetEnv) - if err != nil { return err } + d.SetId(cls.ID) + + if imageSecurityEnabled { + err = csClient.Clusters().EnableImageSecurityEnforcement(cls.ID, targetEnv) + if err != nil { + return err + } + } + switch strings.ToLower(timeoutStage) { case strings.ToLower(masterNodeReady): @@ -534,7 +587,7 @@ func resourceIBMContainerVpcClusterCreate(d *schema.ResourceData, meta interface func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -553,7 +606,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface if err != nil { return fmt.Errorf("[ERROR] Error retrieving cluster %s: %s", clusterID, err) } - err = UpdateTagsUsingCRN(oldList, newList, meta, cluster.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, cluster.CRN) if err != nil { log.Printf( "An error occured during update of instance (%s) tags: %s", clusterID, err) @@ -599,7 +652,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface if (d.HasChange("kube_version") || d.HasChange("update_all_workers") || d.HasChange("patch_version") || d.HasChange("retry_patch_version")) && !d.IsNewResource() { if d.HasChange("kube_version") { - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -624,12 +677,11 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface } _, err = WaitForVpcClusterVersionUpdate(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "[ERROR] Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) } } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -646,7 +698,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface // Update the worker nodes after master node kube-version is updated. // workers will store the existing workers info to identify the replaced node - workersInfo := make(map[string]int, 0) + workersInfo := make(map[string]int) updateAllWorkers := d.Get("update_all_workers").(bool) if updateAllWorkers || d.HasChange("patch_version") || d.HasChange("retry_patch_version") { @@ -721,7 +773,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface } } - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -740,7 +792,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface if err != nil { return err } - ClusterClient, err := meta.(ClientSession).VpcContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -752,7 +804,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface if d.HasChange("worker_count") && !d.IsNewResource() { count := d.Get("worker_count").(int) - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -800,7 +852,7 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface if len(remove) > 0 { for _, zone := range remove { oldZone := zone.(map[string]interface{}) - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -826,10 +878,22 @@ func resourceIBMContainerVpcClusterUpdate(d *schema.ResourceData, meta interface d.Set("force_delete_storage", forceDeleteStorage) } + if d.HasChange("image_security_enforcement") && !d.IsNewResource() { + var imageSecurity bool + if v, ok := d.GetOk("image_security_enforcement"); ok { + imageSecurity = v.(bool) + } + if imageSecurity { + csClient.Clusters().EnableImageSecurityEnforcement(clusterID, targetEnv) + } else { + csClient.Clusters().DisableImageSecurityEnforcement(clusterID, targetEnv) + } + } + return resourceIBMContainerVpcClusterRead(d, meta) } func WaitForV2WorkerZoneDeleted(clusterNameOrID, workerPoolNameOrID, zone string, meta interface{}, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -863,7 +927,7 @@ func workerPoolV2ZoneDeleteStateRefreshFunc(client v2.Workers, instanceID, worke } func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -892,7 +956,7 @@ func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{} var zones = make([]map[string]interface{}, 0) for _, zone := range workerPool.Zones { for _, subnet := range zone.Subnets { - if subnet.Primary == true { + if subnet.Primary { zoneInfo := map[string]interface{}{ "name": zone.ID, "subnet_id": subnet.ID, @@ -917,7 +981,7 @@ func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{} d.Set("kube_version", strings.Split(cls.MasterKubeVersion, "_")[0]) } d.Set("worker_count", workerPool.WorkerCount) - d.Set("worker_labels", IgnoreSystemLabels(workerPool.Labels)) + d.Set("worker_labels", flex.IgnoreSystemLabels(workerPool.Labels)) if cls.Vpcs != nil { d.Set("vpc_id", cls.Vpcs[0]) } @@ -931,7 +995,7 @@ func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{} d.Set("state", cls.State) d.Set("ingress_hostname", cls.Ingress.HostName) d.Set("ingress_secret", cls.Ingress.SecretName) - d.Set("albs", flattenVpcAlbs(albs, "all")) + d.Set("albs", flex.FlattenVpcAlbs(albs, "all")) d.Set("resource_group_id", cls.ResourceGroupID) d.Set("public_service_endpoint_url", cls.ServiceEndpoints.PublicServiceEndpointURL) d.Set("private_service_endpoint_url", cls.ServiceEndpoints.PrivateServiceEndpointURL) @@ -940,22 +1004,29 @@ func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{} } else { d.Set("disable_public_service_endpoint", true) } + d.Set("image_security_enforcement", cls.ImageSecurityEnabled) + d.Set("host_pool_id", workerPool.HostPoolID) - tags, err := GetTagsUsingCRN(meta, cls.CRN) + tags, err := flex.GetTagsUsingCRN(meta, cls.CRN) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) } d.Set("tags", tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") - d.Set(ResourceName, cls.Name) - d.Set(ResourceCRN, cls.CRN) - d.Set(ResourceStatus, cls.State) - d.Set(ResourceGroupName, cls.ResourceGroupName) + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceName, cls.Name) + d.Set(flex.ResourceCRN, cls.CRN) + d.Set(flex.ResourceStatus, cls.State) + d.Set(flex.ResourceGroupName, cls.ResourceGroupName) + + if workerPool.WorkerVolumeEncryption != nil { + d.Set("crk", workerPool.WorkerVolumeEncryption.WorkerVolumeCRKID) + d.Set("kms_instance_id", workerPool.WorkerVolumeEncryption.KmsInstanceID) + } return nil } @@ -966,7 +1037,7 @@ func resourceIBMContainerVpcClusterDelete(d *schema.ResourceData, meta interface if err != nil { return err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -1022,13 +1093,47 @@ func resourceIBMContainerVpcClusterDelete(d *schema.ResourceData, meta interface } return nil } +func vpcClient(meta interface{}) (*vpcv1.VpcV1, error) { + sess, err := meta.(conns.ClientSession).VpcV1API() + return sess, err +} +func isWaitForLBDeleted(lbc *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", "deleting"}, + Target: []string{"done", "failed"}, + Refresh: isLBDeleteRefreshFunc(lbc, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} +func isLBDeleteRefreshFunc(lbc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] is lb delete function here") + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + lb, response, err := lbc.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return lb, "done", nil + } + return nil, "failed", fmt.Errorf("[ERROR] The vpc load balancer %s failed to delete: %s\n%s", id, err, response) + } + return lb, "deleting", nil + } +} func waitForVpcClusterDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { targetEnv, err := getVpcClusterTargetHeader(d, meta) if err != nil { return nil, err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1060,7 +1165,7 @@ func waitForVpcClusterOneWorkerAvailable(d *schema.ResourceData, meta interface{ if err != nil { return nil, err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1101,7 +1206,7 @@ func waitForVpcClusterMasterAvailable(d *schema.ResourceData, meta interface{}) if err != nil { return nil, err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1135,7 +1240,7 @@ func waitForVpcClusterIngressAvailable(d *schema.ResourceData, meta interface{}) if err != nil { return nil, err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1177,7 +1282,7 @@ func getVpcClusterTargetHeader(d *schema.ResourceData, meta interface{}) (v2.Clu func resourceIBMContainerVpcClusterExists(d *schema.ResourceData, meta interface{}) (bool, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } @@ -1193,14 +1298,14 @@ func resourceIBMContainerVpcClusterExists(d *schema.ResourceData, meta interface return false, nil } } - return false, fmt.Errorf("[ERROR] Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container vpc cluster: %s", err) } return cls.ID == clusterID, nil } // WaitForVpcClusterVersionUpdate Waits for cluster creation func WaitForVpcClusterVersionUpdate(d *schema.ResourceData, meta interface{}, target v2.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1238,7 +1343,7 @@ func vpcClusterVersionRefreshFunc(client v2.Clusters, instanceID string, d *sche // WaitForVpcClusterWokersVersionUpdate Waits for Cluster version Update func WaitForVpcClusterWokersVersionUpdate(d *schema.ResourceData, meta interface{}, target v2.ClusterTargetHeader, masterVersion, workerID string) (interface{}, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1274,7 +1379,7 @@ func vpcClusterWorkersVersionRefreshFunc(client v2.Workers, workerID, clusterID func waitForWorkerNodetoDelete(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workerID string) (interface{}, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1302,7 +1407,7 @@ func waitForWorkerNodetoDelete(d *schema.ResourceData, meta interface{}, targetE } func waitForNewWorker(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workersCount int) (interface{}, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -1330,7 +1435,7 @@ func waitForNewWorker(d *schema.ResourceData, meta interface{}, targetEnv v2.Clu } func getNewWorkerID(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workersInfo map[string]int) (string, int, error) { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return "", -1, err } diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_cluster_test.go b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster_test.go new file mode 100644 index 000000000..10581d3ee --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster_test.go @@ -0,0 +1,467 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "log" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + bluemix "github.com/IBM-Cloud/bluemix-go" + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +func TestAccIBMContainerVpcClusterBasic(t *testing.T) { + name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + var conf *v2.ClusterInfo + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVpcClusterBasic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "name", name), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_count", "1"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "flavor", "cx2.2x4"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "zones.#", "1"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_labels.%", "3"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "kms_config.#", "1"), + ), + }, + { + Config: testAccCheckIBMContainerVpcClusterUpdate(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "name", name), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_count", "1"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "flavor", "cx2.2x4"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "zones.#", "2"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_labels.%", "2"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "kms_config.#", "1"), + ), + }, + { + ResourceName: "ibm_container_vpc_cluster.cluster", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_till", "update_all_workers", "kms_config", "force_delete_storage", "wait_for_worker_update"}, + }, + }, + }) +} +func TestAccIBMContainerOpenshiftClusterBasic(t *testing.T) { + name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + openshiftFlavour := "bx2.16x64" + openShiftworkerCount := "2" + var conf *v2.ClusterInfo + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerOcpClusterBasic(name, openshiftFlavour, openShiftworkerCount), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "name", name), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_count", openShiftworkerCount), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "flavor", openshiftFlavour), + ), + }, + }, + }) +} + +func TestAccIBMContainerVpcClusterImageSecuritySetting(t *testing.T) { + clusterName := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVpcClusterImageSecuritySetting(clusterName, "true"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.testacc_vpc_cluster", "name", clusterName), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.testacc_vpc_cluster", "image_security_enforcement", "true"), + ), + }, + }, + }) +} + +func TestAccIBMContainerVpcClusterDedicatedHost(t *testing.T) { + clusterName := fmt.Sprintf("tf-vpc-cluster-dhost-%d", acctest.RandIntRange(10, 100)) + hostPoolID := acc.HostPoolID + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVpcClusterDedicatedHostSetting( + clusterName, + acc.IksClusterVpcID, + "bx2d.4x16", + acc.IksClusterSubnetID, + acc.IksClusterResourceGroupID, + hostPoolID, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.testacc_dhost_vpc_cluster", "host_pool_id", hostPoolID), + ), + }, + }, + }, + ) +} + +func testAccCheckIBMContainerVpcClusterDestroy(s *terraform.State) error { + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_vpc_cluster" { + continue + } + + targetEnv := getVpcClusterTargetHeaderTestACC() + // Try to find the key + _, err := csClient.Clusters().GetCluster(rs.Primary.ID, targetEnv) + + if err == nil { + return fmt.Errorf("Cluster still exists: %s", rs.Primary.ID) + } else if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} +func testAccCheckIBMContainerVpcExists(n string, conf *v2.ClusterInfo) resource.TestCheckFunc { + + return func(s *terraform.State) error { + + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_vpc_cluster" { + continue + } + + targetEnv := getVpcClusterTargetHeaderTestACC() + + cls, err := csClient.Clusters().GetCluster(rs.Primary.ID, targetEnv) + + if err != nil && !strings.Contains(err.Error(), "404") { + return err + } + + conf = cls + + } + return nil + } +} +func getVpcClusterTargetHeaderTestACC() v2.ClusterTargetHeader { + c := new(bluemix.Config) + sess, err := session.New(c) + if err != nil { + log.Fatal(err) + } + resourceGroup := sess.Config.ResourceGroup + targetEnv := v2.ClusterTargetHeader{ + ResourceGroup: resourceGroup, + } + return targetEnv +} +func testAccCheckIBMContainerVpcClusterBasic(name string) string { + return fmt.Sprintf(` +provider "ibm" { + region ="eu-de" +} +data "ibm_resource_group" "resource_group" { + is_default = "true" + //name = "Default" +} +resource "ibm_is_vpc" "vpc" { + name = "%[1]s" +} +resource "ibm_is_subnet" "subnet" { + name = "%[1]s" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-1" + total_ipv4_address_count = 256 +} +resource "ibm_resource_instance" "kms_instance" { + name = "%[1]s" + service = "kms" + plan = "tiered-pricing" + location = "eu-de" +} + +resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kms_instance.guid + key_name = "%[1]s" + standard_key = false + force_delete = true +} +resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + wait_till = "OneWorkerNodeReady" + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = ibm_is_subnet.subnet.id + name = "eu-de-1" + } + kms_config { + instance_id = ibm_resource_instance.kms_instance.guid + crk_id = ibm_kms_key.test.key_id + private_endpoint = false + } + worker_labels = { + "test" = "test-default-pool" + "test1" = "test-default-pool1" + "test2" = "test-default-pool2" + } + + }`, name) +} +func testAccCheckIBMContainerVpcClusterUpdate(name string) string { + return fmt.Sprintf(` +provider "ibm" { + region ="eu-de" +} +data "ibm_resource_group" "resource_group" { + is_default = "true" +} +resource "ibm_is_vpc" "vpc" { + name = "%[1]s" +} +resource "ibm_is_subnet" "subnet" { + name = "%[1]s" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-1" + total_ipv4_address_count = 256 +} +resource "ibm_is_subnet" "subnet2" { + name = "%[1]s-2" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-2" + total_ipv4_address_count = 256 +} +resource "ibm_resource_instance" "kms_instance" { + name = "%[1]s" + service = "kms" + plan = "tiered-pricing" + location = "eu-de" +} + +resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kms_instance.guid + key_name = "%[1]s" + standard_key = false + force_delete = true +} +resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + wait_till = "OneWorkerNodeReady" + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = ibm_is_subnet.subnet.id + name = "eu-de-1" + } + zones { + subnet_id = ibm_is_subnet.subnet2.id + name = "eu-de-2" + } + kms_config { + instance_id = ibm_resource_instance.kms_instance.guid + crk_id = ibm_kms_key.test.key_id + private_endpoint = false + } + worker_labels = { + "test" = "test-default-pool" + "test1" = "test-default-pool1" + } + + }`, name) +} +func testAccCheckIBMContainerOcpClusterBasic(name, openshiftFlavour, openShiftworkerCount string) string { + return fmt.Sprintf(` +provider "ibm" { + region="eu-de" +} +data "ibm_resource_group" "resource_group" { + is_default = "true" +} +resource "ibm_is_vpc" "vpc1" { + name = "%[1]s" +} +resource "ibm_is_subnet" "subnet" { + name = "%[1]s" + vpc = "${ibm_is_vpc.vpc1.id}" + zone = "eu-de-1" + total_ipv4_address_count = 256 +} +resource "ibm_resource_instance" "cos_instance" { + name = "testcos_instance" + service = "cloud-object-storage" + plan = "standard" + location = "global" +} +resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = "${ibm_is_vpc.vpc1.id}" + flavor = "%s" + worker_count = "%s" + kube_version = "4.3.23_openshift" + wait_till = "IngressReady" + entitlement = "cloud_pak" + cos_instance_crn = ibm_resource_instance.cos_instance.id + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = ibm_is_subnet.subnet.id + name = "eu-de-1" + } + } + data "ibm_container_cluster_config" "testacc_ds_cluster" { + cluster_name_id = ibm_container_vpc_cluster.cluster.id + } + `, name, openshiftFlavour, openShiftworkerCount) + +} + +func testAccCheckIBMContainerVpcClusterImageSecuritySetting(name, setting string) string { + return fmt.Sprintf(` + resource "ibm_container_vpc_cluster" "testacc_vpc_cluster" { + name = "%s" + vpc_id = "%s" + flavor = "bx2.2x8" + worker_count = "1" + resource_group_id = "%s" + zones { + subnet_id = "%s" + name = "us-south-1" + } + image_security_enforcement = %s + }`, name, acc.IksClusterVpcID, acc.IksClusterResourceGroupID, acc.SubnetID, setting) +} + +func testAccCheckIBMContainerVpcClusterDedicatedHostSetting(name, vpcID, flavor, subnetID, rgroupID, hostpoolID string) string { + return fmt.Sprintf(` + resource "ibm_container_vpc_cluster" "testacc_dhost_vpc_cluster" { + name = "%s" + vpc_id = "%s" + flavor = "%s" + zones { + subnet_id = "%s" + name = "us-south-1" + } + resource_group_id = "%s" + host_pool_id = "%s" + }`, name, vpcID, flavor, subnetID, rgroupID, hostpoolID) +} + +// This test is here to help to focus on given resources, but requires everything else existing already +func TestAccIBMContainerVpcClusterEnvvar(t *testing.T) { + name := fmt.Sprintf("tf-vpc-cluster-%d", acctest.RandIntRange(10, 100)) + var conf *v2.ClusterInfo + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMContainerVpcClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerVpcClusterEnvvar(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMContainerVpcExists("ibm_container_vpc_cluster.cluster", conf), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "name", name), + resource.TestCheckResourceAttr( + "ibm_container_vpc_cluster.cluster", "worker_count", "1"), + ), + }, + { + ResourceName: "ibm_container_vpc_cluster.cluster", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_till", "update_all_workers", "kms_config", "force_delete_storage", "wait_for_worker_update"}, + }, + }, + }) +} + +// You need to set up env vars: +// export IBM_CLUSTER_VPC_ID +// export IBM_CLUSTER_VPC_SUBNET_ID +// export IBM_CLUSTER_VPC_RESOURCE_GROUP_ID +// export IBM_KMS_INSTANCE_ID +// export IBM_CRK_ID +// for acc.IksClusterVpcID, acc.IksClusterResourceGroupID, acc.IksClusterSubnetID, acc.KmsInstanceID, acc.CrkID +func testAccCheckIBMContainerVpcClusterEnvvar(name string) string { + config := fmt.Sprintf(` + resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = "%[2]s" + flavor = "bx2.4x16" + worker_count = 1 + resource_group_id = "%[3]s" + zones { + subnet_id = "%[4]s" + name = "us-south-1" + } + kms_instance_id = "%[5]s" + crk = "%[6]s" + } + `, name, acc.IksClusterVpcID, acc.IksClusterResourceGroupID, acc.IksClusterSubnetID, acc.KmsInstanceID, acc.CrkID) + fmt.Println(config) + return config +} diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_worker.go b/ibm/service/kubernetes/resource_ibm_container_vpc_worker.go new file mode 100644 index 000000000..39ac7e995 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_worker.go @@ -0,0 +1,637 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "os" + "strings" + "sync" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/remotecommand" +) + +// Mutex to make resource creation sequential. +var resourceIBMContainerVpcWorkerCreateMutex sync.Mutex +var commonVarMutex sync.Mutex + +// Status of worker replace +var workerReplaceStatus bool = false +var replaceInProgress bool = false + +// Variable to identify the first run +var initRun int = 1 + +func ResourceIBMContainerVpcWorker() *schema.Resource { + + return &schema.Resource{ + Create: resourceIBMContainerVpcWorkerCreate, + Read: resourceIBMContainerVpcWorkerRead, + Delete: resourceIBMContainerVpcWorkerDelete, + Exists: resourceIBMContainerVpcWorkerExists, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "cluster_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Cluster name", + }, + + "replace_worker": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "Worker name/id that needs to be replaced", + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "ID of the resource group.", + }, + + "kube_config_path": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: flex.ApplyOnce, + RequiredWith: []string{"check_ptx_status"}, + Description: "Path of downloaded cluster config", + }, + + "check_ptx_status": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + DiffSuppressFunc: flex.ApplyOnce, + RequiredWith: []string{"kube_config_path"}, + Default: false, + Description: "Check portworx status after worker replace", + }, + + "ptx_timeout": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: flex.ApplyOnce, + Default: "15m", + Description: "Timeout for checking ptx pods/status", + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + var err error + _, err = time.ParseDuration(value) + if err != nil { + errors = append(errors, fmt.Errorf("[ERROR] Error parsing ptx_timeout: %s", err)) + } + return + }, + }, + + "ip": { + Type: schema.TypeString, + Computed: true, + Description: "IP of the replaced worker", + }, + }, + } +} + +func ResourceIBMContainerVPCWorkerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + + containerVPCWorkerValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_worker", Schema: validateSchema} + return &containerVPCWorkerValidator +} + +// Since Worker is being managed by Worker Pool, we can't create new workers +// but we can update/replace the existing workers to the new workers. +func resourceIBMContainerVpcWorkerCreate(d *schema.ResourceData, meta interface{}) error { + + //Current Resource status + currentStatus := false + + workerID := d.Get("replace_worker").(string) + cluster_config, cc_ok := d.GetOk("kube_config_path") + check_ptx_status := d.Get("check_ptx_status").(bool) + clusterNameorID := d.Get("cluster_name").(string) + + if check_ptx_status { + //Validate & Check kubeconfig + + if !cc_ok { + return fmt.Errorf("[ERROR] kube_config_path argument must be specified if check_ptx_status is true") + } else { + //1. Load the cluster config + config, err := clientcmd.BuildConfigFromFlags("", cluster_config.(string)) + if err != nil { + return fmt.Errorf("[ERROR] Invalid kubeconfig, failed to set context: %s", err) + } + //2. create the clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("[ERROR] Invalid kubeconfig,, failed to create clientset: %s", err) + } + //3. List pods from kube-system namespace + _, err = clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("[ERROR] Invalid kubeconfig, failed to list resource: %s", err) + } + } + log.Printf("Kubeconfig is valid") + } + defer func() { + commonVarMutex.Lock() + workerReplaceStatus = false + if currentStatus { + workerReplaceStatus = true + } + replaceInProgress = false + commonVarMutex.Unlock() + }() + + //Continue only if the previous resource status is success + err := waitForPreviousResource(workerID) + if err != nil { + return err + } + defer resourceIBMContainerVpcWorkerCreateMutex.Unlock() + + wkClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + + worker, err := wkClient.Workers().Get(clusterNameorID, workerID, targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error getting container vpc worker node: %s", err) + } + + cls, err := wkClient.Clusters().GetCluster(clusterNameorID, targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving conatiner vpc cluster: %s", err) + } + + // Update the worker nodes after master node kube-version is updated. + // workers will store the existing workers info to identify the replaced node + workersInfo := make(map[string]int) + + workers, err := wkClient.Workers().ListWorkers(cls.ID, false, targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) + } + + for index, _worker := range workers { + workersInfo[_worker.ID] = index + } + workersCount := len(workers) + + // check if change is present in MAJOR.MINOR version or in PATCH version + if check_ptx_status || (worker.KubeVersion.Actual != worker.KubeVersion.Target) { + _, err = wkClient.Workers().ReplaceWokerNode(cls.ID, worker.ID, targetEnv) + // As API returns http response 204 NO CONTENT, error raised will be exempted. + if err != nil && !strings.Contains(err.Error(), "EmptyResponseBody") { + return fmt.Errorf("[ERROR] Error replacing the worker node from the cluster: %s", err) + } + + //1. wait for worker node to delete + _, deleteError := waitForVpcWorkerNodetoDelete(d, meta, targetEnv, worker.ID) + if deleteError != nil { + return fmt.Errorf("[ERROR] Worker node - %s is failed to replace", worker.ID) + } + + //2. wait for new workerNode + _, newWorkerError := waitForNewVpcWorker(d, meta, targetEnv, workersCount) + if newWorkerError != nil { + return fmt.Errorf("[ERROR] Failed to spawn new worker node") + } + + //3. Get new worker node ID and update the map + newWorkerID, _, newNodeError := getNewVpcWorkerID(d, meta, targetEnv, workersInfo) + if newNodeError != nil { + return fmt.Errorf("[ERROR] Unable to find the new worker node info") + } + + d.SetId(newWorkerID) + + //4. wait for the worker's version update and normal state + _worker, err := WaitForVpcClusterVpcWokersVersionUpdate(d, meta, targetEnv, cls.MasterKubeVersion, newWorkerID) + if err != nil { + return fmt.Errorf( + "[ERROR] Error waiting for cluster (%s) worker nodes kube version to be updated: %s", d.Id(), err) + } + worker = _worker.(v2.Worker) + + } else { + d.SetId(worker.ID) + } + + for _, _network := range worker.NetworkInterfaces { + if _network.Primary { + d.Set("ip", _network.IpAddress) + break + } + } + + if check_ptx_status { + err = checkPortworxStatus(d, cluster_config.(string)) + if err != nil { + return err + } + } + + //Worker reloaded successfully + currentStatus = true + return resourceIBMContainerVpcWorkerRead(d, meta) +} + +func resourceIBMContainerVpcWorkerRead(d *schema.ResourceData, meta interface{}) error { + //Not importing this resource. + return nil +} + +func resourceIBMContainerVpcWorkerDelete(d *schema.ResourceData, meta interface{}) error { + // Delete operation clears only the entries from the statefiles as + // the replace operation involves both deletion & creation of the + // resource + d.SetId("") + return nil +} + +func resourceIBMContainerVpcWorkerExists(d *schema.ResourceData, meta interface{}) (bool, error) { + wkClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return false, err + } + + workerID := d.Id() + parts, err := flex.SepIdParts(workerID, "-") + if err != nil { + return false, err + } + if len(parts) < 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be in kube-clusterID-* format", d.Id()) + } + cluster := parts[1] + + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return false, err + } + + worker, err := wkClient.Workers().Get(cluster, workerID, targetEnv) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok { + if apiErr.StatusCode() == 404 && strings.Contains(apiErr.Description(), "The specified worker node could not be found") { + return false, nil + } + } + return false, fmt.Errorf("[ERROR] Error getting container vpc worker node: %s", err) + } + if strings.Compare(worker.LifeCycle.ActualState, "deleted") == 0 { + return false, nil + } + + return worker.ID == workerID, nil +} + +func waitForPreviousResource(worker_id string) error { + time.Sleep(time.Second * 5) + for { + commonVarMutex.Lock() + if !replaceInProgress { + defer commonVarMutex.Unlock() + if initRun == 1 || workerReplaceStatus { + initRun = 0 + replaceInProgress = true + log.Printf("Worker routine %s is taking mutex", worker_id) + resourceIBMContainerVpcWorkerCreateMutex.Lock() + return nil + } else { + return fmt.Errorf("[ERROR] Previous worker replace failed") + } + } + commonVarMutex.Unlock() + time.Sleep(time.Second * 10) + } +} + +func checkPortworxStatus(d *schema.ResourceData, cluster_config string) error { + //Get worker ip + worker_ip := d.Get("ip").(string) + //1. Load the cluster config + config, err := clientcmd.BuildConfigFromFlags("", cluster_config) + if err != nil { + return fmt.Errorf("[ERROR] Failed to set context: %s", err) + } + // create the clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("[ERROR] Failed to create clientset: %s", err) + } + + //2. Retrieve portworx pod of current worker + pod_name, err := WaitForPortworxPod(d, clientset, worker_ip) + if err != nil { + return fmt.Errorf("[ERROR] Failed to retrieve portworx pods: %s", err) + } + + //3. Fetch portworx status json + ptx_content, err := WaitForPortworxStatus(d, clientset, config, pod_name.(string)) + if err != nil { + return fmt.Errorf("[ERROR] Failed to fetch portworx status: %s", err) + } + + //Execution should reach here only if the content is json & able to decode it without errors + //4. Check portworx status on current worker + node_data := (ptx_content.(map[string]interface{})["cluster"]).(map[string]interface{})["Nodes"].([]interface{}) + for _, n := range node_data { + n_data := n.(map[string]interface{}) + if n_data["MgmtIp"] == worker_ip { + ptx_status := n_data["NodeData"].(map[string]interface{})["STORAGE-INFO"].(map[string]interface{})["Status"].(string) + if ptx_status == "Up" { + //portworx is Up on this node + log.Printf("Portworx Status is Up") + return nil + } else { + return fmt.Errorf("[ERROR] Portworx Status is not Up on this node: %s", ptx_status) + } + } + } + return fmt.Errorf("[ERROR] No pods found with label name=portworx in kube-system namespace") +} + +func WaitForPortworxPod(d *schema.ResourceData, clientset *kubernetes.Clientset, worker_ip string) (interface{}, error) { + log.Printf("Waiting for the portworx pod to be Available & Ready") + + ptx_timeout, err := time.ParseDuration(d.Get("ptx_timeout").(string)) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error parsing ptx_timeout: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"ptx_not_ready"}, + Target: []string{"ptx_ready"}, + Refresh: ptxPodRefreshFunc(clientset, worker_ip), + Timeout: time.Duration(ptx_timeout), + Delay: 30 * time.Second, + PollInterval: 30 * time.Second, + } + + return stateConf.WaitForState() +} + +func ptxPodRefreshFunc(clientset *kubernetes.Clientset, worker_ip string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + //1. List pods from kube-system namespace + podList, err := clientset.CoreV1().Pods("kube-system").List(context.TODO(), metav1.ListOptions{LabelSelector: "name=portworx"}) + if err != nil { + log.Printf("Failed to list pods: %s", err) + return nil, "ptx_not_ready", nil + } + + //2. Get pod from the current worker + for _, pod := range podList.Items { + if pod.Status.HostIP == worker_ip { + for _, container := range pod.Status.ContainerStatuses { + if container.Name == "portworx" && container.Ready { + log.Printf("Portworx pod %s is ready", pod.Name) + return pod.Name, "ptx_ready", nil + } + } + log.Printf("Portworx pod %s not ready yet", pod.Name) + return pod.Name, "ptx_not_ready", nil + } + } + return nil, "ptx_not_ready", nil + } +} + +func WaitForPortworxStatus(d *schema.ResourceData, clientset *kubernetes.Clientset, config *rest.Config, pod_name string) (interface{}, error) { + log.Printf("Waiting to fetch portworx status json") + + ptx_timeout, err := time.ParseDuration(d.Get("ptx_timeout").(string)) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error parsing ptx_timeout: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"pxctl_fail"}, + Target: []string{"pxctl_success"}, + Refresh: ptxStatusRefreshFunc(clientset, config, pod_name), + Timeout: time.Duration(ptx_timeout), + Delay: 30 * time.Second, + PollInterval: 30 * time.Second, + } + + return stateConf.WaitForState() +} + +func ptxStatusRefreshFunc(clientset *kubernetes.Clientset, config *rest.Config, pod_name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + //Byte buffers for the exec command output + var stdout, stderr bytes.Buffer + + request := clientset.CoreV1().RESTClient().Post(). + Resource("pods"). + Name(pod_name). + Namespace("kube-system"). + SubResource("exec") + + //portworx command to fetch the status as json file + ptx_cmd := []string{ + "/opt/pwx/bin/pxctl", + "status", + "-j", + } + request.VersionedParams(&v1.PodExecOptions{ + Command: ptx_cmd, + Container: "portworx", + Stdin: true, + Stdout: true, + Stderr: true, + TTY: false, + }, scheme.ParameterCodec) + + exec, err := remotecommand.NewSPDYExecutor(config, "POST", request.URL()) + if err != nil { + log.Printf("[ERROR] Failed to Execute Remote Command: %s", err) + return nil, "pxctl_fail", nil + } + err = exec.Stream(remotecommand.StreamOptions{ + Stdin: os.Stdin, + Stdout: &stdout, + Stderr: &stderr, + Tty: false, + }) + if err != nil { + log.Printf("[ERROR] Failed to Read Remote Stream: %s", err) + return nil, "pxctl_fail", nil + } + + //If any error occurs in the exec command, log error & retry + if len(stderr.String()) != 0 { + log.Printf("[ERROR] Execute Remote Command Error: %s", stderr.String()) + return nil, "pxctl_fail", nil + } + + //Parse json data to check the portworx status + var parse_content map[string]interface{} + err = json.Unmarshal(stdout.Bytes(), &parse_content) + if err != nil { + log.Printf("[ERROR] Failed to decode ptx status json: %s", err) + return nil, "pxctl_fail", nil + } + + log.Printf("Successfully fetched portworx status json") + return parse_content, "pxctl_success", nil + } +} + +func waitForVpcWorkerNodetoDelete(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workerID string) (interface{}, error) { + + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return nil, err + } + + clusterID := d.Get("cluster_name").(string) + deleteStateConf := &resource.StateChangeConf{ + Pending: []string{workerDeletePending}, + Target: []string{workerDeleteState}, + Refresh: func() (interface{}, string, error) { + worker, err := csClient.Workers().Get(clusterID, workerID, targetEnv) + if err != nil { + return worker, workerDeletePending, nil + } + if worker.LifeCycle.ActualState == "deleted" { + return worker, workerDeleteState, nil + } + return worker, workerDeletePending, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + PollInterval: 5 * time.Second, + } + return deleteStateConf.WaitForState() +} + +func waitForNewVpcWorker(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workersCount int) (interface{}, error) { + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return nil, err + } + + clusterID := d.Get("cluster_name").(string) + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating"}, + Target: []string{"created"}, + Refresh: func() (interface{}, string, error) { + workers, err := csClient.Workers().ListWorkers(clusterID, false, targetEnv) + if err != nil { + return workers, "", fmt.Errorf("[ERROR] Error in retriving the list of worker nodes") + } + if len(workers) == workersCount { + return workers, "created", nil + } + return workers, "creating", nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + PollInterval: 5 * time.Second, + } + return stateConf.WaitForState() +} + +func getNewVpcWorkerID(d *schema.ResourceData, meta interface{}, targetEnv v2.ClusterTargetHeader, workersInfo map[string]int) (string, int, error) { + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return "", -1, err + } + + clusterID := d.Get("cluster_name").(string) + + workers, err := csClient.Workers().ListWorkers(clusterID, false, targetEnv) + if err != nil { + return "", -1, fmt.Errorf("[ERROR] Error in retriving the list of worker nodes") + } + + for index, worker := range workers { + if _, ok := workersInfo[worker.ID]; !ok { + log.Println("found new replaced node: ", worker.ID) + return worker.ID, index, nil + } + } + return "", -1, fmt.Errorf("[ERROR] no new node found") +} + +// WaitForVpcClusterVpcWokersVersionUpdate Waits for Cluster version Update +func WaitForVpcClusterVpcWokersVersionUpdate(d *schema.ResourceData, meta interface{}, target v2.ClusterTargetHeader, masterVersion, workerID string) (interface{}, error) { + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return nil, err + } + + log.Printf("Waiting for worker (%s) version to be updated.", workerID) + clusterID := d.Get("cluster_name").(string) + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", versionUpdating}, + Target: []string{workerNormal}, + Refresh: vpcClusterVpcWorkersVersionRefreshFunc(csClient.Workers(), workerID, clusterID, d, target, masterVersion), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: 5, + } + + return stateConf.WaitForState() +} + +func vpcClusterVpcWorkersVersionRefreshFunc(client v2.Workers, workerID, clusterID string, d *schema.ResourceData, target v2.ClusterTargetHeader, masterVersion string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + worker, err := client.Get(clusterID, workerID, target) + if err != nil { + return nil, "retry", fmt.Errorf("[ERROR] Error retrieving worker of container vpc cluster: %s", err) + } + // Check active updates + if worker.Health.State == "normal" { + return worker, workerNormal, nil + } + return worker, versionUpdating, nil + } +} diff --git a/ibm/resource_ibm_container_vpc_worker_pool.go b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool.go similarity index 75% rename from ibm/resource_ibm_container_vpc_worker_pool.go rename to ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool.go index 2e34a288b..8d231cb24 100644 --- a/ibm/resource_ibm_container_vpc_worker_pool.go +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -15,13 +15,16 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) const ( workerDesired = "deployed" ) -func resourceIBMContainerVpcWorkerPool() *schema.Resource { +func ResourceIBMContainerVpcWorkerPool() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerVpcWorkerPoolCreate, @@ -41,6 +44,9 @@ func resourceIBMContainerVpcWorkerPool() *schema.Resource { Required: true, ForceNew: true, Description: "Cluster name", + ValidateFunc: validate.InvokeValidator( + "ibm_container_vpc_worker_pool", + "cluster"), }, "flavor": { @@ -111,9 +117,9 @@ func resourceIBMContainerVpcWorkerPool() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", - ValidateFunc: InvokeValidator( + ValidateFunc: validate.InvokeValidator( "ibm_container_vpc_worker_pool", - "worker_taints"), + "effect"), }, }, }, @@ -140,35 +146,63 @@ func resourceIBMContainerVpcWorkerPool() *schema.Resource { "entitlement": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", }, - ResourceControllerURL: { + "host_pool_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The ID of the dedicated host pool associated with the worker pool", + }, + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "Resource Controller URL", }, + "kms_instance_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Instance ID for boot volume encryption", + RequiredWith: []string{"crk"}, + }, + "crk": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Root Key ID for boot volume encryption", + RequiredWith: []string{"kms_instance_id"}, + }, }, } } -func resourceContainerVPCWorkerPoolValidator() *ResourceValidator { +func ResourceIBMContainerVPCWorkerPoolValidator() *validate.ResourceValidator { tainteffects := "NoSchedule,PreferNoSchedule,NoExecute" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "worker_taints", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "effect", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: tainteffects}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) - containerVPCWorkerPoolTaintsValidator := ResourceValidator{ResourceName: "ibm_container_vpc_worker_pool", Schema: validateSchema} + containerVPCWorkerPoolTaintsValidator := validate.ResourceValidator{ResourceName: "ibm_container_vpc_worker_pool", Schema: validateSchema} return &containerVPCWorkerPoolTaintsValidator } func resourceIBMContainerVpcWorkerPoolCreate(d *schema.ResourceData, meta interface{}) error { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -191,14 +225,8 @@ func resourceIBMContainerVpcWorkerPoolCreate(d *schema.ResourceData, meta interf } - // for _, e := range d.Get("zones").(*schema.Set).List() { - // value := e.(map[string]interface{}) - // id := value["id"].(string) - // subnetid := value["subnet_id"].(string) - - // } - - workerPoolConfig := v2.WorkerPoolConfig{ + params := v2.WorkerPoolRequest{ + Cluster: clusterNameorID, Name: d.Get("worker_pool_name").(string), VpcID: d.Get("vpc_id").(string), Flavor: d.Get("flavor").(string), @@ -206,21 +234,30 @@ func resourceIBMContainerVpcWorkerPoolCreate(d *schema.ResourceData, meta interf Zones: zone, } + if v, ok := d.GetOk("kms_instance_id"); ok { + crk := d.Get("crk").(string) + wve := v2.WorkerVolumeEncryption{ + KmsInstanceID: v.(string), + WorkerVolumeCRKID: crk, + } + params.WorkerVolumeEncryption = &wve + } + if l, ok := d.GetOk("labels"); ok { labels := make(map[string]string) for k, v := range l.(map[string]interface{}) { labels[k] = v.(string) } - workerPoolConfig.Labels = labels - } - params := v2.WorkerPoolRequest{ - WorkerPoolConfig: workerPoolConfig, - Cluster: clusterNameorID, + params.Labels = labels } // Update workerpoolConfig with Entitlement option if provided if v, ok := d.GetOk("entitlement"); ok { - workerPoolConfig.Entitlement = v.(string) + params.Entitlement = v.(string) + } + + if hpid, ok := d.GetOk("host_pool_id"); ok { + params.HostPoolID = hpid.(string) } workerPoolsAPI := wpClient.WorkerPools() @@ -239,8 +276,7 @@ func resourceIBMContainerVpcWorkerPoolCreate(d *schema.ResourceData, meta interf //wait for workerpool availability _, err = WaitForWorkerPoolAvailable(d, meta, clusterNameorID, res.ID, d.Timeout(schema.TimeoutCreate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) } return resourceIBMContainerVpcWorkerPoolUpdate(d, meta) @@ -263,7 +299,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf if err != nil { return err } - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -271,8 +307,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf err = ClusterClient.WorkerPools().UpdateLabelsWorkerPool(clusterNameOrID, workerPoolName, labels, Env) if err != nil { - return fmt.Errorf( - "Error updating the labels: %s", err) + return fmt.Errorf("[ERROR] Error updating the labels: %s", err) } } if d.HasChange("taints") { @@ -284,7 +319,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf if err != nil { return err } - ClusterClient, err := meta.(ClientSession).VpcContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -302,7 +337,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf if err != nil { return err } - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -310,8 +345,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf err = ClusterClient.WorkerPools().ResizeWorkerPool(clusterNameOrID, workerPoolName, count, Env) if err != nil { - return fmt.Errorf( - "Error updating the worker_count %d: %s", count, err) + return fmt.Errorf("[ERROR] Error updating the worker_count %d: %s", count, err) } } @@ -334,7 +368,7 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf remove := os.Difference(ns).List() add := ns.Difference(os).List() if len(add) > 0 { - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -348,12 +382,11 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf } err = csClient.WorkerPools().CreateWorkerPoolZone(zoneParam, targetEnv) if err != nil { - return fmt.Errorf("Error adding zone to conatiner vpc cluster: %s", err) + return fmt.Errorf("[ERROR] Error adding zone to conatiner vpc cluster: %s", err) } _, err = WaitForWorkerPoolAvailable(d, meta, clusterID, workerPoolName, d.Timeout(schema.TimeoutCreate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) } } @@ -361,19 +394,18 @@ func resourceIBMContainerVpcWorkerPoolUpdate(d *schema.ResourceData, meta interf if len(remove) > 0 { for _, zone := range remove { oldZone := zone.(map[string]interface{}) - ClusterClient, err := meta.(ClientSession).ContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } Env := v1.ClusterTargetHeader{ResourceGroup: targetEnv.ResourceGroup} err = ClusterClient.WorkerPools().RemoveZone(clusterID, oldZone["name"].(string), workerPoolName, Env) if err != nil { - return fmt.Errorf("Error deleting zone to conatiner vpc cluster: %s", err) + return fmt.Errorf("[ERROR] Error deleting zone to conatiner vpc cluster: %s", err) } _, err = WaitForV2WorkerZoneDeleted(clusterID, workerPoolName, oldZone["name"].(string), meta, d.Timeout(schema.TimeoutDelete), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for deleting workers of worker pool (%s) of cluster (%s): %s", workerPoolName, clusterID, err) + return fmt.Errorf("[ERROR] Error waiting for deleting workers of worker pool (%s) of cluster (%s): %s", workerPoolName, clusterID, err) } } } @@ -413,11 +445,11 @@ func flattenWorkerPoolTaints(taints v2.GetWorkerPoolResponse) []map[string]inter return taintslist } func resourceIBMContainerVpcWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -448,7 +480,7 @@ func resourceIBMContainerVpcWorkerPoolRead(d *schema.ResourceData, meta interfac cls, err := wpClient.Clusters().GetCluster(cluster, targetEnv) if err != nil { - return fmt.Errorf("Error retrieving conatiner vpc cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving conatiner vpc cluster: %s", err) } d.Set("worker_pool_name", workerPool.PoolName) @@ -456,28 +488,33 @@ func resourceIBMContainerVpcWorkerPoolRead(d *schema.ResourceData, meta interfac d.Set("worker_count", workerPool.WorkerCount) d.Set("worker_pool_id", workerPoolID) // d.Set("provider", workerPool.Provider) - d.Set("labels", IgnoreSystemLabels(workerPool.Labels)) + d.Set("labels", flex.IgnoreSystemLabels(workerPool.Labels)) d.Set("zones", zones) d.Set("resource_group_id", cls.ResourceGroupID) d.Set("cluster", cluster) d.Set("vpc_id", workerPool.VpcID) + d.Set("host_pool_id", workerPool.HostPoolID) if workerPool.Taints != nil { d.Set("taints", flattenWorkerPoolTaints(workerPool)) } - controller, err := getBaseController(meta) + if workerPool.WorkerVolumeEncryption != nil { + d.Set("kms_instance_id", workerPool.WorkerVolumeEncryption.KmsInstanceID) + d.Set("crk", workerPool.WorkerVolumeEncryption.WorkerVolumeCRKID) + } + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") return nil } func resourceIBMContainerVpcWorkerPoolDelete(d *schema.ResourceData, meta interface{}) error { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -496,24 +533,23 @@ func resourceIBMContainerVpcWorkerPoolDelete(d *schema.ResourceData, meta interf } _, err = WaitForVpcWorkerDelete(clusterNameorID, workerPoolNameorID, meta, d.Timeout(schema.TimeoutDelete), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolNameorID, clusterNameorID, err) + return fmt.Errorf("[ERROR] Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolNameorID, clusterNameorID, err) } d.SetId("") return nil } func resourceIBMContainerVpcWorkerPoolExists(d *schema.ResourceData, meta interface{}) (bool, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID", d.Id()) } cluster := parts[0] workerPoolID := parts[1] @@ -531,7 +567,10 @@ func resourceIBMContainerVpcWorkerPoolExists(d *schema.ResourceData, meta interf return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container vpc workerpool: %s", err) + } + if strings.Compare(workerPool.Lifecycle.ActualState, "deleted") == 0 { + return false, nil } return workerPool.ID == workerPoolID, nil @@ -539,7 +578,7 @@ func resourceIBMContainerVpcWorkerPoolExists(d *schema.ResourceData, meta interf // WaitForWorkerPoolAvailable Waits for worker creation func WaitForWorkerPoolAvailable(d *schema.ResourceData, meta interface{}, clusterNameOrID, workerPoolNameOrID string, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -562,7 +601,7 @@ func vpcWorkerPoolStateRefreshFunc(client v2.Workers, instanceID string, workerP return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, "", false, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } // Check active transactions //Check for worker state to be deployed @@ -580,7 +619,7 @@ func vpcWorkerPoolStateRefreshFunc(client v2.Workers, instanceID string, workerP } func WaitForVpcWorkerDelete(clusterNameOrID, workerPoolNameOrID string, meta interface{}, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { - wpClient, err := meta.(ClientSession).VpcContainerAPI() + wpClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -601,7 +640,7 @@ func vpcworkerPoolDeleteStateRefreshFunc(client v2.Workers, instanceID, workerPo return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, "", true, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } //Done worker has two fields desiredState and actualState , so check for those 2 for _, e := range workerFields { diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool_test.go b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool_test.go new file mode 100644 index 000000000..3754d7abf --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_pool_test.go @@ -0,0 +1,307 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" +) + +func TestAccIBMContainerVpcClusterWorkerPoolBasic(t *testing.T) { + + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMVpcContainerWorkerPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMVpcContainerWorkerPoolBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "flavor", "cx2.2x4"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "zones.#", "1"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "labels.%", "2"), + ), + }, + { + Config: testAccCheckIBMVpcContainerWorkerPoolUpdate(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "flavor", "cx2.2x4"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "zones.#", "2"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "labels.%", "3"), + ), + }, + { + ResourceName: "ibm_container_vpc_worker_pool.test_pool", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIBMContainerVpcClusterWorkerPoolDedicatedHost(t *testing.T) { + + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + hostpoolID := acc.HostPoolID + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMVpcContainerWorkerPoolDedicatedHostCreate( + acc.ClusterName, + name, + "bx2d.4x16", + acc.IksClusterSubnetID, + acc.IksClusterVpcID, + acc.IksClusterResourceGroupID, + hostpoolID, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.vpc_worker_pool", "host_pool_id", hostpoolID), + ), + }, + }, + }) +} + +func testAccCheckIBMVpcContainerWorkerPoolDestroy(s *terraform.State) error { + + wpClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_vpc_worker_pool" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cluster := parts[0] + workerPoolID := parts[1] + + target := v2.ClusterTargetHeader{} + + // Try to find the key + wp, err := wpClient.WorkerPools().GetWorkerPool(cluster, workerPoolID, target) + + if err == nil { + if wp.ActualState == "deleted" && wp.DesiredState == "deleted" { + return nil + } + return fmt.Errorf("Worker pool still exists: %s", rs.Primary.ID) + } else if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error waiting for worker pool (%s) to be destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckIBMVpcContainerWorkerPoolBasic(name string) string { + return fmt.Sprintf(` + provider "ibm" { + region="eu-de" + } + data "ibm_resource_group" "resource_group" { + is_default=true + } + resource "ibm_is_vpc" "vpc" { + name = "%[1]s" + } + + resource "ibm_is_subnet" "subnet1" { + name = "%[1]s-1" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-1" + total_ipv4_address_count = 256 + } + + resource "ibm_is_subnet" "subnet2" { + name = "%[1]s-2" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-2" + total_ipv4_address_count = 256 + } + + resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + resource_group_id = data.ibm_resource_group.resource_group.id + wait_till = "MasterNodeReady" + zones { + subnet_id = ibm_is_subnet.subnet1.id + name = "eu-de-1" + } + } + resource "ibm_container_vpc_worker_pool" "test_pool" { + cluster = ibm_container_vpc_cluster.cluster.id + worker_pool_name = "%[1]s" + flavor = "cx2.2x4" + vpc_id = ibm_is_vpc.vpc.id + worker_count = 1 + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + name = "eu-de-2" + subnet_id = ibm_is_subnet.subnet2.id + } + labels = { + "test" = "test-pool" + "test1" = "test-pool1" + } + } + `, name) +} + +func testAccCheckIBMVpcContainerWorkerPoolUpdate(name string) string { + return fmt.Sprintf(` + provider "ibm" { + region="eu-de" + } + data "ibm_resource_group" "resource_group" { + is_default=true + } + resource "ibm_is_vpc" "vpc" { + name = "%[1]s" + } + resource "ibm_is_subnet" "subnet1" { + name = "%[1]s-1" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-1" + total_ipv4_address_count = 256 + } + resource "ibm_is_subnet" "subnet2" { + name = "%[1]s-2" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-2" + total_ipv4_address_count = 256 + } + resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + resource_group_id = data.ibm_resource_group.resource_group.id + wait_till = "MasterNodeReady" + zones { + subnet_id = ibm_is_subnet.subnet1.id + name = "eu-de-1" + } + } + resource "ibm_container_vpc_worker_pool" "test_pool" { + cluster = ibm_container_vpc_cluster.cluster.id + worker_pool_name = "%[1]s" + flavor = "cx2.2x4" + vpc_id = ibm_is_vpc.vpc.id + worker_count = 1 + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + name = "eu-de-2" + subnet_id = ibm_is_subnet.subnet2.id + } + zones { + subnet_id = ibm_is_subnet.subnet1.id + name = "eu-de-1" + } + labels = { + "test" = "test-pool" + "test1" = "test-pool1" + "test2" = "test-pool2" + } + } + `, name) +} + +func TestAccIBMContainerVpcClusterWorkerPoolEnvvar(t *testing.T) { + + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMVpcContainerWorkerPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMVpcContainerWorkerPoolEnvvar(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "flavor", "bx2.4x16"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "zones.#", "1"), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "kms_instance_id", acc.KmsInstanceID), + resource.TestCheckResourceAttr( + "ibm_container_vpc_worker_pool.test_pool", "crk", acc.CrkID), + ), + }, + { + ResourceName: "ibm_container_vpc_worker_pool.test_pool", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "kms_instance_id", "crk"}, + }, + }, + }) +} + +func testAccCheckIBMVpcContainerWorkerPoolDedicatedHostCreate(clusterName, name, flavor, subnetID, vpcID, rgroupID, hostpoolID string) string { + return fmt.Sprintf(` + resource "ibm_container_vpc_worker_pool" "vpc_worker_pool" { + cluster = "%s" + flavor = "%s" + worker_pool_name = "%s" + zones { + subnet_id = "%s" + name = "us-south-1" + } + worker_count = 1 + vpc_id = "%s" + resource_group_id = "%s" + host_pool_id = "%s" + } + `, clusterName, flavor, name, subnetID, vpcID, rgroupID, hostpoolID) +} + +func testAccCheckIBMVpcContainerWorkerPoolEnvvar(name string) string { + return fmt.Sprintf(` + resource "ibm_container_vpc_worker_pool" "test_pool" { + cluster = "%[2]s" + worker_pool_name = "%[1]s" + flavor = "bx2.4x16" + vpc_id = "%[3]s" + worker_count = 1 + zones { + subnet_id = "%[4]s" + name = "us-south-1" + } + kms_instance_id = "%[5]s" + crk = "%[6]s" + } + `, name, acc.IksClusterID, acc.IksClusterVpcID, acc.IksClusterSubnetID, acc.KmsInstanceID, acc.CrkID) +} diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_worker_test.go b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_test.go new file mode 100644 index 000000000..a067bcdac --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_worker_test.go @@ -0,0 +1,136 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" +) + +func TestAccIBMContainerVpcClusterWorkerBasic(t *testing.T) { + + name := fmt.Sprintf("tf-vpc-worker-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMVpcContainerWorkerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMVpcContainerWorkerBasic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMVpcContainerExists(), + ), + }, + { + ResourceName: "ibm_container_vpc_worker.test_worker", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMVpcContainerWorkerDestroy(s *terraform.State) error { + + //Destroy basically does nothing in this resource + return nil +} + +func testAccCheckIBMVpcContainerWorkerBasic(name string) string { + return fmt.Sprintf(` + provider "ibm" { + region="eu-de" + } + data "ibm_resource_group" "resource_group" { + is_default=true + } + resource "ibm_is_vpc" "vpc" { + name = "%[1]s" + } + + resource "ibm_is_subnet" "subnet1" { + name = "%[1]s-1" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-1" + total_ipv4_address_count = 256 + } + + resource "ibm_is_subnet" "subnet2" { + name = "%[1]s-2" + vpc = ibm_is_vpc.vpc.id + zone = "eu-de-2" + total_ipv4_address_count = 256 + } + + resource "ibm_container_vpc_cluster" "cluster" { + name = "%[1]s" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + resource_group_id = data.ibm_resource_group.resource_group.id + wait_till = "MasterNodeReady" + zones { + subnet_id = ibm_is_subnet.subnet1.id + name = "eu-de-1" + } + } + + data ibm_container_cluster_config "cluster_config: { + cluster_name_id = "%[1]s" + resource_group_id = data.ibm_resource_group.resource_group.id + } + + resource "ibm_container_vpc_worker" "test_worker" { + cluster_name = "%[1]s" + replace_worker = element(ibm_container_vpc_cluster.cluster.workers, 0) + resource_group_id = data.ibm_resource_group.resource_group.id + kube_config_path = data.ibm_container_cluster_config.cluster_config.config_file_path + check_ptx_status = false + } + `, name) +} + +func testAccCheckIBMVpcContainerExists() resource.TestCheckFunc { + return func(s *terraform.State) error { + + wpClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_container_vpc_worker" { + continue + } + + parts, err := flex.SepIdParts(rs.Primary.ID, "-") + if err != nil { + return err + } + if len(parts) < 2 { + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be in kube-clusterID-* format", rs.Primary.ID) + } + cluster := parts[1] + + target := v2.ClusterTargetHeader{} + + _, err = wpClient.Workers().Get(cluster, rs.Primary.ID, target) + if err != nil { + return fmt.Errorf("[ERROR] Error getting container vpc worker node: %s", err) + } + return nil + } + return fmt.Errorf("[ERROR] Error getting container vpc worker resource") + } +} diff --git a/ibm/resource_ibm_container_worker_pool.go b/ibm/service/kubernetes/resource_ibm_container_worker_pool.go similarity index 79% rename from ibm/resource_ibm_container_worker_pool.go rename to ibm/service/kubernetes/resource_ibm_container_worker_pool.go index ecc4a9364..0d9f9986c 100644 --- a/ibm/resource_ibm_container_worker_pool.go +++ b/ibm/service/kubernetes/resource_ibm_container_worker_pool.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -13,9 +13,12 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMContainerWorkerPool() *schema.Resource { +func ResourceIBMContainerWorkerPool() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerWorkerPoolCreate, @@ -34,6 +37,9 @@ func resourceIBMContainerWorkerPool() *schema.Resource { Required: true, ForceNew: true, Description: "Cluster name", + ValidateFunc: validate.InvokeValidator( + "ibm_container_worker_pool", + "cluster"), }, "machine_type": { @@ -53,14 +59,14 @@ func resourceIBMContainerWorkerPool() *schema.Resource { "size_per_zone": { Type: schema.TypeInt, Required: true, - ValidateFunc: validateSizePerZone, + ValidateFunc: validate.ValidateSizePerZone, Description: "Number of nodes per zone", }, "entitlement": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", }, @@ -69,7 +75,7 @@ func resourceIBMContainerWorkerPool() *schema.Resource { Optional: true, ForceNew: true, Default: hardwareShared, - ValidateFunc: validateAllowedStringValue([]string{hardwareShared, hardwareDedicated}), + ValidateFunc: validate.ValidateAllowedStringValues([]string{hardwareShared, hardwareDedicated}), Description: "Hardware type", }, @@ -147,9 +153,9 @@ func resourceIBMContainerWorkerPool() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", - ValidateFunc: InvokeValidator( + ValidateFunc: validate.InvokeValidator( "ibm_container_worker_pool", - "worker_taints"), + "effect"), }, }, }, @@ -168,9 +174,9 @@ func resourceIBMContainerWorkerPool() *schema.Resource { Optional: true, Description: "ID of the resource group.", ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", @@ -179,23 +185,31 @@ func resourceIBMContainerWorkerPool() *schema.Resource { } } -func resourceContainerWorkerPoolValidator() *ResourceValidator { +func ResourceIBMContainerWorkerPoolValidator() *validate.ResourceValidator { tainteffects := "NoSchedule,PreferNoSchedule,NoExecute" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "worker_taints", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "effect", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: tainteffects}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) - containerWorkerPoolTaintsValidator := ResourceValidator{ResourceName: "ibm_container_worker_pool", Schema: validateSchema} + containerWorkerPoolTaintsValidator := validate.ResourceValidator{ResourceName: "ibm_container_worker_pool", Schema: validateSchema} return &containerWorkerPoolTaintsValidator } func resourceIBMContainerWorkerPoolCreate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -253,11 +267,11 @@ func resourceIBMContainerWorkerPoolCreate(d *schema.ResourceData, meta interface } func resourceIBMContainerWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -291,28 +305,28 @@ func resourceIBMContainerWorkerPoolRead(d *schema.ResourceData, meta interface{} } d.Set("hardware", hardware) d.Set("state", workerPool.State) - d.Set("labels", IgnoreSystemLabels(workerPool.Labels)) - d.Set("zones", flattenZones(workerPool.Zones)) + d.Set("labels", flex.IgnoreSystemLabels(workerPool.Labels)) + d.Set("zones", flex.FlattenZones(workerPool.Zones)) d.Set("cluster", cluster) if strings.Contains(machineType, "encrypted") { d.Set("disk_encryption", true) } else { d.Set("disk_encryption", false) } - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/kubernetes/clusters") + d.Set(flex.ResourceControllerURL, controller+"/kubernetes/clusters") return nil } func resourceIBMContainerWorkerPoolUpdate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -332,8 +346,7 @@ func resourceIBMContainerWorkerPoolUpdate(d *schema.ResourceData, meta interface _, err = WaitForWorkerNormal(clusterNameorID, workerPoolNameorID, meta, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPoolNameorID, clusterNameorID, err) + return fmt.Errorf("[ERROR] Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPoolNameorID, clusterNameorID, err) } } if d.HasChange("labels") { @@ -350,8 +363,7 @@ func resourceIBMContainerWorkerPoolUpdate(d *schema.ResourceData, meta interface _, err = WaitForWorkerNormal(clusterNameorID, workerPoolNameorID, meta, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPoolNameorID, clusterNameorID, err) + return fmt.Errorf("[ERROR] Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPoolNameorID, clusterNameorID, err) } } if d.HasChange("taints") { @@ -361,7 +373,7 @@ func resourceIBMContainerWorkerPoolUpdate(d *schema.ResourceData, meta interface if err != nil { return err } - ClusterClient, err := meta.(ClientSession).VpcContainerAPI() + ClusterClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -375,11 +387,11 @@ func resourceIBMContainerWorkerPoolUpdate(d *schema.ResourceData, meta interface } func resourceIBMContainerWorkerPoolDelete(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -398,23 +410,22 @@ func resourceIBMContainerWorkerPoolDelete(d *schema.ResourceData, meta interface } _, err = WaitForWorkerDelete(clusterNameorID, workerPoolNameorID, meta, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolNameorID, clusterNameorID, err) + return fmt.Errorf("[ERROR] Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolNameorID, clusterNameorID, err) } return nil } func resourceIBMContainerWorkerPoolExists(d *schema.ResourceData, meta interface{}) (bool, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID", d.Id()) } cluster := parts[0] workerPoolID := parts[1] @@ -432,14 +443,14 @@ func resourceIBMContainerWorkerPoolExists(d *schema.ResourceData, meta interface return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container workerpool: %s", err) } return workerPool.ID == workerPoolID, nil } func WaitForWorkerNormal(clusterNameOrID, workerPoolNameOrID string, meta interface{}, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -460,7 +471,7 @@ func workerPoolStateRefreshFunc(client v1.Workers, instanceID, workerPoolNameOrI return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, workerPoolNameOrID, false, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } //Done worker has two fields State and Status , so check for those 2 for _, e := range workerFields { @@ -475,7 +486,7 @@ func workerPoolStateRefreshFunc(client v1.Workers, instanceID, workerPoolNameOrI } func WaitForWorkerDelete(clusterNameOrID, workerPoolNameOrID string, meta interface{}, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -496,7 +507,7 @@ func workerPoolDeleteStateRefreshFunc(client v1.Workers, instanceID, workerPoolN return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, "", true, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } //Done worker has two fields State and Status , so check for those 2 for _, e := range workerFields { @@ -512,16 +523,16 @@ func workerPoolDeleteStateRefreshFunc(client v1.Workers, instanceID, workerPoolN func getWorkerPoolTargetHeader(d *schema.ResourceData, meta interface{}) (v1.ClusterTargetHeader, error) { - _, err := meta.(ClientSession).BluemixSession() + _, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return v1.ClusterTargetHeader{}, err } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return v1.ClusterTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v1.ClusterTargetHeader{ AccountID: accountID, diff --git a/ibm/resource_ibm_container_worker_pool_test.go b/ibm/service/kubernetes/resource_ibm_container_worker_pool_test.go similarity index 85% rename from ibm/resource_ibm_container_worker_pool_test.go rename to ibm/service/kubernetes/resource_ibm_container_worker_pool_test.go index 81b945da1..2106efe6b 100644 --- a/ibm/resource_ibm_container_worker_pool_test.go +++ b/ibm/service/kubernetes/resource_ibm_container_worker_pool_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" @@ -9,6 +9,10 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -21,8 +25,8 @@ func TestAccIBMContainerWorkerPoolBasic(t *testing.T) { clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerWorkerPoolDestroy, Steps: []resource.TestStep{ { @@ -72,8 +76,8 @@ func TestAccIBMContainerWorkerPoolInvalidSizePerZone(t *testing.T) { workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMContainerWorkerPoolDestroy, Steps: []resource.TestStep{ { @@ -86,7 +90,7 @@ func TestAccIBMContainerWorkerPoolInvalidSizePerZone(t *testing.T) { func testAccCheckIBMContainerWorkerPoolDestroy(s *terraform.State) error { - csClient, err := testAccProvider.Meta().(ClientSession).ContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -96,7 +100,7 @@ func testAccCheckIBMContainerWorkerPoolDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -104,7 +108,7 @@ func testAccCheckIBMContainerWorkerPoolDestroy(s *terraform.State) error { workerPoolID := parts[1] target := v1.ClusterTargetHeader{ - Region: csRegion, + Region: acc.CsRegion, } // Try to find the key @@ -113,7 +117,7 @@ func testAccCheckIBMContainerWorkerPoolDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Worker pool still exists: %s", rs.Primary.ID) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for worker pool (%s) to be destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error waiting for worker pool (%s) to be destroyed: %s", rs.Primary.ID, err) } } @@ -145,7 +149,7 @@ resource "ibm_container_worker_pool" "test_pool" { "test" = "test-pool" "test1" = "test-pool1" } -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeVersion, workerPoolName, machineType) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeVersion, workerPoolName, acc.MachineType) } func testAccCheckIBMContainerWorkerPoolUpdate(clusterName, workerPoolName string) string { @@ -173,7 +177,7 @@ resource "ibm_container_worker_pool" "test_pool" { "test" = "test-pool" "test1" = "test-pool1" } -}`, clusterName, datacenter, machineType, publicVlanID, privateVlanID, kubeVersion, workerPoolName, machineType) +}`, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeVersion, workerPoolName, acc.MachineType) } func testAccCheckIBMContainerWorkerPoolInvalidSizePerZone(clusterName, workerPoolName string) string { @@ -190,5 +194,5 @@ resource "ibm_container_worker_pool" "test_pool" { "test" = "test-pool" "test1" = "test-pool1" } -}`, workerPoolName, machineType, clusterName) +}`, workerPoolName, acc.MachineType, clusterName) } diff --git a/ibm/resource_ibm_container_worker_pool_zone_attachment.go b/ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment.go similarity index 79% rename from ibm/resource_ibm_container_worker_pool_zone_attachment.go rename to ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment.go index d550b1b15..4e4ad821b 100644 --- a/ibm/resource_ibm_container_worker_pool_zone_attachment.go +++ b/ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -13,9 +13,12 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) -func resourceIBMContainerWorkerPoolZoneAttachment() *schema.Resource { +func ResourceIBMContainerWorkerPoolZoneAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMContainerWorkerPoolZoneAttachmentCreate, @@ -43,6 +46,9 @@ func resourceIBMContainerWorkerPoolZoneAttachment() *schema.Resource { Required: true, ForceNew: true, Description: "cluster name or ID", + ValidateFunc: validate.InvokeValidator( + "ibm_container_worker_pool_zone_attachment", + "cluster"), }, "worker_pool": { @@ -69,7 +75,7 @@ func resourceIBMContainerWorkerPoolZoneAttachment() *schema.Resource { Optional: true, Description: "ID of the resource group.", ForceNew: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, "region": { @@ -88,15 +94,29 @@ func resourceIBMContainerWorkerPoolZoneAttachment() *schema.Resource { Type: schema.TypeBool, Optional: true, Default: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, Description: "wait_till_albs can be configured to wait for albs during the worker pool zone attachment.", }, }, } } +func ResourceIBMContainerWorkerPoolZoneAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + Required: true, + CloudDataType: "cluster", + CloudDataRange: []string{"resolved_to:id"}}) + + iBMContainerWorkerPoolZoneAttachmentValidator := validate.ResourceValidator{ResourceName: "ibm_container_nlb_dns", Schema: validateSchema} + return &iBMContainerWorkerPoolZoneAttachmentValidator +} func resourceIBMContainerWorkerPoolZoneAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -112,8 +132,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentCreate(d *schema.ResourceData, } if publicVLAN != "" && privateVLAN == "" { - return fmt.Errorf( - "A private_vlan_id must be specified if a public_vlan_id is specified.") + return fmt.Errorf("[ERROR] A private_vlan_id must be specified if a public_vlan_id is specified.") } workerPoolZoneNetwork := v1.WorkerPoolZoneNetwork{ @@ -143,8 +162,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentCreate(d *schema.ResourceData, _, err = WaitForWorkerZoneNormal(cluster, workerPool, zone, meta, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPool, cluster, err) + return fmt.Errorf("[ERROR] Error waiting for workers of worker pool (%s) of cluster (%s) to become ready: %s", workerPool, cluster, err) } var waitTillALBs bool @@ -155,8 +173,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentCreate(d *schema.ResourceData, if waitTillALBs { _, err = waitForWorkerZoneALB(cluster, zone, meta, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for ALBs in zone (%s) of cluster (%s) to become ready: %s", zone, cluster, err) + return fmt.Errorf("[ERROR] Error waiting for ALBs in zone (%s) of cluster (%s) to become ready: %s", zone, cluster, err) } } @@ -165,11 +182,11 @@ func resourceIBMContainerWorkerPoolZoneAttachmentCreate(d *schema.ResourceData, } func resourceIBMContainerWorkerPoolZoneAttachmentRead(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -206,7 +223,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentRead(d *schema.ResourceData, me } func resourceIBMContainerWorkerPoolZoneAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -217,14 +234,13 @@ func resourceIBMContainerWorkerPoolZoneAttachmentUpdate(d *schema.ResourceData, privateVLAN := d.Get("private_vlan_id").(string) publicVLAN := d.Get("public_vlan_id").(string) if publicVLAN != "" && privateVLAN == "" { - return fmt.Errorf( - "A private VLAN must be specified if a public VLAN is specified.") + return fmt.Errorf("[ERROR] A private VLAN must be specified if a public VLAN is specified") } targetEnv, err := getWorkerPoolTargetHeader(d, meta) if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -241,12 +257,12 @@ func resourceIBMContainerWorkerPoolZoneAttachmentUpdate(d *schema.ResourceData, } func resourceIBMContainerWorkerPoolZoneAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -265,24 +281,23 @@ func resourceIBMContainerWorkerPoolZoneAttachmentDelete(d *schema.ResourceData, } _, err = WaitForWorkerZoneDeleted(cluster, workerPool, zone, meta, d.Timeout(schema.TimeoutDelete), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for deleting workers of worker pool (%s) of cluster (%s): %s", workerPool, cluster, err) + return fmt.Errorf("[ERROR] Error waiting for deleting workers of worker pool (%s) of cluster (%s): %s", workerPool, cluster, err) } return nil } func resourceIBMContainerWorkerPoolZoneAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) < 3 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID/ZoneID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterID/WorkerPoolID/ZoneID", d.Id()) } cluster := parts[0] workerPoolID := parts[1] @@ -301,7 +316,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentExists(d *schema.ResourceData, return false, nil } } - return false, fmt.Errorf("Error communicating with the API: %s", err) + return false, fmt.Errorf("[ERROR] Error getting container workerpool during zone attachment: %s", err) } zones := workerPool.Zones var zone v1.WorkerPoolZoneResponse @@ -314,7 +329,7 @@ func resourceIBMContainerWorkerPoolZoneAttachmentExists(d *schema.ResourceData, } func WaitForWorkerZoneNormal(clusterNameOrID, workerPoolNameOrID, zone string, meta interface{}, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -335,7 +350,7 @@ func workerPoolZoneStateRefreshFunc(client v1.Workers, instanceID, workerPoolNam return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, workerPoolNameOrID, false, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } //Done worker has two fields State and Status , so check for those 2 for _, e := range workerFields { @@ -352,7 +367,7 @@ func workerPoolZoneStateRefreshFunc(client v1.Workers, instanceID, workerPoolNam } func WaitForWorkerZoneDeleted(clusterNameOrID, workerPoolNameOrID, zone string, meta interface{}, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -373,7 +388,7 @@ func workerPoolZoneDeleteStateRefreshFunc(client v1.Workers, instanceID, workerP return func() (interface{}, string, error) { workerFields, err := client.ListByWorkerPool(instanceID, workerPoolNameOrID, true, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving workers for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s", err) } //Done worker has two fields State and Status , so check for those 2 for _, e := range workerFields { @@ -388,7 +403,7 @@ func workerPoolZoneDeleteStateRefreshFunc(client v1.Workers, instanceID, workerP } func waitForWorkerZoneALB(clusterNameOrID, zone string, meta interface{}, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -410,7 +425,7 @@ func workerZoneALBStateRefreshFunc(client v1.Albs, instanceID, zone string, targ // Get all ALBs associated with cluster albs, err := client.ListClusterALBs(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving ALBs for cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving ALBs for cluster: %s", err) } privateALBsByZone := []v1.ALBConfig{} diff --git a/ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment_test.go b/ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment_test.go new file mode 100644 index 000000000..b3c4ddbb9 --- /dev/null +++ b/ibm/service/kubernetes/resource_ibm_container_worker_pool_zone_attachment_test.go @@ -0,0 +1,246 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package kubernetes_test + +import ( + "fmt" + "regexp" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/softlayer/softlayer-go/services" + "github.com/softlayer/softlayer-go/sl" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +const NOT_FOUND = "SoftLayer_Exception_Network_LBaaS_ObjectNotFound" + +func TestAccIBMContainerWorkerPoolZoneAttachment_basic(t *testing.T) { + + workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) + clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentBasic(clusterName, workerPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", acc.ZoneUpdatePrivateVlan), + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "public_vlan_id", acc.ZonePublicVlan), + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "2"), + ), + }, + { + Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentUpdatePublicVlan(clusterName, workerPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", acc.ZoneUpdatePrivateVlan), + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "public_vlan_id", acc.ZoneUpdatePublicVlan), + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "1"), + ), + }, + { + ResourceName: "ibm_container_worker_pool_zone_attachment.test_zone", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func TestAccIBMContainerWorkerPoolZoneAttachment_privateVlanOnly(t *testing.T) { + workerPoolName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) + clusterName := fmt.Sprintf("tf-cluster-worker-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentPrivateVlanOnly(clusterName, workerPoolName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "private_vlan_id", acc.ZoneUpdatePrivateVlan), + resource.TestCheckResourceAttr( + "ibm_container_worker_pool_zone_attachment.test_zone", "worker_count", "1"), + ), + }, + }, + }) +} + +func TestAccIBMContainerWorkerPoolZoneAttachment_publicVlanOnly(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMLbaasDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMContainerWorkerPoolZoneAttachmentPublicVlanOnly(), + ExpectError: regexp.MustCompile("must be specified if a public_vlan_id"), + }, + }, + }) +} + +func testAccCheckIBMLbaasDestroy(s *terraform.State) error { + sess := acc.TestAccProvider.Meta().(conns.ClientSession).SoftLayerSession() + service := services.GetNetworkLBaaSLoadBalancerService(sess) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_lbaas" { + continue + } + + // Try to find the key + _, err := service.GetLoadBalancer(sl.String(rs.Primary.ID)) + + if err == nil { + return fmt.Errorf("load balancer (%s) to be destroyed still exists", rs.Primary.ID) + } else if apiErr, ok := err.(sl.Error); ok && apiErr.Exception != NOT_FOUND { + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be destroyed: %s", rs.Primary.ID, err) + } + + } + + return nil +} + +func testAccCheckIBMContainerWorkerPoolZoneAttachmentBasic(clusterName, workerPoolName string) string { + return fmt.Sprintf(` + +resource "ibm_container_cluster" "testacc_cluster" { + name = "%s" + datacenter = "%s" + machine_type = "%s" + hardware = "shared" + public_vlan_id = "%s" + private_vlan_id = "%s" + kube_version = "%s" + wait_till = "OneWorkerNodeReady" +} + +resource "ibm_container_worker_pool" "test_pool" { + worker_pool_name = "%s" + machine_type = "%s" + cluster = ibm_container_cluster.testacc_cluster.id + size_per_zone = 2 + hardware = "shared" + disk_encryption = "true" + labels = { + "test" = "test-pool" + "test1" = "test-pool1" + } +} + +resource "ibm_container_worker_pool_zone_attachment" "test_zone" { + cluster = ibm_container_cluster.testacc_cluster.id + zone = "%s" + worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) + private_vlan_id = "%s" + public_vlan_id = "%s" + wait_till_albs = false +} + + `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeUpdateVersion, workerPoolName, acc.MachineType, acc.Zone, acc.ZoneUpdatePrivateVlan, acc.ZonePublicVlan) +} + +func testAccCheckIBMContainerWorkerPoolZoneAttachmentPrivateVlanOnly(clusterName, workerPoolName string) string { + return fmt.Sprintf(` + +resource "ibm_container_cluster" "testacc_cluster" { + name = "%s" + datacenter = "%s" + machine_type = "%s" + hardware = "shared" + public_vlan_id = "%s" + private_vlan_id = "%s" + kube_version = "%s" + wait_time_minutes = 180 + wait_till = "MasterNodeReady" +} + +resource "ibm_container_worker_pool" "test_pool" { + worker_pool_name = "%s" + machine_type = "%s" + cluster = ibm_container_cluster.testacc_cluster.id + size_per_zone = 1 + hardware = "shared" + disk_encryption = "true" + labels = { + "test" = "test-pool" + "test1" = "test-pool1" + } +} + +resource "ibm_container_worker_pool_zone_attachment" "test_zone" { + cluster = ibm_container_cluster.testacc_cluster.id + zone = "%s" + worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) + private_vlan_id = "%s" +} + + `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeUpdateVersion, workerPoolName, acc.MachineType, acc.Zone, acc.ZoneUpdatePrivateVlan) +} + +func testAccCheckIBMContainerWorkerPoolZoneAttachmentPublicVlanOnly() string { + return fmt.Sprintf(` + resource "ibm_container_worker_pool_zone_attachment" "test_zone" { + cluster = "test" + zone = "ams03" + worker_pool = "testpool" + public_vlan_id = "%s" + } + + `, acc.PublicVlanID) +} + +func testAccCheckIBMContainerWorkerPoolZoneAttachmentUpdatePublicVlan(clusterName, workerPoolName string) string { + return fmt.Sprintf(` + +resource "ibm_container_cluster" "testacc_cluster" { + name = "%s" + datacenter = "%s" + machine_type = "%s" + hardware = "shared" + public_vlan_id = "%s" + private_vlan_id = "%s" + kube_version = "%s" + wait_till = "OneWorkerNodeReady" +} + +resource "ibm_container_worker_pool" "test_pool" { + worker_pool_name = "%s" + machine_type = "%s" + cluster = ibm_container_cluster.testacc_cluster.id + size_per_zone = 1 + hardware = "shared" + disk_encryption = "true" + labels = { + "test" = "test-pool" + "test1" = "test-pool1" + } +} + +resource "ibm_container_worker_pool_zone_attachment" "test_zone" { + cluster = ibm_container_cluster.testacc_cluster.id + zone = "%s" + worker_pool = element(split("/", ibm_container_worker_pool.test_pool.id), 1) + private_vlan_id = "%s" + public_vlan_id = "%s" +} + + `, clusterName, acc.Datacenter, acc.MachineType, acc.PublicVlanID, acc.PrivateVlanID, acc.KubeUpdateVersion, workerPoolName, acc.MachineType, acc.Zone, acc.ZoneUpdatePrivateVlan, acc.ZoneUpdatePublicVlan) +} diff --git a/ibm/resource_ibm_ob_logging.go b/ibm/service/kubernetes/resource_ibm_ob_logging.go similarity index 86% rename from ibm/resource_ibm_ob_logging.go rename to ibm/service/kubernetes/resource_ibm_ob_logging.go index 7ae939010..6cd806b47 100644 --- a/ibm/resource_ibm_ob_logging.go +++ b/ibm/service/kubernetes/resource_ibm_ob_logging.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -14,6 +14,8 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" ) const ( @@ -30,7 +32,7 @@ const ( obLoggingNamespace = "namespace" ) -func resourceIBMObLogging() *schema.Resource { +func ResourceIBMObLogging() *schema.Resource { return &schema.Resource{ Create: resourceIBMLoggingCreate, Read: resourceIBMLoggingRead, @@ -121,7 +123,7 @@ func waitForClusterIntegration(d *schema.ResourceData, meta interface{}, cluster if err != nil { return nil, err } - csClient, err := meta.(ClientSession).VpcContainerAPI() + csClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return nil, err } @@ -147,7 +149,7 @@ func waitForClusterIntegration(d *schema.ResourceData, meta interface{}, cluster } func resourceIBMLoggingCreate(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -193,7 +195,7 @@ func resourceIBMLoggingCreate(d *schema.ResourceData, meta interface{}) error { logging, err = client.Logging().CreateLoggingConfig(params, targetEnv) if err != nil { log.Printf("[DEBUG] logging Instance err %s", err) - if strings.Contains(err.Error(), "The user doesn't have enough privileges to perform this action") { + if strings.Contains(err.Error(), "The user doesn't have enough privileges to perform this action") || strings.Contains(err.Error(), "A logging or monitoring configuration for this cluster already exists. To use a different configuration, delete the existing configuration and try again") { return resource.RetryableError(err) } return resource.NonRetryableError(err) @@ -202,11 +204,11 @@ func resourceIBMLoggingCreate(d *schema.ResourceData, meta interface{}) error { return nil }) - if isResourceTimeoutError(err) { + if conns.IsResourceTimeoutError(err) { logging, err = client.Logging().CreateLoggingConfig(params, targetEnv) } if err != nil { - return fmt.Errorf("error latching logging instance to cluster: %w", err) + return fmt.Errorf("[ERROR] Error latching logging instance to cluster: %w", err) } d.SetId(fmt.Sprintf("%s/%s", clusterName, logging.InstanceID)) @@ -215,16 +217,16 @@ func resourceIBMLoggingCreate(d *schema.ResourceData, meta interface{}) error { } func getLoggingTargetHeader(d *schema.ResourceData, meta interface{}) (v2.LoggingTargetHeader, error) { - _, err := meta.(ClientSession).BluemixSession() + _, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return v2.LoggingTargetHeader{}, err } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return v2.LoggingTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v2.LoggingTargetHeader{ AccountID: accountID, @@ -235,17 +237,17 @@ func getLoggingTargetHeader(d *schema.ResourceData, meta interface{}) (v2.Loggin func resourceIBMLoggingRead(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } if len(parts) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterNameorID/loggingID", d.Id()) + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterNameorID/loggingID", d.Id()) } clusterName := parts[0] loggingID := parts[1] @@ -263,7 +265,7 @@ func resourceIBMLoggingRead(d *schema.ResourceData, meta interface{}) error { return nil } } - return fmt.Errorf("Error in GetLoggingConfig: %s", err) + return fmt.Errorf("[ERROR] Error in GetLoggingConfig: %s", err) } d.Set(obLoggingPrivateEndpoint, config.PrivateEndpoint) @@ -284,7 +286,7 @@ func resourceIBMLoggingUpdate(d *schema.ResourceData, meta interface{}) error { hasChanged := false idChanged := false - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -296,7 +298,7 @@ func resourceIBMLoggingUpdate(d *schema.ResourceData, meta interface{}) error { loggingUpdateModel := v2.LoggingUpdateRequest{} - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -342,7 +344,7 @@ func resourceIBMLoggingUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMLoggingDelete(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -352,7 +354,7 @@ func resourceIBMLoggingDelete(d *schema.ResourceData, meta interface{}) error { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -373,7 +375,7 @@ func resourceIBMLoggingDelete(d *schema.ResourceData, meta interface{}) error { return nil } } - return fmt.Errorf("Error in DeleteLoggingConfig: %s", err) + return fmt.Errorf("[ERROR] Error in DeleteLoggingConfig: %s", err) } d.SetId("") return nil diff --git a/ibm/resource_ibm_ob_logging_test.go b/ibm/service/kubernetes/resource_ibm_ob_logging_test.go similarity index 87% rename from ibm/resource_ibm_ob_logging_test.go rename to ibm/service/kubernetes/resource_ibm_ob_logging_test.go index 35bcb507e..6682687d0 100644 --- a/ibm/resource_ibm_ob_logging_test.go +++ b/ibm/service/kubernetes/resource_ibm_ob_logging_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,8 +24,8 @@ func TestAccIBMLogging_basic(t *testing.T) { updatedIngestionKey := fmt.Sprintf("tf-keys-updated-%d", acctest.RandIntRange(10, 100)) updatedLoggingName := fmt.Sprintf("tf-logging-updated2-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMLoggingDestroy, Steps: []resource.TestStep{ { @@ -54,12 +58,12 @@ func testAccCheckIBMLoggingExists(n string) resource.TestCheckFunc { if !ok { return fmt.Errorf("Not found: %s", n) } - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } loggingID := rs.Primary.ID - parts, err := idParts(loggingID) + parts, err := flex.IdParts(loggingID) if err != nil { return err } @@ -82,7 +86,7 @@ func testAccCheckIBMLoggingExists(n string) resource.TestCheckFunc { } func testAccCheckIBMLoggingDestroy(s *terraform.State) error { - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -93,7 +97,7 @@ func testAccCheckIBMLoggingDestroy(s *terraform.State) error { } loggingID := rs.Primary.ID - parts, err := idParts(loggingID) + parts, err := flex.IdParts(loggingID) if err != nil { return err } @@ -118,12 +122,12 @@ func testAccCheckIBMLoggingDestroy(s *terraform.State) error { func getLoggingTarget() (v2.LoggingTargetHeader, error) { - userDetails, err := testAccProvider.Meta().(ClientSession).BluemixUserDetails() + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() if err != nil { return v2.LoggingTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v2.LoggingTargetHeader{ AccountID: accountID, @@ -169,7 +173,7 @@ func testAccCheckIBMLoggingBasic(clusterName, loggingName, ingestionKeyName stri depends_on = [ibm_resource_key.resourceKey] cluster = ibm_container_cluster.testacc_cluster.id instance_id = ibm_resource_instance.instance.guid - }`, clusterName, datacenter, machineType, loggingName, ingestionKeyName) + }`, clusterName, acc.Datacenter, acc.MachineType, loggingName, ingestionKeyName) } func testAccCheckIBMLoggingUpdate(clusterName, loggingName, ingestionKeyName, instanceName, keyName string) string { @@ -223,5 +227,5 @@ func testAccCheckIBMLoggingUpdate(clusterName, loggingName, ingestionKeyName, in cluster = ibm_container_cluster.testacc_cluster.id instance_id = ibm_resource_instance.instance2.guid private_endpoint = true - }`, clusterName, datacenter, machineType, loggingName, ingestionKeyName, instanceName, keyName) + }`, clusterName, acc.Datacenter, acc.MachineType, loggingName, ingestionKeyName, instanceName, keyName) } diff --git a/ibm/resource_ibm_ob_monitoring.go b/ibm/service/kubernetes/resource_ibm_ob_monitoring.go similarity index 86% rename from ibm/resource_ibm_ob_monitoring.go rename to ibm/service/kubernetes/resource_ibm_ob_monitoring.go index deadd2dae..ffc562e86 100644 --- a/ibm/resource_ibm_ob_monitoring.go +++ b/ibm/service/kubernetes/resource_ibm_ob_monitoring.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes import ( "fmt" @@ -14,6 +14,8 @@ import ( v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" ) const ( @@ -30,7 +32,7 @@ const ( obMonitoringNamespace = "namespace" ) -func resourceIBMObMonitoring() *schema.Resource { +func ResourceIBMObMonitoring() *schema.Resource { return &schema.Resource{ Create: resourceIBMMonitoringCreate, Read: resourceIBMMonitoringRead, @@ -119,7 +121,7 @@ func resourceIBMObMonitoring() *schema.Resource { func resourceIBMMonitoringCreate(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -164,7 +166,7 @@ func resourceIBMMonitoringCreate(d *schema.ResourceData, meta interface{}) error monitoring, err = client.Monitoring().CreateMonitoringConfig(params, targetEnv) if err != nil { log.Printf("[DEBUG] monitoring Instance err %s", err) - if strings.Contains(err.Error(), "The user doesn't have enough privileges to perform this action") { + if strings.Contains(err.Error(), "The user doesn't have enough privileges to perform this action") || strings.Contains(err.Error(), "A logging or monitoring configuration for this cluster already exists. To use a different configuration, delete the existing configuration and try again") { return resource.RetryableError(err) } return resource.NonRetryableError(err) @@ -173,11 +175,11 @@ func resourceIBMMonitoringCreate(d *schema.ResourceData, meta interface{}) error return nil }) - if isResourceTimeoutError(err) { + if conns.IsResourceTimeoutError(err) { monitoring, err = client.Monitoring().CreateMonitoringConfig(params, targetEnv) } if err != nil { - return fmt.Errorf("error latching monitoring instance to cluster: %w", err) + return fmt.Errorf("[ERROR] Error latching monitoring instance to cluster: %w", err) } d.SetId(fmt.Sprintf("%s/%s", clusterName, monitoring.InstanceID)) @@ -186,16 +188,16 @@ func resourceIBMMonitoringCreate(d *schema.ResourceData, meta interface{}) error } func getMonitoringTargetHeader(d *schema.ResourceData, meta interface{}) (v2.MonitoringTargetHeader, error) { - _, err := meta.(ClientSession).BluemixSession() + _, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return v2.MonitoringTargetHeader{}, err } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return v2.MonitoringTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v2.MonitoringTargetHeader{ AccountID: accountID, @@ -206,17 +208,17 @@ func getMonitoringTargetHeader(d *schema.ResourceData, meta interface{}) (v2.Mon func resourceIBMMonitoringRead(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } if len(parts) < 2 { - return fmt.Errorf("Incorrect ID %s: Id should be a combination of clusterNameorID/monitoringID", d.Id()) + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of clusterNameorID/monitoringID", d.Id()) } clusterName := parts[0] monitoringID := parts[1] @@ -234,7 +236,7 @@ func resourceIBMMonitoringRead(d *schema.ResourceData, meta interface{}) error { return nil } } - return fmt.Errorf("Error in GetMonitoringConfig: %s", err) + return fmt.Errorf("[ERROR] Error in GetMonitoringConfig: %s", err) } d.Set(obMonitoringPrivateEndpoint, config.PrivateEndpoint) @@ -255,7 +257,7 @@ func resourceIBMMonitoringUpdate(d *schema.ResourceData, meta interface{}) error hasChanged := false idChanged := false - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -267,7 +269,7 @@ func resourceIBMMonitoringUpdate(d *schema.ResourceData, meta interface{}) error monitoringUpdateModel := v2.MonitoringUpdateRequest{} - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -314,7 +316,7 @@ func resourceIBMMonitoringUpdate(d *schema.ResourceData, meta interface{}) error func resourceIBMMonitoringDelete(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(ClientSession).VpcContainerAPI() + client, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -324,7 +326,7 @@ func resourceIBMMonitoringDelete(d *schema.ResourceData, meta interface{}) error return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -346,7 +348,7 @@ func resourceIBMMonitoringDelete(d *schema.ResourceData, meta interface{}) error return nil } } - return fmt.Errorf("Error in DeleteMonitoringConfig: %s", err) + return fmt.Errorf("[ERROR] Error in DeleteMonitoringConfig: %s", err) } d.SetId("") return nil diff --git a/ibm/resource_ibm_ob_monitoring_test.go b/ibm/service/kubernetes/resource_ibm_ob_monitoring_test.go similarity index 87% rename from ibm/resource_ibm_ob_monitoring_test.go rename to ibm/service/kubernetes/resource_ibm_ob_monitoring_test.go index 8570d5abb..655cdfdc5 100644 --- a/ibm/resource_ibm_ob_monitoring_test.go +++ b/ibm/service/kubernetes/resource_ibm_ob_monitoring_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package kubernetes_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,8 +24,8 @@ func TestAccIBMMonitoring_basic(t *testing.T) { updatedIngestionKey := fmt.Sprintf("tf-key-updated-%d", acctest.RandIntRange(10, 100)) updatedMonitoringName := fmt.Sprintf("tf-monitoring-updated-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMMonitoringDestroy, Steps: []resource.TestStep{ { @@ -54,12 +58,12 @@ func testAccCheckIBMMonitoringExists(n string) resource.TestCheckFunc { if !ok { return fmt.Errorf("Not found: %s", n) } - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } monitoringID := rs.Primary.ID - parts, err := idParts(monitoringID) + parts, err := flex.IdParts(monitoringID) if err != nil { return err } @@ -83,7 +87,7 @@ func testAccCheckIBMMonitoringExists(n string) resource.TestCheckFunc { } func testAccCheckIBMMonitoringDestroy(s *terraform.State) error { - csClient, err := testAccProvider.Meta().(ClientSession).VpcContainerAPI() + csClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() if err != nil { return err } @@ -94,7 +98,7 @@ func testAccCheckIBMMonitoringDestroy(s *terraform.State) error { } monitoringID := rs.Primary.ID - parts, err := idParts(monitoringID) + parts, err := flex.IdParts(monitoringID) if err != nil { return err } @@ -119,12 +123,12 @@ func testAccCheckIBMMonitoringDestroy(s *terraform.State) error { func getMonitoringTarget() (v2.MonitoringTargetHeader, error) { - userDetails, err := testAccProvider.Meta().(ClientSession).BluemixUserDetails() + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() if err != nil { return v2.MonitoringTargetHeader{}, err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount targetEnv := v2.MonitoringTargetHeader{ AccountID: accountID, @@ -170,7 +174,7 @@ func testAccCheckIBMMonitoringBasic(clusterName, monitorName, ingestionKeyName s depends_on = [ibm_resource_key.resourceKey] cluster = ibm_container_cluster.testacc_cluster.id instance_id = ibm_resource_instance.instance.guid - }`, clusterName, datacenter, machineType, monitorName, ingestionKeyName) + }`, clusterName, acc.Datacenter, acc.MachineType, monitorName, ingestionKeyName) } func testAccCheckIBMMonitoringUpdate(clusterName, monitorName, ingestionKeyName, instanceName, keyName string) string { @@ -224,5 +228,5 @@ func testAccCheckIBMMonitoringUpdate(clusterName, monitorName, ingestionKeyName, cluster = ibm_container_cluster.testacc_cluster.id instance_id = ibm_resource_instance.instance2.guid private_endpoint = true - }`, clusterName, datacenter, machineType, monitorName, ingestionKeyName, instanceName, keyName) + }`, clusterName, acc.Datacenter, acc.MachineType, monitorName, ingestionKeyName, instanceName, keyName) } diff --git a/ibm/service/power/README.md b/ibm/service/power/README.md new file mode 100644 index 000000000..3c0a7a8f8 --- /dev/null +++ b/ibm/service/power/README.md @@ -0,0 +1,16 @@ +![GitHub issues by-label](https://img.shields.io/github/issues/IBM-Cloud/terraform-provider-ibm/service/Power%20Systems?color=red&label=Power%20Issues) +![GitHub closed issues by-label](https://img.shields.io/github/issues-closed/IBM-Cloud/terraform-provider-ibm/service/Power%20Systems?color=brightgreen&label=Power%20Issues)
+![GitHub pull requests by-label](https://img.shields.io/github/issues/IBM-Cloud/terraform-provider-ibm/service/Power%20Systems?label=Power%20Pull%20Requests) +![GitHub closed pull requests by-label](https://img.shields.io/github/issues-pr-closed/IBM-Cloud/terraform-provider-ibm/service/Power%20Systems?color=brightgreen&label=Power%20Pull%20Requests) + +# Terraform IBM Provider Power Systems + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Power Systems resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_cloud_connection) +* IBM API Docs: [IBM API Docs for Power Systems](https://cloud.ibm.com/apidocs/power-cloud) +* IBM Power Systems SDK: [IBM SDK for Power Systems](https://github.com/IBM-Cloud/power-go-client) diff --git a/ibm/data_source_ibm_pi_catalog_images.go b/ibm/service/power/data_source_ibm_pi_catalog_images.go similarity index 80% rename from ibm/data_source_ibm_pi_catalog_images.go rename to ibm/service/power/data_source_ibm_pi_catalog_images.go index 1855d9d92..eb505ac07 100644 --- a/ibm/data_source_ibm_pi_catalog_images.go +++ b/ibm/service/power/data_source_ibm_pi_catalog_images.go @@ -1,26 +1,28 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" "time" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) /* Datasource to get the list of images that are available when a power instance is created - */ -func dataSourceIBMPICatalogImages() *schema.Resource { +func DataSourceIBMPICatalogImages() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPICatalogImagesRead, + ReadContext: dataSourceIBMPICatalogImagesRead, Schema: map[string]*schema.Schema{ helpers.PICloudInstanceId: { @@ -32,6 +34,10 @@ func dataSourceIBMPICatalogImages() *schema.Resource { Type: schema.TypeBool, Optional: true, }, + "vtl": { + Type: schema.TypeBool, + Optional: true, + }, "images": { Type: schema.TypeList, Computed: true, @@ -108,27 +114,29 @@ func dataSourceIBMPICatalogImages() *schema.Resource { } } -func dataSourceIBMPICatalogImagesRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - +func dataSourceIBMPICatalogImagesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err - } - sap := false - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - if v, ok := d.GetOk("sap"); ok { - sap = v.(bool) + return diag.FromErr(err) } - imageC := instance.NewIBMPIImageClient(sess, powerinstanceid) - result, err := imageC.GetSAPImages(powerinstanceid, sap) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + includeSAP := false + if s, ok := d.GetOk("sap"); ok { + includeSAP = s.(bool) + } + includeVTL := false + if v, ok := d.GetOk("vtl"); ok { + includeVTL = v.(bool) + } + imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + stockImages, err := imageC.GetAllStockImages(includeSAP, includeVTL) if err != nil { - return err + return diag.FromErr(err) } - imageData := result.Images + images := make([]map[string]interface{}, 0) - for _, i := range imageData { + for _, i := range stockImages.Images { image := make(map[string]interface{}) image["image_id"] = *i.ImageID image["name"] = *i.Name @@ -181,7 +189,6 @@ func dataSourceIBMPICatalogImagesRead(d *schema.ResourceData, meta interface{}) } d.SetId(time.Now().UTC().String()) d.Set("images", images) - d.Set(helpers.PICloudInstanceId, powerinstanceid) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_catalog_images_test.go b/ibm/service/power/data_source_ibm_pi_catalog_images_test.go new file mode 100644 index 000000000..a18020ff3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_catalog_images_test.go @@ -0,0 +1,109 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccCheckIBMPICatalogImagesDataSourceBasicConfig() string { + return fmt.Sprintf(` + data "ibm_pi_catalog_images" "power_catalog_images_basic" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} + +func testAccCheckIBMPICatalogImagesDataSourceSAPConfig() string { + return fmt.Sprintf(` + data "ibm_pi_catalog_images" "power_catalog_images_sap" { + pi_cloud_instance_id = "%s" + sap = "true" + } + `, acc.Pi_cloud_instance_id) +} + +func testAccCheckIBMPICatalogImagesDataSourceVTLConfig() string { + return fmt.Sprintf(` + data "ibm_pi_catalog_images" "power_catalog_images_vtl" { + pi_cloud_instance_id = "%s" + vtl = "true" + } + `, acc.Pi_cloud_instance_id) +} + +func testAccCheckIBMPICatalogImagesDataSourceSAP_And_VTLConfig() string { + return fmt.Sprintf(` + data "ibm_pi_catalog_images" "power_catalog_images_sap_and_vtl" { + pi_cloud_instance_id = "%s" + sap = "true" + vtl = "true" + } + `, acc.Pi_cloud_instance_id) +} + +func TestAccIBMPICatalogImagesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICatalogImagesDataSourceBasicConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_catalog_images.power_catalog_images_basic", "id"), + ), + }, + }, + }) +} + +func TestAccIBMPICatalogImagesDataSourceSAP(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICatalogImagesDataSourceSAPConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_catalog_images.power_catalog_images_sap", "id"), + ), + }, + }, + }) +} + +func TestAccIBMPICatalogImagesDataSourceVTL(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICatalogImagesDataSourceVTLConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_catalog_images.power_catalog_images_vtl", "id"), + ), + }, + }, + }) +} + +func TestAccIBMPICatalogImagesDataSourceSAPAndVTL(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICatalogImagesDataSourceSAP_And_VTLConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_catalog_images.power_catalog_images_sap_and_vtl", "id"), + ), + }, + }, + }) +} diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connection.go b/ibm/service/power/data_source_ibm_pi_cloud_connection.go new file mode 100644 index 000000000..8e5bc59f8 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_cloud_connection.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + PICloudConnectionId = "cloud_connection_id" + PICloudConnectionName = "name" + PICloudConnectionSpeed = "speed" + PICloudConnectionGlobalRouting = "global_routing" + PICloudConnectionMetered = "metered" + PICloudConnectionStatus = "status" + PICloudConnectionClassicEnabled = "classic_enabled" + PICloudConnectionUserIPAddress = "user_ip_address" + PICloudConnectionIBMIPAddress = "ibm_ip_address" + PICloudConnectionPort = "port" + PICloudConnectionNetworks = "networks" + PICloudConnectionClassicGreDest = "gre_destination_address" + PICloudConnectionClassicGreSource = "gre_source_address" + PICloudConnectionVPCEnabled = "vpc_enabled" + PICloudConnectionVPCCRNs = "vpc_crns" + PICloudConnectionConnectionMode = "connection_mode" +) + +func DataSourceIBMPICloudConnection() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPICloudConnectionRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + helpers.PICloudConnectionName: { + Type: schema.TypeString, + Required: true, + Description: "Cloud Connection Name to be used", + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + PICloudConnectionSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + PICloudConnectionGlobalRouting: { + Type: schema.TypeBool, + Computed: true, + }, + PICloudConnectionMetered: { + Type: schema.TypeBool, + Computed: true, + }, + PICloudConnectionStatus: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionIBMIPAddress: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionUserIPAddress: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionPort: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionNetworks: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of Networks attached to this cloud connection", + }, + PICloudConnectionClassicEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Enable classic endpoint destination", + }, + PICloudConnectionClassicGreDest: { + Type: schema.TypeString, + Computed: true, + Description: "GRE destination IP address", + }, + PICloudConnectionClassicGreSource: { + Type: schema.TypeString, + Computed: true, + Description: "GRE auto-assigned source IP address", + }, + PICloudConnectionVPCEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Enable VPC for this cloud connection", + }, + PICloudConnectionVPCCRNs: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of VPCs attached to this cloud connection", + }, + PICloudConnectionConnectionMode: { + Type: schema.TypeString, + Computed: true, + Description: "Type of service the gateway is attached to", + }, + }, + } +} + +func dataSourceIBMPICloudConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudConnectionName := d.Get(helpers.PICloudConnectionName).(string) + client := instance.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + + // Get API does not work with name for Cloud Connection hence using GetAll (max 2) + // TODO: Uncomment Get call below when avaiable and remove GetAll + // cloudConnectionD, err := client.GetWithContext(ctx, cloudConnectionName, cloudInstanceID) + // if err != nil { + // log.Printf("[DEBUG] get cloud connection failed %v", err) + // return diag.Errorf(errors.GetCloudConnectionOperationFailed, cloudConnectionName, err) + // } + cloudConnections, err := client.GetAll() + if err != nil { + log.Printf("[DEBUG] get cloud connections failed %v", err) + return diag.FromErr(err) + } + var cloudConnection *models.CloudConnection + if cloudConnections != nil { + for _, cc := range cloudConnections.CloudConnections { + if cloudConnectionName == *cc.Name { + cloudConnection = cc + break + } + } + } + if cloudConnection == nil { + log.Printf("[DEBUG] cloud connection not found") + return diag.Errorf("failed to perform get cloud connection operation for name %s", cloudConnectionName) + } + + cloudConnection, err = client.Get(*cloudConnection.CloudConnectionID) + if err != nil { + log.Printf("[DEBUG] get cloud connection failed %v", err) + return diag.FromErr(err) + } + + d.SetId(*cloudConnection.CloudConnectionID) + d.Set(helpers.PICloudConnectionName, cloudConnection.Name) + d.Set(PICloudConnectionGlobalRouting, cloudConnection.GlobalRouting) + d.Set(PICloudConnectionMetered, cloudConnection.Metered) + d.Set(PICloudConnectionIBMIPAddress, cloudConnection.IbmIPAddress) + d.Set(PICloudConnectionUserIPAddress, cloudConnection.UserIPAddress) + d.Set(PICloudConnectionStatus, cloudConnection.LinkStatus) + d.Set(PICloudConnectionPort, cloudConnection.Port) + d.Set(PICloudConnectionSpeed, cloudConnection.Speed) + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + d.Set(PICloudConnectionConnectionMode, cloudConnection.ConnectionMode) + if cloudConnection.Networks != nil { + networks := make([]string, len(cloudConnection.Networks)) + for i, ccNetwork := range cloudConnection.Networks { + if ccNetwork != nil { + networks[i] = *ccNetwork.NetworkID + } + } + d.Set(PICloudConnectionNetworks, networks) + } + if cloudConnection.Classic != nil { + d.Set(PICloudConnectionClassicEnabled, cloudConnection.Classic.Enabled) + if cloudConnection.Classic.Gre != nil { + d.Set(PICloudConnectionClassicGreDest, cloudConnection.Classic.Gre.DestIPAddress) + d.Set(PICloudConnectionClassicGreSource, cloudConnection.Classic.Gre.SourceIPAddress) + } + } + if cloudConnection.Vpc != nil { + d.Set(PICloudConnectionVPCEnabled, cloudConnection.Vpc.Enabled) + if cloudConnection.Vpc.Vpcs != nil && len(cloudConnection.Vpc.Vpcs) > 0 { + vpcCRNs := make([]string, len(cloudConnection.Vpc.Vpcs)) + for i, vpc := range cloudConnection.Vpc.Vpcs { + vpcCRNs[i] = *vpc.VpcID + } + d.Set(PICloudConnectionVPCCRNs, vpcCRNs) + } + } + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go b/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go new file mode 100644 index 000000000..732b10ad1 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPICloudConnectionDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_cloud_connection.example", "id"), + resource.TestCheckResourceAttrSet("data.ibm_pi_cloud_connection.example", "connection_mode"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_cloud_connection" "example" { + pi_cloud_connection_name = "%s" + pi_cloud_instance_id = "%s" + } + `, acc.PiCloudConnectionName, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connections.go b/ibm/service/power/data_source_ibm_pi_cloud_connections.go new file mode 100644 index 000000000..ad5a35e43 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_cloud_connections.go @@ -0,0 +1,187 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +Datasource to get the list of Cloud Connections in a power instance +*/ + +const PICloudConnections = "connections" + +func DataSourceIBMPICloudConnections() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPICloudConnectionsRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + PICloudConnections: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + PICloudConnectionId: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionName: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + PICloudConnectionGlobalRouting: { + Type: schema.TypeBool, + Computed: true, + }, + PICloudConnectionMetered: { + Type: schema.TypeBool, + Computed: true, + }, + PICloudConnectionStatus: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionIBMIPAddress: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionUserIPAddress: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionPort: { + Type: schema.TypeString, + Computed: true, + }, + PICloudConnectionNetworks: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of Networks attached to this cloud connection", + }, + PICloudConnectionClassicEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Enable classic endpoint destination", + }, + PICloudConnectionClassicGreDest: { + Type: schema.TypeString, + Computed: true, + Description: "GRE destination IP address", + }, + PICloudConnectionClassicGreSource: { + Type: schema.TypeString, + Computed: true, + Description: "GRE auto-assigned source IP address", + }, + PICloudConnectionVPCEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Enable VPC for this cloud connection", + }, + PICloudConnectionVPCCRNs: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of VPCs attached to this cloud connection", + }, + PICloudConnectionConnectionMode: { + Type: schema.TypeString, + Computed: true, + Description: "Type of service the gateway is attached to", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPICloudConnectionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + + cloudConnections, err := client.GetAll() + if err != nil { + log.Printf("[DEBUG] get cloud connections failed %v", err) + return diag.FromErr(err) + } + + result := make([]map[string]interface{}, 0, len(cloudConnections.CloudConnections)) + for _, cloudConnection := range cloudConnections.CloudConnections { + cc := map[string]interface{}{ + PICloudConnectionId: *cloudConnection.CloudConnectionID, + PICloudConnectionName: *cloudConnection.Name, + PICloudConnectionGlobalRouting: *cloudConnection.GlobalRouting, + PICloudConnectionMetered: *cloudConnection.Metered, + PICloudConnectionIBMIPAddress: *cloudConnection.IbmIPAddress, + PICloudConnectionUserIPAddress: *cloudConnection.UserIPAddress, + PICloudConnectionStatus: *cloudConnection.LinkStatus, + PICloudConnectionPort: *cloudConnection.Port, + PICloudConnectionSpeed: *cloudConnection.Speed, + PICloudConnectionConnectionMode: cloudConnection.ConnectionMode, + } + + if cloudConnection.Networks != nil { + networks := make([]string, len(cloudConnection.Networks)) + for i, ccNetwork := range cloudConnection.Networks { + if ccNetwork != nil { + networks[i] = *ccNetwork.NetworkID + } + } + cc[PICloudConnectionNetworks] = networks + } + if cloudConnection.Classic != nil { + cc[PICloudConnectionClassicEnabled] = cloudConnection.Classic.Enabled + if cloudConnection.Classic.Gre != nil { + cc[PICloudConnectionClassicGreDest] = cloudConnection.Classic.Gre.DestIPAddress + cc[PICloudConnectionClassicGreSource] = cloudConnection.Classic.Gre.SourceIPAddress + } + } + if cloudConnection.Vpc != nil { + cc[PICloudConnectionVPCEnabled] = cloudConnection.Vpc.Enabled + if cloudConnection.Vpc.Vpcs != nil && len(cloudConnection.Vpc.Vpcs) > 0 { + vpcCRNs := make([]string, len(cloudConnection.Vpc.Vpcs)) + for i, vpc := range cloudConnection.Vpc.Vpcs { + vpcCRNs[i] = *vpc.VpcID + } + cc[PICloudConnectionVPCCRNs] = vpcCRNs + } + } + + result = append(result, cc) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(PICloudConnections, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connections_test.go b/ibm/service/power/data_source_ibm_pi_cloud_connections_test.go new file mode 100644 index 000000000..9f53a57bc --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_cloud_connections_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPICloudConnectionsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_cloud_connections.connections", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionsDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_cloud_connections" "connections" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/data_source_ibm_pi_cloud_instance.go b/ibm/service/power/data_source_ibm_pi_cloud_instance.go similarity index 83% rename from ibm/data_source_ibm_pi_cloud_instance.go rename to ibm/service/power/data_source_ibm_pi_cloud_instance.go index 8dc29ecd3..f9fa86dcd 100644 --- a/ibm/data_source_ibm_pi_cloud_instance.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_instance.go @@ -1,21 +1,25 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) -func dataSourceIBMPICloudInstance() *schema.Resource { +func DataSourceIBMPICloudInstance() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPICloudInstanceRead, + ReadContext: dataSourceIBMPICloudInstanceRead, Schema: map[string]*schema.Schema{ helpers.PICloudInstanceId: { Type: schema.TypeString, @@ -24,15 +28,10 @@ func dataSourceIBMPICloudInstance() *schema.Resource { }, // Start of Computed Attributes - "enabled": { Type: schema.TypeBool, Computed: true, }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, "tenant_id": { Type: schema.TypeString, Computed: true, @@ -41,7 +40,6 @@ func dataSourceIBMPICloudInstance() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "capabilities": { Type: schema.TypeList, Computed: true, @@ -103,20 +101,18 @@ func dataSourceIBMPICloudInstance() *schema.Resource { } } -func dataSourceIBMPICloudInstanceRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() - +func dataSourceIBMPICloudInstanceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err + return diag.FromErr(err) } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - cloud_instance := instance.NewIBMPICloudInstanceClient(sess, powerinstanceid) - cloud_instance_data, err := cloud_instance.Get(powerinstanceid) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloud_instance := instance.NewIBMPICloudInstanceClient(ctx, sess, cloudInstanceID) + cloud_instance_data, err := cloud_instance.Get(cloudInstanceID) if err != nil { - return err + return diag.FromErr(err) } d.SetId(*cloud_instance_data.CloudInstanceID) diff --git a/ibm/data_source_ibm_pi_cloud_instance_test.go b/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go similarity index 79% rename from ibm/data_source_ibm_pi_cloud_instance_test.go rename to ibm/service/power/data_source_ibm_pi_cloud_instance_test.go index 1d08b9311..1d80d5933 100644 --- a/ibm/data_source_ibm_pi_cloud_instance_test.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPICloudInstanceDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPICloudInstanceDataSourceConfig(), @@ -31,6 +33,6 @@ func testAccCheckIBMPICloudInstanceDataSourceConfig() string { data "ibm_pi_cloud_instance" "testacc_ds_cloud_instance" { pi_cloud_instance_id = "%s" -}`, pi_cloud_instance_id) +}`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_dhcp.go b/ibm/service/power/data_source_ibm_pi_dhcp.go new file mode 100644 index 000000000..18e4c8048 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_dhcp.go @@ -0,0 +1,133 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPIDhcp() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIDhcpRead, + Schema: map[string]*schema.Schema{ + + // Required Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + Arg_DhcpID: { + Type: schema.TypeString, + Required: true, + Description: "The ID of the DHCP Server", + }, + + // Attributes + Attr_DhcpID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server", + }, + Attr_DhcpLeases: { + Type: schema.TypeList, + Computed: true, + Description: "The list of DHCP Server PVM Instance leases", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_DhcpLeaseInstanceIP: { + Type: schema.TypeString, + Computed: true, + Description: "The IP of the PVM Instance", + }, + Attr_DhcpLeaseInstanceMac: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC Address of the PVM Instance", + }, + }, + }, + }, + Attr_DhcpNetworkDeprecated: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + }, + Attr_DhcpNetworkID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network", + }, + Attr_DhcpNetworkName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the DHCP Server private network", + }, + Attr_DhcpStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the DHCP Server", + }, + }, + } +} + +func dataSourceIBMPIDhcpRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + dhcpID := d.Get(Arg_DhcpID).(string) + + // client + client := st.NewIBMPIDhcpClient(ctx, sess, cloudInstanceID) + + // get dhcp + dhcpServer, err := client.Get(dhcpID) + if err != nil { + log.Printf("[DEBUG] get DHCP failed %v", err) + return diag.FromErr(err) + } + + // set attributes + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *dhcpServer.ID)) + d.Set(Attr_DhcpID, *dhcpServer.ID) + d.Set(Attr_DhcpStatus, *dhcpServer.Status) + + if dhcpServer.Network != nil { + dhcpNetwork := dhcpServer.Network + d.Set(Attr_DhcpNetworkDeprecated, *dhcpNetwork.ID) + d.Set(Attr_DhcpNetworkID, *dhcpNetwork.ID) + d.Set(Attr_DhcpNetworkName, *dhcpNetwork.Name) + } + + if dhcpServer.Leases != nil { + leaseList := make([]map[string]string, len(dhcpServer.Leases)) + for i, lease := range dhcpServer.Leases { + leaseList[i] = map[string]string{ + Attr_DhcpLeaseInstanceIP: *lease.InstanceIP, + Attr_DhcpLeaseInstanceMac: *lease.InstanceMacAddress, + } + } + d.Set(Attr_DhcpLeases, leaseList) + } + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_dhcp_test.go b/ibm/service/power/data_source_ibm_pi_dhcp_test.go new file mode 100644 index 000000000..8db9170a3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_dhcp_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIDhcpDataSourceBasic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDhcpDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_dhcp.dhcp", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIDhcpDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_dhcp" "dhcp" { + pi_cloud_instance_id = "%s" + pi_dhcp_id = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_dhcp_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_dhcps.go b/ibm/service/power/data_source_ibm_pi_dhcps.go new file mode 100644 index 000000000..501cb4929 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_dhcps.go @@ -0,0 +1,116 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +Datasource to get the list of dhcp servers in a power instance +*/ + +func DataSourceIBMPIDhcps() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIDhcpServersRead, + Schema: map[string]*schema.Schema{ + + // Required Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_DhcpServers: { + Type: schema.TypeList, + Computed: true, + Description: "The list of all the DHCP Servers", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_DhcpID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server", + }, + Attr_DhcpNetworkDeprecated: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + }, + Attr_DhcpNetworkID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network", + }, + Attr_DhcpNetworkName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the DHCP Server private network", + }, + Attr_DhcpStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the DHCP Server", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIDhcpServersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session and client + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + + // client + client := st.NewIBMPIDhcpClient(ctx, sess, cloudInstanceID) + + // get all dhcp + dhcpServers, err := client.GetAll() + if err != nil { + log.Printf("[DEBUG] get all DHCP failed %v", err) + return diag.FromErr(err) + } + + // set attributes + servers := make([]map[string]interface{}, 0, len(dhcpServers)) + for _, dhcpServer := range dhcpServers { + server := map[string]interface{}{ + Attr_DhcpID: *dhcpServer.ID, + Attr_DhcpStatus: *dhcpServer.Status, + } + if dhcpServer.Network != nil { + dhcpNetwork := dhcpServer.Network + server[Attr_DhcpNetworkDeprecated] = *dhcpNetwork.ID + server[Attr_DhcpNetworkID] = *dhcpNetwork.ID + server[Attr_DhcpNetworkName] = *dhcpNetwork.Name + } + servers = append(servers, server) + } + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(Attr_DhcpServers, servers) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_dhcps_test.go b/ibm/service/power/data_source_ibm_pi_dhcps_test.go new file mode 100644 index 000000000..84645bae3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_dhcps_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIDhcpServersDataSourceBasic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDhcpsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_dhcps.servers", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIDhcpsDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_dhcps" "servers" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_image.go b/ibm/service/power/data_source_ibm_pi_image.go new file mode 100644 index 000000000..c88a51a55 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_image.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + //"fmt" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPIImage() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIImagesRead, + Schema: map[string]*schema.Schema{ + + helpers.PIImageName: { + Type: schema.TypeString, + Required: true, + Description: "Imagename Name to be used for pvminstances", + ValidateFunc: validation.NoZeroValues, + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + "state": { + Type: schema.TypeString, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + "architecture": { + Type: schema.TypeString, + Computed: true, + }, + "operatingsystem": { + Type: schema.TypeString, + Computed: true, + }, + "hypervisor": { + Type: schema.TypeString, + Computed: true, + }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool": { + Type: schema.TypeString, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIImagesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imagedata, err := imageC.Get(d.Get(helpers.PIImageName).(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(*imagedata.ImageID) + d.Set("state", imagedata.State) + d.Set("size", imagedata.Size) + d.Set("architecture", imagedata.Specifications.Architecture) + d.Set("hypervisor", imagedata.Specifications.HypervisorType) + d.Set("operatingsystem", imagedata.Specifications.OperatingSystem) + d.Set("storage_type", imagedata.StorageType) + d.Set("storage_pool", imagedata.StoragePool) + d.Set("image_type", imagedata.Specifications.ImageType) + + return nil + +} diff --git a/ibm/data_source_ibm_pi_image_test.go b/ibm/service/power/data_source_ibm_pi_image_test.go similarity index 77% rename from ibm/data_source_ibm_pi_image_test.go rename to ibm/service/power/data_source_ibm_pi_image_test.go index 970acc319..539aa9950 100644 --- a/ibm/data_source_ibm_pi_image_test.go +++ b/ibm/service/power/data_source_ibm_pi_image_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIImageDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIImageDataSourceConfig(), @@ -31,6 +33,6 @@ func testAccCheckIBMPIImageDataSourceConfig() string { data "ibm_pi_image" "testacc_ds_image" { pi_image_name = "%s" pi_cloud_instance_id = "%s" - }`, pi_image, pi_cloud_instance_id) + }`, acc.Pi_image, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_images.go b/ibm/service/power/data_source_ibm_pi_images.go new file mode 100644 index 000000000..9b6782aa9 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_images.go @@ -0,0 +1,118 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + //"fmt" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +Datasource to get the list of images that are available when a power instance is created +*/ +func DataSourceIBMPIImages() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIImagesAllRead, + Schema: map[string]*schema.Schema{ + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + + "image_info": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "href": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool": { + Type: schema.TypeString, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIImagesAllRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imagedata, err := imageC.GetAll() + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + d.Set("image_info", flattenStockImages(imagedata.Images)) + + return nil + +} + +func flattenStockImages(list []*models.ImageReference) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + + l := map[string]interface{}{ + "id": *i.ImageID, + "state": *i.State, + "href": *i.Href, + "name": *i.Name, + "storage_type": *i.StorageType, + "storage_pool": *i.StoragePool, + "image_type": i.Specifications.ImageType, + } + + result = append(result, l) + + } + return result +} diff --git a/ibm/data_source_ibm_pi_images_test.go b/ibm/service/power/data_source_ibm_pi_images_test.go similarity index 77% rename from ibm/data_source_ibm_pi_images_test.go rename to ibm/service/power/data_source_ibm_pi_images_test.go index 23d232879..083de5409 100644 --- a/ibm/data_source_ibm_pi_images_test.go +++ b/ibm/service/power/data_source_ibm_pi_images_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIImagesDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIImagesDataSourceConfig(), @@ -30,6 +32,6 @@ func testAccCheckIBMPIImagesDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_images" "testacc_ds_image" { pi_cloud_instance_id = "%s" - }`, pi_cloud_instance_id) + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go new file mode 100644 index 000000000..f6dd4d2d9 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance.go @@ -0,0 +1,270 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIInstance() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstancesRead, + Schema: map[string]*schema.Schema{ + + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "Server Name to be used for pvminstances", + ValidateFunc: validation.NoZeroValues, + }, + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "volumes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "memory": { + Type: schema.TypeFloat, + Computed: true, + }, + "processors": { + Type: schema.TypeFloat, + Computed: true, + }, + "health_status": { + Type: schema.TypeString, + Computed: true, + }, + "addresses": { + Type: schema.TypeList, + Computed: true, + Deprecated: "This field is deprecated, use networks instead", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": { + Type: schema.TypeString, + Computed: true, + }, + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Computed: true, + }, + "network_name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "external_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "networks": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": { + Type: schema.TypeString, + Computed: true, + }, + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Computed: true, + }, + "network_name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "external_ip": { + Type: schema.TypeString, + Computed: true, + }, + /*"version": { + Type: schema.TypeFloat, + Computed: true, + },*/ + }, + }, + }, + "proctype": { + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "minproc": { + Type: schema.TypeFloat, + Computed: true, + }, + "minmem": { + Type: schema.TypeFloat, + Computed: true, + }, + "maxproc": { + Type: schema.TypeFloat, + Computed: true, + }, + "maxmem": { + Type: schema.TypeFloat, + Computed: true, + }, + "pin_policy": { + Type: schema.TypeString, + Computed: true, + }, + "virtual_cores_assigned": { + Type: schema.TypeInt, + Computed: true, + }, + "max_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + }, + "min_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool_affinity": { + Type: schema.TypeBool, + Computed: true, + }, + "license_repository_capacity": { + Type: schema.TypeInt, + Computed: true, + }, + PIPlacementGroupID: { + Type: schema.TypeString, + Computed: true, + }, + "deployment_type": { + Type: schema.TypeString, + Computed: true, + }, + Attr_PIInstanceSharedProcessorPool: { + Type: schema.TypeString, + Computed: true, + }, + Attr_PIInstanceSharedProcessorPoolID: { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + powerC := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + powervmdata, err := powerC.Get(d.Get(helpers.PIInstanceName).(string)) + + if err != nil { + return diag.FromErr(err) + } + + pvminstanceid := *powervmdata.PvmInstanceID + d.SetId(pvminstanceid) + d.Set("memory", powervmdata.Memory) + d.Set("processors", powervmdata.Processors) + d.Set("status", powervmdata.Status) + d.Set("proctype", powervmdata.ProcType) + d.Set("volumes", powervmdata.VolumeIDs) + d.Set("minproc", powervmdata.Minproc) + d.Set("minmem", powervmdata.Minmem) + d.Set("maxproc", powervmdata.Maxproc) + d.Set("maxmem", powervmdata.Maxmem) + d.Set("pin_policy", powervmdata.PinPolicy) + d.Set("virtual_cores_assigned", powervmdata.VirtualCores.Assigned) + d.Set("max_virtual_cores", powervmdata.VirtualCores.Max) + d.Set("min_virtual_cores", powervmdata.VirtualCores.Min) + d.Set("storage_type", powervmdata.StorageType) + d.Set("storage_pool", powervmdata.StoragePool) + d.Set("storage_pool_affinity", powervmdata.StoragePoolAffinity) + d.Set("license_repository_capacity", powervmdata.LicenseRepositoryCapacity) + d.Set("networks", flattenPvmInstanceNetworks(powervmdata.Networks)) + d.Set("deployment_type", powervmdata.DeploymentType) + if *powervmdata.PlacementGroup != "none" { + d.Set(PIPlacementGroupID, powervmdata.PlacementGroup) + } + d.Set(Attr_PIInstanceSharedProcessorPool, powervmdata.SharedProcessorPool) + d.Set(Attr_PIInstanceSharedProcessorPoolID, powervmdata.SharedProcessorPoolID) + + if powervmdata.Addresses != nil { + pvmaddress := make([]map[string]interface{}, len(powervmdata.Addresses)) + for i, pvmip := range powervmdata.Addresses { + + p := make(map[string]interface{}) + p["ip"] = pvmip.IPAddress + p["network_name"] = pvmip.NetworkName + p["network_id"] = pvmip.NetworkID + p["macaddress"] = pvmip.MacAddress + p["type"] = pvmip.Type + p["external_ip"] = pvmip.ExternalIP + pvmaddress[i] = p + } + d.Set("addresses", pvmaddress) + + } + + if powervmdata.Health != nil { + + d.Set("health_status", powervmdata.Health.Status) + + } + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_console_languages.go b/ibm/service/power/data_source_ibm_pi_instance_console_languages.go new file mode 100644 index 000000000..e5cb5b344 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_console_languages.go @@ -0,0 +1,98 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + ConsoleLanguages = "console_languages" + ConsoleLanguageCode = "code" + ConsoleLanguageDesc = "language" +) + +/* +Datasource to get the list of available console languages for an instance +*/ +func DataSourceIBMPIInstanceConsoleLanguages() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstanceConsoleLanguagesRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier or name of the instance", + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + ConsoleLanguages: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + ConsoleLanguageCode: { + Type: schema.TypeString, + Computed: true, + Description: "language code", + }, + ConsoleLanguageDesc: { + Type: schema.TypeString, + Computed: true, + Description: "language description", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIInstanceConsoleLanguagesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + instanceName := d.Get(helpers.PIInstanceName).(string) + + client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + languages, err := client.GetConsoleLanguages(instanceName) + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + + if len(languages.ConsoleLanguages) > 0 { + result := make([]map[string]interface{}, 0, len(languages.ConsoleLanguages)) + for _, language := range languages.ConsoleLanguages { + l := map[string]interface{}{ + ConsoleLanguageCode: *language.Code, + ConsoleLanguageDesc: language.Language, + } + result = append(result, l) + } + d.Set(ConsoleLanguages, result) + } + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go b/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go new file mode 100644 index 000000000..acadb056e --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstanceConsoleLanguages(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceConsoleLanguagesConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_console_languages.example", "id"), + resource.TestCheckResourceAttrSet("data.ibm_pi_console_languages.example", "console_languages.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceConsoleLanguagesConfig() string { + return fmt.Sprintf(` + data "ibm_pi_console_languages" "example" { + pi_cloud_instance_id = "%s" + pi_instance_name = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_instance_name) +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_ip.go b/ibm/service/power/data_source_ibm_pi_instance_ip.go new file mode 100644 index 000000000..4d57021d3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_ip.go @@ -0,0 +1,106 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + "net" + "strconv" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPIInstanceIP() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstancesIPRead, + Schema: map[string]*schema.Schema{ + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "Server Name to be used for pvminstances", + ValidateFunc: validation.NoZeroValues, + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + helpers.PINetworkName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed attributes + "ip": { + Type: schema.TypeString, + Computed: true, + }, + "ipoctet": { + Type: schema.TypeString, + Computed: true, + }, + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "external_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIInstancesIPRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + networkName := d.Get(helpers.PINetworkName).(string) + powerC := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + powervmdata, err := powerC.Get(d.Get(helpers.PIInstanceName).(string)) + if err != nil { + return diag.FromErr(err) + } + + for _, network := range powervmdata.Networks { + if network.NetworkName == networkName { + log.Printf("Printing the ip %s", network.IPAddress) + d.SetId(network.NetworkID) + d.Set("ip", network.IPAddress) + d.Set("network_id", network.NetworkID) + d.Set("macaddress", network.MacAddress) + d.Set("external_ip", network.ExternalIP) + d.Set("type", network.Type) + + IPObject := net.ParseIP(network.IPAddress).To4() + if len(IPObject) > 0 { + d.Set("ipoctet", strconv.Itoa(int(IPObject[3]))) + } + + return nil + } + } + + return diag.Errorf("failed to find instance ip that belongs to the given network") +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_ip_test.go b/ibm/service/power/data_source_ibm_pi_instance_ip_test.go new file mode 100644 index 000000000..36362776a --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_ip_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstanceIPDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceIPDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_instance_ip.testacc_ds_instance_ip", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceIPDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_instance_ip" "testacc_ds_instance_ip" { + pi_network_name = "%[1]s" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[3]s" + } + `, acc.Pi_network_name, acc.Pi_instance_name, acc.Pi_cloud_instance_id) +} diff --git a/ibm/data_source_ibm_pi_instance_test.go b/ibm/service/power/data_source_ibm_pi_instance_test.go similarity index 77% rename from ibm/data_source_ibm_pi_instance_test.go rename to ibm/service/power/data_source_ibm_pi_instance_test.go index b4ef97e4a..daf359010 100644 --- a/ibm/data_source_ibm_pi_instance_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIInstanceDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIInstanceDataSourceConfig(), @@ -32,6 +34,6 @@ func testAccCheckIBMPIInstanceDataSourceConfig() string { data "ibm_pi_instance" "testacc_ds_instance" { pi_instance_name="%s" pi_cloud_instance_id = "%s" -}`, pi_instance_name, pi_cloud_instance_id) +}`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/data_source_ibm_pi_instance_volumes.go b/ibm/service/power/data_source_ibm_pi_instance_volumes.go similarity index 79% rename from ibm/data_source_ibm_pi_instance_volumes.go rename to ibm/service/power/data_source_ibm_pi_instance_volumes.go index fe16ed36f..611ef5cf6 100644 --- a/ibm/data_source_ibm_pi_instance_volumes.go +++ b/ibm/service/power/data_source_ibm_pi_instance_volumes.go @@ -1,31 +1,33 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" + "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func dataSourceIBMPIInstanceVolumes() *schema.Resource { +func DataSourceIBMPIInstanceVolumes() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPIInstanceVolumesRead, + ReadContext: dataSourceIBMPIInstanceVolumesRead, Schema: map[string]*schema.Schema{ - helpers.PIInstanceName: { Type: schema.TypeString, Required: true, Description: "Instance Name to be used for pvminstances", ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { Type: schema.TypeString, Required: true, @@ -33,12 +35,10 @@ func dataSourceIBMPIInstanceVolumes() *schema.Resource { }, //Computed Attributes - "boot_volume_id": { Type: schema.TypeString, Computed: true, }, - "instance_volumes": { Type: schema.TypeList, Computed: true, @@ -87,19 +87,18 @@ func dataSourceIBMPIInstanceVolumes() *schema.Resource { } } -func dataSourceIBMPIInstanceVolumesRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() +func dataSourceIBMPIInstanceVolumesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err + return diag.FromErr(err) } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - volumeC := instance.NewIBMPIVolumeClient(sess, powerinstanceid) - volumedata, err := volumeC.GetAll(d.Get(helpers.PIInstanceName).(string), powerinstanceid, getTimeOut) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + volumeC := instance.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + volumedata, err := volumeC.GetAllInstanceVolumes(d.Get(helpers.PIInstanceName).(string)) if err != nil { - return err + return diag.FromErr(err) } var clientgenU, _ = uuid.GenerateUUID() diff --git a/ibm/data_source_ibm_pi_instance_volumes_test.go b/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go similarity index 80% rename from ibm/data_source_ibm_pi_instance_volumes_test.go rename to ibm/service/power/data_source_ibm_pi_instance_volumes_test.go index 4f7714c8e..211c17b9e 100644 --- a/ibm/data_source_ibm_pi_instance_volumes_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ import ( func TestAccIBMPIVolumesDataSource_basic(t *testing.T) { name := fmt.Sprintf("tf-pi-volume-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIVolumesDataSourceConfig(name), @@ -32,6 +34,6 @@ func testAccCheckIBMPIVolumesDataSourceConfig(name string) string { data "ibm_pi_instance_volumes" "testacc_ds_volumes" { pi_instance_name = "%s" pi_cloud_instance_id = "%s" -}`, pi_instance_name, pi_cloud_instance_id) +}`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_instances.go b/ibm/service/power/data_source_ibm_pi_instances.go new file mode 100644 index 000000000..a266d9c11 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instances.go @@ -0,0 +1,231 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIInstances() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstancesAllRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "pvm_instances": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "pvm_instance_id": { + Type: schema.TypeString, + Computed: true, + }, + "memory": { + Type: schema.TypeFloat, + Computed: true, + }, + "processors": { + Type: schema.TypeFloat, + Computed: true, + }, + "health_status": { + Type: schema.TypeString, + Computed: true, + }, + "networks": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": { + Type: schema.TypeString, + Computed: true, + }, + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Computed: true, + }, + "network_name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "external_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "proctype": { + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "minproc": { + Type: schema.TypeFloat, + Computed: true, + }, + "minmem": { + Type: schema.TypeFloat, + Computed: true, + }, + "maxproc": { + Type: schema.TypeFloat, + Computed: true, + }, + "maxmem": { + Type: schema.TypeFloat, + Computed: true, + }, + "pin_policy": { + Type: schema.TypeString, + Computed: true, + }, + "virtual_cores_assigned": { + Type: schema.TypeInt, + Computed: true, + }, + "max_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + }, + "min_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool": { + Type: schema.TypeString, + Computed: true, + }, + "storage_pool_affinity": { + Type: schema.TypeBool, + Computed: true, + }, + "license_repository_capacity": { + Type: schema.TypeInt, + Computed: true, + }, + PIPlacementGroupID: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIInstancesAllRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + powerC := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + powervmdata, err := powerC.GetAll() + + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + d.Set("pvm_instances", flattenPvmInstances(powervmdata.PvmInstances)) + + return nil +} + +func flattenPvmInstances(list []*models.PVMInstanceReference) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + + l := map[string]interface{}{ + "pvm_instance_id": *i.PvmInstanceID, + "memory": *i.Memory, + "processors": *i.Processors, + "proctype": *i.ProcType, + "status": *i.Status, + "minproc": i.Minproc, + "minmem": i.Minmem, + "maxproc": i.Maxproc, + "maxmem": i.Maxmem, + "pin_policy": i.PinPolicy, + "virtual_cores_assigned": i.VirtualCores.Assigned, + "max_virtual_cores": i.VirtualCores.Max, + "min_virtual_cores": i.VirtualCores.Min, + "storage_type": i.StorageType, + "storage_pool": i.StoragePool, + "storage_pool_affinity": i.StoragePoolAffinity, + "license_repository_capacity": i.LicenseRepositoryCapacity, + PIPlacementGroupID: i.PlacementGroup, + "networks": flattenPvmInstanceNetworks(i.Networks), + } + + if i.Health != nil { + l["health_status"] = i.Health.Status + } + + result = append(result, l) + + } + return result +} + +func flattenPvmInstanceNetworks(list []*models.PVMInstanceNetwork) (networks []map[string]interface{}) { + if list != nil { + networks = make([]map[string]interface{}, len(list)) + for i, pvmip := range list { + + p := make(map[string]interface{}) + p["ip"] = pvmip.IPAddress + p["network_name"] = pvmip.NetworkName + p["network_id"] = pvmip.NetworkID + p["macaddress"] = pvmip.MacAddress + p["type"] = pvmip.Type + p["external_ip"] = pvmip.ExternalIP + networks[i] = p + } + return networks + } + return +} diff --git a/ibm/service/power/data_source_ibm_pi_instances_test.go b/ibm/service/power/data_source_ibm_pi_instances_test.go new file mode 100644 index 000000000..7dc19f1e1 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instances_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstancesDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstancesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_instances.testacc_ds_instance", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstancesDataSourceConfig() string { + return fmt.Sprintf(` + + data "ibm_pi_instances" "testacc_ds_instance" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/data_source_ibm_pi_key.go b/ibm/service/power/data_source_ibm_pi_key.go new file mode 100644 index 000000000..70ab96ba7 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_key.go @@ -0,0 +1,84 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIKey() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIKeyRead, + Schema: map[string]*schema.Schema{ + + // Arguments + Arg_KeyName: { + Type: schema.TypeString, + Required: true, + Description: "SSH key name for a pcloud tenant", + ValidateFunc: validation.NoZeroValues, + }, + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_KeyCreationDate: { + Type: schema.TypeString, + Computed: true, + Description: "Date of sshkey creation", + }, + Attr_Key: { + Type: schema.TypeString, + Sensitive: true, + Computed: true, + Description: "SSH RSA key", + }, + "sshkey": { + Type: schema.TypeString, + Sensitive: true, + Computed: true, + Deprecated: "This field is deprecated, use ssh_key instead", + }, + }, + } +} + +func dataSourceIBMPIKeyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + // get key + sshkeyC := instance.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) + sshkeydata, err := sshkeyC.Get(d.Get(helpers.PIKeyName).(string)) + if err != nil { + return diag.FromErr(err) + } + + // set attributes + d.SetId(*sshkeydata.Name) + d.Set(Attr_KeyCreationDate, sshkeydata.CreationDate.String()) + d.Set(Attr_Key, sshkeydata.SSHKey) + d.Set("sshkey", sshkeydata.SSHKey) // TODO: deprecated, to remove + + return nil +} diff --git a/ibm/data_source_ibm_pi_key_test.go b/ibm/service/power/data_source_ibm_pi_key_test.go similarity index 76% rename from ibm/data_source_ibm_pi_key_test.go rename to ibm/service/power/data_source_ibm_pi_key_test.go index 22b60a4fa..184b74a0e 100644 --- a/ibm/data_source_ibm_pi_key_test.go +++ b/ibm/service/power/data_source_ibm_pi_key_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIKeyDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIKeyDataSourceConfig(), @@ -31,6 +33,6 @@ func testAccCheckIBMPIKeyDataSourceConfig() string { data "ibm_pi_key" "testacc_ds_key" { pi_key_name = "%s" pi_cloud_instance_id = "%s" -}`, pi_key_name, pi_cloud_instance_id) +}`, acc.Pi_key_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_keys.go b/ibm/service/power/data_source_ibm_pi_keys.go new file mode 100644 index 000000000..0f78a9ab4 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_keys.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIKeys() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIKeysRead, + Schema: map[string]*schema.Schema{ + + // Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_Keys: { + Type: schema.TypeList, + Computed: true, + Description: "SSH Keys", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_KeyName: { + Type: schema.TypeString, + Computed: true, + Description: "User defined name for the SSH key", + }, + Attr_Key: { + Type: schema.TypeString, + Computed: true, + Description: "SSH RSA key", + }, + Attr_KeyCreationDate: { + Type: schema.TypeString, + Computed: true, + Description: "Date of SSH key creation", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIKeysRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + // get keys + client := st.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) + sshKeys, err := client.GetAll() + if err != nil { + log.Printf("[ERROR] get all keys failed %v", err) + return diag.FromErr(err) + } + + // set attributes + result := make([]map[string]interface{}, 0, len(sshKeys.SSHKeys)) + for _, sshKey := range sshKeys.SSHKeys { + key := map[string]interface{}{ + Attr_KeyName: sshKey.Name, + Attr_Key: sshKey.SSHKey, + Attr_KeyCreationDate: sshKey.CreationDate.String(), + } + result = append(result, key) + } + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(Attr_Keys, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_keys_test.go b/ibm/service/power/data_source_ibm_pi_keys_test.go new file mode 100644 index 000000000..f45dfc7fc --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_keys_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIKeysDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIKeysDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_keys.test", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIKeysDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_keys" "test" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_network.go b/ibm/service/power/data_source_ibm_pi_network.go new file mode 100644 index 000000000..a080f5a02 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network.go @@ -0,0 +1,130 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + //"fmt" + + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPINetwork() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPINetworkRead, + Schema: map[string]*schema.Schema{ + helpers.PINetworkName: { + Type: schema.TypeString, + Required: true, + Description: "Network Name to be used for pvminstances", + ValidateFunc: validation.NoZeroValues, + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "cidr": { + Type: schema.TypeString, + Computed: true, + }, + + "type": { + Type: schema.TypeString, + Computed: true, + }, + + "vlan_id": { + Type: schema.TypeInt, + Computed: true, + }, + "gateway": { + Type: schema.TypeString, + Computed: true, + }, + "available_ip_count": { + Type: schema.TypeFloat, + Computed: true, + }, + "used_ip_count": { + Type: schema.TypeFloat, + Computed: true, + }, + "used_ip_percent": { + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Deprecated: "This value is deprecated in favor of" + helpers.PINetworkName, + }, + "dns": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "jumbo": { + Type: schema.TypeBool, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + networkC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.Get(d.Get(helpers.PINetworkName).(string)) + if err != nil || networkdata == nil { + return diag.FromErr(err) + } + + d.SetId(*networkdata.NetworkID) + if networkdata.Cidr != nil { + d.Set("cidr", networkdata.Cidr) + } + if networkdata.Type != nil { + d.Set("type", networkdata.Type) + } + d.Set("gateway", networkdata.Gateway) + if networkdata.VlanID != nil { + d.Set("vlan_id", networkdata.VlanID) + } + if networkdata.IPAddressMetrics.Available != nil { + d.Set("available_ip_count", networkdata.IPAddressMetrics.Available) + } + if networkdata.IPAddressMetrics.Used != nil { + d.Set("used_ip_count", networkdata.IPAddressMetrics.Used) + } + if networkdata.IPAddressMetrics.Utilization != nil { + d.Set("used_ip_percent", networkdata.IPAddressMetrics.Utilization) + } + if networkdata.Name != nil { + d.Set("name", networkdata.Name) + } + if len(networkdata.DNSServers) > 0 { + d.Set("dns", networkdata.DNSServers) + } + d.Set("jumbo", networkdata.Jumbo) + + return nil + +} diff --git a/ibm/data_source_ibm_pi_network_port.go b/ibm/service/power/data_source_ibm_pi_network_port.go similarity index 77% rename from ibm/data_source_ibm_pi_network_port.go rename to ibm/service/power/data_source_ibm_pi_network_port.go index 7fe9c7074..e98a9c3b1 100644 --- a/ibm/data_source_ibm_pi_network_port.go +++ b/ibm/service/power/data_source_ibm_pi_network_port.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" + "log" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "log" //"fmt" "github.com/IBM-Cloud/power-go-client/clients/instance" @@ -15,19 +19,17 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func dataSourceIBMPINetworkPort() *schema.Resource { +func DataSourceIBMPINetworkPort() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPINetworkPortsRead, + ReadContext: dataSourceIBMPINetworkPortsRead, Schema: map[string]*schema.Schema{ - helpers.PINetworkName: { Type: schema.TypeString, Required: true, Description: "Network Name to be used for pvminstances", ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { Type: schema.TypeString, Required: true, @@ -35,7 +37,6 @@ func dataSourceIBMPINetworkPort() *schema.Resource { }, // Computed Attributes - "network_ports": { Type: schema.TypeList, Computed: true, @@ -77,19 +78,17 @@ func dataSourceIBMPINetworkPort() *schema.Resource { } } -func dataSourceIBMPINetworkPortsRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() +func dataSourceIBMPINetworkPortsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err + return diag.FromErr(err) } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - networkportC := instance.NewIBMPINetworkClient(sess, powerinstanceid) - networkportdata, err := networkportC.GetAllPort(d.Get(helpers.PINetworkName).(string), powerinstanceid, getTimeOut) - + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + networkportC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkportdata, err := networkportC.GetAllPorts(d.Get(helpers.PINetworkName).(string)) if err != nil { - return err + return diag.FromErr(err) } var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) diff --git a/ibm/data_source_ibm_pi_network_test.go b/ibm/service/power/data_source_ibm_pi_network_test.go similarity index 77% rename from ibm/data_source_ibm_pi_network_test.go rename to ibm/service/power/data_source_ibm_pi_network_test.go index 123f2f939..873681869 100644 --- a/ibm/data_source_ibm_pi_network_test.go +++ b/ibm/service/power/data_source_ibm_pi_network_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPINetworkDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPINetworkDataSourceConfig(), @@ -30,6 +32,6 @@ func testAccCheckIBMPINetworkDataSourceConfig() string { data "ibm_pi_network" "testacc_ds_network" { pi_network_name = "%s" pi_cloud_instance_id = "%s" -}`, pi_network_name, pi_cloud_instance_id) +}`, acc.Pi_network_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_placement_group.go b/ibm/service/power/data_source_ibm_pi_placement_group.go new file mode 100644 index 000000000..9792aa331 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_placement_group.go @@ -0,0 +1,71 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPIPlacementGroup() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIPlacementGroupRead, + Schema: map[string]*schema.Schema{ + helpers.PIPlacementGroupName: { + Type: schema.TypeString, + Required: true, + }, + + "policy": { + Type: schema.TypeString, + Computed: true, + }, + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + PIPlacementGroupMembers: { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIPlacementGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + placementGroupName := d.Get(helpers.PIPlacementGroupName).(string) + client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(placementGroupName) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.SetId(*response.ID) + d.Set("policy", response.Policy) + d.Set(PIPlacementGroupMembers, response.Members) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_placement_group_test.go b/ibm/service/power/data_source_ibm_pi_placement_group_test.go new file mode 100644 index 000000000..0738266a9 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_placement_group_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIPlacementGroupDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIPlacementGroupDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_placement_group.testacc_ds_placement_group", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIPlacementGroupDataSourceConfig() string { + return fmt.Sprintf(` +data "ibm_pi_placement_group" "testacc_ds_placement_group" { + pi_placement_group_name = "%s" + pi_cloud_instance_id = "%s" +}`, acc.Pi_placement_group_name, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/data_source_ibm_pi_placement_groups.go b/ibm/service/power/data_source_ibm_pi_placement_groups.go new file mode 100644 index 000000000..345f2bf05 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_placement_groups.go @@ -0,0 +1,95 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + PIPlacementGroups = "placement_groups" +) + +func DataSourceIBMPIPlacementGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIPlacementGroupsRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + PIPlacementGroups: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + PIPlacementGroupMembers: { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "policy": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIPlacementGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + groups, err := client.GetAll() + if err != nil { + log.Printf("[ERROR] get all placement groups failed %v", err) + return diag.FromErr(err) + } + + result := make([]map[string]interface{}, 0, len(groups.PlacementGroups)) + for _, placementGroup := range groups.PlacementGroups { + key := map[string]interface{}{ + "id": placementGroup.ID, + "name": placementGroup.Name, + PIPlacementGroupMembers: placementGroup.Members, + "policy": placementGroup.Policy, + } + result = append(result, key) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(PIPlacementGroups, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_placement_groups_test.go b/ibm/service/power/data_source_ibm_pi_placement_groups_test.go new file mode 100644 index 000000000..2f0e8131c --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_placement_groups_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIPlacementGrousDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIPlacementGrousDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_placement_groups.test", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIPlacementGrousDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_placement_groups" "test" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_public_network.go b/ibm/service/power/data_source_ibm_pi_public_network.go new file mode 100644 index 000000000..ca5cc380e --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_public_network.go @@ -0,0 +1,76 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + //"fmt" + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIPublicNetwork() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPIPublicNetworkRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "vlan_id": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIPublicNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + networkC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.GetAllPublic() + if err != nil { + return diag.FromErr(err) + } + if len(networkdata.Networks) < 1 { + return diag.Errorf("error getting public network or no public network found in %s", cloudInstanceID) + } + + d.SetId(*networkdata.Networks[0].NetworkID) + if networkdata.Networks[0].Type != nil { + d.Set("type", networkdata.Networks[0].Type) + } + if networkdata.Networks[0].Name != nil { + d.Set("name", networkdata.Networks[0].Name) + } + if networkdata.Networks[0].VlanID != nil { + d.Set("vlan_id", networkdata.Networks[0].VlanID) + } + + return nil +} diff --git a/ibm/data_source_ibm_pi_public_network_test.go b/ibm/service/power/data_source_ibm_pi_public_network_test.go similarity index 79% rename from ibm/data_source_ibm_pi_public_network_test.go rename to ibm/service/power/data_source_ibm_pi_public_network_test.go index 32fb6604f..f8c3eb1c5 100644 --- a/ibm/data_source_ibm_pi_public_network_test.go +++ b/ibm/service/power/data_source_ibm_pi_public_network_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIPublicNetworkDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIPublicNetworkDataSourceConfig(), @@ -29,6 +31,6 @@ func testAccCheckIBMPIPublicNetworkDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_public_network" "testacc_ds_public_network" { pi_cloud_instance_id = "%s" -}`, pi_cloud_instance_id) +}`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_sap_profile.go b/ibm/service/power/data_source_ibm_pi_sap_profile.go new file mode 100644 index 000000000..43510987d --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_sap_profile.go @@ -0,0 +1,81 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPISAPProfile() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISAPProfileRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + PISAPInstanceProfileID: { + Type: schema.TypeString, + Required: true, + Description: "SAP Profile ID", + }, + // Computed Attributes + PISAPProfileCertified: { + Type: schema.TypeBool, + Computed: true, + Description: "Has certification been performed on profile", + }, + PISAPProfileCores: { + Type: schema.TypeInt, + Computed: true, + Description: "Amount of cores", + }, + PISAPProfileMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Amount of memory (in GB)", + }, + PISAPProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of profile", + }, + }, + } +} + +func dataSourceIBMPISAPProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + profileID := d.Get(PISAPInstanceProfileID).(string) + + client := instance.NewIBMPISAPInstanceClient(ctx, sess, cloudInstanceID) + sapProfile, err := client.GetSAPProfile(profileID) + if err != nil { + log.Printf("[DEBUG] get sap profile failed %v", err) + return diag.FromErr(err) + } + + d.SetId(*sapProfile.ProfileID) + d.Set(PISAPProfileCertified, *sapProfile.Certified) + d.Set(PISAPProfileCores, *sapProfile.Cores) + d.Set(PISAPProfileMemory, *sapProfile.Memory) + d.Set(PISAPProfileType, *sapProfile.Type) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_sap_profile_test.go b/ibm/service/power/data_source_ibm_pi_sap_profile_test.go new file mode 100644 index 000000000..dc4026bdf --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_sap_profile_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISAPProfileDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISAPProfileDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_sap_profile.test", "id"), + resource.TestCheckResourceAttr("data.ibm_pi_sap_profile.test", "id", acc.PiSAPProfileID), + ), + }, + }, + }) +} + +func testAccCheckIBMPISAPProfileDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_sap_profile" "test" { + pi_cloud_instance_id = "%s" + pi_sap_profile_id = "%s" + }`, acc.Pi_cloud_instance_id, acc.PiSAPProfileID) +} diff --git a/ibm/service/power/data_source_ibm_pi_sap_profiles.go b/ibm/service/power/data_source_ibm_pi_sap_profiles.go new file mode 100644 index 000000000..0b314791c --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_sap_profiles.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPISAPProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISAPProfilesRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + PISAPProfiles: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + PISAPProfileCertified: { + Type: schema.TypeBool, + Computed: true, + Description: "Has certification been performed on profile", + }, + PISAPProfileCores: { + Type: schema.TypeInt, + Computed: true, + Description: "Amount of cores", + }, + PISAPProfileMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Amount of memory (in GB)", + }, + PISAPProfileID: { + Type: schema.TypeString, + Computed: true, + Description: "SAP Profile ID", + }, + PISAPProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "Type of profile", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISAPProfilesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := instance.NewIBMPISAPInstanceClient(ctx, sess, cloudInstanceID) + sapProfiles, err := client.GetAllSAPProfiles(cloudInstanceID) + if err != nil { + log.Printf("[DEBUG] get all sap profiles failed %v", err) + return diag.FromErr(err) + } + + result := make([]map[string]interface{}, 0, len(sapProfiles.Profiles)) + for _, sapProfile := range sapProfiles.Profiles { + profile := map[string]interface{}{ + PISAPProfileCertified: *sapProfile.Certified, + PISAPProfileCores: *sapProfile.Cores, + PISAPProfileMemory: *sapProfile.Memory, + PISAPProfileID: *sapProfile.ProfileID, + PISAPProfileType: *sapProfile.Type, + } + result = append(result, profile) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(PISAPProfiles, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_sap_profiles_test.go b/ibm/service/power/data_source_ibm_pi_sap_profiles_test.go new file mode 100644 index 000000000..1fca79fe3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_sap_profiles_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISAPProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISAPProfilesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_sap_profiles.test", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISAPProfilesDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_sap_profiles" "test" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go new file mode 100644 index 000000000..e3fcc1be3 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go @@ -0,0 +1,182 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func DataSourceIBMPISharedProcessorPool() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPISharedProcessorPoolRead, + Schema: map[string]*schema.Schema{ + Arg_SharedProcessorPoolID: { + Type: schema.TypeString, + Required: true, + }, + + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + + Attr_SharedProcessorPoolName: { + Type: schema.TypeString, + Computed: true, + Description: "Name of the shared processor pool", + }, + + Attr_SharedProcessorPoolHostID: { + Type: schema.TypeInt, + Computed: true, + Description: "The host ID where the shared processor pool resides", + }, + + Attr_SharedProcessorPoolReservedCores: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of reserved cores for the shared processor pool", + }, + + Attr_SharedProcessorPoolAvailableCores: { + Type: schema.TypeFloat, + Computed: true, + Description: "Shared processor pool available cores", + }, + + Attr_SharedProcessorPoolAllocatedCores: { + Type: schema.TypeFloat, + Computed: true, + Description: "Shared processor pool allocated cores", + }, + + Attr_SharedProcessorPoolStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the shared processor pool", + }, + + Attr_SharedProcessorPoolStatusDetail: { + Type: schema.TypeString, + Computed: true, + Description: "The status details of the shared processor pool", + }, + + Attr_SharedProcessorPoolInstances: { + Type: schema.TypeList, + Computed: true, + Description: "List of server instances deployed in the shared processor pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SharedProcessorPoolInstanceCpus: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The amount of cpus for the server instance", + }, + Attr_SharedProcessorPoolInstanceUncapped: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Identifies if uncapped or not", + }, + Attr_SharedProcessorPoolInstanceAvailabilityZone: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Availability zone for the server instances", + }, + Attr_SharedProcessorPoolInstanceId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The server instance ID", + }, + Attr_SharedProcessorPoolInstanceMemory: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The amount of memory for the server instance", + }, + Attr_SharedProcessorPoolInstanceName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The server instance name", + }, + Attr_SharedProcessorPoolInstanceStatus: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Status of the server", + }, + Attr_SharedProcessorPoolInstanceVcpus: { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "The amout of vcpus for the server instance", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISharedProcessorPoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + poolID := d.Get(Arg_SharedProcessorPoolID).(string) + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(poolID) + if err != nil || response == nil { + return diag.Errorf("error fetching the shared processor pool: %v", err) + } + + d.SetId(*response.SharedProcessorPool.ID) + d.Set(Attr_SharedProcessorPoolName, response.SharedProcessorPool.Name) + d.Set(Attr_SharedProcessorPoolReservedCores, response.SharedProcessorPool.ReservedCores) + d.Set(Attr_SharedProcessorPoolAllocatedCores, response.SharedProcessorPool.AllocatedCores) + d.Set(Attr_SharedProcessorPoolAvailableCores, response.SharedProcessorPool.AvailableCores) + d.Set(Attr_SharedProcessorPoolHostID, response.SharedProcessorPool.HostID) + d.Set(Attr_SharedProcessorPoolStatus, response.SharedProcessorPool.Status) + d.Set(Attr_SharedProcessorPoolStatusDetail, response.SharedProcessorPool.StatusDetail) + + serversMap := []map[string]interface{}{} + if response.Servers != nil { + for _, s := range response.Servers { + if s != nil { + v := map[string]interface{}{ + Attr_SharedProcessorPoolInstanceCpus: s.Cpus, + Attr_SharedProcessorPoolInstanceUncapped: s.Uncapped, + Attr_SharedProcessorPoolInstanceAvailabilityZone: s.AvailabilityZone, + Attr_SharedProcessorPoolInstanceId: s.ID, + Attr_SharedProcessorPoolInstanceMemory: s.Memory, + Attr_SharedProcessorPoolInstanceName: s.Name, + Attr_SharedProcessorPoolInstanceStatus: s.Status, + Attr_SharedProcessorPoolInstanceVcpus: s.Vcpus, + } + serversMap = append(serversMap, v) + } + } + } + d.Set(Attr_SharedProcessorPoolInstances, serversMap) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go new file mode 100644 index 000000000..a39f50926 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIPISharedProcessorPoolDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIPISharedProcessorPoolDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_shared_processor_pool.test_pool", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIPISharedProcessorPoolDataSourceConfig() string { + return fmt.Sprintf(` +data "ibm_pi_shared_processor_pool" "test_pool" { + pi_shared_processor_pool_id = "%s" + pi_cloud_instance_id = "%s" +}`, acc.Pi_shared_processor_pool_id, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go new file mode 100644 index 000000000..e14611d87 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go @@ -0,0 +1,112 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + PISharedProcessorPools = "shared_processor_pools" +) + +func DataSourceIBMPISharedProcessorPools() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISharedProcessorPoolsRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + PISharedProcessorPools: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SharedProcessorPoolID: { + Type: schema.TypeString, + Computed: true, + }, + Attr_SharedProcessorPoolAllocatedCores: { + Type: schema.TypeFloat, + Computed: true, + }, + Attr_SharedProcessorPoolAvailableCores: { + Type: schema.TypeInt, + Computed: true, + }, + Attr_SharedProcessorPoolName: { + Type: schema.TypeString, + Computed: true, + }, + Attr_SharedProcessorPoolReservedCores: { + Type: schema.TypeInt, + Computed: true, + }, + Attr_SharedProcessorPoolHostID: { + Type: schema.TypeInt, + Computed: true, + }, + Attr_SharedProcessorPoolStatus: { + Type: schema.TypeString, + Computed: true, + }, + Attr_SharedProcessorPoolStatusDetail: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISharedProcessorPoolsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + pools, err := client.GetAll() + if err != nil || pools == nil { + return diag.Errorf("error fetching shared processor pools: %v", err) + } + + result := make([]map[string]interface{}, 0, len(pools.SharedProcessorPools)) + for _, pool := range pools.SharedProcessorPools { + key := map[string]interface{}{ + Attr_SharedProcessorPoolID: *pool.ID, + Attr_SharedProcessorPoolName: *pool.Name, + Attr_SharedProcessorPoolAllocatedCores: *pool.AllocatedCores, + Attr_SharedProcessorPoolAvailableCores: *pool.AvailableCores, + Attr_SharedProcessorPoolReservedCores: *pool.ReservedCores, + Attr_SharedProcessorPoolHostID: pool.HostID, + Attr_SharedProcessorPoolStatus: pool.Status, + Attr_SharedProcessorPoolStatusDetail: pool.StatusDetail, + } + result = append(result, key) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(PISharedProcessorPools, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go new file mode 100644 index 000000000..fcbb9c4db --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISharedProcessorPoolsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISharedProcessorPoolsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_shared_processor_pools.test", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISharedProcessorPoolsDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_shared_processor_pools" "test" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/data_source_ibm_pi_snapshot.go b/ibm/service/power/data_source_ibm_pi_snapshot.go similarity index 80% rename from ibm/data_source_ibm_pi_snapshot.go rename to ibm/service/power/data_source_ibm_pi_snapshot.go index e57ac545a..b852f1024 100644 --- a/ibm/data_source_ibm_pi_snapshot.go +++ b/ibm/service/power/data_source_ibm_pi_snapshot.go @@ -1,22 +1,26 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" + "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" ) -func dataSourceIBMPISnapshot() *schema.Resource { +func DataSourceIBMPISnapshot() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPISnapshotRead, + ReadContext: dataSourceIBMPISnapshotRead, Schema: map[string]*schema.Schema{ helpers.PICloudInstanceId: { @@ -81,20 +85,20 @@ func dataSourceIBMPISnapshot() *schema.Resource { } } -func dataSourceIBMPISnapshotRead(d *schema.ResourceData, meta interface{}) error { +func dataSourceIBMPISnapshotRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).IBMPISession() + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err + return diag.FromErr(err) } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) powerinstancename := d.Get(helpers.PIInstanceName).(string) - snapshot := instance.NewIBMPIInstanceClient(sess, powerinstanceid) - snapshotData, err := snapshot.GetSnapShotVM(powerinstanceid, powerinstancename, getTimeOut) + snapshot := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + snapshotData, err := snapshot.GetSnapShotVM(powerinstancename) if err != nil { - return err + return diag.FromErr(err) } var clientgenU, _ = uuid.GenerateUUID() diff --git a/ibm/service/power/data_source_ibm_pi_snapshot_test.go b/ibm/service/power/data_source_ibm_pi_snapshot_test.go new file mode 100644 index 000000000..3636fbf04 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_snapshot_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISnapshotDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISnapshotDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_pvm_snapshots.testacc_pi_snapshots", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISnapshotDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_pi_pvm_snapshots" "testacc_pi_snapshots" { + pi_instance_name = "%s" + pi_cloud_instance_id = "%s" +}`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/data_source_ibm_pi_snapshots.go b/ibm/service/power/data_source_ibm_pi_snapshots.go similarity index 75% rename from ibm/data_source_ibm_pi_snapshots.go rename to ibm/service/power/data_source_ibm_pi_snapshots.go index b5a505eeb..273c0fcef 100644 --- a/ibm/data_source_ibm_pi_snapshots.go +++ b/ibm/service/power/data_source_ibm_pi_snapshots.go @@ -1,24 +1,27 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power import ( + "context" + "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" ) -func dataSourceIBMPISnapshots() *schema.Resource { +func DataSourceIBMPISnapshots() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMPISnapshotsRead, + ReadContext: dataSourceIBMPISnapshotsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { Type: schema.TypeString, Required: true, @@ -26,7 +29,6 @@ func dataSourceIBMPISnapshots() *schema.Resource { }, //Computed Attributes - "instance_snapshots": { Type: schema.TypeList, Computed: true, @@ -44,7 +46,6 @@ func dataSourceIBMPISnapshots() *schema.Resource { Type: schema.TypeInt, Computed: true, }, - "description": { Type: schema.TypeString, Computed: true, @@ -65,6 +66,10 @@ func dataSourceIBMPISnapshots() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "volume_snapshots": { + Type: schema.TypeMap, + Computed: true, + }, }, }, }, @@ -72,19 +77,17 @@ func dataSourceIBMPISnapshots() *schema.Resource { } } -func dataSourceIBMPISnapshotsRead(d *schema.ResourceData, meta interface{}) error { - - sess, err := meta.(ClientSession).IBMPISession() +func dataSourceIBMPISnapshotsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { - return err + return diag.FromErr(err) } - powerinstanceid := d.Get(helpers.PICloudInstanceId).(string) - snapshot := instance.NewIBMPISnapshotClient(sess, powerinstanceid) - snapshotData, err := snapshot.GetAll("", powerinstanceid, getTimeOut) - + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshotData, err := snapshot.GetAll() if err != nil { - return err + return diag.FromErr(err) } var clientgenU, _ = uuid.GenerateUUID() @@ -92,7 +95,6 @@ func dataSourceIBMPISnapshotsRead(d *schema.ResourceData, meta interface{}) erro d.Set("instance_snapshots", flattenSnapshotsInstances(snapshotData.Snapshots)) return nil - } func flattenSnapshotsInstances(list []*models.Snapshot) []map[string]interface{} { @@ -108,6 +110,7 @@ func flattenSnapshotsInstances(list []*models.Snapshot) []map[string]interface{} "action": i.Action, "percent_complete": i.PercentComplete, "status": i.Status, + "volume_snapshots": i.VolumeSnapshots, } result = append(result, l) diff --git a/ibm/service/power/data_source_ibm_pi_snapshots_test.go b/ibm/service/power/data_source_ibm_pi_snapshots_test.go new file mode 100644 index 000000000..be8d385d8 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_snapshots_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISnapshotsDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISnapshotsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_instance_snapshots.testacc_ds_snapshots", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISnapshotsDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_pi_instance_snapshots" "testacc_ds_snapshots" { + pi_cloud_instance_id = "%s" +}`, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_group.go b/ibm/service/power/data_source_ibm_pi_spp_placement_group.go new file mode 100644 index 000000000..5b6f632ae --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_group.go @@ -0,0 +1,75 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPISPPPlacementGroup() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPISPPPlacementGroupRead, + Schema: map[string]*schema.Schema{ + Arg_SPPPlacementGroupID: { + Type: schema.TypeString, + Required: true, + }, + + Attr_SPPPlacementGroupName: { + Type: schema.TypeString, + Computed: true, + }, + + Attr_SPPPlacementGroupPolicy: { + Type: schema.TypeString, + Computed: true, + }, + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + Attr_SPPPlacementGroupMembers: { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPISPPPlacementGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + placementGroupID := d.Get(Arg_SPPPlacementGroupID).(string) + client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(placementGroupID) + if err != nil || response == nil { + return diag.Errorf("error fetching the spp placement group: %v", err) + } + + d.SetId(*response.ID) + d.Set(Attr_SPPPlacementGroupName, response.Name) + d.Set(Attr_SPPPlacementGroupPolicy, response.Policy) + d.Set(Attr_SPPPlacementGroupMembers, response.MemberSharedProcessorPools) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go b/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go new file mode 100644 index 000000000..a5f5d9d18 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISPPPlacementGroupDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISPPPlacementGroupDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_spp_placement_group.testacc_ds_spp_placement_group", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISPPPlacementGroupDataSourceConfig() string { + return fmt.Sprintf(` +data "ibm_pi_spp_placement_group" "testacc_ds_spp_placement_group" { + pi_spp_placement_group_id = "%s" + pi_cloud_instance_id = "%s" +}`, acc.Pi_spp_placement_group_id, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go b/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go new file mode 100644 index 000000000..8ac4d5d67 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go @@ -0,0 +1,93 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + PISPPPlacementGroups = "spp_placement_groups" +) + +func DataSourceIBMPISPPPlacementGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISPPPlacementGroupsRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + PISPPPlacementGroups: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SPPPlacementGroupID: { + Type: schema.TypeString, + Computed: true, + }, + Attr_SPPPlacementGroupName: { + Type: schema.TypeString, + Computed: true, + }, + Attr_SPPPlacementGroupMembers: { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + Attr_SPPPlacementGroupPolicy: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISPPPlacementGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + groups, err := client.GetAll() + if err != nil || groups == nil { + return diag.Errorf("error fetching spp placement groups: %v", err) + } + + result := make([]map[string]interface{}, 0, len(groups.SppPlacementGroups)) + for _, placementGroup := range groups.SppPlacementGroups { + key := map[string]interface{}{ + Attr_SPPPlacementGroupID: placementGroup.ID, + Attr_SPPPlacementGroupName: placementGroup.Name, + Attr_SPPPlacementGroupMembers: placementGroup.MemberSharedProcessorPools, + Attr_SPPPlacementGroupPolicy: placementGroup.Policy, + } + result = append(result, key) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + d.Set(PISPPPlacementGroups, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_groups_test.go b/ibm/service/power/data_source_ibm_pi_spp_placement_groups_test.go new file mode 100644 index 000000000..83b0a789e --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_groups_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISPPPlacementGroupsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISPPPlacementGroupsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_spp_placement_groups.test", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISPPPlacementGroupsDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_spp_placement_groups" "test" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go new file mode 100644 index 000000000..f48c7696a --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go @@ -0,0 +1,84 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + PIPoolName = "pi_storage_pool" +) + +func DataSourceIBMPIStoragePoolCapacity() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIStoragePoolCapacityRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + PIPoolName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + Description: "Storage pool name", + }, + // Computed Attributes + MaxAllocationSize: { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum allocation storage size (GB)", + }, + StorageType: { + Type: schema.TypeString, + Computed: true, + Description: "Storage type of the storage pool", + }, + TotalCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Total pool capacity (GB)", + }, + }, + } +} + +func dataSourceIBMPIStoragePoolCapacityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + storagePool := d.Get(PIPoolName).(string) + + client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + sp, err := client.GetStoragePoolCapacity(storagePool) + if err != nil { + log.Printf("[ERROR] get storage pool capacity failed %v", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, storagePool)) + + d.Set(MaxAllocationSize, *sp.MaxAllocationSize) + d.Set(StorageType, sp.StorageType) + d.Set(TotalCapacity, sp.TotalCapacity) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_pool_capacity_test.go b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity_test.go new file mode 100644 index 000000000..417d67b5d --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIStoragePoolCapacityDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIStoragePoolCapacityDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_storage_pool_capacity.pool", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIStoragePoolCapacityDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_storage_pool_capacity" "pool" { + pi_cloud_instance_id = "%s" + pi_storage_pool = "%s" + } + `, acc.Pi_cloud_instance_id, acc.PiStoragePool) +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go new file mode 100644 index 000000000..bd3f3a7a7 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go @@ -0,0 +1,122 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + MaximumStorageAllocation = "maximum_storage_allocation" + StoragePoolsCapacity = "storage_pools_capacity" + MaxAllocationSize = "max_allocation_size" + PoolName = "pool_name" + StoragePool = "storage_pool" + StorageType = "storage_type" + TotalCapacity = "total_capacity" +) + +func DataSourceIBMPIStoragePoolsCapacity() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIStoragePoolsCapacityRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + MaximumStorageAllocation: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum storage allocation", + }, + StoragePoolsCapacity: { + Type: schema.TypeList, + Computed: true, + Description: "Storage pools capacity", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + MaxAllocationSize: { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum allocation storage size (GB)", + }, + PoolName: { + Type: schema.TypeString, + Computed: true, + Description: "Pool name", + }, + StorageType: { + Type: schema.TypeString, + Computed: true, + Description: "Storage type of the storage pool", + }, + TotalCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Total pool capacity (GB)", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIStoragePoolsCapacityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + spc, err := client.GetAllStoragePoolsCapacity() + if err != nil { + log.Printf("[ERROR] get all storage pools capacity failed %v", err) + return diag.FromErr(err) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + + if spc.MaximumStorageAllocation != nil { + msa := spc.MaximumStorageAllocation + data := map[string]interface{}{ + MaxAllocationSize: *msa.MaxAllocationSize, + StoragePool: *msa.StoragePool, + StorageType: *msa.StorageType, + } + d.Set(MaximumStorageAllocation, flex.Flatten(data)) + } + + result := make([]map[string]interface{}, 0, len(spc.StoragePoolsCapacity)) + for _, sp := range spc.StoragePoolsCapacity { + data := map[string]interface{}{ + MaxAllocationSize: *sp.MaxAllocationSize, + PoolName: sp.PoolName, + StorageType: sp.StorageType, + TotalCapacity: sp.TotalCapacity, + } + result = append(result, data) + } + d.Set(StoragePoolsCapacity, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_pools_capacity_test.go b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity_test.go new file mode 100644 index 000000000..638cc8420 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIStoragePoolsCapacityDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIStoragePoolsCapacityDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_storage_pools_capacity.pools", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIStoragePoolsCapacityDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_storage_pools_capacity" "pools" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go new file mode 100644 index 000000000..d33d338ff --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go @@ -0,0 +1,122 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + PITypeName = "pi_storage_type" +) + +func DataSourceIBMPIStorageTypeCapacity() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIStorageTypeCapacityRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + PITypeName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + Description: "Storage type name", + }, + // Computed Attributes + MaximumStorageAllocation: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum storage allocation", + }, + StoragePoolsCapacity: { + Type: schema.TypeList, + Computed: true, + Description: "Storage pools capacity", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + MaxAllocationSize: { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum allocation storage size (GB)", + }, + PoolName: { + Type: schema.TypeString, + Computed: true, + Description: "Pool name", + }, + StorageType: { + Type: schema.TypeString, + Computed: true, + Description: "Storage type of the storage pool", + }, + TotalCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Total pool capacity (GB)", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIStorageTypeCapacityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + storageType := d.Get(PITypeName).(string) + + client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + stc, err := client.GetStorageTypeCapacity(storageType) + if err != nil { + log.Printf("[ERROR] get storage type capacity failed %v", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, storageType)) + + if stc.MaximumStorageAllocation != nil { + msa := stc.MaximumStorageAllocation + data := map[string]interface{}{ + MaxAllocationSize: *msa.MaxAllocationSize, + StoragePool: *msa.StoragePool, + StorageType: *msa.StorageType, + } + d.Set(MaximumStorageAllocation, flex.Flatten(data)) + } + + result := make([]map[string]interface{}, 0, len(stc.StoragePoolsCapacity)) + for _, sp := range stc.StoragePoolsCapacity { + data := map[string]interface{}{ + MaxAllocationSize: *sp.MaxAllocationSize, + PoolName: sp.PoolName, + StorageType: sp.StorageType, + TotalCapacity: sp.TotalCapacity, + } + result = append(result, data) + } + d.Set(StoragePoolsCapacity, result) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_type_capacity_test.go b/ibm/service/power/data_source_ibm_pi_storage_type_capacity_test.go new file mode 100644 index 000000000..25b3e856b --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_type_capacity_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIStorageTypeCapacityDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIStorageTypeCapacityDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_storage_type_capacity.type", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIStorageTypeCapacityDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_storage_type_capacity" "type" { + pi_cloud_instance_id = "%s" + pi_storage_type = "%s" + } + `, acc.Pi_cloud_instance_id, acc.PiStorageType) +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go new file mode 100644 index 000000000..59feb2795 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go @@ -0,0 +1,151 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + StorageTypesCapacity = "storage_types_capacity" +) + +func DataSourceIBMPIStorageTypesCapacity() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIStorageTypesCapacityRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + MaximumStorageAllocation: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum storage allocation", + }, + StorageTypesCapacity: { + Type: schema.TypeList, + Computed: true, + Description: "Storage types capacity", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + MaximumStorageAllocation: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum storage allocation", + }, + StoragePoolsCapacity: { + Type: schema.TypeList, + Computed: true, + Description: "Storage pools capacity", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + MaxAllocationSize: { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum allocation storage size (GB)", + }, + PoolName: { + Type: schema.TypeString, + Computed: true, + Description: "Pool name", + }, + StorageType: { + Type: schema.TypeString, + Computed: true, + Description: "Storage type of the storage pool", + }, + TotalCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Total pool capacity (GB)", + }, + }, + }, + }, + StorageType: { + Type: schema.TypeString, + Computed: true, + Description: "The storage type", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPIStorageTypesCapacityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + stc, err := client.GetAllStorageTypesCapacity() + if err != nil { + log.Printf("[ERROR] get all storage types capacity failed %v", err) + return diag.FromErr(err) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + + if stc.MaximumStorageAllocation != nil { + msa := stc.MaximumStorageAllocation + data := map[string]interface{}{ + MaxAllocationSize: *msa.MaxAllocationSize, + StoragePool: *msa.StoragePool, + StorageType: *msa.StorageType, + } + d.Set(MaximumStorageAllocation, flex.Flatten(data)) + } + stcResult := make([]map[string]interface{}, 0, len(stc.StorageTypesCapacity)) + for _, st := range stc.StorageTypesCapacity { + stResult := map[string]interface{}{} + if st.MaximumStorageAllocation != nil { + msa := st.MaximumStorageAllocation + data := map[string]interface{}{ + MaxAllocationSize: *msa.MaxAllocationSize, + StoragePool: *msa.StoragePool, + StorageType: *msa.StorageType, + } + stResult[MaximumStorageAllocation] = flex.Flatten(data) + } + spc := make([]map[string]interface{}, 0, len(st.StoragePoolsCapacity)) + for _, sp := range st.StoragePoolsCapacity { + data := map[string]interface{}{ + MaxAllocationSize: *sp.MaxAllocationSize, + PoolName: sp.PoolName, + StorageType: sp.StorageType, + TotalCapacity: sp.TotalCapacity, + } + spc = append(spc, data) + } + stResult[StoragePoolsCapacity] = spc + stResult[StorageType] = st.StorageType + stcResult = append(stcResult, stResult) + } + + d.Set(StorageTypesCapacity, stcResult) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_storage_types_capacity_test.go b/ibm/service/power/data_source_ibm_pi_storage_types_capacity_test.go new file mode 100644 index 000000000..85dda15c8 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_storage_types_capacity_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIStorageTypesCapacityDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIStorageTypesCapacityDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_storage_types_capacity.types", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIStorageTypesCapacityDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_storage_types_capacity" "types" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_system_pools.go b/ibm/service/power/data_source_ibm_pi_system_pools.go new file mode 100644 index 000000000..7e2f52b63 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_system_pools.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "log" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + SystemPoolName = "system_pool_name" + SystemPools = "system_pools" + SystemPool = "system_pool" + Capacity = "capacity" + CoreMemoryRatio = "core_memory_ratio" + MaxAvailable = "max_available" + MaxCoresAvailable = "max_cores_available" + MaxMemoryAvailable = "max_memory_available" + SharedCoreRatio = "shared_core_ratio" + Type = "type" + Systems = "systems" + Cores = "cores" + ID = "id" + Memory = "memory" + Default = "default" + Max = "max" + Min = "min" +) + +func DataSourceIBMPISystemPools() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISystemPoolsRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + // Computed Attributes + SystemPools: { + Type: schema.TypeList, + Computed: true, + Description: "List of available system pools within a particular DataCenter", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + SystemPoolName: { + Type: schema.TypeString, + Computed: true, + Description: "The system pool name", + }, + Capacity: { + Type: schema.TypeMap, + Computed: true, + Description: "Advertised capacity cores and memory (GB)", + }, + CoreMemoryRatio: { + Type: schema.TypeFloat, + Computed: true, + Description: "Processor to Memory (GB) Ratio", + }, + MaxAvailable: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum configurable cores and memory (GB) (aggregated from all hosts)", + }, + MaxCoresAvailable: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum configurable cores available combined with available memory of that host", + }, + MaxMemoryAvailable: { + Type: schema.TypeMap, + Computed: true, + Description: "Maximum configurable memory available combined with available cores of that host", + }, + SharedCoreRatio: { + Type: schema.TypeMap, + Computed: true, + Description: "The min-max-default allocation percentage of shared core per vCPU", + }, + Systems: { + Type: schema.TypeList, + Computed: true, + Description: "The DataCenter list of servers and their available resources", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Cores: { + Type: schema.TypeString, + Computed: true, + Description: "The host available Processor units", + }, + ID: { + Type: schema.TypeString, + Computed: true, + Description: "The host identifier", + }, + Memory: { + Type: schema.TypeString, + Computed: true, + Description: "The host available RAM memory in GiB", + }, + }, + }, + }, + Type: { + Type: schema.TypeString, + Computed: true, + Description: "Type of system hardware", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISystemPoolsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPISystemPoolClient(ctx, sess, cloudInstanceID) + sps, err := client.GetSystemPools() + if err != nil { + log.Printf("[ERROR] get system pools capacity failed %v", err) + return diag.FromErr(err) + } + + var genID, _ = uuid.GenerateUUID() + d.SetId(genID) + + result := make([]map[string]interface{}, 0, len(sps)) + for s, sp := range sps { + data := map[string]interface{}{ + SystemPoolName: s, + Capacity: flattenMax(sp.Capacity), + CoreMemoryRatio: sp.CoreMemoryRatio, + MaxAvailable: flattenMax(sp.MaxAvailable), + MaxCoresAvailable: flattenMax(sp.MaxCoresAvailable), + MaxMemoryAvailable: flattenMax(sp.MaxMemoryAvailable), + SharedCoreRatio: flattenSharedCoreRatio(sp.SharedCoreRatio), + Type: sp.Type, + Systems: flattenSystems(sp.Systems), + } + result = append(result, data) + } + + d.Set(SystemPools, result) + + return nil +} + +func flattenMax(s *models.System) map[string]string { + ret := map[string]interface{}{ + Cores: *s.Cores, + Memory: *s.Memory, + } + return flex.Flatten(ret) +} + +func flattenSystem(s *models.System) map[string]string { + ret := map[string]interface{}{ + Cores: *s.Cores, + ID: s.ID, + Memory: *s.Memory, + } + return flex.Flatten(ret) +} + +func flattenSystems(sl []*models.System) (systems []map[string]string) { + if sl != nil { + systems = make([]map[string]string, 0, len(sl)) + for _, s := range sl { + systems = append(systems, flattenSystem(s)) + } + return systems + } + return +} + +func flattenSharedCoreRatio(scr *models.MinMaxDefault) map[string]string { + ret := map[string]interface{}{ + Default: scr.Default, + Max: scr.Max, + Min: scr.Min, + } + return flex.Flatten(ret) +} diff --git a/ibm/service/power/data_source_ibm_pi_system_pools_test.go b/ibm/service/power/data_source_ibm_pi_system_pools_test.go new file mode 100644 index 000000000..431ea2a1c --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_system_pools_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPISystemPoolsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPISystemPoolsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_system_pools.pools", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISystemPoolsDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_system_pools" "pools" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_tenant.go b/ibm/service/power/data_source_ibm_pi_tenant.go new file mode 100644 index 000000000..5aceed866 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_tenant.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + //"fmt" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceIBMPITenant() *schema.Resource { + + return &schema.Resource{ + ReadContext: dataSourceIBMPITenantRead, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "creation_date": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "tenant_name": { + Type: schema.TypeString, + Computed: true, + }, + "cloud_instances": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloud_instance_id": { + Type: schema.TypeString, + Computed: true, + }, + "region": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPITenantRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + //tenantid := d.Get("tenantid").(string) + + tenantC := instance.NewIBMPITenantClient(ctx, sess, cloudInstanceID) + tenantData, err := tenantC.GetSelfTenant() + if err != nil { + return diag.FromErr(err) + } + + d.SetId(*tenantData.TenantID) + d.Set("creation_date", tenantData.CreationDate.String()) + d.Set("enabled", tenantData.Enabled) + + if tenantData.CloudInstances != nil { + d.Set("tenant_name", tenantData.CloudInstances[0].Name) + } + + if tenantData.CloudInstances != nil { + tenants := make([]map[string]interface{}, len(tenantData.CloudInstances)) + for i, cloudinstance := range tenantData.CloudInstances { + j := make(map[string]interface{}) + j["region"] = cloudinstance.Region + j["cloud_instance_id"] = cloudinstance.CloudInstanceID + tenants[i] = j + } + + d.Set("cloud_instances", tenants) + } + + return nil +} diff --git a/ibm/data_source_ibm_pi_tenant_test.go b/ibm/service/power/data_source_ibm_pi_tenant_test.go similarity index 78% rename from ibm/data_source_ibm_pi_tenant_test.go rename to ibm/service/power/data_source_ibm_pi_tenant_test.go index 3869ae2c7..e5aa91cd3 100644 --- a/ibm/data_source_ibm_pi_tenant_test.go +++ b/ibm/service/power/data_source_ibm_pi_tenant_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ func TestAccIBMPITenantDataSource_basic(t *testing.T) { //name := "Trial Tenant" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPITenantDataSourceConfig(), @@ -32,6 +34,6 @@ func testAccCheckIBMPITenantDataSourceConfig() string { data "ibm_pi_tenant" "testacc_ds_tenant" { pi_cloud_instance_id = "%s" -}`, pi_cloud_instance_id) +}`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_volume.go b/ibm/service/power/data_source_ibm_pi_volume.go new file mode 100644 index 000000000..7974b4dfa --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_volume.go @@ -0,0 +1,92 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + //"fmt" + + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIVolume() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIVolumeRead, + Schema: map[string]*schema.Schema{ + helpers.PIVolumeName: { + Type: schema.TypeString, + Required: true, + Description: "Volume Name to be used for pvminstances", + ValidateFunc: validation.NoZeroValues, + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Computed Attributes + "state": { + Type: schema.TypeString, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + "shareable": { + Type: schema.TypeBool, + Computed: true, + }, + "bootable": { + Type: schema.TypeBool, + Computed: true, + }, + "disk_type": { + Type: schema.TypeString, + Computed: true, + }, + "volume_pool": { + Type: schema.TypeString, + Computed: true, + }, + "wwn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceIBMPIVolumeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + volumeC := instance.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + volumedata, err := volumeC.Get(d.Get(helpers.PIVolumeName).(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(*volumedata.VolumeID) + d.Set("size", volumedata.Size) + d.Set("state", volumedata.State) + d.Set("shareable", volumedata.Shareable) + d.Set("bootable", volumedata.Bootable) + d.Set("disk_type", volumedata.DiskType) + d.Set("volume_pool", volumedata.VolumePool) + d.Set("wwn", volumedata.Wwn) + + return nil +} diff --git a/ibm/data_source_ibm_pi_volume_test.go b/ibm/service/power/data_source_ibm_pi_volume_test.go similarity index 76% rename from ibm/data_source_ibm_pi_volume_test.go rename to ibm/service/power/data_source_ibm_pi_volume_test.go index fc3e41d67..47966a561 100644 --- a/ibm/data_source_ibm_pi_volume_test.go +++ b/ibm/service/power/data_source_ibm_pi_volume_test.go @@ -1,19 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package power_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMPIVolumeDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPIVolumeDataSourceConfig(), @@ -30,6 +32,6 @@ func testAccCheckIBMPIVolumeDataSourceConfig() string { data "ibm_pi_volume" "testacc_ds_volume" { pi_volume_name = "%s" pi_cloud_instance_id = "%s" -}`, pi_volume_name, pi_cloud_instance_id) +}`, acc.Pi_volume_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go new file mode 100644 index 000000000..38c3ae4b0 --- /dev/null +++ b/ibm/service/power/ibm_pi_constants.go @@ -0,0 +1,140 @@ +package power + +import "time" + +const ( + // used by all + Arg_CloudInstanceID = "pi_cloud_instance_id" + + // Keys + Arg_KeyName = "pi_key_name" + Arg_Key = "pi_ssh_key" + + Attr_KeyID = "key_id" + Attr_Keys = "keys" + Attr_KeyCreationDate = "creation_date" + Attr_Key = "ssh_key" + Attr_KeyName = "name" + + // SAP Profile + PISAPProfiles = "profiles" + PISAPProfileCertified = "certified" + PISAPProfileCores = "cores" + PISAPProfileMemory = "memory" + PISAPProfileID = "profile_id" + PISAPProfileType = "type" + + // DHCP + Arg_DhcpCidr = "pi_cidr" + Arg_DhcpID = "pi_dhcp_id" + Arg_DhcpCloudConnectionID = "pi_cloud_connection_id" + Arg_DhcpDnsServer = "pi_dns_server" + Arg_DhcpName = "pi_dhcp_name" + Arg_DhcpSnatEnabled = "pi_dhcp_snat_enabled" + + Attr_DhcpServers = "servers" + Attr_DhcpID = "dhcp_id" + Attr_DhcpLeases = "leases" + Attr_DhcpLeaseInstanceIP = "instance_ip" + Attr_DhcpLeaseInstanceMac = "instance_mac" + Attr_DhcpNetworkDeprecated = "network" // to deprecate + Attr_DhcpNetworkID = "network_id" + Attr_DhcpNetworkName = "network_name" + Attr_DhcpStatus = "status" + + // Instance + Arg_PVMInstanceId = "pi_instance_id" + Arg_PVMInstanceActionType = "pi_action" + Arg_PVMInstanceHealthStatus = "pi_health_status" + + Attr_Status = "status" + Attr_Progress = "progress" + Attr_HealthStatus = "health_status" + + PVMInstanceHealthOk = "OK" + PVMInstanceHealthWarning = "WARNING" + + //Added timeout values for warning and active status + warningTimeOut = 60 * time.Second + activeTimeOut = 2 * time.Minute + // power service instance capabilities + CUSTOM_VIRTUAL_CORES = "custom-virtualcores" + PIInstanceDeploymentType = "pi_deployment_type" + PIInstanceNetwork = "pi_network" + PIInstanceStoragePool = "pi_storage_pool" + PISAPInstanceProfileID = "pi_sap_profile_id" + PISAPInstanceDeploymentType = "pi_sap_deployment_type" + PIInstanceStoragePoolAffinity = "pi_storage_pool_affinity" + Arg_PIInstanceSharedProcessorPool = "pi_shared_processor_pool" + Attr_PIInstanceSharedProcessorPool = "shared_processor_pool" + Attr_PIInstanceSharedProcessorPoolID = "shared_processor_pool_id" + + // Placement Group + PIPlacementGroupID = "placement_group_id" + PIPlacementGroupMembers = "members" + + // Volume + PIAffinityPolicy = "pi_affinity_policy" + PIAffinityVolume = "pi_affinity_volume" + PIAffinityInstance = "pi_affinity_instance" + PIAntiAffinityInstances = "pi_anti_affinity_instances" + PIAntiAffinityVolumes = "pi_anti_affinity_volumes" + + // VPN + PIVPNConnectionId = "connection_id" + PIVPNConnectionStatus = "connection_status" + PIVPNConnectionDeadPeerDetection = "dead_peer_detections" + PIVPNConnectionDeadPeerDetectionAction = "action" + PIVPNConnectionDeadPeerDetectionInterval = "interval" + PIVPNConnectionDeadPeerDetectionThreshold = "threshold" + PIVPNConnectionLocalGatewayAddress = "local_gateway_address" + PIVPNConnectionVpnGatewayAddress = "gateway_address" + + // Cloud Connections + PICloudConnectionTransitEnabled = "pi_cloud_connection_transit_enabled" + + // Shared Processor Pool + Arg_SharedProcessorPoolName = "pi_shared_processor_pool_name" + Arg_SharedProcessorPoolHostGroup = "pi_shared_processor_pool_host_group" + Arg_SharedProcessorPoolPlacementGroupID = "pi_shared_processor_pool_placement_group_id" + Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" + Arg_SharedProcessorPoolID = "pi_shared_processor_pool_id" + Attr_SharedProcessorPoolID = "shared_processor_pool_id" + Attr_SharedProcessorPoolName = "name" + Attr_SharedProcessorPoolReservedCores = "reserved_cores" + Attr_SharedProcessorPoolAvailableCores = "available_cores" + Attr_SharedProcessorPoolAllocatedCores = "allocated_cores" + Attr_SharedProcessorPoolHostID = "host_id" + Attr_SharedProcessorPoolStatus = "status" + Attr_SharedProcessorPoolStatusDetail = "status_detail" + Attr_SharedProcessorPoolPlacementGroups = "spp_placement_groups" + Attr_SharedProcessorPoolInstances = "instances" + Attr_SharedProcessorPoolInstanceCpus = "cpus" + Attr_SharedProcessorPoolInstanceUncapped = "uncapped" + Attr_SharedProcessorPoolInstanceAvailabilityZone = "availability_zone" + Attr_SharedProcessorPoolInstanceId = "id" + Attr_SharedProcessorPoolInstanceMemory = "memory" + Attr_SharedProcessorPoolInstanceName = "name" + Attr_SharedProcessorPoolInstanceStatus = "status" + Attr_SharedProcessorPoolInstanceVcpus = "vcpus" + + // SPP Placement Group + Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" + Arg_SPPPlacementGroupPolicy = "pi_spp_placement_group_policy" + Attr_SPPPlacementGroupID = "spp_placement_group_id" + Attr_SPPPlacementGroupMembers = "members" + Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" + Attr_SPPPlacementGroupPolicy = "policy" + Attr_SPPPlacementGroupName = "name" + + // status + // common status states + StatusShutoff = "SHUTOFF" + StatusActive = "ACTIVE" + StatusResize = "RESIZE" + StatusError = "ERROR" + StatusBuild = "BUILD" + StatusPending = "PENDING" + SctionStart = "start" + SctionStop = "stop" +) diff --git a/ibm/service/power/resource_ibm_pi_capture.go b/ibm/service/power/resource_ibm_pi_capture.go new file mode 100644 index 000000000..ed0b73d15 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_capture.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "errors" + "fmt" + "log" + "time" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_images" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const cloudStorageDestination string = "cloud-storage" +const imageCatalogDestination string = "image-catalog" + +func ResourceIBMPICapture() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPICaptureCreate, + ReadContext: resourceIBMPICaptureRead, + DeleteContext: resourceIBMPICaptureDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(75 * time.Minute), + Delete: schema.DefaultTimeout(50 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: " Cloud Instance ID - This is the service_instance_id.", + }, + + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance Name of the Power VM", + }, + + helpers.PIInstanceCaptureName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the capture to create. Note : this must be unique", + }, + + helpers.PIInstanceCaptureDestination: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination for the deployable image", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"image-catalog", "cloud-storage", "both"}), + }, + + helpers.PIInstanceCaptureVolumeIds: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + ForceNew: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of Data volume IDs", + }, + + helpers.PIInstanceCaptureCloudStorageRegion: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "List of Regions to use", + }, + + helpers.PIInstanceCaptureCloudStorageAccessKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Sensitive: true, + Description: "Name of Cloud Storage Access Key", + }, + helpers.PIInstanceCaptureCloudStorageSecretKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Sensitive: true, + Description: "Name of the Cloud Storage Secret Key", + }, + helpers.PIInstanceCaptureCloudStorageImagePath: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Cloud Storage Image Path (bucket-name [/folder/../..])", + }, + // Computed Attribute + "image_id": { + Type: schema.TypeString, + Computed: true, + Description: "Image ID of Capture Instance", + }, + }, + } +} + +func resourceIBMPICaptureCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get(helpers.PIInstanceName).(string) + capturename := d.Get(helpers.PIInstanceCaptureName).(string) + capturedestination := d.Get(helpers.PIInstanceCaptureDestination).(string) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + client := st.NewIBMPIInstanceClient(context.Background(), sess, cloudInstanceID) + + captureBody := &models.PVMInstanceCapture{ + CaptureDestination: &capturedestination, + CaptureName: &capturename, + } + if capturedestination != imageCatalogDestination { + if v, ok := d.GetOk(helpers.PIInstanceCaptureCloudStorageRegion); ok { + captureBody.CloudStorageRegion = v.(string) + } else { + return diag.Errorf("%s is required when capture destination is %s", helpers.PIInstanceCaptureCloudStorageRegion, capturedestination) + } + if v, ok := d.GetOk(helpers.PIInstanceCaptureCloudStorageAccessKey); ok { + captureBody.CloudStorageAccessKey = v.(string) + } else { + return diag.Errorf("%s is required when capture destination is %s ", helpers.PIInstanceCaptureCloudStorageAccessKey, capturedestination) + } + if v, ok := d.GetOk(helpers.PIInstanceCaptureCloudStorageImagePath); ok { + captureBody.CloudStorageImagePath = v.(string) + } else { + return diag.Errorf("%s is required when capture destination is %s ", helpers.PIInstanceCaptureCloudStorageImagePath, capturedestination) + } + if v, ok := d.GetOk(helpers.PIInstanceCaptureCloudStorageSecretKey); ok { + captureBody.CloudStorageSecretKey = v.(string) + } else { + return diag.Errorf("%s is required when capture destination is %s ", helpers.PIInstanceCaptureCloudStorageSecretKey, capturedestination) + } + } + + if v, ok := d.GetOk(helpers.PIInstanceCaptureVolumeIds); ok { + volids := flex.ExpandStringList((v.(*schema.Set)).List()) + if len(volids) > 0 { + captureBody.CaptureVolumeIDs = volids + } + } + + captureResponse, err := client.CaptureInstanceToImageCatalogV2(name, captureBody) + + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, capturename, capturedestination)) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *captureResponse.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + return resourceIBMPICaptureRead(ctx, d, meta) +} + +func resourceIBMPICaptureRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + captureID := parts[1] + capturedestination := parts[2] + if capturedestination != cloudStorageDestination { + imageClient := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imagedata, err := imageClient.Get(captureID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_images.PcloudCloudinstancesImagesGetNotFound: + log.Printf("[DEBUG] image does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get image failed %v", err) + return diag.FromErr(err) + } + imageid := *imagedata.ImageID + d.Set("image_id", imageid) + } + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + return nil +} + +func resourceIBMPICaptureDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + captureID := parts[1] + capturedestination := parts[2] + if capturedestination != cloudStorageDestination { + imageClient := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + err = imageClient.Delete(captureID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_images.PcloudCloudinstancesImagesGetNotFound: + log.Printf("[DEBUG] image does not exist while deleting %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] delete image failed %v", err) + return diag.FromErr(err) + } + } + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_capture_test.go b/ibm/service/power/resource_ibm_pi_capture_test.go new file mode 100644 index 000000000..5e69dc801 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_capture_test.go @@ -0,0 +1,208 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMPICaptureBasic(t *testing.T) { + captureRes := "ibm_pi_capture.capture_instance" + name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICaptureDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICaptureConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICaptureExists(captureRes), + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + resource.TestCheckResourceAttrSet(captureRes, "image_id"), + ), + }, + }, + }) +} +func TestAccIBMPICaptureWithVolume(t *testing.T) { + captureRes := "ibm_pi_capture.capture_instance" + name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICaptureDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICaptureWithVolumeConfig(name, helpers.PIInstanceHealthOk), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICaptureExists(captureRes), + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + resource.TestCheckResourceAttrSet(captureRes, "image_id"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccIBMPICaptureCloudStorage(t *testing.T) { + captureRes := "ibm_pi_capture.capture_instance" + name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICaptureCloudStorageConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + ), + }, + }, + }) +} + +func TestAccIBMPICaptureBoth(t *testing.T) { + captureRes := "ibm_pi_capture.capture_instance" + name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICaptureBothConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + resource.TestCheckResourceAttrSet(captureRes, "image_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICaptureExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + cloudInstanceID := parts[0] + captureID := parts[1] + if err != nil { + return err + } + client := st.NewIBMPIImageClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(captureID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPICaptureDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_capture" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + cloudInstanceID := parts[0] + captureID := parts[1] + if err != nil { + return err + } + imageClient := st.NewIBMPIImageClient(context.Background(), sess, cloudInstanceID) + _, err = imageClient.Get(captureID) + if err == nil { + return fmt.Errorf("PI Image still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMPICaptureWithVolumeConfig(name string, healthStatus string) string { + return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` + resource "ibm_pi_capture" "capture_instance" { + depends_on=[ibm_pi_instance.power_instance] + pi_cloud_instance_id="%[1]s" + pi_capture_name = "%[2]s" + pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name + pi_capture_destination = "image-catalog" + pi_capture_volume_ids = [ibm_pi_volume.power_volume.volume_id] + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPICaptureConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_capture" "capture_instance" { + pi_cloud_instance_id="%[1]s" + pi_capture_name = "%s" + pi_instance_name = "%s" + pi_capture_destination = "image-catalog" + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_instance_name) +} + +func testAccCheckIBMPICaptureCloudStorageConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_capture" "capture_instance" { + pi_cloud_instance_id="%[1]s" + pi_capture_name = "%s" + pi_instance_name = "%s" + pi_capture_destination = "cloud-storage" + pi_capture_cloud_storage_region = "us-east" + pi_capture_cloud_storage_access_key = "%s" + pi_capture_cloud_storage_secret_key = "%s" + pi_capture_storage_image_path = "%s" + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_instance_name, acc.Pi_capture_cloud_storage_access_key, acc.Pi_capture_cloud_storage_secret_key, acc.Pi_capture_storage_image_path) +} + +func testAccCheckIBMPICaptureBothConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_capture" "capture_instance" { + pi_cloud_instance_id="%[1]s" + pi_capture_name = "%s" + pi_instance_name = "%s" + pi_capture_destination = "both" + pi_capture_cloud_storage_region = "us-east" + pi_capture_cloud_storage_access_key = "%s" + pi_capture_cloud_storage_secret_key = "%s" + pi_capture_storage_image_path = "%s" + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_instance_name, acc.Pi_capture_cloud_storage_access_key, acc.Pi_capture_cloud_storage_secret_key, acc.Pi_capture_storage_image_path) +} diff --git a/ibm/service/power/resource_ibm_pi_cloud_connection.go b/ibm/service/power/resource_ibm_pi_cloud_connection.go new file mode 100644 index 000000000..eecf62362 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_cloud_connection.go @@ -0,0 +1,499 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/errors" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_cloud_connections" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPICloudConnection() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPICloudConnectionCreate, + ReadContext: resourceIBMPICloudConnectionRead, + UpdateContext: resourceIBMPICloudConnectionUpdate, + DeleteContext: resourceIBMPICloudConnectionDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PICloudConnectionName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the cloud connection", + }, + helpers.PICloudConnectionSpeed: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedIntValues([]int{50, 100, 200, 500, 1000, 2000, 5000, 10000}), + Description: "Speed of the cloud connection (speed in megabits per second)", + }, + + // Optional Attributes + helpers.PICloudConnectionGlobalRouting: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable global routing for this cloud connection", + }, + helpers.PICloudConnectionMetered: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable metered for this cloud connection", + }, + helpers.PICloudConnectionNetworks: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of Networks to attach to this cloud connection", + }, + helpers.PICloudConnectionClassicEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable classic endpoint destination", + }, + helpers.PICloudConnectionClassicGreCidr: { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{helpers.PICloudConnectionClassicEnabled, helpers.PICloudConnectionClassicGreDest}, + Description: "GRE network in CIDR notation", + }, + helpers.PICloudConnectionClassicGreDest: { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{helpers.PICloudConnectionClassicEnabled, helpers.PICloudConnectionClassicGreCidr}, + Description: "GRE destination IP address", + }, + helpers.PICloudConnectionVPCEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: false, + RequiredWith: []string{helpers.PICloudConnectionVPCCRNs}, + Description: "Enable VPC for this cloud connection", + }, + helpers.PICloudConnectionVPCCRNs: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + RequiredWith: []string{helpers.PICloudConnectionVPCEnabled}, + Description: "Set of VPCs to attach to this cloud connection", + }, + PICloudConnectionTransitEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable transit gateway for this cloud connection", + }, + + //Computed Attributes + PICloudConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "Cloud connection ID", + }, + PICloudConnectionStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Link status", + }, + PICloudConnectionIBMIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "IBM IP address", + }, + PICloudConnectionUserIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "User IP address", + }, + PICloudConnectionPort: { + Type: schema.TypeString, + Computed: true, + Description: "Port", + }, + PICloudConnectionClassicGreSource: { + Type: schema.TypeString, + Computed: true, + Description: "GRE auto-assigned source IP address", + }, + PICloudConnectionConnectionMode: { + Type: schema.TypeString, + Computed: true, + Description: "Type of service the gateway is attached to", + }, + }, + } +} + +func resourceIBMPICloudConnectionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(helpers.PICloudConnectionName).(string) + speed := int64(d.Get(helpers.PICloudConnectionSpeed).(int)) + + body := &models.CloudConnectionCreate{ + Name: &name, + Speed: &speed, + } + if v, ok := d.GetOk(helpers.PICloudConnectionGlobalRouting); ok { + body.GlobalRouting = v.(bool) + } + if v, ok := d.GetOk(helpers.PICloudConnectionMetered); ok { + body.Metered = v.(bool) + } + // networks + if v, ok := d.GetOk(helpers.PICloudConnectionNetworks); ok && v.(*schema.Set).Len() > 0 { + body.Subnets = flex.ExpandStringList(v.(*schema.Set).List()) + } + // classic + if v, ok := d.GetOk(helpers.PICloudConnectionClassicEnabled); ok { + classicEnabled := v.(bool) + classic := &models.CloudConnectionEndpointClassicUpdate{ + Enabled: classicEnabled, + } + gre := &models.CloudConnectionGRETunnelCreate{} + if v, ok := d.GetOk(helpers.PICloudConnectionClassicGreCidr); ok { + greCIDR := v.(string) + gre.Cidr = &greCIDR + classic.Gre = gre + } + if v, ok := d.GetOk(helpers.PICloudConnectionClassicGreDest); ok { + greDest := v.(string) + gre.DestIPAddress = &greDest + classic.Gre = gre + } + body.Classic = classic + } + + // VPC + if v, ok := d.GetOk(helpers.PICloudConnectionVPCEnabled); ok { + vpcEnabled := v.(bool) + vpc := &models.CloudConnectionEndpointVPC{ + Enabled: vpcEnabled, + } + if v, ok := d.GetOk(helpers.PICloudConnectionVPCCRNs); ok && v.(*schema.Set).Len() > 0 { + vpcIds := flex.ExpandStringList(v.(*schema.Set).List()) + vpcs := make([]*models.CloudConnectionVPC, len(vpcIds)) + for i, vpcId := range vpcIds { + vpcIdCopy := vpcId[0:] + vpcs[i] = &models.CloudConnectionVPC{ + VpcID: &vpcIdCopy, + } + } + vpc.Vpcs = vpcs + } + body.Vpc = vpc + } + + // Transit Gateway + if v, ok := d.GetOk(PICloudConnectionTransitEnabled); ok { + body.TransitEnabled = v.(bool) + } + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + cloudConnection, cloudConnectionJob, err := client.Create(body) + if err != nil { + log.Printf("[DEBUG] create cloud connection failed %v", err) + return diag.FromErr(err) + } + + if cloudConnection != nil { + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *cloudConnection.CloudConnectionID)) + } else if cloudConnectionJob != nil { + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *cloudConnectionJob.CloudConnectionID)) + + jobID := *cloudConnectionJob.JobRef.ID + + client := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + _, err = waitForIBMPIJobCompleted(ctx, client, jobID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPICloudConnectionRead(ctx, d, meta) +} + +func resourceIBMPICloudConnectionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + cloudConnectionID := parts[1] + + ccName := d.Get(helpers.PICloudConnectionName).(string) + ccSpeed := int64(d.Get(helpers.PICloudConnectionSpeed).(int)) + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + if d.HasChangesExcept(helpers.PICloudConnectionNetworks) { + + body := &models.CloudConnectionUpdate{ + Name: &ccName, + Speed: &ccSpeed, + } + if v, ok := d.GetOk(helpers.PICloudConnectionGlobalRouting); ok { + globalRouting := v.(bool) + body.GlobalRouting = &globalRouting + } + if v, ok := d.GetOk(helpers.PICloudConnectionMetered); ok { + metered := v.(bool) + body.Metered = &metered + } + // classic + if v, ok := d.GetOk(helpers.PICloudConnectionClassicEnabled); ok { + classicEnabled := v.(bool) + classic := &models.CloudConnectionEndpointClassicUpdate{ + Enabled: classicEnabled, + } + gre := &models.CloudConnectionGRETunnelCreate{} + if v, ok := d.GetOk(helpers.PICloudConnectionClassicGreCidr); ok { + greCIDR := v.(string) + gre.Cidr = &greCIDR + classic.Gre = gre + } + if v, ok := d.GetOk(helpers.PICloudConnectionClassicGreDest); ok { + greDest := v.(string) + gre.DestIPAddress = &greDest + classic.Gre = gre + } + body.Classic = classic + } else { + // need to disable classic if not provided + classic := &models.CloudConnectionEndpointClassicUpdate{ + Enabled: false, + } + body.Classic = classic + } + // vpc + if v, ok := d.GetOk(helpers.PICloudConnectionVPCEnabled); ok { + vpcEnabled := v.(bool) + vpc := &models.CloudConnectionEndpointVPC{ + Enabled: vpcEnabled, + } + if v, ok := d.GetOk(helpers.PICloudConnectionVPCCRNs); ok && v.(*schema.Set).Len() > 0 { + vpcIds := flex.ExpandStringList(v.(*schema.Set).List()) + vpcs := make([]*models.CloudConnectionVPC, len(vpcIds)) + for i, vpcId := range vpcIds { + vpcs[i] = &models.CloudConnectionVPC{ + VpcID: &vpcId, + } + } + vpc.Vpcs = vpcs + } + body.Vpc = vpc + } else { + // need to disable VPC if not provided + vpc := &models.CloudConnectionEndpointVPC{ + Enabled: false, + } + body.Vpc = vpc + } + + _, cloudConnectionJob, err := client.Update(cloudConnectionID, body) + if err != nil { + return diag.FromErr(err) + } + if cloudConnectionJob != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *cloudConnectionJob.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + } + if d.HasChange(helpers.PICloudConnectionNetworks) { + oldRaw, newRaw := d.GetChange(helpers.PICloudConnectionNetworks) + old := oldRaw.(*schema.Set) + new := newRaw.(*schema.Set) + + toAdd := new.Difference(old) + toRemove := old.Difference(new) + + // call network add api for each toAdd + for _, n := range flex.ExpandStringList(toAdd.List()) { + _, jobReference, err := client.AddNetwork(cloudConnectionID, n) + if err != nil { + return diag.FromErr(err) + } + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + + // call network delete api for each toRemove + for _, n := range flex.ExpandStringList(toRemove.List()) { + _, jobReference, err := client.DeleteNetwork(cloudConnectionID, n) + if err != nil { + return diag.FromErr(err) + } + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + return resourceIBMPICloudConnectionRead(ctx, d, meta) +} + +func resourceIBMPICloudConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + cloudConnectionID := parts[1] + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + cloudConnection, err := client.Get(cloudConnectionID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_cloud_connections.PcloudCloudconnectionsGetNotFound: + log.Printf("[DEBUG] cloud connection does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get cloud connection failed %v", err) + return diag.FromErr(err) + } + + d.Set(PICloudConnectionId, cloudConnection.CloudConnectionID) + d.Set(helpers.PICloudConnectionName, cloudConnection.Name) + d.Set(helpers.PICloudConnectionGlobalRouting, cloudConnection.GlobalRouting) + d.Set(helpers.PICloudConnectionMetered, cloudConnection.Metered) + d.Set(PICloudConnectionIBMIPAddress, cloudConnection.IbmIPAddress) + d.Set(PICloudConnectionUserIPAddress, cloudConnection.UserIPAddress) + d.Set(PICloudConnectionStatus, cloudConnection.LinkStatus) + d.Set(PICloudConnectionPort, cloudConnection.Port) + d.Set(helpers.PICloudConnectionSpeed, cloudConnection.Speed) + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + d.Set(PICloudConnectionConnectionMode, cloudConnection.ConnectionMode) + if cloudConnection.Networks != nil { + networks := make([]string, 0) + for _, ccNetwork := range cloudConnection.Networks { + if ccNetwork != nil { + networks = append(networks, *ccNetwork.NetworkID) + } + } + d.Set(helpers.PICloudConnectionNetworks, networks) + } + if cloudConnection.Classic != nil { + d.Set(helpers.PICloudConnectionClassicEnabled, cloudConnection.Classic.Enabled) + if cloudConnection.Classic.Gre != nil { + d.Set(helpers.PICloudConnectionClassicGreDest, cloudConnection.Classic.Gre.DestIPAddress) + d.Set(PICloudConnectionClassicGreSource, cloudConnection.Classic.Gre.SourceIPAddress) + } + } + if cloudConnection.Vpc != nil { + d.Set(helpers.PICloudConnectionVPCEnabled, cloudConnection.Vpc.Enabled) + if cloudConnection.Vpc.Vpcs != nil && len(cloudConnection.Vpc.Vpcs) > 0 { + vpcCRNs := make([]string, len(cloudConnection.Vpc.Vpcs)) + for i, vpc := range cloudConnection.Vpc.Vpcs { + vpcCRNs[i] = *vpc.VpcID + } + d.Set(helpers.PICloudConnectionVPCCRNs, vpcCRNs) + } + } + + return nil +} +func resourceIBMPICloudConnectionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + cloudConnectionID := parts[1] + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + _, err = client.Get(cloudConnectionID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_cloud_connections.PcloudCloudconnectionsGetNotFound: + log.Printf("[DEBUG] cloud connection does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get cloud connection failed %v", err) + return diag.FromErr(err) + } + log.Printf("[INFO] Found cloud connection with id %s", cloudConnectionID) + + deleteJob, err := client.Delete(cloudConnectionID) + if err != nil { + log.Printf("[DEBUG] delete cloud connection failed %v", err) + return diag.FromErr(err) + } + if deleteJob != nil { + jobID := *deleteJob.ID + + client := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + _, err = waitForIBMPIJobCompleted(ctx, client, jobID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach.go b/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach.go new file mode 100644 index 000000000..24b472ed2 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach.go @@ -0,0 +1,139 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +const ( + PICloudConnectionNetworkId = "pi_network_id" +) + +func ResourceIBMPICloudConnectionNetworkAttach() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPICloudConnectionNetworkAttachCreate, + ReadContext: resourceIBMPICloudConnectionNetworkAttachRead, + DeleteContext: resourceIBMPICloudConnectionNetworkAttachDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "PI cloud instance ID", + }, + helpers.PICloudConnectionId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Cloud Connection ID", + }, + PICloudConnectionNetworkId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Network ID to attach to this cloud connection", + }, + }, + } +} + +func resourceIBMPICloudConnectionNetworkAttachCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudConnectionID := d.Get(helpers.PICloudConnectionId).(string) + networkID := d.Get(PICloudConnectionNetworkId).(string) + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + _, jobReference, err := client.AddNetwork(cloudConnectionID, networkID) + if err != nil { + log.Printf("[ERROR] attach network to cloud connection failed %v", err) + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, cloudConnectionID, networkID)) + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPICloudConnectionNetworkAttachRead(ctx, d, meta) +} + +func resourceIBMPICloudConnectionNetworkAttachRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + cloudConnectionID := parts[1] + networkID := parts[2] + + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + d.Set(helpers.PICloudConnectionId, cloudConnectionID) + d.Set(PICloudConnectionNetworkId, networkID) + + return nil +} + +func resourceIBMPICloudConnectionNetworkAttachDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + cloudConnectionID := parts[1] + networkID := parts[2] + + client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + _, jobReference, err := client.DeleteNetwork(cloudConnectionID, networkID) + if err != nil { + log.Printf("[DEBUG] detach network from cloud connection failed %v", err) + return diag.FromErr(err) + } + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach_test.go b/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach_test.go new file mode 100644 index 000000000..d951b02a4 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_cloud_connection_network_attach_test.go @@ -0,0 +1,60 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPICloudConnectionNetworkAttachBasic(t *testing.T) { + name := fmt.Sprintf("tf-ccnet-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionNetworkAttachConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.cloud_connection"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("data.ibm_pi_cloud_connection.cloud_connection", + "networks.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionNetworkAttachConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "cloud_connection" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 100 + } + resource "ibm_pi_network" "network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "vlan" + pi_cidr = "192.152.61.0/24" + } + resource "ibm_pi_cloud_connection_network_attach" "example" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_id = ibm_pi_cloud_connection.cloud_connection.cloud_connection_id + pi_network_id = ibm_pi_network.network1.network_id + } + data "ibm_pi_cloud_connection" "cloud_connection" { + depends_on = [ibm_pi_cloud_connection_network_attach.example] + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_cloud_connection_test.go b/ibm/service/power/resource_ibm_pi_cloud_connection_test.go new file mode 100644 index 000000000..a70f85763 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_cloud_connection_test.go @@ -0,0 +1,312 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPICloudConnectionbasic(t *testing.T) { + name := fmt.Sprintf("tf-cloudconnection-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICloudConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.cloud_connection"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection", + "pi_cloud_connection_speed", "100"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection", + "pi_cloud_connection_networks.#", "1"), + ), + }, + }, + }) +} +func testAccCheckIBMPICloudConnectionDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_cloud_connection" { + continue + } + cloudInstanceID, cloudConnectionID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPICloudConnectionClient(context.Background(), sess, cloudInstanceID) + _, err = client.Get(cloudConnectionID) + if err == nil { + return fmt.Errorf("Cloud Connection still exists: %s", rs.Primary.ID) + } + } + return nil +} +func splitID(id string) (id1, id2 string, err error) { + parts, err := flex.IdParts(id) + if err != nil { + return + } + id1 = parts[0] + id2 = parts[1] + return +} +func testAccCheckIBMPICloudConnectionExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, cloudConnectionID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPICloudConnectionClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(cloudConnectionID) + if err != nil { + return err + } + + return nil + } +} +func testAccCheckIBMPICloudConnectionConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "cloud_connection" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 100 + pi_cloud_connection_networks = [ibm_pi_network.network1.network_id] + } + resource "ibm_pi_network" "network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "vlan" + pi_cidr = "192.112.111.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func TestAccIBMPICloudConnectionNetworks(t *testing.T) { + name := fmt.Sprintf("tf-cloudconnection-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICloudConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionNetworkConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.cc_network"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cc_network", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cc_network", + "pi_cloud_connection_networks.#", "1"), + ), + }, + { + Config: testAccCheckIBMPICloudConnectionNetworkUpdateConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.cc_network"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cc_network", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cc_network", + "pi_cloud_connection_networks.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionNetworkConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "cc_network" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 1000 + pi_cloud_connection_networks = [ibm_pi_network.network1.network_id] + } + resource "ibm_pi_network" "network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s_net1" + pi_network_type = "vlan" + pi_cidr = "192.112.112.0/24" + } + resource "ibm_pi_network" "network2" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s_net2" + pi_network_type = "vlan" + pi_cidr = "192.112.113.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPICloudConnectionNetworkUpdateConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "cc_network" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 1000 + pi_cloud_connection_networks = [ibm_pi_network.network2.network_id] + } + resource "ibm_pi_network" "network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s_net1" + pi_network_type = "vlan" + pi_cidr = "192.112.112.0/24" + } + resource "ibm_pi_network" "network2" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s_net2" + pi_network_type = "vlan" + pi_cidr = "192.112.113.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func TestAccIBMPICloudConnectionClassic(t *testing.T) { + name := fmt.Sprintf("tf-cloudconnection-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICloudConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionClassicConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.classic"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.classic", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.classic", + "pi_cloud_connection_networks.#", "0"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.classic", + "pi_cloud_connection_classic_enabled", "true"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.classic", + "pi_cloud_connection_vpc_enabled", "false"), + ), + }, + }, + }) +} +func testAccCheckIBMPICloudConnectionClassicConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "classic" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 50 + pi_cloud_connection_classic_enabled = true + } + `, acc.Pi_cloud_instance_id, name) +} + +func TestAccIBMPICloudConnectionVPC(t *testing.T) { + name := fmt.Sprintf("tf-cloudconnection-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICloudConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionVPCConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.vpc"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.vpc", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.vpc", + "pi_cloud_connection_networks.#", "0"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.vpc", + "pi_cloud_connection_classic_enabled", "false"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.vpc", + "pi_cloud_connection_vpc_enabled", "true"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.vpc", + "pi_cloud_connection_vpc_crns.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionVPCConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "vpc" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 50 + pi_cloud_connection_vpc_enabled = true + pi_cloud_connection_vpc_crns = ["crn:v1:bluemix:public:is:us-south:a/d9cec80d0adc400ead8e2076afe26698::vpc:r006-6486cf73-451d-4d44-b90d-83dff504cbed"] + } + `, acc.Pi_cloud_instance_id, name) +} + +func TestAccIBMPICloudConnectionTransitGateway(t *testing.T) { + name := fmt.Sprintf("tf-cloudconnection-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICloudConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICloudConnectionConfigTransitGateway(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICloudConnectionExists("ibm_pi_cloud_connection.cloud_connection_transit"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection_transit", + "pi_cloud_connection_name", name), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection_transit", + "pi_cloud_connection_speed", "100"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection_transit", + "pi_cloud_connection_networks.#", "1"), + resource.TestCheckResourceAttr("ibm_pi_cloud_connection.cloud_connection_transit", + "pi_cloud_connection_transit_enabled", "true"), + ), + }, + }, + }) +} + +func testAccCheckIBMPICloudConnectionConfigTransitGateway(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_cloud_connection" "cloud_connection_transit" { + pi_cloud_instance_id = "%[1]s" + pi_cloud_connection_name = "%[2]s" + pi_cloud_connection_speed = 100 + pi_cloud_connection_networks = [ibm_pi_network.network1.network_id] + pi_cloud_connection_transit_enabled = true + } + resource "ibm_pi_network" "network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "vlan" + pi_cidr = "192.112.111.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_dhcp.go b/ibm/service/power/resource_ibm_pi_dhcp.go new file mode 100644 index 000000000..f87acc039 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_dhcp.go @@ -0,0 +1,308 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/errors" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_service_d_h_c_p" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func ResourceIBMPIDhcp() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIDhcpCreate, + ReadContext: resourceIBMPIDhcpRead, + DeleteContext: resourceIBMPIDhcpDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + + // Required Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ForceNew: true, + }, + + // Optional Arguments + Arg_DhcpCidr: { + Type: schema.TypeString, + Optional: true, + Description: "Optional cidr for DHCP private network", + ForceNew: true, + }, + Arg_DhcpCloudConnectionID: { + Type: schema.TypeString, + Optional: true, + Description: "Optional cloud connection uuid to connect with DHCP private network", + ForceNew: true, + }, + Arg_DhcpDnsServer: { + Type: schema.TypeString, + Optional: true, + Description: "Optional DNS Server for DHCP service", + ForceNew: true, + }, + Arg_DhcpName: { + Type: schema.TypeString, + Optional: true, + Description: "Optional name of DHCP Service (will be prefixed by DHCP identifier)", + ForceNew: true, + }, + Arg_DhcpSnatEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates if SNAT will be enabled for the DHCP service", + ForceNew: true, + }, + + // Attributes + Attr_DhcpID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server", + }, + Attr_DhcpLeases: { + Type: schema.TypeList, + Computed: true, + Description: "The list of DHCP Server PVM Instance leases", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_DhcpLeaseInstanceIP: { + Type: schema.TypeString, + Computed: true, + Description: "The IP of the PVM Instance", + }, + Attr_DhcpLeaseInstanceMac: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC Address of the PVM Instance", + }, + }, + }, + }, + Attr_DhcpNetworkDeprecated: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + }, + Attr_DhcpNetworkID: { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the DHCP Server private network", + }, + Attr_DhcpNetworkName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the DHCP Server private network", + }, + Attr_DhcpStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the DHCP Server", + }, + }, + } +} + +func resourceIBMPIDhcpCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // dhcp create object + body := &models.DHCPServerCreate{} + + // arguments + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + if cidr, ok := d.GetOk(Arg_DhcpCidr); ok { + c := cidr.(string) + body.Cidr = &c + } + if cloudConnectionID, ok := d.GetOk(Arg_DhcpCloudConnectionID); ok { + c := cloudConnectionID.(string) + body.CloudConnectionID = &c + } + if dnsServer, ok := d.GetOk(Arg_DhcpDnsServer); ok { + d := dnsServer.(string) + body.DNSServer = &d + } + if name, ok := d.GetOk(Arg_DhcpName); ok { + n := name.(string) + body.Name = &n + } + snatEnabled := d.Get(Arg_DhcpSnatEnabled).(bool) + body.SnatEnabled = &snatEnabled + + // create dhcp + client := st.NewIBMPIDhcpClient(ctx, sess, cloudInstanceID) + dhcpServer, err := client.Create(body) + if err != nil { + log.Printf("[DEBUG] create DHCP failed %v", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *dhcpServer.ID)) + + // wait for creation + _, err = waitForIBMPIDhcpStatus(ctx, client, *dhcpServer.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + diag.FromErr(err) + } + + return resourceIBMPIDhcpRead(ctx, d, meta) +} + +func resourceIBMPIDhcpRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID, dhcpID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // get dhcp + client := st.NewIBMPIDhcpClient(ctx, sess, cloudInstanceID) + dhcpServer, err := client.Get(dhcpID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_service_d_h_c_p.PcloudDhcpGetNotFound: + log.Printf("[DEBUG] dhcp does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get DHCP failed %v", err) + return diag.FromErr(err) + } + + // set attributes + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *dhcpServer.ID)) + d.Set(Attr_DhcpID, *dhcpServer.ID) + d.Set(Attr_DhcpStatus, *dhcpServer.Status) + + if dhcpServer.Network != nil { + dhcpNetwork := dhcpServer.Network + d.Set(Attr_DhcpNetworkDeprecated, *dhcpNetwork.ID) + d.Set(Attr_DhcpNetworkID, *dhcpNetwork.ID) + d.Set(Attr_DhcpNetworkName, *dhcpNetwork.Name) + } + + if dhcpServer.Leases != nil { + leaseList := make([]map[string]string, len(dhcpServer.Leases)) + for i, lease := range dhcpServer.Leases { + leaseList[i] = map[string]string{ + Attr_DhcpLeaseInstanceIP: *lease.InstanceIP, + Attr_DhcpLeaseInstanceMac: *lease.InstanceMacAddress, + } + } + d.Set(Attr_DhcpLeases, leaseList) + } + + return nil +} +func resourceIBMPIDhcpDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID, dhcpID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // delete dhcp + client := st.NewIBMPIDhcpClient(ctx, sess, cloudInstanceID) + err = client.Delete(dhcpID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_service_d_h_c_p.PcloudDhcpDeleteNotFound: + log.Printf("[DEBUG] dhcp does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] delete DHCP failed %v", err) + return diag.FromErr(err) + } + + // wait for deletion + _, err = waitForIBMPIDhcpDeleted(ctx, client, dhcpID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func waitForIBMPIDhcpStatus(ctx context.Context, client *st.IBMPIDhcpClient, dhcpID string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"building"}, + Target: []string{"active"}, + Refresh: func() (interface{}, string, error) { + dhcpServer, err := client.Get(dhcpID) + if err != nil { + log.Printf("[DEBUG] get DHCP failed %v", err) + return nil, "", err + } + if *dhcpServer.Status != StatusActive { + return dhcpServer, "building", nil + } + return dhcpServer, "active", nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForStateContext(ctx) +} + +func waitForIBMPIDhcpDeleted(ctx context.Context, client *st.IBMPIDhcpClient, dhcpID string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{"deleted"}, + Refresh: func() (interface{}, string, error) { + dhcpServer, err := client.Get(dhcpID) + if err != nil { + log.Printf("[DEBUG] dhcp does not exist %v", err) + return dhcpServer, "deleted", nil + } + return dhcpServer, "deleting", nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForStateContext(ctx) +} diff --git a/ibm/service/power/resource_ibm_pi_dhcp_test.go b/ibm/service/power/resource_ibm_pi_dhcp_test.go new file mode 100644 index 000000000..169936d6f --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_dhcp_test.go @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIDhcpbasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIDhcpDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDhcpConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIDhcpExists("ibm_pi_dhcp.dhcp_service"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "dhcp_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIDhcpDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_dhcp" { + continue + } + + cloudInstanceID, dhcpID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + + client := st.NewIBMPIDhcpClient(context.Background(), sess, cloudInstanceID) + _, err = client.Get(dhcpID) + if err == nil { + return fmt.Errorf("PI DHCP still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIDhcpExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + cloudInstanceID, dhcpID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIDhcpClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(dhcpID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPIDhcpConfig() string { + return fmt.Sprintf(` + resource "ibm_pi_dhcp" "dhcp_service" { + pi_cloud_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id) +} + +func TestAccIBMPIDhcpWithCidrName(t *testing.T) { + name := fmt.Sprintf("tf-dhcp-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIDhcpDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDhcpWithCidrNameConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIDhcpExists("ibm_pi_dhcp.dhcp_service"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "dhcp_id"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "status"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "network_id"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "network_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIDhcpWithCidrNameConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_dhcp" "dhcp_service" { + pi_cloud_instance_id = "%[1]s" + pi_dhcp_name = "%[2]s" + pi_cidr = "192.168.103.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func TestAccIBMPIDhcpSNAT(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIDhcpDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDhcpConfigWithSNATDisabled(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIDhcpExists("ibm_pi_dhcp.dhcp_service"), + resource.TestCheckResourceAttrSet( + "ibm_pi_dhcp.dhcp_service", "dhcp_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIDhcpConfigWithSNATDisabled() string { + return fmt.Sprintf(` + resource "ibm_pi_dhcp" "dhcp_service" { + pi_cloud_instance_id = "%s" + pi_dhcp_snat_enabled = false + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/resource_ibm_pi_ike_policy.go b/ibm/service/power/resource_ibm_pi_ike_policy.go new file mode 100644 index 000000000..2d30b0f3b --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_ike_policy.go @@ -0,0 +1,256 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +const ( + PIPolicyId = "policy_id" +) + +func ResourceIBMPIIKEPolicy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIIKEPolicyCreate, + ReadContext: resourceIBMPIIKEPolicyRead, + UpdateContext: resourceIBMPIIKEPolicyUpdate, + DeleteContext: resourceIBMPIIKEPolicyDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PIVPNPolicyName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the IKE Policy", + }, + helpers.PIVPNPolicyDhGroup: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedIntValues([]int{1, 2, 5, 14, 19, 20, 24}), + Description: "DH group of the IKE Policy", + }, + helpers.PIVPNPolicyEncryption: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"aes-256-cbc", "aes-192-cbc", "aes-128-cbc", "aes-256-gcm", "aes-128-gcm", "3des-cbc"}), + Description: "Encryption of the IKE Policy", + }, + helpers.PIVPNPolicyKeyLifetime: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(180, 86400), + Description: "Policy key lifetime", + }, + helpers.PIVPNPolicyVersion: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(1, 2), + Description: "Version of the IKE Policy", + }, + helpers.PIVPNPolicyPresharedKey: { + Type: schema.TypeString, + Required: true, + Description: "Preshared key used in this IKE Policy (length of preshared key must be even)", + }, + + // Optional Attributes + helpers.PIVPNPolicyAuthentication: { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"sha-256", "sha-384", "sha1", "none"}), + Description: "Authentication for the IKE Policy", + }, + + //Computed Attributes + PIPolicyId: { + Type: schema.TypeString, + Computed: true, + Description: "IKE Policy ID", + }, + }, + } +} + +func resourceIBMPIIKEPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(helpers.PIVPNPolicyName).(string) + dhGroup := int64(d.Get(helpers.PIVPNPolicyDhGroup).(int)) + encryption := d.Get(helpers.PIVPNPolicyEncryption).(string) + presharedKey := d.Get(helpers.PIVPNPolicyPresharedKey).(string) + version := int64(d.Get(helpers.PIVPNPolicyVersion).(int)) + keyLifetime := int64(d.Get(helpers.PIVPNPolicyKeyLifetime).(int)) + klt := models.KeyLifetime(keyLifetime) + + body := &models.IKEPolicyCreate{ + DhGroup: &dhGroup, + Encryption: &encryption, + KeyLifetime: &klt, + Name: &name, + PresharedKey: &presharedKey, + Version: &version, + } + + if v, ok := d.GetOk(helpers.PIVPNPolicyAuthentication); ok { + body.Authentication = models.IKEPolicyAuthentication(v.(string)) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + ikePolicy, err := client.CreateIKEPolicy(body) + if err != nil { + log.Printf("[DEBUG] create ike policy failed %v", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *ikePolicy.ID)) + + return resourceIBMPIIKEPolicyRead(ctx, d, meta) +} + +func resourceIBMPIIKEPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + body := &models.IKEPolicyUpdate{} + + if d.HasChange(helpers.PIVPNPolicyName) { + name := d.Get(helpers.PIVPNPolicyName).(string) + body.Name = name + } + if d.HasChange(helpers.PIVPNPolicyDhGroup) { + dhGroup := int64(d.Get(helpers.PIVPNPolicyDhGroup).(int)) + body.DhGroup = dhGroup + } + if d.HasChange(helpers.PIVPNPolicyEncryption) { + encryption := d.Get(helpers.PIVPNPolicyEncryption).(string) + body.Encryption = encryption + } + if d.HasChange(helpers.PIVPNPolicyKeyLifetime) { + keyLifetime := int64(d.Get(helpers.PIVPNPolicyKeyLifetime).(int)) + body.KeyLifetime = models.KeyLifetime(keyLifetime) + } + if d.HasChange(helpers.PIVPNPolicyPresharedKey) { + presharedKey := d.Get(helpers.PIVPNPolicyPresharedKey).(string) + body.PresharedKey = presharedKey + } + if d.HasChange(helpers.PIVPNPolicyVersion) { + version := int64(d.Get(helpers.PIVPNPolicyVersion).(int)) + body.Version = version + } + if d.HasChange(helpers.PIVPNPolicyAuthentication) { + authentication := d.Get(helpers.PIVPNPolicyAuthentication).(string) + body.Authentication = models.IKEPolicyAuthentication(authentication) + } + + _, err = client.UpdateIKEPolicy(policyID, body) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIIKEPolicyRead(ctx, d, meta) +} + +func resourceIBMPIIKEPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + ikePolicy, err := client.GetIKEPolicy(policyID) + if err != nil { + // FIXME: Uncomment when 404 error is available + // switch err.(type) { + // case *p_cloud_v_p_n_policies.PcloudIkepoliciesGetNotFound: + // log.Printf("[DEBUG] VPN policy does not exist %v", err) + // d.SetId("") + // return nil + // } + log.Printf("[DEBUG] get VPN policy failed %v", err) + return diag.FromErr(err) + } + + d.Set(PIPolicyId, ikePolicy.ID) + d.Set(helpers.PIVPNPolicyName, ikePolicy.Name) + d.Set(helpers.PIVPNPolicyDhGroup, ikePolicy.DhGroup) + d.Set(helpers.PIVPNPolicyEncryption, ikePolicy.Encryption) + d.Set(helpers.PIVPNPolicyKeyLifetime, ikePolicy.KeyLifetime) + d.Set(helpers.PIVPNPolicyVersion, ikePolicy.Version) + d.Set(helpers.PIVPNPolicyAuthentication, ikePolicy.Authentication) + + return nil +} + +func resourceIBMPIIKEPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + + err = client.DeleteIKEPolicy(policyID) + if err != nil { + // FIXME: Uncomment when 404 error is available + // switch err.(type) { + // case *p_cloud_v_p_n_policies.PcloudIkepoliciesDeleteNotFound: + // log.Printf("[DEBUG] VPN policy does not exist %v", err) + // d.SetId("") + // return nil + // } + log.Printf("[DEBUG] delete VPN policy failed %v", err) + return diag.FromErr(err) + } + + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_ike_policy_test.go b/ibm/service/power/resource_ibm_pi_ike_policy_test.go new file mode 100644 index 000000000..4738d1473 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_ike_policy_test.go @@ -0,0 +1,128 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIIKEPolicyBasic(t *testing.T) { + policyRes := "ibm_pi_ike_policy.policy" + name := fmt.Sprintf("tf-pi-ike-policy-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIIKEPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIIKEPolicyConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIIKEPolicyExists(policyRes), + resource.TestCheckResourceAttr(policyRes, "pi_policy_name", name), + resource.TestCheckResourceAttrSet(policyRes, "policy_id"), + resource.TestCheckResourceAttr(policyRes, "pi_policy_authentication", "none"), + ), + }, + { + Config: testAccCheckIBMPIIKEPolicyAuthConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIIKEPolicyExists(policyRes), + resource.TestCheckResourceAttr(policyRes, "pi_policy_name", name), + resource.TestCheckResourceAttrSet(policyRes, "policy_id"), + resource.TestCheckResourceAttr(policyRes, "pi_policy_authentication", "sha1"), + ), + }, + }, + }) +} +func testAccCheckIBMPIIKEPolicyDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_ike_policy" { + continue + } + cloudInstanceID, policyID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnPolicyClient(context.Background(), sess, cloudInstanceID) + _, err = client.GetIKEPolicy(policyID) + if err == nil { + return fmt.Errorf("ike policy still exists: %s", rs.Primary.ID) + } + } + return nil +} +func testAccCheckIBMPIIKEPolicyExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, policyID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnPolicyClient(context.Background(), sess, cloudInstanceID) + + _, err = client.GetIKEPolicy(policyID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPIIKEPolicyConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_ike_policy" "policy" { + pi_cloud_instance_id = "%s" + pi_policy_name = "%s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_preshared_key = "sample" + pi_policy_version = 1 + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPIIKEPolicyAuthConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_ike_policy" "policy" { + pi_cloud_instance_id = "%s" + pi_policy_name = "%s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_preshared_key = "sample" + pi_policy_version = 1 + pi_policy_authentication = "sha1" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_image.go b/ibm/service/power/resource_ibm_pi_image.go new file mode 100644 index 000000000..3f83a8df2 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_image.go @@ -0,0 +1,395 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/errors" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_images" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPIImage() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIImageCreate, + ReadContext: resourceIBMPIImageRead, + DeleteContext: resourceIBMPIImageDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ForceNew: true, + }, + helpers.PIImageName: { + Type: schema.TypeString, + Required: true, + Description: "Image name", + DiffSuppressFunc: flex.ApplyOnce, + ForceNew: true, + }, + helpers.PIImageId: { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{helpers.PIImageId, helpers.PIImageBucketName}, + Description: "Instance image id", + DiffSuppressFunc: flex.ApplyOnce, + ConflictsWith: []string{helpers.PIImageBucketName}, + ForceNew: true, + }, + + // COS import variables + helpers.PIImageBucketName: { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{helpers.PIImageId, helpers.PIImageBucketName}, + Description: "Cloud Object Storage bucket name; bucket-name[/optional/folder]", + ConflictsWith: []string{helpers.PIImageId}, + RequiredWith: []string{helpers.PIImageBucketRegion, helpers.PIImageBucketFileName}, + ForceNew: true, + }, + helpers.PIImageBucketAccess: { + Type: schema.TypeString, + Optional: true, + Description: "Indicates if the bucket has public or private access", + Default: "public", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + ConflictsWith: []string{helpers.PIImageId}, + ForceNew: true, + }, + helpers.PIImageAccessKey: { + Type: schema.TypeString, + Optional: true, + Description: "Cloud Object Storage access key; required for buckets with private access", + ForceNew: true, + Sensitive: true, + RequiredWith: []string{helpers.PIImageSecretKey}, + }, + helpers.PIImageSecretKey: { + Type: schema.TypeString, + Optional: true, + Description: "Cloud Object Storage secret key; required for buckets with private access", + ForceNew: true, + Sensitive: true, + RequiredWith: []string{helpers.PIImageAccessKey}, + }, + helpers.PIImageBucketRegion: { + Type: schema.TypeString, + Optional: true, + Description: "Cloud Object Storage region", + ConflictsWith: []string{helpers.PIImageId}, + RequiredWith: []string{helpers.PIImageBucketName}, + ForceNew: true, + }, + helpers.PIImageBucketFileName: { + Type: schema.TypeString, + Optional: true, + Description: "Cloud Object Storage image filename", + ConflictsWith: []string{helpers.PIImageId}, + RequiredWith: []string{helpers.PIImageBucketName}, + ForceNew: true, + }, + helpers.PIImageStorageType: { + Type: schema.TypeString, + Optional: true, + Description: "Type of storage", + ForceNew: true, + }, + helpers.PIImageStoragePool: { + Type: schema.TypeString, + Optional: true, + Description: "Storage pool where the image will be loaded, if provided then pi_image_storage_type and pi_affinity_policy will be ignored", + ForceNew: true, + }, + PIAffinityPolicy: { + Type: schema.TypeString, + Optional: true, + Description: "Affinity policy for image; ignored if pi_image_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity"}), + ForceNew: true, + }, + PIAffinityVolume: { + Type: schema.TypeString, + Optional: true, + Description: "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + ConflictsWith: []string{PIAffinityInstance}, + ForceNew: true, + }, + PIAffinityInstance: { + Type: schema.TypeString, + Optional: true, + Description: "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", + ConflictsWith: []string{PIAffinityVolume}, + ForceNew: true, + }, + PIAntiAffinityVolumes: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + ConflictsWith: []string{PIAntiAffinityInstances}, + ForceNew: true, + }, + PIAntiAffinityInstances: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + ConflictsWith: []string{PIAntiAffinityVolumes}, + ForceNew: true, + }, + + // Computed Attribute + "image_id": { + Type: schema.TypeString, + Computed: true, + Description: "Image ID", + }, + }, + } +} + +func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + log.Printf("Failed to get the session") + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + imageName := d.Get(helpers.PIImageName).(string) + + client := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + // image copy + if v, ok := d.GetOk(helpers.PIImageId); ok { + imageid := v.(string) + source := "root-project" + var body = &models.CreateImage{ + ImageName: imageName, + ImageID: imageid, + Source: &source, + } + imageResponse, err := client.Create(body) + if err != nil { + return diag.FromErr(err) + } + + IBMPIImageID := imageResponse.ImageID + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *IBMPIImageID)) + + _, err = isWaitForIBMPIImageAvailable(ctx, client, *IBMPIImageID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + } + + // COS image import + if v, ok := d.GetOk(helpers.PIImageBucketName); ok { + bucketName := v.(string) + bucketImageFileName := d.Get(helpers.PIImageBucketFileName).(string) + bucketRegion := d.Get(helpers.PIImageBucketRegion).(string) + bucketAccess := d.Get(helpers.PIImageBucketAccess).(string) + + body := &models.CreateCosImageImportJob{ + ImageName: &imageName, + BucketName: &bucketName, + BucketAccess: &bucketAccess, + ImageFilename: &bucketImageFileName, + Region: &bucketRegion, + } + + if v, ok := d.GetOk(helpers.PIImageAccessKey); ok { + body.AccessKey = v.(string) + } + if v, ok := d.GetOk(helpers.PIImageSecretKey); ok { + body.SecretKey = v.(string) + } + + if v, ok := d.GetOk(helpers.PIImageStorageType); ok { + body.StorageType = v.(string) + } + if v, ok := d.GetOk(helpers.PIImageStoragePool); ok { + body.StoragePool = v.(string) + } + if ap, ok := d.GetOk(PIAffinityPolicy); ok { + policy := ap.(string) + affinity := &models.StorageAffinity{ + AffinityPolicy: &policy, + } + + if policy == "affinity" { + if av, ok := d.GetOk(PIAffinityVolume); ok { + afvol := av.(string) + affinity.AffinityVolume = &afvol + } + if ai, ok := d.GetOk(PIAffinityInstance); ok { + afins := ai.(string) + affinity.AffinityPVMInstance = &afins + } + } else { + if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { + afvols := flex.ExpandStringList(avs.([]interface{})) + affinity.AntiAffinityVolumes = afvols + } + if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { + afinss := flex.ExpandStringList(ais.([]interface{})) + affinity.AntiAffinityPVMInstances = afinss + } + } + body.StorageAffinity = affinity + } + imageResponse, err := client.CreateCosImage(body) + if err != nil { + return diag.FromErr(err) + } + + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *imageResponse.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + // Once the job is completed find by name + image, err := client.Get(imageName) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *image.ImageID)) + } + + return resourceIBMPIImageRead(ctx, d, meta) +} + +func resourceIBMPIImageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, imageID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + imageC := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imagedata, err := imageC.Get(imageID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_images.PcloudCloudinstancesImagesGetNotFound: + log.Printf("[DEBUG] image does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get image failed %v", err) + return diag.FromErr(err) + } + + imageid := *imagedata.ImageID + d.Set("image_id", imageid) + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + + return nil +} + +func resourceIBMPIImageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, imageID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + imageC := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + err = imageC.Delete(imageID) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func isWaitForIBMPIImageAvailable(ctx context.Context, client *st.IBMPIImageClient, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Power Image (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PIImageQueStatus}, + Target: []string{helpers.PIImageActiveStatus}, + Refresh: isIBMPIImageRefreshFunc(ctx, client, id), + Timeout: timeout, + Delay: 20 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIImageRefreshFunc(ctx context.Context, client *st.IBMPIImageClient, id string) resource.StateRefreshFunc { + + log.Printf("Calling the isIBMPIImageRefreshFunc Refresh Function....") + return func() (interface{}, string, error) { + image, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if image.State == "active" { + return image, helpers.PIImageActiveStatus, nil + } + + return image, helpers.PIImageQueStatus, nil + } +} + +func waitForIBMPIJobCompleted(ctx context.Context, client *st.IBMPIJobClient, jobID string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{helpers.JobStatusQueued, helpers.JobStatusReadyForProcessing, helpers.JobStatusInProgress, helpers.JobStatusRunning, helpers.JobStatusWaiting}, + Target: []string{helpers.JobStatusCompleted, helpers.JobStatusFailed}, + Refresh: func() (interface{}, string, error) { + job, err := client.Get(jobID) + if err != nil { + log.Printf("[DEBUG] get job failed %v", err) + return nil, "", fmt.Errorf(errors.GetJobOperationFailed, jobID, err) + } + if job == nil || job.Status == nil { + log.Printf("[DEBUG] get job failed with empty response") + return nil, "", fmt.Errorf("failed to get job status for job id %s", jobID) + } + if *job.Status.State == helpers.JobStatusFailed { + log.Printf("[DEBUG] job status failed with message: %v", job.Status.Message) + return nil, helpers.JobStatusFailed, fmt.Errorf("job status failed for job id %s with message: %v", jobID, job.Status.Message) + } + return job, *job.Status.State, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForStateContext(ctx) +} diff --git a/ibm/service/power/resource_ibm_pi_image_export.go b/ibm/service/power/resource_ibm_pi_image_export.go new file mode 100644 index 000000000..ed3df33d6 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_image_export.go @@ -0,0 +1,121 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func ResourceIBMPIImageExport() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIImageExportCreate, + ReadContext: resourceIBMPIImageExportRead, + DeleteContext: resourceIBMPIImageExportDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + //required attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + ForceNew: true, + }, + helpers.PIImageId: { + Type: schema.TypeString, + Required: true, + Description: "Instance image id", + DiffSuppressFunc: flex.ApplyOnce, + ForceNew: true, + }, + helpers.PIImageBucketName: { + Type: schema.TypeString, + Required: true, + Description: "Cloud Object Storage bucket name; bucket-name[/optional/folder]", + ForceNew: true, + }, + helpers.PIImageAccessKey: { + Type: schema.TypeString, + Required: true, + Description: "Cloud Object Storage access key; required for buckets with private access", + Sensitive: true, + ForceNew: true, + }, + + helpers.PIImageSecretKey: { + Type: schema.TypeString, + Required: true, + Description: "Cloud Object Storage secret key; required for buckets with private access", + Sensitive: true, + ForceNew: true, + }, + helpers.PIImageBucketRegion: { + Type: schema.TypeString, + Description: "Cloud Object Storage region", + ForceNew: true, + Required: true, + }, + }, + } +} + +func resourceIBMPIImageExportCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + log.Printf("Failed to get the session") + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + imageid := d.Get(helpers.PIImageId).(string) + bucketName := d.Get(helpers.PIImageBucketName).(string) + accessKey := d.Get(helpers.PIImageAccessKey).(string) + + client := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + + // image export + var body = &models.ExportImage{ + BucketName: &bucketName, + AccessKey: &accessKey, + Region: d.Get(helpers.PIImageBucketRegion).(string), + SecretKey: d.Get(helpers.PIImageSecretKey).(string), + } + + imageResponse, err := client.ExportImage(imageid, body) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%s/%s/%s", imageid, bucketName, d.Get(helpers.PIImageBucketRegion).(string))) + + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *imageResponse.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func resourceIBMPIImageExportRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func resourceIBMPIImageExportDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_image_export_test.go b/ibm/service/power/resource_ibm_pi_image_export_test.go new file mode 100644 index 000000000..82def95b3 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_image_export_test.go @@ -0,0 +1,44 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIImageEport(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIImageExportConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("ibm_pi_image_export.power_image_export", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIImageExportConfig() string { + return fmt.Sprintf(` + data "ibm_pi_image" "power_image" { + pi_image_name = "%[6]s" + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_image_export" "power_image_export" { + pi_image_id = data.ibm_pi_image.power_image.id + pi_cloud_instance_id = "%[1]s" + pi_image_bucket_name = "%[2]s" + pi_image_access_key = "%[3]s" + pi_image_secret_key = "%[4]s" + pi_image_bucket_region = "%[5]s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_image_bucket_name, acc.Pi_image_bucket_access_key, acc.Pi_image_bucket_secret_key, acc.Pi_image_bucket_region, acc.Pi_image) +} diff --git a/ibm/service/power/resource_ibm_pi_image_test.go b/ibm/service/power/resource_ibm_pi_image_test.go new file mode 100644 index 000000000..20c7ff074 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_image_test.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIImagebasic(t *testing.T) { + + name := fmt.Sprintf("tf-pi-image-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIImageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIImageConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIImageExists("ibm_pi_image.power_image"), + resource.TestCheckResourceAttr( + "ibm_pi_image.power_image", "pi_image_name", name), + ), + }, + }, + }) +} + +func testAccCheckIBMPIImageDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_image" { + continue + } + cloudInstanceID, imageID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + imageC := st.NewIBMPIImageClient(context.Background(), sess, cloudInstanceID) + _, err = imageC.Get(imageID) + if err == nil { + return fmt.Errorf("PI Image still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIImageExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, imageID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIImageClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(imageID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPIImageConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_image" "power_image" { + pi_image_name = "%s" + pi_image_id = "IBMi-74-01-001" + pi_cloud_instance_id = "%s" + } + `, name, acc.Pi_cloud_instance_id) +} + +func TestAccIBMPIImageCOSPublicImport(t *testing.T) { + imageRes := "ibm_pi_image.cos_image" + name := fmt.Sprintf("tf-pi-image-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIImageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIImageCOSPublicConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIImageExists(imageRes), + resource.TestCheckResourceAttr(imageRes, "pi_image_name", name), + resource.TestCheckResourceAttrSet(imageRes, "image_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIImageCOSPublicConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_image" "cos_image" { + pi_image_name = "%[1]s" + pi_cloud_instance_id = "%[2]s" + pi_image_bucket_name = "%[3]s" + pi_image_bucket_access = "public" + pi_image_bucket_region = "us-south" + pi_image_bucket_file_name = "%[4]s" + pi_image_storage_type = "tier1" + } + `, name, acc.Pi_cloud_instance_id, acc.Pi_image_bucket_name, acc.Pi_image_bucket_file_name) +} diff --git a/ibm/service/power/resource_ibm_pi_instance.go b/ibm/service/power/resource_ibm_pi_instance.go new file mode 100644 index 000000000..2e4ce15fa --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -0,0 +1,1329 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "encoding/base64" + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPIInstance() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIInstanceCreate, + ReadContext: resourceIBMPIInstanceRead, + UpdateContext: resourceIBMPIInstanceUpdate, + DeleteContext: resourceIBMPIInstanceDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(120 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "This is the Power Instance id that is assigned to the account", + }, + helpers.PIInstanceLicenseRepositoryCapacity: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The VTL license repository capacity TB value", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "PI instance status", + }, + "pi_migratable": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "set to true to enable migration of the PI instance", + }, + "min_processors": { + Type: schema.TypeFloat, + Computed: true, + Description: "Minimum number of the CPUs", + }, + "min_memory": { + Type: schema.TypeFloat, + Computed: true, + Description: "Minimum memory", + }, + "max_processors": { + Type: schema.TypeFloat, + Computed: true, + Description: "Maximum number of processors", + }, + "max_memory": { + Type: schema.TypeFloat, + Computed: true, + Description: "Maximum memory size", + }, + helpers.PIInstanceVolumeIds: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of PI volumes", + }, + + helpers.PIInstanceUserData: { + Type: schema.TypeString, + Optional: true, + Description: "Base64 encoded data to be passed in for invoking a cloud init script", + }, + + helpers.PIInstanceStorageType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Storage type for server deployment", + }, + PIInstanceStoragePool: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Storage Pool for server deployment; if provided then pi_affinity_policy and pi_storage_type will be ignored", + }, + PIAffinityPolicy: { + Type: schema.TypeString, + Optional: true, + Description: "Affinity policy for pvm instance being created; ignored if pi_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity"}), + }, + PIAffinityVolume: { + Type: schema.TypeString, + Optional: true, + Description: "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + ConflictsWith: []string{PIAffinityInstance}, + }, + PIAffinityInstance: { + Type: schema.TypeString, + Optional: true, + Description: "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", + ConflictsWith: []string{PIAffinityVolume}, + }, + PIAntiAffinityVolumes: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + ConflictsWith: []string{PIAntiAffinityInstances}, + }, + PIAntiAffinityInstances: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + ConflictsWith: []string{PIAntiAffinityVolumes}, + }, + helpers.PIInstanceStorageConnection: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"vSCSI"}), + Description: "Storage Connectivity Group for server deployment", + }, + PIInstanceStoragePoolAffinity: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates if all volumes attached to the server must reside in the same storage pool", + }, + PIInstanceNetwork: { + Type: schema.TypeList, + Required: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of one or more networks to attach to the instance", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_address": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "mac_address": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Required: true, + }, + "network_name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "external_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + helpers.PIPlacementGroupID: { + Type: schema.TypeString, + Optional: true, + Description: "Placement group ID", + }, + Arg_PIInstanceSharedProcessorPool: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{PISAPInstanceProfileID}, + Description: "Shared Processor Pool the instance is deployed on", + }, + Attr_PIInstanceSharedProcessorPoolID: { + Type: schema.TypeString, + Computed: true, + Description: "Shared Processor Pool ID the instance is deployed on", + }, + "health_status": { + Type: schema.TypeString, + Computed: true, + Description: "PI Instance health status", + }, + "instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance ID", + }, + "pin_policy": { + Type: schema.TypeString, + Computed: true, + Description: "PIN Policy of the Instance", + }, + helpers.PIInstanceImageId: { + Type: schema.TypeString, + Required: true, + Description: "PI instance image id", + DiffSuppressFunc: flex.ApplyOnce, + }, + helpers.PIInstanceProcessors: { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + ConflictsWith: []string{PISAPInstanceProfileID}, + Description: "Processors count", + }, + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "PI Instance name", + }, + helpers.PIInstanceProcType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"dedicated", "shared", "capped"}), + ConflictsWith: []string{PISAPInstanceProfileID}, + Description: "Instance processor type", + }, + helpers.PIInstanceSSHKeyName: { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "SSH key name", + }, + helpers.PIInstanceMemory: { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + ConflictsWith: []string{PISAPInstanceProfileID}, + Description: "Memory size", + }, + PIInstanceDeploymentType: { + Type: schema.TypeString, + Optional: true, + Description: "Custom Deployment Type Information", + }, + PISAPInstanceProfileID: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{helpers.PIInstanceProcessors, helpers.PIInstanceMemory, helpers.PIInstanceProcType}, + Description: "SAP Profile ID for the amount of cores and memory", + }, + PISAPInstanceDeploymentType: { + Type: schema.TypeString, + Optional: true, + Description: "Custom SAP Deployment Type Information", + }, + helpers.PIInstanceSystemType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "PI Instance system type", + }, + helpers.PIInstanceReplicants: { + Type: schema.TypeInt, + Optional: true, + Default: 1, + Description: "PI Instance replicas count", + }, + helpers.PIInstanceReplicationPolicy: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity", "none"}), + Default: "none", + Description: "Replication policy for the PI Instance", + }, + helpers.PIInstanceReplicationScheme: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"prefix", "suffix"}), + Default: "suffix", + Description: "Replication scheme", + }, + helpers.PIInstanceProgress: { + Type: schema.TypeFloat, + Computed: true, + Description: "Progress of the operation", + }, + helpers.PIInstancePinPolicy: { + Type: schema.TypeString, + Optional: true, + Description: "Pin Policy of the instance", + Default: "none", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"none", "soft", "hard"}), + }, + + // "reboot_for_resource_change": { + // Type: schema.TypeString, + // Optional: true, + // Description: "Flag to be passed for CPU/Memory changes that require a reboot to take effect", + // }, + "operating_system": { + Type: schema.TypeString, + Computed: true, + Description: "Operating System", + }, + "os_type": { + Type: schema.TypeString, + Computed: true, + Description: "OS Type", + }, + helpers.PIInstanceHealthStatus: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{helpers.PIInstanceHealthOk, helpers.PIInstanceHealthWarning}), + Default: "OK", + Description: "Allow the user to set the status of the lpar so that they can connect to it faster", + }, + helpers.PIVirtualCoresAssigned: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Virtual Cores Assigned to the PVMInstance", + }, + "max_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum Virtual Cores Assigned to the PVMInstance", + }, + "min_virtual_cores": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum Virtual Cores Assigned to the PVMInstance", + }, + }, + } +} + +func resourceIBMPIInstanceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("Now in the PowerVMCreate") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + sapClient := st.NewIBMPISAPInstanceClient(ctx, sess, cloudInstanceID) + imageClient := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + + var pvmList *models.PVMInstanceList + if _, ok := d.GetOk(PISAPInstanceProfileID); ok { + pvmList, err = createSAPInstance(d, sapClient) + } else { + pvmList, err = createPVMInstance(d, client, imageClient) + } + if err != nil { + return diag.FromErr(err) + } + + var instanceReadyStatus string + if r, ok := d.GetOk(helpers.PIInstanceHealthStatus); ok { + instanceReadyStatus = r.(string) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *(*pvmList)[0].PvmInstanceID)) + + for _, s := range *pvmList { + _, err = isWaitForPIInstanceAvailable(ctx, client, *s.PvmInstanceID, instanceReadyStatus) + if err != nil { + return diag.FromErr(err) + } + } + + // If Storage Pool Affinity is given as false we need to update the vm instance. + // Default value is true which indicates that all volumes attached to the server + // must reside in the same storage pool. + storagePoolAffinity := d.Get(PIInstanceStoragePoolAffinity).(bool) + if !storagePoolAffinity { + for _, s := range *pvmList { + body := &models.PVMInstanceUpdate{ + StoragePoolAffinity: &storagePoolAffinity, + } + // This is a synchronous process hence no need to check for health status + _, err = client.Update(*s.PvmInstanceID, body) + if err != nil { + return diag.FromErr(err) + } + } + } + + return resourceIBMPIInstanceRead(ctx, d, meta) + +} + +func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, instanceID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + powervmdata, err := client.Get(instanceID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(helpers.PIInstanceMemory, powervmdata.Memory) + d.Set(helpers.PIInstanceProcessors, powervmdata.Processors) + if powervmdata.Status != nil { + d.Set("status", powervmdata.Status) + } + d.Set(helpers.PIInstanceProcType, powervmdata.ProcType) + if powervmdata.Migratable != nil { + d.Set("pi_migratable", powervmdata.Migratable) + } + d.Set("min_processors", powervmdata.Minproc) + d.Set(helpers.PIInstanceProgress, powervmdata.Progress) + if powervmdata.StorageType != nil { + d.Set(helpers.PIInstanceStorageType, powervmdata.StorageType) + } + d.Set(PIInstanceStoragePool, powervmdata.StoragePool) + d.Set(PIInstanceStoragePoolAffinity, powervmdata.StoragePoolAffinity) + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + d.Set("instance_id", powervmdata.PvmInstanceID) + d.Set(helpers.PIInstanceName, powervmdata.ServerName) + d.Set(helpers.PIInstanceImageId, powervmdata.ImageID) + if *powervmdata.PlacementGroup != "none" { + d.Set(helpers.PIPlacementGroupID, powervmdata.PlacementGroup) + } + d.Set(Arg_PIInstanceSharedProcessorPool, powervmdata.SharedProcessorPool) + d.Set(Attr_PIInstanceSharedProcessorPoolID, powervmdata.SharedProcessorPoolID) + + networksMap := []map[string]interface{}{} + if powervmdata.Networks != nil { + for _, n := range powervmdata.Networks { + if n != nil { + v := map[string]interface{}{ + "ip_address": n.IPAddress, + "mac_address": n.MacAddress, + "network_id": n.NetworkID, + "network_name": n.NetworkName, + "type": n.Type, + "external_ip": n.ExternalIP, + } + networksMap = append(networksMap, v) + } + } + } + d.Set(PIInstanceNetwork, networksMap) + + if powervmdata.SapProfile != nil && powervmdata.SapProfile.ProfileID != nil { + d.Set(PISAPInstanceProfileID, powervmdata.SapProfile.ProfileID) + } + d.Set(helpers.PIInstanceSystemType, powervmdata.SysType) + d.Set("min_memory", powervmdata.Minmem) + d.Set("max_processors", powervmdata.Maxproc) + d.Set("max_memory", powervmdata.Maxmem) + d.Set("pin_policy", powervmdata.PinPolicy) + d.Set("operating_system", powervmdata.OperatingSystem) + if powervmdata.OsType != nil { + d.Set("os_type", powervmdata.OsType) + } + + if powervmdata.Health != nil { + d.Set("health_status", powervmdata.Health.Status) + } + if powervmdata.VirtualCores != nil { + d.Set(helpers.PIVirtualCoresAssigned, powervmdata.VirtualCores.Assigned) + d.Set("max_virtual_cores", powervmdata.VirtualCores.Max) + d.Set("min_virtual_cores", powervmdata.VirtualCores.Min) + } + d.Set(helpers.PIInstanceLicenseRepositoryCapacity, powervmdata.LicenseRepositoryCapacity) + d.Set(PIInstanceDeploymentType, powervmdata.DeploymentType) + return nil +} + +func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + name := d.Get(helpers.PIInstanceName).(string) + mem := d.Get(helpers.PIInstanceMemory).(float64) + procs := d.Get(helpers.PIInstanceProcessors).(float64) + processortype := d.Get(helpers.PIInstanceProcType).(string) + assignedVirtualCores := int64(d.Get(helpers.PIVirtualCoresAssigned).(int)) + + if d.Get("health_status") == "WARNING" { + return diag.Errorf("the operation cannot be performed when the lpar health in the WARNING State") + } + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.Errorf("failed to get the session from the IBM Cloud Service") + } + + cloudInstanceID, instanceID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + // Check if cloud instance is capable of changing virtual cores + cloudInstanceClient := st.NewIBMPICloudInstanceClient(ctx, sess, cloudInstanceID) + cloudInstance, err := cloudInstanceClient.Get(cloudInstanceID) + if err != nil { + return diag.FromErr(err) + } + cores_enabled := checkCloudInstanceCapability(cloudInstance, CUSTOM_VIRTUAL_CORES) + + if d.HasChange(helpers.PIInstanceName) { + body := &models.PVMInstanceUpdate{ + ServerName: name, + } + _, err = client.Update(instanceID, body) + if err != nil { + return diag.Errorf("failed to update the lpar with the change for name: %v", err) + } + _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") + if err != nil { + return diag.FromErr(err) + } + } + + if d.HasChange(helpers.PIInstanceProcType) { + + // Stop the lpar + if d.Get("status") == "SHUTOFF" { + log.Printf("the lpar is in the shutoff state. Nothing to do . Moving on ") + } else { + err := stopLparForResourceChange(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + } + + // Modify + log.Printf("At this point the lpar should be off. Executing the Processor Update Change") + updatebody := &models.PVMInstanceUpdate{ProcType: processortype} + if cores_enabled { + log.Printf("support for %s is enabled", CUSTOM_VIRTUAL_CORES) + updatebody.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} + } else { + log.Printf("no virtual cores support enabled for this customer..") + } + _, err = client.Update(instanceID, updatebody) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForPIInstanceStopped(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + + // Start the lpar + err := startLparAfterResourceChange(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + } + + // Virtual core will be updated only if service instance capability is enabled + if d.HasChange(helpers.PIVirtualCoresAssigned) { + body := &models.PVMInstanceUpdate{ + VirtualCores: &models.VirtualCores{Assigned: &assignedVirtualCores}, + } + _, err = client.Update(instanceID, body) + if err != nil { + return diag.Errorf("failed to update the lpar with the change for virtual cores: %v", err) + } + _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") + if err != nil { + return diag.FromErr(err) + } + } + + // Start of the change for Memory and Processors + if d.HasChange(helpers.PIInstanceMemory) || d.HasChange(helpers.PIInstanceProcessors) || d.HasChange("pi_migratable") { + + maxMemLpar := d.Get("max_memory").(float64) + maxCPULpar := d.Get("max_processors").(float64) + //log.Printf("the required memory is set to [%d] and current max memory is set to [%d] ", int(mem), int(maxMemLpar)) + + if mem > maxMemLpar || procs > maxCPULpar { + log.Printf("Will require a shutdown to perform the change") + } else { + log.Printf("maxMemLpar is set to %f", maxMemLpar) + log.Printf("maxCPULpar is set to %f", maxCPULpar) + } + + //if d.GetOkExists("reboot_for_resource_change") + + if mem > maxMemLpar || procs > maxCPULpar { + + err = performChangeAndReboot(ctx, client, instanceID, cloudInstanceID, mem, procs) + if err != nil { + return diag.FromErr(err) + } + + } else { + + body := &models.PVMInstanceUpdate{ + Memory: mem, + Processors: procs, + } + if m, ok := d.GetOk("pi_migratable"); ok { + migratable := m.(bool) + body.Migratable = &migratable + } + if cores_enabled { + log.Printf("support for %s is enabled", CUSTOM_VIRTUAL_CORES) + body.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} + } else { + log.Printf("no virtual cores support enabled for this customer..") + } + + _, err = client.Update(instanceID, body) + if err != nil { + return diag.Errorf("failed to update the lpar with the change %v", err) + } + _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") + if err != nil { + return diag.FromErr(err) + } + } + } + + // License repository capacity will be updated only if service instance is a vtl instance + // might need to check if lrc was set + if d.HasChange(helpers.PIInstanceLicenseRepositoryCapacity) { + + lrc := d.Get(helpers.PIInstanceLicenseRepositoryCapacity).(int64) + body := &models.PVMInstanceUpdate{ + LicenseRepositoryCapacity: lrc, + } + _, err = client.Update(instanceID, body) + if err != nil { + return diag.Errorf("failed to update the lpar with the change for license repository capacity %s", err) + } + _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") + if err != nil { + diag.FromErr(err) + } + } + + if d.HasChange(PISAPInstanceProfileID) { + // Stop the lpar + if d.Get("status") == "SHUTOFF" { + log.Printf("the lpar is in the shutoff state. Nothing to do... Moving on ") + } else { + err := stopLparForResourceChange(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + } + + // Update the profile id + profileID := d.Get(PISAPInstanceProfileID).(string) + body := &models.PVMInstanceUpdate{ + SapProfileID: profileID, + } + _, err = client.Update(instanceID, body) + if err != nil { + return diag.Errorf("failed to update the lpar with the change for sap profile: %v", err) + } + + // Wait for the resize to complete and status to reset + _, err = isWaitForPIInstanceStopped(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + + // Start the lpar + err := startLparAfterResourceChange(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + } + if d.HasChange(PIInstanceStoragePoolAffinity) { + storagePoolAffinity := d.Get(PIInstanceStoragePoolAffinity).(bool) + body := &models.PVMInstanceUpdate{ + StoragePoolAffinity: &storagePoolAffinity, + } + // This is a synchronous process hence no need to check for health status + _, err = client.Update(instanceID, body) + if err != nil { + return diag.FromErr(err) + } + } + + if d.HasChange(helpers.PIPlacementGroupID) { + + pgClient := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + + oldRaw, newRaw := d.GetChange(helpers.PIPlacementGroupID) + old := oldRaw.(string) + new := newRaw.(string) + + if len(strings.TrimSpace(old)) > 0 { + placementGroupID := old + //remove server from old placement group + body := &models.PlacementGroupServer{ + ID: &instanceID, + } + _, err := pgClient.DeleteMember(placementGroupID, body) + if err != nil { + // ignore delete member error where the server is already not in the PG + if !strings.Contains(err.Error(), "is not part of placement-group") { + return diag.FromErr(err) + } + } + } + + if len(strings.TrimSpace(new)) > 0 { + placementGroupID := new + // add server to a new placement group + body := &models.PlacementGroupServer{ + ID: &instanceID, + } + _, err := pgClient.AddMember(placementGroupID, body) + if err != nil { + return diag.FromErr(err) + } + } + } + + return resourceIBMPIInstanceRead(ctx, d, meta) + +} + +func resourceIBMPIInstanceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, instanceID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + err = client.Delete(instanceID) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceDeleted(ctx, client, instanceID) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func isWaitForPIInstanceDeleted(ctx context.Context, client *st.IBMPIInstanceClient, id string) (interface{}, error) { + + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PIInstanceDeleting}, + Target: []string{helpers.PIInstanceNotFound}, + Refresh: isPIInstanceDeleteRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + Timeout: 10 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceDeleteRefreshFunc(client *st.IBMPIInstanceClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + pvm, err := client.Get(id) + if err != nil { + log.Printf("The power vm does not exist") + return pvm, helpers.PIInstanceNotFound, nil + } + return pvm, helpers.PIInstanceDeleting, nil + } +} + +func isWaitForPIInstanceAvailable(ctx context.Context, client *st.IBMPIInstanceClient, id string, instanceReadyStatus string) (interface{}, error) { + log.Printf("Waiting for PIInstance (%s) to be available and active ", id) + + queryTimeOut := activeTimeOut + if instanceReadyStatus == helpers.PIInstanceHealthWarning { + queryTimeOut = warningTimeOut + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING", helpers.PIInstanceBuilding, helpers.PIInstanceHealthWarning}, + Target: []string{helpers.PIInstanceAvailable, helpers.PIInstanceHealthOk, "ERROR", ""}, + Refresh: isPIInstanceRefreshFunc(client, id, instanceReadyStatus), + Delay: 30 * time.Second, + MinTimeout: queryTimeOut, + Timeout: 120 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceRefreshFunc(client *st.IBMPIInstanceClient, id, instanceReadyStatus string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + // Check for `instanceReadyStatus` health status and also the final health status "OK" + if *pvm.Status == helpers.PIInstanceAvailable && (pvm.Health.Status == instanceReadyStatus || pvm.Health.Status == helpers.PIInstanceHealthOk) { + return pvm, helpers.PIInstanceAvailable, nil + } + if *pvm.Status == "ERROR" { + if pvm.Fault != nil { + err = fmt.Errorf("failed to create the lpar: %s", pvm.Fault.Message) + } else { + err = fmt.Errorf("failed to create the lpar") + } + return pvm, *pvm.Status, err + } + + return pvm, helpers.PIInstanceBuilding, nil + } +} + +func checkBase64(input string) error { + _, err := base64.StdEncoding.DecodeString(input) + if err != nil { + return fmt.Errorf("failed to check if input is base64 %s", err) + } + return err +} + +func isWaitForPIInstanceStopped(ctx context.Context, client *st.IBMPIInstanceClient, id string) (interface{}, error) { + log.Printf("Waiting for PIInstance (%s) to be stopped and powered off ", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"STOPPING", "RESIZE", "VERIFY_RESIZE", helpers.PIInstanceHealthWarning}, + Target: []string{"OK", "SHUTOFF"}, + Refresh: isPIInstanceRefreshFuncOff(client, id), + Delay: 10 * time.Second, + MinTimeout: 2 * time.Minute, // This is the time that the client will execute to check the status of the request + Timeout: 30 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceRefreshFuncOff(client *st.IBMPIInstanceClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + log.Printf("Calling the check Refresh status of the pvm instance %s", id) + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + if *pvm.Status == "SHUTOFF" && pvm.Health.Status == helpers.PIInstanceHealthOk { + return pvm, "SHUTOFF", nil + } + return pvm, "STOPPING", nil + } +} + +func stopLparForResourceChange(ctx context.Context, client *st.IBMPIInstanceClient, id string) error { + body := &models.PVMInstanceAction{ + //Action: flex.PtrToString("stop"), + Action: flex.PtrToString("immediate-shutdown"), + } + err := client.Action(id, body) + if err != nil { + return fmt.Errorf("failed to perform the stop action on the pvm instance %v", err) + } + + _, err = isWaitForPIInstanceStopped(ctx, client, id) + + return err +} + +// Start the lpar + +func startLparAfterResourceChange(ctx context.Context, client *st.IBMPIInstanceClient, id string) error { + body := &models.PVMInstanceAction{ + Action: flex.PtrToString("start"), + } + err := client.Action(id, body) + if err != nil { + return fmt.Errorf("failed to perform the start action on the pvm instance %v", err) + } + + _, err = isWaitForPIInstanceAvailable(ctx, client, id, "OK") + + return err +} + +// Stop / Modify / Start only when the lpar is off limits + +func performChangeAndReboot(ctx context.Context, client *st.IBMPIInstanceClient, id, cloudInstanceID string, mem, procs float64) error { + /* + These are the steps + 1. Stop the lpar - Check if the lpar is SHUTOFF + 2. Once the lpar is SHUTOFF - Make the cpu / memory change - DUring this time , you can check for RESIZE and VERIFY_RESIZE as the transition states + 3. If the change is successful , the lpar state will be back in SHUTOFF + 4. Once the LPAR state is SHUTOFF , initiate the start again and check for ACTIVE + OK + */ + //Execute the stop + + log.Printf("Calling the stop lpar for Resource Change code ..") + err := stopLparForResourceChange(ctx, client, id) + if err != nil { + return err + } + + body := &models.PVMInstanceUpdate{ + Memory: mem, + Processors: procs, + } + + _, updateErr := client.Update(id, body) + if updateErr != nil { + return fmt.Errorf("failed to update the lpar with the change, %s", updateErr) + } + + _, err = isWaitforPIInstanceUpdate(ctx, client, id) + if err != nil { + return fmt.Errorf("failed to get an update from the Service after the resource change, %s", err) + } + + // Now we can start the lpar + log.Printf("Calling the start lpar After the Resource Change code ..") + err = startLparAfterResourceChange(ctx, client, id) + if err != nil { + return err + } + + return nil + +} + +func isWaitforPIInstanceUpdate(ctx context.Context, client *st.IBMPIInstanceClient, id string) (interface{}, error) { + log.Printf("Waiting for PIInstance (%s) to be SHUTOFF AFTER THE RESIZE Due to DLPAR Operation ", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"RESIZE", "VERIFY_RESIZE"}, + Target: []string{"ACTIVE", "SHUTOFF", helpers.PIInstanceHealthOk}, + Refresh: isPIInstanceShutAfterResourceChange(client, id), + Delay: 10 * time.Second, + MinTimeout: 5 * time.Minute, + Timeout: 60 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceShutAfterResourceChange(client *st.IBMPIInstanceClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if *pvm.Status == "SHUTOFF" && pvm.Health.Status == helpers.PIInstanceHealthOk { + log.Printf("The lpar is now off after the resource change...") + return pvm, "SHUTOFF", nil + } + + return pvm, "RESIZE", nil + } +} + +func expandPVMNetworks(networks []interface{}) []*models.PVMInstanceAddNetwork { + pvmNetworks := make([]*models.PVMInstanceAddNetwork, 0, len(networks)) + for _, v := range networks { + network := v.(map[string]interface{}) + pvmInstanceNetwork := &models.PVMInstanceAddNetwork{ + IPAddress: network["ip_address"].(string), + NetworkID: flex.PtrToString(network["network_id"].(string)), + } + pvmNetworks = append(pvmNetworks, pvmInstanceNetwork) + } + return pvmNetworks +} + +func checkCloudInstanceCapability(cloudInstance *models.CloudInstance, custom_capability string) bool { + log.Printf("Checking for the following capability %s", custom_capability) + log.Printf("the instance features are %s", cloudInstance.Capabilities) + for _, v := range cloudInstance.Capabilities { + if v == custom_capability { + return true + } + } + return false +} + +func createSAPInstance(d *schema.ResourceData, sapClient *st.IBMPISAPInstanceClient) (*models.PVMInstanceList, error) { + + name := d.Get(helpers.PIInstanceName).(string) + profileID := d.Get(PISAPInstanceProfileID).(string) + imageid := d.Get(helpers.PIInstanceImageId).(string) + + pvmNetworks := expandPVMNetworks(d.Get(PIInstanceNetwork).([]interface{})) + + var replicants int64 + if r, ok := d.GetOk(helpers.PIInstanceReplicants); ok { + replicants = int64(r.(int)) + } + var replicationpolicy string + if r, ok := d.GetOk(helpers.PIInstanceReplicationPolicy); ok { + replicationpolicy = r.(string) + } + var replicationNamingScheme string + if r, ok := d.GetOk(helpers.PIInstanceReplicationScheme); ok { + replicationNamingScheme = r.(string) + } + instances := &models.PVMInstanceMultiCreate{ + AffinityPolicy: &replicationpolicy, + Count: replicants, + Numerical: &replicationNamingScheme, + } + + body := &models.SAPCreate{ + ImageID: &imageid, + Instances: instances, + Name: &name, + Networks: pvmNetworks, + ProfileID: &profileID, + } + + if v, ok := d.GetOk(PISAPInstanceDeploymentType); ok { + body.DeploymentType = v.(string) + } + if v, ok := d.GetOk(helpers.PIInstanceVolumeIds); ok { + volids := flex.ExpandStringList((v.(*schema.Set)).List()) + if len(volids) > 0 { + body.VolumeIDs = volids + } + } + if p, ok := d.GetOk(helpers.PIInstancePinPolicy); ok { + pinpolicy := p.(string) + if d.Get(helpers.PIInstancePinPolicy) == "soft" || d.Get(helpers.PIInstancePinPolicy) == "hard" { + body.PinPolicy = models.PinPolicy(pinpolicy) + } + } + + if v, ok := d.GetOk(helpers.PIInstanceSSHKeyName); ok { + sshkey := v.(string) + body.SSHKeyName = sshkey + } + if u, ok := d.GetOk(helpers.PIInstanceUserData); ok { + userData := u.(string) + err := checkBase64(userData) + if err != nil { + log.Printf("Data is not base64 encoded") + return nil, err + } + body.UserData = userData + } + if sys, ok := d.GetOk(helpers.PIInstanceSystemType); ok { + body.SysType = sys.(string) + } + + if st, ok := d.GetOk(helpers.PIInstanceStorageType); ok { + body.StorageType = st.(string) + } + if sp, ok := d.GetOk(PIInstanceStoragePool); ok { + body.StoragePool = sp.(string) + } + + if ap, ok := d.GetOk(PIAffinityPolicy); ok { + policy := ap.(string) + affinity := &models.StorageAffinity{ + AffinityPolicy: &policy, + } + + if policy == "affinity" { + if av, ok := d.GetOk(PIAffinityVolume); ok { + afvol := av.(string) + affinity.AffinityVolume = &afvol + } + if ai, ok := d.GetOk(PIAffinityInstance); ok { + afins := ai.(string) + affinity.AffinityPVMInstance = &afins + } + } else { + if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { + afvols := flex.ExpandStringList(avs.([]interface{})) + affinity.AntiAffinityVolumes = afvols + } + if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { + afinss := flex.ExpandStringList(ais.([]interface{})) + affinity.AntiAffinityPVMInstances = afinss + } + } + body.StorageAffinity = affinity + } + + if pg, ok := d.GetOk(helpers.PIPlacementGroupID); ok { + body.PlacementGroup = pg.(string) + } + + pvmList, err := sapClient.Create(body) + if err != nil { + return nil, fmt.Errorf("failed to provision: %v", err) + } + if pvmList == nil { + return nil, fmt.Errorf("failed to provision") + } + + return pvmList, nil +} + +func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, imageClient *st.IBMPIImageClient) (*models.PVMInstanceList, error) { + + name := d.Get(helpers.PIInstanceName).(string) + imageid := d.Get(helpers.PIInstanceImageId).(string) + + var mem, procs float64 + var systype, processortype string + if v, ok := d.GetOk(helpers.PIInstanceMemory); ok { + mem = v.(float64) + } else { + return nil, fmt.Errorf("%s is required for creating pvm instances", helpers.PIInstanceMemory) + } + if v, ok := d.GetOk(helpers.PIInstanceProcessors); ok { + procs = v.(float64) + } else { + return nil, fmt.Errorf("%s is required for creating pvm instances", helpers.PIInstanceProcessors) + } + if v, ok := d.GetOk(helpers.PIInstanceSystemType); ok { + systype = v.(string) + } else { + return nil, fmt.Errorf("%s is required for creating pvm instances", helpers.PIInstanceSystemType) + } + if v, ok := d.GetOk(helpers.PIInstanceProcType); ok { + processortype = v.(string) + } else { + return nil, fmt.Errorf("%s is required for creating pvm instances", helpers.PIInstanceProcType) + } + + pvmNetworks := expandPVMNetworks(d.Get(PIInstanceNetwork).([]interface{})) + + var volids []string + if v, ok := d.GetOk(helpers.PIInstanceVolumeIds); ok { + volids = flex.ExpandStringList((v.(*schema.Set)).List()) + } + var replicants float64 + if r, ok := d.GetOk(helpers.PIInstanceReplicants); ok { + replicants = float64(r.(int)) + } + var replicationpolicy string + if r, ok := d.GetOk(helpers.PIInstanceReplicationPolicy); ok { + replicationpolicy = r.(string) + } + var replicationNamingScheme string + if r, ok := d.GetOk(helpers.PIInstanceReplicationScheme); ok { + replicationNamingScheme = r.(string) + } + var migratable bool + if m, ok := d.GetOk("pi_migratable"); ok { + migratable = m.(bool) + } + + var pinpolicy string + if p, ok := d.GetOk(helpers.PIInstancePinPolicy); ok { + pinpolicy = p.(string) + if pinpolicy == "" { + pinpolicy = "none" + } + } + + var userData string + if u, ok := d.GetOk(helpers.PIInstanceUserData); ok { + userData = u.(string) + } + err := checkBase64(userData) + if err != nil { + log.Printf("Data is not base64 encoded") + return nil, err + } + + //publicinterface := d.Get(helpers.PIInstancePublicNetwork).(bool) + body := &models.PVMInstanceCreate{ + //NetworkIds: networks, + Processors: &procs, + Memory: &mem, + ServerName: flex.PtrToString(name), + SysType: systype, + ImageID: flex.PtrToString(imageid), + ProcType: flex.PtrToString(processortype), + Replicants: replicants, + UserData: userData, + ReplicantNamingScheme: flex.PtrToString(replicationNamingScheme), + ReplicantAffinityPolicy: flex.PtrToString(replicationpolicy), + Networks: pvmNetworks, + Migratable: &migratable, + } + if s, ok := d.GetOk(helpers.PIInstanceSSHKeyName); ok { + sshkey := s.(string) + body.KeyPairName = sshkey + } + if len(volids) > 0 { + body.VolumeIDs = volids + } + if d.Get(helpers.PIInstancePinPolicy) == "soft" || d.Get(helpers.PIInstancePinPolicy) == "hard" { + body.PinPolicy = models.PinPolicy(pinpolicy) + } + + var assignedVirtualCores int64 + if a, ok := d.GetOk(helpers.PIVirtualCoresAssigned); ok { + assignedVirtualCores = int64(a.(int)) + body.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} + } + + if st, ok := d.GetOk(helpers.PIInstanceStorageType); ok { + body.StorageType = st.(string) + } + if sp, ok := d.GetOk(PIInstanceStoragePool); ok { + body.StoragePool = sp.(string) + } + + if dt, ok := d.GetOk(PIInstanceDeploymentType); ok { + body.DeploymentType = dt.(string) + } + + if ap, ok := d.GetOk(PIAffinityPolicy); ok { + policy := ap.(string) + affinity := &models.StorageAffinity{ + AffinityPolicy: &policy, + } + + if policy == "affinity" { + if av, ok := d.GetOk(PIAffinityVolume); ok { + afvol := av.(string) + affinity.AffinityVolume = &afvol + } + if ai, ok := d.GetOk(PIAffinityInstance); ok { + afins := ai.(string) + affinity.AffinityPVMInstance = &afins + } + } else { + if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { + afvols := flex.ExpandStringList(avs.([]interface{})) + affinity.AntiAffinityVolumes = afvols + } + if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { + afinss := flex.ExpandStringList(ais.([]interface{})) + affinity.AntiAffinityPVMInstances = afinss + } + } + body.StorageAffinity = affinity + } + + if sc, ok := d.GetOk(helpers.PIInstanceStorageConnection); ok { + body.StorageConnection = sc.(string) + } + + if pg, ok := d.GetOk(helpers.PIPlacementGroupID); ok { + body.PlacementGroup = pg.(string) + } + + if spp, ok := d.GetOk(Arg_PIInstanceSharedProcessorPool); ok { + body.SharedProcessorPool = spp.(string) + } + + if lrc, ok := d.GetOk(helpers.PIInstanceLicenseRepositoryCapacity); ok { + // check if using vtl image + // check if vtl image is stock image + imageData, err := imageClient.GetStockImage(imageid) + if err != nil { + // check if vtl image is cloud instance image + imageData, err = imageClient.Get(imageid) + if err != nil { + return nil, fmt.Errorf("image doesn't exist. %e", err) + } + } + + if imageData.Specifications.ImageType == "stock-vtl" { + body.LicenseRepositoryCapacity = int64(lrc.(int)) + } else { + return nil, fmt.Errorf("pi_license_repository_capacity should only be used when creating VTL instances. %e", err) + } + } + + pvmList, err := client.Create(body) + + if err != nil { + return nil, fmt.Errorf("failed to provision: %v", err) + } + if pvmList == nil { + return nil, fmt.Errorf("failed to provision") + } + + return pvmList, nil +} + +func splitID(id string) (id1, id2 string, err error) { + parts, err := flex.IdParts(id) + if err != nil { + return + } + id1 = parts[0] + id2 = parts[1] + return +} diff --git a/ibm/service/power/resource_ibm_pi_instance_action.go b/ibm/service/power/resource_ibm_pi_instance_action.go new file mode 100644 index 000000000..071b3d206 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_action.go @@ -0,0 +1,220 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "log" + "time" +) + +func ResourceIBMPIInstanceAction() *schema.Resource { + return &schema.Resource{ + + CreateContext: resourceIBMPIInstanceActionCreate, + ReadContext: resourceIBMPIInstanceActionRead, + UpdateContext: resourceIBMPIInstanceActionUpdate, + DeleteContext: resourceIBMPIInstanceActionDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Update: schema.DefaultTimeout(15 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI Cloud instance id", + }, + Arg_PVMInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PVM instance ID", + }, + Arg_PVMInstanceActionType: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"start", "stop", "hard-reboot", "soft-reboot", "immediate-shutdown", "reset-state"}), + Description: "PVM instance action type", + }, + Arg_PVMInstanceHealthStatus: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{PVMInstanceHealthOk, PVMInstanceHealthWarning}), + Default: PVMInstanceHealthOk, + Description: "Set the health status of the PVM instance to connect it faster", + }, + + // Computed + Attr_Status: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the PVM instance", + }, + Attr_Progress: { + Type: schema.TypeFloat, + Computed: true, + Description: "The progress of an operation", + }, + Attr_HealthStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The PVM's health status value", + }, + }, + } +} + +func resourceIBMPIInstanceActionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + adiag := takeInstanceAction(ctx, d, meta, d.Timeout(schema.TimeoutCreate)) + if adiag != nil { + return adiag + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + id := d.Get(Arg_PVMInstanceId).(string) + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, id)) + + return resourceIBMPIInstanceActionRead(ctx, d, meta) +} + +func resourceIBMPIInstanceActionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, id, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIInstanceClient(context.Background(), sess, cloudInstanceID) + powervmdata, err := client.Get(id) + if err != nil { + return diag.FromErr(err) + } + + d.Set(Attr_Status, powervmdata.Status) + d.Set(Attr_Progress, powervmdata.Progress) + if powervmdata.Health != nil { + d.Set(Attr_HealthStatus, powervmdata.Health.Status) + } + + return nil +} + +func resourceIBMPIInstanceActionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + if d.HasChange(Arg_PVMInstanceActionType) { + takeInstanceAction(ctx, d, meta, d.Timeout(schema.TimeoutUpdate)) + } + + return resourceIBMPIInstanceActionRead(ctx, d, meta) +} + +func resourceIBMPIInstanceActionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // There is no delete or unset concept for instance action + d.SetId("") + return nil +} + +func takeInstanceAction(ctx context.Context, d *schema.ResourceData, meta interface{}, timeout time.Duration) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + id := d.Get(Arg_PVMInstanceId).(string) + action := d.Get(Arg_PVMInstanceActionType).(string) + targetHealthStatus := d.Get(Arg_PVMInstanceHealthStatus).(string) + + body := &models.PVMInstanceAction{Action: &action} + log.Printf("Calling the IBM PI Action %s on the instance %s", action, id) + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + err = client.Action(id, body) + if err != nil { + log.Printf("[ERROR] failed to perform the action on the instance %v", err) + return diag.FromErr(err) + } + + log.Printf("Executed the action on the instance") + + var targetStatus string + if action == "stop" || action == "immediate-shutdown" { + targetStatus = "SHUTOFF" + } else if action == "reset-state" { + targetStatus = "ACTIVE" + targetHealthStatus = "CRITICAL" + } else { + // action is "start" or "soft-reboot" or "hard-reboot" + targetStatus = "ACTIVE" + } + + log.Printf("Calling the check for %s opertion to check for status %s", action, targetStatus) + _, err = isWaitForPIInstanceActionStatus(ctx, client, id, timeout, targetStatus, targetHealthStatus) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func isWaitForPIInstanceActionStatus(ctx context.Context, client *st.IBMPIInstanceClient, id string, timeout time.Duration, targetStatus, targetHealthStatus string) (interface{}, error) { + log.Printf("Waiting for the action to be performed on the instance %s", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusPending}, + Target: []string{targetStatus, StatusError, ""}, + Refresh: isPIActionRefreshFunc(client, id, targetStatus, targetHealthStatus), + Delay: 30 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: 15 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIActionRefreshFunc(client *st.IBMPIInstanceClient, id, targetStatus, targetHealthStatus string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("Waiting for the target status to be [ %s ]", targetStatus) + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if *pvm.Status == targetStatus && (pvm.Health.Status == targetHealthStatus || pvm.Health.Status == PVMInstanceHealthOk) { + log.Printf("The health status is now %s", pvm.Health.Status) + return pvm, targetStatus, nil + } + + if *pvm.Status == "ERROR" { + if pvm.Fault != nil { + err = fmt.Errorf("failed to perform the action on the instance: %s", pvm.Fault.Message) + } else { + err = fmt.Errorf("failed to perform the action on the instance") + } + return pvm, *pvm.Status, err + } + + return pvm, StatusPending, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_instance_action_test.go b/ibm/service/power/resource_ibm_pi_instance_action_test.go new file mode 100644 index 000000000..507ef2624 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_action_test.go @@ -0,0 +1,93 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstanceAction(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceActionConfig("stop"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "status", "SHUTOFF"), + ), + }, + { + Config: testAccCheckIBMPIInstanceActionConfig("start"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "status", "ACTIVE"), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceActionHardReboot(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceActionWithHealthStatusConfig("hard-reboot"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "status", "ACTIVE"), + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "health_status", "WARNING"), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceActionResetState(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceActionWithHealthStatusConfig("reset-state"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "status", "ACTIVE"), + resource.TestCheckResourceAttr( + "ibm_pi_instance_action.example", "health_status", "CRITICAL"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceActionConfig(action string) string { + return fmt.Sprintf(` + resource "ibm_pi_instance_action" "example" { + pi_cloud_instance_id = "%s" + pi_instance_id = "%s" + pi_action = "%s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name, action) +} + +func testAccCheckIBMPIInstanceActionWithHealthStatusConfig(action string) string { + return fmt.Sprintf(` + resource "ibm_pi_instance_action" "example" { + pi_cloud_instance_id = "%s" + pi_instance_id = "%s" + pi_action = "%s" + pi_health_status = "WARNING" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name, action) +} diff --git a/ibm/service/power/resource_ibm_pi_instance_console_language.go b/ibm/service/power/resource_ibm_pi_instance_console_language.go new file mode 100644 index 000000000..a825760d0 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_console_language.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +const ( + PIConsoleLanguageCode = "pi_language_code" +) + +func ResourceIBMPIInstanceConsoleLanguage() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIInstanceConsoleLanguageCreate, + ReadContext: resourceIBMPIInstanceConsoleLanguageRead, + UpdateContext: resourceIBMPIInstanceConsoleLanguageUpdate, + DeleteContext: resourceIBMPIInstanceConsoleLanguageDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier or name of the instance", + }, + PIConsoleLanguageCode: { + Type: schema.TypeString, + Required: true, + Description: "Language code", + }, + }, + } +} + +func resourceIBMPIInstanceConsoleLanguageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + instanceName := d.Get(helpers.PIInstanceName).(string) + code := d.Get(PIConsoleLanguageCode).(string) + + client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + consoleLanguage := &models.ConsoleLanguage{ + Code: &code, + } + + _, err = client.UpdateConsoleLanguage(instanceName, consoleLanguage) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, instanceName)) + + return resourceIBMPIInstanceConsoleLanguageRead(ctx, d, meta) +} + +func resourceIBMPIInstanceConsoleLanguageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // There is no get concept for instance console language + return nil +} + +func resourceIBMPIInstanceConsoleLanguageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + if d.HasChange(ConsoleLanguageCode) { + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + instanceName := d.Get(helpers.PIInstanceName).(string) + code := d.Get(PIConsoleLanguageCode).(string) + + client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + consoleLanguage := &models.ConsoleLanguage{ + Code: &code, + } + _, err = client.UpdateConsoleLanguage(instanceName, consoleLanguage) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + } + return resourceIBMPIInstanceConsoleLanguageRead(ctx, d, meta) +} + +func resourceIBMPIInstanceConsoleLanguageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // There is no delete or unset concept for instance console language + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_instance_console_language_test.go b/ibm/service/power/resource_ibm_pi_instance_console_language_test.go new file mode 100644 index 000000000..4e8c25231 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_console_language_test.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstanceConsoleLanguage(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceConsoleLanguageConfig("037"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_console_language.example", "pi_language_code", "037"), + ), + }, + { + Config: testAccCheckIBMPIInstanceConsoleLanguageConfig("e1399"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_pi_console_language.example", "pi_language_code", "e1399"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceConsoleLanguageConfig(code string) string { + return fmt.Sprintf(` + resource "ibm_pi_console_language" "example" { + pi_cloud_instance_id = "%s" + pi_instance_name = "%s" + pi_language_code = "%s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name, code) +} diff --git a/ibm/service/power/resource_ibm_pi_instance_test.go b/ibm/service/power/resource_ibm_pi_instance_test.go new file mode 100644 index 000000000..d02404379 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_test.go @@ -0,0 +1,412 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" +) + +func testAccCheckIBMPIInstanceConfig(name, instanceHealthStatus string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + data "ibm_pi_image" "power_image" { + pi_image_name = "%[3]s" + pi_cloud_instance_id = "%[1]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[4]s" + } + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 20 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = data.ibm_pi_image.power_image.storage_pool + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = data.ibm_pi_image.power_image.id + pi_key_pair_name = ibm_pi_key.key.key_id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = data.ibm_pi_image.power_image.storage_pool + pi_health_status = "%[5]s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) +} + +func testAccCheckIBMPIInstanceDeploymentTypeConfig(name, instanceHealthStatus string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + data "ibm_pi_image" "power_image" { + pi_image_name = "%[3]s" + pi_cloud_instance_id = "%[1]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[4]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "1" + pi_instance_name = "%[2]s" + pi_proc_type = "dedicated" + pi_image_id = data.ibm_pi_image.power_image.id + pi_key_pair_name = ibm_pi_key.key.key_id + pi_sys_type = "e980" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier1" + pi_health_status = "%[5]s" + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_deployment_type = "EPIC" + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) +} + +func testAccIBMPIInstanceNetworkConfig(name, privateNetIP string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArb2aK0mekAdbYdY9rwcmeNSxqVCwez3WZTYEq+1Nwju0x5/vQFPSD2Kp9LpKBbxx3OVLN4VffgGUJznz9DAr7veLkWaf3iwEil6U4rdrhBo32TuDtoBwiczkZ9gn1uJzfIaCJAJdnO80Kv9k0smbQFq5CSb9H+F5VGyFue/iVd5/b30MLYFAz6Jg1GGWgw8yzA4Gq+nO7HtyuA2FnvXdNA3yK/NmrTiPCdJAtEPZkGu9LcelkQ8y90ArlKfjtfzGzYDE4WhOufFxyWxciUePh425J2eZvElnXSdGha+FCfYjQcvqpCVoBAG70U4fJBGjB+HL/GpCXLyiYXPrSnzC9w==" + } + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "vlan" + pi_dns = ["127.0.0.1"] + pi_gateway = "192.168.17.2" + pi_cidr = "192.168.17.0/24" + pi_ipaddress_range { + pi_ending_ip_address = "192.168.17.254" + pi_starting_ip_address = "192.168.17.3" + } + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = "f4501cad-d0f4-4517-9eea-85402309d90d" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_sys_type = "e980" + pi_storage_type = "tier3" + pi_cloud_instance_id = "%[1]s" + pi_network { + network_id = resource.ibm_pi_network.power_networks.id + ip_address = "%[3]s" + } + } + `, acc.Pi_cloud_instance_id, name, privateNetIP) +} + +func testAccIBMPIInstanceVTLConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "vtl_key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArb2aK0mekAdbYdY9rwcmeNSxqVCwez3WZTYEq+1Nwju0x5/vQFPSD2Kp9LpKBbxx3OVLN4VffgGUJznz9DAr7veLkWaf3iwEil6U4rdrhBo32TuDtoBwiczkZ9gn1uJzfIaCJAJdnO80Kv9k0smbQFq5CSb9H+F5VGyFue/iVd5/b30MLYFAz6Jg1GGWgw8yzA4Gq+nO7HtyuA2FnvXdNA3yK/NmrTiPCdJAtEPZkGu9LcelkQ8y90ArlKfjtfzGzYDE4WhOufFxyWxciUePh425J2eZvElnXSdGha+FCfYjQcvqpCVoBAG70U4fJBGjB+HL/GpCXLyiYXPrSnzC9w==" + } + + resource "ibm_pi_network" "vtl_network" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "pub-vlan" + } + + resource "ibm_pi_instance" "vtl_instance" { + pi_memory = "22" + pi_processors = "2" + pi_instance_name = "%[2]s" + pi_license_repository_capacity = "3" + pi_proc_type = "shared" + pi_image_id = "%[3]s" + pi_key_pair_name = ibm_pi_key.vtl_key.key_id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier1" + pi_network { + network_id = ibm_pi_network.vtl_network.network_id + } + } + + `, acc.Pi_cloud_instance_id, name, acc.Pi_image) +} + +func testAccCheckIBMPIInstanceDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_instance" { + continue + } + cloudInstanceID, instanceID, err := splitID(rs.Primary.ID) + if err == nil { + return err + } + client := st.NewIBMPIInstanceClient(context.Background(), sess, cloudInstanceID) + _, err = client.Get(instanceID) + if err == nil { + return fmt.Errorf("PI Instance still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIInstanceExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + cloudInstanceID, instanceID, err := splitID(rs.Primary.ID) + if err == nil { + return err + } + client := st.NewIBMPIInstanceClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(instanceID) + if err != nil { + return err + } + + return nil + } +} + +func TestAccIBMPIInstanceBasic(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceConfig(name, helpers.PIInstanceHealthWarning), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceDeploymentType(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceDeploymentTypeConfig(name, helpers.PIInstanceHealthWarning), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceNetwork(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + privateNetIP := "192.168.17.253" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIBMPIInstanceNetworkConfig(name, privateNetIP), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttrSet(instanceRes, "pi_network.0.network_id"), + resource.TestCheckResourceAttrSet(instanceRes, "pi_network.0.mac_address"), + resource.TestCheckResourceAttr(instanceRes, "pi_network.0.ip_address", privateNetIP), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceVTL(t *testing.T) { + instanceRes := "ibm_pi_instance.vtl_instance" + name := fmt.Sprintf("tf-pi-vtl-instance-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIBMPIInstanceVTLConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_license_repository_capacity", "3"), + ), + }, + }, + }) +} + +func TestAccIBMPISAPInstance(t *testing.T) { + instanceRes := "ibm_pi_instance.sap" + name := fmt.Sprintf("tf-pi-sap-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIBMPISAPInstanceConfig(name, "tinytest-1x4"), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_sap_profile_id", "tinytest-1x4"), + ), + }, + { + Config: testAccIBMPISAPInstanceConfig(name, "tinytest-1x8"), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_sap_profile_id", "tinytest-1x8"), + ), + }, + }, + }) +} +func testAccIBMPISAPInstanceConfig(name, sapProfile string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_network" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "pub-vlan" + } + resource "ibm_pi_instance" "sap" { + pi_cloud_instance_id = "%[1]s" + pi_instance_name = "%[2]s" + pi_sap_profile_id = "%[3]s" + pi_image_id = "%[4]s" + pi_storage_type = "tier1" + pi_network { + network_id = ibm_pi_network.power_network.network_id + } + pi_health_status = "OK" + } + `, acc.Pi_cloud_instance_id, name, sapProfile, acc.Pi_sap_image) +} + +func TestAccIBMPIInstanceMixedStorage(t *testing.T) { + instanceRes := "ibm_pi_instance.instance" + name := fmt.Sprintf("tf-pi-mixedstorage-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIBMPIInstanceMixedStorage(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_storage_pool_affinity", "false"), + ), + }, + }, + }) +} + +func testAccIBMPIInstanceMixedStorage(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + resource "ibm_pi_network" "power_network" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s" + pi_network_type = "pub-vlan" + } + resource "ibm_pi_volume" "power_volume" { + pi_cloud_instance_id = "%[1]s" + pi_volume_size = 20 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_type = "tier3" + } + resource "ibm_pi_instance" "instance" { + pi_cloud_instance_id = "%[1]s" + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = "ca4ea55f-b329-4cf5-bdce-d2f38cfc6da3" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_sys_type = "s922" + pi_storage_type = "tier1" + pi_storage_pool_affinity = false + pi_network { + network_id = ibm_pi_network.power_network.network_id + } + } + resource "ibm_pi_volume_attach" "power_attach_volume"{ + pi_cloud_instance_id = "%[1]s" + pi_volume_id = ibm_pi_volume.power_volume.volume_id + pi_instance_id = ibm_pi_instance.instance.instance_id + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_ipsec_policy.go b/ibm/service/power/resource_ibm_pi_ipsec_policy.go new file mode 100644 index 000000000..c18aac463 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_ipsec_policy.go @@ -0,0 +1,240 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPIIPSecPolicy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIIPSecPolicyCreate, + ReadContext: resourceIBMPIIPSecPolicyRead, + UpdateContext: resourceIBMPIIPSecPolicyUpdate, + DeleteContext: resourceIBMPIIPSecPolicyDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PIVPNPolicyName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the IPSec Policy", + }, + helpers.PIVPNPolicyDhGroup: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedIntValues([]int{1, 2, 5, 14, 19, 20, 24}), + Description: "DH group of the IPSec Policy", + }, + helpers.PIVPNPolicyEncryption: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"aes-256-cbc", "aes-192-cbc", "aes-128-cbc", "aes-256-gcm", "aes-128-gcm", "3des-cbc"}), + Description: "Encryption of the IPSec Policy", + }, + helpers.PIVPNPolicyKeyLifetime: { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validate.ValidateAllowedRangeInt(180, 86400), + Description: "Policy key lifetime", + }, + helpers.PIVPNPolicyPFS: { + Type: schema.TypeBool, + Required: true, + Description: "Perfect Forward Secrecy", + }, + + // Optional Attributes + helpers.PIVPNPolicyAuthentication: { + Type: schema.TypeString, + Optional: true, + Default: "none", + ValidateFunc: validate.ValidateAllowedStringValues([]string{"hmac-sha-256-128", "hmac-sha1-96", "none"}), + Description: "Authentication for the IPSec Policy", + }, + + //Computed Attributes + PIPolicyId: { + Type: schema.TypeString, + Computed: true, + Description: "IPSec policy ID", + }, + }, + } +} + +func resourceIBMPIIPSecPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(helpers.PIVPNPolicyName).(string) + dhGroup := int64(d.Get(helpers.PIVPNPolicyDhGroup).(int)) + encryption := d.Get(helpers.PIVPNPolicyEncryption).(string) + pfs := d.Get(helpers.PIVPNPolicyPFS).(bool) + keyLifetime := int64(d.Get(helpers.PIVPNPolicyKeyLifetime).(int)) + klt := models.KeyLifetime(keyLifetime) + + body := &models.IPSecPolicyCreate{ + DhGroup: &dhGroup, + Encryption: &encryption, + KeyLifetime: &klt, + Name: &name, + Pfs: &pfs, + } + + if v, ok := d.GetOk(helpers.PIVPNPolicyAuthentication); ok { + body.Authentication = models.IPSECPolicyAuthentication(v.(string)) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + ipsecPolicy, err := client.CreateIPSecPolicy(body) + if err != nil { + log.Printf("[DEBUG] create ipsec policy failed %v", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *ipsecPolicy.ID)) + + return resourceIBMPIIPSecPolicyRead(ctx, d, meta) +} + +func resourceIBMPIIPSecPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + body := &models.IPSecPolicyUpdate{} + + if d.HasChange(helpers.PIVPNPolicyName) { + name := d.Get(helpers.PIVPNPolicyName).(string) + body.Name = name + } + if d.HasChange(helpers.PIVPNPolicyDhGroup) { + dhGroup := int64(d.Get(helpers.PIVPNPolicyDhGroup).(int)) + body.DhGroup = dhGroup + } + if d.HasChange(helpers.PIVPNPolicyEncryption) { + encryption := d.Get(helpers.PIVPNPolicyEncryption).(string) + body.Encryption = encryption + } + if d.HasChange(helpers.PIVPNPolicyKeyLifetime) { + keyLifetime := int64(d.Get(helpers.PIVPNPolicyKeyLifetime).(int)) + body.KeyLifetime = models.KeyLifetime(keyLifetime) + } + if d.HasChange(helpers.PIVPNPolicyPFS) { + pfs := d.Get(helpers.PIVPNPolicyPFS).(bool) + body.Pfs = &pfs + } + if d.HasChange(helpers.PIVPNPolicyAuthentication) { + authentication := d.Get(helpers.PIVPNPolicyAuthentication).(string) + body.Authentication = models.IPSECPolicyAuthentication(authentication) + } + + _, err = client.UpdateIPSecPolicy(policyID, body) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIIPSecPolicyRead(ctx, d, meta) +} + +func resourceIBMPIIPSecPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + ipsecPolicy, err := client.GetIPSecPolicy(policyID) + if err != nil { + // FIXME: Uncomment when 404 error is available + // switch err.(type) { + // case *p_cloud_v_p_n_policies.PcloudIPSecpoliciesGetNotFound: + // log.Printf("[DEBUG] VPN policy does not exist %v", err) + // d.SetId("") + // return nil + // } + log.Printf("[DEBUG] get VPN policy failed %v", err) + return diag.FromErr(err) + } + + d.Set(PIPolicyId, ipsecPolicy.ID) + d.Set(helpers.PIVPNPolicyName, ipsecPolicy.Name) + d.Set(helpers.PIVPNPolicyDhGroup, ipsecPolicy.DhGroup) + d.Set(helpers.PIVPNPolicyEncryption, ipsecPolicy.Encryption) + d.Set(helpers.PIVPNPolicyKeyLifetime, ipsecPolicy.KeyLifetime) + d.Set(helpers.PIVPNPolicyPFS, ipsecPolicy.Pfs) + d.Set(helpers.PIVPNPolicyAuthentication, ipsecPolicy.Authentication) + + return nil +} + +func resourceIBMPIIPSecPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, policyID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnPolicyClient(ctx, sess, cloudInstanceID) + + err = client.DeleteIPSecPolicy(policyID) + if err != nil { + // FIXME: Uncomment when 404 error is available + // switch err.(type) { + // case *p_cloud_v_p_n_policies.PcloudIPSecpoliciesDeleteNotFound: + // log.Printf("[DEBUG] VPN policy does not exist %v", err) + // d.SetId("") + // return nil + // } + log.Printf("[DEBUG] delete VPN policy failed %v", err) + return diag.FromErr(err) + } + + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_ipsec_policy_test.go b/ibm/service/power/resource_ibm_pi_ipsec_policy_test.go new file mode 100644 index 000000000..0c88c2679 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_ipsec_policy_test.go @@ -0,0 +1,104 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIIPSecPolicyBasic(t *testing.T) { + policyRes := "ibm_pi_ipsec_policy.policy" + name := fmt.Sprintf("tf-pi-ipsec-policy-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIIPSecPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIIPSecPolicyConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIIPSecPolicyExists(policyRes), + resource.TestCheckResourceAttr(policyRes, "pi_policy_name", name), + resource.TestCheckResourceAttrSet(policyRes, "policy_id"), + resource.TestCheckResourceAttr(policyRes, "pi_policy_authentication", "hmac-sha-256-128"), + ), + }, + }, + }) +} +func testAccCheckIBMPIIPSecPolicyDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_ipsec_policy" { + continue + } + cloudInstanceID, policyID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnPolicyClient(context.Background(), sess, cloudInstanceID) + _, err = client.GetIPSecPolicy(policyID) + if err == nil { + return fmt.Errorf("ipsec policy still exists: %s", rs.Primary.ID) + } + } + return nil +} +func testAccCheckIBMPIIPSecPolicyExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, policyID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnPolicyClient(context.Background(), sess, cloudInstanceID) + + _, err = client.GetIPSecPolicy(policyID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPIIPSecPolicyConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_ipsec_policy" "policy" { + pi_cloud_instance_id = "%s" + pi_policy_name = "%s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_pfs = true + pi_policy_authentication = "hmac-sha-256-128" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_key.go b/ibm/service/power/resource_ibm_pi_key.go new file mode 100644 index 000000000..3f305e4da --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_key.go @@ -0,0 +1,161 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func ResourceIBMPIKey() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIKeyCreate, + ReadContext: resourceIBMPIKeyRead, + UpdateContext: resourceIBMPIKeyUpdate, + DeleteContext: resourceIBMPIKeyDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + // Arguments + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + Arg_KeyName: { + Type: schema.TypeString, + Required: true, + Description: "User defined name for the SSH key", + }, + Arg_Key: { + Type: schema.TypeString, + Required: true, + Description: "SSH RSA key", + }, + + // Attributes + Attr_KeyCreationDate: { + Type: schema.TypeString, + Computed: true, + Description: "Date of SSH Key creation", + }, + Attr_KeyID: { + Type: schema.TypeString, + Computed: true, + Deprecated: "User defined name for the SSH key (deprecated - replaced by name)", + }, + Attr_KeyName: { + Type: schema.TypeString, + Computed: true, + Description: "User defined name for the SSH key", + }, + Attr_Key: { + Type: schema.TypeString, + Computed: true, + Description: "SSH RSA key", + }, + }, + } +} + +func resourceIBMPIKeyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + name := d.Get(Arg_KeyName).(string) + sshkey := d.Get(Arg_Key).(string) + + // create key + client := st.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) + body := &models.SSHKey{ + Name: &name, + SSHKey: &sshkey, + } + sshResponse, err := client.Create(body) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + log.Printf("Printing the sshkey %+v", *sshResponse) + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, name)) + return resourceIBMPIKeyRead(ctx, d, meta) +} + +func resourceIBMPIKeyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID, key, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // get key + sshkeyC := st.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) + sshkeydata, err := sshkeyC.Get(key) + if err != nil { + return diag.FromErr(err) + } + + // set attributes + d.Set(Attr_KeyName, sshkeydata.Name) + d.Set(Attr_KeyID, sshkeydata.Name) + d.Set(Attr_Key, sshkeydata.SSHKey) + d.Set(Attr_KeyCreationDate, sshkeydata.CreationDate.String()) + + return nil +} +func resourceIBMPIKeyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return resourceIBMPIKeyRead(ctx, d, meta) +} +func resourceIBMPIKeyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + // arguments + cloudInstanceID, key, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // delete key + sshkeyC := st.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) + err = sshkeyC.Delete(key) + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_key_test.go b/ibm/service/power/resource_ibm_pi_key_test.go new file mode 100644 index 000000000..fc62bead4 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_key_test.go @@ -0,0 +1,108 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIKey_basic(t *testing.T) { + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + name := fmt.Sprintf("tf-pi-sshkey-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIKeyConfig(publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIKeyExists("ibm_pi_key.key"), + resource.TestCheckResourceAttr( + "ibm_pi_key.key", "pi_key_name", name), + ), + }, + }, + }) +} +func testAccCheckIBMPIKeyDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_key" { + continue + } + cloudInstanceID, key, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + sshkeyC := st.NewIBMPIKeyClient(context.Background(), sess, cloudInstanceID) + _, err = sshkeyC.Get(key) + if err == nil { + return fmt.Errorf("PI key still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIKeyExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + cloudInstanceID, key, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + + client := st.NewIBMPIKeyClient(context.Background(), sess, cloudInstanceID) + _, err = client.Get(key) + if err != nil { + return err + } + return nil + + } +} + +func testAccCheckIBMPIKeyConfig(publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%s" + pi_key_name = "%s" + pi_ssh_key = "%s" + } + `, acc.Pi_cloud_instance_id, name, publicKey) +} diff --git a/ibm/service/power/resource_ibm_pi_network.go b/ibm/service/power/resource_ibm_pi_network.go new file mode 100644 index 000000000..113e5f917 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network.go @@ -0,0 +1,382 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "net" + "strconv" + "time" + + "github.com/apparentlymart/go-cidr/cidr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +const ( + piEndingIPAaddress = "pi_ending_ip_address" + piStartingIPAaddress = "pi_starting_ip_address" +) + +func ResourceIBMPINetwork() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkCreate, + ReadContext: resourceIBMPINetworkRead, + UpdateContext: resourceIBMPINetworkUpdate, + DeleteContext: resourceIBMPINetworkDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + helpers.PINetworkType: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"vlan", "pub-vlan"}), + Description: "PI network type", + }, + helpers.PINetworkName: { + Type: schema.TypeString, + Required: true, + Description: "PI network name", + }, + helpers.PINetworkDNS: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of PI network DNS name", + }, + helpers.PINetworkCidr: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "PI network CIDR", + }, + helpers.PINetworkGateway: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "PI network gateway", + }, + helpers.PINetworkJumbo: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "PI network enable MTU Jumbo option", + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PINetworkIPAddressRange: { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "List of one or more ip address range(s)", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + piEndingIPAaddress: { + Type: schema.TypeString, + Required: true, + Description: "Ending ip address", + }, + piStartingIPAaddress: { + Type: schema.TypeString, + Required: true, + Description: "Starting ip address", + }, + }, + }, + }, + + //Computed Attributes + "network_id": { + Type: schema.TypeString, + Computed: true, + Description: "PI network ID", + }, + "vlan_id": { + Type: schema.TypeFloat, + Computed: true, + Description: "VLAN Id value", + }, + }, + } +} + +func resourceIBMPINetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + networkname := d.Get(helpers.PINetworkName).(string) + networktype := d.Get(helpers.PINetworkType).(string) + + client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + var body = &models.NetworkCreate{ + Type: &networktype, + Name: networkname, + } + if v, ok := d.GetOk(helpers.PINetworkDNS); ok { + networkdns := flex.ExpandStringList((v.(*schema.Set)).List()) + if len(networkdns) > 0 { + body.DNSServers = networkdns + } + } + + if v, ok := d.GetOk(helpers.PINetworkJumbo); ok { + body.Jumbo = v.(bool) + } + + if networktype == "vlan" { + var networkcidr string + var ipBodyRanges []*models.IPAddressRange + if v, ok := d.GetOk(helpers.PINetworkCidr); ok { + networkcidr = v.(string) + } else { + return diag.Errorf("%s is required when %s is vlan", helpers.PINetworkCidr, helpers.PINetworkType) + } + + gateway, firstip, lastip, err := generateIPData(networkcidr) + if err != nil { + return diag.FromErr(err) + } + + ipBodyRanges = []*models.IPAddressRange{{EndingIPAddress: &lastip, StartingIPAddress: &firstip}} + + if g, ok := d.GetOk(helpers.PINetworkGateway); ok { + gateway = g.(string) + } + + if ips, ok := d.GetOk(helpers.PINetworkIPAddressRange); ok { + ipBodyRanges = getIPAddressRanges(ips.([]interface{})) + } + + body.IPAddressRanges = ipBodyRanges + body.Gateway = gateway + body.Cidr = networkcidr + } + + networkResponse, err := client.Create(body) + if err != nil { + return diag.FromErr(err) + } + + networkID := *networkResponse.NetworkID + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, networkID)) + + _, err = isWaitForIBMPINetworkAvailable(ctx, client, networkID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPINetworkRead(ctx, d, meta) +} + +func resourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, networkID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.Get(networkID) + if err != nil { + return diag.FromErr(err) + } + + d.Set("network_id", networkdata.NetworkID) + d.Set(helpers.PINetworkCidr, networkdata.Cidr) + d.Set(helpers.PINetworkDNS, networkdata.DNSServers) + d.Set("vlan_id", networkdata.VlanID) + d.Set(helpers.PINetworkName, networkdata.Name) + d.Set(helpers.PINetworkType, networkdata.Type) + d.Set(helpers.PINetworkJumbo, networkdata.Jumbo) + d.Set(helpers.PINetworkGateway, networkdata.Gateway) + ipRangesMap := []map[string]interface{}{} + if networkdata.IPAddressRanges != nil { + for _, n := range networkdata.IPAddressRanges { + if n != nil { + v := map[string]interface{}{ + piEndingIPAaddress: n.EndingIPAddress, + piStartingIPAaddress: n.StartingIPAddress, + } + ipRangesMap = append(ipRangesMap, v) + } + } + } + d.Set(helpers.PINetworkIPAddressRange, ipRangesMap) + + return nil + +} + +func resourceIBMPINetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, networkID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + if d.HasChanges(helpers.PINetworkName, helpers.PINetworkDNS, helpers.PINetworkGateway, helpers.PINetworkIPAddressRange) { + networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + body := &models.NetworkUpdate{ + DNSServers: flex.ExpandStringList((d.Get(helpers.PINetworkDNS).(*schema.Set)).List()), + } + if d.Get(helpers.PINetworkType).(string) == "vlan" { + body.Gateway = flex.PtrToString(d.Get(helpers.PINetworkGateway).(string)) + body.IPAddressRanges = getIPAddressRanges(d.Get(helpers.PINetworkIPAddressRange).([]interface{})) + } + + if d.HasChange(helpers.PINetworkName) { + body.Name = flex.PtrToString(d.Get(helpers.PINetworkName).(string)) + } + + _, err = networkC.Update(networkID, body) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPINetworkRead(ctx, d, meta) +} + +func resourceIBMPINetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + log.Printf("Calling the network delete functions. ") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, networkID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + err = networkC.Delete(networkID) + + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + return nil +} + +func isWaitForIBMPINetworkAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PINetworkProvisioning}, + Target: []string{"NETWORK_READY"}, + Refresh: isIBMPINetworkRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkRefreshFunc(client *st.IBMPINetworkClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + network, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if network.VlanID != nil { + return network, "NETWORK_READY", nil + } + + return network, helpers.PINetworkProvisioning, nil + } +} + +func generateIPData(cdir string) (gway, firstip, lastip string, err error) { + _, ipv4Net, err := net.ParseCIDR(cdir) + + if err != nil { + return "", "", "", err + } + + var subnetToSize = map[string]int{ + "21": 2048, + "22": 1024, + "23": 512, + "24": 256, + "25": 128, + "26": 64, + "27": 32, + "28": 16, + "29": 8, + "30": 4, + "31": 2, + } + + //subnetsize, _ := ipv4Net.Mask.Size() + + gateway, err := cidr.Host(ipv4Net, 1) + if err != nil { + log.Printf("Failed to get the gateway for this cidr passed in %s", cdir) + return "", "", "", err + } + ad := cidr.AddressCount(ipv4Net) + + convertedad := strconv.FormatUint(ad, 10) + // Powervc in wdc04 has to reserve 3 ip address hence we start from the 4th. This will be the default behaviour + firstusable, err := cidr.Host(ipv4Net, 4) + if err != nil { + log.Print(err) + return "", "", "", err + } + lastusable, err := cidr.Host(ipv4Net, subnetToSize[convertedad]-2) + if err != nil { + log.Print(err) + return "", "", "", err + } + return gateway.String(), firstusable.String(), lastusable.String(), nil + +} + +func getIPAddressRanges(ipAddressRanges []interface{}) []*models.IPAddressRange { + ipRanges := make([]*models.IPAddressRange, 0, len(ipAddressRanges)) + for _, v := range ipAddressRanges { + if v != nil { + ipAddressRange := v.(map[string]interface{}) + ipRange := &models.IPAddressRange{ + EndingIPAddress: flex.PtrToString(ipAddressRange[piEndingIPAaddress].(string)), + StartingIPAddress: flex.PtrToString(ipAddressRange[piStartingIPAaddress].(string)), + } + ipRanges = append(ipRanges, ipRange) + } + } + return ipRanges +} diff --git a/ibm/service/power/resource_ibm_pi_network_port.go b/ibm/service/power/resource_ibm_pi_network_port.go new file mode 100644 index 000000000..703686eb0 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_port.go @@ -0,0 +1,211 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func ResourceIBMPINetworkPort() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPINetworkPortCreate, + ReadContext: resourceIBMPINetworkPortRead, + UpdateContext: resourceIBMPINetworkPortUpdate, + DeleteContext: resourceIBMPINetworkPortDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + helpers.PINetworkName: { + Type: schema.TypeString, + Required: true, + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + }, + helpers.PINetworkPortDescription: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + helpers.PINetworkPortIPAddress: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + //Computed Attributes + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "portid": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "public_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + DeprecationMessage: "Resource ibm_pi_network_port is deprecated. Use ibm_pi_network_port_attach to create & attach a network port to a pvm instance", + } +} + +func resourceIBMPINetworkPortCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + networkname := d.Get(helpers.PINetworkName).(string) + description := d.Get(helpers.PINetworkPortDescription).(string) + + ipaddress := d.Get(helpers.PINetworkPortIPAddress).(string) + + nwportBody := &models.NetworkPortCreate{Description: description} + + if ipaddress != "" { + log.Printf("IP address provided. ") + nwportBody.IPAddress = ipaddress + } + + client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + + networkPortResponse, err := client.CreatePort(networkname, nwportBody) + if err != nil { + return diag.FromErr(err) + } + + log.Printf("Printing the networkresponse %+v", &networkPortResponse) + + IBMPINetworkPortID := *networkPortResponse.PortID + + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, networkname, IBMPINetworkPortID)) + + _, err = isWaitForIBMPINetworkPortAvailable(ctx, client, IBMPINetworkPortID, networkname, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPINetworkPortRead(ctx, d, meta) +} + +func resourceIBMPINetworkPortRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + + networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.GetPort(networkname, portID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(helpers.PINetworkPortIPAddress, networkdata.IPAddress) + d.Set(helpers.PINetworkPortDescription, networkdata.Description) + d.Set("macaddress", networkdata.MacAddress) + d.Set("status", networkdata.Status) + d.Set("portid", networkdata.PortID) + d.Set("public_ip", networkdata.ExternalIP) + + return nil +} + +func resourceIBMPINetworkPortUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func resourceIBMPINetworkPortDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + log.Printf("Calling the network delete functions. ") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + + client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + + log.Printf("Calling the delete with the following params delete with cloud instance (%s) and networkid (%s) and portid (%s) ", cloudInstanceID, networkname, portID) + err = client.DeletePort(networkname, portID) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func isWaitForIBMPINetworkPortAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, networkname string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PINetworkProvisioning}, + Target: []string{"DOWN"}, + Refresh: isIBMPINetworkPortRefreshFunc(client, id, networkname), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkPortRefreshFunc(client *st.IBMPINetworkClient, id, networkname string) resource.StateRefreshFunc { + + log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) + return func() (interface{}, string, error) { + network, err := client.GetPort(networkname, id) + if err != nil { + return nil, "", err + } + + if &network.PortID != nil { + //if network.State == "available" { + log.Printf(" The port has been created with the following ip address and attached to an instance ") + return network, "DOWN", nil + } + + return network, helpers.PINetworkProvisioning, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_port_attach.go b/ibm/service/power/resource_ibm_pi_network_port_attach.go new file mode 100644 index 000000000..b6dd30576 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_port_attach.go @@ -0,0 +1,269 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPINetworkPortAttach() *schema.Resource { + return &schema.Resource{ + + CreateContext: resourceIBMPINetworkPortAttachCreate, + ReadContext: resourceIBMPINetworkPortAttachRead, + DeleteContext: resourceIBMPINetworkPortAttachDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + helpers.PIInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance id to attach the network port to", + }, + helpers.PINetworkName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Network Name - This is the subnet name in the Cloud instance", + }, + helpers.PINetworkPortDescription: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "A human readable description for this network Port", + Default: "Port Created via Terraform", + }, + helpers.PINetworkPortIPAddress: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + + //Computed Attributes + "macaddress": { + Type: schema.TypeString, + Computed: true, + }, + "port_id": { + Type: schema.TypeString, + Computed: true, + Deprecated: "port_id attribute is deprecated, use network_port_id instead.", + }, + "network_port_id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "public_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + } + +} + +func resourceIBMPINetworkPortAttachCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + networkname := d.Get(helpers.PINetworkName).(string) + instanceID := d.Get(helpers.PIInstanceId).(string) + description := d.Get(helpers.PINetworkPortDescription).(string) + nwportBody := &models.NetworkPortCreate{Description: description} + + if v, ok := d.GetOk(helpers.PINetworkPortIPAddress); ok { + ipaddress := v.(string) + nwportBody.IPAddress = ipaddress + } + + nwportattachBody := &models.NetworkPortUpdate{ + Description: &description, + PvmInstanceID: &instanceID, + } + + client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + + networkPortResponse, err := client.CreatePort(networkname, nwportBody) + if err != nil { + return diag.FromErr(err) + } + + log.Printf("Printing the networkresponse %+v", &networkPortResponse) + + networkPortID := *networkPortResponse.PortID + + _, err = isWaitForIBMPINetworkportAvailable(ctx, client, networkPortID, networkname, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + networkPortResponse, err = client.UpdatePort(networkname, networkPortID, nwportattachBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForIBMPINetworkPortAttachAvailable(ctx, client, networkPortID, networkname, instanceID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, networkname, networkPortID)) + + return resourceIBMPINetworkPortAttachRead(ctx, d, meta) +} + +func resourceIBMPINetworkPortAttachRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + + networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.GetPort(networkname, portID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(helpers.PINetworkPortIPAddress, networkdata.IPAddress) + d.Set(helpers.PINetworkPortDescription, networkdata.Description) + d.Set(helpers.PIInstanceId, networkdata.PvmInstance.PvmInstanceID) + d.Set("macaddress", networkdata.MacAddress) + d.Set("status", networkdata.Status) + d.Set("network_port_id", networkdata.PortID) + d.Set("port_id", networkdata.PortID) + d.Set("public_ip", networkdata.ExternalIP) + + return nil +} + +func resourceIBMPINetworkPortAttachDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + log.Printf("Calling the network delete functions. ") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + + client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) + + log.Printf("Calling the delete with the following params delete with cloud instance (%s) and networkid (%s) and portid (%s) ", cloudInstanceID, networkname, portID) + err = client.DeletePort(networkname, portID) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func isWaitForIBMPINetworkportAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, networkname string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PINetworkProvisioning}, + Target: []string{"DOWN"}, + Refresh: isIBMPINetworkportRefreshFunc(client, id, networkname), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkportRefreshFunc(client *st.IBMPINetworkClient, id, networkname string) resource.StateRefreshFunc { + + log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) + return func() (interface{}, string, error) { + network, err := client.GetPort(networkname, id) + if err != nil { + return nil, "", err + } + + if *network.Status == "DOWN" { + log.Printf(" The port has been created with the following ip address and attached to an instance ") + return network, "DOWN", nil + } + + return network, helpers.PINetworkProvisioning, nil + } +} +func isWaitForIBMPINetworkPortAttachAvailable(ctx context.Context, client *st.IBMPINetworkClient, id, networkname, instanceid string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PINetworkProvisioning}, + Target: []string{"ACTIVE"}, + Refresh: isIBMPINetworkPortAttachRefreshFunc(client, id, networkname, instanceid), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPINetworkPortAttachRefreshFunc(client *st.IBMPINetworkClient, id, networkname, instanceid string) resource.StateRefreshFunc { + + log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) + return func() (interface{}, string, error) { + network, err := client.GetPort(networkname, id) + if err != nil { + return nil, "", err + } + + if *network.Status == "ACTIVE" && network.PvmInstance.PvmInstanceID == instanceid { + log.Printf(" The port has been created with the following ip address and attached to an instance ") + return network, "ACTIVE", nil + } + + return network, helpers.PINetworkProvisioning, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_network_port_attach_test.go b/ibm/service/power/resource_ibm_pi_network_port_attach_test.go new file mode 100644 index 000000000..798080860 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_port_attach_test.go @@ -0,0 +1,145 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPINetworkPortAttachbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-port-attach-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkPortAttachDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPortAttachConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkPortAttachExists("ibm_pi_network_port_attach.power_network_port_attach"), + resource.TestCheckResourceAttr( + "ibm_pi_network_port_attach.power_network_port_attach", "pi_network_name", name), + resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "network_port_id"), + resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "public_ip"), + ), + }, + }, + }) +} + +func TestAccIBMPINetworkPortAttachVlanbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-port-attach-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkPortAttachDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPortAttachVlanConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkPortAttachExists("ibm_pi_network_port_attach.power_network_port_attach"), + resource.TestCheckResourceAttr( + "ibm_pi_network_port_attach.power_network_port_attach", "pi_network_name", name), + resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network_port_attach.power_network_port_attach", "network_port_id"), + ), + }, + }, + }) +} +func testAccCheckIBMPINetworkPortAttachDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_network_port_attach" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + networkC := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + _, err = networkC.GetPort(networkname, portID) + if err == nil { + return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPINetworkPortAttachExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + client := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + + _, err = client.GetPort(networkname, portID) + if err != nil { + return err + } + return nil + + } +} + +func testAccCheckIBMPINetworkPortAttachConfig(name string) string { + return testAccCheckIBMPINetworkConfig(name) + fmt.Sprintf(` + resource "ibm_pi_network_port_attach" "power_network_port_attach" { + pi_cloud_instance_id = "%s" + pi_network_name = ibm_pi_network.power_networks.pi_network_name + pi_network_port_description = "IP Reserved for Test UAT" + pi_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name) +} + +func testAccCheckIBMPINetworkPortAttachVlanConfig(name string) string { + return testAccCheckIBMPINetworkGatewayConfig(name) + fmt.Sprintf(` + resource "ibm_pi_network_port_attach" "power_network_port_attach" { + pi_cloud_instance_id = "%s" + pi_network_name = ibm_pi_network.power_networks.pi_network_name + pi_network_port_description = "IP Reserved for Test UAT" + pi_instance_id = "%s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name) +} diff --git a/ibm/service/power/resource_ibm_pi_network_port_test.go b/ibm/service/power/resource_ibm_pi_network_port_test.go new file mode 100644 index 000000000..65f72d716 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_port_test.go @@ -0,0 +1,109 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPINetworkPortbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-port-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkPortDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPortConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkPortExists("ibm_pi_network_port.power_network_port"), + resource.TestCheckResourceAttr( + "ibm_pi_network_port.power_network_port", "pi_network_name", name), + ), + }, + }, + }) +} +func testAccCheckIBMPINetworkPortDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_network_port" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + networkC := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + _, err = networkC.GetPort(networkname, portID) + if err == nil { + return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPINetworkPortExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID := parts[0] + networkname := parts[1] + portID := parts[2] + client := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + + _, err = client.GetPort(networkname, portID) + if err != nil { + return err + } + return nil + + } +} + +func testAccCheckIBMPINetworkPortConfig(name string) string { + return testAccCheckIBMPINetworkConfig(name) + fmt.Sprintf(` + resource "ibm_pi_network_port" "power_network_port" { + pi_cloud_instance_id = "%s" + pi_network_name = ibm_pi_network.power_networks.pi_network_name + pi_network_port_description = "IP Reserved for Test UAT" + } + `, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/resource_ibm_pi_network_test.go b/ibm/service/power/resource_ibm_pi_network_test.go new file mode 100644 index 000000000..517bf8711 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_network_test.go @@ -0,0 +1,192 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPINetworkbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_gateway"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_ipaddress_range.#"), + ), + }, + { + Config: testAccCheckIBMPINetworkConfigUpdateDNS(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_dns.#", "1"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_gateway"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_ipaddress_range.#"), + ), + }, + }, + }) +} +func TestAccIBMPINetworkGatewaybasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkGatewayConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_gateway"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_ipaddress_range.#"), + ), + }, + { + Config: testAccCheckIBMPINetworkConfigGatewayUpdateDNS(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_gateway", "192.168.17.2"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_ipaddress_range.0.pi_ending_ip_address", "192.168.17.254"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_ipaddress_range.0.pi_starting_ip_address", "192.168.17.3"), + ), + }, + }, + }) +} +func testAccCheckIBMPINetworkDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_network" { + continue + } + cloudInstanceID, networkID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + networkC := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + _, err = networkC.Get(networkID) + if err == nil { + return fmt.Errorf("PI Network still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPINetworkExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, networkID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(networkID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPINetworkConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "pub-vlan" + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPINetworkConfigUpdateDNS(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "pub-vlan" + pi_dns = ["127.0.0.1"] + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPINetworkGatewayConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "vlan" + pi_cidr = "192.168.17.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPINetworkConfigGatewayUpdateDNS(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "vlan" + pi_dns = ["127.0.0.1"] + pi_gateway = "192.168.17.2" + pi_cidr = "192.168.17.0/24" + pi_ipaddress_range { + pi_ending_ip_address = "192.168.17.254" + pi_starting_ip_address = "192.168.17.3" + } + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_placement_group.go b/ibm/service/power/resource_ibm_pi_placement_group.go new file mode 100644 index 000000000..5adfbcaf5 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_placement_group.go @@ -0,0 +1,151 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + models "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func ResourceIBMPIPlacementGroup() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIPlacementGroupCreate, + ReadContext: resourceIBMPIPlacementGroupRead, + UpdateContext: resourceIBMPIPlacementGroupUpdate, + DeleteContext: resourceIBMPIPlacementGroupDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + helpers.PIPlacementGroupName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the placement group", + }, + + helpers.PIPlacementGroupPolicy: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity"}), + Description: "Policy of the placement group", + }, + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + + PIPlacementGroupMembers: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Server IDs that are the placement group members", + }, + + PIPlacementGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "PI placement group ID", + }, + }, + } +} + +func resourceIBMPIPlacementGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(helpers.PIPlacementGroupName).(string) + policy := d.Get(helpers.PIPlacementGroupPolicy).(string) + client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + body := &models.PlacementGroupCreate{ + Name: &name, + Policy: &policy, + } + + response, err := client.Create(body) + if err != nil || response == nil { + return diag.FromErr(fmt.Errorf("error creating the shared processor pool: %s", err)) + } + + log.Printf("Printing the placement group %+v", &response) + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *response.ID)) + return resourceIBMPIPlacementGroupRead(ctx, d, meta) +} + +func resourceIBMPIPlacementGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(parts[1]) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.Set(helpers.PIPlacementGroupName, response.Name) + d.Set(PIPlacementGroupID, response.ID) + d.Set(helpers.PIPlacementGroupPolicy, response.Policy) + d.Set(PIPlacementGroupMembers, response.Members) + + return nil + +} + +func resourceIBMPIPlacementGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return resourceIBMPIPlacementGroupRead(ctx, d, meta) +} + +func resourceIBMPIPlacementGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + err = client.Delete(parts[1]) + + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_placement_group_test.go b/ibm/service/power/resource_ibm_pi_placement_group_test.go new file mode 100644 index 000000000..aa2f953bc --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_placement_group_test.go @@ -0,0 +1,615 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func TestAccIBMPIPlacementGroupBasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-placement-group-%d", acctest.RandIntRange(10, 100)) + policy := "affinity" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIPlacementGroupConfig(name, policy), + ResourceName: "ibm_pi_placement_group.power_placement_group", + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIPlacementGroupExists("ibm_pi_placement_group.power_placement_group"), + resource.TestCheckResourceAttr( + "ibm_pi_placement_group.power_placement_group", "pi_placement_group_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_placement_group.power_placement_group", "pi_placement_group_policy", policy), + resource.TestCheckNoResourceAttr( + "ibm_pi_placement_group.power_placement_group", "members"), + ), + }, + { + Config: testAccCheckIBMPIPlacementGroupAddMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "ibm_pi_instance.power_instance", "pi_placement_group_id"), + testAccCheckIBMPIPlacementGroupMemberExists("ibm_pi_placement_group.power_placement_group", "ibm_pi_instance.power_instance"), + ), + }, + { + Config: testAccCheckIBMPIPlacementGroupUpdateMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "ibm_pi_instance.power_instance", "pi_placement_group_id"), + testAccCheckIBMPIPlacementGroupMemberExists("ibm_pi_placement_group.power_placement_group_another", "ibm_pi_instance.power_instance"), + ), + }, + { + Config: testAccCheckIBMPIPlacementGroupRemoveMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIPlacementGroupMemberDoesNotExist("ibm_pi_placement_group.power_placement_group", "ibm_pi_instance.power_instance"), + ), + }, + { + Config: testAccCheckIBMPICreateInstanceInPlacementGroup(name, policy, "tinytest-1x4"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "ibm_pi_instance.power_instance", "pi_placement_group_id"), + resource.TestCheckResourceAttrSet( + "ibm_pi_instance.power_instance_in_pg", "pi_placement_group_id"), + resource.TestCheckResourceAttrSet( + "ibm_pi_instance.sap_power_instance", "pi_placement_group_id"), + testAccCheckIBMPIPlacementGroupMemberExistsFromInstanceCreate("ibm_pi_placement_group.power_placement_group", "ibm_pi_instance.power_instance", "ibm_pi_instance.power_instance_in_pg"), + testAccCheckIBMPIPlacementGroupMemberExists("ibm_pi_placement_group.power_placement_group", "ibm_pi_instance.sap_power_instance"), + ), + }, + { + Config: testAccCheckIBMPIDeletePlacementGroup(name, policy, "tinytest-1x4"), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIPlacementGroupDelete("ibm_pi_placement_group.power_placement_group", "ibm_pi_instance.power_instance", "ibm_pi_instance.power_instance_in_pg"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIPlacementGroupDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_placement_group" { + continue + } + parts, _ := flex.IdParts(rs.Primary.ID) + cloudinstanceid := parts[0] + placementGroupC := st.NewIBMPIPlacementGroupClient(context.Background(), sess, cloudinstanceid) + _, err = placementGroupC.Get(parts[1]) + if err == nil { + return fmt.Errorf("PI placement group still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIPlacementGroupExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudinstanceid := parts[0] + client := st.NewIBMPIPlacementGroupClient(context.Background(), sess, cloudinstanceid) + + placementGroup, err := client.Get(parts[1]) + if err != nil { + return err + } + parts[1] = *placementGroup.ID + return nil + } +} + +func testAccCheckIBMPIPlacementGroupMemberExists(n string, instance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a server should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudinstanceid := parts[0] + client := st.NewIBMPIPlacementGroupClient(context.Background(), sess, cloudinstanceid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + instancers, ok := s.RootModule().Resources[instance] + if !ok { + return fmt.Errorf("Not found: %s", instance) + } + instanceParts, err := flex.IdParts(instancers.Primary.ID) + if err != nil { + return err + } + var isInstanceFound bool = false + for _, x := range pg.Members { + if x == instanceParts[1] { + isInstanceFound = true + break + } + } + if !isInstanceFound { + return fmt.Errorf("Expected server ID %s in the PG members field but found %s", instanceParts[1], strings.Join(pg.Members[:], ",")) + } + return nil + } +} + +func testAccCheckIBMPIPlacementGroupMemberDoesNotExist(n string, instance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a server should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudinstanceid := parts[0] + client := st.NewIBMPIPlacementGroupClient(context.Background(), sess, cloudinstanceid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + instancers, ok := s.RootModule().Resources[instance] + if !ok { + return fmt.Errorf("Not found: %s", instance) + } + instanccParts, err := flex.IdParts(instancers.Primary.ID) + if err != nil { + return err + } + if len(pg.Members) > 0 { + return fmt.Errorf("Expected server ID %s to be removed so that the PG members field is empty but foumd %s", instanccParts[1], pg.Members[0]) + } + + return nil + } +} + +func containsMember(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + + return false +} + +func testAccCheckIBMPIPlacementGroupMemberExistsFromInstanceCreate(n string, instance string, newInstance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a server should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudinstanceid := parts[0] + client := st.NewIBMPIPlacementGroupClient(context.Background(), sess, cloudinstanceid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + instancers, ok := s.RootModule().Resources[instance] + if !ok { + return fmt.Errorf("Not found: %s", instance) + } + instanceParts, err := flex.IdParts(instancers.Primary.ID) + if err != nil { + return err + } + + newinstancers, ok := s.RootModule().Resources[newInstance] + if !ok { + return fmt.Errorf("Not found: %s", newInstance) + } + newinstanceParts, err := flex.IdParts(newinstancers.Primary.ID) + if err != nil { + return err + } + + if !containsMember(pg.Members, instanceParts[1]) { + return fmt.Errorf("Expected server ID %s in the PG members field", instanceParts[1]) + } + if !containsMember(pg.Members, newinstanceParts[1]) { + return fmt.Errorf("Expected new server ID %s in the PG members field", newinstanceParts[1]) + } + return nil + } +} + +func testAccCheckIBMPIPlacementGroupDelete(n string, instance string, newInstance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + instancers, ok := s.RootModule().Resources[instance] + if !ok { + return fmt.Errorf("Not found: %s", instance) + } + instanceParts, err := flex.IdParts(instancers.Primary.ID) + if err != nil { + return err + } + + newinstancers, ok := s.RootModule().Resources[newInstance] + if !ok { + return fmt.Errorf("Not found: %s", newInstance) + } + newinstanceParts, err := flex.IdParts(newinstancers.Primary.ID) + if err != nil { + return err + } + cloudinstanceid := instanceParts[0] + inst_client := st.NewIBMPIInstanceClient(context.Background(), sess, cloudinstanceid) + + instance, err := inst_client.Get(instanceParts[1]) + if err != nil { + return err + } + + if *instance.PlacementGroup != "none" { + return fmt.Errorf("Expected no placement group ID in the PVM instance data but found %s", *instance.PlacementGroup) + } + newinstance, err := inst_client.Get(newinstanceParts[1]) + if err != nil { + return err + } + if *newinstance.PlacementGroup != "none" { + return fmt.Errorf("Expected no placement group ID in the PVM instance data but found %s", *newinstance.PlacementGroup) + } + return nil + } +} + +func testAccCheckIBMPIPlacementGroupConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[5]s" + } + } + resource "ibm_pi_placement_group" "power_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPIPlacementGroupAddMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[5]s" + } + pi_placement_group_id = ibm_pi_placement_group.power_placement_group.placement_group_id + } + + resource "ibm_pi_placement_group" "power_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPIPlacementGroupUpdateMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[5]s" + } + pi_placement_group_id = ibm_pi_placement_group.power_placement_group_another.placement_group_id + } + + resource "ibm_pi_placement_group" "power_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s" + pi_placement_group_policy = "%[3]s" + } + + resource "ibm_pi_placement_group" "power_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s-2" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPIPlacementGroupRemoveMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[5]s" + } + pi_placement_group_id = "" + } + + resource "ibm_pi_placement_group" "power_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s" + pi_placement_group_policy = "%[3]s" + } + + resource "ibm_pi_placement_group" "power_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s-2" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPICreateInstanceInPlacementGroup(name string, policy string, sapProfile string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[7]s" + } + pi_placement_group_id = ibm_pi_placement_group.power_placement_group.placement_group_id + } + + resource "ibm_pi_instance" "power_instance_in_pg" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s-2" + pi_cloud_instance_id = "%[1]s" + pi_network { + network_id = "%[7]s" + } + pi_placement_group_id = ibm_pi_placement_group.power_placement_group.placement_group_id + } + + resource "ibm_pi_instance" "sap_power_instance" { + pi_cloud_instance_id = "%[1]s" + pi_instance_name = "sap-%[2]s" + pi_sap_profile_id = "%[5]s" + pi_image_id = "%[6]s" + pi_storage_type = "tier1" + pi_network { + network_id = "%[7]s" + } + pi_placement_group_id = ibm_pi_placement_group.power_placement_group.placement_group_id + depends_on = [ ibm_pi_instance.power_instance_in_pg ] + } + + resource "ibm_pi_placement_group" "power_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s" + pi_placement_group_policy = "%[3]s" + } + + resource "ibm_pi_placement_group" "power_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s-2" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, sapProfile, acc.Pi_sap_image, acc.Pi_network_name) +} + +func testAccCheckIBMPIDeletePlacementGroup(name string, policy string, sapProfile string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKUt7bk9yLBZFC187bQJFuLaBZONKFYjeIGCZj5mN0OvaJdJqPN2Mbx9Ui42Y5vrLE7SipG5c94BS/fYf7e2LvsQ+xaU1VQnMvP6XS8emoyKR6q/YzD60MkvkSopwTAgpyf6CpfCsKE5Yclbrsc1HIP16bjSgOapfgaVuEDXifn27i1fP1QRYhosY7YkfSKjyJQihxnFH1sONdl4JspJDC5rp8wZ4E7jSXyaZh6QIMbMBEvKoE8+/8CUgT3EWWndIOIMuPQtills3X3jDojTt722OBW1qETPahYDDEmN00R1Q1Q8V8pfVi1XG+ESLzY93gC8hV+/lWIoIvSEazwkfi7/5kludrZG1RhCGbOffGo3DkrmtqaBbKbjrTh/ZbY0GzHPXqccfW/KIhk6xlmoR0wF9LYPtFuzTkqnHF/tHi8EXPHI5XVv9m01kMLkoUqtWVXP2O7ZM7EwrJ+1TyJqLTrzbKMUbn52GqNuTSFJCAgEVc3XrvIRFjTL1/b428mS9JV5kCfRVLmDAUtPjuaQg1wmI/W97gZCF8IoF4JXWTEQP8IIb2opLxvEoBggsZpiFOtjsr9A914i/Tyd4T4KlvfkavJXqkzQoj29oZZPt10gt2ywwXPvV6usM1iofATB+YtX6vl8wUDaqvEyC8d4OTnSVkPZnFxTG3lhY4cDwa/w== tedfordt@us.ibm.com" + } + + resource "ibm_pi_instance" "power_instance" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[1]s" + pi_storage_type = "tier3" + pi_network { + network_id = "%[7]s" + } + } + + resource "ibm_pi_instance" "power_instance_in_pg" { + pi_processors = "0.25" + pi_proc_type = "shared" + pi_memory = "2" + pi_key_pair_name = ibm_pi_key.key.key_id + pi_image_id = "%[4]s" + pi_sys_type = "e980" + pi_instance_name = "%[2]s-2" + pi_cloud_instance_id = "%[1]s" + pi_network { + network_id = "%[7]s" + } + } + + resource "ibm_pi_instance" "sap_power_instance" { + pi_cloud_instance_id = "%[1]s" + pi_instance_name = "sap-%[2]s" + pi_sap_profile_id = "%[5]s" + pi_image_id = "%[6]s" + pi_storage_type = "tier1" + pi_network { + network_id = "%[7]s" + } + depends_on = [ ibm_pi_instance.power_instance_in_pg ] + } + + resource "ibm_pi_placement_group" "power_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_placement_group_name = "%[2]s-2" + pi_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, sapProfile, acc.Pi_sap_image, acc.Pi_network_name) +} diff --git a/ibm/service/power/resource_ibm_pi_shared_processor_pool.go b/ibm/service/power/resource_ibm_pi_shared_processor_pool.go new file mode 100644 index 000000000..9522d7f90 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_shared_processor_pool.go @@ -0,0 +1,427 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + models "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPISharedProcessorPool() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPISharedProcessorPoolCreate, + ReadContext: resourceIBMPISharedProcessorPoolRead, + UpdateContext: resourceIBMPISharedProcessorPoolUpdate, + DeleteContext: resourceIBMPISharedProcessorPoolDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + // Required Arguments + Arg_SharedProcessorPoolName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the shared processor pool", + }, + + Arg_SharedProcessorPoolHostGroup: { + Type: schema.TypeString, + Required: true, + Description: "Host group of the shared processor pool", + }, + + Arg_SharedProcessorPoolReservedCores: { + Type: schema.TypeInt, + Required: true, + Description: "The amount of reserved cores for the shared processor pool", + }, + + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + + // Optional Arguments + Arg_SharedProcessorPoolPlacementGroupID: { + Type: schema.TypeString, + Optional: true, + Description: "Placement group the shared processor pool is created in", + }, + + // Attributes + Attr_SharedProcessorPoolID: { + Type: schema.TypeString, + Computed: true, + Description: "Shared processor pool ID", + }, + + Attr_SharedProcessorPoolAvailableCores: { + Type: schema.TypeInt, + Computed: true, + Description: "Shared processor pool available cores", + }, + + Attr_SharedProcessorPoolAllocatedCores: { + Type: schema.TypeFloat, + Computed: true, + Description: "Shared processor pool allocated cores", + }, + + Attr_SharedProcessorPoolHostID: { + Type: schema.TypeInt, + Computed: true, + Description: "The host ID where the shared processor pool resides", + }, + + Attr_SharedProcessorPoolStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the shared processor pool", + }, + + Attr_SharedProcessorPoolStatusDetail: { + Type: schema.TypeString, + Computed: true, + Description: "The status details of the shared processor pool", + }, + + Attr_SharedProcessorPoolPlacementGroups: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "SPP placement groups the shared processor pool are in", + }, + + Attr_SharedProcessorPoolInstances: { + Type: schema.TypeList, + Computed: true, + Description: "List of server instances deployed in the shared processor pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SharedProcessorPoolInstanceCpus: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of cpus for the server instance", + }, + Attr_SharedProcessorPoolInstanceUncapped: { + Type: schema.TypeBool, + Computed: true, + Description: "Identifies if uncapped or not", + }, + Attr_SharedProcessorPoolInstanceAvailabilityZone: { + Type: schema.TypeString, + Computed: true, + Description: "Availability zone for the server instances", + }, + Attr_SharedProcessorPoolInstanceId: { + Type: schema.TypeString, + Computed: true, + Description: "The server instance ID", + }, + Attr_SharedProcessorPoolInstanceMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of memory for the server instance", + }, + Attr_SharedProcessorPoolInstanceName: { + Type: schema.TypeString, + Computed: true, + Description: "The server instance name", + }, + Attr_SharedProcessorPoolInstanceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Status of the server", + }, + Attr_SharedProcessorPoolInstanceVcpus: { + Type: schema.TypeFloat, + Computed: true, + Description: "The amout of vcpus for the server instance", + }, + }, + }, + }, + }, + } +} + +func resourceIBMPISharedProcessorPoolCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(Arg_SharedProcessorPoolName).(string) + hostGroup := d.Get(Arg_SharedProcessorPoolHostGroup).(string) + reservedCores := d.Get(Arg_SharedProcessorPoolReservedCores).(int) + cores := int64(reservedCores) + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + body := &models.SharedProcessorPoolCreate{ + Name: &name, + HostGroup: &hostGroup, + ReservedCores: &cores, + } + + if pg, ok := d.GetOk(Arg_SharedProcessorPoolPlacementGroupID); ok { + body.PlacementGroupID = pg.(string) + } + + spp, err := client.Create(body) + if err != nil || spp == nil { + return diag.Errorf("error creating the shared processor pool: %v", err) + } + + var sharedProcessorPoolReadyStatus string + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *spp.ID)) + _, err = isWaitForPISharedProcessorPoolAvailable(ctx, d, client, *spp.ID, sharedProcessorPoolReadyStatus) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPISharedProcessorPoolRead(ctx, d, meta) + +} + +func isWaitForPISharedProcessorPoolAvailable(ctx context.Context, d *schema.ResourceData, client *st.IBMPISharedProcessorPoolClient, id string, sharedProcessorPoolReadyStatus string) (interface{}, error) { + log.Printf("Waiting for PISharedProcessorPool (%s) to be active ", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"configuring"}, + Target: []string{"active", "failed", ""}, + Refresh: isPISharedProcessorPoolRefreshFunc(client, id, sharedProcessorPoolReadyStatus), + Delay: 20 * time.Second, + MinTimeout: activeTimeOut, + Timeout: d.Timeout(schema.TimeoutCreate), + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPISharedProcessorPoolRefreshFunc(client *st.IBMPISharedProcessorPoolClient, id, sharedProcessorPoolReadyStatus string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + pool, err := client.Get(id) + if err != nil { + return nil, "", err + } + // Check for `sharedProcessorPoolReadyStatus` status + if pool.SharedProcessorPool.Status == "active" { + return pool, "active", nil + } + if pool.SharedProcessorPool.Status == "failed" { + err = fmt.Errorf("failed to create the shared processor pool") + return pool, pool.SharedProcessorPool.Status, err + } + + return pool, "configuring", nil + } +} + +func resourceIBMPISharedProcessorPoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(parts[1]) + if err != nil || response == nil { + return diag.Errorf("error reading the shared processor pool: %v", err) + } + + d.Set(Arg_CloudInstanceID, cloudInstanceID) + d.Set(Arg_SharedProcessorPoolHostGroup, response.SharedProcessorPool.HostGroup) + + if response.SharedProcessorPool.Name != nil { + d.Set(Arg_SharedProcessorPoolName, response.SharedProcessorPool.Name) + } + if response.SharedProcessorPool.ID != nil { + d.Set(Attr_SharedProcessorPoolID, response.SharedProcessorPool.ID) + } + if response.SharedProcessorPool.ReservedCores != nil { + d.Set(Arg_SharedProcessorPoolReservedCores, response.SharedProcessorPool.ReservedCores) + } + if response.SharedProcessorPool.AllocatedCores != nil { + d.Set(Attr_SharedProcessorPoolAllocatedCores, response.SharedProcessorPool.AllocatedCores) + } + if response.SharedProcessorPool.AvailableCores != nil { + d.Set(Attr_SharedProcessorPoolAvailableCores, response.SharedProcessorPool.AvailableCores) + } + if response.SharedProcessorPool.AvailableCores != nil { + d.Set(Attr_SharedProcessorPoolAvailableCores, response.SharedProcessorPool.AvailableCores) + } + if response.SharedProcessorPool.SharedProcessorPoolPlacementGroups != nil { + pgIDs := make([]string, len(response.SharedProcessorPool.SharedProcessorPoolPlacementGroups)) + for i, pg := range response.SharedProcessorPool.SharedProcessorPoolPlacementGroups { + pgIDs[i] = *pg.ID + } + d.Set(Attr_SharedProcessorPoolPlacementGroups, pgIDs) + } + d.Set(Attr_SharedProcessorPoolHostID, response.SharedProcessorPool.HostID) + d.Set(Attr_SharedProcessorPoolStatus, response.SharedProcessorPool.Status) + d.Set(Attr_SharedProcessorPoolStatusDetail, response.SharedProcessorPool.StatusDetail) + + serversMap := []map[string]interface{}{} + if response.Servers != nil { + for _, s := range response.Servers { + if s != nil { + v := map[string]interface{}{ + Attr_SharedProcessorPoolInstanceCpus: s.Cpus, + Attr_SharedProcessorPoolInstanceUncapped: s.Uncapped, + Attr_SharedProcessorPoolInstanceAvailabilityZone: s.AvailabilityZone, + Attr_SharedProcessorPoolInstanceId: s.ID, + Attr_SharedProcessorPoolInstanceMemory: s.Memory, + Attr_SharedProcessorPoolInstanceName: s.Name, + Attr_SharedProcessorPoolInstanceStatus: s.Status, + Attr_SharedProcessorPoolInstanceVcpus: s.Vcpus, + } + serversMap = append(serversMap, v) + } + } + } + d.Set(Attr_SharedProcessorPoolInstances, serversMap) + + return nil +} + +func resourceIBMPISharedProcessorPoolUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, sppID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + body := &models.SharedProcessorPoolUpdate{} + + if d.HasChange(Arg_SharedProcessorPoolName) { + name := d.Get(Arg_SharedProcessorPoolName).(string) + body.Name = name + } + if d.HasChange(Arg_SharedProcessorPoolReservedCores) { + reservedCores := int64(d.Get(Arg_SharedProcessorPoolReservedCores).(int)) + body.ReservedCores = reservedCores + } + + _, err = client.Update(sppID, body) + if err != nil { + return diag.Errorf("error updating the shared processor pool: %v", err) + } + + if d.HasChange(Attr_SharedProcessorPoolPlacementGroups) { + + pgClient := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + + oldRaw, newRaw := d.GetChange(Attr_SharedProcessorPoolPlacementGroups) + old := oldRaw.([]interface{}) + new := newRaw.([]interface{}) + + var oldPGs []string + for _, o := range old { + oldPGs = append(oldPGs, o.(string)) + } + var newPGs []string + for _, n := range new { + newPGs = append(newPGs, n.(string)) + } + // find removed pgs and remove them + pgsToRemove := getDifferences(oldPGs, newPGs) + + for _, pgToRemove := range pgsToRemove { + if len(strings.TrimSpace(pgToRemove)) > 0 { + placementGroupID := pgToRemove + //remove spp from old placement group + _, err := pgClient.DeleteMember(placementGroupID, sppID) + if err != nil { + // ignore delete member error where the spp is already not in the PG + if !strings.Contains(err.Error(), "is not part of spp placement group") { + return diag.FromErr(err) + } + } + } + } + + // find added pgs and then add them + pgsToAdd := getDifferences(newPGs, oldPGs) + + for _, pgToAdd := range pgsToAdd { + if len(strings.TrimSpace(pgToAdd)) > 0 { + placementGroupID := pgToAdd + // add spp to a new placement group + _, err := pgClient.AddMember(placementGroupID, sppID) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + return resourceIBMPISharedProcessorPoolRead(ctx, d, meta) +} + +// returns the elements in string array a that are not in array z +func getDifferences(a, z []string) []string { + mb := make(map[string]struct{}, len(z)) + for _, x := range z { + mb[x] = struct{}{} + } + var diff []string + for _, x := range a { + if _, found := mb[x]; !found { + diff = append(diff, x) + } + } + return diff +} + +func resourceIBMPISharedProcessorPoolDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + err = client.Delete(parts[1]) + + if err != nil { + return diag.Errorf("error deleting the shared processor pool: %v", err) + } + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_snapshot.go b/ibm/service/power/resource_ibm_pi_snapshot.go new file mode 100644 index 000000000..2372e889e --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_snapshot.go @@ -0,0 +1,310 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func ResourceIBMPISnapshot() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPISnapshotCreate, + ReadContext: resourceIBMPISnapshotRead, + UpdateContext: resourceIBMPISnapshotUpdate, + DeleteContext: resourceIBMPISnapshotDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + helpers.PISnapshotName: { + Type: schema.TypeString, + Required: true, + Description: "Unique name of the snapshot", + }, + helpers.PIInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "Instance name / id of the pvm", + }, + helpers.PIInstanceVolumeIds: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of PI volumes", + }, + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: " Cloud Instance ID - This is the service_instance_id.", + }, + "pi_description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the PVM instance snapshot", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Snapshot description", + Deprecated: "This field is deprecated, use pi_description instead", + }, + + // Computed Attributes + helpers.PISnapshot: { + Type: schema.TypeString, + Computed: true, + Description: "Id of the snapshot", + Deprecated: "This field is deprecated, use snapshot_id instead", + }, + "snapshot_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the PVM instance snapshot", + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "creation_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_update_date": { + Type: schema.TypeString, + Computed: true, + }, + "volume_snapshots": { + Type: schema.TypeMap, + Computed: true, + }, + }, + } +} + +func resourceIBMPISnapshotCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + instanceid := d.Get(helpers.PIInstanceName).(string) + volids := flex.ExpandStringList((d.Get(helpers.PIInstanceVolumeIds).(*schema.Set)).List()) + name := d.Get(helpers.PISnapshotName).(string) + + var description string + if v, ok := d.GetOk("description"); ok { + description = v.(string) + } + if v, ok := d.GetOk("pi_description"); ok { + description = v.(string) + } + + client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + snapshotBody := &models.SnapshotCreate{Name: &name, Description: description} + + if len(volids) > 0 { + snapshotBody.VolumeIDs = volids + } else { + log.Printf("no volumeids provided. Will snapshot the entire instance") + } + + snapshotResponse, err := client.CreatePvmSnapShot(instanceid, snapshotBody) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *snapshotResponse.SnapshotID)) + + pisnapclient := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, pisnapclient, *snapshotResponse.SnapshotID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPISnapshotRead(ctx, d, meta) +} + +func resourceIBMPISnapshotRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("Calling the Snapshot Read function post create") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + snapshot := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshotdata, err := snapshot.Get(snapshotID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(helpers.PISnapshotName, snapshotdata.Name) + d.Set(helpers.PISnapshot, *snapshotdata.SnapshotID) + d.Set("snapshot_id", *snapshotdata.SnapshotID) + d.Set("status", snapshotdata.Status) + d.Set("creation_date", snapshotdata.CreationDate.String()) + d.Set("volume_snapshots", snapshotdata.VolumeSnapshots) + d.Set("last_update_date", snapshotdata.LastUpdateDate.String()) + + return nil +} + +func resourceIBMPISnapshotUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + log.Printf("Calling the IBM Power Snapshot update call") + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + + if d.HasChange(helpers.PISnapshotName) || d.HasChange("description") { + name := d.Get(helpers.PISnapshotName).(string) + description := d.Get("description").(string) + snapshotBody := &models.SnapshotUpdate{Name: name, Description: description} + + _, err := client.Update(snapshotID, snapshotBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, client, snapshotID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPISnapshotRead(ctx, d, meta) +} + +func resourceIBMPISnapshotDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshot, err := client.Get(snapshotID) + if err != nil { + // snapshot does not exist + d.SetId("") + return nil + } + + log.Printf("The snapshot to be deleted is in the following state .. %s", snapshot.Status) + + err = client.Delete(snapshotID) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceSnapshotDeleted(ctx, client, snapshotID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} +func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *st.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { + + log.Printf("Waiting for PIInstance Snapshot (%s) to be available and active ", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"in_progress", "BUILD"}, + Target: []string{"available", "ACTIVE"}, + Refresh: isPIInstanceSnapshotRefreshFunc(client, id), + Delay: 30 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceSnapshotRefreshFunc(client *st.IBMPISnapshotClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + snapshotInfo, err := client.Get(id) + if err != nil { + return nil, "", err + } + + //if pvm.Health.Status == helpers.PIInstanceHealthOk { + if snapshotInfo.Status == "available" && snapshotInfo.PercentComplete == 100 { + log.Printf("The snapshot is now available") + return snapshotInfo, "available", nil + + } + return snapshotInfo, "in_progress", nil + } +} + +// Delete Snapshot + +func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *st.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { + + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PIInstanceDeleting}, + Target: []string{"Not Found"}, + Refresh: isPIInstanceSnapshotDeleteRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceSnapshotDeleteRefreshFunc(client *st.IBMPISnapshotClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + snapshot, err := client.Get(id) + if err != nil { + log.Printf("The snapshot is not found.") + return snapshot, helpers.PIInstanceNotFound, nil + } + return snapshot, helpers.PIInstanceNotFound, nil + + } +} diff --git a/ibm/service/power/resource_ibm_pi_snapshot_test.go b/ibm/service/power/resource_ibm_pi_snapshot_test.go new file mode 100644 index 000000000..ccfa59837 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_snapshot_test.go @@ -0,0 +1,108 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" +) + +func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { + + name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) + snapshotRes := "ibm_pi_snapshot.power_snapshot" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceSnapshotConfig(name, helpers.PIInstanceHealthOk), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + resource.TestCheckResourceAttr(snapshotRes, "pi_snap_shot_name", name), + resource.TestCheckResourceAttr(snapshotRes, "status", "available"), + resource.TestCheckResourceAttrSet(snapshotRes, "id"), + ), + }, + }, + }) +} +func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_snapshot" { + continue + } + cloudInstanceID, snapshotID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + snapshotC := st.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + _, err = snapshotC.Get(snapshotID) + if err == nil { + return fmt.Errorf("PI Instance Snapshot still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, snapshotID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(snapshotID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPIInstanceSnapshotConfig(name, healthStatus string) string { + return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` + resource "ibm_pi_snapshot" "power_snapshot"{ + depends_on=[ibm_pi_instance.power_instance] + pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name + pi_cloud_instance_id = "%s" + pi_snap_shot_name = "%s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/power/resource_ibm_pi_spp_placement_group.go b/ibm/service/power/resource_ibm_pi_spp_placement_group.go new file mode 100644 index 000000000..534439fee --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_spp_placement_group.go @@ -0,0 +1,145 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + models "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func ResourceIBMPISPPPlacementGroup() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPISPPPlacementGroupCreate, + ReadContext: resourceIBMPISPPPlacementGroupRead, + DeleteContext: resourceIBMPISPPPlacementGroupDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + Arg_SPPPlacementGroupName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the SPP placement group", + }, + + Arg_SPPPlacementGroupPolicy: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity"}), + Description: "Policy of the SPP placement group", + }, + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "PI cloud instance ID", + }, + + Attr_SPPPlacementGroupMembers: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Member SPP IDs that are the SPP placement group members", + }, + + Attr_SPPPlacementGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "SPP placement group ID", + }, + }, + } +} + +func resourceIBMPISPPPlacementGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(Arg_SPPPlacementGroupName).(string) + policy := d.Get(Arg_SPPPlacementGroupPolicy).(string) + client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + body := &models.SPPPlacementGroupCreate{ + Name: &name, + Policy: &policy, + } + + response, err := client.Create(body) + if err != nil || response == nil { + return diag.Errorf("error creating the spp placement group: %v", err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *response.ID)) + return resourceIBMPISPPPlacementGroupRead(ctx, d, meta) +} + +func resourceIBMPISPPPlacementGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + + response, err := client.Get(parts[1]) + if err != nil || response == nil { + return diag.Errorf("error reading the spp placement group: %v", err) + } + + d.Set(Arg_CloudInstanceID, cloudInstanceID) + d.Set(Arg_SPPPlacementGroupName, response.Name) + d.Set(Attr_SPPPlacementGroupID, response.ID) + d.Set(Arg_SPPPlacementGroupPolicy, response.Policy) + d.Set(Attr_SPPPlacementGroupMembers, response.MemberSharedProcessorPools) + + return nil + +} + +func resourceIBMPISPPPlacementGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + err = client.Delete(parts[1]) + + if err != nil { + return diag.Errorf("error deleting the spp placement group: %v", err) + } + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_spp_placement_group_test.go b/ibm/service/power/resource_ibm_pi_spp_placement_group_test.go new file mode 100644 index 000000000..0df6351a1 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_spp_placement_group_test.go @@ -0,0 +1,666 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func TestAccIBMPISPPPlacementGroupBasic(t *testing.T) { + name := fmt.Sprintf("tfspp%d", acctest.RandIntRange(10, 100)) + policy := "affinity" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPISPPPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICreateSAPInstanceWithSPP(name, policy, "tinytest-1x4"), + ExpectError: regexp.MustCompile("\"pi_shared_processor_pool\": conflicts with pi_sap_profile_id"), + }, + { + Config: testAccCheckIBMPISPPPlacementGroupConfig(name, policy), + ResourceName: "ibm_pi_spp_placement_group.spp_placement_group", + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPISPPPlacementGroupExists("ibm_pi_spp_placement_group.spp_placement_group"), + resource.TestCheckResourceAttr( + "ibm_pi_spp_placement_group.spp_placement_group", "pi_spp_placement_group_name", name+"pg"), + resource.TestCheckResourceAttr( + "ibm_pi_spp_placement_group.spp_placement_group", "pi_spp_placement_group_policy", policy), + ), + }, + { + Config: testAccCheckIBMPISPPPlacementGroupAddMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "ibm_pi_shared_processor_pool.spp_pool", "pi_shared_processor_pool_placement_group_id"), + testAccCheckIBMPISPPPlacementGroupMemberExists("ibm_pi_spp_placement_group.spp_placement_group", "ibm_pi_shared_processor_pool.spp_pool"), + ), + }, + { + Config: testAccCheckIBMPISPPPlacementGroupUpdateMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "ibm_pi_shared_processor_pool.spp_pool", "spp_placement_groups.0"), + testAccCheckIBMPISPPPlacementGroupMemberExists("ibm_pi_spp_placement_group.spp_placement_group_another", "ibm_pi_shared_processor_pool.spp_pool"), + ), + }, + { + Config: testAccCheckIBMPISPPPlacementGroupRemoveMemberConfig(name, policy), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPISPPPlacementGroupMemberDoesNotExist("ibm_pi_spp_placement_group.spp_placement_group", "ibm_pi_shared_processor_pool.spp_pool"), + ), + }, + { + Config: testAccCheckIBMPICreateSPPInPlacementGroup(name, policy), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr( + "ibm_pi_shared_processor_pool.spp_pool", "spp_placement_groups.0"), + resource.TestCheckResourceAttrSet( + "ibm_pi_shared_processor_pool.spp_pool_2", "pi_shared_processor_pool_placement_group_id"), + testAccCheckIBMPISPPPlacementGroupMemberExistsFromSPPCreate("ibm_pi_spp_placement_group.spp_placement_group", "ibm_pi_shared_processor_pool.spp_pool_2"), + ), + }, + { + Config: testAccCheckIBMPIDeleteSPPPlacementGroup(name, policy), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPISPPPlacementGroupDelete("ibm_pi_spp_placement_group.spp_placement_group_another", "ibm_pi_shared_processor_pool.spp_pool", "ibm_pi_shared_processor_pool.spp_pool_2"), + ), + }, + { + Config: testAccCheckIBMPICreateInstanceWithSPP(name, policy), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceInSPP("ibm_pi_shared_processor_pool.spp_pool", "ibm_pi_instance.power_instance"), + ), + }, + }, + }) +} + +func testAccCheckIBMPISPPPlacementGroupDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_spp_placement_group" { + continue + } + parts, _ := flex.IdParts(rs.Primary.ID) + cloudpoolid := parts[0] + placementGroupC := st.NewIBMPISPPPlacementGroupClient(context.Background(), sess, cloudpoolid) + _, err = placementGroupC.Get(parts[1]) + if err == nil { + return fmt.Errorf("PI SPP placement group still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPISPPPlacementGroupExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudpoolid := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(context.Background(), sess, cloudpoolid) + + placementGroup, err := client.Get(parts[1]) + if err != nil { + return err + } + parts[1] = *placementGroup.ID + return nil + } +} + +func testAccCheckIBMPISPPPlacementGroupMemberExists(sppPG string, pool string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + pgResource, ok := s.RootModule().Resources[sppPG] + + if !ok { + return fmt.Errorf("Not found: %s", sppPG) + } + + if pgResource.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a spp should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(pgResource.Primary.ID) + if err != nil { + return err + } + cloudpoolid := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(context.Background(), sess, cloudpoolid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + poolResource, ok := s.RootModule().Resources[pool] + if !ok { + return fmt.Errorf("Not found: %s", pool) + } + poolName := poolResource.Primary.Attributes["pi_shared_processor_pool_name"] + + var isPoolFound bool = false + for _, x := range pg.MemberSharedProcessorPools { + if x == poolName { + isPoolFound = true + break + } + } + if !isPoolFound { + return fmt.Errorf("Expected pool ID %s in the PG members field but found %s", poolName, strings.Join(pg.MemberSharedProcessorPools[:], ",")) + } + return nil + } +} + +func testAccCheckIBMPISPPPlacementGroupMemberDoesNotExist(n string, pool string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a server should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudpoolid := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(context.Background(), sess, cloudpoolid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + poolrs, ok := s.RootModule().Resources[pool] + if !ok { + return fmt.Errorf("Not found: %s", pool) + } + instanccParts, err := flex.IdParts(poolrs.Primary.ID) + if err != nil { + return err + } + if len(pg.MemberSharedProcessorPools) > 0 { + return fmt.Errorf("Expected pool ID %s to be removed so that the PG members field is empty but foumd %s", instanccParts[1], pg.MemberSharedProcessorPools[0]) + } + + return nil + } +} + +func containsMemberPool(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + + return false +} + +func testAccCheckIBMPISPPPlacementGroupMemberExistsFromSPPCreate(n string, pool string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh placement group info since a pool should be in the placement group + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudpoolid := parts[0] + client := st.NewIBMPISPPPlacementGroupClient(context.Background(), sess, cloudpoolid) + + pg, err := client.Get(parts[1]) + if err != nil { + return err + } + + poolrs, ok := s.RootModule().Resources[pool] + if !ok { + return fmt.Errorf("Not found: %s", pool) + } + poolName := poolrs.Primary.Attributes["pi_shared_processor_pool_name"] + + if !containsMemberPool(pg.MemberSharedProcessorPools, poolName) { + return fmt.Errorf("Expected pool %s in the PG members field", poolName) + } + return nil + } +} + +func testAccCheckIBMPISPPPlacementGroupDelete(n string, pool string, newPool string) resource.TestCheckFunc { + return func(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + poolrs, ok := s.RootModule().Resources[pool] + if !ok { + return fmt.Errorf("Not found: %s", pool) + } + poolParts, err := flex.IdParts(poolrs.Primary.ID) + if err != nil { + return err + } + + newpoolrs, ok := s.RootModule().Resources[newPool] + if !ok { + return fmt.Errorf("Not found: %s", newPool) + } + newpoolParts, err := flex.IdParts(newpoolrs.Primary.ID) + if err != nil { + return err + } + cloudpoolid := poolParts[0] + spp_client := st.NewIBMPISharedProcessorPoolClient(context.Background(), sess, cloudpoolid) + + pool, err := spp_client.Get(poolParts[1]) + if err != nil { + return err + } + + if len(pool.SharedProcessorPool.SharedProcessorPoolPlacementGroups) > 0 { + return fmt.Errorf("Expected no spp placement group ID in the spp placement groups array but found %s", *pool.SharedProcessorPool.SharedProcessorPoolPlacementGroups[0].ID) + } + newpool, err := spp_client.Get(newpoolParts[1]) + if err != nil { + return err + } + if len(newpool.SharedProcessorPool.SharedProcessorPoolPlacementGroups) > 0 { + return fmt.Errorf("Expected no spp placement group ID in the spp placement groups array but found %s", *newpool.SharedProcessorPool.SharedProcessorPoolPlacementGroups[0].ID) + } + return nil + } +} + +func testAccCheckIBMPIInstanceInSPP(spp string, instance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + sppResource, ok := s.RootModule().Resources[spp] + + if !ok { + return fmt.Errorf("Not found: %s", spp) + } + + if sppResource.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + // refresh shared processor pool info since a instance should be in the spp + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + parts, err := flex.IdParts(sppResource.Primary.ID) + if err != nil { + return err + } + cloudpoolid := parts[0] + client := st.NewIBMPISharedProcessorPoolClient(context.Background(), sess, cloudpoolid) + + sppFromSB, err := client.Get(parts[1]) + if err != nil { + return err + } + + instanceResource, ok := s.RootModule().Resources[instance] + if !ok { + return fmt.Errorf("Instance not found: %s", instance) + } + instanceName := instanceResource.Primary.Attributes["pi_instance_name"] + + var isInstanceFoundInSPPServersList bool = false + for _, s := range sppFromSB.Servers { + if s.Name == instanceName { + isInstanceFoundInSPPServersList = true + break + } + } + if !isInstanceFoundInSPPServersList { + return fmt.Errorf("Expected instance name %s in the SPP servers object but found %v", instanceName, sppFromSB.Servers) + } + return nil + } +} + +func testAccCheckIBMPISPPPlacementGroupConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPISPPPlacementGroupAddMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + pi_shared_processor_pool_placement_group_id = ibm_pi_spp_placement_group.spp_placement_group.spp_placement_group_id + spp_placement_groups = [ibm_pi_spp_placement_group.spp_placement_group.spp_placement_group_id] + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPISPPPlacementGroupUpdateMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + spp_placement_groups = [ibm_pi_spp_placement_group.spp_placement_group_another.spp_placement_group_id] + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPISPPPlacementGroupRemoveMemberConfig(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + spp_placement_groups = [] + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPICreateSPPInPlacementGroup(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + spp_placement_groups = [] + } + resource "ibm_pi_shared_processor_pool" "spp_pool_2" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s2" + pi_shared_processor_pool_host_group = "e980" + pi_shared_processor_pool_reserved_cores = "1" + pi_shared_processor_pool_placement_group_id = ibm_pi_spp_placement_group.spp_placement_group.spp_placement_group_id + spp_placement_groups = [ibm_pi_spp_placement_group.spp_placement_group.spp_placement_group_id] + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPIDeleteSPPPlacementGroup(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + } + resource "ibm_pi_shared_processor_pool" "spp_pool_2" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s2" + pi_shared_processor_pool_host_group = "e980" + pi_shared_processor_pool_reserved_cores = "1" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + `, acc.Pi_cloud_instance_id, name, policy) +} + +func testAccCheckIBMPICreateInstanceWithSPP(name string, policy string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + } + resource "ibm_pi_shared_processor_pool" "spp_pool_2" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s2" + pi_shared_processor_pool_host_group = "e980" + pi_shared_processor_pool_reserved_cores = "1" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + data "ibm_pi_image" "power_image" { + pi_image_name = "%[4]s" + pi_cloud_instance_id = "%[1]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[5]s" + } + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 20 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = data.ibm_pi_image.power_image.storage_pool + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = data.ibm_pi_image.power_image.id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = data.ibm_pi_image.power_image.storage_pool + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_shared_processor_pool = ibm_pi_shared_processor_pool.spp_pool.pi_shared_processor_pool_name + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPICreateSAPInstanceWithSPP(name string, policy string, sapProfile string) string { + return fmt.Sprintf(` + resource "ibm_pi_shared_processor_pool" "spp_pool" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + } + resource "ibm_pi_shared_processor_pool" "spp_pool_2" { + pi_cloud_instance_id = "%[1]s" + pi_shared_processor_pool_name = "%[2]s2" + pi_shared_processor_pool_host_group = "e980" + pi_shared_processor_pool_reserved_cores = "1" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]spg" + pi_spp_placement_group_policy = "%[3]s" + } + resource "ibm_pi_spp_placement_group" "spp_placement_group_another" { + pi_cloud_instance_id = "%[1]s" + pi_spp_placement_group_name = "%[2]s2pg" + pi_spp_placement_group_policy = "%[3]s" + } + + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + data "ibm_pi_image" "power_image" { + pi_image_name = "%[4]s" + pi_cloud_instance_id = "%[1]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[5]s" + } + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 20 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = data.ibm_pi_image.power_image.storage_pool + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = data.ibm_pi_image.power_image.id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = data.ibm_pi_image.power_image.storage_pool + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_shared_processor_pool = ibm_pi_shared_processor_pool.spp_pool.pi_shared_processor_pool_name + } + resource "ibm_pi_instance" "sap" { + pi_cloud_instance_id = "%[1]s" + pi_instance_name = "%[2]sSAP" + pi_sap_profile_id = "%[7]s" + pi_image_id = "%[6]s" + pi_storage_type = "tier1" + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_health_status = "OK" + pi_shared_processor_pool = ibm_pi_shared_processor_pool.spp_pool_2.pi_shared_processor_pool_name + } + `, acc.Pi_cloud_instance_id, name, policy, acc.Pi_image, acc.Pi_network_name, acc.Pi_sap_image, sapProfile) +} diff --git a/ibm/service/power/resource_ibm_pi_volume.go b/ibm/service/power/resource_ibm_pi_volume.go new file mode 100644 index 000000000..67e207e28 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume.go @@ -0,0 +1,377 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPIVolume() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIVolumeCreate, + ReadContext: resourceIBMPIVolumeRead, + UpdateContext: resourceIBMPIVolumeUpdate, + DeleteContext: resourceIBMPIVolumeDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "Cloud Instance ID - This is the service_instance_id.", + }, + helpers.PIVolumeName: { + Type: schema.TypeString, + Required: true, + Description: "Volume Name to create", + }, + helpers.PIVolumeShareable: { + Type: schema.TypeBool, + Optional: true, + Description: "Flag to indicate if the volume can be shared across multiple instances?", + }, + helpers.PIVolumeSize: { + Type: schema.TypeFloat, + Required: true, + Description: "Size of the volume in GB", + }, + helpers.PIVolumeType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"ssd", "standard", "tier1", "tier3"}), + DiffSuppressFunc: flex.ApplyOnce, + Description: "Type of Disk, required if pi_affinity_policy and pi_volume_pool not provided, otherwise ignored", + }, + helpers.PIVolumePool: { + Type: schema.TypeString, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Volume pool where the volume will be created; if provided then pi_volume_type and pi_affinity_policy values will be ignored", + }, + PIAffinityPolicy: { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Affinity policy for data volume being created; ignored if pi_volume_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + ValidateFunc: validate.InvokeValidator("ibm_pi_volume", PIAffinityPolicy), + }, + PIAffinityVolume: { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Volume (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + ConflictsWith: []string{PIAffinityInstance}, + }, + PIAffinityInstance: { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "PVM Instance (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_volume is not provided", + ConflictsWith: []string{PIAffinityVolume}, + }, + PIAntiAffinityVolumes: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of volumes to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + ConflictsWith: []string{PIAntiAffinityInstances}, + }, + PIAntiAffinityInstances: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: flex.ApplyOnce, + Description: "List of pvmInstances to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + ConflictsWith: []string{PIAntiAffinityVolumes}, + }, + + // Computed Attributes + "volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "Volume ID", + }, + "volume_status": { + Type: schema.TypeString, + Computed: true, + Description: "Volume status", + }, + + "delete_on_termination": { + Type: schema.TypeBool, + Computed: true, + Description: "Should the volume be deleted during termination", + }, + "wwn": { + Type: schema.TypeString, + Computed: true, + Description: "WWN Of the volume", + }, + }, + } +} +func ResourceIBMPIVolumeValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "pi_affinity", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "affinity, anti-affinity"}) + ibmPIVolumeResourceValidator := validate.ResourceValidator{ + ResourceName: "ibm_pi_volume", + Schema: validateSchema} + return &ibmPIVolumeResourceValidator +} + +func resourceIBMPIVolumeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get(helpers.PIVolumeName).(string) + size := float64(d.Get(helpers.PIVolumeSize).(float64)) + var shared bool + if v, ok := d.GetOk(helpers.PIVolumeShareable); ok { + shared = v.(bool) + } + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + body := &models.CreateDataVolume{ + Name: &name, + Shareable: &shared, + Size: &size, + } + if v, ok := d.GetOk(helpers.PIVolumeType); ok { + volType := v.(string) + body.DiskType = volType + } + if v, ok := d.GetOk(helpers.PIVolumePool); ok { + volumePool := v.(string) + body.VolumePool = volumePool + } + if ap, ok := d.GetOk(PIAffinityPolicy); ok { + policy := ap.(string) + body.AffinityPolicy = &policy + + if policy == "affinity" { + if av, ok := d.GetOk(PIAffinityVolume); ok { + afvol := av.(string) + body.AffinityVolume = &afvol + } + if ai, ok := d.GetOk(PIAffinityInstance); ok { + afins := ai.(string) + body.AffinityPVMInstance = &afins + } + } else { + if avs, ok := d.GetOk(PIAntiAffinityVolumes); ok { + afvols := flex.ExpandStringList(avs.([]interface{})) + body.AntiAffinityVolumes = afvols + } + if ais, ok := d.GetOk(PIAntiAffinityInstances); ok { + afinss := flex.ExpandStringList(ais.([]interface{})) + body.AntiAffinityPVMInstances = afinss + } + } + + } + + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + vol, err := client.CreateVolume(body) + if err != nil { + return diag.FromErr(err) + } + + volumeid := *vol.VolumeID + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, volumeid)) + + _, err = isWaitForIBMPIVolumeAvailable(ctx, client, volumeid, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIVolumeRead(ctx, d, meta) +} + +func resourceIBMPIVolumeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, volumeID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + + vol, err := client.Get(volumeID) + if err != nil { + return diag.FromErr(err) + } + d.Set(helpers.PIVolumeName, vol.Name) + d.Set(helpers.PIVolumeSize, vol.Size) + if vol.Shareable != nil { + d.Set(helpers.PIVolumeShareable, vol.Shareable) + } + d.Set(helpers.PIVolumeType, vol.DiskType) + d.Set(helpers.PIVolumePool, vol.VolumePool) + d.Set("volume_status", vol.State) + if vol.VolumeID != nil { + d.Set("volume_id", vol.VolumeID) + } + if vol.DeleteOnTermination != nil { + d.Set("delete_on_termination", vol.DeleteOnTermination) + } + d.Set("wwn", vol.Wwn) + d.Set(helpers.PICloudInstanceId, cloudInstanceID) + + return nil +} + +func resourceIBMPIVolumeUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, volumeID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + name := d.Get(helpers.PIVolumeName).(string) + size := float64(d.Get(helpers.PIVolumeSize).(float64)) + var shareable bool + if v, ok := d.GetOk(helpers.PIVolumeShareable); ok { + shareable = v.(bool) + } + + body := &models.UpdateVolume{ + Name: &name, + Shareable: &shareable, + Size: size, + } + volrequest, err := client.UpdateVolume(volumeID, body) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPIVolumeAvailable(ctx, client, *volrequest.VolumeID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIVolumeRead(ctx, d, meta) +} + +func resourceIBMPIVolumeDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, volumeID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + err = client.DeleteVolume(volumeID) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForIBMPIVolumeDeleted(ctx, client, volumeID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + return nil +} + +func isWaitForIBMPIVolumeAvailable(ctx context.Context, client *st.IBMPIVolumeClient, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PIVolumeProvisioning}, + Target: []string{helpers.PIVolumeProvisioningDone}, + Refresh: isIBMPIVolumeRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIVolumeRefreshFunc(client *st.IBMPIVolumeClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vol, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if vol.State == "available" || vol.State == "in-use" { + return vol, helpers.PIVolumeProvisioningDone, nil + } + + return vol, helpers.PIVolumeProvisioning, nil + } +} + +func isWaitForIBMPIVolumeDeleted(ctx context.Context, client *st.IBMPIVolumeClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting", helpers.PIVolumeProvisioning}, + Target: []string{"deleted"}, + Refresh: isIBMPIVolumeDeleteRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: timeout, + } + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIVolumeDeleteRefreshFunc(client *st.IBMPIVolumeClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vol, err := client.Get(id) + if err != nil { + if strings.Contains(err.Error(), "Resource not found") { + return vol, "deleted", nil + } + return nil, "", err + } + if vol == nil { + return vol, "deleted", nil + } + return vol, "deleting", nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_volume_attach.go b/ibm/service/power/resource_ibm_pi_volume_attach.go new file mode 100644 index 000000000..cc1761300 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume_attach.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "errors" + "fmt" + "log" + "time" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_volumes" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPIVolumeAttach() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIVolumeAttachCreate, + ReadContext: resourceIBMPIVolumeAttachRead, + DeleteContext: resourceIBMPIVolumeAttachDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: " Cloud Instance ID - This is the service_instance_id.", + }, + + helpers.PIVolumeId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Id of the volume to attach. Note these volumes should have been created", + }, + + helpers.PIInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "PI Instance Id", + }, + + // Computed Attribute + helpers.PIVolumeAttachStatus: { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceIBMPIVolumeAttachCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + volumeID := d.Get(helpers.PIVolumeId).(string) + pvmInstanceID := d.Get(helpers.PIInstanceId).(string) + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + + volClient := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + volinfo, err := volClient.Get(volumeID) + if err != nil { + return diag.FromErr(err) + } + + if volinfo.State == "available" || *volinfo.Shareable { + log.Printf(" In the current state the volume can be attached to the instance ") + } + + if volinfo.State == "in-use" && *volinfo.Shareable { + + log.Printf("Volume State /Status is permitted and hence attaching the volume to the instance") + } + + if volinfo.State == helpers.PIVolumeAllowableAttachStatus && !*volinfo.Shareable { + return diag.Errorf("the volume cannot be attached in the current state. The volume must be in the *available* state. No other states are permissible") + } + + err = volClient.Attach(pvmInstanceID, volumeID) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, pvmInstanceID, *volinfo.VolumeID)) + + _, err = isWaitForIBMPIVolumeAttachAvailable(ctx, volClient, *volinfo.VolumeID, cloudInstanceID, pvmInstanceID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIVolumeAttachRead(ctx, d, meta) +} + +func resourceIBMPIVolumeAttachRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + ids, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, pvmInstanceID, volumeID := ids[0], ids[1], ids[2] + + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + + vol, err := client.CheckVolumeAttach(pvmInstanceID, volumeID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(helpers.PIVolumeAttachStatus, vol.State) + return nil +} + +func resourceIBMPIVolumeAttachDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + ids, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID, pvmInstanceID, volumeID := ids[0], ids[1], ids[2] + client := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) + + log.Printf("the id of the volume to detach is %s ", volumeID) + + err = client.Detach(pvmInstanceID, volumeID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_volumes.PcloudCloudinstancesVolumesGetNotFound: + log.Printf("[DEBUG] volume does not exist while detaching %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] volume detach failed %v", err) + return diag.FromErr(err) + } + + _, err = isWaitForIBMPIVolumeDetach(ctx, client, volumeID, cloudInstanceID, pvmInstanceID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + // wait for power volume states to be back as available. if it's attached it will be in-use + d.SetId("") + return nil +} + +func isWaitForIBMPIVolumeAttachAvailable(ctx context.Context, client *st.IBMPIVolumeClient, id, cloudInstanceID, pvmInstanceID string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume (%s) to be available for attachment", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", helpers.PIVolumeProvisioning}, + Target: []string{helpers.PIVolumeAllowableAttachStatus}, + Refresh: isIBMPIVolumeAttachRefreshFunc(client, id, cloudInstanceID, pvmInstanceID), + Delay: 10 * time.Second, + MinTimeout: 30 * time.Second, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIVolumeAttachRefreshFunc(client *st.IBMPIVolumeClient, id, cloudInstanceID, pvmInstanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vol, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if vol.State == "in-use" && flex.StringContains(vol.PvmInstanceIDs, pvmInstanceID) { + return vol, helpers.PIVolumeAllowableAttachStatus, nil + } + + return vol, helpers.PIVolumeProvisioning, nil + } +} + +func isWaitForIBMPIVolumeDetach(ctx context.Context, client *st.IBMPIVolumeClient, id, cloudInstanceID, pvmInstanceID string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume (%s) to be available after detachment", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"detaching", helpers.PowerVolumeAttachDeleting}, + Target: []string{helpers.PIVolumeProvisioningDone}, + Refresh: isIBMPIVolumeDetachRefreshFunc(client, id, cloudInstanceID, pvmInstanceID), + Delay: 10 * time.Second, + MinTimeout: 30 * time.Second, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIVolumeDetachRefreshFunc(client *st.IBMPIVolumeClient, id, cloudInstanceID, pvmInstanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vol, err := client.Get(id) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_volumes.PcloudCloudinstancesVolumesGetNotFound: + log.Printf("[DEBUG] volume does not exist while detaching %v", err) + return vol, helpers.PIVolumeProvisioningDone, nil + } + return nil, "", err + } + + // Check if Instance ID is in the Volume's Instance list + // Also validate the Volume state is 'available' when it is not Sharable + // In case of Sharable Volume it can be `in-use` state + if !flex.StringContains(vol.PvmInstanceIDs, pvmInstanceID) && + (*vol.Shareable || (!*vol.Shareable && vol.State == "available")) { + return vol, helpers.PIVolumeProvisioningDone, nil + } + + return vol, "detaching", nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_volume_attach_test.go b/ibm/service/power/resource_ibm_pi_volume_attach_test.go new file mode 100644 index 000000000..287e5b08c --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume_attach_test.go @@ -0,0 +1,176 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "log" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" +) + +func TestAccIBMPIVolumeAttachbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-volume-attach-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVolumeAttachDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVolumeAttachConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeAttachExists("ibm_pi_volume_attach.power_attach_volume"), + resource.TestCheckResourceAttrSet("ibm_pi_volume_attach.power_attach_volume", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_volume_attach.power_attach_volume", "status"), + ), + }, + }, + }) +} +func TestAccIBMPIShareableVolumeAttachbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-shareable-volume-attach-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVolumeAttachDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIShareableVolumeAttachConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeAttachExists("ibm_pi_volume_attach.power_attach_volume"), + resource.TestCheckResourceAttrSet("ibm_pi_volume_attach.power_attach_volume", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_volume_attach.power_attach_volume", "status"), + ), + }, + }, + }) +} +func testAccCheckIBMPIVolumeAttachDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_volume_attach" { + continue + } + + ids, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID, pvmInstanceID, volumeID := ids[0], ids[1], ids[2] + client := st.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID) + volumeAttach, err := client.CheckVolumeAttach(pvmInstanceID, volumeID) + if err == nil { + log.Println("volume attach*****", volumeAttach.State) + return fmt.Errorf("PI Volume Attach still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIVolumeAttachExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + ids, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID, pvmInstanceID, volumeID := ids[0], ids[1], ids[2] + client := st.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID) + + _, err = client.CheckVolumeAttach(pvmInstanceID, volumeID) + if err != nil { + return err + } + return nil + } +} +func testAccCheckIBMPIVolumeAttachConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 2 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = "Tier3-Flash-1" + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = "%[3]s" + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = "Tier3-Flash-1" + pi_network { + network_id = "%[4]s" + } + } + resource "ibm_pi_volume_attach" "power_attach_volume"{ + pi_cloud_instance_id = "%[1]s" + pi_volume_id = ibm_pi_volume.power_volume.volume_id + pi_instance_id = ibm_pi_instance.power_instance.instance_id + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name) +} + +func testAccCheckIBMPIShareableVolumeAttachConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 2 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = "Tier3-Flash-1" + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + count = 2 + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s-${count.index}" + pi_proc_type = "shared" + pi_image_id = "%[3]s" + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = "Tier3-Flash-1" + pi_volume_ids = count.index == 0 ? [ibm_pi_volume.power_volume.volume_id] : null + pi_network { + network_id = "%[4]s" + } + } + resource "ibm_pi_volume_attach" "power_attach_volume"{ + pi_cloud_instance_id = "%[1]s" + pi_volume_id = ibm_pi_volume.power_volume.volume_id + pi_instance_id = ibm_pi_instance.power_instance[1].instance_id + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name) +} diff --git a/ibm/service/power/resource_ibm_pi_volume_test.go b/ibm/service/power/resource_ibm_pi_volume_test.go new file mode 100644 index 000000000..73c17360f --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume_test.go @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "log" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIVolumebasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-volume-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVolumeConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeExists("ibm_pi_volume.power_volume"), + resource.TestCheckResourceAttr( + "ibm_pi_volume.power_volume", "pi_volume_name", name), + ), + }, + { + Config: testAccCheckIBMPIVolumeSizeConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeExists("ibm_pi_volume.power_volume"), + resource.TestCheckResourceAttr( + "ibm_pi_volume.power_volume", "pi_volume_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_volume.power_volume", "pi_volume_size", "30"), + ), + }, + }, + }) +} +func testAccCheckIBMPIVolumeDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_volume" { + continue + } + cloudInstanceID, volumeID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + volumeC := st.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID) + volume, err := volumeC.Get(volumeID) + if err == nil { + log.Println("volume*****", volume.State) + return fmt.Errorf("PI Volume still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func testAccCheckIBMPIVolumeExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, volumeID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(volumeID) + if err != nil { + return err + } + return nil + + } +} + +func testAccCheckIBMPIVolumeConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume"{ + pi_volume_size = 20 + pi_volume_name = "%s" + pi_volume_type = "tier1" + pi_volume_shareable = true + pi_cloud_instance_id = "%s" + } + `, name, acc.Pi_cloud_instance_id) +} + +func testAccCheckIBMPIVolumeSizeConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume"{ + pi_volume_size = 30 + pi_volume_name = "%s" + pi_volume_type = "tier1" + pi_volume_shareable = true + pi_cloud_instance_id = "%s" + } + `, name, acc.Pi_cloud_instance_id) +} + +func TestAccIBMPIVolumePool(t *testing.T) { + name := fmt.Sprintf("tf-pi-volume-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVolumePoolConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeExists("ibm_pi_volume.power_volume"), + resource.TestCheckResourceAttr( + "ibm_pi_volume.power_volume", "pi_volume_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_volume.power_volume", "pi_volume_pool", "Tier3-Flash-1"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVolumePoolConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume"{ + pi_volume_size = 20 + pi_volume_name = "%s" + pi_volume_pool = "Tier3-Flash-1" + pi_volume_shareable = true + pi_cloud_instance_id = "%s" + } + `, name, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/resource_ibm_pi_vpn_connection.go b/ibm/service/power/resource_ibm_pi_vpn_connection.go new file mode 100644 index 000000000..16808bd73 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_vpn_connection.go @@ -0,0 +1,364 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "strconv" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/errors" + "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_v_p_n_connections" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMPIVPNConnection() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIVPNConnectionCreate, + ReadContext: resourceIBMPIVPNConnectionRead, + UpdateContext: resourceIBMPIVPNConnectionUpdate, + DeleteContext: resourceIBMPIVPNConnectionDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Required Attributes + helpers.PICloudInstanceId: { + Type: schema.TypeString, + Required: true, + Description: "PI cloud instance ID", + }, + helpers.PIVPNConnectionName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the VPN Connection", + }, + helpers.PIVPNIKEPolicyId: { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier of IKE Policy selected for this VPN Connection", + }, + helpers.PIVPNIPSecPolicyId: { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier of IPSec Policy selected for this VPN Connection", + }, + helpers.PIVPNConnectionMode: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"policy", "route"}), + Description: "Mode used by this VPN Connection, either 'policy' or 'route'", + DiffSuppressFunc: flex.ApplyOnce, + }, + helpers.PIVPNConnectionNetworks: { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of network IDs to attach to this VPN connection", + }, + helpers.PIVPNConnectionPeerGatewayAddress: { + Type: schema.TypeString, + Required: true, + Description: "Peer Gateway address", + }, + helpers.PIVPNConnectionPeerSubnets: { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Set of CIDR of peer subnets", + }, + + //Computed Attributes + PIVPNConnectionId: { + Type: schema.TypeString, + Computed: true, + Description: "VPN connection ID", + }, + PIVPNConnectionLocalGatewayAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Local Gateway address, only in 'route' mode", + }, + PIVPNConnectionStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Status of the VPN connection", + }, + PIVPNConnectionVpnGatewayAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Public IP address of the VPN Gateway (vSRX) attached to this VPN Connection", + }, + PIVPNConnectionDeadPeerDetection: { + Type: schema.TypeMap, + Computed: true, + Description: "Dead Peer Detection", + }, + }, + } +} + +func resourceIBMPIVPNConnectionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + name := d.Get(helpers.PIVPNConnectionName).(string) + ikePolicyId := d.Get(helpers.PIVPNIKEPolicyId).(string) + ipsecPolicyId := d.Get(helpers.PIVPNIPSecPolicyId).(string) + mode := d.Get(helpers.PIVPNConnectionMode).(string) + networks := d.Get(helpers.PIVPNConnectionNetworks).(*schema.Set) + peerSubnets := d.Get(helpers.PIVPNConnectionPeerSubnets).(*schema.Set) + peerGatewayAddress := d.Get(helpers.PIVPNConnectionPeerGatewayAddress).(string) + pga := models.PeerGatewayAddress(peerGatewayAddress) + + body := &models.VPNConnectionCreate{ + IkePolicy: &ikePolicyId, + IPSecPolicy: &ipsecPolicyId, + Mode: &mode, + Name: &name, + PeerGatewayAddress: &pga, + } + // networks + if networks.Len() > 0 { + body.Networks = flex.ExpandStringList(networks.List()) + } else { + return diag.Errorf("%s is a required field", helpers.PIVPNConnectionNetworks) + } + // peer subnets + if peerSubnets.Len() > 0 { + body.PeerSubnets = flex.ExpandStringList(peerSubnets.List()) + } else { + return diag.Errorf("%s is a required field", helpers.PIVPNConnectionPeerSubnets) + } + + client := st.NewIBMPIVpnConnectionClient(ctx, sess, cloudInstanceID) + vpnConnection, err := client.Create(body) + if err != nil { + log.Printf("[DEBUG] create VPN connection failed %v", err) + return diag.FromErr(err) + } + + vpnConnectionId := *vpnConnection.ID + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, vpnConnectionId)) + + if vpnConnection.JobRef != nil { + jobID := *vpnConnection.JobRef.ID + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + _, err = waitForIBMPIJobCompleted(ctx, jobClient, jobID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMPIVPNConnectionRead(ctx, d, meta) +} + +func resourceIBMPIVPNConnectionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, vpnConnectionID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnConnectionClient(ctx, sess, cloudInstanceID) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + if d.HasChangesExcept(helpers.PIVPNConnectionNetworks, helpers.PIVPNConnectionPeerSubnets) { + body := &models.VPNConnectionUpdate{} + + if d.HasChanges(helpers.PIVPNConnectionName) { + name := d.Get(helpers.PIVPNConnectionName).(string) + body.Name = name + } + if d.HasChanges(helpers.PIVPNIKEPolicyId) { + ikePolicyId := d.Get(helpers.PIVPNIKEPolicyId).(string) + body.IkePolicy = ikePolicyId + } + if d.HasChanges(helpers.PIVPNIPSecPolicyId) { + ipsecPolicyId := d.Get(helpers.PIVPNIPSecPolicyId).(string) + body.IPSecPolicy = ipsecPolicyId + } + if d.HasChanges(helpers.PIVPNConnectionPeerGatewayAddress) { + peerGatewayAddress := d.Get(helpers.PIVPNConnectionPeerGatewayAddress).(string) + body.PeerGatewayAddress = models.PeerGatewayAddress(peerGatewayAddress) + } + + _, err = client.Update(vpnConnectionID, body) + if err != nil { + return diag.FromErr(err) + } + } + if d.HasChanges(helpers.PIVPNConnectionNetworks) { + oldRaw, newRaw := d.GetChange(helpers.PIVPNConnectionNetworks) + old := oldRaw.(*schema.Set) + new := newRaw.(*schema.Set) + + toAdd := new.Difference(old) + toRemove := old.Difference(new) + + for _, n := range flex.ExpandStringList(toAdd.List()) { + jobReference, err := client.AddNetwork(vpnConnectionID, n) + if err != nil { + return diag.FromErr(err) + } + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + for _, n := range flex.ExpandStringList(toRemove.List()) { + jobReference, err := client.DeleteNetwork(vpnConnectionID, n) + if err != nil { + return diag.FromErr(err) + } + if jobReference != nil { + _, err = waitForIBMPIJobCompleted(ctx, jobClient, *jobReference.ID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + + } + if d.HasChanges(helpers.PIVPNConnectionPeerSubnets) { + oldRaw, newRaw := d.GetChange(helpers.PIVPNConnectionPeerSubnets) + old := oldRaw.(*schema.Set) + new := newRaw.(*schema.Set) + + toAdd := new.Difference(old) + toRemove := old.Difference(new) + + for _, s := range flex.ExpandStringList(toAdd.List()) { + _, err := client.AddSubnet(vpnConnectionID, s) + if err != nil { + return diag.FromErr(err) + } + } + for _, s := range flex.ExpandStringList(toRemove.List()) { + _, err := client.DeleteSubnet(vpnConnectionID, s) + if err != nil { + return diag.FromErr(err) + } + } + } + return resourceIBMPIVPNConnectionRead(ctx, d, meta) +} + +func resourceIBMPIVPNConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, vpnConnectionID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnConnectionClient(ctx, sess, cloudInstanceID) + vpnConnection, err := client.Get(vpnConnectionID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_v_p_n_connections.PcloudVpnconnectionsGetNotFound: + log.Printf("[DEBUG] VPN connection does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] get VPN connection failed %v", err) + return diag.FromErr(err) + } + + d.Set(PIVPNConnectionId, vpnConnection.ID) + d.Set(helpers.PIVPNConnectionName, vpnConnection.Name) + if vpnConnection.IkePolicy != nil { + d.Set(helpers.PIVPNIKEPolicyId, vpnConnection.IkePolicy.ID) + } + if vpnConnection.IPSecPolicy != nil { + d.Set(helpers.PIVPNIPSecPolicyId, vpnConnection.IPSecPolicy.ID) + } + d.Set(PIVPNConnectionLocalGatewayAddress, vpnConnection.LocalGatewayAddress) + d.Set(helpers.PIVPNConnectionMode, vpnConnection.Mode) + d.Set(helpers.PIVPNConnectionPeerGatewayAddress, vpnConnection.PeerGatewayAddress) + d.Set(PIVPNConnectionStatus, vpnConnection.Status) + d.Set(PIVPNConnectionVpnGatewayAddress, vpnConnection.VpnGatewayAddress) + + d.Set(helpers.PIVPNConnectionNetworks, vpnConnection.NetworkIDs) + d.Set(helpers.PIVPNConnectionPeerSubnets, vpnConnection.PeerSubnets) + + if vpnConnection.DeadPeerDetection != nil { + dpc := vpnConnection.DeadPeerDetection + dpcMap := map[string]interface{}{ + PIVPNConnectionDeadPeerDetectionAction: *dpc.Action, + PIVPNConnectionDeadPeerDetectionInterval: strconv.FormatInt(*dpc.Interval, 10), + PIVPNConnectionDeadPeerDetectionThreshold: strconv.FormatInt(*dpc.Threshold, 10), + } + d.Set(PIVPNConnectionDeadPeerDetection, dpcMap) + } + + return nil +} + +func resourceIBMPIVPNConnectionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, vpnConnectionID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPIVpnConnectionClient(ctx, sess, cloudInstanceID) + jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + + jobRef, err := client.Delete(vpnConnectionID) + if err != nil { + uErr := errors.Unwrap(err) + switch uErr.(type) { + case *p_cloud_v_p_n_connections.PcloudVpnconnectionsDeleteNotFound: + log.Printf("[DEBUG] VPN connection does not exist %v", err) + d.SetId("") + return nil + } + log.Printf("[DEBUG] delete VPN connection failed %v", err) + return diag.FromErr(err) + } + if jobRef != nil { + jobID := *jobRef.ID + _, err = waitForIBMPIJobCompleted(ctx, jobClient, jobID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + return nil +} diff --git a/ibm/service/power/resource_ibm_pi_vpn_connection_test.go b/ibm/service/power/resource_ibm_pi_vpn_connection_test.go new file mode 100644 index 000000000..31258540a --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_vpn_connection_test.go @@ -0,0 +1,186 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" +) + +func TestAccIBMPIVPNConnectionBasic(t *testing.T) { + connectionRes := "ibm_pi_vpn_connection.vpn" + name := fmt.Sprintf("tf-pi-vpn-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVPNConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVPNConnectionConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVPNConnectionExists(connectionRes), + resource.TestCheckResourceAttr(connectionRes, "pi_vpn_connection_name", name), + resource.TestCheckResourceAttrSet(connectionRes, "connection_id"), + resource.TestCheckResourceAttrSet(connectionRes, "connection_status"), + resource.TestCheckResourceAttr(connectionRes, "pi_networks.#", "1"), + resource.TestCheckResourceAttr(connectionRes, "pi_peer_subnets.#", "1"), + ), + }, + { + Config: testAccCheckIBMPIVPNConnectionNetworkSubnetConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVPNConnectionExists(connectionRes), + resource.TestCheckResourceAttr(connectionRes, "pi_vpn_connection_name", name), + resource.TestCheckResourceAttrSet(connectionRes, "connection_status"), + resource.TestCheckResourceAttr(connectionRes, "pi_networks.#", "2"), + resource.TestCheckResourceAttr(connectionRes, "pi_peer_subnets.#", "2"), + ), + }, + }, + }) +} +func testAccCheckIBMPIVPNConnectionDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_vpn_connection" { + continue + } + cloudInstanceID, vpnConnectionID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnConnectionClient(context.Background(), sess, cloudInstanceID) + _, err = client.Get(vpnConnectionID) + if err == nil { + return fmt.Errorf("vpn connection still exists: %s", rs.Primary.ID) + } + } + return nil +} +func testAccCheckIBMPIVPNConnectionExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + cloudInstanceID, vpnConnectionID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + client := st.NewIBMPIVpnConnectionClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(vpnConnectionID) + if err != nil { + return err + } + + return nil + } +} + +func testAccCheckIBMPIVPNConnectionConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_vpn_connection" "vpn" { + pi_cloud_instance_id = "%[1]s" + pi_vpn_connection_name = "%[2]s" + pi_ike_policy_id = ibm_pi_ike_policy.ike_policy.policy_id + pi_ipsec_policy_id = ibm_pi_ipsec_policy.ipsec_policy.policy_id + pi_vpn_connection_mode = "policy" + pi_networks = [ibm_pi_network.private_network1.network_id] + pi_peer_gateway_address = "1.22.124.1" + pi_peer_subnets = ["107.0.0.0/24"] + } + resource "ibm_pi_ike_policy" "ike_policy" { + pi_cloud_instance_id = "%[1]s" + pi_policy_name = "%[2]s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_preshared_key = "sample" + pi_policy_version = 1 + } + resource "ibm_pi_ipsec_policy" "ipsec_policy" { + pi_cloud_instance_id = "%[1]s" + pi_policy_name = "%[2]s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_pfs = true + pi_policy_authentication = "hmac-sha-256-128" + } + resource "ibm_pi_network" "private_network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s-net1" + pi_network_type = "vlan" + pi_cidr = "192.35.161.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPIVPNConnectionNetworkSubnetConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_vpn_connection" "vpn" { + pi_cloud_instance_id = "%[1]s" + pi_vpn_connection_name = "%[2]s" + pi_ike_policy_id = ibm_pi_ike_policy.ike_policy.policy_id + pi_ipsec_policy_id = ibm_pi_ipsec_policy.ipsec_policy.policy_id + pi_vpn_connection_mode = "policy" + pi_networks = [ ibm_pi_network.private_network1.network_id, ibm_pi_network.private_network2.network_id ] + pi_peer_gateway_address = "1.22.124.2" + pi_peer_subnets = ["107.0.0.0/24","199.166.0.0/24"] + } + resource "ibm_pi_ike_policy" "ike_policy" { + pi_cloud_instance_id = "%[1]s" + pi_policy_name = "%[2]s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_preshared_key = "sample" + pi_policy_version = 1 + } + resource "ibm_pi_ipsec_policy" "ipsec_policy" { + pi_cloud_instance_id = "%[1]s" + pi_policy_name = "%[2]s" + pi_policy_dh_group = 1 + pi_policy_encryption = "3des-cbc" + pi_policy_key_lifetime = 180 + pi_policy_pfs = true + pi_policy_authentication = "hmac-sha-256-128" + } + resource "ibm_pi_network" "private_network1" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s-net1" + pi_network_type = "vlan" + pi_cidr = "192.35.161.0/24" + } + resource "ibm_pi_network" "private_network2" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[2]s-net2" + pi_network_type = "vlan" + pi_cidr = "192.35.162.0/24" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/pushnotification/README.md b/ibm/service/pushnotification/README.md new file mode 100644 index 000000000..2b42dcc15 --- /dev/null +++ b/ibm/service/pushnotification/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Push Notification + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Push Notification resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pn_application_chrome) +* IBM API Docs: [IBM API Docs for Push Notification](https://cloud.ibm.com/apidocs/push-notifications) +* IBM Push Notification SDK: [IBM SDK for Push Notification](https://github.com/IBM/push-notifications-go-sdk/tree/main/pushservicev1) diff --git a/ibm/service/pushnotification/data_source_ibm_push_notification_chrome.go b/ibm/service/pushnotification/data_source_ibm_push_notification_chrome.go new file mode 100644 index 000000000..f036a6fe9 --- /dev/null +++ b/ibm/service/pushnotification/data_source_ibm_push_notification_chrome.go @@ -0,0 +1,65 @@ +package pushnotification + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/push-notifications-go-sdk/pushservicev1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMPNApplicationChrome() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApplicationChromeRead, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique guid of the application using the push service.", + }, + "server_key": { + Type: schema.TypeString, + Computed: true, + Description: "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", + }, + "web_site_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", + }, + }, + DeprecationMessage: "This service is deprecated. For more information about the deprecation of this service, see here https://www.ibm.com/cloud/blog/announcements/ibm-push-notifications-deprecation", + } +} + +func dataSourceApplicationChromeRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + pushServiceClient, err := meta.(conns.ClientSession).PushServiceV1() + if err != nil { + return diag.FromErr(err) + } + + getChromeWebConfOptions := &pushservicev1.GetChromeWebConfOptions{} + + guid := d.Get("guid").(string) + getChromeWebConfOptions.SetApplicationID(guid) + + chromeWebConf, response, err := pushServiceClient.GetChromeWebConfWithContext(context, getChromeWebConfOptions) + if err != nil { + log.Printf("[DEBUG] GetChromeWebConfWithContext failed %s\n%d", err, response.StatusCode) + return diag.FromErr(err) + } + + d.SetId(guid) + if err = d.Set("server_key", chromeWebConf.ApiKey); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_key: %s", err)) + } + if err = d.Set("web_site_url", chromeWebConf.WebSiteURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting web_site_url: %s", err)) + } + + return nil +} diff --git a/ibm/data_source_ibm_push_notification_chrome_test.go b/ibm/service/pushnotification/data_source_ibm_push_notification_chrome_test.go similarity index 89% rename from ibm/data_source_ibm_push_notification_chrome_test.go rename to ibm/service/pushnotification/data_source_ibm_push_notification_chrome_test.go index 8334a5839..7ff160019 100644 --- a/ibm/data_source_ibm_push_notification_chrome_test.go +++ b/ibm/service/pushnotification/data_source_ibm_push_notification_chrome_test.go @@ -1,9 +1,11 @@ -package ibm +package pushnotification_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -13,8 +15,8 @@ func TestAccIBMPNApplicationChromeDataSource_Basic(t *testing.T) { serverKey := fmt.Sprint(acctest.RandString(45)) // dummy value //dummy value websiteURL := "http://webpushnotificaton.mybluemix.net" // dummy url resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMPNApplicationChromeDataSourceConfig(name, serverKey, websiteURL), diff --git a/ibm/service/pushnotification/resource_ibm_push_notification_chrome.go b/ibm/service/pushnotification/resource_ibm_push_notification_chrome.go new file mode 100644 index 000000000..b705a90ca --- /dev/null +++ b/ibm/service/pushnotification/resource_ibm_push_notification_chrome.go @@ -0,0 +1,126 @@ +package pushnotification + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/push-notifications-go-sdk/pushservicev1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPNApplicationChrome() *schema.Resource { + return &schema.Resource{ + Read: resourceApplicationChromeRead, + Create: resourceApplicationChromeCreate, + Update: resourceApplicationChromeUpdate, + Delete: resourceApplicationChromeDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique guid of the push notification instance.", + }, + "server_key": { + Type: schema.TypeString, + Required: true, + Description: "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", + }, + "web_site_url": { + Type: schema.TypeString, + Required: true, + Description: "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", + }, + }, + DeprecationMessage: "This service is deprecated. For more information about the deprecation of this service, see here https://www.ibm.com/cloud/blog/announcements/ibm-push-notifications-deprecation", + } +} + +func resourceApplicationChromeCreate(d *schema.ResourceData, meta interface{}) error { + pnClient, err := meta.(conns.ClientSession).PushServiceV1() + if err != nil { + return err + } + + serverKey := d.Get("server_key").(string) + websiteURL := d.Get("web_site_url").(string) + guid := d.Get("guid").(string) + + _, response, err := pnClient.SaveChromeWebConf(&pushservicev1.SaveChromeWebConfOptions{ + ApplicationID: &guid, + ApiKey: &serverKey, + WebSiteURL: &websiteURL, + }) + + if err != nil { + d.SetId("") + return fmt.Errorf("[ERROR] Error configuring chrome web platform: %s with response code %d", err, response.StatusCode) + } + d.SetId(guid) + + return resourceApplicationChromeRead(d, meta) +} + +func resourceApplicationChromeUpdate(d *schema.ResourceData, meta interface{}) error { + + if d.HasChanges("server_key", "web_site_url") { + return resourceApplicationChromeCreate(d, meta) + } + return nil +} + +func resourceApplicationChromeRead(d *schema.ResourceData, meta interface{}) error { + pnClient, err := meta.(conns.ClientSession).PushServiceV1() + if err != nil { + return err + } + + guid := d.Id() + + chromeWebConf, response, err := pnClient.GetChromeWebConf(&pushservicev1.GetChromeWebConfOptions{ + ApplicationID: &guid, + }) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error fetching chrome web platform configuration: %s with response code %d", err, response.StatusCode) + } + + d.SetId(guid) + + if response.StatusCode == 200 { + d.Set("server_key", *chromeWebConf.ApiKey) + d.Set("web_site_url", *chromeWebConf.WebSiteURL) + } + return nil +} + +func resourceApplicationChromeDelete(d *schema.ResourceData, meta interface{}) error { + pnClient, err := meta.(conns.ClientSession).PushServiceV1() + if err != nil { + return err + } + guid := d.Get("guid").(string) + + response, err := pnClient.DeleteChromeWebConf(&pushservicev1.DeleteChromeWebConfOptions{ + ApplicationID: &guid, + }) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error deleting chrome web platform configuration: %s with response code %d", err, response.StatusCode) + } + + d.SetId("") + + return nil + +} diff --git a/ibm/resource_ibm_push_notification_chrome_test.go b/ibm/service/pushnotification/resource_ibm_push_notification_chrome_test.go similarity index 87% rename from ibm/resource_ibm_push_notification_chrome_test.go rename to ibm/service/pushnotification/resource_ibm_push_notification_chrome_test.go index eb9fe5cb6..fb3582008 100644 --- a/ibm/resource_ibm_push_notification_chrome_test.go +++ b/ibm/service/pushnotification/resource_ibm_push_notification_chrome_test.go @@ -1,10 +1,13 @@ -package ibm +package pushnotification_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/push-notifications-go-sdk/pushservicev1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,8 +22,8 @@ func TestAccIBMPNApplicationChrome_Basic(t *testing.T) { websiteURL := "http://xyz.mybluemix.net" // dummy url newWebsiteURL := "http://abc.mybluemix.net" // dummy url resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPNApplicationChromeDestroy, Steps: []resource.TestStep{ { @@ -79,7 +82,7 @@ func testAccCheckIBMPNApplicationChromeExists(n string, obj pushservicev1.Chrome return fmt.Errorf("Not found: %s", n) } - pushServiceClient, err := testAccProvider.Meta().(ClientSession).PushServiceV1() + pushServiceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PushServiceV1() if err != nil { return err } @@ -101,7 +104,7 @@ func testAccCheckIBMPNApplicationChromeExists(n string, obj pushservicev1.Chrome } func testAccCheckIBMPNApplicationChromeDestroy(s *terraform.State) error { - pushServiceClient, err := testAccProvider.Meta().(ClientSession).PushServiceV1() + pushServiceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PushServiceV1() if err != nil { return err } @@ -120,7 +123,7 @@ func testAccCheckIBMPNApplicationChromeDestroy(s *terraform.State) error { _, _, err := pushServiceClient.GetChromeWebConf(getChromeWebConfOptions) if err != nil && !strings.Contains(err.Error(), "not found") { - return fmt.Errorf("Error checking for chrome web config (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for chrome web config (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/registry/README.md b/ibm/service/registry/README.md new file mode 100644 index 000000000..3249b29c6 --- /dev/null +++ b/ibm/service/registry/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Container Registry + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Container Registry resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cr_namespace) +* IBM API Docs: [IBM API Docs for Container Registry](https://cloud.ibm.com/apidocs/container-registry) +* IBM Container Registry SDK: [IBM SDK for Container Registry](https://github.com/IBM/container-registry-go-sdk/tree/main/containerregistryv1) diff --git a/ibm/data_source_ibm_cr_namespaces.go b/ibm/service/registry/data_source_ibm_cr_namespaces.go similarity index 92% rename from ibm/data_source_ibm_cr_namespaces.go rename to ibm/service/registry/data_source_ibm_cr_namespaces.go index 7f42c5c27..0fca54d7c 100644 --- a/ibm/data_source_ibm_cr_namespaces.go +++ b/ibm/service/registry/data_source_ibm_cr_namespaces.go @@ -1,20 +1,21 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry import ( "context" "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/container-registry-go-sdk/containerregistryv1" ) -func dataIBMContainerRegistryNamespaces() *schema.Resource { +func DataIBMContainerRegistryNamespaces() *schema.Resource { return &schema.Resource{ ReadContext: dataIBMContainerRegistryNamespacesRead, @@ -81,7 +82,7 @@ func dataIBMContainerRegistryNamespaces() *schema.Resource { } func dataIBMContainerRegistryNamespacesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -109,7 +110,7 @@ func dataIBMContainerRegistryNamespacesRead(context context.Context, d *schema.R namespaces = append(namespaces, namespace) } if err = d.Set("namespaces", namespaces); err != nil { - return diag.FromErr(fmt.Errorf("Error setting namespaces: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting namespaces: %s", err)) } d.SetId(time.Now().UTC().String()) return nil diff --git a/ibm/data_source_ibm_cr_namespaces_test.go b/ibm/service/registry/data_source_ibm_cr_namespaces_test.go similarity index 77% rename from ibm/data_source_ibm_cr_namespaces_test.go rename to ibm/service/registry/data_source_ibm_cr_namespaces_test.go index 7c534ed3d..8cbbd87fb 100644 --- a/ibm/data_source_ibm_cr_namespaces_test.go +++ b/ibm/service/registry/data_source_ibm_cr_namespaces_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +16,8 @@ import ( func TestAccIBMCrNamespacesDataSourceBasic(t *testing.T) { namespaceName := fmt.Sprintf("terraform-tf-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMCrNamespacesDataSourceConfig(namespaceName), @@ -28,7 +30,7 @@ func TestAccIBMCrNamespacesDataSourceBasic(t *testing.T) { } func testAccCheckIBMCrNamespacesDataSourceConfig(namespaceName string) string { - return testAccCheckIBMCrNamespaceConfigBasic(namespaceName) + fmt.Sprintf(` + return testAccCheckIBMCrNamespaceConfigBasic(namespaceName) + ` data "ibm_cr_namespaces" "namespaces" {} -`) +` } diff --git a/ibm/resource_ibm_cr_namespace.go b/ibm/service/registry/resource_ibm_cr_namespace.go similarity index 75% rename from ibm/resource_ibm_cr_namespace.go rename to ibm/service/registry/resource_ibm_cr_namespace.go index f939b0cb4..8761da987 100644 --- a/ibm/resource_ibm_cr_namespace.go +++ b/ibm/service/registry/resource_ibm_cr_namespace.go @@ -1,20 +1,23 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/container-registry-go-sdk/containerregistryv1" ) -func resourceIBMCrNamespace() *schema.Resource { +func ResourceIBMCrNamespace() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMCrNamespaceCreate, ReadContext: resourceIBMCrNamespaceRead, @@ -23,60 +26,60 @@ func resourceIBMCrNamespace() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_cr_namespace", "name"), + ValidateFunc: validate.InvokeValidator("ibm_cr_namespace", "name"), Description: "The name of the namespace.", }, - "resource_group_id": &schema.Schema{ + "resource_group_id": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, Description: "The ID of the resource group that the namespace will be created within.", }, - "tags": &schema.Schema{ + "tags": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, Optional: true, Description: "List of tags", }, - "account": &schema.Schema{ + "account": { Type: schema.TypeString, Computed: true, Description: "The IBM Cloud account that owns the namespace.", }, - "created_date": &schema.Schema{ + "created_date": { Type: schema.TypeString, Computed: true, Description: "When the namespace was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "If the namespace has been assigned to a resource group, this is the IBM Cloud CRN representing the namespace.", }, - "resource_created_date": &schema.Schema{ + "resource_created_date": { Type: schema.TypeString, Computed: true, Description: "When the namespace was assigned to a resource group.", }, - "updated_date": &schema.Schema{ + "updated_date": { Type: schema.TypeString, Computed: true, Description: "When the namespace was last updated.", }, // HAND-ADDED DEPRECATED FIELDS, TO BE DELETED IN FUTURE - "created_on": &schema.Schema{ + "created_on": { Type: schema.TypeString, Computed: true, Description: "When the namespace was created.", Deprecated: "This field is deprecated", }, - "updated_on": &schema.Schema{ + "updated_on": { Type: schema.TypeString, Computed: true, Description: "When the namespace was last updated.", @@ -86,13 +89,13 @@ func resourceIBMCrNamespace() *schema.Resource { } } -func resourceIBMCrNamespaceValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMCrNamespaceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^[a-z0-9]+[a-z0-9_-]+[a-z0-9]+$`, MinValueLength: 4, @@ -100,12 +103,12 @@ func resourceIBMCrNamespaceValidator() *ResourceValidator { }, ) - resourceValidator := ResourceValidator{ResourceName: "ibm_cr_namespace", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_cr_namespace", Schema: validateSchema} return &resourceValidator } func resourceIBMCrNamespaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -116,7 +119,7 @@ func resourceIBMCrNamespaceCreate(context context.Context, d *schema.ResourceDat if _, ok := d.GetOk("resource_group_id"); ok { createNamespaceOptions.SetXAuthResourceGroup(d.Get("resource_group_id").(string)) } else { - defaultRg, err := defaultResourceGroup(meta) + defaultRg, err := flex.DefaultResourceGroup(meta) if err != nil { return diag.FromErr(err) } @@ -135,7 +138,7 @@ func resourceIBMCrNamespaceCreate(context context.Context, d *schema.ResourceDat } func resourceIBMCrNamespaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -165,32 +168,32 @@ func resourceIBMCrNamespaceRead(context context.Context, d *schema.ResourceData, } if err = d.Set("name", namespaceDetails.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("resource_group_id", namespaceDetails.ResourceGroup); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group_id: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group_id: %s", err)) } if err = d.Set("account", namespaceDetails.Account); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account: %s", err)) } if err = d.Set("created_date", namespaceDetails.CreatedDate); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_date: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_date: %s", err)) } if err = d.Set("crn", namespaceDetails.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("resource_created_date", namespaceDetails.ResourceCreatedDate); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_created_date: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_created_date: %s", err)) } if err = d.Set("updated_date", namespaceDetails.UpdatedDate); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_date: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_date: %s", err)) } // HAND-ADDED DEPRECATED FIELDS, TO BE DELETED IN FUTURE if err = d.Set("updated_on", namespaceDetails.UpdatedDate); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_date: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_date: %s", err)) } if err = d.Set("created_on", namespaceDetails.CreatedDate); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_date: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_date: %s", err)) } return nil @@ -202,7 +205,7 @@ func resourceIBMCrNamespaceUpdate(context context.Context, d *schema.ResourceDat } func resourceIBMCrNamespaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_cr_namespace_test.go b/ibm/service/registry/resource_ibm_cr_namespace_test.go similarity index 87% rename from ibm/resource_ibm_cr_namespace_test.go rename to ibm/service/registry/resource_ibm_cr_namespace_test.go index c03249167..ebf93a3fe 100644 --- a/ibm/resource_ibm_cr_namespace_test.go +++ b/ibm/service/registry/resource_ibm_cr_namespace_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,18 +23,18 @@ func TestAccIBMCrNamespaceBasic(t *testing.T) { nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCrNamespaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCrNamespaceConfigBasic(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMCrNamespaceExists("ibm_cr_namespace.cr_namespace", conf), resource.TestCheckResourceAttr("ibm_cr_namespace.cr_namespace", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIBMCrNamespaceConfigBasic(nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_cr_namespace.cr_namespace", "name", nameUpdate), @@ -49,11 +52,11 @@ func TestAccIBMCrNamespaceAllArgs(t *testing.T) { tagsUpdate := "[ \"tag3\" ]" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCrNamespaceDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCrNamespaceConfig(name, tags), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMCrNamespaceExists("ibm_cr_namespace.cr_namespace", conf), @@ -61,14 +64,14 @@ func TestAccIBMCrNamespaceAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_cr_namespace.cr_namespace", "tags.#", "2"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMCrNamespaceConfig(nameUpdate, tagsUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_cr_namespace.cr_namespace", "name", nameUpdate), resource.TestCheckResourceAttr("ibm_cr_namespace.cr_namespace", "tags.#", "1"), ), }, - resource.TestStep{ + { ResourceName: "ibm_cr_namespace.cr_namespace", ImportState: true, ImportStateVerify: true, @@ -110,7 +113,7 @@ func testAccCheckIBMCrNamespaceExists(n string, obj containerregistryv1.Namespac return fmt.Errorf("Not found: %s", n) } - containerRegistryClient, err := testAccProvider.Meta().(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerRegistryV1() if err != nil { return err } @@ -135,7 +138,7 @@ func testAccCheckIBMCrNamespaceExists(n string, obj containerregistryv1.Namespac } func testAccCheckIBMCrNamespaceDestroy(s *terraform.State) error { - containerRegistryClient, err := testAccProvider.Meta().(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerRegistryV1() if err != nil { return err } @@ -160,7 +163,7 @@ func testAccCheckIBMCrNamespaceDestroy(s *terraform.State) error { return fmt.Errorf("Details of a namespace. still exists: %s", rs.Primary.ID) } } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for cr_namespace (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for cr_namespace (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_cr_retention_policy.go b/ibm/service/registry/resource_ibm_cr_retention_policy.go similarity index 84% rename from ibm/resource_ibm_cr_retention_policy.go rename to ibm/service/registry/resource_ibm_cr_retention_policy.go index c4665fb40..0235ce15b 100644 --- a/ibm/resource_ibm_cr_retention_policy.go +++ b/ibm/service/registry/resource_ibm_cr_retention_policy.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/container-registry-go-sdk/containerregistryv1" ) -func resourceIBMCrRetentionPolicy() *schema.Resource { +func ResourceIBMCrRetentionPolicy() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMCrRetentionPolicyCreate, ReadContext: resourceIBMCrRetentionPolicyRead, @@ -23,17 +25,17 @@ func resourceIBMCrRetentionPolicy() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "namespace": &schema.Schema{ + "namespace": { Type: schema.TypeString, Required: true, Description: "The namespace to which the retention policy is attached.", }, - "images_per_repo": &schema.Schema{ + "images_per_repo": { Type: schema.TypeInt, Required: true, Description: "Determines how many images will be retained for each repository when the retention policy is executed. The value -1 denotes 'Unlimited' (all images are retained).", }, - "retain_untagged": &schema.Schema{ + "retain_untagged": { Type: schema.TypeBool, Optional: true, Default: false, @@ -44,7 +46,7 @@ func resourceIBMCrRetentionPolicy() *schema.Resource { } func resourceIBMCrRetentionPolicyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -69,7 +71,7 @@ func resourceIBMCrRetentionPolicyCreate(context context.Context, d *schema.Resou } func resourceIBMCrRetentionPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -89,26 +91,26 @@ func resourceIBMCrRetentionPolicyRead(context context.Context, d *schema.Resourc } // A retention policy "does not exist" if `imagesPerRepo` is -1 `retainUntagged` is true - if *retentionPolicy.ImagesPerRepo == -1 && *retentionPolicy.RetainUntagged == true { + if *retentionPolicy.ImagesPerRepo == -1 && *retentionPolicy.RetainUntagged { d.SetId("") return nil } if err = d.Set("namespace", retentionPolicy.Namespace); err != nil { - return diag.FromErr(fmt.Errorf("Error setting namespace: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting namespace: %s", err)) } - if err = d.Set("images_per_repo", intValue(retentionPolicy.ImagesPerRepo)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting images_per_repo: %s", err)) + if err = d.Set("images_per_repo", flex.IntValue(retentionPolicy.ImagesPerRepo)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting images_per_repo: %s", err)) } if err = d.Set("retain_untagged", retentionPolicy.RetainUntagged); err != nil { - return diag.FromErr(fmt.Errorf("Error setting retain_untagged: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting retain_untagged: %s", err)) } return nil } func resourceIBMCrRetentionPolicyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } @@ -144,7 +146,7 @@ func resourceIBMCrRetentionPolicyUpdate(context context.Context, d *schema.Resou } func resourceIBMCrRetentionPolicyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - containerRegistryClient, err := meta.(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := meta.(conns.ClientSession).ContainerRegistryV1() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_cr_retention_policy_test.go b/ibm/service/registry/resource_ibm_cr_retention_policy_test.go similarity index 86% rename from ibm/resource_ibm_cr_retention_policy_test.go rename to ibm/service/registry/resource_ibm_cr_retention_policy_test.go index f22084198..f3d412ff3 100644 --- a/ibm/resource_ibm_cr_retention_policy_test.go +++ b/ibm/service/registry/resource_ibm_cr_retention_policy_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package registry_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -23,11 +26,11 @@ func TestAccIBMCrRetentionPolicyAllArgs(t *testing.T) { retainUntaggedUpdate := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMCrRetentionPolicyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMCrRetentionPolicyConfig(namespace, imagesPerRepo, retainUntagged), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMCrRetentionPolicyExists("ibm_cr_retention_policy.cr_retention_policy", conf), @@ -36,7 +39,7 @@ func TestAccIBMCrRetentionPolicyAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_cr_retention_policy.cr_retention_policy", "retain_untagged", retainUntagged), ), }, - resource.TestStep{ + { Config: testAccCheckIBMCrRetentionPolicyConfig(namespace, imagesPerRepoUpdate, retainUntaggedUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_cr_retention_policy.cr_retention_policy", "namespace", namespace), @@ -71,7 +74,7 @@ func testAccCheckIBMCrRetentionPolicyExists(n string, obj containerregistryv1.Re return fmt.Errorf("Not found: %s", n) } - containerRegistryClient, err := testAccProvider.Meta().(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerRegistryV1() if err != nil { return err } @@ -91,7 +94,7 @@ func testAccCheckIBMCrRetentionPolicyExists(n string, obj containerregistryv1.Re } func testAccCheckIBMCrRetentionPolicyDestroy(s *terraform.State) error { - containerRegistryClient, err := testAccProvider.Meta().(ClientSession).ContainerRegistryV1() + containerRegistryClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ContainerRegistryV1() if err != nil { return err } @@ -110,7 +113,7 @@ func testAccCheckIBMCrRetentionPolicyDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("cr_retention_policy still exists: %s", rs.Primary.ID) } else if response.StatusCode != 403 { // getRetentionPolicy returns 403 if the namespace doesn't exist - return fmt.Errorf("Error checking for cr_retention_policy (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for cr_retention_policy (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/resourcecontroller/README.md b/ibm/service/resourcecontroller/README.md new file mode 100644 index 000000000..e14eaaea6 --- /dev/null +++ b/ibm/service/resourcecontroller/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Resource Controller + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Resource Controller resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) +* IBM API Docs: [IBM API Docs for Resource Controller](https://cloud.ibm.com/apidocs/resource-controller/resource-controller) +* IBM Resource Controller SDK: [IBM SDK for Resource Controller](https://github.com/IBM/platform-services-go-sdk/tree/main/resourcecontrollerv2) diff --git a/ibm/service/resourcecontroller/data_source_ibm_resource_instance.go b/ibm/service/resourcecontroller/data_source_ibm_resource_instance.go new file mode 100644 index 000000000..5f3150b25 --- /dev/null +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_instance.go @@ -0,0 +1,255 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func DataSourceIBMResourceInstance() *schema.Resource { + return &schema.Resource{ + Read: DataSourceIBMResourceInstanceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "Resource instance name for example, myobjectstorage", + Type: schema.TypeString, + Required: true, + }, + + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The id of the resource group in which the instance is present", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_resource_instance", + "resource_group_id"), + }, + + "location": { + Description: "The location or the environment in which instance exists", + Optional: true, + Type: schema.TypeString, + Computed: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_resource_instance", + "location"), + }, + + "service": { + Description: "The service type of the instance", + Optional: true, + Type: schema.TypeString, + Computed: true, + }, + + "plan": { + Description: "The plan type of the instance", + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Description: "The resource instance status", + Type: schema.TypeString, + Computed: true, + }, + + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "CRN of resource instance", + }, + "tags": { + Type: schema.TypeSet, + Computed: true, + Description: "Tags of Resource Instance", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Guid of resource instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + + "extensions": { + Type: schema.TypeMap, + Computed: true, + Description: "The extended metadata as a map associated with the resource instance.", + }, + }, + } +} +func DataSourceIBMResourceInstanceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "region", + Optional: true}) + + ibmIBMResourceInstanceValidator := validate.ResourceValidator{ResourceName: "ibm_resource_instance", Schema: validateSchema} + return &ibmIBMResourceInstanceValidator +} + +func DataSourceIBMResourceInstanceRead(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() + if err != nil { + return err + } + rsAPI := rsConClient.ResourceServiceInstanceV2() + name := d.Get("name").(string) + + rsInstQuery := controllerv2.ServiceInstanceQuery{ + Name: name, + } + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rsInstQuery.ResourceGroupID = rsGrpID.(string) + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInstQuery.ResourceGroupID = defaultRg + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + if service, ok := d.GetOk("service"); ok { + + serviceOff, err := rsCatRepo.FindByName(service.(string), true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + rsInstQuery.ServiceID = serviceOff[0].ID + } + + var instances []models.ServiceInstanceV2 + + instances, err = rsAPI.ListInstances(rsInstQuery) + if err != nil { + return err + } + var filteredInstances []models.ServiceInstanceV2 + var location string + + if loc, ok := d.GetOk("location"); ok { + location = loc.(string) + for _, instance := range instances { + if flex.GetLocation(instance) == location { + filteredInstances = append(filteredInstances, instance) + } + } + } else { + filteredInstances = instances + } + + if len(filteredInstances) == 0 { + return fmt.Errorf("[ERROR] No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + + var instance models.ServiceInstanceV2 + + if len(filteredInstances) > 1 { + return fmt.Errorf("[ERROR] More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + instance = filteredInstances[0] + + d.SetId(instance.ID) + d.Set("status", instance.State) + d.Set("resource_group_id", instance.ResourceGroupID) + d.Set("location", instance.RegionID) + serviceOff, err := rsCatRepo.GetServiceName(instance.ServiceID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + d.Set("service", serviceOff) + + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.Crn.String()) + d.Set(flex.ResourceStatus, instance.State) + d.Set(flex.ResourceGroupName, instance.ResourceGroupName) + d.Set("guid", instance.Guid) + if len(instance.Extensions) == 0 { + d.Set("extensions", instance.Extensions) + } else { + d.Set("extensions", flex.Flatten(instance.Extensions)) + } + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/services/") + + servicePlan, err := rsCatRepo.GetServicePlanName(instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + d.Set("crn", instance.Crn.String()) + tags, err := flex.GetTagsUsingCRN(meta, instance.Crn.String()) + if err != nil { + log.Printf( + "Error on get of resource instance tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + + return nil +} diff --git a/ibm/service/resourcecontroller/data_source_ibm_resource_instance_test.go b/ibm/service/resourcecontroller/data_source_ibm_resource_instance_test.go new file mode 100644 index 000000000..921d9d057 --- /dev/null +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_instance_test.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMResourceInstanceDataSource_basic(t *testing.T) { + instanceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + instanceName2 := fmt.Sprintf("terraform_onerate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: setupResourceInstanceConfig(instanceName, instanceName2), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance2", "service", "kms"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance3", "service", "cloud-object-storage"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceDataSourceConfig(instanceName), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "name", instanceName), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "plan", "standard"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance", "location", "global"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceDataSourceConfigWithService(instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "name", instanceName), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "service", "kms"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "plan", "tiered-pricing"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance2", "location", "us-south"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceDataSourceConfigWithOneRate(instanceName2), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance3", "name", instanceName2), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance3", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance3", "plan", "cos-one-rate-plan"), + resource.TestCheckResourceAttr("data.ibm_resource_instance.testacc_ds_resource_instance3", "location", "global"), + ), + }, + }, + }) +} + +func setupResourceInstanceConfig(instanceName string, instanceName2 string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "instance2" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} +resource "ibm_resource_instance" "instance3" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + } + + +`, instanceName, instanceName, instanceName2) + +} + +func testAccCheckIBMResourceInstanceDataSourceConfig(instanceName string) string { + return fmt.Sprintf(` +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "instance2" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +data "ibm_resource_instance" "testacc_ds_resource_instance" { + name = ibm_resource_instance.instance.name + location = "global" + resource_group_id = data.ibm_resource_group.group.id +} +`, instanceName, instanceName) + +} + +func testAccCheckIBMResourceInstanceDataSourceConfigWithService(instanceName string) string { + return fmt.Sprintf(` + +resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "instance2" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} + +data "ibm_resource_instance" "testacc_ds_resource_instance2" { + name = ibm_resource_instance.instance2.name + service = "kms" +} +`, instanceName, instanceName) + +} +func testAccCheckIBMResourceInstanceDataSourceConfigWithOneRate(instanceName2 string) string { + return fmt.Sprintf(` +data "ibm_resource_group" "group" { + is_default=true +} + +resource "ibm_resource_instance" "instance3" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" +} + +data "ibm_resource_instance" "testacc_ds_resource_instance3" { + name = ibm_resource_instance.instance3.name + location = "global" + resource_group_id = data.ibm_resource_group.group.id +} +`, instanceName2) + +} diff --git a/ibm/service/resourcecontroller/data_source_ibm_resource_key.go b/ibm/service/resourcecontroller/data_source_ibm_resource_key.go new file mode 100644 index 000000000..9a1bf688f --- /dev/null +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_key.go @@ -0,0 +1,216 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller + +import ( + "encoding/json" + "fmt" + "log" + "sort" + "strings" + + "github.com/IBM-Cloud/bluemix-go/crn" + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMResourceKey() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMResourceKeyRead, + + Schema: map[string]*schema.Schema{ + "name": { + Description: "The name of the resource key", + Type: schema.TypeString, + Required: true, + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the resource instance", + ConflictsWith: []string{"resource_alias_id"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_resource_key", + "resource_instance_id"), + }, + + "resource_alias_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the resource alias", + ConflictsWith: []string{"resource_instance_id"}, + }, + + "role": { + Type: schema.TypeString, + Computed: true, + Description: "User role", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of resource key", + }, + + "credentials": { + Description: "Credentials asociated with the key", + Sensitive: true, + Type: schema.TypeMap, + Computed: true, + }, + + "credentials_json": { + Description: "Credentials asociated with the key in json string", + Type: schema.TypeString, + Sensitive: true, + Computed: true, + }, + + "most_recent": { + Description: "If true and multiple entries are found, the most recently created resource key is used. " + + "If false, an error is returned", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "crn of resource key", + }, + }, + } +} +func DataSourceIBMResourceKeyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_instance_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:%s"}, + Optional: true}) + + ibmDataSourceKeyResourceValidator := validate.ResourceValidator{ResourceName: "ibm_resource_key", Schema: validateSchema} + return &ibmDataSourceKeyResourceValidator +} + +func dataSourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerAPI() + if err != nil { + return err + } + rkAPI := rsContClient.ResourceServiceKey() + name := d.Get("name").(string) + mostRecent := d.Get("most_recent").(bool) + + keys, err := rkAPI.GetKeys(name) + if err != nil { + return err + } + var filteredKeys []models.ServiceKey + + if d.Get("resource_instance_id") == "" { + filteredKeys = keys + } else { + crn, err := getCRN(d, meta) + if err != nil { + return err + } + for _, key := range keys { + if key.SourceCrn == *crn { + filteredKeys = append(filteredKeys, key) + } + } + + } + + if len(filteredKeys) == 0 { + return fmt.Errorf("[ERROR] No resource keys found with name [%s]", name) + } + + var key models.ServiceKey + + if len(filteredKeys) > 1 { + if mostRecent { + key = mostRecentResourceKey(filteredKeys) + } else { + return fmt.Errorf("[ERROR] More than one resource key found with name matching [%s]. "+ + "Set 'most_recent' to true in your configuration to force the most recent resource key "+ + "to be used", name) + } + } else { + key = filteredKeys[0] + } + + d.SetId(key.ID) + + if redacted, ok := key.Credentials["redacted"].(string); ok { + log.Printf("Credentials are redacted with code: %s.The User doesn't have the correct access to view the credentials. Refer to the API documentation for additional details.", redacted) + } + if roleCrn, ok := key.Parameters["role_crn"].(string); ok { + d.Set("role", roleCrn[strings.LastIndex(roleCrn, ":")+1:]) + } else if roleCrn, ok := key.Credentials["iam_role_crn"].(string); ok { + d.Set("role", roleCrn[strings.LastIndex(roleCrn, ":")+1:]) + } + + d.Set("credentials", flex.Flatten(key.Credentials)) + creds, err := json.Marshal(key.Credentials) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling resource key credentials: %s", err) + } + if err = d.Set("credentials_json", string(creds)); err != nil { + return fmt.Errorf("[ERROR] Error setting the credentials json: %s", err) + } + d.Set("status", key.State) + d.Set("crn", key.Crn.String()) + return nil +} + +func getCRN(d *schema.ResourceData, meta interface{}) (*crn.CRN, error) { + + rsContClient, err := meta.(conns.ClientSession).ResourceControllerAPI() + if err != nil { + return nil, err + } + + if insID, ok := d.GetOk("resource_instance_id"); ok { + instance, err := rsContClient.ResourceServiceInstance().GetInstance(insID.(string)) + if err != nil { + return nil, err + } + return &(instance.Crn), nil + + } + + alias, err := rsContClient.ResourceServiceAlias().Alias(d.Get("resource_alias_id").(string)) + if err != nil { + return nil, err + } + return &(alias.CRN), nil + +} + +type resourceKeys []models.ServiceKey + +func (k resourceKeys) Len() int { return len(k) } + +func (k resourceKeys) Swap(i, j int) { k[i], k[j] = k[j], k[i] } + +func (k resourceKeys) Less(i, j int) bool { + return (*k[i].CreatedAt).Before(*k[j].CreatedAt) +} + +func mostRecentResourceKey(keys resourceKeys) models.ServiceKey { + sortedKeys := keys + sort.Sort(sortedKeys) + return sortedKeys[len(sortedKeys)-1] +} diff --git a/ibm/data_source_ibm_resource_key_test.go b/ibm/service/resourcecontroller/data_source_ibm_resource_key_test.go similarity index 93% rename from ibm/data_source_ibm_resource_key_test.go rename to ibm/service/resourcecontroller/data_source_ibm_resource_key_test.go index 49c82e60e..8db60b2fb 100644 --- a/ibm/data_source_ibm_resource_key_test.go +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_key_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcecontroller_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMResourceKeyDataSource_basic(t *testing.T) { resourceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMResourceKeyDataSourceConfig(resourceName, resourceKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_resource_key.testacc_ds_resource_key", "name", resourceKey), @@ -39,10 +41,10 @@ func TestAccIBMResourceKeyDataSource_mostrecent(t *testing.T) { resourceKey := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMResourceKeyDataSourceConfigRecent(resourceName, resourceKey), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_resource_key.testacc_ds_resource_key", "name", resourceKey), diff --git a/ibm/data_source_ibm_resource_quota.go b/ibm/service/resourcecontroller/data_source_ibm_resource_quota.go similarity index 86% rename from ibm/data_source_ibm_resource_quota.go rename to ibm/service/resourcecontroller/data_source_ibm_resource_quota.go index 26d9374a9..b40230640 100644 --- a/ibm/data_source_ibm_resource_quota.go +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_quota.go @@ -1,15 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcecontroller import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMResourceQuota() *schema.Resource { +func DataSourceIBMResourceQuota() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMResourceQuotaRead, @@ -59,7 +60,7 @@ func dataSourceIBMResourceQuota() *schema.Resource { } func dataSourceIBMResourceQuotaRead(d *schema.ResourceData, meta interface{}) error { - rsManagementAPI, err := meta.(ClientSession).ResourceManagementAPIv2() + rsManagementAPI, err := meta.(conns.ClientSession).ResourceManagementAPIv2() if err != nil { return err } @@ -67,11 +68,11 @@ func dataSourceIBMResourceQuotaRead(d *schema.ResourceData, meta interface{}) er rsQuotaName := d.Get("name").(string) rsQuotas, err := rsQuota.FindByName(rsQuotaName) if err != nil { - return fmt.Errorf("Error retrieving resource quota: %s", err) + return fmt.Errorf("[ERROR] Error retrieving resource quota: %s", err) } if len(rsQuotas) == 0 { - return fmt.Errorf("Error retrieving resource quota: %s", err) + return fmt.Errorf("[ERROR] Error retrieving resource quota: %s", err) } rsQuotaFields := rsQuotas[0] diff --git a/ibm/data_source_ibm_resource_quota_test.go b/ibm/service/resourcecontroller/data_source_ibm_resource_quota_test.go similarity index 80% rename from ibm/data_source_ibm_resource_quota_test.go rename to ibm/service/resourcecontroller/data_source_ibm_resource_quota_test.go index e4dc56003..c4aefb545 100644 --- a/ibm/data_source_ibm_resource_quota_test.go +++ b/ibm/service/resourcecontroller/data_source_ibm_resource_quota_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcecontroller_test import ( "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIBMResourceQuotaDataSource_basic(t *testing.T) { name := "Trial Quota" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMResourceQuotaDataSourceConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_resource_quota.testacc_ds_resource_quota", "name", name), @@ -31,8 +33,8 @@ func TestAccIBMResourceQuotaDataSource_basic(t *testing.T) { func TestAccIBMResourceQuotaDataSource_invalid_name(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMResourceQuotaDataSourceConfig("abc"), diff --git a/ibm/service/resourcecontroller/resource_ibm_resource_instance.go b/ibm/service/resourcecontroller/resource_ibm_resource_instance.go new file mode 100644 index 000000000..fff1e4133 --- /dev/null +++ b/ibm/service/resourcecontroller/resource_ibm_resource_instance.go @@ -0,0 +1,959 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "strconv" + "strings" + "time" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +const ( + RsInstanceSuccessStatus = "active" + RsInstanceProgressStatus = "in progress" + RsInstanceProvisioningStatus = "provisioning" + RsInstanceInactiveStatus = "inactive" + RsInstanceFailStatus = "failed" + RsInstanceRemovedStatus = "removed" + RsInstanceReclamation = "pending_reclamation" +) + +func ResourceIBMResourceInstance() *schema.Resource { + return &schema.Resource{ + Create: ResourceIBMResourceInstanceCreate, + Read: ResourceIBMResourceInstanceRead, + Update: ResourceIBMResourceInstanceUpdate, + Delete: ResourceIBMResourceInstanceDelete, + Exists: ResourceIBMResourceInstanceExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "A name for the resource instance", + }, + + "service": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the service offering like cloud-object-storage, kms etc", + }, + + "plan": { + Type: schema.TypeString, + Required: true, + Description: "The plan type of the service", + }, + + "location": { + Description: "The location where the instance available", + Required: true, + ForceNew: true, + Type: schema.TypeString, + ValidateFunc: validate.InvokeValidator("ibm_resource_instance", + "location"), + }, + + "resource_group_id": { + Description: "The resource group id", + Optional: true, + ForceNew: true, + Type: schema.TypeString, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_resource_instance", + "resource_group_id"), + }, + + "parameters": { + Type: schema.TypeMap, + Optional: true, + Description: "Arbitrary parameters to pass. Must be a JSON object", + ConflictsWith: []string{"parameters_json"}, + }, + "parameters_json": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"parameters"}, + StateFunc: func(v interface{}) string { + json, err := flex.NormalizeJSONString(v) + if err != nil { + return fmt.Sprintf("%q", err.Error()) + } + return json + }, + Description: "Arbitrary parameters to pass in Json string format", + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_resource_instance", "tags")}, + Set: flex.ResourceIBMVPCHash, + ValidateFunc: validate.InvokeValidator("ibm_resource_instance", + "tags"), + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of resource instance", + }, + + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "CRN of resource instance", + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "Guid of resource instance", + }, + + "service_endpoints": { + Description: "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "public-and-private"}), + }, + + "dashboard_url": { + Description: "Dashboard URL to access resource.", + Type: schema.TypeString, + Computed: true, + }, + + "plan_history": { + Description: "The plan history of the instance.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_plan_id": { + Type: schema.TypeString, + Computed: true, + }, + "start_date": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "account_id": { + Description: "An alpha-numeric value identifying the account ID.", + Type: schema.TypeString, + Computed: true, + }, + + "resource_group_crn": { + Description: "The long ID (full CRN) of the resource group", + Type: schema.TypeString, + Computed: true, + }, + + "resource_id": { + Description: "The unique ID of the offering", + Type: schema.TypeString, + Computed: true, + }, + + "resource_plan_id": { + Description: "The unique ID of the plan associated with the offering", + Type: schema.TypeString, + Computed: true, + }, + + "target_crn": { + Description: "The full deployment CRN as defined in the global catalog", + Type: schema.TypeString, + Computed: true, + }, + + "state": { + Description: "The current state of the instance.", + Type: schema.TypeString, + Computed: true, + }, + + "type": { + Description: "The type of the instance, e.g. service_instance.", + Type: schema.TypeString, + Computed: true, + }, + + "sub_type": { + Description: "The sub-type of instance, e.g. cfaas .", + Type: schema.TypeString, + Computed: true, + }, + + "allow_cleanup": { + Description: "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + Type: schema.TypeBool, + Computed: true, + }, + + "locked": { + Description: "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + Type: schema.TypeBool, + Computed: true, + }, + + "last_operation": { + Type: schema.TypeMap, + Computed: true, + Description: "The status of the last operation requested on the instance", + }, + + "resource_aliases_url": { + Description: "The relative path to the resource aliases for the instance.", + Type: schema.TypeString, + Computed: true, + }, + + "resource_bindings_url": { + Description: "The relative path to the resource bindings for the instance.", + Type: schema.TypeString, + Computed: true, + }, + + "resource_keys_url": { + Description: "The relative path to the resource keys for the instance.", + Type: schema.TypeString, + Computed: true, + }, + + "created_at": { + Type: schema.TypeString, + Description: "The date when the instance was created.", + Computed: true, + }, + + "created_by": { + Type: schema.TypeString, + Description: "The subject who created the instance.", + Computed: true, + }, + + "update_at": { + Type: schema.TypeString, + Description: "The date when the instance was last updated.", + Computed: true, + }, + + "update_by": { + Type: schema.TypeString, + Description: "The subject who updated the instance.", + Computed: true, + }, + + "deleted_at": { + Type: schema.TypeString, + Description: "The date when the instance was deleted.", + Computed: true, + }, + + "deleted_by": { + Type: schema.TypeString, + Description: "The subject who deleted the instance.", + Computed: true, + }, + + "scheduled_reclaim_at": { + Type: schema.TypeString, + Description: "The date when the instance was scheduled for reclamation.", + Computed: true, + }, + + "scheduled_reclaim_by": { + Type: schema.TypeString, + Description: "The subject who initiated the instance reclamation.", + Computed: true, + }, + + "restored_at": { + Type: schema.TypeString, + Description: "The date when the instance under reclamation was restored.", + Computed: true, + }, + + "restored_by": { + Type: schema.TypeString, + Description: "The subject who restored the instance back from reclamation.", + Computed: true, + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + }, + + "extensions": { + Type: schema.TypeMap, + Computed: true, + Description: "The extended metadata as a map associated with the resource instance.", + }, + }, + } +} + +func ResourceIBMResourceInstanceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_group_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:id"}, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "tags", + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "region", + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmResourceInstanceResourceValidator := validate.ResourceValidator{ResourceName: "ibm_resource_instance", Schema: validateSchema} + return &ibmResourceInstanceResourceValidator +} + +func ResourceIBMResourceInstanceCreate(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + serviceName := d.Get("service").(string) + plan := d.Get("plan").(string) + name := d.Get("name").(string) + location := d.Get("location").(string) + + rsInst := rc.CreateResourceInstanceOptions{ + Name: &name, + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(serviceName, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + if metadata, ok := serviceOff[0].Metadata.(*models.ServiceResourceMetadata); ok { + if !metadata.Service.RCProvisionable { + return fmt.Errorf("%s cannot be provisioned by resource controller", serviceName) + } + } else { + return fmt.Errorf("[ERROR] Cannot create instance of resource %s\nUse 'ibm_service_instance' if the resource is a Cloud Foundry service", serviceName) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + rsInst.ResourcePlanID = &servicePlan + + deployments, err := rsCatRepo.ListDeployments(servicePlan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving deployment for plan %s : %s", plan, err) + } + if len(deployments) == 0 { + return fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan) + } + deployments, supportedLocations := FilterDeployments(deployments, location) + + if len(deployments) == 0 { + locationList := make([]string, 0, len(supportedLocations)) + for l := range supportedLocations { + locationList = append(locationList, l) + } + return fmt.Errorf("[ERROR] No deployment found for service plan %s at location %s.\nValid location(s) are: %q.\nUse 'ibm_service_instance' if the service is a Cloud Foundry service", plan, location, locationList) + } + + rsInst.Target = &deployments[0].CatalogCRN + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rg := rsGrpID.(string) + rsInst.ResourceGroup = &rg + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInst.ResourceGroup = &defaultRg + } + + params := map[string]interface{}{} + + if serviceEndpoints, ok := d.GetOk("service_endpoints"); ok { + params["service-endpoints"] = serviceEndpoints.(string) + } + + if parameters, ok := d.GetOk("parameters"); ok { + temp := parameters.(map[string]interface{}) + for k, v := range temp { + if v == "true" || v == "false" { + b, _ := strconv.ParseBool(v.(string)) + params[k] = b + } else if strings.HasPrefix(v.(string), "[") && strings.HasSuffix(v.(string), "]") { + //transform v.(string) to be []string + arrayString := v.(string) + result := []string{} + trimLeft := strings.TrimLeft(arrayString, "[") + trimRight := strings.TrimRight(trimLeft, "]") + if len(trimRight) == 0 { + params[k] = result + } else { + array := strings.Split(trimRight, ",") + for _, a := range array { + result = append(result, strings.Trim(a, "\"")) + } + params[k] = result + } + } else { + params[k] = v + } + } + + } + if s, ok := d.GetOk("parameters_json"); ok { + json.Unmarshal([]byte(s.(string)), ¶ms) + } + + rsInst.Parameters = params + + //Start to create resource instance + instance, resp, err := rsConClient.CreateResourceInstance(&rsInst) + if err != nil { + log.Printf( + "Error when creating resource instance: %s, Instance info NAME->%s, LOCATION->%s, GROUP_ID->%s, PLAN_ID->%s", + err, *rsInst.Name, *rsInst.Target, *rsInst.ResourceGroup, *rsInst.ResourcePlanID) + return fmt.Errorf("[ERROR] Error when creating resource instance: %s with resp code: %s", err, resp) + } + + d.SetId(*instance.ID) + + _, err = waitForResourceInstanceCreate(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for create resource instance (%s) to be succeeded: %s", d.Id(), err) + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + + return ResourceIBMResourceInstanceRead(d, meta) +} +func ResourceIBMResourceInstanceRead(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) + } + + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on get of resource instance tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + d.Set("name", instance.Name) + d.Set("status", instance.State) + d.Set("resource_group_id", instance.ResourceGroupID) + if instance.CRN != nil { + location := strings.Split(*instance.CRN, ":") + if len(location) > 5 { + d.Set("location", location[5]) + } + } + d.Set("crn", instance.CRN) + d.Set("dashboard_url", instance.DashboardURL) + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.GetServiceName(*instance.ResourceID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + d.Set("service", serviceOff) + + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.CRN) + d.Set(flex.ResourceStatus, instance.State) + d.Set(flex.ResourceGroupName, instance.ResourceGroupCRN) + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/services/") + + servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + d.Set("guid", instance.GUID) + if instance.Parameters != nil { + if endpoint, ok := instance.Parameters["service-endpoints"]; ok { + d.Set("service_endpoints", endpoint) + } + } + + if len(instance.Extensions) == 0 { + d.Set("extensions", instance.Extensions) + } else { + d.Set("extensions", flex.Flatten(instance.Extensions)) + } + d.Set("account_id", instance.AccountID) + d.Set("restored_by", instance.RestoredBy) + if instance.RestoredAt != nil { + d.Set("restored_at", instance.RestoredAt.String()) + } + d.Set("scheduled_reclaim_by", instance.ScheduledReclaimBy) + if instance.ScheduledReclaimAt != nil { + d.Set("scheduled_reclaim_at", instance.ScheduledReclaimAt.String()) + } + if instance.DeletedAt != nil { + d.Set("deleted_at", instance.DeletedAt.String()) + } + d.Set("deleted_by", instance.DeletedBy) + if instance.UpdatedAt != nil { + d.Set("update_at", instance.UpdatedAt.String()) + } + if instance.CreatedAt != nil { + d.Set("created_at", instance.CreatedAt.String()) + } + d.Set("update_by", instance.UpdatedBy) + d.Set("created_by", instance.CreatedBy) + d.Set("resource_keys_url", instance.ResourceKeysURL) + d.Set("resource_bindings_url", instance.ResourceBindingsURL) + d.Set("resource_aliases_url", instance.ResourceAliasesURL) + if instance.LastOperation != nil { + d.Set("last_operation", flex.Flatten(instance.LastOperation)) + } + d.Set("locked", instance.Locked) + d.Set("allow_cleanup", instance.AllowCleanup) + d.Set("type", instance.Type) + d.Set("state", instance.State) + d.Set("sub_type", instance.SubType) + d.Set("target_crn", instance.TargetCRN) + d.Set("resource_plan_id", instance.ResourcePlanID) + d.Set("resource_id", instance.ResourceID) + d.Set("resource_group_crn", instance.ResourceGroupCRN) + if instance.PlanHistory != nil { + d.Set("plan_history", flattenPlanHistory(instance.PlanHistory)) + } + + return nil +} + +func ResourceIBMResourceInstanceUpdate(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + instanceID := d.Id() + + resourceInstanceUpdate := rc.UpdateResourceInstanceOptions{ + ID: &instanceID, + } + if d.HasChange("name") { + name := d.Get("name").(string) + resourceInstanceUpdate.Name = &name + } + + if d.HasChange("plan") { + plan := d.Get("plan").(string) + service := d.Get("service").(string) + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(service, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + + resourceInstanceUpdate.ResourcePlanID = &servicePlan + + } + params := map[string]interface{}{} + + if d.HasChange("service_endpoints") { + endpoint := d.Get("service_endpoints").(string) + params["service-endpoints"] = endpoint + } + + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + if d.HasChange("parameters") { + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) + } + + if parameters, ok := d.GetOk("parameters"); ok { + temp := parameters.(map[string]interface{}) + for k, v := range temp { + if v == "true" || v == "false" { + b, _ := strconv.ParseBool(v.(string)) + params[k] = b + } else if strings.HasPrefix(v.(string), "[") && strings.HasSuffix(v.(string), "]") { + //transform v.(string) to be []string + result := []string{} + arrayString := v.(string) + trimLeft := strings.TrimLeft(arrayString, "[") + trimRight := strings.TrimRight(trimLeft, "]") + if len(trimRight) == 0 { + params[k] = result + } else { + array := strings.Split(trimRight, ",") + for _, a := range array { + result = append(result, strings.Trim(a, "\"")) + } + params[k] = result + } + + } else { + params[k] = v + } + } + } + serviceEndpoints := d.Get("service_endpoints").(string) + if serviceEndpoints != "" { + endpoint := d.Get("service_endpoints").(string) + params["service-endpoints"] = endpoint + } else if _, ok := instance.Parameters["service-endpoints"]; ok { + params["service-endpoints"] = instance.Parameters["service-endpoints"] + } + + } + + if d.HasChange("service_endpoints") || d.HasChange("parameters") { + resourceInstanceUpdate.Parameters = params + } + if d.HasChange("parameters_json") { + if s, ok := d.GetOk("parameters_json"); ok { + json.Unmarshal([]byte(s.(string)), ¶ms) + resourceInstanceUpdate.Parameters = params + } + } + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting resource instance: %s with resp code: %s", err, resp) + } + + if d.HasChange("tags") { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on update of resource instance (%s) tags: %s", d.Id(), err) + } + } + + _, resp, err = rsConClient.UpdateResourceInstance(&resourceInstanceUpdate) + if err != nil { + return fmt.Errorf("[ERROR] Error updating resource instance: %s with resp code: %s", err, resp) + } + + _, err = waitForResourceInstanceUpdate(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for update resource instance (%s) to be succeeded: %s", d.Id(), err) + } + + return ResourceIBMResourceInstanceRead(d, meta) +} + +func ResourceIBMResourceInstanceDelete(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + id := d.Id() + recursive := true + resourceInstanceDelete := rc.DeleteResourceInstanceOptions{ + ID: &id, + Recursive: &recursive, + } + + resp, error := rsConClient.DeleteResourceInstance(&resourceInstanceDelete) + if error != nil { + if resp != nil && resp.StatusCode == 410 { + return nil + } + return fmt.Errorf("[ERROR] Error deleting resource instance: %s with resp code: %s", error, resp) + } + + _, err = waitForResourceInstanceDelete(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for resource instance (%s) to be deleted: %s", d.Id(), err) + } + + d.SetId("") + + return nil +} +func ResourceIBMResourceInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting resource instance: %s with resp code: %s", err, resp) + } + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, RsInstanceReclamation)) { + log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state") + d.SetId("") + return false, nil + } + + return *instance.ID == instanceID, nil +} + +func waitForResourceInstanceCreate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{RsInstanceProgressStatus, RsInstanceInactiveStatus, RsInstanceProvisioningStatus}, + Target: []string{RsInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %v", d.Id(), err) + } + return nil, "", fmt.Errorf("[ERROR] Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) + } + if *instance.State == RsInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %v", d.Id(), err) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func waitForResourceInstanceUpdate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{RsInstanceProgressStatus, RsInstanceInactiveStatus}, + Target: []string{RsInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %v", d.Id(), err) + } + return nil, "", fmt.Errorf("[ERROR] Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) + } + if *instance.State == RsInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed: %v", d.Id(), err) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func waitForResourceInstanceDelete(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + stateConf := &resource.StateChangeConf{ + Pending: []string{RsInstanceProgressStatus, RsInstanceInactiveStatus, RsInstanceSuccessStatus}, + Target: []string{RsInstanceRemovedStatus, RsInstanceReclamation}, + Refresh: func() (interface{}, string, error) { + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return instance, RsInstanceSuccessStatus, nil + } + return nil, "", fmt.Errorf("[ERROR] Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) + } + if *instance.State == RsInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %v", d.Id(), err) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func FilterDeployments(deployments []models.ServiceDeployment, location string) ([]models.ServiceDeployment, map[string]bool) { + supportedDeployments := []models.ServiceDeployment{} + supportedLocations := make(map[string]bool) + for _, d := range deployments { + if d.Metadata.RCCompatible { + deploymentLocation := d.Metadata.Deployment.Location + supportedLocations[deploymentLocation] = true + if deploymentLocation == location { + supportedDeployments = append(supportedDeployments, d) + } + } + } + return supportedDeployments, supportedLocations +} + +func flattenPlanHistory(keys []rc.PlanHistoryItem) []interface{} { + var out = make([]interface{}, len(keys)) + for i, k := range keys { + m := make(map[string]interface{}) + m["resource_plan_id"] = k.ResourcePlanID + m["start_date"] = k.StartDate.String() + out[i] = m + } + return out +} diff --git a/ibm/service/resourcecontroller/resource_ibm_resource_instance_test.go b/ibm/service/resourcecontroller/resource_ibm_resource_instance_test.go new file mode 100644 index 000000000..d40146555 --- /dev/null +++ b/ibm/service/resourcecontroller/resource_ibm_resource_instance_test.go @@ -0,0 +1,425 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller_test + +import ( + "fmt" + "regexp" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMResourceInstanceBasic(t *testing.T) { + serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + updateName := fmt.Sprintf("tf-kms-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMResourceInstanceBasic(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists("ibm_resource_instance.instance"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", serviceName), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceUpdateWithSameName(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists("ibm_resource_instance.instance"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", serviceName), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceUpdate(updateName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", updateName), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "standard"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), + ), + }, + { + Config: testAccCheckIBMResourceInstanceNewServiceType(updateName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", updateName), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "kms"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "tiered-pricing"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "us-south"), + ), + }, + }, + }) +} + +func TestAccIBMResourceInstanceImport(t *testing.T) { + serviceName := fmt.Sprintf("tf-ins-%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_resource_instance.instance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMResourceInstanceBasic(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "cloud-object-storage"), + resource.TestCheckResourceAttr(resourceName, "plan", "standard"), + resource.TestCheckResourceAttr(resourceName, "location", "global"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "wait_time_minutes", "parameters"}, + }, + }, + }) +} + +func TestAccIBMResourceInstanceWithServiceendpoints(t *testing.T) { + serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_resource_instance.instance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + + { + Config: testAccCheckIBMResourceInstanceServiceendpoints(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(resourceName, "plan", "standard"), + resource.TestCheckResourceAttr(resourceName, "location", "us-south"), + ), + }, + }, + }) +} + +func TestAccIBMResourceInstanceWithResourceGroup(t *testing.T) { + serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + resourceName := "ibm_resource_instance.instance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMResourceInstanceWithResourceGroup(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", serviceName), + resource.TestCheckResourceAttr(resourceName, "service", "cloud-object-storage"), + resource.TestCheckResourceAttr(resourceName, "plan", "standard"), + resource.TestCheckResourceAttr(resourceName, "location", "global"), + ), + }, + }, + }) +} + +func TestAccIBMCOSResourceInstanceOneRatePlan(t *testing.T) { + serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCOSResourceInstanceOneRatePlan(serviceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMResourceInstanceExists("ibm_resource_instance.instance"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "name", serviceName), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "service", "cloud-object-storage"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "plan", "cos-one-rate-plan"), + resource.TestCheckResourceAttr("ibm_resource_instance.instance", "location", "global"), + ), + }, + }, + }) +} + +func TestAccIBMCOSResourceInstancewithoutplan(t *testing.T) { + serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCOSResourceInstancewithoutplan(serviceName), + ExpectError: regexp.MustCompile("Missing required argument"), + }, + }, + }) +} + +func TestAccIBMCOSResourceInstanceWithInvalidPlan(t *testing.T) { + serviceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMResourceInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCOSResourceInstanceWithInvalidPlan(serviceName), + ExpectError: regexp.MustCompile("Error retrieving deployment for plan invalidcosplan"), + }, + }, + }) +} + +func testAccCheckIBMResourceInstanceDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_resource_instance" { + continue + } + + instanceID := rs.Primary.ID + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + // Try to find the key + instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + + if err == nil { + if *instance.State == "active" { + return fmt.Errorf("Resource Instance still exists: %s", rs.Primary.ID) + } + } else { + if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if Resource Instance (%s) has been destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) + } + } + } + + return nil +} + +func testAccCheckIBMResourceInstanceExists(n string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instanceID := rs.Primary.ID + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + _, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + + if err != nil { + return fmt.Errorf("Get resource instance error: %s with resp code: %s", err, resp) + } + + return nil + } +} + +func testAccCheckIBMResourceInstanceBasic(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + parameters = { + "HMAC" = true + } + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } + } + `, serviceName) +} +func testAccCheckIBMCOSResourceInstanceOneRatePlan(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" + parameters = { + "HMAC" = true + } + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } + } + `, serviceName) +} + +func testAccCheckIBMCOSResourceInstancewithoutplan(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + location = "global" + parameters = { + "HMAC" = true + } + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } + } + `, serviceName) +} +func testAccCheckIBMCOSResourceInstanceWithInvalidPlan(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "invalidcosplan" + location = "global" + parameters = { + "HMAC" = true + } + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } + } + `, serviceName) +} +func testAccCheckIBMResourceInstanceUpdateWithSameName(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + parameters = { + "HMAC" = true + } + } + + `, serviceName) +} + +func testAccCheckIBMResourceInstanceUpdate(updateName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + parameters = { + "HMAC" = true + } + } + `, updateName) +} + +func testAccCheckIBMResourceInstanceNewServiceType(updateName string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "kms" + plan = "tiered-pricing" + location = "us-south" + } + `, updateName) +} + +func testAccCheckIBMResourceInstanceWithResourceGroup(serviceName string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.group.id + parameters = { + "HMAC" = true + } + } + `, serviceName) +} + +func testAccCheckIBMResourceInstanceServiceendpoints(serviceName string) string { + return fmt.Sprintf(` + + resource "ibm_resource_instance" "instance" { + name = "%s" + location = "us-south" + service = "databases-for-postgresql" + plan = "standard" + parameters = { + members_memory_allocation_mb = "4096" + } + + //service_endpoints = "public-and-private" + timeouts { + create = "25m" + update = "15m" + delete = "15m" + } + } + + `, serviceName) +} diff --git a/ibm/service/resourcecontroller/resource_ibm_resource_key.go b/ibm/service/resourcecontroller/resource_ibm_resource_key.go new file mode 100644 index 000000000..de1d2dba5 --- /dev/null +++ b/ibm/service/resourcecontroller/resource_ibm_resource_key.go @@ -0,0 +1,505 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package resourcecontroller + +import ( + "encoding/json" + "fmt" + "log" + "strconv" + "strings" + "time" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" +) + +func ResourceIBMResourceKey() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMResourceKeyCreate, + Read: resourceIBMResourceKeyRead, + Update: resourceIBMResourceKeyUpdate, + Delete: resourceIBMResourceKeyDelete, + Exists: resourceIBMResourceKeyExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the resource key", + }, + + "role": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Name of the user role.Valid roles are Writer, Reader, Manager, Administrator, Operator, Viewer, Editor and Custom Roles.", + // ValidateFunc: validateRole, + }, + + "resource_instance_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The id of the resource instance for which to create resource key", + ConflictsWith: []string{"resource_alias_id"}, + ValidateFunc: validate.InvokeValidator("ibm_resource_key", + "resource_instance_id"), + }, + + "resource_alias_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The id of the resource alias for which to create resource key", + ConflictsWith: []string{"resource_instance_id"}, + }, + + "parameters": { + Type: schema.TypeMap, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Arbitrary parameters to pass. Must be a JSON object", + }, + + "credentials": { + Description: "Credentials asociated with the key", + Type: schema.TypeMap, + Sensitive: true, + Computed: true, + }, + "credentials_json": { + Description: "Credentials asociated with the key in json string", + Type: schema.TypeString, + Sensitive: true, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of resource key", + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "crn of resource key", + }, + + "guid": { + Type: schema.TypeString, + Computed: true, + Description: "When you create a new key, a globally unique identifier (GUID) is assigned.", + }, + + "url": { + Type: schema.TypeString, + Computed: true, + Description: "When you created a new key, a relative URL path is created identifying the location of the key.", + }, + + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "An alpha-numeric value identifying the account ID.", + }, + + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The short ID of the resource group.", + }, + + "source_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of resource instance or alias associated to the key.", + }, + + "state": { + Type: schema.TypeString, + Computed: true, + Description: "The state of the key.", + }, + + "iam_compatible": { + Type: schema.TypeBool, + Computed: true, + Description: "Specifies whether the key's credentials support IAM.", + }, + + "resource_instance_url": { + Type: schema.TypeString, + Computed: true, + Description: "The relative path to the resource.", + }, + + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date when the key was created.", + }, + + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date when the key was last updated.", + }, + + "deleted_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date when the key was deleted.", + }, + + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The subject who created the key.", + }, + + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The subject who updated the key.", + }, + + "deleted_by": { + Type: schema.TypeString, + Computed: true, + Description: "The subject who deleted the key.", + }, + }, + } +} + +func ResourceIBMResourceKeyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "resource_instance_id", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_instance", + CloudDataRange: []string{"service:%s"}, + Optional: true}) + + ibmResourceKeyResourceValidator := validate.ResourceValidator{ResourceName: "ibm_resource_key", Schema: validateSchema} + return &ibmResourceKeyResourceValidator +} + +func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) error { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + name := d.Get("name").(string) + + var instanceID, aliasID string + if insID, ok := d.GetOk("resource_instance_id"); ok { + instanceID = insID.(string) + } + + if aliID, ok := d.GetOk("resource_alias_id"); ok { + aliasID = aliID.(string) + } + + if instanceID == "" && aliasID == "" { + return fmt.Errorf("[ERROR] Provide either `resource_instance_id` or `resource_alias_id`") + } + + keyParameters := rc.ResourceKeyPostParameters{} + + if parameters, ok := d.GetOk("parameters"); ok { + temp := parameters.(map[string]interface{}) + for k, v := range temp { + if v == "true" || v == "false" { + b, _ := strconv.ParseBool(v.(string)) + keyParameters.SetProperty(k, b) + } else { + keyParameters.SetProperty(k, v) + } + } + } + + resourceInstance, sourceCRN, err := getResourceInstanceAndCRN(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource key when get instance and CRN: %s", err) + } + + serviceID := resourceInstance.ResourceID + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource key when get ResourceCatalogAPI: %s", err) + } + + service, err := rsCatClient.ResourceCatalog().Get(*serviceID, true) + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource key when get service: %s", err) + } + + resourceKeyCreate := rc.CreateResourceKeyOptions{ + Name: &name, + Source: sourceCRN, + Parameters: &keyParameters, + } + if r, ok := d.GetOk("role"); ok { + role := r.(string) + serviceRole, err := getRoleFromName(role, service.Name, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource key when get role: %s", err) + } + keyParameters.SetProperty("role_crn", serviceRole.RoleID) + resourceKeyCreate.Role = serviceRole.RoleID + } + + resourceKey, resp, err := rsContClient.CreateResourceKey(&resourceKeyCreate) + if err != nil { + return fmt.Errorf("[ERROR] Error creating resource key: %s with resp code: %s", err, resp) + } + + d.SetId(*resourceKey.ID) + + return resourceIBMResourceKeyRead(d, meta) +} + +func resourceIBMResourceKeyUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + resourceKeyID := d.Id() + resourceKeyGet := rc.GetResourceKeyOptions{ + ID: &resourceKeyID, + } + + resourceKey, resp, err := rsContClient.GetResourceKey(&resourceKeyGet) + if err != nil || resourceKey == nil { + return fmt.Errorf("[ERROR] Error retrieving resource key: %s with resp : %s", err, resp) + } + var credInterface map[string]interface{} + cred, _ := json.Marshal(resourceKey.Credentials) + json.Unmarshal(cred, &credInterface) + d.Set("credentials", flex.Flatten(credInterface)) + + creds, err := json.Marshal(resourceKey.Credentials) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling resource key credentials: %s", err) + } + if err = d.Set("credentials_json", string(creds)); err != nil { + return fmt.Errorf("[ERROR] Error setting the credentials json: %s", err) + } + d.Set("name", *resourceKey.Name) + d.Set("status", *resourceKey.State) + if resourceKey.Credentials != nil && resourceKey.Credentials.Redacted != nil { + log.Printf("Credentials are redacted with code: %s.The User doesn't have the correct access to view the credentials. Refer to the API documentation for additional details.", *resourceKey.Credentials.Redacted) + } + if resourceKey.Credentials != nil && resourceKey.Credentials.IamRoleCRN != nil { + roleCrn := *resourceKey.Credentials.IamRoleCRN + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err == nil { + var resourceCRN string + if resourceKey.CRN != nil { + serviceName := strings.Split(*resourceKey.CRN, ":") + if len(serviceName) > 4 { + resourceCRN = serviceName[4] + } + } + listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ + AccountID: resourceKey.AccountID, + ServiceName: &resourceCRN, + } + roleList, resp, err := iamPolicyManagementClient.ListRoles(listRoleOptions) + roles := flex.MapRoleListToPolicyRoles(*roleList) + if err == nil && len(roles) > 0 { + for _, role := range roles { + if *role.RoleID == roleCrn { + RoleName := role.DisplayName + d.Set("role", RoleName) + } + } + } + if err != nil { + log.Printf("[ERROR] Error listing IAM Roles %s, %s", err, resp) + } + } + } + + sCrn := *resourceKey.SourceCRN + if sCrn != "" { + d.Set("resource_instance_id", sCrn) + } + + d.Set("crn", *resourceKey.CRN) + + d.Set("guid", *resourceKey.GUID) + d.Set("url", *resourceKey.URL) + d.Set("account_id", *resourceKey.AccountID) + d.Set("resource_group_id", *resourceKey.ResourceGroupID) + d.Set("source_crn", *resourceKey.SourceCRN) + d.Set("state", *resourceKey.State) + d.Set("iam_compatible", *resourceKey.IamCompatible) + d.Set("resource_instance_url", *resourceKey.ResourceInstanceURL) + if resourceKey.CreatedAt != nil { + d.Set("created_at", resourceKey.CreatedAt.String()) + } else { + d.Set("created_at", "") + } + if resourceKey.UpdatedAt != nil { + d.Set("updated_at", resourceKey.UpdatedAt.String()) + } else { + d.Set("updated_at", "") + } + if resourceKey.DeletedAt != nil { + d.Set("deleted_at", resourceKey.DeletedAt.String()) + } else { + d.Set("deleted_at", "") + } + d.Set("created_by", *resourceKey.CreatedBy) + d.Set("updated_by", *resourceKey.UpdatedBy) + d.Set("deleted_by", *resourceKey.DeletedBy) + + return nil +} + +func resourceIBMResourceKeyDelete(d *schema.ResourceData, meta interface{}) error { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + resourceKeyID := d.Id() + resourceKeyDelete := rc.DeleteResourceKeyOptions{ + ID: &resourceKeyID, + } + + resp, err := rsContClient.DeleteResourceKey(&resourceKeyDelete) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting resource key: %s with resp code: %s", err, resp) + } + + d.SetId("") + + return nil +} + +func resourceIBMResourceKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + resourceKeyID := d.Id() + resourceKeyGet := rc.GetResourceKeyOptions{ + ID: &resourceKeyID, + } + + resourceKey, resp, err := rsContClient.GetResourceKey(&resourceKeyGet) + if err != nil { + if resp != nil && (resp.StatusCode == 404 || resp.StatusCode == 410) { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting resource key: %s with resp code: %s", err, resp) + } + if err == nil && *resourceKey.State == "removed" { + return false, nil + } + + return *resourceKey.ID == resourceKeyID, nil +} + +func getResourceInstanceAndCRN(d *schema.ResourceData, meta interface{}) (*rc.ResourceInstance, *string, error) { + rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return nil, nil, err + } + if insID, ok := d.GetOk("resource_instance_id"); ok { + insIdString := insID.(string) + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &insIdString, + } + instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + log.Printf("Error when get resource instance in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) + return nil, nil, err + } + return instance, instance.CRN, nil + } + + aliasID := d.Get("resource_alias_id").(string) + resourceAliasGet := rc.GetResourceAliasOptions{ + ID: &aliasID, + } + alias, resp, err := rsContClient.GetResourceAlias(&resourceAliasGet) + if err != nil { + log.Printf("Error when get resource alias in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) + return nil, nil, err + } + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: alias.ResourceInstanceID, + } + instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + log.Printf("Error when get resource instance in getResourceInstanceAndCRN: %s with resp code: %s", err, resp) + return nil, nil, err + } + return instance, instance.CRN, nil + +} + +func getRoleFromName(roleName, serviceName string, meta interface{}) (iampolicymanagementv1.PolicyRole, error) { + + role := iampolicymanagementv1.PolicyRole{} + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return role, err + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return role, err + } + + listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ + AccountID: &userDetails.UserAccount, + ServiceName: &serviceName, + } + + roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) + if err != nil { + return role, err + } + + roles := flex.MapRoleListToPolicyRoles(*roleList) + + role, err = flex.FindRoleByName(roles, roleName) + if err != nil { + return iampolicymanagementv1.PolicyRole{}, err + } + return role, nil + +} diff --git a/ibm/resource_ibm_resource_key_test.go b/ibm/service/resourcecontroller/resource_ibm_resource_key_test.go similarity index 89% rename from ibm/resource_ibm_resource_key_test.go rename to ibm/service/resourcecontroller/resource_ibm_resource_key_test.go index 2a6a51791..99aebcd52 100644 --- a/ibm/resource_ibm_resource_key_test.go +++ b/ibm/service/resourcecontroller/resource_ibm_resource_key_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcecontroller_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,8 +22,8 @@ func TestAccIBMResourceKey_Basic(t *testing.T) { resourceKey := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMResourceKeyDestroy, Steps: []resource.TestStep{ { @@ -29,6 +32,7 @@ func TestAccIBMResourceKey_Basic(t *testing.T) { testAccCheckIBMResourceKeyExists("ibm_resource_key.resourceKey"), resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "name", resourceKey), resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "credentials.%", "7"), + resource.TestCheckResourceAttrSet("ibm_resource_key.resourceKey", "credentials_json"), resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "role", "Reader"), ), }, @@ -48,8 +52,8 @@ func TestAccIBMResourceKey_With_Tags(t *testing.T) { resourceKey := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMResourceKeyDestroy, Steps: []resource.TestStep{ { @@ -77,8 +81,8 @@ func TestAccIBMResourceKey_Parameters(t *testing.T) { resourceKey := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMResourceKeyDestroy, Steps: []resource.TestStep{ { @@ -94,15 +98,15 @@ func TestAccIBMResourceKey_Parameters(t *testing.T) { }) } -func TestAccIBMResourceKeyWithCustomRole(t *testing.T) { +func TestAccIBMResourceKey_WithCustomRole(t *testing.T) { resourceName := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) resourceKey := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) crName := fmt.Sprintf("Name%d", acctest.RandIntRange(10, 100)) displayName := fmt.Sprintf("Disp%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMResourceKeyDestroy, Steps: []resource.TestStep{ { @@ -111,7 +115,7 @@ func TestAccIBMResourceKeyWithCustomRole(t *testing.T) { testAccCheckIBMResourceKeyExists("ibm_resource_key.resourceKey"), resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "name", resourceKey), resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "credentials.%", "7"), - resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "role", crName), + resource.TestCheckResourceAttr("ibm_resource_key.resourceKey", "role", displayName), ), }, }, @@ -126,7 +130,7 @@ func testAccCheckIBMResourceKeyExists(n string) resource.TestCheckFunc { return fmt.Errorf("Not found: %s", n) } - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() if err != nil { return err } @@ -145,7 +149,7 @@ func testAccCheckIBMResourceKeyExists(n string) resource.TestCheckFunc { } func testAccCheckIBMResourceKeyDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceControllerV2API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() if err != nil { return err } @@ -169,7 +173,7 @@ func testAccCheckIBMResourceKeyDestroy(s *terraform.State) error { } return fmt.Errorf("Resource key still exists: %s with resp code: %s", rs.Primary.ID, resp) } else if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("Error waiting for resource key (%s) to be destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) + return fmt.Errorf("[ERROR] Error waiting for resource key (%s) to be destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) } } diff --git a/ibm/service/resourcemanager/README.md b/ibm/service/resourcemanager/README.md new file mode 100644 index 000000000..46f3c0bb7 --- /dev/null +++ b/ibm/service/resourcemanager/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Resource Manager + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Resource Manager resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_group) +* IBM API Docs: [IBM API Docs for Resource Manager](https://cloud.ibm.com/apidocs/resource-controller/resource-manager) +* IBM Resource Manager SDK: [IBM SDK for Resource Manager](https://github.com/IBM/platform-services-go-sdk/tree/main/resourcemanagerv2) diff --git a/ibm/data_source_ibm_resource_group.go b/ibm/service/resourcemanager/data_source_ibm_resource_group.go similarity index 80% rename from ibm/data_source_ibm_resource_group.go rename to ibm/service/resourcemanager/data_source_ibm_resource_group.go index 31b0a10eb..43b9a8af4 100644 --- a/ibm/data_source_ibm_resource_group.go +++ b/ibm/service/resourcemanager/data_source_ibm_resource_group.go @@ -1,16 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcemanager import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMResourceGroup() *schema.Resource { +func DataSourceIBMResourceGroup() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMResourceGroupRead, @@ -21,6 +23,8 @@ func dataSourceIBMResourceGroup() *schema.Resource { Optional: true, Computed: true, ExactlyOneOf: []string{"is_default", "name"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_resource_group", + "name"), }, "is_default": { Description: "Default Resource group", @@ -83,9 +87,23 @@ func dataSourceIBMResourceGroup() *schema.Resource { }, } } +func DataSourceIBMResourceGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateCloudData, + Type: validate.TypeString, + CloudDataType: "resource_group", + CloudDataRange: []string{"resolved_to:name"}, + Optional: true}) + + ibmIBMResourceGroupValidator := validate.ResourceValidator{ResourceName: "ibm_resource_group", Schema: validateSchema} + return &ibmIBMResourceGroupValidator +} func dataSourceIBMResourceGroupRead(d *schema.ResourceData, meta interface{}) error { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } @@ -102,11 +120,11 @@ func dataSourceIBMResourceGroupRead(d *schema.ResourceData, meta interface{}) er if !defaultGrp && name == "" { return fmt.Errorf("[ERROR] Missing required properties. Need a resource group name, or the is_default true") } - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount resourceGroupList := rg.ListResourceGroupsOptions{ AccountID: &accountID, diff --git a/ibm/data_source_ibm_resource_group_test.go b/ibm/service/resourcemanager/data_source_ibm_resource_group_test.go similarity index 83% rename from ibm/data_source_ibm_resource_group_test.go rename to ibm/service/resourcemanager/data_source_ibm_resource_group_test.go index 22d88b48c..dbc137e6c 100644 --- a/ibm/data_source_ibm_resource_group_test.go +++ b/ibm/service/resourcemanager/data_source_ibm_resource_group_test.go @@ -1,21 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcemanager_test import ( - "fmt" "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMResourceGroupDataSource_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMResourceGroupDataSourceConfigDefault(), @@ -33,8 +34,8 @@ func TestAccIBMResourceGroupDataSource_Basic(t *testing.T) { func TestAccIBMResourceGroupDataSource_Default_false(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMResourceGroupDataSourceDefaultFalse(), @@ -45,28 +46,28 @@ func TestAccIBMResourceGroupDataSource_Default_false(t *testing.T) { } func testAccCheckIBMResourceGroupDataSourceConfigDefault() string { - return fmt.Sprintf(` + return ` data "ibm_resource_group" "testacc_ds_resource_group" { is_default = "true" -}`) +}` } func testAccCheckIBMResourceGroupDataSourceConfigWithName() string { - return fmt.Sprintf(` + return ` data "ibm_resource_group" "testacc_ds_resource_group_name" { name = "default" -}`) +}` } func testAccCheckIBMResourceGroupDataSourceDefaultFalse() string { - return fmt.Sprintf(` + return ` data "ibm_resource_group" "testacc_ds_resource_group" { is_default = "false" -}`) +}` } diff --git a/ibm/resource_ibm_resource_group.go b/ibm/service/resourcemanager/resource_ibm_resource_group.go similarity index 85% rename from ibm/resource_ibm_resource_group.go rename to ibm/service/resourcemanager/resource_ibm_resource_group.go index 78646baec..13dac090e 100644 --- a/ibm/resource_ibm_resource_group.go +++ b/ibm/service/resourcemanager/resource_ibm_resource_group.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcemanager import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMResourceGroup() *schema.Resource { +func ResourceIBMResourceGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMResourceGroupCreate, Read: resourceIBMResourceGroupRead, @@ -90,17 +91,17 @@ func resourceIBMResourceGroup() *schema.Resource { } func resourceIBMResourceGroupCreate(d *schema.ResourceData, meta interface{}) error { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } name := d.Get("name").(string) - userDetails, err := meta.(ClientSession).BluemixUserDetails() + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return err } - accountID := userDetails.userAccount + accountID := userDetails.UserAccount resourceGroupCreate := rg.CreateResourceGroupOptions{ Name: &name, @@ -109,7 +110,7 @@ func resourceIBMResourceGroupCreate(d *schema.ResourceData, meta interface{}) er resourceGroup, resp, err := rMgtClient.CreateResourceGroup(&resourceGroupCreate) if err != nil { - return fmt.Errorf("Error creating resource group: %s with response code %s", err, resp) + return fmt.Errorf("[ERROR] Error creating resource group: %s with response code %s", err, resp) } d.SetId(*resourceGroup.ID) @@ -118,7 +119,7 @@ func resourceIBMResourceGroupCreate(d *schema.ResourceData, meta interface{}) er } func resourceIBMResourceGroupRead(d *schema.ResourceData, meta interface{}) error { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } @@ -134,7 +135,7 @@ func resourceIBMResourceGroupRead(d *schema.ResourceData, meta interface{}) erro d.SetId("") return nil } - return fmt.Errorf("Error retrieving resource group: %s with response code %s", err, resp) + return fmt.Errorf("[ERROR] Error retrieving resource group: %s with response code %s", err, resp) } d.Set("name", *resourceGroup.Name) @@ -178,7 +179,7 @@ func resourceIBMResourceGroupRead(d *schema.ResourceData, meta interface{}) erro } func resourceIBMResourceGroupUpdate(d *schema.ResourceData, meta interface{}) error { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } @@ -197,7 +198,7 @@ func resourceIBMResourceGroupUpdate(d *schema.ResourceData, meta interface{}) er if hasChange { _, resp, err := rMgtClient.UpdateResourceGroup(&resourceGroupUpdate) if err != nil { - return fmt.Errorf("Error updating resource group: %s with response code %s", err, resp) + return fmt.Errorf("[ERROR] Error updating resource group: %s with response code %s", err, resp) } } @@ -205,7 +206,7 @@ func resourceIBMResourceGroupUpdate(d *schema.ResourceData, meta interface{}) er } func resourceIBMResourceGroupDelete(d *schema.ResourceData, meta interface{}) error { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } @@ -221,7 +222,7 @@ func resourceIBMResourceGroupDelete(d *schema.ResourceData, meta interface{}) er log.Printf("[WARN] Resource Group is not found") return nil } - return fmt.Errorf("Error Deleting resource group: %s with response code %s", err, resp) + return fmt.Errorf("[ERROR] Error Deleting resource group: %s with response code %s", err, resp) } d.SetId("") @@ -230,7 +231,7 @@ func resourceIBMResourceGroupDelete(d *schema.ResourceData, meta interface{}) er } func resourceIBMResourceGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() if err != nil { return false, err } @@ -244,7 +245,7 @@ func resourceIBMResourceGroupExists(d *schema.ResourceData, meta interface{}) (b if resp != nil && resp.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error communicating with the API: %s with response code %s", err, resp) + return false, fmt.Errorf("[ERROR] Error getting resource group: %s with response code %s", err, resp) } return *resourceGroup.ID == resourceGroupID, nil diff --git a/ibm/resource_ibm_resource_group_test.go b/ibm/service/resourcemanager/resource_ibm_resource_group_test.go similarity index 88% rename from ibm/resource_ibm_resource_group_test.go rename to ibm/service/resourcemanager/resource_ibm_resource_group_test.go index 5c88f7363..b0826f078 100644 --- a/ibm/resource_ibm_resource_group_test.go +++ b/ibm/service/resourcemanager/resource_ibm_resource_group_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package resourcemanager_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,8 +22,8 @@ func TestAccIBMResourceGroupBasic(t *testing.T) { resourceGroupUpdateName := fmt.Sprintf("tf-rg-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMResourceGroupBasic(resourceGroupName), @@ -53,8 +56,8 @@ func TestAccIBMResourceGroupWithTags(t *testing.T) { var conf string resourceGroupName := fmt.Sprintf("tf-rg-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMResourceGroupWithtags(resourceGroupName), @@ -84,7 +87,7 @@ func testAccCheckIBMResourceGroupExists(n string, obj *string) resource.TestChec return fmt.Errorf("Not found: %s", n) } - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceManagerV2API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } @@ -99,7 +102,7 @@ func testAccCheckIBMResourceGroupExists(n string, obj *string) resource.TestChec if resp != nil && resp.StatusCode == 404 { return nil } - return fmt.Errorf("Error retrieving resource group: %s\n Response code is: %+v", err, resp) + return fmt.Errorf("[ERROR] Error retrieving resource group: %s\n Response code is: %+v", err, resp) } obj = resourceGroup.ID @@ -108,7 +111,7 @@ func testAccCheckIBMResourceGroupExists(n string, obj *string) resource.TestChec } func testAccCheckIBMResourceGroupDestroy(s *terraform.State) error { - rsContClient, err := testAccProvider.Meta().(ClientSession).ResourceManagerV2API() + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceManagerV2API() if err != nil { return err } diff --git a/ibm/service/satellite/README.md b/ibm/service/satellite/README.md new file mode 100644 index 000000000..2dc6c8d1b --- /dev/null +++ b/ibm/service/satellite/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Satellite + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Satellite resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/satellite_location) +* IBM API Docs: [IBM API Docs for Satellite](https://containers.cloud.ibm.com/global/swagger-global-api/) +* IBM Satellite SDK: [IBM SDK for Satellite](https://github.com/IBM-Cloud/container-services-go-sdk) diff --git a/ibm/data_source_ibm_satellite_cluster.go b/ibm/service/satellite/data_source_ibm_satellite_cluster.go similarity index 89% rename from ibm/data_source_ibm_satellite_cluster.go rename to ibm/service/satellite/data_source_ibm_satellite_cluster.go index 098b5e220..ba4ed7547 100644 --- a/ibm/data_source_ibm_satellite_cluster.go +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "fmt" @@ -9,10 +9,16 @@ import ( "strings" "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSatelliteCluster() *schema.Resource { +const ( + _OPENSHIFT = "_openshift" +) + +func DataSourceIBMSatelliteCluster() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMSatelliteClusterRead, @@ -157,7 +163,7 @@ func dataSourceIBMSatelliteCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -182,7 +188,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) resourceGrp = v.(string) } - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -195,7 +201,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) clusterFields, response, err := satClient.GetCluster(getSatClusterOptions) if err != nil { - return fmt.Errorf("Error retrieving cluster: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error retrieving cluster: %s\n%s", err, response) } getWorkersOptions := &kubernetesserviceapiv1.GetWorkers1Options{} @@ -205,7 +211,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) } workerFields, response, err := satClient.GetWorkers1(getWorkersOptions) if err != nil { - return fmt.Errorf("Error retrieving workers for satellite cluster: %s", err) + return fmt.Errorf("[ERROR] Error retrieving workers for satellite cluster: %s, %s", err, response) } workers := make([]string, len(workerFields)) for i, worker := range workerFields { @@ -224,7 +230,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) workerPools, response, err := satClient.GetWorkerPools1(getSatWorkerPoolOptions) if err != nil { - return fmt.Errorf("Error retrieving worker pools of the cluster %s: %s\n%s", name, err, response) + return fmt.Errorf("[ERROR] Error retrieving worker pools of the cluster %s: %s\n%s", name, err, response) } d.SetId(*clusterFields.ID) @@ -236,7 +242,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) d.Set("status", *clusterFields.Status) d.Set("workers", workers) - d.Set("worker_pools", flattenSatelliteWorkerPools(workerPools)) + d.Set("worker_pools", flex.FlattenSatelliteWorkerPools(workerPools)) if clusterFields.ServiceEndpoints != nil { d.Set("public_service_endpoint", *clusterFields.ServiceEndpoints.PublicServiceEndpointEnabled) @@ -251,7 +257,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) d.Set("ingress_secret", *clusterFields.Ingress.SecretName) } d.Set("resource_group_id", *clusterFields.ResourceGroup) - d.Set(ResourceGroupName, *clusterFields.ResourceGroupName) + d.Set(flex.ResourceGroupName, *clusterFields.ResourceGroupName) if clusterFields.Lifecycle != nil { d.Set("health", *clusterFields.Lifecycle.MasterHealth) @@ -263,7 +269,7 @@ func dataSourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) d.Set("kube_version", strings.Split(*clusterFields.MasterKubeVersion, "_")[0]) } - tags, err := GetTagsUsingCRN(meta, *clusterFields.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *clusterFields.Crn) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) diff --git a/ibm/data_source_ibm_satellite_cluster_test.go b/ibm/service/satellite/data_source_ibm_satellite_cluster_test.go similarity index 96% rename from ibm/data_source_ibm_satellite_cluster_test.go rename to ibm/service/satellite/data_source_ibm_satellite_cluster_test.go index 7b25adb2d..729e3f6e3 100644 --- a/ibm/data_source_ibm_satellite_cluster_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMSatelliteClusterDataSourceBasic(t *testing.T) { resource_prefix := "tf-satellite" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMSatelliteClusterDataSourceConfig(clusterName, locationName, resource_prefix), diff --git a/ibm/data_source_ibm_satellite_cluster_worker_pool.go b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool.go similarity index 88% rename from ibm/data_source_ibm_satellite_cluster_worker_pool.go rename to ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool.go index a422b2d6a..ccffa17ce 100644 --- a/ibm/data_source_ibm_satellite_cluster_worker_pool.go +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "fmt" "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSatelliteClusterWorkerPool() *schema.Resource { +func DataSourceIBMSatelliteClusterWorkerPool() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMSatelliteClusterWorkerPoolRead, Schema: map[string]*schema.Schema{ @@ -64,6 +65,11 @@ func dataSourceIBMSatelliteClusterWorkerPool() *schema.Resource { Set: schema.HashString, Description: "Host labels on the workers", }, + "operating_system": { + Type: schema.TypeString, + Computed: true, + Description: "The operating system of the hosts in the worker pool", + }, "resource_group_id": { Type: schema.TypeString, Optional: true, @@ -104,7 +110,7 @@ func dataSourceIBMSatelliteClusterWorkerPoolRead(d *schema.ResourceData, meta in cluster = v.(string) } - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -125,7 +131,7 @@ func dataSourceIBMSatelliteClusterWorkerPoolRead(d *schema.ResourceData, meta in workerPool, response, err := satClient.GetWorkerPool(getSatWorkerPoolOptions) if err != nil { - return fmt.Errorf("Error retrieving worker pool %s: %s\n%s", name, err, response) + return fmt.Errorf("[ERROR] Error retrieving worker pool %s: %s\n%s", name, err, response) } var zones = make([]map[string]interface{}, 0) @@ -142,6 +148,7 @@ func dataSourceIBMSatelliteClusterWorkerPoolRead(d *schema.ResourceData, meta in d.Set("worker_count", *workerPool.WorkerCount) d.Set("worker_pool_labels", workerPool.Labels) d.Set("host_labels", workerPool.HostLabels) + d.Set("operating_system", *workerPool.OperatingSystem) d.Set("zones", zones) d.Set("cluster", cluster) d.Set("auto_scale_enabled", *workerPool.AutoscaleEnabled) diff --git a/ibm/data_source_ibm_satellite_cluster_worker_pool_test.go b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_test.go similarity index 86% rename from ibm/data_source_ibm_satellite_cluster_worker_pool_test.go rename to ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_test.go index 3ec664d8a..86c1a516a 100644 --- a/ibm/data_source_ibm_satellite_cluster_worker_pool_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -22,27 +24,29 @@ func TestAccIBMSatelliteClusterWorkerPoolDataSourceBasic(t *testing.T) { region := "us-east" resource_prefix := "tf-satellite" host_provider := "ibm" + operatingSystem := "REDHAT_7_64" publicKey := strings.TrimSpace(` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, clusterName, locationName, managed_from, resource_group, resource_prefix, region, publicKey, host_provider, zones), + Config: testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, clusterName, locationName, managed_from, operatingSystem, resource_group, resource_prefix, region, publicKey, host_provider, zones), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_satellite_cluster_worker_pool.read_wp", "id"), resource.TestCheckResourceAttrSet("data.ibm_satellite_cluster_worker_pool.read_wp", "name"), resource.TestCheckResourceAttrSet("data.ibm_satellite_cluster_worker_pool.read_wp", "cluster"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_cluster_worker_pool.read_wp", "operating_system"), ), }, }, }) } -func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, clusterName, locationName, managed_from, resource_group, resource_prefix, region, publicKey, host_provider string, zones []string) string { +func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, clusterName, locationName, managed_from, operatingSystem, resource_group, resource_prefix, region, publicKey, host_provider string, zones []string) string { return fmt.Sprintf(` provider "ibm" { @@ -90,7 +94,7 @@ func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, cl } data "ibm_is_image" "rhel7" { - name = "ibm-redhat-7-9-minimal-amd64-3" + name = "ibm-redhat-7-9-minimal-amd64-7" } resource "ibm_is_instance" "satellite_instance" { @@ -131,7 +135,7 @@ func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, cl name = "%s" location = ibm_satellite_host.assign_host.0.location enable_config_admin = true - kube_version = "4.6_openshift" + kube_version = "4.9_openshift" wait_for_worker_update = true dynamic "zones" { for_each = var.location_zones @@ -148,6 +152,7 @@ func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, cl resource "ibm_satellite_cluster_worker_pool" "create_wp" { name = "%s" cluster = ibm_satellite_cluster.create_cluster.id + operating_system = "%s" worker_count = 1 dynamic "zones" { for_each = var.location_zones @@ -167,5 +172,5 @@ func testAccCheckIBMSatelliteClusterorkerPoolDataSourceConfig(workerPoolName, cl cluster = ibm_satellite_cluster.create_cluster.id } -`, locationName, managed_from, resource_group, resource_prefix, resource_prefix, region, resource_prefix, publicKey, resource_prefix, region, resource_prefix, host_provider, clusterName, workerPoolName) +`, locationName, managed_from, resource_group, resource_prefix, resource_prefix, region, resource_prefix, publicKey, resource_prefix, region, resource_prefix, host_provider, clusterName, workerPoolName, operatingSystem) } diff --git a/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment.go b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment.go new file mode 100644 index 000000000..556b0a32c --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment.go @@ -0,0 +1,98 @@ +package satellite + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMSatelliteClusterWorkerPoolAttachment() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSatelliteClusterWorkerPoolAttachmentRead, + + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + Description: "Name or id of the cluster", + }, + "worker_pool": { + Type: schema.TypeString, + Required: true, + Description: "worker pool name", + }, + "zone": { + Type: schema.TypeString, + Required: true, + Description: "worker pool zone name", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the resource group that the Satellite location is in. To list the resource group ID of the location, use the `GET /v2/satellite/getController` API method.", + }, + "worker_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of workers", + }, + "autobalance_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Auto enabled status", + }, + "messages": { + Type: schema.TypeList, + Computed: true, + Description: "Filter features by a list of comma separated collections.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func dataSourceIBMSatelliteClusterWorkerPoolAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + cluster := d.Get("cluster").(string) + workerpool := d.Get("worker_pool").(string) + zone := d.Get("zone").(string) + + getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{} + getWorkerPoolOptions.SetCluster(cluster) + getWorkerPoolOptions.SetWorkerpool(workerpool) + + if v, ok := d.GetOk("resource_group_id"); ok { + getWorkerPoolOptions.SetXAuthResourceGroup(v.(string)) + } + + getWorkerPoolResponse, response, err := satClient.GetWorkerPoolWithContext(context, getWorkerPoolOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("[DEBUG] Satellite cluster workerpool zone attachment record is not found %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("Satellite cluster workerpool zone attachment record is not found %s\n%s", err, response)) + } + log.Printf("[DEBUG] GetWorkerPoolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetWorkerPoolWithContext failed %s\n%s", err, response)) + } + + if getWorkerPoolResponse != nil && getWorkerPoolResponse.Zones != nil { + for _, z := range getWorkerPoolResponse.Zones { + if zone == *z.ID { + d.Set("worker_count", *z.WorkerCount) + d.Set("autobalance_enabled", *z.AutobalanceEnabled) + d.Set("messages", *&z.Messages) + d.SetId(fmt.Sprintf("%s/%s/%s", cluster, workerpool, zone)) + } + } + } + return nil +} diff --git a/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment_test.go b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment_test.go new file mode 100644 index 000000000..e498b2c3e --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_cluster_worker_pool_zone_attachment_test.go @@ -0,0 +1,150 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSatelliteClusterWorkerPoolZoneAttachmentDataSourceBasic(t *testing.T) { + clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) + locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + zone := fmt.Sprintf("tf-zone-%d", acctest.RandIntRange(10, 100)) + resource_prefix := fmt.Sprintf("tf-satellite-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSatelliteClusterorkerPoolZoneAttachmentDataSourceConfig(clusterName, locationName, resource_prefix, zone), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_satellite_cluster_worker_pool_zone_attachment.read_worker_pool_zone_attachment", "id")), + }, + }, + }) +} + +func testAccCheckIBMSatelliteClusterorkerPoolZoneAttachmentDataSourceConfig(cluster, location, resource_prefix, zone string) string { + return fmt.Sprintf(` + + provider "ibm" { + region = "us-south" + } + + variable "location_zones" { + description = "Allocate your hosts across these three zones" + type = list(string) + default = ["us-south-1", "us-south-2", "us-south-3"] + } + + resource "ibm_satellite_location" "location" { + location = "%s" + managed_from = "wdc04" + zones = var.location_zones + } + + data "ibm_is_image" "rhel7" { + name = "ibm-redhat-7-9-minimal-amd64-4" + } + + data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.location.id + labels = ["env:prod"] + host_provider = "ibm" + } + + data "ibm_resource_group" "resource_group" { + is_default = true + } + + resource "ibm_is_vpc" "satellite_vpc" { + name = "%s-vpc-1" + } + + resource "ibm_is_subnet" "satellite_subnet" { + count = 3 + + name = "%s-subnet-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + total_ipv4_address_count = 256 + zone = "us-south-${count.index + 1}" + } + + resource "ibm_is_ssh_key" "satellite_ssh" { + name = "%s-ibm-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + + resource "ibm_is_instance" "satellite_instance" { + count = 3 + + name = "%s-instance-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + zone = "us-south-${count.index + 1}" + image = data.ibm_is_image.rhel7.id + profile = "mx2-8x64" + keys = [ibm_is_ssh_key.satellite_ssh.id] + resource_group = data.ibm_resource_group.resource_group.id + user_data = data.ibm_satellite_attach_host_script.script.host_script + + primary_network_interface { + subnet = ibm_is_subnet.satellite_subnet[count.index].id + } + } + + resource "ibm_is_floating_ip" "satellite_ip" { + count = 3 + + name = "%s-fip-${count.index}" + target = ibm_is_instance.satellite_instance[count.index].primary_network_interface[0].id + } + + resource "ibm_satellite_host" "assign_host" { + count = 3 + + location = ibm_satellite_location.location.id + host_id = element(ibm_is_instance.satellite_instance[*].name, count.index) + labels = ["env:prod"] + zone = element(var.location_zones, count.index) + host_provider = "ibm" + } + + resource "ibm_satellite_cluster" "create_cluster" { + name = "%s" + location = ibm_satellite_location.location.id + enable_config_admin = true + kube_version = "4.7_openshift" + wait_for_worker_update = true + dynamic "zones" { + for_each = var.location_zones + content { + id = zones.value + } + } + default_worker_pool_labels = { + "test" = "test-pool1" + "test1" = "test-pool2" + } + } + + resource "ibm_satellite_cluster_worker_pool_zone_attachment" "satellite_cluster_worker_pool_zone_attachment" { + cluster = ibm_satellite_cluster.create_cluster.id + worker_pool = "default" + zone = "%s" + } + + data "ibm_satellite_cluster_worker_pool_zone_attachment" "read_worker_pool_zone_attachment" { + cluster = ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment.cluster + worker_pool = "default" + zone = "%s" + } + + `, location, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix, cluster, zone, zone) +} diff --git a/ibm/data_source_ibm_satellite_endpoint.go b/ibm/service/satellite/data_source_ibm_satellite_endpoint.go similarity index 84% rename from ibm/data_source_ibm_satellite_endpoint.go rename to ibm/service/satellite/data_source_ibm_satellite_endpoint.go index 0139e1835..6a9709929 100644 --- a/ibm/data_source_ibm_satellite_endpoint.go +++ b/ibm/service/satellite/data_source_ibm_satellite_endpoint.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" @@ -9,106 +9,107 @@ import ( "log" "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIbmSatelliteEndpoint() *schema.Resource { +func DataSourceIBMSatelliteEndpoint() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmSatelliteEndpointRead, Schema: map[string]*schema.Schema{ - "location": &schema.Schema{ + "location": { Type: schema.TypeString, Required: true, Description: "The Location ID.", }, - "endpoint_id": &schema.Schema{ + "endpoint_id": { Type: schema.TypeString, Required: true, Description: "The Endpoint ID.", }, - "connection_type": &schema.Schema{ + "connection_type": { Type: schema.TypeString, Computed: true, Description: "The type of the endpoint.", }, - "display_name": &schema.Schema{ + "display_name": { Type: schema.TypeString, Computed: true, Description: "The display name of the endpoint. Endpoint names must start with a letter and end with an alphanumeric character, can contain letters, numbers, and hyphen (-), and must be 63 characters or fewer.", }, - "server_host": &schema.Schema{ + "server_host": { Type: schema.TypeString, Computed: true, Description: "The host name or IP address of the server endpoint. For 'http-tunnel' protocol, server_host can start with '*.' , which means a wildcard to it's sub domains. Such as '*.example.com' can accept request to 'api.example.com' and 'www.example.com'.", }, - "server_port": &schema.Schema{ + "server_port": { Type: schema.TypeInt, Computed: true, Description: "The port number of the server endpoint. For 'http-tunnel' protocol, server_port can be 0, which means any port. Such as 0 is good for 80 (http) and 443 (https).", }, - "sni": &schema.Schema{ + "sni": { Type: schema.TypeString, Computed: true, Description: "The server name indicator (SNI) which used to connect to the server endpoint. Only useful if server side requires SNI.", }, - "client_protocol": &schema.Schema{ + "client_protocol": { Type: schema.TypeString, Computed: true, Description: "The protocol in the client application side.", }, - "client_mutual_auth": &schema.Schema{ + "client_mutual_auth": { Type: schema.TypeBool, Computed: true, Description: "Whether enable mutual auth in the client application side, when client_protocol is 'tls' or 'https', this field is required.", }, - "server_protocol": &schema.Schema{ + "server_protocol": { Type: schema.TypeString, Computed: true, Description: "The protocol in the server application side. This parameter will change to default value if it is omitted even when using PATCH API. If client_protocol is 'udp', server_protocol must be 'udp'. If client_protocol is 'tcp'/'http', server_protocol could be 'tcp'/'tls' and default to 'tcp'. If client_protocol is 'tls'/'https', server_protocol could be 'tcp'/'tls' and default to 'tls'. If client_protocol is 'http-tunnel', server_protocol must be 'tcp'.", }, - "server_mutual_auth": &schema.Schema{ + "server_mutual_auth": { Type: schema.TypeBool, Computed: true, Description: "Whether enable mutual auth in the server application side, when client_protocol is 'tls', this field is required.", }, - "reject_unauth": &schema.Schema{ + "reject_unauth": { Type: schema.TypeBool, Computed: true, Description: "Whether reject any connection to the server application which is not authorized with the list of supplied CAs in the fields certs.server_cert.", }, - "timeout": &schema.Schema{ + "timeout": { Type: schema.TypeInt, Computed: true, Description: "The inactivity timeout in the Endpoint side.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The service or person who created the endpoint. Must be 1000 characters or fewer.", }, - "sources": &schema.Schema{ + "sources": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "source_id": &schema.Schema{ + "source_id": { Type: schema.TypeString, Computed: true, Description: "The Source ID.", }, - "enabled": &schema.Schema{ + "enabled": { Type: schema.TypeBool, Computed: true, Description: "Whether the source is enabled for the endpoint.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Computed: true, Description: "The last time modify the Endpoint configurations.", }, - "pending": &schema.Schema{ + "pending": { Type: schema.TypeBool, Computed: true, Description: "Whether the source has been enabled on this endpoint.", @@ -116,51 +117,51 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "connector_port": &schema.Schema{ + "connector_port": { Type: schema.TypeInt, Computed: true, Description: "The connector port.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "Service instance associated with this location.", }, - "service_name": &schema.Schema{ + "service_name": { Type: schema.TypeString, Computed: true, Description: "The service name of the endpoint.", }, - "client_host": &schema.Schema{ + "client_host": { Type: schema.TypeString, Computed: true, Description: "The hostname which Satellite Link server listen on for the on-location endpoint, or the hostname which the connector server listen on for the on-cloud endpoint destiantion.", }, - "client_port": &schema.Schema{ + "client_port": { Type: schema.TypeInt, Computed: true, Description: "The port which Satellite Link server listen on for the on-location, or the port which the connector server listen on for the on-cloud endpoint destiantion.", }, - "certs": &schema.Schema{ + "certs": { Type: schema.TypeList, //MaxItems: 1, Computed: true, Description: "The certs. Once it is generated, this field will always be defined even it is unused until the cert/key is deleted.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "client": &schema.Schema{ + "client": { Type: schema.TypeList, Computed: true, Description: "The CA which Satellite Link trust when receiving the connection from the client application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, Computed: true, Description: "The root cert or the self-signed cert of the client application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Computed: true, Description: "The filename of the cert.", @@ -171,19 +172,19 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "server": &schema.Schema{ + "server": { Type: schema.TypeList, Computed: true, Description: "The CA which Satellite Link trust when sending the connection to server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, Computed: true, Description: "The root cert or the self-signed cert of the server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Computed: true, Description: "The filename of the cert.", @@ -194,19 +195,19 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "connector": &schema.Schema{ + "connector": { Type: schema.TypeList, Computed: true, Description: "The cert which Satellite Link connector provide to identify itself for connecting to the client/server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, Computed: true, Description: "The end-entity cert of the connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Computed: true, Description: "The filename of the cert.", @@ -214,13 +215,13 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "key": &schema.Schema{ + "key": { Type: schema.TypeList, Computed: true, Description: "The private key of the connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Computed: true, Description: "The name of the key.", @@ -234,70 +235,70 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "status": &schema.Schema{ + "status": { Type: schema.TypeString, Computed: true, Description: "Whether the Endpoint is active or not.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time when the Endpoint is created.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Computed: true, Description: "The last time modify the Endpoint configurations.", }, - "performance": &schema.Schema{ + "performance": { Type: schema.TypeList, //MaxItems: 1, Computed: true, Description: "The last performance data of the endpoint.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connection": &schema.Schema{ + "connection": { Type: schema.TypeInt, Computed: true, Description: "Concurrent connections number of moment when probe read the data.", }, - "rx_bandwidth": &schema.Schema{ + "rx_bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", }, - "tx_bandwidth": &schema.Schema{ + "tx_bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", }, - "bandwidth": &schema.Schema{ + "bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", }, - "connectors": &schema.Schema{ + "connectors": { Type: schema.TypeList, Computed: true, Description: "The last performance data of the endpoint from each Connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connector": &schema.Schema{ + "connector": { Type: schema.TypeString, Computed: true, Description: "The name of the connector reported the performance data.", }, - "connections": &schema.Schema{ + "connections": { Type: schema.TypeInt, Computed: true, Description: "Concurrent connections number of moment when probe read the data from the Connector.", }, - "rx_bw": &schema.Schema{ + "rx_bw": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", }, - "tx_bw": &schema.Schema{ + "tx_bw": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", @@ -313,7 +314,7 @@ func dataSourceIbmSatelliteEndpoint() *schema.Resource { } func dataSourceIbmSatelliteEndpointRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } @@ -331,84 +332,84 @@ func dataSourceIbmSatelliteEndpointRead(context context.Context, d *schema.Resou d.SetId(fmt.Sprintf("%s/%s", *endpoint.LocationID, *endpoint.EndpointID)) if err = d.Set("connection_type", endpoint.ConnType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting connection_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting connection_type: %s", err)) } if err = d.Set("display_name", endpoint.DisplayName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting display_name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting display_name: %s", err)) } if err = d.Set("server_host", endpoint.ServerHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_host: %s", err)) } if err = d.Set("server_port", endpoint.ServerPort); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_port: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_port: %s", err)) } if err = d.Set("sni", endpoint.Sni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting sni: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sni: %s", err)) } if err = d.Set("client_protocol", endpoint.ClientProtocol); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_protocol: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_protocol: %s", err)) } if err = d.Set("client_mutual_auth", endpoint.ClientMutualAuth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_mutual_auth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_mutual_auth: %s", err)) } if err = d.Set("server_protocol", endpoint.ServerProtocol); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_protocol: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_protocol: %s", err)) } if err = d.Set("server_mutual_auth", endpoint.ServerMutualAuth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_mutual_auth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_mutual_auth: %s", err)) } if err = d.Set("reject_unauth", endpoint.RejectUnauth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting reject_unauth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting reject_unauth: %s", err)) } if err = d.Set("timeout", endpoint.Timeout); err != nil { - return diag.FromErr(fmt.Errorf("Error setting timeout: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting timeout: %s", err)) } if err = d.Set("created_by", endpoint.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if endpoint.Sources != nil { err = d.Set("sources", dataSourceEndpointFlattenSources(endpoint.Sources)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting sources %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sources %s", err)) } } if err = d.Set("connector_port", endpoint.ConnectorPort); err != nil { - return diag.FromErr(fmt.Errorf("Error setting connector_port: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting connector_port: %s", err)) } if err = d.Set("crn", endpoint.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("service_name", endpoint.ServiceName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting service_name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting service_name: %s", err)) } if err = d.Set("client_host", endpoint.ClientHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_host: %s", err)) } if err = d.Set("client_port", endpoint.ClientPort); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_port: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_port: %s", err)) } if endpoint.Certs != nil { err = d.Set("certs", dataSourceEndpointFlattenCerts(*endpoint.Certs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting certs %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting certs %s", err)) } } if err = d.Set("status", endpoint.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) } if err = d.Set("created_at", endpoint.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("last_change", endpoint.LastChange); err != nil { - return diag.FromErr(fmt.Errorf("Error setting last_change: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_change: %s", err)) } if endpoint.Performance != nil { err = d.Set("performance", dataSourceEndpointFlattenPerformance(*endpoint.Performance)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting performance %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting performance %s", err)) } } diff --git a/ibm/data_source_ibm_satellite_endpoint_test.go b/ibm/service/satellite/data_source_ibm_satellite_endpoint_test.go similarity index 97% rename from ibm/data_source_ibm_satellite_endpoint_test.go rename to ibm/service/satellite/data_source_ibm_satellite_endpoint_test.go index a99d8dcf0..b180d6369 100644 --- a/ibm/data_source_ibm_satellite_endpoint_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_endpoint_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -20,10 +22,10 @@ func TestAccIbmSatelliteEndpointDataSourceBasic(t *testing.T) { serverProtocol := "tls" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteEndpointDataSourceConfigBasic(endpointLocationID, connType, displayName, serverHost, serverPort, serverProtocol), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_satellite_endpoint.satellite_endpoint", "id"), @@ -72,10 +74,10 @@ func TestAccIbmSatelliteEndpointDataSourceAllArgs(t *testing.T) { endpointCreatedBy := fmt.Sprintf("tf_created_by_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteEndpointDataSourceConfig(endpointLocationID, endpointConnType, endpointDisplayName, endpointServerHost, endpointServerPort, endpointSni, endpointClientProtocol, endpointClientMutualAuth, endpointServerProtocol, endpointServerMutualAuth, endpointRejectUnauth, endpointTimeout, endpointCreatedBy), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_satellite_endpoint.satellite_endpoint", "id"), diff --git a/ibm/service/satellite/data_source_ibm_satellite_host_script.go b/ibm/service/satellite/data_source_ibm_satellite_host_script.go new file mode 100644 index 000000000..f61bfe097 --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_host_script.go @@ -0,0 +1,240 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "fmt" + "io/ioutil" + "log" + "path/filepath" + "strings" + "time" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + homedir "github.com/mitchellh/go-homedir" +) + +func DataSourceIBMSatelliteAttachHostScript() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMSatelliteAttachHostScriptRead, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + Description: "A unique name for the new Satellite location", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "A unique name for the new Satellite location", + }, + "coreos_host": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, returns a CoreOS ignition file for the host. Otherwise, returns a RHEL attach script", + }, + "labels": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of labels for the attach host", + }, + "host_provider": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"host_provider", "custom_script"}, + }, + "script_dir": { + Description: "The directory where the satellite attach host script to be downloaded. Default is home directory", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "script_path": { + Description: "The absolute path to the generated host script file", + Type: schema.TypeString, + Computed: true, + }, + "host_script": { + Type: schema.TypeString, + Computed: true, + Description: "Attach host script content", + }, + "custom_script": { + Description: "The custom script that has to be appended to generated host script file", + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"host_provider", "custom_script"}, + }, + }, + } +} + +func dataSourceIBMSatelliteAttachHostScriptRead(d *schema.ResourceData, meta interface{}) error { + var scriptDir string + location := d.Get("location").(string) + hostProvider := d.Get("host_provider").(string) + + if _, ok := d.GetOk("script_dir"); ok { + scriptDir = d.Get("script_dir").(string) + } + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + var locData *kubernetesserviceapiv1.MultishiftGetController + var response *core.DetailedResponse + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: &location, + } + + err = resource.Retry(1*time.Minute, func() *resource.RetryError { + locData, response, err = satClient.GetSatelliteLocation(getSatLocOptions) + if err != nil || locData == nil { + if response != nil && response.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + locData, response, err = satClient.GetSatelliteLocation(getSatLocOptions) + } + if err != nil || locData == nil { + return fmt.Errorf("[ERROR] Error getting Satellite location (%s): %s\n%s", location, err, response) + } + + // script labels + labels := make(map[string]string) + if v, ok := d.GetOk("labels"); ok { + l := v.(*schema.Set) + labels = flex.FlattenHostLabels(l.List()) + d.Set("labels", l) + } + + if len(scriptDir) == 0 { + scriptDir, err = homedir.Dir() + if err != nil { + return fmt.Errorf("[ERROR] Error fetching homedir: %s", err) + } + } + scriptDir, _ = filepath.Abs(scriptDir) + var scriptPath string + + //Generate script + createRegOptions := &kubernetesserviceapiv1.AttachSatelliteHostOptions{} + createRegOptions.Controller = locData.ID + createRegOptions.Labels = labels + + //check to see if host attach is CoreOS or RHEL + var host_os string + var coreos_enabled bool + if _, ok := d.GetOk("coreos_host"); ok { + coreos_enabled = d.Get("coreos_host").(bool) + if coreos_enabled { + host_os = "RHCOS" + createRegOptions.OperatingSystem = &host_os + scriptPath = filepath.Join(scriptDir, "addHost.ign") + } + } else { + coreos_enabled = false + host_os = "RHEL" + createRegOptions.OperatingSystem = &host_os + scriptPath = filepath.Join(scriptDir, "addHost.sh") + } + + resp, err := satClient.AttachSatelliteHost(createRegOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Generating Satellite Registration Script: %s\n%s", err, resp) + } + + scriptContent := string(resp) + + //if this is a RHEL host, find insert point for custom code + if !coreos_enabled { + lines := strings.Split(scriptContent, "\n") + var index int + for i, line := range lines { + if strings.Contains(line, `export OPERATING_SYSTEM`) { + index = i + break + } + } + + var insertionText string + + switch { + case strings.ToLower(hostProvider) == "aws": + insertionText = ` +yum-config-manager --enable '*' +yum install container-selinux -y +` + case strings.ToLower(hostProvider) == "ibm": + insertionText = ` +subscription-manager refresh +if [[ "${OPERATING_SYSTEM}" == "RHEL7" ]]; then + subscription-manager repos --enable rhel-server-rhscl-7-rpms + subscription-manager repos --enable rhel-7-server-optional-rpms + subscription-manager repos --enable rhel-7-server-rh-common-rpms + subscription-manager repos --enable rhel-7-server-supplementary-rpms + subscription-manager repos --enable rhel-7-server-extras-rpms +elif [[ "${OPERATING_SYSTEM}" == "RHEL8" ]]; then + subscription-manager repos --enable rhel-8-for-x86_64-baseos-rpms + subscription-manager repos --enable rhel-8-for-x86_64-appstream-rpms; +fi +yum install container-selinux -y +` + case strings.ToLower(hostProvider) == "azure": + insertionText = ` +if [[ "${OPERATING_SYSTEM}" == "RHEL8" ]]; then + update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1 + update-alternatives --set python3 /usr/bin/python3.8 +fi +yum install container-selinux -y +` + case strings.ToLower(hostProvider) == "google": + insertionText = ` +if [[ "${OPERATING_SYSTEM}" == "RHEL8" ]]; then + update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1 + update-alternatives --set python3 /usr/bin/python3.8 +fi +yum install container-selinux -y +` + default: + if script, ok := d.GetOk("custom_script"); ok { + insertionText = script.(string) + } + } + + lines[index] = lines[index] + "\n" + insertionText + scriptContent = strings.Join(lines, "\n") + } + + err = ioutil.WriteFile(scriptPath, []byte(scriptContent), 0644) + if err != nil { + return fmt.Errorf("[ERROR] Error Creating Satellite Attach Host Script: %s", err) + } + + d.Set("location", location) + d.Set("host_script", scriptContent) + d.Set("host_provider", hostProvider) + d.Set("script_dir", scriptDir) + d.Set("script_path", scriptPath) + d.SetId(*locData.ID) + + log.Printf("[INFO] Generated satellite location script : %s", *locData.Name) + + return nil +} diff --git a/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go b/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go new file mode 100644 index 000000000..6d3a98709 --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go @@ -0,0 +1,79 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSatelliteAttachHostScriptDataSourceBasic(t *testing.T) { + locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSatelliteAttachHostScriptDataSourceConfig(locationName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_satellite_attach_host_script.script", "host_provider", "ibm"), + ), + }, + }, + }) +} + +func testAccCheckIBMSatelliteAttachHostScriptDataSourceConfig(locationName string) string { + return fmt.Sprintf(` +resource "ibm_satellite_location" "testacc_satellite" { + location = "%s" + managed_from = "wdc04" + zones = ["us-east-1", "us-east-2", "us-east-3"] +} + +data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.testacc_satellite.id + labels = ["env:prod"] + host_provider = "ibm" +}`, locationName) +} + +// test coreos-enabled locations +func TestAccIBMSatelliteAttachHostScriptDataSourceBasicCoreos(t *testing.T) { + locationName := fmt.Sprintf("tf-satellitelocation-coreos-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSatelliteAttachHostScriptDataSourceConfigCoreos(locationName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_satellite_attach_host_script.script", "host_provider", "ibm"), + ), + }, + }, + }) +} + +func testAccCheckIBMSatelliteAttachHostScriptDataSourceConfigCoreos(locationName string) string { + return fmt.Sprintf(` +resource "ibm_satellite_location" "testacc_satellite" { + location = "%s" + managed_from = "wdc04" + coreos_enabled = true + zones = ["us-east-1", "us-east-2", "us-east-3"] +} + +data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.testacc_satellite.id + labels = ["env:prod"] + coreos_host = true + host_provider = "ibm" +}`, locationName) +} diff --git a/ibm/data_source_ibm_satellite_link.go b/ibm/service/satellite/data_source_ibm_satellite_link.go similarity index 83% rename from ibm/data_source_ibm_satellite_link.go rename to ibm/service/satellite/data_source_ibm_satellite_link.go index 3f255634e..e62fbe37f 100644 --- a/ibm/data_source_ibm_satellite_link.go +++ b/ibm/service/satellite/data_source_ibm_satellite_link.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" @@ -9,114 +9,115 @@ import ( "log" "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIbmSatelliteLink() *schema.Resource { +func DataSourceIBMSatelliteLink() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmSatelliteLinkRead, Schema: map[string]*schema.Schema{ - "location": &schema.Schema{ + "location": { Type: schema.TypeString, Required: true, Description: "The Location ID.", }, - "ws_endpoint": &schema.Schema{ + "ws_endpoint": { Type: schema.TypeString, Computed: true, Description: "The ws endpoint of the location.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "Service instance associated with this location.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Computed: true, Description: "Description of the location.", }, - "satellite_link_host": &schema.Schema{ + "satellite_link_host": { Type: schema.TypeString, Computed: true, Description: "Satellite Link hostname of the location.", }, - "status": &schema.Schema{ + "status": { Type: schema.TypeString, Computed: true, Description: "Enabled/Disabled.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "Timestamp of creation of location.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Computed: true, Description: "Timestamp of latest modification of location.", }, - "performance": &schema.Schema{ + "performance": { Type: schema.TypeList, //MaxItems: 1, Computed: true, Description: "The last performance data of the Location.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "tunnels": &schema.Schema{ + "tunnels": { Type: schema.TypeInt, Computed: true, Description: "Tunnels number estbalished from the Location.", }, - "health_status": &schema.Schema{ + "health_status": { Type: schema.TypeString, Computed: true, Description: "Tunnels health status based on the Tunnels number established. Down(0)/Critical(1)/Up(>=2).", }, - "avg_latency": &schema.Schema{ + "avg_latency": { Type: schema.TypeInt, Computed: true, Description: "Average latency calculated form latency of each Connector between Tunnel Server, unit is ms. -1 means no Connector established Tunnel.", }, - "rx_bandwidth": &schema.Schema{ + "rx_bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", }, - "tx_bandwidth": &schema.Schema{ + "tx_bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", }, - "bandwidth": &schema.Schema{ + "bandwidth": { Type: schema.TypeInt, Computed: true, Description: "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", }, - "connectors": &schema.Schema{ + "connectors": { Type: schema.TypeList, Computed: true, Description: "The last performance data of the Location read from each Connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connector": &schema.Schema{ + "connector": { Type: schema.TypeString, Computed: true, Description: "The name of the connector reported the performance data.", }, - "latency": &schema.Schema{ + "latency": { Type: schema.TypeInt, Computed: true, Description: "Latency between Connector and the Tunnel Server it connected.", }, - "rx_bw": &schema.Schema{ + "rx_bw": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", }, - "tx_bw": &schema.Schema{ + "tx_bw": { Type: schema.TypeInt, Computed: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", @@ -132,7 +133,7 @@ func dataSourceIbmSatelliteLink() *schema.Resource { } func dataSourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } @@ -149,31 +150,31 @@ func dataSourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceD d.SetId(*location.LocationID) if err = d.Set("ws_endpoint", location.WsEndpoint); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ws_endpoint: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ws_endpoint: %s", err)) } if err = d.Set("crn", location.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("description", location.Desc); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if err = d.Set("satellite_link_host", location.SatelliteLinkHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting satellite_link_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting satellite_link_host: %s", err)) } if err = d.Set("status", location.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) } if err = d.Set("created_at", location.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("last_change", location.LastChange); err != nil { - return diag.FromErr(fmt.Errorf("Error setting last_change: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_change: %s", err)) } if location.Performance != nil { err = d.Set("performance", dataSourceLocationFlattenPerformance(*location.Performance)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting performance %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting performance %s", err)) } } diff --git a/ibm/data_source_ibm_satellite_link_test.go b/ibm/service/satellite/data_source_ibm_satellite_link_test.go similarity index 90% rename from ibm/data_source_ibm_satellite_link_test.go rename to ibm/service/satellite/data_source_ibm_satellite_link_test.go index 9d0319fe8..ba1fc6b63 100644 --- a/ibm/data_source_ibm_satellite_link_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_link_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIbmSatelliteLinkDataSourceBasic(t *testing.T) { locationID := fmt.Sprintf("tf-satellite-loc-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteLinkDataSourceConfigBasic(locationID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_satellite_link.satellite_link", "id"), diff --git a/ibm/data_source_ibm_satellite_location.go b/ibm/service/satellite/data_source_ibm_satellite_location.go similarity index 84% rename from ibm/data_source_ibm_satellite_location.go rename to ibm/service/satellite/data_source_ibm_satellite_location.go index a0b740b95..f73f22787 100644 --- a/ibm/data_source_ibm_satellite_location.go +++ b/ibm/service/satellite/data_source_ibm_satellite_location.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "fmt" @@ -9,12 +9,14 @@ import ( "time" "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSatelliteLocation() *schema.Resource { +func DataSourceIBMSatelliteLocation() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMSatelliteLocationRead, @@ -34,6 +36,11 @@ func dataSourceIBMSatelliteLocation() *schema.Resource { Computed: true, Description: "A description of the new Satellite location", }, + "coreos_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "If Red Hat CoreOS features are enabled within the Satellite location", + }, "logging_account_id": { Type: schema.TypeString, Computed: true, @@ -56,7 +63,7 @@ func dataSourceIBMSatelliteLocation() *schema.Resource { Computed: true, Description: "ID of the resource group", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "Name of the resource group", @@ -65,7 +72,7 @@ func dataSourceIBMSatelliteLocation() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, }, "host_attached_count": { Type: schema.TypeInt, @@ -138,7 +145,7 @@ func dataSourceIBMSatelliteLocation() *schema.Resource { func dataSourceIBMSatelliteLocationRead(d *schema.ResourceData, meta interface{}) error { location := d.Get("location").(string) - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -160,21 +167,24 @@ func dataSourceIBMSatelliteLocationRead(d *schema.ResourceData, meta interface{} return nil }) - if isResourceTimeoutError(err) { + if conns.IsResourceTimeoutError(err) { instance, response, err = satClient.GetSatelliteLocation(getSatLocOptions) } if err != nil || instance == nil { - return fmt.Errorf("Error retrieving IBM cloud satellite location %s : %s\n%s", location, err, response) + return fmt.Errorf("[ERROR] Error retrieving IBM cloud satellite location %s : %s\n%s", location, err, response) } d.SetId(*instance.ID) d.Set("location", location) d.Set("description", *instance.Description) + if instance.CoreosEnabled != nil { + d.Set("coreos_enabled", *instance.CoreosEnabled) + } d.Set("zones", instance.WorkerZones) d.Set("managed_from", *instance.Datacenter) d.Set("crn", *instance.Crn) d.Set("resource_group_id", *instance.ResourceGroup) - d.Set(ResourceGroupName, *instance.ResourceGroupName) + d.Set(flex.ResourceGroupName, *instance.ResourceGroupName) d.Set("created_on", *instance.CreatedDate) if instance.Hosts != nil { d.Set("host_attached_count", *instance.Hosts.Total) @@ -192,13 +202,13 @@ func dataSourceIBMSatelliteLocationRead(d *schema.ResourceData, meta interface{} hostList, response, err := satClient.GetSatelliteHosts(getSatHostOptions) if err != nil { - return fmt.Errorf("Error retrieving location hosts %s : %s\n%s", location, err, response) + return fmt.Errorf("[ERROR] Error retrieving location hosts %s : %s\n%s", location, err, response) } if hostList != nil { - d.Set("hosts", flattenSatelliteHosts(hostList)) + d.Set("hosts", flex.FlattenSatelliteHosts(hostList)) } - tags, err := GetTagsUsingCRN(meta, *instance.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *instance.Crn) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) diff --git a/ibm/data_source_ibm_satellite_location_nlb_dns.go b/ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns.go similarity index 88% rename from ibm/data_source_ibm_satellite_location_nlb_dns.go rename to ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns.go index 2c8e2eed4..6e01b30b2 100644 --- a/ibm/data_source_ibm_satellite_location_nlb_dns.go +++ b/ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSatelliteLocationNLBDNS() *schema.Resource { +func DataSourceIBMSatelliteLocationNLBDNS() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMSatelliteLocationNLBDNSRead, @@ -84,7 +86,7 @@ func dataSourceIBMSatelliteLocationNLBDNSRead(context context.Context, d *schema location := d.Get("location").(string) - satClient, err := meta.(ClientSession).VpcContainerAPI() + satClient, err := meta.(conns.ClientSession).VpcContainerAPI() if err != nil { return diag.FromErr(err) } @@ -95,6 +97,6 @@ func dataSourceIBMSatelliteLocationNLBDNSRead(context context.Context, d *schema } d.SetId(location) d.Set("location", location) - d.Set("nlb_config", flattenNlbConfigs(nlbData)) + d.Set("nlb_config", flex.FlattenNlbConfigs(nlbData)) return nil } diff --git a/ibm/data_source_ibm_satellite_location_nlb_dns_test.go b/ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns_test.go similarity index 84% rename from ibm/data_source_ibm_satellite_location_nlb_dns_test.go rename to ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns_test.go index 5930eb5e4..0d6d09502 100644 --- a/ibm/data_source_ibm_satellite_location_nlb_dns_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_location_nlb_dns_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMSatelliteLocationNLBDNSListBasic(t *testing.T) { name := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) managed_from := "wdc04" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMSatelliteLocationNLBDNSListConfig(name, managed_from), @@ -29,9 +31,9 @@ func TestAccIBMSatelliteLocationNLBDNSListBasic(t *testing.T) { } func testAccCheckIBMSatelliteLocationNLBDNSListConfig(name, managed_from string) string { - return testAccCheckSatelliteLocationDataSource(name, managed_from) + fmt.Sprintf(` + return testAccCheckSatelliteLocationDataSource(name, managed_from) + ` data ibm_satellite_location_nlb_dns dns_list { location = ibm_satellite_location.location.id } -`) +` } diff --git a/ibm/data_source_ibm_satellite_location_test.go b/ibm/service/satellite/data_source_ibm_satellite_location_test.go similarity index 88% rename from ibm/data_source_ibm_satellite_location_test.go rename to ibm/service/satellite/data_source_ibm_satellite_location_test.go index 9ba1a6c71..5c820689b 100644 --- a/ibm/data_source_ibm_satellite_location_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_location_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,11 +18,11 @@ func TestAccSatelliteLocationDataSourceBasic(t *testing.T) { managed_from := "wdc04" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckSatelliteLocationDataSource(name, managed_from), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_satellite_location.location", "location", name), diff --git a/ibm/resource_ibm_satellite_cluster.go b/ibm/service/satellite/resource_ibm_satellite_cluster.go similarity index 80% rename from ibm/resource_ibm_satellite_cluster.go rename to ibm/service/satellite/resource_ibm_satellite_cluster.go index f5ec06356..eec0df2f2 100644 --- a/ibm/resource_ibm_satellite_cluster.go +++ b/ibm/service/satellite/resource_ibm_satellite_cluster.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" @@ -13,6 +13,9 @@ import ( v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -32,20 +35,42 @@ const ( isWorkerDeployed = "deployed" ) -func resourceIBMSatelliteCluster() *schema.Resource { +func ResourceIBMSatelliteCluster() *schema.Resource { return &schema.Resource{ - Create: resourceIBMSatelliteClusterCreate, - Read: resourceIBMSatelliteClusterRead, - Update: resourceIBMSatelliteClusterUpdate, - Delete: resourceIBMSatelliteClusterDelete, - Importer: &schema.ResourceImporter{}, + Create: resourceIBMSatelliteClusterCreate, + Read: resourceIBMSatelliteClusterRead, + Update: resourceIBMSatelliteClusterUpdate, + Delete: resourceIBMSatelliteClusterDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + ID := d.Id() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return nil, err + } + getSatClusterOptions := &kubernetesserviceapiv1.GetClusterOptions{ + Cluster: &ID, + } + + cluster, response, err := satClient.GetCluster(getSatClusterOptions) + if err != nil || cluster == nil { + if response != nil && response.StatusCode == 404 && strings.Contains(err.Error(), "The specified cluster could not be found") { + return nil, fmt.Errorf("Error reading satellite cluster: %s\n%s", err, response) + } + return nil, fmt.Errorf("Error reading satellite cluster: %s", err) + } + + d.Set("zones", flex.FlattenSatelliteClusterZones(cluster.LocationZones)) + return []*schema.ResourceData{d}, nil + }, + }, CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return immutableResourceCustomizeDiff([]string{"name", "location", "resource_group_id", "crn_token"}, diff) + return flex.ImmutableResourceCustomizeDiff([]string{"name", "location", "resource_group_id", "crn_token"}, diff) }, func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -91,6 +116,12 @@ func resourceIBMSatelliteCluster() *schema.Resource { }, Description: "The OpenShift Container Platform version", }, + "operating_system": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Operating system of the default worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS.", + }, "wait_for_worker_update": { Type: schema.TypeBool, Optional: true, @@ -172,7 +203,7 @@ func resourceIBMSatelliteCluster() *schema.Resource { Computed: true, Description: "ID of the resource group.", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -217,8 +248,8 @@ func resourceIBMSatelliteCluster() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_satellite_cluster", "tags")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_satellite_cluster", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags for the resources", }, "host_labels": { @@ -226,7 +257,7 @@ func resourceIBMSatelliteCluster() *schema.Resource { Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "Labels that describe a Satellite host for default workerpool", }, "crn_token": { @@ -239,26 +270,26 @@ func resourceIBMSatelliteCluster() *schema.Resource { } } -func resourceIBMSatelliteClusterValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMSatelliteClusterValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "tags", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmSatelliteClusteresourceValidator := ResourceValidator{ResourceName: "ibm_satellite_cluster", Schema: validateSchema} + ibmSatelliteClusteresourceValidator := validate.ResourceValidator{ResourceName: "ibm_satellite_cluster", Schema: validateSchema} return &ibmSatelliteClusteresourceValidator } func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) error { var resourceGrp, clusterId string pathParamsMap := make(map[string]string) - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -285,11 +316,10 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) //Wait for location to get normal _, ok := d.GetOk("crn_token") - if ok == false { + if !ok { _, err = waitForLocationNormal(location, d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for getting location (%s) to be normal: %s", location, err) + return fmt.Errorf("[ERROR] Error waiting for getting location (%s) to be normal: %s", location, err) } } @@ -303,6 +333,11 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) createClusterOptions.KubeVersion = &kube_version } + if v, ok := d.GetOk("operating_system"); ok { + operating_system := v.(string) + createClusterOptions.OperatingSystem = &operating_system + } + if res, ok := d.GetOk("zones"); ok { zones := res.(*schema.Set).List() for _, e := range zones { @@ -338,7 +373,7 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) if v, ok := d.GetOk("host_labels"); ok { hostLabels := make(map[string]string) hl := v.(*schema.Set) - hostLabels = flattenHostLabels(hl.List()) + hostLabels = flex.FlattenHostLabels(hl.List()) createClusterOptions.Labels = hostLabels } @@ -350,14 +385,14 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) instance, response, err := satClient.CreateSatelliteClusterRemote(createRemoteClusterOptions) if err != nil { - return fmt.Errorf("Error Creating Satellite Cluster for remote location: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating Satellite Cluster for remote location: %s\n%s", err, response) } clusterId = *instance.ID log.Printf("[INFO] Created ROKS Satellite Cluster for remote location: %s", clusterId) } else { instance, response, err := satClient.CreateSatelliteCluster(createClusterOptions) if err != nil { - return fmt.Errorf("Error Creating Satellite Cluster: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating Satellite Cluster: %s\n%s", err, response) } clusterId = *instance.ID log.Printf("[INFO] Created ROKS Satellite Cluster : %s", clusterId) @@ -385,14 +420,13 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) response, err := satClient.CreateSatelliteWorkerPoolZone(zoneOptions) if err != nil { - return fmt.Errorf("Error Adding Worker Pool Zone : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Adding Worker Pool Zone : %s\n%s", err, response) } } } _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, clusterId, workerPoolName, d.Timeout(schema.TimeoutCreate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for default workerpool (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for default workerpool (%s) to become ready: %s", d.Id(), err) } } } @@ -414,15 +448,14 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) response, err := satClient.V2SetWorkerPoolLabels(wpots) if err != nil { - return fmt.Errorf( - "Error updating the labels: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating the labels: %s\n%s", err, response) } } v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk("tags"); ok || v != "" { getSatClusterOptions := &kubernetesserviceapiv1.GetClusterOptions{ - Cluster: ptrToString(clusterId), + Cluster: flex.PtrToString(clusterId), } cluster, response, err := satClient.GetCluster(getSatClusterOptions) @@ -432,7 +465,7 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) } oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *cluster.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *cluster.Crn) if err != nil { log.Printf( "Error on create of ibm satellite location (%s) tags: %s", d.Id(), err) @@ -442,8 +475,7 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) //Wait for cluster to get warning state _, err = waitForClusterToReady(clusterId, d, meta) if err != nil { - return fmt.Errorf( - "Error waiting for getting cluster (%s) to be warning state: %s", clusterId, err) + return fmt.Errorf("[ERROR] Error waiting for getting cluster (%s) to be warning state: %s", clusterId, err) } return resourceIBMSatelliteClusterRead(d, meta) @@ -451,7 +483,7 @@ func resourceIBMSatelliteClusterCreate(d *schema.ResourceData, meta interface{}) func resourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) error { ID := d.Id() - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -486,7 +518,7 @@ func resourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) e d.Set("ingress_secret", *cluster.Ingress.SecretName) } d.Set("resource_group_id", *cluster.ResourceGroup) - d.Set(ResourceGroupName, *cluster.ResourceGroupName) + d.Set(flex.ResourceGroupName, *cluster.ResourceGroupName) if cluster.ServiceEndpoints != nil { d.Set("public_service_endpoint_url", *cluster.ServiceEndpoints.PublicServiceEndpointURL) d.Set("private_service_endpoint_url", *cluster.ServiceEndpoints.PrivateServiceEndpointURL) @@ -512,23 +544,15 @@ func resourceIBMSatelliteClusterRead(d *schema.ResourceData, meta interface{}) e "An error occured while retrieving default workerpool : %s\n%s", err, response) } - var zones = make([]map[string]interface{}, 0) - for _, zone := range workerPool.Zones { - zoneInfo := map[string]interface{}{ - "id": *zone.ID, - } - zones = append(zones, zoneInfo) - } - d.Set("zones", zones) - - tags, err := GetTagsUsingCRN(meta, *cluster.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *cluster.Crn) if err != nil { log.Printf( "An error occured during reading of instance (%s) tags : %s", d.Id(), err) } d.Set("tags", tags) - d.Set("default_worker_pool_labels", IgnoreSystemLabels(workerPool.Labels)) - d.Set("host_labels", flattenWorkerPoolHostLabels(workerPool.HostLabels)) + d.Set("default_worker_pool_labels", flex.IgnoreSystemLabels(workerPool.Labels)) + d.Set("host_labels", flex.FlattenWorkerPoolHostLabels(workerPool.HostLabels)) + d.Set("operating_system", workerPool.OperatingSystem) return nil } @@ -537,12 +561,12 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) clusterID := d.Id() workerPoolName := "default" - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return err } @@ -571,18 +595,17 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) } _, err = WaitForSatelliteClusterVersionUpdate(d, meta, targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for cluster (%s) version to be updated: %s", d.Id(), err) } } - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } workerOpts := satClient.NewGetWorkers1Options(clusterID) workerFields, response, err := satClient.GetWorkers1(workerOpts) if err != nil { - return fmt.Errorf("Error retrieving workerFields %s: %s", err, response) + return fmt.Errorf("[ERROR] Error retrieving workerFields %s: %s", err, response) } getSatClusterOptions := &kubernetesserviceapiv1.GetClusterOptions{ @@ -592,7 +615,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) cluster, response, err := satClient.GetCluster(getSatClusterOptions) if err != nil { - return fmt.Errorf("Error retrieving cluster %s: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error retrieving cluster %s: %s, %s", clusterID, err, response) } waitForWorkerUpdate := d.Get("wait_for_worker_update").(bool) if workerFields != nil { @@ -605,7 +628,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) err = wrkAPI.Update(clusterID, *w.ID, params, targetEnv) if err != nil { d.Set("patch_version", nil) - return fmt.Errorf("Error updating worker %s: %s", *w.ID, err) + return fmt.Errorf("[ERROR] Error updating worker %s: %s", *w.ID, err) } } } @@ -614,8 +637,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) _, err = WaitForSatelliteWorkerVersionUpdate(d, meta, *cluster.MasterKubeVersion, targetEnv) if err != nil { d.Set("patch_version", nil) - return fmt.Errorf( - "Error waiting for workers of cluster (%s) to update kube version: %s", clusterID, err) + return fmt.Errorf("[ERROR] Error waiting for workers of cluster (%s) to update kube version: %s", clusterID, err) } } } @@ -632,8 +654,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) response, err := satClient.V2ResizeWorkerPool(resizeOpts) if err != nil { - return fmt.Errorf( - "Error updating the worker pool size %d: %s\n%s", workerCount, err, response) + return fmt.Errorf("[ERROR] Error updating the worker pool size %d: %s\n%s", workerCount, err, response) } } @@ -653,8 +674,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) } response, err := satClient.V2SetWorkerPoolLabels(wpots) if err != nil { - return fmt.Errorf( - "Error updating the labels: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating the labels: %s\n%s", err, response) } } @@ -668,9 +688,9 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) cluster, response, err := satClient.GetCluster(getSatClusterOptions) if err != nil { - return fmt.Errorf("Error retrieving cluster %s: %s\n%s", clusterID, err, response) + return fmt.Errorf("[ERROR] Error retrieving cluster %s: %s\n%s", clusterID, err, response) } - err = UpdateTagsUsingCRN(oldList, newList, meta, *cluster.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *cluster.Crn) if err != nil { log.Printf( "An error occured during update of instance (%s) tags: %s", clusterID, err) @@ -700,13 +720,12 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) } response, err := satClient.CreateSatelliteWorkerPoolZone(zoneOptions) if err != nil { - return fmt.Errorf("Error Adding Worker Pool Zone : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Adding Worker Pool Zone : %s\n%s", err, response) } } _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, clusterID, workerPoolName, d.Timeout(schema.TimeoutUpdate), targetEnv) if err != nil { - return fmt.Errorf( - "Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) } } if len(remove) > 0 { @@ -720,7 +739,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) } response, err := satClient.RemoveWorkerPoolZone(zoneOptions) if err != nil { - return fmt.Errorf("Error deleting Worker Pool Zone : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting Worker Pool Zone : %s\n%s", err, response) } } } @@ -730,7 +749,7 @@ func resourceIBMSatelliteClusterUpdate(d *schema.ResourceData, meta interface{}) } func resourceIBMSatelliteClusterDelete(d *schema.ResourceData, meta interface{}) error { - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -741,14 +760,13 @@ func resourceIBMSatelliteClusterDelete(d *schema.ResourceData, meta interface{}) response, err := satClient.RemoveCluster(removeClusterOptions) if err != nil { - return fmt.Errorf("Error Creating Satellite Location: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating Satellite Location: %s\n%s", err, response) } //Wait for cluster to get delete _, err = waitForClusterToDelete(name, d, meta) if err != nil { - return fmt.Errorf( - "Error waiting while deleteing cluster (%s) : %s", name, err) + return fmt.Errorf("[ERROR] Error waiting while deleteing cluster (%s) : %s", name, err) } log.Printf("[INFO] Deleted satellite cluster : %s", name) @@ -758,7 +776,7 @@ func resourceIBMSatelliteClusterDelete(d *schema.ResourceData, meta interface{}) } func waitForLocationNormal(location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return false, err } @@ -785,7 +803,7 @@ func waitForLocationNormal(location string, d *schema.ResourceData, meta interfa return nil }) - if isResourceTimeoutError(err) { + if conns.IsResourceTimeoutError(err) { instance, response, err = satClient.GetSatelliteLocation(getSatLocOptions) } @@ -806,7 +824,7 @@ func waitForLocationNormal(location string, d *schema.ResourceData, meta interfa } func waitForClusterToReady(cluster string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return false, err } @@ -820,10 +838,10 @@ func waitForClusterToReady(cluster string, d *schema.ResourceData, meta interfac } instance, response, err := satClient.GetCluster(getClusterOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting cluster : %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting cluster : %s\n%s", err, response) } if instance != nil && *instance.State == isCluterDeployFailed { - return instance, isCluterDeployFailed, fmt.Errorf("The cluster failed to deploy : %s", cluster) + return instance, isCluterDeployFailed, fmt.Errorf("[ERROR] The cluster failed to deploy : %s", cluster) } if instance != nil && (*instance.State == isClusterNormal || *instance.State == isClusterWarning) { @@ -840,7 +858,7 @@ func waitForClusterToReady(cluster string, d *schema.ResourceData, meta interfac } func waitForClusterToDelete(cluster string, d *schema.ResourceData, meta interface{}) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return false, err } @@ -869,9 +887,9 @@ func waitForClusterToDelete(cluster string, d *schema.ResourceData, meta interfa return stateConf.WaitForState() } -// WaitForSatelliteWorkerVersionUpdate Waits for worker creation +// WaitForSatelliteWorkerVersionUpdate Waits for worker creation func WaitForSatelliteWorkerVersionUpdate(d *schema.ResourceData, meta interface{}, masterVersion string, target v1.ClusterTargetHeader) (interface{}, error) { - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return nil, err } @@ -910,7 +928,7 @@ func WaitForSatelliteWorkerVersionUpdate(d *schema.ResourceData, meta interface{ // WaitForSatelliteClusterVersionUpdate Waits for cluster creation func WaitForSatelliteClusterVersionUpdate(d *schema.ResourceData, meta interface{}, target v1.ClusterTargetHeader) (interface{}, error) { - csClient, err := meta.(ClientSession).ContainerAPI() + csClient, err := meta.(conns.ClientSession).ContainerAPI() if err != nil { return nil, err } @@ -934,7 +952,7 @@ func satelliteClusterVersionRefreshFunc(client v1.Clusters, instanceID string, d return func() (interface{}, string, error) { clusterFields, err := client.FindWithOutShowResourcesCompatible(instanceID, target) if err != nil { - return nil, "", fmt.Errorf("Error retrieving satellite cluster: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error retrieving satellite cluster: %s", err) } // Check active transactions diff --git a/ibm/resource_ibm_satellite_cluster_test.go b/ibm/service/satellite/resource_ibm_satellite_cluster_test.go similarity index 85% rename from ibm/resource_ibm_satellite_cluster_test.go rename to ibm/service/satellite/resource_ibm_satellite_cluster_test.go index 85b1bab57..4e52633bf 100644 --- a/ibm/resource_ibm_satellite_cluster_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_cluster_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,6 +22,7 @@ func TestAccSatelliteCluster_Basic(t *testing.T) { clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) managed_from := "wdc04" + operatingSystem := "REDHAT_7_64" zones := []string{"us-east-1", "us-east-2", "us-east-3"} resource_group := "default" region := "us-east" @@ -29,13 +33,13 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteClusterDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, resource_group, resource_prefix, region, publicKey, host_provider, zones), + { + Config: testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, operatingSystem, resource_group, resource_prefix, region, publicKey, host_provider, zones), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteClusterExists("ibm_satellite_cluster.create_cluster", instance), resource.TestCheckResourceAttr("ibm_satellite_cluster.create_cluster", "name", clusterName), @@ -50,6 +54,7 @@ func TestAccSatelliteCluster_Import(t *testing.T) { clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) managed_from := "wdc04" + operatingSystem := "REDHAT_7_64" zones := []string{"us-east-1", "us-east-2", "us-east-3"} resource_group := "default" region := "us-east" @@ -60,19 +65,19 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteClusterDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, resource_group, resource_prefix, region, publicKey, host_provider, zones), + { + Config: testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, operatingSystem, resource_group, resource_prefix, region, publicKey, host_provider, zones), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteClusterExists("ibm_satellite_cluster.create_cluster", instance), resource.TestCheckResourceAttr("ibm_satellite_cluster.create_cluster", "name", clusterName), ), }, - resource.TestStep{ + { ResourceName: "ibm_satellite_cluster.create_cluster", ImportState: true, ImportStateVerify: true, @@ -92,7 +97,7 @@ func testAccCheckSatelliteClusterExists(n string, instance string) resource.Test } ID := rs.Primary.ID - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -106,7 +111,7 @@ func testAccCheckSatelliteClusterExists(n string, instance string) resource.Test if resp != nil && resp.StatusCode == 404 { return nil } - return fmt.Errorf("Error retrieving satellite cluster: %s\n Response code is: %+v", err, resp) + return fmt.Errorf("[ERROR] Error retrieving satellite cluster: %s\n Response code is: %+v", err, resp) } instance = *cluster.ID @@ -116,7 +121,7 @@ func testAccCheckSatelliteClusterExists(n string, instance string) resource.Test } func testAccCheckSatelliteClusterDestroy(s *terraform.State) error { - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -139,7 +144,7 @@ func testAccCheckSatelliteClusterDestroy(s *terraform.State) error { return nil } -func testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, resource_group, resource_prefix, region, publicKey, host_provider string, zones []string) string { +func testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, operatingSystem, resource_group, resource_prefix, region, publicKey, host_provider string, zones []string) string { return fmt.Sprintf(` provider "ibm" { @@ -153,7 +158,7 @@ func testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, } data "ibm_is_image" "rhel7" { - name = "ibm-redhat-7-9-minimal-amd64-3" + name = "ibm-redhat-7-9-minimal-amd64-7" } resource "ibm_satellite_location" "location" { @@ -228,7 +233,8 @@ func testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, name = "%s" location = ibm_satellite_host.assign_host.0.location enable_config_admin = true - kube_version = "4.6_openshift" + kube_version = "4.9_openshift" + operating_system = "%s" wait_for_worker_update = true dynamic "zones" { for_each = var.location_zones @@ -242,5 +248,5 @@ func testAccCheckSatelliteClusterCreate(clusterName, locationName, managed_from, } } -`, locationName, managed_from, resource_group, resource_prefix, resource_prefix, region, resource_prefix, publicKey, resource_prefix, region, resource_prefix, host_provider, clusterName) +`, locationName, managed_from, resource_group, resource_prefix, resource_prefix, region, resource_prefix, publicKey, resource_prefix, region, resource_prefix, host_provider, clusterName, operatingSystem) } diff --git a/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool.go b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool.go new file mode 100644 index 000000000..e61b53c68 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool.go @@ -0,0 +1,564 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "fmt" + "log" + "strings" + "time" + + v1 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + v2 "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + workerPoolDesired = "deployed" + clusterNormal = "normal" + clusterDeletePending = "deleting" + clusterDeleted = "deleted" + workerNormal = "normal" + subnetNormal = "normal" + workerReadyState = "Ready" + workerDeleteState = "deleted" + workerDeletePending = "deleting" + + versionUpdating = "updating" + clusterProvisioning = "provisioning" + workerProvisioning = "provisioning" + subnetProvisioning = "provisioning" +) + +func ResourceIBMSatelliteClusterWorkerPool() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMSatelliteClusterWorkerPoolCreate, + Read: resourceIBMSatelliteClusterWorkerPoolRead, + Update: resourceIBMSatelliteClusterWorkerPoolUpdate, + Delete: resourceIBMSatelliteClusterWorkerPoolDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return nil, err + } + clusterID := parts[0] + workerPoolID := parts[1] + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return nil, err + } + getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{ + Cluster: &clusterID, + Workerpool: &workerPoolID, + } + workerPool, response, err := satClient.GetWorkerPool(getWorkerPoolOptions) + if err != nil { + return nil, fmt.Errorf("Error reading satellite worker pool: %s\n%s", response, err) + } + + var zones = make([]map[string]interface{}, 0) + for _, zone := range workerPool.Zones { + zoneInfo := map[string]interface{}{ + "id": *zone.ID, + } + zones = append(zones, zoneInfo) + } + + d.Set("zones", zones) + return []*schema.ResourceData{d}, nil + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(120 * time.Minute), + Delete: schema.DefaultTimeout(90 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name for the worker pool", + }, + "cluster": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique name for the new IBM Cloud Satellite cluster", + }, + "flavor": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The flavor defines the amount of virtual CPU, memory, and disk space that is set up in each worker node", + }, + "disk_encryption": { + Type: schema.TypeBool, + Optional: true, + Description: "Disk encryption for worker node", + }, + "isolation": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "entitlement": { + Type: schema.TypeString, + Optional: true, + }, + "operating_system": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Operating system of the worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS.", + }, + "worker_count": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Specify the desired number of workers per zone in this worker pool", + }, + "zones": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Description: "Zone info for worker pool", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "Zone for the worker pool in a multizone cluster", + }, + }, + }, + }, + "worker_pool_labels": { + Type: schema.TypeMap, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Labels on all the workers in the worker pool", + }, + "host_labels": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Labels that describe a Satellite host", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "ID of the resource group.", + }, + }, + } +} +func getClusterTargetHeader(d *schema.ResourceData, meta interface{}) (v1.ClusterTargetHeader, error) { + _, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return v1.ClusterTargetHeader{}, err + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return v1.ClusterTargetHeader{}, err + } + accountID := userDetails.UserAccount + + targetEnv := v1.ClusterTargetHeader{ + AccountID: accountID, + } + + resourceGroup := "" + if v, ok := d.GetOk("resource_group_id"); ok { + resourceGroup = v.(string) + targetEnv.ResourceGroup = resourceGroup + } + return targetEnv, nil +} +func resourceIBMSatelliteClusterWorkerPoolCreate(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + targetEnv, err := getClusterTargetHeader(d, meta) + if err != nil { + return err + } + + createWorkerPoolOptions := &kubernetesserviceapiv1.CreateSatelliteWorkerPoolOptions{} + name := d.Get("name").(string) + createWorkerPoolOptions.Name = &name + + cluster := d.Get("cluster").(string) + createWorkerPoolOptions.Cluster = &cluster + + if v, ok := d.GetOk("resource_group_id"); ok { + pathParamsMap := map[string]string{ + "X-Auth-Resource-Group": v.(string), + } + createWorkerPoolOptions.Headers = pathParamsMap + } + + if v, ok := d.GetOk("operating_system"); ok { + operating_system := v.(string) + createWorkerPoolOptions.OperatingSystem = &operating_system + } + + if v, ok := d.GetOk("worker_count"); ok { + workerCount := int64(v.(int)) + createWorkerPoolOptions.WorkerCount = &workerCount + } + + if v, ok := d.GetOk("zones"); ok { + z := v.(*schema.Set) + createWorkerPoolOptions.Zones = flex.FlattenSatelliteWorkerPoolZones(z) + } + + hostLabels := make(map[string]string) + if v, ok := d.GetOk("host_labels"); ok { + hl := v.(*schema.Set) + hostLabels = flex.FlattenHostLabels(hl.List()) + createWorkerPoolOptions.HostLabels = hostLabels + } else { + createWorkerPoolOptions.HostLabels = hostLabels + } + + labels := make(map[string]string) + if l, ok := d.GetOk("worker_pool_labels"); ok { + for k, v := range l.(map[string]interface{}) { + labels[k] = v.(string) + } + createWorkerPoolOptions.Labels = labels + } else { + createWorkerPoolOptions.Labels = labels + } + + if v, ok := d.GetOk("flavor"); ok { + flavor := v.(string) + createWorkerPoolOptions.Flavor = &flavor + } + + if v, ok := d.GetOk("disk_encryption"); ok { + diskEncryption := v.(bool) + createWorkerPoolOptions.DiskEncryption = &diskEncryption + } + + if v, ok := d.GetOk("isolation"); ok { + isolation := v.(string) + createWorkerPoolOptions.Isolation = &isolation + } + + instance, response, err := satClient.CreateSatelliteWorkerPool(createWorkerPoolOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Creating Satellite cluster worker pool: %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s", cluster, *instance.WorkerPoolID)) + log.Printf("[INFO] Created satellite cluster worker pool: %s", *instance.WorkerPoolID) + + _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, cluster, *instance.WorkerPoolID, d.Timeout(schema.TimeoutCreate), targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) + } + + return resourceIBMSatelliteClusterWorkerPoolRead(d, meta) +} + +func resourceIBMSatelliteClusterWorkerPoolRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + clusterID := parts[0] + workerPoolID := parts[1] + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{ + Cluster: &clusterID, + Workerpool: &workerPoolID, + } + + workerPool, response, err := satClient.GetWorkerPool(getWorkerPoolOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return err + } + + d.Set("name", workerPool.PoolName) + d.Set("cluster", clusterID) + d.Set("flavor", workerPool.Flavor) + d.Set("isolation", workerPool.Isolation) + d.Set("operating_system", workerPool.OperatingSystem) + d.Set("worker_count", workerPool.WorkerCount) + d.Set("worker_pool_labels", flex.IgnoreSystemLabels(workerPool.Labels)) + d.Set("host_labels", flex.FlattenWorkerPoolHostLabels(workerPool.HostLabels)) + + return nil +} + +func resourceIBMSatelliteClusterWorkerPoolUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + clusterNameOrID := parts[0] + workerPoolName := parts[1] + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + targetEnv, err := getClusterTargetHeader(d, meta) + if err != nil { + return err + } + + if d.HasChange("worker_pool_labels") { + labels := make(map[string]string) + if l, ok := d.GetOk("worker_pool_labels"); ok { + for k, v := range l.(map[string]interface{}) { + labels[k] = v.(string) + } + } + + wpots := &kubernetesserviceapiv1.V2SetWorkerPoolLabelsOptions{ + Cluster: &clusterNameOrID, + Workerpool: &workerPoolName, + Labels: labels, + } + response, err := satClient.V2SetWorkerPoolLabels(wpots) + if err != nil { + return fmt.Errorf("[ERROR] Error updating the labels: %s\n%s", err, response) + } + } + + if d.HasChange("worker_count") { + clusterNameOrID := d.Get("cluster").(string) + workerPoolName := d.Get("name").(string) + count := d.Get("worker_count").(int) + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + ClusterClient, err := meta.(conns.ClientSession).ContainerAPI() + if err != nil { + return err + } + Env := v1.ClusterTargetHeader{ResourceGroup: targetEnv.ResourceGroup} + + err = ClusterClient.WorkerPools().ResizeWorkerPool(clusterNameOrID, workerPoolName, count, Env) + if err != nil { + return fmt.Errorf("[ERROR] Error updating the worker_count %d: %s", count, err) + } + } + + if d.HasChange("zones") { + clusterID := d.Get("cluster").(string) + workerPoolName := d.Get("name").(string) + + oldList, newList := d.GetChange("zones") + if oldList == nil { + oldList = new(schema.Set) + } + if newList == nil { + newList = new(schema.Set) + } + os := oldList.(*schema.Set) + ns := newList.(*schema.Set) + remove := os.Difference(ns).List() + add := ns.Difference(os).List() + if len(add) > 0 { + for _, zone := range add { + newZone := zone.(map[string]interface{}) + zID := newZone["id"].(string) + zoneOptions := &kubernetesserviceapiv1.CreateSatelliteWorkerPoolZoneOptions{ + Cluster: &clusterID, + Workerpool: &workerPoolName, + ID: &zID, + } + response, err := satClient.CreateSatelliteWorkerPoolZone(zoneOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Adding Worker Pool Zone : %s\n%s", err, response) + } + } + _, err = WaitForSatelliteWorkerPoolAvailable(d, meta, clusterID, workerPoolName, d.Timeout(schema.TimeoutCreate), targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for workerpool (%s) to become ready: %s", d.Id(), err) + } + } + if len(remove) > 0 { + for _, zone := range remove { + oldZone := zone.(map[string]interface{}) + zID := oldZone["id"].(string) + zoneOptions := &kubernetesserviceapiv1.RemoveWorkerPoolZoneOptions{ + IdOrName: &clusterID, + PoolidOrName: &workerPoolName, + Zoneid: &zID, + } + response, err := satClient.RemoveWorkerPoolZone(zoneOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Worker Pool Zone : %s\n%s", err, response) + } + } + } + } + return resourceIBMSatelliteClusterWorkerPoolRead(d, meta) +} + +func resourceIBMSatelliteClusterWorkerPoolDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + clusterID := parts[0] + workerPoolID := parts[1] + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + targetEnv, err := getVpcClusterTargetHeader(d, meta) + if err != nil { + return err + } + + wpOptions := &kubernetesserviceapiv1.RemoveWorkerPoolOptions{ + IdOrName: &clusterID, + PoolidOrName: &workerPoolID, + } + + response, err := satClient.RemoveWorkerPool(wpOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Deleting Satellite Cluster WorkerPool: %s\n%s", err, response) + } + + _, err = WaitForSatelliteWorkerDelete(clusterID, workerPoolID, meta, d.Timeout(schema.TimeoutDelete), targetEnv) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for removing workers of worker pool (%s) of cluster (%s): %s", workerPoolID, clusterID, err) + } + + d.SetId("") + return nil +} +func getVpcClusterTargetHeader(d *schema.ResourceData, meta interface{}) (v2.ClusterTargetHeader, error) { + targetEnv := v2.ClusterTargetHeader{} + var resourceGroup string + if rg, ok := d.GetOk("resource_group_id"); ok { + resourceGroup = rg.(string) + targetEnv.ResourceGroup = resourceGroup + } + + return targetEnv, nil +} + +// WaitForSatelliteWorkerPoolAvailable Waits for workerpool deployed +func WaitForSatelliteWorkerPoolAvailable(d *schema.ResourceData, meta interface{}, clusterNameOrID, workerPoolNameOrID string, timeout time.Duration, target v1.ClusterTargetHeader) (interface{}, error) { + clusterID := clusterNameOrID + workerPoolID := workerPoolNameOrID + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return nil, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"provision_pending"}, + Target: []string{workerPoolDesired}, + Refresh: func() (interface{}, string, error) { + getWorkersOptions := &kubernetesserviceapiv1.GetWorkers1Options{ + Cluster: &clusterID, + XAuthResourceGroup: &target.ResourceGroup, + } + + workers, response, err := satClient.GetWorkers1(getWorkersOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s\n%s", err, response) + } + + //Check active transactions + //Check for workerpool state to be deployed + //Done workerpool has two fields desiredState and actualState , so check for those 2 + for _, e := range workers { + if *e.PoolName == workerPoolID || *e.PoolID == workerPoolID { + if strings.Compare(*e.Lifecycle.ActualState, workerPoolDesired) != 0 { + log.Printf("worker: %s state: %s", *e.ID, *e.Lifecycle.ActualState) + return workers, "provision_pending", nil + } + } + } + return workers, workerPoolDesired, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func WaitForSatelliteWorkerDelete(clusterNameOrID, workerPoolNameOrID string, meta interface{}, timeout time.Duration, target v2.ClusterTargetHeader) (interface{}, error) { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return nil, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{workerDeleteState}, + Refresh: satelliteWorkerPoolDeleteStateRefreshFunc(satClient, clusterNameOrID, workerPoolNameOrID, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func satelliteWorkerPoolDeleteStateRefreshFunc(satClient *kubernetesserviceapiv1.KubernetesServiceApiV1, clusterID, workerPoolNameOrID string, target v2.ClusterTargetHeader) resource.StateRefreshFunc { + + return func() (interface{}, string, error) { + + getWorkersOptions := &kubernetesserviceapiv1.GetWorkers1Options{ + Cluster: &clusterID, + XAuthResourceGroup: &target.ResourceGroup, + } + + workerFields, response, err := satClient.GetWorkers1(getWorkersOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error retrieving workers for cluster: %s\n%s", err, response) + } + //Done worker has two fields desiredState and actualState , so check for those 2 + for _, e := range workerFields { + if *e.PoolName == workerPoolNameOrID || *e.PoolID == workerPoolNameOrID { + if strings.Compare(*e.Lifecycle.ActualState, "deleted") != 0 { + log.Printf("Deleting worker %s", *e.ID) + return workerFields, "deleting", nil + } + } + } + return workerFields, workerDeleteState, nil + } +} diff --git a/ibm/resource_ibm_satellite_cluster_worker_pool_test.go b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_test.go similarity index 84% rename from ibm/resource_ibm_satellite_cluster_worker_pool_test.go rename to ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_test.go index 730d1b9e3..82d2612ad 100644 --- a/ibm/resource_ibm_satellite_cluster_worker_pool_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,21 +21,23 @@ func TestAccSatelliteClusterWorkerPool_Basic(t *testing.T) { var instance string clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + operatingSystem := "REDHAT_7_64" workerPoolName := fmt.Sprintf("tf-wp-%d", acctest.RandIntRange(10, 100)) resource_prefix := "tf-satellite" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteClusterWorkerPoolDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, workerPoolName, resource_prefix), + { + Config: testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, operatingSystem, workerPoolName, resource_prefix), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteClusterWorkerPoolExists("ibm_satellite_cluster_worker_pool.create_wp", instance), resource.TestCheckResourceAttr("ibm_satellite_cluster.create_cluster", "name", clusterName), resource.TestCheckResourceAttr("ibm_satellite_cluster_worker_pool.create_wp", "name", workerPoolName), + resource.TestCheckResourceAttr("ibm_satellite_cluster_worker_pool.create_wp", "operating_system", operatingSystem), ), }, }, @@ -43,22 +49,23 @@ func TestAccSatelliteClusterWorkerPool_Import(t *testing.T) { clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) workerPoolName := fmt.Sprintf("tf-wp-%d", acctest.RandIntRange(10, 100)) + operatingSystem := "REDHAT_7_64" resource_prefix := "tf-satellite" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteClusterWorkerPoolDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, workerPoolName, resource_prefix), + { + Config: testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, operatingSystem, workerPoolName, resource_prefix), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteClusterWorkerPoolExists("ibm_satellite_cluster_worker_pool.create_wp", instance), resource.TestCheckResourceAttr("ibm_satellite_cluster_worker_pool.create_wp", "name", workerPoolName), ), }, - resource.TestStep{ + { ResourceName: "ibm_satellite_cluster_worker_pool.create_wp", ImportState: true, ImportStateVerify: true, @@ -75,14 +82,14 @@ func testAccCheckSatelliteClusterWorkerPoolExists(n string, instance string) res return fmt.Errorf("Not found: %s", n) } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } clusterID := parts[0] workerPoolID := parts[1] - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -97,7 +104,7 @@ func testAccCheckSatelliteClusterWorkerPoolExists(n string, instance string) res if resp != nil && resp.StatusCode == 404 { return nil } - return fmt.Errorf("Error retrieving worker pool : %s\n Response code is: %+v", err, resp) + return fmt.Errorf("[ERROR] Error retrieving worker pool : %s\n Response code is: %+v", err, resp) } instance = *wp.ID @@ -107,7 +114,7 @@ func testAccCheckSatelliteClusterWorkerPoolExists(n string, instance string) res } func testAccCheckSatelliteClusterWorkerPoolDestroy(s *terraform.State) error { - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -116,7 +123,7 @@ func testAccCheckSatelliteClusterWorkerPoolDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -136,7 +143,7 @@ func testAccCheckSatelliteClusterWorkerPoolDestroy(s *terraform.State) error { return nil } -func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, workerPoolName, resource_prefix string) string { +func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, operatingSystem, workerPoolName, resource_prefix string) string { return fmt.Sprintf(` provider "ibm" { @@ -156,7 +163,7 @@ func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, wor } data "ibm_is_image" "rhel7" { - name = "ibm-redhat-7-9-minimal-amd64-3" + name = "ibm-redhat-7-9-minimal-amd64-7" } data "ibm_satellite_attach_host_script" "script" { @@ -225,7 +232,7 @@ func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, wor name = "%s" location = ibm_satellite_location.location.id enable_config_admin = true - kube_version = "4.6_openshift" + kube_version = "4.9_openshift" wait_for_worker_update = true dynamic "zones" { for_each = var.location_zones @@ -244,6 +251,7 @@ func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, wor cluster = ibm_satellite_cluster.create_cluster.id worker_count = 1 host_labels = ["env:dev"] + operating_system = "%s" dynamic "zones" { for_each = var.location_zones content { @@ -256,5 +264,5 @@ func testAccCheckSatelliteClusterWorkerPoolCreate(clusterName, locationName, wor } } -`, locationName, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix, clusterName, workerPoolName) +`, locationName, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix, clusterName, workerPoolName, operatingSystem) } diff --git a/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment.go b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment.go new file mode 100644 index 000000000..cc9059760 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment.go @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIbmSatelliteClusterWorkerPoolZoneAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmSatelliteClusterWorkerPoolZoneAttachmentCreate, + ReadContext: resourceIbmSatelliteClusterWorkerPoolZoneAttachmentRead, + DeleteContext: resourceIbmSatelliteClusterWorkerPoolZoneAttachmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "worker_pool": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The ID of the resource group that the Satellite location is in. To list the resource group ID of the location, use the `GET /v2/satellite/getController` API method.", + }, + "autobalance_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "messages": { + Type: schema.TypeList, + Computed: true, + Description: "Filter features by a list of comma separated collections.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "worker_count": { + Description: "Number of workers", + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func resourceIbmSatelliteClusterWorkerPoolZoneAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + cluster := d.Get("cluster").(string) + workerpool := d.Get("worker_pool").(string) + zone := d.Get("zone").(string) + createSatelliteWorkerPoolZoneOptions := &kubernetesserviceapiv1.CreateSatelliteWorkerPoolZoneOptions{} + createSatelliteWorkerPoolZoneOptions.SetCluster(cluster) + createSatelliteWorkerPoolZoneOptions.SetWorkerpool(workerpool) + createSatelliteWorkerPoolZoneOptions.SetID(zone) + + if _, ok := d.GetOk("resource_group_id"); ok { + createSatelliteWorkerPoolZoneOptions.SetXAuthResourceGroup(d.Get("resource_group_id").(string)) + } + + response, err := satClient.CreateSatelliteWorkerPoolZone(createSatelliteWorkerPoolZoneOptions) + if err != nil { + log.Printf("[DEBUG] CreateSatelliteWorkerPoolZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateSatelliteWorkerPoolZoneWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", cluster, workerpool, zone)) + + return resourceIbmSatelliteClusterWorkerPoolZoneAttachmentRead(context, d, meta) +} + +func resourceIbmSatelliteClusterWorkerPoolZoneAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{} + getWorkerPoolOptions.SetCluster(parts[0]) + getWorkerPoolOptions.SetWorkerpool(parts[1]) + + getWorkerPoolResponse, response, err := satClient.GetWorkerPoolWithContext(context, getWorkerPoolOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetWorkerPool1WithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetWorkerPool1WithContext failed %s\n%s", err, response)) + } + + if getWorkerPoolResponse != nil && getWorkerPoolResponse.Zones != nil { + d.Set("cluster", parts[0]) + d.Set("worker_pool", parts[1]) + + for _, z := range getWorkerPoolResponse.Zones { + if parts[2] == *z.ID { + d.Set("zone", *z.ID) + d.Set("autobalance_enabled", *z.AutobalanceEnabled) + d.Set("messages", *&z.Messages) + d.Set("worker_count", *z.WorkerCount) + } + } + } + + return nil +} + +func resourceIbmSatelliteClusterWorkerPoolZoneAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + removeWorkerPoolZoneOptions := &kubernetesserviceapiv1.RemoveWorkerPoolZoneOptions{} + removeWorkerPoolZoneOptions.SetIdOrName(parts[0]) + removeWorkerPoolZoneOptions.SetPoolidOrName(parts[1]) + removeWorkerPoolZoneOptions.SetZoneid(parts[2]) + + response, err := satClient.RemoveWorkerPoolZoneWithContext(context, removeWorkerPoolZoneOptions) + if err != nil { + log.Printf("[DEBUG] RemoveWorkerPoolZoneWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveWorkerPoolZoneWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment_test.go b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment_test.go new file mode 100644 index 000000000..215250f40 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_cluster_worker_pool_zone_attachment_test.go @@ -0,0 +1,327 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIbmSatelliteClusterWorkerPoolZoneAttachmentBasic(t *testing.T) { + var conf kubernetesserviceapiv1.GetWorkerPoolResponse + clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) + locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + zone := fmt.Sprintf("tf-zone-%d", acctest.RandIntRange(10, 100)) + resource_prefix := fmt.Sprintf("tf-satellite-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentConfigBasic(locationName, clusterName, resource_prefix, zone), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentExists("ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment", conf), + ), + }, + }, + }) +} + +func TestAccIbmSatelliteClusterWorkerPoolZoneAttachmentAllArgs(t *testing.T) { + var conf kubernetesserviceapiv1.GetWorkerPoolResponse + clusterName := fmt.Sprintf("tf-satellitecluster-%d", acctest.RandIntRange(10, 100)) + locationName := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + zone := fmt.Sprintf("tf-zone-%d", acctest.RandIntRange(10, 100)) + resource_prefix := fmt.Sprintf("tf-satellite-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentConfig(locationName, clusterName, resource_prefix, zone), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentExists("ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment", conf), + resource.TestCheckResourceAttr("ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment", "worker_pool", "default"), + resource.TestCheckResourceAttr("ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment", "zone", zone), + ), + }, + { + ResourceName: "ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentConfigBasic(location, cluster, resource_prefix, zone string) string { + return fmt.Sprintf(` + + provider "ibm" { + region = "us-south" + } + + variable "location_zones" { + description = "Allocate your hosts across these three zones" + type = list(string) + default = ["us-south-1", "us-south-2", "us-south-3"] + } + + resource "ibm_satellite_location" "location" { + location = "%s" + managed_from = "wdc04" + zones = var.location_zones + } + + data "ibm_is_image" "rhel7" { + name = "ibm-redhat-7-9-minimal-amd64-4" + } + + data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.location.id + labels = ["env:prod"] + host_provider = "ibm" + } + + data "ibm_resource_group" "resource_group" { + is_default = true + } + + resource "ibm_is_vpc" "satellite_vpc" { + name = "%s-vpc-1" + } + + resource "ibm_is_subnet" "satellite_subnet" { + count = 3 + + name = "%s-subnet-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + total_ipv4_address_count = 256 + zone = "us-south-${count.index + 1}" + } + + resource "ibm_is_ssh_key" "satellite_ssh" { + name = "%s-ibm-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + + resource "ibm_is_instance" "satellite_instance" { + count = 3 + + name = "%s-instance-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + zone = "us-south-${count.index + 1}" + image = data.ibm_is_image.rhel7.id + profile = "mx2-8x64" + keys = [ibm_is_ssh_key.satellite_ssh.id] + resource_group = data.ibm_resource_group.resource_group.id + user_data = data.ibm_satellite_attach_host_script.script.host_script + + primary_network_interface { + subnet = ibm_is_subnet.satellite_subnet[count.index].id + } + } + + resource "ibm_is_floating_ip" "satellite_ip" { + count = 3 + + name = "%s-fip-${count.index}" + target = ibm_is_instance.satellite_instance[count.index].primary_network_interface[0].id + } + + resource "ibm_satellite_host" "assign_host" { + count = 3 + + location = ibm_satellite_location.location.id + host_id = element(ibm_is_instance.satellite_instance[*].name, count.index) + labels = ["env:prod"] + zone = element(var.location_zones, count.index) + host_provider = "ibm" + } + + resource "ibm_satellite_cluster" "create_cluster" { + name = "%s" + location = ibm_satellite_location.location.id + enable_config_admin = true + kube_version = "4.6_openshift" + wait_for_worker_update = true + dynamic "zones" { + for_each = var.location_zones + content { + id = zones.value + } + } + default_worker_pool_labels = { + "test" = "test-pool1" + "test1" = "test-pool2" + } + } + + resource "ibm_satellite_cluster_worker_pool_zone_attachment" "satellite_cluster_worker_pool_zone_attachment" { + cluster = ibm_satellite_cluster.create_cluster.id + worker_pool = "default" + zone = "%s" + } + `, location, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix, cluster, zone) +} + +func testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentConfig(location, cluster, resource_prefix, zone string) string { + return fmt.Sprintf(` + + provider "ibm" { + region = "us-south" + } + + variable "location_zones" { + description = "Allocate your hosts across these three zones" + type = list(string) + default = ["us-south-1", "us-south-2", "us-south-3"] + } + + resource "ibm_satellite_location" "location" { + location = "%s" + managed_from = "wdc04" + zones = var.location_zones + } + + data "ibm_is_image" "rhel7" { + name = "ibm-redhat-7-9-minimal-amd64-4" + } + + data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.location.id + labels = ["env:prod"] + host_provider = "ibm" + } + + data "ibm_resource_group" "resource_group" { + is_default = true + } + + resource "ibm_is_vpc" "satellite_vpc" { + name = "%s-vpc-1" + } + + resource "ibm_is_subnet" "satellite_subnet" { + count = 3 + + name = "%s-subnet-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + total_ipv4_address_count = 256 + zone = "us-south-${count.index + 1}" + } + + resource "ibm_is_ssh_key" "satellite_ssh" { + name = "%s-ibm-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + + resource "ibm_is_instance" "satellite_instance" { + count = 3 + + name = "%s-instance-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + zone = "us-south-${count.index + 1}" + image = data.ibm_is_image.rhel7.id + profile = "mx2-8x64" + keys = [ibm_is_ssh_key.satellite_ssh.id] + resource_group = data.ibm_resource_group.resource_group.id + user_data = data.ibm_satellite_attach_host_script.script.host_script + + primary_network_interface { + subnet = ibm_is_subnet.satellite_subnet[count.index].id + } + } + + resource "ibm_is_floating_ip" "satellite_ip" { + count = 3 + + name = "%s-fip-${count.index}" + target = ibm_is_instance.satellite_instance[count.index].primary_network_interface[0].id + } + + resource "ibm_satellite_host" "assign_host" { + count = 3 + + location = ibm_satellite_location.location.id + host_id = element(ibm_is_instance.satellite_instance[*].name, count.index) + labels = ["env:prod"] + zone = element(var.location_zones, count.index) + host_provider = "ibm" + } + + resource "ibm_satellite_cluster" "create_cluster" { + name = "%s" + location = ibm_satellite_location.location.id + enable_config_admin = true + kube_version = "4.6_openshift" + wait_for_worker_update = true + dynamic "zones" { + for_each = var.location_zones + content { + id = zones.value + } + } + default_worker_pool_labels = { + "test" = "test-pool1" + "test1" = "test-pool2" + } + } + + resource "ibm_satellite_cluster_worker_pool_zone_attachment" "satellite_cluster_worker_pool_zone_attachment" { + cluster = ibm_satellite_cluster.create_cluster.id + worker_pool = "default" + zone = "%s" + } + `, location, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix, cluster, zone) +} + +func testAccCheckIbmSatelliteClusterWorkerPoolZoneAttachmentExists(n string, obj kubernetesserviceapiv1.GetWorkerPoolResponse) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + getWorkerPoolOptions := &kubernetesserviceapiv1.GetWorkerPoolOptions{} + getWorkerPoolOptions.SetCluster(parts[0]) + getWorkerPoolOptions.SetWorkerpool(parts[1]) + + getWorkerPoolResponse, _, err := satClient.GetWorkerPool(getWorkerPoolOptions) + if err != nil { + return err + } + + if getWorkerPoolResponse != nil && getWorkerPoolResponse.Zones != nil { + for _, zoneId := range getWorkerPoolResponse.Zones { + if parts[2] == *zoneId.ID { + obj = *getWorkerPoolResponse + } + } + } + + return nil + } +} diff --git a/ibm/resource_ibm_satellite_endpoint.go b/ibm/service/satellite/resource_ibm_satellite_endpoint.go similarity index 87% rename from ibm/resource_ibm_satellite_endpoint.go rename to ibm/service/satellite/resource_ibm_satellite_endpoint.go index 47107b0b3..93d153b55 100644 --- a/ibm/resource_ibm_satellite_endpoint.go +++ b/ibm/service/satellite/resource_ibm_satellite_endpoint.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" @@ -9,13 +9,16 @@ import ( "log" "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/go-sdk-core/v5/core" ) -func resourceIbmSatelliteEndpoint() *schema.Resource { +func ResourceIBMSatelliteEndpoint() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmSatelliteEndpointCreate, ReadContext: resourceIbmSatelliteEndpointRead, @@ -24,105 +27,105 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "location": &schema.Schema{ + "location": { Type: schema.TypeString, Required: true, Description: "The Location ID.", }, - "connection_type": &schema.Schema{ + "connection_type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_satellite_endpoint", "connection_type"), + ValidateFunc: validate.InvokeValidator("ibm_satellite_endpoint", "connection_type"), Description: "The type of the endpoint.", }, - "display_name": &schema.Schema{ + "display_name": { Type: schema.TypeString, Required: true, Description: "The display name of the endpoint. Endpoint names must start with a letter and end with an alphanumeric character, can contain letters, numbers, and hyphen (-), and must be 63 characters or fewer.", }, - "server_host": &schema.Schema{ + "server_host": { Type: schema.TypeString, Required: true, Description: "The host name or IP address of the server endpoint. For 'http-tunnel' protocol, server_host can start with '*.' , which means a wildcard to it's sub domains. Such as '*.example.com' can accept request to 'api.example.com' and 'www.example.com'.", }, - "server_port": &schema.Schema{ + "server_port": { Type: schema.TypeInt, Required: true, Description: "The port number of the server endpoint. For 'http-tunnel' protocol, server_port can be 0, which means any port. Such as 0 is good for 80 (http) and 443 (https).", }, - "sni": &schema.Schema{ + "sni": { Type: schema.TypeString, Optional: true, Description: "The server name indicator (SNI) which used to connect to the server endpoint. Only useful if server side requires SNI.", }, - "client_protocol": &schema.Schema{ + "client_protocol": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_satellite_endpoint", "client_protocol"), + ValidateFunc: validate.InvokeValidator("ibm_satellite_endpoint", "client_protocol"), Description: "The protocol in the client application side.", }, - "client_mutual_auth": &schema.Schema{ + "client_mutual_auth": { Type: schema.TypeBool, Optional: true, Default: false, Description: "Whether enable mutual auth in the client application side, when client_protocol is 'tls' or 'https', this field is required.", }, - "server_protocol": &schema.Schema{ + "server_protocol": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_satellite_endpoint", "server_protocol"), + ValidateFunc: validate.InvokeValidator("ibm_satellite_endpoint", "server_protocol"), Description: "The protocol in the server application side. This parameter will change to default value if it is omitted even when using PATCH API. If client_protocol is 'udp', server_protocol must be 'udp'. If client_protocol is 'tcp'/'http', server_protocol could be 'tcp'/'tls' and default to 'tcp'. If client_protocol is 'tls'/'https', server_protocol could be 'tcp'/'tls' and default to 'tls'. If client_protocol is 'http-tunnel', server_protocol must be 'tcp'.", }, - "server_mutual_auth": &schema.Schema{ + "server_mutual_auth": { Type: schema.TypeBool, Optional: true, Default: false, Description: "Whether enable mutual auth in the server application side, when client_protocol is 'tls', this field is required.", }, - "reject_unauth": &schema.Schema{ + "reject_unauth": { Type: schema.TypeBool, Optional: true, Default: false, Description: "Whether reject any connection to the server application which is not authorized with the list of supplied CAs in the fields certs.server_cert.", }, - "timeout": &schema.Schema{ + "timeout": { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_satellite_endpoint", "timeout"), + ValidateFunc: validate.InvokeValidator("ibm_satellite_endpoint", "timeout"), Description: "The inactivity timeout in the Endpoint side.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Optional: true, Description: "The service or person who created the endpoint. Must be 1000 characters or fewer.", }, - "certs": &schema.Schema{ + "certs": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The certs.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "client": &schema.Schema{ + "client": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The CA which Satellite Link trust when receiving the connection from the client application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The root cert or the self-signed cert of the client application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Optional: true, Description: "The filename of the cert.", }, - "file_contents": &schema.Schema{ + "file_contents": { Type: schema.TypeString, Optional: true, Description: "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", @@ -133,26 +136,26 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "server": &schema.Schema{ + "server": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The CA which Satellite Link trust when sending the connection to server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The root cert or the self-signed cert of the server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Optional: true, Description: "The filename of the cert.", }, - "file_contents": &schema.Schema{ + "file_contents": { Type: schema.TypeString, Optional: true, Description: "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", @@ -163,26 +166,26 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "connector": &schema.Schema{ + "connector": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The cert which Satellite Link connector provide to identify itself for connecting to the client/server application.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cert": &schema.Schema{ + "cert": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The end-entity cert. This is required when the key is defined.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Optional: true, Description: "The filename of the cert.", }, - "file_contents": &schema.Schema{ + "file_contents": { Type: schema.TypeString, Optional: true, Description: "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", @@ -190,19 +193,19 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "key": &schema.Schema{ + "key": { Type: schema.TypeList, MaxItems: 1, Optional: true, Description: "The private key of the end-entity certificate. This is required when the cert is defined.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "filename": &schema.Schema{ + "filename": { Type: schema.TypeString, Optional: true, Description: "The name of the key.", }, - "file_contents": &schema.Schema{ + "file_contents": { Type: schema.TypeString, Optional: true, Description: "The content of the key. The private key file must be in Privacy-enhanced Electronic Mail (PEM) format.", @@ -216,27 +219,27 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "sources": &schema.Schema{ + "sources": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "source_id": &schema.Schema{ + "source_id": { Type: schema.TypeString, Optional: true, Description: "The Source ID.", }, - "enabled": &schema.Schema{ + "enabled": { Type: schema.TypeBool, Optional: true, Description: "Whether the source is enabled for the endpoint.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Optional: true, Description: "The last time modify the Endpoint configurations.", }, - "pending": &schema.Schema{ + "pending": { Type: schema.TypeBool, Optional: true, Description: "Whether the source has been enabled on this endpoint.", @@ -244,99 +247,99 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { }, }, }, - "connector_port": &schema.Schema{ + "connector_port": { Type: schema.TypeInt, Computed: true, Description: "The connector port.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "Service instance associated with this location.", }, - "service_name": &schema.Schema{ + "service_name": { Type: schema.TypeString, Computed: true, Description: "The service name of the endpoint.", }, - "client_host": &schema.Schema{ + "client_host": { Type: schema.TypeString, Computed: true, Description: "The hostname which Satellite Link server listen on for the on-location endpoint, or the hostname which the connector server listen on for the on-cloud endpoint destiantion.", }, - "client_port": &schema.Schema{ + "client_port": { Type: schema.TypeInt, Computed: true, Description: "The port which Satellite Link server listen on for the on-location, or the port which the connector server listen on for the on-cloud endpoint destiantion.", }, - "status": &schema.Schema{ + "status": { Type: schema.TypeString, Computed: true, Description: "Whether the Endpoint is active or not.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The time when the Endpoint is created.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Computed: true, Description: "The last time modify the Endpoint configurations.", }, - "endpoint_id": &schema.Schema{ + "endpoint_id": { Type: schema.TypeString, Computed: true, Description: "The Endpoint ID.", }, - "performance": &schema.Schema{ + "performance": { Type: schema.TypeList, Computed: true, Description: "The last performance data of the endpoint.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connection": &schema.Schema{ + "connection": { Type: schema.TypeInt, Optional: true, Description: "Concurrent connections number of moment when probe read the data.", }, - "rx_bandwidth": &schema.Schema{ + "rx_bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", }, - "tx_bandwidth": &schema.Schema{ + "tx_bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", }, - "bandwidth": &schema.Schema{ + "bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", }, - "connectors": &schema.Schema{ + "connectors": { Type: schema.TypeList, Optional: true, Description: "The last performance data of the endpoint from each Connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connector": &schema.Schema{ + "connector": { Type: schema.TypeString, Optional: true, Description: "The name of the connector reported the performance data.", }, - "connections": &schema.Schema{ + "connections": { Type: schema.TypeInt, Optional: true, Description: "Concurrent connections number of moment when probe read the data from the Connector.", }, - "rx_bw": &schema.Schema{ + "rx_bw": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", }, - "tx_bw": &schema.Schema{ + "tx_bw": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", @@ -351,46 +354,46 @@ func resourceIbmSatelliteEndpoint() *schema.Resource { } } -func resourceIbmSatelliteEndpointValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 1) +func ResourceIBMSatelliteEndpointValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "connection_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: "cloud, location", }, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "client_protocol", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: "http, http-tunnel, https, tcp, tls, udp", }, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "server_protocol", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: "tcp, tls, udp", }, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "timeout", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Optional: true, MinValue: "1", MaxValue: "180", }, ) - resourceValidator := ResourceValidator{ResourceName: "ibm_satellite_endpoint", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_satellite_endpoint", Schema: validateSchema} return &resourceValidator } func resourceIbmSatelliteEndpointCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } @@ -573,12 +576,12 @@ func resourceIbmSatelliteEndpointMapToAdditionalNewEndpointRequestCertsConnector } func resourceIbmSatelliteEndpointRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -602,43 +605,43 @@ func resourceIbmSatelliteEndpointRead(context context.Context, d *schema.Resourc } if err = d.Set("location", endpoint.LocationID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) } if err = d.Set("connection_type", endpoint.ConnType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting connection_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting connection_type: %s", err)) } if err = d.Set("display_name", endpoint.DisplayName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting display_name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting display_name: %s", err)) } if err = d.Set("server_host", endpoint.ServerHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_host: %s", err)) } - if err = d.Set("server_port", intValue(endpoint.ServerPort)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_port: %s", err)) + if err = d.Set("server_port", flex.IntValue(endpoint.ServerPort)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_port: %s", err)) } if err = d.Set("sni", endpoint.Sni); err != nil { - return diag.FromErr(fmt.Errorf("Error setting sni: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sni: %s", err)) } if err = d.Set("client_protocol", endpoint.ClientProtocol); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_protocol: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_protocol: %s", err)) } if err = d.Set("client_mutual_auth", endpoint.ClientMutualAuth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_mutual_auth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_mutual_auth: %s", err)) } if err = d.Set("server_protocol", endpoint.ServerProtocol); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_protocol: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_protocol: %s", err)) } if err = d.Set("server_mutual_auth", endpoint.ServerMutualAuth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting server_mutual_auth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting server_mutual_auth: %s", err)) } if err = d.Set("reject_unauth", endpoint.RejectUnauth); err != nil { - return diag.FromErr(fmt.Errorf("Error setting reject_unauth: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting reject_unauth: %s", err)) } - if err = d.Set("timeout", intValue(endpoint.Timeout)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting timeout: %s", err)) + if err = d.Set("timeout", flex.IntValue(endpoint.Timeout)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting timeout: %s", err)) } if err = d.Set("created_by", endpoint.CreatedBy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) } if endpoint.Sources != nil { @@ -648,37 +651,37 @@ func resourceIbmSatelliteEndpointRead(context context.Context, d *schema.Resourc sources = append(sources, sourcesItemMap) } if err = d.Set("sources", sources); err != nil { - return diag.FromErr(fmt.Errorf("Error setting sources: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sources: %s", err)) } } - if err = d.Set("connector_port", intValue(endpoint.ConnectorPort)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting connector_port: %s", err)) + if err = d.Set("connector_port", flex.IntValue(endpoint.ConnectorPort)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting connector_port: %s", err)) } if err = d.Set("crn", endpoint.Crn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("service_name", endpoint.ServiceName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting service_name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting service_name: %s", err)) } if err = d.Set("client_host", endpoint.ClientHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_host: %s", err)) } - if err = d.Set("client_port", intValue(endpoint.ClientPort)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting client_port: %s", err)) + if err = d.Set("client_port", flex.IntValue(endpoint.ClientPort)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_port: %s", err)) } if err = d.Set("status", endpoint.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) } if err = d.Set("created_at", endpoint.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("last_change", endpoint.LastChange); err != nil { - return diag.FromErr(fmt.Errorf("Error setting last_change: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_change: %s", err)) } if endpoint.Performance != nil { performanceMap := resourceIbmSatelliteEndpointEndpointPerformanceToMap(*endpoint.Performance) if err = d.Set("performance", []map[string]interface{}{performanceMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting performance: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting performance: %s", err)) } } @@ -791,10 +794,10 @@ func resourceIbmSatelliteEndpointSourceStatusObjectToMap(sourceStatusObject sate func resourceIbmSatelliteEndpointEndpointPerformanceToMap(endpointPerformance satellitelinkv1.EndpointPerformance) map[string]interface{} { endpointPerformanceMap := map[string]interface{}{} - endpointPerformanceMap["connection"] = intValue(endpointPerformance.Connection) - endpointPerformanceMap["rx_bandwidth"] = intValue(endpointPerformance.RxBandwidth) - endpointPerformanceMap["tx_bandwidth"] = intValue(endpointPerformance.TxBandwidth) - endpointPerformanceMap["bandwidth"] = intValue(endpointPerformance.Bandwidth) + endpointPerformanceMap["connection"] = flex.IntValue(endpointPerformance.Connection) + endpointPerformanceMap["rx_bandwidth"] = flex.IntValue(endpointPerformance.RxBandwidth) + endpointPerformanceMap["tx_bandwidth"] = flex.IntValue(endpointPerformance.TxBandwidth) + endpointPerformanceMap["bandwidth"] = flex.IntValue(endpointPerformance.Bandwidth) if endpointPerformance.Connectors != nil { connectors := []map[string]interface{}{} for _, connectorsItem := range endpointPerformance.Connectors { @@ -811,22 +814,22 @@ func resourceIbmSatelliteEndpointEndpointPerformanceConnectorsItemToMap(endpoint endpointPerformanceConnectorsItemMap := map[string]interface{}{} endpointPerformanceConnectorsItemMap["connector"] = endpointPerformanceConnectorsItem.Connector - endpointPerformanceConnectorsItemMap["connections"] = intValue(endpointPerformanceConnectorsItem.Connections) - endpointPerformanceConnectorsItemMap["rxBW"] = intValue(endpointPerformanceConnectorsItem.RxBW) - endpointPerformanceConnectorsItemMap["txBW"] = intValue(endpointPerformanceConnectorsItem.TxBW) + endpointPerformanceConnectorsItemMap["connections"] = flex.IntValue(endpointPerformanceConnectorsItem.Connections) + endpointPerformanceConnectorsItemMap["rxBW"] = flex.IntValue(endpointPerformanceConnectorsItem.RxBW) + endpointPerformanceConnectorsItemMap["txBW"] = flex.IntValue(endpointPerformanceConnectorsItem.TxBW) return endpointPerformanceConnectorsItemMap } func resourceIbmSatelliteEndpointUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } updateEndpointsOptions := &satellitelinkv1.UpdateEndpointsOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } @@ -1005,14 +1008,14 @@ func resourceIbmSatelliteEndpointMapToUpdateEndpointRequestCertsConnectorCert(up } func resourceIbmSatelliteEndpointDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } deleteEndpointsOptions := &satellitelinkv1.DeleteEndpointsOptions{} - parts, err := sepIdParts(d.Id(), "/") + parts, err := flex.SepIdParts(d.Id(), "/") if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_satellite_endpoint_test.go b/ibm/service/satellite/resource_ibm_satellite_endpoint_test.go similarity index 92% rename from ibm/resource_ibm_satellite_endpoint_test.go rename to ibm/service/satellite/resource_ibm_satellite_endpoint_test.go index e145e4146..c27f0f9ef 100644 --- a/ibm/resource_ibm_satellite_endpoint_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_endpoint_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -24,11 +28,11 @@ func TestAccIbmSatelliteEndpointBasic(t *testing.T) { serverProtocol := "tls" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmSatelliteEndpointDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteEndpointConfigBasic(locationID, connType, displayName, serverHost, serverPort, clientProtocol, serverProtocol), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSatelliteEndpointExists("ibm_satellite_endpoint.satellite_endpoint", conf), @@ -69,11 +73,11 @@ func TestAccIbmSatelliteEndpointAllArgs(t *testing.T) { createdByUpdate := fmt.Sprintf("tf_created_by_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmSatelliteEndpointDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteEndpointConfig(locationID, connType, displayName, serverHost, serverPort, sni, clientProtocol, clientMutualAuth, serverProtocol, serverMutualAuth, rejectUnauth, timeout, createdBy), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSatelliteEndpointExists("ibm_satellite_endpoint.satellite_endpoint", conf), @@ -92,7 +96,7 @@ func TestAccIbmSatelliteEndpointAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_satellite_endpoint.satellite_endpoint", "created_by", createdBy), ), }, - resource.TestStep{ + { Config: testAccCheckIbmSatelliteEndpointConfig(locationIDUpdate, connTypeUpdate, displayNameUpdate, serverHostUpdate, serverPortUpdate, sniUpdate, clientProtocolUpdate, clientMutualAuthUpdate, serverProtocolUpdate, serverMutualAuthUpdate, rejectUnauthUpdate, timeoutUpdate, createdByUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_satellite_endpoint.satellite_endpoint", "location", locationIDUpdate), @@ -110,7 +114,7 @@ func TestAccIbmSatelliteEndpointAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_satellite_endpoint.satellite_endpoint", "created_by", createdByUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_satellite_endpoint.satellite_endpoint", ImportState: true, ImportStateVerify: true, @@ -174,12 +178,12 @@ func testAccCheckIbmSatelliteEndpointExists(n string, obj satellitelinkv1.Endpoi return fmt.Errorf("Not found: %s", n) } - satelliteLinkClient, err := testAccProvider.Meta().(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatellitLinkClientSession() if err != nil { return err } - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -200,7 +204,7 @@ func testAccCheckIbmSatelliteEndpointExists(n string, obj satellitelinkv1.Endpoi } func testAccCheckIbmSatelliteEndpointDestroy(s *terraform.State) error { - satelliteLinkClient, err := testAccProvider.Meta().(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatellitLinkClientSession() if err != nil { return err } @@ -209,7 +213,7 @@ func testAccCheckIbmSatelliteEndpointDestroy(s *terraform.State) error { continue } - parts, err := sepIdParts(rs.Primary.ID, "/") + parts, err := flex.SepIdParts(rs.Primary.ID, "/") if err != nil { return err } @@ -225,7 +229,7 @@ func testAccCheckIbmSatelliteEndpointDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("satellite_endpoint still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for satellite_endpoint (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for satellite_endpoint (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/satellite/resource_ibm_satellite_host.go b/ibm/service/satellite/resource_ibm_satellite_host.go new file mode 100644 index 000000000..57e161b45 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_host.go @@ -0,0 +1,349 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" +) + +const ( + hostCluster = "cluster" + hostLocation = "location" + hostID = "host_id" + hostState = "host_state" + hostLabels = "labels" + hostZone = "zone" + hostWorkerPool = "worker_pool" + hostProvider = "host_provider" + + rsHostNormalStatus = "normal" + rsHostProvisioningStatus = "provisioning" + rsHostReadyStatus = "ready" + rsHostUnknownStatus = "unknown" +) + +func ResourceIBMSatelliteHost() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMSatelliteHostCreate, + Read: resourceIBMSatelliteHostRead, + Update: resourceIBMSatelliteHostUpdate, + Delete: resourceIBMSatelliteHostDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(75 * time.Minute), + Read: schema.DefaultTimeout(75 * time.Minute), + Delete: schema.DefaultTimeout(45 * time.Minute), + Update: schema.DefaultTimeout(45 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + hostLocation: { + Type: schema.TypeString, + Required: true, + Description: "The name or ID of the Satellite location", + }, + hostCluster: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name or ID of a Satellite location or cluster to assign the host to", + }, + hostID: { + Type: schema.TypeString, + Required: true, + Description: "The specific host ID to assign to a Satellite location or cluster", + }, + hostLabels: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of labels for the host", + }, + hostZone: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The zone within the cluster to assign the host to", + }, + hostWorkerPool: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name or ID of the worker pool within the cluster to assign the host to", + }, + hostProvider: { + Type: schema.TypeString, + Optional: true, + Description: "Host Provider", + }, + hostState: { + Type: schema.TypeString, + Computed: true, + Description: "Health status of the host", + }, + "wait_till": { + Type: schema.TypeString, + Optional: true, + Description: "Wait until location is normal", + ValidateFunc: validate.InvokeValidator("ibm_satellite_host", "wait_till"), + }, + }, + } +} + +func ResourceIBMSatelliteHostValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + waitTill := "location_normal" + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "wait_till", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: waitTill}) + + satelliteHostResourceValidator := validate.ResourceValidator{ResourceName: "ibm_satellite_host", Schema: validateSchema} + return &satelliteHostResourceValidator +} +func resourceIBMSatelliteHostCreate(d *schema.ResourceData, meta interface{}) error { + hostName := d.Get(hostID).(string) + location := d.Get(hostLocation).(string) + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + hostAssignOptions := &kubernetesserviceapiv1.CreateSatelliteAssignmentOptions{} + hostAssignOptions.Controller = flex.PtrToString(location) + + if _, ok := d.GetOk(hostCluster); ok { + hostAssignOptions.Cluster = flex.PtrToString(d.Get(hostCluster).(string)) + } else { + hostAssignOptions.Cluster = flex.PtrToString(location) + } + hostAssignOptions.HostID = flex.PtrToString(hostName) + + //Check host attached to location + hostStatus, err := waitForHostAttachment(hostName, location, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for attaching host (%s) to be succeeded: %s", hostName, err) + } + + labels := make(map[string]string) + if _, ok := d.GetOk(hostLabels); ok { + l := d.Get(hostLabels).(*schema.Set) + labels = flex.FlattenHostLabels(l.List()) + hostAssignOptions.Labels = labels + } else { + hostAssignOptions.Labels = labels + } + + if _, ok := d.GetOk(hostWorkerPool); ok { + hostAssignOptions.Workerpool = flex.PtrToString(d.Get(hostWorkerPool).(string)) + } + + if _, ok := d.GetOk(hostZone); ok { + hostAssignOptions.Zone = flex.PtrToString(d.Get(hostZone).(string)) + } + + if hostStatus == rsHostReadyStatus { + _, response, err := satClient.CreateSatelliteAssignment(hostAssignOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Assigning Satellite Host: %s\n%s", err, response) + } + } + + d.SetId(fmt.Sprintf("%s/%s", location, hostName)) + + //Wait for host to reach normal state + _, err = waitForHostAttachment(hostName, location, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for host (%s) to get normal state: %s", hostName, err) + } + wait, ok := d.GetOk("wait_till") + if ok && wait.(string) == "location_normal" { + _, err = waitForLocationNormal(location, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for getting location (%s) to be normal: %s", location, err) + } + } + + return resourceIBMSatelliteHostRead(d, meta) +} + +func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + if len(parts) < 2 { + return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of location/hostName", d.Id()) + } + location := parts[0] + hostName := parts[1] + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + hostOptions := &kubernetesserviceapiv1.GetSatelliteHostsOptions{ + Controller: &location, + } + hostList, resp, err := satClient.GetSatelliteHosts(hostOptions) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + d.SetId("") + return nil + } + log.Println("resourceIBMSatelliteHostRead : error in getting hostlist :", err, resp) + return err + } + + for _, h := range hostList { + if hostName == *h.Name || hostName == *h.ID { + d.Set(hostLocation, location) + d.Set("host_id", hostName) + + if _, ok := d.GetOk(hostLabels); ok { + l := d.Get(hostLabels).(*schema.Set) + d.Set(hostLabels, l) + } + + if h.Health != nil { + d.Set(hostState, *h.Health.Status) + } + + if _, ok := d.GetOk(hostCluster); ok { + d.Set(hostCluster, d.Get(hostCluster).(string)) + } else { + d.Set(hostCluster, location) + } + + if h.Assignment != nil { + d.Set(hostWorkerPool, *h.Assignment.WorkerPoolName) + d.Set(hostZone, *h.Assignment.Zone) + } + } + } + + return nil +} + +func resourceIBMSatelliteHostUpdate(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + locationName := parts[0] + hostID := parts[1] + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + updateHostOptions := &kubernetesserviceapiv1.UpdateSatelliteHostOptions{} + updateHostOptions.Controller = &locationName + updateHostOptions.HostID = &hostID + + if v, ok := d.GetOk(hostState); ok && v != nil && v.(string) == rsHostReadyStatus { + labels := make(map[string]string) + if _, ok := d.GetOk(hostLabels); ok { + l := d.Get(hostLabels).(*schema.Set) + labels = flex.FlattenHostLabels(l.List()) + updateHostOptions.Labels = labels + } + response, err := satClient.UpdateSatelliteHost(updateHostOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating Satellite Host: %s\n%s", err, response) + } + } + + return resourceIBMSatelliteHostRead(d, meta) +} + +func resourceIBMSatelliteHostDelete(d *schema.ResourceData, meta interface{}) error { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + location := parts[0] + hostID := parts[1] + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + removeSatHostOptions := &kubernetesserviceapiv1.RemoveSatelliteHostOptions{} + removeSatHostOptions.Controller = &location + removeSatHostOptions.HostID = &hostID + + response, err := satClient.RemoveSatelliteHost(removeSatHostOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Deleting Satellite Host: %s\n%s", err, response) + } + + d.SetId("") + return nil +} + +func waitForHostAttachment(hostName, location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return false, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{rsHostProvisioningStatus, rsHostUnknownStatus}, + Target: []string{rsHostReadyStatus, rsHostNormalStatus}, + Refresh: func() (interface{}, string, error) { + attachOptions := &kubernetesserviceapiv1.GetSatelliteHostsOptions{ + Controller: &location, + } + hostList, resp, err := satClient.GetSatelliteHosts(attachOptions) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() != 404 { + return nil, "", fmt.Errorf("[ERROR] The satellite host (%s) failed to attached: %v\n%s", hostName, err, resp) + } + } + + if hostList != nil { + for _, h := range hostList { + if h.Health != nil { + if (hostName == *h.Name) && (*h.Health.Status == rsHostNormalStatus || *h.Health.Status == rsHostReadyStatus) { + return *h.Health.Status, *h.Health.Status, err + } + } + } + } + return hostName, rsHostProvisioningStatus, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 60 * time.Second, + MinTimeout: 60 * time.Second, + } + + return stateConf.WaitForState() +} diff --git a/ibm/resource_ibm_satellite_host_test.go b/ibm/service/satellite/resource_ibm_satellite_host_test.go similarity index 88% rename from ibm/resource_ibm_satellite_host_test.go rename to ibm/service/satellite/resource_ibm_satellite_host_test.go index 1a1da797a..a73f91a0f 100644 --- a/ibm/resource_ibm_satellite_host_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_host_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -18,12 +22,12 @@ func TestAccFunctionSatelliteHost_Basic(t *testing.T) { resource_prefix := "tf-satellite" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckSatelliteHostCreate(name, resource_prefix), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteHostExists("ibm_satellite_host.assign_host.0"), @@ -42,11 +46,11 @@ func testAccCheckSatelliteHostExists(n string) resource.TestCheckFunc { return fmt.Errorf("Not found: %s", n) } - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -61,7 +65,7 @@ func testAccCheckSatelliteHostExists(n string) resource.TestCheckFunc { if resp != nil && resp.StatusCode == 404 { return nil } - return fmt.Errorf("Error retrieving satellite hosts: %s\n Response code is: %+v", err, resp) + return fmt.Errorf("[ERROR] Error retrieving satellite hosts: %s\n Response code is: %+v", err, resp) } isExist := false @@ -80,7 +84,7 @@ func testAccCheckSatelliteHostExists(n string) resource.TestCheckFunc { } func testAccCheckSatelliteHostDestroy(s *terraform.State) error { - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -90,7 +94,7 @@ func testAccCheckSatelliteHostDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } diff --git a/ibm/resource_ibm_satellite_link.go b/ibm/service/satellite/resource_ibm_satellite_link.go similarity index 79% rename from ibm/resource_ibm_satellite_link.go rename to ibm/service/satellite/resource_ibm_satellite_link.go index 851ba5546..c1a91f81c 100644 --- a/ibm/resource_ibm_satellite_link.go +++ b/ibm/service/satellite/resource_ibm_satellite_link.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite import ( "context" @@ -10,11 +10,13 @@ import ( "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIbmSatelliteLink() *schema.Resource { +func ResourceIBMSatelliteLink() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmSatelliteLinkCreate, ReadContext: resourceIbmSatelliteLinkRead, @@ -23,107 +25,107 @@ func resourceIbmSatelliteLink() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "CRN of the Location.", }, - "location": &schema.Schema{ + "location": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "Location ID.", }, - "ws_endpoint": &schema.Schema{ + "ws_endpoint": { Type: schema.TypeString, Optional: true, Computed: true, Description: "The ws endpoint of the location.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Computed: true, Description: "Description of the location.", }, - "satellite_link_host": &schema.Schema{ + "satellite_link_host": { Type: schema.TypeString, Computed: true, Description: "Satellite Link hostname of the location.", }, - "status": &schema.Schema{ + "status": { Type: schema.TypeString, Computed: true, Description: "Enabled/Disabled.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "Timestamp of creation of location.", }, - "last_change": &schema.Schema{ + "last_change": { Type: schema.TypeString, Computed: true, Description: "Timestamp of latest modification of location.", }, - "performance": &schema.Schema{ + "performance": { Type: schema.TypeList, Computed: true, Description: "The last performance data of the Location.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "tunnels": &schema.Schema{ + "tunnels": { Type: schema.TypeInt, Optional: true, Description: "Tunnels number estbalished from the Location.", }, - "health_status": &schema.Schema{ + "health_status": { Type: schema.TypeString, Optional: true, Description: "Tunnels health status based on the Tunnels number established. Down(0)/Critical(1)/Up(>=2).", }, - "avg_latency": &schema.Schema{ + "avg_latency": { Type: schema.TypeInt, Optional: true, Description: "Average latency calculated form latency of each Connector between Tunnel Server, unit is ms. -1 means no Connector established Tunnel.", }, - "rx_bandwidth": &schema.Schema{ + "rx_bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", }, - "tx_bandwidth": &schema.Schema{ + "tx_bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", }, - "bandwidth": &schema.Schema{ + "bandwidth": { Type: schema.TypeInt, Optional: true, Description: "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", }, - "connectors": &schema.Schema{ + "connectors": { Type: schema.TypeList, Optional: true, Description: "The last performance data of the Location read from each Connector.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "connector": &schema.Schema{ + "connector": { Type: schema.TypeString, Optional: true, Description: "The name of the connector reported the performance data.", }, - "latency": &schema.Schema{ + "latency": { Type: schema.TypeInt, Optional: true, Description: "Latency between Connector and the Tunnel Server it connected.", }, - "rx_bw": &schema.Schema{ + "rx_bw": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", }, - "tx_bw": &schema.Schema{ + "tx_bw": { Type: schema.TypeInt, Optional: true, Description: "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", @@ -139,7 +141,7 @@ func resourceIbmSatelliteLink() *schema.Resource { } func resourceIbmSatelliteLinkCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } @@ -165,14 +167,14 @@ func resourceIbmSatelliteLinkCreate(context context.Context, d *schema.ResourceD } func resourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } - satClient, err := meta.(ClientSession).SatelliteClientSession() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { - return diag.FromErr(fmt.Errorf("SatelliteClientSession failed %s\n", err)) + return diag.FromErr(fmt.Errorf("[ERROR] SatelliteClientSession failed %s", err)) } getLinkOptions := &satellitelinkv1.GetLinkOptions{} @@ -190,7 +192,7 @@ func resourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceDat } getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ - Controller: ptrToString(d.Id()), + Controller: flex.PtrToString(d.Id()), } locInstance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) @@ -204,25 +206,25 @@ func resourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceDat d.Set("crn", *locInstance.Crn) if err = d.Set("location", link.LocationID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) } if err = d.Set("ws_endpoint", link.WsEndpoint); err != nil { - return diag.FromErr(fmt.Errorf("Error setting ws_endpoint: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ws_endpoint: %s", err)) } if err = d.Set("description", link.Desc); err != nil { - return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } if err = d.Set("satellite_link_host", link.SatelliteLinkHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting satellite_link_host: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting satellite_link_host: %s", err)) } if err = d.Set("status", link.Status); err != nil { - return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) } if err = d.Set("created_at", link.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("last_change", link.LastChange); err != nil { - return diag.FromErr(fmt.Errorf("Error setting last_change: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_change: %s", err)) } if link.Performance != nil { performanceMap := resourceIbmSatelliteLinkLocationPerformanceToMap(*link.Performance) @@ -235,15 +237,15 @@ func resourceIbmSatelliteLinkRead(context context.Context, d *schema.ResourceDat func resourceIbmSatelliteLinkLocationPerformanceToMap(locationPerformance satellitelinkv1.LocationPerformance) map[string]interface{} { locationPerformanceMap := map[string]interface{}{} - locationPerformanceMap["tunnels"] = intValue(locationPerformance.Tunnels) + locationPerformanceMap["tunnels"] = flex.IntValue(locationPerformance.Tunnels) if locationPerformance.HealthStatus != nil { locationPerformanceMap["health_status"] = *locationPerformance.HealthStatus } - locationPerformanceMap["avg_latency"] = intValue(locationPerformance.AvgLatency) - locationPerformanceMap["rx_bandwidth"] = intValue(locationPerformance.RxBandwidth) - locationPerformanceMap["tx_bandwidth"] = intValue(locationPerformance.TxBandwidth) - locationPerformanceMap["bandwidth"] = intValue(locationPerformance.Bandwidth) + locationPerformanceMap["avg_latency"] = flex.IntValue(locationPerformance.AvgLatency) + locationPerformanceMap["rx_bandwidth"] = flex.IntValue(locationPerformance.RxBandwidth) + locationPerformanceMap["tx_bandwidth"] = flex.IntValue(locationPerformance.TxBandwidth) + locationPerformanceMap["bandwidth"] = flex.IntValue(locationPerformance.Bandwidth) if locationPerformance.Connectors != nil { connectors := []map[string]interface{}{} for _, connectorsItem := range locationPerformance.Connectors { @@ -263,13 +265,13 @@ func resourceIbmSatelliteLinkLocationPerformanceConnectorsItemToMap(locationPerf locationPerformanceConnectorsItemMap["connector"] = *locationPerformanceConnectorsItem.Connector } if locationPerformanceConnectorsItem.Latency != nil { - locationPerformanceConnectorsItemMap["latency"] = intValue(locationPerformanceConnectorsItem.Latency) + locationPerformanceConnectorsItemMap["latency"] = flex.IntValue(locationPerformanceConnectorsItem.Latency) } if locationPerformanceConnectorsItem.RxBW != nil { - locationPerformanceConnectorsItemMap["rx_bw"] = intValue(locationPerformanceConnectorsItem.RxBW) + locationPerformanceConnectorsItemMap["rx_bw"] = flex.IntValue(locationPerformanceConnectorsItem.RxBW) } if locationPerformanceConnectorsItem.TxBW != nil { - locationPerformanceConnectorsItemMap["tx_bw"] = intValue(locationPerformanceConnectorsItem.TxBW) + locationPerformanceConnectorsItemMap["tx_bw"] = flex.IntValue(locationPerformanceConnectorsItem.TxBW) } log.Println("locationPerformanceConnectorsItemMap ::", locationPerformanceConnectorsItemMap) @@ -277,7 +279,7 @@ func resourceIbmSatelliteLinkLocationPerformanceConnectorsItemToMap(locationPerf } func resourceIbmSatelliteLinkUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } @@ -305,7 +307,7 @@ func resourceIbmSatelliteLinkUpdate(context context.Context, d *schema.ResourceD } func resourceIbmSatelliteLinkDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - satelliteLinkClient, err := meta.(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := meta.(conns.ClientSession).SatellitLinkClientSession() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_satellite_link_test.go b/ibm/service/satellite/resource_ibm_satellite_link_test.go similarity index 83% rename from ibm/resource_ibm_satellite_link_test.go rename to ibm/service/satellite/resource_ibm_satellite_link_test.go index 487ac956b..f7a9db2cc 100644 --- a/ibm/resource_ibm_satellite_link_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_link_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/container-services-go-sdk/satellitelinkv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,24 +22,24 @@ func TestAccIbmSatelliteLinkBasic(t *testing.T) { locationIDUpdate := fmt.Sprintf("tf-location-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmSatelliteLinkDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSatelliteLinkConfig(locationID), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSatelliteLinkExists("ibm_satellite_link.satellite_link", conf), resource.TestCheckResourceAttr("ibm_satellite_link.satellite_link", "location", locationID), ), }, - resource.TestStep{ + { Config: testAccCheckIbmSatelliteLinkConfig(locationIDUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_satellite_link.satellite_link", "location", locationIDUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_satellite_link.satellite_link", ImportState: true, ImportStateVerify: true, @@ -67,7 +70,7 @@ func testAccCheckIbmSatelliteLinkExists(n string, obj satellitelinkv1.Location) return fmt.Errorf("Not found: %s", n) } - satelliteLinkClient, err := testAccProvider.Meta().(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatellitLinkClientSession() if err != nil { return err } @@ -87,7 +90,7 @@ func testAccCheckIbmSatelliteLinkExists(n string, obj satellitelinkv1.Location) } func testAccCheckIbmSatelliteLinkDestroy(s *terraform.State) error { - satelliteLinkClient, err := testAccProvider.Meta().(ClientSession).SatellitLinkClientSession() + satelliteLinkClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatellitLinkClientSession() if err != nil { return err } @@ -106,7 +109,7 @@ func testAccCheckIbmSatelliteLinkDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("satellite_link still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for satellite_link (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for satellite_link (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/satellite/resource_ibm_satellite_location.go b/ibm/service/satellite/resource_ibm_satellite_location.go new file mode 100644 index 000000000..e605de124 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_location.go @@ -0,0 +1,500 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "context" + "fmt" + "log" + "os" + "time" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + satLocation = "location" + sateLocZone = "managed_from" + + isLocationDeleting = "deleting" + isLocationDeleteDone = "done" + isLocationDeploying = "deploying" + isLocationReady = "action required" + isLocationDeployFailed = "deploy_failed" +) + +func ResourceIBMSatelliteLocation() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMSatelliteLocationCreate, + Read: resourceIBMSatelliteLocationRead, + Update: resourceIBMSatelliteLocationUpdate, + Delete: resourceIBMSatelliteLocationDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + ID := d.Id() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return nil, err + } + + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: &ID, + } + + instance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) + if err != nil || instance == nil { + return nil, fmt.Errorf("Error reading satellite location: %s\n%s", err, response) + } + + d.Set("zones", flex.NewStringSet(schema.HashString, instance.WorkerZones)) + return []*schema.ResourceData{d}, nil + }, + }, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ImmutableResourceCustomizeDiff([]string{satLocation, sateLocZone, "resource_group_id", "zones"}, diff) + }, + ), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + satLocation: { + Type: schema.TypeString, + Required: true, + Description: "A unique name for the new Satellite location", + }, + sateLocZone: { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + if o == "" { + return false + } else if o[0:3] == n[0:3] { + return true + } + return o == n + }, + Description: "The IBM Cloud metro from which the Satellite location is managed", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "A description of the new Satellite location", + }, + "coreos_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Enable Red Hat CoreOS features within the Satellite location", + }, + "logging_account_id": { + Type: schema.TypeString, + Optional: true, + Description: "The account ID for IBM Log Analysis with LogDNA log forwarding", + }, + "cos_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "COSBucket - IBM Cloud Object Storage bucket configuration details", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket": { + Type: schema.TypeString, + Optional: true, + }, + "endpoint": { + Type: schema.TypeString, + Optional: true, + }, + "region": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "cos_credentials": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "COSAuthorization - IBM Cloud Object Storage authorization keys", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_key_id": { + Type: schema.TypeString, + Optional: true, + Description: "The HMAC secret access key ID", + }, + "secret_access_key": { + Type: schema.TypeString, + Optional: true, + Description: "The HMAC secret access key", + }, + }, + }, + }, + "zones": { + Type: schema.TypeSet, + Computed: true, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The names of at least three high availability zones to use for the location", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "ID of the resource group.", + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_satellite_location", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags associated with resource instance", + }, + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "Name of the resource group", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Location CRN", + }, + "host_attached_count": { + Type: schema.TypeInt, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The total number of hosts that are attached to the Satellite location.", + }, + "host_available_count": { + Type: schema.TypeInt, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The available number of hosts that can be assigned to a cluster resource in the Satellite location.", + }, + "created_on": { + Type: schema.TypeString, + Computed: true, + Description: "Created Date", + }, + "ingress_hostname": { + Type: schema.TypeString, + Computed: true, + }, + "ingress_secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + } +} + +func ResourceIBMSatelliteLocationValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmSatelliteLocationValidator := validate.ResourceValidator{ResourceName: "ibm_satellite_location", Schema: validateSchema} + return &ibmSatelliteLocationValidator +} + +func resourceIBMSatelliteLocationCreate(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + createSatLocOptions := &kubernetesserviceapiv1.CreateSatelliteLocationOptions{} + satLocation := d.Get(satLocation).(string) + createSatLocOptions.Name = &satLocation + sateLocZone := d.Get(sateLocZone).(string) + createSatLocOptions.Location = &sateLocZone + + if v, ok := d.GetOk("coreos_enabled"); ok { + coreosEnabled := v.(bool) + createSatLocOptions.CoreosEnabled = coreosEnabled + } + if v, ok := d.GetOk("cos_config"); ok { + createSatLocOptions.CosConfig = flex.ExpandCosConfig(v.([]interface{})) + } + + if v, ok := d.GetOk("cos_credentials"); ok { + createSatLocOptions.CosCredentials = flex.ExpandCosCredentials(v.([]interface{})) + } + + if v, ok := d.GetOk("logging_account_id"); ok { + logAccID := v.(string) + createSatLocOptions.LoggingAccountID = &logAccID + } + + if v, ok := d.GetOk("description"); ok { + desc := v.(string) + createSatLocOptions.Description = &desc + } + + if v, ok := d.GetOk("zones"); ok { + z := v.(*schema.Set) + createSatLocOptions.Zones = flex.FlattenSatelliteZones(z) + } + + if v, ok := d.GetOk("resource_group_id"); ok && v != nil { + pathParamsMap := map[string]string{ + "X-Auth-Resource-Group": v.(string), + } + createSatLocOptions.Headers = pathParamsMap + } + + instance, response, err := satClient.CreateSatelliteLocation(createSatLocOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error Creating Satellite Location: %s\n%s", err, response) + } + + d.SetId(*instance.ID) + log.Printf("[INFO] Created satellite location : %s", satLocation) + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) + if err != nil { + log.Printf( + "Error on create of ibm satellite location (%s) tags: %s", d.Id(), err) + } + } + + //Wait for location to be in ready state + _, err = waitForLocationToReady(*instance.ID, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for location (%s) to reach action required state: %s", *instance.ID, err) + } + + return resourceIBMSatelliteLocationRead(d, meta) +} + +func resourceIBMSatelliteLocationRead(d *schema.ResourceData, meta interface{}) error { + ID := d.Id() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: &ID, + } + + instance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) + if err != nil || instance == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return err + } + + d.Set(satLocation, *instance.Name) + if instance.Description != nil { + d.Set("description", *instance.Description) + } + + if instance.CoreosEnabled != nil { + d.Set("coreos_enabled", *instance.CoreosEnabled) + } + + if instance.Datacenter != nil { + d.Set(sateLocZone, *instance.Datacenter) + } + + if instance.ResourceGroup != nil { + d.Set("resource_group_id", instance.ResourceGroup) + } + + tags, err := flex.GetTagsUsingCRN(meta, *instance.Crn) + if err != nil { + log.Printf( + "Error on get of ibm satellite location tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + d.Set("crn", *instance.Crn) + d.Set(flex.ResourceGroupName, *instance.ResourceGroupName) + if instance.Hosts != nil { + d.Set("host_attached_count", *instance.Hosts.Total) + d.Set("host_available_count", *instance.Hosts.Available) + } + d.Set("created_on", *instance.CreatedDate) + if instance.Ingress != nil { + d.Set("ingress_hostname", *instance.Ingress.Hostname) + d.Set("ingress_secret", *instance.Ingress.SecretName) + } + + return nil +} + +func resourceIBMSatelliteLocationUpdate(d *schema.ResourceData, meta interface{}) error { + ID := d.Id() + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + v := os.Getenv("IC_ENV_TAGS") + if d.HasChange("tags") || v != "" { + oldList, newList := d.GetChange("tags") + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: &ID, + } + + instance, response, err := satClient.GetSatelliteLocation(getSatLocOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving satellite location: %s\n%s", err, response) + } + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.Crn) + if err != nil { + log.Printf( + "An error occured during update of instance (%s) tags: %s", ID, err) + } + } + return nil +} + +func resourceIBMSatelliteLocationDelete(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + removeSatLocOptions := &kubernetesserviceapiv1.RemoveSatelliteLocationOptions{} + name := d.Get(satLocation).(string) + removeSatLocOptions.Controller = &name + + response, err := satClient.RemoveSatelliteLocation(removeSatLocOptions) + if err != nil && response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error Deleting Satellite Location: %s\n%s", err, response) + } + + //Wait for location to delete + _, err = waitForLocationDelete(name, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for deleting location instance: %s", err) + } + + d.SetId("") + return nil +} + +func waitForLocationDelete(location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return false, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{isLocationDeleting, ""}, + Target: []string{isLocationDeleteDone}, + Refresh: func() (interface{}, string, error) { + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationsOptions{} + locations, response, err := satClient.GetSatelliteLocations(getSatLocOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting locations list to delete : %s\n%s", err, response) + } + + isExist := false + if locations != nil { + for _, loc := range locations { + if *loc.ID == location || *loc.Name == location { + isExist = true + return "", isLocationDeleting, nil + } + } + if !isExist { + return location, isLocationDeleteDone, nil + } + } + return nil, "", fmt.Errorf("[ERROR] Failed to delete location : %s\n%s", err, response) + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 60 * time.Second, + MinTimeout: 60 * time.Second, + } + + return stateConf.WaitForState() +} + +func waitForLocationToReady(loc string, d *schema.ResourceData, meta interface{}) (interface{}, error) { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return false, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{isLocationDeploying}, + Target: []string{isLocationReady, isLocationDeployFailed}, + Refresh: func() (interface{}, string, error) { + getSatLocOptions := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: flex.PtrToString(loc), + } + + var location *kubernetesserviceapiv1.MultishiftGetController + var response *core.DetailedResponse + var err error + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + location, response, err = satClient.GetSatelliteLocation(getSatLocOptions) + if err != nil || location == nil { + if response != nil && response.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if conns.IsResourceTimeoutError(err) { + location, response, err = satClient.GetSatelliteLocation(getSatLocOptions) + } + + if location != nil && *location.State == isLocationDeployFailed { + return location, isLocationDeployFailed, fmt.Errorf("[ERROR] The location is in failed state: %s", d.Id()) + } + + if location != nil && *location.State == isLocationReady { + return location, isLocationReady, nil + } + return location, isLocationDeploying, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 60 * time.Second, + MinTimeout: 60 * time.Second, + } + + return stateConf.WaitForState() +} diff --git a/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns.go b/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns.go new file mode 100644 index 000000000..dff5b05ab --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns.go @@ -0,0 +1,101 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMSatelliteLocationNlbDns() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmSatelliteLocationNlbDnsCreate, + ReadContext: resourceIbmSatelliteLocationNlbDnsRead, + DeleteContext: resourceIbmSatelliteLocationNlbDnsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "ips": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + } +} + +func resourceIbmSatelliteLocationNlbDnsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return diag.FromErr(err) + } + + bmxSess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + + registerMultishiftClusterOptions := &kubernetesserviceapiv1.RegisterMultishiftClusterOptions{} + + registerMultishiftClusterOptions.SetXAuthRefreshToken(bmxSess.Config.IAMRefreshToken) + if controller, ok := d.GetOk("location"); ok { + registerMultishiftClusterOptions.SetController(controller.(string)) + } + if _, ok := d.GetOk("ips"); ok { + ips := []string{} + for _, segmentsItem := range d.Get("ips").(*schema.Set).List() { + ips = append(ips, segmentsItem.(string)) + } + registerMultishiftClusterOptions.SetIps(ips) + } + + mscRegisterResp, response, err := satClient.RegisterMultishiftClusterWithContext(context, registerMultishiftClusterOptions) + if err != nil { + log.Printf("[DEBUG] RegisterMultishiftClusterWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RegisterMultishiftClusterWithContext failed %s\n%s", err, response)) + } + d.SetId(*mscRegisterResp.Controller) + + return resourceIbmSatelliteLocationNlbDnsRead(context, d, meta) +} + +func resourceIbmSatelliteLocationNlbDnsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ID := d.Id() + nlbClient, err := meta.(conns.ClientSession).VpcContainerAPI() + if err != nil { + return diag.FromErr(err) + } + + nlbAPI := nlbClient.NlbDns() + getSatLocationNlbDNSListOptions := &kubernetesserviceapiv1.GetSatLocationNlbDNSListOptions{} + getSatLocationNlbDNSListOptions.Controller = flex.PtrToString(ID) + + _, err = nlbAPI.GetLocationNLBDNSList(ID) + if err != nil { + log.Printf("[DEBUG] GetSatLocationNlbDNSListWithContext failed %s\n", err) + return diag.FromErr(fmt.Errorf("[ERROR] GetSatLocationNlbDNSListWithContext failed %s", err)) + } + + return nil +} + +func resourceIbmSatelliteLocationNlbDnsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + + return nil +} diff --git a/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns_test.go b/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns_test.go new file mode 100644 index 000000000..6bea09762 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_location_nlb_dns_test.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIbmSatelliteLocationNlbDnsBasic(t *testing.T) { + var conf containerv2.ExtendedNlbVPCConfig + location := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) + resource_prefix := "tf-satellite" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSatelliteLocationNlbDnsConfigBasic(location, resource_prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSatelliteLocationNlbDnsExists("ibm_satellite_location_nlb_dns.satellite_location_dns", conf), + ), + }, + }, + }) +} + +func testAccCheckIbmSatelliteLocationNlbDnsConfigBasic(location, resource_prefix string) string { + return fmt.Sprintf(` + + provider "ibm" { + region = "us-east" + } + + variable "location_zones" { + description = "Allocate your hosts across these three zones" + type = list(string) + default = ["us-east-1", "us-east-2", "us-east-3"] + } + + resource "ibm_satellite_location" "location" { + location = "%s" + managed_from = "wdc04" + zones = var.location_zones + } + + data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.location.id + labels = ["env:prod"] + host_provider = "ibm" + } + + data "ibm_resource_group" "resource_group" { + is_default = true + } + + resource "ibm_is_vpc" "satellite_vpc" { + name = "%s-vpc-1" + } + + resource "ibm_is_subnet" "satellite_subnet" { + count = 3 + + name = "%s-subnet-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + total_ipv4_address_count = 256 + zone = "us-east-${count.index + 1}" + } + + resource "ibm_is_ssh_key" "satellite_ssh" { + name = "%s-ibm-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + } + + resource "ibm_is_instance" "satellite_instance" { + count = 3 + + name = "%s-instance-${count.index}" + vpc = ibm_is_vpc.satellite_vpc.id + zone = "us-east-${count.index + 1}" + image = "r014-931515d2-fcc3-11e9-896d-3baa2797200f" + profile = "mx2-8x64" + keys = [ibm_is_ssh_key.satellite_ssh.id] + resource_group = data.ibm_resource_group.resource_group.id + user_data = data.ibm_satellite_attach_host_script.script.host_script + + primary_network_interface { + subnet = ibm_is_subnet.satellite_subnet[count.index].id + } + } + + resource "ibm_is_floating_ip" "satellite_ip" { + count = 3 + + name = "%s-fip-${count.index}" + target = ibm_is_instance.satellite_instance[count.index].primary_network_interface[0].id + } + + resource "ibm_satellite_host" "assign_host" { + count = 3 + + location = ibm_satellite_location.location.id + host_id = element(ibm_is_instance.satellite_instance[*].name, count.index) + labels = ["env:prod"] + zone = element(var.location_zones, count.index) + host_provider = "ibm" + } + + resource "ibm_satellite_location_nlb_dns" "satellite_location_dns" { + location = ibm_satellite_host.assign_host[1].location + ips = ibm_is_floating_ip.satellite_ip[*].address + } + + `, location, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix) +} + +func testAccCheckIbmSatelliteLocationNlbDnsExists(n string, obj containerv2.ExtendedNlbVPCConfig) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + nlbClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcContainerAPI() + if err != nil { + return err + } + + nlbAPI := nlbClient.NlbDns() + dnsList, err := nlbAPI.GetLocationNLBDNSList(rs.Primary.ID) + if err != nil { + return err + } + + obj = dnsList[0].Nlb + return nil + } +} diff --git a/ibm/resource_ibm_satellite_location_test.go b/ibm/service/satellite/resource_ibm_satellite_location_test.go similarity index 78% rename from ibm/resource_ibm_satellite_location_test.go rename to ibm/service/satellite/resource_ibm_satellite_location_test.go index af5d99fe8..19c534d91 100644 --- a/ibm/resource_ibm_satellite_location_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_location_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package satellite_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,19 +20,21 @@ func TestAccSatelliteLocation_Basic(t *testing.T) { var instance string name := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) managed_from := "wdc04" + coreos_enabled := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteLocationDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteLocationCreate(name, managed_from), + { + Config: testAccCheckSatelliteLocationCreate(name, managed_from, coreos_enabled), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteLocationExists("ibm_satellite_location.location", instance), resource.TestCheckResourceAttr("ibm_satellite_location.location", "location", name), resource.TestCheckResourceAttr("ibm_satellite_location.location", "managed_from", managed_from), + resource.TestCheckResourceAttr("ibm_satellite_location.location", "coreos_enabled", coreos_enabled), ), }, }, @@ -40,22 +45,23 @@ func TestAccSatelliteLocation_Import(t *testing.T) { var instance string name := fmt.Sprintf("tf_location_%d", acctest.RandIntRange(10, 100)) managed_from := "wdc04" + coreos_enabled := "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckSatelliteLocationDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckSatelliteLocationCreate(name, managed_from), + { + Config: testAccCheckSatelliteLocationCreate(name, managed_from, coreos_enabled), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteLocationExists("ibm_satellite_location.location", instance), resource.TestCheckResourceAttr("ibm_satellite_location.location", "location", name), resource.TestCheckResourceAttr("ibm_satellite_location.location", "managed_from", managed_from), ), }, - resource.TestStep{ + { ResourceName: "ibm_satellite_location.location", ImportState: true, ImportStateVerify: true, @@ -73,7 +79,7 @@ func testAccCheckSatelliteLocationExists(n string, instance string) resource.Tes } ID := rs.Primary.ID - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -86,7 +92,7 @@ func testAccCheckSatelliteLocationExists(n string, instance string) resource.Tes if resp != nil && resp.StatusCode == 404 { return nil } - return fmt.Errorf("Error retrieving satellite location: %s\n Response code is: %+v", err, resp) + return fmt.Errorf("[ERROR] Error retrieving satellite location: %s\n Response code is: %+v", err, resp) } instance = *instance1.ID @@ -96,7 +102,7 @@ func testAccCheckSatelliteLocationExists(n string, instance string) resource.Tes } func testAccCheckSatelliteLocationDestroy(s *terraform.State) error { - satClient, err := testAccProvider.Meta().(ClientSession).SatelliteClientSession() + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() if err != nil { return err } @@ -120,7 +126,7 @@ func testAccCheckSatelliteLocationDestroy(s *terraform.State) error { return nil } -func testAccCheckSatelliteLocationCreate(name, managed_from string) string { +func testAccCheckSatelliteLocationCreate(name, managed_from string, coreos_enabled string) string { return fmt.Sprintf(` data "ibm_resource_group" "res_group" { @@ -130,11 +136,12 @@ func testAccCheckSatelliteLocationCreate(name, managed_from string) string { resource "ibm_satellite_location" "location" { location = "%s" managed_from = "%s" + coreos_enabled = "%s" description = "test" zones = ["us-east-1", "us-east-2", "us-east-3"] resource_group_id = data.ibm_resource_group.res_group.id tags = ["env:dev"] } -`, name, managed_from) +`, name, managed_from, coreos_enabled) } diff --git a/ibm/service/scc/README.md b/ibm/service/scc/README.md new file mode 100644 index 000000000..b6d110aaa --- /dev/null +++ b/ibm/service/scc/README.md @@ -0,0 +1,12 @@ +# Terraform IBM Provider Security and Compliance Center + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the SCC resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/scc_account_settings) +* IBM API Docs: [IBM API Docs for SCC Admin](https://cloud.ibm.com/apidocs/security-compliance/admin) +* IBM API Docs: [IBM API Docs for SCC Posture Management](https://cloud.ibm.com/apidocs/security-compliance/posture) +* IBM SCC SDK: [IBM SDK for SCC](https://github.com/IBM/scc-go-sdk) diff --git a/ibm/service/scc/data_source_ibm_scc_account_location.go b/ibm/service/scc/data_source_ibm_scc_account_location.go new file mode 100644 index 000000000..832086ec2 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_location.go @@ -0,0 +1,137 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func DataSourceIBMSccAccountLocation() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSccAccountLocationRead, + + Schema: map[string]*schema.Schema{ + "location_id": { + Type: schema.TypeString, + Required: true, + Description: "The programatic ID of the location that you want to work in.", + }, + "main_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The base URL for the service.", + }, + "governance_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Configuration Governance APIs.", + }, + "results_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to get the results for the Configuration Governance component.", + }, + "compliance_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Posture Management APIs.", + }, + "analytics_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to generate analytics for the Posture Management component.", + }, + "si_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Security Insights APIs.", + }, + "regions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The programatic ID of the available regions.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmSccAccountLocationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + getLocationOptions := &adminserviceapiv1.GetLocationOptions{} + + getLocationOptions.SetLocationID(d.Get("location_id").(string)) + + location, response, err := adminServiceApiClient.GetLocationWithContext(context, getLocationOptions) + if err != nil { + log.Printf("[DEBUG] GetLocationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLocationWithContext failed %s\n%s", err, response)) + } + + d.SetId(*location.ID) + if err = d.Set("main_endpoint_url", location.MainEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting main_endpoint_url: %s", err)) + } + if err = d.Set("governance_endpoint_url", location.GovernanceEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting governance_endpoint_url: %s", err)) + } + if err = d.Set("results_endpoint_url", location.ResultsEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting results_endpoint_url: %s", err)) + } + if err = d.Set("compliance_endpoint_url", location.ComplianceEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting compliance_endpoint_url: %s", err)) + } + if err = d.Set("analytics_endpoint_url", location.AnalyticsEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting analytics_endpoint_url: %s", err)) + } + if err = d.Set("si_endpoint_url", location.SiEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting si_endpoint_url: %s", err)) + } + + if location.Regions != nil { + err = d.Set("regions", dataSourceLocationFlattenRegions(location.Regions)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting regions %s", err)) + } + } + + return nil +} + +func dataSourceLocationFlattenRegions(result []adminserviceapiv1.Region) (regions []map[string]interface{}) { + for _, regionsItem := range result { + regions = append(regions, dataSourceLocationRegionsToMap(regionsItem)) + } + + return regions +} + +func dataSourceLocationRegionsToMap(regionsItem adminserviceapiv1.Region) (regionsMap map[string]interface{}) { + regionsMap = map[string]interface{}{} + + if regionsItem.ID != nil { + regionsMap["id"] = regionsItem.ID + } + + return regionsMap +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_location_settings.go b/ibm/service/scc/data_source_ibm_scc_account_location_settings.go new file mode 100644 index 000000000..0e8f34f8e --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_location_settings.go @@ -0,0 +1,70 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func DataSourceIBMSccAccountLocationSettings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSccAccountLocationSettingsRead, + + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programatic ID of the location that you want to work in.", + }, + }, + } +} + +func dataSourceIbmSccAccountLocationSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + accountSettings, response, err := adminServiceApiClient.GetSettingsWithContext(context, getSettingsOptions) + if err != nil { + log.Printf("[DEBUG] GetSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSettingsWithContext failed %s\n%s", err, response)) + } + + locationSettings := accountSettings.Location + d.SetId(*accountSettings.Location.ID) + + if err = d.Set("id", locationSettings.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting id: %s", err)) + } + + if d.HasChanges() { + d.SetId(dataSourceIbmSccAccountLocationSettingsID(d)) + } + + return nil +} + +func dataSourceIbmSccAccountLocationSettingsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_location_settings_test.go b/ibm/service/scc/data_source_ibm_scc_account_location_settings_test.go new file mode 100644 index 000000000..40a66ed23 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_location_settings_test.go @@ -0,0 +1,34 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSccAccountLocationSettingsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSccAccountLocationSettingsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_account_location_settings.scc_account_location_settings", "id"), + ), + }, + }, + }) +} + +func testAccCheckIbmSccAccountLocationSettingsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_scc_account_location_settings" "scc_account_location_settings" { + } + `) +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_location_test.go b/ibm/service/scc/data_source_ibm_scc_account_location_test.go new file mode 100644 index 000000000..1dc6a3ad1 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_location_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSccAccountLocationDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSccAccountLocationDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_account_location.scc_account_location", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_account_location.scc_account_location", "location_id"), + ), + }, + }, + }) +} + +func testAccCheckIbmSccAccountLocationDataSourceConfigBasic() string { + return ` + data "ibm_scc_account_location" "scc_account_location" { + location_id = "us" + } + ` +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_locations.go b/ibm/service/scc/data_source_ibm_scc_account_locations.go new file mode 100644 index 000000000..15ff98ac4 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_locations.go @@ -0,0 +1,165 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func DataSourceIBMSccAccountLocations() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSccAccountLocationsRead, + + Schema: map[string]*schema.Schema{ + "locations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programatic ID of the location that you want to work in.", + }, + "main_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The base URL for the service.", + }, + "governance_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Configuration Governance APIs.", + }, + "results_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to get the results for the Configuration Governance component.", + }, + "compliance_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Posture Management APIs.", + }, + "analytics_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to generate analytics for the Posture Management component.", + }, + "si_endpoint_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The endpoint that is used to call the Security Insights APIs.", + }, + "regions": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The programatic ID of the available regions.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmSccAccountLocationsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + listLocationsOptions := &adminserviceapiv1.ListLocationsOptions{} + + locations, response, err := adminServiceApiClient.ListLocationsWithContext(context, listLocationsOptions) + if err != nil { + log.Printf("[DEBUG] ListLocationsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLocationsWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIbmSccAccountLocationsID(d)) + + locations_lst := []map[string]interface{}{} + if locations.Locations != nil { + for _, modelItem := range locations.Locations { + modelMap, err := dataSourceIbmSccAccountLocationsLocationToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + locations_lst = append(locations_lst, modelMap) + } + } + if err = d.Set("locations", locations_lst); err != nil { + return diag.FromErr(fmt.Errorf("Error setting locations %s", err)) + } + + return nil +} + +// dataSourceIbmSccAccountLocationsID returns a reasonable ID for the list. +func dataSourceIbmSccAccountLocationsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmSccAccountLocationsLocationToMap(model *adminserviceapiv1.Location) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.MainEndpointURL != nil { + modelMap["main_endpoint_url"] = *model.MainEndpointURL + } + if model.GovernanceEndpointURL != nil { + modelMap["governance_endpoint_url"] = *model.GovernanceEndpointURL + } + if model.ResultsEndpointURL != nil { + modelMap["results_endpoint_url"] = *model.ResultsEndpointURL + } + if model.ComplianceEndpointURL != nil { + modelMap["compliance_endpoint_url"] = *model.ComplianceEndpointURL + } + if model.AnalyticsEndpointURL != nil { + modelMap["analytics_endpoint_url"] = *model.AnalyticsEndpointURL + } + if model.SiEndpointURL != nil { + modelMap["si_endpoint_url"] = *model.SiEndpointURL + } + if model.Regions != nil { + regions := []map[string]interface{}{} + for _, regionsItem := range model.Regions { + regionsItemMap, err := dataSourceIbmSccAccountLocationsRegionToMap(®ionsItem) + if err != nil { + return modelMap, err + } + regions = append(regions, regionsItemMap) + } + modelMap["regions"] = regions + } + return modelMap, nil +} + +func dataSourceIbmSccAccountLocationsRegionToMap(model *adminserviceapiv1.Region) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ID != nil { + modelMap["id"] = *model.ID + } + return modelMap, nil +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_locations_test.go b/ibm/service/scc/data_source_ibm_scc_account_locations_test.go new file mode 100644 index 000000000..1f539fc63 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_locations_test.go @@ -0,0 +1,34 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSccAccountLocationsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSccAccountLocationsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_account_locations.scc_account_locations", "locations.#"), + ), + }, + }, + }) +} + +func testAccCheckIbmSccAccountLocationsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_scc_account_locations" "scc_account_locations" { + } + `) +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_notification_settings.go b/ibm/service/scc/data_source_ibm_scc_account_notification_settings.go new file mode 100644 index 000000000..6732928e8 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_notification_settings.go @@ -0,0 +1,67 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func DataSourceIBMSccNotificationSettings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSccAccountNotificationSettingsRead, + + Schema: map[string]*schema.Schema{ + "instance_crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect.", + }, + }, + } +} + +func dataSourceIbmSccAccountNotificationSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + accountSettings, response, err := adminServiceApiClient.GetSettingsWithContext(context, getSettingsOptions) + if err != nil { + log.Printf("[DEBUG] GetSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSettingsWithContext failed %s\n%s", err, response)) + } + notificationsSettings := accountSettings.EventNotifications + + if err = d.Set("instance_crn", notificationsSettings.InstanceCrn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting instance_crn: %s", err)) + } + + d.SetId("scc_admin_notification_settings") + + return nil +} + +// dataSourceIbmSccAccountNotificationSettingsID returns a reasonable ID for the list. +func dataSourceIbmSccAccountNotificationSettingsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/scc/data_source_ibm_scc_account_notification_settings_test.go b/ibm/service/scc/data_source_ibm_scc_account_notification_settings_test.go new file mode 100644 index 000000000..237610269 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_account_notification_settings_test.go @@ -0,0 +1,34 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSccAccountNotificationSettingsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSccAccountNotificationSettingsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_account_notification_settings.scc_account_notification_settings", "id"), + ), + }, + }, + }) +} + +func testAccCheckIbmSccAccountNotificationSettingsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_scc_account_notification_settings" "scc_account_notification_settings" { + } + `) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_collector.go b/ibm/service/scc/data_source_ibm_scc_posture_collector.go new file mode 100644 index 000000000..4be5dc2cb --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_collector.go @@ -0,0 +1,306 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureCollector() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureCollectorRead, + + Schema: map[string]*schema.Schema{ + "collector_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The id for the given API.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-friendly name of the collector.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the collector.", + }, + "public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + }, + "last_heartbeat": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of collector.", + }, + "collector_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector version. This field is populated when collector is installed.", + }, + "image_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The image version of the collector. This field is populated when collector is installed. \".", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the collector.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that created the collector.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was created.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that modified the collector.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was modified.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Identifies whether the collector is enabled or not(deleted).", + }, + "registration_code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of the collector.", + }, + "credential_public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The credential public key.", + }, + "failure_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of times the collector has failed.", + }, + "approved_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "approved_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "last_failed_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed local gateway ip. This field will be populated only when collector is installed.", + }, + "reset_reason": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + }, + "install_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + }, + "use_private_endpoint": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + }, + "managed_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The entity that manages the collector.", + }, + "trial_expiry": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + }, + "last_failed_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed internet gateway ip of the collector.", + }, + "status_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector status.", + }, + "reset_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + }, + "is_public": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + }, + "is_ubi_image": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector has a Ubi image.", + }, + }, + } +} + +func dataSourceIBMSccPostureCollectorRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + CollectorOptions := &posturemanagementv2.GetCollectorOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + CollectorOptions.SetAccountID(accountID) + CollectorOptions.SetID(d.Get("collector_id").(string)) + + collector, response, err := postureManagementClient.GetCollectorWithContext(context, CollectorOptions) + if err != nil { + log.Printf("[DEBUG] GetCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCollectorWithContext failed %s\n%s", err, response)) + } + + d.SetId(*collector.ID) + if err = d.Set("display_name", collector.DisplayName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting display_name: %s", err)) + } + if err = d.Set("name", collector.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("public_key", collector.PublicKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting public_key: %s", err)) + } + if err = d.Set("last_heartbeat", flex.DateTimeToString(collector.LastHeartbeat)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_heartbeat: %s", err)) + } + if err = d.Set("status", collector.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + if err = d.Set("collector_version", collector.CollectorVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting collector_version: %s", err)) + } + if err = d.Set("image_version", collector.ImageVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting image_version: %s", err)) + } + if err = d.Set("description", collector.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("created_by", collector.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(collector.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_by", collector.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(collector.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("enabled", collector.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + } + if err = d.Set("registration_code", collector.RegistrationCode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting registration_code: %s", err)) + } + if err = d.Set("type", collector.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("credential_public_key", collector.CredentialPublicKey); err != nil { + return diag.FromErr(fmt.Errorf("Error setting credential_public_key: %s", err)) + } + if err = d.Set("failure_count", flex.IntValue(collector.FailureCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting failure_count: %s", err)) + } + if err = d.Set("approved_local_gateway_ip", collector.ApprovedLocalGatewayIP); err != nil { + return diag.FromErr(fmt.Errorf("Error setting approved_local_gateway_ip: %s", err)) + } + if err = d.Set("approved_internet_gateway_ip", collector.ApprovedInternetGatewayIP); err != nil { + return diag.FromErr(fmt.Errorf("Error setting approved_internet_gateway_ip: %s", err)) + } + if err = d.Set("last_failed_local_gateway_ip", collector.LastFailedLocalGatewayIP); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_failed_local_gateway_ip: %s", err)) + } + if err = d.Set("reset_reason", collector.ResetReason); err != nil { + return diag.FromErr(fmt.Errorf("Error setting reset_reason: %s", err)) + } + if err = d.Set("hostname", collector.Hostname); err != nil { + return diag.FromErr(fmt.Errorf("Error setting hostname: %s", err)) + } + if err = d.Set("install_path", collector.InstallPath); err != nil { + return diag.FromErr(fmt.Errorf("Error setting install_path: %s", err)) + } + if err = d.Set("use_private_endpoint", collector.UsePrivateEndpoint); err != nil { + return diag.FromErr(fmt.Errorf("Error setting use_private_endpoint: %s", err)) + } + if err = d.Set("managed_by", collector.ManagedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting managed_by: %s", err)) + } + if err = d.Set("trial_expiry", flex.DateTimeToString(collector.TrialExpiry)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting trial_expiry: %s", err)) + } + if err = d.Set("last_failed_internet_gateway_ip", collector.LastFailedInternetGatewayIP); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_failed_internet_gateway_ip: %s", err)) + } + if err = d.Set("status_description", collector.StatusDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status_description: %s", err)) + } + if err = d.Set("reset_time", flex.DateTimeToString(collector.ResetTime)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting reset_time: %s", err)) + } + if err = d.Set("is_public", collector.IsPublic); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_public: %s", err)) + } + if err = d.Set("is_ubi_image", collector.IsUbiImage); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_ubi_image: %s", err)) + } + + return nil +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_collector_test.go b/ibm/service/scc/data_source_ibm_scc_posture_collector_test.go new file mode 100644 index 000000000..03acccea9 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_collector_test.go @@ -0,0 +1,47 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureCollectorDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccPostureCollectorDataSourceConfigBasic(acc.Scc_posture_collector_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "collector_id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "display_name"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "name"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "status"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "description"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "enabled"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "registration_code"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "type"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "failure_count"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "use_private_endpoint"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "managed_by"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "status_description"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collector.collector", "is_public"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureCollectorDataSourceConfigBasic(collectorId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_collector" "collector" { + collector_id = "%s" + } + `, collectorId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_collectors.go b/ibm/service/scc/data_source_ibm_scc_posture_collectors.go new file mode 100644 index 000000000..6b5cdaaa4 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_collectors.go @@ -0,0 +1,526 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureCollectors() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureListCollectorsRead, + + Schema: map[string]*schema.Schema{ + "offset": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The offset from the start of the list (0-based).", + }, + "limit": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of items to return.", + }, + "total_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total number of items in the list. This will have value as 0 when no collectors are available and below values will not be populated in that case.", + }, + "first": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "next": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "collectors": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The array of items returned.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the collector.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-friendly name of the collector.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the collector.", + }, + "public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + }, + "last_heartbeat": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of collector.", + }, + "collector_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector version. This field is populated when collector is installed.", + }, + "image_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The image version of the collector. This field is populated when collector is installed. \".", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the collector.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that created the collector.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was created.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that modified the collector.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was modified.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Identifies whether the collector is enabled or not(deleted).", + }, + "registration_code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of the collector.", + }, + "credential_public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The credential public key.", + }, + "failure_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of times the collector has failed.", + }, + "approved_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "approved_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "last_failed_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed local gateway ip. This field will be populated only when collector is installed.", + }, + "reset_reason": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + }, + "install_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + }, + "use_private_endpoint": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + }, + "managed_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The entity that manages the collector.", + }, + "trial_expiry": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + }, + "last_failed_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed internet gateway ip of the collector.", + }, + "status_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector status.", + }, + "reset_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + }, + "is_public": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + }, + "is_ubi_image": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector has a Ubi image.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureListCollectorsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + listCollectorsOptions := &posturemanagementv2.ListCollectorsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + listCollectorsOptions.SetAccountID(accountID) + + collectorList, response, err := postureManagementClient.ListCollectorsWithContext(context, listCollectorsOptions) + if err != nil { + log.Printf("[DEBUG] ListCollectorsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListCollectorsWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMSccPostureListCollectorsID(d)) + if err = d.Set("offset", flex.IntValue(collectorList.Offset)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting offset: %s", err)) + } + if err = d.Set("limit", flex.IntValue(collectorList.Limit)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting limit: %s", err)) + } + if err = d.Set("total_count", flex.IntValue(collectorList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + } + + if collectorList.First != nil { + err = d.Set("first", dataSourceCollectorListFlattenFirst(*collectorList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting first %s", err)) + } + } + + if collectorList.Last != nil { + err = d.Set("last", dataSourceCollectorListFlattenLast(*collectorList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting last %s", err)) + } + } + + if collectorList.Next != nil { + err = d.Set("next", dataSourceCollectorListFlattenNext(*collectorList.Next)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting next %s", err)) + } + } + + if collectorList.Previous != nil { + err = d.Set("previous", dataSourceCollectorListFlattenPrevious(*collectorList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting previous %s", err)) + } + } + + if collectorList.Collectors != nil { + err = d.Set("collectors", dataSourceCollectorListFlattenCollectors(collectorList.Collectors)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting collectors %s", err)) + } + } + + return nil +} + +// dataSourceIBMSccPostureListCollectorsID returns a reasonable ID for the list. +func dataSourceIBMSccPostureListCollectorsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceCollectorListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCollectorListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCollectorListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceCollectorListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCollectorListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCollectorListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceCollectorListFlattenNext(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCollectorListNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCollectorListNextToMap(nextItem posturemanagementv2.PageLink) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} + +func dataSourceCollectorListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCollectorListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCollectorListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceCollectorListFlattenCollectors(result []posturemanagementv2.Collector) (collectors []map[string]interface{}) { + for _, collectorsItem := range result { + collectors = append(collectors, dataSourceCollectorListCollectorsToMap(collectorsItem)) + } + + return collectors +} + +func dataSourceCollectorListCollectorsToMap(collectorsItem posturemanagementv2.Collector) (collectorsMap map[string]interface{}) { + collectorsMap = map[string]interface{}{} + + if collectorsItem.ID != nil { + collectorsMap["id"] = collectorsItem.ID + } + if collectorsItem.DisplayName != nil { + collectorsMap["display_name"] = collectorsItem.DisplayName + } + if collectorsItem.Name != nil { + collectorsMap["name"] = collectorsItem.Name + } + if collectorsItem.PublicKey != nil { + collectorsMap["public_key"] = collectorsItem.PublicKey + } + if collectorsItem.LastHeartbeat != nil { + collectorsMap["last_heartbeat"] = collectorsItem.LastHeartbeat.String() + } + if collectorsItem.Status != nil { + collectorsMap["status"] = collectorsItem.Status + } + if collectorsItem.CollectorVersion != nil { + collectorsMap["collector_version"] = collectorsItem.CollectorVersion + } + if collectorsItem.ImageVersion != nil { + collectorsMap["image_version"] = collectorsItem.ImageVersion + } + if collectorsItem.Description != nil { + collectorsMap["description"] = collectorsItem.Description + } + if collectorsItem.CreatedBy != nil { + collectorsMap["created_by"] = collectorsItem.CreatedBy + } + if collectorsItem.CreatedAt != nil { + collectorsMap["created_at"] = collectorsItem.CreatedAt.String() + } + if collectorsItem.UpdatedBy != nil { + collectorsMap["updated_by"] = collectorsItem.UpdatedBy + } + if collectorsItem.UpdatedAt != nil { + collectorsMap["updated_at"] = collectorsItem.UpdatedAt.String() + } + if collectorsItem.Enabled != nil { + collectorsMap["enabled"] = collectorsItem.Enabled + } + if collectorsItem.RegistrationCode != nil { + collectorsMap["registration_code"] = collectorsItem.RegistrationCode + } + if collectorsItem.Type != nil { + collectorsMap["type"] = collectorsItem.Type + } + if collectorsItem.CredentialPublicKey != nil { + collectorsMap["credential_public_key"] = collectorsItem.CredentialPublicKey + } + if collectorsItem.FailureCount != nil { + collectorsMap["failure_count"] = collectorsItem.FailureCount + } + if collectorsItem.ApprovedLocalGatewayIP != nil { + collectorsMap["approved_local_gateway_ip"] = collectorsItem.ApprovedLocalGatewayIP + } + if collectorsItem.ApprovedInternetGatewayIP != nil { + collectorsMap["approved_internet_gateway_ip"] = collectorsItem.ApprovedInternetGatewayIP + } + if collectorsItem.LastFailedLocalGatewayIP != nil { + collectorsMap["last_failed_local_gateway_ip"] = collectorsItem.LastFailedLocalGatewayIP + } + if collectorsItem.ResetReason != nil { + collectorsMap["reset_reason"] = collectorsItem.ResetReason + } + if collectorsItem.Hostname != nil { + collectorsMap["hostname"] = collectorsItem.Hostname + } + if collectorsItem.InstallPath != nil { + collectorsMap["install_path"] = collectorsItem.InstallPath + } + if collectorsItem.UsePrivateEndpoint != nil { + collectorsMap["use_private_endpoint"] = collectorsItem.UsePrivateEndpoint + } + if collectorsItem.ManagedBy != nil { + collectorsMap["managed_by"] = collectorsItem.ManagedBy + } + if collectorsItem.TrialExpiry != nil { + collectorsMap["trial_expiry"] = collectorsItem.TrialExpiry.String() + } + if collectorsItem.LastFailedInternetGatewayIP != nil { + collectorsMap["last_failed_internet_gateway_ip"] = collectorsItem.LastFailedInternetGatewayIP + } + if collectorsItem.StatusDescription != nil { + collectorsMap["status_description"] = collectorsItem.StatusDescription + } + if collectorsItem.ResetTime != nil { + collectorsMap["reset_time"] = collectorsItem.ResetTime.String() + } + if collectorsItem.IsPublic != nil { + collectorsMap["is_public"] = collectorsItem.IsPublic + } + if collectorsItem.IsUbiImage != nil { + collectorsMap["is_ubi_image"] = collectorsItem.IsUbiImage + } + + return collectorsMap +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_collectors_test.go b/ibm/service/scc/data_source_ibm_scc_posture_collectors_test.go new file mode 100644 index 000000000..c6b2d2534 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_collectors_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureListCollectorsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccPostureListCollectorsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "offset"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "limit"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_collectors.list_collectors", "collectors.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureListCollectorsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_scc_posture_collectors" "list_collectors" { + } + `) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_credential.go b/ibm/service/scc/data_source_ibm_scc_posture_credential.go new file mode 100644 index 000000000..4bc10785f --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_credential.go @@ -0,0 +1,400 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureCredential() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureCredentialRead, + + Schema: map[string]*schema.Schema{ + "credential_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The id for the given API.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Credentials status enabled/disbaled.", + }, + "credential_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials description.", + }, + "display_fields": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Details the fields on the credential. This will change as per credential type selected.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ibm_api_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + }, + "aws_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS client Id.This is mandatory for AWS Cloud.", + }, + "aws_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS client secret.This is mandatory for AWS Cloud.", + }, + "aws_region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS region.", + }, + "aws_arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS arn value.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "azure_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure client Id. This is mandatory for Azure Credential type.", + }, + "azure_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure client secret.This is mandatory for Azure Credential type.", + }, + "azure_subscription_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure subscription Id.This is mandatory for Azure Credential type.", + }, + "azure_resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure resource group.", + }, + "database_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Database name.This is mandatory for Database Credential type.", + }, + "winrm_authtype": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_usessl": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_port": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + }, + "ms_365_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_tenant_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + }, + "auth_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "user_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "pem_file_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the PEM file.", + }, + "pem_data": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The base64 encoded data to associate with the PEM file.", + }, + }, + }, + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user who created the credentials.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time that the credentials was created in UTC.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The modified time that the credentials was modified in UTC.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user who modified the credentials.", + }, + "group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Credential group details.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "credential group id.", + }, + "passphrase": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "passphase of the credential.", + }, + }, + }, + }, + "purpose": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Purpose for which the credential is created.", + }, + }, + } +} + +func dataSourceIBMSccPostureCredentialRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + CredentialOptions := &posturemanagementv2.GetCredentialOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + CredentialOptions.SetAccountID(accountID) + CredentialOptions.SetID(d.Get("credential_id").(string)) + + credential, response, err := postureManagementClient.GetCredentialWithContext(context, CredentialOptions) + if err != nil { + log.Printf("[DEBUG] GetCredentialWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCredentialWithContext failed %s\n%s", err, response)) + } + + d.SetId(*credential.ID) + if err = d.Set("enabled", credential.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + } + if err = d.Set("credential_type", credential.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("name", credential.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("description", credential.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if credential.DisplayFields != nil { + err = d.Set("display_fields", dataSourceCredentialFlattenDisplayFields(*credential.DisplayFields)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting display_fields %s", err)) + } + } + if err = d.Set("created_by", credential.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(credential.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(credential.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", credential.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_by: %s", err)) + } + + if credential.Group != nil { + err = d.Set("group", dataSourceCredentialFlattenGroup(*credential.Group)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting group %s", err)) + } + } + if err = d.Set("purpose", credential.Purpose); err != nil { + return diag.FromErr(fmt.Errorf("Error setting purpose: %s", err)) + } + + return nil +} + +func dataSourceCredentialFlattenDisplayFields(result posturemanagementv2.CredentialDisplayFields) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCredentialDisplayFieldsToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCredentialDisplayFieldsToMap(displayFieldsItem posturemanagementv2.CredentialDisplayFields) (displayFieldsMap map[string]interface{}) { + displayFieldsMap = map[string]interface{}{} + + if displayFieldsItem.IBMAPIKey != nil { + displayFieldsMap["ibm_api_key"] = displayFieldsItem.IBMAPIKey + } + if displayFieldsItem.AwsClientID != nil { + displayFieldsMap["aws_client_id"] = displayFieldsItem.AwsClientID + } + if displayFieldsItem.AwsClientSecret != nil { + displayFieldsMap["aws_client_secret"] = displayFieldsItem.AwsClientSecret + } + if displayFieldsItem.AwsRegion != nil { + displayFieldsMap["aws_region"] = displayFieldsItem.AwsRegion + } + if displayFieldsItem.AwsArn != nil { + displayFieldsMap["aws_arn"] = displayFieldsItem.AwsArn + } + if displayFieldsItem.Username != nil { + displayFieldsMap["username"] = displayFieldsItem.Username + } + if displayFieldsItem.Password != nil { + displayFieldsMap["password"] = displayFieldsItem.Password + } + if displayFieldsItem.AzureClientID != nil { + displayFieldsMap["azure_client_id"] = displayFieldsItem.AzureClientID + } + if displayFieldsItem.AzureClientSecret != nil { + displayFieldsMap["azure_client_secret"] = displayFieldsItem.AzureClientSecret + } + if displayFieldsItem.AzureSubscriptionID != nil { + displayFieldsMap["azure_subscription_id"] = displayFieldsItem.AzureSubscriptionID + } + if displayFieldsItem.AzureResourceGroup != nil { + displayFieldsMap["azure_resource_group"] = displayFieldsItem.AzureResourceGroup + } + if displayFieldsItem.DatabaseName != nil { + displayFieldsMap["database_name"] = displayFieldsItem.DatabaseName + } + if displayFieldsItem.WinrmAuthtype != nil { + displayFieldsMap["winrm_authtype"] = displayFieldsItem.WinrmAuthtype + } + if displayFieldsItem.WinrmUsessl != nil { + displayFieldsMap["winrm_usessl"] = displayFieldsItem.WinrmUsessl + } + if displayFieldsItem.WinrmPort != nil { + displayFieldsMap["winrm_port"] = displayFieldsItem.WinrmPort + } + if displayFieldsItem.Ms365ClientID != nil { + displayFieldsMap["ms_365_client_id"] = displayFieldsItem.Ms365ClientID + } + if displayFieldsItem.Ms365ClientSecret != nil { + displayFieldsMap["ms_365_client_secret"] = displayFieldsItem.Ms365ClientSecret + } + if displayFieldsItem.Ms365TenantID != nil { + displayFieldsMap["ms_365_tenant_id"] = displayFieldsItem.Ms365TenantID + } + if displayFieldsItem.AuthURL != nil { + displayFieldsMap["auth_url"] = displayFieldsItem.AuthURL + } + if displayFieldsItem.ProjectName != nil { + displayFieldsMap["project_name"] = displayFieldsItem.ProjectName + } + if displayFieldsItem.UserDomainName != nil { + displayFieldsMap["user_domain_name"] = displayFieldsItem.UserDomainName + } + if displayFieldsItem.ProjectDomainName != nil { + displayFieldsMap["project_domain_name"] = displayFieldsItem.ProjectDomainName + } + if displayFieldsItem.PemFileName != nil { + displayFieldsMap["pem_file_name"] = displayFieldsItem.PemFileName + } + if displayFieldsItem.PemData != nil { + displayFieldsMap["pem_data"] = displayFieldsItem.PemData + } + + return displayFieldsMap +} + +func dataSourceCredentialFlattenGroup(result posturemanagementv2.CredentialGroup) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCredentialGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCredentialGroupToMap(groupItem posturemanagementv2.CredentialGroup) (groupMap map[string]interface{}) { + groupMap = map[string]interface{}{} + + if groupItem.ID != nil { + groupMap["id"] = groupItem.ID + } + if groupItem.Passphrase != nil { + groupMap["passphrase"] = groupItem.Passphrase + } + + return groupMap +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_credential_test.go b/ibm/service/scc/data_source_ibm_scc_posture_credential_test.go new file mode 100644 index 000000000..70ce3c178 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_credential_test.go @@ -0,0 +1,43 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureCredentialDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccPostureCredentialDataSourceConfigBasic(acc.Scc_posture_credential_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "credential_id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "enabled"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "credential_type"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "name"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "created_by"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "updated_by"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credential.credential", "purpose"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureCredentialDataSourceConfigBasic(credentialId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_credential" "credential" { + credential_id = "%s" + } + `, credentialId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_credentials.go b/ibm/service/scc/data_source_ibm_scc_posture_credentials.go new file mode 100644 index 000000000..7b4e82c82 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_credentials.go @@ -0,0 +1,576 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "net/url" + "reflect" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureCredentials() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureListCredentialsRead, + + Schema: map[string]*schema.Schema{ + "first": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "credentials": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The details of a credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Credentials status enabled/disbaled.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials ID.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials type.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials name.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Credentials description.", + }, + "display_fields": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Details the fields on the credential. This will change as per credential type selected.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ibm_api_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + }, + "aws_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS client Id.This is mandatory for AWS Cloud.", + }, + "aws_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "AWS client secret.This is mandatory for AWS Cloud.", + }, + "aws_region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS region.", + }, + "aws_arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS arn value.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "azure_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure client Id. This is mandatory for Azure Credential type.", + }, + "azure_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Azure client secret.This is mandatory for Azure Credential type.", + }, + "azure_subscription_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure subscription Id.This is mandatory for Azure Credential type.", + }, + "azure_resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure resource group.", + }, + "database_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Database name.This is mandatory for Database Credential type.", + }, + "winrm_authtype": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_usessl": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_port": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + }, + "ms_365_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_tenant_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + }, + "auth_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "user_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "pem_file_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the PEM file.", + }, + "pem_data": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The base64 encoded data to associate with the PEM file.", + }, + }, + }, + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user who created the credentials.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time that the credentials was created in UTC.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The modified time that the credentials was modified in UTC.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "ID of the user who modified the credentials.", + }, + "group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Credential group details.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "credential group id.", + }, + "passphrase": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "passphase of the credential.", + }, + }, + }, + }, + "purpose": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Purpose for which the credential is created.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureListCredentialsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + listCredentialsOptions := &posturemanagementv2.ListCredentialsOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + listCredentialsOptions.SetAccountID(accountID) + + var credentialList *posturemanagementv2.CredentialList + + listCredentialsOptions.Limit = core.Int64Ptr(int64(2)) + result, response, err := postureManagementClient.ListCredentialsWithContext(context, listCredentialsOptions) + credentialList = result + if err != nil { + log.Printf("[DEBUG] ListCredentialsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListCredentialsWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMSccPostureListCredentialsID(d)) + + if credentialList.First != nil { + err = d.Set("first", dataSourceCredentialListFlattenFirst(*credentialList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting first %s", err)) + } + } + + if credentialList.Last != nil { + err = d.Set("last", dataSourceCredentialListFlattenLast(*credentialList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting last %s", err)) + } + } + + if credentialList.Previous != nil { + err = d.Set("previous", dataSourceCredentialListFlattenPrevious(*credentialList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting previous %s", err)) + } + } + + if credentialList.Credentials != nil { + err = d.Set("credentials", dataSourceCredentialListFlattenCredentials(credentialList.Credentials)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting credentials %s", err)) + } + } + + return nil +} + +// dataSourceIBMSccPostureListCredentialsID returns a reasonable ID for the list. +func dataSourceIBMSccPostureListCredentialsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceCredentialListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCredentialListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCredentialListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceCredentialListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCredentialListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCredentialListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceCredentialListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceCredentialListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceCredentialListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceCredentialListFlattenCredentials(result []posturemanagementv2.Credential) (credentials []map[string]interface{}) { + for _, credentialsItem := range result { + credentials = append(credentials, dataSourceCredentialListCredentialsToMap(credentialsItem)) + } + + return credentials +} + +func dataSourceCredentialListCredentialsToMap(credentialsItem posturemanagementv2.Credential) (credentialsMap map[string]interface{}) { + credentialsMap = map[string]interface{}{} + + if credentialsItem.Enabled != nil { + credentialsMap["enabled"] = credentialsItem.Enabled + } + if credentialsItem.ID != nil { + credentialsMap["id"] = credentialsItem.ID + } + if credentialsItem.Type != nil { + credentialsMap["type"] = credentialsItem.Type + } + if credentialsItem.Name != nil { + credentialsMap["name"] = credentialsItem.Name + } + if credentialsItem.Description != nil { + credentialsMap["description"] = credentialsItem.Description + } + if credentialsItem.DisplayFields != nil { + displayFieldsList := []map[string]interface{}{} + displayFieldsMap := dataSourceCredentialListCredentialsDisplayFieldsToMap(*credentialsItem.DisplayFields) + displayFieldsList = append(displayFieldsList, displayFieldsMap) + credentialsMap["display_fields"] = displayFieldsList + } + if credentialsItem.CreatedBy != nil { + credentialsMap["created_by"] = credentialsItem.CreatedBy + } + if credentialsItem.CreatedAt != nil { + credentialsMap["created_at"] = credentialsItem.CreatedAt.String() + } + if credentialsItem.UpdatedAt != nil { + credentialsMap["updated_at"] = credentialsItem.UpdatedAt.String() + } + if credentialsItem.UpdatedBy != nil { + credentialsMap["updated_by"] = credentialsItem.UpdatedBy + } + if credentialsItem.Group != nil { + groupList := []map[string]interface{}{} + groupMap := dataSourceCredentialListCredentialsGroupToMap(*credentialsItem.Group) + groupList = append(groupList, groupMap) + credentialsMap["group"] = groupList + } + if credentialsItem.Purpose != nil { + credentialsMap["purpose"] = credentialsItem.Purpose + } + + return credentialsMap +} + +func dataSourceCredentialListCredentialsDisplayFieldsToMap(displayFieldsItem posturemanagementv2.CredentialDisplayFields) (displayFieldsMap map[string]interface{}) { + displayFieldsMap = map[string]interface{}{} + + if displayFieldsItem.IBMAPIKey != nil { + displayFieldsMap["ibm_api_key"] = displayFieldsItem.IBMAPIKey + } + if displayFieldsItem.AwsClientID != nil { + displayFieldsMap["aws_client_id"] = displayFieldsItem.AwsClientID + } + if displayFieldsItem.AwsClientSecret != nil { + displayFieldsMap["aws_client_secret"] = displayFieldsItem.AwsClientSecret + } + if displayFieldsItem.AwsRegion != nil { + displayFieldsMap["aws_region"] = displayFieldsItem.AwsRegion + } + if displayFieldsItem.AwsArn != nil { + displayFieldsMap["aws_arn"] = displayFieldsItem.AwsArn + } + if displayFieldsItem.Username != nil { + displayFieldsMap["username"] = displayFieldsItem.Username + } + if displayFieldsItem.Password != nil { + displayFieldsMap["password"] = displayFieldsItem.Password + } + if displayFieldsItem.AzureClientID != nil { + displayFieldsMap["azure_client_id"] = displayFieldsItem.AzureClientID + } + if displayFieldsItem.AzureClientSecret != nil { + displayFieldsMap["azure_client_secret"] = displayFieldsItem.AzureClientSecret + } + if displayFieldsItem.AzureSubscriptionID != nil { + displayFieldsMap["azure_subscription_id"] = displayFieldsItem.AzureSubscriptionID + } + if displayFieldsItem.AzureResourceGroup != nil { + displayFieldsMap["azure_resource_group"] = displayFieldsItem.AzureResourceGroup + } + if displayFieldsItem.DatabaseName != nil { + displayFieldsMap["database_name"] = displayFieldsItem.DatabaseName + } + if displayFieldsItem.WinrmAuthtype != nil { + displayFieldsMap["winrm_authtype"] = displayFieldsItem.WinrmAuthtype + } + if displayFieldsItem.WinrmUsessl != nil { + displayFieldsMap["winrm_usessl"] = displayFieldsItem.WinrmUsessl + } + if displayFieldsItem.WinrmPort != nil { + displayFieldsMap["winrm_port"] = displayFieldsItem.WinrmPort + } + if displayFieldsItem.Ms365ClientID != nil { + displayFieldsMap["ms_365_client_id"] = displayFieldsItem.Ms365ClientID + } + if displayFieldsItem.Ms365ClientSecret != nil { + displayFieldsMap["ms_365_client_secret"] = displayFieldsItem.Ms365ClientSecret + } + if displayFieldsItem.Ms365TenantID != nil { + displayFieldsMap["ms_365_tenant_id"] = displayFieldsItem.Ms365TenantID + } + if displayFieldsItem.AuthURL != nil { + displayFieldsMap["auth_url"] = displayFieldsItem.AuthURL + } + if displayFieldsItem.ProjectName != nil { + displayFieldsMap["project_name"] = displayFieldsItem.ProjectName + } + if displayFieldsItem.UserDomainName != nil { + displayFieldsMap["user_domain_name"] = displayFieldsItem.UserDomainName + } + if displayFieldsItem.ProjectDomainName != nil { + displayFieldsMap["project_domain_name"] = displayFieldsItem.ProjectDomainName + } + if displayFieldsItem.PemFileName != nil { + displayFieldsMap["pem_file_name"] = displayFieldsItem.PemFileName + } + if displayFieldsItem.PemData != nil { + displayFieldsMap["pem_data"] = displayFieldsItem.PemData + } + + return displayFieldsMap +} + +func dataSourceCredentialListCredentialsGroupToMap(groupItem posturemanagementv2.CredentialGroup) (groupMap map[string]interface{}) { + groupMap = map[string]interface{}{} + + if groupItem.ID != nil { + groupMap["id"] = groupItem.ID + } + if groupItem.Passphrase != nil { + groupMap["passphrase"] = groupItem.Passphrase + } + + return groupMap +} + +func dataSourceCredentialListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_credentials_test.go b/ibm/service/scc/data_source_ibm_scc_posture_credentials_test.go new file mode 100644 index 000000000..7283e8419 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_credentials_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureListCredentialsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccPostureListCredentialsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credentials.list_credentials", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credentials.list_credentials", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credentials.list_credentials", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_credentials.list_credentials", "credentials.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureListCredentialsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_scc_posture_credentials" "list_credentials" { + } + `) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_group_profile.go b/ibm/service/scc/data_source_ibm_scc_posture_group_profile.go new file mode 100644 index 000000000..786dd7178 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_group_profile.go @@ -0,0 +1,347 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "net/url" + "reflect" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + //"github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureGroupProfileDetails() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureGroupProfileDetailsRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", + }, + "first": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "controls": { + Type: schema.TypeList, + Computed: true, + Description: "Profiles array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The identifier number of the control.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the control.", + }, + "external_control_id": { + Type: schema.TypeString, + Computed: true, + Description: "The external identifier number of the control.", + }, + "goals": { + Type: schema.TypeList, + Computed: true, + Description: "Mapped goals aganist the control identifier.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the goal.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The goal ID.", + }, + "severity": { + Type: schema.TypeString, + Computed: true, + Description: "The severity of the goal.", + }, + "is_manual": { + Type: schema.TypeBool, + Computed: true, + Description: "The goal is manual check.", + }, + "is_remediable": { + Type: schema.TypeBool, + Computed: true, + Description: "The goal is remediable or not.", + }, + "is_reversible": { + Type: schema.TypeBool, + Computed: true, + Description: "The goal is reversible or not.", + }, + "is_automatable": { + Type: schema.TypeBool, + Computed: true, + Description: "The goal is automatable or not.", + }, + "is_auto_remediable": { + Type: schema.TypeBool, + Computed: true, + Description: "The goal is autoremediable or not.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureGroupProfileDetailsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getProfileControlsOptions := &posturemanagementv2.GetProfileControlsOptions{} + + getProfileControlsOptions.SetProfileID(d.Get("profile_id").(string)) + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getProfileControlsOptions.SetAccountID(accountID) + + var controlList *posturemanagementv2.ControlList + var offset int64 + finalList := []posturemanagementv2.ControlItem{} + + for { + + result, response, err := postureManagementClient.GetProfileControlsWithContext(context, getProfileControlsOptions) + controlList = result + if err != nil { + log.Printf("[DEBUG] GetProfileControlsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetProfileControlsWithContext failed %s\n%s", err, response)) + } + offset = dataSourceControlListGetNext(result.Next) + finalList = append(finalList, result.Controls...) + if offset == 0 { + break + } + } + + controlList.Controls = finalList + + d.SetId(dataSourceIBMSccPostureGroupProfileDetailsID(d)) + + if controlList.Controls != nil { + err = d.Set("controls", dataSourceControlListFlattenControls(controlList.Controls)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting controls %s", err)) + } + } + + return nil +} + +// dataSourceIBMGroupProfileDetailsID returns a reasonable ID for the list. +func dataSourceIBMSccPostureGroupProfileDetailsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceControlListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceControlListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceControlListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceControlListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceControlListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceControlListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceControlListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceControlListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceControlListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceControlListFlattenControls(result []posturemanagementv2.ControlItem) (controls []map[string]interface{}) { + for _, controlsItem := range result { + controls = append(controls, dataSourceControlListControlsToMap(controlsItem)) + } + + return controls +} + +func dataSourceControlListControlsToMap(controlsItem posturemanagementv2.ControlItem) (controlsMap map[string]interface{}) { + controlsMap = map[string]interface{}{} + + if controlsItem.ID != nil { + controlsMap["id"] = controlsItem.ID + } + if controlsItem.Description != nil { + controlsMap["description"] = controlsItem.Description + } + if controlsItem.ExternalControlID != nil { + controlsMap["external_control_id"] = controlsItem.ExternalControlID + } + if controlsItem.Goals != nil { + goalsList := []map[string]interface{}{} + for _, goalsItem := range controlsItem.Goals { + goalsList = append(goalsList, dataSourceControlListControlsGoalsToMap(goalsItem)) + } + controlsMap["goals"] = goalsList + } + + return controlsMap +} + +func dataSourceControlListControlsGoalsToMap(goalsItem posturemanagementv2.GoalItem) (goalsMap map[string]interface{}) { + goalsMap = map[string]interface{}{} + + if goalsItem.Description != nil { + goalsMap["description"] = goalsItem.Description + } + if goalsItem.ID != nil { + goalsMap["id"] = goalsItem.ID + } + if goalsItem.Severity != nil { + goalsMap["severity"] = goalsItem.Severity + } + if goalsItem.IsManual != nil { + goalsMap["is_manual"] = goalsItem.IsManual + } + if goalsItem.IsRemediable != nil { + goalsMap["is_remediable"] = goalsItem.IsRemediable + } + if goalsItem.IsReversible != nil { + goalsMap["is_reversible"] = goalsItem.IsReversible + } + if goalsItem.IsAutomatable != nil { + goalsMap["is_automatable"] = goalsItem.IsAutomatable + } + if goalsItem.IsAutoRemediable != nil { + goalsMap["is_auto_remediable"] = goalsItem.IsAutoRemediable + } + + return goalsMap +} + +func dataSourceControlListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_group_profile_test.go b/ibm/service/scc/data_source_ibm_scc_posture_group_profile_test.go new file mode 100644 index 000000000..f01bf5d3e --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_group_profile_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureGroupProfileDetailsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureGroupProfileDetailsDataSourceConfigBasic(acc.Scc_posture_group_profile_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_group_profile.group_profile_details", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_group_profile.group_profile_details", "profile_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureGroupProfileDetailsDataSourceConfigBasic(groupprofileId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_group_profile" "group_profile_details" { + profile_id = "%s" + } + `, groupprofileId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_latest_scans.go b/ibm/service/scc/data_source_ibm_scc_posture_latest_scans.go new file mode 100644 index 000000000..5cc84325e --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_latest_scans.go @@ -0,0 +1,508 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "net/url" + "reflect" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureLatestScans() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureListLatestScansRead, + + Schema: map[string]*schema.Schema{ + "scan_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the scan.", + }, + "first": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "latest_scans": { + Type: schema.TypeList, + Computed: true, + Description: "The details of a scan.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scan_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scan.", + }, + "scan_name": { + Type: schema.TypeString, + Computed: true, + Description: "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The scope ID of the scan.", + }, + "scope_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope.", + }, + "profiles": { + Type: schema.TypeList, + Computed: true, + Description: "Profiles array.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the profile.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "An auto-generated unique identifier for the scope.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile.", + }, + }, + }, + }, + "group_profile_id": { + Type: schema.TypeString, + Computed: true, + Description: "The group ID of profile.", + }, + "group_profile_name": { + Type: schema.TypeString, + Computed: true, + Description: "The group name of the profile.", + }, + "report_run_by": { + Type: schema.TypeString, + Computed: true, + Description: "The entity that ran the report.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time the scan was run.", + }, + "report_setting_id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique ID for Scan that is created.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time the scan completed.", + }, + "result": { + Type: schema.TypeList, + Computed: true, + Description: "The result of a scan.The above values will not be avaialble if no scopes are available.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "goals_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that passed the scan.", + }, + "goals_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "goals_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "goals_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that failed the scan.", + }, + "goals_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of goals that were included in the scan.", + }, + "controls_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that passed the scan.", + }, + "controls_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that failed the scan.", + }, + "controls_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "controls_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "controls_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of controls that were included in the scan.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureListLatestScansRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + listLatestScansOptions := &posturemanagementv2.ListLatestScansOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + listLatestScansOptions.SetAccountID(accountID) + + var scanList *posturemanagementv2.ScanList + var offset int64 + finalList := []posturemanagementv2.ScanItem{} + var scanID string + var suppliedFilter bool + + if v, ok := d.GetOk("scan_id"); ok { + scanID = v.(string) + suppliedFilter = true + } + + for { + listLatestScansOptions.Offset = &offset + + listLatestScansOptions.Limit = core.Int64Ptr(int64(100)) + result, response, err := postureManagementClient.ListLatestScansWithContext(context, listLatestScansOptions) + scanList = result + if err != nil { + log.Printf("[DEBUG] ListLatestScansWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLatestScansWithContext failed %s\n%s", err, response)) + } + offset = dataSourceScanListGetNext(result.Next) + if suppliedFilter { + for _, data := range result.LatestScans { + if *data.ScanID == scanID { + finalList = append(finalList, data) + } + } + } else { + finalList = append(finalList, result.LatestScans...) + } + if offset == 0 { + break + } + } + + scanList.LatestScans = finalList + + if suppliedFilter { + if len(scanList.LatestScans) == 0 { + return diag.FromErr(fmt.Errorf("no LatestScans found with scanID %s", scanID)) + } + d.SetId(scanID) + } else { + d.SetId(dataSourceIBMListLatestScansID(d)) + } + + if scanList.First != nil { + err = d.Set("first", dataSourceScanListFlattenFirst(*scanList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting first %s", err)) + } + } + + if scanList.Last != nil { + err = d.Set("last", dataSourceScanListFlattenLast(*scanList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last %s", err)) + } + } + + if scanList.Previous != nil { + err = d.Set("previous", dataSourceScanListFlattenPrevious(*scanList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting previous %s", err)) + } + } + + if scanList.LatestScans != nil { + err = d.Set("latest_scans", dataSourceScanListFlattenLatestScans(scanList.LatestScans)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting latest_scans %s", err)) + } + } + + return nil +} + +// dataSourceIBMListLatestScansID returns a reasonable ID for the list. +func dataSourceIBMListLatestScansID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceScanListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScanListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScanListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceScanListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScanListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScanListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceScanListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScanListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScanListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceScanListFlattenLatestScans(result []posturemanagementv2.ScanItem) (latestScans []map[string]interface{}) { + for _, latestScansItem := range result { + latestScans = append(latestScans, dataSourceScanListLatestScansToMap(latestScansItem)) + } + + return latestScans +} + +func dataSourceScanListLatestScansToMap(latestScansItem posturemanagementv2.ScanItem) (latestScansMap map[string]interface{}) { + latestScansMap = map[string]interface{}{} + + if latestScansItem.ScanID != nil { + latestScansMap["scan_id"] = latestScansItem.ScanID + } + if latestScansItem.ScanName != nil { + latestScansMap["scan_name"] = latestScansItem.ScanName + } + if latestScansItem.ScopeID != nil { + latestScansMap["scope_id"] = latestScansItem.ScopeID + } + if latestScansItem.ScopeName != nil { + latestScansMap["scope_name"] = latestScansItem.ScopeName + } + if latestScansItem.Profiles != nil { + profilesList := []map[string]interface{}{} + for _, profilesItem := range latestScansItem.Profiles { + profilesList = append(profilesList, dataSourceScanListLatestScansProfilesToMap(profilesItem)) + } + latestScansMap["profiles"] = profilesList + } + if latestScansItem.GroupProfileID != nil { + latestScansMap["group_profile_id"] = latestScansItem.GroupProfileID + } + if latestScansItem.GroupProfileName != nil { + latestScansMap["group_profile_name"] = latestScansItem.GroupProfileName + } + if latestScansItem.ReportRunBy != nil { + latestScansMap["report_run_by"] = latestScansItem.ReportRunBy + } + if latestScansItem.StartTime != nil { + latestScansMap["start_time"] = latestScansItem.StartTime.String() + } + if latestScansItem.ReportSettingID != nil { + latestScansMap["report_setting_id"] = latestScansItem.ReportSettingID + } + if latestScansItem.EndTime != nil { + latestScansMap["end_time"] = latestScansItem.EndTime.String() + } + if latestScansItem.Result != nil { + resultList := []map[string]interface{}{} + resultMap := dataSourceScanListLatestScansResultToMap(*latestScansItem.Result) + resultList = append(resultList, resultMap) + latestScansMap["result"] = resultList + } + + return latestScansMap +} + +func dataSourceScanListLatestScansProfilesToMap(profilesItem posturemanagementv2.ProfileItem) (profilesMap map[string]interface{}) { + profilesMap = map[string]interface{}{} + + if profilesItem.Name != nil { + profilesMap["name"] = profilesItem.Name + } + if profilesItem.ID != nil { + profilesMap["id"] = profilesItem.ID + } + if profilesItem.Type != nil { + profilesMap["type"] = profilesItem.Type + } + + return profilesMap +} + +func dataSourceScanListLatestScansResultToMap(resultItem posturemanagementv2.ScanResult) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if resultItem.GoalsPassCount != nil { + resultMap["goals_pass_count"] = resultItem.GoalsPassCount + } + if resultItem.GoalsUnableToPerformCount != nil { + resultMap["goals_unable_to_perform_count"] = resultItem.GoalsUnableToPerformCount + } + if resultItem.GoalsNotApplicableCount != nil { + resultMap["goals_not_applicable_count"] = resultItem.GoalsNotApplicableCount + } + if resultItem.GoalsFailCount != nil { + resultMap["goals_fail_count"] = resultItem.GoalsFailCount + } + if resultItem.GoalsTotalCount != nil { + resultMap["goals_total_count"] = resultItem.GoalsTotalCount + } + if resultItem.ControlsPassCount != nil { + resultMap["controls_pass_count"] = resultItem.ControlsPassCount + } + if resultItem.ControlsFailCount != nil { + resultMap["controls_fail_count"] = resultItem.ControlsFailCount + } + if resultItem.ControlsNotApplicableCount != nil { + resultMap["controls_not_applicable_count"] = resultItem.ControlsNotApplicableCount + } + if resultItem.ControlsUnableToPerformCount != nil { + resultMap["controls_unable_to_perform_count"] = resultItem.ControlsUnableToPerformCount + } + if resultItem.ControlsTotalCount != nil { + resultMap["controls_total_count"] = resultItem.ControlsTotalCount + } + + return resultMap +} + +func dataSourceScanListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_latest_scans_test.go b/ibm/service/scc/data_source_ibm_scc_posture_latest_scans_test.go new file mode 100644 index 000000000..6094b497d --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_latest_scans_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureListLatestScansDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureListLatestScansDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_latest_scans.list_latest_scans", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_latest_scans.list_latest_scans", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_latest_scans.list_latest_scans", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_latest_scans.list_latest_scans", "latest_scans.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureListLatestScansDataSourceConfigBasic() string { + return ` + data "ibm_scc_posture_latest_scans" "list_latest_scans" { + } + ` +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_profile.go b/ibm/service/scc/data_source_ibm_scc_posture_profile.go new file mode 100644 index 000000000..d004b0a1f --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_profile.go @@ -0,0 +1,161 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureProfileDetails() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureProfileDetailsRead, + + Schema: map[string]*schema.Schema{ + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "The id for the given API.", + }, + "profile_type": { + Type: schema.TypeString, + Required: true, + Description: "The profile type ID. This will be 4 for profiles and 6 for group profiles.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the profile.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "A description of the profile.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "The version of the profile.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who created the profile.", + }, + "modified_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who last modified the profile.", + }, + "reason_for_delete": { + Type: schema.TypeString, + Computed: true, + Description: "A reason that you want to delete a profile.", + }, + "base_profile": { + Type: schema.TypeString, + Computed: true, + Description: "The base profile that the controls are pulled from.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile.", + }, + "no_of_controls": { + Type: schema.TypeInt, + Computed: true, + Description: "no of Controls.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was created in UTC.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was most recently modified in UTC.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + }, + }, + } +} + +func dataSourceIBMSccPostureProfileDetailsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getProfileOptions := &posturemanagementv2.GetProfileOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getProfileOptions.SetAccountID(accountID) + + getProfileOptions.SetID(d.Get("profile_id").(string)) + getProfileOptions.SetProfileType(d.Get("profile_type").(string)) + + profile, response, err := postureManagementClient.GetProfileWithContext(context, getProfileOptions) + if err != nil { + log.Printf("[DEBUG] GetProfileWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetProfileWithContext failed %s\n%s", err, response)) + } + + d.SetId(*profile.ID) + if err = d.Set("name", profile.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", profile.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("version", flex.IntValue(profile.Version)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + if err = d.Set("created_by", profile.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("modified_by", profile.ModifiedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_by: %s", err)) + } + if err = d.Set("reason_for_delete", profile.ReasonForDelete); err != nil { + return nil //return diag.FromErr(fmt.Errorf("[ERROR] Error setting reason_for_delete: %s", err)) + } + if err = d.Set("base_profile", profile.BaseProfile); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting base_profile: %s", err)) + } + if err = d.Set("type", profile.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("no_of_controls", flex.IntValue(profile.NoOfControls)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting no_of_controls: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(profile.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(profile.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("enabled", profile.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enabled: %s", err)) + } + + return nil +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_profile_test.go b/ibm/service/scc/data_source_ibm_scc_posture_profile_test.go new file mode 100644 index 000000000..c4017fe45 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_profile_test.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureProfileDetailsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureProfileDetailsDataSourceConfigBasic(acc.Scc_posture_profile_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "profile_type"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "name"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "version"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "created_by"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "modified_by"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "base_profile"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "type"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "no_of_controls"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profile.profile_details", "enabled"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureProfileDetailsDataSourceConfigBasic(profileId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_profile" "profile_details" { + profile_id = "%s" + profile_type = "authored" + } + `, profileId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_profiles.go b/ibm/service/scc/data_source_ibm_scc_posture_profiles.go new file mode 100644 index 000000000..4453c2793 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_profiles.go @@ -0,0 +1,356 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "net/url" + "reflect" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureListProfilesRead, + + Schema: map[string]*schema.Schema{ + "first": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "profiles": { + Type: schema.TypeList, + Computed: true, + Description: "Profiles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the profile.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "A description of the profile.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "The version of the profile.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who created the profile.", + }, + "modified_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who last modified the profile.", + }, + "reason_for_delete": { + Type: schema.TypeString, + Computed: true, + Description: "A reason that you want to delete a profile.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "An auto-generated unique identifying number of the profile.", + }, + "base_profile": { + Type: schema.TypeString, + Computed: true, + Description: "The base profile that the controls are pulled from.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile.", + }, + "no_of_controls": { + Type: schema.TypeInt, + Computed: true, + Description: "no of Controls.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was created in UTC.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was most recently modified in UTC.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureListProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + listProfilesOptions := &posturemanagementv2.ListProfilesOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + listProfilesOptions.SetAccountID(accountID) + + var profileList *posturemanagementv2.ProfileList + var offset int64 + finalList := []posturemanagementv2.Profile{} + + for { + listProfilesOptions.Offset = &offset + + listProfilesOptions.Limit = core.Int64Ptr(int64(100)) + result, response, err := postureManagementClient.ListProfilesWithContext(context, listProfilesOptions) + profileList = result + if err != nil { + log.Printf("[DEBUG] ListProfilesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListProfilesWithContext failed %s\n%s", err, response)) + } + offset = dataSourceProfileListGetNext(result.Next) + finalList = append(finalList, result.Profiles...) + if offset == 0 { + break + } + } + + profileList.Profiles = finalList + + d.SetId(dataSourceIBMSccPostureListProfilesID(d)) + + if profileList.First != nil { + err = d.Set("first", dataSourceProfileListFlattenFirst(*profileList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting first %s", err)) + } + } + + if profileList.Last != nil { + err = d.Set("last", dataSourceProfileListFlattenLast(*profileList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last %s", err)) + } + } + + if profileList.Previous != nil { + err = d.Set("previous", dataSourceProfileListFlattenPrevious(*profileList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting previous %s", err)) + } + } + + if profileList.Profiles != nil { + err = d.Set("profiles", dataSourceProfileListFlattenProfiles(profileList.Profiles)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profiles %s", err)) + } + } + + return nil +} + +// dataSourceIBMListProfilesID returns a reasonable ID for the list. +func dataSourceIBMSccPostureListProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceProfileListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceProfileListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceProfileListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceProfileListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceProfileListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceProfileListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceProfileListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceProfileListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceProfileListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceProfileListFlattenProfiles(result []posturemanagementv2.Profile) (profiles []map[string]interface{}) { + for _, profilesItem := range result { + profiles = append(profiles, dataSourceProfileListProfilesToMap(profilesItem)) + } + + return profiles +} + +func dataSourceProfileListProfilesToMap(profilesItem posturemanagementv2.Profile) (profilesMap map[string]interface{}) { + profilesMap = map[string]interface{}{} + + if profilesItem.Name != nil { + profilesMap["name"] = profilesItem.Name + } + if profilesItem.Description != nil { + profilesMap["description"] = profilesItem.Description + } + if profilesItem.Version != nil { + profilesMap["version"] = profilesItem.Version + } + if profilesItem.CreatedBy != nil { + profilesMap["created_by"] = profilesItem.CreatedBy + } + if profilesItem.ModifiedBy != nil { + profilesMap["modified_by"] = profilesItem.ModifiedBy + } + if profilesItem.ReasonForDelete != nil { + profilesMap["reason_for_delete"] = profilesItem.ReasonForDelete + } + if profilesItem.ID != nil { + profilesMap["id"] = profilesItem.ID + } + if profilesItem.BaseProfile != nil { + profilesMap["base_profile"] = profilesItem.BaseProfile + } + if profilesItem.Type != nil { + profilesMap["type"] = profilesItem.Type + } + if profilesItem.NoOfControls != nil { + profilesMap["no_of_controls"] = profilesItem.NoOfControls + } + if profilesItem.CreatedAt != nil { + profilesMap["created_at"] = profilesItem.CreatedAt.String() + } + if profilesItem.UpdatedAt != nil { + profilesMap["updated_at"] = profilesItem.UpdatedAt.String() + } + if profilesItem.Enabled != nil { + profilesMap["enabled"] = profilesItem.Enabled + } + + return profilesMap +} + +func dataSourceProfileListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_profiles_test.go b/ibm/service/scc/data_source_ibm_scc_posture_profiles_test.go new file mode 100644 index 000000000..e7e3d2e03 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_profiles_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureListProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureListProfilesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profiles.list_profiles", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profiles.list_profiles", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profiles.list_profiles", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_profiles.list_profiles", "profiles.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureListProfilesDataSourceConfigBasic() string { + return ` + data "ibm_scc_posture_profiles" "list_profiles" { + } + ` +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries.go b/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries.go new file mode 100644 index 000000000..64645aea8 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries.go @@ -0,0 +1,621 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "net/url" + "reflect" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureScanSummaries() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureScanSummariesRead, + + Schema: map[string]*schema.Schema{ + "report_setting_id": { + Type: schema.TypeString, + Required: true, + Description: "The report setting ID. This can be obtained from the /validations/latest_scans API call.", + }, + "first": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "summaries": { + Type: schema.TypeList, + Computed: true, + Description: "Summaries.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scan.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the scope.", + }, + "scope_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the scope.", + }, + "report_run_by": { + Type: schema.TypeString, + Computed: true, + Description: "The entity that ran the report.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time the scan was run.", + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time the scan completed.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the collector as it completes a scan.", + }, + "profiles": { + Type: schema.TypeList, + Computed: true, + Description: "The list of profiles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the profile.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the profile.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", + }, + "validation_result": { + Type: schema.TypeList, + Computed: true, + Description: "The result of a scan.The above values will not be avaialble if no scopes are available.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "goals_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that passed the scan.", + }, + "goals_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "goals_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "goals_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that failed the scan.", + }, + "goals_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of goals that were included in the scan.", + }, + "controls_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that passed the scan.", + }, + "controls_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that failed the scan.", + }, + "controls_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "controls_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "controls_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of controls that were included in the scan.", + }, + }, + }, + }, + }, + }, + }, + "group_profiles": { + Type: schema.TypeList, + Computed: true, + Description: "The list of group profiles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the profile.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the profile.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", + }, + "validation_result": { + Type: schema.TypeList, + Computed: true, + Description: "The result of a scan.The above values will not be avaialble if no scopes are available.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "goals_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that passed the scan.", + }, + "goals_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "goals_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "goals_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of goals that failed the scan.", + }, + "goals_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of goals that were included in the scan.", + }, + "controls_pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that passed the scan.", + }, + "controls_fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that failed the scan.", + }, + "controls_not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + }, + "controls_unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + }, + "controls_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of controls that were included in the scan.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureScanSummariesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + scanSummariesOptions := &posturemanagementv2.ScanSummariesOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + scanSummariesOptions.SetAccountID(accountID) + + scanSummariesOptions.SetReportSettingID(d.Get("report_setting_id").(string)) + + var summaryList *posturemanagementv2.SummaryList + var offset int64 + finalList := []posturemanagementv2.SummaryItem{} + + for { + scanSummariesOptions.Offset = &offset + + scanSummariesOptions.Limit = core.Int64Ptr(int64(100)) + result, response, err := postureManagementClient.ScanSummariesWithContext(context, scanSummariesOptions) + summaryList = result + if err != nil { + log.Printf("[DEBUG] ScanSummariesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ScanSummariesWithContext failed %s\n%s", err, response)) + } + offset = dataSourceSummaryListGetNext(result.Next) + finalList = append(finalList, result.Summaries...) + if offset == 0 { + break + } + } + + summaryList.Summaries = finalList + + d.SetId(dataSourceIBMSccPostureScanSummariesID(d)) + + if summaryList.First != nil { + err = d.Set("first", dataSourceSummaryListFlattenFirst(*summaryList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting first %s", err)) + } + } + + if summaryList.Last != nil { + err = d.Set("last", dataSourceSummaryListFlattenLast(*summaryList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last %s", err)) + } + } + + if summaryList.Previous != nil { + err = d.Set("previous", dataSourceSummaryListFlattenPrevious(*summaryList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting previous %s", err)) + } + } + + if summaryList.Summaries != nil { + err = d.Set("summaries", dataSourceSummaryListFlattenSummaries(summaryList.Summaries)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting summaries %s", err)) + } + } + + return nil +} + +// dataSourceIBMScanSummariesID returns a reasonable ID for the list. +func dataSourceIBMSccPostureScanSummariesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceSummaryListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceSummaryListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceSummaryListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceSummaryListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceSummaryListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceSummaryListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceSummaryListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceSummaryListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceSummaryListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceSummaryListFlattenSummaries(result []posturemanagementv2.SummaryItem) (summaries []map[string]interface{}) { + for _, summariesItem := range result { + summaries = append(summaries, dataSourceSummaryListSummariesToMap(summariesItem)) + } + + return summaries +} + +func dataSourceSummaryListSummariesToMap(summariesItem posturemanagementv2.SummaryItem) (summariesMap map[string]interface{}) { + summariesMap = map[string]interface{}{} + + if summariesItem.ID != nil { + summariesMap["id"] = summariesItem.ID + } + if summariesItem.Name != nil { + summariesMap["name"] = summariesItem.Name + } + if summariesItem.ScopeID != nil { + summariesMap["scope_id"] = summariesItem.ScopeID + } + if summariesItem.ScopeName != nil { + summariesMap["scope_name"] = summariesItem.ScopeName + } + if summariesItem.ReportRunBy != nil { + summariesMap["report_run_by"] = summariesItem.ReportRunBy + } + if summariesItem.StartTime != nil { + summariesMap["start_time"] = summariesItem.StartTime.String() + } + if summariesItem.EndTime != nil { + summariesMap["end_time"] = summariesItem.EndTime.String() + } + if summariesItem.Status != nil { + summariesMap["status"] = summariesItem.Status + } + if summariesItem.Profiles != nil { + profilesList := []map[string]interface{}{} + for _, profilesItem := range summariesItem.Profiles { + profilesList = append(profilesList, dataSourceSummaryListSummariesProfilesToMap(profilesItem)) + } + summariesMap["profiles"] = profilesList + } + if summariesItem.GroupProfiles != nil { + groupProfilesList := []map[string]interface{}{} + for _, groupProfilesItem := range summariesItem.GroupProfiles { + groupProfilesList = append(groupProfilesList, dataSourceSummaryListSummariesGroupProfilesToMap(groupProfilesItem)) + } + summariesMap["group_profiles"] = groupProfilesList + } + + return summariesMap +} + +func dataSourceSummaryListSummariesProfilesToMap(profilesItem posturemanagementv2.ProfileResult) (profilesMap map[string]interface{}) { + profilesMap = map[string]interface{}{} + + if profilesItem.ID != nil { + profilesMap["id"] = profilesItem.ID + } + if profilesItem.Name != nil { + profilesMap["name"] = profilesItem.Name + } + if profilesItem.Type != nil { + profilesMap["type"] = profilesItem.Type + } + if profilesItem.ValidationResult != nil { + validationResultList := []map[string]interface{}{} + validationResultMap := dataSourceSummaryListProfilesValidationResultToMap(*profilesItem.ValidationResult) + validationResultList = append(validationResultList, validationResultMap) + profilesMap["validation_result"] = validationResultList + } + + return profilesMap +} + +func dataSourceSummaryListProfilesValidationResultToMap(validationResultItem posturemanagementv2.ScanResult) (validationResultMap map[string]interface{}) { + validationResultMap = map[string]interface{}{} + + if validationResultItem.GoalsPassCount != nil { + validationResultMap["goals_pass_count"] = validationResultItem.GoalsPassCount + } + if validationResultItem.GoalsUnableToPerformCount != nil { + validationResultMap["goals_unable_to_perform_count"] = validationResultItem.GoalsUnableToPerformCount + } + if validationResultItem.GoalsNotApplicableCount != nil { + validationResultMap["goals_not_applicable_count"] = validationResultItem.GoalsNotApplicableCount + } + if validationResultItem.GoalsFailCount != nil { + validationResultMap["goals_fail_count"] = validationResultItem.GoalsFailCount + } + if validationResultItem.GoalsTotalCount != nil { + validationResultMap["goals_total_count"] = validationResultItem.GoalsTotalCount + } + if validationResultItem.ControlsPassCount != nil { + validationResultMap["controls_pass_count"] = validationResultItem.ControlsPassCount + } + if validationResultItem.ControlsFailCount != nil { + validationResultMap["controls_fail_count"] = validationResultItem.ControlsFailCount + } + if validationResultItem.ControlsNotApplicableCount != nil { + validationResultMap["controls_not_applicable_count"] = validationResultItem.ControlsNotApplicableCount + } + if validationResultItem.ControlsUnableToPerformCount != nil { + validationResultMap["controls_unable_to_perform_count"] = validationResultItem.ControlsUnableToPerformCount + } + if validationResultItem.ControlsTotalCount != nil { + validationResultMap["controls_total_count"] = validationResultItem.ControlsTotalCount + } + + return validationResultMap +} + +func dataSourceSummaryListSummariesGroupProfilesToMap(groupProfilesItem posturemanagementv2.ProfileResult) (groupProfilesMap map[string]interface{}) { + groupProfilesMap = map[string]interface{}{} + + if groupProfilesItem.ID != nil { + groupProfilesMap["id"] = groupProfilesItem.ID + } + if groupProfilesItem.Name != nil { + groupProfilesMap["name"] = groupProfilesItem.Name + } + if groupProfilesItem.Type != nil { + groupProfilesMap["type"] = groupProfilesItem.Type + } + if groupProfilesItem.ValidationResult != nil { + validationResultList := []map[string]interface{}{} + validationResultMap := dataSourceSummaryListGroupProfilesValidationResultToMap(*groupProfilesItem.ValidationResult) + validationResultList = append(validationResultList, validationResultMap) + groupProfilesMap["validation_result"] = validationResultList + } + + return groupProfilesMap +} + +func dataSourceSummaryListGroupProfilesValidationResultToMap(validationResultItem posturemanagementv2.ScanResult) (validationResultMap map[string]interface{}) { + validationResultMap = map[string]interface{}{} + + if validationResultItem.GoalsPassCount != nil { + validationResultMap["goals_pass_count"] = validationResultItem.GoalsPassCount + } + if validationResultItem.GoalsUnableToPerformCount != nil { + validationResultMap["goals_unable_to_perform_count"] = validationResultItem.GoalsUnableToPerformCount + } + if validationResultItem.GoalsNotApplicableCount != nil { + validationResultMap["goals_not_applicable_count"] = validationResultItem.GoalsNotApplicableCount + } + if validationResultItem.GoalsFailCount != nil { + validationResultMap["goals_fail_count"] = validationResultItem.GoalsFailCount + } + if validationResultItem.GoalsTotalCount != nil { + validationResultMap["goals_total_count"] = validationResultItem.GoalsTotalCount + } + if validationResultItem.ControlsPassCount != nil { + validationResultMap["controls_pass_count"] = validationResultItem.ControlsPassCount + } + if validationResultItem.ControlsFailCount != nil { + validationResultMap["controls_fail_count"] = validationResultItem.ControlsFailCount + } + if validationResultItem.ControlsNotApplicableCount != nil { + validationResultMap["controls_not_applicable_count"] = validationResultItem.ControlsNotApplicableCount + } + if validationResultItem.ControlsUnableToPerformCount != nil { + validationResultMap["controls_unable_to_perform_count"] = validationResultItem.ControlsUnableToPerformCount + } + if validationResultItem.ControlsTotalCount != nil { + validationResultMap["controls_total_count"] = validationResultItem.ControlsTotalCount + } + + return validationResultMap +} + +func dataSourceSummaryListGetNext(next interface{}) int64 { + if reflect.ValueOf(next).IsNil() { + return 0 + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return 0 + } + + q := u.Query() + var page string + + if q.Get("start") != "" { + page = q.Get("start") + } else if q.Get("offset") != "" { + page = q.Get("offset") + } + + convertedVal, err := strconv.ParseInt(page, 10, 64) + if err != nil { + return 0 + } + return convertedVal +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries_test.go b/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries_test.go new file mode 100644 index 000000000..675de220c --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scan_summaries_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureScanSummariesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureScanSummariesDataSourceConfigBasic(acc.Scc_posture_report_setting_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "report_setting_id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summaries.scan_summaries", "summaries.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureScanSummariesDataSourceConfigBasic(report_setting_id string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_scan_summaries" "scan_summaries" { + report_setting_id = "%s" + } + `, report_setting_id) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scan_summary.go b/ibm/service/scc/data_source_ibm_scc_posture_scan_summary.go new file mode 100644 index 000000000..b112e65d7 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scan_summary.go @@ -0,0 +1,356 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureScansSummary() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureScansSummaryRead, + + Schema: map[string]*schema.Schema{ + "scan_id": { + Type: schema.TypeString, + Required: true, + Description: "Your Scan ID.", + }, + "profile_id": { + Type: schema.TypeString, + Required: true, + Description: "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", + }, + "discover_id": { + Type: schema.TypeString, + Computed: true, + Description: "The scan discovery ID.", + }, + "profile_name": { + Type: schema.TypeString, + Computed: true, + Description: "The scan profile name.", + }, + "scope_id": { + Type: schema.TypeString, + Computed: true, + Description: "The scan summary scope ID.", + }, + "controls": { + Type: schema.TypeList, + Computed: true, + Description: "The list of controls on the scan summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The scan summary control ID.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The control status.", + }, + "external_control_id": { + Type: schema.TypeString, + Computed: true, + Description: "The external control ID.", + }, + "desciption": { + Type: schema.TypeString, + Computed: true, + Description: "The scan profile name.", + }, + "goals": { + Type: schema.TypeList, + Computed: true, + Description: "The list of goals on the control.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the goal.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The goal ID.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The goal status.", + }, + "severity": { + Type: schema.TypeString, + Computed: true, + Description: "The severity of the goal.", + }, + "completed_time": { + Type: schema.TypeString, + Computed: true, + Description: "The report completed time.", + }, + "error": { + Type: schema.TypeString, + Computed: true, + Description: "The error on goal validation.", + }, + "resource_result": { + Type: schema.TypeList, + Computed: true, + Description: "The list of resource results.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The resource name.", + }, + "types": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The resource control result status.", + }, + "display_expected_value": { + Type: schema.TypeString, + Computed: true, + Description: "The expected results of a resource.", + }, + "actual_value": { + Type: schema.TypeString, + Computed: true, + Description: "The actual results of a resource.", + }, + "results_info": { + Type: schema.TypeString, + Computed: true, + Description: "The results information.", + }, + "not_applicable_reason": { + Type: schema.TypeString, + Computed: true, + Description: "The reason for goal not applicable for a resource.", + }, + }, + }, + }, + }, + }, + }, + "resource_statistics": { + Type: schema.TypeList, + Computed: true, + Description: "A scans summary controls.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "pass_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The resource count of pass controls.", + }, + "fail_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The resource count of fail controls.", + }, + "unable_to_perform_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of resources that were unable to be scanned against a control.", + }, + "not_applicable_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The resource count of not applicable(na) controls.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureScansSummaryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + scansSummaryOptions := &posturemanagementv2.ScansSummaryOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + scansSummaryOptions.SetAccountID(accountID) + + scansSummaryOptions.SetScanID(d.Get("scan_id").(string)) + scansSummaryOptions.SetProfileID(d.Get("profile_id").(string)) + + summary, response, err := postureManagementClient.ScansSummaryWithContext(context, scansSummaryOptions) + if err != nil { + log.Printf("[DEBUG] ScansSummaryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ScansSummaryWithContext failed %s\n%s", err, response)) + } + + d.SetId(*summary.ID) + + if err = d.Set("discover_id", summary.DiscoverID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting discover_id: %s", err)) + } + if err = d.Set("profile_name", summary.ProfileName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile_name: %s", err)) + } + if err = d.Set("scope_id", summary.ScopeID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting scope_id: %s", err)) + } + + if summary.Controls != nil { + err = d.Set("controls", dataSourceSummaryFlattenControlsv2(summary.Controls)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting controls %s", err)) + } + } + + return nil +} + +func dataSourceSummaryFlattenControlsv2(result []posturemanagementv2.Control) (controls []map[string]interface{}) { + for _, controlsItem := range result { + controls = append(controls, dataSourceSummaryControlsToMapv2(controlsItem)) + } + + return controls +} + +func dataSourceSummaryControlsToMapv2(controlsItem posturemanagementv2.Control) (controlsMap map[string]interface{}) { + controlsMap = map[string]interface{}{} + + if controlsItem.ID != nil { + controlsMap["id"] = controlsItem.ID + } + if controlsItem.Status != nil { + controlsMap["status"] = controlsItem.Status + } + if controlsItem.ExternalControlID != nil { + controlsMap["external_control_id"] = controlsItem.ExternalControlID + } + if controlsItem.Description != nil { + controlsMap["description"] = controlsItem.Description + } + if controlsItem.Goals != nil { + goalsList := []map[string]interface{}{} + for _, goalsItem := range controlsItem.Goals { + goalsList = append(goalsList, dataSourceSummaryControlsGoalsToMapv2(goalsItem)) + } + controlsMap["goals"] = goalsList + } + if controlsItem.ResourceStatistics != nil { + resourceStatisticsList := []map[string]interface{}{} + resourceStatisticsMap := dataSourceSummaryControlsResourceStatisticsToMapv2(*controlsItem.ResourceStatistics) + resourceStatisticsList = append(resourceStatisticsList, resourceStatisticsMap) + controlsMap["resource_statistics"] = resourceStatisticsList + } + + return controlsMap +} + +func dataSourceSummaryControlsGoalsToMapv2(goalsItem posturemanagementv2.Goal) (goalsMap map[string]interface{}) { + goalsMap = map[string]interface{}{} + + if goalsItem.Description != nil { + goalsMap["description"] = goalsItem.Description + } + if goalsItem.ID != nil { + goalsMap["id"] = goalsItem.ID + } + if goalsItem.Status != nil { + goalsMap["status"] = goalsItem.Status + } + if goalsItem.Severity != nil { + goalsMap["severity"] = goalsItem.Severity + } + if goalsItem.CompletedTime != nil { + goalsMap["completed_time"] = goalsItem.CompletedTime.String() + } + if goalsItem.Error != nil { + goalsMap["error"] = goalsItem.Error + } + if goalsItem.ResourceResult != nil { + resourceResultList := []map[string]interface{}{} + for _, resourceResultItem := range goalsItem.ResourceResult { + resourceResultList = append(resourceResultList, dataSourceSummaryGoalsResourceResultToMapv2(resourceResultItem)) + } + goalsMap["resource_result"] = resourceResultList + } + + return goalsMap +} + +func dataSourceSummaryGoalsResourceResultToMapv2(resourceResultItem posturemanagementv2.ResourceResult) (resourceResultMap map[string]interface{}) { + resourceResultMap = map[string]interface{}{} + + if resourceResultItem.Name != nil { + resourceResultMap["name"] = resourceResultItem.Name + } + if resourceResultItem.Types != nil { + resourceResultMap["types"] = resourceResultItem.Types + } + if resourceResultItem.Status != nil { + resourceResultMap["status"] = resourceResultItem.Status + } + if resourceResultItem.DisplayExpectedValue != nil { + resourceResultMap["display_expected_value"] = resourceResultItem.DisplayExpectedValue + } + if resourceResultItem.ActualValue != nil { + resourceResultMap["actual_value"] = resourceResultItem.ActualValue + } + if resourceResultItem.ResultsInfo != nil { + resourceResultMap["results_info"] = resourceResultItem.ResultsInfo + } + if resourceResultItem.NotApplicableReason != nil { + resourceResultMap["not_applicable_reason"] = resourceResultItem.NotApplicableReason + } + + return resourceResultMap +} + +func dataSourceSummaryControlsResourceStatisticsToMapv2(resourceStatisticsItem posturemanagementv2.ResourceStatistics) (resourceStatisticsMap map[string]interface{}) { + resourceStatisticsMap = map[string]interface{}{} + + if resourceStatisticsItem.PassCount != nil { + resourceStatisticsMap["pass_count"] = resourceStatisticsItem.PassCount + } + if resourceStatisticsItem.FailCount != nil { + resourceStatisticsMap["fail_count"] = resourceStatisticsItem.FailCount + } + if resourceStatisticsItem.UnableToPerformCount != nil { + resourceStatisticsMap["unable_to_perform_count"] = resourceStatisticsItem.UnableToPerformCount + } + if resourceStatisticsItem.NotApplicableCount != nil { + resourceStatisticsMap["not_applicable_count"] = resourceStatisticsItem.NotApplicableCount + } + + return resourceStatisticsMap +} diff --git a/ibm/data_source_ibm_scc_posture_scan_summary_test.go b/ibm/service/scc/data_source_ibm_scc_posture_scan_summary_test.go similarity index 80% rename from ibm/data_source_ibm_scc_posture_scan_summary_test.go rename to ibm/service/scc/data_source_ibm_scc_posture_scan_summary_test.go index da2bbe2e5..6686df68b 100644 --- a/ibm/data_source_ibm_scc_posture_scan_summary_test.go +++ b/ibm/service/scc/data_source_ibm_scc_posture_scan_summary_test.go @@ -1,22 +1,24 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package scc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMSccPostureScansSummaryDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSccPostureScansSummaryDataSourceConfigBasic(scc_posture_scan_id, scc_posture_profile_id), + { + Config: testAccCheckIBMSccPostureScansSummaryDataSourceConfigBasic(acc.Scc_posture_scan_id_scansummary, acc.Scc_posture_profile_id_scansummary), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summary.scans_summary", "id"), resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scan_summary.scans_summary", "scan_id"), diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scope.go b/ibm/service/scc/data_source_ibm_scc_posture_scope.go new file mode 100644 index 000000000..8f18e609b --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scope.go @@ -0,0 +1,1427 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureScope() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureScopeRead, + + Schema: map[string]*schema.Schema{ + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The id for the given API.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_name .", + }, + "uuid": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_uuid .Will be displayed only when value exists.", + }, + "partner_uuid": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of partner_uuid .Will be displayed only when value exists.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_description .Will be displayed only when value exists.", + }, + "org_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_org_id .Will be displayed only when value exists.", + }, + "cloud_type_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_cloud_type_id .Will be displayed only when value exists.", + }, + "tld_credential_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_tld_credential_id .Will be displayed only when value exists.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_status .Will be displayed only when value exists.", + }, + "status_msg": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_status_msg .Will be displayed only when value exists.", + }, + "subset_selected": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_subset_selected .Will be displayed only when value exists.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_enabled .Will be displayed only when value exists.", + }, + "last_discover_start_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_last_discover_start_time .Will be displayed only when value exists.", + }, + "last_discover_completed_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_last_discover_completed_time .Will be displayed only when value exists.", + }, + "last_successful_discover_start_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_last_successful_discover_start_time .Will be displayed only when value exists.", + }, + "last_successful_discover_completed_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_last_successful_discover_completed_time .Will be displayed only when value exists.", + }, + "task_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_task_type .Will be displayed only when value exists.", + }, + "tasks": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of scope_tasks .Will be displayed only when value exists.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "task_logs": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of task_logs .", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "task_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_id .", + }, + "task_gateway_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_gateway_id .", + }, + "task_gateway_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_gateway_name .", + }, + "task_task_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_task_type .", + }, + "task_gateway_schema_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_gateway_schema_id .", + }, + "task_schema_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_schema_name .", + }, + "task_discover_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_discover_id .", + }, + "task_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_status .", + }, + "task_status_msg": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_status_msg .", + }, + "task_start_time": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_start_time .", + }, + "task_updated_time": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of task_updated_time .", + }, + "task_derived_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_derived_status .", + }, + "task_created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of task_created_by .", + }, + }, + }, + }, + "status_updated_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_status_updated_time .Will be displayed only when value exists.", + }, + "collectors_by_type": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of collectors_by_type .Will be displayed only when value exists.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "credentials_by_type": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_credentials_by_type .Will be displayed only when value exists.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "credentials_by_sub_categeory_type": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_credentials_by_sub_categeory_type .Will be displayed only when value exists.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "sub_categories_by_type": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_sub_categories_by_type .Will be displayed only when value exists.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "resource_groups": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_resource_groups .Will be displayed only when value exists.", + }, + "region_names": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_region_names .Will be displayed only when value exists.", + }, + "cloud_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_cloud_type .Will be displayed only when value exists.", + }, + "env_sub_category": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_env_sub_category .Will be displayed only when value exists.", + }, + "tld_credentail": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of ScopeDetailsCredential .", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_id .", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_name .", + }, + "uuid": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_uuid .", + }, + "credential_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_type .", + }, + "data": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of credential_data .", + }, + "display_fields": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Details the fields on the credential. This will change as per credential type selected.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ibm_api_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + }, + "aws_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS client Id.This is mandatory for AWS Cloud.", + }, + "aws_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS client secret.This is mandatory for AWS Cloud.", + }, + "aws_region": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS region.", + }, + "aws_arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "AWS arn value.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "password": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + }, + "azure_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure client Id. This is mandatory for Azure Credential type.", + }, + "azure_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure client secret.This is mandatory for Azure Credential type.", + }, + "azure_subscription_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure subscription Id.This is mandatory for Azure Credential type.", + }, + "azure_resource_group": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Azure resource group.", + }, + "database_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Database name.This is mandatory for Database Credential type.", + }, + "winrm_authtype": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_usessl": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + }, + "winrm_port": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + }, + "ms_365_client_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_client_secret": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + }, + "ms_365_tenant_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + }, + "auth_url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "user_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "project_domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + }, + "pem_file_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the PEM file.", + }, + "pem_data": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The base64 encoded data to associate with the PEM file.", + }, + }, + }, + }, + "version_timestamp": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of credential_version_timestamp .", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_description .", + }, + "is_enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of credential_is_enabled .", + }, + "gateway_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_gateway_key .", + }, + "credential_group": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of credential_credential_group .", + }, + "enabled_credential_group": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of credential_enabled_credential_group .", + }, + "groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of credential_groups .", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credential_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "credential group id.", + }, + "passphrase": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "passphase of the credential.", + }, + }, + }, + }, + "purpose": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of credential_purpose .", + }, + }, + }, + }, + "collectors": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of collectors .Will be displayed only when value exists.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collector_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the collector.", + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-friendly name of the collector.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the collector.", + }, + "public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + }, + "last_heartbeat": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of collector.", + }, + "collector_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector version. This field is populated when collector is installed.", + }, + "image_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The image version of the collector. This field is populated when collector is installed. \".", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the collector.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that created the collector.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was created.", + }, + "updated_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that modified the collector.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was modified.", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Identifies whether the collector is enabled or not(deleted).", + }, + "registration_code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of the collector.", + }, + "credential_public_key": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The credential public key.", + }, + "failure_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of times the collector has failed.", + }, + "approved_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "approved_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "last_failed_local_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed local gateway ip. This field will be populated only when collector is installed.", + }, + "reset_reason": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + }, + "install_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + }, + "use_private_endpoint": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + }, + "managed_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The entity that manages the collector.", + }, + "trial_expiry": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + }, + "last_failed_internet_gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The failed internet gateway ip of the collector.", + }, + "status_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The collector status.", + }, + "reset_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + }, + "is_public": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + }, + "is_ubi_image": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector has a Ubi image.", + }, + }, + }, + }, + "first_level_scoped_data": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of scope_first_level_scoped_data .Will be displayed only when value exists.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scope_object": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_object .", + }, + "scope_init_scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_init_scope .", + }, + "scope": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope .", + }, + "scope_changed": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_changed .", + }, + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_id .", + }, + "scope_properties": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_properties .", + }, + "scope_overlay": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_overlay .", + }, + "scope_new_found": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_new_found .", + }, + "scope_discovery_status": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_discovery_status .", + }, + "scope_fact_status": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_fact_status .", + }, + "scope_facts": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_facts .", + }, + "scope_list_members": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_list_members .", + }, + "scope_children": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_children .", + }, + "scope_resource_category": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_resource_category .", + }, + "scope_resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_resource_type .", + }, + "scope_resource": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_resource .", + }, + "scope_resource_attributes": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_resource_attributes .", + }, + "scope_drift": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_drift .", + }, + "scope_parse_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_parse_status .", + }, + "scope_transformed_facts": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "Stores the value of scope_transformed_facts .", + }, + "scope_collector_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_collector_id .", + }, + }, + }, + }, + "discovery_methods": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of scope_discovery_methods .Will be displayed only when value exists.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "discovery_method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_discovery_method .Will be displayed only when value exists.", + }, + "file_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_file_type .Will be displayed only when value exists.", + }, + "file_format": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_file_format .Will be displayed only when value exists.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_created_by .Will be displayed only when value exists.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_created_on .Will be displayed only when value exists.", + }, + "modified_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_modified_by .Will be displayed only when value exists.", + }, + "modified_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_modified_on .Will be displayed only when value exists.", + }, + "is_discovery_scheduled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_is_discovery_scheduled .Will be displayed only when value exists.", + }, + "interval": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_freq .Will be displayed only when value exists.", + }, + "discovery_setting_id": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Stores the value of scope_discovery_setting_id .Will be displayed only when value exists.", + }, + "include_new_eagerly": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Stores the value of scope_include_new_eagerly .Will be displayed only when value exists.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_type .Will be displayed only when value exists.", + }, + "correlation_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation).", + }, + "credential_attributes": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_credential_attributes .Will be displayed only when value exists.", + }, + }, + } +} + +func dataSourceIBMSccPostureScopeRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + ScopeDetailsOptions := &posturemanagementv2.GetScopeDetailsOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + ScopeDetailsOptions.SetAccountID(accountID) + ScopeDetailsOptions.SetID(d.Get("scope_id").(string)) + + scope, response, err := postureManagementClient.GetScopeDetailsWithContext(context, ScopeDetailsOptions) + if err != nil { + log.Printf("[DEBUG] GetScopeDetailsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetScopeDetailsWithContext failed %s\n%s", err, response)) + } + + d.SetId(*scope.ID) + if err = d.Set("name", scope.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("uuid", scope.UUID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting uuid: %s", err)) + } + if err = d.Set("partner_uuid", scope.PartnerUUID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting partner_uuid: %s", err)) + } + if err = d.Set("description", scope.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("org_id", flex.IntValue(scope.OrgID)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting org_id: %s", err)) + } + if err = d.Set("cloud_type_id", flex.IntValue(scope.CloudTypeID)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cloud_type_id: %s", err)) + } + if err = d.Set("tld_credential_id", flex.IntValue(scope.TldCredentialID)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting tld_credential_id: %s", err)) + } + if err = d.Set("status", scope.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + if err = d.Set("status_msg", scope.StatusMsg); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status_msg: %s", err)) + } + if err = d.Set("subset_selected", scope.SubsetSelected); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subset_selected: %s", err)) + } + if err = d.Set("enabled", scope.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enabled: %s", err)) + } + if err = d.Set("last_discover_start_time", scope.LastDiscoverStartTime); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_discover_start_time: %s", err)) + } + if err = d.Set("last_discover_completed_time", scope.LastDiscoverCompletedTime); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_discover_completed_time: %s", err)) + } + if err = d.Set("last_successful_discover_start_time", scope.LastSuccessfulDiscoverStartTime); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_successful_discover_start_time: %s", err)) + } + if err = d.Set("last_successful_discover_completed_time", scope.LastSuccessfulDiscoverCompletedTime); err != nil { + return diag.FromErr(fmt.Errorf("Error setting last_successful_discover_completed_time: %s", err)) + } + if err = d.Set("task_type", scope.TaskType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting task_type: %s", err)) + } + + if scope.Tasks != nil { + err = d.Set("tasks", dataSourceScopeFlattenTasks(scope.Tasks)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting tasks %s", err)) + } + } + if err = d.Set("status_updated_time", scope.StatusUpdatedTime); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status_updated_time: %s", err)) + } + + if scope.CollectorsByType != nil { + convertedMap := make(map[string]interface{}, len(scope.CollectorsByType)) + for k, v := range scope.CollectorsByType { + convertedMap[k] = v + } + + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting collectors_by_type %s", err)) + } + } + + if scope.CredentialsByType != nil { + convertedMap := make(map[string]interface{}, len(scope.CredentialsByType)) + for k, v := range scope.CredentialsByType { + convertedMap[k] = v + } + + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting credentials_by_type %s", err)) + } + } + + if scope.CredentialsBySubCategeoryType != nil { + convertedMap := make(map[string]interface{}, len(scope.CredentialsBySubCategeoryType)) + for k, v := range scope.CredentialsBySubCategeoryType { + convertedMap[k] = v + } + + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting credentials_by_sub_categeory_type %s", err)) + } + } + if err = d.Set("resource_groups", scope.ResourceGroups); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_groups: %s", err)) + } + if err = d.Set("region_names", scope.RegionNames); err != nil { + return diag.FromErr(fmt.Errorf("Error setting region_names: %s", err)) + } + if err = d.Set("cloud_type", scope.CloudType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cloud_type: %s", err)) + } + if err = d.Set("env_sub_category", scope.EnvSubCategory); err != nil { + return diag.FromErr(fmt.Errorf("Error setting env_sub_category: %s", err)) + } + + if scope.TldCredentail != nil { + err = d.Set("tld_credentail", dataSourceScopeFlattenTldCredentail(*scope.TldCredentail)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting tld_credentail %s", err)) + } + } + + if scope.Collectors != nil { + err = d.Set("collectors", dataSourceScopeFlattenCollectors(scope.Collectors)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting collectors %s", err)) + } + } + + if scope.FirstLevelScopedData != nil { + err = d.Set("first_level_scoped_data", dataSourceScopeFlattenFirstLevelScopedData(scope.FirstLevelScopedData)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting first_level_scoped_data %s", err)) + } + } + if err = d.Set("discovery_method", scope.DiscoveryMethod); err != nil { + return diag.FromErr(fmt.Errorf("Error setting discovery_method: %s", err)) + } + if err = d.Set("file_type", scope.FileType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting file_type: %s", err)) + } + if err = d.Set("file_format", scope.FileFormat); err != nil { + return diag.FromErr(fmt.Errorf("Error setting file_format: %s", err)) + } + if err = d.Set("created_by", scope.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("created_at", scope.CreatedAt); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("modified_by", scope.ModifiedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting modified_by: %s", err)) + } + if err = d.Set("modified_at", scope.ModifiedAt); err != nil { + return diag.FromErr(fmt.Errorf("Error setting modified_at: %s", err)) + } + if err = d.Set("is_discovery_scheduled", scope.IsDiscoveryScheduled); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_discovery_scheduled: %s", err)) + } + if err = d.Set("interval", flex.IntValue(scope.Interval)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting interval: %s", err)) + } + if err = d.Set("discovery_setting_id", flex.IntValue(scope.DiscoverySettingID)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting discovery_setting_id: %s", err)) + } + if err = d.Set("include_new_eagerly", scope.IncludeNewEagerly); err != nil { + return diag.FromErr(fmt.Errorf("Error setting include_new_eagerly: %s", err)) + } + if err = d.Set("type", scope.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("correlation_id", scope.CorrelationID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting correlation_id: %s", err)) + } + if err = d.Set("credential_attributes", scope.CredentialAttributes); err != nil { + return diag.FromErr(fmt.Errorf("Error setting credential_attributes: %s", err)) + } + + return nil +} + +func dataSourceScopeFlattenTasks(result []posturemanagementv2.ScopeDetailsGatewayTask) (tasks []map[string]interface{}) { + for _, tasksItem := range result { + tasks = append(tasks, dataSourceScopeTasksToMap(tasksItem)) + } + + return tasks +} + +func dataSourceScopeTasksToMap(tasksItem posturemanagementv2.ScopeDetailsGatewayTask) (tasksMap map[string]interface{}) { + tasksMap = map[string]interface{}{} + + if tasksItem.TaskLogs != nil { + taskLogsList := []map[string]interface{}{} + for _, taskLogsItem := range tasksItem.TaskLogs { + taskLogsList = append(taskLogsList, dataSourceScopeTasksTaskLogsToMap(taskLogsItem)) + } + tasksMap["task_logs"] = taskLogsList + } + if tasksItem.TaskID != nil { + tasksMap["task_id"] = tasksItem.TaskID + } + if tasksItem.TaskGatewayID != nil { + tasksMap["task_gateway_id"] = tasksItem.TaskGatewayID + } + if tasksItem.TaskGatewayName != nil { + tasksMap["task_gateway_name"] = tasksItem.TaskGatewayName + } + if tasksItem.TaskTaskType != nil { + tasksMap["task_task_type"] = tasksItem.TaskTaskType + } + if tasksItem.TaskGatewaySchemaID != nil { + tasksMap["task_gateway_schema_id"] = tasksItem.TaskGatewaySchemaID + } + if tasksItem.TaskSchemaName != nil { + tasksMap["task_schema_name"] = tasksItem.TaskSchemaName + } + if tasksItem.TaskDiscoverID != nil { + tasksMap["task_discover_id"] = tasksItem.TaskDiscoverID + } + if tasksItem.TaskStatus != nil { + tasksMap["task_status"] = tasksItem.TaskStatus + } + if tasksItem.TaskStatusMsg != nil { + tasksMap["task_status_msg"] = tasksItem.TaskStatusMsg + } + if tasksItem.TaskStartTime != nil { + tasksMap["task_start_time"] = tasksItem.TaskStartTime + } + if tasksItem.TaskUpdatedTime != nil { + tasksMap["task_updated_time"] = tasksItem.TaskUpdatedTime + } + if tasksItem.TaskDerivedStatus != nil { + tasksMap["task_derived_status"] = tasksItem.TaskDerivedStatus + } + if tasksItem.TaskCreatedBy != nil { + tasksMap["task_created_by"] = tasksItem.TaskCreatedBy + } + + return tasksMap +} + +func dataSourceScopeTasksTaskLogsToMap(taskLogsItem posturemanagementv2.TaskLogs) (taskLogsMap map[string]interface{}) { + taskLogsMap = map[string]interface{}{} + + return taskLogsMap +} + +func dataSourceScopeFlattenTldCredentail(result posturemanagementv2.ScopeDetailsCredential) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScopeTldCredentailToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScopeTldCredentailToMap(tldCredentailItem posturemanagementv2.ScopeDetailsCredential) (tldCredentailMap map[string]interface{}) { + tldCredentailMap = map[string]interface{}{} + + if tldCredentailItem.ID != nil { + tldCredentailMap["credential_id"] = tldCredentailItem.ID + } + if tldCredentailItem.Name != nil { + tldCredentailMap["name"] = tldCredentailItem.Name + } + if tldCredentailItem.UUID != nil { + tldCredentailMap["uuid"] = tldCredentailItem.UUID + } + if tldCredentailItem.Type != nil { + tldCredentailMap["credential_type"] = tldCredentailItem.Type + } + if tldCredentailItem.Data != nil { + tldCredentailMap["data"] = tldCredentailItem.Data + } + if tldCredentailItem.DisplayFields != nil { + displayFieldsList := []map[string]interface{}{} + displayFieldsMap := dataSourceScopeTldCredentailDisplayFieldsToMap(*tldCredentailItem.DisplayFields) + displayFieldsList = append(displayFieldsList, displayFieldsMap) + tldCredentailMap["display_fields"] = displayFieldsList + } + if tldCredentailItem.VersionTimestamp != nil { + tldCredentailMap["version_timestamp"] = tldCredentailItem.VersionTimestamp + } + if tldCredentailItem.Description != nil { + tldCredentailMap["description"] = tldCredentailItem.Description + } + if tldCredentailItem.IsEnabled != nil { + tldCredentailMap["is_enabled"] = tldCredentailItem.IsEnabled + } + if tldCredentailItem.GatewayKey != nil { + tldCredentailMap["gateway_key"] = tldCredentailItem.GatewayKey + } + if tldCredentailItem.CredentialGroup != nil { + tldCredentailMap["credential_group"] = tldCredentailItem.CredentialGroup + } + if tldCredentailItem.EnabledCredentialGroup != nil { + tldCredentailMap["enabled_credential_group"] = tldCredentailItem.EnabledCredentialGroup + } + if tldCredentailItem.Groups != nil { + groupsList := []map[string]interface{}{} + for _, groupsItem := range tldCredentailItem.Groups { + groupsList = append(groupsList, dataSourceScopeTldCredentailGroupsToMap(groupsItem)) + } + tldCredentailMap["groups"] = groupsList + } + if tldCredentailItem.Purpose != nil { + tldCredentailMap["purpose"] = tldCredentailItem.Purpose + } + + return tldCredentailMap +} + +func dataSourceScopeTldCredentailDisplayFieldsToMap(displayFieldsItem posturemanagementv2.ScopeDetailsCredentialDisplayFields) (displayFieldsMap map[string]interface{}) { + displayFieldsMap = map[string]interface{}{} + + if displayFieldsItem.IBMAPIKey != nil { + displayFieldsMap["ibm_api_key"] = displayFieldsItem.IBMAPIKey + } + if displayFieldsItem.AwsClientID != nil { + displayFieldsMap["aws_client_id"] = displayFieldsItem.AwsClientID + } + if displayFieldsItem.AwsClientSecret != nil { + displayFieldsMap["aws_client_secret"] = displayFieldsItem.AwsClientSecret + } + if displayFieldsItem.AwsRegion != nil { + displayFieldsMap["aws_region"] = displayFieldsItem.AwsRegion + } + if displayFieldsItem.AwsArn != nil { + displayFieldsMap["aws_arn"] = displayFieldsItem.AwsArn + } + if displayFieldsItem.Username != nil { + displayFieldsMap["username"] = displayFieldsItem.Username + } + if displayFieldsItem.Password != nil { + displayFieldsMap["password"] = displayFieldsItem.Password + } + if displayFieldsItem.AzureClientID != nil { + displayFieldsMap["azure_client_id"] = displayFieldsItem.AzureClientID + } + if displayFieldsItem.AzureClientSecret != nil { + displayFieldsMap["azure_client_secret"] = displayFieldsItem.AzureClientSecret + } + if displayFieldsItem.AzureSubscriptionID != nil { + displayFieldsMap["azure_subscription_id"] = displayFieldsItem.AzureSubscriptionID + } + if displayFieldsItem.AzureResourceGroup != nil { + displayFieldsMap["azure_resource_group"] = displayFieldsItem.AzureResourceGroup + } + if displayFieldsItem.DatabaseName != nil { + displayFieldsMap["database_name"] = displayFieldsItem.DatabaseName + } + if displayFieldsItem.WinrmAuthtype != nil { + displayFieldsMap["winrm_authtype"] = displayFieldsItem.WinrmAuthtype + } + if displayFieldsItem.WinrmUsessl != nil { + displayFieldsMap["winrm_usessl"] = displayFieldsItem.WinrmUsessl + } + if displayFieldsItem.WinrmPort != nil { + displayFieldsMap["winrm_port"] = displayFieldsItem.WinrmPort + } + if displayFieldsItem.Ms365ClientID != nil { + displayFieldsMap["ms_365_client_id"] = displayFieldsItem.Ms365ClientID + } + if displayFieldsItem.Ms365ClientSecret != nil { + displayFieldsMap["ms_365_client_secret"] = displayFieldsItem.Ms365ClientSecret + } + if displayFieldsItem.Ms365TenantID != nil { + displayFieldsMap["ms_365_tenant_id"] = displayFieldsItem.Ms365TenantID + } + if displayFieldsItem.AuthURL != nil { + displayFieldsMap["auth_url"] = displayFieldsItem.AuthURL + } + if displayFieldsItem.ProjectName != nil { + displayFieldsMap["project_name"] = displayFieldsItem.ProjectName + } + if displayFieldsItem.UserDomainName != nil { + displayFieldsMap["user_domain_name"] = displayFieldsItem.UserDomainName + } + if displayFieldsItem.ProjectDomainName != nil { + displayFieldsMap["project_domain_name"] = displayFieldsItem.ProjectDomainName + } + + return displayFieldsMap +} + +func dataSourceScopeTldCredentailGroupsToMap(groupsItem posturemanagementv2.CredentialGroup) (groupsMap map[string]interface{}) { + groupsMap = map[string]interface{}{} + + if groupsItem.ID != nil { + groupsMap["credential_group_id"] = groupsItem.ID + } + if groupsItem.Passphrase != nil { + groupsMap["passphrase"] = groupsItem.Passphrase + } + + return groupsMap +} + +func dataSourceScopeFlattenCollectors(result []posturemanagementv2.Collector) (collectors []map[string]interface{}) { + for _, collectorsItem := range result { + collectors = append(collectors, dataSourceScopeCollectorsToMap(collectorsItem)) + } + + return collectors +} + +func dataSourceScopeCollectorsToMap(collectorsItem posturemanagementv2.Collector) (collectorsMap map[string]interface{}) { + collectorsMap = map[string]interface{}{} + + if collectorsItem.ID != nil { + collectorsMap["collector_id"] = collectorsItem.ID + } + if collectorsItem.DisplayName != nil { + collectorsMap["display_name"] = collectorsItem.DisplayName + } + if collectorsItem.Name != nil { + collectorsMap["name"] = collectorsItem.Name + } + if collectorsItem.PublicKey != nil { + collectorsMap["public_key"] = collectorsItem.PublicKey + } + if collectorsItem.LastHeartbeat != nil { + collectorsMap["last_heartbeat"] = collectorsItem.LastHeartbeat.String() + } + if collectorsItem.Status != nil { + collectorsMap["status"] = collectorsItem.Status + } + if collectorsItem.CollectorVersion != nil { + collectorsMap["collector_version"] = collectorsItem.CollectorVersion + } + if collectorsItem.ImageVersion != nil { + collectorsMap["image_version"] = collectorsItem.ImageVersion + } + if collectorsItem.Description != nil { + collectorsMap["description"] = collectorsItem.Description + } + if collectorsItem.CreatedBy != nil { + collectorsMap["created_by"] = collectorsItem.CreatedBy + } + if collectorsItem.CreatedAt != nil { + collectorsMap["created_at"] = collectorsItem.CreatedAt.String() + } + if collectorsItem.UpdatedBy != nil { + collectorsMap["updated_by"] = collectorsItem.UpdatedBy + } + if collectorsItem.UpdatedAt != nil { + collectorsMap["updated_at"] = collectorsItem.UpdatedAt.String() + } + if collectorsItem.Enabled != nil { + collectorsMap["enabled"] = collectorsItem.Enabled + } + if collectorsItem.RegistrationCode != nil { + collectorsMap["registration_code"] = collectorsItem.RegistrationCode + } + if collectorsItem.Type != nil { + collectorsMap["type"] = collectorsItem.Type + } + if collectorsItem.CredentialPublicKey != nil { + collectorsMap["credential_public_key"] = collectorsItem.CredentialPublicKey + } + if collectorsItem.FailureCount != nil { + collectorsMap["failure_count"] = collectorsItem.FailureCount + } + if collectorsItem.ApprovedLocalGatewayIP != nil { + collectorsMap["approved_local_gateway_ip"] = collectorsItem.ApprovedLocalGatewayIP + } + if collectorsItem.ApprovedInternetGatewayIP != nil { + collectorsMap["approved_internet_gateway_ip"] = collectorsItem.ApprovedInternetGatewayIP + } + if collectorsItem.LastFailedLocalGatewayIP != nil { + collectorsMap["last_failed_local_gateway_ip"] = collectorsItem.LastFailedLocalGatewayIP + } + if collectorsItem.ResetReason != nil { + collectorsMap["reset_reason"] = collectorsItem.ResetReason + } + if collectorsItem.Hostname != nil { + collectorsMap["hostname"] = collectorsItem.Hostname + } + if collectorsItem.InstallPath != nil { + collectorsMap["install_path"] = collectorsItem.InstallPath + } + if collectorsItem.UsePrivateEndpoint != nil { + collectorsMap["use_private_endpoint"] = collectorsItem.UsePrivateEndpoint + } + if collectorsItem.ManagedBy != nil { + collectorsMap["managed_by"] = collectorsItem.ManagedBy + } + if collectorsItem.TrialExpiry != nil { + collectorsMap["trial_expiry"] = collectorsItem.TrialExpiry.String() + } + if collectorsItem.LastFailedInternetGatewayIP != nil { + collectorsMap["last_failed_internet_gateway_ip"] = collectorsItem.LastFailedInternetGatewayIP + } + if collectorsItem.StatusDescription != nil { + collectorsMap["status_description"] = collectorsItem.StatusDescription + } + if collectorsItem.ResetTime != nil { + collectorsMap["reset_time"] = collectorsItem.ResetTime.String() + } + if collectorsItem.IsPublic != nil { + collectorsMap["is_public"] = collectorsItem.IsPublic + } + if collectorsItem.IsUbiImage != nil { + collectorsMap["is_ubi_image"] = collectorsItem.IsUbiImage + } + + return collectorsMap +} + +func dataSourceScopeFlattenFirstLevelScopedData(result []posturemanagementv2.ScopeDetailsAssetData) (firstLevelScopedData []map[string]interface{}) { + for _, firstLevelScopedDataItem := range result { + firstLevelScopedData = append(firstLevelScopedData, dataSourceScopeFirstLevelScopedDataToMap(firstLevelScopedDataItem)) + } + + return firstLevelScopedData +} + +func dataSourceScopeFirstLevelScopedDataToMap(firstLevelScopedDataItem posturemanagementv2.ScopeDetailsAssetData) (firstLevelScopedDataMap map[string]interface{}) { + firstLevelScopedDataMap = map[string]interface{}{} + + if firstLevelScopedDataItem.ScopeObject != nil { + firstLevelScopedDataMap["scope_object"] = firstLevelScopedDataItem.ScopeObject + } + if firstLevelScopedDataItem.ScopeInitScope != nil { + firstLevelScopedDataMap["scope_init_scope"] = firstLevelScopedDataItem.ScopeInitScope + } + if firstLevelScopedDataItem.Scope != nil { + firstLevelScopedDataMap["scope"] = firstLevelScopedDataItem.Scope + } + if firstLevelScopedDataItem.ScopeChanged != nil { + firstLevelScopedDataMap["scope_changed"] = firstLevelScopedDataItem.ScopeChanged + } + if firstLevelScopedDataItem.ScopeID != nil { + firstLevelScopedDataMap["scope_id"] = firstLevelScopedDataItem.ScopeID + } + if firstLevelScopedDataItem.ScopeProperties != nil { + firstLevelScopedDataMap["scope_properties"] = firstLevelScopedDataItem.ScopeProperties + } + if firstLevelScopedDataItem.ScopeOverlay != nil { + firstLevelScopedDataMap["scope_overlay"] = firstLevelScopedDataItem.ScopeOverlay + } + if firstLevelScopedDataItem.ScopeNewFound != nil { + firstLevelScopedDataMap["scope_new_found"] = firstLevelScopedDataItem.ScopeNewFound + } + if firstLevelScopedDataItem.ScopeDiscoveryStatus != nil { + firstLevelScopedDataMap["scope_discovery_status"] = firstLevelScopedDataItem.ScopeDiscoveryStatus + } + if firstLevelScopedDataItem.ScopeFactStatus != nil { + firstLevelScopedDataMap["scope_fact_status"] = firstLevelScopedDataItem.ScopeFactStatus + } + if firstLevelScopedDataItem.ScopeFacts != nil { + firstLevelScopedDataMap["scope_facts"] = firstLevelScopedDataItem.ScopeFacts + } + if firstLevelScopedDataItem.ScopeListMembers != nil { + firstLevelScopedDataMap["scope_list_members"] = firstLevelScopedDataItem.ScopeListMembers + } + if firstLevelScopedDataItem.ScopeChildren != nil { + firstLevelScopedDataMap["scope_children"] = firstLevelScopedDataItem.ScopeChildren + } + if firstLevelScopedDataItem.ScopeResourceCategory != nil { + firstLevelScopedDataMap["scope_resource_category"] = firstLevelScopedDataItem.ScopeResourceCategory + } + if firstLevelScopedDataItem.ScopeResourceType != nil { + firstLevelScopedDataMap["scope_resource_type"] = firstLevelScopedDataItem.ScopeResourceType + } + if firstLevelScopedDataItem.ScopeResource != nil { + firstLevelScopedDataMap["scope_resource"] = firstLevelScopedDataItem.ScopeResource + } + if firstLevelScopedDataItem.ScopeResourceAttributes != nil { + firstLevelScopedDataMap["scope_resource_attributes"] = firstLevelScopedDataItem.ScopeResourceAttributes + } + if firstLevelScopedDataItem.ScopeDrift != nil { + firstLevelScopedDataMap["scope_drift"] = firstLevelScopedDataItem.ScopeDrift + } + if firstLevelScopedDataItem.ScopeParseStatus != nil { + firstLevelScopedDataMap["scope_parse_status"] = firstLevelScopedDataItem.ScopeParseStatus + } + if firstLevelScopedDataItem.ScopeTransformedFacts != nil { + firstLevelScopedDataMap["scope_transformed_facts"] = firstLevelScopedDataItem.ScopeTransformedFacts + } + if firstLevelScopedDataItem.ScopeCollectorID != nil { + firstLevelScopedDataMap["scope_collector_id"] = firstLevelScopedDataItem.ScopeCollectorID + } + + return firstLevelScopedDataMap +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation.go b/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation.go new file mode 100644 index 000000000..cc9cc0f2d --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation.go @@ -0,0 +1,89 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureScopeCorrelation() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureScopeCorrelationRead, + + Schema: map[string]*schema.Schema{ + "correlation_id": { + Type: schema.TypeString, + Required: true, + Description: "A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation).", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Returns the current status of a task.", + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: "Returns the time that task started.", + }, + "last_heartbeat": { + Type: schema.TypeString, + Computed: true, + Description: "Returns the time that the scope was last updated. This value exists when collector is installed and running.", + }, + }, + } +} + +func dataSourceIBMSccPostureScopeCorrelationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getCorrelationIDOptions := &posturemanagementv2.GetCorrelationIDOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getCorrelationIDOptions.SetAccountID(accountID) + + getCorrelationIDOptions.SetCorrelationID(d.Get("correlation_id").(string)) + + scopeTaskStatus, response, err := postureManagementClient.GetCorrelationIDWithContext(context, getCorrelationIDOptions) + if err != nil { + log.Printf("[DEBUG] GetCorrelationIDWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCorrelationIDWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMSccPostureScopeCorrelationID(d)) + if err = d.Set("status", scopeTaskStatus.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + if err = d.Set("start_time", scopeTaskStatus.StartTime); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting start_time: %s", err)) + } + if err = d.Set("last_heartbeat", flex.DateTimeToString(scopeTaskStatus.LastHeartbeat)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_heartbeat: %s", err)) + } + + return nil +} + +// dataSourceIBMScopeCorrelationID returns a reasonable ID for the list. +func dataSourceIBMSccPostureScopeCorrelationID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation_test.go b/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation_test.go new file mode 100644 index 000000000..3e86a3ef8 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scope_correlation_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureScopeCorrelationDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureScopeCorrelationDataSourceConfigBasic(acc.Scc_posture_correlation_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scope_correlation.scope_correlation", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scope_correlation.scope_correlation", "correlation_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureScopeCorrelationDataSourceConfigBasic(correlationId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_scope_correlation" "scope_correlation" { + correlation_id = "%s" + } + `, correlationId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scope_test.go b/ibm/service/scc/data_source_ibm_scc_posture_scope_test.go new file mode 100644 index 000000000..6ae258ee5 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scope_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureScopeDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccPostureScopeDataSourceConfigBasic(acc.Scc_posture_scope_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scope.scope", "scope_id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scope.scope", "name"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureScopeDataSourceConfigBasic(scopeId string) string { + return fmt.Sprintf(` + data "ibm_scc_posture_scope" "scope" { + scope_id = "%s" + } + `, scopeId) +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scopes.go b/ibm/service/scc/data_source_ibm_scc_posture_scopes.go new file mode 100644 index 000000000..6f28fb79e --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scopes.go @@ -0,0 +1,630 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func DataSourceIBMSccPostureScopes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSccPostureListScopesRead, + + Schema: map[string]*schema.Schema{ + "offset": { + Type: schema.TypeInt, + Computed: true, + Description: "The offset of the page.", + }, + "limit": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of scopes displayed per page.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of scopes. This value is 0 if no scopes are available and below fields will not be available in that case.", + }, + "first": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "last": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "previous": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "next": { + Type: schema.TypeList, + Computed: true, + Description: "The URL of a page.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL of a page.", + }, + }, + }, + }, + "scopes": { + Type: schema.TypeList, + Computed: true, + Description: "Scopes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "A detailed description of the scope.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who created the scope.", + }, + "modified_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who most recently modified the scope.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "An auto-generated unique identifier for the scope.", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "Stores the value of scope_uuid .", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "A unique name for your scope.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether scope is enabled/disabled.", + }, + "credential_type": { + Type: schema.TypeString, + Computed: true, + Description: "The environment that the scope is targeted to.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the scope was created in UTC.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the scope was last modified in UTC.", + }, + "collectors": { + Type: schema.TypeList, + Computed: true, + Description: "Stores the value of collectors .Will be displayed only when value exists.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the collector.", + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-friendly name of the collector.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the collector.", + }, + "public_key": { + Type: schema.TypeString, + Computed: true, + Description: "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + }, + "last_heartbeat": { + Type: schema.TypeString, + Computed: true, + Description: "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of collector.", + }, + "collector_version": { + Type: schema.TypeString, + Computed: true, + Description: "The collector version. This field is populated when collector is installed.", + }, + "image_version": { + Type: schema.TypeString, + Computed: true, + Description: "The image version of the collector. This field is populated when collector is installed. \".", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the collector.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that created the collector.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was created.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the user that modified the collector.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time the collector was modified.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Identifies whether the collector is enabled or not(deleted).", + }, + "registration_code": { + Type: schema.TypeString, + Computed: true, + Description: "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the collector.", + }, + "credential_public_key": { + Type: schema.TypeString, + Computed: true, + Description: "The credential public key.", + }, + "failure_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of times the collector has failed.", + }, + "approved_local_gateway_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "approved_internet_gateway_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + }, + "last_failed_local_gateway_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The failed local gateway ip. This field will be populated only when collector is installed.", + }, + "reset_reason": { + Type: schema.TypeString, + Computed: true, + Description: "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + }, + "hostname": { + Type: schema.TypeString, + Computed: true, + Description: "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + }, + "install_path": { + Type: schema.TypeString, + Computed: true, + Description: "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + }, + "use_private_endpoint": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + }, + "managed_by": { + Type: schema.TypeString, + Computed: true, + Description: "The entity that manages the collector.", + }, + "trial_expiry": { + Type: schema.TypeString, + Computed: true, + Description: "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + }, + "last_failed_internet_gateway_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The failed internet gateway ip of the collector.", + }, + "status_description": { + Type: schema.TypeString, + Computed: true, + Description: "The collector status.", + }, + "reset_time": { + Type: schema.TypeString, + Computed: true, + Description: "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + }, + "is_public": { + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + }, + "is_ubi_image": { + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether the collector has a Ubi image.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSccPostureListScopesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + listScopesOptions := &posturemanagementv2.ListScopesOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + listScopesOptions.SetAccountID(accountID) + + finalList, response, err := postureManagementClient.ListScopesWithContext(context, listScopesOptions) + if err != nil { + log.Printf("[DEBUG] ListScopesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListScopesWithContext failed %s\n%s", err, response)) + } + + scopeList := finalList + + d.SetId(dataSourceIBMSccPostureListScopesID(d)) + if err = d.Set("offset", flex.IntValue(scopeList.Offset)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting offset: %s", err)) + } + if err = d.Set("limit", flex.IntValue(scopeList.Limit)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting limit: %s", err)) + } + if err = d.Set("total_count", flex.IntValue(scopeList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) + } + + if scopeList.First != nil { + err = d.Set("first", dataSourceScopeListFlattenFirst(*scopeList.First)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting first %s", err)) + } + } + + if scopeList.Last != nil { + err = d.Set("last", dataSourceScopeListFlattenLast(*scopeList.Last)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last %s", err)) + } + } + + if scopeList.Previous != nil { + err = d.Set("previous", dataSourceScopeListFlattenPrevious(*scopeList.Previous)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting previous %s", err)) + } + } + + if scopeList.Next != nil { + err = d.Set("next", dataSourceScopeListFlattenNext(*scopeList.Next)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting next %s", err)) + } + } + + if scopeList.Scopes != nil { + err = d.Set("scopes", dataSourceScopeListFlattenScopes(scopeList.Scopes)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting scopes %s", err)) + } + } + + return nil +} + +// dataSourceIBMListScopesID returns a reasonable ID for the list. +func dataSourceIBMSccPostureListScopesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceScopeListFlattenFirst(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScopeListFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScopeListFirstToMap(firstItem posturemanagementv2.PageLink) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceScopeListFlattenLast(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScopeListLastToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScopeListLastToMap(lastItem posturemanagementv2.PageLink) (lastMap map[string]interface{}) { + lastMap = map[string]interface{}{} + + if lastItem.Href != nil { + lastMap["href"] = lastItem.Href + } + + return lastMap +} + +func dataSourceScopeListFlattenPrevious(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScopeListPreviousToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScopeListPreviousToMap(previousItem posturemanagementv2.PageLink) (previousMap map[string]interface{}) { + previousMap = map[string]interface{}{} + + if previousItem.Href != nil { + previousMap["href"] = previousItem.Href + } + + return previousMap +} + +func dataSourceScopeListFlattenNext(result posturemanagementv2.PageLink) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceScopeListNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceScopeListNextToMap(nextItem posturemanagementv2.PageLink) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} + +func dataSourceScopeListFlattenScopes(result []posturemanagementv2.ScopeItem) (scopes []map[string]interface{}) { + for _, scopesItem := range result { + scopes = append(scopes, dataSourceScopeListScopesToMap(scopesItem)) + } + + return scopes +} + +func dataSourceScopeListScopesToMap(scopesItem posturemanagementv2.ScopeItem) (scopesMap map[string]interface{}) { + scopesMap = map[string]interface{}{} + + if scopesItem.Description != nil { + scopesMap["description"] = scopesItem.Description + } + if scopesItem.CreatedBy != nil { + scopesMap["created_by"] = scopesItem.CreatedBy + } + if scopesItem.ModifiedBy != nil { + scopesMap["modified_by"] = scopesItem.ModifiedBy + } + if scopesItem.ID != nil { + scopesMap["id"] = scopesItem.ID + } + if scopesItem.UUID != nil { + scopesMap["uuid"] = scopesItem.UUID + } + if scopesItem.Name != nil { + scopesMap["name"] = scopesItem.Name + } + if scopesItem.Enabled != nil { + scopesMap["enabled"] = scopesItem.Enabled + } + if scopesItem.CredentialType != nil { + scopesMap["credential_type"] = scopesItem.CredentialType + } + if scopesItem.CreatedAt != nil { + scopesMap["created_at"] = scopesItem.CreatedAt.String() + } + if scopesItem.UpdatedAt != nil { + scopesMap["updated_at"] = scopesItem.UpdatedAt.String() + } + if scopesItem.Collectors != nil { + collectorsList := []map[string]interface{}{} + for _, collectorsItem := range scopesItem.Collectors { + collectorsList = append(collectorsList, dataSourceScopeListScopesCollectorsToMap(collectorsItem)) + } + scopesMap["collectors"] = collectorsList + } + + return scopesMap +} + +func dataSourceScopeListScopesCollectorsToMap(collectorsItem posturemanagementv2.Collector) (collectorsMap map[string]interface{}) { + collectorsMap = map[string]interface{}{} + + if collectorsItem.ID != nil { + collectorsMap["id"] = collectorsItem.ID + } + if collectorsItem.DisplayName != nil { + collectorsMap["display_name"] = collectorsItem.DisplayName + } + if collectorsItem.Name != nil { + collectorsMap["name"] = collectorsItem.Name + } + if collectorsItem.PublicKey != nil { + collectorsMap["public_key"] = collectorsItem.PublicKey + } + if collectorsItem.LastHeartbeat != nil { + collectorsMap["last_heartbeat"] = collectorsItem.LastHeartbeat.String() + } + if collectorsItem.Status != nil { + collectorsMap["status"] = collectorsItem.Status + } + if collectorsItem.CollectorVersion != nil { + collectorsMap["collector_version"] = collectorsItem.CollectorVersion + } + if collectorsItem.ImageVersion != nil { + collectorsMap["image_version"] = collectorsItem.ImageVersion + } + if collectorsItem.Description != nil { + collectorsMap["description"] = collectorsItem.Description + } + if collectorsItem.CreatedBy != nil { + collectorsMap["created_by"] = collectorsItem.CreatedBy + } + if collectorsItem.CreatedAt != nil { + collectorsMap["created_at"] = collectorsItem.CreatedAt.String() + } + if collectorsItem.UpdatedBy != nil { + collectorsMap["updated_by"] = collectorsItem.UpdatedBy + } + if collectorsItem.UpdatedAt != nil { + collectorsMap["updated_at"] = collectorsItem.UpdatedAt.String() + } + if collectorsItem.Enabled != nil { + collectorsMap["enabled"] = collectorsItem.Enabled + } + if collectorsItem.RegistrationCode != nil { + collectorsMap["registration_code"] = collectorsItem.RegistrationCode + } + if collectorsItem.Type != nil { + collectorsMap["type"] = collectorsItem.Type + } + if collectorsItem.CredentialPublicKey != nil { + collectorsMap["credential_public_key"] = collectorsItem.CredentialPublicKey + } + if collectorsItem.FailureCount != nil { + collectorsMap["failure_count"] = collectorsItem.FailureCount + } + if collectorsItem.ApprovedLocalGatewayIP != nil { + collectorsMap["approved_local_gateway_ip"] = collectorsItem.ApprovedLocalGatewayIP + } + if collectorsItem.ApprovedInternetGatewayIP != nil { + collectorsMap["approved_internet_gateway_ip"] = collectorsItem.ApprovedInternetGatewayIP + } + if collectorsItem.LastFailedLocalGatewayIP != nil { + collectorsMap["last_failed_local_gateway_ip"] = collectorsItem.LastFailedLocalGatewayIP + } + if collectorsItem.ResetReason != nil { + collectorsMap["reset_reason"] = collectorsItem.ResetReason + } + if collectorsItem.Hostname != nil { + collectorsMap["hostname"] = collectorsItem.Hostname + } + if collectorsItem.InstallPath != nil { + collectorsMap["install_path"] = collectorsItem.InstallPath + } + if collectorsItem.UsePrivateEndpoint != nil { + collectorsMap["use_private_endpoint"] = collectorsItem.UsePrivateEndpoint + } + if collectorsItem.ManagedBy != nil { + collectorsMap["managed_by"] = collectorsItem.ManagedBy + } + if collectorsItem.TrialExpiry != nil { + collectorsMap["trial_expiry"] = collectorsItem.TrialExpiry.String() + } + if collectorsItem.LastFailedInternetGatewayIP != nil { + collectorsMap["last_failed_internet_gateway_ip"] = collectorsItem.LastFailedInternetGatewayIP + } + if collectorsItem.StatusDescription != nil { + collectorsMap["status_description"] = collectorsItem.StatusDescription + } + if collectorsItem.ResetTime != nil { + collectorsMap["reset_time"] = collectorsItem.ResetTime.String() + } + if collectorsItem.IsPublic != nil { + collectorsMap["is_public"] = collectorsItem.IsPublic + } + if collectorsItem.IsUbiImage != nil { + collectorsMap["is_ubi_image"] = collectorsItem.IsUbiImage + } + + return collectorsMap +} diff --git a/ibm/service/scc/data_source_ibm_scc_posture_scopes_test.go b/ibm/service/scc/data_source_ibm_scc_posture_scopes_test.go new file mode 100644 index 000000000..d6bc28f14 --- /dev/null +++ b/ibm/service/scc/data_source_ibm_scc_posture_scopes_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureListScopesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureListScopesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "id"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "offset"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "limit"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "first.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "last.#"), + resource.TestCheckResourceAttrSet("data.ibm_scc_posture_scopes.list_scopes", "scopes.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMSccPostureListScopesDataSourceConfigBasic() string { + return ` + data "ibm_scc_posture_scopes" "list_scopes" { + } + ` +} diff --git a/ibm/service/scc/resource_ibm_scc_account_settings.go b/ibm/service/scc/resource_ibm_scc_account_settings.go new file mode 100644 index 000000000..57fea8f67 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_account_settings.go @@ -0,0 +1,347 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func ResourceIBMSccAccountSettings() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmSccAccountSettingsCreate, + ReadContext: resourceIbmSccAccountSettingsRead, + UpdateContext: resourceIbmSccAccountSettingsUpdate, + DeleteContext: resourceIbmSccAccountSettingsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "location_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_account_settings", "location_id"), + Description: "The programatic ID of the location that you want to work in.", + Deprecated: "The attribute location_id will soon be deprecated. Please use location instead. See https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/scc_account_settings for details", + }, + "location": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, // Made this Required to avoid drift + ConflictsWith: []string{"location_id"}, + Description: "Location Settings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "location_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The programatic ID of the location that you want to work in.", + ValidateFunc: validate.InvokeValidator("ibm_scc_account_settings", "location_id"), + }, + }, + }, + }, + "event_notifications": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The Event Notification settings to register.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + Description: "The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect.", + }, + }, + }, + // Made a custom DiffSuppressFunc in order to prevent resource drift due to it being Optional + DiffSuppressFunc: func(_, oldValue, newValue string, d *schema.ResourceData) bool { + if _, ok := d.GetOk("event_notifications"); ok { + // oldValue being 1 vs newValue being 0 means the schema field is now missing the *.tf files + if oldValue == "1" && newValue == "0" { + return true + } else { + return oldValue == newValue + } + } else { + return false + } + }, + }, + }, + } +} + +func resourceIbmSccAccountSettingsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[DEBUG] Starting resourceIbmSccAccountSettings%s \n", "Create") + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + // Get the available body that you can put from the SDK + patchAccountSettingsOptions := &adminserviceapiv1.PatchAccountSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + // Set the patchSettings to use userAccount tied to the API_KEY + patchAccountSettingsOptions.SetAccountID(userDetails.UserAccount) + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + // Check with GetSettings what the current setting is + accountSettings, response, err := adminServiceApiClient.GetSettingsWithContext(context, getSettingsOptions) + + hasChange := false + + // Handle the backwards compatibility + if _, ok := d.GetOk("location_id"); ok { + location_id, exists := d.Get("location_id").(string) + if !exists { + return diag.FromErr(fmt.Errorf("SCC Admin: Failed to insert location_id into CREATE payload")) + } + // if GetSettings is different than the terrafrom config file, prepare a PATCH call + if location_id != *accountSettings.Location.ID { + patchAccountSettingsOptions.SetLocation(&adminserviceapiv1.LocationID{ + ID: core.StringPtr(location_id), + }) + hasChange = true + } + } else if _, ok := d.GetOk("location"); ok { + // check from the local tf file is location is defined + location, err := resourceIbmSccAccountSettingsMapToLocationID(d.Get("location.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + // if GetSettings is different than the terrafrom config file, prepare a PATCH call + if location.ID != accountSettings.Location.ID { + patchAccountSettingsOptions.SetLocation(location) + hasChange = true + } + } + + // check from the local tf file if event_notifications is defined + event_obj := d.Get("event_notifications.0").(map[string]interface{}) + if _, ok := d.GetOk("event_notifications"); ok && event_obj["instance_crn"] != nil { + eventNotifications, err := resourceIbmSccAccountSettingsMapToNotificationsRegistration(d.Get("event_notifications.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + // if GetSettings is different than the terrafrom config file, prepare a PATCH call + if eventNotifications.InstanceCrn != event_obj["instance_crn"] { + patchAccountSettingsOptions.SetEventNotifications(eventNotifications) + hasChange = true + } + } + + // use scc-go-sdk to send the PATCH request if there is a change + if hasChange { + _, response, err = adminServiceApiClient.PatchAccountSettingsWithContext(context, patchAccountSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PatchAccountSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PatchAccountSettingsWithContext failed %s\n%s", err, response)) + } + } + // Set the ID of the Terraform object + d.SetId("scc_admin_account_settings") + + return resourceIbmSccAccountSettingsRead(context, d, meta) +} + +func resourceIbmSccAccountSettingID(d *schema.ResourceData) string { + // make a unique ID according to the timestamp + return time.Now().UTC().String() +} + +func resourceIbmSccAccountSettingsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[DEBUG] Starting resourceIbmSccAccountSettings%s \n", "Read") + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + // Get the Settings to call GetSettings + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + // Return back the current Settings according to GetSettings + accountSettings, response, err := adminServiceApiClient.GetSettingsWithContext(context, getSettingsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSettingsWithContext failed %s\n%s", err, response)) + } + + if accountSettings.Location != nil { + locationMap, err := resourceIbmSccAccountSettingsLocationIDToMap(accountSettings.Location) + if err != nil { + return diag.FromErr(err) + } + // Handle backwards compatiability + if _, ok := d.GetOk("location_id"); ok { + log.Printf("[DEBUG] Found location_id for Operation %s \n", "Read") + if err = d.Set("location_id", locationMap["location_id"]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting location_id: %s", err)) + } + } else { + if err = d.Set("location", []map[string]interface{}{locationMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + } + } + } + if accountSettings.EventNotifications != nil { + eventNotificationsMap, err := resourceIbmSccAccountSettingsNotificationsRegistrationToMap(accountSettings.EventNotifications) + if err != nil { + return diag.FromErr(err) + } + // if _, ok := d.GetOk("event_notifications"); ok { + log.Println("[DEBUG] event_notifications was found from the resource") + if err = d.Set("event_notifications", []map[string]interface{}{eventNotificationsMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting event_notifications during the read: %s", err)) + } + // } + } + + return nil +} + +func resourceIbmSccAccountSettingsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[DEBUG] Starting resourceIbmSccAccountSettings%s \n", "Update") + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + // Use the same logic as resourceIbmSccAccountSettingsCreate + patchAccountSettingsOptions := &adminserviceapiv1.PatchAccountSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + patchAccountSettingsOptions.SetAccountID(userDetails.UserAccount) + + // Flag to see if anything has been changed from the Update(terraform apply) + hasChange := false + + // handle the backwards compatibility + if _, ok := d.GetOk("location_id"); ok && d.HasChange("location_id") { + location_id, exists := d.Get("location_id").(string) + if !exists { + return diag.FromErr(fmt.Errorf("SCC Admin: Failed to insert location_id into Update payload")) + } + // if location is different than the terrafrom config file, prepare a PATCH call + patchAccountSettingsOptions.SetLocation(&adminserviceapiv1.LocationID{ + ID: core.StringPtr(location_id), + }) + hasChange = true + } else if d.HasChange("location") { + location, err := resourceIbmSccAccountSettingsMapToLocationID(d.Get("location.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchAccountSettingsOptions.SetLocation(location) + hasChange = true + } + + if d.HasChange("event_notifications") { + eventNotifications, err := resourceIbmSccAccountSettingsMapToNotificationsRegistration(d.Get("event_notifications.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + patchAccountSettingsOptions.SetEventNotifications(eventNotifications) + // if eventNotifications.InstanceCrn != nil && len(*eventNotifications.InstanceCrn) != 0 { + // hasChange = true + // } + hasChange = true + } + + if hasChange { + _, response, err := adminServiceApiClient.PatchAccountSettingsWithContext(context, patchAccountSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PatchAccountSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PatchAccountSettingsWithContext failed %s\n%s", err, response)) + } + } + + return resourceIbmSccAccountSettingsRead(context, d, meta) +} + +func resourceIbmSccAccountSettingsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Use GetSettings since there is no API to delete the configuration of the AccountSettings and avoid compiler warnings + adminServiceApiClient, err := meta.(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(err) + } + + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + _, response, err := adminServiceApiClient.GetSettingsWithContext(context, getSettingsOptions) + if err != nil { + log.Printf("[DEBUG] PatchAccountSettingsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("PatchAccountSettingsWithContext failed %s\n%s", err, response)) + } + // Set the object to a empty string so Terraform deletes the object + d.SetId("") + + return nil +} + +func resourceIbmSccAccountSettingsMapToLocationID(modelMap map[string]interface{}) (*adminserviceapiv1.LocationID, error) { + model := &adminserviceapiv1.LocationID{} + model.ID = core.StringPtr(modelMap["location_id"].(string)) + return model, nil +} + +func resourceIbmSccAccountSettingsMapToNotificationsRegistration(modelMap map[string]interface{}) (*adminserviceapiv1.NotificationsRegistration, error) { + model := &adminserviceapiv1.NotificationsRegistration{} + model.InstanceCrn = core.StringPtr(modelMap["instance_crn"].(string)) + return model, nil +} + +func resourceIbmSccAccountSettingsLocationIDToMap(model *adminserviceapiv1.LocationID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["location_id"] = model.ID + return modelMap, nil +} + +func resourceIbmSccAccountSettingsNotificationsRegistrationToMap(model *adminserviceapiv1.NotificationsRegistration) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + + // if len(*model.InstanceCrn) > 0 { + modelMap["instance_crn"] = model.InstanceCrn + // } + return modelMap, nil +} diff --git a/ibm/service/scc/resource_ibm_scc_account_settings_test.go b/ibm/service/scc/resource_ibm_scc_account_settings_test.go new file mode 100644 index 000000000..4d092f7bd --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_account_settings_test.go @@ -0,0 +1,124 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/scc-go-sdk/v3/adminserviceapiv1" +) + +func TestAccIbmSccAccountSettingsBasic(t *testing.T) { + var conf adminserviceapiv1.AccountSettings + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmSccAccountSettingsDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSccAccountSettingsConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSccAccountSettingsExists("ibm_scc_account_settings.scc_account_settings", conf), + resource.TestCheckResourceAttr( + "ibm_scc_account_settings.scc_account_settings", + "location.0.location_id", + "us", + ), + resource.TestCheckResourceAttr( + "ibm_scc_account_settings.scc_account_settings", + "event_notifications.#", + "1", + ), + ), + // ExpectNonEmptyPlan: true, + }, + resource.TestStep{ + ResourceName: "ibm_scc_account_settings.scc_account_settings", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmSccAccountSettingsConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_scc_account_settings" "scc_account_settings" { + location { + location_id = "us" + } + event_notifications { + } + } + `) +} + +func testAccCheckIbmSccAccountSettingsExists(n string, obj adminserviceapiv1.AccountSettings) resource.TestCheckFunc { + + return func(s *terraform.State) error { + // rs, ok := s.RootModule().Resources[n] + _, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + adminServiceApiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return err + } + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + accountSettings, _, err := adminServiceApiClient.GetSettings(getSettingsOptions) + if err != nil { + return err + } + + obj = *accountSettings + return nil + } +} + +func testAccCheckIbmSccAccountSettingsDestroy(s *terraform.State) error { + adminServiceApiClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).AdminServiceApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_account_settings" { + continue + } + + getSettingsOptions := &adminserviceapiv1.GetSettingsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + getSettingsOptions.SetAccountID(userDetails.UserAccount) + + // Try to find the key + _, response, err := adminServiceApiClient.GetSettings(getSettingsOptions) + if response.StatusCode == 404 { + return fmt.Errorf("Error checking for scc_account_settings (%s) has been destroyed: %s", rs.Primary.ID, err) + } + + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_account_settings_validator.go b/ibm/service/scc/resource_ibm_scc_account_settings_validator.go new file mode 100644 index 000000000..e907259a3 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_account_settings_validator.go @@ -0,0 +1,24 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMSccAccountSettingsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 2) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location_id", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "us, eu, uk", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_account_settings", Schema: validateSchema} + return &resourceValidator +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_collector.go b/ibm/service/scc/resource_ibm_scc_posture_collector.go new file mode 100644 index 000000000..9948f6a2d --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_collector.go @@ -0,0 +1,232 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func ResourceIBMSccPostureCollectors() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccPostureCollectorsCreate, + ReadContext: resourceIBMSccPostureCollectorsRead, + UpdateContext: resourceIBMSccPostureCollectorsUpdate, + DeleteContext: resourceIBMSccPostureCollectorsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_collector", "name"), + Description: "A unique name for your collector.", + }, + "is_public": { + Type: schema.TypeBool, + Required: true, + Description: "Determines whether the collector endpoint is accessible on a public network. If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + }, + "managed_by": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_collector", "managed_by"), + Description: "Determines whether the collector is an IBM or customer-managed virtual machine. Use `ibm` to allow Security and Compliance Center to create, install, and manage the collector on your behalf. The collector is installed in an OpenShift cluster and approved automatically for use. Use `customer` if you would like to install the collector by using your own virtual machine. For more information, check out the [docs](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-collector).", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Default: "", + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_collector", "description"), + Description: "A detailed description of the collector.", + }, + "passphrase": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_collector", "passphrase"), + Description: "To protect the credentials that you add to the service, a passphrase is used to generate a data encryption key. The key is used to securely store your credentials and prevent anyone from accessing them.", + }, + "is_ubi_image": { + Type: schema.TypeBool, + Optional: true, + Description: "Determines whether the collector has a Ubi image.", + }, + }, + } +} + +func ResourceIBMSccPostureCollectorsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-.,_\s]*$`, + MinValueLength: 3, + MaxValueLength: 46, + }, + validate.ValidateSchema{ + Identifier: "managed_by", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "customer, ibm", + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9-._,\s]*$`, + MinValueLength: 1, + MaxValueLength: 255, + }, + validate.ValidateSchema{ + Identifier: "passphrase", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9-._,\s]*$`, + MinValueLength: 1, + MaxValueLength: 255, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_collectors", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSccPostureCollectorsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + createCollectorOptions := &posturemanagementv2.CreateCollectorOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + createCollectorOptions.SetAccountID(userDetails.UserAccount) + + createCollectorOptions.SetName(d.Get("name").(string)) + createCollectorOptions.SetIsPublic(d.Get("is_public").(bool)) + createCollectorOptions.SetManagedBy(d.Get("managed_by").(string)) + if _, ok := d.GetOk("description"); ok { + createCollectorOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("passphrase"); ok { + createCollectorOptions.SetPassphrase(d.Get("passphrase").(string)) + } + if _, ok := d.GetOk("is_ubi_image"); ok { + createCollectorOptions.SetIsUbiImage(d.Get("is_ubi_image").(bool)) + } + + collector, response, err := postureManagementClient.CreateCollectorWithContext(context, createCollectorOptions) + if err != nil { + log.Printf("[DEBUG] CreateCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateCollectorWithContext failed %s\n%s", err, response)) + } + + d.SetId(*collector.ID) + + return resourceIBMSccPostureCollectorsRead(context, d, meta) +} + +func resourceIBMSccPostureCollectorsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getCollectorsOptions := &posturemanagementv2.GetCollectorOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getCollectorsOptions.SetAccountID(accountID) + getCollectorsOptions.SetID(d.Id()) + + collector, response, err := postureManagementClient.GetCollectorWithContext(context, getCollectorsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCollectorWithContext failed %s\n%s", err, response)) + } + d.SetId(*(collector.ID)) + return nil +} + +func resourceIBMSccPostureCollectorsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + updateCollectorOptions := &posturemanagementv2.UpdateCollectorOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + updateCollectorOptions.SetAccountID(userDetails.UserAccount) + + updateCollectorOptions.SetID(d.Id()) + + hasChange := false + + if hasChange { + //updateCollectorOptions.CollectorUpdatePatch, _ = patchVals.AsPatch() + _, response, err := postureManagementClient.UpdateCollectorWithContext(context, updateCollectorOptions) + if err != nil { + log.Printf("[DEBUG] UpdateCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateCollectorWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccPostureCollectorsRead(context, d, meta) +} + +func resourceIBMSccPostureCollectorsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + deleteCollectorOptions := &posturemanagementv2.DeleteCollectorOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + deleteCollectorOptions.SetAccountID(userDetails.UserAccount) + + deleteCollectorOptions.SetID(d.Id()) + + response, err := postureManagementClient.DeleteCollectorWithContext(context, deleteCollectorOptions) + if err != nil { + log.Printf("[DEBUG] DeleteCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteCollectorWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_collector_test.go b/ibm/service/scc/resource_ibm_scc_posture_collector_test.go new file mode 100644 index 000000000..78f18537f --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_collector_test.go @@ -0,0 +1,193 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func TestAccIBMSccPostureCollectorsBasic(t *testing.T) { + var conf posturemanagementv2.Collector + name := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + isPublic := "true" + managedBy := "customer" + nameUpdate := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + isPublicUpdate := "true" + managedByUpdate := "customer" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccPostureCollectorsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureCollectorsConfigBasic(name, isPublic, managedBy), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureCollectorsExists("ibm_scc_posture_collector.collectors", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "name", name), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_public", isPublic), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "managed_by", managedBy), + ), + }, + { + Config: testAccCheckIBMSccPostureCollectorsConfigBasic(nameUpdate, isPublicUpdate, managedByUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_public", isPublicUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "managed_by", managedByUpdate), + ), + }, + }, + }) +} + +func TestAccIBMCollectorsAllArgs(t *testing.T) { + var conf posturemanagementv2.Collector + name := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + isPublic := "false" + managedBy := "ibm" + description := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + passphrase := fmt.Sprintf("tf_passphrase_%d", time.Now().UnixNano()) + isUbiImage := "true" + nameUpdate := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + isPublicUpdate := "true" + managedByUpdate := "customer" + descriptionUpdate := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + passphraseUpdate := fmt.Sprintf("tf_passphrase_%d", time.Now().UnixNano()) + isUbiImageUpdate := "false" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccPostureCollectorsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureCollectorsConfig(name, isPublic, managedBy, description, passphrase, isUbiImage), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureCollectorsExists("ibm_scc_posture_collector.collectors", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "name", name), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_public", isPublic), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "managed_by", managedBy), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "description", description), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "passphrase", passphrase), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_ubi_image", isUbiImage), + ), + }, + { + Config: testAccCheckIBMSccPostureCollectorsConfig(nameUpdate, isPublicUpdate, managedByUpdate, descriptionUpdate, passphraseUpdate, isUbiImageUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_public", isPublicUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "managed_by", managedByUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "passphrase", passphraseUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_collector.collectors", "is_ubi_image", isUbiImageUpdate), + ), + }, + { + ResourceName: "ibm_scc_posture_collector.collectors", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccPostureCollectorsConfigBasic(name string, isPublic string, managedBy string) string { + return fmt.Sprintf(` + + resource "ibm_scc_posture_collector" "collectors" { + name = "%s" + is_public = %s + managed_by = "%s" + } + `, name, isPublic, managedBy) +} + +func testAccCheckIBMSccPostureCollectorsConfig(name string, isPublic string, managedBy string, description string, passphrase string, isUbiImage string) string { + return fmt.Sprintf(` + + resource "ibm_scc_posture_collector" "collectors" { + name = "%s" + is_public = %s + managed_by = "%s" + description = "%s" + passphrase = "%s" + is_ubi_image = %s + } + `, name, isPublic, managedBy, description, passphrase, isUbiImage) +} + +func testAccCheckIBMSccPostureCollectorsExists(n string, obj posturemanagementv2.Collector) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + + listCollectorsOptions := &posturemanagementv2.ListCollectorsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + listCollectorsOptions.SetAccountID(userDetails.UserAccount) + + newCollector, _, err := postureManagementClient.ListCollectors(listCollectorsOptions) + if err != nil { + return err + } + fmt.Println(rs) + obj = (newCollector.Collectors[0]) + return nil + } +} + +func testAccCheckIBMSccPostureCollectorsDestroy(s *terraform.State) error { + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_posture_collector" { + continue + } + + listCollectorsOptions := &posturemanagementv2.ListCollectorsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + listCollectorsOptions.SetAccountID(userDetails.UserAccount) + + // Try to find the key + _, response, err := postureManagementClient.ListCollectors(listCollectorsOptions) + + if err == nil { + return err //fmt.Errorf("collectors still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for collectors (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_credential.go b/ibm/service/scc/resource_ibm_scc_posture_credential.go new file mode 100644 index 000000000..fed69a8a3 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_credential.go @@ -0,0 +1,321 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func ResourceIBMSccPostureCredentials() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccPostureCredentialsCreate, + ReadContext: resourceIBMSccPostureCredentialsRead, + UpdateContext: resourceIBMSccPostureCredentialsUpdate, + DeleteContext: resourceIBMSccPostureCredentialsDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "Credentials status enabled/disbaled.", + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_credential", "type"), + Description: "Credentials type.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_credential", "name"), + Description: "Credentials name.", + }, + "description": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_credential", "description"), + Description: "Credentials description.", + }, + "display_fields": { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Details the fields on the credential. This will change as per credential type selected.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ibm_api_key": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM Cloud API Key. This is mandatory for IBM Credential Type ie when type=ibm_cloud.", + }, + }, + }, + }, + "group": { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Credential group details.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "credential group id.", + }, + "passphrase": { + Type: schema.TypeString, + Required: true, + Description: "passphase of the credential.", + }, + }, + }, + }, + "purpose": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_credential", "purpose"), + Description: "Purpose for which the credential is created.", + }, + }, + } +} + +func ResourceIBMSccPostureCredentialsValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "aws_cloud, azure_cloud, database, ibm_cloud, kerberos_windows, ms_365, openstack_cloud, username_password", + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-._,\s]*$`, + MinValueLength: 3, + MaxValueLength: 30, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-._,\s]*$`, + MinValueLength: 1, + MaxValueLength: 255, + }, + validate.ValidateSchema{ + Identifier: "purpose", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "discovery_collection, discovery_collection_remediation, discovery_fact_collection, discovery_fact_collection_remediation, remediation", + Regexp: `^[a-zA-Z0-9-\\.,_\\s]*$`, + MinValueLength: 1, + MaxValueLength: 100, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_posture_credentials", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSccPostureCredentialsCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + createCredentialOptions := &posturemanagementv2.CreateCredentialOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + createCredentialOptions.SetAccountID(userDetails.UserAccount) + + createCredentialOptions.SetEnabled(d.Get("enabled").(bool)) + createCredentialOptions.SetType(d.Get("type").(string)) + createCredentialOptions.SetName(d.Get("name").(string)) + createCredentialOptions.SetDescription(d.Get("description").(string)) + displayFields := resourceIBMSccPostureCredentialsMapToNewCredentialDisplayFields(d.Get("display_fields.0").(map[string]interface{})) + createCredentialOptions.SetDisplayFields(&displayFields) + group := resourceIBMSccPostureCredentialsMapToCredentialGroup(d.Get("group.0").(map[string]interface{})) + createCredentialOptions.SetGroup(&group) + createCredentialOptions.SetPurpose(d.Get("purpose").(string)) + + credential, response, err := postureManagementClient.CreateCredentialWithContext(context, createCredentialOptions) + if err != nil { + log.Printf("[DEBUG] CreateCredentialWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateCredentialWithContext failed %s\n%s", err, response)) + } + + d.SetId(*credential.ID) + + return resourceIBMSccPostureCredentialsRead(context, d, meta) +} + +func resourceIBMSccPostureCredentialsMapToNewCredentialDisplayFields(newCredentialDisplayFieldsMap map[string]interface{}) posturemanagementv2.NewCredentialDisplayFields { + newCredentialDisplayFields := posturemanagementv2.NewCredentialDisplayFields{} + + if newCredentialDisplayFieldsMap["ibm_api_key"] != nil { + newCredentialDisplayFields.IBMAPIKey = core.StringPtr(newCredentialDisplayFieldsMap["ibm_api_key"].(string)) + } + + return newCredentialDisplayFields +} + +func resourceIBMSccPostureCredentialsMapToUpdateCredentialDisplayFields(updateCredentialDisplayFieldsMap map[string]interface{}) posturemanagementv2.UpdateCredentialDisplayFields { + updateCredentialDisplayFields := posturemanagementv2.UpdateCredentialDisplayFields{} + + if updateCredentialDisplayFieldsMap["ibm_api_key"] != nil { + updateCredentialDisplayFields.IBMAPIKey = core.StringPtr(updateCredentialDisplayFieldsMap["ibm_api_key"].(string)) + } + + return updateCredentialDisplayFields +} + +func resourceIBMSccPostureCredentialsMapToCredentialGroup(credentialGroupMap map[string]interface{}) posturemanagementv2.CredentialGroup { + credentialGroup := posturemanagementv2.CredentialGroup{} + + credentialGroup.ID = core.StringPtr(credentialGroupMap["id"].(string)) + credentialGroup.Passphrase = core.StringPtr(credentialGroupMap["passphrase"].(string)) + + return credentialGroup +} + +func resourceIBMSccPostureCredentialsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getCredentialsOptions := &posturemanagementv2.GetCredentialOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getCredentialsOptions.SetAccountID(accountID) + getCredentialsOptions.SetID(d.Id()) + + credential, response, err := postureManagementClient.GetCredentialWithContext(context, getCredentialsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetCredentialWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetCredentialWithContext failed %s\n%s", err, response)) + } + d.SetId(*(credential.ID)) + return nil +} + +func resourceIBMSccPostureCredentialsNewCredentialDisplayFieldsToMap(newCredentialDisplayFields posturemanagementv2.NewCredentialDisplayFields) map[string]interface{} { + newCredentialDisplayFieldsMap := map[string]interface{}{} + + if newCredentialDisplayFields.IBMAPIKey != nil { + newCredentialDisplayFieldsMap["ibm_api_key"] = newCredentialDisplayFields.IBMAPIKey + } + + return newCredentialDisplayFieldsMap +} + +func resourceIBMCredentialsCredentialGroupToMap(credentialGroup posturemanagementv2.CredentialGroup) map[string]interface{} { + credentialGroupMap := map[string]interface{}{} + + credentialGroupMap["id"] = credentialGroup.ID + credentialGroupMap["passphrase"] = credentialGroup.Passphrase + + return credentialGroupMap +} + +func resourceIBMSccPostureCredentialsUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + updateCredentialOptions := &posturemanagementv2.UpdateCredentialOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + updateCredentialOptions.SetAccountID(userDetails.UserAccount) + + updateCredentialOptions.SetID(d.Id()) + + updateCredentialOptions.SetEnabled(d.Get("enabled").(bool)) + + updateCredentialOptions.SetType(d.Get("type").(string)) + + updateCredentialOptions.SetName(d.Get("name").(string)) + + updateCredentialOptions.SetDescription(d.Get("description").(string)) + + updateCredentialDisplayFieldsModel := &posturemanagementv2.UpdateCredentialDisplayFields{ + IBMAPIKey: core.StringPtr("sample_api_key"), + } + //displayFields := resourceIBMSccPostureV2CredentialsMapToUpdateCredentialDisplayFields(d.Get("display_fields.0").(map[string]interface{})) + updateCredentialOptions.SetDisplayFields(updateCredentialDisplayFieldsModel) + + updateCredentialOptions.SetPurpose(d.Get("purpose").(string)) + + _, response, err := postureManagementClient.UpdateCredentialWithContext(context, updateCredentialOptions) + if err != nil { + log.Printf("[DEBUG] UpdateCredentialWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateCredentialWithContext failed %s\n%s", err, response)) + } + + return resourceIBMSccPostureCredentialsRead(context, d, meta) +} + +func resourceIBMSccPostureCredentialsDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + deleteCredentialOptions := &posturemanagementv2.DeleteCredentialOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + deleteCredentialOptions.SetAccountID(userDetails.UserAccount) + + deleteCredentialOptions.SetID(d.Id()) + + response, err := postureManagementClient.DeleteCredentialWithContext(context, deleteCredentialOptions) + if err != nil { + log.Printf("[DEBUG] DeleteCredentialWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteCredentialWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_credential_test.go b/ibm/service/scc/resource_ibm_scc_posture_credential_test.go new file mode 100644 index 000000000..7253eed8d --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_credential_test.go @@ -0,0 +1,150 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func TestAccIBMSccPostureCredentialsBasic(t *testing.T) { + var conf posturemanagementv2.Credential + enabled := "true" + typeVar := "ibm_cloud" + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + purpose := "discovery_collection" + enabledUpdate := "true" + typeVarUpdate := "ibm_cloud" + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + purposeUpdate := "discovery_fact_collection_remediation" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccPostureCredentialsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureCredentialsConfigBasic(enabled, typeVar, name, description, purpose), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureCredentialsExists("ibm_scc_posture_credential.credentials", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "enabled", enabled), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "type", typeVar), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "name", name), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "description", description), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "purpose", purpose), + ), + }, + { + Config: testAccCheckIBMSccPostureCredentialsConfigBasic(enabledUpdate, typeVarUpdate, nameUpdate, descriptionUpdate, purposeUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureCredentialsExists("ibm_scc_posture_credential.credentials", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "enabled", enabledUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "type", typeVarUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_credential.credentials", "purpose", purposeUpdate), + ), + }, + { + ResourceName: "ibm_scc_posture_credential.credentials", + ImportState: true, + //ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccPostureCredentialsConfigBasic(enabled string, typeVar string, name string, description string, purpose string) string { + return fmt.Sprintf(` + + resource "ibm_scc_posture_credential" "credentials" { + enabled = %s + type = "%s" + name = "%s" + description = "%s" + display_fields { + ibm_api_key = "sample_api_key" + + } + group { + id = "1" + passphrase = "passphrase" + } + purpose = "%s" + } + `, enabled, typeVar, name, description, purpose) +} + +func testAccCheckIBMSccPostureCredentialsExists(n string, obj posturemanagementv2.Credential) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + + listCredentialsOptions := &posturemanagementv2.ListCredentialsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + listCredentialsOptions.SetAccountID(userDetails.UserAccount) + + newCredential, _, err := postureManagementClient.ListCredentials(listCredentialsOptions) + if err != nil { + return err + } + fmt.Println(rs) + obj = (newCredential.Credentials[0]) + return nil + } +} + +func testAccCheckIBMSccPostureCredentialsDestroy(s *terraform.State) error { + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_posture_credential" { + continue + } + + listCredentialsOptions := &posturemanagementv2.ListCredentialsOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + listCredentialsOptions.SetAccountID(userDetails.UserAccount) + + // Try to find the key + _, response, err := postureManagementClient.ListCredentials(listCredentialsOptions) + + if err == nil { + return nil + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for credentials (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_import_profile.go b/ibm/service/scc/resource_ibm_scc_posture_import_profile.go new file mode 100644 index 000000000..61dd3743f --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_import_profile.go @@ -0,0 +1,192 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMSccPostureProfileImport() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccPostureProfileImport, + ReadContext: resourceIBMSccPostureProfileImportRead, + UpdateContext: resourceIBMSccPostureProfileImportRead, + DeleteContext: resourceIBMSccPostureProfileImportDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "file": { + Type: schema.TypeString, + Description: "File to import", + Required: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name of the profile.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "A description of the profile.", + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "The version of the profile.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who created the profile.", + }, + "modified_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user who last modified the profile.", + }, + "base_profile": { + Type: schema.TypeString, + Computed: true, + Description: "The base profile that the controls are pulled from.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of profile.", + }, + "no_of_controls": { + Type: schema.TypeInt, + Computed: true, + Description: "no of Controls.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was created in UTC.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The time that the profile was most recently modified in UTC.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + }, + }, + } +} + +func resourceIBMSccPostureProfileImport(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + importProfilesOptions := &posturemanagementv2.ImportProfilesOptions{} + accountID := userDetails.UserAccount + importProfilesOptions.SetAccountID(accountID) + + f, err := os.Open(d.Get("file").(string)) + if err != nil { + log.Printf("[DEBUG] ImportProfilesWithContext failed to read file %s", err) + return diag.FromErr(fmt.Errorf("ImportProfilesWithContext failed to read file %s", err)) + } + importProfilesOptions.SetFile(f) + + profile, response, err := postureManagementClient.ImportProfilesWithContext(context, importProfilesOptions) + if err != nil { + log.Printf("[DEBUG] ImportProfilesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ImportProfilesWithContext failed %s\n%s", err, response)) + } + + d.SetId(*profile.ProfileID) + + return resourceIBMSccPostureProfileImportRead(context, d, meta) +} + +func resourceIBMSccPostureProfileImportRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getProfileOptions := &posturemanagementv2.GetProfileOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getProfileOptions.SetAccountID(accountID) + + getProfileOptions.SetID(d.Id()) + getProfileOptions.SetProfileType("custom") + + profile, response, err := postureManagementClient.GetProfileWithContext(context, getProfileOptions) + if err != nil { + log.Printf("[DEBUG] GetProfileWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetProfileWithContext failed %s\n%s", err, response)) + } + + d.SetId(*profile.ID) + if err = d.Set("name", profile.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", profile.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("version", flex.IntValue(profile.Version)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + if err = d.Set("created_by", profile.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("modified_by", profile.ModifiedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting modified_by: %s", err)) + } + if err = d.Set("base_profile", profile.BaseProfile); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting base_profile: %s", err)) + } + if err = d.Set("type", profile.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("no_of_controls", flex.IntValue(profile.NoOfControls)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting no_of_controls: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(profile.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(profile.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("enabled", profile.Enabled); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enabled: %s", err)) + } + + return nil +} + +func resourceIBMSccPostureProfileImportDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_import_profile_test.go b/ibm/service/scc/resource_ibm_scc_posture_import_profile_test.go new file mode 100644 index 000000000..60c33c874 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_import_profile_test.go @@ -0,0 +1,77 @@ +package scc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMSccPostureProfileImportBasic(t *testing.T) { + name := "ibm_scc_posture_profile_import." + "profiles" + file := "../../test-fixtures/import_profile.csv" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckSccPostureProfileImportConfigBasic(file), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(name, "file", file), + resource.TestCheckResourceAttr(name, "enabled", "true"), + resource.TestCheckResourceAttr(name, "type", "custom"), + testAccCheckSccPostureProfileImportRemoveImportedRecords(name), + ), + }, + { + ResourceName: name, + ImportState: true, + }, + }, + }) +} + +func testAccCheckSccPostureProfileImportConfigBasic(file string) string { + return fmt.Sprintf(` + resource "ibm_scc_posture_profile_import" "profiles" { + file = "%[1]s" + }`, file) +} + +func testAccCheckSccPostureProfileImportRemoveImportedRecords(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("[ERROR] Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No Record ID is set") + } + deleteProfileOptions := &posturemanagementv2.DeleteProfileOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + accountID := userDetails.UserAccount + deleteProfileOptions.SetAccountID(accountID) + + deleteProfileOptions.SetID(rs.Primary.ID) + _, err = postureManagementClient.DeleteProfile(deleteProfileOptions) + if err != nil { + return err + } + return nil + } +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation.go b/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation.go new file mode 100644 index 000000000..518c20329 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation.go @@ -0,0 +1,208 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMSccPostureScanInitiateValidation() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccPostureScanInitiateValidation, + ReadContext: resourceIBMSccPostureScanInitiateRead, + DeleteContext: resourceIBMSccPostureScanInitiateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "scope_id": { + Type: schema.TypeString, + Description: "The unique ID of the scope.", + ForceNew: true, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scan_initiate_validation", "scope_id"), + }, + "profile_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique ID of the profile.", + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scan_initiate_validation", "profile_id"), + }, + "group_profile_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The ID of the profile group.", + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scan_initiate_validation", "group_profile_id"), + }, + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The name of a scheduled scan.", + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scan_initiate_validation", "name"), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The description of a scheduled scan.", + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scan_initiate_validation", "description"), + }, + "frequency": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "The frequency at which a scan is run specified in milliseconds.", + }, + "no_of_occurrences": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "The number of times that a scan should be run.", + }, + "end_time": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The date on which a scan should stop running specified in UTC.", + }, + "result": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the profile group.", + }, + }, + } +} + +func ResourceIBMSccPostureScanInitiateValidationValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "scope_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9]*$`, + MinValueLength: 1, + MaxValueLength: 20, + }, + validate.ValidateSchema{ + Identifier: "profile_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9]*$`, + MinValueLength: 1, + MaxValueLength: 20, + }, + validate.ValidateSchema{ + Identifier: "group_profile_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[0-9]*$`, + MinValueLength: 1, + MaxValueLength: 20, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9-\.,_\s]*$`, + MinValueLength: 1, + MaxValueLength: 32, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z0-9-._,\s]*$`, + MinValueLength: 1, + MaxValueLength: 255, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_posture_scan_initiate_validation", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSccPostureScanInitiateValidation(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + createValidationOptions := &posturemanagementv2.CreateValidationOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + createValidationOptions.SetAccountID(userDetails.UserAccount) + + createValidationOptions.SetScopeID(d.Get("scope_id").(string)) + createValidationOptions.SetProfileID(d.Get("profile_id").(string)) + + if _, ok := d.GetOk("group_profile_id"); ok { + createValidationOptions.SetGroupProfileID(d.Get("group_profile_id").(string)) + } + + if _, ok := d.GetOk("name"); ok { + createValidationOptions.SetName(d.Get("name").(string)) + } + + if _, ok := d.GetOk("description"); ok { + createValidationOptions.SetDescription(d.Get("description").(string)) + } + + if frequency, ok := d.GetOk("frequency"); ok { + createValidationOptions.SetFrequency(int64(frequency.(int))) + } + + if no_of_occurrences, ok := d.GetOk("no_of_occurrences"); ok { + createValidationOptions.SetNoOfOccurrences(int64(no_of_occurrences.(int))) + } + + if end_time, ok := d.GetOk("end_time"); ok { + createValidationOptions.SetEndTime(end_time.(*strfmt.DateTime)) + } + + result, response, err := postureManagementClient.CreateValidationWithContext(context, createValidationOptions) + if result == nil || err != nil { + log.Printf("[DEBUG] CreateValidationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateValidationWithContext failed %s\n%s", err, response)) + } + + if *result.Result { + correlationId := strings.Split(*result.Message, "= ")[1] + d.SetId(correlationId) + d.Set("result", fmt.Sprintf("%v", *result.Result)) + return nil + } + + return diag.FromErr(fmt.Errorf("CreateValidationWithContext failed %s\n%s", err, *result.Message)) +} + +func resourceIBMSccPostureScanInitiateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func resourceIBMSccPostureScanInitiateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation_test.go b/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation_test.go new file mode 100644 index 000000000..137f978e9 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_scan_initiate_validation_test.go @@ -0,0 +1,40 @@ +package scc_test + +import ( + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSccPostureScanInitiateValidationBasic(t *testing.T) { + name := "ibm_scc_posture_scan_initiate_validation." + "scans" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckSccPostureScanInitiateValidationConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(name, "result", "true"), + ), + }, + { + ResourceName: name, + ImportState: true, + }, + }, + }) +} + +func testAccCheckSccPostureScanInitiateValidationConfigBasic() string { + return `resource "ibm_scc_posture_scan_initiate_validation" "scans" { + scope_id = "70324" + profile_id = "425" + name = "Test1Sept22_Scan" + description = "Test1Sept22_Scan on scope 70324" + frequency = 6300 + no_of_occurrences = 9 + }` +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_scope.go b/ibm/service/scc/resource_ibm_scc_posture_scope.go new file mode 100644 index 000000000..21644b7a8 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_scope.go @@ -0,0 +1,235 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func ResourceIBMSccPostureScopes() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccPostureScopesCreate, + ReadContext: resourceIBMSccPostureScopesRead, + UpdateContext: resourceIBMSccPostureScopesUpdate, + DeleteContext: resourceIBMSccPostureScopesDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scope", "name"), + Description: "A unique name for your scope.", + }, + "description": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scope", "description"), + Description: "A detailed description of the scope.", + }, + "collector_ids": { + Type: schema.TypeList, + Required: true, + Description: "The unique IDs of the collectors that are attached to the scope.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "credential_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scope", "credential_id"), + Description: "The unique identifier of the credential.", + }, + "credential_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_scc_posture_scope", "credential_type"), + Description: "The environment that the scope is targeted to.", + }, + }, + } +} + +func ResourceIBMSccPostureScopesValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-\\.,_\s]*$`, + MinValueLength: 3, + MaxValueLength: 50, + }, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-\\.,_\s]*$`, + MinValueLength: 1, + MaxValueLength: 255, + }, + validate.ValidateSchema{ + Identifier: "credential_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9-\\.,_\\s]*$`, + MinValueLength: 1, + MaxValueLength: 50, + }, + validate.ValidateSchema{ + Identifier: "credential_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "aws, azure, gcp, hosted, ibm, on_premise, openstack, services", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_posture_scope", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSccPostureScopesCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + createScopeOptions := &posturemanagementv2.CreateScopeOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + createScopeOptions.SetAccountID(userDetails.UserAccount) + + createScopeOptions.SetName(d.Get("name").(string)) + createScopeOptions.SetDescription(d.Get("description").(string)) + collector_ids_int := d.Get("collector_ids").([]interface{}) + collector_ids := make([]string, len(collector_ids_int)) + for i, collector_id := range collector_ids_int { + collector_ids[i] = collector_id.(string) + } + createScopeOptions.SetCollectorIds(collector_ids) //[]string{ + createScopeOptions.SetCredentialID(d.Get("credential_id").(string)) + createScopeOptions.SetCredentialType(d.Get("credential_type").(string)) + + scope, response, err := postureManagementClient.CreateScopeWithContext(context, createScopeOptions) + if err != nil { + log.Printf("[DEBUG] CreateScopeWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateScopeWithContext failed %s\n%s", err, response)) + } + + d.SetId(*scope.ID) + + return resourceIBMSccPostureScopesRead(context, d, meta) +} + +func resourceIBMSccPostureScopesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + getScopesOptions := &posturemanagementv2.GetScopeDetailsOptions{} + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + + accountID := userDetails.UserAccount + getScopesOptions.SetAccountID(accountID) + getScopesOptions.SetID(d.Id()) + + scope, response, err := postureManagementClient.GetScopeDetailsWithContext(context, getScopesOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetScopeDetailsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetScopeDetailsWithContext failed %s\n%s", err, response)) + } + d.SetId(*scope.ID) + + return nil +} + +func resourceIBMSccPostureScopesUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + updateScopeDetailsOptions := &posturemanagementv2.UpdateScopeDetailsOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + updateScopeDetailsOptions.SetAccountID(userDetails.UserAccount) + + hasChange := false + + updateScopeDetailsOptions.SetID(d.Id()) + + if d.HasChange("name") { + updateScopeDetailsOptions.SetName(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("description") { + updateScopeDetailsOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + + if hasChange { + _, response, err := postureManagementClient.UpdateScopeDetailsWithContext(context, updateScopeDetailsOptions) + if err != nil { + log.Printf("[DEBUG] UpdateScopeDetailsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateScopeDetailsWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccPostureScopesRead(context, d, meta) +} + +func resourceIBMSccPostureScopesDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + postureManagementClient, err := meta.(conns.ClientSession).PostureManagementV2() + if err != nil { + return diag.FromErr(err) + } + + deleteScopeOptions := &posturemanagementv2.DeleteScopeOptions{} + + userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting userDetails %s", err)) + } + deleteScopeOptions.SetAccountID(userDetails.UserAccount) + + deleteScopeOptions.SetID(d.Id()) + + response, err := postureManagementClient.DeleteScopeWithContext(context, deleteScopeOptions) + if err != nil { + log.Printf("[DEBUG] DeleteScopeWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteScopeWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_posture_scope_test.go b/ibm/service/scc/resource_ibm_scc_posture_scope_test.go new file mode 100644 index 000000000..222466f45 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_posture_scope_test.go @@ -0,0 +1,185 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/scc-go-sdk/v4/posturemanagementv2" +) + +func TestAccIBMSccPostureScopesBasic(t *testing.T) { + var conf posturemanagementv2.ScopeItem + name := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + description := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + credentialType := "ibm" + nameUpdate := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + descriptionUpdate := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + credentialTypeUpdate := "ibm" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccPostureScopesDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureScopesConfigBasic(name, description, acc.Scc_posture_credential_id_scope, credentialType, acc.Scc_posture_collector_id_scope), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureScopesExists("ibm_scc_posture_scope.scopes", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "name", name), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "description", description), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_id", acc.Scc_posture_credential_id_scope), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_type", credentialType), + ), + }, + { + Config: testAccCheckIBMSccPostureScopesConfigBasic(nameUpdate, descriptionUpdate, acc.Scc_posture_credential_id_scope_update, credentialTypeUpdate, acc.Scc_posture_collector_id_scope_update), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_id", acc.Scc_posture_credential_id_scope_update), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_type", credentialTypeUpdate), + ), + }, + }, + }) +} + +func TestAccIBMScopesAllArgs(t *testing.T) { + var conf posturemanagementv2.ScopeItem + name := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + description := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + credentialType := "ibm" + nameUpdate := fmt.Sprintf("tf_name_%d", time.Now().UnixNano()) + descriptionUpdate := fmt.Sprintf("tf_description_%d", time.Now().UnixNano()) + credentialTypeUpdate := "ibm" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccPostureScopesDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSccPostureScopesConfig(name, description, acc.Scc_posture_credential_id_scope, credentialType, acc.Scc_posture_collector_id_scope), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccPostureScopesExists("ibm_scc_posture_scope.scopes", conf), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "name", name), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "description", description), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_id", acc.Scc_posture_credential_id_scope), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_type", credentialType), + ), + }, + { + Config: testAccCheckIBMSccPostureScopesConfig(nameUpdate, descriptionUpdate, acc.Scc_posture_credential_id_scope_update, credentialTypeUpdate, acc.Scc_posture_collector_id_scope_update), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_id", acc.Scc_posture_credential_id_scope_update), + resource.TestCheckResourceAttr("ibm_scc_posture_scope.scopes", "credential_type", credentialTypeUpdate), + ), + }, + { + ResourceName: "ibm_scc_posture_scope.scopes", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccPostureScopesConfigBasic(name string, description string, credentialID string, credentialType string, collectorID []string) string { + return fmt.Sprintf(` + + resource "ibm_scc_posture_scope" "scopes" { + name = "%s" + description = "%s" + credential_id = "%s" + credential_type = "%s" + collector_ids = %q + } + `, name, description, credentialID, credentialType, collectorID) +} + +func testAccCheckIBMSccPostureScopesConfig(name string, description string, credentialID string, credentialType string, collectorID []string) string { + return fmt.Sprintf(` + + resource "ibm_scc_posture_scope" "scopes" { + name = "%s" + description = "%s" + credential_id = "%s" + credential_type = "%s" + collector_ids = %q + } + `, name, description, credentialID, credentialType, collectorID) +} + +func testAccCheckIBMSccPostureScopesExists(n string, obj posturemanagementv2.ScopeItem) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + + listScopesOptions := &posturemanagementv2.ListScopesOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + listScopesOptions.SetAccountID(userDetails.UserAccount) + + newScope, _, err := postureManagementClient.ListScopes(listScopesOptions) + if err != nil { + return err + } + fmt.Println(rs) + obj = (newScope.Scopes[0]) + return nil + } +} + +func testAccCheckIBMSccPostureScopesDestroy(s *terraform.State) error { + postureManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).PostureManagementV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_posture_scope" { + continue + } + + listScopesOptions := &posturemanagementv2.ListScopesOptions{} + + userDetails, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + if err != nil { + return err + } + + listScopesOptions.SetAccountID(userDetails.UserAccount) + + // Try to find the key + _, response, err := postureManagementClient.ListScopes(listScopesOptions) + + if err == nil { + return err + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for scopes (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_rule.go b/ibm/service/scc/resource_ibm_scc_rule.go new file mode 100644 index 000000000..966ae504a --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule.go @@ -0,0 +1,1079 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +// Functions that were changed for validation: +// - resourceIBMSccRuleMapToRuleCondition +// - resourceIBMSccRuleMapToRuleSingleProperty + +const maxDepth = 1 + +func ResourceIBMSccRule() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccRuleCreate, + ReadContext: resourceIBMSccRuleRead, + UpdateContext: resourceIBMSccRuleUpdate, + DeleteContext: resourceIBMSccRuleDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Your IBM Cloud account ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "A human-readable alias to assign to your rule.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "An extended description of your rule.", + }, + "rule_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of rule. Rules that you create are `user_defined`.", + }, + "labels": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "Labels that you can use to group and search for similar rules, such as those that help you to meet a specific organization guideline.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "creation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date the resource was created.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the user or application that created the resource.", + }, + "modification_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + // ForceNew: true, // Type 1 Fix + Description: "The date the resource was last modified.", + }, + "modified_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the user or application that last modified the resource.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "enforcement_actions": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "The actions that the service must run on your behalf when a request to create or modify the target resource does not comply with your conditions.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "To block a request from completing, use `disallow`.", + }, + }, + }, + MaxItems: 1, + }, + "required_config": &schema.Schema{ + Description: "The requirements that must be met to determine the resource's level of compliance in accordance with the rule. Use logical operators (and/or) to define multiple property checks and conditions. To define requirements for a rule, list one or more property check objects in the and array. To add conditions to a property check, use or.", + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: getRequiredConfigSchema(0), + }, + MaxItems: 1, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The properties that describe the resource that you want to targetwith the rule or template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + }, + "resource_kind": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of resource that you want to target.", + }, + "additional_target_attributes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + ValidateFunc: validate.InvokeValidator("ibm_scc_rule", "operator"), + }, + }, + }, + }, + }, + }, + MaxItems: 1, + }, + }, + CustomizeDiff: customdiff.All( + // update the version number via API GET if any of the fields are changed + customdiff.ComputedIf("version", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("name") || diff.HasChange("description") || + diff.HasChange("target") || diff.HasChange("labels") || + diff.HasChange("required_config") || diff.HasChange("enforcement_actions") + }), + // update the modification_date via API GET if any of the fields are changed + customdiff.ComputedIf("modification_date", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("name") || diff.HasChange("description") || + diff.HasChange("target") || diff.HasChange("labels") || + diff.HasChange("required_config") || diff.HasChange("enforcement_actions") + }), + ), + } +} + +func getRequiredConfigSchema(currentDepth int) map[string]*schema.Schema { + baseMap := map[string]*schema.Schema{ + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + }, + "property": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + Description: "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + }, + "operator": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + ValidateFunc: validate.InvokeValidator("ibm_scc_rule", "operator"), + }, + } + + if currentDepth > maxDepth { + return baseMap + } + baseMap["and"] = &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A condition with the and logical operator.", + Elem: &schema.Resource{ + Schema: getRequiredConfigSchema(currentDepth + 1), + }, + } + baseMap["or"] = &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "A condition with the or logical operator.", + Elem: &schema.Resource{ + Schema: getRequiredConfigSchema(currentDepth + 1), + }, + } + return baseMap +} + +func resourceIBMSccRuleCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + createRulesOptions := &configurationgovernancev1.CreateRulesOptions{} + var rule []configurationgovernancev1.CreateRuleRequest + ruleItem, err := resourceIBMSccRuleMapToCreateRuleRequest(d) + if err != nil { + return diag.FromErr(err) + } + rule = append(rule, *ruleItem) + createRulesOptions.SetRules(rule) + + createRulesResponse, response, err := configurationGovernanceClient.CreateRulesWithContext(context, createRulesOptions) + if err != nil || response.GetStatusCode() == 207 || response.StatusCode > 300 { + log.Printf("[DEBUG] CreateRulesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateRulesWithContext failed %s\n%s", err, response)) + } + + d.SetId(*createRulesResponse.Rules[0].Rule.RuleID) + + return resourceIBMSccRuleRead(context, d, meta) +} + +func resourceIBMSccRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + getRuleOptions := &configurationgovernancev1.GetRuleOptions{} + + getRuleOptions.SetRuleID(d.Id()) + + rule, response, err := configurationGovernanceClient.GetRuleWithContext(context, getRuleOptions) + log.Println("[DEBUG] Grabbed a response from the Read Operation") + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetRuleWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("account_id", rule.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + if err = d.Set("name", rule.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("description", rule.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if err = d.Set("rule_type", rule.RuleType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rule_type: %s", err)) + } + targetMap, e := resourceIBMSccRuleTargetResourceToMap(rule.Target) + if e != nil { + return diag.FromErr(err) + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting target: %s", err)) + } + requiredConfigMap, e := resourceIBMSccRuleRuleRequiredConfigToMap(rule.RequiredConfig) + if e != nil { + return diag.FromErr(err) + } + if err = d.Set("required_config", []map[string]interface{}{requiredConfigMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting required_config: %s", err)) + } + + enforcementAction := []map[string]interface{}{} + for _, enforcementActionItem := range rule.EnforcementActions { + enforcementActionItemMap, err := resourceIBMSccRuleEnforcementActionToMap(&enforcementActionItem) + if err != nil { + return diag.FromErr(err) + } + enforcementAction = append(enforcementAction, enforcementActionItemMap) + } + + if err = d.Set("enforcement_actions", enforcementAction); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enforcement_actions: %s", err)) + } + if rule.Labels != nil { + if err = d.Set("labels", rule.Labels); err != nil { + return diag.FromErr(fmt.Errorf("Error setting labels: %s", err)) + } + } + if err = d.Set("creation_date", flex.DateTimeToString(rule.CreationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting creation_date: %s", err)) + } + if err = d.Set("created_by", rule.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("modification_date", flex.DateTimeToString(rule.ModificationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting modification_date: %s", err)) + } + if err = d.Set("modified_by", rule.ModifiedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting modified_by: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMSccRuleUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + updateRuleOptions := &configurationgovernancev1.UpdateRuleOptions{} + + updateRuleOptions.SetRuleID(d.Id()) + + hasChange := d.HasChange("name") || d.HasChange("description") || + d.HasChange("target") || d.HasChange("labels") || + d.HasChange("required_config") || d.HasChange("enforcement_actions") + + if hasChange { + updateRuleOptions.SetName(d.Get("name").(string)) + updateRuleOptions.SetAccountID(d.Get("account_id").(string)) + updateRuleOptions.SetDescription(d.Get("description").(string)) + + target, err := resourceIBMSccRuleMapToTargetResource(d.Get("target.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + updateRuleOptions.SetTarget(target) + labels := []string{} + if d.Get("labels") != nil { + for _, labelsItem := range d.Get("labels").([]interface{}) { + labels = append(labels, labelsItem.(string)) + } + } + updateRuleOptions.SetLabels(labels) + + required_config, err := resourceIBMSccRuleMapToRuleRequiredConfig(d.Get("required_config.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + updateRuleOptions.SetRequiredConfig(required_config) + + enforcementActions := []configurationgovernancev1.EnforcementAction{} + for _, enforcementActionsItem := range d.Get("enforcement_actions").([]interface{}) { + if enforcementActionsItem != nil { + enforcementActionsItemModel, err := resourceIBMSccRuleMapToEnforcementAction(enforcementActionsItem.(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + enforcementActions = append(enforcementActions, *enforcementActionsItemModel) + } + } + updateRuleOptions.SetEnforcementActions(enforcementActions) + + updateRuleOptions.SetIfMatch(d.Get("version").(string)) + _, response, err := configurationGovernanceClient.UpdateRuleWithContext(context, updateRuleOptions) + if err != nil || response.GetStatusCode() == 207 || response.StatusCode > 300 { + log.Printf("[DEBUG] UpdateRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateRuleWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccRuleRead(context, d, meta) +} + +func resourceIBMSccRuleDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + deleteRuleOptions := &configurationgovernancev1.DeleteRuleOptions{} + + deleteRuleOptions.SetRuleID(d.Id()) + + response, err := configurationGovernanceClient.DeleteRuleWithContext(context, deleteRuleOptions) + if err != nil { + log.Printf("[DEBUG] DeleteRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteRuleWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMSccRuleMapToCreateRuleRequest(d *schema.ResourceData) (*configurationgovernancev1.CreateRuleRequest, error) { + model := &configurationgovernancev1.CreateRuleRequest{} + if d.Get("request_id") != nil { + model.RequestID = core.StringPtr(d.Get("request_id").(string)) + } + RuleModel, err := resourceIBMSccRuleMapToRuleRequest(d) + if err != nil { + return model, err + } + model.Rule = RuleModel + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequest(d *schema.ResourceData) (*configurationgovernancev1.RuleRequest, error) { + model := &configurationgovernancev1.RuleRequest{} + if d.Get("account_id") != nil { + model.AccountID = core.StringPtr(d.Get("account_id").(string)) + } + model.Name = core.StringPtr(d.Get("name").(string)) + model.Description = core.StringPtr(d.Get("description").(string)) + if d.Get("rule_type") != nil { + model.RuleType = core.StringPtr(d.Get("rule_type").(string)) + } + targetList := d.Get("target").([]interface{}) + TargetModel, err := resourceIBMSccRuleMapToTargetResource(targetList[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Target = TargetModel + requiredConfigList := d.Get("required_config").([]interface{}) + RequiredConfigModel, err := resourceIBMSccRuleMapToRuleRequiredConfig(requiredConfigList[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.RequiredConfig = RequiredConfigModel + enforcementActions := []configurationgovernancev1.EnforcementAction{} + for _, enforcementActionsItem := range d.Get("enforcement_actions").([]interface{}) { + if enforcementActionsItem != nil { + enforcementActionsItemModel, err := resourceIBMSccRuleMapToEnforcementAction(enforcementActionsItem.(map[string]interface{})) + if err != nil { + return model, err + } + enforcementActions = append(enforcementActions, *enforcementActionsItemModel) + } + } + model.EnforcementActions = enforcementActions + if d.Get("labels") != nil { + labels := []string{} + for _, labelsItem := range d.Get("labels").([]interface{}) { + labels = append(labels, labelsItem.(string)) + } + model.Labels = labels + } + return model, nil +} + +func resourceIBMSccRuleMapToTargetResource(modelMap map[string]interface{}) (*configurationgovernancev1.TargetResource, error) { + model := &configurationgovernancev1.TargetResource{} + model.ServiceName = core.StringPtr(modelMap["service_name"].(string)) + model.ResourceKind = core.StringPtr(modelMap["resource_kind"].(string)) + if modelMap["additional_target_attributes"] != nil { + additionalTargetAttributes := []configurationgovernancev1.TargetResourceAdditionalTargetAttributesItem{} + for _, additionalTargetAttributesItem := range modelMap["additional_target_attributes"].([]interface{}) { + if additionalTargetAttributesItem != nil { + additionalTargetAttributesItemModel, err := resourceIBMSccRuleMapToTargetResourceAdditionalTargetAttributesItem(additionalTargetAttributesItem.(map[string]interface{})) + if err != nil { + return model, err + } + additionalTargetAttributes = append(additionalTargetAttributes, *additionalTargetAttributesItemModel) + } + } + model.AdditionalTargetAttributes = additionalTargetAttributes + } + return model, nil +} + +func resourceIBMSccRuleMapToTargetResourceAdditionalTargetAttributesItem(modelMap map[string]interface{}) (*configurationgovernancev1.TargetResourceAdditionalTargetAttributesItem, error) { + model := &configurationgovernancev1.TargetResourceAdditionalTargetAttributesItem{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + model.Operator = core.StringPtr(modelMap["operator"].(string)) + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequiredConfig(modelMap map[string]interface{}) (configurationgovernancev1.RuleRequiredConfigIntf, error) { + model := &configurationgovernancev1.RuleRequiredConfig{} + + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["property"] != nil { + model.Property = core.StringPtr(modelMap["property"].(string)) + } + if modelMap["operator"] != nil { + model.Operator = core.StringPtr(modelMap["operator"].(string)) + } + // TODO: handle the usage of Lists/Arrays of strings(can't be done until the go-sdk is modified) + if modelMap["value"] != nil { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + if modelMap["or"] != nil { + or := []configurationgovernancev1.RuleConditionIntf{} + for _, orItem := range modelMap["or"].([]interface{}) { + if orItem == nil { + return model, errors.New("or block needs to be populated") + } + orItemModel, err := resourceIBMSccRuleMapToRuleCondition(orItem.(map[string]interface{})) + if err != nil { + return model, err + } + or = append(or, orItemModel) + } + model.Or = or + } + if modelMap["and"] != nil { + and := []configurationgovernancev1.RuleConditionIntf{} + for _, andItem := range modelMap["and"].([]interface{}) { + if andItem == nil { + return model, errors.New("and block needs to be populated") + } + andItemModel, err := resourceIBMSccRuleMapToRuleCondition(andItem.(map[string]interface{})) + if err != nil { + return model, err + } + and = append(and, andItemModel) + } + model.And = and + } + // Error out if 'and' and 'or' are set at the same level + if len(model.And) > 0 && len(model.Or) > 0 { + return model, errors.New("attributes of required_config 'or' and 'and' cannot be set at the same level") + } + + // Error out if the property, value, and operator are at the same level as 'and' and 'or' + if (len(*model.Value) > 0 || len(*model.Property) > 0 || len(*model.Operator) > 0) && + (len(model.And) > 0 || len(model.Or) > 0) { + return model, errors.New("'property','value','operator' should be nested inside 'and'/'or' or be by itself") + } + + return model, nil +} + +func resourceIBMSccRuleMapToRuleCondition(modelMap map[string]interface{}) (configurationgovernancev1.RuleConditionIntf, error) { + model := &configurationgovernancev1.RuleCondition{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["property"] != nil { + model.Property = core.StringPtr(modelMap["property"].(string)) + } + if modelMap["operator"] != nil { + model.Operator = core.StringPtr(modelMap["operator"].(string)) + } + if modelMap["value"] != nil { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + if modelMap["or"] != nil { + or := []configurationgovernancev1.RuleSingleProperty{} + for _, orItem := range modelMap["or"].([]interface{}) { + if orItem == nil { + return model, errors.New("or block needs to be populated") + } + orItemModel, err := resourceIBMSccRuleMapToRuleSingleProperty(orItem.(map[string]interface{})) + if err != nil { + return model, err + } + or = append(or, *orItemModel) + } + model.Or = or + } + if modelMap["and"] != nil { + and := []configurationgovernancev1.RuleSingleProperty{} + for _, andItem := range modelMap["and"].([]interface{}) { + if andItem == nil { + return model, errors.New("and block needs to be populated") + } + andItemModel, err := resourceIBMSccRuleMapToRuleSingleProperty(andItem.(map[string]interface{})) + if err != nil { + return model, err + } + and = append(and, *andItemModel) + } + model.And = and + } + // Error out if 'and' and 'or' are set at the same level + if len(model.And) > 0 && len(model.Or) > 0 { + return model, errors.New("attributes of required_config 'or' and 'and' cannot be set at the same level") + } + + // Error out if the property, value, and operator are at the same level as 'and' and 'or' + if (len(*model.Value) > 0 || len(*model.Property) > 0 || len(*model.Operator) > 0) && + (len(model.And) > 0 || len(model.Or) > 0) { + return model, errors.New("'property','value','operator' should be nested inside 'and'/'or' or be by itself") + } + return model, nil +} + +func resourceIBMSccRuleMapToRuleSingleProperty(modelMap map[string]interface{}) (*configurationgovernancev1.RuleSingleProperty, error) { + model := &configurationgovernancev1.RuleSingleProperty{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + model.Property = core.StringPtr(modelMap["property"].(string)) + model.Operator = core.StringPtr(modelMap["operator"].(string)) + if modelMap["value"] != nil { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + return model, nil +} + +func resourceIBMSccRuleMapToRuleConditionSingleProperty(modelMap map[string]interface{}) (*configurationgovernancev1.RuleConditionSingleProperty, error) { + model := &configurationgovernancev1.RuleConditionSingleProperty{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + model.Property = core.StringPtr(modelMap["property"].(string)) + model.Operator = core.StringPtr(modelMap["operator"].(string)) + if modelMap["value"] != nil { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + return model, nil +} + +func resourceIBMSccRuleMapToRuleConditionOrLvl2(modelMap map[string]interface{}) (*configurationgovernancev1.RuleConditionOrLvl2, error) { + model := &configurationgovernancev1.RuleConditionOrLvl2{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + or := []configurationgovernancev1.RuleSingleProperty{} + for _, orItem := range modelMap["or"].([]interface{}) { + orItemModel, err := resourceIBMSccRuleMapToRuleSingleProperty(orItem.(map[string]interface{})) + if err != nil { + return model, err + } + or = append(or, *orItemModel) + } + model.Or = or + return model, nil +} + +func resourceIBMSccRuleMapToRuleConditionAndLvl2(modelMap map[string]interface{}) (*configurationgovernancev1.RuleConditionAndLvl2, error) { + model := &configurationgovernancev1.RuleConditionAndLvl2{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + and := []configurationgovernancev1.RuleSingleProperty{} + for _, andItem := range modelMap["and"].([]interface{}) { + andItemModel, err := resourceIBMSccRuleMapToRuleSingleProperty(andItem.(map[string]interface{})) + if err != nil { + return model, err + } + and = append(and, *andItemModel) + } + model.And = and + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequiredConfigSingleProperty(modelMap map[string]interface{}) (*configurationgovernancev1.RuleRequiredConfigSingleProperty, error) { + model := &configurationgovernancev1.RuleRequiredConfigSingleProperty{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + model.Property = core.StringPtr(modelMap["property"].(string)) + model.Operator = core.StringPtr(modelMap["operator"].(string)) + if modelMap["value"] != nil { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequiredConfigMultipleProperties(modelMap map[string]interface{}) (configurationgovernancev1.RuleRequiredConfigMultiplePropertiesIntf, error) { + model := &configurationgovernancev1.RuleRequiredConfigMultipleProperties{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + if modelMap["or"] != nil { + or := []configurationgovernancev1.RuleConditionIntf{} + for _, orItem := range modelMap["or"].([]interface{}) { + orItemModel, err := resourceIBMSccRuleMapToRuleCondition(orItem.(map[string]interface{})) + if err != nil { + return model, err + } + or = append(or, orItemModel) + } + model.Or = or + } + if modelMap["and"] != nil { + and := []configurationgovernancev1.RuleConditionIntf{} + for _, andItem := range modelMap["and"].([]interface{}) { + andItemModel, err := resourceIBMSccRuleMapToRuleCondition(andItem.(map[string]interface{})) + if err != nil { + return model, err + } + and = append(and, andItemModel) + } + model.And = and + } + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequiredConfigMultiplePropertiesConditionOr(modelMap map[string]interface{}) (*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionOr, error) { + model := &configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionOr{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + or := []configurationgovernancev1.RuleConditionIntf{} + for _, orItem := range modelMap["or"].([]interface{}) { + orItemModel, err := resourceIBMSccRuleMapToRuleCondition(orItem.(map[string]interface{})) + if err != nil { + return model, err + } + or = append(or, orItemModel) + } + model.Or = or + return model, nil +} + +func resourceIBMSccRuleMapToRuleRequiredConfigMultiplePropertiesConditionAnd(modelMap map[string]interface{}) (*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionAnd, error) { + model := &configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionAnd{} + if modelMap["description"] != nil { + model.Description = core.StringPtr(modelMap["description"].(string)) + } + and := []configurationgovernancev1.RuleConditionIntf{} + for _, andItem := range modelMap["and"].([]interface{}) { + andItemModel, err := resourceIBMSccRuleMapToRuleCondition(andItem.(map[string]interface{})) + if err != nil { + return model, err + } + and = append(and, andItemModel) + } + model.And = and + return model, nil +} + +func resourceIBMSccRuleMapToEnforcementAction(modelMap map[string]interface{}) (*configurationgovernancev1.EnforcementAction, error) { + model := &configurationgovernancev1.EnforcementAction{} + model.Action = core.StringPtr(modelMap["action"].(string)) + return model, nil +} + +func resourceIBMSccRuleCreateRuleRequestToMap(model *configurationgovernancev1.CreateRuleRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.RequestID != nil { + modelMap["request_id"] = model.RequestID + } + ruleMap, err := resourceIBMSccRuleRuleRequestToMap(model.Rule) + if err != nil { + return modelMap, err + } + modelMap["rule"] = []map[string]interface{}{ruleMap} + return modelMap, nil +} + +func resourceIBMSccRuleRuleRequestToMap(model *configurationgovernancev1.RuleRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AccountID != nil { + modelMap["account_id"] = model.AccountID + } + modelMap["name"] = model.Name + modelMap["description"] = model.Description + if model.RuleType != nil { + modelMap["rule_type"] = model.RuleType + } + targetMap, err := resourceIBMSccRuleTargetResourceToMap(model.Target) + if err != nil { + return modelMap, err + } + modelMap["target"] = []map[string]interface{}{targetMap} + requiredConfigMap, err := resourceIBMSccRuleRuleRequiredConfigToMap(model.RequiredConfig) + if err != nil { + return modelMap, err + } + modelMap["required_config"] = []map[string]interface{}{requiredConfigMap} + enforcementActions := []map[string]interface{}{} + for _, enforcementActionsItem := range model.EnforcementActions { + enforcementActionsItemMap, err := resourceIBMSccRuleEnforcementActionToMap(&enforcementActionsItem) + if err != nil { + return modelMap, err + } + enforcementActions = append(enforcementActions, enforcementActionsItemMap) + } + modelMap["enforcement_actions"] = enforcementActions + if model.Labels != nil { + modelMap["labels"] = model.Labels + } + return modelMap, nil +} + +func resourceIBMSccRuleTargetResourceToMap(model *configurationgovernancev1.TargetResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["service_name"] = model.ServiceName + modelMap["resource_kind"] = model.ResourceKind + if model.AdditionalTargetAttributes != nil { + additionalTargetAttributes := []map[string]interface{}{} + for _, additionalTargetAttributesItem := range model.AdditionalTargetAttributes { + additionalTargetAttributesItemMap, err := resourceIBMSccRuleTargetResourceAdditionalTargetAttributesItemToMap(&additionalTargetAttributesItem) + if err != nil { + return modelMap, err + } + additionalTargetAttributes = append(additionalTargetAttributes, additionalTargetAttributesItemMap) + } + modelMap["additional_target_attributes"] = additionalTargetAttributes + } + return modelMap, nil +} + +func resourceIBMSccRuleTargetResourceAdditionalTargetAttributesItemToMap(model *configurationgovernancev1.TargetResourceAdditionalTargetAttributesItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + modelMap["operator"] = model.Operator + return modelMap, nil +} + +func resourceIBMSccRuleRuleRequiredConfigToMap(model configurationgovernancev1.RuleRequiredConfigIntf) (map[string]interface{}, error) { + if _, ok := model.(*configurationgovernancev1.RuleRequiredConfigSingleProperty); ok { + return resourceIBMSccRuleRuleRequiredConfigSinglePropertyToMap(model.(*configurationgovernancev1.RuleRequiredConfigSingleProperty)) + } else if _, ok := model.(*configurationgovernancev1.RuleRequiredConfigMultipleProperties); ok { + return resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesToMap(model.(*configurationgovernancev1.RuleRequiredConfigMultipleProperties)) + } else if _, ok := model.(*configurationgovernancev1.RuleRequiredConfig); ok { + modelMap := make(map[string]interface{}) + model := model.(*configurationgovernancev1.RuleRequiredConfig) + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Property != nil { + modelMap["property"] = model.Property + } + if model.Operator != nil { + modelMap["operator"] = model.Operator + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Or != nil { + or := []map[string]interface{}{} + for _, orItem := range model.Or { + orItemMap, err := resourceIBMSccRuleRuleConditionToMap(orItem) + if err != nil { + return modelMap, err + } + or = append(or, orItemMap) + } + modelMap["or"] = or + } + if model.And != nil { + and := []map[string]interface{}{} + for _, andItem := range model.And { + andItemMap, err := resourceIBMSccRuleRuleConditionToMap(andItem) + if err != nil { + return modelMap, err + } + and = append(and, andItemMap) + } + modelMap["and"] = and + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized configurationgovernancev1.RuleRequiredConfigIntf subtype encountered") + } +} + +func resourceIBMSccRuleRuleConditionToMap(model configurationgovernancev1.RuleConditionIntf) (map[string]interface{}, error) { + if _, ok := model.(*configurationgovernancev1.RuleConditionSingleProperty); ok { + return resourceIBMSccRuleRuleConditionSinglePropertyToMap(model.(*configurationgovernancev1.RuleConditionSingleProperty)) + } else if _, ok := model.(*configurationgovernancev1.RuleConditionOrLvl2); ok { + return resourceIBMSccRuleRuleConditionOrLvl2ToMap(model.(*configurationgovernancev1.RuleConditionOrLvl2)) + } else if _, ok := model.(*configurationgovernancev1.RuleConditionAndLvl2); ok { + return resourceIBMSccRuleRuleConditionAndLvl2ToMap(model.(*configurationgovernancev1.RuleConditionAndLvl2)) + } else if _, ok := model.(*configurationgovernancev1.RuleCondition); ok { + modelMap := make(map[string]interface{}) + model := model.(*configurationgovernancev1.RuleCondition) + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Property != nil { + modelMap["property"] = model.Property + } + if model.Operator != nil { + modelMap["operator"] = model.Operator + } + if model.Value != nil { + modelMap["value"] = model.Value + } + if model.Or != nil { + or := []map[string]interface{}{} + for _, orItem := range model.Or { + orItemMap, err := resourceIBMSccRuleRuleSinglePropertyToMap(&orItem) + if err != nil { + return modelMap, err + } + or = append(or, orItemMap) + } + modelMap["or"] = or + } + if model.And != nil { + and := []map[string]interface{}{} + for _, andItem := range model.And { + andItemMap, err := resourceIBMSccRuleRuleSinglePropertyToMap(&andItem) + if err != nil { + return modelMap, err + } + and = append(and, andItemMap) + } + modelMap["and"] = and + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized configurationgovernancev1.RuleConditionIntf subtype encountered") + } +} + +func resourceIBMSccRuleRuleSinglePropertyToMap(model *configurationgovernancev1.RuleSingleProperty) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + modelMap["property"] = model.Property + modelMap["operator"] = model.Operator + if model.Value != nil { + modelMap["value"] = model.Value + } + return modelMap, nil +} + +func resourceIBMSccRuleRuleConditionSinglePropertyToMap(model *configurationgovernancev1.RuleConditionSingleProperty) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + modelMap["property"] = model.Property + modelMap["operator"] = model.Operator + if model.Value != nil { + modelMap["value"] = model.Value + } + return modelMap, nil +} + +func resourceIBMSccRuleRuleConditionOrLvl2ToMap(model *configurationgovernancev1.RuleConditionOrLvl2) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + or := []map[string]interface{}{} + for _, orItem := range model.Or { + orItemMap, err := resourceIBMSccRuleRuleSinglePropertyToMap(&orItem) + if err != nil { + return modelMap, err + } + or = append(or, orItemMap) + } + modelMap["or"] = or + return modelMap, nil +} + +func resourceIBMSccRuleRuleConditionAndLvl2ToMap(model *configurationgovernancev1.RuleConditionAndLvl2) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + and := []map[string]interface{}{} + for _, andItem := range model.And { + andItemMap, err := resourceIBMSccRuleRuleSinglePropertyToMap(&andItem) + if err != nil { + return modelMap, err + } + and = append(and, andItemMap) + } + modelMap["and"] = and + return modelMap, nil +} + +func resourceIBMSccRuleRuleRequiredConfigSinglePropertyToMap(model *configurationgovernancev1.RuleRequiredConfigSingleProperty) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + modelMap["property"] = model.Property + modelMap["operator"] = model.Operator + if model.Value != nil { + modelMap["value"] = model.Value + } + return modelMap, nil +} + +func resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesToMap(model configurationgovernancev1.RuleRequiredConfigMultiplePropertiesIntf) (map[string]interface{}, error) { + if _, ok := model.(*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionOr); ok { + return resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesConditionOrToMap(model.(*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionOr)) + } else if _, ok := model.(*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionAnd); ok { + return resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesConditionAndToMap(model.(*configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionAnd)) + } else if _, ok := model.(*configurationgovernancev1.RuleRequiredConfigMultipleProperties); ok { + modelMap := make(map[string]interface{}) + model := model.(*configurationgovernancev1.RuleRequiredConfigMultipleProperties) + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Or != nil { + or := []map[string]interface{}{} + for _, orItem := range model.Or { + orItemMap, err := resourceIBMSccRuleRuleConditionToMap(orItem) + if err != nil { + return modelMap, err + } + or = append(or, orItemMap) + } + modelMap["or"] = or + } + if model.And != nil { + and := []map[string]interface{}{} + for _, andItem := range model.And { + andItemMap, err := resourceIBMSccRuleRuleConditionToMap(andItem) + if err != nil { + return modelMap, err + } + and = append(and, andItemMap) + } + modelMap["and"] = and + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized configurationgovernancev1.RuleRequiredConfigMultiplePropertiesIntf subtype encountered") + } +} + +func resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesConditionOrToMap(model *configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionOr) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + or := []map[string]interface{}{} + for _, orItem := range model.Or { + orItemMap, err := resourceIBMSccRuleRuleConditionToMap(orItem) + if err != nil { + return modelMap, err + } + or = append(or, orItemMap) + } + modelMap["or"] = or + return modelMap, nil +} + +func resourceIBMSccRuleRuleRequiredConfigMultiplePropertiesConditionAndToMap(model *configurationgovernancev1.RuleRequiredConfigMultiplePropertiesConditionAnd) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + and := []map[string]interface{}{} + for _, andItem := range model.And { + andItemMap, err := resourceIBMSccRuleRuleConditionToMap(andItem) + if err != nil { + return modelMap, err + } + and = append(and, andItemMap) + } + modelMap["and"] = and + return modelMap, nil +} + +func resourceIBMSccRuleEnforcementActionToMap(model *configurationgovernancev1.EnforcementAction) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["action"] = model.Action + return modelMap, nil +} diff --git a/ibm/service/scc/resource_ibm_scc_rule_attachment.go b/ibm/service/scc/resource_ibm_scc_rule_attachment.go new file mode 100644 index 000000000..8eafcd195 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule_attachment.go @@ -0,0 +1,348 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func ResourceIBMSccRuleAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccRuleAttachmentCreate, + ReadContext: resourceIBMSccRuleAttachmentRead, + UpdateContext: resourceIBMSccRuleAttachmentUpdate, + DeleteContext: resourceIBMSccRuleAttachmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The UUID that uniquely identifies the attachment.", + }, + "rule_id": &schema.Schema{ + ForceNew: true, + Type: schema.TypeString, + Required: true, + Description: "The UUID that uniquely identifies the rule.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Your IBM Cloud account ID.", + }, + "included_scope": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The extent at which the rule can be attached across your accounts.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A short description or alias to assign to the scope.", + }, + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate.", + }, + "scope_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of scope that you want to evaluate.", + ValidateFunc: validate.InvokeValidator("ibm_scc_rule_attachment", "scope_type"), + }, + }, + }, + MaxItems: 1, + }, + "excluded_scopes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "The extent at which the rule can be excluded from the included scope.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A short description or alias to assign to the scope.", + }, + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate.", + }, + "scope_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of scope that you want to evaluate.", + ValidateFunc: validate.InvokeValidator("ibm_scc_rule_attachment", "scope_type"), + }, + }, + }, + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + CustomizeDiff: customdiff.All( + // update the version number via API GET if any of the fields are true + customdiff.ComputedIf("version", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("included_scope") || diff.HasChange("excluded_scopes") + }), + ), + } +} + +func resourceIBMSccRuleAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + createRuleAttachmentsOptions := &configurationgovernancev1.CreateRuleAttachmentsOptions{} + + createRuleAttachmentsOptions.SetRuleID(d.Get("rule_id").(string)) + var attachment []configurationgovernancev1.RuleAttachmentRequest + attachmentItem, err := resourceIBMSccRuleAttachmentMapToRuleAttachmentRequest(d) + if err != nil { + return diag.FromErr(err) + } + attachment = append(attachment, *attachmentItem) + createRuleAttachmentsOptions.SetAttachments(attachment) + + createRuleAttachmentsResponse, response, err := configurationGovernanceClient.CreateRuleAttachmentsWithContext(context, createRuleAttachmentsOptions) + if err != nil || response.StatusCode > 300 { + log.Printf("[DEBUG] CreateRuleAttachmentsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateRuleAttachmentsWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createRuleAttachmentsOptions.RuleID, *createRuleAttachmentsResponse.Attachments[0].AttachmentID)) + + return resourceIBMSccRuleAttachmentRead(context, d, meta) +} + +func resourceIBMSccRuleAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + getRuleAttachmentOptions := &configurationgovernancev1.GetRuleAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getRuleAttachmentOptions.SetRuleID(parts[0]) + getRuleAttachmentOptions.SetAttachmentID(parts[1]) + + ruleAttachment, response, err := configurationGovernanceClient.GetRuleAttachmentWithContext(context, getRuleAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetRuleAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetRuleAttachmentWithContext failed %s\n%s", err, response)) + } + + // TODO: handle argument of type []interface{} + if err = d.Set("rule_id", ruleAttachment.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rule_id: %s", err)) + } + if err = d.Set("account_id", ruleAttachment.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + includedScopeMap, err := resourceIBMSccRuleAttachmentRuleScopeToMap(ruleAttachment.IncludedScope) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("included_scope", []map[string]interface{}{includedScopeMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting included_scope: %s", err)) + } + + excludedScope := []map[string]interface{}{} + if ruleAttachment.ExcludedScopes != nil { + for _, excludedScopeItem := range ruleAttachment.ExcludedScopes { + excludedScopeItemMap, err := resourceIBMSccRuleAttachmentRuleScopeToMap(&excludedScopeItem) + if err != nil { + return diag.FromErr(err) + } + excludedScope = append(excludedScope, excludedScopeItemMap) + } + } + if err = d.Set("excluded_scopes", excludedScope); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded_scopes: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMSccRuleAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + updateRuleAttachmentOptions := &configurationgovernancev1.UpdateRuleAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateRuleAttachmentOptions.SetRuleID(parts[0]) + updateRuleAttachmentOptions.SetAttachmentID(parts[1]) + + // This code is never going to work since the schema has ForceNew in property rule_id + // if d.HasChange("rule_id") { + // return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + // " The resource must be re-created to update this property.", "rule_id")) + // } + + hasChange := d.HasChange("included_scope") || d.HasChange("excluded_scopes") + + if hasChange { + updateRuleAttachmentOptions.SetIfMatch(d.Get("version").(string)) + updateRuleAttachmentOptions.SetRuleID(d.Get("rule_id").(string)) + updateRuleAttachmentOptions.SetAccountID(d.Get("account_id").(string)) + + includedScope, err := resourceIBMSccRuleAttachmentMapToRuleScope(d.Get("included_scope.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + updateRuleAttachmentOptions.SetIncludedScope(includedScope) + + excludedScopes := []configurationgovernancev1.RuleScope{} + if d.Get("excluded_scopes") != nil { + for _, scopeItem := range d.Get("excluded_scopes").([]interface{}) { + excludedScope, err := resourceIBMSccRuleAttachmentMapToRuleScope(scopeItem.(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + excludedScopes = append(excludedScopes, *excludedScope) + } + } + updateRuleAttachmentOptions.SetExcludedScopes(excludedScopes) + + _, response, err := configurationGovernanceClient.UpdateRuleAttachmentWithContext(context, updateRuleAttachmentOptions) + if err != nil || response.StatusCode > 300 { + log.Printf("[DEBUG] UpdateRuleAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateRuleAttachmentWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccRuleAttachmentRead(context, d, meta) +} + +func resourceIBMSccRuleAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + deleteRuleAttachmentOptions := &configurationgovernancev1.DeleteRuleAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteRuleAttachmentOptions.SetRuleID(parts[0]) + deleteRuleAttachmentOptions.SetAttachmentID(parts[1]) + + response, err := configurationGovernanceClient.DeleteRuleAttachmentWithContext(context, deleteRuleAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] DeleteRuleAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteRuleAttachmentWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMSccRuleAttachmentMapToRuleAttachmentRequest(d *schema.ResourceData) (*configurationgovernancev1.RuleAttachmentRequest, error) { + model := &configurationgovernancev1.RuleAttachmentRequest{} + model.AccountID = core.StringPtr(d.Get("account_id").(string)) + includedScopeList := d.Get("included_scope").([]interface{}) + IncludedScopeModel, err := resourceIBMSccRuleAttachmentMapToRuleScope(includedScopeList[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.IncludedScope = IncludedScopeModel + if d.Get("excluded_scopes") != nil { + excludedScopes := []configurationgovernancev1.RuleScope{} + for _, excludedScopesItem := range d.Get("excluded_scopes").([]interface{}) { + excludedScopesItemModel, err := resourceIBMSccRuleAttachmentMapToRuleScope(excludedScopesItem.(map[string]interface{})) + if err != nil { + return model, err + } + excludedScopes = append(excludedScopes, *excludedScopesItemModel) + } + model.ExcludedScopes = excludedScopes + } + return model, nil +} + +func resourceIBMSccRuleAttachmentMapToRuleScope(modelMap map[string]interface{}) (*configurationgovernancev1.RuleScope, error) { + model := &configurationgovernancev1.RuleScope{} + if modelMap["note"] != nil { + model.Note = core.StringPtr(modelMap["note"].(string)) + } + model.ScopeID = core.StringPtr(modelMap["scope_id"].(string)) + model.ScopeType = core.StringPtr(modelMap["scope_type"].(string)) + return model, nil +} + +func resourceIBMSccRuleAttachmentRuleAttachmentRequestToMap(model *configurationgovernancev1.RuleAttachmentRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["account_id"] = model.AccountID + includedScopeMap, err := resourceIBMSccRuleAttachmentRuleScopeToMap(model.IncludedScope) + if err != nil { + return modelMap, err + } + modelMap["included_scope"] = []map[string]interface{}{includedScopeMap} + if model.ExcludedScopes != nil { + excludedScopes := []map[string]interface{}{} + for _, excludedScopesItem := range model.ExcludedScopes { + excludedScopesItemMap, err := resourceIBMSccRuleAttachmentRuleScopeToMap(&excludedScopesItem) + if err != nil { + return modelMap, err + } + excludedScopes = append(excludedScopes, excludedScopesItemMap) + } + modelMap["excluded_scopes"] = excludedScopes + } + return modelMap, nil +} + +func resourceIBMSccRuleAttachmentRuleScopeToMap(model *configurationgovernancev1.RuleScope) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Note != nil { + modelMap["note"] = model.Note + } + modelMap["scope_id"] = model.ScopeID + modelMap["scope_type"] = model.ScopeType + return modelMap, nil +} diff --git a/ibm/service/scc/resource_ibm_scc_rule_attachment_test.go b/ibm/service/scc/resource_ibm_scc_rule_attachment_test.go new file mode 100644 index 000000000..5715a042a --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule_attachment_test.go @@ -0,0 +1,172 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func TestAccIBMSccRuleAttachmentBasic(t *testing.T) { + var conf configurationgovernancev1.RuleAttachment + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccRuleAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccRuleAttachmentConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccRuleAttachmentExists("ibm_scc_rule_attachment.scc_rule_attachment", conf), + ), + }, + resource.TestStep{ + ResourceName: "ibm_scc_rule_attachment.scc_rule_attachment", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccRuleAttachmentConfigBasic() string { + account_id := os.Getenv("SCC_GOVERNANCE_ACCOUNT_ID") + resource_group_id := os.Getenv("IBM_SCC_RESOURCE_GROUP") + return fmt.Sprintf(` + + resource "ibm_scc_rule" "scc_rule" { + account_id = "%s" + name = "scc_tf_sample_rule" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + operator = "string_equals" + } + } + labels = ["test1", "test2"] + required_config { + description = "test config" + or { + property = "location" + operator = "string_equals" + value = "us-south" + } + or { + property = "location" + operator = "string_equals" + value = "us-east" + } + } + enforcement_actions { + action = "disallow" + } + } + + resource "ibm_scc_rule_attachment" "scc_rule_attachment" { + rule_id = ibm_scc_rule.scc_rule.id + account_id = "%s" + included_scope { + note = "note" + scope_id = "%s" + scope_type = "account" + } + excluded_scopes { + note = "note" + scope_id = "%s" + scope_type = "account.resource_group" + } + depends_on = [ + ibm_scc_rule.scc_rule + ] + } + `, account_id, account_id, account_id, resource_group_id) +} + +func testAccCheckIBMSccRuleAttachmentExists(n string, obj configurationgovernancev1.RuleAttachment) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + + getRuleAttachmentOptions := &configurationgovernancev1.GetRuleAttachmentOptions{} + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + ruleID := parts[0] + getRuleAttachmentOptions.SetRuleID(ruleID) + getRuleAttachmentOptions.SetAttachmentID(parts[1]) + + ruleAttachment, _, err := configurationGovernanceClient.GetRuleAttachment(getRuleAttachmentOptions) + if err != nil { + return err + } + + if *ruleAttachment.RuleID != ruleID { + return fmt.Errorf( + "ibm_scc_rule_attachment.scc_rule_attachment: Attribute 'rule_id' expected %#v, got %#v", + ruleID, + ruleAttachment.RuleID, + ) + } + + obj = *ruleAttachment + return nil + } +} + +func testAccCheckIBMSccRuleAttachmentDestroy(s *terraform.State) error { + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_rule_attachment" { + continue + } + + getRuleAttachmentOptions := &configurationgovernancev1.GetRuleAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getRuleAttachmentOptions.SetRuleID(parts[0]) + getRuleAttachmentOptions.SetAttachmentID(parts[1]) + + // Try to find the key + _, response, err := configurationGovernanceClient.GetRuleAttachment(getRuleAttachmentOptions) + + if err == nil { + return fmt.Errorf("scc_rule_attachment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for scc_rule_attachment (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_rule_attachment_validator.go b/ibm/service/scc/resource_ibm_scc_rule_attachment_validator.go new file mode 100644 index 000000000..ee1079506 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule_attachment_validator.go @@ -0,0 +1,24 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMSccRuleAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "scope_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "enterprise, enterprise.account_group, enterprise.account, account, account.resource_group", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_rule_attachment", Schema: validateSchema} + return &resourceValidator +} diff --git a/ibm/service/scc/resource_ibm_scc_rule_test.go b/ibm/service/scc/resource_ibm_scc_rule_test.go new file mode 100644 index 000000000..d1261cd94 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule_test.go @@ -0,0 +1,133 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func TestAccIBMSccRuleBasic(t *testing.T) { + var conf configurationgovernancev1.Rule + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccRuleConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccRuleExists("ibm_scc_rule.scc_rule", conf), + ), + }, + resource.TestStep{ + ResourceName: "ibm_scc_rule.scc_rule", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccRuleConfigBasic() string { + // Check if the user has a SCC_GOVERANCE_ACCOUNT_ID + account_id := os.Getenv("SCC_GOVERNANCE_ACCOUNT_ID") + return fmt.Sprintf(` + + resource "ibm_scc_rule" "scc_rule" { + account_id = "%s" + name = "scc_tf_sample_rule" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + operator = "string_equals" + } + } + labels = ["test1", "test2"] + required_config { + description = "test config" + or { + property = "location" + operator = "string_equals" + value = "us-west" + } + or { + property = "location" + operator = "string_equals" + value = "us-east" + } + } + enforcement_actions { + action = "disallow" + } + } + `, account_id) +} + +func testAccCheckIBMSccRuleExists(n string, obj configurationgovernancev1.Rule) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + + getRuleOptions := &configurationgovernancev1.GetRuleOptions{} + + getRuleOptions.SetRuleID(rs.Primary.ID) + + rule, _, err := configurationGovernanceClient.GetRule(getRuleOptions) + if err != nil { + return err + } + + obj = *rule + return nil + } +} + +func testAccCheckIBMSccRuleDestroy(s *terraform.State) error { + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_rule" { + continue + } + + getRuleOptions := &configurationgovernancev1.GetRuleOptions{} + + getRuleOptions.SetRuleID(rs.Primary.ID) + + // Try to find the key + _, response, err := configurationGovernanceClient.GetRule(getRuleOptions) + + if err == nil { + return fmt.Errorf("scc_rule still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for scc_rule (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_rule_validator.go b/ibm/service/scc/resource_ibm_scc_rule_validator.go new file mode 100644 index 000000000..d3ef2f667 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_rule_validator.go @@ -0,0 +1,30 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMSccRuleValidator() *validate.ResourceValidator { + + validateSchemaList := make([]validate.ValidateSchema, 2) + validateSchemaList = append(validateSchemaList, validateIBMSccRuleReqConfig()) + resourceValidator := validate.ResourceValidator{ + ResourceName: "ibm_scc_rule", + Schema: validateSchemaList, + } + return &resourceValidator +} + +func validateIBMSccRuleReqConfig() validate.ValidateSchema { + validateSchema := validate.ValidateSchema{ + Identifier: "operator", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "is_true, is_false, is_empty, is_not_empty, string_equals, string_not_equals, string_match, string_not_match, num_equals, num_not_equals, num_less_than, num_less_than_equals, num_greater_than, num_greater_than_equals", + } + return validateSchema +} diff --git a/ibm/service/scc/resource_ibm_scc_template.go b/ibm/service/scc/resource_ibm_scc_template.go new file mode 100644 index 000000000..318eb901d --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template.go @@ -0,0 +1,406 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func ResourceIBMSccTemplate() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccTemplateCreate, + ReadContext: resourceIBMSccTemplateRead, + UpdateContext: resourceIBMSccTemplateUpdate, + DeleteContext: resourceIBMSccTemplateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Your IBM Cloud account ID.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "A human-readablse alias to assign to your template.", + ValidateFunc: validate.InvokeValidator("ibm_scc_template", "name"), + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "An extended description of your template.", + ValidateFunc: validate.InvokeValidator("ibm_scc_template", "description"), + }, + "template_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The UUID that uniquely identifies the template.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "The properties that describe the resource that you want to targetwith the rule or template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + ValidateFunc: validate.InvokeValidator("ibm_scc_template", "service_name"), + }, + "resource_kind": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of resource that you want to target.", + }, + "additional_target_attributes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + }, + }, + }, + }, + }, + }, + }, + "customized_defaults": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "A list of default property values to apply to your template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "property": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of the resource property that you want to configure.Property options differ depending on the service or resource that you are targeting with a template. To view a list of properties that are compatible with templates, refer to the service documentation.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The custom value that you want to apply as the default for the resource property in the `name` field.This value is used to to override the default value that is provided by IBM when a resource is created. Value options differ depending on the resource that you are configuring. To learn more about your options, refer to the service documentation.", + }, + }, + }, + }, + }, + } +} + +func resourceIBMSccTemplateCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + createTemplatesOptions := &configurationgovernancev1.CreateTemplatesOptions{} + + var template []configurationgovernancev1.CreateTemplateRequest + templateItem, err := resourceIBMSccTemplateMapToCreateTemplateRequest(d) + template = append(template, *templateItem) + createTemplatesOptions.SetTemplates(template) + + createTemplatesResponse, response, err := configurationGovernanceClient.CreateTemplatesWithContext(context, createTemplatesOptions) + if err != nil || response.GetStatusCode() == 207 || response.StatusCode > 300 { + log.Printf("[DEBUG] CreateTemplatesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTemplatesWithContext failed %s\n%s", err, response)) + } + + d.SetId(*createTemplatesResponse.Templates[0].Template.TemplateID) + + return resourceIBMSccTemplateRead(context, d, meta) +} + +func resourceIBMSccTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + getTemplateOptions := &configurationgovernancev1.GetTemplateOptions{} + + getTemplateOptions.SetTemplateID(d.Id()) + + templateResponse, response, err := configurationGovernanceClient.GetTemplateWithContext(context, getTemplateOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTemplateWithContext failed %s\n%s", err, response)) + } + + // TODO: handle argument of type []interface{} + if err = d.Set("account_id", templateResponse.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + if err = d.Set("name", templateResponse.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("description", templateResponse.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + targetMap, err := resourceIBMSccTemplateSimpleTargetResourceToMap(templateResponse.Target) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting target: %s", err)) + } + + customizedDefaults := []map[string]interface{}{} + for _, customizedDefaultsItem := range templateResponse.CustomizedDefaults { + customizedDefaultsItemMap, err := resourceIBMSccTemplateTemplateCustomizedDefaultPropertyToMap(&customizedDefaultsItem) + if err != nil { + return diag.FromErr(err) + } + customizedDefaults = append(customizedDefaults, customizedDefaultsItemMap) + } + if err = d.Set("customized_defaults", customizedDefaults); err != nil { + return diag.FromErr(fmt.Errorf("Error setting customized_defaults: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMSccTemplateUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + updateTemplateOptions := &configurationgovernancev1.UpdateTemplateOptions{} + + updateTemplateOptions.SetTemplateID(d.Id()) + + hasChange := d.HasChange("name") || d.HasChange("description") || + d.HasChange("target") || d.HasChange("customized_defaults") + + if hasChange { + updateTemplateOptions.SetIfMatch(d.Get("version").(string)) + updateTemplateOptions.SetName(d.Get("name").(string)) + updateTemplateOptions.SetAccountID(d.Get("account_id").(string)) + updateTemplateOptions.SetDescription(d.Get("description").(string)) + + target, err := resourceIBMSccTemplateMapToSimpleTargetResource(d.Get("target.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + updateTemplateOptions.SetTarget(target) + + customizedDefaults := []configurationgovernancev1.TemplateCustomizedDefaultProperty{} + for _, customizedDefaultsItem := range d.Get("customized_defaults").([]interface{}) { + if customizedDefaultsItem != nil { + customizedDefaultsItemModel, err := resourceIBMSccTemplateMapToTemplateCustomizedDefaultProperty(customizedDefaultsItem.(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + customizedDefaults = append(customizedDefaults, *customizedDefaultsItemModel) + } + } + updateTemplateOptions.SetCustomizedDefaults(customizedDefaults) + + _, response, err := configurationGovernanceClient.UpdateTemplateWithContext(context, updateTemplateOptions) + if err != nil { + log.Printf("[DEBUG] UpdateTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateTemplateWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccTemplateRead(context, d, meta) +} + +func resourceIBMSccTemplateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + deleteTemplateOptions := &configurationgovernancev1.DeleteTemplateOptions{} + + deleteTemplateOptions.SetTemplateID(d.Id()) + + response, err := configurationGovernanceClient.DeleteTemplateWithContext(context, deleteTemplateOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTemplateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMSccTemplateMapToCreateTemplateRequest(d *schema.ResourceData) (*configurationgovernancev1.CreateTemplateRequest, error) { + model := &configurationgovernancev1.CreateTemplateRequest{} + if d.Get("request_id") != nil { + model.RequestID = core.StringPtr(d.Get("request_id").(string)) + } + TemplateModel, err := resourceIBMSccTemplateMapToTemplate(d) + if err != nil { + return model, err + } + model.Template = TemplateModel + return model, nil +} + +func resourceIBMSccTemplateMapToTemplate(d *schema.ResourceData) (*configurationgovernancev1.Template, error) { + model := &configurationgovernancev1.Template{} + model.AccountID = core.StringPtr(d.Get("account_id").(string)) + model.Name = core.StringPtr(d.Get("name").(string)) + model.Description = core.StringPtr(d.Get("description").(string)) + if d.Get("template_id") != nil { + model.TemplateID = core.StringPtr(d.Get("template_id").(string)) + } + targetList := d.Get("target").([]interface{}) + TargetModel, err := resourceIBMSccTemplateMapToSimpleTargetResource(targetList[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Target = TargetModel + customizedDefaults := []configurationgovernancev1.TemplateCustomizedDefaultProperty{} + for _, customizedDefaultsItem := range d.Get("customized_defaults").([]interface{}) { + customizedDefaultsItemModel, err := resourceIBMSccTemplateMapToTemplateCustomizedDefaultProperty(customizedDefaultsItem.(map[string]interface{})) + if err != nil { + return model, err + } + customizedDefaults = append(customizedDefaults, *customizedDefaultsItemModel) + } + model.CustomizedDefaults = customizedDefaults + return model, nil +} + +func resourceIBMSccTemplateMapToSimpleTargetResource(modelMap map[string]interface{}) (*configurationgovernancev1.SimpleTargetResource, error) { + model := &configurationgovernancev1.SimpleTargetResource{} + model.ServiceName = core.StringPtr(modelMap["service_name"].(string)) + model.ResourceKind = core.StringPtr(modelMap["resource_kind"].(string)) + if modelMap["additional_target_attributes"] != nil { + additionalTargetAttributes := []configurationgovernancev1.BaseTargetAttribute{} + for _, additionalTargetAttributesItem := range modelMap["additional_target_attributes"].([]interface{}) { + additionalTargetAttributesItemModel, err := resourceIBMSccTemplateMapToBaseTargetAttribute(additionalTargetAttributesItem.(map[string]interface{})) + if err != nil { + return model, err + } + additionalTargetAttributes = append(additionalTargetAttributes, *additionalTargetAttributesItemModel) + } + model.AdditionalTargetAttributes = additionalTargetAttributes + } + return model, nil +} + +func resourceIBMSccTemplateMapToBaseTargetAttribute(modelMap map[string]interface{}) (*configurationgovernancev1.BaseTargetAttribute, error) { + model := &configurationgovernancev1.BaseTargetAttribute{} + model.Name = core.StringPtr(modelMap["name"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMSccTemplateMapToTemplateCustomizedDefaultProperty(modelMap map[string]interface{}) (*configurationgovernancev1.TemplateCustomizedDefaultProperty, error) { + model := &configurationgovernancev1.TemplateCustomizedDefaultProperty{} + model.Property = core.StringPtr(modelMap["property"].(string)) + model.Value = core.StringPtr(modelMap["value"].(string)) + return model, nil +} + +func resourceIBMSccTemplateCreateTemplateRequestToMap(model *configurationgovernancev1.CreateTemplateRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.RequestID != nil { + modelMap["request_id"] = model.RequestID + } + templateMap, err := resourceIBMSccTemplateTemplateToMap(model.Template) + if err != nil { + return modelMap, err + } + modelMap["template"] = []map[string]interface{}{templateMap} + return modelMap, nil +} + +func resourceIBMSccTemplateTemplateToMap(model *configurationgovernancev1.Template) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["account_id"] = model.AccountID + modelMap["name"] = model.Name + modelMap["description"] = model.Description + if model.TemplateID != nil { + modelMap["template_id"] = model.TemplateID + } + targetMap, err := resourceIBMSccTemplateSimpleTargetResourceToMap(model.Target) + if err != nil { + return modelMap, err + } + modelMap["target"] = []map[string]interface{}{targetMap} + customizedDefaults := []map[string]interface{}{} + for _, customizedDefaultsItem := range model.CustomizedDefaults { + customizedDefaultsItemMap, err := resourceIBMSccTemplateTemplateCustomizedDefaultPropertyToMap(&customizedDefaultsItem) + if err != nil { + return modelMap, err + } + customizedDefaults = append(customizedDefaults, customizedDefaultsItemMap) + } + modelMap["customized_defaults"] = customizedDefaults + return modelMap, nil +} + +func resourceIBMSccTemplateSimpleTargetResourceToMap(model *configurationgovernancev1.SimpleTargetResource) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["service_name"] = model.ServiceName + modelMap["resource_kind"] = model.ResourceKind + if model.AdditionalTargetAttributes != nil { + additionalTargetAttributes := []map[string]interface{}{} + for _, additionalTargetAttributesItem := range model.AdditionalTargetAttributes { + additionalTargetAttributesItemMap, err := resourceIBMSccTemplateBaseTargetAttributeToMap(&additionalTargetAttributesItem) + if err != nil { + return modelMap, err + } + additionalTargetAttributes = append(additionalTargetAttributes, additionalTargetAttributesItemMap) + } + modelMap["additional_target_attributes"] = additionalTargetAttributes + } + return modelMap, nil +} + +func resourceIBMSccTemplateBaseTargetAttributeToMap(model *configurationgovernancev1.BaseTargetAttribute) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["name"] = model.Name + modelMap["value"] = model.Value + return modelMap, nil +} + +func resourceIBMSccTemplateTemplateCustomizedDefaultPropertyToMap(model *configurationgovernancev1.TemplateCustomizedDefaultProperty) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["property"] = model.Property + modelMap["value"] = model.Value + return modelMap, nil +} diff --git a/ibm/service/scc/resource_ibm_scc_template_attachment.go b/ibm/service/scc/resource_ibm_scc_template_attachment.go new file mode 100644 index 000000000..28339a004 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template_attachment.go @@ -0,0 +1,338 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func ResourceIBMSccTemplateAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSccTemplateAttachmentCreate, + ReadContext: resourceIBMSccTemplateAttachmentRead, + UpdateContext: resourceIBMSccTemplateAttachmentUpdate, + DeleteContext: resourceIBMSccTemplateAttachmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The UUID that uniquely identifies the template.", + }, + "template_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The UUID that uniquely identifies the template.", + }, + "account_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Your IBM Cloud account ID.", + }, + "included_scope": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Description: "The extent at which the template can be attached across your accounts.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A short description or alias to assign to the scope.", + }, + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the scope, such as an enterprise, account, or account group, where you want to apply the customized defaults that are associated with a template.", + }, + "scope_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of scope.", + ValidateFunc: validate.InvokeValidator("ibm_scc_template_attachment", "scope_type"), + }, + }, + }, + }, + "excluded_scopes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A short description or alias to assign to the scope.", + }, + "scope_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the scope, such as an enterprise, account, or account group, where you want to apply the customized defaults that are associated with a template.", + }, + "scope_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The type of scope.", + ValidateFunc: validate.InvokeValidator("ibm_scc_template_attachment", "scope_type"), + }, + }, + }, + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceIBMSccTemplateAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + createTemplateAttachmentsOptions := &configurationgovernancev1.CreateTemplateAttachmentsOptions{} + + createTemplateAttachmentsOptions.SetTemplateID(d.Get("template_id").(string)) + var attachment []configurationgovernancev1.TemplateAttachmentRequest + attachmentItem, err := resourceIBMSccTemplateAttachmentMapToTemplateAttachmentRequest(d) + if err != nil { + return diag.FromErr(err) + } + attachment = append(attachment, *attachmentItem) + createTemplateAttachmentsOptions.SetAttachments(attachment) + + createTemplateAttachmentsResponse, response, err := configurationGovernanceClient.CreateTemplateAttachmentsWithContext(context, createTemplateAttachmentsOptions) + if err != nil || response.StatusCode > 300 { + log.Printf("[DEBUG] CreateTemplateAttachmentsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTemplateAttachmentsWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createTemplateAttachmentsOptions.TemplateID, *createTemplateAttachmentsResponse.Attachments[0].AttachmentID)) + + return resourceIBMSccTemplateAttachmentRead(context, d, meta) +} + +func resourceIBMSccTemplateAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + getTemplateAttachmentOptions := &configurationgovernancev1.GetTemplateAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTemplateAttachmentOptions.SetTemplateID(parts[0]) + getTemplateAttachmentOptions.SetAttachmentID(parts[1]) + + templateAttachment, response, err := configurationGovernanceClient.GetTemplateAttachmentWithContext(context, getTemplateAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTemplateAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTemplateAttachmentWithContext failed %s\n%s", err, response)) + } + + // TODO: handle argument of type []interface{} + if err = d.Set("template_id", templateAttachment.TemplateID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting template_id: %s", err)) + } + if err = d.Set("account_id", templateAttachment.AccountID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) + } + includedScopeMap, err := resourceIBMSccTemplateAttachmentTemplateScopeToMap(templateAttachment.IncludedScope) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("included_scope", []map[string]interface{}{includedScopeMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting included_scope: %s", err)) + } + + excludedScope := []map[string]interface{}{} + if templateAttachment.ExcludedScopes != nil { + for _, excludedScopeItem := range templateAttachment.ExcludedScopes { + excludedScopeItemMap, err := resourceIBMSccTemplateAttachmentTemplateScopeToMap(&excludedScopeItem) + if err != nil { + return diag.FromErr(err) + } + excludedScope = append(excludedScope, excludedScopeItemMap) + } + } + if err = d.Set("excluded_scopes", excludedScope); err != nil { + return diag.FromErr(fmt.Errorf("Error setting excluded_scopes: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMSccTemplateAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + updateTemplateAttachmentOptions := &configurationgovernancev1.UpdateTemplateAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateTemplateAttachmentOptions.SetTemplateID(parts[0]) + updateTemplateAttachmentOptions.SetAttachmentID(parts[1]) + + if d.HasChange("template_id") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "template_id")) + } + + hasChange := d.HasChange("included_scope") || d.HasChange("excluded_scopes") + + updateTemplateAttachmentOptions.SetIfMatch(d.Get("version").(string)) + + if hasChange { + updateTemplateAttachmentOptions.SetIfMatch(d.Get("version").(string)) + updateTemplateAttachmentOptions.SetTemplateID(d.Get("template_id").(string)) + updateTemplateAttachmentOptions.SetAccountID(d.Get("account_id").(string)) + + includedScope, err := resourceIBMSccTemplateAttachmentMapToTemplateScope(d.Get("included_scope.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + updateTemplateAttachmentOptions.SetIncludedScope(includedScope) + + excludedScopes := []configurationgovernancev1.TemplateScope{} + if d.Get("excluded_scopes") != nil { + for _, scopeItem := range d.Get("excluded_scopes").([]interface{}) { + excludedScope, err := resourceIBMSccTemplateAttachmentMapToTemplateScope(scopeItem.(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + excludedScopes = append(excludedScopes, *excludedScope) + } + } + updateTemplateAttachmentOptions.SetExcludedScopes(excludedScopes) + + _, response, err := configurationGovernanceClient.UpdateTemplateAttachmentWithContext(context, updateTemplateAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] UpdateTemplateAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateTemplateAttachmentWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSccTemplateAttachmentRead(context, d, meta) +} + +func resourceIBMSccTemplateAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + configurationGovernanceClient, err := meta.(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return diag.FromErr(err) + } + + deleteTemplateAttachmentOptions := &configurationgovernancev1.DeleteTemplateAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTemplateAttachmentOptions.SetTemplateID(parts[0]) + deleteTemplateAttachmentOptions.SetAttachmentID(parts[1]) + + response, err := configurationGovernanceClient.DeleteTemplateAttachmentWithContext(context, deleteTemplateAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTemplateAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTemplateAttachmentWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMSccTemplateAttachmentMapToTemplateAttachmentRequest(d *schema.ResourceData) (*configurationgovernancev1.TemplateAttachmentRequest, error) { + model := &configurationgovernancev1.TemplateAttachmentRequest{} + model.AccountID = core.StringPtr(d.Get("account_id").(string)) + IncludedScopeModel, err := resourceIBMSccTemplateAttachmentMapToTemplateScope(d.Get("included_scope.0").(map[string]interface{})) + if err != nil { + return model, err + } + model.IncludedScope = IncludedScopeModel + if d.Get("excluded_scopes") != nil { + excludedScopes := []configurationgovernancev1.TemplateScope{} + for _, excludedScopesItem := range d.Get("excluded_scopes").([]interface{}) { + excludedScopesItemModel, err := resourceIBMSccTemplateAttachmentMapToTemplateScope(excludedScopesItem.(map[string]interface{})) + if err != nil { + return model, err + } + excludedScopes = append(excludedScopes, *excludedScopesItemModel) + } + model.ExcludedScopes = excludedScopes + } + return model, nil +} + +func resourceIBMSccTemplateAttachmentMapToTemplateScope(modelMap map[string]interface{}) (*configurationgovernancev1.TemplateScope, error) { + model := &configurationgovernancev1.TemplateScope{} + if modelMap["note"] != nil { + model.Note = core.StringPtr(modelMap["note"].(string)) + } + model.ScopeID = core.StringPtr(modelMap["scope_id"].(string)) + model.ScopeType = core.StringPtr(modelMap["scope_type"].(string)) + return model, nil +} + +func resourceIBMSccTemplateAttachmentTemplateAttachmentRequestToMap(model *configurationgovernancev1.TemplateAttachmentRequest) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["account_id"] = model.AccountID + includedScopeMap, err := resourceIBMSccTemplateAttachmentTemplateScopeToMap(model.IncludedScope) + if err != nil { + return modelMap, err + } + modelMap["included_scope"] = []map[string]interface{}{includedScopeMap} + if model.ExcludedScopes != nil { + excludedScopes := []map[string]interface{}{} + for _, excludedScopesItem := range model.ExcludedScopes { + excludedScopesItemMap, err := resourceIBMSccTemplateAttachmentTemplateScopeToMap(&excludedScopesItem) + if err != nil { + return modelMap, err + } + excludedScopes = append(excludedScopes, excludedScopesItemMap) + } + modelMap["excluded_scopes"] = excludedScopes + } + return modelMap, nil +} + +func resourceIBMSccTemplateAttachmentTemplateScopeToMap(model *configurationgovernancev1.TemplateScope) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Note != nil { + modelMap["note"] = model.Note + } + modelMap["scope_id"] = model.ScopeID + modelMap["scope_type"] = model.ScopeType + return modelMap, nil +} diff --git a/ibm/service/scc/resource_ibm_scc_template_attachment_test.go b/ibm/service/scc/resource_ibm_scc_template_attachment_test.go new file mode 100644 index 000000000..8dab7ddf4 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template_attachment_test.go @@ -0,0 +1,158 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func TestAccIBMSccTemplateAttachmentBasic(t *testing.T) { + var conf configurationgovernancev1.TemplateAttachment + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccTemplateAttachmentDestroy, + + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccTemplateAttachmentConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccTemplateAttachmentExists("ibm_scc_template_attachment.scc_template_attachment", conf), + ), + }, + resource.TestStep{ + ResourceName: "ibm_scc_template_attachment.scc_template_attachment", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccTemplateAttachmentConfigBasic() string { + account_id := os.Getenv("SCC_GOVERNANCE_ACCOUNT_ID") + resource_group_id := os.Getenv("IBM_SCC_RESOURCE_GROUP") + return fmt.Sprintf(` + resource "ibm_scc_template" "scc_template" { + account_id = "%s" + name = "Terraform template" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + } + } + customized_defaults { + property = "activity_tracking.write_data_events" + value = "true" + } + } + + resource "ibm_scc_template_attachment" "scc_template_attachment" { + template_id = ibm_scc_template.scc_template.id + account_id = "%s" + included_scope { + note = "note" + scope_id = "%s" + scope_type = "account" + } + excluded_scopes { + note = "note" + scope_id = "%s" + scope_type = "account.resource_group" + } + depends_on = [ + ibm_scc_template.scc_template + ] + } + `, account_id, account_id, account_id, resource_group_id) +} + +func testAccCheckIBMSccTemplateAttachmentExists(n string, obj configurationgovernancev1.TemplateAttachment) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + + getTemplateAttachmentOptions := &configurationgovernancev1.GetTemplateAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + templateID := parts[0] + getTemplateAttachmentOptions.SetTemplateID(templateID) + getTemplateAttachmentOptions.SetAttachmentID(parts[1]) + + templateAttachment, _, err := configurationGovernanceClient.GetTemplateAttachment(getTemplateAttachmentOptions) + if err != nil { + return err + } + + if *templateAttachment.TemplateID != templateID { + return fmt.Errorf( + "ibm_scc_template_attachment.scc_template_attachment: Attribute 'template_id' expected %#v, got %#v", + templateID, + templateAttachment.TemplateID, + ) + } + obj = *templateAttachment + return nil + } +} + +func testAccCheckIBMSccTemplateAttachmentDestroy(s *terraform.State) error { + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_template_attachment" { + continue + } + + getTemplateAttachmentOptions := &configurationgovernancev1.GetTemplateAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getTemplateAttachmentOptions.SetTemplateID(parts[0]) + getTemplateAttachmentOptions.SetAttachmentID(parts[1]) + + // Try to find the key + _, response, err := configurationGovernanceClient.GetTemplateAttachment(getTemplateAttachmentOptions) + + if err == nil { + return fmt.Errorf("scc_template_attachment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for scc_template_attachment (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_template_attachment_validator.go b/ibm/service/scc/resource_ibm_scc_template_attachment_validator.go new file mode 100644 index 000000000..a55862b2d --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template_attachment_validator.go @@ -0,0 +1,24 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMSccTemplateAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "scope_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "enterprise, enterprise.account_group, enterprise.account, account, account.resource_group", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_template_attachment", Schema: validateSchema} + return &resourceValidator +} diff --git a/ibm/service/scc/resource_ibm_scc_template_test.go b/ibm/service/scc/resource_ibm_scc_template_test.go new file mode 100644 index 000000000..d8f03e442 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template_test.go @@ -0,0 +1,118 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/scc-go-sdk/v3/configurationgovernancev1" +) + +func TestAccIBMSccTemplateBasic(t *testing.T) { + var conf configurationgovernancev1.TemplateResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSccTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMSccTemplateConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSccTemplateExists("ibm_scc_template.scc_template", conf), + ), + }, + resource.TestStep{ + ResourceName: "ibm_scc_template.scc_template", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSccTemplateConfigBasic() string { + account_id := os.Getenv("SCC_GOVERNANCE_ACCOUNT_ID") + return fmt.Sprintf(` + + resource "ibm_scc_template" "scc_template" { + account_id = "%s" + name = "Terraform template" + description = "description" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + } + } + customized_defaults { + property = "activity_tracking.write_data_events" + value = "true" + } + } + `, account_id) +} + +func testAccCheckIBMSccTemplateExists(n string, obj configurationgovernancev1.TemplateResponse) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + + getTemplateOptions := &configurationgovernancev1.GetTemplateOptions{} + + getTemplateOptions.SetTemplateID(rs.Primary.ID) + + template, _, err := configurationGovernanceClient.GetTemplate(getTemplateOptions) + if err != nil { + return err + } + + obj = *template + return nil + } +} + +func testAccCheckIBMSccTemplateDestroy(s *terraform.State) error { + configurationGovernanceClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ConfigurationGovernanceV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_scc_template" { + continue + } + + getTemplateOptions := &configurationgovernancev1.GetTemplateOptions{} + + getTemplateOptions.SetTemplateID(rs.Primary.ID) + + // Try to find the key + _, response, err := configurationGovernanceClient.GetTemplate(getTemplateOptions) + + if err == nil { + return fmt.Errorf("scc_template still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for scc_template (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/scc/resource_ibm_scc_template_validator.go b/ibm/service/scc/resource_ibm_scc_template_validator.go new file mode 100644 index 000000000..5e4bff9a3 --- /dev/null +++ b/ibm/service/scc/resource_ibm_scc_template_validator.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package scc + +import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" +) + +func ResourceIBMSccTemplateValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 3) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + MinValueLength: 1, + MaxValueLength: 32, + Regexp: ".*", + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "description", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + MinValueLength: 1, + MaxValueLength: 256, + Regexp: ".*", + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_name", + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Required: true, + Regexp: "^[a-z-]*$", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_scc_template", Schema: validateSchema} + return &resourceValidator +} diff --git a/ibm/service/schematics/README.md b/ibm/service/schematics/README.md new file mode 100644 index 000000000..32e7f0f29 --- /dev/null +++ b/ibm/service/schematics/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Schematics + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Schematics resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/schematics_action) +* IBM API Docs: [IBM API Docs for Schematics](https://cloud.ibm.com/apidocs/schematics/schematics) +* IBM Schematics SDK: [IBM SDK for Schematics](https://github.com/IBM/schematics-go-sdk) diff --git a/ibm/service/schematics/data_source_ibm_schematics_action.go b/ibm/service/schematics/data_source_ibm_schematics_action.go new file mode 100644 index 000000000..ad97052fa --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_action.go @@ -0,0 +1,1719 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsAction() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsActionRead, + + Schema: map[string]*schema.Schema{ + "action_id": { + Type: schema.TypeString, + Required: true, + Description: "Action Id. Use GET /actions API to look up the Action Ids in your IBM Cloud account.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Action description.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource-group name for an action. By default, action is created in default resource group.", + }, + "tags": { + Type: schema.TypeList, + Computed: true, + Description: "Action tags.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "user_state": { + Type: schema.TypeList, + Computed: true, + Description: "User defined status of the Schematics object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": { + Type: schema.TypeString, + Computed: true, + Description: "User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution.", + }, + "set_by": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the User who set the state of the Object.", + }, + "set_at": { + Type: schema.TypeString, + Computed: true, + Description: "When the User who set the state of the Object.", + }, + }, + }, + }, + "source_readme_url": { + Type: schema.TypeString, + Computed: true, + Description: "URL of the `README` file, for the source URL.", + }, + "source": { + Type: schema.TypeList, + Computed: true, + Description: "Source of templates, playbooks, or controls.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of source for the Template.", + }, + "git": { + Type: schema.TypeList, + Computed: true, + Description: "Connection details to Git source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "computed_git_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + }, + "git_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "URL to the GIT Repo that can be used to clone the template.", + }, + "git_token": { + Type: schema.TypeString, + Computed: true, + Description: "Personal Access Token to connect to Git URLs.", + }, + "git_repo_folder": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the folder in the Git Repo, that contains the template.", + }, + "git_release": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the release tag, used to fetch the Git Repo.", + }, + "git_branch": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the branch, used to fetch the Git Repo.", + }, + }, + }, + }, + "catalog": { + Type: schema.TypeList, + Computed: true, + Description: "Connection details to IBM Cloud Catalog source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_name": { + Type: schema.TypeString, + Computed: true, + Description: "name of the private catalog.", + }, + "offering_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the offering in the IBM Catalog.", + }, + "offering_version": { + Type: schema.TypeString, + Computed: true, + Description: "Version string of the offering in the IBM Catalog.", + }, + "offering_kind": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the offering, in the IBM Catalog.", + }, + "offering_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the offering the IBM Catalog.", + }, + "offering_version_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the offering version the IBM Catalog.", + }, + "offering_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "Repo Url of the offering, in the IBM Catalog.", + }, + }, + }, + }, + // "cos_bucket": { + // Type: schema.TypeList, + // Computed: true, + // Description: "Connection details to a IBM Cloud Object Storage bucket.", + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "cos_bucket_url": { + // Type: schema.TypeString, + // Computed: true, + // Description: "COS Bucket Url.", + // }, + // }, + // }, + // }, + }, + }, + }, + "source_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of source for the Template.", + }, + "command_parameter": { + Type: schema.TypeString, + Computed: true, + Description: "Schematics job command parameter (playbook-name).", + }, + "inventory": { + Type: schema.TypeString, + Computed: true, + Description: "Target inventory record ID, used by the action or ansible playbook.", + }, + "credentials": { + Type: schema.TypeList, + Computed: true, + Description: "credentials of the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + // "secure": { + // Type: schema.TypeBool, + // Computed: true, + // Description: "Is the variable secure or sensitive ?.", + // }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + // "options": { + // Type: schema.TypeList, + // Computed: true, + // Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + // Elem: &schema.Schema{ + // Type: schema.TypeString, + // }, + // }, + // "min_value": { + // Type: schema.TypeInt, + // Computed: true, + // Description: "Minimum value of the variable. Applicable for integer type.", + // }, + // "max_value": { + // Type: schema.TypeInt, + // Computed: true, + // Description: "Maximum value of the variable. Applicable for integer type.", + // }, + // "min_length": { + // Type: schema.TypeInt, + // Computed: true, + // Description: "Minimum length of the variable value. Applicable for string type.", + // }, + // "max_length": { + // Type: schema.TypeInt, + // Computed: true, + // Description: "Maximum length of the variable value. Applicable for string type.", + // }, + // "matches": { + // Type: schema.TypeString, + // Computed: true, + // Description: "Regex for the variable value.", + // }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "bastion": { + Type: schema.TypeList, + Computed: true, + Description: "Describes a bastion resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Bastion Name(Unique).", + }, + "host": { + Type: schema.TypeString, + Computed: true, + Description: "Reference to the Inventory resource definition.", + }, + }, + }, + }, + "bastion_credential": { + Type: schema.TypeList, + Computed: true, + Description: "User editable variable data & system generated reference to value.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "targets_ini": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", + }, + "action_inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Input variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "action_outputs": { + Type: schema.TypeList, + Computed: true, + Description: "Output variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Action ID.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Action Cloud Resource Name.", + }, + "account": { + Type: schema.TypeString, + Computed: true, + Description: "Action account ID.", + }, + "source_created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action Playbook Source creation time.", + }, + "source_created_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of user who created the Action Playbook Source.", + }, + "source_updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The action playbook updation time.", + }, + "source_updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of user who updated the action playbook source.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of the user who created an action.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of the user who updated an action.", + }, + "state": { + Type: schema.TypeList, + Computed: true, + Description: "Computed state of the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of automation (workspace or action).", + }, + "status_job_id": { + Type: schema.TypeString, + Computed: true, + Description: "Job id reference for this status.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Automation status message - to be displayed along with the status_code.", + }, + }, + }, + }, + "playbook_names": { + Type: schema.TypeList, + Computed: true, + Description: "Playbook names retrieved from the respository.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "sys_lock": { + Type: schema.TypeList, + Computed: true, + Description: "System lock status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sys_locked": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the automation locked by a Schematic job ?.", + }, + "sys_locked_by": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the User who performed the job, that lead to the locking of the automation.", + }, + "sys_locked_at": { + Type: schema.TypeString, + Computed: true, + Description: "When the User performed the job that lead to locking of the automation ?.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSchematicsActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + getActionOptions := &schematicsv1.GetActionOptions{} + + getActionOptions.SetActionID(d.Get("action_id").(string)) + + action, response, err := schematicsClient.GetActionWithContext(context, getActionOptions) + if err != nil { + log.Printf("[DEBUG] GetActionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetActionWithContext failed %s\n%s", err, response)) + } + + d.SetId(*getActionOptions.ActionID) + if err = d.Set("name", action.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", action.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", action.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("resource_group", action.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + + if action.UserState != nil { + err = d.Set("user_state", dataSourceActionFlattenUserState(*action.UserState)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting user_state %s", err)) + } + } + if err = d.Set("source_readme_url", action.SourceReadmeURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_readme_url: %s", err)) + } + + if action.Source != nil { + err = d.Set("source", dataSourceActionFlattenSource(*action.Source)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source %s", err)) + } + } + if err = d.Set("source_type", action.SourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_type: %s", err)) + } + if err = d.Set("command_parameter", action.CommandParameter); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_parameter: %s", err)) + } + if err = d.Set("inventory", action.Inventory); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting inventory: %s", err)) + } + + if action.Credentials != nil { + err = d.Set("credentials", dataSourceActionFlattenCredentials(action.Credentials)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting credentials %s", err)) + } + } + + if action.Bastion != nil { + err = d.Set("bastion", dataSourceActionFlattenBastion(*action.Bastion)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion %s", err)) + } + } + + if action.BastionCredential != nil { + err = d.Set("bastion_credential", dataSourceActionFlattenBastionCredential(*action.BastionCredential)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion_credential %s", err)) + } + } + if err = d.Set("targets_ini", action.TargetsIni); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting targets_ini: %s", err)) + } + + if action.Inputs != nil { + err = d.Set("action_inputs", dataSourceActionFlattenInputs(action.Inputs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action_inputs %s", err)) + } + } + + if action.Outputs != nil { + err = d.Set("action_outputs", dataSourceActionFlattenOutputs(action.Outputs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action_outputs %s", err)) + } + } + + if action.Settings != nil { + err = d.Set("settings", dataSourceActionFlattenSettings(action.Settings)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting settings %s", err)) + } + } + if err = d.Set("id", action.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) + } + if err = d.Set("crn", action.Crn); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("account", action.Account); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account: %s", err)) + } + if err = d.Set("source_created_at", flex.DateTimeToString(action.SourceCreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_created_at: %s", err)) + } + if err = d.Set("source_created_by", action.SourceCreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_created_by: %s", err)) + } + if err = d.Set("source_updated_at", flex.DateTimeToString(action.SourceUpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_updated_at: %s", err)) + } + if err = d.Set("source_updated_by", action.SourceUpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_updated_by: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(action.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", action.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(action.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", action.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + + if action.State != nil { + err = d.Set("state", dataSourceActionFlattenState(*action.State)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state %s", err)) + } + } + + if action.SysLock != nil { + err = d.Set("sys_lock", dataSourceActionFlattenSysLock(*action.SysLock)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sys_lock %s", err)) + } + } + + return nil +} + +func dataSourceActionFlattenUserState(result schematicsv1.UserState) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionUserStateToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionUserStateToMap(userStateItem schematicsv1.UserState) (userStateMap map[string]interface{}) { + userStateMap = map[string]interface{}{} + + if userStateItem.State != nil { + userStateMap["state"] = userStateItem.State + } + if userStateItem.SetBy != nil { + userStateMap["set_by"] = userStateItem.SetBy + } + if userStateItem.SetAt != nil { + userStateMap["set_at"] = userStateItem.SetAt.String() + } + + return userStateMap +} + +func dataSourceActionFlattenSource(result schematicsv1.ExternalSource) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionSourceToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionSourceToMap(sourceItem schematicsv1.ExternalSource) (sourceMap map[string]interface{}) { + sourceMap = map[string]interface{}{} + + if sourceItem.SourceType != nil { + sourceMap["source_type"] = sourceItem.SourceType + } + if sourceItem.Git != nil { + gitList := []map[string]interface{}{} + gitMap := dataSourceActionSourceGitToMap(*sourceItem.Git) + gitList = append(gitList, gitMap) + sourceMap["git"] = gitList + } + if sourceItem.Catalog != nil { + catalogList := []map[string]interface{}{} + catalogMap := dataSourceActionSourceCatalogToMap(*sourceItem.Catalog) + catalogList = append(catalogList, catalogMap) + sourceMap["catalog"] = catalogList + } + // if sourceItem.CosBucket != nil { + // cosBucketList := []map[string]interface{}{} + // cosBucketMap := dataSourceActionSourceCosBucketToMap(*sourceItem.CosBucket) + // cosBucketList = append(cosBucketList, cosBucketMap) + // sourceMap["cos_bucket"] = cosBucketList + // } + + return sourceMap +} + +func dataSourceActionSourceGitToMap(gitItem schematicsv1.GitSource) (gitMap map[string]interface{}) { + gitMap = map[string]interface{}{} + + if gitItem.ComputedGitRepoURL != nil { + gitMap["computed_git_repo_url"] = gitItem.ComputedGitRepoURL + } + if gitItem.GitRepoURL != nil { + gitMap["git_repo_url"] = gitItem.GitRepoURL + } + if gitItem.GitToken != nil { + gitMap["git_token"] = gitItem.GitToken + } + if gitItem.GitRepoFolder != nil { + gitMap["git_repo_folder"] = gitItem.GitRepoFolder + } + if gitItem.GitRelease != nil { + gitMap["git_release"] = gitItem.GitRelease + } + if gitItem.GitBranch != nil { + gitMap["git_branch"] = gitItem.GitBranch + } + + return gitMap +} + +func dataSourceActionSourceCatalogToMap(catalogItem schematicsv1.CatalogSource) (catalogMap map[string]interface{}) { + catalogMap = map[string]interface{}{} + + if catalogItem.CatalogName != nil { + catalogMap["catalog_name"] = catalogItem.CatalogName + } + if catalogItem.OfferingName != nil { + catalogMap["offering_name"] = catalogItem.OfferingName + } + if catalogItem.OfferingVersion != nil { + catalogMap["offering_version"] = catalogItem.OfferingVersion + } + if catalogItem.OfferingKind != nil { + catalogMap["offering_kind"] = catalogItem.OfferingKind + } + if catalogItem.OfferingID != nil { + catalogMap["offering_id"] = catalogItem.OfferingID + } + if catalogItem.OfferingVersionID != nil { + catalogMap["offering_version_id"] = catalogItem.OfferingVersionID + } + if catalogItem.OfferingRepoURL != nil { + catalogMap["offering_repo_url"] = catalogItem.OfferingRepoURL + } + + return catalogMap +} + +// func dataSourceActionSourceCosBucketToMap(cosBucketItem schematicsv1.ExternalSourceCosBucket) (cosBucketMap map[string]interface{}) { +// cosBucketMap = map[string]interface{}{} + +// if cosBucketItem.CosBucketURL != nil { +// cosBucketMap["cos_bucket_url"] = cosBucketItem.CosBucketURL +// } + +// return cosBucketMap +// } + +func dataSourceActionFlattenCredentials(result []schematicsv1.CredentialVariableData) (credentials []map[string]interface{}) { + for _, credentialsItem := range result { + credentials = append(credentials, dataSourceActionCredentialsToMap(credentialsItem)) + } + + return credentials +} + +func dataSourceActionCredentialsToMap(credentialsItem schematicsv1.CredentialVariableData) (credentialsMap map[string]interface{}) { + credentialsMap = map[string]interface{}{} + + if credentialsItem.Name != nil { + credentialsMap["name"] = credentialsItem.Name + } + if credentialsItem.Value != nil { + credentialsMap["value"] = credentialsItem.Value + } + if credentialsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceActionCredentialsMetadataToMap(*credentialsItem.Metadata) + metadataList = append(metadataList, metadataMap) + credentialsMap["metadata"] = metadataList + } + if credentialsItem.Link != nil { + credentialsMap["link"] = credentialsItem.Link + } + + return credentialsMap +} + +func dataSourceActionCredentialsMetadataToMap(metadataItem schematicsv1.CredentialVariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + // if metadataItem.Secure != nil { + // metadataMap["secure"] = metadataItem.Secure + // } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + // if metadataItem.Options != nil { + // metadataMap["options"] = metadataItem.Options + // } + // if metadataItem.MinValue != nil { + // metadataMap["min_value"] = metadataItem.MinValue + // } + // if metadataItem.MaxValue != nil { + // metadataMap["max_value"] = metadataItem.MaxValue + // } + // if metadataItem.MinLength != nil { + // metadataMap["min_length"] = metadataItem.MinLength + // } + // if metadataItem.MaxLength != nil { + // metadataMap["max_length"] = metadataItem.MaxLength + // } + // if metadataItem.Matches != nil { + // metadataMap["matches"] = metadataItem.Matches + // } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceActionFlattenBastion(result schematicsv1.BastionResourceDefinition) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionBastionToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionBastionToMap(bastionItem schematicsv1.BastionResourceDefinition) (bastionMap map[string]interface{}) { + bastionMap = map[string]interface{}{} + + if bastionItem.Name != nil { + bastionMap["name"] = bastionItem.Name + } + if bastionItem.Host != nil { + bastionMap["host"] = bastionItem.Host + } + + return bastionMap +} + +func dataSourceActionFlattenBastionCredential(result schematicsv1.CredentialVariableData) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionBastionCredentialToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionBastionCredentialToMap(bastionCredentialItem schematicsv1.CredentialVariableData) (bastionCredentialMap map[string]interface{}) { + bastionCredentialMap = map[string]interface{}{} + + if bastionCredentialItem.Name != nil { + bastionCredentialMap["name"] = bastionCredentialItem.Name + } + if bastionCredentialItem.Value != nil { + bastionCredentialMap["value"] = bastionCredentialItem.Value + } + if bastionCredentialItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceActionBastionCredentialMetadataToMap(*bastionCredentialItem.Metadata) + metadataList = append(metadataList, metadataMap) + bastionCredentialMap["metadata"] = metadataList + } + if bastionCredentialItem.Link != nil { + bastionCredentialMap["link"] = bastionCredentialItem.Link + } + + return bastionCredentialMap +} + +func dataSourceActionBastionCredentialMetadataToMap(metadataItem schematicsv1.CredentialVariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + // if metadataItem.Secure != nil { + // metadataMap["secure"] = metadataItem.Secure + // } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + // if metadataItem.Options != nil { + // metadataMap["options"] = metadataItem.Options + // } + // if metadataItem.MinValue != nil { + // metadataMap["min_value"] = metadataItem.MinValue + // } + // if metadataItem.MaxValue != nil { + // metadataMap["max_value"] = metadataItem.MaxValue + // } + // if metadataItem.MinLength != nil { + // metadataMap["min_length"] = metadataItem.MinLength + // } + // if metadataItem.MaxLength != nil { + // metadataMap["max_length"] = metadataItem.MaxLength + // } + // if metadataItem.Matches != nil { + // metadataMap["matches"] = metadataItem.Matches + // } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceActionFlattenInputs(result []schematicsv1.VariableData) (actionInputs []map[string]interface{}) { + for _, actionInputsItem := range result { + actionInputs = append(actionInputs, dataSourceActionInputsToMap(actionInputsItem)) + } + + return actionInputs +} + +func dataSourceActionInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceActionInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceActionInputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceActionFlattenOutputs(result []schematicsv1.VariableData) (actionOutputs []map[string]interface{}) { + for _, actionOutputsItem := range result { + actionOutputs = append(actionOutputs, dataSourceActionOutputsToMap(actionOutputsItem)) + } + + return actionOutputs +} + +func dataSourceActionOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { + outputsMap = map[string]interface{}{} + + if outputsItem.Name != nil { + outputsMap["name"] = outputsItem.Name + } + if outputsItem.Value != nil { + outputsMap["value"] = outputsItem.Value + } + if outputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceActionOutputsMetadataToMap(*outputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + outputsMap["metadata"] = metadataList + } + if outputsItem.Link != nil { + outputsMap["link"] = outputsItem.Link + } + + return outputsMap +} + +func dataSourceActionOutputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceActionFlattenSettings(result []schematicsv1.VariableData) (settings []map[string]interface{}) { + for _, settingsItem := range result { + settings = append(settings, dataSourceActionSettingsToMap(settingsItem)) + } + + return settings +} + +func dataSourceActionSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceActionSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceActionSettingsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceActionFlattenState(result schematicsv1.ActionState) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionStateToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionStateToMap(stateItem schematicsv1.ActionState) (stateMap map[string]interface{}) { + stateMap = map[string]interface{}{} + + if stateItem.StatusCode != nil { + stateMap["status_code"] = stateItem.StatusCode + } + if stateItem.StatusJobID != nil { + stateMap["status_job_id"] = stateItem.StatusJobID + } + if stateItem.StatusMessage != nil { + stateMap["status_message"] = stateItem.StatusMessage + } + + return stateMap +} + +func dataSourceActionFlattenSysLock(result schematicsv1.SystemLock) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceActionSysLockToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceActionSysLockToMap(sysLockItem schematicsv1.SystemLock) (sysLockMap map[string]interface{}) { + sysLockMap = map[string]interface{}{} + + if sysLockItem.SysLocked != nil { + sysLockMap["sys_locked"] = sysLockItem.SysLocked + } + if sysLockItem.SysLockedBy != nil { + sysLockMap["sys_locked_by"] = sysLockItem.SysLockedBy + } + if sysLockItem.SysLockedAt != nil { + sysLockMap["sys_locked_at"] = sysLockItem.SysLockedAt.String() + } + + return sysLockMap +} diff --git a/ibm/data_source_ibm_schematics_action_test.go b/ibm/service/schematics/data_source_ibm_schematics_action_test.go similarity index 92% rename from ibm/data_source_ibm_schematics_action_test.go rename to ibm/service/schematics/data_source_ibm_schematics_action_test.go index de855256d..b59d97335 100644 --- a/ibm/data_source_ibm_schematics_action_test.go +++ b/ibm/service/schematics/data_source_ibm_schematics_action_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,10 +18,10 @@ func TestAccIBMSchematicsActionDataSourceBasic(t *testing.T) { actionName := fmt.Sprintf("acc-test-schematics-actions_%s", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSchematicsActionDataSourceConfigBasic(actionName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_schematics_action.schematics_action", "id"), diff --git a/ibm/service/schematics/data_source_ibm_schematics_inventory.go b/ibm/service/schematics/data_source_ibm_schematics_inventory.go new file mode 100644 index 000000000..bbd7746e2 --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_inventory.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsInventory() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsInventoryRead, + + Schema: map[string]*schema.Schema{ + "inventory_id": { + Type: schema.TypeString, + Required: true, + Description: "Resource Inventory Id. Use `GET /v2/inventories` API to look up the Resource Inventory definition Ids in your IBM Cloud account.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory id.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of your Inventory. The description can be up to 2048 characters long in size.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who created the Inventory.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who updated the Inventory.", + }, + "inventories_ini": { + Type: schema.TypeString, + Computed: true, + Description: "Input inventory of host and host group for the playbook, in the .ini file format.", + }, + "resource_queries": { + Type: schema.TypeList, + Computed: true, + Description: "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMSchematicsInventoryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + + getInventoryOptions := &schematicsv1.GetInventoryOptions{} + + getInventoryOptions.SetInventoryID(d.Get("inventory_id").(string)) + + inventoryResourceRecord, response, err := schematicsClient.GetInventoryWithContext(context, getInventoryOptions) + if err != nil { + log.Printf("[DEBUG] GetInventoryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInventoryWithContext failed %s\n%s", err, response)) + } + + d.SetId(*getInventoryOptions.InventoryID) + if err = d.Set("name", inventoryResourceRecord.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("id", inventoryResourceRecord.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) + } + if err = d.Set("description", inventoryResourceRecord.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", inventoryResourceRecord.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("resource_group", inventoryResourceRecord.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(inventoryResourceRecord.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", inventoryResourceRecord.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(inventoryResourceRecord.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", inventoryResourceRecord.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + if err = d.Set("inventories_ini", inventoryResourceRecord.InventoriesIni); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting inventories_ini: %s", err)) + } + + return nil +} diff --git a/ibm/service/schematics/data_source_ibm_schematics_inventory_test.go b/ibm/service/schematics/data_source_ibm_schematics_inventory_test.go new file mode 100644 index 000000000..5e29ebe26 --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_inventory_test.go @@ -0,0 +1,88 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSchematicsInventoryDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsInventoryDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "id"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "inventory_id"), + ), + }, + }, + }) +} + +func TestAccIBMSchematicsInventoryDataSourceAllArgs(t *testing.T) { + inventoryResourceRecordName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + inventoryResourceRecordDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + inventoryResourceRecordLocation := "us-south" + inventoryResourceRecordResourceGroup := fmt.Sprintf("tf_resource_group_%d", acctest.RandIntRange(10, 100)) + inventoryResourceRecordInventoriesIni := fmt.Sprintf("tf_inventories_ini_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsInventoryDataSourceConfig(inventoryResourceRecordName, inventoryResourceRecordDescription, inventoryResourceRecordLocation, inventoryResourceRecordResourceGroup, inventoryResourceRecordInventoriesIni), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "id"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "inventory_id"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "name"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "id"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "description"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "location"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "resource_group"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "created_by"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_inventory.schematics_inventory", "updated_at"), + ), + }, + }, + }) +} + +func testAccCheckIBMSchematicsInventoryDataSourceConfigBasic() string { + return ` + resource "ibm_schematics_inventory" "schematics_inventory" { + name = "test_inventory" + location = "us-south" + } + + data "ibm_schematics_inventory" "schematics_inventory" { + inventory_id = ibm_schematics_inventory.schematics_inventory.id + } + ` +} + +func testAccCheckIBMSchematicsInventoryDataSourceConfig(inventoryResourceRecordName string, inventoryResourceRecordDescription string, inventoryResourceRecordLocation string, inventoryResourceRecordResourceGroup string, inventoryResourceRecordInventoriesIni string) string { + return fmt.Sprintf(` + resource "ibm_schematics_inventory" "schematics_inventory" { + name = "%s" + description = "%s" + location = "%s" + resource_group = "%s" + } + + data "ibm_schematics_inventory" "schematics_inventory" { + inventory_id = ibm_schematics_inventory.schematics_inventory.id + } + `, inventoryResourceRecordName, inventoryResourceRecordDescription, inventoryResourceRecordLocation, inventoryResourceRecordResourceGroup) +} diff --git a/ibm/service/schematics/data_source_ibm_schematics_job.go b/ibm/service/schematics/data_source_ibm_schematics_job.go new file mode 100644 index 000000000..64f35170d --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_job.go @@ -0,0 +1,4378 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsJob() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsJobRead, + + Schema: map[string]*schema.Schema{ + "job_id": { + Type: schema.TypeString, + Required: true, + Description: "Job Id. Use `GET /v2/jobs` API to look up the Job Ids in your IBM Cloud account.", + }, + "command_object": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Schematics automation resource.", + }, + "command_object_id": { + Type: schema.TypeString, + Computed: true, + Description: "Job command object id (workspace-id, action-id).", + }, + "command_name": { + Type: schema.TypeString, + Computed: true, + Description: "Schematics job command name.", + }, + "command_parameter": { + Type: schema.TypeString, + Computed: true, + Description: "Schematics job command parameter (playbook-name).", + }, + "command_options": { + Type: schema.TypeList, + Computed: true, + Description: "Command line options for the command.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "job_inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Job inputs used by Action or Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "job_env_settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables used by the Job while performing Action or Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "tags": { + Type: schema.TypeList, + Computed: true, + Description: "User defined tags, while running the job.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Job ID.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Job name, uniquely derived from the related Workspace or Action.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource-group name derived from the related Workspace or Action.", + }, + "submitted_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job submission time.", + }, + "submitted_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who submitted the job.", + }, + "start_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job start time.", + }, + "end_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job end time.", + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: "Duration of job execution; example 40 sec.", + }, + "status": { + Type: schema.TypeList, + Computed: true, + Description: "Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_job_status": { + Type: schema.TypeList, + Computed: true, + Description: "Workspace Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_name": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace name.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace).", + }, + "flow_status": { + Type: schema.TypeList, + Computed: true, + Description: "Environment Flow JOB Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Computed: true, + Description: "flow id.", + }, + "flow_name": { + Type: schema.TypeString, + Computed: true, + Description: "flow name.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Flow Job status message - to be displayed along with the status_code;.", + }, + "workitems": { + Type: schema.TypeList, + Computed: true, + Description: "Environment's individual workItem status details;.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace id.", + }, + "workspace_name": { + Type: schema.TypeString, + Computed: true, + Description: "workspace name.", + }, + "job_id": { + Type: schema.TypeString, + Computed: true, + Description: "workspace job id.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "workitem job status message;.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "workitem job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "template_status": { + Type: schema.TypeList, + Computed: true, + Description: "Workspace Flow Template job status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Computed: true, + Description: "Template Id.", + }, + "template_name": { + Type: schema.TypeString, + Computed: true, + Description: "Template name.", + }, + "flow_index": { + Type: schema.TypeInt, + Computed: true, + Description: "Index of the template in the Flow.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template).", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "action_job_status": { + Type: schema.TypeList, + Computed: true, + Description: "Action Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_name": { + Type: schema.TypeString, + Computed: true, + Description: "Action name.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Action Job status message - to be displayed along with the action_status_code.", + }, + "bastion_status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Resources.", + }, + "bastion_status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Bastion status message - to be displayed along with the bastion_status_code;.", + }, + "targets_status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Resources.", + }, + "targets_status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Aggregated status message for all target resources, to be displayed along with the targets_status_code;.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "system_job_status": { + Type: schema.TypeList, + Computed: true, + Description: "System Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "system_status_message": { + Type: schema.TypeString, + Computed: true, + Description: "System job message.", + }, + "system_status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "schematics_resource_status": { + Type: schema.TypeList, + Computed: true, + Description: "job staus for each schematics resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "system job status message.", + }, + "schematics_resource_id": { + Type: schema.TypeString, + Computed: true, + Description: "id for each resource which is targeted as a part of system job.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "flow_job_status": { + Type: schema.TypeList, + Computed: true, + Description: "Environment Flow JOB Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Computed: true, + Description: "flow id.", + }, + "flow_name": { + Type: schema.TypeString, + Computed: true, + Description: "flow name.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "Flow Job status message - to be displayed along with the status_code;.", + }, + "workitems": { + Type: schema.TypeList, + Computed: true, + Description: "Environment's individual workItem status details;.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace id.", + }, + "workspace_name": { + Type: schema.TypeString, + Computed: true, + Description: "workspace name.", + }, + "job_id": { + Type: schema.TypeString, + Computed: true, + Description: "workspace job id.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Computed: true, + Description: "workitem job status message;.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "workitem job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + }, + }, + }, + "data": { + Type: schema.TypeList, + Computed: true, + Description: "Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "job_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of Job.", + }, + "workspace_job_data": { + Type: schema.TypeList, + Computed: true, + Description: "Workspace Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_name": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace name.", + }, + "flow_id": { + Type: schema.TypeString, + Computed: true, + Description: "Flow Id.", + }, + "flow_name": { + Type: schema.TypeString, + Computed: true, + Description: "Flow name.", + }, + "inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Input variables data used by the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Computed: true, + Description: "Output variables data from the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables used by all the templates in the Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "template_data": { + Type: schema.TypeList, + Computed: true, + Description: "Input / output data of the Template in the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Computed: true, + Description: "Template Id.", + }, + "template_name": { + Type: schema.TypeString, + Computed: true, + Description: "Template name.", + }, + "flow_index": { + Type: schema.TypeInt, + Computed: true, + Description: "Index of the template in the Flow.", + }, + "inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Job inputs used by the Templates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Computed: true, + Description: "Job output from the Templates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables used by the template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "action_job_data": { + Type: schema.TypeList, + Computed: true, + Description: "Action Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_name": { + Type: schema.TypeString, + Computed: true, + Description: "Flow name.", + }, + "inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Input variables data used by the Action Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Computed: true, + Description: "Output variables data from the Action Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables used by all the templates in the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + "inventory_record": { + Type: schema.TypeList, + Computed: true, + Description: "Complete inventory resource details with user inputs and system generated data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory id.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of your Inventory. The description can be up to 2048 characters long in size.", + }, + "location": { + Type: schema.TypeString, + Computed: true, + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who created the Inventory.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who updated the Inventory.", + }, + "inventories_ini": { + Type: schema.TypeString, + Computed: true, + Description: "Input inventory of host and host group for the playbook, in the .ini file format.", + }, + "resource_queries": { + Type: schema.TypeList, + Computed: true, + Description: "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "materialized_inventory": { + Type: schema.TypeString, + Computed: true, + Description: "Materialized inventory details used by the Action Job, in .ini format.", + }, + }, + }, + }, + "system_job_data": { + Type: schema.TypeList, + Computed: true, + Description: "Controls Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_id": { + Type: schema.TypeString, + Computed: true, + Description: "Key ID for which key event is generated.", + }, + "schematics_resource_id": { + Type: schema.TypeList, + Computed: true, + Description: "List of the schematics resource id.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "flow_job_data": { + Type: schema.TypeList, + Computed: true, + Description: "Flow Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Computed: true, + Description: "Flow ID.", + }, + "flow_name": { + Type: schema.TypeString, + Computed: true, + Description: "Flow Name.", + }, + "workitems": { + Type: schema.TypeList, + Computed: true, + Description: "Job data used by each workitem Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command_object_id": { + Type: schema.TypeString, + Computed: true, + Description: "command object id.", + }, + "command_object_name": { + Type: schema.TypeString, + Computed: true, + Description: "command object name.", + }, + "layers": { + Type: schema.TypeString, + Computed: true, + Description: "layer name.", + }, + "source_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of source for the Template.", + }, + "source": { + Type: schema.TypeList, + Computed: true, + Description: "Source of templates, playbooks, or controls.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of source for the Template.", + }, + "git": { + Type: schema.TypeList, + Computed: true, + Description: "Connection details to Git source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "computed_git_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + }, + "git_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "URL to the GIT Repo that can be used to clone the template.", + }, + "git_token": { + Type: schema.TypeString, + Computed: true, + Description: "Personal Access Token to connect to Git URLs.", + }, + "git_repo_folder": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the folder in the Git Repo, that contains the template.", + }, + "git_release": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the release tag, used to fetch the Git Repo.", + }, + "git_branch": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the branch, used to fetch the Git Repo.", + }, + }, + }, + }, + "catalog": { + Type: schema.TypeList, + Computed: true, + Description: "Connection details to IBM Cloud Catalog source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_name": { + Type: schema.TypeString, + Computed: true, + Description: "name of the private catalog.", + }, + "offering_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the offering in the IBM Catalog.", + }, + "offering_version": { + Type: schema.TypeString, + Computed: true, + Description: "Version string of the offering in the IBM Catalog.", + }, + "offering_kind": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the offering, in the IBM Catalog.", + }, + "offering_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the offering the IBM Catalog.", + }, + "offering_version_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the offering version the IBM Catalog.", + }, + "offering_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "Repo Url of the offering, in the IBM Catalog.", + }, + }, + }, + }, + // "cos_bucket": { + // Type: schema.TypeList, + // Computed: true, + // Description: "Connection details to a IBM Cloud Object Storage bucket.", + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "cos_bucket_url": { + // Type: schema.TypeString, + // Computed: true, + // Description: "COS Bucket Url.", + // }, + // }, + // }, + // }, + }, + }, + }, + "inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Input variables data for the workItem used in FlowJob.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Computed: true, + Description: "Output variables for the workItem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Computed: true, + Description: "Environment variables for the workItem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Computed: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Computed: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Computed: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Computed: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Computed: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Computed: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Computed: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "last_job": { + Type: schema.TypeList, + Computed: true, + Description: "Status of the last job executed by the workitem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command_object": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Schematics automation resource.", + }, + "command_object_name": { + Type: schema.TypeString, + Computed: true, + Description: "command object name (workspace_name/action_name).", + }, + "command_object_id": { + Type: schema.TypeString, + Computed: true, + Description: "Workitem command object id, maps to workspace_id or action_id.", + }, + "command_name": { + Type: schema.TypeString, + Computed: true, + Description: "Schematics job command name.", + }, + "job_id": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace job id.", + }, + "job_status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of Jobs.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + }, + }, + }, + "bastion": { + Type: schema.TypeList, + Computed: true, + Description: "Describes a bastion resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Bastion Name(Unique).", + }, + "host": { + Type: schema.TypeString, + Computed: true, + Description: "Reference to the Inventory resource definition.", + }, + }, + }, + }, + "log_summary": { + Type: schema.TypeList, + Computed: true, + Description: "Job log summary record.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "job_id": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace Id.", + }, + "job_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of Job.", + }, + "log_start_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job log start timestamp.", + }, + "log_analyzed_till": { + Type: schema.TypeString, + Computed: true, + Description: "Job log update timestamp.", + }, + "elapsed_time": { + Type: schema.TypeFloat, + Computed: true, + Description: "Job log elapsed time (log_analyzed_till - log_start_at).", + }, + "log_errors": { + Type: schema.TypeList, + Computed: true, + Description: "Job log errors.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "error_code": { + Type: schema.TypeString, + Computed: true, + Description: "Error code in the Log.", + }, + "error_msg": { + Type: schema.TypeString, + Computed: true, + Description: "Summary error message in the log.", + }, + "error_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of occurrence.", + }, + }, + }, + }, + "repo_download_job": { + Type: schema.TypeList, + Computed: true, + Description: "Repo download Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scanned_file_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of files scanned.", + }, + "quarantined_file_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of files quarantined.", + }, + "detected_filetype": { + Type: schema.TypeString, + Computed: true, + Description: "Detected template or data file type.", + }, + "inputs_count": { + Type: schema.TypeString, + Computed: true, + Description: "Number of inputs detected.", + }, + "outputs_count": { + Type: schema.TypeString, + Computed: true, + Description: "Number of outputs detected.", + }, + }, + }, + }, + "workspace_job": { + Type: schema.TypeList, + Computed: true, + Description: "Workspace Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resources_add": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources add.", + }, + "resources_modify": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources modify.", + }, + "resources_destroy": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources destroy.", + }, + }, + }, + }, + "flow_job": { + Type: schema.TypeList, + Computed: true, + Description: "Flow Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workitems_completed": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of workitems completed successfully.", + }, + "workitems_pending": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of workitems pending in the flow.", + }, + "workitems_failed": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of workitems failed.", + }, + "workitems": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Computed: true, + Description: "workspace ID.", + }, + "job_id": { + Type: schema.TypeString, + Computed: true, + Description: "workspace JOB ID.", + }, + "resources_add": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources add.", + }, + "resources_modify": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources modify.", + }, + "resources_destroy": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of resources destroy.", + }, + "log_url": { + Type: schema.TypeString, + Computed: true, + Description: "Log url for job.", + }, + }, + }, + }, + }, + }, + }, + "action_job": { + Type: schema.TypeList, + Computed: true, + Description: "Flow Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "number of targets or hosts.", + }, + "task_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "number of tasks in playbook.", + }, + "play_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "number of plays in playbook.", + }, + "recap": { + Type: schema.TypeList, + Computed: true, + Description: "Recap records.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target": { + Type: schema.TypeList, + Computed: true, + Description: "List of target or host name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "ok": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of OK.", + }, + "changed": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of changed.", + }, + "failed": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of failed.", + }, + "skipped": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of skipped.", + }, + "unreachable": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of unreachable.", + }, + }, + }, + }, + }, + }, + }, + "system_job": { + Type: schema.TypeList, + Computed: true, + Description: "System Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_count": { + Type: schema.TypeFloat, + Computed: true, + Description: "number of targets or hosts.", + }, + "success": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of passed.", + }, + "failed": { + Type: schema.TypeFloat, + Computed: true, + Description: "Number of failed.", + }, + }, + }, + }, + }, + }, + }, + "log_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job log store URL.", + }, + "state_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job state store URL.", + }, + "results_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job results store URL.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + } +} + +func dataSourceIBMSchematicsJobRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + getJobOptions := &schematicsv1.GetJobOptions{} + + getJobOptions.SetJobID(d.Get("job_id").(string)) + + job, response, err := schematicsClient.GetJobWithContext(context, getJobOptions) + if err != nil { + log.Printf("[DEBUG] GetJobWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetJobWithContext failed %s\n%s", err, response)) + } + + d.SetId(*getJobOptions.JobID) + if err = d.Set("command_object", job.CommandObject); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_object: %s", err)) + } + if err = d.Set("command_object_id", job.CommandObjectID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_object_id: %s", err)) + } + if err = d.Set("command_name", job.CommandName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_name: %s", err)) + } + if err = d.Set("command_parameter", job.CommandParameter); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_parameter: %s", err)) + } + + if job.Inputs != nil { + err = d.Set("job_inputs", dataSourceJobFlattenInputs(job.Inputs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting job_inputs %s", err)) + } + } + + if job.Settings != nil { + err = d.Set("job_env_settings", dataSourceJobFlattenSettings(job.Settings)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting job_env_settings %s", err)) + } + } + if err = d.Set("id", job.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) + } + if err = d.Set("name", job.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", job.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", job.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("resource_group", job.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if err = d.Set("submitted_at", flex.DateTimeToString(job.SubmittedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting submitted_at: %s", err)) + } + if err = d.Set("submitted_by", job.SubmittedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting submitted_by: %s", err)) + } + if err = d.Set("start_at", flex.DateTimeToString(job.StartAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting start_at: %s", err)) + } + if err = d.Set("end_at", flex.DateTimeToString(job.EndAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting end_at: %s", err)) + } + if err = d.Set("duration", job.Duration); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting duration: %s", err)) + } + + if job.Status != nil { + err = d.Set("status", dataSourceJobFlattenStatus(*job.Status)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status %s", err)) + } + } + + if job.Data != nil { + err = d.Set("data", dataSourceJobFlattenData(*job.Data)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting data %s", err)) + } + } + + if job.Bastion != nil { + err = d.Set("bastion", dataSourceJobFlattenBastion(*job.Bastion)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion %s", err)) + } + } + + if job.LogSummary != nil { + err = d.Set("log_summary", dataSourceJobFlattenLogSummary(*job.LogSummary)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting log_summary %s", err)) + } + } + if err = d.Set("log_store_url", job.LogStoreURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting log_store_url: %s", err)) + } + if err = d.Set("state_store_url", job.StateStoreURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state_store_url: %s", err)) + } + if err = d.Set("results_url", job.ResultsURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting results_url: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(job.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func dataSourceJobFlattenInputs(result []schematicsv1.VariableData) (jobInputs []map[string]interface{}) { + for _, jobInputsItem := range result { + jobInputs = append(jobInputs, dataSourceJobInputsToMap(jobInputsItem)) + } + + return jobInputs +} + +func dataSourceJobInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceJobInputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceJobFlattenSettings(result []schematicsv1.VariableData) (jobEnvSettings []map[string]interface{}) { + for _, jobEnvSettingsItem := range result { + jobEnvSettings = append(jobEnvSettings, dataSourceJobSettingsToMap(jobEnvSettingsItem)) + } + + return jobEnvSettings +} + +func dataSourceJobSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceJobSettingsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceJobFlattenStatus(result schematicsv1.JobStatus) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceJobStatusToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceJobStatusToMap(statusItem schematicsv1.JobStatus) (statusMap map[string]interface{}) { + statusMap = map[string]interface{}{} + + if statusItem.WorkspaceJobStatus != nil { + workspaceJobStatusList := []map[string]interface{}{} + workspaceJobStatusMap := dataSourceJobStatusWorkspaceJobStatusToMap(*statusItem.WorkspaceJobStatus) + workspaceJobStatusList = append(workspaceJobStatusList, workspaceJobStatusMap) + statusMap["workspace_job_status"] = workspaceJobStatusList + } + if statusItem.ActionJobStatus != nil { + actionJobStatusList := []map[string]interface{}{} + actionJobStatusMap := dataSourceJobStatusActionJobStatusToMap(*statusItem.ActionJobStatus) + actionJobStatusList = append(actionJobStatusList, actionJobStatusMap) + statusMap["action_job_status"] = actionJobStatusList + } + if statusItem.SystemJobStatus != nil { + systemJobStatusList := []map[string]interface{}{} + systemJobStatusMap := dataSourceJobStatusSystemJobStatusToMap(*statusItem.SystemJobStatus) + systemJobStatusList = append(systemJobStatusList, systemJobStatusMap) + statusMap["system_job_status"] = systemJobStatusList + } + if statusItem.FlowJobStatus != nil { + flowJobStatusList := []map[string]interface{}{} + flowJobStatusMap := dataSourceJobStatusFlowJobStatusToMap(*statusItem.FlowJobStatus) + flowJobStatusList = append(flowJobStatusList, flowJobStatusMap) + statusMap["flow_job_status"] = flowJobStatusList + } + + return statusMap +} + +func dataSourceJobStatusWorkspaceJobStatusToMap(workspaceJobStatusItem schematicsv1.JobStatusWorkspace) (workspaceJobStatusMap map[string]interface{}) { + workspaceJobStatusMap = map[string]interface{}{} + + if workspaceJobStatusItem.WorkspaceName != nil { + workspaceJobStatusMap["workspace_name"] = workspaceJobStatusItem.WorkspaceName + } + if workspaceJobStatusItem.StatusCode != nil { + workspaceJobStatusMap["status_code"] = workspaceJobStatusItem.StatusCode + } + if workspaceJobStatusItem.StatusMessage != nil { + workspaceJobStatusMap["status_message"] = workspaceJobStatusItem.StatusMessage + } + if workspaceJobStatusItem.FlowStatus != nil { + flowStatusList := []map[string]interface{}{} + flowStatusMap := dataSourceJobWorkspaceJobStatusFlowStatusToMap(*workspaceJobStatusItem.FlowStatus) + flowStatusList = append(flowStatusList, flowStatusMap) + workspaceJobStatusMap["flow_status"] = flowStatusList + } + if workspaceJobStatusItem.TemplateStatus != nil { + templateStatusList := []map[string]interface{}{} + for _, templateStatusItem := range workspaceJobStatusItem.TemplateStatus { + templateStatusList = append(templateStatusList, dataSourceJobWorkspaceJobStatusTemplateStatusToMap(templateStatusItem)) + } + workspaceJobStatusMap["template_status"] = templateStatusList + } + if workspaceJobStatusItem.UpdatedAt != nil { + workspaceJobStatusMap["updated_at"] = workspaceJobStatusItem.UpdatedAt.String() + } + + return workspaceJobStatusMap +} + +func dataSourceJobWorkspaceJobStatusFlowStatusToMap(flowStatusItem schematicsv1.JobStatusFlow) (flowStatusMap map[string]interface{}) { + flowStatusMap = map[string]interface{}{} + + if flowStatusItem.FlowID != nil { + flowStatusMap["flow_id"] = flowStatusItem.FlowID + } + if flowStatusItem.FlowName != nil { + flowStatusMap["flow_name"] = flowStatusItem.FlowName + } + if flowStatusItem.StatusCode != nil { + flowStatusMap["status_code"] = flowStatusItem.StatusCode + } + if flowStatusItem.StatusMessage != nil { + flowStatusMap["status_message"] = flowStatusItem.StatusMessage + } + if flowStatusItem.Workitems != nil { + workitemsList := []map[string]interface{}{} + for _, workitemsItem := range flowStatusItem.Workitems { + workitemsList = append(workitemsList, dataSourceJobFlowStatusWorkitemsToMap(workitemsItem)) + } + flowStatusMap["workitems"] = workitemsList + } + if flowStatusItem.UpdatedAt != nil { + flowStatusMap["updated_at"] = flowStatusItem.UpdatedAt.String() + } + + return flowStatusMap +} + +func dataSourceJobFlowStatusWorkitemsToMap(workitemsItem schematicsv1.JobStatusWorkitem) (workitemsMap map[string]interface{}) { + workitemsMap = map[string]interface{}{} + + if workitemsItem.WorkspaceID != nil { + workitemsMap["workspace_id"] = workitemsItem.WorkspaceID + } + if workitemsItem.WorkspaceName != nil { + workitemsMap["workspace_name"] = workitemsItem.WorkspaceName + } + if workitemsItem.JobID != nil { + workitemsMap["job_id"] = workitemsItem.JobID + } + if workitemsItem.StatusCode != nil { + workitemsMap["status_code"] = workitemsItem.StatusCode + } + if workitemsItem.StatusMessage != nil { + workitemsMap["status_message"] = workitemsItem.StatusMessage + } + if workitemsItem.UpdatedAt != nil { + workitemsMap["updated_at"] = workitemsItem.UpdatedAt.String() + } + + return workitemsMap +} + +func dataSourceJobWorkspaceJobStatusTemplateStatusToMap(templateStatusItem schematicsv1.JobStatusTemplate) (templateStatusMap map[string]interface{}) { + templateStatusMap = map[string]interface{}{} + + if templateStatusItem.TemplateID != nil { + templateStatusMap["template_id"] = templateStatusItem.TemplateID + } + if templateStatusItem.TemplateName != nil { + templateStatusMap["template_name"] = templateStatusItem.TemplateName + } + if templateStatusItem.FlowIndex != nil { + templateStatusMap["flow_index"] = templateStatusItem.FlowIndex + } + if templateStatusItem.StatusCode != nil { + templateStatusMap["status_code"] = templateStatusItem.StatusCode + } + if templateStatusItem.StatusMessage != nil { + templateStatusMap["status_message"] = templateStatusItem.StatusMessage + } + if templateStatusItem.UpdatedAt != nil { + templateStatusMap["updated_at"] = templateStatusItem.UpdatedAt.String() + } + + return templateStatusMap +} + +func dataSourceJobStatusActionJobStatusToMap(actionJobStatusItem schematicsv1.JobStatusAction) (actionJobStatusMap map[string]interface{}) { + actionJobStatusMap = map[string]interface{}{} + + if actionJobStatusItem.ActionName != nil { + actionJobStatusMap["action_name"] = actionJobStatusItem.ActionName + } + if actionJobStatusItem.StatusCode != nil { + actionJobStatusMap["status_code"] = actionJobStatusItem.StatusCode + } + if actionJobStatusItem.StatusMessage != nil { + actionJobStatusMap["status_message"] = actionJobStatusItem.StatusMessage + } + if actionJobStatusItem.BastionStatusCode != nil { + actionJobStatusMap["bastion_status_code"] = actionJobStatusItem.BastionStatusCode + } + if actionJobStatusItem.BastionStatusMessage != nil { + actionJobStatusMap["bastion_status_message"] = actionJobStatusItem.BastionStatusMessage + } + if actionJobStatusItem.TargetsStatusCode != nil { + actionJobStatusMap["targets_status_code"] = actionJobStatusItem.TargetsStatusCode + } + if actionJobStatusItem.TargetsStatusMessage != nil { + actionJobStatusMap["targets_status_message"] = actionJobStatusItem.TargetsStatusMessage + } + if actionJobStatusItem.UpdatedAt != nil { + actionJobStatusMap["updated_at"] = actionJobStatusItem.UpdatedAt.String() + } + + return actionJobStatusMap +} + +func dataSourceJobStatusSystemJobStatusToMap(systemJobStatusItem schematicsv1.JobStatusSystem) (systemJobStatusMap map[string]interface{}) { + systemJobStatusMap = map[string]interface{}{} + + if systemJobStatusItem.SystemStatusMessage != nil { + systemJobStatusMap["system_status_message"] = systemJobStatusItem.SystemStatusMessage + } + if systemJobStatusItem.SystemStatusCode != nil { + systemJobStatusMap["system_status_code"] = systemJobStatusItem.SystemStatusCode + } + if systemJobStatusItem.SchematicsResourceStatus != nil { + schematicsResourceStatusList := []map[string]interface{}{} + for _, schematicsResourceStatusItem := range systemJobStatusItem.SchematicsResourceStatus { + schematicsResourceStatusList = append(schematicsResourceStatusList, dataSourceJobSystemJobStatusSchematicsResourceStatusToMap(schematicsResourceStatusItem)) + } + systemJobStatusMap["schematics_resource_status"] = schematicsResourceStatusList + } + if systemJobStatusItem.UpdatedAt != nil { + systemJobStatusMap["updated_at"] = systemJobStatusItem.UpdatedAt.String() + } + + return systemJobStatusMap +} + +func dataSourceJobSystemJobStatusSchematicsResourceStatusToMap(schematicsResourceStatusItem schematicsv1.JobStatusSchematicsResources) (schematicsResourceStatusMap map[string]interface{}) { + schematicsResourceStatusMap = map[string]interface{}{} + + if schematicsResourceStatusItem.StatusCode != nil { + schematicsResourceStatusMap["status_code"] = schematicsResourceStatusItem.StatusCode + } + if schematicsResourceStatusItem.StatusMessage != nil { + schematicsResourceStatusMap["status_message"] = schematicsResourceStatusItem.StatusMessage + } + if schematicsResourceStatusItem.SchematicsResourceID != nil { + schematicsResourceStatusMap["schematics_resource_id"] = schematicsResourceStatusItem.SchematicsResourceID + } + if schematicsResourceStatusItem.UpdatedAt != nil { + schematicsResourceStatusMap["updated_at"] = schematicsResourceStatusItem.UpdatedAt.String() + } + + return schematicsResourceStatusMap +} + +func dataSourceJobStatusFlowJobStatusToMap(flowJobStatusItem schematicsv1.JobStatusFlow) (flowJobStatusMap map[string]interface{}) { + flowJobStatusMap = map[string]interface{}{} + + if flowJobStatusItem.FlowID != nil { + flowJobStatusMap["flow_id"] = flowJobStatusItem.FlowID + } + if flowJobStatusItem.FlowName != nil { + flowJobStatusMap["flow_name"] = flowJobStatusItem.FlowName + } + if flowJobStatusItem.StatusCode != nil { + flowJobStatusMap["status_code"] = flowJobStatusItem.StatusCode + } + if flowJobStatusItem.StatusMessage != nil { + flowJobStatusMap["status_message"] = flowJobStatusItem.StatusMessage + } + if flowJobStatusItem.Workitems != nil { + workitemsList := []map[string]interface{}{} + for _, workitemsItem := range flowJobStatusItem.Workitems { + workitemsList = append(workitemsList, dataSourceJobFlowJobStatusWorkitemsToMap(workitemsItem)) + } + flowJobStatusMap["workitems"] = workitemsList + } + if flowJobStatusItem.UpdatedAt != nil { + flowJobStatusMap["updated_at"] = flowJobStatusItem.UpdatedAt.String() + } + + return flowJobStatusMap +} + +func dataSourceJobFlowJobStatusWorkitemsToMap(workitemsItem schematicsv1.JobStatusWorkitem) (workitemsMap map[string]interface{}) { + workitemsMap = map[string]interface{}{} + + if workitemsItem.WorkspaceID != nil { + workitemsMap["workspace_id"] = workitemsItem.WorkspaceID + } + if workitemsItem.WorkspaceName != nil { + workitemsMap["workspace_name"] = workitemsItem.WorkspaceName + } + if workitemsItem.JobID != nil { + workitemsMap["job_id"] = workitemsItem.JobID + } + if workitemsItem.StatusCode != nil { + workitemsMap["status_code"] = workitemsItem.StatusCode + } + if workitemsItem.StatusMessage != nil { + workitemsMap["status_message"] = workitemsItem.StatusMessage + } + if workitemsItem.UpdatedAt != nil { + workitemsMap["updated_at"] = workitemsItem.UpdatedAt.String() + } + + return workitemsMap +} + +func dataSourceJobFlattenData(result schematicsv1.JobData) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceJobDataToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceJobDataToMap(dataItem schematicsv1.JobData) (dataMap map[string]interface{}) { + dataMap = map[string]interface{}{} + + if dataItem.JobType != nil { + dataMap["job_type"] = dataItem.JobType + } + if dataItem.WorkspaceJobData != nil { + workspaceJobDataList := []map[string]interface{}{} + workspaceJobDataMap := dataSourceJobDataWorkspaceJobDataToMap(*dataItem.WorkspaceJobData) + workspaceJobDataList = append(workspaceJobDataList, workspaceJobDataMap) + dataMap["workspace_job_data"] = workspaceJobDataList + } + if dataItem.ActionJobData != nil { + actionJobDataList := []map[string]interface{}{} + actionJobDataMap := dataSourceJobDataActionJobDataToMap(*dataItem.ActionJobData) + actionJobDataList = append(actionJobDataList, actionJobDataMap) + dataMap["action_job_data"] = actionJobDataList + } + if dataItem.SystemJobData != nil { + systemJobDataList := []map[string]interface{}{} + systemJobDataMap := dataSourceJobDataSystemJobDataToMap(*dataItem.SystemJobData) + systemJobDataList = append(systemJobDataList, systemJobDataMap) + dataMap["system_job_data"] = systemJobDataList + } + if dataItem.FlowJobData != nil { + flowJobDataList := []map[string]interface{}{} + flowJobDataMap := dataSourceJobDataFlowJobDataToMap(*dataItem.FlowJobData) + flowJobDataList = append(flowJobDataList, flowJobDataMap) + dataMap["flow_job_data"] = flowJobDataList + } + + return dataMap +} + +func dataSourceJobDataWorkspaceJobDataToMap(workspaceJobDataItem schematicsv1.JobDataWorkspace) (workspaceJobDataMap map[string]interface{}) { + workspaceJobDataMap = map[string]interface{}{} + + if workspaceJobDataItem.WorkspaceName != nil { + workspaceJobDataMap["workspace_name"] = workspaceJobDataItem.WorkspaceName + } + if workspaceJobDataItem.FlowID != nil { + workspaceJobDataMap["flow_id"] = workspaceJobDataItem.FlowID + } + if workspaceJobDataItem.FlowName != nil { + workspaceJobDataMap["flow_name"] = workspaceJobDataItem.FlowName + } + if workspaceJobDataItem.Inputs != nil { + inputsList := []map[string]interface{}{} + for _, inputsItem := range workspaceJobDataItem.Inputs { + inputsList = append(inputsList, dataSourceJobWorkspaceJobDataInputsToMap(inputsItem)) + } + workspaceJobDataMap["inputs"] = inputsList + } + if workspaceJobDataItem.Outputs != nil { + outputsList := []map[string]interface{}{} + for _, outputsItem := range workspaceJobDataItem.Outputs { + outputsList = append(outputsList, dataSourceJobWorkspaceJobDataOutputsToMap(outputsItem)) + } + workspaceJobDataMap["outputs"] = outputsList + } + if workspaceJobDataItem.Settings != nil { + settingsList := []map[string]interface{}{} + for _, settingsItem := range workspaceJobDataItem.Settings { + settingsList = append(settingsList, dataSourceJobWorkspaceJobDataSettingsToMap(settingsItem)) + } + workspaceJobDataMap["settings"] = settingsList + } + if workspaceJobDataItem.TemplateData != nil { + templateDataList := []map[string]interface{}{} + for _, templateDataItem := range workspaceJobDataItem.TemplateData { + templateDataList = append(templateDataList, dataSourceJobWorkspaceJobDataTemplateDataToMap(templateDataItem)) + } + workspaceJobDataMap["template_data"] = templateDataList + } + if workspaceJobDataItem.UpdatedAt != nil { + workspaceJobDataMap["updated_at"] = workspaceJobDataItem.UpdatedAt.String() + } + + return workspaceJobDataMap +} + +func dataSourceJobWorkspaceJobDataInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceJobWorkspaceJobDataOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { + outputsMap = map[string]interface{}{} + + if outputsItem.Name != nil { + outputsMap["name"] = outputsItem.Name + } + if outputsItem.Value != nil { + outputsMap["value"] = outputsItem.Value + } + if outputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobOutputsMetadataToMap(*outputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + outputsMap["metadata"] = metadataList + } + if outputsItem.Link != nil { + outputsMap["link"] = outputsItem.Link + } + + return outputsMap +} + +func dataSourceJobOutputsMetadataToMap(metadataItem schematicsv1.VariableMetadata) (metadataMap map[string]interface{}) { + metadataMap = map[string]interface{}{} + + if metadataItem.Type != nil { + metadataMap["type"] = metadataItem.Type + } + if metadataItem.Aliases != nil { + metadataMap["aliases"] = metadataItem.Aliases + } + if metadataItem.Description != nil { + metadataMap["description"] = metadataItem.Description + } + if metadataItem.DefaultValue != nil { + metadataMap["default_value"] = metadataItem.DefaultValue + } + if metadataItem.Secure != nil { + metadataMap["secure"] = metadataItem.Secure + } + if metadataItem.Immutable != nil { + metadataMap["immutable"] = metadataItem.Immutable + } + if metadataItem.Hidden != nil { + metadataMap["hidden"] = metadataItem.Hidden + } + if metadataItem.Options != nil { + metadataMap["options"] = metadataItem.Options + } + if metadataItem.MinValue != nil { + metadataMap["min_value"] = metadataItem.MinValue + } + if metadataItem.MaxValue != nil { + metadataMap["max_value"] = metadataItem.MaxValue + } + if metadataItem.MinLength != nil { + metadataMap["min_length"] = metadataItem.MinLength + } + if metadataItem.MaxLength != nil { + metadataMap["max_length"] = metadataItem.MaxLength + } + if metadataItem.Matches != nil { + metadataMap["matches"] = metadataItem.Matches + } + if metadataItem.Position != nil { + metadataMap["position"] = metadataItem.Position + } + if metadataItem.GroupBy != nil { + metadataMap["group_by"] = metadataItem.GroupBy + } + if metadataItem.Source != nil { + metadataMap["source"] = metadataItem.Source + } + + return metadataMap +} + +func dataSourceJobWorkspaceJobDataSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceJobWorkspaceJobDataTemplateDataToMap(templateDataItem schematicsv1.JobDataTemplate) (templateDataMap map[string]interface{}) { + templateDataMap = map[string]interface{}{} + + if templateDataItem.TemplateID != nil { + templateDataMap["template_id"] = templateDataItem.TemplateID + } + if templateDataItem.TemplateName != nil { + templateDataMap["template_name"] = templateDataItem.TemplateName + } + if templateDataItem.FlowIndex != nil { + templateDataMap["flow_index"] = templateDataItem.FlowIndex + } + if templateDataItem.Inputs != nil { + inputsList := []map[string]interface{}{} + for _, inputsItem := range templateDataItem.Inputs { + inputsList = append(inputsList, dataSourceJobTemplateDataInputsToMap(inputsItem)) + } + templateDataMap["inputs"] = inputsList + } + if templateDataItem.Outputs != nil { + outputsList := []map[string]interface{}{} + for _, outputsItem := range templateDataItem.Outputs { + outputsList = append(outputsList, dataSourceJobTemplateDataOutputsToMap(outputsItem)) + } + templateDataMap["outputs"] = outputsList + } + if templateDataItem.Settings != nil { + settingsList := []map[string]interface{}{} + for _, settingsItem := range templateDataItem.Settings { + settingsList = append(settingsList, dataSourceJobTemplateDataSettingsToMap(settingsItem)) + } + templateDataMap["settings"] = settingsList + } + if templateDataItem.UpdatedAt != nil { + templateDataMap["updated_at"] = templateDataItem.UpdatedAt.String() + } + + return templateDataMap +} + +func dataSourceJobTemplateDataInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceJobTemplateDataOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { + outputsMap = map[string]interface{}{} + + if outputsItem.Name != nil { + outputsMap["name"] = outputsItem.Name + } + if outputsItem.Value != nil { + outputsMap["value"] = outputsItem.Value + } + if outputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobOutputsMetadataToMap(*outputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + outputsMap["metadata"] = metadataList + } + if outputsItem.Link != nil { + outputsMap["link"] = outputsItem.Link + } + + return outputsMap +} + +func dataSourceJobTemplateDataSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceJobDataActionJobDataToMap(actionJobDataItem schematicsv1.JobDataAction) (actionJobDataMap map[string]interface{}) { + actionJobDataMap = map[string]interface{}{} + + if actionJobDataItem.ActionName != nil { + actionJobDataMap["action_name"] = actionJobDataItem.ActionName + } + if actionJobDataItem.Inputs != nil { + inputsList := []map[string]interface{}{} + for _, inputsItem := range actionJobDataItem.Inputs { + inputsList = append(inputsList, dataSourceJobActionJobDataInputsToMap(inputsItem)) + } + actionJobDataMap["inputs"] = inputsList + } + if actionJobDataItem.Outputs != nil { + outputsList := []map[string]interface{}{} + for _, outputsItem := range actionJobDataItem.Outputs { + outputsList = append(outputsList, dataSourceJobActionJobDataOutputsToMap(outputsItem)) + } + actionJobDataMap["outputs"] = outputsList + } + if actionJobDataItem.Settings != nil { + settingsList := []map[string]interface{}{} + for _, settingsItem := range actionJobDataItem.Settings { + settingsList = append(settingsList, dataSourceJobActionJobDataSettingsToMap(settingsItem)) + } + actionJobDataMap["settings"] = settingsList + } + if actionJobDataItem.UpdatedAt != nil { + actionJobDataMap["updated_at"] = actionJobDataItem.UpdatedAt.String() + } + if actionJobDataItem.InventoryRecord != nil { + inventoryRecordList := []map[string]interface{}{} + inventoryRecordMap := dataSourceJobActionJobDataInventoryRecordToMap(*actionJobDataItem.InventoryRecord) + inventoryRecordList = append(inventoryRecordList, inventoryRecordMap) + actionJobDataMap["inventory_record"] = inventoryRecordList + } + if actionJobDataItem.MaterializedInventory != nil { + actionJobDataMap["materialized_inventory"] = actionJobDataItem.MaterializedInventory + } + + return actionJobDataMap +} + +func dataSourceJobActionJobDataInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceJobActionJobDataOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { + outputsMap = map[string]interface{}{} + + if outputsItem.Name != nil { + outputsMap["name"] = outputsItem.Name + } + if outputsItem.Value != nil { + outputsMap["value"] = outputsItem.Value + } + if outputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobOutputsMetadataToMap(*outputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + outputsMap["metadata"] = metadataList + } + if outputsItem.Link != nil { + outputsMap["link"] = outputsItem.Link + } + + return outputsMap +} + +func dataSourceJobActionJobDataSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceJobActionJobDataInventoryRecordToMap(inventoryRecordItem schematicsv1.InventoryResourceRecord) (inventoryRecordMap map[string]interface{}) { + inventoryRecordMap = map[string]interface{}{} + + if inventoryRecordItem.Name != nil { + inventoryRecordMap["name"] = inventoryRecordItem.Name + } + if inventoryRecordItem.ID != nil { + inventoryRecordMap["id"] = inventoryRecordItem.ID + } + if inventoryRecordItem.Description != nil { + inventoryRecordMap["description"] = inventoryRecordItem.Description + } + if inventoryRecordItem.Location != nil { + inventoryRecordMap["location"] = inventoryRecordItem.Location + } + if inventoryRecordItem.ResourceGroup != nil { + inventoryRecordMap["resource_group"] = inventoryRecordItem.ResourceGroup + } + if inventoryRecordItem.CreatedAt != nil { + inventoryRecordMap["created_at"] = inventoryRecordItem.CreatedAt.String() + } + if inventoryRecordItem.CreatedBy != nil { + inventoryRecordMap["created_by"] = inventoryRecordItem.CreatedBy + } + if inventoryRecordItem.UpdatedAt != nil { + inventoryRecordMap["updated_at"] = inventoryRecordItem.UpdatedAt.String() + } + if inventoryRecordItem.UpdatedBy != nil { + inventoryRecordMap["updated_by"] = inventoryRecordItem.UpdatedBy + } + if inventoryRecordItem.InventoriesIni != nil { + inventoryRecordMap["inventories_ini"] = inventoryRecordItem.InventoriesIni + } + if inventoryRecordItem.ResourceQueries != nil { + inventoryRecordMap["resource_queries"] = inventoryRecordItem.ResourceQueries + } + + return inventoryRecordMap +} + +func dataSourceJobDataSystemJobDataToMap(systemJobDataItem schematicsv1.JobDataSystem) (systemJobDataMap map[string]interface{}) { + systemJobDataMap = map[string]interface{}{} + + if systemJobDataItem.KeyID != nil { + systemJobDataMap["key_id"] = systemJobDataItem.KeyID + } + if systemJobDataItem.SchematicsResourceID != nil { + systemJobDataMap["schematics_resource_id"] = systemJobDataItem.SchematicsResourceID + } + if systemJobDataItem.UpdatedAt != nil { + systemJobDataMap["updated_at"] = systemJobDataItem.UpdatedAt.String() + } + + return systemJobDataMap +} + +func dataSourceJobDataFlowJobDataToMap(flowJobDataItem schematicsv1.JobDataFlow) (flowJobDataMap map[string]interface{}) { + flowJobDataMap = map[string]interface{}{} + + if flowJobDataItem.FlowID != nil { + flowJobDataMap["flow_id"] = flowJobDataItem.FlowID + } + if flowJobDataItem.FlowName != nil { + flowJobDataMap["flow_name"] = flowJobDataItem.FlowName + } + if flowJobDataItem.Workitems != nil { + workitemsList := []map[string]interface{}{} + for _, workitemsItem := range flowJobDataItem.Workitems { + workitemsList = append(workitemsList, dataSourceJobFlowJobDataWorkitemsToMap(workitemsItem)) + } + flowJobDataMap["workitems"] = workitemsList + } + if flowJobDataItem.UpdatedAt != nil { + flowJobDataMap["updated_at"] = flowJobDataItem.UpdatedAt.String() + } + + return flowJobDataMap +} + +func dataSourceJobFlowJobDataWorkitemsToMap(workitemsItem schematicsv1.JobDataWorkItem) (workitemsMap map[string]interface{}) { + workitemsMap = map[string]interface{}{} + + if workitemsItem.CommandObjectID != nil { + workitemsMap["command_object_id"] = workitemsItem.CommandObjectID + } + if workitemsItem.CommandObjectName != nil { + workitemsMap["command_object_name"] = workitemsItem.CommandObjectName + } + if workitemsItem.Layers != nil { + workitemsMap["layers"] = workitemsItem.Layers + } + if workitemsItem.SourceType != nil { + workitemsMap["source_type"] = workitemsItem.SourceType + } + if workitemsItem.Source != nil { + sourceList := []map[string]interface{}{} + sourceMap := dataSourceJobWorkitemsSourceToMap(*workitemsItem.Source) + sourceList = append(sourceList, sourceMap) + workitemsMap["source"] = sourceList + } + if workitemsItem.Inputs != nil { + inputsList := []map[string]interface{}{} + for _, inputsItem := range workitemsItem.Inputs { + inputsList = append(inputsList, dataSourceJobWorkitemsInputsToMap(inputsItem)) + } + workitemsMap["inputs"] = inputsList + } + if workitemsItem.Outputs != nil { + outputsList := []map[string]interface{}{} + for _, outputsItem := range workitemsItem.Outputs { + outputsList = append(outputsList, dataSourceJobWorkitemsOutputsToMap(outputsItem)) + } + workitemsMap["outputs"] = outputsList + } + if workitemsItem.Settings != nil { + settingsList := []map[string]interface{}{} + for _, settingsItem := range workitemsItem.Settings { + settingsList = append(settingsList, dataSourceJobWorkitemsSettingsToMap(settingsItem)) + } + workitemsMap["settings"] = settingsList + } + if workitemsItem.LastJob != nil { + lastJobList := []map[string]interface{}{} + lastJobMap := dataSourceJobWorkitemsLastJobToMap(*workitemsItem.LastJob) + lastJobList = append(lastJobList, lastJobMap) + workitemsMap["last_job"] = lastJobList + } + if workitemsItem.UpdatedAt != nil { + workitemsMap["updated_at"] = workitemsItem.UpdatedAt.String() + } + + return workitemsMap +} + +func dataSourceJobWorkitemsSourceToMap(sourceItem schematicsv1.ExternalSource) (sourceMap map[string]interface{}) { + sourceMap = map[string]interface{}{} + + if sourceItem.SourceType != nil { + sourceMap["source_type"] = sourceItem.SourceType + } + if sourceItem.Git != nil { + gitList := []map[string]interface{}{} + gitMap := dataSourceJobSourceGitToMap(*sourceItem.Git) + gitList = append(gitList, gitMap) + sourceMap["git"] = gitList + } + if sourceItem.Catalog != nil { + catalogList := []map[string]interface{}{} + catalogMap := dataSourceJobSourceCatalogToMap(*sourceItem.Catalog) + catalogList = append(catalogList, catalogMap) + sourceMap["catalog"] = catalogList + } + // if sourceItem.CosBucket != nil { + // cosBucketList := []map[string]interface{}{} + // cosBucketMap := dataSourceJobSourceCosBucketToMap(*sourceItem.CosBucket) + // cosBucketList = append(cosBucketList, cosBucketMap) + // sourceMap["cos_bucket"] = cosBucketList + // } + + return sourceMap +} + +func dataSourceJobSourceGitToMap(gitItem schematicsv1.GitSource) (gitMap map[string]interface{}) { + gitMap = map[string]interface{}{} + + if gitItem.ComputedGitRepoURL != nil { + gitMap["computed_git_repo_url"] = gitItem.ComputedGitRepoURL + } + if gitItem.GitRepoURL != nil { + gitMap["git_repo_url"] = gitItem.GitRepoURL + } + if gitItem.GitToken != nil { + gitMap["git_token"] = gitItem.GitToken + } + if gitItem.GitRepoFolder != nil { + gitMap["git_repo_folder"] = gitItem.GitRepoFolder + } + if gitItem.GitRelease != nil { + gitMap["git_release"] = gitItem.GitRelease + } + if gitItem.GitBranch != nil { + gitMap["git_branch"] = gitItem.GitBranch + } + + return gitMap +} + +func dataSourceJobSourceCatalogToMap(catalogItem schematicsv1.CatalogSource) (catalogMap map[string]interface{}) { + catalogMap = map[string]interface{}{} + + if catalogItem.CatalogName != nil { + catalogMap["catalog_name"] = catalogItem.CatalogName + } + if catalogItem.OfferingName != nil { + catalogMap["offering_name"] = catalogItem.OfferingName + } + if catalogItem.OfferingVersion != nil { + catalogMap["offering_version"] = catalogItem.OfferingVersion + } + if catalogItem.OfferingKind != nil { + catalogMap["offering_kind"] = catalogItem.OfferingKind + } + if catalogItem.OfferingID != nil { + catalogMap["offering_id"] = catalogItem.OfferingID + } + if catalogItem.OfferingVersionID != nil { + catalogMap["offering_version_id"] = catalogItem.OfferingVersionID + } + if catalogItem.OfferingRepoURL != nil { + catalogMap["offering_repo_url"] = catalogItem.OfferingRepoURL + } + + return catalogMap +} + +// func dataSourceJobSourceCosBucketToMap(cosBucketItem schematicsv1.ExternalSourceCosBucket) (cosBucketMap map[string]interface{}) { +// cosBucketMap = map[string]interface{}{} + +// if cosBucketItem.CosBucketURL != nil { +// cosBucketMap["cos_bucket_url"] = cosBucketItem.CosBucketURL +// } + +// return cosBucketMap +// } + +func dataSourceJobWorkitemsInputsToMap(inputsItem schematicsv1.VariableData) (inputsMap map[string]interface{}) { + inputsMap = map[string]interface{}{} + + if inputsItem.Name != nil { + inputsMap["name"] = inputsItem.Name + } + if inputsItem.Value != nil { + inputsMap["value"] = inputsItem.Value + } + if inputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobInputsMetadataToMap(*inputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + inputsMap["metadata"] = metadataList + } + if inputsItem.Link != nil { + inputsMap["link"] = inputsItem.Link + } + + return inputsMap +} + +func dataSourceJobWorkitemsOutputsToMap(outputsItem schematicsv1.VariableData) (outputsMap map[string]interface{}) { + outputsMap = map[string]interface{}{} + + if outputsItem.Name != nil { + outputsMap["name"] = outputsItem.Name + } + if outputsItem.Value != nil { + outputsMap["value"] = outputsItem.Value + } + if outputsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobOutputsMetadataToMap(*outputsItem.Metadata) + metadataList = append(metadataList, metadataMap) + outputsMap["metadata"] = metadataList + } + if outputsItem.Link != nil { + outputsMap["link"] = outputsItem.Link + } + + return outputsMap +} + +func dataSourceJobWorkitemsSettingsToMap(settingsItem schematicsv1.VariableData) (settingsMap map[string]interface{}) { + settingsMap = map[string]interface{}{} + + if settingsItem.Name != nil { + settingsMap["name"] = settingsItem.Name + } + if settingsItem.Value != nil { + settingsMap["value"] = settingsItem.Value + } + if settingsItem.Metadata != nil { + metadataList := []map[string]interface{}{} + metadataMap := dataSourceJobSettingsMetadataToMap(*settingsItem.Metadata) + metadataList = append(metadataList, metadataMap) + settingsMap["metadata"] = metadataList + } + if settingsItem.Link != nil { + settingsMap["link"] = settingsItem.Link + } + + return settingsMap +} + +func dataSourceJobWorkitemsLastJobToMap(lastJobItem schematicsv1.JobDataWorkItemLastJob) (lastJobMap map[string]interface{}) { + lastJobMap = map[string]interface{}{} + + if lastJobItem.CommandObject != nil { + lastJobMap["command_object"] = lastJobItem.CommandObject + } + if lastJobItem.CommandObjectName != nil { + lastJobMap["command_object_name"] = lastJobItem.CommandObjectName + } + if lastJobItem.CommandObjectID != nil { + lastJobMap["command_object_id"] = lastJobItem.CommandObjectID + } + if lastJobItem.CommandName != nil { + lastJobMap["command_name"] = lastJobItem.CommandName + } + if lastJobItem.JobID != nil { + lastJobMap["job_id"] = lastJobItem.JobID + } + if lastJobItem.JobStatus != nil { + lastJobMap["job_status"] = lastJobItem.JobStatus + } + + return lastJobMap +} + +func dataSourceJobFlattenBastion(result schematicsv1.BastionResourceDefinition) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceJobBastionToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceJobBastionToMap(bastionItem schematicsv1.BastionResourceDefinition) (bastionMap map[string]interface{}) { + bastionMap = map[string]interface{}{} + + if bastionItem.Name != nil { + bastionMap["name"] = bastionItem.Name + } + if bastionItem.Host != nil { + bastionMap["host"] = bastionItem.Host + } + + return bastionMap +} + +func dataSourceJobFlattenLogSummary(result schematicsv1.JobLogSummary) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceJobLogSummaryToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceJobLogSummaryToMap(logSummaryItem schematicsv1.JobLogSummary) (logSummaryMap map[string]interface{}) { + logSummaryMap = map[string]interface{}{} + + if logSummaryItem.JobID != nil { + logSummaryMap["job_id"] = logSummaryItem.JobID + } + if logSummaryItem.JobType != nil { + logSummaryMap["job_type"] = logSummaryItem.JobType + } + if logSummaryItem.LogStartAt != nil { + logSummaryMap["log_start_at"] = logSummaryItem.LogStartAt.String() + } + if logSummaryItem.LogAnalyzedTill != nil { + logSummaryMap["log_analyzed_till"] = logSummaryItem.LogAnalyzedTill.String() + } + if logSummaryItem.ElapsedTime != nil { + logSummaryMap["elapsed_time"] = logSummaryItem.ElapsedTime + } + if logSummaryItem.LogErrors != nil { + logErrorsList := []map[string]interface{}{} + for _, logErrorsItem := range logSummaryItem.LogErrors { + logErrorsList = append(logErrorsList, dataSourceJobLogSummaryLogErrorsToMap(logErrorsItem)) + } + logSummaryMap["log_errors"] = logErrorsList + } + if logSummaryItem.RepoDownloadJob != nil { + repoDownloadJobList := []map[string]interface{}{} + repoDownloadJobMap := dataSourceJobLogSummaryRepoDownloadJobToMap(*logSummaryItem.RepoDownloadJob) + repoDownloadJobList = append(repoDownloadJobList, repoDownloadJobMap) + logSummaryMap["repo_download_job"] = repoDownloadJobList + } + if logSummaryItem.WorkspaceJob != nil { + workspaceJobList := []map[string]interface{}{} + workspaceJobMap := dataSourceJobLogSummaryWorkspaceJobToMap(*logSummaryItem.WorkspaceJob) + workspaceJobList = append(workspaceJobList, workspaceJobMap) + logSummaryMap["workspace_job"] = workspaceJobList + } + if logSummaryItem.FlowJob != nil { + flowJobList := []map[string]interface{}{} + flowJobMap := dataSourceJobLogSummaryFlowJobToMap(*logSummaryItem.FlowJob) + flowJobList = append(flowJobList, flowJobMap) + logSummaryMap["flow_job"] = flowJobList + } + if logSummaryItem.ActionJob != nil { + actionJobList := []map[string]interface{}{} + actionJobMap := dataSourceJobLogSummaryActionJobToMap(*logSummaryItem.ActionJob) + actionJobList = append(actionJobList, actionJobMap) + logSummaryMap["action_job"] = actionJobList + } + if logSummaryItem.SystemJob != nil { + systemJobList := []map[string]interface{}{} + systemJobMap := dataSourceJobLogSummarySystemJobToMap(*logSummaryItem.SystemJob) + systemJobList = append(systemJobList, systemJobMap) + logSummaryMap["system_job"] = systemJobList + } + + return logSummaryMap +} + +func dataSourceJobLogSummaryLogErrorsToMap(logErrorsItem schematicsv1.JobLogSummaryLogErrors) (logErrorsMap map[string]interface{}) { + logErrorsMap = map[string]interface{}{} + + if logErrorsItem.ErrorCode != nil { + logErrorsMap["error_code"] = logErrorsItem.ErrorCode + } + if logErrorsItem.ErrorMsg != nil { + logErrorsMap["error_msg"] = logErrorsItem.ErrorMsg + } + if logErrorsItem.ErrorCount != nil { + logErrorsMap["error_count"] = logErrorsItem.ErrorCount + } + + return logErrorsMap +} + +func dataSourceJobLogSummaryRepoDownloadJobToMap(repoDownloadJobItem schematicsv1.JobLogSummaryRepoDownloadJob) (repoDownloadJobMap map[string]interface{}) { + repoDownloadJobMap = map[string]interface{}{} + + if repoDownloadJobItem.ScannedFileCount != nil { + repoDownloadJobMap["scanned_file_count"] = repoDownloadJobItem.ScannedFileCount + } + if repoDownloadJobItem.QuarantinedFileCount != nil { + repoDownloadJobMap["quarantined_file_count"] = repoDownloadJobItem.QuarantinedFileCount + } + if repoDownloadJobItem.DetectedFiletype != nil { + repoDownloadJobMap["detected_filetype"] = repoDownloadJobItem.DetectedFiletype + } + if repoDownloadJobItem.InputsCount != nil { + repoDownloadJobMap["inputs_count"] = repoDownloadJobItem.InputsCount + } + if repoDownloadJobItem.OutputsCount != nil { + repoDownloadJobMap["outputs_count"] = repoDownloadJobItem.OutputsCount + } + + return repoDownloadJobMap +} + +func dataSourceJobLogSummaryWorkspaceJobToMap(workspaceJobItem schematicsv1.JobLogSummaryWorkspaceJob) (workspaceJobMap map[string]interface{}) { + workspaceJobMap = map[string]interface{}{} + + if workspaceJobItem.ResourcesAdd != nil { + workspaceJobMap["resources_add"] = workspaceJobItem.ResourcesAdd + } + if workspaceJobItem.ResourcesModify != nil { + workspaceJobMap["resources_modify"] = workspaceJobItem.ResourcesModify + } + if workspaceJobItem.ResourcesDestroy != nil { + workspaceJobMap["resources_destroy"] = workspaceJobItem.ResourcesDestroy + } + + return workspaceJobMap +} + +func dataSourceJobLogSummaryFlowJobToMap(flowJobItem schematicsv1.JobLogSummaryFlowJob) (flowJobMap map[string]interface{}) { + flowJobMap = map[string]interface{}{} + + if flowJobItem.WorkitemsCompleted != nil { + flowJobMap["workitems_completed"] = flowJobItem.WorkitemsCompleted + } + if flowJobItem.WorkitemsPending != nil { + flowJobMap["workitems_pending"] = flowJobItem.WorkitemsPending + } + if flowJobItem.WorkitemsFailed != nil { + flowJobMap["workitems_failed"] = flowJobItem.WorkitemsFailed + } + if flowJobItem.Workitems != nil { + workitemsList := []map[string]interface{}{} + for _, workitemsItem := range flowJobItem.Workitems { + workitemsList = append(workitemsList, dataSourceJobFlowJobWorkitemsToMap(workitemsItem)) + } + flowJobMap["workitems"] = workitemsList + } + + return flowJobMap +} + +func dataSourceJobFlowJobWorkitemsToMap(workitemsItem schematicsv1.JobLogSummaryWorkitems) (workitemsMap map[string]interface{}) { + workitemsMap = map[string]interface{}{} + + if workitemsItem.WorkspaceID != nil { + workitemsMap["workspace_id"] = workitemsItem.WorkspaceID + } + if workitemsItem.JobID != nil { + workitemsMap["job_id"] = workitemsItem.JobID + } + if workitemsItem.ResourcesAdd != nil { + workitemsMap["resources_add"] = workitemsItem.ResourcesAdd + } + if workitemsItem.ResourcesModify != nil { + workitemsMap["resources_modify"] = workitemsItem.ResourcesModify + } + if workitemsItem.ResourcesDestroy != nil { + workitemsMap["resources_destroy"] = workitemsItem.ResourcesDestroy + } + if workitemsItem.LogURL != nil { + workitemsMap["log_url"] = workitemsItem.LogURL + } + + return workitemsMap +} + +func dataSourceJobLogSummaryActionJobToMap(actionJobItem schematicsv1.JobLogSummaryActionJob) (actionJobMap map[string]interface{}) { + actionJobMap = map[string]interface{}{} + + if actionJobItem.TargetCount != nil { + actionJobMap["target_count"] = actionJobItem.TargetCount + } + if actionJobItem.TaskCount != nil { + actionJobMap["task_count"] = actionJobItem.TaskCount + } + if actionJobItem.PlayCount != nil { + actionJobMap["play_count"] = actionJobItem.PlayCount + } + if actionJobItem.Recap != nil { + recapList := []map[string]interface{}{} + recapMap := dataSourceJobActionJobRecapToMap(*actionJobItem.Recap) + recapList = append(recapList, recapMap) + actionJobMap["recap"] = recapList + } + + return actionJobMap +} + +func dataSourceJobActionJobRecapToMap(recapItem schematicsv1.JobLogSummaryActionJobRecap) (recapMap map[string]interface{}) { + recapMap = map[string]interface{}{} + + if recapItem.Target != nil { + recapMap["target"] = recapItem.Target + } + if recapItem.Ok != nil { + recapMap["ok"] = recapItem.Ok + } + if recapItem.Changed != nil { + recapMap["changed"] = recapItem.Changed + } + if recapItem.Failed != nil { + recapMap["failed"] = recapItem.Failed + } + if recapItem.Skipped != nil { + recapMap["skipped"] = recapItem.Skipped + } + if recapItem.Unreachable != nil { + recapMap["unreachable"] = recapItem.Unreachable + } + + return recapMap +} + +func dataSourceJobLogSummarySystemJobToMap(systemJobItem schematicsv1.JobLogSummarySystemJob) (systemJobMap map[string]interface{}) { + systemJobMap = map[string]interface{}{} + + if systemJobItem.TargetCount != nil { + systemJobMap["target_count"] = systemJobItem.TargetCount + } + if systemJobItem.Success != nil { + systemJobMap["success"] = systemJobItem.Success + } + if systemJobItem.Failed != nil { + systemJobMap["failed"] = systemJobItem.Failed + } + + return systemJobMap +} diff --git a/ibm/data_source_ibm_schematics_job_test.go b/ibm/service/schematics/data_source_ibm_schematics_job_test.go similarity index 88% rename from ibm/data_source_ibm_schematics_job_test.go rename to ibm/service/schematics/data_source_ibm_schematics_job_test.go index 7e1457067..c159433ea 100644 --- a/ibm/data_source_ibm_schematics_job_test.go +++ b/ibm/service/schematics/data_source_ibm_schematics_job_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,14 +18,14 @@ func TestAccIBMSchematicsJobDataSourceBasic(t *testing.T) { //jobCommandObjectID := fmt.Sprintf("command_object_id_%d", acctest.RandIntRange(10, 100)) jobCommandName := "ansible_playbook_run" jobCommandParameter := fmt.Sprintf("command_parameter_%d", acctest.RandIntRange(10, 100)) - jobLocation := "us-east" + jobLocation := "us" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSchematicsJobDataSourceConfig(jobCommandObject, actionID, jobCommandName, jobCommandParameter, jobLocation), + { + Config: testAccCheckIBMSchematicsJobDataSourceConfig(jobCommandObject, acc.ActionID, jobCommandName, jobCommandParameter, jobLocation), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "id"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "job_id"), @@ -31,7 +33,6 @@ func TestAccIBMSchematicsJobDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "command_object_id"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "command_name"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "name"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "description"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "location"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "resource_group"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "submitted_at"), @@ -39,7 +40,7 @@ func TestAccIBMSchematicsJobDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "start_at"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "end_at"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "status.#"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "job_log_summary.#"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "log_summary.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_job.schematics_job", "updated_at"), ), }, diff --git a/ibm/data_source_ibm_schematics_output.go b/ibm/service/schematics/data_source_ibm_schematics_output.go similarity index 75% rename from ibm/data_source_ibm_schematics_output.go rename to ibm/service/schematics/data_source_ibm_schematics_output.go index 9e3a8be43..e3b4949aa 100644 --- a/ibm/data_source_ibm_schematics_output.go +++ b/ibm/service/schematics/data_source_ibm_schematics_output.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics import ( "encoding/json" @@ -9,11 +9,13 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/schematics-go-sdk/schematicsv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSchematicsOutput() *schema.Resource { +func DataSourceIBMSchematicsOutput() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMSchematicsOutputRead, @@ -23,6 +25,11 @@ func dataSourceIBMSchematicsOutput() *schema.Resource { Required: true, Description: "The ID of the workspace for which you want to retrieve output values. To find the workspace ID, use the `GET /workspaces` API.", }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: "The Region of the workspace.", + }, "template_id": { Type: schema.TypeString, Required: true, @@ -37,7 +44,7 @@ func dataSourceIBMSchematicsOutput() *schema.Resource { Optional: true, Description: "The json output in string", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this Workspace", @@ -47,7 +54,7 @@ func dataSourceIBMSchematicsOutput() *schema.Resource { } func dataSourceIBMSchematicsOutputRead(d *schema.ResourceData, meta interface{}) error { - schematicsClient, err := meta.(ClientSession).SchematicsV1() + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() if err != nil { return err } @@ -55,6 +62,14 @@ func dataSourceIBMSchematicsOutputRead(d *schema.ResourceData, meta interface{}) workspaceID := d.Get("workspace_id").(string) templateID := d.Get("template_id").(string) + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + getWorkspaceOutputsOptions := &schematicsv1.GetWorkspaceOutputsOptions{} getWorkspaceOutputsOptions.SetWID(d.Get("workspace_id").(string)) @@ -88,18 +103,18 @@ func dataSourceIBMSchematicsOutputRead(d *schema.ResourceData, meta interface{}) } if !(found) { - return fmt.Errorf("Error while fetching template id in workspace: %s", workspaceID) + return fmt.Errorf("[ERROR] Error while fetching template id in workspace: %s", workspaceID) } d.Set("output_json", outputJSON) d.SetId(fmt.Sprintf("%s/%s", workspaceID, templateID)) - d.Set("output_values", Flatten(items)) + d.Set("output_values", flex.Flatten(items)) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/schematics") + d.Set(flex.ResourceControllerURL, controller+"/schematics") return nil } @@ -109,7 +124,7 @@ func dataSourceIBMSchematicsOutputID(d *schema.ResourceData) string { return time.Now().UTC().String() } -func dataSourceOutputValuesListFlattenOutputValues(result []schematicsv1.OutputValuesItem) (outputValues interface{}) { +func dataSourceOutputValuesListFlattenOutputValues(result []schematicsv1.OutputValuesInner) (outputValues interface{}) { for _, outputValuesItem := range result { outputValues = dataSourceOutputValuesListOutputValuesToMap(outputValuesItem) } @@ -117,7 +132,7 @@ func dataSourceOutputValuesListFlattenOutputValues(result []schematicsv1.OutputV return outputValues } -func dataSourceOutputValuesListOutputValuesToMap(outputValuesItem schematicsv1.OutputValuesItem) (outputValuesMap map[string]interface{}) { +func dataSourceOutputValuesListOutputValuesToMap(outputValuesItem schematicsv1.OutputValuesInner) (outputValuesMap map[string]interface{}) { outputValuesMap = map[string]interface{}{} if outputValuesItem.Folder != nil { @@ -127,10 +142,10 @@ func dataSourceOutputValuesListOutputValuesToMap(outputValuesItem schematicsv1.O outputValuesMap["id"] = outputValuesItem.ID } - m := []Map{} + m := []flex.Map{} for _, outputValues := range outputValuesItem.OutputValues { - m = append(m, Flatten(outputValues.(map[string]interface{}))) + m = append(m, flex.Flatten(outputValues.(map[string]interface{}))) } if outputValuesItem.OutputValues != nil { diff --git a/ibm/service/schematics/data_source_ibm_schematics_output_test.go b/ibm/service/schematics/data_source_ibm_schematics_output_test.go new file mode 100644 index 000000000..fb75b1c8f --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_output_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMSchematicsOutputDataSourceBasic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsOutputDataSourceConfigBasic(acc.WorkspaceID, acc.TemplateID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_schematics_output.schematics_output", "workspace_id", acc.WorkspaceID), + ), + }, + }, + }) +} + +func testAccCheckIBMSchematicsOutputDataSourceConfigBasic(wID string, templateID string) string { + return fmt.Sprintf(` + data "ibm_schematics_output" "schematics_output" { + workspace_id = "%s" + template_id = "%s" + } + `, acc.WorkspaceID, templateID) +} diff --git a/ibm/service/schematics/data_source_ibm_schematics_resource_query.go b/ibm/service/schematics/data_source_ibm_schematics_resource_query.go new file mode 100644 index 000000000..d9625ba98 --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_resource_query.go @@ -0,0 +1,215 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsResourceQuery() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsResourceQueryRead, + + Schema: map[string]*schema.Schema{ + "query_id": { + Type: schema.TypeString, + Required: true, + Description: "Resource query Id. Use `GET /v2/resource_query` API to look up the Resource query definition Ids in your IBM Cloud account.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: "The Region of the workspace.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Resource type (cluster, vsi, icd, vpc).", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Resource query name.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Resource Query id.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Resource query creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who created the Resource query.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Resource query updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who updated the Resource query.", + }, + "queries": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query_type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of the query(workspaces).", + }, + "query_condition": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the resource query param.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Value of the resource query param.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Description of resource query param variable.", + }, + }, + }, + }, + "query_select": { + Type: schema.TypeList, + Computed: true, + Description: "List of query selection parameters.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMSchematicsResourceQueryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + getResourcesQueryOptions := &schematicsv1.GetResourcesQueryOptions{} + + getResourcesQueryOptions.SetQueryID(d.Get("query_id").(string)) + + resourceQueryRecord, response, err := schematicsClient.GetResourcesQueryWithContext(context, getResourcesQueryOptions) + if err != nil { + log.Printf("[DEBUG] GetResourcesQueryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetResourcesQueryWithContext failed %s\n%s", err, response)) + } + + d.SetId(*getResourcesQueryOptions.QueryID) + if err = d.Set("type", resourceQueryRecord.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("name", resourceQueryRecord.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("id", resourceQueryRecord.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting id: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(resourceQueryRecord.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", resourceQueryRecord.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(resourceQueryRecord.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", resourceQueryRecord.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + + if resourceQueryRecord.Queries != nil { + err = d.Set("queries", dataSourceResourceQueryRecordFlattenQueries(resourceQueryRecord.Queries)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting queries %s", err)) + } + } + + return nil +} + +func dataSourceResourceQueryRecordFlattenQueries(result []schematicsv1.ResourceQuery) (queries []map[string]interface{}) { + for _, queriesItem := range result { + queries = append(queries, dataSourceResourceQueryRecordQueriesToMap(queriesItem)) + } + + return queries +} + +func dataSourceResourceQueryRecordQueriesToMap(queriesItem schematicsv1.ResourceQuery) (queriesMap map[string]interface{}) { + queriesMap = map[string]interface{}{} + + if queriesItem.QueryType != nil { + queriesMap["query_type"] = queriesItem.QueryType + } + if queriesItem.QueryCondition != nil { + queryConditionList := []map[string]interface{}{} + for _, queryConditionItem := range queriesItem.QueryCondition { + queryConditionList = append(queryConditionList, dataSourceResourceQueryRecordQueriesQueryConditionToMap(queryConditionItem)) + } + queriesMap["query_condition"] = queryConditionList + } + if queriesItem.QuerySelect != nil { + queriesMap["query_select"] = queriesItem.QuerySelect + } + + return queriesMap +} + +func dataSourceResourceQueryRecordQueriesQueryConditionToMap(queryConditionItem schematicsv1.ResourceQueryParam) (queryConditionMap map[string]interface{}) { + queryConditionMap = map[string]interface{}{} + + if queryConditionItem.Name != nil { + queryConditionMap["name"] = queryConditionItem.Name + } + if queryConditionItem.Value != nil { + queryConditionMap["value"] = queryConditionItem.Value + } + if queryConditionItem.Description != nil { + queryConditionMap["description"] = queryConditionItem.Description + } + + return queryConditionMap +} diff --git a/ibm/service/schematics/data_source_ibm_schematics_state.go b/ibm/service/schematics/data_source_ibm_schematics_state.go new file mode 100644 index 000000000..c66d1145c --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_state.go @@ -0,0 +1,117 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsState() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsStateRead, + + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the workspace for which you want to retrieve the Terraform statefile URL. To find the workspace ID, use the GET /v1/workspaces API.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: "The Region of the workspace.", + }, + "template_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the Terraform template for which you want to retrieve the Terraform statefile. When you create a workspace, the Terraform template that your workspace points to is assigned a unique ID. To find this ID, use the GET /v1/workspaces API and review the template_data.id value.", + }, + "state_store": { + Type: schema.TypeString, + Computed: true, + }, + "state_store_json": { + Type: schema.TypeString, + Computed: true, + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", + }, + }, + } +} + +func dataSourceIBMSchematicsStateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + + getWorkspaceTemplateStateOptions := &schematicsv1.GetWorkspaceTemplateStateOptions{} + + getWorkspaceTemplateStateOptions.SetWID(d.Get("workspace_id").(string)) + getWorkspaceTemplateStateOptions.SetTID(d.Get("template_id").(string)) + + _, response, _ := schematicsClient.GetWorkspaceTemplateStateWithContext(context, getWorkspaceTemplateStateOptions) + if response.StatusCode != 200 { + log.Printf("[DEBUG] GetWorkspaceTemplateStateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetWorkspaceTemplateStateWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMSchematicsStateID(d)) + + var stateStore map[string]interface{} + json.Unmarshal(response.RawResult, &stateStore) + + b := bytes.NewReader(response.RawResult) + + decoder := json.NewDecoder(b) + decoder.UseNumber() + decoder.Decode(&stateStore) + + statestr := fmt.Sprintf("%v", stateStore) + d.Set("state_store", statestr) + + stateByte, err := json.MarshalIndent(stateStore, "", "") + if err != nil { + return diag.FromErr(err) + } + + stateStoreJSON := string(stateByte[:]) + d.Set("state_store_json", stateStoreJSON) + + controller, err := flex.GetBaseController(meta) + if err != nil { + return diag.FromErr(err) + } + d.Set(flex.ResourceControllerURL, controller+"/schematics") + + return nil +} + +// dataSourceIBMSchematicsStateID returns a reasonable ID for the list. +func dataSourceIBMSchematicsStateID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_schematics_state_test.go b/ibm/service/schematics/data_source_ibm_schematics_state_test.go similarity index 78% rename from ibm/data_source_ibm_schematics_state_test.go rename to ibm/service/schematics/data_source_ibm_schematics_state_test.go index d540ed92f..5286bef52 100644 --- a/ibm/data_source_ibm_schematics_state_test.go +++ b/ibm/service/schematics/data_source_ibm_schematics_state_test.go @@ -1,23 +1,25 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMSchematicsStateDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMSchematicsStateDataSourceConfigBasic(workspaceID, templateID), + { + Config: testAccCheckIBMSchematicsStateDataSourceConfigBasic(acc.WorkspaceID, acc.TemplateID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_schematics_state.schematics_state", "id"), resource.TestCheckResourceAttrSet("data.ibm_schematics_state.schematics_state", "state_store"), @@ -33,5 +35,5 @@ func testAccCheckIBMSchematicsStateDataSourceConfigBasic(workspaceID string, tem workspace_id = "%s" template_id = "%s" } - `, workspaceID, templateID) + `, acc.WorkspaceID, templateID) } diff --git a/ibm/service/schematics/data_source_ibm_schematics_workspace.go b/ibm/service/schematics/data_source_ibm_schematics_workspace.go new file mode 100644 index 000000000..c523e18bb --- /dev/null +++ b/ibm/service/schematics/data_source_ibm_schematics_workspace.go @@ -0,0 +1,1128 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func DataSourceIBMSchematicsWorkspace() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMSchematicsWorkspaceRead, + + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the workspace. To find the workspace ID, use the `GET /v1/workspaces` API.", + }, + "applied_shareddata_ids": { + Type: schema.TypeList, + Computed: true, + Description: "List of applied shared dataset ID.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "catalog_ref": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dry_run": { + Type: schema.TypeBool, + Computed: true, + Description: "Dry run.", + }, + "owning_account": { + Type: schema.TypeString, + Computed: true, + Description: "Owning account ID of the catalog.", + }, + "item_icon_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL to the icon of the software template in the IBM Cloud catalog.", + }, + "item_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", + }, + "item_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the software that you chose to install from the IBM Cloud catalog.", + }, + "item_readme_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL to the readme file of the software template in the IBM Cloud catalog.", + }, + "item_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL to the software template in the IBM Cloud catalog.", + }, + "launch_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL to the dashboard to access your software.", + }, + "offering_version": { + Type: schema.TypeString, + Computed: true, + Description: "The version of the software template that you chose to install from the IBM Cloud catalog.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was created.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that created the workspace.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The workspace CRN.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the workspace.", + }, + "last_health_check_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the last health check was performed by Schematics.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IBM Cloud location where your workspace was provisioned.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the workspace.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "The resource group the workspace was provisioned in.", + }, + "runtime_data": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the provisioning engine, state file, and runtime logs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "engine_cmd": { + Type: schema.TypeString, + Computed: true, + Description: "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", + }, + "engine_name": { + Type: schema.TypeString, + Computed: true, + Description: "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", + }, + "engine_version": { + Type: schema.TypeString, + Computed: true, + Description: "The version of the provisioning engine that was used.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", + }, + "log_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", + }, + "output_values": { + Type: schema.TypeList, + Computed: true, + Description: "List of Output values.", + Elem: &schema.Schema{ + Type: schema.TypeMap, + }, + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Description: "List of resources.", + Elem: &schema.Schema{ + Type: schema.TypeMap, + }, + }, + "state_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs.", + }, + }, + }, + }, + "shared_data": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the Target used by the templates originating from IBM Cloud catalog offerings. This information is not relevant when you create a workspace from your own Terraform template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + "cluster_name": { + Type: schema.TypeString, + Computed: true, + Description: "Target cluster name.", + }, + "entitlement_keys": { + Type: schema.TypeList, + Computed: true, + Description: "The entitlement key that you want to use to install IBM Cloud entitled software.", + Elem: &schema.Schema{ + Type: schema.TypeMap, + }, + }, + "namespace": { + Type: schema.TypeString, + Computed: true, + Description: "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + "resource_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", + }, + "tags": { + Type: schema.TypeList, + Computed: true, + Description: "A list of tags that are associated with the workspace.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "template_env_settings": { + Type: schema.TypeList, + Computed: true, + Description: "List of environment values.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", + }, + "hidden": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", + }, + }, + }, + }, + "template_git_folder": { + Type: schema.TypeString, + Computed: true, + Description: "The subfolder in your GitHub or GitLab repository where your Terraform template is stored. If your template is stored in the root directory, `.` is returned.", + }, + "template_init_state_file": { + Type: schema.TypeString, + Computed: true, + Description: "Init state file.", + }, + "template_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Terraform version that was used to run your Terraform code.", + }, + "template_uninstall_script_name": { + Type: schema.TypeString, + Computed: true, + Description: "Uninstall script name.", + }, + "template_values": { + Type: schema.TypeString, + Computed: true, + Description: "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", + }, + "template_values_metadata": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "A list of input variables that are associated with the workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Type of the variable.", + }, + "aliases": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The list of aliases for the variable name.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The description of the meta data.", + }, + "cloud_data_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Cloud data type of the variable. eg. resource_group_id, region, vpc_id.", + }, + "default_value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Default value for the variable only if the override value is not specified.", + }, + "link_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the link.", + }, + "secure": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Is the variable readonly ?.", + }, + "hidden": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If **true**, the variable is not displayed on UI or Command line.", + }, + "required": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If the variable required?.", + }, + "options": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The list of possible values for this variable. If type is **integer** or **date**, then the array of string is converted to array of integers or date during the runtime.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "min_value": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value of the variable. Applicable for the integer type.", + }, + "max_value": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value of the variable. Applicable for the integer type.", + }, + "min_length": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The minimum length of the variable value. Applicable for the string type.", + }, + "max_length": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum length of the variable value. Applicable for the string type.", + }, + "matches": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The regex for the variable value.", + }, + "position": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The relative position of this variable in a list.", + }, + "group_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The display name of the group this variable belongs to.", + }, + "source": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The source of this meta-data.", + }, + }, + }, + }, + "template_inputs": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the input variables that your template uses.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of your input variable.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the variable.", + }, + "secure": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](https://cloud.ibm.com/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + }, + }, + }, + }, + "template_ref": { + Type: schema.TypeString, + Computed: true, + Description: "Workspace template ref.", + }, + "template_git_branch": { + Type: schema.TypeString, + Computed: true, + Description: "The repository branch.", + }, + "template_git_full_url": { + Type: schema.TypeString, + Computed: true, + Description: "Full repository URL.", + }, + "template_git_has_uploadedgitrepotar": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Has uploaded Git repository tar.", + }, + "template_git_release": { + Type: schema.TypeString, + Computed: true, + Description: "The repository release.", + }, + "template_git_repo_sha_value": { + Type: schema.TypeString, + Computed: true, + Description: "The repository SHA value.", + }, + "template_git_repo_url": { + Type: schema.TypeString, + Computed: true, + Description: "The repository URL.", + }, + "template_git_url": { + Type: schema.TypeString, + Computed: true, + Description: "The source URL.", + }, + + /*"template_type": { + Type: schema.TypeList, + Optional: true, + Description: "List of Workspace type.", + Elem: &schema.Schema{Type: schema.TypeString}, + },*/ + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was last updated.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that updated the workspace.", + }, + "is_frozen": { + Type: schema.TypeBool, + Computed: true, + Deprecated: "use frozen instead", + }, + "frozen": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, the workspace is frozen and changes to the workspace are disabled.", + }, + "frozen_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was frozen.", + }, + "frozen_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that froze the workspace.", + }, + "is_locked": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, the workspace is locked and disabled for changes.", + Deprecated: "Use locked instead", + }, + "locked": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, the workspace is locked and disabled for changes.", + }, + "locked_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that initiated a resource-related job, such as applying or destroying resources, that locked the workspace.", + }, + "locked_time": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was locked.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace.", + }, + "status_msg": { + Type: schema.TypeString, + Computed: true, + Description: "The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace.", + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", + }, + }, + } +} + +func SchematicsEndpointURL(region, meta interface{}) (string, bool, error) { + sess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return "", false, err + } + if region != sess.Config.Region { + // overide provider region with resource/datasource region argument + // update client with updated region endpoint + schematicsEndpoint := fmt.Sprintf("https://%s.%s", fmt.Sprintf("%s.schematics", region), "cloud.ibm.com") + visibility := sess.Config.Visibility + if visibility == "private" || visibility == "public-and-private" { + schematicsEndpoint = fmt.Sprintf("https://%s.%s", fmt.Sprintf("private-%s.schematics", region), "cloud.ibm.com") + } + schematicsEndpointURL := conns.EnvFallBack([]string{"IBMCLOUD_SCHEMATICS_API_ENDPOINT"}, schematicsEndpoint) + return schematicsEndpointURL, true, nil + } + return "", false, nil +} + +func dataSourceIBMSchematicsWorkspaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + + getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} + + getWorkspaceOptions.SetWID(d.Get("workspace_id").(string)) + + workspaceResponse, response, err := schematicsClient.GetWorkspaceWithContext(context, getWorkspaceOptions) + if err != nil { + log.Printf("[DEBUG] GetWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetWorkspaceWithContext failed %s\n%s", err, response)) + } + + d.SetId(*getWorkspaceOptions.WID) + + if workspaceResponse.CatalogRef != nil { + err = d.Set("catalog_ref", dataSourceWorkspaceResponseFlattenCatalogRef(*workspaceResponse.CatalogRef)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting catalog_ref %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(workspaceResponse.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", workspaceResponse.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("crn", workspaceResponse.Crn); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("description", workspaceResponse.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if err = d.Set("last_health_check_at", flex.DateTimeToString(workspaceResponse.LastHealthCheckAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_health_check_at: %s", err)) + } + if err = d.Set("location", workspaceResponse.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("name", workspaceResponse.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("resource_group", workspaceResponse.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + + if workspaceResponse.RuntimeData != nil { + err = d.Set("runtime_data", dataSourceWorkspaceResponseFlattenRuntimeData(workspaceResponse.RuntimeData)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting runtime_data %s", err)) + } + } + + if workspaceResponse.SharedData != nil { + err = d.Set("shared_data", dataSourceWorkspaceResponseFlattenSharedData(*workspaceResponse.SharedData)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting shared_data %s", err)) + } + } + if err = d.Set("status", workspaceResponse.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + + if workspaceResponse.TemplateData != nil { + templateData := dataSourceWorkspaceResponseFlattenTemplateData(workspaceResponse.TemplateData) + + if err = d.Set("template_env_settings", templateData[0]["env_values"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading env_values: %s", err)) + } + if err = d.Set("template_git_folder", templateData[0]["folder"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading folder: %s", err)) + } + if err = d.Set("template_init_state_file", templateData[0]["init_state_file"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading init_state_file: %s", err)) + } + if err = d.Set("template_type", templateData[0]["type"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading type: %s", err)) + } + if err = d.Set("template_uninstall_script_name", templateData[0]["uninstall_script_name"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading uninstall_script_name: %s", err)) + } + if err = d.Set("template_values", templateData[0]["values"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading values: %s", err)) + } + if err = d.Set("template_values_metadata", templateData[0]["values_metadata"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading values_metadata: %s", err)) + } + if err = d.Set("template_inputs", templateData[0]["variablestore"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading variablestore: %s", err)) + } + } + if err = d.Set("template_ref", workspaceResponse.TemplateRef); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting template_ref: %s", err)) + } + + if workspaceResponse.TemplateRepo != nil { + templateRepoMap := dataSourceWorkspaceResponseFlattenTemplateRepo(*workspaceResponse.TemplateRepo) + if err = d.Set("template_git_branch", templateRepoMap[0]["branch"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading branch: %s", err)) + } + if err = d.Set("template_git_release", templateRepoMap[0]["release"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading release: %s", err)) + } + if err = d.Set("template_git_repo_sha_value", templateRepoMap[0]["repo_sha_value"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading repo_sha_value: %s", err)) + } + if err = d.Set("template_git_repo_url", templateRepoMap[0]["repo_url"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading repo_url: %s", err)) + } + if err = d.Set("template_git_url", templateRepoMap[0]["url"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading url: %s", err)) + } + if err = d.Set("template_git_has_uploadedgitrepotar", templateRepoMap[0]["has_uploadedgitrepotar"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading has_uploadedgitrepotar: %s", err)) + } + } + /*if err = d.Set("type", workspaceResponse.Type); err != nil { + return fmt.Errorf("[ERROR] Error setting type: %s", err) + }*/ + if workspaceResponse.UpdatedAt != nil { + if err = d.Set("updated_at", workspaceResponse.UpdatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + } + if err = d.Set("updated_by", workspaceResponse.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + + if workspaceResponse.WorkspaceStatus != nil { + workspaceStatusMap := dataSourceWorkspaceResponseFlattenWorkspaceStatus(*workspaceResponse.WorkspaceStatus) + if err = d.Set("is_frozen", workspaceStatusMap[0]["frozen"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen: %s", err)) + } + if err = d.Set("frozen", workspaceStatusMap[0]["frozen"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen: %s", err)) + } + if err = d.Set("frozen_at", workspaceStatusMap[0]["frozen_at"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen_at: %s", err)) + } + if err = d.Set("frozen_by", workspaceStatusMap[0]["frozen_by"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen_by: %s", err)) + } + if err = d.Set("is_locked", workspaceStatusMap[0]["locked"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked: %s", err)) + } + if err = d.Set("locked", workspaceStatusMap[0]["locked"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked: %s", err)) + } + if err = d.Set("locked_by", workspaceStatusMap[0]["locked_by"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked_by: %s", err)) + } + if err = d.Set("locked_time", workspaceStatusMap[0]["locked_time"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked_time: %s", err)) + } + } + + if workspaceResponse.WorkspaceStatusMsg != nil { + workspaceStatusMsgMap := dataSourceWorkspaceResponseFlattenWorkspaceStatusMsg(*workspaceResponse.WorkspaceStatusMsg) + if err = d.Set("status_code", workspaceStatusMsgMap[0]["status_code"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading status_code: %s", err)) + } + if err = d.Set("status_msg", workspaceStatusMsgMap[0]["status_msg"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading status_msg: %s", err)) + } + } + + controller, err := flex.GetBaseController(meta) + if err != nil { + return diag.FromErr(err) + } + d.Set(flex.ResourceControllerURL, controller+"/schematics") + + return nil +} + +func dataSourceWorkspaceResponseFlattenCatalogRef(result schematicsv1.CatalogRef) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceWorkspaceResponseCatalogRefToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceWorkspaceResponseCatalogRefToMap(catalogRefItem schematicsv1.CatalogRef) (catalogRefMap map[string]interface{}) { + catalogRefMap = map[string]interface{}{} + + if catalogRefItem.DryRun != nil { + catalogRefMap["dry_run"] = catalogRefItem.DryRun + } + if catalogRefItem.OwningAccount != nil { + catalogRefMap["owning_account"] = catalogRefItem.OwningAccount + } + if catalogRefItem.ItemIconURL != nil { + catalogRefMap["item_icon_url"] = catalogRefItem.ItemIconURL + } + if catalogRefItem.ItemID != nil { + catalogRefMap["item_id"] = catalogRefItem.ItemID + } + if catalogRefItem.ItemName != nil { + catalogRefMap["item_name"] = catalogRefItem.ItemName + } + if catalogRefItem.ItemReadmeURL != nil { + catalogRefMap["item_readme_url"] = catalogRefItem.ItemReadmeURL + } + if catalogRefItem.ItemURL != nil { + catalogRefMap["item_url"] = catalogRefItem.ItemURL + } + if catalogRefItem.LaunchURL != nil { + catalogRefMap["launch_url"] = catalogRefItem.LaunchURL + } + if catalogRefItem.OfferingVersion != nil { + catalogRefMap["offering_version"] = catalogRefItem.OfferingVersion + } + + return catalogRefMap +} + +func dataSourceWorkspaceResponseFlattenRuntimeData(result []schematicsv1.TemplateRunTimeDataResponse) (runtimeData []map[string]interface{}) { + for _, runtimeDataItem := range result { + runtimeData = append(runtimeData, dataSourceWorkspaceResponseRuntimeDataToMap(runtimeDataItem)) + } + + return runtimeData +} + +func dataSourceWorkspaceResponseRuntimeDataToMap(runtimeDataItem schematicsv1.TemplateRunTimeDataResponse) (runtimeDataMap map[string]interface{}) { + runtimeDataMap = map[string]interface{}{} + + if runtimeDataItem.EngineCmd != nil { + runtimeDataMap["engine_cmd"] = runtimeDataItem.EngineCmd + } + if runtimeDataItem.EngineName != nil { + runtimeDataMap["engine_name"] = runtimeDataItem.EngineName + } + if runtimeDataItem.EngineVersion != nil { + runtimeDataMap["engine_version"] = runtimeDataItem.EngineVersion + } + if runtimeDataItem.ID != nil { + runtimeDataMap["id"] = runtimeDataItem.ID + } + if runtimeDataItem.LogStoreURL != nil { + runtimeDataMap["log_store_url"] = runtimeDataItem.LogStoreURL + } + if runtimeDataItem.OutputValues != nil { + runtimeDataMap["output_values"] = runtimeDataItem.OutputValues + } + if runtimeDataItem.Resources != nil { + runtimeDataMap["resources"] = runtimeDataItem.Resources + } + if runtimeDataItem.StateStoreURL != nil { + runtimeDataMap["state_store_url"] = runtimeDataItem.StateStoreURL + } + + return runtimeDataMap +} + +func dataSourceWorkspaceResponseFlattenSharedData(result schematicsv1.SharedTargetDataResponse) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceWorkspaceResponseSharedDataToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceWorkspaceResponseSharedDataToMap(sharedDataItem schematicsv1.SharedTargetDataResponse) (sharedDataMap map[string]interface{}) { + sharedDataMap = map[string]interface{}{} + + if sharedDataItem.ClusterID != nil { + sharedDataMap["cluster_id"] = sharedDataItem.ClusterID + } + if sharedDataItem.ClusterName != nil { + sharedDataMap["cluster_name"] = sharedDataItem.ClusterName + } + if sharedDataItem.EntitlementKeys != nil { + sharedDataMap["entitlement_keys"] = sharedDataItem.EntitlementKeys + } + if sharedDataItem.Namespace != nil { + sharedDataMap["namespace"] = sharedDataItem.Namespace + } + if sharedDataItem.Region != nil { + sharedDataMap["region"] = sharedDataItem.Region + } + if sharedDataItem.ResourceGroupID != nil { + sharedDataMap["resource_group_id"] = sharedDataItem.ResourceGroupID + } + + return sharedDataMap +} + +func dataSourceWorkspaceResponseFlattenTemplateData(result []schematicsv1.TemplateSourceDataResponse) (templateData []map[string]interface{}) { + for _, templateDataItem := range result { + templateData = append(templateData, dataSourceWorkspaceResponseTemplateDataToMap(templateDataItem)) + } + + return templateData +} + +func dataSourceWorkspaceResponseTemplateDataToMap(templateDataItem schematicsv1.TemplateSourceDataResponse) (templateDataMap map[string]interface{}) { + templateDataMap = map[string]interface{}{} + + if templateDataItem.EnvValues != nil { + envValuesList := []map[string]interface{}{} + for _, envValuesItem := range templateDataItem.EnvValues { + envValuesList = append(envValuesList, dataSourceWorkspaceResponseTemplateDataEnvValuesToMap(envValuesItem)) + } + templateDataMap["env_values"] = envValuesList + } + if templateDataItem.Folder != nil { + templateDataMap["folder"] = templateDataItem.Folder + } + if templateDataItem.Compact != nil { + templateDataMap["compact"] = templateDataItem.Compact + } + if templateDataItem.HasGithubtoken != nil { + templateDataMap["has_githubtoken"] = templateDataItem.HasGithubtoken + } + if templateDataItem.ID != nil { + templateDataMap["id"] = templateDataItem.ID + } + if templateDataItem.Type != nil { + templateDataMap["type"] = templateDataItem.Type + } + if templateDataItem.UninstallScriptName != nil { + templateDataMap["uninstall_script_name"] = templateDataItem.UninstallScriptName + } + if templateDataItem.Values != nil { + templateDataMap["values"] = templateDataItem.Values + } + if templateDataItem.ValuesMetadata != nil { + valuesMetadata := []map[string]interface{}{} + for _, valuesMetadataItem := range templateDataItem.ValuesMetadata { + valuesMetadataItemMap := dataSourceIbmSchematicsWorkspaceVariableMetadataToMap(&valuesMetadataItem) + valuesMetadata = append(valuesMetadata, valuesMetadataItemMap) + } + templateDataMap["values_metadata"] = valuesMetadata + } + if templateDataItem.ValuesURL != nil { + templateDataMap["values_url"] = templateDataItem.ValuesURL + } + if templateDataItem.Variablestore != nil { + variablestoreList := []map[string]interface{}{} + for _, variablestoreItem := range templateDataItem.Variablestore { + variablestoreList = append(variablestoreList, dataSourceWorkspaceResponseTemplateDataVariablestoreToMap(variablestoreItem)) + } + templateDataMap["variablestore"] = variablestoreList + } + + return templateDataMap +} +func dataSourceIbmSchematicsWorkspaceVariableMetadataToMap(model *schematicsv1.VariableMetadata) map[string]interface{} { + modelMap := make(map[string]interface{}) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Aliases != nil { + modelMap["aliases"] = model.Aliases + } + if model.Description != nil { + modelMap["description"] = *model.Description + } + if model.CloudDataType != nil { + modelMap["cloud_data_type"] = *model.CloudDataType + } + if model.DefaultValue != nil { + modelMap["default_value"] = *model.DefaultValue + } + if model.LinkStatus != nil { + modelMap["link_status"] = *model.LinkStatus + } + if model.Secure != nil { + modelMap["secure"] = *model.Secure + } + if model.Immutable != nil { + modelMap["immutable"] = *model.Immutable + } + if model.Hidden != nil { + modelMap["hidden"] = *model.Hidden + } + if model.Required != nil { + modelMap["required"] = *model.Required + } + if model.Options != nil { + modelMap["options"] = model.Options + } + if model.MinValue != nil { + modelMap["min_value"] = *model.MinValue + } + if model.MaxValue != nil { + modelMap["max_value"] = *model.MaxValue + } + if model.MinLength != nil { + modelMap["min_length"] = *model.MinLength + } + if model.MaxLength != nil { + modelMap["max_length"] = *model.MaxLength + } + if model.Matches != nil { + modelMap["matches"] = *model.Matches + } + if model.Position != nil { + modelMap["position"] = *model.Position + } + if model.GroupBy != nil { + modelMap["group_by"] = *model.GroupBy + } + if model.Source != nil { + modelMap["source"] = *model.Source + } + return modelMap +} +func dataSourceWorkspaceResponseTemplateDataEnvValuesToMap(envValuesItem schematicsv1.EnvVariableResponse) (envValuesMap map[string]interface{}) { + envValuesMap = map[string]interface{}{} + + if envValuesItem.Hidden != nil { + envValuesMap["hidden"] = *envValuesItem.Hidden + } + if envValuesItem.Name != nil { + envValuesMap["name"] = envValuesItem.Name + } + if envValuesItem.Secure != nil { + envValuesMap["secure"] = *envValuesItem.Secure + } + if envValuesItem.Value != nil { + envValuesMap["value"] = envValuesItem.Value + } + + return envValuesMap +} + +func dataSourceWorkspaceResponseTemplateDataVariablestoreToMap(variablestoreItem schematicsv1.WorkspaceVariableResponse) (variablestoreMap map[string]interface{}) { + variablestoreMap = map[string]interface{}{} + + if variablestoreItem.Description != nil { + variablestoreMap["description"] = variablestoreItem.Description + } + if variablestoreItem.Name != nil { + variablestoreMap["name"] = variablestoreItem.Name + } + if variablestoreItem.Secure != nil { + variablestoreMap["secure"] = variablestoreItem.Secure + } + if variablestoreItem.Type != nil { + variablestoreMap["type"] = variablestoreItem.Type + } + if variablestoreItem.Value != nil { + variablestoreMap["value"] = variablestoreItem.Value + } + + return variablestoreMap +} + +func dataSourceWorkspaceResponseFlattenTemplateRepo(result schematicsv1.TemplateRepoResponse) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceWorkspaceResponseTemplateRepoToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceWorkspaceResponseTemplateRepoToMap(templateRepoItem schematicsv1.TemplateRepoResponse) (templateRepoMap map[string]interface{}) { + templateRepoMap = map[string]interface{}{} + + if templateRepoItem.Branch != nil { + templateRepoMap["branch"] = templateRepoItem.Branch + } + if templateRepoItem.FullURL != nil { + templateRepoMap["full_url"] = templateRepoItem.FullURL + } + if templateRepoItem.HasUploadedgitrepotar != nil { + templateRepoMap["has_uploadedgitrepotar"] = templateRepoItem.HasUploadedgitrepotar + } + if templateRepoItem.Release != nil { + templateRepoMap["release"] = templateRepoItem.Release + } + if templateRepoItem.RepoShaValue != nil { + templateRepoMap["repo_sha_value"] = templateRepoItem.RepoShaValue + } + if templateRepoItem.RepoURL != nil { + templateRepoMap["repo_url"] = templateRepoItem.RepoURL + } + if templateRepoItem.URL != nil { + templateRepoMap["url"] = templateRepoItem.URL + } + + return templateRepoMap +} + +func dataSourceWorkspaceResponseFlattenWorkspaceStatus(result schematicsv1.WorkspaceStatusResponse) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceWorkspaceResponseWorkspaceStatusToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceWorkspaceResponseWorkspaceStatusToMap(workspaceStatusItem schematicsv1.WorkspaceStatusResponse) (workspaceStatusMap map[string]interface{}) { + workspaceStatusMap = map[string]interface{}{} + + if workspaceStatusItem.Frozen != nil { + workspaceStatusMap["frozen"] = workspaceStatusItem.Frozen + } + if workspaceStatusItem.FrozenAt != nil { + workspaceStatusMap["frozen_at"] = workspaceStatusItem.FrozenAt.String() + } + if workspaceStatusItem.FrozenBy != nil { + workspaceStatusMap["frozen_by"] = workspaceStatusItem.FrozenBy + } + if workspaceStatusItem.Locked != nil { + workspaceStatusMap["locked"] = workspaceStatusItem.Locked + } + if workspaceStatusItem.LockedBy != nil { + workspaceStatusMap["locked_by"] = workspaceStatusItem.LockedBy + } + if workspaceStatusItem.LockedTime != nil { + workspaceStatusMap["locked_time"] = workspaceStatusItem.LockedTime.String() + } + + return workspaceStatusMap +} + +func dataSourceWorkspaceResponseFlattenWorkspaceStatusMsg(result schematicsv1.WorkspaceStatusMessage) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceWorkspaceResponseWorkspaceStatusMsgToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceWorkspaceResponseWorkspaceStatusMsgToMap(workspaceStatusMsgItem schematicsv1.WorkspaceStatusMessage) (workspaceStatusMsgMap map[string]interface{}) { + workspaceStatusMsgMap = map[string]interface{}{} + + if workspaceStatusMsgItem.StatusCode != nil { + workspaceStatusMsgMap["status_code"] = workspaceStatusMsgItem.StatusCode + } + if workspaceStatusMsgItem.StatusMsg != nil { + workspaceStatusMsgMap["status_msg"] = workspaceStatusMsgItem.StatusMsg + } + + return workspaceStatusMsgMap +} diff --git a/ibm/data_source_ibm_schematics_workspace_test.go b/ibm/service/schematics/data_source_ibm_schematics_workspace_test.go similarity index 90% rename from ibm/data_source_ibm_schematics_workspace_test.go rename to ibm/service/schematics/data_source_ibm_schematics_workspace_test.go index baed06544..ccbaf9885 100644 --- a/ibm/data_source_ibm_schematics_workspace_test.go +++ b/ibm/service/schematics/data_source_ibm_schematics_workspace_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,15 +16,14 @@ import ( func TestAccIBMSchematicsWorkspaceDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSchematicsWorkspaceDataSourceConfigBasic(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "id"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "workspace_id"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "applied_shareddata_ids.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "created_at"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "created_by"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "crn"), @@ -35,9 +36,9 @@ func TestAccIBMSchematicsWorkspaceDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "shared_data.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "status"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "tags.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "template_type"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "template_env_settings.#"), ), }, }, @@ -52,15 +53,14 @@ func TestAccIBMSchematicsWorkspaceDataSourceAllArgs(t *testing.T) { workspaceResponseResourceGroup := "default" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSchematicsWorkspaceDataSourceConfig(workspaceResponseDescription, workspaceResponseLocation, workspaceResponseName, workspaceResponseResourceGroup), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "id"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "workspace_id"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "applied_shareddata_ids.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "created_at"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "created_by"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "crn"), @@ -73,10 +73,9 @@ func TestAccIBMSchematicsWorkspaceDataSourceAllArgs(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "shared_data.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "status"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "tags.#"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "template_type"), resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "updated_at"), - resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "template_env_settings"), + resource.TestCheckResourceAttrSet("data.ibm_schematics_workspace.schematics_workspace", "template_env_settings.#"), ), }, }, @@ -84,7 +83,7 @@ func TestAccIBMSchematicsWorkspaceDataSourceAllArgs(t *testing.T) { } func testAccCheckIBMSchematicsWorkspaceDataSourceConfigBasic() string { - return fmt.Sprintf(` + return ` resource "ibm_schematics_workspace" "schematics_workspace" { description = "tf-acc-test-schematics" name = "tf-acc-test-schematics" @@ -101,7 +100,7 @@ func testAccCheckIBMSchematicsWorkspaceDataSourceConfigBasic() string { data "ibm_schematics_workspace" "schematics_workspace" { workspace_id = ibm_schematics_workspace.schematics_workspace.id } - `) + ` } func testAccCheckIBMSchematicsWorkspaceDataSourceConfig(workspaceResponseDescription string, workspaceResponseLocation string, workspaceResponseName string, workspaceResponseResourceGroup string) string { diff --git a/ibm/service/schematics/resource_ibm_schematics_action.go b/ibm/service/schematics/resource_ibm_schematics_action.go new file mode 100644 index 000000000..5b7efef5f --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_action.go @@ -0,0 +1,1968 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +const ( + actionName = "name" +) + +func ResourceIBMSchematicsAction() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSchematicsActionCreate, + ReadContext: resourceIBMSchematicsActionRead, + UpdateContext: resourceIBMSchematicsActionUpdate, + DeleteContext: resourceIBMSchematicsActionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action.", + ValidateFunc: validate.InvokeValidator("ibm_schematics_action", "name"), + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Action description.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_action", "location"), + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "Resource-group name for an action. By default, action is created in default resource group.", + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Description: "Action tags.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "user_state": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "User defined status of the Schematics object.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": { + Type: schema.TypeString, + Optional: true, + Description: "User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution.", + }, + "set_by": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Name of the User who set the state of the Object.", + }, + "set_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "When the User who set the state of the Object.", + }, + }, + }, + }, + "source_readme_url": { + Type: schema.TypeString, + Optional: true, + Description: "URL of the `README` file, for the source URL.", + }, + "source": { + Type: schema.TypeList, + Optional: true, + Description: "Source of templates, playbooks, or controls.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_type": { + Type: schema.TypeString, + Required: true, + Description: "Type of source for the Template.", + }, + "git": { + Type: schema.TypeList, + Optional: true, + Description: "Connection details to Git source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "computed_git_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + }, + "git_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "URL to the GIT Repo that can be used to clone the template.", + ValidateFunc: validation.IsURLWithHTTPorHTTPS, + }, + "git_token": { + Type: schema.TypeString, + Optional: true, + Description: "Personal Access Token to connect to Git URLs.", + }, + "git_repo_folder": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the folder in the Git Repo, that contains the template.", + }, + "git_release": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the release tag, used to fetch the Git Repo.", + }, + "git_branch": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the branch, used to fetch the Git Repo.", + }, + }, + }, + }, + "catalog": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Connection details to IBM Cloud Catalog source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_name": { + Type: schema.TypeString, + Optional: true, + Description: "name of the private catalog.", + }, + "offering_name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the offering in the IBM Catalog.", + }, + "offering_version": { + Type: schema.TypeString, + Optional: true, + Description: "Version string of the offering in the IBM Catalog.", + }, + "offering_kind": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the offering, in the IBM Catalog.", + }, + "offering_id": { + Type: schema.TypeString, + Optional: true, + Description: "Id of the offering the IBM Catalog.", + }, + "offering_version_id": { + Type: schema.TypeString, + Optional: true, + Description: "Id of the offering version the IBM Catalog.", + }, + "offering_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "Repo Url of the offering, in the IBM Catalog.", + }, + }, + }, + }, + // "cos_bucket": { + // Type: schema.TypeList, + // MaxItems: 1, + // Optional: true, + // Description: "Connection details to a IBM Cloud Object Storage bucket.", + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "cos_bucket_url": { + // Type: schema.TypeString, + // Optional: true, + // Description: "COS Bucket Url.", + // }, + // }, + // }, + // }, + }, + }, + }, + "source_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_action", "source_type"), + Description: "Type of source for the Template.", + }, + "command_parameter": { + Type: schema.TypeString, + Optional: true, + Description: "Schematics job command parameter (playbook-name).", + }, + "inventory": { + Type: schema.TypeString, + Optional: true, + Description: "Target inventory record ID, used by the action or ansible playbook.", + }, + "credentials": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "credentials of the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "bastion": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Describes a bastion resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Bastion Name(Unique).", + }, + "host": { + Type: schema.TypeString, + Optional: true, + Description: "Reference to the Inventory resource definition.", + }, + }, + }, + }, + "bastion_credential": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable variable data & system generated reference to value.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "targets_ini": { + Type: schema.TypeString, + Optional: true, + Description: "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", + }, + "action_inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Input variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "action_outputs": { + Type: schema.TypeList, + Optional: true, + Description: "Output variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables for the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "state": { + Type: schema.TypeList, + Computed: true, + Description: "Computed state of the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of automation (workspace or action).", + }, + "status_job_id": { + Type: schema.TypeString, + Optional: true, + Description: "Job id reference for this status.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Automation status message - to be displayed along with the status_code.", + }, + }, + }, + }, + "sys_lock": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "System lock status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sys_locked": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the automation locked by a Schematic job ?.", + }, + "sys_locked_by": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the User who performed the job, that lead to the locking of the automation.", + }, + "sys_locked_at": { + Type: schema.TypeString, + Optional: true, + Description: "When the User performed the job that lead to locking of the automation ?.", + }, + }, + }, + }, + "x_github_token": { + Type: schema.TypeString, + Optional: true, + Description: "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "Action Cloud Resource Name.", + }, + "account": { + Type: schema.TypeString, + Computed: true, + Description: "Action account ID.", + }, + "source_created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action Playbook Source creation time.", + }, + "source_created_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of user who created the Action Playbook Source.", + }, + "source_updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The action playbook updation time.", + }, + "source_updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of user who updated the action playbook source.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of the user who created an action.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Action updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "E-mail address of the user who updated an action.", + }, + "playbook_names": { + Type: schema.TypeList, + Computed: true, + Description: "Playbook names retrieved from the respository.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ResourceIBMSchematicsActionValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "eu-de, eu-gb, us-east, us-south", + }, + validate.ValidateSchema{ + Identifier: "source_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "cos_bucket, external_scm, git_hub, git_hub_enterprise, git_lab, ibm_cloud_catalog, ibm_git_lab, local", + }, + validate.ValidateSchema{ + Identifier: actionName, + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + MinValueLength: 1, + MaxValueLength: 65, + Optional: true, + }) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_schematics_action", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSchematicsActionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + createActionOptions := &schematicsv1.CreateActionOptions{} + + if _, ok := d.GetOk("name"); ok { + createActionOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("description"); ok { + createActionOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("location"); ok { + createActionOptions.SetLocation(d.Get("location").(string)) + } + if _, ok := d.GetOk("resource_group"); ok { + createActionOptions.SetResourceGroup(d.Get("resource_group").(string)) + } + if _, ok := d.GetOk("tags"); ok { + createActionOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("user_state"); ok { + userState := resourceIBMSchematicsActionMapToUserState(d.Get("user_state.0").(map[string]interface{})) + createActionOptions.SetUserState(&userState) + } + if _, ok := d.GetOk("source_readme_url"); ok { + createActionOptions.SetSourceReadmeURL(d.Get("source_readme_url").(string)) + } + if _, ok := d.GetOk("source"); ok { + source := resourceIBMSchematicsActionMapToExternalSource(d.Get("source.0").(map[string]interface{})) + createActionOptions.SetSource(&source) + } + if _, ok := d.GetOk("source_type"); ok { + createActionOptions.SetSourceType(d.Get("source_type").(string)) + } + if _, ok := d.GetOk("command_parameter"); ok { + createActionOptions.SetCommandParameter(d.Get("command_parameter").(string)) + } + if _, ok := d.GetOk("inventory"); ok { + createActionOptions.SetInventory(d.Get("inventory").(string)) + } + if _, ok := d.GetOk("credentials"); ok { + var credentials []schematicsv1.CredentialVariableData + for _, e := range d.Get("credentials").([]interface{}) { + value := e.(map[string]interface{}) + credentialsItem := resourceIBMSchematicsActionMapToCredentialsVariableData(value) + credentials = append(credentials, credentialsItem) + } + createActionOptions.SetCredentials(credentials) + } + if _, ok := d.GetOk("bastion"); ok { + bastion := resourceIBMSchematicsActionMapToBastionResourceDefinition(d.Get("bastion.0").(map[string]interface{})) + createActionOptions.SetBastion(&bastion) + } + if _, ok := d.GetOk("bastion_credential"); ok { + bastionCredential := resourceIBMSchematicsActionMapToCredentialsVariableData(d.Get("bastion_credential.0").(map[string]interface{})) + createActionOptions.SetBastionCredential(&bastionCredential) + } + if _, ok := d.GetOk("targets_ini"); ok { + createActionOptions.SetTargetsIni(d.Get("targets_ini").(string)) + } + if _, ok := d.GetOk("action_inputs"); ok { + var actionInputs []schematicsv1.VariableData + for _, e := range d.Get("action_inputs").([]interface{}) { + value := e.(map[string]interface{}) + actionInputsItem := resourceIBMSchematicsActionMapToVariableData(value) + actionInputs = append(actionInputs, actionInputsItem) + } + createActionOptions.SetInputs(actionInputs) + } + if _, ok := d.GetOk("action_outputs"); ok { + var actionOutputs []schematicsv1.VariableData + for _, e := range d.Get("action_outputs").([]interface{}) { + value := e.(map[string]interface{}) + actionOutputsItem := resourceIBMSchematicsActionMapToVariableData(value) + actionOutputs = append(actionOutputs, actionOutputsItem) + } + createActionOptions.SetOutputs(actionOutputs) + } + if _, ok := d.GetOk("settings"); ok { + var settings []schematicsv1.VariableData + for _, e := range d.Get("settings").([]interface{}) { + value := e.(map[string]interface{}) + settingsItem := resourceIBMSchematicsActionMapToVariableData(value) + settings = append(settings, settingsItem) + } + createActionOptions.SetSettings(settings) + } + if _, ok := d.GetOk("state"); ok { + state := resourceIBMSchematicsActionMapToActionState(d.Get("state.0").(map[string]interface{})) + createActionOptions.SetState(&state) + } + if _, ok := d.GetOk("sys_lock"); ok { + sysLock := resourceIBMSchematicsActionMapToSystemLock(d.Get("sys_lock.0").(map[string]interface{})) + createActionOptions.SetSysLock(&sysLock) + } + if _, ok := d.GetOk("x_github_token"); ok { + createActionOptions.SetXGithubToken(d.Get("x_github_token").(string)) + } + + action, response, err := schematicsClient.CreateActionWithContext(context, createActionOptions) + if err != nil { + log.Printf("[DEBUG] CreateActionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateActionWithContext failed %s\n%s", err, response)) + } + + d.SetId(*action.ID) + + return resourceIBMSchematicsActionRead(context, d, meta) +} + +func resourceIBMSchematicsActionMapToUserState(userStateMap map[string]interface{}) schematicsv1.UserState { + userState := schematicsv1.UserState{} + + if userStateMap["state"] != nil { + userState.State = core.StringPtr(userStateMap["state"].(string)) + } + if userStateMap["set_by"] != nil { + userState.SetBy = core.StringPtr(userStateMap["set_by"].(string)) + } + if userStateMap["set_at"] != nil { + setAt, err := strfmt.ParseDateTime(userStateMap["set_at"].(string)) + if err != nil { + userState.SetAt = &setAt + } + } + + return userState +} + +func resourceIBMSchematicsActionMapToExternalSource(externalSourceMap map[string]interface{}) schematicsv1.ExternalSource { + externalSource := schematicsv1.ExternalSource{} + + externalSource.SourceType = core.StringPtr(externalSourceMap["source_type"].(string)) + if externalSourceMap["git"] != nil { + externalSourceGit := resourceIBMSchematicsActionMapToExternalSourceGit(externalSourceMap["git"].([]interface{})[0].(map[string]interface{})) + externalSource.Git = &externalSourceGit + } + if externalSourceMap["catalog"] != nil && len(externalSourceMap["catalog"].([]interface{})) > 0 { + externalSourceCatalog := resourceIBMSchematicsActionMapToExternalSourceCatalog(externalSourceMap["catalog"].([]interface{})[0].(map[string]interface{})) + externalSource.Catalog = &externalSourceCatalog + } + + return externalSource +} + +func resourceIBMSchematicsActionMapToExternalSourceGit(externalSourceGitMap map[string]interface{}) schematicsv1.GitSource { + externalSourceGit := schematicsv1.GitSource{} + + if externalSourceGitMap["computed_git_repo_url"] != nil { + externalSourceGit.ComputedGitRepoURL = core.StringPtr(externalSourceGitMap["computed_git_repo_url"].(string)) + } + if externalSourceGitMap["git_repo_url"] != nil { + externalSourceGit.GitRepoURL = core.StringPtr(externalSourceGitMap["git_repo_url"].(string)) + } + if externalSourceGitMap["git_token"] != nil { + externalSourceGit.GitToken = core.StringPtr(externalSourceGitMap["git_token"].(string)) + } + if externalSourceGitMap["git_repo_folder"] != nil { + externalSourceGit.GitRepoFolder = core.StringPtr(externalSourceGitMap["git_repo_folder"].(string)) + } + if externalSourceGitMap["git_release"] != nil { + externalSourceGit.GitRelease = core.StringPtr(externalSourceGitMap["git_release"].(string)) + } + if externalSourceGitMap["git_branch"] != nil { + externalSourceGit.GitBranch = core.StringPtr(externalSourceGitMap["git_branch"].(string)) + } + + return externalSourceGit +} + +func resourceIBMSchematicsActionMapToExternalSourceCatalog(externalSourceCatalogMap map[string]interface{}) schematicsv1.CatalogSource { + externalSourceCatalog := schematicsv1.CatalogSource{} + + if externalSourceCatalogMap["catalog_name"] != nil { + externalSourceCatalog.CatalogName = core.StringPtr(externalSourceCatalogMap["catalog_name"].(string)) + } + if externalSourceCatalogMap["offering_name"] != nil { + externalSourceCatalog.OfferingName = core.StringPtr(externalSourceCatalogMap["offering_name"].(string)) + } + if externalSourceCatalogMap["offering_version"] != nil { + externalSourceCatalog.OfferingVersion = core.StringPtr(externalSourceCatalogMap["offering_version"].(string)) + } + if externalSourceCatalogMap["offering_kind"] != nil { + externalSourceCatalog.OfferingKind = core.StringPtr(externalSourceCatalogMap["offering_kind"].(string)) + } + if externalSourceCatalogMap["offering_id"] != nil { + externalSourceCatalog.OfferingID = core.StringPtr(externalSourceCatalogMap["offering_id"].(string)) + } + if externalSourceCatalogMap["offering_version_id"] != nil { + externalSourceCatalog.OfferingVersionID = core.StringPtr(externalSourceCatalogMap["offering_version_id"].(string)) + } + if externalSourceCatalogMap["offering_repo_url"] != nil { + externalSourceCatalog.OfferingRepoURL = core.StringPtr(externalSourceCatalogMap["offering_repo_url"].(string)) + } + + return externalSourceCatalog +} + +// func resourceIBMSchematicsActionMapToExternalSourceCosBucket(externalSourceCosBucketMap map[string]interface{}) schematicsv1.ExternalSourceCosBucket { +// externalSourceCosBucket := schematicsv1.ExternalSourceCosBucket{} + +// if externalSourceCosBucketMap["cos_bucket_url"] != nil { +// externalSourceCosBucket.CosBucketURL = core.StringPtr(externalSourceCosBucketMap["cos_bucket_url"].(string)) +// } + +// return externalSourceCosBucket +// } + +func resourceIBMSchematicsActionMapToVariableData(variableDataMap map[string]interface{}) schematicsv1.VariableData { + variableData := schematicsv1.VariableData{} + + if variableDataMap["name"] != nil { + variableData.Name = core.StringPtr(variableDataMap["name"].(string)) + } + if variableDataMap["value"] != nil { + variableData.Value = core.StringPtr(variableDataMap["value"].(string)) + } + if variableDataMap["metadata"] != nil && len(variableDataMap["metadata"].([]interface{})) != 0 { + variableMetaData := resourceIBMSchematicsJobMapToVariableMetadata(variableDataMap["metadata"].([]interface{})[0].(map[string]interface{})) + variableData.Metadata = &variableMetaData + } + if variableDataMap["link"] != nil { + variableData.Link = core.StringPtr(variableDataMap["link"].(string)) + } + + return variableData +} +func resourceIBMSchematicsActionMapToCredentialsVariableData(variableDataMap map[string]interface{}) schematicsv1.CredentialVariableData { + variableData := schematicsv1.CredentialVariableData{} + + if variableDataMap["name"] != nil { + variableData.Name = core.StringPtr(variableDataMap["name"].(string)) + } + if variableDataMap["value"] != nil { + variableData.Value = core.StringPtr(variableDataMap["value"].(string)) + } + if variableDataMap["metadata"] != nil && len(variableDataMap["metadata"].([]interface{})) != 0 { + variableMetaData := resourceIBMSchematicsJobMapToCredentialVariableMetadata(variableDataMap["metadata"].([]interface{})[0].(map[string]interface{})) + variableData.Metadata = &variableMetaData + } + if variableDataMap["link"] != nil { + variableData.Link = core.StringPtr(variableDataMap["link"].(string)) + } + + return variableData +} + +func resourceIBMSchematicsActionMapToVariableMetadata(variableMetadataMap map[string]interface{}) schematicsv1.VariableMetadata { + variableMetadata := schematicsv1.VariableMetadata{} + + if variableMetadataMap["type"] != nil { + variableMetadata.Type = core.StringPtr(variableMetadataMap["type"].(string)) + } + if variableMetadataMap["aliases"] != nil { + aliases := []string{} + for _, aliasesItem := range variableMetadataMap["aliases"].([]interface{}) { + aliases = append(aliases, aliasesItem.(string)) + } + variableMetadata.Aliases = aliases + } + if variableMetadataMap["description"] != nil { + variableMetadata.Description = core.StringPtr(variableMetadataMap["description"].(string)) + } + if variableMetadataMap["default_value"] != nil { + variableMetadata.DefaultValue = core.StringPtr(variableMetadataMap["default_value"].(string)) + } + if variableMetadataMap["secure"] != nil { + variableMetadata.Secure = core.BoolPtr(variableMetadataMap["secure"].(bool)) + } + if variableMetadataMap["immutable"] != nil { + variableMetadata.Immutable = core.BoolPtr(variableMetadataMap["immutable"].(bool)) + } + if variableMetadataMap["hidden"] != nil { + variableMetadata.Hidden = core.BoolPtr(variableMetadataMap["hidden"].(bool)) + } + if variableMetadataMap["options"] != nil { + options := []string{} + for _, optionsItem := range variableMetadataMap["options"].([]interface{}) { + options = append(options, optionsItem.(string)) + } + variableMetadata.Options = options + } + if variableMetadataMap["min_value"] != nil { + variableMetadata.MinValue = core.Int64Ptr(int64(variableMetadataMap["min_value"].(int))) + } + if variableMetadataMap["max_value"] != nil { + variableMetadata.MaxValue = core.Int64Ptr(int64(variableMetadataMap["max_value"].(int))) + } + if variableMetadataMap["min_length"] != nil { + variableMetadata.MinLength = core.Int64Ptr(int64(variableMetadataMap["min_length"].(int))) + } + if variableMetadataMap["max_length"] != nil { + variableMetadata.MaxLength = core.Int64Ptr(int64(variableMetadataMap["max_length"].(int))) + } + if variableMetadataMap["matches"] != nil { + variableMetadata.Matches = core.StringPtr(variableMetadataMap["matches"].(string)) + } + if variableMetadataMap["position"] != nil { + variableMetadata.Position = core.Int64Ptr(int64(variableMetadataMap["position"].(int))) + } + if variableMetadataMap["group_by"] != nil { + variableMetadata.GroupBy = core.StringPtr(variableMetadataMap["group_by"].(string)) + } + if variableMetadataMap["source"] != nil { + variableMetadata.Source = core.StringPtr(variableMetadataMap["source"].(string)) + } + + return variableMetadata +} + +func resourceIBMSchematicsActionMapToBastionResourceDefinition(bastionResourceDefinitionMap map[string]interface{}) schematicsv1.BastionResourceDefinition { + bastionResourceDefinition := schematicsv1.BastionResourceDefinition{} + + if bastionResourceDefinitionMap["name"] != nil { + bastionResourceDefinition.Name = core.StringPtr(bastionResourceDefinitionMap["name"].(string)) + } + if bastionResourceDefinitionMap["host"] != nil { + bastionResourceDefinition.Host = core.StringPtr(bastionResourceDefinitionMap["host"].(string)) + } + + return bastionResourceDefinition +} + +func resourceIBMSchematicsActionMapToActionState(actionStateMap map[string]interface{}) schematicsv1.ActionState { + actionState := schematicsv1.ActionState{} + + if actionStateMap["status_code"] != nil { + actionState.StatusCode = core.StringPtr(actionStateMap["status_code"].(string)) + } + if actionStateMap["status_job_id"] != nil { + actionState.StatusJobID = core.StringPtr(actionStateMap["status_job_id"].(string)) + } + if actionStateMap["status_message"] != nil { + actionState.StatusMessage = core.StringPtr(actionStateMap["status_message"].(string)) + } + + return actionState +} + +func resourceIBMSchematicsActionMapToSystemLock(systemLockMap map[string]interface{}) schematicsv1.SystemLock { + systemLock := schematicsv1.SystemLock{} + + if systemLockMap["sys_locked"] != nil { + systemLock.SysLocked = core.BoolPtr(systemLockMap["sys_locked"].(bool)) + } + if systemLockMap["sys_locked_by"] != nil { + systemLock.SysLockedBy = core.StringPtr(systemLockMap["sys_locked_by"].(string)) + } + if systemLockMap["sys_locked_at"] != nil { + + } + + return systemLock +} + +func resourceIBMSchematicsActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + getActionOptions := &schematicsv1.GetActionOptions{} + + getActionOptions.SetActionID(d.Id()) + + action, response, err := schematicsClient.GetActionWithContext(context, getActionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetActionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetActionWithContext failed %s\n%s", err, response)) + } + if err = d.Set("name", action.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", action.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", action.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("resource_group", action.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if action.Tags != nil { + if err = d.Set("tags", action.Tags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting tags: %s", err)) + } + } + if action.UserState != nil { + userStateMap := resourceIBMSchematicsActionUserStateToMap(*action.UserState) + if err = d.Set("user_state", []map[string]interface{}{userStateMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting user_state: %s", err)) + } + } + if err = d.Set("source_readme_url", action.SourceReadmeURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_readme_url: %s", err)) + } + if _, ok := d.GetOk("source"); ok { + if action.Source != nil { + sourceMap := resourceIBMSchematicsActionExternalSourceToMap(*action.Source) + if err = d.Set("source", []map[string]interface{}{sourceMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source: %s", err)) + } + } + } + if err = d.Set("source_type", action.SourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_type: %s", err)) + } + if err = d.Set("command_parameter", action.CommandParameter); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_parameter: %s", err)) + } + if err = d.Set("inventory", action.Inventory); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting inventory: %s", err)) + } + if action.Credentials != nil { + credentials := []map[string]interface{}{} + for _, credentialsItem := range action.Credentials { + credentialsItemMap := resourceIBMSchematicsActionCredentialVariableDataToMap(credentialsItem) + credentials = append(credentials, credentialsItemMap) + } + if err = d.Set("credentials", credentials); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting credentials: %s", err)) + } + } + if _, ok := d.GetOk("bastion"); ok { + if action.Bastion != nil { + bastionMap := resourceIBMSchematicsActionBastionResourceDefinitionToMap(*action.Bastion) + if err = d.Set("bastion", []map[string]interface{}{bastionMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion: %s", err)) + } + } + } + if action.BastionCredential != nil { + bastionCredentialMap := resourceIBMSchematicsActionCredentialVariableDataToMap(*action.BastionCredential) + if err = d.Set("bastion_credential", []map[string]interface{}{bastionCredentialMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion_credential: %s", err)) + } + } + if err = d.Set("targets_ini", action.TargetsIni); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting targets_ini: %s", err)) + } + if action.Inputs != nil { + actionInputs := []map[string]interface{}{} + for _, actionInputsItem := range action.Inputs { + actionInputsItemMap := resourceIBMSchematicsActionVariableDataToMap(actionInputsItem) + actionInputs = append(actionInputs, actionInputsItemMap) + } + if err = d.Set("action_inputs", actionInputs); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action_inputs: %s", err)) + } + } + if action.Outputs != nil { + actionOutputs := []map[string]interface{}{} + for _, actionOutputsItem := range action.Outputs { + actionOutputsItemMap := resourceIBMSchematicsActionVariableDataToMap(actionOutputsItem) + actionOutputs = append(actionOutputs, actionOutputsItemMap) + } + if err = d.Set("action_outputs", actionOutputs); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action_outputs: %s", err)) + } + } + if action.Settings != nil { + settings := []map[string]interface{}{} + for _, settingsItem := range action.Settings { + settingsItemMap := resourceIBMSchematicsActionVariableDataToMap(settingsItem) + settings = append(settings, settingsItemMap) + } + if err = d.Set("settings", settings); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting settings: %s", err)) + } + } + if action.State != nil { + stateMap := resourceIBMSchematicsActionActionStateToMap(*action.State) + if err = d.Set("state", []map[string]interface{}{stateMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) + } + } + if action.SysLock != nil { + sysLockMap := resourceIBMSchematicsActionSystemLockToMap(*action.SysLock) + if err = d.Set("sys_lock", []map[string]interface{}{sysLockMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting sys_lock: %s", err)) + } + } + if err = d.Set("crn", action.Crn); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("account", action.Account); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting account: %s", err)) + } + if err = d.Set("source_created_at", flex.DateTimeToString(action.SourceCreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_created_at: %s", err)) + } + if err = d.Set("source_created_by", action.SourceCreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_created_by: %s", err)) + } + if err = d.Set("source_updated_at", flex.DateTimeToString(action.SourceUpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_updated_at: %s", err)) + } + if err = d.Set("source_updated_by", action.SourceUpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting source_updated_by: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(action.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", action.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(action.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", action.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + if action.PlaybookNames != nil && len(action.PlaybookNames) > 0 { + if err = d.Set("playbook_names", action.PlaybookNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting playbook_names: %s", err)) + } + } else { + d.Set("playbook_names", []string{}) + } + + return nil +} + +func resourceIBMSchematicsActionUserStateToMap(userState schematicsv1.UserState) map[string]interface{} { + userStateMap := map[string]interface{}{} + + if userState.State != nil { + userStateMap["state"] = userState.State + } + if userState.SetBy != nil { + userStateMap["set_by"] = userState.SetBy + } + if userState.SetAt != nil { + userStateMap["set_at"] = userState.SetAt.String() + } + + return userStateMap +} + +func resourceIBMSchematicsActionExternalSourceToMap(externalSource schematicsv1.ExternalSource) map[string]interface{} { + externalSourceMap := map[string]interface{}{} + + externalSourceMap["source_type"] = externalSource.SourceType + if externalSource.Git != nil { + GitMap := resourceIBMSchematicsActionExternalSourceGitToMap(*externalSource.Git) + externalSourceMap["git"] = []map[string]interface{}{GitMap} + } + if externalSource.Catalog != nil { + CatalogMap := resourceIBMSchematicsActionExternalSourceCatalogToMap(*externalSource.Catalog) + externalSourceMap["catalog"] = []map[string]interface{}{CatalogMap} + } + // if externalSource.CosBucket != nil { + // CosBucketMap := resourceIBMSchematicsActionExternalSourceCosBucketToMap(*externalSource.CosBucket) + // externalSourceMap["cos_bucket"] = []map[string]interface{}{CosBucketMap} + // } + + return externalSourceMap +} + +func resourceIBMSchematicsActionExternalSourceGitToMap(externalSourceGit schematicsv1.GitSource) map[string]interface{} { + externalSourceGitMap := map[string]interface{}{} + + if externalSourceGit.ComputedGitRepoURL != nil { + externalSourceGitMap["computed_git_repo_url"] = externalSourceGit.ComputedGitRepoURL + } + if externalSourceGit.GitRepoURL != nil { + externalSourceGitMap["git_repo_url"] = externalSourceGit.GitRepoURL + } + if externalSourceGit.GitToken != nil { + externalSourceGitMap["git_token"] = externalSourceGit.GitToken + } + if externalSourceGit.GitRepoFolder != nil { + externalSourceGitMap["git_repo_folder"] = externalSourceGit.GitRepoFolder + } + if externalSourceGit.GitRelease != nil { + externalSourceGitMap["git_release"] = externalSourceGit.GitRelease + } + if externalSourceGit.GitBranch != nil { + externalSourceGitMap["git_branch"] = externalSourceGit.GitBranch + } + + return externalSourceGitMap +} + +func resourceIBMSchematicsActionExternalSourceCatalogToMap(externalSourceCatalog schematicsv1.CatalogSource) map[string]interface{} { + externalSourceCatalogMap := map[string]interface{}{} + + if externalSourceCatalog.CatalogName != nil { + externalSourceCatalogMap["catalog_name"] = externalSourceCatalog.CatalogName + } + if externalSourceCatalog.OfferingName != nil { + externalSourceCatalogMap["offering_name"] = externalSourceCatalog.OfferingName + } + if externalSourceCatalog.OfferingVersion != nil { + externalSourceCatalogMap["offering_version"] = externalSourceCatalog.OfferingVersion + } + if externalSourceCatalog.OfferingKind != nil { + externalSourceCatalogMap["offering_kind"] = externalSourceCatalog.OfferingKind + } + if externalSourceCatalog.OfferingID != nil { + externalSourceCatalogMap["offering_id"] = externalSourceCatalog.OfferingID + } + if externalSourceCatalog.OfferingVersionID != nil { + externalSourceCatalogMap["offering_version_id"] = externalSourceCatalog.OfferingVersionID + } + if externalSourceCatalog.OfferingRepoURL != nil { + externalSourceCatalogMap["offering_repo_url"] = externalSourceCatalog.OfferingRepoURL + } + + return externalSourceCatalogMap +} + +// func resourceIBMSchematicsActionExternalSourceCosBucketToMap(externalSourceCosBucket schematicsv1.ExternalSourceCosBucket) map[string]interface{} { +// externalSourceCosBucketMap := map[string]interface{}{} + +// if externalSourceCosBucket.CosBucketURL != nil { +// externalSourceCosBucketMap["cos_bucket_url"] = externalSourceCosBucket.CosBucketURL +// } + +// return externalSourceCosBucketMap +// } + +func resourceIBMSchematicsActionVariableDataToMap(variableData schematicsv1.VariableData) map[string]interface{} { + variableDataMap := map[string]interface{}{} + + if variableData.Name != nil { + variableDataMap["name"] = variableData.Name + } + if variableData.Value != nil { + variableDataMap["value"] = variableData.Value + } + if variableData.Metadata != nil { + MetadataMap := resourceIBMSchematicsActionVariableMetadataToMap(*variableData.Metadata) + variableDataMap["metadata"] = []map[string]interface{}{MetadataMap} + } + if variableData.Link != nil { + variableDataMap["link"] = variableData.Link + } + + return variableDataMap +} +func resourceIBMSchematicsActionCredentialVariableDataToMap(variableData schematicsv1.CredentialVariableData) map[string]interface{} { + variableDataMap := map[string]interface{}{} + + if variableData.Name != nil { + variableDataMap["name"] = variableData.Name + } + if variableData.Value != nil { + variableDataMap["value"] = variableData.Value + } + if variableData.Metadata != nil { + MetadataMap := resourceIBMSchematicsActionCredentialVariableMetadataToMap(*variableData.Metadata) + variableDataMap["metadata"] = []map[string]interface{}{MetadataMap} + } + if variableData.Link != nil { + variableDataMap["link"] = variableData.Link + } + + return variableDataMap +} + +func resourceIBMSchematicsActionCredentialVariableMetadataToMap(variableMetadata schematicsv1.CredentialVariableMetadata) map[string]interface{} { + variableMetadataMap := map[string]interface{}{} + + if variableMetadata.Type != nil { + variableMetadataMap["type"] = variableMetadata.Type + } + if variableMetadata.Aliases != nil { + variableMetadataMap["aliases"] = variableMetadata.Aliases + } + if variableMetadata.Description != nil { + variableMetadataMap["description"] = variableMetadata.Description + } + if variableMetadata.DefaultValue != nil { + variableMetadataMap["default_value"] = variableMetadata.DefaultValue + } + if variableMetadata.Immutable != nil { + variableMetadataMap["immutable"] = variableMetadata.Immutable + } + if variableMetadata.Hidden != nil { + variableMetadataMap["hidden"] = variableMetadata.Hidden + } + if variableMetadata.Position != nil { + variableMetadataMap["position"] = flex.IntValue(variableMetadata.Position) + } + if variableMetadata.GroupBy != nil { + variableMetadataMap["group_by"] = variableMetadata.GroupBy + } + if variableMetadata.Source != nil { + variableMetadataMap["source"] = variableMetadata.Source + } + + return variableMetadataMap +} +func resourceIBMSchematicsActionVariableMetadataToMap(variableMetadata schematicsv1.VariableMetadata) map[string]interface{} { + variableMetadataMap := map[string]interface{}{} + + if variableMetadata.Type != nil { + variableMetadataMap["type"] = variableMetadata.Type + } + if variableMetadata.Aliases != nil { + variableMetadataMap["aliases"] = variableMetadata.Aliases + } + if variableMetadata.Description != nil { + variableMetadataMap["description"] = variableMetadata.Description + } + if variableMetadata.DefaultValue != nil { + variableMetadataMap["default_value"] = variableMetadata.DefaultValue + } + if variableMetadata.Secure != nil { + variableMetadataMap["secure"] = variableMetadata.Secure + } + if variableMetadata.Immutable != nil { + variableMetadataMap["immutable"] = variableMetadata.Immutable + } + if variableMetadata.Hidden != nil { + variableMetadataMap["hidden"] = variableMetadata.Hidden + } + if variableMetadata.Options != nil { + variableMetadataMap["options"] = variableMetadata.Options + } + if variableMetadata.MinValue != nil { + variableMetadataMap["min_value"] = flex.IntValue(variableMetadata.MinValue) + } + if variableMetadata.MaxValue != nil { + variableMetadataMap["max_value"] = flex.IntValue(variableMetadata.MaxValue) + } + if variableMetadata.MinLength != nil { + variableMetadataMap["min_length"] = flex.IntValue(variableMetadata.MinLength) + } + if variableMetadata.MaxLength != nil { + variableMetadataMap["max_length"] = flex.IntValue(variableMetadata.MaxLength) + } + if variableMetadata.Matches != nil { + variableMetadataMap["matches"] = variableMetadata.Matches + } + if variableMetadata.Position != nil { + variableMetadataMap["position"] = flex.IntValue(variableMetadata.Position) + } + if variableMetadata.GroupBy != nil { + variableMetadataMap["group_by"] = variableMetadata.GroupBy + } + if variableMetadata.Source != nil { + variableMetadataMap["source"] = variableMetadata.Source + } + + return variableMetadataMap +} + +func resourceIBMSchematicsActionBastionResourceDefinitionToMap(bastionResourceDefinition schematicsv1.BastionResourceDefinition) map[string]interface{} { + bastionResourceDefinitionMap := map[string]interface{}{} + + if bastionResourceDefinition.Name != nil { + bastionResourceDefinitionMap["name"] = bastionResourceDefinition.Name + } + if bastionResourceDefinition.Host != nil { + bastionResourceDefinitionMap["host"] = bastionResourceDefinition.Host + } + + return bastionResourceDefinitionMap +} + +func resourceIBMSchematicsActionActionStateToMap(actionState schematicsv1.ActionState) map[string]interface{} { + actionStateMap := map[string]interface{}{} + + if actionState.StatusCode != nil { + actionStateMap["status_code"] = actionState.StatusCode + } + if actionState.StatusJobID != nil { + actionStateMap["status_job_id"] = actionState.StatusJobID + } + if actionState.StatusMessage != nil { + actionStateMap["status_message"] = actionState.StatusMessage + } + + return actionStateMap +} + +func resourceIBMSchematicsActionSystemLockToMap(systemLock schematicsv1.SystemLock) map[string]interface{} { + systemLockMap := map[string]interface{}{} + + if systemLock.SysLocked != nil { + systemLockMap["sys_locked"] = systemLock.SysLocked + } + if systemLock.SysLockedBy != nil { + systemLockMap["sys_locked_by"] = systemLock.SysLockedBy + } + if systemLock.SysLockedAt != nil { + systemLockMap["sys_locked_at"] = systemLock.SysLockedAt.String() + } + + return systemLockMap +} + +func resourceIBMSchematicsActionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + + updateActionOptions := &schematicsv1.UpdateActionOptions{} + + updateActionOptions.SetActionID(d.Id()) + + hasChange := false + + if d.HasChange("name") { + updateActionOptions.SetName(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("description") { + updateActionOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + if d.HasChange("location") { + updateActionOptions.SetLocation(d.Get("location").(string)) + hasChange = true + } + if d.HasChange("resource_group") { + updateActionOptions.SetResourceGroup(d.Get("resource_group").(string)) + hasChange = true + } + if d.HasChange("tags") { + updateActionOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + hasChange = true + } + if d.HasChange("user_state") { + userStateAttr := d.Get("user_state").([]interface{}) + if len(userStateAttr) > 0 { + userState := resourceIBMSchematicsActionMapToUserState(d.Get("user_state.0").(map[string]interface{})) + updateActionOptions.SetUserState(&userState) + hasChange = true + } + } + if d.HasChange("source_readme_url") { + updateActionOptions.SetSourceReadmeURL(d.Get("source_readme_url").(string)) + hasChange = true + } + if d.HasChange("source") { + sourceAttr := d.Get("source").([]interface{}) + if len(sourceAttr) > 0 { + source := resourceIBMSchematicsActionMapToExternalSource(d.Get("source.0").(map[string]interface{})) + updateActionOptions.SetSource(&source) + hasChange = true + } + } + if d.HasChange("source_type") { + updateActionOptions.SetSourceType(d.Get("source_type").(string)) + hasChange = true + } + if d.HasChange("command_parameter") { + updateActionOptions.SetCommandParameter(d.Get("command_parameter").(string)) + hasChange = true + } + if d.HasChange("inventory") { + updateActionOptions.SetInventory(d.Get("inventory").(string)) + hasChange = true + } + if d.HasChange("credentials") { + // TODO: handle Credentials of type TypeList -- not primitive, not model + hasChange = true + } + if d.HasChange("bastion") { + bastionAttr := d.Get("bastion").([]interface{}) + if len(bastionAttr) > 0 { + bastion := resourceIBMSchematicsActionMapToBastionResourceDefinition(d.Get("bastion.0").(map[string]interface{})) + updateActionOptions.SetBastion(&bastion) + hasChange = true + } + } + if d.HasChange("inventory") { + updateActionOptions.SetInventory(d.Get("inventory").(string)) + hasChange = true + } + if d.HasChange("bastion_credential") { + bastionCredential := resourceIBMSchematicsActionMapToCredentialsVariableData(d.Get("bastion_credential.0").(map[string]interface{})) + updateActionOptions.SetBastionCredential(&bastionCredential) + hasChange = true + } + if d.HasChange("targets_ini") { + updateActionOptions.SetTargetsIni(d.Get("targets_ini").(string)) + hasChange = true + } + if d.HasChange("action_inputs") { + var inputs []schematicsv1.VariableData + for _, e := range d.Get("action_inputs").([]interface{}) { + value := e.(map[string]interface{}) + inputsItem := resourceIBMSchematicsActionMapToVariableData(value) + inputs = append(inputs, inputsItem) + } + updateActionOptions.SetInputs(inputs) + hasChange = true + } + if d.HasChange("action_outputs") { + var outputs []schematicsv1.VariableData + for _, e := range d.Get("action_outputs").([]interface{}) { + value := e.(map[string]interface{}) + outputsItem := resourceIBMSchematicsActionMapToVariableData(value) + outputs = append(outputs, outputsItem) + } + updateActionOptions.SetOutputs(outputs) + hasChange = true + } + if d.HasChange("settings") { + var settings []schematicsv1.VariableData + for _, e := range d.Get("settings").([]interface{}) { + value := e.(map[string]interface{}) + settingsItem := resourceIBMSchematicsActionMapToVariableData(value) + settings = append(settings, settingsItem) + } + updateActionOptions.SetSettings(settings) + hasChange = true + } + if d.HasChange("state") { + stateAttr := d.Get("state").([]interface{}) + if len(stateAttr) > 0 { + state := resourceIBMSchematicsActionMapToActionState(d.Get("state.0").(map[string]interface{})) + updateActionOptions.SetState(&state) + hasChange = true + } + } + if d.HasChange("sys_lock") { + sysLockAttr := d.Get("sys_lock").([]interface{}) + if len(sysLockAttr) > 0 { + sysLock := resourceIBMSchematicsActionMapToSystemLock(d.Get("sys_lock.0").(map[string]interface{})) + updateActionOptions.SetSysLock(&sysLock) + hasChange = true + } + } + + if hasChange { + _, response, err := schematicsClient.UpdateActionWithContext(context, updateActionOptions) + if err != nil { + log.Printf("[DEBUG] UpdateActionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateActionWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSchematicsActionRead(context, d, meta) +} + +func resourceIBMSchematicsActionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + deleteActionOptions := &schematicsv1.DeleteActionOptions{} + + deleteActionOptions.SetActionID(d.Id()) + + response, err := schematicsClient.DeleteActionWithContext(context, deleteActionOptions) + if err != nil { + log.Printf("[DEBUG] DeleteActionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteActionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/resource_ibm_schematics_action_test.go b/ibm/service/schematics/resource_ibm_schematics_action_test.go similarity index 86% rename from ibm/resource_ibm_schematics_action_test.go rename to ibm/service/schematics/resource_ibm_schematics_action_test.go index e33d156df..94e50fa58 100644 --- a/ibm/resource_ibm_schematics_action_test.go +++ b/ibm/service/schematics/resource_ibm_schematics_action_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,11 +23,11 @@ func TestAccIBMSchematicsActionBasic(t *testing.T) { description := fmt.Sprintf("acc-test-schematics-action_description_%s", acctest.RandString(10)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSchematicsActionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSchematicsActionConfigBasic(actionName, description), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSchematicsActionExists("ibm_schematics_action.schematics_action", conf), @@ -66,7 +69,7 @@ func testAccCheckIBMSchematicsActionExists(n string, obj schematicsv1.Action) re return fmt.Errorf("Not found: %s", n) } - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() if err != nil { return err } @@ -87,7 +90,7 @@ func testAccCheckIBMSchematicsActionExists(n string, obj schematicsv1.Action) re } func testAccCheckIBMSchematicsActionDestroy(s *terraform.State) error { - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() if err != nil { return err } @@ -106,7 +109,7 @@ func testAccCheckIBMSchematicsActionDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("schematics_action still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for schematics_action (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for schematics_action (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/schematics/resource_ibm_schematics_inventory.go b/ibm/service/schematics/resource_ibm_schematics_inventory.go new file mode 100644 index 000000000..77b7e7063 --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_inventory.go @@ -0,0 +1,300 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func ResourceIBMSchematicsInventory() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSchematicsInventoryCreate, + ReadContext: resourceIBMSchematicsInventoryRead, + UpdateContext: resourceIBMSchematicsInventoryUpdate, + DeleteContext: resourceIBMSchematicsInventoryDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_inventory", "name"), + Description: "The unique name of your Inventory definition. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of your Inventory definition. The description can be up to 2048 characters long in size.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_inventory", "location"), + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "Resource-group name for the Inventory definition. By default, Inventory definition will be created in Default Resource Group.", + }, + "inventories_ini": { + Type: schema.TypeString, + Optional: true, + Description: "Input inventory of host and host group for the playbook, in the `.ini` file format.", + }, + "resource_queries": { + Type: schema.TypeList, + Optional: true, + Description: "Input resource query definitions that is used to dynamically generate the inventory of host and host group for the playbook.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who created the Inventory.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Inventory updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who updated the Inventory.", + }, + }, + } +} + +func ResourceIBMSchematicsInventoryValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + Optional: true, + MinValueLength: 3, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "eu-de, eu-gb, us-east, us-south", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_schematics_inventory", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSchematicsInventoryCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + createInventoryOptions := &schematicsv1.CreateInventoryOptions{} + + if _, ok := d.GetOk("name"); ok { + createInventoryOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("description"); ok { + createInventoryOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("location"); ok { + createInventoryOptions.SetLocation(d.Get("location").(string)) + } + if _, ok := d.GetOk("resource_group"); ok { + createInventoryOptions.SetResourceGroup(d.Get("resource_group").(string)) + } + if _, ok := d.GetOk("inventories_ini"); ok { + createInventoryOptions.SetInventoriesIni(d.Get("inventories_ini").(string)) + } + if _, ok := d.GetOk("resource_queries"); ok { + createInventoryOptions.SetResourceQueries(flex.ExpandStringList(d.Get("resource_queries").([]interface{}))) + } + + inventoryResourceRecord, response, err := schematicsClient.CreateInventoryWithContext(context, createInventoryOptions) + if err != nil { + log.Printf("[DEBUG] CreateInventoryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateInventoryWithContext failed %s\n%s", err, response)) + } + + d.SetId(*inventoryResourceRecord.ID) + + return resourceIBMSchematicsInventoryRead(context, d, meta) +} + +func resourceIBMSchematicsInventoryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + inventoryIDSplit := strings.Split(d.Id(), ".") + region := inventoryIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + + getInventoryOptions := &schematicsv1.GetInventoryOptions{} + + getInventoryOptions.SetInventoryID(d.Id()) + + inventoryResourceRecord, response, err := schematicsClient.GetInventoryWithContext(context, getInventoryOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetInventoryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInventoryWithContext failed %s\n%s", err, response)) + } + if err = d.Set("name", inventoryResourceRecord.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", inventoryResourceRecord.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", inventoryResourceRecord.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("resource_group", inventoryResourceRecord.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if err = d.Set("inventories_ini", inventoryResourceRecord.InventoriesIni); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting inventories_ini: %s", err)) + } + if inventoryResourceRecord.ResourceQueries != nil { + if err = d.Set("resource_queries", inventoryResourceRecord.ResourceQueries); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_queries: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(inventoryResourceRecord.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", inventoryResourceRecord.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(inventoryResourceRecord.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", inventoryResourceRecord.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + + return nil +} + +func resourceIBMSchematicsInventoryUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + + inventoryIDSplit := strings.Split(d.Id(), ".") + region := inventoryIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + updateInventoryOptions := &schematicsv1.ReplaceInventoryOptions{} + + updateInventoryOptions.SetInventoryID(d.Id()) + + hasChange := false + + if d.HasChange("name") { + updateInventoryOptions.SetName(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("description") { + updateInventoryOptions.SetDescription(d.Get("description").(string)) + hasChange = true + } + if d.HasChange("location") { + updateInventoryOptions.SetLocation(d.Get("location").(string)) + hasChange = true + } + if d.HasChange("resource_group") { + updateInventoryOptions.SetResourceGroup(d.Get("resource_group").(string)) + hasChange = true + } + if d.HasChange("inventories_ini") { + updateInventoryOptions.SetInventoriesIni(d.Get("inventories_ini").(string)) + hasChange = true + } + if d.HasChange("resource_queries") { + resourceQueriesAttr := d.Get("resource_queries").([]string) + if len(resourceQueriesAttr) > 0 { + resourceQueries := d.Get("resource_queries").([]string) + updateInventoryOptions.SetResourceQueries(resourceQueries) + } + + hasChange = true + } + + if hasChange { + _, response, err := schematicsClient.ReplaceInventoryWithContext(context, updateInventoryOptions) + if err != nil { + log.Printf("[DEBUG] UpdateInventoryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateInventoryWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMSchematicsInventoryRead(context, d, meta) +} + +func resourceIBMSchematicsInventoryDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + inventoryIDSplit := strings.Split(d.Id(), ".") + region := inventoryIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + deleteInventoryOptions := &schematicsv1.DeleteInventoryOptions{} + + deleteInventoryOptions.SetInventoryID(d.Id()) + + response, err := schematicsClient.DeleteInventoryWithContext(context, deleteInventoryOptions) + if err != nil { + log.Printf("[DEBUG] DeleteInventoryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteInventoryWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/schematics/resource_ibm_schematics_inventory_test.go b/ibm/service/schematics/resource_ibm_schematics_inventory_test.go new file mode 100644 index 000000000..0f2f45495 --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_inventory_test.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func TestAccIBMSchematicsInventoryBasic(t *testing.T) { + var conf schematicsv1.InventoryResourceRecord + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsInventoryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsInventoryConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsInventoryExists("ibm_schematics_inventory.schematics_inventory", conf), + ), + }, + }, + }) +} +func TestAccIBMSchematicsInventoryAllArgs(t *testing.T) { + var conf schematicsv1.InventoryResourceRecord + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + location := "us-south" + resourceGroup := "" + inventoriesIni := fmt.Sprintf("tf_inventories_ini_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + locationUpdate := location + resourceGroupUpdate := resourceGroup + inventoriesIniUpdate := fmt.Sprintf("tf_inventories_ini_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsInventoryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsInventoryConfig(name, description, location, resourceGroup, inventoriesIni), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsInventoryExists("ibm_schematics_inventory.schematics_inventory", conf), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "name", name), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "description", description), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "location", location), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "resource_group", resourceGroup), + ), + }, + { + Config: testAccCheckIBMSchematicsInventoryConfig(nameUpdate, descriptionUpdate, locationUpdate, resourceGroupUpdate, inventoriesIniUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "location", locationUpdate), + resource.TestCheckResourceAttr("ibm_schematics_inventory.schematics_inventory", "resource_group", resourceGroupUpdate), + ), + }, + { + ResourceName: "ibm_schematics_inventory.schematics_inventory", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSchematicsInventoryConfigBasic() string { + return ` + + resource "ibm_schematics_inventory" "schematics_inventory" { + name = "test_inventory" + location = "us-south" + } + ` +} + +func testAccCheckIBMSchematicsInventoryConfig(name string, description string, location string, resourceGroup string, inventoriesIni string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_inventory" "schematics_inventory" { + name = "%s" + description = "%s" + location = "us-south" + } + `, name, description) +} + +func testAccCheckIBMSchematicsInventoryExists(n string, obj schematicsv1.InventoryResourceRecord) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + + getInventoryOptions := &schematicsv1.GetInventoryOptions{} + + getInventoryOptions.SetInventoryID(rs.Primary.ID) + + inventoryResourceRecord, _, err := schematicsClient.GetInventory(getInventoryOptions) + if err != nil { + return err + } + + obj = *inventoryResourceRecord + return nil + } +} + +func testAccCheckIBMSchematicsInventoryDestroy(s *terraform.State) error { + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_schematics_inventory" { + continue + } + + getInventoryOptions := &schematicsv1.GetInventoryOptions{} + + getInventoryOptions.SetInventoryID(rs.Primary.ID) + + // Try to find the key + _, response, err := schematicsClient.GetInventory(getInventoryOptions) + + if err == nil { + return fmt.Errorf("schematics_inventory still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for schematics_inventory (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/schematics/resource_ibm_schematics_job.go b/ibm/service/schematics/resource_ibm_schematics_job.go new file mode 100644 index 000000000..4893b8b7a --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_job.go @@ -0,0 +1,5104 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func ResourceIBMSchematicsJob() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSchematicsJobCreate, + ReadContext: resourceIBMSchematicsJobRead, + UpdateContext: resourceIBMSchematicsJobUpdate, + DeleteContext: resourceIBMSchematicsJobDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "command_object": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_job", "command_object"), + Description: "Name of the Schematics automation resource.", + }, + "command_object_id": { + Type: schema.TypeString, + Required: true, + Description: "Job command object id (workspace-id, action-id).", + }, + "command_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_job", "command_name"), + Description: "Schematics job command name.", + }, + "command_parameter": { + Type: schema.TypeString, + Optional: true, + Description: "Schematics job command parameter (playbook-name).", + }, + "command_options": { + Type: schema.TypeList, + Optional: true, + Description: "Command line options for the command.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "job_inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Job inputs used by Action or Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "job_env_settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables used by the Job while performing Action or Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Description: "User defined tags, while running the job.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_job", "location"), + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "status": { + Type: schema.TypeList, + Computed: true, + Description: "Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_job_status": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Workspace Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_name": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace name.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace).", + }, + "flow_status": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Environment Flow JOB Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Optional: true, + Description: "flow id.", + }, + "flow_name": { + Type: schema.TypeString, + Optional: true, + Description: "flow name.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Flow Job status message - to be displayed along with the status_code;.", + }, + "workitems": { + Type: schema.TypeList, + Optional: true, + Description: "Environment's individual workItem status details;.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace id.", + }, + "workspace_name": { + Type: schema.TypeString, + Optional: true, + Description: "workspace name.", + }, + "job_id": { + Type: schema.TypeString, + Optional: true, + Description: "workspace job id.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "workitem job status message;.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "workitem job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "template_status": { + Type: schema.TypeList, + Optional: true, + Description: "Workspace Flow Template job status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Optional: true, + Description: "Template Id.", + }, + "template_name": { + Type: schema.TypeString, + Optional: true, + Description: "Template name.", + }, + "flow_index": { + Type: schema.TypeInt, + Optional: true, + Description: "Index of the template in the Flow.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template).", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "action_job_status": { + Type: schema.TypeList, + Optional: true, + Description: "Action Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_name": { + Type: schema.TypeString, + Optional: true, + Description: "Action name.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Action Job status message - to be displayed along with the action_status_code.", + }, + "bastion_status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Resources.", + }, + "bastion_status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Bastion status message - to be displayed along with the bastion_status_code;.", + }, + "targets_status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Resources.", + }, + "targets_status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Aggregated status message for all target resources, to be displayed along with the targets_status_code;.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "system_job_status": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "System Job Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "system_status_message": { + Type: schema.TypeString, + Optional: true, + Description: "System job message.", + }, + "system_status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "schematics_resource_status": { + Type: schema.TypeList, + Optional: true, + Description: "job staus for each schematics resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "system job status message.", + }, + "schematics_resource_id": { + Type: schema.TypeString, + Optional: true, + Description: "id for each resource which is targeted as a part of system job.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "flow_job_status": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Environment Flow JOB Status.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Optional: true, + Description: "flow id.", + }, + "flow_name": { + Type: schema.TypeString, + Optional: true, + Description: "flow name.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "Flow Job status message - to be displayed along with the status_code;.", + }, + "workitems": { + Type: schema.TypeList, + Optional: true, + Description: "Environment's individual workItem status details;.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace id.", + }, + "workspace_name": { + Type: schema.TypeString, + Optional: true, + Description: "workspace name.", + }, + "job_id": { + Type: schema.TypeString, + Optional: true, + Description: "workspace job id.", + }, + "status_code": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + "status_message": { + Type: schema.TypeString, + Optional: true, + Description: "workitem job status message;.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "workitem job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + }, + }, + }, + "data": { + Type: schema.TypeList, + Optional: true, + Description: "Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "job_type": { + Type: schema.TypeString, + Required: true, + Description: "Type of Job.", + }, + "workspace_job_data": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Workspace Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_name": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace name.", + }, + "flow_id": { + Type: schema.TypeString, + Optional: true, + Description: "Flow Id.", + }, + "flow_name": { + Type: schema.TypeString, + Optional: true, + Description: "Flow name.", + }, + "inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Input variables data used by the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Optional: true, + Description: "Output variables data from the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables used by all the templates in the Workspace.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "template_data": { + Type: schema.TypeList, + Optional: true, + Description: "Input / output data of the Template in the Workspace Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Optional: true, + Description: "Template Id.", + }, + "template_name": { + Type: schema.TypeString, + Optional: true, + Description: "Template name.", + }, + "flow_index": { + Type: schema.TypeInt, + Optional: true, + Description: "Index of the template in the Flow.", + }, + "inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Job inputs used by the Templates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Optional: true, + Description: "Job output from the Templates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables used by the template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "action_job_data": { + Type: schema.TypeList, + Optional: true, + Description: "Action Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_name": { + Type: schema.TypeString, + Optional: true, + Description: "Flow name.", + }, + "inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Input variables data used by the Action Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Optional: true, + Description: "Output variables data from the Action Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables used by all the templates in the Action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + "inventory_record": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Complete inventory resource details with user inputs and system generated data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + }, + "id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Inventory id.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of your Inventory. The description can be up to 2048 characters long in size.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + }, + "created_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Inventory creation time.", + }, + "created_by": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Email address of user who created the Inventory.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Inventory updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Email address of user who updated the Inventory.", + }, + "inventories_ini": { + Type: schema.TypeString, + Optional: true, + Description: "Input inventory of host and host group for the playbook, in the .ini file format.", + }, + "resource_queries": { + Type: schema.TypeList, + Optional: true, + Description: "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "materialized_inventory": { + Type: schema.TypeString, + Optional: true, + Description: "Materialized inventory details used by the Action Job, in .ini format.", + }, + }, + }, + }, + "system_job_data": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Controls Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_id": { + Type: schema.TypeString, + Optional: true, + Description: "Key ID for which key event is generated.", + }, + "schematics_resource_id": { + Type: schema.TypeList, + Optional: true, + Description: "List of the schematics resource id.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "flow_job_data": { + Type: schema.TypeList, + Optional: true, + Description: "Flow Job data.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_id": { + Type: schema.TypeString, + Optional: true, + Description: "Flow ID.", + }, + "flow_name": { + Type: schema.TypeString, + Optional: true, + Description: "Flow Name.", + }, + "workitems": { + Type: schema.TypeList, + Optional: true, + Description: "Job data used by each workitem Job.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command_object_id": { + Type: schema.TypeString, + Optional: true, + Description: "command object id.", + }, + "command_object_name": { + Type: schema.TypeString, + Optional: true, + Description: "command object name.", + }, + "layers": { + Type: schema.TypeString, + Optional: true, + Description: "layer name.", + }, + "source_type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of source for the Template.", + }, + "source": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Source of templates, playbooks, or controls.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_type": { + Type: schema.TypeString, + Required: true, + Description: "Type of source for the Template.", + }, + "git": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Connection details to Git source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "computed_git_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + }, + "git_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "URL to the GIT Repo that can be used to clone the template.", + }, + "git_token": { + Type: schema.TypeString, + Optional: true, + Description: "Personal Access Token to connect to Git URLs.", + }, + "git_repo_folder": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the folder in the Git Repo, that contains the template.", + }, + "git_release": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the release tag, used to fetch the Git Repo.", + }, + "git_branch": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the branch, used to fetch the Git Repo.", + }, + }, + }, + }, + "catalog": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Connection details to IBM Cloud Catalog source.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog_name": { + Type: schema.TypeString, + Optional: true, + Description: "name of the private catalog.", + }, + "offering_name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the offering in the IBM Catalog.", + }, + "offering_version": { + Type: schema.TypeString, + Optional: true, + Description: "Version string of the offering in the IBM Catalog.", + }, + "offering_kind": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the offering, in the IBM Catalog.", + }, + "offering_id": { + Type: schema.TypeString, + Optional: true, + Description: "Id of the offering the IBM Catalog.", + }, + "offering_version_id": { + Type: schema.TypeString, + Optional: true, + Description: "Id of the offering version the IBM Catalog.", + }, + "offering_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "Repo Url of the offering, in the IBM Catalog.", + }, + }, + }, + }, + // "cos_bucket": { + // Type: schema.TypeList, + // MaxItems: 1, + // Optional: true, + // Description: "Connection details to a IBM Cloud Object Storage bucket.", + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "cos_bucket_url": { + // Type: schema.TypeString, + // Optional: true, + // Description: "COS Bucket Url.", + // }, + // }, + // }, + // }, + }, + }, + }, + "inputs": { + Type: schema.TypeList, + Optional: true, + Description: "Input variables data for the workItem used in FlowJob.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "outputs": { + Type: schema.TypeList, + Optional: true, + Description: "Output variables for the workItem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "settings": { + Type: schema.TypeList, + Optional: true, + Description: "Environment variables for the workItem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value for the variable or reference to the value.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "User editable metadata for the variables.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the variable.", + }, + "aliases": { + Type: schema.TypeList, + Optional: true, + Description: "List of aliases for the variable name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the meta data.", + }, + "default_value": { + Type: schema.TypeString, + Optional: true, + Description: "Default value for the variable, if the override value is not specified.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable secure or sensitive ?.", + }, + "immutable": { + Type: schema.TypeBool, + Optional: true, + Description: "Is the variable readonly ?.", + }, + "hidden": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, the variable will not be displayed on UI or CLI.", + }, + "options": { + Type: schema.TypeList, + Optional: true, + Description: "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "min_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum value of the variable. Applicable for integer type.", + }, + "max_value": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum value of the variable. Applicable for integer type.", + }, + "min_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum length of the variable value. Applicable for string type.", + }, + "max_length": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum length of the variable value. Applicable for string type.", + }, + "matches": { + Type: schema.TypeString, + Optional: true, + Description: "Regex for the variable value.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Relative position of this variable in a list.", + }, + "group_by": { + Type: schema.TypeString, + Optional: true, + Description: "Display name of the group this variable belongs to.", + }, + "source": { + Type: schema.TypeString, + Optional: true, + Description: "Source of this meta-data.", + }, + }, + }, + }, + "link": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Reference link to the variable value By default the expression will point to self.value.", + }, + }, + }, + }, + "last_job": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Status of the last job executed by the workitem.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command_object": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the Schematics automation resource.", + }, + "command_object_name": { + Type: schema.TypeString, + Optional: true, + Description: "command object name (workspace_name/action_name).", + }, + "command_object_id": { + Type: schema.TypeString, + Optional: true, + Description: "Workitem command object id, maps to workspace_id or action_id.", + }, + "command_name": { + Type: schema.TypeString, + Optional: true, + Description: "Schematics job command name.", + }, + "job_id": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace job id.", + }, + "job_status": { + Type: schema.TypeString, + Optional: true, + Description: "Status of Jobs.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Description: "Job status updation timestamp.", + }, + }, + }, + }, + }, + }, + }, + "bastion": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Describes a bastion resource.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Bastion Name(Unique).", + }, + "host": { + Type: schema.TypeString, + Optional: true, + Description: "Reference to the Inventory resource definition.", + }, + }, + }, + }, + "log_summary": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "Job log summary record.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "job_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Workspace Id.", + }, + "job_type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of Job.", + }, + "log_start_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Job log start timestamp.", + }, + "log_analyzed_till": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Job log update timestamp.", + }, + "elapsed_time": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Job log elapsed time (log_analyzed_till - log_start_at).", + }, + "log_errors": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "Job log errors.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "error_code": { + Type: schema.TypeString, + Optional: true, + Description: "Error code in the Log.", + }, + "error_msg": { + Type: schema.TypeString, + Optional: true, + Description: "Summary error message in the log.", + }, + "error_count": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of occurrence.", + }, + }, + }, + }, + "repo_download_job": { + Type: schema.TypeList, + Optional: true, + Description: "Repo download Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "scanned_file_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of files scanned.", + }, + "quarantined_file_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of files quarantined.", + }, + "detected_filetype": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Detected template or data file type.", + }, + "inputs_count": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Number of inputs detected.", + }, + "outputs_count": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Number of outputs detected.", + }, + }, + }, + }, + "workspace_job": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Workspace Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resources_add": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources add.", + }, + "resources_modify": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources modify.", + }, + "resources_destroy": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources destroy.", + }, + }, + }, + }, + "flow_job": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Flow Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workitems_completed": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of workitems completed successfully.", + }, + "workitems_pending": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of workitems pending in the flow.", + }, + "workitems_failed": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of workitems failed.", + }, + "workitems": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "workspace_id": { + Type: schema.TypeString, + Optional: true, + Description: "workspace ID.", + }, + "job_id": { + Type: schema.TypeString, + Optional: true, + Description: "workspace JOB ID.", + }, + "resources_add": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources add.", + }, + "resources_modify": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources modify.", + }, + "resources_destroy": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Number of resources destroy.", + }, + "log_url": { + Type: schema.TypeString, + Optional: true, + Description: "Log url for job.", + }, + }, + }, + }, + }, + }, + }, + "action_job": { + Type: schema.TypeList, + Optional: true, + Description: "Flow Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "number of targets or hosts.", + }, + "task_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "number of tasks in playbook.", + }, + "play_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "number of plays in playbook.", + }, + "recap": { + Type: schema.TypeList, + Optional: true, + Description: "Recap records.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target": { + Type: schema.TypeList, + Optional: true, + Description: "List of target or host name.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "ok": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of OK.", + }, + "changed": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of changed.", + }, + "failed": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of failed.", + }, + "skipped": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of skipped.", + }, + "unreachable": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of unreachable.", + }, + }, + }, + }, + }, + }, + }, + "system_job": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "System Job log summary.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_count": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "number of targets or hosts.", + }, + "success": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of passed.", + }, + "failed": { + Type: schema.TypeFloat, + Optional: true, + Description: "Number of failed.", + }, + }, + }, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Job name, uniquely derived from the related Workspace or Action.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource-group name derived from the related Workspace or Action.", + }, + "submitted_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job submission time.", + }, + "submitted_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who submitted the job.", + }, + "start_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job start time.", + }, + "end_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job end time.", + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: "Duration of job execution; example 40 sec.", + }, + "log_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job log store URL.", + }, + "state_store_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job state store URL.", + }, + "results_url": { + Type: schema.TypeString, + Computed: true, + Description: "Job results store URL.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Job status updation timestamp.", + }, + }, + } +} + +func ResourceIBMSchematicsJobValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "command_object", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "action, environment, system, workspace", + }, + validate.ValidateSchema{ + Identifier: "command_name", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "ansible_playbook_check, ansible_playbook_run, create_action, create_cart, create_environment, create_workspace, delete_action, delete_environment, delete_workspace, environment_init, environment_install, environment_uninstall, patch_action, patch_workspace, put_action, put_environment, put_workspace, repository_process, system_key_delete, system_key_disable, system_key_enable, system_key_restore, system_key_rotate, workspace_apply, workspace_destroy, workspace_plan, workspace_refresh", + }, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "eu-de, eu-gb, us-east, us-south", + }) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_schematics_job", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSchematicsJobCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + + session, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + + iamRefreshToken := session.Config.IAMRefreshToken + + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + createJobOptions := &schematicsv1.CreateJobOptions{} + createJobOptions.SetRefreshToken(iamRefreshToken) + + if _, ok := d.GetOk("command_object"); ok { + createJobOptions.SetCommandObject(d.Get("command_object").(string)) + } + if _, ok := d.GetOk("command_object_id"); ok { + createJobOptions.SetCommandObjectID(d.Get("command_object_id").(string)) + } + if _, ok := d.GetOk("command_name"); ok { + createJobOptions.SetCommandName(d.Get("command_name").(string)) + } + if _, ok := d.GetOk("command_parameter"); ok { + createJobOptions.SetCommandParameter(d.Get("command_parameter").(string)) + } + if _, ok := d.GetOk("command_options"); ok { + createJobOptions.SetCommandOptions(d.Get("command_options").([]string)) + } + if _, ok := d.GetOk("job_inputs"); ok { + var jobInputs []schematicsv1.VariableData + for _, e := range d.Get("job_inputs").([]interface{}) { + value := e.(map[string]interface{}) + jobInputsItem := resourceIBMSchematicsJobMapToVariableData(value) + jobInputs = append(jobInputs, jobInputsItem) + } + createJobOptions.SetInputs(jobInputs) + } + if _, ok := d.GetOk("job_env_settings"); ok { + var jobEnvSettings []schematicsv1.VariableData + for _, e := range d.Get("job_env_settings").([]interface{}) { + value := e.(map[string]interface{}) + jobEnvSettingsItem := resourceIBMSchematicsJobMapToVariableData(value) + jobEnvSettings = append(jobEnvSettings, jobEnvSettingsItem) + } + createJobOptions.SetSettings(jobEnvSettings) + } + if _, ok := d.GetOk("tags"); ok { + createJobOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("location"); ok { + createJobOptions.SetLocation(d.Get("location").(string)) + } + if _, ok := d.GetOk("status"); ok { + statusAttr := d.Get("status").([]interface{}) + if len(statusAttr) > 0 { + status := resourceIBMSchematicsJobMapToJobStatus(d.Get("status.0").(map[string]interface{})) + createJobOptions.SetStatus(&status) + } + } + if _, ok := d.GetOk("data"); ok { + dataAttr := d.Get("data").([]interface{}) + if len(dataAttr) > 0 { + data := resourceIBMSchematicsJobMapToJobData(d.Get("data.0").(map[string]interface{})) + createJobOptions.SetData(&data) + } + } + if _, ok := d.GetOk("bastion"); ok { + bastionAttr := d.Get("bastion").([]interface{}) + if len(bastionAttr) > 0 { + bastion := resourceIBMSchematicsJobMapToBastionResourceDefinition(d.Get("bastion.0").(map[string]interface{})) + createJobOptions.SetBastion(&bastion) + } + } + if _, ok := d.GetOk("log_summary"); ok { + logSummaryAttr := d.Get("log_summary").([]interface{}) + if len(logSummaryAttr) > 0 { + logSummary := resourceIBMSchematicsJobMapToJobLogSummary(d.Get("log_summary.0").(map[string]interface{})) + createJobOptions.SetLogSummary(&logSummary) + } + } + + job, response, err := schematicsClient.CreateJobWithContext(context, createJobOptions) + if err != nil { + log.Printf("[DEBUG] CreateJobWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateJobWithContext failed %s\n%s", err, response)) + } + + d.SetId(*job.ID) + + return resourceIBMSchematicsJobRead(context, d, meta) +} + +func resourceIBMSchematicsJobMapToVariableData(variableDataMap map[string]interface{}) schematicsv1.VariableData { + variableData := schematicsv1.VariableData{} + + if variableDataMap["name"] != nil { + variableData.Name = core.StringPtr(variableDataMap["name"].(string)) + } + if variableDataMap["value"] != nil { + variableData.Value = core.StringPtr(variableDataMap["value"].(string)) + } + if variableDataMap["metadata"] != nil && len(variableDataMap["metadata"].([]interface{})) != 0 { + variableMetaData := resourceIBMSchematicsJobMapToVariableMetadata(variableDataMap["metadata"].([]interface{})[0].(map[string]interface{})) + variableData.Metadata = &variableMetaData + } + if variableDataMap["link"] != nil { + variableData.Link = core.StringPtr(variableDataMap["link"].(string)) + } + + return variableData +} + +func resourceIBMSchematicsJobMapToVariableMetadata(variableMetadataMap map[string]interface{}) schematicsv1.VariableMetadata { + variableMetadata := schematicsv1.VariableMetadata{} + + if variableMetadataMap["type"] != nil { + variableMetadata.Type = core.StringPtr(variableMetadataMap["type"].(string)) + } + if variableMetadataMap["aliases"] != nil { + aliases := []string{} + for _, aliasesItem := range variableMetadataMap["aliases"].([]interface{}) { + aliases = append(aliases, aliasesItem.(string)) + } + variableMetadata.Aliases = aliases + } + if variableMetadataMap["description"] != nil { + variableMetadata.Description = core.StringPtr(variableMetadataMap["description"].(string)) + } + if variableMetadataMap["default_value"] != nil { + variableMetadata.DefaultValue = core.StringPtr(variableMetadataMap["default_value"].(string)) + } + if variableMetadataMap["secure"] != nil { + variableMetadata.Secure = core.BoolPtr(variableMetadataMap["secure"].(bool)) + } + if variableMetadataMap["immutable"] != nil { + variableMetadata.Immutable = core.BoolPtr(variableMetadataMap["immutable"].(bool)) + } + if variableMetadataMap["hidden"] != nil { + variableMetadata.Hidden = core.BoolPtr(variableMetadataMap["hidden"].(bool)) + } + if variableMetadataMap["options"] != nil { + options := []string{} + for _, optionsItem := range variableMetadataMap["options"].([]interface{}) { + options = append(options, optionsItem.(string)) + } + variableMetadata.Options = options + } + if variableMetadataMap["min_value"] != nil { + variableMetadata.MinValue = core.Int64Ptr(int64(variableMetadataMap["min_value"].(int))) + } + if variableMetadataMap["max_value"] != nil { + variableMetadata.MaxValue = core.Int64Ptr(int64(variableMetadataMap["max_value"].(int))) + } + if variableMetadataMap["min_length"] != nil { + variableMetadata.MinLength = core.Int64Ptr(int64(variableMetadataMap["min_length"].(int))) + } + if variableMetadataMap["max_length"] != nil { + variableMetadata.MaxLength = core.Int64Ptr(int64(variableMetadataMap["max_length"].(int))) + } + if variableMetadataMap["matches"] != nil { + variableMetadata.Matches = core.StringPtr(variableMetadataMap["matches"].(string)) + } + if variableMetadataMap["position"] != nil { + variableMetadata.Position = core.Int64Ptr(int64(variableMetadataMap["position"].(int))) + } + if variableMetadataMap["group_by"] != nil { + variableMetadata.GroupBy = core.StringPtr(variableMetadataMap["group_by"].(string)) + } + if variableMetadataMap["source"] != nil { + variableMetadata.Source = core.StringPtr(variableMetadataMap["source"].(string)) + } + + return variableMetadata +} +func resourceIBMSchematicsJobMapToCredentialVariableMetadata(variableMetadataMap map[string]interface{}) schematicsv1.CredentialVariableMetadata { + variableMetadata := schematicsv1.CredentialVariableMetadata{} + + if variableMetadataMap["type"] != nil { + variableMetadata.Type = core.StringPtr(variableMetadataMap["type"].(string)) + } + if variableMetadataMap["aliases"] != nil { + aliases := []string{} + for _, aliasesItem := range variableMetadataMap["aliases"].([]interface{}) { + aliases = append(aliases, aliasesItem.(string)) + } + variableMetadata.Aliases = aliases + } + if variableMetadataMap["description"] != nil { + variableMetadata.Description = core.StringPtr(variableMetadataMap["description"].(string)) + } + if variableMetadataMap["default_value"] != nil { + variableMetadata.DefaultValue = core.StringPtr(variableMetadataMap["default_value"].(string)) + } + if variableMetadataMap["immutable"] != nil { + variableMetadata.Immutable = core.BoolPtr(variableMetadataMap["immutable"].(bool)) + } + if variableMetadataMap["hidden"] != nil { + variableMetadata.Hidden = core.BoolPtr(variableMetadataMap["hidden"].(bool)) + } + + if variableMetadataMap["position"] != nil { + variableMetadata.Position = core.Int64Ptr(int64(variableMetadataMap["position"].(int))) + } + if variableMetadataMap["group_by"] != nil { + variableMetadata.GroupBy = core.StringPtr(variableMetadataMap["group_by"].(string)) + } + if variableMetadataMap["source"] != nil { + variableMetadata.Source = core.StringPtr(variableMetadataMap["source"].(string)) + } + + return variableMetadata +} + +func resourceIBMSchematicsJobMapToJobStatus(jobStatusMap map[string]interface{}) schematicsv1.JobStatus { + jobStatus := schematicsv1.JobStatus{} + + if jobStatusMap["workspace_job_status"] != nil { + // TODO: handle WorkspaceJobStatus of type JobStatusWorkspace -- not primitive type, not list + } + if jobStatusMap["action_job_status"] != nil { + actionJobStatus := resourceIBMSchematicsJobMapToJobStatusAction(jobStatusMap["action_job_status"].([]interface{})[0].(map[string]interface{})) + jobStatus.ActionJobStatus = &actionJobStatus + } + + return jobStatus +} + +func resourceIBMSchematicsJobMapToJobStatusWorkspace(jobStatusWorkspaceMap map[string]interface{}) schematicsv1.JobStatusWorkspace { + jobStatusWorkspace := schematicsv1.JobStatusWorkspace{} + + if jobStatusWorkspaceMap["workspace_name"] != nil { + jobStatusWorkspace.WorkspaceName = core.StringPtr(jobStatusWorkspaceMap["workspace_name"].(string)) + } + if jobStatusWorkspaceMap["status_code"] != nil { + jobStatusWorkspace.StatusCode = core.StringPtr(jobStatusWorkspaceMap["status_code"].(string)) + } + if jobStatusWorkspaceMap["status_message"] != nil { + jobStatusWorkspace.StatusMessage = core.StringPtr(jobStatusWorkspaceMap["status_message"].(string)) + } + if jobStatusWorkspaceMap["flow_status"] != nil { + // TODO: handle FlowStatus of type JobStatusFlow -- not primitive type, not list + } + if jobStatusWorkspaceMap["template_status"] != nil { + templateStatus := []schematicsv1.JobStatusTemplate{} + for _, templateStatusItem := range jobStatusWorkspaceMap["template_status"].([]interface{}) { + templateStatusItemModel := resourceIBMSchematicsJobMapToJobStatusTemplate(templateStatusItem.(map[string]interface{})) + templateStatus = append(templateStatus, templateStatusItemModel) + } + jobStatusWorkspace.TemplateStatus = templateStatus + } + if jobStatusWorkspaceMap["updated_at"] != nil { + + } + + return jobStatusWorkspace +} + +func resourceIBMSchematicsJobMapToJobStatusFlow(jobStatusFlowMap map[string]interface{}) schematicsv1.JobStatusFlow { + jobStatusFlow := schematicsv1.JobStatusFlow{} + + if jobStatusFlowMap["flow_id"] != nil { + jobStatusFlow.FlowID = core.StringPtr(jobStatusFlowMap["flow_id"].(string)) + } + if jobStatusFlowMap["flow_name"] != nil { + jobStatusFlow.FlowName = core.StringPtr(jobStatusFlowMap["flow_name"].(string)) + } + if jobStatusFlowMap["status_code"] != nil { + jobStatusFlow.StatusCode = core.StringPtr(jobStatusFlowMap["status_code"].(string)) + } + if jobStatusFlowMap["status_message"] != nil { + jobStatusFlow.StatusMessage = core.StringPtr(jobStatusFlowMap["status_message"].(string)) + } + if jobStatusFlowMap["workitems"] != nil { + workitems := []schematicsv1.JobStatusWorkitem{} + for _, workitemsItem := range jobStatusFlowMap["workitems"].([]interface{}) { + workitemsItemModel := resourceIBMSchematicsJobMapToJobStatusWorkitem(workitemsItem.(map[string]interface{})) + workitems = append(workitems, workitemsItemModel) + } + jobStatusFlow.Workitems = workitems + } + if jobStatusFlowMap["updated_at"] != nil { + + } + + return jobStatusFlow +} + +func resourceIBMSchematicsJobMapToJobStatusWorkitem(jobStatusWorkitemMap map[string]interface{}) schematicsv1.JobStatusWorkitem { + jobStatusWorkitem := schematicsv1.JobStatusWorkitem{} + + if jobStatusWorkitemMap["workspace_id"] != nil { + jobStatusWorkitem.WorkspaceID = core.StringPtr(jobStatusWorkitemMap["workspace_id"].(string)) + } + if jobStatusWorkitemMap["workspace_name"] != nil { + jobStatusWorkitem.WorkspaceName = core.StringPtr(jobStatusWorkitemMap["workspace_name"].(string)) + } + if jobStatusWorkitemMap["job_id"] != nil { + jobStatusWorkitem.JobID = core.StringPtr(jobStatusWorkitemMap["job_id"].(string)) + } + if jobStatusWorkitemMap["status_code"] != nil { + jobStatusWorkitem.StatusCode = core.StringPtr(jobStatusWorkitemMap["status_code"].(string)) + } + if jobStatusWorkitemMap["status_message"] != nil { + jobStatusWorkitem.StatusMessage = core.StringPtr(jobStatusWorkitemMap["status_message"].(string)) + } + if jobStatusWorkitemMap["updated_at"] != nil { + + } + + return jobStatusWorkitem +} + +func resourceIBMSchematicsJobMapToJobStatusTemplate(jobStatusTemplateMap map[string]interface{}) schematicsv1.JobStatusTemplate { + jobStatusTemplate := schematicsv1.JobStatusTemplate{} + + if jobStatusTemplateMap["template_id"] != nil { + jobStatusTemplate.TemplateID = core.StringPtr(jobStatusTemplateMap["template_id"].(string)) + } + if jobStatusTemplateMap["template_name"] != nil { + jobStatusTemplate.TemplateName = core.StringPtr(jobStatusTemplateMap["template_name"].(string)) + } + if jobStatusTemplateMap["flow_index"] != nil { + jobStatusTemplate.FlowIndex = core.Int64Ptr(int64(jobStatusTemplateMap["flow_index"].(int))) + } + if jobStatusTemplateMap["status_code"] != nil { + jobStatusTemplate.StatusCode = core.StringPtr(jobStatusTemplateMap["status_code"].(string)) + } + if jobStatusTemplateMap["status_message"] != nil { + jobStatusTemplate.StatusMessage = core.StringPtr(jobStatusTemplateMap["status_message"].(string)) + } + if jobStatusTemplateMap["updated_at"] != nil { + + } + + return jobStatusTemplate +} + +func resourceIBMSchematicsJobMapToJobStatusAction(jobStatusActionMap map[string]interface{}) schematicsv1.JobStatusAction { + jobStatusAction := schematicsv1.JobStatusAction{} + + if jobStatusActionMap["action_name"] != nil { + jobStatusAction.ActionName = core.StringPtr(jobStatusActionMap["action_name"].(string)) + } + if jobStatusActionMap["status_code"] != nil { + jobStatusAction.StatusCode = core.StringPtr(jobStatusActionMap["status_code"].(string)) + } + if jobStatusActionMap["status_message"] != nil { + jobStatusAction.StatusMessage = core.StringPtr(jobStatusActionMap["status_message"].(string)) + } + if jobStatusActionMap["bastion_status_code"] != nil { + jobStatusAction.BastionStatusCode = core.StringPtr(jobStatusActionMap["bastion_status_code"].(string)) + } + if jobStatusActionMap["bastion_status_message"] != nil { + jobStatusAction.BastionStatusMessage = core.StringPtr(jobStatusActionMap["bastion_status_message"].(string)) + } + if jobStatusActionMap["targets_status_code"] != nil { + jobStatusAction.TargetsStatusCode = core.StringPtr(jobStatusActionMap["targets_status_code"].(string)) + } + if jobStatusActionMap["targets_status_message"] != nil { + jobStatusAction.TargetsStatusMessage = core.StringPtr(jobStatusActionMap["targets_status_message"].(string)) + } + if jobStatusActionMap["updated_at"] != nil { + updatedAt, err := strfmt.ParseDateTime(jobStatusActionMap["updated_at"].(string)) + if err != nil { + jobStatusAction.UpdatedAt = &updatedAt + } + } + + return jobStatusAction +} + +func resourceIBMSchematicsJobMapToJobStatusSystem(jobStatusSystemMap map[string]interface{}) schematicsv1.JobStatusSystem { + jobStatusSystem := schematicsv1.JobStatusSystem{} + + if jobStatusSystemMap["system_status_message"] != nil { + jobStatusSystem.SystemStatusMessage = core.StringPtr(jobStatusSystemMap["system_status_message"].(string)) + } + if jobStatusSystemMap["system_status_code"] != nil { + jobStatusSystem.SystemStatusCode = core.StringPtr(jobStatusSystemMap["system_status_code"].(string)) + } + if jobStatusSystemMap["schematics_resource_status"] != nil { + schematicsResourceStatus := []schematicsv1.JobStatusSchematicsResources{} + for _, schematicsResourceStatusItem := range jobStatusSystemMap["schematics_resource_status"].([]interface{}) { + schematicsResourceStatusItemModel := resourceIBMSchematicsJobMapToJobStatusSchematicsResources(schematicsResourceStatusItem.(map[string]interface{})) + schematicsResourceStatus = append(schematicsResourceStatus, schematicsResourceStatusItemModel) + } + jobStatusSystem.SchematicsResourceStatus = schematicsResourceStatus + } + if jobStatusSystemMap["updated_at"] != nil { + + } + + return jobStatusSystem +} + +func resourceIBMSchematicsJobMapToJobStatusSchematicsResources(jobStatusSchematicsResourcesMap map[string]interface{}) schematicsv1.JobStatusSchematicsResources { + jobStatusSchematicsResources := schematicsv1.JobStatusSchematicsResources{} + + if jobStatusSchematicsResourcesMap["status_code"] != nil { + jobStatusSchematicsResources.StatusCode = core.StringPtr(jobStatusSchematicsResourcesMap["status_code"].(string)) + } + if jobStatusSchematicsResourcesMap["status_message"] != nil { + jobStatusSchematicsResources.StatusMessage = core.StringPtr(jobStatusSchematicsResourcesMap["status_message"].(string)) + } + if jobStatusSchematicsResourcesMap["schematics_resource_id"] != nil { + jobStatusSchematicsResources.SchematicsResourceID = core.StringPtr(jobStatusSchematicsResourcesMap["schematics_resource_id"].(string)) + } + if jobStatusSchematicsResourcesMap["updated_at"] != nil { + + } + + return jobStatusSchematicsResources +} + +func resourceIBMSchematicsJobMapToJobData(jobDataMap map[string]interface{}) schematicsv1.JobData { + jobData := schematicsv1.JobData{} + + jobData.JobType = core.StringPtr(jobDataMap["job_type"].(string)) + if jobDataMap["workspace_job_data"] != nil { + workspaceJobData := resourceIBMSchematicsJobMapToJobDataWorkspace(jobDataMap["workspace_job_data"].([]interface{})[0].(map[string]interface{})) + jobData.WorkspaceJobData = &workspaceJobData + } + if jobDataMap["action_job_data"] != nil { + actionJobData := resourceIBMSchematicsJobMapToJobDataAction(jobDataMap["action_job_data"].([]interface{})[0].(map[string]interface{})) + jobData.ActionJobData = &actionJobData + } + if jobDataMap["system_job_data"] != nil { + systemJobData := resourceIBMSchematicsJobMapToJobDataSystem(jobDataMap["system_job_data"].([]interface{})[0].(map[string]interface{})) + jobData.SystemJobData = &systemJobData + } + if jobDataMap["flow_job_data"] != nil { + flowJobData := resourceIBMSchematicsJobMapToJobDataFlow(jobDataMap["flow_job_data"].([]interface{})[0].(map[string]interface{})) + jobData.FlowJobData = &flowJobData + } + + return jobData +} + +func resourceIBMSchematicsJobMapToJobDataWorkspace(jobDataWorkspaceMap map[string]interface{}) schematicsv1.JobDataWorkspace { + jobDataWorkspace := schematicsv1.JobDataWorkspace{} + + if jobDataWorkspaceMap["workspace_name"] != nil { + jobDataWorkspace.WorkspaceName = core.StringPtr(jobDataWorkspaceMap["workspace_name"].(string)) + } + if jobDataWorkspaceMap["flow_id"] != nil { + jobDataWorkspace.FlowID = core.StringPtr(jobDataWorkspaceMap["flow_id"].(string)) + } + if jobDataWorkspaceMap["flow_name"] != nil { + jobDataWorkspace.FlowName = core.StringPtr(jobDataWorkspaceMap["flow_name"].(string)) + } + if jobDataWorkspaceMap["inputs"] != nil { + inputs := []schematicsv1.VariableData{} + for _, inputsItem := range jobDataWorkspaceMap["inputs"].([]interface{}) { + inputsItemModel := resourceIBMSchematicsJobMapToVariableData(inputsItem.(map[string]interface{})) + inputs = append(inputs, inputsItemModel) + } + jobDataWorkspace.Inputs = inputs + } + if jobDataWorkspaceMap["outputs"] != nil { + outputs := []schematicsv1.VariableData{} + for _, outputsItem := range jobDataWorkspaceMap["outputs"].([]interface{}) { + outputsItemModel := resourceIBMSchematicsJobMapToVariableData(outputsItem.(map[string]interface{})) + outputs = append(outputs, outputsItemModel) + } + jobDataWorkspace.Outputs = outputs + } + if jobDataWorkspaceMap["settings"] != nil { + settings := []schematicsv1.VariableData{} + for _, settingsItem := range jobDataWorkspaceMap["settings"].([]interface{}) { + settingsItemModel := resourceIBMSchematicsJobMapToVariableData(settingsItem.(map[string]interface{})) + settings = append(settings, settingsItemModel) + } + jobDataWorkspace.Settings = settings + } + if jobDataWorkspaceMap["template_data"] != nil { + templateData := []schematicsv1.JobDataTemplate{} + for _, templateDataItem := range jobDataWorkspaceMap["template_data"].([]interface{}) { + templateDataItemModel := resourceIBMSchematicsJobMapToJobDataTemplate(templateDataItem.(map[string]interface{})) + templateData = append(templateData, templateDataItemModel) + } + jobDataWorkspace.TemplateData = templateData + } + if jobDataWorkspaceMap["updated_at"] != nil { + + } + + return jobDataWorkspace +} + +func resourceIBMSchematicsJobMapToJobDataTemplate(jobDataTemplateMap map[string]interface{}) schematicsv1.JobDataTemplate { + jobDataTemplate := schematicsv1.JobDataTemplate{} + + if jobDataTemplateMap["template_id"] != nil { + jobDataTemplate.TemplateID = core.StringPtr(jobDataTemplateMap["template_id"].(string)) + } + if jobDataTemplateMap["template_name"] != nil { + jobDataTemplate.TemplateName = core.StringPtr(jobDataTemplateMap["template_name"].(string)) + } + if jobDataTemplateMap["flow_index"] != nil { + jobDataTemplate.FlowIndex = core.Int64Ptr(int64(jobDataTemplateMap["flow_index"].(int))) + } + if jobDataTemplateMap["inputs"] != nil { + inputs := []schematicsv1.VariableData{} + for _, inputsItem := range jobDataTemplateMap["inputs"].([]interface{}) { + inputsItemModel := resourceIBMSchematicsJobMapToVariableData(inputsItem.(map[string]interface{})) + inputs = append(inputs, inputsItemModel) + } + jobDataTemplate.Inputs = inputs + } + if jobDataTemplateMap["outputs"] != nil { + outputs := []schematicsv1.VariableData{} + for _, outputsItem := range jobDataTemplateMap["outputs"].([]interface{}) { + outputsItemModel := resourceIBMSchematicsJobMapToVariableData(outputsItem.(map[string]interface{})) + outputs = append(outputs, outputsItemModel) + } + jobDataTemplate.Outputs = outputs + } + if jobDataTemplateMap["settings"] != nil { + settings := []schematicsv1.VariableData{} + for _, settingsItem := range jobDataTemplateMap["settings"].([]interface{}) { + settingsItemModel := resourceIBMSchematicsJobMapToVariableData(settingsItem.(map[string]interface{})) + settings = append(settings, settingsItemModel) + } + jobDataTemplate.Settings = settings + } + if jobDataTemplateMap["updated_at"] != nil { + + } + + return jobDataTemplate +} + +func resourceIBMSchematicsJobMapToJobDataAction(jobDataActionMap map[string]interface{}) schematicsv1.JobDataAction { + jobDataAction := schematicsv1.JobDataAction{} + + if jobDataActionMap["action_name"] != nil { + jobDataAction.ActionName = core.StringPtr(jobDataActionMap["action_name"].(string)) + } + if jobDataActionMap["inputs"] != nil { + inputs := []schematicsv1.VariableData{} + for _, inputsItem := range jobDataActionMap["inputs"].([]interface{}) { + inputsItemModel := resourceIBMSchematicsJobMapToVariableData(inputsItem.(map[string]interface{})) + inputs = append(inputs, inputsItemModel) + } + jobDataAction.Inputs = inputs + } + if jobDataActionMap["outputs"] != nil { + outputs := []schematicsv1.VariableData{} + for _, outputsItem := range jobDataActionMap["outputs"].([]interface{}) { + outputsItemModel := resourceIBMSchematicsJobMapToVariableData(outputsItem.(map[string]interface{})) + outputs = append(outputs, outputsItemModel) + } + jobDataAction.Outputs = outputs + } + if jobDataActionMap["settings"] != nil { + settings := []schematicsv1.VariableData{} + for _, settingsItem := range jobDataActionMap["settings"].([]interface{}) { + settingsItemModel := resourceIBMSchematicsJobMapToVariableData(settingsItem.(map[string]interface{})) + settings = append(settings, settingsItemModel) + } + jobDataAction.Settings = settings + } + if jobDataActionMap["updated_at"] != nil { + + } + if jobDataActionMap["inventory_record"] != nil { + // TODO: handle InventoryRecord of type InventoryResourceRecord -- not primitive type, not list + } + if jobDataActionMap["materialized_inventory"] != nil { + jobDataAction.MaterializedInventory = core.StringPtr(jobDataActionMap["materialized_inventory"].(string)) + } + + return jobDataAction +} + +func resourceIBMSchematicsJobMapToInventoryResourceRecord(inventoryResourceRecordMap map[string]interface{}) schematicsv1.InventoryResourceRecord { + inventoryResourceRecord := schematicsv1.InventoryResourceRecord{} + + if inventoryResourceRecordMap["name"] != nil { + inventoryResourceRecord.Name = core.StringPtr(inventoryResourceRecordMap["name"].(string)) + } + if inventoryResourceRecordMap["id"] != nil { + inventoryResourceRecord.ID = core.StringPtr(inventoryResourceRecordMap["id"].(string)) + } + if inventoryResourceRecordMap["description"] != nil { + inventoryResourceRecord.Description = core.StringPtr(inventoryResourceRecordMap["description"].(string)) + } + if inventoryResourceRecordMap["location"] != nil { + inventoryResourceRecord.Location = core.StringPtr(inventoryResourceRecordMap["location"].(string)) + } + if inventoryResourceRecordMap["resource_group"] != nil { + inventoryResourceRecord.ResourceGroup = core.StringPtr(inventoryResourceRecordMap["resource_group"].(string)) + } + if inventoryResourceRecordMap["created_at"] != nil { + + } + if inventoryResourceRecordMap["created_by"] != nil { + inventoryResourceRecord.CreatedBy = core.StringPtr(inventoryResourceRecordMap["created_by"].(string)) + } + if inventoryResourceRecordMap["updated_at"] != nil { + + } + if inventoryResourceRecordMap["updated_by"] != nil { + inventoryResourceRecord.UpdatedBy = core.StringPtr(inventoryResourceRecordMap["updated_by"].(string)) + } + if inventoryResourceRecordMap["inventories_ini"] != nil { + inventoryResourceRecord.InventoriesIni = core.StringPtr(inventoryResourceRecordMap["inventories_ini"].(string)) + } + if inventoryResourceRecordMap["resource_queries"] != nil { + resourceQueries := []string{} + for _, resourceQueriesItem := range inventoryResourceRecordMap["resource_queries"].([]interface{}) { + resourceQueries = append(resourceQueries, resourceQueriesItem.(string)) + } + inventoryResourceRecord.ResourceQueries = resourceQueries + } + + return inventoryResourceRecord +} + +func resourceIBMSchematicsJobMapToJobDataSystem(jobDataSystemMap map[string]interface{}) schematicsv1.JobDataSystem { + jobDataSystem := schematicsv1.JobDataSystem{} + + if jobDataSystemMap["key_id"] != nil { + jobDataSystem.KeyID = core.StringPtr(jobDataSystemMap["key_id"].(string)) + } + if jobDataSystemMap["schematics_resource_id"] != nil { + schematicsResourceID := []string{} + for _, schematicsResourceIDItem := range jobDataSystemMap["schematics_resource_id"].([]interface{}) { + schematicsResourceID = append(schematicsResourceID, schematicsResourceIDItem.(string)) + } + jobDataSystem.SchematicsResourceID = schematicsResourceID + } + if jobDataSystemMap["updated_at"] != nil { + + } + + return jobDataSystem +} + +func resourceIBMSchematicsJobMapToJobDataFlow(jobDataFlowMap map[string]interface{}) schematicsv1.JobDataFlow { + jobDataFlow := schematicsv1.JobDataFlow{} + + if jobDataFlowMap["flow_id"] != nil { + jobDataFlow.FlowID = core.StringPtr(jobDataFlowMap["flow_id"].(string)) + } + if jobDataFlowMap["flow_name"] != nil { + jobDataFlow.FlowName = core.StringPtr(jobDataFlowMap["flow_name"].(string)) + } + if jobDataFlowMap["workitems"] != nil { + workitems := []schematicsv1.JobDataWorkItem{} + for _, workitemsItem := range jobDataFlowMap["workitems"].([]interface{}) { + workitemsItemModel := resourceIBMSchematicsJobMapToJobDataWorkItem(workitemsItem.(map[string]interface{})) + workitems = append(workitems, workitemsItemModel) + } + jobDataFlow.Workitems = workitems + } + if jobDataFlowMap["updated_at"] != nil { + + } + + return jobDataFlow +} + +func resourceIBMSchematicsJobMapToJobDataWorkItem(jobDataWorkItemMap map[string]interface{}) schematicsv1.JobDataWorkItem { + jobDataWorkItem := schematicsv1.JobDataWorkItem{} + + if jobDataWorkItemMap["command_object_id"] != nil { + jobDataWorkItem.CommandObjectID = core.StringPtr(jobDataWorkItemMap["command_object_id"].(string)) + } + if jobDataWorkItemMap["command_object_name"] != nil { + jobDataWorkItem.CommandObjectName = core.StringPtr(jobDataWorkItemMap["command_object_name"].(string)) + } + if jobDataWorkItemMap["layers"] != nil { + jobDataWorkItem.Layers = core.StringPtr(jobDataWorkItemMap["layers"].(string)) + } + if jobDataWorkItemMap["source_type"] != nil { + jobDataWorkItem.SourceType = core.StringPtr(jobDataWorkItemMap["source_type"].(string)) + } + if jobDataWorkItemMap["source"] != nil { + // TODO: handle Source of type ExternalSource -- not primitive type, not list + } + if jobDataWorkItemMap["inputs"] != nil { + inputs := []schematicsv1.VariableData{} + for _, inputsItem := range jobDataWorkItemMap["inputs"].([]interface{}) { + inputsItemModel := resourceIBMSchematicsJobMapToVariableData(inputsItem.(map[string]interface{})) + inputs = append(inputs, inputsItemModel) + } + jobDataWorkItem.Inputs = inputs + } + if jobDataWorkItemMap["outputs"] != nil { + outputs := []schematicsv1.VariableData{} + for _, outputsItem := range jobDataWorkItemMap["outputs"].([]interface{}) { + outputsItemModel := resourceIBMSchematicsJobMapToVariableData(outputsItem.(map[string]interface{})) + outputs = append(outputs, outputsItemModel) + } + jobDataWorkItem.Outputs = outputs + } + if jobDataWorkItemMap["settings"] != nil { + settings := []schematicsv1.VariableData{} + for _, settingsItem := range jobDataWorkItemMap["settings"].([]interface{}) { + settingsItemModel := resourceIBMSchematicsJobMapToVariableData(settingsItem.(map[string]interface{})) + settings = append(settings, settingsItemModel) + } + jobDataWorkItem.Settings = settings + } + if jobDataWorkItemMap["updated_at"] != nil { + + } + + return jobDataWorkItem +} + +func resourceIBMSchematicsJobMapToExternalSource(externalSourceMap map[string]interface{}) schematicsv1.ExternalSource { + externalSource := schematicsv1.ExternalSource{} + + externalSource.SourceType = core.StringPtr(externalSourceMap["source_type"].(string)) + if externalSourceMap["git"] != nil { + // TODO: handle Git of type ExternalSourceGit -- not primitive type, not list + } + if externalSourceMap["catalog"] != nil { + // TODO: handle Catalog of type ExternalSourceCatalog -- not primitive type, not list + } + + return externalSource +} + +func resourceIBMSchematicsJobMapToExternalSourceGit(externalSourceGitMap map[string]interface{}) schematicsv1.GitSource { + externalSourceGit := schematicsv1.GitSource{} + + if externalSourceGitMap["computed_git_repo_url"] != nil { + externalSourceGit.ComputedGitRepoURL = core.StringPtr(externalSourceGitMap["computed_git_repo_url"].(string)) + } + if externalSourceGitMap["git_repo_url"] != nil { + externalSourceGit.GitRepoURL = core.StringPtr(externalSourceGitMap["git_repo_url"].(string)) + } + if externalSourceGitMap["git_token"] != nil { + externalSourceGit.GitToken = core.StringPtr(externalSourceGitMap["git_token"].(string)) + } + if externalSourceGitMap["git_repo_folder"] != nil { + externalSourceGit.GitRepoFolder = core.StringPtr(externalSourceGitMap["git_repo_folder"].(string)) + } + if externalSourceGitMap["git_release"] != nil { + externalSourceGit.GitRelease = core.StringPtr(externalSourceGitMap["git_release"].(string)) + } + if externalSourceGitMap["git_branch"] != nil { + externalSourceGit.GitBranch = core.StringPtr(externalSourceGitMap["git_branch"].(string)) + } + + return externalSourceGit +} + +func resourceIBMSchematicsJobMapToExternalSourceCatalog(externalSourceCatalogMap map[string]interface{}) schematicsv1.CatalogSource { + externalSourceCatalog := schematicsv1.CatalogSource{} + + if externalSourceCatalogMap["catalog_name"] != nil { + externalSourceCatalog.CatalogName = core.StringPtr(externalSourceCatalogMap["catalog_name"].(string)) + } + if externalSourceCatalogMap["offering_name"] != nil { + externalSourceCatalog.OfferingName = core.StringPtr(externalSourceCatalogMap["offering_name"].(string)) + } + if externalSourceCatalogMap["offering_version"] != nil { + externalSourceCatalog.OfferingVersion = core.StringPtr(externalSourceCatalogMap["offering_version"].(string)) + } + if externalSourceCatalogMap["offering_kind"] != nil { + externalSourceCatalog.OfferingKind = core.StringPtr(externalSourceCatalogMap["offering_kind"].(string)) + } + if externalSourceCatalogMap["offering_id"] != nil { + externalSourceCatalog.OfferingID = core.StringPtr(externalSourceCatalogMap["offering_id"].(string)) + } + if externalSourceCatalogMap["offering_version_id"] != nil { + externalSourceCatalog.OfferingVersionID = core.StringPtr(externalSourceCatalogMap["offering_version_id"].(string)) + } + if externalSourceCatalogMap["offering_repo_url"] != nil { + externalSourceCatalog.OfferingRepoURL = core.StringPtr(externalSourceCatalogMap["offering_repo_url"].(string)) + } + + return externalSourceCatalog +} + +// func resourceIBMSchematicsJobMapToExternalSourceCosBucket(externalSourceCosBucketMap map[string]interface{}) schematicsv1.ExternalSourceCosBucket { +// externalSourceCosBucket := schematicsv1.ExternalSourceCosBucket{} + +// if externalSourceCosBucketMap["cos_bucket_url"] != nil { +// externalSourceCosBucket.CosBucketURL = core.StringPtr(externalSourceCosBucketMap["cos_bucket_url"].(string)) +// } + +// return externalSourceCosBucket +// } + +func resourceIBMSchematicsJobMapToJobDataWorkItemLastJob(jobDataWorkItemLastJobMap map[string]interface{}) schematicsv1.JobDataWorkItemLastJob { + jobDataWorkItemLastJob := schematicsv1.JobDataWorkItemLastJob{} + + if jobDataWorkItemLastJobMap["command_object"] != nil { + jobDataWorkItemLastJob.CommandObject = core.StringPtr(jobDataWorkItemLastJobMap["command_object"].(string)) + } + if jobDataWorkItemLastJobMap["command_object_name"] != nil { + jobDataWorkItemLastJob.CommandObjectName = core.StringPtr(jobDataWorkItemLastJobMap["command_object_name"].(string)) + } + if jobDataWorkItemLastJobMap["command_object_id"] != nil { + jobDataWorkItemLastJob.CommandObjectID = core.StringPtr(jobDataWorkItemLastJobMap["command_object_id"].(string)) + } + if jobDataWorkItemLastJobMap["command_name"] != nil { + jobDataWorkItemLastJob.CommandName = core.StringPtr(jobDataWorkItemLastJobMap["command_name"].(string)) + } + if jobDataWorkItemLastJobMap["job_id"] != nil { + jobDataWorkItemLastJob.JobID = core.StringPtr(jobDataWorkItemLastJobMap["job_id"].(string)) + } + if jobDataWorkItemLastJobMap["job_status"] != nil { + jobDataWorkItemLastJob.JobStatus = core.StringPtr(jobDataWorkItemLastJobMap["job_status"].(string)) + } + + return jobDataWorkItemLastJob +} + +func resourceIBMSchematicsJobMapToBastionResourceDefinition(bastionResourceDefinitionMap map[string]interface{}) schematicsv1.BastionResourceDefinition { + bastionResourceDefinition := schematicsv1.BastionResourceDefinition{} + + if bastionResourceDefinitionMap["name"] != nil { + bastionResourceDefinition.Name = core.StringPtr(bastionResourceDefinitionMap["name"].(string)) + } + if bastionResourceDefinitionMap["host"] != nil { + bastionResourceDefinition.Host = core.StringPtr(bastionResourceDefinitionMap["host"].(string)) + } + + return bastionResourceDefinition +} + +func resourceIBMSchematicsJobMapToJobLogSummary(jobLogSummaryMap map[string]interface{}) schematicsv1.JobLogSummary { + jobLogSummary := schematicsv1.JobLogSummary{} + + if jobLogSummaryMap["job_id"] != nil { + jobLogSummary.JobID = core.StringPtr(jobLogSummaryMap["job_id"].(string)) + } + if jobLogSummaryMap["job_type"] != nil { + jobLogSummary.JobType = core.StringPtr(jobLogSummaryMap["job_type"].(string)) + } + if jobLogSummaryMap["log_start_at"] != nil { + + } + if jobLogSummaryMap["log_analyzed_till"] != nil { + + } + if jobLogSummaryMap["elapsed_time"] != nil { + jobLogSummary.ElapsedTime = core.Float64Ptr(jobLogSummaryMap["elapsed_time"].(float64)) + } + if jobLogSummaryMap["log_errors"] != nil { + logErrors := []schematicsv1.JobLogSummaryLogErrors{} + for _, logErrorsItem := range jobLogSummaryMap["log_errors"].([]interface{}) { + logErrorsItemModel := resourceIBMSchematicsJobMapToJobLogSummaryLogErrors(logErrorsItem.(map[string]interface{})) + logErrors = append(logErrors, logErrorsItemModel) + } + jobLogSummary.LogErrors = logErrors + } + if jobLogSummaryMap["repo_download_job"] != nil && jobLogSummaryMap["repo_download_job"].([]interface{})[0] != nil { + repoDownloadJob := resourceIBMSchematicsJobMapToJobLogSummaryRepoDownloadJob(jobLogSummaryMap["repo_download_job"].([]interface{})[0].(map[string]interface{})) + jobLogSummary.RepoDownloadJob = &repoDownloadJob + } + if jobLogSummaryMap["workspace_job"] != nil && jobLogSummaryMap["workspace_job"].([]interface{})[0] != nil { + workspaceJob := resourceIBMSchematicsJobMapToJobLogSummaryWorkspaceJob(jobLogSummaryMap["workspace_job"].([]interface{})[0].(map[string]interface{})) + jobLogSummary.WorkspaceJob = &workspaceJob + } + if jobLogSummaryMap["flow_job"] != nil && jobLogSummaryMap["flow_job"].([]interface{})[0] != nil { + flowJob := resourceIBMSchematicsJobMapToJobLogSummaryFlowJob(jobLogSummaryMap["flow_job"].([]interface{})[0].(map[string]interface{})) + jobLogSummary.FlowJob = &flowJob + } + if jobLogSummaryMap["action_job"] != nil && jobLogSummaryMap["action_job"].([]interface{})[0] != nil { + actionJob := resourceIBMSchematicsJobMapToJobLogSummaryActionJob(jobLogSummaryMap["action_job"].([]interface{})[0].(map[string]interface{})) + jobLogSummary.ActionJob = &actionJob + } + if jobLogSummaryMap["system_job"] != nil && jobLogSummaryMap["system_job"].([]interface{})[0] != nil { + systemJob := resourceIBMSchematicsJobMapToJobLogSummarySystemJob(jobLogSummaryMap["system_job"].([]interface{})[0].(map[string]interface{})) + jobLogSummary.SystemJob = &systemJob + } + + return jobLogSummary +} + +func resourceIBMSchematicsJobMapToJobLogSummaryLogErrors(jobLogSummaryLogErrorsMap map[string]interface{}) schematicsv1.JobLogSummaryLogErrors { + jobLogSummaryLogErrors := schematicsv1.JobLogSummaryLogErrors{} + + if jobLogSummaryLogErrorsMap["error_code"] != nil { + jobLogSummaryLogErrors.ErrorCode = core.StringPtr(jobLogSummaryLogErrorsMap["error_code"].(string)) + } + if jobLogSummaryLogErrorsMap["error_msg"] != nil { + jobLogSummaryLogErrors.ErrorMsg = core.StringPtr(jobLogSummaryLogErrorsMap["error_msg"].(string)) + } + if jobLogSummaryLogErrorsMap["error_count"] != nil { + jobLogSummaryLogErrors.ErrorCount = core.Float64Ptr(jobLogSummaryLogErrorsMap["error_count"].(float64)) + } + + return jobLogSummaryLogErrors +} + +func resourceIBMSchematicsJobMapToJobLogSummaryRepoDownloadJob(jobLogSummaryRepoDownloadJobMap map[string]interface{}) schematicsv1.JobLogSummaryRepoDownloadJob { + jobLogSummaryRepoDownloadJob := schematicsv1.JobLogSummaryRepoDownloadJob{} + + if jobLogSummaryRepoDownloadJobMap["scanned_file_count"] != nil { + jobLogSummaryRepoDownloadJob.ScannedFileCount = core.Float64Ptr(jobLogSummaryRepoDownloadJobMap["scanned_file_count"].(float64)) + } + if jobLogSummaryRepoDownloadJobMap["quarantined_file_count"] != nil { + jobLogSummaryRepoDownloadJob.QuarantinedFileCount = core.Float64Ptr(jobLogSummaryRepoDownloadJobMap["quarantined_file_count"].(float64)) + } + if jobLogSummaryRepoDownloadJobMap["detected_filetype"] != nil { + jobLogSummaryRepoDownloadJob.DetectedFiletype = core.StringPtr(jobLogSummaryRepoDownloadJobMap["detected_filetype"].(string)) + } + if jobLogSummaryRepoDownloadJobMap["inputs_count"] != nil { + jobLogSummaryRepoDownloadJob.InputsCount = core.StringPtr(jobLogSummaryRepoDownloadJobMap["inputs_count"].(string)) + } + if jobLogSummaryRepoDownloadJobMap["outputs_count"] != nil { + jobLogSummaryRepoDownloadJob.OutputsCount = core.StringPtr(jobLogSummaryRepoDownloadJobMap["outputs_count"].(string)) + } + + return jobLogSummaryRepoDownloadJob +} + +func resourceIBMSchematicsJobMapToJobLogSummaryWorkspaceJob(jobLogSummaryWorkspaceJobMap map[string]interface{}) schematicsv1.JobLogSummaryWorkspaceJob { + jobLogSummaryWorkspaceJob := schematicsv1.JobLogSummaryWorkspaceJob{} + + if jobLogSummaryWorkspaceJobMap["resources_add"] != nil { + jobLogSummaryWorkspaceJob.ResourcesAdd = core.Float64Ptr(jobLogSummaryWorkspaceJobMap["resources_add"].(float64)) + } + if jobLogSummaryWorkspaceJobMap["resources_modify"] != nil { + jobLogSummaryWorkspaceJob.ResourcesModify = core.Float64Ptr(jobLogSummaryWorkspaceJobMap["resources_modify"].(float64)) + } + if jobLogSummaryWorkspaceJobMap["resources_destroy"] != nil { + jobLogSummaryWorkspaceJob.ResourcesDestroy = core.Float64Ptr(jobLogSummaryWorkspaceJobMap["resources_destroy"].(float64)) + } + + return jobLogSummaryWorkspaceJob +} + +func resourceIBMSchematicsJobMapToJobLogSummaryFlowJob(jobLogSummaryFlowJobMap map[string]interface{}) schematicsv1.JobLogSummaryFlowJob { + jobLogSummaryFlowJob := schematicsv1.JobLogSummaryFlowJob{} + + if jobLogSummaryFlowJobMap["workitems_completed"] != nil { + jobLogSummaryFlowJob.WorkitemsCompleted = core.Float64Ptr(jobLogSummaryFlowJobMap["workitems_completed"].(float64)) + } + if jobLogSummaryFlowJobMap["workitems_pending"] != nil { + jobLogSummaryFlowJob.WorkitemsPending = core.Float64Ptr(jobLogSummaryFlowJobMap["workitems_pending"].(float64)) + } + if jobLogSummaryFlowJobMap["workitems_failed"] != nil { + jobLogSummaryFlowJob.WorkitemsFailed = core.Float64Ptr(jobLogSummaryFlowJobMap["workitems_failed"].(float64)) + } + if jobLogSummaryFlowJobMap["workitems"] != nil { + workitems := []schematicsv1.JobLogSummaryWorkitems{} + for _, workitemsItem := range jobLogSummaryFlowJobMap["workitems"].([]interface{}) { + workitemsItemModel := resourceIBMSchematicsJobMapToJobLogSummaryWorkitems(workitemsItem.(map[string]interface{})) + workitems = append(workitems, workitemsItemModel) + } + jobLogSummaryFlowJob.Workitems = workitems + } + + return jobLogSummaryFlowJob +} + +func resourceIBMSchematicsJobMapToJobLogSummaryWorkitems(jobLogSummaryWorkitemsMap map[string]interface{}) schematicsv1.JobLogSummaryWorkitems { + jobLogSummaryWorkitems := schematicsv1.JobLogSummaryWorkitems{} + + if jobLogSummaryWorkitemsMap["workspace_id"] != nil { + jobLogSummaryWorkitems.WorkspaceID = core.StringPtr(jobLogSummaryWorkitemsMap["workspace_id"].(string)) + } + if jobLogSummaryWorkitemsMap["job_id"] != nil { + jobLogSummaryWorkitems.JobID = core.StringPtr(jobLogSummaryWorkitemsMap["job_id"].(string)) + } + if jobLogSummaryWorkitemsMap["resources_add"] != nil { + jobLogSummaryWorkitems.ResourcesAdd = core.Float64Ptr(jobLogSummaryWorkitemsMap["resources_add"].(float64)) + } + if jobLogSummaryWorkitemsMap["resources_modify"] != nil { + jobLogSummaryWorkitems.ResourcesModify = core.Float64Ptr(jobLogSummaryWorkitemsMap["resources_modify"].(float64)) + } + if jobLogSummaryWorkitemsMap["resources_destroy"] != nil { + jobLogSummaryWorkitems.ResourcesDestroy = core.Float64Ptr(jobLogSummaryWorkitemsMap["resources_destroy"].(float64)) + } + if jobLogSummaryWorkitemsMap["log_url"] != nil { + jobLogSummaryWorkitems.LogURL = core.StringPtr(jobLogSummaryWorkitemsMap["log_url"].(string)) + } + + return jobLogSummaryWorkitems +} + +func resourceIBMSchematicsJobMapToJobLogSummaryActionJob(jobLogSummaryActionJobMap map[string]interface{}) schematicsv1.JobLogSummaryActionJob { + jobLogSummaryActionJob := schematicsv1.JobLogSummaryActionJob{} + + if jobLogSummaryActionJobMap["target_count"] != nil { + jobLogSummaryActionJob.TargetCount = core.Float64Ptr(jobLogSummaryActionJobMap["target_count"].(float64)) + } + if jobLogSummaryActionJobMap["task_count"] != nil { + jobLogSummaryActionJob.TaskCount = core.Float64Ptr(jobLogSummaryActionJobMap["task_count"].(float64)) + } + if jobLogSummaryActionJobMap["play_count"] != nil { + jobLogSummaryActionJob.PlayCount = core.Float64Ptr(jobLogSummaryActionJobMap["play_count"].(float64)) + } + if jobLogSummaryActionJobMap["recap"] != nil && jobLogSummaryActionJobMap["recap"].([]interface{})[0] != nil { + recap := resourceIBMSchematicsJobMapToJobLogSummaryActionJobRecap(jobLogSummaryActionJobMap["recap"].([]interface{})[0].(map[string]interface{})) + jobLogSummaryActionJob.Recap = &recap + } + + return jobLogSummaryActionJob +} + +func resourceIBMSchematicsJobMapToJobLogSummaryActionJobRecap(jobLogSummaryActionJobRecapMap map[string]interface{}) schematicsv1.JobLogSummaryActionJobRecap { + jobLogSummaryActionJobRecap := schematicsv1.JobLogSummaryActionJobRecap{} + + if jobLogSummaryActionJobRecapMap["target"] != nil { + target := []string{} + for _, targetItem := range jobLogSummaryActionJobRecapMap["target"].([]interface{}) { + target = append(target, targetItem.(string)) + } + jobLogSummaryActionJobRecap.Target = target + } + if jobLogSummaryActionJobRecapMap["ok"] != nil { + jobLogSummaryActionJobRecap.Ok = core.Float64Ptr(jobLogSummaryActionJobRecapMap["ok"].(float64)) + } + if jobLogSummaryActionJobRecapMap["changed"] != nil { + jobLogSummaryActionJobRecap.Changed = core.Float64Ptr(jobLogSummaryActionJobRecapMap["changed"].(float64)) + } + if jobLogSummaryActionJobRecapMap["failed"] != nil { + jobLogSummaryActionJobRecap.Failed = core.Float64Ptr(jobLogSummaryActionJobRecapMap["failed"].(float64)) + } + if jobLogSummaryActionJobRecapMap["skipped"] != nil { + jobLogSummaryActionJobRecap.Skipped = core.Float64Ptr(jobLogSummaryActionJobRecapMap["skipped"].(float64)) + } + if jobLogSummaryActionJobRecapMap["unreachable"] != nil { + jobLogSummaryActionJobRecap.Unreachable = core.Float64Ptr(jobLogSummaryActionJobRecapMap["unreachable"].(float64)) + } + + return jobLogSummaryActionJobRecap +} + +func resourceIBMSchematicsJobMapToJobLogSummarySystemJob(jobLogSummarySystemJobMap map[string]interface{}) schematicsv1.JobLogSummarySystemJob { + jobLogSummarySystemJob := schematicsv1.JobLogSummarySystemJob{} + + if jobLogSummarySystemJobMap["target_count"] != nil { + jobLogSummarySystemJob.TargetCount = core.Float64Ptr(jobLogSummarySystemJobMap["target_count"].(float64)) + } + if jobLogSummarySystemJobMap["success"] != nil { + jobLogSummarySystemJob.Success = core.Float64Ptr(jobLogSummarySystemJobMap["success"].(float64)) + } + if jobLogSummarySystemJobMap["failed"] != nil { + jobLogSummarySystemJob.Failed = core.Float64Ptr(jobLogSummarySystemJobMap["failed"].(float64)) + } + + return jobLogSummarySystemJob +} + +func resourceIBMSchematicsJobRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + jobIDSplit := strings.Split(d.Id(), ".") + region := jobIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + getJobOptions := &schematicsv1.GetJobOptions{} + + getJobOptions.SetJobID(d.Id()) + + job, response, err := schematicsClient.GetJobWithContext(context, getJobOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetJobWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetJobWithContext failed %s\n%s", err, response)) + } + if err = d.Set("command_object", job.CommandObject); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_object: %s", err)) + } + if err = d.Set("command_object_id", job.CommandObjectID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_object_id: %s", err)) + } + if err = d.Set("command_name", job.CommandName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_name: %s", err)) + } + if _, ok := d.GetOk("command_parameter"); ok { + if err = d.Set("command_parameter", d.Get("command_parameter").(string)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_parameter: %s", err)) + } + } + if job.CommandOptions != nil { + if err = d.Set("command_options", job.CommandOptions); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting command_options: %s", err)) + } + } + if job.Inputs != nil { + jobInputs := []map[string]interface{}{} + for _, jobInputsItem := range job.Inputs { + jobInputsItemMap := resourceIBMSchematicsJobVariableDataToMap(jobInputsItem) + jobInputs = append(jobInputs, jobInputsItemMap) + } + if err = d.Set("job_inputs", jobInputs); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting job_inputs: %s", err)) + } + } + if job.Settings != nil { + jobEnvSettings := []map[string]interface{}{} + for _, jobEnvSettingsItem := range job.Settings { + jobEnvSettingsItemMap := resourceIBMSchematicsJobVariableDataToMap(jobEnvSettingsItem) + jobEnvSettings = append(jobEnvSettings, jobEnvSettingsItemMap) + } + if err = d.Set("job_env_settings", jobEnvSettings); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting job_env_settings: %s", err)) + } + } + if job.Tags != nil { + if err = d.Set("tags", job.Tags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting tags: %s", err)) + } + } + if err = d.Set("location", job.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if job.Status != nil { + statusMap := resourceIBMSchematicsJobJobStatusToMap(*job.Status) + if err = d.Set("status", []map[string]interface{}{statusMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + } + if job.Data != nil { + dataMap := resourceIBMSchematicsJobJobDataToMap(*job.Data) + if err = d.Set("data", []map[string]interface{}{dataMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting data: %s", err)) + } + } + if job.Bastion != nil { + bastionMap := resourceIBMSchematicsJobBastionResourceDefinitionToMap(*job.Bastion) + if err = d.Set("bastion", []map[string]interface{}{bastionMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bastion: %s", err)) + } + } + if job.LogSummary != nil { + logSummaryMap := resourceIBMSchematicsJobJobLogSummaryToMap(*job.LogSummary) + if err = d.Set("log_summary", []map[string]interface{}{logSummaryMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting log_summary: %s", err)) + } + } + if err = d.Set("name", job.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("description", job.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("resource_group", job.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if err = d.Set("submitted_at", flex.DateTimeToString(job.SubmittedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting submitted_at: %s", err)) + } + if err = d.Set("submitted_by", job.SubmittedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting submitted_by: %s", err)) + } + if err = d.Set("start_at", flex.DateTimeToString(job.StartAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting start_at: %s", err)) + } + if err = d.Set("end_at", flex.DateTimeToString(job.EndAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting end_at: %s", err)) + } + if err = d.Set("duration", job.Duration); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting duration: %s", err)) + } + if err = d.Set("log_store_url", job.LogStoreURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting log_store_url: %s", err)) + } + if err = d.Set("state_store_url", job.StateStoreURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state_store_url: %s", err)) + } + if err = d.Set("results_url", job.ResultsURL); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting results_url: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(job.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMSchematicsJobVariableDataToMap(variableData schematicsv1.VariableData) map[string]interface{} { + variableDataMap := map[string]interface{}{} + + if variableData.Name != nil { + variableDataMap["name"] = variableData.Name + } + if variableData.Value != nil { + variableDataMap["value"] = variableData.Value + } + if variableData.Metadata != nil { + MetadataMap := resourceIBMSchematicsJobVariableMetadataToMap(*variableData.Metadata) + variableDataMap["metadata"] = []map[string]interface{}{MetadataMap} + } + if variableData.Link != nil { + variableDataMap["link"] = variableData.Link + } + + return variableDataMap +} + +func resourceIBMSchematicsJobVariableMetadataToMap(variableMetadata schematicsv1.VariableMetadata) map[string]interface{} { + variableMetadataMap := map[string]interface{}{} + + if variableMetadata.Type != nil { + variableMetadataMap["type"] = variableMetadata.Type + } + if variableMetadata.Aliases != nil { + variableMetadataMap["aliases"] = variableMetadata.Aliases + } + if variableMetadata.Description != nil { + variableMetadataMap["description"] = variableMetadata.Description + } + if variableMetadata.DefaultValue != nil { + variableMetadataMap["default_value"] = variableMetadata.DefaultValue + } + if variableMetadata.Secure != nil { + variableMetadataMap["secure"] = variableMetadata.Secure + } + if variableMetadata.Immutable != nil { + variableMetadataMap["immutable"] = variableMetadata.Immutable + } + if variableMetadata.Hidden != nil { + variableMetadataMap["hidden"] = variableMetadata.Hidden + } + if variableMetadata.Options != nil { + variableMetadataMap["options"] = variableMetadata.Options + } + if variableMetadata.MinValue != nil { + variableMetadataMap["min_value"] = flex.IntValue(variableMetadata.MinValue) + } + if variableMetadata.MaxValue != nil { + variableMetadataMap["max_value"] = flex.IntValue(variableMetadata.MaxValue) + } + if variableMetadata.MinLength != nil { + variableMetadataMap["min_length"] = flex.IntValue(variableMetadata.MinLength) + } + if variableMetadata.MaxLength != nil { + variableMetadataMap["max_length"] = flex.IntValue(variableMetadata.MaxLength) + } + if variableMetadata.Matches != nil { + variableMetadataMap["matches"] = variableMetadata.Matches + } + if variableMetadata.Position != nil { + variableMetadataMap["position"] = flex.IntValue(variableMetadata.Position) + } + if variableMetadata.GroupBy != nil { + variableMetadataMap["group_by"] = variableMetadata.GroupBy + } + if variableMetadata.Source != nil { + variableMetadataMap["source"] = variableMetadata.Source + } + + return variableMetadataMap +} + +func resourceIBMSchematicsJobJobStatusToMap(jobStatus schematicsv1.JobStatus) map[string]interface{} { + jobStatusMap := map[string]interface{}{} + + if jobStatus.WorkspaceJobStatus != nil { + WorkspaceJobStatusMap := resourceIBMSchematicsJobJobStatusWorkspaceToMap(*jobStatus.WorkspaceJobStatus) + jobStatusMap["workspace_job_status"] = []map[string]interface{}{WorkspaceJobStatusMap} + } + if jobStatus.ActionJobStatus != nil { + ActionJobStatusMap := resourceIBMSchematicsJobJobStatusActionToMap(*jobStatus.ActionJobStatus) + jobStatusMap["action_job_status"] = []map[string]interface{}{ActionJobStatusMap} + } + if jobStatus.SystemJobStatus != nil { + SystemJobStatusMap := resourceIBMSchematicsJobJobStatusSystemToMap(*jobStatus.SystemJobStatus) + jobStatusMap["system_job_status"] = []map[string]interface{}{SystemJobStatusMap} + } + if jobStatus.FlowJobStatus != nil { + FlowJobStatusMap := resourceIBMSchematicsJobJobStatusFlowToMap(*jobStatus.FlowJobStatus) + jobStatusMap["flow_job_status"] = []map[string]interface{}{FlowJobStatusMap} + } + + return jobStatusMap +} + +func resourceIBMSchematicsJobJobStatusWorkspaceToMap(jobStatusWorkspace schematicsv1.JobStatusWorkspace) map[string]interface{} { + jobStatusWorkspaceMap := map[string]interface{}{} + + if jobStatusWorkspace.WorkspaceName != nil { + jobStatusWorkspaceMap["workspace_name"] = jobStatusWorkspace.WorkspaceName + } + if jobStatusWorkspace.StatusCode != nil { + jobStatusWorkspaceMap["status_code"] = jobStatusWorkspace.StatusCode + } + if jobStatusWorkspace.StatusMessage != nil { + jobStatusWorkspaceMap["status_message"] = jobStatusWorkspace.StatusMessage + } + if jobStatusWorkspace.FlowStatus != nil { + FlowStatusMap := resourceIBMSchematicsJobJobStatusFlowToMap(*jobStatusWorkspace.FlowStatus) + jobStatusWorkspaceMap["flow_status"] = []map[string]interface{}{FlowStatusMap} + } + if jobStatusWorkspace.TemplateStatus != nil { + templateStatus := []map[string]interface{}{} + for _, templateStatusItem := range jobStatusWorkspace.TemplateStatus { + templateStatusItemMap := resourceIBMSchematicsJobJobStatusTemplateToMap(templateStatusItem) + templateStatus = append(templateStatus, templateStatusItemMap) + // TODO: handle TemplateStatus of type TypeList -- list of non-primitive, not model items + } + jobStatusWorkspaceMap["template_status"] = templateStatus + } + if jobStatusWorkspace.UpdatedAt != nil { + jobStatusWorkspaceMap["updated_at"] = jobStatusWorkspace.UpdatedAt.String() + } + + return jobStatusWorkspaceMap +} + +func resourceIBMSchematicsJobJobStatusFlowToMap(jobStatusFlow schematicsv1.JobStatusFlow) map[string]interface{} { + jobStatusFlowMap := map[string]interface{}{} + + if jobStatusFlow.FlowID != nil { + jobStatusFlowMap["flow_id"] = jobStatusFlow.FlowID + } + if jobStatusFlow.FlowName != nil { + jobStatusFlowMap["flow_name"] = jobStatusFlow.FlowName + } + if jobStatusFlow.StatusCode != nil { + jobStatusFlowMap["status_code"] = jobStatusFlow.StatusCode + } + if jobStatusFlow.StatusMessage != nil { + jobStatusFlowMap["status_message"] = jobStatusFlow.StatusMessage + } + if jobStatusFlow.Workitems != nil { + workitems := []map[string]interface{}{} + for _, workitemsItem := range jobStatusFlow.Workitems { + workitemsItemMap := resourceIBMSchematicsJobJobStatusWorkitemToMap(workitemsItem) + workitems = append(workitems, workitemsItemMap) + // TODO: handle Workitems of type TypeList -- list of non-primitive, not model items + } + jobStatusFlowMap["workitems"] = workitems + } + if jobStatusFlow.UpdatedAt != nil { + jobStatusFlowMap["updated_at"] = jobStatusFlow.UpdatedAt.String() + } + + return jobStatusFlowMap +} + +func resourceIBMSchematicsJobJobStatusWorkitemToMap(jobStatusWorkitem schematicsv1.JobStatusWorkitem) map[string]interface{} { + jobStatusWorkitemMap := map[string]interface{}{} + + if jobStatusWorkitem.WorkspaceID != nil { + jobStatusWorkitemMap["workspace_id"] = jobStatusWorkitem.WorkspaceID + } + if jobStatusWorkitem.WorkspaceName != nil { + jobStatusWorkitemMap["workspace_name"] = jobStatusWorkitem.WorkspaceName + } + if jobStatusWorkitem.JobID != nil { + jobStatusWorkitemMap["job_id"] = jobStatusWorkitem.JobID + } + if jobStatusWorkitem.StatusCode != nil { + jobStatusWorkitemMap["status_code"] = jobStatusWorkitem.StatusCode + } + if jobStatusWorkitem.StatusMessage != nil { + jobStatusWorkitemMap["status_message"] = jobStatusWorkitem.StatusMessage + } + if jobStatusWorkitem.UpdatedAt != nil { + jobStatusWorkitemMap["updated_at"] = jobStatusWorkitem.UpdatedAt.String() + } + + return jobStatusWorkitemMap +} + +func resourceIBMSchematicsJobJobStatusTemplateToMap(jobStatusTemplate schematicsv1.JobStatusTemplate) map[string]interface{} { + jobStatusTemplateMap := map[string]interface{}{} + + if jobStatusTemplate.TemplateID != nil { + jobStatusTemplateMap["template_id"] = jobStatusTemplate.TemplateID + } + if jobStatusTemplate.TemplateName != nil { + jobStatusTemplateMap["template_name"] = jobStatusTemplate.TemplateName + } + if jobStatusTemplate.FlowIndex != nil { + jobStatusTemplateMap["flow_index"] = flex.IntValue(jobStatusTemplate.FlowIndex) + } + if jobStatusTemplate.StatusCode != nil { + jobStatusTemplateMap["status_code"] = jobStatusTemplate.StatusCode + } + if jobStatusTemplate.StatusMessage != nil { + jobStatusTemplateMap["status_message"] = jobStatusTemplate.StatusMessage + } + if jobStatusTemplate.UpdatedAt != nil { + jobStatusTemplateMap["updated_at"] = jobStatusTemplate.UpdatedAt.String() + } + + return jobStatusTemplateMap +} + +func resourceIBMSchematicsJobJobStatusActionToMap(jobStatusAction schematicsv1.JobStatusAction) map[string]interface{} { + jobStatusActionMap := map[string]interface{}{} + + if jobStatusAction.ActionName != nil { + jobStatusActionMap["action_name"] = jobStatusAction.ActionName + } + if jobStatusAction.StatusCode != nil { + jobStatusActionMap["status_code"] = jobStatusAction.StatusCode + } + if jobStatusAction.StatusMessage != nil { + jobStatusActionMap["status_message"] = jobStatusAction.StatusMessage + } + if jobStatusAction.BastionStatusCode != nil { + jobStatusActionMap["bastion_status_code"] = jobStatusAction.BastionStatusCode + } + if jobStatusAction.BastionStatusMessage != nil { + jobStatusActionMap["bastion_status_message"] = jobStatusAction.BastionStatusMessage + } + if jobStatusAction.TargetsStatusCode != nil { + jobStatusActionMap["targets_status_code"] = jobStatusAction.TargetsStatusCode + } + if jobStatusAction.TargetsStatusMessage != nil { + jobStatusActionMap["targets_status_message"] = jobStatusAction.TargetsStatusMessage + } + if jobStatusAction.UpdatedAt != nil { + jobStatusActionMap["updated_at"] = jobStatusAction.UpdatedAt.String() + } + + return jobStatusActionMap +} + +func resourceIBMSchematicsJobJobStatusSystemToMap(jobStatusSystem schematicsv1.JobStatusSystem) map[string]interface{} { + jobStatusSystemMap := map[string]interface{}{} + + if jobStatusSystem.SystemStatusMessage != nil { + jobStatusSystemMap["system_status_message"] = jobStatusSystem.SystemStatusMessage + } + if jobStatusSystem.SystemStatusCode != nil { + jobStatusSystemMap["system_status_code"] = jobStatusSystem.SystemStatusCode + } + if jobStatusSystem.SchematicsResourceStatus != nil { + schematicsResourceStatus := []map[string]interface{}{} + for _, schematicsResourceStatusItem := range jobStatusSystem.SchematicsResourceStatus { + schematicsResourceStatusItemMap := resourceIBMSchematicsJobJobStatusSchematicsResourcesToMap(schematicsResourceStatusItem) + schematicsResourceStatus = append(schematicsResourceStatus, schematicsResourceStatusItemMap) + // TODO: handle SchematicsResourceStatus of type TypeList -- list of non-primitive, not model items + } + jobStatusSystemMap["schematics_resource_status"] = schematicsResourceStatus + } + if jobStatusSystem.UpdatedAt != nil { + jobStatusSystemMap["updated_at"] = jobStatusSystem.UpdatedAt.String() + } + + return jobStatusSystemMap +} + +func resourceIBMSchematicsJobJobStatusSchematicsResourcesToMap(jobStatusSchematicsResources schematicsv1.JobStatusSchematicsResources) map[string]interface{} { + jobStatusSchematicsResourcesMap := map[string]interface{}{} + + if jobStatusSchematicsResources.StatusCode != nil { + jobStatusSchematicsResourcesMap["status_code"] = jobStatusSchematicsResources.StatusCode + } + if jobStatusSchematicsResources.StatusMessage != nil { + jobStatusSchematicsResourcesMap["status_message"] = jobStatusSchematicsResources.StatusMessage + } + if jobStatusSchematicsResources.SchematicsResourceID != nil { + jobStatusSchematicsResourcesMap["schematics_resource_id"] = jobStatusSchematicsResources.SchematicsResourceID + } + if jobStatusSchematicsResources.UpdatedAt != nil { + jobStatusSchematicsResourcesMap["updated_at"] = jobStatusSchematicsResources.UpdatedAt.String() + } + + return jobStatusSchematicsResourcesMap +} + +func resourceIBMSchematicsJobJobDataToMap(jobData schematicsv1.JobData) map[string]interface{} { + jobDataMap := map[string]interface{}{} + + jobDataMap["job_type"] = jobData.JobType + if jobData.WorkspaceJobData != nil { + WorkspaceJobDataMap := resourceIBMSchematicsJobJobDataWorkspaceToMap(*jobData.WorkspaceJobData) + jobDataMap["workspace_job_data"] = []map[string]interface{}{WorkspaceJobDataMap} + } + if jobData.ActionJobData != nil { + ActionJobDataMap := resourceIBMSchematicsJobJobDataActionToMap(*jobData.ActionJobData) + jobDataMap["action_job_data"] = []map[string]interface{}{ActionJobDataMap} + } + if jobData.SystemJobData != nil { + SystemJobDataMap := resourceIBMSchematicsJobJobDataSystemToMap(*jobData.SystemJobData) + jobDataMap["system_job_data"] = []map[string]interface{}{SystemJobDataMap} + } + if jobData.FlowJobData != nil { + FlowJobDataMap := resourceIBMSchematicsJobJobDataFlowToMap(*jobData.FlowJobData) + jobDataMap["flow_job_data"] = []map[string]interface{}{FlowJobDataMap} + } + + return jobDataMap +} + +func resourceIBMSchematicsJobJobDataWorkspaceToMap(jobDataWorkspace schematicsv1.JobDataWorkspace) map[string]interface{} { + jobDataWorkspaceMap := map[string]interface{}{} + + if jobDataWorkspace.WorkspaceName != nil { + jobDataWorkspaceMap["workspace_name"] = jobDataWorkspace.WorkspaceName + } + if jobDataWorkspace.FlowID != nil { + jobDataWorkspaceMap["flow_id"] = jobDataWorkspace.FlowID + } + if jobDataWorkspace.FlowName != nil { + jobDataWorkspaceMap["flow_name"] = jobDataWorkspace.FlowName + } + if jobDataWorkspace.Inputs != nil { + inputs := []map[string]interface{}{} + for _, inputsItem := range jobDataWorkspace.Inputs { + inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) + inputs = append(inputs, inputsItemMap) + // TODO: handle Inputs of type TypeList -- list of non-primitive, not model items + } + jobDataWorkspaceMap["inputs"] = inputs + } + if jobDataWorkspace.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range jobDataWorkspace.Outputs { + outputsItemMap := resourceIBMSchematicsJobVariableDataToMap(outputsItem) + outputs = append(outputs, outputsItemMap) + // TODO: handle Outputs of type TypeList -- list of non-primitive, not model items + } + jobDataWorkspaceMap["outputs"] = outputs + } + if jobDataWorkspace.Settings != nil { + settings := []map[string]interface{}{} + for _, settingsItem := range jobDataWorkspace.Settings { + settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) + settings = append(settings, settingsItemMap) + // TODO: handle Settings of type TypeList -- list of non-primitive, not model items + } + jobDataWorkspaceMap["settings"] = settings + } + if jobDataWorkspace.TemplateData != nil { + templateData := []map[string]interface{}{} + for _, templateDataItem := range jobDataWorkspace.TemplateData { + templateDataItemMap := resourceIBMSchematicsJobJobDataTemplateToMap(templateDataItem) + templateData = append(templateData, templateDataItemMap) + // TODO: handle TemplateData of type TypeList -- list of non-primitive, not model items + } + jobDataWorkspaceMap["template_data"] = templateData + } + if jobDataWorkspace.UpdatedAt != nil { + jobDataWorkspaceMap["updated_at"] = jobDataWorkspace.UpdatedAt.String() + } + + return jobDataWorkspaceMap +} + +func resourceIBMSchematicsJobJobDataTemplateToMap(jobDataTemplate schematicsv1.JobDataTemplate) map[string]interface{} { + jobDataTemplateMap := map[string]interface{}{} + + if jobDataTemplate.TemplateID != nil { + jobDataTemplateMap["template_id"] = jobDataTemplate.TemplateID + } + if jobDataTemplate.TemplateName != nil { + jobDataTemplateMap["template_name"] = jobDataTemplate.TemplateName + } + if jobDataTemplate.FlowIndex != nil { + jobDataTemplateMap["flow_index"] = flex.IntValue(jobDataTemplate.FlowIndex) + } + if jobDataTemplate.Inputs != nil { + inputs := []map[string]interface{}{} + for _, inputsItem := range jobDataTemplate.Inputs { + inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) + inputs = append(inputs, inputsItemMap) + // TODO: handle Inputs of type TypeList -- list of non-primitive, not model items + } + jobDataTemplateMap["inputs"] = inputs + } + if jobDataTemplate.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range jobDataTemplate.Outputs { + outputsItemMap := resourceIBMSchematicsJobVariableDataToMap(outputsItem) + outputs = append(outputs, outputsItemMap) + // TODO: handle Outputs of type TypeList -- list of non-primitive, not model items + } + jobDataTemplateMap["outputs"] = outputs + } + if jobDataTemplate.Settings != nil { + settings := []map[string]interface{}{} + for _, settingsItem := range jobDataTemplate.Settings { + settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) + settings = append(settings, settingsItemMap) + // TODO: handle Settings of type TypeList -- list of non-primitive, not model items + } + jobDataTemplateMap["settings"] = settings + } + if jobDataTemplate.UpdatedAt != nil { + jobDataTemplateMap["updated_at"] = jobDataTemplate.UpdatedAt.String() + } + + return jobDataTemplateMap +} + +func resourceIBMSchematicsJobJobDataActionToMap(jobDataAction schematicsv1.JobDataAction) map[string]interface{} { + jobDataActionMap := map[string]interface{}{} + + if jobDataAction.ActionName != nil { + jobDataActionMap["action_name"] = jobDataAction.ActionName + } + if jobDataAction.Inputs != nil { + inputs := []map[string]interface{}{} + for _, inputsItem := range jobDataAction.Inputs { + inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) + inputs = append(inputs, inputsItemMap) + // TODO: handle Inputs of type TypeList -- list of non-primitive, not model items + } + jobDataActionMap["inputs"] = inputs + } + if jobDataAction.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range jobDataAction.Outputs { + outputsItemMap := resourceIBMSchematicsJobVariableDataToMap(outputsItem) + outputs = append(outputs, outputsItemMap) + // TODO: handle Outputs of type TypeList -- list of non-primitive, not model items + } + jobDataActionMap["outputs"] = outputs + } + if jobDataAction.Settings != nil { + settings := []map[string]interface{}{} + for _, settingsItem := range jobDataAction.Settings { + settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) + settings = append(settings, settingsItemMap) + // TODO: handle Settings of type TypeList -- list of non-primitive, not model items + } + jobDataActionMap["settings"] = settings + } + if jobDataAction.UpdatedAt != nil { + jobDataActionMap["updated_at"] = jobDataAction.UpdatedAt.String() + } + if jobDataAction.InventoryRecord != nil { + InventoryRecordMap := resourceIBMSchematicsJobInventoryResourceRecordToMap(*jobDataAction.InventoryRecord) + jobDataActionMap["inventory_record"] = []map[string]interface{}{InventoryRecordMap} + } + if jobDataAction.MaterializedInventory != nil { + jobDataActionMap["materialized_inventory"] = jobDataAction.MaterializedInventory + } + + return jobDataActionMap +} + +func resourceIBMSchematicsJobInventoryResourceRecordToMap(inventoryResourceRecord schematicsv1.InventoryResourceRecord) map[string]interface{} { + inventoryResourceRecordMap := map[string]interface{}{} + + if inventoryResourceRecord.Name != nil { + inventoryResourceRecordMap["name"] = inventoryResourceRecord.Name + } + if inventoryResourceRecord.ID != nil { + inventoryResourceRecordMap["id"] = inventoryResourceRecord.ID + } + if inventoryResourceRecord.Description != nil { + inventoryResourceRecordMap["description"] = inventoryResourceRecord.Description + } + if inventoryResourceRecord.Location != nil { + inventoryResourceRecordMap["location"] = inventoryResourceRecord.Location + } + if inventoryResourceRecord.ResourceGroup != nil { + inventoryResourceRecordMap["resource_group"] = inventoryResourceRecord.ResourceGroup + } + if inventoryResourceRecord.CreatedAt != nil { + inventoryResourceRecordMap["created_at"] = inventoryResourceRecord.CreatedAt.String() + } + if inventoryResourceRecord.CreatedBy != nil { + inventoryResourceRecordMap["created_by"] = inventoryResourceRecord.CreatedBy + } + if inventoryResourceRecord.UpdatedAt != nil { + inventoryResourceRecordMap["updated_at"] = inventoryResourceRecord.UpdatedAt.String() + } + if inventoryResourceRecord.UpdatedBy != nil { + inventoryResourceRecordMap["updated_by"] = inventoryResourceRecord.UpdatedBy + } + if inventoryResourceRecord.InventoriesIni != nil { + inventoryResourceRecordMap["inventories_ini"] = inventoryResourceRecord.InventoriesIni + } + if inventoryResourceRecord.ResourceQueries != nil { + inventoryResourceRecordMap["resource_queries"] = inventoryResourceRecord.ResourceQueries + } + + return inventoryResourceRecordMap +} + +func resourceIBMSchematicsJobJobDataSystemToMap(jobDataSystem schematicsv1.JobDataSystem) map[string]interface{} { + jobDataSystemMap := map[string]interface{}{} + + if jobDataSystem.KeyID != nil { + jobDataSystemMap["key_id"] = jobDataSystem.KeyID + } + if jobDataSystem.SchematicsResourceID != nil { + jobDataSystemMap["schematics_resource_id"] = jobDataSystem.SchematicsResourceID + } + if jobDataSystem.UpdatedAt != nil { + jobDataSystemMap["updated_at"] = jobDataSystem.UpdatedAt.String() + } + + return jobDataSystemMap +} + +func resourceIBMSchematicsJobJobDataFlowToMap(jobDataFlow schematicsv1.JobDataFlow) map[string]interface{} { + jobDataFlowMap := map[string]interface{}{} + + if jobDataFlow.FlowID != nil { + jobDataFlowMap["flow_id"] = jobDataFlow.FlowID + } + if jobDataFlow.FlowName != nil { + jobDataFlowMap["flow_name"] = jobDataFlow.FlowName + } + if jobDataFlow.Workitems != nil { + workitems := []map[string]interface{}{} + for _, workitemsItem := range jobDataFlow.Workitems { + workitemsItemMap := resourceIBMSchematicsJobJobDataWorkItemToMap(workitemsItem) + workitems = append(workitems, workitemsItemMap) + // TODO: handle Workitems of type TypeList -- list of non-primitive, not model items + } + jobDataFlowMap["workitems"] = workitems + } + if jobDataFlow.UpdatedAt != nil { + jobDataFlowMap["updated_at"] = jobDataFlow.UpdatedAt.String() + } + + return jobDataFlowMap +} + +func resourceIBMSchematicsJobJobDataWorkItemToMap(jobDataWorkItem schematicsv1.JobDataWorkItem) map[string]interface{} { + jobDataWorkItemMap := map[string]interface{}{} + + if jobDataWorkItem.CommandObjectID != nil { + jobDataWorkItemMap["command_object_id"] = jobDataWorkItem.CommandObjectID + } + if jobDataWorkItem.CommandObjectName != nil { + jobDataWorkItemMap["command_object_name"] = jobDataWorkItem.CommandObjectName + } + if jobDataWorkItem.Layers != nil { + jobDataWorkItemMap["layers"] = jobDataWorkItem.Layers + } + if jobDataWorkItem.SourceType != nil { + jobDataWorkItemMap["source_type"] = jobDataWorkItem.SourceType + } + if jobDataWorkItem.Source != nil { + SourceMap := resourceIBMSchematicsJobExternalSourceToMap(*jobDataWorkItem.Source) + jobDataWorkItemMap["source"] = []map[string]interface{}{SourceMap} + } + if jobDataWorkItem.Inputs != nil { + inputs := []map[string]interface{}{} + for _, inputsItem := range jobDataWorkItem.Inputs { + inputsItemMap := resourceIBMSchematicsJobVariableDataToMap(inputsItem) + inputs = append(inputs, inputsItemMap) + // TODO: handle Inputs of type TypeList -- list of non-primitive, not model items + } + jobDataWorkItemMap["inputs"] = inputs + } + if jobDataWorkItem.Outputs != nil { + outputs := []map[string]interface{}{} + for _, outputsItem := range jobDataWorkItem.Outputs { + outputsItemMap := resourceIBMSchematicsJobVariableDataToMap(outputsItem) + outputs = append(outputs, outputsItemMap) + // TODO: handle Outputs of type TypeList -- list of non-primitive, not model items + } + jobDataWorkItemMap["outputs"] = outputs + } + if jobDataWorkItem.Settings != nil { + settings := []map[string]interface{}{} + for _, settingsItem := range jobDataWorkItem.Settings { + settingsItemMap := resourceIBMSchematicsJobVariableDataToMap(settingsItem) + settings = append(settings, settingsItemMap) + // TODO: handle Settings of type TypeList -- list of non-primitive, not model items + } + jobDataWorkItemMap["settings"] = settings + } + if jobDataWorkItem.LastJob != nil { + LastJobMap := resourceIBMSchematicsJobJobDataWorkItemLastJobToMap(*jobDataWorkItem.LastJob) + jobDataWorkItemMap["last_job"] = []map[string]interface{}{LastJobMap} + } + if jobDataWorkItem.UpdatedAt != nil { + jobDataWorkItemMap["updated_at"] = jobDataWorkItem.UpdatedAt.String() + } + + return jobDataWorkItemMap +} + +func resourceIBMSchematicsJobExternalSourceToMap(externalSource schematicsv1.ExternalSource) map[string]interface{} { + externalSourceMap := map[string]interface{}{} + + externalSourceMap["source_type"] = externalSource.SourceType + if externalSource.Git != nil { + GitMap := resourceIBMSchematicsJobExternalSourceGitToMap(*externalSource.Git) + externalSourceMap["git"] = []map[string]interface{}{GitMap} + } + if externalSource.Catalog != nil { + CatalogMap := resourceIBMSchematicsJobExternalSourceCatalogToMap(*externalSource.Catalog) + externalSourceMap["catalog"] = []map[string]interface{}{CatalogMap} + } + // if externalSource.CosBucket != nil { + // CosBucketMap := resourceIBMSchematicsJobExternalSourceCosBucketToMap(*externalSource.CosBucket) + // externalSourceMap["cos_bucket"] = []map[string]interface{}{CosBucketMap} + // } + + return externalSourceMap +} + +func resourceIBMSchematicsJobExternalSourceGitToMap(externalSourceGit schematicsv1.GitSource) map[string]interface{} { + externalSourceGitMap := map[string]interface{}{} + + if externalSourceGit.ComputedGitRepoURL != nil { + externalSourceGitMap["computed_git_repo_url"] = externalSourceGit.ComputedGitRepoURL + } + if externalSourceGit.GitRepoURL != nil { + externalSourceGitMap["git_repo_url"] = externalSourceGit.GitRepoURL + } + if externalSourceGit.GitToken != nil { + externalSourceGitMap["git_token"] = externalSourceGit.GitToken + } + if externalSourceGit.GitRepoFolder != nil { + externalSourceGitMap["git_repo_folder"] = externalSourceGit.GitRepoFolder + } + if externalSourceGit.GitRelease != nil { + externalSourceGitMap["git_release"] = externalSourceGit.GitRelease + } + if externalSourceGit.GitBranch != nil { + externalSourceGitMap["git_branch"] = externalSourceGit.GitBranch + } + + return externalSourceGitMap +} + +func resourceIBMSchematicsJobExternalSourceCatalogToMap(externalSourceCatalog schematicsv1.CatalogSource) map[string]interface{} { + externalSourceCatalogMap := map[string]interface{}{} + + if externalSourceCatalog.CatalogName != nil { + externalSourceCatalogMap["catalog_name"] = externalSourceCatalog.CatalogName + } + if externalSourceCatalog.OfferingName != nil { + externalSourceCatalogMap["offering_name"] = externalSourceCatalog.OfferingName + } + if externalSourceCatalog.OfferingVersion != nil { + externalSourceCatalogMap["offering_version"] = externalSourceCatalog.OfferingVersion + } + if externalSourceCatalog.OfferingKind != nil { + externalSourceCatalogMap["offering_kind"] = externalSourceCatalog.OfferingKind + } + if externalSourceCatalog.OfferingID != nil { + externalSourceCatalogMap["offering_id"] = externalSourceCatalog.OfferingID + } + if externalSourceCatalog.OfferingVersionID != nil { + externalSourceCatalogMap["offering_version_id"] = externalSourceCatalog.OfferingVersionID + } + if externalSourceCatalog.OfferingRepoURL != nil { + externalSourceCatalogMap["offering_repo_url"] = externalSourceCatalog.OfferingRepoURL + } + + return externalSourceCatalogMap +} + +// func resourceIBMSchematicsJobExternalSourceCosBucketToMap(externalSourceCosBucket schematicsv1.ExternalSourceCosBucket) map[string]interface{} { +// externalSourceCosBucketMap := map[string]interface{}{} + +// if externalSourceCosBucket.CosBucketURL != nil { +// externalSourceCosBucketMap["cos_bucket_url"] = externalSourceCosBucket.CosBucketURL +// } + +// return externalSourceCosBucketMap +// } + +func resourceIBMSchematicsJobJobDataWorkItemLastJobToMap(jobDataWorkItemLastJob schematicsv1.JobDataWorkItemLastJob) map[string]interface{} { + jobDataWorkItemLastJobMap := map[string]interface{}{} + + if jobDataWorkItemLastJob.CommandObject != nil { + jobDataWorkItemLastJobMap["command_object"] = jobDataWorkItemLastJob.CommandObject + } + if jobDataWorkItemLastJob.CommandObjectName != nil { + jobDataWorkItemLastJobMap["command_object_name"] = jobDataWorkItemLastJob.CommandObjectName + } + if jobDataWorkItemLastJob.CommandObjectID != nil { + jobDataWorkItemLastJobMap["command_object_id"] = jobDataWorkItemLastJob.CommandObjectID + } + if jobDataWorkItemLastJob.CommandName != nil { + jobDataWorkItemLastJobMap["command_name"] = jobDataWorkItemLastJob.CommandName + } + if jobDataWorkItemLastJob.JobID != nil { + jobDataWorkItemLastJobMap["job_id"] = jobDataWorkItemLastJob.JobID + } + if jobDataWorkItemLastJob.JobStatus != nil { + jobDataWorkItemLastJobMap["job_status"] = jobDataWorkItemLastJob.JobStatus + } + + return jobDataWorkItemLastJobMap +} + +func resourceIBMSchematicsJobBastionResourceDefinitionToMap(bastionResourceDefinition schematicsv1.BastionResourceDefinition) map[string]interface{} { + bastionResourceDefinitionMap := map[string]interface{}{} + + if bastionResourceDefinition.Name != nil { + bastionResourceDefinitionMap["name"] = bastionResourceDefinition.Name + } + if bastionResourceDefinition.Host != nil { + bastionResourceDefinitionMap["host"] = bastionResourceDefinition.Host + } + + return bastionResourceDefinitionMap +} + +func resourceIBMSchematicsJobJobLogSummaryToMap(jobLogSummary schematicsv1.JobLogSummary) map[string]interface{} { + jobLogSummaryMap := map[string]interface{}{} + + if jobLogSummary.JobID != nil { + jobLogSummaryMap["job_id"] = jobLogSummary.JobID + } + if jobLogSummary.JobType != nil { + jobLogSummaryMap["job_type"] = jobLogSummary.JobType + } + if jobLogSummary.LogStartAt != nil { + jobLogSummaryMap["log_start_at"] = jobLogSummary.LogStartAt.String() + } + if jobLogSummary.LogAnalyzedTill != nil { + jobLogSummaryMap["log_analyzed_till"] = jobLogSummary.LogAnalyzedTill.String() + } + if jobLogSummary.ElapsedTime != nil { + jobLogSummaryMap["elapsed_time"] = jobLogSummary.ElapsedTime + } + if jobLogSummary.LogErrors != nil { + logErrors := []map[string]interface{}{} + for _, logErrorsItem := range jobLogSummary.LogErrors { + logErrorsItemMap := resourceIBMSchematicsJobJobLogSummaryLogErrorsToMap(logErrorsItem) + logErrors = append(logErrors, logErrorsItemMap) + // TODO: handle LogErrors of type TypeList -- list of non-primitive, not model items + } + jobLogSummaryMap["log_errors"] = logErrors + } + if jobLogSummary.RepoDownloadJob != nil { + RepoDownloadJobMap := resourceIBMSchematicsJobJobLogSummaryRepoDownloadJobToMap(*jobLogSummary.RepoDownloadJob) + jobLogSummaryMap["repo_download_job"] = []map[string]interface{}{RepoDownloadJobMap} + } + if jobLogSummary.WorkspaceJob != nil { + WorkspaceJobMap := resourceIBMSchematicsJobJobLogSummaryWorkspaceJobToMap(*jobLogSummary.WorkspaceJob) + jobLogSummaryMap["workspace_job"] = []map[string]interface{}{WorkspaceJobMap} + } + if jobLogSummary.FlowJob != nil { + FlowJobMap := resourceIBMSchematicsJobJobLogSummaryFlowJobToMap(*jobLogSummary.FlowJob) + jobLogSummaryMap["flow_job"] = []map[string]interface{}{FlowJobMap} + } + if jobLogSummary.ActionJob != nil { + ActionJobMap := resourceIBMSchematicsJobJobLogSummaryActionJobToMap(*jobLogSummary.ActionJob) + jobLogSummaryMap["action_job"] = []map[string]interface{}{ActionJobMap} + } + if jobLogSummary.SystemJob != nil { + SystemJobMap := resourceIBMSchematicsJobJobLogSummarySystemJobToMap(*jobLogSummary.SystemJob) + jobLogSummaryMap["system_job"] = []map[string]interface{}{SystemJobMap} + } + + return jobLogSummaryMap +} + +func resourceIBMSchematicsJobJobLogSummaryLogErrorsToMap(jobLogSummaryLogErrors schematicsv1.JobLogSummaryLogErrors) map[string]interface{} { + jobLogSummaryLogErrorsMap := map[string]interface{}{} + + if jobLogSummaryLogErrors.ErrorCode != nil { + jobLogSummaryLogErrorsMap["error_code"] = jobLogSummaryLogErrors.ErrorCode + } + if jobLogSummaryLogErrors.ErrorMsg != nil { + jobLogSummaryLogErrorsMap["error_msg"] = jobLogSummaryLogErrors.ErrorMsg + } + if jobLogSummaryLogErrors.ErrorCount != nil { + jobLogSummaryLogErrorsMap["error_count"] = jobLogSummaryLogErrors.ErrorCount + } + + return jobLogSummaryLogErrorsMap +} + +func resourceIBMSchematicsJobJobLogSummaryRepoDownloadJobToMap(jobLogSummaryRepoDownloadJob schematicsv1.JobLogSummaryRepoDownloadJob) map[string]interface{} { + jobLogSummaryRepoDownloadJobMap := map[string]interface{}{} + + if jobLogSummaryRepoDownloadJob.ScannedFileCount != nil { + jobLogSummaryRepoDownloadJobMap["scanned_file_count"] = jobLogSummaryRepoDownloadJob.ScannedFileCount + } + if jobLogSummaryRepoDownloadJob.QuarantinedFileCount != nil { + jobLogSummaryRepoDownloadJobMap["quarantined_file_count"] = jobLogSummaryRepoDownloadJob.QuarantinedFileCount + } + if jobLogSummaryRepoDownloadJob.DetectedFiletype != nil { + jobLogSummaryRepoDownloadJobMap["detected_filetype"] = jobLogSummaryRepoDownloadJob.DetectedFiletype + } + if jobLogSummaryRepoDownloadJob.InputsCount != nil { + jobLogSummaryRepoDownloadJobMap["inputs_count"] = jobLogSummaryRepoDownloadJob.InputsCount + } + if jobLogSummaryRepoDownloadJob.OutputsCount != nil { + jobLogSummaryRepoDownloadJobMap["outputs_count"] = jobLogSummaryRepoDownloadJob.OutputsCount + } + + return jobLogSummaryRepoDownloadJobMap +} + +func resourceIBMSchematicsJobJobLogSummaryWorkspaceJobToMap(jobLogSummaryWorkspaceJob schematicsv1.JobLogSummaryWorkspaceJob) map[string]interface{} { + jobLogSummaryWorkspaceJobMap := map[string]interface{}{} + + if jobLogSummaryWorkspaceJob.ResourcesAdd != nil { + jobLogSummaryWorkspaceJobMap["resources_add"] = jobLogSummaryWorkspaceJob.ResourcesAdd + } + if jobLogSummaryWorkspaceJob.ResourcesModify != nil { + jobLogSummaryWorkspaceJobMap["resources_modify"] = jobLogSummaryWorkspaceJob.ResourcesModify + } + if jobLogSummaryWorkspaceJob.ResourcesDestroy != nil { + jobLogSummaryWorkspaceJobMap["resources_destroy"] = jobLogSummaryWorkspaceJob.ResourcesDestroy + } + + return jobLogSummaryWorkspaceJobMap +} + +func resourceIBMSchematicsJobJobLogSummaryFlowJobToMap(jobLogSummaryFlowJob schematicsv1.JobLogSummaryFlowJob) map[string]interface{} { + jobLogSummaryFlowJobMap := map[string]interface{}{} + + if jobLogSummaryFlowJob.WorkitemsCompleted != nil { + jobLogSummaryFlowJobMap["workitems_completed"] = jobLogSummaryFlowJob.WorkitemsCompleted + } + if jobLogSummaryFlowJob.WorkitemsPending != nil { + jobLogSummaryFlowJobMap["workitems_pending"] = jobLogSummaryFlowJob.WorkitemsPending + } + if jobLogSummaryFlowJob.WorkitemsFailed != nil { + jobLogSummaryFlowJobMap["workitems_failed"] = jobLogSummaryFlowJob.WorkitemsFailed + } + if jobLogSummaryFlowJob.Workitems != nil { + workitems := []map[string]interface{}{} + for _, workitemsItem := range jobLogSummaryFlowJob.Workitems { + workitemsItemMap := resourceIBMSchematicsJobJobLogSummaryWorkitemsToMap(workitemsItem) + workitems = append(workitems, workitemsItemMap) + // TODO: handle Workitems of type TypeList -- list of non-primitive, not model items + } + jobLogSummaryFlowJobMap["workitems"] = workitems + } + + return jobLogSummaryFlowJobMap +} + +func resourceIBMSchematicsJobJobLogSummaryWorkitemsToMap(jobLogSummaryWorkitems schematicsv1.JobLogSummaryWorkitems) map[string]interface{} { + jobLogSummaryWorkitemsMap := map[string]interface{}{} + + if jobLogSummaryWorkitems.WorkspaceID != nil { + jobLogSummaryWorkitemsMap["workspace_id"] = jobLogSummaryWorkitems.WorkspaceID + } + if jobLogSummaryWorkitems.JobID != nil { + jobLogSummaryWorkitemsMap["job_id"] = jobLogSummaryWorkitems.JobID + } + if jobLogSummaryWorkitems.ResourcesAdd != nil { + jobLogSummaryWorkitemsMap["resources_add"] = jobLogSummaryWorkitems.ResourcesAdd + } + if jobLogSummaryWorkitems.ResourcesModify != nil { + jobLogSummaryWorkitemsMap["resources_modify"] = jobLogSummaryWorkitems.ResourcesModify + } + if jobLogSummaryWorkitems.ResourcesDestroy != nil { + jobLogSummaryWorkitemsMap["resources_destroy"] = jobLogSummaryWorkitems.ResourcesDestroy + } + if jobLogSummaryWorkitems.LogURL != nil { + jobLogSummaryWorkitemsMap["log_url"] = jobLogSummaryWorkitems.LogURL + } + + return jobLogSummaryWorkitemsMap +} + +func resourceIBMSchematicsJobJobLogSummaryActionJobToMap(jobLogSummaryActionJob schematicsv1.JobLogSummaryActionJob) map[string]interface{} { + jobLogSummaryActionJobMap := map[string]interface{}{} + + if jobLogSummaryActionJob.TargetCount != nil { + jobLogSummaryActionJobMap["target_count"] = jobLogSummaryActionJob.TargetCount + } + if jobLogSummaryActionJob.TaskCount != nil { + jobLogSummaryActionJobMap["task_count"] = jobLogSummaryActionJob.TaskCount + } + if jobLogSummaryActionJob.PlayCount != nil { + jobLogSummaryActionJobMap["play_count"] = jobLogSummaryActionJob.PlayCount + } + if jobLogSummaryActionJob.Recap != nil { + RecapMap := resourceIBMSchematicsJobJobLogSummaryActionJobRecapToMap(*jobLogSummaryActionJob.Recap) + jobLogSummaryActionJobMap["recap"] = []map[string]interface{}{RecapMap} + } + + return jobLogSummaryActionJobMap +} + +func resourceIBMSchematicsJobJobLogSummaryActionJobRecapToMap(jobLogSummaryActionJobRecap schematicsv1.JobLogSummaryActionJobRecap) map[string]interface{} { + jobLogSummaryActionJobRecapMap := map[string]interface{}{} + + if jobLogSummaryActionJobRecap.Target != nil { + jobLogSummaryActionJobRecapMap["target"] = jobLogSummaryActionJobRecap.Target + } + if jobLogSummaryActionJobRecap.Ok != nil { + jobLogSummaryActionJobRecapMap["ok"] = jobLogSummaryActionJobRecap.Ok + } + if jobLogSummaryActionJobRecap.Changed != nil { + jobLogSummaryActionJobRecapMap["changed"] = jobLogSummaryActionJobRecap.Changed + } + if jobLogSummaryActionJobRecap.Failed != nil { + jobLogSummaryActionJobRecapMap["failed"] = jobLogSummaryActionJobRecap.Failed + } + if jobLogSummaryActionJobRecap.Skipped != nil { + jobLogSummaryActionJobRecapMap["skipped"] = jobLogSummaryActionJobRecap.Skipped + } + if jobLogSummaryActionJobRecap.Unreachable != nil { + jobLogSummaryActionJobRecapMap["unreachable"] = jobLogSummaryActionJobRecap.Unreachable + } + + return jobLogSummaryActionJobRecapMap +} + +func resourceIBMSchematicsJobJobLogSummarySystemJobToMap(jobLogSummarySystemJob schematicsv1.JobLogSummarySystemJob) map[string]interface{} { + jobLogSummarySystemJobMap := map[string]interface{}{} + + if jobLogSummarySystemJob.TargetCount != nil { + jobLogSummarySystemJobMap["target_count"] = jobLogSummarySystemJob.TargetCount + } + if jobLogSummarySystemJob.Success != nil { + jobLogSummarySystemJobMap["success"] = jobLogSummarySystemJob.Success + } + if jobLogSummarySystemJob.Failed != nil { + jobLogSummarySystemJobMap["failed"] = jobLogSummarySystemJob.Failed + } + + return jobLogSummarySystemJobMap +} + +func resourceIBMSchematicsJobUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + + session, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + + iamRefreshToken := session.Config.IAMRefreshToken + jobIDSplit := strings.Split(d.Id(), ".") + region := jobIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + updateJobOptions := &schematicsv1.UpdateJobOptions{} + + updateJobOptions.SetJobID(d.Id()) + updateJobOptions.SetRefreshToken(iamRefreshToken) + + if _, ok := d.GetOk("command_object"); ok { + updateJobOptions.SetCommandObject(d.Get("command_object").(string)) + } + if _, ok := d.GetOk("command_object_id"); ok { + updateJobOptions.SetCommandObjectID(d.Get("command_object_id").(string)) + } + if _, ok := d.GetOk("command_name"); ok { + updateJobOptions.SetCommandName(d.Get("command_name").(string)) + } + if _, ok := d.GetOk("command_parameter"); ok { + updateJobOptions.SetCommandParameter(d.Get("command_parameter").(string)) + } + if _, ok := d.GetOk("command_options"); ok { + updateJobOptions.SetCommandOptions(flex.ExpandStringList(d.Get("command_options").([]interface{}))) + } + if _, ok := d.GetOk("job_inputs"); ok { + var jobInputs []schematicsv1.VariableData + for _, e := range d.Get("job_inputs").([]interface{}) { + value := e.(map[string]interface{}) + jobInputsItem := resourceIBMSchematicsJobMapToVariableData(value) + jobInputs = append(jobInputs, jobInputsItem) + } + updateJobOptions.SetInputs(jobInputs) + } + if _, ok := d.GetOk("job_env_settings"); ok { + var jobEnvSettings []schematicsv1.VariableData + for _, e := range d.Get("job_env_settings").([]interface{}) { + value := e.(map[string]interface{}) + jobEnvSettingsItem := resourceIBMSchematicsJobMapToVariableData(value) + jobEnvSettings = append(jobEnvSettings, jobEnvSettingsItem) + } + updateJobOptions.SetSettings(jobEnvSettings) + } + if _, ok := d.GetOk("tags"); ok { + updateJobOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + } + if _, ok := d.GetOk("location"); ok { + updateJobOptions.SetLocation(d.Get("location").(string)) + } + if _, ok := d.GetOk("status"); ok { + statusAttr := d.Get("status").([]interface{}) + if len(statusAttr) > 0 { + status := resourceIBMSchematicsJobMapToJobStatus(d.Get("status.0").(map[string]interface{})) + updateJobOptions.SetStatus(&status) + } + } + if _, ok := d.GetOk("data"); ok { + dataAttr := d.Get("data").([]interface{}) + if len(dataAttr) > 0 { + data := resourceIBMSchematicsJobMapToJobData(d.Get("data.0").(map[string]interface{})) + updateJobOptions.SetData(&data) + } + } + if _, ok := d.GetOk("bastion"); ok { + bastionAttr := d.Get("bastion").([]interface{}) + if len(bastionAttr) > 0 { + bastion := resourceIBMSchematicsJobMapToBastionResourceDefinition(d.Get("bastion.0").(map[string]interface{})) + updateJobOptions.SetBastion(&bastion) + } + } + if _, ok := d.GetOk("log_summary"); ok { + jobLogSummaryAttr := d.Get("log_summary").([]interface{}) + if len(jobLogSummaryAttr) > 0 { + logSummary := resourceIBMSchematicsJobMapToJobLogSummary(d.Get("log_summary.0").(map[string]interface{})) + updateJobOptions.SetLogSummary(&logSummary) + } + } + + _, response, err := schematicsClient.UpdateJobWithContext(context, updateJobOptions) + if err != nil { + log.Printf("[DEBUG] UpdateJobWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateJobWithContext failed %s\n%s", err, response)) + } + + return resourceIBMSchematicsJobRead(context, d, meta) +} + +func resourceIBMSchematicsJobDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + session, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + jobIDSplit := strings.Split(d.Id(), ".") + region := jobIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + deleteJobOptions := &schematicsv1.DeleteJobOptions{} + + iamRefreshToken := session.Config.IAMRefreshToken + deleteJobOptions.SetRefreshToken(iamRefreshToken) + + deleteJobOptions.SetJobID(d.Id()) + + response, err := schematicsClient.DeleteJobWithContext(context, deleteJobOptions) + if err != nil { + log.Printf("[DEBUG] DeleteJobWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteJobWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/resource_ibm_schematics_job_test.go b/ibm/service/schematics/resource_ibm_schematics_job_test.go similarity index 84% rename from ibm/resource_ibm_schematics_job_test.go rename to ibm/service/schematics/resource_ibm_schematics_job_test.go index 77b34a02a..fb877f786 100644 --- a/ibm/resource_ibm_schematics_job_test.go +++ b/ibm/service/schematics/resource_ibm_schematics_job_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package schematics_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,20 +19,20 @@ import ( func TestAccIBMSchematicsJobBasic(t *testing.T) { var conf schematicsv1.Job commandObject := "action" - commandObjectID := actionID + commandObjectID := acc.ActionID commandName := "ansible_playbook_run" commandParameter := "ssh_user.yml" commandObjectUpdate := "action" - commandObjectIDUpdate := actionID + commandObjectIDUpdate := acc.ActionID commandNameUpdate := "ansible_playbook_run" commandParameterUpdate := "ssh_user_updated.yml" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMSchematicsJobDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSchematicsJobConfig(commandObject, commandObjectID, commandName, commandParameter), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMSchematicsJobExists("ibm_schematics_job.schematics_job", conf), @@ -39,7 +42,7 @@ func TestAccIBMSchematicsJobBasic(t *testing.T) { resource.TestCheckResourceAttr("ibm_schematics_job.schematics_job", "command_parameter", commandParameter), ), }, - resource.TestStep{ + { Config: testAccCheckIBMSchematicsJobConfig(commandObjectUpdate, commandObjectIDUpdate, commandNameUpdate, commandParameterUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_schematics_job.schematics_job", "command_object", commandObjectUpdate), @@ -60,7 +63,7 @@ func testAccCheckIBMSchematicsJobConfig(commandObject string, commandObjectID st command_object_id = "%s" command_name = "%s" command_parameter = "%s" - location = "us-east" + location = "us" } `, commandObject, commandObjectID, commandName, commandParameter) } @@ -73,7 +76,7 @@ func testAccCheckIBMSchematicsJobExists(n string, obj schematicsv1.Job) resource return fmt.Errorf("Not found: %s", n) } - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() if err != nil { return err } @@ -93,7 +96,7 @@ func testAccCheckIBMSchematicsJobExists(n string, obj schematicsv1.Job) resource } func testAccCheckIBMSchematicsJobDestroy(s *terraform.State) error { - schematicsClient, err := testAccProvider.Meta().(ClientSession).SchematicsV1() + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() if err != nil { return err } @@ -112,7 +115,7 @@ func testAccCheckIBMSchematicsJobDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("schematics_job still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for schematics_job (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for schematics_job (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/schematics/resource_ibm_schematics_resource_query.go b/ibm/service/schematics/resource_ibm_schematics_resource_query.go new file mode 100644 index 000000000..ab9817a1b --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_resource_query.go @@ -0,0 +1,376 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func ResourceIBMSchematicsResourceQuery() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSchematicsResourceQueryCreate, + ReadContext: resourceIBMSchematicsResourceQueryRead, + UpdateContext: resourceIBMSchematicsResourceQueryUpdate, + DeleteContext: resourceIBMSchematicsResourceQueryDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_resource_query", "type"), + Description: "Resource type (cluster, vsi, icd, vpc).", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Resource query name.", + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_schematics_resource_query", "location"), + Description: "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + }, + "queries": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query_type": { + Type: schema.TypeString, + Optional: true, + Description: "Type of the query(workspaces).", + }, + "query_condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the resource query param.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "Value of the resource query param.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of resource query param variable.", + }, + }, + }, + }, + "query_select": { + Type: schema.TypeList, + Optional: true, + Description: "List of query selection parameters.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "Resource query creation time.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who created the Resource query.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Resource query updation time.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "Email address of user who updated the Resource query.", + }, + }, + } +} + +func ResourceIBMSchematicsResourceQueryValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "vsi", + }, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "eu-de, eu-gb, us-east, us-south", + }) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_schematics_resource_query", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMSchematicsResourceQueryCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + createResourceQueryOptions := &schematicsv1.CreateResourceQueryOptions{} + + if _, ok := d.GetOk("type"); ok { + createResourceQueryOptions.SetType(d.Get("type").(string)) + } + if _, ok := d.GetOk("name"); ok { + createResourceQueryOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("queries"); ok { + var queries []schematicsv1.ResourceQuery + for _, e := range d.Get("queries").([]interface{}) { + value := e.(map[string]interface{}) + queriesItem := resourceIBMSchematicsResourceQueryMapToResourceQuery(value) + queries = append(queries, queriesItem) + } + createResourceQueryOptions.SetQueries(queries) + } + + resourceQueryRecord, response, err := schematicsClient.CreateResourceQueryWithContext(context, createResourceQueryOptions) + if err != nil { + log.Printf("[DEBUG] CreateResourceQueryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateResourceQueryWithContext failed %s\n%s", err, response)) + } + + d.SetId(*resourceQueryRecord.ID) + + return resourceIBMSchematicsResourceQueryRead(context, d, meta) +} + +func resourceIBMSchematicsResourceQueryMapToResourceQuery(resourceQueryMap map[string]interface{}) schematicsv1.ResourceQuery { + resourceQuery := schematicsv1.ResourceQuery{} + + if resourceQueryMap["query_type"] != nil { + resourceQuery.QueryType = core.StringPtr(resourceQueryMap["query_type"].(string)) + } + if resourceQueryMap["query_condition"] != nil { + queryCondition := []schematicsv1.ResourceQueryParam{} + for _, queryConditionItem := range resourceQueryMap["query_condition"].([]interface{}) { + queryConditionItemModel := resourceIBMSchematicsResourceQueryMapToResourceQueryParam(queryConditionItem.(map[string]interface{})) + queryCondition = append(queryCondition, queryConditionItemModel) + } + resourceQuery.QueryCondition = queryCondition + } + if resourceQueryMap["query_select"] != nil { + querySelect := []string{} + for _, querySelectItem := range resourceQueryMap["query_select"].([]interface{}) { + querySelect = append(querySelect, querySelectItem.(string)) + } + resourceQuery.QuerySelect = querySelect + } + + return resourceQuery +} + +func resourceIBMSchematicsResourceQueryMapToResourceQueryParam(resourceQueryParamMap map[string]interface{}) schematicsv1.ResourceQueryParam { + resourceQueryParam := schematicsv1.ResourceQueryParam{} + + if resourceQueryParamMap["name"] != nil { + resourceQueryParam.Name = core.StringPtr(resourceQueryParamMap["name"].(string)) + } + if resourceQueryParamMap["value"] != nil { + resourceQueryParam.Value = core.StringPtr(resourceQueryParamMap["value"].(string)) + } + if resourceQueryParamMap["description"] != nil { + resourceQueryParam.Description = core.StringPtr(resourceQueryParamMap["description"].(string)) + } + + return resourceQueryParam +} + +func resourceIBMSchematicsResourceQueryRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + getResourcesQueryOptions := &schematicsv1.GetResourcesQueryOptions{} + + getResourcesQueryOptions.SetQueryID(d.Id()) + + resourceQueryRecord, response, err := schematicsClient.GetResourcesQueryWithContext(context, getResourcesQueryOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetResourcesQueryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetResourcesQueryWithContext failed %s\n%s", err, response)) + } + if err = d.Set("type", resourceQueryRecord.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("name", resourceQueryRecord.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if resourceQueryRecord.Queries != nil { + queries := []map[string]interface{}{} + for _, queriesItem := range resourceQueryRecord.Queries { + queriesItemMap := resourceIBMSchematicsResourceQueryResourceQueryToMap(queriesItem) + queries = append(queries, queriesItemMap) + } + if err = d.Set("queries", queries); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting queries: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(resourceQueryRecord.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("created_by", resourceQueryRecord.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("updated_at", flex.DateTimeToString(resourceQueryRecord.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + if err = d.Set("updated_by", resourceQueryRecord.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + + return nil +} + +func resourceIBMSchematicsResourceQueryResourceQueryToMap(resourceQuery schematicsv1.ResourceQuery) map[string]interface{} { + resourceQueryMap := map[string]interface{}{} + + if resourceQuery.QueryType != nil { + resourceQueryMap["query_type"] = resourceQuery.QueryType + } + if resourceQuery.QueryCondition != nil { + queryCondition := []map[string]interface{}{} + for _, queryConditionItem := range resourceQuery.QueryCondition { + queryConditionItemMap := resourceIBMSchematicsResourceQueryResourceQueryParamToMap(queryConditionItem) + queryCondition = append(queryCondition, queryConditionItemMap) + // TODO: handle QueryCondition of type TypeList -- list of non-primitive, not model items + } + resourceQueryMap["query_condition"] = queryCondition + } + if resourceQuery.QuerySelect != nil { + resourceQueryMap["query_select"] = resourceQuery.QuerySelect + } + + return resourceQueryMap +} + +func resourceIBMSchematicsResourceQueryResourceQueryParamToMap(resourceQueryParam schematicsv1.ResourceQueryParam) map[string]interface{} { + resourceQueryParamMap := map[string]interface{}{} + + if resourceQueryParam.Name != nil { + resourceQueryParamMap["name"] = resourceQueryParam.Name + } + if resourceQueryParam.Value != nil { + resourceQueryParamMap["value"] = resourceQueryParam.Value + } + if resourceQueryParam.Description != nil { + resourceQueryParamMap["description"] = resourceQueryParam.Description + } + + return resourceQueryParamMap +} + +func resourceIBMSchematicsResourceQueryUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + replaceResourcesQueryOptions := &schematicsv1.ReplaceResourcesQueryOptions{} + + replaceResourcesQueryOptions.SetQueryID(d.Id()) + if _, ok := d.GetOk("type"); ok { + replaceResourcesQueryOptions.SetType(d.Get("type").(string)) + } + if _, ok := d.GetOk("name"); ok { + replaceResourcesQueryOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("queries"); ok { + var queries []schematicsv1.ResourceQuery + for _, e := range d.Get("queries").([]interface{}) { + value := e.(map[string]interface{}) + queriesItem := resourceIBMSchematicsResourceQueryMapToResourceQuery(value) + queries = append(queries, queriesItem) + } + replaceResourcesQueryOptions.SetQueries(queries) + } + + _, response, err := schematicsClient.ReplaceResourcesQueryWithContext(context, replaceResourcesQueryOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceResourcesQueryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceResourcesQueryWithContext failed %s\n%s", err, response)) + } + + return resourceIBMSchematicsResourceQueryRead(context, d, meta) +} + +func resourceIBMSchematicsResourceQueryDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + deleteResourcesQueryOptions := &schematicsv1.DeleteResourcesQueryOptions{} + + deleteResourcesQueryOptions.SetQueryID(d.Id()) + + response, err := schematicsClient.DeleteResourcesQueryWithContext(context, deleteResourcesQueryOptions) + if err != nil { + log.Printf("[DEBUG] DeleteResourcesQueryWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteResourcesQueryWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/schematics/resource_ibm_schematics_resource_query_test.go b/ibm/service/schematics/resource_ibm_schematics_resource_query_test.go new file mode 100644 index 000000000..1d4b65286 --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_resource_query_test.go @@ -0,0 +1,153 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func TestAccIBMSchematicsResourceQueryBasic(t *testing.T) { + var conf schematicsv1.ResourceQueryRecord + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsResourceQueryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsResourceQueryConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsResourceQueryExists("ibm_schematics_resource_query.schematics_resource_query", conf), + ), + }, + }, + }) +} + +func TestAccIBMSchematicsResourceQueryAllArgs(t *testing.T) { + var conf schematicsv1.ResourceQueryRecord + typeVar := "vsi" + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + typeVarUpdate := "vsi" + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsResourceQueryDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsResourceQueryConfig(typeVar, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsResourceQueryExists("ibm_schematics_resource_query.schematics_resource_query", conf), + resource.TestCheckResourceAttr("ibm_schematics_resource_query.schematics_resource_query", "type", typeVar), + resource.TestCheckResourceAttr("ibm_schematics_resource_query.schematics_resource_query", "name", name), + ), + }, + { + Config: testAccCheckIBMSchematicsResourceQueryConfig(typeVarUpdate, nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_schematics_resource_query.schematics_resource_query", "type", typeVarUpdate), + resource.TestCheckResourceAttr("ibm_schematics_resource_query.schematics_resource_query", "name", nameUpdate), + ), + }, + { + ResourceName: "ibm_schematics_resource_query.schematics_resource_query", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSchematicsResourceQueryConfigBasic() string { + return ` + + resource "ibm_schematics_resource_query" "schematics_resource_query" { + } + ` +} + +func testAccCheckIBMSchematicsResourceQueryConfig(typeVar string, name string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_resource_query" "schematics_resource_query" { + type = "%s" + name = "%s" + queries { + query_type = "workspaces" + query_condition { + name = "name" + value = "value" + description = "description" + } + query_select = [ "query_select" ] + } + } + `, typeVar, name) +} + +func testAccCheckIBMSchematicsResourceQueryExists(n string, obj schematicsv1.ResourceQueryRecord) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + + getResourcesQueryOptions := &schematicsv1.GetResourcesQueryOptions{} + + getResourcesQueryOptions.SetQueryID(rs.Primary.ID) + + resourceQueryRecord, _, err := schematicsClient.GetResourcesQuery(getResourcesQueryOptions) + if err != nil { + return err + } + + obj = *resourceQueryRecord + return nil + } +} + +func testAccCheckIBMSchematicsResourceQueryDestroy(s *terraform.State) error { + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_schematics_resource_query" { + continue + } + + getResourcesQueryOptions := &schematicsv1.GetResourcesQueryOptions{} + + getResourcesQueryOptions.SetQueryID(rs.Primary.ID) + + // Try to find the key + _, response, err := schematicsClient.GetResourcesQuery(getResourcesQueryOptions) + + if err == nil { + return fmt.Errorf("schematics_resource_query still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for schematics_resource_query (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/schematics/resource_ibm_schematics_workspace.go b/ibm/service/schematics/resource_ibm_schematics_workspace.go new file mode 100644 index 000000000..c190dcb38 --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_workspace.go @@ -0,0 +1,1716 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/schematics-go-sdk/schematicsv1" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +const ( + schematicsWorkspaceName = "name" + schematicsWorkspaceDescription = "description" + schematicsWorkspaceTemplateType = "template_type" +) + +func ResourceIBMSchematicsWorkspace() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMSchematicsWorkspaceCreate, + ReadContext: resourceIBMSchematicsWorkspaceRead, + UpdateContext: resourceIBMSchematicsWorkspaceUpdate, + DeleteContext: resourceIBMSchematicsWorkspaceDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "applied_shareddata_ids": { + Type: schema.TypeList, + Optional: true, + Description: "List of applied shared dataset ID.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "catalog_ref": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dry_run": { + Type: schema.TypeBool, + Optional: true, + Description: "Dry run.", + }, + "owning_account": { + Type: schema.TypeString, + Optional: true, + Description: "Owning account ID of the catalog.", + }, + "item_icon_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL to the icon of the software template in the IBM Cloud catalog.", + }, + "item_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", + }, + "item_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the software that you chose to install from the IBM Cloud catalog.", + }, + "item_readme_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL to the readme file of the software template in the IBM Cloud catalog.", + }, + "item_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL to the software template in the IBM Cloud catalog.", + }, + "launch_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL to the dashboard to access your software.", + }, + "offering_version": { + Type: schema.TypeString, + Optional: true, + Description: "The version of the software template that you chose to install from the IBM Cloud catalog.", + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the workspace.", + ValidateFunc: validate.InvokeValidator("ibm_schematics_workspace", "description"), + }, + "location": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The location where you want to create your Schematics workspace and run the Schematics jobs. The location that you enter must match the API endpoint that you use. For example, if you use the Frankfurt API endpoint, you must specify `eu-de` as your location. If you use an API endpoint for a geography and you do not specify a location, Schematics determines the location based on availability.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of your workspace. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. When you create a workspace for your own Terraform template, consider including the microservice component that you set up with your Terraform template and the IBM Cloud environment where you want to deploy your resources in your name.", + ValidateFunc: validate.InvokeValidator("ibm_schematics_workspace", "name"), + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the resource group where you want to provision the workspace.", + }, + "shared_data": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Information about the Target used by the templates originating from the IBM Cloud catalog offerings. This information is not relevant for workspace created using your own Terraform template.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_created_on": { + Type: schema.TypeString, + Optional: true, + Description: "Cluster created on.", + }, + "cluster_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + "cluster_name": { + Type: schema.TypeString, + Optional: true, + Description: "The cluster name.", + }, + "cluster_type": { + Type: schema.TypeString, + Optional: true, + Description: "The cluster type.", + }, + "entitlement_keys": { + Type: schema.TypeList, + Optional: true, + Description: "The entitlement key that you want to use to install IBM Cloud entitled software.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "namespace": { + Type: schema.TypeString, + Optional: true, + Description: "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", + }, + "region": { + Type: schema.TypeString, + Optional: true, + Description: "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + "resource_group_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + }, + "worker_count": { + Type: schema.TypeInt, + Optional: true, + Description: "The cluster worker count.", + }, + "worker_machine_type": { + Type: schema.TypeString, + Optional: true, + Description: "The cluster worker type.", + }, + }, + }, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Description: "A list of tags that are associated with the workspace.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "template_env_settings": { + Type: schema.TypeList, + Optional: true, + Description: "A list of environment variables that you want to apply during the execution of a bash script or Terraform job. This field must be provided as a list of key-value pairs, for example, **TF_LOG=debug**. Each entry will be a map with one entry where `key is the environment variable name and value is value`. You can define environment variables for IBM Cloud catalog offerings that are provisioned by using a bash script. See [example to use special environment variable](https://cloud.ibm.com/docs/schematics?topic=schematics-set-parallelism#parallelism-example) that are supported by Schematics.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "template_git_folder": { + Type: schema.TypeString, + Optional: true, + Description: "The subfolder in your GitHub or GitLab repository where your Terraform template is stored.", + }, + "template_init_state_file": { + Type: schema.TypeString, + Optional: true, + Description: "The content of an existing Terraform statefile that you want to import in to your workspace. To get the content of a Terraform statefile for a specific Terraform template in an existing workspace, run `ibmcloud terraform state pull --id --template `.", + }, + "template_type": { + Type: schema.TypeString, + Required: true, + Description: "The Terraform version that you want to use to run your Terraform code. Enter `terraform_v0.12` to use Terraform version 0.12, and `terraform_v0.11` to use Terraform version 0.11. The Terraform config files are run with Terraform version 0.11. This is a required variable. Make sure that your Terraform config files are compatible with the Terraform version that you select.", + ValidateFunc: validate.InvokeValidator("ibm_schematics_workspace", "template_type"), + }, + "template_uninstall_script_name": { + Type: schema.TypeString, + Optional: true, + Description: "Uninstall script name.", + }, + "template_values": { + Type: schema.TypeString, + Optional: true, + Description: "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", + }, + "template_values_metadata": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "List of values metadata.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "template_inputs": { + Type: schema.TypeList, + Optional: true, + Description: "VariablesRequest -.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of your input variable.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the variable.", + }, + "secure": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to `true`, the value of your input variable is protected and not returned in your API response.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", + }, + "use_default": { + Type: schema.TypeBool, + Optional: true, + Description: "Variable uses default value; and is not over-ridden.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + }, + }, + }, + }, + "template_ref": { + Type: schema.TypeString, + Optional: true, + Description: "Workspace template ref.", + }, + "template_git_branch": { + Type: schema.TypeString, + Optional: true, + Description: "The repository branch.", + }, + "template_git_release": { + Type: schema.TypeString, + Optional: true, + Description: "The repository release.", + }, + "template_git_repo_sha_value": { + Type: schema.TypeString, + Optional: true, + Description: "The repository SHA value.", + }, + "template_git_repo_url": { + Type: schema.TypeString, + Optional: true, + Description: "The repository URL.", + }, + "template_git_url": { + Type: schema.TypeString, + Optional: true, + Description: "The source URL.", + ValidateFunc: validation.IsURLWithHTTPorHTTPS, + }, + "template_git_has_uploadedgitrepotar": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Has uploaded git repo tar", + }, + /*"template_type": { + Type: schema.TypeList, + Required: true, + Description: "List of Workspace type.", + Elem: &schema.Schema{Type: schema.TypeString}, + },*/ + "frozen": { + Type: schema.TypeBool, + Optional: true, + Description: "If set to true, the workspace is frozen and changes to the workspace are disabled.", + }, + "frozen_at": { + Type: schema.TypeString, + Optional: true, + Description: "The timestamp when the workspace was frozen.", + }, + "frozen_by": { + Type: schema.TypeString, + Optional: true, + Description: "The user ID that froze the workspace.", + }, + "locked": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If set to true, the workspace is locked and disabled for changes.", + }, + "locked_by": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user ID that initiated a resource-related action, such as applying or destroying resources, that locked the workspace.", + }, + "locked_time": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The timestamp when the workspace was locked.", + }, + "x_github_token": { + Type: schema.TypeString, + Optional: true, + Description: "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was created.", + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that created the workspace.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The workspace CRN.", + }, + "last_health_check_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the last health check was performed by Schematics.", + }, + "runtime_data": { + Type: schema.TypeList, + Computed: true, + Description: "Information about the provisioning engine, state file, and runtime logs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "engine_cmd": { + Type: schema.TypeString, + Optional: true, + Description: "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", + }, + "engine_name": { + Type: schema.TypeString, + Optional: true, + Description: "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", + }, + "engine_version": { + Type: schema.TypeString, + Optional: true, + Description: "The version of the provisioning engine that was used.", + }, + "id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", + }, + "log_store_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", + }, + "output_values": { + Type: schema.TypeList, + Optional: true, + Description: "List of Output values.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "resources": { + Type: schema.TypeList, + Optional: true, + Description: "List of resources.", + Elem: &schema.Schema{Type: schema.TypeMap}, + }, + "state_store_url": { + Type: schema.TypeString, + Optional: true, + Description: "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs.", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the workspace was last updated.", + }, + "updated_by": { + Type: schema.TypeString, + Computed: true, + Description: "The user ID that updated the workspace.", + }, + "status_code": { + Type: schema.TypeString, + Computed: true, + Description: "The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace.", + }, + "status_msg": { + Type: schema.TypeString, + Computed: true, + Description: "The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace.", + }, + }, + } +} + +func ResourceIBMSchematicsWorkspaceValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: schematicsWorkspaceName, + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Regexp: `^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$`, + MinValueLength: 1, + MaxValueLength: 128, + Required: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: schematicsWorkspaceDescription, + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + MinValueLength: 0, + MaxValueLength: 2048, + Optional: true}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: schematicsWorkspaceTemplateType, + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Regexp: `^terraform_v(?:0\.11|0\.12|0\.13|0\.14|0\.15|1\.0|1\.1)(?:\.\d+)?$`, + Default: "[]", + Optional: true}) + + ibmSchematicsWorkspaceResourceValidator := validate.ResourceValidator{ResourceName: "ibm_schematics_workspace", Schema: validateSchema} + return &ibmSchematicsWorkspaceResourceValidator +} + +func resourceIBMSchematicsWorkspaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + if r, ok := d.GetOk("location"); ok { + region := r.(string) + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + } + createWorkspaceOptions := &schematicsv1.CreateWorkspaceOptions{} + + if _, ok := d.GetOk("applied_shareddata_ids"); ok { + createWorkspaceOptions.SetAppliedShareddataIds(flex.ExpandStringList(d.Get("applied_shareddata_ids").([]interface{}))) + } + if _, ok := d.GetOk("catalog_ref"); ok { + catalogRefAttr := d.Get("catalog_ref").([]interface{}) + if len(catalogRefAttr) > 0 { + catalogRef := resourceIBMSchematicsWorkspaceMapToCatalogRef(d.Get("catalog_ref.0").(map[string]interface{})) + createWorkspaceOptions.SetCatalogRef(&catalogRef) + } + } + if _, ok := d.GetOk("description"); ok { + createWorkspaceOptions.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("location"); ok { + createWorkspaceOptions.SetLocation(d.Get("location").(string)) + } + if _, ok := d.GetOk("name"); ok { + createWorkspaceOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("resource_group"); ok { + createWorkspaceOptions.SetResourceGroup(d.Get("resource_group").(string)) + } + if _, ok := d.GetOk("shared_data"); ok { + sharedDataAttr := d.Get("shared_data").([]interface{}) + if len(sharedDataAttr) > 0 { + sharedData := resourceIBMSchematicsWorkspaceMapToSharedTargetData(d.Get("shared_data.0").(map[string]interface{})) + createWorkspaceOptions.SetSharedData(&sharedData) + } + } + if _, ok := d.GetOk("tags"); ok { + createWorkspaceOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + } + + var templateData []schematicsv1.TemplateSourceDataRequest + + templateSourceDataRequestMap := map[string]interface{}{} + hasTemplateData := false + + if _, ok := d.GetOk("template_env_settings"); ok { + templateSourceDataRequestMap["env_values"] = d.Get("template_env_settings").([]interface{}) + hasTemplateData = true + } + if _, ok := d.GetOk("template_git_folder"); ok { + templateSourceDataRequestMap["folder"] = d.Get("template_git_folder").(string) + hasTemplateData = true + } + if _, ok := d.GetOk("template_init_state_file"); ok { + templateSourceDataRequestMap["init_state_file"] = d.Get("template_init_state_file").(string) + hasTemplateData = true + } + if _, ok := d.GetOk("template_type"); ok { + templateSourceDataRequestMap["type"] = d.Get("template_type").(string) + createWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) + hasTemplateData = true + } + if _, ok := d.GetOk("template_uninstall_script_name"); ok { + templateSourceDataRequestMap["uninstall_script_name"] = d.Get("template_uninstall_script_name").(string) + hasTemplateData = true + } + if _, ok := d.GetOk("template_values"); ok { + templateSourceDataRequestMap["values"] = d.Get("template_values").(string) + hasTemplateData = true + } + if _, ok := d.GetOk("template_values_metadata"); ok { + templateSourceDataRequestMap["values_metadata"] = d.Get("template_values_metadata").([]interface{}) + hasTemplateData = true + } + if _, ok := d.GetOk("template_inputs"); ok { + templateSourceDataRequestMap["variablestore"] = d.Get("template_inputs").([]interface{}) + hasTemplateData = true + } + if hasTemplateData { + templateDataItem := resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap) + templateData = append(templateData, templateDataItem) + createWorkspaceOptions.SetTemplateData(templateData) + } + if _, ok := d.GetOk("template_ref"); ok { + createWorkspaceOptions.SetTemplateRef(d.Get("template_ref").(string)) + } + + templateRepoRequestMap := map[string]interface{}{} + hasTemplateRepo := false + if _, ok := d.GetOk("template_git_branch"); ok { + templateRepoRequestMap["branch"] = d.Get("template_git_branch").(string) + hasTemplateRepo = true + } + if _, ok := d.GetOk("template_git_release"); ok { + templateRepoRequestMap["release"] = d.Get("template_git_release").(string) + hasTemplateRepo = true + } + if _, ok := d.GetOk("template_git_repo_sha_value"); ok { + templateRepoRequestMap["repo_sha_value"] = d.Get("template_git_repo_sha_value").(string) + hasTemplateRepo = true + } + if _, ok := d.GetOk("template_git_repo_url"); ok { + templateRepoRequestMap["repo_url"] = d.Get("template_git_repo_url").(string) + hasTemplateRepo = true + } + if _, ok := d.GetOk("template_git_url"); ok { + templateRepoRequestMap["url"] = d.Get("template_git_url").(string) + hasTemplateRepo = true + } + if _, ok := d.GetOk("template_git_has_uploadedgitrepotar"); ok { + templateRepoRequestMap["has_uploadedgitrepotar"] = d.Get("template_git_has_uploadedgitrepotar").(string) + hasTemplateRepo = true + } + if hasTemplateRepo { + templateRepo := resourceIBMSchematicsWorkspaceMapToTemplateRepoRequest(templateRepoRequestMap) + createWorkspaceOptions.SetTemplateRepo(&templateRepo) + } + + /*if _, ok := d.GetOk("template_type"); ok { + createWorkspaceOptions.SetType(flex.ExpandStringList(d.Get("template_type").([]interface{}))) + }*/ + workspaceStatusRequestMap := map[string]interface{}{} + hasWorkspaceStatus := false + if _, ok := d.GetOk("frozen"); ok { + workspaceStatusRequestMap["frozen"] = d.Get("frozen").(bool) + hasWorkspaceStatus = true + } + if _, ok := d.GetOk("frozen_at"); ok { + workspaceStatusRequestMap["frozen_at"] = d.Get("frozen_at").(string) + hasWorkspaceStatus = true + } + if _, ok := d.GetOk("frozen_by"); ok { + workspaceStatusRequestMap["frozen_by"] = d.Get("frozen_by").(string) + hasWorkspaceStatus = true + } + if _, ok := d.GetOk("locked"); ok { + workspaceStatusRequestMap["locked"] = d.Get("locked").(bool) + hasWorkspaceStatus = true + } + if _, ok := d.GetOk("locked_by"); ok { + workspaceStatusRequestMap["locked_by"] = d.Get("locked_by").(string) + hasWorkspaceStatus = true + } + if _, ok := d.GetOk("locked_time"); ok { + workspaceStatusRequestMap["locked_time"] = d.Get("locked_time").(string) + hasWorkspaceStatus = true + } + if hasWorkspaceStatus { + workspaceStatus := resourceIBMSchematicsWorkspaceMapToWorkspaceStatusRequest(workspaceStatusRequestMap) + createWorkspaceOptions.SetWorkspaceStatus(&workspaceStatus) + } + if _, ok := d.GetOk("x_github_token"); ok { + createWorkspaceOptions.SetXGithubToken(d.Get("x_github_token").(string)) + } + + workspaceResponse, response, err := schematicsClient.CreateWorkspaceWithContext(context, createWorkspaceOptions) + if err != nil { + log.Printf("[DEBUG] CreateWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateWorkspaceWithContext failed %s\n%s", err, response)) + } + + d.SetId(*workspaceResponse.ID) + + return resourceIBMSchematicsWorkspaceRead(context, d, meta) +} + +func resourceIBMSchematicsWorkspaceMapToCatalogRef(catalogRefMap map[string]interface{}) schematicsv1.CatalogRef { + catalogRef := schematicsv1.CatalogRef{} + + if catalogRefMap["dry_run"] != nil { + catalogRef.DryRun = core.BoolPtr(catalogRefMap["dry_run"].(bool)) + } + if catalogRefMap["owning_account"] != nil { + catalogRef.OwningAccount = core.StringPtr(catalogRefMap["owning_account"].(string)) + } + if catalogRefMap["item_icon_url"] != nil { + catalogRef.ItemIconURL = core.StringPtr(catalogRefMap["item_icon_url"].(string)) + } + if catalogRefMap["item_id"] != nil { + catalogRef.ItemID = core.StringPtr(catalogRefMap["item_id"].(string)) + } + if catalogRefMap["item_name"] != nil { + catalogRef.ItemName = core.StringPtr(catalogRefMap["item_name"].(string)) + } + if catalogRefMap["item_readme_url"] != nil { + catalogRef.ItemReadmeURL = core.StringPtr(catalogRefMap["item_readme_url"].(string)) + } + if catalogRefMap["item_url"] != nil { + catalogRef.ItemURL = core.StringPtr(catalogRefMap["item_url"].(string)) + } + if catalogRefMap["launch_url"] != nil { + catalogRef.LaunchURL = core.StringPtr(catalogRefMap["launch_url"].(string)) + } + if catalogRefMap["offering_version"] != nil { + catalogRef.OfferingVersion = core.StringPtr(catalogRefMap["offering_version"].(string)) + } + + return catalogRef +} + +func resourceIBMSchematicsWorkspaceMapToSharedTargetData(sharedTargetDataMap map[string]interface{}) schematicsv1.SharedTargetData { + sharedTargetData := schematicsv1.SharedTargetData{} + + if sharedTargetDataMap["cluster_created_on"] != nil { + sharedTargetData.ClusterCreatedOn = core.StringPtr(sharedTargetDataMap["cluster_created_on"].(string)) + } + if sharedTargetDataMap["cluster_id"] != nil { + sharedTargetData.ClusterID = core.StringPtr(sharedTargetDataMap["cluster_id"].(string)) + } + if sharedTargetDataMap["cluster_name"] != nil { + sharedTargetData.ClusterName = core.StringPtr(sharedTargetDataMap["cluster_name"].(string)) + } + if sharedTargetDataMap["cluster_type"] != nil { + sharedTargetData.ClusterType = core.StringPtr(sharedTargetDataMap["cluster_type"].(string)) + } + if sharedTargetDataMap["entitlement_keys"] != nil { + entitlementKeys := []interface{}{} + for _, entitlementKeysItem := range sharedTargetDataMap["entitlement_keys"].([]interface{}) { + entitlementKeys = append(entitlementKeys, entitlementKeysItem.(interface{})) + } + sharedTargetData.EntitlementKeys = entitlementKeys + } + if sharedTargetDataMap["namespace"] != nil { + sharedTargetData.Namespace = core.StringPtr(sharedTargetDataMap["namespace"].(string)) + } + if sharedTargetDataMap["region"] != nil { + sharedTargetData.Region = core.StringPtr(sharedTargetDataMap["region"].(string)) + } + if sharedTargetDataMap["resource_group_id"] != nil { + sharedTargetData.ResourceGroupID = core.StringPtr(sharedTargetDataMap["resource_group_id"].(string)) + } + if sharedTargetDataMap["worker_count"] != nil { + sharedTargetData.WorkerCount = core.Int64Ptr(int64(sharedTargetDataMap["worker_count"].(int))) + } + if sharedTargetDataMap["worker_machine_type"] != nil { + sharedTargetData.WorkerMachineType = core.StringPtr(sharedTargetDataMap["worker_machine_type"].(string)) + } + + return sharedTargetData +} + +func resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap map[string]interface{}) schematicsv1.TemplateSourceDataRequest { + templateSourceDataRequest := schematicsv1.TemplateSourceDataRequest{} + + if templateSourceDataRequestMap["env_values"] != nil { + envValues := []interface{}{} + for _, envValuesItem := range templateSourceDataRequestMap["env_values"].([]interface{}) { + envValues = append(envValues, envValuesItem.(interface{})) + } + templateSourceDataRequest.EnvValues = envValues + } + if templateSourceDataRequestMap["folder"] != nil { + templateSourceDataRequest.Folder = core.StringPtr(templateSourceDataRequestMap["folder"].(string)) + } + if templateSourceDataRequestMap["compact"] != nil { + templateSourceDataRequest.Compact = core.BoolPtr(templateSourceDataRequestMap["compact"].(bool)) + } + if templateSourceDataRequestMap["init_state_file"] != nil { + templateSourceDataRequest.InitStateFile = core.StringPtr(templateSourceDataRequestMap["init_state_file"].(string)) + } + if templateSourceDataRequestMap["type"] != nil { + templateSourceDataRequest.Type = core.StringPtr(templateSourceDataRequestMap["type"].(string)) + } + if templateSourceDataRequestMap["uninstall_script_name"] != nil { + templateSourceDataRequest.UninstallScriptName = core.StringPtr(templateSourceDataRequestMap["uninstall_script_name"].(string)) + } + if templateSourceDataRequestMap["values"] != nil { + templateSourceDataRequest.Values = core.StringPtr(templateSourceDataRequestMap["values"].(string)) + } + if templateSourceDataRequestMap["values_metadata"] != nil { + valuesMetadata := make([]schematicsv1.VariableMetadata, 0) + for _, valuesMetadataItem := range templateSourceDataRequestMap["values_metadata"].([]interface{}) { + valuesMetadata = append(valuesMetadata, valuesMetadataItem.(schematicsv1.VariableMetadata)) + } + templateSourceDataRequest.ValuesMetadata = valuesMetadata + } + if templateSourceDataRequestMap["variablestore"] != nil { + variablestore := []schematicsv1.WorkspaceVariableRequest{} + for _, variablestoreItem := range templateSourceDataRequestMap["variablestore"].([]interface{}) { + variablestoreItemModel := resourceIBMSchematicsWorkspaceMapToWorkspaceVariableRequest(variablestoreItem.(map[string]interface{})) + variablestore = append(variablestore, variablestoreItemModel) + } + templateSourceDataRequest.Variablestore = variablestore + } + + return templateSourceDataRequest +} + +func resourceIBMSchematicsWorkspaceMapToWorkspaceVariableRequest(workspaceVariableRequestMap map[string]interface{}) schematicsv1.WorkspaceVariableRequest { + workspaceVariableRequest := schematicsv1.WorkspaceVariableRequest{} + + if workspaceVariableRequestMap["description"] != nil { + workspaceVariableRequest.Description = core.StringPtr(workspaceVariableRequestMap["description"].(string)) + } + if workspaceVariableRequestMap["name"] != nil { + workspaceVariableRequest.Name = core.StringPtr(workspaceVariableRequestMap["name"].(string)) + } + if workspaceVariableRequestMap["secure"] != nil { + workspaceVariableRequest.Secure = core.BoolPtr(workspaceVariableRequestMap["secure"].(bool)) + } + if workspaceVariableRequestMap["type"] != nil { + workspaceVariableRequest.Type = core.StringPtr(workspaceVariableRequestMap["type"].(string)) + } + if workspaceVariableRequestMap["use_default"] != nil { + workspaceVariableRequest.UseDefault = core.BoolPtr(workspaceVariableRequestMap["use_default"].(bool)) + } + if workspaceVariableRequestMap["value"] != nil { + workspaceVariableRequest.Value = core.StringPtr(workspaceVariableRequestMap["value"].(string)) + } + + return workspaceVariableRequest +} + +func resourceIBMSchematicsWorkspaceMapToTemplateRepoRequest(templateRepoRequestMap map[string]interface{}) schematicsv1.TemplateRepoRequest { + templateRepoRequest := schematicsv1.TemplateRepoRequest{} + + if templateRepoRequestMap["branch"] != nil { + templateRepoRequest.Branch = core.StringPtr(templateRepoRequestMap["branch"].(string)) + } + if templateRepoRequestMap["release"] != nil { + templateRepoRequest.Release = core.StringPtr(templateRepoRequestMap["release"].(string)) + } + if templateRepoRequestMap["repo_sha_value"] != nil { + templateRepoRequest.RepoShaValue = core.StringPtr(templateRepoRequestMap["repo_sha_value"].(string)) + } + if templateRepoRequestMap["repo_url"] != nil { + templateRepoRequest.RepoURL = core.StringPtr(templateRepoRequestMap["repo_url"].(string)) + } + if templateRepoRequestMap["url"] != nil { + templateRepoRequest.URL = core.StringPtr(templateRepoRequestMap["url"].(string)) + } + + return templateRepoRequest +} + +func resourceIBMSchematicsWorkspaceMapToTemplateRepoUpdateRequest(templateRepoUpdateRequestMap map[string]interface{}) schematicsv1.TemplateRepoUpdateRequest { + templateRepoUpdateRequest := schematicsv1.TemplateRepoUpdateRequest{} + + if templateRepoUpdateRequestMap["branch"] != nil { + templateRepoUpdateRequest.Branch = core.StringPtr(templateRepoUpdateRequestMap["branch"].(string)) + } + if templateRepoUpdateRequestMap["release"] != nil { + templateRepoUpdateRequest.Release = core.StringPtr(templateRepoUpdateRequestMap["release"].(string)) + } + if templateRepoUpdateRequestMap["repo_sha_value"] != nil { + templateRepoUpdateRequest.RepoShaValue = core.StringPtr(templateRepoUpdateRequestMap["repo_sha_value"].(string)) + } + if templateRepoUpdateRequestMap["repo_url"] != nil { + templateRepoUpdateRequest.RepoURL = core.StringPtr(templateRepoUpdateRequestMap["repo_url"].(string)) + } + if templateRepoUpdateRequestMap["url"] != nil { + templateRepoUpdateRequest.URL = core.StringPtr(templateRepoUpdateRequestMap["url"].(string)) + } + + return templateRepoUpdateRequest +} + +func resourceIBMSchematicsWorkspaceMapToWorkspaceStatusRequest(workspaceStatusRequestMap map[string]interface{}) schematicsv1.WorkspaceStatusRequest { + workspaceStatusRequest := schematicsv1.WorkspaceStatusRequest{} + + if workspaceStatusRequestMap["frozen"] != nil { + workspaceStatusRequest.Frozen = core.BoolPtr(workspaceStatusRequestMap["frozen"].(bool)) + } + if workspaceStatusRequestMap["frozen_at"] != nil { + frozenAt, err := strfmt.ParseDateTime(workspaceStatusRequestMap["frozen_at"].(string)) + if err != nil { + workspaceStatusRequest.FrozenAt = &frozenAt + } + } + if workspaceStatusRequestMap["frozen_by"] != nil { + workspaceStatusRequest.FrozenBy = core.StringPtr(workspaceStatusRequestMap["frozen_by"].(string)) + } + if workspaceStatusRequestMap["locked"] != nil { + workspaceStatusRequest.Locked = core.BoolPtr(workspaceStatusRequestMap["locked"].(bool)) + } + if workspaceStatusRequestMap["locked_by"] != nil { + workspaceStatusRequest.LockedBy = core.StringPtr(workspaceStatusRequestMap["locked_by"].(string)) + } + if workspaceStatusRequestMap["locked_time"] != nil { + lockedTime, err := strfmt.ParseDateTime(workspaceStatusRequestMap["locked_time"].(string)) + if err != nil { + workspaceStatusRequest.LockedTime = &lockedTime + } + } + + return workspaceStatusRequest +} + +func resourceIBMSchematicsWorkspaceMapToWorkspaceStatusUpdateRequest(workspaceStatusUpdateRequestMap map[string]interface{}) schematicsv1.WorkspaceStatusUpdateRequest { + workspaceStatusUpdateRequest := schematicsv1.WorkspaceStatusUpdateRequest{} + + if workspaceStatusUpdateRequestMap["frozen"] != nil { + workspaceStatusUpdateRequest.Frozen = core.BoolPtr(workspaceStatusUpdateRequestMap["frozen"].(bool)) + } + if workspaceStatusUpdateRequestMap["frozen_at"] != nil { + frozenAt := workspaceStatusUpdateRequestMap["frozen_at"].(strfmt.DateTime) + workspaceStatusUpdateRequest.FrozenAt = &frozenAt + } + if workspaceStatusUpdateRequestMap["frozen_by"] != nil { + workspaceStatusUpdateRequest.FrozenBy = core.StringPtr(workspaceStatusUpdateRequestMap["frozen_by"].(string)) + } + if workspaceStatusUpdateRequestMap["locked"] != nil { + workspaceStatusUpdateRequest.Locked = core.BoolPtr(workspaceStatusUpdateRequestMap["locked"].(bool)) + } + if workspaceStatusUpdateRequestMap["locked_by"] != nil { + workspaceStatusUpdateRequest.LockedBy = core.StringPtr(workspaceStatusUpdateRequestMap["locked_by"].(string)) + } + if workspaceStatusUpdateRequestMap["locked_time"] != nil { + lockedTime := workspaceStatusUpdateRequestMap["locked_time"].(strfmt.DateTime) + workspaceStatusUpdateRequest.LockedTime = &lockedTime + } + + return workspaceStatusUpdateRequest +} + +func resourceIBMSchematicsWorkspaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} + + getWorkspaceOptions.SetWID(d.Id()) + + workspaceResponse, response, err := schematicsClient.GetWorkspaceWithContext(context, getWorkspaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetWorkspaceWithContext failed %s\n%s", err, response)) + } + if workspaceResponse.AppliedShareddataIds != nil { + if err = d.Set("applied_shareddata_ids", workspaceResponse.AppliedShareddataIds); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting applied_shareddata_ids: %s", err)) + } + } + if workspaceResponse.CatalogRef != nil { + catalogRefMap := resourceIBMSchematicsWorkspaceCatalogRefToMap(*workspaceResponse.CatalogRef) + if err = d.Set("catalog_ref", []map[string]interface{}{catalogRefMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting catalog_ref: %s", err)) + } + } + if err = d.Set("description", workspaceResponse.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + if err = d.Set("location", workspaceResponse.Location); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting location: %s", err)) + } + if err = d.Set("name", workspaceResponse.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("resource_group", workspaceResponse.ResourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + if _, ok := d.GetOk("shared_data"); ok { + if workspaceResponse.SharedData != nil { + sharedDataMap := resourceIBMSchematicsWorkspaceSharedTargetDataResponseToMap(*workspaceResponse.SharedData) + if err = d.Set("shared_data", []map[string]interface{}{sharedDataMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading shared_data: %s", err)) + } + } + } + if workspaceResponse.Tags != nil { + if err = d.Set("tags", workspaceResponse.Tags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting tags: %s", err)) + } + } + if workspaceResponse.TemplateData != nil { + templateData := []map[string]interface{}{} + for _, templateDataItem := range workspaceResponse.TemplateData { + templateDataItemMap := resourceIBMSchematicsWorkspaceTemplateSourceDataResponseToMap(templateDataItem) + templateData = append(templateData, templateDataItemMap) + } + if err = d.Set("template_env_settings", templateData[0]["env_values"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading env_values: %s", err)) + } + if err = d.Set("template_git_folder", templateData[0]["folder"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading folder: %s", err)) + } + if err = d.Set("template_init_state_file", templateData[0]["init_state_file"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading init_state_file: %s", err)) + } + if err = d.Set("template_type", templateData[0]["type"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading type: %s", err)) + } + if err = d.Set("template_uninstall_script_name", templateData[0]["uninstall_script_name"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading uninstall_script_name: %s", err)) + } + if err = d.Set("template_values", templateData[0]["values"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading values: %s", err)) + } + if err = d.Set("template_values_metadata", templateData[0]["values_metadata"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading values_metadata: %s", err)) + } + if err = d.Set("template_inputs", templateData[0]["variablestore"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading variablestore: %s", err)) + } + + } + if err = d.Set("template_ref", workspaceResponse.TemplateRef); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting template_ref: %s", err)) + } + if workspaceResponse.TemplateRepo != nil { + templateRepoMap := resourceIBMSchematicsWorkspaceTemplateRepoResponseToMap(*workspaceResponse.TemplateRepo) + if err = d.Set("template_git_branch", templateRepoMap["branch"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading branch: %s", err)) + } + if err = d.Set("template_git_release", templateRepoMap["release"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading release: %s", err)) + } + if err = d.Set("template_git_repo_sha_value", templateRepoMap["repo_sha_value"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading repo_sha_value: %s", err)) + } + if err = d.Set("template_git_repo_url", templateRepoMap["repo_url"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading repo_url: %s", err)) + } + if err = d.Set("template_git_url", templateRepoMap["url"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading url: %s", err)) + } + if err = d.Set("template_git_has_uploadedgitrepotar", templateRepoMap["has_uploadedgitrepotar"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading has_uploadedgitrepotar: %s", err)) + } + } + /*if workspaceResponse.Type != nil { + if err = d.Set("template_type", workspaceResponse.Type); err != nil { + return fmt.Errorf("[ERROR] Error reading type: %s", err) + } + }*/ + if workspaceResponse.WorkspaceStatus != nil { + workspaceStatusMap := resourceIBMSchematicsWorkspaceWorkspaceStatusResponseToMap(*workspaceResponse.WorkspaceStatus) + if err = d.Set("frozen", workspaceStatusMap["frozen"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen: %s", err)) + } + if err = d.Set("frozen_at", workspaceStatusMap["frozen_at"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen_at: %s", err)) + } + if err = d.Set("frozen_by", workspaceStatusMap["frozen_by"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading frozen_by: %s", err)) + } + if err = d.Set("locked", workspaceStatusMap["locked"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked: %s", err)) + } + if err = d.Set("locked_by", workspaceStatusMap["locked_by"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked_by: %s", err)) + } + if err = d.Set("locked_time", workspaceStatusMap["locked_time"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading locked_time: %s", err)) + } + } + if workspaceResponse.CreatedAt != nil { + if err = d.Set("created_at", workspaceResponse.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading created_at: %s", err)) + } + } + if err = d.Set("created_by", workspaceResponse.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_by: %s", err)) + } + if err = d.Set("crn", workspaceResponse.Crn); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading crn: %s", err)) + } + if workspaceResponse.LastHealthCheckAt != nil { + if err = d.Set("last_health_check_at", workspaceResponse.LastHealthCheckAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading last_health_check_at: %s", err)) + } + } + if workspaceResponse.RuntimeData != nil { + runtimeData := []map[string]interface{}{} + for _, runtimeDataItem := range workspaceResponse.RuntimeData { + runtimeDataItemMap := resourceIBMSchematicsWorkspaceTemplateRunTimeDataResponseToMap(runtimeDataItem) + runtimeData = append(runtimeData, runtimeDataItemMap) + } + if err = d.Set("runtime_data", runtimeData); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting runtime_data: %s", err)) + } + } + if err = d.Set("status", workspaceResponse.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + if workspaceResponse.UpdatedAt != nil { + if err = d.Set("updated_at", workspaceResponse.UpdatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading updated_at: %s", err)) + } + } + if err = d.Set("updated_by", workspaceResponse.UpdatedBy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_by: %s", err)) + } + if workspaceResponse.WorkspaceStatusMsg != nil { + workspaceStatusMsgMap := resourceIBMSchematicsWorkspaceWorkspaceStatusMessageToMap(*workspaceResponse.WorkspaceStatusMsg) + if err = d.Set("status_code", workspaceStatusMsgMap["status_code"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading status_code: %s", err)) + } + if err = d.Set("status_msg", workspaceStatusMsgMap["status_msg"]); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error reading status_msg: %s", err)) + } + } + + return nil +} + +func resourceIBMSchematicsWorkspaceCatalogRefToMap(catalogRef schematicsv1.CatalogRef) map[string]interface{} { + catalogRefMap := map[string]interface{}{} + + if catalogRef.DryRun != nil { + catalogRefMap["dry_run"] = catalogRef.DryRun + } + if catalogRef.OwningAccount != nil { + catalogRefMap["owning_account"] = catalogRef.OwningAccount + } + if catalogRef.ItemIconURL != nil { + catalogRefMap["item_icon_url"] = catalogRef.ItemIconURL + } + if catalogRef.ItemID != nil { + catalogRefMap["item_id"] = catalogRef.ItemID + } + if catalogRef.ItemName != nil { + catalogRefMap["item_name"] = catalogRef.ItemName + } + if catalogRef.ItemReadmeURL != nil { + catalogRefMap["item_readme_url"] = catalogRef.ItemReadmeURL + } + if catalogRef.ItemURL != nil { + catalogRefMap["item_url"] = catalogRef.ItemURL + } + if catalogRef.LaunchURL != nil { + catalogRefMap["launch_url"] = catalogRef.LaunchURL + } + if catalogRef.OfferingVersion != nil { + catalogRefMap["offering_version"] = catalogRef.OfferingVersion + } + + return catalogRefMap +} + +func resourceIBMSchematicsWorkspaceSharedTargetDataToMap(sharedTargetData schematicsv1.SharedTargetData) map[string]interface{} { + sharedTargetDataMap := map[string]interface{}{} + + if sharedTargetData.ClusterCreatedOn != nil { + sharedTargetDataMap["cluster_created_on"] = sharedTargetData.ClusterCreatedOn + } + if sharedTargetData.ClusterID != nil { + sharedTargetDataMap["cluster_id"] = sharedTargetData.ClusterID + } + if sharedTargetData.ClusterName != nil { + sharedTargetDataMap["cluster_name"] = sharedTargetData.ClusterName + } + if sharedTargetData.ClusterType != nil { + sharedTargetDataMap["cluster_type"] = sharedTargetData.ClusterType + } + if sharedTargetData.EntitlementKeys != nil { + entitlementKeys := []interface{}{} + for _, entitlementKeysItem := range sharedTargetData.EntitlementKeys { + entitlementKeys = append(entitlementKeys, entitlementKeysItem) + } + sharedTargetDataMap["entitlement_keys"] = entitlementKeys + } + if sharedTargetData.Namespace != nil { + sharedTargetDataMap["namespace"] = sharedTargetData.Namespace + } + if sharedTargetData.Region != nil { + sharedTargetDataMap["region"] = sharedTargetData.Region + } + if sharedTargetData.ResourceGroupID != nil { + sharedTargetDataMap["resource_group_id"] = sharedTargetData.ResourceGroupID + } + if sharedTargetData.WorkerCount != nil { + sharedTargetDataMap["worker_count"] = flex.IntValue(sharedTargetData.WorkerCount) + } + if sharedTargetData.WorkerMachineType != nil { + sharedTargetDataMap["worker_machine_type"] = sharedTargetData.WorkerMachineType + } + + return sharedTargetDataMap +} + +func resourceIBMSchematicsWorkspaceSharedTargetDataResponseToMap(sharedTargetData schematicsv1.SharedTargetDataResponse) map[string]interface{} { + sharedTargetDataResponseMap := map[string]interface{}{} + + sharedTargetDataResponseMap["cluster_id"] = sharedTargetData.ClusterID + sharedTargetDataResponseMap["cluster_name"] = sharedTargetData.ClusterName + if sharedTargetData.EntitlementKeys != nil { + entitlementKeys := []interface{}{} + for _, entitlementKeysItem := range sharedTargetData.EntitlementKeys { + entitlementKeys = append(entitlementKeys, entitlementKeysItem) + } + sharedTargetDataResponseMap["entitlement_keys"] = entitlementKeys + } + sharedTargetDataResponseMap["namespace"] = sharedTargetData.Namespace + sharedTargetDataResponseMap["region"] = sharedTargetData.Region + sharedTargetDataResponseMap["resource_group_id"] = sharedTargetData.ResourceGroupID + + return sharedTargetDataResponseMap +} + +func resourceIBMSchematicsWorkspaceTemplateSourceDataRequestToMap(templateSourceDataRequest schematicsv1.TemplateSourceDataRequest) map[string]interface{} { + templateSourceDataRequestMap := map[string]interface{}{} + + if templateSourceDataRequest.EnvValues != nil { + envValues := []interface{}{} + for _, envValuesItem := range templateSourceDataRequest.EnvValues { + envValues = append(envValues, envValuesItem) + } + templateSourceDataRequestMap["env_values"] = envValues + } + if templateSourceDataRequest.Folder != nil { + templateSourceDataRequestMap["folder"] = templateSourceDataRequest.Folder + } + if templateSourceDataRequest.Compact != nil { + templateSourceDataRequestMap["compact"] = templateSourceDataRequest.Compact + } + if templateSourceDataRequest.InitStateFile != nil { + templateSourceDataRequestMap["init_state_file"] = templateSourceDataRequest.InitStateFile + } + if templateSourceDataRequest.Type != nil { + templateSourceDataRequestMap["type"] = templateSourceDataRequest.Type + } + if templateSourceDataRequest.UninstallScriptName != nil { + templateSourceDataRequestMap["uninstall_script_name"] = templateSourceDataRequest.UninstallScriptName + } + if templateSourceDataRequest.Values != nil { + templateSourceDataRequestMap["values"] = templateSourceDataRequest.Values + } + if templateSourceDataRequest.ValuesMetadata != nil { + valuesMetadata := []interface{}{} + for _, valuesMetadataItem := range templateSourceDataRequest.ValuesMetadata { + valuesMetadata = append(valuesMetadata, valuesMetadataItem) + } + templateSourceDataRequestMap["values_metadata"] = valuesMetadata + } + if templateSourceDataRequest.Variablestore != nil { + variablestore := []map[string]interface{}{} + for _, variablestoreItem := range templateSourceDataRequest.Variablestore { + variablestoreItemMap := resourceIBMSchematicsWorkspaceWorkspaceVariableRequestToMap(variablestoreItem) + variablestore = append(variablestore, variablestoreItemMap) + // TODO: handle Variablestore of type TypeList -- list of non-primitive, not model items + } + templateSourceDataRequestMap["variablestore"] = variablestore + } + + return templateSourceDataRequestMap +} + +func resourceIBMSchematicsWorkspaceTemplateSourceDataResponseToMap(templateSourceDataResponse schematicsv1.TemplateSourceDataResponse) map[string]interface{} { + templateSourceDataResponseMap := map[string]interface{}{} + + if templateSourceDataResponse.EnvValues != nil { + envValues := []map[string]interface{}{} + for _, envValuesItem := range templateSourceDataResponse.EnvValues { + flattenedEnvVals := map[string]interface{}{} + if envValuesItem.Name != nil { + flattenedEnvVals[*envValuesItem.Name] = envValuesItem.Value + } + + envValues = append(envValues, flattenedEnvVals) + } + templateSourceDataResponseMap["env_values"] = envValues + } + if templateSourceDataResponse.Type != nil { + templateSourceDataResponseMap["type"] = templateSourceDataResponse.Type + } + templateSourceDataResponseMap["folder"] = templateSourceDataResponse.Folder + templateSourceDataResponseMap["uninstall_script_name"] = templateSourceDataResponse.UninstallScriptName + templateSourceDataResponseMap["values"] = templateSourceDataResponse.Values + if templateSourceDataResponse.ValuesMetadata != nil { + valuesMetadata := []interface{}{} + for _, valuesMetadataItem := range templateSourceDataResponse.ValuesMetadata { + valuesMetadata = append(valuesMetadata, valuesMetadataItem) + } + templateSourceDataResponseMap["values_metadata"] = valuesMetadata + } + if templateSourceDataResponse.Variablestore != nil { + variablestore := []map[string]interface{}{} + for _, variablestoreItem := range templateSourceDataResponse.Variablestore { + variablestoreItemMap := resourceIBMSchematicsWorkspaceWorkspaceVariableResponseToMap(variablestoreItem) + variablestore = append(variablestore, variablestoreItemMap) + } + templateSourceDataResponseMap["variablestore"] = variablestore + } + + return templateSourceDataResponseMap +} + +func resourceIBMSchematicsWorkspaceWorkspaceVariableRequestToMap(workspaceVariableRequest schematicsv1.WorkspaceVariableRequest) map[string]interface{} { + workspaceVariableRequestMap := map[string]interface{}{} + + if workspaceVariableRequest.Description != nil { + workspaceVariableRequestMap["description"] = workspaceVariableRequest.Description + } + if workspaceVariableRequest.Name != nil { + workspaceVariableRequestMap["name"] = workspaceVariableRequest.Name + } + if workspaceVariableRequest.Secure != nil { + workspaceVariableRequestMap["secure"] = workspaceVariableRequest.Secure + } + if workspaceVariableRequest.Type != nil { + workspaceVariableRequestMap["type"] = workspaceVariableRequest.Type + } + if workspaceVariableRequest.UseDefault != nil { + workspaceVariableRequestMap["use_default"] = workspaceVariableRequest.UseDefault + } + if workspaceVariableRequest.Value != nil { + workspaceVariableRequestMap["value"] = workspaceVariableRequest.Value + } + + return workspaceVariableRequestMap +} + +func resourceIBMSchematicsWorkspaceWorkspaceVariableResponseToMap(workspaceVariableResponse schematicsv1.WorkspaceVariableResponse) map[string]interface{} { + workspaceVariableRequestMap := map[string]interface{}{} + + workspaceVariableRequestMap["description"] = workspaceVariableResponse.Description + workspaceVariableRequestMap["name"] = workspaceVariableResponse.Name + workspaceVariableRequestMap["secure"] = workspaceVariableResponse.Secure + workspaceVariableRequestMap["type"] = workspaceVariableResponse.Type + workspaceVariableRequestMap["value"] = workspaceVariableResponse.Value + + return workspaceVariableRequestMap +} + +func resourceIBMSchematicsWorkspaceTemplateRepoRequestToMap(templateRepoRequest schematicsv1.TemplateRepoRequest) map[string]interface{} { + templateRepoRequestMap := map[string]interface{}{} + + if templateRepoRequest.Branch != nil { + templateRepoRequestMap["branch"] = templateRepoRequest.Branch + } + if templateRepoRequest.Release != nil { + templateRepoRequestMap["release"] = templateRepoRequest.Release + } + if templateRepoRequest.RepoShaValue != nil { + templateRepoRequestMap["repo_sha_value"] = templateRepoRequest.RepoShaValue + } + if templateRepoRequest.RepoURL != nil { + templateRepoRequestMap["repo_url"] = templateRepoRequest.RepoURL + } + if templateRepoRequest.URL != nil { + templateRepoRequestMap["url"] = templateRepoRequest.URL + } + + return templateRepoRequestMap +} + +func resourceIBMSchematicsWorkspaceTemplateRepoResponseToMap(templateRepoResponse schematicsv1.TemplateRepoResponse) map[string]interface{} { + templateRepoResponseMap := map[string]interface{}{} + + templateRepoResponseMap["branch"] = templateRepoResponse.Branch + templateRepoResponseMap["release"] = templateRepoResponse.Release + templateRepoResponseMap["repo_sha_value"] = templateRepoResponse.RepoShaValue + templateRepoResponseMap["repo_url"] = templateRepoResponse.RepoURL + templateRepoResponseMap["url"] = templateRepoResponse.URL + templateRepoResponseMap["has_uploadedgitrepotar"] = templateRepoResponse.HasUploadedgitrepotar + + return templateRepoResponseMap +} + +func resourceIBMSchematicsWorkspaceWorkspaceStatusRequestToMap(workspaceStatusRequest schematicsv1.WorkspaceStatusRequest) map[string]interface{} { + workspaceStatusRequestMap := map[string]interface{}{} + + if workspaceStatusRequest.Frozen != nil { + workspaceStatusRequestMap["frozen"] = workspaceStatusRequest.Frozen + } + if workspaceStatusRequest.FrozenAt != nil { + workspaceStatusRequestMap["frozen_at"] = workspaceStatusRequest.FrozenAt.String() + } + if workspaceStatusRequest.FrozenBy != nil { + workspaceStatusRequestMap["frozen_by"] = workspaceStatusRequest.FrozenBy + } + if workspaceStatusRequest.Locked != nil { + workspaceStatusRequestMap["locked"] = workspaceStatusRequest.Locked + } + if workspaceStatusRequest.LockedBy != nil { + workspaceStatusRequestMap["locked_by"] = workspaceStatusRequest.LockedBy + } + if workspaceStatusRequest.LockedTime != nil { + workspaceStatusRequestMap["locked_time"] = workspaceStatusRequest.LockedTime.String() + } + + return workspaceStatusRequestMap +} + +func resourceIBMSchematicsWorkspaceWorkspaceStatusResponseToMap(workspaceStatusResponse schematicsv1.WorkspaceStatusResponse) map[string]interface{} { + workspaceStatusResponseMap := map[string]interface{}{} + + workspaceStatusResponseMap["frozen"] = workspaceStatusResponse.Frozen + if workspaceStatusResponse.FrozenAt != nil { + workspaceStatusResponseMap["frozen_at"] = workspaceStatusResponse.FrozenAt.String() + } + workspaceStatusResponseMap["frozen_by"] = workspaceStatusResponse.FrozenBy + workspaceStatusResponseMap["locked"] = workspaceStatusResponse.Locked + workspaceStatusResponseMap["locked_by"] = workspaceStatusResponse.LockedBy + if workspaceStatusResponse.LockedTime != nil { + workspaceStatusResponseMap["locked_time"] = workspaceStatusResponse.LockedTime.String() + } + + return workspaceStatusResponseMap +} + +func resourceIBMSchematicsWorkspaceTemplateRunTimeDataResponseToMap(templateRunTimeDataResponse schematicsv1.TemplateRunTimeDataResponse) map[string]interface{} { + templateRunTimeDataResponseMap := map[string]interface{}{} + + if templateRunTimeDataResponse.EngineCmd != nil { + templateRunTimeDataResponseMap["engine_cmd"] = templateRunTimeDataResponse.EngineCmd + } + if templateRunTimeDataResponse.EngineName != nil { + templateRunTimeDataResponseMap["engine_name"] = templateRunTimeDataResponse.EngineName + } + if templateRunTimeDataResponse.EngineVersion != nil { + templateRunTimeDataResponseMap["engine_version"] = templateRunTimeDataResponse.EngineVersion + } + if templateRunTimeDataResponse.ID != nil { + templateRunTimeDataResponseMap["id"] = templateRunTimeDataResponse.ID + } + if templateRunTimeDataResponse.LogStoreURL != nil { + templateRunTimeDataResponseMap["log_store_url"] = templateRunTimeDataResponse.LogStoreURL + } + if templateRunTimeDataResponse.OutputValues != nil { + outputValues := []interface{}{} + for _, outputValuesItem := range templateRunTimeDataResponse.OutputValues { + outputValues = append(outputValues, outputValuesItem) + } + templateRunTimeDataResponseMap["output_values"] = outputValues + } + if templateRunTimeDataResponse.Resources != nil { + resources := []interface{}{} + for _, resourcesItem := range templateRunTimeDataResponse.Resources { + resources = append(resources, resourcesItem) + } + templateRunTimeDataResponseMap["resources"] = resources + } + if templateRunTimeDataResponse.StateStoreURL != nil { + templateRunTimeDataResponseMap["state_store_url"] = templateRunTimeDataResponse.StateStoreURL + } + + return templateRunTimeDataResponseMap +} + +func resourceIBMSchematicsWorkspaceWorkspaceStatusMessageToMap(workspaceStatusMessage schematicsv1.WorkspaceStatusMessage) map[string]interface{} { + workspaceStatusMessageMap := map[string]interface{}{} + + if workspaceStatusMessage.StatusCode != nil { + workspaceStatusMessageMap["status_code"] = workspaceStatusMessage.StatusCode + } + if workspaceStatusMessage.StatusMsg != nil { + workspaceStatusMessageMap["status_msg"] = workspaceStatusMessage.StatusMsg + } + + return workspaceStatusMessageMap +} + +func resourceIBMSchematicsWorkspaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + updateWorkspaceOptions := &schematicsv1.UpdateWorkspaceOptions{} + replaceWorkspaceOptions := &schematicsv1.ReplaceWorkspaceOptions{} + + updateWorkspaceOptions.SetWID(d.Id()) + replaceWorkspaceOptions.SetWID(d.Id()) + + hasChange := false + + metadataChange := false + repoChange := false + templateInputsChange := false + + if d.HasChange("catalog_ref") { + catalogRefAttr := d.Get("catalog_ref").([]interface{}) + if len(catalogRefAttr) > 0 { + catalogRef := resourceIBMSchematicsWorkspaceMapToCatalogRef(d.Get("catalog_ref.0").(map[string]interface{})) + updateWorkspaceOptions.SetCatalogRef(&catalogRef) + replaceWorkspaceOptions.SetCatalogRef(&catalogRef) + hasChange = true + repoChange = true + } + } + + if d.HasChange("description") { + updateWorkspaceOptions.SetDescription(d.Get("description").(string)) + replaceWorkspaceOptions.SetDescription(d.Get("description").(string)) + hasChange = true + metadataChange = true + } + if d.HasChange("name") { + updateWorkspaceOptions.SetName(d.Get("name").(string)) + replaceWorkspaceOptions.SetName(d.Get("name").(string)) + hasChange = true + metadataChange = true + } + if d.HasChange("shared_data") { + sharedDataAttr := d.Get("shared_data").([]interface{}) + if len(sharedDataAttr) > 0 { + sharedData := resourceIBMSchematicsWorkspaceMapToSharedTargetData(d.Get("shared_data.0").(map[string]interface{})) + updateWorkspaceOptions.SetSharedData(&sharedData) + replaceWorkspaceOptions.SetSharedData(&sharedData) + hasChange = true + } + } + if d.HasChange("tags") { + updateWorkspaceOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + replaceWorkspaceOptions.SetTags(flex.ExpandStringList(d.Get("tags").([]interface{}))) + hasChange = true + metadataChange = true + } + + var templateData []schematicsv1.TemplateSourceDataRequest + + templateSourceDataRequestMap := map[string]interface{}{} + hasTemplateData := false + + if d.HasChange("template_env_settings") { + templateSourceDataRequestMap["env_values"] = d.Get("template_env_settings").([]interface{}) + hasTemplateData = true + } + if d.HasChange("template_git_folder") { + templateSourceDataRequestMap["folder"] = d.Get("template_git_folder").(string) + hasTemplateData = true + } + if d.HasChange("template_init_state_file") { + templateSourceDataRequestMap["init_state_file"] = d.Get("template_init_state_file").(string) + hasTemplateData = true + } + //if d.HasChange("template_type") { + templateSourceDataRequestMap["type"] = d.Get("template_type").(string) + updateWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) + replaceWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) + //hasTemplateData = true + //} + if d.HasChange("template_uninstall_script_name") { + templateSourceDataRequestMap["uninstall_script_name"] = d.Get("template_uninstall_script_name").(string) + hasTemplateData = true + } + if d.HasChange("template_values") { + templateSourceDataRequestMap["values"] = d.Get("template_values").(string) + hasTemplateData = true + } + if d.HasChange("template_values_metadata") { + templateSourceDataRequestMap["values_metadata"] = d.Get("template_values_metadata").([]interface{}) + hasTemplateData = true + } + if d.HasChange("template_inputs") { + templateSourceDataRequestMap["variablestore"] = d.Get("template_inputs").([]interface{}) + hasTemplateData = true + } + if hasTemplateData { + templateDataItem := resourceIBMSchematicsWorkspaceMapToTemplateSourceDataRequest(templateSourceDataRequestMap) + templateData = append(templateData, templateDataItem) + updateWorkspaceOptions.SetTemplateData(templateData) + replaceWorkspaceOptions.SetTemplateData(templateData) + hasChange = true + templateInputsChange = true + } + + templateRepoRequestMap := map[string]interface{}{} + hasTemplateRepo := false + if d.HasChange("template_git_branch") { + templateRepoRequestMap["branch"] = d.Get("template_git_branch").(string) + templateRepoRequestMap["url"] = d.Get("template_git_url").(string) + hasTemplateRepo = true + } + if d.HasChange("template_git_release") { + templateRepoRequestMap["release"] = d.Get("template_git_release").(string) + templateRepoRequestMap["url"] = d.Get("template_git_url").(string) + hasTemplateRepo = true + } + if d.HasChange("template_git_repo_sha_value") { + templateRepoRequestMap["repo_sha_value"] = d.Get("template_git_repo_sha_value").(string) + hasTemplateRepo = true + } + if d.HasChange("template_git_repo_url") { + templateRepoRequestMap["repo_url"] = d.Get("template_git_repo_url").(string) + hasTemplateRepo = true + } + if d.HasChange("template_git_url") { + templateRepoRequestMap["url"] = d.Get("template_git_url").(string) + hasTemplateRepo = true + } + if d.HasChange("template_git_has_uploadedgitrepotar") { + templateRepoRequestMap["has_uploadedgitrepotar"] = d.Get("template_git_has_uploadedgitrepotar").(string) + hasTemplateRepo = true + } + if hasTemplateRepo { + templateRepo := resourceIBMSchematicsWorkspaceMapToTemplateRepoUpdateRequest(templateRepoRequestMap) + updateWorkspaceOptions.SetTemplateRepo(&templateRepo) + replaceWorkspaceOptions.SetTemplateRepo(&templateRepo) + hasChange = true + repoChange = true + } + + //if d.HasChange("template_type") { + updateWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) + replaceWorkspaceOptions.SetType([]string{d.Get("template_type").(string)}) + //hasChange = true + //} + + workspaceStatusRequestMap := map[string]interface{}{} + workspaceStatus := false + if d.HasChange("frozen") { + workspaceStatusRequestMap["frozen"] = d.Get("frozen").(bool) + workspaceStatus = true + } + if d.HasChange("frozen_at") { + workspaceStatusRequestMap["frozen_at"] = d.Get("frozen_at").(string) + workspaceStatus = true + } + if d.HasChange("frozen_by") { + workspaceStatusRequestMap["frozen_by"] = d.Get("frozen_by").(string) + workspaceStatus = true + } + if d.HasChange("locked") { + workspaceStatusRequestMap["locked"] = d.Get("locked").(bool) + workspaceStatus = true + } + if d.HasChange("locked_by") { + workspaceStatusRequestMap["locked_by"] = d.Get("locked_by").(string) + workspaceStatus = true + } + if d.HasChange("locked_time") { + workspaceStatusRequestMap["locked_time"] = d.Get("locked_time").(string) + workspaceStatus = true + } + if workspaceStatus { + workspaceStatus := resourceIBMSchematicsWorkspaceMapToWorkspaceStatusUpdateRequest(workspaceStatusRequestMap) + updateWorkspaceOptions.SetWorkspaceStatus(&workspaceStatus) + replaceWorkspaceOptions.SetWorkspaceStatus(&workspaceStatus) + hasChange = true + metadataChange = true + } + + if hasChange { + changed := false + + if !changed && repoChange { + changed = true + _, response, err := schematicsClient.ReplaceWorkspaceWithContext(context, replaceWorkspaceOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceWorkspaceWithContext failed %s\n%s", err, response)) + } + } + + if !changed && metadataChange { + _, response, err := schematicsClient.UpdateWorkspaceWithContext(context, updateWorkspaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateWorkspaceWithContext failed %s\n%s", err, response)) + } + } + + if !changed && templateInputsChange { + + for i := range replaceWorkspaceOptions.TemplateData { + + workspaceId := d.Id() + runtimeData := d.Get("runtime_data").([]interface{}) + templateId := runtimeData[i].(map[string]interface{})["id"].(string) + + workspaceVariableRequestModel := replaceWorkspaceOptions.TemplateData[i].Variablestore + envVariables := replaceWorkspaceOptions.TemplateData[i].EnvValues + values := replaceWorkspaceOptions.TemplateData[i].Values + + replaceWorkspaceInputsOptions := &schematicsv1.ReplaceWorkspaceInputsOptions{ + WID: &workspaceId, + TID: &templateId, + EnvValues: envVariables, + Values: values, + Variablestore: workspaceVariableRequestModel, + } + + _, response, err := schematicsClient.ReplaceWorkspaceInputs(replaceWorkspaceInputsOptions) + if err != nil { + log.Printf("[DEBUG] ReplaceWorkspaceInputs failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ReplaceWorkspaceInputs failed %s\n%s", err, response)) + } + } + } + + } + + return resourceIBMSchematicsWorkspaceRead(context, d, meta) +} + +func resourceIBMSchematicsWorkspaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + schematicsClient, err := meta.(conns.ClientSession).SchematicsV1() + if err != nil { + return diag.FromErr(err) + } + + session, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + actionIDSplit := strings.Split(d.Id(), ".") + region := actionIDSplit[0] + schematicsURL, updatedURL, _ := SchematicsEndpointURL(region, meta) + if updatedURL { + schematicsClient.Service.Options.URL = schematicsURL + } + deleteWorkspaceOptions := &schematicsv1.DeleteWorkspaceOptions{} + + deleteWorkspaceOptions.SetWID(d.Id()) + + iamRefreshToken := session.Config.IAMRefreshToken + deleteWorkspaceOptions.SetRefreshToken(iamRefreshToken) + + _, response, err := schematicsClient.DeleteWorkspaceWithContext(context, deleteWorkspaceOptions) + if err != nil { + log.Printf("[DEBUG] DeleteWorkspaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteWorkspaceWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/schematics/resource_ibm_schematics_workspace_test.go b/ibm/service/schematics/resource_ibm_schematics_workspace_test.go new file mode 100644 index 000000000..3b0ad8d73 --- /dev/null +++ b/ibm/service/schematics/resource_ibm_schematics_workspace_test.go @@ -0,0 +1,247 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package schematics_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/schematics-go-sdk/schematicsv1" +) + +func TestAccIBMSchematicsWorkspaceBasic(t *testing.T) { + var conf schematicsv1.WorkspaceResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsWorkspaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsWorkspaceConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), + ), + }, + }, + }) +} + +func TestAccIBMSchematicsWorkspaceAllArgs(t *testing.T) { + var conf schematicsv1.WorkspaceResponse + description := fmt.Sprintf("tf-acc-test-schematics-all-args_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-acc-test-schematics_%d", acctest.RandIntRange(10, 100)) + templateType := "terraform_v0.13.5" + + descriptionUpdate := fmt.Sprintf("description_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf-acc-test-schematics_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMSchematicsWorkspaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMSchematicsWorkspaceConfig(description, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", description), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", name), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), + ), + }, + { + Config: testAccCheckIBMSchematicsWorkspaceConfigUpdate(descriptionUpdate, nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), + ), + }, + { + Config: testAccCheckIBMSchematicsWorkspaceConfigUpdateRepoURL(descriptionUpdate, nameUpdate, acc.RepoURL), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), + ), + }, + { + Config: testAccCheckIBMSchematicsWorkspaceConfigUpdateRepoBranch(descriptionUpdate, nameUpdate, acc.RepoURL, acc.RepoBranch), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMSchematicsWorkspaceExists("ibm_schematics_workspace.schematics_workspace", conf), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "description", descriptionUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_schematics_workspace.schematics_workspace", "template_type", templateType), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_at"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "created_by"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "crn"), + resource.TestCheckResourceAttrSet("ibm_schematics_workspace.schematics_workspace", "runtime_data.#"), + ), + }, + { + ResourceName: "ibm_schematics_workspace.schematics_workspace", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMSchematicsWorkspaceConfigBasic() string { + return ` + + resource "ibm_schematics_workspace" "schematics_workspace" { + description = "tf-acc-test-schematics" + name = "tf-acc-test-schematics" + location = "us-east" + resource_group = "default" + template_type = "terraform_v0.13.5" + } + ` +} + +func testAccCheckIBMSchematicsWorkspaceConfig(description string, name string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_workspace" "schematics_workspace" { + description = "%s" + location = "us-east" + name = "%s" + resource_group = "default" + template_type = "terraform_v0.13.5" + } + `, description, name) +} + +func testAccCheckIBMSchematicsWorkspaceConfigUpdate(description string, name string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_workspace" "schematics_workspace" { + description = "%s" + location = "us-east" + name = "%s" + resource_group = "default" + template_type = "terraform_v0.13.5" + template_inputs { + name = "testinput" + value = "test" + type = "string" + } + } + `, description, name) +} + +func testAccCheckIBMSchematicsWorkspaceConfigUpdateRepoURL(description string, name string, repoURL string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_workspace" "schematics_workspace" { + description = "%s" + location = "us-east" + name = "%s" + resource_group = "default" + template_type = "terraform_v0.13.5" + template_git_url = "%s" + template_inputs { + name = "testinput" + value = "test" + type = "string" + } + } + `, description, name, repoURL) +} + +func testAccCheckIBMSchematicsWorkspaceConfigUpdateRepoBranch(description string, name string, repoURL string, repoBranch string) string { + return fmt.Sprintf(` + + resource "ibm_schematics_workspace" "schematics_workspace" { + description = "%s" + location = "us-east" + name = "%s" + resource_group = "default" + template_type = "terraform_v0.13.5" + template_git_url = "%s" + template_inputs { + name = "testinput" + value = "test" + type = "string" + } + template_git_branch = "%s" + } + `, description, name, repoURL, repoBranch) +} + +func testAccCheckIBMSchematicsWorkspaceExists(n string, obj schematicsv1.WorkspaceResponse) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + + getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} + + getWorkspaceOptions.SetWID(rs.Primary.ID) + + workspaceResponse, _, err := schematicsClient.GetWorkspace(getWorkspaceOptions) + if err != nil { + return err + } + + obj = *workspaceResponse + return nil + } +} + +func testAccCheckIBMSchematicsWorkspaceDestroy(s *terraform.State) error { + schematicsClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SchematicsV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_schematics_workspace" { + continue + } + + getWorkspaceOptions := &schematicsv1.GetWorkspaceOptions{} + + getWorkspaceOptions.SetWID(rs.Primary.ID) + + // Try to find the key + _, response, err := schematicsClient.GetWorkspace(getWorkspaceOptions) + + if err == nil { + return fmt.Errorf("schematics_workspace still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for schematics_workspace (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/secretsmanager/README.md b/ibm/service/secretsmanager/README.md new file mode 100644 index 000000000..8a457ce67 --- /dev/null +++ b/ibm/service/secretsmanager/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Secrets Manager + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the Secrets Manager resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/secrets_manager_secret) +* IBM API Docs: [IBM API Docs for Secrets Manager](https://cloud.ibm.com/apidocs/secrets-manager) +* IBM Secrets Manager SDK: [IBM SDK for Secrets Manager](https://github.com/IBM/secrets-manager-go-sdk) diff --git a/ibm/data_source_ibm_secrets_manager_secret.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go similarity index 84% rename from ibm/data_source_ibm_secrets_manager_secret.go rename to ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go index 497f6f964..02b7b1a39 100644 --- a/ibm/data_source_ibm_secrets_manager_secret.go +++ b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package secretsmanager import ( "context" @@ -10,12 +10,14 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSecretsManagerSecret() *schema.Resource { +func DataSourceIBMSecretsManagerSecret() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMSecretsManagerSecretRead, @@ -25,13 +27,13 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { Required: true, Description: "Secrets Manager instance GUID", }, - "secret_type": &schema.Schema{ + "secret_type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeDataSourceValidator("ibm_secrets_manager_secret", "secret_type"), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secret", "secret_type"), Description: "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", }, - "secret_id": &schema.Schema{ + "secret_id": { Type: schema.TypeString, Required: true, Description: "The v4 UUID that uniquely identifies the secret.", @@ -39,22 +41,22 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeDataSourceValidator("ibm_secrets_manager_secret", "endpoint_type"), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secret", "endpoint_type"), Description: "Endpoint Type. 'public' or 'private'", Default: "public", }, - "metadata": &schema.Schema{ + "metadata": { Type: schema.TypeList, Computed: true, Description: "The metadata that describes the resource array.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "collection_type": &schema.Schema{ + "collection_type": { Type: schema.TypeString, Computed: true, Description: "The type of resources in the resource array.", }, - "collection_total": &schema.Schema{ + "collection_total": { Type: schema.TypeInt, Computed: true, Description: "The number of elements in the resource array.", @@ -62,27 +64,27 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { }, }, }, - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The MIME type that represents the secret.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Computed: true, Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", }, - "secret_group_id": &schema.Schema{ + "secret_group_id": { Type: schema.TypeString, Computed: true, Description: "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", }, - "labels": &schema.Schema{ + "labels": { Type: schema.TypeList, Computed: true, Description: "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", @@ -90,58 +92,58 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { Type: schema.TypeString, }, }, - "state": &schema.Schema{ + "state": { Type: schema.TypeInt, Computed: true, Description: "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", }, - "state_description": &schema.Schema{ + "state_description": { Type: schema.TypeString, Computed: true, Description: "A text representation of the secret state.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", }, - "creation_date": &schema.Schema{ + "creation_date": { Type: schema.TypeString, Computed: true, Description: "The date the secret was created. The date format follows RFC 3339.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for the entity that created the secret.", }, - "last_update_date": &schema.Schema{ + "last_update_date": { Type: schema.TypeString, Computed: true, Description: "Updates when the actual secret is modified. The date format follows RFC 3339.", }, - "versions": &schema.Schema{ + "versions": { Type: schema.TypeList, Computed: true, Description: "An array that contains metadata for each secret version.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The ID of the secret version.", }, - "creation_date": &schema.Schema{ + "creation_date": { Type: schema.TypeString, Computed: true, Description: "The date that the version of the secret was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for the entity that created the secret.", }, - "auto_rotated": &schema.Schema{ + "auto_rotated": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether the version of the secret was created by automatic rotation.", @@ -149,46 +151,46 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { }, }, }, - "expiration_date": &schema.Schema{ + "expiration_date": { Type: schema.TypeString, Computed: true, Description: "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", }, - "payload": &schema.Schema{ + "payload": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The new secret data to assign to an `arbitrary` secret.", }, - "secret_data": &schema.Schema{ + "secret_data": { Type: schema.TypeMap, Sensitive: true, Computed: true, Description: "The secret data object", }, - "username": &schema.Schema{ + "username": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The username to assign to this secret.", }, - "password": &schema.Schema{ + "password": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The password to assign to this secret.", }, - "next_rotation_date": &schema.Schema{ + "next_rotation_date": { Type: schema.TypeString, Computed: true, Description: "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", }, - "ttl": &schema.Schema{ + "ttl": { Type: schema.TypeString, Computed: true, Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", }, - "access_groups": &schema.Schema{ + "access_groups": { Type: schema.TypeList, Computed: true, Description: "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage > Access (IAM) > Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", @@ -196,18 +198,18 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { Type: schema.TypeString, }, }, - "api_key": &schema.Schema{ + "api_key": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", }, - "service_id": &schema.Schema{ + "service_id": { Type: schema.TypeString, Computed: true, Description: "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", }, - "reuse_api_key": &schema.Schema{ + "reuse_api_key": { Type: schema.TypeBool, Computed: true, Description: "(IAM credentials) Reuse the service ID and API key for future read operations.", @@ -216,42 +218,42 @@ func dataSourceIBMSecretsManagerSecret() *schema.Resource { } } -func datasourceIBMSecretsManagerSecretValidator() *ResourceValidator { +func DataSourceIBMSecretsManagerSecretValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - secretType := "arbitrary, iam_credentials, username_password" + validateSchema := make([]validate.ValidateSchema, 0) + secretType := "arbitrary,iam_credentials,imported_cert,public_cert,private_cert,username_password,kv" endpointType := "public, private" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "secret_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: secretType}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "endpoint_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: endpointType}) - ibmSecretsManagerSecretdatasourceValidator := ResourceValidator{ResourceName: "ibm_secrets_manager_secret", Schema: validateSchema} + ibmSecretsManagerSecretdatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_secrets_manager_secret", Schema: validateSchema} return &ibmSecretsManagerSecretdatasourceValidator } func dataSourceIBMSecretsManagerSecretRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - bluemixSession, err := meta.(ClientSession).BluemixSession() + bluemixSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } region := bluemixSession.Config.Region - secretsManagerClient, err := meta.(ClientSession).SecretsManagerV1() + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV1() if err != nil { return diag.FromErr(err) } - rContollerClient, err := meta.(ClientSession).ResourceControllerAPIV2() + rContollerClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() if err != nil { return diag.FromErr(err) } @@ -272,14 +274,14 @@ func dataSourceIBMSecretsManagerSecretRead(context context.Context, d *schema.Re if crnData[4] == "secrets-manager" { if endpointType == "private" { - smEndpointURL = "https://" + instanceID + "private" + "." + region + ".secrets-manager.appdomain.cloud" + smEndpointURL = "https://" + instanceID + ".private." + region + ".secrets-manager.appdomain.cloud" } else { smEndpointURL = "https://" + instanceID + "." + region + ".secrets-manager.appdomain.cloud" } - smUrl := envFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) + smUrl := conns.EnvFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) secretsManagerClient.Service.Options.URL = smUrl } else { - return diag.FromErr(fmt.Errorf("Invalid or unsupported service Instance")) + return diag.FromErr(fmt.Errorf("[ERROR] Invalid or unsupported service Instance")) } secretType := d.Get("secret_type").(string) @@ -300,7 +302,7 @@ func dataSourceIBMSecretsManagerSecretRead(context context.Context, d *schema.Re if getSecret.Metadata != nil { err = d.Set("metadata", dataSourceGetSecretFlattenMetadata(*getSecret.Metadata)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting metadata %s", err)) } } diff --git a/ibm/data_source_ibm_secrets_manager_secret_test.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go similarity index 77% rename from ibm/data_source_ibm_secrets_manager_secret_test.go rename to ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go index 1c7a83065..d5cbd1b56 100644 --- a/ibm/data_source_ibm_secrets_manager_secret_test.go +++ b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go @@ -1,24 +1,26 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package secretsmanager_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMSecretsManagerSecretDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSecretsManagerSecretDataSourceConfigBasic(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_type", secretsManagerSecretType), + resource.TestCheckResourceAttr("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_type", acc.SecretsManagerSecretType), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "id"), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_type"), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_id"), @@ -36,5 +38,5 @@ func testAccCheckIBMSecretsManagerSecretDataSourceConfigBasic() string { secret_type = "%s" secret_id = "%s" } - `, secretsManagerInstanceID, secretsManagerSecretType, secretsManagerSecretID) + `, acc.SecretsManagerInstanceID, acc.SecretsManagerSecretType, acc.SecretsManagerSecretID) } diff --git a/ibm/data_source_ibm_secrets_manager_secrets.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go similarity index 86% rename from ibm/data_source_ibm_secrets_manager_secrets.go rename to ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go index 8bb34a2e2..f999d7def 100644 --- a/ibm/data_source_ibm_secrets_manager_secrets.go +++ b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package secretsmanager import ( "context" @@ -10,12 +10,14 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMSecretsManagerSecrets() *schema.Resource { +func DataSourceIBMSecretsManagerSecrets() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMSecretsManagerSecretsRead, @@ -25,31 +27,31 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { Required: true, Description: "Secrets Manager instance GUID", }, - "secret_type": &schema.Schema{ + "secret_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeDataSourceValidator("ibm_secrets_manager_secrets", "secret_type"), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secrets", "secret_type"), Description: "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", }, "endpoint_type": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeDataSourceValidator("ibm_secrets_manager_secrets", "endpoint_type"), + ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secrets", "endpoint_type"), Description: "Endpoint Type. 'public' or 'private'", Default: "public", }, - "metadata": &schema.Schema{ + "metadata": { Type: schema.TypeList, Computed: true, Description: "The metadata that describes the resource array.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "collection_type": &schema.Schema{ + "collection_type": { Type: schema.TypeString, Computed: true, Description: "The type of resources in the resource array.", }, - "collection_total": &schema.Schema{ + "collection_total": { Type: schema.TypeInt, Computed: true, Description: "The number of elements in the resource array.", @@ -57,38 +59,38 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { }, }, }, - "secrets": &schema.Schema{ + "secrets": { Type: schema.TypeList, Computed: true, Description: "A collection of secret resources.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The MIME type that represents the secret.", }, - "secret_id": &schema.Schema{ + "secret_id": { Type: schema.TypeString, Computed: true, Description: "The v4 UUID that uniquely identifies the secret.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Computed: true, Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", }, - "secret_group_id": &schema.Schema{ + "secret_group_id": { Type: schema.TypeString, Computed: true, Description: "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", }, - "labels": &schema.Schema{ + "labels": { Type: schema.TypeList, Computed: true, Description: "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", @@ -96,63 +98,63 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { Type: schema.TypeString, }, }, - "state": &schema.Schema{ + "state": { Type: schema.TypeInt, Computed: true, Description: "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", }, - "state_description": &schema.Schema{ + "state_description": { Type: schema.TypeString, Computed: true, Description: "A text representation of the secret state.", }, - "secret_type": &schema.Schema{ + "secret_type": { Type: schema.TypeString, Computed: true, Description: "The secret type.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", }, - "creation_date": &schema.Schema{ + "creation_date": { Type: schema.TypeString, Computed: true, Description: "The date the secret was created. The date format follows RFC 3339.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for the entity that created the secret.", }, - "last_update_date": &schema.Schema{ + "last_update_date": { Type: schema.TypeString, Computed: true, Description: "Updates when the actual secret is modified. The date format follows RFC 3339.", }, - "versions": &schema.Schema{ + "versions": { Type: schema.TypeList, Computed: true, Description: "An array that contains metadata for each secret version.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The ID of the secret version.", }, - "creation_date": &schema.Schema{ + "creation_date": { Type: schema.TypeString, Computed: true, Description: "The date that the version of the secret was created.", }, - "created_by": &schema.Schema{ + "created_by": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for the entity that created the secret.", }, - "auto_rotated": &schema.Schema{ + "auto_rotated": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether the version of the secret was created by automatic rotation.", @@ -160,46 +162,46 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { }, }, }, - "expiration_date": &schema.Schema{ + "expiration_date": { Type: schema.TypeString, Computed: true, Description: "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", }, - "payload": &schema.Schema{ + "payload": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The new secret data to assign to an `arbitrary` secret.", }, - "secret_data": &schema.Schema{ + "secret_data": { Type: schema.TypeMap, Sensitive: true, Computed: true, Description: "The secret data object", }, - "username": &schema.Schema{ + "username": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The username to assign to this secret.", }, - "password": &schema.Schema{ + "password": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The password to assign to this secret.", }, - "next_rotation_date": &schema.Schema{ + "next_rotation_date": { Type: schema.TypeString, Computed: true, Description: "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", }, - "ttl": &schema.Schema{ + "ttl": { Type: schema.TypeString, Computed: true, Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", }, - "access_groups": &schema.Schema{ + "access_groups": { Type: schema.TypeList, Computed: true, Description: "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage > Access (IAM) > Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", @@ -207,18 +209,18 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { Type: schema.TypeString, }, }, - "api_key": &schema.Schema{ + "api_key": { Type: schema.TypeString, Computed: true, Sensitive: true, Description: "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", }, - "service_id": &schema.Schema{ + "service_id": { Type: schema.TypeString, Computed: true, Description: "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", }, - "reuse_api_key": &schema.Schema{ + "reuse_api_key": { Type: schema.TypeBool, Computed: true, Description: "(IAM credentials) Reuse the service ID and API key for future read operations.", @@ -230,42 +232,42 @@ func dataSourceIBMSecretsManagerSecrets() *schema.Resource { } } -func datasourceIBMSecretsManagerSecretsValidator() *ResourceValidator { +func DataSourceIBMSecretsManagerSecretsValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) secretType := "arbitrary, iam_credentials, username_password" endpointType := "public, private" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "secret_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: secretType}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "endpoint_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: endpointType}) - ibmSecretsManagerSecretsdatasourceValidator := ResourceValidator{ResourceName: "ibm_secrets_manager_secrets", Schema: validateSchema} + ibmSecretsManagerSecretsdatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_secrets_manager_secrets", Schema: validateSchema} return &ibmSecretsManagerSecretsdatasourceValidator } func dataSourceIBMSecretsManagerSecretsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - bluemixSession, err := meta.(ClientSession).BluemixSession() + bluemixSession, err := meta.(conns.ClientSession).BluemixSession() if err != nil { return diag.FromErr(err) } region := bluemixSession.Config.Region - secretsManagerClient, err := meta.(ClientSession).SecretsManagerV1() + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV1() if err != nil { return diag.FromErr(err) } - rContollerClient, err := meta.(ClientSession).ResourceControllerAPIV2() + rContollerClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() if err != nil { return diag.FromErr(err) } @@ -286,14 +288,14 @@ func dataSourceIBMSecretsManagerSecretsRead(context context.Context, d *schema.R if crnData[4] == "secrets-manager" { if endpointType == "private" { - smEndpointURL = "https://" + instanceID + "private" + "." + region + ".secrets-manager.appdomain.cloud" + smEndpointURL = "https://" + instanceID + ".private." + region + ".secrets-manager.appdomain.cloud" } else { smEndpointURL = "https://" + instanceID + "." + region + ".secrets-manager.appdomain.cloud" } - smUrl := envFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) + smUrl := conns.EnvFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) secretsManagerClient.Service.Options.URL = smUrl } else { - return diag.FromErr(fmt.Errorf("Invalid or unsupported service Instance")) + return diag.FromErr(fmt.Errorf("[ERROR] Invalid or unsupported service Instance")) } listAllSecretsOptions := &secretsmanagerv1.ListAllSecretsOptions{} @@ -337,14 +339,14 @@ func dataSourceIBMSecretsManagerSecretsRead(context context.Context, d *schema.R if listSecrets.Metadata != nil { err = d.Set("metadata", dataSourceListSecretsFlattenMetadata(*listSecrets.Metadata)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting metadata %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting metadata %s", err)) } } if listSecrets.Resources != nil { err = d.Set("secrets", dataSourceListSecretsFlattenResources(listSecrets.Resources)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resources %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resources %s", err)) } } diff --git a/ibm/data_source_ibm_secrets_manager_secrets_test.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go similarity index 80% rename from ibm/data_source_ibm_secrets_manager_secrets_test.go rename to ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go index 6598aa606..9849e835b 100644 --- a/ibm/data_source_ibm_secrets_manager_secrets_test.go +++ b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go @@ -1,24 +1,26 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package secretsmanager_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMSecretsManagerSecretsDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMSecretsManagerSecretsDataSourceConfigBasic(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secret_type", secretsManagerSecretType), + resource.TestCheckResourceAttr("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secret_type", acc.SecretsManagerSecretType), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "id"), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secret_type"), resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "metadata.#"), @@ -39,5 +41,5 @@ func testAccCheckIBMSecretsManagerSecretsDataSourceConfigBasic() string { output "WorkSpaceValues" { value = data.ibm_secrets_manager_secrets.secrets_manager_secrets.secret_type } - `, secretsManagerInstanceID, secretsManagerSecretType) + `, acc.SecretsManagerInstanceID, acc.SecretsManagerSecretType) } diff --git a/ibm/service/transitgateway/README.md b/ibm/service/transitgateway/README.md new file mode 100644 index 000000000..55422f706 --- /dev/null +++ b/ibm/service/transitgateway/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider Transit Gateway Services + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the TG resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/tg_connection) +* IBM API Docs: [IBM API Docs for TG](https://cloud.ibm.com/apidocs/transit-gateway) +* IBM TG SDK: [IBM SDK for TG](https://github.com/IBM/networking-go-sdk/tree/master/transitgatewayapisv1) diff --git a/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter.go b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter.go new file mode 100644 index 000000000..8eaeaaa2e --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter.go @@ -0,0 +1,114 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + tgPrefixFilterId = "filter_id" +) + +func DataSourceIBMTransitGatewayConnectionPrefixFilter() *schema.Resource { + + return &schema.Resource{ + Read: dataSourceIBMTransitGatewayConnectionPrefixFilterRead, + Schema: map[string]*schema.Schema{ + tgGatewayId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway identifier", + }, + tgConnectionId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway Connection identifier", + }, + tgPrefixFilterId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway Connection Prefix Filter identifier", + }, + tgAction: { + Type: schema.TypeString, + Computed: true, + Description: "Whether to permit or deny the prefix filter", + }, + tgBefore: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of prefix filter that handles ordering", + }, + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was created", + }, + tgGe: { + Type: schema.TypeInt, + Computed: true, + Description: "IP Prefix GE", + }, + tgLe: { + Type: schema.TypeInt, + Computed: true, + Description: "IP Prefix LE", + }, + tgPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "IP Prefix", + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was last updated", + }, + }, + } +} + +func dataSourceIBMTransitGatewayConnectionPrefixFilterRead(d *schema.ResourceData, meta interface{}) error { + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(tgGatewayId).(string) + connectionId := d.Get(tgConnectionId).(string) + filterId := d.Get(tgPrefixFilterId).(string) + + getTransitGatewayConnectionPrefixFilterOptionsModel := &transitgatewayapisv1.GetTransitGatewayConnectionPrefixFilterOptions{} + getTransitGatewayConnectionPrefixFilterOptionsModel.SetTransitGatewayID(gatewayId) + getTransitGatewayConnectionPrefixFilterOptionsModel.SetID(connectionId) + getTransitGatewayConnectionPrefixFilterOptionsModel.SetFilterID(filterId) + prefixFilter, response, err := client.GetTransitGatewayConnectionPrefixFilter(getTransitGatewayConnectionPrefixFilterOptionsModel) + if err != nil { + return fmt.Errorf("Error retrieving transit gateway connection prefix filter (%s): %s\n%s", filterId, err, response) + } + + d.SetId(*prefixFilter.ID) + d.Set(tgPrefixFilterId, prefixFilter.ID) + d.Set(tgAction, prefixFilter.Action) + d.Set(tgCreatedAt, prefixFilter.CreatedAt.String()) + d.Set(tgPrefix, prefixFilter.Prefix) + + if prefixFilter.UpdatedAt != nil { + d.Set(tgUpdatedAt, prefixFilter.UpdatedAt.String()) + } + if prefixFilter.Before != nil { + d.Set(tgBefore, prefixFilter.Before) + } + if prefixFilter.Ge != nil { + d.Set(tgGe, prefixFilter.Ge) + } + if prefixFilter.Le != nil { + d.Set(tgLe, prefixFilter.Le) + } + + return nil +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter_test.go b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter_test.go new file mode 100644 index 000000000..339db4ce8 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filter_test.go @@ -0,0 +1,62 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccIBMTransitGatewayConnectionPrefixFilterDataSource_basic(t *testing.T) { + randNum := acctest.RandIntRange(10, 100) + gatewayName := fmt.Sprintf("gateway-name-%d", randNum) + location := fmt.Sprintf("us-south") + connectionName := fmt.Sprintf("connection-name-%d", randNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMTransitGatewayDataConnectionPrefixFilterSourceConfig(gatewayName, location, connectionName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_tg_connection_prefix_filter.ds_tg_prefix_filter", "filter_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMTransitGatewayDataConnectionPrefixFilterSourceConfig(gatewayName, location, connectionName string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_connection" "test_tg_connection"{ + gateway = ibm_tg_gateway.test_tg_gateway.id + network_type = "classic" + name = "%s" + } + + resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.test_tg_gateway.id + connection_id = ibm_tg_connection.test_tg_connection.connection_id + action = "permit" + prefix = "10.0.0.0/16" + } + + data "ibm_tg_connection_prefix_filter" "ds_tg_prefix_filter" { + gateway = ibm_tg_gateway.test_tg_gateway.id + connection_id = ibm_tg_connection.test_tg_connection.connection_id + filter_id = ibm_tg_connection_prefix_filter.test_tg_prefix_filter.filter_id + } + `, gatewayName, location, connectionName) +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters.go b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters.go new file mode 100644 index 000000000..ea826eb57 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "time" +) + +const ( + tgPrefixFilters = "prefix_filters" + tgAction = "action" + tgBefore = "before" + tgGe = "ge" + tgLe = "le" + tgPrefix = "prefix" +) + +func DataSourceIBMTransitGatewayConnectionPrefixFilters() *schema.Resource { + + return &schema.Resource{ + Read: dataSourceIBMTransitGatewayConnectionPrefixFiltersRead, + Schema: map[string]*schema.Schema{ + tgGatewayId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway identifier", + }, + tgConnectionId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway Connection identifier", + }, + tgPrefixFilters: { + Type: schema.TypeList, + Description: "Collection of prefix filters", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgID: { + Type: schema.TypeString, + Computed: true, + }, + tgAction: { + Type: schema.TypeString, + Computed: true, + Description: "Whether to permit or deny the prefix filter", + }, + tgBefore: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of prefix filter that handles ordering", + }, + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was created", + }, + tgGe: { + Type: schema.TypeInt, + Computed: true, + Description: "IP Prefix GE", + }, + tgLe: { + Type: schema.TypeInt, + Computed: true, + Description: "IP Prefix LE", + }, + tgPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "IP Prefix", + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was last updated", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMTransitGatewayConnectionPrefixFiltersRead(d *schema.ResourceData, meta interface{}) error { + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(tgGatewayId).(string) + connectionId := d.Get(tgConnectionId).(string) + + listTransitGatewayConnectionPrefixFiltersOptionsModel := &transitgatewayapisv1.ListTransitGatewayConnectionPrefixFiltersOptions{} + listTransitGatewayConnectionPrefixFiltersOptionsModel.SetTransitGatewayID(gatewayId) + listTransitGatewayConnectionPrefixFiltersOptionsModel.SetID(connectionId) + listPrefixFilters, response, err := client.ListTransitGatewayConnectionPrefixFilters(listTransitGatewayConnectionPrefixFiltersOptionsModel) + if err != nil { + return fmt.Errorf("Error while listing transit gateway connection prefix filters %s\n%s", err, response) + } + + prefixFiltersCollection := make([]map[string]interface{}, 0) + for _, prefixFilter := range listPrefixFilters.PrefixFilters { + tgPrefixFilter := map[string]interface{}{} + tgPrefixFilter[tgID] = prefixFilter.ID + tgPrefixFilter[tgAction] = prefixFilter.Action + tgPrefixFilter[tgCreatedAt] = prefixFilter.CreatedAt.String() + tgPrefixFilter[tgPrefix] = prefixFilter.Prefix + + if prefixFilter.UpdatedAt != nil { + tgPrefixFilter[tgUpdatedAt] = prefixFilter.UpdatedAt.String() + } + if prefixFilter.Before != nil { + tgPrefixFilter[tgBefore] = prefixFilter.Before + } + if prefixFilter.Ge != nil { + tgPrefixFilter[tgGe] = prefixFilter.Ge + } + if prefixFilter.Le != nil { + tgPrefixFilter[tgLe] = prefixFilter.Le + } + + prefixFiltersCollection = append(prefixFiltersCollection, tgPrefixFilter) + } + + d.Set(tgPrefixFilters, prefixFiltersCollection) + d.SetId(dataSourceIBMTransitGatewayConnectionPrefixFiltersID(d)) + return nil +} + +// dataSourceIBMTransitGatewayRouteReportsID returns a reasonable ID for a transit gateways list. +func dataSourceIBMTransitGatewayConnectionPrefixFiltersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters_test.go b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters_test.go new file mode 100644 index 000000000..a3a7235a3 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_connection_prefix_filters_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccIBMTransitGatewayConnectionPrefixFiltersDataSource_basic(t *testing.T) { + randNum := acctest.RandIntRange(10, 100) + gatewayName := fmt.Sprintf("gateway-name-%d", randNum) + location := fmt.Sprintf("us-south") + connectionName := fmt.Sprintf("connection-name-%d", randNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMTransitGatewayDataConnectionPrefixFiltersSourceConfig(gatewayName, location, connectionName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_tg_connection_prefix_filters.ds_tg_prefix_filters", "prefix_filters.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMTransitGatewayDataConnectionPrefixFiltersSourceConfig(gatewayName, location, connectionName string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_connection" "test_tg_connection"{ + gateway = ibm_tg_gateway.test_tg_gateway.id + network_type = "classic" + name = "%s" + } + + resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.test_tg_gateway.id + connection_id = ibm_tg_connection.test_tg_connection.connection_id + action = "permit" + prefix = "10.0.0.0/16" + } + + data "ibm_tg_connection_prefix_filters" "ds_tg_prefix_filters" { + gateway = ibm_tg_gateway.test_tg_gateway.id + connection_id = ibm_tg_connection.test_tg_connection.connection_id + } + `, gatewayName, location, connectionName) +} diff --git a/ibm/data_source_ibm_tg_gateway.go b/ibm/service/transitgateway/data_source_ibm_tg_gateway.go similarity index 92% rename from ibm/data_source_ibm_tg_gateway.go rename to ibm/service/transitgateway/data_source_ibm_tg_gateway.go index 2b168a40e..e8f183eab 100644 --- a/ibm/data_source_ibm_tg_gateway.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_gateway.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/transitgatewayapisv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,9 +15,10 @@ import ( const ( tgConnName = "name" tgConnections = "connections" + ID = "id" ) -func dataSourceIBMTransitGateway() *schema.Resource { +func DataSourceIBMTransitGateway() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMTransitGatewayRead, @@ -25,7 +27,7 @@ func dataSourceIBMTransitGateway() *schema.Resource { Type: schema.TypeString, Required: true, Description: "The Transit Gateway identifier", - ValidateFunc: InvokeValidator("ibm_tg_gateway", tgName), + ValidateFunc: validate.InvokeValidator("ibm_tg_gateway", tgName), }, tgCrn: { Type: schema.TypeString, @@ -147,7 +149,7 @@ func dataSourceIBMTransitGatewayRead(d *schema.ResourceData, meta interface{}) e listTransitGatewaysOptionsModel := &transitgatewayapisv1.ListTransitGatewaysOptions{} listTransitGateways, response, err := client.ListTransitGateways(listTransitGatewaysOptionsModel) if err != nil { - return fmt.Errorf("Error while listing transit gateways %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while listing transit gateways %s\n%s", err, response) } gwName := d.Get(tgName).(string) @@ -176,8 +178,7 @@ func dataSourceIBMTransitGatewayRead(d *schema.ResourceData, meta interface{}) e } if !foundGateway { - return fmt.Errorf( - "Couldn't find any gateway with the specified name: (%s)", gwName) + return fmt.Errorf("[ERROR] Couldn't find any gateway with the specified name: (%s)", gwName) } return dataSourceIBMTransitGatewayConnectionsRead(d, meta) @@ -196,7 +197,7 @@ func dataSourceIBMTransitGatewayConnectionsRead(d *schema.ResourceData, meta int listTransitGatewayConnectionsOptions.SetTransitGatewayID(tgGatewayId) listTGConnections, response, err := client.ListTransitGatewayConnections(listTransitGatewayConnectionsOptions) if err != nil { - return fmt.Errorf("Error while listing transit gateway connections %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while listing transit gateway connections %s\n%s", err, response) } connections := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_tg_gateway_test.go b/ibm/service/transitgateway/data_source_ibm_tg_gateway_test.go similarity index 93% rename from ibm/data_source_ibm_tg_gateway_test.go rename to ibm/service/transitgateway/data_source_ibm_tg_gateway_test.go index b2e087deb..42efd70f3 100644 --- a/ibm/data_source_ibm_tg_gateway_test.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_gateway_test.go @@ -1,28 +1,30 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMTransitGatewayDataSource_basic(t *testing.T) { gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) - location := fmt.Sprintf("us-south") + location := "us-south" classicConnName := fmt.Sprintf("classic-connection-name-%d", acctest.RandIntRange(10, 100)) greConnName := fmt.Sprintf("gre-connection-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMTransitGatewayDataSourceConfig(gatewayname, location), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -31,7 +33,7 @@ func TestAccIBMTransitGatewayDataSource_basic(t *testing.T) { "data.ibm_tg_gateway.test_tg_gateway", "location", location), ), }, - resource.TestStep{ + { Config: testAccCheckIBMTransitGatewayGreConnectionDataSourceConfig(gatewayname, location, classicConnName, greConnName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_tg_gateway.test_tg_gateway", "connections.#"), diff --git a/ibm/data_source_ibm_tg_gateways.go b/ibm/service/transitgateway/data_source_ibm_tg_gateways.go similarity index 94% rename from ibm/data_source_ibm_tg_gateways.go rename to ibm/service/transitgateway/data_source_ibm_tg_gateways.go index 847d0f399..e0f2bf0ad 100644 --- a/ibm/data_source_ibm_tg_gateways.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_gateways.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "fmt" @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMTransitGateways() *schema.Resource { +func DataSourceIBMTransitGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMTransitGatewaysRead, @@ -75,7 +75,7 @@ func dataSourceIBMTransitGatewaysRead(d *schema.ResourceData, meta interface{}) listTransitGatewaysOptionsModel := &transitgatewayapisv1.ListTransitGatewaysOptions{} listTransitGateways, response, err := client.ListTransitGateways(listTransitGatewaysOptionsModel) if err != nil { - return fmt.Errorf("Error while listing transit gateways %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while listing transit gateways %s\n%s", err, response) } tgws := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_tg_gateways_test.go b/ibm/service/transitgateway/data_source_ibm_tg_gateways_test.go similarity index 86% rename from ibm/data_source_ibm_tg_gateways_test.go rename to ibm/service/transitgateway/data_source_ibm_tg_gateways_test.go index 8e7397546..21b167303 100644 --- a/ibm/data_source_ibm_tg_gateways_test.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_gateways_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,11 +16,11 @@ import ( func TestAccIBMTransitGatewaysDataSource_basic(t *testing.T) { resName := "data.ibm_tg_gateways.test1" gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) - location := fmt.Sprintf("us-south") + location := "us-south" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { @@ -44,7 +46,7 @@ func TestAccIBMTransitGatewaysDataSource_basic(t *testing.T) { func testAccCheckIBMTransitGatewaysDataSourceConfig() string { // status filter defaults to empty - return fmt.Sprintf(` + return ` data "ibm_tg_gateways" "test1" { - }`) + }` } diff --git a/ibm/data_source_ibm_tg_location.go b/ibm/service/transitgateway/data_source_ibm_tg_location.go similarity index 94% rename from ibm/data_source_ibm_tg_location.go rename to ibm/service/transitgateway/data_source_ibm_tg_location.go index 727517cc8..e27f7fd96 100644 --- a/ibm/data_source_ibm_tg_location.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_location.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "fmt" @@ -16,7 +16,7 @@ const ( tgLocationsDisplayName = "display_name" ) -func dataSourceIBMTransitGatewaysLocation() *schema.Resource { +func DataSourceIBMTransitGatewaysLocation() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMTransitGatewaysLocationRead, Schema: map[string]*schema.Schema{ @@ -76,7 +76,7 @@ func dataSourceIBMTransitGatewaysLocationRead(d *schema.ResourceData, meta inter detailGatewayLocationOptionsModel.Name = &locName detailTransitGatewayLocation, response, err := client.GetGatewayLocation(detailGatewayLocationOptionsModel) if err != nil { - return fmt.Errorf("Error while fetching transit gateway detailed location: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while fetching transit gateway detailed location: %s\n%s", err, response) } if detailTransitGatewayLocation != nil { diff --git a/ibm/data_source_ibm_tg_location_test.go b/ibm/service/transitgateway/data_source_ibm_tg_location_test.go similarity index 82% rename from ibm/data_source_ibm_tg_location_test.go rename to ibm/service/transitgateway/data_source_ibm_tg_location_test.go index e5b8148cc..00707be1d 100644 --- a/ibm/data_source_ibm_tg_location_test.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_location_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +15,8 @@ func TestAccIBMTransitGatewaysLocationDataSource_basic(t *testing.T) { resName := "data.ibm_tg_location.test_tg_location" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMTransitGatewaysLocationDataSourceConfig(), @@ -31,8 +32,8 @@ func TestAccIBMTransitGatewaysLocationDataSource_basic(t *testing.T) { func testAccCheckIBMTransitGatewaysLocationDataSourceConfig() string { // status filter defaults to empty - return fmt.Sprintf(` + return ` data "ibm_tg_location" "test_tg_location" { name = "us-south" - } `) + } ` } diff --git a/ibm/data_source_ibm_tg_locations.go b/ibm/service/transitgateway/data_source_ibm_tg_locations.go similarity index 92% rename from ibm/data_source_ibm_tg_locations.go rename to ibm/service/transitgateway/data_source_ibm_tg_locations.go index de0bdb4e9..37b9bbb83 100644 --- a/ibm/data_source_ibm_tg_locations.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_locations.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "fmt" @@ -18,7 +18,7 @@ const ( tgLocationsType = "type" ) -func dataSourceIBMTransitGatewaysLocations() *schema.Resource { +func DataSourceIBMTransitGatewaysLocations() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMTransitGatewaysLocationsRead, @@ -61,7 +61,7 @@ func dataSourceIBMTransitGatewaysLocationsRead(d *schema.ResourceData, meta inte listTransitGatewayLocationsOptionsModel := &transitgatewayapisv1.ListGatewayLocationsOptions{} listTransitGatewayLocations, response, err := client.ListGatewayLocations(listTransitGatewayLocationsOptionsModel) if err != nil { - return fmt.Errorf("Error while fetching transit gateways locations: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while fetching transit gateways locations: %s\n%s", err, response) } tgLocationsCol := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_tg_locations_test.go b/ibm/service/transitgateway/data_source_ibm_tg_locations_test.go similarity index 82% rename from ibm/data_source_ibm_tg_locations_test.go rename to ibm/service/transitgateway/data_source_ibm_tg_locations_test.go index 12ea6b3aa..43319097b 100644 --- a/ibm/data_source_ibm_tg_locations_test.go +++ b/ibm/service/transitgateway/data_source_ibm_tg_locations_test.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( - "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,8 +15,8 @@ func TestAccIBMTransitGatewaysLocationsDataSource_basic(t *testing.T) { resName := "data.ibm_tg_locations.test_tg_locations" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMTransitGatewaysLocationsDataSourceConfig(), @@ -31,7 +32,7 @@ func TestAccIBMTransitGatewaysLocationsDataSource_basic(t *testing.T) { func testAccCheckIBMTransitGatewaysLocationsDataSourceConfig() string { // status filter defaults to empty - return fmt.Sprintf(` + return ` data "ibm_tg_locations" "test_tg_locations" { - } `) + } ` } diff --git a/ibm/service/transitgateway/data_source_ibm_tg_route_report.go b/ibm/service/transitgateway/data_source_ibm_tg_route_report.go new file mode 100644 index 000000000..ef0e994d9 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_route_report.go @@ -0,0 +1,237 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + tgRouteReport = "route_report" +) + +func DataSourceIBMTransitGatewayRouteReport() *schema.Resource { + + return &schema.Resource{ + Read: dataSourceIBMTransitGatewayRouteReportRead, + Schema: map[string]*schema.Schema{ + tgGatewayId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway identifier", + }, + tgRouteReport: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway Route Report identifier", + }, + tgRouteReportConnections: { + Type: schema.TypeList, + Description: "Collection of transit gateway connections", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgps: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's bgps", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgpAsPath: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpIsUsed: { + Type: schema.TypeBool, + Computed: true, + }, + tgRouteReportConnectionBgpLocalPreference: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + ID: { + Type: schema.TypeString, + Computed: true, + }, + tgConnName: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionType: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's used routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionRoutePrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportOverlappingRoutesDetail: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping route's details", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgConnectionId: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + tgStatus: { + Type: schema.TypeString, + Computed: true, + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceIBMTransitGatewayRouteReportRead(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(tgGatewayId).(string) + routeReportId := d.Get(tgRouteReport).(string) + + getTransitGatewayRouteReportOptionsModel := &transitgatewayapisv1.GetTransitGatewayRouteReportOptions{} + getTransitGatewayRouteReportOptionsModel.SetTransitGatewayID(gatewayId) + getTransitGatewayRouteReportOptionsModel.SetID(routeReportId) + routeReport, response, err := client.GetTransitGatewayRouteReport(getTransitGatewayRouteReportOptionsModel) + if err != nil { + return fmt.Errorf("Error while retrieving transit gateway route report %s\n%s", err, response) + } + + d.Set(tgRouteReport, routeReport.ID) + d.SetId(*routeReport.ID) + d.Set(tgStatus, routeReport.Status) + d.Set(tgCreatedAt, routeReport.CreatedAt.String()) + if routeReport.UpdatedAt != nil { + d.Set(tgUpdatedAt, routeReport.UpdatedAt.String()) + } + + connections := make([]map[string]interface{}, 0) + for _, connection := range routeReport.Connections { + tgConn := map[string]interface{}{} + + // Set connection info + if connection.ID != nil { + tgConn[ID] = *connection.ID + } + if connection.Name != nil { + tgConn[tgConnName] = *connection.Name + } + if connection.Type != nil { + tgConn[tgRouteReportConnectionType] = *connection.Type + } + + // set bgps + bgps := make([]map[string]interface{}, 0) + for _, bgp := range connection.Bgps { + tgConnBgp := map[string]interface{}{} + + if bgp.AsPath != nil { + tgConnBgp[tgRouteReportConnectionBgpAsPath] = *bgp.AsPath + } + if bgp.IsUsed != nil { + tgConnBgp[tgRouteReportConnectionBgpIsUsed] = *bgp.IsUsed + } + if bgp.LocalPreference != nil { + tgConnBgp[tgRouteReportConnectionBgpLocalPreference] = *bgp.LocalPreference + } + if bgp.Prefix != nil { + tgConnBgp[tgRouteReportConnectionBgpPrefix] = *bgp.Prefix + } + + bgps = append(bgps, tgConnBgp) + } + tgConn[tgRouteReportConnectionBgps] = bgps + + // Set connection routes + routes := make([]map[string]interface{}, 0) + for _, route := range connection.Routes { + tgConnRoute := map[string]interface{}{} + + if route.Prefix != nil { + tgConnRoute[tgRouteReportConnectionRoutePrefix] = *route.Prefix + } + + routes = append(routes, tgConnRoute) + } + tgConn[tgRouteReportConnectionRoutes] = routes + + connections = append(connections, tgConn) + } + d.Set(tgRouteReportConnections, connections) + + // Set overlapping route details + overlappingRoutes := make([]map[string]interface{}, 0) + for _, overlap := range routeReport.OverlappingRoutes { + tgRoutes := map[string]interface{}{} + + routes := make([]map[string]interface{}, 0) + for _, routeDetail := range overlap.Routes { + tgRoutesDetail := map[string]interface{}{} + + if routeDetail.ConnectionID != nil { + tgRoutesDetail[tgConnectionId] = *routeDetail.ConnectionID + } + if routeDetail.Prefix != nil { + tgRoutesDetail[tgRouteReportOverlappingPrefix] = *routeDetail.Prefix + } + + routes = append(routes, tgRoutesDetail) + } + tgRoutes[tgRouteReportOverlappingRoutesDetail] = routes + + overlappingRoutes = append(overlappingRoutes, tgRoutes) + } + d.Set(tgRouteReportOverlappingRoutes, overlappingRoutes) + + return nil +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_route_report_test.go b/ibm/service/transitgateway/data_source_ibm_tg_route_report_test.go new file mode 100644 index 000000000..9ef2d8995 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_route_report_test.go @@ -0,0 +1,50 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccIBMTransitGatewayRouteReportDataSource_basic(t *testing.T) { + gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) + location := fmt.Sprintf("us-south") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMTransitGatewayDataRouteReportSourceConfig(gatewayname, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_tg_route_report.test_tg_route_get", "connections.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMTransitGatewayDataRouteReportSourceConfig(gatewayname, location string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_route_report" "test_tg_route" { + gateway = ibm_tg_gateway.test_tg_gateway.id + } + + data "ibm_tg_route_report" "test_tg_route_get" { + gateway = ibm_tg_gateway.test_tg_gateway.id + route_report = ibm_tg_route_report.test_tg_route.route_report_id + } + `, gatewayname, location) +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_route_reports.go b/ibm/service/transitgateway/data_source_ibm_tg_route_reports.go new file mode 100644 index 000000000..f1ce3b2fb --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_route_reports.go @@ -0,0 +1,273 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "time" + + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + tgRouteReports = "route_reports" + tgRouteReportConnections = "connections" + tgRouteReportOverlappingRoutes = "overlapping_routes" + tgRouteReportOverlappingRoutesDetail = "routes" + tgRouteReportConnectionBgps = "bgps" + tgRouteReportConnectionBgpAsPath = "as_path" + tgRouteReportConnectionBgpIsUsed = "is_used" + tgRouteReportConnectionBgpLocalPreference = "local_preference" + tgRouteReportConnectionBgpPrefix = "prefix" + tgRouteReportConnectionRoutes = "routes" + tgRouteReportConnectionRoutePrefix = "prefix" + tgRouteReportConnectionType = "type" + tgRouteReportOverlappingPrefix = "prefix" +) + +func DataSourceIBMTransitGatewayRouteReports() *schema.Resource { + + return &schema.Resource{ + Read: dataSourceIBMTransitGatewayRouteReportsRead, + Schema: map[string]*schema.Schema{ + + tgGatewayId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway identifier", + }, + + tgRouteReports: { + Type: schema.TypeList, + Description: "Collection of transit gateway route reports", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgID: { + Type: schema.TypeString, + Computed: true, + }, + + tgRouteReportConnections: { + Type: schema.TypeList, + Description: "Collection of transit gateway connections", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgps: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's bgps", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgpAsPath: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpIsUsed: { + Type: schema.TypeBool, + Computed: true, + }, + tgRouteReportConnectionBgpLocalPreference: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + ID: { + Type: schema.TypeString, + Computed: true, + }, + tgConnName: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionType: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's used routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionRoutePrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportOverlappingRoutesDetail: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping route's details", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgConnectionId: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + tgStatus: { + Type: schema.TypeString, + Computed: true, + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMTransitGatewayRouteReportsRead(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(tgGatewayId).(string) + + listTransitGatewayRouteReportsOptionsModel := &transitgatewayapisv1.ListTransitGatewayRouteReportsOptions{} + listTransitGatewayRouteReportsOptionsModel.SetTransitGatewayID(gatewayId) + listTransitGatewayRouteReports, response, err := client.ListTransitGatewayRouteReports(listTransitGatewayRouteReportsOptionsModel) + if err != nil { + return fmt.Errorf("Error while listing transit gateway route reports %s\n%s", err, response) + } + + reports := make([]map[string]interface{}, 0) + for _, routeReport := range listTransitGatewayRouteReports.RouteReports { + tgReport := map[string]interface{}{} + tgReport[tgID] = routeReport.ID + tgReport[tgCreatedAt] = routeReport.CreatedAt.String() + tgReport[tgStatus] = routeReport.Status + + if routeReport.UpdatedAt != nil { + tgReport[tgUpdatedAt] = routeReport.UpdatedAt.String() + } + + connections := make([]map[string]interface{}, 0) + for _, connection := range routeReport.Connections { + tgConn := map[string]interface{}{} + + // Set connection info + if connection.ID != nil { + tgConn[ID] = *connection.ID + } + if connection.Name != nil { + tgConn[tgConnName] = *connection.Name + } + if connection.Type != nil { + tgConn[tgRouteReportConnectionType] = *connection.Type + } + + // set bgps + bgps := make([]map[string]interface{}, 0) + for _, bgp := range connection.Bgps { + tgConnBgp := map[string]interface{}{} + + if bgp.AsPath != nil { + tgConnBgp[tgRouteReportConnectionBgpAsPath] = *bgp.AsPath + } + if bgp.IsUsed != nil { + tgConnBgp[tgRouteReportConnectionBgpIsUsed] = *bgp.IsUsed + } + if bgp.LocalPreference != nil { + tgConnBgp[tgRouteReportConnectionBgpLocalPreference] = *bgp.LocalPreference + } + if bgp.Prefix != nil { + tgConnBgp[tgRouteReportConnectionBgpPrefix] = *bgp.Prefix + } + + bgps = append(bgps, tgConnBgp) + } + tgConn[tgRouteReportConnectionBgps] = bgps + + // Set connection routes + routes := make([]map[string]interface{}, 0) + for _, route := range connection.Routes { + tgConnRoute := map[string]interface{}{} + + if route.Prefix != nil { + tgConnRoute[tgRouteReportConnectionRoutePrefix] = *route.Prefix + } + + routes = append(routes, tgConnRoute) + } + tgConn[tgRouteReportConnectionRoutes] = routes + + connections = append(connections, tgConn) + } + tgReport[tgRouteReportConnections] = connections + + // Set overlapping route details + overlappingRoutes := make([]map[string]interface{}, 0) + for _, overlap := range routeReport.OverlappingRoutes { + tgRoutes := map[string]interface{}{} + + routes := make([]map[string]interface{}, 0) + for _, routeDetail := range overlap.Routes { + tgRoutesDetail := map[string]interface{}{} + + if routeDetail.ConnectionID != nil { + tgRoutesDetail[tgConnectionId] = *routeDetail.ConnectionID + } + if routeDetail.Prefix != nil { + tgRoutesDetail[tgRouteReportOverlappingPrefix] = *routeDetail.Prefix + } + + routes = append(routes, tgRoutesDetail) + } + tgRoutes[tgRouteReportOverlappingRoutesDetail] = routes + + overlappingRoutes = append(overlappingRoutes, tgRoutes) + } + tgReport[tgRouteReportOverlappingRoutes] = overlappingRoutes + + reports = append(reports, tgReport) + } + d.Set(tgRouteReports, reports) + d.SetId(dataSourceIBMTransitGatewayRouteReportsID(d)) + return nil +} + +// dataSourceIBMTransitGatewayRouteReportsID returns a reasonable ID for a transit gateways list. +func dataSourceIBMTransitGatewayRouteReportsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/transitgateway/data_source_ibm_tg_route_reports_test.go b/ibm/service/transitgateway/data_source_ibm_tg_route_reports_test.go new file mode 100644 index 000000000..6fc3f82f8 --- /dev/null +++ b/ibm/service/transitgateway/data_source_ibm_tg_route_reports_test.go @@ -0,0 +1,51 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMTransitGatewayRouteReportsDataSource_basic(t *testing.T) { + gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) + location := fmt.Sprintf("us-south") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMTransitGatewayDataRouteReportListSourceConfig(gatewayname, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_tg_route_reports.test_tg_route_list", "route_reports.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMTransitGatewayDataRouteReportListSourceConfig(gatewayname, location string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_route_report" "test_tg_route" { + gateway = ibm_tg_gateway.test_tg_gateway.id + } + + data "ibm_tg_route_reports" "test_tg_route_list" { + gateway = ibm_tg_gateway.test_tg_gateway.id + } + `, gatewayname, location) +} diff --git a/ibm/resource_ibm_tg_gateway.go b/ibm/service/transitgateway/resource_ibm_tg_gateway.go similarity index 83% rename from ibm/resource_ibm_tg_gateway.go rename to ibm/service/transitgateway/resource_ibm_tg_gateway.go index 818122096..e79257daf 100644 --- a/ibm/resource_ibm_tg_gateway.go +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "context" @@ -10,6 +10,9 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/transitgatewayapisv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -35,7 +38,7 @@ const ( isTransitGatewayDeleted = "done" ) -func resourceIBMTransitGateway() *schema.Resource { +func ResourceIBMTransitGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMTransitGatewayCreate, Read: resourceIBMTransitGatewayRead, @@ -52,7 +55,7 @@ func resourceIBMTransitGateway() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -69,7 +72,7 @@ func resourceIBMTransitGateway() *schema.Resource { Required: true, ForceNew: false, Description: "Name Transit Gateway Services", - ValidateFunc: InvokeValidator("ibm_tg_gateway", tgName), + ValidateFunc: validate.InvokeValidator("ibm_tg_gateway", tgName), }, tgGlobal: { @@ -84,8 +87,8 @@ func resourceIBMTransitGateway() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_tg_gateway", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_tg_gateway", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the transit gateway instance", }, @@ -115,31 +118,31 @@ func resourceIBMTransitGateway() *schema.Resource { Description: "The Status of the resource", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -148,36 +151,36 @@ func resourceIBMTransitGateway() *schema.Resource { } } -func resourceIBMTGValidator() *ResourceValidator { +func ResourceIBMTGValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: tgName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, AllowedValues: `^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$}`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmTGResourceValidator := ResourceValidator{ResourceName: "ibm_tg_gateway", Schema: validateSchema} + ibmTGResourceValidator := validate.ResourceValidator{ResourceName: "ibm_tg_gateway", Schema: validateSchema} return &ibmTGResourceValidator } func transitgatewayClient(meta interface{}) (*transitgatewayapisv1.TransitGatewayApisV1, error) { - sess, err := meta.(ClientSession).TransitGatewayV1API() + sess, err := meta.(conns.ClientSession).TransitGatewayV1API() return sess, err } @@ -220,7 +223,7 @@ func resourceIBMTransitGatewayCreate(d *schema.ResourceData, meta interface{}) e v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(tgGatewayTags); ok || v != "" { oldList, newList := d.GetChange(tgGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *tgw.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *tgw.Crn) if err != nil { log.Printf( "Error on create of transit gateway (%s) tags: %s", d.Id(), err) @@ -251,7 +254,7 @@ func isTransitGatewayRefreshFunc(client *transitgatewayapisv1.TransitGatewayApis } transitGateway, response, err := client.GetTransitGateway(gettgwoptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Transit Gateway: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway: %s\n%s", err, response) } if *transitGateway.Status == "available" || *transitGateway.Status == "failed" { @@ -294,26 +297,26 @@ func resourceIBMTransitGatewayRead(d *schema.ResourceData, meta interface{}) err d.Set(tgGlobal, tgw.Global) d.Set(tgStatus, tgw.Status) - tags, err := GetTagsUsingCRN(meta, *tgw.Crn) + tags, err := flex.GetTagsUsingCRN(meta, *tgw.Crn) if err != nil { log.Printf( "Error on get of transit gateway (%s) tags: %s", d.Id(), err) } d.Set(tgGatewayTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/interconnectivity/transit") - d.Set(ResourceName, *tgw.Name) - d.Set(ResourceCRN, *tgw.Crn) - d.Set(ResourceStatus, *tgw.Status) + d.Set(flex.ResourceControllerURL, controller+"/interconnectivity/transit") + d.Set(flex.ResourceName, *tgw.Name) + d.Set(flex.ResourceCRN, *tgw.Crn) + d.Set(flex.ResourceStatus, *tgw.Status) if tgw.ResourceGroup != nil { rg := tgw.ResourceGroup d.Set(tgResourceGroup, *rg.ID) - d.Set(ResourceGroupName, *rg.ID) + d.Set(flex.ResourceGroupName, *rg.ID) } return nil } @@ -332,7 +335,7 @@ func resourceIBMTransitGatewayUpdate(d *schema.ResourceData, meta interface{}) e tgw, resp, err := client.GetTransitGateway(tgOptions) if err != nil { - log.Printf("Error fetching Tranisit Gateway: %s", resp) + log.Printf("Error fetching Transit Gateway: %s", resp) return err } @@ -352,7 +355,7 @@ func resourceIBMTransitGatewayUpdate(d *schema.ResourceData, meta interface{}) e } if d.HasChange(tgGatewayTags) { oldList, newList := d.GetChange(tgGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *tgw.Crn) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *tgw.Crn) if err != nil { log.Printf( "Error on update of transit gateway (%s) tags: %s", ID, err) @@ -385,7 +388,7 @@ func resourceIBMTransitGatewayDelete(d *schema.ResourceData, meta interface{}) e if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error deleting Transit Gateway (%s): %s\n%s", ID, err, response) + return fmt.Errorf("[ERROR] Error deleting Transit Gateway (%s): %s\n%s", ID, err, response) } _, err = isWaitForTransitGatewayDeleted(client, ID, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -412,7 +415,7 @@ func isWaitForTransitGatewayDeleted(client *transitgatewayapisv1.TransitGatewayA func isTransitGatewayDeleteRefreshFunc(client *transitgatewayapisv1.TransitGatewayApisV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] tg gateway delete function here") gettgwoptions := &transitgatewayapisv1.GetTransitGatewayOptions{ ID: &id, } @@ -421,7 +424,7 @@ func isTransitGatewayDeleteRefreshFunc(client *transitgatewayapisv1.TransitGatew if response != nil && response.StatusCode == 404 { return transitGateway, isTransitGatewayDeleted, nil } - return nil, "", fmt.Errorf("Error Getting Transit Gateway: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway: %s\n%s", err, response) } return transitGateway, isTransitGatewayDeleting, err } @@ -446,7 +449,7 @@ func resourceIBMTransitGatewayExists(d *schema.ResourceData, meta interface{}) ( d.SetId("") return false, nil } - return false, fmt.Errorf("Error Getting Transit Gateway: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Transit Gateway: %s\n%s", err, response) } return true, nil diff --git a/ibm/resource_ibm_tg_gateway_connection.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection.go similarity index 87% rename from ibm/resource_ibm_tg_gateway_connection.go rename to ibm/service/transitgateway/resource_ibm_tg_gateway_connection.go index 888b77008..99cb295ff 100644 --- a/ibm/resource_ibm_tg_gateway_connection.go +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/networking-go-sdk/transitgatewayapisv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -39,7 +41,7 @@ const ( tgMtu = "mtu" ) -func resourceIBMTransitGatewayConnection() *schema.Resource { +func ResourceIBMTransitGatewayConnection() *schema.Resource { return &schema.Resource{ Create: resourceIBMTransitGatewayConnectionCreate, Read: resourceIBMTransitGatewayConnectionRead, @@ -70,14 +72,14 @@ func resourceIBMTransitGatewayConnection() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_tg_connection", tgNetworkType), + ValidateFunc: validate.InvokeValidator("ibm_tg_connection", tgNetworkType), Description: "Defines what type of network is connected via this connection. Allowable values (classic,directlink,vpc,gre_tunnel)", }, tgName: { Type: schema.TypeString, Optional: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_tg_connection", tgName), + ValidateFunc: validate.InvokeValidator("ibm_tg_connection", tgName), Description: "The user-defined name for this transit gateway. If unspecified, the name will be the network name (the name of the VPC in the case of network type 'vpc', and the word Classic, in the case of network type 'classic').", }, tgNetworkId: { @@ -163,7 +165,7 @@ func resourceIBMTransitGatewayConnection() *schema.Resource { Computed: true, Description: "Only visible for cross account connections, this field represents the status of the request to connect the given network between accounts.Possible values: [pending,approved,rejected,expired,detached]", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the transit gateway", @@ -171,28 +173,28 @@ func resourceIBMTransitGatewayConnection() *schema.Resource { }, } } -func resourceIBMTransitGatewayConnectionValidator() *ResourceValidator { +func ResourceIBMTransitGatewayConnectionValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) networkType := "classic, directlink, vpc, gre_tunnel" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: tgNetworkType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: networkType}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: tgName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) - ibmTransitGatewayConnectionResourceValidator := ResourceValidator{ResourceName: "ibm_tg_connection", Schema: validateSchema} + ibmTransitGatewayConnectionResourceValidator := validate.ResourceValidator{ResourceName: "ibm_tg_connection", Schema: validateSchema} return &ibmTransitGatewayConnectionResourceValidator } @@ -255,7 +257,7 @@ func resourceIBMTransitGatewayConnectionCreate(d *schema.ResourceData, meta inte tgConnections, response, err := client.CreateTransitGatewayConnection(createTransitGatewayConnectionOptions) if err != nil { - return fmt.Errorf("Create Transit Gateway connection err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Create Transit Gateway connection err %s\n%s", err, response) } d.SetId(fmt.Sprintf("%s/%s", gatewayId, *tgConnections.ID)) @@ -289,9 +291,9 @@ func isWaitForTransitGatewayConnectionAvailable(client *transitgatewayapisv1.Tra func isTransitGatewayConnectionRefreshFunc(client *transitgatewayapisv1.TransitGatewayApisV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { - return nil, "", fmt.Errorf("Error Getting Transit Gateway connection: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway connection: %s", err) // return err } @@ -302,7 +304,7 @@ func isTransitGatewayConnectionRefreshFunc(client *transitgatewayapisv1.TransitG getTransitGatewayConnectionOptions.SetID(ID) tgConnection, response, err := client.GetTransitGatewayConnection(getTransitGatewayConnectionOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) } if *tgConnection.Status == "attached" || *tgConnection.Status == "failed" { return tgConnection, isTransitGatewayConnectionAttached, nil @@ -317,7 +319,7 @@ func resourceIBMTransitGatewayConnectionRead(d *schema.ResourceData, meta interf if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -334,7 +336,7 @@ func resourceIBMTransitGatewayConnectionRead(d *schema.ResourceData, meta interf d.SetId("") return nil } - return fmt.Errorf("Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) + return fmt.Errorf("[ERROR] Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) } if instance.Name != nil { @@ -368,9 +370,9 @@ func resourceIBMTransitGatewayConnectionRead(d *schema.ResourceData, meta interf } tgw, response, err := client.GetTransitGateway(getTransitGatewayOptions) if err != nil { - return fmt.Errorf("Error Getting Transit Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Transit Gateway : %s\n%s", err, response) } - d.Set(RelatedCRN, *tgw.Crn) + d.Set(flex.RelatedCRN, *tgw.Crn) return nil } @@ -381,7 +383,7 @@ func resourceIBMTransitGatewayConnectionUpdate(d *schema.ResourceData, meta inte if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -396,7 +398,7 @@ func resourceIBMTransitGatewayConnectionUpdate(d *schema.ResourceData, meta inte _, response, err := client.GetTransitGatewayConnection(getTransitGatewayConnectionOptions) if err != nil { - return fmt.Errorf("Error Getting Transit Gateway Connection: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Transit Gateway Connection: %s\n%s", err, response) } updateTransitGatewayConnectionOptions := &transitgatewayapisv1.UpdateTransitGatewayConnectionOptions{} @@ -411,7 +413,7 @@ func resourceIBMTransitGatewayConnectionUpdate(d *schema.ResourceData, meta inte _, response, err = client.UpdateTransitGatewayConnection(updateTransitGatewayConnectionOptions) if err != nil { - return fmt.Errorf("Error in Update Transit Gateway Connection : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error in Update Transit Gateway Connection : %s\n%s", err, response) } return resourceIBMTransitGatewayConnectionRead(d, meta) @@ -423,7 +425,7 @@ func resourceIBMTransitGatewayConnectionDelete(d *schema.ResourceData, meta inte if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -440,7 +442,7 @@ func resourceIBMTransitGatewayConnectionDelete(d *schema.ResourceData, meta inte if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error deleting Transit Gateway Connection(%s): %s\n%s", ID, err, response) + return fmt.Errorf("[ERROR] Error deleting Transit Gateway Connection(%s): %s\n%s", ID, err, response) } _, err = isWaitForTransitGatewayConnectionDeleted(client, d.Id(), d.Timeout(schema.TimeoutCreate)) @@ -469,10 +471,10 @@ func isWaitForTransitGatewayConnectionDeleted(client *transitgatewayapisv1.Trans func isTransitGatewayConnectionDeleteRefreshFunc(client *transitgatewayapisv1.TransitGatewayApisV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") - parts, err := idParts(id) + log.Printf("[DEBUG] tg gateway connection delete function here") + parts, err := flex.IdParts(id) if err != nil { - return nil, "", fmt.Errorf("Error Getting Transit Gateway connection: %s", err) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway connection: %s", err) } @@ -489,7 +491,7 @@ func isTransitGatewayConnectionDeleteRefreshFunc(client *transitgatewayapisv1.Tr return tgConnection, isTransitGatewayConnectionDeleted, nil } - return nil, "", fmt.Errorf("Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Transit Gateway Connection (%s): %s\n%s", ID, err, response) } return tgConnection, isTransitGatewayConnectionDeleting, err } @@ -499,12 +501,12 @@ func resourceIBMTransitGatewayConnectionExists(d *schema.ResourceData, meta inte if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) < 2 { - return false, fmt.Errorf("Incorrect ID %s: Id should be a combination of gatewayID/ConnectionID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of gatewayID/ConnectionID", d.Id()) } gatewayId := parts[0] ID := parts[1] @@ -519,7 +521,7 @@ func resourceIBMTransitGatewayConnectionExists(d *schema.ResourceData, meta inte d.SetId("") return false, nil } - return false, fmt.Errorf("Error Getting Transit Gateway Connection: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Transit Gateway Connection: %s\n%s", err, response) } return true, nil diff --git a/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter.go new file mode 100644 index 000000000..fc4c982cb --- /dev/null +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter.go @@ -0,0 +1,278 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMTransitGatewayConnectionPrefixFilter() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMTransitGatewayConnectionPrefixFilterCreate, + Read: resourceIBMTransitGatewayConnectionPrefixFilterRead, + Delete: resourceIBMTransitGatewayConnectionPrefixFilterDelete, + Update: resourceIBMTransitGatewayConnectionPrefixFilterUpdate, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + tgGatewayId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The Transit Gateway identifier", + }, + tgConnectionId: { + Type: schema.TypeString, + Required: true, + Description: "The Transit Gateway Connection identifier", + }, + tgPrefixFilterId: { + Type: schema.TypeString, + Computed: true, + Description: "The Transit Gateway Connection Prefix Filter identifier", + }, + tgAction: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_tg_connection_prefix_filter", tgAction), + Description: "Whether to permit or deny the prefix filter", + }, + tgBefore: { + Type: schema.TypeString, + Optional: true, + Description: "Identifier of prefix filter that handles ordering", + }, + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was created", + }, + tgGe: { + Type: schema.TypeInt, + Optional: true, + Description: "IP Prefix GE", + }, + tgLe: { + Type: schema.TypeInt, + Optional: true, + Description: "IP Prefix LE", + }, + tgPrefix: { + Type: schema.TypeString, + Required: true, + Description: "IP Prefix", + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this prefix filter was last updated", + }, + }, + } +} + +func ResourceIBMTransitGatewayConnectionPrefixFilterValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + actionValues := "permit, deny" + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: tgAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: actionValues}) + + ibmTransitGatewayConnectionPrefixFilterResourceValidator := validate.ResourceValidator{ResourceName: "ibm_tg_connection_prefix_filter", Schema: validateSchema} + + return &ibmTransitGatewayConnectionPrefixFilterResourceValidator +} + +func resourceIBMTransitGatewayConnectionPrefixFilterCreate(d *schema.ResourceData, meta interface{}) error { + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + gatewayId := d.Get(tgGatewayId).(string) + connectionId := d.Get(tgConnectionId).(string) + + createPrefixFilterOptions := &transitgatewayapisv1.CreateTransitGatewayConnectionPrefixFilterOptions{} + createPrefixFilterOptions.SetTransitGatewayID(gatewayId) + createPrefixFilterOptions.SetID(connectionId) + + action := d.Get(tgAction).(string) + createPrefixFilterOptions.SetAction(action) + prefix := d.Get(tgPrefix).(string) + createPrefixFilterOptions.SetPrefix(prefix) + + if _, ok := d.GetOk(tgBefore); ok { + before := d.Get(tgBefore).(string) + createPrefixFilterOptions.SetBefore(before) + } + if _, ok := d.GetOk(tgGe); ok { + ge := int64(d.Get(tgGe).(int)) + createPrefixFilterOptions.SetGe(ge) + } + if _, ok := d.GetOk(tgLe); ok { + le := int64(d.Get(tgLe).(int)) + createPrefixFilterOptions.SetLe(le) + } + + prefixFilter, response, err := client.CreateTransitGatewayConnectionPrefixFilter(createPrefixFilterOptions) + if err != nil { + return fmt.Errorf("[ERROR] Create Transit Gateway connection prefix filter err %s\n%s", err, response) + } + d.SetId(fmt.Sprintf("%s/%s/%s", gatewayId, connectionId, *prefixFilter.ID)) + + return resourceIBMTransitGatewayConnectionPrefixFilterRead(d, meta) +} + +func resourceIBMTransitGatewayConnectionPrefixFilterRead(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + gatewayId := parts[0] + connectionId := parts[1] + filterId := parts[2] + + getTransitGatewayConnectionPrefixFilterOptionsModel := &transitgatewayapisv1.GetTransitGatewayConnectionPrefixFilterOptions{} + getTransitGatewayConnectionPrefixFilterOptionsModel.SetTransitGatewayID(gatewayId) + getTransitGatewayConnectionPrefixFilterOptionsModel.SetID(connectionId) + getTransitGatewayConnectionPrefixFilterOptionsModel.SetFilterID(filterId) + prefixFilter, response, err := client.GetTransitGatewayConnectionPrefixFilter(getTransitGatewayConnectionPrefixFilterOptionsModel) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error while retrieving transit gateway connection prefix filter (%s): %s\n%s", filterId, err, response) + } + + d.Set(tgPrefixFilterId, *prefixFilter.ID) + d.Set(tgCreatedAt, prefixFilter.CreatedAt.String()) + d.Set(tgPrefix, prefixFilter.Prefix) + + if prefixFilter.UpdatedAt != nil { + d.Set(tgUpdatedAt, prefixFilter.UpdatedAt.String()) + } + if prefixFilter.Before != nil { + d.Set(tgBefore, prefixFilter.Before) + } + if prefixFilter.Ge != nil { + d.Set(tgGe, prefixFilter.Ge) + } + if prefixFilter.Le != nil { + d.Set(tgLe, prefixFilter.Le) + } + + return nil +} + +func resourceIBMTransitGatewayConnectionPrefixFilterUpdate(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + gatewayId := parts[0] + connectionId := parts[1] + filterId := parts[2] + + updatePrefixFilterOptions := &transitgatewayapisv1.UpdateTransitGatewayConnectionPrefixFilterOptions{} + updatePrefixFilterOptions.SetTransitGatewayID(gatewayId) + updatePrefixFilterOptions.SetID(connectionId) + updatePrefixFilterOptions.SetFilterID(filterId) + + if d.HasChange(tgAction) { + if d.Get(tgAction) != nil { + action := d.Get(tgAction).(string) + updatePrefixFilterOptions.SetAction(action) + } + } + if d.HasChange(tgBefore) { + if d.Get(tgBefore) != nil { + before := d.Get(tgBefore).(string) + updatePrefixFilterOptions.SetBefore(before) + } + } + if d.HasChange(tgGe) { + if d.Get(tgGe) != nil { + ge := int64(d.Get(tgGe).(int)) + updatePrefixFilterOptions.SetGe(ge) + } + } + if d.HasChange(tgLe) { + if d.Get(tgLe) != nil { + le := int64(d.Get(tgLe).(int)) + updatePrefixFilterOptions.SetLe(le) + } + } + if d.HasChange(tgPrefix) { + if d.Get(tgPrefix) != nil { + prefix := d.Get(tgPrefix).(string) + updatePrefixFilterOptions.SetPrefix(prefix) + } + } + + _, response, err := client.UpdateTransitGatewayConnectionPrefixFilter(updatePrefixFilterOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error in Update Transit Gateway Connection Prefix Filter (%s): %s\n%s", filterId, err, response) + } + + return resourceIBMTransitGatewayConnectionPrefixFilterRead(d, meta) +} + +func resourceIBMTransitGatewayConnectionPrefixFilterDelete(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + gatewayId := parts[0] + connectionId := parts[1] + filterId := parts[2] + + deletePrefixFilterOptions := &transitgatewayapisv1.DeleteTransitGatewayConnectionPrefixFilterOptions{} + deletePrefixFilterOptions.SetTransitGatewayID(gatewayId) + deletePrefixFilterOptions.SetID(connectionId) + deletePrefixFilterOptions.SetFilterID(filterId) + + response, err := client.DeleteTransitGatewayConnectionPrefixFilter(deletePrefixFilterOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error deleting Transit Gateway Connection Prefix Filter(%s): %s\n%s", filterId, err, response) + } + + d.SetId("") + return nil +} diff --git a/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter_test.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter_test.go new file mode 100644 index 000000000..3ea99f887 --- /dev/null +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_prefix_filter_test.go @@ -0,0 +1,140 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMTransitGatewayConnectionPrefixFilter_basic(t *testing.T) { + var tgPrefixFilter string + randNum := acctest.RandIntRange(10, 100) + gatewayName := fmt.Sprintf("gateway-name-%d", randNum) + location := fmt.Sprintf("us-south") + connectionName := fmt.Sprintf("connection-name-%d", randNum) + prefix := "10.0.0.0/16" + updatedPrefix := "10.0.0.0/17" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMTransitGatewayConnectionPrefixFilterDestroy, + Steps: []resource.TestStep{ + // Create test case + { + Config: testAccCheckIBMTransitGatewayConnectionPrefixFiltersConfig(gatewayName, location, connectionName, prefix), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMTransitGatewayConnectionPrefixFilterExists("ibm_tg_connection_prefix_filter.test_tg_prefix_filter", tgPrefixFilter), + resource.TestCheckResourceAttr("ibm_tg_connection_prefix_filter.test_tg_prefix_filter", "prefix", prefix), + ), + }, + // Update test case + { + Config: testAccCheckIBMTransitGatewayConnectionPrefixFiltersConfig(gatewayName, location, connectionName, updatedPrefix), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMTransitGatewayConnectionPrefixFilterExists("ibm_tg_connection_prefix_filter.test_tg_prefix_filter", tgPrefixFilter), + resource.TestCheckResourceAttr("ibm_tg_connection_prefix_filter.test_tg_prefix_filter", "prefix", updatedPrefix), + ), + }, + }, + }, + ) +} + +func testAccCheckIBMTransitGatewayConnectionPrefixFiltersConfig(gatewayName, location, connectionName, prefix string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_connection" "test_tg_connection"{ + gateway = ibm_tg_gateway.test_tg_gateway.id + network_type = "classic" + name = "%s" + } + + resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.test_tg_gateway.id + connection_id = ibm_tg_connection.test_tg_connection.connection_id + action = "permit" + prefix = "%s" + } + `, gatewayName, location, connectionName, prefix) +} + +func testAccCheckIBMTransitGatewayConnectionPrefixFilterExists(n string, vc string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + connectionId := parts[1] + filterId := parts[2] + + detailPrefixFilterOptions := &transitgatewayapisv1.GetTransitGatewayConnectionPrefixFilterOptions{} + detailPrefixFilterOptions.SetTransitGatewayID(gatewayId) + detailPrefixFilterOptions.SetID(connectionId) + detailPrefixFilterOptions.SetFilterID(filterId) + + r, response, err := client.GetTransitGatewayConnectionPrefixFilter(detailPrefixFilterOptions) + if err != nil { + return fmt.Errorf("testAccCheckIBMTransitGatewayConnectionPrefixFilterExists: Error Getting Transit Gateway Connection Prefix Filter: %s\n%s", err, response) + } + + vc = *r.ID + return nil + } +} + +func testAccCheckIBMTransitGatewayConnectionPrefixFilterDestroy(s *terraform.State) error { + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_tg_connection_prefix_filter" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + connectionId := parts[1] + filterId := parts[2] + + detailPrefixFilterOptions := &transitgatewayapisv1.GetTransitGatewayConnectionPrefixFilterOptions{} + detailPrefixFilterOptions.SetTransitGatewayID(gatewayId) + detailPrefixFilterOptions.SetID(connectionId) + detailPrefixFilterOptions.SetFilterID(filterId) + + _, _, err = client.GetTransitGatewayConnectionPrefixFilter(detailPrefixFilterOptions) + if err == nil { + return fmt.Errorf(" transit gateway connection prefix filter still exists: %s", rs.Primary.ID) + } + } + return nil +} diff --git a/ibm/resource_ibm_tg_gateway_connection_test.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_test.go similarity index 90% rename from ibm/resource_ibm_tg_gateway_connection_test.go rename to ibm/service/transitgateway/resource_ibm_tg_gateway_connection_test.go index 9d2b6df9e..f43e07905 100644 --- a/ibm/resource_ibm_tg_gateway_connection_test.go +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_connection_test.go @@ -1,16 +1,21 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( "fmt" + "log" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "log" - "testing" ) func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { @@ -22,12 +27,12 @@ func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { vpcName := fmt.Sprintf("vpc-name-%d", acctest.RandIntRange(10, 100)) dlGatewayName := fmt.Sprintf("dl-gateway-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMTransitGatewayConnectionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { //Create test case Config: testAccCheckIBMTransitGatewayConnectionConfig(tgConnectionName, gatewayName, vpcName), Check: resource.ComposeTestCheckFunc( @@ -36,7 +41,7 @@ func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { ), }, //update - resource.TestStep{ + { Config: testAccCheckIBMTransitGatewayConnectionConfig(updateVcName, gatewayName, vpcName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMTransitGatewayConnectionExists("ibm_tg_connection.test_ibm_tg_connection", tgConnection), @@ -44,7 +49,7 @@ func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { ), }, // tg cross account test - resource.TestStep{ + { //Create test case Config: testAccCheckIBMTransitGatewayCrossAccConnectionConfig(tgConnectionName, gatewayName, vpcName), Check: resource.ComposeTestCheckFunc( @@ -53,7 +58,7 @@ func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { ), }, // tg gre tunnel test - resource.TestStep{ + { //Create test case Config: testAccCheckIBMTransitGatewayGreConnectionConfig(tgConnectionName, gatewayName, tgSecondConnectionName), Check: resource.ComposeTestCheckFunc( @@ -62,7 +67,7 @@ func TestAccIBMTransitGatewayConnection_basic(t *testing.T) { ), }, // tg directlink test - resource.TestStep{ + { //Create test case Config: testAccCheckIBMTransitGatewayDirectlinkConnectionConfig(dlGatewayName, gatewayName, tgConnectionName), Check: resource.ComposeTestCheckFunc( @@ -94,7 +99,7 @@ resource "ibm_tg_connection" "test_ibm_tg_connection"{ network_id = "%s" network_account_id = "%s" } - `, vpcName, gatewayName, vcName, tg_cross_network_id, tg_cross_network_account_id) + `, vpcName, gatewayName, vcName, acc.Tg_cross_network_id, acc.Tg_cross_network_account_id) } @@ -181,9 +186,13 @@ resource "ibm_tg_connection" "test_ibm_tg_dl_connection"{ `, dlGatewayName, gatewayName, dlConnectionName) } +func transitgatewayClient(meta interface{}) (*transitgatewayapisv1.TransitGatewayApisV1, error) { + sess, err := meta.(conns.ClientSession).TransitGatewayV1API() + return sess, err +} func testAccCheckIBMTransitGatewayConnectionDestroy(s *terraform.State) error { - client, err := transitgatewayClient(testAccProvider.Meta()) + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -192,7 +201,7 @@ func testAccCheckIBMTransitGatewayConnectionDestroy(s *terraform.State) error { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -213,7 +222,7 @@ func testAccCheckIBMTransitGatewayConnectionDestroy(s *terraform.State) error { func testAccCheckIBMTransitGatewayConnectionExists(n string, vc string) resource.TestCheckFunc { log.Printf("Inside testAccCheckIBMTransitGatewayConnectionExists : %s", vc) return func(s *terraform.State) error { - client, err := transitgatewayClient(testAccProvider.Meta()) + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -221,7 +230,7 @@ func testAccCheckIBMTransitGatewayConnectionExists(n string, vc string) resource if !ok { return fmt.Errorf("Not found: %s", n) } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -272,18 +281,18 @@ func TestAccIBMTransitGatewayConnectionImport(t *testing.T) { gatewayname := fmt.Sprintf("tg-gateway-name-%d", acctest.RandIntRange(10, 100)) vpcName := fmt.Sprintf("vpc-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMTransitGatewayConnectionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMTransitGatewayConnectionConfig(tgConnectionName, gatewayname, vpcName), Check: resource.ComposeTestCheckFunc( testAccCheckIBMTransitGatewayConnectionExists("ibm_tg_connection.test_ibm_tg_connection", virtualConnection), resource.TestCheckResourceAttr("ibm_tg_connection.test_ibm_tg_connection", "name", tgConnectionName), ), }, - resource.TestStep{ + { ResourceName: "ibm_tg_connection.test_ibm_tg_connection", ImportState: true, ImportStateVerify: true, diff --git a/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report.go new file mode 100644 index 000000000..fba669fce --- /dev/null +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report.go @@ -0,0 +1,366 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway + +import ( + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + tgRouteReportId = "route_report_id" + + isTransitGatewayRouteReportPending = "pending" + isTransitGatewayRouteReportDone = "complete" +) + +func ResourceIBMTransitGatewayRouteReport() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMTransitGatewayRouteReportCreate, + Read: resourceIBMTransitGatewayRouteReportRead, + Delete: resourceIBMTransitGatewayRouteReportDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + tgGatewayId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The Transit Gateway identifier", + }, + tgRouteReportId: { + Type: schema.TypeString, + Computed: true, + Description: "The Transit Gateway Route Report identifier", + }, + tgRouteReportConnections: { + Type: schema.TypeList, + Description: "Collection of transit gateway connections", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgps: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's bgps", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionBgpAsPath: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpIsUsed: { + Type: schema.TypeBool, + Computed: true, + }, + tgRouteReportConnectionBgpLocalPreference: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionBgpPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + ID: { + Type: schema.TypeString, + Computed: true, + }, + tgConnName: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionType: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportConnectionRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway connection's used routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportConnectionRoutePrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + tgCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingRoutes: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgRouteReportOverlappingRoutesDetail: { + Type: schema.TypeList, + Description: "Collection of transit gateway overlapping route's details", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + tgConnectionId: { + Type: schema.TypeString, + Computed: true, + }, + tgRouteReportOverlappingPrefix: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + tgStatus: { + Type: schema.TypeString, + Computed: true, + }, + tgUpdatedAt: { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceIBMTransitGatewayRouteReportCreate(d *schema.ResourceData, meta interface{}) error { + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + + createTransitGatewayRouteReportOptions := &transitgatewayapisv1.CreateTransitGatewayRouteReportOptions{} + + gatewayId := d.Get(tgGatewayId).(string) + createTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + + tgRouteReport, response, err := client.CreateTransitGatewayRouteReport(createTransitGatewayRouteReportOptions) + if err != nil { + return fmt.Errorf("Create Transit Gateway Route Report err %s\n%s", err, response) + } + + d.SetId(fmt.Sprintf("%s/%s", gatewayId, *tgRouteReport.ID)) + d.Set(tgRouteReportId, *tgRouteReport.ID) + + _, err = isWaitForTransitGatewayRouteReportAvailable(client, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + + return resourceIBMTransitGatewayRouteReportRead(d, meta) +} + +func isWaitForTransitGatewayRouteReportAvailable(client *transitgatewayapisv1.TransitGatewayApisV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for transit gateway route report (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isTransitGatewayRouteReportPending}, + Target: []string{isTransitGatewayRouteReportDone, ""}, + Refresh: isTransitGatewayRouteReportRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isTransitGatewayRouteReportRefreshFunc(client *transitgatewayapisv1.TransitGatewayApisV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + parts, err := flex.IdParts(id) + if err != nil { + return nil, "", fmt.Errorf("Error Getting Transit Gateway Route Report: %s", err) + } + + gatewayId := parts[0] + ID := parts[1] + + getTransitGatewayRouteReportOptions := &transitgatewayapisv1.GetTransitGatewayRouteReportOptions{} + getTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + getTransitGatewayRouteReportOptions.SetID(ID) + + routeReport, response, getRouteErr := client.GetTransitGatewayRouteReport(getTransitGatewayRouteReportOptions) + if getRouteErr != nil { + return nil, "", fmt.Errorf("Error Getting Transit Gateway Route Report: %s\n%s", err, response) + } + + if *routeReport.Status == "complete" { + return routeReport, isTransitGatewayRouteReportDone, nil + } + + return routeReport, isTransitGatewayRouteReportPending, nil + } +} + +func resourceIBMTransitGatewayRouteReportRead(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + gatewayId := parts[0] + ID := parts[1] + + getTransitGatewayRouteReportOptions := &transitgatewayapisv1.GetTransitGatewayRouteReportOptions{} + getTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + getTransitGatewayRouteReportOptions.SetID(ID) + instance, response, err := client.GetTransitGatewayRouteReport(getTransitGatewayRouteReportOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error Getting Transit Gateway Route Report (%s): %s\n%s", ID, err, response) + } + + d.Set(tgRouteReportId, *instance.ID) + d.Set(tgGatewayId, gatewayId) + + if instance.Status != nil { + d.Set(tgStatus, *instance.Status) + } + if instance.CreatedAt != nil { + d.Set(tgCreatedAt, instance.CreatedAt.String()) + } + if instance.UpdatedAt != nil { + d.Set(tgUpdatedAt, instance.UpdatedAt.String()) + } + + connections := make([]map[string]interface{}, 0) + for _, connection := range instance.Connections { + tgConn := map[string]interface{}{} + + // Set connection info + if connection.ID != nil { + tgConn[ID] = *connection.ID + } + if connection.Name != nil { + tgConn[tgConnName] = *connection.Name + } + if connection.Type != nil { + tgConn[tgRouteReportConnectionType] = *connection.Type + } + + // set bgps + bgps := make([]map[string]interface{}, 0) + for _, bgp := range connection.Bgps { + tgConnBgp := map[string]interface{}{} + + if bgp.AsPath != nil { + tgConnBgp[tgRouteReportConnectionBgpAsPath] = *bgp.AsPath + } + if bgp.IsUsed != nil { + tgConnBgp[tgRouteReportConnectionBgpIsUsed] = *bgp.IsUsed + } + if bgp.LocalPreference != nil { + tgConnBgp[tgRouteReportConnectionBgpLocalPreference] = *bgp.LocalPreference + } + if bgp.Prefix != nil { + tgConnBgp[tgRouteReportConnectionBgpPrefix] = *bgp.Prefix + } + + bgps = append(bgps, tgConnBgp) + } + tgConn[tgRouteReportConnectionBgps] = bgps + + // Set connection routes + routes := make([]map[string]interface{}, 0) + for _, route := range connection.Routes { + tgConnRoute := map[string]interface{}{} + + if route.Prefix != nil { + tgConnRoute[tgRouteReportConnectionRoutePrefix] = *route.Prefix + } + + routes = append(routes, tgConnRoute) + } + tgConn[tgRouteReportConnectionRoutes] = routes + + connections = append(connections, tgConn) + } + d.Set(tgRouteReportConnections, connections) + + // Set overlapping route details + overlappingRoutes := make([]map[string]interface{}, 0) + for _, overlap := range instance.OverlappingRoutes { + tgRoutes := map[string]interface{}{} + + routes := make([]map[string]interface{}, 0) + for _, routeDetail := range overlap.Routes { + tgRoutesDetail := map[string]interface{}{} + + if routeDetail.ConnectionID != nil { + tgRoutesDetail[tgConnectionId] = *routeDetail.ConnectionID + } + if routeDetail.Prefix != nil { + tgRoutesDetail[tgRouteReportOverlappingPrefix] = *routeDetail.Prefix + } + + routes = append(routes, tgRoutesDetail) + } + tgRoutes[tgRouteReportOverlappingRoutesDetail] = routes + + overlappingRoutes = append(overlappingRoutes, tgRoutes) + } + d.Set(tgRouteReportOverlappingRoutes, overlappingRoutes) + + return nil +} + +func resourceIBMTransitGatewayRouteReportDelete(d *schema.ResourceData, meta interface{}) error { + + client, err := transitgatewayClient(meta) + if err != nil { + return err + } + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + + gatewayId := parts[0] + ID := parts[1] + deleteTransitGatewayRouteReportOptions := &transitgatewayapisv1.DeleteTransitGatewayRouteReportOptions{ + ID: &ID, + } + deleteTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + response, err := client.DeleteTransitGatewayRouteReport(deleteTransitGatewayRouteReportOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("Error deleting Transit Gateway Route Report(%s): %s\n%s", ID, err, response) + } + + d.SetId("") + return nil +} diff --git a/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report_test.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report_test.go new file mode 100644 index 000000000..8f355f9b8 --- /dev/null +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_route_report_test.go @@ -0,0 +1,113 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package transitgateway_test + +import ( + "fmt" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "log" + "testing" +) + +func TestAccIBMTransitGatewayRouteReport_basic(t *testing.T) { + var tgRouteReport string + gatewayName := fmt.Sprintf("tg-gateway-name-%d", acctest.RandIntRange(10, 100)) + location := fmt.Sprintf("us-south") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMTransitGatewayRouteReportDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMTransitGatewayRouteReportConfig(gatewayName, location), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMTransitGatewayRouteReportExists("ibm_tg_route_report.test_tg_route", tgRouteReport), + resource.TestCheckResourceAttrSet("ibm_tg_route_report.test_tg_route", "route_report_id"), + ), + }, + }, + }, + ) +} + +func testAccCheckIBMTransitGatewayRouteReportConfig(gatewayname, location string) string { + return fmt.Sprintf(` + + resource "ibm_tg_gateway" "test_tg_gateway" { + name="%s" + location="%s" + global=true + } + + resource "ibm_tg_route_report" "test_tg_route" { + gateway = ibm_tg_gateway.test_tg_gateway.id + } + `, gatewayname, location) +} + +func testAccCheckIBMTransitGatewayRouteReportDestroy(s *terraform.State) error { + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_tg_route_report" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + ID := parts[1] + + detailTransitGatewayRouteReportOptions := &transitgatewayapisv1.GetTransitGatewayRouteReportOptions{} + detailTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + detailTransitGatewayRouteReportOptions.SetID(ID) + _, _, err = client.GetTransitGatewayRouteReport(detailTransitGatewayRouteReportOptions) + if err == nil { + return fmt.Errorf(" transit gateway route report still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMTransitGatewayRouteReportExists(n string, vc string) resource.TestCheckFunc { + log.Printf("Inside testAccCheckIBMTransitGatewayRouteReportExists : %s", vc) + return func(s *terraform.State) error { + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + gatewayId := parts[0] + ID := parts[1] + + detailTransitGatewayRouteReportOptions := &transitgatewayapisv1.GetTransitGatewayRouteReportOptions{ + ID: &ID, + } + detailTransitGatewayRouteReportOptions.SetTransitGatewayID(gatewayId) + r, response, err := client.GetTransitGatewayRouteReport(detailTransitGatewayRouteReportOptions) + if err != nil { + return fmt.Errorf("testAccCheckIBMTransitGatewayRouteReportExists: Error Getting Transit Gateway Route Report: %s\n%s", err, response) + } + + vc = *r.ID + return nil + } +} diff --git a/ibm/resource_ibm_tg_gateway_test.go b/ibm/service/transitgateway/resource_ibm_tg_gateway_test.go similarity index 87% rename from ibm/resource_ibm_tg_gateway_test.go rename to ibm/service/transitgateway/resource_ibm_tg_gateway_test.go index fc048fad2..247b553c0 100644 --- a/ibm/resource_ibm_tg_gateway_test.go +++ b/ibm/service/transitgateway/resource_ibm_tg_gateway_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package transitgateway_test import ( "errors" @@ -9,6 +9,8 @@ import ( "log" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM/networking-go-sdk/transitgatewayapisv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,10 +21,10 @@ func TestAccIBMTransitGateway_basic(t *testing.T) { var instance string gatewayname := fmt.Sprintf("tg-gateway-name-%d", acctest.RandIntRange(10, 100)) newgatewayname := fmt.Sprintf("newgateway-name-%d", acctest.RandIntRange(10, 100)) - location := fmt.Sprintf("us-south") + location := "us-south" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMTransitGatewayDestroy, // Delete test case Steps: []resource.TestStep{ { @@ -66,7 +68,7 @@ func testAccCheckIBMTransitGatewayExists(n string, instance string) resource.Tes if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - client, err := transitgatewayClient(testAccProvider.Meta()) + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -75,7 +77,7 @@ func testAccCheckIBMTransitGatewayExists(n string, instance string) resource.Tes } instance1, response, err := client.GetTransitGateway(tgOptions) if err != nil { - return fmt.Errorf("Error Getting Transit Gateway: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Transit Gateway: %s\n%s", err, response) } instance = *instance1.ID return nil @@ -83,7 +85,7 @@ func testAccCheckIBMTransitGatewayExists(n string, instance string) resource.Tes } func testAccCheckIBMTransitGatewayDestroy(s *terraform.State) error { - client, err := transitgatewayClient(testAccProvider.Meta()) + client, err := transitgatewayClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -107,13 +109,13 @@ func testAccCheckIBMTransitGatewayDestroy(s *terraform.State) error { func TestAccIBMTransitGatewayImport(t *testing.T) { var instance string gatewayname := fmt.Sprintf("gateway-name-%d", acctest.RandIntRange(10, 100)) - location := fmt.Sprintf("us-south") + location := "us-south" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMTransitGatewayDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMTransitGatewayConfig(gatewayname, location), Check: resource.ComposeTestCheckFunc( testAccCheckIBMTransitGatewayExists("ibm_tg_gateway.test_tg_gateway", instance), @@ -121,7 +123,7 @@ func TestAccIBMTransitGatewayImport(t *testing.T) { resource.TestCheckResourceAttr("ibm_tg_gateway.test_tg_gateway", "location", location), ), }, - resource.TestStep{ + { ResourceName: "ibm_tg_gateway.test_tg_gateway", ImportState: true, ImportStateVerify: true, diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policies.go b/ibm/service/vpc/data_source_ibm_is_backup_policies.go new file mode 100644 index 000000000..1ca4bde5b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policies.go @@ -0,0 +1,354 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBackupPolicies() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBackupPoliciesRead, + + Schema: map[string]*schema.Schema{ + "resource_group": { + Type: schema.TypeString, + Description: "Filters the collection to resources in the resource group with the specified identifier", + Optional: true, + }, + "name": { + Type: schema.TypeString, + Description: "Filters the collection to resources with the exact specified name", + Optional: true, + }, + "tag": { + Type: schema.TypeString, + Description: "Filters the collection to resources with the exact tag value", + Optional: true, + }, + + "backup_policies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of backup policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this backup policy.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the backup policy.", + }, + "last_job_completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the most recent job for this backup policy completed.", + }, + "match_resource_types": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "match_user_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy.", + }, + "plans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The plans for the backup policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this backup policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsBackupPoliciesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + start := "" + matchBackupPolicies := []vpcv1.BackupPolicy{} + + var resourceGroup string + if v, ok := d.GetOk("resource_group"); ok { + resourceGroup = v.(string) + } + + var name string + if v, ok := d.GetOk("name"); ok { + name = v.(string) + } + + var tag string + if v, ok := d.GetOk("tag"); ok { + tag = v.(string) + } + + for { + listBackupPoliciesOptions := &vpcv1.ListBackupPoliciesOptions{} + if start != "" { + listBackupPoliciesOptions.Start = &start + } + if resourceGroup != "" { + listBackupPoliciesOptions.SetResourceGroupID(resourceGroup) + } + if name != "" { + listBackupPoliciesOptions.SetName(name) + } + if tag != "" { + listBackupPoliciesOptions.SetTag(tag) + } + backupPolicyCollection, response, err := sess.ListBackupPoliciesWithContext(context, listBackupPoliciesOptions) + if err != nil { + log.Printf("[DEBUG] ListBackupPoliciesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListBackupPoliciesWithContext failed %s\n%s", err, response)) + } + if backupPolicyCollection != nil && *backupPolicyCollection.TotalCount == int64(0) { + break + } + start = flex.GetNext(backupPolicyCollection.Next) + matchBackupPolicies = append(matchBackupPolicies, backupPolicyCollection.BackupPolicies...) + if start == "" { + break + } + + } + + d.SetId(dataSourceIBMIsBackupPoliciesID(d)) + + if matchBackupPolicies != nil { + err = d.Set("backup_policies", dataSourceBackupPolicyCollectionFlattenBackupPolicies(matchBackupPolicies)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting backup_policies %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsBackupPoliciesID returns a reasonable ID for the list. +func dataSourceIBMIsBackupPoliciesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceBackupPolicyCollectionFlattenBackupPolicies(result []vpcv1.BackupPolicy) (backupPolicies []map[string]interface{}) { + for _, backupPoliciesItem := range result { + backupPolicies = append(backupPolicies, dataSourceBackupPolicyCollectionBackupPoliciesToMap(backupPoliciesItem)) + } + + return backupPolicies +} + +func dataSourceBackupPolicyCollectionBackupPoliciesToMap(backupPoliciesItem vpcv1.BackupPolicy) (backupPoliciesMap map[string]interface{}) { + backupPoliciesMap = map[string]interface{}{} + + if backupPoliciesItem.CreatedAt != nil { + backupPoliciesMap["created_at"] = backupPoliciesItem.CreatedAt.String() + } + if backupPoliciesItem.CRN != nil { + backupPoliciesMap["crn"] = backupPoliciesItem.CRN + } + if backupPoliciesItem.Href != nil { + backupPoliciesMap["href"] = backupPoliciesItem.Href + } + if backupPoliciesItem.ID != nil { + backupPoliciesMap["id"] = backupPoliciesItem.ID + } + if backupPoliciesItem.LifecycleState != nil { + backupPoliciesMap["lifecycle_state"] = backupPoliciesItem.LifecycleState + } + if backupPoliciesItem.LastJobCompletedAt != nil { + backupPoliciesMap["last_job_completed_at"] = flex.DateTimeToString(backupPoliciesItem.LastJobCompletedAt) + } + if backupPoliciesItem.MatchResourceTypes != nil { + backupPoliciesMap["match_resource_types"] = backupPoliciesItem.MatchResourceTypes + } + if backupPoliciesItem.MatchUserTags != nil { + backupPoliciesMap["match_user_tags"] = backupPoliciesItem.MatchUserTags + } + if backupPoliciesItem.Name != nil { + backupPoliciesMap["name"] = backupPoliciesItem.Name + } + if backupPoliciesItem.Plans != nil { + plansList := []map[string]interface{}{} + for _, plansItem := range backupPoliciesItem.Plans { + plansList = append(plansList, dataSourceBackupPolicyCollectionBackupPoliciesPlansToMap(plansItem)) + } + backupPoliciesMap["plans"] = plansList + } + if backupPoliciesItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceBackupPolicyCollectionBackupPoliciesResourceGroupToMap(*backupPoliciesItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + backupPoliciesMap["resource_group"] = resourceGroupList + } + if backupPoliciesItem.ResourceType != nil { + backupPoliciesMap["resource_type"] = backupPoliciesItem.ResourceType + } + + return backupPoliciesMap +} + +func dataSourceBackupPolicyCollectionBackupPoliciesPlansToMap(plansItem vpcv1.BackupPolicyPlanReference) (plansMap map[string]interface{}) { + plansMap = map[string]interface{}{} + + if plansItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceBackupPolicyCollectionPlansDeletedToMap(*plansItem.Deleted) + deletedList = append(deletedList, deletedMap) + plansMap["deleted"] = deletedList + } + if plansItem.Href != nil { + plansMap["href"] = plansItem.Href + } + if plansItem.ID != nil { + plansMap["id"] = plansItem.ID + } + if plansItem.Name != nil { + plansMap["name"] = plansItem.Name + } + if plansItem.ResourceType != nil { + plansMap["resource_type"] = plansItem.ResourceType + } + + return plansMap +} + +func dataSourceBackupPolicyCollectionPlansDeletedToMap(deletedItem vpcv1.BackupPolicyPlanReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceBackupPolicyCollectionBackupPoliciesResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policies_test.go b/ibm/service/vpc/data_source_ibm_is_backup_policies_test.go new file mode 100644 index 000000000..ed135ca3b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policies_test.go @@ -0,0 +1,63 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsBackupPoliciesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplanname%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPoliciesDataSourceConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.match_resource_types.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.plans.0.deleted.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.plans.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.plans.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.plans.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policies.is_backup_policies", "backup_policies.0.plans.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBackupPoliciesDataSourceConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyPlanConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName) + fmt.Sprintf(` + data "ibm_is_backup_policies" "is_backup_policies" { + depends_on = [ibm_is_backup_policy_plan.is_backup_policy_plan] + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy.go b/ibm/service/vpc/data_source_ibm_is_backup_policy.go new file mode 100644 index 000000000..1aa3b6ca8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy.go @@ -0,0 +1,334 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBackupPolicy() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBackupPolicyRead, + + Schema: map[string]*schema.Schema{ + + "identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The backup policy identifier.", + }, + + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique user-defined name for this backup policy.", + }, + + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this backup policy.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy.", + }, + "last_job_completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the most recent job for this backup policy completed.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the backup policy.", + }, + "match_resource_types": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "match_user_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "plans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The plans for the backup policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this backup policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + } +} + +func dataSourceIBMIsBackupPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + var backupPolicy *vpcv1.BackupPolicy + + if v, ok := d.GetOk("identifier"); ok { + + id := v.(string) + getBackupPolicyOptions := &vpcv1.GetBackupPolicyOptions{} + getBackupPolicyOptions.SetID(id) + backupPolicyInfo, response, err := sess.GetBackupPolicyWithContext(context, getBackupPolicyOptions) + if err != nil { + log.Printf("[DEBUG] GetBackupPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyWithContext failed %s\n%s", err, response)) + } + backupPolicy = backupPolicyInfo + + } else if v, ok := d.GetOk("name"); ok { + + name := v.(string) + start := "" + allrecs := []vpcv1.BackupPolicy{} + for { + listBackupPoliciesOptions := &vpcv1.ListBackupPoliciesOptions{} + if start != "" { + listBackupPoliciesOptions.Start = &start + } + backupPolicyCollection, response, err := sess.ListBackupPoliciesWithContext(context, listBackupPoliciesOptions) + if err != nil { + log.Printf("[DEBUG] ListBackupPoliciesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListBackupPoliciesWithContext failed %s\n%s", err, response)) + } + if backupPolicyCollection != nil && *backupPolicyCollection.TotalCount == int64(0) { + break + } + start = flex.GetNext(backupPolicyCollection.Next) + allrecs = append(allrecs, backupPolicyCollection.BackupPolicies...) + if start == "" { + break + } + } + for _, backupPolicyInfo := range allrecs { + if *backupPolicyInfo.Name == name { + backupPolicy = &backupPolicyInfo + break + } + } + if backupPolicy == nil { + return diag.FromErr(fmt.Errorf("[ERROR] No backup policy found with name (%s)", name)) + } + } + + d.SetId(*backupPolicy.ID) + + if err = d.Set("created_at", backupPolicy.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", backupPolicy.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("href", backupPolicy.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if backupPolicy.LastJobCompletedAt != nil { + if err = d.Set("last_job_completed_at", backupPolicy.LastJobCompletedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_job_completed_at: %s", err)) + } + } + if err = d.Set("lifecycle_state", backupPolicy.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", backupPolicy.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if backupPolicy.Plans != nil { + err = d.Set("plans", dataSourceBackupPolicyFlattenPlans(backupPolicy.Plans)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting plans %s", err)) + } + } + + matchResourceType := make([]string, 0) + if backupPolicy.MatchResourceTypes != nil { + for _, matchResourceTyp := range backupPolicy.MatchResourceTypes { + matchResourceType = append(matchResourceType, matchResourceTyp) + } + } + d.Set("match_resource_types", matchResourceType) + + matchUserTags := make([]string, 0) + if backupPolicy.MatchUserTags != nil { + for _, matchUserTag := range backupPolicy.MatchUserTags { + matchUserTags = append(matchUserTags, matchUserTag) + } + } + d.Set("match_user_tags", matchUserTags) + + if backupPolicy.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceBackupPolicyFlattenResourceGroup(*backupPolicy.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) + } + } + if err = d.Set("resource_type", backupPolicy.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + return nil +} + +func dataSourceBackupPolicyFlattenPlans(result []vpcv1.BackupPolicyPlanReference) (plans []map[string]interface{}) { + for _, plansItem := range result { + plans = append(plans, dataSourceBackupPolicyPlansToMap(plansItem)) + } + + return plans +} + +func dataSourceBackupPolicyPlansToMap(plansItem vpcv1.BackupPolicyPlanReference) (plansMap map[string]interface{}) { + plansMap = map[string]interface{}{} + + if plansItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceBackupPolicyPlansDeletedToMap(*plansItem.Deleted) + deletedList = append(deletedList, deletedMap) + plansMap["deleted"] = deletedList + } + if plansItem.Href != nil { + plansMap["href"] = plansItem.Href + } + if plansItem.ID != nil { + plansMap["id"] = plansItem.ID + } + if plansItem.Name != nil { + plansMap["name"] = plansItem.Name + } + if plansItem.ResourceType != nil { + plansMap["resource_type"] = plansItem.ResourceType + } + + return plansMap +} + +func dataSourceBackupPolicyPlansDeletedToMap(deletedItem vpcv1.BackupPolicyPlanReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceBackupPolicyFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceBackupPolicyResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceBackupPolicyResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_plan.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_plan.go new file mode 100644 index 000000000..11f1d8639 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_plan.go @@ -0,0 +1,208 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBackupPolicyPlan() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBackupPolicyPlanRead, + + Schema: map[string]*schema.Schema{ + "backup_policy_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The backup policy identifier.", + }, + "identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The backup policy plan identifier.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique user-defined name for this backup policy plan.", + }, + "active": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the plan is active.", + }, + "attach_user_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "User tags to attach to each resource created by this plan.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "copy_user_tags": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether to copy the source's user tags to the created resource.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy plan was created.", + }, + "cron_spec": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The cron specification for the backup schedule.", + }, + "deletion_trigger": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delete_after": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The maximum number of days to keep each backup after creation.", + }, + "delete_over_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum number of recent backups to keep. If absent, there is no maximum.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + } +} + +func dataSourceIBMIsBackupPolicyPlanRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + var backupPolicyPlan *vpcv1.BackupPolicyPlan + + if v, ok := d.GetOk("identifier"); ok { + id := v.(string) + getBackupPolicyPlanOptions := &vpcv1.GetBackupPolicyPlanOptions{} + + getBackupPolicyPlanOptions.SetBackupPolicyID(d.Get("backup_policy_id").(string)) + getBackupPolicyPlanOptions.SetID(id) + + backupPolicyPlanInfo, response, err := sess.GetBackupPolicyPlanWithContext(context, getBackupPolicyPlanOptions) + if err != nil { + log.Printf("[DEBUG] GetBackupPolicyPlanWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyPlanWithContext failed %s\n%s", err, response)) + } + backupPolicyPlan = backupPolicyPlanInfo + } else if v, ok := d.GetOk("name"); ok { + + name := v.(string) + listBackupPolicyPlansOptions := &vpcv1.ListBackupPolicyPlansOptions{} + + listBackupPolicyPlansOptions.SetBackupPolicyID(d.Get("backup_policy_id").(string)) + + backupPolicyPlanCollection, response, err := sess.ListBackupPolicyPlansWithContext(context, listBackupPolicyPlansOptions) + if err != nil { + log.Printf("[DEBUG] ListBackupPolicyPlansWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListBackupPolicyPlansWithContext failed %s\n%s", err, response)) + } + for _, backupPolicyPlanInfo := range backupPolicyPlanCollection.Plans { + if *backupPolicyPlanInfo.Name == name { + backupPolicyPlan = &backupPolicyPlanInfo + break + } + } + if backupPolicyPlan == nil { + return diag.FromErr(fmt.Errorf("[ERROR] No backup policy plan found with name (%s)", name)) + } + } + + d.SetId(*backupPolicyPlan.ID) + + if err = d.Set("active", backupPolicyPlan.Active); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting active: %s", err)) + } + if err = d.Set("attach_user_tags", backupPolicyPlan.AttachUserTags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attach_user_tags: %s", err)) + } + if err = d.Set("copy_user_tags", backupPolicyPlan.CopyUserTags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting copy_user_tags: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(backupPolicyPlan.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("cron_spec", backupPolicyPlan.CronSpec); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cron_spec: %s", err)) + } + + if backupPolicyPlan.DeletionTrigger != nil { + err = d.Set("deletion_trigger", dataSourceBackupPolicyPlanFlattenDeletionTrigger(*backupPolicyPlan.DeletionTrigger)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting deletion_trigger %s", err)) + } + } + if err = d.Set("href", backupPolicyPlan.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", backupPolicyPlan.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", backupPolicyPlan.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("resource_type", backupPolicyPlan.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + return nil +} + +func dataSourceBackupPolicyPlanFlattenDeletionTrigger(result vpcv1.BackupPolicyPlanDeletionTrigger) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceBackupPolicyPlanDeletionTriggerToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceBackupPolicyPlanDeletionTriggerToMap(deletionTriggerItem vpcv1.BackupPolicyPlanDeletionTrigger) (deletionTriggerMap map[string]interface{}) { + deletionTriggerMap = map[string]interface{}{} + + if deletionTriggerItem.DeleteAfter != nil { + deletionTriggerMap["delete_after"] = deletionTriggerItem.DeleteAfter + } + if deletionTriggerItem.DeleteOverCount != nil { + deletionTriggerMap["delete_over_count"] = deletionTriggerItem.DeleteOverCount + } + + return deletionTriggerMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_plan_test.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_plan_test.go new file mode 100644 index 000000000..6bad94640 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_plan_test.go @@ -0,0 +1,60 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsBackupPolicyPlanDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplanname%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyPlanDataSourceConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "backup_policy_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "active"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "attach_user_tags.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "copy_user_tags"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "cron_spec"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "deletion_trigger.0.delete_after"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plan.is_backup_policy_plan", "resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBackupPolicyPlanDataSourceConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyPlanConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName) + fmt.Sprintf(` + data "ibm_is_backup_policy_plan" "is_backup_policy_plan" { + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + identifier = ibm_is_backup_policy_plan.is_backup_policy_plan[0].backup_policy_plan_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_plans.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_plans.go new file mode 100644 index 000000000..fb7f2cdac --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_plans.go @@ -0,0 +1,247 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBackupPolicyPlans() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBackupPolicyPlansRead, + + Schema: map[string]*schema.Schema{ + "backup_policy_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The backup policy identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "plans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of backup policy plans.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "active": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the plan is active.", + }, + "attach_user_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The user tags to attach to backups (snapshots) created by this plan.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "copy_user_tags": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether to copy the source's user tags to the created backups (snapshots).", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy plan was created.", + }, + "cron_spec": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The cron specification for the backup schedule.", + }, + "deletion_trigger": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delete_after": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The maximum number of days to keep each backup after creation.", + }, + "delete_over_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The maximum number of recent backups to keep. If absent, there is no maximum.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsBackupPolicyPlansRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listBackupPolicyPlansOptions := &vpcv1.ListBackupPolicyPlansOptions{} + + listBackupPolicyPlansOptions.SetBackupPolicyID(d.Get("backup_policy_id").(string)) + + backupPolicyPlanCollection, response, err := vpcClient.ListBackupPolicyPlansWithContext(context, listBackupPolicyPlansOptions) + if err != nil { + log.Printf("[DEBUG] ListBackupPolicyPlansWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListBackupPolicyPlansWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchPlans []vpcv1.BackupPolicyPlan + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range backupPolicyPlanCollection.Plans { + if *data.Name == name { + matchPlans = append(matchPlans, data) + } + } + backupPolicyPlanCollection.Plans = matchPlans + } + if suppliedFilter { + if len(backupPolicyPlanCollection.Plans) == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] no plans found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(dataSourceIBMIsBackupPolicyPlansID(d)) + } + + if backupPolicyPlanCollection.Plans != nil { + err = d.Set("plans", dataSourceBackupPolicyPlanCollectionFlattenPlans(backupPolicyPlanCollection.Plans)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting plans %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsBackupPolicyPlansID returns a reasonable ID for the list. +func dataSourceIBMIsBackupPolicyPlansID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceBackupPolicyPlanCollectionFlattenPlans(result []vpcv1.BackupPolicyPlan) (plans []map[string]interface{}) { + for _, plansItem := range result { + plans = append(plans, dataSourceBackupPolicyPlanCollectionPlansToMap(plansItem)) + } + + return plans +} + +func dataSourceBackupPolicyPlanCollectionPlansToMap(plansItem vpcv1.BackupPolicyPlan) (plansMap map[string]interface{}) { + plansMap = map[string]interface{}{} + + if plansItem.Active != nil { + plansMap["active"] = plansItem.Active + } + if plansItem.AttachUserTags != nil { + plansMap["attach_user_tags"] = plansItem.AttachUserTags + } + if plansItem.CopyUserTags != nil { + plansMap["copy_user_tags"] = plansItem.CopyUserTags + } + if plansItem.CreatedAt != nil { + plansMap["created_at"] = plansItem.CreatedAt.String() + } + if plansItem.CronSpec != nil { + plansMap["cron_spec"] = plansItem.CronSpec + } + if plansItem.DeletionTrigger != nil { + deletionTriggerList := []map[string]interface{}{} + deletionTriggerMap := dataSourceBackupPolicyPlanCollectionPlansDeletionTriggerToMap(*plansItem.DeletionTrigger) + deletionTriggerList = append(deletionTriggerList, deletionTriggerMap) + plansMap["deletion_trigger"] = deletionTriggerList + } + if plansItem.Href != nil { + plansMap["href"] = plansItem.Href + } + if plansItem.ID != nil { + plansMap["id"] = plansItem.ID + } + if plansItem.LifecycleState != nil { + plansMap["lifecycle_state"] = plansItem.LifecycleState + } + if plansItem.Name != nil { + plansMap["name"] = plansItem.Name + } + if plansItem.ResourceType != nil { + plansMap["resource_type"] = plansItem.ResourceType + } + + return plansMap +} + +func dataSourceBackupPolicyPlanCollectionClonePolicyZonesToMap(zonesItem vpcv1.ZoneReference) (zonesMap map[string]interface{}) { + zonesMap = map[string]interface{}{} + + if zonesItem.Href != nil { + zonesMap["href"] = zonesItem.Href + } + if zonesItem.Name != nil { + zonesMap["name"] = zonesItem.Name + } + + return zonesMap +} + +func dataSourceBackupPolicyPlanCollectionPlansDeletionTriggerToMap(deletionTriggerItem vpcv1.BackupPolicyPlanDeletionTrigger) (deletionTriggerMap map[string]interface{}) { + deletionTriggerMap = map[string]interface{}{} + + if deletionTriggerItem.DeleteAfter != nil { + deletionTriggerMap["delete_after"] = deletionTriggerItem.DeleteAfter + } + if deletionTriggerItem.DeleteOverCount != nil { + deletionTriggerMap["delete_over_count"] = deletionTriggerItem.DeleteOverCount + } + + return deletionTriggerMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_plans_test.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_plans_test.go new file mode 100644 index 000000000..3d52c7be7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_plans_test.go @@ -0,0 +1,63 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsBackupPolicyPlansDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplanname%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyPlansDataSourceConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "backup_policy_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.active"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.attach_user_tags.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.copy_user_tags"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.cron_spec"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.deletion_trigger.0.delete_after"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy_plans.is_backup_policy_plans", "plans.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBackupPolicyPlansDataSourceConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyPlanConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName) + fmt.Sprintf(` + data "ibm_is_backup_policy_plans" "is_backup_policy_plans" { + depends_on = [ibm_is_backup_policy_plan.is_backup_policy_plan] + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + name = "%s" + } + `, bakupPolicyPlanName+"-1") +} diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_test.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_test.go new file mode 100644 index 000000000..56b7cee36 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsBackupPolicyDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplanname%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyDataSourceConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "match_resource_types.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "match_user_tags.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "plans.#"), + // resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "plans.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "plans.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "plans.0.name"), + // resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "plans.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "resource_group.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "resource_group.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_backup_policy.is_backup_policy", "resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBackupPolicyDataSourceConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyPlanConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName) + fmt.Sprintf(` + data "ibm_is_backup_policy" "is_backup_policy" { + depends_on = [ibm_is_backup_policy_plan.is_backup_policy_plan] + identifier = ibm_is_backup_policy.is_backup_policy.id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go new file mode 100644 index 000000000..75ee97c93 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go @@ -0,0 +1,689 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIsBareMetalServer() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + AtLeastOneOf: []string{isBareMetalServerName, "identifier"}, + ConflictsWith: []string{isBareMetalServerName}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_bare_metal_server", "identifier"), + }, + isBareMetalServerName: { + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{isBareMetalServerName, "identifier"}, + Computed: true, + ConflictsWith: []string{"identifier"}, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerName), + Description: "Bare metal server name", + }, + isBareMetalServerBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second)", + }, + isBareMetalServerBootTarget: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the bare metal server was created", + }, + isBareMetalServerCPU: { + Type: schema.TypeList, + Computed: true, + Description: "The bare metal server CPU configuration", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerCPUArchitecture: { + Type: schema.TypeString, + Computed: true, + Description: "The CPU architecture", + }, + isBareMetalServerCPUCoreCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of cores", + }, + isBareMetalServerCpuSocketCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of CPU sockets", + }, + isBareMetalServerCpuThreadPerCore: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of hardware threads per core", + }, + }, + }, + }, + isBareMetalServerCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this bare metal server", + }, + isBareMetalServerDisks: { + Type: schema.TypeList, + Computed: true, + Description: "The disks for this bare metal server, including any disks that are associated with the boot_target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerDiskHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk", + }, + isBareMetalServerDiskID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerDiskInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + }, + isBareMetalServerDiskName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk", + }, + isBareMetalServerDiskResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + isBareMetalServerDiskSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + }, + }, + }, + }, + isBareMetalServerHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server", + }, + isBareMetalServerMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of memory, truncated to whole gibibytes", + }, + + isBareMetalServerPrimaryNetworkInterface: { + Type: schema.TypeList, + Computed: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Deprecated: "This URL of the interface", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + }, + }, + }, + + isBareMetalServerNetworkInterfaces: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + }, + }, + }, + + isBareMetalServerKeys: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "SSH key Ids for the bare metal server", + }, + + isBareMetalServerImage: { + Type: schema.TypeString, + Computed: true, + Description: "image name", + }, + isBareMetalServerProfile: { + Type: schema.TypeString, + Computed: true, + Description: "profil name", + }, + + isBareMetalServerZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + isBareMetalServerVPC: { + Type: schema.TypeString, + Computed: true, + Description: "The VPC the bare metal server is to be a part of", + }, + + isBareMetalServerResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Resource group name", + }, + isBareMetalServerResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Resource type name", + }, + + isBareMetalServerStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server status", + }, + + isBareMetalServerStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isBareMetalServerStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isBareMetalServerStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + isBareMetalServerTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Tags for the Bare metal server", + }, + }, + } +} + +func DataSourceIBMIsBareMetalServerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "identifier", + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISBMSDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server", Schema: validateSchema} + return &ibmISBMSDataSourceValidator +} + +func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Get("identifier").(string) + name := d.Get(isBareMetalServerName).(string) + + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + var bms *vpcv1.BareMetalServer + if id != "" { + options := &vpcv1.GetBareMetalServerOptions{} + options.ID = &id + server, response, err := sess.GetBareMetalServerWithContext(context, options) + if err != nil { + log.Printf("[DEBUG] GetBareMetalServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Bare Metal Server (%s): %s\n%s", id, err, response)) + } + bms = server + } else if name != "" { + options := &vpcv1.ListBareMetalServersOptions{} + options.Name = &name + bmservers, response, err := sess.ListBareMetalServersWithContext(context, options) + if err != nil { + log.Printf("[DEBUG] ListBareMetalServersWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Listing Bare Metal Server (%s): %s\n%s", name, err, response)) + } + if len(bmservers.BareMetalServers) == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] No bare metal servers found with name %s", name)) + } + bms = &bmservers.BareMetalServers[0] + } + + d.SetId(*bms.ID) + d.Set(isBareMetalServerBandwidth, bms.Bandwidth) + bmsBootTargetIntf := bms.BootTarget.(*vpcv1.BareMetalServerBootTarget) + bmsBootTarget := bmsBootTargetIntf.ID + d.Set(isBareMetalServerBootTarget, bmsBootTarget) + + // set keys and image using initialization + + optionsInitialization := &vpcv1.GetBareMetalServerInitializationOptions{ + ID: bms.ID, + } + + initialization, response, err := sess.GetBareMetalServerInitialization(optionsInitialization) + if err != nil || initialization == nil { + return diag.FromErr(fmt.Errorf("[Error] Error getting Bare Metal Server (%s) initialization : %s\n%s", *bms.ID, err, response)) + } + + d.Set(isBareMetalServerImage, initialization.Image.ID) + + keyListList := []string{} + for i := 0; i < len(initialization.Keys); i++ { + keyListList = append(keyListList, string(*(initialization.Keys[i].ID))) + } + d.Set(isBareMetalServerKeys, keyListList) + + cpuList := make([]map[string]interface{}, 0) + if bms.Cpu != nil { + currentCPU := map[string]interface{}{} + currentCPU[isBareMetalServerCPUArchitecture] = *bms.Cpu.Architecture + currentCPU[isBareMetalServerCPUCoreCount] = *bms.Cpu.CoreCount + currentCPU[isBareMetalServerCpuSocketCount] = *bms.Cpu.SocketCount + currentCPU[isBareMetalServerCpuThreadPerCore] = *bms.Cpu.ThreadsPerCore + cpuList = append(cpuList, currentCPU) + } + d.Set(isBareMetalServerCPU, cpuList) + if err = d.Set(isBareMetalServerCreatedAt, bms.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set(isBareMetalServerCRN, bms.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + + diskList := make([]map[string]interface{}, 0) + if bms.Disks != nil { + for _, disk := range bms.Disks { + currentDisk := map[string]interface{}{ + isBareMetalServerDiskHref: disk.Href, + isBareMetalServerDiskID: disk.ID, + isBareMetalServerDiskInterfaceType: disk.InterfaceType, + isBareMetalServerDiskName: disk.Name, + isBareMetalServerDiskResourceType: disk.ResourceType, + isBareMetalServerDiskSize: disk.Size, + } + diskList = append(diskList, currentDisk) + } + } + d.Set(isBareMetalServerDisks, diskList) + if err = d.Set(isBareMetalServerHref, bms.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set(isBareMetalServerMemory, bms.Memory); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting memory: %s", err)) + } + if err = d.Set(isBareMetalServerName, *bms.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("identifier", *bms.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting identifier: %s", err)) + } + //pni + + if bms.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *bms.PrimaryNetworkInterface.ID + currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href + currentPrimNic[isBareMetalServerNicName] = *bms.PrimaryNetworkInterface.Name + currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href + currentPrimNic[isBareMetalServerNicSubnet] = *bms.PrimaryNetworkInterface.Subnet.ID + if bms.PrimaryNetworkInterface.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *bms.PrimaryNetworkInterface.PrimaryIP.Address + } + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *bms.PrimaryNetworkInterface.PrimaryIP.Href + } + if bms.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *bms.PrimaryNetworkInterface.PrimaryIP.Name + } + if bms.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *bms.PrimaryNetworkInterface.PrimaryIP.ID + } + if bms.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *bms.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + currentPrimNic[isBareMetalServerNicPrimaryIP] = primaryIpList + } + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: bms.ID, + ID: bms.PrimaryNetworkInterface.ID, + } + bmsnic, response, err := sess.GetBareMetalServerNetworkInterface(getnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response)) + } + + switch reflect.TypeOf(bmsnic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed + + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + + primaryNicList = append(primaryNicList, currentPrimNic) + d.Set(isBareMetalServerPrimaryNetworkInterface, primaryNicList) + } + + //ni + + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range bms.NetworkInterfaces { + if intfc.ID != nil && *intfc.ID != *bms.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + currentNic["id"] = *intfc.ID + currentNic[isBareMetalServerNicHref] = *intfc.Href + currentNic[isBareMetalServerNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *intfc.PrimaryIP.ID + } + if intfc.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *intfc.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList + } + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: bms.ID, + ID: intfc.ID, + } + bmsnicintf, response, err := sess.GetBareMetalServerNetworkInterface(getnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response)) + } + + switch reflect.TypeOf(bmsnicintf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicSubnet] = *bmsnic.Subnet.ID + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicSubnet] = *bmsnic.Subnet.ID + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + interfacesList = append(interfacesList, currentNic) + } + } + d.Set(isBareMetalServerNetworkInterfaces, interfacesList) + + if err = d.Set(isBareMetalServerProfile, *bms.Profile.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile: %s", err)) + } + if bms.ResourceGroup != nil { + d.Set(isBareMetalServerResourceGroup, *bms.ResourceGroup.ID) + } + if err = d.Set(isBareMetalServerResourceType, bms.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set(isBareMetalServerStatus, *bms.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + statusReasonsList := make([]map[string]interface{}, 0) + if bms.StatusReasons != nil { + for _, sr := range bms.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isBareMetalServerStatusReasonsCode] = *sr.Code + currentSR[isBareMetalServerStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isBareMetalServerStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + } + d.Set(isBareMetalServerStatusReasons, statusReasonsList) + + if err = d.Set(isBareMetalServerVPC, *bms.VPC.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpc: %s", err)) + } + if err = d.Set(isBareMetalServerZone, *bms.Zone.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone: %s", err)) + } + + tags, err := flex.GetTagsUsingCRN(meta, *bms.CRN) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource bare metal server (%s) tags: %s", d.Id(), err) + } + d.Set(isBareMetalServerTags, tags) + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go new file mode 100644 index 000000000..ad87303cf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerDisk = "disk" +) + +func DataSourceIBMIsBareMetalServerDisk() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerDiskRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + + isBareMetalServerDisk: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server disk identifier", + }, + //disks + + isBareMetalServerDiskHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk", + }, + isBareMetalServerDiskID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerDiskInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + }, + isBareMetalServerDiskName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk", + }, + isBareMetalServerDiskResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + isBareMetalServerDiskSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + }, + }, + } +} + +func dataSourceIBMISBareMetalServerDiskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + bareMetalServerDiskID := d.Get(isBareMetalServerDisk).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerDiskOptions{ + BareMetalServerID: &bareMetalServerID, + ID: &bareMetalServerDiskID, + } + + disk, response, err := sess.GetBareMetalServerDiskWithContext(context, options) + if err != nil || disk == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) disk (%s): %s\n%s", bareMetalServerID, bareMetalServerDiskID, err, response)) + } + d.SetId(*disk.ID) + d.Set(isBareMetalServerDiskHref, *disk.Href) + d.Set(isBareMetalServerDiskInterfaceType, *disk.InterfaceType) + d.Set(isBareMetalServerDiskName, *disk.Name) + d.Set(isBareMetalServerDiskResourceType, *disk.ResourceType) + d.Set(isBareMetalServerDiskSize, *disk.Size) + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk_test.go new file mode 100644 index 000000000..ea1096c5c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk_test.go @@ -0,0 +1,50 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerDiskDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_disk.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerDiskDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "servers.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerDiskDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_disk" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + disk = ibm_is_bare_metal_server.testacc_bms.disks.0.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go new file mode 100644 index 000000000..a1448e178 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go @@ -0,0 +1,114 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerID = "bare_metal_server" + isBareMetalServerDiskHref = "href" + isBareMetalServerDiskResourceType = "resource_type" +) + +func DataSourceIBMIsBareMetalServerDisks() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerDisksRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + + //disks + + isBareMetalServerDisks: { + Type: schema.TypeList, + Computed: true, + Description: "A list of bare metal server disks. Disk is a block device that is locally attached to the physical server. By default, the listed disks are sorted by their created_at property values, with the newest disk first.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerDiskHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk", + }, + isBareMetalServerDiskID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerDiskInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + }, + isBareMetalServerDiskName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk", + }, + isBareMetalServerDiskResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + isBareMetalServerDiskSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISBareMetalServerDisksRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.ListBareMetalServerDisksOptions{ + BareMetalServerID: &bareMetalServerID, + } + + diskCollection, response, err := sess.ListBareMetalServerDisksWithContext(context, options) + disks := diskCollection.Disks + if err != nil || disks == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) disks: %s\n%s", bareMetalServerID, err, response)) + } + disksInfo := make([]map[string]interface{}, 0) + for _, disk := range disks { + l := map[string]interface{}{ + isBareMetalServerDiskHref: disk.Href, + isBareMetalServerDiskID: disk.ID, + isBareMetalServerDiskInterfaceType: disk.InterfaceType, + isBareMetalServerDiskName: disk.Name, + isBareMetalServerDiskResourceType: disk.ResourceType, + isBareMetalServerDiskSize: disk.Size, + } + disksInfo = append(disksInfo, l) + } + d.SetId(dataSourceIBMISBMSDisksID(d)) + d.Set(isBareMetalServerDisks, disksInfo) + return nil +} + +// dataSourceIBMISBMSProfilesID returns a reasonable ID for a Bare Metal Server Disks list. +func dataSourceIBMISBMSDisksID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks_test.go new file mode 100644 index 000000000..46c5aae6e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks_test.go @@ -0,0 +1,51 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerDisksDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_disks.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerDisksDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "disks.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.name"), + resource.TestCheckResourceAttrSet(resName, "disks.0.interface_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerDisksDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_disks" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization.go new file mode 100644 index 000000000..97312ca47 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization.go @@ -0,0 +1,229 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/ScaleFT/sshkeys" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerImageName = "image_name" + isBareMetalServerUserAccountUserName = "username" + isBareMetalServerUserAccountEncryptionKey = "encryption_key" + isBareMetalServerUserAccountEncPwd = "encrypted_password" + isBareMetalServerUserAccountPassword = "password" + isBareMetalServerPEM = "private_key" + isBareMetalServerPassphrase = "passphrase" + isBareMetalServerUserAccountResourceType = "resource_type" +) + +func DataSourceIBMIsBareMetalServerInitialization() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerInitializationRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + + isBareMetalServerPEM: { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "Bare Metal Server Private Key file", + }, + + isBareMetalServerPassphrase: { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "Passphrase for Bare Metal Server Private Key file", + }, + + isBareMetalServerImage: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier of the image the bare metal server was provisioned from", + }, + + isBareMetalServerImageName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for the image the bare metal server was provisioned from", + }, + + isBareMetalServerUserAccounts: { + Type: schema.TypeList, + Computed: true, + Description: "The user accounts that are created at initialization. There can be multiple account types distinguished by the resource_type attribute.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerUserAccountUserName: { + Type: schema.TypeString, + Computed: true, + Description: "The username for the account created at initialization", + }, + isBareMetalServerUserAccountEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for the encryption key", + }, + isBareMetalServerUserAccountEncPwd: { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The password at initialization, encrypted using encryption_key, and returned base64-encoded", + }, + isBareMetalServerUserAccountPassword: { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The password at initialization, encrypted using encryption_key, and returned base64-encoded", + }, + isBareMetalServerUserAccountResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced : [ host_user_account ]", + }, + }, + }, + }, + + isBareMetalServerKeys: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "SSH key Ids for the bare metal server", + }, + }, + } +} + +func dataSourceIBMISBareMetalServerInitializationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerInitializationOptions{ + ID: &bareMetalServerID, + } + + initialization, response, err := sess.GetBareMetalServerInitializationWithContext(context, options) + if err != nil || initialization == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) initialization : %s\n%s", bareMetalServerID, err, response)) + } + d.SetId(bareMetalServerID) + if initialization.Image != nil { + d.Set(isBareMetalServerImage, initialization.Image.ID) + d.Set(isBareMetalServerImageName, initialization.Image.Name) + } + + var keys []string + keys = make([]string, 0) + if initialization.Keys != nil { + for _, key := range initialization.Keys { + keys = append(keys, *key.ID) + } + } + d.Set(isBareMetalServerKeys, flex.NewStringSet(schema.HashString, keys)) + accList := make([]map[string]interface{}, 0) + if initialization.UserAccounts != nil { + + for _, accIntf := range initialization.UserAccounts { + acc := accIntf.(*vpcv1.BareMetalServerInitializationUserAccount) + currAccount := map[string]interface{}{ + isBareMetalServerUserAccountUserName: *acc.Username, + } + currAccount[isBareMetalServerUserAccountResourceType] = *acc.ResourceType + currAccount[isBareMetalServerUserAccountEncryptionKey] = *acc.EncryptionKey.CRN + encPassword := base64.StdEncoding.EncodeToString(*acc.EncryptedPassword) + currAccount[isBareMetalServerUserAccountEncPwd] = encPassword + + var rsaKey *rsa.PrivateKey + if privatekey, ok := d.GetOk(isBareMetalServerPEM); ok { + keyFlag := privatekey.(string) + keybytes := []byte(keyFlag) + + if keyFlag != "" { + block, err := pem.Decode(keybytes) + if block == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Failed to load the private key from the given key contents. Instead of the key file path, please make sure the private key is pem format")) + } + isEncrypted := false + switch block.Type { + case "RSA PRIVATE KEY": + isEncrypted = x509.IsEncryptedPEMBlock(block) + case "OPENSSH PRIVATE KEY": + var err error + isEncrypted, err = isOpenSSHPrivKeyEncrypted(block.Bytes) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Failed to check if the provided open ssh key is encrypted or not %s", err)) + } + default: + return diag.FromErr(fmt.Errorf("[ERROR] PEM and OpenSSH private key formats with RSA key type are supported, can not support this key file type: %s", err)) + } + passphrase := "" + var privateKey interface{} + if isEncrypted { + if pass, ok := d.GetOk(isBareMetalServerPassphrase); ok { + passphrase = pass.(string) + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Mandatory field 'passphrase' not provided")) + } + var err error + privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, []byte(passphrase)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Fail to decrypting the private key: %s", err)) + } + } else { + var err error + privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, nil) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Fail to decrypting the private key: %s", err)) + } + } + var ok bool + rsaKey, ok = privateKey.(*rsa.PrivateKey) + if !ok { + return diag.FromErr(fmt.Errorf("[ERROR] Failed to convert to RSA private key")) + } + } + } + + if acc.EncryptedPassword != nil { + ciphertext := *acc.EncryptedPassword + password := base64.StdEncoding.EncodeToString(ciphertext) + if rsaKey != nil { + rng := rand.Reader + clearPassword, err := rsa.DecryptPKCS1v15(rng, rsaKey, ciphertext) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Can not decrypt the password with the given key, %s", err)) + } + password = string(clearPassword) + } + currAccount[isBareMetalServerUserAccountPassword] = password + } + accList = append(accList, currAccount) + } + d.Set(isBareMetalServerUserAccounts, accList) + } + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization_test.go new file mode 100644 index 000000000..c6a32f1d0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_initialization_test.go @@ -0,0 +1,49 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerInitializationDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_initialization.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerInitializationDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr(resName, "name", name), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerInitializationDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_initialization" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface.go new file mode 100644 index 000000000..74ea794cc --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface.go @@ -0,0 +1,386 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerNicEnableInfraNAT = "enable_infrastructure_nat" + isBareMetalServerNicFloatingIPs = "floating_ips" + isBareMetalServerNicFloatingIPId = "id" + isBareMetalServerNicIpAddress = "address" + isBareMetalServerNicIpCRN = "crn" + isBareMetalServerNicIpHref = "href" + isBareMetalServerNicIpID = "reserved_ip" + isBareMetalServerNicIpName = "name" + isBareMetalServerNicIpAutoDelete = "auto_delete" + isBareMetalServerNicHref = "href" + isBareMetalServerNicID = "network_interface" + isBareMetalServerNicInterfaceType = "interface_type" + isBareMetalServerNicReservedIps = "ips" + isBareMetalServerNicMacAddress = "mac_address" + isBareMetalServerNicPrimaryIP = "primary_ip" + isBareMetalServerNicResourceType = "resource_type" + isBareMetalServerNicStatus = "status" + isBareMetalServerNicType = "type" + isBareMetalServerNicAllowedVlans = "allowed_vlans" + isBareMetalServerNicAllowInterfaceToFloat = "allow_interface_to_float" + isBareMetalServerNicVlan = "vlan" +) + +func DataSourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNetworkInterfaceRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + + isBareMetalServerNicID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server network interface identifier", + }, + //network interface properties + + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicFloatingIPs: { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + + isBareMetalServerNicIpCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Deprecated: "This field is deprecated - replaced by id", + Description: "The unique identifier for this floating IP", + }, + isBareMetalServerNicFloatingIPId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this floating IP", + }, + + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP", + }, + }, + }, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + + isBareMetalServerNicMacAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the interface. If absent, the value is not known.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface", + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type : [ subnet_reserved_ip ]", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Collection of security groups ids", + }, + + isBareMetalServerNicStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface : [ available, deleting, failed, pending ]", + }, + + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "The id of the associated subnet", + }, + + isBareMetalServerNicType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of this bare metal server network interface : [ primary, secondary ]", + }, + + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + }, + } +} + +func dataSourceIBMISBareMetalServerNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + bareMetalServerNicID := d.Get(isBareMetalServerNicID).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerID, + ID: &bareMetalServerNicID, + } + + nicIntf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil || nicIntf == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface (%s): %s\n%s", bareMetalServerID, bareMetalServerNicID, err, response)) + } + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.SetId(*nic.ID) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicIpID: *ip.ID, + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, *nic.Href) + + d.Set(isBareMetalServerNicID, *nic.ID) + + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + if nic.PortSpeed != nil { + d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) + } + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + + d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) + if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + + d.Set(isBareMetalServerNicType, *nic.Type) + + if nic.AllowedVlans != nil { + var out = make([]interface{}, len(nic.AllowedVlans), len(nic.AllowedVlans)) + for i, v := range nic.AllowedVlans { + out[i] = int(v) + } + d.Set(isBareMetalServerNicAllowedVlans, schema.NewSet(schema.HashInt, out)) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.SetId(*nic.ID) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicIpID: *ip.ID, + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, *nic.Href) + d.Set(isBareMetalServerNicID, *nic.ID) + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + if nic.PortSpeed != nil { + d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) + } + if nic.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + } + + d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) + + if len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + d.Set(isBareMetalServerNicType, *nic.Type) + d.Set(isBareMetalServerNicAllowInterfaceToFloat, *nic.AllowInterfaceToFloat) + d.Set(isBareMetalServerNicVlan, *nic.Vlan) + } + } + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip.go new file mode 100644 index 000000000..7273df41f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip.go @@ -0,0 +1,112 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerNetworkInterfaceFloatingIPID = "floating_ip" +) + +func DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + isBareMetalServerNetworkInterface: { + Type: schema.TypeString, + Required: true, + Description: "The network interface identifier of bare metal server", + }, + isBareMetalServerNetworkInterfaceFloatingIPID: { + Type: schema.TypeString, + Required: true, + Description: "The floating ip identifier of the network interface associated with the bare metal server", + }, + floatingIPName: { + Type: schema.TypeString, + Computed: true, + Description: "Name of the floating IP", + }, + + floatingIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP address", + }, + + floatingIPStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP status", + }, + + floatingIPZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + floatingIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Target info", + }, + + floatingIPCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP crn", + }, + }, + } +} + +func dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + nicID := d.Get(isBareMetalServerNetworkInterface).(string) + fipID := d.Get(isBareMetalServerNetworkInterfaceFloatingIPID).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerID, + NetworkInterfaceID: &nicID, + ID: &fipID, + } + + ip, response, err := sess.GetBareMetalServerNetworkInterfaceFloatingIPWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching floating IP for bare metal server %s\n%s", err, response)) + } + d.Set(floatingIPName, *ip.Name) + d.Set(floatingIPAddress, *ip.Address) + d.Set(floatingIPStatus, *ip.Status) + d.Set(floatingIPZone, *ip.Zone.Name) + + d.Set(floatingIPCRN, *ip.CRN) + + target, ok := ip.Target.(*vpcv1.FloatingIPTarget) + if ok { + d.Set(floatingIPTarget, target.ID) + } + + d.SetId(*ip.ID) + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip_test.go new file mode 100644 index 000000000..4d8ab16a0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ip_test.go @@ -0,0 +1,53 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNetworkInterfaceFloatingIPDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_network_interface_floating_ip.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIPDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "name"), + resource.TestCheckResourceAttrSet(resName, "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIPDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_interface_floating_ip" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.id + floating_ip = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.floating_ip.0.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips.go new file mode 100644 index 000000000..52c6a2cc7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerNetworkInterface = "network_interface" + floatingIPId = "id" +) + +func DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIPs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPsRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + isBareMetalServerNetworkInterface: { + Type: schema.TypeString, + Required: true, + Description: "The network interface identifier of bare metal server", + }, + + //floating ip properties + isBareMetalServerNicFloatingIPs: { + Type: schema.TypeList, + Description: "The floating IPs associated with this network interface.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIPName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the floating IP", + }, + floatingIPId: { + Type: schema.TypeString, + Required: true, + Description: "ID of the floating IP", + }, + + floatingIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP address", + }, + + floatingIPStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP status", + }, + + floatingIPZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + floatingIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Target info", + }, + + floatingIPCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP crn", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + nicID := d.Get(isBareMetalServerNetworkInterface).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + allFloatingIPs := []vpcv1.FloatingIP{} + options := &vpcv1.ListBareMetalServerNetworkInterfaceFloatingIpsOptions{ + BareMetalServerID: &bareMetalServerID, + NetworkInterfaceID: &nicID, + } + + fips, response, err := sess.ListBareMetalServerNetworkInterfaceFloatingIpsWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching floating IPs for bare metal server %s\n%s", err, response)) + } + allFloatingIPs = append(allFloatingIPs, fips.FloatingIps...) + fipInfo := make([]map[string]interface{}, 0) + for _, ip := range allFloatingIPs { + l := map[string]interface{}{} + + l[floatingIPName] = *ip.Name + l[floatingIPAddress] = *ip.Address + l[floatingIPStatus] = *ip.Status + l[floatingIPZone] = *ip.Zone.Name + + l[floatingIPCRN] = *ip.CRN + + target, ok := ip.Target.(*vpcv1.FloatingIPTarget) + if ok { + l[floatingIPTarget] = target.ID + } + + l[floatingIPId] = *ip.ID + + fipInfo = append(fipInfo, l) + } + d.SetId(dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPsID(d)) + d.Set(isBareMetalServerNicFloatingIPs, fipInfo) + return nil +} + +// dataSourceIBMISBMSProfilesID returns a reasonable ID for a BMS network interface floating ip list. +func dataSourceIBMISBareMetalServerNetworkInterfaceFloatingIPsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips_test.go new file mode 100644 index 000000000..d0ad49d5a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_floating_ips_test.go @@ -0,0 +1,52 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNetworkInterfaceFloatingIPsDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_network_interface_floating_ip.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIPsDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "floating_ips.0.name"), + resource.TestCheckResourceAttrSet(resName, "floating_ips.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIPsDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_interface_floating_ips" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip.go new file mode 100644 index 000000000..6c07a3935 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip.go @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Response Param Constants + + isBareMetalServerNICReservedIPCreatedAt = "created_at" + isBareMetalServerNICReservedIPhref = "href" + isBareMetalServerNICReservedIPLifecycleState = "lifecycle_state" + isBareMetalServerNICReservedIPOwner = "owner" + isBareMetalServerNICReservedIPType = "resource_type" + isBareMetalServerNICReservedIPTarget = "target" +) + +func DataSourceIBMISBareMetalServerNICReservedIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNICReservedIPRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The Bare Metal Server identifier.", + }, + isBareMetalServerNicID: { + Type: schema.TypeString, + Required: true, + Description: "The Bare Metal Server network interface identifier.", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Required: true, + Description: "The reserved IP identifier.", + }, + + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, this reserved IP will be automatically deleted", + }, + isBareMetalServerNICReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isBareMetalServerNICReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isBareMetalServerNICReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isBareMetalServerNICReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isBareMetalServerNICReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id.", + }, + }, + } +} + +// dataSourceIBMISBareMetalServerNICReservedIPRead is used when the reserved IPs are read from the vpc +func dataSourceIBMISBareMetalServerNICReservedIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + bareMetalServer := d.Get(isBareMetalServerID).(string) + bareMetalServerNICId := d.Get(isBareMetalServerNicID).(string) + reservedIPID := d.Get(isBareMetalServerNicIpID).(string) + + options := sess.NewGetBareMetalServerNetworkInterfaceIPOptions(bareMetalServer, bareMetalServerNICId, reservedIPID) + reserveIP, response, err := sess.GetBareMetalServerNetworkInterfaceIPWithContext(context, options) + + if err != nil || response == nil || reserveIP == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching the reserved IP %s\n%s", err, response)) + } + + d.SetId(*reserveIP.ID) + d.Set(isBareMetalServerNicIpAutoDelete, *reserveIP.AutoDelete) + d.Set(isBareMetalServerNICReservedIPCreatedAt, (*reserveIP.CreatedAt).String()) + d.Set(isBareMetalServerNICReservedIPhref, *reserveIP.Href) + d.Set(isBareMetalServerNicIpName, *reserveIP.Name) + d.Set(isBareMetalServerNICReservedIPOwner, *reserveIP.Owner) + d.Set(isBareMetalServerNICReservedIPType, *reserveIP.ResourceType) + d.Set(isBareMetalServerNicIpAddress, *reserveIP.Address) + if reserveIP.Target != nil { + target, ok := reserveIP.Target.(*vpcv1.ReservedIPTarget) + if ok { + d.Set(isBareMetalServerNICReservedIPTarget, target.ID) + } + } + return nil // By default there should be no error +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip_test.go new file mode 100644 index 000000000..11bb1cfbf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ip_test.go @@ -0,0 +1,58 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNICReservedIP_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_network_interface_reserved_ip.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccIBMISBareMetalServerNICReservedIPdataSoruceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "name"), + resource.TestCheckResourceAttrSet(resName, "address"), + resource.TestCheckResourceAttrSet(resName, "auto_delete"), + resource.TestCheckResourceAttrSet(resName, "created_at"), + resource.TestCheckResourceAttrSet(resName, "href"), + resource.TestCheckResourceAttrSet(resName, "owner"), + resource.TestCheckResourceAttrSet(resName, "reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "resource_type"), + resource.TestCheckResourceAttrSet(resName, "target"), + ), + }, + }, + }) +} + +func testAccIBMISBareMetalServerNICReservedIPdataSoruceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_interface_reserved_ip" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.id + reserved_ip = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.primary_ip.0.reserved_ip + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips.go new file mode 100644 index 000000000..593203f1a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips.go @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Request Param Constants + isBareMetalServerNICReservedIPLimit = "limit" + isBareMetalServerNICReservedIPSort = "sort" + isBareMetalServerNICReservedIPs = "reserved_ips" + isBareMetalServerNICReservedIPsCount = "total_count" +) + +func DataSourceIBMISBareMetalServerNICReservedIPs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNICReservedIPsRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The BareMetalServer identifier.", + }, + isBareMetalServerNicID: { + Type: schema.TypeString, + Required: true, + Description: "The BareMetalServer network interface identifier.", + }, + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isBareMetalServerNICReservedIPs: { + Type: schema.TypeList, + Description: "Collection of all reserved IPs bound to a network interface.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If reserved ip shall be deleted automatically", + }, + isBareMetalServerNICReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isBareMetalServerNICReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isBareMetalServerNICReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isBareMetalServerNICReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isBareMetalServerNICReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id", + }, + }, + }, + }, + isBareMetalServerNICReservedIPsCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of resources across all pages", + }, + }, + } +} + +func dataSourceIBMISBareMetalServerNICReservedIPsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + bareMetalServerID := d.Get(isBareMetalServerID).(string) + nicID := d.Get(isBareMetalServerNicID).(string) + + // Flatten all the reserved IPs + allrecs := []vpcv1.ReservedIP{} + options := &vpcv1.ListBareMetalServerNetworkInterfaceIpsOptions{ + BareMetalServerID: &bareMetalServerID, + NetworkInterfaceID: &nicID, + } + + result, response, err := sess.ListBareMetalServerNetworkInterfaceIpsWithContext(context, options) + if err != nil || response == nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching reserved ips %s\n%s", err, response)) + } + allrecs = append(allrecs, result.Ips...) + + // Now store all the reserved IP info with their response tags + reservedIPs := []map[string]interface{}{} + for _, data := range allrecs { + ipsOutput := map[string]interface{}{} + ipsOutput[isBareMetalServerNicIpAddress] = *data.Address + ipsOutput[isBareMetalServerNicIpAutoDelete] = *data.AutoDelete + ipsOutput[isBareMetalServerNICReservedIPCreatedAt] = (*data.CreatedAt).String() + ipsOutput[isBareMetalServerNICReservedIPhref] = *data.Href + ipsOutput[isBareMetalServerNicIpID] = *data.ID + ipsOutput[isBareMetalServerNicIpName] = *data.Name + ipsOutput[isBareMetalServerNICReservedIPOwner] = *data.Owner + ipsOutput[isBareMetalServerNICReservedIPType] = *data.ResourceType + target, ok := data.Target.(*vpcv1.ReservedIPTarget) + if ok { + ipsOutput[isReservedIPTarget] = target.ID + } + reservedIPs = append(reservedIPs, ipsOutput) + } + + d.SetId(time.Now().UTC().String()) // This is not any reserved ip or BareMetalServer id but state id + d.Set(isBareMetalServerNICReservedIPs, reservedIPs) + d.Set(isBareMetalServerNICReservedIPsCount, len(reservedIPs)) + d.Set(isBareMetalServerID, bareMetalServerID) + d.Set(isBareMetalServerNicID, nicID) + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips_test.go new file mode 100644 index 000000000..af4841298 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_reserved_ips_test.go @@ -0,0 +1,56 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNICReservedIPs_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_network_interface_reserved_ips.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccIBMISBareMetalServerNICReservedIPSResoruceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.name"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.address"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.auto_delete"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.created_at"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.href"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "reserved_ips.0.target"), + ), + }, + }, + }) +} + +func testAccIBMISBareMetalServerNICReservedIPSResoruceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_interface_reserved_ips" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_test.go new file mode 100644 index 000000000..d55d1f0bb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interface_test.go @@ -0,0 +1,57 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNetworkInterfaceDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_network_interface.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "id"), + resource.TestCheckResourceAttrSet(resName, "primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "port_speed"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_interface" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server.testacc_bms.primary_network_interface.0.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces.go new file mode 100644 index 000000000..aa80d14c7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces.go @@ -0,0 +1,368 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIsBareMetalServerNetworkInterfaces() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServerNetworkInterfacesRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier", + }, + + //network interface properties + isBareMetalServerNetworkInterfaces: { + Type: schema.TypeList, + Description: "A list of all network interfaces on a bare metal server. A network interface is an abstract representation of a network interface card and connects a bare metal server to a subnet. While each network interface can attach to only one subnet, multiple network interfaces can be created to attach to multiple subnets. Multiple interfaces may also attach to the same subnet.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicFloatingIPs: { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + + isBareMetalServerNicIpCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Deprecated: "This field is deprecated - replaced by id", + Description: "The unique identifier for this floating IP", + }, + isBareMetalServerNicFloatingIPId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this floating IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP", + }, + }, + }, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + + isBareMetalServerNicMacAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the interface. If absent, the value is not known.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface", + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "title: IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type : [ subnet_reserved_ip ]", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Collection of security groups ids", + }, + + isBareMetalServerNicStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface : [ available, deleting, failed, pending ]", + }, + + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "The id of the associated subnet", + }, + + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the network interface", + }, + + isBareMetalServerNicType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of this bare metal server network interface : [ primary, secondary ]", + }, + + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISBareMetalServerNetworkInterfacesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerID := d.Get(isBareMetalServerID).(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.ListBareMetalServerNetworkInterfacesOptions{ + BareMetalServerID: &bareMetalServerID, + } + nics := []vpcv1.BareMetalServerNetworkInterfaceIntf{} + bmsNics, response, err := sess.ListBareMetalServerNetworkInterfacesWithContext(context, options) + if err != nil || bmsNics == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error listing Bare Metal Server (%s) network interfaces : %s\n%s", bareMetalServerID, err, response)) + } + nics = append(nics, bmsNics.NetworkInterfaces...) + nicsInfo := make([]map[string]interface{}, 0) + for _, nicIntf := range nics { + l := map[string]interface{}{} + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + l[isBareMetalServerNicAllowIPSpoofing] = *nic.AllowIPSpoofing + l[isBareMetalServerNicEnableInfraNAT] = *nic.EnableInfrastructureNat + if nic.FloatingIps != nil { + floatingIPList := make([]map[string]interface{}, 0) + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicIpID: *ip.ID, + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + l[isBareMetalServerNicFloatingIPs] = floatingIPList + } + l[isBareMetalServerNicHref] = *nic.Href + l[isBareMetalServerNicInterfaceType] = *nic.InterfaceType + l[isBareMetalServerNicMacAddress] = *nic.MacAddress + l[isBareMetalServerNicName] = *nic.Name + if nic.PortSpeed != nil { + l[isBareMetalServerNicPortSpeed] = *nic.PortSpeed + } + if nic.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + l[isBareMetalServerNicPrimaryIP] = primaryIpList + } + l[isBareMetalServerNicResourceType] = *nic.ResourceType + if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + l[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + l[isBareMetalServerNicStatus] = *nic.Status + l[isBareMetalServerNicSubnet] = *nic.Subnet.ID + l[isBareMetalServerNicType] = *nic.Type + l["id"] = *nic.ID + + if nic.AllowedVlans != nil { + var out = make([]interface{}, len(nic.AllowedVlans), len(nic.AllowedVlans)) + for i, v := range nic.AllowedVlans { + out[i] = int(v) + } + l[isBareMetalServerNicAllowedVlans] = schema.NewSet(schema.HashInt, out) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + l[isBareMetalServerNicAllowIPSpoofing] = *nic.AllowIPSpoofing + l[isBareMetalServerNicEnableInfraNAT] = *nic.EnableInfrastructureNat + if nic.FloatingIps != nil { + floatingIPList := make([]map[string]interface{}, 0) + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicIpID: *ip.ID, + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + l[isBareMetalServerNicFloatingIPs] = floatingIPList + } + l[isBareMetalServerNicHref] = *nic.Href + l[isBareMetalServerNicInterfaceType] = *nic.InterfaceType + l[isBareMetalServerNicMacAddress] = *nic.MacAddress + l[isBareMetalServerNicName] = *nic.Name + if nic.PortSpeed != nil { + l[isBareMetalServerNicPortSpeed] = *nic.PortSpeed + } + + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + l[isBareMetalServerNicPrimaryIP] = primaryIpList + l[isBareMetalServerNicResourceType] = *nic.ResourceType + if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + l[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + l[isBareMetalServerNicStatus] = *nic.Status + l[isBareMetalServerNicSubnet] = *nic.Subnet.ID + l[isBareMetalServerNicType] = *nic.Type + l["id"] = *nic.ID + l[isBareMetalServerNicAllowInterfaceToFloat] = *nic.AllowInterfaceToFloat + l[isBareMetalServerNicVlan] = *nic.Vlan + } + } + nicsInfo = append(nicsInfo, l) + } + d.SetId(dataSourceIBMISBareMetalServerNetworkInterfacesID(d)) + d.Set(isBareMetalServerNetworkInterfaces, nicsInfo) + return nil +} + +// dataSourceIBMISBMSProfilesID returns a reasonable ID for a BMS Profile list. +func dataSourceIBMISBareMetalServerNetworkInterfacesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces_test.go new file mode 100644 index 000000000..b904b145b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_interfaces_test.go @@ -0,0 +1,56 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerNetworkInterfacesDataSource_basic(t *testing.T) { + var server string + resName := "data.ibm_is_bare_metal_server_network_interfaces.test1" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBareMetalServerNetworkInterfacesDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.name"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.id"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.port_speed"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfacesDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + + fmt.Sprintf(`data "ibm_is_bare_metal_server_network_interfaces" "test1" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go new file mode 100644 index 000000000..9a964211a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go @@ -0,0 +1,432 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerProfileName = "name" + isBareMetalServerProfileBandwidth = "bandwidth" + isBareMetalServerProfileType = "type" + isBareMetalServerProfileValue = "value" + isBareMetalServerProfileCPUArchitecture = "cpu_architecture" + isBareMetalServerProfileCPUCoreCount = "cpu_core_count" + isBareMetalServerProfileCPUSocketCount = "cpu_socket_count" + isBareMetalServerProfileDisks = "disks" + isBareMetalServerProfileDiskQuantity = "quantity" + isBareMetalServerProfileDiskSize = "size" + isBareMetalServerProfileDiskSITs = "supported_interface_types" + isBareMetalServerProfileFamily = "family" + isBareMetalServerProfileHref = "href" + isBareMetalServerProfileMemory = "memory" + isBareMetalServerProfileOS = "os_architecture" + isBareMetalServerProfileValues = "values" + isBareMetalServerProfileDefault = "default" + isBareMetalServerProfileRT = "resource_type" + isBareMetalServerProfileSIFs = "supported_image_flags" + isBareMetalServerProfileSTPMMs = "supported_trusted_platform_module_modes" +) + +func DataSourceIBMIsBareMetalServerProfile() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBMSProfileRead, + + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileName: { + Type: schema.TypeString, + Required: true, + Description: "The name for this bare metal server profile", + }, + + isBareMetalServerProfileFamily: { + Type: schema.TypeString, + Computed: true, + Description: "The product family this bare metal server profile belongs to", + }, + isBareMetalServerProfileHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server profile", + }, + isBareMetalServerProfileBandwidth: { + Type: schema.TypeList, + Computed: true, + Description: "The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileRT: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type for this bare metal server profile", + }, + + isBareMetalServerProfileCPUArchitecture: { + Type: schema.TypeList, + Computed: true, + Description: "The CPU architecture for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeString, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileCPUSocketCount: { + Type: schema.TypeList, + Computed: true, + Description: "The number of CPU sockets for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileCPUCoreCount: { + Type: schema.TypeList, + Computed: true, + Description: "The CPU core count for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileMemory: { + Type: schema.TypeList, + Computed: true, + Description: "The memory (in gibibytes) for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileSTPMMs: { + Type: schema.TypeList, + Computed: true, + Description: "An array of supported trusted platform module (TPM) modes for this bare metal server profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The supported trusted platform module (TPM) modes", + }, + }, + }, + }, + isBareMetalServerProfileOS: { + Type: schema.TypeList, + Computed: true, + Description: "The supported OS architecture(s) for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDefault: { + Type: schema.TypeString, + Computed: true, + Description: "The default for this profile field", + }, + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The supported OS architecture(s) for a bare metal server with this profile", + }, + }, + }, + }, + isBareMetalServerProfileDisks: { + Type: schema.TypeList, + Computed: true, + Description: "Collection of the bare metal server profile's disks", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDiskQuantity: { + Type: schema.TypeList, + Computed: true, + Description: "The number of disks of this configuration for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileDiskSize: { + Type: schema.TypeList, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileDiskSITs: { + Type: schema.TypeList, + Computed: true, + Description: "The disk interface used for attaching the disk.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDefault: { + Type: schema.TypeString, + Computed: true, + Description: "The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Description: "The supported disk interfaces used for attaching the disk", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISBMSProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + name := d.Get("name").(string) + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerProfileOptions{ + Name: &name, + } + bmsProfile, response, err := sess.GetBareMetalServerProfileWithContext(context, options) + if err != nil || bmsProfile == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Bare Metal Server Profile (%s): %s\n%s", name, err, response)) + } + d.SetId(*bmsProfile.Name) + d.Set(isBareMetalServerProfileName, *bmsProfile.Name) + d.Set(isBareMetalServerProfileFamily, *bmsProfile.Family) + d.Set(isBareMetalServerProfileHref, *bmsProfile.Href) + if bmsProfile.Bandwidth != nil { + bwList := make([]map[string]interface{}, 0) + bw := bmsProfile.Bandwidth.(*vpcv1.BareMetalServerProfileBandwidth) + bandwidth := map[string]interface{}{ + isBareMetalServerProfileType: *bw.Type, + isBareMetalServerProfileValue: *bw.Value, + } + bwList = append(bwList, bandwidth) + d.Set(isBareMetalServerProfileBandwidth, bwList) + } + if bmsProfile.CpuArchitecture != nil { + caList := make([]map[string]interface{}, 0) + ca := bmsProfile.CpuArchitecture + architecture := map[string]interface{}{ + isBareMetalServerProfileType: *ca.Type, + isBareMetalServerProfileValue: *ca.Value, + } + caList = append(caList, architecture) + d.Set(isBareMetalServerProfileCPUArchitecture, caList) + } + if bmsProfile.CpuCoreCount != nil { + ccList := make([]map[string]interface{}, 0) + cc := bmsProfile.CpuCoreCount.(*vpcv1.BareMetalServerProfileCpuCoreCount) + coreCount := map[string]interface{}{ + isBareMetalServerProfileType: *cc.Type, + isBareMetalServerProfileValue: *cc.Value, + } + ccList = append(ccList, coreCount) + d.Set(isBareMetalServerProfileCPUCoreCount, ccList) + } + if bmsProfile.CpuSocketCount != nil { + scList := make([]map[string]interface{}, 0) + sc := bmsProfile.CpuSocketCount.(*vpcv1.BareMetalServerProfileCpuSocketCount) + socketCount := map[string]interface{}{ + isBareMetalServerProfileType: *sc.Type, + isBareMetalServerProfileValue: *sc.Value, + } + scList = append(scList, socketCount) + d.Set(isBareMetalServerProfileCPUSocketCount, scList) + } + + if bmsProfile.Memory != nil { + memList := make([]map[string]interface{}, 0) + mem := bmsProfile.Memory.(*vpcv1.BareMetalServerProfileMemory) + m := map[string]interface{}{ + isBareMetalServerProfileType: *mem.Type, + isBareMetalServerProfileValue: *mem.Value, + } + memList = append(memList, m) + d.Set(isBareMetalServerProfileMemory, memList) + } + d.Set(isBareMetalServerProfileRT, *bmsProfile.ResourceType) + if bmsProfile.SupportedTrustedPlatformModuleModes != nil { + list := make([]map[string]interface{}, 0) + var stpmmlist []string + for _, item := range bmsProfile.SupportedTrustedPlatformModuleModes.Values { + stpmmlist = append(stpmmlist, item) + } + m := map[string]interface{}{ + isBareMetalServerProfileType: *bmsProfile.SupportedTrustedPlatformModuleModes.Type, + } + m[isBareMetalServerProfileValues] = stpmmlist + list = append(list, m) + d.Set(isBareMetalServerProfileSTPMMs, list) + } + if bmsProfile.OsArchitecture != nil { + list := make([]map[string]interface{}, 0) + var valuelist []string + for _, item := range bmsProfile.OsArchitecture.Values { + valuelist = append(valuelist, item) + } + m := map[string]interface{}{ + isBareMetalServerProfileDefault: *bmsProfile.OsArchitecture.Default, + isBareMetalServerProfileType: *bmsProfile.OsArchitecture.Type, + } + m[isBareMetalServerProfileValues] = valuelist + list = append(list, m) + d.Set(isBareMetalServerProfileOS, list) + } + + if bmsProfile.Disks != nil { + list := make([]map[string]interface{}, 0) + for _, disk := range bmsProfile.Disks { + qlist := make([]map[string]interface{}, 0) + slist := make([]map[string]interface{}, 0) + sitlist := make([]map[string]interface{}, 0) + quantity := disk.Quantity.(*vpcv1.BareMetalServerProfileDiskQuantity) + q := make(map[string]interface{}) + q[isBareMetalServerProfileType] = *quantity.Type + q[isBareMetalServerProfileValue] = *quantity.Value + qlist = append(qlist, q) + size := disk.Size.(*vpcv1.BareMetalServerProfileDiskSize) + s := map[string]interface{}{ + isBareMetalServerProfileType: *size.Type, + isBareMetalServerProfileValue: *size.Value, + } + slist = append(slist, s) + sit := map[string]interface{}{ + isBareMetalServerProfileDefault: *disk.SupportedInterfaceTypes.Default, + isBareMetalServerProfileType: *disk.SupportedInterfaceTypes.Type, + } + var valuelist []string + for _, item := range disk.SupportedInterfaceTypes.Values { + valuelist = append(valuelist, item) + } + sit[isBareMetalServerProfileValues] = valuelist + sitlist = append(sitlist, sit) + sz := map[string]interface{}{ + isBareMetalServerProfileDiskQuantity: qlist, + isBareMetalServerProfileDiskSize: slist, + isBareMetalServerProfileDiskSITs: sitlist, + } + list = append(list, sz) + } + d.Set(isBareMetalServerProfileDisks, list) + } + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go new file mode 100644 index 000000000..ace31529e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go @@ -0,0 +1,41 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBMSProfileDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_profile.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBMSProfileDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "name"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBMSProfileDataSourceConfig() string { + // status filter defaults to empty + return fmt.Sprintf(` + data "ibm_is_bare_metal_server_profiles" "testbmsps" { + } + + data "ibm_is_bare_metal_server_profile" "test1" { + name = data.ibm_is_bare_metal_server_profiles.testbmsps.profiles.0.name + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go new file mode 100644 index 000000000..daeb6bacd --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go @@ -0,0 +1,449 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerProfiles = "profiles" +) + +func DataSourceIBMIsBareMetalServerProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBareMetalServerProfilesRead, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerProfiles: { + Type: schema.TypeList, + Description: "List of BMS profile maps", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + isBareMetalServerProfileName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this bare metal server profile", + }, + + isBareMetalServerProfileFamily: { + Type: schema.TypeString, + Computed: true, + Description: "The product family this bare metal server profile belongs to", + }, + isBareMetalServerProfileHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server profile", + }, + isBareMetalServerProfileBandwidth: { + Type: schema.TypeList, + Computed: true, + Description: "The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileRT: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type for this bare metal server profile", + }, + + isBareMetalServerProfileCPUArchitecture: { + Type: schema.TypeList, + Computed: true, + Description: "The CPU architecture for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeString, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileCPUSocketCount: { + Type: schema.TypeList, + Computed: true, + Description: "The number of CPU sockets for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileCPUCoreCount: { + Type: schema.TypeList, + Computed: true, + Description: "The CPU core count for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileMemory: { + Type: schema.TypeList, + Computed: true, + Description: "The memory (in gibibytes) for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileSTPMMs: { + Type: schema.TypeList, + Computed: true, + Description: "An array of supported trusted platform module (TPM) modes for this bare metal server profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The supported trusted platform module (TPM) modes", + }, + }, + }, + }, + isBareMetalServerProfileOS: { + Type: schema.TypeList, + Computed: true, + Description: "The supported OS architecture(s) for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDefault: { + Type: schema.TypeString, + Computed: true, + Description: "The default for this profile field", + }, + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The supported OS architecture(s) for a bare metal server with this profile", + }, + }, + }, + }, + isBareMetalServerProfileDisks: { + Type: schema.TypeList, + Computed: true, + Description: "Collection of the bare metal server profile's disks", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDiskQuantity: { + Type: schema.TypeList, + Computed: true, + Description: "The number of disks of this configuration for a bare metal server with this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + + isBareMetalServerProfileDiskSize: { + Type: schema.TypeList, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValue: { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field", + }, + }, + }, + }, + isBareMetalServerProfileDiskSITs: { + Type: schema.TypeList, + Computed: true, + Description: "The disk interface used for attaching the disk.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerProfileDefault: { + Type: schema.TypeString, + Computed: true, + Description: "The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + isBareMetalServerProfileType: { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field", + }, + isBareMetalServerProfileValues: { + Type: schema.TypeSet, + Computed: true, + Description: "The supported disk interfaces used for attaching the disk", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsBareMetalServerProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.BareMetalServerProfile{} + for { + listBMSProfilesOptions := &vpcv1.ListBareMetalServerProfilesOptions{} + if start != "" { + listBMSProfilesOptions.Start = &start + } + availableProfiles, response, err := sess.ListBareMetalServerProfilesWithContext(context, listBMSProfilesOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching Bare Metal Server Profiles %s\n%s", err, response)) + } + start = flex.GetNext(availableProfiles.Next) + allrecs = append(allrecs, availableProfiles.Profiles...) + if start == "" { + break + } + } + + profilesInfo := make([]map[string]interface{}, 0) + for _, profile := range allrecs { + + l := map[string]interface{}{ + isBareMetalServerProfileName: *profile.Name, + isBareMetalServerProfileFamily: *profile.Family, + } + l[isBareMetalServerProfileHref] = *profile.Href + if profile.Bandwidth != nil { + bwList := make([]map[string]interface{}, 0) + bw := profile.Bandwidth.(*vpcv1.BareMetalServerProfileBandwidth) + bandwidth := map[string]interface{}{ + isBareMetalServerProfileType: *bw.Type, + isBareMetalServerProfileValue: *bw.Value, + } + bwList = append(bwList, bandwidth) + l[isBareMetalServerProfileBandwidth] = bwList + } + if profile.CpuArchitecture != nil { + caList := make([]map[string]interface{}, 0) + ca := profile.CpuArchitecture + architecture := map[string]interface{}{ + isBareMetalServerProfileType: *ca.Type, + isBareMetalServerProfileValue: *ca.Value, + } + caList = append(caList, architecture) + l[isBareMetalServerProfileCPUArchitecture] = caList + } + if profile.CpuCoreCount != nil { + ccList := make([]map[string]interface{}, 0) + cc := profile.CpuCoreCount.(*vpcv1.BareMetalServerProfileCpuCoreCount) + coreCount := map[string]interface{}{ + isBareMetalServerProfileType: *cc.Type, + isBareMetalServerProfileValue: *cc.Value, + } + ccList = append(ccList, coreCount) + l[isBareMetalServerProfileCPUCoreCount] = ccList + } + if profile.CpuSocketCount != nil { + scList := make([]map[string]interface{}, 0) + sc := profile.CpuSocketCount.(*vpcv1.BareMetalServerProfileCpuSocketCount) + socketCount := map[string]interface{}{ + isBareMetalServerProfileType: *sc.Type, + isBareMetalServerProfileValue: *sc.Value, + } + scList = append(scList, socketCount) + l[isBareMetalServerProfileCPUSocketCount] = scList + } + + if profile.Memory != nil { + memList := make([]map[string]interface{}, 0) + mem := profile.Memory.(*vpcv1.BareMetalServerProfileMemory) + m := map[string]interface{}{ + isBareMetalServerProfileType: *mem.Type, + isBareMetalServerProfileValue: *mem.Value, + } + memList = append(memList, m) + l[isBareMetalServerProfileMemory] = memList + } + l[isBareMetalServerProfileRT] = *profile.ResourceType + if profile.SupportedTrustedPlatformModuleModes != nil { + list := make([]map[string]interface{}, 0) + var stpmmlist []string + for _, item := range profile.SupportedTrustedPlatformModuleModes.Values { + stpmmlist = append(stpmmlist, item) + } + m := map[string]interface{}{ + isBareMetalServerProfileType: *profile.SupportedTrustedPlatformModuleModes.Type, + } + m[isBareMetalServerProfileValues] = stpmmlist + list = append(list, m) + l[isBareMetalServerProfileSTPMMs] = list + } + if profile.OsArchitecture != nil { + list := make([]map[string]interface{}, 0) + var valuelist []string + for _, item := range profile.OsArchitecture.Values { + valuelist = append(valuelist, item) + } + m := map[string]interface{}{ + isBareMetalServerProfileDefault: *profile.OsArchitecture.Default, + isBareMetalServerProfileType: *profile.OsArchitecture.Type, + } + m[isBareMetalServerProfileValues] = valuelist + list = append(list, m) + l[isBareMetalServerProfileOS] = list + } + + if profile.Disks != nil { + list := make([]map[string]interface{}, 0) + for _, disk := range profile.Disks { + qlist := make([]map[string]interface{}, 0) + slist := make([]map[string]interface{}, 0) + sitlist := make([]map[string]interface{}, 0) + quantity := disk.Quantity.(*vpcv1.BareMetalServerProfileDiskQuantity) + q := make(map[string]interface{}) + q[isBareMetalServerProfileType] = *quantity.Type + q[isBareMetalServerProfileValue] = *quantity.Value + qlist = append(qlist, q) + size := disk.Size.(*vpcv1.BareMetalServerProfileDiskSize) + s := map[string]interface{}{ + isBareMetalServerProfileType: *size.Type, + isBareMetalServerProfileValue: *size.Value, + } + slist = append(slist, s) + sit := map[string]interface{}{ + isBareMetalServerProfileDefault: *disk.SupportedInterfaceTypes.Default, + isBareMetalServerProfileType: *disk.SupportedInterfaceTypes.Type, + } + var valuelist []string + for _, item := range disk.SupportedInterfaceTypes.Values { + valuelist = append(valuelist, item) + } + sit[isBareMetalServerProfileValues] = valuelist + sitlist = append(sitlist, sit) + sz := map[string]interface{}{ + isBareMetalServerProfileDiskQuantity: qlist, + isBareMetalServerProfileDiskSize: slist, + isBareMetalServerProfileDiskSITs: sitlist, + } + list = append(list, sz) + } + l[isBareMetalServerProfileDisks] = list + } + + profilesInfo = append(profilesInfo, l) + } + d.SetId(dataSourceIBMIsBMSProfilesID(d)) + d.Set(isBareMetalServerProfiles, profilesInfo) + return nil +} + +// dataSourceIBMIsBMSProfilesID returns a reasonable ID for a BMS Profile list. +func dataSourceIBMIsBMSProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go new file mode 100644 index 000000000..fa32f3387 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBMSProfilesDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_profiles.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBMSProfilesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.family"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBMSProfilesDataSourceConfig() string { + // status filter defaults to empty + return fmt.Sprintf(` + data "ibm_is_bare_metal_server_profiles" "test1" { + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go new file mode 100644 index 000000000..3424358fe --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go @@ -0,0 +1,60 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBMSDataSource_basic(t *testing.T) { + var server string + resName := "data.ibm_is_bare_metal_server.test1" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBMSDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + resName, "name", name), + resource.TestCheckResourceAttr( + "data.ibm_is_bare_metal_server.test1", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "data.ibm_is_bare_metal_server.test1", "profile", acc.IsBareMetalServerProfileName), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.port_speed"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBMSDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_server" "test1" { + name = "%s" + }`, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go new file mode 100644 index 000000000..c50e022ed --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go @@ -0,0 +1,652 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServers = "servers" +) + +func DataSourceIBMIsBareMetalServers() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISBareMetalServersRead, + + Schema: map[string]*schema.Schema{ + + isBareMetalServers: { + Type: schema.TypeList, + Description: "List of Bare Metal Servers", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server id", + }, + isBareMetalServerName: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server name", + }, + isBareMetalServerBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second)", + }, + isBareMetalServerBootTarget: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the bare metal server was created", + }, + isBareMetalServerCPU: { + Type: schema.TypeList, + Computed: true, + Description: "The bare metal server CPU configuration", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerCPUArchitecture: { + Type: schema.TypeString, + Computed: true, + Description: "The CPU architecture", + }, + isBareMetalServerCPUCoreCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of cores", + }, + isBareMetalServerCpuSocketCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of CPU sockets", + }, + isBareMetalServerCpuThreadPerCore: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of hardware threads per core", + }, + }, + }, + }, + isBareMetalServerCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this bare metal server", + }, + isBareMetalServerDisks: { + Type: schema.TypeList, + Computed: true, + Description: "The disks for this bare metal server, including any disks that are associated with the boot_target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerDiskHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk", + }, + isBareMetalServerDiskID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerDiskInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + }, + isBareMetalServerDiskName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk", + }, + isBareMetalServerDiskResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + isBareMetalServerDiskSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + }, + }, + }, + }, + isBareMetalServerHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server", + }, + isBareMetalServerMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of memory, truncated to whole gibibytes", + }, + + isBareMetalServerPrimaryNetworkInterface: { + Type: schema.TypeList, + Computed: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Deprecated: "This URL of the interface", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + }, + }, + }, + + isBareMetalServerNetworkInterfaces: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + }, + }, + }, + + isBareMetalServerKeys: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "SSH key Ids for the bare metal server", + }, + + isBareMetalServerImage: { + Type: schema.TypeString, + Computed: true, + Description: "image id", + }, + isBareMetalServerProfile: { + Type: schema.TypeString, + Computed: true, + Description: "profile name", + }, + + isBareMetalServerZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + isBareMetalServerVPC: { + Type: schema.TypeString, + Computed: true, + Description: "The VPC the bare metal server is to be a part of", + }, + + isBareMetalServerResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Resource group name", + }, + isBareMetalServerResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Resource type name", + }, + + isBareMetalServerStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server status", + }, + + isBareMetalServerStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isBareMetalServerStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isBareMetalServerStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + isBareMetalServerTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Tags for the Bare metal server", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + start := "" + allrecs := []vpcv1.BareMetalServer{} + for { + listBareMetalServersOptions := &vpcv1.ListBareMetalServersOptions{} + if start != "" { + listBareMetalServersOptions.Start = &start + } + availableServers, response, err := sess.ListBareMetalServersWithContext(context, listBareMetalServersOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching Bare Metal Servers %s\n%s", err, response)) + } + start = flex.GetNext(availableServers.Next) + allrecs = append(allrecs, availableServers.BareMetalServers...) + if start == "" { + break + } + } + + serversInfo := make([]map[string]interface{}, 0) + for _, bms := range allrecs { + + l := map[string]interface{}{ + isBareMetalServerName: *bms.Name, + } + l["id"] = *bms.ID + l[isBareMetalServerBandwidth] = *bms.Bandwidth + bmsBootTargetIntf := bms.BootTarget.(*vpcv1.BareMetalServerBootTarget) + bmsBootTarget := bmsBootTargetIntf.ID + l[isBareMetalServerBootTarget] = bmsBootTarget + cpuList := make([]map[string]interface{}, 0) + if bms.Cpu != nil { + currentCPU := map[string]interface{}{} + currentCPU[isBareMetalServerCPUArchitecture] = *bms.Cpu.Architecture + currentCPU[isBareMetalServerCPUCoreCount] = *bms.Cpu.CoreCount + currentCPU[isBareMetalServerCpuSocketCount] = *bms.Cpu.SocketCount + currentCPU[isBareMetalServerCpuThreadPerCore] = *bms.Cpu.ThreadsPerCore + cpuList = append(cpuList, currentCPU) + } + l[isBareMetalServerCPU] = cpuList + l[isBareMetalServerName] = *bms.Name + l[isBareMetalServerCRN] = *bms.CRN + + // disks + + diskList := make([]map[string]interface{}, 0) + if bms.Disks != nil { + for _, disk := range bms.Disks { + currentDisk := map[string]interface{}{ + isBareMetalServerDiskHref: disk.Href, + isBareMetalServerDiskID: disk.ID, + isBareMetalServerDiskInterfaceType: disk.InterfaceType, + isBareMetalServerDiskName: disk.Name, + isBareMetalServerDiskResourceType: disk.ResourceType, + isBareMetalServerDiskSize: disk.Size, + } + diskList = append(diskList, currentDisk) + } + } + l[isBareMetalServerDisks] = diskList + + l[isBareMetalServerHref] = *bms.Href + l[isBareMetalServerMemory] = *bms.Memory + l[isBareMetalServerProfile] = *bms.Profile.Name + //pni + + if bms.PrimaryNetworkInterface != nil && bms.PrimaryNetworkInterface.ID != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *bms.PrimaryNetworkInterface.ID + currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href + currentPrimNic[isBareMetalServerNicName] = *bms.PrimaryNetworkInterface.Name + currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href + currentPrimNic[isBareMetalServerNicSubnet] = *bms.PrimaryNetworkInterface.Subnet.ID + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *bms.PrimaryNetworkInterface.PrimaryIP.Address + } + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *bms.PrimaryNetworkInterface.PrimaryIP.Href + } + if bms.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *bms.PrimaryNetworkInterface.PrimaryIP.Name + } + if bms.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *bms.PrimaryNetworkInterface.PrimaryIP.ID + } + if bms.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *bms.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + currentPrimNic[isBareMetalServerNicPrimaryIP] = primaryIpList + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: bms.ID, + ID: bms.PrimaryNetworkInterface.ID, + } + bmsnic, response, err := sess.GetBareMetalServerNetworkInterface(getnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response)) + } + + switch reflect.TypeOf(bmsnic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed + + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + + primaryNicList = append(primaryNicList, currentPrimNic) + l[isBareMetalServerPrimaryNetworkInterface] = primaryNicList + } + + //ni + + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range bms.NetworkInterfaces { + if intfc.ID != nil && *intfc.ID != *bms.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + currentNic["id"] = *intfc.ID + currentNic[isBareMetalServerNicHref] = *intfc.Href + currentNic[isBareMetalServerNicName] = *intfc.Name + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *intfc.PrimaryIP.ID + } + if intfc.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *intfc.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: bms.ID, + ID: intfc.ID, + } + bmsnicintf, response, err := sess.GetBareMetalServerNetworkInterface(getnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response)) + } + + switch reflect.TypeOf(bmsnicintf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicSubnet] = *bmsnic.Subnet.ID + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicSubnet] = *bmsnic.Subnet.ID + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + interfacesList = append(interfacesList, currentNic) + } + } + l[isBareMetalServerNetworkInterfaces] = interfacesList + l[isBareMetalServerCreatedAt] = bms.CreatedAt.String() + + //disks + l[isBareMetalServerResourceType] = *bms.ResourceType + l[isBareMetalServerStatus] = *bms.Status + if bms.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range bms.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isBareMetalServerStatusReasonsCode] = *sr.Code + currentSR[isBareMetalServerStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isBareMetalServerStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + l[isBareMetalServerStatusReasons] = statusReasonsList + } + l[isBareMetalServerVPC] = *bms.VPC.ID + l[isBareMetalServerZone] = *bms.Zone.Name + + // set keys and image using initialization + + optionsInitialization := &vpcv1.GetBareMetalServerInitializationOptions{ + ID: bms.ID, + } + + initialization, response, err := sess.GetBareMetalServerInitialization(optionsInitialization) + if err != nil || initialization == nil { + log.Printf("[ERROR] Error getting Bare Metal Server (%s) initialization : %s\n%s", *bms.ID, err, response) + } + + l[isBareMetalServerImage] = *initialization.Image.ID + + keyListList := []string{} + for i := 0; i < len(initialization.Keys); i++ { + keyListList = append(keyListList, string(*(initialization.Keys[i].ID))) + } + l[isBareMetalServerKeys] = keyListList + + tags, err := flex.GetTagsUsingCRN(meta, *bms.CRN) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource bare metal server (%s) tags: %s", *bms.ID, err) + } + l[isBareMetalServerTags] = tags + if bms.ResourceGroup != nil { + l[isBareMetalServerResourceGroup] = *bms.ResourceGroup.ID + } + serversInfo = append(serversInfo, l) + } + d.SetId(dataSourceIBMISBareMetalServersID(d)) + d.Set(isBareMetalServers, serversInfo) + return nil +} + +// dataSourceIBMISBareMetalServersID returns a reasonable ID for a Bare Metal Servers list. +func dataSourceIBMISBareMetalServersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go new file mode 100644 index 000000000..96979a9b0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go @@ -0,0 +1,56 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBMSsDataSource_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_servers.test1" + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBMSsDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "servers.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.id"), + resource.TestCheckResourceAttrSet(resName, "servers.0.memory"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.port_speed"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBMSsDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_servers" "test1" { + }`) +} diff --git a/ibm/data_source_ibm_is_dedicated_host.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host.go similarity index 85% rename from ibm/data_source_ibm_is_dedicated_host.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host.go index c1b58a0c0..7c1cc34e7 100644 --- a/ibm/data_source_ibm_is_dedicated_host.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,50 +9,51 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHost() *schema.Resource { +func DataSourceIbmIsDedicatedHost() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "The unique name of this dedicated host", }, - "host_group": &schema.Schema{ + "host_group": { Type: schema.TypeString, Required: true, Description: "The unique identifier of the dedicated host group this dedicated host belongs to", }, - "resource_group": &schema.Schema{ + "resource_group": { Type: schema.TypeString, Optional: true, Computed: true, Description: "The unique identifier of the resource group this dedicated host belongs to", }, - "available_memory": &schema.Schema{ + "available_memory": { Type: schema.TypeInt, Computed: true, Description: "The amount of memory in gibibytes that is currently available for instances.", }, - "available_vcpu": &schema.Schema{ + "available_vcpu": { Type: schema.TypeList, Computed: true, Description: "The available VCPU for the dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "architecture": &schema.Schema{ + "architecture": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture.", }, - "count": &schema.Schema{ + "count": { Type: schema.TypeInt, Computed: true, Description: "The number of VCPUs assigned.", @@ -60,55 +61,55 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the dedicated host was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "available": &schema.Schema{ + "available": { Type: schema.TypeInt, Computed: true, Description: "The remaining space left for instance placement in GB (gigabytes).", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this disk.", }, - "instance_disks": &schema.Schema{ + "instance_disks": { Type: schema.TypeList, Computed: true, Description: "Instance disks that are on this dedicated host disk.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -116,22 +117,22 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", @@ -139,37 +140,37 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of this dedicated host disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined or system-provided name for this disk.", }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host disk is available for instance disk creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for this dedicated host disk.", @@ -180,34 +181,34 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "instance_placement_enabled": &schema.Schema{ + "instance_placement_enabled": { Type: schema.TypeBool, Computed: true, Description: "If set to true, instances can be placed on this dedicated host.", }, - "instances": &schema.Schema{ + "instances": { Type: schema.TypeList, Computed: true, Description: "Array of instances that are allocated to this dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this virtual server instance.", }, - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -215,17 +216,17 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this virtual server instance.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this virtual server instance (and default system hostname).", @@ -233,28 +234,28 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of the dedicated host resource.", }, - "memory": &schema.Schema{ + "memory": { Type: schema.TypeInt, Computed: true, Description: "The total amount of memory in gibibytes for this host.", }, - "profile": &schema.Schema{ + "profile": { Type: schema.TypeList, Computed: true, Description: "The profile this dedicated host uses.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this dedicated host profile.", @@ -262,38 +263,38 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host is available for instance creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "socket_count": &schema.Schema{ + "socket_count": { Type: schema.TypeInt, Computed: true, Description: "The total number of sockets for this host.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The administrative state of the dedicated host.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the dedicated host on which the unexpected property value was encountered.", }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on this dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -301,18 +302,18 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "vcpu": &schema.Schema{ + "vcpu": { Type: schema.TypeList, Computed: true, Description: "The total VCPU of the dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "architecture": &schema.Schema{ + "architecture": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture.", }, - "count": &schema.Schema{ + "count": { Type: schema.TypeInt, Computed: true, Description: "The number of VCPUs assigned.", @@ -320,7 +321,7 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeString, Computed: true, Description: "The globally unique name of the zone this dedicated host resides in.", @@ -330,7 +331,7 @@ func dataSourceIbmIsDedicatedHost() *schema.Resource { } func dataSourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -355,100 +356,100 @@ func dataSourceIbmIsDedicatedHostRead(context context.Context, d *schema.Resourc d.SetId(*dedicatedHost.ID) if err = d.Set("available_memory", dedicatedHost.AvailableMemory); err != nil { - return diag.FromErr(fmt.Errorf("Error setting available_memory: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting available_memory: %s", err)) } if dedicatedHost.AvailableVcpu != nil { err = d.Set("available_vcpu", dataSourceDedicatedHostFlattenAvailableVcpu(*dedicatedHost.AvailableVcpu)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting available_vcpu %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting available_vcpu %s", err)) } } if err = d.Set("created_at", dedicatedHost.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("crn", dedicatedHost.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if dedicatedHost.Disks != nil { err = d.Set("disks", dataSourceDedicatedHostFlattenDisks(dedicatedHost.Disks)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting disks %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disks %s", err)) } } if dedicatedHost.Group != nil { err = d.Set("host_group", *dedicatedHost.Group.ID) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting group %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting group %s", err)) } } if err = d.Set("href", dedicatedHost.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("instance_placement_enabled", dedicatedHost.InstancePlacementEnabled); err != nil { - return diag.FromErr(fmt.Errorf("Error setting instance_placement_enabled: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_placement_enabled: %s", err)) } if dedicatedHost.Instances != nil { err = d.Set("instances", dataSourceDedicatedHostFlattenInstances(dedicatedHost.Instances)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting instances %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instances %s", err)) } } if err = d.Set("lifecycle_state", dedicatedHost.LifecycleState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) } if err = d.Set("memory", dedicatedHost.Memory); err != nil { - return diag.FromErr(fmt.Errorf("Error setting memory: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting memory: %s", err)) } if err = d.Set("name", dedicatedHost.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if dedicatedHost.Profile != nil { err = d.Set("profile", dataSourceDedicatedHostFlattenProfile(*dedicatedHost.Profile)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting profile %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile %s", err)) } } if err = d.Set("provisionable", dedicatedHost.Provisionable); err != nil { - return diag.FromErr(fmt.Errorf("Error setting provisionable: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting provisionable: %s", err)) } if dedicatedHost.ResourceGroup != nil { err = d.Set("resource_group", *dedicatedHost.ResourceGroup.ID) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) } } if err = d.Set("resource_type", dedicatedHost.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } if err = d.Set("socket_count", dedicatedHost.SocketCount); err != nil { - return diag.FromErr(fmt.Errorf("Error setting socket_count: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting socket_count: %s", err)) } if err = d.Set("state", dedicatedHost.State); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) } if dedicatedHost.SupportedInstanceProfiles != nil { err = d.Set("supported_instance_profiles", dataSourceDedicatedHostFlattenSupportedInstanceProfiles(dedicatedHost.SupportedInstanceProfiles)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_profiles %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_profiles %s", err)) } } if dedicatedHost.Vcpu != nil { err = d.Set("vcpu", dataSourceDedicatedHostFlattenVcpu(*dedicatedHost.Vcpu)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting vcpu %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vcpu %s", err)) } } if dedicatedHost.Zone != nil { err = d.Set("zone", *dedicatedHost.Zone.Name) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting zone %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone %s", err)) } } @@ -456,7 +457,7 @@ func dataSourceIbmIsDedicatedHostRead(context context.Context, d *schema.Resourc } } } - return diag.FromErr(fmt.Errorf("No Dedicated Host found with name %s", name)) + return diag.FromErr(fmt.Errorf("[ERROR] No Dedicated Host found with name %s", name)) } // dataSourceIbmIsDedicatedHostID returns a reasonable ID for the list. diff --git a/ibm/data_source_ibm_is_dedicated_host_disk.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disk.go similarity index 81% rename from ibm/data_source_ibm_is_dedicated_host_disk.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_disk.go index a09283dc6..def4fdae5 100644 --- a/ibm/data_source_ibm_is_dedicated_host_disk.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disk.go @@ -1,62 +1,63 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostDisk() *schema.Resource { +func DataSourceIbmIsDedicatedHostDisk() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostDiskRead, Schema: map[string]*schema.Schema{ - "dedicated_host": &schema.Schema{ + "dedicated_host": { Type: schema.TypeString, Required: true, Description: "The dedicated host identifier.", }, - "disk": &schema.Schema{ + "disk": { Type: schema.TypeString, Required: true, Description: "The dedicated host disk identifier.", }, - "available": &schema.Schema{ + "available": { Type: schema.TypeInt, Computed: true, Description: "The remaining space left for instance placement in GB (gigabytes).", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this disk.", }, - "instance_disks": &schema.Schema{ + "instance_disks": { Type: schema.TypeList, Computed: true, Description: "Instance disks that are on this dedicated host disk.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -64,22 +65,22 @@ func dataSourceIbmIsDedicatedHostDisk() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", @@ -87,37 +88,37 @@ func dataSourceIbmIsDedicatedHostDisk() *schema.Resource { }, }, }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of this dedicated host disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined or system-provided name for this disk.", }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host disk is available for instance disk creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for this dedicated host disk.", @@ -130,7 +131,7 @@ func dataSourceIbmIsDedicatedHostDisk() *schema.Resource { } func dataSourceIbmIsDedicatedHostDiskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -148,43 +149,43 @@ func dataSourceIbmIsDedicatedHostDiskRead(context context.Context, d *schema.Res d.SetId(*dedicatedHostDisk.ID) if err = d.Set("available", dedicatedHostDisk.Available); err != nil { - return diag.FromErr(fmt.Errorf("Error setting available: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting available: %s", err)) } if err = d.Set("created_at", dedicatedHostDisk.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("href", dedicatedHostDisk.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if dedicatedHostDisk.InstanceDisks != nil { err = d.Set("instance_disks", dataSourceDedicatedHostDiskFlattenInstanceDisks(dedicatedHostDisk.InstanceDisks)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting instance_disks %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_disks %s", err)) } } if err = d.Set("interface_type", dedicatedHostDisk.InterfaceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting interface_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting interface_type: %s", err)) } if dedicatedHostDisk.LifecycleState != nil { if err = d.Set("lifecycle_state", dedicatedHostDisk.LifecycleState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) } } if err = d.Set("name", dedicatedHostDisk.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("provisionable", dedicatedHostDisk.Provisionable); err != nil { - return diag.FromErr(fmt.Errorf("Error setting provisionable: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting provisionable: %s", err)) } if err = d.Set("resource_type", dedicatedHostDisk.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } if err = d.Set("size", dedicatedHostDisk.Size); err != nil { - return diag.FromErr(fmt.Errorf("Error setting size: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting size: %s", err)) } if err = d.Set("supported_instance_interface_types", dedicatedHostDisk.SupportedInstanceInterfaceTypes); err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_interface_types: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_interface_types: %s", err)) } return nil diff --git a/ibm/service/vpc/data_source_ibm_is_dedicated_host_disk_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disk_test.go new file mode 100644 index 000000000..75d13cd8f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disk_test.go @@ -0,0 +1,62 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISDedicatedHostDiskDataSource_basic(t *testing.T) { + resName := "data.ibm_is_dedicated_host_disk.test1" + var conf vpcv1.DedicatedHost + groupname := fmt.Sprintf("tf-dhostgroup%d", acctest.RandIntRange(10, 100)) + dhname := fmt.Sprintf("tf-dhost%d", acctest.RandIntRange(10, 100)) + dhresname := "ibm_is_dedicated_host.dhost" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsDedicatedHostConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIsDedicatedHostExists(dhresname, conf), + resource.TestCheckResourceAttr(dhresname, "name", dhname), + resource.TestCheckResourceAttr(dhresname, "disks.#", "2"), + resource.TestCheckResourceAttrSet(dhresname, "disks.0.name"), + resource.TestCheckResourceAttrSet(dhresname, "disks.0.size"), + ), + }, + { + Config: testAccCheckIBMISDedicatedHostDiskDataSourceConfig(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "name"), + resource.TestCheckResourceAttrSet(resName, "size"), + ), + }, + }, + }) +} + +func testAccCheckIBMISDedicatedHostDiskDataSourceConfig(class, family, groupname, DedicatedHostProfileName, dhname string) string { + return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, acc.DedicatedHostProfileName, dhname) + fmt.Sprintf(` + data "ibm_is_dedicated_host" "dhost" { + name = "%s" + host_group = ibm_is_dedicated_host.dhost.host_group + } + data "ibm_is_dedicated_host_disks" "test1" { + dedicated_host = data.ibm_is_dedicated_host.dhost.id + + } + data "ibm_is_dedicated_host_disk" "test1" { + dedicated_host = data.ibm_is_dedicated_host.dhost.id + disk = data.ibm_is_dedicated_host_disks.test1.disks.0.id + }`, dhname) +} diff --git a/ibm/data_source_ibm_is_dedicated_host_disks.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disks.go similarity index 89% rename from ibm/data_source_ibm_is_dedicated_host_disks.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_disks.go index 14d503a26..756279b3e 100644 --- a/ibm/data_source_ibm_is_dedicated_host_disks.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disks.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,61 +9,62 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostDisks() *schema.Resource { +func DataSourceIbmIsDedicatedHostDisks() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostDisksRead, Schema: map[string]*schema.Schema{ - "dedicated_host": &schema.Schema{ + "dedicated_host": { Type: schema.TypeString, Required: true, Description: "The dedicated host identifier.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "available": &schema.Schema{ + "available": { Type: schema.TypeInt, Computed: true, Description: "The remaining space left for instance placement in GB (gigabytes).", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this disk.", }, - "instance_disks": &schema.Schema{ + "instance_disks": { Type: schema.TypeList, Computed: true, Description: "Instance disks that are on this dedicated host disk.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -71,22 +72,22 @@ func dataSourceIbmIsDedicatedHostDisks() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", @@ -94,37 +95,37 @@ func dataSourceIbmIsDedicatedHostDisks() *schema.Resource { }, }, }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of this dedicated host disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined or system-provided name for this disk.", }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host disk is available for instance disk creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for this dedicated host disk.", @@ -140,7 +141,7 @@ func dataSourceIbmIsDedicatedHostDisks() *schema.Resource { } func dataSourceIbmIsDedicatedHostDisksRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -160,7 +161,7 @@ func dataSourceIbmIsDedicatedHostDisksRead(context context.Context, d *schema.Re if dedicatedHostDiskCollection.Disks != nil { err = d.Set("disks", dataSourceDedicatedHostDiskCollectionFlattenDisks(dedicatedHostDiskCollection.Disks)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting disks %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disks %s", err)) } } diff --git a/ibm/data_source_ibm_is_dedicated_host_disks_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disks_test.go similarity index 75% rename from ibm/data_source_ibm_is_dedicated_host_disks_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_disks_test.go index d3d8c9be8..3bd71128b 100644 --- a/ibm/data_source_ibm_is_dedicated_host_disks_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_disks_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,11 +21,11 @@ func TestAccIBMISDedicatedHostDisksDataSource_basic(t *testing.T) { dhname := fmt.Sprintf("tf-dhost%d", acctest.RandIntRange(10, 100)) dhresname := "ibm_is_dedicated_host.dhost" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIbmIsDedicatedHostConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + Config: testAccCheckIbmIsDedicatedHostConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostExists(dhresname, conf), resource.TestCheckResourceAttr(dhresname, "name", dhname), @@ -33,7 +35,7 @@ func TestAccIBMISDedicatedHostDisksDataSource_basic(t *testing.T) { ), }, { - Config: testAccCheckIBMISDedicatedHostDisksDataSourceConfig(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + Config: testAccCheckIBMISDedicatedHostDisksDataSourceConfig(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "disks.0.name"), resource.TestCheckResourceAttrSet(resName, "disks.0.size"), @@ -43,9 +45,9 @@ func TestAccIBMISDedicatedHostDisksDataSource_basic(t *testing.T) { }) } -func testAccCheckIBMISDedicatedHostDisksDataSourceConfig(class, family, groupname, dedicatedHostProfileName, dhname string) string { +func testAccCheckIBMISDedicatedHostDisksDataSourceConfig(class, family, groupname, DedicatedHostProfileName, dhname string) string { // status filter defaults to empty - return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, dedicatedHostProfileName, dhname) + fmt.Sprintf(` + return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, acc.DedicatedHostProfileName, dhname) + fmt.Sprintf(` data "ibm_is_dedicated_host" "dhost" { name = "%s" host_group = ibm_is_dedicated_host.dhost.host_group diff --git a/ibm/data_source_ibm_is_dedicated_host_group.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_group.go similarity index 84% rename from ibm/data_source_ibm_is_dedicated_host_group.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_group.go index e91a1ef31..95b61b04f 100644 --- a/ibm/data_source_ibm_is_dedicated_host_group.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_group.go @@ -1,62 +1,63 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostGroup() *schema.Resource { +func DataSourceIbmIsDedicatedHostGroup() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostGroupRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "class": &schema.Schema{ + "class": { Type: schema.TypeString, Computed: true, Description: "The dedicated host profile class for hosts in this group.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the dedicated host group was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host group.", }, - "dedicated_hosts": &schema.Schema{ + "dedicated_hosts": { Type: schema.TypeList, Computed: true, Description: "The dedicated hosts that are in this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host.", }, - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -64,22 +65,22 @@ func dataSourceIbmIsDedicatedHostGroup() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this dedicated host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", @@ -87,38 +88,38 @@ func dataSourceIbmIsDedicatedHostGroup() *schema.Resource { }, }, }, - "family": &schema.Schema{ + "family": { Type: schema.TypeString, Computed: true, Description: "The dedicated host profile family for hosts in this group.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host group.", }, - "resource_group": &schema.Schema{ + "resource_group": { Type: schema.TypeString, Computed: true, Description: "The unique identifier of the resource group for this dedicated host group.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -126,7 +127,7 @@ func dataSourceIbmIsDedicatedHostGroup() *schema.Resource { }, }, }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeString, Computed: true, Description: "The globally unique name of the zone this dedicated host group resides in.", @@ -136,7 +137,7 @@ func dataSourceIbmIsDedicatedHostGroup() *schema.Resource { } func dataSourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -159,59 +160,59 @@ func dataSourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.Re dedicatedHostGroup = data d.SetId(*dedicatedHostGroup.ID) if err = d.Set("class", dedicatedHostGroup.Class); err != nil { - return diag.FromErr(fmt.Errorf("Error setting class: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting class: %s", err)) } if dedicatedHostGroup.CreatedAt != nil { if err = d.Set("created_at", dedicatedHostGroup.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } } if err = d.Set("crn", dedicatedHostGroup.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if dedicatedHostGroup.DedicatedHosts != nil { err = d.Set("dedicated_hosts", dataSourceDedicatedHostGroupFlattenDedicatedHosts(dedicatedHostGroup.DedicatedHosts)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting dedicated_hosts %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting dedicated_hosts %s", err)) } } if err = d.Set("family", dedicatedHostGroup.Family); err != nil { - return diag.FromErr(fmt.Errorf("Error setting family: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting family: %s", err)) } if err = d.Set("href", dedicatedHostGroup.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if dedicatedHostGroup.ResourceGroup != nil { err = d.Set("resource_group", *dedicatedHostGroup.ResourceGroup.ID) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) } } if err = d.Set("resource_type", dedicatedHostGroup.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } if dedicatedHostGroup.SupportedInstanceProfiles != nil { err = d.Set("supported_instance_profiles", dataSourceDedicatedHostGroupFlattenSupportedInstanceProfiles(dedicatedHostGroup.SupportedInstanceProfiles)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_profiles %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_profiles %s", err)) } } if dedicatedHostGroup.Zone != nil { err = d.Set("zone", *dedicatedHostGroup.Zone.Name) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting zone %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone %s", err)) } } return nil } } } - return diag.FromErr(fmt.Errorf("No Dedicated Host Group found with name %s", name)) + return diag.FromErr(fmt.Errorf("[ERROR] No Dedicated Host Group found with name %s", name)) } func dataSourceDedicatedHostGroupFlattenDedicatedHosts(result []vpcv1.DedicatedHostReference) (dedicatedHosts []map[string]interface{}) { diff --git a/ibm/data_source_ibm_is_dedicated_host_group_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_group_test.go similarity index 76% rename from ibm/data_source_ibm_is_dedicated_host_group_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_group_test.go index 8c7a1fe56..1330270cd 100644 --- a/ibm/data_source_ibm_is_dedicated_host_group_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,16 +17,16 @@ func TestAccIbmIsDedicatedHostGroupDataSourceBasic(t *testing.T) { name := fmt.Sprintf("tfdhgroup%d", acctest.RandIntRange(10, 100)) resName := "data.ibm_is_dedicated_host_group.dgroup" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostGroupDataSourceConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, name), + { + Config: testAccCheckIbmIsDedicatedHostGroupDataSourceConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resName, "name", name), - resource.TestCheckResourceAttr(resName, "class", dedicatedHostGroupClass), - resource.TestCheckResourceAttr(resName, "family", dedicatedHostGroupFamily), + resource.TestCheckResourceAttr(resName, "class", acc.DedicatedHostGroupClass), + resource.TestCheckResourceAttr(resName, "family", acc.DedicatedHostGroupFamily), resource.TestCheckResourceAttrSet(resName, "zone"), ), }, diff --git a/ibm/data_source_ibm_is_dedicated_host_groups.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_groups.go similarity index 90% rename from ibm/data_source_ibm_is_dedicated_host_groups.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_groups.go index 544c38d7e..414a0fb4d 100644 --- a/ibm/data_source_ibm_is_dedicated_host_groups.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_groups.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,56 +9,58 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { +func DataSourceIbmIsDedicatedHostGroups() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostGroupsRead, Schema: map[string]*schema.Schema{ - "host_groups": &schema.Schema{ + "host_groups": { Type: schema.TypeList, Computed: true, Description: "Collection of dedicated host groups.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "class": &schema.Schema{ + "class": { Type: schema.TypeString, Computed: true, Description: "The dedicated host profile class for hosts in this group.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the dedicated host group was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host group.", }, - "dedicated_hosts": &schema.Schema{ + "dedicated_hosts": { Type: schema.TypeList, Computed: true, Description: "The dedicated hosts that are in this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host.", }, - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -66,22 +68,22 @@ func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this dedicated host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", @@ -89,48 +91,48 @@ func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { }, }, }, - "family": &schema.Schema{ + "family": { Type: schema.TypeString, Computed: true, Description: "The dedicated host profile family for hosts in this group.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host group.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this dedicated host group.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "resource_group": &schema.Schema{ + "resource_group": { Type: schema.TypeString, Computed: true, Description: "The resource group for this dedicated host group.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -138,7 +140,7 @@ func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { }, }, }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeString, Computed: true, Description: "The globally unique name of the zone this dedicated host group resides in.", @@ -146,7 +148,7 @@ func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { }, }, }, - "total_count": &schema.Schema{ + "total_count": { Type: schema.TypeInt, Computed: true, Description: "The total number of resources across all pages.", @@ -156,7 +158,7 @@ func dataSourceIbmIsDedicatedHostGroups() *schema.Resource { } func dataSourceIbmIsDedicatedHostGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -173,7 +175,7 @@ func dataSourceIbmIsDedicatedHostGroupsRead(context context.Context, d *schema.R log.Printf("[DEBUG] ListDedicatedHostGroupsWithContext failed %s\n%s", err, response) return diag.FromErr(err) } - start = GetNext(listDedicatedHostGroupsOptions.Next) + start = flex.GetNext(listDedicatedHostGroupsOptions.Next) allrecs = append(allrecs, listDedicatedHostGroupsOptions.Groups...) if start == "" { break @@ -185,11 +187,11 @@ func dataSourceIbmIsDedicatedHostGroupsRead(context context.Context, d *schema.R d.SetId(dataSourceIbmIsDedicatedHostGroupsID(d)) err = d.Set("host_groups", dataSourceDedicatedHostGroupCollectionFlattenGroups(allrecs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting groups %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting groups %s", err)) } if err = d.Set("total_count", len(allrecs)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } } diff --git a/ibm/data_source_ibm_is_dedicated_host_groups_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_groups_test.go similarity index 77% rename from ibm/data_source_ibm_is_dedicated_host_groups_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_groups_test.go index daf26aece..5ed8cb72e 100644 --- a/ibm/data_source_ibm_is_dedicated_host_groups_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_groups_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,21 +19,21 @@ func TestAccIbmIsDedicatedHostGroupsDataSourceBasic(t *testing.T) { name := fmt.Sprintf("tfdhgroups%d", acctest.RandIntRange(10, 100)) resName := "data.ibm_is_dedicated_host_groups.dhgroups" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, name), + Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostGroupExists("ibm_is_dedicated_host_group.is_dedicated_host_group", conf), - resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "class", dedicatedHostGroupClass), - resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "family", dedicatedHostGroupFamily), + resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "class", acc.DedicatedHostGroupClass), + resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "family", acc.DedicatedHostGroupFamily), resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "name", name), ), }, { - Config: testAccCheckIbmIsDedicatedHostGroupsDataSourceConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, name), + Config: testAccCheckIbmIsDedicatedHostGroupsDataSourceConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, name), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "host_groups.0.name"), resource.TestCheckResourceAttrSet(resName, "host_groups.0.class"), diff --git a/ibm/data_source_ibm_is_dedicated_host_profile.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profile.go similarity index 88% rename from ibm/data_source_ibm_is_dedicated_host_profile.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_profile.go index 285c3f626..6adc3fade 100644 --- a/ibm/data_source_ibm_is_dedicated_host_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profile.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,44 +9,45 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { +func DataSourceIbmIsDedicatedHostProfile() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostProfileRead, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The globally unique name for this virtual server instance profile.", }, - "class": &schema.Schema{ + "class": { Type: schema.TypeString, Computed: true, Description: "The product class this dedicated host profile belongs to.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host profile's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeString, Computed: true, Description: "The interface of the disk for a dedicated host with this profileThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", @@ -54,18 +55,18 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "quantity": &schema.Schema{ + "quantity": { Type: schema.TypeList, Computed: true, Description: "The number of disks of this type for a dedicated host with this profile.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", @@ -73,18 +74,18 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "size": &schema.Schema{ + "size": { Type: schema.TypeList, Computed: true, Description: "The size of the disk in GB (gigabytes).", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", @@ -92,17 +93,17 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for a dedicated host with this profile.", @@ -116,52 +117,52 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "family": &schema.Schema{ + "family": { Type: schema.TypeString, Computed: true, Description: "The product family this dedicated host profile belongs toThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "memory": &schema.Schema{ + "memory": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -172,42 +173,42 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "socket_count": &schema.Schema{ + "socket_count": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -218,18 +219,18 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on dedicated hosts with this profile.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -237,17 +238,17 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "vcpu_architecture": &schema.Schema{ + "vcpu_architecture": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture for a dedicated host with this profile.", @@ -255,42 +256,42 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { }, }, }, - "vcpu_count": &schema.Schema{ + "vcpu_count": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -306,7 +307,7 @@ func dataSourceIbmIsDedicatedHostProfile() *schema.Resource { } func dataSourceIbmIsDedicatedHostProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -321,60 +322,60 @@ func dataSourceIbmIsDedicatedHostProfileRead(context context.Context, d *schema. return diag.FromErr(err) } if dedicatedHostProfile == nil { - return diag.FromErr(fmt.Errorf("No Dedicated Host Profile found with name %s", name)) + return diag.FromErr(fmt.Errorf("[ERROR] No Dedicated Host Profile found with name %s", name)) } d.SetId(dataSourceIbmIsDedicatedHostProfileID(d)) if err = d.Set("class", dedicatedHostProfile.Class); err != nil { - return diag.FromErr(fmt.Errorf("Error setting class: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting class: %s", err)) } if dedicatedHostProfile.Disks != nil { err = d.Set("disks", dataSourceDedicatedHostProfileFlattenDisks(dedicatedHostProfile.Disks)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting disks %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disks %s", err)) } } if err = d.Set("family", dedicatedHostProfile.Family); err != nil { - return diag.FromErr(fmt.Errorf("Error setting family: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting family: %s", err)) } if err = d.Set("href", dedicatedHostProfile.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if dedicatedHostProfile.Memory != nil { err = d.Set("memory", dataSourceDedicatedHostProfileFlattenMemory(*dedicatedHostProfile.Memory.(*vpcv1.DedicatedHostProfileMemory))) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting memory %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting memory %s", err)) } } if dedicatedHostProfile.SocketCount != nil { err = d.Set("socket_count", dataSourceDedicatedHostProfileFlattenSocketCount(*dedicatedHostProfile.SocketCount.(*vpcv1.DedicatedHostProfileSocket))) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting socket_count %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting socket_count %s", err)) } } if dedicatedHostProfile.SupportedInstanceProfiles != nil { err = d.Set("supported_instance_profiles", dataSourceDedicatedHostProfileFlattenSupportedInstanceProfiles(dedicatedHostProfile.SupportedInstanceProfiles)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_profiles %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_profiles %s", err)) } } if dedicatedHostProfile.VcpuArchitecture != nil { err = d.Set("vcpu_architecture", dataSourceDedicatedHostProfileFlattenVcpuArchitecture(*dedicatedHostProfile.VcpuArchitecture)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting vcpu_architecture %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vcpu_architecture %s", err)) } } if dedicatedHostProfile.VcpuCount != nil { err = d.Set("vcpu_count", dataSourceDedicatedHostProfileFlattenVcpuCount(*dedicatedHostProfile.VcpuCount.(*vpcv1.DedicatedHostProfileVcpu))) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting vcpu_count %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vcpu_count %s", err)) } } diff --git a/ibm/service/vpc/data_source_ibm_is_dedicated_host_profile_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profile_test.go new file mode 100644 index 000000000..2fbcd0a58 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profile_test.go @@ -0,0 +1,41 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmIsDedicatedHostProfileDataSourceBasic(t *testing.T) { + + resName := "data.ibm_is_dedicated_host_profile.dhprofile" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsDedicatedHostProfileDataSourceConfigBasic(acc.DedicatedHostProfileName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", acc.DedicatedHostProfileName), + resource.TestCheckResourceAttrSet(resName, "class"), + resource.TestCheckResourceAttrSet(resName, "family"), + ), + }, + }, + }) +} + +func testAccCheckIbmIsDedicatedHostProfileDataSourceConfigBasic(profile string) string { + return fmt.Sprintf(` + + data "ibm_is_dedicated_host_profile" "dhprofile" { + name = "%s" + } + `, profile) +} diff --git a/ibm/data_source_ibm_is_dedicated_host_profiles.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles.go similarity index 91% rename from ibm/data_source_ibm_is_dedicated_host_profiles.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles.go index ab70cdb96..fee8a8783 100644 --- a/ibm/data_source_ibm_is_dedicated_host_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,45 +9,47 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { +func DataSourceIbmIsDedicatedHostProfiles() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostProfilesRead, Schema: map[string]*schema.Schema{ - "profiles": &schema.Schema{ + "profiles": { Type: schema.TypeList, Computed: true, Description: "Collection of dedicated host profiles.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "class": &schema.Schema{ + "class": { Type: schema.TypeString, Computed: true, Description: "The product class this dedicated host profile belongs to.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host profile's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeString, Computed: true, Description: "The interface of the disk for a dedicated host with this profileThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", @@ -55,18 +57,18 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "quantity": &schema.Schema{ + "quantity": { Type: schema.TypeList, Computed: true, Description: "The number of disks of this type for a dedicated host with this profile.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", @@ -74,18 +76,18 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "size": &schema.Schema{ + "size": { Type: schema.TypeList, Computed: true, Description: "The size of the disk in GB (gigabytes).", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", @@ -93,17 +95,17 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for a dedicated host with this profile.", @@ -117,52 +119,52 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "family": &schema.Schema{ + "family": { Type: schema.TypeString, Computed: true, Description: "The product family this dedicated host profile belongs toThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "memory": &schema.Schema{ + "memory": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -173,47 +175,47 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this dedicated host profile.", }, - "socket_count": &schema.Schema{ + "socket_count": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -224,18 +226,18 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on dedicated hosts with this profile.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -243,18 +245,18 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "vcpu_architecture": &schema.Schema{ + "vcpu_architecture": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture for a dedicated host with this profile.", @@ -262,43 +264,43 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "vcpu_count": &schema.Schema{ + "vcpu_count": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "type": &schema.Schema{ + "type": { Type: schema.TypeString, Computed: true, Description: "The type for this profile field.", }, - "value": &schema.Schema{ + "value": { Type: schema.TypeInt, Computed: true, Description: "The value for this profile field.", }, - "default": &schema.Schema{ + "default": { Type: schema.TypeInt, Computed: true, Description: "The default value for this profile field.", }, - "max": &schema.Schema{ + "max": { Type: schema.TypeInt, Computed: true, Description: "The maximum value for this profile field.", }, - "min": &schema.Schema{ + "min": { Type: schema.TypeInt, Computed: true, Description: "The minimum value for this profile field.", }, - "step": &schema.Schema{ + "step": { Type: schema.TypeInt, Computed: true, Description: "The increment step value for this profile field.", }, - "values": &schema.Schema{ + "values": { Type: schema.TypeList, Computed: true, Description: "The permitted values for this profile field.", @@ -312,7 +314,7 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { }, }, }, - "total_count": &schema.Schema{ + "total_count": { Type: schema.TypeInt, Computed: true, Description: "The total number of resources across all pages.", @@ -322,7 +324,7 @@ func dataSourceIbmIsDedicatedHostProfiles() *schema.Resource { } func dataSourceIbmIsDedicatedHostProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -340,7 +342,7 @@ func dataSourceIbmIsDedicatedHostProfilesRead(context context.Context, d *schema log.Printf("[DEBUG] ListDedicatedHostProfilesWithContext failed %s\n%s", err, response) return diag.FromErr(err) } - start = GetNext(dedicatedHostProfileCollection.Next) + start = flex.GetNext(dedicatedHostProfileCollection.Next) allrecs = append(allrecs, dedicatedHostProfileCollection.Profiles...) if start == "" { break @@ -353,11 +355,11 @@ func dataSourceIbmIsDedicatedHostProfilesRead(context context.Context, d *schema err = d.Set("profiles", dataSourceDedicatedHostProfileCollectionFlattenProfiles(allrecs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting profiles %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profiles %s", err)) } if err = d.Set("total_count", len(allrecs)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } } return nil diff --git a/ibm/data_source_ibm_is_dedicated_host_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles_test.go similarity index 84% rename from ibm/data_source_ibm_is_dedicated_host_profiles_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles_test.go index 33498a546..671152293 100644 --- a/ibm/data_source_ibm_is_dedicated_host_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_profiles_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ func TestAccIbmIsDedicatedHostProfilesDataSourceBasic(t *testing.T) { resName := "data.ibm_is_dedicated_host_profiles.dhprofiles" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIsDedicatedHostProfilesDataSourceConfigBasic(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), diff --git a/ibm/data_source_ibm_is_dedicated_host_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_host_test.go similarity index 84% rename from ibm/data_source_ibm_is_dedicated_host_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_host_test.go index 35e38ae44..c77c1e6b5 100644 --- a/ibm/data_source_ibm_is_dedicated_host_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_host_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,12 +19,12 @@ func TestAccIbmIsDedicatedHostDSBasic(t *testing.T) { grpname := fmt.Sprintf("tf-dhostgroup%d", acctest.RandIntRange(10, 100)) dhname := fmt.Sprintf("tf-dhost%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostDSConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, grpname, dedicatedHostProfileName, dhname), + { + Config: testAccCheckIbmIsDedicatedHostDSConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, grpname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "name"), resource.TestCheckResourceAttrSet(resName, "zone"), diff --git a/ibm/data_source_ibm_is_dedicated_hosts.go b/ibm/service/vpc/data_source_ibm_is_dedicated_hosts.go similarity index 90% rename from ibm/data_source_ibm_is_dedicated_hosts.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_hosts.go index 2280c52fb..5c34e96b9 100644 --- a/ibm/data_source_ibm_is_dedicated_hosts.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_hosts.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,45 +9,47 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsDedicatedHosts() *schema.Resource { +func DataSourceIbmIsDedicatedHosts() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsDedicatedHostsRead, Schema: map[string]*schema.Schema{ - "host_group": &schema.Schema{ + "host_group": { Type: schema.TypeString, Optional: true, Description: "The unique identifier of the dedicated host group this dedicated host belongs to", }, - "dedicated_hosts": &schema.Schema{ + "dedicated_hosts": { Type: schema.TypeList, Computed: true, Description: "Collection of dedicated hosts.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "available_memory": &schema.Schema{ + "available_memory": { Type: schema.TypeInt, Computed: true, Description: "The amount of memory in gibibytes that is currently available for instances.", }, - "available_vcpu": &schema.Schema{ + "available_vcpu": { Type: schema.TypeList, Computed: true, Description: "The available VCPU for the dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "architecture": &schema.Schema{ + "architecture": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture.", }, - "count": &schema.Schema{ + "count": { Type: schema.TypeInt, Computed: true, Description: "The number of VCPUs assigned.", @@ -55,55 +57,55 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the dedicated host was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "available": &schema.Schema{ + "available": { Type: schema.TypeInt, Computed: true, Description: "The remaining space left for instance placement in GB (gigabytes).", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this disk.", }, - "instance_disks": &schema.Schema{ + "instance_disks": { Type: schema.TypeList, Computed: true, Description: "Instance disks that are on this dedicated host disk.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -111,22 +113,22 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", @@ -134,37 +136,37 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of this dedicated host disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined or system-provided name for this disk.", }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host disk is available for instance disk creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for this dedicated host disk.", @@ -175,44 +177,44 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "host_group": &schema.Schema{ + "host_group": { Type: schema.TypeString, Computed: true, Description: "The unique identifier of the dedicated host group this dedicated host is in.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this dedicated host.", }, - "instance_placement_enabled": &schema.Schema{ + "instance_placement_enabled": { Type: schema.TypeBool, Computed: true, Description: "If set to true, instances can be placed on this dedicated host.", }, - "instances": &schema.Schema{ + "instances": { Type: schema.TypeList, Computed: true, Description: "Array of instances that are allocated to this dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this virtual server instance.", }, - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -220,17 +222,17 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this virtual server instance.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this virtual server instance (and default system hostname).", @@ -238,33 +240,33 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of the dedicated host resource.", }, - "memory": &schema.Schema{ + "memory": { Type: schema.TypeInt, Computed: true, Description: "The total amount of memory in gibibytes for this host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "profile": &schema.Schema{ + "profile": { Type: schema.TypeList, Computed: true, Description: "The profile this dedicated host uses.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this dedicated host profile.", @@ -272,43 +274,43 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host is available for instance creation.", }, - "resource_group": &schema.Schema{ + "resource_group": { Type: schema.TypeString, Computed: true, Description: "The unique identifier of the resource group for this dedicated host.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "socket_count": &schema.Schema{ + "socket_count": { Type: schema.TypeInt, Computed: true, Description: "The total number of sockets for this host.", }, - "state": &schema.Schema{ + "state": { Type: schema.TypeString, Computed: true, Description: "The administrative state of the dedicated host.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the dedicated host on which the unexpected property value was encountered.", }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on this dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -316,18 +318,18 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "vcpu": &schema.Schema{ + "vcpu": { Type: schema.TypeList, Computed: true, Description: "The total VCPU of the dedicated host.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "architecture": &schema.Schema{ + "architecture": { Type: schema.TypeString, Computed: true, Description: "The VCPU architecture.", }, - "count": &schema.Schema{ + "count": { Type: schema.TypeInt, Computed: true, Description: "The number of VCPUs assigned.", @@ -335,7 +337,7 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeString, Computed: true, Description: "The globally unique name of the zone this dedicated host resides in.", @@ -343,7 +345,7 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { }, }, }, - "total_count": &schema.Schema{ + "total_count": { Type: schema.TypeInt, Computed: true, Description: "The total number of resources across all pages.", @@ -353,7 +355,7 @@ func dataSourceIbmIsDedicatedHosts() *schema.Resource { } func dataSourceIbmIsDedicatedHostsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -374,7 +376,7 @@ func dataSourceIbmIsDedicatedHostsRead(context context.Context, d *schema.Resour log.Printf("[DEBUG] ListDedicatedHostsWithContext failed %s\n%s", err, response) return diag.FromErr(err) } - start = GetNext(dedicatedHostCollection.Next) + start = flex.GetNext(dedicatedHostCollection.Next) allrecs = append(allrecs, dedicatedHostCollection.DedicatedHosts...) if start == "" { break @@ -387,11 +389,11 @@ func dataSourceIbmIsDedicatedHostsRead(context context.Context, d *schema.Resour err = d.Set("dedicated_hosts", dataSourceDedicatedHostCollectionFlattenDedicatedHosts(allrecs)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting dedicated_hosts %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting dedicated_hosts %s", err)) } if err = d.Set("total_count", len(allrecs)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } } return nil diff --git a/ibm/data_source_ibm_is_dedicated_hosts_test.go b/ibm/service/vpc/data_source_ibm_is_dedicated_hosts_test.go similarity index 77% rename from ibm/data_source_ibm_is_dedicated_hosts_test.go rename to ibm/service/vpc/data_source_ibm_is_dedicated_hosts_test.go index d36aaeba7..cc18c8a41 100644 --- a/ibm/data_source_ibm_is_dedicated_hosts_test.go +++ b/ibm/service/vpc/data_source_ibm_is_dedicated_hosts_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,12 +22,12 @@ func TestAccIbmIsDedicatedHostsDSBasic(t *testing.T) { dhresName := "ibm_is_dedicated_host.dhost" resName := "data.ibm_is_dedicated_hosts.dhosts" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIbmIsDedicatedHostConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + Config: testAccCheckIbmIsDedicatedHostConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeTestCheckFunc( testAccCheckIbmIsDedicatedHostExists(dhresName, conf), resource.TestCheckResourceAttr( @@ -33,7 +35,7 @@ func TestAccIbmIsDedicatedHostsDSBasic(t *testing.T) { ), }, { - Config: testAccCheckIbmIsDedicatedHostsDSConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + Config: testAccCheckIbmIsDedicatedHostsDSConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "dedicated_hosts.0.name"), resource.TestCheckResourceAttrSet(resName, "dedicated_hosts.0.available_memory"), diff --git a/ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets.go b/ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets.go new file mode 100644 index 000000000..ca8be7918 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets.go @@ -0,0 +1,197 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "net/url" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/bluemix-go/api/globalsearch/globalsearchv2" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/platform-services-go-sdk/catalogmanagementv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isVPEResources = "resources" + isVPEResourceCRN = "crn" + isVPEResourceParent = "parent" + isVPEResourceName = "name" + isVPEResourceEndpointType = "endpoint_type" + isVPEResourceType = "resource_type" + isVPEResourceFullQualifiedDomainNames = "full_qualified_domain_names" + isVPEResourceServiceLocation = "location" +) + +func DataSourceIBMISEndpointGatewayTargets() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISEndpointGatewayTargetsRead, + + Schema: map[string]*schema.Schema{ + isVPEResources: { + Type: schema.TypeList, + Computed: true, + Description: "List of resources", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVPEResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "CRN for this specific object", + }, + isVPEResourceParent: { + Type: schema.TypeString, + Computed: true, + Description: "Parent for this specific object", + }, + isVPEResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "Display name in the requested language", + }, + isVPEResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Resource type of this offering.", + }, + isVPEResourceEndpointType: { + Type: schema.TypeString, + Computed: true, + Description: "Data endpoint type of this offering", + }, + isVPEResourceFullQualifiedDomainNames: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Fully qualified domain names", + }, + isVPEResourceServiceLocation: { + Type: schema.TypeString, + Computed: true, + Description: "Service location of this offering", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISEndpointGatewayTargetsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bmxSess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return diag.FromErr(err) + } + region := bmxSess.Config.Region + catalogManagementClient, err := meta.(conns.ClientSession).CatalogManagementV1() + if err != nil { + return diag.FromErr(err) + } + resourceInfo := make([]map[string]interface{}, 0) + getCatalogOptions := &catalogmanagementv1.SearchObjectsOptions{} + // query := "kind%3Avpe+AND+svc+AND+parent_id%3Aus-south" + query := fmt.Sprintf("kind:vpe AND svc AND parent_id:%s", region) + getCatalogOptions.Query = &query + digest := false + getCatalogOptions.Digest = &digest + + start := int64(0) + catalog := []catalogmanagementv1.CatalogObject{} + for { + if start != int64(0) { + getCatalogOptions.Offset = &start + } + search, response, err := catalogManagementClient.SearchObjectsWithContext(context, getCatalogOptions) + if err != nil { + log.Printf("[DEBUG] GetCatalogWithContext failed %s\n%s", err, response) + return diag.FromErr(err) + } + next := search.Next + if next == nil { + start = int64(0) + } else { + u, _ := url.Parse(fmt.Sprintf("%s", *next)) + q := u.Query() + start, _ = strconv.ParseInt(q.Get("offset"), 10, 64) + } + catalog = append(catalog, search.Resources...) + if start == int64(0) { + break + } + } + if catalog != nil { + for _, res := range catalog { + l := map[string]interface{}{} + if res.ParentID != nil { + l[isVPEResourceParent] = *res.ParentID + } + l[isVPEResourceType] = "provider_cloud_service" + if res.Label != nil { + l[isVPEResourceName] = *res.Label + } + sl := "" + data := res.Data + if data != nil { + if serviceCrn, ok := data["service_crn"].(string); ok { + if serviceCrn != "" { + l[isVPEResourceCRN] = serviceCrn + crnFs := strings.Split(serviceCrn, ":") + if len(crnFs) > 5 { + sl = crnFs[5] + } + l[isVPEResourceServiceLocation] = sl + } + } + if data["endpoint_type"] != nil { + l[isVPEResourceEndpointType] = data["endpoint_type"] + } + if data["fully_qualified_domain_names"] != nil { + l[isVPEResourceFullQualifiedDomainNames] = data["fully_qualified_domain_names"] + } + } + resourceInfo = append(resourceInfo, l) + } + staticService := map[string]interface{}{} + staticService[isVPEResourceName] = "ibm-ntp-server" + staticService[isVPEResourceType] = "provider_infrastructure_service" + resourceInfo = append(resourceInfo, staticService) + } + queryString := "doc.extensions.virtual_private_endpoints.endpoints.ip_address:*" + fields := []string{"name", "region", "family", "type", "crn", "tags", "organization_guid", "doc.extensions", "doc.resource_group_id", "doc.space_guid", "resource_id"} + getSearchOptions := globalsearchv2.SearchBody{ + Query: queryString, + Fields: fields, + } + globalSearchClient, err := meta.(conns.ClientSession).GlobalSearchAPI() + if err != nil { + return diag.FromErr(err) + } + searchResult, err := globalSearchClient.Searches().PostQuery(getSearchOptions) + if err != nil { + log.Printf("[DEBUG] PostQuery on globalSearchApi for query string %s failed %s", queryString, err) + return diag.FromErr(err) + } + searchItems := searchResult.Items + for _, item := range searchItems { + info := map[string]interface{}{} + info[isVPEResourceName] = item.Name + info[isVPEResourceType] = item.Type + info[isVPEResourceCRN] = item.CRN + resourceInfo = append(resourceInfo, info) + + } + + d.Set(isVPEResources, resourceInfo) + d.SetId(dataSourceIBMISEndpointGatewayTargetsId(d)) + return nil +} +func dataSourceIBMISEndpointGatewayTargetsId(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_is_endpoint_gateway_targets_test.go b/ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets_test.go similarity index 83% rename from ibm/data_source_ibm_is_endpoint_gateway_targets_test.go rename to ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets_test.go index 5ec769627..28e9a3b0b 100644 --- a/ibm/data_source_ibm_is_endpoint_gateway_targets_test.go +++ b/ibm/service/vpc/data_source_ibm_is_endpoint_gateway_targets_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISEndpointGatewayTargetsDataSource_basics(t *testing.T) { resName := "data.ibm_is_endpoint_gateway_targets.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISEgtsDataSourceConfig(), diff --git a/ibm/service/vpc/data_source_ibm_is_floating_ip.go b/ibm/service/vpc/data_source_ibm_is_floating_ip.go new file mode 100644 index 000000000..fe9f568ed --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_floating_ip.go @@ -0,0 +1,383 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + floatingIPName = "name" + floatingIPAddress = "address" + floatingIPStatus = "status" + floatingIPZone = "zone" + floatingIPTarget = "target" + floatingIPTargets = "target_list" + floatingIPTargetsHref = "href" + floatingIPTargetsCrn = "crn" + floatingIPTargetsDeleted = "deleted" + floatingIPTargetsMoreInfo = "more_info" + floatingIPTargetsId = "id" + floatingIPTargetsName = "name" + floatingIPTargetsResourceType = "resource_type" + floatingIPTags = "tags" + floatingIPCRN = "crn" + floatingIpPrimaryIP = "primary_ip" + floatingIpPrimaryIpAddress = "address" + floatingIpPrimaryIpHref = "href" + floatingIpPrimaryIpName = "name" + floatingIpPrimaryIpId = "reserved_ip" + floatingIpPrimaryIpResourceType = "resource_type" +) + +func DataSourceIBMISFloatingIP() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISFloatingIPRead, + + Schema: map[string]*schema.Schema{ + + floatingIPName: { + Type: schema.TypeString, + Required: true, + Description: "Name of the floating IP", + }, + + floatingIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP address", + }, + + floatingIPStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP status", + }, + + floatingIPZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + floatingIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Target info", + }, + + floatingIPTargets: { + Type: schema.TypeList, + Computed: true, + Description: "The target of this floating IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIPTargetsDeleted: { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIPTargetsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + floatingIPTargetsHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + floatingIPTargetsId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + floatingIPTargetsName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + floatingIpPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIpPrimaryIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + floatingIpPrimaryIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + floatingIpPrimaryIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + floatingIpPrimaryIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + floatingIpPrimaryIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + floatingIPTargetsResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + floatingIPTargetsCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this public gateway.", + }, + }, + }, + }, + + floatingIPCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP crn", + }, + + floatingIPTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Floating IP tags", + }, + }, + } +} + +func dataSourceIBMISFloatingIPRead(d *schema.ResourceData, meta interface{}) error { + floatingIPName := d.Get(isFloatingIPName).(string) + err := floatingIPGet(d, meta, floatingIPName) + if err != nil { + return err + } + return nil +} + +func floatingIPGet(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + start := "" + allFloatingIPs := []vpcv1.FloatingIP{} + for { + floatingIPOptions := &vpcv1.ListFloatingIpsOptions{} + if start != "" { + floatingIPOptions.Start = &start + } + floatingIPs, response, err := sess.ListFloatingIps(floatingIPOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching floating IPs %s\n%s", err, response) + } + start = flex.GetNext(floatingIPs.Next) + allFloatingIPs = append(allFloatingIPs, floatingIPs.FloatingIps...) + if start == "" { + break + } + } + + for _, ip := range allFloatingIPs { + if *ip.Name == name { + + d.Set(floatingIPName, *ip.Name) + d.Set(floatingIPAddress, *ip.Address) + d.Set(floatingIPStatus, *ip.Status) + d.Set(floatingIPZone, *ip.Zone.Name) + + d.Set(floatingIPCRN, *ip.CRN) + if ip.Target != nil { + targetId, targetMap := dataSourceFloatingIPCollectionFloatingIpTargetToMap(ip.Target) + d.Set(floatingIPTarget, targetId) + targetList := []map[string]interface{}{} + targetList = append(targetList, targetMap) + d.Set(floatingIPTargets, targetList) + } + tags, err := flex.GetTagsUsingCRN(meta, *ip.CRN) + if err != nil { + fmt.Printf("[ERROR] Error on get of vpc Floating IP (%s) tags: %s", *ip.Address, err) + } + + d.Set(floatingIPTags, tags) + d.SetId(*ip.ID) + + return nil + } + } + + return fmt.Errorf("[ERROR] No floatingIP found with name %s", name) + +} + +func dataSourceFloatingIPCollectionFloatingIpTargetToMap(targetItemIntf vpcv1.FloatingIPTargetIntf) (targetId string, targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + targetId = "" + switch reflect.TypeOf(targetItemIntf).String() { + case "*vpcv1.FloatingIPTargetNetworkInterfaceReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetNetworkInterfaceReference) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + } + case "*vpcv1.FloatingIPTargetPublicGatewayReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetPublicGatewayReference) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPTargetPgDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap[floatingIPTargetsCrn] = targetItem.CRN + } + } + case "*vpcv1.FloatingIPTarget": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTarget) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.PrimaryIP != nil && targetItem.PrimaryIP.Address != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap[floatingIPTargetsCrn] = targetItem.CRN + } + } + } + + return targetId, targetMap +} + +func dataSourceFloatingIPTargetNicDeletedToMap(deletedItem vpcv1.NetworkInterfaceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[floatingIPTargetsMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} +func dataSourceFloatingIPTargetPgDeletedToMap(deletedItem vpcv1.PublicGatewayReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[floatingIPTargetsMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/data_source_ibm_is_floating_ip_test.go b/ibm/service/vpc/data_source_ibm_is_floating_ip_test.go similarity index 75% rename from ibm/data_source_ibm_is_floating_ip_test.go rename to ibm/service/vpc/data_source_ibm_is_floating_ip_test.go index a412a5614..03f372045 100644 --- a/ibm/data_source_ibm_is_floating_ip_test.go +++ b/ibm/service/vpc/data_source_ibm_is_floating_ip_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,14 +27,19 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE sshname := fmt.Sprintf("tfip-sshname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISFloatingIPDataSourceConfig(vpcname, subnetname, sshname, publicKey, instancename, fipname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resName, "name", fipname), - resource.TestCheckResourceAttr(resName, "zone", ISZoneName), + resource.TestCheckResourceAttr(resName, "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet(resName, "target_list.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "target_list.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "target_list.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "target_list.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "target_list.0.primary_ip.0.resource_type"), ), }, }, @@ -64,7 +71,6 @@ func testAccCheckIBMISFloatingIPDataSourceConfig(vpcname, subnetname, sshname, p image = "%s" profile = "%s" primary_network_interface { - port_speed = "100" subnet = ibm_is_subnet.testacc_subnet.id } vpc = ibm_is_vpc.testacc_vpc.id @@ -80,5 +86,5 @@ func testAccCheckIBMISFloatingIPDataSourceConfig(vpcname, subnetname, sshname, p data "ibm_is_floating_ip" "test" { name = ibm_is_floating_ip.testacc_floatingip.name } - `, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, instancename, isImage, instanceProfileName, ISZoneName, fipname) + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, instancename, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, fipname) } diff --git a/ibm/service/vpc/data_source_ibm_is_floating_ips.go b/ibm/service/vpc/data_source_ibm_is_floating_ips.go new file mode 100644 index 000000000..c26c5af8c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_floating_ips.go @@ -0,0 +1,530 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsFloatingIps() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsFloatingIpsRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The unique user-defined name for this floating IP.", + }, + "floating_ips": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of floating IPs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the floating IP was created.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this floating IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this floating IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the floating IP.", + }, + "target": { + Type: schema.TypeList, + Computed: true, + Description: "The target of this floating IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + "primary_ipv4_address": { + Type: schema.TypeString, + Computed: true, + Description: "The primary IPv4 address.If the address has not yet been selected, the value will be `0.0.0.0`.", + }, + floatingIpPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIpPrimaryIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + floatingIpPrimaryIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + floatingIpPrimaryIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + floatingIpPrimaryIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + floatingIpPrimaryIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this public gateway.", + }, + }, + }, + }, + "zone": { + Type: schema.TypeList, + Computed: true, + Description: "The zone this floating IP resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsFloatingIpsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + start := "" + allFloatingIPs := []vpcv1.FloatingIP{} + for { + floatingIPOptions := &vpcv1.ListFloatingIpsOptions{} + if start != "" { + floatingIPOptions.Start = &start + } + floatingIPs, response, err := sess.ListFloatingIps(floatingIPOptions) + if err != nil { + log.Printf("[DEBUG] Error Fetching floating IPs %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Fetching floating IPs %s\n%s", err, response)) + } + start = flex.GetNext(floatingIPs.Next) + allFloatingIPs = append(allFloatingIPs, floatingIPs.FloatingIps...) + if start == "" { + break + } + } + var matchFloatingIps []vpcv1.FloatingIP + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range allFloatingIPs { + if *data.Name == name { + matchFloatingIps = append(matchFloatingIps, data) + } + } + } else { + matchFloatingIps = allFloatingIPs + } + if suppliedFilter { + if len(matchFloatingIps) == 0 { + return diag.FromErr(fmt.Errorf("no FloatingIps found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(dataSourceIBMIsFloatingIpsID(d)) + } + + if matchFloatingIps != nil { + err = d.Set("floating_ips", dataSourceFloatingIPCollectionFlattenFloatingIps(matchFloatingIps)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting floating_ips %s", err)) + } + } + return nil +} + +// dataSourceIBMIsFloatingIpsID returns a reasonable ID for the list. +func dataSourceIBMIsFloatingIpsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceFloatingIPCollectionFlattenFirst(result vpcv1.FloatingIPCollectionFirst) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFloatingIPCollectionFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFloatingIPCollectionFirstToMap(firstItem vpcv1.FloatingIPCollectionFirst) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceFloatingIPCollectionFlattenFloatingIps(result []vpcv1.FloatingIP) (floatingIps []map[string]interface{}) { + for _, floatingIpsItem := range result { + floatingIps = append(floatingIps, dataSourceFloatingIPCollectionFloatingIpsToMap(floatingIpsItem)) + } + + return floatingIps +} + +func dataSourceFloatingIPCollectionFloatingIpsToMap(floatingIpsItem vpcv1.FloatingIP) (floatingIpsMap map[string]interface{}) { + floatingIpsMap = map[string]interface{}{} + + if floatingIpsItem.Address != nil { + floatingIpsMap["address"] = floatingIpsItem.Address + } + if floatingIpsItem.CreatedAt != nil { + floatingIpsMap["created_at"] = floatingIpsItem.CreatedAt.String() + } + if floatingIpsItem.CRN != nil { + floatingIpsMap["crn"] = floatingIpsItem.CRN + } + if floatingIpsItem.Href != nil { + floatingIpsMap["href"] = floatingIpsItem.Href + } + if floatingIpsItem.ID != nil { + floatingIpsMap["id"] = floatingIpsItem.ID + } + if floatingIpsItem.Name != nil { + floatingIpsMap["name"] = floatingIpsItem.Name + } + if floatingIpsItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceFloatingIPCollectionFloatingIpsResourceGroupToMap(*floatingIpsItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + floatingIpsMap["resource_group"] = resourceGroupList + } + if floatingIpsItem.Status != nil { + floatingIpsMap["status"] = floatingIpsItem.Status + } + if floatingIpsItem.Target != nil { + targetList := []map[string]interface{}{} + targetMap := dataSourceFloatingIPCollectionFloatingIpsTargetToMap(floatingIpsItem.Target) + targetList = append(targetList, targetMap) + floatingIpsMap["target"] = targetList + } + if floatingIpsItem.Zone != nil { + zoneList := []map[string]interface{}{} + zoneMap := dataSourceFloatingIPCollectionFloatingIpsZoneToMap(*floatingIpsItem.Zone) + zoneList = append(zoneList, zoneMap) + floatingIpsMap["zone"] = zoneList + } + + return floatingIpsMap +} + +func dataSourceFloatingIPCollectionFloatingIpsResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceFloatingIPCollectionFloatingIpsTargetToMap(targetItemIntf vpcv1.FloatingIPTargetIntf) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + switch reflect.TypeOf(targetItemIntf).String() { + case "*vpcv1.FloatingIPTargetNetworkInterfaceReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetNetworkInterfaceReference) + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPCollectionTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + targetMap["primary_ipv4_address"] = *targetItem.PrimaryIP.Address + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap["resource_type"] = targetItem.ResourceType + } + } + case "*vpcv1.FloatingIPTargetPublicGatewayReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetPublicGatewayReference) + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPCollectionTargetPgDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.ResourceType != nil { + targetMap["resource_type"] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap["crn"] = targetItem.CRN + } + } + case "*vpcv1.FloatingIPTarget": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTarget) + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFloatingIPCollectionTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.PrimaryIP != nil && targetItem.PrimaryIP.Address != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + targetMap["primary_ipv4_address"] = *targetItem.PrimaryIP.Address + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap["resource_type"] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap["crn"] = targetItem.CRN + } + } + } + + return targetMap +} + +func dataSourceFloatingIPCollectionTargetNicDeletedToMap(deletedItem vpcv1.NetworkInterfaceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} +func dataSourceFloatingIPCollectionTargetPgDeletedToMap(deletedItem vpcv1.PublicGatewayReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceFloatingIPCollectionFloatingIpsZoneToMap(zoneItem vpcv1.ZoneReference) (zoneMap map[string]interface{}) { + zoneMap = map[string]interface{}{} + + if zoneItem.Href != nil { + zoneMap["href"] = zoneItem.Href + } + if zoneItem.Name != nil { + zoneMap["name"] = zoneItem.Name + } + + return zoneMap +} + +func dataSourceFloatingIPCollectionFlattenNext(result vpcv1.FloatingIPCollectionNext) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFloatingIPCollectionNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFloatingIPCollectionNextToMap(nextItem vpcv1.FloatingIPCollectionNext) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_floating_ips_test.go b/ibm/service/vpc/data_source_ibm_is_floating_ips_test.go new file mode 100644 index 000000000..c6be00862 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_floating_ips_test.go @@ -0,0 +1,90 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsFloatingIpsDataSourceBasic(t *testing.T) { + + vpcname := fmt.Sprintf("tfip-vpc-%d", acctest.RandIntRange(10, 100)) + fipname := fmt.Sprintf("tfip-%d", acctest.RandIntRange(10, 100)) + instancename := fmt.Sprintf("tfip-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tfip-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsFloatingIpsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, instancename, fipname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.0.target.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.0.target.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.0.target.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.0.target.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_floating_ips.is_floating_ips", "floating_ips.0.target.0.primary_ip.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsFloatingIpsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, instancename, fipname string) string { + // status filter defaults to empty + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + port_speed = "100" + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + resource "ibm_is_floating_ip" "testacc_floatingip" { + name = "%s" + target = ibm_is_instance.testacc_instance.primary_network_interface[0].id + } + + data "ibm_is_floating_ips" "is_floating_ips" { + name = ibm_is_floating_ip.testacc_floatingip.name + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, instancename, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, fipname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_flow_log.go b/ibm/service/vpc/data_source_ibm_is_flow_log.go new file mode 100644 index 000000000..5cec87c65 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_flow_log.go @@ -0,0 +1,429 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsFlowLog() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsFlowLogRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"identifier", "name"}, + Description: "The unique user-defined name for this flow log collector.", + }, + + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"identifier", "name"}, + Description: "The flow log collector identifier.", + }, + "active": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this collector is active.", + }, + "auto_delete": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, this flow log collector will be automatically deleted when the target is deleted.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the flow log collector was created.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this flow log collector.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this flow log collector.", + }, + "lifecycle_state": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the flow log collector.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this flow log collector.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "storage_bucket": { + Type: schema.TypeList, + Computed: true, + Description: "The Cloud Object Storage bucket where the collected flows are logged.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name of this COS bucket.", + }, + }, + }, + }, + "target": { + Type: schema.TypeList, + Computed: true, + Description: "The target this collector is collecting flow logs for. If the target is an instance,subnet, or VPC, flow logs will not be collected for any network interfaces within thetarget that are themselves the target of a more specific flow log collector.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual server instance.", + }, + }, + }, + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "The VPC this flow log collector is associated with.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsFlowLogRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + name := d.Get("name").(string) + identifier := d.Get("identifier").(string) + var flowLogCollector *vpcv1.FlowLogCollector + + if name != "" { + + listOptions := &vpcv1.ListFlowLogCollectorsOptions{ + Name: &name, + } + + flowlogCollectors, response, err := sess.ListFlowLogCollectors(listOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("Error Fetching Flow Logs for VPC %s\n%s", err, response)) + } + + allrecs := flowlogCollectors.FlowLogCollectors + + if len(allrecs) == 0 { + return diag.FromErr(fmt.Errorf("[ERROR] No flow log collector found with name (%s)", name)) + } + flc := allrecs[0] + flowLogCollector = &flc + + } else if identifier != "" { + getFlowLogCollectorOptions := &vpcv1.GetFlowLogCollectorOptions{} + + getFlowLogCollectorOptions.SetID(d.Get("identifier").(string)) + + flowlogCollector, response, err := sess.GetFlowLogCollectorWithContext(context, getFlowLogCollectorOptions) + if err != nil { + log.Printf("[DEBUG] GetFlowLogCollectorWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetFlowLogCollectorWithContext failed %s\n%s", err, response)) + } + flowLogCollector = flowlogCollector + } + + d.SetId(*flowLogCollector.ID) + if err = d.Set("active", flowLogCollector.Active); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting active: %s", err)) + } + if err = d.Set("auto_delete", flowLogCollector.AutoDelete); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting auto_delete: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(flowLogCollector.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", flowLogCollector.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("href", flowLogCollector.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", flowLogCollector.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", flowLogCollector.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("identifier", *flowLogCollector.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting identifier: %s", err)) + } + + if flowLogCollector.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceFlowLogCollectorFlattenResourceGroup(*flowLogCollector.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) + } + } + + if flowLogCollector.StorageBucket != nil { + err = d.Set("storage_bucket", dataSourceFlowLogCollectorFlattenStorageBucket(*flowLogCollector.StorageBucket)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting storage_bucket %s", err)) + } + } + + if flowLogCollector.Target != nil { + targetIntf := flowLogCollector.Target + target := targetIntf.(*vpcv1.FlowLogCollectorTarget) + err = d.Set("target", dataSourceFlowLogCollectorFlattenTarget(*target)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting target %s", err)) + } + } + + if flowLogCollector.VPC != nil { + err = d.Set("vpc", dataSourceFlowLogCollectorFlattenVPC(*flowLogCollector.VPC)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpc %s", err)) + } + } + + return nil +} + +func dataSourceFlowLogCollectorFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFlowLogCollectorResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFlowLogCollectorResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceFlowLogCollectorFlattenStorageBucket(result vpcv1.LegacyCloudObjectStorageBucketReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFlowLogCollectorStorageBucketToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFlowLogCollectorStorageBucketToMap(storageBucketItem vpcv1.LegacyCloudObjectStorageBucketReference) (storageBucketMap map[string]interface{}) { + storageBucketMap = map[string]interface{}{} + + if storageBucketItem.Name != nil { + storageBucketMap["name"] = storageBucketItem.Name + } + + return storageBucketMap +} + +func dataSourceFlowLogCollectorFlattenTarget(result vpcv1.FlowLogCollectorTarget) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFlowLogCollectorTargetToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFlowLogCollectorTargetToMap(targetItem vpcv1.FlowLogCollectorTarget) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFlowLogCollectorTargetDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.ResourceType != nil { + targetMap["resource_type"] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap["crn"] = targetItem.CRN + } + + return targetMap +} + +func dataSourceFlowLogCollectorTargetDeletedToMap(deletedItem vpcv1.NetworkInterfaceReferenceTargetContextDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceFlowLogCollectorFlattenVPC(result vpcv1.VPCReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceFlowLogCollectorVPCToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceFlowLogCollectorVPCToMap(vpcItem vpcv1.VPCReference) (vpcMap map[string]interface{}) { + vpcMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + vpcMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceFlowLogCollectorVPCDeletedToMap(*vpcItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcMap["deleted"] = deletedList + } + if vpcItem.Href != nil { + vpcMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + vpcMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + vpcMap["name"] = vpcItem.Name + } + + return vpcMap +} + +func dataSourceFlowLogCollectorVPCDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_flow_log_test.go b/ibm/service/vpc/data_source_ibm_is_flow_log_test.go new file mode 100644 index 000000000..fc1651742 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_flow_log_test.go @@ -0,0 +1,129 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsFlowLogDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("flowlog-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("resource-instance-%d", acctest.RandIntRange(10, 100)) + flowlogname := fmt.Sprintf("flowlog-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("flowlog-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + serviceName := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + + { + Config: testAccCheckIBMISFlowLogDataSourceConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "identifier"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "active"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "storage_bucket.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_flow_log.is_flow_log_name", "crn"), + ), + }, + }, + }, + ) +} + +func testAccCheckIBMISFlowLogDataSourceConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass string, isActive bool) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + keys = [ibm_is_ssh_key.testacc_sshkey.id] + zone = "%s" + } + + + resource "ibm_resource_instance" "instance2" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "bucket2" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance2.id + region_location = "%s" + storage_class = "%s" + } + + resource "ibm_is_flow_log" "test_flow_log" { + name = "%s" + target = ibm_is_instance.testacc_instance.id + storage_bucket = ibm_cos_bucket.bucket2.bucket_name + active = %v + } + + data "ibm_is_flow_log" "is_flow_log" { + identifier = ibm_is_flow_log.test_flow_log.id + } + + data "ibm_is_flow_log" "is_flow_log_name" { + name = ibm_is_flow_log.test_flow_log.name + } + + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) + +} diff --git a/ibm/data_source_ibm_is_flow_logs.go b/ibm/service/vpc/data_source_ibm_is_flow_logs.go similarity index 94% rename from ibm/data_source_ibm_is_flow_logs.go rename to ibm/service/vpc/data_source_ibm_is_flow_logs.go index 6d9fe2837..b635deebe 100644 --- a/ibm/data_source_ibm_is_flow_logs.go +++ b/ibm/service/vpc/data_source_ibm_is_flow_logs.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +16,7 @@ const ( isFlowLogs = "flow_log_collectors" ) -func dataSourceIBMISFlowLogs() *schema.Resource { +func DataSourceIBMISFlowLogs() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISFlowLogsRead, @@ -104,9 +105,9 @@ func dataSourceIBMISFlowLogsRead(d *schema.ResourceData, meta interface{}) error } flowlogCollectors, response, err := sess.ListFlowLogCollectors(listOptions) if err != nil { - return fmt.Errorf("Error Fetching Flow Logs for VPC %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching Flow Logs for VPC %s\n%s", err, response) } - start = GetNext(flowlogCollectors.Next) + start = flex.GetNext(flowlogCollectors.Next) allrecs = append(allrecs, flowlogCollectors.FlowLogCollectors...) if start == "" { break diff --git a/ibm/data_source_ibm_is_flow_logs_test.go b/ibm/service/vpc/data_source_ibm_is_flow_logs_test.go similarity index 92% rename from ibm/data_source_ibm_is_flow_logs_test.go rename to ibm/service/vpc/data_source_ibm_is_flow_logs_test.go index a2b364fd3..e7afcc8d1 100644 --- a/ibm/data_source_ibm_is_flow_logs_test.go +++ b/ibm/service/vpc/data_source_ibm_is_flow_logs_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -31,12 +33,12 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resName := "data.ibm_is_flow_logs.display_flow_logs" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISFlowLogDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { //Create test case Config: testAccCheckIBMISFlowLogsDataSourceConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, true), Check: resource.ComposeTestCheckFunc( @@ -45,7 +47,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE ), }, //update - resource.TestStep{ + { Config: testAccCheckIBMISFlowLogsDataSourceConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, false), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISFlowLogExists("ibm_is_flow_log.test_flow_log", instance), @@ -129,6 +131,6 @@ func testAccCheckIBMISFlowLogsDataSourceConfig(vpcname, name, flowlogname, sshna data "ibm_is_flow_logs" "display_flow_logs" { } - `, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) } diff --git a/ibm/service/vpc/data_source_ibm_is_ike_policies.go b/ibm/service/vpc/data_source_ibm_is_ike_policies.go new file mode 100644 index 000000000..e14ff6c8e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ike_policies.go @@ -0,0 +1,310 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsIkePolicies() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsIkePoliciesRead, + + Schema: map[string]*schema.Schema{ + "ike_policies": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of IKE policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authentication_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The authentication algorithm.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "The VPN gateway connections that use this IKE policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this IKE policy was created.", + }, + "dh_group": { + Type: schema.TypeInt, + Computed: true, + Description: "The Diffie-Hellman group.", + }, + "encryption_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The encryption algorithm.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IKE policy's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this IKE policy.", + }, + "ike_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The IKE protocol version.", + }, + "key_lifetime": { + Type: schema.TypeInt, + Computed: true, + Description: "The key lifetime in seconds.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this IKE policy.", + }, + "negotiation_mode": { + Type: schema.TypeString, + Computed: true, + Description: "The IKE negotiation mode. Only `main` is supported.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this IKE policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsIkePoliciesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.IkePolicy{} + for { + listIkePoliciesOptions := &vpcv1.ListIkePoliciesOptions{} + if start != "" { + listIkePoliciesOptions.Start = &start + } + ikePolicyCollection, response, err := vpcClient.ListIkePoliciesWithContext(context, listIkePoliciesOptions) + if err != nil || ikePolicyCollection == nil { + log.Printf("[DEBUG] ListIkePoliciesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListIkePoliciesWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(ikePolicyCollection.Next) + allrecs = append(allrecs, ikePolicyCollection.IkePolicies...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsIkePoliciesID(d)) + + err = d.Set("ike_policies", dataSourceIkePolicyCollectionFlattenIkePolicies(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting ike_policies %s", err)) + } + + return nil +} + +// dataSourceIBMIsIkePoliciesID returns a reasonable ID for the list. +func dataSourceIBMIsIkePoliciesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIkePolicyCollectionFlattenIkePolicies(result []vpcv1.IkePolicy) (ikePolicies []map[string]interface{}) { + for _, ikePoliciesItem := range result { + ikePolicies = append(ikePolicies, dataSourceIkePolicyCollectionIkePoliciesToMap(ikePoliciesItem)) + } + + return ikePolicies +} + +func dataSourceIkePolicyCollectionIkePoliciesToMap(ikePoliciesItem vpcv1.IkePolicy) (ikePoliciesMap map[string]interface{}) { + ikePoliciesMap = map[string]interface{}{} + + if ikePoliciesItem.AuthenticationAlgorithm != nil { + ikePoliciesMap["authentication_algorithm"] = ikePoliciesItem.AuthenticationAlgorithm + } + if ikePoliciesItem.Connections != nil { + connectionsList := []map[string]interface{}{} + for _, connectionsItem := range ikePoliciesItem.Connections { + connectionsList = append(connectionsList, dataSourceIkePolicyCollectionIkePoliciesConnectionsToMap(connectionsItem)) + } + ikePoliciesMap["connections"] = connectionsList + } + if ikePoliciesItem.CreatedAt != nil { + ikePoliciesMap["created_at"] = ikePoliciesItem.CreatedAt.String() + } + if ikePoliciesItem.DhGroup != nil { + ikePoliciesMap["dh_group"] = ikePoliciesItem.DhGroup + } + if ikePoliciesItem.EncryptionAlgorithm != nil { + ikePoliciesMap["encryption_algorithm"] = ikePoliciesItem.EncryptionAlgorithm + } + if ikePoliciesItem.Href != nil { + ikePoliciesMap["href"] = ikePoliciesItem.Href + } + if ikePoliciesItem.ID != nil { + ikePoliciesMap["id"] = ikePoliciesItem.ID + } + if ikePoliciesItem.IkeVersion != nil { + ikePoliciesMap["ike_version"] = ikePoliciesItem.IkeVersion + } + if ikePoliciesItem.KeyLifetime != nil { + ikePoliciesMap["key_lifetime"] = ikePoliciesItem.KeyLifetime + } + if ikePoliciesItem.Name != nil { + ikePoliciesMap["name"] = ikePoliciesItem.Name + } + if ikePoliciesItem.NegotiationMode != nil { + ikePoliciesMap["negotiation_mode"] = ikePoliciesItem.NegotiationMode + } + if ikePoliciesItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceIkePolicyCollectionIkePoliciesResourceGroupToMap(*ikePoliciesItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + ikePoliciesMap["resource_group"] = resourceGroupList + } + if ikePoliciesItem.ResourceType != nil { + ikePoliciesMap["resource_type"] = ikePoliciesItem.ResourceType + } + + return ikePoliciesMap +} + +func dataSourceIkePolicyCollectionIkePoliciesConnectionsToMap(connectionsItem vpcv1.VPNGatewayConnectionReference) (connectionsMap map[string]interface{}) { + connectionsMap = map[string]interface{}{} + + if connectionsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceIkePolicyCollectionConnectionsDeletedToMap(*connectionsItem.Deleted) + deletedList = append(deletedList, deletedMap) + connectionsMap["deleted"] = deletedList + } + if connectionsItem.Href != nil { + connectionsMap["href"] = connectionsItem.Href + } + if connectionsItem.ID != nil { + connectionsMap["id"] = connectionsItem.ID + } + if connectionsItem.Name != nil { + connectionsMap["name"] = connectionsItem.Name + } + if connectionsItem.ResourceType != nil { + connectionsMap["resource_type"] = connectionsItem.ResourceType + } + + return connectionsMap +} + +func dataSourceIkePolicyCollectionConnectionsDeletedToMap(deletedItem vpcv1.VPNGatewayConnectionReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceIkePolicyCollectionIkePoliciesResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_ike_policies_test.go b/ibm/service/vpc/data_source_ibm_is_ike_policies_test.go new file mode 100644 index 000000000..d7f2b998d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ike_policies_test.go @@ -0,0 +1,51 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsIkePoliciesDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tfike-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsIkePoliciesDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.dh_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.ike_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policies.is_ike_policies", "ike_policies.0.negotiation_mode"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsIkePoliciesDataSourceConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_is_ike_policy" "example" { + name = "%s" + authentication_algorithm = "sha1" + encryption_algorithm = "aes128" + dh_group = 5 + ike_version = 2 + key_lifetime = 1800 + } + data "ibm_is_ike_policies" "is_ike_policies" { + depends_on = [ibm_is_ike_policy.example] + } + `, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_ike_policy.go b/ibm/service/vpc/data_source_ibm_is_ike_policy.go new file mode 100644 index 000000000..16580ea78 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ike_policy.go @@ -0,0 +1,319 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsIkePolicy() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsIkePolicyRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "ike_policy"}, + Description: "The IKE policy name.", + }, + "ike_policy": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "ike_policy"}, + Description: "The IKE policy identifier.", + }, + "authentication_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The authentication algorithm.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "The VPN gateway connections that use this IKE policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this IKE policy was created.", + }, + "dh_group": { + Type: schema.TypeInt, + Computed: true, + Description: "The Diffie-Hellman group.", + }, + "encryption_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The encryption algorithm.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IKE policy's canonical URL.", + }, + "ike_version": { + Type: schema.TypeInt, + Computed: true, + Description: "The IKE protocol version.", + }, + "key_lifetime": { + Type: schema.TypeInt, + Computed: true, + Description: "The key lifetime in seconds.", + }, + "negotiation_mode": { + Type: schema.TypeString, + Computed: true, + Description: "The IKE negotiation mode. Only `main` is supported.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this IKE policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} + +func dataSourceIBMIsIkePolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get("name").(string) + identifier := d.Get("ike_policy").(string) + var ikePolicy *vpcv1.IkePolicy + if name != "" { + start := "" + allrecs := []vpcv1.IkePolicy{} + for { + listIkePoliciesyOptions := &vpcv1.ListIkePoliciesOptions{} + if start != "" { + listIkePoliciesyOptions.Start = &start + } + ikePolicies, response, err := vpcClient.ListIkePolicies(listIkePoliciesyOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("Error Fetching IKE Policies %s\n%s", err, response)) + } + start = flex.GetNext(ikePolicies.Next) + allrecs = append(allrecs, ikePolicies.IkePolicies...) + if start == "" { + break + } + } + ike_policy_found := false + for _, ikePolicyItem := range allrecs { + if *ikePolicyItem.Name == name { + ikePolicy = &ikePolicyItem + ike_policy_found = true + break + } + } + if !ike_policy_found { + log.Printf("[DEBUG] No ike policy found with given name %s", name) + return diag.FromErr(fmt.Errorf("No ike policy found with given name %s", name)) + } + + } else { + getIkePolicyOptions := &vpcv1.GetIkePolicyOptions{} + + getIkePolicyOptions.SetID(identifier) + + ikePolicy1, response, err := vpcClient.GetIkePolicyWithContext(context, getIkePolicyOptions) + if err != nil { + log.Printf("[DEBUG] GetIkePolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetIkePolicyWithContext failed %s\n%s", err, response)) + } + ikePolicy = ikePolicy1 + } + + d.SetId(*ikePolicy.ID) + if err = d.Set("authentication_algorithm", ikePolicy.AuthenticationAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting authentication_algorithm: %s", err)) + } + + if ikePolicy.Connections != nil { + err = d.Set("connections", dataSourceIkePolicyFlattenConnections(ikePolicy.Connections)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting connections %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(ikePolicy.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("dh_group", flex.IntValue(ikePolicy.DhGroup)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting dh_group: %s", err)) + } + if err = d.Set("encryption_algorithm", ikePolicy.EncryptionAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting encryption_algorithm: %s", err)) + } + if err = d.Set("href", ikePolicy.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("ike_version", flex.IntValue(ikePolicy.IkeVersion)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ike_version: %s", err)) + } + if err = d.Set("key_lifetime", flex.IntValue(ikePolicy.KeyLifetime)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting key_lifetime: %s", err)) + } + if err = d.Set("name", ikePolicy.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("negotiation_mode", ikePolicy.NegotiationMode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting negotiation_mode: %s", err)) + } + + if ikePolicy.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceIkePolicyFlattenResourceGroup(*ikePolicy.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + } + } + if err = d.Set("resource_type", ikePolicy.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + + return nil +} + +func dataSourceIkePolicyFlattenConnections(result []vpcv1.VPNGatewayConnectionReference) (connections []map[string]interface{}) { + for _, connectionsItem := range result { + connections = append(connections, dataSourceIkePolicyConnectionsToMap(connectionsItem)) + } + + return connections +} + +func dataSourceIkePolicyConnectionsToMap(connectionsItem vpcv1.VPNGatewayConnectionReference) (connectionsMap map[string]interface{}) { + connectionsMap = map[string]interface{}{} + + if connectionsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceIkePolicyConnectionsDeletedToMap(*connectionsItem.Deleted) + deletedList = append(deletedList, deletedMap) + connectionsMap["deleted"] = deletedList + } + if connectionsItem.Href != nil { + connectionsMap["href"] = connectionsItem.Href + } + if connectionsItem.ID != nil { + connectionsMap["id"] = connectionsItem.ID + } + if connectionsItem.Name != nil { + connectionsMap["name"] = connectionsItem.Name + } + if connectionsItem.ResourceType != nil { + connectionsMap["resource_type"] = connectionsItem.ResourceType + } + + return connectionsMap +} + +func dataSourceIkePolicyConnectionsDeletedToMap(deletedItem vpcv1.VPNGatewayConnectionReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceIkePolicyFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceIkePolicyResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceIkePolicyResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_ike_policy_test.go b/ibm/service/vpc/data_source_ibm_is_ike_policy_test.go new file mode 100644 index 000000000..c40ea3b8c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ike_policy_test.go @@ -0,0 +1,76 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsIkePolicyDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tfike-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsIkePolicyDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "connections.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "dh_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "encryption_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "ike_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "negotiation_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy", "resource_type"), + ), + }, + { + Config: testAccCheckIBMIsIkePolicyDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "connections.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "dh_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "encryption_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "ike_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "negotiation_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ike_policy.is_ike_policy1", "resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsIkePolicyDataSourceConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_is_ike_policy" "example" { + name = "%s" + authentication_algorithm = "sha1" + encryption_algorithm = "aes128" + dh_group = 5 + ike_version = 2 + key_lifetime = 1800 + } + data "ibm_is_ike_policy" "is_ike_policy" { + name = ibm_is_ike_policy.example.name + } + data "ibm_is_ike_policy" "is_ike_policy1" { + ike_policy = ibm_is_ike_policy.example.id + } + `, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_image.go b/ibm/service/vpc/data_source_ibm_is_image.go new file mode 100644 index 000000000..b20a79a41 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image.go @@ -0,0 +1,283 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isImageCatalogOffering = "catalog_offering" + isImageCatalogOfferingManaged = "managed" + isImageCatalogOfferingVersion = "version" + isImageCatalogOfferingCrn = "crn" + isImageCatalogOfferingDeleted = "deleted" + isImageCatalogOfferingMoreInfo = "more_info" +) + +func DataSourceIBMISImage() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISImageRead, + + Schema: map[string]*schema.Schema{ + + "name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"identifier", "name"}, + Description: "Image name", + }, + + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"identifier", "name"}, + Description: "Image id", + }, + + "visibility": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), + Description: "Whether the image is publicly visible or private to the account", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of this image", + }, + + "os": { + Type: schema.TypeString, + Computed: true, + Description: "Image Operating system", + }, + "architecture": { + Type: schema.TypeString, + Computed: true, + Description: "The operating system architecture", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this image", + }, + isImageCheckSum: { + Type: schema.TypeString, + Computed: true, + Description: "The SHA256 Checksum for this image", + }, + isImageEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", + }, + isImageEncryption: { + Type: schema.TypeString, + Computed: true, + Description: "The type of encryption used on the image", + }, + "source_volume": { + Type: schema.TypeString, + Computed: true, + Description: "Source volume id of the image", + }, + isImageCatalogOffering: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isImageCatalogOfferingManaged: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this image is managed as part of a catalog offering. A managed image can be provisioned using its catalog offering CRN or catalog offering version CRN.", + }, + isImageCatalogOfferingVersion: { + Type: schema.TypeList, + Computed: true, + Description: "The catalog offering version associated with this image.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + // isImageCatalogOfferingDeleted: { + // Type: schema.TypeList, + // Computed: true, + // Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // isImageCatalogOfferingMoreInfo: { + // Type: schema.TypeString, + // Computed: true, + // Description: "Link to documentation about deleted resources.", + // }, + // }, + // }, + // }, + isImageCatalogOfferingCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this version of the IBM Cloud catalog offering.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISImageRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get("name").(string) + identifier := d.Get("identifier").(string) + var visibility string + if v, ok := d.GetOk("visibility"); ok { + visibility = v.(string) + } + if name != "" { + err := imageGetByName(d, meta, name, visibility) + if err != nil { + return err + } + } else if identifier != "" { + err := imageGetById(d, meta, identifier) + if err != nil { + return err + } + } + + return nil +} + +func imageGetByName(d *schema.ResourceData, meta interface{}, name, visibility string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + listImagesOptions := &vpcv1.ListImagesOptions{ + Name: &name, + } + + if visibility != "" { + listImagesOptions.Visibility = &visibility + } + availableImages, response, err := sess.ListImages(listImagesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Images %s\n%s", err, response) + } + allrecs := availableImages.Images + + if len(allrecs) == 0 { + return fmt.Errorf("[ERROR] No image found with name %s", name) + } + image := allrecs[0] + d.SetId(*image.ID) + d.Set("status", *image.Status) + if *image.Status == "deprecated" { + fmt.Printf("[WARN] Given image %s is deprecated and soon will be obsolete.", name) + } + d.Set("name", *image.Name) + d.Set("visibility", *image.Visibility) + d.Set("os", *image.OperatingSystem.Name) + d.Set("architecture", *image.OperatingSystem.Architecture) + d.Set("crn", *image.CRN) + if image.Encryption != nil { + d.Set("encryption", *image.Encryption) + } + if image.EncryptionKey != nil { + d.Set("encryption_key", *image.EncryptionKey.CRN) + } + if image.File != nil && image.File.Checksums != nil { + d.Set(isImageCheckSum, *image.File.Checksums.Sha256) + } + if image.SourceVolume != nil { + d.Set("source_volume", *image.SourceVolume.ID) + } + if image.CatalogOffering != nil { + catalogOfferingList := []map[string]interface{}{} + catalogOfferingMap := dataSourceImageCollectionCatalogOfferingToMap(*image.CatalogOffering) + catalogOfferingList = append(catalogOfferingList, catalogOfferingMap) + d.Set(isImageCatalogOffering, catalogOfferingList) + } + return nil + +} +func imageGetById(d *schema.ResourceData, meta interface{}, identifier string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getImageOptions := &vpcv1.GetImageOptions{ + ID: &identifier, + } + + image, response, err := sess.GetImage(getImageOptions) + if err != nil { + if response.StatusCode == 404 { + return fmt.Errorf("[ERROR] No image found with id %s", identifier) + } + return fmt.Errorf("[ERROR] Error Fetching Images %s\n%s", err, response) + } + + d.SetId(*image.ID) + d.Set("status", *image.Status) + if *image.Status == "deprecated" { + fmt.Printf("[WARN] Given image %s is deprecated and soon will be obsolete.", name) + } + d.Set("name", *image.Name) + d.Set("visibility", *image.Visibility) + d.Set("os", *image.OperatingSystem.Name) + d.Set("architecture", *image.OperatingSystem.Architecture) + d.Set("crn", *image.CRN) + if image.Encryption != nil { + d.Set("encryption", *image.Encryption) + } + if image.EncryptionKey != nil { + d.Set("encryption_key", *image.EncryptionKey.CRN) + } + if image.File != nil && image.File.Checksums != nil { + d.Set(isImageCheckSum, *image.File.Checksums.Sha256) + } + if image.SourceVolume != nil { + d.Set("source_volume", *image.SourceVolume.ID) + } + if image.CatalogOffering != nil { + catalogOfferingList := []map[string]interface{}{} + catalogOfferingMap := dataSourceImageCollectionCatalogOfferingToMap(*image.CatalogOffering) + catalogOfferingList = append(catalogOfferingList, catalogOfferingMap) + d.Set(isImageCatalogOffering, catalogOfferingList) + } + return nil +} + +func dataSourceImageCollectionCatalogOfferingToMap(imageCatalogOfferingItem vpcv1.ImageCatalogOffering) (imageCatalogOfferingMap map[string]interface{}) { + imageCatalogOfferingMap = map[string]interface{}{} + if imageCatalogOfferingItem.Managed != nil { + imageCatalogOfferingMap[isImageCatalogOfferingManaged] = imageCatalogOfferingItem.Managed + } + if imageCatalogOfferingItem.Version != nil { + imageCatalogOfferingVersionList := []map[string]interface{}{} + imageCatalogOfferingVersionMap := map[string]interface{}{} + imageCatalogOfferingVersionMap[isImageCatalogOfferingCrn] = imageCatalogOfferingItem.Version.CRN + + // if imageCatalogOfferingItem.Version.Deleted != nil { + // imageCatalogOfferingVersionDeletedList := []map[string]interface{}{} + // imageCatalogOfferingVersionDeletedMap := map[string]interface{}{} + // imageCatalogOfferingVersionDeletedMap[isImageCatalogOfferingMoreInfo] = imageCatalogOfferingItem.Version.Deleted.MoreInfo + // imageCatalogOfferingVersionDeletedList = append(imageCatalogOfferingVersionDeletedList, imageCatalogOfferingVersionDeletedMap) + // imageCatalogOfferingVersionMap[isImageCatalogOfferingDeleted] = imageCatalogOfferingVersionDeletedList + // } + imageCatalogOfferingVersionList = append(imageCatalogOfferingVersionList, imageCatalogOfferingVersionMap) + imageCatalogOfferingMap[isImageCatalogOfferingVersion] = imageCatalogOfferingVersionList + } + + return imageCatalogOfferingMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_test.go b/ibm/service/vpc/data_source_ibm_is_image_test.go new file mode 100644 index 000000000..e0a933688 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image_test.go @@ -0,0 +1,154 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISImageDataSource_basic(t *testing.T) { + resName := "data.ibm_is_image.test1" + imageName := fmt.Sprintf("tfimage-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImageDataSourceConfig(imageName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", imageName), + resource.TestCheckResourceAttrSet(resName, "os"), + resource.TestCheckResourceAttrSet(resName, "architecture"), + resource.TestCheckResourceAttrSet(resName, "visibility"), + resource.TestCheckResourceAttrSet(resName, "status"), + ), + }, + }, + }) +} +func TestAccIBMISImageDataSource_catalog(t *testing.T) { + resName := "data.ibm_is_image.test1" + resName1 := "data.ibm_is_image.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISCatalogImageDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "name"), + resource.TestCheckResourceAttrSet(resName, "os"), + resource.TestCheckResourceAttrSet(resName, "architecture"), + resource.TestCheckResourceAttrSet(resName, "visibility"), + resource.TestCheckResourceAttrSet(resName, "status"), + resource.TestCheckResourceAttr(resName, "catalog_offering.0.managed", "true"), + resource.TestCheckResourceAttrSet(resName, "catalog_offering.0.version.0.crn"), + resource.TestCheckResourceAttrSet(resName1, "name"), + resource.TestCheckResourceAttrSet(resName1, "os"), + resource.TestCheckResourceAttrSet(resName1, "architecture"), + resource.TestCheckResourceAttrSet(resName1, "visibility"), + resource.TestCheckResourceAttrSet(resName1, "status"), + resource.TestCheckResourceAttr(resName1, "catalog_offering.0.managed", "true"), + resource.TestCheckResourceAttrSet(resName1, "catalog_offering.0.version.0.crn"), + ), + }, + }, + }) +} + +func TestAccIBMISImageDataSource_With_VisibiltyPublic(t *testing.T) { + resName := "data.ibm_is_image.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImageDataSourceWithVisibilityPublic("public"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", acc.IsImageName), + resource.TestCheckResourceAttrSet(resName, "os"), + resource.TestCheckResourceAttrSet(resName, "architecture"), + resource.TestCheckResourceAttrSet(resName, "visibility"), + resource.TestCheckResourceAttrSet(resName, "status"), + ), + }, + }, + }) +} + +func TestAccIBMISImageDataSource_With_VisibiltyPrivate(t *testing.T) { + resName := "data.ibm_is_image.test1" + imageName := fmt.Sprintf("tfimage-name-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImageDataSourceWithVisibilityPrivate(imageName, "private"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", imageName), + resource.TestCheckResourceAttrSet(resName, "os"), + resource.TestCheckResourceAttrSet(resName, "architecture"), + resource.TestCheckResourceAttrSet(resName, "visibility"), + resource.TestCheckResourceAttrSet(resName, "status"), + ), + }, + }, + }) +} + +func testAccCheckIBMISImageDataSourceConfig(imageName string) string { + return fmt.Sprintf(` + resource "ibm_is_image" "isExampleImage" { + href = "%s" + name = "%s" + operating_system = "%s" + } + data "ibm_is_image" "test1" { + name = ibm_is_image.isExampleImage.name + }`, acc.Image_cos_url, imageName, acc.Image_operating_system) +} +func testAccCheckIBMISCatalogImageDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_is_images" "test1" { + catalog_managed = true + } + data "ibm_is_image" "test1" { + name = data.ibm_is_images.test1.images.0.name + } + data "ibm_is_image" "test2" { + identifier = data.ibm_is_images.test1.images.0.id + }`) +} + +func testAccCheckIBMISImageDataSourceWithVisibilityPublic(visibility string) string { + return fmt.Sprintf(` + data "ibm_is_image" "test1" { + name = "%s" + visibility = "%s" + }`, acc.IsImageName, visibility) +} + +func testAccCheckIBMISImageDataSourceWithVisibilityPrivate(imageName, visibility string) string { + return fmt.Sprintf(` + resource "ibm_is_image" "isExampleImage" { + href = "%s" + name = "%s" + operating_system = "%s" + } + data "ibm_is_image" "test1" { + name = ibm_is_image.isExampleImage.name + visibility = "%s" + }`, acc.Image_cos_url, imageName, acc.Image_operating_system, visibility) +} diff --git a/ibm/service/vpc/data_source_ibm_is_images.go b/ibm/service/vpc/data_source_ibm_is_images.go new file mode 100644 index 000000000..a073c304e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_images.go @@ -0,0 +1,306 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isImages = "images" + isImagesResourceGroupID = "resource_group" + isImageCatalogManaged = "catalog_managed" +) + +func DataSourceIBMISImages() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISImagesRead, + + Schema: map[string]*schema.Schema{ + isImagesResourceGroupID: { + Type: schema.TypeString, + Description: "The id of the resource group", + Optional: true, + }, + isImageCatalogManaged: { + Type: schema.TypeBool, + Description: "Lists images managed as part of a catalog offering. If an image is managed, accounts in the same enterprise with access to that catalog can specify the image's catalog offering version CRN to provision virtual server instances using the image", + Optional: true, + }, + isImageName: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_image", isImageName), + Description: "The name of the image", + }, + isImageStatus: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_images", isImageStatus), + Description: "The status of the image", + }, + isImageVisibility: { + Type: schema.TypeString, + Optional: true, + Description: "Whether the image is publicly visible or private to the account", + }, + + isImages: { + Type: schema.TypeList, + Description: "List of images", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Image name", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this image", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of this image", + }, + "visibility": { + Type: schema.TypeString, + Computed: true, + Description: "Whether the image is publicly visible or private to the account", + }, + "os": { + Type: schema.TypeString, + Computed: true, + Description: "Image Operating system", + }, + "architecture": { + Type: schema.TypeString, + Computed: true, + Description: "The operating system architecture", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this image", + }, + isImageCheckSum: { + Type: schema.TypeString, + Computed: true, + Description: "The SHA256 Checksum for this image", + }, + isImageEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", + }, + isImageEncryption: { + Type: schema.TypeString, + Computed: true, + Description: "The type of encryption used on the image", + }, + "source_volume": { + Type: schema.TypeString, + Computed: true, + Description: "Source volume id of the image", + }, + isImageCatalogOffering: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isImageCatalogOfferingManaged: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this image is managed as part of a catalog offering. A managed image can be provisioned using its catalog offering CRN or catalog offering version CRN.", + }, + isImageCatalogOfferingVersion: { + Type: schema.TypeList, + Computed: true, + Description: "The catalog offering version associated with this image.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isImageCatalogOfferingDeleted: { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isImageCatalogOfferingMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + isImageCatalogOfferingCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this version of the IBM Cloud catalog offering.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMISImagesValidator() *validate.ResourceValidator { + + status := "available, deleting, deprecated, failed, obsolete, pending, tentative, unusable" + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isImageStatus, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: status}) + ibmISImageResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_images", Schema: validateSchema} + return &ibmISImageResourceValidator +} + +func dataSourceIBMISImagesRead(d *schema.ResourceData, meta interface{}) error { + + err := imageList(d, meta) + if err != nil { + return err + } + return nil +} + +func imageList(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + start := "" + allrecs := []vpcv1.Image{} + + var resourceGroupID string + if v, ok := d.GetOk(isImagesResourceGroupID); ok { + resourceGroupID = v.(string) + } + + var imageName string + if v, ok := d.GetOk(isImageName); ok { + imageName = v.(string) + } + + var visibility string + if v, ok := d.GetOk(isImageVisibility); ok { + visibility = v.(string) + } + + var status string + if v, ok := d.GetOk(isImageStatus); ok { + status = v.(string) + } + var catalogManaged bool + if v, ok := d.GetOk(isImageCatalogManaged); ok { + catalogManaged = v.(bool) + } + + listImagesOptions := &vpcv1.ListImagesOptions{} + if resourceGroupID != "" { + listImagesOptions.SetResourceGroupID(resourceGroupID) + } + if imageName != "" { + listImagesOptions.SetName(imageName) + } + if visibility != "" { + listImagesOptions.SetVisibility(visibility) + } + + for { + if start != "" { + listImagesOptions.Start = &start + } + availableImages, response, err := sess.ListImages(listImagesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Images %s\n%s", err, response) + } + start = flex.GetNext(availableImages.Next) + allrecs = append(allrecs, availableImages.Images...) + if start == "" { + break + } + } + + if status != "" { + allrecsTemp := []vpcv1.Image{} + for _, image := range allrecs { + if status == *image.Status { + allrecsTemp = append(allrecsTemp, image) + } + } + allrecs = allrecsTemp + } + + if catalogManaged { + allrecsTemp := []vpcv1.Image{} + for _, image := range allrecs { + if image.CatalogOffering != nil && catalogManaged == *image.CatalogOffering.Managed { + allrecsTemp = append(allrecsTemp, image) + } + } + allrecs = allrecsTemp + } + + imagesInfo := make([]map[string]interface{}, 0) + for _, image := range allrecs { + + l := map[string]interface{}{ + "name": *image.Name, + "id": *image.ID, + "status": *image.Status, + "crn": *image.CRN, + "visibility": *image.Visibility, + "os": *image.OperatingSystem.Name, + "architecture": *image.OperatingSystem.Architecture, + } + if image.File != nil && image.File.Checksums != nil { + l[isImageCheckSum] = *image.File.Checksums.Sha256 + } + if image.Encryption != nil { + l["encryption"] = *image.Encryption + } + if image.EncryptionKey != nil { + l["encryption_key"] = *image.EncryptionKey.CRN + } + if image.SourceVolume != nil { + l["source_volume"] = *image.SourceVolume.ID + } + if image.CatalogOffering != nil { + catalogOfferingList := []map[string]interface{}{} + catalogOfferingMap := dataSourceImageCollectionCatalogOfferingToMap(*image.CatalogOffering) + catalogOfferingList = append(catalogOfferingList, catalogOfferingMap) + l[isImageCatalogOffering] = catalogOfferingList + } + imagesInfo = append(imagesInfo, l) + } + d.SetId(dataSourceIBMISImagesID(d)) + d.Set(isImages, imagesInfo) + return nil +} + +// dataSourceIBMISImagesId returns a reasonable ID for a image list. +func dataSourceIBMISImagesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_images_test.go b/ibm/service/vpc/data_source_ibm_is_images_test.go new file mode 100644 index 000000000..2bbbbda00 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_images_test.go @@ -0,0 +1,117 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISImagesDataSource_basic(t *testing.T) { + resName := "data.ibm_is_images.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImagesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "images.0.name"), + resource.TestCheckResourceAttrSet(resName, "images.0.status"), + resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), + ), + }, + }, + }) +} +func TestAccIBMISImagesDataSource_catalog(t *testing.T) { + resName := "data.ibm_is_images.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISCatalogImagesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "images.0.name"), + resource.TestCheckResourceAttr(resName, "images.0.catalog_offering.0.managed", "true"), + resource.TestCheckResourceAttrSet(resName, "images.0.status"), + resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), + ), + }, + }, + }) +} + +func TestAccIBMISImageDataSource_With_FilterVisibilty(t *testing.T) { + resName := "data.ibm_is_images.test1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImagesDataSourceWithVisibilityPublic("public"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "images.0.name"), + resource.TestCheckResourceAttrSet(resName, "images.0.status"), + resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), + ), + }, + }, + }) +} + +func TestAccIBMISImageDataSource_With_FilterStatus(t *testing.T) { + resName := "data.ibm_is_images.test1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImagesDataSourceWithStatusPublic("available"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "images.0.name"), + resource.TestCheckResourceAttrSet(resName, "images.0.status"), + resource.TestCheckResourceAttrSet(resName, "images.0.architecture"), + ), + }, + }, + }) +} + +func testAccCheckIBMISImagesDataSourceConfig() string { + // status filter defaults to empty + return fmt.Sprintf(` + data "ibm_is_images" "test1" { + }`) +} +func testAccCheckIBMISCatalogImagesDataSourceConfig() string { + // status filter defaults to empty + return fmt.Sprintf(` + data "ibm_is_images" "test1" { + catalog_managed = true + }`) +} + +func testAccCheckIBMISImagesDataSourceWithVisibilityPublic(visibility string) string { + return fmt.Sprintf(` + data "ibm_is_images" "test1" { + visibility = "%s" + } + `, visibility) +} + +func testAccCheckIBMISImagesDataSourceWithStatusPublic(status string) string { + return fmt.Sprintf(` + data "ibm_is_images" "test1" { + status = "%s" + } + `, status) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance.go b/ibm/service/vpc/data_source_ibm_is_instance.go new file mode 100644 index 000000000..8652a0e6f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance.go @@ -0,0 +1,1133 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "log" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/ScaleFT/sshkeys" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "golang.org/x/crypto/ssh" +) + +const ( + isInstancePEM = "private_key" + isInstancePassphrase = "passphrase" + isInstanceInitPassword = "password" + isInstanceInitKeys = "keys" + isInstanceNicPrimaryIP = "primary_ip" + isInstanceNicReservedIpAddress = "address" + isInstanceNicReservedIpHref = "href" + isInstanceNicReservedIpAutoDelete = "auto_delete" + isInstanceNicReservedIpName = "name" + isInstanceNicReservedIpId = "reserved_ip" + isInstanceNicReservedIpResourceType = "resource_type" +) + +func DataSourceIBMISInstance() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISInstanceRead, + + Schema: map[string]*schema.Schema{ + + isInstanceAvailablePolicyHostFailure: { + Type: schema.TypeString, + Computed: true, + Description: "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + }, + + isInstanceName: { + Type: schema.TypeString, + Required: true, + Description: "Instance name", + }, + + isInstanceMetadataServiceEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + + isInstancePEM: { + Type: schema.TypeString, + Optional: true, + Description: "Instance Private Key file", + }, + + isInstancePassphrase: { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "Passphrase for Instance Private Key file", + }, + + isInstanceInitPassword: { + Type: schema.TypeString, + Sensitive: true, + Computed: true, + Description: "password for Windows Instance", + }, + + isInstanceInitKeys: { + Type: schema.TypeList, + Computed: true, + Description: "Instance keys", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance key id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance key name", + }, + }, + }, + }, + + isInstanceVPC: { + Type: schema.TypeString, + Computed: true, + Description: "VPC id", + }, + + isInstanceZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + isInstanceProfile: { + Type: schema.TypeString, + Computed: true, + Description: "Profile info", + }, + + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + + isInstanceBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + }, + + isInstanceTotalNetworkBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + }, + + isInstanceLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the virtual server instance.", + }, + isInstanceLifecycleReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current lifecycle_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceLifecycleReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + + isInstanceTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "list of tags for the instance", + }, + isInstanceBootVolume: { + Type: schema.TypeList, + Computed: true, + Description: "Instance Boot Volume", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume name", + }, + "device": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume device", + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume id", + }, + "volume_name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume name", + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume CRN", + }, + }, + }, + }, + + isInstanceCatalogOffering: { + Type: schema.TypeList, + Computed: true, + Description: "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceCatalogOfferingOfferingCrn: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a catalog offering by a unique CRN property", + }, + isInstanceCatalogOfferingVersionCrn: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a version of a catalog offering by a unique CRN property", + }, + }, + }, + }, + + isInstanceVolumeAttachments: { + Type: schema.TypeList, + Computed: true, + Description: "Instance Volume Attachments", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Volume Attachment id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Volume Attachment name", + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume id", + }, + "volume_name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume name", + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot Volume's volume CRN", + }, + }, + }, + }, + + isInstancePrimaryNetworkInterface: { + Type: schema.TypeList, + Computed: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network Interface id", + }, + isInstanceNicName: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network Interface name", + }, + isInstanceNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance Primary Network Interface port speed", + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network Interface IPV4 Address", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Instance Primary Network Interface Security groups", + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network Interface subnet", + }, + }, + }, + }, + + isInstanceNetworkInterfaces: { + Type: schema.TypeList, + Computed: true, + Description: "Instance Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network Interface id", + }, + isInstanceNicName: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network Interface name", + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network Interface IPV4 Address", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Instance Network Interface Security Groups", + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network Interface subnet", + }, + }, + }, + }, + + isInstanceImage: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Image", + }, + + isInstanceVolumes: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of volumes", + }, + + isInstanceResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Instance resource group", + }, + + isInstanceCPU: { + Type: schema.TypeList, + Computed: true, + Description: "Instance vCPU", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceCPUArch: { + Type: schema.TypeString, + Computed: true, + Description: "Instance vCPU Architecture", + }, + isInstanceCPUCount: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance vCPU count", + }, + }, + }, + }, + + isInstanceGpu: { + Type: schema.TypeList, + Computed: true, + Description: "Instance GPU", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceGpuCount: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance GPU Count", + }, + isInstanceGpuMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance GPU Memory", + }, + isInstanceGpuManufacturer: { + Type: schema.TypeString, + Computed: true, + Description: "Instance GPU Manufacturer", + }, + isInstanceGpuModel: { + Type: schema.TypeString, + Computed: true, + Description: "Instance GPU Model", + }, + }, + }, + }, + + isInstanceMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance memory", + }, + + isInstanceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "instance status", + }, + + isInstanceStatusReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isInstanceStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isInstanceStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + IsInstanceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + isInstanceDisks: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of the instance's disks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the disk was created.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance disk.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance disk.", + }, + "interface_type": { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "size": { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes).", + }, + }, + }, + }, + "placement_target": { + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this dedicated host group.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this dedicated host group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this dedicated host group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstanceRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isInstanceName).(string) + + err := instanceGetByName(d, meta, name) + if err != nil { + return err + } + return nil +} + +func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + listInstancesOptions := &vpcv1.ListInstancesOptions{ + Name: &name, + } + + instances, response, err := sess.ListInstances(listInstancesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Instances %s\n%s", err, response) + } + allrecs := instances.Instances + + if len(allrecs) == 0 { + return fmt.Errorf("[ERROR] No Instance found with name %s", name) + } + instance := allrecs[0] + d.SetId(*instance.ID) + id := *instance.ID + + // catalog + if instance.CatalogOffering != nil { + versionCrn := *instance.CatalogOffering.Version.CRN + catalogList := make([]map[string]interface{}, 0) + catalogMap := map[string]interface{}{} + catalogMap[isInstanceCatalogOfferingVersionCrn] = versionCrn + catalogList = append(catalogList, catalogMap) + d.Set(isInstanceCatalogOffering, catalogList) + } + + d.Set(isInstanceName, *instance.Name) + if instance.Profile != nil { + d.Set(isInstanceProfile, *instance.Profile.Name) + } + if instance.MetadataService != nil { + d.Set(isInstanceMetadataServiceEnabled, instance.MetadataService.Enabled) + } + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + d.Set(isInstanceAvailablePolicyHostFailure, *instance.AvailabilityPolicy.HostFailure) + } + cpuList := make([]map[string]interface{}, 0) + if instance.Vcpu != nil { + currentCPU := map[string]interface{}{} + currentCPU[isInstanceCPUArch] = *instance.Vcpu.Architecture + currentCPU[isInstanceCPUCount] = *instance.Vcpu.Count + cpuList = append(cpuList, currentCPU) + } + d.Set(isInstanceCPU, cpuList) + + if instance.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) + d.Set("placement_target", []map[string]interface{}{placementTargetMap}) + } + + d.Set(isInstanceMemory, *instance.Memory) + + gpuList := make([]map[string]interface{}, 0) + if instance.Gpu != nil { + currentGpu := map[string]interface{}{} + currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer + currentGpu[isInstanceGpuModel] = instance.Gpu.Model + currentGpu[isInstanceGpuCount] = instance.Gpu.Count + currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory + gpuList = append(gpuList, currentGpu) + d.Set(isInstanceGpu, gpuList) + } + + if instance.Bandwidth != nil { + d.Set(isInstanceBandwidth, int(*instance.Bandwidth)) + } + + if instance.TotalNetworkBandwidth != nil { + d.Set(isInstanceTotalNetworkBandwidth, int(*instance.TotalNetworkBandwidth)) + } + + if instance.TotalVolumeBandwidth != nil { + d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) + } + + if instance.Disks != nil { + d.Set(isInstanceDisks, dataSourceInstanceFlattenDisks(instance.Disks)) + } + + if instance.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID + currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name + + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + if instance.PrimaryNetworkInterface.PrimaryIP.Address != nil { + currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + currentPrimIp[isInstanceNicReservedIpAddress] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + } + if instance.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *instance.PrimaryNetworkInterface.PrimaryIP.Href + } + if instance.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *instance.PrimaryNetworkInterface.PrimaryIP.Name + } + if instance.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *instance.PrimaryNetworkInterface.PrimaryIP.ID + } + if instance.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *instance.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: instance.PrimaryNetworkInterface.ID, + } + insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + if insnic.PortSpeed != nil { + currentPrimNic[isInstanceNicPortSpeed] = *insnic.PortSpeed + } + currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + primaryNicList = append(primaryNicList, currentPrimNic) + d.Set(isInstancePrimaryNetworkInterface, primaryNicList) + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + if *intfc.ID != *instance.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + currentNic["id"] = *intfc.ID + currentNic[isInstanceNicName] = *intfc.Name + + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + if intfc.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *intfc.PrimaryIP.Address + currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *intfc.PrimaryIP.ID + } + if intfc.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *intfc.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: intfc.ID, + } + insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + + } + } + + d.Set(isInstanceNetworkInterfaces, interfacesList) + } + + var rsaKey *rsa.PrivateKey + if instance.Image != nil { + d.Set(isInstanceImage, *instance.Image.ID) + image := *instance.Image.Name + res := strings.Contains(image, "windows") + if res { + if privatekey, ok := d.GetOk(isInstancePEM); ok { + keyFlag := privatekey.(string) + keybytes := []byte(keyFlag) + + if keyFlag != "" { + block, err := pem.Decode(keybytes) + if block == nil { + return fmt.Errorf("[ERROR] Failed to load the private key from the given key contents. Instead of the key file path, please make sure the private key is pem format") + } + isEncrypted := false + switch block.Type { + case "RSA PRIVATE KEY": + isEncrypted = x509.IsEncryptedPEMBlock(block) + case "OPENSSH PRIVATE KEY": + var err error + isEncrypted, err = isOpenSSHPrivKeyEncrypted(block.Bytes) + if err != nil { + return fmt.Errorf("[ERROR] Failed to check if the provided open ssh key is encrypted or not %s", err) + } + default: + return fmt.Errorf("PEM and OpenSSH private key formats with RSA key type are supported, can not support this key file type: %s", err) + } + passphrase := "" + var privateKey interface{} + if isEncrypted { + if pass, ok := d.GetOk(isInstancePassphrase); ok { + passphrase = pass.(string) + } else { + return fmt.Errorf("[ERROR] Mandatory field 'passphrase' not provided") + } + var err error + privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, []byte(passphrase)) + if err != nil { + return fmt.Errorf("[ERROR] Fail to decrypting the private key: %s", err) + } + } else { + var err error + privateKey, err = sshkeys.ParseEncryptedRawPrivateKey(keybytes, nil) + if err != nil { + return fmt.Errorf("[ERROR] Fail to decrypting the private key: %s", err) + } + } + var ok bool + rsaKey, ok = privateKey.(*rsa.PrivateKey) + if !ok { + return fmt.Errorf("[ERROR] Failed to convert to RSA private key") + } + } + } + } + } + + getInstanceInitializationOptions := &vpcv1.GetInstanceInitializationOptions{ + ID: &id, + } + initParms, response, err := sess.GetInstanceInitialization(getInstanceInitializationOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting instance Initialization: %s\n%s", err, response) + } + if initParms.Keys != nil { + initKeyList := make([]map[string]interface{}, 0) + for _, key := range initParms.Keys { + initKey := map[string]interface{}{} + id := "" + if key.ID != nil { + id = *key.ID + } + initKey["id"] = id + name := "" + if key.Name != nil { + name = *key.Name + } + initKey["name"] = name + initKeyList = append(initKeyList, initKey) + break + + } + d.Set(isInstanceInitKeys, initKeyList) + } + //set the lifecycle status, reasons + if instance.LifecycleState != nil { + d.Set(isInstanceLifecycleState, *instance.LifecycleState) + } + if instance.LifecycleReasons != nil { + d.Set(isInstanceLifecycleReasons, dataSourceInstanceFlattenLifecycleReasons(instance.LifecycleReasons)) + } + + if initParms.Password != nil && initParms.Password.EncryptedPassword != nil { + ciphertext := *initParms.Password.EncryptedPassword + password := base64.StdEncoding.EncodeToString(ciphertext) + if rsaKey != nil { + rng := rand.Reader + clearPassword, err := rsa.DecryptPKCS1v15(rng, rsaKey, ciphertext) + if err != nil { + return fmt.Errorf("[ERROR] Can not decrypt the password with the given key, %s", err) + } + password = string(clearPassword) + } + d.Set(isInstanceInitPassword, password) + } + + d.Set(isInstanceStatus, *instance.Status) + //set the status reasons + if instance.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range instance.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isInstanceStatusReasonsCode] = *sr.Code + currentSR[isInstanceStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + } + d.Set(isInstanceVPC, *instance.VPC.ID) + d.Set(isInstanceZone, *instance.Zone.Name) + + var volumes []string + volumes = make([]string, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + if volume.Volume != nil && *volume.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { + volumes = append(volumes, *volume.Volume.ID) + } + } + } + d.Set(isInstanceVolumes, flex.NewStringSet(schema.HashString, volumes)) + if instance.VolumeAttachments != nil { + volList := make([]map[string]interface{}, 0) + for _, volume := range instance.VolumeAttachments { + vol := map[string]interface{}{} + if volume.Volume != nil { + vol["id"] = *volume.ID + vol["volume_id"] = *volume.Volume.ID + vol["name"] = *volume.Name + vol["volume_name"] = *volume.Volume.Name + vol["volume_crn"] = *volume.Volume.CRN + volList = append(volList, vol) + } + } + d.Set(isInstanceVolumeAttachments, volList) + } + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + bootVol["id"] = *instance.BootVolumeAttachment.ID + bootVol["name"] = *instance.BootVolumeAttachment.Name + if instance.BootVolumeAttachment.Device != nil { + bootVol["device"] = *instance.BootVolumeAttachment.Device.ID + } + if instance.BootVolumeAttachment.Volume != nil { + bootVol["volume_name"] = *instance.BootVolumeAttachment.Volume.Name + bootVol["volume_id"] = *instance.BootVolumeAttachment.Volume.ID + bootVol["volume_crn"] = *instance.BootVolumeAttachment.Volume.CRN + } + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceBootVolume, bootVolList) + } + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource vpc Instance (%s) tags: %s", d.Id(), err) + } + d.Set(isInstanceTags, tags) + + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/vs") + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.CRN) + d.Set(IsInstanceCRN, instance.CRN) + d.Set(flex.ResourceStatus, instance.Status) + if instance.ResourceGroup != nil { + d.Set(isInstanceResourceGroup, instance.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, instance.ResourceGroup.Name) + } + return nil + +} + +const opensshv1Magic = "openssh-key-v1" + +type opensshPrivateKey struct { + CipherName string + KdfName string + KdfOpts string + NumKeys uint32 + PubKey string + PrivKeyBlock string +} + +func isOpenSSHPrivKeyEncrypted(data []byte) (bool, error) { + magic := append([]byte(opensshv1Magic), 0) + if !bytes.Equal(magic, data[0:len(magic)]) { + return false, errors.New("[ERROR] Invalid openssh private key format") + } + content := data[len(magic):] + + privKey := opensshPrivateKey{} + + if err := ssh.Unmarshal(content, &privKey); err != nil { + return false, err + } + + if privKey.KdfName == "none" && privKey.CipherName == "none" { + return false, nil + } + return true, nil +} + +func dataSourceInstanceFlattenDisks(result []vpcv1.InstanceDisk) (disks []map[string]interface{}) { + for _, disksItem := range result { + disks = append(disks, dataSourceInstanceDisksToMap(disksItem)) + } + + return disks +} + +func dataSourceInstanceDisksToMap(disksItem vpcv1.InstanceDisk) (disksMap map[string]interface{}) { + disksMap = map[string]interface{}{} + + if disksItem.CreatedAt != nil { + disksMap["created_at"] = disksItem.CreatedAt.String() + } + if disksItem.Href != nil { + disksMap["href"] = disksItem.Href + } + if disksItem.ID != nil { + disksMap["id"] = disksItem.ID + } + if disksItem.InterfaceType != nil { + disksMap["interface_type"] = disksItem.InterfaceType + } + if disksItem.Name != nil { + disksMap["name"] = disksItem.Name + } + if disksItem.ResourceType != nil { + disksMap["resource_type"] = disksItem.ResourceType + } + if disksItem.Size != nil { + disksMap["size"] = disksItem.Size + } + + return disksMap +} +func dataSourceInstanceFlattenLifecycleReasons(lifecycleReasons []vpcv1.LifecycleReason) (lifecycleReasonsList []map[string]interface{}) { + lifecycleReasonsList = make([]map[string]interface{}, 0) + for _, lr := range lifecycleReasons { + currentLR := map[string]interface{}{} + if lr.Code != nil && lr.Message != nil { + currentLR[isInstanceLifecycleReasonsCode] = *lr.Code + currentLR[isInstanceLifecycleReasonsMessage] = *lr.Message + if lr.MoreInfo != nil { + currentLR[isInstanceLifecycleReasonsMoreInfo] = *lr.MoreInfo + } + lifecycleReasonsList = append(lifecycleReasonsList, currentLR) + } + } + return lifecycleReasonsList +} diff --git a/ibm/data_source_ibm_is_instance_disk.go b/ibm/service/vpc/data_source_ibm_is_instance_disk.go similarity index 77% rename from ibm/data_source_ibm_is_instance_disk.go rename to ibm/service/vpc/data_source_ibm_is_instance_disk.go index d58095dbc..3fa0368b4 100644 --- a/ibm/data_source_ibm_is_instance_disk.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_disk.go @@ -1,60 +1,61 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsInstanceDisk() *schema.Resource { +func DataSourceIbmIsInstanceDisk() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsInstanceDiskRead, Schema: map[string]*schema.Schema{ - "instance": &schema.Schema{ + "instance": { Type: schema.TypeString, Required: true, Description: "The instance identifier.", }, - "disk": &schema.Schema{ + "disk": { Type: schema.TypeString, Required: true, Description: "The instance disk identifier.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", @@ -64,7 +65,7 @@ func dataSourceIbmIsInstanceDisk() *schema.Resource { } func dataSourceIbmIsInstanceDiskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -82,22 +83,22 @@ func dataSourceIbmIsInstanceDiskRead(context context.Context, d *schema.Resource d.SetId(*instanceDisk.ID) if err = d.Set("created_at", instanceDisk.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("href", instanceDisk.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("interface_type", instanceDisk.InterfaceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting interface_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting interface_type: %s", err)) } if err = d.Set("name", instanceDisk.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("resource_type", instanceDisk.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } if err = d.Set("size", instanceDisk.Size); err != nil { - return diag.FromErr(fmt.Errorf("Error setting size: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting size: %s", err)) } return nil diff --git a/ibm/data_source_ibm_is_instance_disk_test.go b/ibm/service/vpc/data_source_ibm_is_instance_disk_test.go similarity index 90% rename from ibm/data_source_ibm_is_instance_disk_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_disk_test.go index 153888235..50d4f7a81 100644 --- a/ibm/data_source_ibm_is_instance_disk_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_disk_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name), @@ -35,7 +37,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resource.TestCheckResourceAttr( insResName, "name", name), resource.TestCheckResourceAttr( - insResName, "zone", ISZoneName), + insResName, "zone", acc.ISZoneName), resource.TestCheckResourceAttr( insResName, "disks.#", "1"), resource.TestCheckResourceAttrSet( @@ -44,7 +46,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE insResName, "disks.0.size"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMISInstanceDiskDataSourceConfig(vpcname, subnetname, sshname, publicKey, volname, name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "name"), @@ -59,7 +61,7 @@ func testAccCheckIBMISInstanceDiskDataSourceConfig(vpcname, subnetname, sshname, return testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name) + fmt.Sprintf(` data "ibm_is_instance" "ins" { name = "%s" - private_key = file("test-fixtures/.ssh/id_rsa") + private_key = file("../../test-fixtures/.ssh/id_rsa") passphrase = "" } data "ibm_is_instance_disks" "test1" { diff --git a/ibm/data_source_ibm_is_instance_disks.go b/ibm/service/vpc/data_source_ibm_is_instance_disks.go similarity index 88% rename from ibm/data_source_ibm_is_instance_disks.go rename to ibm/service/vpc/data_source_ibm_is_instance_disks.go index 8b96977e3..f42fcc4af 100644 --- a/ibm/data_source_ibm_is_instance_disks.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_disks.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,59 +9,60 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsInstanceDisks() *schema.Resource { +func DataSourceIbmIsInstanceDisks() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsInstanceDisksRead, Schema: map[string]*schema.Schema{ - "instance": &schema.Schema{ + "instance": { Type: schema.TypeString, Required: true, Description: "The instance identifier.", }, - isInstanceDisks: &schema.Schema{ + isInstanceDisks: { Type: schema.TypeList, Computed: true, Description: "Collection of the instance's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", @@ -74,7 +75,7 @@ func dataSourceIbmIsInstanceDisks() *schema.Resource { } func dataSourceIbmIsInstanceDisksRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -93,7 +94,7 @@ func dataSourceIbmIsInstanceDisksRead(context context.Context, d *schema.Resourc if instanceDiskCollection.Disks != nil { err = d.Set(isInstanceDisks, dataSourceInstanceDiskCollectionFlattenDisks(instanceDiskCollection.Disks)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting disks %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disks %s", err)) } } diff --git a/ibm/data_source_ibm_is_instance_disks_test.go b/ibm/service/vpc/data_source_ibm_is_instance_disks_test.go similarity index 91% rename from ibm/data_source_ibm_is_instance_disks_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_disks_test.go index 10ab3d461..5660b7de8 100644 --- a/ibm/data_source_ibm_is_instance_disks_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_disks_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -27,8 +29,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE //instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name), @@ -37,7 +39,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resource.TestCheckResourceAttr( insResName, "name", name), resource.TestCheckResourceAttr( - insResName, "zone", ISZoneName), + insResName, "zone", acc.ISZoneName), resource.TestCheckResourceAttr( insResName, "disks.#", "1"), resource.TestCheckResourceAttrSet( @@ -62,7 +64,7 @@ func testAccCheckIBMISInstanceDisksDataSourceConfig(vpcname, subnetname, sshname return testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name) + fmt.Sprintf(` data "ibm_is_instance" "ins" { name = "%s" - private_key = file("test-fixtures/.ssh/id_rsa") + private_key = file("../../test-fixtures/.ssh/id_rsa") passphrase = "" } data "ibm_is_instance_disks" "test1" { diff --git a/ibm/data_source_ibm_is_instance_group.go b/ibm/service/vpc/data_source_ibm_is_instance_group.go similarity index 93% rename from ibm/data_source_ibm_is_instance_group.go rename to ibm/service/vpc/data_source_ibm_is_instance_group.go index 140b308ae..88930b423 100644 --- a/ibm/data_source_ibm_is_instance_group.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroup() *schema.Resource { +func DataSourceIBMISInstanceGroup() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupRead, @@ -105,9 +106,9 @@ func dataSourceIBMISInstanceGroupRead(d *schema.ResourceData, meta interface{}) } instanceGroupsCollection, response, err := sess.ListInstanceGroups(&listInstanceGroupOptions) if err != nil { - return fmt.Errorf("Error Fetching InstanceGroups %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching InstanceGroups %s\n%s", err, response) } - start = GetNext(instanceGroupsCollection.Next) + start = flex.GetNext(instanceGroupsCollection.Next) allrecs = append(allrecs, instanceGroupsCollection.InstanceGroups...) if start == "" { diff --git a/ibm/data_source_ibm_is_instance_group_manager.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager.go similarity index 94% rename from ibm/data_source_ibm_is_instance_group_manager.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager.go index 2bb898ee4..95070d79f 100644 --- a/ibm/data_source_ibm_is_instance_group_manager.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManager() *schema.Resource { +func DataSourceIBMISInstanceGroupManager() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagerRead, @@ -116,9 +117,9 @@ func dataSourceIBMISInstanceGroupManagerRead(d *schema.ResourceData, meta interf } instanceGroupManagerCollections, response, err := sess.ListInstanceGroupManagers(&listInstanceGroupManagerOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Managers %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Managers %s\n%s", err, response) } - start = GetNext(instanceGroupManagerCollections.Next) + start = flex.GetNext(instanceGroupManagerCollections.Next) allrecs = append(allrecs, instanceGroupManagerCollections.Managers...) if start == "" { diff --git a/ibm/data_source_ibm_is_instance_group_manager_action.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_action.go similarity index 82% rename from ibm/data_source_ibm_is_instance_group_manager_action.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_action.go index 467d5ab01..8d2873fee 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_action.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_action.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManagerAction() *schema.Resource { +func DataSourceIBMISInstanceGroupManagerAction() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagerActionRead, @@ -154,12 +155,12 @@ func dataSourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta } instanceGroupManagerActionsCollection, response, err := sess.ListInstanceGroupManagerActions(&listInstanceGroupManagerActionsOptions) if err != nil { - return fmt.Errorf("error Getting InstanceGroup Manager Actions %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Actions %s\n%s", err, response) } if instanceGroupManagerActionsCollection != nil && *instanceGroupManagerActionsCollection.TotalCount == int64(0) { break } - start = GetNext(instanceGroupManagerActionsCollection.Next) + start = flex.GetNext(instanceGroupManagerActionsCollection.Next) allrecs = append(allrecs, instanceGroupManagerActionsCollection.Actions...) if start == "" { break @@ -172,53 +173,53 @@ func dataSourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta d.SetId(fmt.Sprintf("%s/%s/%s", instanceGroupID, instanceGroupManagerID, *instanceGroupManagerAction.ID)) if err = d.Set("auto_delete", *instanceGroupManagerAction.AutoDelete); err != nil { - return fmt.Errorf("error setting auto_delete: %s", err) + return fmt.Errorf("[ERROR] Error setting auto_delete: %s", err) } - if err = d.Set("auto_delete_timeout", intValue(instanceGroupManagerAction.AutoDeleteTimeout)); err != nil { - return fmt.Errorf("error setting auto_delete_timeout: %s", err) + if err = d.Set("auto_delete_timeout", flex.IntValue(instanceGroupManagerAction.AutoDeleteTimeout)); err != nil { + return fmt.Errorf("[ERROR] Error setting auto_delete_timeout: %s", err) } if err = d.Set("created_at", instanceGroupManagerAction.CreatedAt.String()); err != nil { - return fmt.Errorf("error setting created_at: %s", err) + return fmt.Errorf("[ERROR] Error setting created_at: %s", err) } if err = d.Set("action_id", *instanceGroupManagerAction.ID); err != nil { - return fmt.Errorf("error setting instance_group_manager_action : %s", err) + return fmt.Errorf("[ERROR] Error setting instance_group_manager_action : %s", err) } if err = d.Set("resource_type", *instanceGroupManagerAction.ResourceType); err != nil { - return fmt.Errorf("error setting resource_type: %s", err) + return fmt.Errorf("[ERROR] Error setting resource_type: %s", err) } if err = d.Set("status", *instanceGroupManagerAction.Status); err != nil { - return fmt.Errorf("error setting status: %s", err) + return fmt.Errorf("[ERROR] Error setting status: %s", err) } if err = d.Set("updated_at", instanceGroupManagerAction.UpdatedAt.String()); err != nil { - return fmt.Errorf("error setting updated_at: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_at: %s", err) } if err = d.Set("action_type", *instanceGroupManagerAction.ActionType); err != nil { - return fmt.Errorf("error setting action_type: %s", err) + return fmt.Errorf("[ERROR] Error setting action_type: %s", err) } if instanceGroupManagerAction.CronSpec != nil { if err = d.Set("cron_spec", *instanceGroupManagerAction.CronSpec); err != nil { - return fmt.Errorf("error setting cron_spec: %s", err) + return fmt.Errorf("[ERROR] Error setting cron_spec: %s", err) } } if instanceGroupManagerAction.LastAppliedAt != nil { if err = d.Set("last_applied_at", instanceGroupManagerAction.LastAppliedAt.String()); err != nil { - return fmt.Errorf("error setting last_applied_at: %s", err) + return fmt.Errorf("[ERROR] Error setting last_applied_at: %s", err) } } if instanceGroupManagerAction.NextRunAt != nil { if err = d.Set("next_run_at", instanceGroupManagerAction.NextRunAt.String()); err != nil { - return fmt.Errorf("error setting next_run_at: %s", err) + return fmt.Errorf("[ERROR] Error setting next_run_at: %s", err) } } instanceGroupManagerScheduledActionGroupGroup := instanceGroupManagerAction.Group if instanceGroupManagerScheduledActionGroupGroup != nil && instanceGroupManagerScheduledActionGroupGroup.MembershipCount != nil { - d.Set("membership_count", intValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount)) + d.Set("membership_count", flex.IntValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount)) } instanceGroupManagerScheduledActionManagerManagerInt := instanceGroupManagerAction.Manager if instanceGroupManagerScheduledActionManagerManagerInt != nil { @@ -226,9 +227,9 @@ func dataSourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta if instanceGroupManagerScheduledActionManagerManager != nil && instanceGroupManagerScheduledActionManagerManager.ID != nil { if instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount != nil { - d.Set("max_membership_count", intValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount)) + d.Set("max_membership_count", flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount)) } - d.Set("min_membership_count", intValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount)) + d.Set("min_membership_count", flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount)) d.Set("target_manager_name", *instanceGroupManagerScheduledActionManagerManager.Name) d.Set("target_manager", *instanceGroupManagerScheduledActionManagerManager.ID) } diff --git a/ibm/data_source_ibm_is_instance_group_manager_action_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_action_test.go similarity index 94% rename from ibm/data_source_ibm_is_instance_group_manager_action_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_action_test.go index 021b0dc51..27995593a 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_action_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_action_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ func TestAccIBMISInstanceGroupManagerAction_dataBasic(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManageraction := fmt.Sprintf("testinstancegroupmanageraction%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerActionDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_instance_group_manager_actions.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions.go similarity index 91% rename from ibm/data_source_ibm_is_instance_group_manager_actions.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions.go index d9f5487a0..02473ec7c 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_actions.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManagerActions() *schema.Resource { +func DataSourceIBMISInstanceGroupManagerActions() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagerActionsRead, @@ -170,12 +171,12 @@ func dataSourceIBMISInstanceGroupManagerActionsRead(d *schema.ResourceData, meta } instanceGroupManagerActionsCollection, response, err := sess.ListInstanceGroupManagerActions(&listInstanceGroupManagerActionsOptions) if err != nil { - return fmt.Errorf("error Getting InstanceGroup Manager Actions %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Actions %s\n%s", err, response) } if instanceGroupManagerActionsCollection != nil && *instanceGroupManagerActionsCollection.TotalCount == int64(0) { break } - start = GetNext(instanceGroupManagerActionsCollection.Next) + start = flex.GetNext(instanceGroupManagerActionsCollection.Next) allrecs = append(allrecs, instanceGroupManagerActionsCollection.Actions...) if start == "" { break @@ -189,7 +190,7 @@ func dataSourceIBMISInstanceGroupManagerActionsRead(d *schema.ResourceData, meta action := map[string]interface{}{ "name": *instanceGroupManagerAction.Name, "auto_delete": *instanceGroupManagerAction.AutoDelete, - "auto_delete_timeout": intValue(instanceGroupManagerAction.AutoDeleteTimeout), + "auto_delete_timeout": flex.IntValue(instanceGroupManagerAction.AutoDeleteTimeout), "created_at": instanceGroupManagerAction.CreatedAt.String(), "action_id": *instanceGroupManagerAction.ID, "resource_type": *instanceGroupManagerAction.ResourceType, @@ -208,7 +209,7 @@ func dataSourceIBMISInstanceGroupManagerActionsRead(d *schema.ResourceData, meta } instanceGroupManagerScheduledActionGroupGroup := instanceGroupManagerAction.Group if instanceGroupManagerScheduledActionGroupGroup != nil && instanceGroupManagerScheduledActionGroupGroup.MembershipCount != nil { - action["membership_count"] = intValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount) + action["membership_count"] = flex.IntValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount) } instanceGroupManagerScheduledActionManagerManagerInt := instanceGroupManagerAction.Manager if instanceGroupManagerScheduledActionManagerManagerInt != nil { @@ -216,9 +217,9 @@ func dataSourceIBMISInstanceGroupManagerActionsRead(d *schema.ResourceData, meta if instanceGroupManagerScheduledActionManagerManager != nil && instanceGroupManagerScheduledActionManagerManager.ID != nil { if instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount != nil { - action["max_membership_count"] = intValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount) + action["max_membership_count"] = flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount) } - action["min_membership_count"] = intValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount) + action["min_membership_count"] = flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount) action["target_manager_name"] = *instanceGroupManagerScheduledActionManagerManager.Name action["target_manager"] = *instanceGroupManagerScheduledActionManagerManager.ID } diff --git a/ibm/data_source_ibm_is_instance_group_manager_actions_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions_test.go similarity index 94% rename from ibm/data_source_ibm_is_instance_group_manager_actions_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions_test.go index d6fbed09b..b8aa4f6d7 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_actions_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_actions_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ func TestAccIBMISInstanceGroupManagerActions_dataBasic(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManagerAction := fmt.Sprintf("testinstancegroupmanageraction%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerActionDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_instance_group_manager_policies.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies.go similarity index 92% rename from ibm/data_source_ibm_is_instance_group_manager_policies.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies.go index 91634ce10..bbdbe7709 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_policies.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManagerPolicies() *schema.Resource { +func DataSourceIBMISInstanceGroupManagerPolicies() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagerPoliciesRead, @@ -100,9 +101,9 @@ func dataSourceIBMISInstanceGroupManagerPoliciesRead(d *schema.ResourceData, met } instanceGroupManagerPolicyCollection, response, err := sess.ListInstanceGroupManagerPolicies(&listInstanceGroupManagerPoliciesOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Manager Policies %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Policies %s\n%s", err, response) } - start = GetNext(instanceGroupManagerPolicyCollection.Next) + start = flex.GetNext(instanceGroupManagerPolicyCollection.Next) allrecs = append(allrecs, instanceGroupManagerPolicyCollection.Policies...) if start == "" { break diff --git a/ibm/data_source_ibm_is_instance_group_manager_policies_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies_test.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_manager_policies_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies_test.go index 6aa540840..2ea459f06 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_policies_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policies_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ func TestAccIBMISInstanceGroupManagerPolicies_dataBasic(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManagerPolicy := fmt.Sprintf("testinstancegroupmanagerpolicy%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerPolicyDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_instance_group_manager_policy.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy.go similarity index 90% rename from ibm/data_source_ibm_is_instance_group_manager_policy.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy.go index a15aaa7f5..4287407e1 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_policy.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManagerPolicy() *schema.Resource { +func DataSourceIBMISInstanceGroupManagerPolicy() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagerPolicyRead, @@ -84,9 +85,9 @@ func dataSourceIBMISInstanceGroupManagerPolicyRead(d *schema.ResourceData, meta } instanceGroupManagerPolicyCollection, response, err := sess.ListInstanceGroupManagerPolicies(&listInstanceGroupManagerPoliciesOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Manager Policies %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Policies %s\n%s", err, response) } - start = GetNext(instanceGroupManagerPolicyCollection.Next) + start = flex.GetNext(instanceGroupManagerPolicyCollection.Next) allrecs = append(allrecs, instanceGroupManagerPolicyCollection.Policies...) if start == "" { break diff --git a/ibm/data_source_ibm_is_instance_group_manager_policy_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy_test.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_manager_policy_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy_test.go index 2efc369de..5be4f8bf1 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_policy_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_policy_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ func TestAccIBMISInstanceGroupManagerPolicy_dataBasic(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManagerPolicy := fmt.Sprintf("testinstancegroupmanagerpolicy%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerPolicyDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_instance_group_manager_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_test.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_manager_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_manager_test.go index ab6d41c6d..cbfa84836 100644 --- a/ibm/data_source_ibm_is_instance_group_manager_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_manager_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -24,8 +26,8 @@ func TestAccIBMISInstanceGroupManager_dataBasic(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagerDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), @@ -56,8 +58,8 @@ func TestAccIBMISInstanceGroupManager_dataBasic_scheduled(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagerDConfigScheduled(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), diff --git a/ibm/data_source_ibm_is_instance_group_managers.go b/ibm/service/vpc/data_source_ibm_is_instance_group_managers.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_managers.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_managers.go index dfec1220e..fe68e482e 100644 --- a/ibm/data_source_ibm_is_instance_group_managers.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_managers.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceGroupManagers() *schema.Resource { +func DataSourceIBMISInstanceGroupManagers() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupManagersRead, @@ -133,10 +134,10 @@ func dataSourceIBMISInstanceGroupManagersRead(d *schema.ResourceData, meta inter } instanceGroupManagerCollections, response, err := sess.ListInstanceGroupManagers(&listInstanceGroupManagerOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Managers %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Managers %s\n%s", err, response) } - start = GetNext(instanceGroupManagerCollections.Next) + start = flex.GetNext(instanceGroupManagerCollections.Next) allrecs = append(allrecs, instanceGroupManagerCollections.Managers...) if start == "" { diff --git a/ibm/data_source_ibm_is_instance_group_managers_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_managers_test.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_managers_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_managers_test.go index 8d2006179..b7bb66b53 100644 --- a/ibm/data_source_ibm_is_instance_group_managers_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_managers_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -24,8 +26,8 @@ func TestAccIBMISInstanceGroupManagers_dataBasic(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagersDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), @@ -56,8 +58,8 @@ func TestAccIBMISInstanceGroupManagers_dataBasic_scheduled(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagersDConfigScheduled(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), diff --git a/ibm/data_source_ibm_is_instance_group_membership.go b/ibm/service/vpc/data_source_ibm_is_instance_group_membership.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_membership.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_membership.go index 9310f7f01..140416ea2 100644 --- a/ibm/data_source_ibm_is_instance_group_membership.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_membership.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIBMISInstanceGroupMembership() *schema.Resource { +func DataSourceIBMISInstanceGroupMembership() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupMembershipRead, @@ -115,10 +116,10 @@ func dataSourceIBMISInstanceGroupMembershipRead(d *schema.ResourceData, meta int } instanceGroupMembershipCollection, response, err := sess.ListInstanceGroupMemberships(&listInstanceGroupMembershipsOptions) if err != nil || instanceGroupMembershipCollection == nil { - return fmt.Errorf("Error Getting InstanceGroup Membership Collection %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Membership Collection %s\n%s", err, response) } - start = GetNext(instanceGroupMembershipCollection.Next) + start = flex.GetNext(instanceGroupMembershipCollection.Next) allrecs = append(allrecs, instanceGroupMembershipCollection.Memberships...) if start == "" { diff --git a/ibm/data_source_ibm_is_instance_group_membership_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_membership_test.go similarity index 93% rename from ibm/data_source_ibm_is_instance_group_membership_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_membership_test.go index a70506d30..842f85ad6 100644 --- a/ibm/data_source_ibm_is_instance_group_membership_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_membership_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -23,8 +25,8 @@ func TestAccIbmIsInstanceGroupMembershipDataSource_Basic(t *testing.T) { templateName := fmt.Sprintf("testtemplate%d", randInt) sshKeyName := fmt.Sprintf("testsshkey%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmIsInstanceGroupMembershipDataSourceConfigBasic(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName), diff --git a/ibm/data_source_ibm_is_instance_group_memberships.go b/ibm/service/vpc/data_source_ibm_is_instance_group_memberships.go similarity index 95% rename from ibm/data_source_ibm_is_instance_group_memberships.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_memberships.go index 044575052..d39476f5c 100644 --- a/ibm/data_source_ibm_is_instance_group_memberships.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_memberships.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -16,7 +17,7 @@ const ( isInstanceGroupMemberships = "memberships" ) -func dataSourceIBMISInstanceGroupMemberships() *schema.Resource { +func DataSourceIBMISInstanceGroupMemberships() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceGroupMembershipsRead, @@ -130,10 +131,10 @@ func dataSourceIBMISInstanceGroupMembershipsRead(d *schema.ResourceData, meta in } instanceGroupMembershipCollection, response, err := sess.ListInstanceGroupMemberships(&listInstanceGroupMembershipsOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Membership Collection %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Membership Collection %s\n%s", err, response) } - start = GetNext(instanceGroupMembershipCollection.Next) + start = flex.GetNext(instanceGroupMembershipCollection.Next) allrecs = append(allrecs, instanceGroupMembershipCollection.Memberships...) if start == "" { diff --git a/ibm/data_source_ibm_is_instance_group_memberships_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_memberships_test.go similarity index 93% rename from ibm/data_source_ibm_is_instance_group_memberships_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_memberships_test.go index b00f63aa4..f9d0395da 100644 --- a/ibm/data_source_ibm_is_instance_group_memberships_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_memberships_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -23,10 +25,10 @@ func TestAccIbmIsInstanceGroupMembershipsDataSource_Basic(t *testing.T) { templateName := fmt.Sprintf("testtemplate%d", randInt) sshKeyName := fmt.Sprintf("testsshkey%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIsInstanceGroupMembershipsDataSourceConfigBasic(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName), Check: resource.ComposeTestCheckFunc( // resource.TestCheckResourceAttrSet("data.ibm_is_instance_group_memberships.is_instance_group_memberships", "id"), diff --git a/ibm/data_source_ibm_is_instance_group_test.go b/ibm/service/vpc/data_source_ibm_is_instance_group_test.go similarity index 92% rename from ibm/data_source_ibm_is_instance_group_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_group_test.go index f256a5cb4..8b8f1abc6 100644 --- a/ibm/data_source_ibm_is_instance_group_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_group_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -23,8 +25,8 @@ func TestAccIBMISInstanceGroup_dataBasic(t *testing.T) { templateName := fmt.Sprintf("testtemplate%d", randInt) sshKeyName := fmt.Sprintf("testsshkey%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/service/vpc/data_source_ibm_is_instance_groups.go b/ibm/service/vpc/data_source_ibm_is_instance_groups.go new file mode 100644 index 000000000..bbfae2b0f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_groups.go @@ -0,0 +1,634 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISInstanceGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: DataSourceIBMIsInstanceGroupsRead, + + Schema: map[string]*schema.Schema{ + "instance_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of instance groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "application_port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Required if specifying a load balancer pool only. Used by the instance group when scaling up instances to supply the port for the load balancer pool member.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the instance group was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this instance group.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance group.", + }, + "instance_template": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The template used to create new instances for this group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this instance template.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance template.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance template.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this instance template.", + }, + }, + }, + }, + "load_balancer_pool": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The load balancer pool managed by this group. Instances createdby this group will have a new load balancer pool member in thatpool created.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + }, + }, + }, + "managers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The managers for the instance group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance group manager.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance group manager.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this instance group manager.", + }, + }, + }, + }, + "membership_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of instances in the instance group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this instance group.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the instance group- `deleting`: Group is being deleted- `healthy`: Group has `membership_count` instances- `scaling`: Instances in the group are being created or deleted to reach `membership_count`- `unhealthy`: Group is unable to reach `membership_count` instances.", + }, + "subnets": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The subnets to use when creating new instances.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the instance group was updated.", + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC the instance group resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMIsInstanceGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.InstanceGroup{} + listInstanceGroupsOptions := &vpcv1.ListInstanceGroupsOptions{} + for { + + if start != "" { + listInstanceGroupsOptions.Start = &start + } + + instanceGroupCollection, response, err := vpcClient.ListInstanceGroupsWithContext(context, listInstanceGroupsOptions) + if err != nil { + log.Printf("[DEBUG] ListInstanceGroupsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListInstanceGroupsWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(instanceGroupCollection.Next) + allrecs = append(allrecs, instanceGroupCollection.InstanceGroups...) + if start == "" { + break + } + } + + d.SetId(DataSourceIBMIsInstanceGroupsID(d)) + + instanceGroups := []map[string]interface{}{} + + for _, instanceGroupItem := range allrecs { + instanceGroup, err := DataSourceIBMIsInstanceGroupsInstanceGroupToMap(&instanceGroupItem) + if err != nil { + return diag.FromErr(err) + } + instanceGroups = append(instanceGroups, instanceGroup) + } + + if err = d.Set("instance_groups", instanceGroups); err != nil { + return diag.FromErr(fmt.Errorf("Error setting instance_groups %s", err)) + } + + return nil +} + +// DataSourceIBMIsInstanceGroupsID returns a reasonable ID for the list. +func DataSourceIBMIsInstanceGroupsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsInstanceGroupsInstanceGroupCollectionFirstToMap(model *vpcv1.InstanceGroupCollectionFirst) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsInstanceGroupToMap(model *vpcv1.InstanceGroup) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.ApplicationPort != nil { + modelMap["application_port"] = *model.ApplicationPort + } + if model.CreatedAt != nil { + modelMap["created_at"] = model.CreatedAt.String() + } + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.InstanceTemplate != nil { + instanceTemplateMap, err := DataSourceIBMIsInstanceGroupsInstanceTemplateReferenceToMap(model.InstanceTemplate) + if err != nil { + return modelMap, err + } + modelMap["instance_template"] = []map[string]interface{}{instanceTemplateMap} + } + if model.LoadBalancerPool != nil { + loadBalancerPoolMap, err := DataSourceIBMIsInstanceGroupsLoadBalancerPoolReferenceToMap(model.LoadBalancerPool) + if err != nil { + return modelMap, err + } + modelMap["load_balancer_pool"] = []map[string]interface{}{loadBalancerPoolMap} + } + if model.Managers != nil { + managers := []map[string]interface{}{} + for _, managersItem := range model.Managers { + managersItemMap, err := DataSourceIBMIsInstanceGroupsInstanceGroupManagerReferenceToMap(&managersItem) + if err != nil { + return modelMap, err + } + managers = append(managers, managersItemMap) + } + modelMap["managers"] = managers + } + if model.MembershipCount != nil { + modelMap["membership_count"] = *model.MembershipCount + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceGroup != nil { + resourceGroupMap, err := DataSourceIBMIsInstanceGroupsResourceGroupReferenceToMap(model.ResourceGroup) + if err != nil { + return modelMap, err + } + modelMap["resource_group"] = []map[string]interface{}{resourceGroupMap} + } + if model.Status != nil { + modelMap["status"] = *model.Status + } + if model.Subnets != nil { + subnets := []map[string]interface{}{} + for _, subnetsItem := range model.Subnets { + subnetsItemMap, err := DataSourceIBMIsInstanceGroupsSubnetReferenceToMap(&subnetsItem) + if err != nil { + return modelMap, err + } + subnets = append(subnets, subnetsItemMap) + } + modelMap["subnets"] = subnets + } + if model.UpdatedAt != nil { + modelMap["updated_at"] = model.UpdatedAt.String() + } + if model.VPC != nil { + vpcMap, err := DataSourceIBMIsInstanceGroupsVPCReferenceToMap(model.VPC) + if err != nil { + return modelMap, err + } + modelMap["vpc"] = []map[string]interface{}{vpcMap} + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsInstanceTemplateReferenceToMap(model *vpcv1.InstanceTemplateReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceGroupsInstanceTemplateReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsInstanceTemplateReferenceDeletedToMap(model *vpcv1.InstanceTemplateReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsLoadBalancerPoolReferenceToMap(model *vpcv1.LoadBalancerPoolReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceGroupsLoadBalancerPoolReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsLoadBalancerPoolReferenceDeletedToMap(model *vpcv1.LoadBalancerPoolReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsInstanceGroupManagerReferenceToMap(model *vpcv1.InstanceGroupManagerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceGroupsInstanceGroupManagerReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsInstanceGroupManagerReferenceDeletedToMap(model *vpcv1.InstanceGroupManagerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsResourceGroupReferenceToMap(model *vpcv1.ResourceGroupReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceGroupsSubnetReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceGroupsVPCReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceGroupsVPCReferenceDeletedToMap(model *vpcv1.VPCReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_groups_test.go b/ibm/service/vpc/data_source_ibm_is_instance_groups_test.go new file mode 100644 index 000000000..95084384b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_groups_test.go @@ -0,0 +1,59 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsInstanceGroupsDataSourceBasic(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + instanceGroupName := fmt.Sprintf("testinstancegroup%d", randInt) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceGroupsDataSourceConfigBasic(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.instance_template.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.managers.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.membership_count"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.subnets.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_groups.is_instance_groups", "instance_groups.0.vpc.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceGroupsDataSourceConfigBasic(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName string) string { + return testAccCheckIBMISInstanceGroupConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName) + fmt.Sprintf(` + data "ibm_is_instance_groups" "is_instance_groups" { + depends_on = [ibm_is_instance_group.instance_group] + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface.go new file mode 100644 index 000000000..bba64f8c0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface.go @@ -0,0 +1,506 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceNetworkInterface() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceNetworkInterfaceRead, + + Schema: map[string]*schema.Schema{ + "instance_name": { + Type: schema.TypeString, + Required: true, + Description: "The instance name.", + }, + "network_interface_name": { + Type: schema.TypeString, + Required: true, + Description: "The network interface name.", + }, + "allow_ip_spoofing": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the network interface was created.", + }, + "floating_ips": { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this floating IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + "port_speed": { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps.", + }, + "primary_ipv4_address": { + Type: schema.TypeString, + Computed: true, + Description: "The primary IPv4 address.", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of security groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface.", + }, + "subnet": { + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of this network interface as it relates to an instance.", + }, + }, + } +} + +func dataSourceIBMIsInstanceNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + instance_name := d.Get("instance_name").(string) + listInstancesOptions := &vpcv1.ListInstancesOptions{} + + start := "" + allrecs := []vpcv1.Instance{} + for { + + if start != "" { + listInstancesOptions.Start = &start + } + + instances, response, err := vpcClient.ListInstancesWithContext(context, listInstancesOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Fetching Instances %s\n%s", err, response)) + } + start = flex.GetNext(instances.Next) + allrecs = append(allrecs, instances.Instances...) + if start == "" { + break + } + } + + ins_id := "" + for _, instance := range allrecs { + if *instance.Name == instance_name { + ins_id = *instance.ID + listInstanceNetworkInterfacesOptions := &vpcv1.ListInstanceNetworkInterfacesOptions{ + InstanceID: &ins_id, + } + networkInterfaceCollection, response, err := vpcClient.ListInstanceNetworkInterfacesWithContext(context, listInstanceNetworkInterfacesOptions) + + if err != nil { + log.Printf("[DEBUG] ListSecurityGroupNetworkInterfacesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListSecurityGroupNetworkInterfacesWithContext failed %s\n%s", err, response)) + } + network_interface_name := d.Get("network_interface_name").(string) + for _, networkInterface := range networkInterfaceCollection.NetworkInterfaces { + if *networkInterface.Name == network_interface_name { + d.SetId(fmt.Sprintf("%s/%s", ins_id, *networkInterface.ID)) + if err = d.Set("allow_ip_spoofing", networkInterface.AllowIPSpoofing); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allow_ip_spoofing: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(networkInterface.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + + if networkInterface.FloatingIps != nil { + err = d.Set("floating_ips", dataSourceNetworkInterfaceFlattenFloatingIps(networkInterface.FloatingIps)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting floating_ips %s", err)) + } + } + if err = d.Set("href", networkInterface.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("name", networkInterface.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(networkInterface.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("primary_ipv4_address", networkInterface.PrimaryIP.Address); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_ipv4_address: %s", err)) + } + if networkInterface.PrimaryIP != nil { + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + if networkInterface.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *networkInterface.PrimaryIP.Address + } + if networkInterface.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *networkInterface.PrimaryIP.Href + } + if networkInterface.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *networkInterface.PrimaryIP.Name + } + if networkInterface.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *networkInterface.PrimaryIP.ID + } + if networkInterface.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *networkInterface.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentPrimIp) + d.Set(isInstanceNicPrimaryIP, primaryIpList) + } + if err = d.Set("resource_type", networkInterface.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + if networkInterface.SecurityGroups != nil { + err = d.Set("security_groups", dataSourceNetworkInterfaceFlattenSecurityGroups(networkInterface.SecurityGroups)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting security_groups %s", err)) + } + } + if err = d.Set("status", networkInterface.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + + if networkInterface.Subnet != nil { + err = d.Set("subnet", dataSourceNetworkInterfaceFlattenSubnet(*networkInterface.Subnet)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnet %s", err)) + } + } + if err = d.Set("type", networkInterface.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + return nil + } + } + return diag.FromErr(fmt.Errorf("Network interface %s not found.", network_interface_name)) + } + } + + return diag.FromErr(fmt.Errorf("Instance %s not found. %s", instance_name, err)) +} + +func dataSourceNetworkInterfaceFlattenFloatingIps(result []vpcv1.FloatingIPReference) (floatingIps []map[string]interface{}) { + for _, floatingIpsItem := range result { + floatingIps = append(floatingIps, dataSourceNetworkInterfaceFloatingIpsToMap(floatingIpsItem)) + } + + return floatingIps +} + +func dataSourceNetworkInterfaceFloatingIpsToMap(floatingIpsItem vpcv1.FloatingIPReference) (floatingIpsMap map[string]interface{}) { + floatingIpsMap = map[string]interface{}{} + + if floatingIpsItem.Address != nil { + floatingIpsMap["address"] = floatingIpsItem.Address + } + if floatingIpsItem.CRN != nil { + floatingIpsMap["crn"] = floatingIpsItem.CRN + } + if floatingIpsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkInterfaceFloatingIpsDeletedToMap(*floatingIpsItem.Deleted) + deletedList = append(deletedList, deletedMap) + floatingIpsMap["deleted"] = deletedList + } + if floatingIpsItem.Href != nil { + floatingIpsMap["href"] = floatingIpsItem.Href + } + if floatingIpsItem.ID != nil { + floatingIpsMap["id"] = floatingIpsItem.ID + } + if floatingIpsItem.Name != nil { + floatingIpsMap["name"] = floatingIpsItem.Name + } + + return floatingIpsMap +} + +func dataSourceNetworkInterfaceFloatingIpsDeletedToMap(deletedItem vpcv1.FloatingIPReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkInterfaceFlattenSecurityGroups(result []vpcv1.SecurityGroupReference) (securityGroups []map[string]interface{}) { + for _, securityGroupsItem := range result { + securityGroups = append(securityGroups, dataSourceNetworkInterfaceSecurityGroupsToMap(securityGroupsItem)) + } + + return securityGroups +} + +func dataSourceNetworkInterfaceSecurityGroupsToMap(securityGroupsItem vpcv1.SecurityGroupReference) (securityGroupsMap map[string]interface{}) { + securityGroupsMap = map[string]interface{}{} + + if securityGroupsItem.CRN != nil { + securityGroupsMap["crn"] = securityGroupsItem.CRN + } + if securityGroupsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkInterfaceSecurityGroupsDeletedToMap(*securityGroupsItem.Deleted) + deletedList = append(deletedList, deletedMap) + securityGroupsMap["deleted"] = deletedList + } + if securityGroupsItem.Href != nil { + securityGroupsMap["href"] = securityGroupsItem.Href + } + if securityGroupsItem.ID != nil { + securityGroupsMap["id"] = securityGroupsItem.ID + } + if securityGroupsItem.Name != nil { + securityGroupsMap["name"] = securityGroupsItem.Name + } + + return securityGroupsMap +} + +func dataSourceNetworkInterfaceSecurityGroupsDeletedToMap(deletedItem vpcv1.SecurityGroupReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkInterfaceFlattenSubnet(result vpcv1.SubnetReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceNetworkInterfaceSubnetToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceNetworkInterfaceSubnetToMap(subnetItem vpcv1.SubnetReference) (subnetMap map[string]interface{}) { + subnetMap = map[string]interface{}{} + + if subnetItem.CRN != nil { + subnetMap["crn"] = subnetItem.CRN + } + if subnetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkInterfaceSubnetDeletedToMap(*subnetItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetMap["deleted"] = deletedList + } + if subnetItem.Href != nil { + subnetMap["href"] = subnetItem.Href + } + if subnetItem.ID != nil { + subnetMap["id"] = subnetItem.ID + } + if subnetItem.Name != nil { + subnetMap["name"] = subnetItem.Name + } + + return subnetMap +} + +func dataSourceNetworkInterfaceSubnetDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip.go new file mode 100644 index 000000000..49fd59f5b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip.go @@ -0,0 +1,143 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Request Param Constants + isInstanceNICID = "network_interface" + isInstanceNICReservedIPID = "reserved_ip" + + // Response Param Constants + isInstanceNICReservedIPAddress = "address" + isInstanceNICReservedIPAutoDelete = "auto_delete" + isInstanceNICReservedIPCreatedAt = "created_at" + isInstanceNICReservedIPhref = "href" + isInstanceNICReservedIPName = "name" + isInstanceNICReservedIPOwner = "owner" + isInstanceNICReservedIPType = "resource_type" + isInstanceNICReservedIPTarget = "target" +) + +func DataSourceIBMISInstanceNICReservedIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISInstanceNICReservedIPRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "The instance identifier.", + }, + isInstanceNICID: { + Type: schema.TypeString, + Required: true, + Description: "The instance network interface identifier.", + }, + isInstanceNICReservedIPID: { + Type: schema.TypeString, + Required: true, + Description: "The reserved IP identifier.", + }, + + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isInstanceNICReservedIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isInstanceNICReservedIPAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, this reserved IP will be automatically deleted", + }, + isInstanceNICReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isInstanceNICReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isInstanceNICReservedIPName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isInstanceNICReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isInstanceNICReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isInstanceNICReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id.", + }, + }, + } +} + +// dataSourceIBMISInstanceNICReservedIPRead is used when the reserved IPs are read from the vpc +func dataSourceIBMISInstanceNICReservedIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + instance := d.Get(isInstanceID).(string) + instanceNICId := d.Get(isInstanceNICID).(string) + reservedIPID := d.Get(isInstanceNICReservedIPID).(string) + + options := sess.NewGetInstanceNetworkInterfaceIPOptions(instance, instanceNICId, reservedIPID) + reserveIP, response, err := sess.GetInstanceNetworkInterfaceIPWithContext(context, options) + + if err != nil || response == nil || reserveIP == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching the reserved IP %s\n%s", err, response)) + } + + d.SetId(*reserveIP.ID) + d.Set(isInstanceNICReservedIPAutoDelete, *reserveIP.AutoDelete) + d.Set(isInstanceNICReservedIPCreatedAt, (*reserveIP.CreatedAt).String()) + d.Set(isInstanceNICReservedIPhref, *reserveIP.Href) + d.Set(isInstanceNICReservedIPName, *reserveIP.Name) + d.Set(isInstanceNICReservedIPOwner, *reserveIP.Owner) + d.Set(isInstanceNICReservedIPType, *reserveIP.ResourceType) + d.Set(isInstanceNICReservedIPAddress, *reserveIP.Address) + if reserveIP.Target != nil { + target, ok := reserveIP.Target.(*vpcv1.ReservedIPTarget) + if ok { + d.Set(isInstanceNICReservedIPTarget, target.ID) + } + } + return nil // By default there should be no error +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip_test.go new file mode 100644 index 000000000..371baa796 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip_test.go @@ -0,0 +1,93 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceNICReservedIP_basic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + ripname := fmt.Sprintf("tf-rip-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIBMISInstanceNICReservedIPdataSoruceConfig(vpcname, subnetname, ripname, sshname, publicKey, insname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcname), + resource.TestCheckResourceAttr("ibm_is_subnet.testacc_subnet", "name", subnetname), + resource.TestCheckResourceAttr("ibm_is_ssh_key.testacc_sshkey", "name", sshname), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance", "name", insname), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "id"), + resource.TestCheckResourceAttr("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "name", ripname), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ip.instance_network_interface_reserved_ip", "target"), + ), + }, + }, + }) +} + +func testAccIBMISInstanceNICReservedIPdataSoruceConfig(vpcname, subnetname, ripname, sshname, publicKey, insname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + data "ibm_is_instance_network_interface_reserved_ip" "instance_network_interface_reserved_ip" { + instance = ibm_is_instance.testacc_instance.id + network_interface = ibm_is_instance.testacc_instance.primary_network_interface.0.id + reserved_ip = ibm_is_instance.testacc_instance.primary_network_interface.0.primary_ip.0.reserved_ip + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, ripname, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips.go new file mode 100644 index 000000000..db39ddd2a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips.go @@ -0,0 +1,172 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Request Param Constants + isInstanceNICReservedIPLimit = "limit" + isInstanceNICReservedIPSort = "sort" + isInstanceNICReservedIPs = "reserved_ips" + isInstanceNICReservedIPsCount = "total_count" +) + +func DataSourceIBMISInstanceNICReservedIPs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISInstanceNICReservedIPsRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isInstanceID: { + Type: schema.TypeString, + Required: true, + Description: "The instance identifier.", + }, + isInstanceNICID: { + Type: schema.TypeString, + Required: true, + Description: "The instance network interface identifier.", + }, + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isInstanceNICReservedIPs: { + Type: schema.TypeList, + Description: "Collection of reserved IPs in this subnet.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNICReservedIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isInstanceNICReservedIPAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If reserved ip shall be deleted automatically", + }, + isInstanceNICReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isInstanceNICReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isInstanceNICReservedIPID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP", + }, + isInstanceNICReservedIPName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isInstanceNICReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isInstanceNICReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isInstanceNICReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id", + }, + }, + }, + }, + isInstanceNICReservedIPsCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of resources across all pages", + }, + }, + } +} + +func dataSourceIBMISInstanceNICReservedIPsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + instanceID := d.Get(isInstanceID).(string) + nicID := d.Get(isInstanceNICID).(string) + + // Flatten all the reserved IPs + start := "" + allrecs := []vpcv1.ReservedIP{} + for { + options := &vpcv1.ListInstanceNetworkInterfaceIpsOptions{ + InstanceID: &instanceID, + NetworkInterfaceID: &nicID, + } + if start != "" { + options.Start = &start + } + + result, response, err := sess.ListInstanceNetworkInterfaceIpsWithContext(context, options) + if err != nil || response == nil || result == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching reserved ips %s\n%s", err, response)) + } + start = flex.GetNext(result.Next) + allrecs = append(allrecs, result.Ips...) + if start == "" { + break + } + } + // Now store all the reserved IP info with their response tags + reservedIPs := []map[string]interface{}{} + for _, data := range allrecs { + ipsOutput := map[string]interface{}{} + ipsOutput[isInstanceNICReservedIPAddress] = *data.Address + ipsOutput[isInstanceNICReservedIPAutoDelete] = *data.AutoDelete + ipsOutput[isInstanceNICReservedIPCreatedAt] = (*data.CreatedAt).String() + ipsOutput[isInstanceNICReservedIPhref] = *data.Href + ipsOutput[isInstanceNICReservedIPID] = *data.ID + ipsOutput[isInstanceNICReservedIPName] = *data.Name + ipsOutput[isInstanceNICReservedIPOwner] = *data.Owner + ipsOutput[isInstanceNICReservedIPType] = *data.ResourceType + target, ok := data.Target.(*vpcv1.ReservedIPTarget) + if ok { + ipsOutput[isReservedIPTarget] = target.ID + } + reservedIPs = append(reservedIPs, ipsOutput) + } + + d.SetId(time.Now().UTC().String()) // This is not any reserved ip or instance id but state id + d.Set(isInstanceNICReservedIPs, reservedIPs) + d.Set(isInstanceNICReservedIPsCount, len(reservedIPs)) + d.Set(isInstanceID, instanceID) + d.Set(isInstanceNICID, nicID) + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips_test.go new file mode 100644 index 000000000..82fff4d74 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips_test.go @@ -0,0 +1,95 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceNICReservedIPs_basic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + ripname := fmt.Sprintf("tf-rip-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIBMISInstanceNICReservedIPSResoruceConfig2(vpcname, subnetname, ripname, sshname, publicKey, insname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.testacc_vpc", "name", vpcname), + resource.TestCheckResourceAttr("ibm_is_subnet.testacc_subnet", "name", subnetname), + resource.TestCheckResourceAttr("ibm_is_ssh_key.testacc_sshkey", "name", sshname), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance", "name", insname), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.reserved_ip"), + resource.TestCheckResourceAttr("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.name", ripname), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface_reserved_ips.instance_network_interface_reserved_ips", "reserved_ips.0.target"), + ), + }, + }, + }) +} + +func testAccIBMISInstanceNICReservedIPSResoruceConfig2(vpcname, subnetname, ripname, sshname, publicKey, insname string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + data "ibm_is_instance_network_interface_reserved_ips" "instance_network_interface_reserved_ips" { + instance = ibm_is_instance.testacc_instance.id + network_interface = ibm_is_instance.testacc_instance.primary_network_interface.0.id + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, ripname, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interface_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_test.go new file mode 100644 index 000000000..eca890cb9 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface_test.go @@ -0,0 +1,182 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsInstanceNetworkInterfaceDataSourceBasic(t *testing.T) { + + networkInterfaceName := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfaceDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, insname, networkInterfaceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ipv4_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ip.0.resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceNetworkInterfaceDataSourceAllArgs(t *testing.T) { + allowIPSpoofing := "false" + networkInterfaceName := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + primaryIpv4Address := "10.240.0.6" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfaceDataSourceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, networkInterfaceName, primaryIpv4Address), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "href"), + resource.TestCheckResourceAttr("data.ibm_is_instance_network_interface.is_instance_network_interface", "name", networkInterfaceName), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "primary_ipv4_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "security_groups.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interface.is_instance_network_interface", "type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkInterfaceDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, insname, name string) string { + + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + data "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance_name = ibm_is_instance.testacc_instance.name + network_interface_name = ibm_is_instance_network_interface.is_instance_network_interface.name + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, name) +} + +func testAccCheckIBMIsInstanceNetworkInterfaceDataSourceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + allow_ip_spoofing = %s + name = "%s" + primary_ipv4_address = "%s" + } + data "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance_name = ibm_is_instance.testacc_instance.name + network_interface_name = ibm_is_instance_network_interface.is_instance_network_interface.name + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, allowIPSpoofing, name, primaryIpv4Address) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces.go new file mode 100644 index 000000000..378498351 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces.go @@ -0,0 +1,415 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceNetworkInterfaces() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceNetworkInterfacesRead, + + Schema: map[string]*schema.Schema{ + "instance_name": { + Type: schema.TypeString, + Required: true, + Description: "The instance name.", + }, + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of network interfaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_ip_spoofing": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the network interface was created.", + }, + "floating_ips": { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this floating IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + "port_speed": { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps.", + }, + "primary_ipv4_address": { + Type: schema.TypeString, + Computed: true, + Description: "The primary IPv4 address.", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of security groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface.", + }, + "subnet": { + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of this network interface as it relates to an instance.", + }, + }, + }, + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of resources across all pages.", + }, + }, + } +} + +func dataSourceIBMIsInstanceNetworkInterfacesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + instance_name := d.Get("instance_name").(string) + listInstancesOptions := &vpcv1.ListInstancesOptions{} + + start := "" + allrecs := []vpcv1.Instance{} + for { + + if start != "" { + listInstancesOptions.Start = &start + } + + instances, response, err := vpcClient.ListInstances(listInstancesOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Fetching Instances %s\n%s", err, response)) + } + start = flex.GetNext(instances.Next) + allrecs = append(allrecs, instances.Instances...) + if start == "" { + break + } + } + + ins_id := "" + for _, instance := range allrecs { + if *instance.Name == instance_name { + ins_id = *instance.ID + listInstanceNetworkInterfacesOptions := &vpcv1.ListInstanceNetworkInterfacesOptions{ + InstanceID: &ins_id, + } + networkInterfaceCollection, response, err := vpcClient.ListInstanceNetworkInterfacesWithContext(context, listInstanceNetworkInterfacesOptions) + + if err != nil { + log.Printf("[DEBUG] ListSecurityGroupNetworkInterfacesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListSecurityGroupNetworkInterfacesWithContext failed %s\n%s", err, response)) + } + + d.SetId(ins_id) + + if networkInterfaceCollection.NetworkInterfaces != nil { + err = d.Set("network_interfaces", dataSourceNetworkInterfaceCollectionFlattenNetworkInterfaces(networkInterfaceCollection.NetworkInterfaces)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_interfaces %s", err)) + } + } + return nil + } + } + + return diag.FromErr(fmt.Errorf("Instance %s not found. %s", instance_name, err)) +} + +// dataSourceIBMIsInstanceNetworkInterfacesID returns a reasonable ID for the list. +func dataSourceIBMIsInstanceNetworkInterfacesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceNetworkInterfaceCollectionFlattenNetworkInterfaces(result []vpcv1.NetworkInterface) (networkInterfaces []map[string]interface{}) { + for _, networkInterfacesItem := range result { + networkInterfaces = append(networkInterfaces, dataSourceNetworkInterfaceCollectionNetworkInterfacesToMap(networkInterfacesItem)) + } + + return networkInterfaces +} + +func dataSourceNetworkInterfaceCollectionNetworkInterfacesToMap(networkInterfacesItem vpcv1.NetworkInterface) (networkInterfacesMap map[string]interface{}) { + networkInterfacesMap = map[string]interface{}{} + + if networkInterfacesItem.AllowIPSpoofing != nil { + networkInterfacesMap["allow_ip_spoofing"] = networkInterfacesItem.AllowIPSpoofing + } + if networkInterfacesItem.CreatedAt != nil { + networkInterfacesMap["created_at"] = networkInterfacesItem.CreatedAt.String() + } + if networkInterfacesItem.FloatingIps != nil { + floatingIpsList := []map[string]interface{}{} + for _, floatingIpsItem := range networkInterfacesItem.FloatingIps { + floatingIpsList = append(floatingIpsList, dataSourceNetworkInterfaceFloatingIpsToMap(floatingIpsItem)) + } + networkInterfacesMap["floating_ips"] = floatingIpsList + } + if networkInterfacesItem.Href != nil { + networkInterfacesMap["href"] = networkInterfacesItem.Href + } + if networkInterfacesItem.ID != nil { + networkInterfacesMap["id"] = networkInterfacesItem.ID + } + if networkInterfacesItem.Name != nil { + networkInterfacesMap["name"] = networkInterfacesItem.Name + } + if networkInterfacesItem.PortSpeed != nil { + networkInterfacesMap["port_speed"] = networkInterfacesItem.PortSpeed + } + if networkInterfacesItem.PrimaryIP != nil { + networkInterfacesMap["primary_ipv4_address"] = networkInterfacesItem.PrimaryIP.Address + } + if networkInterfacesItem.PrimaryIP != nil { + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + + if networkInterfacesItem.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *networkInterfacesItem.PrimaryIP.Address + } + if networkInterfacesItem.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *networkInterfacesItem.PrimaryIP.Href + } + if networkInterfacesItem.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *networkInterfacesItem.PrimaryIP.Name + } + if networkInterfacesItem.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *networkInterfacesItem.PrimaryIP.ID + } + if networkInterfacesItem.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *networkInterfacesItem.PrimaryIP.ResourceType + } + + primaryIpList = append(primaryIpList, currentPrimIp) + networkInterfacesMap[isInstanceNicPrimaryIP] = primaryIpList + } + if networkInterfacesItem.ResourceType != nil { + networkInterfacesMap["resource_type"] = networkInterfacesItem.ResourceType + } + if networkInterfacesItem.SecurityGroups != nil { + securityGroupsList := []map[string]interface{}{} + for _, securityGroupsItem := range networkInterfacesItem.SecurityGroups { + securityGroupsList = append(securityGroupsList, dataSourceNetworkInterfaceSecurityGroupsToMap(securityGroupsItem)) + } + networkInterfacesMap["security_groups"] = securityGroupsList + } + if networkInterfacesItem.Status != nil { + networkInterfacesMap["status"] = networkInterfacesItem.Status + } + if networkInterfacesItem.Subnet != nil { + subnetList := []map[string]interface{}{} + subnetMap := dataSourceNetworkInterfaceSubnetToMap(*networkInterfacesItem.Subnet) + subnetList = append(subnetList, subnetMap) + networkInterfacesMap["subnet"] = subnetList + } + if networkInterfacesItem.Type != nil { + networkInterfacesMap["type"] = networkInterfacesItem.Type + } + + return networkInterfacesMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces_test.go new file mode 100644 index 000000000..7cb51eaed --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces_test.go @@ -0,0 +1,166 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsInstanceNetworkInterfacesDataSourceBasic(t *testing.T) { + + name := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfacesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, insname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ip.0.resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceNetworkInterfacesDataSourceAllArgs(t *testing.T) { + allowIPSpoofing := "false" + networkInterfaceName := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + primaryIpv4Address := "10.240.0.6" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfacesDataSourceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, networkInterfaceName, primaryIpv4Address), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.primary_ipv4_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_interfaces.is_instance_network_interfaces", "network_interfaces.0.type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkInterfacesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, insname, name string) string { + + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + data "ibm_is_instance_network_interfaces" "is_instance_network_interfaces" { + instance_name = ibm_is_instance.testacc_instance.name + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, name) +} + +func testAccCheckIBMIsInstanceNetworkInterfacesDataSourceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + allow_ip_spoofing = %s + name = "%s" + primary_ipv4_address = "%s" + } + data "ibm_is_instance_network_interfaces" "is_instance_network_interfaces" { + instance_name = ibm_is_instance.testacc_instance.name + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, allowIPSpoofing, name, primaryIpv4Address) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profile.go b/ibm/service/vpc/data_source_ibm_is_instance_profile.go new file mode 100644 index 000000000..935c88687 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile.go @@ -0,0 +1,1074 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceProfileName = "name" + isInstanceProfileFamily = "family" + isInstanceProfileArchitecture = "architecture" +) + +func DataSourceIBMISInstanceProfile() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISInstanceProfileRead, + + Schema: map[string]*schema.Schema{ + + isInstanceProfileName: { + Type: schema.TypeString, + Required: true, + }, + + isInstanceProfileFamily: { + Type: schema.TypeString, + Computed: true, + Description: "The product family this virtual server instance profile belongs to.", + }, + + isInstanceProfileArchitecture: { + Type: schema.TypeString, + Computed: true, + Description: "The default OS architecture for an instance with this profile.", + }, + + "architecture_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for the OS architecture.", + }, + + "architecture_values": { + Type: schema.TypeList, + Computed: true, + Description: "The supported OS architecture(s) for an instance with this profile.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "bandwidth": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_count": { + Type: schema.TypeList, + Computed: true, + Description: "GPU count of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_manufacturer": { + Type: schema.TypeList, + Computed: true, + Description: "GPU manufacturer of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The possible GPU manufacturer(s) for an instance with this profile", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "gpu_memory": { + Type: schema.TypeList, + Computed: true, + Description: "GPU memory of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_model": { + Type: schema.TypeList, + Computed: true, + Description: "GPU model of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The possible GPU model(s) for an instance with this profile", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "total_volume_bandwidth": { + Type: schema.TypeList, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes. An increase in this value will result in a corresponding decrease to total_network_bandwidth.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "disks": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of the instance profile's disks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "quantity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "size": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "supported_interface_types": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The supported disk interfaces used for attaching the disk.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "memory": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "port_speed": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + }, + }, + }, + "vcpu_architecture": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeString, + Computed: true, + Description: "The default VCPU architecture for an instance with this profile.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "The VCPU architecture for an instance with this profile.", + }, + }, + }, + }, + "vcpu_count": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstanceProfileRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isInstanceProfileName).(string) + err := instanceProfileGet(d, meta, name) + if err != nil { + return err + } + return nil +} + +func instanceProfileGet(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + getInstanceProfileOptions := &vpcv1.GetInstanceProfileOptions{ + Name: &name, + } + profile, _, err := sess.GetInstanceProfile(getInstanceProfileOptions) + if err != nil { + return err + } + // For lack of anything better, compose our id from profile name. + d.SetId(*profile.Name) + d.Set(isInstanceProfileName, *profile.Name) + d.Set(isInstanceProfileFamily, *profile.Family) + if profile.OsArchitecture != nil { + if profile.OsArchitecture.Default != nil { + d.Set(isInstanceProfileArchitecture, *profile.OsArchitecture.Default) + } + if profile.OsArchitecture.Type != nil { + d.Set("architecture_type", *profile.OsArchitecture.Type) + } + if profile.OsArchitecture.Values != nil { + d.Set("architecture_values", *&profile.OsArchitecture.Values) + } + + } + if profile.Bandwidth != nil { + err = d.Set("bandwidth", dataSourceInstanceProfileFlattenBandwidth(*profile.Bandwidth.(*vpcv1.InstanceProfileBandwidth))) + if err != nil { + return err + } + } + if profile.GpuCount != nil { + err = d.Set("gpu_count", dataSourceInstanceProfileFlattenGPUCount(*profile.GpuCount.(*vpcv1.InstanceProfileGpu))) + if err != nil { + return err + } + } + if profile.GpuMemory != nil { + err = d.Set("gpu_memory", dataSourceInstanceProfileFlattenGPUMemory(*profile.GpuMemory.(*vpcv1.InstanceProfileGpuMemory))) + if err != nil { + return err + } + } + if profile.GpuManufacturer != nil { + err = d.Set("gpu_manufacturer", dataSourceInstanceProfileFlattenGPUManufacturer(*profile.GpuManufacturer)) + if err != nil { + return err + } + } + if profile.GpuModel != nil { + err = d.Set("gpu_model", dataSourceInstanceProfileFlattenGPUModel(*profile.GpuModel)) + if err != nil { + return err + } + } + if profile.TotalVolumeBandwidth != nil { + err = d.Set("total_volume_bandwidth", dataSourceInstanceProfileFlattenTotalVolumeBandwidth(*profile.TotalVolumeBandwidth.(*vpcv1.InstanceProfileVolumeBandwidth))) + if err != nil { + return err + } + } + if profile.Disks != nil { + err = d.Set("disks", dataSourceInstanceProfileFlattenDisks(profile.Disks)) + if err != nil { + return err + } + } + if err = d.Set("href", profile.Href); err != nil { + return err + } + + if profile.Memory != nil { + err = d.Set("memory", dataSourceInstanceProfileFlattenMemory(*profile.Memory.(*vpcv1.InstanceProfileMemory))) + if err != nil { + return err + } + } + if profile.PortSpeed != nil { + err = d.Set("port_speed", dataSourceInstanceProfileFlattenPortSpeed(*profile.PortSpeed.(*vpcv1.InstanceProfilePortSpeed))) + if err != nil { + return err + } + } + + if profile.VcpuArchitecture != nil { + err = d.Set("vcpu_architecture", dataSourceInstanceProfileFlattenVcpuArchitecture(*profile.VcpuArchitecture)) + if err != nil { + return err + } + } + + if profile.VcpuCount != nil { + err = d.Set("vcpu_count", dataSourceInstanceProfileFlattenVcpuCount(*profile.VcpuCount.(*vpcv1.InstanceProfileVcpu))) + if err != nil { + return err + } + } + return nil +} + +func dataSourceInstanceProfileFlattenBandwidth(result vpcv1.InstanceProfileBandwidth) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileBandwidthToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileBandwidthToMap(bandwidthItem vpcv1.InstanceProfileBandwidth) (bandwidthMap map[string]interface{}) { + bandwidthMap = map[string]interface{}{} + + if bandwidthItem.Type != nil { + bandwidthMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Value != nil { + bandwidthMap["value"] = bandwidthItem.Value + } + if bandwidthItem.Default != nil { + bandwidthMap["default"] = bandwidthItem.Default + } + if bandwidthItem.Max != nil { + bandwidthMap["max"] = bandwidthItem.Max + } + if bandwidthItem.Min != nil { + bandwidthMap["min"] = bandwidthItem.Min + } + if bandwidthItem.Step != nil { + bandwidthMap["step"] = bandwidthItem.Step + } + if bandwidthItem.Values != nil { + bandwidthMap["values"] = bandwidthItem.Values + } + + return bandwidthMap +} + +func dataSourceInstanceProfileFlattenGPUCount(result vpcv1.InstanceProfileGpu) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileGPUCountToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileGPUCountToMap(bandwidthItem vpcv1.InstanceProfileGpu) (gpuCountMap map[string]interface{}) { + gpuCountMap = map[string]interface{}{} + + if bandwidthItem.Type != nil { + gpuCountMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Value != nil { + gpuCountMap["value"] = bandwidthItem.Value + } + if bandwidthItem.Default != nil { + gpuCountMap["default"] = bandwidthItem.Default + } + if bandwidthItem.Max != nil { + gpuCountMap["max"] = bandwidthItem.Max + } + if bandwidthItem.Min != nil { + gpuCountMap["min"] = bandwidthItem.Min + } + if bandwidthItem.Step != nil { + gpuCountMap["step"] = bandwidthItem.Step + } + if bandwidthItem.Values != nil { + gpuCountMap["values"] = bandwidthItem.Values + } + + return gpuCountMap +} + +func dataSourceInstanceProfileFlattenGPUManufacturer(result vpcv1.InstanceProfileGpuManufacturer) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileGPUManufacturerToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileGPUManufacturerToMap(bandwidthItem vpcv1.InstanceProfileGpuManufacturer) (gpuManufactrerMap map[string]interface{}) { + gpuManufactrerMap = map[string]interface{}{} + + if bandwidthItem.Type != nil { + gpuManufactrerMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Values != nil { + gpuManufactrerMap["values"] = bandwidthItem.Values + } + + return gpuManufactrerMap +} + +func dataSourceInstanceProfileFlattenGPUModel(result vpcv1.InstanceProfileGpuModel) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileGPUModelToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileGPUModelToMap(bandwidthItem vpcv1.InstanceProfileGpuModel) (gpuModel map[string]interface{}) { + gpuModelMap := map[string]interface{}{} + + if bandwidthItem.Type != nil { + gpuModelMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Values != nil { + gpuModelMap["values"] = bandwidthItem.Values + } + + return gpuModelMap +} + +func dataSourceInstanceProfileFlattenGPUMemory(result vpcv1.InstanceProfileGpuMemory) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileGPUMemoryToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileGPUMemoryToMap(bandwidthItem vpcv1.InstanceProfileGpuMemory) (gpuMemoryMap map[string]interface{}) { + gpuMemoryMap = map[string]interface{}{} + + if bandwidthItem.Type != nil { + gpuMemoryMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Value != nil { + gpuMemoryMap["value"] = bandwidthItem.Value + } + if bandwidthItem.Default != nil { + gpuMemoryMap["default"] = bandwidthItem.Default + } + if bandwidthItem.Max != nil { + gpuMemoryMap["max"] = bandwidthItem.Max + } + if bandwidthItem.Min != nil { + gpuMemoryMap["min"] = bandwidthItem.Min + } + if bandwidthItem.Step != nil { + gpuMemoryMap["step"] = bandwidthItem.Step + } + if bandwidthItem.Values != nil { + gpuMemoryMap["values"] = bandwidthItem.Values + } + + return gpuMemoryMap +} + +func dataSourceInstanceProfileFlattenMemory(result vpcv1.InstanceProfileMemory) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileMemoryToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileMemoryToMap(memoryItem vpcv1.InstanceProfileMemory) (memoryMap map[string]interface{}) { + memoryMap = map[string]interface{}{} + + if memoryItem.Type != nil { + memoryMap["type"] = memoryItem.Type + } + if memoryItem.Value != nil { + memoryMap["value"] = memoryItem.Value + } + if memoryItem.Default != nil { + memoryMap["default"] = memoryItem.Default + } + if memoryItem.Max != nil { + memoryMap["max"] = memoryItem.Max + } + if memoryItem.Min != nil { + memoryMap["min"] = memoryItem.Min + } + if memoryItem.Step != nil { + memoryMap["step"] = memoryItem.Step + } + if memoryItem.Values != nil { + memoryMap["values"] = memoryItem.Values + } + + return memoryMap +} + +func dataSourceInstanceProfileFlattenPortSpeed(result vpcv1.InstanceProfilePortSpeed) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfilePortSpeedToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfilePortSpeedToMap(portSpeedItem vpcv1.InstanceProfilePortSpeed) (portSpeedMap map[string]interface{}) { + portSpeedMap = map[string]interface{}{} + + if portSpeedItem.Type != nil { + portSpeedMap["type"] = portSpeedItem.Type + } + if portSpeedItem.Value != nil { + portSpeedMap["value"] = portSpeedItem.Value + } + + return portSpeedMap +} + +func dataSourceInstanceProfileFlattenVcpuArchitecture(result vpcv1.InstanceProfileVcpuArchitecture) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileVcpuArchitectureToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileVcpuArchitectureToMap(vcpuArchitectureItem vpcv1.InstanceProfileVcpuArchitecture) (vcpuArchitectureMap map[string]interface{}) { + vcpuArchitectureMap = map[string]interface{}{} + + if vcpuArchitectureItem.Default != nil { + vcpuArchitectureMap["default"] = vcpuArchitectureItem.Default + } + if vcpuArchitectureItem.Type != nil { + vcpuArchitectureMap["type"] = vcpuArchitectureItem.Type + } + if vcpuArchitectureItem.Value != nil { + vcpuArchitectureMap["value"] = vcpuArchitectureItem.Value + } + + return vcpuArchitectureMap +} + +func dataSourceInstanceProfileFlattenVcpuCount(result vpcv1.InstanceProfileVcpu) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileVcpuCountToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileVcpuCountToMap(vcpuCountItem vpcv1.InstanceProfileVcpu) (vcpuCountMap map[string]interface{}) { + vcpuCountMap = map[string]interface{}{} + + if vcpuCountItem.Type != nil { + vcpuCountMap["type"] = vcpuCountItem.Type + } + if vcpuCountItem.Value != nil { + vcpuCountMap["value"] = vcpuCountItem.Value + } + if vcpuCountItem.Default != nil { + vcpuCountMap["default"] = vcpuCountItem.Default + } + if vcpuCountItem.Max != nil { + vcpuCountMap["max"] = vcpuCountItem.Max + } + if vcpuCountItem.Min != nil { + vcpuCountMap["min"] = vcpuCountItem.Min + } + if vcpuCountItem.Step != nil { + vcpuCountMap["step"] = vcpuCountItem.Step + } + if vcpuCountItem.Values != nil { + vcpuCountMap["values"] = vcpuCountItem.Values + } + + return vcpuCountMap +} + +func dataSourceInstanceProfileFlattenDisks(result []vpcv1.InstanceProfileDisk) (disks []map[string]interface{}) { + for _, disksItem := range result { + disks = append(disks, dataSourceInstanceProfileDisksToMap(disksItem)) + } + + return disks +} + +func dataSourceInstanceProfileDisksToMap(disksItem vpcv1.InstanceProfileDisk) (disksMap map[string]interface{}) { + disksMap = map[string]interface{}{} + + if disksItem.Quantity != nil { + quantityList := []map[string]interface{}{} + quantityMap := dataSourceInstanceProfileDisksQuantityToMap(*disksItem.Quantity.(*vpcv1.InstanceProfileDiskQuantity)) + quantityList = append(quantityList, quantityMap) + disksMap["quantity"] = quantityList + } + if disksItem.Size != nil { + sizeList := []map[string]interface{}{} + sizeMap := dataSourceInstanceProfileDisksSizeToMap(*disksItem.Size.(*vpcv1.InstanceProfileDiskSize)) + sizeList = append(sizeList, sizeMap) + disksMap["size"] = sizeList + } + if disksItem.SupportedInterfaceTypes != nil { + supportedInterfaceTypesList := []map[string]interface{}{} + supportedInterfaceTypesMap := dataSourceInstanceProfileDisksSupportedInterfaceTypesToMap(*disksItem.SupportedInterfaceTypes) + supportedInterfaceTypesList = append(supportedInterfaceTypesList, supportedInterfaceTypesMap) + disksMap["supported_interface_types"] = supportedInterfaceTypesList + } + + return disksMap +} + +func dataSourceInstanceProfileDisksQuantityToMap(quantityItem vpcv1.InstanceProfileDiskQuantity) (quantityMap map[string]interface{}) { + quantityMap = map[string]interface{}{} + + if quantityItem.Type != nil { + quantityMap["type"] = quantityItem.Type + } + if quantityItem.Value != nil { + quantityMap["value"] = quantityItem.Value + } + if quantityItem.Default != nil { + quantityMap["default"] = quantityItem.Default + } + if quantityItem.Max != nil { + quantityMap["max"] = quantityItem.Max + } + if quantityItem.Min != nil { + quantityMap["min"] = quantityItem.Min + } + if quantityItem.Step != nil { + quantityMap["step"] = quantityItem.Step + } + if quantityItem.Values != nil { + quantityMap["values"] = quantityItem.Values + } + + return quantityMap +} + +func dataSourceInstanceProfileDisksSizeToMap(sizeItem vpcv1.InstanceProfileDiskSize) (sizeMap map[string]interface{}) { + sizeMap = map[string]interface{}{} + + if sizeItem.Type != nil { + sizeMap["type"] = sizeItem.Type + } + if sizeItem.Value != nil { + sizeMap["value"] = sizeItem.Value + } + if sizeItem.Default != nil { + sizeMap["default"] = sizeItem.Default + } + if sizeItem.Max != nil { + sizeMap["max"] = sizeItem.Max + } + if sizeItem.Min != nil { + sizeMap["min"] = sizeItem.Min + } + if sizeItem.Step != nil { + sizeMap["step"] = sizeItem.Step + } + if sizeItem.Values != nil { + sizeMap["values"] = sizeItem.Values + } + + return sizeMap +} + +func dataSourceInstanceProfileDisksSupportedInterfaceTypesToMap(supportedInterfaceTypesItem vpcv1.InstanceProfileDiskSupportedInterfaces) (supportedInterfaceTypesMap map[string]interface{}) { + supportedInterfaceTypesMap = map[string]interface{}{} + + if supportedInterfaceTypesItem.Default != nil { + supportedInterfaceTypesMap["default"] = supportedInterfaceTypesItem.Default + } + if supportedInterfaceTypesItem.Type != nil { + supportedInterfaceTypesMap["type"] = supportedInterfaceTypesItem.Type + } + if supportedInterfaceTypesItem.Values != nil { + supportedInterfaceTypesMap["values"] = supportedInterfaceTypesItem.Values + } + + return supportedInterfaceTypesMap +} + +func dataSourceInstanceProfileFlattenTotalVolumeBandwidth(result vpcv1.InstanceProfileVolumeBandwidth) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileTotalVolumeBandwidthToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileTotalVolumeBandwidthToMap(bandwidthItem vpcv1.InstanceProfileVolumeBandwidth) (bandwidthMap map[string]interface{}) { + bandwidthMap = map[string]interface{}{} + + if bandwidthItem.Type != nil { + bandwidthMap["type"] = bandwidthItem.Type + } + if bandwidthItem.Value != nil { + bandwidthMap["value"] = bandwidthItem.Value + } + if bandwidthItem.Default != nil { + bandwidthMap["default"] = bandwidthItem.Default + } + if bandwidthItem.Max != nil { + bandwidthMap["max"] = bandwidthItem.Max + } + if bandwidthItem.Min != nil { + bandwidthMap["min"] = bandwidthItem.Min + } + if bandwidthItem.Step != nil { + bandwidthMap["step"] = bandwidthItem.Step + } + if bandwidthItem.Values != nil { + bandwidthMap["values"] = bandwidthItem.Values + } + + return bandwidthMap +} diff --git a/ibm/data_source_ibm_is_instance_profile_test.go b/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go similarity index 84% rename from ibm/data_source_ibm_is_instance_profile_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_profile_test.go index 04d2ff074..c2ced4bef 100644 --- a/ibm/data_source_ibm_is_instance_profile_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,13 +16,13 @@ func TestAccIBMISInstanceProfileDataSource_basic(t *testing.T) { resName := "data.ibm_is_instance_profile.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISInstanceProfileDataSourceConfig(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName, "name", instanceProfileName), + resource.TestCheckResourceAttr(resName, "name", acc.InstanceProfileName), resource.TestCheckResourceAttrSet(resName, "family"), resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "bandwidth.#"), resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "family"), @@ -41,5 +43,5 @@ func testAccCheckIBMISInstanceProfileDataSourceConfig() string { data "ibm_is_instance_profile" "test1" { name = "%s" -}`, instanceProfileName) +}`, acc.InstanceProfileName) } diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go new file mode 100644 index 000000000..8c0abbc58 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go @@ -0,0 +1,674 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "time" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceProfiles = "profiles" +) + +func DataSourceIBMISInstanceProfiles() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISInstanceProfilesRead, + + Schema: map[string]*schema.Schema{ + + isInstanceProfiles: { + Type: schema.TypeList, + Description: "List of instance profile maps", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "family": { + Type: schema.TypeString, + Computed: true, + Description: "The product family this virtual server instance profile belongs to.", + }, + "architecture": { + Type: schema.TypeString, + Computed: true, + Description: "The default OS architecture for an instance with this profile.", + }, + "architecture_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for the OS architecture.", + }, + + "architecture_values": { + Type: schema.TypeList, + Computed: true, + Description: "The supported OS architecture(s) for an instance with this profile.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "bandwidth": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_count": { + Type: schema.TypeList, + Computed: true, + Description: "GPU count of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_manufacturer": { + Type: schema.TypeList, + Computed: true, + Description: "GPU manufacturer of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The possible GPU manufacturer(s) for an instance with this profile", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "gpu_memory": { + Type: schema.TypeList, + Computed: true, + Description: "GPU memory of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "gpu_model": { + Type: schema.TypeList, + Computed: true, + Description: "GPU model of this profile", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The possible GPU model(s) for an instance with this profile", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "total_volume_bandwidth": { + Type: schema.TypeList, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes. An increase in this value will result in a corresponding decrease to total_network_bandwidth.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "disks": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of the instance profile's disks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "quantity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "size": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "supported_interface_types": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The supported disk interfaces used for attaching the disk.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "memory": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "port_speed": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + }, + }, + }, + "vcpu_architecture": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeString, + Computed: true, + Description: "The default VCPU architecture for an instance with this profile.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "The VCPU architecture for an instance with this profile.", + }, + }, + }, + }, + "vcpu_count": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": { + Type: schema.TypeInt, + Computed: true, + Description: "The value for this profile field.", + }, + "default": { + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": { + Type: schema.TypeInt, + Computed: true, + Description: "The increment step value for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstanceProfilesRead(d *schema.ResourceData, meta interface{}) error { + err := instanceProfilesList(d, meta) + if err != nil { + return err + } + return nil +} + +func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + listInstanceProfilesOptions := &vpcv1.ListInstanceProfilesOptions{} + availableProfiles, response, err := sess.ListInstanceProfiles(listInstanceProfilesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Instance Profiles %s\n%s", err, response) + } + profilesInfo := make([]map[string]interface{}, 0) + for _, profile := range availableProfiles.Profiles { + + l := map[string]interface{}{ + "name": *profile.Name, + "family": *profile.Family, + } + if profile.OsArchitecture != nil { + if profile.OsArchitecture.Default != nil { + l["architecture"] = *profile.OsArchitecture.Default + } + if profile.OsArchitecture.Type != nil { + l["architecture_type"] = profile.OsArchitecture.Type + } + if profile.OsArchitecture.Values != nil { + l["architecture_values"] = profile.OsArchitecture.Values + } + } + if profile.Bandwidth != nil { + bandwidthList := []map[string]interface{}{} + bandwidthMap := dataSourceInstanceProfileBandwidthToMap(*profile.Bandwidth.(*vpcv1.InstanceProfileBandwidth)) + bandwidthList = append(bandwidthList, bandwidthMap) + l["bandwidth"] = bandwidthList + } + + if profile.GpuCount != nil { + l["gpu_count"] = dataSourceInstanceProfileFlattenGPUCount(*profile.GpuCount.(*vpcv1.InstanceProfileGpu)) + } + + if profile.GpuMemory != nil { + l["gpu_memory"] = dataSourceInstanceProfileFlattenGPUMemory(*profile.GpuMemory.(*vpcv1.InstanceProfileGpuMemory)) + } + + if profile.GpuManufacturer != nil { + l["gpu_manufacturer"] = dataSourceInstanceProfileFlattenGPUManufacturer(*profile.GpuManufacturer) + } + + if profile.GpuModel != nil { + l["gpu_model"] = dataSourceInstanceProfileFlattenGPUModel(*profile.GpuModel) + } + + if profile.TotalVolumeBandwidth != nil { + l["total_volume_bandwidth"] = dataSourceInstanceProfileFlattenTotalVolumeBandwidth(*profile.TotalVolumeBandwidth.(*vpcv1.InstanceProfileVolumeBandwidth)) + } + + if profile.Disks != nil { + disksList := []map[string]interface{}{} + for _, disksItem := range profile.Disks { + disksList = append(disksList, dataSourceInstanceProfileDisksToMap(disksItem)) + } + l["disks"] = disksList + } + if profile.Href != nil { + l["href"] = profile.Href + } + if profile.Memory != nil { + memoryList := []map[string]interface{}{} + memoryMap := dataSourceInstanceProfileMemoryToMap(*profile.Memory.(*vpcv1.InstanceProfileMemory)) + memoryList = append(memoryList, memoryMap) + l["memory"] = memoryList + } + if profile.PortSpeed != nil { + portSpeedList := []map[string]interface{}{} + portSpeedMap := dataSourceInstanceProfilePortSpeedToMap(*profile.PortSpeed.(*vpcv1.InstanceProfilePortSpeed)) + portSpeedList = append(portSpeedList, portSpeedMap) + l["port_speed"] = portSpeedList + } + if profile.VcpuArchitecture != nil { + vcpuArchitectureList := []map[string]interface{}{} + vcpuArchitectureMap := dataSourceInstanceProfileVcpuArchitectureToMap(*profile.VcpuArchitecture) + vcpuArchitectureList = append(vcpuArchitectureList, vcpuArchitectureMap) + l["vcpu_architecture"] = vcpuArchitectureList + } + if profile.VcpuCount != nil { + vcpuCountList := []map[string]interface{}{} + vcpuCountMap := dataSourceInstanceProfileVcpuCountToMap(*profile.VcpuCount.(*vpcv1.InstanceProfileVcpu)) + vcpuCountList = append(vcpuCountList, vcpuCountMap) + l["vcpu_count"] = vcpuCountList + } + if profile.Disks != nil { + l[isInstanceDisks] = dataSourceInstanceProfileFlattenDisks(profile.Disks) + if err != nil { + return fmt.Errorf("[ERROR] Error setting disks %s", err) + } + } + profilesInfo = append(profilesInfo, l) + } + d.SetId(dataSourceIBMISInstanceProfilesID(d)) + d.Set(isInstanceProfiles, profilesInfo) + return nil +} + +// dataSourceIBMISInstanceProfilesID returns a reasonable ID for a Instance Profile list. +func dataSourceIBMISInstanceProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_is_instance_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go similarity index 90% rename from ibm/data_source_ibm_is_instance_profiles_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go index d5509bad6..ac732c619 100644 --- a/ibm/data_source_ibm_is_instance_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ func TestAccIBMISInstanceProfilesDataSource_basic(t *testing.T) { resName := "data.ibm_is_instance_profiles.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISInstanceProfilesDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template.go b/ibm/service/vpc/data_source_ibm_is_instance_template.go new file mode 100644 index 000000000..3787c211b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -0,0 +1,904 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceTemplateHref = "href" + isInstanceTemplateCrn = "crn" + isInstanceTemplateLimit = "limit" + isInstanceTemplateNext = "next" + isInstanceTemplateTotalCount = "total_count" + isInstanceTemplatePortSpeed = "port_speed" + isInstanceTemplatePortType = "type" + isInstanceTemplatePortValue = "value" + isInstanceTemplateDeleteVol = "delete_volume_on_instance_delete" + isInstanceTemplateVol = "volume" + isInstanceTemplateMemory = "memory" + isInstanceTemplateMemoryValue = "value" + isInstanceTemplateMemoryType = "type" + isInstanceTemplateMemoryValues = "values" + isInstanceTemplateMemoryDefault = "default" + isInstanceTemplateMemoryMin = "min" + isInstanceTemplateMemoryMax = "max" + isInstanceTemplateMemoryStep = "step" + isInstanceTemplateSocketCount = "socket_count" + isInstanceTemplateSocketValue = "value" + isInstanceTemplateSocketType = "type" + isInstanceTemplateSocketValues = "values" + isInstanceTemplateSocketDefault = "default" + isInstanceTemplateSocketMin = "min" + isInstanceTemplateSocketMax = "max" + isInstanceTemplateSocketStep = "step" + isInstanceTemplateVcpuArch = "vcpu_architecture" + isInstanceTemplateVcpuArchType = "type" + isInstanceTemplateVcpuArchValue = "value" + isInstanceTemplateVcpuCount = "vcpu_count" + isInstanceTemplateVcpuCountValue = "value" + isInstanceTemplateVcpuCountType = "type" + isInstanceTemplateVcpuCountValues = "values" + isInstanceTemplateVcpuCountDefault = "default" + isInstanceTemplateVcpuCountMin = "min" + isInstanceTemplateVcpuCountMax = "max" + isInstanceTemplateVcpuCountStep = "step" + isInstanceTemplateStart = "start" + isInstanceTemplateVersion = "version" + isInstanceTemplateBootVolumeAttachment = "boot_volume_attachment" +) + +func DataSourceIBMISInstanceTemplate() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMISInstanceTemplateRead, + Schema: map[string]*schema.Schema{ + "identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"identifier", isInstanceTemplateName}, + }, + isInstanceTemplateName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"identifier", isInstanceTemplateName}, + }, + isInstanceTemplateHref: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateCrn: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVPC: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateZone: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateKeys: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + isInstanceDefaultTrustedProfileAutoLink: { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + }, + isInstanceDefaultTrustedProfileTarget: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + }, + isInstanceTemplateMetadataServiceEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + isInstanceAvailablePolicyHostFailure: { + Type: schema.TypeString, + Computed: true, + Description: "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + }, + isInstanceTemplateVolumeAttachments: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateDeleteVol: { + Type: schema.TypeBool, + Computed: true, + }, + isInstanceTemplateName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVol: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVolAttVolPrototype: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolAttVolIops: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + isInstanceTemplateVolAttVolProfile: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + isInstanceTemplateVolAttVolCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceTemplateVolAttVolEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + isInstanceTemplateVolAttTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The user tags associated with this volume.", + }, + }, + }, + }, + }, + }, + }, + isInstanceTemplatePrimaryNetworkInterface: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + isInstanceTemplateNetworkInterfaces: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + isInstanceTemplateUserData: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateImage: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateBootVolumeAttachment: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateDeleteVol: { + Type: schema.TypeBool, + Computed: true, + }, + isInstanceTemplateName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVol: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateBootSize: { + Type: schema.TypeInt, + Computed: true, + }, + isInstanceTemplateBootProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateBootVolumeTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The user tags associated with this volume.", + }, + }, + }, + }, + isInstanceTemplateResourceGroup: { + Type: schema.TypeString, + Computed: true, + }, + "placement_target": { + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions to use for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this dedicated host.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this dedicated host.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this dedicated host.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + instanceC, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + if idOk, ok := d.GetOk("identifier"); ok { + id := idOk.(string) + getInstanceTemplatesOptions := &vpcv1.GetInstanceTemplateOptions{ + ID: &id, + } + instTempl, _, err := instanceC.GetInstanceTemplate(getInstanceTemplatesOptions) + if err != nil { + return diag.FromErr(err) + } + instance := instTempl.(*vpcv1.InstanceTemplate) + d.SetId(*instance.ID) + d.Set(isInstanceTemplateHref, instance.Href) + d.Set(isInstanceTemplateCrn, instance.CRN) + d.Set(isInstanceTemplateName, instance.Name) + d.Set(isInstanceTemplateUserData, instance.UserData) + + if instance.DefaultTrustedProfile != nil { + if instance.DefaultTrustedProfile.AutoLink != nil { + d.Set(isInstanceDefaultTrustedProfileAutoLink, instance.DefaultTrustedProfile.AutoLink) + } + if instance.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instance.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByID) + d.Set(isInstanceDefaultTrustedProfileTarget, target.ID) + } + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByCRN) + d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN) + } + } + } + } + + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + d.Set(isInstanceTemplateAvailablePolicyHostFailure, *instance.AvailabilityPolicy.HostFailure) + } + if instance.Keys != nil { + keys := []string{} + for _, intfc := range instance.Keys { + instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) + keys = append(keys, *instanceKeyIntf.ID) + } + d.Set(isInstanceTemplateKeys, keys) + } + + if instance.MetadataService != nil { + d.Set(isInstanceTemplateMetadataServiceEnabled, instance.MetadataService.Enabled) + } + + if instance.Profile != nil { + instanceProfileIntf := instance.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + d.Set(isInstanceTemplateProfile, *identity.Name) + } + + if instance.PlacementTarget != nil { + placementTargetList := []map[string]interface{}{} + placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + placementTargetList = append(placementTargetList, placementTargetMap) + d.Set("placement_target", placementTargetList) + } + + if instance.TotalVolumeBandwidth != nil { + d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) + } + + if instance.PrimaryNetworkInterface != nil { + log.Printf("[INFO] UJJK PNI") + interfaceList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name + if instance.PrimaryNetworkInterface.PrimaryIP != nil { + primaryipIntf := instance.PrimaryNetworkInterface.PrimaryIP + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + log.Printf("[INFO] UJJK NetworkInterfaceIPPrototype") + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + if primaryip.Address != nil { + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = *primaryip.Address + } + if primaryip.ID != nil { + currentPrimIp[isInstanceTemplateNicReservedIpId] = *primaryip.ID + } + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + log.Printf("[INFO] UJJK NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext") + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + if primaryip.Address != nil { + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = *primaryip.Address + } + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + log.Printf("[INFO] UJJK NetworkInterfaceIPPrototypeReservedIPIdentity") + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + if primaryip.ID != nil { + currentPrimIp[isInstanceTemplateNicReservedIpId] = *primaryip.ID + } + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + subInf := instance.PrimaryNetworkInterface.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + + if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfaceList = append(interfaceList, currentPrimNic) + d.Set(isInstanceTemplatePrimaryNetworkInterface, interfaceList) + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + primaryipIntf := intfc.PrimaryIP + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = primaryip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + interfacesList = append(interfacesList, currentNic) + } + d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) + } + + if instance.Image != nil { + imageInf := instance.Image + imageIdentity := imageInf.(*vpcv1.ImageIdentity) + d.Set(isInstanceTemplateImage, imageIdentity.ID) + } + + if instance.VPC != nil { + vpcInf := instance.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + d.Set(isInstanceTemplateVPC, vpcRef.ID) + } + + if instance.Zone != nil { + zoneInf := instance.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + d.Set(isInstanceTemplateZone, zone.Name) + } + + interfacesList := make([]map[string]interface{}, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = instance.BootVolumeAttachment.Volume.UserTags + } + newVolumeArr = append(newVolumeArr, newVolume) + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + + interfacesList = append(interfacesList, volumeAttach) + } + d.Set(isInstanceTemplateVolumeAttachments, interfacesList) + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + + bootVol[isInstanceTemplateDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instance.BootVolumeAttachment.Volume != nil { + volumeIntf := instance.BootVolumeAttachment.Volume + bootVol[isInstanceTemplateName] = volumeIntf.Name + bootVol[isInstanceTemplateVol] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + if instance.BootVolumeAttachment.Volume.Profile != nil { + volProfIntf := instance.BootVolumeAttachment.Volume.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if instance.BootVolumeAttachment.Volume.UserTags != nil { + bootVol[isInstanceTemplateBootVolumeTags] = instance.BootVolumeAttachment.Volume.UserTags + } + } + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceTemplateBootVolumeAttachment, bootVolList) + } + + if instance.ResourceGroup != nil { + rg := instance.ResourceGroup + d.Set(isInstanceTemplateResourceGroup, rg.ID) + } + } else if nameOk, ok := d.GetOk(isInstanceTemplateName); ok { + name := nameOk.(string) + listInstanceTemplatesOptions := &vpcv1.ListInstanceTemplatesOptions{} + availableTemplates, _, err := instanceC.ListInstanceTemplates(listInstanceTemplatesOptions) + if err != nil { + return diag.FromErr(err) + } + flag := false + for _, instTempl := range availableTemplates.Templates { + instance := instTempl.(*vpcv1.InstanceTemplate) + if name == *instance.Name { + flag = true + d.SetId(*instance.ID) + d.Set(isInstanceTemplateHref, instance.Href) + d.Set(isInstanceTemplateCrn, instance.CRN) + d.Set(isInstanceTemplateName, instance.Name) + d.Set(isInstanceTemplateUserData, instance.UserData) + + if instance.DefaultTrustedProfile != nil { + if instance.DefaultTrustedProfile.AutoLink != nil { + d.Set(isInstanceDefaultTrustedProfileAutoLink, instance.DefaultTrustedProfile.AutoLink) + } + if instance.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instance.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByID) + d.Set(isInstanceDefaultTrustedProfileTarget, target.ID) + } + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByCRN) + d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN) + } + } + } + } + if instance.Keys != nil { + keys := []string{} + for _, intfc := range instance.Keys { + instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) + keys = append(keys, *instanceKeyIntf.ID) + } + d.Set(isInstanceTemplateKeys, keys) + } + + if instance.MetadataService != nil { + d.Set(isInstanceTemplateMetadataServiceEnabled, instance.MetadataService.Enabled) + } + + if instance.Profile != nil { + instanceProfileIntf := instance.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + d.Set(isInstanceTemplateProfile, identity.Name) + } + + if instance.PlacementTarget != nil { + placementTargetList := []map[string]interface{}{} + placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + placementTargetList = append(placementTargetList, placementTargetMap) + d.Set("placement_target", placementTargetList) + } + + if instance.PrimaryNetworkInterface != nil { + interfaceList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name + if instance.PrimaryNetworkInterface.PrimaryIP != nil { + primaryipIntf := instance.PrimaryNetworkInterface.PrimaryIP + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + if primaryip.Address != nil { + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = *primaryip.Address + } + if primaryip.ID != nil { + currentPrimIp[isInstanceTemplateNicReservedIpId] = *primaryip.ID + } + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + if primaryip.Address != nil { + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = *primaryip.Address + } + if primaryip.Name != nil { + currentPrimIp[isInstanceTemplateNicReservedIpName] = *primaryip.Name + } + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + if primaryip.ID != nil { + currentPrimIp[isInstanceTemplateNicReservedIpId] = *primaryip.ID + } + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + subInf := instance.PrimaryNetworkInterface.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + + if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfaceList = append(interfaceList, currentPrimNic) + d.Set(isInstanceTemplatePrimaryNetworkInterface, interfaceList) + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + primaryipIntf := intfc.PrimaryIP + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + } + } + } + //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + interfacesList = append(interfacesList, currentNic) + } + d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) + } + + if instance.TotalVolumeBandwidth != nil { + d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) + } + + if instance.Image != nil { + imageInf := instance.Image + imageIdentity := imageInf.(*vpcv1.ImageIdentity) + d.Set(isInstanceTemplateImage, imageIdentity.ID) + } + + if instance.VPC != nil { + vpcInf := instance.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + d.Set(isInstanceTemplateVPC, vpcRef.ID) + } + + if instance.Zone != nil { + zoneInf := instance.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + d.Set(isInstanceTemplateZone, zone.Name) + } + + interfacesList := make([]map[string]interface{}, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags + } + newVolumeArr = append(newVolumeArr, newVolume) + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + + interfacesList = append(interfacesList, volumeAttach) + } + d.Set(isInstanceTemplateVolumeAttachments, interfacesList) + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + + bootVol[isInstanceTemplateDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instance.BootVolumeAttachment.Volume != nil { + volumeIntf := instance.BootVolumeAttachment.Volume + bootVol[isInstanceTemplateName] = volumeIntf.Name + bootVol[isInstanceTemplateVol] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + if instance.BootVolumeAttachment.Volume.Profile != nil { + volProfIntf := instance.BootVolumeAttachment.Volume.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if instance.BootVolumeAttachment.Volume.UserTags != nil { + bootVol[isInstanceTemplateBootVolumeTags] = instance.BootVolumeAttachment.Volume.UserTags + } + } + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceTemplateBootVolumeAttachment, bootVolList) + } + + if instance.ResourceGroup != nil { + rg := instance.ResourceGroup + d.Set(isInstanceTemplateResourceGroup, rg.ID) + } + } + } + if !flag { + return diag.FromErr(fmt.Errorf("[ERROR] No Instance Template found with name %s", name)) + } + } + return nil +} + +func dataSourceInstanceTemplateCollectionTemplatePlacementTargetToMap(placementTargetItem vpcv1.InstancePlacementTargetPrototype) (placementTargetMap map[string]interface{}) { + placementTargetMap = map[string]interface{}{} + + if placementTargetItem.ID != nil { + placementTargetMap["id"] = placementTargetItem.ID + } + if placementTargetItem.CRN != nil { + placementTargetMap["crn"] = placementTargetItem.CRN + } + if placementTargetItem.Href != nil { + placementTargetMap["href"] = placementTargetItem.Href + } + + return placementTargetMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go new file mode 100644 index 000000000..80c7318b4 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceTemplate_dataBasic(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_instance_template.instance_template_data", "name", templateName), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "availability_policy.0.host_failure"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceTemplate_ReservedIp_Basic(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateRipDataConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_instance_template.instance_template_data", "name", templateName), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_interface.0.primary_ip.0.reserved_ip"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + data "ibm_is_instance_template" "instance_template_data" { + name = ibm_is_instance_template.instancetemplate1.name + } + `) +} +func testAccCheckIBMISInstanceTemplateRipDataConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateRipConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + data "ibm_is_instance_template" "instance_template_data" { + name = ibm_is_instance_template.instancetemplate1.name + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates.go b/ibm/service/vpc/data_source_ibm_is_instance_templates.go new file mode 100644 index 000000000..c8743f62c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -0,0 +1,680 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceTemplates = "templates" + isInstanceTemplatesFirst = "first" + isInstanceTemplatesHref = "href" + isInstanceTemplatesCrn = "crn" + isInstanceTemplatesLimit = "limit" + isInstanceTemplatesNext = "next" + isInstanceTemplatesTotalCount = "total_count" + isInstanceTemplatesName = "name" + isInstanceTemplatesPortSpeed = "port_speed" + isInstanceTemplatesPortType = "type" + isInstanceTemplatesPortValue = "value" + isInstanceTemplatesDeleteVol = "delete_volume_on_instance_delete" + isInstanceTemplatesVol = "volume" + isInstanceTemplatesMemory = "memory" + isInstanceTemplatesMemoryValue = "value" + isInstanceTemplatesMemoryType = "type" + isInstanceTemplatesMemoryValues = "values" + isInstanceTemplatesMemoryDefault = "default" + isInstanceTemplatesMemoryMin = "min" + isInstanceTemplatesMemoryMax = "max" + isInstanceTemplatesMemoryStep = "step" + isInstanceTemplatesSocketCount = "socket_count" + isInstanceTemplatesSocketValue = "value" + isInstanceTemplatesSocketType = "type" + isInstanceTemplatesSocketValues = "values" + isInstanceTemplatesSocketDefault = "default" + isInstanceTemplatesSocketMin = "min" + isInstanceTemplatesSocketMax = "max" + isInstanceTemplatesSocketStep = "step" + isInstanceTemplatesVcpuArch = "vcpu_architecture" + isInstanceTemplatesVcpuArchType = "type" + isInstanceTemplatesVcpuArchValue = "value" + isInstanceTemplatesVcpuCount = "vcpu_count" + isInstanceTemplatesVcpuCountValue = "value" + isInstanceTemplatesVcpuCountType = "type" + isInstanceTemplatesVcpuCountValues = "values" + isInstanceTemplatesVcpuCountDefault = "default" + isInstanceTemplatesVcpuCountMin = "min" + isInstanceTemplatesVcpuCountMax = "max" + isInstanceTemplatesVcpuCountStep = "step" + isInstanceTemplatesStart = "start" + isInstanceTemplatesVersion = "version" + isInstanceTemplatesGeneration = "generation" + isInstanceTemplatesBootVolumeAttachment = "boot_volume_attachment" + + isInstanceTemplateVPC = "vpc" + isInstanceTemplateZone = "zone" + isInstanceTemplateProfile = "profile" + isInstanceTemplateKeys = "keys" + isInstanceTemplateVolumeAttachments = "volume_attachments" + isInstanceTemplateNetworkInterfaces = "network_interfaces" + isInstanceTemplatePrimaryNetworkInterface = "primary_network_interface" + isInstanceTemplateNicName = "name" + isInstanceTemplateNicPortSpeed = "port_speed" + isInstanceTemplateNicAllowIPSpoofing = "allow_ip_spoofing" + isInstanceTemplateNicPrimaryIpv4Address = "primary_ipv4_address" + isInstanceTemplateNicSecondaryAddress = "secondary_addresses" + isInstanceTemplateNicSecurityGroups = "security_groups" + isInstanceTemplateNicSubnet = "subnet" + isInstanceTemplateNicFloatingIPs = "floating_ips" + isInstanceTemplateUserData = "user_data" + isInstanceTemplateGeneration = "generation" + isInstanceTemplateImage = "image" + isInstanceTemplateResourceGroup = "resource_group" + isInstanceTemplateName = "name" + isInstanceTemplateDeleteVolume = "delete_volume_on_instance_delete" + isInstanceTemplateVolAttName = "name" + isInstanceTemplateVolAttVolume = "volume" +) + +func DataSourceIBMISInstanceTemplates() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISInstanceTemplatesRead, + Schema: map[string]*schema.Schema{ + isInstanceTemplates: { + Type: schema.TypeList, + Description: "Collection of instance templates", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isInstanceAvailablePolicyHostFailure: { + Type: schema.TypeString, + Computed: true, + Description: "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + }, + isInstanceTemplatesName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateMetadataServiceEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + isInstanceTemplatesHref: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplatesCrn: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVPC: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateZone: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateKeys: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + isInstanceDefaultTrustedProfileAutoLink: { + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + }, + isInstanceDefaultTrustedProfileTarget: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + }, + isInstanceTemplateVolumeAttachments: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplatesDeleteVol: { + Type: schema.TypeBool, + Computed: true, + }, + isInstanceTemplatesName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplatesVol: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVolAttVolPrototype: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolAttVolIops: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + isInstanceTemplateVolAttVolProfile: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + isInstanceTemplateVolAttVolCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceTemplateVolAttVolEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + isInstanceTemplateVolAttTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The user tags associated with this volume.", + }, + }, + }, + }, + }, + }, + }, + + "placement_target": { + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions for the virtual server instance. For the target tobe changed, the instance `status` must be `stopping` or `stopped`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this dedicated host.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this dedicated host.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this dedicated host.", + }, + }, + }, + }, + + isInstanceTemplatePrimaryNetworkInterface: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + isInstanceTemplateNetworkInterfaces: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + isInstanceTemplateUserData: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateImage: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplatesBootVolumeAttachment: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplatesDeleteVol: { + Type: schema.TypeBool, + Computed: true, + }, + isInstanceTemplatesName: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplatesVol: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateBootSize: { + Type: schema.TypeInt, + Computed: true, + }, + isInstanceTemplateBootProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateBootVolumeTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "The user tags associated with this volume.", + }, + }, + }, + }, + isInstanceTemplateResourceGroup: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface{}) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + listInstanceTemplatesOptions := &vpcv1.ListInstanceTemplatesOptions{} + availableTemplates, _, err := instanceC.ListInstanceTemplates(listInstanceTemplatesOptions) + if err != nil { + return err + } + templates := make([]map[string]interface{}, 0) + for _, instTempl := range availableTemplates.Templates { + template := map[string]interface{}{} + instance := instTempl.(*vpcv1.InstanceTemplate) + template["id"] = instance.ID + template[isInstanceTemplatesHref] = instance.Href + template[isInstanceTemplatesCrn] = instance.CRN + template[isInstanceTemplateName] = instance.Name + template[isInstanceTemplateUserData] = instance.UserData + + if instance.DefaultTrustedProfile != nil { + if instance.DefaultTrustedProfile.AutoLink != nil { + template[isInstanceDefaultTrustedProfileAutoLink] = instance.DefaultTrustedProfile.AutoLink + } + if instance.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instance.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByID) + template[isInstanceDefaultTrustedProfileTarget] = target.ID + } + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByCRN) + template[isInstanceDefaultTrustedProfileTarget] = target.CRN + } + } + } + } + + if instance.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + template["placement_target"] = []map[string]interface{}{placementTargetMap} + } + + if instance.MetadataService != nil { + template[isInstanceTemplateMetadataServiceEnabled] = *instance.MetadataService.Enabled + } + + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + template[isInstanceTemplateAvailablePolicyHostFailure] = *instance.AvailabilityPolicy.HostFailure + } + if instance.Keys != nil { + keys := []string{} + for _, intfc := range instance.Keys { + instanceKeyIntf := intfc.(*vpcv1.KeyIdentity) + keys = append(keys, *instanceKeyIntf.ID) + } + template[isInstanceTemplateKeys] = keys + } + if instance.Profile != nil { + instanceProfileIntf := instance.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + template[isInstanceTemplateProfile] = identity.Name + } + + if instance.PlacementTarget != nil { + placementTargetList := []map[string]interface{}{} + placementTargetMap := dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + placementTargetList = append(placementTargetList, placementTargetMap) + template["placement_target"] = placementTargetList + } + + if instance.TotalVolumeBandwidth != nil { + template[isInstanceTotalVolumeBandwidth] = int(*instance.TotalVolumeBandwidth) + } + + if instance.PrimaryNetworkInterface != nil { + interfaceList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name + + if instance.PrimaryNetworkInterface.PrimaryIP != nil { + primaryipIntf := instance.PrimaryNetworkInterface.PrimaryIP + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpId] = primaryip.ID + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = primaryip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + subInf := instance.PrimaryNetworkInterface.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + + if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfaceList = append(interfaceList, currentPrimNic) + template[isInstanceTemplatePrimaryNetworkInterface] = interfaceList + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + primaryipIntf := intfc.PrimaryIP + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(primaryipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpId] = primaryip.ID + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = primaryip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = primaryip.Address + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = primaryip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + //currentNic[isInstanceTemplateNicAllowIpSpoofing] = intfc.AllowIpSpoofing + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + secGrpIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*secGrpIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + interfacesList = append(interfacesList, currentNic) + } + template[isInstanceTemplateNetworkInterfaces] = interfacesList + } + + if instance.Image != nil { + imageInf := instance.Image + imageIdentity := imageInf.(*vpcv1.ImageIdentity) + template[isInstanceTemplateImage] = imageIdentity.ID + } + + if instance.VPC != nil { + vpcInf := instance.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + template[isInstanceTemplateVPC] = vpcRef.ID + } + + if instance.Zone != nil { + zoneInf := instance.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + template[isInstanceTemplateZone] = zone.Name + } + + interfacesList := make([]map[string]interface{}, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = instance.BootVolumeAttachment.Volume.UserTags + } + newVolumeArr = append(newVolumeArr, newVolume) + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + + interfacesList = append(interfacesList, volumeAttach) + } + template[isInstanceTemplateVolumeAttachments] = interfacesList + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + + bootVol[isInstanceTemplatesDeleteVol] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instance.BootVolumeAttachment.Volume != nil { + volumeIntf := instance.BootVolumeAttachment.Volume + bootVol[isInstanceTemplatesName] = volumeIntf.Name + bootVol[isInstanceTemplatesVol] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + if instance.BootVolumeAttachment.Volume.Profile != nil { + volProfIntf := instance.BootVolumeAttachment.Volume.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if instance.BootVolumeAttachment.Volume.UserTags != nil { + bootVol[isInstanceTemplateBootVolumeTags] = instance.BootVolumeAttachment.Volume.UserTags + } + } + bootVolList = append(bootVolList, bootVol) + template[isInstanceTemplatesBootVolumeAttachment] = bootVolList + } + + if instance.ResourceGroup != nil { + rg := instance.ResourceGroup + template[isInstanceTemplateResourceGroup] = rg.ID + } + + templates = append(templates, template) + } + d.SetId(dataSourceIBMISInstanceTemplatesID(d)) + d.Set(isInstanceTemplates, templates) + return nil +} + +// dataSourceIBMISInstanceTemplatesID returns a reasonable ID for a instance templates list. +func dataSourceIBMISInstanceTemplatesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(placementTargetItem vpcv1.InstancePlacementTargetPrototype) (placementTargetMap map[string]interface{}) { + placementTargetMap = map[string]interface{}{} + + if placementTargetItem.ID != nil { + placementTargetMap["id"] = placementTargetItem.ID + } + if placementTargetItem.CRN != nil { + placementTargetMap["crn"] = placementTargetItem.CRN + } + if placementTargetItem.Href != nil { + placementTargetMap["href"] = placementTargetItem.Href + } + + return placementTargetMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go new file mode 100644 index 000000000..00e12cb8c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go @@ -0,0 +1,85 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceTemplates_dataBasic(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.id"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.name"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceTemplates_dataReservedIp(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplatesReservedIpConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.id"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.primary_network_interface.0.primary_ip.0.reserved_ip"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + + data "ibm_is_instance_templates" "instance_templates_data" { + } + `) +} +func testAccCheckIBMISInstanceTemplatesReservedIpConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateRipConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + + data "ibm_is_instance_templates" "instance_templates_data" { + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_test.go b/ibm/service/vpc/data_source_ibm_is_instance_test.go new file mode 100644 index 000000000..7ce0fcc9f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_test.go @@ -0,0 +1,166 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceDataSource_basic(t *testing.T) { + + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instance.ds_instance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceDataSourceConfig(vpcname, subnetname, sshname, instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + resName, "name", instanceName), + resource.TestCheckResourceAttr( + resName, "tags.#", "1"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + resName, "availability_policy_host_failure"), + resource.TestCheckResourceAttrSet( + resName, "lifecycle_state"), + resource.TestCheckResourceAttr( + resName, "lifecycle_reasons.#", "0"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceDataSource_reserved_ip(t *testing.T) { + + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instance.ds_instance" + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceDataSourceReservedIpConfig(vpcname, subnetname, sshname, publicKey, instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + resName, "name", instanceName), + resource.TestCheckResourceAttr( + resName, "tags.#", "1"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.primary_ip.0.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceDataSourceConfig(vpcname, subnetname, sshname, instanceName string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" +} + +resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = file("./test-fixtures/.ssh/id_rsa.pub") +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + tags = ["tag1"] +} +data "ibm_is_instance" "ds_instance" { + name = ibm_is_instance.testacc_instance.name + private_key = file("./test-fixtures/.ssh/id_rsa") + passphrase = "" +}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, instanceName, acc.IsWinImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceDataSourceReservedIpConfig(vpcname, subnetname, sshname, publicKey, instanceName string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" +} + +resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + tags = ["tag1"] +} +data "ibm_is_instance" "ds_instance" { + name = ibm_is_instance.testacc_instance.name +}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, instanceName, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} diff --git a/ibm/data_source_ibm_is_instance_volume_attachment.go b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachment.go similarity index 95% rename from ibm/data_source_ibm_is_instance_volume_attachment.go rename to ibm/service/vpc/data_source_ibm_is_instance_volume_attachment.go index 22b443119..e10c77556 100644 --- a/ibm/data_source_ibm_is_instance_volume_attachment.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -23,7 +23,7 @@ const ( isInstanceVolumeAttVolumeReferenceName = "volume_name" ) -func dataSourceIBMISInstanceVolumeAttachment() *schema.Resource { +func DataSourceIBMISInstanceVolumeAttachment() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceVolumeAttachmentRead, @@ -135,7 +135,7 @@ func instanceVolumeAttachmentGetByName(d *schema.ResourceData, meta interface{}, } volumeAtts, response, err := sess.ListInstanceVolumeAttachments(listInstanceVolumeAttOptions) if err != nil { - return fmt.Errorf("Error fetching Instance volume attachments %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching Instance volume attachments %s\n%s", err, response) } allrecs = append(allrecs, volumeAtts.VolumeAttachments...) for _, volumeAtt := range allrecs { @@ -164,5 +164,5 @@ func instanceVolumeAttachmentGetByName(d *schema.ResourceData, meta interface{}, return nil } } - return fmt.Errorf("No Instance volume attachment found with name %s on instance %s", name, instanceId) + return fmt.Errorf("[ERROR] No Instance volume attachment found with name %s on instance %s", name, instanceId) } diff --git a/ibm/data_source_ibm_is_instance_volume_attachment_test.go b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachment_test.go similarity index 89% rename from ibm/data_source_ibm_is_instance_volume_attachment_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_volume_attachment_test.go index 5d8543360..c3365400f 100644 --- a/ibm/data_source_ibm_is_instance_volume_attachment_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachment_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -23,10 +25,10 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) resName := fmt.Sprintf("data.ibm_is_instance_volume_attachment.ds_vol_att") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISInstanceVolumeAttachmentDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -79,5 +81,5 @@ func testAccCheckIBMISInstanceVolumeAttachmentDataSourceConfig(vpcname, subnetna name = ibm_is_instance.testacc_instance.volume_attachments.0.name } - `, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName) + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } diff --git a/ibm/data_source_ibm_is_instance_volume_attachments.go b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachments.go similarity index 96% rename from ibm/data_source_ibm_is_instance_volume_attachments.go rename to ibm/service/vpc/data_source_ibm_is_instance_volume_attachments.go index 8e4844af9..e9a0dd0e6 100644 --- a/ibm/data_source_ibm_is_instance_volume_attachments.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachments.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISInstanceVolumeAttachments() *schema.Resource { +func DataSourceIBMISInstanceVolumeAttachments() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISInstanceVolumeAttachmentsRead, @@ -130,7 +130,7 @@ func instanceGetVolumeAttachments(d *schema.ResourceData, meta interface{}, inst } volumeAtts, response, err := sess.ListInstanceVolumeAttachments(listInstanceVolumeAttOptions) if err != nil { - return fmt.Errorf("Error Fetching Instance volume attachments %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching Instance volume attachments %s\n%s", err, response) } allrecs = append(allrecs, volumeAtts.VolumeAttachments...) volAttList := make([]map[string]interface{}, 0) diff --git a/ibm/data_source_ibm_is_instance_volume_attachments_test.go b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachments_test.go similarity index 89% rename from ibm/data_source_ibm_is_instance_volume_attachments_test.go rename to ibm/service/vpc/data_source_ibm_is_instance_volume_attachments_test.go index b22074923..95cfcf125 100644 --- a/ibm/data_source_ibm_is_instance_volume_attachments_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_volume_attachments_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -24,10 +26,10 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resName := fmt.Sprintf("data.ibm_is_instance_volume_attachments.ds_vol_atts") resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISInstanceVolumeAttsDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet( @@ -77,5 +79,5 @@ func testAccCheckIBMISInstanceVolumeAttsDataSourceConfig(vpcname, subnetname, ss instance = ibm_is_instance.testacc_instance.id } - `, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName) + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } diff --git a/ibm/service/vpc/data_source_ibm_is_instances.go b/ibm/service/vpc/data_source_ibm_is_instances.go new file mode 100644 index 000000000..8d8e80ffb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instances.go @@ -0,0 +1,1028 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstances = "instances" + isInstanceGroupName = "instance_group_name" +) + +func DataSourceIBMISInstances() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISInstancesRead, + + Schema: map[string]*schema.Schema{ + isInstanceGroup: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"vpc", "vpc_crn", "vpc_name", isInstanceGroupName}, + Description: "Instance group ID to filter the instances attached to it", + }, + isInstanceGroupName: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"vpc", "vpc_crn", "vpc_name", isInstanceGroup}, + Description: "Instance group name to filter the instances attached to it", + }, + "vpc_name": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"vpc", "vpc_crn", "instance_group"}, + Description: "Name of the vpc to filter the instances attached to it", + }, + + "vpc": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"vpc_name", "vpc_crn", "instance_group"}, + Description: "VPC ID to filter the instances attached to it", + }, + + "vpc_crn": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"vpc_name", "vpc", "instance_group"}, + Description: "VPC CRN to filter the instances attached to it", + }, + + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "Instance resource group", + }, + + "dedicated_host_name": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"dedicated_host"}, + Description: "Name of the dedicated host to filter the instances attached to it", + }, + + "dedicated_host": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"dedicated_host_name"}, + Description: "ID of the dedicated host to filter the instances attached to it", + }, + + "placement_group_name": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"placement_group"}, + Description: "Name of the placement group to filter the instances attached to it", + }, + + "placement_group": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"placement_group_name"}, + Description: "ID of the placement group to filter the instances attached to it", + }, + + isInstances: { + Type: schema.TypeList, + Description: "List of instances", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance name", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The crn for this Instance", + }, + "memory": { + Type: schema.TypeInt, + Computed: true, + Description: "Instance memory", + }, + isInstanceMetadataServiceEnabled: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Instance status", + }, + isInstanceAvailablePolicyHostFailure: { + Type: schema.TypeString, + Computed: true, + Description: "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + }, + + isInstanceLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the virtual server instance.", + }, + isInstanceLifecycleReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current lifecycle_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceLifecycleReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + + isInstanceStatusReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isInstanceStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isInstanceStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Instance resource group", + }, + "vpc": { + Type: schema.TypeString, + Computed: true, + Description: "vpc attached to the instance", + }, + + isInstanceCatalogOffering: { + Type: schema.TypeList, + Computed: true, + Description: "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceCatalogOfferingOfferingCrn: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a catalog offering by a unique CRN property", + }, + isInstanceCatalogOfferingVersionCrn: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a version of a catalog offering by a unique CRN property", + }, + }, + }, + }, + + "boot_volume": { + Type: schema.TypeList, + Computed: true, + Description: "Instance Boot Volume", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot volume id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot volume name", + }, + "device": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot volume device", + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot volume's volume id", + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Boot volume's volume CRN", + }, + }, + }, + }, + + "volume_attachments": { + Type: schema.TypeList, + Computed: true, + Description: "Instance Volume Attachments", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance volume Attachment id", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance volume Attachment name", + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance volume Attachment's volume id", + }, + "volume_name": { + Type: schema.TypeString, + Computed: true, + Description: "Instance volume Attachment's volume name", + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + Description: "Instance volume Attachment's volume CRN", + }, + }, + }, + }, + + "primary_network_interface": { + Type: schema.TypeList, + Computed: true, + Description: "Instance Primary Network Interface", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network interface id", + }, + isInstanceNicName: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network interface name", + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network interface IPV4 Address", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Instance Primary Network interface security groups", + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Primary Network interface subnet", + }, + }, + }, + }, + "placement_target": { + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this placement target resource.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this placement target resource.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this placement target resource.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this placement target resource. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Description: "Instance Network Interfaces", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network interface id", + }, + isInstanceNicName: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network interface name", + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network interface IPV4 Address", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Instance Network interface security groups", + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Computed: true, + Description: "Instance Network interface subnet", + }, + }, + }, + }, + "profile": { + Type: schema.TypeString, + Computed: true, + Description: "Instance Profile", + }, + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + + isInstanceBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + }, + + isInstanceTotalNetworkBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + }, + "vcpu": { + Type: schema.TypeList, + Computed: true, + Description: "Instance vcpu", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "architecture": { + Type: schema.TypeString, + Computed: true, + Description: "Instance vcpu architecture", + }, + "count": { + Type: schema.TypeInt, + Computed: true, + Description: "Instance vcpu count", + }, + }, + }, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + Description: "Instance zone", + }, + "image": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Instance Image", + }, + + isInstanceGpu: { + Type: schema.TypeList, + Computed: true, + Description: "Instance GPU", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceGpuCount: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance GPU Count", + }, + isInstanceGpuMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance GPU Memory", + }, + isInstanceGpuManufacturer: { + Type: schema.TypeString, + Computed: true, + Description: "Instance GPU Manufacturer", + }, + isInstanceGpuModel: { + Type: schema.TypeString, + Computed: true, + Description: "Instance GPU Model", + }, + }, + }, + }, + + isInstanceDisks: { + Type: schema.TypeList, + Computed: true, + Description: "Collection of the instance's disks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the disk was created.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance disk.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance disk.", + }, + "interface_type": { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "size": { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes).", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISInstancesRead(d *schema.ResourceData, meta interface{}) error { + + err := instancesList(d, meta) + if err != nil { + return err + } + return nil +} + +func instancesList(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + var vpcName, vpcID, vpcCrn, resourceGroup, insGrp, dHostNameStr, dHostIdStr, placementGrpNameStr, placementGrpIdStr string + + if vpc, ok := d.GetOk("vpc_name"); ok { + vpcName = vpc.(string) + } + + if vpc, ok := d.GetOk("vpc"); ok { + vpcID = vpc.(string) + } + + if vpccrn, ok := d.GetOk("vpc_crn"); ok { + vpcCrn = vpccrn.(string) + } + + if rg, ok := d.GetOk("resource_group"); ok { + resourceGroup = rg.(string) + } + + if dHostNameIntf, ok := d.GetOk("dedicated_host_name"); ok { + dHostNameStr = dHostNameIntf.(string) + } + + if dHostIdIntf, ok := d.GetOk("dedicated_host"); ok { + dHostIdStr = dHostIdIntf.(string) + } + + if placementGrpNameIntf, ok := d.GetOk("placement_group_name"); ok { + placementGrpNameStr = placementGrpNameIntf.(string) + } + + if placementGrpIdIntf, ok := d.GetOk("placement_group"); ok { + placementGrpIdStr = placementGrpIdIntf.(string) + } + + if insGrpInf, ok := d.GetOk(isInstanceGroup); ok { + insGrp = insGrpInf.(string) + } else if insGrpNameInf, ok := d.GetOk(isInstanceGroupName); ok { + insGrpName := insGrpNameInf.(string) + start := "" + allrecs := []vpcv1.InstanceGroup{} + for { + listInstanceGroupOptions := vpcv1.ListInstanceGroupsOptions{} + if start != "" { + listInstanceGroupOptions.Start = &start + } + instanceGroupsCollection, response, err := sess.ListInstanceGroups(&listInstanceGroupOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching InstanceGroups %s\n%s", err, response) + } + start = flex.GetNext(instanceGroupsCollection.Next) + allrecs = append(allrecs, instanceGroupsCollection.InstanceGroups...) + + if start == "" { + break + } + + } + + for _, instanceGroup := range allrecs { + if *instanceGroup.Name == insGrpName { + insGrp = *instanceGroup.ID + break + } + } + } + + listInstancesOptions := &vpcv1.ListInstancesOptions{} + + if vpcName != "" { + listInstancesOptions.VPCName = &vpcName + } + if vpcID != "" { + listInstancesOptions.VPCID = &vpcID + } + if resourceGroup != "" { + listInstancesOptions.ResourceGroupID = &resourceGroup + } + if vpcCrn != "" { + listInstancesOptions.VPCCRN = &vpcCrn + } + + if dHostNameStr != "" { + listInstancesOptions.DedicatedHostName = &dHostNameStr + } + + if dHostIdStr != "" { + listInstancesOptions.DedicatedHostID = &dHostIdStr + } + + if placementGrpNameStr != "" { + listInstancesOptions.PlacementGroupName = &placementGrpNameStr + } + + if placementGrpIdStr != "" { + listInstancesOptions.PlacementGroupID = &placementGrpIdStr + } + + start := "" + allrecs := []vpcv1.Instance{} + for { + + if start != "" { + listInstancesOptions.Start = &start + } + + instances, response, err := sess.ListInstances(listInstancesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Instances %s\n%s", err, response) + } + start = flex.GetNext(instances.Next) + allrecs = append(allrecs, instances.Instances...) + if start == "" { + break + } + } + + if insGrp != "" { + membershipMap := map[string]bool{} + start := "" + for { + listInstanceGroupMembershipsOptions := vpcv1.ListInstanceGroupMembershipsOptions{ + InstanceGroupID: &insGrp, + } + if start != "" { + listInstanceGroupMembershipsOptions.Start = &start + } + instanceGroupMembershipCollection, response, err := sess.ListInstanceGroupMemberships(&listInstanceGroupMembershipsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Membership Collection %s\n%s", err, response) + } + + start = flex.GetNext(instanceGroupMembershipCollection.Next) + for _, membershipItem := range instanceGroupMembershipCollection.Memberships { + membershipMap[*membershipItem.Instance.ID] = true + } + + if start == "" { + break + } + + } + + //Filtering instance allrecs to contain instance group members only + i := 0 + for _, ins := range allrecs { + if membershipMap[*ins.ID] { + allrecs[i] = ins + i++ + } + } + allrecs = allrecs[:i] + } + + instancesInfo := make([]map[string]interface{}, 0) + for _, instance := range allrecs { + id := *instance.ID + l := map[string]interface{}{} + l["id"] = id + l["crn"] = *instance.CRN + l["name"] = *instance.Name + l["memory"] = *instance.Memory + if instance.MetadataService != nil { + l[isInstanceMetadataServiceEnabled] = *instance.MetadataService.Enabled + } + l["status"] = *instance.Status + l["resource_group"] = *instance.ResourceGroup.ID + l["vpc"] = *instance.VPC.ID + + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + l[isInstanceAvailablePolicyHostFailure] = *instance.AvailabilityPolicy.HostFailure + } + + if instance.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) + l["placement_target"] = []map[string]interface{}{placementTargetMap} + } + if instance.Bandwidth != nil { + l[isInstanceBandwidth] = int(*instance.Bandwidth) + } + + if instance.TotalNetworkBandwidth != nil { + l[isInstanceTotalNetworkBandwidth] = int(*instance.TotalNetworkBandwidth) + } + + if instance.TotalVolumeBandwidth != nil { + l[isInstanceTotalVolumeBandwidth] = int(*instance.TotalVolumeBandwidth) + } + + // catalog + if instance.CatalogOffering != nil { + versionCrn := *instance.CatalogOffering.Version.CRN + catalogList := make([]map[string]interface{}, 0) + catalogMap := map[string]interface{}{} + catalogMap[isInstanceCatalogOfferingVersionCrn] = versionCrn + catalogList = append(catalogList, catalogMap) + l[isInstanceCatalogOffering] = catalogList + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + bootVol["id"] = *instance.BootVolumeAttachment.ID + bootVol["name"] = *instance.BootVolumeAttachment.Name + if instance.BootVolumeAttachment.Device != nil { + bootVol["device"] = *instance.BootVolumeAttachment.Device.ID + } + if instance.BootVolumeAttachment.Volume != nil { + bootVol["volume_id"] = *instance.BootVolumeAttachment.Volume.ID + bootVol["volume_crn"] = *instance.BootVolumeAttachment.Volume.CRN + } + bootVolList = append(bootVolList, bootVol) + l["boot_volume"] = bootVolList + } + //set the status reasons + statusReasonsList := make([]map[string]interface{}, 0) + if instance.StatusReasons != nil { + for _, sr := range instance.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isInstanceStatusReasonsCode] = *sr.Code + currentSR[isInstanceStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + } + l[isInstanceStatusReasons] = statusReasonsList + + if instance.VolumeAttachments != nil { + volList := make([]map[string]interface{}, 0) + for _, volume := range instance.VolumeAttachments { + vol := map[string]interface{}{} + if volume.Volume != nil { + vol["id"] = *volume.ID + vol["volume_id"] = *volume.Volume.ID + vol["name"] = *volume.Name + vol["volume_name"] = *volume.Volume.Name + vol["volume_crn"] = *volume.Volume.CRN + volList = append(volList, vol) + } + } + l["volume_attachments"] = volList + } + + if instance.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID + currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name + + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + + if instance.PrimaryNetworkInterface.PrimaryIP.Address != nil { + currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + currentPrimIp[isInstanceNicReservedIpAddress] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + } + if instance.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *instance.PrimaryNetworkInterface.PrimaryIP.Href + } + if instance.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *instance.PrimaryNetworkInterface.PrimaryIP.Name + } + if instance.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *instance.PrimaryNetworkInterface.PrimaryIP.ID + } + if instance.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *instance.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: instance.PrimaryNetworkInterface.ID, + } + insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + primaryNicList = append(primaryNicList, currentPrimNic) + l["primary_network_interface"] = primaryNicList + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + if *intfc.ID != *instance.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + currentNic["id"] = *intfc.ID + currentNic[isInstanceNicName] = *intfc.Name + + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + if intfc.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *intfc.PrimaryIP.Address + currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *intfc.PrimaryIP.ID + } + if intfc.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *intfc.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: intfc.ID, + } + insnic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + } + } + l["network_interfaces"] = interfacesList + } + + l["profile"] = *instance.Profile.Name + + cpuList := make([]map[string]interface{}, 0) + if instance.Vcpu != nil { + currentCPU := map[string]interface{}{} + currentCPU["architecture"] = *instance.Vcpu.Architecture + currentCPU["count"] = *instance.Vcpu.Count + cpuList = append(cpuList, currentCPU) + } + l["vcpu"] = cpuList + + gpuList := make([]map[string]interface{}, 0) + if instance.Gpu != nil { + currentGpu := map[string]interface{}{} + currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer + currentGpu[isInstanceGpuModel] = instance.Gpu.Model + currentGpu[isInstanceGpuCount] = instance.Gpu.Count + currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory + gpuList = append(gpuList, currentGpu) + l[isInstanceGpu] = gpuList + } + + //set the lifecycle status, reasons + if instance.LifecycleState != nil { + l[isInstanceLifecycleState] = *instance.LifecycleState + } + if instance.LifecycleReasons != nil { + l[isInstanceLifecycleReasons] = dataSourceInstanceFlattenLifecycleReasons(instance.LifecycleReasons) + } + + l["zone"] = *instance.Zone.Name + if instance.Image != nil { + l["image"] = *instance.Image.ID + } + + if instance.Disks != nil { + l[isInstanceDisks] = dataSourceInstanceFlattenDisks(instance.Disks) + } + + instancesInfo = append(instancesInfo, l) + } + d.SetId(dataSourceIBMISInstancesID(d)) + d.Set(isInstances, instancesInfo) + return nil +} + +// dataSourceIBMISInstancesID returns a reasonable ID for a Instance list. +func dataSourceIBMISInstancesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_instances_test.go b/ibm/service/vpc/data_source_ibm_is_instances_test.go new file mode 100644 index 000000000..886e31920 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instances_test.go @@ -0,0 +1,210 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstancesDataSource_basic(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instances.ds_instances" + userData := "a" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", instanceName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstancesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "instances.0.name"), + resource.TestCheckResourceAttrSet(resName, "instances.0.memory"), + resource.TestCheckResourceAttrSet(resName, "instances.0.status"), + resource.TestCheckResourceAttrSet(resName, "instances.0.resource_group"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vpc"), + resource.TestCheckResourceAttrSet(resName, "instances.0.boot_volume.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.volume_attachments.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.network_interfaces.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.profile"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vcpu.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.zone"), + resource.TestCheckResourceAttrSet(resName, "instances.0.availability_policy_host_failure"), + resource.TestCheckResourceAttrSet(resName, "instances.0.lifecycle_state"), + resource.TestCheckResourceAttr(resName, "instances.0.lifecycle_reasons.#", "0"), + ), + }, + }, + }) +} +func TestAccIBMISInstancesDataSource_ReservedIp(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instances.ds_instances" + userData := "a" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", instanceName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstancesDataSourceReservedIpConfig(vpcname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "instances.0.name"), + resource.TestCheckResourceAttrSet(resName, "instances.0.memory"), + resource.TestCheckResourceAttrSet(resName, "instances.0.status"), + resource.TestCheckResourceAttrSet(resName, "instances.0.resource_group"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vpc"), + resource.TestCheckResourceAttrSet(resName, "instances.0.boot_volume.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.volume_attachments.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "instances.0.network_interfaces.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.profile"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vcpu.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.zone"), + ), + }, + }, + }) +} + +func TestAccIBMISInstancesDataSource_vpcfilter(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instances.ds_instances1" + userData := "a" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", instanceName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstancesDataSourceConfig1(vpcname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "instances.0.name"), + ), + }, + }, + }) +} + +func TestAccIBMISInstancesDataSource_InsGroupfilter(t *testing.T) { + + randInt := acctest.RandIntRange(10, 100) + instanceGroupName := fmt.Sprintf("testinstancegroup%d", randInt) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resName := "data.ibm_is_instances.ds_instances1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceGroupConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_group.instance_group", "name", instanceGroupName), + ), + }, + { + Config: testAccCheckIBMISInstancesDataSourceConfigInstanceGroup(instanceGroupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "instances.0.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstancesDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_is_instances" "ds_instances" { + }`) +} + +func testAccCheckIBMISInstancesDataSourceReservedIpConfig(vpcname string) string { + return fmt.Sprintf(` + data "ibm_is_instances" "ds_instances" { + vpc_name = "%s" + }`, vpcname) +} + +func testAccCheckIBMISInstancesDataSourceConfig1(vpcname string) string { + return fmt.Sprintf(` + data "ibm_is_instances" "ds_instances1" { + vpc_name = "%s" + }`, vpcname) +} +func testAccCheckIBMISInstancesDataSourceConfigInstanceGroup(insGrpName string) string { + return fmt.Sprintf(` + data "ibm_is_instances" "ds_instances1" { + instance_group_name = "%s" + }`, insGrpName) +} diff --git a/ibm/service/vpc/data_source_ibm_is_ipsec_policies.go b/ibm/service/vpc/data_source_ibm_is_ipsec_policies.go new file mode 100644 index 000000000..37fee725c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ipsec_policies.go @@ -0,0 +1,310 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsIpsecPolicies() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsIpsecPoliciesRead, + + Schema: map[string]*schema.Schema{ + "ipsec_policies": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of IPsec policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authentication_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The authentication algorithm.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "The VPN gateway connections that use this IPsec policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this IPsec policy was created.", + }, + "encapsulation_mode": { + Type: schema.TypeString, + Computed: true, + Description: "The encapsulation mode used. Only `tunnel` is supported.", + }, + "encryption_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The encryption algorithm.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IPsec policy's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this IPsec policy.", + }, + "key_lifetime": { + Type: schema.TypeInt, + Computed: true, + Description: "The key lifetime in seconds.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this IPsec policy.", + }, + "pfs": { + Type: schema.TypeString, + Computed: true, + Description: "Perfect Forward Secrecy.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this IPsec policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "transform_protocol": { + Type: schema.TypeString, + Computed: true, + Description: "The transform protocol used. Only `esp` is supported.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsIpsecPoliciesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.IPsecPolicy{} + for { + listIpsecPoliciesOptions := &vpcv1.ListIpsecPoliciesOptions{} + if start != "" { + listIpsecPoliciesOptions.Start = &start + } + iPsecPolicyCollection, response, err := vpcClient.ListIpsecPoliciesWithContext(context, listIpsecPoliciesOptions) + if err != nil || iPsecPolicyCollection == nil { + log.Printf("[DEBUG] ListIpsecPoliciesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListIpsecPoliciesWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(iPsecPolicyCollection.Next) + allrecs = append(allrecs, iPsecPolicyCollection.IpsecPolicies...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsIpsecPoliciesID(d)) + + err = d.Set("ipsec_policies", dataSourceIPsecPolicyCollectionFlattenIpsecPolicies(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting ipsec_policies %s", err)) + } + + return nil +} + +// dataSourceIBMIsIpsecPoliciesID returns a reasonable ID for the list. +func dataSourceIBMIsIpsecPoliciesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIPsecPolicyCollectionFlattenIpsecPolicies(result []vpcv1.IPsecPolicy) (ipsecPolicies []map[string]interface{}) { + for _, ipsecPoliciesItem := range result { + ipsecPolicies = append(ipsecPolicies, dataSourceIPsecPolicyCollectionIpsecPoliciesToMap(ipsecPoliciesItem)) + } + + return ipsecPolicies +} + +func dataSourceIPsecPolicyCollectionIpsecPoliciesToMap(ipsecPoliciesItem vpcv1.IPsecPolicy) (ipsecPoliciesMap map[string]interface{}) { + ipsecPoliciesMap = map[string]interface{}{} + + if ipsecPoliciesItem.AuthenticationAlgorithm != nil { + ipsecPoliciesMap["authentication_algorithm"] = ipsecPoliciesItem.AuthenticationAlgorithm + } + if ipsecPoliciesItem.Connections != nil { + connectionsList := []map[string]interface{}{} + for _, connectionsItem := range ipsecPoliciesItem.Connections { + connectionsList = append(connectionsList, dataSourceIPsecPolicyCollectionIpsecPoliciesConnectionsToMap(connectionsItem)) + } + ipsecPoliciesMap["connections"] = connectionsList + } + if ipsecPoliciesItem.CreatedAt != nil { + ipsecPoliciesMap["created_at"] = ipsecPoliciesItem.CreatedAt.String() + } + if ipsecPoliciesItem.EncapsulationMode != nil { + ipsecPoliciesMap["encapsulation_mode"] = ipsecPoliciesItem.EncapsulationMode + } + if ipsecPoliciesItem.EncryptionAlgorithm != nil { + ipsecPoliciesMap["encryption_algorithm"] = ipsecPoliciesItem.EncryptionAlgorithm + } + if ipsecPoliciesItem.Href != nil { + ipsecPoliciesMap["href"] = ipsecPoliciesItem.Href + } + if ipsecPoliciesItem.ID != nil { + ipsecPoliciesMap["id"] = ipsecPoliciesItem.ID + } + if ipsecPoliciesItem.KeyLifetime != nil { + ipsecPoliciesMap["key_lifetime"] = ipsecPoliciesItem.KeyLifetime + } + if ipsecPoliciesItem.Name != nil { + ipsecPoliciesMap["name"] = ipsecPoliciesItem.Name + } + if ipsecPoliciesItem.Pfs != nil { + ipsecPoliciesMap["pfs"] = ipsecPoliciesItem.Pfs + } + if ipsecPoliciesItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceIPsecPolicyCollectionIpsecPoliciesResourceGroupToMap(*ipsecPoliciesItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + ipsecPoliciesMap["resource_group"] = resourceGroupList + } + if ipsecPoliciesItem.ResourceType != nil { + ipsecPoliciesMap["resource_type"] = ipsecPoliciesItem.ResourceType + } + if ipsecPoliciesItem.TransformProtocol != nil { + ipsecPoliciesMap["transform_protocol"] = ipsecPoliciesItem.TransformProtocol + } + + return ipsecPoliciesMap +} + +func dataSourceIPsecPolicyCollectionIpsecPoliciesConnectionsToMap(connectionsItem vpcv1.VPNGatewayConnectionReference) (connectionsMap map[string]interface{}) { + connectionsMap = map[string]interface{}{} + + if connectionsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceIPsecPolicyCollectionConnectionsDeletedToMap(*connectionsItem.Deleted) + deletedList = append(deletedList, deletedMap) + connectionsMap["deleted"] = deletedList + } + if connectionsItem.Href != nil { + connectionsMap["href"] = connectionsItem.Href + } + if connectionsItem.ID != nil { + connectionsMap["id"] = connectionsItem.ID + } + if connectionsItem.Name != nil { + connectionsMap["name"] = connectionsItem.Name + } + if connectionsItem.ResourceType != nil { + connectionsMap["resource_type"] = connectionsItem.ResourceType + } + + return connectionsMap +} + +func dataSourceIPsecPolicyCollectionConnectionsDeletedToMap(deletedItem vpcv1.VPNGatewayConnectionReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceIPsecPolicyCollectionIpsecPoliciesResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_ipsec_policies_test.go b/ibm/service/vpc/data_source_ibm_is_ipsec_policies_test.go new file mode 100644 index 000000000..fc88810cb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ipsec_policies_test.go @@ -0,0 +1,51 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsIpsecPoliciesDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tfipsecc-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsIpsecPoliciesDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.encapsulation_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.encryption_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.pfs"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policies.is_ipsec_policies", "ipsec_policies.0.transform_protocol"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsIpsecPoliciesDataSourceConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_is_ipsec_policy" "example" { + name = "%s" + authentication_algorithm = "sha1" + encryption_algorithm = "aes128" + pfs = "group_2" + } + data "ibm_is_ipsec_policies" "is_ipsec_policies" { + depends_on = [ibm_is_ipsec_policy.example] + } + `, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_ipsec_policy.go b/ibm/service/vpc/data_source_ibm_is_ipsec_policy.go new file mode 100644 index 000000000..b4a7a64bd --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ipsec_policy.go @@ -0,0 +1,321 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsIpsecPolicy() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsIpsecPolicyRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "ipsec_policy"}, + Description: "The IPsec policy name.", + }, + "ipsec_policy": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "ipsec_policy"}, + Description: "The IPsec policy identifier.", + }, + "authentication_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The authentication algorithm.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "The VPN gateway connections that use this IPsec policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this IPsec policy was created.", + }, + "encapsulation_mode": { + Type: schema.TypeString, + Computed: true, + Description: "The encapsulation mode used. Only `tunnel` is supported.", + }, + "encryption_algorithm": { + Type: schema.TypeString, + Computed: true, + Description: "The encryption algorithm.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IPsec policy's canonical URL.", + }, + "key_lifetime": { + Type: schema.TypeInt, + Computed: true, + Description: "The key lifetime in seconds.", + }, + + "pfs": { + Type: schema.TypeString, + Computed: true, + Description: "Perfect Forward Secrecy.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this IPsec policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "transform_protocol": { + Type: schema.TypeString, + Computed: true, + Description: "The transform protocol used. Only `esp` is supported.", + }, + }, + } +} + +func dataSourceIBMIsIpsecPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get("name").(string) + identifier := d.Get("ipsec_policy").(string) + var IPSecPolicy *vpcv1.IPsecPolicy + if name != "" { + start := "" + allrecs := []vpcv1.IPsecPolicy{} + for { + listIPSecPoliciesyOptions := &vpcv1.ListIpsecPoliciesOptions{} + if start != "" { + listIPSecPoliciesyOptions.Start = &start + } + ipSecPolicy, response, err := vpcClient.ListIpsecPolicies(listIPSecPoliciesyOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("Error Fetching IPSec Policies %s\n%s", err, response)) + } + start = flex.GetNext(ipSecPolicy.Next) + allrecs = append(allrecs, ipSecPolicy.IpsecPolicies...) + if start == "" { + break + } + } + ipsec_policy_found := false + for _, ipSecPolicyItem := range allrecs { + if *ipSecPolicyItem.Name == name { + IPSecPolicy = &ipSecPolicyItem + ipsec_policy_found = true + break + } + } + + if !ipsec_policy_found { + log.Printf("[DEBUG] No ipsec policy found with given name %s", name) + return diag.FromErr(fmt.Errorf("No ipsec policy found with given name %s", name)) + } + + } else { + getIPSecPolicyOptions := &vpcv1.GetIpsecPolicyOptions{} + + getIPSecPolicyOptions.SetID(identifier) + + ipsecPolicy1, response, err := vpcClient.GetIpsecPolicyWithContext(context, getIPSecPolicyOptions) + if err != nil { + log.Printf("[DEBUG] GetIpsecPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetIpsecPolicyWithContext failed %s\n%s", err, response)) + } + IPSecPolicy = ipsecPolicy1 + } + + d.SetId(*IPSecPolicy.ID) + if err = d.Set("authentication_algorithm", IPSecPolicy.AuthenticationAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting authentication_algorithm: %s", err)) + } + + if IPSecPolicy.Connections != nil { + err = d.Set("connections", dataSourceIPsecPolicyFlattenConnections(IPSecPolicy.Connections)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting connections %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(IPSecPolicy.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("encapsulation_mode", IPSecPolicy.EncapsulationMode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting encapsulation_mode: %s", err)) + } + if err = d.Set("encryption_algorithm", IPSecPolicy.EncryptionAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting encryption_algorithm: %s", err)) + } + if err = d.Set("href", IPSecPolicy.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("key_lifetime", flex.IntValue(IPSecPolicy.KeyLifetime)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting key_lifetime: %s", err)) + } + if err = d.Set("name", IPSecPolicy.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("pfs", IPSecPolicy.Pfs); err != nil { + return diag.FromErr(fmt.Errorf("Error setting pfs: %s", err)) + } + + if IPSecPolicy.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceIPsecPolicyFlattenResourceGroup(*IPSecPolicy.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + } + } + if err = d.Set("resource_type", IPSecPolicy.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + if err = d.Set("transform_protocol", IPSecPolicy.TransformProtocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting transform_protocol: %s", err)) + } + + return nil +} + +func dataSourceIPsecPolicyFlattenConnections(result []vpcv1.VPNGatewayConnectionReference) (connections []map[string]interface{}) { + for _, connectionsItem := range result { + connections = append(connections, dataSourceIPsecPolicyConnectionsToMap(connectionsItem)) + } + + return connections +} + +func dataSourceIPsecPolicyConnectionsToMap(connectionsItem vpcv1.VPNGatewayConnectionReference) (connectionsMap map[string]interface{}) { + connectionsMap = map[string]interface{}{} + + if connectionsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceIPsecPolicyConnectionsDeletedToMap(*connectionsItem.Deleted) + deletedList = append(deletedList, deletedMap) + connectionsMap["deleted"] = deletedList + } + if connectionsItem.Href != nil { + connectionsMap["href"] = connectionsItem.Href + } + if connectionsItem.ID != nil { + connectionsMap["id"] = connectionsItem.ID + } + if connectionsItem.Name != nil { + connectionsMap["name"] = connectionsItem.Name + } + if connectionsItem.ResourceType != nil { + connectionsMap["resource_type"] = connectionsItem.ResourceType + } + + return connectionsMap +} + +func dataSourceIPsecPolicyConnectionsDeletedToMap(deletedItem vpcv1.VPNGatewayConnectionReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceIPsecPolicyFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceIPsecPolicyResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceIPsecPolicyResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_ipsec_policy_test.go b/ibm/service/vpc/data_source_ibm_is_ipsec_policy_test.go new file mode 100644 index 000000000..766d03463 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ipsec_policy_test.go @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsIpsecPolicyDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tfipsecc-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsIpsecPolicyDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "connections.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "encapsulation_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "encryption_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "pfs"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy", "transform_protocol"), + ), + }, + { + Config: testAccCheckIBMIsIpsecPolicyDataSourceConfigBasic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "authentication_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "connections.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "encapsulation_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "encryption_algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "key_lifetime"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "pfs"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_ipsec_policy.is_ipsec_policy1", "transform_protocol"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsIpsecPolicyDataSourceConfigBasic(name string) string { + return fmt.Sprintf(` + resource "ibm_is_ipsec_policy" "example" { + name = "%s" + authentication_algorithm = "sha1" + encryption_algorithm = "aes128" + pfs = "group_2" + } + data "ibm_is_ipsec_policy" "is_ipsec_policy" { + ipsec_policy = ibm_is_ipsec_policy.example.id + } + data "ibm_is_ipsec_policy" "is_ipsec_policy1" { + name = ibm_is_ipsec_policy.example.name + } + `, name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb.go b/ibm/service/vpc/data_source_ibm_is_lb.go new file mode 100644 index 000000000..a15002975 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb.go @@ -0,0 +1,505 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "strconv" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + name = "name" + poolAlgorithm = "algorithm" + href = "href" + poolProtocol = "protocol" + poolCreatedAt = "created_at" + poolProvisioningStatus = "provisioning_status" + healthMonitor = "health_monitor" + instanceGroup = "instance_group" + members = "members" + sessionPersistence = "session_persistence" + crnInstance = "crn" + sessionType = "type" + healthMonitorType = "type" + healthMonitorDelay = "delay" + healthMonitorMaxRetries = "max_retries" + healthMonitorPort = "port" + healthMonitorTimeout = "timeout" + healthMonitorURLPath = "url_path" + isLBPrivateIPDetail = "private_ip" + isLBPrivateIpAddress = "address" + isLBPrivateIpHref = "href" + isLBPrivateIpName = "name" + isLBPrivateIpId = "reserved_ip" + isLBPrivateIpResourceType = "resource_type" +) + +func DataSourceIBMISLB() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISLBRead, + + Schema: map[string]*schema.Schema{ + isLBName: { + Type: schema.TypeString, + Required: true, + Description: "Load Balancer name", + }, + + isLBType: { + Type: schema.TypeString, + Computed: true, + Description: "Load Balancer type", + }, + + isLBUdpSupported: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this load balancer supports UDP.", + }, + + isLBStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Load Balancer status", + }, + + isLBRouteMode: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether route mode is enabled for this load balancer", + }, + + isLBCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this Load Balancer", + }, + + isLBOperatingStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Load Balancer operating status", + }, + + isLBPublicIPs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Load Balancer Public IPs", + }, + + isLBPrivateIPs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Load Balancer private IPs", + }, + + isLBSubnets: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Load Balancer subnets list", + }, + + isLBSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Load Balancer securitygroups list", + }, + + isLBSecurityGroupsSupported: { + Type: schema.TypeBool, + Computed: true, + Description: "Security Group Supported for this Load Balancer", + }, + + isLBTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Tags associated to Load Balancer", + }, + + isLBResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Load Balancer Resource group", + }, + + isLBHostName: { + Type: schema.TypeString, + Computed: true, + Description: "Load Balancer Host Name", + }, + + isLBLogging: { + Type: schema.TypeBool, + Computed: true, + Description: "Logging of Load Balancer", + }, + + isLBListeners: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Load Balancer Listeners list", + }, + isLBPools: { + Type: schema.TypeList, + Computed: true, + Description: "Load Balancer Pools list", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + poolAlgorithm: { + Type: schema.TypeString, + Computed: true, + Description: "The load balancing algorithm.", + }, + healthMonitor: { + Description: "The health monitor of this pool.", + Computed: true, + Type: schema.TypeMap, + }, + + instanceGroup: { + Description: "The instance group that is managing this pool.", + Computed: true, + Type: schema.TypeMap, + }, + + members: { + Description: "The backend server members of the pool.", + Computed: true, + Type: schema.TypeList, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + href: { + Type: schema.TypeString, + Computed: true, + Description: "The member's canonical URL.", + }, + ID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool member.", + }, + }, + }, + }, + sessionPersistence: { + Description: "The session persistence of this pool.", + Computed: true, + Type: schema.TypeMap, + }, + poolCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this pool was created.", + }, + href: { + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + ID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool", + }, + name: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool", + }, + poolProtocol: { + Type: schema.TypeString, + Computed: true, + Description: "The protocol used for this load balancer pool.", + }, + poolProvisioningStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this pool.", + }, + }, + }, + }, + isLBPrivateIPDetail: { + Type: schema.TypeList, + Computed: true, + Description: "The private IP addresses assigned to this load balancer.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isLBPrivateIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isLBPrivateIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isLBPrivateIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isLBPrivateIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isLBPrivateIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func dataSourceIBMISLBRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isLBName).(string) + err := lbGetByName(d, meta, name) + if err != nil { + return err + } + return nil +} + +func lbGetByName(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + start := "" + allrecs := []vpcv1.LoadBalancer{} + for { + listLoadBalancersOptions := &vpcv1.ListLoadBalancersOptions{} + if start != "" { + listLoadBalancersOptions.Start = &start + } + lbs, response, err := sess.ListLoadBalancers(listLoadBalancersOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Load Balancers %s\n%s", err, response) + } + start = flex.GetNext(lbs.Next) + allrecs = append(allrecs, lbs.LoadBalancers...) + if start == "" { + break + } + } + + for _, lb := range allrecs { + if *lb.Name == name { + d.SetId(*lb.ID) + d.Set(isLBName, *lb.Name) + if lb.Logging != nil && lb.Logging.Datapath != nil { + d.Set(isLBLogging, *lb.Logging.Datapath.Active) + } + if *lb.IsPublic { + d.Set(isLBType, "public") + } else { + d.Set(isLBType, "private") + } + d.Set(isLBStatus, *lb.ProvisioningStatus) + if lb.RouteMode != nil { + d.Set(isLBRouteMode, *lb.RouteMode) + } + if lb.UDPSupported != nil { + d.Set(isLBUdpSupported, *lb.UDPSupported) + } + d.Set(isLBCrn, *lb.CRN) + d.Set(isLBOperatingStatus, *lb.OperatingStatus) + publicIpList := make([]string, 0) + if lb.PublicIps != nil { + for _, ip := range lb.PublicIps { + if ip.Address != nil { + pubip := *ip.Address + publicIpList = append(publicIpList, pubip) + } + } + } + d.Set(isLBPublicIPs, publicIpList) + privateIpList := make([]string, 0) + privateIpDetailList := make([]map[string]interface{}, 0) + if lb.PrivateIps != nil { + for _, ip := range lb.PrivateIps { + if ip.Address != nil { + prip := *ip.Address + privateIpList = append(privateIpList, prip) + } + currentPriIp := map[string]interface{}{} + + if ip.Address != nil { + currentPriIp[isLBPrivateIpAddress] = ip.Address + } + if ip.Href != nil { + currentPriIp[isLBPrivateIpHref] = ip.Href + } + if ip.Name != nil { + currentPriIp[isLBPrivateIpName] = ip.Name + } + if ip.ID != nil { + currentPriIp[isLBPrivateIpId] = ip.ID + } + if ip.ResourceType != nil { + currentPriIp[isLBPrivateIpResourceType] = ip.ResourceType + } + privateIpDetailList = append(privateIpDetailList, currentPriIp) + + } + } + d.Set(isLBPrivateIPDetail, privateIpDetailList) + d.Set(isLBPrivateIPs, privateIpList) + if lb.Subnets != nil { + subnetList := make([]string, 0) + for _, subnet := range lb.Subnets { + if subnet.ID != nil { + sub := *subnet.ID + subnetList = append(subnetList, sub) + } + } + d.Set(isLBSubnets, subnetList) + } + + d.Set(isLBSecurityGroupsSupported, false) + if lb.SecurityGroups != nil { + securitygroupList := make([]string, 0) + for _, securityGroup := range lb.SecurityGroups { + if securityGroup.ID != nil { + securityGroupID := *securityGroup.ID + securitygroupList = append(securitygroupList, securityGroupID) + } + } + d.Set(isLBSecurityGroups, securitygroupList) + d.Set(isLBSecurityGroupsSupported, true) + } + + if lb.Listeners != nil { + listenerList := make([]string, 0) + for _, listener := range lb.Listeners { + if listener.ID != nil { + lis := *listener.ID + listenerList = append(listenerList, lis) + } + } + d.Set(isLBListeners, listenerList) + } + listLoadBalancerPoolsOptions := &vpcv1.ListLoadBalancerPoolsOptions{} + listLoadBalancerPoolsOptions.SetLoadBalancerID(*lb.ID) + poolsResult, _, _ := sess.ListLoadBalancerPools(listLoadBalancerPoolsOptions) + if poolsResult != nil { + poolsInfo := make([]map[string]interface{}, 0) + + for _, p := range poolsResult.Pools { + // log.Printf("******* p ******** : (%+v)", p) + pool := make(map[string]interface{}) + pool[poolAlgorithm] = *p.Algorithm + pool[ID] = *p.ID + pool[href] = *p.Href + pool[poolProtocol] = *p.Protocol + pool[poolCreatedAt] = p.CreatedAt.String() + pool[poolProvisioningStatus] = *p.ProvisioningStatus + pool["name"] = *p.Name + if p.HealthMonitor != nil { + healthMonitorInfo := make(map[string]interface{}) + delayfinal := strconv.FormatInt(*(p.HealthMonitor.Delay), 10) + healthMonitorInfo[healthMonitorDelay] = delayfinal + maxRetriesfinal := strconv.FormatInt(*(p.HealthMonitor.MaxRetries), 10) + timeoutfinal := strconv.FormatInt(*(p.HealthMonitor.Timeout), 10) + healthMonitorInfo[healthMonitorMaxRetries] = maxRetriesfinal + healthMonitorInfo[healthMonitorTimeout] = timeoutfinal + if p.HealthMonitor.URLPath != nil { + healthMonitorInfo[healthMonitorURLPath] = *(p.HealthMonitor.URLPath) + } + healthMonitorInfo[healthMonitorType] = *(p.HealthMonitor.Type) + pool[healthMonitor] = healthMonitorInfo + } + + if p.SessionPersistence != nil { + sessionPersistenceInfo := make(map[string]interface{}) + sessionPersistenceInfo[sessionType] = *p.SessionPersistence.Type + pool[sessionPersistence] = sessionPersistenceInfo + } + if p.Members != nil { + memberList := make([]map[string]interface{}, len(p.Members)) + for j, m := range p.Members { + member := make(map[string]interface{}) + member[ID] = *m.ID + member[href] = *m.Href + memberList[j] = member + } + pool[members] = memberList + } + + if p.InstanceGroup != nil { + instanceGroupInfo := make(map[string]interface{}) + instanceGroupInfo[ID] = *(p.InstanceGroup.ID) + instanceGroupInfo[crnInstance] = *(p.InstanceGroup.CRN) + instanceGroupInfo[href] = *(p.InstanceGroup.Href) + instanceGroupInfo[name] = *(p.InstanceGroup.Name) + pool[instanceGroup] = instanceGroupInfo + } + poolsInfo = append(poolsInfo, pool) + } //for + d.Set(isLBPools, poolsInfo) + } + + d.Set(isLBResourceGroup, *lb.ResourceGroup.ID) + d.Set(isLBHostName, *lb.Hostname) + tags, err := flex.GetTagsUsingCRN(meta, *lb.CRN) + if err != nil { + log.Printf( + "Error on get of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) + } + d.Set(isLBTags, tags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/loadBalancers") + d.Set(flex.ResourceName, *lb.Name) + if lb.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, *lb.ResourceGroup.ID) + } + return nil + } + } + return fmt.Errorf("[ERROR] No Load balancer found with name %s", name) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener.go b/ibm/service/vpc/data_source_ibm_is_lb_listener.go new file mode 100644 index 000000000..e3d1b8718 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener.go @@ -0,0 +1,446 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListener() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenerRead, + + Schema: map[string]*schema.Schema{ + isLBListenerLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + isLBListenerID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The listener identifier.", + }, + "accept_proxy_protocol": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value.", + }, + "certificate_instance": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The certificate instance used for SSL termination. It is applicable only to `https`protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance.", + }, + }, + }, + }, + "connection_limit": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The connection limit of the listener.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this listener was created.", + }, + "default_pool": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The default pool associated with the listener.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "https_redirect": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If specified, the target listener that requests are redirected to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The HTTP status code for this redirect.", + }, + "listener": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect relative target URI.", + }, + }, + }, + }, + "policies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The policies for this listener.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener policy's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy's unique identifier.", + }, + }, + }, + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + }, + "port_max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + }, + "port_min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener protocol. Load balancers in the `network` family support `tcp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this listener.", + }, + }, + } +} + +func dataSourceIBMIsLbListenerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getLoadBalancerListenerOptions := &vpcv1.GetLoadBalancerListenerOptions{} + + getLoadBalancerListenerOptions.SetLoadBalancerID(d.Get(isLBListenerLBID).(string)) + getLoadBalancerListenerOptions.SetID(d.Get(isLBListenerID).(string)) + + loadBalancerListener, response, err := vpcClient.GetLoadBalancerListenerWithContext(context, getLoadBalancerListenerOptions) + if err != nil { + log.Printf("[DEBUG] GetLoadBalancerListenerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLoadBalancerListenerWithContext failed %s\n%s", err, response)) + } + + d.SetId(*loadBalancerListener.ID) + if err = d.Set("accept_proxy_protocol", loadBalancerListener.AcceptProxyProtocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting accept_proxy_protocol: %s", err)) + } + + if loadBalancerListener.CertificateInstance != nil { + err = d.Set("certificate_instance", dataSourceLoadBalancerListenerFlattenCertificateInstance(*loadBalancerListener.CertificateInstance)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_instance %s", err)) + } + } + if loadBalancerListener.ConnectionLimit != nil { + if err = d.Set("connection_limit", flex.IntValue(loadBalancerListener.ConnectionLimit)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting connection_limit: %s", err)) + } + } + if err = d.Set("created_at", loadBalancerListener.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if loadBalancerListener.DefaultPool != nil { + err = d.Set("default_pool", dataSourceLoadBalancerListenerFlattenDefaultPool(*loadBalancerListener.DefaultPool)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting default_pool %s", err)) + } + } + if err = d.Set("href", loadBalancerListener.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if loadBalancerListener.HTTPSRedirect != nil { + err = d.Set("https_redirect", dataSourceLoadBalancerListenerFlattenHTTPSRedirect(*loadBalancerListener.HTTPSRedirect)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting https_redirect %s", err)) + } + } + + if loadBalancerListener.Policies != nil { + err = d.Set("policies", dataSourceLoadBalancerListenerFlattenPolicies(loadBalancerListener.Policies)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting policies %s", err)) + } + } + if err = d.Set("port", flex.IntValue(loadBalancerListener.Port)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port: %s", err)) + } + if err = d.Set("port_max", flex.IntValue(loadBalancerListener.PortMax)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port_max: %s", err)) + } + if err = d.Set("port_min", flex.IntValue(loadBalancerListener.PortMin)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port_min: %s", err)) + } + if err = d.Set("protocol", loadBalancerListener.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting protocol: %s", err)) + } + if err = d.Set("provisioning_status", loadBalancerListener.ProvisioningStatus); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provisioning_status: %s", err)) + } + + return nil +} + +func dataSourceLoadBalancerListenerFlattenCertificateInstance(result vpcv1.CertificateInstanceReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerListenerCertificateInstanceToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerListenerCertificateInstanceToMap(certificateInstanceItem vpcv1.CertificateInstanceReference) (certificateInstanceMap map[string]interface{}) { + certificateInstanceMap = map[string]interface{}{} + + if certificateInstanceItem.CRN != nil { + certificateInstanceMap["crn"] = certificateInstanceItem.CRN + } + + return certificateInstanceMap +} + +func dataSourceLoadBalancerListenerFlattenDefaultPool(result vpcv1.LoadBalancerPoolReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerListenerDefaultPoolToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerListenerDefaultPoolToMap(defaultPoolItem vpcv1.LoadBalancerPoolReference) (defaultPoolMap map[string]interface{}) { + defaultPoolMap = map[string]interface{}{} + + if defaultPoolItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerDefaultPoolDeletedToMap(*defaultPoolItem.Deleted) + deletedList = append(deletedList, deletedMap) + defaultPoolMap["deleted"] = deletedList + } + if defaultPoolItem.Href != nil { + defaultPoolMap["href"] = defaultPoolItem.Href + } + if defaultPoolItem.ID != nil { + defaultPoolMap["id"] = defaultPoolItem.ID + } + if defaultPoolItem.Name != nil { + defaultPoolMap["name"] = defaultPoolItem.Name + } + + return defaultPoolMap +} + +func dataSourceLoadBalancerListenerDefaultPoolDeletedToMap(deletedItem vpcv1.LoadBalancerPoolReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerFlattenHTTPSRedirect(result vpcv1.LoadBalancerListenerHTTPSRedirect) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerListenerHTTPSRedirectToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerListenerHTTPSRedirectToMap(httpsRedirectItem vpcv1.LoadBalancerListenerHTTPSRedirect) (httpsRedirectMap map[string]interface{}) { + httpsRedirectMap = map[string]interface{}{} + + if httpsRedirectItem.HTTPStatusCode != nil { + httpsRedirectMap["http_status_code"] = httpsRedirectItem.HTTPStatusCode + } + if httpsRedirectItem.Listener != nil { + listenerList := []map[string]interface{}{} + listenerMap := dataSourceLoadBalancerListenerHTTPSRedirectListenerToMap(*httpsRedirectItem.Listener) + listenerList = append(listenerList, listenerMap) + httpsRedirectMap["listener"] = listenerList + } + if httpsRedirectItem.URI != nil { + httpsRedirectMap["uri"] = httpsRedirectItem.URI + } + + return httpsRedirectMap +} + +func dataSourceLoadBalancerListenerHTTPSRedirectListenerToMap(listenerItem vpcv1.LoadBalancerListenerReference) (listenerMap map[string]interface{}) { + listenerMap = map[string]interface{}{} + + if listenerItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerListenerDeletedToMap(*listenerItem.Deleted) + deletedList = append(deletedList, deletedMap) + listenerMap["deleted"] = deletedList + } + if listenerItem.Href != nil { + listenerMap["href"] = listenerItem.Href + } + if listenerItem.ID != nil { + listenerMap["id"] = listenerItem.ID + } + + return listenerMap +} + +func dataSourceLoadBalancerListenerListenerDeletedToMap(deletedItem vpcv1.LoadBalancerListenerReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerFlattenPolicies(result []vpcv1.LoadBalancerListenerPolicyReference) (policies []map[string]interface{}) { + for _, policiesItem := range result { + policies = append(policies, dataSourceLoadBalancerListenerPoliciesToMap(policiesItem)) + } + + return policies +} + +func dataSourceLoadBalancerListenerPoliciesToMap(policiesItem vpcv1.LoadBalancerListenerPolicyReference) (policiesMap map[string]interface{}) { + policiesMap = map[string]interface{}{} + + if policiesItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPoliciesDeletedToMap(*policiesItem.Deleted) + deletedList = append(deletedList, deletedMap) + policiesMap["deleted"] = deletedList + } + if policiesItem.Href != nil { + policiesMap["href"] = policiesItem.Href + } + if policiesItem.ID != nil { + policiesMap["id"] = policiesItem.ID + } + + return policiesMap +} + +func dataSourceLoadBalancerListenerPoliciesDeletedToMap(deletedItem vpcv1.LoadBalancerListenerPolicyReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policies.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policies.go new file mode 100644 index 000000000..4a3232fce --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policies.go @@ -0,0 +1,386 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListenerPolicies() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenerPoliciesRead, + + Schema: map[string]*schema.Schema{ + isLBListenerPolicyLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + isLBListenerPolicyListenerID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The listener identifier.", + }, + "policies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this policy was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener policy's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy's unique identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this policy.", + }, + "priority": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Priority of the policy. Lower value indicates higher priority.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this policy.", + }, + "rules": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The rules for this policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's unique identifier.", + }, + }, + }, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "- If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The HTTP status code for this redirect.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect target URL.", + }, + "listener": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect relative target URI.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbListenerPoliciesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listLoadBalancerListenerPoliciesOptions := &vpcv1.ListLoadBalancerListenerPoliciesOptions{} + + listLoadBalancerListenerPoliciesOptions.SetLoadBalancerID(d.Get(isLBListenerPolicyLBID).(string)) + listLoadBalancerListenerPoliciesOptions.SetListenerID(d.Get(isLBListenerPolicyListenerID).(string)) + + loadBalancerListenerPolicyCollection, response, err := vpcClient.ListLoadBalancerListenerPoliciesWithContext(context, listLoadBalancerListenerPoliciesOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerListenerPoliciesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerListenerPoliciesWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIsLbListenerPoliciesID(d)) + + if loadBalancerListenerPolicyCollection.Policies != nil { + err = d.Set("policies", dataSourceLoadBalancerListenerPolicyCollectionFlattenPolicies(loadBalancerListenerPolicyCollection.Policies)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting policies %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsLbListenerPoliciesID returns a reasonable ID for the list. +func dataSourceIBMIsLbListenerPoliciesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceLoadBalancerListenerPolicyCollectionFlattenPolicies(result []vpcv1.LoadBalancerListenerPolicy) (policies []map[string]interface{}) { + for _, policiesItem := range result { + policies = append(policies, dataSourceLoadBalancerListenerPolicyCollectionPoliciesToMap(policiesItem)) + } + + return policies +} + +func dataSourceLoadBalancerListenerPolicyCollectionPoliciesToMap(policiesItem vpcv1.LoadBalancerListenerPolicy) (policiesMap map[string]interface{}) { + policiesMap = map[string]interface{}{} + + if policiesItem.Action != nil { + policiesMap["action"] = policiesItem.Action + } + if policiesItem.CreatedAt != nil { + policiesMap["created_at"] = policiesItem.CreatedAt.String() + } + if policiesItem.Href != nil { + policiesMap["href"] = policiesItem.Href + } + if policiesItem.ID != nil { + policiesMap["id"] = policiesItem.ID + } + if policiesItem.Name != nil { + policiesMap["name"] = policiesItem.Name + } + if policiesItem.Priority != nil { + policiesMap["priority"] = policiesItem.Priority + } + if policiesItem.ProvisioningStatus != nil { + policiesMap["provisioning_status"] = policiesItem.ProvisioningStatus + } + if policiesItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, rulesItem := range policiesItem.Rules { + rulesList = append(rulesList, dataSourceLoadBalancerListenerPolicyCollectionPoliciesRulesToMap(rulesItem)) + } + policiesMap["rules"] = rulesList + } + if policiesItem.Target != nil { + targetList := []map[string]interface{}{} + target := policiesItem.Target.(*vpcv1.LoadBalancerListenerPolicyTarget) + targetMap := dataSourceLoadBalancerListenerPolicyCollectionPoliciesTargetToMap(*target) + targetList = append(targetList, targetMap) + policiesMap["target"] = targetList + } + + return policiesMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionPoliciesRulesToMap(rulesItem vpcv1.LoadBalancerListenerPolicyRuleReference) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + + if rulesItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyCollectionRulesDeletedToMap(*rulesItem.Deleted) + deletedList = append(deletedList, deletedMap) + rulesMap["deleted"] = deletedList + } + if rulesItem.Href != nil { + rulesMap["href"] = rulesItem.Href + } + if rulesItem.ID != nil { + rulesMap["id"] = rulesItem.ID + } + + return rulesMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionRulesDeletedToMap(deletedItem vpcv1.LoadBalancerListenerPolicyRuleReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionPoliciesTargetToMap(targetItem vpcv1.LoadBalancerListenerPolicyTarget) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyCollectionTargetDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.HTTPStatusCode != nil { + targetMap["http_status_code"] = targetItem.HTTPStatusCode + } + if targetItem.URL != nil { + targetMap["url"] = targetItem.URL + } + if targetItem.Listener != nil { + listenerList := []map[string]interface{}{} + listenerMap := dataSourceLoadBalancerListenerPolicyCollectionTargetListenerToMap(*targetItem.Listener) + listenerList = append(listenerList, listenerMap) + targetMap["listener"] = listenerList + } + if targetItem.URI != nil { + targetMap["uri"] = targetItem.URI + } + + return targetMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionTargetDeletedToMap(deletedItem vpcv1.LoadBalancerPoolReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionTargetListenerToMap(listenerItem vpcv1.LoadBalancerListenerReference) (listenerMap map[string]interface{}) { + listenerMap = map[string]interface{}{} + + if listenerItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyCollectionListenerDeletedToMap(*listenerItem.Deleted) + deletedList = append(deletedList, deletedMap) + listenerMap["deleted"] = deletedList + } + if listenerItem.Href != nil { + listenerMap["href"] = listenerItem.Href + } + if listenerItem.ID != nil { + listenerMap["id"] = listenerItem.ID + } + + return listenerMap +} + +func dataSourceLoadBalancerListenerPolicyCollectionListenerDeletedToMap(deletedItem vpcv1.LoadBalancerListenerReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policies_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policies_test.go new file mode 100644 index 000000000..6eb585fab --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policies_test.go @@ -0,0 +1,49 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenerPoliciesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblisuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblisuat-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblisuat%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyname1 := fmt.Sprintf("tflblisuat-listener-policy-%d", acctest.RandIntRange(10, 100)) + priority1 := "1" + protocol := "http" + port := "8080" + action := "forward" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenerPoliciesDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policies.is_lb_listener_policies", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policies.is_lb_listener_policies", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policies.is_lb_listener_policies", "listener"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policies.is_lb_listener_policies", "policies.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenerPoliciesDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol, lblistenerpolicyname, action, priority string) string { + return testAccCheckIBMISLBListenerPolicyConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority) + fmt.Sprintf(` + data "ibm_is_lb_listener_policies" "is_lb_listener_policies" { + lb = "${ibm_is_lb.testacc_LB.id}" + listener = "${ibm_is_lb_listener.testacc_lb_listener.listener_id}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy.go new file mode 100644 index 000000000..9ebd0df2b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy.go @@ -0,0 +1,365 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListenerPolicy() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenerPolicyRead, + + Schema: map[string]*schema.Schema{ + isLBListenerPolicyLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + isLBListenerPolicyListenerID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The listener identifier.", + }, + isLBListenerPolicyID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The policy identifier.", + }, + "action": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this policy was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener policy's canonical URL.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this policy.", + }, + "priority": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Priority of the policy. Lower value indicates higher priority.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this policy.", + }, + "rules": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The rules for this policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's unique identifier.", + }, + }, + }, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "- If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The HTTP status code for this redirect.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect target URL.", + }, + "listener": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect relative target URI.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbListenerPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getLoadBalancerListenerPolicyOptions := &vpcv1.GetLoadBalancerListenerPolicyOptions{} + + getLoadBalancerListenerPolicyOptions.SetLoadBalancerID(d.Get(isLBListenerPolicyLBID).(string)) + getLoadBalancerListenerPolicyOptions.SetListenerID(d.Get(isLBListenerPolicyListenerID).(string)) + getLoadBalancerListenerPolicyOptions.SetID(d.Get(isLBListenerPolicyID).(string)) + + loadBalancerListenerPolicy, response, err := vpcClient.GetLoadBalancerListenerPolicyWithContext(context, getLoadBalancerListenerPolicyOptions) + if err != nil { + log.Printf("[DEBUG] GetLoadBalancerListenerPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLoadBalancerListenerPolicyWithContext failed %s\n%s", err, response)) + } + d.SetId(*loadBalancerListenerPolicy.ID) + if err = d.Set("action", loadBalancerListenerPolicy.Action); err != nil { + return diag.FromErr(fmt.Errorf("Error setting action: %s", err)) + } + + if err = d.Set("created_at", loadBalancerListenerPolicy.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("href", loadBalancerListenerPolicy.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("name", loadBalancerListenerPolicy.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("priority", flex.IntValue(loadBalancerListenerPolicy.Priority)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting priority: %s", err)) + } + if err = d.Set("provisioning_status", loadBalancerListenerPolicy.ProvisioningStatus); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provisioning_status: %s", err)) + } + + if loadBalancerListenerPolicy.Rules != nil { + err = d.Set("rules", dataSourceLoadBalancerListenerPolicyFlattenRules(loadBalancerListenerPolicy.Rules)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting rules %s", err)) + } + } + + if loadBalancerListenerPolicy.Target != nil { + target := loadBalancerListenerPolicy.Target.(*vpcv1.LoadBalancerListenerPolicyTarget) + err = d.Set("target", dataSourceLoadBalancerListenerPolicyFlattenTarget(*target)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting target %s", err)) + } + } + + return nil +} + +func dataSourceLoadBalancerListenerPolicyFlattenRules(result []vpcv1.LoadBalancerListenerPolicyRuleReference) (rules []map[string]interface{}) { + for _, rulesItem := range result { + rules = append(rules, dataSourceLoadBalancerListenerPolicyRulesToMap(rulesItem)) + } + + return rules +} + +func dataSourceLoadBalancerListenerPolicyRulesToMap(rulesItem vpcv1.LoadBalancerListenerPolicyRuleReference) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + + if rulesItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyRulesDeletedToMap(*rulesItem.Deleted) + deletedList = append(deletedList, deletedMap) + rulesMap["deleted"] = deletedList + } + if rulesItem.Href != nil { + rulesMap["href"] = rulesItem.Href + } + if rulesItem.ID != nil { + rulesMap["id"] = rulesItem.ID + } + + return rulesMap +} + +func dataSourceLoadBalancerListenerPolicyRulesDeletedToMap(deletedItem vpcv1.LoadBalancerListenerPolicyRuleReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerPolicyFlattenTarget(result vpcv1.LoadBalancerListenerPolicyTarget) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerListenerPolicyTargetToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerListenerPolicyTargetToMap(targetItem vpcv1.LoadBalancerListenerPolicyTarget) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyTargetDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.HTTPStatusCode != nil { + targetMap["http_status_code"] = targetItem.HTTPStatusCode + } + if targetItem.URL != nil { + targetMap["url"] = targetItem.URL + } + if targetItem.Listener != nil { + listenerList := []map[string]interface{}{} + listenerMap := dataSourceLoadBalancerListenerPolicyTargetListenerToMap(*targetItem.Listener) + listenerList = append(listenerList, listenerMap) + targetMap["listener"] = listenerList + } + if targetItem.URI != nil { + targetMap["uri"] = targetItem.URI + } + + return targetMap +} + +func dataSourceLoadBalancerListenerPolicyTargetDeletedToMap(deletedItem vpcv1.LoadBalancerPoolReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerPolicyTargetListenerToMap(listenerItem vpcv1.LoadBalancerListenerReference) (listenerMap map[string]interface{}) { + listenerMap = map[string]interface{}{} + + if listenerItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerPolicyListenerDeletedToMap(*listenerItem.Deleted) + deletedList = append(deletedList, deletedMap) + listenerMap["deleted"] = deletedList + } + if listenerItem.Href != nil { + listenerMap["href"] = listenerItem.Href + } + if listenerItem.ID != nil { + listenerMap["id"] = listenerItem.ID + } + + return listenerMap +} + +func dataSourceLoadBalancerListenerPolicyListenerDeletedToMap(deletedItem vpcv1.LoadBalancerListenerReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule.go new file mode 100644 index 000000000..76be6381f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule.go @@ -0,0 +1,125 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListenerPolicyRule() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenerPolicyRuleRead, + + Schema: map[string]*schema.Schema{ + isLBListenerPolicyRuleLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + isLBListenerPolicyRuleListenerID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The listener identifier.", + }, + isLBListenerPolicyRulePolicyID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The policy identifier.", + }, + isLBListenerPolicyRuleid: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The rule identifier.", + }, + "condition": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The condition of the rule.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this rule was created.", + }, + "field": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's canonical URL.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this rule.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded.", + }, + }, + } +} + +func dataSourceIBMIsLbListenerPolicyRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getLoadBalancerListenerPolicyRuleOptions := &vpcv1.GetLoadBalancerListenerPolicyRuleOptions{} + + getLoadBalancerListenerPolicyRuleOptions.SetLoadBalancerID(d.Get(isLBListenerPolicyRuleLBID).(string)) + getLoadBalancerListenerPolicyRuleOptions.SetListenerID(d.Get(isLBListenerPolicyRuleListenerID).(string)) + getLoadBalancerListenerPolicyRuleOptions.SetPolicyID(d.Get(isLBListenerPolicyRulePolicyID).(string)) + getLoadBalancerListenerPolicyRuleOptions.SetID(d.Get(isLBListenerPolicyRuleid).(string)) + + loadBalancerListenerPolicyRule, response, err := vpcClient.GetLoadBalancerListenerPolicyRuleWithContext(context, getLoadBalancerListenerPolicyRuleOptions) + if err != nil { + log.Printf("[DEBUG] GetLoadBalancerListenerPolicyRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLoadBalancerListenerPolicyRuleWithContext failed %s\n%s", err, response)) + } + + d.SetId(*loadBalancerListenerPolicyRule.ID) + if err = d.Set("condition", loadBalancerListenerPolicyRule.Condition); err != nil { + return diag.FromErr(fmt.Errorf("Error setting condition: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(loadBalancerListenerPolicyRule.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("field", loadBalancerListenerPolicyRule.Field); err != nil { + return diag.FromErr(fmt.Errorf("Error setting field: %s", err)) + } + if err = d.Set("href", loadBalancerListenerPolicyRule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("provisioning_status", loadBalancerListenerPolicyRule.ProvisioningStatus); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provisioning_status: %s", err)) + } + if err = d.Set("type", loadBalancerListenerPolicyRule.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + if err = d.Set("value", loadBalancerListenerPolicyRule.Value); err != nil { + return diag.FromErr(fmt.Errorf("Error setting value: %s", err)) + } + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule_test.go new file mode 100644 index 000000000..1b3675eb4 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rule_test.go @@ -0,0 +1,63 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenerPolicyRuleDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblisuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblisuat-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblisuat%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyname := fmt.Sprintf("tflblisuat-listener-policy-%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyRuleField1 := fmt.Sprintf("tflblipolicy-rule-field-%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyRuleValue1 := fmt.Sprintf("tflblipolicy-rule-value-%d", acctest.RandIntRange(10, 100)) + + priority := "1" + protocol := "http" + port := "8080" + action := "forward" + condition := "equals" + typeh := "header" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenerPolicyRuleDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, typeh, lblistenerpolicyRuleField1, lblistenerpolicyRuleValue1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "rule"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "listener"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "condition"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "provisioning_status"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "type"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rule.is_lb_listener_policy_rule", "value"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenerPolicyRuleDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, types, field, value string) string { + return testAccCheckIBMISLBListenerPolicyRuleConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, types, field, value) + fmt.Sprintf(` + data "ibm_is_lb_listener_policy_rule" "is_lb_listener_policy_rule" { + lb = "${ibm_is_lb.testacc_LB.id}" + listener = "${ibm_is_lb_listener.testacc_lb_listener.listener_id}" + policy = "${ibm_is_lb_listener_policy.testacc_lb_listener_policy.policy_id}" + rule = "${ibm_is_lb_listener_policy_rule.testacc_lb_listener_policy_rule.rule}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules.go new file mode 100644 index 000000000..b4f6ecb00 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules.go @@ -0,0 +1,161 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListenerPolicyRules() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenerPolicyRulesRead, + + Schema: map[string]*schema.Schema{ + isLBListenerPolicyRuleLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + isLBListenerPolicyRuleListenerID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The listener identifier.", + }, + isLBListenerPolicyRulePolicyID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The policy identifier.", + }, + "rules": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of rules.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "condition": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The condition of the rule.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this rule was created.", + }, + "field": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The rule's unique identifier.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this rule.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set.", + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbListenerPolicyRulesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listLoadBalancerListenerPolicyRulesOptions := &vpcv1.ListLoadBalancerListenerPolicyRulesOptions{} + listLoadBalancerListenerPolicyRulesOptions.SetLoadBalancerID(d.Get(isLBListenerPolicyRuleLBID).(string)) + listLoadBalancerListenerPolicyRulesOptions.SetListenerID(d.Get(isLBListenerPolicyRuleListenerID).(string)) + listLoadBalancerListenerPolicyRulesOptions.SetPolicyID(d.Get(isLBListenerPolicyRulePolicyID).(string)) + + loadBalancerListenerPolicyRuleCollection, response, err := vpcClient.ListLoadBalancerListenerPolicyRulesWithContext(context, listLoadBalancerListenerPolicyRulesOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerListenerPolicyRulesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerListenerPolicyRulesWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIsLbListenerPolicyRulesID(d)) + + if loadBalancerListenerPolicyRuleCollection.Rules != nil { + err = d.Set("rules", dataSourceLoadBalancerListenerPolicyRuleCollectionFlattenRules(loadBalancerListenerPolicyRuleCollection.Rules)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting rules %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsLbListenerPolicyRulesID returns a reasonable ID for the list. +func dataSourceIBMIsLbListenerPolicyRulesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceLoadBalancerListenerPolicyRuleCollectionFlattenRules(result []vpcv1.LoadBalancerListenerPolicyRule) (rules []map[string]interface{}) { + for _, rulesItem := range result { + rules = append(rules, dataSourceLoadBalancerListenerPolicyRuleCollectionRulesToMap(rulesItem)) + } + + return rules +} + +func dataSourceLoadBalancerListenerPolicyRuleCollectionRulesToMap(rulesItem vpcv1.LoadBalancerListenerPolicyRule) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + if rulesItem.Condition != nil { + rulesMap["condition"] = rulesItem.Condition + } + if rulesItem.CreatedAt != nil { + rulesMap["created_at"] = rulesItem.CreatedAt.String() + } + if rulesItem.Field != nil { + rulesMap["field"] = rulesItem.Field + } + if rulesItem.Href != nil { + rulesMap["href"] = rulesItem.Href + } + if rulesItem.ID != nil { + rulesMap["id"] = rulesItem.ID + } + if rulesItem.ProvisioningStatus != nil { + rulesMap["provisioning_status"] = rulesItem.ProvisioningStatus + } + if rulesItem.Type != nil { + rulesMap["type"] = rulesItem.Type + } + if rulesItem.Value != nil { + rulesMap["value"] = rulesItem.Value + } + + return rulesMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules_test.go new file mode 100644 index 000000000..e9ba9bd52 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_rules_test.go @@ -0,0 +1,57 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenerPolicyRulesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblisuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblisuat-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblisuat%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyname := fmt.Sprintf("tflblisuat-listener-policy-%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyRuleField1 := fmt.Sprintf("tflblipolicy-rule-field-%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyRuleValue1 := fmt.Sprintf("tflblipolicy-rule-value-%d", acctest.RandIntRange(10, 100)) + + priority := "1" + protocol := "http" + port := "8080" + action := "forward" + condition := "equals" + typeh := "header" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenerPolicyRulesDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, typeh, lblistenerpolicyRuleField1, lblistenerpolicyRuleValue1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rules.is_lb_listener_policy_rules", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rules.is_lb_listener_policy_rules", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rules.is_lb_listener_policy_rules", "listener"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rules.is_lb_listener_policy_rules", "policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy_rules.is_lb_listener_policy_rules", "rules.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenerPolicyRulesDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, types, field, value string) string { + return testAccCheckIBMISLBListenerPolicyRuleConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, types, field, value) + fmt.Sprintf(` + data "ibm_is_lb_listener_policy_rules" "is_lb_listener_policy_rules" { + lb = "${ibm_is_lb.testacc_LB.id}" + listener = ibm_is_lb_listener.testacc_lb_listener.listener_id + policy = ibm_is_lb_listener_policy.testacc_lb_listener_policy.policy_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_test.go new file mode 100644 index 000000000..2f5a79f0f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_policy_test.go @@ -0,0 +1,58 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenerPolicyDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblisuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblisuat-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblisuatdata%d", acctest.RandIntRange(10, 100)) + lblistenerpolicyname1 := fmt.Sprintf("tflblisuat-listener-policy-%d", acctest.RandIntRange(10, 100)) + priority1 := "1" + protocol := "http" + port := "8080" + action := "forward" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenerPolicyDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "listener"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "policy_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "action"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "priority"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener_policy.is_lb_listener_policy", "provisioning_status"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenerPolicyDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol, lblistenerpolicyname, action, priority string) string { + return testAccCheckIBMISLBListenerPolicyConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority) + fmt.Sprintf(` + + data "ibm_is_lb_listener_policy" "is_lb_listener_policy" { + lb = "${ibm_is_lb.testacc_LB.id}" + listener = ibm_is_lb_listener.testacc_lb_listener.listener_id + policy_id = ibm_is_lb_listener_policy.testacc_lb_listener_policy.policy_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listener_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listener_test.go new file mode 100644 index 000000000..0bfa839d7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listener_test.go @@ -0,0 +1,54 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenerDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + protocol1 := "http" + port1 := "8080" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenerDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "listener_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "accept_proxy_protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "port"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "port_max"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "port_min"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listener.is_lb_listener", "provisioning_status"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenerDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return testAccCheckIBMISLBListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol) + fmt.Sprintf(` + + data "ibm_is_lb_listener" "is_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + listener_id = ibm_is_lb_listener.testacc_lb_listener.listener_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listeners.go b/ibm/service/vpc/data_source_ibm_is_lb_listeners.go new file mode 100644 index 000000000..fc47c762b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listeners.go @@ -0,0 +1,448 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBListeners() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbListenersRead, + + Schema: map[string]*schema.Schema{ + isLBListenerLBID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The load balancer identifier.", + }, + "listeners": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of listeners.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accept_proxy_protocol": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value.", + }, + "certificate_instance": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The certificate instance used for SSL termination. It is applicable only to `https`protocol.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance.", + }, + }, + }, + }, + "connection_limit": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The connection limit of the listener.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this listener was created.", + }, + "default_pool": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The default pool associated with the listener.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "https_redirect": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If specified, the target listener that requests are redirected to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The HTTP status code for this redirect.", + }, + "listener": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The redirect relative target URI.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer listener.", + }, + "policies": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The policies for this listener.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener policy's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy's unique identifier.", + }, + }, + }, + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + }, + "port_max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + }, + "port_min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The listener protocol. Load balancers in the `network` family support `tcp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this listener.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbListenersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listLoadBalancerListenersOptions := &vpcv1.ListLoadBalancerListenersOptions{} + + listLoadBalancerListenersOptions.SetLoadBalancerID(d.Get(isLBListenerLBID).(string)) + + loadBalancerListenerCollection, response, err := vpcClient.ListLoadBalancerListenersWithContext(context, listLoadBalancerListenersOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerListenersWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerListenersWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIsLbListenersID(d)) + + if loadBalancerListenerCollection.Listeners != nil { + err = d.Set("listeners", dataSourceLoadBalancerListenerCollectionFlattenListeners(loadBalancerListenerCollection.Listeners)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting listeners %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsLbListenersID returns a reasonable ID for the list. +func dataSourceIBMIsLbListenersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceLoadBalancerListenerCollectionFlattenListeners(result []vpcv1.LoadBalancerListener) (listeners []map[string]interface{}) { + for _, listenersItem := range result { + listeners = append(listeners, dataSourceLoadBalancerListenerCollectionListenersToMap(listenersItem)) + } + + return listeners +} + +func dataSourceLoadBalancerListenerCollectionListenersToMap(listenersItem vpcv1.LoadBalancerListener) (listenersMap map[string]interface{}) { + listenersMap = map[string]interface{}{} + + if listenersItem.AcceptProxyProtocol != nil { + listenersMap["accept_proxy_protocol"] = listenersItem.AcceptProxyProtocol + } + if listenersItem.CertificateInstance != nil { + certificateInstanceList := []map[string]interface{}{} + certificateInstanceMap := dataSourceLoadBalancerListenerCollectionListenersCertificateInstanceToMap(*listenersItem.CertificateInstance) + certificateInstanceList = append(certificateInstanceList, certificateInstanceMap) + listenersMap["certificate_instance"] = certificateInstanceList + } + if listenersItem.ConnectionLimit != nil { + listenersMap["connection_limit"] = listenersItem.ConnectionLimit + } + if listenersItem.CreatedAt != nil { + listenersMap["created_at"] = listenersItem.CreatedAt.String() + } + if listenersItem.DefaultPool != nil { + defaultPoolList := []map[string]interface{}{} + defaultPoolMap := dataSourceLoadBalancerListenerCollectionListenersDefaultPoolToMap(*listenersItem.DefaultPool) + defaultPoolList = append(defaultPoolList, defaultPoolMap) + listenersMap["default_pool"] = defaultPoolList + } + if listenersItem.Href != nil { + listenersMap["href"] = listenersItem.Href + } + if listenersItem.HTTPSRedirect != nil { + httpsRedirectList := []map[string]interface{}{} + httpsRedirectMap := dataSourceLoadBalancerListenerCollectionListenersHTTPSRedirectToMap(*listenersItem.HTTPSRedirect) + httpsRedirectList = append(httpsRedirectList, httpsRedirectMap) + listenersMap["https_redirect"] = httpsRedirectList + } + if listenersItem.ID != nil { + listenersMap["id"] = listenersItem.ID + } + if listenersItem.Policies != nil { + policiesList := []map[string]interface{}{} + for _, policiesItem := range listenersItem.Policies { + policiesList = append(policiesList, dataSourceLoadBalancerListenerCollectionListenersPoliciesToMap(policiesItem)) + } + listenersMap["policies"] = policiesList + } + if listenersItem.Port != nil { + listenersMap["port"] = listenersItem.Port + } + if listenersItem.PortMax != nil { + listenersMap["port_max"] = listenersItem.PortMax + } + if listenersItem.PortMin != nil { + listenersMap["port_min"] = listenersItem.PortMin + } + if listenersItem.Protocol != nil { + listenersMap["protocol"] = listenersItem.Protocol + } + if listenersItem.ProvisioningStatus != nil { + listenersMap["provisioning_status"] = listenersItem.ProvisioningStatus + } + + return listenersMap +} + +func dataSourceLoadBalancerListenerCollectionListenersCertificateInstanceToMap(certificateInstanceItem vpcv1.CertificateInstanceReference) (certificateInstanceMap map[string]interface{}) { + certificateInstanceMap = map[string]interface{}{} + + if certificateInstanceItem.CRN != nil { + certificateInstanceMap["crn"] = certificateInstanceItem.CRN + } + + return certificateInstanceMap +} + +func dataSourceLoadBalancerListenerCollectionListenersDefaultPoolToMap(defaultPoolItem vpcv1.LoadBalancerPoolReference) (defaultPoolMap map[string]interface{}) { + defaultPoolMap = map[string]interface{}{} + + if defaultPoolItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerCollectionDefaultPoolDeletedToMap(*defaultPoolItem.Deleted) + deletedList = append(deletedList, deletedMap) + defaultPoolMap["deleted"] = deletedList + } + if defaultPoolItem.Href != nil { + defaultPoolMap["href"] = defaultPoolItem.Href + } + if defaultPoolItem.ID != nil { + defaultPoolMap["id"] = defaultPoolItem.ID + } + if defaultPoolItem.Name != nil { + defaultPoolMap["name"] = defaultPoolItem.Name + } + + return defaultPoolMap +} + +func dataSourceLoadBalancerListenerCollectionDefaultPoolDeletedToMap(deletedItem vpcv1.LoadBalancerPoolReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerCollectionListenersHTTPSRedirectToMap(httpsRedirectItem vpcv1.LoadBalancerListenerHTTPSRedirect) (httpsRedirectMap map[string]interface{}) { + httpsRedirectMap = map[string]interface{}{} + + if httpsRedirectItem.HTTPStatusCode != nil { + httpsRedirectMap["http_status_code"] = httpsRedirectItem.HTTPStatusCode + } + if httpsRedirectItem.Listener != nil { + listenerList := []map[string]interface{}{} + listenerMap := dataSourceLoadBalancerListenerCollectionHTTPSRedirectListenerToMap(*httpsRedirectItem.Listener) + listenerList = append(listenerList, listenerMap) + httpsRedirectMap["listener"] = listenerList + } + if httpsRedirectItem.URI != nil { + httpsRedirectMap["uri"] = httpsRedirectItem.URI + } + + return httpsRedirectMap +} + +func dataSourceLoadBalancerListenerCollectionHTTPSRedirectListenerToMap(listenerItem vpcv1.LoadBalancerListenerReference) (listenerMap map[string]interface{}) { + listenerMap = map[string]interface{}{} + + if listenerItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerCollectionListenerDeletedToMap(*listenerItem.Deleted) + deletedList = append(deletedList, deletedMap) + listenerMap["deleted"] = deletedList + } + if listenerItem.Href != nil { + listenerMap["href"] = listenerItem.Href + } + if listenerItem.ID != nil { + listenerMap["id"] = listenerItem.ID + } + + return listenerMap +} + +func dataSourceLoadBalancerListenerCollectionListenerDeletedToMap(deletedItem vpcv1.LoadBalancerListenerReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerListenerCollectionListenersPoliciesToMap(policiesItem vpcv1.LoadBalancerListenerPolicyReference) (policiesMap map[string]interface{}) { + policiesMap = map[string]interface{}{} + + if policiesItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerListenerCollectionPoliciesDeletedToMap(*policiesItem.Deleted) + deletedList = append(deletedList, deletedMap) + policiesMap["deleted"] = deletedList + } + if policiesItem.Href != nil { + policiesMap["href"] = policiesItem.Href + } + if policiesItem.ID != nil { + policiesMap["id"] = policiesItem.ID + } + + return policiesMap +} + +func dataSourceLoadBalancerListenerCollectionPoliciesDeletedToMap(deletedItem vpcv1.LoadBalancerListenerPolicyReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_listeners_test.go b/ibm/service/vpc/data_source_ibm_is_lb_listeners_test.go new file mode 100644 index 000000000..4c4f87689 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_listeners_test.go @@ -0,0 +1,45 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbListenersDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + protocol1 := "http" + port1 := "8080" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbListenersDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listeners.is_lb_listeners", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listeners.is_lb_listeners", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_listeners.is_lb_listeners", "listeners.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbListenersDataSourceConfigBasic(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return testAccCheckIBMISLBListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol) + fmt.Sprintf(` + + data "ibm_is_lb_listeners" "is_lb_listeners" { + lb = "${ibm_is_lb.testacc_LB.id}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool.go b/ibm/service/vpc/data_source_ibm_is_lb_pool.go new file mode 100644 index 000000000..9e1c8870d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool.go @@ -0,0 +1,446 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBPool() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbPoolRead, + + Schema: map[string]*schema.Schema{ + "lb": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The pool identifier.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The user-defined name for this load balancer pool.", + }, + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The load balancing algorithm.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this pool was created.", + }, + "health_monitor": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The health monitor of this pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delay": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check interval in seconds. Interval must be greater than timeout value.", + }, + "max_retries": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check max retries.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check port number. If specified, this overrides the ports specified in the server member resources.", + }, + "timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check timeout in seconds.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered.", + }, + "url_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1).", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "instance_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance group that is managing this pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this instance group.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this instance group.", + }, + }, + }, + }, + "members": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The backend server members of the pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The member's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool member.", + }, + }, + }, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this pool.", + }, + "proxy_protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`).", + }, + "session_persistence": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookie_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbPoolRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + var loadBalancerPool *vpcv1.LoadBalancerPool + + if v, ok := d.GetOk("identifier"); ok { + getLoadBalancerPoolOptions := &vpcv1.GetLoadBalancerPoolOptions{} + + getLoadBalancerPoolOptions.SetLoadBalancerID(d.Get("lb").(string)) + getLoadBalancerPoolOptions.SetID(v.(string)) + + loadBalancerPoolInfo, response, err := sess.GetLoadBalancerPoolWithContext(context, getLoadBalancerPoolOptions) + if err != nil { + log.Printf("[DEBUG] GetLoadBalancerPoolWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLoadBalancerPoolWithContext failed %s\n%s", err, response)) + } + loadBalancerPool = loadBalancerPoolInfo + + } else if v, ok := d.GetOk("name"); ok { + listLoadBalancerPoolsOptions := &vpcv1.ListLoadBalancerPoolsOptions{} + + listLoadBalancerPoolsOptions.SetLoadBalancerID(d.Get("lb").(string)) + + loadBalancerPoolCollection, response, err := sess.ListLoadBalancerPoolsWithContext(context, listLoadBalancerPoolsOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerPoolsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerPoolsWithContext failed %s\n%s", err, response)) + } + + name := v.(string) + for _, data := range loadBalancerPoolCollection.Pools { + if *data.Name == name { + loadBalancerPool = &data + break + } + } + if loadBalancerPool == nil { + log.Printf("[DEBUG] No LoadBalancerPool found with name (%s)", name) + return diag.FromErr(fmt.Errorf("No LoadBalancerPool found with name (%s)", name)) + } + + } + + d.SetId(*loadBalancerPool.ID) + if err = d.Set("algorithm", loadBalancerPool.Algorithm); err != nil { + return diag.FromErr(fmt.Errorf("Error setting algorithm: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(loadBalancerPool.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if loadBalancerPool.HealthMonitor != nil { + err = d.Set("health_monitor", dataSourceLoadBalancerPoolFlattenHealthMonitor(*loadBalancerPool.HealthMonitor)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting health_monitor %s", err)) + } + } + if err = d.Set("href", loadBalancerPool.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if loadBalancerPool.InstanceGroup != nil { + err = d.Set("instance_group", dataSourceLoadBalancerPoolFlattenInstanceGroup(*loadBalancerPool.InstanceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting instance_group %s", err)) + } + } + + if loadBalancerPool.Members != nil { + err = d.Set("members", dataSourceLoadBalancerPoolFlattenMembers(loadBalancerPool.Members)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting members %s", err)) + } + } + + if err = d.Set("identifier", loadBalancerPool.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting identifier: %s", err)) + } + + if err = d.Set("name", loadBalancerPool.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("protocol", loadBalancerPool.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting protocol: %s", err)) + } + if err = d.Set("provisioning_status", loadBalancerPool.ProvisioningStatus); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provisioning_status: %s", err)) + } + if err = d.Set("proxy_protocol", loadBalancerPool.ProxyProtocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting proxy_protocol: %s", err)) + } + + if loadBalancerPool.SessionPersistence != nil { + err = d.Set("session_persistence", dataSourceLoadBalancerPoolFlattenSessionPersistence(*loadBalancerPool.SessionPersistence)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting session_persistence %s", err)) + } + } + + return nil +} + +func dataSourceLoadBalancerPoolFlattenHealthMonitor(result vpcv1.LoadBalancerPoolHealthMonitor) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerPoolHealthMonitorToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerPoolHealthMonitorToMap(healthMonitorItem vpcv1.LoadBalancerPoolHealthMonitor) (healthMonitorMap map[string]interface{}) { + healthMonitorMap = map[string]interface{}{} + + if healthMonitorItem.Delay != nil { + healthMonitorMap["delay"] = healthMonitorItem.Delay + } + if healthMonitorItem.MaxRetries != nil { + healthMonitorMap["max_retries"] = healthMonitorItem.MaxRetries + } + if healthMonitorItem.Port != nil { + healthMonitorMap["port"] = healthMonitorItem.Port + } + if healthMonitorItem.Timeout != nil { + healthMonitorMap["timeout"] = healthMonitorItem.Timeout + } + if healthMonitorItem.Type != nil { + healthMonitorMap["type"] = healthMonitorItem.Type + } + if healthMonitorItem.URLPath != nil { + healthMonitorMap["url_path"] = healthMonitorItem.URLPath + } + + return healthMonitorMap +} + +func dataSourceLoadBalancerPoolFlattenInstanceGroup(result vpcv1.InstanceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerPoolInstanceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerPoolInstanceGroupToMap(instanceGroupItem vpcv1.InstanceGroupReference) (instanceGroupMap map[string]interface{}) { + instanceGroupMap = map[string]interface{}{} + + if instanceGroupItem.CRN != nil { + instanceGroupMap["crn"] = instanceGroupItem.CRN + } + if instanceGroupItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolInstanceGroupDeletedToMap(*instanceGroupItem.Deleted) + deletedList = append(deletedList, deletedMap) + instanceGroupMap["deleted"] = deletedList + } + if instanceGroupItem.Href != nil { + instanceGroupMap["href"] = instanceGroupItem.Href + } + if instanceGroupItem.ID != nil { + instanceGroupMap["id"] = instanceGroupItem.ID + } + if instanceGroupItem.Name != nil { + instanceGroupMap["name"] = instanceGroupItem.Name + } + + return instanceGroupMap +} + +func dataSourceLoadBalancerPoolInstanceGroupDeletedToMap(deletedItem vpcv1.InstanceGroupReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerPoolFlattenMembers(result []vpcv1.LoadBalancerPoolMemberReference) (members []map[string]interface{}) { + for _, membersItem := range result { + members = append(members, dataSourceLoadBalancerPoolMembersToMap(membersItem)) + } + + return members +} + +func dataSourceLoadBalancerPoolMembersToMap(membersItem vpcv1.LoadBalancerPoolMemberReference) (membersMap map[string]interface{}) { + membersMap = map[string]interface{}{} + + if membersItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolMembersDeletedToMap(*membersItem.Deleted) + deletedList = append(deletedList, deletedMap) + membersMap["deleted"] = deletedList + } + if membersItem.Href != nil { + membersMap["href"] = membersItem.Href + } + if membersItem.ID != nil { + membersMap["id"] = membersItem.ID + } + + return membersMap +} + +func dataSourceLoadBalancerPoolMembersDeletedToMap(deletedItem vpcv1.LoadBalancerPoolMemberReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerPoolFlattenSessionPersistence(result vpcv1.LoadBalancerPoolSessionPersistence) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerPoolSessionPersistenceToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerPoolSessionPersistenceToMap(sessionPersistenceItem vpcv1.LoadBalancerPoolSessionPersistence) (sessionPersistenceMap map[string]interface{}) { + sessionPersistenceMap = map[string]interface{}{} + + if sessionPersistenceItem.CookieName != nil { + sessionPersistenceMap["cookie_name"] = sessionPersistenceItem.CookieName + } + if sessionPersistenceItem.Type != nil { + sessionPersistenceMap["type"] = sessionPersistenceItem.Type + } + + return sessionPersistenceMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool_member.go b/ibm/service/vpc/data_source_ibm_is_lb_pool_member.go new file mode 100644 index 000000000..8ccd2550f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool_member.go @@ -0,0 +1,213 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIBLBPoolMember() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbPoolMemberRead, + + Schema: map[string]*schema.Schema{ + "lb": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + "pool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The pool identifier.", + }, + "member": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The member identifier.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this member was created.", + }, + "health": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Health of the server member in the pool.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The member's canonical URL.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port number of the application running in the server member.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this member.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual server instance.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual server instance.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this virtual server instance (and default system hostname).", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "weight": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`.", + }, + }, + } +} + +func dataSourceIBMIsLbPoolMemberRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getLoadBalancerPoolMemberOptions := &vpcv1.GetLoadBalancerPoolMemberOptions{} + + getLoadBalancerPoolMemberOptions.SetLoadBalancerID(d.Get("lb").(string)) + getLoadBalancerPoolMemberOptions.SetPoolID(d.Get("pool").(string)) + getLoadBalancerPoolMemberOptions.SetID(d.Get("member").(string)) + + loadBalancerPoolMember, response, err := sess.GetLoadBalancerPoolMemberWithContext(context, getLoadBalancerPoolMemberOptions) + if err != nil { + log.Printf("[DEBUG] GetLoadBalancerPoolMemberWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetLoadBalancerPoolMemberWithContext failed %s\n%s", err, response)) + } + + d.SetId(*loadBalancerPoolMember.ID) + if err = d.Set("created_at", flex.DateTimeToString(loadBalancerPoolMember.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("health", loadBalancerPoolMember.Health); err != nil { + return diag.FromErr(fmt.Errorf("Error setting health: %s", err)) + } + if err = d.Set("href", loadBalancerPoolMember.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("port", flex.IntValue(loadBalancerPoolMember.Port)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port: %s", err)) + } + if err = d.Set("provisioning_status", loadBalancerPoolMember.ProvisioningStatus); err != nil { + return diag.FromErr(fmt.Errorf("Error setting provisioning_status: %s", err)) + } + + if loadBalancerPoolMember.Target != nil { + target := loadBalancerPoolMember.Target.(*vpcv1.LoadBalancerPoolMemberTarget) + err = d.Set("target", dataSourceLoadBalancerPoolMemberFlattenTarget(*target)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting target %s", err)) + } + } + if err = d.Set("weight", flex.IntValue(loadBalancerPoolMember.Weight)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting weight: %s", err)) + } + + return nil +} + +func dataSourceLoadBalancerPoolMemberFlattenTarget(result vpcv1.LoadBalancerPoolMemberTarget) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceLoadBalancerPoolMemberTargetToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceLoadBalancerPoolMemberTargetToMap(targetItem vpcv1.LoadBalancerPoolMemberTarget) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + if targetItem.CRN != nil { + targetMap["crn"] = targetItem.CRN + } + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolMemberTargetDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.Address != nil { + targetMap["address"] = targetItem.Address + } + + return targetMap +} + +func dataSourceLoadBalancerPoolMemberTargetDeletedToMap(deletedItem vpcv1.InstanceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool_member_test.go b/ibm/service/vpc/data_source_ibm_is_lb_pool_member_test.go new file mode 100644 index 000000000..4a8ba31aa --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool_member_test.go @@ -0,0 +1,53 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbPoolMemberDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + port := "8080" + address := "127.0.0.1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbPoolMemberDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, port, address), + Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "pool"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "member"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "health"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "port"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "provisioning_status"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_member.is_lb_pool_member", "target.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbPoolMemberDataSourceConfigBasic(vpcname, subnetname, zone, cidr, name, poolName, port, address string) string { + return testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, zone, cidr, name, poolName, port, address) + fmt.Sprintf(` + data "ibm_is_lb_pool_member" "is_lb_pool_member" { + lb = "${ibm_is_lb.testacc_LB.id}" + pool = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" + member = "${element(split("/",ibm_is_lb_pool_member.testacc_lb_mem.id),2)}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool_members.go b/ibm/service/vpc/data_source_ibm_is_lb_pool_members.go new file mode 100644 index 000000000..8d07993be --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool_members.go @@ -0,0 +1,242 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBPoolMembers() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbPoolMembersRead, + + Schema: map[string]*schema.Schema{ + "lb": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + "pool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The pool identifier.", + }, + "members": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of members.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this member was created.", + }, + "health": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Health of the server member in the pool.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The member's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool member.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port number of the application running in the server member.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this member.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual server instance.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual server instance.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this virtual server instance (and default system hostname).", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "weight": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbPoolMembersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listLoadBalancerPoolMembersOptions := &vpcv1.ListLoadBalancerPoolMembersOptions{} + + listLoadBalancerPoolMembersOptions.SetLoadBalancerID(d.Get("lb").(string)) + listLoadBalancerPoolMembersOptions.SetPoolID(d.Get("pool").(string)) + + loadBalancerPoolMemberCollection, response, err := sess.ListLoadBalancerPoolMembersWithContext(context, listLoadBalancerPoolMembersOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerPoolMembersWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerPoolMembersWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIsLbPoolMembersID(d)) + + if loadBalancerPoolMemberCollection.Members != nil { + err = d.Set("members", dataSourceLoadBalancerPoolMemberCollectionFlattenMembers(loadBalancerPoolMemberCollection.Members)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting members %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsLbPoolMembersID returns a reasonable ID for the list. +func dataSourceIBMIsLbPoolMembersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceLoadBalancerPoolMemberCollectionFlattenMembers(result []vpcv1.LoadBalancerPoolMember) (members []map[string]interface{}) { + for _, membersItem := range result { + members = append(members, dataSourceLoadBalancerPoolMemberCollectionMembersToMap(membersItem)) + } + + return members +} + +func dataSourceLoadBalancerPoolMemberCollectionMembersToMap(membersItem vpcv1.LoadBalancerPoolMember) (membersMap map[string]interface{}) { + membersMap = map[string]interface{}{} + + if membersItem.CreatedAt != nil { + membersMap["created_at"] = membersItem.CreatedAt.String() + } + if membersItem.Health != nil { + membersMap["health"] = membersItem.Health + } + if membersItem.Href != nil { + membersMap["href"] = membersItem.Href + } + if membersItem.ID != nil { + membersMap["id"] = membersItem.ID + } + if membersItem.Port != nil { + membersMap["port"] = membersItem.Port + } + if membersItem.ProvisioningStatus != nil { + membersMap["provisioning_status"] = membersItem.ProvisioningStatus + } + if membersItem.Target != nil { + targetList := []map[string]interface{}{} + target := membersItem.Target.(*vpcv1.LoadBalancerPoolMemberTarget) + targetMap := dataSourceLoadBalancerPoolMemberCollectionMembersTargetToMap(*target) + targetList = append(targetList, targetMap) + membersMap["target"] = targetList + } + if membersItem.Weight != nil { + membersMap["weight"] = membersItem.Weight + } + + return membersMap +} + +func dataSourceLoadBalancerPoolMemberCollectionMembersTargetToMap(targetItem vpcv1.LoadBalancerPoolMemberTarget) (targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + + if targetItem.CRN != nil { + targetMap["crn"] = targetItem.CRN + } + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolMemberCollectionTargetDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap["deleted"] = deletedList + } + if targetItem.Href != nil { + targetMap["href"] = targetItem.Href + } + if targetItem.ID != nil { + targetMap["id"] = targetItem.ID + } + if targetItem.Name != nil { + targetMap["name"] = targetItem.Name + } + if targetItem.Address != nil { + targetMap["address"] = targetItem.Address + } + + return targetMap +} + +func dataSourceLoadBalancerPoolMemberCollectionTargetDeletedToMap(deletedItem vpcv1.InstanceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool_members_test.go b/ibm/service/vpc/data_source_ibm_is_lb_pool_members_test.go new file mode 100644 index 000000000..1de16b32c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool_members_test.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbPoolMembersDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + port := "8080" + address := "127.0.0.1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbPoolMembersDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, port, address), + Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_members.is_lb_pool_members", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_members.is_lb_pool_members", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_members.is_lb_pool_members", "pool"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool_members.is_lb_pool_members", "members.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbPoolMembersDataSourceConfigBasic(vpcname, subnetname, zone, cidr, name, poolName, port, address string) string { + return testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, zone, cidr, name, poolName, port, address) + fmt.Sprintf(` + data "ibm_is_lb_pool_members" "is_lb_pool_members" { + lb = "${ibm_is_lb.testacc_LB.id}" + pool = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pool_test.go b/ibm/service/vpc/data_source_ibm_is_lb_pool_test.go new file mode 100644 index 000000000..087ee21cf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pool_test.go @@ -0,0 +1,58 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbPoolDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflbp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + alg1 := "round_robin" + protocol1 := "http" + delay1 := "45" + retries1 := "5" + timeout1 := "15" + healthType1 := "http" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbPoolDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), + Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "identifier"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "algorithm"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "health_monitor.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "provisioning_status"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pool.is_lb_pool", "proxy_protocol"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbPoolDataSourceConfigBasic(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType string) string { + return testAccCheckIBMISLBPoolConfig(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType) + fmt.Sprintf(` + data "ibm_is_lb_pool" "is_lb_pool" { + lb = "${ibm_is_lb.testacc_LB.id}" + identifier = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pools.go b/ibm/service/vpc/data_source_ibm_is_lb_pools.go new file mode 100644 index 000000000..772624656 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pools.go @@ -0,0 +1,415 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISLBPools() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsLbPoolsRead, + + Schema: map[string]*schema.Schema{ + "lb": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The load balancer identifier.", + }, + "pools": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of pools.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "algorithm": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The load balancing algorithm.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this pool was created.", + }, + "health_monitor": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The health monitor of this pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delay": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check interval in seconds. Interval must be greater than timeout value.", + }, + "max_retries": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check max retries.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check port number. If specified, this overrides the ports specified in the server member resources.", + }, + "timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The health check timeout in seconds.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered.", + }, + "url_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1).", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool.", + }, + "instance_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance group that is managing this pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this instance group.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this instance group.", + }, + }, + }, + }, + "members": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The backend server members of the pool.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The member's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this load balancer pool member.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this load balancer pool.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered.", + }, + "provisioning_status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The provisioning status of this pool.", + }, + "proxy_protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`).", + }, + "session_persistence": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookie_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsLbPoolsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listLoadBalancerPoolsOptions := &vpcv1.ListLoadBalancerPoolsOptions{} + + listLoadBalancerPoolsOptions.SetLoadBalancerID(d.Get("lb").(string)) + + loadBalancerPoolCollection, response, err := sess.ListLoadBalancerPoolsWithContext(context, listLoadBalancerPoolsOptions) + if err != nil { + log.Printf("[DEBUG] ListLoadBalancerPoolsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListLoadBalancerPoolsWithContext failed %s\n%s", err, response)) + } + if err = d.Set("lb", d.Get("lb").(string)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting lb: %s", err)) + } + + d.SetId(dataSourceIBMIsLbPoolsID(d)) + + if loadBalancerPoolCollection.Pools != nil { + err = d.Set("pools", dataSourceLoadBalancerPoolCollectionFlattenPools(loadBalancerPoolCollection.Pools)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting pools %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsLbPoolsID returns a reasonable ID for the list. +func dataSourceIBMIsLbPoolsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceLoadBalancerPoolCollectionFlattenPools(result []vpcv1.LoadBalancerPool) (pools []map[string]interface{}) { + for _, poolsItem := range result { + pools = append(pools, dataSourceLoadBalancerPoolCollectionPoolsToMap(poolsItem)) + } + + return pools +} + +func dataSourceLoadBalancerPoolCollectionPoolsToMap(poolsItem vpcv1.LoadBalancerPool) (poolsMap map[string]interface{}) { + poolsMap = map[string]interface{}{} + + if poolsItem.Algorithm != nil { + poolsMap["algorithm"] = poolsItem.Algorithm + } + if poolsItem.CreatedAt != nil { + poolsMap["created_at"] = poolsItem.CreatedAt.String() + } + if poolsItem.HealthMonitor != nil { + healthMonitorList := []map[string]interface{}{} + healthMonitorMap := dataSourceLoadBalancerPoolCollectionPoolsHealthMonitorToMap(*poolsItem.HealthMonitor) + healthMonitorList = append(healthMonitorList, healthMonitorMap) + poolsMap["health_monitor"] = healthMonitorList + } + if poolsItem.Href != nil { + poolsMap["href"] = poolsItem.Href + } + if poolsItem.ID != nil { + poolsMap["id"] = poolsItem.ID + } + if poolsItem.InstanceGroup != nil { + instanceGroupList := []map[string]interface{}{} + instanceGroupMap := dataSourceLoadBalancerPoolCollectionPoolsInstanceGroupToMap(*poolsItem.InstanceGroup) + instanceGroupList = append(instanceGroupList, instanceGroupMap) + poolsMap["instance_group"] = instanceGroupList + } + if poolsItem.Members != nil { + membersList := []map[string]interface{}{} + for _, membersItem := range poolsItem.Members { + membersList = append(membersList, dataSourceLoadBalancerPoolCollectionPoolsMembersToMap(membersItem)) + } + poolsMap["members"] = membersList + } + if poolsItem.Name != nil { + poolsMap["name"] = poolsItem.Name + } + if poolsItem.Protocol != nil { + poolsMap["protocol"] = poolsItem.Protocol + } + if poolsItem.ProvisioningStatus != nil { + poolsMap["provisioning_status"] = poolsItem.ProvisioningStatus + } + if poolsItem.ProxyProtocol != nil { + poolsMap["proxy_protocol"] = poolsItem.ProxyProtocol + } + if poolsItem.SessionPersistence != nil { + sessionPersistenceList := []map[string]interface{}{} + sessionPersistenceMap := dataSourceLoadBalancerPoolCollectionPoolsSessionPersistenceToMap(*poolsItem.SessionPersistence) + sessionPersistenceList = append(sessionPersistenceList, sessionPersistenceMap) + poolsMap["session_persistence"] = sessionPersistenceList + } + + return poolsMap +} + +func dataSourceLoadBalancerPoolCollectionPoolsHealthMonitorToMap(healthMonitorItem vpcv1.LoadBalancerPoolHealthMonitor) (healthMonitorMap map[string]interface{}) { + healthMonitorMap = map[string]interface{}{} + + if healthMonitorItem.Delay != nil { + healthMonitorMap["delay"] = healthMonitorItem.Delay + } + if healthMonitorItem.MaxRetries != nil { + healthMonitorMap["max_retries"] = healthMonitorItem.MaxRetries + } + if healthMonitorItem.Port != nil { + healthMonitorMap["port"] = healthMonitorItem.Port + } + if healthMonitorItem.Timeout != nil { + healthMonitorMap["timeout"] = healthMonitorItem.Timeout + } + if healthMonitorItem.Type != nil { + healthMonitorMap["type"] = healthMonitorItem.Type + } + if healthMonitorItem.URLPath != nil { + healthMonitorMap["url_path"] = healthMonitorItem.URLPath + } + + return healthMonitorMap +} + +func dataSourceLoadBalancerPoolCollectionPoolsInstanceGroupToMap(instanceGroupItem vpcv1.InstanceGroupReference) (instanceGroupMap map[string]interface{}) { + instanceGroupMap = map[string]interface{}{} + + if instanceGroupItem.CRN != nil { + instanceGroupMap["crn"] = instanceGroupItem.CRN + } + if instanceGroupItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolCollectionInstanceGroupDeletedToMap(*instanceGroupItem.Deleted) + deletedList = append(deletedList, deletedMap) + instanceGroupMap["deleted"] = deletedList + } + if instanceGroupItem.Href != nil { + instanceGroupMap["href"] = instanceGroupItem.Href + } + if instanceGroupItem.ID != nil { + instanceGroupMap["id"] = instanceGroupItem.ID + } + if instanceGroupItem.Name != nil { + instanceGroupMap["name"] = instanceGroupItem.Name + } + + return instanceGroupMap +} + +func dataSourceLoadBalancerPoolCollectionInstanceGroupDeletedToMap(deletedItem vpcv1.InstanceGroupReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerPoolCollectionPoolsMembersToMap(membersItem vpcv1.LoadBalancerPoolMemberReference) (membersMap map[string]interface{}) { + membersMap = map[string]interface{}{} + + if membersItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceLoadBalancerPoolCollectionMembersDeletedToMap(*membersItem.Deleted) + deletedList = append(deletedList, deletedMap) + membersMap["deleted"] = deletedList + } + if membersItem.Href != nil { + membersMap["href"] = membersItem.Href + } + if membersItem.ID != nil { + membersMap["id"] = membersItem.ID + } + + return membersMap +} + +func dataSourceLoadBalancerPoolCollectionMembersDeletedToMap(deletedItem vpcv1.LoadBalancerPoolMemberReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceLoadBalancerPoolCollectionPoolsSessionPersistenceToMap(sessionPersistenceItem vpcv1.LoadBalancerPoolSessionPersistence) (sessionPersistenceMap map[string]interface{}) { + sessionPersistenceMap = map[string]interface{}{} + + if sessionPersistenceItem.CookieName != nil { + sessionPersistenceMap["cookie_name"] = sessionPersistenceItem.CookieName + } + if sessionPersistenceItem.Type != nil { + sessionPersistenceMap["type"] = sessionPersistenceItem.Type + } + + return sessionPersistenceMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_pools_test.go b/ibm/service/vpc/data_source_ibm_is_lb_pools_test.go new file mode 100644 index 000000000..f306e5a8a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_pools_test.go @@ -0,0 +1,48 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsLbPoolsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tflbp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + alg1 := "round_robin" + protocol1 := "http" + delay1 := "45" + retries1 := "5" + timeout1 := "15" + healthType1 := "http" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsLbPoolsDataSourceConfigBasic(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pools.is_lb_pools", "lb"), + resource.TestCheckResourceAttrSet("data.ibm_is_lb_pools.is_lb_pools", "pools.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsLbPoolsDataSourceConfigBasic(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType string) string { + return testAccCheckIBMISLBPoolConfig(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType) + fmt.Sprintf(` + data "ibm_is_lb_pools" "is_lb_pools" { + lb = "${ibm_is_lb.testacc_LB.id}" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_lb_profiles.go b/ibm/service/vpc/data_source_ibm_is_lb_profiles.go new file mode 100644 index 000000000..9b543deac --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_profiles.go @@ -0,0 +1,171 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isLbsProfiles = "lb_profiles" +) + +func DataSourceIBMISLbProfiles() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISLbProfilesRead, + + Schema: map[string]*schema.Schema{ + + isLbsProfiles: { + Type: schema.TypeList, + Description: "Collection of load balancer profile collectors", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name for this load balancer profile", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this load balancer profile", + }, + "family": { + Type: schema.TypeString, + Computed: true, + Description: "The product family this load balancer profile belongs to", + }, + "route_mode_supported": { + Type: schema.TypeBool, + Computed: true, + Description: "The route mode support for a load balancer with this profile depends on its configuration", + }, + "route_mode_type": { + Type: schema.TypeString, + Computed: true, + Description: "The route mode type for this load balancer profile, one of [fixed, dependent]", + }, + "udp_supported": { + Type: schema.TypeBool, + Computed: true, + Description: "The UDP support for a load balancer with this profile", + }, + "udp_supported_type": { + Type: schema.TypeString, + Computed: true, + Description: "The UDP support type for a load balancer with this profile", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISLbProfilesRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + start := "" + allrecs := []vpcv1.LoadBalancerProfile{} + for { + listOptions := &vpcv1.ListLoadBalancerProfilesOptions{} + if start != "" { + listOptions.Start = &start + } + profileCollectors, response, err := sess.ListLoadBalancerProfiles(listOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching Load Balancer Profiles for VPC %s\n%s", err, response) + } + start = flex.GetNext(profileCollectors.Next) + allrecs = append(allrecs, profileCollectors.Profiles...) + if start == "" { + break + } + } + lbprofilesInfo := make([]map[string]interface{}, 0) + for _, profileCollector := range allrecs { + + l := map[string]interface{}{ + "name": *profileCollector.Name, + "href": *profileCollector.Href, + "family": *profileCollector.Family, + } + if profileCollector.UDPSupported != nil { + udpSupport := profileCollector.UDPSupported + switch reflect.TypeOf(udpSupport).String() { + case "*vpcv1.LoadBalancerProfileUDPSupportedFixed": + { + udp := udpSupport.(*vpcv1.LoadBalancerProfileUDPSupportedFixed) + l["udp_supported"] = udp.Value + l["udp_supported_type"] = udp.Type + } + case "*vpcv1.LoadBalancerProfileUDPSupportedDependent": + { + udp := udpSupport.(*vpcv1.LoadBalancerProfileUDPSupportedDependent) + if udp.Type != nil { + l["udp_supported_type"] = *udp.Type + } + } + case "*vpcv1.LoadBalancerProfileUDPSupported": + { + udp := udpSupport.(*vpcv1.LoadBalancerProfileUDPSupported) + if udp.Type != nil { + l["udp_supported_type"] = *udp.Type + } + if udp.Value != nil { + l["udp_supported"] = *udp.Value + } + } + } + } + if profileCollector.RouteModeSupported != nil { + routeMode := profileCollector.RouteModeSupported + switch reflect.TypeOf(routeMode).String() { + case "*vpcv1.LoadBalancerProfileRouteModeSupportedFixed": + { + rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupportedFixed) + l["route_mode_supported"] = rms.Value + l["route_mode_type"] = rms.Type + } + case "*vpcv1.LoadBalancerProfileRouteModeSupportedDependent": + { + rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupportedDependent) + if rms.Type != nil { + l["route_mode_type"] = *rms.Type + } + } + case "*vpcv1.LoadBalancerProfileRouteModeSupported": + { + rms := routeMode.(*vpcv1.LoadBalancerProfileRouteModeSupported) + if rms.Type != nil { + l["route_mode_type"] = *rms.Type + } + if rms.Value != nil { + l["route_mode_supported"] = *rms.Value + } + } + } + } + lbprofilesInfo = append(lbprofilesInfo, l) + } + d.SetId(dataSourceIBMISLbProfilesID(d)) + d.Set(isLbsProfiles, lbprofilesInfo) + return nil +} + +// dataSourceIBMISLbProfilesID returns a reasonable ID for a profileCollector list. +func dataSourceIBMISLbProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_is_lb_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_lb_profiles_test.go similarity index 87% rename from ibm/data_source_ibm_is_lb_profiles_test.go rename to ibm/service/vpc/data_source_ibm_is_lb_profiles_test.go index 3937a4ecb..458ef0ea2 100644 --- a/ibm/data_source_ibm_is_lb_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_lb_profiles_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,12 +19,12 @@ func TestAccIBMISLBProfilesDatasource_basic(t *testing.T) { subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) var lb string resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testDSCheckIBMISLBProfilesConfig(vpcname, subnetname, ISZoneName, ISCIDR, name), + Config: testDSCheckIBMISLBProfilesConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBExists("ibm_is_lb.testacc_lb", lb), resource.TestCheckResourceAttrSet("data.ibm_is_lb_profiles.test_profiles", "lb_profiles.#"), diff --git a/ibm/service/vpc/data_source_ibm_is_lb_test.go b/ibm/service/vpc/data_source_ibm_is_lb_test.go new file mode 100644 index 000000000..3a62ebb2e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lb_test.go @@ -0,0 +1,90 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISLBDatasource_basic(t *testing.T) { + name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + routeMode := "false" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testDSCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "name", name), + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "route_mode", routeMode), + ), + }, + }, + }) +} +func TestAccIBMISLBDatasource_ReservedIp(t *testing.T) { + name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + routeMode := "false" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testDSCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "name", name), + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "route_mode", routeMode), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.0.address"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.0.href"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.0.name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_lb.ds_lb", "private_ip.0.resource_type"), + ), + }, + }, + }) +} + +func testDSCheckIBMISLBConfig(vpcname, subnetname, zone, cidr, name string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" +} +resource "ibm_is_lb" "testacc_lb" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] +} +data "ibm_is_lb" "ds_lb" { + name = ibm_is_lb.testacc_lb.name +}`, vpcname, subnetname, zone, cidr, name) +} diff --git a/ibm/data_source_ibm_is_lbs.go b/ibm/service/vpc/data_source_ibm_is_lbs.go similarity index 76% rename from ibm/data_source_ibm_is_lbs.go rename to ibm/service/vpc/data_source_ibm_is_lbs.go index 9dffea10e..a1b689c9f 100644 --- a/ibm/data_source_ibm_is_lbs.go +++ b/ibm/service/vpc/data_source_ibm_is_lbs.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -18,9 +19,10 @@ const ( CreatedAt = "created_at" isLbProfile = "profile" ProvisioningStatus = "provisioning_status" + ID = "id" ) -func dataSourceIBMISLBS() *schema.Resource { +func DataSourceIBMISLBS() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISLBSRead, Schema: map[string]*schema.Schema{ @@ -54,6 +56,11 @@ func dataSourceIBMISLBS() *schema.Resource { Computed: true, Description: "Load Balancer name", }, + isLBUdpSupported: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this load balancer supports UDP.", + }, isLBRouteMode: { Type: schema.TypeBool, Computed: true, @@ -91,7 +98,40 @@ func dataSourceIBMISLBS() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Description: "Load Balancer private IPs", }, - + isLBPrivateIPDetail: { + Type: schema.TypeList, + Computed: true, + Description: "The private IP addresses assigned to this load balancer.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isLBPrivateIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isLBPrivateIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isLBPrivateIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isLBPrivateIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isLBPrivateIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, isLBSubnets: { Type: schema.TypeList, Computed: true, @@ -126,7 +166,7 @@ func dataSourceIBMISLBS() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "Tags associated to Load Balancer", }, @@ -192,19 +232,19 @@ func dataSourceIBMISLBS() *schema.Resource { }, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -239,9 +279,9 @@ func getLbs(d *schema.ResourceData, meta interface{}) error { } lbs, response, err := sess.ListLoadBalancers(listLoadBalancersOptions) if err != nil { - return fmt.Errorf("Error Fetching Load Balancers %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching Load Balancers %s\n%s", err, response) } - start = GetNext(lbs.Next) + start = flex.GetNext(lbs.Next) allrecs = append(allrecs, lbs.LoadBalancers...) if start == "" { break @@ -258,6 +298,9 @@ func getLbs(d *schema.ResourceData, meta interface{}) error { if lb.RouteMode != nil { lbInfo[isLBRouteMode] = *lb.RouteMode } + if lb.UDPSupported != nil { + lbInfo[isLBUdpSupported] = *lb.UDPSupported + } lbInfo[CRN] = *lb.CRN lbInfo[ProvisioningStatus] = *lb.ProvisioningStatus @@ -281,15 +324,34 @@ func getLbs(d *schema.ResourceData, meta interface{}) error { lbInfo[isLBPublicIPs] = publicIpList privateIpList := make([]string, 0) + privateIpDetailList := make([]map[string]interface{}, 0) if lb.PrivateIps != nil { for _, ip := range lb.PrivateIps { if ip.Address != nil { prip := *ip.Address privateIpList = append(privateIpList, prip) } + currentPriIp := map[string]interface{}{} + if ip.Address != nil { + currentPriIp[isLBPrivateIpAddress] = ip.Address + } + if ip.Href != nil { + currentPriIp[isLBPrivateIpHref] = ip.Href + } + if ip.Name != nil { + currentPriIp[isLBPrivateIpName] = ip.Name + } + if ip.ID != nil { + currentPriIp[isLBPrivateIpId] = ip.ID + } + if ip.ResourceType != nil { + currentPriIp[isLBPrivateIpResourceType] = ip.ResourceType + } + privateIpDetailList = append(privateIpDetailList, currentPriIp) } } lbInfo[isLBPrivateIPs] = privateIpList + lbInfo[isLBPrivateIPDetail] = privateIpDetailList //log.Printf("*******isLBPrivateIPs %+v", lbInfo[isLBPrivateIPs]) if lb.Subnets != nil { @@ -343,22 +405,22 @@ func getLbs(d *schema.ResourceData, meta interface{}) error { } lbInfo[isLBResourceGroup] = *lb.ResourceGroup.ID lbInfo[isLBHostName] = *lb.Hostname - tags, err := GetTagsUsingCRN(meta, *lb.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *lb.CRN) if err != nil { log.Printf( "Error on get of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) } lbInfo[isLBTags] = tags - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - lbInfo[ResourceControllerURL] = controller + "/vpc-ext/network/loadBalancers" - lbInfo[ResourceName] = *lb.Name + lbInfo[flex.ResourceControllerURL] = controller + "/vpc-ext/network/loadBalancers" + lbInfo[flex.ResourceName] = *lb.Name //log.Printf("*******lbInfo %+v", lbInfo) if lb.ResourceGroup != nil { - lbInfo[ResourceGroupName] = *lb.ResourceGroup.ID + lbInfo[flex.ResourceGroupName] = *lb.ResourceGroup.ID } lbList = append(lbList, lbInfo) // log.Printf("*******lbList %+v", lbList) diff --git a/ibm/service/vpc/data_source_ibm_is_lbs_test.go b/ibm/service/vpc/data_source_ibm_is_lbs_test.go new file mode 100644 index 000000000..fd078bd5f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_lbs_test.go @@ -0,0 +1,108 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISLBSDatasource_basic(t *testing.T) { + name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + var lb string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + + { + Config: testDSCheckIBMISLBSConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_lb", lb), + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "name", name), + ), + }, + { + Config: testDSCheckIBMISLBSDatasourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.route_mode"), + ), + }, + }, + }) + +} +func TestAccIBMISLBSDatasource_ReservedIp(t *testing.T) { + name := fmt.Sprintf("tflb-name-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + var lb string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + + { + Config: testDSCheckIBMISLBSConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_lb", lb), + resource.TestCheckResourceAttr( + "data.ibm_is_lb.ds_lb", "name", name), + ), + }, + { + Config: testDSCheckIBMISLBSDatasourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.route_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_lbs.test_lbs", "load_balancers.0.private_ip.0.resource_type"), + ), + }, + }, + }) + +} + +func testDSCheckIBMISLBSConfig(vpcname, subnetname, zone, cidr, name string) string { + // status filter defaults to empty + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_lb" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + } + data "ibm_is_lb" "ds_lb" { + name = ibm_is_lb.testacc_lb.name + }`, vpcname, subnetname, zone, cidr, name) +} +func testDSCheckIBMISLBSDatasourceConfig() string { + // status filter defaults to empty + return fmt.Sprintf(` + data "ibm_is_lbs" "test_lbs" { + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_network_acl.go b/ibm/service/vpc/data_source_ibm_is_network_acl.go new file mode 100644 index 000000000..5e6e336e5 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_network_acl.go @@ -0,0 +1,706 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsNetworkACL() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsNetworkACLRead, + + Schema: map[string]*schema.Schema{ + isNetworkACLName: { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"vpc_name"}, + ExactlyOneOf: []string{"name", "network_acl"}, + Description: "The network acl name.", + }, + "vpc_name": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{isNetworkACLName}, + Description: "The name of the vpc the network acl resides in.", + }, + "network_acl": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "network_acl"}, + Description: "The network acl id.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the network ACL was created.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this network ACL.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL.", + }, + isNetworkACLResourceGroup: { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this network ACL.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + isNetworkACLRules: { + Type: schema.TypeList, + Computed: true, + Description: "The ordered rules for this network ACL. If no rules exist, all traffic will be denied.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRuleAction: { + Type: schema.TypeString, + Computed: true, + Description: "Whether to allow or deny matching traffic.", + }, + "before": { + Type: schema.TypeList, + Computed: true, + Description: "The rule that this rule is immediately before. In a rule collection, this alwaysrefers to the next item in the collection. If absent, this is the last rule.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL rule.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network ACL rule.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network ACL rule.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the rule was created.", + }, + isNetworkACLRuleDestination: { + Type: schema.TypeString, + Computed: true, + Description: "The destination CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + }, + isNetworkACLRuleDirection: { + Type: schema.TypeString, + Computed: true, + Description: "Whether the traffic to be matched is `inbound` or `outbound`.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL rule.", + }, + isNetworkACLRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network ACL rule.", + }, + isNetworkACLRuleIPVersion: { + Type: schema.TypeString, + Computed: true, + Description: "The IP version for this rule.", + }, + isNetworkACLRuleName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + isNetworkACLRuleProtocol: { + Type: schema.TypeString, + Computed: true, + Description: "The protocol to enforce.", + }, + isNetworkACLRuleSource: { + Type: schema.TypeString, + Computed: true, + Description: "The source CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + }, + isNetworkACLRuleICMP: { + Type: schema.TypeList, + Computed: true, + Description: "The protocol ICMP", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRuleICMPCode: { + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic code to allow. Valid values from 0 to 255.", + }, + isNetworkACLRuleICMPType: { + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic type to allow. Valid values from 0 to 254.", + }, + }, + }, + }, + + isNetworkACLRuleTCP: { + Type: schema.TypeList, + Computed: true, + Description: "TCP protocol", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRulePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRulePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + }, + }, + }, + + isNetworkACLRuleUDP: { + Type: schema.TypeList, + Computed: true, + Description: "UDP protocol", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRulePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRulePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + }, + }, + }, + }, + }, + }, + "subnets": { + Type: schema.TypeList, + Computed: true, + Description: "The subnets to which this network ACL is attached.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "The VPC this network ACL is a part of.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsNetworkACLRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + vpc_name_str := "" + network_acl_name := "" + if vpc, ok := d.GetOk("vpc_name"); ok { + vpc_name_str = vpc.(string) + } + networkACL := &vpcv1.NetworkACL{} + if vpc_name_str != "" { + network_acl_name = d.Get(isNetworkACLName).(string) + + start := "" + allrecs := []vpcv1.NetworkACL{} + for { + listNetworkAclsOptions := &vpcv1.ListNetworkAclsOptions{} + if start != "" { + listNetworkAclsOptions.Start = &start + } + networkACLCollection, response, err := vpcClient.ListNetworkAclsWithContext(context, listNetworkAclsOptions) + if err != nil || networkACLCollection == nil { + log.Printf("[DEBUG] ListNetworkAclsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListNetworkAclsWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(networkACLCollection.Next) + allrecs = append(allrecs, networkACLCollection.NetworkAcls...) + if start == "" { + break + } + } + acl_found := false + for _, networkAcl := range allrecs { + if *networkAcl.VPC.Name == vpc_name_str && network_acl_name == *networkAcl.Name { + networkACL = &networkAcl + acl_found = true + break + } + } + + if !acl_found { + log.Printf("[DEBUG] No networkACL found with given VPC %s and ACL name %s", vpc_name_str, network_acl_name) + return diag.FromErr(fmt.Errorf("[ERROR] No networkACL found with given VPC %s and ACL name %s", vpc_name_str, network_acl_name)) + } + } else { + + getNetworkACLOptions := &vpcv1.GetNetworkACLOptions{} + + getNetworkACLOptions.SetID(d.Get("network_acl").(string)) + + networkACLInst, response, err := vpcClient.GetNetworkACLWithContext(context, getNetworkACLOptions) + if err != nil || networkACLInst == nil { + log.Printf("[DEBUG] GetNetworkACLWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetNetworkACLWithContext failed %s\n%s", err, response)) + } + networkACL = networkACLInst + } + d.SetId(*networkACL.ID) + if err = d.Set("created_at", flex.DateTimeToString(networkACL.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", networkACL.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("href", networkACL.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("name", networkACL.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if networkACL.ResourceGroup != nil { + err = d.Set(isNetworkACLResourceGroup, dataSourceNetworkACLFlattenResourceGroup(*networkACL.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) + } + } + + if networkACL.Rules != nil { + err = d.Set(isNetworkACLRules, dataSourceNetworkACLFlattenRules(networkACL.Rules)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting rules %s", err)) + } + } + + if networkACL.Subnets != nil { + err = d.Set("subnets", dataSourceNetworkACLFlattenSubnets(networkACL.Subnets)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnets %s", err)) + } + } + + if networkACL.VPC != nil { + err = d.Set("vpc", dataSourceNetworkACLFlattenVPC(*networkACL.VPC)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpc %s", err)) + } + } + + return nil +} + +func dataSourceNetworkACLFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceNetworkACLResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceNetworkACLResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceNetworkACLFlattenRules(result []vpcv1.NetworkACLRuleItemIntf) (rules []map[string]interface{}) { + for _, rulesItem := range result { + rules = append(rules, dataSourceNetworkACLRulesToMap(rulesItem)) + } + + return rules +} + +func dataSourceNetworkACLRulesToMap(rule vpcv1.NetworkACLRuleItemIntf) (rulesMap map[string]interface{}) { + rulesMap = map[string]interface{}{} + + switch reflect.TypeOf(rule).String() { + case "*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolIcmp": + { + rulex := rule.(*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolIcmp) + rulesMap["id"] = *rulex.ID + rulesMap[isNetworkACLRuleHref] = *rulex.Href + rulesMap[isNetworkACLRuleProtocol] = *rulex.Protocol + if rulex.Before != nil { + beforeList := []map[string]interface{}{} + beforeMap := dataSourceNetworkACLRulesBeforeToMap(*rulex.Before) + beforeList = append(beforeList, beforeMap) + rulesMap["before"] = beforeList + } + rulesMap["created_at"] = flex.DateTimeToString(rulex.CreatedAt) + rulesMap[isNetworkACLRuleName] = *rulex.Name + rulesMap[isNetworkACLRuleAction] = *rulex.Action + rulesMap[isNetworkACLRuleIPVersion] = *rulex.IPVersion + rulesMap[isNetworkACLRuleSource] = *rulex.Source + rulesMap[isNetworkACLRuleDestination] = *rulex.Destination + rulesMap[isNetworkACLRuleDirection] = *rulex.Direction + rulesMap[isNetworkACLRuleTCP] = make([]map[string]int, 0, 0) + rulesMap[isNetworkACLRuleUDP] = make([]map[string]int, 0, 0) + icmp := make([]map[string]int, 1, 1) + if rulex.Code != nil && rulex.Type != nil { + icmp[0] = map[string]int{ + isNetworkACLRuleICMPCode: int(*rulex.Code), + isNetworkACLRuleICMPType: int(*rulex.Type), + } + } + rulesMap[isNetworkACLRuleICMP] = icmp + } + case "*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolTcpudp": + { + rulex := rule.(*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolTcpudp) + rulesMap["id"] = *rulex.ID + rulesMap[isNetworkACLRuleHref] = *rulex.Href + rulesMap[isNetworkACLRuleProtocol] = *rulex.Protocol + if rulex.Before != nil { + beforeList := []map[string]interface{}{} + beforeMap := dataSourceNetworkACLRulesBeforeToMap(*rulex.Before) + beforeList = append(beforeList, beforeMap) + rulesMap["before"] = beforeList + } + rulesMap["created_at"] = flex.DateTimeToString(rulex.CreatedAt) + rulesMap[isNetworkACLRuleName] = *rulex.Name + rulesMap[isNetworkACLRuleAction] = *rulex.Action + rulesMap[isNetworkACLRuleIPVersion] = *rulex.IPVersion + rulesMap[isNetworkACLRuleSource] = *rulex.Source + rulesMap[isNetworkACLRuleDestination] = *rulex.Destination + rulesMap[isNetworkACLRuleDirection] = *rulex.Direction + if *rulex.Protocol == "tcp" { + rulesMap[isNetworkACLRuleICMP] = make([]map[string]int, 0, 0) + rulesMap[isNetworkACLRuleUDP] = make([]map[string]int, 0, 0) + tcp := make([]map[string]int, 1, 1) + tcp[0] = map[string]int{ + isNetworkACLRuleSourcePortMax: checkNetworkACLNil(rulex.SourcePortMax), + isNetworkACLRuleSourcePortMin: checkNetworkACLNil(rulex.SourcePortMin), + } + tcp[0][isNetworkACLRulePortMax] = checkNetworkACLNil(rulex.DestinationPortMax) + tcp[0][isNetworkACLRulePortMin] = checkNetworkACLNil(rulex.DestinationPortMin) + rulesMap[isNetworkACLRuleTCP] = tcp + } else if *rulex.Protocol == "udp" { + rulesMap[isNetworkACLRuleICMP] = make([]map[string]int, 0, 0) + rulesMap[isNetworkACLRuleTCP] = make([]map[string]int, 0, 0) + udp := make([]map[string]int, 1, 1) + udp[0] = map[string]int{ + isNetworkACLRuleSourcePortMax: checkNetworkACLNil(rulex.SourcePortMax), + isNetworkACLRuleSourcePortMin: checkNetworkACLNil(rulex.SourcePortMin), + } + udp[0][isNetworkACLRulePortMax] = checkNetworkACLNil(rulex.DestinationPortMax) + udp[0][isNetworkACLRulePortMin] = checkNetworkACLNil(rulex.DestinationPortMin) + rulesMap[isNetworkACLRuleUDP] = udp + } + } + case "*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAll": + { + rulex := rule.(*vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAll) + rulesMap["id"] = *rulex.ID + rulesMap[isNetworkACLRuleHref] = *rulex.Href + rulesMap[isNetworkACLRuleProtocol] = *rulex.Protocol + if rulex.Before != nil { + beforeList := []map[string]interface{}{} + beforeMap := dataSourceNetworkACLRulesBeforeToMap(*rulex.Before) + beforeList = append(beforeList, beforeMap) + rulesMap["before"] = beforeList + } + rulesMap["created_at"] = flex.DateTimeToString(rulex.CreatedAt) + rulesMap[isNetworkACLRuleName] = *rulex.Name + rulesMap[isNetworkACLRuleAction] = *rulex.Action + rulesMap[isNetworkACLRuleIPVersion] = *rulex.IPVersion + rulesMap[isNetworkACLRuleSource] = *rulex.Source + rulesMap[isNetworkACLRuleDestination] = *rulex.Destination + rulesMap[isNetworkACLRuleDirection] = *rulex.Direction + rulesMap[isNetworkACLRuleICMP] = make([]map[string]int, 0, 0) + rulesMap[isNetworkACLRuleTCP] = make([]map[string]int, 0, 0) + rulesMap[isNetworkACLRuleUDP] = make([]map[string]int, 0, 0) + } + } + + return rulesMap +} + +func dataSourceNetworkACLRulesBeforeToMap(beforeItem vpcv1.NetworkACLRuleReference) (beforeMap map[string]interface{}) { + beforeMap = map[string]interface{}{} + + if beforeItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLBeforeDeletedToMap(*beforeItem.Deleted) + deletedList = append(deletedList, deletedMap) + beforeMap["deleted"] = deletedList + } + if beforeItem.Href != nil { + beforeMap["href"] = beforeItem.Href + } + if beforeItem.ID != nil { + beforeMap["id"] = beforeItem.ID + } + if beforeItem.Name != nil { + beforeMap["name"] = beforeItem.Name + } + + return beforeMap +} + +func dataSourceNetworkACLBeforeDeletedToMap(deletedItem vpcv1.NetworkACLRuleReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkACLFlattenSubnets(result []vpcv1.SubnetReference) (subnets []map[string]interface{}) { + for _, subnetsItem := range result { + subnets = append(subnets, dataSourceNetworkACLSubnetsToMap(subnetsItem)) + } + + return subnets +} + +func dataSourceNetworkACLSubnetsToMap(subnetsItem vpcv1.SubnetReference) (subnetsMap map[string]interface{}) { + subnetsMap = map[string]interface{}{} + + if subnetsItem.CRN != nil { + subnetsMap["crn"] = subnetsItem.CRN + } + if subnetsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLSubnetsDeletedToMap(*subnetsItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetsMap["deleted"] = deletedList + } + if subnetsItem.Href != nil { + subnetsMap["href"] = subnetsItem.Href + } + if subnetsItem.ID != nil { + subnetsMap["id"] = subnetsItem.ID + } + if subnetsItem.Name != nil { + subnetsMap["name"] = subnetsItem.Name + } + + return subnetsMap +} + +func dataSourceNetworkACLSubnetsDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkACLFlattenVPC(result vpcv1.VPCReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceNetworkACLVPCToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceNetworkACLVPCToMap(vpcItem vpcv1.VPCReference) (vpcMap map[string]interface{}) { + vpcMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + vpcMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLVPCDeletedToMap(*vpcItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcMap["deleted"] = deletedList + } + if vpcItem.Href != nil { + vpcMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + vpcMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + vpcMap["name"] = vpcItem.Name + } + + return vpcMap +} + +func dataSourceNetworkACLVPCDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/data_source_ibm_is_network_acl_rule.go b/ibm/service/vpc/data_source_ibm_is_network_acl_rule.go similarity index 96% rename from ibm/data_source_ibm_is_network_acl_rule.go rename to ibm/service/vpc/data_source_ibm_is_network_acl_rule.go index c39f1aa5a..3e557863e 100644 --- a/ibm/data_source_ibm_is_network_acl_rule.go +++ b/ibm/service/vpc/data_source_ibm_is_network_acl_rule.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "reflect" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +17,7 @@ const ( isNetworkACLRuleHref = "href" ) -func dataSourceIBMISNetworkACLRule() *schema.Resource { +func DataSourceIBMISNetworkACLRule() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISNetworkACLRuleRead, @@ -38,7 +40,7 @@ func dataSourceIBMISNetworkACLRule() *schema.Resource { isNetworkACLRuleName: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleName), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleName), Description: "The user-defined name for this rule", }, isNetworkACLRuleProtocol: { @@ -187,9 +189,9 @@ func nawaclRuleDataGet(d *schema.ResourceData, meta interface{}, name, nwACLID s ruleList, response, err := sess.ListNetworkACLRules(listNetworkACLRulesOptions) if err != nil { - return fmt.Errorf("Error Fetching network acl ruless %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching network acl ruless %s\n%s", err, response) } - start = GetNext(ruleList.Next) + start = flex.GetNext(ruleList.Next) allrecs = append(allrecs, ruleList.Rules...) if start == "" { diff --git a/ibm/data_source_ibm_is_network_acl_rule_test.go b/ibm/service/vpc/data_source_ibm_is_network_acl_rule_test.go similarity index 89% rename from ibm/data_source_ibm_is_network_acl_rule_test.go rename to ibm/service/vpc/data_source_ibm_is_network_acl_rule_test.go index a4e971bc4..2bf7f504e 100644 --- a/ibm/data_source_ibm_is_network_acl_rule_test.go +++ b/ibm/service/vpc/data_source_ibm_is_network_acl_rule_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISNetworkACLRuleDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISNetworkACLRuleDataSourceConfig(), diff --git a/ibm/data_source_ibm_is_network_acl_rules.go b/ibm/service/vpc/data_source_ibm_is_network_acl_rules.go similarity index 97% rename from ibm/data_source_ibm_is_network_acl_rules.go rename to ibm/service/vpc/data_source_ibm_is_network_acl_rules.go index 249a94b8a..279dcdc32 100644 --- a/ibm/data_source_ibm_is_network_acl_rules.go +++ b/ibm/service/vpc/data_source_ibm_is_network_acl_rules.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "reflect" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -16,7 +17,7 @@ const ( isNwACLRules = "rules" ) -func dataSourceIBMISNetworkACLRules() *schema.Resource { +func DataSourceIBMISNetworkACLRules() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISNetworkACLRulesRead, @@ -194,9 +195,9 @@ func networkACLRulesList(d *schema.ResourceData, meta interface{}, nwACLID strin ruleList, response, err := sess.ListNetworkACLRules(listNetworkACLRulesOptions) if err != nil { - return fmt.Errorf("Error Fetching network acl ruless %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching network acl ruless %s\n%s", err, response) } - start = GetNext(ruleList.Next) + start = flex.GetNext(ruleList.Next) allrecs = append(allrecs, ruleList.Rules...) if start == "" { diff --git a/ibm/data_source_ibm_is_network_acl_rules_test.go b/ibm/service/vpc/data_source_ibm_is_network_acl_rules_test.go similarity index 87% rename from ibm/data_source_ibm_is_network_acl_rules_test.go rename to ibm/service/vpc/data_source_ibm_is_network_acl_rules_test.go index 6b59bfda9..5d3df2a83 100644 --- a/ibm/data_source_ibm_is_network_acl_rules_test.go +++ b/ibm/service/vpc/data_source_ibm_is_network_acl_rules_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISNetworkACLRulesDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISNetworkACLRulesDataSourceConfig(), diff --git a/ibm/service/vpc/data_source_ibm_is_network_acl_test.go b/ibm/service/vpc/data_source_ibm_is_network_acl_test.go new file mode 100644 index 000000000..d5a1d12e8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_network_acl_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsNetworkACLDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsNetworkACLDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "rules.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "subnets.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acl.is_network_acl", "vpc.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsNetworkACLDataSourceConfigBasic() string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "tf-nwacl-vpc" + } + + resource "ibm_is_network_acl" "isExampleACL" { + name = "is-example-acl" + vpc = ibm_is_vpc.testacc_vpc.id + rules { + name = "outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + icmp { + code = 8 + type = 1 + } + # Optionals : + # port_max = + # port_min = + } + rules { + name = "inbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + icmp { + code = 8 + type = 1 + } + # Optionals : + # port_max = + # port_min = + } + } + + data "ibm_is_network_acl" "is_network_acl" { + vpc_name = ibm_is_vpc.testacc_vpc.name + name = ibm_is_network_acl.isExampleACL.name + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_network_acls.go b/ibm/service/vpc/data_source_ibm_is_network_acls.go new file mode 100644 index 000000000..fdc31577b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_network_acls.go @@ -0,0 +1,569 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsNetworkAcls() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsNetworkAclsRead, + + Schema: map[string]*schema.Schema{ + "resource_group": { + Type: schema.TypeString, + Optional: true, + Description: "Resource group identifier.", + }, + "network_acls": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of network ACLs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the network ACL was created.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this network ACL.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network ACL.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network ACL.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this network ACL.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + isNetworkACLRules: { + Type: schema.TypeList, + Computed: true, + Description: "The ordered rules for this network ACL. If no rules exist, all traffic will be denied.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRuleAction: { + Type: schema.TypeString, + Computed: true, + Description: "Whether to allow or deny matching traffic.", + }, + "before": { + Type: schema.TypeList, + Computed: true, + Description: "The rule that this rule is immediately before. In a rule collection, this alwaysrefers to the next item in the collection. If absent, this is the last rule.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL rule.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network ACL rule.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network ACL rule.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the rule was created.", + }, + isNetworkACLRuleDestination: { + Type: schema.TypeString, + Computed: true, + Description: "The destination CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + }, + isNetworkACLRuleDirection: { + Type: schema.TypeString, + Computed: true, + Description: "Whether the traffic to be matched is `inbound` or `outbound`.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network ACL rule.", + }, + isNetworkACLRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network ACL rule.", + }, + isNetworkACLRuleIPVersion: { + Type: schema.TypeString, + Computed: true, + Description: "The IP version for this rule.", + }, + isNetworkACLRuleName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + isNetworkACLRuleProtocol: { + Type: schema.TypeString, + Computed: true, + Description: "The protocol to enforce.", + }, + isNetworkACLRuleSource: { + Type: schema.TypeString, + Computed: true, + Description: "The source CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + }, + isNetworkACLRuleICMP: { + Type: schema.TypeList, + Computed: true, + Description: "The protocol ICMP", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRuleICMPCode: { + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic code to allow. Valid values from 0 to 255.", + }, + isNetworkACLRuleICMPType: { + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic type to allow. Valid values from 0 to 254.", + }, + }, + }, + }, + + isNetworkACLRuleTCP: { + Type: schema.TypeList, + Computed: true, + Description: "TCP protocol", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRulePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRulePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + }, + }, + }, + + isNetworkACLRuleUDP: { + Type: schema.TypeList, + Computed: true, + Description: "UDP protocol", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isNetworkACLRulePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRulePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMax: { + Type: schema.TypeInt, + Computed: true, + Description: "The highest port in the range of ports to be matched", + }, + isNetworkACLRuleSourcePortMin: { + Type: schema.TypeInt, + Computed: true, + Description: "The lowest port in the range of ports to be matched", + }, + }, + }, + }, + }, + }, + }, + "subnets": { + Type: schema.TypeList, + Computed: true, + Description: "The subnets to which this network ACL is attached.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "The VPC this network ACL is a part of.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsNetworkAclsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + resource_group_id := d.Get("resource_group").(string) + start := "" + allrecs := []vpcv1.NetworkACL{} + listNetworkAclsOptions := &vpcv1.ListNetworkAclsOptions{} + if resource_group_id != "" { + listNetworkAclsOptions.ResourceGroupID = &resource_group_id + } + for { + if start != "" { + listNetworkAclsOptions.Start = &start + } + networkACLCollection, response, err := vpcClient.ListNetworkAclsWithContext(context, listNetworkAclsOptions) + if err != nil || networkACLCollection == nil { + log.Printf("[DEBUG] ListNetworkAclsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListNetworkAclsWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(networkACLCollection.Next) + allrecs = append(allrecs, networkACLCollection.NetworkAcls...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsNetworkAclsID(d)) + + err = d.Set("network_acls", dataSourceNetworkACLCollectionFlattenNetworkAcls(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_acls %s", err)) + } + + return nil +} + +// dataSourceIBMIsNetworkAclsID returns a reasonable ID for the list. +func dataSourceIBMIsNetworkAclsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceNetworkACLCollectionFlattenNetworkAcls(result []vpcv1.NetworkACL) (networkAcls []map[string]interface{}) { + for _, networkAclsItem := range result { + networkAcls = append(networkAcls, dataSourceNetworkACLCollectionNetworkAclsToMap(networkAclsItem)) + } + + return networkAcls +} + +func dataSourceNetworkACLCollectionNetworkAclsToMap(networkAclsItem vpcv1.NetworkACL) (networkAclsMap map[string]interface{}) { + networkAclsMap = map[string]interface{}{} + + if networkAclsItem.CreatedAt != nil { + networkAclsMap["created_at"] = networkAclsItem.CreatedAt.String() + } + if networkAclsItem.CRN != nil { + networkAclsMap["crn"] = networkAclsItem.CRN + } + if networkAclsItem.Href != nil { + networkAclsMap["href"] = networkAclsItem.Href + } + if networkAclsItem.ID != nil { + networkAclsMap["id"] = networkAclsItem.ID + } + if networkAclsItem.Name != nil { + networkAclsMap["name"] = networkAclsItem.Name + } + if networkAclsItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceNetworkACLCollectionNetworkAclsResourceGroupToMap(*networkAclsItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + networkAclsMap["resource_group"] = resourceGroupList + } + if networkAclsItem.Rules != nil { + rulesList := []map[string]interface{}{} + for _, rulesItem := range networkAclsItem.Rules { + rulesList = append(rulesList, dataSourceNetworkACLRulesToMap(rulesItem)) + } + networkAclsMap[isNetworkACLRules] = rulesList + } + if networkAclsItem.Subnets != nil { + subnetsList := []map[string]interface{}{} + for _, subnetsItem := range networkAclsItem.Subnets { + subnetsList = append(subnetsList, dataSourceNetworkACLCollectionNetworkAclsSubnetsToMap(subnetsItem)) + } + networkAclsMap["subnets"] = subnetsList + } + if networkAclsItem.VPC != nil { + vpcList := []map[string]interface{}{} + vpcMap := dataSourceNetworkACLCollectionNetworkAclsVPCToMap(*networkAclsItem.VPC) + vpcList = append(vpcList, vpcMap) + networkAclsMap["vpc"] = vpcList + } + + return networkAclsMap +} + +func dataSourceNetworkACLCollectionNetworkAclsResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceNetworkACLCollectionRulesBeforeToMap(beforeItem vpcv1.NetworkACLRuleReference) (beforeMap map[string]interface{}) { + beforeMap = map[string]interface{}{} + + if beforeItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLCollectionBeforeDeletedToMap(*beforeItem.Deleted) + deletedList = append(deletedList, deletedMap) + beforeMap["deleted"] = deletedList + } + if beforeItem.Href != nil { + beforeMap["href"] = beforeItem.Href + } + if beforeItem.ID != nil { + beforeMap["id"] = beforeItem.ID + } + if beforeItem.Name != nil { + beforeMap["name"] = beforeItem.Name + } + + return beforeMap +} + +func dataSourceNetworkACLCollectionBeforeDeletedToMap(deletedItem vpcv1.NetworkACLRuleReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkACLCollectionNetworkAclsSubnetsToMap(subnetsItem vpcv1.SubnetReference) (subnetsMap map[string]interface{}) { + subnetsMap = map[string]interface{}{} + + if subnetsItem.CRN != nil { + subnetsMap["crn"] = subnetsItem.CRN + } + if subnetsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLCollectionSubnetsDeletedToMap(*subnetsItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetsMap["deleted"] = deletedList + } + if subnetsItem.Href != nil { + subnetsMap["href"] = subnetsItem.Href + } + if subnetsItem.ID != nil { + subnetsMap["id"] = subnetsItem.ID + } + if subnetsItem.Name != nil { + subnetsMap["name"] = subnetsItem.Name + } + + return subnetsMap +} + +func dataSourceNetworkACLCollectionSubnetsDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceNetworkACLCollectionNetworkAclsVPCToMap(vpcItem vpcv1.VPCReference) (vpcMap map[string]interface{}) { + vpcMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + vpcMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceNetworkACLCollectionVPCDeletedToMap(*vpcItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcMap["deleted"] = deletedList + } + if vpcItem.Href != nil { + vpcMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + vpcMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + vpcMap["name"] = vpcItem.Name + } + + return vpcMap +} + +func dataSourceNetworkACLCollectionVPCDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_network_acls_test.go b/ibm/service/vpc/data_source_ibm_is_network_acls_test.go new file mode 100644 index 000000000..ff11c9f3f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_network_acls_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsNetworkAclsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsNetworkAclsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_network_acls.is_network_acls", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_network_acls.is_network_acls", "network_acls.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsNetworkAclsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_network_acls" "is_network_acls" { + } + `) +} diff --git a/ibm/data_source_ibm_is_operating_system.go b/ibm/service/vpc/data_source_ibm_is_operating_system.go similarity index 94% rename from ibm/data_source_ibm_is_operating_system.go rename to ibm/service/vpc/data_source_ibm_is_operating_system.go index 480000bdd..b6496cce7 100644 --- a/ibm/data_source_ibm_is_operating_system.go +++ b/ibm/service/vpc/data_source_ibm_is_operating_system.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -21,7 +21,7 @@ const ( isOperatingSystemVersion = "version" ) -func dataSourceIBMISOperatingSystem() *schema.Resource { +func DataSourceIBMISOperatingSystem() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISOperatingSystemRead, @@ -93,7 +93,7 @@ func osGet(d *schema.ResourceData, meta interface{}, name string) error { } os, response, err := sess.GetOperatingSystem(getOperatingSystemOptions) if err != nil || os == nil { - return fmt.Errorf("Error Getting Operating System Details %s , %s", err, response) + return fmt.Errorf("[ERROR] Error Getting Operating System Details %s , %s", err, response) } d.Set(isOperatingSystemName, *os.Name) d.SetId(*os.Name) diff --git a/ibm/data_source_ibm_is_operating_system_test.go b/ibm/service/vpc/data_source_ibm_is_operating_system_test.go similarity index 83% rename from ibm/data_source_ibm_is_operating_system_test.go rename to ibm/service/vpc/data_source_ibm_is_operating_system_test.go index e0d099eaa..c6276b59e 100644 --- a/ibm/data_source_ibm_is_operating_system_test.go +++ b/ibm/service/vpc/data_source_ibm_is_operating_system_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISOperatingSystemDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISOperatingSystemDataSourceConfig(), diff --git a/ibm/data_source_ibm_is_operating_systems.go b/ibm/service/vpc/data_source_ibm_is_operating_systems.go similarity index 93% rename from ibm/data_source_ibm_is_operating_systems.go rename to ibm/service/vpc/data_source_ibm_is_operating_systems.go index 5568231dc..1c68d44b8 100644 --- a/ibm/data_source_ibm_is_operating_systems.go +++ b/ibm/service/vpc/data_source_ibm_is_operating_systems.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +16,7 @@ const ( isOperatingSystems = "operating_systems" ) -func dataSourceIBMISOperatingSystems() *schema.Resource { +func DataSourceIBMISOperatingSystems() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISOperatingSystemsRead, @@ -99,9 +100,9 @@ func osList(d *schema.ResourceData, meta interface{}) error { osList, response, err := sess.ListOperatingSystems(listOperatingSystemsOptions) if err != nil { - return fmt.Errorf("Error Fetching operating systems %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching operating systems %s\n%s", err, response) } - start = GetNext(osList.Next) + start = flex.GetNext(osList.Next) allrecs = append(allrecs, osList.OperatingSystems...) if start == "" { break diff --git a/ibm/data_source_ibm_is_operating_systems_test.go b/ibm/service/vpc/data_source_ibm_is_operating_systems_test.go similarity index 81% rename from ibm/data_source_ibm_is_operating_systems_test.go rename to ibm/service/vpc/data_source_ibm_is_operating_systems_test.go index 66517e731..716ba135d 100644 --- a/ibm/data_source_ibm_is_operating_systems_test.go +++ b/ibm/service/vpc/data_source_ibm_is_operating_systems_test.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISOperatingSystemsDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISOperatingSystemsDataSourceConfig(), diff --git a/ibm/data_source_ibm_is_placement_group.go b/ibm/service/vpc/data_source_ibm_is_placement_group.go similarity index 81% rename from ibm/data_source_ibm_is_placement_group.go rename to ibm/service/vpc/data_source_ibm_is_placement_group.go index fa7cff687..eccd1e175 100644 --- a/ibm/data_source_ibm_is_placement_group.go +++ b/ibm/service/vpc/data_source_ibm_is_placement_group.go @@ -1,20 +1,22 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsPlacementGroup() *schema.Resource { +func DataSourceIbmIsPlacementGroup() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsPlacementGroupRead, @@ -82,14 +84,14 @@ func dataSourceIbmIsPlacementGroup() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, isPlacementGroupAccessTags: { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "List of access management tags", }, }, @@ -97,7 +99,7 @@ func dataSourceIbmIsPlacementGroup() *schema.Resource { } func dataSourceIbmIsPlacementGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -114,7 +116,7 @@ func dataSourceIbmIsPlacementGroupRead(context context.Context, d *schema.Resour log.Printf("[DEBUG] ListPlacementGroupsWithContext failed %s\n%s", err, response) return diag.FromErr(err) } - start = GetNext(placementGroupCollection.Next) + start = flex.GetNext(placementGroupCollection.Next) allrecs = append(allrecs, placementGroupCollection.PlacementGroups...) if start == "" { break @@ -125,40 +127,40 @@ func dataSourceIbmIsPlacementGroupRead(context context.Context, d *schema.Resour d.SetId(*placementGroup.ID) if err = d.Set("created_at", placementGroup.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("crn", placementGroup.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("href", placementGroup.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("lifecycle_state", placementGroup.LifecycleState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) } if err = d.Set("name", placementGroup.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if placementGroup.ResourceGroup != nil { err = d.Set("resource_group", dataSourcePlacementGroupFlattenResourceGroup(*placementGroup.ResourceGroup)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) } } if err = d.Set("resource_type", placementGroup.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } if err = d.Set("strategy", placementGroup.Strategy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting strategy: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting strategy: %s", err)) } - tags, err := GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isUserTagType) + tags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isUserTagType) if err != nil { log.Printf( "An error getting placement group (%s) tags : %s", d.Id(), err) } - accesstags, err := GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isAccessTagType) + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error getting placement group (%s) access tags: %s", d.Id(), err) @@ -169,7 +171,7 @@ func dataSourceIbmIsPlacementGroupRead(context context.Context, d *schema.Resour return nil } } - return diag.FromErr(fmt.Errorf("No placement group found with name %s", pgname)) + return diag.FromErr(fmt.Errorf("[ERROR] No placement group found with name %s", pgname)) } func dataSourcePlacementGroupFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { diff --git a/ibm/data_source_ibm_is_placement_group_test.go b/ibm/service/vpc/data_source_ibm_is_placement_group_test.go similarity index 92% rename from ibm/data_source_ibm_is_placement_group_test.go rename to ibm/service/vpc/data_source_ibm_is_placement_group_test.go index 285f9e05b..95df6b77c 100644 --- a/ibm/data_source_ibm_is_placement_group_test.go +++ b/ibm/service/vpc/data_source_ibm_is_placement_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIbmIsPlacementGroupDataSourceAllArgs(t *testing.T) { placementGroupName := fmt.Sprintf("tf-pg-name%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmIsPlacementGroupDataSourceConfig(placementGroupStrategy, placementGroupName), diff --git a/ibm/data_source_ibm_is_placement_groups.go b/ibm/service/vpc/data_source_ibm_is_placement_groups.go similarity index 88% rename from ibm/data_source_ibm_is_placement_groups.go rename to ibm/service/vpc/data_source_ibm_is_placement_groups.go index 74a10da4c..b395f7674 100644 --- a/ibm/data_source_ibm_is_placement_groups.go +++ b/ibm/service/vpc/data_source_ibm_is_placement_groups.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,13 +9,15 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsPlacementGroups() *schema.Resource { +func DataSourceIbmIsPlacementGroups() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsPlacementGroupsRead, @@ -94,14 +96,14 @@ func dataSourceIbmIsPlacementGroups() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, isPlacementGroupAccessTags: { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "List of access management tags", }, }, @@ -117,7 +119,7 @@ func dataSourceIbmIsPlacementGroups() *schema.Resource { } func dataSourceIbmIsPlacementGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -134,7 +136,7 @@ func dataSourceIbmIsPlacementGroupsRead(context context.Context, d *schema.Resou log.Printf("[DEBUG] ListPlacementGroupsWithContext failed %s\n%s", err, response) return diag.FromErr(err) } - start = GetNext(placementGroupCollection.Next) + start = flex.GetNext(placementGroupCollection.Next) allrecs = append(allrecs, placementGroupCollection.PlacementGroups...) if start == "" { break @@ -142,14 +144,12 @@ func dataSourceIbmIsPlacementGroupsRead(context context.Context, d *schema.Resou } d.SetId(dataSourceIbmIsPlacementGroupsID(d)) - if len(allrecs) > 0 { - err = d.Set("placement_groups", dataSourcePlacementGroupCollectionFlattenPlacementGroups(meta, allrecs)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting placement_groups %s", err)) - } - if err = d.Set("total_count", len(allrecs)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) - } + err = d.Set("placement_groups", dataSourcePlacementGroupCollectionFlattenPlacementGroups(meta, allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting placement_groups %s", err)) + } + if err = d.Set("total_count", len(allrecs)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) } return nil } @@ -160,6 +160,7 @@ func dataSourceIbmIsPlacementGroupsID(d *schema.ResourceData) string { } func dataSourcePlacementGroupCollectionFlattenPlacementGroups(meta interface{}, result []vpcv1.PlacementGroup) (placementGroups []map[string]interface{}) { + placementGroups = make([]map[string]interface{}, 0) for _, placementGroupsItem := range result { placementGroups = append(placementGroups, dataSourcePlacementGroupCollectionPlacementGroupsToMap(meta, placementGroupsItem)) } @@ -200,13 +201,13 @@ func dataSourcePlacementGroupCollectionPlacementGroupsToMap(meta interface{}, pl if placementGroupsItem.Strategy != nil { placementGroupsMap["strategy"] = placementGroupsItem.Strategy } - tags, err := GetGlobalTagsUsingCRN(meta, *placementGroupsItem.CRN, "", isUserTagType) + tags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroupsItem.CRN, "", isUserTagType) if err != nil { log.Printf( "An error getting placement group (%s) tags : %s", *placementGroupsItem.ID, err) } - accesstags, err := GetGlobalTagsUsingCRN(meta, *placementGroupsItem.CRN, "", isAccessTagType) + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroupsItem.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error getting placement group (%s) access tags: %s", *placementGroupsItem.ID, err) diff --git a/ibm/data_source_ibm_is_placement_groups_test.go b/ibm/service/vpc/data_source_ibm_is_placement_groups_test.go similarity index 91% rename from ibm/data_source_ibm_is_placement_groups_test.go rename to ibm/service/vpc/data_source_ibm_is_placement_groups_test.go index 26d88dee1..911ed7f55 100644 --- a/ibm/data_source_ibm_is_placement_groups_test.go +++ b/ibm/service/vpc/data_source_ibm_is_placement_groups_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIbmIsPlacementGroupsDataSourceAllArgs(t *testing.T) { placementGroupName := fmt.Sprintf("tf-pg-name%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmIsPlacementGroupsDataSourceConfig(placementGroupStrategy, placementGroupName), @@ -51,6 +53,9 @@ func testAccCheckIbmIsPlacementGroupsDataSourceConfig(placementGroupStrategy str } data "ibm_is_placement_groups" "is_placement_groups" { + depends_on = [ + ibm_is_placement_group.is_placement_group + ] } `, placementGroupStrategy, placementGroupName) } diff --git a/ibm/data_source_ibm_is_public_gateway.go b/ibm/service/vpc/data_source_ibm_is_public_gateway.go similarity index 81% rename from ibm/data_source_ibm_is_public_gateway.go rename to ibm/service/vpc/data_source_ibm_is_public_gateway.go index 5f511bd70..169a2c55c 100644 --- a/ibm/data_source_ibm_is_public_gateway.go +++ b/ibm/service/vpc/data_source_ibm_is_public_gateway.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISPublicGateway() *schema.Resource { +func DataSourceIBMISPublicGateway() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISPublicGatewayRead, @@ -57,17 +58,17 @@ func dataSourceIBMISPublicGateway() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "Service tags for the public gateway instance", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", @@ -79,19 +80,19 @@ func dataSourceIBMISPublicGateway() *schema.Resource { Description: "The crn of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -122,9 +123,9 @@ func dataSourceIBMISPublicGatewayRead(d *schema.ResourceData, meta interface{}) } publicgws, response, err := sess.ListPublicGateways(listPublicGatewaysOptions) if err != nil { - return fmt.Errorf("Error Fetching public gateways %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching public gateways %s\n%s", err, response) } - start = GetNext(publicgws.Next) + start = flex.GetNext(publicgws.Next) allrecs = append(allrecs, publicgws.PublicGateways...) if start == "" { break @@ -145,27 +146,27 @@ func dataSourceIBMISPublicGatewayRead(d *schema.ResourceData, meta interface{}) d.Set(isPublicGatewayStatus, *publicgw.Status) d.Set(isPublicGatewayZone, *publicgw.Zone.Name) d.Set(isPublicGatewayVPC, *publicgw.VPC.ID) - tags, err := GetTagsUsingCRN(meta, *publicgw.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *publicgw.CRN) if err != nil { log.Printf( "Error on get of vpc public gateway (%s) tags: %s", *publicgw.ID, err) } d.Set(isPublicGatewayTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/publicGateways") - d.Set(ResourceName, *publicgw.Name) - d.Set(ResourceCRN, *publicgw.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/publicGateways") + d.Set(flex.ResourceName, *publicgw.Name) + d.Set(flex.ResourceCRN, *publicgw.CRN) d.Set(isPublicGatewayCRN, *publicgw.CRN) - d.Set(ResourceStatus, *publicgw.Status) + d.Set(flex.ResourceStatus, *publicgw.Status) if publicgw.ResourceGroup != nil { d.Set(isPublicGatewayResourceGroup, *publicgw.ResourceGroup.ID) - d.Set(ResourceGroupName, *publicgw.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *publicgw.ResourceGroup.Name) } return nil } } - return fmt.Errorf("No Public gateway found with name %s", name) + return fmt.Errorf("[ERROR] No Public gateway found with name %s", name) } diff --git a/ibm/data_source_ibm_is_public_gateway_test.go b/ibm/service/vpc/data_source_ibm_is_public_gateway_test.go similarity index 89% rename from ibm/data_source_ibm_is_public_gateway_test.go rename to ibm/service/vpc/data_source_ibm_is_public_gateway_test.go index 5db4e0f61..3374f1492 100644 --- a/ibm/data_source_ibm_is_public_gateway_test.go +++ b/ibm/service/vpc/data_source_ibm_is_public_gateway_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,8 +20,8 @@ func TestAccIBMISPublicGatewayDatasource_basic(t *testing.T) { resName := "data.ibm_is_public_gateway.testacc_dspgw" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISPublicGatewayDataSourceConfig(vpcname, name1, zone), diff --git a/ibm/data_source_ibm_is_public_gateways.go b/ibm/service/vpc/data_source_ibm_is_public_gateways.go similarity index 85% rename from ibm/data_source_ibm_is_public_gateways.go rename to ibm/service/vpc/data_source_ibm_is_public_gateways.go index 387e7d476..c8bb274fe 100644 --- a/ibm/data_source_ibm_is_public_gateways.go +++ b/ibm/service/vpc/data_source_ibm_is_public_gateways.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -16,7 +17,7 @@ const ( isPublicGateways = "public_gateways" ) -func dataSourceIBMISPublicGateways() *schema.Resource { +func DataSourceIBMISPublicGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISPublicGatewaysRead, @@ -73,17 +74,17 @@ func dataSourceIBMISPublicGateways() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "Service tags for the public gateway instance", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", @@ -95,19 +96,19 @@ func dataSourceIBMISPublicGateways() *schema.Resource { Description: "The crn of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -148,9 +149,9 @@ func publicGatewaysGet(d *schema.ResourceData, meta interface{}, name string) er } publicgws, response, err := sess.ListPublicGateways(listPublicGatewaysOptions) if err != nil { - return fmt.Errorf("Error Fetching public gateways %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching public gateways %s\n%s", err, response) } - start = GetNext(publicgws.Next) + start = flex.GetNext(publicgws.Next) allrecs = append(allrecs, publicgws.PublicGateways...) if start == "" { break @@ -166,10 +167,10 @@ func publicGatewaysGet(d *schema.ResourceData, meta interface{}, name string) er isPublicGatewayZone: *publicgw.Zone.Name, isPublicGatewayVPC: *publicgw.VPC.ID, - ResourceName: *publicgw.Name, - isPublicGatewayCRN: *publicgw.CRN, - ResourceCRN: *publicgw.CRN, - ResourceStatus: *publicgw.Status, + flex.ResourceName: *publicgw.Name, + isPublicGatewayCRN: *publicgw.CRN, + flex.ResourceCRN: *publicgw.CRN, + flex.ResourceStatus: *publicgw.Status, } if publicgw.FloatingIP != nil { floatIP := map[string]interface{}{ @@ -178,20 +179,20 @@ func publicGatewaysGet(d *schema.ResourceData, meta interface{}, name string) er } l[isPublicGatewayFloatingIP] = floatIP } - tags, err := GetTagsUsingCRN(meta, *publicgw.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *publicgw.CRN) if err != nil { log.Printf( "Error on get of vpc public gateway (%s) tags: %s", *publicgw.ID, err) } l[isPublicGatewayTags] = tags - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - l[ResourceControllerURL] = controller + "/vpc-ext/network/publicGateways" + l[flex.ResourceControllerURL] = controller + "/vpc-ext/network/publicGateways" if publicgw.ResourceGroup != nil { l[isPublicGatewayResourceGroup] = *publicgw.ResourceGroup.ID - l[ResourceGroupName] = *publicgw.ResourceGroup.Name + l[flex.ResourceGroupName] = *publicgw.ResourceGroup.Name } publicgwInfo = append(publicgwInfo, l) } diff --git a/ibm/data_source_ibm_is_public_gateways_test.go b/ibm/service/vpc/data_source_ibm_is_public_gateways_test.go similarity index 90% rename from ibm/data_source_ibm_is_public_gateways_test.go rename to ibm/service/vpc/data_source_ibm_is_public_gateways_test.go index 6b1202893..ef7bbde43 100644 --- a/ibm/data_source_ibm_is_public_gateways_test.go +++ b/ibm/service/vpc/data_source_ibm_is_public_gateways_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -20,8 +22,8 @@ func TestAccIBMISPublicGatewaysDatasource_basic(t *testing.T) { resName := "data.ibm_is_public_gateways.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISPublicGatewayDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_region.go b/ibm/service/vpc/data_source_ibm_is_region.go similarity index 82% rename from ibm/data_source_ibm_is_region.go rename to ibm/service/vpc/data_source_ibm_is_region.go index f8d611773..9a7e9fc63 100644 --- a/ibm/data_source_ibm_is_region.go +++ b/ibm/service/vpc/data_source_ibm_is_region.go @@ -1,9 +1,10 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,7 +15,7 @@ const ( isRegionStatus = "status" ) -func dataSourceIBMISRegion() *schema.Resource { +func DataSourceIBMISRegion() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISRegionRead, @@ -27,7 +28,7 @@ func dataSourceIBMISRegion() *schema.Resource { isRegionName: { Type: schema.TypeString, - Required: true, + Optional: true, }, isRegionStatus: { @@ -41,6 +42,13 @@ func dataSourceIBMISRegion() *schema.Resource { func dataSourceIBMISRegionRead(d *schema.ResourceData, meta interface{}) error { name := d.Get("name").(string) + if name == "" { + bmxSess, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + name = bmxSess.Config.Region + } return regionGet(d, meta, name) } diff --git a/ibm/service/vpc/data_source_ibm_is_region_test.go b/ibm/service/vpc/data_source_ibm_is_region_test.go new file mode 100644 index 000000000..a3889ec67 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_region_test.go @@ -0,0 +1,42 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISRegionDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISRegionDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_is_region.testacc_ds_region", "name", acc.RegionName), + resource.TestCheckResourceAttr("data.ibm_is_region.testacc_default_region", "name", acc.RegionName), + ), + }, + }, + }) +} + +func testAccCheckIBMISRegionDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_is_region" "testacc_ds_region" { + name = "%s" +} +data "ibm_is_region" "testacc_default_region" { +} +`, acc.RegionName) + +} diff --git a/ibm/data_source_ibm_is_regions.go b/ibm/service/vpc/data_source_ibm_is_regions.go similarity index 96% rename from ibm/data_source_ibm_is_regions.go rename to ibm/service/vpc/data_source_ibm_is_regions.go index a600abf03..f2cf36e87 100644 --- a/ibm/data_source_ibm_is_regions.go +++ b/ibm/service/vpc/data_source_ibm_is_regions.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "time" @@ -15,7 +15,7 @@ const ( isRegionHref = "href" ) -func dataSourceIBMISRegions() *schema.Resource { +func DataSourceIBMISRegions() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISRegionsRead, Schema: map[string]*schema.Schema{ diff --git a/ibm/data_source_ibm_is_regions_test.go b/ibm/service/vpc/data_source_ibm_is_regions_test.go similarity index 85% rename from ibm/data_source_ibm_is_regions_test.go rename to ibm/service/vpc/data_source_ibm_is_regions_test.go index 318ea760b..22fbb835b 100644 --- a/ibm/data_source_ibm_is_regions_test.go +++ b/ibm/service/vpc/data_source_ibm_is_regions_test.go @@ -1,22 +1,24 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISRegionsDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISRegionsDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_is_regions.testacc_ds_regions", "regions.0.name"), diff --git a/ibm/data_source_ibm_is_security_group.go b/ibm/service/vpc/data_source_ibm_is_security_group.go similarity index 90% rename from ibm/data_source_ibm_is_security_group.go rename to ibm/service/vpc/data_source_ibm_is_security_group.go index a593dea25..5bc62ebef 100644 --- a/ibm/data_source_ibm_is_security_group.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "reflect" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -29,7 +30,7 @@ const ( isSgCRN = "crn" ) -func dataSourceIBMISSecurityGroup() *schema.Resource { +func DataSourceIBMISSecurityGroup() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISSecurityGroupRuleRead, @@ -108,25 +109,25 @@ func dataSourceIBMISSecurityGroup() *schema.Resource { }, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -136,7 +137,7 @@ func dataSourceIBMISSecurityGroup() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, @@ -176,12 +177,12 @@ func securityGroupGet(d *schema.ResourceData, meta interface{}, name string) err } sgs, response, err := sess.ListSecurityGroups(listSgOptions) if err != nil || sgs == nil { - return fmt.Errorf("Error Getting Security Groups %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Security Groups %s\n%s", err, response) } if *sgs.TotalCount == int64(0) { break } - start = GetNext(sgs.Next) + start = flex.GetNext(sgs.Next) allrecs = append(allrecs, sgs.SecurityGroups...) if start == "" { @@ -196,7 +197,7 @@ func securityGroupGet(d *schema.ResourceData, meta interface{}, name string) err d.Set(isSgName, *group.Name) d.Set(isSgVPC, *group.VPC.ID) d.Set(isSgCRN, *group.CRN) - tags, err := GetTagsUsingCRN(meta, *group.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *group.CRN) if err != nil { log.Printf( "An error occured during reading of security group (%s) tags : %s", *group.ID, err) @@ -298,25 +299,25 @@ func securityGroupGet(d *schema.ResourceData, meta interface{}, name string) err if group.ResourceGroup != nil { if group.ResourceGroup.Name != nil { - d.Set(ResourceGroupName, *group.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *group.ResourceGroup.Name) } } - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc/network/securityGroups") + d.Set(flex.ResourceControllerURL, controller+"/vpc/network/securityGroups") if group.Name != nil { - d.Set(ResourceName, *group.Name) + d.Set(flex.ResourceName, *group.Name) } if group.CRN != nil { - d.Set(ResourceCRN, *group.CRN) + d.Set(flex.ResourceCRN, *group.CRN) } return nil } } - return fmt.Errorf("No Security Group found with name %s", name) + return fmt.Errorf("[ERROR] No Security Group found with name %s", name) } diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_rule.go b/ibm/service/vpc/data_source_ibm_is_security_group_rule.go new file mode 100644 index 000000000..39134bc68 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_group_rule.go @@ -0,0 +1,300 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIsSecurityGroupRule() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSecurityGroupRuleRead, + + Schema: map[string]*schema.Schema{ + "security_group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The security group identifier.", + }, + "security_group_rule": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The rule identifier.", + }, + "direction": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The direction of traffic to enforce, either `inbound` or `outbound`.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this security group rule.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol to enforce.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "cidr_block": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic code to allow.", + }, + "type": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic type to allow.", + }, + "port_max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive upper bound of TCP/UDP port range.", + }, + "port_min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive lower bound of TCP/UDP port range.", + }, + }, + } +} + +func dataSourceIBMIsSecurityGroupRuleRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + getSecurityGroupRuleOptions := &vpcv1.GetSecurityGroupRuleOptions{} + + getSecurityGroupRuleOptions.SetSecurityGroupID(d.Get("security_group").(string)) + getSecurityGroupRuleOptions.SetID(d.Get("security_group_rule").(string)) + + securityGroupRuleIntf, response, err := vpcClient.GetSecurityGroupRuleWithContext(context, getSecurityGroupRuleOptions) + if err != nil || securityGroupRuleIntf == nil { + log.Printf("[DEBUG] GetSecurityGroupRuleWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSecurityGroupRuleWithContext failed %s\n%s", err, response)) + } + + switch reflect.TypeOf(securityGroupRuleIntf).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + securityGroupRule := securityGroupRuleIntf.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + + d.SetId(*securityGroupRule.ID) + if err = d.Set("direction", securityGroupRule.Direction); err != nil { + return diag.FromErr(fmt.Errorf("Error setting direction: %s", err)) + } + if err = d.Set("href", securityGroupRule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("ip_version", securityGroupRule.IPVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ip_version: %s", err)) + } + if err = d.Set("protocol", securityGroupRule.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting protocol: %s", err)) + } + if securityGroupRule.Remote != nil { + securityGroupRuleRemote, err := dataSourceSecurityGroupRuleFlattenRemote(securityGroupRule.Remote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error flattening securityGroupRule.Remote %s", err)) + } + err = d.Set("remote", securityGroupRuleRemote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting remote %s", err)) + } + } + + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + securityGroupRule := securityGroupRuleIntf.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + + d.SetId(*securityGroupRule.ID) + if err = d.Set("direction", securityGroupRule.Direction); err != nil { + return diag.FromErr(fmt.Errorf("Error setting direction: %s", err)) + } + if err = d.Set("href", securityGroupRule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("ip_version", securityGroupRule.IPVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ip_version: %s", err)) + } + if err = d.Set("protocol", securityGroupRule.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting protocol: %s", err)) + } + if securityGroupRule.Remote != nil { + securityGroupRuleRemote, err := dataSourceSecurityGroupRuleFlattenRemote(securityGroupRule.Remote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error flattening securityGroupRule.Remote %s", err)) + } + err = d.Set("remote", securityGroupRuleRemote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting remote %s", err)) + } + } + + if err = d.Set("code", flex.IntValue(securityGroupRule.Code)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting code: %s", err)) + } + if err = d.Set("type", flex.IntValue(securityGroupRule.Type)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + securityGroupRule := securityGroupRuleIntf.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + + d.SetId(*securityGroupRule.ID) + if err = d.Set("direction", securityGroupRule.Direction); err != nil { + return diag.FromErr(fmt.Errorf("Error setting direction: %s", err)) + } + if err = d.Set("href", securityGroupRule.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("ip_version", securityGroupRule.IPVersion); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ip_version: %s", err)) + } + if err = d.Set("protocol", securityGroupRule.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting protocol: %s", err)) + } + if securityGroupRule.Remote != nil { + securityGroupRuleRemote, err := dataSourceSecurityGroupRuleFlattenRemote(securityGroupRule.Remote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error flattening securityGroupRule.Remote %s", err)) + } + err = d.Set("remote", securityGroupRuleRemote) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting remote %s", err)) + } + } + if err = d.Set("port_max", flex.IntValue(securityGroupRule.PortMax)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port_max: %s", err)) + } + if err = d.Set("port_min", flex.IntValue(securityGroupRule.PortMin)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port_min: %s", err)) + } + } + } + + return nil +} + +func dataSourceSecurityGroupRuleFlattenRemote(m vpcv1.SecurityGroupRuleRemoteIntf) ([]map[string]interface{}, error) { + var ruleList []map[string]interface{} + ruleMap := dataSourceSecurityGroupRuleRemoteToMap(m.(*vpcv1.SecurityGroupRuleRemote)) + ruleList = append(ruleList, ruleMap) + return ruleList, nil +} + +func dataSourceSecurityGroupRuleRemoteToMap(remoteItem *vpcv1.SecurityGroupRuleRemote) (remoteMap map[string]interface{}) { + remoteMap = map[string]interface{}{} + + if remoteItem.Address != nil { + remoteMap["address"] = *remoteItem.Address + } + + if remoteItem.CIDRBlock != nil { + remoteMap["cidr_block"] = *remoteItem.CIDRBlock + } + if remoteItem.CRN != nil { + remoteMap["crn"] = *remoteItem.CRN + } + if remoteItem.Deleted != nil { + remoteDeletedList := []map[string]interface{}{} + remoteDeletedMap := dataSourceSecurityGroupRuleRemoteDeletedToMap(remoteItem.Deleted) + remoteDeletedList = append(remoteDeletedList, remoteDeletedMap) + remoteMap["deleted"] = remoteDeletedList + } + + if remoteItem.Href != nil { + remoteMap["href"] = *remoteItem.Href + } + if remoteItem.ID != nil { + remoteMap["id"] = *remoteItem.ID + } + if remoteItem.Name != nil { + remoteMap["name"] = *remoteItem.Name + } + + return remoteMap +} + +func dataSourceSecurityGroupRuleRemoteDeletedToMap(deletedItem *vpcv1.SecurityGroupReferenceDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = deletedItem.MoreInfo + } + + return resultMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_rule_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_rule_test.go new file mode 100644 index 000000000..556133c76 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_group_rule_test.go @@ -0,0 +1,70 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsSecurityGroupRuleDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfsecgrprl-vpc-%d", acctest.RandIntRange(10, 100)) + sgname := fmt.Sprintf("tfsecgrprl-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSecurityGroupRuleDataSourceConfigBasic(vpcname, sgname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "security_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "direction"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "ip_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rule.example", "remote.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSecurityGroupRuleDataSourceConfigBasic(vpcname, sgname string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "example" { + name = "%s" + } + + resource "ibm_is_security_group" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + } + + resource "ibm_is_security_group_rule" "example" { + depends_on = [ + ibm_is_security_group.example, + ] + group = ibm_is_security_group.example.id + direction = "inbound" + remote = "127.0.0.1" + udp { + port_min = 805 + port_max = 807 + } + } + + data "ibm_is_security_group_rule" "example" { + depends_on = [ + ibm_is_security_group_rule.example, + ] + security_group_rule = ibm_is_security_group_rule.example.rule_id + security_group = ibm_is_security_group.example.id + } + `, vpcname, sgname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_rules.go b/ibm/service/vpc/data_source_ibm_is_security_group_rules.go new file mode 100644 index 000000000..fb1eb1f90 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_group_rules.go @@ -0,0 +1,230 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "reflect" + "time" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIsSecurityGroupRules() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMIsSecurityGroupRulesRead, + + Schema: map[string]*schema.Schema{ + "security_group": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The security group identifier.", + }, + "rules": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Array of rules.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "direction": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The direction of traffic to enforce, either `inbound` or `outbound`.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this security group rule.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group rule.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol to enforce.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "cidr_block": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic code to allow.", + }, + "type": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic type to allow.", + }, + "port_max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive upper bound of TCP/UDP port range.", + }, + "port_min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive lower bound of TCP/UDP port range.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsSecurityGroupRulesRead(d *schema.ResourceData, meta interface{}) error { + secGrpId := d.Get("security_group").(string) + sess, err := vpcClient(meta) + if err != nil { + return err + } + + listSecurityGroupRuleOptions := vpcv1.ListSecurityGroupRulesOptions{ + SecurityGroupID: &secGrpId, + } + + ruleList, response, err := sess.ListSecurityGroupRules(&listSecurityGroupRuleOptions) + if err != nil { + return fmt.Errorf("Error fetching security group rules %s\n%s", err, response) + } + + rulesInfo := make([]map[string]interface{}, 0) + for _, rule := range ruleList.Rules { + l := map[string]interface{}{} + switch reflect.TypeOf(rule).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + rulex := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + l["direction"] = *rulex.Direction + l["href"] = *rulex.Href + l["id"] = *rulex.ID + l["ip_version"] = *rulex.IPVersion + l["protocol"] = *rulex.Protocol + // nested map for remote. + if rulex.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupRuleRemoteToMap(rulex.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + l["remote"] = remoteList + } + + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + rulex := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + l["direction"] = *rulex.Direction + l["href"] = *rulex.Href + l["id"] = *rulex.ID + l["ip_version"] = *rulex.IPVersion + l["code"] = *rulex.Code + l["protocol"] = *rulex.Protocol + l["type"] = *rulex.Type + // remote + if rulex.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupRuleRemoteToMap(rulex.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + l["remote"] = remoteList + } + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + rulex := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + l["direction"] = *rulex.Direction + l["href"] = *rulex.Href + l["id"] = *rulex.ID + l["ip_version"] = *rulex.IPVersion + l["protocol"] = *rulex.Protocol + l["port_max"] = *rulex.PortMax + l["port_min"] = *rulex.PortMin + // remote + if rulex.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupRuleRemoteToMap(rulex.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + l["remote"] = remoteList + } + } + } + rulesInfo = append(rulesInfo, l) + } + d.SetId(dataSourceIBMIsSecurityGroupRulesID(d)) + d.Set("rules", rulesInfo) + return nil +} + +// dataSourceIBMIsSecurityGroupRulesID returns a reasonable ID for the list. +func dataSourceIBMIsSecurityGroupRulesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceSecurityGroupRuleCollectionRemoteDeletedToMap(deletedItem *vpcv1.SecurityGroupReferenceDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = *deletedItem.MoreInfo + } + + return resultMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_rules_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_rules_test.go new file mode 100644 index 000000000..e2dc4fe2c --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_group_rules_test.go @@ -0,0 +1,72 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsSecurityGroupRulesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfsubnet-vpc-%d", acctest.RandIntRange(10, 100)) + sgname := fmt.Sprintf("tfsubnet-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSecurityGroupRulesDataSourceConfigBasic(vpcname, sgname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "security_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.0.direction"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.0.ip_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.0.protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_group_rules.example", "rules.0.remote.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSecurityGroupRulesDataSourceConfigBasic(vpcname, sgname string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "example" { + name = "%s" + } + + resource "ibm_is_security_group" "example" { + name = "%s" + vpc = ibm_is_vpc.example.id + depends_on = [ + ibm_is_vpc.example, + ] + } + + resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id + direction = "outbound" + remote = "127.0.0.1" + tcp { + port_min = 8080 + port_max = 8080 + } + depends_on = [ + ibm_is_security_group.example, + ] + } + data "ibm_is_security_group_rules" "example" { + depends_on = [ + ibm_is_security_group_rule.example, + ] + security_group = ibm_is_security_group.example.id + } + `, vpcname, sgname) +} diff --git a/ibm/data_source_ibm_is_security_group_target.go b/ibm/service/vpc/data_source_ibm_is_security_group_target.go similarity index 91% rename from ibm/data_source_ibm_is_security_group_target.go rename to ibm/service/vpc/data_source_ibm_is_security_group_target.go index 2d29ec993..9c312e3c3 100644 --- a/ibm/data_source_ibm_is_security_group_target.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group_target.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISSecurityGroupTarget() *schema.Resource { +func DataSourceIBMISSecurityGroupTarget() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISSecurityGroupTargetRead, @@ -77,13 +78,13 @@ func dataSourceIBMISSecurityGroupTargetRead(d *schema.ResourceData, meta interfa } groups, response, err := sess.ListSecurityGroupTargets(listSecurityGroupTargetsOptions) if err != nil { - return fmt.Errorf("Error Getting InstanceGroup Managers %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Managers %s\n%s", err, response) } if *groups.TotalCount == int64(0) { break } - start = GetNext(groups.Next) + start = flex.GetNext(groups.Next) allrecs = append(allrecs, groups.Targets...) if start == "" { diff --git a/ibm/data_source_ibm_is_security_group_targets.go b/ibm/service/vpc/data_source_ibm_is_security_group_targets.go similarity index 92% rename from ibm/data_source_ibm_is_security_group_targets.go rename to ibm/service/vpc/data_source_ibm_is_security_group_targets.go index 20e56775a..df852cdfd 100644 --- a/ibm/data_source_ibm_is_security_group_targets.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group_targets.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISSecurityGroupTargets() *schema.Resource { +func DataSourceIBMISSecurityGroupTargets() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISSecurityGroupTargetsRead, @@ -86,13 +87,13 @@ func dataSourceIBMISSecurityGroupTargetsRead(d *schema.ResourceData, meta interf } groups, response, err := sess.ListSecurityGroupTargets(listSecurityGroupTargetsOptions) if err != nil || groups == nil { - return fmt.Errorf("Error Getting InstanceGroup Managers %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Managers %s\n%s", err, response) } if *groups.TotalCount == int64(0) { break } - start = GetNext(groups.Next) + start = flex.GetNext(groups.Next) allrecs = append(allrecs, groups.Targets...) if start == "" { diff --git a/ibm/data_source_ibm_is_security_group_targets_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go similarity index 84% rename from ibm/data_source_ibm_is_security_group_targets_test.go rename to ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go index 362ee4eb1..693e5e9ba 100644 --- a/ibm/data_source_ibm_is_security_group_targets_test.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,12 +26,12 @@ func TestAccIBMISSecurityGroupTargets_basic(t *testing.T) { name := fmt.Sprintf("tfsg-one-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSecurityGroupTargetsDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISsecurityGroupTargetsConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, name), + Config: testAccCheckIBMISsecurityGroupTargetsConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSecurityGroupTargetsExists("ibm_is_security_group_target.testacc_security_group_target", &securityGroup), // resource.TestCheckResourceAttr( @@ -42,7 +46,7 @@ func TestAccIBMISSecurityGroupTargets_basic(t *testing.T) { func testAccCheckIBMISSecurityGroupTargetsDestroy(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -50,7 +54,7 @@ func testAccCheckIBMISSecurityGroupTargetsDestroy(s *terraform.State) error { if rs.Type != "ibm_is_security_group_target" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -78,15 +82,15 @@ func testAccCheckIBMISSecurityGroupTargetsExists(n string, securityGroupID *stri return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Security Group Target ID is set") + return fmt.Errorf("[ERROR] No Security Group Target ID is set") } - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -104,7 +108,7 @@ func testAccCheckIBMISSecurityGroupTargetsExists(n string, securityGroupID *stri *securityGroupID = "" return nil } - return fmt.Errorf("Error getting Security Group Target : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) } *securityGroupID = fmt.Sprintf("%s/%s", securityGroupId, targetID) diff --git a/ibm/data_source_ibm_is_security_group_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_test.go similarity index 94% rename from ibm/data_source_ibm_is_security_group_test.go rename to ibm/service/vpc/data_source_ibm_is_security_group_test.go index 73759784c..4ada572d5 100644 --- a/ibm/data_source_ibm_is_security_group_test.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,11 +19,11 @@ func TestAccIBMISSecurityGroupDatasource_basic(t *testing.T) { dataSourceName := "data.ibm_is_security_group.sg1_rule" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSecurityGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISSgRuleConfig(vpcname, sgname), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(dataSourceName, "vpc"), diff --git a/ibm/service/vpc/data_source_ibm_is_security_groups.go b/ibm/service/vpc/data_source_ibm_is_security_groups.go new file mode 100644 index 000000000..cb9bcb6bb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_groups.go @@ -0,0 +1,691 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMIsSecurityGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSecurityGroupsRead, + + Schema: map[string]*schema.Schema{ + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "resource group identifier.", + }, + "vpc_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "vpc identifier.", + }, + "vpc_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "vpc crn", + }, + "vpc_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "vpc name.", + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of security groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this security group was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "rules": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The rules for this security group. If no rules exist, all traffic will be denied.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "direction": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The direction of traffic to enforce, either `inbound` or `outbound`.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this security group rule.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group rule.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The protocol to enforce.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "cidr_block": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic code to allow.", + }, + "type": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The ICMP traffic type to allow.", + }, + "port_max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive upper bound of TCP/UDP port range.", + }, + "port_min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The inclusive lower bound of TCP/UDP port range.", + }, + }, + }, + }, + "targets": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The targets for this security group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The load balancer's CRN.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this security group is a part of.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsSecurityGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + resourceGrp := d.Get("resource_group").(string) + vpcId := d.Get("vpc_id").(string) + vpcCrn := d.Get("vpc_crn").(string) + vpcName := d.Get("vpc_name").(string) + + start := "" + allrecs := []vpcv1.SecurityGroup{} + listSecurityGroupsOptions := &vpcv1.ListSecurityGroupsOptions{} + if resourceGrp != "" { + listSecurityGroupsOptions.ResourceGroupID = &resourceGrp + } + if vpcId != "" { + listSecurityGroupsOptions.VPCID = &vpcId + } + if vpcCrn != "" { + listSecurityGroupsOptions.VPCCRN = &vpcCrn + } + if vpcName != "" { + listSecurityGroupsOptions.VPCName = &vpcName + } + for { + + if start != "" { + listSecurityGroupsOptions.Start = &start + } + securityGroupCollection, response, err := vpcClient.ListSecurityGroupsWithContext(context, listSecurityGroupsOptions) + if err != nil { + log.Printf("[DEBUG] ListSecurityGroupsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListSecurityGroupsWithContext failed %s\n%s", err, response)) + } + + start = flex.GetNext(securityGroupCollection.Next) + allrecs = append(allrecs, securityGroupCollection.SecurityGroups...) + + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsSecurityGroupsID(d)) + err = d.Set("security_groups", dataSourceSecurityGroupCollectionFlattenSecurityGroups(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting security_groups %s", err)) + } + return nil +} + +// dataSourceIBMIsSecurityGroupsID returns a reasonable ID for the list. +func dataSourceIBMIsSecurityGroupsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceSecurityGroupCollectionFlattenSecurityGroups(modelSlice []vpcv1.SecurityGroup) (result []map[string]interface{}) { + result = []map[string]interface{}{} + for _, securityGroupsItem := range modelSlice { + mapItem := dataSourceSecurityGroupCollectionSecurityGroupsToMap(&securityGroupsItem) + result = append(result, mapItem) + } + return result +} + +func dataSourceSecurityGroupCollectionSecurityGroupsToMap(securityGroupsItem *vpcv1.SecurityGroup) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if securityGroupsItem.CreatedAt != nil { + resultMap["created_at"] = securityGroupsItem.CreatedAt.String() + } + if securityGroupsItem.CRN != nil { + resultMap["crn"] = securityGroupsItem.CRN + } + if securityGroupsItem.Href != nil { + resultMap["href"] = securityGroupsItem.Href + } + if securityGroupsItem.ID != nil { + resultMap["id"] = securityGroupsItem.ID + } + if securityGroupsItem.Name != nil { + resultMap["name"] = securityGroupsItem.Name + } + if securityGroupsItem.ResourceGroup != nil { + var mapSlice []map[string]interface{} + modelMap := dataSourceSecurityGroupCollectionSecurityGroupsResourceGroupToMap(securityGroupsItem.ResourceGroup) + mapSlice = append(mapSlice, modelMap) + resultMap["resource_group"] = mapSlice + } + if securityGroupsItem.Rules != nil { + var mapSlice []map[string]interface{} + for _, listElem := range securityGroupsItem.Rules { + mapElem := dataSourceSecurityGroupCollectionSecurityGroupsRulesToMap(listElem) + mapSlice = append(mapSlice, mapElem) + } + resultMap["rules"] = mapSlice + } + if securityGroupsItem.Targets != nil { + var mapSlice []map[string]interface{} + for _, listElem := range securityGroupsItem.Targets { + mapElem := dataSourceSecurityGroupCollectionSecurityGroupsTargetsToMap(listElem) + mapSlice = append(mapSlice, mapElem) + } + resultMap["targets"] = mapSlice + } + if securityGroupsItem.VPC != nil { + var mapSlice []map[string]interface{} + modelMap := dataSourceSecurityGroupCollectionSecurityGroupsVPCToMap(securityGroupsItem.VPC) + mapSlice = append(mapSlice, modelMap) + resultMap["vpc"] = mapSlice + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionSecurityGroupsResourceGroupToMap(resourceGroupItem *vpcv1.ResourceGroupReference) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resultMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resultMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resultMap["name"] = resourceGroupItem.Name + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionSecurityGroupsRulesToMap(rulesItem vpcv1.SecurityGroupRuleIntf) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + switch reflect.TypeOf(rulesItem).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + securityGroupRule := rulesItem.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + if securityGroupRule.ID != nil { + resultMap["id"] = securityGroupRule.ID + } + if securityGroupRule.Direction != nil { + resultMap["direction"] = securityGroupRule.Direction + } + if securityGroupRule.Href != nil { + resultMap["href"] = securityGroupRule.Href + } + if securityGroupRule.IPVersion != nil { + resultMap["ip_version"] = securityGroupRule.IPVersion + } + if securityGroupRule.Protocol != nil { + resultMap["protocol"] = securityGroupRule.Protocol + } + if securityGroupRule.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupsRemoteToMap(*securityGroupRule.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + resultMap["remote"] = remoteList + } + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + securityGroupRule := rulesItem.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + if securityGroupRule.ID != nil { + resultMap["id"] = securityGroupRule.ID + } + if securityGroupRule.Direction != nil { + resultMap["direction"] = securityGroupRule.Direction + } + if securityGroupRule.Href != nil { + resultMap["href"] = securityGroupRule.Href + } + if securityGroupRule.IPVersion != nil { + resultMap["ip_version"] = securityGroupRule.IPVersion + } + if securityGroupRule.Protocol != nil { + resultMap["protocol"] = securityGroupRule.Protocol + } + if securityGroupRule.Href != nil { + resultMap["href"] = securityGroupRule.Href + } + if securityGroupRule.Code != nil { + resultMap["code"] = securityGroupRule.Code + } + if securityGroupRule.Type != nil { + resultMap["type"] = securityGroupRule.Type + } + + if securityGroupRule.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupsRemoteToMap(*securityGroupRule.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + resultMap["remote"] = remoteList + } + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + securityGroupRule := rulesItem.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + if securityGroupRule.ID != nil { + resultMap["id"] = securityGroupRule.ID + } + if securityGroupRule.Direction != nil { + resultMap["direction"] = securityGroupRule.Direction + } + if securityGroupRule.Href != nil { + resultMap["href"] = securityGroupRule.Href + } + if securityGroupRule.IPVersion != nil { + resultMap["ip_version"] = securityGroupRule.IPVersion + } + if securityGroupRule.Protocol != nil { + resultMap["protocol"] = securityGroupRule.Protocol + } + if securityGroupRule.Href != nil { + resultMap["href"] = securityGroupRule.Href + } + if securityGroupRule.PortMax != nil { + resultMap["port_max"] = securityGroupRule.PortMax + } + if securityGroupRule.PortMin != nil { + resultMap["port_min"] = securityGroupRule.PortMin + } + + if securityGroupRule.Remote != nil { + remoteList := []map[string]interface{}{} + remoteMap := dataSourceSecurityGroupsRemoteToMap(*securityGroupRule.Remote.(*vpcv1.SecurityGroupRuleRemote)) + remoteList = append(remoteList, remoteMap) + resultMap["remote"] = remoteList + } + } + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionRemoteDeletedToMap(deletedItem *vpcv1.SecurityGroupReferenceDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = deletedItem.MoreInfo + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionSecurityGroupsTargetsToMap(targetsItem vpcv1.SecurityGroupTargetReferenceIntf) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + // SecurityGroupTargetReference + switch reflect.TypeOf(targetsItem).String() { + case "*vpcv1.SecurityGroupTargetReference": + { + targetx := targetsItem.(*vpcv1.SecurityGroupTargetReference) + if targetx.Deleted != nil { + targetxDeletedList := []map[string]interface{}{} + targetxDeletedMap := dataSourceSecurityGroupCollectionTargetsDeletedToMap(targetx.Deleted) + targetxDeletedList = append(targetxDeletedList, targetxDeletedMap) + resultMap["deleted"] = targetxDeletedList + } + if targetx.Href != nil { + resultMap["href"] = *targetx.Href + } + if targetx.ID != nil { + resultMap["id"] = *targetx.ID + } + if targetx.Name != nil { + resultMap["name"] = *targetx.Name + } + if targetx.ResourceType != nil { + resultMap["resource_type"] = *targetx.ResourceType + } + + } + case "*vpcv1.SecurityGroupTargetReferenceLoadBalancerReference": + { + targety := targetsItem.(*vpcv1.SecurityGroupTargetReferenceLoadBalancerReference) + if targety.CRN != nil { + resultMap["crn"] = *targety.CRN + } + if targety.Deleted != nil { + targetyDeletedList := []map[string]interface{}{} + targetyDeletedMap := dataSourceSecurityGroupCollectionTargetsDeleted2ToMap(targety.Deleted) + targetyDeletedList = append(targetyDeletedList, targetyDeletedMap) + resultMap["deleted"] = targetyDeletedList + } + if targety.Href != nil { + resultMap["href"] = *targety.Href + } + if targety.ID != nil { + resultMap["id"] = *targety.ID + } + if targety.Name != nil { + resultMap["name"] = *targety.Name + } + } + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionTargetsDeletedToMap(deletedItem *vpcv1.NetworkInterfaceReferenceTargetContextDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = deletedItem.MoreInfo + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionTargetsDeleted2ToMap(deletedItem *vpcv1.LoadBalancerReferenceDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = deletedItem.MoreInfo + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionSecurityGroupsVPCToMap(vpcItem *vpcv1.VPCReference) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + resultMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + var mapSlice []map[string]interface{} + modelMap := dataSourceSecurityGroupCollectionVPCDeletedToMap(vpcItem.Deleted) + mapSlice = append(mapSlice, modelMap) + resultMap["deleted"] = mapSlice + } + if vpcItem.Href != nil { + resultMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + resultMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + resultMap["name"] = vpcItem.Name + } + + return resultMap +} + +func dataSourceSecurityGroupCollectionVPCDeletedToMap(deletedItem *vpcv1.VPCReferenceDeleted) (resultMap map[string]interface{}) { + resultMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + resultMap["more_info"] = deletedItem.MoreInfo + } + + return resultMap +} + +func dataSourceSecurityGroupsRemoteToMap(remoteItem vpcv1.SecurityGroupRuleRemote) (remoteMap map[string]interface{}) { + remoteMap = map[string]interface{}{} + + if remoteItem.Address != nil { + remoteMap["address"] = *remoteItem.Address + } + + if remoteItem.CIDRBlock != nil { + remoteMap["cidr_block"] = *remoteItem.CIDRBlock + } + if remoteItem.CRN != nil { + remoteMap["crn"] = *remoteItem.CRN + } + if remoteItem.Deleted != nil { + remoteDeletedList := []map[string]interface{}{} + remoteDeletedMap := dataSourceSecurityGroupRuleCollectionRemoteDeletedToMap(remoteItem.Deleted) + remoteDeletedList = append(remoteDeletedList, remoteDeletedMap) + remoteMap["deleted"] = remoteDeletedList + } + + if remoteItem.Href != nil { + remoteMap["href"] = *remoteItem.Href + } + if remoteItem.ID != nil { + remoteMap["id"] = *remoteItem.ID + } + if remoteItem.Name != nil { + remoteMap["name"] = *remoteItem.Name + } + return remoteMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_groups_test.go b/ibm/service/vpc/data_source_ibm_is_security_groups_test.go new file mode 100644 index 000000000..3732ec0bf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_groups_test.go @@ -0,0 +1,42 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsSecurityGroupsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSecurityGroupsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.rules.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.targets.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_security_groups.example", "security_groups.0.vpc.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSecurityGroupsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_security_groups" "example" { + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot.go b/ibm/service/vpc/data_source_ibm_is_snapshot.go new file mode 100644 index 000000000..ebf9a0088 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot.go @@ -0,0 +1,324 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceSnapshot() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISSnapshotRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{isSnapshotName, "identifier"}, + Description: "Snapshot identifier", + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_snapshot", "identifier"), + }, + + isSnapshotName: { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{isSnapshotName, "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_snapshot", isSnapshotName), + Description: "Snapshot name", + }, + + isSnapshotResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Resource group info", + }, + + isSnapshotSourceVolume: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot source volume id", + }, + isSnapshotSourceImage: { + Type: schema.TypeString, + Computed: true, + Description: "If present, the image id from which the data on this volume was most directly provisioned.", + }, + + isSnapshotOperatingSystem: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the operating system included in this image", + }, + + isSnapshotBootable: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + }, + + isSnapshotLCState: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot lifecycle state", + }, + isSnapshotCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + isSnapshotEncryption: { + Type: schema.TypeString, + Computed: true, + Description: "Encryption type of the snapshot", + }, + isSnapshotHref: { + Type: schema.TypeString, + Computed: true, + Description: "URL for the snapshot", + }, + + isSnapshotMinCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum capacity of the snapshot", + }, + isSnapshotResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type of the snapshot", + }, + + isSnapshotSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the snapshot", + }, + + isSnapshotCapturedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this snapshot was created", + }, + + isSnapshotUserTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "User Tags for the snapshot", + }, + + isSnapshotBackupPolicyPlan: { + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMISSnapshotValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "identifier", + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSnapshotName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + ibmISSnapshotDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_snapshot", Schema: validateSchema} + return &ibmISSnapshotDataSourceValidator +} + +func dataSourceIBMISSnapshotRead(d *schema.ResourceData, meta interface{}) error { + name := d.Get(isSnapshotName).(string) + id := d.Get("identifier").(string) + err := snapshotGetByNameOrID(d, meta, name, id) + if err != nil { + return err + } + return nil +} + +func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + if name != "" { + start := "" + allrecs := []vpcv1.Snapshot{} + for { + listSnapshotOptions := &vpcv1.ListSnapshotsOptions{ + Name: &name, + } + if start != "" { + listSnapshotOptions.Start = &start + } + snapshots, response, err := sess.ListSnapshots(listSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching snapshots %s\n%s", err, response) + } + start = flex.GetNext(snapshots.Next) + allrecs = append(allrecs, snapshots.Snapshots...) + if start == "" { + break + } + } + + for _, snapshot := range allrecs { + if *snapshot.Name == name || *snapshot.ID == id { + d.SetId(*snapshot.ID) + d.Set(isSnapshotName, *snapshot.Name) + d.Set(isSnapshotHref, *snapshot.Href) + d.Set(isSnapshotCRN, *snapshot.CRN) + d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) + d.Set(isSnapshotSize, *snapshot.Size) + d.Set(isSnapshotEncryption, *snapshot.Encryption) + d.Set(isSnapshotLCState, *snapshot.LifecycleState) + d.Set(isSnapshotResourceType, *snapshot.ResourceType) + d.Set(isSnapshotBootable, *snapshot.Bootable) + if snapshot.UserTags != nil { + if err = d.Set(isSnapshotUserTags, snapshot.UserTags); err != nil { + return fmt.Errorf("Error setting user tags: %s", err) + } + } + if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { + d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) + } + if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { + d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) + } + if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { + d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) + } + if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { + d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) + } + backupPolicyPlanList := []map[string]interface{}{} + if snapshot.BackupPolicyPlan != nil { + backupPolicyPlan := map[string]interface{}{} + if snapshot.BackupPolicyPlan.Deleted != nil { + snapshotBackupPolicyPlanDeletedMap := map[string]interface{}{} + snapshotBackupPolicyPlanDeletedMap["more_info"] = snapshot.BackupPolicyPlan.Deleted.MoreInfo + backupPolicyPlan["deleted"] = []map[string]interface{}{snapshotBackupPolicyPlanDeletedMap} + } + backupPolicyPlan["href"] = snapshot.BackupPolicyPlan.Href + backupPolicyPlan["id"] = snapshot.BackupPolicyPlan.ID + backupPolicyPlan["name"] = snapshot.BackupPolicyPlan.Name + backupPolicyPlan["resource_type"] = snapshot.BackupPolicyPlan.ResourceType + backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) + } + d.Set(isSnapshotBackupPolicyPlan, backupPolicyPlanList) + return nil + } + } + return fmt.Errorf("[ERROR] No snapshot found with name %s", name) + } else { + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching snapshot %s\n%s", err, response) + } + if (response != nil && response.StatusCode == 404) || snapshot == nil { + return fmt.Errorf("[ERROR] No snapshot found with id %s", id) + } + d.SetId(*snapshot.ID) + d.Set(isSnapshotName, *snapshot.Name) + d.Set(isSnapshotHref, *snapshot.Href) + d.Set(isSnapshotCRN, *snapshot.CRN) + d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) + d.Set(isSnapshotSize, *snapshot.Size) + d.Set(isSnapshotEncryption, *snapshot.Encryption) + d.Set(isSnapshotLCState, *snapshot.LifecycleState) + d.Set(isSnapshotResourceType, *snapshot.ResourceType) + d.Set(isSnapshotBootable, *snapshot.Bootable) + if snapshot.CapturedAt != nil { + d.Set(isSnapshotCapturedAt, (*snapshot.CapturedAt).String()) + } + if snapshot.UserTags != nil { + if err = d.Set(isSnapshotUserTags, snapshot.UserTags); err != nil { + return fmt.Errorf("Error setting user tags: %s", err) + } + } + if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { + d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) + } + if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { + d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) + } + if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { + d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) + } + if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { + d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) + } + backupPolicyPlanList := []map[string]interface{}{} + if snapshot.BackupPolicyPlan != nil { + backupPolicyPlan := map[string]interface{}{} + if snapshot.BackupPolicyPlan.Deleted != nil { + snapshotBackupPolicyPlanDeletedMap := map[string]interface{}{} + snapshotBackupPolicyPlanDeletedMap["more_info"] = snapshot.BackupPolicyPlan.Deleted.MoreInfo + backupPolicyPlan["deleted"] = []map[string]interface{}{snapshotBackupPolicyPlanDeletedMap} + } + backupPolicyPlan["href"] = snapshot.BackupPolicyPlan.Href + backupPolicyPlan["id"] = snapshot.BackupPolicyPlan.ID + backupPolicyPlan["name"] = snapshot.BackupPolicyPlan.Name + backupPolicyPlan["resource_type"] = snapshot.BackupPolicyPlan.ResourceType + backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) + } + d.Set(isSnapshotBackupPolicyPlan, backupPolicyPlanList) + return nil + } +} diff --git a/ibm/data_source_ibm_is_snapshot_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go similarity index 85% rename from ibm/data_source_ibm_is_snapshot_test.go rename to ibm/service/vpc/data_source_ibm_is_snapshot_test.go index d76fd5e66..aedb6506a 100644 --- a/ibm/data_source_ibm_is_snapshot_test.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSnapshotDestroy, Steps: []resource.TestStep{ { @@ -35,11 +37,12 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), resource.TestCheckResourceAttr( "ibm_is_snapshot.testacc_snapshot", "name", name1), - resource.TestCheckResourceAttrSet(snpName, "delatable"), + // resource.TestCheckResourceAttrSet(snpName, "delatable"), // commented as it is deprecated resource.TestCheckResourceAttrSet(snpName, "href"), resource.TestCheckResourceAttrSet(snpName, "crn"), resource.TestCheckResourceAttrSet(snpName, "lifecycle_state"), resource.TestCheckResourceAttrSet(snpName, "encryption"), + // resource.TestCheckResourceAttrSet(snpName, "captured_at"), // Commented as the attribute is optional. ), }, }, @@ -87,5 +90,5 @@ func testDSCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, vol depends_on = [ibm_is_snapshot.testacc_snapshot] name = "%s" } -`, vpcname, subnetname, ISZoneName, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, sname, sname) +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname, sname) } diff --git a/ibm/service/vpc/data_source_ibm_is_snapshots.go b/ibm/service/vpc/data_source_ibm_is_snapshots.go new file mode 100644 index 000000000..60c596363 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshots.go @@ -0,0 +1,324 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isSnapshots = "snapshots" + isSnapshotId = "id" +) + +func DataSourceSnapshots() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISSnapshotsRead, + + Schema: map[string]*schema.Schema{ + + isSnapshotResourceGroup: { + Type: schema.TypeString, + Description: "Filters the snapshot collection by resources group id", + Optional: true, + }, + + isSnapshotName: { + Type: schema.TypeString, + Description: "Filters the snapshot collection by snapshot name", + Optional: true, + }, + + isSnapshotSourceImage: { + Type: schema.TypeString, + Description: "Filters the snapshot collection by source image id", + Optional: true, + }, + + isSnapshotSourceVolume: { + Type: schema.TypeString, + Description: "Filters the snapshot collection by source volume id", + Optional: true, + }, + + "backup_policy_plan_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to backup policy jobs with the backup plan with the specified identifier", + }, + + "tag": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with the exact tag value", + }, + + isSnapshots: { + Type: schema.TypeList, + Description: "List of snapshots", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isSnapshotId: { + Type: schema.TypeString, + Computed: true, + }, + + isSnapshotName: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot name", + }, + + isSnapshotResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Resource group info", + }, + + isSnapshotSourceVolume: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot source volume", + }, + isSnapshotSourceImage: { + Type: schema.TypeString, + Computed: true, + Description: "If present, the image id from which the data on this volume was most directly provisioned.", + }, + + isSnapshotOperatingSystem: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the operating system included in this image", + }, + + isSnapshotLCState: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot lifecycle state", + }, + isSnapshotCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + isSnapshotEncryption: { + Type: schema.TypeString, + Computed: true, + Description: "Encryption type of the snapshot", + }, + isSnapshotHref: { + Type: schema.TypeString, + Computed: true, + Description: "URL for the snapshot", + }, + + isSnapshotBootable: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + }, + + isSnapshotMinCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum capacity of the snapshot", + }, + isSnapshotResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type of the snapshot", + }, + + isSnapshotSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the snapshot", + }, + + isSnapshotCapturedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this snapshot was created", + }, + + isSnapshotUserTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "User Tags for the snapshot", + }, + + isSnapshotBackupPolicyPlan: { + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISSnapshotsRead(d *schema.ResourceData, meta interface{}) error { + err := getSnapshots(d, meta) + if err != nil { + return err + } + return nil +} + +func getSnapshots(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + start := "" + allrecs := []vpcv1.Snapshot{} + for { + listSnapshotOptions := &vpcv1.ListSnapshotsOptions{} + if start != "" { + listSnapshotOptions.Start = &start + } + if rgFilterOk, ok := d.GetOk(isSnapshotResourceGroup); ok { + rgFilter := rgFilterOk.(string) + listSnapshotOptions.ResourceGroupID = &rgFilter + } + if nameFilterOk, ok := d.GetOk(isSnapshotName); ok { + nameFilter := nameFilterOk.(string) + listSnapshotOptions.Name = &nameFilter + } + if sourceImageFilterOk, ok := d.GetOk(isSnapshotSourceImage); ok { + sourceImageFilter := sourceImageFilterOk.(string) + listSnapshotOptions.SourceImageID = &sourceImageFilter + } + if sourceVolumeFilterOk, ok := d.GetOk(isSnapshotSourceVolume); ok { + sourceVolumeFilter := sourceVolumeFilterOk.(string) + listSnapshotOptions.SourceVolumeID = &sourceVolumeFilter + } + if backupPolicyPlanIdFilterOk, ok := d.GetOk("backup_policy_plan_id"); ok { + backupPolicyPlanIdFilter := backupPolicyPlanIdFilterOk.(string) + listSnapshotOptions.BackupPolicyPlanID = &backupPolicyPlanIdFilter + } + if tagFilterOk, ok := d.GetOk("tag"); ok { + tagFilter := tagFilterOk.(string) + listSnapshotOptions.Tag = &tagFilter + } + + snapshots, response, err := sess.ListSnapshots(listSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching snapshots %s\n%s", err, response) + } + start = flex.GetNext(snapshots.Next) + allrecs = append(allrecs, snapshots.Snapshots...) + if start == "" { + break + } + } + + snapshotsInfo := make([]map[string]interface{}, 0) + for _, snapshot := range allrecs { + l := map[string]interface{}{ + isSnapshotId: *snapshot.ID, + isSnapshotName: *snapshot.Name, + isSnapshotHref: *snapshot.Href, + isSnapshotCRN: *snapshot.CRN, + isSnapshotMinCapacity: *snapshot.MinimumCapacity, + isSnapshotSize: *snapshot.Size, + isSnapshotEncryption: *snapshot.Encryption, + isSnapshotLCState: *snapshot.LifecycleState, + isSnapshotResourceType: *snapshot.ResourceType, + isSnapshotBootable: *snapshot.Bootable, + } + if snapshot.CapturedAt != nil { + l[isSnapshotCapturedAt] = (*snapshot.CapturedAt).String() + } + + if snapshot.UserTags != nil { + l[isSnapshotUserTags] = snapshot.UserTags + } + if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { + l[isSnapshotResourceGroup] = *snapshot.ResourceGroup.ID + } + if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { + l[isSnapshotSourceVolume] = *snapshot.SourceVolume.ID + } + if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { + l[isSnapshotSourceImage] = *snapshot.SourceImage.ID + } + if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { + l[isSnapshotOperatingSystem] = *snapshot.OperatingSystem.Name + } + backupPolicyPlanList := []map[string]interface{}{} + if snapshot.BackupPolicyPlan != nil { + backupPolicyPlan := map[string]interface{}{} + if snapshot.BackupPolicyPlan.Deleted != nil { + snapshotBackupPolicyPlanDeletedMap := map[string]interface{}{} + snapshotBackupPolicyPlanDeletedMap["more_info"] = snapshot.BackupPolicyPlan.Deleted.MoreInfo + backupPolicyPlan["deleted"] = []map[string]interface{}{snapshotBackupPolicyPlanDeletedMap} + } + backupPolicyPlan["href"] = snapshot.BackupPolicyPlan.Href + backupPolicyPlan["id"] = snapshot.BackupPolicyPlan.ID + backupPolicyPlan["name"] = snapshot.BackupPolicyPlan.Name + backupPolicyPlan["resource_type"] = snapshot.BackupPolicyPlan.ResourceType + backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) + } + l[isSnapshotBackupPolicyPlan] = backupPolicyPlanList + snapshotsInfo = append(snapshotsInfo, l) + } + d.SetId(dataSourceIBMISSnapshotsID(d)) + d.Set(isSnapshots, snapshotsInfo) + return nil +} + +// dataSourceIBMISSnapshotsID returns a reasonable ID for the snapshot list. +func dataSourceIBMISSnapshotsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_is_snapshots_test.go b/ibm/service/vpc/data_source_ibm_is_snapshots_test.go similarity index 78% rename from ibm/data_source_ibm_is_snapshots_test.go rename to ibm/service/vpc/data_source_ibm_is_snapshots_test.go index fc9b33bd5..a94293c3e 100644 --- a/ibm/data_source_ibm_is_snapshots_test.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshots_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSnapshotDestroy, Steps: []resource.TestStep{ { @@ -38,21 +40,25 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE ), }, { - Config: testDSCheckIBMISSnapshotsConfig(), + Config: testDSCheckIBMISSnapshotsConfig(name1), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(snpName, "snapshots.0.delatable"), + resource.TestCheckResourceAttr( + snpName, "snapshots.0.name", name1), + // resource.TestCheckResourceAttrSet(snpName, "snapshots.0.delatable"), // Commented as it is deprecated. resource.TestCheckResourceAttrSet(snpName, "snapshots.0.href"), resource.TestCheckResourceAttrSet(snpName, "snapshots.0.crn"), resource.TestCheckResourceAttrSet(snpName, "snapshots.0.lifecycle_state"), resource.TestCheckResourceAttrSet(snpName, "snapshots.0.encryption"), + resource.TestCheckResourceAttrSet(snpName, "snapshots.0.captured_at"), ), }, }, }) } -func testDSCheckIBMISSnapshotsConfig() string { +func testDSCheckIBMISSnapshotsConfig(name1 string) string { return fmt.Sprintf(` data "ibm_is_snapshots" "ds_snapshot" { -}`) + name = "%s" + }`, name1) } diff --git a/ibm/data_source_ibm_is_ssh_key.go b/ibm/service/vpc/data_source_ibm_is_ssh_key.go similarity index 80% rename from ibm/data_source_ibm_is_ssh_key.go rename to ibm/service/vpc/data_source_ibm_is_ssh_key.go index d58d545b8..6b5f46f68 100644 --- a/ibm/data_source_ibm_is_ssh_key.go +++ b/ibm/service/vpc/data_source_ibm_is_ssh_key.go @@ -1,16 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISSSHKey() *schema.Resource { +func DataSourceIBMISSSHKey() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISSSHKeyRead, @@ -51,19 +52,19 @@ func dataSourceIBMISSSHKey() *schema.Resource { Description: "The ssh key length", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", @@ -75,7 +76,7 @@ func dataSourceIBMISSSHKey() *schema.Resource { Description: "The crn of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -101,12 +102,6 @@ func keyGetByName(d *schema.ResourceData, meta interface{}, name string) error { } listKeysOptions := &vpcv1.ListKeysOptions{} - resourceGroup := "" - if rg, ok := d.GetOk("resource_group"); ok { - resourceGroup = rg.(string) - listKeysOptions.ResourceGroupID = &resourceGroup - } - start := "" allrecs := []vpcv1.Key{} for { @@ -116,9 +111,9 @@ func keyGetByName(d *schema.ResourceData, meta interface{}, name string) error { keys, response, err := sess.ListKeys(listKeysOptions) if err != nil { - return fmt.Errorf("Error fetching Keys %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching Keys %s\n%s", err, response) } - start = GetNext(keys.Next) + start = flex.GetNext(keys.Next) allrecs = append(allrecs, keys.Keys...) if start == "" { break @@ -132,16 +127,16 @@ func keyGetByName(d *schema.ResourceData, meta interface{}, name string) error { d.Set(isKeyType, *key.Type) d.Set(isKeyFingerprint, *key.Fingerprint) d.Set(isKeyLength, *key.Length) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc/compute/sshKeys") - d.Set(ResourceName, *key.Name) - d.Set(ResourceCRN, *key.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc/compute/sshKeys") + d.Set(flex.ResourceName, *key.Name) + d.Set(flex.ResourceCRN, *key.CRN) d.Set(IsKeyCRN, *key.CRN) if key.ResourceGroup != nil { - d.Set(ResourceGroupName, *key.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *key.ResourceGroup.ID) } if key.PublicKey != nil { d.Set(isKeyPublicKey, *key.PublicKey) @@ -149,5 +144,5 @@ func keyGetByName(d *schema.ResourceData, meta interface{}, name string) error { return nil } } - return fmt.Errorf("No SSH Key found with name %s", name) + return fmt.Errorf("[ERROR] No SSH Key found with name %s", name) } diff --git a/ibm/data_source_ibm_is_ssh_key_test.go b/ibm/service/vpc/data_source_ibm_is_ssh_key_test.go similarity index 89% rename from ibm/data_source_ibm_is_ssh_key_test.go rename to ibm/service/vpc/data_source_ibm_is_ssh_key_test.go index eb811383b..d4bbc2a13 100644 --- a/ibm/data_source_ibm_is_ssh_key_test.go +++ b/ibm/service/vpc/data_source_ibm_is_ssh_key_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -19,8 +21,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testDSCheckIBMISSSHKeyConfig(publicKey, name1), diff --git a/ibm/service/vpc/data_source_ibm_is_ssh_keys.go b/ibm/service/vpc/data_source_ibm_is_ssh_keys.go new file mode 100644 index 000000000..8455cbf41 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ssh_keys.go @@ -0,0 +1,226 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isKeys = "keys" + isKeyCreatedAt = "created_at" + isKeyCRN = "crn" + isKeysHref = "href" + isKeyId = "id" + isKeyResourceGroupHref = "href" + isKeyResourceGroupId = "id" + isKeyResourceGroupName = "name" + isKeysLimit = "limit" +) + +func DataSourceIBMIsSshKeys() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSshKeysRead, + + Schema: map[string]*schema.Schema{ + isKeys: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of keys.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isKeyCreatedAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the key was created.", + }, + isKeyCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this key.", + }, + isKeyFingerprint: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The fingerprint for this key. The value is returned base64-encoded and prefixed with the hash algorithm (always `SHA256`).", + }, + isKeysHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this key.", + }, + isKeyId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this key.", + }, + isKeyLength: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The length of this key (in bits).", + }, + isKeyName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this key. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + isKeyPublicKey: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The public SSH key, consisting of two space-separated fields: the algorithm name, and the base64-encoded key.", + }, + isKeyResourceGroup: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this key.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isKeyResourceGroupHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + isKeyResourceGroupId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + isKeyResourceGroupName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + isKeyType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The crypto-system used by this key.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsSshKeysRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.Key{} + listKeysOptions := &vpcv1.ListKeysOptions{} + + for { + if start != "" { + listKeysOptions.Start = &start + } + + keyCollection, response, err := vpcClient.ListKeysWithContext(context, listKeysOptions) + if err != nil || keyCollection == nil { + log.Printf("[DEBUG] ListKeysWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListKeysWithContext failed %s\n%s", err, response)) + } + + start = flex.GetNext(keyCollection.Next) + allrecs = append(allrecs, keyCollection.Keys...) + + if start == "" { + break + } + + } + + d.SetId(dataSourceIBMIsSshKeysID(d)) + + err = d.Set(isKeys, dataSourceKeyCollectionFlattenKeys(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting keys %s", err)) + } + + return nil +} + +// dataSourceIBMIsSshKeysID returns a reasonable ID for the list. +func dataSourceIBMIsSshKeysID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceKeyCollectionFlattenKeys(result []vpcv1.Key) (keys []map[string]interface{}) { + for _, keysItem := range result { + keys = append(keys, dataSourceKeyCollectionKeysToMap(keysItem)) + } + + return keys +} + +func dataSourceKeyCollectionKeysToMap(keysItem vpcv1.Key) (keysMap map[string]interface{}) { + keysMap = map[string]interface{}{} + + if keysItem.CreatedAt != nil { + keysMap[isKeyCreatedAt] = keysItem.CreatedAt.String() + } + if keysItem.CRN != nil { + keysMap[isKeyCRN] = keysItem.CRN + } + if keysItem.Fingerprint != nil { + keysMap[isKeyFingerprint] = keysItem.Fingerprint + } + if keysItem.Href != nil { + keysMap[isKeysHref] = keysItem.Href + } + if keysItem.ID != nil { + keysMap[isKeyId] = keysItem.ID + } + if keysItem.Length != nil { + keysMap[isKeyLength] = keysItem.Length + } + if keysItem.Name != nil { + keysMap[isKeyName] = keysItem.Name + } + if keysItem.PublicKey != nil { + keysMap[isKeyPublicKey] = keysItem.PublicKey + } + if keysItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceKeyCollectionKeysResourceGroupToMap(*keysItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + keysMap[isKeyResourceGroup] = resourceGroupList + } + if keysItem.Type != nil { + keysMap[isKeyType] = keysItem.Type + } + + return keysMap +} + +func dataSourceKeyCollectionKeysResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap[isKeyResourceGroupHref] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap[isKeyResourceGroupId] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap[isKeyResourceGroupName] = resourceGroupItem.Name + } + + return resourceGroupMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_ssh_keys_test.go b/ibm/service/vpc/data_source_ibm_is_ssh_keys_test.go new file mode 100644 index 000000000..b6c154cc6 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_ssh_keys_test.go @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsSshKeysDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSshKeysDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_ssh_keys.is_ssh_keys", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_ssh_keys.is_ssh_keys", "keys.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSshKeysDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_ssh_keys" "is_ssh_keys" { + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_subnet.go b/ibm/service/vpc/data_source_ibm_is_subnet.go new file mode 100644 index 000000000..6a2503e06 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_subnet.go @@ -0,0 +1,356 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMISSubnet() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISSubnetRead, + + Schema: map[string]*schema.Schema{ + + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{isSubnetName, "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_subnet", "identifier"), + }, + + isSubnetIpv4CidrBlock: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetAvailableIpv4AddressCount: { + Type: schema.TypeInt, + Computed: true, + }, + + isSubnetTotalIpv4AddressCount: { + Type: schema.TypeInt, + Computed: true, + }, + + isSubnetName: { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{isSubnetName, "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_subnet", isSubnetName), + }, + + isSubnetTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags", + }, + + isSubnetAccessTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "List of access tags", + }, + + isSubnetCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + isSubnetNetworkACL: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetPublicGateway: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetStatus: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetVPC: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetVPCName: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetZone: { + Type: schema.TypeString, + Computed: true, + }, + + isSubnetResourceGroup: { + Type: schema.TypeString, + Computed: true, + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + "routing_table": { + Type: schema.TypeList, + Computed: true, + Description: "The routing table for this subnet", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this routing table.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this routing table.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this routing table.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMISSubnetValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "identifier", + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSubnetName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + ibmISSubnetDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_subnet", Schema: validateSchema} + return &ibmISSubnetDataSourceValidator +} + +func dataSourceIBMISSubnetRead(d *schema.ResourceData, meta interface{}) error { + err := subnetGetByNameOrID(d, meta) + if err != nil { + return err + } + return nil +} + +func subnetGetByNameOrID(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + var subnet *vpcv1.Subnet + if v, ok := d.GetOk("identifier"); ok { + id := v.(string) + getSubnetOptions := &vpcv1.GetSubnetOptions{ + ID: &id, + } + subnetinfo, response, err := sess.GetSubnet(getSubnetOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response) + } + subnet = subnetinfo + } else if v, ok := d.GetOk(isSubnetName); ok { + name := v.(string) + start := "" + allrecs := []vpcv1.Subnet{} + getSubnetsListOptions := &vpcv1.ListSubnetsOptions{} + + for { + if start != "" { + getSubnetsListOptions.Start = &start + } + subnetsCollection, response, err := sess.ListSubnets(getSubnetsListOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching subnets List %s\n%s", err, response) + } + start = flex.GetNext(subnetsCollection.Next) + allrecs = append(allrecs, subnetsCollection.Subnets...) + if start == "" { + break + } + } + + for _, subnetInfo := range allrecs { + if *subnetInfo.Name == name { + subnet = &subnetInfo + break + } + } + if subnet == nil { + return fmt.Errorf("[ERROR] No subnet found with name (%s)", name) + } + } + + d.SetId(*subnet.ID) + + if subnet.RoutingTable != nil { + err = d.Set("routing_table", dataSourceSubnetFlattenroutingTable(*subnet.RoutingTable)) + if err != nil { + return fmt.Errorf("Error setting routing_table %s", err) + } + } + d.Set(isSubnetName, *subnet.Name) + d.Set(isSubnetIpv4CidrBlock, *subnet.Ipv4CIDRBlock) + d.Set(isSubnetAvailableIpv4AddressCount, *subnet.AvailableIpv4AddressCount) + d.Set(isSubnetTotalIpv4AddressCount, *subnet.TotalIpv4AddressCount) + if subnet.NetworkACL != nil { + d.Set(isSubnetNetworkACL, *subnet.NetworkACL.ID) + } + if subnet.PublicGateway != nil { + d.Set(isSubnetPublicGateway, *subnet.PublicGateway.ID) + } else { + d.Set(isSubnetPublicGateway, nil) + } + d.Set(isSubnetStatus, *subnet.Status) + d.Set(isSubnetZone, *subnet.Zone.Name) + d.Set(isSubnetVPC, *subnet.VPC.ID) + d.Set(isSubnetVPCName, *subnet.VPC.Name) + + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + + tags, err := flex.GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "An error occured during reading of subnet (%s) tags : %s", d.Id(), err) + } + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of resource subnet (%s) access tags: %s", d.Id(), err) + } + + d.Set(isSubnetTags, tags) + d.Set(isSubnetAccessTags, accesstags) + d.Set(isSubnetCRN, *subnet.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/subnets") + d.Set(flex.ResourceName, *subnet.Name) + d.Set(flex.ResourceCRN, *subnet.CRN) + d.Set(flex.ResourceStatus, *subnet.Status) + if subnet.ResourceGroup != nil { + d.Set(isSubnetResourceGroup, *subnet.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *subnet.ResourceGroup.Name) + } + return nil +} + +func dataSourcesubnetRoutingTableDeletedToMap(deletedItem vpcv1.RoutingTableReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceSubnetFlattenroutingTable(result vpcv1.RoutingTableReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceSubnetRoutingTableToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceSubnetRoutingTableToMap(routingTableItem vpcv1.RoutingTableReference) (routingTableMap map[string]interface{}) { + routingTableMap = map[string]interface{}{} + + if routingTableItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourcesubnetRoutingTableDeletedToMap(*routingTableItem.Deleted) + deletedList = append(deletedList, deletedMap) + routingTableMap["deleted"] = deletedList + } + if routingTableItem.Href != nil { + routingTableMap["href"] = routingTableItem.Href + } + if routingTableItem.ID != nil { + routingTableMap["id"] = routingTableItem.ID + } + if routingTableItem.Name != nil { + routingTableMap["name"] = routingTableItem.Name + } + if routingTableItem.ResourceType != nil { + routingTableMap["resource_type"] = routingTableItem.ResourceType + } + + return routingTableMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go new file mode 100644 index 000000000..52552240a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go @@ -0,0 +1,166 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "reflect" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Request Param Constants + isSubNetID = "subnet" + isReservedIPID = "reserved_ip" + + // Response Param Constants + isReservedIPAddress = "address" + isReservedIPAutoDelete = "auto_delete" + isReservedIPCreatedAt = "created_at" + isReservedIPhref = "href" + isReservedIPName = "name" + isReservedIPOwner = "owner" + isReservedIPType = "resource_type" +) + +func DataSourceIBMISReservedIP() *schema.Resource { + return &schema.Resource{ + Read: dataSdataSourceIBMISReservedIPRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isSubNetID: { + Type: schema.TypeString, + Required: true, + Description: "The subnet identifier.", + }, + isReservedIPID: { + Type: schema.TypeString, + Required: true, + Description: "The reserved IP identifier.", + }, + + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isReservedIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isReservedIPLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reserved IP", + }, + isReservedIPAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, this reserved IP will be automatically deleted", + }, + isReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isReservedIPName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id.", + }, + }, + } +} + +// dataSdataSourceIBMISReservedIPRead is used when the reserved IPs are read from the vpc +func dataSdataSourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{}) error { + + sess, err := vpcClient(meta) + if err != nil { + return err + } + + subnetID := d.Get(isSubNetID).(string) + reservedIPID := d.Get(isReservedIPID).(string) + + options := sess.NewGetSubnetReservedIPOptions(subnetID, reservedIPID) + reserveIP, response, err := sess.GetSubnetReservedIP(options) + + if err != nil || response == nil || reserveIP == nil { + return fmt.Errorf("[ERROR] Error fetching the reserved IP %s\n%s", err, response) + } + + d.SetId(*reserveIP.ID) + d.Set(isReservedIPAutoDelete, *reserveIP.AutoDelete) + d.Set(isReservedIPAddress, *reserveIP.Address) + d.Set(isReservedIPCreatedAt, (*reserveIP.CreatedAt).String()) + d.Set(isReservedIPhref, *reserveIP.Href) + d.Set(isReservedIPName, *reserveIP.Name) + d.Set(isReservedIPOwner, *reserveIP.Owner) + if reserveIP.LifecycleState != nil { + d.Set(isReservedIPLifecycleState, *reserveIP.LifecycleState) + } + d.Set(isReservedIPType, *reserveIP.ResourceType) + if reserveIP.Target != nil { + targetIntf := reserveIP.Target + switch reflect.TypeOf(targetIntf).String() { + case "*vpcv1.ReservedIPTargetEndpointGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetEndpointGatewayReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext": + { + target := targetIntf.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetLoadBalancerReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetLoadBalancerReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetVPNGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetVPNGatewayReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTarget": + { + target := targetIntf.(*vpcv1.ReservedIPTarget) + d.Set(isReservedIPTarget, target.ID) + } + } + } + return nil // By default there should be no error +} diff --git a/ibm/data_source_ibm_is_subnet_reserved_ip_test.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go similarity index 86% rename from ibm/data_source_ibm_is_subnet_reserved_ip_test.go rename to ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go index a53c7d08c..a375bd8af 100644 --- a/ibm/data_source_ibm_is_subnet_reserved_ip_test.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go @@ -1,11 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,13 +18,13 @@ func TestAccIBMISSubnetReservedIP_basic(t *testing.T) { resIPName := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) terraformTag := "data.ibm_is_subnet_reserved_ip.data_resip1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccIBMISReservedIPdataSoruceConfig(vpcName, subnetName, resIPName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(terraformTag, isReservedIPName, resIPName), + resource.TestCheckResourceAttr(terraformTag, "name", resIPName), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go new file mode 100644 index 000000000..d24168170 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go @@ -0,0 +1,194 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Define all the constants that matches with the given terrafrom attribute +const ( + // Request Param Constants + isReservedIPLimit = "limit" + isReservedIPSort = "sort" + isReservedIPs = "reserved_ips" + isReservedIPsCount = "total_count" +) + +func DataSourceIBMISReservedIPs() *schema.Resource { + return &schema.Resource{ + Read: dataSdataSourceIBMISReservedIPsRead, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isSubNetID: { + Type: schema.TypeString, + Required: true, + Description: "The subnet identifier.", + }, + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isReservedIPs: { + Type: schema.TypeList, + Description: "Collection of reserved IPs in this subnet.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservedIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address", + }, + isReservedIPAutoDelete: { + Type: schema.TypeBool, + Computed: true, + Description: "If reserved ip shall be deleted automatically", + }, + isReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isReservedIPID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP", + }, + isReservedIPLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reserved IP", + }, + isReservedIPName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Reserved IP target id", + }, + }, + }, + }, + isReservedIPsCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of resources across all pages", + }, + }, + } +} + +func dataSdataSourceIBMISReservedIPsRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + subnetID := d.Get(isSubNetID).(string) + + // Flatten all the reserved IPs + start := "" + allrecs := []vpcv1.ReservedIP{} + for { + options := &vpcv1.ListSubnetReservedIpsOptions{SubnetID: &subnetID} + + if start != "" { + options.Start = &start + } + + result, response, err := sess.ListSubnetReservedIps(options) + if err != nil || response == nil || result == nil { + return fmt.Errorf("[ERROR] Error fetching reserved ips %s\n%s", err, response) + } + start = flex.GetNext(result.Next) + allrecs = append(allrecs, result.ReservedIps...) + if start == "" { + break + } + } + + // Now store all the reserved IP info with their response tags + reservedIPs := []map[string]interface{}{} + for _, data := range allrecs { + ipsOutput := map[string]interface{}{} + ipsOutput[isReservedIPAddress] = *data.Address + ipsOutput[isReservedIPAutoDelete] = *data.AutoDelete + ipsOutput[isReservedIPCreatedAt] = (*data.CreatedAt).String() + ipsOutput[isReservedIPhref] = *data.Href + ipsOutput[isReservedIPID] = *data.ID + ipsOutput[isReservedIPLifecycleState] = data.LifecycleState + ipsOutput[isReservedIPName] = *data.Name + ipsOutput[isReservedIPOwner] = *data.Owner + ipsOutput[isReservedIPType] = *data.ResourceType + if data.Target != nil { + targetIntf := data.Target + switch reflect.TypeOf(targetIntf).String() { + case "*vpcv1.ReservedIPTargetEndpointGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetEndpointGatewayReference) + ipsOutput[isReservedIPTarget] = target.ID + } + case "*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext": + { + target := targetIntf.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) + ipsOutput[isReservedIPTarget] = target.ID + } + case "*vpcv1.ReservedIPTargetLoadBalancerReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetLoadBalancerReference) + ipsOutput[isReservedIPTarget] = target.ID + } + case "*vpcv1.ReservedIPTargetVPNGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetVPNGatewayReference) + ipsOutput[isReservedIPTarget] = target.ID + } + case "*vpcv1.ReservedIPTarget": + { + target := targetIntf.(*vpcv1.ReservedIPTarget) + ipsOutput[isReservedIPTarget] = target.ID + } + } + } + reservedIPs = append(reservedIPs, ipsOutput) + } + + d.SetId(time.Now().UTC().String()) // This is not any reserved ip or subnet id but state id + d.Set(isReservedIPs, reservedIPs) + d.Set(isReservedIPsCount, len(reservedIPs)) + d.Set(isSubNetID, subnetID) + return nil +} diff --git a/ibm/data_source_ibm_is_subnet_reserved_ips_test.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips_test.go similarity index 95% rename from ibm/data_source_ibm_is_subnet_reserved_ips_test.go rename to ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips_test.go index 98df288dc..dcdb13605 100644 --- a/ibm/data_source_ibm_is_subnet_reserved_ips_test.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -23,8 +25,8 @@ func TestAccIBMISSubnetReservedIPs_basic(t *testing.T) { reservedIPName2 := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccIBMISReservedIPSResoruceConfig2(vpcName, subnetName, diff --git a/ibm/data_source_ibm_is_subnet_test.go b/ibm/service/vpc/data_source_ibm_is_subnet_test.go similarity index 83% rename from ibm/data_source_ibm_is_subnet_test.go rename to ibm/service/vpc/data_source_ibm_is_subnet_test.go index b0ec520f0..1ac7869be 100644 --- a/ibm/data_source_ibm_is_subnet_test.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,12 +18,12 @@ func TestAccIBMISSubnetDatasource_basic(t *testing.T) { name := fmt.Sprintf("tfsubnet-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { - Config: testDSCheckIBMISSubnetConfig(vpcname, name, ISZoneName, ISCIDR), + Config: testDSCheckIBMISSubnetConfig(vpcname, name, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "data.ibm_is_subnet.ds_subnet", "name", name), diff --git a/ibm/service/vpc/data_source_ibm_is_subnets.go b/ibm/service/vpc/data_source_ibm_is_subnets.go new file mode 100644 index 000000000..395a64bf3 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_subnets.go @@ -0,0 +1,241 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "strconv" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isSubnets = "subnets" + isSubnetResourceGroupID = "resource_group" + isSubnetRoutingTableName = "routing_table_name" +) + +func DataSourceIBMISSubnets() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISSubnetsRead, + + Schema: map[string]*schema.Schema{ + isSubnetResourceGroupID: { + Type: schema.TypeString, + Description: "Resource Group ID", + Optional: true, + }, + + isSubnetRoutingTableName: { + Type: schema.TypeString, + Description: "Name of the routing table", + Optional: true, + }, + + isSubnetRoutingTableID: { + Type: schema.TypeString, + Description: "ID of the routing table", + Optional: true, + }, + + isSubnets: { + Type: schema.TypeList, + Description: "List of subnets", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "crn": { + Type: schema.TypeString, + Computed: true, + }, + "ipv4_cidr_block": { + Type: schema.TypeString, + Computed: true, + }, + "available_ipv4_address_count": { + Type: schema.TypeString, + Computed: true, + }, + "network_acl": { + Type: schema.TypeString, + Computed: true, + }, + "public_gateway": { + Type: schema.TypeString, + Computed: true, + }, + isSubnetResourceGroupID: { + Type: schema.TypeString, + Computed: true, + }, + "total_ipv4_address_count": { + Type: schema.TypeString, + Computed: true, + }, + "vpc": { + Type: schema.TypeString, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + }, + "routing_table": { + Type: schema.TypeList, + Computed: true, + Description: "The routing table for this subnet", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this routing table.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this routing table.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this routing table.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISSubnetsRead(d *schema.ResourceData, meta interface{}) error { + err := subnetList(d, meta) + if err != nil { + return err + } + return nil +} + +func subnetList(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + start := "" + allrecs := []vpcv1.Subnet{} + + var resourceGroup string + if v, ok := d.GetOk(isSubnetResourceGroupID); ok { + resourceGroup = v.(string) + } + + var routingTable string + if v, ok := d.GetOk(isSubnetRoutingTableID); ok { + routingTable = v.(string) + } + + var resourceTableName string + if v, ok := d.GetOk(isSubnetRoutingTableName); ok { + resourceTableName = v.(string) + } + + options := &vpcv1.ListSubnetsOptions{} + if resourceGroup != "" { + options.SetResourceGroupID(resourceGroup) + } + if routingTable != "" { + options.SetRoutingTableID(routingTable) + } + if resourceTableName != "" { + options.SetRoutingTableName(resourceTableName) + } + + for { + if start != "" { + options.Start = &start + } + subnets, response, err := sess.ListSubnets(options) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching subnets %s\n%s", err, response) + } + start = flex.GetNext(subnets.Next) + allrecs = append(allrecs, subnets.Subnets...) + if start == "" { + break + } + } + subnetsInfo := make([]map[string]interface{}, 0) + for _, subnet := range allrecs { + + var aac string = strconv.FormatInt(*subnet.AvailableIpv4AddressCount, 10) + var tac string = strconv.FormatInt(*subnet.TotalIpv4AddressCount, 10) + l := map[string]interface{}{ + "name": *subnet.Name, + "id": *subnet.ID, + "status": *subnet.Status, + "crn": *subnet.CRN, + "ipv4_cidr_block": *subnet.Ipv4CIDRBlock, + "available_ipv4_address_count": aac, + "network_acl": *subnet.NetworkACL.Name, + "total_ipv4_address_count": tac, + "vpc": *subnet.VPC.ID, + "zone": *subnet.Zone.Name, + } + if subnet.PublicGateway != nil { + l["public_gateway"] = *subnet.PublicGateway.ID + } + if subnet.ResourceGroup != nil { + l["resource_group"] = *subnet.ResourceGroup.ID + } + if subnet.RoutingTable != nil { + l["routing_table"] = dataSourceSubnetFlattenroutingTable(*subnet.RoutingTable) + } + subnetsInfo = append(subnetsInfo, l) + } + d.SetId(dataSourceIBMISSubnetsID(d)) + d.Set(isSubnets, subnetsInfo) + return nil +} + +// dataSourceIBMISSubnetsId returns a reasonable ID for a subnet list. +func dataSourceIBMISSubnetsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/data_source_ibm_is_subnets_test.go b/ibm/service/vpc/data_source_ibm_is_subnets_test.go similarity index 87% rename from ibm/data_source_ibm_is_subnets_test.go rename to ibm/service/vpc/data_source_ibm_is_subnets_test.go index dc3ff166b..92ec7a24c 100644 --- a/ibm/data_source_ibm_is_subnets_test.go +++ b/ibm/service/vpc/data_source_ibm_is_subnets_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,19 +20,19 @@ func TestAccIBMISSubnetsDataSource_basic(t *testing.T) { name := fmt.Sprintf("tfsubnet-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISSubnetConfig(vpcname, name, ISZoneName, ISCIDR), + Config: testAccCheckIBMISSubnetConfig(vpcname, name, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetExists("ibm_is_subnet.testacc_subnet", subnet), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "name", name), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "zone", ISZoneName), + "ibm_is_subnet.testacc_subnet", "zone", acc.ISZoneName), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", ISCIDR), + "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", acc.ISCIDR), ), }, { @@ -58,19 +60,19 @@ func TestAccIBMISSubnetsDataSource_basic_filterResourceGroup(t *testing.T) { name := fmt.Sprintf("tfsubnet-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISSubnetsDataSourceFilterResourceGroupConfig(vpcname, name, ISZoneName, ISCIDR), + Config: testAccCheckIBMISSubnetsDataSourceFilterResourceGroupConfig(vpcname, name, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetExists("ibm_is_subnet.testacc_subnet", subnet), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "name", name), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "zone", ISZoneName), + "ibm_is_subnet.testacc_subnet", "zone", acc.ISZoneName), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", ISCIDR), + "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", acc.ISCIDR), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_resource_group", "subnets.0.name"), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_resource_group", "subnets.0.status"), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_resource_group", "subnets.0.status"), @@ -93,19 +95,19 @@ func TestAccIBMISSubnetsDataSource_basic_filterRoutingTable(t *testing.T) { name := fmt.Sprintf("tfsubnet-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISSubnetsDataSourceFilterRoutingTableConfig(vpcname, name, ISZoneName, ISCIDR), + Config: testAccCheckIBMISSubnetsDataSourceFilterRoutingTableConfig(vpcname, name, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetExists("ibm_is_subnet.testacc_subnet", subnet), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "name", name), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "zone", ISZoneName), + "ibm_is_subnet.testacc_subnet", "zone", acc.ISZoneName), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", ISCIDR), + "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", acc.ISCIDR), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_routing_table", "subnets.0.name"), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_routing_table", "subnets.0.status"), resource.TestCheckResourceAttrSet("data.ibm_is_subnets.ds_subnets_routing_table", "subnets.0.status"), @@ -156,6 +158,7 @@ func testAccCheckIBMISSubnetsDataSourceFilterResourceGroupConfig(vpcname, name, } data "ibm_is_subnets" "ds_subnets_resource_group" { + depends_on = [ibm_is_subnet.testacc_subnet] resource_group = data.ibm_resource_group.resourceGroup.id } `, vpcname, name, zone, cidr) @@ -188,7 +191,8 @@ func testAccCheckIBMISSubnetsDataSourceFilterRoutingTableConfig(vpcname, name, z } data "ibm_is_subnets" "ds_subnets_routing_table" { - routing_table = ibm_is_vpc_routing_table.test_cr_route_table1.id + depends_on = [ibm_is_subnet.testacc_subnet ] + routing_table = ibm_is_vpc_routing_table.test_cr_route_table1.routing_table } `, vpcname, name, zone, cidr) } diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go new file mode 100644 index 000000000..97e0a2714 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMISEndpointGateway() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISEndpointGatewayRead, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayName: { + Type: schema.TypeString, + Required: true, + Description: "Endpoint gateway name", + }, + isVirtualEndpointGatewayResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway resource type", + }, + isVirtualEndpointGatewayCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this Endpoint gateway", + }, + isVirtualEndpointGatewayResourceGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group id", + }, + isVirtualEndpointGatewayCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway created date and time", + }, + isVirtualEndpointGatewayHealthState: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway health state", + }, + isVirtualEndpointGatewayLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway lifecycle state", + }, + isVirtualEndpointGatewaySecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Endpoint gateway securitygroups list", + }, + isVirtualEndpointGatewayIPs: { + Type: schema.TypeList, + Computed: true, + Description: "Endpoint gateway IPs", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayIPsID: { + Type: schema.TypeString, + Computed: true, + Description: "The IPs id", + }, + isVirtualEndpointGatewayIPsName: { + Type: schema.TypeString, + Computed: true, + Description: "The IPs name", + }, + isVirtualEndpointGatewayIPsResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway IP resource type", + }, + isVirtualEndpointGatewayIPsAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway IP Address", + }, + }, + }, + }, + isVirtualEndpointGatewayTarget: { + Type: schema.TypeList, + Computed: true, + Description: "Endpoint gateway target", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayTargetName: { + Type: schema.TypeString, + Computed: true, + Description: "The target name", + }, + isVirtualEndpointGatewayTargetResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The target resource type", + }, + }, + }, + }, + isVirtualEndpointGatewayVpcID: { + Type: schema.TypeString, + Computed: true, + Description: "The VPC id", + }, + }, + } +} + +func dataSourceIBMISEndpointGatewayRead( + d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + name := d.Get(isVirtualEndpointGatewayName).(string) + + options := sess.NewListEndpointGatewaysOptions() + options.Name = &name + + results, response, err := sess.ListEndpointGateways(options) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching endpoint gateways %s\n%s", err, response) + } + allrecs := results.EndpointGateways + + if len(allrecs) == 0 { + return fmt.Errorf("[ERROR] No Virtual Endpoints Gateway found with given name %s", name) + } + result := allrecs[0] + d.SetId(*result.ID) + d.Set(isVirtualEndpointGatewayName, result.Name) + d.Set(isVirtualEndpointGatewayCRN, result.CRN) + d.Set(isVirtualEndpointGatewayHealthState, result.HealthState) + d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String()) + d.Set(isVirtualEndpointGatewayLifecycleState, result.LifecycleState) + d.Set(isVirtualEndpointGatewayResourceType, result.ResourceType) + d.Set(isVirtualEndpointGatewayIPs, flattenIPs(result.Ips)) + d.Set(isVirtualEndpointGatewayResourceGroupID, result.ResourceGroup.ID) + d.Set(isVirtualEndpointGatewayTarget, flattenEndpointGatewayTarget( + result.Target.(*vpcv1.EndpointGatewayTarget))) + d.Set(isVirtualEndpointGatewayVpcID, result.VPC.ID) + if result.SecurityGroups != nil { + d.Set(isVirtualEndpointGatewaySecurityGroups, flattenDataSourceSecurityGroups(result.SecurityGroups)) + } + return nil +} diff --git a/ibm/data_source_ibm_is_virtual_endpoint_gateway_ips.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_ips.go similarity index 94% rename from ibm/data_source_ibm_is_virtual_endpoint_gateway_ips.go rename to ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_ips.go index 6a0d79647..9a3b16960 100644 --- a/ibm/data_source_ibm_is_virtual_endpoint_gateway_ips.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_ips.go @@ -1,17 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceIBMISEndpointGatewayIPs() *schema.Resource { +func DataSourceIBMISEndpointGatewayIPs() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISEndpointGatewayIPsRead, Importer: &schema.ResourceImporter{}, @@ -102,9 +103,9 @@ func dataSourceIBMISEndpointGatewayIPsRead(d *schema.ResourceData, meta interfac } result, response, err := sess.ListEndpointGatewayIps(options) if err != nil { - return fmt.Errorf("Error fetching endpoint gateway ips %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching endpoint gateway ips %s\n%s", err, response) } - start = GetNext(result.Next) + start = flex.GetNext(result.Next) allrecs = append(allrecs, result.Ips...) if start == "" { break diff --git a/ibm/data_source_ibm_is_virtual_endpoint_gateway_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_test.go similarity index 88% rename from ibm/data_source_ibm_is_virtual_endpoint_gateway_test.go rename to ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_test.go index 93326512a..adf957913 100644 --- a/ibm/data_source_ibm_is_virtual_endpoint_gateway_test.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMISVirtualEndpointGatewayDataSource_basic(t *testing.T) { subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, Steps: []resource.TestStep{ { diff --git a/ibm/data_source_ibm_is_virtual_endpoint_gateways.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go similarity index 89% rename from ibm/data_source_ibm_is_virtual_endpoint_gateways.go rename to ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go index daab41d42..62598549e 100644 --- a/ibm/data_source_ibm_is_virtual_endpoint_gateways.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -16,7 +17,7 @@ const ( isVirtualEndpointGateways = "virtual_endpoint_gateways" ) -func dataSourceIBMISEndpointGateways() *schema.Resource { +func DataSourceIBMISEndpointGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISEndpointGatewaysRead, Importer: &schema.ResourceImporter{}, @@ -66,6 +67,13 @@ func dataSourceIBMISEndpointGateways() *schema.Resource { Computed: true, Description: "Endpoint gateway lifecycle state", }, + isVirtualEndpointGatewaySecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Endpoint gateway securitygroups list", + }, isVirtualEndpointGatewayIPs: { Type: schema.TypeList, Computed: true, @@ -141,9 +149,9 @@ func dataSourceIBMISEndpointGatewaysRead(d *schema.ResourceData, meta interface{ } result, response, err := sess.ListEndpointGateways(options) if err != nil { - return fmt.Errorf("Error fetching endpoint gateways %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching endpoint gateways %s\n%s", err, response) } - start = GetNext(result.Next) + start = flex.GetNext(result.Next) allrecs = append(allrecs, result.EndpointGateways...) if start == "" { break @@ -165,6 +173,10 @@ func dataSourceIBMISEndpointGatewaysRead(d *schema.ResourceData, meta interface{ flattenEndpointGatewayTarget(endpointGateway.Target.(*vpcv1.EndpointGatewayTarget)) endpointGatewayOutput[isVirtualEndpointGatewayIPs] = flattenDataSourceIPs(endpointGateway.Ips) + if endpointGateway.SecurityGroups != nil { + endpointGatewayOutput[isVirtualEndpointGatewaySecurityGroups] = + flattenDataSourceSecurityGroups(endpointGateway.SecurityGroups) + } endpointGateways = append(endpointGateways, endpointGatewayOutput) } d.SetId(dataSourceIBMISEndpointGatewaysCheckID(d)) diff --git a/ibm/data_source_ibm_is_virtual_endpoint_gateways_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways_test.go similarity index 88% rename from ibm/data_source_ibm_is_virtual_endpoint_gateways_test.go rename to ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways_test.go index 532bd5c8b..04de4137d 100644 --- a/ibm/data_source_ibm_is_virtual_endpoint_gateways_test.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,8 +20,8 @@ func TestAccIBMISVirtualEndpointGatewaysDataSource_basic(t *testing.T) { subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVirtualEndpointGatewaysDataSourceConfig(vpcname1, subnetname1, name1), diff --git a/ibm/service/vpc/data_source_ibm_is_volume.go b/ibm/service/vpc/data_source_ibm_is_volume.go new file mode 100644 index 000000000..1c1fd0bdc --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volume.go @@ -0,0 +1,272 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMISVolume() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISVolumeRead, + + Schema: map[string]*schema.Schema{ + + isVolumeName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_subnet", isVolumeName), + Description: "Volume name", + }, + + isVolumeZone: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Zone name", + }, + + isVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum bandwidth (in megabits per second) for the volume", + }, + + isVolumeResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Resource group name", + }, + + isVolumeProfileName: { + Type: schema.TypeString, + Computed: true, + Description: "Volume profile name", + }, + + isVolumeEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "Volume encryption key info", + }, + + isVolumeEncryptionType: { + Type: schema.TypeString, + Computed: true, + Description: "Volume encryption type info", + }, + + isVolumeCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Vloume capacity value", + }, + + isVolumeIops: { + Type: schema.TypeInt, + Computed: true, + Description: "IOPS value for the Volume", + }, + + isVolumeCrn: { + Type: schema.TypeString, + Computed: true, + Description: "CRN value for the volume instance", + }, + + isVolumeStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Volume status", + }, + + isVolumeStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isVolumeStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isVolumeStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + + isVolumeTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Tags for the volume instance", + }, + + isVolumeSourceSnapshot: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the snapshot from which this volume was cloned", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func DataSourceIBMISVolumeValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + ibmISVoulmeDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} + return &ibmISVoulmeDataSourceValidator +} + +func dataSourceIBMISVolumeRead(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isVolumeName).(string) + + err := volumeGet(d, meta, name) + if err != nil { + return err + } + return nil +} + +func volumeGet(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + zone := "" + if zname, ok := d.GetOk(isVolumeZone); ok { + zone = zname.(string) + } + listVolumesOptions := &vpcv1.ListVolumesOptions{ + Name: &name, + } + + if zone != "" { + listVolumesOptions.ZoneName = &zone + } + listVolumesOptions.Name = &name + vols, response, err := sess.ListVolumes(listVolumesOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching volumes %s\n%s", err, response) + } + allrecs := vols.Volumes + + if len(allrecs) == 0 { + return fmt.Errorf("[ERROR] No Volume found with name %s", name) + } + vol := allrecs[0] + d.SetId(*vol.ID) + d.Set(isVolumeBandwidth, int(*vol.Bandwidth)) + d.Set(isVolumeName, *vol.Name) + d.Set(isVolumeProfileName, *vol.Profile.Name) + d.Set(isVolumeZone, *vol.Zone.Name) + if vol.EncryptionKey != nil { + d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) + } + if vol.Encryption != nil { + d.Set(isVolumeEncryptionType, vol.Encryption) + } + if vol.SourceSnapshot != nil { + d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) + } + d.Set(isVolumeIops, *vol.Iops) + d.Set(isVolumeCapacity, *vol.Capacity) + d.Set(isVolumeCrn, *vol.CRN) + d.Set(isVolumeStatus, *vol.Status) + if vol.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range vol.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isVolumeStatusReasonsCode] = *sr.Code + currentSR[isVolumeStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isVolumeStatusReasonsMoreInfo] = *sr.Message + } + statusReasonsList = append(statusReasonsList, currentSR) + } + d.Set(isVolumeStatusReasons, statusReasonsList) + } + d.Set(isVolumeTags, vol.UserTags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") + d.Set(flex.ResourceName, *vol.Name) + d.Set(flex.ResourceCRN, *vol.CRN) + d.Set(flex.ResourceStatus, *vol.Status) + if vol.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, vol.ResourceGroup.Name) + d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) + } + d.Set(isVolumeStatusReasons, statusReasonsList) + } + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") + d.Set(flex.ResourceName, *vol.Name) + d.Set(flex.ResourceCRN, *vol.CRN) + d.Set(flex.ResourceStatus, *vol.Status) + if vol.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, vol.ResourceGroup.Name) + d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) + } + return nil +} diff --git a/ibm/data_source_ibm_is_volume_profile.go b/ibm/service/vpc/data_source_ibm_is_volume_profile.go similarity index 95% rename from ibm/data_source_ibm_is_volume_profile.go rename to ibm/service/vpc/data_source_ibm_is_volume_profile.go index 31eb39aa3..26dab6293 100644 --- a/ibm/data_source_ibm_is_volume_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_volume_profile.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "github.com/IBM/vpc-go-sdk/vpcv1" @@ -13,7 +13,7 @@ const ( isVolumeProfileFamily = "family" ) -func dataSourceIBMISVolumeProfile() *schema.Resource { +func DataSourceIBMISVolumeProfile() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISVolumeProfileRead, diff --git a/ibm/service/vpc/data_source_ibm_is_volume_profile_test.go b/ibm/service/vpc/data_source_ibm_is_volume_profile_test.go new file mode 100644 index 000000000..f59a29437 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volume_profile_test.go @@ -0,0 +1,39 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISVolumeProfileDataSource_basic(t *testing.T) { + resName := "data.ibm_is_volume_profile.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeProfileDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", acc.VolumeProfileName), + resource.TestCheckResourceAttrSet(resName, "family"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVolumeProfileDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_is_volume_profile" "test1" { + name = "%s" +}`, acc.VolumeProfileName) +} diff --git a/ibm/data_source_ibm_is_volume_profiles.go b/ibm/service/vpc/data_source_ibm_is_volume_profiles.go similarity index 86% rename from ibm/data_source_ibm_is_volume_profiles.go rename to ibm/service/vpc/data_source_ibm_is_volume_profiles.go index 88d4eb38b..7315e82f3 100644 --- a/ibm/data_source_ibm_is_volume_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_volume_profiles.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -15,7 +16,7 @@ const ( isVolumeProfiles = "profiles" ) -func dataSourceIBMISVolumeProfiles() *schema.Resource { +func DataSourceIBMISVolumeProfiles() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISVolumeProfilesRead, @@ -66,9 +67,9 @@ func volumeProfilesList(d *schema.ResourceData, meta interface{}) error { } availableProfiles, response, err := sess.ListVolumeProfiles(listVolumeProfilesOptions) if err != nil { - return fmt.Errorf("Error Fetching Volume Profiles %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching Volume Profiles %s\n%s", err, response) } - start = GetNext(availableProfiles.Next) + start = flex.GetNext(availableProfiles.Next) allrecs = append(allrecs, availableProfiles.Profiles...) if start == "" { break @@ -78,7 +79,7 @@ func volumeProfilesList(d *schema.ResourceData, meta interface{}) error { // listVolumeProfilesOptions := &vpcv1.ListVolumeProfilesOptions{} // availableProfiles, response, err := sess.ListVolumeProfiles(listVolumeProfilesOptions) // if err != nil { - // return fmt.Errorf("Error Fetching Volume Profiles %s\n%s", err, response) + // return fmt.Errorf("[ERROR] Error Fetching Volume Profiles %s\n%s", err, response) // } profilesInfo := make([]map[string]interface{}, 0) for _, profile := range allrecs { diff --git a/ibm/data_source_ibm_is_volume_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_volume_profiles_test.go similarity index 83% rename from ibm/data_source_ibm_is_volume_profiles_test.go rename to ibm/service/vpc/data_source_ibm_is_volume_profiles_test.go index a750f0c09..75568c263 100644 --- a/ibm/data_source_ibm_is_volume_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_volume_profiles_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -14,10 +16,10 @@ func TestAccIBMISVolumeProfilesDataSource_basic(t *testing.T) { resName := "data.ibm_is_volume_profiles.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISVolumeProfilesDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), diff --git a/ibm/data_source_ibm_is_volume_test.go b/ibm/service/vpc/data_source_ibm_is_volume_test.go similarity index 86% rename from ibm/data_source_ibm_is_volume_test.go rename to ibm/service/vpc/data_source_ibm_is_volume_test.go index 57665ba44..1b34155db 100644 --- a/ibm/data_source_ibm_is_volume_test.go +++ b/ibm/service/vpc/data_source_ibm_is_volume_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -17,8 +19,8 @@ func TestAccIBMISVolumeDatasource_basic(t *testing.T) { resName := "data.ibm_is_volume.testacc_dsvol" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVolumeDataSourceConfig(name, zone), diff --git a/ibm/service/vpc/data_source_ibm_is_volumes.go b/ibm/service/vpc/data_source_ibm_is_volumes.go new file mode 100644 index 000000000..1edcaa1f0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volumes.go @@ -0,0 +1,908 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isVolumes = "volumes" + isVolumesActive = "active" + isVolumesBandwidth = "bandwidth" + isVolumesBusy = "busy" + isVolumesCapacity = "capacity" + isVolumesCreatedAt = "created_at" + isVolumesCRN = "crn" + isVolumesEncryption = "encryption" + isVolumesEncryptionKey = "encryption_key" + isVolumesEncryptionKeyCRN = "crn" + isVolumesHref = "href" + isVolumesId = "id" + isVolumesIops = "iops" + isVolumesName = "name" + isVolumesOperatingSystem = "operating_system" + isVolumesOperatingSystemHref = "href" + isVolumesOperatingSystemName = "name" + isVolumesProfile = "profile" + isVolumesProfileHref = "href" + isVolumesProfileName = "name" + isVolumesResourceGroup = "resource_group" + isVolumesResourceGroupHref = "href" + isVolumesResourceGroupId = "id" + isVolumesResourceGroupName = "name" + isVolumesSourceImage = "source_image" + isVolumesSourceImageCRN = "crn" + isVolumesSourceImageDeleted = "deleted" + isVolumesSourceImageDeletedMoreInfo = "more_info" + isVolumesSourceImageHref = "href" + isVolumesSourceImageId = "id" + isVolumesSourceImageName = "name" + isVolumesSourceSnapshot = "source_snapshot" + isVolumesSourceSnapshotCRN = "crn" + isVolumesSourceSnapshotDeleted = "deleted" + isVolumesSourceSnapshotDeletedMoreInfo = "more_info" + isVolumesSourceSnapshotHref = "href" + isVolumesSourceSnapshotId = "id" + isVolumesSourceSnapshotName = "name" + isVolumesSourceSnapshotResourceType = "resource_type" + isVolumesStatus = "status" + isVolumesStatusReasons = "status_reasons" + isVolumesStatusReasonsCode = "code" + isVolumesStatusReasonsMessage = "message" + isVolumesStatusReasonsMoreInfo = "more_info" + isVolumesVolumeAttachments = "volume_attachments" + isVolumesVolumeAttachmentsDeleteVolumeOnInstanceDelete = "delete_volume_on_instance_delete" + isVolumesVolumeAttachmentsDeleted = "deleted" + isVolumesVolumeAttachmentsDeletedMoreInfo = "more_info" + isVolumesVolumeAttachmentsDevice = "device" + isVolumesVolumeAttachmentsDeviceId = "id" + isVolumesVolumeAttachmentsHref = "href" + isVolumesVolumeAttachmentsId = "id" + isVolumesVolumeAttachmentsInstance = "instance" + isVolumesVolumeAttachmentsInstanceCRN = "crn" + isVolumesVolumeAttachmentsInstanceDeleted = "deleted" + isVolumesVolumeAttachmentsInstanceDeletedMoreInfo = "more_info" + isVolumesVolumeAttachmentsInstanceHref = "href" + isVolumesVolumeAttachmentsInstanceId = "id" + isVolumesVolumeAttachmentsInstanceName = "name" + isVolumesVolumeAttachmentsName = "name" + isVolumesVolumeAttachmentsType = "type" + isVolumesZone = "zone" + isVolumesZoneHref = "href" + isVolumesZoneName = "name" +) + +func DataSourceIBMIsVolumes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVolumesRead, + + Schema: map[string]*schema.Schema{ + "volume_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Volume name identifier.", + }, + "zone_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Zone name identifier.", + }, + isVolumes: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of volumes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesActive: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether a running virtual server instance has an attachment to this volume.", + }, + isVolumesBandwidth: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum bandwidth (in megabits per second) for the volume.", + }, + isVolumesBusy: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this volume is performing an operation that must be serialized. If an operation specifies that it requires serialization, the operation will fail unless this property is `false`.", + }, + isVolumesCapacity: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The capacity to use for the volume (in gigabytes). The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isVolumesCreatedAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the volume was created.", + }, + isVolumesCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this volume.", + }, + isVolumesEncryption: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of encryption used on the volume.", + }, + isVolumesEncryptionKey: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The root key used to wrap the data encryption key for the volume.This property will be present for volumes with an `encryption` type of`user_managed`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesEncryptionKeyCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + }, + }, + }, + isVolumesHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume.", + }, + isVolumesId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this volume.", + }, + isVolumesIops: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum I/O operations per second (IOPS) to use for the volume. Applicable only to volumes using a profile `family` of `custom`.", + }, + isVolumesName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this volume.", + }, + isVolumesOperatingSystem: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The operating system associated with this volume. If absent, this volume was notcreated from an image, or the image did not include an operating system.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesOperatingSystemHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this operating system.", + }, + isVolumesOperatingSystemName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this operating system.", + }, + }, + }, + }, + isVolumesProfile: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The profile this volume uses.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesProfileHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume profile.", + }, + isVolumesProfileName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this volume profile.", + }, + }, + }, + }, + isVolumesResourceGroup: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this volume.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesResourceGroupHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + isVolumesResourceGroupId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + isVolumesResourceGroupName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + isVolumesSourceImage: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The image from which this volume was created (this may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).If absent, this volume was not created from an image.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesSourceImageCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this image.", + }, + isVolumesSourceImageDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesSourceImageDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + isVolumesSourceImageHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this image.", + }, + isVolumesSourceImageId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this image.", + }, + isVolumesSourceImageName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this image.", + }, + }, + }, + }, + isVolumesSourceSnapshot: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The snapshot from which this volume was cloned.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesSourceSnapshotCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this snapshot.", + }, + isVolumesSourceSnapshotDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesSourceSnapshotDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + isVolumesSourceSnapshotHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot.", + }, + isVolumesSourceSnapshotId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot.", + }, + isVolumesSourceSnapshotName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this snapshot.", + }, + isVolumesSourceSnapshotResourceType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + isVolumesStatus: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the volume.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the volume on which the unexpected property value was encountered.", + }, + isVolumesStatusReasons: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).The enumerated reason code values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected reason code was encountered.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesStatusReasonsCode: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason.", + }, + isVolumesStatusReasonsMessage: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason.", + }, + isVolumesStatusReasonsMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + isVolumesVolumeAttachments: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The volume attachments for this volume.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesVolumeAttachmentsDeleteVolumeOnInstanceDelete: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, when deleting the instance the volume will also be deleted.", + }, + isVolumesVolumeAttachmentsDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesVolumeAttachmentsDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + isVolumesVolumeAttachmentsDevice: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information about how the volume is exposed to the instance operating system.This property may be absent if the volume attachment's `status` is not `attached`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesVolumeAttachmentsDeviceId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A unique identifier for the device which is exposed to the instance operating system.", + }, + }, + }, + }, + isVolumesVolumeAttachmentsHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume attachment.", + }, + isVolumesVolumeAttachmentsId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this volume attachment.", + }, + isVolumesVolumeAttachmentsInstance: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The attached instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesVolumeAttachmentsInstanceCRN: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual server instance.", + }, + isVolumesVolumeAttachmentsInstanceDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesVolumeAttachmentsInstanceDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + isVolumesVolumeAttachmentsInstanceHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance.", + }, + isVolumesVolumeAttachmentsInstanceId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual server instance.", + }, + isVolumesVolumeAttachmentsInstanceName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this virtual server instance (and default system hostname).", + }, + }, + }, + }, + isVolumesVolumeAttachmentsName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this volume attachment.", + }, + isVolumesVolumeAttachmentsType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of volume attachment.", + }, + }, + }, + }, + isVolumesZone: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this volume resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumesZoneHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + isVolumesZoneName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + isVolumeTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "User Tags for the Volume", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVolumesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + // filters - volume-name and zone-name + volumeName := d.Get("volume_name").(string) + zoneName := d.Get("zone_name").(string) + + start := "" + allrecs := []vpcv1.Volume{} + + // list + for { + listVolumesOptions := &vpcv1.ListVolumesOptions{} + if start != "" { + listVolumesOptions.Start = &start + } + if volumeName != "" { + listVolumesOptions.Name = &volumeName + } + if zoneName != "" { + listVolumesOptions.ZoneName = &zoneName + } + volumeCollection, response, err := vpcClient.ListVolumesWithContext(context, listVolumesOptions) + if err != nil { + log.Printf("[DEBUG] ListVolumesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListVolumesWithContext failed %s\n%s", err, response)) + } + + start = flex.GetNext(volumeCollection.Next) + allrecs = append(allrecs, volumeCollection.Volumes...) + + if start == "" { + break + } + + } + + d.SetId(dataSourceIBMIsVolumesID(d)) + + err = d.Set(isVolumes, dataSourceVolumeCollectionFlattenVolumes(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting volumes %s", err)) + } + + return nil +} + +// dataSourceIBMIsVolumesID returns a reasonable ID for the list. +func dataSourceIBMIsVolumesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceVolumeCollectionFlattenVolumes(result []vpcv1.Volume) (volumes []map[string]interface{}) { + for _, volumesItem := range result { + volumes = append(volumes, dataSourceVolumeCollectionVolumesToMap(volumesItem)) + } + + return volumes +} + +func dataSourceVolumeCollectionVolumesToMap(volumesItem vpcv1.Volume) (volumesMap map[string]interface{}) { + volumesMap = map[string]interface{}{} + + if volumesItem.Active != nil { + volumesMap[isVolumesActive] = volumesItem.Active + } + if volumesItem.Bandwidth != nil { + volumesMap[isVolumesBandwidth] = volumesItem.Bandwidth + } + if volumesItem.Busy != nil { + volumesMap[isVolumesBusy] = volumesItem.Busy + } + if volumesItem.Capacity != nil { + volumesMap[isVolumesCapacity] = volumesItem.Capacity + } + if volumesItem.CreatedAt != nil { + volumesMap[isVolumesCreatedAt] = volumesItem.CreatedAt.String() + } + if volumesItem.CRN != nil { + volumesMap[isVolumesCRN] = volumesItem.CRN + } + if volumesItem.Encryption != nil { + volumesMap[isVolumesEncryption] = volumesItem.Encryption + } + if volumesItem.EncryptionKey != nil { + encryptionKeyList := []map[string]interface{}{} + encryptionKeyMap := dataSourceVolumeCollectionVolumesEncryptionKeyToMap(*volumesItem.EncryptionKey) + encryptionKeyList = append(encryptionKeyList, encryptionKeyMap) + volumesMap[isVolumesEncryptionKey] = encryptionKeyList + } + if volumesItem.Href != nil { + volumesMap[isVolumesHref] = volumesItem.Href + } + if volumesItem.ID != nil { + volumesMap[isVolumesId] = volumesItem.ID + } + if volumesItem.Iops != nil { + volumesMap[isVolumesIops] = volumesItem.Iops + } + if volumesItem.Name != nil { + volumesMap[isVolumesName] = volumesItem.Name + } + if volumesItem.OperatingSystem != nil { + operatingSystemList := []map[string]interface{}{} + operatingSystemMap := dataSourceVolumeCollectionVolumesOperatingSystemToMap(*volumesItem.OperatingSystem) + operatingSystemList = append(operatingSystemList, operatingSystemMap) + volumesMap[isVolumesOperatingSystem] = operatingSystemList + } + if volumesItem.Profile != nil { + profileList := []map[string]interface{}{} + profileMap := dataSourceVolumeCollectionVolumesProfileToMap(*volumesItem.Profile) + profileList = append(profileList, profileMap) + volumesMap[isVolumesProfile] = profileList + } + if volumesItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceVolumeCollectionVolumesResourceGroupToMap(*volumesItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + volumesMap[isVolumesResourceGroup] = resourceGroupList + } + if volumesItem.SourceImage != nil { + sourceImageList := []map[string]interface{}{} + sourceImageMap := dataSourceVolumeCollectionVolumesSourceImageToMap(*volumesItem.SourceImage) + sourceImageList = append(sourceImageList, sourceImageMap) + volumesMap[isVolumesSourceImage] = sourceImageList + } + if volumesItem.SourceSnapshot != nil { + sourceSnapshotList := []map[string]interface{}{} + sourceSnapshotMap := dataSourceVolumeCollectionVolumesSourceSnapshotToMap(*volumesItem.SourceSnapshot) + sourceSnapshotList = append(sourceSnapshotList, sourceSnapshotMap) + volumesMap[isVolumesSourceSnapshot] = sourceSnapshotList + } + if volumesItem.Status != nil { + volumesMap[isVolumesStatus] = volumesItem.Status + } + if volumesItem.StatusReasons != nil { + statusReasonsList := []map[string]interface{}{} + for _, statusReasonsItem := range volumesItem.StatusReasons { + statusReasonsList = append(statusReasonsList, dataSourceVolumeCollectionVolumesStatusReasonsToMap(statusReasonsItem)) + } + volumesMap[isVolumesStatusReasons] = statusReasonsList + } + if volumesItem.VolumeAttachments != nil { + volumeAttachmentsList := []map[string]interface{}{} + for _, volumeAttachmentsItem := range volumesItem.VolumeAttachments { + volumeAttachmentsList = append(volumeAttachmentsList, dataSourceVolumeCollectionVolumesVolumeAttachmentsToMap(volumeAttachmentsItem)) + } + volumesMap[isVolumesVolumeAttachments] = volumeAttachmentsList + } + if volumesItem.Zone != nil { + zoneList := []map[string]interface{}{} + zoneMap := dataSourceVolumeCollectionVolumesZoneToMap(*volumesItem.Zone) + zoneList = append(zoneList, zoneMap) + volumesMap[isVolumesZone] = zoneList + } + if volumesItem.UserTags != nil { + volumesMap[isVolumeTags] = volumesItem.UserTags + } + return volumesMap +} + +func dataSourceVolumeCollectionVolumesEncryptionKeyToMap(encryptionKeyItem vpcv1.EncryptionKeyReference) (encryptionKeyMap map[string]interface{}) { + encryptionKeyMap = map[string]interface{}{} + + if encryptionKeyItem.CRN != nil { + encryptionKeyMap[isVolumesEncryptionKeyCRN] = encryptionKeyItem.CRN + } + + return encryptionKeyMap +} + +func dataSourceVolumeCollectionVolumesOperatingSystemToMap(operatingSystemItem vpcv1.OperatingSystemReference) (operatingSystemMap map[string]interface{}) { + operatingSystemMap = map[string]interface{}{} + + if operatingSystemItem.Href != nil { + operatingSystemMap[isVolumesOperatingSystemHref] = operatingSystemItem.Href + } + if operatingSystemItem.Name != nil { + operatingSystemMap[isVolumesOperatingSystemName] = operatingSystemItem.Name + } + + return operatingSystemMap +} + +func dataSourceVolumeCollectionVolumesProfileToMap(profileItem vpcv1.VolumeProfileReference) (profileMap map[string]interface{}) { + profileMap = map[string]interface{}{} + + if profileItem.Href != nil { + profileMap[isVolumesProfileHref] = profileItem.Href + } + if profileItem.Name != nil { + profileMap[isVolumesProfileName] = profileItem.Name + } + + return profileMap +} + +func dataSourceVolumeCollectionVolumesResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap[isVolumesResourceGroupHref] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap[isVolumesResourceGroupId] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap[isVolumesResourceGroupName] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceVolumeCollectionVolumesSourceImageToMap(sourceImageItem vpcv1.ImageReference) (sourceImageMap map[string]interface{}) { + sourceImageMap = map[string]interface{}{} + + if sourceImageItem.CRN != nil { + sourceImageMap[isVolumesSourceImageCRN] = sourceImageItem.CRN + } + if sourceImageItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVolumeCollectionSourceImageDeletedToMap(*sourceImageItem.Deleted) + deletedList = append(deletedList, deletedMap) + sourceImageMap[isVolumesSourceImageDeleted] = deletedList + } + if sourceImageItem.Href != nil { + sourceImageMap[isVolumesSourceImageHref] = sourceImageItem.Href + } + if sourceImageItem.ID != nil { + sourceImageMap[isVolumesSourceImageId] = sourceImageItem.ID + } + if sourceImageItem.Name != nil { + sourceImageMap[isVolumesSourceImageName] = sourceImageItem.Name + } + + return sourceImageMap +} + +func dataSourceVolumeCollectionSourceImageDeletedToMap(deletedItem vpcv1.ImageReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[isVolumesSourceImageDeletedMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVolumeCollectionVolumesSourceSnapshotToMap(sourceSnapshotItem vpcv1.SnapshotReference) (sourceSnapshotMap map[string]interface{}) { + sourceSnapshotMap = map[string]interface{}{} + + if sourceSnapshotItem.CRN != nil { + sourceSnapshotMap[isVolumesSourceSnapshotCRN] = sourceSnapshotItem.CRN + } + if sourceSnapshotItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVolumeCollectionSourceSnapshotDeletedToMap(*sourceSnapshotItem.Deleted) + deletedList = append(deletedList, deletedMap) + sourceSnapshotMap[isVolumesSourceSnapshotDeleted] = deletedList + } + if sourceSnapshotItem.Href != nil { + sourceSnapshotMap[isVolumesSourceSnapshotHref] = sourceSnapshotItem.Href + } + if sourceSnapshotItem.ID != nil { + sourceSnapshotMap[isVolumesSourceSnapshotId] = sourceSnapshotItem.ID + } + if sourceSnapshotItem.Name != nil { + sourceSnapshotMap[isVolumesSourceSnapshotName] = sourceSnapshotItem.Name + } + if sourceSnapshotItem.ResourceType != nil { + sourceSnapshotMap[isVolumesSourceSnapshotResourceType] = sourceSnapshotItem.ResourceType + } + + return sourceSnapshotMap +} + +func dataSourceVolumeCollectionSourceSnapshotDeletedToMap(deletedItem vpcv1.SnapshotReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[isVolumesSourceSnapshotDeletedMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVolumeCollectionVolumesStatusReasonsToMap(statusReasonsItem vpcv1.VolumeStatusReason) (statusReasonsMap map[string]interface{}) { + statusReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + statusReasonsMap[isVolumesStatusReasonsCode] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + statusReasonsMap[isVolumesStatusReasonsMessage] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + statusReasonsMap[isVolumesStatusReasonsMoreInfo] = statusReasonsItem.MoreInfo + } + + return statusReasonsMap +} + +func dataSourceVolumeCollectionVolumesVolumeAttachmentsToMap(volumeAttachmentsItem vpcv1.VolumeAttachmentReferenceVolumeContext) (volumeAttachmentsMap map[string]interface{}) { + volumeAttachmentsMap = map[string]interface{}{} + + if volumeAttachmentsItem.DeleteVolumeOnInstanceDelete != nil { + volumeAttachmentsMap[isVolumesVolumeAttachmentsDeleteVolumeOnInstanceDelete] = volumeAttachmentsItem.DeleteVolumeOnInstanceDelete + } + if volumeAttachmentsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVolumeCollectionVolumeAttachmentsDeletedToMap(*volumeAttachmentsItem.Deleted) + deletedList = append(deletedList, deletedMap) + volumeAttachmentsMap[isVolumesVolumeAttachmentsDeleted] = deletedList + } + if volumeAttachmentsItem.Device != nil { + deviceList := []map[string]interface{}{} + deviceMap := dataSourceVolumeCollectionVolumeAttachmentsDeviceToMap(*volumeAttachmentsItem.Device) + deviceList = append(deviceList, deviceMap) + volumeAttachmentsMap[isVolumesVolumeAttachmentsDevice] = deviceList + } + if volumeAttachmentsItem.Href != nil { + volumeAttachmentsMap[isVolumesVolumeAttachmentsHref] = volumeAttachmentsItem.Href + } + if volumeAttachmentsItem.ID != nil { + volumeAttachmentsMap[isVolumesVolumeAttachmentsId] = volumeAttachmentsItem.ID + } + if volumeAttachmentsItem.Instance != nil { + instanceList := []map[string]interface{}{} + instanceMap := dataSourceVolumeCollectionVolumeAttachmentsInstanceToMap(*volumeAttachmentsItem.Instance) + instanceList = append(instanceList, instanceMap) + volumeAttachmentsMap[isVolumesVolumeAttachmentsInstance] = instanceList + } + if volumeAttachmentsItem.Name != nil { + volumeAttachmentsMap[isVolumesVolumeAttachmentsName] = volumeAttachmentsItem.Name + } + if volumeAttachmentsItem.Type != nil { + volumeAttachmentsMap[isVolumesVolumeAttachmentsType] = volumeAttachmentsItem.Type + } + + return volumeAttachmentsMap +} + +func dataSourceVolumeCollectionVolumeAttachmentsDeletedToMap(deletedItem vpcv1.VolumeAttachmentReferenceVolumeContextDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[isVolumesVolumeAttachmentsDeletedMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVolumeCollectionVolumeAttachmentsDeviceToMap(deviceItem vpcv1.VolumeAttachmentDevice) (deviceMap map[string]interface{}) { + deviceMap = map[string]interface{}{} + + if deviceItem.ID != nil { + deviceMap[isVolumesVolumeAttachmentsDeviceId] = deviceItem.ID + } + + return deviceMap +} + +func dataSourceVolumeCollectionVolumeAttachmentsInstanceToMap(instanceItem vpcv1.InstanceReference) (instanceMap map[string]interface{}) { + instanceMap = map[string]interface{}{} + + if instanceItem.CRN != nil { + instanceMap[isVolumesVolumeAttachmentsInstanceCRN] = instanceItem.CRN + } + if instanceItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVolumeCollectionInstanceDeletedToMap(*instanceItem.Deleted) + deletedList = append(deletedList, deletedMap) + instanceMap[isVolumesVolumeAttachmentsInstanceDeleted] = deletedList + } + if instanceItem.Href != nil { + instanceMap[isVolumesVolumeAttachmentsInstanceHref] = instanceItem.Href + } + if instanceItem.ID != nil { + instanceMap[isVolumesVolumeAttachmentsInstanceId] = instanceItem.ID + } + if instanceItem.Name != nil { + instanceMap[isVolumesVolumeAttachmentsInstanceName] = instanceItem.Name + } + + return instanceMap +} + +func dataSourceVolumeCollectionInstanceDeletedToMap(deletedItem vpcv1.InstanceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[isVolumesVolumeAttachmentsInstanceDeletedMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVolumeCollectionVolumesZoneToMap(zoneItem vpcv1.ZoneReference) (zoneMap map[string]interface{}) { + zoneMap = map[string]interface{}{} + + if zoneItem.Href != nil { + zoneMap[isVolumesZoneHref] = zoneItem.Href + } + if zoneItem.Name != nil { + zoneMap[isVolumesZoneName] = zoneItem.Name + } + + return zoneMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_volumes_test.go b/ibm/service/vpc/data_source_ibm_is_volumes_test.go new file mode 100644 index 000000000..b5f00d6bf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volumes_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVolumesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVolumesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "volumes.#"), + ), + }, + { + Config: testAccCheckIBMIsVolumesDataSourceConfigFilterByZone(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "volumes.#"), + ), + }, + { + Config: testAccCheckIBMIsVolumesDataSourceConfigFilterByName(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_volumes.is_volumes", "volumes.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVolumesDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_volumes" "is_volumes" { + } + `) +} + +func testAccCheckIBMIsVolumesDataSourceConfigFilterByZone() string { + return fmt.Sprintf(` + data "ibm_is_volumes" "is_volumes" { + zone_name = "us-south-1" + } + `) +} + +func testAccCheckIBMIsVolumesDataSourceConfigFilterByName() string { + return fmt.Sprintf(` + data "ibm_is_volumes" "is_volumes" { + volume_name = "worrier-mailable-timpani-scowling" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc.go b/ibm/service/vpc/data_source_ibm_is_vpc.go new file mode 100644 index 000000000..7e1a79ef5 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc.go @@ -0,0 +1,590 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "reflect" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMISVPC() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISVPCRead, + + Schema: map[string]*schema.Schema{ + isVPCDefaultNetworkACL: { + Type: schema.TypeString, + Computed: true, + }, + + isVPCClassicAccess: { + Type: schema.TypeBool, + Computed: true, + }, + + isVPCDefaultRoutingTable: { + Type: schema.TypeString, + Computed: true, + Description: "Default routing table associated with VPC", + }, + + isVPCName: { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{isVPCName, "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_subnet", isVPCName), + }, + "identifier": { + Type: schema.TypeString, + ExactlyOneOf: []string{isVPCName, "identifier"}, + Optional: true, + }, + + isVPCDefaultNetworkACLName: { + Type: schema.TypeString, + Computed: true, + Description: "Default Network ACL name", + }, + + isVPCDefaultSecurityGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "Default security group name", + }, + + isVPCDefaultSecurityGroupCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Default security group CRN", + }, + + isVPCDefaultNetworkACLCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Default Network ACL CRN", + }, + + isVPCDefaultRoutingTableName: { + Type: schema.TypeString, + Computed: true, + Description: "Default routing table name", + }, + + isVPCResourceGroup: { + Type: schema.TypeString, + Computed: true, + }, + + isVPCStatus: { + Type: schema.TypeString, + Computed: true, + }, + + isVPCDefaultSecurityGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Security group associated with VPC", + }, + + isVPCTags: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + }, + + isVPCCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + cseSourceAddresses: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud service endpoint IP Address", + }, + + "zone_name": { + Type: schema.TypeString, + Computed: true, + Description: "Location info of CSE Address", + }, + }, + }, + }, + + isVPCSecurityGroupList: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVPCSecurityGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "Security group name", + }, + + isVPCSecurityGroupID: { + Type: schema.TypeString, + Computed: true, + Description: "Security group id", + }, + + isSecurityGroupRules: { + Type: schema.TypeList, + Computed: true, + Description: "Security Rules", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + isVPCSecurityGroupRuleID: { + Type: schema.TypeString, + Computed: true, + Description: "Rule ID", + }, + + isVPCSecurityGroupRuleDirection: { + Type: schema.TypeString, + Computed: true, + Description: "Direction of traffic to enforce, either inbound or outbound", + }, + + isVPCSecurityGroupRuleIPVersion: { + Type: schema.TypeString, + Computed: true, + Description: "IP version: ipv4", + }, + + isVPCSecurityGroupRuleRemote: { + Type: schema.TypeString, + Computed: true, + Description: "Security group id: an IP address, a CIDR block, or a single security group identifier", + }, + + isVPCSecurityGroupRuleType: { + Type: schema.TypeInt, + Computed: true, + }, + + isVPCSecurityGroupRuleCode: { + Type: schema.TypeInt, + Computed: true, + }, + + isVPCSecurityGroupRulePortMin: { + Type: schema.TypeInt, + Computed: true, + }, + + isVPCSecurityGroupRulePortMax: { + Type: schema.TypeInt, + Computed: true, + }, + + isVPCSecurityGroupRuleProtocol: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + subnetsList: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "subent name", + }, + + "id": { + Type: schema.TypeString, + Computed: true, + Description: "subnet ID", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "subnet status", + }, + + "zone": { + Type: schema.TypeString, + Computed: true, + Description: "subnet location", + }, + + totalIPV4AddressCount: { + Type: schema.TypeInt, + Computed: true, + Description: "Total IPv4 address count in the subnet", + }, + + availableIPV4AddressCount: { + Type: schema.TypeInt, + Computed: true, + Description: "Available IPv4 address count in the subnet", + }, + }, + }, + }, + }, + } +} + +func DataSourceIBMISVpcValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVPCName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + ibmISVpcDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpc", Schema: validateSchema} + return &ibmISVpcDataSourceValidator +} + +func dataSourceIBMISVPCRead(d *schema.ResourceData, meta interface{}) error { + name := d.Get(isVPCName).(string) + id := d.Get("identifier").(string) + err := vpcGetByNameOrId(d, meta, name, id) + if err != nil { + return err + } + return nil +} + +func vpcGetByNameOrId(d *schema.ResourceData, meta interface{}, name, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + flag := false + if id != "" { + getVpcsOptions := &vpcv1.GetVPCOptions{ + ID: &id, + } + vpcGet, response, err := sess.GetVPC(getVpcsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching vpc %s\n%s", err, response) + } + flag = true + setVpcDetails(d, vpcGet, meta, sess) + } else { + start := "" + allrecs := []vpcv1.VPC{} + for { + listVpcsOptions := &vpcv1.ListVpcsOptions{} + if start != "" { + listVpcsOptions.Start = &start + } + vpcs, response, err := sess.ListVpcs(listVpcsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Fetching vpcs %s\n%s", err, response) + } + start = flex.GetNext(vpcs.Next) + allrecs = append(allrecs, vpcs.Vpcs...) + if start == "" { + break + } + } + for _, v := range allrecs { + if *v.Name == name { + flag = true + setVpcDetails(d, &v, meta, sess) + } + } + } + if !flag { + return fmt.Errorf("[ERROR] No VPC found with name %s", name) + } + return nil +} + +func setVpcDetails(d *schema.ResourceData, vpc *vpcv1.VPC, meta interface{}, sess *vpcv1.VpcV1) error { + if vpc != nil { + d.SetId(*vpc.ID) + d.Set("identifier", *vpc.ID) + d.Set(isVPCName, *vpc.Name) + d.Set(isVPCClassicAccess, *vpc.ClassicAccess) + d.Set(isVPCStatus, *vpc.Status) + if vpc.ResourceGroup != nil { + d.Set(isVPCResourceGroup, *vpc.ResourceGroup.ID) + } + if vpc.DefaultNetworkACL != nil { + d.Set(isVPCDefaultNetworkACLName, *vpc.DefaultNetworkACL.Name) + d.Set(isVPCDefaultNetworkACL, *vpc.DefaultNetworkACL.ID) + d.Set(isVPCDefaultNetworkACLCRN, vpc.DefaultNetworkACL.CRN) + } else { + d.Set(isVPCDefaultNetworkACL, nil) + } + if vpc.DefaultRoutingTable != nil { + d.Set(isVPCDefaultRoutingTableName, *vpc.DefaultRoutingTable.Name) + d.Set(isVPCDefaultRoutingTable, *vpc.DefaultRoutingTable.ID) + } + if vpc.DefaultSecurityGroup != nil { + d.Set(isVPCDefaultSecurityGroupName, *vpc.DefaultSecurityGroup.Name) + d.Set(isVPCDefaultSecurityGroup, *vpc.DefaultSecurityGroup.ID) + d.Set(isVPCDefaultSecurityGroupCRN, vpc.DefaultSecurityGroup.CRN) + } else { + d.Set(isVPCDefaultSecurityGroup, nil) + } + tags, err := flex.GetTagsUsingCRN(meta, *vpc.CRN) + if err != nil { + log.Printf( + "An error occured during reading of vpc (%s) tags : %s", d.Id(), err) + } + d.Set(isVPCTags, tags) + d.Set(isVPCCRN, *vpc.CRN) + + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/vpcs") + d.Set(flex.ResourceName, *vpc.Name) + d.Set(flex.ResourceCRN, *vpc.CRN) + d.Set(flex.ResourceStatus, *vpc.Status) + if vpc.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, *vpc.ResourceGroup.Name) + } + //set the cse ip addresses info + if vpc.CseSourceIps != nil { + cseSourceIpsList := make([]map[string]interface{}, 0) + for _, sourceIP := range vpc.CseSourceIps { + currentCseSourceIp := map[string]interface{}{} + if sourceIP.IP != nil { + currentCseSourceIp["address"] = *sourceIP.IP.Address + currentCseSourceIp["zone_name"] = *sourceIP.Zone.Name + cseSourceIpsList = append(cseSourceIpsList, currentCseSourceIp) + } + } + d.Set(cseSourceAddresses, cseSourceIpsList) + } + + // adding pagination support for subnets inside vpc + + startSub := "" + allrecsSub := []vpcv1.Subnet{} + options := &vpcv1.ListSubnetsOptions{} + + for { + if startSub != "" { + options.Start = &startSub + } + s, response, err := sess.ListSubnets(options) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching subnets %s\n%s", err, response) + } + startSub = flex.GetNext(s.Next) + allrecsSub = append(allrecsSub, s.Subnets...) + if startSub == "" { + break + } + } + if err == nil { + subnetsInfo := make([]map[string]interface{}, 0) + for _, subnet := range allrecsSub { + if *subnet.VPC.ID == d.Id() { + l := map[string]interface{}{ + "name": *subnet.Name, + "id": *subnet.ID, + "status": *subnet.Status, + "zone": *subnet.Zone.Name, + totalIPV4AddressCount: *subnet.TotalIpv4AddressCount, + availableIPV4AddressCount: *subnet.AvailableIpv4AddressCount, + } + subnetsInfo = append(subnetsInfo, l) + } + } + d.Set(subnetsList, subnetsInfo) + } + + // adding pagination support for sg inside vpc + + startSg := "" + allrecsSg := []vpcv1.SecurityGroup{} + + for { + vpcId := d.Id() + listSgOptions := &vpcv1.ListSecurityGroupsOptions{ + VPCID: &vpcId, + } + if startSg != "" { + listSgOptions.Start = &startSg + } + sgs, response, err := sess.ListSecurityGroups(listSgOptions) + if err != nil || sgs == nil { + return fmt.Errorf("[ERROR] Error fetching Security Groups %s\n%s", err, response) + } + if *sgs.TotalCount == int64(0) { + break + } + startSg = flex.GetNext(sgs.Next) + allrecsSg = append(allrecsSg, sgs.SecurityGroups...) + + if startSg == "" { + break + } + + } + + securityGroupList := make([]map[string]interface{}, 0) + + for _, group := range allrecsSg { + g := make(map[string]interface{}) + + g[isVPCSecurityGroupName] = *group.Name + g[isVPCSecurityGroupID] = *group.ID + + rules := make([]map[string]interface{}, 0) + for _, sgrule := range group.Rules { + switch reflect.TypeOf(sgrule).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + r := make(map[string]interface{}) + if rule.Code != nil { + r[isVPCSecurityGroupRuleCode] = int(*rule.Code) + } + if rule.Type != nil { + r[isVPCSecurityGroupRuleType] = int(*rule.Type) + } + r[isVPCSecurityGroupRuleDirection] = *rule.Direction + r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.Protocol != nil { + r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol + } + r[isVPCSecurityGroupRuleID] = *rule.ID + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isVPCSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isVPCSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + r := make(map[string]interface{}) + r[isVPCSecurityGroupRuleDirection] = *rule.Direction + r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.Protocol != nil { + r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol + } + r[isVPCSecurityGroupRuleID] = *rule.ID + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isVPCSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isVPCSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + r := make(map[string]interface{}) + r[isVPCSecurityGroupRuleDirection] = *rule.Direction + r[isVPCSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.PortMin != nil { + r[isVPCSecurityGroupRulePortMin] = int(*rule.PortMin) + } + if rule.PortMax != nil { + r[isVPCSecurityGroupRulePortMax] = int(*rule.PortMax) + } + r[isVPCSecurityGroupRuleID] = *rule.ID + if rule.Protocol != nil { + r[isVPCSecurityGroupRuleProtocol] = *rule.Protocol + } + + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isVPCSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isVPCSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isVPCSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + } + } + g[isVPCSgRules] = rules + securityGroupList = append(securityGroupList, g) + } + + d.Set(isVPCSecurityGroupList, securityGroupList) + + return nil + } + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix.go b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix.go new file mode 100644 index 000000000..a7d9de147 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix.go @@ -0,0 +1,239 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPCAddressPrefix() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPCAddressPrefixRead, + + Schema: map[string]*schema.Schema{ + "vpc": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpc", "vpc_name"}, + Description: "The VPC identifier.", + }, + "vpc_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpc", "vpc_name"}, + Description: "The VPC name.", + }, + "address_prefix": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"address_prefix", "address_prefix_name"}, + Description: "The address prefix identifier.", + }, + "address_prefix_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"address_prefix", "address_prefix_name"}, + Description: "The address prefix name.", + }, + "cidr": { + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block for this prefix.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the prefix was created.", + }, + "has_subnets": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether subnets exist with addresses from this prefix.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this address prefix.", + }, + "is_default": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", + }, + "zone": { + Type: schema.TypeList, + Computed: true, + Description: "The zone this address prefix resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPCAddressPrefixRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + vpc_id := d.Get("vpc").(string) + address_prefix_id := d.Get("address_prefix").(string) + address_prefix_name := d.Get("address_prefix_name").(string) + vpc_name := d.Get("vpc_name").(string) + var addressPrefix *vpcv1.AddressPrefix + if vpc_id == "" { + start := "" + allrecs := []vpcv1.VPC{} + for { + listVpcsOptions := &vpcv1.ListVpcsOptions{} + if start != "" { + listVpcsOptions.Start = &start + } + vpcs, response, err := vpcClient.ListVpcs(listVpcsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("Error Fetching vpcs %s\n%s", err, response)) + } + start = flex.GetNext(vpcs.Next) + allrecs = append(allrecs, vpcs.Vpcs...) + if start == "" { + break + } + } + vpc_found := false + for _, vpc := range allrecs { + if *vpc.Name == vpc_name { + vpc_id = *vpc.ID + vpc_found = true + break + } + } + if !vpc_found { + log.Printf("[DEBUG] VPC with given name not found %s\n", vpc_name) + return diag.FromErr(fmt.Errorf("VPC with given name not found %s\n", vpc_name)) + } + } + if address_prefix_id != "" { + getVPCAddressPrefixOptions := &vpcv1.GetVPCAddressPrefixOptions{} + + getVPCAddressPrefixOptions.SetVPCID(vpc_id) + getVPCAddressPrefixOptions.SetID(address_prefix_id) + + addressPrefix1, response, err := vpcClient.GetVPCAddressPrefixWithContext(context, getVPCAddressPrefixOptions) + if err != nil { + log.Printf("[DEBUG] GetVPCAddressPrefixWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVPCAddressPrefixWithContext failed %s\n%s", err, response)) + } + addressPrefix = addressPrefix1 + + } else { + start := "" + allrecs := []vpcv1.AddressPrefix{} + listVpcAddressPrefixesOptions := &vpcv1.ListVPCAddressPrefixesOptions{} + + listVpcAddressPrefixesOptions.SetVPCID(vpc_id) + for { + if start != "" { + listVpcAddressPrefixesOptions.Start = &start + } + addressPrefixCollection, response, err := vpcClient.ListVPCAddressPrefixesWithContext(context, listVpcAddressPrefixesOptions) + if err != nil { + log.Printf("[DEBUG] ListVpcAddressPrefixesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListVpcAddressPrefixesWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(addressPrefixCollection.Next) + allrecs = append(allrecs, addressPrefixCollection.AddressPrefixes...) + if start == "" { + break + } + } + address_prefix_found := false + for _, addressPrefixItem := range allrecs { + if *addressPrefixItem.Name == address_prefix_name { + addressPrefix = &addressPrefixItem + address_prefix_found = true + break + } + } + if !address_prefix_found { + log.Printf("[DEBUG] Address Prefix with given name not found %s\n", address_prefix_name) + return diag.FromErr(fmt.Errorf("Address Prefix with given name not found %s\n", address_prefix_name)) + } + } + d.SetId(*addressPrefix.ID) + if err = d.Set("cidr", addressPrefix.CIDR); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cidr: %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(addressPrefix.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("has_subnets", addressPrefix.HasSubnets); err != nil { + return diag.FromErr(fmt.Errorf("Error setting has_subnets: %s", err)) + } + + if err = d.Set("href", addressPrefix.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("is_default", addressPrefix.IsDefault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_default: %s", err)) + } + + if err = d.Set("name", addressPrefix.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + zone := []map[string]interface{}{} + if addressPrefix.Zone != nil { + modelMap, err := dataSourceIBMIsVPCAddressPrefixZoneReferenceToMap(addressPrefix.Zone) + if err != nil { + return diag.FromErr(err) + } + zone = append(zone, modelMap) + } + if err = d.Set("zone", zone); err != nil { + return diag.FromErr(fmt.Errorf("Error setting zone %s", err)) + } + + return nil +} + +func dataSourceIBMIsVPCAddressPrefixZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Href != nil { + modelMap["href"] = model.Href + } + if model.Name != nil { + modelMap["name"] = model.Name + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix_test.go new file mode 100644 index 000000000..b3a96fb7e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefix_test.go @@ -0,0 +1,105 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPCAddressPrefixDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tfvpcuat-%d", acctest.RandIntRange(10, 100)) + prefixName := fmt.Sprintf("tfaddprename-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPCAddressPrefixDataSourceConfigBasic(name, prefixName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "has_subnets"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix", "zone.#"), + ), + }, + { + Config: testAccCheckIBMIsVPCAddressPrefixDataSourceConfigBasic(name, prefixName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "has_subnets"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix1", "zone.#"), + ), + }, + { + Config: testAccCheckIBMIsVPCAddressPrefixDataSourceConfigBasic(name, prefixName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "has_subnets"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix2", "zone.#"), + ), + }, + { + Config: testAccCheckIBMIsVPCAddressPrefixDataSourceConfigBasic(name, prefixName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "has_subnets"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefix.is_vpc_address_prefix3", "zone.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPCAddressPrefixDataSourceConfigBasic(name, prefixName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + address_prefix_management = "manual" + } + resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix" { + name = "%s" + zone = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + cidr = "%s" + is_default = true + } + data "ibm_is_vpc_address_prefix" "is_vpc_address_prefix" { + vpc = ibm_is_vpc.testacc_vpc.id + address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix + } + data "ibm_is_vpc_address_prefix" "is_vpc_address_prefix1" { + vpc_name = ibm_is_vpc.testacc_vpc.name + address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix + } + data "ibm_is_vpc_address_prefix" "is_vpc_address_prefix2" { + vpc = ibm_is_vpc.testacc_vpc.id + address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name + } + data "ibm_is_vpc_address_prefix" "is_vpc_address_prefix3" { + vpc_name = ibm_is_vpc.testacc_vpc.name + address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name + } + `, name, prefixName, acc.ISZoneName, acc.ISAddressPrefixCIDR) +} diff --git a/ibm/data_source_ibm_is_vpc_address_prefixes.go b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes.go similarity index 92% rename from ibm/data_source_ibm_is_vpc_address_prefixes.go rename to ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes.go index e3fee9276..172e4ae1c 100644 --- a/ibm/data_source_ibm_is_vpc_address_prefixes.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,80 +9,82 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM/vpc-go-sdk/vpcv1" ) -func dataSourceIbmIsVpcAddressPrefixes() *schema.Resource { +func DataSourceIbmIsVpcAddressPrefixes() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIbmIsVpcAddressPrefixRead, Schema: map[string]*schema.Schema{ - "vpc": &schema.Schema{ + "vpc": { Type: schema.TypeString, Required: true, Description: "The VPC identifier.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Description: "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", }, - "address_prefixes": &schema.Schema{ + "address_prefixes": { Type: schema.TypeList, Computed: true, Description: "Collection of address prefixes.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cidr": &schema.Schema{ + "cidr": { Type: schema.TypeString, Computed: true, Description: "The CIDR block for this prefix.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the prefix was created.", }, - "has_subnets": &schema.Schema{ + "has_subnets": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether subnets exist with addresses from this prefix.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this address prefix.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this address prefix.", }, - "is_default": &schema.Schema{ + "is_default": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeList, Computed: true, Description: "The zone this address prefix resides in.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this zone.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this zone.", @@ -99,7 +101,7 @@ func dataSourceIbmIsVpcAddressPrefixes() *schema.Resource { func dataSourceIbmIsVpcAddressPrefixRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -119,7 +121,7 @@ func dataSourceIbmIsVpcAddressPrefixRead(context context.Context, d *schema.Reso log.Printf("[DEBUG] ListVpcAddressPrefixesWithContext failed %s\n%s", err, response) return diag.FromErr(fmt.Errorf("ListVpcAddressPrefixesWithContext failed %s\n%s", err, response)) } - start = GetNext(addressPrefixCollection.Next) + start = flex.GetNext(addressPrefixCollection.Next) allrecs = append(allrecs, addressPrefixCollection.AddressPrefixes...) if start == "" { break @@ -155,7 +157,7 @@ func dataSourceIbmIsVpcAddressPrefixRead(context context.Context, d *schema.Reso if matchAddressPrefixes != nil { err = d.Set("address_prefixes", dataSourceAddressPrefixCollectionFlattenAddressPrefixes(matchAddressPrefixes)) if err != nil { - return diag.FromErr(fmt.Errorf("Error setting address_prefixes %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting address_prefixes %s", err)) } } diff --git a/ibm/data_source_ibm_is_vpc_address_prefixes_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes_test.go similarity index 88% rename from ibm/data_source_ibm_is_vpc_address_prefixes_test.go rename to ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes_test.go index 408f1fa59..230c040ff 100644 --- a/ibm/data_source_ibm_is_vpc_address_prefixes_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_address_prefixes_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,10 +17,10 @@ func TestAccIbmIsVpcAddressPrefixesDataSourceBasic(t *testing.T) { name := fmt.Sprintf("tfvpcuat-%d", acctest.RandIntRange(10, 100)) prefixName := fmt.Sprintf("tfaddprename-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIsVpcAddressPrefixDataSourceConfigBasic(name, prefixName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_is_vpc_address_prefixes.is_vpc_address_prefix", "id"), diff --git a/ibm/data_source_ibm_is_vpc_default_routing_table.go b/ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table.go similarity index 98% rename from ibm/data_source_ibm_is_vpc_default_routing_table.go rename to ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table.go index e544e61ba..4cff866b7 100644 --- a/ibm/data_source_ibm_is_vpc_default_routing_table.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "log" @@ -25,7 +25,7 @@ const ( isDefaultRTDefault = "is_default" ) -func dataSourceIBMISVPCDefaultRoutingTable() *schema.Resource { +func DataSourceIBMISVPCDefaultRoutingTable() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISVPCDefaultRoutingTableGet, Schema: map[string]*schema.Schema{ diff --git a/ibm/data_source_ibm_is_vpc_default_routing_table_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table_test.go similarity index 87% rename from ibm/data_source_ibm_is_vpc_default_routing_table_test.go rename to ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table_test.go index 4ad9b7ca2..6cd6e15f3 100644 --- a/ibm/data_source_ibm_is_vpc_default_routing_table_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_default_routing_table_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMISVPCDefaultRoutingTableDataSource_basic(t *testing.T) { node := "data.ibm_is_vpc_default_routing_table.def_route_table" vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVPCDefaultRoutingTableDataSourceConfig(vpcname), diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go new file mode 100644 index 000000000..76ee2e13a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go @@ -0,0 +1,382 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + rtRoutes = "routes" + rtCrn = "crn" +) + +func DataSourceIBMIBMIsVPCRoutingTable() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIBMIsVPCRoutingTableRead, + + Schema: map[string]*schema.Schema{ + isVpcID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPC identifier.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{rName, isRoutingTableID}, + ConflictsWith: []string{isRoutingTableID}, + Description: "The user-defined name for this routing table.", + }, + isRoutingTableAcceptRoutesFrom: { + Type: schema.TypeList, + Computed: true, + Description: "The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + isRoutingTableID: &schema.Schema{ + Type: schema.TypeString, + AtLeastOneOf: []string{rName, isRoutingTableID}, + ConflictsWith: []string{rName}, + Optional: true, + Description: "The routing table identifier.", + }, + + rtCreateAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this routing table was created.", + }, + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this routing table.", + }, + rtIsDefault: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this is the default routing table for this VPC.", + }, + rtLifecycleState: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the routing table.", + }, + rtResourceType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + rtRouteDirectLinkIngress: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this routing table is used to route traffic that originates from[Direct Link](https://cloud.ibm.com/docs/dl/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + }, + rtRouteTransitGatewayIngress: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this routing table is used to route traffic that originates from from [Transit Gateway](https://cloud.ibm.com/cloud/transit-gateway/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + }, + rtRouteVPCZoneIngress: &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this routing table is used to route traffic that originates from subnets in other zones in this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + }, + rtRoutes: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The routes for this routing table.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this route.", + }, + rId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this route.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this route.", + }, + }, + }, + }, + rtSubnets: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The subnets to which this routing table is attached.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rtCrn: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + rDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + rId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIBMIsVPCRoutingTableRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + vpcId := d.Get(isVpcID).(string) + rtId := d.Get(isRoutingTableID).(string) + routingTableName := d.Get(rtName).(string) + var routingTable *vpcv1.RoutingTable + if rtId != "" { + getVPCRoutingTableOptions := &vpcv1.GetVPCRoutingTableOptions{ + VPCID: &vpcId, + ID: &rtId, + } + + rt, response, err := vpcClient.GetVPCRoutingTableWithContext(context, getVPCRoutingTableOptions) + if err != nil { + log.Printf("[DEBUG] GetVPCRoutingTableWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPCRoutingTableWithContext failed %s\n%s", err, response)) + } + routingTable = rt + } else { + start := "" + allrecs := []vpcv1.RoutingTable{} + for { + listOptions := &vpcv1.ListVPCRoutingTablesOptions{ + VPCID: &vpcId, + } + if start != "" { + listOptions.Start = &start + } + result, detail, err := vpcClient.ListVPCRoutingTables(listOptions) + if err != nil { + log.Printf("[ERROR] Error reading list of VPC Routing Tables:%s\n%s", err, detail) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPCRoutingTables failed %s\n%s", err, detail)) + } + start = flex.GetNext(result.Next) + allrecs = append(allrecs, result.RoutingTables...) + if start == "" { + break + } + } + for _, r := range allrecs { + if *r.Name == routingTableName { + routingTable = &r + } + } + } + + d.SetId(*routingTable.ID) + + if err = d.Set(rtCreateAt, flex.DateTimeToString(routingTable.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + acceptRoutesFromInfo := make([]map[string]interface{}, 0) + if routingTable.AcceptRoutesFrom != nil { + for _, AcceptRoutesFrom := range routingTable.AcceptRoutesFrom { + l := map[string]interface{}{} + if AcceptRoutesFrom.ResourceType != nil { + l["resource_type"] = *AcceptRoutesFrom.ResourceType + acceptRoutesFromInfo = append(acceptRoutesFromInfo, l) + } + } + } + if err = d.Set(isRoutingTableAcceptRoutesFrom, acceptRoutesFromInfo); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting accept_routes_from %s", err)) + } + + if err = d.Set(isRoutingTableID, routingTable.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting routing_table: %s", err)) + } + + if err = d.Set(rtHref, routingTable.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + + if err = d.Set(rtIsDefault, routingTable.IsDefault); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting is_default: %s", err)) + } + + if err = d.Set(rtLifecycleState, routingTable.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + + if err = d.Set(rName, routingTable.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set(rtResourceType, routingTable.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + if err = d.Set(rtRouteDirectLinkIngress, routingTable.RouteDirectLinkIngress); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting route_direct_link_ingress: %s", err)) + } + + if err = d.Set(rtRouteTransitGatewayIngress, routingTable.RouteTransitGatewayIngress); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting route_transit_gateway_ingress: %s", err)) + } + + if err = d.Set(rtRouteVPCZoneIngress, routingTable.RouteVPCZoneIngress); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting route_vpc_zone_ingress: %s", err)) + } + + routes := []map[string]interface{}{} + if routingTable.Routes != nil { + for _, modelItem := range routingTable.Routes { + modelMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + routes = append(routes, modelMap) + } + } + if err = d.Set(rtRoutes, routes); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting routes %s", err)) + } + + subnets := []map[string]interface{}{} + if routingTable.Subnets != nil { + for _, modelItem := range routingTable.Subnets { + modelMap, err := dataSourceIBMIBMIsVPCRoutingTableSubnetReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + subnets = append(subnets, modelMap) + } + } + if err = d.Set(rtSubnets, subnets); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnets %s", err)) + } + + return nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteReferenceToMap(model *vpcv1.RouteReference) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap[rDeleted] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap[rtHref] = *model.Href + } + if model.ID != nil { + modelMap[rId] = *model.ID + } + if model.Name != nil { + modelMap[rName] = *model.Name + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteReferenceDeletedToMap(model *vpcv1.RouteReferenceDeleted) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.MoreInfo != nil { + modelMap[rMoreInfo] = *model.MoreInfo + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.CRN != nil { + modelMap[rtCrn] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIBMIsVPCRoutingTableSubnetReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap[rDeleted] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap[rtHref] = *model.Href + } + if model.ID != nil { + modelMap[rId] = *model.ID + } + if model.Name != nil { + modelMap[rName] = *model.Name + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.MoreInfo != nil { + modelMap[rMoreInfo] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route.go new file mode 100644 index 000000000..df8c8125b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route.go @@ -0,0 +1,425 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + rDeleted = "deleted" + rAddress = "address" + rMoreInfo = "more_info" + rId = "id" +) + +func DataSourceIBMIBMIsVPCRoutingTableRoute() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIBMIsVPCRoutingTableRouteRead, + + Schema: map[string]*schema.Schema{ + isVpcID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPC identifier.", + }, + isRoutingTableID: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The routing table identifier.", + }, + isRoutingTableRouteID: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{rName, isRoutingTableRouteID}, + ConflictsWith: []string{rName}, + Description: "The VPC routing table route identifier.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{rName, isRoutingTableRouteID}, + ConflictsWith: []string{isRoutingTableRouteID}, + Description: "The user-defined name for this route.", + }, + rAction: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The action to perform with a packet matching the route:- `delegate`: delegate to the system's built-in routes- `delegate_vpc`: delegate to the system's built-in routes, ignoring Internet-bound routes- `deliver`: deliver the packet to the specified `next_hop`- `drop`: drop the packet.", + }, + rtCreateAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the route was created.", + }, + "creator": { + Type: schema.TypeList, + Computed: true, + Description: "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's CRN.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN gateway.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + rDestination: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The destination of the route.", + }, + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this route.", + }, + rtLifecycleState: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the route.", + }, + rNextHop: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If `action` is `deliver`, the next hop that packets will be delivered to. Forother `action` values, its `address` will be `0.0.0.0`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rAddress: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + rDeleted: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + rId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + rtResourceType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "origin": { + Type: schema.TypeString, + Computed: true, + Description: "The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + }, + rZone: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone the route applies to. (Traffic from subnets in this zone will besubject to this route.).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rtHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + rName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + vpcID := d.Get(isVpcID).(string) + routingTableId := d.Get("routing_table").(string) + routeId := d.Get("route_id").(string) + routeName := d.Get("name").(string) + var route *vpcv1.Route + + if routeId != "" { + getVPCRoutingTableRouteOptions := &vpcv1.GetVPCRoutingTableRouteOptions{} + getVPCRoutingTableRouteOptions.SetVPCID(vpcID) + getVPCRoutingTableRouteOptions.SetRoutingTableID(routingTableId) + getVPCRoutingTableRouteOptions.SetID(routeId) + + r, response, err := vpcClient.GetVPCRoutingTableRouteWithContext(context, getVPCRoutingTableRouteOptions) + if err != nil { + log.Printf("[DEBUG] GetVPCRoutingTableRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPCRoutingTableRouteWithContext failed %s\n%s", err, response)) + } + route = r + } else { + start := "" + allrecs := []vpcv1.Route{} + for { + listVpcRoutingTablesRoutesOptions := &vpcv1.ListVPCRoutingTableRoutesOptions{ + VPCID: &vpcID, + RoutingTableID: &routingTableId, + } + + if start != "" { + listVpcRoutingTablesRoutesOptions.Start = &start + } + result, detail, err := vpcClient.ListVPCRoutingTableRoutes(listVpcRoutingTablesRoutesOptions) + if err != nil { + log.Printf("Error reading list of VPC Routing Table Routes:%s\n%s", err, detail) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPCRoutingTableRouteWithContext failed %s\n%s", err, detail)) + } + start = flex.GetNext(result.Next) + allrecs = append(allrecs, result.Routes...) + if start == "" { + break + } + } + + for _, r := range allrecs { + if *r.Name == routeName { + route = &r + break + } + } + if route == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Route not found with name: %s", routeName)) + } + } + + d.SetId(*route.ID) + + if err = d.Set(rAction, route.Action); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action: %s", err)) + } + + if err = d.Set(rtCreateAt, flex.DateTimeToString(route.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + + // creator changes + creator := []map[string]interface{}{} + if route.Creator != nil { + mm, err := dataSourceIBMIsRouteCreatorToMap(route.Creator) + if err != nil { + log.Printf("Error reading list of VPC Routing Table Routes' creator:%s", err) + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching creator: %s", err)) + } + creator = append(creator, mm) + + } + if err = d.Set("creator", creator); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting creator: %s", err)) + } + + if err = d.Set(isRoutingTableRouteID, route.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting route_id: %s", err)) + } + + if err = d.Set(rDestination, route.Destination); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination: %s", err)) + } + + if err = d.Set(rtHref, route.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + + if err = d.Set(rtLifecycleState, route.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + + if err = d.Set(rName, route.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + nextHop := []map[string]interface{}{} + if route.NextHop != nil { + modelMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopToMap(route.NextHop) + if err != nil { + return diag.FromErr(err) + } + nextHop = append(nextHop, modelMap) + } + if err = d.Set(rNextHop, nextHop); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting next_hop %s", err)) + } + + //orgin + if err = d.Set("origin", route.Origin); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting origin %s", err)) + } + + zone := []map[string]interface{}{} + if route.Zone != nil { + modelMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteZoneReferenceToMap(route.Zone) + if err != nil { + return diag.FromErr(err) + } + zone = append(zone, modelMap) + } + if err = d.Set(rZone, zone); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone %s", err)) + } + + return nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopToMap(model vpcv1.RouteNextHopIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.RouteNextHopIP); ok { + return dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopIPToMap(model.(*vpcv1.RouteNextHopIP)) + } else if _, ok := model.(*vpcv1.RouteNextHopVPNGatewayConnectionReference); ok { + return dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopVPNGatewayConnectionReferenceToMap(model.(*vpcv1.RouteNextHopVPNGatewayConnectionReference)) + } else if _, ok := model.(*vpcv1.RouteNextHop); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.RouteNextHop) + if model.Address != nil { + modelMap[rAddress] = *model.Address + } + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteVPNGatewayConnectionReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap[rDeleted] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap[rtHref] = *model.Href + } + if model.ID != nil { + modelMap[rId] = *model.ID + } + if model.Name != nil { + modelMap[rName] = *model.Name + } + if model.ResourceType != nil { + modelMap[rtResourceType] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("[ERROR] Unrecognized vpcv1.RouteNextHopIntf subtype encountered") + } +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteVPNGatewayConnectionReferenceDeletedToMap(model *vpcv1.VPNGatewayConnectionReferenceDeleted) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.MoreInfo != nil { + modelMap[rMoreInfo] = *model.MoreInfo + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopIPToMap(model *vpcv1.RouteNextHopIP) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.Address != nil { + modelMap[rAddress] = *model.Address + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteRouteNextHopVPNGatewayConnectionReferenceToMap(model *vpcv1.RouteNextHopVPNGatewayConnectionReference) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIBMIsVPCRoutingTableRouteVPNGatewayConnectionReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap[rDeleted] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap[rtHref] = *model.Href + } + if model.ID != nil { + modelMap[rId] = *model.ID + } + if model.Name != nil { + modelMap[rName] = *model.Name + } + if model.ResourceType != nil { + modelMap[rtResourceType] = *model.ResourceType + } + return modelMap, nil +} + +func dataSourceIBMIBMIsVPCRoutingTableRouteZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := map[string]interface{}{} + if model.Href != nil { + modelMap[rtHref] = *model.Href + } + if model.Name != nil { + modelMap[rName] = *model.Name + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route_test.go new file mode 100644 index 000000000..1a35ae2dd --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_route_test.go @@ -0,0 +1,89 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIBMIsVPCRoutingTableRouteDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) + rtname := fmt.Sprintf("tf-rtname-%d", acctest.RandIntRange(100, 200)) + rname := fmt.Sprintf("tf-routename-%d", acctest.RandIntRange(100, 200)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIBMIsVPCRoutingTableRouteDataSourceConfigBasic(vpcname, rtname, rname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "route_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "route_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "vpc"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "vpc"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "routing_table"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "routing_table"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "destination"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "destination"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "next_hop.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "next_hop.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route", "zone.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table_route.ibm_is_vpc_routing_table_route_name", "zone.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIBMIsVPCRoutingTableRouteDataSourceConfigBasic(vpcname, rtname, rname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "test_route_vpc" { + name = "%s" + } + resource "ibm_is_vpc_routing_table" "test_route_rt" { + vpc = ibm_is_vpc.test_route_vpc.id + name = "%s" + route_direct_link_ingress = true + route_transit_gateway_ingress = false + route_vpc_zone_ingress = false + } + resource "ibm_is_vpc_routing_table_route" "test_route_rt_route" { + vpc = ibm_is_vpc.test_route_vpc.id + routing_table = ibm_is_vpc_routing_table.test_route_rt.routing_table + zone = "us-south-1" + name = "%s" + destination = "192.168.4.0/24" + action = "deliver" + next_hop = "0.0.0.0" + } + data "ibm_is_vpc_routing_table_route" "ibm_is_vpc_routing_table_route" { + vpc = ibm_is_vpc.test_route_vpc.id + routing_table = ibm_is_vpc_routing_table.test_route_rt.routing_table + route_id = ibm_is_vpc_routing_table_route.test_route_rt_route.route_id + } + data "ibm_is_vpc_routing_table_route" "ibm_is_vpc_routing_table_route_name" { + vpc = ibm_is_vpc.test_route_vpc.id + routing_table = ibm_is_vpc_routing_table.test_route_rt.routing_table + name = ibm_is_vpc_routing_table_route.test_route_rt_route.name + } + `, vpcname, rtname, rname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go new file mode 100644 index 000000000..8939aec41 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go @@ -0,0 +1,351 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isRoutingTableRouteID = "route_id" + isRoutingTableRouteHref = "href" + isRoutingTableRouteName = "name" + isRoutingTableRouteCreatedAt = "created_at" + isRoutingTableRouteLifecycleState = "lifecycle_state" + isRoutingTableRouteAction = "action" + isRoutingTableRouteDestination = "destination" + isRoutingTableRouteNexthop = "nexthop" + isRoutingTableRouteZoneName = "zone" + isRoutingTableRouteVpcID = "vpc" + isRouteTableID = "routing_table" + isRoutingTableRoutes = "routes" +) + +func DataSourceIBMISVPCRoutingTableRoutes() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMISVPCRoutingTableRoutesList, + Schema: map[string]*schema.Schema{ + isRoutingTableRouteVpcID: { + Type: schema.TypeString, + Required: true, + Description: "VPC identifier", + }, + isRouteTableID: { + Type: schema.TypeString, + Required: true, + Description: "Routing table identifier", + }, + isRoutingTableRoutes: { + Type: schema.TypeList, + Description: "Collection of Routing Table Routes", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isRoutingTableRouteID: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route ID", + }, + isRoutingTableRouteHref: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Href", + }, + isRoutingTableRouteName: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Name", + }, + isRoutingTableRouteCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Created At", + }, + "creator": { + Type: schema.TypeList, + Computed: true, + Description: "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's CRN.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN gateway.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + isRoutingTableRouteLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Lifecycle State", + }, + isRoutingTableRouteAction: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Action", + }, + isRoutingTableRouteDestination: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Destination", + }, + isRoutingTableRouteNexthop: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Nexthop Address or VPN Gateway Connection ID", + }, + "origin": { + Type: schema.TypeString, + Computed: true, + Description: "The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + }, + isRoutingTableRouteZoneName: { + Type: schema.TypeString, + Computed: true, + Description: "Routing Table Route Zone Name", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMISVPCRoutingTableRoutesList(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + vpcID := d.Get(isRoutingTableRouteVpcID).(string) + routingTableID := d.Get(isRouteTableID).(string) + start := "" + allrecs := []vpcv1.Route{} + for { + listVpcRoutingTablesRoutesOptions := sess.NewListVPCRoutingTableRoutesOptions(vpcID, routingTableID) + if start != "" { + listVpcRoutingTablesRoutesOptions.Start = &start + } + result, detail, err := sess.ListVPCRoutingTableRoutes(listVpcRoutingTablesRoutesOptions) + if err != nil { + log.Printf("Error reading list of VPC Routing Table Routes:%s\n%s", err, detail) + return err + } + start = flex.GetNext(result.Next) + allrecs = append(allrecs, result.Routes...) + if start == "" { + break + } + } + + vpcRoutingTableRoutes := make([]map[string]interface{}, 0) + + for _, instance := range allrecs { + route := map[string]interface{}{} + if instance.ID != nil { + route[isRoutingTableRouteID] = *instance.ID + } + if instance.Href != nil { + route[isRoutingTableRouteHref] = *instance.Href + } + if instance.Name != nil { + route[isRoutingTableRouteName] = *instance.Name + } + if instance.CreatedAt != nil { + route[isRoutingTableRouteCreatedAt] = (*instance.CreatedAt).String() + } + // creator changes + creator := []map[string]interface{}{} + if instance.Creator != nil { + mm, err := dataSourceIBMIsRouteCreatorToMap(instance.Creator) + if err != nil { + log.Printf("Error reading list of VPC Routing Table Routes' creator:%s", err) + return err + } + creator = append(creator, mm) + + } + route["creator"] = creator + if instance.LifecycleState != nil { + route[isRoutingTableRouteLifecycleState] = *instance.LifecycleState + } + if instance.Destination != nil { + route[isRoutingTableRouteDestination] = *instance.Destination + } + if instance.Zone != nil && instance.Zone.Name != nil { + route[isRoutingTableRouteZoneName] = *instance.Zone.Name + } + if instance.NextHop != nil { + nexthop := *instance.NextHop.(*vpcv1.RouteNextHop) + if nexthop.Address != nil { + route[isRoutingTableRouteNexthop] = *nexthop.Address + } else { + route[isRoutingTableRouteNexthop] = *nexthop.ID + } + } + //orgin + if instance.Origin != nil { + route["origin"] = *instance.Origin + } + + vpcRoutingTableRoutes = append(vpcRoutingTableRoutes, route) + } + d.SetId(dataSourceIBMISVPCRoutingTableRoutesID(d)) + d.Set(isRoutingTableRouteVpcID, vpcID) + d.Set(isRouteTableID, routingTableID) + d.Set(isRoutingTableRoutes, vpcRoutingTableRoutes) + return nil +} + +// dataSourceIBMISVPCRoutingTablesID returns a reasonable ID for dns zones list. +func dataSourceIBMISVPCRoutingTableRoutesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIBMIsRouteCreatorToMap(model vpcv1.RouteCreatorIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.RouteCreatorVPNGatewayReference); ok { + return DataSourceIBMIsRouteCreatorVPNGatewayReferenceToMap(model.(*vpcv1.RouteCreatorVPNGatewayReference)) + } else if _, ok := model.(*vpcv1.RouteCreatorVPNServerReference); ok { + return DataSourceIBMIsRouteCreatorVPNServerReferenceToMap(model.(*vpcv1.RouteCreatorVPNServerReference)) + } else if _, ok := model.(*vpcv1.RouteCreator); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.RouteCreator) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsRouteVPNGatewayReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("[Error] unrecognized vpcv1.RouteCreatorIntf subtype encountered") + } +} + +func DataSourceIBMIsRouteCreatorVPNGatewayReferenceToMap(model *vpcv1.RouteCreatorVPNGatewayReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsRouteVPNGatewayReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil +} + +func DataSourceIBMIsRouteCreatorVPNServerReferenceToMap(model *vpcv1.RouteCreatorVPNServerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.CRN != nil { + modelMap["crn"] = *model.CRN + } + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsRouteVPNServerReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil +} + +func DataSourceIBMIsRouteVPNGatewayReferenceDeletedToMap(model *vpcv1.VPNGatewayReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsRouteVPNServerReferenceDeletedToMap(model *vpcv1.VPNServerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/data_source_ibm_is_vpc_routing_table_routes_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes_test.go similarity index 89% rename from ibm/data_source_ibm_is_vpc_routing_table_routes_test.go rename to ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes_test.go index e6ecaad61..a1ce02a8e 100644 --- a/ibm/data_source_ibm_is_vpc_routing_table_routes_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -18,8 +20,8 @@ func TestAccIBMISVPCRoutingTableRoutesDataSource_basic(t *testing.T) { routeName := fmt.Sprintf("tfvpcuat-create-data-%d", acctest.RandIntRange(10, 100)) routeTableName := fmt.Sprintf("tfvpcrt-create-data-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVPCRoutingTableRoutesDataSourceConfig(routeTableName, name1, subnetName, routeName), @@ -65,5 +67,5 @@ data "ibm_is_vpc_routing_table_routes" "routes_test" { routing_table = ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table.routing_table } -`, name, rtName, subnetName, ISZoneName, ISCIDR, routeName, ISZoneName, ISRouteNextHop) +`, name, rtName, subnetName, acc.ISZoneName, acc.ISCIDR, routeName, acc.ISZoneName, acc.ISRouteNextHop) } diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_test.go new file mode 100644 index 000000000..370be32e8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_test.go @@ -0,0 +1,77 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIBMIsVPCRoutingTableDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) + rtname := fmt.Sprintf("tf-rtname-%d", acctest.RandIntRange(100, 200)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIBMIsVPCRoutingTableDataSourceConfigBasic(vpcname, rtname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "routing_table"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "vpc"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "route_direct_link_ingress"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "route_transit_gateway_ingress"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table", "route_vpc_zone_ingress"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "routing_table"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "vpc"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "is_default"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "route_direct_link_ingress"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "route_transit_gateway_ingress"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc_routing_table.ibm_is_vpc_routing_table_name", "route_vpc_zone_ingress"), + ), + }, + }, + }) +} + +func testAccCheckIBMIBMIsVPCRoutingTableDataSourceConfigBasic(vpcname, rtname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "test_route_vpc" { + name = "%s" + } + resource "ibm_is_vpc_routing_table" "test_route_rt" { + vpc = ibm_is_vpc.test_route_vpc.id + name = "%s" + route_direct_link_ingress = true + route_transit_gateway_ingress = false + route_vpc_zone_ingress = false + } + data "ibm_is_vpc_routing_table" "ibm_is_vpc_routing_table" { + vpc = ibm_is_vpc.test_route_vpc.id + routing_table = ibm_is_vpc_routing_table.test_route_rt.routing_table + } + data "ibm_is_vpc_routing_table" "ibm_is_vpc_routing_table_name" { + vpc = ibm_is_vpc.test_route_vpc.id + name = ibm_is_vpc_routing_table.test_route_rt.name + } + `, vpcname, rtname) +} diff --git a/ibm/data_source_ibm_is_vpc_routing_tables.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_tables.go similarity index 84% rename from ibm/data_source_ibm_is_vpc_routing_tables.go rename to ibm/service/vpc/data_source_ibm_is_vpc_routing_tables.go index 8b0d485b2..1d7e9b319 100644 --- a/ibm/data_source_ibm_is_vpc_routing_tables.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_tables.go @@ -1,18 +1,21 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( //"encoding/json" + "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const ( + isRoutingTableAcceptRoutesFrom = "accept_routes_from" isRoutingTableID = "routing_table" isRoutingTableHref = "href" isRoutingTableName = "name" @@ -29,7 +32,7 @@ const ( isRoutingTableDefault = "is_default" ) -func dataSourceIBMISVPCRoutingTables() *schema.Resource { +func DataSourceIBMISVPCRoutingTables() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISVPCRoutingTablesList, Schema: map[string]*schema.Schema{ @@ -44,6 +47,20 @@ func dataSourceIBMISVPCRoutingTables() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + isRoutingTableAcceptRoutesFrom: { + Type: schema.TypeList, + Computed: true, + Description: "The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, isRoutingTableID: { Type: schema.TypeString, Computed: true, @@ -159,7 +176,7 @@ func dataSourceIBMISVPCRoutingTablesList(d *schema.ResourceData, meta interface{ log.Printf("Error reading list of VPC Routing Tables:%s\n%s", err, detail) return err } - start = GetNext(result.Next) + start = flex.GetNext(result.Next) allrecs = append(allrecs, result.RoutingTables...) if start == "" { break @@ -170,6 +187,15 @@ func dataSourceIBMISVPCRoutingTablesList(d *schema.ResourceData, meta interface{ for _, routingTable := range allrecs { rtable := map[string]interface{}{} + acceptRoutesFromInfo := make([]map[string]interface{}, 0) + for _, AcceptRoutesFrom := range routingTable.AcceptRoutesFrom { + if AcceptRoutesFrom.ResourceType != nil { + l := map[string]interface{}{} + l["resource_type"] = *AcceptRoutesFrom.ResourceType + acceptRoutesFromInfo = append(acceptRoutesFromInfo, l) + } + } + rtable[isRoutingTableAcceptRoutesFrom] = acceptRoutesFromInfo if routingTable.ID != nil { rtable[isRoutingTableID] = *routingTable.ID } diff --git a/ibm/data_source_ibm_is_vpc_routing_tables_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_tables_test.go similarity index 88% rename from ibm/data_source_ibm_is_vpc_routing_tables_test.go rename to ibm/service/vpc/data_source_ibm_is_vpc_routing_tables_test.go index c0f716f4e..f673df866 100644 --- a/ibm/data_source_ibm_is_vpc_routing_tables_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_tables_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMISVPCRoutingTablesDataSource_basic(t *testing.T) { vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) routetablename := fmt.Sprintf("tf-routetable-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVPCRoutingTablesDataSourceConfig(vpcname, routetablename), diff --git a/ibm/data_source_ibm_is_vpc_test.go b/ibm/service/vpc/data_source_ibm_is_vpc_test.go similarity index 79% rename from ibm/data_source_ibm_is_vpc_test.go rename to ibm/service/vpc/data_source_ibm_is_vpc_test.go index b3df30225..3eeee7d16 100644 --- a/ibm/data_source_ibm_is_vpc_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -16,8 +18,8 @@ func TestAccIBMISVPCDatasource_basic(t *testing.T) { name := fmt.Sprintf("tfc-vpc-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { @@ -32,6 +34,10 @@ func TestAccIBMISVPCDatasource_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc", "default_network_acl_name"), resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc", "default_security_group_name"), resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc", "default_routing_table_name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc_by_id", "cse_source_addresses.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc_by_id", "default_network_acl_name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc_by_id", "default_security_group_name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpc.ds_vpc_by_id", "default_routing_table_name"), ), }, }, @@ -44,8 +50,8 @@ func TestAccIBMISVPCDatasource_securityGroup(t *testing.T) { sgname := fmt.Sprintf("tfc-sg-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { @@ -70,6 +76,9 @@ func testDSCheckIBMISVPCConfig(name string) string { } data "ibm_is_vpc" "ds_vpc" { name = "${ibm_is_vpc.testacc_vpc.name}" + } + data "ibm_is_vpc" "ds_vpc_by_id" { + identifier = "${ibm_is_vpc.testacc_vpc.id}" }`, name) } diff --git a/ibm/data_source_ibm_is_vpcs.go b/ibm/service/vpc/data_source_ibm_is_vpcs.go similarity index 91% rename from ibm/data_source_ibm_is_vpcs.go rename to ibm/service/vpc/data_source_ibm_is_vpcs.go index f118e6208..a672a650f 100644 --- a/ibm/data_source_ibm_is_vpcs.go +++ b/ibm/service/vpc/data_source_ibm_is_vpcs.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( //"encoding/json" @@ -12,6 +12,8 @@ import ( "reflect" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -22,7 +24,7 @@ const ( isVPCID = "id" ) -func dataSourceIBMISVPCs() *schema.Resource { +func DataSourceIBMISVPCs() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMISVPCListRead, Schema: map[string]*schema.Schema{ @@ -109,7 +111,7 @@ func dataSourceIBMISVPCs() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: resourceIBMVPCHash, + Set: flex.ResourceIBMVPCHash, }, isVPCCRN: { @@ -118,30 +120,30 @@ func dataSourceIBMISVPCs() *schema.Resource { Description: "The crn of the resource", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -298,7 +300,7 @@ func dataSourceIBMISVPCs() *schema.Resource { } func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(ClientSession).VpcV1API() + sess, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -315,7 +317,7 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, log.Printf("Error reading list of VPCs:%s\n%s", err, detail) return diag.FromErr(err) } - start = GetNext(result.Next) + start = flex.GetNext(result.Next) allrecs = append(allrecs, result.Vpcs...) if start == "" { break @@ -326,15 +328,15 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, for _, vpc := range allrecs { l := map[string]interface{}{ - isVPCID: *vpc.ID, - isVPCName: *vpc.Name, - isVPCClassicAccess: *vpc.ClassicAccess, - isVPCStatus: *vpc.Status, - isVPCCRN: *vpc.CRN, - ResourceName: *vpc.Name, - ResourceCRN: *vpc.CRN, - ResourceStatus: *vpc.Status, - isVPCResourceGroup: *vpc.ResourceGroup.ID, + isVPCID: *vpc.ID, + isVPCName: *vpc.Name, + isVPCClassicAccess: *vpc.ClassicAccess, + isVPCStatus: *vpc.Status, + isVPCCRN: *vpc.CRN, + flex.ResourceName: *vpc.Name, + flex.ResourceCRN: *vpc.CRN, + flex.ResourceStatus: *vpc.Status, + isVPCResourceGroup: *vpc.ResourceGroup.ID, } if vpc.DefaultNetworkACL != nil { @@ -351,21 +353,21 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, l[isVPCDefaultSecurityGroupName] = *vpc.DefaultSecurityGroup.Name l[isVPCDefaultSecurityGroupCRN] = vpc.DefaultSecurityGroup.CRN } - tags, err := GetTagsUsingCRN(meta, *vpc.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *vpc.CRN) if err != nil { log.Printf( "An error occured during reading of vpc (%s) tags : %s", d.Id(), err) } l[isVPCTags] = tags - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return diag.FromErr(err) } - l[ResourceControllerURL] = controller + "/vpc-ext/network/vpcs" + l[flex.ResourceControllerURL] = controller + "/vpc-ext/network/vpcs" if vpc.ResourceGroup != nil { - l[ResourceGroupName] = *vpc.ResourceGroup.Name + l[flex.ResourceGroupName] = *vpc.ResourceGroup.Name } //set the cse ip addresses info if vpc.CseSourceIps != nil { @@ -388,13 +390,13 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, options := &vpcv1.ListSubnetsOptions{} for { if startSub != "" { - options.Start = &start + options.Start = &startSub } s, response, err := sess.ListSubnetsWithContext(context, options) if err != nil { - return diag.FromErr(fmt.Errorf("Error fetching subnets %s\n%s", err, response)) + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching subnets %s\n%s", err, response)) } - start = GetNext(s.Next) + startSub = flex.GetNext(s.Next) allrecsSub = append(allrecsSub, s.Subnets...) if startSub == "" { break @@ -418,7 +420,7 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, l[subnetsList] = subnetsInfo } - // adding pagination support for subnets inside vpc + // adding pagination support for sg inside vpc startSg := "" allrecsSg := []vpcv1.SecurityGroup{} @@ -433,12 +435,12 @@ func dataSourceIBMISVPCListRead(context context.Context, d *schema.ResourceData, } sgs, response, err := sess.ListSecurityGroupsWithContext(context, listSgOptions) if err != nil { - return diag.FromErr(fmt.Errorf("Error fetching Security Groups %s\n%s", err, response)) + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching Security Groups %s\n%s", err, response)) } if *sgs.TotalCount == int64(0) { break } - start = GetNext(sgs.Next) + start = flex.GetNext(sgs.Next) allrecsSg = append(allrecsSg, sgs.SecurityGroups...) if startSg == "" { diff --git a/ibm/data_source_ibm_is_vpcs_test.go b/ibm/service/vpc/data_source_ibm_is_vpcs_test.go similarity index 83% rename from ibm/data_source_ibm_is_vpcs_test.go rename to ibm/service/vpc/data_source_ibm_is_vpcs_test.go index 4f26267e5..78005f9c4 100644 --- a/ibm/data_source_ibm_is_vpcs_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpcs_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,8 +17,8 @@ func TestAccIBMISVPCsDatasource_basic(t *testing.T) { node := "data.ibm_is_vpcs.test1" vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testDSCheckIBMISVPCsConfig(vpcname), diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go new file mode 100644 index 000000000..467619076 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go @@ -0,0 +1,543 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISVPNGateway() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNGatewayRead, + + Schema: map[string]*schema.Schema{ + isVPNGatewayID: { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", isVPNGatewayID}, + Description: "The VPN gateway identifier.", + }, + "vpn_gateway_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", isVPNGatewayID}, + Description: "The VPN gateway name.", + }, + "connections": { + Type: schema.TypeList, + Computed: true, + Description: "Connections for this VPN gateway.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN gateway connection.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN connection.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this VPN gateway was created.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's CRN.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's canonical URL.", + }, + "members": { + Type: schema.TypeList, + Computed: true, + Description: "Collection of VPN gateway members.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "private_ip_address": { + Type: schema.TypeString, + Computed: true, + Description: "The private IP address assigned to the VPN gateway member. This property will be present only when the VPN gateway status is`available`.", + }, + "public_ip_address": { + Type: schema.TypeString, + Computed: true, + Description: "The public IP address assigned to the VPN gateway member.", + }, + "role": { + Type: schema.TypeString, + Computed: true, + Description: "The high availability role assigned to the VPN gateway member.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN gateway member.", + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN gateway.", + }, + "resource_group": { + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this VPN gateway.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN gateway.", + }, + "subnet": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + }, + }, + }, + "mode": { + Type: schema.TypeString, + Computed: true, + Description: "Route mode VPN gateway.", + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "VPC for the VPN Gateway", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNGatewayRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + vpn_gateway_name := d.Get("vpn_gateway_name").(string) + vpn_gateway_id := d.Get("vpn_gateway").(string) + vpnGateway := &vpcv1.VPNGateway{} + if vpn_gateway_id != "" { + getVPNGatewayOptions := &vpcv1.GetVPNGatewayOptions{} + + getVPNGatewayOptions.SetID(vpn_gateway_id) + + vpnGatewayIntf, response, err := vpcClient.GetVPNGatewayWithContext(context, getVPNGatewayOptions) + if err != nil || vpnGatewayIntf.(*vpcv1.VPNGateway) == nil { + log.Printf("[DEBUG] GetVPNGatewayWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVPNGatewayWithContext failed %s\n%s", err, response)) + } + vpnGateway = vpnGatewayIntf.(*vpcv1.VPNGateway) + } else { + listvpnGWOptions := vpcClient.NewListVPNGatewaysOptions() + + start := "" + allrecs := []vpcv1.VPNGatewayIntf{} + for { + if start != "" { + listvpnGWOptions.Start = &start + } + availableVPNGateways, detail, err := vpcClient.ListVPNGatewaysWithContext(context, listvpnGWOptions) + if err != nil || availableVPNGateways == nil { + return diag.FromErr(fmt.Errorf("Error reading list of VPN Gateways:%s\n%s", err, detail)) + } + start = flex.GetNext(availableVPNGateways.Next) + allrecs = append(allrecs, availableVPNGateways.VPNGateways...) + if start == "" { + break + } + } + vpn_gateway_found := false + for _, vpnGatewayIntfItem := range allrecs { + if *vpnGatewayIntfItem.(*vpcv1.VPNGateway).Name == vpn_gateway_name { + vpnGateway = vpnGatewayIntfItem.(*vpcv1.VPNGateway) + vpn_gateway_found = true + break + } + } + if !vpn_gateway_found { + log.Printf("[DEBUG] No vpn gateway found with given name %s", vpn_gateway_name) + return diag.FromErr(fmt.Errorf("No vpn gateway found with given name %s", vpn_gateway_name)) + } + } + d.SetId(*vpnGateway.ID) + + if vpnGateway.Connections != nil { + err = d.Set("connections", dataSourceVPNGatewayFlattenConnections(vpnGateway.Connections)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting connections %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(vpnGateway.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("crn", vpnGateway.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("href", vpnGateway.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if vpnGateway.Members != nil { + err = d.Set("members", dataSourceVPNGatewayFlattenMembers(vpnGateway.Members)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting members %s", err)) + } + } + if err = d.Set("name", vpnGateway.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if vpnGateway.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceVPNGatewayFlattenResourceGroup(*vpnGateway.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + } + } + if err = d.Set("resource_type", vpnGateway.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + if err = d.Set("status", vpnGateway.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + + if vpnGateway.Subnet != nil { + err = d.Set("subnet", dataSourceVPNGatewayFlattenSubnet(*vpnGateway.Subnet)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting subnet %s", err)) + } + } + if err = d.Set("mode", vpnGateway.Mode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mode: %s", err)) + } + if vpnGateway.VPC != nil { + err = d.Set("vpc", dataSourceVPNGatewayFlattenVPC(vpnGateway.VPC)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting vpc: %s", err)) + } + } + return nil +} + +func dataSourceVPNGatewayFlattenConnections(result []vpcv1.VPNGatewayConnectionReference) (connections []map[string]interface{}) { + for _, connectionsItem := range result { + connections = append(connections, dataSourceVPNGatewayConnectionsToMap(connectionsItem)) + } + + return connections +} + +func dataSourceVPNGatewayConnectionsToMap(connectionsItem vpcv1.VPNGatewayConnectionReference) (connectionsMap map[string]interface{}) { + connectionsMap = map[string]interface{}{} + + if connectionsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewayConnectionsDeletedToMap(*connectionsItem.Deleted) + deletedList = append(deletedList, deletedMap) + connectionsMap["deleted"] = deletedList + } + if connectionsItem.Href != nil { + connectionsMap["href"] = connectionsItem.Href + } + if connectionsItem.ID != nil { + connectionsMap["id"] = connectionsItem.ID + } + if connectionsItem.Name != nil { + connectionsMap["name"] = connectionsItem.Name + } + if connectionsItem.ResourceType != nil { + connectionsMap["resource_type"] = connectionsItem.ResourceType + } + + return connectionsMap +} + +func dataSourceVPNGatewayConnectionsDeletedToMap(deletedItem vpcv1.VPNGatewayConnectionReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNGatewayFlattenMembers(result []vpcv1.VPNGatewayMember) (members []map[string]interface{}) { + for _, membersItem := range result { + members = append(members, dataSourceVPNGatewayMembersToMap(membersItem)) + } + + return members +} + +func dataSourceVPNGatewayMembersToMap(membersItem vpcv1.VPNGatewayMember) (membersMap map[string]interface{}) { + membersMap = map[string]interface{}{} + + if membersItem.PrivateIP != nil && membersItem.PrivateIP.Address != nil { + membersMap["private_ip_address"] = membersItem.PrivateIP.Address + } + if membersItem.PublicIP != nil { + membersMap["public_ip_address"] = membersItem.PublicIP.Address + } + if membersItem.Role != nil { + membersMap["role"] = membersItem.Role + } + if membersItem.Status != nil { + membersMap["status"] = membersItem.Status + } + + return membersMap +} + +func dataSourceVPNGatewayFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNGatewayResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNGatewayResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceVPNGatewayFlattenSubnet(result vpcv1.SubnetReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNGatewaySubnetToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNGatewaySubnetToMap(subnetItem vpcv1.SubnetReference) (subnetMap map[string]interface{}) { + subnetMap = map[string]interface{}{} + + if subnetItem.CRN != nil { + subnetMap["crn"] = subnetItem.CRN + } + if subnetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewaySubnetDeletedToMap(*subnetItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetMap["deleted"] = deletedList + } + if subnetItem.Href != nil { + subnetMap["href"] = subnetItem.Href + } + if subnetItem.ID != nil { + subnetMap["id"] = subnetItem.ID + } + if subnetItem.Name != nil { + subnetMap["name"] = subnetItem.Name + } + + return subnetMap +} + +func dataSourceVPNGatewaySubnetDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNGatewayFlattenVPC(result *vpcv1.VPCReference) (vpcs []map[string]interface{}) { + vpcs = append(vpcs, dataSourceVPNGatewayVpcToMap(*result)) + return vpcs +} + +func dataSourceVPNGatewayVpcToMap(vpcItem vpcv1.VPCReference) (vpcsMap map[string]interface{}) { + vpcsMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + vpcsMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewayVpcDeletedToMap(*vpcItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcsMap["deleted"] = deletedList + } + if vpcItem.Href != nil { + vpcsMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + vpcsMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + vpcsMap["name"] = vpcItem.Name + } + + return vpcsMap + +} + +func dataSourceVPNGatewayVpcDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go new file mode 100644 index 000000000..92ac55363 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection.go @@ -0,0 +1,551 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMISVPNGatewayConnection() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNGatewayConnectionRead, + + Schema: map[string]*schema.Schema{ + "vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway identifier.", + }, + "vpn_gateway_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_name", "vpn_gateway"}, + Description: "The VPN gateway name.", + }, + "vpn_gateway_connection": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_connection", "vpn_gateway_connection_name"}, + Description: "The VPN gateway connection identifier.", + }, + "vpn_gateway_connection_name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"vpn_gateway_connection", "vpn_gateway_connection_name"}, + Description: "The VPN gateway connection name.", + }, + "admin_state_up": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to false, the VPN gateway connection is shut down.", + }, + "authentication_mode": { + Type: schema.TypeString, + Computed: true, + Description: "The authentication mode. Only `psk` is currently supported.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this VPN gateway connection was created.", + }, + "dead_peer_detection": { + Type: schema.TypeList, + Computed: true, + Description: "The Dead Peer Detection settings.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeString, + Computed: true, + Description: "Dead Peer Detection actions.", + }, + "interval": { + Type: schema.TypeInt, + Computed: true, + Description: "Dead Peer Detection interval in seconds.", + }, + "timeout": { + Type: schema.TypeInt, + Computed: true, + Description: "Dead Peer Detection timeout in seconds. Must be at least the interval.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The VPN connection's canonical URL.", + }, + "ike_policy": { + Type: schema.TypeList, + Computed: true, + Description: "The IKE policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#ike-auto-negotiation-phase-1).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IKE policy's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this IKE policy.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this IKE policy.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "ipsec_policy": { + Type: schema.TypeList, + Computed: true, + Description: "The IPsec policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#ipsec-auto-negotiation-phase-2).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The IPsec policy's canonical URL.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this IPsec policy.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this IPsec policy.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "mode": { + Type: schema.TypeString, + Computed: true, + Description: "The mode of the VPN gateway.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN gateway connection.", + }, + "peer_address": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the peer VPN gateway.", + }, + "psk": { + Type: schema.TypeString, + Computed: true, + Description: "The preshared key.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of a VPN gateway connection.", + }, + "routing_protocol": { + Type: schema.TypeString, + Computed: true, + Description: "Routing protocols are disabled for this VPN gateway connection.", + }, + "tunnels": { + Type: schema.TypeList, + Computed: true, + Description: "The VPN tunnel configuration for this VPN gateway connection (in static route mode).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "public_ip_address": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address of the VPN gateway member in which the tunnel resides.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN Tunnel.", + }, + }, + }, + }, + "local_cidrs": { + Type: schema.TypeList, + Computed: true, + Description: "The local CIDRs for this resource.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "peer_cidrs": { + Type: schema.TypeList, + Computed: true, + Description: "The peer CIDRs for this resource.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNGatewayConnectionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + vpn_gateway_id := d.Get("vpn_gateway").(string) + vpn_gateway_name := d.Get("vpn_gateway_name").(string) + vpn_gateway_connection := d.Get("vpn_gateway_connection").(string) + vpn_gateway_connection_name := d.Get("vpn_gateway_connection_name").(string) + + vpnGatewayConnection := &vpcv1.VPNGatewayConnection{} + + if vpn_gateway_name != "" { + listvpnGWOptions := vpcClient.NewListVPNGatewaysOptions() + + start := "" + allrecs := []vpcv1.VPNGatewayIntf{} + for { + if start != "" { + listvpnGWOptions.Start = &start + } + availableVPNGateways, detail, err := vpcClient.ListVPNGatewaysWithContext(context, listvpnGWOptions) + if err != nil || availableVPNGateways == nil { + return diag.FromErr(fmt.Errorf("Error reading list of VPN Gateways:%s\n%s", err, detail)) + } + start = flex.GetNext(availableVPNGateways.Next) + allrecs = append(allrecs, availableVPNGateways.VPNGateways...) + if start == "" { + break + } + } + vpn_gateway_found := false + for _, vpnGatewayIntfItem := range allrecs { + if *vpnGatewayIntfItem.(*vpcv1.VPNGateway).Name == vpn_gateway_name { + vpnGateway := vpnGatewayIntfItem.(*vpcv1.VPNGateway) + vpn_gateway_id = *vpnGateway.ID + vpn_gateway_found = true + break + } + } + if !vpn_gateway_found { + log.Printf("[DEBUG] No vpn gateway and connection found with given name %s", vpn_gateway_name) + return diag.FromErr(fmt.Errorf("No vpn gateway and connection found with given name %s", vpn_gateway_name)) + } + } + + if vpn_gateway_connection_name != "" { + listvpnGWConnectionOptions := vpcClient.NewListVPNGatewayConnectionsOptions(vpn_gateway_id) + + availableVPNGatewayConnections, detail, err := vpcClient.ListVPNGatewayConnections(listvpnGWConnectionOptions) + if err != nil || availableVPNGatewayConnections == nil { + return diag.FromErr(fmt.Errorf("Error reading list of VPN Gateway Connections:%s\n%s", err, detail)) + } + + vpn_gateway_conn_found := false + for _, connectionItem := range availableVPNGatewayConnections.Connections { + connection := connectionItem.(*vpcv1.VPNGatewayConnection) + if *connection.Name == vpn_gateway_connection_name { + vpnGatewayConnection = connection + vpn_gateway_conn_found = true + break + } + } + if !vpn_gateway_conn_found { + return diag.FromErr(fmt.Errorf("VPN gateway connection %s not found", vpn_gateway_connection_name)) + } + } else if vpn_gateway_connection != "" { + getVPNGatewayConnectionOptions := &vpcv1.GetVPNGatewayConnectionOptions{} + + getVPNGatewayConnectionOptions.SetVPNGatewayID(vpn_gateway_id) + getVPNGatewayConnectionOptions.SetID(vpn_gateway_connection) + + vpnGatewayConnectionIntf, response, err := vpcClient.GetVPNGatewayConnectionWithContext(context, getVPNGatewayConnectionOptions) + if err != nil || vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnection) == nil { + log.Printf("[DEBUG] GetVPNGatewayConnectionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVPNGatewayConnectionWithContext failed %s\n%s", err, response)) + } + vpnGatewayConnection = vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnection) + } + + d.SetId(fmt.Sprintf("%s/%s", vpn_gateway_id, *vpnGatewayConnection.ID)) + + if err = d.Set("admin_state_up", vpnGatewayConnection.AdminStateUp); err != nil { + return diag.FromErr(fmt.Errorf("Error setting admin_state_up: %s", err)) + } + if err = d.Set("authentication_mode", vpnGatewayConnection.AuthenticationMode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting authentication_mode: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnGatewayConnection.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if vpnGatewayConnection.DeadPeerDetection != nil { + err = d.Set("dead_peer_detection", dataSourceVPNGatewayConnectionFlattenDeadPeerDetection(*vpnGatewayConnection.DeadPeerDetection)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting dead_peer_detection %s", err)) + } + } + if err = d.Set("href", vpnGatewayConnection.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if vpnGatewayConnection.IkePolicy != nil { + err = d.Set("ike_policy", dataSourceVPNGatewayConnectionFlattenIkePolicy(*vpnGatewayConnection.IkePolicy)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting ike_policy %s", err)) + } + } + + if vpnGatewayConnection.IpsecPolicy != nil { + err = d.Set("ipsec_policy", dataSourceVPNGatewayConnectionFlattenIpsecPolicy(*vpnGatewayConnection.IpsecPolicy)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting ipsec_policy %s", err)) + } + } + if err = d.Set("mode", vpnGatewayConnection.Mode); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mode: %s", err)) + } + if err = d.Set("name", vpnGatewayConnection.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("peer_address", vpnGatewayConnection.PeerAddress); err != nil { + return diag.FromErr(fmt.Errorf("Error setting peer_address: %s", err)) + } + if err = d.Set("psk", vpnGatewayConnection.Psk); err != nil { + return diag.FromErr(fmt.Errorf("Error setting psk: %s", err)) + } + if err = d.Set("resource_type", vpnGatewayConnection.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + if err = d.Set("status", vpnGatewayConnection.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + if err = d.Set("routing_protocol", vpnGatewayConnection.RoutingProtocol); err != nil { + return diag.FromErr(fmt.Errorf("Error setting routing_protocol: %s", err)) + } + + if vpnGatewayConnection.Tunnels != nil { + err = d.Set("tunnels", dataSourceVPNGatewayConnectionFlattenTunnels(vpnGatewayConnection.Tunnels)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting tunnels %s", err)) + } + } + + if len(vpnGatewayConnection.LocalCIDRs) > 0 { + err = d.Set("local_cidrs", vpnGatewayConnection.LocalCIDRs) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting local CIDRs %s", err)) + } + } + + if len(vpnGatewayConnection.PeerCIDRs) > 0 { + err = d.Set("peer_cidrs", vpnGatewayConnection.PeerCIDRs) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting Peer CIDRs %s", err)) + } + } + return nil +} + +func dataSourceVPNGatewayConnectionFlattenDeadPeerDetection(result vpcv1.VPNGatewayConnectionDpd) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNGatewayConnectionDeadPeerDetectionToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNGatewayConnectionDeadPeerDetectionToMap(deadPeerDetectionItem vpcv1.VPNGatewayConnectionDpd) (deadPeerDetectionMap map[string]interface{}) { + deadPeerDetectionMap = map[string]interface{}{} + + if deadPeerDetectionItem.Action != nil { + deadPeerDetectionMap["action"] = deadPeerDetectionItem.Action + } + if deadPeerDetectionItem.Interval != nil { + deadPeerDetectionMap["interval"] = deadPeerDetectionItem.Interval + } + if deadPeerDetectionItem.Timeout != nil { + deadPeerDetectionMap["timeout"] = deadPeerDetectionItem.Timeout + } + + return deadPeerDetectionMap +} + +func dataSourceVPNGatewayConnectionFlattenIkePolicy(result vpcv1.IkePolicyReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNGatewayConnectionIkePolicyToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNGatewayConnectionIkePolicyToMap(ikePolicyItem vpcv1.IkePolicyReference) (ikePolicyMap map[string]interface{}) { + ikePolicyMap = map[string]interface{}{} + + if ikePolicyItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewayConnectionIkePolicyDeletedToMap(*ikePolicyItem.Deleted) + deletedList = append(deletedList, deletedMap) + ikePolicyMap["deleted"] = deletedList + } + if ikePolicyItem.Href != nil { + ikePolicyMap["href"] = ikePolicyItem.Href + } + if ikePolicyItem.ID != nil { + ikePolicyMap["id"] = ikePolicyItem.ID + } + if ikePolicyItem.Name != nil { + ikePolicyMap["name"] = ikePolicyItem.Name + } + if ikePolicyItem.ResourceType != nil { + ikePolicyMap["resource_type"] = ikePolicyItem.ResourceType + } + + return ikePolicyMap +} + +func dataSourceVPNGatewayConnectionIkePolicyDeletedToMap(deletedItem vpcv1.IkePolicyReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNGatewayConnectionFlattenIpsecPolicy(result vpcv1.IPsecPolicyReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNGatewayConnectionIpsecPolicyToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNGatewayConnectionIpsecPolicyToMap(ipsecPolicyItem vpcv1.IPsecPolicyReference) (ipsecPolicyMap map[string]interface{}) { + ipsecPolicyMap = map[string]interface{}{} + + if ipsecPolicyItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewayConnectionIpsecPolicyDeletedToMap(*ipsecPolicyItem.Deleted) + deletedList = append(deletedList, deletedMap) + ipsecPolicyMap["deleted"] = deletedList + } + if ipsecPolicyItem.Href != nil { + ipsecPolicyMap["href"] = ipsecPolicyItem.Href + } + if ipsecPolicyItem.ID != nil { + ipsecPolicyMap["id"] = ipsecPolicyItem.ID + } + if ipsecPolicyItem.Name != nil { + ipsecPolicyMap["name"] = ipsecPolicyItem.Name + } + if ipsecPolicyItem.ResourceType != nil { + ipsecPolicyMap["resource_type"] = ipsecPolicyItem.ResourceType + } + + return ipsecPolicyMap +} + +func dataSourceVPNGatewayConnectionIpsecPolicyDeletedToMap(deletedItem vpcv1.IPsecPolicyReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNGatewayConnectionFlattenTunnels(result []vpcv1.VPNGatewayConnectionStaticRouteModeTunnel) (tunnels []map[string]interface{}) { + for _, tunnelsItem := range result { + tunnels = append(tunnels, dataSourceVPNGatewayConnectionTunnelsToMap(tunnelsItem)) + } + + return tunnels +} + +func dataSourceVPNGatewayConnectionTunnelsToMap(tunnelsItem vpcv1.VPNGatewayConnectionStaticRouteModeTunnel) (tunnelsMap map[string]interface{}) { + tunnelsMap = map[string]interface{}{} + + if tunnelsItem.PublicIP != nil { + tunnelsMap["public_ip_address"] = tunnelsItem.PublicIP.Address + } + if tunnelsItem.Status != nil { + tunnelsMap["status"] = tunnelsItem.Status + } + + return tunnelsMap +} + +func dataSourceVPNGatewayConnectionTunnelsPublicIPToMap(publicIPItem vpcv1.IP) (publicIPMap map[string]interface{}) { + publicIPMap = map[string]interface{}{} + + if publicIPItem.Address != nil { + publicIPMap["address"] = publicIPItem.Address + } + + return publicIPMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection_test.go new file mode 100644 index 000000000..5c758f72e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connection_test.go @@ -0,0 +1,152 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNGatewayConnectionDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + name := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(100, 200)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNGatewayConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "admin_state_up"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "authentication_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.interval"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.public_ip_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "peer_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "psk"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "status"), + ), + }, + { + Config: testAccCheckIBMIsVPNGatewayConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "admin_state_up"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "authentication_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.interval"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.public_ip_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "peer_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "psk"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example1", "status"), + ), + }, + { + Config: testAccCheckIBMIsVPNGatewayConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "admin_state_up"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "authentication_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.interval"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.public_ip_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "peer_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "psk"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example2", "status"), + ), + }, + { + Config: testAccCheckIBMIsVPNGatewayConnectionDataSourceConfigBasic(vpcname, subnetname, vpngwname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "admin_state_up"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "authentication_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.interval"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "dead_peer_detection.0.timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.public_ip_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example", "tunnels.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "peer_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "psk"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway_connection.example3", "status"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNGatewayConnectionDataSourceConfigBasic(vpc, subnet, vpngwname, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = "${ibm_is_vpc.example.id}" + zone = "%s" + ipv4_cidr_block = "%s" + + } + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = "${ibm_is_subnet.example.id}" + + + } + resource "ibm_is_vpn_gateway_connection" "example" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.example.id}" + peer_address = "1.2.3.4" + local_cidrs = [ibm_is_subnet.example.ipv4_cidr_block] + preshared_key = "VPNDemoPassword" + } + data "ibm_is_vpn_gateway_connection" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection + } + data "ibm_is_vpn_gateway_connection" "example1" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name + } + data "ibm_is_vpn_gateway_connection" "example2" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection + } + data "ibm_is_vpn_gateway_connection" "example3" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name + } + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname, name) +} diff --git a/ibm/data_source_ibm_is_vpn_gateway_connections.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go similarity index 94% rename from ibm/data_source_ibm_is_vpn_gateway_connections.go rename to ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go index d594361ed..b18525833 100644 --- a/ibm/data_source_ibm_is_vpn_gateway_connections.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -17,7 +18,7 @@ const ( isVPNGatewayConnectionID = "id" ) -func dataSourceIBMISVPNGatewayConnections() *schema.Resource { +func DataSourceIBMISVPNGatewayConnections() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMVPNGatewayConnectionsRead, @@ -163,7 +164,7 @@ func dataSourceIBMVPNGatewayConnectionsRead(d *schema.ResourceData, meta interfa availableVPNGatewayConnections, detail, err := sess.ListVPNGatewayConnections(listvpnGWConnectionOptions) if err != nil { - return fmt.Errorf("Error reading list of VPN Gateway Connections:%s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error reading list of VPN Gateway Connections:%s\n%s", err, detail) } vpngatewayconnections := make([]map[string]interface{}, 0) for _, instance := range availableVPNGatewayConnections.Connections { @@ -184,10 +185,10 @@ func dataSourceIBMVPNGatewayConnectionsRead(d *schema.ResourceData, meta interfa gatewayconnection[isVPNGatewayConnectionIPSECPolicy] = *data.IpsecPolicy.ID } if data.LocalCIDRs != nil { - gatewayconnection[isVPNGatewayConnectionLocalCIDRS] = flattenStringList(data.LocalCIDRs) + gatewayconnection[isVPNGatewayConnectionLocalCIDRS] = flex.FlattenStringList(data.LocalCIDRs) } if data.PeerCIDRs != nil { - gatewayconnection[isVPNGatewayConnectionPeerCIDRS] = flattenStringList(data.PeerCIDRs) + gatewayconnection[isVPNGatewayConnectionPeerCIDRS] = flex.FlattenStringList(data.PeerCIDRs) } gatewayconnection[isVPNGatewayConnectionMode] = *data.Mode gatewayconnection[isVPNGatewayConnectionName] = *data.Name diff --git a/ibm/data_source_ibm_is_vpn_gateway_connections_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections_test.go similarity index 90% rename from ibm/data_source_ibm_is_vpn_gateway_connections_test.go rename to ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections_test.go index ec6a9b42c..40dd276fa 100644 --- a/ibm/data_source_ibm_is_vpn_gateway_connections_test.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_connections_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -20,8 +22,8 @@ func TestAccIBMISVpnGatewayConnectionsDataSource_basic(t *testing.T) { name := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(100, 200)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISVpnGatewayconnectionsDataSourceConfig(vpcname, subnetname, vpngwname, name), @@ -66,6 +68,6 @@ func testAccCheckIBMISVpnGatewayconnectionsDataSourceConfig(vpc, subnet, vpngwna } data "ibm_is_vpn_gateway_connections" "test1" { vpn_gateway = ibm_is_vpn_gateway.testacc_vpnGateway.id - }`, vpc, subnet, ISZoneName, ISCIDR, vpngwname, name) + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname, name) } diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go new file mode 100644 index 000000000..fe4ae5b45 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway_test.go @@ -0,0 +1,107 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNGatewayDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(100, 200)) + vpngwname := fmt.Sprintf("tfvpnuat-vpngw-%d", acctest.RandIntRange(100, 200)) + vpngwconname := fmt.Sprintf("tfvpnuat-vpngwconn-%d", acctest.RandIntRange(100, 200)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNGatewayDataSourceConfigBasic(vpcname, subnetname, vpngwname, vpngwconname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "connections.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "connections.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "connections.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.public_ip_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.role"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "members.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_group.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "subnet.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example", "vpc.0.id"), + ), + }, + { + Config: testAccCheckIBMIsVPNGatewayDataSourceConfigBasic(vpcname, subnetname, vpngwname, vpngwconname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "connections.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "members.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateway.example-name", "subnet.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNGatewayDataSourceConfigBasic(vpc, subnet, vpngwname, vpngwconname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "example" { + name = "%s" + } + resource "ibm_is_subnet" "example" { + name = "%s" + vpc = "${ibm_is_vpc.example.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "example" { + name = "%s" + subnet = "${ibm_is_subnet.example.id}" + } + resource "ibm_is_vpn_gateway_connection" "example" { + name = "%s" + vpn_gateway = ibm_is_vpn_gateway.example.id + peer_address = ibm_is_vpn_gateway.example.public_ip_address + preshared_key = "VPNDemoPassword" + local_cidrs = [ibm_is_subnet.example.ipv4_cidr_block] + + } + data "ibm_is_vpn_gateway" "example" { + depends_on = [ + ibm_is_vpn_gateway_connection.example + ] + vpn_gateway = ibm_is_vpn_gateway.example.id + } + data "ibm_is_vpn_gateway" "example-name" { + depends_on = [ + ibm_is_vpn_gateway_connection.example + ] + vpn_gateway_name = ibm_is_vpn_gateway.example.name + } + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpngwname, vpngwconname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go new file mode 100644 index 000000000..bacdbfd2b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go @@ -0,0 +1,265 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isvpnGateways = "vpn_gateways" + isVPNGatewayResourceType = "resource_type" + isVPNGatewayCrn = "crn" +) + +func DataSourceIBMISVPNGateways() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMVPNGatewaysRead, + + Schema: map[string]*schema.Schema{ + + isvpnGateways: { + Type: schema.TypeList, + Description: "Collection of VPN Gateways", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVPNGatewayName: { + Type: schema.TypeString, + Computed: true, + Description: "VPN Gateway instance name", + }, + isVPNGatewayCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this VPN gateway was created", + }, + isVPNGatewayCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The VPN gateway's CRN", + }, + isVPNGatewayMembers: { + Type: schema.TypeList, + Computed: true, + Description: "Collection of VPN gateway members", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The public IP address assigned to the VPN gateway member", + }, + + "private_address": { + Type: schema.TypeString, + Computed: true, + Description: "The private IP address assigned to the VPN gateway member", + }, + "role": { + Type: schema.TypeString, + Computed: true, + Description: "The high availability role assigned to the VPN gateway member", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN gateway member", + }, + }, + }, + }, + + isVPNGatewayResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + + isVPNGatewayStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN gateway", + }, + + isVPNGatewaySubnet: { + Type: schema.TypeString, + Computed: true, + Description: "VPNGateway subnet info", + }, + isVPNGatewayResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "resource group identifiers ", + }, + isVPNGatewayMode: { + Type: schema.TypeString, + Computed: true, + Description: " VPN gateway mode(policy/route) ", + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "VPC for the VPN Gateway", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMVPNGatewaysRead(d *schema.ResourceData, meta interface{}) error { + + sess, err := vpcClient(meta) + if err != nil { + return err + } + + listvpnGWOptions := sess.NewListVPNGatewaysOptions() + + start := "" + allrecs := []vpcv1.VPNGatewayIntf{} + for { + if start != "" { + listvpnGWOptions.Start = &start + } + availableVPNGateways, detail, err := sess.ListVPNGateways(listvpnGWOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error reading list of VPN Gateways:%s\n%s", err, detail) + } + start = flex.GetNext(availableVPNGateways.Next) + allrecs = append(allrecs, availableVPNGateways.VPNGateways...) + if start == "" { + break + } + } + + vpngateways := make([]map[string]interface{}, 0) + for _, instance := range allrecs { + gateway := map[string]interface{}{} + data := instance.(*vpcv1.VPNGateway) + gateway[isVPNGatewayName] = *data.Name + gateway[isVPNGatewayCreatedAt] = data.CreatedAt.String() + gateway[isVPNGatewayResourceType] = *data.ResourceType + gateway[isVPNGatewayStatus] = *data.Status + gateway[isVPNGatewayMode] = *data.Mode + gateway[isVPNGatewayResourceGroup] = *data.ResourceGroup.ID + gateway[isVPNGatewaySubnet] = *data.Subnet.ID + gateway[isVPNGatewayCrn] = *data.CRN + + if data.Members != nil { + vpcMembersIpsList := make([]map[string]interface{}, 0) + for _, memberIP := range data.Members { + currentMemberIP := map[string]interface{}{} + if memberIP.PublicIP != nil { + currentMemberIP["address"] = *memberIP.PublicIP.Address + currentMemberIP["role"] = *memberIP.Role + currentMemberIP["status"] = *memberIP.Status + vpcMembersIpsList = append(vpcMembersIpsList, currentMemberIP) + } + if memberIP.PrivateIP != nil && memberIP.PrivateIP.Address != nil { + currentMemberIP["private_address"] = *memberIP.PrivateIP.Address + } + } + gateway[isVPNGatewayMembers] = vpcMembersIpsList + } + + if data.VPC != nil { + vpcList := []map[string]interface{}{} + vpcList = append(vpcList, dataSourceVPNServerCollectionVPNGatewayVpcReferenceToMap(data.VPC)) + gateway["vpc"] = vpcList + } + + vpngateways = append(vpngateways, gateway) + } + + d.SetId(dataSourceIBMVPNGatewaysID(d)) + d.Set(isvpnGateways, vpngateways) + return nil +} + +// dataSourceIBMVPNGatewaysID returns a reasonable ID list. +func dataSourceIBMVPNGatewaysID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceVPNServerCollectionVPNGatewayVpcReferenceToMap(vpcsItem *vpcv1.VPCReference) (vpcsMap map[string]interface{}) { + vpcsMap = map[string]interface{}{} + + if vpcsItem.CRN != nil { + vpcsMap["crn"] = vpcsItem.CRN + } + if vpcsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNGatewayCollectionVpcsDeletedToMap(*vpcsItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcsMap["deleted"] = deletedList + } + if vpcsItem.Href != nil { + vpcsMap["href"] = vpcsItem.Href + } + if vpcsItem.ID != nil { + vpcsMap["id"] = vpcsItem.ID + } + if vpcsItem.Name != nil { + vpcsMap["name"] = vpcsItem.Name + } + + return vpcsMap +} + +func dataSourceVPNGatewayCollectionVpcsDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go new file mode 100644 index 000000000..a97333816 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateways_test.go @@ -0,0 +1,70 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISVpnGatewaysDataSource_basic(t *testing.T) { + var vpnGateway string + node := "data.ibm_is_vpn_gateways.test1" + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVpnGatewaysDataSourceConfig(vpcname, subnetname, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), + resource.TestCheckResourceAttrSet(node, "vpn_gateways.#"), + ), + }, + { + Config: testAccCheckIBMISVpnGatewaysDataSourceConfig(vpcname, subnetname, name1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_gateways.test1", "vpn_gateways.0.vpc.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVpnGatewaysDataSourceConfig(vpc, subnet, name string) string { + // status filter defaults to empty + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + + } + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + } + data "ibm_is_vpn_gateways" "test1" { + + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) + +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server.go b/ibm/service/vpc/data_source_ibm_is_vpn_server.go new file mode 100644 index 000000000..693faa272 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server.go @@ -0,0 +1,793 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServer() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerRead, + + Schema: map[string]*schema.Schema{ + + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique identifier for this VPN server", + }, + + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique user-defined name for this VPN server", + }, + + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The certificate instance for this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance.", + }, + }, + }, + }, + "client_authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of authentication.", + }, + "identity_provider": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered,The type of identity provider to be used by VPN client.", + }, + "client_ca": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance,The certificate instance used for the VPN client certificate authority (CA).", + }, + }, + }, + }, + "client_auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + }, + "client_auto_delete_timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + }, + "client_dns_server_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The DNS server addresses that will be provided to VPN clients that are connected to this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "client_idle_timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients.", + }, + "client_ip_pool": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The VPN client IPv4 address pool, expressed in CIDR format.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN server was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPN server.", + }, + "enable_split_tunneling": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the split tunneling is enabled on this VPN server.", + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Fully qualified domain name assigned to this VPN server.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN server.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN server.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port number used by this VPN server.", + }, + "private_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reserved IPs bound to this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The transport protocol used by this VPN server.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups targeting this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "subnets": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The subnets this VPN server is part of.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "The VPC this VPN server resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNServerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + var vpnServer *vpcv1.VPNServer + + if v, ok := d.GetOk("identifier"); ok { + + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + getVPNServerOptions.SetID(v.(string)) + vpnServerInfo, response, err := sess.GetVPNServerWithContext(context, getVPNServerOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerWithContext failed %s\n%s", err, response)) + } + vpnServer = vpnServerInfo + } else if v, ok := d.GetOk("name"); ok { + + name := v.(string) + start := "" + allrecs := []vpcv1.VPNServer{} + + for { + listVPNServersOptions := &vpcv1.ListVPNServersOptions{} + if start != "" { + listVPNServersOptions.Start = &start + } + vpnServerCollection, response, err := sess.ListVPNServersWithContext(context, listVPNServersOptions) + if err != nil { + log.Printf("[DEBUG] ListVPNServersWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPNServersWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(vpnServerCollection.Next) + allrecs = append(allrecs, vpnServerCollection.VPNServers...) + if start == "" { + break + } + } + + for _, vpnServerInfo := range allrecs { + if *vpnServerInfo.Name == name { + vpnServer = &vpnServerInfo + break + } + } + if vpnServer == nil { + log.Printf("[DEBUG] No vpnServer found with name %s", name) + return diag.FromErr(fmt.Errorf("[ERROR] No vpn server found with name %s", name)) + } + } + + d.SetId(fmt.Sprintf("%s", *vpnServer.ID)) + err = d.Set("identifier", vpnServer.ID) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting identifier %s", err)) + } + + if vpnServer.Certificate != nil { + err = d.Set("certificate", dataSourceVPNServerFlattenCertificate(*vpnServer.Certificate)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting certificate %s", err)) + } + } + + vpnServerAuthenticationPrototypeArray := make([]interface{}, len(vpnServer.ClientAuthentication)) + if vpnServer.ClientAuthentication != nil { + for i, clientAuthenticationItem := range vpnServer.ClientAuthentication { + vpnServerAuthenticationPrototype := make(map[string]interface{}) + vpnServerAuthentication := clientAuthenticationItem.(*vpcv1.VPNServerAuthentication) + if vpnServerAuthentication != nil { + if vpnServerAuthentication.Method != nil { + vpnServerAuthenticationPrototype["method"] = *vpnServerAuthentication.Method + if vpnServerAuthentication.ClientCa != nil && vpnServerAuthentication.ClientCa.CRN != nil { + vpnServerAuthenticationPrototype["client_ca"] = *vpnServerAuthentication.ClientCa.CRN + } + if vpnServerAuthentication.IdentityProvider != nil { + vpnServerAuthenticationByUsernameIDProvider := vpnServerAuthentication.IdentityProvider.(*vpcv1.VPNServerAuthenticationByUsernameIDProvider) + vpnServerAuthenticationPrototype["identity_provider"] = *vpnServerAuthenticationByUsernameIDProvider.ProviderType + } + } + } + vpnServerAuthenticationPrototypeArray[i] = vpnServerAuthenticationPrototype + } + } + err = d.Set("client_authentication", vpnServerAuthenticationPrototypeArray) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_authentication %s", err)) + } + + if err = d.Set("client_auto_delete", vpnServer.ClientAutoDelete); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_auto_delete: %s", err)) + } + if err = d.Set("client_auto_delete_timeout", flex.IntValue(vpnServer.ClientAutoDeleteTimeout)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_auto_delete_timeout: %s", err)) + } + + if vpnServer.ClientDnsServerIps != nil { + err = d.Set("client_dns_server_ips", dataSourceVPNServerFlattenClientDnsServerIps(vpnServer.ClientDnsServerIps)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_dns_server_ips %s", err)) + } + } + if err = d.Set("client_idle_timeout", flex.IntValue(vpnServer.ClientIdleTimeout)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_idle_timeout: %s", err)) + } + if err = d.Set("client_ip_pool", vpnServer.ClientIPPool); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_ip_pool: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnServer.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", vpnServer.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("enable_split_tunneling", vpnServer.EnableSplitTunneling); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enable_split_tunneling: %s", err)) + } + if err = d.Set("health_state", vpnServer.HealthState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting health_state: %s", err)) + } + if err = d.Set("hostname", vpnServer.Hostname); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting hostname: %s", err)) + } + if err = d.Set("href", vpnServer.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", vpnServer.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", vpnServer.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("port", flex.IntValue(vpnServer.Port)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port: %s", err)) + } + + if vpnServer.PrivateIps != nil { + err = d.Set("private_ips", dataSourceVPNServerFlattenPrivateIps(vpnServer.PrivateIps)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting private_ips %s", err)) + } + } + if err = d.Set("protocol", vpnServer.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting protocol: %s", err)) + } + + if vpnServer.ResourceGroup != nil { + err = d.Set("resource_group", dataSourceVPNServerFlattenResourceGroup(*vpnServer.ResourceGroup)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group %s", err)) + } + } + if err = d.Set("resource_type", vpnServer.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + if vpnServer.SecurityGroups != nil { + err = d.Set("security_groups", dataSourceVPNServerFlattenSecurityGroups(vpnServer.SecurityGroups)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting security_groups %s", err)) + } + } + + if vpnServer.Subnets != nil { + err = d.Set("subnets", dataSourceVPNServerFlattenSubnets(vpnServer.Subnets)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnets %s", err)) + } + } + + if vpnServer.VPC != nil { + err = d.Set("vpc", dataSourceVPNServerFlattenVpcReference(vpnServer.VPC)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting the vpc: %s", err)) + } + } + + return nil +} + +func dataSourceVPNServerFlattenCertificate(result vpcv1.CertificateInstanceReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerCertificateToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerCertificateToMap(certificateItem vpcv1.CertificateInstanceReference) (certificateMap map[string]interface{}) { + certificateMap = map[string]interface{}{} + + if certificateItem.CRN != nil { + certificateMap["crn"] = certificateItem.CRN + } + + return certificateMap +} + +func dataSourceVPNServerClientAuthenticationClientCaToMap(clientCaItem vpcv1.CertificateInstanceReference) (clientCaMap map[string]interface{}) { + clientCaMap = map[string]interface{}{} + + if clientCaItem.CRN != nil { + clientCaMap["crn"] = clientCaItem.CRN + } + + return clientCaMap +} + +func dataSourceVPNServerFlattenClientDnsServerIps(result []vpcv1.IP) (clientDnsServerIps []map[string]interface{}) { + for _, clientDnsServerIpsItem := range result { + clientDnsServerIps = append(clientDnsServerIps, dataSourceVPNServerClientDnsServerIpsToMap(clientDnsServerIpsItem)) + } + + return clientDnsServerIps +} + +func dataSourceVPNServerClientDnsServerIpsToMap(clientDnsServerIpsItem vpcv1.IP) (clientDnsServerIpsMap map[string]interface{}) { + clientDnsServerIpsMap = map[string]interface{}{} + + if clientDnsServerIpsItem.Address != nil { + clientDnsServerIpsMap["address"] = clientDnsServerIpsItem.Address + } + + return clientDnsServerIpsMap +} + +func dataSourceVPNServerFlattenPrivateIps(result []vpcv1.ReservedIPReference) (privateIps []map[string]interface{}) { + for _, privateIpsItem := range result { + privateIps = append(privateIps, dataSourceVPNServerPrivateIpsToMap(privateIpsItem)) + } + + return privateIps +} + +func dataSourceVPNServerPrivateIpsToMap(privateIpsItem vpcv1.ReservedIPReference) (privateIpsMap map[string]interface{}) { + privateIpsMap = map[string]interface{}{} + + if privateIpsItem.Address != nil { + privateIpsMap["address"] = privateIpsItem.Address + } + if privateIpsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerPrivateIpsDeletedToMap(*privateIpsItem.Deleted) + deletedList = append(deletedList, deletedMap) + privateIpsMap["deleted"] = deletedList + } + if privateIpsItem.Href != nil { + privateIpsMap["href"] = privateIpsItem.Href + } + if privateIpsItem.ID != nil { + privateIpsMap["id"] = privateIpsItem.ID + } + if privateIpsItem.Name != nil { + privateIpsMap["name"] = privateIpsItem.Name + } + if privateIpsItem.ResourceType != nil { + privateIpsMap["resource_type"] = privateIpsItem.ResourceType + } + + return privateIpsMap +} + +func dataSourceVPNServerPrivateIpsDeletedToMap(deletedItem vpcv1.ReservedIPReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNServerFlattenResourceGroup(result vpcv1.ResourceGroupReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerResourceGroupToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceVPNServerFlattenSecurityGroups(result []vpcv1.SecurityGroupReference) (securityGroups []map[string]interface{}) { + for _, securityGroupsItem := range result { + securityGroups = append(securityGroups, dataSourceVPNServerSecurityGroupsToMap(securityGroupsItem)) + } + + return securityGroups +} + +func dataSourceVPNServerSecurityGroupsToMap(securityGroupsItem vpcv1.SecurityGroupReference) (securityGroupsMap map[string]interface{}) { + securityGroupsMap = map[string]interface{}{} + + if securityGroupsItem.CRN != nil { + securityGroupsMap["crn"] = securityGroupsItem.CRN + } + if securityGroupsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerSecurityGroupsDeletedToMap(*securityGroupsItem.Deleted) + deletedList = append(deletedList, deletedMap) + securityGroupsMap["deleted"] = deletedList + } + if securityGroupsItem.Href != nil { + securityGroupsMap["href"] = securityGroupsItem.Href + } + if securityGroupsItem.ID != nil { + securityGroupsMap["id"] = securityGroupsItem.ID + } + if securityGroupsItem.Name != nil { + securityGroupsMap["name"] = securityGroupsItem.Name + } + + return securityGroupsMap +} + +func dataSourceVPNServerSecurityGroupsDeletedToMap(deletedItem vpcv1.SecurityGroupReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNServerFlattenSubnets(result []vpcv1.SubnetReference) (subnets []map[string]interface{}) { + for _, subnetsItem := range result { + subnets = append(subnets, dataSourceVPNServerSubnetsToMap(subnetsItem)) + } + + return subnets +} + +func dataSourceVPNServerSubnetsToMap(subnetsItem vpcv1.SubnetReference) (subnetsMap map[string]interface{}) { + subnetsMap = map[string]interface{}{} + + if subnetsItem.CRN != nil { + subnetsMap["crn"] = subnetsItem.CRN + } + if subnetsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerSubnetsDeletedToMap(*subnetsItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetsMap["deleted"] = deletedList + } + if subnetsItem.Href != nil { + subnetsMap["href"] = subnetsItem.Href + } + if subnetsItem.ID != nil { + subnetsMap["id"] = subnetsItem.ID + } + if subnetsItem.Name != nil { + subnetsMap["name"] = subnetsItem.Name + } + + return subnetsMap +} + +func dataSourceVPNServerSubnetsDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +// dataSourceVPNServerFlattenVpcRefrence +func dataSourceVPNServerFlattenVpcReference(result *vpcv1.VPCReference) (vpcs []map[string]interface{}) { + vpcs = append(vpcs, dataSourceVPNServerVpcToMap(*result)) + return vpcs +} +func dataSourceVPNServerVpcToMap(vpcItem vpcv1.VPCReference) (vpcsMap map[string]interface{}) { + vpcsMap = map[string]interface{}{} + + if vpcItem.CRN != nil { + vpcsMap["crn"] = vpcItem.CRN + } + if vpcItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerVpcsDeletedToMap(*vpcItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcsMap["deleted"] = deletedList + } + if vpcItem.Href != nil { + vpcsMap["href"] = vpcItem.Href + } + if vpcItem.ID != nil { + vpcsMap["id"] = vpcItem.ID + } + if vpcItem.Name != nil { + vpcsMap["name"] = vpcItem.Name + } + + return vpcsMap +} + +func dataSourceVPNServerVpcsDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_client.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_client.go new file mode 100644 index 000000000..91a1949d6 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_client.go @@ -0,0 +1,199 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServerClient() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerClientRead, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPN server identifier.", + }, + "identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPN client identifier.", + }, + "client_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP address assigned to this VPN client from `client_ip_pool`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "common_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN client was created.", + }, + "disconnected_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN client was disconnected.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN client.", + }, + "remote_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The remote IP address of this VPN client.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "remote_port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The remote port of this VPN client.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server.", + }, + }, + } +} + +func dataSourceIBMIsVPNServerClientRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVPNServerClientOptions := &vpcv1.GetVPNServerClientOptions{} + + getVPNServerClientOptions.SetVPNServerID(d.Get("vpn_server").(string)) + getVPNServerClientOptions.SetID(d.Get("identifier").(string)) + + vpnServerClient, response, err := sess.GetVPNServerClientWithContext(context, getVPNServerClientOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerClientWithContext failed %s\n%s", err, response)) + } + + d.SetId(*vpnServerClient.ID) + + if vpnServerClient.ClientIP != nil { + err = d.Set("client_ip", dataSourceVPNServerClientFlattenClientIP(*vpnServerClient.ClientIP)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_ip %s", err)) + } + } + if err = d.Set("common_name", vpnServerClient.CommonName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting common_name: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnServerClient.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("disconnected_at", flex.DateTimeToString(vpnServerClient.DisconnectedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disconnected_at: %s", err)) + } + if err = d.Set("href", vpnServerClient.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + + if vpnServerClient.RemoteIP != nil { + err = d.Set("remote_ip", dataSourceVPNServerClientFlattenRemoteIP(*vpnServerClient.RemoteIP)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting remote_ip %s", err)) + } + } + if err = d.Set("remote_port", flex.IntValue(vpnServerClient.RemotePort)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting remote_port: %s", err)) + } + if err = d.Set("resource_type", vpnServerClient.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("status", vpnServerClient.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + if err = d.Set("username", vpnServerClient.Username); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting username: %s", err)) + } + + return nil +} + +func dataSourceVPNServerClientFlattenClientIP(result vpcv1.IP) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerClientClientIPToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerClientClientIPToMap(clientIPItem vpcv1.IP) (clientIPMap map[string]interface{}) { + clientIPMap = map[string]interface{}{} + + if clientIPItem.Address != nil { + clientIPMap["address"] = clientIPItem.Address + } + + return clientIPMap +} + +func dataSourceVPNServerClientFlattenRemoteIP(result vpcv1.IP) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerClientRemoteIPToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerClientRemoteIPToMap(remoteIPItem vpcv1.IP) (remoteIPMap map[string]interface{}) { + remoteIPMap = map[string]interface{}{} + + if remoteIPItem.Address != nil { + remoteIPMap["address"] = remoteIPItem.Address + } + + return remoteIPMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config.go new file mode 100644 index 000000000..34d503433 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServerClientConfiguration() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerClientConfigurationRead, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPN server identifier.", + }, + "file_path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The File Path to store configuration.", + }, + "vpn_server_client_configuration": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The VPN client configuration.", + }, + }, + } +} + +func dataSourceIBMIsVPNServerClientConfigurationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVPNServerClientConfigurationOptions := &vpcv1.GetVPNServerClientConfigurationOptions{} + getVPNServerClientConfigurationOptions.SetID(d.Get("vpn_server").(string)) + + result, response, err := sess.GetVPNServerClientConfigurationWithContext(context, getVPNServerClientConfigurationOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerClientWithContext failed %s\n%s", err, response)) + } + + d.SetId(d.Get("vpn_server").(string)) + configStr := *result + configStr = strings.Trim(configStr, "\n") + configStr = strings.Trim(configStr, `"`) + configStr = strings.Replace(configStr, `\n`, "\n", -1) + + if v, ok := d.GetOk("file_path"); ok { + fileName := v.(string) + f, err := os.Create(fileName) + if err == nil { + _, err = f.WriteString(configStr) + } + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Saving VPNServerClientConfiguration Result: %s", err)) + + } + log.Printf("OpenVPN client configuration was saved to {{.%s}}", fileName) + } + + if err = d.Set("vpn_server_client_configuration", *result); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting VPNServerClientConfiguration Result: %s", err)) + } + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config_test.go new file mode 100644 index 000000000..e8ac14c21 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_client_config_test.go @@ -0,0 +1,54 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNServerClientConfigDataSourceBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + nameVpc := fmt.Sprintf("test-vpc-tf-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("test-subnet1-tf-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerClientConfigDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_client_configuration.is_vpn_server_client_configuration", "vpn_server"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerClientConfigDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + data "ibm_is_vpn_server_client_configuration" "is_vpn_server_client_configuration" { + vpn_server = ibm_is_vpn_server.is_vpn_server.id + file_path = "vpnServerClinetConfigFile.txt" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_clients.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_clients.go new file mode 100644 index 000000000..29a6b3f62 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_clients.go @@ -0,0 +1,266 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServerClients() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerClientsRead, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPN server identifier.", + }, + "clients": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of VPN clients.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP address assigned to this VPN client from `client_ip_pool`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "common_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN client was created.", + }, + "disconnected_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN client was disconnected.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN client.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN client.", + }, + "remote_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The remote IP address of this VPN client.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "remote_port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The remote port of this VPN client.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered.", + }, + "username": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNServerClientsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.VPNServerClient{} + + for { + listVPNServerClientsOptions := &vpcv1.ListVPNServerClientsOptions{} + listVPNServerClientsOptions.SetVPNServerID(d.Get("vpn_server").(string)) + if start != "" { + listVPNServerClientsOptions.Start = &start + } + vpnServerClientCollection, response, err := sess.ListVPNServerClientsWithContext(context, listVPNServerClientsOptions) + if err != nil { + log.Printf("[DEBUG] ListVPNServerClientsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPNServerClientsWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(vpnServerClientCollection.Next) + allrecs = append(allrecs, vpnServerClientCollection.Clients...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsVPNServerClientsID(d)) + + if allrecs != nil { + err = d.Set("clients", dataSourceVPNServerClientCollectionFlattenClients(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting clients %s", err)) + } + } + return nil +} + +// dataSourceIBMIsVPNServerClientsID returns a reasonable ID for the list. +func dataSourceIBMIsVPNServerClientsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceVPNServerClientCollectionFlattenClients(result []vpcv1.VPNServerClient) (clients []map[string]interface{}) { + for _, clientsItem := range result { + clients = append(clients, dataSourceVPNServerClientCollectionClientsToMap(clientsItem)) + } + + return clients +} + +func dataSourceVPNServerClientCollectionClientsToMap(clientsItem vpcv1.VPNServerClient) (clientsMap map[string]interface{}) { + clientsMap = map[string]interface{}{} + + if clientsItem.ClientIP != nil { + clientIPList := []map[string]interface{}{} + clientIPMap := dataSourceVPNServerClientCollectionClientsClientIPToMap(*clientsItem.ClientIP) + clientIPList = append(clientIPList, clientIPMap) + clientsMap["client_ip"] = clientIPList + } + if clientsItem.CommonName != nil { + clientsMap["common_name"] = clientsItem.CommonName + } + if clientsItem.CreatedAt != nil { + clientsMap["created_at"] = clientsItem.CreatedAt.String() + } + if clientsItem.DisconnectedAt != nil { + clientsMap["disconnected_at"] = clientsItem.DisconnectedAt.String() + } + if clientsItem.Href != nil { + clientsMap["href"] = clientsItem.Href + } + if clientsItem.ID != nil { + clientsMap["id"] = clientsItem.ID + } + if clientsItem.RemoteIP != nil { + remoteIPList := []map[string]interface{}{} + remoteIPMap := dataSourceVPNServerClientCollectionClientsRemoteIPToMap(*clientsItem.RemoteIP) + remoteIPList = append(remoteIPList, remoteIPMap) + clientsMap["remote_ip"] = remoteIPList + } + if clientsItem.RemotePort != nil { + clientsMap["remote_port"] = clientsItem.RemotePort + } + if clientsItem.ResourceType != nil { + clientsMap["resource_type"] = clientsItem.ResourceType + } + if clientsItem.Status != nil { + clientsMap["status"] = clientsItem.Status + } + if clientsItem.Username != nil { + clientsMap["username"] = clientsItem.Username + } + + return clientsMap +} + +func dataSourceVPNServerClientCollectionClientsClientIPToMap(clientIPItem vpcv1.IP) (clientIPMap map[string]interface{}) { + clientIPMap = map[string]interface{}{} + + if clientIPItem.Address != nil { + clientIPMap["address"] = clientIPItem.Address + } + + return clientIPMap +} + +func dataSourceVPNServerClientCollectionClientsRemoteIPToMap(remoteIPItem vpcv1.IP) (remoteIPMap map[string]interface{}) { + remoteIPMap = map[string]interface{}{} + + if remoteIPItem.Address != nil { + remoteIPMap["address"] = remoteIPItem.Address + } + + return remoteIPMap +} + +func dataSourceVPNServerClientCollectionFlattenFirst(result vpcv1.VPNServerClientCollectionFirst) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerClientCollectionFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerClientCollectionFirstToMap(firstItem vpcv1.VPNServerClientCollectionFirst) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceVPNServerClientCollectionFlattenNext(result vpcv1.VPNServerClientCollectionNext) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerClientCollectionNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerClientCollectionNextToMap(nextItem vpcv1.VPNServerClientCollectionNext) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_route.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_route.go new file mode 100644 index 000000000..bc3e254e7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_route.go @@ -0,0 +1,168 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServerRoute() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerRouteRead, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPN server identifier.", + }, + + "identifier": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique identifier for this VPN server route", + }, + + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique user-defined name for this VPN server route", + }, + + "action": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN route was created.", + }, + "destination": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN route.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN route.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} + +func dataSourceIBMIsVPNServerRouteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + var vpnServerRoute *vpcv1.VPNServerRoute + + if v, ok := d.GetOk("identifier"); ok { + + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + getVPNServerRouteOptions.SetVPNServerID(d.Get("vpn_server").(string)) + getVPNServerRouteOptions.SetID(v.(string)) + + vpnServerRouteInfo, response, err := sess.GetVPNServerRouteWithContext(context, getVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerRouteWithContext failed %s\n%s", err, response)) + } + vpnServerRoute = vpnServerRouteInfo + } else if v, ok := d.GetOk("name"); ok { + name := v.(string) + + start := "" + allrecs := []vpcv1.VPNServerRoute{} + + for { + listVPNServerRoutesOptions := &vpcv1.ListVPNServerRoutesOptions{} + listVPNServerRoutesOptions.SetVPNServerID(d.Get("vpn_server").(string)) + + if start != "" { + listVPNServerRoutesOptions.Start = &start + } + vpnServerRouteCollection, response, err := sess.ListVPNServerRoutesWithContext(context, listVPNServerRoutesOptions) + if err != nil { + log.Printf("[DEBUG] ListVPNServerRoutesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPNServerRoutesWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(vpnServerRouteCollection.Next) + allrecs = append(allrecs, vpnServerRouteCollection.Routes...) + if start == "" { + break + } + } + + for _, vpnServerRouteInfo := range allrecs { + if *vpnServerRouteInfo.Name == name { + vpnServerRoute = &vpnServerRouteInfo + break + } + } + if vpnServerRoute == nil { + log.Printf("[DEBUG] No vpnServer route found with name %s", name) + return diag.FromErr(fmt.Errorf("[ERROR] No vpn server route found with name %s", name)) + } + } + + d.SetId(fmt.Sprintf("%s/%s", d.Get("vpn_server").(string), *vpnServerRoute.ID)) + + if err = d.Set("vpn_server", d.Get("vpn_server").(string)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpn_server: %s", err)) + } + + if err = d.Set("identifier", *vpnServerRoute.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting identifier: %s", err)) + } + if err = d.Set("action", vpnServerRoute.Action); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnServerRoute.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("destination", vpnServerRoute.Destination); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination: %s", err)) + } + if err = d.Set("href", vpnServerRoute.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", vpnServerRoute.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", vpnServerRoute.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("resource_type", vpnServerRoute.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_route_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_route_test.go new file mode 100644 index 000000000..ebd4361d2 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_route_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNServerRouteDataSourceBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + nameVpc := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tf-vpnserver-%d", acctest.RandIntRange(10, 100)) + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + destination := "172.16.0.0/16" + name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + action := "translate" + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerRouteDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "identifier"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "vpn_server"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "destination"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_route.is_vpn_server_route", "resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerRouteDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerRouteConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + data "ibm_is_vpn_server_route" "is_vpn_server_route" { + vpn_server = ibm_is_vpn_server_route.is_vpn_server_route.vpn_server + identifier = ibm_is_vpn_server_route.is_vpn_server_route.vpn_route + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_routes.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_routes.go new file mode 100644 index 000000000..e0c034e09 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_routes.go @@ -0,0 +1,200 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServerRoutes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServerRoutesRead, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The VPN server identifier.", + }, + "routes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of VPN routes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN route was created.", + }, + "destination": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN route.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN route.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN route.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this VPN route.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNServerRoutesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.VPNServerRoute{} + + for { + listVPNServerRoutesOptions := &vpcv1.ListVPNServerRoutesOptions{} + listVPNServerRoutesOptions.SetVPNServerID(d.Get("vpn_server").(string)) + + if start != "" { + listVPNServerRoutesOptions.Start = &start + } + vpnServerRouteCollection, response, err := sess.ListVPNServerRoutesWithContext(context, listVPNServerRoutesOptions) + if err != nil { + log.Printf("[DEBUG] ListVPNServerRoutesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPNServerRoutesWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(vpnServerRouteCollection.Next) + allrecs = append(allrecs, vpnServerRouteCollection.Routes...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsVPNServerRoutesID(d)) + + if allrecs != nil { + err = d.Set("routes", dataSourceVPNServerRouteCollectionFlattenRoutes(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting routes %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsVPNServerRoutesID returns a reasonable ID for the list. +func dataSourceIBMIsVPNServerRoutesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceVPNServerRouteCollectionFlattenFirst(result vpcv1.VPNServerRouteCollectionFirst) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerRouteCollectionFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerRouteCollectionFirstToMap(firstItem vpcv1.VPNServerRouteCollectionFirst) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceVPNServerRouteCollectionFlattenNext(result vpcv1.VPNServerRouteCollectionNext) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerRouteCollectionNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerRouteCollectionNextToMap(nextItem vpcv1.VPNServerRouteCollectionNext) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} + +func dataSourceVPNServerRouteCollectionFlattenRoutes(result []vpcv1.VPNServerRoute) (routes []map[string]interface{}) { + for _, routesItem := range result { + routes = append(routes, dataSourceVPNServerRouteCollectionRoutesToMap(routesItem)) + } + + return routes +} + +func dataSourceVPNServerRouteCollectionRoutesToMap(routesItem vpcv1.VPNServerRoute) (routesMap map[string]interface{}) { + routesMap = map[string]interface{}{} + + if routesItem.Action != nil { + routesMap["action"] = routesItem.Action + } + if routesItem.CreatedAt != nil { + routesMap["created_at"] = routesItem.CreatedAt.String() + } + if routesItem.Destination != nil { + routesMap["destination"] = routesItem.Destination + } + if routesItem.Href != nil { + routesMap["href"] = routesItem.Href + } + if routesItem.ID != nil { + routesMap["id"] = routesItem.ID + } + if routesItem.LifecycleState != nil { + routesMap["lifecycle_state"] = routesItem.LifecycleState + } + if routesItem.Name != nil { + routesMap["name"] = routesItem.Name + } + if routesItem.ResourceType != nil { + routesMap["resource_type"] = routesItem.ResourceType + } + + return routesMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_routes_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_routes_test.go new file mode 100644 index 000000000..57c52d611 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_routes_test.go @@ -0,0 +1,65 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNServerRoutesDataSourceBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + nameVpc := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tf-vpnserver-%d", acctest.RandIntRange(10, 100)) + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + destination := "172.16.0.0/16" + name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + action := "translate" + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerRoutesDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "vpn_server"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.action"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.destination"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.resource_type"), + resource.TestCheckResourceAttr("data.ibm_is_vpn_server_routes.is_vpn_server_routes", "routes.0.destination", "172.16.0.0/16"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerRoutesDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerRouteConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + data "ibm_is_vpn_server_routes" "is_vpn_server_routes" { + vpn_server = ibm_is_vpn_server_route.is_vpn_server_route.vpn_server + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_server_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_server_test.go new file mode 100644 index 000000000..6059d925f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_server_test.go @@ -0,0 +1,81 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNServerDataSourceBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + nameVpc := fmt.Sprintf("test-vpc-tf-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("test-subnet1-tf-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "identifier"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "certificate.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_authentication.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_auto_delete_timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_dns_server_ips.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_idle_timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "client_ip_pool"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "enable_split_tunneling"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "health_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "hostname"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "port"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "private_ips.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "protocol"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "security_groups.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "subnets.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "vpc.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "vpc.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "vpc.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_server.is_vpn_server", "vpc.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + data "ibm_is_vpn_server" "is_vpn_server" { + identifier = ibm_is_vpn_server.is_vpn_server.id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_servers.go b/ibm/service/vpc/data_source_ibm_is_vpn_servers.go new file mode 100644 index 000000000..4b0507f61 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_servers.go @@ -0,0 +1,800 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVPNServers() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVPNServersRead, + + Schema: map[string]*schema.Schema{ + "resource_group_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "resource group identifier.", + }, + "vpn_servers": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of VPN servers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The certificate instance for this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance.", + }, + }, + }, + }, + "client_authentication": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of authentication.", + }, + "identity_provider": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered,The type of identity provider to be used by VPN client.", + }, + "client_ca": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this certificate instance,The certificate instance used for the VPN client certificate authority (CA).", + }, + }, + }, + }, + "client_auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + }, + "client_auto_delete_timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + }, + "client_dns_server_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The DNS server addresses that will be provided to VPN clients that are connected to this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + }, + }, + }, + "client_idle_timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients.", + }, + "client_ip_pool": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The VPN client IPv4 address pool, expressed in CIDR format.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN server was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPN server.", + }, + "enable_split_tunneling": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the split tunneling is enabled on this VPN server.", + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Fully qualified domain name assigned to this VPN server.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN server.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN server.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN server.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPN server.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port number used by this VPN server.", + }, + "private_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reserved IPs bound to this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The transport protocol used by this VPN server.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups targeting this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + }, + }, + }, + }, + "subnets": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The subnets this VPN server is part of.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "vpc": { + Type: schema.TypeSet, + Computed: true, + Description: "The VPC this VPN server resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVPNServersRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + resourceGrp := d.Get("resource_group_id").(string) + + start := "" + allrecs := []vpcv1.VPNServer{} + + for { + listVPNServersOptions := &vpcv1.ListVPNServersOptions{} + if resourceGrp != "" { + listVPNServersOptions.ResourceGroupID = &resourceGrp + } + + if start != "" { + listVPNServersOptions.Start = &start + } + vpnServerCollection, response, err := sess.ListVPNServersWithContext(context, listVPNServersOptions) + if err != nil { + log.Printf("[DEBUG] ListVPNServersWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListVPNServersWithContext failed %s\n%s", err, response)) + } + start = flex.GetNext(vpnServerCollection.Next) + allrecs = append(allrecs, vpnServerCollection.VPNServers...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsVPNServersID(d)) + + if allrecs != nil { + err = d.Set("vpn_servers", dataSourceVPNServerCollectionFlattenVPNServers(allrecs)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpn_servers %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsVPNServersID returns a reasonable ID for the list. +func dataSourceIBMIsVPNServersID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceVPNServerCollectionFlattenFirst(result vpcv1.VPNServerCollectionFirst) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerCollectionFirstToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerCollectionFirstToMap(firstItem vpcv1.VPNServerCollectionFirst) (firstMap map[string]interface{}) { + firstMap = map[string]interface{}{} + + if firstItem.Href != nil { + firstMap["href"] = firstItem.Href + } + + return firstMap +} + +func dataSourceVPNServerCollectionFlattenNext(result vpcv1.VPNServerCollectionNext) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceVPNServerCollectionNextToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceVPNServerCollectionNextToMap(nextItem vpcv1.VPNServerCollectionNext) (nextMap map[string]interface{}) { + nextMap = map[string]interface{}{} + + if nextItem.Href != nil { + nextMap["href"] = nextItem.Href + } + + return nextMap +} + +func dataSourceVPNServerCollectionFlattenVPNServers(result []vpcv1.VPNServer) (vpnServers []map[string]interface{}) { + for _, vpnServersItem := range result { + vpnServers = append(vpnServers, dataSourceVPNServerCollectionVPNServersToMap(vpnServersItem)) + } + + return vpnServers +} + +func dataSourceVPNServerCollectionVPNServersToMap(vpnServersItem vpcv1.VPNServer) (vpnServersMap map[string]interface{}) { + vpnServersMap = map[string]interface{}{} + + if vpnServersItem.Certificate != nil { + certificateList := []map[string]interface{}{} + certificateMap := dataSourceVPNServerCollectionVPNServersCertificateToMap(*vpnServersItem.Certificate) + certificateList = append(certificateList, certificateMap) + vpnServersMap["certificate"] = certificateList + } + + vpnServerAuthenticationPrototypeArray := make([]interface{}, len(vpnServersItem.ClientAuthentication)) + for i, clientAuthenticationItem := range vpnServersItem.ClientAuthentication { + vpnServerAuthenticationPrototype := make(map[string]interface{}) + vpnServerAuthentication := clientAuthenticationItem.(*vpcv1.VPNServerAuthentication) + if vpnServerAuthentication != nil { + if vpnServerAuthentication.Method != nil { + vpnServerAuthenticationPrototype["method"] = *vpnServerAuthentication.Method + if vpnServerAuthentication.ClientCa != nil && vpnServerAuthentication.ClientCa.CRN != nil { + vpnServerAuthenticationPrototype["client_ca"] = *vpnServerAuthentication.ClientCa.CRN + } + if vpnServerAuthentication.IdentityProvider != nil { + vpnServerAuthenticationByUsernameIDProvider := vpnServerAuthentication.IdentityProvider.(*vpcv1.VPNServerAuthenticationByUsernameIDProvider) + vpnServerAuthenticationPrototype["identity_provider"] = *vpnServerAuthenticationByUsernameIDProvider.ProviderType + } + } + } + vpnServerAuthenticationPrototypeArray[i] = vpnServerAuthenticationPrototype + } + vpnServersMap["client_authentication"] = vpnServerAuthenticationPrototypeArray + + if vpnServersItem.ClientAutoDelete != nil { + vpnServersMap["client_auto_delete"] = vpnServersItem.ClientAutoDelete + } + if vpnServersItem.ClientAutoDeleteTimeout != nil { + vpnServersMap["client_auto_delete_timeout"] = vpnServersItem.ClientAutoDeleteTimeout + } + if vpnServersItem.ClientDnsServerIps != nil { + clientDnsServerIpsList := []map[string]interface{}{} + for _, clientDnsServerIpsItem := range vpnServersItem.ClientDnsServerIps { + clientDnsServerIpsList = append(clientDnsServerIpsList, dataSourceVPNServerCollectionVPNServersClientDnsServerIpsToMap(clientDnsServerIpsItem)) + } + vpnServersMap["client_dns_server_ips"] = clientDnsServerIpsList + } + if vpnServersItem.ClientIdleTimeout != nil { + vpnServersMap["client_idle_timeout"] = vpnServersItem.ClientIdleTimeout + } + if vpnServersItem.ClientIPPool != nil { + vpnServersMap["client_ip_pool"] = vpnServersItem.ClientIPPool + } + if vpnServersItem.CreatedAt != nil { + vpnServersMap["created_at"] = vpnServersItem.CreatedAt.String() + } + if vpnServersItem.CRN != nil { + vpnServersMap["crn"] = vpnServersItem.CRN + } + if vpnServersItem.EnableSplitTunneling != nil { + vpnServersMap["enable_split_tunneling"] = vpnServersItem.EnableSplitTunneling + } + if vpnServersItem.HealthState != nil { + vpnServersMap["health_state"] = vpnServersItem.HealthState + } + if vpnServersItem.Hostname != nil { + vpnServersMap["hostname"] = vpnServersItem.Hostname + } + if vpnServersItem.Href != nil { + vpnServersMap["href"] = vpnServersItem.Href + } + if vpnServersItem.ID != nil { + vpnServersMap["id"] = vpnServersItem.ID + } + if vpnServersItem.LifecycleState != nil { + vpnServersMap["lifecycle_state"] = vpnServersItem.LifecycleState + } + if vpnServersItem.Name != nil { + vpnServersMap["name"] = vpnServersItem.Name + } + if vpnServersItem.Port != nil { + vpnServersMap["port"] = vpnServersItem.Port + } + if vpnServersItem.PrivateIps != nil { + privateIpsList := []map[string]interface{}{} + for _, privateIpsItem := range vpnServersItem.PrivateIps { + privateIpsList = append(privateIpsList, dataSourceVPNServerCollectionVPNServersPrivateIpsToMap(privateIpsItem)) + } + vpnServersMap["private_ips"] = privateIpsList + } + if vpnServersItem.Protocol != nil { + vpnServersMap["protocol"] = vpnServersItem.Protocol + } + if vpnServersItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceVPNServerCollectionVPNServersResourceGroupToMap(*vpnServersItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + vpnServersMap["resource_group"] = resourceGroupList + } + if vpnServersItem.ResourceType != nil { + vpnServersMap["resource_type"] = vpnServersItem.ResourceType + } + if vpnServersItem.SecurityGroups != nil { + securityGroupsList := []map[string]interface{}{} + for _, securityGroupsItem := range vpnServersItem.SecurityGroups { + securityGroupsList = append(securityGroupsList, dataSourceVPNServerCollectionVPNServersSecurityGroupsToMap(securityGroupsItem)) + } + vpnServersMap["security_groups"] = securityGroupsList + } + if vpnServersItem.Subnets != nil { + subnetsList := []map[string]interface{}{} + for _, subnetsItem := range vpnServersItem.Subnets { + subnetsList = append(subnetsList, dataSourceVPNServerCollectionVPNServersSubnetsToMap(subnetsItem)) + } + vpnServersMap["subnets"] = subnetsList + } + if vpnServersItem.VPC != nil { + vpcList := []map[string]interface{}{} + // for _, vpcsItem := range vpnServersItem.VPC { + vpcList = append(vpcList, dataSourceVPNServerCollectionVPNServersVpcReferenceToMap(vpnServersItem.VPC)) + // } + vpnServersMap["vpc"] = vpcList + } + + return vpnServersMap +} + +func dataSourceVPNServerCollectionVPNServersCertificateToMap(certificateItem vpcv1.CertificateInstanceReference) (certificateMap map[string]interface{}) { + certificateMap = map[string]interface{}{} + + if certificateItem.CRN != nil { + certificateMap["crn"] = certificateItem.CRN + } + + return certificateMap +} + +func dataSourceVPNServerCollectionClientAuthenticationIdentityProviderToMap(identityProviderItem vpcv1.VPNServerAuthenticationByUsernameIDProvider) (identityProviderMap map[string]interface{}) { + identityProviderMap = map[string]interface{}{} + + if identityProviderItem.ProviderType != nil { + identityProviderMap["provider_type"] = identityProviderItem.ProviderType + } + + return identityProviderMap +} + +func dataSourceVPNServerCollectionClientAuthenticationClientCaToMap(clientCaItem vpcv1.CertificateInstanceReference) (clientCaMap map[string]interface{}) { + clientCaMap = map[string]interface{}{} + + if clientCaItem.CRN != nil { + clientCaMap["crn"] = clientCaItem.CRN + } + + return clientCaMap +} + +func dataSourceVPNServerCollectionVPNServersClientDnsServerIpsToMap(clientDnsServerIpsItem vpcv1.IP) (clientDnsServerIpsMap map[string]interface{}) { + clientDnsServerIpsMap = map[string]interface{}{} + + if clientDnsServerIpsItem.Address != nil { + clientDnsServerIpsMap["address"] = clientDnsServerIpsItem.Address + } + + return clientDnsServerIpsMap +} + +func dataSourceVPNServerCollectionVPNServersPrivateIpsToMap(privateIpsItem vpcv1.ReservedIPReference) (privateIpsMap map[string]interface{}) { + privateIpsMap = map[string]interface{}{} + + if privateIpsItem.Address != nil { + privateIpsMap["address"] = privateIpsItem.Address + } + if privateIpsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerCollectionPrivateIpsDeletedToMap(*privateIpsItem.Deleted) + deletedList = append(deletedList, deletedMap) + privateIpsMap["deleted"] = deletedList + } + if privateIpsItem.Href != nil { + privateIpsMap["href"] = privateIpsItem.Href + } + if privateIpsItem.ID != nil { + privateIpsMap["id"] = privateIpsItem.ID + } + if privateIpsItem.Name != nil { + privateIpsMap["name"] = privateIpsItem.Name + } + if privateIpsItem.ResourceType != nil { + privateIpsMap["resource_type"] = privateIpsItem.ResourceType + } + + return privateIpsMap +} + +func dataSourceVPNServerCollectionPrivateIpsDeletedToMap(deletedItem vpcv1.ReservedIPReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNServerCollectionVPNServersResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + + return resourceGroupMap +} + +func dataSourceVPNServerCollectionVPNServersSecurityGroupsToMap(securityGroupsItem vpcv1.SecurityGroupReference) (securityGroupsMap map[string]interface{}) { + securityGroupsMap = map[string]interface{}{} + + if securityGroupsItem.CRN != nil { + securityGroupsMap["crn"] = securityGroupsItem.CRN + } + if securityGroupsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerCollectionSecurityGroupsDeletedToMap(*securityGroupsItem.Deleted) + deletedList = append(deletedList, deletedMap) + securityGroupsMap["deleted"] = deletedList + } + if securityGroupsItem.Href != nil { + securityGroupsMap["href"] = securityGroupsItem.Href + } + if securityGroupsItem.ID != nil { + securityGroupsMap["id"] = securityGroupsItem.ID + } + if securityGroupsItem.Name != nil { + securityGroupsMap["name"] = securityGroupsItem.Name + } + + return securityGroupsMap +} + +func dataSourceVPNServerCollectionSecurityGroupsDeletedToMap(deletedItem vpcv1.SecurityGroupReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +func dataSourceVPNServerCollectionVPNServersSubnetsToMap(subnetsItem vpcv1.SubnetReference) (subnetsMap map[string]interface{}) { + subnetsMap = map[string]interface{}{} + + if subnetsItem.CRN != nil { + subnetsMap["crn"] = subnetsItem.CRN + } + if subnetsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerCollectionSubnetsDeletedToMap(*subnetsItem.Deleted) + deletedList = append(deletedList, deletedMap) + subnetsMap["deleted"] = deletedList + } + if subnetsItem.Href != nil { + subnetsMap["href"] = subnetsItem.Href + } + if subnetsItem.ID != nil { + subnetsMap["id"] = subnetsItem.ID + } + if subnetsItem.Name != nil { + subnetsMap["name"] = subnetsItem.Name + } + // if subnetsItem.ResourceType != nil { + // subnetsMap["resource_type"] = subnetsItem.ResourceType + // } + + return subnetsMap +} + +func dataSourceVPNServerCollectionSubnetsDeletedToMap(deletedItem vpcv1.SubnetReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + +// dataSourceVPNServerCollectionVPNServersVpcReferenceToMap +func dataSourceVPNServerCollectionVPNServersVpcReferenceToMap(vpcsItem *vpcv1.VPCReference) (vpcsMap map[string]interface{}) { + vpcsMap = map[string]interface{}{} + + if vpcsItem.CRN != nil { + vpcsMap["crn"] = vpcsItem.CRN + } + if vpcsItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceVPNServerCollectionVpcsDeletedToMap(*vpcsItem.Deleted) + deletedList = append(deletedList, deletedMap) + vpcsMap["deleted"] = deletedList + } + if vpcsItem.Href != nil { + vpcsMap["href"] = vpcsItem.Href + } + if vpcsItem.ID != nil { + vpcsMap["id"] = vpcsItem.ID + } + if vpcsItem.Name != nil { + vpcsMap["name"] = vpcsItem.Name + } + // if vpcsItem.ResourceType != nil { + // vpcsMap["resource_type"] = vpcsItem.ResourceType + // } + + return vpcsMap +} + +func dataSourceVPNServerCollectionVpcsDeletedToMap(deletedItem vpcv1.VPCReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_servers_test.go b/ibm/service/vpc/data_source_ibm_is_vpn_servers_test.go new file mode 100644 index 000000000..64e580292 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_vpn_servers_test.go @@ -0,0 +1,68 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsVPNServersDataSourceBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + nameVpc := fmt.Sprintf("test-vpc-tf-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("test-subnet1-tf-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServersDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.client_auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.client_auto_delete_timeout"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.health_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.hostname"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.vpc.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.vpc.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.vpc.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_vpn_servers.is_vpn_servers", "vpn_servers.0.vpc.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVPNServersDataSourceConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + data "ibm_is_vpn_servers" "is_vpn_servers" { + } + `) +} diff --git a/ibm/data_source_ibm_is_zone.go b/ibm/service/vpc/data_source_ibm_is_zone.go similarity index 96% rename from ibm/data_source_ibm_is_zone.go rename to ibm/service/vpc/data_source_ibm_is_zone.go index e99158048..fe89424be 100644 --- a/ibm/data_source_ibm_is_zone.go +++ b/ibm/service/vpc/data_source_ibm_is_zone.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -16,7 +16,7 @@ const ( isZoneStatus = "status" ) -func dataSourceIBMISZone() *schema.Resource { +func DataSourceIBMISZone() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISZoneRead, diff --git a/ibm/service/vpc/data_source_ibm_is_zone_test.go b/ibm/service/vpc/data_source_ibm_is_zone_test.go new file mode 100644 index 000000000..cf7823abe --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_zone_test.go @@ -0,0 +1,39 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISZoneDataSource_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISZoneDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_is_zone.testacc_ds_zone", "name", acc.ISZoneName), + resource.TestCheckResourceAttr("data.ibm_is_zone.testacc_ds_zone", "region", acc.RegionName), + ), + }, + }, + }) +} + +func testAccCheckIBMISZoneDataSourceConfig() string { + return fmt.Sprintf(` + +data "ibm_is_zone" "testacc_ds_zone" { + name = "%s" + region = "%s" +}`, acc.ISZoneName, acc.RegionName) +} diff --git a/ibm/data_source_ibm_is_zones.go b/ibm/service/vpc/data_source_ibm_is_zones.go similarity index 97% rename from ibm/data_source_ibm_is_zones.go rename to ibm/service/vpc/data_source_ibm_is_zones.go index 5b2c92d54..0772cb410 100644 --- a/ibm/data_source_ibm_is_zones.go +++ b/ibm/service/vpc/data_source_ibm_is_zones.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "time" @@ -14,7 +14,7 @@ const ( isZoneNames = "zones" ) -func dataSourceIBMISZones() *schema.Resource { +func DataSourceIBMISZones() *schema.Resource { return &schema.Resource{ Read: dataSourceIBMISZonesRead, diff --git a/ibm/data_source_ibm_is_zones_test.go b/ibm/service/vpc/data_source_ibm_is_zones_test.go similarity index 78% rename from ibm/data_source_ibm_is_zones_test.go rename to ibm/service/vpc/data_source_ibm_is_zones_test.go index 4892620f9..b2ece4148 100644 --- a/ibm/data_source_ibm_is_zones_test.go +++ b/ibm/service/vpc/data_source_ibm_is_zones_test.go @@ -1,25 +1,27 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccIBMISZonesDataSource_1(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISZonesDataSourceConfig1(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones1", "region", regionName), + resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones1", "region", acc.RegionName), resource.TestCheckResourceAttrSet("data.ibm_is_zones.testacc_ds_zones1", "zones.0"), ), }, @@ -33,19 +35,19 @@ func testAccCheckIBMISZonesDataSourceConfig1() string { data "ibm_is_zones" "testacc_ds_zones1" { region = "%s" - }`, regionName) + }`, acc.RegionName) } func TestAccIBMISZonesDataSource_2(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISZonesDataSourceConfig2(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones2", "region", regionName), + resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones2", "region", acc.RegionName), resource.TestCheckResourceAttrSet("data.ibm_is_zones.testacc_ds_zones2", "zones.0"), ), }, @@ -60,19 +62,19 @@ func testAccCheckIBMISZonesDataSourceConfig2() string { data "ibm_is_zones" "testacc_ds_zones2" { region = "%s" status = "" - }`, regionName) + }`, acc.RegionName) } func TestAccIBMISZonesDataSource_3(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISZonesDataSourceConfig3(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones3", "region", regionName), + resource.TestCheckResourceAttr("data.ibm_is_zones.testacc_ds_zones3", "region", acc.RegionName), resource.TestCheckNoResourceAttr("data.ibm_is_zones.testacc_ds_zones3", "zones.0"), ), }, @@ -86,5 +88,5 @@ func testAccCheckIBMISZonesDataSourceConfig3() string { data "ibm_is_zones" "testacc_ds_zones3" { region = "%s" status = "no.status.matches.this" - }`, regionName) + }`, acc.RegionName) } diff --git a/ibm/service/vpc/resource_ibm_is_backup_policy.go b/ibm/service/vpc/resource_ibm_is_backup_policy.go new file mode 100644 index 000000000..c2d16166e --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_backup_policy.go @@ -0,0 +1,299 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsBackupPolicy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsBackupPolicyCreate, + ReadContext: resourceIBMIsBackupPolicyRead, + UpdateContext: resourceIBMIsBackupPolicyUpdate, + DeleteContext: resourceIBMIsBackupPolicyDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "match_resource_types": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: schema.HashString, + Description: "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "match_user_tags": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Description: "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy", "name"), + Description: "The user-defined name for this backup policy. Names must be unique within the region this backup policy resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The unique identifier of the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this backup policy.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy.", + }, + "last_job_completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the most recent job for this backup policy completed.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the backup policy.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsBackupPolicyValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "match_user_tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "match_resource_types", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-z][a-z0-9]*(_[a-z0-9]+)*$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + ) + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_backup_policy", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsBackupPolicyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createBackupPolicyOptions := &vpcv1.CreateBackupPolicyOptions{} + + if _, ok := d.GetOk("match_resource_types"); ok { + createBackupPolicyOptions.SetMatchResourceTypes(flex.ExpandStringList((d.Get("match_resource_types").(*schema.Set)).List())) + } + if _, ok := d.GetOk("match_user_tags"); ok { + createBackupPolicyOptions.SetMatchUserTags((flex.ExpandStringList((d.Get("match_user_tags").(*schema.Set)).List()))) + } + if _, ok := d.GetOk("name"); ok { + createBackupPolicyOptions.SetName(d.Get("name").(string)) + } + if resGroup, ok := d.GetOk("resource_group"); ok { + resourceGroupStr := resGroup.(string) + resourceGroup := vpcv1.ResourceGroupIdentity{ + ID: &resourceGroupStr, + } + createBackupPolicyOptions.SetResourceGroup(&resourceGroup) + } + + backupPolicy, response, err := vpcClient.CreateBackupPolicyWithContext(context, createBackupPolicyOptions) + if err != nil { + log.Printf("[DEBUG] CreateBackupPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] CreateBackupPolicyWithContext failed %s\n%s", err, response)) + } + + d.SetId(*backupPolicy.ID) + + return resourceIBMIsBackupPolicyRead(context, d, meta) +} + +func resourceIBMIsBackupPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getBackupPolicyOptions := &vpcv1.GetBackupPolicyOptions{} + + getBackupPolicyOptions.SetID(d.Id()) + + backupPolicy, response, err := vpcClient.GetBackupPolicyWithContext(context, getBackupPolicyOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetBackupPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyWithContext failed %s\n%s", err, response)) + } + + if backupPolicy.MatchResourceTypes != nil { + if err = d.Set("match_resource_types", backupPolicy.MatchResourceTypes); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_types: %s", err)) + } + } + if backupPolicy.MatchUserTags != nil { + if err = d.Set("match_user_tags", backupPolicy.MatchUserTags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_user_tags: %s", err)) + } + } + if backupPolicy.Name != nil { + if err = d.Set("name", backupPolicy.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + if backupPolicy.ResourceGroup != nil { + resourceGroupID := *backupPolicy.ResourceGroup.ID + if err = d.Set("resource_group", resourceGroupID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + } + if backupPolicy.CreatedAt != nil { + if err = d.Set("created_at", flex.DateTimeToString(backupPolicy.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + } + + if backupPolicy.CRN != nil { + if err = d.Set("crn", backupPolicy.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + } + + if backupPolicy.Href != nil { + if err = d.Set("href", backupPolicy.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + } + + if backupPolicy.LastJobCompletedAt != nil { + if err = d.Set("last_job_completed_at", flex.DateTimeToString(backupPolicy.LastJobCompletedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting last_job_completed_at: %s", err)) + } + } + + if backupPolicy.LifecycleState != nil { + if err = d.Set("lifecycle_state", backupPolicy.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + } + + if backupPolicy.ResourceType != nil { + if err = d.Set("resource_type", backupPolicy.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + } + + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMIsBackupPolicyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + updateBackupPolicyOptions := &vpcv1.UpdateBackupPolicyOptions{} + updateBackupPolicyOptions.SetID(d.Id()) + hasChange := false + patchVals := &vpcv1.BackupPolicyPatch{} + if d.HasChange("match_user_tags") { + patchVals.MatchUserTags = (flex.ExpandStringList((d.Get("match_user_tags").(*schema.Set)).List())) + hasChange = true + } + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + updateBackupPolicyOptions.SetIfMatch(d.Get("version").(string)) + if hasChange { + updateBackupPolicyOptions.BackupPolicyPatch, _ = patchVals.AsPatch() + _, response, err := vpcClient.UpdateBackupPolicyWithContext(context, updateBackupPolicyOptions) + if err != nil { + log.Printf("[DEBUG] UpdateBackupPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateBackupPolicyWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMIsBackupPolicyRead(context, d, meta) +} + +func resourceIBMIsBackupPolicyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + deleteBackupPolicyOptions := &vpcv1.DeleteBackupPolicyOptions{} + deleteBackupPolicyOptions.SetID(d.Id()) + deleteBackupPolicyOptions.SetIfMatch(d.Get("version").(string)) + _, response, err := vpcClient.DeleteBackupPolicyWithContext(context, deleteBackupPolicyOptions) + if err != nil { + log.Printf("[DEBUG] DeleteBackupPolicyWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteBackupPolicyWithContext failed %s\n%s", err, response)) + } + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_backup_policy_plan.go b/ibm/service/vpc/resource_ibm_is_backup_policy_plan.go new file mode 100644 index 000000000..b9b5ae9ef --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_backup_policy_plan.go @@ -0,0 +1,439 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "strconv" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsBackupPolicyPlan() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsBackupPolicyPlanCreate, + ReadContext: resourceIBMIsBackupPolicyPlanRead, + UpdateContext: resourceIBMIsBackupPolicyPlanUpdate, + DeleteContext: resourceIBMIsBackupPolicyPlanDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "backup_policy_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The backup policy identifier.", + }, + "backup_policy_plan_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The backup policy identifier.", + }, + "cron_spec": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy_plan", "cron_spec"), + Description: "The cron specification for the backup schedule.", + }, + "active": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether the plan is active.", + }, + "attach_user_tags": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: schema.HashString, + Description: "User tags to attach to each backup (snapshot) created by this plan. If unspecified, no user tags will be attached.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "copy_user_tags": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether to copy the source's user tags to the created backups (snapshots).", + }, + "deletion_trigger": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delete_after": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 30, + Description: "The maximum number of days to keep each backup after creation.", + }, + "delete_over_count": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The maximum number of recent backups to keep. If unspecified, there will be no maximum.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy_plan", "name"), + Description: "The user-defined name for this backup policy plan. Names must be unique within the backup policy this plan resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the backup policy plan was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Version of the BackupPolicyPlan.", + }, + }, + } +} + +func ResourceIBMIsBackupPolicyPlanValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cron_spec", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^((((\d+,)+\d+|([\d\*]+(\/|-)\d+)|\d+|\*) ?){5,7})$`, + MinValueLength: 9, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_backup_policy_plan", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsBackupPolicyPlanCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createBackupPolicyPlanOptions := &vpcv1.CreateBackupPolicyPlanOptions{} + + createBackupPolicyPlanOptions.SetBackupPolicyID(d.Get("backup_policy_id").(string)) + createBackupPolicyPlanOptions.SetCronSpec(d.Get("cron_spec").(string)) + if _, ok := d.GetOk("active"); ok { + createBackupPolicyPlanOptions.SetActive(d.Get("active").(bool)) + } + if _, ok := d.GetOk("attach_user_tags"); ok { + createBackupPolicyPlanOptions.SetAttachUserTags((flex.ExpandStringList((d.Get("attach_user_tags").(*schema.Set)).List()))) + } + if _, ok := d.GetOk("copy_user_tags"); ok { + createBackupPolicyPlanOptions.SetCopyUserTags(d.Get("copy_user_tags").(bool)) + } + if _, ok := d.GetOk("deletion_trigger"); ok { + backupPolicyPlanDeletionTriggerPrototypeMap := d.Get("deletion_trigger.0").(map[string]interface{}) + backupPolicyPlanDeletionTriggerPrototype := vpcv1.BackupPolicyPlanDeletionTriggerPrototype{} + + if backupPolicyPlanDeletionTriggerPrototypeMap["delete_after"] != nil { + backupPolicyPlanDeletionTriggerPrototype.DeleteAfter = core.Int64Ptr(int64(backupPolicyPlanDeletionTriggerPrototypeMap["delete_after"].(int))) + } + if backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"] != nil { + deleteOverCountString := backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"].(string) + if deleteOverCountString != "" && deleteOverCountString != "null" { + deleteOverCount, err := strconv.ParseInt(backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"].(string), 10, 64) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting delete_over_count: %s", err)) + } + deleteOverCountint := int64(deleteOverCount) + if deleteOverCountint >= int64(0) { + backupPolicyPlanDeletionTriggerPrototype.DeleteOverCount = core.Int64Ptr(deleteOverCountint) + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting delete_over_count: Retention count and days cannot be both zero")) + } + } + } + createBackupPolicyPlanOptions.SetDeletionTrigger(&backupPolicyPlanDeletionTriggerPrototype) + } + if _, ok := d.GetOk("name"); ok { + createBackupPolicyPlanOptions.SetName(d.Get("name").(string)) + } + + backupPolicyPlan, response, err := vpcClient.CreateBackupPolicyPlanWithContext(context, createBackupPolicyPlanOptions) + if err != nil { + log.Printf("[DEBUG] CreateBackupPolicyPlanWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] CreateBackupPolicyPlanWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createBackupPolicyPlanOptions.BackupPolicyID, *backupPolicyPlan.ID)) + + return resourceIBMIsBackupPolicyPlanRead(context, d, meta) +} + +func resourceIBMIsBackupPolicyPlanRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getBackupPolicyPlanOptions := &vpcv1.GetBackupPolicyPlanOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getBackupPolicyPlanOptions.SetBackupPolicyID(parts[0]) + getBackupPolicyPlanOptions.SetID(parts[1]) + + backupPolicyPlan, response, err := vpcClient.GetBackupPolicyPlanWithContext(context, getBackupPolicyPlanOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetBackupPolicyPlanWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyPlanWithContext failed %s\n%s", err, response)) + } + + if getBackupPolicyPlanOptions.BackupPolicyID != nil { + if err = d.Set("backup_policy_id", getBackupPolicyPlanOptions.BackupPolicyID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting backup_policy_id: %s", err)) + } + } + + if getBackupPolicyPlanOptions.ID != nil { + if err = d.Set("backup_policy_plan_id", getBackupPolicyPlanOptions.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting backup_policy_plan_id: %s", err)) + } + } + + if backupPolicyPlan.CronSpec != nil { + if err = d.Set("cron_spec", backupPolicyPlan.CronSpec); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting cron_spec: %s", err)) + } + } + + if backupPolicyPlan.Active != nil { + if err = d.Set("active", backupPolicyPlan.Active); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting active: %s", err)) + } + } + + if backupPolicyPlan.AttachUserTags != nil { + if err = d.Set("attach_user_tags", backupPolicyPlan.AttachUserTags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attach_user_tags: %s", err)) + } + } + + if backupPolicyPlan.CopyUserTags != nil { + if err = d.Set("copy_user_tags", backupPolicyPlan.CopyUserTags); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting copy_user_tags: %s", err)) + } + } + + if backupPolicyPlan.DeletionTrigger != nil { + deletionTriggerMap := resourceIBMIsBackupPolicyPlanBackupPolicyPlanDeletionTriggerPrototypeToMap(*backupPolicyPlan.DeletionTrigger) + if err = d.Set("deletion_trigger", []map[string]interface{}{deletionTriggerMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting deletion_trigger: %s", err)) + } + } + + if backupPolicyPlan.Name != nil { + if err = d.Set("name", backupPolicyPlan.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + + if backupPolicyPlan.CreatedAt != nil { + if err = d.Set("created_at", flex.DateTimeToString(backupPolicyPlan.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + } + + if err = d.Set("href", backupPolicyPlan.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", backupPolicyPlan.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("resource_type", backupPolicyPlan.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMIsBackupPolicyPlanBackupPolicyPlanDeletionTriggerPrototypeToMap(backupPolicyPlanDeletionTriggerPrototype vpcv1.BackupPolicyPlanDeletionTrigger) map[string]interface{} { + backupPolicyPlanDeletionTriggerPrototypeMap := map[string]interface{}{} + + if backupPolicyPlanDeletionTriggerPrototype.DeleteAfter != nil { + backupPolicyPlanDeletionTriggerPrototypeMap["delete_after"] = flex.IntValue(backupPolicyPlanDeletionTriggerPrototype.DeleteAfter) + } + if backupPolicyPlanDeletionTriggerPrototype.DeleteOverCount != nil { + backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"] = strconv.FormatInt(*backupPolicyPlanDeletionTriggerPrototype.DeleteOverCount, 10) + } else { + backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"] = "null" + } + + return backupPolicyPlanDeletionTriggerPrototypeMap +} + +func resourceIBMIsBackupPolicyPlanUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + updateBackupPolicyPlanOptions := &vpcv1.UpdateBackupPolicyPlanOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateBackupPolicyPlanOptions.SetBackupPolicyID(parts[0]) + updateBackupPolicyPlanOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.BackupPolicyPlanPatch{} + if d.HasChange("cron_spec") { + patchVals.CronSpec = core.StringPtr(d.Get("cron_spec").(string)) + hasChange = true + } + if d.HasChange("active") { + patchVals.Active = core.BoolPtr(d.Get("active").(bool)) + hasChange = true + } + if d.HasChange("attach_user_tags") { + patchVals.AttachUserTags = (flex.ExpandStringList((d.Get("attach_user_tags").(*schema.Set)).List())) + hasChange = true + } + if d.HasChange("copy_user_tags") { + patchVals.CopyUserTags = core.BoolPtr(d.Get("copy_user_tags").(bool)) + hasChange = true + } + + deleteOverCountBool := false + if d.HasChange("deletion_trigger") { + backupPolicyPlanDeletionTriggerPrototype := vpcv1.BackupPolicyPlanDeletionTriggerPatch{} + backupPolicyPlanDeletionTriggerPrototypeMap := d.Get("deletion_trigger.0").(map[string]interface{}) + if backupPolicyPlanDeletionTriggerPrototypeMap["delete_after"] != nil { + backupPolicyPlanDeletionTriggerPrototype.DeleteAfter = core.Int64Ptr(int64(backupPolicyPlanDeletionTriggerPrototypeMap["delete_after"].(int))) + } + if backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"] != nil { + deleteOverCountString := backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"].(string) + if deleteOverCountString != "" && deleteOverCountString != "null" { + deleteOverCount, err := strconv.ParseInt(backupPolicyPlanDeletionTriggerPrototypeMap["delete_over_count"].(string), 10, 64) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting delete_over_count: %s", err)) + } + deleteOverCountint := int64(deleteOverCount) + if deleteOverCountint >= int64(0) { + backupPolicyPlanDeletionTriggerPrototype.DeleteOverCount = core.Int64Ptr(deleteOverCountint) + } + } else { + deleteOverCountBool = true + } + } + patchVals.DeletionTrigger = &backupPolicyPlanDeletionTriggerPrototype + hasChange = true + } + + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + updateBackupPolicyPlanOptions.SetIfMatch(d.Get("version").(string)) + + if hasChange { + backupPolicyPlanPatch, err := patchVals.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] [ERROR] Error calling asPatch for BackupPolicyPlanPatch: %s", err)) + } + + if deleteOverCountBool { + backupPolicyPlanDeletionTriggerMap := backupPolicyPlanPatch["deletion_trigger"] + backupPolicyPlanDeletionTrigger := backupPolicyPlanDeletionTriggerMap.(map[string]interface{}) + backupPolicyPlanDeletionTrigger["delete_over_count"] = nil + backupPolicyPlanPatch["deletion_trigger"] = backupPolicyPlanDeletionTrigger + } + + updateBackupPolicyPlanOptions.BackupPolicyPlanPatch = backupPolicyPlanPatch + _, response, err := vpcClient.UpdateBackupPolicyPlanWithContext(context, updateBackupPolicyPlanOptions) + if err != nil { + log.Printf("[DEBUG] UpdateBackupPolicyPlanWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateBackupPolicyPlanWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMIsBackupPolicyPlanRead(context, d, meta) +} + +func resourceIBMIsBackupPolicyPlanDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + deleteBackupPolicyPlanOptions := &vpcv1.DeleteBackupPolicyPlanOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteBackupPolicyPlanOptions.SetBackupPolicyID(parts[0]) + deleteBackupPolicyPlanOptions.SetID(parts[1]) + + deleteBackupPolicyPlanOptions.SetIfMatch(d.Get("version").(string)) + + _, response, err := vpcClient.DeleteBackupPolicyPlanWithContext(context, deleteBackupPolicyPlanOptions) + if err != nil { + log.Printf("[DEBUG] DeleteBackupPolicyPlanWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteBackupPolicyPlanWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_backup_policy_plan_test.go b/ibm/service/vpc/resource_ibm_is_backup_policy_plan_test.go new file mode 100644 index 000000000..5e8aa378e --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_backup_policy_plan_test.go @@ -0,0 +1,213 @@ +// Copyright IBM Corp. 2021, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsBackupPolicyPlanBasic(t *testing.T) { + var conf vpcv1.BackupPolicyPlan + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplanname%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanNameUpdate := fmt.Sprintf("tfbakuppolicyplannameupdate%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + cronSpecUpdate := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()+1) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + if strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute())) == "61" { + cronSpecUpdate = strings.TrimSpace(("1") + " " + strconv.Itoa(time.Now().UTC().Hour()+1) + " " + "*" + " " + "*" + " " + "*") + } + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsBackupPolicyPlanDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyPlanConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsBackupPolicyPlanExists("ibm_is_backup_policy_plan.is_backup_policy_plan.0", conf), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "name", bakupPolicyPlanName+"-1"), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "cron_spec", cronSpec), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "backup_policy_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "backup_policy_plan_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "active"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "copy_user_tags"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "deletion_trigger.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "href"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "version"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyPlanConfigBasic(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpecUpdate, bakupPolicyPlanNameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsBackupPolicyPlanExists("ibm_is_backup_policy_plan.is_backup_policy_plan.0", conf), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "name", bakupPolicyPlanNameUpdate+"-1"), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "cron_spec", cronSpecUpdate), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "backup_policy_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "backup_policy_plan_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "active"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "copy_user_tags"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "deletion_trigger.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "href"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan.0", "version"), + ), + }, + }, + }) +} + +func TestAccIBMIsBackupPolicyPlanImport(t *testing.T) { + var conf vpcv1.BackupPolicyPlan + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + bakupPolicyName := fmt.Sprintf("tfbakuppolicynameimport%d", acctest.RandIntRange(10, 100)) + bakupPolicyPlanName := fmt.Sprintf("tfbakuppolicyplannameimport%d", acctest.RandIntRange(10, 100)) + // bakupPolicyPlanNameUpdate := fmt.Sprintf("tfbakuppolicyplannameupdate%d", acctest.RandIntRange(10, 100)) + cronSpec := strings.TrimSpace(strconv.Itoa(time.Now().UTC().Minute()) + " " + strconv.Itoa(time.Now().UTC().Hour()) + " " + "*" + " " + "*" + " " + "*") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsBackupPolicyPlanDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyPlanConfigImport(bakupPolicyName, vpcname, subnetname, sshname, volname, name, cronSpec, bakupPolicyPlanName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsBackupPolicyPlanExists("ibm_is_backup_policy_plan.is_backup_policy_plan_import", conf), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "name", bakupPolicyPlanName+"-import"), + resource.TestCheckResourceAttr("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "cron_spec", cronSpec), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "backup_policy_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "backup_policy_plan_id"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "active"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "copy_user_tags"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "deletion_trigger.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "href"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy_plan.is_backup_policy_plan_import", "version"), + ), + }, + resource.TestStep{ + ResourceName: "ibm_is_backup_policy_plan.is_backup_policy_plan_import", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsBackupPolicyPlanConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name) + fmt.Sprintf(` + resource "ibm_is_backup_policy_plan" "is_backup_policy_plan" { + count = 2 + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + name = "%s-${count.index+1}" + cron_spec = "%s" + } + `, bakupPolicyPlanName, cronSpec) +} + +func testAccCheckIBMIsBackupPolicyPlanConfigImport(backupPolicyName, vpcname, subnetname, sshname, volName, name, cronSpec, bakupPolicyPlanName string) string { + + return testAccCheckIBMIsBackupPolicyConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volName, name) + fmt.Sprintf(` + resource "ibm_is_backup_policy_plan" "is_backup_policy_plan_import" { + backup_policy_id = ibm_is_backup_policy.is_backup_policy.id + name = "%s-import" + cron_spec = "%s" + } + `, bakupPolicyPlanName, cronSpec) +} + +func testAccCheckIBMIsBackupPolicyPlanExists(n string, obj vpcv1.BackupPolicyPlan) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + getBackupPolicyPlanOptions := &vpcv1.GetBackupPolicyPlanOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getBackupPolicyPlanOptions.SetBackupPolicyID(parts[0]) + getBackupPolicyPlanOptions.SetID(parts[1]) + + backupPolicyPlan, _, err := vpcClient.GetBackupPolicyPlan(getBackupPolicyPlanOptions) + if err != nil { + return err + } + + obj = *backupPolicyPlan + return nil + } +} + +func testAccCheckIBMIsBackupPolicyPlanDestroy(s *terraform.State) error { + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_backup_policy_plan" { + continue + } + + getBackupPolicyPlanOptions := &vpcv1.GetBackupPolicyPlanOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getBackupPolicyPlanOptions.SetBackupPolicyID(parts[0]) + getBackupPolicyPlanOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetBackupPolicyPlan(getBackupPolicyPlanOptions) + + if err == nil { + return fmt.Errorf("BackupPolicyPlan still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for BackupPolicyPlan (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_backup_policy_test.go b/ibm/service/vpc/resource_ibm_is_backup_policy_test.go new file mode 100644 index 000000000..da096e107 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_backup_policy_test.go @@ -0,0 +1,145 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsBackupPolicyBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + backupPolicyName := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + backupPolicyNameUpdate := fmt.Sprintf("tfbakuppolicyname%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsBackupPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyConfigBasic(backupPolicyName, vpcname, subnetname, sshname, volname, name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_backup_policy.is_backup_policy", "name", backupPolicyName), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "match_resource_types.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "match_user_tags.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "resource_group"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "href"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "version"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsBackupPolicyConfigBasic(backupPolicyNameUpdate, vpcname, subnetname, sshname, volname, name), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_backup_policy.is_backup_policy", "name", backupPolicyNameUpdate), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "match_resource_types.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "match_user_tags.#"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "resource_group"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "href"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_backup_policy.is_backup_policy", "version"), + ), + }, + { + ResourceName: "ibm_is_backup_policy.is_backup_policy", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsBackupPolicyConfigBasic(backupPolicyName string, vpcname, subnetname, sshname, volName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + // public_key = file("../../test-fixtures/.ssh/id_rsa") + public_key = file("~/.ssh/id_rsa.pub") + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + # capacity= 200 + tags = ["tag-0"] + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + volumes = [ibm_is_volume.storage.id] + } + + resource "ibm_is_backup_policy" "is_backup_policy" { + depends_on = [ibm_is_instance.testacc_instance] + match_user_tags = ["tag-0"] + name = "%s" + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, backupPolicyName) +} + +func testAccCheckIBMIsBackupPolicyDestroy(s *terraform.State) error { + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_backup_policy" { + continue + } + + getBackupPolicyOptions := &vpcv1.GetBackupPolicyOptions{} + + getBackupPolicyOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := vpcClient.GetBackupPolicy(getBackupPolicyOptions) + + if err == nil { + return fmt.Errorf("BackupPolicy still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for BackupPolicy (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go new file mode 100644 index 000000000..9065cbb84 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go @@ -0,0 +1,2358 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "os" + "reflect" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerAction = "action" + isBareMetalServerBandwidth = "bandwidth" + isBareMetalServerBootTarget = "boot_target" + isBareMetalServerCreatedAt = "created_at" + isBareMetalServerCPU = "cpu" + isBareMetalServerCPUArchitecture = "architecture" + isBareMetalServerCPUCoreCount = "core_count" + isBareMetalServerCpuSocketCount = "socket_count" + isBareMetalServerCpuThreadPerCore = "threads_per_core" + isBareMetalServerCRN = "crn" + isBareMetalServerDisks = "disks" + isBareMetalServerDiskID = "id" + isBareMetalServerDiskSize = "size" + isBareMetalServerDiskName = "name" + isBareMetalServerDiskInterfaceType = "interface_type" + isBareMetalServerHref = "href" + isBareMetalServerMemory = "memory" + isBareMetalServerTags = "tags" + isBareMetalServerName = "name" + isBareMetalServerNetworkInterfaces = "network_interfaces" + isBareMetalServerPrimaryNetworkInterface = "primary_network_interface" + isBareMetalServerProfile = "profile" + isBareMetalServerResourceGroup = "resource_group" + isBareMetalServerResourceType = "resource_type" + isBareMetalServerStatus = "status" + isBareMetalServerStatusReasons = "status_reasons" + isBareMetalServerVPC = "vpc" + isBareMetalServerZone = "zone" + isBareMetalServerStatusReasonsCode = "code" + isBareMetalServerStatusReasonsMessage = "message" + isBareMetalServerStatusReasonsMoreInfo = "more_info" + isBareMetalServerDeleteType = "delete_type" + isBareMetalServerImage = "image" + isBareMetalServerKeys = "keys" + isBareMetalServerUserData = "user_data" + isBareMetalServerNicName = "name" + isBareMetalServerNicPortSpeed = "port_speed" + isBareMetalServerNicAllowIPSpoofing = "allow_ip_spoofing" + isBareMetalServerNicSecurityGroups = "security_groups" + isBareMetalServerNicSubnet = "subnet" + isBareMetalServerUserAccounts = "user_accounts" + isBareMetalServerActionDeleting = "deleting" + isBareMetalServerActionDeleted = "deleted" + isBareMetalServerActionStatusStopping = "stopping" + isBareMetalServerActionStatusStopped = "stopped" + isBareMetalServerActionStatusStarting = "starting" + isBareMetalServerStatusRunning = "running" + isBareMetalServerStatusPending = "pending" + isBareMetalServerStatusRestarting = "restarting" + isBareMetalServerStatusFailed = "failed" +) + +func ResourceIBMIsBareMetalServer() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerCreate, + ReadContext: resourceIBMISBareMetalServerRead, + UpdateContext: resourceIBMISBareMetalServerUpdate, + DeleteContext: resourceIBMISBareMetalServerDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) (result []*schema.ResourceData, err error) { + log.Printf("[INFO] Bare metal server (%s) importing", d.Id()) + d.Set(isBareMetalServerDeleteType, "hard") + return []*schema.ResourceData{d}, nil + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + ), + + Schema: map[string]*schema.Schema{ + + isBareMetalServerName: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerName), + Description: "Bare metal server name", + }, + + isBareMetalServerAction: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerAction), + Description: "This restart/start/stops a bare metal server.", + }, + isBareMetalServerBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second)", + }, + isBareMetalServerBootTarget: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + + isBareMetalServerCPU: { + Type: schema.TypeList, + Computed: true, + Description: "The bare metal server CPU configuration", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerCPUArchitecture: { + Type: schema.TypeString, + Computed: true, + Description: "The CPU architecture", + }, + isBareMetalServerCPUCoreCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of cores", + }, + isBareMetalServerCpuSocketCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of CPU sockets", + }, + isBareMetalServerCpuThreadPerCore: { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of hardware threads per core", + }, + }, + }, + }, + isBareMetalServerCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this bare metal server", + }, + isBareMetalServerDisks: { + Type: schema.TypeList, + Computed: true, + Description: "The disks for this bare metal server, including any disks that are associated with the boot_target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerDiskHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk", + }, + isBareMetalServerDiskID: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server disk", + }, + isBareMetalServerDiskInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + }, + isBareMetalServerDiskName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk", + }, + isBareMetalServerDiskResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + isBareMetalServerDiskSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes)", + }, + }, + }, + }, + isBareMetalServerHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server", + }, + isBareMetalServerMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of memory, truncated to whole gibibytes", + }, + isBareMetalServerDeleteType: { + Type: schema.TypeString, + Optional: true, + Default: "hard", + Description: "Enables stopping type of the bare metal server before deleting", + }, + isBareMetalServerPrimaryNetworkInterface: { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Computed: true, + Description: "title: IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.reserved_ip"}, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.reserved_ip"}, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.reserved_ip"}, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.address", "primary_network_interface.0.primary_ip.0.auto_delete", "primary_network_interface.0.primary_ip.0.name"}, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + }, + }, + }, + + isBareMetalServerNetworkInterfaces: { + Type: schema.TypeSet, + Optional: true, + Set: resourceIBMBMSNicSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "The user-defined name for this network interface. If unspecified, the name will be a hyphenated list of randomly-selected words", + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + MinItems: 0, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "title: IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Collection of security group ids", + }, + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + Description: "The associated subnet", + }, + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + }, + }, + }, + + isBareMetalServerKeys: { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + DiffSuppressFunc: flex.ApplyOnce, + Description: "SSH key Ids for the bare metal server", + }, + + isBareMetalServerImage: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "image id", + }, + isBareMetalServerProfile: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "profile name", + }, + + isBareMetalServerUserData: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "User data given for the bare metal server", + }, + + isBareMetalServerZone: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Zone name", + }, + + isBareMetalServerVPC: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The VPC the bare metal server is to be a part of", + }, + + isBareMetalServerResourceGroup: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Resource group name", + }, + isBareMetalServerResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Resource type name", + }, + + isBareMetalServerStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server status", + }, + + isBareMetalServerStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isBareMetalServerStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + isBareMetalServerStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + isBareMetalServerTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Tags for the Bare metal server", + }, + }, + } +} + +func ResourceIBMIsBareMetalServerValidator() *validate.ResourceValidator { + bareMetalServerActions := "start, restart, stop" + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: bareMetalServerActions}) + ibmISBareMetalServerResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server", Schema: validateSchema} + return &ibmISBareMetalServerResourceValidator +} + +func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.CreateBareMetalServerOptions{} + var imageStr string + if image, ok := d.GetOk(isBareMetalServerImage); ok { + imageStr = image.(string) + } + keySet := d.Get(isBareMetalServerKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + options.Initialization = &vpcv1.BareMetalServerInitializationPrototype{ + Image: &vpcv1.ImageIdentity{ + ID: &imageStr, + }, + Keys: keyobjs, + } + if userdata, ok := d.GetOk(isBareMetalServerUserData); ok { + userdatastr := userdata.(string) + options.Initialization.UserData = &userdatastr + } + } + + if name, ok := d.GetOk(isBareMetalServerName); ok { + nameStr := name.(string) + options.Name = &nameStr + } + + if primnicintf, ok := d.GetOk(isBareMetalServerPrimaryNetworkInterface); ok && len(primnicintf.([]interface{})) > 0 { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.BareMetalServerPrimaryNetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := primnic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + + if primaryIpIntf, ok := primnic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + primnicobj.PrimaryIP = primaryip + } + } + } + + allowIPSpoofing, ok := primnic[isBareMetalServerNicAllowIPSpoofing] + + if ok && allowIPSpoofing != nil { + allowIPSpoofingbool := allowIPSpoofing.(bool) + if allowIPSpoofingbool { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + } + enableInfraNATbool := true + enableInfraNAT, ok := primnic[isBareMetalServerNicEnableInfraNAT] + if ok && enableInfraNAT != nil { + enableInfraNATbool = enableInfraNAT.(bool) + primnicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + secgrpintf, ok := primnic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + + if allowedVlansOk, ok := primnic[isBareMetalServerNicAllowedVlans]; ok { + allowedVlansList := allowedVlansOk.(*schema.Set).List() + + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + primnicobj.AllowedVlans = allowedVlans + interfaceType := "pci" + primnicobj.InterfaceType = &interfaceType + } + options.PrimaryNetworkInterface = primnicobj + } + + if nicsintf, ok := d.GetOk(isBareMetalServerNetworkInterfaces); ok { + + nics := nicsintf.(*schema.Set).List() + inlinenicobj := make([]vpcv1.BareMetalServerNetworkInterfacePrototypeIntf, 0) + for _, resource := range nics { + nic := resource.(map[string]interface{}) + interfaceType := "" + + if allowedVlansOk, ok := nic[isBareMetalServerNicAllowedVlans]; ok { + interfaceType = "pci" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByPciPrototype{} + nicobj.InterfaceType = &interfaceType + + allowedVlansList := allowedVlansOk.(*schema.Set).List() + + if len(allowedVlansList) > 0 { + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + nicobj.AllowedVlans = allowedVlans + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + inlinenicobj = append(inlinenicobj, nicobj) + } else { + interfaceType = "vlan" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + nicobj.InterfaceType = &interfaceType + + if aitf, ok := nic[isBareMetalServerNicAllowInterfaceToFloat]; ok { + allowInterfaceToFloat := aitf.(bool) + nicobj.AllowInterfaceToFloat = &allowInterfaceToFloat + } + if vlan, ok := nic[isBareMetalServerNicVlan]; ok { + vlanInt := int64(vlan.(int)) + nicobj.Vlan = &vlanInt + } + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + inlinenicobj = append(inlinenicobj, nicobj) + } + } else { + interfaceType = "vlan" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + nicobj.InterfaceType = &interfaceType + + if aitf, ok := nic[isBareMetalServerNicAllowInterfaceToFloat]; ok { + allowInterfaceToFloat := aitf.(bool) + nicobj.AllowInterfaceToFloat = &allowInterfaceToFloat + } + if vlan, ok := nic[isBareMetalServerNicVlan]; ok { + vlanInt := int64(vlan.(int)) + nicobj.Vlan = &vlanInt + } + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + inlinenicobj = append(inlinenicobj, nicobj) + } + } + options.NetworkInterfaces = inlinenicobj + } + + if rgrp, ok := d.GetOk(isBareMetalServerResourceGroup); ok { + rg := rgrp.(string) + options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + if p, ok := d.GetOk(isBareMetalServerProfile); ok { + profile := p.(string) + options.Profile = &vpcv1.BareMetalServerProfileIdentity{ + Name: &profile, + } + } + + if z, ok := d.GetOk(isBareMetalServerZone); ok { + zone := z.(string) + options.Zone = &vpcv1.ZoneIdentity{ + Name: &zone, + } + } + + if v, ok := d.GetOk(isBareMetalServerVPC); ok { + vpc := v.(string) + options.VPC = &vpcv1.VPCIdentity{ + ID: &vpc, + } + } + + bms, response, err := sess.CreateBareMetalServerWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[DEBUG] Create bare metal server err %s\n%s", err, response)) + } + d.SetId(*bms.ID) + log.Printf("[INFO] Bare Metal Server : %s", *bms.ID) + _, err = isWaitForBareMetalServerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isBareMetalServerTags); ok || v != "" { + oldList, newList := d.GetChange(isBareMetalServerTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *bms.CRN) + if err != nil { + log.Printf( + "[ERROR] Error on create of resource bare metal server (%s) tags: %s", d.Id(), err) + } + } + + return resourceIBMISBareMetalServerRead(context, d, meta) +} + +func resourceIBMISBareMetalServerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + err := bareMetalServerGet(context, d, meta, id) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + d.SetId(*bms.ID) + d.Set(isBareMetalServerBandwidth, bms.Bandwidth) + bmsBootTargetIntf := bms.BootTarget.(*vpcv1.BareMetalServerBootTarget) + bmsBootTarget := bmsBootTargetIntf.ID + d.Set(isBareMetalServerBootTarget, bmsBootTarget) + cpuList := make([]map[string]interface{}, 0) + if bms.Cpu != nil { + currentCPU := map[string]interface{}{} + currentCPU[isBareMetalServerCPUArchitecture] = *bms.Cpu.Architecture + currentCPU[isBareMetalServerCPUCoreCount] = *bms.Cpu.CoreCount + currentCPU[isBareMetalServerCpuSocketCount] = *bms.Cpu.SocketCount + currentCPU[isBareMetalServerCpuThreadPerCore] = *bms.Cpu.ThreadsPerCore + cpuList = append(cpuList, currentCPU) + } + d.Set(isBareMetalServerCPU, cpuList) + d.Set(isBareMetalServerCRN, *bms.CRN) + + diskList := make([]map[string]interface{}, 0) + if bms.Disks != nil { + for _, disk := range bms.Disks { + currentDisk := map[string]interface{}{ + isBareMetalServerDiskHref: disk.Href, + isBareMetalServerDiskID: disk.ID, + isBareMetalServerDiskInterfaceType: disk.InterfaceType, + isBareMetalServerDiskName: disk.Name, + isBareMetalServerDiskResourceType: disk.ResourceType, + isBareMetalServerDiskSize: disk.Size, + } + diskList = append(diskList, currentDisk) + } + } + d.Set(isBareMetalServerDisks, diskList) + d.Set(isBareMetalServerHref, *bms.Href) + d.Set(isBareMetalServerMemory, *bms.Memory) + d.Set(isBareMetalServerName, *bms.Name) + + // get initialization + getBmsInitialization := &vpcv1.GetBareMetalServerInitializationOptions{ + ID: bms.ID, + } + bmsinitialization, response, err := sess.GetBareMetalServerInitializationWithContext(context, getBmsInitialization) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) initialization: %s\n%s", id, err, response) + } + if bmsinitialization != nil && bmsinitialization.Image.ID != nil { + d.Set(isBareMetalServerImage, *bmsinitialization.Image.ID) + } + if bmsinitialization != nil && bmsinitialization.Keys != nil { + keyList := []string{} + if len(bmsinitialization.Keys) != 0 { + for i := 0; i < len(bmsinitialization.Keys); i++ { + keyList = append(keyList, string(*(bmsinitialization.Keys[i].ID))) + } + } + d.Set(isBareMetalServerKeys, keyList) + } + + //pni + + if bms.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *bms.PrimaryNetworkInterface.ID + currentPrimNic[isBareMetalServerNicName] = *bms.PrimaryNetworkInterface.Name + currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href + currentPrimNic[isBareMetalServerNicSubnet] = *bms.PrimaryNetworkInterface.Subnet.ID + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + ID: bms.PrimaryNetworkInterface.ID, + } + bmsnic, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, getnicoptions) + + if err != nil { + return fmt.Errorf("[ERROR] Error getting primary network interface attached to the bare metal server %s\n%s", err, response) + } + + if bms.PrimaryNetworkInterface.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *bms.PrimaryNetworkInterface.PrimaryIP.Address + } + if bms.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *bms.PrimaryNetworkInterface.PrimaryIP.Href + } + if bms.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *bms.PrimaryNetworkInterface.PrimaryIP.Name + } + if bms.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *bms.PrimaryNetworkInterface.PrimaryIP.ID + } + if bms.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *bms.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + + primaryIpList = append(primaryIpList, currentIP) + currentPrimNic[isBareMetalServerNicPrimaryIP] = primaryIpList + + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: bms.PrimaryNetworkInterface.Subnet.ID, + ID: bms.PrimaryNetworkInterface.PrimaryIP.ID, + } + bmsRip, response, err := sess.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the bare metal server primary network interface(%s): %s\n%s", *bms.PrimaryNetworkInterface.PrimaryIP.ID, *bms.PrimaryNetworkInterface.ID, err, response) + } + currentIP[isBareMetalServerNicIpAutoDelete] = bmsRip.AutoDelete + } + switch reflect.TypeOf(bmsnic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentPrimNic[isBareMetalServerNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicEnableInfraNAT] = *primNic.EnableInfrastructureNat + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + if primNic.AllowedVlans != nil { + var out = make([]interface{}, len(primNic.AllowedVlans), len(primNic.AllowedVlans)) + for i, v := range primNic.AllowedVlans { + out[i] = int(v) + } + currentPrimNic[isBareMetalServerNicAllowedVlans] = schema.NewSet(schema.HashInt, out) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + currentPrimNic[isBareMetalServerNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicEnableInfraNAT] = *primNic.EnableInfrastructureNat + + if len(primNic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(primNic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(primNic.SecurityGroups[i].ID))) + } + currentPrimNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + + primaryNicList = append(primaryNicList, currentPrimNic) + d.Set(isBareMetalServerPrimaryNetworkInterface, primaryNicList) + } + + //ni + if bms.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range bms.NetworkInterfaces { + flagAllowFloat := false + if *intfc.ID != *bms.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + subnetId := *intfc.Subnet.ID + ripId := "" + nicId := *intfc.ID + currentNic["id"] = nicId + currentNic[isBareMetalServerNicName] = *intfc.Name + currentNic[isBareMetalServerNicHref] = *intfc.Href + currentNic[isBareMetalServerNicSubnet] = subnetId + + getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + ID: &nicId, + } + bmsnicintf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface(%s) attached to the bare metal server(%s) %s\n%s", nicId, id, err, response) + } + if intfc.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + ripId = *intfc.PrimaryIP.ID + currentIP[isBareMetalServerNicIpID] = ripId + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + bmsRip, response, err := sess.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the bare metal server network interface(%s): %s\n%s", ripId, nicId, err, response) + } + if bmsRip.AutoDelete != nil { + currentIP[isBareMetalServerNicIpAutoDelete] = *bmsRip.AutoDelete + } + } + if intfc.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *intfc.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList + } + + switch reflect.TypeOf(bmsnicintf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicEnableInfraNAT] = *bmsnic.EnableInfrastructureNat + currentNic[isBareMetalServerNicPortSpeed] = *bmsnic.PortSpeed + currentNic[isBareMetalServerNicInterfaceType] = "pci" + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + if bmsnic.AllowedVlans != nil { + var out = make([]interface{}, len(bmsnic.AllowedVlans), len(bmsnic.AllowedVlans)) + for i, v := range bmsnic.AllowedVlans { + out[i] = int(v) + } + currentNic[isBareMetalServerNicAllowedVlans] = schema.NewSet(schema.HashInt, out) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + bmsnic := bmsnicintf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + if bmsnic.AllowInterfaceToFloat != nil { + flagAllowFloat = *bmsnic.AllowInterfaceToFloat + } + currentNic[isBareMetalServerNicAllowIPSpoofing] = *bmsnic.AllowIPSpoofing + currentNic[isBareMetalServerNicEnableInfraNAT] = *bmsnic.EnableInfrastructureNat + currentNic[isBareMetalServerNicPortSpeed] = *bmsnic.PortSpeed + currentNic[isBareMetalServerNicInterfaceType] = "vlan" + if bmsnic.Vlan != nil { + currentNic[isBareMetalServerNicVlan] = *bmsnic.Vlan + } + if len(bmsnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(bmsnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(bmsnic.SecurityGroups[i].ID))) + } + currentNic[isBareMetalServerNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + } + } + if !flagAllowFloat { + interfacesList = append(interfacesList, currentNic) + } + } + } + d.Set(isBareMetalServerNetworkInterfaces, interfacesList) + } + d.Set(isBareMetalServerProfile, *bms.Profile.Name) + if bms.ResourceGroup != nil { + d.Set(isBareMetalServerResourceGroup, *bms.ResourceGroup.ID) + } + d.Set(isBareMetalServerResourceType, bms.ResourceType) + d.Set(isBareMetalServerStatus, *bms.Status) + statusReasonsList := make([]map[string]interface{}, 0) + if bms.StatusReasons != nil { + for _, sr := range bms.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isBareMetalServerStatusReasonsCode] = *sr.Code + currentSR[isBareMetalServerStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isBareMetalServerStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + } + d.Set(isBareMetalServerStatusReasons, statusReasonsList) + d.Set(isBareMetalServerVPC, *bms.VPC.ID) + d.Set(isBareMetalServerZone, *bms.Zone.Name) + + tags, err := flex.GetTagsUsingCRN(meta, *bms.CRN) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource bare metal server (%s) tags: %s", d.Id(), err) + } + d.Set(isBareMetalServerTags, tags) + + return nil +} + +func resourceIBMISBareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + id := d.Id() + + err := bareMetalServerUpdate(context, d, meta, id) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMISBareMetalServerRead(context, d, meta) +} + +func bareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + if d.HasChange(isBareMetalServerTags) { + bmscrn := d.Get(isBareMetalServerCRN).(string) + if bmscrn == "" { + options := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + bmscrn = *bms.CRN + } + oldList, newList := d.GetChange(isBareMetalServerTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, bmscrn) + if err != nil { + log.Printf( + "Error on update of vpc Bare metal server (%s) tags: %s", id, err) + } + } + + if d.HasChange(isBareMetalServerNetworkInterfaces) { + oldList, newList := d.GetChange(isBareMetalServerNetworkInterfaces) + if oldList == nil { + oldList = new(schema.Set) + } + if newList == nil { + newList = new(schema.Set) + } + os := oldList.(*schema.Set) + ns := newList.(*schema.Set) + for _, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + for _, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + if strings.Compare(newPack["name"].(string), oldPack["name"].(string)) == 0 { + networkId := newPack["id"].(string) + newAllowedVlans := newPack[isBareMetalServerNicAllowedVlans].(*schema.Set) + newNicName := newPack[isBareMetalServerNicName].(string) + newIpSpoofing := newPack[isBareMetalServerNicAllowIPSpoofing].(bool) + newInfraNat := newPack[isBareMetalServerNicEnableInfraNAT].(bool) + + oldAllowedVlans := oldPack[isBareMetalServerNicAllowedVlans].(*schema.Set) + oldNicName := oldPack[isBareMetalServerNicName].(string) + oldIpSpoofing := oldPack[isBareMetalServerNicAllowIPSpoofing].(bool) + oldInfraNat := oldPack[isBareMetalServerNicEnableInfraNAT].(bool) + + if oldAllowedVlans.Difference(newAllowedVlans).Len() > 0 || newAllowedVlans.Difference(oldAllowedVlans).Len() > 0 || newInfraNat != oldInfraNat || newIpSpoofing != oldIpSpoofing { + + updatepnicfoptions := &vpcv1.UpdateBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + ID: &networkId, + } + + bmsPatchModel := &vpcv1.BareMetalServerNetworkInterfacePatch{} + if strings.Compare(newNicName, oldNicName) != 0 { + bmsPatchModel.Name = &newNicName + } + + if oldAllowedVlans.Difference(newAllowedVlans).Len() > 0 || newAllowedVlans.Difference(oldAllowedVlans).Len() > 0 { + allowedVlansList := newPack[isBareMetalServerNicAllowedVlans].(*schema.Set).List() + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + bmsPatchModel.AllowedVlans = allowedVlans + } + + if newIpSpoofing != oldIpSpoofing { + bmsPatchModel.AllowIPSpoofing = &newIpSpoofing + } + if newInfraNat != oldInfraNat { + bmsPatchModel.EnableInfrastructureNat = &newInfraNat + } + networkInterfacePatch, err := bmsPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerNetworkInterfacePatch: %s", err) + } + updatepnicfoptions.BareMetalServerNetworkInterfacePatch = networkInterfacePatch + _, response, err := sess.UpdateBareMetalServerNetworkInterface(updatepnicfoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while updating network interface(%s) of bar emetal server(%s) \n%s: %q", networkId, d.Id(), err, response) + } + ns.Remove(nA) + os.Remove(oA) + } + } + } + } + remove := os.Difference(ns).List() + + if len(remove) > 0 { + // check if any removing nic is of pci type + flag := false + for _, rem := range remove { + oldNic := rem.(map[string]interface{}) + interfaceType := oldNic["interface_type"].(string) + if interfaceType == "pci" { + flag = true + } + } + if flag { + err = resourceStopServerIfRunning(id, "hard", d, context, sess) + if err != nil { + return err + } + } + for _, rem := range remove { + oldNic := rem.(map[string]interface{}) + networkId := oldNic["id"].(string) + removeBMSNic := &vpcv1.DeleteBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + ID: &networkId, + } + _, err = sess.DeleteBareMetalServerNetworkInterface(removeBMSNic) + if err != nil { + return err + } + } + + if flag { + err = resourceStartServerIfStopped(id, "hard", d, context, sess) + if err != nil { + return err + } + } + } + add := ns.Difference(os).List() + if len(add) > 0 { + // check if any adding nic is of pci type + flag := false + for _, a := range add { + oldNic := a.(map[string]interface{}) + allowedVlansOk, ok := oldNic[isBareMetalServerNicAllowedVlans] + if ok && len(allowedVlansOk.(*schema.Set).List()) > 0 { + flag = true + } + } + if flag { + err = resourceStopServerIfRunning(id, "hard", d, context, sess) + if err != nil { + return err + } + } + for _, a := range add { + nic := a.(map[string]interface{}) + addNicOptions := &vpcv1.CreateBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + } + interfaceType := "" + + if allowedVlansOk, ok := nic[isBareMetalServerNicAllowedVlans]; ok { + interfaceType = "pci" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByPciPrototype{} + nicobj.InterfaceType = &interfaceType + + allowedVlansList := allowedVlansOk.(*schema.Set).List() + + if len(allowedVlansList) > 0 { + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + nicobj.AllowedVlans = allowedVlans + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + addNicOptions.BareMetalServerNetworkInterfacePrototype = nicobj + } else { + interfaceType = "vlan" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + nicobj.InterfaceType = &interfaceType + + if aitf, ok := nic[isBareMetalServerNicAllowInterfaceToFloat]; ok { + allowInterfaceToFloat := aitf.(bool) + nicobj.AllowInterfaceToFloat = &allowInterfaceToFloat + } + if vlan, ok := nic[isBareMetalServerNicVlan]; ok { + vlanInt := int64(vlan.(int)) + nicobj.Vlan = &vlanInt + } + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + addNicOptions.BareMetalServerNetworkInterfacePrototype = nicobj + } + } else { + interfaceType = "vlan" + var nicobj = &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + nicobj.InterfaceType = &interfaceType + + if aitf, ok := nic[isBareMetalServerNicAllowInterfaceToFloat]; ok { + allowInterfaceToFloat := aitf.(bool) + nicobj.AllowInterfaceToFloat = &allowInterfaceToFloat + } + if vlan, ok := nic[isBareMetalServerNicVlan]; ok { + vlanInt := int64(vlan.(int)) + nicobj.Vlan = &vlanInt + } + + subnetintf, _ := nic[isBareMetalServerNicSubnet] + subnetintfstr := subnetintf.(string) + nicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := nic[isBareMetalServerNicName] + namestr := name.(string) + if namestr != "" { + nicobj.Name = &namestr + } + + enableInfraNAT, ok := nic[isBareMetalServerNicEnableInfraNAT] + enableInfraNATbool := enableInfraNAT.(bool) + if ok { + nicobj.EnableInfrastructureNat = &enableInfraNATbool + } + + if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicobj.PrimaryIP = primaryip + } + } + } + + allowIPSpoofing, ok := nic[isBareMetalServerNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok && allowIPSpoofingbool { + nicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isBareMetalServerNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nicobj.SecurityGroups = secgrpobjs + } + } + addNicOptions.BareMetalServerNetworkInterfacePrototype = nicobj + } + _, _, err := sess.CreateBareMetalServerNetworkInterface(addNicOptions) + if err != nil { + return err + } + } + if flag { + err = resourceStartServerIfStopped(id, "hard", d, context, sess) + if err != nil { + return err + } + } + + } + + // if len(add) > 0 { + // } + // if len(remove) > 0 { + // } + // nics := d.Get(isBareMetalServerNetworkInterfaces).(*schema.Set).List() + // for i := range nics { + // securitygrpKey := fmt.Sprintf("network_interfaces.%d.security_groups", i) + // networkNameKey := fmt.Sprintf("network_interfaces.%d.name", i) + // ipSpoofingKey := fmt.Sprintf("network_interfaces.%d.allow_ip_spoofing", i) + // infraNatKey := fmt.Sprintf("network_interfaces.%d.enable_infrastructure_nat", i) + // allowedVlans := fmt.Sprintf("network_interfaces.%d.allowed_vlans", i) + // primaryipname := fmt.Sprintf("network_interfaces.%d.primary_ip.0.name", i) + // primaryipauto := fmt.Sprintf("network_interfaces.%d.primary_ip.0.auto_delete", i) + // primaryiprip := fmt.Sprintf("network_interfaces.%d.primary_ip.0.reserved_ip", i) + // if d.HasChange(primaryipname) || d.HasChange(primaryipauto) { + // subnetId := d.Get(isBareMetalServerNicSubnet).(string) + // ripId := d.Get(primaryiprip).(string) + // updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + // SubnetID: &subnetId, + // ID: &ripId, + // } + // reservedIpPath := &vpcv1.ReservedIPPatch{} + // if d.HasChange(primaryipname) { + // name := d.Get(primaryipname).(string) + // reservedIpPath.Name = &name + // } + // if d.HasChange(primaryipauto) { + // auto := d.Get(primaryipauto).(bool) + // reservedIpPath.AutoDelete = &auto + // } + // reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + // if err != nil { + // return fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err) + // } + // updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + // _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error updating bare metal server network interface reserved ip(%s): %s\n%s", ripId, err, response) + // } + // } + + // if d.HasChange(securitygrpKey) { + // ovs, nvs := d.GetChange(securitygrpKey) + // ov := ovs.(*schema.Set) + // nv := nvs.(*schema.Set) + // remove := flex.ExpandStringList(ov.Difference(nv).List()) + // add := flex.ExpandStringList(nv.Difference(ov).List()) + // if len(add) > 0 { + // networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) + // networkID := d.Get(networkIDKey).(string) + // for i := range add { + // createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + // SecurityGroupID: &add[i], + // ID: &networkID, + // } + // _, response, err := sess.CreateSecurityGroupTargetBinding(createsgnicoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while creating security group %q for network interface of bare metal server %s\n%s: %q", add[i], d.Id(), err, response) + // } + // } + + // } + // if len(remove) > 0 { + // networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) + // networkID := d.Get(networkIDKey).(string) + // for i := range remove { + // deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + // SecurityGroupID: &remove[i], + // ID: &networkID, + // } + // response, err := sess.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while removing security group %q for network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response) + // } + // } + // } + + // } + + } + options := &vpcv1.UpdateBareMetalServerOptions{ + ID: &id, + } + bmsPatchModel := &vpcv1.BareMetalServerPatch{} + flag := false + + if d.HasChange(isBareMetalServerPrimaryNetworkInterface) { + nicId := d.Get("primary_network_interface.0.id").(string) + + if d.HasChange("primary_network_interface.0.primary_ip.0.name") || d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete") { + subnetId := d.Get("primary_network_interface.0.subnet").(string) + ripId := d.Get("primary_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_network_interface.0.primary_ip.0.name") { + name := d.Get("primary_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("primary_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating bare metal server primary network interface reserved ip(%s): %s\n%s", ripId, err, response) + } + } + bmsNicUpdateOptions := &vpcv1.UpdateBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &id, + ID: &nicId, + } + bmsNicPatchModel := &vpcv1.BareMetalServerNetworkInterfacePatch{} + if d.HasChange("primary_network_interface.0.allowed_vlans") { + if allowedVlansOk, ok := d.GetOk("primary_network_interface.0.allowed_vlans"); ok { + allowedVlansList := allowedVlansOk.(*schema.Set).List() + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + bmsNicPatchModel.AllowedVlans = allowedVlans + } + } + if d.HasChange("primary_network_interface.0.allow_ip_spoofing") { + + if allowIpSpoofingOk, ok := d.GetOk("primary_network_interface.0.allow_ip_spoofing"); ok { + allowIpSpoofing := allowIpSpoofingOk.(bool) + if allowIpSpoofing { + bmsNicPatchModel.AllowIPSpoofing = &allowIpSpoofing + } + } + } + if d.HasChange("primary_network_interface.0.enable_infrastructure_nat") { + if enableNatOk, ok := d.GetOk("primary_network_interface.0.enable_infrastructure_nat"); ok { + enableNat := enableNatOk.(bool) + bmsNicPatchModel.EnableInfrastructureNat = &enableNat + } + } + if d.HasChange("primary_network_interface.0.name") { + if nameOk, ok := d.GetOk("primary_network_interface.0.name"); ok { + name := nameOk.(string) + bmsNicPatchModel.Name = &name + } + } + bmsNicPatch, err := bmsNicPatchModel.AsPatch() + if err != nil { + return err + } + bmsNicUpdateOptions.BareMetalServerNetworkInterfacePatch = bmsNicPatch + _, _, err = sess.UpdateBareMetalServerNetworkInterfaceWithContext(context, bmsNicUpdateOptions) + if err != nil { + return err + } + _, err = isWaitForBareMetalServerAvailable(sess, id, d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + if d.HasChange(isBareMetalServerName) { + flag = true + nameStr := "" + if name, ok := d.GetOk(isBareMetalServerName); ok { + nameStr = name.(string) + } + bmsPatchModel.Name = &nameStr + } + if flag { + bmsPatch, err := bmsPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerPatch: %s", err) + } + options.BareMetalServerPatch = bmsPatch + _, response, err := sess.UpdateBareMetalServerWithContext(context, options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating Bare Metal Server: %s\n%s", err, response) + } + } + + if d.HasChange(isBareMetalServerAction) { + action := "" + if actionOk, ok := d.GetOk(isBareMetalServerAction); ok { + action = actionOk.(string) + } + if action == "start" { + isBareMetalServerStart(sess, d.Id(), d, 10) + } else if action == "stop" { + isBareMetalServerStop(sess, d.Id(), d, 10) + } else if action == "restart" { + isBareMetalServerRestart(sess, d.Id(), d, 10) + } + } + return nil +} + +func resourceIBMISBareMetalServerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + deleteType := "hard" + if dt, ok := d.GetOk(isBareMetalServerDeleteType); ok { + deleteType = dt.(string) + } + err := bareMetalServerDelete(context, d, meta, id, deleteType) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func bareMetalServerDelete(context context.Context, d *schema.ResourceData, meta interface{}, id, deleteType string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getBmsOptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, getBmsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + if *bms.Status == "running" { + + options := &vpcv1.StopBareMetalServerOptions{ + ID: bms.ID, + Type: &deleteType, + } + + response, err := sess.StopBareMetalServerWithContext(context, options) + if err != nil && response != nil && response.StatusCode != 204 { + return fmt.Errorf("[ERROR] Error stopping Bare Metal Server (%s): %s\n%s", id, err, response) + } + isWaitForBareMetalServerActionStop(sess, d.Timeout(schema.TimeoutDelete), id, d) + + } + options := &vpcv1.DeleteBareMetalServerOptions{ + ID: &id, + } + response, err = sess.DeleteBareMetalServerWithContext(context, options) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Bare Metal Server : %s\n%s", err, response) + } + _, err = isWaitForBareMetalServerDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForBareMetalServerDeleted(bmsC *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isBareMetalServerActionDeleting}, + Target: []string{"done", "", isBareMetalServerActionDeleted, isBareMetalServerStatusFailed}, + Refresh: isBareMetalServerDeleteRefreshFunc(bmsC, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isBareMetalServerDeleteRefreshFunc(bmsC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bmsgetoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := bmsC.GetBareMetalServer(bmsgetoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return bms, isBareMetalServerActionDeleted, nil + } + return bms, "", fmt.Errorf("[ERROR] Error Getting Bare Metal Server: %s\n%s", err, response) + } + if *bms.Status == isBareMetalServerStatusFailed { + return bms, *bms.Status, fmt.Errorf("[ERROR] The Bare Metal Server (%s) failed to delete: %v", *bms.ID, err) + } + return bms, isBareMetalServerActionDeleting, err + } +} + +func isWaitForBareMetalServerAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) to be available.", id) + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerStatusPending, isBareMetalServerActionStatusStarting}, + Target: []string{isBareMetalServerStatusRunning, isBareMetalServerStatusFailed}, + Refresh: isBareMetalServerRefreshFunc(client, id, d, communicator), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerRefreshFunc(client *vpcv1.VpcV1, id string, d *schema.ResourceData, communicator chan interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bmsgetoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := client.GetBareMetalServer(bmsgetoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting Bare Metal Server: %s\n%s", err, response) + } + d.Set(isBareMetalServerStatus, *bms.Status) + + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + + if *bms.Status == "running" || *bms.Status == "failed" { + // let know the isRestartStartAction() to stop + close(communicator) + if *bms.Status == "failed" { + bmsStatusReason := bms.StatusReasons + + //set the status reasons + if bms.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range bms.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isBareMetalServerStatusReasonsCode] = *sr.Code + currentSR[isBareMetalServerStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isBareMetalServerStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isBareMetalServerStatusReasons, statusReasonsList) + } + + out, err := json.MarshalIndent(bmsStatusReason, "", " ") + if err != nil { + return bms, *bms.Status, fmt.Errorf("[ERROR] The Bare Metal Server (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted bare metal server and attempt to create the bare metal server again replacing the previous configuration", *bms.ID) + } + return bms, *bms.Status, fmt.Errorf("[ERROR] Bare Metal Server (%s) went into failed state during the operation \n (%+v) \n [WARNING] Running terraform apply again will remove the tainted Bare Metal Server and attempt to create the Bare Metal Server again replacing the previous configuration", *bms.ID, string(out)) + } + return bms, *bms.Status, nil + + } + return bms, isBareMetalServerStatusPending, nil + } +} + +func isWaitForBareMetalServerActionStop(bmsC *vpcv1.VpcV1, timeout time.Duration, id string, d *schema.ResourceData) (interface{}, error) { + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerStatusRunning, isBareMetalServerStatusPending, isBareMetalServerActionStatusStopping}, + Target: []string{isBareMetalServerActionStatusStopped, isBareMetalServerStatusFailed, ""}, + Refresh: func() (interface{}, string, error) { + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := bmsC.GetBareMetalServer(getbmsoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Bare Metal Server: %s\n%s", err, response) + } + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + if *bms.Status == isBareMetalServerStatusFailed { + // let know the isRestartStopAction() to stop + close(communicator) + return bms, *bms.Status, fmt.Errorf("[ERROR] The Bare Metal Server %s failed to stop: %v", id, err) + } + return bms, *bms.Status, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isBareMetalServerRestartStopAction(bmsC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int, communicator chan interface{}) { + subticker := time.NewTicker(time.Duration(forceTimeout) * time.Minute) + for { + select { + + case <-subticker.C: + log.Println("Bare Metal Server is still in stopping state, retrying to stop with -force") + actiontype := "hard" + createbmssactoptions := &vpcv1.StopBareMetalServerOptions{ + ID: &id, + Type: &actiontype, + } + response, err := bmsC.StopBareMetalServer(createbmssactoptions) + if err != nil { + communicator <- fmt.Errorf("[ERROR] Error retrying Bare Metal Server action stop: %s\n%s", err, response) + return + } + case <-communicator: + // indicates refresh func is reached target and not proceed with the thread) + subticker.Stop() + return + + } + } +} + +func isBareMetalServerStart(bmsC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int) (interface{}, error) { + createbmsactoptions := &vpcv1.StartBareMetalServerOptions{ + ID: &id, + } + response, err := bmsC.StartBareMetalServer(createbmsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, nil + } + return nil, fmt.Errorf("[ERROR] Error creating Bare Metal Server action start : %s\n%s", err, response) + } + _, err = isWaitForBareMetalServerAvailable(bmsC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return nil, err + } + return nil, nil +} +func isBareMetalServerStop(bmsC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int) (interface{}, error) { + stoppingType := "soft" + createbmsactoptions := &vpcv1.StopBareMetalServerOptions{ + ID: &id, + Type: &stoppingType, + } + response, err := bmsC.StopBareMetalServer(createbmsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, nil + } + return nil, fmt.Errorf("[ERROR] Error creating Bare Metal Server Action stop: %s\n%s", err, response) + } + _, err = isWaitForBareMetalServerActionStop(bmsC, d.Timeout(schema.TimeoutUpdate), d.Id(), d) + if err != nil { + return nil, err + } + return nil, nil +} +func isBareMetalServerRestart(bmsC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int) (interface{}, error) { + createbmsactoptions := &vpcv1.RestartBareMetalServerOptions{ + ID: &id, + } + response, err := bmsC.RestartBareMetalServer(createbmsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, nil + } + return nil, fmt.Errorf("[ERROR] Error creating Bare Metal Server action restart: %s\n%s", err, response) + } + _, err = isWaitForBareMetalServerAvailable(bmsC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return nil, err + } + return nil, nil +} + +func resourceIBMBMSNicSet(v interface{}) int { + var buf bytes.Buffer + a := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", a["subnet"].(string))) + // buf.WriteString(fmt.Sprintf("%s-", a["name"].(string))) + buf.WriteString(fmt.Sprintf("%d-", a["vlan"].(int))) + buf.WriteString(fmt.Sprintf("%v-", a["allowed_vlans"].(*schema.Set))) + return conns.String(buf.String()) +} + +func resourceStopServerIfRunning(id, stoppingType string, d *schema.ResourceData, context context.Context, sess *vpcv1.VpcV1) error { + getBmsOptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, getBmsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + if *bms.Status == "running" { + + options := &vpcv1.StopBareMetalServerOptions{ + ID: bms.ID, + Type: &stoppingType, + } + + response, err := sess.StopBareMetalServerWithContext(context, options) + if err != nil && response != nil && response.StatusCode != 204 { + return fmt.Errorf("[ERROR] Error stopping Bare Metal Server (%s): %s\n%s", id, err, response) + } + isWaitForBareMetalServerActionStop(sess, d.Timeout(schema.TimeoutDelete), id, d) + + } + return nil +} + +func resourceStartServerIfStopped(id, stoppingType string, d *schema.ResourceData, context context.Context, sess *vpcv1.VpcV1) error { + getBmsOptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, getBmsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + if *bms.Status == "stopped" { + + createbmsactoptions := &vpcv1.StartBareMetalServerOptions{ + ID: &id, + } + response, err := sess.StartBareMetalServer(createbmsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error creating Bare Metal Server action start : %s\n%s", err, response) + } + _, err = isWaitForBareMetalServerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_action.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_action.go new file mode 100644 index 000000000..1331dce08 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_action.go @@ -0,0 +1,352 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerActionAvailable = "available" + isBareMetalServerActionPending = "pending" + isBareMetalServerActionFailed = "failed" + isBareMetalServerStopType = "stop_type" +) + +func ResourceIBMIsBareMetalServerAction() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerActionCreate, + ReadContext: resourceIBMISBareMetalServerActionRead, + UpdateContext: resourceIBMISBareMetalServerActionUpdate, + DeleteContext: resourceIBMISBareMetalServerActionDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Bare metal server identifier", + }, + isBareMetalServerStopType: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Default: "hard", + Description: "The type of stop operation", + }, + isBareMetalServerAction: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerAction), + Description: "This restart/start/stops a bare metal server.", + }, + isBareMetalServerStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server status", + }, + + isBareMetalServerStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isBareMetalServerStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + isBareMetalServerStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISBareMetalServerActionValidator() *validate.ResourceValidator { + bareMetalServerStopTypes := "soft, hard" + bareMetalServerActions := "start, restart, stop" + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: bareMetalServerActions}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerStopType, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: bareMetalServerStopTypes}) + ibmISBareMetalServerActionResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server_action", Schema: validateSchema} + return &ibmISBareMetalServerActionResourceValidator +} + +func resourceIBMISBareMetalServerActionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + bareMetalServerId := "" + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + + bareMetalServerAction := "" + if bmsAction, ok := d.GetOk(isBareMetalServerAction); ok { + bareMetalServerAction = bmsAction.(string) + } + if bareMetalServerAction == "stop" { + bareMetalServerStopType := "hard" + if stopType, ok := d.GetOk(isBareMetalServerStopType); ok { + bareMetalServerStopType = stopType.(string) + } + + createBareMetalServerStopOptions := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &bareMetalServerStopType, + } + + _, err = sess.StopBareMetalServerWithContext(context, createBareMetalServerStopOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionStop(sess, d.Timeout(schema.TimeoutCreate), bareMetalServerId, d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } else if bareMetalServerAction == "start" { + + createBareMetalServerStartOptions := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + _, err := sess.StartBareMetalServerWithContext(context, createBareMetalServerStartOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionAvailable(sess, bareMetalServerId, d.Timeout(schema.TimeoutDelete), d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } else if bareMetalServerAction == "restart" { + createBareMetalServerRestartOptions := &vpcv1.RestartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + _, err := sess.RestartBareMetalServerWithContext(context, createBareMetalServerRestartOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionAvailable(sess, bareMetalServerId, d.Timeout(schema.TimeoutDelete), d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } + d.SetId(bareMetalServerId) + err = bareMetalServerActionGet(context, sess, bareMetalServerId, d) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func resourceIBMISBareMetalServerActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + id := d.Id() + err = bareMetalServerActionGet(context, sess, id, d) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func bareMetalServerActionGet(context context.Context, sess *vpcv1.VpcV1, id string, d *schema.ResourceData) error { + options := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s): %s\n%s", id, err, response) + } + d.SetId(*bms.ID) + d.Set(isBareMetalServerStatus, *bms.Status) + statusReasonsList := make([]map[string]interface{}, 0) + if bms.StatusReasons != nil { + for _, sr := range bms.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isBareMetalServerStatusReasonsCode] = *sr.Code + currentSR[isBareMetalServerStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isBareMetalServerStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + } + d.Set(isBareMetalServerStatusReasons, statusReasonsList) + return nil +} + +func resourceIBMISBareMetalServerActionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + if d.HasChange(isBareMetalServerAction) { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + bareMetalServerId := d.Id() + + bareMetalServerAction := "" + if bmsAction, ok := d.GetOk(isBareMetalServerAction); ok { + bareMetalServerAction = bmsAction.(string) + } + + if bareMetalServerAction == "stop" { + bareMetalServerStopType := "soft" + if stopType, ok := d.GetOk(isBareMetalServerStopType); ok { + bareMetalServerStopType = stopType.(string) + } + + createBareMetalServerStopOptions := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &bareMetalServerStopType, + } + + _, err := sess.StopBareMetalServerWithContext(context, createBareMetalServerStopOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionStop(sess, d.Timeout(schema.TimeoutUpdate), bareMetalServerId, d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } else if bareMetalServerAction == "start" { + createBareMetalServerStartOptions := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + _, err := sess.StartBareMetalServerWithContext(context, createBareMetalServerStartOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionAvailable(sess, bareMetalServerId, d.Timeout(schema.TimeoutDelete), d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } else if bareMetalServerAction == "restart" { + createBareMetalServerRestartOptions := &vpcv1.RestartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + _, err := sess.RestartBareMetalServerWithContext(context, createBareMetalServerRestartOptions) + if err != nil { + return diag.FromErr(err) + } + _, waitErr := isWaitForBareMetalServerActionAvailable(sess, bareMetalServerId, d.Timeout(schema.TimeoutDelete), d) + if waitErr != nil { + return diag.FromErr(waitErr) + } + } + err = bareMetalServerActionGet(context, sess, bareMetalServerId, d) + if err != nil { + return diag.FromErr(err) + } + } + return nil +} + +func resourceIBMISBareMetalServerActionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} + +func isWaitForBareMetalServerActionAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) to be running.", id) + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerStatusPending, isBareMetalServerActionStatusStarting}, + Target: []string{isBareMetalServerStatusRunning, isBareMetalServerStatusFailed}, + Refresh: isBareMetalServerActionRefreshFunc(client, id, d, communicator), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerActionRefreshFunc(client *vpcv1.VpcV1, id string, d *schema.ResourceData, communicator chan interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bmsgetoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := client.GetBareMetalServer(bmsgetoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting Bare Metal Server: %s\n%s", err, response) + } + d.Set(isBareMetalServerStatus, *bms.Status) + + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + + if *bms.Status == "running" { + // let know the isRestartStartAction() to stop + close(communicator) + return bms, *bms.Status, nil + + } + if *bms.Status == "failed" { + // let know the isRestartStartAction() to stop + close(communicator) + return bms, *bms.Status, fmt.Errorf("[ERROR] Error Bare Metal Server is in failed state") + + } + return bms, isBareMetalServerStatusPending, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_action_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_action_test.go new file mode 100644 index 000000000..9cafa3368 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_action_test.go @@ -0,0 +1,82 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerAction_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerActionConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_action.testacc_action", "status", "stopped"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerActionConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_bare_metal_server_action" "testacc_action" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + action = "stop" + stop_type = "hard" + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go new file mode 100644 index 000000000..3cf82b34e --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go @@ -0,0 +1,200 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIsBareMetalServerDisk() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerDiskCreate, + ReadContext: resourceIBMISBareMetalServerDiskRead, + UpdateContext: resourceIBMISBareMetalServerDiskUpdate, + DeleteContext: resourceIBMISBareMetalServerDiskDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "Bare metal server identifier", + }, + isBareMetalServerDisk: { + Type: schema.TypeString, + Required: true, + Description: "Bare metal server disk identifier", + }, + + isBareMetalServerDiskName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Bare metal server disk name", + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_disk", isBareMetalServerDiskName), + }, + }, + } +} + +func ResourceIBMIsBareMetalServerDiskValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerDiskName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + ibmISBareMetalServerDiskResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server_disk", Schema: validateSchema} + return &ibmISBareMetalServerDiskResourceValidator +} + +func resourceIBMISBareMetalServerDiskCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + var bareMetalServerId, diskId, diskName string + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + if bmsDiskId, ok := d.GetOk(isBareMetalServerDisk); ok { + diskId = bmsDiskId.(string) + } + if bmsDiskName, ok := d.GetOk(isBareMetalServerDiskName); ok { + diskName = bmsDiskName.(string) + } + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.UpdateBareMetalServerDiskOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &diskId, + } + diskPatchModel := &vpcv1.BareMetalServerDiskPatch{ + Name: &diskName, + } + diskPatch, err := diskPatchModel.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerDiskPatch %s", err)) + } + options.BareMetalServerDiskPatch = diskPatch + disk, response, err := sess.UpdateBareMetalServerDiskWithContext(context, options) + if err != nil || disk == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating bare metal server (%s) disk (%s) err %s\n%s", bareMetalServerId, diskId, err, response)) + } + d.SetId(*disk.ID) + err = bareMetalServerDiskGet(context, d, sess, bareMetalServerId, diskId) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func bareMetalServerDiskGet(context context.Context, d *schema.ResourceData, sess *vpcv1.VpcV1, bareMetalServerId, diskId string) error { + + options := &vpcv1.GetBareMetalServerDiskOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &diskId, + } + disk, response, err := sess.GetBareMetalServerDiskWithContext(context, options) + if err != nil || disk == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error fetching bare metal server (%s) disk (%s) err %s\n%s", bareMetalServerId, diskId, err, response) + } + + d.Set(isBareMetalServerID, bareMetalServerId) + d.Set(isBareMetalServerDisk, *disk.ID) + d.Set(isBareMetalServerDiskName, *disk.Name) + + return nil +} + +func resourceIBMISBareMetalServerDiskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var bareMetalServerId, diskId string + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + if bmsDiskId, ok := d.GetOk(isBareMetalServerDisk); ok { + diskId = bmsDiskId.(string) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + err = bareMetalServerDiskGet(context, d, sess, bareMetalServerId, diskId) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func resourceIBMISBareMetalServerDiskUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + if d.HasChange(isBareMetalServerDiskName) { + var bareMetalServerId, diskId, diskName string + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + if bmsDiskId, ok := d.GetOk(isBareMetalServerDisk); ok { + diskId = bmsDiskId.(string) + } + if bmsDiskName, ok := d.GetOk(isBareMetalServerDiskName); ok { + diskName = bmsDiskName.(string) + } + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.UpdateBareMetalServerDiskOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &diskId, + } + diskPatchModel := &vpcv1.BareMetalServerDiskPatch{ + Name: &diskName, + } + diskPatch, err := diskPatchModel.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerDiskPatch %s", err)) + } + options.BareMetalServerDiskPatch = diskPatch + disk, response, err := sess.UpdateBareMetalServerDiskWithContext(context, options) + if err != nil || disk == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating bare metal server (%s) disk (%s) err %s\n%s", bareMetalServerId, diskId, err, response)) + } + err = bareMetalServerDiskGet(context, d, sess, bareMetalServerId, diskId) + if err != nil { + return diag.FromErr(err) + } + } + return nil +} + +func resourceIBMISBareMetalServerDiskDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk_test.go new file mode 100644 index 000000000..4fb10dc93 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk_test.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISBareMetalServerDisk_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + diskName1 := fmt.Sprintf("tf-bms-disk-%d", acctest.RandIntRange(10, 100)) + diskName2 := fmt.Sprintf("tf-bms-disk-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerDiskConfig(vpcname, subnetname, sshname, publicKey, name, diskName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_disk.testacc_bms_disk", "name", diskName1), + ), + }, + { + Config: testAccCheckIBMISBareMetalServerDiskConfig(vpcname, subnetname, sshname, publicKey, name, diskName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_disk.testacc_bms_disk", "name", diskName2), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerDiskConfig(vpcname, subnetname, sshname, publicKey, name, diskName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_bare_metal_server_disk" "testacc_bms_disk" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + disk = ibm_is_bare_metal_server.testacc_bms.disks.0.id + name = "%s" + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsImage, acc.ISZoneName, diskName) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface.go new file mode 100644 index 000000000..25216d71b --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface.go @@ -0,0 +1,1149 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerNetworkInterfaceAvailable = "available" + isBareMetalServerNetworkInterfaceDeleting = "deleting" + isBareMetalServerNetworkInterfacePending = "pending" + isBareMetalServerNetworkInterfacePCIPending = "pci_pending" + isBareMetalServerNetworkInterfaceVlanPending = "vlan_pending" + isBareMetalServerNetworkInterfaceDeleted = "deleted" + isBareMetalServerNetworkInterfaceFailed = "failed" + isBareMetalServerHardStop = "hard_stop" +) + +func ResourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerNetworkInterfaceCreate, + ReadContext: resourceIBMISBareMetalServerNetworkInterfaceRead, + UpdateContext: resourceIBMISBareMetalServerNetworkInterfaceUpdate, + DeleteContext: resourceIBMISBareMetalServerNetworkInterfaceDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "Bare metal server identifier", + }, + isBareMetalServerNicID: { + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server network interface identifier", + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + isBareMetalServerHardStop: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Only used for PCI network interfaces, whether to hard/immediately stop server", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicFloatingIPs: { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicFloatingIPId: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP identifier", + }, + }, + }, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + isBareMetalServerNicMacAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the interface. If absent, the value is not known.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user-defined name for this network interface", + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "title: IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.address", "primary_ip.0.auto_delete", "primary_ip.0.name"}, + Description: "The unique identifier for this reserved IP", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "The unique user-defined name for this reserved IP", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type: [ subnet_reserved_ip ]", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "If set to true, this reserved IP will be automatically deleted when the target is deleted or when the reserved IP is unbound.", + }, + }, + }, + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type : [ subnet_reserved_ip ]", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Collection of security groups ids", + }, + + isBareMetalServerNicStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface : [ available, deleting, failed, pending ]", + }, + + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Required: true, + Description: "The id of the associated subnet", + }, + + isBareMetalServerNicType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of this bare metal server network interface : [ primary, secondary ]", + }, + + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConflictsWith: []string{isBareMetalServerNicAllowInterfaceToFloat, isBareMetalServerNicVlan}, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + ConflictsWith: []string{isBareMetalServerNicAllowedVlans}, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{isBareMetalServerNicAllowedVlans}, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + }, + } +} + +func ResourceIBMIsBareMetalServerNetworkInterfaceValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isBareMetalServerName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISBareMetalServerNicResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server_network_interface", Schema: validateSchema} + return &ibmISBareMetalServerNicResourceValidator +} + +func resourceIBMISBareMetalServerNetworkInterfaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + bareMetalServerId := "" + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + if allowedVlansOk, ok := d.GetOk(isBareMetalServerNicAllowedVlans); ok { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.CreateBareMetalServerNetworkInterfaceOptions{} + interfaceType := "pci" + // to create pci, server needs to be in stopped state + + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + bms, response, err := sess.GetBareMetalServerWithContext(context, getbmsoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching bare metal server (%s) err %s\n%s", bareMetalServerId, err, response)) + } + // failed, pending, restarting, running, starting, stopped, stopping, maintenance + if *bms.Status == "failed" { + return diag.FromErr(fmt.Errorf("[ERROR] Error cannot attach network interface to a failed bare metal server")) + } else if *bms.Status == "running" { + log.Printf("[DEBUG] Stopping bare metal server (%s) to create a PCI network interface", bareMetalServerId) + stopType := "hard" + if d.Get(isBareMetalServerHardStop).(bool) { + stopType = "soft" + } + createstopaction := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &stopType, + } + res, err := sess.StopBareMetalServerWithContext(context, createstopaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error stopping bare metal server (%s) err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerStoppedForNIC(sess, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + } else if *bms.Status != "stopped" { + return diag.FromErr(fmt.Errorf("[ERROR] Error bare metal server in %s state, please try after some time", *bms.Status)) + } + + nicOptions := &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByPciPrototype{} + allowedVlansList := allowedVlansOk.(*schema.Set).List() + + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + nicOptions.AllowedVlans = allowedVlans + + if name, ok := d.GetOk(isBareMetalServerNicName); ok { + nameStr := name.(string) + nicOptions.Name = &nameStr + } + nicOptions.InterfaceType = &interfaceType + + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { + allowIPSpoofing := ais.(bool) + if allowIPSpoofing { + nicOptions.AllowIPSpoofing = &allowIPSpoofing + } + } + if ein, ok := d.GetOk(isBareMetalServerNicEnableInfraNAT); ok { + enableInfrastructureNat := ein.(bool) + nicOptions.EnableInfrastructureNat = &enableInfrastructureNat + } + if subnetOk, ok := d.GetOk(isBareMetalServerNicSubnet); ok { + subnet := subnetOk.(string) + nicOptions.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnet, + } + } + + if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicOptions.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicOptions.PrimaryIP = primaryip + } + } + + } + + sGroups := d.Get(isBareMetalServerNicSecurityGroups).(*schema.Set).List() + var sGroupList []vpcv1.SecurityGroupIdentityIntf + // Add new allowed_subnets + for _, sGroup := range sGroups { + sGroupStr := sGroup.(string) + sgModel := &vpcv1.SecurityGroupIdentity{ + ID: &sGroupStr, + } + sGroupList = append(sGroupList, sgModel) + } + nicOptions.SecurityGroups = sGroupList + options.BareMetalServerID = &bareMetalServerId + options.BareMetalServerNetworkInterfacePrototype = nicOptions + nic, response, err := sess.CreateBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil || nic == nil { + return diag.FromErr(fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface err %s\n%s", bareMetalServerId, err, response)) + } + switch reflect.TypeOf(nic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + } + + _, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + log.Printf("[INFO] Bare Metal Server Network Interface : %s", d.Id()) + nicAfterWait, err := isWaitForBareMetalServerNetworkInterfaceAvailable(sess, bareMetalServerId, nicId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + + err = bareMetalServerNICGet(d, meta, sess, nicAfterWait, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + + // restarting the server after PCI creation + log.Printf("[DEBUG] Starting bare metal server (%s) to create a PCI network interface", bareMetalServerId) + + createstartaction := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + res, err := sess.StartBareMetalServerWithContext(context, createstartaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error starting bare metal server (%s) err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerAvailableForNIC(sess, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + + } else { + err := createVlanTypeNetworkInterface(context, d, meta, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + } + + return nil +} + +func createVlanTypeNetworkInterface(context context.Context, d *schema.ResourceData, meta interface{}, bareMetalServerId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.CreateBareMetalServerNetworkInterfaceOptions{} + interfaceType := "vlan" + nicOptions := &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + if aitf, ok := d.GetOk(isBareMetalServerNicAllowInterfaceToFloat); ok { + allowInterfaceToFloat := aitf.(bool) + nicOptions.AllowInterfaceToFloat = &allowInterfaceToFloat + } + if vlan, ok := d.GetOk(isBareMetalServerNicVlan); ok { + vlanInt := int64(vlan.(int)) + nicOptions.Vlan = &vlanInt + } + + if name, ok := d.GetOk(isBareMetalServerNicName); ok { + nameStr := name.(string) + nicOptions.Name = &nameStr + } + nicOptions.InterfaceType = &interfaceType + + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { + allowIPSpoofing := ais.(bool) + if allowIPSpoofing { + nicOptions.AllowIPSpoofing = &allowIPSpoofing + } + } + if ein, ok := d.GetOk(isBareMetalServerNicEnableInfraNAT); ok { + enableInfrastructureNat := ein.(bool) + nicOptions.EnableInfrastructureNat = &enableInfrastructureNat + } + if subnetOk, ok := d.GetOk(isBareMetalServerNicSubnet); ok { + subnet := subnetOk.(string) + nicOptions.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnet, + } + } + + if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicOptions.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicOptions.PrimaryIP = primaryip + } + } + + } + + sGroups := d.Get(isBareMetalServerNicSecurityGroups).(*schema.Set).List() + var sGroupList []vpcv1.SecurityGroupIdentityIntf + // Add new allowed_subnets + for _, sGroup := range sGroups { + sGroupStr := sGroup.(string) + sgModel := &vpcv1.SecurityGroupIdentity{ + ID: &sGroupStr, + } + sGroupList = append(sGroupList, sgModel) + } + nicOptions.SecurityGroups = sGroupList + options.BareMetalServerID = &bareMetalServerId + options.BareMetalServerNetworkInterfacePrototype = nicOptions + nic, response, err := sess.CreateBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil || nic == nil { + return fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface err %s\n%s", bareMetalServerId, err, response) + } + + switch reflect.TypeOf(nic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + } + + _, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return err + } + log.Printf("[INFO] Bare Metal Server Network Interface : %s", d.Id()) + nicAfterWait, err := isWaitForBareMetalServerNetworkInterfaceAvailable(sess, bareMetalServerId, nicId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + err = bareMetalServerNICGet(d, meta, sess, nicAfterWait, bareMetalServerId) + if err != nil { + return err + } + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicID, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicID, + } + + nicIntf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil || nicIntf == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface (%s): %s\n%s", bareMetalServerId, nicID, err, response)) + } + err = bareMetalServerNICGet(d, meta, sess, nicIntf, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func bareMetalServerNICGet(d *schema.ResourceData, meta interface{}, sess *vpcv1.VpcV1, nicIntf interface{}, bareMetalServerId string) error { + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicID, *nic.ID) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + d.Set(isBareMetalServerNicStatus, *nic.Status) + + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, *nic.Href) + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + if nic.PortSpeed != nil { + d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) + } + if nic.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: nic.Subnet.ID, + ID: nic.PrimaryIP.ID, + } + bmsRip, response, err := sess.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the bare metal server network interface(%s): %s\n%s", *nic.PrimaryIP.ID, *nic.ID, err, response) + } + currentIP[isBareMetalServerNicIpAutoDelete] = bmsRip.AutoDelete + primaryIpList = append(primaryIpList, currentIP) + + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + } + d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) + + if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + d.Set(isBareMetalServerNicType, *nic.Type) + if nic.AllowedVlans != nil { + var out = make([]interface{}, len(nic.AllowedVlans), len(nic.AllowedVlans)) + for i, v := range nic.AllowedVlans { + out[i] = int(v) + } + d.Set(isBareMetalServerNicAllowedVlans, schema.NewSet(schema.HashInt, out)) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + d.Set(isBareMetalServerNicStatus, *nic.Status) + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, nic.Href) + d.Set(isBareMetalServerNicID, *nic.ID) + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + d.Set(isBareMetalServerNicPortSpeed, nic.PortSpeed) + + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: nic.Subnet.ID, + ID: nic.PrimaryIP.ID, + } + bmsRip, response, err := sess.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the bare metal server network interface(%s): %s\n%s", *nic.PrimaryIP.ID, *nic.ID, err, response) + } + currentIP[isBareMetalServerNicIpAutoDelete] = bmsRip.AutoDelete + + primaryIpList = append(primaryIpList, currentIP) + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + + d.Set(isBareMetalServerNicResourceType, nic.ResourceType) + + if len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + d.Set(isBareMetalServerNicType, *nic.Type) + d.Set(isBareMetalServerNicAllowInterfaceToFloat, *nic.AllowInterfaceToFloat) + d.Set(isBareMetalServerNicVlan, *nic.Vlan) + } + } + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + bareMetalServerId, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + options := &vpcv1.UpdateBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + + if d.HasChange("primary_ip.0.name") || d.HasChange("primary_ip.0.auto_delete") { + subnetId := d.Get(isBareMetalServerNicSubnet).(string) + ripId := d.Get("primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_ip.0.name") { + name := d.Get("primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_ip.0.auto_delete") { + auto := d.Get("primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating network interface reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + + nicPatchModel := &vpcv1.BareMetalServerNetworkInterfacePatch{} + flag := false + if d.HasChange(isBareMetalServerNicAllowIPSpoofing) { + flag = true + aisBool := false + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { + aisBool = ais.(bool) + } + nicPatchModel.AllowIPSpoofing = &aisBool + } + if d.HasChange(isBareMetalServerNicAllowedVlans) { + flag = true + + if allowedVlansOk, ok := d.GetOk(isBareMetalServerNicAllowedVlans); ok { + allowedVlansList := allowedVlansOk.(*schema.Set).List() + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + nicPatchModel.AllowedVlans = allowedVlans + } + } + if d.HasChange(isBareMetalServerNicEnableInfraNAT) { + flag = true + einBool := false + if ein, ok := d.GetOk(isBareMetalServerNicEnableInfraNAT); ok { + einBool = ein.(bool) + } + nicPatchModel.EnableInfrastructureNat = &einBool + } + if d.HasChange(isBareMetalServerNicName) { + flag = true + nameStr := "" + if name, ok := d.GetOk(isBareMetalServerNicName); ok { + nameStr = name.(string) + } + nicPatchModel.Name = &nameStr + } + + if flag { + nicPatchModelAsPatch, err := nicPatchModel.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerNetworkInterfacePatch %s", err)) + } + options.BareMetalServerNetworkInterfacePatch = nicPatchModelAsPatch + + nicIntf, response, err := sess.UpdateBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating Bare Metal Server: %s\n%s", err, response)) + } + return diag.FromErr(bareMetalServerNICGet(d, meta, sess, nicIntf, bareMetalServerId)) + } + + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + err = bareMetalServerNetworkInterfaceDelete(context, d, meta, bareMetalServerId, nicId) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func bareMetalServerNetworkInterfaceDelete(context context.Context, d *schema.ResourceData, meta interface{}, bareMetalServerId, nicId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getBmsNicOptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + nicIntf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, getBmsNicOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface(%s) : %s\n%s", bareMetalServerId, nicId, err, response) + } + nicType := "" + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nicType = "pci" + log.Printf("[DEBUG] PCI type network interface needs the server in stopped state") + log.Printf("[DEBUG] Stopping the bare metal server %s", bareMetalServerId) + // to delete pci, server needs to be in stopped state + + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + bms, response, err := sess.GetBareMetalServerWithContext(context, getbmsoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching bare metal server (%s) err %s\n%s", bareMetalServerId, err, response) + } + // failed, pending, restarting, running, starting, stopped, stopping, maintenance + if *bms.Status == "failed" { + return fmt.Errorf("[ERROR] Error cannot detach network interface from a failed bare metal server") + } else if *bms.Status == "running" { + log.Printf("[DEBUG] Stopping bare metal server (%s) to create a PCI network interface", bareMetalServerId) + stopType := "soft" + if d.Get(isBareMetalServerHardStop).(bool) { + stopType = "hard" + } + createstopaction := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &stopType, + } + res, err := sess.StopBareMetalServerWithContext(context, createstopaction) + if err != nil || res.StatusCode != 204 { + return fmt.Errorf("[ERROR] Error stopping bare metal server (%s) err %s\n%s", bareMetalServerId, err, response) + } + _, err = isWaitForBareMetalServerStoppedForNIC(sess, bareMetalServerId, d.Timeout(schema.TimeoutDelete), d) + if err != nil || res.StatusCode != 204 { + return err + } + } else if *bms.Status != "stopped" { + return fmt.Errorf("[ERROR] Error bare metal server in %s state, please try after some time", *bms.Status) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nicType = "vlan" + } + } + + options := &vpcv1.DeleteBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + response, err = sess.DeleteBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Bare Metal Server (%s) network interface (%s) : %s\n%s", bareMetalServerId, nicId, err, response) + } + _, err = isWaitForBareMetalServerNetworkInterfaceDeleted(sess, bareMetalServerId, nicId, nicType, nicIntf, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + if nicType == "pci" { + // restarting the server after PCI deletion + log.Printf("[DEBUG] Starting bare metal server (%s) after deleting the PCI network interface", bareMetalServerId) + createstartaction := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + res, err := sess.StartBareMetalServerWithContext(context, createstartaction) + if err != nil || res.StatusCode != 204 { + return fmt.Errorf("[ERROR] Error starting bare metal server (%s) err %s\n%s", bareMetalServerId, err, response) + } + _, err = isWaitForBareMetalServerAvailableForNIC(sess, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + d.SetId("") + return nil +} + +func isWaitForBareMetalServerNetworkInterfaceDeleted(bmsC *vpcv1.VpcV1, bareMetalServerId, nicId, nicType string, nicIntf vpcv1.BareMetalServerNetworkInterfaceIntf, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) / (%s) to be deleted.", bareMetalServerId, nicId) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerNetworkInterfaceAvailable, isBareMetalServerNetworkInterfaceDeleting, isBareMetalServerNetworkInterfacePending}, + Target: []string{isBareMetalServerNetworkInterfaceDeleted, isBareMetalServerNetworkInterfaceVlanPending, isBareMetalServerNetworkInterfaceFailed, ""}, + Refresh: isBareMetalServerNetworkInterfaceDeleteRefreshFunc(bmsC, bareMetalServerId, nicId, nicType, nicIntf), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isBareMetalServerNetworkInterfaceDeleteRefreshFunc(bmsC *vpcv1.VpcV1, bareMetalServerId, nicId, nicType string, nicIntf vpcv1.BareMetalServerNetworkInterfaceIntf) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getBmsNicOptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + bmsNic, response, err := bmsC.GetBareMetalServerNetworkInterface(getBmsNicOptions) + if bmsNic != nil && nicType == "vlan" { + getBmsOptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + bms, response, err := bmsC.GetBareMetalServer(getBmsOptions) + if err != nil { + return bmsNic, isBareMetalServerNetworkInterfaceFailed, fmt.Errorf("[ERROR] Error getting Bare Metal Server(%s) : %s\n%s", bareMetalServerId, err, response) + } + if *bms.Status == "stopped" { + return bmsNic, isBareMetalServerNetworkInterfaceVlanPending, fmt.Errorf("[ERROR] Error deleting Bare Metal Server(%s) Network Interface (%s), server in stopped state ", bareMetalServerId, nicId) + } + } + if err != nil { + if response != nil && response.StatusCode == 404 { + return nicIntf, isBareMetalServerNetworkInterfaceDeleted, nil + } + return bmsNic, isBareMetalServerNetworkInterfaceFailed, fmt.Errorf("[ERROR] Error getting Bare Metal Server(%s) Network Interface (%s): %s\n%s", bareMetalServerId, nicId, err, response) + } + return bmsNic, isBareMetalServerNetworkInterfaceDeleting, err + } +} + +func isWaitForBareMetalServerNetworkInterfaceAvailable(client *vpcv1.VpcV1, bareMetalServerId, nicId string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) Network Interface (%s) to be available.", bareMetalServerId, nicId) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerNetworkInterfacePending}, + Target: []string{isBareMetalServerNetworkInterfaceAvailable, isBareMetalServerNetworkInterfacePCIPending, isBareMetalServerNetworkInterfaceFailed}, + Refresh: isBareMetalServerNetworkInterfaceRefreshFunc(client, bareMetalServerId, nicId, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerNetworkInterfaceRefreshFunc(client *vpcv1.VpcV1, bareMetalServerId, nicId string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getBmsNicOptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + bmsNic, response, err := client.GetBareMetalServerNetworkInterface(getBmsNicOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) Network Interface (%s) : %s\n%s", bareMetalServerId, nicId, err, response) + } + status := "" + pcipending := false + switch reflect.TypeOf(bmsNic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := bmsNic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + status = *nic.Status + d.Set(isBareMetalServerNicStatus, *nic.Status) + getBmsOptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + bms, response, err := client.GetBareMetalServer(getBmsOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) : %s\n%s", bareMetalServerId, err, response) + } + if *bms.Status == "stopped" { + pcipending = true + } + + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := bmsNic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + status = *nic.Status + d.Set(isBareMetalServerNicStatus, *nic.Status) + if *nic.PrimaryIP.Address == "0.0.0.0" { + return bmsNic, "pending", nil + } + } + } + + if status == "available" || status == "failed" { + return bmsNic, status, nil + } + if pcipending { + return bmsNic, isBareMetalServerNetworkInterfacePCIPending, nil + } + return bmsNic, "pending", nil + } +} + +func MakeTerraformNICID(id1, id2 string) string { + // Include both bare metal sever id and network interface id to create a unique Terraform id. As a bonus, + // we can extract the bare metal sever id as needed for API calls such as READ. + return fmt.Sprintf("%s/%s", id1, id2) +} + +func ParseNICTerraformID(s string) (string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], nil +} + +func isWaitForBareMetalServerAvailableForNIC(client *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) to be available.", id) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerStatusPending, isBareMetalServerActionStatusStarting, "running"}, + Target: []string{isBareMetalServerStatusRunning, isBareMetalServerStatusFailed}, + Refresh: isBareMetalServerForNICRefreshFunc(client, id, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerForNICRefreshFunc(client *vpcv1.VpcV1, id string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bmsgetoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := client.GetBareMetalServer(bmsgetoptions) + if err != nil { + return nil, "failed", fmt.Errorf("[ERROR] Error getting Bare Metal Server: %s\n%s", err, response) + } + + if *bms.Status == "running" || *bms.Status == "failed" { + return bms, *bms.Status, nil + } + return bms, "pending", nil + } +} + +func isWaitForBareMetalServerStoppedForNIC(client *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) to be stopped.", id) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerStatusPending, isBareMetalServerActionStatusStarting}, + Target: []string{isBareMetalServerActionStatusStopped}, + Refresh: isBareMetalServerForNICStoppedRefreshFunc(client, id, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerForNICStoppedRefreshFunc(client *vpcv1.VpcV1, id string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bmsgetoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := client.GetBareMetalServer(bmsgetoptions) + if err != nil { + return nil, "failed", fmt.Errorf("[ERROR] Error getting Bare Metal Server: %s\n%s", err, response) + } + if *bms.Status == "stopped" || *bms.Status == "failed" { + // let know the isRestartStartAction() to stop + if *bms.Status == "failed" { + return bms, *bms.Status, fmt.Errorf("[ERROR] Error bare metal server in failed state") + } + return bms, "stopped", nil + + } + return bms, isBareMetalServerStatusPending, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float.go new file mode 100644 index 000000000..60c096c05 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float.go @@ -0,0 +1,745 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isFloatedBareMetalServerID = "floating_bare_metal_server" +) + +func ResourceIBMIsBareMetalServerNetworkInterfaceAllowFloat() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerNetworkInterfaceAllowFloatCreate, + ReadContext: resourceIBMISBareMetalServerNetworkInterfaceAllowFloatRead, + UpdateContext: resourceIBMISBareMetalServerNetworkInterfaceAllowFloatUpdate, + DeleteContext: resourceIBMISBareMetalServerNetworkInterfaceAllowFloatDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Bare metal server identifier", + }, + + isFloatedBareMetalServerID: { + Type: schema.TypeString, + Computed: true, + Description: "Bare metal server identifier of the server to which nic is floating to", + }, + isBareMetalServerNicID: { + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server network interface identifier", + }, + isBareMetalServerNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + isBareMetalServerNicEnableInfraNAT: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + }, + isBareMetalServerNicFloatingIPs: { + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address", + }, + isBareMetalServerNicFloatingIPId: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP identifier", + }, + }, + }, + }, + isBareMetalServerNicHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface", + }, + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Computed: true, + Description: "The network interface type: [ pci, vlan ]", + }, + isBareMetalServerNicMacAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the interface. If absent, the value is not known.", + }, + isBareMetalServerNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user-defined name for this network interface", + }, + isBareMetalServerNicPortSpeed: { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps", + }, + isBareMetalServerNicPrimaryIP: { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "title: IPv4, The IP address. ", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isBareMetalServerNicIpAddress: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "The globally unique IP address", + }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isBareMetalServerNicIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isBareMetalServerNicIpID: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.address", "primary_ip.0.auto_delete", "primary_ip.0.name"}, + Description: "Identifies a reserved IP by a unique property.", + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isBareMetalServerNicResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type : [ subnet_reserved_ip ]", + }, + + isBareMetalServerNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Collection of security groups ids", + }, + + isBareMetalServerNicStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface : [ available, deleting, failed, pending ]", + }, + + isBareMetalServerNicSubnet: { + Type: schema.TypeString, + Required: true, + Description: "The id of the associated subnet", + }, + + isBareMetalServerNicType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of this bare metal server network interface : [ primary, secondary ]", + }, + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Required: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + }, + } +} + +func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + bareMetalServerId := "" + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + + err := createVlanTypeNetworkInterfaceAllowFloat(context, d, meta, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func createVlanTypeNetworkInterfaceAllowFloat(context context.Context, d *schema.ResourceData, meta interface{}, bareMetalServerId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.CreateBareMetalServerNetworkInterfaceOptions{} + interfaceType := "vlan" + nicOptions := &vpcv1.BareMetalServerNetworkInterfacePrototypeBareMetalServerNetworkInterfaceByVlanPrototype{} + allowInterfaceToFloat := true + nicOptions.AllowInterfaceToFloat = &allowInterfaceToFloat + if vlan, ok := d.GetOk(isBareMetalServerNicVlan); ok { + vlanInt := int64(vlan.(int)) + nicOptions.Vlan = &vlanInt + } + + if name, ok := d.GetOk(isBareMetalServerNicName); ok { + nameStr := name.(string) + nicOptions.Name = &nameStr + } + nicOptions.InterfaceType = &interfaceType + + if aisOk, ok := d.GetOkExists(isBareMetalServerNicAllowIPSpoofing); ok { + allowIPSpoofing := aisOk.(bool) + nicOptions.AllowIPSpoofing = &allowIPSpoofing + } + + if ein, ok := d.GetOkExists(isBareMetalServerNicEnableInfraNAT); ok { + enableInfrastructureNat := ein.(bool) + nicOptions.EnableInfrastructureNat = &enableInfrastructureNat + } + + if subnetOk, ok := d.GetOk(isBareMetalServerNicSubnet); ok { + subnet := subnetOk.(string) + nicOptions.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnet, + } + } + + if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { + primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) + + reservedIpIdOk, ok := primaryIp[isBareMetalServerNicIpID] + if ok && reservedIpIdOk.(string) != "" { + ipid := reservedIpIdOk.(string) + nicOptions.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &ipid, + } + } else { + + primaryip := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + + reservedIpAddressOk, okAdd := primaryIp[isBareMetalServerNicIpAddress] + if okAdd && reservedIpAddressOk.(string) != "" { + reservedIpAddress := reservedIpAddressOk.(string) + primaryip.Address = &reservedIpAddress + } + reservedIpNameOk, okName := primaryIp[isBareMetalServerNicIpName] + if okName && reservedIpNameOk.(string) != "" { + reservedIpName := reservedIpNameOk.(string) + primaryip.Name = &reservedIpName + } + reservedIpAutoOk, okAuto := primaryIp[isBareMetalServerNicIpAutoDelete] + if okAuto { + reservedIpAuto := reservedIpAutoOk.(bool) + primaryip.AutoDelete = &reservedIpAuto + } + if okAdd || okName || okAuto { + nicOptions.PrimaryIP = primaryip + } + } + } + + sGroups := d.Get(isBareMetalServerNicSecurityGroups).(*schema.Set).List() + var sGroupList []vpcv1.SecurityGroupIdentityIntf + // Add new allowed_subnets + for _, sGroup := range sGroups { + sGroupStr := sGroup.(string) + sgModel := &vpcv1.SecurityGroupIdentity{ + ID: &sGroupStr, + } + sGroupList = append(sGroupList, sgModel) + } + nicOptions.SecurityGroups = sGroupList + options.BareMetalServerID = &bareMetalServerId + options.BareMetalServerNetworkInterfacePrototype = nicOptions + nic, response, err := sess.CreateBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil || nic == nil { + return fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface err %s\n%s", bareMetalServerId, err, response) + } + d.Set(isFloatedBareMetalServerID, bareMetalServerId) + switch reflect.TypeOf(nic).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nicIntf := nic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nicIntf.ID)) + } + } + _, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return err + } + + log.Printf("[INFO] Bare Metal Server Network Interface : %s", d.Id()) + nicAfterWait, err := isWaitForBareMetalServerNetworkInterfaceAvailable(sess, bareMetalServerId, nicId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + + err = bareMetalServerNICAllowFloatGet(d, meta, sess, nicAfterWait, bareMetalServerId) + if err != nil { + return err + } + + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicID, err := ParseNICTerraformID(d.Id()) + d.Set(isFloatedBareMetalServerID, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicID, + } + var nicIntf vpcv1.BareMetalServerNetworkInterfaceIntf + // try to fetch original nic + nicIntf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, options) + if (err != nil || nicIntf == nil) && response != nil { + //if original nic is not present, try fetching nic without server id + nicIntf, response, err = findNicsWithoutBMS(context, d, sess, nicID) + // response here can be either nil or not nil and if it returns 404 means nic is deleted + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + // if response returns an error + if err != nil || nicIntf == nil { + if response != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface (%s): %s\n%s", bareMetalServerId, nicID, err, response)) + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface (%s): %s", bareMetalServerId, nicID, err)) + } + } + } + err = bareMetalServerNICAllowFloatGet(d, meta, sess, nicIntf, bareMetalServerId) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func findNicsWithoutBMS(context context.Context, d *schema.ResourceData, sess *vpcv1.VpcV1, nicId string) (result vpcv1.BareMetalServerNetworkInterfaceIntf, response *core.DetailedResponse, err error) { + // listing all servers + start := "" + allrecs := []vpcv1.BareMetalServer{} + for { + listBareMetalServersOptions := &vpcv1.ListBareMetalServersOptions{} + if start != "" { + listBareMetalServersOptions.Start = &start + } + availableServers, response, err := sess.ListBareMetalServersWithContext(context, listBareMetalServersOptions) + if err != nil { + return nil, nil, fmt.Errorf("[ERROR] Error fetching Bare Metal Servers %s\n%s", err, response) + } + start = flex.GetNext(availableServers.Next) + allrecs = append(allrecs, availableServers.BareMetalServers...) + if start == "" { + break + } + } + // finding nic id each server + for _, server := range allrecs { + nics := server.NetworkInterfaces + for _, nic := range nics { + if *nic.ID == nicId { + options := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: server.ID, + ID: &nicId, + } + //return response of the server nic matches + d.Set(isFloatedBareMetalServerID, *server.ID) + return sess.GetBareMetalServerNetworkInterfaceWithContext(context, options) + } + } + } + // if not found return nil response and error + return nil, nil, fmt.Errorf("[ERROR] Error Network interface not found") +} + +func bareMetalServerNICAllowFloatGet(d *schema.ResourceData, meta interface{}, sess *vpcv1.VpcV1, nicIntf interface{}, bareMetalServerId string) error { + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByPci) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + d.Set(isBareMetalServerNicStatus, *nic.Status) + + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, *nic.Href) + d.Set(isBareMetalServerNicID, *nic.ID) + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + if nic.PortSpeed != nil { + d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) + } + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: nic.Subnet.ID, + ID: nic.PrimaryIP.ID, + } + bmsRip, response, err := sess.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the bare metal server network interface(%s): %s\n%s", *nic.PrimaryIP.ID, *nic.ID, err, response) + } + currentIP[isBareMetalServerNicIpAutoDelete] = bmsRip.AutoDelete + + primaryIpList = append(primaryIpList, currentIP) + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + + d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) + + if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + d.Set(isBareMetalServerNicType, *nic.Type) + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + d.SetId(MakeTerraformNICID(bareMetalServerId, *nic.ID)) + d.Set(isBareMetalServerNicAllowIPSpoofing, *nic.AllowIPSpoofing) + d.Set(isBareMetalServerNicEnableInfraNAT, *nic.EnableInfrastructureNat) + d.Set(isBareMetalServerNicStatus, *nic.Status) + floatingIPList := make([]map[string]interface{}, 0) + if nic.FloatingIps != nil { + for _, ip := range nic.FloatingIps { + currentIP := map[string]interface{}{ + isBareMetalServerNicFloatingIPId: *ip.ID, + isBareMetalServerNicIpAddress: *ip.Address, + } + floatingIPList = append(floatingIPList, currentIP) + } + } + d.Set(isBareMetalServerNicFloatingIPs, floatingIPList) + + d.Set(isBareMetalServerNicHref, nic.Href) + d.Set(isBareMetalServerNicID, *nic.ID) + d.Set(isBareMetalServerNicInterfaceType, *nic.InterfaceType) + + d.Set(isBareMetalServerNicMacAddress, *nic.MacAddress) + d.Set(isBareMetalServerNicName, *nic.Name) + d.Set(isBareMetalServerNicPortSpeed, nic.PortSpeed) + + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpAddress] = *nic.PrimaryIP.Address + } + if nic.PrimaryIP.Href != nil { + currentIP[isBareMetalServerNicIpHref] = *nic.PrimaryIP.Href + } + if nic.PrimaryIP.Name != nil { + currentIP[isBareMetalServerNicIpName] = *nic.PrimaryIP.Name + } + if nic.PrimaryIP.ID != nil { + currentIP[isBareMetalServerNicIpID] = *nic.PrimaryIP.ID + } + if nic.PrimaryIP.ResourceType != nil { + currentIP[isBareMetalServerNicResourceType] = *nic.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) + + d.Set(isBareMetalServerNicResourceType, nic.ResourceType) + + if len(nic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(nic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(nic.SecurityGroups[i].ID))) + } + d.Set(isBareMetalServerNicSecurityGroups, flex.NewStringSet(schema.HashString, secgrpList)) + } + + d.Set(isBareMetalServerNicStatus, *nic.Status) + d.Set(isBareMetalServerNicSubnet, *nic.Subnet.ID) + d.Set(isBareMetalServerNicType, *nic.Type) + d.Set(isBareMetalServerNicAllowInterfaceToFloat, *nic.AllowInterfaceToFloat) + d.Set(isBareMetalServerNicVlan, *nic.Vlan) + } + } + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + bareMetalServerId, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + if d.HasChange("primary_ip.0.name") || d.HasChange("primary_ip.0.auto_delete") { + subnetId := d.Get(isBareMetalServerNicSubnet).(string) + ripId := d.Get("primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_ip.0.name") { + name := d.Get("primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_ip.0.auto_delete") { + auto := d.Get("primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating network interface reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + + options := &vpcv1.UpdateBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + nicPatchModel := &vpcv1.BareMetalServerNetworkInterfacePatch{} + flag := false + if d.HasChange(isBareMetalServerNicAllowIPSpoofing) { + flag = true + aisBool := false + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { + aisBool = ais.(bool) + } + nicPatchModel.AllowIPSpoofing = &aisBool + } + if d.HasChange(isBareMetalServerNicEnableInfraNAT) { + flag = true + einBool := false + if ein, ok := d.GetOk(isBareMetalServerNicEnableInfraNAT); ok { + einBool = ein.(bool) + } + nicPatchModel.EnableInfrastructureNat = &einBool + } + if d.HasChange(isBareMetalServerNicName) { + flag = true + nameStr := "" + if name, ok := d.GetOk(isBareMetalServerNicName); ok { + nameStr = name.(string) + } + nicPatchModel.Name = &nameStr + } + + if flag { + nicPatchModelAsPatch, err := nicPatchModel.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerNetworkInterfacePatch %s", err)) + } + options.BareMetalServerNetworkInterfacePatch = nicPatchModelAsPatch + + nicIntf, response, err := sess.UpdateBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating Bare Metal Server: %s\n%s", err, response)) + } + return diag.FromErr(bareMetalServerNICAllowFloatGet(d, meta, sess, nicIntf, bareMetalServerId)) + } + + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicId, err := ParseNICTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + err = bareMetalServerNetworkInterfaceAllowFloatDelete(context, d, meta, bareMetalServerId, nicId) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func bareMetalServerNetworkInterfaceAllowFloatDelete(context context.Context, d *schema.ResourceData, meta interface{}, bareMetalServerId, nicId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getBmsNicOptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + nicIntf, response, err := sess.GetBareMetalServerNetworkInterfaceWithContext(context, getBmsNicOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface(%s) : %s\n%s", bareMetalServerId, nicId, err, response) + } + nicType := "" + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nicType = "pci" + log.Printf("[DEBUG] PCI type network interface needs the server in stopped state") + log.Printf("[DEBUG] Stopping the bare metal server %s", bareMetalServerId) + // to delete pci, server needs to be in stopped state + + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + bms, response, err := sess.GetBareMetalServerWithContext(context, getbmsoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching bare metal server (%s) err %s\n%s", bareMetalServerId, err, response) + } + // failed, pending, restarting, running, starting, stopped, stopping, maintenance + if *bms.Status == "failed" { + return fmt.Errorf("[ERROR] Error cannot detach network interface from a failed bare metal server") + } else if *bms.Status == "running" { + log.Printf("[DEBUG] Stopping bare metal server (%s) to create a PCI network interface", bareMetalServerId) + stopType := "soft" + if d.Get(isBareMetalServerHardStop).(bool) { + stopType = "hard" + } + createstopaction := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &stopType, + } + res, err := sess.StopBareMetalServerWithContext(context, createstopaction) + if err != nil || res.StatusCode != 204 { + return fmt.Errorf("[ERROR] Error stopping bare metal server (%s) err %s\n%s", bareMetalServerId, err, response) + } + _, err = isWaitForBareMetalServerStoppedForNIC(sess, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil || res.StatusCode != 204 { + return err + } + } else if *bms.Status != "stopped" { + return fmt.Errorf("[ERROR] Error bare metal server in %s state, please try after some time", *bms.Status) + } + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nicType = "vlan" + } + } + + options := &vpcv1.DeleteBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &nicId, + } + response, err = sess.DeleteBareMetalServerNetworkInterfaceWithContext(context, options) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Bare Metal Server (%s) network interface (%s) : %s\n%s", bareMetalServerId, nicId, err, response) + } + _, err = isWaitForBareMetalServerNetworkInterfaceDeleted(sess, bareMetalServerId, nicId, nicType, nicIntf, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float_test.go new file mode 100644 index 000000000..a595005f3 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_allow_float_test.go @@ -0,0 +1,257 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "reflect" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISBareMetalServerNetworkInterfaceAllowFloat_rip_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + subnetreservedipname := fmt.Sprintf("tfip-subnet-rip-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatRipConfig(vpcname, subnetname, subnetreservedipname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatExists("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_subnet_reserved_ip.testacc_rip", "name", subnetreservedipname), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "interface_type", "vlan"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "allow_ip_spoofing", "false"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "name", "eth21"), + resource.TestCheckResourceAttrWith("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "primary_ip.0.address", func(v string) error { + if v == "0.0.0.0" { + return fmt.Errorf("Attribute 'address' %s is not updated", v) + } + return nil + }), + resource.TestCheckResourceAttrSet( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "floating_bare_metal_server"), + resource.TestCheckResourceAttrWith("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "floating_bare_metal_server", func(v string) error { + if v == "" { + return fmt.Errorf("Attribute 'floating_bare_metal_server' %s is not populated", v) + } + return nil + }), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServerNetworkInterfaceAllowFloat_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatExists("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "allow_ip_spoofing", "false"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "allow_interface_to_float", "true"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "enable_infrastructure_nat", "false"), + resource.TestCheckResourceAttrWith("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "primary_ip.0.address", func(v string) error { + if v == "0.0.0.0" { + return fmt.Errorf("Attribute 'address' %s is not updated", v) + } + return nil + }), + resource.TestCheckResourceAttrSet( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "floating_bare_metal_server"), + resource.TestCheckResourceAttrWith("ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "floating_bare_metal_server", func(v string) error { + if v == "" { + return fmt.Errorf("Attribute 'floating_bare_metal_server' %s is not populated", v) + } + return nil + }), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatExists(n, ip string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + bmsId, nicId, err := vpc.ParseNICTerraformID(rs.Primary.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error parsing ID : %s", rs.Primary.ID) + } + getbmsnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bmsId, + ID: &nicId, + } + nicIntf, _, err := sess.GetBareMetalServerNetworkInterface(getbmsnicoptions) + + if err != nil { + return err + } + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + ip = vpc.MakeTerraformNICID(bmsId, *nic.ID) + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + ip = vpc.MakeTerraformNICID(bmsId, *nic.ID) + } + } + return nil + } +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + allowed_vlans = [101, 102] + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource ibm_is_bare_metal_server_network_interface_allow_float bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth21" + vlan = 101 + allow_ip_spoofing = false + enable_infrastructure_nat = false + } + + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} +func testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatRipConfig(vpcname, subnetname, subnetreservedipname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + allowed_vlans = [101, 102] + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource ibm_is_bare_metal_server_network_interface_allow_float bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth21" + vlan = 101 + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + + +`, vpcname, subnetname, acc.ISZoneName, subnetreservedipname, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip.go new file mode 100644 index 000000000..68838fd8d --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip.go @@ -0,0 +1,373 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isBareMetalServerNetworkInterfaceFloatingIpAvailable = "available" + isBareMetalServerNetworkInterfaceFloatingIpDeleting = "deleting" + isBareMetalServerNetworkInterfaceFloatingIpPending = "pending" + isBareMetalServerNetworkInterfacePCIFloatingIpPending = "pci_pending" + isBareMetalServerNetworkInterfaceFloatingIpDeleted = "deleted" + isBareMetalServerNetworkInterfaceFloatingIpFailed = "failed" + isBareMetalServerFloatingIpHardStop = "hard_stop" +) + +func ResourceIBMIsBareMetalServerNetworkInterfaceFloatingIp() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISBareMetalServerNetworkInterfaceFloatingIpCreate, + ReadContext: resourceIBMISBareMetalServerNetworkInterfaceFloatingIpRead, + UpdateContext: resourceIBMISBareMetalServerNetworkInterfaceFloatingIpUpdate, + DeleteContext: resourceIBMISBareMetalServerNetworkInterfaceFloatingIpDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isBareMetalServerID: { + Type: schema.TypeString, + Required: true, + Description: "Bare metal server identifier", + }, + isBareMetalServerNetworkInterface: { + Type: schema.TypeString, + Required: true, + Description: "Bare metal server network interface identifier", + }, + isBareMetalServerNetworkInterfaceFloatingIPID: { + Type: schema.TypeString, + Required: true, + Description: "The floating ip identifier of the network interface associated with the bare metal server", + }, + floatingIPName: { + Type: schema.TypeString, + Computed: true, + Description: "Name of the floating IP", + }, + + floatingIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP address", + }, + + floatingIPStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP status", + }, + + floatingIPZone: { + Type: schema.TypeString, + Computed: true, + Description: "Zone name", + }, + + floatingIPTarget: { + Type: schema.TypeString, + Computed: true, + Description: "Target info", + }, + + floatingIPCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP crn", + }, + }, + } +} + +func resourceIBMISBareMetalServerNetworkInterfaceFloatingIpCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + bareMetalServerId := "" + if bmsId, ok := d.GetOk(isBareMetalServerID); ok { + bareMetalServerId = bmsId.(string) + } + bareMetalServerNicId := "" + if nicId, ok := d.GetOk(isBareMetalServerNetworkInterface); ok { + if strings.Contains(nicId.(string), "/") { + _, bareMetalServerNicId, err = ParseNICTerraformID(nicId.(string)) + if err != nil { + return diag.FromErr(err) + } + } else { + bareMetalServerNicId = nicId.(string) + } + + } + bareMetalServerNicFipId := "" + if fipId, ok := d.GetOk(isBareMetalServerNetworkInterfaceFloatingIPID); ok { + bareMetalServerNicFipId = fipId.(string) + } + + options := &vpcv1.AddBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &bareMetalServerNicId, + ID: &bareMetalServerNicFipId, + } + + fip, response, err := sess.AddBareMetalServerNetworkInterfaceFloatingIPWithContext(context, options) + if err != nil || fip == nil { + return diag.FromErr(fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface (%s) floating ip (%s) err %s\n%s", bareMetalServerId, bareMetalServerNicId, bareMetalServerNicFipId, err, response)) + } + d.SetId(MakeTerraformNICFipID(bareMetalServerId, bareMetalServerNicId, *fip.ID)) + err = bareMetalServerNICFipGet(d, fip, bareMetalServerId, bareMetalServerNicId) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceFloatingIpRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicID, fipId, err := ParseNICFipTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + options := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicID, + ID: &fipId, + } + + fip, response, err := sess.GetBareMetalServerNetworkInterfaceFloatingIPWithContext(context, options) + if err != nil || fip == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface (%s): %s\n%s", bareMetalServerId, nicID, err, response)) + } + err = bareMetalServerNICFipGet(d, fip, bareMetalServerId, nicID) + if err != nil { + return diag.FromErr(err) + } + return nil +} + +func bareMetalServerNICFipGet(d *schema.ResourceData, fip *vpcv1.FloatingIP, bareMetalServerId, nicId string) error { + + d.SetId(MakeTerraformNICFipID(bareMetalServerId, nicId, *fip.ID)) + d.Set(floatingIPName, *fip.Name) + d.Set(floatingIPAddress, *fip.Address) + d.Set(floatingIPStatus, fip.Status) + d.Set(floatingIPZone, *fip.Zone.Name) + + d.Set(floatingIPCRN, *fip.CRN) + + target, ok := fip.Target.(*vpcv1.FloatingIPTarget) + if ok { + d.Set(floatingIPTarget, target.ID) + } + + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceFloatingIpUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + if d.HasChange(isBareMetalServerNetworkInterfaceFloatingIPID) { + bareMetalServerId, nicId, _, err := ParseNICFipTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + floatingIpId := "" + if fipOk, ok := d.GetOk(isBareMetalServerNetworkInterfaceFloatingIPID); ok { + floatingIpId = fipOk.(string) + } + options := &vpcv1.AddBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicId, + ID: &floatingIpId, + } + + fip, response, err := sess.AddBareMetalServerNetworkInterfaceFloatingIPWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating Bare Metal Server: %s\n%s", err, response)) + } + d.SetId(MakeTerraformNICFipID(bareMetalServerId, nicId, *fip.ID)) + return diag.FromErr(bareMetalServerNICFipGet(d, fip, bareMetalServerId, nicId)) + } + return nil +} + +func resourceIBMISBareMetalServerNetworkInterfaceFloatingIpDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + bareMetalServerId, nicId, fipId, err := ParseNICFipTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + err = bareMetalServerNetworkInterfaceFipDelete(context, d, meta, bareMetalServerId, nicId, fipId) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func bareMetalServerNetworkInterfaceFipDelete(context context.Context, d *schema.ResourceData, meta interface{}, bareMetalServerId, nicId, fipId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getBmsNicFipOptions := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + fip, response, err := sess.GetBareMetalServerNetworkInterfaceFloatingIPWithContext(context, getBmsNicFipOptions) + if err != nil || fip == nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) network interface(%s) Floating Ip(%s) : %s\n%s", bareMetalServerId, nicId, fipId, err, response) + } + + options := &vpcv1.RemoveBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + response, err = sess.RemoveBareMetalServerNetworkInterfaceFloatingIPWithContext(context, options) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Bare Metal Server (%s) network interface (%s) Floating Ip(%s) : %s\n%s", bareMetalServerId, nicId, fipId, err, response) + } + _, err = isWaitForBareMetalServerNetworkInterfaceFloatingIpDeleted(sess, bareMetalServerId, nicId, fipId, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForBareMetalServerNetworkInterfaceFloatingIpDeleted(bmsC *vpcv1.VpcV1, bareMetalServerId, nicId, fipId string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) / (%s) / (%s) to be deleted.", bareMetalServerId, nicId, fipId) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerNetworkInterfaceFloatingIpAvailable, isBareMetalServerNetworkInterfaceFloatingIpDeleting, isBareMetalServerNetworkInterfaceFloatingIpPending}, + Target: []string{isBareMetalServerNetworkInterfaceFloatingIpDeleted, isBareMetalServerNetworkInterfaceFailed, ""}, + Refresh: isBareMetalServerNetworkInterfaceFloatingIpDeleteRefreshFunc(bmsC, bareMetalServerId, nicId, fipId), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isBareMetalServerNetworkInterfaceFloatingIpDeleteRefreshFunc(bmsC *vpcv1.VpcV1, bareMetalServerId, nicId, fipId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getBmsNicFloatingIpOptions := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + fip, response, err := bmsC.GetBareMetalServerNetworkInterfaceFloatingIP(getBmsNicFloatingIpOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return fip, isBareMetalServerNetworkInterfaceFloatingIpDeleted, nil + } + return fip, isBareMetalServerNetworkInterfaceFloatingIpFailed, fmt.Errorf("[ERROR] Error getting Bare Metal Server(%s) Network Interface (%s) FloatingIp(%s) : %s\n%s", bareMetalServerId, nicId, fipId, err, response) + } + return fip, isBareMetalServerNetworkInterfaceFloatingIpDeleting, err + } +} + +func isWaitForBareMetalServerNetworkInterfaceFloatingIpAvailable(client *vpcv1.VpcV1, bareMetalServerId, nicId, fipId string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for Bare Metal Server (%s) Network Interface (%s) to be available.", bareMetalServerId, nicId) + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isBareMetalServerNetworkInterfaceFloatingIpPending}, + Target: []string{isBareMetalServerNetworkInterfaceFloatingIpAvailable, isBareMetalServerNetworkInterfaceFloatingIpFailed}, + Refresh: isBareMetalServerNetworkInterfaceFloatingIpRefreshFunc(client, bareMetalServerId, nicId, fipId, d, communicator), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isBareMetalServerNetworkInterfaceFloatingIpRefreshFunc(client *vpcv1.VpcV1, bareMetalServerId, nicId, fipId string, d *schema.ResourceData, communicator chan interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getBmsNicFloatingIpOptions := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bareMetalServerId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + fip, response, err := client.GetBareMetalServerNetworkInterfaceFloatingIP(getBmsNicFloatingIpOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting Bare Metal Server (%s) Network Interface (%s) FloatingIp(%s) : %s\n%s", bareMetalServerId, nicId, fipId, err, response) + } + status := "" + + status = *fip.Status + d.Set(floatingIPStatus, *fip.Status) + + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + + if status == "available" || status == "failed" { + close(communicator) + return fip, status, nil + + } + + return fip, "pending", nil + } +} + +func MakeTerraformNICFipID(id1, id2, id3 string) string { + // Include bare metal sever id, network interface id, floating ip id to create a unique Terraform id. As a bonus, + // we can extract the bare metal sever id as needed for API calls such as READ. + return fmt.Sprintf("%s/%s/%s", id1, id2, id3) +} + +func ParseNICFipTerraformID(s string) (string, string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 3 { + return "", "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" || segments[2] == "" { + return "", "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], segments[2], nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip_test.go new file mode 100644 index 000000000..4bb453bde --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_floating_ip_test.go @@ -0,0 +1,155 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISBareMetalServerNetworkInterfaceFloatingIp_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIpConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerNetworkInterfaceExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIpDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_bare_metal_server_floating_ip" { + continue + } + bmsId, nicId, fipId, err := vpc.ParseNICFipTerraformID(rs.Primary.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error parsing ID : %s", rs.Primary.ID) + } + getbmsnicfipoptions := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bmsId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + _, _, err = sess.GetBareMetalServerNetworkInterfaceFloatingIP(getbmsnicfipoptions) + if err == nil { + return fmt.Errorf("Bare metal server network interface floating ip association still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIpExists(n, ip string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + bmsId, nicId, fipId, err := vpc.ParseNICFipTerraformID(rs.Primary.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error parsing ID : %s", rs.Primary.ID) + } + getbmsnicfipoptions := &vpcv1.GetBareMetalServerNetworkInterfaceFloatingIPOptions{ + BareMetalServerID: &bmsId, + NetworkInterfaceID: &nicId, + ID: &fipId, + } + fip, _, err := sess.GetBareMetalServerNetworkInterfaceFloatingIP(getbmsnicfipoptions) + if err != nil { + return err + } + ip = vpc.MakeTerraformNICFipID(bmsId, nicId, *fip.ID) + return nil + } +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceFloatingIpConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_floating_ip" "testacc_fip" { + name = "testfip1" + zone = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + resource ibm_is_bare_metal_server_network_interface bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] + } + + resource ibm_is_bare_metal_server_network_interface_floating_ip bms_nic_fip { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + network_interface = ibm_is_bare_metal_server_network_interface.bms_nic.id + floating_ip = ibm_is_floating_ip.testacc_fip.id + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.ISZoneName, acc.IsBareMetalServerProfileName, name, acc.IsImage, acc.ISZoneName) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_test.go new file mode 100644 index 000000000..dd7091c99 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_test.go @@ -0,0 +1,231 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "reflect" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISBareMetalServerNetworkInterface_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerNetworkInterfaceExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServerNetworkInterface_basic_rip(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + subnetreservedipname := fmt.Sprintf("tfip-subnet-rip-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerNetworkInterfaceRipConfig(vpcname, subnetname, subnetreservedipname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerNetworkInterfaceExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_bare_metal_server_network_interface" { + continue + } + bmsId, nicId, err := vpc.ParseNICTerraformID(rs.Primary.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error parsing ID : %s", rs.Primary.ID) + } + getbmsnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bmsId, + ID: &nicId, + } + _, _, err = sess.GetBareMetalServerNetworkInterface(getbmsnicoptions) + if err == nil { + return fmt.Errorf("Bare metal server network interafce still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceExists(n, ip string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + bmsId, nicId, err := vpc.ParseNICTerraformID(rs.Primary.ID) + if err != nil { + return fmt.Errorf("[ERROR] Error parsing ID : %s", rs.Primary.ID) + } + getbmsnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ + BareMetalServerID: &bmsId, + ID: &nicId, + } + nicIntf, _, err := sess.GetBareMetalServerNetworkInterface(getbmsnicoptions) + + if err != nil { + return err + } + switch reflect.TypeOf(nicIntf).String() { + case "*vpcv1.BareMetalServerNetworkInterfaceByPci": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + ip = vpc.MakeTerraformNICID(bmsId, *nic.ID) + } + case "*vpcv1.BareMetalServerNetworkInterfaceByVlan": + { + nic := nicIntf.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) + ip = vpc.MakeTerraformNICID(bmsId, *nic.ID) + } + } + return nil + } +} + +func testAccCheckIBMISBareMetalServerNetworkInterfaceConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + resource ibm_is_bare_metal_server_network_interface bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsImage, acc.ISZoneName) +} +func testAccCheckIBMISBareMetalServerNetworkInterfaceRipConfig(vpcname, subnetname, subnetreservedipname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } + resource ibm_is_bare_metal_server_network_interface bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + +`, vpcname, subnetname, acc.ISZoneName, subnetreservedipname, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsImage, acc.ISZoneName) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go new file mode 100644 index 000000000..9ae1f6289 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go @@ -0,0 +1,338 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISBareMetalServer_basic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServer_multi_nic(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerMultiNicConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "network_interfaces.0.vlan", "102"), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServer_multi_nic_with_allow_float(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerMultiNicWithAllowFloatConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "network_interfaces.0.vlan", "102"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "name", "eth21"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "allow_ip_spoofing", "false"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "allow_interface_to_float", "true"), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server_network_interface_allow_float.bms_nic", "enable_infrastructure_nat", "true"), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServer_basic_reserved_ip(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerReservedIpConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_bare_metal_server" { + continue + } + + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetBareMetalServer(getbmsoptions) + if err == nil { + return fmt.Errorf("Bare metal server still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISBareMetalServerExists(n, ip string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &rs.Primary.ID, + } + bms, _, err := sess.GetBareMetalServer(getbmsoptions) + if err != nil { + return err + } + ip = *bms.ID + return nil + } +} + +func testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} + +func testAccCheckIBMISBareMetalServerMultiNicConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + allowed_vlans = [102,103] + } + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + vlan = 102 + } + vpc = ibm_is_vpc.testacc_vpc.id + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} +func testAccCheckIBMISBareMetalServerMultiNicWithAllowFloatConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + allowed_vlans = [101,102,103] + } + network_interfaces { + name = "eth20" + subnet = ibm_is_subnet.testacc_subnet.id + vlan = 102 + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource ibm_is_bare_metal_server_network_interface_allow_float bms_nic { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth21" + vlan = 101 + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} +func testAccCheckIBMISBareMetalServerReservedIpConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + primary_ip { + auto_delete = true + address = "${replace(ibm_is_subnet.testacc_subnet.ipv4_cidr_block, "0/28", "14")}" + } + } + vpc = ibm_is_vpc.testacc_vpc.id + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} diff --git a/ibm/resource_ibm_is_dedicated_host.go b/ibm/service/vpc/resource_ibm_is_dedicated_host.go similarity index 87% rename from ibm/resource_ibm_is_dedicated_host.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host.go index dcf84b4e7..2c2de7651 100644 --- a/ibm/resource_ibm_is_dedicated_host.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,6 +9,9 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -34,7 +37,7 @@ const ( isDedicatedHostStatusFailed = "failed" ) -func resourceIbmIsDedicatedHost() *schema.Resource { +func ResourceIbmIsDedicatedHost() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmIsDedicatedHostCreate, ReadContext: resourceIbmIsDedicatedHostRead, @@ -53,7 +56,7 @@ func resourceIbmIsDedicatedHost() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_dedicated_host", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_dedicated_host", "name"), Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, "profile": { @@ -109,45 +112,45 @@ func resourceIbmIsDedicatedHost() *schema.Resource { Computed: true, Description: "The CRN for this dedicated host.", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Computed: true, Description: "Collection of the dedicated host's disks.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "available": &schema.Schema{ + "available": { Type: schema.TypeInt, Computed: true, Description: "The remaining space left for instance placement in GB (gigabytes).", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the disk was created.", }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this disk.", }, - "instance_disks": &schema.Schema{ + "instance_disks": { Type: schema.TypeList, Computed: true, Description: "Instance disks that are on this dedicated host disk.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -155,22 +158,22 @@ func resourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this instance disk.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined name for this disk.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The resource type.", @@ -178,37 +181,37 @@ func resourceIbmIsDedicatedHost() *schema.Resource { }, }, }, - "interface_type": &schema.Schema{ + "interface_type": { Type: schema.TypeString, Computed: true, Description: "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", }, - "lifecycle_state": &schema.Schema{ + "lifecycle_state": { Type: schema.TypeString, Computed: true, Description: "The lifecycle state of this dedicated host disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The user-defined or system-provided name for this disk.", }, - "provisionable": &schema.Schema{ + "provisionable": { Type: schema.TypeBool, Computed: true, Description: "Indicates whether this dedicated host disk is available for instance disk creation.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "size": &schema.Schema{ + "size": { Type: schema.TypeInt, Computed: true, Description: "The size of the disk in GB (gigabytes).", }, - "supported_instance_interface_types": &schema.Schema{ + "supported_instance_interface_types": { Type: schema.TypeList, Computed: true, Description: "The instance disk interfaces supported for this dedicated host disk.", @@ -342,25 +345,25 @@ func resourceIbmIsDedicatedHost() *schema.Resource { } } -func resourceIbmIsDedicatedHostValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIbmIsDedicatedHostValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63, }) - resourceValidator := ResourceValidator{ResourceName: "ibm_is_dedicated_host", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_dedicated_host", Schema: validateSchema} return &resourceValidator } func resourceIbmIsDedicatedHostCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -420,7 +423,7 @@ func resourceIbmIsDedicatedHostCreate(context context.Context, d *schema.Resourc } func resourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -439,18 +442,18 @@ func resourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceD return diag.FromErr(err) } - if err = d.Set("available_memory", intValue(dedicatedHost.AvailableMemory)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting available_memory: %s", err)) + if err = d.Set("available_memory", flex.IntValue(dedicatedHost.AvailableMemory)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting available_memory: %s", err)) } availableVcpuMap := resourceIbmIsDedicatedHostVCPUToMap(*dedicatedHost.AvailableVcpu) if err = d.Set("available_vcpu", []map[string]interface{}{availableVcpuMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting available_vcpu: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting available_vcpu: %s", err)) } if err = d.Set("created_at", dedicatedHost.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("crn", dedicatedHost.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } disks := []map[string]interface{}{} for _, disksItem := range dedicatedHost.Disks { @@ -458,15 +461,15 @@ func resourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceD disks = append(disks, disksItemMap) } if err = d.Set("disks", disks); err != nil { - return diag.FromErr(fmt.Errorf("Error setting disks: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting disks: %s", err)) } d.Set("host_group", *dedicatedHost.Group.ID) if err = d.Set("href", dedicatedHost.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("instance_placement_enabled", dedicatedHost.InstancePlacementEnabled); err != nil { - return diag.FromErr(fmt.Errorf("Error setting instance_placement_enabled: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_placement_enabled: %s", err)) } instances := []map[string]interface{}{} for _, instancesItem := range dedicatedHost.Instances { @@ -474,35 +477,35 @@ func resourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceD instances = append(instances, instancesItemMap) } if err = d.Set("instances", instances); err != nil { - return diag.FromErr(fmt.Errorf("Error setting instances: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instances: %s", err)) } if err = d.Set("lifecycle_state", dedicatedHost.LifecycleState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) } - if err = d.Set("memory", intValue(dedicatedHost.Memory)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting memory: %s", err)) + if err = d.Set("memory", flex.IntValue(dedicatedHost.Memory)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting memory: %s", err)) } if err = d.Set("name", dedicatedHost.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if err = d.Set("profile", *dedicatedHost.Profile.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting profile: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile: %s", err)) } if err = d.Set("provisionable", dedicatedHost.Provisionable); err != nil { - return diag.FromErr(fmt.Errorf("Error setting provisionable: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting provisionable: %s", err)) } if err = d.Set("resource_group", *dedicatedHost.ResourceGroup.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) } if err = d.Set("resource_type", dedicatedHost.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } - if err = d.Set("socket_count", intValue(dedicatedHost.SocketCount)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting socket_count: %s", err)) + if err = d.Set("socket_count", flex.IntValue(dedicatedHost.SocketCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting socket_count: %s", err)) } if err = d.Set("state", dedicatedHost.State); err != nil { - return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting state: %s", err)) } supportedInstanceProfiles := []map[string]interface{}{} for _, supportedInstanceProfilesItem := range dedicatedHost.SupportedInstanceProfiles { @@ -510,15 +513,15 @@ func resourceIbmIsDedicatedHostRead(context context.Context, d *schema.ResourceD supportedInstanceProfiles = append(supportedInstanceProfiles, supportedInstanceProfilesItemMap) } if err = d.Set("supported_instance_profiles", supportedInstanceProfiles); err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_profiles: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_profiles: %s", err)) } vcpuMap := resourceIbmIsDedicatedHostVCPUToMap(*dedicatedHost.Vcpu) if err = d.Set("vcpu", []map[string]interface{}{vcpuMap}); err != nil { - return diag.FromErr(fmt.Errorf("Error setting vcpu: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vcpu: %s", err)) } if err = d.Set("zone", *dedicatedHost.Zone.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting zone: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone: %s", err)) } return nil @@ -528,7 +531,7 @@ func resourceIbmIsDedicatedHostVCPUToMap(vCPU vpcv1.Vcpu) map[string]interface{} vCPUMap := map[string]interface{}{} vCPUMap["architecture"] = vCPU.Architecture - vCPUMap["count"] = intValue(vCPU.Count) + vCPUMap["count"] = flex.IntValue(vCPU.Count) return vCPUMap } @@ -566,7 +569,7 @@ func resourceIbmIsDedicatedHostInstanceProfileReferenceToMap(instanceProfileRefe } func resourceIbmIsDedicatedHostUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -615,7 +618,7 @@ func resourceIbmIsDedicatedHostUpdate(context context.Context, d *schema.Resourc } func resourceIbmIsDedicatedHostDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -679,10 +682,10 @@ func isWaitForDedicatedHostDelete(instanceC *vpcv1.VpcV1, d *schema.ResourceData if response != nil && response.StatusCode == 404 { return dedicatedhost, isDedicatedHostDeleteDone, nil } - return nil, "", fmt.Errorf("Error getting dedicated Host: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting dedicated Host: %s\n%s", err, response) } if *dedicatedhost.State == isDedicatedHostFailed { - return dedicatedhost, *dedicatedhost.State, fmt.Errorf("The Dedicated host %s failed to delete: %v", d.Id(), err) + return dedicatedhost, *dedicatedhost.State, fmt.Errorf("[ERROR] The Dedicated host %s failed to delete: %v", d.Id(), err) } return dedicatedhost, isDedicatedHostDeleting, nil }, @@ -716,7 +719,7 @@ func isDedicatedHostRefreshFunc(instanceC *vpcv1.VpcV1, id string, d *schema.Res } dhost, response, err := instanceC.GetDedicatedHost(getinsOptions) if dhost == nil || err != nil { - return nil, "", fmt.Errorf("Error getting dedicated host : %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting dedicated host : %s\n%s", err, response) } d.Set("state", *dhost.State) d.Set("lifecycle_state", *dhost.LifecycleState) @@ -733,7 +736,7 @@ func isDedicatedHostRefreshFunc(instanceC *vpcv1.VpcV1, id string, d *schema.Res func resourceIbmIsDedicatedHostDedicatedHostDiskToMap(dedicatedHostDisk vpcv1.DedicatedHostDisk) map[string]interface{} { dedicatedHostDiskMap := map[string]interface{}{} - dedicatedHostDiskMap["available"] = intValue(dedicatedHostDisk.Available) + dedicatedHostDiskMap["available"] = flex.IntValue(dedicatedHostDisk.Available) dedicatedHostDiskMap["created_at"] = dedicatedHostDisk.CreatedAt.String() dedicatedHostDiskMap["href"] = dedicatedHostDisk.Href dedicatedHostDiskMap["id"] = dedicatedHostDisk.ID @@ -751,7 +754,7 @@ func resourceIbmIsDedicatedHostDedicatedHostDiskToMap(dedicatedHostDisk vpcv1.De dedicatedHostDiskMap["name"] = dedicatedHostDisk.Name dedicatedHostDiskMap["provisionable"] = dedicatedHostDisk.Provisionable dedicatedHostDiskMap["resource_type"] = dedicatedHostDisk.ResourceType - dedicatedHostDiskMap["size"] = intValue(dedicatedHostDisk.Size) + dedicatedHostDiskMap["size"] = flex.IntValue(dedicatedHostDisk.Size) dedicatedHostDiskMap["supported_instance_interface_types"] = dedicatedHostDisk.SupportedInstanceInterfaceTypes return dedicatedHostDiskMap diff --git a/ibm/resource_ibm_is_dedicated_host_disk_management.go b/ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management.go similarity index 79% rename from ibm/resource_ibm_is_dedicated_host_disk_management.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management.go index 4fa208d44..1730b84d6 100644 --- a/ibm/resource_ibm_is_dedicated_host_disk_management.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const () -func resourceIBMISDedicatedHostDiskManagement() *schema.Resource { +func ResourceIBMISDedicatedHostDiskManagement() *schema.Resource { return &schema.Resource{ Create: resourceIBMisDedicatedHostDiskManagementCreate, Read: resourceIBMisDedicatedHostDiskManagementRead, @@ -27,21 +28,21 @@ func resourceIBMISDedicatedHostDiskManagement() *schema.Resource { ForceNew: true, Description: "ID of the dedicated host for which disks has to be managed", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Required: true, Description: "Disk information that has to be updated.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Required: true, Description: "The unique identifier for this disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_dedicated_host_disk_management", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_dedicated_host_disk_management", "name"), Description: "The user-defined name for this disk. The disk will be updated with this new name", }, }, @@ -51,20 +52,20 @@ func resourceIBMISDedicatedHostDiskManagement() *schema.Resource { } } -func resourceIBMISDedicatedHostDiskManagementValidator() *ResourceValidator { +func ResourceIBMISDedicatedHostDiskManagementValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) - ibmISDedicatedHostDiskManagementValidator := ResourceValidator{ResourceName: "ibm_is_dedicated_host_disk_management", Schema: validateSchema} + ibmISDedicatedHostDiskManagementValidator := validate.ResourceValidator{ResourceName: "ibm_is_dedicated_host_disk_management", Schema: validateSchema} return &ibmISDedicatedHostDiskManagementValidator } @@ -91,13 +92,13 @@ func resourceIBMisDedicatedHostDiskManagementCreate(d *schema.ResourceData, meta dedicatedHostDiskPatch, err := dedicatedHostDiskPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for DedicatedHostDiskPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for DedicatedHostDiskPatch: %s", err) } updateDedicatedHostDiskOptions.SetDedicatedHostDiskPatch(dedicatedHostDiskPatch) _, _, err = sess.UpdateDedicatedHostDisk(updateDedicatedHostDiskOptions) if err != nil { - return fmt.Errorf("Error calling UpdateDedicatedHostDisk: %s", err) + return fmt.Errorf("[ERROR] Error calling UpdateDedicatedHostDisk: %s", err) } } @@ -128,13 +129,13 @@ func resourceIBMisDedicatedHostDiskManagementUpdate(d *schema.ResourceData, meta dedicatedHostDiskPatch, err := dedicatedHostDiskPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for DedicatedHostDiskPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for DedicatedHostDiskPatch: %s", err) } updateDedicatedHostDiskOptions.SetDedicatedHostDiskPatch(dedicatedHostDiskPatch) _, response, err := sess.UpdateDedicatedHostDisk(updateDedicatedHostDiskOptions) if err != nil { - return fmt.Errorf("Error updating dedicated host disk: %s %s", err, response) + return fmt.Errorf("[ERROR] Error updating dedicated host disk: %s %s", err, response) } } diff --git a/ibm/resource_ibm_is_dedicated_host_disk_management_test.go b/ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management_test.go similarity index 77% rename from ibm/resource_ibm_is_dedicated_host_disk_management_test.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management_test.go index d5a4e2b4c..c1bd66f7a 100644 --- a/ibm/resource_ibm_is_dedicated_host_disk_management_test.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host_disk_management_test.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,11 +22,11 @@ func TestAccIBMISDedicatedHostDiskManagement_basic(t *testing.T) { diskName := "tf-dhdisk01" diskResname := "data.ibm_is_dedicated_host_disk.test1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIbmIsDedicatedHostConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + Config: testAccCheckIbmIsDedicatedHostConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostExists(resName, conf), resource.TestCheckResourceAttr(resName, "name", dhname), @@ -33,8 +35,8 @@ func TestAccIBMISDedicatedHostDiskManagement_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "disks.0.size"), ), }, - resource.TestStep{ - Config: testAccCheckIBMISDedicatedHostDiskManagementConfig(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname, diskName), + { + Config: testAccCheckIBMISDedicatedHostDiskManagementConfig(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname, diskName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(diskResname, "name"), resource.TestCheckResourceAttrSet(diskResname, "size"), @@ -45,8 +47,8 @@ func TestAccIBMISDedicatedHostDiskManagement_basic(t *testing.T) { }) } -func testAccCheckIBMISDedicatedHostDiskManagementConfig(class, family, groupname, dedicatedHostProfileName, dhname, diskName string) string { - return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, dedicatedHostProfileName, dhname) + fmt.Sprintf(` +func testAccCheckIBMISDedicatedHostDiskManagementConfig(class, family, groupname, DedicatedHostProfileName, dhname, diskName string) string { + return testAccCheckIbmIsDedicatedHostConfigBasic(class, family, groupname, acc.DedicatedHostProfileName, dhname) + fmt.Sprintf(` data "ibm_is_dedicated_host" "dhost" { name = "%s" host_group = ibm_is_dedicated_host.dhost.host_group diff --git a/ibm/resource_ibm_is_dedicated_host_group.go b/ibm/service/vpc/resource_ibm_is_dedicated_host_group.go similarity index 85% rename from ibm/resource_ibm_is_dedicated_host_group.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host_group.go index bd75fe714..5c769a973 100644 --- a/ibm/resource_ibm_is_dedicated_host_group.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host_group.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -15,7 +17,7 @@ import ( "github.com/IBM/vpc-go-sdk/vpcv1" ) -func resourceIbmIsDedicatedHostGroup() *schema.Resource { +func ResourceIbmIsDedicatedHostGroup() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmIsDedicatedHostGroupCreate, ReadContext: resourceIbmIsDedicatedHostGroupRead, @@ -24,67 +26,67 @@ func resourceIbmIsDedicatedHostGroup() *schema.Resource { Importer: &schema.ResourceImporter{}, Schema: map[string]*schema.Schema{ - "class": &schema.Schema{ + "class": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "The dedicated host profile class for hosts in this group.", }, - "family": &schema.Schema{ + "family": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_dedicated_host_group", "family"), + ValidateFunc: validate.InvokeValidator("ibm_is_dedicated_host_group", "family"), Description: "The dedicated host profile family for hosts in this group.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_dedicated_host_group", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_dedicated_host_group", "name"), Description: "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "resource_group": &schema.Schema{ + "resource_group": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, Description: "The unique identifier of the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", }, - "zone": &schema.Schema{ + "zone": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "The globally unique name of the zone this dedicated host group will reside in.", }, - "created_at": &schema.Schema{ + "created_at": { Type: schema.TypeString, Computed: true, Description: "The date and time that the dedicated host group was created.", }, - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host group.", }, - "dedicated_hosts": &schema.Schema{ + "dedicated_hosts": { Type: schema.TypeList, Computed: true, Description: "The dedicated hosts that are in this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "crn": &schema.Schema{ + "crn": { Type: schema.TypeString, Computed: true, Description: "The CRN for this dedicated host.", }, - "deleted": &schema.Schema{ + "deleted": { Type: schema.TypeList, Computed: true, Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "more_info": &schema.Schema{ + "more_info": { Type: schema.TypeString, Computed: true, Description: "Link to documentation about deleted resources.", @@ -92,22 +94,22 @@ func resourceIbmIsDedicatedHostGroup() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host.", }, - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Computed: true, Description: "The unique identifier for this dedicated host.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", @@ -115,28 +117,28 @@ func resourceIbmIsDedicatedHostGroup() *schema.Resource { }, }, }, - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this dedicated host group.", }, - "resource_type": &schema.Schema{ + "resource_type": { Type: schema.TypeString, Computed: true, Description: "The type of resource referenced.", }, - "supported_instance_profiles": &schema.Schema{ + "supported_instance_profiles": { Type: schema.TypeList, Computed: true, Description: "Array of instance profiles that can be used by instances placed on this dedicated host group.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "href": &schema.Schema{ + "href": { Type: schema.TypeString, Computed: true, Description: "The URL for this virtual server instance profile.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Computed: true, Description: "The globally unique name for this virtual server instance profile.", @@ -148,33 +150,33 @@ func resourceIbmIsDedicatedHostGroup() *schema.Resource { } } -func resourceIbmIsDedicatedHostGroupValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIbmIsDedicatedHostGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "family", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: "balanced, compute, memory", }) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63, }) - resourceValidator := ResourceValidator{ResourceName: "ibm_is_dedicated_host_group", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_dedicated_host_group", Schema: validateSchema} return &resourceValidator } func resourceIbmIsDedicatedHostGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -235,7 +237,7 @@ func resourceIbmIsDedicatedHostGroupMapToResourceGroupIdentityByID(resourceGroup } func resourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -255,31 +257,31 @@ func resourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.Reso } if err = d.Set("class", dedicatedHostGroup.Class); err != nil { - return diag.FromErr(fmt.Errorf("Error setting class: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting class: %s", err)) } if err = d.Set("family", dedicatedHostGroup.Family); err != nil { - return diag.FromErr(fmt.Errorf("Error setting family: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting family: %s", err)) } if err = d.Set("name", dedicatedHostGroup.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if dedicatedHostGroup.ResourceGroup != nil { resourceGroupID := *dedicatedHostGroup.ResourceGroup.ID if err = d.Set("resource_group", resourceGroupID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) } } if dedicatedHostGroup.Zone != nil { zoneName := *dedicatedHostGroup.Zone.Name if err = d.Set("zone", zoneName); err != nil { - return diag.FromErr(fmt.Errorf("Error setting zone: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone: %s", err)) } } if err = d.Set("created_at", dedicatedHostGroup.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("crn", dedicatedHostGroup.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } dedicatedHosts := []map[string]interface{}{} for _, dedicatedHostsItem := range dedicatedHostGroup.DedicatedHosts { @@ -287,13 +289,13 @@ func resourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.Reso dedicatedHosts = append(dedicatedHosts, dedicatedHostsItemMap) } if err = d.Set("dedicated_hosts", dedicatedHosts); err != nil { - return diag.FromErr(fmt.Errorf("Error setting dedicated_hosts: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting dedicated_hosts: %s", err)) } if err = d.Set("href", dedicatedHostGroup.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("resource_type", dedicatedHostGroup.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } supportedInstanceProfiles := []map[string]interface{}{} for _, supportedInstanceProfilesItem := range dedicatedHostGroup.SupportedInstanceProfiles { @@ -301,7 +303,7 @@ func resourceIbmIsDedicatedHostGroupRead(context context.Context, d *schema.Reso supportedInstanceProfiles = append(supportedInstanceProfiles, supportedInstanceProfilesItemMap) } if err = d.Set("supported_instance_profiles", supportedInstanceProfiles); err != nil { - return diag.FromErr(fmt.Errorf("Error setting supported_instance_profiles: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting supported_instance_profiles: %s", err)) } return nil @@ -382,7 +384,7 @@ func resourceIbmIsDedicatedHostGroupInstanceProfileReferenceToMap(instanceProfil } func resourceIbmIsDedicatedHostGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -419,7 +421,7 @@ func resourceIbmIsDedicatedHostGroupUpdate(context context.Context, d *schema.Re } func resourceIbmIsDedicatedHostGroupDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } diff --git a/ibm/resource_ibm_is_dedicated_host_group_test.go b/ibm/service/vpc/resource_ibm_is_dedicated_host_group_test.go similarity index 81% rename from ibm/resource_ibm_is_dedicated_host_group_test.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host_group_test.go index 9e15fcbab..c1916b298 100644 --- a/ibm/resource_ibm_is_dedicated_host_group_test.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host_group_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -18,18 +21,18 @@ func TestAccIbmIsDedicatedHostGroupBasic(t *testing.T) { var conf vpcv1.DedicatedHostGroup name := fmt.Sprintf("tfdhgroup%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, name), + { + Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostGroupExists("ibm_is_dedicated_host_group.is_dedicated_host_group", conf), ), }, - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, name), + { + Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, name), Check: resource.ComposeAggregateTestCheckFunc(), }, }, @@ -45,11 +48,11 @@ func TestAccIbmIsDedicatedHostGroupAllArgs(t *testing.T) { nameUpdate := fmt.Sprintf("tfdhgroup%d", acctest.RandIntRange(10, 1000)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostGroupDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(class, family, name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostGroupExists("ibm_is_dedicated_host_group.is_dedicated_host_group", conf), @@ -58,13 +61,13 @@ func TestAccIbmIsDedicatedHostGroupAllArgs(t *testing.T) { resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "name", name), ), }, - resource.TestStep{ + { Config: testAccCheckIbmIsDedicatedHostGroupConfigBasic(class, family, nameUpdate), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_is_dedicated_host_group.is_dedicated_host_group", "name", nameUpdate), ), }, - resource.TestStep{ + { ResourceName: "ibm_is_dedicated_host_group.is_dedicated_host_group", ImportState: true, ImportStateVerify: true, @@ -97,7 +100,7 @@ func testAccCheckIbmIsDedicatedHostGroupExists(n string, obj vpcv1.DedicatedHost return fmt.Errorf("Not found: %s", n) } - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -117,7 +120,7 @@ func testAccCheckIbmIsDedicatedHostGroupExists(n string, obj vpcv1.DedicatedHost } func testAccCheckIbmIsDedicatedHostGroupDestroy(s *terraform.State) error { - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -136,7 +139,7 @@ func testAccCheckIbmIsDedicatedHostGroupDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("DedicatedHostGroup still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for DedicatedHostGroup (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for DedicatedHostGroup (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_is_dedicated_host_test.go b/ibm/service/vpc/resource_ibm_is_dedicated_host_test.go similarity index 81% rename from ibm/resource_ibm_is_dedicated_host_test.go rename to ibm/service/vpc/resource_ibm_is_dedicated_host_test.go index d44fb8404..de2fdc3f3 100644 --- a/ibm/resource_ibm_is_dedicated_host_test.go +++ b/ibm/service/vpc/resource_ibm_is_dedicated_host_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,12 +24,12 @@ func TestAccIbmIsDedicatedHostBasic(t *testing.T) { resname := "ibm_is_dedicated_host.dhost" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsDedicatedHostDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmIsDedicatedHostConfigBasic(dedicatedHostGroupClass, dedicatedHostGroupFamily, groupname, dedicatedHostProfileName, dhname), + { + Config: testAccCheckIbmIsDedicatedHostConfigBasic(acc.DedicatedHostGroupClass, acc.DedicatedHostGroupFamily, groupname, acc.DedicatedHostProfileName, dhname), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmIsDedicatedHostExists(resname, conf), resource.TestCheckResourceAttr(resname, "name", dhname), @@ -35,7 +38,7 @@ func TestAccIbmIsDedicatedHostBasic(t *testing.T) { resource.TestCheckResourceAttrSet(resname, "disks.0.size"), ), }, - resource.TestStep{ + { ResourceName: resname, ImportState: true, ImportStateVerify: true, @@ -74,7 +77,7 @@ func testAccCheckIbmIsDedicatedHostExists(n string, obj vpcv1.DedicatedHost) res return fmt.Errorf("Not found: %s", n) } - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -94,7 +97,7 @@ func testAccCheckIbmIsDedicatedHostExists(n string, obj vpcv1.DedicatedHost) res } func testAccCheckIbmIsDedicatedHostDestroy(s *terraform.State) error { - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -113,7 +116,7 @@ func testAccCheckIbmIsDedicatedHostDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("DedicatedHost still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for DedicatedHost (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for DedicatedHost (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/service/vpc/resource_ibm_is_floating_ip.go b/ibm/service/vpc/resource_ibm_is_floating_ip.go new file mode 100644 index 000000000..f4dad9c1c --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_floating_ip.go @@ -0,0 +1,807 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isFloatingIPAddress = "address" + isFloatingIPCRN = "crn" + isFloatingIPName = "name" + isFloatingIPStatus = "status" + isFloatingIPZone = "zone" + isFloatingIPTarget = "target" + isFloatingIPResourceGroup = "resource_group" + isFloatingIPTags = "tags" + + isFloatingIPPending = "pending" + isFloatingIPAvailable = "available" + isFloatingIPDeleting = "deleting" + isFloatingIPDeleted = "done" +) + +func ResourceIBMISFloatingIP() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISFloatingIPCreate, + Read: resourceIBMISFloatingIPRead, + Update: resourceIBMISFloatingIPUpdate, + Delete: resourceIBMISFloatingIPDelete, + Exists: resourceIBMISFloatingIPExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + + if diff.HasChange(isFloatingIPTarget) { + if !diff.NewValueKnown(isFloatingIPTarget) { + diff.ForceNew(isFloatingIPTarget) + return nil + } + old, new := diff.GetChange(isFloatingIPTarget) + if old != "" || new != "" { + sess, err := vpcClient(v) + if err != nil { + return err + } + if checkIfZoneChanged(old.(string), new.(string), diff.Get(isFloatingIPZone).(string), sess) { + diff.ForceNew(isFloatingIPTarget) + } + } + } + return nil + }, + ), + ), + + Schema: map[string]*schema.Schema{ + isFloatingIPAddress: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP address", + }, + + isFloatingIPName: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_floating_ip", isFloatingIPName), + Description: "Name of the floating IP", + }, + + isFloatingIPStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Floating IP status", + }, + + isFloatingIPZone: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ConflictsWith: []string{isFloatingIPTarget}, + ExactlyOneOf: []string{isFloatingIPTarget, isFloatingIPZone}, + Description: "Zone name", + }, + + isFloatingIPTarget: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{isFloatingIPZone}, + ExactlyOneOf: []string{isFloatingIPTarget, isFloatingIPZone}, + Description: "Target info", + }, + floatingIPTargets: { + Type: schema.TypeList, + Computed: true, + Description: "The target of this floating IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIPTargetsDeleted: { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIPTargetsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + floatingIPTargetsHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + floatingIPTargetsId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network interface.", + }, + floatingIPTargetsName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this network interface.", + }, + floatingIpPrimaryIP: { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + floatingIpPrimaryIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + floatingIpPrimaryIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + floatingIpPrimaryIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + floatingIpPrimaryIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + floatingIpPrimaryIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + floatingIPTargetsResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + floatingIPTargetsCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this public gateway.", + }, + }, + }, + }, + + isFloatingIPResourceGroup: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + Description: "Resource group info", + }, + + isFloatingIPTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_floating_ip", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Floating IP tags", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + isFloatingIPCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func vpcClient(meta interface{}) (*vpcv1.VpcV1, error) { + sess, err := meta.(conns.ClientSession).VpcV1API() + return sess, err +} + +func ResourceIBMISFloatingIPValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isFloatingIPName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISFloatingIPResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_floating_ip", Schema: validateSchema} + return &ibmISFloatingIPResourceValidator +} + +func resourceIBMISFloatingIPCreate(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isFloatingIPName).(string) + err := fipCreate(d, meta, name) + if err != nil { + return err + } + + return resourceIBMISFloatingIPRead(d, meta) +} + +func fipCreate(d *schema.ResourceData, meta interface{}, name string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + floatingIPPrototype := &vpcv1.FloatingIPPrototype{ + Name: &name, + } + zone, target := "", "" + if zn, ok := d.GetOk(isFloatingIPZone); ok { + zone = zn.(string) + floatingIPPrototype.Zone = &vpcv1.ZoneIdentity{ + Name: &zone, + } + } + + if tgt, ok := d.GetOk(isFloatingIPTarget); ok { + target = tgt.(string) + floatingIPPrototype.Target = &vpcv1.FloatingIPByTargetNetworkInterfaceIdentity{ + ID: &target, + } + } + + if zone == "" && target == "" { + return fmt.Errorf("%s or %s need to be provided", isFloatingIPZone, isFloatingIPTarget) + } + + if rgrp, ok := d.GetOk(isFloatingIPResourceGroup); ok { + rg := rgrp.(string) + floatingIPPrototype.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + createFloatingIPOptions := &vpcv1.CreateFloatingIPOptions{ + FloatingIPPrototype: floatingIPPrototype, + } + + floatingip, response, err := sess.CreateFloatingIP(createFloatingIPOptions) + if err != nil { + return fmt.Errorf("[DEBUG] Floating IP err %s\n%s", err, response) + } + d.SetId(*floatingip.ID) + log.Printf("[INFO] Floating IP : %s[%s]", *floatingip.ID, *floatingip.Address) + _, err = isWaitForInstanceFloatingIP(sess, d.Id(), d) + if err != nil { + return err + } + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isFloatingIPTags); ok || v != "" { + oldList, newList := d.GetChange(isFloatingIPTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *floatingip.CRN) + if err != nil { + log.Printf( + "Error on create of vpc Floating IP (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMISFloatingIPRead(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + err := fipGet(d, meta, id) + if err != nil { + return err + } + + return nil +} + +func fipGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + getFloatingIPOptions := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + floatingip, response, err := sess.GetFloatingIP(getFloatingIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Floating IP (%s): %s\n%s", id, err, response) + + } + d.Set(isFloatingIPName, *floatingip.Name) + d.Set(isFloatingIPAddress, *floatingip.Address) + d.Set(isFloatingIPStatus, *floatingip.Status) + d.Set(isFloatingIPZone, *floatingip.Zone.Name) + targetId, targetMap := floatingIPCollectionFloatingIpTargetToMap(floatingip.Target) + if targetId != "" { + d.Set(isFloatingIPTarget, targetId) + } else { + d.Set(isFloatingIPTarget, "") + } + targetList := make([]map[string]interface{}, 0) + targetList = append(targetList, targetMap) + d.Set(floatingIPTargets, targetList) + tags, err := flex.GetTagsUsingCRN(meta, *floatingip.CRN) + if err != nil { + log.Printf( + "Error on get of vpc Floating IP (%s) tags: %s", d.Id(), err) + } + d.Set(isFloatingIPTags, tags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/floatingIPs") + d.Set(flex.ResourceName, *floatingip.Name) + d.Set(isFloatingIPCRN, *floatingip.CRN) + d.Set(flex.ResourceCRN, *floatingip.CRN) + d.Set(flex.ResourceStatus, *floatingip.Status) + if floatingip.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, floatingip.ResourceGroup.Name) + d.Set(isFloatingIPResourceGroup, floatingip.ResourceGroup.ID) + } + return nil +} + +func resourceIBMISFloatingIPUpdate(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + err := fipUpdate(d, meta, id) + if err != nil { + return err + } + return resourceIBMISFloatingIPRead(d, meta) +} + +func fipUpdate(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + if d.HasChange(isFloatingIPTags) { + options := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + fip, response, err := sess.GetFloatingIP(options) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Floating IP: %s\n%s", err, response) + } + oldList, newList := d.GetChange(isFloatingIPTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *fip.CRN) + if err != nil { + log.Printf( + "Error on update of vpc Floating IP (%s) tags: %s", id, err) + } + } + hasChanged := false + options := &vpcv1.UpdateFloatingIPOptions{ + ID: &id, + } + floatingIPPatchModel := &vpcv1.FloatingIPPatch{} + if d.HasChange(isFloatingIPName) { + name := d.Get(isFloatingIPName).(string) + floatingIPPatchModel.Name = &name + hasChanged = true + floatingIPPatch, err := floatingIPPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for FloatingIPPatch: %s", err) + } + options.FloatingIPPatch = floatingIPPatch + } + + if d.HasChange(isFloatingIPTarget) { + target := d.Get(isFloatingIPTarget).(string) + floatingIPPatchModel.Target = &vpcv1.FloatingIPTargetPatch{ + ID: &target, + } + hasChanged = true + floatingIPPatch, err := floatingIPPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for floatingIPPatch: %s", err) + } + options.FloatingIPPatch = floatingIPPatch + } + if hasChanged { + _, response, err := sess.UpdateFloatingIP(options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vpc Floating IP: %s\n%s", err, response) + } + } + return nil +} + +func resourceIBMISFloatingIPDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + err := fipDelete(d, meta, id) + if err != nil { + return err + } + return nil +} + +func fipDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + getFloatingIpOptions := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + _, response, err := sess.GetFloatingIP(getFloatingIpOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + + return fmt.Errorf("[ERROR] Error Getting Floating IP (%s): %s\n%s", id, err, response) + } + + options := &vpcv1.DeleteFloatingIPOptions{ + ID: &id, + } + response, err = sess.DeleteFloatingIP(options) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Floating IP : %s\n%s", err, response) + } + _, err = isWaitForFloatingIPDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func resourceIBMISFloatingIPExists(d *schema.ResourceData, meta interface{}) (bool, error) { + id := d.Id() + exists, err := fipExists(d, meta, id) + return exists, err +} + +func fipExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + getFloatingIpOptions := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + _, response, err := sess.GetFloatingIP(getFloatingIpOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting floating IP: %s\n%s", err, response) + } + return true, nil +} + +func isWaitForFloatingIPDeleted(fip *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for FloatingIP (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isFloatingIPPending, isFloatingIPDeleting}, + Target: []string{"", isFloatingIPDeleted}, + Refresh: isFloatingIPDeleteRefreshFunc(fip, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isFloatingIPDeleteRefreshFunc(fip *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] floating ip delete function here") + getfipoptions := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + FloatingIP, response, err := fip.GetFloatingIP(getfipoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return FloatingIP, isFloatingIPDeleted, nil + } + return FloatingIP, "", fmt.Errorf("[ERROR] Error Getting Floating IP: %s\n%s", err, response) + } + return FloatingIP, isFloatingIPDeleting, err + } +} + +func isWaitForInstanceFloatingIP(floatingipC *vpcv1.VpcV1, id string, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for floating IP (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isFloatingIPPending}, + Target: []string{isFloatingIPAvailable, ""}, + Refresh: isInstanceFloatingIPRefreshFunc(floatingipC, id), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isInstanceFloatingIPRefreshFunc(floatingipC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getfipoptions := &vpcv1.GetFloatingIPOptions{ + ID: &id, + } + instance, response, err := floatingipC.GetFloatingIP(getfipoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Floating IP for the instance: %s\n%s", err, response) + } + + if *instance.Status == "available" { + return instance, isFloatingIPAvailable, nil + } + + return instance, isFloatingIPPending, nil + } +} + +func checkIfZoneChanged(oldNic, newNic, currentZone string, floatingipC *vpcv1.VpcV1) bool { + var oldZone, newZone string + listInstancesOptions := &vpcv1.ListInstancesOptions{} + start := "" + allrecs := []vpcv1.Instance{} + for { + + if start != "" { + listInstancesOptions.Start = &start + } + + instances, _, err := floatingipC.ListInstances(listInstancesOptions) + if err != nil { + return false + } + start = flex.GetNext(instances.Next) + allrecs = append(allrecs, instances.Instances...) + if start == "" { + break + } + } + for _, instance := range allrecs { + for _, nic := range instance.NetworkInterfaces { + if oldNic == *nic.ID { + oldZone = *instance.Zone.Name + } + if newNic == *nic.ID { + newZone = *instance.Zone.Name + } + } + } + if newZone != oldZone { + if oldZone == "" && newZone == currentZone { + return false + } + return true + } + return false +} + +func floatingIPCollectionFloatingIpTargetToMap(targetItemIntf vpcv1.FloatingIPTargetIntf) (targetId string, targetMap map[string]interface{}) { + targetMap = map[string]interface{}{} + targetId = "" + if targetItemIntf != nil { + switch reflect.TypeOf(targetItemIntf).String() { + case "*vpcv1.FloatingIPTargetNetworkInterfaceReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetNetworkInterfaceReference) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := floatingIPTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + } + case "*vpcv1.FloatingIPTargetPublicGatewayReference": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTargetPublicGatewayReference) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := floatingIPTargetPgDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap[floatingIPTargetsCrn] = targetItem.CRN + } + } + case "*vpcv1.FloatingIPTarget": + { + targetItem := targetItemIntf.(*vpcv1.FloatingIPTarget) + targetId = *targetItem.ID + if targetItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := floatingIPTargetNicDeletedToMap(*targetItem.Deleted) + deletedList = append(deletedList, deletedMap) + targetMap[floatingIPTargetsDeleted] = deletedList + } + if targetItem.Href != nil { + targetMap[floatingIPTargetsHref] = targetItem.Href + } + if targetItem.ID != nil { + targetMap[floatingIPTargetsId] = targetItem.ID + } + if targetItem.Name != nil { + targetMap[floatingIPTargetsName] = targetItem.Name + } + if targetItem.PrimaryIP != nil && targetItem.PrimaryIP.Address != nil { + primaryIpList := make([]map[string]interface{}, 0) + currentIP := map[string]interface{}{} + if targetItem.PrimaryIP.Address != nil { + currentIP[floatingIpPrimaryIpAddress] = *targetItem.PrimaryIP.Address + } + if targetItem.PrimaryIP.Href != nil { + currentIP[floatingIpPrimaryIpHref] = *targetItem.PrimaryIP.Href + } + if targetItem.PrimaryIP.Name != nil { + currentIP[floatingIpPrimaryIpName] = *targetItem.PrimaryIP.Name + } + if targetItem.PrimaryIP.ID != nil { + currentIP[floatingIpPrimaryIpId] = *targetItem.PrimaryIP.ID + } + if targetItem.PrimaryIP.ResourceType != nil { + currentIP[floatingIpPrimaryIpResourceType] = *targetItem.PrimaryIP.ResourceType + } + primaryIpList = append(primaryIpList, currentIP) + targetMap[floatingIpPrimaryIP] = primaryIpList + } + if targetItem.ResourceType != nil { + targetMap[floatingIPTargetsResourceType] = targetItem.ResourceType + } + if targetItem.CRN != nil { + targetMap[floatingIPTargetsCrn] = targetItem.CRN + } + } + } + } + + return targetId, targetMap +} + +func floatingIPTargetNicDeletedToMap(deletedItem vpcv1.NetworkInterfaceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[floatingIPTargetsMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} +func floatingIPTargetPgDeletedToMap(deletedItem vpcv1.PublicGatewayReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap[floatingIPTargetsMoreInfo] = deletedItem.MoreInfo + } + + return deletedMap +} diff --git a/ibm/service/vpc/resource_ibm_is_floating_ip_test.go b/ibm/service/vpc/resource_ibm_is_floating_ip_test.go new file mode 100644 index 000000000..7e3fca9fc --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_floating_ip_test.go @@ -0,0 +1,189 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISFloatingIP_basic(t *testing.T) { + var ip string + vpcname := fmt.Sprintf("tfip-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfip-%d", acctest.RandIntRange(10, 100)) + instancename := fmt.Sprintf("tfip-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tfip-sshname-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + userData2 := "b" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISFloatingIPDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISFloatingIPConfig(vpcname, subnetname, sshname, publicKey, instancename, userData1, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISFloatingIPExists("ibm_is_floating_ip.testacc_floatingip", ip), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.resource_type"), + ), + }, + { + Config: testAccCheckIBMISFloatingIPConfig(vpcname, subnetname, sshname, publicKey, instancename, userData2, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISFloatingIPExists("ibm_is_floating_ip.testacc_floatingip", ip), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData2), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("ibm_is_floating_ip.testacc_floatingip", "target_list.0.primary_ip.0.resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMISFloatingIP_NoTarget(t *testing.T) { + var ip string + name := fmt.Sprintf("tfip-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISFloatingIPDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISFloatingIPNoTargetConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISFloatingIPExists("ibm_is_floating_ip.testacc_floatingip", ip), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_floating_ip.testacc_floatingip", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func testAccCheckIBMISFloatingIPDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_floating_ip" { + continue + } + + getfipoptions := &vpcv1.GetFloatingIPOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetFloatingIP(getfipoptions) + if err == nil { + return fmt.Errorf("Floating IP still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISFloatingIPExists(n, ip string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getfipoptions := &vpcv1.GetFloatingIPOptions{ + ID: &rs.Primary.ID, + } + foundip, _, err := sess.GetFloatingIP(getfipoptions) + if err != nil { + return err + } + ip = *foundip.ID + return nil + } +} + +func testAccCheckIBMISFloatingIPConfig(vpcname, subnetname, sshname, publicKey, instancename, userData, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + resource "ibm_is_floating_ip" "testacc_floatingip" { + name = "%s" + target = ibm_is_instance.testacc_instance.primary_network_interface[0].id + } +`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, instancename, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName, name) +} + +func testAccCheckIBMISFloatingIPNoTargetConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_is_floating_ip" "testacc_floatingip" { + name = "%s" + zone = "%s" + } +`, name, acc.ISZoneName) +} diff --git a/ibm/resource_ibm_is_flow_log.go b/ibm/service/vpc/resource_ibm_is_flow_log.go similarity index 81% rename from ibm/resource_ibm_is_flow_log.go rename to ibm/service/vpc/resource_ibm_is_flow_log.go index 7cfd4a6f0..ff638a58f 100644 --- a/ibm/resource_ibm_is_flow_log.go +++ b/ibm/service/vpc/resource_ibm_is_flow_log.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -10,6 +10,8 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -32,7 +34,7 @@ const ( isFlowLogTags = "tags" ) -func resourceIBMISFlowLog() *schema.Resource { +func ResourceIBMISFlowLog() *schema.Resource { return &schema.Resource{ Create: resourceIBMISFlowLogCreate, Read: resourceIBMISFlowLogRead, @@ -49,7 +51,7 @@ func resourceIBMISFlowLog() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -59,7 +61,7 @@ func resourceIBMISFlowLog() *schema.Resource { Required: true, ForceNew: false, Description: "Flow Log Collector name", - ValidateFunc: InvokeValidator("ibm_is_flow_log", isFlowLogName), + ValidateFunc: validate.InvokeValidator("ibm_is_flow_log", isFlowLogName), }, isFlowLogStorageBucket: { @@ -131,36 +133,36 @@ func resourceIBMISFlowLog() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_flow_log", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_flow_log", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the VPC Flow logs", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -169,30 +171,30 @@ func resourceIBMISFlowLog() *schema.Resource { } } -func resourceIBMISFlowLogValidator() *ResourceValidator { +func ResourceIBMISFlowLogValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isFlowLogName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISFlowLogValidator := ResourceValidator{ResourceName: "ibm_is_flow_log", Schema: validateSchema} + ibmISFlowLogValidator := validate.ResourceValidator{ResourceName: "ibm_is_flow_log", Schema: validateSchema} return &ibmISFlowLogValidator } @@ -223,7 +225,7 @@ func resourceIBMISFlowLogCreate(d *schema.ResourceData, meta interface{}) error createFlowLogCollectorOptionsModel.Target = FlowLogCollectorTargetModel bucketname := d.Get(isFlowLogStorageBucket).(string) - cloudObjectStorageBucketIdentityModel := new(vpcv1.CloudObjectStorageBucketIdentityByName) + cloudObjectStorageBucketIdentityModel := new(vpcv1.LegacyCloudObjectStorageBucketIdentityCloudObjectStorageBucketIdentityByName) cloudObjectStorageBucketIdentityModel.Name = &bucketname createFlowLogCollectorOptionsModel.StorageBucket = cloudObjectStorageBucketIdentityModel @@ -238,7 +240,7 @@ func resourceIBMISFlowLogCreate(d *schema.ResourceData, meta interface{}) error v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isFlowLogTags); ok || v != "" { oldList, newList := d.GetChange(isFlowLogTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *flowlogCollector.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *flowlogCollector.CRN) if err != nil { log.Printf( "Error on create of resource vpc flow log (%s) tags: %s", d.Id(), err) @@ -262,7 +264,7 @@ func resourceIBMISFlowLogRead(d *schema.ResourceData, meta interface{}) error { } flowlogCollector, response, err := sess.GetFlowLogCollector(getOptions) if err != nil { - return fmt.Errorf("Error Getting Flow Log Collector: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Flow Log Collector: %s\n%s", err, response) } if flowlogCollector.Name != nil { @@ -304,25 +306,25 @@ func resourceIBMISFlowLogRead(d *schema.ResourceData, meta interface{}) error { d.Set(isFlowLogStorageBucket, *bucket.Name) } - tags, err := GetTagsUsingCRN(meta, *flowlogCollector.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *flowlogCollector.CRN) if err != nil { log.Printf( "Error on get of resource vpc flow log (%s) tags: %s", d.Id(), err) } d.Set(isFlowLogTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/flowLogs") - d.Set(ResourceName, *flowlogCollector.Name) - d.Set(ResourceCRN, *flowlogCollector.CRN) - d.Set(ResourceStatus, *flowlogCollector.LifecycleState) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/flowLogs") + d.Set(flex.ResourceName, *flowlogCollector.Name) + d.Set(flex.ResourceCRN, *flowlogCollector.CRN) + d.Set(flex.ResourceStatus, *flowlogCollector.LifecycleState) if flowlogCollector.ResourceGroup != nil { d.Set(isFlowLogResourceGroup, *flowlogCollector.ResourceGroup.ID) - d.Set(ResourceGroupName, *flowlogCollector.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *flowlogCollector.ResourceGroup.ID) } return nil @@ -342,12 +344,12 @@ func resourceIBMISFlowLogUpdate(d *schema.ResourceData, meta interface{}) error } flowlogCollector, response, err := sess.GetFlowLogCollector(getOptions) if err != nil { - return fmt.Errorf("Error Getting Flow Log Collector: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Flow Log Collector: %s\n%s", err, response) } if d.HasChange(isFlowLogTags) { oldList, newList := d.GetChange(isFlowLogTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *flowlogCollector.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *flowlogCollector.CRN) if err != nil { log.Printf( "Error on update of resource flow log (%s) tags: %s", *flowlogCollector.ID, err) @@ -366,12 +368,12 @@ func resourceIBMISFlowLogUpdate(d *schema.ResourceData, meta interface{}) error } flowLogCollectorPatch, err := flowLogCollectorPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for FlowLogCollectorPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for FlowLogCollectorPatch: %s", err) } updoptions.FlowLogCollectorPatch = flowLogCollectorPatch _, response, err = sess.UpdateFlowLogCollector(updoptions) if err != nil { - return fmt.Errorf("Error updating flow log collector:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating flow log collector:%s\n%s", err, response) } } @@ -391,7 +393,7 @@ func resourceIBMISFlowLogDelete(d *schema.ResourceData, meta interface{}) error response, err := sess.DeleteFlowLogCollector(delOptions) if err != nil && response.StatusCode != 404 { - return fmt.Errorf("Error deleting flow log collector:%s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting flow log collector:%s\n%s", err, response) } d.SetId("") @@ -411,7 +413,7 @@ func resourceIBMISFlowLogExists(d *schema.ResourceData, meta interface{}) (bool, } _, response, err := sess.GetFlowLogCollector(getOptions) if err != nil && response.StatusCode != 404 { - return false, fmt.Errorf("Error Getting Flow Log Collector : %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting Flow Log Collector : %s\n%s", err, response) } if response.StatusCode == 404 { d.SetId("") diff --git a/ibm/resource_ibm_is_flow_log_test.go b/ibm/service/vpc/resource_ibm_is_flow_log_test.go similarity index 89% rename from ibm/resource_ibm_is_flow_log_test.go rename to ibm/service/vpc/resource_ibm_is_flow_log_test.go index f24bcc901..bb1e572b3 100644 --- a/ibm/resource_ibm_is_flow_log_test.go +++ b/ibm/service/vpc/resource_ibm_is_flow_log_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" @@ -10,6 +10,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -35,12 +38,12 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE bucketRegionType := "cross_region_location" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISFlowLogDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { //Create test case Config: testAccCheckIBMISFlowLogConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, true), Check: resource.ComposeTestCheckFunc( @@ -49,7 +52,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE ), }, //update - resource.TestStep{ + { Config: testAccCheckIBMISFlowLogConfig(vpcname, name, newflowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, false), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISFlowLogExists("ibm_is_flow_log.test_flow_log", instance), @@ -120,11 +123,15 @@ func testAccCheckIBMISFlowLogConfig(vpcname, name, flowlogname, sshname, publicK active = %v } - `, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) } +func vpcClient(meta interface{}) (*vpcv1.VpcV1, error) { + sess, err := meta.(conns.ClientSession).VpcV1API() + return sess, err +} func testAccCheckIBMISFlowLogDestroy(s *terraform.State) error { - sess, err := vpcClient(testAccProvider.Meta()) + sess, err := vpcClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -153,7 +160,7 @@ func testAccCheckIBMISFlowLogExists(n string, instance string) resource.TestChec if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - sess, err := vpcClient(testAccProvider.Meta()) + sess, err := vpcClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -162,7 +169,7 @@ func testAccCheckIBMISFlowLogExists(n string, instance string) resource.TestChec } instance1, response, err := sess.GetFlowLogCollector(getOptions) if err != nil { - return fmt.Errorf("Error Getting Flow log: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Flow log: %s\n%s", err, response) } instance = *instance1.ID return nil @@ -187,18 +194,18 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE bucketRegionType := "cross_region_location" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISFlowLogDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISFlowLogConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass, false), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISFlowLogExists("ibm_is_flow_log.test_flow_log", instance), resource.TestCheckResourceAttr("ibm_is_flow_log.test_flow_log", "name", flowlogname), ), }, - resource.TestStep{ + { ResourceName: "ibm_is_flow_log.test_flow_log", ImportState: true, ImportStateVerify: true, diff --git a/ibm/resource_ibm_is_ike_policy.go b/ibm/service/vpc/resource_ibm_is_ike_policy.go similarity index 79% rename from ibm/resource_ibm_is_ike_policy.go rename to ibm/service/vpc/resource_ibm_is_ike_policy.go index c58f1ec4a..99c5c40ac 100644 --- a/ibm/resource_ibm_is_ike_policy.go +++ b/ibm/service/vpc/resource_ibm_is_ike_policy.go @@ -1,12 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -27,7 +29,7 @@ const ( isIKEHref = "href" ) -func resourceIBMISIKEPolicy() *schema.Resource { +func ResourceIBMISIKEPolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMISIKEPolicyCreate, Read: resourceIBMISIKEPolicyRead, @@ -40,28 +42,28 @@ func resourceIBMISIKEPolicy() *schema.Resource { isIKEName: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ike_policy", isIKEName), + ValidateFunc: validate.InvokeValidator("ibm_is_ike_policy", isIKEName), Description: "IKE name", }, isIKEAuthenticationAlg: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ike_policy", isIKEAuthenticationAlg), + ValidateFunc: validate.InvokeValidator("ibm_is_ike_policy", isIKEAuthenticationAlg), Description: "Authentication algorithm type", }, isIKEEncryptionAlg: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ike_policy", isIKEEncryptionAlg), + ValidateFunc: validate.InvokeValidator("ibm_is_ike_policy", isIKEEncryptionAlg), Description: "Encryption alogorithm type", }, isIKEDhGroup: { Type: schema.TypeInt, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ike_policy", isIKEDhGroup), + ValidateFunc: validate.InvokeValidator("ibm_is_ike_policy", isIKEDhGroup), Description: "IKE DH group", }, @@ -77,14 +79,14 @@ func resourceIBMISIKEPolicy() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 28800, - ValidateFunc: validateKeyLifeTime, + ValidateFunc: validate.ValidateKeyLifeTime, Description: "IKE Key lifetime", }, isIKEVERSION: { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_ike_policy", isIKEVERSION), + ValidateFunc: validate.InvokeValidator("ibm_is_ike_policy", isIKEVERSION), Description: "IKE version", }, @@ -120,18 +122,18 @@ func resourceIBMISIKEPolicy() *schema.Resource { }, }, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -140,52 +142,52 @@ func resourceIBMISIKEPolicy() *schema.Resource { } } -func resourceIBMISIKEValidator() *ResourceValidator { +func ResourceIBMISIKEValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - authentication_algorithm := "md5, sha1, sha256, sha512" - encryption_algorithm := "triple_des, aes128, aes256" - dh_group := "2, 5, 14, 19" + validateSchema := make([]validate.ValidateSchema, 0) + authentication_algorithm := "md5, sha1, sha256, sha512, sha384" + encryption_algorithm := "triple_des, aes128, aes192, aes256" + dh_group := "2, 5, 14, 19, 15, 16, 17, 18, 20, 21, 22, 23, 24, 31" ike_version := "1, 2" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIKEName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIKEAuthenticationAlg, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: authentication_algorithm}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIKEEncryptionAlg, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: encryption_algorithm}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIKEDhGroup, - ValidateFunctionIdentifier: ValidateAllowedIntValue, - Type: TypeInt, + ValidateFunctionIdentifier: validate.ValidateAllowedIntValue, + Type: validate.TypeInt, Required: true, AllowedValues: dh_group}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIKEVERSION, - ValidateFunctionIdentifier: ValidateAllowedIntValue, - Type: TypeInt, + ValidateFunctionIdentifier: validate.ValidateAllowedIntValue, + Type: validate.TypeInt, Optional: true, AllowedValues: ike_version}) - ibmISIKEResourceValidator := ResourceValidator{ResourceName: "ibm_is_ike_policy", Schema: validateSchema} + ibmISIKEResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_ike_policy", Schema: validateSchema} return &ibmISIKEResourceValidator } @@ -264,7 +266,7 @@ func ikepGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting IKE Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting IKE Policy(%s): %s\n%s", id, err, response) } d.Set(isIKEName, *ike.Name) @@ -272,7 +274,7 @@ func ikepGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isIKEEncryptionAlg, *ike.EncryptionAlgorithm) if ike.ResourceGroup != nil { d.Set(isIKEResourceGroup, *ike.ResourceGroup.ID) - d.Set(ResourceGroupName, *ike.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *ike.ResourceGroup.Name) } else { d.Set(isIKEResourceGroup, nil) } @@ -294,12 +296,12 @@ func ikepGet(d *schema.ResourceData, meta interface{}, id string) error { } } d.Set(isIKEVPNConnections, connList) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/ikepolicies") - d.Set(ResourceName, *ike.Name) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/ikepolicies") + d.Set(flex.ResourceName, *ike.Name) return nil } @@ -338,13 +340,13 @@ func ikepUpdate(d *schema.ResourceData, meta interface{}, id string) error { ikePolicyPatchModel.IkeVersion = &ikeVersion ikePolicyPatch, err := ikePolicyPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for IkePolicyPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for IkePolicyPatch: %s", err) } options.IkePolicyPatch = ikePolicyPatch _, response, err := sess.UpdateIkePolicy(options) if err != nil { - return fmt.Errorf("Error on update of IKE Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error on update of IKE Policy(%s): %s\n%s", id, err, response) } } return nil @@ -370,7 +372,7 @@ func ikepDelete(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting IKE Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting IKE Policy(%s): %s\n%s", id, err, response) } deleteIkePolicyOptions := &vpcv1.DeleteIkePolicyOptions{ @@ -378,7 +380,7 @@ func ikepDelete(d *schema.ResourceData, meta interface{}, id string) error { } response, err = sess.DeleteIkePolicy(deleteIkePolicyOptions) if err != nil { - return fmt.Errorf("Error Deleting IKE Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Deleting IKE Policy(%s): %s\n%s", id, err, response) } d.SetId("") return nil @@ -403,7 +405,7 @@ func ikepExists(d *schema.ResourceData, meta interface{}, id string) (bool, erro if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting IKE Policy(%s): %s\n%s", id, err, response) + return false, fmt.Errorf("[ERROR] Error getting IKE Policy(%s): %s\n%s", id, err, response) } return true, nil diff --git a/ibm/resource_ibm_is_ike_policy_test.go b/ibm/service/vpc/resource_ibm_is_ike_policy_test.go similarity index 83% rename from ibm/resource_ibm_is_ike_policy_test.go rename to ibm/service/vpc/resource_ibm_is_ike_policy_test.go index bf26d5e35..8f8a93f77 100644 --- a/ibm/resource_ibm_is_ike_policy_test.go +++ b/ibm/service/vpc/resource_ibm_is_ike_policy_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,11 +20,11 @@ import ( func TestAccIBMISIKEPolicy_basic(t *testing.T) { name := fmt.Sprintf("tfike-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkIKEPolicyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISIKEPolicyConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -42,11 +45,11 @@ func TestAccIBMISIKEPolicy_basic(t *testing.T) { resource.TestCheckResourceAttr( "ibm_is_ike_policy.example", "name", name), resource.TestCheckResourceAttr( - "ibm_is_ike_policy.example", "authentication_algorithm", "sha1"), + "ibm_is_ike_policy.example", "authentication_algorithm", "sha384"), resource.TestCheckResourceAttr( - "ibm_is_ike_policy.example", "encryption_algorithm", "aes128"), + "ibm_is_ike_policy.example", "encryption_algorithm", "aes256"), resource.TestCheckResourceAttr( - "ibm_is_ike_policy.example", "dh_group", "5"), + "ibm_is_ike_policy.example", "dh_group", "15"), resource.TestCheckResourceAttr( "ibm_is_ike_policy.example", "ike_version", "2"), ), @@ -57,7 +60,7 @@ func TestAccIBMISIKEPolicy_basic(t *testing.T) { func checkIKEPolicyDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_ike_policy" { continue @@ -87,7 +90,7 @@ func testAccCheckIBMISIKEPolicyExists(n, policy string) resource.TestCheckFunc { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getikepoptions := &vpcv1.GetIkePolicyOptions{ ID: &rs.Primary.ID, } @@ -116,9 +119,9 @@ func testAccCheckIBMISIKEPolicyConfigUpdate(name string) string { return fmt.Sprintf(` resource "ibm_is_ike_policy" "example" { name = "%s" - authentication_algorithm = "sha1" - encryption_algorithm = "aes128" - dh_group = 5 + authentication_algorithm = "sha384" + encryption_algorithm = "aes256" + dh_group = 15 ike_version = 2 key_lifetime = 1800 } diff --git a/ibm/resource_ibm_is_image.go b/ibm/service/vpc/resource_ibm_is_image.go similarity index 85% rename from ibm/resource_ibm_is_image.go rename to ibm/service/vpc/resource_ibm_is_image.go index bea447aed..fe7ce15b9 100644 --- a/ibm/resource_ibm_is_image.go +++ b/ibm/service/vpc/resource_ibm_is_image.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -10,6 +10,8 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -40,7 +42,7 @@ const ( isImageDeleted = "done" ) -func resourceIBMISImage() *schema.Resource { +func ResourceIBMISImage() *schema.Resource { return &schema.Resource{ Create: resourceIBMISImageCreate, Read: resourceIBMISImageRead, @@ -57,7 +59,7 @@ func resourceIBMISImage() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -66,7 +68,7 @@ func resourceIBMISImage() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, RequiredWith: []string{isImageOperatingSystem}, ExactlyOneOf: []string{isImageHref, isImageVolume}, Description: "Image Href value", @@ -76,7 +78,7 @@ func resourceIBMISImage() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_image", isImageName), + ValidateFunc: validate.InvokeValidator("ibm_is_image", isImageName), Description: "Image name", }, @@ -96,8 +98,8 @@ func resourceIBMISImage() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_image", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_image", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "Tags for the image", }, @@ -155,19 +157,19 @@ func resourceIBMISImage() *schema.Resource { Description: "The resource group for this image", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", @@ -185,13 +187,13 @@ func resourceIBMISImage() *schema.Resource { Description: "The SHA256 checksum of this image", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -200,28 +202,28 @@ func resourceIBMISImage() *schema.Resource { } } -func resourceIBMISImageValidator() *ResourceValidator { +func ResourceIBMISImageValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isImageName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISImageResourceValidator := ResourceValidator{ResourceName: "ibm_is_image", Schema: validateSchema} + ibmISImageResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_image", Schema: validateSchema} return &ibmISImageResourceValidator } @@ -295,7 +297,7 @@ func imgCreateByFile(d *schema.ResourceData, meta interface{}, href, name, opera v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isImageTags); ok || v != "" { oldList, newList := d.GetChange(isImageTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) if err != nil { log.Printf( "Error on create of resource vpc Image (%s) tags: %s", d.Id(), err) @@ -320,10 +322,10 @@ func imgCreateByVolume(d *schema.ResourceData, meta interface{}, name, volume st } vol, response, err := sess.GetVolume(options) if err != nil || vol == nil { - return fmt.Errorf("Error retrieving Volume (%s) details: %s\n%s", volume, err, response) + return fmt.Errorf("[ERROR] Error retrieving Volume (%s) details: %s\n%s", volume, err, response) } if vol.VolumeAttachments == nil { - return fmt.Errorf("Error creating Image because the specified source_volume %s is not attached to a virtual server instance ", volume) + return fmt.Errorf("[ERROR] Error creating Image because the specified source_volume %s is not attached to a virtual server instance ", volume) } volAtt := &vol.VolumeAttachments[0] insId = *volAtt.Instance.ID @@ -332,7 +334,7 @@ func imgCreateByVolume(d *schema.ResourceData, meta interface{}, name, volume st } instance, response, err := sess.GetInstance(getinsOptions) if err != nil || instance == nil { - return fmt.Errorf("Error retrieving Instance (%s) to which the source_volume (%s) is attached : %s\n%s", insId, volume, err, response) + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the source_volume (%s) is attached : %s\n%s", insId, volume, err, response) } if instance != nil && *instance.Status == "running" { actiontype := "stop" @@ -342,7 +344,7 @@ func imgCreateByVolume(d *schema.ResourceData, meta interface{}, name, volume st } _, response, err = sess.CreateInstanceAction(createinsactoptions) if err != nil { - return fmt.Errorf("Error stopping Instance (%s) to which the source_volume (%s) is attached : %s\n%s", insId, volume, err, response) + return fmt.Errorf("[ERROR] Error stopping Instance (%s) to which the source_volume (%s) is attached : %s\n%s", insId, volume, err, response) } _, err = isWaitForInstanceActionStop(sess, d.Timeout(schema.TimeoutCreate), insId, d) if err != nil { @@ -384,7 +386,7 @@ func imgCreateByVolume(d *schema.ResourceData, meta interface{}, name, volume st v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isImageTags); ok || v != "" { oldList, newList := d.GetChange(isImageTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) if err != nil { log.Printf( "Error on create of resource vpc Image (%s) tags: %s", d.Id(), err) @@ -414,7 +416,7 @@ func isImageRefreshFunc(imageC *vpcv1.VpcV1, id string) resource.StateRefreshFun } image, response, err := imageC.GetImage(getimgoptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Image: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Image: %s\n%s", err, response) } if *image.Status == "available" || *image.Status == "failed" { @@ -454,10 +456,10 @@ func imgUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } image, response, err := sess.GetImage(options) if err != nil { - return fmt.Errorf("Error getting Image IP: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Image IP: %s\n%s", err, response) } oldList, newList := d.GetChange(isImageTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *image.CRN) if err != nil { log.Printf( "Error on update of resource vpc Image (%s) tags: %s", id, err) @@ -472,12 +474,12 @@ func imgUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } imagePatch, err := imagePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for ImagePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for ImagePatch: %s", err) } options.ImagePatch = imagePatch _, response, err := sess.UpdateImage(options) if err != nil { - return fmt.Errorf("Error on update of resource vpc Image: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error on update of resource vpc Image: %s\n%s", err, response) } } return nil @@ -507,7 +509,7 @@ func imgGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting Image (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Image (%s): %s\n%s", id, err, response) } // d.Set(isImageArchitecure, image.Architecture) if image.MinimumProvisionedSize != nil { @@ -541,20 +543,20 @@ func imgGet(d *schema.ResourceData, meta interface{}, id string) error { if image.File != nil && image.File.Checksums != nil { d.Set(isImageCheckSum, *image.File.Checksums.Sha256) } - tags, err := GetTagsUsingCRN(meta, *image.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *image.CRN) if err != nil { log.Printf( "Error on get of resource vpc Image (%s) tags: %s", d.Id(), err) } d.Set(isImageTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/compute/image") - d.Set(ResourceName, *image.Name) - d.Set(ResourceStatus, *image.Status) - d.Set(ResourceCRN, *image.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/image") + d.Set(flex.ResourceName, *image.Name) + d.Set(flex.ResourceStatus, *image.Status) + d.Set(flex.ResourceCRN, *image.CRN) d.Set(IsImageCRN, *image.CRN) if image.ResourceGroup != nil { d.Set(isImageResourceGroup, *image.ResourceGroup.ID) @@ -585,7 +587,7 @@ func imgDelete(d *schema.ResourceData, meta interface{}, id string) error { if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Getting Image (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Image (%s): %s\n%s", id, err, response) } options := &vpcv1.DeleteImageOptions{ @@ -593,7 +595,7 @@ func imgDelete(d *schema.ResourceData, meta interface{}, id string) error { } response, err = sess.DeleteImage(options) if err != nil { - return fmt.Errorf("Error Deleting Image : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Image : %s\n%s", err, response) } _, err = isWaitForImageDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -620,7 +622,7 @@ func isWaitForImageDeleted(imageC *vpcv1.VpcV1, id string, timeout time.Duration func isImageDeleteRefreshFunc(imageC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] is image delete function here") getimgoptions := &vpcv1.GetImageOptions{ ID: &id, } @@ -629,7 +631,7 @@ func isImageDeleteRefreshFunc(imageC *vpcv1.VpcV1, id string) resource.StateRefr if response != nil && response.StatusCode == 404 { return image, isImageDeleted, nil } - return image, "", fmt.Errorf("Error Getting Image: %s\n%s", err, response) + return image, "", fmt.Errorf("[ERROR] Error Getting Image: %s\n%s", err, response) } return image, isImageDeleting, err } @@ -653,7 +655,7 @@ func imgExists(d *schema.ResourceData, meta interface{}, id string) (bool, error if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Image: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Image: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_image_test.go b/ibm/service/vpc/resource_ibm_is_image_test.go similarity index 84% rename from ibm/resource_ibm_is_image_test.go rename to ibm/service/vpc/resource_ibm_is_image_test.go index c3f2ccef2..0880e0743 100644 --- a/ibm/resource_ibm_is_image_test.go +++ b/ibm/service/vpc/resource_ibm_is_image_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,11 +23,11 @@ func TestAccIBMISImage_basic(t *testing.T) { name := fmt.Sprintf("tfimg-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckImage(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckImage(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkImageDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISImageConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISImageExists("ibm_is_image.isExampleImage", image), @@ -48,11 +51,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE name := fmt.Sprintf("tfimg-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckImage(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckImage(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkImageDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISImageConfig1(vpcname, subnetname, sshname, publicKey, instanceName, name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISImageExists("ibm_is_image.isExampleImageFromVolume", image), @@ -68,11 +71,11 @@ func TestAccIBMISImage_encrypted(t *testing.T) { var image string name := fmt.Sprintf("tfimg-enc-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheckEncryptedImage(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheckEncryptedImage(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkImageDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISImageEncryptedConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISImageExists("ibm_is_image.isExampleImageEncrypted", image), @@ -85,7 +88,7 @@ func TestAccIBMISImage_encrypted(t *testing.T) { } func checkImageDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_image" { continue @@ -115,7 +118,7 @@ func testAccCheckIBMISImageExists(n, image string) resource.TestCheckFunc { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getimgoptions := &vpcv1.GetImageOptions{ ID: &rs.Primary.ID, } @@ -136,7 +139,7 @@ func testAccCheckIBMISImageConfig(name string) string { name = "%s" operating_system = "%s" } - `, image_cos_url, name, image_operating_system) + `, acc.Image_cos_url, name, acc.Image_operating_system) } func testAccCheckIBMISImageConfig1(vpcname, subnetname, sshname, publicKey, instanceName, name string) string { return fmt.Sprintf(` @@ -178,7 +181,7 @@ func testAccCheckIBMISImageConfig1(vpcname, subnetname, sshname, publicKey, inst timeouts { create = "45m" } - }`, vpcname, subnetname, ISZoneName, sshname, publicKey, instanceName, isImage, instanceProfileName, ISZoneName, name) + }`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, instanceName, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, name) } func testAccCheckIBMISImageEncryptedConfig(name string) string { @@ -190,5 +193,5 @@ func testAccCheckIBMISImageEncryptedConfig(name string) string { name = "%s" operating_system = "%s" } - `, IsImageEncryptedDataKey, IsImageEncryptionKey, image_cos_url_encrypted, name, image_operating_system) + `, acc.IsImageEncryptedDataKey, acc.IsImageEncryptionKey, acc.Image_cos_url_encrypted, name, acc.Image_operating_system) } diff --git a/ibm/service/vpc/resource_ibm_is_instance.go b/ibm/service/vpc/resource_ibm_is_instance.go new file mode 100644 index 000000000..db35839d0 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance.go @@ -0,0 +1,3978 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceName = "name" + IsInstanceCRN = "crn" + isInstanceKeys = "keys" + isInstanceTags = "tags" + isInstanceBootVolumeTags = "tags" + isInstanceNetworkInterfaces = "network_interfaces" + isInstancePrimaryNetworkInterface = "primary_network_interface" + isInstanceNicName = "name" + isInstanceProfile = "profile" + isInstanceNicPortSpeed = "port_speed" + isInstanceNicAllowIPSpoofing = "allow_ip_spoofing" + isInstanceNicPrimaryIpv4Address = "primary_ipv4_address" + isInstanceNicSecondaryAddress = "secondary_addresses" + isInstanceNicSecurityGroups = "security_groups" + isInstanceNicSubnet = "subnet" + isInstanceNicFloatingIP = "floating_ip" + isInstanceNicFloatingIPs = "floating_ips" + isInstanceUserData = "user_data" + isInstanceVolumes = "volumes" + isInstanceVPC = "vpc" + isInstanceZone = "zone" + isInstanceBootVolume = "boot_volume" + isInstanceVolumeSnapshot = "snapshot" + isInstanceSourceTemplate = "instance_template" + isInstanceBandwidth = "bandwidth" + isInstanceTotalVolumeBandwidth = "total_volume_bandwidth" + isInstanceTotalNetworkBandwidth = "total_network_bandwidth" + isInstanceVolAttVolAutoDelete = "auto_delete_volume" + isInstanceVolAttVolBillingTerm = "billing_term" + isInstanceImage = "image" + isInstanceCPU = "vcpu" + isInstanceCPUArch = "architecture" + isInstanceCPUCores = "cores" + isInstanceCPUCount = "count" + isInstanceGpu = "gpu" + isInstanceGpuCores = "cores" + isInstanceGpuCount = "count" + isInstanceGpuManufacturer = "manufacturer" + isInstanceGpuMemory = "memory" + isInstanceGpuModel = "model" + isInstanceMemory = "memory" + isInstanceDisks = "disks" + isInstanceDedicatedHost = "dedicated_host" + isInstanceStatus = "status" + isInstanceStatusReasons = "status_reasons" + isInstanceStatusReasonsCode = "code" + isInstanceStatusReasonsMessage = "message" + isInstanceStatusReasonsMoreInfo = "more_info" + isEnableCleanDelete = "wait_before_delete" + isInstanceProvisioning = "provisioning" + isInstanceProvisioningDone = "done" + isInstanceAvailable = "available" + isInstanceDeleting = "deleting" + isInstanceDeleteDone = "done" + isInstanceFailed = "failed" + + isInstanceStatusRestarting = "restarting" + isInstanceStatusStarting = "starting" + isInstanceActionStatusStopping = "stopping" + isInstanceActionStatusStopped = "stopped" + isInstanceStatusPending = "pending" + isInstanceStatusRunning = "running" + isInstanceStatusFailed = "failed" + isInstanceAvailablePolicyHostFailure = "availability_policy_host_failure" + + isInstanceBootAttachmentName = "name" + isInstanceBootVolumeId = "volume_id" + isInstanceBootSize = "size" + isInstanceBootIOPS = "iops" + isInstanceBootEncryption = "encryption" + isInstanceBootProfile = "profile" + isInstanceAction = "action" + isInstanceVolumeAttachments = "volume_attachments" + isInstanceVolumeAttaching = "attaching" + isInstanceVolumeAttached = "attached" + isInstanceVolumeDetaching = "detaching" + isInstanceResourceGroup = "resource_group" + isInstanceLifecycleReasons = "lifecycle_reasons" + isInstanceLifecycleState = "lifecycle_state" + isInstanceLifecycleReasonsCode = "code" + isInstanceLifecycleReasonsMessage = "message" + isInstanceLifecycleReasonsMoreInfo = "more_info" + + isInstanceCatalogOffering = "catalog_offering" + isInstanceCatalogOfferingOfferingCrn = "offering_crn" + isInstanceCatalogOfferingVersionCrn = "version_crn" + + isPlacementTargetDedicatedHost = "dedicated_host" + isPlacementTargetDedicatedHostGroup = "dedicated_host_group" + isInstancePlacementTarget = "placement_target" + isPlacementTargetPlacementGroup = "placement_group" + + isInstanceDefaultTrustedProfileAutoLink = "default_trusted_profile_auto_link" + isInstanceDefaultTrustedProfileTarget = "default_trusted_profile_target" + isInstanceMetadataServiceEnabled = "metadata_service_enabled" +) + +func ResourceIBMISInstance() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMisInstanceCreate, + Read: resourceIBMisInstanceRead, + Update: resourceIBMisInstanceUpdate, + Delete: resourceIBMisInstanceDelete, + Exists: resourceIBMisInstanceExists, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) (result []*schema.ResourceData, err error) { + log.Printf("[INFO] Instance (%s) importing", d.Id()) + id := d.Id() + instanceC, err := vpcClient(meta) + if err != nil { + return nil, err + } + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil, nil + } + return nil, fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + var volumes []string + volumes = make([]string, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + if volume.Volume != nil && *volume.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { + volumes = append(volumes, *volume.Volume.ID) + } + } + } + d.Set(isInstanceVolumes, flex.NewStringSet(schema.HashString, volumes)) + return []*schema.ResourceData{d}, nil + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.InstanceProfileValidate(diff) + }), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }), + ), + + Schema: map[string]*schema.Schema{ + isInstanceAvailablePolicyHostFailure: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The availability policy to use for this virtual server instance", + }, + + isInstanceName: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_instance", isInstanceName), + Description: "Instance name", + }, + isInstanceVPC: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + Description: "VPC id", + }, + IsInstanceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "Crn for this Instance", + }, + + isInstanceSourceTemplate: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, + ConflictsWith: []string{"boot_volume.0.snapshot"}, + Description: "Id of the instance template", + }, + isInstanceZone: { + Type: schema.TypeString, + ForceNew: true, + Computed: true, + Optional: true, + Description: "Zone name", + }, + + isInstanceProfile: { + Type: schema.TypeString, + ForceNew: false, + Computed: true, + Optional: true, + Description: "Profile info", + }, + isInstanceDefaultTrustedProfileAutoLink: { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Computed: true, + RequiredWith: []string{isInstanceDefaultTrustedProfileTarget}, + Description: "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + }, + isInstanceDefaultTrustedProfileTarget: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + }, + isPlacementTargetDedicatedHost: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{isPlacementTargetDedicatedHostGroup, isPlacementTargetPlacementGroup}, + Description: "Unique Identifier of the Dedicated Host where the instance will be placed", + }, + + isPlacementTargetDedicatedHostGroup: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetPlacementGroup}, + Description: "Unique Identifier of the Dedicated Host Group where the instance will be placed", + }, + + isPlacementTargetPlacementGroup: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetDedicatedHostGroup}, + Description: "Unique Identifier of the Placement Group for restricting the placement of the instance", + }, + + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance", isInstanceTotalVolumeBandwidth), + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + + isInstanceBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + }, + + isInstanceTotalNetworkBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + }, + + isInstanceKeys: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + DiffSuppressFunc: flex.ApplyOnce, + Description: "SSH key Ids for the instance", + }, + + isInstanceTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "list of tags for the instance", + }, + + isEnableCleanDelete: { + Type: schema.TypeBool, + Optional: true, + Default: true, + DiffSuppressFunc: suppressEnableCleanDelete, + Description: "Enables stopping of instance before deleting and waits till deletion is complete", + }, + + isInstanceAction: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance", isInstanceAction), + Description: "Enables stopping of instance before deleting and waits till deletion is complete", + }, + + isInstanceActionForce: { + Type: schema.TypeBool, + Optional: true, + RequiredWith: []string{isInstanceAction}, + Default: false, + Description: "If set to true, the action will be forced immediately, and all queued actions deleted. Ignored for the start action.", + }, + + isInstanceVolumeAttachments: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + }, + "volume_name": { + Type: schema.TypeString, + Computed: true, + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + isInstanceCatalogOffering: { + Type: schema.TypeList, + MinItems: 0, + MaxItems: 1, + Optional: true, + ForceNew: true, + Description: "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceCatalogOfferingOfferingCrn: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"catalog_offering.0.version_crn"}, + RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile}, + Description: "Identifies a catalog offering by a unique CRN property", + }, + isInstanceCatalogOfferingVersionCrn: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"catalog_offering.0.offering_crn"}, + RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile}, + Description: "Identifies a version of a catalog offering by a unique CRN property", + }, + }, + }, + }, + + isInstancePrimaryNetworkInterface: { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isInstanceNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isInstanceNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceNicPortSpeed: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + Deprecated: "This field is deprected", + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.address"}, + Deprecated: "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + MinItems: 0, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Optional: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ipv4_address"}, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ipv4_address", "primary_network_interface.0.primary_ip.0.address"}, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + isInstanceNetworkInterfaces: { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + isInstanceNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether IP spoofing is allowed on this interface.", + }, + isInstanceNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceNicPrimaryIpv4Address: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Deprecated: "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead", + Computed: true, + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + MinItems: 0, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Optional: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + isInstanceUserData: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "User data given for the instance", + }, + + isInstanceImage: { + Type: schema.TypeString, + ForceNew: true, + Computed: true, + Optional: true, + ConflictsWith: []string{"boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, + AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, + RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile}, + Description: "image id", + }, + + isInstanceBootVolume: { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceBootAttachmentName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance", isInstanceBootAttachmentName), + }, + + isInstanceBootVolumeId: { + Type: schema.TypeString, + Computed: true, + }, + + isInstanceVolumeSnapshot: { + Type: schema.TypeString, + RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceProfile, isInstanceKeys, isInstanceVPC}, + AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, + ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, + Optional: true, + ForceNew: true, + }, + isInstanceBootEncryption: { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: flex.ApplyOnce, + Computed: true, + }, + isInstanceBootSize: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance", isInstanceBootSize), + }, + isInstanceBootIOPS: { + Type: schema.TypeInt, + Computed: true, + }, + isInstanceBootProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceBootVolumeTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + }, + }, + }, + + isInstanceVolumes: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of volumes", + }, + + isInstanceVolAttVolAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Description: "Auto delete volume along with instance", + }, + + isInstanceResourceGroup: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + Description: "Instance resource group", + }, + + isInstanceCPU: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceCPUArch: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceCPUCount: { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + isInstanceGpu: { + Type: schema.TypeList, + Computed: true, + Description: "The virtual server instance GPU configuration", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceGpuCount: { + Type: schema.TypeInt, + Computed: true, + Description: "The number of GPUs assigned to the instance", + }, + isInstanceGpuMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "The overall amount of GPU memory in GiB (gibibytes)", + }, + isInstanceGpuManufacturer: { + Type: schema.TypeString, + Computed: true, + Description: "The GPU manufacturer", + }, + isInstanceGpuModel: { + Type: schema.TypeString, + Computed: true, + Description: "The GPU model", + }, + }, + }, + }, + + isInstanceMemory: { + Type: schema.TypeInt, + Computed: true, + Description: "Instance memory", + }, + + isInstanceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "instance status", + }, + isInstanceStatusReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isInstanceStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isInstanceStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + isInstanceLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the virtual server instance.", + }, + isInstanceLifecycleReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current lifecycle_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceLifecycleReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + + isInstanceLifecycleReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + isInstanceMetadataServiceEnabled: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + "force_recovery_time": { + Description: "Define timeout to force the instances to start/stop in minutes.", + Type: schema.TypeInt, + Optional: true, + }, + isInstanceDisks: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of the instance's disks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the disk was created.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance disk.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance disk.", + }, + "interface_type": { + Type: schema.TypeString, + Computed: true, + Description: "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this disk.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "size": { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes).", + }, + }, + }, + }, + isInstancePlacementTarget: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this placement target.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this placement target.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this placement target.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this placement target.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISInstanceValidator() *validate.ResourceValidator { + actions := "stop, start, reboot" + host_failure := "restart, stop" + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceTotalVolumeBandwidth, + ValidateFunctionIdentifier: validate.IntAtLeast, + Type: validate.TypeInt, + Optional: true, + MinValue: "500"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceBootSize, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "250"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: actions}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceBootAttachmentName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceAvailablePolicyHostFailure, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: host_failure}) + + ibmISInstanceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance", Schema: validateSchema} + return &ibmISInstanceValidator +} + +func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + instanceproto := &vpcv1.InstancePrototype{ + Image: &vpcv1.ImageIdentity{ + ID: &image, + }, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.InstanceProfileIdentity{ + Name: &profile, + }, + Name: &name, + VPC: &vpcv1.VPCIdentity{ + ID: &vpcID, + }, + } + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + if availablePolicyItem, ok := d.GetOk(isInstanceAvailablePolicyHostFailure); ok { + hostFailure := availablePolicyItem.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPrototype{ + HostFailure: &hostFailure, + } + } + + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + + if boot, ok := d.GetOk(isInstanceBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + name, ok := bootvol[isInstanceBootAttachmentName] + namestr := name.(string) + if namestr != "" && ok { + volTemplate.Name = &namestr + } + sizeOk, ok := bootvol[isInstanceBootSize] + size := sizeOk.(int) + if size != 0 && ok { + sizeInt64 := int64(size) + volTemplate.Capacity = &sizeInt64 + } + enc, ok := bootvol[isInstanceBootEncryption] + encstr := enc.(string) + if ok && encstr != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encstr, + } + } + + volprof := "general-purpose" + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + var userTags *schema.Set + if v, ok := bootvol[isInstanceBootVolumeTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volTemplate.UserTags = userTagsArray + } + } + deletebool := true + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + DeleteVolumeOnInstanceDelete: &deletebool, + Volume: volTemplate, + } + + } + + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := primnic[isInstanceNicName] + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := primnic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + + allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := primnic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, ok := nic[isInstanceNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := nic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + keySet := d.Get(isInstanceKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + if userdata, ok := d.GetOk(isInstanceUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + if grp, ok := d.GetOk(isInstanceResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + + metadataServiceEnabled := d.Get(isInstanceMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + + options := &vpcv1.CreateInstanceOptions{ + InstancePrototype: instanceproto, + } + + instance, response, err := sess.CreateInstance(options) + if err != nil { + log.Printf("[DEBUG] Instance err %s\n%s", err, response) + return err + } + d.SetId(*instance.ID) + + log.Printf("[INFO] Instance : %s", *instance.ID) + d.Set(isInstanceStatus, instance.Status) + + _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isInstanceTags); ok || v != "" { + oldList, newList := d.GetChange(isInstanceTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + return nil +} +func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image, offerringCrn, versionCrn string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + instanceproto := &vpcv1.InstancePrototypeInstanceByCatalogOffering{ + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.InstanceProfileIdentity{ + Name: &profile, + }, + Name: &name, + VPC: &vpcv1.VPCIdentity{ + ID: &vpcID, + }, + } + if offerringCrn != "" { + catalogOffering := &vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN{ + CRN: &offerringCrn, + } + offeringPrototype := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering{ + Offering: catalogOffering, + } + instanceproto.CatalogOffering = offeringPrototype + } + if versionCrn != "" { + versionOffering := &vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN{ + CRN: &versionCrn, + } + versionPrototype := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion{ + Version: versionOffering, + } + instanceproto.CatalogOffering = versionPrototype + } + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + if availablePolicyItem, ok := d.GetOk(isInstanceAvailablePolicyHostFailure); ok { + hostFailure := availablePolicyItem.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPrototype{ + HostFailure: &hostFailure, + } + } + + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + + if boot, ok := d.GetOk(isInstanceBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + name, ok := bootvol[isInstanceBootAttachmentName] + namestr := name.(string) + if namestr != "" && ok { + volTemplate.Name = &namestr + } + sizeOk, ok := bootvol[isInstanceBootSize] + size := sizeOk.(int) + if size != 0 && ok { + sizeInt64 := int64(size) + volTemplate.Capacity = &sizeInt64 + } + enc, ok := bootvol[isInstanceBootEncryption] + encstr := enc.(string) + if ok && encstr != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encstr, + } + } + + volprof := "general-purpose" + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + deletebool := true + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + DeleteVolumeOnInstanceDelete: &deletebool, + Volume: volTemplate, + } + + } + + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := primnic[isInstanceNicName] + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := primnic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + + allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := primnic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, ok := nic[isInstanceNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := nic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + keySet := d.Get(isInstanceKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + if userdata, ok := d.GetOk(isInstanceUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + if grp, ok := d.GetOk(isInstanceResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + + metadataServiceEnabled := d.Get(isInstanceMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + + options := &vpcv1.CreateInstanceOptions{ + InstancePrototype: instanceproto, + } + + instance, response, err := sess.CreateInstance(options) + if err != nil { + log.Printf("[DEBUG] Instance err %s\n%s", err, response) + return err + } + d.SetId(*instance.ID) + + log.Printf("[INFO] Instance : %s", *instance.ID) + d.Set(isInstanceStatus, instance.Status) + + _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isInstanceTags); ok || v != "" { + oldList, newList := d.GetChange(isInstanceTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image, template string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + instanceproto := &vpcv1.InstancePrototypeInstanceBySourceTemplate{ + SourceTemplate: &vpcv1.InstanceTemplateIdentity{ + ID: &template, + }, + Name: &name, + } + + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + if profile != "" { + instanceproto.Profile = &vpcv1.InstanceProfileIdentity{ + Name: &profile, + } + } + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + + if vpcID != "" { + instanceproto.VPC = &vpcv1.VPCIdentity{ + ID: &vpcID, + } + } + if zone != "" { + instanceproto.Zone = &vpcv1.ZoneIdentity{ + Name: &zone, + } + } + + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + if availablePolicyItem, ok := d.GetOk(isInstanceAvailablePolicyHostFailure); ok { + hostFailure := availablePolicyItem.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPrototype{ + HostFailure: &hostFailure, + } + } + if boot, ok := d.GetOk(isInstanceBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + name, ok := bootvol[isInstanceBootAttachmentName] + namestr := name.(string) + if namestr != "" && ok { + volTemplate.Name = &namestr + } + sizeOk, ok := bootvol[isInstanceBootSize] + size := sizeOk.(int) + if size != 0 && ok { + sizeInt64 := int64(size) + volTemplate.Capacity = &sizeInt64 + } + enc, ok := bootvol[isInstanceBootEncryption] + encstr := enc.(string) + if ok && encstr != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encstr, + } + } + + volprof := "general-purpose" + + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + var userTags *schema.Set + if v, ok := bootvol[isInstanceBootVolumeTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volTemplate.UserTags = userTagsArray + } + } + deletebool := true + + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + DeleteVolumeOnInstanceDelete: &deletebool, + Volume: volTemplate, + } + } + + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := primnic[isInstanceNicName] + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := primnic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := primnic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, ok := nic[isInstanceNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := nic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + keySet := d.Get(isInstanceKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + if userdata, ok := d.GetOk(isInstanceUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + if grp, ok := d.GetOk(isInstanceResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + + if metadataServiceEnabled, ok := d.GetOkExists(isInstanceMetadataServiceEnabled); ok { + metadataServiceEnabledBool := metadataServiceEnabled.(bool) + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabledBool, + } + } + + options := &vpcv1.CreateInstanceOptions{ + InstancePrototype: instanceproto, + } + + instance, response, err := sess.CreateInstance(options) + if err != nil { + log.Printf("[DEBUG] Instance err %s\n%s", err, response) + return err + } + d.SetId(*instance.ID) + + log.Printf("[INFO] Instance : %s", *instance.ID) + d.Set(isInstanceStatus, instance.Status) + + if instance.MetadataService != nil { + d.Set(isInstanceMetadataServiceEnabled, instance.MetadataService.Enabled) + } + + _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isInstanceTags); ok || v != "" { + oldList, newList := d.GetChange(isInstanceTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + instanceproto := &vpcv1.InstancePrototypeInstanceBySourceSnapshot{ + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.InstanceProfileIdentity{ + Name: &profile, + }, + Name: &name, + VPC: &vpcv1.VPCIdentity{ + ID: &vpcID, + }, + } + + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } else if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } else if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + + if boot, ok := d.GetOk(isInstanceBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceBySourceSnapshotContext{} + + name, ok := bootvol[isInstanceBootAttachmentName] + namestr := name.(string) + if namestr != "" && ok { + volTemplate.Name = &namestr + } + sizeOk, ok := bootvol[isInstanceBootSize] + size := sizeOk.(int) + if size != 0 && ok { + sizeInt64 := int64(size) + volTemplate.Capacity = &sizeInt64 + } + enc, ok := bootvol[isInstanceBootEncryption] + encstr := enc.(string) + if ok && encstr != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encstr, + } + } + + volprof := "general-purpose" + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + var userTags *schema.Set + if v, ok := bootvol[isInstanceBootVolumeTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volTemplate.UserTags = userTagsArray + } + } + snapshotId, ok := bootvol[isInstanceVolumeSnapshot] + snapshotIdStr := snapshotId.(string) + if snapshotIdStr != "" && ok { + volTemplate.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &snapshotIdStr, + } + } + deletebool := true + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ + DeleteVolumeOnInstanceDelete: &deletebool, + Volume: volTemplate, + } + } + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, _ := primnic[isInstanceNicName] + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := primnic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, primary_network_interface error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + + allowIPSpoofing, ok := primnic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := primnic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + if nicsintf, ok := d.GetOk(isInstanceNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + name, ok := nic[isInstanceNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + ipv4, _ := nic[isInstanceNicPrimaryIpv4Address] + ipv4str = ipv4.(string) + + primaryIpOk, ok := nic[isInstanceNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + var reservedipautodeleteok interface{} + reservedipautodeleteok, okAuto = primip[isInstanceNicReservedIpAutoDelete] + autodelete = reservedipautodeleteok.(bool) + } + if ipv4str != "" && reservedipv4 != "" && ipv4str != reservedipv4 { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", ipv4str, reservedipv4) + } + if reservedIp != "" && (ipv4str != "" || reservedipv4 != "" || reservedipname != "") { + return fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if ipv4str != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if ipv4str != "" { + primaryipobj.Address = &ipv4str + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + allowIPSpoofing, ok := nic[isInstanceNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + keySet := d.Get(isInstanceKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + if userdata, ok := d.GetOk(isInstanceUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + if grp, ok := d.GetOk(isInstanceResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + if availablePolicyItem, ok := d.GetOk(isInstanceAvailablePolicyHostFailure); ok { + hostFailure := availablePolicyItem.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPrototype{ + HostFailure: &hostFailure, + } + } + metadataServiceEnabled := d.Get(isInstanceMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + + options := &vpcv1.CreateInstanceOptions{ + InstancePrototype: instanceproto, + } + + instance, response, err := sess.CreateInstance(options) + if err != nil { + log.Printf("[DEBUG] Instance err %s\n%s", err, response) + return err + } + d.SetId(*instance.ID) + + log.Printf("[INFO] Instance : %s", *instance.ID) + d.Set(isInstanceStatus, instance.Status) + + _, err = isWaitForInstanceAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isInstanceTags); ok || v != "" { + oldList, newList := d.GetChange(isInstanceTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMisInstanceCreate(d *schema.ResourceData, meta interface{}) error { + + profile := d.Get(isInstanceProfile).(string) + name := d.Get(isInstanceName).(string) + vpcID := d.Get(isInstanceVPC).(string) + zone := d.Get(isInstanceZone).(string) + image := d.Get(isInstanceImage).(string) + snapshot := d.Get("boot_volume.0.snapshot").(string) + template := d.Get(isInstanceSourceTemplate).(string) + if catalogOfferingOk, ok := d.GetOk(isInstanceCatalogOffering); ok { + catalogOffering := catalogOfferingOk.([]interface{})[0].(map[string]interface{}) + offeringCrn, _ := catalogOffering[isInstanceCatalogOfferingOfferingCrn].(string) + versionCrn, _ := catalogOffering[isInstanceCatalogOfferingVersionCrn].(string) + err := instanceCreateByCatalogOffering(d, meta, profile, name, vpcID, zone, image, offeringCrn, versionCrn) + if err != nil { + return err + } + + } else if snapshot != "" { + err := instanceCreateByVolume(d, meta, profile, name, vpcID, zone) + if err != nil { + return err + } + } else if template != "" { + err := instanceCreateByTemplate(d, meta, profile, name, vpcID, zone, image, template) + if err != nil { + return err + } + } else { + err := instanceCreateByImage(d, meta, profile, name, vpcID, zone, image) + if err != nil { + return err + } + } + + return resourceIBMisInstanceUpdate(d, meta) +} + +func isWaitForInstanceAvailable(instanceC *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for instance (%s) to be available.", id) + + communicator := make(chan interface{}) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isInstanceProvisioning}, + Target: []string{isInstanceStatusRunning, "available", "failed", ""}, + Refresh: isInstanceRefreshFunc(instanceC, id, d, communicator), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + if v, ok := d.GetOk("force_recovery_time"); ok { + forceTimeout := v.(int) + go isRestartStartAction(instanceC, id, d, forceTimeout, communicator) + } + + return stateConf.WaitForState() +} + +func isInstanceRefreshFunc(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, communicator chan interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + d.Set(isInstanceStatus, *instance.Status) + + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + + if *instance.Status == "available" || *instance.Status == "failed" || *instance.Status == "running" { + // let know the isRestartStartAction() to stop + close(communicator) + // taint the instance if status is failed + if *instance.Status == "failed" { + instanceStatusReason := instance.StatusReasons + + //set the status reasons + if instance.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range instance.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isInstanceStatusReasonsCode] = *sr.Code + currentSR[isInstanceStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + } + + out, err := json.MarshalIndent(instanceStatusReason, "", " ") + if err != nil { + return instance, *instance.Status, fmt.Errorf("[ERROR] Instance (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted instance and attempt to create the instance again replacing the previous configuration", *instance.ID) + } + return instance, *instance.Status, fmt.Errorf("[ERROR] Instance (%s) went into failed state during the operation \n (%+v) \n [WARNING] Running terraform apply again will remove the tainted instance and attempt to create the instance again replacing the previous configuration", *instance.ID, string(out)) + } + return instance, *instance.Status, nil + + } + return instance, isInstanceProvisioning, nil + } +} + +func isRestartStartAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int, communicator chan interface{}) { + subticker := time.NewTicker(time.Duration(forceTimeout) * time.Minute) + //subticker := time.NewTicker(time.Duration(forceTimeout) * time.Second) + for { + select { + + case <-subticker.C: + log.Println("Instance is still in starting state, force retry by restarting the instance.") + actiontype := "stop" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err := instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + communicator <- fmt.Errorf("[ERROR] Error retrying instance action start: %s\n%s", err, response) + return + } + waitTimeout := time.Duration(1) * time.Minute + _, _ = isWaitForInstanceActionStop(instanceC, waitTimeout, id, d) + actiontype = "start" + createinsactoptions = &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + communicator <- fmt.Errorf("[ERROR] Error retrying instance action start: %s\n%s", err, response) + return + } + case <-communicator: + // indicates refresh func is reached target and not proceed with the thread + subticker.Stop() + return + + } + } +} +func resourceIBMisInstanceRead(d *schema.ResourceData, meta interface{}) error { + + ID := d.Id() + + err := instanceGet(d, meta, ID) + if err != nil { + return err + } + return nil +} + +func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + getinsIniOptions := &vpcv1.GetInstanceInitializationOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Instance: %s\n%s", err, response) + } + instanceInitialization, response, err := instanceC.GetInstanceInitialization(getinsIniOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Instance initialization details: %s\n%s", err, response) + } + if instanceInitialization.DefaultTrustedProfile != nil && instanceInitialization.DefaultTrustedProfile.AutoLink != nil { + d.Set(isInstanceDefaultTrustedProfileAutoLink, *instanceInitialization.DefaultTrustedProfile.AutoLink) + } + if instanceInitialization.DefaultTrustedProfile != nil && instanceInitialization.DefaultTrustedProfile.Target != nil { + d.Set(isInstanceDefaultTrustedProfileTarget, *instanceInitialization.DefaultTrustedProfile.Target.ID) + } + + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + d.Set(isInstanceAvailablePolicyHostFailure, *instance.AvailabilityPolicy.HostFailure) + } + + // catalog + if instance.CatalogOffering != nil { + versionCrn := *instance.CatalogOffering.Version.CRN + catalogList := make([]map[string]interface{}, 0) + catalogMap := map[string]interface{}{} + catalogMap[isInstanceCatalogOfferingVersionCrn] = versionCrn + catalogList = append(catalogList, catalogMap) + d.Set(isInstanceCatalogOffering, catalogList) + } + d.Set(isInstanceName, *instance.Name) + if instance.Profile != nil { + d.Set(isInstanceProfile, *instance.Profile.Name) + } + cpuList := make([]map[string]interface{}, 0) + if instance.Vcpu != nil { + currentCPU := map[string]interface{}{} + currentCPU[isInstanceCPUArch] = *instance.Vcpu.Architecture + currentCPU[isInstanceCPUCount] = *instance.Vcpu.Count + cpuList = append(cpuList, currentCPU) + } + d.Set(isInstanceCPU, cpuList) + + if instance.Bandwidth != nil { + d.Set(isInstanceBandwidth, int(*instance.Bandwidth)) + } + + if instance.TotalNetworkBandwidth != nil { + d.Set(isInstanceTotalNetworkBandwidth, int(*instance.TotalNetworkBandwidth)) + } + + if instance.TotalVolumeBandwidth != nil { + d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) + } + + d.Set(isInstanceMemory, *instance.Memory) + gpuList := make([]map[string]interface{}, 0) + if instance.Gpu != nil { + currentGpu := map[string]interface{}{} + currentGpu[isInstanceGpuManufacturer] = instance.Gpu.Manufacturer + currentGpu[isInstanceGpuModel] = instance.Gpu.Model + currentGpu[isInstanceGpuCount] = instance.Gpu.Count + currentGpu[isInstanceGpuMemory] = instance.Gpu.Memory + gpuList = append(gpuList, currentGpu) + } + d.Set(isInstanceGpu, gpuList) + + if instance.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID + currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name + + //reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + if instance.PrimaryNetworkInterface.PrimaryIP.Address != nil { + currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + currentPrimIp[isInstanceNicReservedIpAddress] = *instance.PrimaryNetworkInterface.PrimaryIP.Address + } + if instance.PrimaryNetworkInterface.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *instance.PrimaryNetworkInterface.PrimaryIP.Href + } + if instance.PrimaryNetworkInterface.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *instance.PrimaryNetworkInterface.PrimaryIP.Name + } + if instance.PrimaryNetworkInterface.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *instance.PrimaryNetworkInterface.PrimaryIP.ID + } + if instance.PrimaryNetworkInterface.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *instance.PrimaryNetworkInterface.PrimaryIP.ResourceType + } + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: instance.PrimaryNetworkInterface.Subnet.ID, + ID: instance.PrimaryNetworkInterface.PrimaryIP.ID, + } + insRip, response, err := instanceC.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the instance network interface(%s): %s\n%s", *instance.PrimaryNetworkInterface.PrimaryIP.ID, *instance.PrimaryNetworkInterface.ID, err, response) + } + currentPrimIp[isInstanceNicReservedIpAutoDelete] = insRip.AutoDelete + + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: instance.PrimaryNetworkInterface.ID, + } + insnic, response, err := instanceC.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + currentPrimNic[isInstanceNicAllowIPSpoofing] = *insnic.AllowIPSpoofing + if insnic.PortSpeed != nil { + currentPrimNic[isInstanceNicPortSpeed] = *insnic.PortSpeed + } + currentPrimNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentPrimNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + + primaryNicList = append(primaryNicList, currentPrimNic) + d.Set(isInstancePrimaryNetworkInterface, primaryNicList) + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + if *intfc.ID != *instance.PrimaryNetworkInterface.ID { + currentNic := map[string]interface{}{} + currentNic["id"] = *intfc.ID + currentNic[isInstanceNicName] = *intfc.Name + + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + + if intfc.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *intfc.PrimaryIP.Address + currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIP.Address + } + if intfc.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *intfc.PrimaryIP.Href + } + if intfc.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *intfc.PrimaryIP.Name + } + if intfc.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *intfc.PrimaryIP.ID + } + if intfc.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *intfc.PrimaryIP.ResourceType + } + + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: intfc.Subnet.ID, + ID: intfc.PrimaryIP.ID, + } + insRip, response, err := instanceC.GetSubnetReservedIP(getripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the instance network interface(%s): %s\n%s", *intfc.PrimaryIP.ID, *intfc.ID, err, response) + } + currentPrimIp[isInstanceNicReservedIpAutoDelete] = insRip.AutoDelete + + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceNicPrimaryIP] = primaryIpList + + getnicoptions := &vpcv1.GetInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: intfc.ID, + } + insnic, response, err := instanceC.GetInstanceNetworkInterface(getnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s\n%s", err, response) + } + currentNic[isInstanceNicAllowIPSpoofing] = *insnic.AllowIPSpoofing + currentNic[isInstanceNicSubnet] = *insnic.Subnet.ID + if len(insnic.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(insnic.SecurityGroups); i++ { + secgrpList = append(secgrpList, string(*(insnic.SecurityGroups[i].ID))) + } + currentNic[isInstanceNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + + } + } + + d.Set(isInstanceNetworkInterfaces, interfacesList) + } + + if instance.Image != nil { + d.Set(isInstanceImage, *instance.Image.ID) + } + + d.Set(isInstanceStatus, *instance.Status) + + //set the status reasons + if instance.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range instance.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isInstanceStatusReasonsCode] = *sr.Code + currentSR[isInstanceStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + } + + //set the lifecycle status, reasons + if instance.LifecycleState != nil { + d.Set(isInstanceLifecycleState, *instance.LifecycleState) + } + if instance.LifecycleReasons != nil { + d.Set(isInstanceLifecycleReasons, dataSourceInstanceFlattenLifecycleReasons(instance.LifecycleReasons)) + } + + d.Set(isInstanceVPC, *instance.VPC.ID) + d.Set(isInstanceZone, *instance.Zone.Name) + + if instance.VolumeAttachments != nil { + volList := make([]map[string]interface{}, 0) + for _, volume := range instance.VolumeAttachments { + vol := map[string]interface{}{} + if volume.Volume != nil { + vol["id"] = *volume.ID + vol["volume_id"] = *volume.Volume.ID + vol["name"] = *volume.Name + vol["volume_name"] = *volume.Volume.Name + vol["volume_crn"] = *volume.Volume.CRN + volList = append(volList, vol) + } + } + d.Set(isInstanceVolumeAttachments, volList) + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + if instance.BootVolumeAttachment.Volume != nil { + bootVol[isInstanceBootAttachmentName] = *instance.BootVolumeAttachment.Volume.Name + bootVol[isInstanceBootVolumeId] = *instance.BootVolumeAttachment.Volume.ID + options := &vpcv1.GetVolumeOptions{ + ID: instance.BootVolumeAttachment.Volume.ID, + } + vol, response, err := instanceC.GetVolume(options) + if err != nil { + log.Printf("Error Getting Boot Volume (%s): %s\n%s", id, err, response) + } + if vol != nil { + bootVol[isInstanceBootSize] = *vol.Capacity + bootVol[isInstanceBootIOPS] = *vol.Iops + bootVol[isInstanceBootProfile] = *vol.Profile.Name + if vol.EncryptionKey != nil { + bootVol[isInstanceBootEncryption] = *vol.EncryptionKey.CRN + } + if vol.SourceSnapshot != nil { + bootVol[isInstanceVolumeSnapshot] = vol.SourceSnapshot.ID + } + if vol.UserTags != nil { + bootVol[isInstanceBootVolumeTags] = vol.UserTags + } + } + } + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceBootVolume, bootVolList) + } + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on get of resource Instance (%s) tags: %s", d.Id(), err) + } + d.Set(isInstanceTags, tags) + + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/vs") + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.CRN) + d.Set(IsInstanceCRN, *instance.CRN) + d.Set(flex.ResourceStatus, *instance.Status) + if instance.ResourceGroup != nil { + d.Set(isInstanceResourceGroup, *instance.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *instance.ResourceGroup.Name) + } + if instance.MetadataService != nil { + d.Set(isInstanceMetadataServiceEnabled, instance.MetadataService.Enabled) + } + if instance.Disks != nil { + disks := []map[string]interface{}{} + for _, disksItem := range instance.Disks { + disksItemMap := resourceIbmIsInstanceInstanceDiskToMap(disksItem) + disks = append(disks, disksItemMap) + } + if err = d.Set(isInstanceDisks, disks); err != nil { + return fmt.Errorf("[ERROR] Error setting disks: %s", err) + } + } + + placementTarget := []map[string]interface{}{} + if instance.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) + placementTarget = append(placementTarget, placementTargetMap) + } + if err = d.Set(isInstancePlacementTarget, placementTarget); err != nil { + return fmt.Errorf("[ERROR] Error setting placement_target: %s", err) + } + return nil +} + +func instanceUpdate(d *schema.ResourceData, meta interface{}) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + id := d.Id() + + bootVolSize := "boot_volume.0.size" + if d.HasChange(bootVolSize) && !d.IsNewResource() { + old, new := d.GetChange(bootVolSize) + if new.(int) < old.(int) { + return fmt.Errorf("[ERROR] Error while updating boot volume size of the instance, only expansion is possible") + } + bootVol := int64(new.(int)) + volId := d.Get("boot_volume.0.volume_id").(string) + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + volPatchModel := &vpcv1.VolumePatch{ + Capacity: &bootVol, + } + volPatchModelAsPatch, err := volPatchModel.AsPatch() + + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while apply as patch for boot volume of instance %s", err)) + } + + updateVolumeOptions.VolumePatch = volPatchModelAsPatch + + vol, res, err := instanceC.UpdateVolume(updateVolumeOptions) + + if vol == nil || err != nil { + return (fmt.Errorf("[ERROR] Error encountered while expanding boot volume of instance %s/n%s", err, res)) + } + + _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + bootVolTags := "boot_volume.0.tags" + if d.HasChange(bootVolTags) && !d.IsNewResource() { + var userTags *schema.Set + if v, ok := d.GetOk("boot_volume.0.tags"); ok { + volId := d.Get("boot_volume.0.volume_id").(string) + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumePatchModel := &vpcv1.VolumePatch{} + volumePatchModel.UserTags = userTagsArray + volumePatch, err := volumePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error encountered while apply as patch for boot volume of instance %s", err) + } + optionsget := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + _, response, err := instanceC.GetVolume(optionsget) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Boot Volume (%s): %s\n%s", id, err, response) + } + eTag := response.Headers.Get("ETag") + updateVolumeOptions.IfMatch = &eTag + updateVolumeOptions.VolumePatch = volumePatch + vol, res, err := instanceC.UpdateVolume(updateVolumeOptions) + if vol == nil || err != nil { + return (fmt.Errorf("[ERROR] Error encountered while applying tags for boot volume of instance %s/n%s", err, res)) + } + _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + } + } + + if d.HasChange(isPlacementTargetDedicatedHost) || d.HasChange(isPlacementTargetDedicatedHostGroup) && !d.IsNewResource() { + dedicatedHost := d.Get(isPlacementTargetDedicatedHost).(string) + dedicatedHostGroup := d.Get(isPlacementTargetDedicatedHostGroup).(string) + actiontype := "stop" + + if dedicatedHost == "" && dedicatedHostGroup == "" { + return fmt.Errorf("[ERROR] Error: Instances cannot be moved from private to public hosts") + } + + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err := instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return err + } + + updateOptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + + instancePatchModel := &vpcv1.InstancePatch{} + + if dedicatedHost != "" { + placementTarget := &vpcv1.InstancePlacementTargetPatch{ + ID: &dedicatedHost, + } + instancePatchModel.PlacementTarget = placementTarget + } else if dedicatedHostGroup != "" { + placementTarget := &vpcv1.InstancePlacementTargetPatch{ + ID: &dedicatedHostGroup, + } + instancePatchModel.PlacementTarget = placementTarget + } + + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch with total volume bandwidth for InstancePatch: %s", err) + } + + updateOptions.InstancePatch = instancePatch + + _, _, err = instanceC.UpdateInstance(updateOptions) + if err != nil { + return err + } + + actiontype = "start" + createinsactoptions = &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + _, err = isWaitForInstanceActionStart(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return err + } + } + + if d.HasChange(isInstanceAction) && !d.IsNewResource() { + + actiontype := d.Get(isInstanceAction).(string) + if actiontype != "" { + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Instance (%s): %s\n%s", id, err, response) + } + if (actiontype == "stop" || actiontype == "reboot") && *instance.Status != isInstanceStatusRunning { + d.Set(isInstanceAction, nil) + return fmt.Errorf("[ERROR] Error with stop/reboot action: Cannot invoke stop/reboot action while instance is not in running state") + } else if actiontype == "start" && *instance.Status != isInstanceActionStatusStopped { + d.Set(isInstanceAction, nil) + return fmt.Errorf("[ERROR] Error with start action: Cannot invoke start action while instance is not in stopped state") + } + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + if instanceActionForceIntf, ok := d.GetOk(isInstanceActionForce); ok { + force := instanceActionForceIntf.(bool) + createinsactoptions.Force = &force + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + if actiontype == "stop" { + _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return err + } + } else if actiontype == "start" || actiontype == "reboot" { + _, err = isWaitForInstanceActionStart(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return err + } + } + + } + } + if d.HasChange(isInstanceVolumes) { + ovs, nvs := d.GetChange(isInstanceVolumes) + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + var volautoDelete bool + if volumeautodeleteIntf, ok := d.GetOk(isInstanceVolAttVolAutoDelete); ok && volumeautodeleteIntf != nil { + volautoDelete = volumeautodeleteIntf.(bool) + } + + if len(add) > 0 { + for i := range add { + createvolattoptions := &vpcv1.CreateInstanceVolumeAttachmentOptions{ + InstanceID: &id, + Volume: &vpcv1.VolumeAttachmentPrototypeVolume{ + ID: &add[i], + }, + DeleteVolumeOnInstanceDelete: &volautoDelete, + } + vol, _, err := instanceC.CreateInstanceVolumeAttachment(createvolattoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while attaching volume %q for instance %s: %q", add[i], d.Id(), err) + } + _, err = isWaitForInstanceVolumeAttached(instanceC, d, id, *vol.ID) + if err != nil { + return err + } + } + + } + if len(remove) > 0 { + for i := range remove { + listvolattoptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{ + InstanceID: &id, + } + vols, _, err := instanceC.ListInstanceVolumeAttachments(listvolattoptions) + if err != nil { + return err + } + for _, vol := range vols.VolumeAttachments { + if *vol.Volume.ID == remove[i] { + delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: &id, + ID: vol.ID, + } + _, err := instanceC.DeleteInstanceVolumeAttachment(delvolattoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing volume %q for instance %s: %q", remove[i], d.Id(), err) + } + _, err = isWaitForInstanceVolumeDetached(instanceC, d, d.Id(), *vol.ID) + if err != nil { + return err + } + break + } + } + } + } + } + + if d.HasChange("primary_network_interface.0.security_groups") && !d.IsNewResource() { + ovs, nvs := d.GetChange("primary_network_interface.0.security_groups") + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + networkID := d.Get("primary_network_interface.0.id").(string) + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &networkID, + } + _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating security group %q for primary network interface of instance %s\n%s: %q", add[i], d.Id(), err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + + } + if len(remove) > 0 { + networkID := d.Get("primary_network_interface.0.id").(string) + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &networkID, + } + response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing security group %q for primary network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + } + } + + if !d.IsNewResource() && (d.HasChange("primary_network_interface.0.primary_ip.0.name") || d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete")) { + subnetId := d.Get("primary_network_interface.0.subnet").(string) + ripId := d.Get("primary_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_network_interface.0.primary_ip.0.name") { + name := d.Get("primary_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("primary_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := instanceC.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating instance network interface reserved ip(%s): %s\n%s", ripId, err, response) + } + } + + if (d.HasChange("primary_network_interface.0.allow_ip_spoofing") || d.HasChange("primary_network_interface.0.name")) && !d.IsNewResource() { + newName := d.Get("primary_network_interface.0.name").(string) + networkID := d.Get("primary_network_interface.0.id").(string) + allowIPSpoofing := d.Get("primary_network_interface.0.allow_ip_spoofing").(bool) + updatepnicfoptions := &vpcv1.UpdateInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: &networkID, + } + + networkInterfacePatchModel := &vpcv1.NetworkInterfacePatch{ + Name: &newName, + AllowIPSpoofing: &allowIPSpoofing, + } + networkInterfacePatch, err := networkInterfacePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for NetworkInterfacePatch: %s", err) + } + updatepnicfoptions.NetworkInterfacePatch = networkInterfacePatch + + _, response, err := instanceC.UpdateInstanceNetworkInterface(updatepnicfoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while updating name %s for primary network interface of instance %s\n%s: %q", newName, d.Id(), err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + + if d.HasChange(isInstanceNetworkInterfaces) && !d.IsNewResource() { + nics := d.Get(isInstanceNetworkInterfaces).([]interface{}) + for i := range nics { + securitygrpKey := fmt.Sprintf("network_interfaces.%d.security_groups", i) + networkNameKey := fmt.Sprintf("network_interfaces.%d.name", i) + subnetKey := fmt.Sprintf("network_interfaces.%d.subnet", i) + ipSpoofingKey := fmt.Sprintf("network_interfaces.%d.allow_ip_spoofing", i) + primaryipname := fmt.Sprintf("network_interfaces.%d.primary_ip.0.name", i) + primaryipauto := fmt.Sprintf("network_interfaces.%d.primary_ip.0.auto_delete", i) + primaryiprip := fmt.Sprintf("network_interfaces.%d.primary_ip.0.reserved_ip", i) + if d.HasChange(primaryipname) || d.HasChange(primaryipauto) { + subnetId := d.Get(subnetKey).(string) + ripId := d.Get(primaryiprip).(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange(primaryipname) { + name := d.Get(primaryipname).(string) + reservedIpPath.Name = &name + } + if d.HasChange(primaryipauto) { + auto := d.Get(primaryipauto).(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := instanceC.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating instance network interface reserved ip(%s): %s\n%s", ripId, err, response) + } + } + + if d.HasChange(securitygrpKey) { + ovs, nvs := d.GetChange(securitygrpKey) + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) + networkID := d.Get(networkIDKey).(string) + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &networkID, + } + _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating security group %q for network interface of instance %s\n%s: %q", add[i], d.Id(), err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + + } + if len(remove) > 0 { + networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) + networkID := d.Get(networkIDKey).(string) + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &networkID, + } + response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing security group %q for network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + } + } + + } + + if d.HasChange(networkNameKey) || d.HasChange(ipSpoofingKey) { + newName := d.Get(networkNameKey).(string) + networkIDKey := fmt.Sprintf("network_interfaces.%d.id", i) + networkID := d.Get(networkIDKey).(string) + ipSpoofing := d.Get(ipSpoofingKey).(bool) + updatepnicfoptions := &vpcv1.UpdateInstanceNetworkInterfaceOptions{ + InstanceID: &id, + ID: &networkID, + } + + instancePatchModel := &vpcv1.NetworkInterfacePatch{ + Name: &newName, + AllowIPSpoofing: &ipSpoofing, + } + networkInterfacePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for NetworkInterfacePatch: %s", err) + } + updatepnicfoptions.NetworkInterfacePatch = networkInterfacePatch + + _, response, err := instanceC.UpdateInstanceNetworkInterface(updatepnicfoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while updating name %s for network interface of instance %s\n%s: %q", newName, d.Id(), err, response) + } + if err != nil { + return err + } + } + } + + } + + if d.HasChange(isInstanceTotalVolumeBandwidth) && !d.IsNewResource() { + totalVolBandwidth := int64(d.Get(isInstanceTotalVolumeBandwidth).(int)) + updnetoptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + + instancePatchModel := &vpcv1.InstancePatch{ + TotalVolumeBandwidth: &totalVolBandwidth, + } + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch with total volume bandwidth for InstancePatch: %s", err) + } + updnetoptions.InstancePatch = instancePatch + + _, _, err = instanceC.UpdateInstance(updnetoptions) + if err != nil { + return err + } + } + + if d.HasChange(isInstanceName) && !d.IsNewResource() { + name := d.Get(isInstanceName).(string) + updnetoptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + + instancePatchModel := &vpcv1.InstancePatch{ + Name: &name, + } + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for InstancePatch: %s", err) + } + updnetoptions.InstancePatch = instancePatch + + _, _, err = instanceC.UpdateInstance(updnetoptions) + if err != nil { + return err + } + } + + if d.HasChange(isInstanceMetadataServiceEnabled) && !d.IsNewResource() { + enabled := d.Get(isInstanceMetadataServiceEnabled).(bool) + updatedoptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + instancePatchModel := &vpcv1.InstancePatch{ + MetadataService: &vpcv1.InstanceMetadataServicePatch{ + Enabled: &enabled, + }, + } + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) + } + updatedoptions.InstancePatch = instancePatch + + _, _, err = instanceC.UpdateInstance(updatedoptions) + if err != nil { + return err + } + } + if d.HasChange(isInstanceAvailablePolicyHostFailure) && !d.IsNewResource() { + + updatedoptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + availablePolicyHostFailure := d.Get(isInstanceAvailablePolicyHostFailure).(string) + instancePatchModel := &vpcv1.InstancePatch{ + AvailabilityPolicy: &vpcv1.InstanceAvailabilityPolicyPatch{ + HostFailure: &availablePolicyHostFailure, + }, + } + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) + } + updatedoptions.InstancePatch = instancePatch + + _, _, err = instanceC.UpdateInstance(updatedoptions) + if err != nil { + return err + } + } + + if d.HasChange(isInstanceProfile) && !d.IsNewResource() { + + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Instance (%s): %s\n%s", id, err, response) + } + + if instance != nil && *instance.Status == "running" { + actiontype := "stop" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return err + } + } + + updnetoptions := &vpcv1.UpdateInstanceOptions{ + ID: &id, + } + + instanceProfile := d.Get(isInstanceProfile).(string) + profile := &vpcv1.InstancePatchProfile{ + Name: &instanceProfile, + } + instancePatchModel := &vpcv1.InstancePatch{ + Profile: profile, + } + instancePatch, err := instancePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for InstancePatch: %s", err) + } + updnetoptions.InstancePatch = instancePatch + + _, response, err = instanceC.UpdateInstance(updnetoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error in UpdateInstancePatch: %s\n%s", err, response) + } + + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return err + } + + } + + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + if d.HasChange(isInstanceTags) { + oldList, newList := d.GetChange(isInstanceTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on update of resource Instance (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMisInstanceUpdate(d *schema.ResourceData, meta interface{}) error { + + err := instanceUpdate(d, meta) + if err != nil { + return err + } + + return resourceIBMisInstanceRead(d, meta) +} + +func instanceDelete(d *schema.ResourceData, meta interface{}, id string) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + + cleanDelete := d.Get(isEnableCleanDelete).(bool) + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + _, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Instance (%s): %s\n%s", id, err, response) + } + + bootvolid := "" + + if cleanDelete { + actiontype := "stop" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response) + } + _, err = isWaitForInstanceActionStop(instanceC, d.Timeout(schema.TimeoutDelete), id, d) + if err != nil { + return err + } + listvolattoptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{ + InstanceID: &id, + } + vols, response, err := instanceC.ListInstanceVolumeAttachments(listvolattoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Listing volume attachments to the instance: %s\n%s", err, response) + } + for _, vol := range vols.VolumeAttachments { + if *vol.Type == "data" { + delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: &id, + ID: vol.ID, + } + _, err := instanceC.DeleteInstanceVolumeAttachment(delvolattoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing volume Attachment %q for instance %s: %q", *vol.ID, d.Id(), err) + } + _, err = isWaitForInstanceVolumeDetached(instanceC, d, d.Id(), *vol.ID) + if err != nil { + return err + } + } + if *vol.Type == "boot" { + bootvolid = *vol.Volume.ID + } + } + } + deleteinstanceOptions := &vpcv1.DeleteInstanceOptions{ + ID: &id, + } + _, err = instanceC.DeleteInstance(deleteinstanceOptions) + if err != nil { + return err + } + if cleanDelete { + _, err = isWaitForInstanceDelete(instanceC, d, d.Id()) + if err != nil { + return err + } + if _, ok := d.GetOk(isInstanceBootVolume); ok { + _, err = isWaitForVolumeDeleted(instanceC, bootvolid, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + } + } + return nil +} + +func resourceIBMisInstanceDelete(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + err := instanceDelete(d, meta, id) + if err != nil { + return err + } + + d.SetId("") + return nil +} + +func instanceExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + instanceC, err := vpcClient(meta) + if err != nil { + return false, err + } + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + _, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + return true, nil +} + +func resourceIBMisInstanceExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + id := d.Id() + + exists, err := instanceExists(d, meta, id) + return exists, err + +} + +func isWaitForInstanceDelete(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id string) (interface{}, error) { + + stateConf := &resource.StateChangeConf{ + Pending: []string{isInstanceDeleting, isInstanceAvailable}, + Target: []string{isInstanceDeleteDone, ""}, + Refresh: func() (interface{}, string, error) { + getinsoptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return instance, isInstanceDeleteDone, nil + } + return nil, "", fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + if *instance.Status == isInstanceFailed { + return instance, *instance.Status, fmt.Errorf("[ERROR] The instance %s failed to delete: %v", d.Id(), err) + } + return instance, isInstanceDeleting, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isWaitForInstanceActionStop(instanceC *vpcv1.VpcV1, timeout time.Duration, id string, d *schema.ResourceData) (interface{}, error) { + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isInstanceStatusRunning, isInstanceStatusPending, isInstanceActionStatusStopping}, + Target: []string{isInstanceActionStatusStopped, isInstanceStatusFailed, ""}, + Refresh: func() (interface{}, string, error) { + getinsoptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + if *instance.Status == isInstanceStatusFailed { + // let know the isRestartStopAction() to stop + close(communicator) + return instance, *instance.Status, fmt.Errorf("[ERROR] The instance %s failed to stop: %v", id, err) + } + return instance, *instance.Status, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + if v, ok := d.GetOk("force_recovery_time"); ok { + forceTimeout := v.(int) + go isRestartStopAction(instanceC, id, d, forceTimeout, communicator) + } + + return stateConf.WaitForState() +} + +func isWaitForInstanceActionStart(instanceC *vpcv1.VpcV1, timeout time.Duration, id string, d *schema.ResourceData) (interface{}, error) { + communicator := make(chan interface{}) + stateConf := &resource.StateChangeConf{ + Pending: []string{isInstanceActionStatusStopped, isInstanceStatusPending, isInstanceActionStatusStopping, isInstanceStatusStarting, isInstanceStatusRestarting}, + Target: []string{isInstanceStatusRunning, isInstanceStatusFailed, ""}, + Refresh: func() (interface{}, string, error) { + getinsoptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := instanceC.GetInstance(getinsoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Instance: %s\n%s", err, response) + } + select { + case data := <-communicator: + return nil, "", data.(error) + default: + fmt.Println("no message sent") + } + if *instance.Status == isInstanceStatusFailed { + // let know the isRestartStopAction() to stop + close(communicator) + return instance, *instance.Status, fmt.Errorf("[ERROR] The instance %s failed to start: %v", id, err) + } + return instance, *instance.Status, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + if v, ok := d.GetOk("force_recovery_time"); ok { + forceTimeout := v.(int) + go isRestartStopAction(instanceC, id, d, forceTimeout, communicator) + } + + return stateConf.WaitForState() +} + +func isRestartStopAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceData, forceTimeout int, communicator chan interface{}) { + subticker := time.NewTicker(time.Duration(forceTimeout) * time.Minute) + //subticker := time.NewTicker(time.Duration(forceTimeout) * time.Second) + for { + select { + + case <-subticker.C: + log.Println("Instance is still in stopping state, retrying to stop with -force") + actiontype := "stop" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err := instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + communicator <- fmt.Errorf("[ERROR] Error retrying instance action stop: %s\n%s", err, response) + return + } + case <-communicator: + // indicates refresh func is reached target and not proceed with the thread) + subticker.Stop() + return + + } + } +} + +func isWaitForInstanceVolumeAttached(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id, volID string) (interface{}, error) { + log.Printf("Waiting for instance (%s) volume (%s) to be attached.", id, volID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isInstanceVolumeAttaching}, + Target: []string{isInstanceVolumeAttached, ""}, + Refresh: isInstanceVolumeRefreshFunc(instanceC, id, volID), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isInstanceVolumeRefreshFunc(instanceC *vpcv1.VpcV1, id, volID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getvolattoptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: &id, + ID: &volID, + } + vol, response, err := instanceC.GetInstanceVolumeAttachment(getvolattoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Attaching volume: %s\n%s", err, response) + } + + if *vol.Status == isInstanceVolumeAttached { + return vol, isInstanceVolumeAttached, nil + } + + return vol, isInstanceVolumeAttaching, nil + } +} + +func isWaitForInstanceVolumeDetached(instanceC *vpcv1.VpcV1, d *schema.ResourceData, id, volID string) (interface{}, error) { + + stateConf := &resource.StateChangeConf{ + Pending: []string{isInstanceVolumeAttached, isInstanceVolumeDetaching}, + Target: []string{isInstanceDeleteDone, ""}, + Refresh: func() (interface{}, string, error) { + getvolattoptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: &id, + ID: &volID, + } + vol, response, err := instanceC.GetInstanceVolumeAttachment(getvolattoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return vol, isInstanceDeleteDone, nil + } + return nil, "", fmt.Errorf("[ERROR] Error Detaching: %s\n%s", err, response) + } + if *vol.Status == isInstanceFailed { + return vol, *vol.Status, fmt.Errorf("[ERROR] The instance %s failed to detach volume %s: %v", d.Id(), volID, err) + } + return vol, isInstanceVolumeDetaching, nil + }, + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func resourceIbmIsInstanceInstanceDiskToMap(instanceDisk vpcv1.InstanceDisk) map[string]interface{} { + instanceDiskMap := map[string]interface{}{} + + instanceDiskMap["created_at"] = instanceDisk.CreatedAt.String() + instanceDiskMap["href"] = instanceDisk.Href + instanceDiskMap["id"] = instanceDisk.ID + instanceDiskMap["interface_type"] = instanceDisk.InterfaceType + instanceDiskMap["name"] = instanceDisk.Name + instanceDiskMap["resource_type"] = instanceDisk.ResourceType + instanceDiskMap["size"] = flex.IntValue(instanceDisk.Size) + + return instanceDiskMap +} + +func suppressEnableCleanDelete(k, old, new string, d *schema.ResourceData) bool { + // During import + if old == "" && d.Id() != "" { + return true + } + return false +} + +func resourceIbmIsInstanceInstancePlacementToMap(instancePlacement vpcv1.InstancePlacementTarget) map[string]interface{} { + instancePlacementMap := map[string]interface{}{} + + instancePlacementMap["crn"] = instancePlacement.CRN + if instancePlacement.Deleted != nil { + DeletedMap := resourceIbmIsInstanceDedicatedHostGroupReferenceDeletedToMap(*instancePlacement.Deleted) + instancePlacementMap["deleted"] = []map[string]interface{}{DeletedMap} + } + instancePlacementMap["href"] = instancePlacement.Href + instancePlacementMap["id"] = instancePlacement.ID + instancePlacementMap["name"] = instancePlacement.Name + instancePlacementMap["resource_type"] = instancePlacement.ResourceType + + return instancePlacementMap +} + +func resourceIbmIsInstanceDedicatedHostGroupReferenceDeletedToMap(dedicatedHostGroupReferenceDeleted vpcv1.DedicatedHostGroupReferenceDeleted) map[string]interface{} { + dedicatedHostGroupReferenceDeletedMap := map[string]interface{}{} + + dedicatedHostGroupReferenceDeletedMap["more_info"] = dedicatedHostGroupReferenceDeleted.MoreInfo + + return dedicatedHostGroupReferenceDeletedMap +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_action.go b/ibm/service/vpc/resource_ibm_is_instance_action.go new file mode 100644 index 000000000..71033c2bb --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_action.go @@ -0,0 +1,278 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceActionAvailable = "available" + isInstanceActionPending = "pending" + isInstanceActionFailed = "failed" + isInstanceStopType = "stop_type" + isInstanceID = "instance" + isInstanceActionForce = "force_action" +) + +func ResourceIBMISInstanceAction() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISInstanceActionCreate, + ReadContext: resourceIBMISInstanceActionRead, + UpdateContext: resourceIBMISInstanceActionUpdate, + DeleteContext: resourceIBMISInstanceActionDelete, + Exists: resourceIBMISInstanceActionExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isInstanceID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance identifier", + }, + isInstanceAction: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_action", isInstanceAction), + Description: "This restart/start/stops an instance.", + }, + isInstanceActionForce: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If set to true, the action will be forced immediately, and all queued actions deleted. Ignored for the start action.", + }, + isInstanceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Instance status", + }, + + isInstanceStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isInstanceStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isInstanceStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISInstanceActionValidator() *validate.ResourceValidator { + + instanceActions := "start, reboot, stop" + validateSchema := make([]validate.ValidateSchema, 0) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: instanceActions}) + ibmISInstanceActionResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_action", Schema: validateSchema} + return &ibmISInstanceActionResourceValidator +} + +func resourceIBMISInstanceActionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + instanceId := "" + if insId, ok := d.GetOk(isInstanceID); ok { + instanceId = insId.(string) + } + + actiontypeIntf := d.Get(isInstanceAction) + actiontype := actiontypeIntf.(string) + + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &instanceId, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Instance (%s): %s\n%s", instanceId, err, response)) + } + if (actiontype == "stop" || actiontype == "reboot") && *instance.Status != isInstanceStatusRunning { + d.Set(isInstanceAction, nil) + return diag.FromErr(fmt.Errorf("[ERROR] Error with stop/reboot action: Cannot invoke stop/reboot action while instance is not in running state")) + } else if actiontype == "start" && *instance.Status != isInstanceActionStatusStopped { + d.Set(isInstanceAction, nil) + return diag.FromErr(fmt.Errorf("[ERROR] Error with start action: Cannot invoke start action while instance is not in stopped state")) + } + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &instanceId, + Type: &actiontype, + } + if instanceActionForceIntf, ok := d.GetOk(isInstanceActionForce); ok { + force := instanceActionForceIntf.(bool) + createinsactoptions.Force = &force + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response)) + } + if actiontype == "stop" { + _, err = isWaitForInstanceActionStop(sess, d.Timeout(schema.TimeoutUpdate), instanceId, d) + if err != nil { + return diag.FromErr(err) + } + } else if actiontype == "start" || actiontype == "reboot" { + _, err = isWaitForInstanceActionStart(sess, d.Timeout(schema.TimeoutUpdate), instanceId, d) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId(instanceId) + return resourceIBMISInstanceActionRead(context, d, meta) +} + +func resourceIBMISInstanceActionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + id := d.Id() + + options := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := sess.GetInstance(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting instance (%s): %s\n%s", id, err, response)) + } + + d.Set(isInstanceStatus, *instance.Status) + statusReasonsList := make([]map[string]interface{}, 0) + if instance.StatusReasons != nil { + for _, sr := range instance.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isInstanceStatusReasonsCode] = *sr.Code + currentSR[isInstanceStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + return nil +} + +func resourceIBMISInstanceActionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + _, actiontypeIntf := d.GetChange(isInstanceAction) + actiontype := actiontypeIntf.(string) + id := d.Id() + + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Instance (%s): %s\n%s", id, err, response)) + } + if (actiontype == "stop" || actiontype == "reboot") && *instance.Status != isInstanceStatusRunning { + d.Set(isInstanceAction, nil) + return diag.FromErr(fmt.Errorf("[ERROR] Error with stop/reboot action: Cannot invoke stop/reboot action while instance is not in running state")) + } else if actiontype == "start" && *instance.Status != isInstanceActionStatusStopped { + d.Set(isInstanceAction, nil) + return diag.FromErr(fmt.Errorf("[ERROR] Error with start action: Cannot invoke start action while instance is not in stopped state")) + } + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &id, + Type: &actiontype, + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Creating Instance Action: %s\n%s", err, response)) + } + if actiontype == "stop" { + _, err = isWaitForInstanceActionStop(sess, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return diag.FromErr(err) + } + } else if actiontype == "start" || actiontype == "reboot" { + _, err = isWaitForInstanceActionStart(sess, d.Timeout(schema.TimeoutUpdate), id, d) + if err != nil { + return diag.FromErr(err) + } + } + + return nil +} + +func resourceIBMISInstanceActionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} + +func resourceIBMISInstanceActionExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + id := d.Id() + getInstanceOptions := &vpcv1.GetInstanceOptions{ + ID: &id, + } + _, response, err := sess.GetInstance(getInstanceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting instance : %s\n%s", err, response) + } + return true, err +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_action_test.go b/ibm/service/vpc/resource_ibm_is_instance_action_test.go new file mode 100644 index 000000000..42b1afc03 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_action_test.go @@ -0,0 +1,194 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISInstanceAction_basic(t *testing.T) { + //var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceActionRebootConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + ), + }, + { + Config: testAccCheckIBMISInstanceActionCheckStatusConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "status", "running"), + ), + }, + { + Config: testAccCheckIBMISInstanceActionStopConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + ), + }, + { + Config: testAccCheckIBMISInstanceActionCheckStatusConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "status", "stopped"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceActionRebootConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + data "ibm_is_images" "im_images" { + + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = data.ibm_is_images.im_images.images.4.id + profile = "bx2d-16x64" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + + resource "ibm_is_instance_action" "testacc_instanceaction" { + depends_on = [ibm_is_instance.testacc_instance] + action = "reboot" + instance = ibm_is_instance.testacc_instance.id + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceActionStopConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + data "ibm_is_images" "im_images" { + + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = data.ibm_is_images.im_images.images.4.id + profile = "bx2d-16x64" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + + resource "ibm_is_instance_action" "testacc_instanceaction" { + depends_on = [ibm_is_instance.testacc_instance] + action = "stop" + instance = ibm_is_instance.testacc_instance.id + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceActionCheckStatusConfig(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + data "ibm_is_images" "im_images" { + + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = data.ibm_is_images.im_images.images.4.id + profile = "bx2d-16x64" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.ISZoneName) +} diff --git a/ibm/resource_ibm_is_instance_disk_management.go b/ibm/service/vpc/resource_ibm_is_instance_disk_management.go similarity index 79% rename from ibm/resource_ibm_is_instance_disk_management.go rename to ibm/service/vpc/resource_ibm_is_instance_disk_management.go index fcbf5e4da..8ce2aea7f 100644 --- a/ibm/resource_ibm_is_instance_disk_management.go +++ b/ibm/service/vpc/resource_ibm_is_instance_disk_management.go @@ -1,18 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const () -func resourceIBMISInstanceDiskManagement() *schema.Resource { +func ResourceIBMISInstanceDiskManagement() *schema.Resource { return &schema.Resource{ Create: resourceIBMisInstanceDiskManagementCreate, Read: resourceIBMisInstanceDiskManagementRead, @@ -27,21 +28,21 @@ func resourceIBMISInstanceDiskManagement() *schema.Resource { ForceNew: true, Description: "ID of the instance for which disks has to be managed", }, - "disks": &schema.Schema{ + "disks": { Type: schema.TypeList, Required: true, Description: "Disk information that has to be updated.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ + "id": { Type: schema.TypeString, Required: true, Description: "The unique identifier for this instance disk.", }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_disk_management", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_disk_management", "name"), Description: "The user-defined name for this disk. The disk will be updated with this new name", }, }, @@ -51,20 +52,20 @@ func resourceIBMISInstanceDiskManagement() *schema.Resource { } } -func resourceIBMISInstanceDiskManagementValidator() *ResourceValidator { +func ResourceIBMISInstanceDiskManagementValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) - ibmISInstanceDiskManagementValidator := ResourceValidator{ResourceName: "ibm_is_instance_disk_management", Schema: validateSchema} + ibmISInstanceDiskManagementValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_disk_management", Schema: validateSchema} return &ibmISInstanceDiskManagementValidator } @@ -92,13 +93,13 @@ func resourceIBMisInstanceDiskManagementCreate(d *schema.ResourceData, meta inte instanceDiskPatch, err := instanceDiskPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceDiskPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceDiskPatch: %s", err) } updateInstanceDiskOptions.SetInstanceDiskPatch(instanceDiskPatch) _, response, err := sess.UpdateInstanceDisk(updateInstanceDiskOptions) if err != nil { - return fmt.Errorf("Error calling UpdateInstanceDisk: %s %s", err, response) + return fmt.Errorf("[ERROR] Error calling UpdateInstanceDisk: %s %s", err, response) } } @@ -130,13 +131,13 @@ func resourceIBMisInstanceDiskManagementUpdate(d *schema.ResourceData, meta inte instanceDiskPatch, err := instanceDiskPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceDiskPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceDiskPatch: %s", err) } updateInstanceDiskOptions.SetInstanceDiskPatch(instanceDiskPatch) _, _, err = sess.UpdateInstanceDisk(updateInstanceDiskOptions) if err != nil { - return fmt.Errorf("Error updating instance disk: %s", err) + return fmt.Errorf("[ERROR] Error updating instance disk: %s", err) } } diff --git a/ibm/resource_ibm_is_instance_disk_management_test.go b/ibm/service/vpc/resource_ibm_is_instance_disk_management_test.go similarity index 91% rename from ibm/resource_ibm_is_instance_disk_management_test.go rename to ibm/service/vpc/resource_ibm_is_instance_disk_management_test.go index 22c987859..dbaccd421 100644 --- a/ibm/resource_ibm_is_instance_disk_management_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_disk_management_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -26,8 +28,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) diskName := "tfinsdisk01" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name), @@ -36,7 +38,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resource.TestCheckResourceAttr( insResName, "name", name), resource.TestCheckResourceAttr( - insResName, "zone", ISZoneName), + insResName, "zone", acc.ISZoneName), resource.TestCheckResourceAttr( insResName, "disks.#", "1"), resource.TestCheckResourceAttrSet( @@ -45,7 +47,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE insResName, "disks.0.size"), ), }, - resource.TestStep{ + { Config: testAccCheckIBMISInstanceDiskManagementConfig(vpcname, subnetname, sshname, publicKey, volname, name, diskName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(resName, "name"), @@ -61,7 +63,7 @@ func testAccCheckIBMISInstanceDiskManagementConfig(vpcname, subnetname, sshname, return testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name) + fmt.Sprintf(` data "ibm_is_instance" "ins" { name = "%s" - private_key = file("test-fixtures/.ssh/id_rsa") + private_key = file("../../test-fixtures/.ssh/id_rsa") passphrase = "" } data "ibm_is_instance_disks" "test1" { diff --git a/ibm/resource_ibm_is_instance_group.go b/ibm/service/vpc/resource_ibm_is_instance_group.go similarity index 85% rename from ibm/resource_ibm_is_instance_group.go rename to ibm/service/vpc/resource_ibm_is_instance_group.go index ce0f44907..818dc89b4 100644 --- a/ibm/resource_ibm_is_instance_group.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -26,7 +28,7 @@ const ( DELETING = "deleting" ) -func resourceIBMISInstanceGroup() *schema.Resource { +func ResourceIBMISInstanceGroup() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceGroupCreate, Read: resourceIBMISInstanceGroupRead, @@ -37,7 +39,7 @@ func resourceIBMISInstanceGroup() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -52,7 +54,7 @@ func resourceIBMISInstanceGroup() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group", "name"), Description: "The user-defined name for this instance group", }, @@ -66,7 +68,7 @@ func resourceIBMISInstanceGroup() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 0, - ValidateFunc: InvokeValidator("ibm_is_instance_group", "instance_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group", "instance_count"), Description: "The number of instances in the instance group", }, @@ -92,7 +94,7 @@ func resourceIBMISInstanceGroup() *schema.Resource { "application_port": { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group", "application_port"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group", "application_port"), RequiredWith: []string{"load_balancer", "load_balancer_pool"}, Description: "Used by the instance group when scaling up instances to supply the port for the load balancer pool member.", }, @@ -140,51 +142,51 @@ func resourceIBMISInstanceGroup() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_instance_group", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_group", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags for instance group", }, }, } } -func resourceIBMISInstanceGroupValidator() *ResourceValidator { +func ResourceIBMISInstanceGroupValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "instance_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "1000"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "application_port", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISInstanceGroupResourceValidator := ResourceValidator{ResourceName: "ibm_is_instance_group", Schema: validateSchema} + ibmISInstanceGroupResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_group", Schema: validateSchema} return &ibmISInstanceGroupResourceValidator } @@ -243,7 +245,7 @@ func resourceIBMISInstanceGroupCreate(d *schema.ResourceData, meta interface{}) instanceGroup, response, err := sess.CreateInstanceGroup(&instanceGroupOptions) if err != nil || instanceGroup == nil { - return fmt.Errorf("Error Creating InstanceGroup: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating InstanceGroup: %s\n%s", err, response) } d.SetId(*instanceGroup.ID) @@ -255,7 +257,7 @@ func resourceIBMISInstanceGroupCreate(d *schema.ResourceData, meta interface{}) v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk("tags"); ok || v != "" { oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instanceGroup.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instanceGroup.CRN) if err != nil { log.Printf( "Error on create of instance group (%s) tags: %s", d.Id(), err) @@ -281,10 +283,10 @@ func resourceIBMISInstanceGroupUpdate(d *schema.ResourceData, meta interface{}) getInstanceGroupOptions := vpcv1.GetInstanceGroupOptions{ID: &instanceGroupID} instanceGroup, response, err := sess.GetInstanceGroup(&getInstanceGroupOptions) if err != nil || instanceGroup == nil { - return fmt.Errorf("Error getting instance group: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting instance group: %s\n%s", err, response) } oldList, newList := d.GetChange("tags") - err = UpdateTagsUsingCRN(oldList, newList, meta, *instanceGroup.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instanceGroup.CRN) if err != nil { log.Printf( "Error on update of instance group (%s) tags: %s", d.Id(), err) @@ -338,12 +340,12 @@ func resourceIBMISInstanceGroupUpdate(d *schema.ResourceData, meta interface{}) instanceGroupUpdateOptions.ID = &instanceGroupID instanceGroupPatch, err := instanceGroupPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceGroupPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceGroupPatch: %s", err) } instanceGroupUpdateOptions.InstanceGroupPatch = instanceGroupPatch _, response, err := sess.UpdateInstanceGroup(&instanceGroupUpdateOptions) if err != nil { - return fmt.Errorf("Error Updating InstanceGroup: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating InstanceGroup: %s\n%s", err, response) } // wait for instance group health update with update timeout configured. @@ -369,7 +371,7 @@ func resourceIBMISInstanceGroupRead(d *schema.ResourceData, meta interface{}) er d.SetId("") return nil } - return fmt.Errorf("Error Getting InstanceGroup: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup: %s\n%s", err, response) } d.Set("name", *instanceGroup.Name) d.Set("instance_template", *instanceGroup.InstanceTemplate.ID) @@ -398,7 +400,7 @@ func resourceIBMISInstanceGroupRead(d *schema.ResourceData, meta interface{}) er d.Set("status", *instanceGroup.Status) d.Set("vpc", *instanceGroup.VPC.ID) d.Set("crn", *instanceGroup.CRN) - tags, err := GetTagsUsingCRN(meta, *instanceGroup.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *instanceGroup.CRN) if err != nil { log.Printf( "Error on get of instance group (%s) tags: %s", d.Id(), err) @@ -413,7 +415,7 @@ func getLBStatus(sess *vpcv1.VpcV1, lbId string) (string, error) { } lb, response, err := sess.GetLoadBalancer(getlboptions) if err != nil || lb == nil { - return "", fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return "", fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } return *lb.ProvisioningStatus, nil } @@ -445,14 +447,14 @@ func resourceIBMISInstanceGroupDelete(d *schema.ResourceData, meta interface{}) instanceGroupPatchModel.MembershipCount = &zeroMembers instanceGroupPatch, err := instanceGroupPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for ImagePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for ImagePatch: %s", err) } instanceGroupUpdateOptions.ID = &instanceGroupID instanceGroupUpdateOptions.InstanceGroupPatch = instanceGroupPatch _, response, err = sess.UpdateInstanceGroup(&instanceGroupUpdateOptions) if err != nil { - return fmt.Errorf("Error updating instanceGroup's instance count to 0 : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating instanceGroup's instance count to 0 : %s\n%s", err, response) } _, healthError := waitForHealthyInstanceGroup(instanceGroupID, meta, d.Timeout(schema.TimeoutUpdate)) if healthError != nil { @@ -493,7 +495,7 @@ func resourceIBMISInstanceGroupDelete(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error Deleting the InstanceGroup: %s\n%s", Err, response) + return fmt.Errorf("[ERROR] Error Deleting the InstanceGroup: %s\n%s", Err, response) } _, deleteError := waitForInstanceGroupDelete(d, meta) @@ -515,7 +517,7 @@ func resourceIBMISInstanceGroupExists(d *schema.ResourceData, meta interface{}) if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error Getting InstanceGroup: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting InstanceGroup: %s\n%s", err, response) } return true, nil } @@ -534,7 +536,7 @@ func waitForHealthyInstanceGroup(instanceGroupID string, meta interface{}, timeo Refresh: func() (interface{}, string, error) { instanceGroup, response, err := sess.GetInstanceGroup(&getInstanceGroupOptions) if err != nil || instanceGroup == nil { - return nil, SCALING, fmt.Errorf("Error Getting InstanceGroup: %s\n%s", err, response) + return nil, SCALING, fmt.Errorf("[ERROR] Error Getting InstanceGroup: %s\n%s", err, response) } log.Println("Status : ", *instanceGroup.Status) diff --git a/ibm/resource_ibm_is_instance_group_manager.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager.go similarity index 83% rename from ibm/resource_ibm_is_instance_group_manager.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager.go index af34c17e5..2cb7fa8a9 100644 --- a/ibm/resource_ibm_is_instance_group_manager.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager.go @@ -1,17 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMISInstanceGroupManager() *schema.Resource { +func ResourceIBMISInstanceGroupManager() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceGroupManagerCreate, Read: resourceIBMISInstanceGroupManagerRead, @@ -30,7 +32,7 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { "name": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "name"), Description: "instance group manager name", }, @@ -52,7 +54,7 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { Optional: true, Default: "autoscale", ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "manager_type"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "manager_type"), Description: "The type of instance group manager.", }, @@ -60,7 +62,7 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 90, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "aggregation_window"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "aggregation_window"), Description: "The time window in seconds to aggregate metrics prior to evaluation", }, @@ -68,14 +70,14 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 300, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "cooldown"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "cooldown"), Description: "The duration of time in seconds to pause further scale actions after scaling has taken place", }, "max_membership_count": { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "max_membership_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "max_membership_count"), Description: "The maximum number of members in a managed instance group", }, @@ -83,7 +85,7 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager", "min_membership_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager", "min_membership_count"), Description: "The minimum number of members in a managed instance group", }, @@ -124,56 +126,56 @@ func resourceIBMISInstanceGroupManager() *schema.Resource { } } -func resourceIBMISInstanceGroupManagerValidator() *ResourceValidator { +func ResourceIBMISInstanceGroupManagerValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) managerType := "autoscale, scheduled" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "manager_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: managerType}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "aggregation_window", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "90", MaxValue: "600"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "cooldown", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "120", MaxValue: "3600"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "max_membership_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "1000"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "min_membership_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "1000"}) - ibmISInstanceGroupManagerResourceValidator := ResourceValidator{ResourceName: "ibm_is_instance_group_manager", Schema: validateSchema} + ibmISInstanceGroupManagerResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_group_manager", Schema: validateSchema} return &ibmISInstanceGroupManagerResourceValidator } @@ -207,7 +209,7 @@ func resourceIBMISInstanceGroupManagerCreate(d *schema.ResourceData, meta interf } instanceGroupManagerIntf, response, err := sess.CreateInstanceGroupManager(&createInstanceGroupManagerOptions) if err != nil || instanceGroupManagerIntf == nil { - return fmt.Errorf("Error creating InstanceGroup manager: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error creating InstanceGroup manager: %s\n%s", err, response) } instanceGroupManager := instanceGroupManagerIntf.(*vpcv1.InstanceGroupManager) d.SetId(fmt.Sprintf("%s/%s", instanceGroupID, *instanceGroupManager.ID)) @@ -259,7 +261,7 @@ func resourceIBMISInstanceGroupManagerCreate(d *schema.ResourceData, meta interf instanceGroupManagerIntf, response, err := sess.CreateInstanceGroupManager(&createInstanceGroupManagerOptions) if err != nil || instanceGroupManagerIntf == nil { - return fmt.Errorf("Error creating InstanceGroup manager: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error creating InstanceGroup manager: %s\n%s", err, response) } instanceGroupManager := instanceGroupManagerIntf.(*vpcv1.InstanceGroupManager) @@ -321,7 +323,7 @@ func resourceIBMISInstanceGroupManagerUpdate(d *schema.ResourceData, meta interf } if changed { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -331,7 +333,7 @@ func resourceIBMISInstanceGroupManagerUpdate(d *schema.ResourceData, meta interf updateInstanceGroupManagerOptions.InstanceGroupID = &instanceGroupID instanceGroupManagerPatch, err := instanceGroupManagerPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceGroupManagerPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceGroupManagerPatch: %s", err) } updateInstanceGroupManagerOptions.InstanceGroupManagerPatch = instanceGroupManagerPatch @@ -342,7 +344,7 @@ func resourceIBMISInstanceGroupManagerUpdate(d *schema.ResourceData, meta interf _, response, err := sess.UpdateInstanceGroupManager(&updateInstanceGroupManagerOptions) if err != nil { - return fmt.Errorf("Error updating InstanceGroup manager: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating InstanceGroup manager: %s\n%s", err, response) } } return resourceIBMISInstanceGroupManagerRead(d, meta) @@ -354,7 +356,7 @@ func resourceIBMISInstanceGroupManagerRead(d *schema.ResourceData, meta interfac return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -371,7 +373,7 @@ func resourceIBMISInstanceGroupManagerRead(d *schema.ResourceData, meta interfac d.SetId("") return nil } - return fmt.Errorf("Error Getting InstanceGroup Manager: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager: %s\n%s", err, response) } instanceGroupManager := instanceGroupManagerIntf.(*vpcv1.InstanceGroupManager) @@ -426,7 +428,7 @@ func resourceIBMISInstanceGroupManagerDelete(d *schema.ResourceData, meta interf return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -449,7 +451,7 @@ func resourceIBMISInstanceGroupManagerDelete(d *schema.ResourceData, meta interf d.SetId("") return nil } - return fmt.Errorf("Error Deleting the InstanceGroup Manager: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting the InstanceGroup Manager: %s\n%s", err, response) } return nil } diff --git a/ibm/resource_ibm_is_instance_group_manager_action.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager_action.go similarity index 80% rename from ibm/resource_ibm_is_instance_group_manager_action.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager_action.go index a435b1fc0..8eb72c587 100644 --- a/ibm/resource_ibm_is_instance_group_manager_action.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager_action.go @@ -1,18 +1,20 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/go-openapi/strfmt" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMISInstanceGroupManagerAction() *schema.Resource { +func ResourceIBMISInstanceGroupManagerAction() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceGroupManagerActionCreate, Read: resourceIBMISInstanceGroupManagerActionRead, @@ -32,7 +34,7 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { "name": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_action", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_action", "name"), Description: "instance group manager action name", }, @@ -64,7 +66,7 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { "cron_spec": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_action", "cron_spec"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_action", "cron_spec"), Description: "The cron specification for a recurring scheduled action. Actions can be applied a maximum of one time within a 5 min period.", ConflictsWith: []string{"run_at"}, }, @@ -72,15 +74,16 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { "membership_count": { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_action", "membership_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_action", "membership_count"), Description: "The number of members the instance group should have at the scheduled time.", ConflictsWith: []string{"target_manager", "max_membership_count", "min_membership_count"}, + AtLeastOneOf: []string{"target_manager", "membership_count"}, }, "max_membership_count": { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_action", "max_membership_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_action", "max_membership_count"), Description: "The maximum number of members in a managed instance group", ConflictsWith: []string{"membership_count"}, RequiredWith: []string{"target_manager", "min_membership_count"}, @@ -90,7 +93,7 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_action", "min_membership_count"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_action", "min_membership_count"), Description: "The minimum number of members in a managed instance group", ConflictsWith: []string{"membership_count"}, }, @@ -101,6 +104,7 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { Description: "The unique identifier for this instance group manager of type autoscale.", ConflictsWith: []string{"membership_count"}, RequiredWith: []string{"min_membership_count", "max_membership_count"}, + AtLeastOneOf: []string{"target_manager", "membership_count"}, }, "target_manager_name": { @@ -158,49 +162,49 @@ func resourceIBMISInstanceGroupManagerAction() *schema.Resource { } } -func resourceIBMISInstanceGroupManagerActionValidator() *ResourceValidator { +func ResourceIBMISInstanceGroupManagerActionValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "max_membership_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "1000"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "min_membership_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "1000"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "cron_spec", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Regexp: `^((((\d+,)+\d+|([\d\*]+(\/|-)\d+)|\d+|\*) ?){5,7})$`, MinValueLength: 9, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "membership_count", - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "100"}) - ibmISInstanceGroupManagerResourceValidator := ResourceValidator{ResourceName: "ibm_is_instance_group_manager_action", Schema: validateSchema} + ibmISInstanceGroupManagerResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_group_manager_action", Schema: validateSchema} return &ibmISInstanceGroupManagerResourceValidator } @@ -228,7 +232,7 @@ func resourceIBMISInstanceGroupManagerActionCreate(d *schema.ResourceData, meta runat := v.(string) datetime, err := strfmt.ParseDateTime(runat) if err != nil { - return fmt.Errorf("error in converting run_at to datetime format %s", err) + return fmt.Errorf("[ERROR] Error in converting run_at to datetime format %s", err) } instanceGroupManagerActionPrototype.RunAt = &datetime } @@ -271,7 +275,7 @@ func resourceIBMISInstanceGroupManagerActionCreate(d *schema.ResourceData, meta instanceGroupManagerActionIntf, response, err := sess.CreateInstanceGroupManagerAction(&instanceGroupManagerActionOptions) if err != nil || instanceGroupManagerActionIntf == nil { - return fmt.Errorf("error creating InstanceGroup manager Action: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error creating InstanceGroup manager Action: %s\n%s", err, response) } instanceGroupManagerAction := instanceGroupManagerActionIntf.(*vpcv1.InstanceGroupManagerAction) d.SetId(fmt.Sprintf("%s/%s/%s", instanceGroupID, instancegroupmanagerscheduledID, *instanceGroupManagerAction.ID)) @@ -306,7 +310,7 @@ func resourceIBMISInstanceGroupManagerActionUpdate(d *schema.ResourceData, meta runat := d.Get("run_at").(string) datetime, err := strfmt.ParseDateTime(runat) if err != nil { - return fmt.Errorf("error in converting run_at to datetime format %s", err) + return fmt.Errorf("[ERROR] Error in converting run_at to datetime format %s", err) } instanceGroupManagerActionPatchModel.RunAt = &datetime changed = true @@ -337,7 +341,7 @@ func resourceIBMISInstanceGroupManagerActionUpdate(d *schema.ResourceData, meta if changed { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -353,7 +357,7 @@ func resourceIBMISInstanceGroupManagerActionUpdate(d *schema.ResourceData, meta instanceGroupManagerActionPatch, err := instanceGroupManagerActionPatchModel.AsPatch() if err != nil { - return fmt.Errorf("error calling asPatch for instanceGroupManagerActionPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for instanceGroupManagerActionPatch: %s", err) } updateInstanceGroupManagerActionOptions.InstanceGroupManagerActionPatch = instanceGroupManagerActionPatch @@ -363,7 +367,7 @@ func resourceIBMISInstanceGroupManagerActionUpdate(d *schema.ResourceData, meta } _, response, err := sess.UpdateInstanceGroupManagerAction(updateInstanceGroupManagerActionOptions) if err != nil { - return fmt.Errorf("error updating InstanceGroup manager action: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating InstanceGroup manager action: %s\n%s", err, response) } } return resourceIBMISInstanceGroupManagerRead(d, meta) @@ -375,7 +379,7 @@ func resourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta in return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -395,61 +399,61 @@ func resourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta in d.SetId("") return nil } - return fmt.Errorf("error Getting InstanceGroup Manager Action: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Action: %s\n%s", err, response) } instanceGroupManagerAction := instanceGroupManagerActionIntf.(*vpcv1.InstanceGroupManagerAction) if err = d.Set("auto_delete", *instanceGroupManagerAction.AutoDelete); err != nil { - return fmt.Errorf("error setting auto_delete: %s", err) + return fmt.Errorf("[ERROR] Error setting auto_delete: %s", err) } - if err = d.Set("auto_delete_timeout", intValue(instanceGroupManagerAction.AutoDeleteTimeout)); err != nil { - return fmt.Errorf("error setting auto_delete_timeout: %s", err) + if err = d.Set("auto_delete_timeout", flex.IntValue(instanceGroupManagerAction.AutoDeleteTimeout)); err != nil { + return fmt.Errorf("[ERROR] Error setting auto_delete_timeout: %s", err) } if err = d.Set("created_at", instanceGroupManagerAction.CreatedAt.String()); err != nil { - return fmt.Errorf("error setting created_at: %s", err) + return fmt.Errorf("[ERROR] Error setting created_at: %s", err) } if err = d.Set("action_id", *instanceGroupManagerAction.ID); err != nil { - return fmt.Errorf("error setting instance_group_manager_action : %s", err) + return fmt.Errorf("[ERROR] Error setting instance_group_manager_action : %s", err) } if err = d.Set("name", *instanceGroupManagerAction.Name); err != nil { - return fmt.Errorf("error setting name: %s", err) + return fmt.Errorf("[ERROR] Error setting name: %s", err) } if err = d.Set("resource_type", *instanceGroupManagerAction.ResourceType); err != nil { - return fmt.Errorf("error setting resource_type: %s", err) + return fmt.Errorf("[ERROR] Error setting resource_type: %s", err) } if err = d.Set("status", *instanceGroupManagerAction.Status); err != nil { - return fmt.Errorf("error setting status: %s", err) + return fmt.Errorf("[ERROR] Error setting status: %s", err) } if err = d.Set("updated_at", instanceGroupManagerAction.UpdatedAt.String()); err != nil { - return fmt.Errorf("error setting updated_at: %s", err) + return fmt.Errorf("[ERROR] Error setting updated_at: %s", err) } if err = d.Set("action_type", *instanceGroupManagerAction.ActionType); err != nil { - return fmt.Errorf("error setting action_type: %s", err) + return fmt.Errorf("[ERROR] Error setting action_type: %s", err) } if instanceGroupManagerAction.CronSpec != nil { if err = d.Set("cron_spec", *instanceGroupManagerAction.CronSpec); err != nil { - return fmt.Errorf("error setting cron_spec: %s", err) + return fmt.Errorf("[ERROR] Error setting cron_spec: %s", err) } } if instanceGroupManagerAction.LastAppliedAt != nil { if err = d.Set("last_applied_at", instanceGroupManagerAction.LastAppliedAt.String()); err != nil { - return fmt.Errorf("error setting last_applied_at: %s", err) + return fmt.Errorf("[ERROR] Error setting last_applied_at: %s", err) } } if instanceGroupManagerAction.NextRunAt != nil { if err = d.Set("next_run_at", instanceGroupManagerAction.NextRunAt.String()); err != nil { - return fmt.Errorf("error setting next_run_at: %s", err) + return fmt.Errorf("[ERROR] Error setting next_run_at: %s", err) } } instanceGroupManagerScheduledActionGroupGroup := instanceGroupManagerAction.Group if instanceGroupManagerScheduledActionGroupGroup != nil && instanceGroupManagerScheduledActionGroupGroup.MembershipCount != nil { - d.Set("membership_count", intValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount)) + d.Set("membership_count", flex.IntValue(instanceGroupManagerScheduledActionGroupGroup.MembershipCount)) } instanceGroupManagerScheduledActionManagerManagerInt := instanceGroupManagerAction.Manager if instanceGroupManagerScheduledActionManagerManagerInt != nil { @@ -457,9 +461,9 @@ func resourceIBMISInstanceGroupManagerActionRead(d *schema.ResourceData, meta in if instanceGroupManagerScheduledActionManagerManager != nil && instanceGroupManagerScheduledActionManagerManager.ID != nil { if instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount != nil { - d.Set("max_membership_count", intValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount)) + d.Set("max_membership_count", flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MaxMembershipCount)) } - d.Set("min_membership_count", intValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount)) + d.Set("min_membership_count", flex.IntValue(instanceGroupManagerScheduledActionManagerManager.MinMembershipCount)) d.Set("target_manager_name", *instanceGroupManagerScheduledActionManagerManager.Name) d.Set("target_manager", *instanceGroupManagerScheduledActionManagerManager.ID) } @@ -474,7 +478,7 @@ func resourceIBMISInstanceGroupManagerActionDelete(d *schema.ResourceData, meta return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -498,7 +502,7 @@ func resourceIBMISInstanceGroupManagerActionDelete(d *schema.ResourceData, meta d.SetId("") return nil } - return fmt.Errorf("error Deleting the InstanceGroup Manager Action: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting the InstanceGroup Manager Action: %s\n%s", err, response) } return nil } @@ -510,7 +514,7 @@ func resourceIBMISInstanceGroupManagerActionExists(d *schema.ResourceData, meta return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -529,7 +533,7 @@ func resourceIBMISInstanceGroupManagerActionExists(d *schema.ResourceData, meta if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("error Getting InstanceGroup Manager Action: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Action: %s\n%s", err, response) } return true, nil diff --git a/ibm/resource_ibm_is_instance_group_manager_action_test.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager_action_test.go similarity index 88% rename from ibm/resource_ibm_is_instance_group_manager_action_test.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager_action_test.go index 83d6d31d6..699f2d584 100644 --- a/ibm/resource_ibm_is_instance_group_manager_action_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager_action_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -28,8 +32,8 @@ func TestAccIBMISInstanceGroupManagerAction_basic(t *testing.T) { instanceGroupManagerAction := fmt.Sprintf("testinstancegroupmanageraction%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerActionDestroy, Steps: []resource.TestStep{ { @@ -58,14 +62,15 @@ func TestAccIBMISInstanceGroupManagerAction_basic_autoscale(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManagerAutoscale := fmt.Sprintf("testinstancegroupmanagerautoscale%d", randInt) instanceGroupManagerAction := fmt.Sprintf("testinstancegroupmanageraction%d", randInt) + instanceGroupManagerPolicyAction := fmt.Sprintf("testinstancegroupmanagerpolicy%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerActionDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerAction), + Config: testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerPolicyAction, instanceGroupManagerAction), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "ibm_is_instance_group_manager.instance_group_manager", "name", instanceGroupManager), @@ -78,14 +83,14 @@ func TestAccIBMISInstanceGroupManagerAction_basic_autoscale(t *testing.T) { } func testAccCheckIBMISInstanceGroupManagerActionDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_instance_group_manager_action" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -132,7 +137,7 @@ func testAccCheckIBMISInstanceGroupManagerActionConfig(vpcName, subnetName, sshK resource "ibm_is_instance_template" "instancetemplate1" { name = "%s" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + image = "%s" profile = "bx2-8x32" primary_network_interface { @@ -166,11 +171,11 @@ func testAccCheckIBMISInstanceGroupManagerActionConfig(vpcName, subnetName, sshK membership_count = 1 } - `, vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAction) + `, vpcName, subnetName, sshKeyName, publicKey, templateName, acc.IsImage, instanceGroupName, instanceGroupManager, instanceGroupManagerAction) } -func testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerAction string) string { +func testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerPolicyAction, instanceGroupManagerAction string) string { return fmt.Sprintf(` provider "ibm" { generation = 2 @@ -194,7 +199,7 @@ func testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetN resource "ibm_is_instance_template" "instancetemplate1" { name = "%s" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + image = "%s" profile = "bx2-8x32" primary_network_interface { @@ -237,7 +242,7 @@ func testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetN metric_type = "cpu" metric_value = 70 policy_type = "target" - name = "instancegrouppolicysunitha" + name = "%s" } resource "ibm_is_instance_group_manager_action" "instance_group_manager_action" { @@ -250,6 +255,6 @@ func testAccCheckIBMISInstanceGroupManagerActionAutoscaleConfig(vpcName, subnetN max_membership_count = 2 } - `, vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerAction) + `, vpcName, subnetName, sshKeyName, publicKey, templateName, acc.IsImage, instanceGroupName, instanceGroupManager, instanceGroupManagerAutoscale, instanceGroupManagerPolicyAction, instanceGroupManagerAction) } diff --git a/ibm/resource_ibm_is_instance_group_manager_policy.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager_policy.go similarity index 78% rename from ibm/resource_ibm_is_instance_group_manager_policy.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager_policy.go index c21835d7e..118b4bf5b 100644 --- a/ibm/resource_ibm_is_instance_group_manager_policy.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager_policy.go @@ -1,16 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceIBMISInstanceGroupManagerPolicy() *schema.Resource { +func ResourceIBMISInstanceGroupManagerPolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceGroupManagerPolicyCreate, Read: resourceIBMISInstanceGroupManagerPolicyRead, @@ -24,7 +27,7 @@ func resourceIBMISInstanceGroupManagerPolicy() *schema.Resource { "name": { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_policy", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_policy", "name"), Description: "instance group manager policy name", }, @@ -43,7 +46,7 @@ func resourceIBMISInstanceGroupManagerPolicy() *schema.Resource { "metric_type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_policy", "metric_type"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_policy", "metric_type"), Description: "The type of metric to be evaluated", }, @@ -56,7 +59,7 @@ func resourceIBMISInstanceGroupManagerPolicy() *schema.Resource { "policy_type": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_manager_policy", "policy_type"), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_manager_policy", "policy_type"), Description: "The type of Policy for the Instance Group", }, @@ -69,36 +72,36 @@ func resourceIBMISInstanceGroupManagerPolicy() *schema.Resource { } } -func resourceIBMISInstanceGroupManagerPolicyValidator() *ResourceValidator { +func ResourceIBMISInstanceGroupManagerPolicyValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) metricTypes := "cpu,memory,network_in,network_out" policyType := "target" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "metric_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: metricTypes}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "policy_type", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: policyType}) - ibmISInstanceGroupManagerPolicyResourceValidator := ResourceValidator{ResourceName: "ibm_is_instance_group_manager_policy", Schema: validateSchema} + ibmISInstanceGroupManagerPolicyResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_group_manager_policy", Schema: validateSchema} return &ibmISInstanceGroupManagerPolicyResourceValidator } @@ -130,8 +133,8 @@ func resourceIBMISInstanceGroupManagerPolicyCreate(d *schema.ResourceData, meta } isInsGrpKey := "Instance_Group_Key_" + instanceGroupID - ibmMutexKV.Lock(isInsGrpKey) - defer ibmMutexKV.Unlock(isInsGrpKey) + conns.IbmMutexKV.Lock(isInsGrpKey) + defer conns.IbmMutexKV.Unlock(isInsGrpKey) _, healthError := waitForHealthyInstanceGroup(instanceGroupID, meta, d.Timeout(schema.TimeoutCreate)) if healthError != nil { @@ -140,7 +143,7 @@ func resourceIBMISInstanceGroupManagerPolicyCreate(d *schema.ResourceData, meta data, response, err := sess.CreateInstanceGroupManagerPolicy(&createInstanceGroupManagerPolicyOptions) if err != nil || data == nil { - return fmt.Errorf("Error Creating InstanceGroup Manager Policy: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating InstanceGroup Manager Policy: %s\n%s", err, response) } instanceGroupManagerPolicy := data.(*vpcv1.InstanceGroupManagerPolicy) @@ -178,7 +181,7 @@ func resourceIBMISInstanceGroupManagerPolicyUpdate(d *schema.ResourceData, meta } if changed { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -191,8 +194,8 @@ func resourceIBMISInstanceGroupManagerPolicyUpdate(d *schema.ResourceData, meta updateInstanceGroupManagerPolicyOptions.InstanceGroupManagerID = &instanceGroupManagerID isInsGrpKey := "Instance_Group_Key_" + instanceGroupID - ibmMutexKV.Lock(isInsGrpKey) - defer ibmMutexKV.Unlock(isInsGrpKey) + conns.IbmMutexKV.Lock(isInsGrpKey) + defer conns.IbmMutexKV.Unlock(isInsGrpKey) _, healthError := waitForHealthyInstanceGroup(instanceGroupID, meta, d.Timeout(schema.TimeoutUpdate)) if healthError != nil { @@ -201,7 +204,7 @@ func resourceIBMISInstanceGroupManagerPolicyUpdate(d *schema.ResourceData, meta _, response, err := sess.UpdateInstanceGroupManagerPolicy(&updateInstanceGroupManagerPolicyOptions) if err != nil { - return fmt.Errorf("Error Updating InstanceGroup Manager Policy: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating InstanceGroup Manager Policy: %s\n%s", err, response) } } return resourceIBMISInstanceGroupManagerPolicyRead(d, meta) @@ -213,7 +216,7 @@ func resourceIBMISInstanceGroupManagerPolicyRead(d *schema.ResourceData, meta in return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -232,7 +235,7 @@ func resourceIBMISInstanceGroupManagerPolicyRead(d *schema.ResourceData, meta in d.SetId("") return nil } - return fmt.Errorf("Error Getting InstanceGroup Manager Policy: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Policy: %s\n%s", err, response) } instanceGroupManagerPolicy := data.(*vpcv1.InstanceGroupManagerPolicy) d.Set("name", *instanceGroupManagerPolicy.Name) @@ -251,7 +254,7 @@ func resourceIBMISInstanceGroupManagerPolicyDelete(d *schema.ResourceData, meta if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -266,8 +269,8 @@ func resourceIBMISInstanceGroupManagerPolicyDelete(d *schema.ResourceData, meta } isInsGrpKey := "Instance_Group_Key_" + instanceGroupID - ibmMutexKV.Lock(isInsGrpKey) - defer ibmMutexKV.Unlock(isInsGrpKey) + conns.IbmMutexKV.Lock(isInsGrpKey) + defer conns.IbmMutexKV.Unlock(isInsGrpKey) _, healthError := waitForHealthyInstanceGroup(instanceGroupID, meta, d.Timeout(schema.TimeoutDelete)) if healthError != nil { @@ -280,7 +283,7 @@ func resourceIBMISInstanceGroupManagerPolicyDelete(d *schema.ResourceData, meta d.SetId("") return nil } - return fmt.Errorf("Error Deleting the InstanceGroup Manager Policy: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting the InstanceGroup Manager Policy: %s\n%s", err, response) } return nil } @@ -291,13 +294,13 @@ func resourceIBMISInstanceGroupManagerPolicyExists(d *schema.ResourceData, meta return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 3 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of instanceGroupID/instanceGroupManagerID/instanceGroupManagerPolicyID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of instanceGroupID/instanceGroupManagerID/instanceGroupManagerPolicyID", d.Id()) } instanceGroupID := parts[0] instanceGroupManagerID := parts[1] @@ -314,7 +317,7 @@ func resourceIBMISInstanceGroupManagerPolicyExists(d *schema.ResourceData, meta if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error Getting InstanceGroup Manager Policy: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error Getting InstanceGroup Manager Policy: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_instance_group_manager_policy_test.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager_policy_test.go similarity index 94% rename from ibm/resource_ibm_is_instance_group_manager_policy_test.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager_policy_test.go index 5287c3f67..16d3405db 100644 --- a/ibm/resource_ibm_is_instance_group_manager_policy_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager_policy_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -27,8 +30,8 @@ func TestAccIBMISInstanceGroupManagerPolicy_basic(t *testing.T) { instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) instanceGroupManagerPolicy := fmt.Sprintf("testinstancegroupmanagerpolicy%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupManagerPolicyDestroy, Steps: []resource.TestStep{ { @@ -49,7 +52,7 @@ func TestAccIBMISInstanceGroupManagerPolicy_basic(t *testing.T) { } func testAccCheckIBMISInstanceGroupManagerPolicyDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_instance_group_manager_policy" { continue diff --git a/ibm/resource_ibm_is_instance_group_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_group_manager_test.go similarity index 95% rename from ibm/resource_ibm_is_instance_group_manager_test.go rename to ibm/service/vpc/resource_ibm_is_instance_group_manager_test.go index fd68241fd..3600faeff 100644 --- a/ibm/resource_ibm_is_instance_group_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_manager_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -26,8 +29,8 @@ func TestAccIBMISInstanceGroupManager_basic(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagerConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), @@ -58,8 +61,8 @@ func TestAccIBMISInstanceGroupManager_basic_scheduled(t *testing.T) { sshKeyName := fmt.Sprintf("testsshkey%d", randInt) instanceGroupManager := fmt.Sprintf("testinstancegroupmanager%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceGroupManagerConfigScheduled(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, instanceGroupManager), @@ -73,7 +76,7 @@ func TestAccIBMISInstanceGroupManager_basic_scheduled(t *testing.T) { } func testAccCheckIBMISInstanceGroupManagerDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_instance_group_manager" { continue diff --git a/ibm/resource_ibm_is_instance_group_membership.go b/ibm/service/vpc/resource_ibm_is_instance_group_membership.go similarity index 85% rename from ibm/resource_ibm_is_instance_group_membership.go rename to ibm/service/vpc/resource_ibm_is_instance_group_membership.go index 20a0e2809..e109415c8 100644 --- a/ibm/resource_ibm_is_instance_group_membership.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_membership.go @@ -1,11 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -26,7 +28,7 @@ const ( isInstanceGroupMembershipStatus = "status" ) -func resourceIBMISInstanceGroupMembership() *schema.Resource { +func ResourceIBMISInstanceGroupMembership() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceGroupMembershipUpdate, Read: resourceIBMISInstanceGroupMembershipRead, @@ -40,19 +42,19 @@ func resourceIBMISInstanceGroupMembership() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_membership", isInstanceGroup), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_membership", isInstanceGroup), Description: "The instance group identifier.", }, isInstanceGroupMembership: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_membership", isInstanceGroupMembership), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_membership", isInstanceGroupMembership), Description: "The unique identifier for this instance group membership.", }, isInstanceGroupMembershipName: { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_instance_group_membership", isInstanceGroupMembershipName), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_group_membership", isInstanceGroupMembershipName), Description: "The user-defined name for this instance group membership. Names must be unique within the instance group.", }, isInstanceGroupMemershipActionDelete: { @@ -126,37 +128,37 @@ func resourceIBMISInstanceGroupMembership() *schema.Resource { } } -func resourceIBMISInstanceGroupMembershipValidator() *ResourceValidator { +func ResourceIBMISInstanceGroupMembershipValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isInstanceGroupMembershipName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isInstanceGroup, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^[-0-9a-z_]+$`, MinValueLength: 1, MaxValueLength: 64}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isInstanceGroupMembership, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^[-0-9a-z_]+$`, MinValueLength: 1, MaxValueLength: 64}) - ibmISInstanceGroupMembershipResourceValidator := ResourceValidator{ResourceName: "ibm_is_instance_group_membership", Schema: validateSchema} + ibmISInstanceGroupMembershipResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_group_membership", Schema: validateSchema} return &ibmISInstanceGroupMembershipResourceValidator } @@ -176,7 +178,7 @@ func resourceIBMISInstanceGroupMembershipUpdate(d *schema.ResourceData, meta int instanceGroupMembership, response, err := sess.GetInstanceGroupMembership(&getInstanceGroupMembershipOptions) if err != nil || instanceGroupMembership == nil { - return fmt.Errorf("Error Getting InstanceGroup Membership: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Membership: %s\n%s", err, response) } d.SetId(fmt.Sprintf("%s/%s", instanceGroupID, instanceGroupMembershipID)) @@ -199,12 +201,12 @@ func resourceIBMISInstanceGroupMembershipUpdate(d *schema.ResourceData, meta int updateInstanceGroupMembershipOptions.InstanceGroupID = &instanceGroupID instanceGroupMembershipPatch, err := instanceGroupMembershipPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstanceGroupMembershipPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceGroupMembershipPatch: %s", err) } updateInstanceGroupMembershipOptions.InstanceGroupMembershipPatch = instanceGroupMembershipPatch _, response, err := sess.UpdateInstanceGroupMembership(&updateInstanceGroupMembershipOptions) if err != nil { - return fmt.Errorf("Error updating InstanceGroup Membership: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating InstanceGroup Membership: %s\n%s", err, response) } } } @@ -217,7 +219,7 @@ func resourceIBMISInstanceGroupMembershipRead(d *schema.ResourceData, meta inter return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -234,7 +236,7 @@ func resourceIBMISInstanceGroupMembershipRead(d *schema.ResourceData, meta inter d.SetId("") return nil } - return fmt.Errorf("Error Getting InstanceGroup Membership: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting InstanceGroup Membership: %s\n%s", err, response) } d.Set(isInstanceGroupMemershipDeleteInstanceOnMembershipDelete, *instanceGroupMembership.DeleteInstanceOnMembershipDelete) d.Set(isInstanceGroupMembership, *instanceGroupMembership.ID) @@ -274,7 +276,7 @@ func resourceIBMISInstanceGroupMembershipDelete(d *schema.ResourceData, meta int return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -291,7 +293,7 @@ func resourceIBMISInstanceGroupMembershipDelete(d *schema.ResourceData, meta int d.SetId("") return nil } - return fmt.Errorf("Error Deleting the InstanceGroup Membership: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting the InstanceGroup Membership: %s\n%s", err, response) } return nil } diff --git a/ibm/resource_ibm_is_instance_group_membership_test.go b/ibm/service/vpc/resource_ibm_is_instance_group_membership_test.go similarity index 93% rename from ibm/resource_ibm_is_instance_group_membership_test.go rename to ibm/service/vpc/resource_ibm_is_instance_group_membership_test.go index 5f28221b9..a9f5b0995 100644 --- a/ibm/resource_ibm_is_instance_group_membership_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_membership_test.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -25,8 +27,8 @@ func TestAccIbmIsInstanceGroupMembershipResource_Basic(t *testing.T) { membershipName := fmt.Sprintf("testmembershipname%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { Config: testAccCheckIbmIsInstanceGroupMembershipResourceConfigBasic(vpcName, subnetName, sshKeyName, publicKey, templateName, instanceGroupName, membershipName), diff --git a/ibm/resource_ibm_is_instance_group_test.go b/ibm/service/vpc/resource_ibm_is_instance_group_test.go similarity index 91% rename from ibm/resource_ibm_is_instance_group_test.go rename to ibm/service/vpc/resource_ibm_is_instance_group_test.go index 6a5d05711..5ffaea391 100644 --- a/ibm/resource_ibm_is_instance_group_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_group_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -25,8 +28,8 @@ func TestAccIBMISInstanceGroup_basic(t *testing.T) { templateName := fmt.Sprintf("testtemplate%d", randInt) sshKeyName := fmt.Sprintf("testsshkey%d", randInt) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, Steps: []resource.TestStep{ { @@ -65,12 +68,12 @@ func TestAccIBMISInstanceGroup_basic_loadbalancer(t *testing.T) { healthType1 := "http" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, Steps: []resource.TestStep{ // { - // Config: testAccCheckIBMISLBPoolConfig(vpcName, subnetName, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), + // Config: testAccCheckIBMISLBPoolConfig(vpcName, subnetName, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), // Check: resource.ComposeTestCheckFunc( // testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), // resource.TestCheckResourceAttr( @@ -94,7 +97,7 @@ func TestAccIBMISInstanceGroup_basic_loadbalancer(t *testing.T) { // ), // }, { - Config: testAccCheckIBMISInstanceGrouplbConfig(vpcName, subnetName, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, sshKeyName, publicKey, templateName, instanceGroupName), + Config: testAccCheckIBMISInstanceGrouplbConfig(vpcName, subnetName, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, sshKeyName, publicKey, templateName, instanceGroupName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "ibm_is_instance_group.instance_group", "name", instanceGroupName), @@ -107,7 +110,7 @@ func TestAccIBMISInstanceGroup_basic_loadbalancer(t *testing.T) { } func testAccCheckIBMISInstanceGroupDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_instance_group" { continue @@ -225,6 +228,6 @@ func testAccCheckIBMISInstanceGroupConfig(vpcName, subnetName, sshKeyName, publi instance_count = 2 subnets = [ibm_is_subnet.subnet2.id] } - `, vpcName, subnetName, sshKeyName, publicKey, templateName, isImage, instanceGroupName) + `, vpcName, subnetName, sshKeyName, publicKey, templateName, acc.IsImage, instanceGroupName) } diff --git a/ibm/service/vpc/resource_ibm_is_instance_network_interface.go b/ibm/service/vpc/resource_ibm_is_instance_network_interface.go new file mode 100644 index 000000000..053a474f8 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_network_interface.go @@ -0,0 +1,822 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isNetworkInterfacePending = "pending" + isNetworkInterfaceAvailable = "available" + isNetworkInterfaceFailed = "failed" + isNetworkInterfaceDeleting = "deleting" + isNetworkInterfaceDeleted = "deleted" +) + +func ResourceIBMIsInstanceNetworkInterface() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsInstanceNetworkInterfaceCreate, + ReadContext: resourceIBMIsInstanceNetworkInterfaceRead, + UpdateContext: resourceIBMIsInstanceNetworkInterfaceUpdate, + DeleteContext: resourceIBMIsInstanceNetworkInterfaceDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique identifier of the instance.", + }, + isInstanceNicSubnet: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique identifier of the subnet.", + }, + isInstanceNicAllowIPSpoofing: &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + }, + isInstanceNicName: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_interface", isInstanceNicName), + Description: "The user-defined name for this network interface. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + isInstanceNicPrimaryIpv4Address: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"primary_ip.0.address"}, + Deprecated: "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead", + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_interface", isInstanceNicPrimaryIpv4Address), + Description: "The primary IPv4 address. If specified, it must be an available address on the network interface's subnet. If unspecified, an available address on the subnet will be automatically selected.", + }, + isInstanceNicPrimaryIP: { + Type: schema.TypeList, + MinItems: 0, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceNicReservedIpAddress: { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Optional: true, + ConflictsWith: []string{"primary_ipv4_address"}, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceNicReservedIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isInstanceNicReservedIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isInstanceNicReservedIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceNicReservedIpId: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_ipv4_address"}, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isInstanceNicReservedIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + "network_interface": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique ID of this network interface", + }, + isInstanceNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the network interface was created.", + }, + isInstanceNicFloatingIP: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The ID of the floating IP to attach to this network interface", + }, + isInstanceNicFloatingIPs: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The floating IPs associated with this network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + "id": { + Type: schema.TypeString, + Optional: true, + Description: "The unique identifier for this floating IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this floating IP.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this network interface.", + }, + "port_speed": { + Type: schema.TypeInt, + Computed: true, + Description: "The network interface port speed in Mbps.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the network interface.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of this network interface as it relates to an instance.", + }, + }, + } +} + +func ResourceIBMIsInstanceNetworkInterfaceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceNicName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: isInstanceNicPrimaryIpv4Address, + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Optional: true, + Regexp: `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_network_interface", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsInstanceNetworkInterfaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + instance_id := d.Get("instance").(string) + + createInstanceNetworkInterfaceOptions := &vpcv1.CreateInstanceNetworkInterfaceOptions{} + + createInstanceNetworkInterfaceOptions.SetInstanceID(instance_id) + + subnetId := d.Get(isInstanceNicSubnet).(string) + subnetIdentity := vpcv1.SubnetIdentity{ + ID: &subnetId, + } + createInstanceNetworkInterfaceOptions.SetSubnet(&subnetIdentity) + if allow_ip_spoofing, ok := d.GetOk(isInstanceNicAllowIPSpoofing); ok { + createInstanceNetworkInterfaceOptions.SetAllowIPSpoofing(allow_ip_spoofing.(bool)) + } + if name, ok := d.GetOk(isInstanceNicName); ok { + createInstanceNetworkInterfaceOptions.SetName(name.(string)) + } + + var primary_ipv4, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool + if primary_ipv4Ok, ok := d.GetOk(isInstanceNicPrimaryIpv4Address); ok { + primary_ipv4 = primary_ipv4Ok.(string) + } + + //reserved ip changes + if primaryIpOk, ok := d.GetOk(isInstanceNicPrimaryIP); ok { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceNicReservedIpId] + reservedIp = reservedipok.(string) + reservedipv4Ok, _ := primip[isInstanceNicReservedIpAddress] + reservedipv4 = reservedipv4Ok.(string) + + reservedipnameOk, _ := primip[isInstanceNicReservedIpName] + reservedipname = reservedipnameOk.(string) + + reservedipautodeleteok, okAuto := primip[isInstanceNicReservedIpAutoDelete] + if okAuto { + autodelete = reservedipautodeleteok.(bool) + } + } + + if primary_ipv4 != "" && reservedipv4 != "" && primary_ipv4 != reservedipv4 { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", primary_ipv4, reservedipv4)) + } + if reservedIp != "" && (primary_ipv4 != "" || reservedipv4 != "" || reservedipname != "") { + return diag.FromErr(fmt.Errorf("[ERROR] Error creating instance, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp)) + } + if reservedIp != "" { + createInstanceNetworkInterfaceOptions.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if primary_ipv4 != "" || reservedipv4 != "" || reservedipname != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if primary_ipv4 != "" { + primaryipobj.Address = &primary_ipv4 + } + if reservedipv4 != "" { + primaryipobj.Address = &reservedipv4 + } + if reservedipname != "" { + primaryipobj.Name = &reservedipname + } + if okAuto { + primaryipobj.AutoDelete = &autodelete + } + createInstanceNetworkInterfaceOptions.PrimaryIP = primaryipobj + } + } + + if secgrpintf, ok := d.GetOk(isInstanceNicSecurityGroups); ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + createInstanceNetworkInterfaceOptions.SecurityGroups = secgrpobjs + } + } + + isNICKey := "instance_key_" + instance_id + conns.IbmMutexKV.Lock(isNICKey) + defer conns.IbmMutexKV.Unlock(isNICKey) + + networkInterface, response, err := vpcClient.CreateInstanceNetworkInterfaceWithContext(context, createInstanceNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] CreateInstanceNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateInstanceNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createInstanceNetworkInterfaceOptions.InstanceID, *networkInterface.ID)) + d.Set("network_interface", *networkInterface.ID) + + _, err = isWaitForNetworkInterfaceAvailable(vpcClient, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error occured while waiting for network interface %s", err)) + } + + if floating_ip_Intf, ok := d.GetOk(isInstanceNicFloatingIP); ok && floating_ip_Intf.(string) != "" { + floating_ip_id := floating_ip_Intf.(string) + + addInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.AddInstanceNetworkInterfaceFloatingIPOptions{ + InstanceID: createInstanceNetworkInterfaceOptions.InstanceID, + NetworkInterfaceID: networkInterface.ID, + ID: &floating_ip_id, + } + + _, response, err := vpcClient.AddInstanceNetworkInterfaceFloatingIP(addInstanceNetworkInterfaceFloatingIPOptions) + + if err != nil { + d.Set(isInstanceNicFloatingIP, "") + return diag.FromErr(fmt.Errorf("[DEBUG] Error adding Floating IP to network interface %s\n%s", err, response)) + } + _, err = isWaitForNetworkInterfaceAvailable(vpcClient, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error occured while waiting for network interface %s", err)) + } + + } + + _, err = isWaitForInstanceAvailable(vpcClient, instance_id, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + return resourceIBMIsInstanceNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsInstanceNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + getInstanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getInstanceNetworkInterfaceOptions.SetInstanceID(parts[0]) + getInstanceNetworkInterfaceOptions.SetID(parts[1]) + + networkInterface, response, err := vpcClient.GetInstanceNetworkInterfaceWithContext(context, getInstanceNetworkInterfaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetInstanceNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInstanceNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + d.SetId(fmt.Sprintf("%s/%s", parts[0], *networkInterface.ID)) + d.Set("network_interface", *networkInterface.ID) + d.Set("instance", parts[0]) + if err = d.Set(isInstanceNicSubnet, *networkInterface.Subnet.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnet: %s", err)) + } + if err = d.Set(isInstanceNicAllowIPSpoofing, *networkInterface.AllowIPSpoofing); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allow_ip_spoofing: %s", err)) + } + if err = d.Set(isInstanceNicName, *networkInterface.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if networkInterface.PrimaryIP != nil { + if err = d.Set(isInstanceNicPrimaryIpv4Address, *networkInterface.PrimaryIP.Address); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_ipv4_address: %s", err)) + } + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + + if networkInterface.PrimaryIP.Address != nil { + currentPrimIp[isInstanceNicReservedIpAddress] = *networkInterface.PrimaryIP.Address + } + if networkInterface.PrimaryIP.Href != nil { + currentPrimIp[isInstanceNicReservedIpHref] = *networkInterface.PrimaryIP.Href + } + if networkInterface.PrimaryIP.Name != nil { + currentPrimIp[isInstanceNicReservedIpName] = *networkInterface.PrimaryIP.Name + } + if networkInterface.PrimaryIP.ID != nil { + currentPrimIp[isInstanceNicReservedIpId] = *networkInterface.PrimaryIP.ID + } + if networkInterface.PrimaryIP.ResourceType != nil { + currentPrimIp[isInstanceNicReservedIpResourceType] = *networkInterface.PrimaryIP.ResourceType + } + getripoptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: networkInterface.Subnet.ID, + ID: networkInterface.PrimaryIP.ID, + } + insRip, response, err := vpcClient.GetSubnetReservedIP(getripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the instance network interface(%s): %s\n%s", *networkInterface.PrimaryIP.ID, *networkInterface.ID, err, response)) + } + currentPrimIp[isInstanceNicReservedIpAutoDelete] = insRip.AutoDelete + + primaryIpList = append(primaryIpList, currentPrimIp) + d.Set(isInstanceNicPrimaryIP, primaryIpList) + } + if networkInterface.SecurityGroups != nil && len(networkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for _, secGrp := range networkInterface.SecurityGroups { + secgrpList = append(secgrpList, string(*(secGrp.ID))) + } + d.Set("security_groups", flex.NewStringSet(schema.HashString, secgrpList)) + } + + if err = d.Set("created_at", flex.DateTimeToString(networkInterface.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + floatingIps := []map[string]interface{}{} + if networkInterface.FloatingIps != nil { + + for _, floatingIpsItem := range networkInterface.FloatingIps { + floatingIpsItemMap := resourceIBMIsInstanceNetworkInterfaceFloatingIPReferenceToMap(floatingIpsItem) + floatingIps = append(floatingIps, floatingIpsItemMap) + } + } + if err = d.Set(isInstanceNicFloatingIPs, floatingIps); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting floating_ips: %s", err)) + } + if err = d.Set("href", networkInterface.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(networkInterface.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("resource_type", networkInterface.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("status", networkInterface.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + if err = d.Set("type", networkInterface.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + return nil +} + +func resourceIBMIsInstanceNetworkInterfaceFloatingIPReferenceToMap(floatingIPReference vpcv1.FloatingIPReference) map[string]interface{} { + floatingIPReferenceMap := map[string]interface{}{} + + floatingIPReferenceMap["address"] = floatingIPReference.Address + floatingIPReferenceMap["crn"] = floatingIPReference.CRN + if floatingIPReference.Deleted != nil { + DeletedMap := resourceIBMIsInstanceNetworkInterfaceFloatingIPReferenceDeletedToMap(*floatingIPReference.Deleted) + floatingIPReferenceMap["deleted"] = []map[string]interface{}{DeletedMap} + } + floatingIPReferenceMap["href"] = floatingIPReference.Href + floatingIPReferenceMap["id"] = floatingIPReference.ID + floatingIPReferenceMap["name"] = floatingIPReference.Name + + return floatingIPReferenceMap +} + +func resourceIBMIsInstanceNetworkInterfaceFloatingIPReferenceDeletedToMap(floatingIPReferenceDeleted vpcv1.FloatingIPReferenceDeleted) map[string]interface{} { + floatingIPReferenceDeletedMap := map[string]interface{}{} + + floatingIPReferenceDeletedMap["more_info"] = floatingIPReferenceDeleted.MoreInfo + + return floatingIPReferenceDeletedMap +} + +func resourceIBMIsInstanceNetworkInterfaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + updateInstanceNetworkInterfaceOptions := &vpcv1.UpdateInstanceNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + instance_id := parts[0] + network_interface_id := parts[1] + updateInstanceNetworkInterfaceOptions.SetInstanceID(instance_id) + updateInstanceNetworkInterfaceOptions.SetID(network_interface_id) + + hasChange := false + + patchVals := &vpcv1.NetworkInterfacePatch{} + + if d.HasChange(isInstanceNicAllowIPSpoofing) { + patchVals.AllowIPSpoofing = core.BoolPtr(d.Get(isInstanceNicAllowIPSpoofing).(bool)) + hasChange = true + } + if d.HasChange(isInstanceNicName) { + patchVals.Name = core.StringPtr(d.Get(isInstanceNicName).(string)) + hasChange = true + } + if !d.IsNewResource() && (d.HasChange("primary_network_interface.0.primary_ip.0.name") || d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete")) { + subnetId := d.Get(isBareMetalServerNicSubnet).(string) + ripId := d.Get("primary_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_network_interface.0.primary_ip.0.name") { + name := d.Get("primary_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("primary_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := vpcClient.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating instance network interface reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + + if d.HasChange(isInstanceNicSecurityGroups) && !d.IsNewResource() { + + ovs, nvs := d.GetChange(isInstanceNicSecurityGroups) + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &network_interface_id, + } + _, response, err := vpcClient.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating security group %q for network interface of instance %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForInstanceAvailable(vpcClient, instance_id, d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &network_interface_id, + } + response, err := vpcClient.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while removing security group %q for network interface of instance %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForInstanceAvailable(vpcClient, instance_id, d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(err) + } + } + } + hasChange = true + } + if hasChange { + isNICKey := "instance_key_" + instance_id + conns.IbmMutexKV.Lock(isNICKey) + defer conns.IbmMutexKV.Unlock(isNICKey) + updateInstanceNetworkInterfaceOptions.NetworkInterfacePatch, _ = patchVals.AsPatch() + _, response, err := vpcClient.UpdateInstanceNetworkInterfaceWithContext(context, updateInstanceNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateInstanceNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateInstanceNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + } + + if d.HasChange(isInstanceNicFloatingIP) { + floating_ip_id_old, floating_ip_id_new := d.GetChange(isInstanceNicFloatingIP) + instance_id := parts[0] + network_interface_id := parts[1] + if floating_ip_id_new == nil || floating_ip_id_new.(string) == "" { + removeInstanceNetworkInterfaceFloatingIPOptions := vpcClient.NewRemoveInstanceNetworkInterfaceFloatingIPOptions(instance_id, network_interface_id, floating_ip_id_old.(string)) + response, err := vpcClient.RemoveInstanceNetworkInterfaceFloatingIP(removeInstanceNetworkInterfaceFloatingIPOptions) + if err != nil { + if response.StatusCode == 404 { + log.Println("[DEBUG] The specified floating IP address is not associated with the network interface with the specified identifier. ", err.Error()) + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error de-associating the floating ip %s in network interface %s of instance %s, %s\n%s", floating_ip_id_old.(string), network_interface_id, instance_id, err, response)) + } + } + } else { + floating_ip_id := floating_ip_id_new.(string) + getFloatingIPOptions := &vpcv1.GetFloatingIPOptions{ + ID: &floating_ip_id, + } + floatingip, response, err := vpcClient.GetFloatingIP(getFloatingIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Floating IP (%s): %s\n%s", floating_ip_id, err, response)) + + } + + if floatingip != nil && floatingip.Target != nil { + floatingIpTarget := floatingip.Target.(*vpcv1.FloatingIPTarget) + if *floatingIpTarget.ID != network_interface_id { + d.Set(isInstanceNicFloatingIP, "") + return diag.FromErr(fmt.Errorf("[Error] Provided floating ip is already bound to another resource")) + } + } + + addInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.AddInstanceNetworkInterfaceFloatingIPOptions{ + InstanceID: &instance_id, + NetworkInterfaceID: &network_interface_id, + ID: &floating_ip_id, + } + + _, response, err = vpcClient.AddInstanceNetworkInterfaceFloatingIP(addInstanceNetworkInterfaceFloatingIPOptions) + + if err != nil { + d.Set(isInstanceNicFloatingIP, "") + return diag.FromErr(fmt.Errorf("[DEBUG] Error adding Floating IP to network interface %s\n%s", err, response)) + } + } + + } + + _, err = isWaitForNetworkInterfaceAvailable(vpcClient, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error occured while waiting for network interface %s", err)) + } + _, err = isWaitForInstanceAvailable(vpcClient, instance_id, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + return resourceIBMIsInstanceNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsInstanceNetworkInterfaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + deleteInstanceNetworkInterfaceOptions := &vpcv1.DeleteInstanceNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + instance_id := parts[0] + network_intf_id := parts[1] + isNICKey := "instance_key_" + instance_id + conns.IbmMutexKV.Lock(isNICKey) + defer conns.IbmMutexKV.Unlock(isNICKey) + + deleteInstanceNetworkInterfaceOptions.SetInstanceID(instance_id) + deleteInstanceNetworkInterfaceOptions.SetID(network_intf_id) + + response, err := vpcClient.DeleteInstanceNetworkInterfaceWithContext(context, deleteInstanceNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] DeleteInstanceNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteInstanceNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + + _, err = isWaitForNetworkInterfaceDelete(vpcClient, d.Id(), d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error occured while waiting for network interface %s", err)) + } + + _, err = isWaitForInstanceAvailable(vpcClient, instance_id, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + + return nil +} + +func isWaitForNetworkInterfaceAvailable(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for dedicated host (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isNetworkInterfacePending}, + Target: []string{isNetworkInterfaceAvailable, isNetworkInterfaceFailed}, + Refresh: isNetworkInterfaceRefreshFunc(vpcClient, id, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isNetworkInterfaceRefreshFunc(vpcClient *vpcv1.VpcV1, id string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getInstanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error splitting ID in parts %s", err) + } + + getInstanceNetworkInterfaceOptions.SetInstanceID(parts[0]) + getInstanceNetworkInterfaceOptions.SetID(parts[1]) + + networkInterface, response, err := vpcClient.GetInstanceNetworkInterface(getInstanceNetworkInterfaceOptions) + if err != nil { + return nil, "", fmt.Errorf("GetInstanceNetworkInterface failed %s\n%s", err, response) + } + d.Set("status", *networkInterface.Status) + + if *networkInterface.Status == isNetworkInterfaceFailed { + return networkInterface, *networkInterface.Status, fmt.Errorf("Network Interface creationg failed with status %s ", *networkInterface.Status) + } + return networkInterface, *networkInterface.Status, nil + } +} + +func isWaitForNetworkInterfaceDelete(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for dedicated host (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isNetworkInterfacePending, isNetworkInterfaceDeleting, isNetworkInterfaceAvailable}, + Target: []string{isNetworkInterfaceDeleted}, + Refresh: isNetworkInterfaceRefreshDeleteFunc(vpcClient, id, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isNetworkInterfaceRefreshDeleteFunc(vpcClient *vpcv1.VpcV1, id string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getInstanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error splitting ID in parts %s", err) + } + + getInstanceNetworkInterfaceOptions.SetInstanceID(parts[0]) + getInstanceNetworkInterfaceOptions.SetID(parts[1]) + + networkInterface, response, err := vpcClient.GetInstanceNetworkInterface(getInstanceNetworkInterfaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return networkInterface, isNetworkInterfaceDeleted, nil + } + return nil, "", fmt.Errorf("GetInstanceNetworkInterface failed %s\n%s", err, response) + } + d.Set("status", *networkInterface.Status) + + if *networkInterface.Status == isNetworkInterfaceFailed { + return networkInterface, *networkInterface.Status, fmt.Errorf("Network Interface creationg failed with status %s ", *networkInterface.Status) + } + return networkInterface, *networkInterface.Status, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_network_interface_test.go b/ibm/service/vpc/resource_ibm_is_instance_network_interface_test.go new file mode 100644 index 000000000..b61b3dd53 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_network_interface_test.go @@ -0,0 +1,258 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsInstanceNetworkInterfaceAllArgs(t *testing.T) { + var conf vpcv1.NetworkInterface + allowIPSpoofing := "false" + name := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + secGrpName := fmt.Sprintf("tf-sec-grp%d", acctest.RandIntRange(10, 100)) + primaryIpv4Address := "10.240.0.6" + allowIPSpoofingUpdate := "true" + nameUpdate := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsInstanceNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfaceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address, secGrpName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkInterfaceExists("ibm_is_instance_network_interface.is_instance_network_interface", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "allow_ip_spoofing", allowIPSpoofing), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "name", name), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "primary_ipv4_address", primaryIpv4Address), + ), + }, + { + Config: testAccCheckIBMIsInstanceNetworkInterfaceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofingUpdate, nameUpdate, primaryIpv4Address, secGrpName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "allow_ip_spoofing", allowIPSpoofingUpdate), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "primary_ipv4_address", primaryIpv4Address), + ), + }, + { + ResourceName: "ibm_is_instance_network_interface.is_instance_network_interface", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccIBMIsInstanceNetworkInterface_rip(t *testing.T) { + var conf vpcv1.NetworkInterface + allowIPSpoofing := "false" + name := fmt.Sprintf("tf-net-int%d", acctest.RandIntRange(10, 100)) + secGrpName := fmt.Sprintf("tf-sec-grp%d", acctest.RandIntRange(10, 100)) + primaryIpv4Address := "10.240.0.6" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + insname := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsInstanceNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsInstanceNetworkInterfaceRipConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address, secGrpName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkInterfaceExists("ibm_is_instance_network_interface.is_instance_network_interface", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "allow_ip_spoofing", allowIPSpoofing), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "name", name), + resource.TestCheckResourceAttr("ibm_is_instance_network_interface.is_instance_network_interface", "primary_ipv4_address", primaryIpv4Address), + ), + }, + { + ResourceName: "ibm_is_instance_network_interface.is_instance_network_interface", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkInterfaceConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address, secGrpName string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + allow_ip_spoofing = %s + name = "%s" + primary_ipv4_address = "%s" + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, secGrpName, allowIPSpoofing, name, primaryIpv4Address) +} +func testAccCheckIBMIsInstanceNetworkInterfaceRipConfig(vpcname, subnetname, sshname, publicKey, insname, allowIPSpoofing, name, primaryIpv4Address, secGrpName string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_instance_network_interface" "is_instance_network_interface" { + instance = ibm_is_instance.testacc_instance.id + subnet = ibm_is_subnet.testacc_subnet.id + allow_ip_spoofing = %s + name = "%s" + primary_ip { + address = "%s" + } + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, secGrpName, allowIPSpoofing, name, primaryIpv4Address) +} + +func testAccCheckIBMIsInstanceNetworkInterfaceExists(n string, obj vpcv1.NetworkInterface) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + getInstanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceNetworkInterfaceOptions.SetInstanceID(parts[0]) + getInstanceNetworkInterfaceOptions.SetID(parts[1]) + + networkInterface, _, err := vpcClient.GetInstanceNetworkInterface(getInstanceNetworkInterfaceOptions) + if err != nil { + return err + } + + obj = *networkInterface + return nil + } +} + +func testAccCheckIBMIsInstanceNetworkInterfaceDestroy(s *terraform.State) error { + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance_network_interface" { + continue + } + + getInstanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceNetworkInterfaceOptions.SetInstanceID(parts[0]) + getInstanceNetworkInterfaceOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetInstanceNetworkInterface(getInstanceNetworkInterfaceOptions) + + if err == nil { + return fmt.Errorf("NetworkInterface still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for NetworkInterface (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go new file mode 100644 index 000000000..215003ed1 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -0,0 +1,1354 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "reflect" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceTemplateBootVolume = "boot_volume" + isInstanceTemplateBootVolumeTags = "tags" + isInstanceTemplateVolAttTags = "tags" + isInstanceTemplateCRN = "crn" + isInstanceTemplateVolAttVolAutoDelete = "auto_delete" + isInstanceTemplateVolAttVol = "volume" + isInstanceTemplateVolAttachmentName = "name" + isInstanceTemplateVolAttVolPrototype = "volume_prototype" + isInstanceTemplateVolAttVolCapacity = "capacity" + isInstanceTemplateVolAttVolIops = "iops" + isInstanceTemplateVolAttVolName = "name" + isInstanceTemplateVolAttVolBillingTerm = "billing_term" + isInstanceTemplateVolAttVolEncryptionKey = "encryption_key" + isInstanceTemplateVolAttVolType = "type" + isInstanceTemplateVolAttVolProfile = "profile" + isInstanceTemplateProvisioning = "provisioning" + isInstanceTemplateProvisioningDone = "done" + isInstanceTemplateAvailable = "available" + isInstanceTemplateDeleting = "deleting" + isInstanceTemplateDeleteDone = "done" + isInstanceTemplateFailed = "failed" + isInstanceTemplateBootName = "name" + isInstanceTemplateBootSize = "size" + isInstanceTemplateBootIOPS = "iops" + isInstanceTemplateBootEncryption = "encryption" + isInstanceTemplateBootProfile = "profile" + isInstanceTemplateVolumeAttaching = "attaching" + isInstanceTemplateVolumeAttached = "attached" + isInstanceTemplateVolumeDetaching = "detaching" + isInstanceTemplatePlacementTarget = "placement_target" + isInstanceTemplateDedicatedHost = "dedicated_host" + isInstanceTemplateDedicatedHostGroup = "dedicated_host_group" + isInstanceTemplateResourceType = "resource_type" + isInstanceTemplateVolumeDeleteOnInstanceDelete = "delete_volume_on_instance_delete" + isInstanceTemplateMetadataServiceEnabled = "metadata_service_enabled" + isInstanceTemplateAvailablePolicyHostFailure = "availability_policy_host_failure" + isInstanceTemplateHostFailure = "host_failure" + isInstanceTemplateNicPrimaryIP = "primary_ip" + isInstanceTemplateNicReservedIpAddress = "address" + isInstanceTemplateNicReservedIpAutoDelete = "auto_delete" + isInstanceTemplateNicReservedIpName = "name" + isInstanceTemplateNicReservedIpId = "reserved_ip" +) + +func ResourceIBMISInstanceTemplate() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMisInstanceTemplateCreate, + Read: resourceIBMisInstanceTemplateRead, + Update: resourceIBMisInstanceTemplateUpdate, + Delete: resourceIBMisInstanceTemplateDelete, + Exists: resourceIBMisInstanceTemplateExists, + Importer: &schema.ResourceImporter{}, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceVolumeAttachmentValidate(diff) + }), + ), + + Schema: map[string]*schema.Schema{ + isInstanceTemplateAvailablePolicyHostFailure: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The availability policy to use for this virtual server instance", + }, + + isInstanceTemplateName: { + Type: schema.TypeString, + Optional: true, + ForceNew: false, + ValidateFunc: validate.ValidateISName, + Description: "Instance Template name", + }, + + isInstanceTemplateMetadataServiceEnabled: { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + Description: "Indicates whether the metadata service endpoint is available to the virtual server instance", + }, + + isInstanceTemplateVPC: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "VPC id", + }, + + isInstanceTemplateZone: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "Zone name", + }, + + isInstanceTemplateProfile: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "Profile info", + }, + + isInstanceDefaultTrustedProfileAutoLink: { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Computed: true, + RequiredWith: []string{isInstanceDefaultTrustedProfileTarget}, + Description: "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + }, + isInstanceDefaultTrustedProfileTarget: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + }, + + isInstanceTotalVolumeBandwidth: { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_template", isInstanceTotalVolumeBandwidth), + Description: "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + }, + + isInstanceTemplateKeys: { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + DiffSuppressFunc: flex.ApplyOnce, + Description: "SSH key Ids for the instance template", + }, + + isPlacementTargetDedicatedHost: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{isPlacementTargetDedicatedHostGroup, isPlacementTargetPlacementGroup}, + Description: "Unique Identifier of the Dedicated Host where the instance will be placed", + }, + + isPlacementTargetDedicatedHostGroup: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetPlacementGroup}, + Description: "Unique Identifier of the Dedicated Host Group where the instance will be placed", + }, + + isPlacementTargetPlacementGroup: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{isPlacementTargetDedicatedHost, isPlacementTargetDedicatedHostGroup}, + Description: "Unique Identifier of the Placement Group for restricting the placement of the instance", + }, + + isInstanceTemplateVolumeAttachments: { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolumeDeleteOnInstanceDelete: { + Type: schema.TypeBool, + Required: true, + Description: "If set to true, when deleting the instance the volume will also be deleted.", + }, + isInstanceTemplateVolAttachmentName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_template", isInstanceTemplateVolAttachmentName), + Description: "The user-defined name for this volume attachment.", + }, + isInstanceTemplateVolAttVol: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The unique identifier for this volume.", + }, + isInstanceTemplateVolAttVolPrototype: { + Type: schema.TypeList, + MaxItems: 1, + MinItems: 1, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolAttVolIops: { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + isInstanceTemplateVolAttVolProfile: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + isInstanceTemplateVolAttVolCapacity: { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceTemplateVolAttVolEncryptionKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + isInstanceTemplateVolAttTags: { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_template", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + }, + }, + }, + }, + }, + }, + + isInstanceTemplatePrimaryNetworkInterface: { + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + Description: "Primary Network interface info", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + isInstanceTemplateNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.address"}, + Deprecated: "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead", + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ipv4_address"}, + Computed: true, + ForceNew: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"primary_network_interface.0.primary_ip.0.address", "primary_network_interface.0.primary_ip.0.auto_delete", "primary_network_interface.0.primary_ip.0.name", "primary_network_interface.0.primary_ipv4_address"}, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + isInstanceTemplateNetworkInterfaces: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicAllowIPSpoofing: { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + isInstanceTemplateNicName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceTemplateNicPrimaryIpv4Address: { + Type: schema.TypeString, + Optional: true, + Deprecated: "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead", + Computed: true, + }, + isInstanceTemplateNicPrimaryIP: { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateNicReservedIpAddress: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isInstanceTemplateNicReservedIpAutoDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + isInstanceTemplateNicReservedIpName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isInstanceTemplateNicReservedIpId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Identifies a reserved IP by a unique property.", + }, + }, + }, + }, + isInstanceTemplateNicSecurityGroups: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + isInstanceTemplateNicSubnet: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + isInstanceTemplateUserData: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "User data given for the instance", + }, + + isInstanceTemplateCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for the instance", + }, + + isInstanceTemplateImage: { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "image name", + }, + + isInstanceTemplateBootVolume: { + Type: schema.TypeList, + DiffSuppressFunc: flex.ApplyOnce, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateBootName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceTemplateBootVolumeTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_template", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + isInstanceTemplateBootEncryption: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + isInstanceTemplateBootSize: { + Type: schema.TypeInt, + Computed: true, + }, + isInstanceTemplateBootProfile: { + Type: schema.TypeString, + Computed: true, + }, + isInstanceTemplateVolumeDeleteOnInstanceDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + }, + }, + }, + + isInstanceTemplateResourceGroup: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + Description: "Instance template resource group", + }, + + isInstanceTemplatePlacementTarget: { + Type: schema.TypeList, + Computed: true, + Description: "The placement restrictions for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this placement target.", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this placement target.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this placement target.", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISInstanceTemplateValidator() *validate.ResourceValidator { + host_failure := "restart, stop" + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceTemplateVolAttachmentName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceTotalVolumeBandwidth, + ValidateFunctionIdentifier: validate.IntAtLeast, + Type: validate.TypeInt, + Optional: true, + MinValue: "500"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceTemplateAvailablePolicyHostFailure, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: host_failure}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + ibmISInstanceTemplateValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_template", Schema: validateSchema} + return &ibmISInstanceTemplateValidator +} + +func resourceIBMisInstanceTemplateCreate(d *schema.ResourceData, meta interface{}) error { + profile := d.Get(isInstanceTemplateProfile).(string) + name := d.Get(isInstanceTemplateName).(string) + vpcID := d.Get(isInstanceTemplateVPC).(string) + zone := d.Get(isInstanceTemplateZone).(string) + image := d.Get(isInstanceTemplateImage).(string) + + err := instanceTemplateCreate(d, meta, profile, name, vpcID, zone, image) + if err != nil { + return err + } + + return resourceIBMisInstanceTemplateRead(d, meta) +} + +func resourceIBMisInstanceTemplateRead(d *schema.ResourceData, meta interface{}) error { + ID := d.Id() + err := instanceTemplateGet(d, meta, ID) + if err != nil { + return err + } + return nil +} + +func resourceIBMisInstanceTemplateDelete(d *schema.ResourceData, meta interface{}) error { + + ID := d.Id() + + err := instanceTemplateDelete(d, meta, ID) + if err != nil { + return err + } + return nil +} + +func resourceIBMisInstanceTemplateUpdate(d *schema.ResourceData, meta interface{}) error { + + err := instanceTemplateUpdate(d, meta) + if err != nil { + return err + } + return resourceIBMisInstanceTemplateRead(d, meta) +} + +func resourceIBMisInstanceTemplateExists(d *schema.ResourceData, meta interface{}) (bool, error) { + ID := d.Id() + ok, err := instanceTemplateExists(d, meta, ID) + if err != nil { + return false, err + } + return ok, err +} + +func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + instanceproto := &vpcv1.InstanceTemplatePrototype{ + Image: &vpcv1.ImageIdentity{ + ID: &image, + }, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.InstanceProfileIdentity{ + Name: &profile, + }, + VPC: &vpcv1.VPCIdentity{ + ID: &vpcID, + }, + } + if name != "" { + instanceproto.Name = &name + } + + metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + if availablePolicyHostFailureIntf, ok := d.GetOk(isInstanceTemplateAvailablePolicyHostFailure); ok { + availablePolicyHostFailure := availablePolicyHostFailureIntf.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPrototype{ + HostFailure: &availablePolicyHostFailure, + } + } + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } + + if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } + + if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + + // BOOT VOLUME ATTACHMENT for instance template + if boot, ok := d.GetOk(isInstanceTemplateBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + name, ok := bootvol[isInstanceTemplateBootName] + namestr := name.(string) + if ok && namestr != "" { + volTemplate.Name = &namestr + } + + var userTags *schema.Set + if v, ok := bootvol[isInstanceTemplateBootVolumeTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volTemplate.UserTags = userTagsArray + } + } + + volcap := 100 + volcapint64 := int64(volcap) + volprof := "general-purpose" + volTemplate.Capacity = &volcapint64 + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + + if encryption, ok := bootvol[isInstanceTemplateBootEncryption]; ok { + bootEncryption := encryption.(string) + if bootEncryption != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &bootEncryption, + } + } + } + + var deleteVolumeOption bool + if deleteVolume, ok := bootvol[isInstanceTemplateVolumeDeleteOnInstanceDelete]; ok { + deleteVolumeOption = deleteVolume.(bool) + } + + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + DeleteVolumeOnInstanceDelete: &deleteVolumeOption, + Volume: volTemplate, + } + } + + // Handle volume attachments + if volsintf, ok := d.GetOk(isInstanceTemplateVolumeAttachments); ok { + vols := volsintf.([]interface{}) + var intfs []vpcv1.VolumeAttachmentPrototypeInstanceContext + for _, resource := range vols { + vol := resource.(map[string]interface{}) + volInterface := &vpcv1.VolumeAttachmentPrototypeInstanceContext{} + deleteVolBool := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete].(bool) + volInterface.DeleteVolumeOnInstanceDelete = &deleteVolBool + attachmentnamestr := vol[isInstanceTemplateVolAttachmentName].(string) + volInterface.Name = &attachmentnamestr + volIdStr := vol[isInstanceTemplateVolAttVol].(string) + + if volIdStr != "" { + volInterface.Volume = &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ + ID: &volIdStr, + } + } else { + newvolintf := vol[isInstanceTemplateVolAttVolPrototype].([]interface{})[0] + newvol := newvolintf.(map[string]interface{}) + profileName := newvol[isInstanceTemplateVolAttVolProfile].(string) + capacity := int64(newvol[isInstanceTemplateVolAttVolCapacity].(int)) + + volPrototype := &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContext{ + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profileName, + }, + Capacity: &capacity, + } + iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) + encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) + + if iops != 0 { + volPrototype.Iops = &iops + } + + if encryptionKey != "" { + volPrototype.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionKey, + } + } + var userTags *schema.Set + if v, ok := newvol[isInstanceTemplateVolAttTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volPrototype.UserTags = userTagsArray + } + } + volInterface.Volume = volPrototype + } + + intfs = append(intfs, *volInterface) + } + instanceproto.VolumeAttachments = intfs + } + + // Handle primary network interface + if primnicintf, ok := d.GetOk(isInstanceTemplatePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceTemplateNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + + if name, ok := primnic[isInstanceTemplateNicName]; ok { + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + } + allowIPSpoofing, ok := primnic[isInstanceTemplateNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + + secgrpintf, ok := primnic[isInstanceTemplateNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool + if IPAddress, ok := primnic[isInstanceTemplateNicPrimaryIpv4Address]; ok { + PrimaryIpv4Address = IPAddress.(string) + } + primaryIpOk, ok := primnic[isInstanceTemplateNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceTemplateNicReservedIpId] + reservedIp = reservedipok.(string) + reservedipv4Ok, _ := primip[isInstanceTemplateNicReservedIpAddress] + reservedIpAddress = reservedipv4Ok.(string) + reservedipnameOk, _ := primip[isInstanceTemplateNicReservedIpName] + reservedIpName = reservedipnameOk.(string) + reservedipautodeleteok, okAuto := primip[isInstanceTemplateNicReservedIpAutoDelete] + if okAuto { + reservedIpAutoDelete = reservedipautodeleteok.(bool) + } + } + if PrimaryIpv4Address != "" && reservedIpAddress != "" && PrimaryIpv4Address != reservedIpAddress { + return fmt.Errorf("[ERROR] Error creating instance template, primary_network_interface error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", PrimaryIpv4Address, reservedIpAddress) + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if PrimaryIpv4Address != "" { + primaryipobj.Address = &PrimaryIpv4Address + } + if reservedIpAddress != "" { + primaryipobj.Address = &reservedIpAddress + } + if reservedIpName != "" { + primaryipobj.Name = &reservedIpName + } + if okAuto { + primaryipobj.AutoDelete = &reservedIpAutoDelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + // Handle additional network interface + if nicsintf, ok := d.GetOk(isInstanceTemplateNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceTemplateNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + + name, ok := nic[isInstanceTemplateNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + allowIPSpoofing, ok := nic[isInstanceTemplateNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceTemplateNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool + if IPAddress, ok := nic[isInstanceTemplateNicPrimaryIpv4Address]; ok { + PrimaryIpv4Address = IPAddress.(string) + } + primaryIpOk, ok := nic[isInstanceTemplateNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceTemplateNicReservedIpId] + reservedIp = reservedipok.(string) + reservedipv4Ok, _ := primip[isInstanceTemplateNicReservedIpAddress] + reservedIpAddress = reservedipv4Ok.(string) + reservedipnameOk, _ := primip[isInstanceTemplateNicReservedIpName] + reservedIpName = reservedipnameOk.(string) + // var reservedipautodeleteok interface{} + + if v, ok := primip[isInstanceTemplateNicReservedIpAutoDelete].(bool); ok && v { + log.Printf("[INFO] UJJK isInstanceTemplateNicReservedIpAutoDelete is v is %t and okay is %t", v, ok) + reservedIpAutoDelete = primip[isInstanceTemplateNicReservedIpAutoDelete].(bool) + okAuto = true + } + // reservedipautodeleteok, okAuto = primip[isInstanceTemplateNicReservedIpAutoDelete] + // if okAuto { + // reservedIpAutoDelete = reservedipautodeleteok.(bool) + // } + } + if PrimaryIpv4Address != "" && reservedIpAddress != "" && PrimaryIpv4Address != reservedIpAddress { + return fmt.Errorf("[ERROR] Error creating instance template, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", PrimaryIpv4Address, reservedIpAddress) + } + if reservedIp != "" && (PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto) { + return fmt.Errorf("[ERROR] Error creating instance template, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if PrimaryIpv4Address != "" { + primaryipobj.Address = &PrimaryIpv4Address + } + if reservedIpAddress != "" { + primaryipobj.Address = &reservedIpAddress + } + if reservedIpName != "" { + primaryipobj.Name = &reservedIpName + } + if okAuto { + primaryipobj.AutoDelete = &reservedIpAutoDelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + // Handle SSH Keys + keySet := d.Get(isInstanceTemplateKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + // Handle user data + if userdata, ok := d.GetOk(isInstanceTemplateUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + // handle resource group + if grp, ok := d.GetOk(isInstanceTemplateResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + + options := &vpcv1.CreateInstanceTemplateOptions{ + InstanceTemplatePrototype: instanceproto, + } + + instanceIntf, response, err := sess.CreateInstanceTemplate(options) + if err != nil { + return fmt.Errorf("[ERROR] Error creating InstanceTemplate: %s\n%s", err, response) + } + instance := instanceIntf.(*vpcv1.InstanceTemplate) + d.SetId(*instance.ID) + return nil +} + +func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + getinsOptions := &vpcv1.GetInstanceTemplateOptions{ + ID: &ID, + } + instanceIntf, response, err := instanceC.GetInstanceTemplate(getinsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Instance template: %s\n%s", err, response) + } + instance := instanceIntf.(*vpcv1.InstanceTemplate) + d.Set(isInstanceTemplateName, *instance.Name) + d.Set(isInstanceTemplateCRN, *instance.CRN) + if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { + d.Set(isInstanceTemplateAvailablePolicyHostFailure, instance.AvailabilityPolicy.HostFailure) + } + if instance.Profile != nil { + instanceProfileIntf := instance.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + d.Set(isInstanceTemplateProfile, *identity.Name) + } + + if instance.DefaultTrustedProfile != nil { + if instance.DefaultTrustedProfile.AutoLink != nil { + d.Set(isInstanceDefaultTrustedProfileAutoLink, instance.DefaultTrustedProfile.AutoLink) + } + if instance.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instance.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByID) + d.Set(isInstanceDefaultTrustedProfileTarget, target.ID) + } + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instance.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityTrustedProfileByCRN) + d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN) + } + } + } + } + + if instance.TotalVolumeBandwidth != nil { + d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) + } + if instance.MetadataService != nil { + d.Set(isInstanceTemplateMetadataServiceEnabled, instance.MetadataService.Enabled) + } + + var placementTargetMap map[string]interface{} + if instance.PlacementTarget != nil { + placementTargetMap = resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + } + if err = d.Set(isInstanceTemplatePlacementTarget, []map[string]interface{}{placementTargetMap}); err != nil { + return fmt.Errorf("[ERROR] Error setting placement_target: %s", err) + } + + if instance.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name + if instance.PrimaryNetworkInterface.PrimaryIP != nil { + pipIntf := instance.PrimaryNetworkInterface.PrimaryIP + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + switch reflect.TypeOf(pipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentPrimNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + subInf := instance.PrimaryNetworkInterface.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if instance.PrimaryNetworkInterface.AllowIPSpoofing != nil { + currentPrimNic[isInstanceTemplateNicAllowIPSpoofing] = *instance.PrimaryNetworkInterface.AllowIPSpoofing + } + if len(instance.PrimaryNetworkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(instance.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instance.PrimaryNetworkInterface.SecurityGroups[i] + subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*subnetIdentity.ID)) + } + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + primaryNicList = append(primaryNicList, currentPrimNic) + d.Set(isInstanceTemplatePrimaryNetworkInterface, primaryNicList) + } + + if instance.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instance.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + pipIntf := intfc.PrimaryIP + switch reflect.TypeOf(pipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + if intfc.AllowIPSpoofing != nil { + currentNic[isInstanceTemplateNicAllowIPSpoofing] = *intfc.AllowIPSpoofing + } + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*subnetIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + } + d.Set(isInstanceTemplateNetworkInterfaces, interfacesList) + } + + if instance.Image != nil { + imageInf := instance.Image + imageIdentity := imageInf.(*vpcv1.ImageIdentity) + d.Set(isInstanceTemplateImage, *imageIdentity.ID) + } + vpcInf := instance.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + d.Set(isInstanceTemplateVPC, vpcRef.ID) + zoneInf := instance.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + d.Set(isInstanceTemplateZone, *zone.Name) + + interfacesList := make([]map[string]interface{}, 0) + if instance.VolumeAttachments != nil { + for _, volume := range instance.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags + } + if len(newVolume) > 0 { + newVolumeArr = append(newVolumeArr, newVolume) + } + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + interfacesList = append(interfacesList, volumeAttach) + } + d.Set(isInstanceTemplateVolumeAttachments, interfacesList) + } + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + bootVol[isInstanceTemplateDeleteVolume] = *instance.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instance.BootVolumeAttachment.Volume != nil { + volumeIntf := instance.BootVolumeAttachment.Volume + bootVol[isInstanceTemplateBootName] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + if volumeIntf.Profile != nil { + volProfIntf := volumeIntf.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if volumeIntf.EncryptionKey != nil { + volEncryption := volumeIntf.EncryptionKey + volEncryptionIntf := volEncryption.(*vpcv1.EncryptionKeyIdentity) + bootVol[isInstanceTemplateBootEncryption] = volEncryptionIntf.CRN + } + if volumeIntf.UserTags != nil { + bootVol[isVolumeTags] = volumeIntf.UserTags + } + } + + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceTemplateBootVolume, bootVolList) + } + + if instance.ResourceGroup != nil { + d.Set(isInstanceTemplateResourceGroup, instance.ResourceGroup.ID) + } + return nil +} + +func resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(instancePlacementTargetPrototype vpcv1.InstancePlacementTargetPrototype) map[string]interface{} { + instancePlacementTargetPrototypeMap := map[string]interface{}{} + + instancePlacementTargetPrototypeMap["id"] = instancePlacementTargetPrototype.ID + instancePlacementTargetPrototypeMap["crn"] = instancePlacementTargetPrototype.CRN + instancePlacementTargetPrototypeMap["href"] = instancePlacementTargetPrototype.Href + + return instancePlacementTargetPrototypeMap +} + +func instanceTemplateUpdate(d *schema.ResourceData, meta interface{}) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + ID := d.Id() + + if d.HasChange(isInstanceName) { + name := d.Get(isInstanceTemplateName).(string) + updnetoptions := &vpcv1.UpdateInstanceTemplateOptions{ + ID: &ID, + } + + instanceTemplatePatchModel := &vpcv1.InstanceTemplatePatch{ + Name: &name, + } + instanceTemplatePatch, err := instanceTemplatePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for InstanceTemplatePatch: %s", err) + } + updnetoptions.InstanceTemplatePatch = instanceTemplatePatch + + _, _, err = instanceC.UpdateInstanceTemplate(updnetoptions) + if err != nil { + return err + } + } + return nil +} + +func instanceTemplateDelete(d *schema.ResourceData, meta interface{}, ID string) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + + deleteinstanceTemplateOptions := &vpcv1.DeleteInstanceTemplateOptions{ + ID: &ID, + } + _, err = instanceC.DeleteInstanceTemplate(deleteinstanceTemplateOptions) + if err != nil { + return err + } + return nil +} + +func instanceTemplateExists(d *schema.ResourceData, meta interface{}, ID string) (bool, error) { + instanceC, err := vpcClient(meta) + if err != nil { + return false, err + } + getinsOptions := &vpcv1.GetInstanceTemplateOptions{ + ID: &ID, + } + _, response, err := instanceC.GetInstanceTemplate(getinsOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error Getting InstanceTemplate: %s\n%s", err, response) + } + return true, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_template_test.go b/ibm/service/vpc/resource_ibm_is_instance_template_test.go new file mode 100644 index 000000000..9ea83c98f --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_template_test.go @@ -0,0 +1,524 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISInstanceTemplate_basic(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceTemplate_Reserved_IP_basic(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateRipConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "primary_network_interface.0.primary_ip.0.reserved_ip"), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceTemplate_metadata_service(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceMetadataServiceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "metadata_service_enabled", "true"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceTemplate_withAvailabilityPolicy(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateConfigAvailablePolicyHostFailure_Default(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "availability_policy_host_failure", "stop"), + ), + }, + { + Config: testAccCheckIBMISInstanceTemplateConfigAvailablePolicyHostFailure_Updated(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "availability_policy_host_failure", "stop"), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceTemplate_WithVolumeAttachment(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceTemplate_WithVolumeAttachmentUserTag(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + userTag := "tag-0" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateWithVolumeUserTag(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.tags.0", userTag), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplateDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance_template" { + continue + } + + getInstanceTemplateOptions := vpcv1.GetInstanceTemplateOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetInstanceTemplate(&getInstanceTemplateOptions) + + if err == nil { + return fmt.Errorf("instance template still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "is_images" { + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName) + +} +func testAccCheckIBMISInstanceTemplateRipConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.subnet2.id + name = "test-instance-template-rip" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "is_images" { + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "%s" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, acc.ISZoneName, acc.ISCIDR, sshKeyName, publicKey, templateName, acc.ISZoneName) + +} + +func testAccCheckIBMISInstanceMetadataServiceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string, metadataService bool) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "is_images" { + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + metadata_service_enabled = %t + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName, metadataService) + +} + +func testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = "%s" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "%s" + volume_prototype { + iops = 6000 + profile = "custom" + capacity = 100 + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName, acc.IsImage, volAttachName) + +} + +func testAccCheckIBMISInstanceTemplateWithVolumeUserTag(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = "%s" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + boot_volume{ + tags = ["%s"] + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName, acc.IsImage, userTag) + +} + +func testAccCheckIBMISInstanceTemplateConfigAvailablePolicyHostFailure_Default(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + data "ibm_is_images" "is_images" { + } + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName) + +} +func testAccCheckIBMISInstanceTemplateConfigAvailablePolicyHostFailure_Updated(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + data "ibm_is_images" "is_images" { + } + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + availability_policy_host_failure = "stop" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName) + +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_test.go b/ibm/service/vpc/resource_ibm_is_instance_test.go new file mode 100644 index 000000000..5a83c6c86 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_test.go @@ -0,0 +1,1875 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strconv" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISInstance_basic(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + userData2 := "b" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData2), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"), + ), + }, + }, + }) +} +func TestAccIBMISInstance_lifecycle(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + userData2 := "b" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "lifecycle_reasons.#", "0"), + ), + }, + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData2), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "lifecycle_reasons.#", "0"), + ), + }, + }, + }) +} +func TestAccIBMISInstance_rip(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + subnetripname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceRipConfig(vpcname, subnetname, subnetripname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_ResizeBoot(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + resize1 := int64(220) + resize2 := int64(250) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceResizeConfig(vpcname, subnetname, sshname, publicKey, name, userData1, resize1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "boot_volume.0.size", fmt.Sprintf("%d", resize1)), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstanceResizeConfig(vpcname, subnetname, sshname, publicKey, name, userData1, resize2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "boot_volume.0.size", fmt.Sprintf("%d", resize2)), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_bootVolumeUserTags(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + userTags1 := "tags-0" + userTags2 := "tags-1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceUserTagConfig(vpcname, subnetname, sshname, publicKey, name, userData1, userTags1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "boot_volume.0.tags.0", userTags1), + ), + }, + { + Config: testAccCheckIBMISInstanceUserTagConfig(vpcname, subnetname, sshname, publicKey, name, userData1, userTags2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "boot_volume.0.tags.0", userTags2), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_withAvailablePolicy(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + templateName := fmt.Sprintf("tf-instnace-template-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_Default(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance", "availability_policy_host_failure", "restart"), + ), + }, + { + Config: testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_Updated(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance", "availability_policy_host_failure", "stop"), + ), + }, + { + Config: testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_WithTemplate(vpcname, subnetname, sshname, publicKey, templateName, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance", "availability_policy_host_failure", "stop"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceBandwidth_basic(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + totalVolumeBandwidth := 1000 + totalVolumeBandwidthUpdated := 1000 + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceBandwidthConfig(vpcname, subnetname, sshname, publicKey, name, totalVolumeBandwidth), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "total_volume_bandwidth", strconv.Itoa(totalVolumeBandwidth)), + ), + }, + { + Config: testAccCheckIBMISInstanceBandwidthUpdateConfig(vpcname, subnetname, sshname, publicKey, name, totalVolumeBandwidthUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "total_volume_bandwidth", strconv.Itoa(totalVolumeBandwidthUpdated)), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceWithSecurityGroup_basic(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + secGrpName := fmt.Sprintf("tf-secgrp-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceWithSecurityGroupConfig(vpcname, subnetname, sshname, publicKey, secGrpName, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.security_groups.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "network_interfaces.0.security_groups.#"), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_action(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData := "a" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstanceConfigActionStop(vpcname, subnetname, sshname, publicKey, name, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "status", "stopped"), + ), + }, + { + Config: testAccCheckIBMISInstanceConfigActionStart(vpcname, subnetname, sshname, publicKey, name, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "status", "running"), + ), + }, + { + Config: testAccCheckIBMISInstanceConfigActionReboot(vpcname, subnetname, sshname, publicKey, name, userData), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "status", "running"), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_metadata_service(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceWithMetaConfigDefault(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "metadata_service_enabled", "false"), + ), + }, + { + Config: testAccCheckIBMISInstanceWithMetaConfig(vpcname, subnetname, sshname, publicKey, name, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "metadata_service_enabled", "true"), + ), + }, + }, + }) +} +func TestAccIBMISInstance_profile(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, acc.InstanceProfileName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "profile", acc.InstanceProfileName), + ), + }, + + { + Config: testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, acc.InstanceProfileNameUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "profile", acc.InstanceProfileNameUpdate), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_basicwithipv4(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + ipv4address := "10.240.0.6" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfigwithipv4(vpcname, subnetname, sshname, publicKey, name, ipv4address), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.primary_ipv4_address", ipv4address), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_VolumeAutoDelete(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVolumeAutoDelete(vpcname, subnetname, sshname, publicKey, volname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "1"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "auto_delete_volume", "true"), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_Volume(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "1"), + ), + }, + { + Config: testAccCheckIBMISInstanceVolumeUpdate(vpcname, subnetname, sshname, publicKey, volname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "0"), + ), + }, + { + Config: testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_Disk(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "disks.#", "1"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "disks.0.name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "disks.0.size"), + ), + }, + }, + }) +} + +func TestAccIBMISInstance_Placement(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + dhostname := fmt.Sprintf("tf-dhost-%d", acctest.RandIntRange(10, 100)) + dhostgrpname := fmt.Sprintf("tf-dhostgrp-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstancePlacement(vpcname, subnetname, sshname, publicKey, volname, name, dhostname, dhostgrpname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "data.ibm_is_dedicated_host.dhost", "instances.#"), + resource.TestCheckResourceAttr( + "data.ibm_is_dedicated_host.dhost", "instances.0.name", name), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceSnapshotRestore_basic(t *testing.T) { + var instance, instanceRestore string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + snapshot := fmt.Sprintf("tf-snapshot-%d", acctest.RandIntRange(10, 100)) + vsiRestore := fmt.Sprintf("tf-instancerestore-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceSnapshotRestoreConfig(vpcname, subnetname, sshname, publicKey, name, snapshot, vsiRestore), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance_restore", instanceRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", snapshot), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "name", vsiRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "boot_volume.0.name", "boot-restore"), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceSnapshotRestore_forcenew(t *testing.T) { + var instance, instanceRestore string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tf-instnace2-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + vsiRestore := fmt.Sprintf("tf-instancerestore-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceSnapshotRestoreForceNewConfig(vpcname, subnetname, sshname, publicKey, name, name2, name, vsiRestore), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance_restore", instanceRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", fmt.Sprintf("%s%s", name, "-snapshot")), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "name", vsiRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "boot_volume.0.name", "boot-restore"), + ), + }, + { + Config: testAccCheckIBMISInstanceSnapshotRestoreForceNewConfig(vpcname, subnetname, sshname, publicKey, name, name2, name2, vsiRestore), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance_restore", instanceRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", fmt.Sprintf("%s%s", name2, "-snapshot")), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "name", vsiRestore), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_restore", "boot_volume.0.name", "boot-restore"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceDestroy(s *terraform.State) error { + + instanceC, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance" { + continue + } + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &rs.Primary.ID, + } + _, _, err := instanceC.GetInstance(getinsOptions) + + if err == nil { + return fmt.Errorf("instance still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISInstanceWithSecurityGroupConfig(vpcname, subnetname, sshname, publicKey, secgrpname, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + security_groups = [ibm_is_security_group.testacc_security_group.id] + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + security_groups = [ibm_is_security_group.testacc_security_group.id] + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, secgrpname, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceExists(n string, instance string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + instanceC, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &rs.Primary.ID, + } + foundins, _, err := instanceC.GetInstance(getinsOptions) + if err != nil { + return err + } + instance = *foundins.ID + return nil + } +} + +func testAccCheckIBMISInstanceWithMetaConfigDefault(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceWithMetaConfig(vpcname, subnetname, sshname, publicKey, name string, metadata_service_enabled bool) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + metadata_service_enabled=%t + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, metadata_service_enabled) +} + +func testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceRipConfig(vpcname, subnetname, subnetripname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_subnet_reserved_ip" "testacc_rip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_rip.reserved_ip + } + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, subnetripname, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceResizeConfig(vpcname, subnetname, sshname, publicKey, name, userData string, resize int64) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + boot_volume { + size = %d + } + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, resize, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceBandwidthConfig(vpcname, subnetname, sshname, publicKey, name string, bandwidth int) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + total_volume_bandwidth = %d + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, bandwidth, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceBandwidthUpdateConfig(vpcname, subnetname, sshname, publicKey, name string, bandwidth int) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + total_volume_bandwidth = %d + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, bandwidth, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigActionStop(vpcname, subnetname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + action = "stop" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigActionStart(vpcname, subnetname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + action = "start" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigActionReboot(vpcname, subnetname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + action = "reboot" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceSnapshotRestoreConfig(vpcname, subnetname, sshname, publicKey, name, snapshot, insRestore string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + } + + resource "ibm_is_instance" "testacc_instance_restore" { + name = "%s" + profile = "%s" + boot_volume { + name = "boot-restore" + snapshot = ibm_is_snapshot.testacc_snapshot.id + } + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, snapshot, insRestore, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceSnapshotRestoreForceNewConfig(vpcname, subnetname, sshname, publicKey, name, name2, name3, insRestore string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_instance" "testacc_instance1" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + data "ibm_is_instance" "testacc_ins_data" { + name = "%s" + depends_on = [ + ibm_is_instance.testacc_instance, + ibm_is_instance.testacc_instance1, + ] + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "${data.ibm_is_instance.testacc_ins_data.name}-snapshot" + source_volume = data.ibm_is_instance.testacc_ins_data.boot_volume[0].volume_id + } + + resource "ibm_is_instance" "testacc_instance_restore" { + name = "%s" + profile = "%s" + boot_volume { + name = "boot-restore" + snapshot = ibm_is_snapshot.testacc_snapshot.id + } + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, name2, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, name3, insRestore, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigWithProfile(vpcname, subnetname, sshname, publicKey, name, isInstanceProfileName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, isInstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigwithipv4(vpcname, subnetname, sshname, publicKey, name, ipv4address string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + primary_ipv4_address = "%s" + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, ipv4address, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceVolume(vpcname, subnetname, sshname, publicKey, volName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + # capacity= 200 + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + volumes = [ibm_is_volume.storage.id] + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceDisk(vpcname, subnetname, sshname, publicKey, volName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + # capacity= 200 + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + volumes = [ibm_is_volume.storage.id] + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceDiskProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstancePlacement(vpcname, subnetname, sshname, publicKey, volName, name, dhostname, dhostgrpname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + dedicated_host_group = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + + } + data "ibm_is_dedicated_host" "dhost"{ + host_group = ibm_is_instance.testacc_instance.dedicated_host_group + name = "%s" + } + + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.DedicatedHostGroupID, acc.ISZoneName, acc.DedicatedHostName) +} + +func testAccCheckIBMISInstanceVolumeAutoDelete(vpcname, subnetname, sshname, publicKey, volName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + volumes = [ibm_is_volume.storage.id] + auto_delete_volume = true + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceVolumeUpdate(vpcname, subnetname, sshname, publicKey, volName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "10iops-tier" + zone = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + +`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_Default(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_Updated(vpcname, subnetname, sshname, publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + availability_policy_host_failure = "stop" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +} + +func testAccCheckIBMISInstanceConfigWithAvailablePolicyHostFailure_WithTemplate(vpcname, subnetname, sshname, publicKey, templateName, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + data "ibm_is_images" "is_images" { + } + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + availability_policy_host_failure = "stop" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + instance_template = ibm_is_instance_template.instancetemplate1.id + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, templateName, acc.ISZoneName, name) +} + +func testAccCheckIBMISInstanceUserTagConfig(vpcname, subnetname, sshname, publicKey, name, userData, userTags1 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + boot_volume { + tags = ["%s"] + } + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userTags1, userData, acc.ISZoneName) +} + +func TestAccIBMISInstance_catalog(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceCatalogImageConfig(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "catalog_offering.0.version_crn"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_images.testacc_images", "images.0.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceCatalogImageConfig(vpcname, subnetname, sshname, publicKey, name, userData string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "testacc_images" { + catalog_managed = true + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + catalog_offering { + version_crn = data.ibm_is_images.testacc_images.images.0.catalog_offering.0.version.0.crn + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.InstanceProfileName, userData, acc.ISZoneName) +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go new file mode 100644 index 000000000..4c1cb7ed4 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go @@ -0,0 +1,810 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isInstanceId = "instance" + isInstanceVolAttVol = "volume" + isInstanceVolAttTags = "tags" + isInstanceVolAttId = "volume_attachment_id" + isInstanceVolAttIops = "volume_iops" + isInstanceExistingVolume = "existing" + isInstanceVolAttName = "name" + isInstanceVolAttVolume = "volume" + isInstanceVolumeDeleteOnInstanceDelete = "delete_volume_on_instance_delete" + isInstanceVolumeDeleteOnAttachmentDelete = "delete_volume_on_attachment_delete" + isInstanceVolCapacity = "capacity" + isInstanceVolIops = "iops" + isInstanceVolEncryptionKey = "encryption_key" + isInstanceVolProfile = "profile" +) + +func ResourceIBMISInstanceVolumeAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMisInstanceVolumeAttachmentCreate, + Read: resourceIBMisInstanceVolumeAttachmentRead, + Update: resourceIBMisInstanceVolumeAttachmentUpdate, + Delete: resourceIBMisInstanceVolumeAttachmentDelete, + Exists: resourceIBMisInstanceVolumeAttachmentExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceVolumeValidate(diff) + }), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }), + ), + Schema: map[string]*schema.Schema{ + isInstanceId: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceId), + Description: "Instance id", + }, + isInstanceVolAttId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this volume attachment", + }, + + isInstanceVolAttName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolAttName), + Description: "The user-defined name for this volume attachment.", + }, + + isInstanceVolumeDeleteOnInstanceDelete: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "If set to true, when deleting the instance the volume will also be deleted.", + }, + isInstanceVolumeDeleteOnAttachmentDelete: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "If set to true, when deleting the attachment, the volume will also be deleted. Default value for this true.", + }, + isInstanceVolAttVol: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{isInstanceVolIops, isInstanceVolumeAttVolumeReferenceName, isInstanceVolProfile, isInstanceVolCapacity, isInstanceVolumeSnapshot, isInstanceVolAttTags}, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceName), + Description: "Instance id", + }, + + isInstanceVolIops: { + Type: schema.TypeInt, + Computed: true, + Optional: true, + ConflictsWith: []string{isInstanceVolAttVol}, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + + isInstanceVolumeAttVolumeReferenceName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolumeAttVolumeReferenceName), + Description: "The unique user-defined name for this volume", + }, + + isInstanceVolAttTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConflictsWith: []string{isInstanceVolAttVol}, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + + isInstanceVolProfile: { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{isInstanceVolAttVol}, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolProfile), + Description: "The globally unique name for the volume profile to use for this volume.", + }, + + isInstanceVolCapacity: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + AtLeastOneOf: []string{isInstanceVolAttVol, isInstanceVolCapacity, isInstanceVolumeSnapshot}, + ConflictsWith: []string{isInstanceVolAttVol}, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", isInstanceVolCapacity), + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceVolEncryptionKey: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + isInstanceVolumeSnapshot: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + AtLeastOneOf: []string{isInstanceVolAttVol, isInstanceVolCapacity, isInstanceVolumeSnapshot}, + ConflictsWith: []string{isInstanceVolAttVol}, + Description: "The snapshot of the volume to be attached", + }, + isInstanceVolumeAttVolumeReferenceCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this volume", + }, + isInstanceVolumeAttVolumeReferenceDeleted: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources", + }, + isInstanceVolumeAttVolumeReferenceHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume", + }, + + isInstanceVolumeAttDevice: { + Type: schema.TypeString, + Computed: true, + Description: "A unique identifier for the device which is exposed to the instance operating system", + }, + + isInstanceVolumeAttHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume attachment", + }, + + isInstanceVolumeAttStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of this volume attachment, one of [ attached, attaching, deleting, detaching ]", + }, + + isInstanceVolumeAttType: { + Type: schema.TypeString, + Computed: true, + Description: "The type of volume attachment one of [ boot, data ]", + }, + + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMISInstanceVolumeAttachmentValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceId, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceVolAttName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceVolCapacity, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + MinValue: "10", + MaxValue: "16000"}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceVolumeAttVolumeReferenceName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceVolProfile, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "general-purpose, 5iops-tier, 10iops-tier, custom", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISInstanceVolumeAttachmentValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_volume_attachment", Schema: validateSchema} + return &ibmISInstanceVolumeAttachmentValidator +} + +func instanceVolAttachmentCreate(d *schema.ResourceData, meta interface{}, instanceId string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + instanceVolAttproto := &vpcv1.CreateInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + } + volumeIdStr := "" + if volumeId, ok := d.GetOk(isInstanceVolAttVol); ok { + volumeIdStr = volumeId.(string) + } + if volumeIdStr != "" { + var volProtoVol = &vpcv1.VolumeAttachmentPrototypeVolumeVolumeIdentity{} + volProtoVol.ID = &volumeIdStr + instanceVolAttproto.Volume = volProtoVol + } else { + var volProtoVol = &vpcv1.VolumeAttachmentPrototypeVolumeVolumePrototypeInstanceContext{} + if volname, ok := d.GetOk(isInstanceVolumeAttVolumeReferenceName); ok { + volnamestr := volname.(string) + volProtoVol.Name = &volnamestr + } + var userTags *schema.Set + if v, ok := d.GetOk(isInstanceVolAttTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volProtoVol.UserTags = userTagsArray + } + } + volSnapshotStr := "" + if volSnapshot, ok := d.GetOk(isInstanceVolumeSnapshot); ok { + volSnapshotStr = volSnapshot.(string) + volProtoVol.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshotStr, + } + } + encryptionCRNStr := "" + if encryptionCRN, ok := d.GetOk(isInstanceVolEncryptionKey); ok { + encryptionCRNStr = encryptionCRN.(string) + volProtoVol.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionCRNStr, + } + } + var snapCapacity int64 + if volSnapshotStr != "" { + snapshotGet, _, err := sess.GetSnapshot(&vpcv1.GetSnapshotOptions{ + ID: &volSnapshotStr, + }) + if err != nil { + return fmt.Errorf("[ERROR] Error while getting snapshot details %q for instance %s: %q", volSnapshotStr, d.Id(), err) + } + snapCapacity = int64(int(*snapshotGet.MinimumCapacity)) + } + var volCapacityInt int64 + if volCapacity, ok := d.GetOk(isInstanceVolCapacity); ok { + volCapacityInt = int64(volCapacity.(int)) + if volCapacityInt != 0 && volCapacityInt > snapCapacity { + volProtoVol.Capacity = &volCapacityInt + } + } + var iops int64 + if volIops, ok := d.GetOk(isInstanceVolIops); ok { + iops = int64(volIops.(int)) + if iops != 0 { + volProtoVol.Iops = &iops + } + volProfileStr := "custom" + volProtoVol.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfileStr, + } + } else { + volProfileStr := "general-purpose" + if volProfile, ok := d.GetOk(isInstanceVolProfile); ok { + volProfileStr = volProfile.(string) + volProtoVol.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfileStr, + } + } else { + volProtoVol.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfileStr, + } + } + } + + instanceVolAttproto.Volume = volProtoVol + } + + if autoDelete, ok := d.GetOk(isInstanceVolumeDeleteOnInstanceDelete); ok { + autoDeleteBool := autoDelete.(bool) + instanceVolAttproto.DeleteVolumeOnInstanceDelete = &autoDeleteBool + } + if name, ok := d.GetOk(isInstanceVolAttName); ok { + namestr := name.(string) + instanceVolAttproto.Name = &namestr + } + + isInstanceKey := "instance_key_" + instanceId + conns.IbmMutexKV.Lock(isInstanceKey) + defer conns.IbmMutexKV.Unlock(isInstanceKey) + + instanceVolAtt, response, err := sess.CreateInstanceVolumeAttachment(instanceVolAttproto) + if err != nil { + log.Printf("[DEBUG] Instance volume attachment create err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while attaching volume for instance %s: %q", instanceId, err) + } + d.SetId(makeTerraformVolAttID(instanceId, *instanceVolAtt.ID)) + _, err = isWaitForInstanceVolumeAttached(sess, d, instanceId, *instanceVolAtt.ID) + if err != nil { + return err + } + log.Printf("[INFO] Instance (%s) volume attachment : %s", instanceId, *instanceVolAtt.ID) + return nil +} + +func resourceIBMisInstanceVolumeAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + instanceId := d.Get(isInstanceId).(string) + err := instanceVolAttachmentCreate(d, meta, instanceId) + if err != nil { + return err + } + return resourceIBMisInstanceVolumeAttachmentRead(d, meta) +} + +func resourceIBMisInstanceVolumeAttachmentRead(d *schema.ResourceData, meta interface{}) error { + instanceID, id, err := parseVolAttTerraformID(d.Id()) + if err != nil { + return err + } + err = instanceVolumeAttachmentGet(d, meta, instanceID, id) + if err != nil { + return err + } + return nil +} + +func instanceVolumeAttachmentGet(d *schema.ResourceData, meta interface{}, instanceId, id string) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + + getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + volumeAtt, response, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Instance volume attachment : %s\n%s", err, response) + } + d.Set(isInstanceId, instanceId) + + if volumeAtt.Volume != nil { + d.Set(isInstanceVolumeAttVolumeReferenceName, *volumeAtt.Volume.Name) + d.Set(isInstanceVolumeAttVolumeReferenceCrn, *volumeAtt.Volume.CRN) + if volumeAtt.Volume.Deleted != nil { + d.Set(isInstanceVolumeAttVolumeReferenceDeleted, *volumeAtt.Volume.Deleted.MoreInfo) + } + d.Set(isInstanceVolumeAttVolumeReferenceHref, *volumeAtt.Volume.Href) + } + d.Set(isInstanceVolumeDeleteOnInstanceDelete, *volumeAtt.DeleteVolumeOnInstanceDelete) + d.Set(isInstanceVolAttName, *volumeAtt.Name) + if volumeAtt.Device != nil { + d.Set(isInstanceVolumeAttDevice, *volumeAtt.Device.ID) + } + d.Set(isInstanceVolumeAttHref, *volumeAtt.Href) + d.Set(isInstanceVolAttId, *volumeAtt.ID) + d.Set(isInstanceVolumeAttStatus, *volumeAtt.Status) + d.Set(isInstanceVolumeAttType, *volumeAtt.Type) + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return fmt.Errorf("Error setting version: %s", err) + } + volId := *volumeAtt.Volume.ID + getVolOptions := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + volumeDetail, _, err := instanceC.GetVolume(getVolOptions) + if err != nil || volumeDetail == nil { + return fmt.Errorf("[ERROR] Error while getting volume details of volume %s ", id) + } + + d.Set(isInstanceVolAttVol, *volumeDetail.ID) + d.Set(isInstanceVolIops, *volumeDetail.Iops) + d.Set(isInstanceVolProfile, *volumeDetail.Profile.Name) + d.Set(isInstanceVolCapacity, *volumeDetail.Capacity) + if volumeDetail.EncryptionKey != nil { + d.Set(isInstanceVolEncryptionKey, *volumeDetail.EncryptionKey.CRN) + } + if volumeDetail.SourceSnapshot != nil { + d.Set(isInstanceVolumeSnapshot, *volumeDetail.SourceSnapshot.ID) + } + return nil +} + +func instanceVolAttUpdate(d *schema.ResourceData, meta interface{}) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + instanceId, id, err := parseVolAttTerraformID(d.Id()) + if err != nil { + return err + } + updateInstanceVolAttOptions := &vpcv1.UpdateInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + flag := false + + // name && auto delete change + volAttNamePatchModel := &vpcv1.VolumeAttachmentPatch{} + if d.HasChange(isInstanceVolumeDeleteOnInstanceDelete) { + autoDelete := d.Get(isInstanceVolumeDeleteOnInstanceDelete).(bool) + volAttNamePatchModel.DeleteVolumeOnInstanceDelete = &autoDelete + flag = true + } + + if d.HasChange(isInstanceVolAttName) { + name := d.Get(isInstanceVolAttName).(string) + volAttNamePatchModel.Name = &name + flag = true + } + if flag { + volAttNamePatchModelAsPatch, err := volAttNamePatchModel.AsPatch() + if err != nil || volAttNamePatchModelAsPatch == nil { + return fmt.Errorf("[ERROR] Error Instance volume attachment (%s) as patch : %s", id, err) + } + updateInstanceVolAttOptions.VolumeAttachmentPatch = volAttNamePatchModelAsPatch + + instanceVolAttUpdate, response, err := instanceC.UpdateInstanceVolumeAttachment(updateInstanceVolAttOptions) + if err != nil || instanceVolAttUpdate == nil { + log.Printf("[DEBUG] Instance volume attachment updation err %s\n%s", err, response) + return err + } + } + + if d.HasChange(isInstanceVolumeAttVolumeReferenceName) { + newname := d.Get(isInstanceVolumeAttVolumeReferenceName).(string) + volid := d.Get(isInstanceVolAttVol).(string) + voloptions := &vpcv1.UpdateVolumeOptions{ + ID: &volid, + } + volumePatchModel := &vpcv1.VolumePatch{ + Name: &newname, + } + volumePatch, err := volumePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for VolumePatch: %s", err) + } + voloptions.VolumePatch = volumePatch + _, response, err := instanceC.UpdateVolume(voloptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating volume name : %s\n%s", err, response) + } + } + + // profile/iops update + + volId := "" + if volIdOk, ok := d.GetOk(isInstanceVolAttVol); ok { + volId = volIdOk.(string) + } + + if volId != "" && (d.HasChange(isInstanceVolIops) || d.HasChange(isInstanceVolProfile) || d.HasChange(isInstanceVolAttTags)) { + insId := d.Get(isInstanceId).(string) + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &insId, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) : %s\n%s", insId, err, response) + } + + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &insId, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", insId, err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, insId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + updateVolumeProfileOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + volumeProfilePatchModel := &vpcv1.VolumePatch{} + if d.HasChange(isInstanceVolProfile) { + profile := d.Get(isInstanceVolProfile).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + } else if d.HasChange(isVolumeIops) { + profile := d.Get(isInstanceVolProfile).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + iops := int64(d.Get(isVolumeIops).(int)) + volumeProfilePatchModel.Iops = &iops + } + if d.HasChange(isInstanceVolAttTags) && !d.IsNewResource() { + if v, ok := d.GetOk(isInstanceVolAttTags); ok { + userTags := v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volumeProfilePatchModel.UserTags = userTagsArray + } + } + + } + + volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeProfilePatch: %s", err) + } + optionsget := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + _, response, err = instanceC.GetVolume(optionsget) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Boot Volume (%s): %s\n%s", id, err, response) + } + eTag := response.Headers.Get("ETag") + updateVolumeProfileOptions.IfMatch = &eTag + updateVolumeProfileOptions.VolumePatch = volumeProfilePatch + _, response, err = instanceC.UpdateVolume(updateVolumeProfileOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating volume profile/iops/userTags: %s\n%s", err, response) + } + isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) + } + + // capacity update + + if volId != "" && d.HasChange(isInstanceVolCapacity) { + + getvolumeoptions := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + vol, response, err := instanceC.GetVolume(getvolumeoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Volume (%s): %s\n%s", id, err, response) + } + + if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].Name == "" { + return fmt.Errorf("[ERROR] Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) + } + + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &instanceId, + } + instance, response, err := instanceC.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) : %s\n%s", instanceId, err, response) + } + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &instanceId, + Type: &actiontype, + } + _, response, err = instanceC.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", instanceId, err, response) + } + _, err = isWaitForInstanceAvailable(instanceC, instanceId, d.Timeout(schema.TimeoutCreate), d) + return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", instanceId, err, response) + } + capacity := int64(d.Get(isVolumeCapacity).(int)) + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + volumeCapacityPatchModel := &vpcv1.VolumePatch{} + volumeCapacityPatchModel.Capacity = &capacity + volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatchModel: %s", err) + } + updateVolumeOptions.VolumePatch = volumeCapacityPatch + _, response, err = instanceC.UpdateVolume(updateVolumeOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating volume capacity: %s\n%s", err, response) + } + _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + return nil +} + +func resourceIBMisInstanceVolumeAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { + + err := instanceVolAttUpdate(d, meta) + if err != nil { + return err + } + return resourceIBMisInstanceVolumeAttachmentRead(d, meta) +} + +func instanceVolAttDelete(d *schema.ResourceData, meta interface{}, instanceId, id, volId string, volDelete bool) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + + deleteInstanceVolAttOptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + + isInstanceKey := "instance_key_" + instanceId + conns.IbmMutexKV.Lock(isInstanceKey) + defer conns.IbmMutexKV.Unlock(isInstanceKey) + + _, err = instanceC.DeleteInstanceVolumeAttachment(deleteInstanceVolAttOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while deleting volume attachment (%s) from instance (%s) : %q", id, instanceId, err) + } + _, err = isWaitForInstanceVolumeDetached(instanceC, d, instanceId, id) + + if err != nil { + return fmt.Errorf("[ERROR] Error while deleting volume attachment (%s) from instance (%s) on wait : %q", id, instanceId, err) + } + if volDelete { + deleteVolumeOptions := &vpcv1.DeleteVolumeOptions{ + ID: &volId, + } + response, err := instanceC.DeleteVolume(deleteVolumeOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while deleting volume : %s\n%s", err, response) + } + _, err = isWaitForVolumeDeleted(instanceC, volId, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + } + return nil +} + +func resourceIBMisInstanceVolumeAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + instanceId, id, err := parseVolAttTerraformID(d.Id()) + if err != nil { + return err + } + + volDelete := false + if volDeleteOk, ok := d.GetOk(isInstanceVolumeDeleteOnAttachmentDelete); ok { + volDelete = volDeleteOk.(bool) + } + volId := "" + if volIdOk, ok := d.GetOk(isInstanceVolAttVol); ok { + volId = volIdOk.(string) + } + + err = instanceVolAttDelete(d, meta, instanceId, id, volId, volDelete) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func resourceIBMisInstanceVolumeAttachmentExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + instanceId, id, err := parseVolAttTerraformID(d.Id()) + if err != nil { + return false, err + } + exists, err := instanceVolAttExists(d, meta, instanceId, id) + return exists, err +} + +func instanceVolAttExists(d *schema.ResourceData, meta interface{}, instanceId, id string) (bool, error) { + instanceC, err := vpcClient(meta) + if err != nil { + return false, err + } + getinsvolattOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + _, response, err := instanceC.GetInstanceVolumeAttachment(getinsvolattOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Instance volume attachment: %s\n%s", err, response) + } + return true, nil +} + +func makeTerraformVolAttID(id1, id2 string) string { + // Include both instance id and volume attachment to create a unique Terraform id. As a bonus, + // we can extract the instance id as needed for API calls such as READ. + return fmt.Sprintf("%s/%s", id1, id2) +} + +func parseVolAttTerraformID(s string) (string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_volume_attachment_test.go b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment_test.go new file mode 100644 index 000000000..bedbd571b --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment_test.go @@ -0,0 +1,292 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISInstanceVolumeAttachment_basic(t *testing.T) { + var instanceVolAtt string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + attName := fmt.Sprintf("tf-volatt-%d", acctest.RandIntRange(10, 100)) + autoDelete := true + volName := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + iops1 := int64(600) + iops2 := int64(900) + + capacity1 := int64(20) + capacity2 := int64(22) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity1, iops1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "name", attName), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity1)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "iops", "600"), + ), + }, + { + Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity1, iops2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "name", attName), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity1)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "iops", "900"), + ), + }, + + { + Config: testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, autoDelete, capacity2, iops2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "name", attName), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity2)), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceVolumeAttachment_userTag(t *testing.T) { + var instanceVolAtt string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + attName := fmt.Sprintf("tf-volatt-%d", acctest.RandIntRange(10, 100)) + autoDelete := true + volName := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + iops1 := int64(600) + capacity1 := int64(20) + userTag1 := "tag-0" + userTag2 := "tag-1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVolumeAttachmentUsertagConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, userTag1, autoDelete, capacity1, iops1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "name", attName), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "capacity", fmt.Sprintf("%d", capacity1)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "tags.0", userTag1), + ), + }, + { + Config: testAccCheckIBMISInstanceVolumeAttachmentUsertagConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, userTag2, autoDelete, capacity1, iops1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceVolumeAttachmentExists("ibm_is_instance_volume_attachment.testacc_att", instanceVolAtt), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "name", attName), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "delete_volume_on_instance_delete", fmt.Sprintf("%t", autoDelete)), + resource.TestCheckResourceAttr( + "ibm_is_instance_volume_attachment.testacc_att", "tags.0", userTag2), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceVolumeAttachmentDestroy(s *terraform.State) error { + + instanceC, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance_volume_attachment" { + continue + } + getinsvolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + ID: &rs.Primary.ID, + } + _, _, err := instanceC.GetInstanceVolumeAttachment(getinsvolAttOptions) + + if err == nil { + return fmt.Errorf("instance volume attachment still exists: %s", rs.Primary.ID) + } + } + + return nil +} +func parseVolAttTerraformID(s string) (string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], nil +} + +func testAccCheckIBMISInstanceVolumeAttachmentExists(n string, instanceVolAtt string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + instanceId, id, err := parseVolAttTerraformID(rs.Primary.ID) + instanceC, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + ID: &id, + InstanceID: &instanceId, + } + foundins, _, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) + if err != nil { + return err + } + instanceVolAtt = *foundins.ID + return nil + } +} + +func testAccCheckIBMISInstanceVolumeAttachmentConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName string, autoDelete bool, capacity, iops int64) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_instance_volume_attachment" "testacc_att" { + instance = ibm_is_instance.testacc_instance.id + + name = "%s" + profile = "custom" + capacity = %d + iops = %d + + delete_volume_on_instance_delete = %t + volume_name = "%s" + } + + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, attName, capacity, iops, autoDelete, volName) +} + +func testAccCheckIBMISInstanceVolumeAttachmentUsertagConfig(vpcname, subnetname, sshname, publicKey, name, attName, volName, usertag string, autoDelete bool, capacity, iops int64) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_instance_volume_attachment" "testacc_att" { + instance = ibm_is_instance.testacc_instance.id + + name = "%s" + profile = "custom" + capacity = %d + iops = %d + tags = ["%s"] + + delete_volume_on_instance_delete = %t + volume_name = "%s" + } + + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, attName, capacity, iops, usertag, autoDelete, volName) +} diff --git a/ibm/resource_ibm_is_ipsec_policy.go b/ibm/service/vpc/resource_ibm_is_ipsec_policy.go similarity index 76% rename from ibm/resource_ibm_is_ipsec_policy.go rename to ibm/service/vpc/resource_ibm_is_ipsec_policy.go index 08dd03971..6d1539e5e 100644 --- a/ibm/resource_ibm_is_ipsec_policy.go +++ b/ibm/service/vpc/resource_ibm_is_ipsec_policy.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( + "context" "fmt" "log" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -26,7 +30,7 @@ const ( isIPSecVPNConnectionHref = "href" ) -func resourceIBMISIPSecPolicy() *schema.Resource { +func ResourceIBMISIPSecPolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMISIPSecPolicyCreate, Read: resourceIBMISIPSecPolicyRead, @@ -35,32 +39,39 @@ func resourceIBMISIPSecPolicy() *schema.Resource { Exists: resourceIBMISIPSecPolicyExists, Importer: &schema.ResourceImporter{}, + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceIPSecPolicyValidate(diff) + }), + ), + Schema: map[string]*schema.Schema{ isIpSecName: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ipsec_policy", isIpSecName), + ValidateFunc: validate.InvokeValidator("ibm_is_ipsec_policy", isIpSecName), Description: "IPSEC name", }, isIpSecAuthenticationAlg: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ipsec_policy", isIpSecAuthenticationAlg), + ValidateFunc: validate.InvokeValidator("ibm_is_ipsec_policy", isIpSecAuthenticationAlg), Description: "Authentication alorothm", }, isIpSecEncryptionAlg: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ipsec_policy", isIpSecEncryptionAlg), + ValidateFunc: validate.InvokeValidator("ibm_is_ipsec_policy", isIpSecEncryptionAlg), Description: "Encryption algorithm", }, isIpSecPFS: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_ipsec_policy", isIpSecPFS), + ValidateFunc: validate.InvokeValidator("ibm_is_ipsec_policy", isIpSecPFS), Description: "PFS info", }, @@ -76,7 +87,7 @@ func resourceIBMISIPSecPolicy() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 3600, - ValidateFunc: validateKeyLifeTime, + ValidateFunc: validate.ValidateKeyLifeTime, Description: "IPSEC key lifetime", }, @@ -112,25 +123,25 @@ func resourceIBMISIPSecPolicy() *schema.Resource { }, }, }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -139,44 +150,44 @@ func resourceIBMISIPSecPolicy() *schema.Resource { } } -func resourceIBMISIPSECValidator() *ResourceValidator { +func ResourceIBMISIPSECValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - authentication_algorithm := "md5, sha1, sha256, sha512" - encryption_algorithm := "triple_des, aes128, aes256" - pfs := "disabled, group_2, group_5, group_14" + validateSchema := make([]validate.ValidateSchema, 0) + authentication_algorithm := "md5, sha1, sha256, sha512, sha384, disabled" + encryption_algorithm := "triple_des, aes128, aes256, aes128gcm16, aes192gcm16, aes256gcm16" + pfs := "disabled, group_2, group_5, group_14, group_19, group_15, group_16, group_17, group_18, group_20, group_21, group_22, group_23, group_24, group_31" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIpSecName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIpSecAuthenticationAlg, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: authentication_algorithm}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIpSecEncryptionAlg, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: encryption_algorithm}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isIpSecPFS, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: pfs}) - ibmISIPSECResourceValidator := ResourceValidator{ResourceName: "ibm_is_ipsec_policy", Schema: validateSchema} + ibmISIPSECResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_ipsec_policy", Schema: validateSchema} return &ibmISIPSECResourceValidator } @@ -250,14 +261,14 @@ func ipsecpGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting IPSEC Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting IPSEC Policy(%s): %s\n%s", id, err, response) } d.Set(isIpSecName, *ipSec.Name) d.Set(isIpSecAuthenticationAlg, *ipSec.AuthenticationAlgorithm) d.Set(isIpSecEncryptionAlg, *ipSec.EncryptionAlgorithm) if ipSec.ResourceGroup != nil { d.Set(isIPSecResourceGroup, *ipSec.ResourceGroup.ID) - d.Set(ResourceGroupName, *ipSec.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *ipSec.ResourceGroup.Name) } else { d.Set(isIPSecResourceGroup, nil) } @@ -279,13 +290,13 @@ func ipsecpGet(d *schema.ResourceData, meta interface{}, id string) error { } } d.Set(isIPSecVPNConnections, connList) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/ipsecpolicies") - d.Set(ResourceName, *ipSec.Name) - // d.Set(ResourceCRN, *ipSec.Crn) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/ipsecpolicies") + d.Set(flex.ResourceName, *ipSec.Name) + // d.Set(flex.ResourceCRN, *ipSec.Crn) return nil } @@ -325,13 +336,13 @@ func ipsecpUpdate(d *schema.ResourceData, meta interface{}, id string) error { } ipsecPolicyPatch, err := ipsecPolicyPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for IPsecPolicyPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for IPsecPolicyPatch: %s", err) } options.IPsecPolicyPatch = ipsecPolicyPatch _, response, err := sess.UpdateIpsecPolicy(options) if err != nil { - return fmt.Errorf("Error on update of IPSEC Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error on update of IPSEC Policy(%s): %s\n%s", id, err, response) } } return nil @@ -357,14 +368,14 @@ func ipsecpDelete(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting IPSEC Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting IPSEC Policy(%s): %s\n%s", id, err, response) } deleteIpsecPolicyOptions := &vpcv1.DeleteIpsecPolicyOptions{ ID: &id, } response, err = sess.DeleteIpsecPolicy(deleteIpsecPolicyOptions) if err != nil { - return fmt.Errorf("Error Deleting IPSEC Policy(%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Deleting IPSEC Policy(%s): %s\n%s", id, err, response) } d.SetId("") return nil @@ -389,7 +400,7 @@ func ipsecpExists(d *schema.ResourceData, meta interface{}, id string) (bool, er if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting IPSEC Policy(%s): %s\n%s", id, err, response) + return false, fmt.Errorf("[ERROR] Error getting IPSEC Policy(%s): %s\n%s", id, err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_ipsec_policy_test.go b/ibm/service/vpc/resource_ibm_is_ipsec_policy_test.go similarity index 89% rename from ibm/resource_ibm_is_ipsec_policy_test.go rename to ibm/service/vpc/resource_ibm_is_ipsec_policy_test.go index b0cf40808..545daf09a 100644 --- a/ibm/resource_ibm_is_ipsec_policy_test.go +++ b/ibm/service/vpc/resource_ibm_is_ipsec_policy_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -17,11 +20,11 @@ import ( func TestAccIBMISIPSecPolicy_basic(t *testing.T) { name := fmt.Sprintf("tfipsecc-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkPolicyDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISIPSecPolicyConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -53,7 +56,7 @@ func TestAccIBMISIPSecPolicy_basic(t *testing.T) { func checkPolicyDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_ipsec_policy" { continue @@ -84,7 +87,7 @@ func testAccCheckIBMISIpSecPolicyExists(n, policy string) resource.TestCheckFunc return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getipsecpoptions := &vpcv1.GetIpsecPolicyOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/service/vpc/resource_ibm_is_lb.go b/ibm/service/vpc/resource_ibm_is_lb.go new file mode 100644 index 000000000..06e4176ca --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_lb.go @@ -0,0 +1,876 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isLBName = "name" + isLBStatus = "status" + isLBCrn = "crn" + isLBTags = "tags" + isLBType = "type" + isLBSubnets = "subnets" + isLBHostName = "hostname" + isLBPublicIPs = "public_ips" + isLBPrivateIPs = "private_ips" + isLBListeners = "listeners" + isLBPools = "pools" + isLBOperatingStatus = "operating_status" + isLBDeleting = "deleting" + isLBDeleted = "done" + isLBProvisioning = "provisioning" + isLBProvisioningDone = "done" + isLBResourceGroup = "resource_group" + isLBProfile = "profile" + isLBRouteMode = "route_mode" + isLBUdpSupported = "udp_supported" + isLBLogging = "logging" + isLBSecurityGroups = "security_groups" + isLBSecurityGroupsSupported = "security_group_supported" +) + +func ResourceIBMISLB() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISLBCreate, + Read: resourceIBMISLBRead, + Update: resourceIBMISLBUpdate, + Delete: resourceIBMISLBDelete, + Exists: resourceIBMISLBExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceRouteModeValidate(diff) + }), + ), + + Schema: map[string]*schema.Schema{ + + isLBName: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_lb", isLBName), + Description: "Load Balancer name", + }, + + isLBType: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Default: "public", + ValidateFunc: validate.InvokeValidator("ibm_is_lb", isLBType), + Description: "Load Balancer type", + }, + + isLBStatus: { + Type: schema.TypeString, + Computed: true, + }, + + isLBCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this Load Balancer", + }, + + isLBOperatingStatus: { + Type: schema.TypeString, + Computed: true, + }, + + isLBPublicIPs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + isLBPrivateIPs: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + isLBPrivateIPDetail: { + Type: schema.TypeList, + Computed: true, + Description: "The private IP addresses assigned to this load balancer.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isLBPrivateIpAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.", + }, + isLBPrivateIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isLBPrivateIpName: { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in. ", + }, + isLBPrivateIpId: { + Type: schema.TypeString, + Computed: true, + Description: "Identifies a reserved IP by a unique property.", + }, + isLBPrivateIpResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + }, + }, + }, + isLBSubnets: { + Type: schema.TypeSet, + Required: true, + ForceNew: false, + MinItems: 1, + MaxItems: 15, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Load Balancer subnets list", + }, + + isLBSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Load Balancer securitygroups list", + ConflictsWith: []string{isLBProfile}, + }, + + isLBSecurityGroupsSupported: { + Type: schema.TypeBool, + Computed: true, + Description: "Security Group Supported for this Load Balancer", + }, + + isLBProfile: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The profile to use for this load balancer.", + ValidateFunc: validate.InvokeValidator("ibm_is_lb", isLBProfile), + ConflictsWith: []string{isLBLogging}, + }, + + isLBTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_lb", "tags")}, + Set: flex.ResourceIBMVPCHash, + }, + + isLBResourceGroup: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + }, + + isLBRouteMode: { + Type: schema.TypeBool, + ForceNew: true, + Optional: true, + Default: false, + Description: "Indicates whether route mode is enabled for this load balancer", + }, + + isLBUdpSupported: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this load balancer supports UDP.", + }, + + isLBHostName: { + Type: schema.TypeString, + Computed: true, + }, + + isLBLogging: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Logging of Load Balancer", + ConflictsWith: []string{isLBProfile}, + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMISLBValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + lbtype := "public, private" + isLBProfileAllowedValues := "network-fixed" + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isLBName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isLBType, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: lbtype}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isLBProfile, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: false, + AllowedValues: isLBProfileAllowedValues}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISLBResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb", Schema: validateSchema} + return &ibmISLBResourceValidator +} + +func resourceIBMISLBCreate(d *schema.ResourceData, meta interface{}) error { + + name := d.Get(isLBName).(string) + subnets := d.Get(isLBSubnets).(*schema.Set) + + var isLogging bool + if lbLogging, ok := d.GetOk(isLBLogging); ok { + isLogging = lbLogging.(bool) + } + + var securityGroups *schema.Set + if sg, ok := d.GetOk(isLBSecurityGroups); ok { + securityGroups = sg.(*schema.Set) + } + + // subnets := flex.ExpandStringList((d.Get(isLBSubnets).(*schema.Set)).List()) + var lbType, rg string + isPublic := true + if types, ok := d.GetOk(isLBType); ok { + lbType = types.(string) + } + + if lbType == "private" { + isPublic = false + } + + if grp, ok := d.GetOk(isLBResourceGroup); ok { + rg = grp.(string) + } + + err := lbCreate(d, meta, name, lbType, rg, subnets, isPublic, isLogging, securityGroups) + if err != nil { + return err + } + + return resourceIBMISLBRead(d, meta) +} + +func lbCreate(d *schema.ResourceData, meta interface{}, name, lbType, rg string, subnets *schema.Set, isPublic, isLogging bool, securityGroups *schema.Set) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + options := &vpcv1.CreateLoadBalancerOptions{ + IsPublic: &isPublic, + Name: &name, + } + + if routeModeBool, ok := d.GetOk(isLBRouteMode); ok { + routeMode := routeModeBool.(bool) + options.RouteMode = &routeMode + } + + if subnets.Len() != 0 { + subnetobjs := make([]vpcv1.SubnetIdentityIntf, subnets.Len()) + for i, subnet := range subnets.List() { + subnetstr := subnet.(string) + subnetobjs[i] = &vpcv1.SubnetIdentity{ + ID: &subnetstr, + } + } + options.Subnets = subnetobjs + } + + if securityGroups != nil && securityGroups.Len() != 0 { + securityGroupobjs := make([]vpcv1.SecurityGroupIdentityIntf, securityGroups.Len()) + for i, securityGroup := range securityGroups.List() { + securityGroupstr := securityGroup.(string) + securityGroupobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &securityGroupstr, + } + } + options.SecurityGroups = securityGroupobjs + } + + if rg != "" { + options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + if _, ok := d.GetOk(isLBProfile); ok { + profile := d.Get(isLBProfile).(string) + // Construct an instance of the LoadBalancerPoolIdentityByName model + loadBalancerProfileIdentityModel := new(vpcv1.LoadBalancerProfileIdentityByName) + loadBalancerProfileIdentityModel.Name = &profile + options.Profile = loadBalancerProfileIdentityModel + } else { + + dataPath := &vpcv1.LoadBalancerLoggingDatapath{ + Active: &isLogging, + } + loadBalancerLogging := &vpcv1.LoadBalancerLogging{ + Datapath: dataPath, + } + options.Logging = loadBalancerLogging + } + + lb, response, err := sess.CreateLoadBalancer(options) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating Load Balancer err %s\n%s", err, response) + } + d.SetId(*lb.ID) + log.Printf("[INFO] Load Balancer : %s", *lb.ID) + _, err = isWaitForLBAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isLBTags); ok || v != "" { + oldList, newList := d.GetChange(isLBTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *lb.CRN) + if err != nil { + log.Printf( + "Error on create of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMISLBRead(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + err := lbGet(d, meta, id) + if err != nil { + return err + } + + return nil +} + +func lbGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Load Balancer : %s\n%s", err, response) + } + d.Set(isLBName, *lb.Name) + if *lb.IsPublic { + d.Set(isLBType, "public") + } else { + d.Set(isLBType, "private") + } + if lb.RouteMode != nil { + d.Set(isLBRouteMode, *lb.RouteMode) + } + d.Set(isLBStatus, *lb.ProvisioningStatus) + d.Set(isLBCrn, *lb.CRN) + d.Set(isLBOperatingStatus, *lb.OperatingStatus) + publicIpList := make([]string, 0) + if lb.PublicIps != nil { + for _, ip := range lb.PublicIps { + if ip.Address != nil { + pubip := *ip.Address + publicIpList = append(publicIpList, pubip) + } + } + } + d.Set(isLBPublicIPs, publicIpList) + privateIpList := make([]string, 0) + privateIpDetailList := make([]map[string]interface{}, 0) + if lb.PrivateIps != nil { + for _, ip := range lb.PrivateIps { + if ip.Address != nil { + prip := *ip.Address + privateIpList = append(privateIpList, prip) + } + currentPriIp := map[string]interface{}{} + if ip.Address != nil { + currentPriIp[isLBPrivateIpAddress] = ip.Address + } + if ip.Href != nil { + currentPriIp[isLBPrivateIpHref] = ip.Href + } + if ip.Name != nil { + currentPriIp[isLBPrivateIpName] = ip.Name + } + if ip.ID != nil { + currentPriIp[isLBPrivateIpId] = ip.ID + } + if ip.ResourceType != nil { + currentPriIp[isLBPrivateIpResourceType] = ip.ResourceType + } + privateIpDetailList = append(privateIpDetailList, currentPriIp) + } + } + // isLBPrivateIPs is same as isLBPrivateIPDetail.[].address + d.Set(isLBPrivateIPs, privateIpList) + d.Set(isLBPrivateIPDetail, privateIpDetailList) + if lb.Subnets != nil { + subnetList := make([]string, 0) + for _, subnet := range lb.Subnets { + if subnet.ID != nil { + sub := *subnet.ID + subnetList = append(subnetList, sub) + } + } + d.Set(isLBSubnets, subnetList) + } + + d.Set(isLBSecurityGroupsSupported, false) + if lb.SecurityGroups != nil { + securitygroupList := make([]string, 0) + for _, SecurityGroup := range lb.SecurityGroups { + if SecurityGroup.ID != nil { + securityGroupID := *SecurityGroup.ID + securitygroupList = append(securitygroupList, securityGroupID) + } + } + d.Set(isLBSecurityGroups, securitygroupList) + d.Set(isLBSecurityGroupsSupported, true) + } + + if lb.Profile != nil { + profile := lb.Profile + if profile.Name != nil { + d.Set(isLBProfile, *lb.Profile.Name) + } + } else { + if lb.Logging != nil && lb.Logging.Datapath != nil && lb.Logging.Datapath.Active != nil { + d.Set(isLBLogging, *lb.Logging.Datapath.Active) + } + } + + d.Set(isLBResourceGroup, *lb.ResourceGroup.ID) + d.Set(isLBHostName, *lb.Hostname) + if lb.UDPSupported != nil { + d.Set(isLBUdpSupported, *lb.UDPSupported) + } + tags, err := flex.GetTagsUsingCRN(meta, *lb.CRN) + if err != nil { + log.Printf( + "Error on get of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) + } + d.Set(isLBTags, tags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/loadBalancers") + d.Set(flex.ResourceName, *lb.Name) + if lb.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, lb.ResourceGroup.Name) + } + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return fmt.Errorf("[ERROR] Error setting version: %s", err) + } + return nil +} + +func resourceIBMISLBUpdate(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + name := "" + isLogging := false + hasChanged := false + hasChangedLog := false + var remove, add []string + hasChangedSecurityGroups := false + + if d.HasChange(isLBName) { + name = d.Get(isLBName).(string) + hasChanged = true + } + if d.HasChange(isLBLogging) { + isLogging = d.Get(isLBLogging).(bool) + hasChangedLog = true + } + if d.HasChange(isLBSecurityGroups) { + oldSecurityGroups, newSecurityGroups := d.GetChange(isLBSecurityGroups) + oSecurityGroups := oldSecurityGroups.(*schema.Set) + nSecurityGroups := newSecurityGroups.(*schema.Set) + remove = flex.ExpandStringList(oSecurityGroups.Difference(nSecurityGroups).List()) + add = flex.ExpandStringList(nSecurityGroups.Difference(oSecurityGroups).List()) + hasChangedSecurityGroups = true + } + + err := lbUpdate(d, meta, id, name, hasChanged, isLogging, hasChangedLog, hasChangedSecurityGroups, remove, add) + if err != nil { + return err + } + + return resourceIBMISLBRead(d, meta) +} + +func lbUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool, isLogging bool, hasChangedLog bool, hasChangedSecurityGroups bool, remove, add []string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + if d.HasChange(isLBTags) { + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Load Balancer : %s\n%s", err, response) + } + oldList, newList := d.GetChange(isLBTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *lb.CRN) + if err != nil { + log.Printf( + "Error on update of resource vpc Load Balancer (%s) tags: %s", d.Id(), err) + } + } + + if d.HasChange(isLBSubnets) { + updateLoadBalancerOptions := &vpcv1.UpdateLoadBalancerOptions{ + ID: &id, + } + updateLoadBalancerOptions.SetIfMatch(d.Get("version").(string)) + loadBalancerPatchModel := &vpcv1.LoadBalancerPatch{} + subnets := d.Get(isLBSubnets).(*schema.Set) + if subnets.Len() != 0 { + subnetobjs := make([]vpcv1.SubnetIdentityIntf, subnets.Len()) + for i, subnet := range subnets.List() { + subnetstr := subnet.(string) + subnetobjs[i] = &vpcv1.SubnetIdentity{ + ID: &subnetstr, + } + } + loadBalancerPatchModel.Subnets = subnetobjs + } + loadBalancerPatch, err := loadBalancerPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerPatch: %s", err) + } + updateLoadBalancerOptions.LoadBalancerPatch = loadBalancerPatch + + _, response, err := sess.UpdateLoadBalancer(updateLoadBalancerOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating subents in vpc Load Balancer : %s\n%s", err, response) + } + _, err = isWaitForLBAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + + if hasChanged { + updateLoadBalancerOptions := &vpcv1.UpdateLoadBalancerOptions{ + ID: &id, + } + loadBalancerPatchModel := &vpcv1.LoadBalancerPatch{ + Name: &name, + } + loadBalancerPatch, err := loadBalancerPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerPatch: %s", err) + } + updateLoadBalancerOptions.LoadBalancerPatch = loadBalancerPatch + + _, response, err := sess.UpdateLoadBalancer(updateLoadBalancerOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating vpc Load Balancer : %s\n%s", err, response) + } + } + if hasChangedLog { + updateLoadBalancerOptions := &vpcv1.UpdateLoadBalancerOptions{ + ID: &id, + } + dataPath := &vpcv1.LoadBalancerLoggingDatapath{ + Active: &isLogging, + } + loadBalancerLogging := &vpcv1.LoadBalancerLogging{ + Datapath: dataPath, + } + loadBalancerPatchModel := &vpcv1.LoadBalancerPatch{ + Logging: loadBalancerLogging, + } + loadBalancerPatch, err := loadBalancerPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerPatch: %s", err) + } + updateLoadBalancerOptions.LoadBalancerPatch = loadBalancerPatch + + _, response, err := sess.UpdateLoadBalancer(updateLoadBalancerOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating vpc Load Balancer : %s\n%s", err, response) + } + } + + if hasChangedSecurityGroups { + + if len(add) > 0 { + for _, securityGroupID := range add { + createSecurityGroupTargetBindingOptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{} + createSecurityGroupTargetBindingOptions.SecurityGroupID = &securityGroupID + createSecurityGroupTargetBindingOptions.ID = &id + _, response, err := sess.CreateSecurityGroupTargetBinding(createSecurityGroupTargetBindingOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating Security Group Target Binding %s\n%s", err, response) + } + _, err = isWaitForLBAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + + if len(remove) > 0 { + for _, securityGroupID := range remove { + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupID, + ID: &id, + } + _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + continue + } + return fmt.Errorf("[ERROR] Error Getting Security Group Target for this load balancer (%s): %s\n%s", securityGroupID, err, response) + } + deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(securityGroupID, id) + response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Security Group Target for this load balancer : %s\n%s", err, response) + } + _, err = isWaitForLBAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + } + return nil +} + +func resourceIBMISLBDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + err := lbDelete(d, meta, id) + if err != nil { + return err + } + + d.SetId("") + return nil +} + +func lbDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + _, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting vpc load balancer(%s): %s\n%s", id, err, response) + } + + deleteLoadBalancerOptions := &vpcv1.DeleteLoadBalancerOptions{ + ID: &id, + } + response, err = sess.DeleteLoadBalancer(deleteLoadBalancerOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting vpc load balancer : %s\n%s", err, response) + } + _, err = isWaitForLBDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForLBDeleted(lbc *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isLBDeleting}, + Target: []string{isLBDeleted, "failed"}, + Refresh: isLBDeleteRefreshFunc(lbc, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isLBDeleteRefreshFunc(lbc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] is lb delete function here") + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + lb, response, err := lbc.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return lb, isLBDeleted, nil + } + return nil, "failed", fmt.Errorf("[ERROR] The vpc load balancer %s failed to delete: %s\n%s", id, err, response) + } + return lb, isLBDeleting, nil + } +} + +func resourceIBMISLBExists(d *schema.ResourceData, meta interface{}) (bool, error) { + id := d.Id() + + exists, err := lbExists(d, meta, id) + return exists, err + +} + +func lbExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ + ID: &id, + } + _, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting vpc load balancer: %s\n%s", err, response) + } + return true, nil +} + +func isWaitForLBAvailable(sess *vpcv1.VpcV1, lbId string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for load balancer (%s) to be available.", lbId) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isLBProvisioning, "update_pending"}, + Target: []string{isLBProvisioningDone, ""}, + Refresh: isLBRefreshFunc(sess, lbId), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isLBRefreshFunc(sess *vpcv1.VpcV1, lbId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getlboptions := &vpcv1.GetLoadBalancerOptions{ + ID: &lbId, + } + lb, response, err := sess.GetLoadBalancer(getlboptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) + } + + if *lb.ProvisioningStatus == "active" || *lb.ProvisioningStatus == "failed" { + return lb, isLBProvisioningDone, nil + } + + return lb, isLBProvisioning, nil + } +} diff --git a/ibm/resource_ibm_is_lb_listener.go b/ibm/service/vpc/resource_ibm_is_lb_listener.go similarity index 77% rename from ibm/resource_ibm_is_lb_listener.go rename to ibm/service/vpc/resource_ibm_is_lb_listener.go index e647f746a..499a87b81 100644 --- a/ibm/resource_ibm_is_lb_listener.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -35,7 +38,7 @@ const ( isLBListenerHTTPSRedirectURI = "https_redirect_uri" ) -func resourceIBMISLBListener() *schema.Resource { +func ResourceIBMISLBListener() *schema.Resource { return &schema.Resource{ Create: resourceIBMISLBListenerCreate, Read: resourceIBMISLBListenerRead, @@ -62,25 +65,30 @@ func resourceIBMISLBListener() *schema.Resource { isLBListenerPort: { Type: schema.TypeInt, Optional: true, - ValidateFunc: validateLBListenerPort, + ValidateFunc: validate.ValidateLBListenerPort, Computed: true, Description: "Loadbalancer listener port", }, isLBListenerPortMin: { - Type: schema.TypeInt, - Computed: true, - Description: "The inclusive lower bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener.", + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validate.ValidateLBListenerPort, + Computed: true, + Description: "The inclusive lower bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener.", }, + isLBListenerPortMax: { - Type: schema.TypeInt, - Computed: true, - Description: "The inclusive upper bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener", + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validate.ValidateLBListenerPort, + Computed: true, + Description: "The inclusive upper bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener", }, isLBListenerProtocol: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener", isLBListenerProtocol), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener", isLBListenerProtocol), Description: "Loadbalancer protocol", }, @@ -121,7 +129,7 @@ func resourceIBMISLBListener() *schema.Resource { isLBListenerConnectionLimit: { Type: schema.TypeInt, Optional: true, - ValidateFunc: validateLBListenerConnectionLimit, + ValidateFunc: validate.ValidateLBListenerConnectionLimit, Description: "Connection limit for Loadbalancer", }, @@ -161,7 +169,7 @@ func resourceIBMISLBListener() *schema.Resource { Computed: true, }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the LB resource", @@ -170,19 +178,19 @@ func resourceIBMISLBListener() *schema.Resource { } } -func resourceIBMISLBListenerValidator() *ResourceValidator { +func ResourceIBMISLBListenerValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) - protocol := "https, http, tcp" + validateSchema := make([]validate.ValidateSchema, 0) + protocol := "https, http, tcp, udp" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBListenerProtocol, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: protocol}) - ibmISLBListenerResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb_listener", Schema: validateSchema} + ibmISLBListenerResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb_listener", Schema: validateSchema} return &ibmISLBListenerResourceValidator } @@ -191,6 +199,8 @@ func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] LB Listener create") lbID := d.Get(isLBListenerLBID).(string) port := int64(d.Get(isLBListenerPort).(int)) + portMin := int64(d.Get(isLBListenerPortMin).(int)) + portMax := int64(d.Get(isLBListenerPortMax).(int)) protocol := d.Get(isLBListenerProtocol).(string) var defPool, certificateCRN string if pool, ok := d.GetOk(isLBListenerDefaultPool); ok { @@ -230,10 +240,10 @@ func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) err } isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) - err := lbListenerCreate(d, meta, lbID, protocol, defPool, certificateCRN, listener, uri, port, connLimit, httpStatusCode) + err := lbListenerCreate(d, meta, lbID, protocol, defPool, certificateCRN, listener, uri, port, portMin, portMax, connLimit, httpStatusCode) if err != nil { return err } @@ -241,7 +251,7 @@ func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) err return resourceIBMISLBListenerRead(d, meta) } -func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, defPool, certificateCRN, listener, uri string, port, connLimit, httpStatusCode int64) error { +func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, defPool, certificateCRN, listener, uri string, port, portMin, portMax, connLimit, httpStatusCode int64) error { sess, err := vpcClient(meta) if err != nil { return err @@ -258,17 +268,40 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, lb, response, err := sess.GetLoadBalancer(getlboptions) if err != nil || lb == nil { - return fmt.Errorf("Error getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Load Balancer : %s\n%s", err, response) } - if lb != nil && *lb.RouteMode && lb.Profile != nil && *lb.Profile.Name == "network-fixed" { - portMin := int64(1) - portMax := int64(65535) - - options.PortMin = &portMin - options.PortMax = &portMax - } else { - options.Port = &port + if portMin > 0 && portMax > 0 && portMin != 1 && portMax != 65535 { + return fmt.Errorf("[ERROR] Only acceptable value for port_min is 1 and port_max is 65535 for route_mode enabled private network load balancer") + } + pmin := int64(1) + pmax := int64(65535) + + options.PortMin = &pmin + options.PortMax = &pmax + } else if lb != nil && lb.Profile != nil { + if strings.EqualFold(*lb.Profile.Family, "network") && *lb.IsPublic { + if port == 0 && (portMin == 0 || portMax == 0) { + return fmt.Errorf( + "[ERROR] Error port_min(%d)/port_max(%d) for public network load balancer(%s) needs to be in between 1-65335", portMin, portMax, lbID) + } else { + if port != 0 { + options.Port = &port + } else { + options.PortMin = &portMin + options.PortMax = &portMax + } + } + } else if portMin != portMax { + return fmt.Errorf("[ERROR] Listener port_min and port_max values have to be equal for ALB and private NLB (excluding route mode)") + } else { + if port != 0 && (portMin == 0 || port == portMin) { + options.Port = &port + } else { + options.PortMin = &portMin + options.PortMax = &portMax + } + } } if app, ok := d.GetOk(isLBListenerAcceptProxyProtocol); ok { @@ -304,24 +337,21 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } lbListener, response, err := sess.CreateLoadBalancerListener(options) if err != nil { - return fmt.Errorf("Error while creating Load Balanacer Listener err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating Load Balanacer Listener err %s\n%s", err, response) } d.SetId(fmt.Sprintf("%s/%s", lbID, *lbListener.ID)) _, err = isWaitForLBListenerAvailable(sess, lbID, *lbListener.ID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("[ERROR] Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", lbID, err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", lbID, err) } log.Printf("[INFO] Load balancer Listener : %s", *lbListener.ID) @@ -352,7 +382,7 @@ func isLBListenerRefreshFunc(sess *vpcv1.VpcV1, lbID, lbListenerID string) resou } lblis, response, err := sess.GetLoadBalancerListener(getLoadBalancerListenerOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Load Balancer Listener: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer Listener: %s\n%s", err, response) } if *lblis.ProvisioningStatus == "active" || *lblis.ProvisioningStatus == "failed" { @@ -365,7 +395,7 @@ func isLBListenerRefreshFunc(sess *vpcv1.VpcV1, lbID, lbListenerID string) resou func resourceIBMISLBListenerRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -396,7 +426,7 @@ func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID d.SetId("") return nil } - return fmt.Errorf("Error Getting Load Balancer Listener : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer Listener : %s\n%s", err, response) } d.Set(isLBListenerLBID, lbID) if lbListener.Port != nil { @@ -433,15 +463,15 @@ func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } - d.Set(RelatedCRN, *lb.CRN) + d.Set(flex.RelatedCRN, *lb.CRN) return nil } func resourceIBMISLBListenerUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -517,11 +547,21 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener loadBalancerListenerPatchModel.HTTPSRedirect = HTTPSRedirect } } - if d.HasChange(isLBListenerPort) { + if _, ok := d.GetOk(isLBListenerPort); ok && d.HasChange(isLBListenerPort) { port = int64(d.Get(isLBListenerPort).(int)) loadBalancerListenerPatchModel.Port = &port hasChanged = true } + if d.HasChange(isLBListenerPortMin) { + portMin := int64(d.Get(isLBListenerPortMin).(int)) + loadBalancerListenerPatchModel.PortMin = &portMin + hasChanged = true + } + if d.HasChange(isLBListenerPortMax) { + portMax := int64(d.Get(isLBListenerPortMax).(int)) + loadBalancerListenerPatchModel.PortMax = &portMax + hasChanged = true + } if d.HasChange(isLBListenerProtocol) { protocol = d.Get(isLBListenerProtocol).(string) @@ -544,7 +584,7 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener if hasChanged { loadBalancerListenerPatch, err := loadBalancerListenerPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerListenerPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPatch: %s", err) } if httpsRedirectRemoved { loadBalancerListenerPatch["https_redirect"] = nil @@ -555,8 +595,8 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener updateLoadBalancerListenerOptions.LoadBalancerListenerPatch = loadBalancerListenerPatch isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutUpdate)) if err != nil { @@ -565,7 +605,7 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener } _, response, err := sess.UpdateLoadBalancerListener(updateLoadBalancerListenerOptions) if err != nil { - return fmt.Errorf("Error Updating Load Balancer Listener : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Load Balancer Listener : %s\n%s", err, response) } _, err = isWaitForLBListenerAvailable(sess, lbID, lbListenerID, d.Timeout(schema.TimeoutUpdate)) @@ -585,7 +625,7 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener func resourceIBMISLBListenerDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -594,8 +634,8 @@ func resourceIBMISLBListenerDelete(d *schema.ResourceData, meta interface{}) err lbListenerID := parts[1] isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbListenerDelete(d, meta, lbID, lbListenerID) if err != nil { @@ -621,12 +661,11 @@ func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListener d.SetId("") return nil } - return fmt.Errorf("Error Getting vpc load balancer listener(%s): %s\n%s", lbListenerID, err, response) + return fmt.Errorf("[ERROR] Error Getting vpc load balancer listener(%s): %s\n%s", lbListenerID, err, response) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } deleteLoadBalancerListenerOptions := &vpcv1.DeleteLoadBalancerListenerOptions{ LoadBalancerID: &lbID, @@ -634,7 +673,7 @@ func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListener } response, err = sess.DeleteLoadBalancerListener(deleteLoadBalancerListenerOptions) if err != nil { - return fmt.Errorf("Error Deleting Load Balancer Pool : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Load Balancer Pool : %s\n%s", err, response) } _, err = isWaitForLBListenerDeleted(sess, lbID, lbListenerID, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -642,8 +681,7 @@ func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListener } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to be active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be active: %s", lbID, err) } d.SetId("") @@ -676,7 +714,7 @@ func isLBListenerDeleteRefreshFunc(lbc *vpcv1.VpcV1, lbID, lbListenerID string) if response != nil && response.StatusCode == 404 { return lbLis, isLBListenerDeleted, nil } - return nil, "", fmt.Errorf("The vpc load balancer listener %s failed to delete: %s\n%s", lbListenerID, err, response) + return nil, "", fmt.Errorf("[ERROR] The vpc load balancer listener %s failed to delete: %s\n%s", lbListenerID, err, response) } return lbLis, isLBListenerDeleting, nil } @@ -684,12 +722,12 @@ func isLBListenerDeleteRefreshFunc(lbc *vpcv1.VpcV1, lbID, lbListenerID string) func resourceIBMISLBListenerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of lbID/lbListenerID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of lbID/lbListenerID", d.Id()) } lbID := parts[0] lbListenerID := parts[1] @@ -714,7 +752,7 @@ func lbListenerExists(d *schema.ResourceData, meta interface{}, lbID, lbListener if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Load balancer Listener: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Load balancer Listener: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_lb_listener_policy.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go similarity index 91% rename from ibm/resource_ibm_is_lb_listener_policy.go rename to ibm/service/vpc/resource_ibm_is_lb_listener_policy.go index 0cab21500..e8bf3a8d6 100644 --- a/ibm/resource_ibm_is_lb_listener_policy.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -10,6 +10,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -47,7 +50,7 @@ const ( isLBListenerPolicyHTTPSRedirectListener = "target_https_redirect_listener" ) -func resourceIBMISLBListenerPolicy() *schema.Resource { +func ResourceIBMISLBListenerPolicy() *schema.Resource { return &schema.Resource{ Create: resourceIBMISLBListenerPolicyCreate, Read: resourceIBMISLBListenerPolicyRead, @@ -59,7 +62,7 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { CustomizeDiff: customdiff.All( customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceLBListenerPolicyCustomizeDiff(diff) + return flex.ResourceLBListenerPolicyCustomizeDiff(diff) }, ), ), @@ -132,7 +135,7 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy", isLBListenerPolicyAction), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy", isLBListenerPolicyAction), Description: "Policy Action", }, @@ -140,7 +143,7 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { Type: schema.TypeInt, Required: true, ForceNew: false, - ValidateFunc: validateLBListenerPolicyPriority, + ValidateFunc: validate.ValidateLBListenerPolicyPriority, Description: "Listener Policy Priority", }, @@ -149,7 +152,7 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { Optional: true, ForceNew: false, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy", isLBListenerPolicyName), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy", isLBListenerPolicyName), Description: "Policy name", }, @@ -169,28 +172,28 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { isLBListenerPolicyRuleCondition: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRulecondition), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRulecondition), Description: "Condition of the rule", }, isLBListenerPolicyRuleType: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRuleType), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRuleType), Description: "Type of the rule", }, isLBListenerPolicyRuleValue: { Type: schema.TypeString, Required: true, - ValidateFunc: validateStringLength, + ValidateFunc: validate.ValidateStringLength, Description: "Value to be matched for rule condition", }, isLBListenerPolicyRuleField: { Type: schema.TypeString, Optional: true, - ValidateFunc: validateStringLength, + ValidateFunc: validate.ValidateStringLength, Description: "HTTP header field. This is only applicable to rule type.", }, @@ -250,7 +253,7 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { Description: "Listner Policy status", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the LB resource", @@ -259,28 +262,28 @@ func resourceIBMISLBListenerPolicy() *schema.Resource { } } -func resourceIBMISLBListenerPolicyValidator() *ResourceValidator { +func ResourceIBMISLBListenerPolicyValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) action := "forward, redirect, reject, https_redirect" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBListenerPolicyName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBListenerPolicyAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: action}) - ibmISLBListenerPolicyResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb_listener_policy", Schema: validateSchema} + ibmISLBListenerPolicyResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb_listener_policy", Schema: validateSchema} return &ibmISLBListenerPolicyResourceValidator } @@ -314,7 +317,7 @@ func resourceIBMISLBListenerPolicyCreate(d *schema.ResourceData, meta interface{ func getListenerID(id string) (string, error) { if strings.Contains(id, "/") { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return "", err } @@ -327,7 +330,7 @@ func getListenerID(id string) (string, error) { func getPoolID(id string) (string, error) { if strings.Contains(id, "/") { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return "", err } @@ -469,8 +472,8 @@ func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, list } isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLbAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -480,7 +483,7 @@ func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, list policy, response, err := sess.CreateLoadBalancerListenerPolicy(options) if err != nil { - return fmt.Errorf("Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response) + return fmt.Errorf("[ERROR] Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response) } d.SetId(fmt.Sprintf("%s/%s/%s", lbID, listenerID, *(policy.ID))) @@ -543,7 +546,7 @@ func isWaitForLbListenerPolicyAvailable(vpc *vpcv1.VpcV1, id string, timeout tim func isLbListenerPolicyRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return nil, "", err } @@ -575,7 +578,7 @@ func isLbListenerPolicyRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRe func resourceIBMISLBListenerPolicyRead(d *schema.ResourceData, meta interface{}) error { ID := d.Id() - parts, err := idParts(ID) + parts, err := flex.IdParts(ID) if err != nil { return err } @@ -606,12 +609,12 @@ func lbListenerPolicyExists(d *schema.ResourceData, meta interface{}, ID string) if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 3 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of lbID/listenerID/policyID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of lbID/listenerID/policyID", d.Id()) } lbID := parts[0] @@ -631,13 +634,13 @@ func lbListenerPolicyExists(d *schema.ResourceData, meta interface{}, ID string) if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Load balancer policy: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Load balancer policy: %s\n%s", err, response) } return true, nil } func resourceIBMISLBListenerPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -765,15 +768,15 @@ func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, list if hasChanged { loadBalancerListenerPolicyPatch, err := loadBalancerListenerPolicyPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerListenerPolicyPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPolicyPatch: %s", err) } if httpsURIRemoved { loadBalancerListenerPolicyPatch["target"].(map[string]interface{})["uri"] = nil } updatePolicyOptions.LoadBalancerListenerPolicyPatch = loadBalancerListenerPolicyPatch isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLbAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -782,7 +785,7 @@ func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, list } _, response, err := sess.UpdateLoadBalancerListenerPolicy(&updatePolicyOptions) if err != nil { - return fmt.Errorf("Error Updating in policy : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating in policy : %s\n%s", err, response) } _, err = isWaitForLbListenerPolicyAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) @@ -796,7 +799,7 @@ func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, list func resourceIBMISLBListenerPolicyDelete(d *schema.ResourceData, meta interface{}) error { //Retrieve lbId, listenerId and policyID - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -806,8 +809,8 @@ func resourceIBMISLBListenerPolicyDelete(d *schema.ResourceData, meta interface{ policyID := parts[2] isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbListenerPolicyDelete(d, meta, lbID, listenerID, policyID) if err != nil { @@ -855,7 +858,7 @@ func lbListenerPolicyDelete(d *schema.ResourceData, meta interface{}, lbID, list response, err = sess.DeleteLoadBalancerListenerPolicy(deleteLbListenerPolicyOptions) if err != nil { - return fmt.Errorf("Error in lbListenerPolicyDelete: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error in lbListenerPolicyDelete: %s\n%s", err, response) } _, err = isWaitForLbListnerPolicyDeleted(sess, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -881,7 +884,7 @@ func isLbListenerPolicyDeleteRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.S return func() (interface{}, string, error) { //Retrieve lbId, listenerId and policyID - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return nil, isLBListenerPolicyFailed, nil } @@ -1012,9 +1015,9 @@ func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listene } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } - d.Set(RelatedCRN, *lb.CRN) + d.Set(flex.RelatedCRN, *lb.CRN) return nil } diff --git a/ibm/resource_ibm_is_lb_listener_policy_rule.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule.go similarity index 87% rename from ibm/resource_ibm_is_lb_listener_policy_rule.go rename to ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule.go index 1a5475d03..195b8bece 100644 --- a/ibm/resource_ibm_is_lb_listener_policy_rule.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -34,7 +37,7 @@ const ( isLBListenerPolicyRuleProvisioningDone = "done" ) -func resourceIBMISLBListenerPolicyRule() *schema.Resource { +func ResourceIBMISLBListenerPolicyRule() *schema.Resource { return &schema.Resource{ Create: resourceIBMISLBListenerPolicyRuleCreate, Read: resourceIBMISLBListenerPolicyRuleRead, @@ -113,28 +116,28 @@ func resourceIBMISLBListenerPolicyRule() *schema.Resource { isLBListenerPolicyRulecondition: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRulecondition), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRulecondition), Description: "Condition info of the rule.", }, isLBListenerPolicyRuletype: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRuletype), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_listener_policy_rule", isLBListenerPolicyRuletype), Description: "Policy rule type.", }, isLBListenerPolicyRulevalue: { Type: schema.TypeString, Required: true, - ValidateFunc: validateStringLength, + ValidateFunc: validate.ValidateStringLength, Description: "policy rule value info", }, isLBListenerPolicyRulefield: { Type: schema.TypeString, Optional: true, - ValidateFunc: validateStringLength, + ValidateFunc: validate.ValidateStringLength, }, isLBListenerPolicyRuleid: { @@ -147,7 +150,7 @@ func resourceIBMISLBListenerPolicyRule() *schema.Resource { Computed: true, }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the LB resource", @@ -156,27 +159,27 @@ func resourceIBMISLBListenerPolicyRule() *schema.Resource { } } -func resourceIBMISLBListenerPolicyRuleValidator() *ResourceValidator { +func ResourceIBMISLBListenerPolicyRuleValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) condition := "contains, equals, matches_regex" ruletype := "header, hostname, path, body, query" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBListenerPolicyRulecondition, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: condition}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBListenerPolicyRuletype, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: ruletype}) - ibmISLBListenerPolicyRuleResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb_listener_policy_rule", Schema: validateSchema} + ibmISLBListenerPolicyRuleResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb_listener_policy_rule", Schema: validateSchema} return &ibmISLBListenerPolicyRuleResourceValidator } @@ -212,7 +215,7 @@ func resourceIBMISLBListenerPolicyRuleCreate(d *schema.ResourceData, meta interf func getLbListenerID(id string) (string, error) { if strings.Contains(id, "/") { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return "", err } @@ -225,7 +228,7 @@ func getLbListenerID(id string) (string, error) { func getLbPolicyID(id string) (string, error) { if strings.Contains(id, "/") { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return "", err } @@ -237,7 +240,7 @@ func getLbPolicyID(id string) (string, error) { } func vpcSdkClient(meta interface{}) (*vpcv1.VpcV1, error) { - sess, err := meta.(ClientSession).VpcV1API() + sess, err := meta.(conns.ClientSession).VpcV1API() return sess, err } @@ -259,8 +262,8 @@ func lbListenerPolicyRuleCreate(d *schema.ResourceData, meta interface{}, lbID, } isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLoadbalancerAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -270,7 +273,7 @@ func lbListenerPolicyRuleCreate(d *schema.ResourceData, meta interface{}, lbID, rule, response, err := sess.CreateLoadBalancerListenerPolicyRule(options) if err != nil { - return fmt.Errorf("Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response) + return fmt.Errorf("[ERROR] Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response) } d.SetId(fmt.Sprintf("%s/%s/%s/%s", lbID, listenerID, policyID, *(rule.ID))) @@ -334,7 +337,7 @@ func isWaitForLbListenerPolicyRuleAvailable(vpc *vpcv1.VpcV1, id string, timeout func isLbListenerPolicyRuleRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return nil, "", err } @@ -368,7 +371,7 @@ func isLbListenerPolicyRuleRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.Sta func resourceIBMISLBListenerPolicyRuleRead(d *schema.ResourceData, meta interface{}) error { ID := d.Id() - parts, err := idParts(ID) + parts, err := flex.IdParts(ID) if err != nil { return err } @@ -400,12 +403,12 @@ func lbListenerPolicyRuleExists(d *schema.ResourceData, meta interface{}, ID str if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 4 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of lbID/listenerID/policyID/ruleID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of lbID/listenerID/policyID/ruleID", d.Id()) } lbID := parts[0] listenerID := parts[1] @@ -426,13 +429,13 @@ func lbListenerPolicyRuleExists(d *schema.ResourceData, meta interface{}, ID str if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting policy: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting policy: %s\n%s", err, response) } return true, nil } func resourceIBMISLBListenerPolicyRuleUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -491,13 +494,13 @@ func lbListenerPolicyRuleUpdate(d *schema.ResourceData, meta interface{}, lbID, if hasChanged { loadBalancerListenerPolicyRulePatch, err := loadBalancerListenerPolicyRulePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerListenerPolicyRulePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPolicyRulePatch: %s", err) } updatePolicyRuleOptions.LoadBalancerListenerPolicyRulePatch = loadBalancerListenerPolicyRulePatch isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLoadbalancerAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -507,7 +510,7 @@ func lbListenerPolicyRuleUpdate(d *schema.ResourceData, meta interface{}, lbID, _, response, err := sess.UpdateLoadBalancerListenerPolicyRule(&updatePolicyRuleOptions) if err != nil { - return fmt.Errorf("Error Updating in policy : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating in policy : %s\n%s", err, response) } _, err = isWaitForLbListenerPolicyRuleAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) @@ -521,7 +524,7 @@ func lbListenerPolicyRuleUpdate(d *schema.ResourceData, meta interface{}, lbID, func resourceIBMISLBListenerPolicyRuleDelete(d *schema.ResourceData, meta interface{}) error { //Retrieve lbId, listenerId and policyID - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -532,8 +535,8 @@ func resourceIBMISLBListenerPolicyRuleDelete(d *schema.ResourceData, meta interf ruleID := parts[3] isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbListenerPolicyRuleDelete(d, meta, lbID, listenerID, policyID, ruleID) if err != nil { @@ -567,7 +570,7 @@ func lbListenerPolicyRuleDelete(d *schema.ResourceData, meta interface{}, lbID, d.SetId("") return nil } - return fmt.Errorf("Error in LbListenerPolicyGet : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error in LbListenerPolicyGet : %s\n%s", err, response) } deleteLbListenerPolicyRuleOptions := &vpcv1.DeleteLoadBalancerListenerPolicyRuleOptions{ @@ -578,7 +581,7 @@ func lbListenerPolicyRuleDelete(d *schema.ResourceData, meta interface{}, lbID, } response, err = sess.DeleteLoadBalancerListenerPolicyRule(deleteLbListenerPolicyRuleOptions) if err != nil { - return fmt.Errorf("Error in lbListenerPolicyRuleDelete: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error in lbListenerPolicyRuleDelete: %s\n%s", err, response) } _, err = isWaitForLbListnerPolicyRuleDeleted(sess, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -604,7 +607,7 @@ func isLbListenerPolicyRuleDeleteRefreshFunc(vpc *vpcv1.VpcV1, id string) resour return func() (interface{}, string, error) { //Retrieve lbId, listenerId and policyID - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return nil, isLBListenerPolicyFailed, nil } @@ -674,9 +677,9 @@ func lbListenerPolicyRuleGet(d *schema.ResourceData, meta interface{}, lbID, lis } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } - d.Set(RelatedCRN, *lb.CRN) + d.Set(flex.RelatedCRN, *lb.CRN) return nil } diff --git a/ibm/resource_ibm_is_lb_listener_policy_rule_test.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule_test.go similarity index 89% rename from ibm/resource_ibm_is_lb_listener_policy_rule_test.go rename to ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule_test.go index d934c326f..95eefaa8c 100644 --- a/ibm/resource_ibm_is_lb_listener_policy_rule_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_rule_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -36,12 +40,12 @@ func TestAccIBMISLBListenerPolicyRule_basic(t *testing.T) { typeb := "body" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBListenerPolicyRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBListenerPolicyRuleConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, typeh, lblistenerpolicyRuleField1, lblistenerpolicyRuleValue1), + Config: testAccCheckIBMISLBListenerPolicyRuleConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, action, priority, condition, typeh, lblistenerpolicyRuleField1, lblistenerpolicyRuleValue1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyRuleExists("ibm_is_lb_listener_policy_rule.testacc_lb_listener_policy_rule", ruleID), resource.TestCheckResourceAttr( @@ -54,7 +58,7 @@ func TestAccIBMISLBListenerPolicyRule_basic(t *testing.T) { }, { - Config: testAccCheckIBMISLBListenerPolicyRuleConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname, priority, condition, typeb, lblistenerpolicyRuleField2, lblistenerpolicyRuleValue2), + Config: testAccCheckIBMISLBListenerPolicyRuleConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname, priority, condition, typeb, lblistenerpolicyRuleField2, lblistenerpolicyRuleValue2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyRuleExists("ibm_is_lb_listener_policy_rule.testacc_lb_listener_policy_rule", ruleID), resource.TestCheckResourceAttr( @@ -69,7 +73,7 @@ func TestAccIBMISLBListenerPolicyRule_basic(t *testing.T) { func testAccCheckIBMISLBListenerPolicyRuleDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_lb_listener_policy_rule" { continue @@ -79,7 +83,7 @@ func testAccCheckIBMISLBListenerPolicyRuleDestroy(s *terraform.State) error { return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -118,7 +122,7 @@ func testAccCheckIBMISLBListenerPolicyRuleExists(n string, ruleID string) resour return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -128,7 +132,7 @@ func testAccCheckIBMISLBListenerPolicyRuleExists(n string, ruleID string) resour policyID := parts[2] ruleID := parts[3] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getLbListenerPolicyRuleOptions := &vpcv1.GetLoadBalancerListenerPolicyRuleOptions{ LoadBalancerID: &lbID, ListenerID: &lbListenerID, diff --git a/ibm/resource_ibm_is_lb_listener_policy_test.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go similarity index 91% rename from ibm/resource_ibm_is_lb_listener_policy_test.go rename to ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go index df0e2d665..340fbac61 100644 --- a/ibm/resource_ibm_is_lb_listener_policy_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -29,12 +33,12 @@ func TestAccIBMISLBListenerPolicy_basic(t *testing.T) { priority2 := "2" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBListenerPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBListenerPolicyConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), + Config: testAccCheckIBMISLBListenerPolicyConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -48,7 +52,7 @@ func TestAccIBMISLBListenerPolicy_basic(t *testing.T) { }, { - Config: testAccCheckIBMISLBListenerPolicyConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2, action), + Config: testAccCheckIBMISLBListenerPolicyConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2, action), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -76,12 +80,12 @@ func TestAccIBMISLBListenerPolicyRedirect_basic(t *testing.T) { priority2 := "2" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBListenerPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBListenerPolicyRedirectConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), + Config: testAccCheckIBMISLBListenerPolicyRedirectConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -94,7 +98,7 @@ func TestAccIBMISLBListenerPolicyRedirect_basic(t *testing.T) { }, { - Config: testAccCheckIBMISLBListenerPolicyRedirectConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2), + Config: testAccCheckIBMISLBListenerPolicyRedirectConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -122,12 +126,12 @@ func TestAccIBMISLBListenerPolicyReject_basic(t *testing.T) { priority2 := "2" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBListenerPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBListenerPolicyRejectConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), + Config: testAccCheckIBMISLBListenerPolicyRejectConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname1, action, priority1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -140,7 +144,7 @@ func TestAccIBMISLBListenerPolicyReject_basic(t *testing.T) { }, { - Config: testAccCheckIBMISLBListenerPolicyRejectConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2), + Config: testAccCheckIBMISLBListenerPolicyRejectConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port, protocol, lblistenerpolicyname2, priority2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerPolicyExists("ibm_is_lb_listener_policy.testacc_lb_listener_policy", policyID), resource.TestCheckResourceAttr( @@ -163,12 +167,12 @@ func TestAccIBMISLBListenerPolicyHttpRedirect_basic(t *testing.T) { port1 := "9086" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBListenerDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1, lbpolicyname), + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), resource.TestCheckResourceAttr( @@ -180,7 +184,7 @@ func TestAccIBMISLBListenerPolicyHttpRedirect_basic(t *testing.T) { ), }, { - Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1, lbpolicyname), + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), resource.TestCheckResourceAttr( @@ -192,7 +196,7 @@ func TestAccIBMISLBListenerPolicyHttpRedirect_basic(t *testing.T) { ), }, { - Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigRemove(vpcname, subnetname, ISZoneName, ISCIDR, lbname, port1, protocol1, lbpolicyname), + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigRemove(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), resource.TestCheckResourceAttr( @@ -209,7 +213,7 @@ func TestAccIBMISLBListenerPolicyHttpRedirect_basic(t *testing.T) { func testAccCheckIBMISLBListenerPolicyDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_lb_listener_policy" { continue @@ -219,7 +223,7 @@ func testAccCheckIBMISLBListenerPolicyDestroy(s *terraform.State) error { return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -257,7 +261,7 @@ func testAccCheckIBMISLBListenerPolicyExists(n string, policyID string) resource return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -266,7 +270,7 @@ func testAccCheckIBMISLBListenerPolicyExists(n string, policyID string) resource lbListenerID := parts[1] policyID := parts[2] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getLbListenerPolicyOptions := &vpcv1.GetLoadBalancerListenerPolicyOptions{ LoadBalancerID: &lbID, ListenerID: &lbListenerID, @@ -564,7 +568,7 @@ func testAccCheckIBMISLBListenerPolicyHttpsRedirectConfig(vpcname, subnetname, z health_timeout = 30 health_type = "https" proxy_protocol = "v1" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance, lbpolicyname) + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, lbpolicyname) } @@ -624,7 +628,7 @@ func testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigUpdate(vpcname, subnetn health_timeout = 30 health_type = "https" proxy_protocol = "v1" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance, lbpolicyname) + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, lbpolicyname) } @@ -681,6 +685,6 @@ func testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigRemove(vpcname, subnetn health_timeout = 30 health_type = "https" proxy_protocol = "v1" - }`, vpcname, subnetname, zone, cidr, lbname, lbListerenerCertificateInstance, lbpolicyname) + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, lbpolicyname) } diff --git a/ibm/service/vpc/resource_ibm_is_lb_listener_test.go b/ibm/service/vpc/resource_ibm_is_lb_listener_test.go new file mode 100644 index 000000000..207ffbe33 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_test.go @@ -0,0 +1,542 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISLBListener_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "http" + port1 := "8080" + + protocol2 := "tcp" + port2 := "9080" + + connLimit := "100" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", port1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "accept_proxy_protocol", "true"), + ), + }, + + { + Config: testAccCheckIBMISLBListenerConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port2, protocol2, connLimit), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", port2), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol2), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "connection_limit", connLimit), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "accept_proxy_protocol", "false"), + ), + }, + }, + }) +} +func TestAccIBMISLBListener_basic_udp(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "udp" + port1 := "8080" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBUdpListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", port1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), + ), + }, + }, + }) +} +func TestAccIBMISNLBRouteModeListener_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "tcp" + port1 := "1" + port2 := "65535" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISNLBRouteModeListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "type", "private"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "route_mode", "true"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", port1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_min", port1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_max", port2), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), + ), + }, + }, + }) +} +func TestAccIBMISNLBPortRangeListener_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "tcp" + portMin := "20" + portMax := "40" + portMin1 := "20" + portMax2 := "40" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISNLBPortRangeListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, portMin, portMax, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "type", "public"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "route_mode", "false"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", portMin), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_min", portMin), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_max", portMax), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), + ), + }, + { + Config: testAccCheckIBMISNLBPortRangeListenerConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, portMin1, portMax2, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.testacc_lb_listener", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "type", "public"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "route_mode", "false"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port", portMin1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_min", portMin1), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "port_max", portMax2), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.testacc_lb_listener", "protocol", protocol1), + ), + }, + }, + }) +} + +func TestAccIBMISLBListenerHttpRedirect_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "https" + port1 := "9086" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBListenerHttpsRedirectConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_status_code", "301"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", "/example?doc=geta"), + ), + }, + { + Config: testAccCheckIBMISLBListenerHttpsRedirectConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_status_code", "303"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", "/example?doc=updated"), + ), + }, + { + Config: testAccCheckIBMISLBListenerHttpsRedirectConfigRemove(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_uri", ""), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect_listener", ""), + ), + }, + }, + }) +} + +func testAccCheckIBMISLBListenerDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_lb_listener" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + lbID := parts[0] + lbListenerID := parts[1] + getlblptions := &vpcv1.GetLoadBalancerListenerOptions{ + LoadBalancerID: &lbID, + ID: &lbListenerID, + } + _, _, err1 := sess.GetLoadBalancerListener(getlblptions) + if err1 == nil { + return fmt.Errorf("LB Listener still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISLBListenerExists(n, LBListener string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + lbID := parts[0] + lbListenerID := parts[1] + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getlblptions := &vpcv1.GetLoadBalancerListenerOptions{ + LoadBalancerID: &lbID, + ID: &lbListenerID, + } + foundLBListener, _, err := sess.GetLoadBalancerListener(getlblptions) + if err != nil { + return err + } + LBListener = *foundLBListener.ID + + return nil + } +} + +func testAccCheckIBMISLBListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "testacc_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + port = %s + protocol = "%s" + accept_proxy_protocol = true + }`, vpcname, subnetname, zone, cidr, lbname, port, protocol) + +} +func testAccCheckIBMISLBUdpListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + profile = "network-fixed" + type = "public" + } + resource "ibm_is_lb_listener" "testacc_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + port = %s + protocol = "%s" + }`, vpcname, subnetname, zone, cidr, lbname, port, protocol) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect_listener = ibm_is_lb_listener.lb_listener1.listener_id + https_redirect_status_code = 301 + https_redirect_uri = "/example?doc=geta" + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect_listener = ibm_is_lb_listener.lb_listener1.listener_id + https_redirect_status_code = 303 + https_redirect_uri = "/example?doc=updated" + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectConfigRemove(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} +func testAccCheckIBMISNLBRouteModeListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + profile = "network-fixed" + route_mode = true + type = "private" + } + resource "ibm_is_lb_listener" "testacc_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + port = %s + protocol = "%s" +}`, vpcname, subnetname, zone, cidr, lbname, port, protocol) + +} +func testAccCheckIBMISNLBPortRangeListenerConfig(vpcname, subnetname, zone, cidr, lbname, portMin, portMax, protocol string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + profile = "network-fixed" + type = "public" + } + resource "ibm_is_lb_listener" "testacc_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + port_min = %s + port_max = %s + protocol = "%s" +}`, vpcname, subnetname, zone, cidr, lbname, portMin, portMax, protocol) + +} + +func testAccCheckIBMISLBListenerConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol, connLimit string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "testacc_lb_listener" { + lb = "${ibm_is_lb.testacc_LB.id}" + port = %s + protocol = "%s" + connection_limit = %s + accept_proxy_protocol = false +}`, vpcname, subnetname, zone, cidr, lbname, port, protocol, connLimit) + +} diff --git a/ibm/resource_ibm_is_lb_pool.go b/ibm/service/vpc/resource_ibm_is_lb_pool.go similarity index 82% rename from ibm/resource_ibm_is_lb_pool.go rename to ibm/service/vpc/resource_ibm_is_lb_pool.go index 66c44c992..29a2efbdd 100644 --- a/ibm/resource_ibm_is_lb_pool.go +++ b/ibm/service/vpc/resource_ibm_is_lb_pool.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,6 +9,9 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -41,7 +44,7 @@ const ( isLBPool = "pool_id" ) -func resourceIBMISLBPool() *schema.Resource { +func ResourceIBMISLBPool() *schema.Resource { return &schema.Resource{ Create: resourceIBMISLBPoolCreate, Read: resourceIBMISLBPoolRead, @@ -58,7 +61,7 @@ func resourceIBMISLBPool() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceIBMISLBPoolCookieValidate(diff) + return flex.ResourceIBMISLBPoolCookieValidate(diff) }, ), @@ -66,7 +69,7 @@ func resourceIBMISLBPool() *schema.Resource { isLBPoolName: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolName), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolName), Description: "Load Balancer Pool name", }, @@ -80,14 +83,14 @@ func resourceIBMISLBPool() *schema.Resource { isLBPoolAlgorithm: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolAlgorithm), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolAlgorithm), Description: "Load Balancer Pool algorithm", }, isLBPoolProtocol: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolProtocol), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolProtocol), Description: "Load Balancer Protocol", }, @@ -112,7 +115,7 @@ func resourceIBMISLBPool() *schema.Resource { isLBPoolHealthType: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolHealthType), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolHealthType), Description: "Load Balancer health type", }, @@ -133,14 +136,14 @@ func resourceIBMISLBPool() *schema.Resource { isLBPoolSessPersistenceType: { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolSessPersistenceType), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolSessPersistenceType), Description: "Load Balancer Pool session persisence type.", }, isLBPoolSessPersistenceAppCookieName: { Type: schema.TypeString, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolSessPersistenceAppCookieName), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolSessPersistenceAppCookieName), Description: "Load Balancer Pool session persisence app cookie name.", }, @@ -160,7 +163,7 @@ func resourceIBMISLBPool() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool", isLBPoolProxyProtocol), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool", isLBPoolProxyProtocol), Description: "PROXY protocol setting for this pool", }, @@ -170,7 +173,7 @@ func resourceIBMISLBPool() *schema.Resource { Description: "The LB Pool id", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the LB resource", @@ -179,68 +182,68 @@ func resourceIBMISLBPool() *schema.Resource { } } -func resourceIBMISLBPoolValidator() *ResourceValidator { +func ResourceIBMISLBPoolValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) algorithm := "round_robin, weighted_round_robin, least_connections" - protocol := "http, tcp, https" + protocol := "http, tcp, https, udp" persistanceType := "source_ip, app_cookie, http_cookie" proxyProtocol := "disabled, v1, v2" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolAlgorithm, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: algorithm}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolProtocol, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: protocol}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolHealthType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: protocol}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolProxyProtocol, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: proxyProtocol}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolSessPersistenceAppCookieName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: "^[-A-Za-z0-9!#$%&'*+.^_`~|]+$", MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolSessPersistenceType, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: persistanceType}) - ibmISLBPoolResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb_pool", Schema: validateSchema} + ibmISLBPoolResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb_pool", Schema: validateSchema} return &ibmISLBPoolResourceValidator } @@ -277,8 +280,8 @@ func resourceIBMISLBPoolCreate(d *schema.ResourceData, meta interface{}) error { healthMonitorPort = int64(hmp.(int)) } isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err := lbPoolCreate(d, meta, name, lbID, algorithm, protocol, healthType, spType, cName, healthMonitorURL, pProtocol, healthDelay, maxRetries, healthTimeOut, healthMonitorPort) if err != nil { @@ -296,8 +299,7 @@ func lbPoolCreate(d *schema.ResourceData, meta interface{}, name, lbID, algorith _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } options := &vpcv1.CreateLoadBalancerPoolOptions{ @@ -339,14 +341,12 @@ func lbPoolCreate(d *schema.ResourceData, meta interface{}, name, lbID, algorith _, err = isWaitForLBPoolActive(sess, lbID, *lbPool.ID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", *lbPool.ID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", *lbPool.ID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } return nil @@ -354,7 +354,7 @@ func lbPoolCreate(d *schema.ResourceData, meta interface{}, name, lbID, algorith func resourceIBMISLBPoolRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -386,7 +386,7 @@ func lbPoolGet(d *schema.ResourceData, meta interface{}, lbID, lbPoolID string) d.SetId("") return nil } - return fmt.Errorf("Error Getting Load Balancer Pool : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer Pool : %s\n%s", err, response) } d.Set(isLBPoolName, *lbPool.Name) d.Set(isLBPool, lbPoolID) @@ -429,15 +429,15 @@ func lbPoolGet(d *schema.ResourceData, meta interface{}, lbID, lbPoolID string) } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } - d.Set(RelatedCRN, *lb.CRN) + d.Set(flex.RelatedCRN, *lb.CRN) return nil } func resourceIBMISLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -526,8 +526,8 @@ func lbPoolUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin loadBalancerPoolPatchModel.Protocol = &protocol isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err := isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf( @@ -542,7 +542,7 @@ func lbPoolUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin LoadBalancerPoolPatch, err := loadBalancerPoolPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerPoolPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerPoolPatch: %s", err) } if sessionPersistenceRemoved { LoadBalancerPoolPatch["session_persistence"] = nil @@ -551,7 +551,7 @@ func lbPoolUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin _, response, err := sess.UpdateLoadBalancerPool(updateLoadBalancerPoolOptions) if err != nil { - return fmt.Errorf("Error Updating Load Balancer Pool : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Load Balancer Pool : %s\n%s", err, response) } _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutUpdate)) @@ -571,7 +571,7 @@ func lbPoolUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin func resourceIBMISLBPoolDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -580,8 +580,8 @@ func resourceIBMISLBPoolDelete(d *schema.ResourceData, meta interface{}) error { lbPoolID := parts[1] isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbPoolDelete(d, meta, lbID, lbPoolID) if err != nil { @@ -606,18 +606,16 @@ func lbPoolDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin d.SetId("") return nil } - return fmt.Errorf("Error Getting vpc load balancer pool(%s): %s\n%s", lbPoolID, err, response) + return fmt.Errorf("[ERROR] Error Getting vpc load balancer pool(%s): %s\n%s", lbPoolID, err, response) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) } deleteLoadBalancerPoolOptions := &vpcv1.DeleteLoadBalancerPoolOptions{ @@ -626,18 +624,16 @@ func lbPoolDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin } response, err = sess.DeleteLoadBalancerPool(deleteLoadBalancerPoolOptions) if err != nil { - return fmt.Errorf("Error Deleting Load Balancer Pool : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Load Balancer Pool : %s\n%s", err, response) } _, err = isWaitForLBPoolDeleted(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is deleted: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is deleted: %s", lbPoolID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } d.SetId("") return nil @@ -645,12 +641,12 @@ func lbPoolDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin func resourceIBMISLBPoolExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of lbID/lbPoolID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of lbID/lbPoolID", d.Id()) } lbID := parts[0] @@ -676,7 +672,7 @@ func lbPoolExists(d *schema.ResourceData, meta interface{}, lbID, lbPoolID strin if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Load balancer pool: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Load balancer pool: %s\n%s", err, response) } return true, nil } @@ -705,7 +701,7 @@ func isLBPoolRefreshFunc(sess *vpcv1.VpcV1, lbId, lbPoolId string) resource.Stat } lbPool, response, err := sess.GetLoadBalancerPool(getlbpOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Load Balancer Pool: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer Pool: %s\n%s", err, response) } if *lbPool.ProvisioningStatus == isLBPoolActive || *lbPool.ProvisioningStatus == isLBPoolFailed { @@ -733,7 +729,7 @@ func isWaitForLBPoolDeleted(lbc *vpcv1.VpcV1, lbId, lbPoolId string, timeout tim func isLBPoolDeleteRefreshFunc(lbc *vpcv1.VpcV1, lbId, lbPoolId string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] is lb pool delete function here") getlbpOptions := &vpcv1.GetLoadBalancerPoolOptions{ LoadBalancerID: &lbId, ID: &lbPoolId, @@ -743,7 +739,7 @@ func isLBPoolDeleteRefreshFunc(lbc *vpcv1.VpcV1, lbId, lbPoolId string) resource if response != nil && response.StatusCode == 404 { return lbPool, isLBPoolDeleteDone, nil } - return nil, "", fmt.Errorf("The vpc load balancer pool %s failed to delete: %s\n%s", lbPoolId, err, response) + return nil, "", fmt.Errorf("[ERROR] The vpc load balancer pool %s failed to delete: %s\n%s", lbPoolId, err, response) } return lbPool, isLBPoolDeletePending, nil } diff --git a/ibm/resource_ibm_is_lb_pool_member.go b/ibm/service/vpc/resource_ibm_is_lb_pool_member.go similarity index 84% rename from ibm/resource_ibm_is_lb_pool_member.go rename to ibm/service/vpc/resource_ibm_is_lb_pool_member.go index 2a19d2999..5ec485b61 100644 --- a/ibm/resource_ibm_is_lb_pool_member.go +++ b/ibm/service/vpc/resource_ibm_is_lb_pool_member.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -9,6 +9,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -29,7 +32,7 @@ const ( isLBPoolUpdating = "updating" ) -func resourceIBMISLBPoolMember() *schema.Resource { +func ResourceIBMISLBPoolMember() *schema.Resource { return &schema.Resource{ Create: resourceIBMISLBPoolMemberCreate, Read: resourceIBMISLBPoolMemberRead, @@ -101,7 +104,7 @@ func resourceIBMISLBPoolMember() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_lb_pool_member", isLBPoolMemberWeight), + ValidateFunc: validate.InvokeValidator("ibm_is_lb_pool_member", isLBPoolMemberWeight), Description: "Load balcner pool member weight", }, @@ -123,7 +126,7 @@ func resourceIBMISLBPoolMember() *schema.Resource { Description: "LB pool member Href value", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the LB resource", @@ -132,19 +135,19 @@ func resourceIBMISLBPoolMember() *schema.Resource { } } -func resourceIBMISLBPoolMemberValidator() *ResourceValidator { +func ResourceIBMISLBPoolMemberValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isLBPoolMemberWeight, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, Optional: true, MinValue: "0", MaxValue: "100"}) - ibmISLBResourceValidator := ResourceValidator{ResourceName: "ibm_is_lb_pool_member", Schema: validateSchema} + ibmISLBResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_lb_pool_member", Schema: validateSchema} return &ibmISLBResourceValidator } @@ -161,12 +164,10 @@ func resourceIBMISLBPoolMemberCreate(d *schema.ResourceData, meta interface{}) e port64 := int64(port) var weight int64 - if w, ok := d.GetOkExists(isLBPoolMemberWeight); ok { - weight = int64(w.(int)) - } + isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbpMemberCreate(d, meta, lbID, lbPoolID, port64, weight) if err != nil { @@ -183,14 +184,12 @@ func lbpMemberCreate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID st } _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } options := &vpcv1.CreateLoadBalancerPoolMemberOptions{ @@ -212,7 +211,10 @@ func lbpMemberCreate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID st } options.Target = target } - options.Weight = &weight + if w, ok := d.GetOkExists(isLBPoolMemberWeight); ok { + weight = int64(w.(int)) + options.Weight = &weight + } lbPoolMember, response, err := sess.CreateLoadBalancerPoolMember(options) if err != nil { @@ -229,14 +231,12 @@ func lbpMemberCreate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID st _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } return nil @@ -267,7 +267,7 @@ func isLBPoolMemberRefreshFunc(lbc *vpcv1.VpcV1, lbID, lbPoolID, lbPoolMemID str } lbPoolMem, response, err := lbc.GetLoadBalancerPoolMember(getlbpmoptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Load Balancer Pool Member: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer Pool Member: %s\n%s", err, response) } if *lbPoolMem.ProvisioningStatus == isLBPoolMemberActive { @@ -280,7 +280,7 @@ func isLBPoolMemberRefreshFunc(lbc *vpcv1.VpcV1, lbID, lbPoolID, lbPoolMemID str func resourceIBMISLBPoolMemberRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -318,7 +318,7 @@ func lbpmemberGet(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, lbPo d.SetId("") return nil } - return fmt.Errorf("Error Getting Load Balancer Pool Member: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer Pool Member: %s\n%s", err, response) } d.Set(isLBPoolID, lbPoolID) d.Set(isLBID, lbID) @@ -340,15 +340,15 @@ func lbpmemberGet(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, lbPo } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("Error Getting Load Balancer : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) } - d.Set(RelatedCRN, *lb.CRN) + d.Set(flex.RelatedCRN, *lb.CRN) return nil } func resourceIBMISLBPoolMemberUpdate(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -377,8 +377,8 @@ func lbpmemberUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l weight := int64(d.Get(isLBPoolMemberWeight).(int)) isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutUpdate)) if err != nil { @@ -424,13 +424,13 @@ func lbpmemberUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l loadBalancerPoolMemberPatch, err := loadBalancerPoolMemberPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for LoadBalancerPoolMemberPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerPoolMemberPatch: %s", err) } updatelbpmoptions.LoadBalancerPoolMemberPatch = loadBalancerPoolMemberPatch _, response, err := sess.UpdateLoadBalancerPoolMember(updatelbpmoptions) if err != nil { - return fmt.Errorf("Error Updating Load Balancer Pool Member: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Load Balancer Pool Member: %s\n%s", err, response) } _, err = isWaitForLBPoolMemberAvailable(sess, lbID, lbPoolID, lbPoolMemID, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -454,7 +454,7 @@ func lbpmemberUpdate(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l func resourceIBMISLBPoolMemberDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -464,8 +464,8 @@ func resourceIBMISLBPoolMemberDelete(d *schema.ResourceData, meta interface{}) e lbPoolMemID := parts[2] isLBKey := "load_balancer_key_" + lbID - ibmMutexKV.Lock(isLBKey) - defer ibmMutexKV.Unlock(isLBKey) + conns.IbmMutexKV.Lock(isLBKey) + defer conns.IbmMutexKV.Unlock(isLBKey) err = lbpmemberDelete(d, meta, lbID, lbPoolID, lbPoolMemID) if err != nil { @@ -492,7 +492,7 @@ func lbpmemberDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l d.SetId("") return nil } - return fmt.Errorf("Error Getting Load Balancer Pool Member: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Load Balancer Pool Member: %s\n%s", err, response) } _, err = isWaitForLBPoolMemberAvailable(sess, lbID, lbPoolID, lbPoolMemID, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -501,14 +501,12 @@ func lbpmemberDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } dellbpmoptions := &vpcv1.DeleteLoadBalancerPoolMemberOptions{ @@ -518,7 +516,7 @@ func lbpmemberDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l } response, err = sess.DeleteLoadBalancerPoolMember(dellbpmoptions) if err != nil { - return fmt.Errorf("Error Deleting Load Balancer Pool Member: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Load Balancer Pool Member: %s\n%s", err, response) } _, err = isWaitForLBPoolMemberDeleted(sess, lbID, lbPoolID, lbPoolMemID, d.Timeout(schema.TimeoutDelete)) @@ -528,14 +526,12 @@ func lbpmemberDelete(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l _, err = isWaitForLBPoolActive(sess, lbID, lbPoolID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer pool (%s) is active: %s", lbPoolID, err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) } d.SetId("") @@ -570,14 +566,14 @@ func isDeleteLBPoolMemberRefreshFunc(lbc *vpcv1.VpcV1, lbID, lbPoolID, lbPoolMem if response != nil && response.StatusCode == 404 { return lbPoolMem, isLBPoolMemberDeleted, nil } - return nil, "", fmt.Errorf("Error Deleting Load balancer pool member: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Deleting Load balancer pool member: %s\n%s", err, response) } return lbPoolMem, isLBPoolMemberDeletePending, nil } } func resourceIBMISLBPoolMemberExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } @@ -611,14 +607,14 @@ func lbpmemberExists(d *schema.ResourceData, meta interface{}, lbID, lbPoolID, l if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Load balancer pool member: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Load balancer pool member: %s\n%s", err, response) } return true, nil } func getPoolId(id string) (string, error) { if strings.Contains(id, "/") { - parts, err := idParts(id) + parts, err := flex.IdParts(id) if err != nil { return "", err } diff --git a/ibm/service/vpc/resource_ibm_is_lb_pool_member_test.go b/ibm/service/vpc/resource_ibm_is_lb_pool_member_test.go new file mode 100644 index 000000000..9a3b16f75 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_lb_pool_member_test.go @@ -0,0 +1,320 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISLBPoolMember_basic(t *testing.T) { + var lb string + + vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + port := "8080" + port1 := "9000" + address := "127.0.0.1" + address1 := "192.168.0.1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBPoolMemberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, port, address), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_lb_mem", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_lb_mem", "port", port), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_lb_mem", "target_address", address), + ), + }, + + { + Config: testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, port1, address1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_lb_mem", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_lb_mem", "port", port1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_lb_mem", "target_address", address1), + ), + }, + }, + }) +} + +func TestAccIBMISLBPoolMember_basic_network(t *testing.T) { + var lb string + + vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) + nlbPoolName := fmt.Sprintf("tfnlbpoolc%d", acctest.RandIntRange(10, 100)) + + nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) + nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) + + sshname := "terraform-test-ssh-key" + vsiName := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBPoolMemberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBPoolMemberIDConfig( + vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, acc.IsImageName, + vsiName, nlbName, nlbPoolName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_nlb_mem", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_nlb_mem", "weight", "20"), + ), + }, + { + Config: testAccCheckIBMISLBPoolMemberIDConfig( + vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, acc.IsImageName, + vsiName, nlbName1, nlbPoolName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_nlb_mem", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool_member.testacc_nlb_mem", "port", "8080"), + ), + }, + }, + }) +} + +// Weight set to zero from TF when it wasn't passed, must be kept blank so that backend could set it to default. +// Function to validate if the weight is set to default as 50, when it is not provided in TF config. +func TestAccIBMISLBPoolMember_basic_opt_weight_check(t *testing.T) { + var lb string + + vpcname := fmt.Sprintf("tflbpm-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpmc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + port := "8080" + address := "127.0.0.1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBPoolMemberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBPoolMemberWeightConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, port, address), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolMemberExists("ibm_is_lb_pool_member.testacc_lb_mem_wgt", lb), + resource.TestCheckResourceAttr("ibm_is_lb_pool_member.testacc_lb_mem_wgt", "weight", "50"), + ), + }, + }, + }) +} + +func testAccCheckIBMISLBPoolMemberDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_lb_pool_member" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + lbID := parts[0] + lbPoolID := parts[1] + lbPoolMemID := parts[2] + getlbpmoptions := &vpcv1.GetLoadBalancerPoolMemberOptions{ + LoadBalancerID: &lbID, + PoolID: &lbPoolID, + ID: &lbPoolMemID, + } + _, _, err1 := sess.GetLoadBalancerPoolMember(getlbpmoptions) + + if err1 == nil { + return fmt.Errorf("LB Pool member still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISLBPoolMemberExists(n, lbPoolMember string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + lbID := parts[0] + lbPoolID := parts[1] + lbPoolMemID := parts[2] + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getlbpmoptions := &vpcv1.GetLoadBalancerPoolMemberOptions{ + LoadBalancerID: &lbID, + PoolID: &lbPoolID, + ID: &lbPoolMemID, + } + foundLBPoolMember, _, err := sess.GetLoadBalancerPoolMember(getlbpmoptions) + if err != nil { + return err + } + lbPoolMember = *foundLBPoolMember.ID + + return nil + } +} + +func testAccCheckIBMISLBPoolMemberConfig(vpcname, subnetname, zone, cidr, name, poolName, port, address string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_pool" "testacc_lb_pool" { + name = "%s" + lb = "${ibm_is_lb.testacc_LB.id}" + algorithm = "round_robin" + protocol = "http" + health_delay= 45 + health_retries = 5 + health_timeout = 30 + health_type = "tcp" + } + resource "ibm_is_lb_pool_member" "testacc_lb_mem" { + lb = "${ibm_is_lb.testacc_LB.id}" + pool = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" + port = "%s" + target_address = "%s" +}`, vpcname, subnetname, zone, cidr, name, poolName, port, address) +} + +func testAccCheckIBMISLBPoolMemberIDConfig(vpcname, subnetname, zone, cidr, sshname, + isImageName, vsiName, nlbName, nlbPoolName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + data "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + } + data "ibm_is_image" "ds_image" { + name = "%s" + } + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = data.ibm_is_image.ds_image.id + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [data.ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_lb" "testacc_NLB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + profile = "network-fixed" + } + resource "ibm_is_lb_pool" "testacc_nlb_pool" { + name = "%s" + lb = "${ibm_is_lb.testacc_NLB.id}" + algorithm = "weighted_round_robin" + protocol = "tcp" + health_delay = 60 + health_retries = 5 + health_timeout = 30 + health_type = "tcp" + } + resource "ibm_is_lb_pool_member" "testacc_nlb_mem" { + lb = "${ibm_is_lb.testacc_NLB.id}" + pool = "${element(split("/",ibm_is_lb_pool.testacc_nlb_pool.id),1)}" + port = 8080 + weight = 20 + target_id = "${ibm_is_instance.testacc_instance.id}" + } +`, vpcname, subnetname, zone, cidr, sshname, isImageName, vsiName, + acc.InstanceProfileName, zone, nlbName, nlbPoolName) +} + +func testAccCheckIBMISLBPoolMemberWeightConfig(vpcname, subnetname, zone, cidr, name, poolName, port, address string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_pool" "testacc_lb_pool" { + name = "%s" + lb = "${ibm_is_lb.testacc_LB.id}" + algorithm = "round_robin" + protocol = "http" + health_delay= 45 + health_retries = 5 + health_timeout = 30 + health_type = "tcp" + } + resource "ibm_is_lb_pool_member" "testacc_lb_mem_wgt" { + lb = "${ibm_is_lb.testacc_LB.id}" + pool = "${element(split("/",ibm_is_lb_pool.testacc_lb_pool.id),1)}" + port = "%s" + target_address = "%s" +}`, vpcname, subnetname, zone, cidr, name, poolName, port, address) +} diff --git a/ibm/resource_ibm_is_lb_pool_test.go b/ibm/service/vpc/resource_ibm_is_lb_pool_test.go similarity index 79% rename from ibm/resource_ibm_is_lb_pool_test.go rename to ibm/service/vpc/resource_ibm_is_lb_pool_test.go index 1b905576e..f5baeb13a 100644 --- a/ibm/resource_ibm_is_lb_pool_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_pool_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -38,12 +42,12 @@ func TestAccIBMISLBPool_basic(t *testing.T) { healthType2 := "tcp" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBPoolDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBPoolConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), + Config: testAccCheckIBMISLBPoolConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -68,7 +72,7 @@ func TestAccIBMISLBPool_basic(t *testing.T) { }, { - Config: testAccCheckIBMISLBPoolConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName1, alg2, protocol2, delay2, retries2, timeout2, healthType2), + Config: testAccCheckIBMISLBPoolConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName1, alg2, protocol2, delay2, retries2, timeout2, healthType2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -90,7 +94,7 @@ func TestAccIBMISLBPool_basic(t *testing.T) { ), }, { - Config: testAccCheckIBMISLBPoolConfigWithProxy(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, proxyProtocol2, delay1, retries1, timeout1, healthType1), + Config: testAccCheckIBMISLBPoolConfigWithProxy(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, proxyProtocol2, delay1, retries1, timeout1, healthType1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -116,6 +120,49 @@ func TestAccIBMISLBPool_basic(t *testing.T) { }, }) } +func TestAccIBMISLBPool_basic_udp(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflbp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflbpc-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + poolName := fmt.Sprintf("tflbpoolc%d", acctest.RandIntRange(10, 100)) + alg1 := "round_robin" + protocol1 := "udp" + delay1 := "5" + retries1 := "2" + timeout1 := "2" + healthType1 := "http" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBPoolUdpConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "name", poolName), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "algorithm", alg1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "protocol", protocol1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "health_delay", delay1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "health_retries", retries1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "health_timeout", timeout1), + resource.TestCheckResourceAttr( + "ibm_is_lb_pool.testacc_lb_pool", "health_type", healthType1), + ), + }, + }, + }) +} func TestAccIBMISLBPool_port(t *testing.T) { var lb string @@ -133,12 +180,12 @@ func TestAccIBMISLBPool_port(t *testing.T) { port := "2554" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBPoolDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBPoolPortConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port), + Config: testAccCheckIBMISLBPoolPortConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -184,12 +231,12 @@ func TestAccIBMISLBPool_SessionPersistence(t *testing.T) { app_cookie_name := "testacc_cookie" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISLBPoolDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISLBPoolSessionPersistenceConfig(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port, session_persistence_appcookie_type, app_cookie_name), + Config: testAccCheckIBMISLBPoolSessionPersistenceConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port, session_persistence_appcookie_type, app_cookie_name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -219,7 +266,7 @@ func TestAccIBMISLBPool_SessionPersistence(t *testing.T) { ), }, { - Config: testAccCheckIBMISLBPoolSessionPersistenceConfigUpdate(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port, session_persistence_httpcookie_type), + Config: testAccCheckIBMISLBPoolSessionPersistenceConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port, session_persistence_httpcookie_type), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -249,7 +296,7 @@ func TestAccIBMISLBPool_SessionPersistence(t *testing.T) { ), }, { - Config: testAccCheckIBMISLBPoolSessionPersistenceConfigRemove(vpcname, subnetname, ISZoneName, ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port), + Config: testAccCheckIBMISLBPoolSessionPersistenceConfigRemove(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, poolName, alg1, protocol1, delay1, retries1, timeout1, healthType1, port), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISLBPoolExists("ibm_is_lb_pool.testacc_lb_pool", lb), resource.TestCheckResourceAttr( @@ -284,13 +331,13 @@ func TestAccIBMISLBPool_SessionPersistence(t *testing.T) { func testAccCheckIBMISLBPoolDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_lb_pool" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -322,7 +369,7 @@ func testAccCheckIBMISLBPoolExists(n, lbPool string) resource.TestCheckFunc { return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -330,7 +377,7 @@ func testAccCheckIBMISLBPoolExists(n, lbPool string) resource.TestCheckFunc { lbID := parts[0] lbPoolID := parts[1] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getlbpptions := &vpcv1.GetLoadBalancerPoolOptions{ LoadBalancerID: &lbID, ID: &lbPoolID, @@ -372,6 +419,37 @@ func testAccCheckIBMISLBPoolConfig(vpcname, subnetname, zone, cidr, name, poolNa health_type = "%s" }`, vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType) +} +func testAccCheckIBMISLBPoolUdpConfig(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + profile = "network-fixed" + type = "public" + } + resource "ibm_is_lb_pool" "testacc_lb_pool" { + name = "%s" + lb = "${ibm_is_lb.testacc_LB.id}" + algorithm = "%s" + protocol = "%s" + health_delay = %s + health_retries = %s + health_timeout = %s + health_type = "%s" + health_monitor_url = "/" +}`, vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType) + } func testAccCheckIBMISLBPoolPortConfig(vpcname, subnetname, zone, cidr, name, poolName, algorithm, protocol, delay, retries, timeout, healthType, port string) string { diff --git a/ibm/service/vpc/resource_ibm_is_lb_test.go b/ibm/service/vpc/resource_ibm_is_lb_test.go new file mode 100644 index 000000000..70e07c679 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_lb_test.go @@ -0,0 +1,560 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testAccCheckIBMISLBUdpConfig(vpcname, subnetname, zone, cidr, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + profile = "network-fixed" + type = "public" +}`, vpcname, subnetname, zone, cidr, name) + +} +func TestAccIBMISLB_basic_udp(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBUdpConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "hostname"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "udp_supported", "true"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "udp_supported"), + ), + }, + + { + Config: testAccCheckIBMISLBUdpConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "udp_supported", "true"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "udp_supported"), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "hostname"), + ), + }, + + { + Config: testAccCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_subnet(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tflb-subnet-name1-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBSubnetConfig(vpcname, subnetname, subnetname1, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "hostname"), + ), + }, + + { + Config: testAccCheckIBMISLBSubnetConfig(vpcname, subnetname, subnetname1, acc.ISZoneName, acc.ISCIDR, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name1), + ), + }, + }, + }) +} +func TestAccIBMISLB_basic_rip(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "hostname"), + ), + }, + + { + Config: testAccCheckIBMISLBConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name1), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "private_ip.0.address"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "private_ip.0.href"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "private_ip.0.name"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "private_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_LB", "private_ip.0.resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_logging(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBLoggingCongig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "logging", "true"), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_securityGroups(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + securityGroup := fmt.Sprintf("tflbsecuritygroup%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBSecurityGroupConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, securityGroup), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "logging", "false"), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_network(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) + nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, nlbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "name", nlbName), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_NLB", "hostname"), + ), + }, + + { + Config: testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, nlbName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "name", nlbName1), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_network_vnf(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflb-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-subnet-name-%d", acctest.RandIntRange(10, 100)) + nlbName := fmt.Sprintf("tfnlbcreate%d", acctest.RandIntRange(10, 100)) + nlbName1 := fmt.Sprintf("tfnlbupdate%d", acctest.RandIntRange(10, 100)) + routeModeTrue := true + routeModeFalse := false + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, nlbName, routeModeTrue), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "route_mode", fmt.Sprintf("%t", routeModeTrue)), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "profile", "network-fixed"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "type", "private"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "name", nlbName), + resource.TestCheckResourceAttrSet( + "ibm_is_lb.testacc_NLB", "hostname"), + ), + }, + + { + Config: testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, nlbName1, routeModeFalse), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_NLB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "route_mode", fmt.Sprintf("%t", routeModeFalse)), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "profile", "network-fixed"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "type", "private"), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_NLB", "name", nlbName1), + ), + }, + }, + }) +} + +func TestAccIBMISLB_basic_private(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflbt-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflb-create-name-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfcreate%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfupdate%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name), + ), + }, + + { + Config: testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBExists("ibm_is_lb.testacc_LB", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", name1), + ), + }, + }, + }) +} + +func testAccCheckIBMISLBDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_lb" { + continue + } + + getlboptions := &vpcv1.GetLoadBalancerOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetLoadBalancer(getlboptions) + if err == nil { + return fmt.Errorf("LB still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISLBExists(n, lb string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getlboptions := &vpcv1.GetLoadBalancerOptions{ + ID: &rs.Primary.ID, + } + foundLB, _, err := sess.GetLoadBalancer(getlboptions) + if err != nil { + return err + } + lb = *foundLB.ID + + return nil + } +} + +func testAccCheckIBMISLBConfig(vpcname, subnetname, zone, cidr, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] +}`, vpcname, subnetname, zone, cidr, name) + +} + +func testAccCheckIBMISLBSubnetConfig(vpcname, subnetname, subnetname1, zone, cidr, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id, ibm_is_subnet.testacc_subnet1.id] +}`, vpcname, subnetname, zone, cidr, subnetname1, acc.ISZoneName2, acc.ISCIDR2, name) + +} + +func testAccCheckIBMISLBLoggingCongig(vpcname, subnetname, zone, cidr, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + logging = true +}`, vpcname, subnetname, zone, cidr, name) + +} + +func testAccCheckIBMISLBNetworkConfig(vpcname, subnetname, zone, cidr, nlbName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_NLB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + profile = "network-fixed" + }`, vpcname, subnetname, zone, cidr, nlbName) + +} + +func testAccCheckIBMISLBNetworkRouteModeConfig(vpcname, subnetname, zone, cidr, nlbName string, routeMode bool) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_is_lb" "testacc_NLB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + profile = "network-fixed" + route_mode = %t + type = "private" + }`, vpcname, subnetname, zone, nlbName, routeMode) + +} + +func testAccCheckIBMISLBConfigPrivate(vpcname, subnetname, zone, cidr, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + type = "private" +}`, vpcname, subnetname, zone, cidr, name) + +} + +func testAccCheckIBMISLBSecurityGroupConfig(vpcname, subnetname, zone, cidr, name, securityGroup string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_lb" "testacc_LB" { + name = "%s" + subnets = [ibm_is_subnet.testacc_subnet.id] + security_groups = [ibm_is_security_group.testacc_security_group.id] + logging = false +}`, vpcname, subnetname, zone, cidr, securityGroup, name) + +} diff --git a/ibm/resource_ibm_is_network_acl_rule.go b/ibm/service/vpc/resource_ibm_is_network_acl_rule.go similarity index 84% rename from ibm/resource_ibm_is_network_acl_rule.go rename to ibm/service/vpc/resource_ibm_is_network_acl_rule.go index 85f078b35..a8377f313 100644 --- a/ibm/resource_ibm_is_network_acl_rule.go +++ b/ibm/service/vpc/resource_ibm_is_network_acl_rule.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -23,7 +25,7 @@ const ( isNwACLRuleBefore = "before" ) -func resourceIBMISNetworkACLRule() *schema.Resource { +func ResourceIBMISNetworkACLRule() *schema.Resource { return &schema.Resource{ Create: resourceIBMISNetworkACLRuleCreate, Read: resourceIBMISNetworkACLRuleRead, @@ -38,7 +40,7 @@ func resourceIBMISNetworkACLRule() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -75,14 +77,14 @@ func resourceIBMISNetworkACLRule() *schema.Resource { Optional: true, ForceNew: false, Description: "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleName), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleName), }, isNetworkACLRuleAction: { Type: schema.TypeString, Required: true, ForceNew: false, Description: "Whether to allow or deny matching traffic", - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleAction), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleAction), }, isNetworkACLRuleIPVersion: { Type: schema.TypeString, @@ -94,13 +96,13 @@ func resourceIBMISNetworkACLRule() *schema.Resource { Required: true, ForceNew: false, Description: "The source CIDR block. The CIDR block 0.0.0.0/0 applies to all addresses.", - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSource), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSource), }, isNetworkACLRuleDestination: { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleDestination), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleDestination), Description: "The destination CIDR block. The CIDR block 0.0.0.0/0 applies to all addresses.", }, isNetworkACLRuleDirection: { @@ -108,7 +110,7 @@ func resourceIBMISNetworkACLRule() *schema.Resource { Required: true, ForceNew: false, Description: "Direction of traffic to enforce, either inbound or outbound", - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleDirection), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleDirection), }, isNetworkACLRuleICMP: { Type: schema.TypeList, @@ -122,13 +124,13 @@ func resourceIBMISNetworkACLRule() *schema.Resource { isNetworkACLRuleICMPCode: { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleICMPCode), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleICMPCode), Description: "The ICMP traffic code to allow. Valid values from 0 to 255.", }, isNetworkACLRuleICMPType: { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleICMPType), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleICMPType), Description: "The ICMP traffic type to allow. Valid values from 0 to 254.", }, }, @@ -148,28 +150,28 @@ func resourceIBMISNetworkACLRule() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMax), Description: "The highest port in the range of ports to be matched", }, isNetworkACLRulePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMin), Description: "The lowest port in the range of ports to be matched", }, isNetworkACLRuleSourcePortMax: { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMax), Description: "The highest port in the range of ports to be matched", }, isNetworkACLRuleSourcePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMin), Description: "The lowest port in the range of ports to be matched", }, }, @@ -189,28 +191,28 @@ func resourceIBMISNetworkACLRule() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMax), Description: "The highest port in the range of ports to be matched", }, isNetworkACLRulePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRulePortMin), Description: "The lowest port in the range of ports to be matched", }, isNetworkACLRuleSourcePortMax: { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMax), Description: "The highest port in the range of ports to be matched", }, isNetworkACLRuleSourcePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl_rule", isNetworkACLRuleSourcePortMin), Description: "The lowest port in the range of ports to be matched", }, }, @@ -220,109 +222,109 @@ func resourceIBMISNetworkACLRule() *schema.Resource { } } -func resourceIBMISNetworkACLRuleValidator() *ResourceValidator { +func ResourceIBMISNetworkACLRuleValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) direction := "inbound, outbound" action := "allow, deny" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: action}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleDirection, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: direction}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNwACLID, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleDestination, - ValidateFunctionIdentifier: ValidateIPorCIDR, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateIPorCIDR, + Type: validate.TypeString, Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSource, - ValidateFunctionIdentifier: ValidateIPorCIDR, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateIPorCIDR, + Type: validate.TypeString, Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleICMPType, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "254"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleICMPCode, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "255"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRulePortMin, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRulePortMax, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSourcePortMin, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSourcePortMax, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISNetworkACLRuleResourceValidator := ResourceValidator{ResourceName: "ibm_is_network_acl_rule", Schema: validateSchema} + ibmISNetworkACLRuleResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_network_acl_rule", Schema: validateSchema} return &ibmISNetworkACLRuleResourceValidator } @@ -441,7 +443,7 @@ func nwaclRuleCreate(d *schema.ResourceData, meta interface{}, nwACLID string) e } nwaclRule, response, err := sess.CreateNetworkACLRule(createNetworkAclRuleOptions) if err != nil || nwaclRule == nil { - return fmt.Errorf("Error Creating network ACL rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating network ACL rule : %s\n%s", err, response) } err = nwaclRuleGet(d, meta, nwACLID, nwaclRule) if err != nil { @@ -469,7 +471,7 @@ func resourceIBMISNetworkACLRuleRead(d *schema.ResourceData, meta interface{}) e d.SetId("") return nil } - return fmt.Errorf("Error getting Network ACL Rule (%s) : %s\n%s", ruleId, err, response) + return fmt.Errorf("[ERROR] Error getting Network ACL Rule (%s) : %s\n%s", ruleId, err, response) } err = nwaclRuleGet(d, meta, nwACLID, nwaclRule) if err != nil { @@ -740,12 +742,12 @@ func nwaclRuleUpdate(d *schema.ResourceData, meta interface{}, id, nwACLId strin if hasChanged { updateNetworkACLOptionsPatch, err := updateNetworkACLOptionsPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for NetworkACLOptionsPatch : %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for NetworkACLOptionsPatch : %s", err) } updateNetworkACLRuleOptions.NetworkACLRulePatch = updateNetworkACLOptionsPatch _, response, err := sess.UpdateNetworkACLRule(updateNetworkACLRuleOptions) if err != nil { - return fmt.Errorf("Error Updating Network ACL Rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Network ACL Rule : %s\n%s", err, response) } } return nil @@ -782,7 +784,7 @@ func nwaclRuleDelete(d *schema.ResourceData, meta interface{}, id, nwACLId strin d.SetId("") return nil } - return fmt.Errorf("Error Getting Network ACL Rule (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Network ACL Rule (%s): %s\n%s", id, err, response) } deleteNetworkAclRuleOptions := &vpcv1.DeleteNetworkACLRuleOptions{ @@ -791,7 +793,7 @@ func nwaclRuleDelete(d *schema.ResourceData, meta interface{}, id, nwACLId strin } response, err = sess.DeleteNetworkACLRule(deleteNetworkAclRuleOptions) if err != nil { - return fmt.Errorf("Error Deleting Network ACL Rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Network ACL Rule : %s\n%s", err, response) } d.SetId("") return nil @@ -811,7 +813,7 @@ func nwaclRuleExists(d *schema.ResourceData, meta interface{}, id, nwACLId strin if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Network ACL Rule: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Network ACL Rule: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_network_acl_rule_test.go b/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go similarity index 90% rename from ibm/resource_ibm_is_network_acl_rule_test.go rename to ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go index e94af697f..356cc3783 100644 --- a/ibm/resource_ibm_is_network_acl_rule_test.go +++ b/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go @@ -1,14 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "reflect" + "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -21,8 +25,8 @@ func TestNetworkACLRule_basicICMP(t *testing.T) { ruleName := fmt.Sprintf("tf-outbound-icmp-%d", acctest.RandIntRange(10, 100)) updatedRuleName := fmt.Sprintf("%s-update", ruleName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLRuleDestroy, Steps: []resource.TestStep{ { @@ -59,8 +63,8 @@ func TestNetworkACLRule_basicAll(t *testing.T) { ruleName := fmt.Sprintf("tf-outbound-all-%d", acctest.RandIntRange(10, 100)) updatedRuleName := fmt.Sprintf("%s-update", ruleName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLRuleDestroy, Steps: []resource.TestStep{ { @@ -89,8 +93,8 @@ func TestNetworkACLRule_basicTCP(t *testing.T) { ruleName := fmt.Sprintf("tf-outbound-tcp-%d", acctest.RandIntRange(10, 100)) updatedRuleName := fmt.Sprintf("%s-update", ruleName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLRuleDestroy, Steps: []resource.TestStep{ { @@ -127,8 +131,8 @@ func TestNetworkACLRule_basicUDP(t *testing.T) { ruleName := fmt.Sprintf("tf-outbound-udp-%d", acctest.RandIntRange(10, 100)) updatedRuleName := fmt.Sprintf("%s-update", ruleName) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLRuleDestroy, Steps: []resource.TestStep{ { @@ -160,7 +164,7 @@ func TestNetworkACLRule_basicUDP(t *testing.T) { } func checkNetworkACLRuleDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_network_acl_rule" { continue @@ -177,6 +181,21 @@ func checkNetworkACLRuleDestroy(s *terraform.State) error { } return nil } +func makeTerraformACLRuleID(id1, id2 string) string { + // Include both network acl id and rule id to create a unique Terraform id. As a bonus, + // we can extract the network acl id as needed for API calls such as READ. + return fmt.Sprintf("%s/%s", id1, id2) +} +func parseNwACLTerraformID(s string) (string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], nil +} func testAccCheckIBMISNetworkACLRuleExists(n, nwACLRule string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -189,7 +208,7 @@ func testAccCheckIBMISNetworkACLRuleExists(n, nwACLRule string) resource.TestChe return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() nwACLID, ruleID, err := parseNwACLTerraformID(rs.Primary.ID) getnwaclRuleoptions := &vpcv1.GetNetworkACLRuleOptions{ ID: &ruleID, diff --git a/ibm/resource_ibm_is_networkacls.go b/ibm/service/vpc/resource_ibm_is_networkacls.go similarity index 81% rename from ibm/resource_ibm_is_networkacls.go rename to ibm/service/vpc/resource_ibm_is_networkacls.go index f5e78e697..4ac3f3f9d 100644 --- a/ibm/resource_ibm_is_networkacls.go +++ b/ibm/service/vpc/resource_ibm_is_networkacls.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -12,6 +12,8 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -45,7 +47,7 @@ const ( isNetworkACLCRN = "crn" ) -func resourceIBMISNetworkACL() *schema.Resource { +func ResourceIBMISNetworkACL() *schema.Resource { return &schema.Resource{ Create: resourceIBMISNetworkACLCreate, Read: resourceIBMISNetworkACLRead, @@ -61,7 +63,7 @@ func resourceIBMISNetworkACL() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -70,7 +72,7 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLName), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLName), Description: "Network ACL name", }, isNetworkACLVPC: { @@ -90,8 +92,8 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_network_acl", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, @@ -100,24 +102,24 @@ func resourceIBMISNetworkACL() *schema.Resource { Computed: true, Description: "The crn of the resource", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -136,13 +138,13 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleName), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleName), }, isNetworkACLRuleAction: { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleAction), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleAction), }, isNetworkACLRuleIPVersion: { Type: schema.TypeString, @@ -152,20 +154,20 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSource), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSource), }, isNetworkACLRuleDestination: { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleDestination), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleDestination), }, isNetworkACLRuleDirection: { Type: schema.TypeString, Required: true, ForceNew: false, Description: "Direction of traffic to enforce, either inbound or outbound", - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleDirection), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleDirection), }, isNetworkACLSubnets: { Type: schema.TypeInt, @@ -181,12 +183,12 @@ func resourceIBMISNetworkACL() *schema.Resource { isNetworkACLRuleICMPCode: { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleICMPCode), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleICMPCode), }, isNetworkACLRuleICMPType: { Type: schema.TypeInt, Optional: true, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleICMPType), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleICMPType), }, }, }, @@ -203,25 +205,25 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMax), }, isNetworkACLRulePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMin), }, isNetworkACLRuleSourcePortMax: { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMax), }, isNetworkACLRuleSourcePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMin), }, }, }, @@ -238,25 +240,25 @@ func resourceIBMISNetworkACL() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMax), }, isNetworkACLRulePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRulePortMin), }, isNetworkACLRuleSourcePortMax: { Type: schema.TypeInt, Optional: true, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMax), }, isNetworkACLRuleSourcePortMin: { Type: schema.TypeInt, Optional: true, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_network_acl", isNetworkACLRuleSourcePortMin), }, }, }, @@ -268,109 +270,109 @@ func resourceIBMISNetworkACL() *schema.Resource { } } -func resourceIBMISNetworkACLValidator() *ResourceValidator { +func ResourceIBMISNetworkACLValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) direction := "inbound, outbound" action := "allow, deny" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: action}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleDirection, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: direction}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleDestination, - ValidateFunctionIdentifier: ValidateIPorCIDR, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateIPorCIDR, + Type: validate.TypeString, Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSource, - ValidateFunctionIdentifier: ValidateIPorCIDR, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateIPorCIDR, + Type: validate.TypeString, Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleICMPType, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "254"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleICMPCode, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "255"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRulePortMin, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRulePortMax, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSourcePortMin, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isNetworkACLRuleSourcePortMax, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISNetworkACLResourceValidator := ResourceValidator{ResourceName: "ibm_is_network_acl", Schema: validateSchema} + ibmISNetworkACLResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_network_acl", Schema: validateSchema} return &ibmISNetworkACLResourceValidator } @@ -394,7 +396,7 @@ func nwaclCreate(d *schema.ResourceData, meta interface{}, name string) error { if vpcID, ok := d.GetOk(isNetworkACLVPC); ok { vpc = vpcID.(string) } else { - return fmt.Errorf("Required parameter vpc is not set") + return fmt.Errorf("[ERROR] Required parameter vpc is not set") } nwaclTemplate := &vpcv1.NetworkACLPrototype{ @@ -445,7 +447,7 @@ func nwaclCreate(d *schema.ResourceData, meta interface{}, name string) error { v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isNetworkACLTags); ok || v != "" { oldList, newList := d.GetChange(isNetworkACLTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *nwacl.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *nwacl.CRN) if err != nil { log.Printf( "Error on create of resource network acl (%s) tags: %s", d.Id(), err) @@ -477,15 +479,15 @@ func nwaclGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting Network ACL(%s) : %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting Network ACL(%s) : %s\n%s", id, err, response) } d.Set(isNetworkACLName, *nwacl.Name) d.Set(isNetworkACLVPC, *nwacl.VPC.ID) if nwacl.ResourceGroup != nil { d.Set(isNetworkACLResourceGroup, *nwacl.ResourceGroup.ID) - d.Set(ResourceGroupName, *nwacl.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *nwacl.ResourceGroup.Name) } - tags, err := GetTagsUsingCRN(meta, *nwacl.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *nwacl.CRN) if err != nil { log.Printf( "Error on get of resource network acl (%s) tags: %s", d.Id(), err) @@ -573,13 +575,13 @@ func nwaclGet(d *schema.ResourceData, meta interface{}, id string) error { } } d.Set(isNetworkACLRules, rules) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/acl") - d.Set(ResourceName, *nwacl.Name) - // d.Set(ResourceCRN, *nwacl.Crn) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/acl") + d.Set(flex.ResourceName, *nwacl.Name) + // d.Set(flex.ResourceCRN, *nwacl.Crn) return nil } @@ -616,17 +618,17 @@ func nwaclUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasC } networkACLPatch, err := networkACLPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for NetworkACLPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for NetworkACLPatch: %s", err) } updateNetworkACLOptions.NetworkACLPatch = networkACLPatch _, response, err := sess.UpdateNetworkACL(updateNetworkACLOptions) if err != nil { - return fmt.Errorf("Error Updating Network ACL(%s) : %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Updating Network ACL(%s) : %s\n%s", id, err, response) } } if d.HasChange(isNetworkACLTags) { oldList, newList := d.GetChange(isNetworkACLTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, d.Get(isNetworkACLCRN).(string)) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, d.Get(isNetworkACLCRN).(string)) if err != nil { log.Printf( "Error on update of resource network acl (%s) tags: %s", d.Id(), err) @@ -678,7 +680,7 @@ func nwaclDelete(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting Network ACL (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Network ACL (%s): %s\n%s", id, err, response) } deleteNetworkAclOptions := &vpcv1.DeleteNetworkACLOptions{ @@ -686,7 +688,7 @@ func nwaclDelete(d *schema.ResourceData, meta interface{}, id string) error { } response, err = sess.DeleteNetworkACL(deleteNetworkAclOptions) if err != nil { - return fmt.Errorf("Error Deleting Network ACL : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Network ACL : %s\n%s", err, response) } d.SetId("") return nil @@ -711,7 +713,7 @@ func nwaclExists(d *schema.ResourceData, meta interface{}, id string) (bool, err if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Network ACL: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Network ACL: %s\n%s", err, response) } return true, nil } @@ -735,9 +737,9 @@ func clearRules(nwaclC *vpcv1.VpcV1, nwaclid string) error { } rawrules, response, err := nwaclC.ListNetworkACLRules(listNetworkAclRulesOptions) if err != nil { - return fmt.Errorf("Error Listing network ACL rules : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Listing network ACL rules : %s\n%s", err, response) } - start = GetNext(rawrules.Next) + start = flex.GetNext(rawrules.Next) allrecs = append(allrecs, rawrules.Rules...) if start == "" { break @@ -762,7 +764,7 @@ func clearRules(nwaclC *vpcv1.VpcV1, nwaclid string) error { response, err := nwaclC.DeleteNetworkACLRule(deleteNetworkAclRuleOptions) if err != nil { - return fmt.Errorf("Error Deleting network ACL rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting network ACL rule : %s\n%s", err, response) } } return nil @@ -773,7 +775,7 @@ func validateInlineRules(rules []interface{}) error { rulex := rule.(map[string]interface{}) action := rulex[isNetworkACLRuleAction].(string) if (action != "allow") && (action != "deny") { - return fmt.Errorf("Invalid action. valid values are allow|deny") + return fmt.Errorf("[ERROR] Invalid action. valid values are allow|deny") } direction := rulex[isNetworkACLRuleDirection].(string) @@ -892,7 +894,7 @@ func createInlineRules(nwaclC *vpcv1.VpcV1, nwaclid string, rules []interface{}) } _, response, err := nwaclC.CreateNetworkACLRule(createNetworkAclRuleOptions) if err != nil { - return fmt.Errorf("Error Creating network ACL rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Creating network ACL rule : %s\n%s", err, response) } } return nil diff --git a/ibm/resource_ibm_is_networkacls_test.go b/ibm/service/vpc/resource_ibm_is_networkacls_test.go similarity index 89% rename from ibm/resource_ibm_is_networkacls_test.go rename to ibm/service/vpc/resource_ibm_is_networkacls_test.go index fe212366e..c7ace6f0e 100644 --- a/ibm/resource_ibm_is_networkacls_test.go +++ b/ibm/service/vpc/resource_ibm_is_networkacls_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,11 +19,11 @@ import ( func TestNetworkACLGen1(t *testing.T) { var nwACL string resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISNetworkACLConfig(), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISNetworkACLExists("ibm_is_network_acl.isExampleACL", nwACL), @@ -37,11 +40,11 @@ func TestNetworkACLGen1(t *testing.T) { func TestNetworkACLGen2(t *testing.T) { var nwACL string resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkNetworkACLDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISNetworkACLConfig1(), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISNetworkACLExists("ibm_is_network_acl.isExampleACL", nwACL), @@ -58,7 +61,7 @@ func TestNetworkACLGen2(t *testing.T) { } func checkNetworkACLDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_network_acl" { continue @@ -87,7 +90,7 @@ func testAccCheckIBMISNetworkACLExists(n, nwACL string) resource.TestCheckFunc { if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getnwacloptions := &vpcv1.GetNetworkACLOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/resource_ibm_is_placement_group.go b/ibm/service/vpc/resource_ibm_is_placement_group.go similarity index 78% rename from ibm/resource_ibm_is_placement_group.go rename to ibm/service/vpc/resource_ibm_is_placement_group.go index cc04a7b33..443f65edb 100644 --- a/ibm/resource_ibm_is_placement_group.go +++ b/ibm/service/vpc/resource_ibm_is_placement_group.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -9,6 +9,9 @@ import ( "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -32,7 +35,7 @@ const ( isPlacementGroupAccessTags = "access_tags" ) -func resourceIbmIsPlacementGroup() *schema.Resource { +func ResourceIbmIsPlacementGroup() *schema.Resource { return &schema.Resource{ CreateContext: resourceIbmIsPlacementGroupCreate, ReadContext: resourceIbmIsPlacementGroupRead, @@ -47,7 +50,7 @@ func resourceIbmIsPlacementGroup() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), Schema: map[string]*schema.Schema{ @@ -55,13 +58,13 @@ func resourceIbmIsPlacementGroup() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_placement_group", "strategy"), + ValidateFunc: validate.InvokeValidator("ibm_is_placement_group", "strategy"), Description: "The strategy for this placement group- `host_spread`: place on different compute hosts- `power_spread`: place on compute hosts that use different power sourcesThe enumerated values for this property may expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the placement group on which the unexpected strategy was encountered.", }, "name": { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_placement_group", "name"), + ValidateFunc: validate.InvokeValidator("ibm_is_placement_group", "name"), Description: "The unique user-defined name for this placement group. If unspecified, the name will be a hyphenated list of randomly-selected words.", }, "resource_group": { @@ -75,16 +78,16 @@ func resourceIbmIsPlacementGroup() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_placement_group", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_placement_group", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, isPlacementGroupAccessTags: { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_placement_group", "accesstag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_placement_group", isPlacementGroupAccessTags)}, + Set: flex.ResourceIBMVPCHash, Description: "List of access management tags", }, "created_at": { @@ -116,38 +119,38 @@ func resourceIbmIsPlacementGroup() *schema.Resource { } } -func resourceIbmIsPlacementGroupValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 1) +func ResourceIbmIsPlacementGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "strategy", - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: "host_spread, power_spread", }, - ValidateSchema{ + validate.ValidateSchema{ Identifier: "name", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63, }, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128, }, - ValidateSchema{ - Identifier: "accesstag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: isPlacementGroupAccessTags, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([ ]*[A-Za-z0-9:_.-]+[ ]*)+$`, MinValueLength: 1, @@ -155,12 +158,12 @@ func resourceIbmIsPlacementGroupValidator() *ResourceValidator { }, ) - resourceValidator := ResourceValidator{ResourceName: "ibm_is_placement_group", Schema: validateSchema} + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_placement_group", Schema: validateSchema} return &resourceValidator } func resourceIbmIsPlacementGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -192,7 +195,7 @@ func resourceIbmIsPlacementGroupCreate(context context.Context, d *schema.Resour } if _, ok := d.GetOk(isPlacementGroupTags); ok { oldList, newList := d.GetChange(isPlacementGroupTags) - err = UpdateGlobalTagsUsingCRN(oldList, newList, meta, *placementGroup.CRN, "", isUserTagType) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *placementGroup.CRN, "", isUserTagType) if err != nil { log.Printf( "Error creating placement group (%s) tags: %s", d.Id(), err) @@ -202,7 +205,7 @@ func resourceIbmIsPlacementGroupCreate(context context.Context, d *schema.Resour if _, ok := d.GetOk(isPlacementGroupAccessTags); ok { oldList, newList := d.GetChange(isPlacementGroupAccessTags) - err = UpdateGlobalTagsUsingCRN(oldList, newList, meta, *placementGroup.CRN, "", isAccessTagType) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *placementGroup.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error creating placement group (%s) access tags: %s", d.Id(), err) @@ -213,7 +216,7 @@ func resourceIbmIsPlacementGroupCreate(context context.Context, d *schema.Resour } func resourceIbmIsPlacementGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -233,38 +236,38 @@ func resourceIbmIsPlacementGroupRead(context context.Context, d *schema.Resource } if err = d.Set("strategy", placementGroup.Strategy); err != nil { - return diag.FromErr(fmt.Errorf("Error setting strategy: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting strategy: %s", err)) } if err = d.Set("name", placementGroup.Name); err != nil { - return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } if placementGroup.ResourceGroup != nil { if err = d.Set("resource_group", *placementGroup.ResourceGroup.ID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_group: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) } } if err = d.Set("created_at", placementGroup.CreatedAt.String()); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) } if err = d.Set("crn", placementGroup.CRN); err != nil { - return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) } if err = d.Set("href", placementGroup.Href); err != nil { - return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) } if err = d.Set("lifecycle_state", placementGroup.LifecycleState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) } if err = d.Set("resource_type", placementGroup.ResourceType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) } - tags, err := GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isUserTagType) + tags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isUserTagType) if err != nil { log.Printf( "Error getting placement group (%s) tags: %s", d.Id(), err) } - accesstags, err := GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isAccessTagType) + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *placementGroup.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error getting placement group (%s) access tags: %s", d.Id(), err) @@ -276,7 +279,7 @@ func resourceIbmIsPlacementGroupRead(context context.Context, d *schema.Resource } func resourceIbmIsPlacementGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -308,7 +311,7 @@ func resourceIbmIsPlacementGroupUpdate(context context.Context, d *schema.Resour } if d.HasChange(isPlacementGroupTags) { oldList, newList := d.GetChange(isPlacementGroupTags) - err := UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isUserTagType) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isUserTagType) if err != nil { log.Printf( "Error on update of resource subnet (%s) tags: %s", d.Id(), err) @@ -317,7 +320,7 @@ func resourceIbmIsPlacementGroupUpdate(context context.Context, d *schema.Resour if d.HasChange(isPlacementGroupAccessTags) { oldList, newList := d.GetChange(isPlacementGroupAccessTags) - err := UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isAccessTagType) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isAccessTagType) if err != nil { log.Printf( "Error on update of resource subnet (%s) access tags: %s", d.Id(), err) @@ -327,7 +330,7 @@ func resourceIbmIsPlacementGroupUpdate(context context.Context, d *schema.Resour } func resourceIbmIsPlacementGroupDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - vpcClient, err := meta.(ClientSession).VpcV1API() + vpcClient, err := meta.(conns.ClientSession).VpcV1API() if err != nil { return diag.FromErr(err) } @@ -341,10 +344,10 @@ func resourceIbmIsPlacementGroupDelete(context context.Context, d *schema.Resour if response.StatusCode == 409 { _, err = isWaitForPlacementGroupDeleteRetry(vpcClient, d, d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("Error deleting PLacementGroup: %s", err)) + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting PLacementGroup: %s", err)) } } else { - return diag.FromErr(fmt.Errorf("Error deleting PLacementGroup: %s\n%s", err, response)) + return diag.FromErr(fmt.Errorf("[ERROR] Error deleting PLacementGroup: %s\n%s", err, response)) } } _, err = isWaitForPlacementGroupDelete(vpcClient, d, d.Id()) @@ -371,12 +374,12 @@ func isWaitForPlacementGroupDelete(vpcClient *vpcv1.VpcV1, d *schema.ResourceDat if response != nil && response.StatusCode == 404 { return placementGroup, isPlacementGroupDeleteDone, nil } else if response != nil && response.StatusCode == 409 { - return placementGroup, *placementGroup.LifecycleState, fmt.Errorf("The PLacementGroup %s failed to delete: %v", id, err) + return placementGroup, *placementGroup.LifecycleState, fmt.Errorf("[ERROR] The PLacementGroup %s failed to delete: %v", id, err) } - return nil, "", fmt.Errorf("Error Getting PLacementGroup: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting PLacementGroup: %s\n%s", err, response) } if *placementGroup.LifecycleState == isPlacementGroupFailed { - return placementGroup, *placementGroup.LifecycleState, fmt.Errorf("The PLacementGroup %s failed to delete: %v", id, err) + return placementGroup, *placementGroup.LifecycleState, fmt.Errorf("[ERROR] The PLacementGroup %s failed to delete: %v", id, err) } return placementGroup, isPlacementGroupDeleting, nil }, @@ -405,7 +408,7 @@ func isWaitForPlacementGroupDeleteRetry(vpcClient *vpcv1.VpcV1, d *schema.Resour } else if response != nil && response.StatusCode == 404 { return response, isPlacementGroupDeleteDone, nil } - return response, "", fmt.Errorf("Error deleting PLacementGroup: %s\n%s", err, response) + return response, "", fmt.Errorf("[ERROR] Error deleting PLacementGroup: %s\n%s", err, response) } return response, isPlacementGroupDeleting, nil }, @@ -439,7 +442,7 @@ func isPlacementGroupRefreshFunc(vpcClient *vpcv1.VpcV1, id string, d *schema.Re } placementGroup, response, err := vpcClient.GetPlacementGroup(getinsOptions) if placementGroup == nil || err != nil { - return nil, "", fmt.Errorf("Error getting placementGroup : %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting placementGroup : %s\n%s", err, response) } d.Set("lifecycle_state", *placementGroup.LifecycleState) diff --git a/ibm/resource_ibm_is_placement_group_test.go b/ibm/service/vpc/resource_ibm_is_placement_group_test.go similarity index 89% rename from ibm/resource_ibm_is_placement_group_test.go rename to ibm/service/vpc/resource_ibm_is_placement_group_test.go index 1b96e5db3..f143e59e4 100644 --- a/ibm/resource_ibm_is_placement_group_test.go +++ b/ibm/service/vpc/resource_ibm_is_placement_group_test.go @@ -1,12 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -21,8 +24,8 @@ func TestAccIbmIsPlacementGroupBasic(t *testing.T) { name := fmt.Sprintf("tf-pg-name%d", acctest.RandIntRange(10, 100)) nameupdate := fmt.Sprintf("tf-pg-name%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsPlacementGroupDestroy, Steps: []resource.TestStep{ { @@ -54,8 +57,8 @@ func TestAccIbmIsPlacementGroupAllArgs(t *testing.T) { tagupdate1 := "prodplgrp" tagupdate2 := "devplgrp" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmIsPlacementGroupDestroy, Steps: []resource.TestStep{ { @@ -119,7 +122,7 @@ func testAccCheckIbmIsPlacementGroupExists(n string, obj vpcv1.PlacementGroup) r return fmt.Errorf("Not found: %s", n) } - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -139,7 +142,7 @@ func testAccCheckIbmIsPlacementGroupExists(n string, obj vpcv1.PlacementGroup) r } func testAccCheckIbmIsPlacementGroupDestroy(s *terraform.State) error { - vpcClient, err := testAccProvider.Meta().(ClientSession).VpcV1API() + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -158,7 +161,7 @@ func testAccCheckIbmIsPlacementGroupDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("PlacementGroup still exists: %s", rs.Primary.ID) } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for PlacementGroup (%s) has been destroyed: %s", rs.Primary.ID, err) + return fmt.Errorf("[ERROR] Error checking for PlacementGroup (%s) has been destroyed: %s", rs.Primary.ID, err) } } diff --git a/ibm/resource_ibm_is_public_gateway.go b/ibm/service/vpc/resource_ibm_is_public_gateway.go similarity index 81% rename from ibm/resource_ibm_is_public_gateway.go rename to ibm/service/vpc/resource_ibm_is_public_gateway.go index 602bffc18..c231fe89f 100644 --- a/ibm/resource_ibm_is_public_gateway.go +++ b/ibm/service/vpc/resource_ibm_is_public_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -10,6 +10,8 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -33,7 +35,7 @@ const ( isPublicGatewayResourceGroup = "resource_group" ) -func resourceIBMISPublicGateway() *schema.Resource { +func ResourceIBMISPublicGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMISPublicGatewayCreate, Read: resourceIBMISPublicGatewayRead, @@ -49,7 +51,7 @@ func resourceIBMISPublicGateway() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -58,7 +60,7 @@ func resourceIBMISPublicGateway() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_public_gateway", isPublicGatewayName), + ValidateFunc: validate.InvokeValidator("ibm_is_public_gateway", isPublicGatewayName), Description: "Name of the Public gateway instance", }, @@ -66,7 +68,7 @@ func resourceIBMISPublicGateway() *schema.Resource { Type: schema.TypeMap, Optional: true, Computed: true, - DiffSuppressFunc: applyOnce, + DiffSuppressFunc: flex.ApplyOnce, }, isPublicGatewayStatus: { @@ -101,24 +103,24 @@ func resourceIBMISPublicGateway() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_public_gateway", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_public_gateway", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "Service tags for the public gateway instance", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", @@ -129,13 +131,13 @@ func resourceIBMISPublicGateway() *schema.Resource { Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -144,30 +146,30 @@ func resourceIBMISPublicGateway() *schema.Resource { } } -func resourceIBMISPublicGatewayValidator() *ResourceValidator { +func ResourceIBMISPublicGatewayValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isPublicGatewayName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISPublicGatewayResourceValidator := ResourceValidator{ResourceName: "ibm_is_public_gateway", Schema: validateSchema} + ibmISPublicGatewayResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_public_gateway", Schema: validateSchema} return &ibmISPublicGatewayResourceValidator } @@ -214,7 +216,7 @@ func resourceIBMISPublicGatewayCreate(d *schema.ResourceData, meta interface{}) publicgw, response, err := sess.CreatePublicGateway(options) if err != nil { - return fmt.Errorf("Error while creating Public Gateway %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating Public Gateway %s\n%s", err, response) } d.SetId(*publicgw.ID) log.Printf("[INFO] PublicGateway : %s", *publicgw.ID) @@ -227,7 +229,7 @@ func resourceIBMISPublicGatewayCreate(d *schema.ResourceData, meta interface{}) v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isPublicGatewayTags); ok || v != "" { oldList, newList := d.GetChange(isPublicGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *publicgw.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *publicgw.CRN) if err != nil { log.Printf( "Error on create of vpc public gateway (%s) tags: %s", d.Id(), err) @@ -258,7 +260,7 @@ func isPublicGatewayRefreshFunc(publicgwC *vpcv1.VpcV1, id string) resource.Stat } publicgw, response, err := publicgwC.GetPublicGateway(getPublicGatewayOptions) if err != nil { - return nil, "", fmt.Errorf("Error getting Public Gateway : %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting Public Gateway : %s\n%s", err, response) } if *publicgw.Status == isPublicGatewayProvisioningDone { @@ -284,7 +286,7 @@ func resourceIBMISPublicGatewayRead(d *schema.ResourceData, meta interface{}) er d.SetId("") return nil } - return fmt.Errorf("Error getting Public Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Public Gateway : %s\n%s", err, response) } d.Set(isPublicGatewayName, *publicgw.Name) if publicgw.FloatingIP != nil { @@ -298,24 +300,24 @@ func resourceIBMISPublicGatewayRead(d *schema.ResourceData, meta interface{}) er d.Set(isPublicGatewayStatus, *publicgw.Status) d.Set(isPublicGatewayZone, *publicgw.Zone.Name) d.Set(isPublicGatewayVPC, *publicgw.VPC.ID) - tags, err := GetTagsUsingCRN(meta, *publicgw.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *publicgw.CRN) if err != nil { log.Printf( "Error on get of vpc public gateway (%s) tags: %s", id, err) } d.Set(isPublicGatewayTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/publicGateways") - d.Set(ResourceName, *publicgw.Name) - d.Set(ResourceCRN, *publicgw.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/publicGateways") + d.Set(flex.ResourceName, *publicgw.Name) + d.Set(flex.ResourceCRN, *publicgw.CRN) d.Set(isPublicGatewayCRN, *publicgw.CRN) - d.Set(ResourceStatus, *publicgw.Status) + d.Set(flex.ResourceStatus, *publicgw.Status) if publicgw.ResourceGroup != nil { d.Set(isPublicGatewayResourceGroup, *publicgw.ResourceGroup.ID) - d.Set(ResourceGroupName, *publicgw.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *publicgw.ResourceGroup.Name) } return nil } @@ -340,10 +342,10 @@ func resourceIBMISPublicGatewayUpdate(d *schema.ResourceData, meta interface{}) } publicgw, response, err := sess.GetPublicGateway(getPublicGatewayOptions) if err != nil { - return fmt.Errorf("Error getting Public Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Public Gateway : %s\n%s", err, response) } oldList, newList := d.GetChange(isPublicGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *publicgw.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *publicgw.CRN) if err != nil { log.Printf( "Error on update of resource Public Gateway (%s) tags: %s", id, err) @@ -358,12 +360,12 @@ func resourceIBMISPublicGatewayUpdate(d *schema.ResourceData, meta interface{}) } PublicGatewayPatch, err := PublicGatewayPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for PublicGatewayPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for PublicGatewayPatch: %s", err) } updatePublicGatewayOptions.PublicGatewayPatch = PublicGatewayPatch _, response, err := sess.UpdatePublicGateway(updatePublicGatewayOptions) if err != nil { - return fmt.Errorf("Error Updating Public Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Public Gateway : %s\n%s", err, response) } } return resourceIBMISPublicGatewayRead(d, meta) @@ -385,7 +387,7 @@ func resourceIBMISPublicGatewayDelete(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error Getting Public Gateway (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Public Gateway (%s): %s\n%s", id, err, response) } deletePublicGatewayOptions := &vpcv1.DeletePublicGatewayOptions{ @@ -393,7 +395,7 @@ func resourceIBMISPublicGatewayDelete(d *schema.ResourceData, meta interface{}) } response, err = sess.DeletePublicGateway(deletePublicGatewayOptions) if err != nil { - return fmt.Errorf("Error Deleting Public Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Public Gateway : %s\n%s", err, response) } _, err = isWaitForPublicGatewayDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -420,7 +422,7 @@ func isWaitForPublicGatewayDeleted(pg *vpcv1.VpcV1, id string, timeout time.Dura func isPublicGatewayDeleteRefreshFunc(pg *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] is pubic gateway delete function here") getPublicGatewayOptions := &vpcv1.GetPublicGatewayOptions{ ID: &id, } @@ -429,7 +431,7 @@ func isPublicGatewayDeleteRefreshFunc(pg *vpcv1.VpcV1, id string) resource.State if response != nil && response.StatusCode == 404 { return pgw, isPublicGatewayDeleted, nil } - return nil, "", fmt.Errorf("The Public Gateway %s failed to delete: %s\n%s", id, err, response) + return nil, "", fmt.Errorf("[ERROR] The Public Gateway %s failed to delete: %s\n%s", id, err, response) } return pgw, isPublicGatewayDeleting, nil } @@ -449,7 +451,7 @@ func resourceIBMISPublicGatewayExists(d *schema.ResourceData, meta interface{}) if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Public Gateway: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Public Gateway: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_public_gateway_test.go b/ibm/service/vpc/resource_ibm_is_public_gateway_test.go similarity index 89% rename from ibm/resource_ibm_is_public_gateway_test.go rename to ibm/service/vpc/resource_ibm_is_public_gateway_test.go index 6c5b238e0..299caf72b 100644 --- a/ibm/resource_ibm_is_public_gateway_test.go +++ b/ibm/service/vpc/resource_ibm_is_public_gateway_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -23,8 +26,8 @@ func TestAccIBMISPublicGateway_basic(t *testing.T) { zone := "us-south-1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISPublicGatewayDestroy, Steps: []resource.TestStep{ { @@ -55,7 +58,7 @@ func TestAccIBMISPublicGateway_basic(t *testing.T) { } func testAccCheckIBMISPublicGatewayDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_public_gateway" { continue @@ -86,7 +89,7 @@ func testAccCheckIBMISPublicGatewayExists(n, publicgw string) resource.TestCheck return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getpgwoptions := &vpcv1.GetPublicGatewayOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/service/vpc/resource_ibm_is_security_group.go b/ibm/service/vpc/resource_ibm_is_security_group.go new file mode 100644 index 000000000..58466e5af --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_security_group.go @@ -0,0 +1,601 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isSecurityGroupName = "name" + isSecurityGroupVPC = "vpc" + isSecurityGroupRules = "rules" + isSecurityGroupResourceGroup = "resource_group" + isSecurityGroupTags = "tags" + isSecurityGroupCRN = "crn" +) + +func ResourceIBMISSecurityGroup() *schema.Resource { + + return &schema.Resource{ + Create: resourceIBMISSecurityGroupCreate, + Read: resourceIBMISSecurityGroupRead, + Update: resourceIBMISSecurityGroupUpdate, + Delete: resourceIBMISSecurityGroupDelete, + Exists: resourceIBMISSecurityGroupExists, + Importer: &schema.ResourceImporter{}, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isSecurityGroupName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Security group name", + ValidateFunc: validate.InvokeValidator("ibm_is_security_group", isSecurityGroupName), + }, + isSecurityGroupVPC: { + Type: schema.TypeString, + Required: true, + Description: "Security group's resource group id", + ForceNew: true, + }, + + isSecurityGroupTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_security_group", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags", + }, + + isSecurityGroupCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + isSecurityGroupRules: { + Type: schema.TypeList, + Computed: true, + Description: "Security Rules", + Elem: &schema.Resource{ + Schema: makeIBMISSecurityRuleSchema(), + }, + }, + + isSecurityGroupResourceGroup: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Resource Group ID", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func ResourceIBMISSecurityGroupValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSecurityGroupName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISSecurityGroupResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_security_group", Schema: validateSchema} + return &ibmISSecurityGroupResourceValidator +} + +func resourceIBMISSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + vpc := d.Get(isSecurityGroupVPC).(string) + + createSecurityGroupOptions := &vpcv1.CreateSecurityGroupOptions{ + VPC: &vpcv1.VPCIdentity{ + ID: &vpc, + }, + } + var rg, name string + if grp, ok := d.GetOk(isSecurityGroupResourceGroup); ok { + rg = grp.(string) + createSecurityGroupOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + if nm, ok := d.GetOk(isSecurityGroupName); ok { + name = nm.(string) + createSecurityGroupOptions.Name = &name + } + sg, response, err := sess.CreateSecurityGroup(createSecurityGroupOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating Security Group %s\n%s", err, response) + } + d.SetId(*sg.ID) + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isSecurityGroupTags); ok || v != "" { + oldList, newList := d.GetChange(isSecurityGroupTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *sg.CRN) + if err != nil { + log.Printf( + "Error while creating Security Group tags : %s\n%s", *sg.ID, err) + } + } + return resourceIBMISSecurityGroupRead(d, meta) +} + +func resourceIBMISSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + id := d.Id() + + getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ + ID: &id, + } + group, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Security Group : %s\n%s", err, response) + } + tags, err := flex.GetTagsUsingCRN(meta, *group.CRN) + if err != nil { + log.Printf( + "Error getting Security Group tags : %s\n%s", d.Id(), err) + } + d.Set(isSecurityGroupTags, tags) + d.Set(isSecurityGroupCRN, *group.CRN) + d.Set(isSecurityGroupName, *group.Name) + d.Set(isSecurityGroupVPC, *group.VPC.ID) + rules := make([]map[string]interface{}, 0) + if len(group.Rules) > 0 { + for _, rule := range group.Rules { + switch reflect.TypeOf(rule).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + r := make(map[string]interface{}) + if rule.Code != nil { + r[isSecurityGroupRuleCode] = int(*rule.Code) + } + if rule.Type != nil { + r[isSecurityGroupRuleType] = int(*rule.Type) + } + r[isSecurityGroupRuleDirection] = *rule.Direction + r[isSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.Protocol != nil { + r[isSecurityGroupRuleProtocol] = *rule.Protocol + } + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + r := make(map[string]interface{}) + r[isSecurityGroupRuleDirection] = *rule.Direction + r[isSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.Protocol != nil { + r[isSecurityGroupRuleProtocol] = *rule.Protocol + } + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + rule := rule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + r := make(map[string]interface{}) + if rule.PortMin != nil { + r[isSecurityGroupRulePortMin] = int(*rule.PortMin) + } + if rule.PortMax != nil { + r[isSecurityGroupRulePortMax] = int(*rule.PortMax) + } + r[isSecurityGroupRuleDirection] = *rule.Direction + r[isSecurityGroupRuleIPVersion] = *rule.IPVersion + if rule.Protocol != nil { + r[isSecurityGroupRuleProtocol] = *rule.Protocol + } + remote, ok := rule.Remote.(*vpcv1.SecurityGroupRuleRemote) + if ok { + if remote != nil && reflect.ValueOf(remote).IsNil() == false { + if remote.ID != nil { + r[isSecurityGroupRuleRemote] = remote.ID + } else if remote.Address != nil { + r[isSecurityGroupRuleRemote] = remote.Address + } else if remote.CIDRBlock != nil { + r[isSecurityGroupRuleRemote] = remote.CIDRBlock + } + } + } + rules = append(rules, r) + } + } + } + } + d.Set(isSecurityGroupRules, rules) + d.SetId(*group.ID) + if group.ResourceGroup != nil { + d.Set(isSecurityGroupResourceGroup, group.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, group.ResourceGroup.Name) + } + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/securityGroups") + d.Set(flex.ResourceName, *group.Name) + d.Set(flex.ResourceCRN, *group.CRN) + return nil +} + +func resourceIBMISSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + id := d.Id() + name := "" + hasChanged := false + + if d.HasChange(isSecurityGroupTags) { + oldList, newList := d.GetChange(isSecurityGroupTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, d.Get(isSecurityGroupCRN).(string)) + if err != nil { + log.Printf( + "Error Updating Security Group tags: %s\n%s", d.Id(), err) + } + } + + if d.HasChange(isSecurityGroupName) { + name = d.Get(isSecurityGroupName).(string) + hasChanged = true + } else { + return resourceIBMISSecurityGroupRead(d, meta) + } + + if hasChanged { + updateSecurityGroupOptions := &vpcv1.UpdateSecurityGroupOptions{ + ID: &id, + } + securityGroupPatchModel := &vpcv1.SecurityGroupPatch{ + Name: &name, + } + securityGroupPatch, err := securityGroupPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for SecurityGroupPatch: %s", err) + } + updateSecurityGroupOptions.SecurityGroupPatch = securityGroupPatch + _, response, err := sess.UpdateSecurityGroup(updateSecurityGroupOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating Security Group : %s\n%s", err, response) + } + } + return resourceIBMISSecurityGroupRead(d, meta) +} + +func resourceIBMISSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + id := d.Id() + + getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ + ID: &id, + } + _, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Security Group (%s): %s\n%s", id, err, response) + } + + start := "" + allrecs := []vpcv1.SecurityGroupTargetReferenceIntf{} + + for { + listSecurityGroupTargetsOptions := sess.NewListSecurityGroupTargetsOptions(id) + + groups, response, err := sess.ListSecurityGroupTargets(listSecurityGroupTargetsOptions) + if err != nil || groups == nil { + return fmt.Errorf("[ERROR] Error Getting Security Group Targets %s\n%s", err, response) + } + if *groups.TotalCount == int64(0) { + break + } + + start = flex.GetNext(groups.Next) + allrecs = append(allrecs, groups.Targets...) + + if start == "" { + break + } + + } + + for _, securityGroupTargetReferenceIntf := range allrecs { + if securityGroupTargetReferenceIntf != nil { + securityGroupTargetReference := securityGroupTargetReferenceIntf.(*vpcv1.SecurityGroupTargetReference) + if securityGroupTargetReference != nil && securityGroupTargetReference.ID != nil { + + deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(id, *securityGroupTargetReference.ID) + response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) + if err != nil { + if response != nil { + if response.StatusCode == 404 { + log.Printf("[DEBUG] Security group target(%s) binding is already deleted", *securityGroupTargetReference.ID) + } else if response.StatusCode == 409 { + log.Printf("[DEBUG] Security group target(%s) binding is in deleting status, waiting till target is removed", *securityGroupTargetReference.ID) + _, err = isWaitForTargetDeleted(sess, id, *securityGroupTargetReference.ID, securityGroupTargetReferenceIntf, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + } + } else { + return fmt.Errorf("[ERROR] Error deleting security group target binding while deleting security group : %s\n%s", err, response) + } + } + + } + } + } + + deleteSecurityGroupOptions := &vpcv1.DeleteSecurityGroupOptions{ + ID: &id, + } + response, err = sess.DeleteSecurityGroup(deleteSecurityGroupOptions) + + if err != nil { + if response != nil { + if response.StatusCode == 404 { + log.Printf("[DEBUG] Security group(%s) target bindings are already deleted", id) + } else if response.StatusCode == 409 { + log.Printf("[DEBUG] Security group(%s) has target bindings is in deleting, will wait till target is removed", id) + _, err = isWaitForSgCleanup(sess, id, allrecs, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + } + } else { + return fmt.Errorf("[ERROR] Error Deleting Security Group : %s\n%s", err, response) + } + } + d.SetId("") + return nil +} + +func resourceIBMISSecurityGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + id := d.Id() + + getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ + ID: &id, + } + _, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Security Group: %s\n%s", err, response) + } + return true, nil +} + +func makeIBMISSecurityRuleSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + + isSecurityGroupRuleDirection: { + Type: schema.TypeString, + Computed: true, + Description: "Direction of traffic to enforce, either inbound or outbound", + }, + + isSecurityGroupRuleIPVersion: { + Type: schema.TypeString, + Computed: true, + Description: "IP version: ipv4", + }, + + isSecurityGroupRuleRemote: { + Type: schema.TypeString, + Computed: true, + Description: "Security group id: an IP address, a CIDR block, or a single security group identifier", + }, + + isSecurityGroupRuleType: { + Type: schema.TypeInt, + Computed: true, + }, + + isSecurityGroupRuleCode: { + Type: schema.TypeInt, + Computed: true, + }, + + isSecurityGroupRulePortMin: { + Type: schema.TypeInt, + Computed: true, + }, + + isSecurityGroupRulePortMax: { + Type: schema.TypeInt, + Computed: true, + }, + + isSecurityGroupRuleProtocol: { + Type: schema.TypeString, + Computed: true, + }, + } +} + +func isWaitForTargetDeleted(client *vpcv1.VpcV1, sgId, targetId string, target vpcv1.SecurityGroupTargetReferenceIntf, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Security group(%s) target(%s) to be deleted.", sgId, targetId) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{"done", ""}, + Refresh: isTargetRefreshFunc(client, sgId, targetId, target), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isTargetRefreshFunc(client *vpcv1.VpcV1, sgId, targetId string, target vpcv1.SecurityGroupTargetReferenceIntf) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + targetgetoptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &sgId, + ID: &targetId, + } + sgTarget, response, err := client.GetSecurityGroupTarget(targetgetoptions) + if err != nil { + return target, "", fmt.Errorf("[ERROR] Error getting target(%s): %s\n%s", targetId, err, response) + } + if response != nil && response.StatusCode == 404 { + return target, "done", nil + } + return sgTarget, "deleting", nil + } +} +func isWaitForSgCleanup(client *vpcv1.VpcV1, sgId string, targets []vpcv1.SecurityGroupTargetReferenceIntf, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Security group(%s) target(%s) to be deleted.", sgId, targets) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{"done", ""}, + Refresh: isSgRefreshFunc(client, sgId, targets), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSgRefreshFunc(client *vpcv1.VpcV1, sgId string, groups []vpcv1.SecurityGroupTargetReferenceIntf) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + start := "" + allrecs := []vpcv1.SecurityGroupTargetReferenceIntf{} + for { + listSecurityGroupTargetsOptions := client.NewListSecurityGroupTargetsOptions(sgId) + + sggroups, response, err := client.ListSecurityGroupTargets(listSecurityGroupTargetsOptions) + if err != nil || sggroups == nil { + return groups, "", fmt.Errorf("[ERROR] Error Getting Security Group Targets %s\n%s", err, response) + } + if *sggroups.TotalCount == int64(0) { + return groups, "done", nil + } + + start = flex.GetNext(sggroups.Next) + allrecs = append(allrecs, sggroups.Targets...) + + if start == "" { + break + } + } + return allrecs, "deleting", nil + } +} diff --git a/ibm/resource_ibm_is_security_group_network_interface_attachment.go b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go similarity index 87% rename from ibm/resource_ibm_is_security_group_network_interface_attachment.go rename to ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go index a5025d36a..3089ef35d 100644 --- a/ibm/resource_ibm_is_security_group_network_interface_attachment.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go @@ -1,12 +1,13 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -32,7 +33,7 @@ const ( isSGNICAFloatingIpCRN = "crn" ) -func resourceIBMISSecurityGroupNetworkInterfaceAttachment() *schema.Resource { +func ResourceIBMISSecurityGroupNetworkInterfaceAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMISSecurityGroupNetworkInterfaceAttachmentCreate, Read: resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead, @@ -144,7 +145,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachment() *schema.Resource { }, }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the Security Group", @@ -167,7 +168,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentCreate(d *schema.Resour } _, response, err := sess.CreateSecurityGroupTargetBinding(options) if err != nil { - return fmt.Errorf("Error while creating SecurityGroup NetworkInterface Binding %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating SecurityGroup NetworkInterface Binding %s\n%s", err, response) } d.SetId(fmt.Sprintf("%s/%s", sgID, nicID)) return resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d, meta) @@ -179,7 +180,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d *schema.Resource if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -196,7 +197,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d *schema.Resource d.SetId("") return nil } - return fmt.Errorf("Error getting target(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) + return fmt.Errorf("[ERROR] Error getting target(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) } instance_id := strings.Split(*secGroupTarget.(*vpcv1.SecurityGroupTargetReference).Href, "/")[5] net_interf_id := *secGroupTarget.(*vpcv1.SecurityGroupTargetReference).ID @@ -206,14 +207,16 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d *schema.Resource } instanceNic, response, err := sess.GetInstanceNetworkInterface(getnicoptions) if err != nil { - return fmt.Errorf("Error getting network interfaces attached to the instance %s %s\n%s", instance_id, err, response) + return fmt.Errorf("[ERROR] Error getting network interfaces attached to the instance %s %s\n%s", instance_id, err, response) } d.Set(isSGNICAGroupId, sgID) d.Set(isSGNICANicId, nicID) d.Set(isSGNICAInstanceNwInterfaceID, *instanceNic.ID) d.Set(isSGNICAName, *instanceNic.Name) d.Set(isSGNICAPortSpeed, *instanceNic.PortSpeed) - d.Set(isSGNICAPrimaryIPV4Address, *instanceNic.PrimaryIpv4Address) + if instanceNic.PrimaryIP != nil && instanceNic.PrimaryIP.Address != nil { + d.Set(isSGNICAPrimaryIPV4Address, *instanceNic.PrimaryIP.Address) + } d.Set(isSGNICAStatus, *instanceNic.Status) d.Set(isSGNICAType, *instanceNic.Type) if instanceNic.Subnet != nil { @@ -245,9 +248,9 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d *schema.Resource } sg, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) if err != nil { - return fmt.Errorf("Error Getting Security Group : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Security Group : %s\n%s", err, response) } - d.Set(RelatedCRN, *sg.CRN) + d.Set(flex.RelatedCRN, *sg.CRN) return nil } @@ -256,7 +259,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentDelete(d *schema.Resour if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -274,7 +277,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentDelete(d *schema.Resour d.SetId("") return nil } - return fmt.Errorf("Error getting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) + return fmt.Errorf("[ERROR] Error getting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) } removeSecurityGroupNetworkInterfaceOptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ @@ -283,7 +286,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentDelete(d *schema.Resour } response, err = sess.DeleteSecurityGroupTargetBinding(removeSecurityGroupNetworkInterfaceOptions) if err != nil { - return fmt.Errorf("Error Deleting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) + return fmt.Errorf("[ERROR] Error Deleting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) } d.SetId("") return nil @@ -294,12 +297,12 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentExists(d *schema.Resour if err != nil { return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of sgID/nicID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of sgID/nicID", d.Id()) } sgID := parts[0] nicID := parts[1] @@ -312,7 +315,7 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentExists(d *schema.Resour if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) + return false, fmt.Errorf("[ERROR] Error getting NetworkInterface(%s) for the SecurityGroup (%s) : %s\n%s", nicID, sgID, err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_security_group_network_interface_attachment_test.go b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go similarity index 84% rename from ibm/resource_ibm_is_security_group_network_interface_attachment_test.go rename to ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go index 358083694..e7edc3734 100644 --- a/ibm/resource_ibm_is_security_group_network_interface_attachment_test.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" @@ -9,6 +9,10 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -27,8 +31,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE sshname := fmt.Sprintf("tfssh-name-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSecurityGroupNwInterfaceAttachmentDestroy, Steps: []resource.TestStep{ { @@ -44,24 +48,24 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE } func testAccCheckIBMISSecurityGroupNwInterfaceAttachmentDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_security_group_network_interface_attachment" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } sgID := parts[0] nicID := parts[1] - getsgnicptions := &vpcv1.GetSecurityGroupNetworkInterfaceOptions{ + getsgnicptions := &vpcv1.GetSecurityGroupTargetOptions{ SecurityGroupID: &sgID, ID: &nicID, } - _, _, err1 := sess.GetSecurityGroupNetworkInterface(getsgnicptions) + _, _, err1 := sess.GetSecurityGroupTarget(getsgnicptions) if err1 == nil { return fmt.Errorf("network interface still exists: %s", rs.Primary.ID) } @@ -81,7 +85,7 @@ func testAccCheckIBMISSecurityGroupNwInterfaceAttachmentExists(n, instance strin if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -89,7 +93,7 @@ func testAccCheckIBMISSecurityGroupNwInterfaceAttachmentExists(n, instance strin sgID := parts[0] nicID := parts[1] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getsgnicptions := &vpcv1.GetSecurityGroupTargetOptions{ SecurityGroupID: &sgID, ID: &nicID, @@ -144,5 +148,5 @@ func testAccCheckIBMISSecurityGroupNwInterfaceAttachmentConfig(vpcname, subnetna resource "ibm_is_security_group_network_interface_attachment" "sgnic" { security_group = ibm_is_security_group.testacc_security_group.id network_interface = ibm_is_instance.testacc_instance.primary_network_interface[0].id - }`, vpcname, subnetname, ISZoneName, ISCIDR, sshname, publicKey, name, isImage, instanceProfileName, ISZoneName, sgName) + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sgName) } diff --git a/ibm/resource_ibm_is_security_group_rule.go b/ibm/service/vpc/resource_ibm_is_security_group_rule.go similarity index 83% rename from ibm/resource_ibm_is_security_group_rule.go rename to ibm/service/vpc/resource_ibm_is_security_group_rule.go index fd7fa31a1..2bcda4eff 100644 --- a/ibm/resource_ibm_is_security_group_rule.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_rule.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "reflect" "strings" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -29,7 +32,7 @@ const ( isSecurityGroupRuleID = "rule_id" ) -func resourceIBMISSecurityGroupRule() *schema.Resource { +func ResourceIBMISSecurityGroupRule() *schema.Resource { return &schema.Resource{ Create: resourceIBMISSecurityGroupRuleCreate, @@ -58,7 +61,7 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { Type: schema.TypeString, Required: true, Description: "Direction of traffic to enforce, either inbound or outbound", - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleDirection), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleDirection), }, isSecurityGroupRuleIPVersion: { @@ -66,7 +69,7 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { Optional: true, Description: "IP version: ipv4", Default: isSecurityGroupRuleIPVersionDefault, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleIPVersion), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleIPVersion), }, isSecurityGroupRuleRemote: { @@ -90,13 +93,13 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { Type: schema.TypeInt, Optional: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleType), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleType), }, isSecurityGroupRuleCode: { Type: schema.TypeInt, Optional: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleCode), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRuleCode), }, }, }, @@ -117,14 +120,14 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { Optional: true, ForceNew: false, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMin), }, isSecurityGroupRulePortMax: { Type: schema.TypeInt, Optional: true, ForceNew: false, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMax), }, }, }, @@ -145,20 +148,20 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { Optional: true, ForceNew: false, Default: 1, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMin), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMin), }, isSecurityGroupRulePortMax: { Type: schema.TypeInt, Optional: true, ForceNew: false, Default: 65535, - ValidateFunc: InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMax), + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_rule", isSecurityGroupRulePortMax), }, }, }, }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the Security Group", @@ -172,55 +175,55 @@ func resourceIBMISSecurityGroupRule() *schema.Resource { } } -func resourceIBMISSecurityGroupRuleValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMISSecurityGroupRuleValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) direction := "inbound, outbound" ip_version := "ipv4" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRuleDirection, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: direction}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRuleIPVersion, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: true, AllowedValues: ip_version}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRuleType, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "254"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRuleCode, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "0", MaxValue: "255"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRulePortMin, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSecurityGroupRulePortMax, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "65535"}) - ibmISSecurityGroupRuleResourceValidator := ResourceValidator{ResourceName: "ibm_is_security_group_rule", Schema: validateSchema} + ibmISSecurityGroupRuleResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_security_group_rule", Schema: validateSchema} return &ibmISSecurityGroupRuleResourceValidator } @@ -235,8 +238,8 @@ func resourceIBMISSecurityGroupRuleCreate(d *schema.ResourceData, meta interface return err } isSecurityGroupRuleKey := "security_group_rule_key_" + parsed.secgrpID - ibmMutexKV.Lock(isSecurityGroupRuleKey) - defer ibmMutexKV.Unlock(isSecurityGroupRuleKey) + conns.IbmMutexKV.Lock(isSecurityGroupRuleKey) + defer conns.IbmMutexKV.Unlock(isSecurityGroupRuleKey) options := &vpcv1.CreateSecurityGroupRuleOptions{ SecurityGroupID: &parsed.secgrpID, @@ -245,7 +248,7 @@ func resourceIBMISSecurityGroupRuleCreate(d *schema.ResourceData, meta interface rule, response, err := sess.CreateSecurityGroupRule(options) if err != nil { - return fmt.Errorf("Error while creating Security Group Rule %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating Security Group Rule %s\n%s", err, response) } switch reflect.TypeOf(rule).String() { case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": @@ -293,7 +296,7 @@ func resourceIBMISSecurityGroupRuleRead(d *schema.ResourceData, meta interface{} d.SetId("") return nil } - return fmt.Errorf("Error Getting Security Group Rule (%s): %s\n%s", ruleID, err, response) + return fmt.Errorf("[ERROR] Error Getting Security Group Rule (%s): %s\n%s", ruleID, err, response) } d.Set(isSecurityGroupID, secgrpID) getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ @@ -301,9 +304,9 @@ func resourceIBMISSecurityGroupRuleRead(d *schema.ResourceData, meta interface{} } sg, response, err := sess.GetSecurityGroup(getSecurityGroupOptions) if err != nil { - return fmt.Errorf("Error Getting Security Group : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting Security Group : %s\n%s", err, response) } - d.Set(RelatedCRN, *sg.CRN) + d.Set(flex.RelatedCRN, *sg.CRN) switch reflect.TypeOf(sgrule).String() { case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": { @@ -412,13 +415,13 @@ func resourceIBMISSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface return err } isSecurityGroupRuleKey := "security_group_rule_key_" + parsed.secgrpID - ibmMutexKV.Lock(isSecurityGroupRuleKey) - defer ibmMutexKV.Unlock(isSecurityGroupRuleKey) + conns.IbmMutexKV.Lock(isSecurityGroupRuleKey) + defer conns.IbmMutexKV.Unlock(isSecurityGroupRuleKey) updateSecurityGroupRuleOptions := sgTemplate _, response, err := sess.UpdateSecurityGroupRule(updateSecurityGroupRuleOptions) if err != nil { - return fmt.Errorf("Error Updating Security Group Rule : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Security Group Rule : %s\n%s", err, response) } return resourceIBMISSecurityGroupRuleRead(d, meta) } @@ -434,8 +437,8 @@ func resourceIBMISSecurityGroupRuleDelete(d *schema.ResourceData, meta interface } isSecurityGroupRuleKey := "security_group_rule_key_" + secgrpID - ibmMutexKV.Lock(isSecurityGroupRuleKey) - defer ibmMutexKV.Unlock(isSecurityGroupRuleKey) + conns.IbmMutexKV.Lock(isSecurityGroupRuleKey) + defer conns.IbmMutexKV.Unlock(isSecurityGroupRuleKey) getSecurityGroupRuleOptions := &vpcv1.GetSecurityGroupRuleOptions{ SecurityGroupID: &secgrpID, @@ -448,7 +451,7 @@ func resourceIBMISSecurityGroupRuleDelete(d *schema.ResourceData, meta interface d.SetId("") return nil } - return fmt.Errorf("Error Getting Security Group Rule (%s): %s\n%s", ruleID, err, response) + return fmt.Errorf("[ERROR] Error Getting Security Group Rule (%s): %s\n%s", ruleID, err, response) } deleteSecurityGroupRuleOptions := &vpcv1.DeleteSecurityGroupRuleOptions{ @@ -456,8 +459,8 @@ func resourceIBMISSecurityGroupRuleDelete(d *schema.ResourceData, meta interface ID: &ruleID, } response, err = sess.DeleteSecurityGroupRule(deleteSecurityGroupRuleOptions) - if err != nil { - return fmt.Errorf("Error Deleting Security Group Rule : %s\n%s", err, response) + if err != nil && response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error Deleting Security Group Rule : %s\n%s", err, response) } d.SetId("") return nil @@ -482,7 +485,7 @@ func resourceIBMISSecurityGroupRuleExists(d *schema.ResourceData, meta interface if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Security Group Rule (%s): %s\n%s", ruleID, err, response) + return false, fmt.Errorf("[ERROR] Error getting Security Group Rule (%s): %s\n%s", ruleID, err, response) } return true, nil } @@ -519,10 +522,10 @@ type parsedIBMISSecurityGroupRuleDictionary struct { } func inferRemoteSecurityGroup(s string) (address, cidr, id string, err error) { - if isSecurityGroupAddress(s) { + if validate.IsSecurityGroupAddress(s) { address = s return - } else if isSecurityGroupCIDR(s) { + } else if validate.IsSecurityGroupCIDR(s) { cidr = s return } else { @@ -586,6 +589,18 @@ func parseIBMISSecurityGroupRuleDictionary(d *schema.ResourceData, tag string, s } else if parsed.remoteSecGrpID != "" { remoteTemplate.ID = &parsed.remoteSecGrpID remoteTemplateUpdate.ID = &parsed.remoteSecGrpID + + // check if remote is actually a SG identifier + getSecurityGroupOptions := &vpcv1.GetSecurityGroupOptions{ + ID: &parsed.remoteSecGrpID, + } + sg, res, err := sess.GetSecurityGroup(getSecurityGroupOptions) + if err != nil || sg == nil { + if res != nil && res.StatusCode == 404 { + return nil, nil, nil, err + } + return nil, nil, nil, fmt.Errorf("Error getting Security Group in remote (%s): %s\n%s", parsed.remoteSecGrpID, err, res) + } } sgTemplate.Remote = remoteTemplate securityGroupRulePatchModel.Remote = remoteTemplateUpdate @@ -662,7 +677,7 @@ func parseIBMISSecurityGroupRuleDictionary(d *schema.ResourceData, tag string, s } securityGroupRulePatch, err := securityGroupRulePatchModel.AsPatch() if err != nil { - return nil, nil, nil, fmt.Errorf("Error calling asPatch for SecurityGroupRulePatch: %s", err) + return nil, nil, nil, fmt.Errorf("[ERROR] Error calling asPatch for SecurityGroupRulePatch: %s", err) } sgTemplateUpdate.SecurityGroupRulePatch = securityGroupRulePatch // log.Printf("[DEBUG] parse tag=%s\n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v \n\t%v ", diff --git a/ibm/resource_ibm_is_security_group_rule_test.go b/ibm/service/vpc/resource_ibm_is_security_group_rule_test.go similarity index 87% rename from ibm/resource_ibm_is_security_group_rule_test.go rename to ibm/service/vpc/resource_ibm_is_security_group_rule_test.go index 6adfc749f..4f61b1fd1 100644 --- a/ibm/resource_ibm_is_security_group_rule_test.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_rule_test.go @@ -1,14 +1,18 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "reflect" + "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -23,8 +27,8 @@ func TestAccIBMISSecurityGroupRule_basic(t *testing.T) { //name2 := fmt.Sprintf("tfsgrule-updatename-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSecurityGroupRuleDestroy, Steps: []resource.TestStep{ { @@ -38,9 +42,18 @@ func TestAccIBMISSecurityGroupRule_basic(t *testing.T) { }, }) } - +func parseISTerraformID(s string) (string, string, error) { + segments := strings.Split(s, ".") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments)", s) + } + return segments[0], segments[1], nil +} func testAccCheckIBMISSecurityGroupRuleDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_security_group_rule" { continue @@ -78,7 +91,7 @@ func testAccCheckIBMISSecurityGroupRuleExists(n, securityGroupRuleID string) res if err != nil { return err } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getsgruleoptions := &vpcv1.GetSecurityGroupRuleOptions{ SecurityGroupID: &secgrpID, ID: &ruleID, diff --git a/ibm/service/vpc/resource_ibm_is_security_group_target.go b/ibm/service/vpc/resource_ibm_is_security_group_target.go new file mode 100644 index 000000000..2c06ce506 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_security_group_target.go @@ -0,0 +1,327 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isSecurityGroupTargetID = "target" + isSecurityGroupResourceType = "resource_type" +) + +func ResourceIBMISSecurityGroupTarget() *schema.Resource { + + return &schema.Resource{ + Create: resourceIBMISSecurityGroupTargetCreate, + Read: resourceIBMISSecurityGroupTargetRead, + Delete: resourceIBMISSecurityGroupTargetDelete, + Exists: resourceIBMISSecurityGroupTargetExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + "security_group": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Security group id", + }, + + isSecurityGroupTargetID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "security group target identifier", + ValidateFunc: validate.InvokeValidator("ibm_is_security_group_target", isSecurityGroupTargetID), + }, + + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Security group target name", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this Security group target", + }, + + isSecurityGroupResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Resource Type", + }, + }, + } +} + +func ResourceIBMISSecurityGroupTargetValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSecurityGroupTargetID, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64}, + validate.ValidateSchema{ + Identifier: "security_group", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64}) + + ibmISSecurityGroupResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_security_group_target", Schema: validateSchema} + return &ibmISSecurityGroupResourceValidator +} + +func resourceIBMISSecurityGroupTargetCreate(d *schema.ResourceData, meta interface{}) error { + + sess, err := vpcClient(meta) + if err != nil { + return err + } + + securityGroupID := d.Get("security_group").(string) + targetID := d.Get(isSecurityGroupTargetID).(string) + + createSecurityGroupTargetBindingOptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{} + createSecurityGroupTargetBindingOptions.SecurityGroupID = &securityGroupID + createSecurityGroupTargetBindingOptions.ID = &targetID + + sg, response, err := sess.CreateSecurityGroupTargetBinding(createSecurityGroupTargetBindingOptions) + if err != nil || sg == nil { + return fmt.Errorf("[ERROR] Error while creating Security Group Target Binding %s\n%s", err, response) + } + sgtarget := sg.(*vpcv1.SecurityGroupTargetReference) + d.SetId(fmt.Sprintf("%s/%s", securityGroupID, *sgtarget.ID)) + crn := sgtarget.CRN + if crn != nil && *crn != "" && strings.Contains(*crn, "load-balancer") { + lbid := sgtarget.ID + _, errsgt := isWaitForLbSgTargetCreateAvailable(sess, *lbid, d.Timeout(schema.TimeoutCreate)) + if errsgt != nil { + return errsgt + } + } + + return resourceIBMISSecurityGroupTargetRead(d, meta) +} + +func resourceIBMISSecurityGroupTargetRead(d *schema.ResourceData, meta interface{}) error { + + sess, err := vpcClient(meta) + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + securityGroupID := parts[0] + securityGroupTargetID := parts[1] + + d.Set("security_group", securityGroupID) + d.Set(isSecurityGroupTargetID, securityGroupTargetID) + + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupID, + ID: &securityGroupTargetID, + } + + data, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil || data == nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) + } + + target := data.(*vpcv1.SecurityGroupTargetReference) + d.Set("name", *target.Name) + d.Set("crn", target.CRN) + if target.ResourceType != nil && *target.ResourceType != "" { + d.Set(isSecurityGroupResourceType, *target.ResourceType) + } + + return nil +} + +func resourceIBMISSecurityGroupTargetDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + securityGroupID := parts[0] + securityGroupTargetID := parts[1] + + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupID, + ID: &securityGroupTargetID, + } + sgt, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Security Group Targets (%s): %s\n%s", securityGroupID, err, response) + } + + deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(securityGroupID, securityGroupTargetID) + response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Security Group Targets : %s\n%s", err, response) + } + securityGroupTargetReference := sgt.(*vpcv1.SecurityGroupTargetReference) + crn := securityGroupTargetReference.CRN + if crn != nil && *crn != "" && strings.Contains(*crn, "load-balancer") { + lbid := securityGroupTargetReference.ID + _, errsgt := isWaitForLBRemoveAvailable(sess, sgt, *lbid, securityGroupID, securityGroupTargetID, d.Timeout(schema.TimeoutDelete)) + if errsgt != nil { + return errsgt + } + } + d.SetId("") + return nil +} + +func resourceIBMISSecurityGroupTargetExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return false, err + } + securityGroupID := parts[0] + securityGroupTargetID := parts[1] + + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupID, + ID: &securityGroupTargetID, + } + + _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) + } + return true, nil + +} + +func isWaitForLBRemoveAvailable(sess *vpcv1.VpcV1, sgt vpcv1.SecurityGroupTargetReferenceIntf, lbId, securityGroupID, securityGroupTargetID string, timeout time.Duration) (interface{}, error) { + log.Printf("[INFO] Waiting for load balancer binding (%s) to be removed.", lbId) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isLBProvisioning}, + Target: []string{isLBProvisioningDone}, + Refresh: isLBRemoveRefreshFunc(sess, sgt, lbId, securityGroupID, securityGroupTargetID), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 1, + } + + return stateConf.WaitForState() +} + +func isLBRemoveRefreshFunc(sess *vpcv1.VpcV1, sgt vpcv1.SecurityGroupTargetReferenceIntf, lbId, securityGroupID, securityGroupTargetID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupID, + ID: &securityGroupTargetID, + } + _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + getlboptions := &vpcv1.GetLoadBalancerOptions{ + ID: &lbId, + } + lb, response, err := sess.GetLoadBalancer(getlboptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) + } + + if *lb.ProvisioningStatus == "active" || *lb.ProvisioningStatus == "failed" { + return sgt, isLBProvisioningDone, nil + } else { + return sgt, isLBProvisioning, nil + } + } + return nil, isLBProvisioningDone, fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) + } + return sgt, isLBProvisioning, nil + } +} + +func isWaitForLbSgTargetCreateAvailable(sess *vpcv1.VpcV1, lbId string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for load balancer (%s) to be available.", lbId) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isLBProvisioning, "update_pending"}, + Target: []string{isLBProvisioningDone, ""}, + Refresh: isLBSgTargetRefreshFunc(sess, lbId), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isLBSgTargetRefreshFunc(sess *vpcv1.VpcV1, lbId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getlboptions := &vpcv1.GetLoadBalancerOptions{ + ID: &lbId, + } + lb, response, err := sess.GetLoadBalancer(getlboptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) + } + + if *lb.ProvisioningStatus == "active" || *lb.ProvisioningStatus == "failed" { + return lb, isLBProvisioningDone, nil + } + + return lb, isLBProvisioning, nil + } +} diff --git a/ibm/resource_ibm_is_security_group_target_test.go b/ibm/service/vpc/resource_ibm_is_security_group_target_test.go similarity index 83% rename from ibm/resource_ibm_is_security_group_target_test.go rename to ibm/service/vpc/resource_ibm_is_security_group_target_test.go index af83549d9..8d71e8b5d 100644 --- a/ibm/resource_ibm_is_security_group_target_test.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_target_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,12 +26,12 @@ func TestAccIBMISSecurityGroupTarget_basic(t *testing.T) { name := fmt.Sprintf("tfsg-one-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSecurityGroupTargetDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISsecurityGroupTargetConfig(vpcname, subnetname, ISZoneName, ISCIDR, lbname, name), + Config: testAccCheckIBMISsecurityGroupTargetConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSecurityGroupTargetExists("ibm_is_security_group_target.testacc_security_group_target", &securityGroup), resource.TestCheckResourceAttr( @@ -40,7 +44,7 @@ func TestAccIBMISSecurityGroupTarget_basic(t *testing.T) { func testAccCheckIBMISSecurityGroupTargetDestroy(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -48,7 +52,7 @@ func testAccCheckIBMISSecurityGroupTargetDestroy(s *terraform.State) error { if rs.Type != "ibm_is_security_group_target" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -76,15 +80,15 @@ func testAccCheckIBMISSecurityGroupTargetExists(n string, securityGroupID *strin return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No Security Group Target ID is set") + return fmt.Errorf("[ERROR] No Security Group Target ID is set") } - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -102,7 +106,7 @@ func testAccCheckIBMISSecurityGroupTargetExists(n string, securityGroupID *strin *securityGroupID = "" return nil } - return fmt.Errorf("error getting Security Group Target : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) } *securityGroupID = fmt.Sprintf("%s/%s", securityGroupId, targetID) diff --git a/ibm/service/vpc/resource_ibm_is_security_group_test.go b/ibm/service/vpc/resource_ibm_is_security_group_test.go new file mode 100644 index 000000000..45eac4976 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_security_group_test.go @@ -0,0 +1,229 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSecurityGroup_basic(t *testing.T) { + var securityGroup string + + vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsg-createname-%d", acctest.RandIntRange(10, 100)) + //name2 := fmt.Sprintf("tfsg-updatename-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISsecurityGroupConfig(vpcname, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "tags.#", "2"), + ), + }, + { + Config: testAccCheckIBMISsecurityGroupConfigUpdate(vpcname, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "tags.#", "1"), + ), + }, + }, + }) +} +func TestAccIBMISSecurityGroup_wait(t *testing.T) { + var securityGroup string + + vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfsg-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tfsg-ssh-%d", acctest.RandIntRange(10, 100)) + vsiname := fmt.Sprintf("tfsg-vsi-%d", acctest.RandIntRange(10, 100)) + bmname := fmt.Sprintf("tfsg-bm-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsg-createname-%d", acctest.RandIntRange(10, 100)) + publickey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + `) + //name2 := fmt.Sprintf("tfsg-updatename-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISsecurityGroupWaitConfig(name1, vpcname, subnetname, sshname, publickey, vsiname, bmname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_security_group.testacc_security_group", "tags.#", "2"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.testacc_vpc", "name", vpcname), + resource.TestCheckResourceAttr( + "ibm_is_subnet.testacc_subnet", "name", subnetname), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.testacc_sshkey", "name", sshname), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", vsiname), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", bmname), + ), + }, + }, + }) +} + +func testAccCheckIBMISSecurityGroupDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_security_group" { + continue + } + + getsgoptions := &vpcv1.GetSecurityGroupOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetSecurityGroup(getsgoptions) + + if err == nil { + return fmt.Errorf("securitygroup still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISSecurityGroupExists(n, securityGroupID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getsgoptions := &vpcv1.GetSecurityGroupOptions{ + ID: &rs.Primary.ID, + } + foundsecurityGroup, _, err := sess.GetSecurityGroup(getsgoptions) + if err != nil { + return err + } + securityGroupID = *foundsecurityGroup.ID + return nil + } +} + +func testAccCheckIBMISsecurityGroupConfig(vpcname, name string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + tags = ["Tag1", "tag2"] +}`, vpcname, name) + +} +func testAccCheckIBMISsecurityGroupWaitConfig(name, vpcname, subnetname, sshname, publicKey, vsiname, bmname string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource ibm_is_subnet testacc_subnet { + name = "%s" + zone = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + total_ipv4_address_count = 16 +} + +resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + tags = ["tag1", "tag2"] +} + + +resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + security_groups = [ibm_is_security_group.testacc_security_group.id] + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth12" + security_groups = [ibm_is_security_group.testacc_security_group.id] + } +} + +resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + security_groups = [ibm_is_security_group.testacc_security_group.id] + } + vpc = ibm_is_vpc.testacc_vpc.id +} +`, vpcname, subnetname, acc.ISZoneName, name, sshname, publicKey, vsiname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, acc.IsBareMetalServerProfileName, bmname, acc.IsBareMetalServerImage, acc.ISZoneName) + +} + +func testAccCheckIBMISsecurityGroupConfigUpdate(vpcname, name string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} + +resource "ibm_is_security_group" "testacc_security_group" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + tags = ["tag1"] +}`, vpcname, name) + +} diff --git a/ibm/service/vpc/resource_ibm_is_snapshot.go b/ibm/service/vpc/resource_ibm_is_snapshot.go new file mode 100644 index 000000000..d28783ff6 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_snapshot.go @@ -0,0 +1,641 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isSnapshotName = "name" + isSnapshotResourceGroup = "resource_group" + isSnapshotSourceVolume = "source_volume" + isSnapshotSourceImage = "source_image" + isSnapshotUserTags = "tags" + isSnapshotCRN = "crn" + isSnapshotHref = "href" + isSnapshotEncryption = "encryption" + isSnapshotEncryptionKey = "encryption_key" + isSnapshotOperatingSystem = "operating_system" + isSnapshotLCState = "lifecycle_state" + isSnapshotMinCapacity = "minimum_capacity" + isSnapshotResourceType = "resource_type" + isSnapshotSize = "size" + isSnapshotBootable = "bootable" + isSnapshotDeleting = "deleting" + isSnapshotDeleted = "deleted" + isSnapshotAvailable = "stable" + isSnapshotFailed = "failed" + isSnapshotPending = "pending" + isSnapshotSuspended = "suspended" + isSnapshotUpdating = "updating" + isSnapshotWaiting = "waiting" + isSnapshotCapturedAt = "captured_at" + isSnapshotBackupPolicyPlan = "backup_policy_plan" +) + +func ResourceIBMSnapshot() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISSnapshotCreate, + Read: resourceIBMISSnapshotRead, + Update: resourceIBMISSnapshotUpdate, + Delete: resourceIBMISSnapshotDelete, + Exists: resourceIBMISSnapshotExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: map[string]*schema.Schema{ + + isSnapshotName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_snapshot", isSnapshotName), + Description: "Snapshot name", + }, + + isSnapshotResourceGroup: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Resource group info", + }, + + isSnapshotSourceVolume: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Snapshot source volume", + }, + + isSnapshotSourceImage: { + Type: schema.TypeString, + Computed: true, + Description: "If present, the image id from which the data on this volume was most directly provisioned.", + }, + + isSnapshotOperatingSystem: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the operating system included in this image", + }, + + isSnapshotBootable: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + }, + + isSnapshotLCState: { + Type: schema.TypeString, + Computed: true, + Description: "Snapshot lifecycle state", + }, + isSnapshotCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + isSnapshotEncryption: { + Type: schema.TypeString, + Computed: true, + Description: "Encryption type of the snapshot", + }, + isSnapshotEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "A reference to the root key used to wrap the data encryption key for the source volume.", + }, + + isSnapshotHref: { + Type: schema.TypeString, + Computed: true, + Description: "URL for the snapshot", + }, + + isSnapshotMinCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "Minimum capacity of the snapshot", + }, + isSnapshotResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type of the snapshot", + }, + + isSnapshotSize: { + Type: schema.TypeInt, + Computed: true, + Description: "The size of the snapshot", + }, + + isSnapshotUserTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot", isSnapshotUserTags)}, + Set: flex.ResourceIBMVPCHash, + Description: "User Tags for the snapshot", + }, + + isSnapshotBackupPolicyPlan: { + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this backup policy plan.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISSnapshotValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSnapshotName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSnapshotUserTags, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + ibmISSnapshotResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_snapshot", Schema: validateSchema} + return &ibmISSnapshotResourceValidator +} + +func resourceIBMISSnapshotCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.CreateSnapshotOptions{} + snapshotprototypeoptions := &vpcv1.SnapshotPrototypeSnapshotBySourceVolume{} + if snapshotName, ok := d.GetOk(isSnapshotName); ok { + name := snapshotName.(string) + snapshotprototypeoptions.Name = &name + } + if sourceVolume, ok := d.GetOk(isSnapshotSourceVolume); ok { + sv := sourceVolume.(string) + snapshotprototypeoptions.SourceVolume = &vpcv1.VolumeIdentity{ + ID: &sv, + } + } + if grp, ok := d.GetOk(isVPCResourceGroup); ok { + rg := grp.(string) + snapshotprototypeoptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + var userTags *schema.Set + if v, ok := d.GetOk(isSnapshotUserTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + snapshotprototypeoptions.UserTags = userTagsArray + } + } + + log.Printf("[DEBUG] Snapshot create") + options.SnapshotPrototype = snapshotprototypeoptions + snapshot, response, err := sess.CreateSnapshot(options) + if err != nil || snapshot == nil { + return fmt.Errorf("[ERROR] Error creating Snapshot %s\n%s", err, response) + } + + d.SetId(*snapshot.ID) + log.Printf("[INFO] Snapshot : %s", *snapshot.ID) + + _, err = isWaitForSnapshotAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return err + } + + return resourceIBMISSnapshotRead(d, meta) +} + +func isWaitForSnapshotAvailable(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isSnapshotPending}, + Target: []string{isSnapshotAvailable, isSnapshotFailed}, + Refresh: isSnapshotRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSnapshotRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + return nil, isSnapshotFailed, fmt.Errorf("[ERROR] Error getting Snapshot : %s\n%s", err, response) + } + + if *snapshot.LifecycleState == isSnapshotAvailable { + return snapshot, *snapshot.LifecycleState, nil + } else if *snapshot.LifecycleState == isSnapshotFailed { + return snapshot, *snapshot.LifecycleState, fmt.Errorf("Snapshot (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot and attempt to create the snapshot again replacing the previous configuration", *snapshot.ID) + } + + return snapshot, isSnapshotPending, nil + } +} + +func resourceIBMISSnapshotRead(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + err := snapshotGet(d, meta, id) + if err != nil { + return err + } + return nil +} + +func snapshotGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Snapshot : %s\n%s", err, response) + } + + d.SetId(*snapshot.ID) + d.Set(isSnapshotName, *snapshot.Name) + d.Set(isSnapshotHref, *snapshot.Href) + d.Set(isSnapshotCRN, *snapshot.CRN) + d.Set(isSnapshotMinCapacity, *snapshot.MinimumCapacity) + d.Set(isSnapshotSize, *snapshot.Size) + d.Set(isSnapshotEncryption, *snapshot.Encryption) + d.Set(isSnapshotLCState, *snapshot.LifecycleState) + d.Set(isSnapshotResourceType, *snapshot.ResourceType) + d.Set(isSnapshotBootable, *snapshot.Bootable) + if snapshot.UserTags != nil { + if err = d.Set(isSnapshotUserTags, snapshot.UserTags); err != nil { + return fmt.Errorf("Error setting user tags: %s", err) + } + } + if snapshot.ResourceGroup != nil && snapshot.ResourceGroup.ID != nil { + d.Set(isSnapshotResourceGroup, *snapshot.ResourceGroup.ID) + } + if snapshot.SourceVolume != nil && snapshot.SourceVolume.ID != nil { + d.Set(isSnapshotSourceVolume, *snapshot.SourceVolume.ID) + } + + if snapshot.SourceImage != nil && snapshot.SourceImage.ID != nil { + d.Set(isSnapshotSourceImage, *snapshot.SourceImage.ID) + } + + if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil { + d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name) + } + backupPolicyPlanList := []map[string]interface{}{} + if snapshot.BackupPolicyPlan != nil { + backupPolicyPlan := map[string]interface{}{} + if snapshot.BackupPolicyPlan.Deleted != nil { + snapshotBackupPolicyPlanDeletedMap := map[string]interface{}{} + snapshotBackupPolicyPlanDeletedMap["more_info"] = snapshot.BackupPolicyPlan.Deleted.MoreInfo + backupPolicyPlan["deleted"] = []map[string]interface{}{snapshotBackupPolicyPlanDeletedMap} + } + backupPolicyPlan["href"] = snapshot.BackupPolicyPlan.Href + backupPolicyPlan["id"] = snapshot.BackupPolicyPlan.ID + backupPolicyPlan["name"] = snapshot.BackupPolicyPlan.Name + backupPolicyPlan["resource_type"] = snapshot.BackupPolicyPlan.ResourceType + backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) + } + d.Set(isSnapshotBackupPolicyPlan, backupPolicyPlanList) + return nil +} + +func resourceIBMISSnapshotUpdate(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + name := "" + hasChanged := false + + if d.HasChange(isSnapshotName) { + name = d.Get(isSnapshotName).(string) + hasChanged = true + } + err := snapshotUpdate(d, meta, id, name, hasChanged) + if err != nil { + return err + } + return resourceIBMISSnapshotRead(d, meta) +} + +func snapshotUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + _, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error getting Snapshot : %s\n%s", err, response) + } + eTag := response.Headers.Get("ETag") + + updateSnapshotOptions := &vpcv1.UpdateSnapshotOptions{ + ID: &id, + } + updateSnapshotOptions.IfMatch = &eTag + + // user tags update + if d.HasChange(isSnapshotUserTags) { + var userTags *schema.Set + if v, ok := d.GetOk(isSnapshotUserTags); ok { + + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + snapshotPatchModel := &vpcv1.SnapshotPatch{} + snapshotPatchModel.UserTags = userTagsArray + snapshotPatch, err := snapshotPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("Error calling asPatch for SnapshotPatch: %s", err) + } + updateSnapshotOptions.SnapshotPatch = snapshotPatch + _, response, err := sess.UpdateSnapshot(updateSnapshotOptions) + if err != nil { + return fmt.Errorf("Error updating Snapshot : %s\n%s", err, response) + } + _, err = isWaitForSnapshotUpdate(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + } + } + + if d.HasChange(isSnapshotName) { + updateSnapshotOptions := &vpcv1.UpdateSnapshotOptions{ + ID: &id, + } + snapshotPatchModel := &vpcv1.SnapshotPatch{ + Name: &name, + } + snapshotPatch, err := snapshotPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for SnapshotPatch: %s", err) + } + updateSnapshotOptions.SnapshotPatch = snapshotPatch + _, response, err := sess.UpdateSnapshot(updateSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating Snapshot : %s\n%s", err, response) + } + _, err = isWaitForSnapshotUpdate(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + return nil +} + +func isWaitForSnapshotUpdate(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isSnapshotUpdating}, + Target: []string{isSnapshotAvailable, isSnapshotFailed}, + Refresh: isSnapshotUpdateRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isSnapshotUpdateRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + return nil, isSnapshotFailed, fmt.Errorf("[ERROR] Error getting Snapshot : %s\n%s", err, response) + } + + if *snapshot.LifecycleState == isSnapshotAvailable || *snapshot.LifecycleState == isSnapshotFailed { + return snapshot, *snapshot.LifecycleState, nil + } else if *snapshot.LifecycleState == isSnapshotFailed { + return snapshot, *snapshot.LifecycleState, fmt.Errorf("Snapshot (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot and attempt to create the snapshot again replacing the previous configuration", *snapshot.ID) + } + + return snapshot, isSnapshotUpdating, nil + } +} + +func resourceIBMISSnapshotDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + err := snapshotDelete(d, meta, id) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func snapshotDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + _, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Snapshot (%s): %s\n%s", id, err, response) + } + + deleteSnapshotOptions := &vpcv1.DeleteSnapshotOptions{ + ID: &id, + } + response, err = sess.DeleteSnapshot(deleteSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Snapshot : %s\n%s", err, response) + } + _, err = isWaitForSnapshotDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForSnapshotDeleted(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{isSnapshotDeleting}, + Target: []string{isSnapshotDeleted, isSnapshotFailed}, + Refresh: isSnapshotDeleteRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSnapshotDeleteRefreshFunc(sess *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] Refresh function for Snapshot delete.") + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return snapshot, isSnapshotDeleted, nil + } + return nil, isSnapshotFailed, fmt.Errorf("[ERROR] The Snapshot %s failed to delete: %s\n%s", id, err, response) + } + return snapshot, *snapshot.LifecycleState, nil + } +} + +func resourceIBMISSnapshotExists(d *schema.ResourceData, meta interface{}) (bool, error) { + id := d.Id() + exists, err := snapshotExists(d, meta, id) + return exists, err +} + +func snapshotExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + _, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Snapshot: %s\n%s", err, response) + } + return true, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_snapshot_test.go b/ibm/service/vpc/resource_ibm_is_snapshot_test.go new file mode 100644 index 000000000..e1fd459c8 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_snapshot_test.go @@ -0,0 +1,270 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSnapshot_basic(t *testing.T) { + var snapshot string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", name1), + ), + }, + { + Config: testAccCheckIBMISSnapshotConfigUpdate(vpcname, subnetname, sshname, publicKey, volname, name, name2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", name2), + ), + }, + }, + }) +} + +func TestAccIBMISSnapshotUsertag_basic(t *testing.T) { + var snapshot string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + // name2 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) + tagnameupdate := fmt.Sprintf("tfusertagupd%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISSnapshotConfigUsertag(vpcname, subnetname, sshname, publicKey, volname, name, name1, tagname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "tags.0", tagname), + ), + }, + { + Config: testAccCheckIBMISSnapshotConfigUsertag(vpcname, subnetname, sshname, publicKey, volname, name, name1, tagnameupdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "tags.0", tagnameupdate), + ), + }, + }, + }) +} + +func testAccCheckIBMISSnapshotDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_snapshot" { + continue + } + + getSnapshotoptions := &vpcv1.GetSnapshotOptions{ + ID: &rs.Primary.ID, + } + snapshot, _, err := sess.GetSnapshot(getSnapshotoptions) + + if err == nil && *snapshot.LifecycleState != "deleted" { + return fmt.Errorf("snapshot still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMISSnapshotExists(n, sID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getSnapshotoptions := &vpcv1.GetSnapshotOptions{ + ID: &rs.Primary.ID, + } + snapshotID, _, err := sess.GetSnapshot(getSnapshotoptions) + if err != nil { + return err + } + sID = *snapshotID.ID + return nil + } +} + +func testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id +}`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname) + +} + +func testAccCheckIBMISSnapshotConfigUpdate(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname) + +} + +func testAccCheckIBMISSnapshotConfigUsertag(vpcname, subnetname, sshname, publicKey, volname, name, sname, usertag string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + tags = ["%s"] + }`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname, usertag) + +} diff --git a/ibm/service/vpc/resource_ibm_is_ssh_key.go b/ibm/service/vpc/resource_ibm_is_ssh_key.go new file mode 100644 index 000000000..5e2878f34 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_ssh_key.go @@ -0,0 +1,436 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "log" + "os" + "strings" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "golang.org/x/crypto/ssh" +) + +const ( + isKeyName = "name" + IsKeyCRN = "crn" + isKeyPublicKey = "public_key" + isKeyType = "type" + isKeyFingerprint = "fingerprint" + isKeyLength = "length" + isKeyTags = "tags" + isKeyResourceGroup = "resource_group" +) + +func ResourceIBMISSSHKey() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISSSHKeyCreate, + Read: resourceIBMISSSHKeyRead, + Update: resourceIBMISSSHKeyUpdate, + Delete: resourceIBMISSSHKeyDelete, + Exists: resourceIBMISSSHKeyExists, + Importer: &schema.ResourceImporter{}, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: map[string]*schema.Schema{ + isKeyName: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_security_group", isKeyName), + Description: "SSH Key name", + }, + + isKeyPublicKey: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: suppressPublicKeyDiff, + Description: "SSH Public key data", + }, + + isKeyType: { + Type: schema.TypeString, + Computed: true, + Description: "Key type", + }, + + isKeyFingerprint: { + Type: schema.TypeString, + Computed: true, + Description: "SSH key Fingerprint info", + }, + + isKeyLength: { + Type: schema.TypeInt, + Computed: true, + Description: "SSH key Length", + }, + isKeyTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_ssh_key", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags for SSH key", + }, + + isKeyResourceGroup: { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + Description: "Resource group ID", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + IsKeyCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func ResourceIBMISSHKeyValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isKeyName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISSSHKeyResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_ssh_key", Schema: validateSchema} + return &ibmISSSHKeyResourceValidator +} + +func resourceIBMISSSHKeyCreate(d *schema.ResourceData, meta interface{}) error { + + log.Printf("[DEBUG] Key create") + name := d.Get(isKeyName).(string) + publickey := d.Get(isKeyPublicKey).(string) + + err := keyCreate(d, meta, name, publickey) + if err != nil { + return err + } + return resourceIBMISSSHKeyRead(d, meta) +} + +func keyCreate(d *schema.ResourceData, meta interface{}, name, publickey string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.CreateKeyOptions{ + PublicKey: &publickey, + Name: &name, + } + + if rgrp, ok := d.GetOk(isKeyResourceGroup); ok { + rg := rgrp.(string) + options.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + key, response, err := sess.CreateKey(options) + if err != nil { + return fmt.Errorf("[DEBUG] Create SSH Key %s\n%s", err, response) + } + d.SetId(*key.ID) + log.Printf("[INFO] Key : %s", *key.ID) + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isKeyTags); ok || v != "" { + oldList, newList := d.GetChange(isKeyTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *key.CRN) + if err != nil { + log.Printf( + "Error on create of vpc SSH Key (%s) tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMISSSHKeyRead(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + + err := keyGet(d, meta, id) + if err != nil { + return err + } + return nil +} + +func keyGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.GetKeyOptions{ + ID: &id, + } + key, response, err := sess.GetKey(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting SSH Key (%s): %s\n%s", id, err, response) + } + d.Set(isKeyName, *key.Name) + d.Set(isKeyPublicKey, *key.PublicKey) + d.Set(isKeyType, *key.Type) + d.Set(isKeyFingerprint, *key.Fingerprint) + d.Set(isKeyLength, *key.Length) + tags, err := flex.GetTagsUsingCRN(meta, *key.CRN) + if err != nil { + log.Printf( + "Error on get of vpc SSH Key (%s) tags: %s", d.Id(), err) + } + d.Set(isKeyTags, tags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/sshKeys") + d.Set(flex.ResourceName, *key.Name) + d.Set(flex.ResourceCRN, *key.CRN) + d.Set(IsKeyCRN, *key.CRN) + if key.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, *key.ResourceGroup.Name) + d.Set(isKeyResourceGroup, *key.ResourceGroup.ID) + } + return nil +} + +func resourceIBMISSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + name := "" + hasChanged := false + + if d.HasChange(isKeyName) { + name = d.Get(isKeyName).(string) + hasChanged = true + } + + err := keyUpdate(d, meta, id, name, hasChanged) + if err != nil { + return err + } + return resourceIBMISSSHKeyRead(d, meta) +} + +func keyUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasChanged bool) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + if d.HasChange(isKeyTags) { + options := &vpcv1.GetKeyOptions{ + ID: &id, + } + key, response, err := sess.GetKey(options) + if err != nil { + return fmt.Errorf("[ERROR] Error getting SSH Key : %s\n%s", err, response) + } + oldList, newList := d.GetChange(isKeyTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *key.CRN) + if err != nil { + log.Printf( + "Error on update of resource vpc SSH Key (%s) tags: %s", id, err) + } + } + if hasChanged { + options := &vpcv1.UpdateKeyOptions{ + ID: &id, + } + keyPatchModel := &vpcv1.KeyPatch{ + Name: &name, + } + keyPatch, err := keyPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for KeyPatch: %s", err) + } + options.KeyPatch = keyPatch + _, response, err := sess.UpdateKey(options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vpc SSH Key: %s\n%s", err, response) + } + } + return nil +} + +func resourceIBMISSSHKeyDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + err := keyDelete(d, meta, id) + if err != nil { + return err + } + return nil +} + +func keyDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getKeyOptions := &vpcv1.GetKeyOptions{ + ID: &id, + } + _, response, err := sess.GetKey(getKeyOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting SSH Key (%s): %s\n%s", id, err, response) + } + + options := &vpcv1.DeleteKeyOptions{ + ID: &id, + } + response, err = sess.DeleteKey(options) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting SSH Key : %s\n%s", err, response) + } + d.SetId("") + return nil +} + +func resourceIBMISSSHKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) { + id := d.Id() + + exists, err := keyExists(d, meta, id) + return exists, err +} + +func keyExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + options := &vpcv1.GetKeyOptions{ + ID: &id, + } + _, response, err := sess.GetKey(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting SSH Key: %s\n%s", err, response) + } + return true, nil +} + +// to suppress any change shown when keys are same +func suppressPublicKeyDiff(k, old, new string, d *schema.ResourceData) bool { + // if there are extra spaces or new lines, suppress that change + if strings.Compare(strings.TrimSpace(old), strings.TrimSpace(new)) != 0 { + // if old is empty + if old != "" { + //create a new piblickey object from the string + usePK, error := parseKey(new) + if error != nil { + return false + } + // returns the key in byte format with an extra added new line at the end + newkey := strings.TrimRight(string(ssh.MarshalAuthorizedKey(usePK)), "\n") + // check if both keys are same, if yes suppress the change + return strings.TrimSpace(strings.TrimPrefix(newkey, old)) == "" + } else { + return strings.TrimSpace(strings.TrimPrefix(new, old)) == "" + } + } else { + return true + } +} + +// takes a string and returns public key object +func parseKey(s string) (ssh.PublicKey, error) { + keyBytes := []byte(s) + + // Accepts formats of PublicKey: + // - + // - ssh-rsa + // - ssh-rsa + // if PublicKey provides other than just base64 key, then first part must be "ssh-rsa" + if subStrs := strings.Split(s, " "); len(subStrs) > 1 && subStrs[0] != "ssh-rsa" { + return nil, errors.New("not an RSA key") + } + + pk, _, _, _, e := ssh.ParseAuthorizedKey(keyBytes) + if e == nil { + return pk, nil + } + + decodedKey := make([]byte, base64.StdEncoding.DecodedLen(len(keyBytes))) + n, e := base64.StdEncoding.Decode(decodedKey, keyBytes) + if e != nil { + return nil, e + } + decodedKey = decodedKey[:n] + + pk, e = ssh.ParsePublicKey(decodedKey) + if e == nil { + return pk, nil + } + return nil, e +} diff --git a/ibm/service/vpc/resource_ibm_is_ssh_key_test.go b/ibm/service/vpc/resource_ibm_is_ssh_key_test.go new file mode 100644 index 000000000..638ba0a2b --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_ssh_key_test.go @@ -0,0 +1,141 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSSHKey_basic(t *testing.T) { + var key string + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + name := fmt.Sprintf("tfssh-createname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISKeyConfig(publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISKeyExists("ibm_is_ssh_key.isExampleKey", key), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.isExampleKey", "name", name), + ), + }, + }, + }) +} +func TestAccIBMISSSHKey_Newlinebasic(t *testing.T) { + var key, key1 string + publicKeyTrim := strings.TrimSpace(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKd3e4uoENwyLGDxpUyxkeC008r6JOHGkeF4HxEUrE2ZkTXvuOyRaF8Utyv12U5Jvpf/NQVGmdlG3rQPY5VRELthr8mhNWexY5WYo/zXSZNjHCjozpL101bcxfNG498y6uv6UoTk6geJcmckVjOYY/2T9F2B1q6dQxIsYIghjfZBFM6+wA136Nx0nof2lZiK7KAIzIlgUY3g3hhno0x5FmJHM9waoHXFLgQA0psz8XUcSt2Zr0JGFOm5U6HV/tvoP4AVB5YrhRatHry2Ulfh4acy0wswgRM0zieU0U/nLJbCgDVLwZyABEC6WcLTfrkkI53I9oYb8XyeWpyRFQLfT7AIIjfgT7q0q4gzSKTJSDR85SHhOmC/bhCDBuJ9s1ICyschF1y8lPjL/maxweNorg3RfuqsZZdmNHR9RKSxt7CPM98Z6yu5wMWRVLC6Ux5MGp6m0mDIJOfaZla6uvp8d/G6cjWCdU5eCeBh6XdQn4UDXwEB/s86lpgbDsPLMCleP8J+w8uZPQA1KZ+uWGBjoswhtOCa6bU/6ZuTqGpQVOGjVOWUGOq/ocvR03ucj6fBKViFWxV75ABXfJLarKkkIMlv9IeJ05NZG6kQjiCRN4T2I0gd9lAm0YqcITEqcN4Wgbm1z2zPwvMyWuMCW3LY4932JHKQkCEXgGBAtsnrXhZw==`) + publicKeyTrim1 := strings.TrimSpace(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR`) + name := fmt.Sprintf("tfssh-createname-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfssh-withsignaturename-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISKeyNewlineConfig(name, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISKeyExists("ibm_is_ssh_key.isExampleKey", key), + testAccCheckIBMISKeyExists("ibm_is_ssh_key.isExampleKeyWithSignature", key1), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.isExampleKey", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.isExampleKey", "public_key", publicKeyTrim), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.isExampleKeyWithSignature", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_ssh_key.isExampleKeyWithSignature", "public_key", publicKeyTrim1), + ), + }, + }, + }) +} + +func checkKeyDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_ssh_key" { + continue + } + + getkeyoptions := &vpcv1.GetKeyOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetKey(getkeyoptions) + if err == nil { + return fmt.Errorf("key still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISKeyExists(n, keyID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getkeyoptions := &vpcv1.GetKeyOptions{ + ID: &rs.Primary.ID, + } + foundkey, _, err := sess.GetKey(getkeyoptions) + if err != nil { + return err + } + keyID = *foundkey.ID + return nil + } +} + +func testAccCheckIBMISKeyConfig(publicKey, name string) string { + return fmt.Sprintf(` + resource "ibm_is_ssh_key" "isExampleKey" { + name = "%s" + public_key = "%s" + } + `, name, publicKey) +} +func testAccCheckIBMISKeyNewlineConfig(name, name1 string) string { + return fmt.Sprintf(` + resource "ibm_is_ssh_key" "isExampleKey" { + name = "%s" + public_key = <<-EOT + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKd3e4uoENwyLGDxpUyxkeC008r6JOHGkeF4HxEUrE2ZkTXvuOyRaF8Utyv12U5Jvpf/NQVGmdlG3rQPY5VRELthr8mhNWexY5WYo/zXSZNjHCjozpL101bcxfNG498y6uv6UoTk6geJcmckVjOYY/2T9F2B1q6dQxIsYIghjfZBFM6+wA136Nx0nof2lZiK7KAIzIlgUY3g3hhno0x5FmJHM9waoHXFLgQA0psz8XUcSt2Zr0JGFOm5U6HV/tvoP4AVB5YrhRatHry2Ulfh4acy0wswgRM0zieU0U/nLJbCgDVLwZyABEC6WcLTfrkkI53I9oYb8XyeWpyRFQLfT7AIIjfgT7q0q4gzSKTJSDR85SHhOmC/bhCDBuJ9s1ICyschF1y8lPjL/maxweNorg3RfuqsZZdmNHR9RKSxt7CPM98Z6yu5wMWRVLC6Ux5MGp6m0mDIJOfaZla6uvp8d/G6cjWCdU5eCeBh6XdQn4UDXwEB/s86lpgbDsPLMCleP8J+w8uZPQA1KZ+uWGBjoswhtOCa6bU/6ZuTqGpQVOGjVOWUGOq/ocvR03ucj6fBKViFWxV75ABXfJLarKkkIMlv9IeJ05NZG6kQjiCRN4T2I0gd9lAm0YqcITEqcN4Wgbm1z2zPwvMyWuMCW3LY4932JHKQkCEXgGBAtsnrXhZw== + EOT + } + resource "ibm_is_ssh_key" "isExampleKeyWithSignature" { + name = "%s" + public_key = <<-EOT + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR abc@abc-MacBook-Pro.local + EOT + } + `, name, name1) +} diff --git a/ibm/resource_ibm_is_subnet.go b/ibm/service/vpc/resource_ibm_is_subnet.go similarity index 82% rename from ibm/resource_ibm_is_subnet.go rename to ibm/service/vpc/resource_ibm_is_subnet.go index 98b44d469..7f1f7b4d5 100644 --- a/ibm/resource_ibm_is_subnet.go +++ b/ibm/service/vpc/resource_ibm_is_subnet.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -11,6 +11,9 @@ import ( "strings" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -45,7 +48,7 @@ const ( isAccessTagType = "access" ) -func resourceIBMISSubnet() *schema.Resource { +func ResourceIBMISSubnet() *schema.Resource { return &schema.Resource{ Create: resourceIBMISSubnetCreate, Read: resourceIBMISSubnetRead, @@ -61,7 +64,7 @@ func resourceIBMISSubnet() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -72,7 +75,7 @@ func resourceIBMISSubnet() *schema.Resource { Optional: true, Computed: true, ConflictsWith: []string{isSubnetTotalIpv4AddressCount}, - ValidateFunc: InvokeValidator("ibm_is_subnet", isSubnetIpv4CidrBlock), + ValidateFunc: validate.InvokeValidator("ibm_is_subnet", isSubnetIpv4CidrBlock), Description: "IPV4 subnet - CIDR block", }, @@ -95,7 +98,7 @@ func resourceIBMISSubnet() *schema.Resource { ForceNew: true, Default: "ipv4", Optional: true, - ValidateFunc: validateIPVersion, + ValidateFunc: validate.ValidateIPVersion, Description: "The IP version(s) to support for this subnet.", }, @@ -103,7 +106,7 @@ func resourceIBMISSubnet() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_subnet", isSubnetName), + ValidateFunc: validate.InvokeValidator("ibm_is_subnet", isSubnetName), Description: "Subnet name", }, @@ -111,8 +114,8 @@ func resourceIBMISSubnet() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_subnet", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_subnet", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, @@ -120,8 +123,8 @@ func resourceIBMISSubnet() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_subnet", "accesstag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_subnet", isSubnetAccessTags)}, + Set: flex.ResourceIBMVPCHash, Description: "List of access management tags", }, @@ -142,6 +145,7 @@ func resourceIBMISSubnet() *schema.Resource { isSubnetPublicGateway: { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: false, Description: "Public Gateway of the subnet", }, @@ -181,30 +185,30 @@ func resourceIBMISSubnet() *schema.Resource { Description: "routing table id that is associated with the subnet", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -213,47 +217,47 @@ func resourceIBMISSubnet() *schema.Resource { } } -func resourceIBMISSubnetValidator() *ResourceValidator { +func ResourceIBMISSubnetValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSubnetName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isSubnetIpv4CidrBlock, - ValidateFunctionIdentifier: ValidateCIDRAddress, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateCIDRAddress, + Type: validate.TypeString, ForceNew: true, Optional: true}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "accesstag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: isSubnetAccessTags, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^([ ]*[A-Za-z0-9:_.-]+[ ]*)+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISSubnetResourceValidator := ResourceValidator{ResourceName: "ibm_is_subnet", Schema: validateSchema} + ibmISSubnetResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_subnet", Schema: validateSchema} return &ibmISSubnetResourceValidator } @@ -281,8 +285,8 @@ func resourceIBMISSubnetCreate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("only one of %s or %s needs to be provided", isSubnetIpv4CidrBlock, isSubnetTotalIpv4AddressCount) } isSubnetKey := "subnet_key_" + vpc + "_" + zone - ibmMutexKV.Lock(isSubnetKey) - defer ibmMutexKV.Unlock(isSubnetKey) + conns.IbmMutexKV.Lock(isSubnetKey) + defer conns.IbmMutexKV.Unlock(isSubnetKey) acl := "" if nwacl, ok := d.GetOk(isSubnetNetworkACL); ok { @@ -360,7 +364,7 @@ func subnetCreate(d *schema.ResourceData, meta interface{}, name, vpc, zone, ipv subnet, response, err := sess.CreateSubnet(createSubnetOptions) if err != nil { log.Printf("[DEBUG] Subnet err %s\n%s", err, response) - return fmt.Errorf("Error while creating Subnet %s\n%v", err, response) + return fmt.Errorf("[ERROR] Error while creating Subnet %s\n%v", err, response) } d.SetId(*subnet.ID) log.Printf("[INFO] Subnet : %s", *subnet.ID) @@ -371,7 +375,7 @@ func subnetCreate(d *schema.ResourceData, meta interface{}, name, vpc, zone, ipv v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isSubnetTags); ok || v != "" { oldList, newList := d.GetChange(isSubnetTags) - err = UpdateGlobalTagsUsingCRN(oldList, newList, meta, *subnet.CRN, "", isUserTagType) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *subnet.CRN, "", isUserTagType) if err != nil { log.Printf( "Error on create of resource subnet (%s) tags: %s", d.Id(), err) @@ -380,7 +384,7 @@ func subnetCreate(d *schema.ResourceData, meta interface{}, name, vpc, zone, ipv if _, ok := d.GetOk(isSubnetAccessTags); ok { oldList, newList := d.GetChange(isSubnetAccessTags) - err = UpdateGlobalTagsUsingCRN(oldList, newList, meta, *subnet.CRN, "", isAccessTagType) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *subnet.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error on create of resource subnet (%s) access tags: %s", d.Id(), err) @@ -412,7 +416,7 @@ func isSubnetRefreshFunc(subnetC *vpcv1.VpcV1, id string) resource.StateRefreshF } subnet, response, err := subnetC.GetSubnet(getSubnetOptions) if err != nil { - return nil, "", fmt.Errorf("Error getting Subnet : %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting Subnet : %s\n%s", err, response) } if *subnet.Status == "available" || *subnet.Status == "failed" { @@ -448,7 +452,7 @@ func subnetGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting Subnet (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response) } d.Set(isSubnetName, *subnet.Name) d.Set(isSubnetIPVersion, *subnet.IPVersion) @@ -472,18 +476,18 @@ func subnetGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isSubnetZone, *subnet.Zone.Name) d.Set(isSubnetVPC, *subnet.VPC.ID) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - tags, err := GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isUserTagType) + tags, err := flex.GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isUserTagType) if err != nil { log.Printf( "Error on get of resource subnet (%s) tags: %s", d.Id(), err) } - accesstags, err := GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isAccessTagType) + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *subnet.CRN, "", isAccessTagType) if err != nil { log.Printf( "Error on get of resource subnet (%s) access tags: %s", d.Id(), err) @@ -492,13 +496,13 @@ func subnetGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isSubnetTags, tags) d.Set(isSubnetAccessTags, accesstags) d.Set(isSubnetCRN, *subnet.CRN) - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/subnets") - d.Set(ResourceName, *subnet.Name) - d.Set(ResourceCRN, *subnet.CRN) - d.Set(ResourceStatus, *subnet.Status) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/subnets") + d.Set(flex.ResourceName, *subnet.Name) + d.Set(flex.ResourceCRN, *subnet.CRN) + d.Set(flex.ResourceStatus, *subnet.Status) if subnet.ResourceGroup != nil { d.Set(isSubnetResourceGroup, *subnet.ResourceGroup.ID) - d.Set(ResourceGroupName, *subnet.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *subnet.ResourceGroup.Name) } return nil } @@ -508,7 +512,7 @@ func resourceIBMISSubnetUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange(isSubnetTags) { oldList, newList := d.GetChange(isSubnetTags) - err := UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get(isSubnetCRN).(string), "", isUserTagType) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get(isSubnetCRN).(string), "", isUserTagType) if err != nil { log.Printf( "Error on update of resource subnet (%s) tags: %s", d.Id(), err) @@ -517,7 +521,7 @@ func resourceIBMISSubnetUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange(isSubnetAccessTags) { oldList, newList := d.GetChange(isSubnetAccessTags) - err := UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get(isSubnetCRN).(string), "", isAccessTagType) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get(isSubnetCRN).(string), "", isAccessTagType) if err != nil { log.Printf( "Error on update of resource subnet (%s) access tags: %s", d.Id(), err) @@ -562,7 +566,7 @@ func subnetUpdate(d *schema.ResourceData, meta interface{}, id string) error { } response, err := sess.UnsetSubnetPublicGateway(unsetSubnetPublicGatewayOptions) if err != nil { - return fmt.Errorf("Error Detaching the public gateway attached to the subnet : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Detaching the public gateway attached to the subnet : %s\n%s", err, response) } _, err = isWaitForSubnetAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) if err != nil { @@ -577,7 +581,7 @@ func subnetUpdate(d *schema.ResourceData, meta interface{}, id string) error { } _, response, err := sess.SetSubnetPublicGateway(setSubnetPublicGatewayOptions) if err != nil { - return fmt.Errorf("Error Attaching public gateway to the subnet : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Attaching public gateway to the subnet : %s\n%s", err, response) } _, err = isWaitForSubnetAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) if err != nil { @@ -607,13 +611,13 @@ func subnetUpdate(d *schema.ResourceData, meta interface{}, id string) error { if hasChanged { subnetPatch, err := subnetPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for SubnetPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for SubnetPatch: %s", err) } updateSubnetOptions.SubnetPatch = subnetPatch updateSubnetOptions.ID = &id _, response, err := sess.UpdateSubnet(updateSubnetOptions) if err != nil { - return fmt.Errorf("Error Updating Subnet : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Subnet : %s\n%s", err, response) } } return nil @@ -644,7 +648,7 @@ func subnetDelete(d *schema.ResourceData, meta interface{}, id string) error { if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Getting Subnet (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response) } if subnet.PublicGateway != nil { unsetSubnetPublicGatewayOptions := &vpcv1.UnsetSubnetPublicGatewayOptions{ @@ -665,12 +669,13 @@ func subnetDelete(d *schema.ResourceData, meta interface{}, id string) error { response, err = sess.DeleteSubnet(deleteSubnetOptions) if err != nil { if response != nil && response.StatusCode == 409 { + log.Printf("[DEBUG] Delete subnet response status code: 409 conflict, provider will try again. %s", err) _, err = isWaitForSubnetDeleteRetry(sess, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("Error Deleting Subnet : %s", err) + return fmt.Errorf("[ERROR] Error Deleting Subnet : %s", err) } } else { - return fmt.Errorf("Error Deleting Subnet : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Subnet : %s\n%s", err, response) } } _, err = isWaitForSubnetDeleted(sess, d.Id(), d.Timeout(schema.TimeoutDelete)) @@ -682,7 +687,7 @@ func subnetDelete(d *schema.ResourceData, meta interface{}, id string) error { } func isWaitForSubnetDeleteRetry(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Retrying subnet (%s) delete", id) + log.Printf("[DEBUG] Retrying subnet (%s) delete", id) stateConf := &resource.StateChangeConf{ Pending: []string{isSubnetInUse}, Target: []string{isSubnetDeleting, isSubnetDeleted, ""}, @@ -690,7 +695,7 @@ func isWaitForSubnetDeleteRetry(vpcClient *vpcv1.VpcV1, id string, timeout time. deleteSubnetOptions := &vpcv1.DeleteSubnetOptions{ ID: &id, } - log.Printf("Retrying subnet (%s) delete", id) + log.Printf("[DEBUG] Retrying subnet (%s) delete", id) response, err := vpcClient.DeleteSubnet(deleteSubnetOptions) if err != nil { if response != nil && response.StatusCode == 409 { @@ -698,7 +703,7 @@ func isWaitForSubnetDeleteRetry(vpcClient *vpcv1.VpcV1, id string, timeout time. } else if response != nil && response.StatusCode == 404 { return response, isSubnetDeleted, nil } - return response, "", fmt.Errorf("Error deleting subnet: %s\n%s", err, response) + return response, "", fmt.Errorf("[ERROR] Error deleting subnet: %s\n%s", err, response) } return response, isSubnetDeleting, nil }, @@ -726,7 +731,7 @@ func isWaitForSubnetDeleted(subnetC *vpcv1.VpcV1, id string, timeout time.Durati func isSubnetDeleteRefreshFunc(subnetC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] is subnet delete function here") getSubnetOptions := &vpcv1.GetSubnetOptions{ ID: &id, } @@ -738,7 +743,7 @@ func isSubnetDeleteRefreshFunc(subnetC *vpcv1.VpcV1, id string) resource.StateRe if response != nil && strings.Contains(err.Error(), "please detach all network interfaces from subnet before deleting it") { return subnet, isSubnetDeleting, nil } - return subnet, "", fmt.Errorf("The Subnet %s failed to delete: %s\n%s", id, err, response) + return subnet, "", fmt.Errorf("[ERROR] The Subnet %s failed to delete: %s\n%s", id, err, response) } return subnet, isSubnetDeleting, err } @@ -763,7 +768,7 @@ func subnetExists(d *schema.ResourceData, meta interface{}, id string) (bool, er if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Subnet: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Subnet: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_subnet_network_acl_attachment.go b/ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment.go similarity index 94% rename from ibm/resource_ibm_is_subnet_network_acl_attachment.go rename to ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment.go index 1aa081e77..e863770e3 100644 --- a/ibm/resource_ibm_is_subnet_network_acl_attachment.go +++ b/ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" @@ -18,7 +18,7 @@ const ( isNetworkACLID = "network_acl" ) -func resourceIBMISSubnetNetworkACLAttachment() *schema.Resource { +func ResourceIBMISSubnetNetworkACLAttachment() *schema.Resource { return &schema.Resource{ Create: resourceIBMISSubnetNetworkACLAttachmentCreate, Read: resourceIBMISSubnetNetworkACLAttachmentRead, @@ -215,7 +215,7 @@ func resourceIBMISSubnetNetworkACLAttachmentCreate(d *schema.ResourceData, meta if err != nil { log.Printf("[DEBUG] Error while attaching a network ACL to a subnet %s\n%s", err, response) - return fmt.Errorf("Error while attaching a network ACL to a subnet %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while attaching a network ACL to a subnet %s\n%s", err, response) } d.SetId(subnet) log.Printf("[INFO] Network ACL : %s", *resultACL.ID) @@ -241,11 +241,12 @@ func resourceIBMISSubnetNetworkACLAttachmentRead(d *schema.ResourceData, meta in d.SetId("") return nil } - return fmt.Errorf("Error getting subnet's (%s) attached network ACL: %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting subnet's (%s) attached network ACL: %s\n%s", id, err, response) } d.Set(isNetworkACLName, *nwacl.Name) d.Set(isNetworkACLCRN, *nwacl.CRN) d.Set(isNetworkACLVPC, *nwacl.VPC.ID) + d.Set(isNetworkACLID, *nwacl.ID) if nwacl.ResourceGroup != nil { d.Set(isNetworkACLResourceGroup, *nwacl.ResourceGroup.ID) } @@ -355,7 +356,7 @@ func resourceIBMISSubnetNetworkACLAttachmentUpdate(d *schema.ResourceData, meta if err != nil { log.Printf("[DEBUG] Error while attaching a network ACL to a subnet %s\n%s", err, response) - return fmt.Errorf("Error while attaching a network ACL to a subnet %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while attaching a network ACL to a subnet %s\n%s", err, response) } log.Printf("[INFO] Updated subnet %s with Network ACL : %s", subnet, *resultACL.ID) @@ -382,7 +383,7 @@ func resourceIBMISSubnetNetworkACLAttachmentDelete(d *schema.ResourceData, meta d.SetId("") return nil } - return fmt.Errorf("Error Getting Subnet (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response) } // Fetch VPC vpcID := *subnet.VPC.ID @@ -396,7 +397,7 @@ func resourceIBMISSubnetNetworkACLAttachmentDelete(d *schema.ResourceData, meta d.SetId("") return nil } - return fmt.Errorf("Error getting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting VPC : %s\n%s", err, response) } // Fetch default network ACL @@ -414,7 +415,7 @@ func resourceIBMISSubnetNetworkACLAttachmentDelete(d *schema.ResourceData, meta if err != nil { log.Printf("[DEBUG] Error while attaching a network ACL to a subnet %s\n%s", err, response) - return fmt.Errorf("Error while attaching a network ACL to a subnet %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while attaching a network ACL to a subnet %s\n%s", err, response) } log.Printf("[INFO] Updated subnet %s with VPC default Network ACL : %s", id, *resultACL.ID) } else { @@ -439,7 +440,7 @@ func resourceIBMISSubnetNetworkACLAttachmentExists(d *schema.ResourceData, meta if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting subnet's attached network ACL: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting subnet's attached network ACL: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_subnet_network_acl_attachment_test.go b/ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment_test.go similarity index 88% rename from ibm/resource_ibm_is_subnet_network_acl_attachment_test.go rename to ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment_test.go index e226e0d6d..a31529162 100644 --- a/ibm/resource_ibm_is_subnet_network_acl_attachment_test.go +++ b/ibm/service/vpc/resource_ibm_is_subnet_network_acl_attachment_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,12 +23,12 @@ func TestAccIBMISSubnetNetworkACLAttachment_basic(t *testing.T) { vpcname := fmt.Sprintf("tfsubnet-vpc-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tfsubnet-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: checkSubnetNetworkACLAttachmentDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISSubnetNetworkACLAttachmentConfig(nwaclname, vpcname, name1, ISZoneName, ISCIDR), + { + Config: testAccCheckIBMISSubnetNetworkACLAttachmentConfig(nwaclname, vpcname, name1, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetNetworkACLAttachmentExists("ibm_is_subnet_network_acl_attachment.attach", subnetNwACL), ), @@ -36,7 +39,7 @@ func TestAccIBMISSubnetNetworkACLAttachment_basic(t *testing.T) { func checkSubnetNetworkACLAttachmentDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_subnet_network_acl_attachment" { continue @@ -67,7 +70,7 @@ func testAccCheckIBMISSubnetNetworkACLAttachmentExists(n, subnetNwACL string) re return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getSubnetNetworkACLOptionsModel := &vpcv1.GetSubnetNetworkACLOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment.go b/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment.go new file mode 100644 index 000000000..058f308f4 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment.go @@ -0,0 +1,334 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isPublicGatewayID = "public_gateway" + IsPublicGatewayResourceType = "resource_type" + IsPublicGatewayAttachmentAvailable = "available" + IsPublicGatewayAttachmentDeleting = "deleting" + IsPublicGatewayAttachmentFailed = "failed" + IsPublicGatewayAttachmentPending = "pending" +) + +func ResourceIBMISSubnetPublicGatewayAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISSubnetPublicGatewayAttachmentCreate, + ReadContext: resourceIBMISSubnetPublicGatewayAttachmentRead, + UpdateContext: resourceIBMISSubnetPublicGatewayAttachmentUpdate, + DeleteContext: resourceIBMISSubnetPublicGatewayAttachmentDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isSubnetID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The subnet identifier", + }, + + isPublicGatewayID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of public gateway", + }, + + isPublicGatewayName: { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Public gateway instance", + }, + + isPublicGatewayFloatingIP: { + Type: schema.TypeMap, + Computed: true, + }, + + isPublicGatewayStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Public gateway instance status", + }, + + isPublicGatewayResourceGroup: { + Type: schema.TypeString, + Computed: true, + Description: "Public gateway resource group info", + }, + + isPublicGatewayVPC: { + Type: schema.TypeString, + Computed: true, + Description: "Public gateway VPC info", + }, + + isPublicGatewayZone: { + Type: schema.TypeString, + Computed: true, + Description: "Public gateway zone info", + }, + + IsPublicGatewayResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + isPublicGatewayCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + }, + } +} + +func resourceIBMISSubnetPublicGatewayAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + subnet := d.Get(isSubnetID).(string) + publicGateway := d.Get(isPublicGatewayID).(string) + + publicGatewayIdentity := &vpcv1.PublicGatewayIdentity{ + ID: &publicGateway, + } + + // Construct an instance of the SetSubnetPublicGatewayOptions + setSubnetPublicGatewayOptions := &vpcv1.SetSubnetPublicGatewayOptions{ + ID: &subnet, + PublicGatewayIdentity: publicGatewayIdentity, + } + + pg, response, err := sess.SetSubnetPublicGatewayWithContext(context, setSubnetPublicGatewayOptions) + + if err != nil { + log.Printf("[DEBUG] Error while attaching public gateway(%s) to subnet(%s) %s\n%s", publicGateway, subnet, err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while attaching public gateway(%s) to subnet(%s) %s\n%s", publicGateway, subnet, err, response)) + } + d.SetId(subnet) + _, err = isWaitForSubnetPublicGatewayAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[INFO] Public Gateway : %s", *pg.ID) + log.Printf("[INFO] Subnet ID : %s", subnet) + + return resourceIBMISSubnetPublicGatewayAttachmentRead(context, d, meta) +} + +func resourceIBMISSubnetPublicGatewayAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getSubnetPublicGatewayOptionsModel := &vpcv1.GetSubnetPublicGatewayOptions{ + ID: &id, + } + pg, response, err := sess.GetSubnetPublicGatewayWithContext(context, getSubnetPublicGatewayOptionsModel) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting subnet's (%s) attached public gateway: %s\n%s", id, err, response)) + } + d.Set(isPublicGatewayName, pg.Name) + d.Set(isSubnetID, id) + d.Set(isPublicGatewayID, pg.ID) + if pg.FloatingIP != nil { + floatIP := map[string]interface{}{ + "id": *pg.FloatingIP.ID, + isPublicGatewayFloatingIPAddress: *pg.FloatingIP.Address, + } + d.Set(isPublicGatewayFloatingIP, floatIP) + } + d.Set(isPublicGatewayStatus, pg.Status) + if pg.ResourceGroup != nil { + d.Set(isPublicGatewayResourceGroup, *pg.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *pg.ResourceGroup.Name) + } + d.Set(isPublicGatewayVPC, *pg.VPC.ID) + d.Set(isPublicGatewayZone, *pg.Zone.Name) + d.Set(IsPublicGatewayResourceType, pg.ResourceType) + d.Set(isPublicGatewayCRN, pg.CRN) + + return nil +} + +func resourceIBMISSubnetPublicGatewayAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + if d.HasChange(isPublicGatewayID) { + subnet := d.Get(isSubnetID).(string) + publicGateway := d.Get(isPublicGatewayID).(string) + + publicGatewayIdentity := &vpcv1.PublicGatewayIdentity{ + ID: &publicGateway, + } + + // Construct an instance of the SetSubnetPublicGatewayOptions + setSubnetPublicGatewayOptions := &vpcv1.SetSubnetPublicGatewayOptions{ + ID: &subnet, + PublicGatewayIdentity: publicGatewayIdentity, + } + + pg, response, err := sess.SetSubnetPublicGatewayWithContext(context, setSubnetPublicGatewayOptions) + + if err != nil || pg == nil { + log.Printf("[DEBUG] Error while attaching public gateway(%s) to subnet(%s) %s\n%s", publicGateway, subnet, err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while attaching public gateway(%s) to subnet(%s) %s\n%s", publicGateway, subnet, err, response)) + } + log.Printf("[INFO] Updated subnet %s with public gateway(%s)", subnet, publicGateway) + + d.SetId(subnet) + return resourceIBMISSubnetPublicGatewayAttachmentRead(context, d, meta) + } + + return resourceIBMISSubnetPublicGatewayAttachmentRead(context, d, meta) +} + +func resourceIBMISSubnetPublicGatewayAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + // Get subnet details + getSubnetOptions := &vpcv1.GetSubnetOptions{ + ID: &id, + } + _, response, err := sess.GetSubnetWithContext(context, getSubnetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response)) + } + + // Construct an instance of the UnsetSubnetPublicGatewayOptions model + unsetSubnetPublicGatewayOptions := &vpcv1.UnsetSubnetPublicGatewayOptions{ + ID: &id, + } + res, err := sess.UnsetSubnetPublicGatewayWithContext(context, unsetSubnetPublicGatewayOptions) + + if err != nil { + log.Printf("[DEBUG] Error while detaching public gateway to subnet %s\n%s", err, res) + return diag.FromErr(fmt.Errorf("[ERROR] Error while detaching public gateway to subnet %s\n%s", err, res)) + } + _, err = isWaitForSubnetPublicGatewayDelete(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + return nil +} + +func isWaitForSubnetPublicGatewayAvailable(subnetC *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for subnet (%s) public gateway attachment to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{IsPublicGatewayAttachmentPending, IsPublicGatewayAttachmentDeleting}, + Target: []string{IsPublicGatewayAttachmentAvailable, IsPublicGatewayAttachmentFailed, ""}, + Refresh: isSubnetPublicGatewayRefreshFunc(subnetC, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSubnetPublicGatewayRefreshFunc(subnetC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getSubnetPublicGatewayOptionsModel := &vpcv1.GetSubnetPublicGatewayOptions{ + ID: &id, + } + pg, response, err := subnetC.GetSubnetPublicGateway(getSubnetPublicGatewayOptionsModel) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return pg, "", fmt.Errorf("[ERROR] Error getting subnet's (%s) attached public gateway: %s\n%s", id, err, response) + } + return pg, "", fmt.Errorf("[ERROR] Error getting subnet's (%s) attached public gateway: %s\n%s", id, err, response) + } + + if *pg.Status == "failed" { + return pg, IsPublicGatewayAttachmentFailed, fmt.Errorf("[ERROR] Error subnet (%s) public gateway attachment failed: %s\n%s", id, err, response) + } + + return pg, *pg.Status, nil + } +} + +func isWaitForSubnetPublicGatewayDelete(subnetC *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for subnet (%s) public gateway attachment to be detached.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{IsPublicGatewayAttachmentPending, IsPublicGatewayAttachmentDeleting}, + Target: []string{IsPublicGatewayAttachmentAvailable, IsPublicGatewayAttachmentFailed, ""}, + Refresh: isSubnetPublicGatewayDeleteRefreshFunc(subnetC, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSubnetPublicGatewayDeleteRefreshFunc(subnetC *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getSubnetPublicGatewayOptionsModel := &vpcv1.GetSubnetPublicGatewayOptions{ + ID: &id, + } + pg, response, err := subnetC.GetSubnetPublicGateway(getSubnetPublicGatewayOptionsModel) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return pg, "", nil + } + return pg, "", fmt.Errorf("[ERROR] Error getting subnet's (%s) attached public gateway: %s\n%s", id, err, response) + } + + if *pg.Status == "failed" { + return pg, IsPublicGatewayAttachmentFailed, fmt.Errorf("[ERROR] Error subnet (%s) public gateway attachment failed: %s\n%s", id, err, response) + } + + return pg, *pg.Status, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment_test.go b/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment_test.go new file mode 100644 index 000000000..02e0c39d3 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_public_gateway_attachment_test.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSubnetPublicGatewayAttachment_basic(t *testing.T) { + var subnetPublicGateway string + pgname := fmt.Sprintf("tfnw-pg-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tfsubnet-vpc-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsubnet-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkSubnetPublicGatewayAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISSubnetPublicGatewayAttachmentConfig(vpcname, name1, acc.ISZoneName, pgname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSubnetPublicGatewayAttachmentExists("ibm_is_subnet_public_gateway_attachment.attach", subnetPublicGateway), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_public_gateway_attachment.attach", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_public_gateway_attachment.attach", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_public_gateway_attachment.attach", "resource_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_public_gateway_attachment.attach", "status"), + ), + }, + }, + }) +} + +func checkSubnetPublicGatewayAttachmentDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_subnet_public_gateway_attachment" { + continue + } + getSubnetPublicGatewayOptionsModel := &vpcv1.GetSubnetPublicGatewayOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetSubnetPublicGateway(getSubnetPublicGatewayOptionsModel) + + if err == nil { + return fmt.Errorf("subnet public gateway attachment still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMISSubnetPublicGatewayAttachmentExists(n, subnetPublicGateway string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getSubnetPublicGatewayOptionsModel := &vpcv1.GetSubnetPublicGatewayOptions{ + ID: &rs.Primary.ID, + } + foundSubnetPG, _, err := sess.GetSubnetPublicGateway(getSubnetPublicGatewayOptionsModel) + if err != nil { + return err + } + subnetPublicGateway = *foundSubnetPG.ID + return nil + } +} + +func testAccCheckIBMISSubnetPublicGatewayAttachmentConfig(vpcname, name, zone, pgname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_public_gateway" "testacc_pg" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + } + + resource "ibm_is_subnet_public_gateway_attachment" "attach" { + depends_on = [ibm_is_public_gateway.testacc_pg, ibm_is_subnet.testacc_subnet] + subnet = ibm_is_subnet.testacc_subnet.id + public_gateway = ibm_is_public_gateway.testacc_pg.id + } + + `, vpcname, name, zone, pgname, zone) +} diff --git a/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go new file mode 100644 index 000000000..3c6e85bbe --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go @@ -0,0 +1,392 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isReservedIPProvisioning = "provisioning" + isReservedIPProvisioningDone = "done" + isReservedIP = "reserved_ip" + isReservedIPTarget = "target" + isReservedIPLifecycleState = "lifecycle_state" +) + +func ResourceIBMISReservedIP() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISReservedIPCreate, + Read: resourceIBMISReservedIPRead, + Update: resourceIBMISReservedIPUpdate, + Delete: resourceIBMISReservedIPDelete, + Exists: resourceIBMISReservedIPExists, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + /* + Request Parameters + ================== + These are mandatory req parameters + */ + isSubNetID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The subnet identifier.", + }, + isReservedIPAutoDelete: { + Type: schema.TypeBool, + Default: nil, + Computed: true, + Optional: true, + Description: "If set to true, this reserved IP will be automatically deleted", + }, + isReservedIPName: { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_subnet_reserved_ip", isReservedIPName), + Description: "The user-defined or system-provided name for this reserved IP.", + }, + isReservedIPTarget: { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "The unique identifier for target.", + }, + isReservedIPLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reserved IP", + }, + /* + Response Parameters + =================== + All of these are computed and an user doesn't need to provide + these from outside. + */ + + isReservedIPAddress: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The address for this reserved IP.", + }, + isReservedIP: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier of the reserved IP.", + }, + isReservedIPCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reserved IP was created.", + }, + isReservedIPhref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + isReservedIPOwner: { + Type: schema.TypeString, + Computed: true, + Description: "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + }, + isReservedIPType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} +func ResourceIBMISSubnetReservedIPValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservedIPName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + ibmISSubnetReservedIPCResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_subnet_reserved_ip", Schema: validateSchema} + return &ibmISSubnetReservedIPCResourceValidator +} + +// resourceIBMISReservedIPCreate Creates a reserved IP given a subnet ID +func resourceIBMISReservedIPCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + subnetID := d.Get(isSubNetID).(string) + options := sess.NewCreateSubnetReservedIPOptions(subnetID) + + nameStr := "" + if name, ok := d.GetOk(isReservedIPName); ok { + nameStr = name.(string) + } + if nameStr != "" { + options.Name = &nameStr + } + addStr := "" + if address, ok := d.GetOk(isReservedIPAddress); ok { + addStr = address.(string) + } + if addStr != "" { + options.Address = &addStr + } + + autoDeleteBool := d.Get(isReservedIPAutoDelete).(bool) + options.AutoDelete = &autoDeleteBool + if t, ok := d.GetOk(isReservedIPTarget); ok { + targetId := t.(string) + options.Target = &vpcv1.ReservedIPTargetPrototype{ + ID: &targetId, + } + } + rip, response, err := sess.CreateSubnetReservedIP(options) + if err != nil || response == nil || rip == nil { + return fmt.Errorf("[ERROR] Error creating the reserved IP: %s\n%s", err, response) + } + + // Set id for the reserved IP as combination of subnet ID and reserved IP ID + d.SetId(fmt.Sprintf("%s/%s", subnetID, *rip.ID)) + _, err = isWaitForReservedIpAvailable(sess, subnetID, *rip.ID, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for the reserved IP to be available: %s", err) + } + + return resourceIBMISReservedIPRead(d, meta) +} + +func resourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{}) error { + rip, err := get(d, meta) + if err != nil { + return err + } + + allIDs, err := flex.IdParts(d.Id()) + if err != nil { + return fmt.Errorf("[ERROR] The ID can not be split into subnet ID and reserved IP ID. %s", err) + } + subnetID := allIDs[0] + + if rip != nil { + d.Set(isReservedIPAddress, *rip.Address) + d.Set(isReservedIP, *rip.ID) + d.Set(isSubNetID, subnetID) + if rip.LifecycleState != nil { + d.Set(isReservedIPLifecycleState, *rip.LifecycleState) + } + d.Set(isReservedIPAutoDelete, *rip.AutoDelete) + d.Set(isReservedIPCreatedAt, (*rip.CreatedAt).String()) + d.Set(isReservedIPhref, *rip.Href) + d.Set(isReservedIPName, *rip.Name) + d.Set(isReservedIPOwner, *rip.Owner) + d.Set(isReservedIPType, *rip.ResourceType) + if rip.Target != nil { + targetIntf := rip.Target + switch reflect.TypeOf(targetIntf).String() { + case "*vpcv1.ReservedIPTargetEndpointGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetEndpointGatewayReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext": + { + target := targetIntf.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetLoadBalancerReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetLoadBalancerReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTargetVPNGatewayReference": + { + target := targetIntf.(*vpcv1.ReservedIPTargetVPNGatewayReference) + d.Set(isReservedIPTarget, target.ID) + } + case "*vpcv1.ReservedIPTarget": + { + target := targetIntf.(*vpcv1.ReservedIPTarget) + d.Set(isReservedIPTarget, target.ID) + } + } + } + } + return nil +} + +func resourceIBMISReservedIPUpdate(d *schema.ResourceData, meta interface{}) error { + + // For updating the name + nameChanged := d.HasChange(isReservedIPName) + autoDeleteChanged := d.HasChange(isReservedIPAutoDelete) + + if nameChanged || autoDeleteChanged { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + allIDs, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + subnetID := allIDs[0] + reservedIPID := allIDs[1] + + options := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetID, + ID: &reservedIPID, + } + + patch := new(vpcv1.ReservedIPPatch) + + if nameChanged { + name := d.Get(isReservedIPName).(string) + patch.Name = core.StringPtr(name) + } + + if autoDeleteChanged { + autoDelete := d.Get(isReservedIPAutoDelete).(bool) + patch.AutoDelete = core.BoolPtr(autoDelete) + } + + reservedIPPatch, err := patch.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error updating the reserved IP %s", err) + } + + options.ReservedIPPatch = reservedIPPatch + + _, response, err := sess.UpdateSubnetReservedIP(options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating the reserved IP %s\n%s", err, response) + } + } + return resourceIBMISReservedIPRead(d, meta) +} + +func resourceIBMISReservedIPDelete(d *schema.ResourceData, meta interface{}) error { + + rip, err := get(d, meta) + if err != nil { + return err + } + if err == nil && rip == nil { + // If there is no such reserved IP, it can not be deleted + return nil + } + + sess, err := vpcClient(meta) + if err != nil { + return err + } + allIDs, err := flex.IdParts(d.Id()) + if err != nil { + return err + } + subnetID := allIDs[0] + reservedIPID := allIDs[1] + deleteOptions := sess.NewDeleteSubnetReservedIPOptions(subnetID, reservedIPID) + response, err := sess.DeleteSubnetReservedIP(deleteOptions) + if err != nil || response == nil { + return fmt.Errorf("[ERROR] Error deleting the reserverd ip %s in subnet %s, %s\n%s", reservedIPID, subnetID, err, response) + } + d.SetId("") + return nil +} + +func resourceIBMISReservedIPExists(d *schema.ResourceData, meta interface{}) (bool, error) { + rip, err := get(d, meta) + if err != nil { + return false, err + } + if err == nil && rip == nil { + return false, nil + } + return true, nil +} + +// get is a generic function that gets the reserved ip given subnet id and reserved ip +func get(d *schema.ResourceData, meta interface{}) (*vpcv1.ReservedIP, error) { + sess, err := vpcClient(meta) + if err != nil { + return nil, err + } + allIDs, err := flex.IdParts(d.Id()) + subnetID := allIDs[0] + reservedIPID := allIDs[1] + options := sess.NewGetSubnetReservedIPOptions(subnetID, reservedIPID) + rip, response, err := sess.GetSubnetReservedIP(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil, nil + } + return nil, fmt.Errorf("[ERROR] Error Getting Reserved IP : %s\n%s", err, response) + } + return rip, nil +} + +func isWaitForReservedIpAvailable(sess *vpcv1.VpcV1, subnetid, id string, timeout time.Duration, d *schema.ResourceData) (interface{}, error) { + log.Printf("Waiting for reseved ip (%s/%s) to be available.", subnetid, id) + stateConf := &resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: []string{"done", "failed", ""}, + Refresh: isReserveIpRefreshFunc(sess, subnetid, id, d), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isReserveIpRefreshFunc(sess *vpcv1.VpcV1, subnetid, id string, d *schema.ResourceData) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getreservedipOptions := &vpcv1.GetSubnetReservedIPOptions{ + ID: &id, + SubnetID: &subnetid, + } + rsip, response, err := sess.GetSubnetReservedIP(getreservedipOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error Getting reserved ip(%s/%s) : %s\n%s", subnetid, id, err, response) + } + if rsip.LifecycleState != nil { + d.Set(isReservedIPLifecycleState, *rsip.LifecycleState) + } + d.Set(isReservedIPAddress, *rsip.Address) + + if rsip.LifecycleState != nil && *rsip.LifecycleState == "failed" { + return rsip, "failed", fmt.Errorf("[ERROR] Error Reserved ip(%s/%s) creation failed : %s\n%s", subnetid, id, err, response) + } + if rsip.LifecycleState != nil && *rsip.LifecycleState == "stable" { + return rsip, "done", nil + } + return rsip, "pending", nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip_test.go b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip_test.go new file mode 100644 index 000000000..34bd6bc8c --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip_test.go @@ -0,0 +1,176 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSubnetReservedIPResource_basic(t *testing.T) { + var reservedIPID string + vpcName := fmt.Sprintf("tfresip-vpc-%d", acctest.RandIntRange(10, 100)) + subnetName := fmt.Sprintf("tfresip-subnet-%d", acctest.RandIntRange(10, 100)) + reservedIPName := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) + reservedIPName2 := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) + terraformTag := "ibm_is_subnet_reserved_ip.resIP1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckisSubnetReservedIPDestroy, + Steps: []resource.TestStep{ + { + // Tests create + Config: testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, reservedIPName), + Check: resource.ComposeTestCheckFunc( + testAccCheckISSubnetReservedIPExists(terraformTag, &reservedIPID), + resource.TestCheckResourceAttr(terraformTag, "name", reservedIPName), + ), + }, + { + // Tests Update + Config: testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, reservedIPName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckISSubnetReservedIPExists(terraformTag, &reservedIPID), + resource.TestCheckResourceAttr(terraformTag, "name", reservedIPName2), + ), + }, + }, + }) +} +func TestAccIBMISSubnetReservedIPResource_address(t *testing.T) { + var reservedIPID string + vpcName := fmt.Sprintf("tfresip-vpc-%d", acctest.RandIntRange(10, 100)) + subnetName := fmt.Sprintf("tfresip-subnet-%d", acctest.RandIntRange(10, 100)) + reservedIPName := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) + terraformTag := "ibm_is_subnet_reserved_ip.resIP1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckisSubnetReservedIPDestroy, + Steps: []resource.TestStep{ + { + // Tests create + Config: testAccCheckISSubnetReservedIPConfigAddress(vpcName, subnetName, reservedIPName), + Check: resource.ComposeTestCheckFunc( + testAccCheckISSubnetReservedIPExists(terraformTag, &reservedIPID), + resource.TestCheckResourceAttr(terraformTag, "name", reservedIPName), + resource.TestCheckResourceAttr(terraformTag, "address", "10.240.0.14"), + ), + }, + }, + }) +} + +func testAccCheckisSubnetReservedIPDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_subnet_reserved_ip" { + continue + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + opt := sess.NewGetSubnetReservedIPOptions(parts[0], parts[1]) + _, response, err := sess.GetSubnetReservedIP(opt) + if err == nil { + return fmt.Errorf("Reserved IP still exists: %v", response) + } + } + return nil +} + +func testAccCheckISSubnetReservedIPExists(resIPName string, reservedIPID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[resIPName] + if !ok { + return fmt.Errorf("Not Found (reserved IP): %s", resIPName) + } + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No reserved IP ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + opt := sess.NewGetSubnetReservedIPOptions(parts[0], parts[1]) + result, response, err := sess.GetSubnetReservedIP(opt) + if err != nil { + return fmt.Errorf("Reserved IP does not exist: %s", response) + } + *reservedIPID = *result.ID + return nil + } +} + +func testAccCheckISSubnetReservedIPConfigBasic(vpcName, subnetName, resIPName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet1" { + name = "%s" + vpc = ibm_is_vpc.vpc1.id + zone = "us-south-1" + total_ipv4_address_count = 256 + } + + resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { + name = "my-endpoint-gateway-1" + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.vpc1.id + } + + resource "ibm_is_subnet_reserved_ip" "resIP1" { + subnet = ibm_is_subnet.subnet1.id + name = "%s" + target = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id + } + `, vpcName, subnetName, resIPName) +} +func testAccCheckISSubnetReservedIPConfigAddress(vpcName, subnetName, resIPName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet1" { + name = "%s" + vpc = ibm_is_vpc.vpc1.id + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_subnet_reserved_ip" "resIP1" { + subnet = ibm_is_subnet.subnet1.id + name = "%s" + address = "${replace(ibm_is_subnet.subnet1.ipv4_cidr_block, "0/24", "14")}" + } + `, vpcName, subnetName, acc.ISZoneName, acc.ISCIDR, resIPName) +} diff --git a/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment.go b/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment.go new file mode 100644 index 000000000..fa9a4b537 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment.go @@ -0,0 +1,296 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMISSubnetRoutingTableAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMISSubnetRoutingTableAttachmentCreate, + ReadContext: resourceIBMISSubnetRoutingTableAttachmentRead, + UpdateContext: resourceIBMISSubnetRoutingTableAttachmentUpdate, + DeleteContext: resourceIBMISSubnetRoutingTableAttachmentDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + + isSubnetID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The subnet identifier", + }, + + isRoutingTableID: { + Type: schema.TypeString, + Required: true, + Description: "The unique identifier of routing table", + }, + + rtRouteDirectLinkIngress: { + Type: schema.TypeBool, + Computed: true, + Description: "If true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + }, + + rtIsDefault: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this is the default routing table for this VPC", + }, + rtLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "he lifecycle state of the routing table [ deleting, failed, pending, stable, suspended, updating, waiting ]", + }, + + isRoutingTableName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the routing table", + }, + isRoutingTableResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type", + }, + + rtRouteTransitGatewayIngress: { + Type: schema.TypeBool, + Computed: true, + Description: "If true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + }, + + rtRouteVPCZoneIngress: { + Type: schema.TypeBool, + Computed: true, + Description: "If true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + }, + + rtSubnets: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rtName: { + Type: schema.TypeString, + Computed: true, + Description: "Subnet name", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Subnet ID", + }, + }, + }, + }, + + rtRoutes: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rtName: { + Type: schema.TypeString, + Computed: true, + Description: "route name", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "route ID", + }, + }, + }, + }, + }, + } +} + +func resourceIBMISSubnetRoutingTableAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + subnet := d.Get(isSubnetID).(string) + routingTable := d.Get(isRoutingTableID).(string) + + // Construct an instance of the RoutingTableIdentityByID model + routingTableIdentityModel := new(vpcv1.RoutingTableIdentityByID) + routingTableIdentityModel.ID = &routingTable + + // Construct an instance of the ReplaceSubnetRoutingTableOptions model + replaceSubnetRoutingTableOptionsModel := new(vpcv1.ReplaceSubnetRoutingTableOptions) + replaceSubnetRoutingTableOptionsModel.ID = &subnet + replaceSubnetRoutingTableOptionsModel.RoutingTableIdentity = routingTableIdentityModel + resultRT, response, err := sess.ReplaceSubnetRoutingTableWithContext(context, replaceSubnetRoutingTableOptionsModel) + + if err != nil { + log.Printf("[DEBUG] Error while attaching a routing table to a subnet %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while attaching a routing table to a subnet %s\n%s", err, response)) + } + d.SetId(subnet) + log.Printf("[INFO] Routing Table : %s", *resultRT.ID) + log.Printf("[INFO] Subnet ID : %s", subnet) + + return resourceIBMISSubnetRoutingTableAttachmentRead(context, d, meta) +} + +func resourceIBMISSubnetRoutingTableAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getSubnetRoutingTableOptionsModel := &vpcv1.GetSubnetRoutingTableOptions{ + ID: &id, + } + subRT, response, err := sess.GetSubnetRoutingTableWithContext(context, getSubnetRoutingTableOptionsModel) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting subnet's (%s) attached routing table: %s\n%s", id, err, response)) + } + d.Set(isRoutingTableName, *subRT.Name) + d.Set(isSubnetID, id) + d.Set(isRoutingTableID, *subRT.ID) + d.Set(isRoutingTableResourceType, *subRT.ResourceType) + d.Set(rtRouteDirectLinkIngress, *subRT.RouteDirectLinkIngress) + d.Set(rtIsDefault, *subRT.IsDefault) + d.Set(rtLifecycleState, *subRT.LifecycleState) + d.Set(isRoutingTableResourceType, *subRT.ResourceType) + d.Set(rtRouteTransitGatewayIngress, *subRT.RouteTransitGatewayIngress) + d.Set(rtRouteVPCZoneIngress, *subRT.RouteVPCZoneIngress) + subnets := make([]map[string]interface{}, 0) + + for _, s := range subRT.Subnets { + subnet := make(map[string]interface{}) + subnet[ID] = *s.ID + subnet["name"] = *s.Name + subnets = append(subnets, subnet) + } + d.Set(rtSubnets, subnets) + + routes := make([]map[string]interface{}, 0) + for _, s := range subRT.Routes { + route := make(map[string]interface{}) + route[ID] = *s.ID + route["name"] = *s.Name + routes = append(routes, route) + } + d.Set(rtRoutes, routes) + return nil +} + +func resourceIBMISSubnetRoutingTableAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + if d.HasChange(isRoutingTableID) { + subnet := d.Get(isSubnetID).(string) + routingTable := d.Get(isRoutingTableID).(string) + + // Construct an instance of the RoutingTableIdentityByID model + routingTableIdentityModel := new(vpcv1.RoutingTableIdentityByID) + routingTableIdentityModel.ID = &routingTable + + // Construct an instance of the ReplaceSubnetRoutingTableOptions model + replaceSubnetRoutingTableOptionsModel := new(vpcv1.ReplaceSubnetRoutingTableOptions) + replaceSubnetRoutingTableOptionsModel.ID = &subnet + replaceSubnetRoutingTableOptionsModel.RoutingTableIdentity = routingTableIdentityModel + resultRT, response, err := sess.ReplaceSubnetRoutingTableWithContext(context, replaceSubnetRoutingTableOptionsModel) + + if err != nil { + log.Printf("[DEBUG] Error while attaching a routing table to a subnet %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while attaching a routing table to a subnet %s\n%s", err, response)) + } + log.Printf("[INFO] Updated subnet %s with Routing Table : %s", subnet, *resultRT.ID) + + d.SetId(subnet) + return resourceIBMISSubnetRoutingTableAttachmentRead(context, d, meta) + } + + return resourceIBMISSubnetRoutingTableAttachmentRead(context, d, meta) +} + +func resourceIBMISSubnetRoutingTableAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + id := d.Id() + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + // Set the subnet with VPC default routing table + getSubnetOptions := &vpcv1.GetSubnetOptions{ + ID: &id, + } + subnet, response, err := sess.GetSubnetWithContext(context, getSubnetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Subnet (%s): %s\n%s", id, err, response)) + } + // Fetch VPC + vpcID := *subnet.VPC.ID + + getvpcOptions := &vpcv1.GetVPCOptions{ + ID: &vpcID, + } + vpc, response, err := sess.GetVPCWithContext(context, getvpcOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error getting VPC : %s\n%s", err, response)) + } + + // Fetch default routing table + if vpc.DefaultRoutingTable != nil { + log.Printf("[DEBUG] vpc default routing table is not null :%s", *vpc.DefaultRoutingTable.ID) + // Construct an instance of the RoutingTableIdentityByID model + routingTableIdentityModel := new(vpcv1.RoutingTableIdentityByID) + routingTableIdentityModel.ID = vpc.DefaultRoutingTable.ID + + // Construct an instance of the ReplaceSubnetRoutingTableOptions model + replaceSubnetRoutingTableOptionsModel := new(vpcv1.ReplaceSubnetRoutingTableOptions) + replaceSubnetRoutingTableOptionsModel.ID = &id + replaceSubnetRoutingTableOptionsModel.RoutingTableIdentity = routingTableIdentityModel + resultRT, response, err := sess.ReplaceSubnetRoutingTableWithContext(context, replaceSubnetRoutingTableOptionsModel) + + if err != nil { + log.Printf("[DEBUG] Error while attaching a routing table to a subnet %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while attaching a routing table to a subnet %s\n%s", err, response)) + } + log.Printf("[INFO] Updated subnet %s with VPC default Routing Table : %s", id, *resultRT.ID) + } else { + log.Printf("[DEBUG] vpc default routing table is null") + } + + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment_test.go b/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment_test.go new file mode 100644 index 000000000..69717214f --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_subnet_routing_table_attachment_test.go @@ -0,0 +1,116 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISSubnetRoutingTableAttachment_basic(t *testing.T) { + var subnetRT string + rtname := fmt.Sprintf("tfrt-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tfvpc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfsubnet-vpc-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkSubnetRoutingTableAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISSubnetRoutingTableAttachmentConfig(rtname, subnetname, vpcname, acc.ISZoneName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSubnetRoutingTableAttachmentExists("ibm_is_subnet_routing_table_attachment.attach", subnetRT), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_routing_table_attachment.attach", "lifecycle_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_routing_table_attachment.attach", "resource_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_subnet_routing_table_attachment.attach", "id"), + ), + }, + }, + }) +} + +func checkSubnetRoutingTableAttachmentDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_subnet_routing_table_attachment" { + continue + } + + getSubnetRoutingTableOptionsModel := &vpcv1.GetSubnetRoutingTableOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetSubnetRoutingTable(getSubnetRoutingTableOptionsModel) + + if err == nil { + return fmt.Errorf("subnet routing table attachment still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMISSubnetRoutingTableAttachmentExists(n, subnetRT string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getSubnetRoutingTableOptionsModel := &vpcv1.GetSubnetRoutingTableOptions{ + ID: &rs.Primary.ID, + } + foundsubnetRT, _, err := sess.GetSubnetRoutingTable(getSubnetRoutingTableOptionsModel) + if err != nil { + return err + } + subnetRT = *foundsubnetRT.ID + return nil + } +} + +func testAccCheckIBMISSubnetRoutingTableAttachmentConfig(rtname, subnetname, vpcname, zone string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_vpc_routing_table" "testacc_vpc_routing_table" { + vpc = ibm_is_vpc.testacc_vpc.id + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_subnet_routing_table_attachment" "attach" { + depends_on = [ibm_is_vpc_routing_table.testacc_vpc_routing_table, ibm_is_subnet.testacc_subnet] + subnet = ibm_is_subnet.testacc_subnet.id + routing_table = ibm_is_vpc_routing_table.testacc_vpc_routing_table.routing_table + } + + `, vpcname, rtname, subnetname, zone) +} diff --git a/ibm/resource_ibm_is_subnet_test.go b/ibm/service/vpc/resource_ibm_is_subnet_test.go similarity index 82% rename from ibm/resource_ibm_is_subnet_test.go rename to ibm/service/vpc/resource_ibm_is_subnet_test.go index 5291910df..a4dadf59e 100644 --- a/ibm/resource_ibm_is_subnet_test.go +++ b/ibm/service/vpc/resource_ibm_is_subnet_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,34 +25,34 @@ func TestAccIBMISSubnet_basic(t *testing.T) { name2 := fmt.Sprintf("tfsubnet-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISSubnetDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISSubnetConfig(vpcname, name1, ISZoneName, ISCIDR), + Config: testAccCheckIBMISSubnetConfig(vpcname, name1, acc.ISZoneName, acc.ISCIDR), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetExists("ibm_is_subnet.testacc_subnet", subnet), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "name", name1), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "zone", ISZoneName), + "ibm_is_subnet.testacc_subnet", "zone", acc.ISZoneName), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", ISCIDR), + "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", acc.ISCIDR), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "tags.#", "2"), ), }, { - Config: testAccCheckIBMISSubnetConfigUpdate(vpcname, name2, ISZoneName, ISCIDR, gwname), + Config: testAccCheckIBMISSubnetConfigUpdate(vpcname, name2, acc.ISZoneName, acc.ISCIDR, gwname), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISSubnetExists("ibm_is_subnet.testacc_subnet", subnet), resource.TestCheckResourceAttr( "ibm_is_subnet.testacc_subnet", "name", name2), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "zone", ISZoneName), + "ibm_is_subnet.testacc_subnet", "zone", acc.ISZoneName), resource.TestCheckResourceAttr( - "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", ISCIDR), + "ibm_is_subnet.testacc_subnet", "ipv4_cidr_block", acc.ISCIDR), resource.TestCheckResourceAttrSet( "ibm_is_subnet.testacc_subnet", "public_gateway"), resource.TestCheckResourceAttr( @@ -62,7 +65,7 @@ func TestAccIBMISSubnet_basic(t *testing.T) { func testAccCheckIBMISSubnetDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_subnet" { continue @@ -93,7 +96,7 @@ func testAccCheckIBMISSubnetExists(n, subnetID string) resource.TestCheckFunc { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getsubnetoptions := &vpcv1.GetSubnetOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go new file mode 100644 index 000000000..a3718cd05 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go @@ -0,0 +1,580 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isVirtualEndpointGatewayName = "name" + isVirtualEndpointGatewayResourceType = "resource_type" + isVirtualEndpointGatewayCRN = "crn" + isVirtualEndpointGatewayResourceGroupID = "resource_group" + isVirtualEndpointGatewayCreatedAt = "created_at" + isVirtualEndpointGatewayIPs = "ips" + isVirtualEndpointGatewayIPsID = "id" + isVirtualEndpointGatewayIPsAddress = "address" + isVirtualEndpointGatewayIPsName = "name" + isVirtualEndpointGatewayIPsSubnet = "subnet" + isVirtualEndpointGatewayIPsResourceType = "resource_type" + isVirtualEndpointGatewayHealthState = "health_state" + isVirtualEndpointGatewayLifecycleState = "lifecycle_state" + isVirtualEndpointGatewayTarget = "target" + isVirtualEndpointGatewayTargetName = "name" + isVirtualEndpointGatewayTargetCRN = "crn" + isVirtualEndpointGatewayTargetResourceType = "resource_type" + isVirtualEndpointGatewayVpcID = "vpc" + isVirtualEndpointGatewayTags = "tags" + isVirtualEndpointGatewaySecurityGroups = "security_groups" +) + +func ResourceIBMISEndpointGateway() *schema.Resource { + targetNameFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetName) + targetCRNFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetCRN) + return &schema.Resource{ + Create: resourceIBMisVirtualEndpointGatewayCreate, + Read: resourceIBMisVirtualEndpointGatewayRead, + Update: resourceIBMisVirtualEndpointGatewayUpdate, + Delete: resourceIBMisVirtualEndpointGatewayDelete, + Exists: resourceIBMisVirtualEndpointGatewayExists, + Importer: &schema.ResourceImporter{}, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway", isVirtualEndpointGatewayName), + Description: "Endpoint gateway name", + }, + isVirtualEndpointGatewayResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway resource type", + }, + isVirtualEndpointGatewayCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this Endpoint gateway", + }, + isVirtualEndpointGatewayResourceGroupID: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The resource group id", + }, + isVirtualEndpointGatewayCreatedAt: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway created date and time", + }, + isVirtualEndpointGatewayHealthState: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway health state", + }, + isVirtualEndpointGatewayLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "Endpoint gateway lifecycle state", + }, + isVirtualEndpointGatewaySecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "Endpoint gateway securitygroups list", + }, + isVirtualEndpointGatewayIPs: { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "Endpoint gateway IPs", + DiffSuppressFunc: flex.ApplyOnce, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayIPsID: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IPs id", + }, + isVirtualEndpointGatewayIPsName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IPs name", + }, + isVirtualEndpointGatewayIPsSubnet: { + Type: schema.TypeString, + Optional: true, + Description: "The Subnet id", + }, + isVirtualEndpointGatewayIPsResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The VPE Resource Type", + }, + isVirtualEndpointGatewayIPsAddress: { + Type: schema.TypeString, + Computed: true, + Description: "The IP Address", + }, + }, + }, + }, + isVirtualEndpointGatewayTarget: { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Description: "Endpoint gateway target", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVirtualEndpointGatewayTargetName: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + AtLeastOneOf: []string{ + targetNameFmt, + targetCRNFmt, + }, + Description: "The target name", + }, + isVirtualEndpointGatewayTargetCRN: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + AtLeastOneOf: []string{ + targetNameFmt, + targetCRNFmt, + }, + Description: "The target crn", + }, + isVirtualEndpointGatewayTargetResourceType: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway", isVirtualEndpointGatewayTargetResourceType), + Description: "The target resource type", + }, + }, + }, + }, + isVirtualEndpointGatewayVpcID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPC id", + }, + isVirtualEndpointGatewayTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_virtual_endpoint_gateway", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of tags for VPE", + }, + }, + } +} + +func ResourceIBMISEndpointGatewayValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVirtualEndpointGatewayName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVirtualEndpointGatewayTargetResourceType, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "provider_cloud_service, provider_infrastructure_service"}) + + ibmEndpointGatewayResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_virtual_endpoint_gateway", Schema: validateSchema} + return &ibmEndpointGatewayResourceValidator +} + +func resourceIBMisVirtualEndpointGatewayCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + name := d.Get(isVirtualEndpointGatewayName).(string) + + // target opiton + targetOpt := &vpcv1.EndpointGatewayTargetPrototype{} + targetNameFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetName) + targetCRNFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetCRN) + targetResourceTypeFmt := fmt.Sprintf("%s.0.%s", isVirtualEndpointGatewayTarget, isVirtualEndpointGatewayTargetResourceType) + targetOpt.ResourceType = core.StringPtr(d.Get(targetResourceTypeFmt).(string)) + if v, ok := d.GetOk(targetNameFmt); ok { + targetOpt.Name = core.StringPtr(v.(string)) + } + if v, ok := d.GetOk(targetCRNFmt); ok { + targetOpt.CRN = core.StringPtr(v.(string)) + } + + // vpc option + vpcID := d.Get(isVirtualEndpointGatewayVpcID).(string) + vpcOpt := &vpcv1.VPCIdentity{ + ID: core.StringPtr(vpcID), + } + + // update option + opt := sess.NewCreateEndpointGatewayOptions(targetOpt, vpcOpt) + opt.SetName(name) + opt.SetTarget(targetOpt) + opt.SetVPC(vpcOpt) + + // IPs option + if ips, ok := d.GetOk(isVirtualEndpointGatewayIPs); ok { + opt.SetIps(expandIPs(ips.([]interface{}))) + } + // Security group option + var securityGroups *schema.Set + if sg, ok := d.GetOk(isVirtualEndpointGatewaySecurityGroups); ok { + securityGroups = sg.(*schema.Set) + if securityGroups != nil && securityGroups.Len() != 0 { + securityGroupobjs := make([]vpcv1.SecurityGroupIdentityIntf, securityGroups.Len()) + for i, securityGroup := range securityGroups.List() { + securityGroupstr := securityGroup.(string) + securityGroupobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &securityGroupstr, + } + } + opt.SecurityGroups = securityGroupobjs + } + } + // Resource group option + if resourceGroup, ok := d.GetOk(isVirtualEndpointGatewayResourceGroupID); ok { + resourceGroupID := resourceGroup.(string) + + resourceGroupOpt := &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(resourceGroupID), + } + opt.SetResourceGroup(resourceGroupOpt) + + } + result, response, err := sess.CreateEndpointGateway(opt) + if err != nil { + log.Printf("Create Endpoint Gateway failed: %v", response) + return fmt.Errorf("Create Endpoint Gateway failed %s\n%s", err, response) + } + + d.SetId(*result.ID) + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isVirtualEndpointGatewayTags); ok || v != "" { + oldList, newList := d.GetChange(isVirtualEndpointGatewayTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *result.CRN) + if err != nil { + log.Printf( + "Error on create of VPE (%s) tags: %s", d.Id(), err) + } + } + return resourceIBMisVirtualEndpointGatewayRead(d, meta) +} + +func resourceIBMisVirtualEndpointGatewayUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + if d.HasChange(isVirtualEndpointGatewayName) { + name := d.Get(isVirtualEndpointGatewayName).(string) + + // create option + endpointGatewayPatchModel := new(vpcv1.EndpointGatewayPatch) + endpointGatewayPatchModel.Name = core.StringPtr(name) + endpointGatewayPatchModelAsPatch, _ := endpointGatewayPatchModel.AsPatch() + opt := sess.NewUpdateEndpointGatewayOptions(d.Id(), endpointGatewayPatchModelAsPatch) + _, response, err := sess.UpdateEndpointGateway(opt) + if err != nil { + log.Printf("Update Endpoint Gateway failed: %v", response) + return fmt.Errorf("Update Endpoint Gateway failed : %s\n%s", err, response) + } + + } + id := d.Id() + var remove, add []string + if d.HasChange(isVirtualEndpointGatewaySecurityGroups) { + o, n := d.GetChange(isVirtualEndpointGatewaySecurityGroups) + oSecurityGroups := o.(*schema.Set) + nSecurityGroups := n.(*schema.Set) + remove = flex.ExpandStringList(oSecurityGroups.Difference(nSecurityGroups).List()) + add = flex.ExpandStringList(nSecurityGroups.Difference(oSecurityGroups).List()) + if len(add) > 0 { + for _, sgId := range add { + createSecurityGroupTargetBindingOptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{} + createSecurityGroupTargetBindingOptions.SecurityGroupID = &sgId + createSecurityGroupTargetBindingOptions.ID = &id + _, response, err := sess.CreateSecurityGroupTargetBinding(createSecurityGroupTargetBindingOptions) + if err != nil { + return fmt.Errorf("Error while creating Security Group Target Binding %s\n%s", err, response) + } + _, err = isWaitForVirtualEndpointGatewayAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + if len(remove) > 0 { + for _, sgId := range remove { + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &sgId, + ID: &id, + } + _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + continue + } + return fmt.Errorf("Error Getting Security Group Target for this endpoint gateway (%s): %s\n%s", sgId, err, response) + } + deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(sgId, id) + response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) + if err != nil { + return fmt.Errorf("Error Deleting Security Group Target for this endpoint gateway : %s\n%s", err, response) + } + _, err = isWaitForVirtualEndpointGatewayAvailable(sess, d.Id(), d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + + } + if d.HasChange(isVirtualEndpointGatewayTags) { + opt := sess.NewGetEndpointGatewayOptions(d.Id()) + result, response, err := sess.GetEndpointGateway(opt) + if err != nil { + return fmt.Errorf("[ERROR] Error getting VPE: %s\n%s", err, response) + } + oldList, newList := d.GetChange(isVirtualEndpointGatewayTags) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *result.CRN) + if err != nil { + log.Printf( + "Error on update of VPE (%s) tags: %s", d.Id(), err) + } + } + return resourceIBMisVirtualEndpointGatewayRead(d, meta) +} + +func resourceIBMisVirtualEndpointGatewayRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + // read option + opt := sess.NewGetEndpointGatewayOptions(d.Id()) + result, response, err := sess.GetEndpointGateway(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("Get Endpoint Gateway failed: %v", response) + return fmt.Errorf("Get Endpoint Gateway failed %s\n%s", err, response) + } + d.Set(isVirtualEndpointGatewayName, result.Name) + d.Set(isVirtualEndpointGatewayHealthState, result.HealthState) + d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String()) + d.Set(isVirtualEndpointGatewayLifecycleState, result.LifecycleState) + d.Set(isVirtualEndpointGatewayResourceType, result.ResourceType) + d.Set(isVirtualEndpointGatewayCRN, result.CRN) + d.Set(isVirtualEndpointGatewayIPs, flattenIPs(result.Ips)) + d.Set(isVirtualEndpointGatewayResourceGroupID, result.ResourceGroup.ID) + d.Set(isVirtualEndpointGatewayTarget, + flattenEndpointGatewayTarget(result.Target.(*vpcv1.EndpointGatewayTarget))) + d.Set(isVirtualEndpointGatewayVpcID, result.VPC.ID) + if result.SecurityGroups != nil { + d.Set(isVirtualEndpointGatewaySecurityGroups, flattenDataSourceSecurityGroups(result.SecurityGroups)) + } + tags, err := flex.GetTagsUsingCRN(meta, *result.CRN) + if err != nil { + log.Printf( + "Error on get of VPE (%s) tags: %s", d.Id(), err) + } + d.Set(isVirtualEndpointGatewayTags, tags) + return nil +} + +func flattenDataSourceSecurityGroups(securityGroupList []vpcv1.SecurityGroupReference) interface{} { + securitygroupList := make([]string, 0) + for _, securityGroup := range securityGroupList { + if securityGroup.ID != nil { + securityGroupID := *securityGroup.ID + securitygroupList = append(securitygroupList, securityGroupID) + } + } + return securitygroupList +} + +func isWaitForVirtualEndpointGatewayAvailable(sess *vpcv1.VpcV1, endPointGatewayId string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for virtual endpoint gateway (%s) to be available.", endPointGatewayId) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"waiting", "pending", "updating"}, + Target: []string{"stable", "failed", ""}, + Refresh: isVirtualEndpointGatewayRefreshFunc(sess, endPointGatewayId), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isVirtualEndpointGatewayRefreshFunc(sess *vpcv1.VpcV1, endPointGatewayId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + opt := sess.NewGetEndpointGatewayOptions(endPointGatewayId) + result, response, err := sess.GetEndpointGateway(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, "", fmt.Errorf("Error Getting Virtual Endpoint Gateway : %s\n%s", err, response) + } + } + if *result.LifecycleState == "stable" || *result.LifecycleState == "failed" { + return result, *result.LifecycleState, nil + } + return result, *result.LifecycleState, nil + } +} + +func resourceIBMisVirtualEndpointGatewayDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + opt := sess.NewDeleteEndpointGatewayOptions(d.Id()) + response, err := sess.DeleteEndpointGateway(opt) + if err != nil { + log.Printf("Delete Endpoint Gateway failed: %v", response) + return fmt.Errorf("Delete Endpoint Gateway failed : %s\n%s", err, response) + } + return nil +} + +func resourceIBMisVirtualEndpointGatewayExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + + opt := sess.NewGetEndpointGatewayOptions(d.Id()) + _, response, err := sess.GetEndpointGateway(opt) + if err != nil { + if response != nil && response.StatusCode == 404 { + log.Printf("Endpoint Gateway does not exist.") + return false, nil + } + log.Printf("Error : %s", response) + return false, err + } + return true, nil +} + +func expandIPs(ipsSet []interface{}) (ipsOptions []vpcv1.EndpointGatewayReservedIPIntf) { + ipsList := ipsSet + for _, item := range ipsList { + ips := item.(map[string]interface{}) + // IPs option + ipsID := ips[isVirtualEndpointGatewayIPsID].(string) + ipsName := ips[isVirtualEndpointGatewayIPsName].(string) + + // IPs subnet option + ipsSubnetID := ips[isVirtualEndpointGatewayIPsSubnet].(string) + + ipsSubnetOpt := &vpcv1.SubnetIdentity{ + ID: &ipsSubnetID, + } + + ipsOpt := &vpcv1.EndpointGatewayReservedIP{ + ID: core.StringPtr(ipsID), + Name: core.StringPtr(ipsName), + Subnet: ipsSubnetOpt, + } + ipsOptions = append(ipsOptions, ipsOpt) + } + return ipsOptions +} + +func flattenIPs(ipsList []vpcv1.ReservedIPReference) interface{} { + ipsListOutput := make([]interface{}, 0) + for _, item := range ipsList { + ips := make(map[string]interface{}, 0) + ips[isVirtualEndpointGatewayIPsID] = *item.ID + ips[isVirtualEndpointGatewayIPsName] = *item.Name + ips[isVirtualEndpointGatewayIPsResourceType] = *item.ResourceType + ips[isVirtualEndpointGatewayIPsAddress] = *item.Address + + ipsListOutput = append(ipsListOutput, ips) + } + return ipsListOutput +} + +func flattenEndpointGatewayTarget(target *vpcv1.EndpointGatewayTarget) interface{} { + targetSlice := []interface{}{} + targetOutput := map[string]string{} + if target == nil { + return targetOutput + } + if target.Name != nil { + targetOutput[isVirtualEndpointGatewayTargetName] = *target.Name + } + if target.CRN != nil { + targetOutput[isVirtualEndpointGatewayTargetCRN] = *target.CRN + } + if target.ResourceType != nil { + targetOutput[isVirtualEndpointGatewayTargetResourceType] = *target.ResourceType + } + targetSlice = append(targetSlice, targetOutput) + return targetSlice +} diff --git a/ibm/resource_ibm_is_virtual_endpoint_gateway_ip.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip.go similarity index 95% rename from ibm/resource_ibm_is_virtual_endpoint_gateway_ip.go rename to ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip.go index 27449e4b7..0be1209fe 100644 --- a/ibm/resource_ibm_is_virtual_endpoint_gateway_ip.go +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip.go @@ -1,13 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -26,7 +27,7 @@ const ( isVirtualEndpointGatewayIPTargetResourceType = "resource_type" ) -func resourceIBMISEndpointGatewayIP() *schema.Resource { +func ResourceIBMISEndpointGatewayIP() *schema.Resource { return &schema.Resource{ Create: resourceIBMisVirtualEndpointGatewayIPCreate, Read: resourceIBMisVirtualEndpointGatewayIPRead, @@ -128,7 +129,7 @@ func resourceIBMisVirtualEndpointGatewayIPRead(d *schema.ResourceData, meta inte if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -156,7 +157,7 @@ func resourceIBMisVirtualEndpointGatewayIPDelete(d *schema.ResourceData, meta in if err != nil { return err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -178,12 +179,12 @@ func resourceIBMisVirtualEndpointGatewayIPExists(d *schema.ResourceData, meta in return false, err } - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of gatewayID/ipID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of gatewayID/ipID", d.Id()) } gatewayID := parts[0] ipID := parts[1] diff --git a/ibm/resource_ibm_is_virtual_endpoint_gateway_ip_test.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip_test.go similarity index 82% rename from ibm/resource_ibm_is_virtual_endpoint_gateway_ip_test.go rename to ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip_test.go index ee08bd843..c367286a4 100644 --- a/ibm/resource_ibm_is_virtual_endpoint_gateway_ip_test.go +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_ip_test.go @@ -1,12 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,15 +21,15 @@ func TestAccIBMISVirtualEndpointGatewayIP_Basic(t *testing.T) { var endpointGateway string name := "ibm_is_virtual_endpoint_gateway.virtual_endpoint_gateway" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, // No requirement for CheckDestory of this resource as by reaching this point it must have already been deleted from CIS. Steps: []resource.TestStep{ { Config: testAccCheckisVirtualEndpointGatewayIPConfigBasic(), Check: resource.ComposeTestCheckFunc( testAccCheckisVirtualEndpointGatewayIPExists(name, &endpointGateway), - resource.TestCheckResourceAttr(name, "reserved_ip_id", subnetID), + resource.TestCheckResourceAttr(name, "reserved_ip_id", acc.SubnetID), ), }, }, @@ -36,14 +40,14 @@ func TestAccIBMISVirtualEndpointGatewayIP_import(t *testing.T) { name := "ibm_is_virtual_endpoint_gateway.virtual_endpoint_gateway" t.Skip() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckisVirtualEndpointGatewayIPDestroy, Steps: []resource.TestStep{ { Config: testAccCheckisVirtualEndpointGatewayIPConfigBasic(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(name, "ip_id", subnetID), + resource.TestCheckResourceAttr(name, "ip_id", acc.SubnetID), ), }, { @@ -61,8 +65,8 @@ func TestAccIBMISVirtualEndpointGatewayIP_CreateAfterManualDestroy(t *testing.T) t.Skip() resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckisVirtualEndpointGatewayIPDestroy, Steps: []resource.TestStep{ { @@ -91,12 +95,12 @@ func TestAccIBMISVirtualEndpointGatewayIP_CreateAfterManualDestroy(t *testing.T) func testAccisVirtualEndpointGatewayIPManuallyDelete(tfEndpointGwIPID *string) resource.TestCheckFunc { return func(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } tfEndpointGwIP := *tfEndpointGwIPID - parts, err := idParts(tfEndpointGwIP) + parts, err := flex.IdParts(tfEndpointGwIP) if err != nil { return err } @@ -112,7 +116,7 @@ func testAccisVirtualEndpointGatewayIPManuallyDelete(tfEndpointGwIPID *string) r } func testAccCheckisVirtualEndpointGatewayIPDestroy(s *terraform.State) error { - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } @@ -120,7 +124,7 @@ func testAccCheckisVirtualEndpointGatewayIPDestroy(s *terraform.State) error { if rs.Type != "ibm_is_virtual_endpoint_gateway" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -143,15 +147,15 @@ func testAccCheckisVirtualEndpointGatewayIPExists(n string, tfEndpointGwIPID *st return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No endpoint gateway ID is set") + return fmt.Errorf("[ERROR] No endpoint gateway ID is set") } - sess, err := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() if err != nil { return err } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -176,5 +180,5 @@ func testAccCheckisVirtualEndpointGatewayIPConfigBasic() string { gateway = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id reserved_ip = "%[1]s" } - `, subnetID) + `, acc.SubnetID) } diff --git a/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go new file mode 100644 index 000000000..17c425dc3 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway_test.go @@ -0,0 +1,317 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISVirtualEndpointGateway_Basic(t *testing.T) { + var endpointGateway string + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &endpointGateway), + resource.TestCheckResourceAttr(name, "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISVirtualEndpointGateway_CharacterCount(t *testing.T) { + var endpointGateway string + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d-%s", acctest.RandIntRange(10, 100), acctest.RandString(38)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &endpointGateway), + resource.TestCheckResourceAttr(name, "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISVirtualEndpointGateway_Basic_SecurityGroups(t *testing.T) { + var endpointGateway string + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + sgname1 := fmt.Sprintf("tfsg-createname-%d", acctest.RandIntRange(10, 100)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasicSecurityGroups(vpcname1, subnetname1, sgname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &endpointGateway), + resource.TestCheckResourceAttr(name, "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISVirtualEndpointGateway_Import(t *testing.T) { + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", name1), + ), + }, + { + ResourceName: name, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIBMISVirtualEndpointGateway_FullySpecified(t *testing.T) { + var monitor string + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, + Steps: []resource.TestStep{ + { + ExpectNonEmptyPlan: true, + Config: testAccCheckisVirtualEndpointGatewayConfigFullySpecified(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &monitor), + resource.TestCheckResourceAttr(name, "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISVirtualEndpointGateway_CreateAfterManualDestroy(t *testing.T) { + t.Skip() + var monitorOne, monitorTwo string + vpcname1 := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + name := "ibm_is_virtual_endpoint_gateway.endpoint_gateway" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckisVirtualEndpointGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &monitorOne), + testAccisVirtualEndpointGatewayManuallyDelete(&monitorOne), + ), + }, + { + Config: testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckisVirtualEndpointGatewayExists(name, &monitorTwo), + func(state *terraform.State) error { + if monitorOne == monitorTwo { + return fmt.Errorf("load balancer monitor id is unchanged even after we thought we deleted it ( %s )", + monitorTwo) + } + return nil + }, + ), + }, + }, + }) +} + +func testAccisVirtualEndpointGatewayManuallyDelete(tfEndpointGwID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + tfEndpointGw := *tfEndpointGwID + opt := sess.NewDeleteEndpointGatewayOptions(tfEndpointGw) + response, err := sess.DeleteEndpointGateway(opt) + if err != nil { + return fmt.Errorf("Delete Endpoint Gateway failed: %v", response) + } + return nil + } +} + +func testAccCheckisVirtualEndpointGatewayDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_virtual_endpoint_gateway" { + continue + } + opt := sess.NewGetEndpointGatewayOptions(rs.Primary.ID) + _, response, err := sess.GetEndpointGateway(opt) + if err == nil { + return fmt.Errorf("Endpoint Gateway still exists: %v", response) + } + } + + return nil +} + +func testAccCheckisVirtualEndpointGatewayExists(n string, tfEndpointGwID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No endpoint gateway ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + opt := sess.NewGetEndpointGatewayOptions(rs.Primary.ID) + result, response, err := sess.GetEndpointGateway(opt) + if err != nil { + return fmt.Errorf("Endpoint Gateway does not exist: %s", response) + } + *tfEndpointGwID = *result.ID + return nil + } +} + +func testAccCheckisVirtualEndpointGatewayConfigBasic(vpcname1, subnetname1, name1 string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default=true + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%[1]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%[2]s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%[3]s" + ipv4_cidr_block = "%[4]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { + name = "%[5]s" + target { + name = "ibm-dns-server2" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.testacc_vpc.id + resource_group = data.ibm_resource_group.test_acc.id + }`, vpcname1, subnetname1, acc.ISZoneName, acc.ISCIDR, name1) +} + +func testAccCheckisVirtualEndpointGatewayConfigFullySpecified(vpcname1, subnetname1, name1 string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default=true + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%[1]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%[2]s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%[3]s" + ipv4_cidr_block = "%[4]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { + name = "%[5]s" + target { + name = "ibm-dns-server2" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.testacc_vpc.id + ips { + subnet = ibm_is_subnet.testacc_subnet.id + name = "test-reserved-ip1" + } + resource_group = data.ibm_resource_group.test_acc.id + }`, vpcname1, subnetname1, acc.ISZoneName, acc.ISCIDR, name1) +} + +func testAccCheckisVirtualEndpointGatewayConfigBasicSecurityGroups(vpcname1, subnetname1, sgname1, name1 string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "test_acc" { + is_default=true + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%[1]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%[2]s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%[3]s" + ipv4_cidr_block = "%[4]s" + resource_group = data.ibm_resource_group.test_acc.id + } + resource "ibm_is_security_group" "testacc_security_group" { + name = "%[5]s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { + name = "%[6]s" + target { + name = "ibm-dns-server2" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.testacc_vpc.id + resource_group = data.ibm_resource_group.test_acc.id + security_groups = [ibm_is_security_group.testacc_security_group.id] + }`, vpcname1, subnetname1, acc.ISZoneName, acc.ISCIDR, sgname1, name1) +} diff --git a/ibm/service/vpc/resource_ibm_is_volume.go b/ibm/service/vpc/resource_ibm_is_volume.go new file mode 100644 index 000000000..69f16ce0e --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_volume.go @@ -0,0 +1,832 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isVolumeName = "name" + isVolumeProfileName = "profile" + isVolumeZone = "zone" + isVolumeEncryptionKey = "encryption_key" + isVolumeEncryptionType = "encryption_type" + isVolumeCapacity = "capacity" + isVolumeIops = "iops" + isVolumeCrn = "crn" + isVolumeTags = "tags" + isVolumeStatus = "status" + isVolumeStatusReasons = "status_reasons" + isVolumeStatusReasonsCode = "code" + isVolumeStatusReasonsMessage = "message" + isVolumeStatusReasonsMoreInfo = "more_info" + isVolumeDeleting = "deleting" + isVolumeDeleted = "done" + isVolumeProvisioning = "provisioning" + isVolumeProvisioningDone = "done" + isVolumeResourceGroup = "resource_group" + isVolumeSourceSnapshot = "source_snapshot" + isVolumeDeleteAllSnapshots = "delete_all_snapshots" + isVolumeBandwidth = "bandwidth" +) + +func ResourceIBMISVolume() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISVolumeCreate, + Read: resourceIBMISVolumeRead, + Update: resourceIBMISVolumeUpdate, + Delete: resourceIBMISVolumeDelete, + Exists: resourceIBMISVolumeExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceVolumeValidate(diff) + }), + ), + + Schema: map[string]*schema.Schema{ + + isVolumeName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeName), + Description: "Volume name", + }, + + isVolumeProfileName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeProfileName), + Description: "Volume profile name", + }, + + isVolumeZone: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Zone name", + }, + + isVolumeEncryptionKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Volume encryption key info", + }, + + isVolumeEncryptionType: { + Type: schema.TypeString, + Computed: true, + Description: "Volume encryption type info", + }, + + isVolumeCapacity: { + Type: schema.TypeInt, + Optional: true, + Default: 100, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeCapacity), + Description: "Volume capacity value", + }, + isVolumeResourceGroup: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Resource group name", + }, + isVolumeIops: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeIops), + Description: "IOPS value for the Volume", + }, + isVolumeCrn: { + Type: schema.TypeString, + Computed: true, + Description: "CRN value for the volume instance", + }, + isVolumeStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Volume status", + }, + + isVolumeStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isVolumeStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isVolumeStatusReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about this status reason", + }, + }, + }, + }, + + isVolumeSourceSnapshot: { + Type: schema.TypeString, + Computed: true, + Description: "Identifier of the snapshot from which this volume was cloned", + }, + isVolumeDeleteAllSnapshots: { + Type: schema.TypeBool, + Optional: true, + Description: "Deletes all snapshots created from this volume", + }, + isVolumeTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + isVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum bandwidth (in megabits per second) for the volume", + }, + }, + } +} + +func ResourceIBMISVolumeValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeProfileName, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "general-purpose, 5iops-tier, 10iops-tier, custom", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeCapacity, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + MinValue: "10", + MaxValue: "16000"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeIops, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + MinValue: "100", + MaxValue: "48000"}) + + ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} + return &ibmISVolumeResourceValidator +} + +func resourceIBMISVolumeCreate(d *schema.ResourceData, meta interface{}) error { + + volName := d.Get(isVolumeName).(string) + profile := d.Get(isVolumeProfileName).(string) + zone := d.Get(isVolumeZone).(string) + var volCapacity int64 + if capacity, ok := d.GetOk(isVolumeCapacity); ok { + volCapacity = int64(capacity.(int)) + } else { + volCapacity = 100 + } + + err := volCreate(d, meta, volName, profile, zone, volCapacity) + if err != nil { + return err + } + + return resourceIBMISVolumeRead(d, meta) +} + +func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone string, volCapacity int64) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.CreateVolumeOptions{ + VolumePrototype: &vpcv1.VolumePrototype{ + Name: &volName, + Capacity: &volCapacity, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profile, + }, + }, + } + volTemplate := options.VolumePrototype.(*vpcv1.VolumePrototype) + + if key, ok := d.GetOk(isVolumeEncryptionKey); ok { + encryptionKey := key.(string) + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionKey, + } + } + + if rgrp, ok := d.GetOk(isVolumeResourceGroup); ok { + rg := rgrp.(string) + volTemplate.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + if i, ok := d.GetOk(isVolumeIops); ok { + iops := int64(i.(int)) + volTemplate.Iops = &iops + } + + var userTags *schema.Set + if v, ok := d.GetOk(isVolumeTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volTemplate.UserTags = userTagsArray + } + } + + vol, response, err := sess.CreateVolume(options) + if err != nil { + return fmt.Errorf("[DEBUG] Create volume err %s\n%s", err, response) + } + d.SetId(*vol.ID) + log.Printf("[INFO] Volume : %s", *vol.ID) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + return nil +} + +func resourceIBMISVolumeRead(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + err := volGet(d, meta, id) + if err != nil { + return err + } + return nil +} + +func volGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := sess.GetVolume(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + } + d.SetId(*vol.ID) + d.Set(isVolumeName, *vol.Name) + d.Set(isVolumeProfileName, *vol.Profile.Name) + d.Set(isVolumeZone, *vol.Zone.Name) + if vol.EncryptionKey != nil { + d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) + } + if vol.Encryption != nil { + d.Set(isVolumeEncryptionType, vol.Encryption) + } + d.Set(isVolumeIops, *vol.Iops) + d.Set(isVolumeCapacity, *vol.Capacity) + d.Set(isVolumeCrn, *vol.CRN) + if vol.SourceSnapshot != nil { + d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) + } + d.Set(isVolumeStatus, *vol.Status) + d.Set(isVolumeBandwidth, int(*vol.Bandwidth)) + //set the status reasons + if vol.StatusReasons != nil { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range vol.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isVolumeStatusReasonsCode] = *sr.Code + currentSR[isVolumeStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isVolumeStatusReasonsMoreInfo] = *sr.Message + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isVolumeStatusReasons, statusReasonsList) + } + if vol.UserTags != nil { + if err = d.Set(isVolumeTags, vol.UserTags); err != nil { + return fmt.Errorf("Error setting user tags: %s", err) + } + } + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") + d.Set(flex.ResourceName, *vol.Name) + d.Set(flex.ResourceCRN, *vol.CRN) + d.Set(flex.ResourceStatus, *vol.Status) + if vol.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, vol.ResourceGroup.Name) + d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) + } + return nil +} + +func resourceIBMISVolumeUpdate(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + name := "" + hasNameChanged := false + delete := false + + if delete_all_snapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && delete_all_snapshots.(bool) { + delete = true + } + + if d.HasChange(isVolumeName) { + name = d.Get(isVolumeName).(string) + hasNameChanged = true + } + + err := volUpdate(d, meta, id, name, hasNameChanged, delete) + if err != nil { + return err + } + return resourceIBMISVolumeRead(d, meta) +} + +func volUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasNameChanged, delete bool) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + var capacity int64 + if delete { + deleteAllSnapshots(sess, id) + } + + optionsget := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(optionsget) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error getting Volume (%s): %s\n%s", id, err, response) + } + eTag := response.Headers.Get("ETag") + options := &vpcv1.UpdateVolumeOptions{ + ID: &id, + } + options.IfMatch = &eTag + + //name update + volumeNamePatchModel := &vpcv1.VolumePatch{} + if hasNameChanged { + volumeNamePatchModel.Name = &name + volumeNamePatch, err := volumeNamePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch: %s", err) + } + options.VolumePatch = volumeNamePatch + _, _, err = sess.UpdateVolume(options) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // profile/ iops update + if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) { + volumeProfilePatchModel := &vpcv1.VolumePatch{} + volId := d.Id() + getvoloptions := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + vol, response, err := sess.GetVolume(getvoloptions) + if err != nil || vol == nil { + return fmt.Errorf("[ERROR] Error retrieving Volume (%s) details: %s\n%s", volId, err, response) + } + if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) < 1 { + return fmt.Errorf("[ERROR] Error updating Volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) + } + volAtt := &vol.VolumeAttachments[0] + insId := *volAtt.Instance.ID + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &insId, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + } + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &insId, + Type: &actiontype, + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + } + _, err = isWaitForInstanceAvailable(sess, insId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + if d.HasChange(isVolumeProfileName) { + profile := d.Get(isVolumeProfileName).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + } else if d.HasChange(isVolumeIops) { + profile := d.Get(isVolumeProfileName).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + iops := int64(d.Get(isVolumeIops).(int)) + volumeProfilePatchModel.Iops = &iops + } + + volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for VolumeProfilePatch: %s", err) + } + options.VolumePatch = volumeProfilePatch + _, response, err = sess.UpdateVolume(options) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // capacity update + if d.HasChange(isVolumeCapacity) { + id := d.Id() + getvolumeoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := sess.GetVolume(getvolumeoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Volume (%s): %s\n%s", id, err, response) + } + if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].ID == "" { + return fmt.Errorf("[ERROR] Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) + } + insId := vol.VolumeAttachments[0].Instance.ID + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: insId, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) : %s\n%s", *insId, err, response) + } + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: insId, + Type: &actiontype, + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", *insId, err, response) + } + _, err = isWaitForInstanceAvailable(sess, *insId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + capacity = int64(d.Get(isVolumeCapacity).(int)) + volumeCapacityPatchModel := &vpcv1.VolumePatch{} + volumeCapacityPatchModel.Capacity = &capacity + + volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatch: %s", err) + } + options.VolumePatch = volumeCapacityPatch + _, response, err = sess.UpdateVolume(options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vpc volume: %s\n%s", err, response) + } + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // user tags update + if d.HasChange(isVolumeTags) { + var userTags *schema.Set + if v, ok := d.GetOk(isVolumeTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volumeNamePatchModel := &vpcv1.VolumePatch{} + volumeNamePatchModel.UserTags = userTagsArray + volumeNamePatch, err := volumeNamePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("Error calling asPatch for volumeNamePatch: %s", err) + } + options.IfMatch = &eTag + options.VolumePatch = volumeNamePatch + _, response, err := sess.UpdateVolume(options) + if err != nil { + return fmt.Errorf("Error updating volume : %s\n%s", err, response) + } + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + } + } + + return nil +} + +func resourceIBMISVolumeDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + err := volDelete(d, meta, id) + if err != nil { + return err + } + return nil +} + +func volDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getvoloptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + volDetails, response, err := sess.GetVolume(getvoloptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + } + + if volDetails.VolumeAttachments != nil { + for _, volAtt := range volDetails.VolumeAttachments { + deleteVolumeAttachment := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: volAtt.Instance.ID, + ID: volAtt.ID, + } + _, err := sess.DeleteInstanceVolumeAttachment(deleteVolumeAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing volume attachment %q for instance %s: %q", *volAtt.ID, *volAtt.Instance.ID, err) + } + _, err = isWaitForInstanceVolumeDetached(sess, d, d.Id(), *volAtt.ID) + if err != nil { + return err + } + + } + } + + options := &vpcv1.DeleteVolumeOptions{ + ID: &id, + } + response, err = sess.DeleteVolume(options) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) + } + _, err = isWaitForVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVolumeDeleting}, + Target: []string{"done", ""}, + Refresh: isVolumeDeleteRefreshFunc(vol, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + volgetoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := vol.GetVolume(volgetoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return vol, isVolumeDeleted, nil + } + return vol, "", fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + } + return vol, isVolumeDeleting, err + } +} + +func resourceIBMISVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + id := d.Id() + + exists, err := volExists(d, meta, id) + return exists, err +} + +func volExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + options := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + } + return true, nil +} + +func isWaitForVolumeAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVolumeProvisioning}, + Target: []string{isVolumeProvisioningDone, ""}, + Refresh: isVolumeRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + volgetoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := client.GetVolume(volgetoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting volume: %s\n%s", err, response) + } + + if *vol.Status == "available" { + return vol, isVolumeProvisioningDone, nil + } + + return vol, isVolumeProvisioning, nil + } +} + +func deleteAllSnapshots(sess *vpcv1.VpcV1, id string) error { + delete_all_snapshots := new(vpcv1.DeleteSnapshotsOptions) + delete_all_snapshots.SourceVolumeID = &id + response, err := sess.DeleteSnapshots(delete_all_snapshots) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting snapshots from volume %s\n%s", err, response) + } + return nil +} diff --git a/ibm/resource_ibm_is_volume_test.go b/ibm/service/vpc/resource_ibm_is_volume_test.go similarity index 81% rename from ibm/resource_ibm_is_volume_test.go rename to ibm/service/vpc/resource_ibm_is_volume_test.go index 2029b3de8..831830587 100644 --- a/ibm/resource_ibm_is_volume_test.go +++ b/ibm/service/vpc/resource_ibm_is_volume_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" @@ -9,6 +9,9 @@ import ( "strings" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -21,11 +24,11 @@ func TestAccIBMISVolume_basic(t *testing.T) { name1 := fmt.Sprintf("tf-vol-upd-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISVolumeConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), @@ -34,7 +37,7 @@ func TestAccIBMISVolume_basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccCheckIBMISVolumeConfig(name1), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), @@ -46,6 +49,48 @@ func TestAccIBMISVolume_basic(t *testing.T) { }) } +func TestAccIBMISVolumeUsertag_basic(t *testing.T) { + var vol string + name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) + tagnameupdate := fmt.Sprintf("tfusertagupd%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISVolumeUsertagConfig(name, tagname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "tags.0", tagname), + ), + }, + + resource.TestStep{ + Config: testAccCheckIBMISVolumeUsertagConfig(name, tagnameupdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "tags.0", tagnameupdate), + ), + }, + }, + }) +} + func TestAccIBMISVolumeUpdateCustom_basic(t *testing.T) { var vol string vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) @@ -60,8 +105,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE iops2 := int64(900) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ { @@ -103,8 +148,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE profileName2 := "5iops-tier" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ { @@ -146,8 +191,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE capacity2 := int64(120) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ { @@ -187,11 +232,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE `) sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, initialVolumeCapacityArray), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), @@ -204,7 +249,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE ), }, - resource.TestStep{ + { Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, finalVolumeCapacityArray), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), @@ -222,7 +267,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE func testAccCheckIBMISVolumeDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_vol" { continue @@ -234,7 +279,7 @@ func testAccCheckIBMISVolumeDestroy(s *terraform.State) error { _, _, err := sess.GetVolume(getvolumeoptions) if err == nil { - return fmt.Errorf("Volume still exists: %s", rs.Primary.ID) + return fmt.Errorf("[ERROR] Volume still exists: %s", rs.Primary.ID) } } @@ -253,7 +298,7 @@ func testAccCheckIBMISVolumeExists(n, volID string) resource.TestCheckFunc { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getvolumeoptions := &vpcv1.GetVolumeOptions{ ID: &rs.Primary.ID, } @@ -316,7 +361,7 @@ func testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey keys = [ibm_is_ssh_key.testacc_sshkey.id] } -`, vpcname, subnetname, ISZoneName, sshname, publicKey, volName, ISZoneName, iops, name, isImage, instanceProfileName, ISZoneName) +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, iops, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } @@ -356,7 +401,7 @@ func testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, keys = [ibm_is_ssh_key.testacc_sshkey.id] } -`, vpcname, subnetname, ISZoneName, sshname, publicKey, volName, profileName, ISZoneName, name, isImage, instanceProfileName, ISZoneName) +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, profileName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } @@ -404,7 +449,7 @@ func testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, zone = "%s" keys = [ibm_is_ssh_key.testacc_sshkey.id] } -`, capacityArray, ISZoneName, vpcname, subnetname, ISZoneName, sshname, publicKey, insname, isImage, instanceProfileName, ISZoneName) +`, capacityArray, acc.ISZoneName, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } @@ -445,6 +490,20 @@ func testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicK keys = [ibm_is_ssh_key.testacc_sshkey.id] } -`, vpcname, subnetname, ISZoneName, sshname, publicKey, volName, ISZoneName, capacity, name, isImage, instanceProfileName, ISZoneName) +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, capacity, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + +} + +func testAccCheckIBMISVolumeUsertagConfig(name, usertag string) string { + return fmt.Sprintf( + ` + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "10iops-tier" + zone = "us-south-1" + # capacity= 200 + tags = ["%s"] + } +`, name, usertag) } diff --git a/ibm/resource_ibm_is_vpc.go b/ibm/service/vpc/resource_ibm_is_vpc.go similarity index 86% rename from ibm/resource_ibm_is_vpc.go rename to ibm/service/vpc/resource_ibm_is_vpc.go index b9e377424..a9cd031aa 100644 --- a/ibm/resource_ibm_is_vpc.go +++ b/ibm/service/vpc/resource_ibm_is_vpc.go @@ -1,16 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( - "bytes" "context" "fmt" "log" "os" "reflect" - "strings" "time" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -18,7 +16,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/internal/hashcode" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" ) const ( @@ -61,7 +60,7 @@ const ( isVPCSecurityGroupID = "group_id" ) -func resourceIBMISVPC() *schema.Resource { +func ResourceIBMISVPC() *schema.Resource { return &schema.Resource{ Create: resourceIBMISVPCCreate, Read: resourceIBMISVPCRead, @@ -77,7 +76,7 @@ func resourceIBMISVPC() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -88,17 +87,14 @@ func resourceIBMISVPC() *schema.Resource { Default: "auto", DiffSuppressFunc: suppressNullAddPrefix, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_vpc", isVPCAddressPrefixManagement), + ValidateFunc: validate.InvokeValidator("ibm_is_vpc", isVPCAddressPrefixManagement), Description: "Address Prefix management value", }, isVPCDefaultNetworkACL: { Type: schema.TypeString, - Optional: true, - Default: nil, Computed: true, - Deprecated: "This field is deprecated", - Description: "Default network ACL", + Description: "Default network ACL ID", }, isVPCDefaultRoutingTable: { @@ -119,7 +115,7 @@ func resourceIBMISVPC() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_vpc", isVPCName), + ValidateFunc: validate.InvokeValidator("ibm_is_vpc", isVPCName), Description: "VPC name", }, @@ -127,7 +123,7 @@ func resourceIBMISVPC() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_vpc", isVPCDefaultNetworkACLName), + ValidateFunc: validate.InvokeValidator("ibm_is_vpc", isVPCDefaultNetworkACLName), Description: "Default Network ACL name", }, @@ -135,7 +131,7 @@ func resourceIBMISVPC() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_vpc", isVPCDefaultSecurityGroupName), + ValidateFunc: validate.InvokeValidator("ibm_is_vpc", isVPCDefaultSecurityGroupName), Description: "Default security group name", }, @@ -155,7 +151,7 @@ func resourceIBMISVPC() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: InvokeValidator("ibm_is_vpc", isVPCDefaultRoutingTableName), + ValidateFunc: validate.InvokeValidator("ibm_is_vpc", isVPCDefaultRoutingTableName), Description: "Default routing table name", }, @@ -182,8 +178,8 @@ func resourceIBMISVPC() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_vpc", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_vpc", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "List of tags", }, @@ -193,30 +189,30 @@ func resourceIBMISVPC() *schema.Resource { Description: "The crn of the resource", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -368,67 +364,67 @@ func resourceIBMISVPC() *schema.Resource { } } -func resourceIBMISVPCValidator() *ResourceValidator { +func ResourceIBMISVPCValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) address_prefix_management := "auto, manual" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCAddressPrefixManagement, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, Default: "auto", AllowedValues: address_prefix_management}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCDefaultNetworkACLName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCDefaultSecurityGroupName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCDefaultRoutingTableName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISVPCResourceValidator := ResourceValidator{ResourceName: "ibm_is_vpc", Schema: validateSchema} + ibmISVPCResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpc", Schema: validateSchema} return &ibmISVPCResourceValidator } @@ -477,7 +473,7 @@ func vpcCreate(d *schema.ResourceData, meta interface{}, name, apm, rg string, i vpc, response, err := sess.CreateVPC(options) if err != nil { - return fmt.Errorf("Error while creating VPC %s ", beautifyError(err, response)) + return fmt.Errorf("[ERROR] Error while creating VPC %s ", flex.BeautifyError(err, response)) } d.SetId(*vpc.ID) @@ -501,7 +497,7 @@ func vpcCreate(d *schema.ResourceData, meta interface{}, name, apm, rg string, i v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isVPCTags); ok || v != "" { oldList, newList := d.GetChange(isVPCTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vpc.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *vpc.CRN) if err != nil { log.Printf( "Error on create of resource vpc (%s) tags: %s", d.Id(), err) @@ -532,7 +528,7 @@ func isVPCRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { } vpc, response, err := vpc.GetVPC(getvpcOptions) if err != nil { - return nil, isVPCFailed, fmt.Errorf("Error getting VPC : %s\n%s", err, response) + return nil, isVPCFailed, fmt.Errorf("[ERROR] Error getting VPC : %s\n%s", err, response) } if *vpc.Status == isVPCAvailable || *vpc.Status == isVPCFailed { @@ -566,7 +562,7 @@ func vpcGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error getting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting VPC : %s\n%s", err, response) } d.Set(isVPCName, *vpc.Name) @@ -592,24 +588,24 @@ func vpcGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isVPCDefaultRoutingTable, *vpc.DefaultRoutingTable.ID) d.Set(isVPCDefaultRoutingTableName, *vpc.DefaultRoutingTable.Name) } - tags, err := GetTagsUsingCRN(meta, *vpc.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *vpc.CRN) if err != nil { log.Printf( "Error on get of resource vpc (%s) tags: %s", d.Id(), err) } d.Set(isVPCTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } d.Set(isVPCCRN, *vpc.CRN) - d.Set(ResourceControllerURL, controller+"/vpc-ext/network/vpcs") - d.Set(ResourceName, *vpc.Name) - d.Set(ResourceCRN, *vpc.CRN) - d.Set(ResourceStatus, *vpc.Status) + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/network/vpcs") + d.Set(flex.ResourceName, *vpc.Name) + d.Set(flex.ResourceCRN, *vpc.CRN) + d.Set(flex.ResourceStatus, *vpc.Status) if vpc.ResourceGroup != nil { d.Set(isVPCResourceGroup, *vpc.ResourceGroup.ID) - d.Set(ResourceGroupName, *vpc.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *vpc.ResourceGroup.Name) } //set the cse ip addresses info if vpc.CseSourceIps != nil { @@ -634,9 +630,9 @@ func vpcGet(d *schema.ResourceData, meta interface{}, id string) error { } s, response, err := sess.ListSubnets(options) if err != nil { - return fmt.Errorf("Error Fetching subnets %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Fetching subnets %s\n%s", err, response) } - start = GetNext(s.Next) + start = flex.GetNext(s.Next) allrecs = append(allrecs, s.Subnets...) if start == "" { break @@ -808,10 +804,10 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } vpc, response, err := sess.GetVPC(getvpcOptions) if err != nil { - return fmt.Errorf("Error getting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting VPC : %s\n%s", err, response) } oldList, newList := d.GetChange(isVPCTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vpc.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *vpc.CRN) if err != nil { log.Printf( "Error on update of resource vpc (%s) tags: %s", d.Id(), err) @@ -843,12 +839,12 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } vpcPatch, err := vpcPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for VPCPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for VPCPatch: %s", err) } updateVpcOptions.VPCPatch = vpcPatch _, response, err := sess.UpdateVPC(updateVpcOptions) if err != nil { - return fmt.Errorf("Error Updating VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating VPC : %s\n%s", err, response) } } return nil @@ -879,7 +875,7 @@ func vpcDelete(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting VPC (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting VPC (%s): %s\n%s", id, err, response) } deletevpcOptions := &vpcv1.DeleteVPCOptions{ @@ -887,7 +883,7 @@ func vpcDelete(d *schema.ResourceData, meta interface{}, id string) error { } response, err = sess.DeleteVPC(deletevpcOptions) if err != nil { - return fmt.Errorf("Error Deleting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting VPC : %s\n%s", err, response) } _, err = isWaitForVPCDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -914,7 +910,7 @@ func isWaitForVPCDeleted(vpc *vpcv1.VpcV1, id string, timeout time.Duration) (in func isVPCDeleteRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - log.Printf("[DEBUG] delete function here") + log.Printf("[DEBUG] is vpc delete function here") getvpcOptions := &vpcv1.GetVPCOptions{ ID: &id, } @@ -923,7 +919,7 @@ func isVPCDeleteRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRefreshFu if response != nil && response.StatusCode == 404 { return vpc, isVPCDeleted, nil } - return nil, isVPCFailed, fmt.Errorf("The VPC %s failed to delete: %s\n%s", id, err, response) + return nil, isVPCFailed, fmt.Errorf("[ERROR] The VPC %s failed to delete: %s\n%s", id, err, response) } return vpc, isVPCDeleting, nil @@ -949,17 +945,17 @@ func vpcExists(d *schema.ResourceData, meta interface{}, id string) (bool, error if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting VPC: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting VPC: %s\n%s", err, response) } return true, nil } -func resourceIBMVPCHash(v interface{}) int { - var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("%s", - strings.ToLower(v.(string)))) - return hashcode.String(buf.String()) -} +// func ResourceIBMVPCHash(v interface{}) int { +// var buf bytes.Buffer +// buf.WriteString(fmt.Sprintf("%s", +// strings.ToLower(v.(string)))) +// return conns.String(buf.String()) +// } func nwaclNameUpdate(sess *vpcv1.VpcV1, id, name string) error { updateNetworkACLOptions := &vpcv1.UpdateNetworkACLOptions{ @@ -970,12 +966,12 @@ func nwaclNameUpdate(sess *vpcv1.VpcV1, id, name string) error { } networkACLPatch, err := networkACLPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for NetworkACLPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for NetworkACLPatch: %s", err) } updateNetworkACLOptions.NetworkACLPatch = networkACLPatch _, response, err := sess.UpdateNetworkACL(updateNetworkACLOptions) if err != nil { - return fmt.Errorf("Error Updating Network ACL(%s) name : %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Updating Network ACL(%s) name : %s\n%s", id, err, response) } return nil } @@ -989,12 +985,12 @@ func sgNameUpdate(sess *vpcv1.VpcV1, id, name string) error { } securityGroupPatch, err := securityGroupPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for SecurityGroupPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for SecurityGroupPatch: %s", err) } updateSecurityGroupOptions.SecurityGroupPatch = securityGroupPatch _, response, err := sess.UpdateSecurityGroup(updateSecurityGroupOptions) if err != nil { - return fmt.Errorf("Error Updating Security Group name : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Security Group name : %s\n%s", err, response) } return nil } @@ -1007,12 +1003,12 @@ func rtNameUpdate(sess *vpcv1.VpcV1, vpcID, id, name string) error { routingTablePatchModel.Name = &name routingTablePatchModelAsPatch, asPatchErr := routingTablePatchModel.AsPatch() if asPatchErr != nil { - return fmt.Errorf("Error calling asPatch for RoutingTablePatchModel: %s", asPatchErr) + return fmt.Errorf("[ERROR] Error calling asPatch for RoutingTablePatchModel: %s", asPatchErr) } updateVpcRoutingTableOptions.RoutingTablePatch = routingTablePatchModelAsPatch _, response, err := sess.UpdateVPCRoutingTable(updateVpcRoutingTableOptions) if err != nil { - return fmt.Errorf("Error Updating Routing table name %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating Routing table name %s\n%s", err, response) } return nil } diff --git a/ibm/resource_ibm_is_vpc_address_prefix.go b/ibm/service/vpc/resource_ibm_is_vpc_address_prefix.go similarity index 75% rename from ibm/resource_ibm_is_vpc_address_prefix.go rename to ibm/service/vpc/resource_ibm_is_vpc_address_prefix.go index f24026b97..c9a1348cc 100644 --- a/ibm/resource_ibm_is_vpc_address_prefix.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_address_prefix.go @@ -1,11 +1,14 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -17,9 +20,10 @@ const ( isVPCAddressPrefixVPCID = "vpc" isVPCAddressPrefixHasSubnets = "has_subnets" isVPCAddressPrefixDefault = "is_default" + isAddressPrefix = "address_prefix" ) -func resourceIBMISVpcAddressPrefix() *schema.Resource { +func ResourceIBMISVpcAddressPrefix() *schema.Resource { return &schema.Resource{ Create: resourceIBMISVpcAddressPrefixCreate, Read: resourceIBMISVpcAddressPrefixRead, @@ -33,7 +37,7 @@ func resourceIBMISVpcAddressPrefix() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_address_prefix", isVPCAddressPrefixPrefixName), + ValidateFunc: validate.InvokeValidator("ibm_is_address_prefix", isVPCAddressPrefixPrefixName), Description: "Name", }, isVPCAddressPrefixZoneName: { @@ -47,7 +51,7 @@ func resourceIBMISVpcAddressPrefix() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_address_prefix", isVPCAddressPrefixCIDR), + ValidateFunc: validate.InvokeValidator("ibm_is_address_prefix", isVPCAddressPrefixCIDR), Description: "CIDIR address prefix", }, isVPCAddressPrefixDefault: { @@ -70,43 +74,49 @@ func resourceIBMISVpcAddressPrefix() *schema.Resource { Description: "Boolean value, set to true if VPC instance have subnets", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the VPC resource", }, + + isAddressPrefix: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier of the address prefix", + }, }, } } -func resourceIBMISAddressPrefixValidator() *ResourceValidator { +func ResourceIBMISAddressPrefixValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCAddressPrefixPrefixName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCRouteDestinationCIDR, - ValidateFunctionIdentifier: ValidateCIDRAddress, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateCIDRAddress, + Type: validate.TypeString, ForceNew: true, Required: true}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCAddressPrefixCIDR, - ValidateFunctionIdentifier: ValidateOverlappingAddress, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateOverlappingAddress, + Type: validate.TypeString, ForceNew: true, Required: true}) - ibmISAddressPrefixResourceValidator := ResourceValidator{ResourceName: "ibm_is_address_prefix", Schema: validateSchema} + ibmISAddressPrefixResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_address_prefix", Schema: validateSchema} return &ibmISAddressPrefixResourceValidator } @@ -122,8 +132,8 @@ func resourceIBMISVpcAddressPrefixCreate(d *schema.ResourceData, meta interface{ } isVPCAddressPrefixKey := "vpc_address_prefix_key_" + vpcID - ibmMutexKV.Lock(isVPCAddressPrefixKey) - defer ibmMutexKV.Unlock(isVPCAddressPrefixKey) + conns.IbmMutexKV.Lock(isVPCAddressPrefixKey) + defer conns.IbmMutexKV.Unlock(isVPCAddressPrefixKey) err := vpcAddressPrefixCreate(d, meta, prefixName, zoneName, cidr, vpcID, isDefault) if err != nil { @@ -148,16 +158,17 @@ func vpcAddressPrefixCreate(d *schema.ResourceData, meta interface{}, name, zone } addrPrefix, response, err := sess.CreateVPCAddressPrefix(options) if err != nil { - return fmt.Errorf("Error while creating VPC Address Prefix %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating VPC Address Prefix %s\n%s", err, response) } addrPrefixID := *addrPrefix.ID d.SetId(fmt.Sprintf("%s/%s", vpcID, addrPrefixID)) + d.Set(isAddressPrefix, addrPrefixID) return nil } func resourceIBMISVpcAddressPrefixRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -187,7 +198,7 @@ func vpcAddressPrefixGet(d *schema.ResourceData, meta interface{}, vpcID, addrPr d.SetId("") return nil } - return fmt.Errorf("Error Getting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) + return fmt.Errorf("[ERROR] Error Getting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) } d.Set(isVPCAddressPrefixVPCID, vpcID) d.Set(isVPCAddressPrefixDefault, *addrPrefix.IsDefault) @@ -197,14 +208,15 @@ func vpcAddressPrefixGet(d *schema.ResourceData, meta interface{}, vpcID, addrPr } d.Set(isVPCAddressPrefixCIDR, *addrPrefix.CIDR) d.Set(isVPCAddressPrefixHasSubnets, *addrPrefix.HasSubnets) + d.Set(isAddressPrefix, addrPrefixID) getVPCOptions := &vpcv1.GetVPCOptions{ ID: &vpcID, } vpc, response, err := sess.GetVPC(getVPCOptions) if err != nil { - return fmt.Errorf("Error Getting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting VPC : %s\n%s", err, response) } - d.Set(RelatedCRN, *vpc.CRN) + d.Set(flex.RelatedCRN, *vpc.CRN) return nil } @@ -216,7 +228,7 @@ func resourceIBMISVpcAddressPrefixUpdate(d *schema.ResourceData, meta interface{ hasNameChanged := false hasIsDefaultChanged := false - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -224,8 +236,8 @@ func resourceIBMISVpcAddressPrefixUpdate(d *schema.ResourceData, meta interface{ addrPrefixID := parts[1] isVPCAddressPrefixKey := "vpc_address_prefix_key_" + vpcID - ibmMutexKV.Lock(isVPCAddressPrefixKey) - defer ibmMutexKV.Unlock(isVPCAddressPrefixKey) + conns.IbmMutexKV.Lock(isVPCAddressPrefixKey) + defer conns.IbmMutexKV.Unlock(isVPCAddressPrefixKey) if d.HasChange(isVPCAddressPrefixPrefixName) { name = d.Get(isVPCAddressPrefixPrefixName).(string) @@ -263,12 +275,12 @@ func vpcAddressPrefixUpdate(d *schema.ResourceData, meta interface{}, vpcID, add } addressPrefixPatch, err := addressPrefixPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for AddressPrefixPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for AddressPrefixPatch: %s", err) } updatevpcAddressPrefixoptions.AddressPrefixPatch = addressPrefixPatch _, response, err := sess.UpdateVPCAddressPrefix(updatevpcAddressPrefixoptions) if err != nil { - return fmt.Errorf("Error Updating VPC Address Prefix: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating VPC Address Prefix: %s\n%s", err, response) } } return nil @@ -276,7 +288,7 @@ func vpcAddressPrefixUpdate(d *schema.ResourceData, meta interface{}, vpcID, add func resourceIBMISVpcAddressPrefixDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -284,8 +296,8 @@ func resourceIBMISVpcAddressPrefixDelete(d *schema.ResourceData, meta interface{ addrPrefixID := parts[1] isVPCAddressPrefixKey := "vpc_address_prefix_key_" + vpcID - ibmMutexKV.Lock(isVPCAddressPrefixKey) - defer ibmMutexKV.Unlock(isVPCAddressPrefixKey) + conns.IbmMutexKV.Lock(isVPCAddressPrefixKey) + defer conns.IbmMutexKV.Unlock(isVPCAddressPrefixKey) error := vpcAddressPrefixDelete(d, meta, vpcID, addrPrefixID) if error != nil { @@ -311,7 +323,7 @@ func vpcAddressPrefixDelete(d *schema.ResourceData, meta interface{}, vpcID, add if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Getting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) + return fmt.Errorf("[ERROR] Error Getting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) } deletevpcAddressPrefixOptions := &vpcv1.DeleteVPCAddressPrefixOptions{ @@ -323,7 +335,7 @@ func vpcAddressPrefixDelete(d *schema.ResourceData, meta interface{}, vpcID, add if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Deleting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) + return fmt.Errorf("[ERROR] Error Deleting VPC Address Prefix (%s): %s\n%s", addrPrefixID, err, response) } d.SetId("") return nil @@ -331,9 +343,9 @@ func vpcAddressPrefixDelete(d *schema.ResourceData, meta interface{}, vpcID, add func resourceIBMISVpcAddressPrefixExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of vpcID/addrPrefixID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of vpcID/addrPrefixID", d.Id()) } if err != nil { return false, err @@ -359,7 +371,7 @@ func vpcAddressPrefixExists(d *schema.ResourceData, meta interface{}, vpcID, add if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting VPC Address Prefix: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting VPC Address Prefix: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_vpc_address_prefix_test.go b/ibm/service/vpc/resource_ibm_is_vpc_address_prefix_test.go similarity index 85% rename from ibm/resource_ibm_is_vpc_address_prefix_test.go rename to ibm/service/vpc/resource_ibm_is_vpc_address_prefix_test.go index a57c50dde..fbca3ad6a 100644 --- a/ibm/resource_ibm_is_vpc_address_prefix_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_address_prefix_test.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" @@ -9,6 +9,10 @@ import ( "regexp" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -23,8 +27,8 @@ func TestAccIBMISVPCAddressPrefix_basic(t *testing.T) { prefixName1 := fmt.Sprintf("tfaddprenamename-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCAddressPrefixDestroy, Steps: []resource.TestStep{ { @@ -54,10 +58,10 @@ func TestAccIBMISVPCAddressPrefix_InvalidCidr(t *testing.T) { prefixName2 := fmt.Sprintf("tfaddprename-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIBMISVPCAddressPrefixConfig2(name2, prefixName2), ExpectError: regexp.MustCompile(fmt.Sprintf("the request is overlapping with reserved address ranges")), }, @@ -66,13 +70,13 @@ func TestAccIBMISVPCAddressPrefix_InvalidCidr(t *testing.T) { } func testAccCheckIBMISVPCAddressPrefixDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_vpc_address_prefix" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -102,14 +106,14 @@ func testAccCheckIBMISVPCAddressPrefixExists(n, vpcAddressPrefix string) resourc if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } vpcID := parts[0] addrPrefixID := parts[1] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getvpcAddressPrefixOptions := &vpcv1.GetVPCAddressPrefixOptions{ VPCID: &vpcID, ID: &addrPrefixID, @@ -135,7 +139,7 @@ resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix" { vpc = "${ibm_is_vpc.testacc_vpc.id}" cidr = "%s" is_default = true -}`, name, prefixName, ISZoneName, ISAddressPrefixCIDR) +}`, name, prefixName, acc.ISZoneName, acc.ISAddressPrefixCIDR) } func testAccCheckIBMISVPCAddressPrefixConfig1(name, prefixName string) string { @@ -148,7 +152,7 @@ resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix1" { zone = "%s" vpc = "${ibm_is_vpc.testacc_vpc1.id}" cidr = "%s" -}`, name, prefixName, ISZoneName, ISAddressPrefixCIDR) +}`, name, prefixName, acc.ISZoneName, acc.ISAddressPrefixCIDR) } func testAccCheckIBMISVPCAddressPrefixConfig2(name, prefixName string) string { @@ -161,5 +165,5 @@ resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix2" { zone = "%s" vpc = "${ibm_is_vpc.testacc_vpc2.id}" cidr = "127.0.0.0/8" -}`, name, prefixName, ISZoneName) +}`, name, prefixName, acc.ISZoneName) } diff --git a/ibm/resource_ibm_is_vpc_route.go b/ibm/service/vpc/resource_ibm_is_vpc_route.go similarity index 78% rename from ibm/resource_ibm_is_vpc_route.go rename to ibm/service/vpc/resource_ibm_is_vpc_route.go index 2247a67f5..55d6a719b 100644 --- a/ibm/resource_ibm_is_vpc_route.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_route.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -30,14 +32,15 @@ const ( isRouteStatusDeleted = "deleted" ) -func resourceIBMISVpcRoute() *schema.Resource { +func ResourceIBMISVpcRoute() *schema.Resource { return &schema.Resource{ - Create: resourceIBMISVpcRouteCreate, - Read: resourceIBMISVpcRouteRead, - Update: resourceIBMISVpcRouteUpdate, - Delete: resourceIBMISVpcRouteDelete, - Exists: resourceIBMISVpcRouteExists, - Importer: &schema.ResourceImporter{}, + DeprecationMessage: "This resource is deprecated, use ibm_is_vpc_routing_table_route instead.", + Create: resourceIBMISVpcRouteCreate, + Read: resourceIBMISVpcRouteRead, + Update: resourceIBMISVpcRouteUpdate, + Delete: resourceIBMISVpcRouteDelete, + Exists: resourceIBMISVpcRouteExists, + Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), @@ -49,7 +52,7 @@ func resourceIBMISVpcRoute() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_route", isVPCRouteName), + ValidateFunc: validate.InvokeValidator("ibm_is_route", isVPCRouteName), Description: "VPC route name", }, isVPCRouteLocation: { @@ -63,7 +66,7 @@ func resourceIBMISVpcRoute() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: InvokeValidator("ibm_is_route", isVPCRouteDestinationCIDR), + ValidateFunc: validate.InvokeValidator("ibm_is_route", isVPCRouteDestinationCIDR), Description: "VPC route destination CIDR value", }, @@ -86,7 +89,7 @@ func resourceIBMISVpcRoute() *schema.Resource { Description: "VPC route next hop value", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the VPC resource", @@ -95,27 +98,27 @@ func resourceIBMISVpcRoute() *schema.Resource { } } -func resourceIBMISRouteValidator() *ResourceValidator { +func ResourceIBMISRouteValidator() *validate.ResourceValidator { - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCRouteName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPCRouteDestinationCIDR, - ValidateFunctionIdentifier: ValidateCIDRAddress, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateCIDRAddress, + Type: validate.TypeString, ForceNew: true, Required: true}) - ibmISRouteResourceValidator := ResourceValidator{ResourceName: "ibm_is_route", Schema: validateSchema} + ibmISRouteResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_route", Schema: validateSchema} return &ibmISRouteResourceValidator } @@ -142,7 +145,7 @@ func vpcRouteCreate(d *schema.ResourceData, meta interface{}, routeName, zoneNam VPCID: &vpcID, Destination: &cidr, Name: &routeName, - NextHop: &vpcv1.RouteNextHopPrototype{ + NextHop: &vpcv1.RoutePrototypeNextHopRouteNextHopPrototypeRouteNextHopIP{ Address: &nextHop, }, Zone: &vpcv1.ZoneIdentity{ @@ -151,7 +154,7 @@ func vpcRouteCreate(d *schema.ResourceData, meta interface{}, routeName, zoneNam } route, response, err := sess.CreateVPCRoute(createRouteOptions) if err != nil { - return fmt.Errorf("Error while creating VPC Route err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating VPC Route err %s\n%s", err, response) } routeID := *route.ID @@ -176,7 +179,7 @@ func isWaitForRouteStable(sess *vpcv1.VpcV1, d *schema.ResourceData, vpcID, rout } route, response, err := sess.GetVPCRoute(getVpcRouteOptions) if err != nil { - return route, "", fmt.Errorf("Error Getting VPC Route: %s\n%s", err, response) + return route, "", fmt.Errorf("[ERROR] Error Getting VPC Route: %s\n%s", err, response) } if *route.LifecycleState == "stable" || *route.LifecycleState == "failed" { @@ -194,7 +197,7 @@ func isWaitForRouteStable(sess *vpcv1.VpcV1, d *schema.ResourceData, vpcID, rout func resourceIBMISVpcRouteRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -223,7 +226,7 @@ func vpcRouteGet(d *schema.ResourceData, meta interface{}, vpcID, routeID string d.SetId("") return nil } - return fmt.Errorf("Error Getting VPC Route (%s): %s\n%s", routeID, err, response) + return fmt.Errorf("[ERROR] Error Getting VPC Route (%s): %s\n%s", routeID, err, response) } d.Set(isVPCRouteVPCID, vpcID) d.Set(isVPCRouteName, route.Name) @@ -239,9 +242,9 @@ func vpcRouteGet(d *schema.ResourceData, meta interface{}, vpcID, routeID string } vpc, response, err := sess.GetVPC(getVPCOptions) if err != nil { - return fmt.Errorf("Error Getting VPC : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting VPC : %s\n%s", err, response) } - d.Set(RelatedCRN, *vpc.CRN) + d.Set(flex.RelatedCRN, *vpc.CRN) return nil } @@ -251,7 +254,7 @@ func resourceIBMISVpcRouteUpdate(d *schema.ResourceData, meta interface{}) error name := "" hasChanged := false - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -286,19 +289,19 @@ func vpcRouteUpdate(d *schema.ResourceData, meta interface{}, vpcID, routeID, na } routePatch, err := routePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for RoutePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for RoutePatch: %s", err) } updateVpcRouteOptions.RoutePatch = routePatch _, response, err := sess.UpdateVPCRoute(updateVpcRouteOptions) if err != nil { - return fmt.Errorf("Error Updating VPC Route: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Updating VPC Route: %s\n%s", err, response) } } return nil } func resourceIBMISVpcRouteDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -328,7 +331,7 @@ func vpcRouteDelete(d *schema.ResourceData, meta interface{}, vpcID, routeID str if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Getting VPC Route (%s): %s\n%s", routeID, err, response) + return fmt.Errorf("[ERROR] Error Getting VPC Route (%s): %s\n%s", routeID, err, response) } deleteRouteOptions := &vpcv1.DeleteVPCRouteOptions{ VPCID: &vpcID, @@ -336,7 +339,7 @@ func vpcRouteDelete(d *schema.ResourceData, meta interface{}, vpcID, routeID str } response, err = sess.DeleteVPCRoute(deleteRouteOptions) if err != nil { - return fmt.Errorf("Error Deleting VPC Route: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting VPC Route: %s\n%s", err, response) } _, err = isWaitForVPCRouteDeleted(sess, vpcID, routeID, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -362,7 +365,7 @@ func isWaitForVPCRouteDeleted(sess *vpcv1.VpcV1, vpcID, routeID string, timeout if response != nil && response.StatusCode == 404 { return route, isRouteStatusDeleted, nil } - return route, isRouteStatusDeleting, fmt.Errorf("The VPC route %s failed to delete: %s\n%s", routeID, err, response) + return route, isRouteStatusDeleting, fmt.Errorf("[ERROR] The VPC route %s failed to delete: %s\n%s", routeID, err, response) } return route, isRouteStatusDeleting, nil }, @@ -375,12 +378,12 @@ func isWaitForVPCRouteDeleted(sess *vpcv1.VpcV1, vpcID, routeID string, timeout } func resourceIBMISVpcRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of vpcID/routeID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of vpcID/routeID", d.Id()) } vpcID := parts[0] routeID := parts[1] @@ -402,7 +405,7 @@ func vpcRouteExists(d *schema.ResourceData, meta interface{}, vpcID, routeID str if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting VPC Route: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting VPC Route: %s\n%s", err, response) } return true, nil } diff --git a/ibm/resource_ibm_is_vpc_route_test.go b/ibm/service/vpc/resource_ibm_is_vpc_route_test.go similarity index 83% rename from ibm/resource_ibm_is_vpc_route_test.go rename to ibm/service/vpc/resource_ibm_is_vpc_route_test.go index a7e00703c..596daa8de 100644 --- a/ibm/resource_ibm_is_vpc_route_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_route_test.go @@ -1,13 +1,17 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -22,8 +26,8 @@ func TestAccIBMISVPCRoute_basic(t *testing.T) { routeName1 := fmt.Sprintf("tfvpcuat-create-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCRouteDestroy, Steps: []resource.TestStep{ { @@ -47,12 +51,12 @@ func TestAccIBMISVPCRoute_basic(t *testing.T) { } func testAccCheckIBMISVPCRouteDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_vpc_route" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -84,7 +88,7 @@ func testAccCheckIBMISVPCRouteExists(n, vpcrouteID string) resource.TestCheckFun return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -92,7 +96,7 @@ func testAccCheckIBMISVPCRouteExists(n, vpcrouteID string) resource.TestCheckFun vpcID := parts[0] routeID := parts[1] - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getVpcRouteOptions := &vpcv1.GetVPCRouteOptions{ VPCID: &vpcID, ID: &routeID, @@ -126,5 +130,5 @@ resource "ibm_is_vpc_route" "testacc_vpc_route" { destination = "%s" next_hop = "%s" depends_on = [ibm_is_subnet.testacc_subnet] -}`, name, subnetName, ISZoneName, ISCIDR, routeName, ISZoneName, ISRouteDestination, ISRouteNextHop) +}`, name, subnetName, acc.ISZoneName, acc.ISCIDR, routeName, acc.ISZoneName, acc.ISRouteDestination, acc.ISRouteNextHop) } diff --git a/ibm/service/vpc/resource_ibm_is_vpc_routing_table.go b/ibm/service/vpc/resource_ibm_is_vpc_routing_table.go new file mode 100644 index 000000000..f8f464987 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpc_routing_table.go @@ -0,0 +1,382 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + rtID = "routing_table" + rtVpcID = "vpc" + rtName = "name" + rtRouteDirectLinkIngress = "route_direct_link_ingress" + rtRouteTransitGatewayIngress = "route_transit_gateway_ingress" + rtRouteVPCZoneIngress = "route_vpc_zone_ingress" + rtCreateAt = "created_at" + rtHref = "href" + rtIsDefault = "is_default" + rtResourceType = "resource_type" + rtLifecycleState = "lifecycle_state" + rtSubnets = "subnets" + rtDestination = "destination" + rtAction = "action" + rtNextHop = "next_hop" + rtZone = "zone" + rtOrigin = "origin" +) + +func ResourceIBMISVPCRoutingTable() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISVPCRoutingTableCreate, + Read: resourceIBMISVPCRoutingTableRead, + Update: resourceIBMISVPCRoutingTableUpdate, + Delete: resourceIBMISVPCRoutingTableDelete, + Exists: resourceIBMISVPCRoutingTableExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + rtVpcID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPC identifier.", + }, + "accept_routes_from_resource_type": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The filters specifying the resources that may create routes in this routing table, The resource type: vpn_gateway or vpn_server", + }, + rtRouteDirectLinkIngress: { + Type: schema.TypeBool, + ForceNew: false, + Default: false, + Optional: true, + Description: "If set to true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + }, + rtRouteTransitGatewayIngress: { + Type: schema.TypeBool, + ForceNew: false, + Default: false, + Optional: true, + Description: "If set to true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + }, + rtRouteVPCZoneIngress: { + Type: schema.TypeBool, + ForceNew: false, + Default: false, + Optional: true, + Description: "If set to true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + }, + rtName: { + Type: schema.TypeString, + Optional: true, + ForceNew: false, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_vpc_routing_table", rtName), + Description: "The user-defined name for this routing table.", + }, + rtID: { + Type: schema.TypeString, + Computed: true, + Description: "The routing table identifier.", + }, + rtHref: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table Href", + }, + rtResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table Resource Type", + }, + rtCreateAt: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table Created At", + }, + rtLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table Lifecycle State", + }, + rtIsDefault: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this is the default routing table for this VPC", + }, + rtSubnets: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + rtName: { + Type: schema.TypeString, + Computed: true, + Description: "Subnet name", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Subnet ID", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMISVPCRoutingTableValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + actionAllowedValues := "delegate, delegate_vpc, deliver, drop" + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: rtName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: false, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: rtAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: false, + AllowedValues: actionAllowedValues}) + + ibmISVPCRoutingTableValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpc_routing_table", Schema: validateSchema} + return &ibmISVPCRoutingTableValidator +} + +func resourceIBMISVPCRoutingTableCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + vpcID := d.Get(rtVpcID).(string) + rtName := d.Get(rtName).(string) + // acptresourcetype + + createVpcRoutingTableOptions := sess.NewCreateVPCRoutingTableOptions(vpcID) + createVpcRoutingTableOptions.SetName(rtName) + if _, ok := d.GetOk(rtRouteDirectLinkIngress); ok { + routeDirectLinkIngress := d.Get(rtRouteDirectLinkIngress).(bool) + createVpcRoutingTableOptions.RouteDirectLinkIngress = &routeDirectLinkIngress + } + + if acceptRoutesFrom, ok := d.GetOk("accept_routes_from_resource_type"); ok { + var aroutes []vpcv1.ResourceFilter + acptRoutes := acceptRoutesFrom.(*schema.Set) + for _, val := range acptRoutes.List() { + value := val.(string) + resourceFilter := vpcv1.ResourceFilter{ + ResourceType: &value, + } + aroutes = append(aroutes, resourceFilter) + } + createVpcRoutingTableOptions.AcceptRoutesFrom = aroutes + } + + if _, ok := d.GetOk(rtRouteTransitGatewayIngress); ok { + routeTransitGatewayIngress := d.Get(rtRouteTransitGatewayIngress).(bool) + createVpcRoutingTableOptions.RouteTransitGatewayIngress = &routeTransitGatewayIngress + } + if _, ok := d.GetOk(rtRouteVPCZoneIngress); ok { + routeVPCZoneIngress := d.Get(rtRouteVPCZoneIngress).(bool) + createVpcRoutingTableOptions.RouteVPCZoneIngress = &routeVPCZoneIngress + } + routeTable, response, err := sess.CreateVPCRoutingTable(createVpcRoutingTableOptions) + if err != nil { + log.Printf("[DEBUG] Create VPC Routing table err %s\n%s", err, response) + return err + } + + d.SetId(fmt.Sprintf("%s/%s", vpcID, *routeTable.ID)) + + return resourceIBMISVPCRoutingTableRead(d, meta) +} + +func resourceIBMISVPCRoutingTableRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + idSet := strings.Split(d.Id(), "/") + getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(idSet[0], idSet[1]) + routeTable, response, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting VPC Routing table: %s\n%s", err, response) + } + + d.Set(rtVpcID, idSet[0]) + d.Set(rtID, routeTable.ID) + d.Set(rtName, routeTable.Name) + d.Set(rtHref, routeTable.Href) + d.Set(rtLifecycleState, routeTable.LifecycleState) + d.Set(rtCreateAt, routeTable.CreatedAt.String()) + d.Set(rtResourceType, routeTable.ResourceType) + d.Set(rtRouteDirectLinkIngress, routeTable.RouteDirectLinkIngress) + d.Set(rtRouteTransitGatewayIngress, routeTable.RouteTransitGatewayIngress) + d.Set(rtRouteVPCZoneIngress, routeTable.RouteVPCZoneIngress) + d.Set(rtIsDefault, routeTable.IsDefault) + acceptRoutesFromArray := make([]string, 0) + for i := 0; i < len(routeTable.AcceptRoutesFrom); i++ { + acceptRoutesFromArray = append(acceptRoutesFromArray, string(*(routeTable.AcceptRoutesFrom[i].ResourceType))) + } + if err = d.Set("accept_routes_from_resource_type", acceptRoutesFromArray); err != nil { + return fmt.Errorf("[ERROR] Error setting accept_routes_from_resource_type: %s", err) + } + subnets := make([]map[string]interface{}, 0) + + for _, s := range routeTable.Subnets { + subnet := make(map[string]interface{}) + subnet[ID] = *s.ID + subnet["name"] = *s.Name + subnets = append(subnets, subnet) + } + + d.Set(rtSubnets, subnets) + + return nil +} + +func resourceIBMISVPCRoutingTableUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + //Etag + idSett := strings.Split(d.Id(), "/") + getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(idSett[0], idSett[1]) + _, respGet, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) + eTag := respGet.Headers.Get("ETag") + + idSet := strings.Split(d.Id(), "/") + updateVpcRoutingTableOptions := new(vpcv1.UpdateVPCRoutingTableOptions) + updateVpcRoutingTableOptions.VPCID = &idSet[0] + updateVpcRoutingTableOptions.ID = &idSet[1] + hasChange := false + // Construct an instance of the RoutingTablePatch model + routingTablePatchModel := new(vpcv1.RoutingTablePatch) + + if d.HasChange(rtName) { + name := d.Get(rtName).(string) + routingTablePatchModel.Name = core.StringPtr(name) + hasChange = true + } + if d.HasChange("accept_routes_from_resource_type") { + var aroutes []vpcv1.ResourceFilter + acptRoutes := d.Get("accept_routes_from_resource_type").(*schema.Set) + for _, val := range acptRoutes.List() { + value := val.(string) + resourceFilter := vpcv1.ResourceFilter{ + ResourceType: &value, + } + aroutes = append(aroutes, resourceFilter) + } + routingTablePatchModel.AcceptRoutesFrom = aroutes + hasChange = true + } + if d.HasChange(rtRouteDirectLinkIngress) { + routeDirectLinkIngress := d.Get(rtRouteDirectLinkIngress).(bool) + routingTablePatchModel.RouteDirectLinkIngress = core.BoolPtr(routeDirectLinkIngress) + hasChange = true + } + if d.HasChange(rtRouteTransitGatewayIngress) { + routeTransitGatewayIngress := d.Get(rtRouteTransitGatewayIngress).(bool) + routingTablePatchModel.RouteTransitGatewayIngress = core.BoolPtr(routeTransitGatewayIngress) + hasChange = true + } + if d.HasChange(rtRouteVPCZoneIngress) { + routeVPCZoneIngress := d.Get(rtRouteVPCZoneIngress).(bool) + routingTablePatchModel.RouteVPCZoneIngress = core.BoolPtr(routeVPCZoneIngress) + hasChange = true + } + if hasChange { + updateVpcRoutingTableOptions.IfMatch = &eTag + } + + routingTablePatchModelAsPatch, asPatchErr := routingTablePatchModel.AsPatch() + if asPatchErr != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for RoutingTablePatchModel: %s", asPatchErr) + } + + updateVpcRoutingTableOptions.RoutingTablePatch = routingTablePatchModelAsPatch + _, response, err := sess.UpdateVPCRoutingTable(updateVpcRoutingTableOptions) + if err != nil { + log.Printf("[DEBUG] Update VPC Routing table err %s\n%s", err, response) + return err + } + return resourceIBMISVPCRoutingTableRead(d, meta) +} + +func resourceIBMISVPCRoutingTableDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + idSet := strings.Split(d.Id(), "/") + + deleteTableOptions := sess.NewDeleteVPCRoutingTableOptions(idSet[0], idSet[1]) + response, err := sess.DeleteVPCRoutingTable(deleteTableOptions) + if err != nil && response.StatusCode != 404 { + log.Printf("Error deleting VPC Routing table : %s", response) + return err + } + + d.SetId("") + return nil +} + +func resourceIBMISVPCRoutingTableExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + + idSet := strings.Split(d.Id(), "/") + if len(idSet) != 2 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of vpcID/routingTableID", d.Id()) + } + getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(idSet[0], idSet[1]) + _, response, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return false, nil + } + return false, fmt.Errorf("[ERROR] Error Getting VPC Routing table : %s\n%s", err, response) + } + return true, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go new file mode 100644 index 000000000..c4512c4bf --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go @@ -0,0 +1,371 @@ +// Copyright IBM Corp. 2017, 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "net" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + rID = "route_id" + rDestination = "destination" + rAction = "action" + rNextHop = "next_hop" + rName = "name" + rZone = "zone" +) + +func ResourceIBMISVPCRoutingTableRoute() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISVPCRoutingTableRouteCreate, + Read: resourceIBMISVPCRoutingTableRouteRead, + Update: resourceIBMISVPCRoutingTableRouteUpdate, + Delete: resourceIBMISVPCRoutingTableRouteDelete, + Exists: resourceIBMISVPCRoutingTableRouteExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + rtID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The routing table identifier.", + }, + rtVpcID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPC identifier.", + }, + rDestination: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The destination of the route.", + }, + rZone: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The zone to apply the route to. Traffic from subnets in this zone will be subject to this route.", + }, + rNextHop: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "If action is deliver, the next hop that packets will be delivered to. For other action values, its address will be 0.0.0.0.", + }, + rAction: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "deliver", + Description: "The action to perform with a packet matching the route.", + ValidateFunc: validate.InvokeValidator("ibm_is_vpc_routing_table_route", rAction), + }, + rName: { + Type: schema.TypeString, + Optional: true, + ForceNew: false, + Computed: true, + Description: "The user-defined name for this route.", + ValidateFunc: validate.InvokeValidator("ibm_is_vpc_routing_table_route", rName), + }, + rID: { + Type: schema.TypeString, + Computed: true, + Description: "The routing table route identifier.", + }, + rtHref: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table route Href", + }, + rtCreateAt: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table route Created At", + }, + "creator": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The VPN gateway's CRN.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The VPN gateway's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique identifier for this VPN gateway.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The user-defined name for this VPN gateway.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The resource type.", + }, + }, + }, + }, + rtLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "Routing table route Lifecycle State", + }, + rtOrigin: { + Type: schema.TypeString, + Computed: true, + Description: "The origin of this route.", + }, + }, + } +} + +func ResourceIBMISVPCRoutingTableRouteValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + actionAllowedValues := "delegate, delegate_vpc, deliver, drop" + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: rtName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: false, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: rAction, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: false, + AllowedValues: actionAllowedValues}) + + ibmVPCRoutingTableRouteValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpc_routing_table_route", Schema: validateSchema} + return &ibmVPCRoutingTableRouteValidator +} + +func resourceIBMISVPCRoutingTableRouteCreate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + vpcID := d.Get(rtVpcID).(string) + tableID := d.Get(rtID).(string) + destination := d.Get(rDestination).(string) + zone := d.Get(rZone).(string) + z := &vpcv1.ZoneIdentityByName{ + Name: core.StringPtr(zone), + } + + createVpcRoutingTableRouteOptions := sess.NewCreateVPCRoutingTableRouteOptions(vpcID, tableID, destination, z) + createVpcRoutingTableRouteOptions.SetZone(z) + createVpcRoutingTableRouteOptions.SetDestination(destination) + + if add, ok := d.GetOk(rNextHop); ok { + item := add.(string) + if net.ParseIP(item) == nil { + nhConnectionID := &vpcv1.RoutePrototypeNextHopRouteNextHopPrototypeVPNGatewayConnectionIdentity{ + ID: core.StringPtr(item), + } + createVpcRoutingTableRouteOptions.SetNextHop(nhConnectionID) + } else { + nh := &vpcv1.RoutePrototypeNextHopRouteNextHopPrototypeRouteNextHopIP{ + Address: core.StringPtr(item), + } + createVpcRoutingTableRouteOptions.SetNextHop(nh) + } + } + + if action, ok := d.GetOk(rAction); ok { + routeAction := action.(string) + createVpcRoutingTableRouteOptions.SetAction(routeAction) + } + + if name, ok := d.GetOk(rName); ok { + routeName := name.(string) + createVpcRoutingTableRouteOptions.SetName(routeName) + } + + route, response, err := sess.CreateVPCRoutingTableRoute(createVpcRoutingTableRouteOptions) + if err != nil { + log.Printf("[DEBUG] Create VPC Routing table route err %s\n%s", err, response) + return err + } + + d.SetId(fmt.Sprintf("%s/%s/%s", vpcID, tableID, *route.ID)) + d.Set(rID, *route.ID) + return resourceIBMISVPCRoutingTableRouteRead(d, meta) +} + +func resourceIBMISVPCRoutingTableRouteRead(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + idSet := strings.Split(d.Id(), "/") + getVpcRoutingTableRouteOptions := sess.NewGetVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) + route, response, err := sess.GetVPCRoutingTableRoute(getVpcRoutingTableRouteOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting VPC Routing table route: %s\n%s", err, response) + } + + d.Set(rID, *route.ID) + d.Set(rName, *route.Name) + d.Set(rDestination, *route.Destination) + if route.NextHop != nil { + nexthop := route.NextHop.(*vpcv1.RouteNextHop) + if nexthop.Address != nil { + d.Set(rNextHop, *nexthop.Address) + } + if nexthop.ID != nil { + d.Set(rNextHop, *nexthop.ID) + } + } + if err = d.Set("origin", route.Origin); err != nil { + return fmt.Errorf("[ERROR] Error setting origin %s", err) + } + if route.Zone != nil { + d.Set(rZone, *route.Zone.Name) + } + d.Set(rtHref, route.Href) + d.Set(rtLifecycleState, route.LifecycleState) + d.Set(rtCreateAt, route.CreatedAt.String()) + creator := []map[string]interface{}{} + if route.Creator != nil { + mm, err := dataSourceIBMIsRouteCreatorToMap(route.Creator) + if err != nil { + log.Printf("Error reading VPC Routing Table Routes' creator:%s", err) + return err + } + creator = append(creator, mm) + + d.Set("creator", creator) + } + return nil +} + +func resourceIBMISVPCRoutingTableRouteUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + idSet := strings.Split(d.Id(), "/") + if d.HasChange(rName) { + routePatch := make(map[string]interface{}) + updateVpcRoutingTableRouteOptions := sess.NewUpdateVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2], routePatch) + + // Construct an instance of the RoutePatch model + routePatchModel := new(vpcv1.RoutePatch) + name := d.Get(rName).(string) + routePatchModel.Name = &name + routePatchModelAsPatch, patchErr := routePatchModel.AsPatch() + + if patchErr != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for VPC Routing Table Route Patch: %s", patchErr) + } + + updateVpcRoutingTableRouteOptions.RoutePatch = routePatchModelAsPatch + _, response, err := sess.UpdateVPCRoutingTableRoute(updateVpcRoutingTableRouteOptions) + if err != nil { + log.Printf("[DEBUG] Update VPC Routing table route err %s\n%s", err, response) + return err + } + } + + return resourceIBMISVPCRoutingTableRouteRead(d, meta) +} + +func resourceIBMISVPCRoutingTableRouteDelete(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + idSet := strings.Split(d.Id(), "/") + deleteVpcRoutingTableRouteOptions := sess.NewDeleteVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) + response, err := sess.DeleteVPCRoutingTableRoute(deleteVpcRoutingTableRouteOptions) + if err != nil && response.StatusCode != 404 { + log.Printf("Error deleting VPC Routing table route : %s", response) + return err + } + + d.SetId("") + return nil +} + +func resourceIBMISVPCRoutingTableRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + + idSet := strings.Split(d.Id(), "/") + if len(idSet) != 3 { + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of vpcID/routingTableID/routeID", d.Id()) + } + getVpcRoutingTableRouteOptions := sess.NewGetVPCRoutingTableRouteOptions(idSet[0], idSet[1], idSet[2]) + _, response, err := sess.GetVPCRoutingTableRoute(getVpcRoutingTableRouteOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return false, nil + } + return false, fmt.Errorf("[ERROR] Error Getting VPC Routing table route : %s\n%s", err, response) + } + return true, nil +} diff --git a/ibm/resource_ibm_is_vpc_routing_table_route_test.go b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route_test.go similarity index 83% rename from ibm/resource_ibm_is_vpc_routing_table_route_test.go rename to ibm/service/vpc/resource_ibm_is_vpc_routing_table_route_test.go index 8b1bb05ce..5157cbcf6 100644 --- a/ibm/resource_ibm_is_vpc_routing_table_route_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route_test.go @@ -1,15 +1,19 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "testing" ) func TestAccIBMISVPCRoutingTableRoute_basic(t *testing.T) { @@ -22,8 +26,8 @@ func TestAccIBMISVPCRoutingTableRoute_basic(t *testing.T) { routeTableName1 := fmt.Sprintf("tfvpcrt-up-create-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCRouteTableRouteDestroy, Steps: []resource.TestStep{ { @@ -47,18 +51,18 @@ func TestAccIBMISVPCRoutingTableRoute_basic(t *testing.T) { } func testAccCheckIBMISVPCRouteTableRouteDestroy(s *terraform.State) error { - //userDetails, _ := testAccProvider.Meta().(ClientSession).BluemixUserDetails() + //userDetails, _ := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() - //sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + //sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_vpc_routing_table_route" { continue } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } - sess, err := vpcClient(testAccProvider.Meta()) + sess, err := vpcClient(acc.TestAccProvider.Meta()) if err != nil { return err } @@ -78,7 +82,7 @@ func testAccCheckIBMISVPCRouteTableRouteDestroy(s *terraform.State) error { func testAccCheckIBMISVPCRouteTableRouteExists(n, vpcrouteTableID string) resource.TestCheckFunc { return func(s *terraform.State) error { - //sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + //sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() rs, ok := s.RootModule().Resources[n] @@ -90,7 +94,7 @@ func testAccCheckIBMISVPCRouteTableRouteExists(n, vpcrouteTableID string) resour return errors.New("No Record ID is set") } - parts, err := idParts(rs.Primary.ID) + parts, err := flex.IdParts(rs.Primary.ID) if err != nil { return err } @@ -98,12 +102,12 @@ func testAccCheckIBMISVPCRouteTableRouteExists(n, vpcrouteTableID string) resour vpcID := parts[0] routeTableID := parts[1] routeID := parts[2] - sess, err := vpcClient(testAccProvider.Meta()) + sess, err := vpcClient(acc.TestAccProvider.Meta()) getVpcRoutingTableRouteOptions := sess.NewGetVPCRoutingTableRouteOptions(vpcID, routeTableID, routeID) rtResponse, detail, err := sess.GetVPCRoutingTableRoute(getVpcRoutingTableRouteOptions) if err != nil { - return fmt.Errorf("Error Getting Routing table route: %s\n%s", err, detail) + return fmt.Errorf("[ERROR] Error Getting Routing table route: %s\n%s", err, detail) } vpcrouteTableID = *rtResponse.ID return nil @@ -138,5 +142,5 @@ resource "ibm_is_vpc_routing_table_route" "test_custom_route1" { next_hop = "%s" destination = ibm_is_subnet.test_cr_subnet1.ipv4_cidr_block } -`, name, rtName, subnetName, ISZoneName, ISCIDR, routeName, ISZoneName, ISRouteNextHop) +`, name, rtName, subnetName, acc.ISZoneName, acc.ISCIDR, routeName, acc.ISZoneName, acc.ISRouteNextHop) } diff --git a/ibm/service/vpc/resource_ibm_is_vpc_routing_table_test.go b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_test.go new file mode 100644 index 000000000..3068c21d0 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_test.go @@ -0,0 +1,176 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISVPCRoutingTable_basic(t *testing.T) { + var vpcRouteTables string + name1 := fmt.Sprintf("tfvpc-create-%d", acctest.RandIntRange(10, 100)) + routeTableName := fmt.Sprintf("tfvpcrt-create-%d", acctest.RandIntRange(10, 100)) + routeTableName1 := fmt.Sprintf("tfvpcrt-up-create-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPCRouteTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPCRouteTableConfig(routeTableName, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), + resource.TestCheckResourceAttr( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName), + ), + }, + { + Config: testAccCheckIBMISVPCRouteTableConfig(routeTableName1, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), + resource.TestCheckResourceAttr( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName1), + ), + }, + }, + }) +} + +func TestAccIBMISVPCRoutingTable_acceptRoutesFrom(t *testing.T) { + var vpcRouteTables string + name1 := fmt.Sprintf("tfvpc-create-%d", acctest.RandIntRange(10, 100)) + routeTableName := fmt.Sprintf("tfvpcrt-create-%d", acctest.RandIntRange(10, 100)) + routeTableName1 := fmt.Sprintf("tfvpcrt-up-create-%d", acctest.RandIntRange(10, 100)) + acceptRoutesFromVPNServer := "vpn_server" + acceptRoutesFromVPNGateway := "vpn_gateway" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPCRouteTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPCRouteTableAcceptRoutesFromConfig(routeTableName, name1, acceptRoutesFromVPNServer), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), + resource.TestCheckResourceAttr( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName), + resource.TestCheckResourceAttrSet( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "accept_routes_from_resource_type.#"), + ), + }, + { + Config: testAccCheckIBMISVPCRouteTableAcceptRoutesFromConfig(routeTableName1, name1, acceptRoutesFromVPNGateway), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCRouteTableExists("ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", vpcRouteTables), + resource.TestCheckResourceAttr( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "name", routeTableName1), + resource.TestCheckResourceAttrSet( + "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", "accept_routes_from_resource_type.#"), + ), + }, + { + ResourceName: "ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMISVPCRouteTableDestroy(s *terraform.State) error { + //userDetails, _ := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixUserDetails() + + //sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpc_routing_table" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + sess, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + vpcID := parts[0] + routeTableID := parts[1] + getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(vpcID, routeTableID) + _, _, err = sess.GetVPCRoutingTable(getVpcRoutingTableOptions) + if err == nil { + return fmt.Errorf("Routing table still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISVPCRouteTableExists(n, vpcrouteTableID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + //sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + vpcID := parts[0] + routeTableID := parts[1] + sess, err := vpcClient(acc.TestAccProvider.Meta()) + getVpcRoutingTableOptions := sess.NewGetVPCRoutingTableOptions(vpcID, routeTableID) + rtResponse, detail, err := sess.GetVPCRoutingTable(getVpcRoutingTableOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting Flow log: %s\n%s", err, detail) + } + vpcrouteTableID = *rtResponse.ID + return nil + } +} + +func testAccCheckIBMISVPCRouteTableConfig(rtName, name string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} +resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { + depends_on = [ibm_is_vpc.testacc_vpc] + vpc = ibm_is_vpc.testacc_vpc.id + name = "%s" +}`, name, rtName) +} + +func testAccCheckIBMISVPCRouteTableAcceptRoutesFromConfig(rtName, name, acceptRoutesFromVPNServer string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" +} +resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { + depends_on = [ibm_is_vpc.testacc_vpc] + vpc = ibm_is_vpc.testacc_vpc.id + name = "%s" + accept_routes_from_resource_type=["%s"] +}`, name, rtName, acceptRoutesFromVPNServer) +} diff --git a/ibm/resource_ibm_is_vpc_test.go b/ibm/service/vpc/resource_ibm_is_vpc_test.go similarity index 92% rename from ibm/resource_ibm_is_vpc_test.go rename to ibm/service/vpc/resource_ibm_is_vpc_test.go index 8fcc9b11e..b94de227c 100644 --- a/ibm/resource_ibm_is_vpc_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_test.go @@ -1,13 +1,16 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc_test import ( "errors" "fmt" "testing" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -21,8 +24,8 @@ func TestAccIBMISVPC_basic(t *testing.T) { apm := "manual" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { @@ -74,8 +77,8 @@ func TestAccIBMISVPC_basic_apm(t *testing.T) { apm2 := "manual" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { @@ -107,8 +110,8 @@ func TestAccIBMISVPC_securityGroups(t *testing.T) { vpcname := fmt.Sprintf("terraformvpcuat-%d", acctest.RandIntRange(10, 100)) sgname := fmt.Sprintf("terraformvpcsg-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVPCDestroy, Steps: []resource.TestStep{ { @@ -128,7 +131,7 @@ func TestAccIBMISVPC_securityGroups(t *testing.T) { } func testAccCheckIBMISVPCDestroy(s *terraform.State) error { - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { if rs.Type != "ibm_is_vpc" { continue @@ -157,7 +160,7 @@ func testAccCheckIBMISVPCExists(n, vpcID string) resource.TestCheckFunc { if rs.Primary.ID == "" { return errors.New("No Record ID is set") } - sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() getvpcoptions := &vpcv1.GetVPCOptions{ ID: &rs.Primary.ID, } diff --git a/ibm/resource_ibm_is_vpn_gateway.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go similarity index 77% rename from ibm/resource_ibm_is_vpn_gateway.go rename to ibm/service/vpc/resource_ibm_is_vpn_gateway.go index 1dac1af71..6581fae57 100644 --- a/ibm/resource_ibm_is_vpn_gateway.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "context" @@ -10,6 +10,8 @@ import ( "os" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -36,7 +38,7 @@ const ( isVPNGatewayPrivateIPAddress2 = "private_ip_address2" ) -func resourceIBMISVPNGateway() *schema.Resource { +func ResourceIBMISVPNGateway() *schema.Resource { return &schema.Resource{ Create: resourceIBMISVPNGatewayCreate, Read: resourceIBMISVPNGatewayRead, @@ -52,7 +54,7 @@ func resourceIBMISVPNGateway() *schema.Resource { CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) + return flex.ResourceTagsCustomizeDiff(diff) }, ), @@ -62,7 +64,7 @@ func resourceIBMISVPNGateway() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, - ValidateFunc: InvokeValidator("ibm_is_route", isVPNGatewayName), + ValidateFunc: validate.InvokeValidator("ibm_is_route", isVPNGatewayName), Description: "VPN Gateway instance name", }, @@ -115,24 +117,24 @@ func resourceIBMISVPNGateway() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: InvokeValidator("ibm_is_vpn_gateway", "tag")}, - Set: resourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway", "tags")}, + Set: flex.ResourceIBMVPCHash, Description: "VPN Gateway tags list", }, - ResourceControllerURL: { + flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - ResourceName: { + flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - ResourceCRN: { + flex.ResourceCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the resource", @@ -144,13 +146,13 @@ func resourceIBMISVPNGateway() *schema.Resource { Description: "The crn of the resource", }, - ResourceStatus: { + flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - ResourceGroupName: { + flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", @@ -165,7 +167,7 @@ func resourceIBMISVPNGateway() *schema.Resource { Optional: true, ForceNew: true, Default: "route", - ValidateFunc: InvokeValidator("ibm_is_vpn_gateway", isVPNGatewayMode), + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway", isVPNGatewayMode), Description: "mode in VPN gateway(route/policy)", }, @@ -201,42 +203,85 @@ func resourceIBMISVPNGateway() *schema.Resource { }, }, }, + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "VPC for the VPN Gateway", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, }, } } -func resourceIBMISVPNGatewayValidator() *ResourceValidator { +func ResourceIBMISVPNGatewayValidator() *validate.ResourceValidator { modeCheckTypes := "route,policy" - validateSchema := make([]ValidateSchema, 0) + validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayMode, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Required: false, AllowedValues: modeCheckTypes}) validateSchema = append(validateSchema, - ValidateSchema{ - Identifier: "tag", - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Optional: true, Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) - ibmISVPNGatewayResourceValidator := ResourceValidator{ResourceName: "ibm_is_vpn_gateway", Schema: validateSchema} + ibmISVPNGatewayResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpn_gateway", Schema: validateSchema} return &ibmISVPNGatewayResourceValidator } @@ -283,18 +328,18 @@ func vpngwCreate(d *schema.ResourceData, meta interface{}, name, subnetID, mode } vpnGateway := vpnGatewayIntf.(*vpcv1.VPNGateway) + d.SetId(*vpnGateway.ID) + log.Printf("[INFO] VPNGateway : %s", *vpnGateway.ID) + _, err = isWaitForVpnGatewayAvailable(sess, *vpnGateway.ID, d.Timeout(schema.TimeoutCreate)) if err != nil { return err } - d.SetId(*vpnGateway.ID) - log.Printf("[INFO] VPNGateway : %s", *vpnGateway.ID) - v := os.Getenv("IC_ENV_TAGS") if _, ok := d.GetOk(isVPNGatewayTags); ok || v != "" { oldList, newList := d.GetChange(isVPNGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vpnGateway.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *vpnGateway.CRN) if err != nil { log.Printf( "Error on create of resource vpc VPN Gateway (%s) tags: %s", d.Id(), err) @@ -325,7 +370,7 @@ func isVpnGatewayRefreshFunc(vpnGateway *vpcv1.VpcV1, id string) resource.StateR } vpnGatewayIntf, response, err := vpnGateway.GetVPNGateway(getVpnGatewayOptions) if err != nil { - return nil, "", fmt.Errorf("Error Getting Vpn Gateway: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error Getting Vpn Gateway: %s\n%s", err, response) } vpnGateway := vpnGatewayIntf.(*vpcv1.VPNGateway) @@ -361,7 +406,7 @@ func vpngwGet(d *schema.ResourceData, meta interface{}, id string) error { d.SetId("") return nil } - return fmt.Errorf("Error Getting Vpn Gateway (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Vpn Gateway (%s): %s\n%s", id, err, response) } vpnGateway := vpnGatewayIntf.(*vpcv1.VPNGateway) @@ -385,23 +430,23 @@ func vpngwGet(d *schema.ResourceData, meta interface{}, id string) error { } } - tags, err := GetTagsUsingCRN(meta, *vpnGateway.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *vpnGateway.CRN) if err != nil { log.Printf( "Error on get of resource vpc VPN Gateway (%s) tags: %s", d.Id(), err) } d.Set(isVPNGatewayTags, tags) - controller, err := getBaseController(meta) + controller, err := flex.GetBaseController(meta) if err != nil { return err } - d.Set(ResourceControllerURL, controller+"/vpc/network/vpngateways") - d.Set(ResourceName, *vpnGateway.Name) - d.Set(ResourceCRN, *vpnGateway.CRN) + d.Set(flex.ResourceControllerURL, controller+"/vpc/network/vpngateways") + d.Set(flex.ResourceName, *vpnGateway.Name) + d.Set(flex.ResourceCRN, *vpnGateway.CRN) d.Set(isVPNGatewayCRN, *vpnGateway.CRN) - d.Set(ResourceStatus, *vpnGateway.Status) + d.Set(flex.ResourceStatus, *vpnGateway.Status) if vpnGateway.ResourceGroup != nil { - d.Set(ResourceGroupName, *vpnGateway.ResourceGroup.Name) + d.Set(flex.ResourceGroupName, *vpnGateway.ResourceGroup.Name) d.Set(isVPNGatewayResourceGroup, *vpnGateway.ResourceGroup.ID) } d.Set(isVPNGatewayMode, *vpnGateway.Mode) @@ -415,7 +460,7 @@ func vpngwGet(d *schema.ResourceData, meta interface{}, id string) error { currentMemberIP["status"] = *memberIP.Status vpcMembersIpsList = append(vpcMembersIpsList, currentMemberIP) } - if memberIP.PrivateIP != nil { + if memberIP.PrivateIP != nil && memberIP.PrivateIP.Address != nil { currentMemberIP["private_address"] = *memberIP.PrivateIP.Address } } @@ -424,6 +469,14 @@ func vpngwGet(d *schema.ResourceData, meta interface{}, id string) error { if vpnGateway.CreatedAt != nil { d.Set(isVPNGatewayCreatedAt, (vpnGateway.CreatedAt).String()) } + if vpnGateway.VPC != nil { + vpcList := []map[string]interface{}{} + vpcList = append(vpcList, dataSourceVPNServerCollectionVPNGatewayVpcReferenceToMap(vpnGateway.VPC)) + err = d.Set("vpc", vpcList) + if err != nil { + return fmt.Errorf("Error setting the vpc: %s", err) + } + } return nil } @@ -455,12 +508,12 @@ func vpngwUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasC } vpnGatewayIntf, response, err := sess.GetVPNGateway(getVpnGatewayOptions) if err != nil { - return fmt.Errorf("Error getting Volume : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error getting Volume : %s\n%s", err, response) } vpnGateway := vpnGatewayIntf.(*vpcv1.VPNGateway) oldList, newList := d.GetChange(isVPNGatewayTags) - err = UpdateTagsUsingCRN(oldList, newList, meta, *vpnGateway.CRN) + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *vpnGateway.CRN) if err != nil { log.Printf( "Error on update of resource vpc Vpn Gateway (%s) tags: %s", id, err) @@ -475,12 +528,12 @@ func vpngwUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasC } vpnGatewayPatch, err := vpnGatewayPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for VPNGatewayPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for VPNGatewayPatch: %s", err) } options.VPNGatewayPatch = vpnGatewayPatch _, response, err := sess.UpdateVPNGateway(options) if err != nil { - return fmt.Errorf("Error updating vpc Vpn Gateway: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating vpc Vpn Gateway: %s\n%s", err, response) } } return nil @@ -511,7 +564,7 @@ func vpngwDelete(d *schema.ResourceData, meta interface{}, id string) error { if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("Error Getting Vpn Gateway (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Vpn Gateway (%s): %s\n%s", id, err, response) } options := &vpcv1.DeleteVPNGatewayOptions{ @@ -519,7 +572,7 @@ func vpngwDelete(d *schema.ResourceData, meta interface{}, id string) error { } response, err = sess.DeleteVPNGateway(options) if err != nil { - return fmt.Errorf("Error Deleting Vpn Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Vpn Gateway : %s\n%s", err, response) } _, err = isWaitForVpnGatewayDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { @@ -554,7 +607,7 @@ func isVpnGatewayDeleteRefreshFunc(vpnGateway *vpcv1.VpcV1, id string) resource. if response != nil && response.StatusCode == 404 { return "", isVPNGatewayDeleted, nil } - return "", "", fmt.Errorf("Error Getting Vpn Gateway: %s\n%s", err, response) + return "", "", fmt.Errorf("[ERROR] Error Getting Vpn Gateway: %s\n%s", err, response) } return vpngw, isVPNGatewayDeleting, err } @@ -580,7 +633,7 @@ func vpngwExists(d *schema.ResourceData, meta interface{}, id string) (bool, err if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Vpn Gatewa: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Vpn Gatewa: %s\n%s", err, response) } return true, nil } diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go new file mode 100644 index 000000000..a059e3da9 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connection_test.go @@ -0,0 +1,486 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISVPNGatewayConnection_basic(t *testing.T) { + var VPNGatewayConnection string + vpcname1 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname1 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(10, 100)) + vpnname1 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(10, 100)) + + vpcname2 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname2 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(10, 100)) + vpnname2 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(10, 100)) + updname2 := fmt.Sprintf("tfvpngc-updatename-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayConnectionConfig(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, name2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name1), + resource.TestCheckResourceAttrSet( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "gateway_connection"), + ), + }, + { + Config: testAccCheckIBMISVPNGatewayConnectionUpdate(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, updname2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "name", updname2), + ), + }, + }, + }) +} + +func TestAccIBMISVPNGatewayConnection_route(t *testing.T) { + var VPNGatewayConnection string + vpcname1 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname1 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(100, 200)) + vpnname1 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(100, 200)) + name1 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(100, 200)) + + vpcname2 := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(100, 200)) + subnetname2 := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(100, 200)) + vpnname2 := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(100, 200)) + name2 := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(100, 200)) + updname2 := fmt.Sprintf("tfvpngc-updatename-%d", acctest.RandIntRange(100, 200)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayConnectionRouteConfig(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, name2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "mode", "route"), + ), + }, + { + Config: testAccCheckIBMISVPNGatewayConnectionRouteUpdate(vpcname1, subnetname1, vpnname1, name1, vpcname2, subnetname2, vpnname2, updname2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "name", updname2), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection2", "mode", "route"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVPNGatewayConnectionDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpn_gateway_connection" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + gID := parts[0] + gConnID := parts[1] + + getvpngcoptions := &vpcv1.GetVPNGatewayConnectionOptions{ + VPNGatewayID: &gID, + ID: &gConnID, + } + _, _, err1 := sess.GetVPNGatewayConnection(getvpngcoptions) + + if err1 == nil { + return fmt.Errorf("VPNGatewayConnection still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISVPNGatewayConnectionExists(n, vpngcID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + + gID := parts[0] + gConnID := parts[1] + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getvpngcoptions := &vpcv1.GetVPNGatewayConnectionOptions{ + VPNGatewayID: &gID, + ID: &gConnID, + } + foundvpngcIntf, res, err := sess.GetVPNGatewayConnection(getvpngcoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Getting VPN Gateway connection: %s\n%s", err, res) + } + foundvpngc := foundvpngcIntf.(*vpcv1.VPNGatewayConnection) + vpngcID = *foundvpngc.ID + return nil + } +} + +func testAccCheckIBMISVPNGatewayConnectionConfig(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc1.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet1.id}" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" + preshared_key = "VPNDemoPassword" + local_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] + peer_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] + + } + + resource "ibm_is_vpc" "testacc_vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet2" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc2.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet2.id}" + mode = "policy" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" + preshared_key = "VPNDemoPassword" + local_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] + peer_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] + + } + + `, vpc1, subnet1, acc.ISZoneName, acc.ISCIDR, vpnname1, name1, vpc2, subnet2, acc.ISZoneName, acc.ISCIDR, vpnname2, name2) + +} + +func testAccCheckIBMISVPNGatewayConnectionUpdate(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc1.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet1.id}" + mode = "policy" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" + preshared_key = "VPNDemoPassword" + local_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] + peer_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] + + } + + resource "ibm_is_vpc" "testacc_vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet2" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc2.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet2.id}" + mode = "policy" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" + preshared_key = "VPNDemoPassword" + local_cidrs = ["${ibm_is_subnet.testacc_subnet2.ipv4_cidr_block}"] + peer_cidrs = ["${ibm_is_subnet.testacc_subnet1.ipv4_cidr_block}"] + + } + + `, vpc1, subnet1, acc.ISZoneName, acc.ISCIDR, vpnname1, name1, vpc2, subnet2, acc.ISZoneName, acc.ISCIDR, vpnname2, name2) + +} + +func testAccCheckIBMISVPNGatewayConnectionRouteConfig(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc1" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc1.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet1.id}" + mode = "route" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" + preshared_key = "VPNDemoPassword" + } + resource "ibm_is_vpc" "testacc_vpc2" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet2" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc2.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet2.id}" + mode = "route" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" + preshared_key = "VPNDemoPassword" + } + `, vpc1, subnet1, acc.ISZoneName, acc.ISCIDR, vpnname1, name1, vpc2, subnet2, acc.ISZoneName, acc.ISCIDR, vpnname2, name2) + +} + +func testAccCheckIBMISVPNGatewayConnectionRouteUpdate(vpc1, subnet1, vpnname1, name1, vpc2, subnet2, vpnname2, name2 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc1" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc1.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet1.id}" + mode = "route" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address}" + preshared_key = "VPNDemoPassword" + } + resource "ibm_is_vpc" "testacc_vpc2" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet2" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc2.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway2" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet2.id}" + mode = "route" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection2" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway2.id}" + peer_address = "${ibm_is_vpn_gateway.testacc_VPNGateway2.public_ip_address}" + preshared_key = "VPNDemoPassword" + } + `, vpc1, subnet1, acc.ISZoneName, acc.ISCIDR, vpnname1, name1, vpc2, subnet2, acc.ISZoneName, acc.ISCIDR, vpnname2, name2) + +} + +func TestAccIBMISVPNGatewayConnection_ike_ipsec_null_patch(t *testing.T) { + var VPNGatewayConnection string + vpcname := fmt.Sprintf("tfvpngc-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngc-subnet-%d", acctest.RandIntRange(10, 100)) + vpnname := fmt.Sprintf("tfvpngc-vpn-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfvpngc-createname-%d", acctest.RandIntRange(10, 100)) + noNullPass := "" + nullPass := "null" + ikepolicyname := fmt.Sprintf("tfvpngc-ike-%d", acctest.RandIntRange(10, 100)) + ipsecpolicyname := fmt.Sprintf("tfvpngc-ipsec-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayConnectionNullPatchConfig(vpcname, subnetname, vpnname, ikepolicyname, ipsecpolicyname, name, noNullPass), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "gateway_connection"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.testacc_vpc1", "name", vpcname), + resource.TestCheckResourceAttr( + "ibm_is_subnet.testacc_subnet1", "name", subnetname), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_VPNGateway1", "name", vpnname), + resource.TestCheckResourceAttr( + "ibm_is_ike_policy.testacc_ike", "name", ikepolicyname), + resource.TestCheckResourceAttr( + "ibm_is_ipsec_policy.testacc_ipsec", "name", ipsecpolicyname), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "ike_policy"), + resource.TestCheckResourceAttrSet( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "ipsec_policy"), + ), + }, + { + Config: testAccCheckIBMISVPNGatewayConnectionNullPatchConfig(vpcname, subnetname, vpnname, ikepolicyname, ipsecpolicyname, name, nullPass), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayConnectionExists("ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", VPNGatewayConnection), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_vpc.testacc_vpc1", "name", vpcname), + resource.TestCheckResourceAttr( + "ibm_is_subnet.testacc_subnet1", "name", subnetname), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_VPNGateway1", "name", vpnname), + resource.TestCheckResourceAttr( + "ibm_is_ike_policy.testacc_ike", "name", ikepolicyname), + resource.TestCheckResourceAttr( + "ibm_is_ipsec_policy.testacc_ipsec", "name", ipsecpolicyname), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "ike_policy", ""), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway_connection.testacc_VPNGatewayConnection1", "ipsec_policy", ""), + ), + }, + }, + }) +} + +func testAccCheckIBMISVPNGatewayConnectionNullPatchConfig(vpc, subnet, vpnname, ikepolicyname, ipsecpolicyname, name, noNullPass string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet1" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc1.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_VPNGateway1" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet1.id}" + timeouts { + create = "18m" + delete = "18m" + } + } + resource "ibm_is_ike_policy" "testacc_ike" { + name = "%s" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + dh_group = 2 + ike_version = 1 + } + resource "ibm_is_ipsec_policy" "testacc_ipsec" { + name = "%s" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + pfs = "disabled" + } + resource "ibm_is_vpn_gateway_connection" "testacc_VPNGatewayConnection1" { + name = "%s" + vpn_gateway = "${ibm_is_vpn_gateway.testacc_VPNGateway1.id}" + preshared_key = "VPNDemoPassword" + peer_address = ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address != "0.0.0.0" ? ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address : ibm_is_vpn_gateway.testacc_VPNGateway1.public_ip_address2 + ike_policy = "%s" == "null" ? "" : ibm_is_ike_policy.testacc_ike.id + ipsec_policy = "%s" == "null" ? "" : ibm_is_ipsec_policy.testacc_ipsec.id + } + + `, vpc, subnet, acc.ISZoneName, acc.ISCIDR, vpnname, ikepolicyname, ipsecpolicyname, name, noNullPass, noNullPass) + +} diff --git a/ibm/resource_ibm_is_vpn_gateway_connections.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go similarity index 82% rename from ibm/resource_ibm_is_vpn_gateway_connections.go rename to ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go index 84139cc09..8d6ed56da 100644 --- a/ibm/resource_ibm_is_vpn_gateway_connections.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_connections.go @@ -1,13 +1,15 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package vpc import ( "fmt" "log" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -39,7 +41,7 @@ const ( isVPNGatewayConnectionCreatedat = "created_at" ) -func resourceIBMISVPNGatewayConnection() *schema.Resource { +func ResourceIBMISVPNGatewayConnection() *schema.Resource { return &schema.Resource{ Create: resourceIBMISVPNGatewayConnectionCreate, Read: resourceIBMISVPNGatewayConnectionRead, @@ -57,7 +59,7 @@ func resourceIBMISVPNGatewayConnection() *schema.Resource { isVPNGatewayConnectionName: { Type: schema.TypeString, Required: true, - ValidateFunc: InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionName), + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionName), Description: "VPN Gateway connection name", }, @@ -109,21 +111,21 @@ func resourceIBMISVPNGatewayConnection() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "restart", - ValidateFunc: InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionAction), + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionAction), Description: "Action detection for dead peer detection action", }, isVPNGatewayConnectionDeadPeerDetectionInterval: { Type: schema.TypeInt, Optional: true, Default: 2, - ValidateFunc: InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionInterval), + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionInterval), Description: "Interval for dead peer detection interval", }, isVPNGatewayConnectionDeadPeerDetectionTimeout: { Type: schema.TypeInt, Optional: true, Default: 10, - ValidateFunc: InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionTimeout), + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_gateway_connection", isVPNGatewayConnectionDeadPeerDetectionTimeout), Description: "Timeout for dead peer detection", }, @@ -151,7 +153,7 @@ func resourceIBMISVPNGatewayConnection() *schema.Resource { Description: "VPN gateway connection status", }, - RelatedCRN: { + flex.RelatedCRN: { Type: schema.TypeString, Computed: true, Description: "The crn of the VPN Gateway resource", @@ -205,43 +207,43 @@ func resourceIBMISVPNGatewayConnection() *schema.Resource { } } -func resourceIBMISVPNGatewayConnectionValidator() *ResourceValidator { - validateSchema := make([]ValidateSchema, 0) +func ResourceIBMISVPNGatewayConnectionValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) action := "restart, clear, hold, none" validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayConnectionName, - ValidateFunctionIdentifier: ValidateRegexpLen, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, Required: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayConnectionDeadPeerDetectionAction, - ValidateFunctionIdentifier: ValidateAllowedStringValue, - Type: TypeString, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, Optional: true, AllowedValues: action}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayConnectionDeadPeerDetectionInterval, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "1", MaxValue: "86399"}) validateSchema = append(validateSchema, - ValidateSchema{ + validate.ValidateSchema{ Identifier: isVPNGatewayConnectionDeadPeerDetectionTimeout, - ValidateFunctionIdentifier: IntBetween, - Type: TypeInt, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, MinValue: "2", MaxValue: "86399"}) - ibmISVPNGatewayConnectionResourceValidator := ResourceValidator{ResourceName: "ibm_is_vpn_gateway_connection", Schema: validateSchema} + ibmISVPNGatewayConnectionResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpn_gateway_connection", Schema: validateSchema} return &ibmISVPNGatewayConnectionResourceValidator } @@ -306,11 +308,11 @@ func vpngwconCreate(d *schema.ResourceData, meta interface{}, name, gatewayID, p } if _, ok := d.GetOk(isVPNGatewayConnectionLocalCIDRS); ok { - localCidrs := expandStringList((d.Get(isVPNGatewayConnectionLocalCIDRS).(*schema.Set)).List()) + localCidrs := flex.ExpandStringList((d.Get(isVPNGatewayConnectionLocalCIDRS).(*schema.Set)).List()) vpnGatewayConnectionPrototypeModel.LocalCIDRs = localCidrs } if _, ok := d.GetOk(isVPNGatewayConnectionPeerCIDRS); ok { - peerCidrs := expandStringList((d.Get(isVPNGatewayConnectionPeerCIDRS).(*schema.Set)).List()) + peerCidrs := flex.ExpandStringList((d.Get(isVPNGatewayConnectionPeerCIDRS).(*schema.Set)).List()) vpnGatewayConnectionPrototypeModel.PeerCIDRs = peerCidrs } @@ -318,7 +320,7 @@ func vpngwconCreate(d *schema.ResourceData, meta interface{}, name, gatewayID, p if ikePolicy, ok := d.GetOk(isVPNGatewayConnectionIKEPolicy); ok { ikePolicyIdentity = ikePolicy.(string) - vpnGatewayConnectionPrototypeModel.IkePolicy = &vpcv1.IkePolicyIdentity{ + vpnGatewayConnectionPrototypeModel.IkePolicy = &vpcv1.VPNGatewayConnectionIkePolicyPrototype{ ID: &ikePolicyIdentity, } } else { @@ -326,7 +328,7 @@ func vpngwconCreate(d *schema.ResourceData, meta interface{}, name, gatewayID, p } if ipsecPolicy, ok := d.GetOk(isVPNGatewayConnectionIPSECPolicy); ok { ipsecPolicyIdentity = ipsecPolicy.(string) - vpnGatewayConnectionPrototypeModel.IpsecPolicy = &vpcv1.IPsecPolicyIdentity{ + vpnGatewayConnectionPrototypeModel.IpsecPolicy = &vpcv1.VPNGatewayConnectionIPsecPolicyPrototype{ ID: &ipsecPolicyIdentity, } } else { @@ -345,7 +347,7 @@ func vpngwconCreate(d *schema.ResourceData, meta interface{}, name, gatewayID, p func resourceIBMISVPNGatewayConnectionRead(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -375,7 +377,7 @@ func vpngwconGet(d *schema.ResourceData, meta interface{}, gID, gConnID string) d.SetId("") return nil } - return fmt.Errorf("Error Getting Vpn Gateway Connection (%s): %s\n%s", gConnID, err, response) + return fmt.Errorf("[ERROR] Error Getting Vpn Gateway Connection (%s): %s\n%s", gConnID, err, response) } d.Set(isVPNGatewayConnection, gConnID) vpnGatewayConnection := vpnGatewayConnectionIntf.(*vpcv1.VPNGatewayConnection) @@ -386,10 +388,10 @@ func vpngwconGet(d *schema.ResourceData, meta interface{}, gID, gConnID string) d.Set(isVPNGatewayConnectionPreSharedKey, *vpnGatewayConnection.Psk) if vpnGatewayConnection.LocalCIDRs != nil { - d.Set(isVPNGatewayConnectionLocalCIDRS, flattenStringList(vpnGatewayConnection.LocalCIDRs)) + d.Set(isVPNGatewayConnectionLocalCIDRS, flex.FlattenStringList(vpnGatewayConnection.LocalCIDRs)) } if vpnGatewayConnection.PeerCIDRs != nil { - d.Set(isVPNGatewayConnectionPeerCIDRS, flattenStringList(vpnGatewayConnection.PeerCIDRs)) + d.Set(isVPNGatewayConnectionPeerCIDRS, flex.FlattenStringList(vpnGatewayConnection.PeerCIDRs)) } if vpnGatewayConnection.IkePolicy != nil { d.Set(isVPNGatewayConnectionIKEPolicy, *vpnGatewayConnection.IkePolicy.ID) @@ -437,17 +439,17 @@ func vpngwconGet(d *schema.ResourceData, meta interface{}, gID, gConnID string) } vpngatewayIntf, response, err := sess.GetVPNGateway(getVPNGatewayOptions) if err != nil { - return fmt.Errorf("Error Getting VPN Gateway : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Getting VPN Gateway : %s\n%s", err, response) } vpngateway := vpngatewayIntf.(*vpcv1.VPNGateway) - d.Set(RelatedCRN, *vpngateway.CRN) + d.Set(flex.RelatedCRN, *vpngateway.CRN) return nil } func resourceIBMISVPNGatewayConnectionUpdate(d *schema.ResourceData, meta interface{}) error { hasChanged := false - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -495,19 +497,24 @@ func vpngwconUpdate(d *schema.ResourceData, meta interface{}, gID, gConnID strin interval := int64(d.Get(isVPNGatewayConnectionDeadPeerDetectionInterval).(int)) timeout := int64(d.Get(isVPNGatewayConnectionDeadPeerDetectionTimeout).(int)) - // Construct an instance of the VPNGatewayConnectionDpdPrototype model - vpnGatewayConnectionDpdPrototypeModel := new(vpcv1.VPNGatewayConnectionDpdPrototype) - vpnGatewayConnectionDpdPrototypeModel.Action = &action - vpnGatewayConnectionDpdPrototypeModel.Interval = &interval - vpnGatewayConnectionDpdPrototypeModel.Timeout = &timeout - vpnGatewayConnectionPatchModel.DeadPeerDetection = vpnGatewayConnectionDpdPrototypeModel + // Construct an instance of the VPNGatewayConnectionDpdPatch model + vpnGatewayConnectionDpdPatchModel := new(vpcv1.VPNGatewayConnectionDpdPatch) + vpnGatewayConnectionDpdPatchModel.Action = &action + vpnGatewayConnectionDpdPatchModel.Interval = &interval + vpnGatewayConnectionDpdPatchModel.Timeout = &timeout + vpnGatewayConnectionPatchModel.DeadPeerDetection = vpnGatewayConnectionDpdPatchModel hasChanged = true } if d.HasChange(isVPNGatewayConnectionIKEPolicy) { ikePolicyIdentity := d.Get(isVPNGatewayConnectionIKEPolicy).(string) - vpnGatewayConnectionPatchModel.IkePolicy = &vpcv1.IkePolicyIdentity{ - ID: &ikePolicyIdentity, + if ikePolicyIdentity == "" { + var nullPatch *vpcv1.VPNGatewayConnectionIkePolicyPatch + vpnGatewayConnectionPatchModel.IkePolicy = nullPatch + } else { + vpnGatewayConnectionPatchModel.IkePolicy = &vpcv1.VPNGatewayConnectionIkePolicyPatch{ + ID: &ikePolicyIdentity, + } } hasChanged = true } else { @@ -516,8 +523,13 @@ func vpngwconUpdate(d *schema.ResourceData, meta interface{}, gID, gConnID strin if d.HasChange(isVPNGatewayConnectionIPSECPolicy) { ipsecPolicyIdentity := d.Get(isVPNGatewayConnectionIPSECPolicy).(string) - vpnGatewayConnectionPatchModel.IpsecPolicy = &vpcv1.IPsecPolicyIdentity{ - ID: &ipsecPolicyIdentity, + if ipsecPolicyIdentity == "" { + var nullPatch *vpcv1.VPNGatewayConnectionIPsecPolicyPatch + vpnGatewayConnectionPatchModel.IpsecPolicy = nullPatch + } else { + vpnGatewayConnectionPatchModel.IpsecPolicy = &vpcv1.VPNGatewayConnectionIPsecPolicyPatch{ + ID: &ipsecPolicyIdentity, + } } hasChanged = true } else { @@ -533,12 +545,12 @@ func vpngwconUpdate(d *schema.ResourceData, meta interface{}, gID, gConnID strin if hasChanged { vpnGatewayConnectionPatch, err := vpnGatewayConnectionPatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for VPNGatewayConnectionPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for VPNGatewayConnectionPatch: %s", err) } updateVpnGatewayConnectionOptions.VPNGatewayConnectionPatch = vpnGatewayConnectionPatch _, response, err := sess.UpdateVPNGatewayConnection(updateVpnGatewayConnectionOptions) if err != nil { - return fmt.Errorf("Error updating Vpn Gateway Connection: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating Vpn Gateway Connection: %s\n%s", err, response) } } return nil @@ -546,7 +558,7 @@ func vpngwconUpdate(d *schema.ResourceData, meta interface{}, gID, gConnID strin func resourceIBMISVPNGatewayConnectionDelete(d *schema.ResourceData, meta interface{}) error { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return err } @@ -577,7 +589,7 @@ func vpngwconDelete(d *schema.ResourceData, meta interface{}, gID, gConnID strin d.SetId("") return nil } - return fmt.Errorf("Error Getting Vpn Gateway Connection(%s): %s\n%s", gConnID, err, response) + return fmt.Errorf("[ERROR] Error Getting Vpn Gateway Connection(%s): %s\n%s", gConnID, err, response) } deleteVpnGatewayConnectionOptions := &vpcv1.DeleteVPNGatewayConnectionOptions{ @@ -586,13 +598,12 @@ func vpngwconDelete(d *schema.ResourceData, meta interface{}, gID, gConnID strin } response, err = sess.DeleteVPNGatewayConnection(deleteVpnGatewayConnectionOptions) if err != nil { - return fmt.Errorf("Error Deleting Vpn Gateway Connection : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error Deleting Vpn Gateway Connection : %s\n%s", err, response) } _, err = isWaitForVPNGatewayConnectionDeleted(sess, gID, gConnID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf( - "Error checking for Vpn Gateway Connection (%s) is deleted: %s", gConnID, err) + return fmt.Errorf("[ERROR] Error checking for Vpn Gateway Connection (%s) is deleted: %s", gConnID, err) } d.SetId("") @@ -625,7 +636,7 @@ func isVPNGatewayConnectionDeleteRefreshFunc(vpnGatewayConnection *vpcv1.VpcV1, if response != nil && response.StatusCode == 404 { return "", isVPNGatewayConnectionDeleted, nil } - return "", "", fmt.Errorf("The Vpn Gateway Connection %s failed to delete: %s\n%s", gConnID, err, response) + return "", "", fmt.Errorf("[ERROR] The Vpn Gateway Connection %s failed to delete: %s\n%s", gConnID, err, response) } return vpngwcon, isVPNGatewayConnectionDeleting, nil } @@ -633,12 +644,12 @@ func isVPNGatewayConnectionDeleteRefreshFunc(vpnGatewayConnection *vpcv1.VpcV1, func resourceIBMISVPNGatewayConnectionExists(d *schema.ResourceData, meta interface{}) (bool, error) { - parts, err := idParts(d.Id()) + parts, err := flex.IdParts(d.Id()) if err != nil { return false, err } if len(parts) != 2 { - return false, fmt.Errorf("Incorrect ID %s: ID should be a combination of gID/gConnID", d.Id()) + return false, fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of gID/gConnID", d.Id()) } gID := parts[0] @@ -662,7 +673,7 @@ func vpngwconExists(d *schema.ResourceData, meta interface{}, gID, gConnID strin if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("Error getting Vpn Gateway Connection: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Vpn Gateway Connection: %s\n%s", err, response) } return true, nil } diff --git a/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go new file mode 100644 index 000000000..dbec6075d --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway_test.go @@ -0,0 +1,242 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "regexp" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISVPNGateway_basic(t *testing.T) { + var vpnGateway string + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayConfig(vpcname, subnetname, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name1), + ), + }, + }, + }) +} + +func TestAccIBMISVPNGateway_route(t *testing.T) { + var vpnGateway string + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayRouteConfig(vpcname, subnetname, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name1), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_vpnGateway", "mode", "route"), + ), + }, + { + Config: testAccCheckIBMISVPNGatewayRouteConfig(vpcname, subnetname, name1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("ibm_is_vpn_gateway.testacc_vpnGateway", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_gateway.testacc_vpnGateway", "vpc.0.name"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_gateway.testacc_vpnGateway", "vpc.0.crn"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_gateway.testacc_vpnGateway", "vpc.0.href"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_gateway.testacc_vpnGateway", "vpc.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVPNGatewayDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpn_gateway" { + continue + } + + getvpngcptions := &vpcv1.GetVPNGatewayConnectionOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetVPNGatewayConnection(getvpngcptions) + + if err == nil { + return fmt.Errorf("vpnGateway still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISVPNGatewayExists(n, vpnGatewayID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getvpngcptions := &vpcv1.GetVPNGatewayOptions{ + ID: &rs.Primary.ID, + } + foundvpnGatewayIntf, _, err := sess.GetVPNGateway(getvpngcptions) + if err != nil { + return err + } + foundvpnGateway := foundvpnGatewayIntf.(*vpcv1.VPNGateway) + vpnGatewayID = *foundvpnGateway.ID + return nil + } +} + +func testAccCheckIBMISVPNGatewayConfig(vpc, subnet, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + mode = "policy" + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) + +} + +func testAccCheckIBMISVPNGatewayRouteConfig(vpc, subnet, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + mode = "route" + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) + +} + +func testAccCheckIBMISVPNGatewayTaintConfig(vpc, subnet, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + mode = "policy" + timeouts{ + create = "2m" + } + lifecycle { + create_before_destroy = true + } + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) + +} +func testAccCheckIBMISVPNGatewayTaintConfig2(vpc, subnet, name string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + zone = "%s" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_vpn_gateway" "testacc_vpnGateway" { + name = "%s" + subnet = "${ibm_is_subnet.testacc_subnet.id}" + mode = "policy" + timeouts{ + create = "12m" + } + lifecycle { + create_before_destroy = true + } + }`, vpc, subnet, acc.ISZoneName, acc.ISCIDR, name) + +} + +func TestAccIBMISVPNGateway_taint(t *testing.T) { + var vpnGateway string + vpcname := fmt.Sprintf("tfvpnuat-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpnuat-subnet-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfvpnuat-taintname-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfvpnuat-createname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPNGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVPNGatewayTaintConfig(vpcname, subnetname, name1), + ExpectError: regexp.MustCompile(fmt.Sprintf("timeout while waiting for state to become 'done,")), + }, + { + Config: testAccCheckIBMISVPNGatewayTaintConfig2(vpcname, subnetname, name2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPNGatewayExists("ibm_is_vpn_gateway.testacc_vpnGateway", vpnGateway), + resource.TestCheckResourceAttr( + "ibm_is_vpn_gateway.testacc_vpnGateway", "name", name2), + ), + }, + }, + }) +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_server.go b/ibm/service/vpc/resource_ibm_is_vpn_server.go new file mode 100644 index 000000000..3660a90e2 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_server.go @@ -0,0 +1,925 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isVPNServerStatusPending = "pending" + isVPNServerStatusUpdating = "updating" + isVPNServerStatusStable = "stable" + isVPNServerStatusFailed = "failed" + + isVPNServerStatusDeleting = "deleting" + isVPNServerStatusDeleted = "deleted" +) + +func ResourceIBMIsVPNServer() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVPNServerCreate, + ReadContext: resourceIBMIsVPNServerRead, + UpdateContext: resourceIBMIsVPNServerUpdate, + DeleteContext: resourceIBMIsVPNServerDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "certificate_crn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + Description: "The crn of certificate instance for this VPN server.", + }, + "client_authentication": &schema.Schema{ + Type: schema.TypeList, + Required: true, + ForceNew: false, + MaxItems: 2, + Description: "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "method": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"certificate", "username"}), + Description: "The type of authentication.", + }, + "identity_provider": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"iam"}), + Description: "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + }, + "client_ca_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The crn of certificate instance to use for the VPN client certificate authority (CA).", + }, + }, + }, + }, + "client_auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + }, + "client_auto_delete_timeout": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + }, + "client_dns_server_ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The DNS server addresses that will be provided to VPN clients connected to this VPN server. The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "client_idle_timeout": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 600, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server", "client_idle_timeout"), + Description: "The seconds a VPN client can be idle before this VPN server will disconnect it. Specify `0` to prevent the server from disconnecting idle clients.", + }, + "client_ip_pool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server", "client_ip_pool"), + Description: "The VPN client IPv4 address pool, expressed in CIDR format. The request must not overlap with any existing address prefixes in the VPC or any of the following reserved address ranges: - `127.0.0.0/8` (IPv4 loopback addresses) - `161.26.0.0/16` (IBM services) - `166.8.0.0/14` (Cloud Service Endpoints) - `169.254.0.0/16` (IPv4 link-local addresses) - `224.0.0.0/4` (IPv4 multicast addresses)The prefix length of the client IP address pool's CIDR must be between`/9` (8,388,608 addresses) and `/22` (1024 addresses). A CIDR block that contains twice the number of IP addresses that are required to enable the maximum number of concurrent connections is recommended.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN server was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPN server.", + }, + "enable_split_tunneling": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Indicates whether the split tunneling is enabled on this VPN server.", + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + }, + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Fully qualified domain name assigned to this VPN server.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN server.", + }, + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPN server.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN server.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server", "name"), + Description: "The user-defined name for this VPN server. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPC this VPN server is serving.", + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 443, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server", "port"), + Description: "The port number to use for this VPN server.", + }, + "private_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reserved IPs bound to this VPN server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The user-defined or system-provided name for this reserved IP.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + + "protocol": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "udp", + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server", "protocol"), + Description: "The transport protocol to use for this VPN server.", + }, + + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The unique identifier for this resource group. The resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + }, + + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The unique identifier for this security group. The security groups to use for this VPN server. If unspecified, the VPC's default security group is used.", + }, + + "subnets": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 2, + // ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The unique identifier for this subnet. The subnets to provision this VPN server in. Use subnets in different zones for high availability.", + }, + + "vpc": { + Type: schema.TypeList, + Computed: true, + Description: "The VPC this VPN server resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "deleted": { + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPC.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this VPC.", + }, + }, + }, + }, + + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Default: "vpn_server", + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"vpn_server"}), + Description: "The type of resource referenced.", + }, + + "version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsVPNServerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "client_ip_pool", + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Required: true, + Regexp: `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$`, + }, + validate.ValidateSchema{ + Identifier: "client_idle_timeout", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "0", + MaxValue: "28800", + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "port", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "65535", + }, + validate.ValidateSchema{ + Identifier: "protocol", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "tcp, udp", + }, + validate.ValidateSchema{ + Identifier: "method", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "certificate , username"}, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpn_server", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsVPNServerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createVPNServerOptions := &vpcv1.CreateVPNServerOptions{} + crn_val := d.Get("certificate_crn").(string) + certificateInstanceIdentity := &vpcv1.CertificateInstanceIdentity{} + certificateInstanceIdentity.CRN = &crn_val + createVPNServerOptions.Certificate = certificateInstanceIdentity + + var clientAuthentication []vpcv1.VPNServerAuthenticationPrototypeIntf + clientAuthArray := d.Get("client_authentication").([]interface{}) + for _, clientauth := range clientAuthArray { + clientAuth := clientauth.(map[string]interface{}) + method := clientAuth["method"].(string) + clientAuthPrototype := &vpcv1.VPNServerAuthenticationPrototype{} + clientAuthPrototype.Method = &method + + if method == "certificate" { + if clientAuth["client_ca_crn"] != nil { + crn_val := clientAuth["client_ca_crn"].(string) + certificateInstanceIdentity := &vpcv1.CertificateInstanceIdentity{} + certificateInstanceIdentity.CRN = &crn_val + clientAuthPrototype.ClientCa = certificateInstanceIdentity + + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error method type `certificate` should be passed with `client_ca_crn`")) + } + } else { + if clientAuth["identity_provider"] != nil { + providerType := clientAuth["identity_provider"].(string) + clientAuthPrototype.IdentityProvider = &vpcv1.VPNServerAuthenticationByUsernameIDProvider{ + ProviderType: &providerType, + } + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error method type `username` should be passed with `identity_provider`")) + } + + } + clientAuthentication = append(clientAuthentication, clientAuthPrototype) + } + createVPNServerOptions.ClientAuthentication = clientAuthentication + + if _, ok := d.GetOk("client_dns_server_ips"); ok { + var clientDnsServerIps []vpcv1.IP + clientDnsServerIpsArray := d.Get("client_dns_server_ips").(*schema.Set) + for _, val := range clientDnsServerIpsArray.List() { + value := val.(string) + address := &vpcv1.IP{ + Address: &value, + } + clientDnsServerIps = append(clientDnsServerIps, *address) + } + createVPNServerOptions.SetClientDnsServerIps(clientDnsServerIps) + } + + if _, ok := d.GetOk("client_idle_timeout"); ok { + createVPNServerOptions.SetClientIdleTimeout(int64(d.Get("client_idle_timeout").(int))) + } + + createVPNServerOptions.SetClientIPPool(d.Get("client_ip_pool").(string)) + + if _, ok := d.GetOk("enable_split_tunneling"); ok { + createVPNServerOptions.SetEnableSplitTunneling(d.Get("enable_split_tunneling").(bool)) + } + + if _, ok := d.GetOk("name"); ok { + createVPNServerOptions.SetName(d.Get("name").(string)) + } + + if _, ok := d.GetOk("port"); ok { + createVPNServerOptions.SetPort(int64(d.Get("port").(int))) + } + + if _, ok := d.GetOk("protocol"); ok { + createVPNServerOptions.SetProtocol(d.Get("protocol").(string)) + } + + if rg, ok := d.GetOk("resource_group"); ok { + resourceGroup := rg.(string) + createVPNServerOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &resourceGroup, + } + } + + if _, ok := d.GetOk("security_groups"); ok { + sg := d.Get("security_groups").(*schema.Set) + var securityGroups []vpcv1.SecurityGroupIdentityIntf + for _, val := range sg.List() { + value := val.(string) + securityGroupIdentity := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupIdentity) + } + createVPNServerOptions.SetSecurityGroups(securityGroups) + } + + var subnets []vpcv1.SubnetIdentityIntf + subnetsArray := d.Get("subnets").(*schema.Set) + for _, val := range subnetsArray.List() { + value := val.(string) + subnetIdentity := &vpcv1.SubnetIdentity{ + ID: &value, + } + subnets = append(subnets, subnetIdentity) + } + createVPNServerOptions.SetSubnets(subnets) + + vpnServer, response, err := sess.CreateVPNServerWithContext(context, createVPNServerOptions) + if err != nil { + log.Printf("[DEBUG] CreateVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] CreateVPNServerWithContext failed %s\n%s", err, response)) + } + + d.SetId(*vpnServer.ID) + + _, err = isWaitForVPNServerStable(context, sess, d, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer failed %s\n", err)) + } + + return resourceIBMIsVPNServerRead(context, d, meta) +} + +func isWaitForVPNServerStable(context context.Context, sess *vpcv1.VpcV1, d *schema.ResourceData, timeout time.Duration) (interface{}, error) { + + log.Printf("Waiting for VPN Server(%s) to be stable.", d.Id()) + stateConf := &resource.StateChangeConf{ + Pending: []string{isVPNServerStatusPending, isVPNServerStatusUpdating}, + Target: []string{isVPNServerStatusStable, isVPNServerStatusFailed}, + Refresh: func() (interface{}, string, error) { + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + + getVPNServerOptions.SetID(d.Id()) + + vpnServer, response, err := sess.GetVPNServerWithContext(context, getVPNServerOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerWithContext failed %s\n%s", err, response) + return vpnServer, "", fmt.Errorf("Error Getting VPC Server: %s\n%s", err, response) + } + + if *vpnServer.LifecycleState == "stable" || *vpnServer.LifecycleState == "failed" { + return vpnServer, *vpnServer.LifecycleState, nil + } + return vpnServer, *vpnServer.LifecycleState, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func resourceIBMIsVPNServerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + + getVPNServerOptions.SetID(d.Id()) + + vpnServer, response, err := sess.GetVPNServerWithContext(context, getVPNServerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("vpn_server", d.Id()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpn_server: %s", err)) + } + + if err = d.Set("certificate_crn", *vpnServer.Certificate.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting certificate: %s", err)) + } + + vpnServerAuthenticationPrototypeArray := make([]interface{}, len(vpnServer.ClientAuthentication)) + for i, clientAuthenticationItem := range vpnServer.ClientAuthentication { + vpnServerAuthenticationPrototype := make(map[string]interface{}) + vpnServerAuthentication := clientAuthenticationItem.(*vpcv1.VPNServerAuthentication) + if vpnServerAuthentication != nil { + if vpnServerAuthentication.Method != nil { + vpnServerAuthenticationPrototype["method"] = *vpnServerAuthentication.Method + if vpnServerAuthentication.ClientCa != nil && vpnServerAuthentication.ClientCa.CRN != nil { + vpnServerAuthenticationPrototype["client_ca_crn"] = *vpnServerAuthentication.ClientCa.CRN + } + if vpnServerAuthentication.IdentityProvider != nil { + vpnServerAuthenticationByUsernameIDProvider := vpnServerAuthentication.IdentityProvider.(*vpcv1.VPNServerAuthenticationByUsernameIDProvider) + vpnServerAuthenticationPrototype["identity_provider"] = *vpnServerAuthenticationByUsernameIDProvider.ProviderType + } + } + } + vpnServerAuthenticationPrototypeArray[i] = vpnServerAuthenticationPrototype + } + if err = d.Set("client_authentication", vpnServerAuthenticationPrototypeArray); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_authentication: %s", err)) + } + + if err = d.Set("client_ip_pool", *vpnServer.ClientIPPool); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_ip_pool: %s", err)) + } + + subnets := make([]string, 0) + for i := 0; i < len(vpnServer.Subnets); i++ { + subnets = append(subnets, string(*(vpnServer.Subnets[i].ID))) + } + if err = d.Set("subnets", subnets); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnets: %s", err)) + } + + if vpnServer.ClientDnsServerIps != nil { + // clientDnsServerIps := []map[string]interface{}{} + clientDnsServerIps := make([]string, 0) + for _, clientDnsServerIpsItem := range vpnServer.ClientDnsServerIps { + if clientDnsServerIpsItem.Address != nil { + clientDnsServerIps = append(clientDnsServerIps, *clientDnsServerIpsItem.Address) + } + } + if err = d.Set("client_dns_server_ips", clientDnsServerIps); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_dns_server_ips: %s", err)) + } + } + if err = d.Set("client_idle_timeout", flex.IntValue(vpnServer.ClientIdleTimeout)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_idle_timeout: %s", err)) + } + if err = d.Set("enable_split_tunneling", vpnServer.EnableSplitTunneling); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enable_split_tunneling: %s", err)) + } + if err = d.Set("name", vpnServer.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("port", flex.IntValue(vpnServer.Port)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port: %s", err)) + } + if err = d.Set("protocol", vpnServer.Protocol); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting protocol: %s", err)) + } + if vpnServer.ResourceGroup != nil && vpnServer.ResourceGroup.ID != nil { + if err = d.Set("resource_group", vpnServer.ResourceGroup.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + } + if vpnServer.SecurityGroups != nil { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range vpnServer.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + if err = d.Set("security_groups", securityGroups); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting security_groups: %s", err)) + } + } + if err = d.Set("client_auto_delete", vpnServer.ClientAutoDelete); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_auto_delete: %s", err)) + } + if err = d.Set("client_auto_delete_timeout", flex.IntValue(vpnServer.ClientAutoDeleteTimeout)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting client_auto_delete_timeout: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnServer.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", vpnServer.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("health_state", vpnServer.HealthState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting health_state: %s", err)) + } + if err = d.Set("hostname", vpnServer.Hostname); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting hostname: %s", err)) + } + if err = d.Set("href", vpnServer.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", vpnServer.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + privateIps := []map[string]interface{}{} + for _, privateIpsItem := range vpnServer.PrivateIps { + privateIpsItemMap := resourceIBMIsVPNServerReservedIPReferenceToMap(privateIpsItem) + privateIps = append(privateIps, privateIpsItemMap) + } + if err = d.Set("private_ips", privateIps); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting private_ips: %s", err)) + } + + if vpnServer.VPC != nil { + err = d.Set("vpc", dataSourceVPNServerFlattenVpcReference(vpnServer.VPC)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting the vpc: %s", err)) + } + } + + if err = d.Set("resource_type", vpnServer.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + if err = d.Set("version", response.Headers.Get("Etag")); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting version: %s", err)) + } + + return nil +} + +func resourceIBMIsVPNServerReservedIPReferenceToMap(reservedIPReference vpcv1.ReservedIPReference) map[string]interface{} { + reservedIPReferenceMap := map[string]interface{}{} + + reservedIPReferenceMap["address"] = reservedIPReference.Address + if reservedIPReference.Deleted != nil { + DeletedMap := resourceIBMIsVPNServerReservedIPReferenceDeletedToMap(*reservedIPReference.Deleted) + reservedIPReferenceMap["deleted"] = []map[string]interface{}{DeletedMap} + } + reservedIPReferenceMap["href"] = reservedIPReference.Href + reservedIPReferenceMap["id"] = reservedIPReference.ID + reservedIPReferenceMap["name"] = reservedIPReference.Name + reservedIPReferenceMap["resource_type"] = reservedIPReference.ResourceType + + return reservedIPReferenceMap +} + +func resourceIBMIsVPNServerReservedIPReferenceDeletedToMap(reservedIPReferenceDeleted vpcv1.ReservedIPReferenceDeleted) map[string]interface{} { + reservedIPReferenceDeletedMap := map[string]interface{}{} + + reservedIPReferenceDeletedMap["more_info"] = reservedIPReferenceDeleted.MoreInfo + + return reservedIPReferenceDeletedMap +} + +func resourceIBMIsVPNServerVPCReference(result *vpcv1.VPCReference) (vpcs []map[string]interface{}) { + vpcs = append(vpcs, resourceIBMIsVPNServerVPCReferenceToMap(*result)) + return vpcs +} + +func resourceIBMIsVPNServerVPCReferenceToMap(vpcRef vpcv1.VPCReference) map[string]interface{} { + vpcMap := map[string]interface{}{} + vpcMap["crn"] = vpcRef.CRN + if vpcRef.Deleted != nil { + deletedMap := resourceIBMIsVPNServerVPCReferenceDeletedToMap(*vpcRef.Deleted) + // vpcMap["deleted"] = []map[string]interface{}{deletedMap} + vpcMap["deleted"] = deletedMap + } + vpcMap["href"] = vpcRef.Href + vpcMap["name"] = vpcRef.Name + return vpcMap +} + +func resourceIBMIsVPNServerVPCReferenceDeletedToMap(vpcRefDeleted vpcv1.VPCReferenceDeleted) map[string]interface{} { + vpcRefDeletedMap := map[string]interface{}{} + vpcRefDeletedMap["more_info"] = vpcRefDeleted.MoreInfo + return vpcRefDeletedMap +} + +func resourceIBMIsVPNServerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + updateVPNServerOptions := &vpcv1.UpdateVPNServerOptions{} + updateVPNServerOptions.SetID(d.Id()) + hasChange := false + + patchVals := &vpcv1.VPNServerPatch{} + if d.HasChange("certificate_crn") { + crn_val := d.Get("certificate_crn").(string) + + certificateInstanceIdentity := &vpcv1.CertificateInstanceIdentity{} + certificateInstanceIdentity.CRN = &crn_val + patchVals.Certificate = certificateInstanceIdentity + hasChange = true + } + + if d.HasChange("client_authentication") { + var clientAuthentication []vpcv1.VPNServerAuthenticationPrototypeIntf + clientAuthArray := d.Get("client_authentication").([]interface{}) + for _, clientauth := range clientAuthArray { + clientAuth := clientauth.(map[string]interface{}) + method := clientAuth["method"].(string) + clientAuthPrototype := &vpcv1.VPNServerAuthenticationPrototype{} + clientAuthPrototype.Method = &method + + if method == "certificate" { + if clientAuth["client_ca_crn"] != nil && clientAuth["client_ca_crn"] != "" { + crn_val := clientAuth["client_ca_crn"].(string) + certificateInstanceIdentity := &vpcv1.CertificateInstanceIdentity{} + certificateInstanceIdentity.CRN = &crn_val + clientAuthPrototype.ClientCa = certificateInstanceIdentity + + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error method type `certificate` should be passed with `client_ca_crn`")) + } + } else { + if clientAuth["identity_provider"] != nil && clientAuth["identity_provider"] != "" { + providerType := clientAuth["identity_provider"].(string) + clientAuthPrototype.IdentityProvider = &vpcv1.VPNServerAuthenticationByUsernameIDProvider{ + ProviderType: &providerType, + } + } else { + return diag.FromErr(fmt.Errorf("[ERROR] Error method type `username` should be passed with `identity_provider`")) + } + + } + clientAuthentication = append(clientAuthentication, clientAuthPrototype) + } + patchVals.ClientAuthentication = clientAuthentication + hasChange = true + } + + if d.HasChange("client_ip_pool") { + patchVals.ClientIPPool = core.StringPtr(d.Get("client_ip_pool").(string)) + hasChange = true + } + + if d.HasChange("client_dns_server_ips") { + var clientDnsServerIps []vpcv1.IP + clientDnsServerIpsArray := d.Get("client_dns_server_ips").(*schema.Set) + for _, val := range clientDnsServerIpsArray.List() { + value := val.(string) + address := &vpcv1.IP{ + Address: &value, + } + clientDnsServerIps = append(clientDnsServerIps, *address) + } + patchVals.ClientDnsServerIps = clientDnsServerIps + hasChange = true + } + + if d.HasChange("client_idle_timeout") { + patchVals.ClientIdleTimeout = core.Int64Ptr(int64(d.Get("client_idle_timeout").(int))) + hasChange = true + } + + if d.HasChange("enable_split_tunneling") { + patchVals.EnableSplitTunneling = core.BoolPtr(d.Get("enable_split_tunneling").(bool)) + hasChange = true + } + + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + + if d.HasChange("port") { + patchVals.Port = core.Int64Ptr(int64(d.Get("port").(int))) + hasChange = true + } + + if d.HasChange("protocol") { + patchVals.Protocol = core.StringPtr(d.Get("protocol").(string)) + hasChange = true + } + + updateVPNServerOptions.SetIfMatch(d.Get("version").(string)) + + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + getVPNServerOptions.SetID(d.Id()) + _, response, err := sess.GetVPNServerWithContext(context, getVPNServerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerWithContext failed %s\n%s", err, response)) + } + eTag := response.Headers.Get("ETag") // Getting Etag from the response headers. + + // Upgrade or Downgrade of Subnet + if d.HasChange("subnets") { + var subnets []vpcv1.SubnetIdentityIntf + subnetsArray := d.Get("subnets").(*schema.Set) + for _, val := range subnetsArray.List() { + value := val.(string) + subnetIdentity := &vpcv1.SubnetIdentity{ + ID: &value, + } + subnets = append(subnets, subnetIdentity) + } + patchVals.Subnets = subnets + hasChange = true + } + if hasChange { + updateVPNServerOptions.IfMatch = &eTag // if-Match or Etag Change for Patch + updateVPNServerOptions.VPNServerPatch, _ = patchVals.AsPatch() + _, response, err := sess.UpdateVPNServerWithContext(context, updateVPNServerOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateVPNServerWithContext failed %s\n%s", err, response)) + } + _, err = isWaitForVPNServerStable(context, sess, d, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer failed %s\n", err)) + } + } + + return resourceIBMIsVPNServerRead(context, d, meta) +} + +func resourceIBMIsVPNServerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + deleteVPNServerOptions := &vpcv1.DeleteVPNServerOptions{} + + deleteVPNServerOptions.SetID(d.Id()) + + deleteVPNServerOptions.SetIfMatch(d.Get("version").(string)) + + response, err := sess.DeleteVPNServerWithContext(context, deleteVPNServerOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVPNServerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteVPNServerWithContext failed %s\n%s", err, response)) + } + + _, err = isWaitForVPNServerDeleted(context, sess, d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer failed %s\n", err)) + } + d.SetId("") + + return nil +} + +func isWaitForVPNServerDeleted(context context.Context, sess *vpcv1.VpcV1, d *schema.ResourceData) (interface{}, error) { + + log.Printf("Waiting for VPN Server (%s) to be deleted.", d.Id()) + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVPNServerStatusDeleting}, + Target: []string{isVPNServerStatusDeleted, isVPNServerStatusFailed}, + Refresh: func() (interface{}, string, error) { + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + getVPNServerOptions.SetID(d.Id()) + + vpnServer, response, err := sess.GetVPNServerWithContext(context, getVPNServerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return vpnServer, isVPNServerStatusDeleted, nil + } + return vpnServer, isVPNServerStatusDeleting, fmt.Errorf("The VPC route %s failed to delete: %s\n%s", d.Id(), err, response) + } + return vpnServer, isVPNServerStatusDeleting, nil + + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_server_client.go b/ibm/service/vpc/resource_ibm_is_vpn_server_client.go new file mode 100644 index 000000000..b1f887d24 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_server_client.go @@ -0,0 +1,179 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsVPNServerClient() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVPNServerClientDisconnect, + ReadContext: resourceIBMIsVPNServerClientDisconnect, + UpdateContext: resourceIBMIsVPNServerClientDisconnect, + DeleteContext: resourceIBMIsVPNServerClientDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPN server identifier.", + }, + "vpn_client": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPN Client identifier.", + }, + "delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "The delete to use for this VPN client to be deleted or not, when false, client is disconneted and when set to true client is deleted.", + }, + "status_code": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "status code of the result.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "description of the result.", + }, + }, + } +} + +func resourceIBMIsVPNServerClientDisconnect(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVPNServerClientOptions := &vpcv1.GetVPNServerClientOptions{} + + getVPNServerClientOptions.SetVPNServerID(d.Get("vpn_server").(string)) + getVPNServerClientOptions.SetID(d.Get("vpn_client").(string)) + + _, response, err := sess.GetVPNServerClientWithContext(context, getVPNServerClientOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerClientWithContext failed %s\n%s", err, response)) + } + + var flag bool + if v, ok := d.GetOk("delete"); ok { + flag = v.(bool) + } + + if flag == false { + + disconnectVPNServerRouteOptions := &vpcv1.DisconnectVPNClientOptions{} + disconnectVPNServerRouteOptions.SetVPNServerID(d.Get("vpn_server").(string)) + disconnectVPNServerRouteOptions.SetID(d.Get("vpn_client").(string)) + + response, err := sess.DisconnectVPNClientWithContext(context, disconnectVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] DisconnectVPNClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DisconnectVPNClientWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("status_code", response.StatusCode); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status_code: %s", err)) + } + + if err = d.Set("description", "The VPN client disconnection request was accepted."); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + d.SetId(fmt.Sprintf("%s/%s/%v", d.Get("vpn_server").(string), d.Get("vpn_client").(string), response.StatusCode)) + + } else if flag == true { + + deleteVPNServerClientOptions := &vpcv1.DeleteVPNServerClientOptions{} + deleteVPNServerClientOptions.SetVPNServerID(d.Get("vpn_server").(string)) + deleteVPNServerClientOptions.SetID(d.Get("vpn_client").(string)) + + response, err := sess.DeleteVPNServerClientWithContext(context, deleteVPNServerClientOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteVPNServerClientWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("status_code", response.StatusCode); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status_code: %s", err)) + } + + if err = d.Set("description", "The VPN client disconnection request was accepted."); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status_code: %s", err)) + } + + d.SetId(fmt.Sprintf("%s/%s", d.Get("vpn_server").(string), d.Get("vpn_client").(string))) + } + + if err = d.Set("delete", d.Get("delete")); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting delete: %s", err)) + } + return nil +} + +func resourceIBMIsVPNServerClientDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Failed %s\n%s", "false", err)) + } + if len(parts) != 2 { + return diag.FromErr(fmt.Errorf("[ERROR] Incorrect ID %s: ID should be a combination of vpnServer/vpnClient", d.Id())) + } + vpnServer := parts[0] + vpnClient := parts[1] + + getVPNServerClientOptions := &vpcv1.GetVPNServerClientOptions{} + + getVPNServerClientOptions.SetVPNServerID(vpnServer) + getVPNServerClientOptions.SetID(vpnClient) + + _, response, err := sess.GetVPNServerClientWithContext(context, getVPNServerClientOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerClientWithContext failed %s\n%s", err, response)) + } + + deleteVPNServerClientOptions := &vpcv1.DeleteVPNServerClientOptions{} + deleteVPNServerClientOptions.SetVPNServerID(d.Get("vpn_server").(string)) + deleteVPNServerClientOptions.SetID(d.Get("vpn_client").(string)) + + response, err = sess.DeleteVPNServerClientWithContext(context, deleteVPNServerClientOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVPNServerClientWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteVPNServerClientWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_server_route.go b/ibm/service/vpc/resource_ibm_is_vpn_server_route.go new file mode 100644 index 000000000..50d611ef2 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_server_route.go @@ -0,0 +1,367 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +const ( + isVPNServerRouteStatusPending = "pending" + isVPNServerRouteStatusUpdating = "updating" + isVPNServerRouteStatusStable = "stable" + isVPNServerRouteStatusFailed = "failed" + + isVPNServerRouteStatusDeleting = "deleting" + isVPNServerRouteStatusDeleted = "deleted" +) + +func ResourceIBMIsVPNServerRoute() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVPNServerRouteCreate, + ReadContext: resourceIBMIsVPNServerRouteRead, + UpdateContext: resourceIBMIsVPNServerRouteUpdate, + DeleteContext: resourceIBMIsVPNServerRouteDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "vpn_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The VPN server identifier.", + }, + "vpn_route": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The VPN route identifier.", + }, + "destination": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server_route", "destination"), + Description: "The destination to use for this VPN route in the VPN server. Must be unique within the VPN server. If an incoming packet does not match any destination, it will be dropped.", + }, + "action": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "deliver", + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server_route", "action"), + Description: "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server, then deliver the packet to target.- `deliver`: deliver the packet to the target.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_vpn_server_route", "name"), + Description: "The user-defined name for this VPN route. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPN server the VPN route resides in.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the VPN route was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this VPN route.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the VPN route.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} + +func ResourceIBMIsVPNServerRouteValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "destination", + ValidateFunctionIdentifier: validate.ValidateRegexp, + Type: validate.TypeString, + Required: true, + Regexp: `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$`, + }, + validate.ValidateSchema{ + Identifier: "action", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "deliver, drop, translate", + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_vpn_server_route", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsVPNServerRouteCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createVPNServerRouteOptions := &vpcv1.CreateVPNServerRouteOptions{} + + createVPNServerRouteOptions.SetVPNServerID(d.Get("vpn_server").(string)) + createVPNServerRouteOptions.SetDestination(d.Get("destination").(string)) + if _, ok := d.GetOk("action"); ok { + createVPNServerRouteOptions.SetAction(d.Get("action").(string)) + } + if _, ok := d.GetOk("name"); ok { + createVPNServerRouteOptions.SetName(d.Get("name").(string)) + } + + vpnServerRoute, response, err := sess.CreateVPNServerRouteWithContext(context, createVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] CreateVPNServerRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] CreateVPNServerRouteWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createVPNServerRouteOptions.VPNServerID, *vpnServerRoute.ID)) + + _, err = isWaitForVPNServerRouteStable(context, sess, d, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer Route failed %s\n", err)) + } + return resourceIBMIsVPNServerRouteRead(context, d, meta) +} + +func isWaitForVPNServerRouteStable(context context.Context, sess *vpcv1.VpcV1, d *schema.ResourceData, timeout time.Duration) (interface{}, error) { + + log.Printf("Waiting for VPN Server Route(%s) to be stable.", d.Id()) + stateConf := &resource.StateChangeConf{ + Pending: []string{isVPNServerStatusPending, isVPNServerRouteStatusUpdating}, + Target: []string{isVPNServerStatusStable, isVPNServerRouteStatusFailed}, + Refresh: func() (interface{}, string, error) { + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + log.Printf("[DEBUG] Getting ID failed %s", err) + return nil, "", fmt.Errorf("Error Getting VPC Server: %s", err) + } + + getVPNServerRouteOptions.SetVPNServerID(parts[0]) + getVPNServerRouteOptions.SetID(parts[1]) + + vpnServerRoute, response, err := sess.GetVPNServerRouteWithContext(context, getVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] GetVPNServerRouteWithContext failed %s\n%s", err, response) + return vpnServerRoute, "", fmt.Errorf("Error Getting VPC Server Route: %s\n%s", err, response) + } + + if *vpnServerRoute.LifecycleState == "stable" || *vpnServerRoute.LifecycleState == "failed" { + return vpnServerRoute, *vpnServerRoute.LifecycleState, nil + } + return vpnServerRoute, *vpnServerRoute.LifecycleState, nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} +func resourceIBMIsVPNServerRouteRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getVPNServerRouteOptions.SetVPNServerID(parts[0]) + getVPNServerRouteOptions.SetID(parts[1]) + + vpnServerRoute, response, err := sess.GetVPNServerRouteWithContext(context, getVPNServerRouteOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVPNServerRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetVPNServerRouteWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("vpn_server", getVPNServerRouteOptions.VPNServerID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpn_server: %s", err)) + } + if err = d.Set("vpn_route", getVPNServerRouteOptions.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpn_route: %s", err)) + } + + if err = d.Set("destination", vpnServerRoute.Destination); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination: %s", err)) + } + if err = d.Set("action", vpnServerRoute.Action); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting action: %s", err)) + } + if err = d.Set("name", vpnServerRoute.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if err = d.Set("created_at", flex.DateTimeToString(vpnServerRoute.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("href", vpnServerRoute.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", vpnServerRoute.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("resource_type", vpnServerRoute.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + return nil +} + +func resourceIBMIsVPNServerRouteUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + updateVPNServerRouteOptions := &vpcv1.UpdateVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateVPNServerRouteOptions.SetVPNServerID(parts[0]) + updateVPNServerRouteOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.VPNServerRoutePatch{} + + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + + if hasChange { + updateVPNServerRouteOptions.VPNServerRoutePatch, _ = patchVals.AsPatch() + _, response, err := sess.UpdateVPNServerRouteWithContext(context, updateVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVPNServerRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateVPNServerRouteWithContext failed %s\n%s", err, response)) + } + _, err = isWaitForVPNServerRouteStable(context, sess, d, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer Route failed %s\n", err)) + } + } + + return resourceIBMIsVPNServerRouteRead(context, d, meta) +} + +func resourceIBMIsVPNServerRouteDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + deleteVPNServerRouteOptions := &vpcv1.DeleteVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteVPNServerRouteOptions.SetVPNServerID(parts[0]) + deleteVPNServerRouteOptions.SetID(parts[1]) + + response, err := sess.DeleteVPNServerRouteWithContext(context, deleteVPNServerRouteOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVPNServerRouteWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] DeleteVPNServerRouteWithContext failed %s\n%s", err, response)) + } + _, err = isWaitForVPNServerRouteDeleted(context, sess, d) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] VPNServer Route failed %s\n", err)) + } + d.SetId("") + + return nil +} + +func isWaitForVPNServerRouteDeleted(context context.Context, sess *vpcv1.VpcV1, d *schema.ResourceData) (interface{}, error) { + + log.Printf("Waiting for VPN Server Route(%s) to be deleted.", d.Id()) + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVPNServerRouteStatusDeleting}, + Target: []string{isVPNServerStatusDeleted, isVPNServerRouteStatusFailed}, + Refresh: func() (interface{}, string, error) { + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + log.Printf("[DEBUG] Getting ID failed %s", err) + return nil, "", fmt.Errorf("Error Getting VPC Server: %s", err) + } + + getVPNServerRouteOptions.SetVPNServerID(parts[0]) + getVPNServerRouteOptions.SetID(parts[1]) + + vpnServerRoute, response, err := sess.GetVPNServerRouteWithContext(context, getVPNServerRouteOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return vpnServerRoute, isVPNServerRouteStatusDeleted, nil + } + return vpnServerRoute, isVPNServerRouteStatusDeleting, fmt.Errorf("The VPC route %s failed to delete: %s\n%s", d.Id(), err, response) + } + return vpnServerRoute, isVPNServerRouteStatusDeleting, nil + + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_server_route_test.go b/ibm/service/vpc/resource_ibm_is_vpn_server_route_test.go new file mode 100644 index 000000000..f8cc2a01b --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_server_route_test.go @@ -0,0 +1,148 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVPNServerRouteBasic(t *testing.T) { + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + nameVpc := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + vpnServerName := fmt.Sprintf("tf-vpnserver-%d", acctest.RandIntRange(10, 100)) + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + destination := "172.16.0.0/16" + name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + action := "translate" + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVPNServerRouteDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerRouteConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, name, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "destination", destination), + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "action", action), + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "name", name), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server_route.is_vpn_server_route", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server_route.is_vpn_server_route", "href"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server_route.is_vpn_server_route", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server_route.is_vpn_server_route", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server_route.is_vpn_server_route", "vpn_route"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsVPNServerRouteConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, destination, action, nameUpdate, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "destination", destination), + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "action", action), + resource.TestCheckResourceAttr("ibm_is_vpn_server_route.is_vpn_server_route", "name", nameUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_is_vpn_server_route.is_vpn_server_route", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerRouteConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol string, destination string, action string, name, isCertificateCrn, isClientCaCrn string) string { + return testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol, isCertificateCrn, isClientCaCrn) + fmt.Sprintf(` + resource "ibm_is_vpn_server_route" "is_vpn_server_route" { + vpn_server = ibm_is_vpn_server.is_vpn_server.id + destination = "%s" + action = "%s" + name = "%s" + } + `, destination, action, name) +} + +func testAccCheckIBMIsVPNServerRouteExists(n string, obj vpcv1.VPNServerRoute) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getVPNServerRouteOptions.SetVPNServerID(parts[0]) + getVPNServerRouteOptions.SetID(parts[1]) + + vpnServerRoute, _, err := sess.GetVPNServerRoute(getVPNServerRouteOptions) + if err != nil { + return err + } + + obj = *vpnServerRoute + return nil + } +} + +func testAccCheckIBMIsVPNServerRouteDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpn_server_route" { + continue + } + + getVPNServerRouteOptions := &vpcv1.GetVPNServerRouteOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getVPNServerRouteOptions.SetVPNServerID(parts[0]) + getVPNServerRouteOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := sess.GetVPNServerRoute(getVPNServerRouteOptions) + + if err == nil { + return fmt.Errorf("VPNServerRoute still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for VPNServerRoute (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_vpn_server_test.go b/ibm/service/vpc/resource_ibm_is_vpn_server_test.go new file mode 100644 index 000000000..b7f049292 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_vpn_server_test.go @@ -0,0 +1,182 @@ +// Copyright IBM Corp. 2022 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVPNServerBasic(t *testing.T) { + var vpnserver string + if acc.ISCertificateCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CERTIFICATE_CRN for testing ibm_is_vpn_server resource") + } + + if acc.ISClientCaCrn == "" { + fmt.Println("[ERROR] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") + } + isCertificateCrn := acc.ISCertificateCrn + isClientCaCrn := acc.ISClientCaCrn + clientIPPool := "10.5.0.0/21" + clientIdleTimeout := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunneling := "true" + nameVpc := fmt.Sprintf("test-vpc-tf-%d", acctest.RandIntRange(10, 100)) + nameSubnet1 := fmt.Sprintf("test-subnet1-tf-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-name%d", acctest.RandIntRange(10, 100)) + port := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocol := "udp" + + clientIPPoolUpdate := "10.6.0.0/21" + clientIdleTimeoutUpdate := fmt.Sprintf("%d", acctest.RandIntRange(0, 28800)) + enableSplitTunnelingUpdate := "false" + nameUpdate := fmt.Sprintf("tf-name%d", acctest.RandIntRange(10, 100)) + portUpdate := fmt.Sprintf("%d", acctest.RandIntRange(1, 65535)) + protocolUpdate := "tcp" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVPNServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPool, clientIdleTimeout, enableSplitTunneling, name, port, protocol, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVPNServerExists("ibm_is_vpn_server.is_vpn_server", vpnserver), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "certificate_crn"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "client_authentication.0.method"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "client_auto_delete"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "client_auto_delete_timeout"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "client_dns_server_ips.#"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "hostname"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "href"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "health_state"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "vpn_server"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "private_ips.0.address"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "private_ips.0.href"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "private_ips.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "private_ips.0.name"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "private_ips.0.resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "resource_group"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "security_groups.#"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "subnets.#"), + resource.TestCheckResourceAttrSet("ibm_is_vpn_server.is_vpn_server", "vpc.#"), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "client_ip_pool", clientIPPool), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "client_idle_timeout", clientIdleTimeout), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "enable_split_tunneling", enableSplitTunneling), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "name", name), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "port", port), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "protocol", protocol), + ), + }, + { + Config: testAccCheckIBMIsVPNServerConfigBasic(nameVpc, nameSubnet1, clientIPPoolUpdate, clientIdleTimeoutUpdate, enableSplitTunnelingUpdate, nameUpdate, portUpdate, protocolUpdate, isCertificateCrn, isClientCaCrn), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "client_ip_pool", clientIPPoolUpdate), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "client_idle_timeout", clientIdleTimeoutUpdate), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "enable_split_tunneling", enableSplitTunnelingUpdate), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "port", portUpdate), + resource.TestCheckResourceAttr("ibm_is_vpn_server.is_vpn_server", "protocol", protocolUpdate), + ), + }, + { + ResourceName: "ibm_is_vpn_server.is_vpn_server", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsVPNServerConfigBasic(nameVpc string, nameSubnet1 string, clientIPPool string, clientIdleTimeout string, enableSplitTunneling string, vpnServerName string, port string, protocol string, isCertificateCrn string, isClientCaCrn string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet-1" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" + } + + resource "ibm_is_vpn_server" "is_vpn_server" { + certificate_crn = "%s" + client_authentication { + method = "certificate" + client_ca_crn = "%s" + } + client_ip_pool = "%s" + subnets = [ibm_is_subnet.testacc_subnet-1.id] + client_dns_server_ips = ["192.168.3.4"] + client_idle_timeout = %s + enable_split_tunneling = %s + name = "%s" + port = %s + protocol = "%s" + } + `, nameVpc, nameSubnet1, isCertificateCrn, isClientCaCrn, clientIPPool, clientIdleTimeout, enableSplitTunneling, vpnServerName, port, protocol) +} + +func testAccCheckIBMIsVPNServerExists(n string, obj string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + + getVPNServerOptions.SetID(rs.Primary.ID) + + vpnServer, _, err := sess.GetVPNServer(getVPNServerOptions) + if err != nil { + return err + } + + obj = *vpnServer.ID + return nil + } +} + +func testAccCheckIBMIsVPNServerDestroy(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vpn_server" { + continue + } + + getVPNServerOptions := &vpcv1.GetVPNServerOptions{} + + getVPNServerOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := sess.GetVPNServer(getVPNServerOptions) + + if err == nil { + return fmt.Errorf("VPNServer still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for VPNServer (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/test-fixtures/.ssh/id_rsa b/ibm/service/vpc/test-fixtures/.ssh/id_rsa new file mode 100644 index 000000000..05ed85faf --- /dev/null +++ b/ibm/service/vpc/test-fixtures/.ssh/id_rsa @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAugoOuuyDJaLBUM6tw8yzCiq0D0L7NijSr0iwGUBd3o7/xhlQ +JmLyBSeihLEJ18p/sSJX+egXJcd2m+6tBvZZsqbmEttWLvZ60RiQWUnZs3gQiHNf +2nUD+vYZbo6Ht9azrA5uzsdT1OJOqDH2kACGBWnDfH9Pk3j4LYEcL4Timout+Xfw +s1LS9Cr1NU8DSi3qeFVbswcIb9iQw6KMsHpNWPSlyagOgzqVy3iMypcWtvZmKG9p +mT4ktulO1cLyDonbpxt9mIxpblsxzPiSOJQ7ZniDphtwITSKnPV+eLmnA4cLWWZX +wN17cARTkDszL59AMJKBtpqoh6h3Mk1/D1qgR/meSrtxTWC/qcOcx8ylA9rM02eC +0F1PbKDHYMzr8UUwn2mTDJCKv5uC4g2ZUhVJHVbADj8qpFTp1L5hpzGdz23Gg9eu +AYQ2nyvx4jkYIDEAWXxeHoqhRt50p1/nE9o3RyjWBvf/Q4Tgm6hGnm7Re6Fgjt6s +bRn+gs/LiIs0zp9oARusNgBsLkpmH0wImnrVFlTkG2gnyBVtByVeYrxnHYlcZR/d +aaSYV/kw6gP2swJlA35NrUtAF/sjfTakc8GNDwkUQHfWZqjgS/p0GAEMXxbn05u7 +DW0Gfq9YqarmO7lVTPRhVjyxeLIz8eBPmlSMoLwLcYEZulF7WZN17UYVRasCAwEA +AQKCAgBNZw/X37109DFgMI2FcG5xZXEDBIhGcVevDBwQdYJYrcBnKHL7daFiWao5 +cPs6aAsWpMZbuJ+g3UtQ903QHsEVHnGNGOrToUNaKdEtBRfpnqOqUe5oktT0Hl5Y +bD61U0Pv6xVZPP95DCtTuW3vXfhk2is2ajWukt8W96fFcZFiYYkhyTBBO81/PzxE +ULp6q33pUQJVCzEMb9tTOhc0+b2irC8qJpzbJo3aWS6iv5f4ya2ZVzllQ8C8xXdC +YtiZCex0q3Bm/syC2Lhwol8b4TiRmsSTYMkXV6fwRAe5rOx7AD3NlVIfcUcBRRuL +X8YdIzHuw5XqZpCF2Ka3LB0YQ0l50mGGfGTOK2Jtl60p/67dH1tEmpvvyA/EIzff +CAlz/AtXpp0XQCiz+4hiMTsNGZn4f2kB9HA72g6YD0pYRjxdOKLBhcrT2VJ88imw +Bs9P/S57Ll2KXJSpjbu8WNBOzA84EhQat/egQHB+55w74oKlEaxJSEiwHYXYpRI2 +ZXPTvjZnqCr9xRSVD/k7Eg0tYFODYn36VH+CTb7rmduHW0//DJILIko+7PMfDvXe +rQyoMPrlyI3Z7uZLpyLuKMCYAfwQIyRur/oC7KFjhOy4mWGEUwBU07jJ0c9/qw3h +bjOnSEaI4w9rvUzCYGIuLxz9tOY1ISS9dzmKZE2JjexrtHfTmQKCAQEAx3iTxW30 +FsK6qMLEawb+P4G2yTMBglMHvF1Gqa2CHrIFKi2UXJc2+A5jMzBQgTJpeHOctKvh +3/5b3xZGdSu+Efr8bN8HqQ1Z63dvZCucXI6BTfOm+kaEbNi2YFfoS9jQByrrPGWO +ZeetoMGbG4EwElfpIIfZhWZjkcnmDmWiEY5ovcpkzlqtsVIi+XiGOok3Tt3PK1co +IQJ2321+LW5HOKNThcYZCfuNg1SflEQSkAqJamQYYXoQwp7N+LHeG5F8t2CRLa2/ +mq4uOwcofTuoKnbEjdMIZu/7Xy8wzhZdCGMemQJITkhtwZRNj+ByGLqoq/UzThGf +0CD8PR537I1LzQKCAQEA7sMFx4SPL/nTmsYrLmJ/8EHFPVAKAPxpOHYi0EpsW3ZQ +sozpmLhRemBXN8vzLffBuO+8lu7urKpVKxgx8nPRtobsuZEGFCWnQ10zgC3JYrmg +Z6RqkaGTqA9++j04akUAjNtZW/Ib3qABvDF33neSX847U5nT0y3jVYa5QhTMYGOI +xrWk6wfXD+XeRE770TOff/0u3/QUA8O7zQ+hEw61lMooqqr3y4R2/qAfVXZ4stfY +d4eA3usK3Ajkf1BJEbd3GXyc0YIbwnRmCY5TeYsEHLPVGQathoMbWPkIFeAWwsRy +j05t1FfAfJf05OUlV877rv2l/bapI5IPMPmfWJ2PVwKCAQAwbJ9DIKxPEjsKWS4h +5XK3rB/ZvF4za0DHg8Vxz8N0/DawxJvt1m/rzGJcvO/uTXS5Xye93LRbEn7vK5Mz +QslDyDCbpZFQgwM/XKFYKhYtihLt/6abv57KZdnwjabBMwNdmhe9c9Ib/yBxlE65 +YKVw7pKT6SbvcanebKtC931e0bmvyYCrb+wWzh/bfFzpvQIGTWbL2L7PNK/zEbu9 +/7WelFfkc/EEMWNrbJHJBrWS7lvpzh71GxMSjEbohxWqj6k9Q147PqDzRjHG9rfn +nyH2HRseawrxInVd6DDq9xbiwF1fO+SdzIuIoR4rPYu1YSstg7tOyoyHlFpn5Aut +C6hJAoIBAG21y1gMf0cKQsNhv8HGnQcnEZzExHQDh83b6s9PA09bpGUG/uef+kCD +OFB5NLqwl6GE92FbVOyeMBhnO7wun/SBNxFlpCdpzdvUXa/OWjU1GpHFKPrWBeU5 +iZ0uuFeMcV5IBF2NeGTpnSJ+kJf21ZmUSAp4Kq9k7IsGJuZIbEj2M4krOiaNKbMy +atl0eZ19XRMQoZNisjewnwDw55C8N4+w/NK/ULGBorQJm5xHndp/+AWkjADie9Dz +fRtLJugvJ1jcu6pBYMQPfDtz3MOCr1cJAyhGu0GNyOkvNRnoKE1Cu2lCHpFt6RLX +OD5dVLVudJPKFZXpcvrXSIe2jBPKAm0CggEBALRoecFIII8oLcRlEo/ie2x7fB9T +A3X3285Lf3p5NX+4072khdeqwlLaz45u8qSSgXPyFOcyh/GU4OY8B0167LmSqL0X +u72Osx8z/aDrOz66DB5uIwdRUDGg8k0FlbLOu0FoKHVkaxq+rBEjYO92GdDcNiVL +ZBhSlg6gEiSpXZF3x2gZrU0vYnoimo+kV0USbEDjKlgYojPNYRKDKm/jCPx7o1XA +j1LA4cSun4I+yelVd7Eq695uj8FNdQIGboEyRU3sXHleGx//9TZJ6IWJcIUFLUdE +eAyoTLC28WMaCm64rSVYkihsrqTPCfwc89XaOjsPrGKln4zF+gg1KCz2hik= +-----END RSA PRIVATE KEY----- diff --git a/ibm/service/vpc/test-fixtures/.ssh/id_rsa.pub b/ibm/service/vpc/test-fixtures/.ssh/id_rsa.pub new file mode 100644 index 000000000..8a2325613 --- /dev/null +++ b/ibm/service/vpc/test-fixtures/.ssh/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6Cg667IMlosFQzq3DzLMKKrQPQvs2KNKvSLAZQF3ejv/GGVAmYvIFJ6KEsQnXyn+xIlf56Bclx3ab7q0G9lmypuYS21Yu9nrRGJBZSdmzeBCIc1/adQP69hlujoe31rOsDm7Ox1PU4k6oMfaQAIYFacN8f0+TePgtgRwvhOKai635d/CzUtL0KvU1TwNKLep4VVuzBwhv2JDDooywek1Y9KXJqA6DOpXLeIzKlxa29mYob2mZPiS26U7VwvIOidunG32YjGluWzHM+JI4lDtmeIOmG3AhNIqc9X54uacDhwtZZlfA3XtwBFOQOzMvn0AwkoG2mqiHqHcyTX8PWqBH+Z5Ku3FNYL+pw5zHzKUD2szTZ4LQXU9soMdgzOvxRTCfaZMMkIq/m4LiDZlSFUkdVsAOPyqkVOnUvmGnMZ3PbcaD164BhDafK/HiORggMQBZfF4eiqFG3nSnX+cT2jdHKNYG9/9DhOCbqEaebtF7oWCO3qxtGf6Cz8uIizTOn2gBG6w2AGwuSmYfTAiaetUWVOQbaCfIFW0HJV5ivGcdiVxlH91ppJhX+TDqA/azAmUDfk2tS0AX+yN9NqRzwY0PCRRAd9ZmqOBL+nQYAQxfFufTm7sNbQZ+r1ipquY7uVVM9GFWPLF4sjPx4E+aVIygvAtxgRm6UXtZk3XtRhVFqw== \ No newline at end of file diff --git a/ibm/structures.go b/ibm/structures.go deleted file mode 100644 index 7cb72c5c4..000000000 --- a/ibm/structures.go +++ /dev/null @@ -1,2861 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - b64 "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "log" - "net/url" - "os" - "path" - "reflect" - "strconv" - "strings" - - "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" - "github.com/IBM/ibm-cos-sdk-go/service/s3" - kp "github.com/IBM/keyprotect-go-client" - "github.com/IBM/platform-services-go-sdk/globaltaggingv1" - "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" - rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" - "github.com/apache/openwhisk-client-go/whisk" - "github.com/go-openapi/strfmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/softlayer/softlayer-go/datatypes" - "github.com/softlayer/softlayer-go/sl" - - "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" - "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" - "github.com/IBM-Cloud/bluemix-go/api/icd/icdv4" - "github.com/IBM-Cloud/bluemix-go/api/mccp/mccpv2" - "github.com/IBM-Cloud/bluemix-go/api/schematics" - "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" - "github.com/IBM/platform-services-go-sdk/iamaccessgroupsv2" - "github.com/IBM/platform-services-go-sdk/iamidentityv1" -) - -const ( - prodBaseController = "https://cloud.ibm.com" - stageBaseController = "https://test.cloud.ibm.com" - //ResourceControllerURL ... - ResourceControllerURL = "resource_controller_url" - //ResourceName ... - ResourceName = "resource_name" - //ResourceCRN ... - ResourceCRN = "resource_crn" - //ResourceStatus ... - ResourceStatus = "resource_status" - //ResourceGroupName ... - ResourceGroupName = "resource_group_name" - //RelatedCRN ... - RelatedCRN = "related_crn" - SystemIBMLabelPrefix = "ibm-cloud.kubernetes.io/" - KubernetesLabelPrefix = "kubernetes.io/" - K8sLabelPrefix = "k8s.io/" -) - -//HashInt ... -func HashInt(v interface{}) int { return v.(int) } - -func expandStringList(input []interface{}) []string { - vs := make([]string, len(input)) - for i, v := range input { - vs[i] = v.(string) - } - return vs -} - -func flattenStringList(list []string) []interface{} { - vs := make([]interface{}, len(list)) - for i, v := range list { - vs[i] = v - } - return vs -} - -func expandIntList(input []interface{}) []int { - vs := make([]int, len(input)) - for i, v := range input { - vs[i] = v.(int) - } - return vs -} - -func flattenIntList(list []int) []interface{} { - vs := make([]interface{}, len(list)) - for i, v := range list { - vs[i] = v - } - return vs -} - -func newStringSet(f schema.SchemaSetFunc, in []string) *schema.Set { - var out = make([]interface{}, len(in), len(in)) - for i, v := range in { - out[i] = v - } - return schema.NewSet(f, out) -} - -func flattenRoute(in []mccpv2.Route) *schema.Set { - vs := make([]string, len(in)) - for i, v := range in { - vs[i] = v.GUID - } - return newStringSet(schema.HashString, vs) -} - -func stringSliceToSet(in []string) *schema.Set { - vs := make([]string, len(in)) - for i, v := range in { - vs[i] = v - } - return newStringSet(schema.HashString, vs) -} - -func flattenServiceBindings(in []mccpv2.ServiceBinding) *schema.Set { - vs := make([]string, len(in)) - for i, v := range in { - vs[i] = v.ServiceInstanceGUID - } - return newStringSet(schema.HashString, vs) -} - -func flattenPort(in []int) *schema.Set { - var out = make([]interface{}, len(in)) - for i, v := range in { - out[i] = v - } - return schema.NewSet(HashInt, out) -} - -func flattenFileStorageID(in []datatypes.Network_Storage) *schema.Set { - var out = []interface{}{} - for _, v := range in { - if *v.NasType == "NAS" { - out = append(out, *v.Id) - } - } - return schema.NewSet(HashInt, out) -} - -func flattenBlockStorageID(in []datatypes.Network_Storage) *schema.Set { - var out = []interface{}{} - for _, v := range in { - if *v.NasType == "ISCSI" { - out = append(out, *v.Id) - } - } - return schema.NewSet(HashInt, out) -} - -func flattenSSHKeyIDs(in []datatypes.Security_Ssh_Key) *schema.Set { - var out = []interface{}{} - for _, v := range in { - out = append(out, *v.Id) - } - return schema.NewSet(HashInt, out) -} - -func flattenSpaceRoleUsers(in []mccpv2.SpaceRole) *schema.Set { - var out = []interface{}{} - for _, v := range in { - out = append(out, v.UserName) - } - return schema.NewSet(schema.HashString, out) -} - -func flattenOrgRole(in []mccpv2.OrgRole, excludeUsername string) *schema.Set { - var out = []interface{}{} - for _, v := range in { - if excludeUsername == "" { - out = append(out, v.UserName) - } else { - if v.UserName != excludeUsername { - out = append(out, v.UserName) - } - } - } - return schema.NewSet(schema.HashString, out) -} - -func flattenMapInterfaceVal(m map[string]interface{}) map[string]string { - out := make(map[string]string) - for k, v := range m { - out[k] = fmt.Sprintf("%v", v) - } - return out -} - -func flattenCredentials(creds map[string]interface{}) map[string]string { - return flattenMapInterfaceVal(creds) -} - -func flattenServiceKeyCredentials(creds map[string]interface{}) map[string]string { - return flattenCredentials(creds) -} - -func flattenServiceInstanceCredentials(keys []mccpv2.ServiceKeyFields) []interface{} { - var out = make([]interface{}, len(keys), len(keys)) - for i, k := range keys { - m := make(map[string]interface{}) - m["name"] = k.Entity.Name - m["credentials"] = Flatten(k.Entity.Credentials) - out[i] = m - } - return out -} - -func flattenUsersSet(userList *schema.Set) []string { - users := make([]string, 0) - for _, user := range userList.List() { - users = append(users, user.(string)) - } - return users -} - -func expandProtocols(configured []interface{}) ([]datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration, error) { - protocols := make([]datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration, 0, len(configured)) - for _, lRaw := range configured { - data := lRaw.(map[string]interface{}) - p := &datatypes.Network_LBaaS_LoadBalancerProtocolConfiguration{ - FrontendProtocol: sl.String(data["frontend_protocol"].(string)), - BackendProtocol: sl.String(data["backend_protocol"].(string)), - FrontendPort: sl.Int(data["frontend_port"].(int)), - BackendPort: sl.Int(data["backend_port"].(int)), - } - if v, ok := data["session_stickiness"]; ok && v.(string) != "" { - p.SessionType = sl.String(v.(string)) - } - if v, ok := data["max_conn"]; ok && v.(int) != 0 { - p.MaxConn = sl.Int(v.(int)) - } - if v, ok := data["tls_certificate_id"]; ok && v.(int) != 0 { - p.TlsCertificateId = sl.Int(v.(int)) - } - if v, ok := data["load_balancing_method"]; ok { - p.LoadBalancingMethod = sl.String(lbMethodToId[v.(string)]) - } - if v, ok := data["protocol_id"]; ok && v.(string) != "" { - p.ListenerUuid = sl.String(v.(string)) - } - - var isValid bool - if p.TlsCertificateId != nil && *p.TlsCertificateId != 0 { - // validate the protocol is correct - if *p.FrontendProtocol == "HTTPS" { - isValid = true - } - } else { - isValid = true - } - - if isValid { - protocols = append(protocols, *p) - } else { - return protocols, fmt.Errorf("tls_certificate_id may be set only when frontend protocol is 'HTTPS'") - } - - } - return protocols, nil -} - -func expandMembers(configured []interface{}) []datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo { - members := make([]datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo, 0, len(configured)) - for _, lRaw := range configured { - data := lRaw.(map[string]interface{}) - p := &datatypes.Network_LBaaS_LoadBalancerServerInstanceInfo{} - if v, ok := data["private_ip_address"]; ok && v.(string) != "" { - p.PrivateIpAddress = sl.String(v.(string)) - } - if v, ok := data["weight"]; ok && v.(int) != 0 { - p.Weight = sl.Int(v.(int)) - } - - members = append(members, *p) - } - return members -} - -func flattenServerInstances(list []datatypes.Network_LBaaS_Member) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - l := map[string]interface{}{ - "private_ip_address": *i.Address, - "member_id": *i.Uuid, - } - if i.Weight != nil { - l["weight"] = *i.Weight - } - result = append(result, l) - } - return result -} - -func flattenProtocols(list []datatypes.Network_LBaaS_Listener) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - l := map[string]interface{}{ - "frontend_protocol": *i.Protocol, - "frontend_port": *i.ProtocolPort, - "backend_protocol": *i.DefaultPool.Protocol, - "backend_port": *i.DefaultPool.ProtocolPort, - "load_balancing_method": lbIdToMethod[*i.DefaultPool.LoadBalancingAlgorithm], - "protocol_id": *i.Uuid, - } - if i.DefaultPool.SessionAffinity != nil && i.DefaultPool.SessionAffinity.Type != nil && *i.DefaultPool.SessionAffinity.Type != "" { - l["session_stickiness"] = *i.DefaultPool.SessionAffinity.Type - } - if i.ConnectionLimit != nil && *i.ConnectionLimit != 0 { - l["max_conn"] = *i.ConnectionLimit - } - if i.TlsCertificateId != nil && *i.TlsCertificateId != 0 { - l["tls_certificate_id"] = *i.TlsCertificateId - } - result = append(result, l) - } - return result -} - -func flattenVpcWorkerPools(list []containerv2.GetWorkerPoolResponse) []map[string]interface{} { - workerPools := make([]map[string]interface{}, len(list)) - for i, workerPool := range list { - l := map[string]interface{}{ - "id": workerPool.ID, - "name": workerPool.PoolName, - "flavor": workerPool.Flavor, - "worker_count": workerPool.WorkerCount, - "isolation": workerPool.Isolation, - "labels": workerPool.Labels, - "state": workerPool.Lifecycle.ActualState, - } - zones := workerPool.Zones - zonesConfig := make([]map[string]interface{}, len(zones)) - for j, zone := range zones { - z := map[string]interface{}{ - "zone": zone.ID, - "worker_count": zone.WorkerCount, - } - subnets := zone.Subnets - subnetConfig := make([]map[string]interface{}, len(subnets)) - for k, subnet := range subnets { - s := map[string]interface{}{ - "id": subnet.ID, - "primary": subnet.Primary, - } - subnetConfig[k] = s - } - z["subnets"] = subnetConfig - zonesConfig[j] = z - } - l["zones"] = zonesConfig - workerPools[i] = l - } - - return workerPools -} - -func flattenVpcZones(list []containerv2.ZoneResp) []map[string]interface{} { - zones := make([]map[string]interface{}, len(list)) - for i, zone := range list { - l := map[string]interface{}{ - "id": zone.ID, - "subnet_id": flattenSubnets(zone.Subnets), - "worker_count": zone.WorkerCount, - } - zones[i] = l - } - return zones -} -func flattenConditions(list []iamaccessgroupsv2.RuleConditions) []map[string]interface{} { - conditions := make([]map[string]interface{}, len(list)) - for i, cond := range list { - l := map[string]interface{}{ - "claim": cond.Claim, - "operator": cond.Operator, - "value": strings.ReplaceAll(*cond.Value, "\"", ""), - } - conditions[i] = l - } - return conditions -} -func flattenAccessGroupRules(list *iamaccessgroupsv2.RulesList) []map[string]interface{} { - rules := make([]map[string]interface{}, len(list.Rules)) - for i, item := range list.Rules { - l := map[string]interface{}{ - "name": item.Name, - "expiration": item.Expiration, - "identity_provider": item.RealmName, - "conditions": flattenConditions(item.Conditions), - } - rules[i] = l - } - return rules -} - -func flattenSubnets(list []containerv2.Subnet) []map[string]interface{} { - subs := make([]map[string]interface{}, len(list)) - for i, sub := range list { - l := map[string]interface{}{ - "id": sub.ID, - "worker_count": sub.Primary, - } - subs[i] = l - } - return subs -} - -func flattenZones(list []containerv1.WorkerPoolZoneResponse) []map[string]interface{} { - zones := make([]map[string]interface{}, len(list)) - for i, zone := range list { - l := map[string]interface{}{ - "zone": zone.WorkerPoolZone.ID, - "private_vlan": zone.WorkerPoolZone.WorkerPoolZoneNetwork.PrivateVLAN, - "public_vlan": zone.WorkerPoolZone.WorkerPoolZoneNetwork.PublicVLAN, - "worker_count": zone.WorkerCount, - } - zones[i] = l - } - return zones -} - -func flattenWorkerPools(list []containerv1.WorkerPoolResponse) []map[string]interface{} { - workerPools := make([]map[string]interface{}, len(list)) - for i, workerPool := range list { - l := map[string]interface{}{ - "id": workerPool.ID, - "hardware": workerPool.Isolation, - "name": workerPool.Name, - "machine_type": workerPool.MachineType, - "size_per_zone": workerPool.Size, - "state": workerPool.State, - "labels": workerPool.Labels, - } - zones := workerPool.Zones - zonesConfig := make([]map[string]interface{}, len(zones)) - for j, zone := range zones { - z := map[string]interface{}{ - "zone": zone.ID, - "private_vlan": zone.PrivateVLAN, - "public_vlan": zone.PublicVLAN, - "worker_count": zone.WorkerCount, - } - zonesConfig[j] = z - } - l["zones"] = zonesConfig - workerPools[i] = l - } - - return workerPools -} - -func flattenAlbs(list []containerv1.ALBConfig, filterType string) []map[string]interface{} { - albs := make([]map[string]interface{}, 0) - for _, alb := range list { - if alb.ALBType == filterType || filterType == "all" { - l := map[string]interface{}{ - "id": alb.ALBID, - "name": alb.Name, - "alb_type": alb.ALBType, - "enable": alb.Enable, - "state": alb.State, - "num_of_instances": alb.NumOfInstances, - "alb_ip": alb.ALBIP, - "resize": alb.Resize, - "disable_deployment": alb.DisableDeployment, - } - albs = append(albs, l) - } - } - return albs -} - -func flattenVpcAlbs(list []containerv2.AlbConfig, filterType string) []map[string]interface{} { - albs := make([]map[string]interface{}, 0) - for _, alb := range list { - if alb.AlbType == filterType || filterType == "all" { - l := map[string]interface{}{ - "id": alb.AlbID, - "name": alb.Name, - "alb_type": alb.AlbType, - "enable": alb.Enable, - "state": alb.State, - "resize": alb.Resize, - "disable_deployment": alb.DisableDeployment, - "load_balancer_hostname": alb.LoadBalancerHostname, - } - albs = append(albs, l) - } - } - return albs -} - -func flattenNetworkInterfaces(list []containerv2.Network) []map[string]interface{} { - nwInterfaces := make([]map[string]interface{}, len(list)) - for i, nw := range list { - l := map[string]interface{}{ - "cidr": nw.Cidr, - "ip_address": nw.IpAddress, - "subnet_id": nw.SubnetID, - } - nwInterfaces[i] = l - } - return nwInterfaces -} - -func flattenVlans(list []containerv1.Vlan) []map[string]interface{} { - vlans := make([]map[string]interface{}, len(list)) - for i, vlanR := range list { - subnets := make([]map[string]interface{}, len(vlanR.Subnets)) - for j, subnetR := range vlanR.Subnets { - subnet := make(map[string]interface{}) - subnet["id"] = subnetR.ID - subnet["cidr"] = subnetR.Cidr - subnet["is_byoip"] = subnetR.IsByOIP - subnet["is_public"] = subnetR.IsPublic - ips := make([]string, len(subnetR.Ips)) - for k, ip := range subnetR.Ips { - ips[k] = ip - } - subnet["ips"] = ips - subnets[j] = subnet - } - l := map[string]interface{}{ - "id": vlanR.ID, - "subnets": subnets, - } - vlans[i] = l - } - return vlans -} - -func flattenIcdGroups(grouplist icdv4.GroupList) []map[string]interface{} { - groups := make([]map[string]interface{}, len(grouplist.Groups)) - for i, group := range grouplist.Groups { - memorys := make([]map[string]interface{}, 1) - memory := make(map[string]interface{}) - memory["units"] = group.Memory.Units - memory["allocation_mb"] = group.Memory.AllocationMb - memory["minimum_mb"] = group.Memory.MinimumMb - memory["step_size_mb"] = group.Memory.StepSizeMb - memory["is_adjustable"] = group.Memory.IsAdjustable - memory["can_scale_down"] = group.Memory.CanScaleDown - memorys[0] = memory - - cpus := make([]map[string]interface{}, 1) - cpu := make(map[string]interface{}) - cpu["units"] = group.Cpu.Units - cpu["allocation_count"] = group.Cpu.AllocationCount - cpu["minimum_count"] = group.Cpu.MinimumCount - cpu["step_size_count"] = group.Cpu.StepSizeCount - cpu["is_adjustable"] = group.Cpu.IsAdjustable - cpu["can_scale_down"] = group.Cpu.CanScaleDown - cpus[0] = cpu - - disks := make([]map[string]interface{}, 1) - disk := make(map[string]interface{}) - disk["units"] = group.Disk.Units - disk["allocation_mb"] = group.Disk.AllocationMb - disk["minimum_mb"] = group.Disk.MinimumMb - disk["step_size_mb"] = group.Disk.StepSizeMb - disk["is_adjustable"] = group.Disk.IsAdjustable - disk["can_scale_down"] = group.Disk.CanScaleDown - disks[0] = disk - - l := map[string]interface{}{ - "group_id": group.Id, - "count": group.Count, - "memory": memorys, - "cpu": cpus, - "disk": disks, - } - groups[i] = l - } - return groups -} - -func normalizeJSONString(jsonString interface{}) (string, error) { - var j interface{} - if jsonString == nil || jsonString.(string) == "" { - return "", nil - } - s := jsonString.(string) - err := json.Unmarshal([]byte(s), &j) - if err != nil { - return s, err - } - bytes, err := json.Marshal(j) - if err != nil { - return "", err - } - return string(bytes[:]), nil -} - -func expandAnnotations(annotations string) (whisk.KeyValueArr, error) { - var result whisk.KeyValueArr - dc := json.NewDecoder(strings.NewReader(annotations)) - dc.UseNumber() - err := dc.Decode(&result) - return result, err -} - -func flattenAnnotations(in whisk.KeyValueArr) (string, error) { - b, err := json.Marshal(in) - if err != nil { - return "", err - } - return string(b[:]), nil -} - -func expandParameters(annotations string) (whisk.KeyValueArr, error) { - var result whisk.KeyValueArr - dc := json.NewDecoder(strings.NewReader(annotations)) - dc.UseNumber() - err := dc.Decode(&result) - return result, err -} - -func flattenParameters(in whisk.KeyValueArr) (string, error) { - b, err := json.Marshal(in) - if err != nil { - return "", err - } - return string(b[:]), nil -} - -func expandLimits(l []interface{}) *whisk.Limits { - if len(l) == 0 || l[0] == nil { - return &whisk.Limits{} - } - in := l[0].(map[string]interface{}) - obj := &whisk.Limits{ - Timeout: ptrToInt(in["timeout"].(int)), - Memory: ptrToInt(in["memory"].(int)), - Logsize: ptrToInt(in["log_size"].(int)), - } - return obj -} - -func flattenActivityTrack(in *resourceconfigurationv1.ActivityTracking) []interface{} { - - att := make(map[string]interface{}) - if in != nil { - if in.ReadDataEvents != nil { - att["read_data_events"] = *in.ReadDataEvents - } - if in.WriteDataEvents != nil { - att["write_data_events"] = *in.WriteDataEvents - } - if in.ActivityTrackerCrn != nil { - att["activity_tracker_crn"] = *in.ActivityTrackerCrn - } - } - return []interface{}{att} -} - -func flattenMetricsMonitor(in *resourceconfigurationv1.MetricsMonitoring) []interface{} { - att := make(map[string]interface{}) - if in != nil { - if in.UsageMetricsEnabled != nil { - att["usage_metrics_enabled"] = *in.UsageMetricsEnabled - } - if in.MetricsMonitoringCrn != nil { - att["metrics_monitoring_crn"] = *in.MetricsMonitoringCrn - } - if in.RequestMetricsEnabled != nil { - att["request_metrics_enabled"] = *in.RequestMetricsEnabled - } - } - return []interface{}{att} -} - -func archiveRuleGet(in []*s3.LifecycleRule) []interface{} { - rules := make([]interface{}, 0, len(in)) - for _, r := range in { - // Checking this is not an expire_rule. LifeCycle rules are either archive or expire - if r.Expiration == nil { - rule := make(map[string]interface{}) - - if r.Status != nil { - if *r.Status == "Enabled" { - rule["enable"] = true - - } else { - rule["enable"] = false - } - - } - if r.ID != nil { - rule["rule_id"] = *r.ID - } - - for _, transition := range r.Transitions { - if transition.Days != nil { - rule["days"] = int(*transition.Days) - } - if transition.StorageClass != nil { - rule["type"] = *transition.StorageClass - } - } - - rules = append(rules, rule) - } - } - return rules -} - -func expireRuleGet(in []*s3.LifecycleRule) []interface{} { - rules := make([]interface{}, 0, len(in)) - for _, r := range in { - if r.Expiration != nil { - rule := make(map[string]interface{}) - - if r.Status != nil { - if *r.Status == "Enabled" { - rule["enable"] = true - - } else { - rule["enable"] = false - } - } - if r.ID != nil { - rule["rule_id"] = *r.ID - } - - if r.Expiration != nil { - rule["days"] = int(*(r.Expiration).Days) - } - if r.Filter != nil && r.Filter.Prefix != nil { - rule["prefix"] = *(r.Filter).Prefix - } - - rules = append(rules, rule) - } - } - return rules -} - -func retentionRuleGet(in *s3.ProtectionConfiguration) []interface{} { - rules := make([]interface{}, 0, 1) - if in != nil && in.Status != nil && *in.Status == "COMPLIANCE" { - protectConfig := make(map[string]interface{}) - if in.DefaultRetention != nil { - protectConfig["default"] = int(*(in.DefaultRetention).Days) - } - if in.MaximumRetention != nil { - protectConfig["maximum"] = int(*(in.MaximumRetention).Days) - } - if in.MinimumRetention != nil { - protectConfig["minimum"] = int(*(in.MinimumRetention).Days) - } - if in.EnablePermanentRetention != nil { - protectConfig["permanent"] = *in.EnablePermanentRetention - } - rules = append(rules, protectConfig) - } - return rules -} - -func flattenCosObejctVersioning(in *s3.GetBucketVersioningOutput) []interface{} { - versioning := make([]interface{}, 0, 1) - if in != nil { - if in.Status != nil { - att := make(map[string]interface{}) - if *in.Status == "Enabled" { - att["enable"] = true - } else { - att["enable"] = false - } - versioning = append(versioning, att) - } - } - return versioning -} - -func flattenLimits(in *whisk.Limits) []interface{} { - att := make(map[string]interface{}) - if in.Timeout != nil { - att["timeout"] = *in.Timeout - } - if in.Memory != nil { - att["memory"] = *in.Memory - } - if in.Memory != nil { - att["log_size"] = *in.Logsize - } - return []interface{}{att} -} - -func expandExec(execs []interface{}) *whisk.Exec { - var code string - var document []byte - for _, exec := range execs { - e, _ := exec.(map[string]interface{}) - code_path := e["code_path"].(string) - if code_path != "" { - ext := path.Ext(code_path) - if strings.ToLower(ext) == ".zip" { - data, err := ioutil.ReadFile(code_path) - if err != nil { - log.Println("Error reading file", err) - return &whisk.Exec{} - } - sEnc := b64.StdEncoding.EncodeToString([]byte(data)) - code = sEnc - } else { - data, err := ioutil.ReadFile(code_path) - if err != nil { - log.Println("Error reading file", err) - return &whisk.Exec{} - } - document = data - code = string(document) - } - } else { - code = e["code"].(string) - } - obj := &whisk.Exec{ - Image: e["image"].(string), - Init: e["init"].(string), - Code: ptrToString(code), - Kind: e["kind"].(string), - Main: e["main"].(string), - Components: expandStringList(e["components"].([]interface{})), - } - return obj - } - - return &whisk.Exec{} -} - -func flattenExec(in *whisk.Exec, d *schema.ResourceData) []interface{} { - code_data := 4194304 // length of 'code' parameter should be always <= 4MB data - att := make(map[string]interface{}) - // open-whisk SDK will not return the value for code_path - // Hence using d.GetOk method to setback the code_path value. - if cPath, ok := d.GetOk("exec.0.code_path"); ok { - att["code_path"] = cPath.(string) - } - if in.Image != "" { - att["image"] = in.Image - } - if in.Init != "" { - att["init"] = in.Init - } - if in != nil && in.Code != nil && len(*in.Code) <= code_data { - att["code"] = *in.Code - } - if in.Kind != "" { - att["kind"] = in.Kind - } - if in.Main != "" { - att["main"] = in.Main - } - - if len(in.Components) > 0 { - att["components"] = flattenStringList(in.Components) - } - - return []interface{}{att} -} - -func ptrToInt(i int) *int { - return &i -} - -func ptrToString(s string) *string { - return &s -} - -func intValue(i64 *int64) (i int) { - if i64 != nil { - i = int(*i64) - } - return -} - -func float64Value(f32 *float32) (f float64) { - if f32 != nil { - f = float64(*f32) - } - return -} - -func dateToString(d *strfmt.Date) (s string) { - if d != nil { - s = d.String() - } - return -} - -func dateTimeToString(dt *strfmt.DateTime) (s string) { - if dt != nil { - s = dt.String() - } - return -} - -func filterActionAnnotations(in whisk.KeyValueArr) (string, error) { - noExec := make(whisk.KeyValueArr, 0, len(in)) - for _, v := range in { - if v.Key == "exec" { - continue - } - noExec = append(noExec, v) - } - - return flattenAnnotations(noExec) -} - -func filterActionParameters(in whisk.KeyValueArr) (string, error) { - noAction := make(whisk.KeyValueArr, 0, len(in)) - for _, v := range in { - if v.Key == "_actions" { - continue - } - noAction = append(noAction, v) - } - return flattenParameters(noAction) -} - -func filterInheritedAnnotations(inheritedAnnotations, annotations whisk.KeyValueArr) whisk.KeyValueArr { - userDefinedAnnotations := make(whisk.KeyValueArr, 0) - for _, a := range annotations { - insert := false - if a.Key == "binding" || a.Key == "exec" { - insert = false - break - } - for _, b := range inheritedAnnotations { - if a.Key == b.Key && reflect.DeepEqual(a.Value, b.Value) { - insert = false - break - } - insert = true - } - if insert { - userDefinedAnnotations = append(userDefinedAnnotations, a) - } - } - return userDefinedAnnotations -} - -func filterInheritedParameters(inheritedParameters, parameters whisk.KeyValueArr) whisk.KeyValueArr { - userDefinedParameters := make(whisk.KeyValueArr, 0) - for _, p := range parameters { - insert := false - if p.Key == "_actions" { - insert = false - break - } - for _, b := range inheritedParameters { - if p.Key == b.Key && reflect.DeepEqual(p.Value, b.Value) { - insert = false - break - } - insert = true - } - if insert { - userDefinedParameters = append(userDefinedParameters, p) - } - - } - return userDefinedParameters -} - -func isEmpty(object interface{}) bool { - //First check normal definitions of empty - if object == nil { - return true - } else if object == "" { - return true - } else if object == false { - return true - } - - //Then see if it's a struct - if reflect.ValueOf(object).Kind() == reflect.Struct { - // and create an empty copy of the struct object to compare against - empty := reflect.New(reflect.TypeOf(object)).Elem().Interface() - if reflect.DeepEqual(object, empty) { - return true - } - } - return false -} - -func filterTriggerAnnotations(in whisk.KeyValueArr) (string, error) { - noFeed := make(whisk.KeyValueArr, 0, len(in)) - for _, v := range in { - if v.Key == "feed" { - continue - } - noFeed = append(noFeed, v) - } - return flattenParameters(noFeed) -} - -func flattenFeed(feedName string) []interface{} { - att := make(map[string]interface{}) - att["name"] = feedName - att["parameters"] = "[]" - return []interface{}{att} -} - -func flattenGatewayVlans(list []datatypes.Network_Gateway_Vlan) []map[string]interface{} { - vlans := make([]map[string]interface{}, len(list)) - for i, ele := range list { - vlan := make(map[string]interface{}) - vlan["bypass"] = *ele.BypassFlag - vlan["network_vlan_id"] = *ele.NetworkVlanId - vlan["vlan_id"] = *ele.Id - vlans[i] = vlan - } - return vlans -} - -func flattenGatewayMembers(d *schema.ResourceData, list []datatypes.Network_Gateway_Member) []map[string]interface{} { - members := make([]map[string]interface{}, len(list)) - for i, ele := range list { - hardware := *ele.Hardware - member := make(map[string]interface{}) - member["member_id"] = *ele.HardwareId - member["hostname"] = *hardware.Hostname - member["domain"] = *hardware.Domain - if hardware.Notes != nil { - member["notes"] = *hardware.Notes - } - if hardware.Datacenter != nil { - member["datacenter"] = *hardware.Datacenter.Name - } - if hardware.PrimaryNetworkComponent.MaxSpeed != nil { - member["network_speed"] = *hardware.PrimaryNetworkComponent.MaxSpeed - } - member["redundant_network"] = false - member["unbonded_network"] = false - backendNetworkComponent := ele.Hardware.BackendNetworkComponents - - if len(backendNetworkComponent) > 2 && ele.Hardware.PrimaryBackendNetworkComponent != nil { - if *hardware.PrimaryBackendNetworkComponent.RedundancyEnabledFlag { - member["redundant_network"] = true - } else { - member["unbonded_network"] = true - } - } - tagReferences := ele.Hardware.TagReferences - tagReferencesLen := len(tagReferences) - if tagReferencesLen > 0 { - tags := make([]interface{}, 0, tagReferencesLen) - for _, tagRef := range tagReferences { - tags = append(tags, *tagRef.Tag.Name) - } - member["tags"] = schema.NewSet(schema.HashString, tags) - } - - member["redundant_power_supply"] = false - - if *hardware.PowerSupplyCount == 2 { - member["redundant_power_supply"] = true - } - member["memory"] = *hardware.MemoryCapacity - if !(*hardware.PrivateNetworkOnlyFlag) { - member["public_vlan_id"] = *hardware.NetworkVlans[1].Id - } - member["private_vlan_id"] = *hardware.NetworkVlans[0].Id - - if hardware.PrimaryIpAddress != nil { - member["public_ipv4_address"] = *hardware.PrimaryIpAddress - } - if hardware.PrimaryBackendIpAddress != nil { - member["private_ipv4_address"] = *hardware.PrimaryBackendIpAddress - } - member["ipv6_enabled"] = false - if ele.Hardware.PrimaryNetworkComponent.PrimaryVersion6IpAddressRecord != nil { - member["ipv6_enabled"] = true - member["ipv6_address"] = *hardware.PrimaryNetworkComponent.PrimaryVersion6IpAddressRecord.IpAddress - } - - member["private_network_only"] = *hardware.PrivateNetworkOnlyFlag - userData := hardware.UserData - if len(userData) > 0 && userData[0].Value != nil { - member["user_metadata"] = *userData[0].Value - } - members[i] = member - } - return members -} - -func flattenDisks(result datatypes.Virtual_Guest) []int { - var out = make([]int, 0) - - for _, v := range result.BlockDevices { - // skip 1,7 which is reserved for the swap disk and metadata - _, ok := sl.GrabOk(result, "BillingItem.OrderItem.Preset") - if ok { - if *v.Device != "1" && *v.Device != "7" && *v.Device != "0" { - capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") - - if ok { - out = append(out, capacity.(int)) - } - - } - } else { - if *v.Device != "1" && *v.Device != "7" { - capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") - - if ok { - out = append(out, capacity.(int)) - } - } - } - } - - return out -} - -func flattenDisksForWindows(result datatypes.Virtual_Guest) []int { - var out = make([]int, 0) - - for _, v := range result.BlockDevices { - // skip 1,7 which is reserved for the swap disk and metadata - _, ok := sl.GrabOk(result, "BillingItem.OrderItem.Preset") - if ok { - if *v.Device != "1" && *v.Device != "7" && *v.Device != "0" && *v.Device != "3" { - capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") - - if ok { - out = append(out, capacity.(int)) - } - } - } else { - if *v.Device != "1" && *v.Device != "7" && *v.Device != "3" { - capacity, ok := sl.GrabOk(v, "DiskImage.Capacity") - - if ok { - out = append(out, capacity.(int)) - } - } - } - } - - return out -} - -func filterResourceKeyParameters(params map[string]interface{}) map[string]interface{} { - delete(params, "role_crn") - return params -} - -func idParts(id string) ([]string, error) { - if strings.Contains(id, "/") { - parts := strings.Split(id, "/") - return parts, nil - } - return []string{}, fmt.Errorf("The given id %s does not contain / please check documentation on how to provider id during import command", id) -} - -func sepIdParts(id string, separator string) ([]string, error) { - if strings.Contains(id, separator) { - parts := strings.Split(id, separator) - return parts, nil - } - return []string{}, fmt.Errorf("The given id %s does not contain %s please check documentation on how to provider id during import command", id, separator) -} - -func vmIdParts(id string) ([]string, error) { - parts := strings.Split(id, "/") - return parts, nil -} - -func cfIdParts(id string) ([]string, error) { - parts := strings.Split(id, ":") - return parts, nil -} - -// getCustomAttributes will return all attributes which are not system defined -func getCustomAttributes(r iampolicymanagementv1.PolicyResource) []iampolicymanagementv1.ResourceAttribute { - attributes := []iampolicymanagementv1.ResourceAttribute{} - for _, a := range r.Attributes { - switch *a.Name { - case "accesGroupId": - case "accountId": - case "organizationId": - case "spaceId": - case "region": - case "resource": - case "resourceType": - case "resourceGroupId": - case "serviceType": - case "serviceName": - case "serviceInstance": - default: - attributes = append(attributes, a) - } - } - return attributes -} - -func flattenPolicyResource(list []iampolicymanagementv1.PolicyResource) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - l := map[string]interface{}{ - "service": getResourceAttribute("serviceName", i), - "resource_instance_id": getResourceAttribute("serviceInstance", i), - "region": getResourceAttribute("region", i), - "resource_type": getResourceAttribute("resourceType", i), - "resource": getResourceAttribute("resource", i), - "resource_group_id": getResourceAttribute("resourceGroupId", i), - } - customAttributes := getCustomAttributes(i) - if len(customAttributes) > 0 { - out := make(map[string]string) - for _, a := range customAttributes { - out[*a.Name] = *a.Value - } - l["attributes"] = out - } - - result = append(result, l) - } - return result -} -func flattenPolicyResourceAttributes(list []iampolicymanagementv1.PolicyResource) []map[string]interface{} { - result := make([]map[string]interface{}, 0) - for _, i := range list { - for _, a := range i.Attributes { - if *a.Name != "accountId" { - l := map[string]interface{}{ - "name": a.Name, - "value": a.Value, - "operator": a.Operator, - } - result = append(result, l) - } - } - } - return result -} - -// Cloud Internet Services -func flattenHealthMonitors(list []datatypes.Network_LBaaS_Listener) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - ports := make([]int, 0, 0) - for _, i := range list { - l := map[string]interface{}{ - "protocol": *i.DefaultPool.Protocol, - "port": *i.DefaultPool.ProtocolPort, - "interval": *i.DefaultPool.HealthMonitor.Interval, - "max_retries": *i.DefaultPool.HealthMonitor.MaxRetries, - "timeout": *i.DefaultPool.HealthMonitor.Timeout, - "monitor_id": *i.DefaultPool.HealthMonitor.Uuid, - } - - if i.DefaultPool.HealthMonitor.UrlPath != nil { - l["url_path"] = *i.DefaultPool.HealthMonitor.UrlPath - } - - if !contains(ports, *i.DefaultPool.ProtocolPort) { - result = append(result, l) - } - - ports = append(ports, *i.DefaultPool.ProtocolPort) - } - return result -} - -func contains(s []int, e int) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} -func StringContains(s []string, str string) bool { - for _, a := range s { - if a == str { - return true - } - } - return false -} - -func flattenMembersData(list []iamaccessgroupsv2.ListGroupMembersResponseMember, users []usermanagementv2.UserInfo, serviceids []iamidentityv1.ServiceID) ([]string, []string) { - var ibmid []string - var serviceid []string - for _, m := range list { - if *m.Type == "user" { - for _, user := range users { - if user.IamID == *m.IamID { - ibmid = append(ibmid, user.Email) - break - } - } - } else { - - for _, srid := range serviceids { - if *srid.IamID == *m.IamID { - serviceid = append(serviceid, *srid.ID) - break - } - } - - } - - } - return ibmid, serviceid -} - -func flattenAccessGroupMembers(list []iamaccessgroupsv2.ListGroupMembersResponseMember, users []usermanagementv2.UserInfo, serviceids []iamidentityv1.ServiceID) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, m := range list { - var value, vtype string - vtype = *m.Type - if *m.Type == "user" { - for _, user := range users { - if user.IamID == *m.IamID { - value = user.Email - break - } - } - } else { - for _, srid := range serviceids { - if *srid.IamID == *m.IamID { - value = *srid.ID - break - } - } - - } - l := map[string]interface{}{ - "iam_id": value, - "type": vtype, - } - result = append(result, l) - } - return result -} - -func flattenUserIds(accountID string, users []string, meta interface{}) ([]string, error) { - userids := make([]string, len(users)) - for i, name := range users { - iamID, err := getIBMUniqueId(accountID, name, meta) - if err != nil { - return nil, err - } - userids[i] = iamID - } - return userids, nil -} - -func flattenServiceIds(services []string, meta interface{}) ([]string, error) { - serviceids := make([]string, len(services)) - for i, id := range services { - serviceID, err := getServiceID(id, meta) - if err != nil { - return nil, err - } - serviceids[i] = *serviceID.IamID - } - return serviceids, nil -} - -func expandUsers(userList *schema.Set) (users []icdv4.User) { - for _, iface := range userList.List() { - userEl := iface.(map[string]interface{}) - user := icdv4.User{ - UserName: userEl["name"].(string), - Password: userEl["password"].(string), - } - users = append(users, user) - } - return -} - -// IBM Cloud Databases -func flattenConnectionStrings(cs []CsEntry) []map[string]interface{} { - entries := make([]map[string]interface{}, len(cs), len(cs)) - for i, csEntry := range cs { - l := map[string]interface{}{ - "name": csEntry.Name, - "password": csEntry.Password, - "composed": csEntry.Composed, - "certname": csEntry.CertName, - "certbase64": csEntry.CertBase64, - "queryoptions": csEntry.QueryOptions, - "scheme": csEntry.Scheme, - "path": csEntry.Path, - "database": csEntry.Database, - "bundlename": csEntry.BundleName, - "bundlebase64": csEntry.BundleBase64, - } - hosts := csEntry.Hosts - hostsList := make([]map[string]interface{}, len(hosts), len(hosts)) - for j, host := range hosts { - z := map[string]interface{}{ - "hostname": host.HostName, - "port": strconv.Itoa(host.Port), - } - hostsList[j] = z - } - l["hosts"] = hostsList - var queryOpts string - if len(csEntry.QueryOptions) != 0 { - queryOpts = "?" - count := 0 - for k, v := range csEntry.QueryOptions { - if count >= 1 { - queryOpts = queryOpts + "&" - } - queryOpts = queryOpts + fmt.Sprintf("%v", k) + "=" + fmt.Sprintf("%v", v) - count++ - } - } else { - queryOpts = "" - } - l["queryoptions"] = queryOpts - entries[i] = l - } - - return entries -} - -func flattenPhaseOneAttributes(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { - phaseoneAttributesMap := make([]map[string]interface{}, 0, 1) - phaseoneAttributes := make(map[string]interface{}) - phaseoneAttributes["authentication"] = *vpn.PhaseOneAuthentication - phaseoneAttributes["encryption"] = *vpn.PhaseOneEncryption - phaseoneAttributes["diffie_hellman_group"] = *vpn.PhaseOneDiffieHellmanGroup - phaseoneAttributes["keylife"] = *vpn.PhaseOneKeylife - phaseoneAttributesMap = append(phaseoneAttributesMap, phaseoneAttributes) - return phaseoneAttributesMap -} - -func flattenPhaseTwoAttributes(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { - phasetwoAttributesMap := make([]map[string]interface{}, 0, 1) - phasetwoAttributes := make(map[string]interface{}) - phasetwoAttributes["authentication"] = *vpn.PhaseTwoAuthentication - phasetwoAttributes["encryption"] = *vpn.PhaseTwoEncryption - phasetwoAttributes["diffie_hellman_group"] = *vpn.PhaseTwoDiffieHellmanGroup - phasetwoAttributes["keylife"] = *vpn.PhaseTwoKeylife - phasetwoAttributesMap = append(phasetwoAttributesMap, phasetwoAttributes) - return phasetwoAttributesMap -} - -func flattenaddressTranslation(vpn *datatypes.Network_Tunnel_Module_Context, fwID int) []map[string]interface{} { - addressTranslationMap := make([]map[string]interface{}, 0, 1) - addressTranslationAttributes := make(map[string]interface{}) - for _, networkAddressTranslation := range vpn.AddressTranslations { - if *networkAddressTranslation.NetworkTunnelContext.Id == fwID { - addressTranslationAttributes["remote_ip_adress"] = *networkAddressTranslation.CustomerIpAddress - addressTranslationAttributes["internal_ip_adress"] = *networkAddressTranslation.InternalIpAddress - addressTranslationAttributes["notes"] = *networkAddressTranslation.Notes - } - } - addressTranslationMap = append(addressTranslationMap, addressTranslationAttributes) - return addressTranslationMap -} - -func flattenremoteSubnet(vpn *datatypes.Network_Tunnel_Module_Context) []map[string]interface{} { - remoteSubnetMap := make([]map[string]interface{}, 0, 1) - remoteSubnetAttributes := make(map[string]interface{}) - for _, customerSubnet := range vpn.CustomerSubnets { - remoteSubnetAttributes["remote_ip_adress"] = customerSubnet.NetworkIdentifier - remoteSubnetAttributes["remote_ip_cidr"] = customerSubnet.Cidr - remoteSubnetAttributes["account_id"] = customerSubnet.AccountId - } - remoteSubnetMap = append(remoteSubnetMap, remoteSubnetAttributes) - return remoteSubnetMap -} - -// IBM Cloud Databases -func expandWhitelist(whiteList *schema.Set) (whitelist []icdv4.WhitelistEntry) { - for _, iface := range whiteList.List() { - wlItem := iface.(map[string]interface{}) - wlEntry := icdv4.WhitelistEntry{ - Address: wlItem["address"].(string), - Description: wlItem["description"].(string), - } - whitelist = append(whitelist, wlEntry) - } - return -} - -// Cloud Internet Services -func flattenWhitelist(whitelist icdv4.Whitelist) []map[string]interface{} { - entries := make([]map[string]interface{}, len(whitelist.WhitelistEntrys), len(whitelist.WhitelistEntrys)) - for i, whitelistEntry := range whitelist.WhitelistEntrys { - l := map[string]interface{}{ - "address": whitelistEntry.Address, - "description": whitelistEntry.Description, - } - entries[i] = l - } - return entries -} - -func expandStringMap(inVal interface{}) map[string]string { - outVal := make(map[string]string) - if inVal == nil { - return outVal - } - for k, v := range inVal.(map[string]interface{}) { - strValue := fmt.Sprintf("%v", v) - outVal[k] = strValue - } - return outVal -} - -// Cloud Internet Services -func convertTfToCisThreeVar(glbTfId string) (glbId string, zoneId string, cisId string, err error) { - g := strings.SplitN(glbTfId, ":", 3) - glbId = g[0] - if len(g) > 2 { - zoneId = g[1] - cisId = g[2] - } else { - err = errors.New("cis_id or zone_id not passed") - return - } - return -} -func convertCisToTfFourVar(firewallType string, ID string, ID2 string, cisID string) (buildID string) { - if ID != "" { - buildID = firewallType + ":" + ID + ":" + ID2 + ":" + cisID - } else { - buildID = "" - } - return -} -func convertTfToCisFourVar(TfID string) (firewallType string, ID string, zoneID string, cisID string, err error) { - g := strings.SplitN(TfID, ":", 4) - firewallType = g[0] - if len(g) > 3 { - ID = g[1] - zoneID = g[2] - cisID = g[3] - } else { - err = errors.New("Id or cis_id or zone_id not passed") - return - } - return -} - -// Cloud Internet Services -func convertCisToTfThreeVar(Id string, Id2 string, cisId string) (buildId string) { - if Id != "" { - buildId = Id + ":" + Id2 + ":" + cisId - } else { - buildId = "" - } - return -} - -// Cloud Internet Services -func convertTfToCisTwoVarSlice(tfIds []string) (Ids []string, cisId string, err error) { - for _, item := range tfIds { - Id := strings.SplitN(item, ":", 2) - if len(Id) < 2 { - err = errors.New("cis_id not passed") - return - } - Ids = append(Ids, Id[0]) - cisId = Id[1] - } - return -} - -// Cloud Internet Services -func convertCisToTfTwoVarSlice(Ids []string, cisId string) (buildIds []string) { - for _, Id := range Ids { - buildIds = append(buildIds, Id+":"+cisId) - } - return -} - -// Cloud Internet Services -func convertCisToTfTwoVar(Id string, cisId string) (buildId string) { - if Id != "" { - buildId = Id + ":" + cisId - } else { - buildId = "" - } - return -} - -// Cloud Internet Services -func convertTftoCisTwoVar(tfId string) (Id string, cisId string, err error) { - g := strings.SplitN(tfId, ":", 2) - Id = g[0] - if len(g) > 1 { - cisId = g[1] - } else { - err = errors.New(" cis_id or zone_id not passed") - return - } - return -} - -// Cloud Internet Services -func transformToIBMCISDnsData(recordType string, id string, value interface{}) (newValue interface{}, err error) { - switch { - case id == "flags": - switch { - case strings.ToUpper(recordType) == "SRV", - strings.ToUpper(recordType) == "CAA", - strings.ToUpper(recordType) == "DNSKEY": - newValue, err = strconv.Atoi(value.(string)) - case strings.ToUpper(recordType) == "NAPTR": - newValue, err = value.(string), nil - } - case stringInSlice(id, dnsTypeIntFields): - newValue, err = strconv.Atoi(value.(string)) - case stringInSlice(id, dnsTypeFloatFields): - newValue, err = strconv.ParseFloat(value.(string), 32) - default: - newValue, err = value.(string), nil - } - - return -} - -func indexOf(element string, data []string) int { - for k, v := range data { - if element == v { - return k - } - } - return -1 //not found. -} - -func rcInstanceExists(resourceId string, resourceType string, meta interface{}) (bool, error) { - // Check to see if Resource Manager instance exists - rsConClient, err := meta.(ClientSession).ResourceControllerAPI() - if err != nil { - return true, nil - } - exists := true - instance, err := rsConClient.ResourceServiceInstance().GetInstance(resourceId) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - exists = false - } else { - return true, fmt.Errorf("Error checking resource instance exists: %s", err) - } - } else { - if strings.Contains(instance.State, "removed") { - exists = false - } - } - if exists { - return true, nil - } - // Implement when pointer to terraform.State available - // If rcInstance is now in removed state, set TF state to removed - // s := *terraform.State - // for _, r := range s.RootModule().Resources { - // if r.Type != resourceType { - // continue - // } - // if r.Primary.ID == resourceId { - // r.Primary.Set("status", "removed") - // } - // } - return false, nil -} - -// Implement when pointer to terraform.State available -// func resourceInstanceExistsTf(resourceId string, resourceType string) bool { -// // Check TF state to see if Cloud resource instance has already been removed -// s := *terraform.State -// for _, r := range s.RootModule().Resources { -// if r.Type != resourceType { -// continue -// } -// if r.Primary.ID == resourceId { -// if strings.Contains(r.Primary.Attributes["status"], "removed") { -// return false -// } -// } -// } -// return true -// } - -// convert CRN to be url safe -func EscapeUrlParm(urlParm string) string { - if strings.Contains(urlParm, "/") { - newUrlParm := url.PathEscape(urlParm) - return newUrlParm - } - return urlParm -} - -func GetTags(d *schema.ResourceData, meta interface{}) error { - resourceID := d.Id() - gtClient, err := meta.(ClientSession).GlobalTaggingAPI() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - taggingResult, err := gtClient.Tags().GetTags(resourceID) - if err != nil { - return err - } - var taglist []string - for _, item := range taggingResult.Items { - taglist = append(taglist, item.Name) - } - d.Set("tags", flattenStringList(taglist)) - return nil -} - -func UpdateTags(d *schema.ResourceData, meta interface{}) error { - resourceID := d.Id() - gtClient, err := meta.(ClientSession).GlobalTaggingAPI() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - oldList, newList := d.GetChange("tags") - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - olds := oldList.(*schema.Set) - news := newList.(*schema.Set) - removeInt := olds.Difference(news).List() - addInt := news.Difference(olds).List() - add := make([]string, len(addInt)) - for i, v := range addInt { - add[i] = fmt.Sprint(v) - } - remove := make([]string, len(removeInt)) - for i, v := range removeInt { - remove[i] = fmt.Sprint(v) - } - - if len(add) > 0 { - _, err := gtClient.Tags().AttachTags(resourceID, add) - if err != nil { - return fmt.Errorf("Error updating database tags %v : %s", add, err) - } - } - if len(remove) > 0 { - _, err := gtClient.Tags().DetachTags(resourceID, remove) - if err != nil { - return fmt.Errorf("Error detaching database tags %v: %s", remove, err) - } - for _, v := range remove { - _, err := gtClient.Tags().DeleteTag(v) - if err != nil { - return fmt.Errorf("Error deleting database tag %v: %s", v, err) - } - } - } - return nil -} - -func GetGlobalTagsUsingCRN(meta interface{}, resourceID, resourceType, tagType string) (*schema.Set, error) { - - gtClient, err := meta.(ClientSession).GlobalTaggingAPIv1() - if err != nil { - return nil, fmt.Errorf("Error getting global tagging client settings: %s", err) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return nil, err - } - accountID := userDetails.userAccount - - var providers []string - if strings.Contains(resourceType, "SoftLayer_") { - providers = []string{"ims"} - } - - ListTagsOptions := &globaltaggingv1.ListTagsOptions{} - ListTagsOptions.AttachedTo = &resourceID - ListTagsOptions.Providers = providers - if len(tagType) > 0 { - ListTagsOptions.TagType = ptrToString(tagType) - - if tagType == service { - ListTagsOptions.AccountID = ptrToString(accountID) - } - } - taggingResult, _, err := gtClient.ListTags(ListTagsOptions) - if err != nil { - return nil, err - } - var taglist []string - for _, item := range taggingResult.Items { - taglist = append(taglist, *item.Name) - } - log.Println("tagList: ", taglist) - return newStringSet(resourceIBMVPCHash, taglist), nil -} - -func UpdateGlobalTagsUsingCRN(oldList, newList interface{}, meta interface{}, resourceID, resourceType, tagType string) error { - gtClient, err := meta.(ClientSession).GlobalTaggingAPIv1() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err - } - acctID := userDetails.userAccount - - resources := []globaltaggingv1.Resource{} - r := globaltaggingv1.Resource{ResourceID: ptrToString(resourceID), ResourceType: ptrToString(resourceType)} - resources = append(resources, r) - - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - olds := oldList.(*schema.Set) - news := newList.(*schema.Set) - removeInt := olds.Difference(news).List() - addInt := news.Difference(olds).List() - add := make([]string, len(addInt)) - for i, v := range addInt { - add[i] = fmt.Sprint(v) - } - remove := make([]string, len(removeInt)) - for i, v := range removeInt { - remove[i] = fmt.Sprint(v) - } - - if strings.TrimSpace(tagType) == "" || tagType == "user" { - schematicTags := os.Getenv("IC_ENV_TAGS") - var envTags []string - if schematicTags != "" { - envTags = strings.Split(schematicTags, ",") - add = append(add, envTags...) - } - } - - if len(remove) > 0 { - detachTagOptions := &globaltaggingv1.DetachTagOptions{} - detachTagOptions.Resources = resources - detachTagOptions.TagNames = remove - if len(tagType) > 0 { - detachTagOptions.TagType = ptrToString(tagType) - if tagType == service { - detachTagOptions.AccountID = ptrToString(acctID) - } - } - - _, resp, err := gtClient.DetachTag(detachTagOptions) - if err != nil { - return fmt.Errorf("Error detaching database tags %v: %s\n%s", remove, err, resp) - } - for _, v := range remove { - delTagOptions := &globaltaggingv1.DeleteTagOptions{ - TagName: ptrToString(v), - } - _, resp, err := gtClient.DeleteTag(delTagOptions) - if err != nil { - return fmt.Errorf("Error deleting database tag %v: %s\n%s", v, err, resp) - } - } - } - - if len(add) > 0 { - AttachTagOptions := &globaltaggingv1.AttachTagOptions{} - AttachTagOptions.Resources = resources - AttachTagOptions.TagNames = add - if len(tagType) > 0 { - AttachTagOptions.TagType = ptrToString(tagType) - if tagType == service { - AttachTagOptions.AccountID = ptrToString(acctID) - } - } - - _, resp, err := gtClient.AttachTag(AttachTagOptions) - if err != nil { - return fmt.Errorf("Error updating database tags %v : %s\n%s", add, err, resp) - } - } - - return nil -} - -func GetTagsUsingCRN(meta interface{}, resourceCRN string) (*schema.Set, error) { - - gtClient, err := meta.(ClientSession).GlobalTaggingAPI() - if err != nil { - return nil, fmt.Errorf("Error getting global tagging client settings: %s", err) - } - taggingResult, err := gtClient.Tags().GetTags(resourceCRN) - if err != nil { - return nil, err - } - var taglist []string - for _, item := range taggingResult.Items { - taglist = append(taglist, item.Name) - } - log.Println("tagList: ", taglist) - return newStringSet(resourceIBMVPCHash, taglist), nil -} - -func UpdateTagsUsingCRN(oldList, newList interface{}, meta interface{}, resourceCRN string) error { - gtClient, err := meta.(ClientSession).GlobalTaggingAPI() - if err != nil { - return fmt.Errorf("Error getting global tagging client settings: %s", err) - } - if oldList == nil { - oldList = new(schema.Set) - } - if newList == nil { - newList = new(schema.Set) - } - olds := oldList.(*schema.Set) - news := newList.(*schema.Set) - removeInt := olds.Difference(news).List() - addInt := news.Difference(olds).List() - add := make([]string, len(addInt)) - for i, v := range addInt { - add[i] = fmt.Sprint(v) - } - remove := make([]string, len(removeInt)) - for i, v := range removeInt { - remove[i] = fmt.Sprint(v) - } - - schematicTags := os.Getenv("IC_ENV_TAGS") - var envTags []string - if schematicTags != "" { - envTags = strings.Split(schematicTags, ",") - add = append(add, envTags...) - } - - if len(remove) > 0 { - _, err := gtClient.Tags().DetachTags(resourceCRN, remove) - if err != nil { - return fmt.Errorf("Error detaching database tags %v: %s", remove, err) - } - for _, v := range remove { - _, err := gtClient.Tags().DeleteTag(v) - if err != nil { - return fmt.Errorf("Error deleting database tag %v: %s", v, err) - } - } - } - - if len(add) > 0 { - _, err := gtClient.Tags().AttachTags(resourceCRN, add) - if err != nil { - return fmt.Errorf("Error updating database tags %v : %s", add, err) - } - } - - return nil -} - -func getBaseController(meta interface{}) (string, error) { - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return "", err - } - if userDetails != nil && userDetails.cloudName == "staging" { - return stageBaseController, nil - } - return prodBaseController, nil -} - -func flattenSSLCiphers(ciphers []datatypes.Network_LBaaS_SSLCipher) *schema.Set { - c := make([]string, len(ciphers)) - for i, v := range ciphers { - c[i] = *v.Name - } - return newStringSet(schema.HashString, c) -} - -func resourceTagsCustomizeDiff(diff *schema.ResourceDiff) error { - - if diff.Id() != "" && diff.HasChange("tags") { - o, n := diff.GetChange("tags") - oldSet := o.(*schema.Set) - newSet := n.(*schema.Set) - removeInt := oldSet.Difference(newSet).List() - addInt := newSet.Difference(oldSet).List() - if v := os.Getenv("IC_ENV_TAGS"); v != "" { - s := strings.Split(v, ",") - if len(removeInt) == len(s) && len(addInt) == 0 { - fmt.Println("Suppresing the TAG diff ") - return diff.Clear("tags") - } - } - } - return nil -} - -func resourceLBListenerPolicyCustomizeDiff(diff *schema.ResourceDiff) error { - policyActionIntf, _ := diff.GetOk(isLBListenerPolicyAction) - policyAction := policyActionIntf.(string) - - if policyAction == "forward" { - _, policyTargetIDSet := diff.GetOk(isLBListenerPolicyTargetID) - - if !policyTargetIDSet && diff.NewValueKnown(isLBListenerPolicyTargetID) { - return fmt.Errorf("Load balancer listener policy: When action is forward please specify target_id") - } - } else if policyAction == "redirect" { - _, httpsStatusCodeSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectStatusCode) - _, targetURLSet := diff.GetOk(isLBListenerPolicyTargetURL) - - if !httpsStatusCodeSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectStatusCode) { - return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_http_status_code") - } - - if !targetURLSet && diff.NewValueKnown(isLBListenerPolicyTargetURL) { - return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_url") - } - } else if policyAction == "https_redirect" { - _, listenerSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectListener) - _, httpsStatusSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectStatusCode) - - if !listenerSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectListener) { - return fmt.Errorf("Load balancer listener policy: When action is https_redirect please specify target_https_redirect_listener") - } - - if !httpsStatusSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectStatusCode) { - return fmt.Errorf("When action is https_redirect please specify target_https_redirect_status_code") - } - } - - return nil -} - -func resourceIBMISLBPoolCookieValidate(diff *schema.ResourceDiff) error { - _, sessionPersistenceTypeIntf := diff.GetChange(isLBPoolSessPersistenceType) - _, sessionPersistenceCookieNameIntf := diff.GetChange(isLBPoolSessPersistenceAppCookieName) - sessionPersistenceType := sessionPersistenceTypeIntf.(string) - sessionPersistenceCookieName := sessionPersistenceCookieNameIntf.(string) - - if sessionPersistenceType == "app_cookie" { - if sessionPersistenceCookieName == "" { - return fmt.Errorf("Load Balancer Pool: %s is required for %s 'app_cookie'", isLBPoolSessPersistenceAppCookieName, isLBPoolSessPersistenceType) - } - if strings.HasPrefix(sessionPersistenceCookieName, "IBM") { - return fmt.Errorf("Load Balancer Pool: %s starting with IBM are not allowed", isLBPoolSessPersistenceAppCookieName) - } - } - - if sessionPersistenceCookieName != "" && sessionPersistenceType != "app_cookie" { - return fmt.Errorf("Load Balancer Pool: %s is only applicable for %s 'app_cookie'.", isLBPoolSessPersistenceAppCookieName, isLBPoolSessPersistenceType) - } - return nil -} - -func resourceVolumeAttachmentValidate(diff *schema.ResourceDiff) error { - - if volsintf, ok := diff.GetOk("volume_attachments"); ok { - vols := volsintf.([]interface{}) - for volAttIdx := range vols { - volumeid := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + isInstanceTemplateVolAttVol - volumePrototype := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + isInstanceTemplateVolAttVolPrototype - var volIdnterpolated = false - var volumeIdFound = false - if _, volumeIdFound = diff.GetOk(volumeid); !volumeIdFound { - if !diff.NewValueKnown(volumeid) { - volIdnterpolated = true - } - } - _, volPrototypeFound := diff.GetOk(volumePrototype) - - if volPrototypeFound && (volumeIdFound || volIdnterpolated) { - return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Cannot provide both 'volume' and 'volume_prototype' together.", volAttIdx) - } - if !volPrototypeFound && !volumeIdFound && !volIdnterpolated { - return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Volume details missing. Provide either 'volume' or 'volume_prototype'.", volAttIdx) - } - } - } - - return nil -} - -func resourceVolumeValidate(diff *schema.ResourceDiff) error { - - if diff.Id() != "" && diff.HasChange(isVolumeCapacity) { - o, n := diff.GetChange(isVolumeCapacity) - old := int64(o.(int)) - new := int64(n.(int)) - if new < old { - return fmt.Errorf("'%s' attribute has a constraint, it supports only expansion and can't be changed from %d to %d.", isVolumeCapacity, old, new) - } - } - - profile := "" - var capacity, iops int64 - if profileOk, ok := diff.GetOk(isVolumeProfileName); ok { - profile = profileOk.(string) - } - if capacityOk, ok := diff.GetOk(isVolumeCapacity); ok { - capacity = int64(capacityOk.(int)) - } - - if capacity == int64(0) { - capacity = int64(100) - } - if profile == "5iops-tier" && capacity > 9600 { - return fmt.Errorf("'%s' storage block supports capacity up to %d.", profile, 9600) - } else if profile == "10iops-tier" && capacity > 4800 { - return fmt.Errorf("'%s' storage block supports capacity up to %d.", profile, 4800) - } - - if iopsOk, ok := diff.GetOk(isVolumeIops); ok { - iops = int64(iopsOk.(int)) - } - - if diff.HasChange(isVolumeProfileName) { - oldProfile, newProfile := diff.GetChange(isVolumeProfileName) - if oldProfile.(string) == "custom" || newProfile.(string) == "custom" { - diff.ForceNew(isVolumeProfileName) - } - } - - if profile != "custom" { - if iops != 0 && diff.NewValueKnown(isVolumeIops) && diff.HasChange(isVolumeIops) { - return fmt.Errorf("VolumeError : iops is applicable for only custom volume profiles") - } - } else { - if capacity == 0 { - capacity = int64(100) - } - if capacity >= 10 && capacity <= 39 { - min := int64(100) - max := int64(1000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 40 && capacity <= 79 { - min := int64(100) - max := int64(2000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 80 && capacity <= 99 { - min := int64(100) - max := int64(4000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 100 && capacity <= 499 { - min := int64(100) - max := int64(6000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 500 && capacity <= 999 { - min := int64(100) - max := int64(10000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 1000 && capacity <= 1999 { - min := int64(100) - max := int64(20000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 2000 && capacity <= 3999 { - min := int64(200) - max := int64(40000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 4000 && capacity <= 7999 { - min := int64(300) - max := int64(40000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 8000 && capacity <= 9999 { - min := int64(500) - max := int64(48000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - if capacity >= 10000 && capacity <= 16000 { - min := int64(1000) - max := int64(48000) - if !(iops >= min && iops <= max) { - return fmt.Errorf("VolumeError : allowed iops value for capacity(%d) is [%d-%d] ", capacity, min, max) - } - } - } - return nil -} - -func resourceRouteModeValidate(diff *schema.ResourceDiff) error { - - var lbtype, lbprofile string - if typeOk, ok := diff.GetOk(isLBType); ok { - lbtype = typeOk.(string) - } - if profileOk, ok := diff.GetOk(isLBProfile); ok { - lbprofile = profileOk.(string) - } - if rmOk, ok := diff.GetOk(isLBRouteMode); ok { - routeMode := rmOk.(bool) - - if routeMode && lbtype != "private" { - return fmt.Errorf("'type' must be 'private', at present public load balancers are not supported with route mode enabled.") - } - if routeMode && lbprofile != "network-fixed" { - return fmt.Errorf("'profile' must be 'network-fixed', route mode is supported by private network load balancer.") - } - } - - return nil -} - -func flattenRoleData(object []iampolicymanagementv1.Role, roleType string) []map[string]string { - var roles []map[string]string - - for _, item := range object { - role := make(map[string]string) - role["name"] = *item.DisplayName - role["type"] = roleType - role["description"] = *item.Description - roles = append(roles, role) - } - return roles -} - -func flattenCustomRoleData(object []iampolicymanagementv1.CustomRole, roleType string) []map[string]string { - var roles []map[string]string - - for _, item := range object { - role := make(map[string]string) - role["name"] = *item.DisplayName - role["type"] = roleType - role["description"] = *item.Description - roles = append(roles, role) - } - return roles -} - -func flattenActions(object []iampolicymanagementv1.Role) map[string]interface{} { - actions := map[string]interface{}{ - "reader": flattenActionbyDisplayName("Reader", object), - "manager": flattenActionbyDisplayName("Manager", object), - "reader_plus": flattenActionbyDisplayName("ReaderPlus", object), - "writer": flattenActionbyDisplayName("Writer", object), - } - return actions -} - -func flattenActionbyDisplayName(displayName string, object []iampolicymanagementv1.Role) []string { - var actionIDs []string - for _, role := range object { - if *role.DisplayName == displayName { - actionIDs = role.Actions - } - } - return actionIDs -} - -func flattenCatalogRef(object schematics.CatalogInfo) map[string]interface{} { - catalogRef := map[string]interface{}{ - "item_id": object.ItemID, - "item_name": object.ItemName, - "item_url": object.ItemURL, - "offering_version": object.OfferingVersion, - } - return catalogRef -} - -// GetNext ... -func GetNext(next interface{}) string { - if reflect.ValueOf(next).IsNil() { - return "" - } - - u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) - if err != nil { - return "" - } - - q := u.Query() - return q.Get("start") -} - -// GetNextIAM ... -func GetNextIAM(next interface{}) string { - if reflect.ValueOf(next).IsNil() { - return "" - } - - u, err := url.Parse(reflect.ValueOf(next).Elem().String()) - if err != nil { - return "" - } - q := u.Query() - return q.Get("pagetoken") -} - -/* Return the default resource group */ -func defaultResourceGroup(meta interface{}) (string, error) { - - rMgtClient, err := meta.(ClientSession).ResourceManagerV2API() - if err != nil { - return "", err - } - defaultGrp := true - resourceGroupList := rg.ListResourceGroupsOptions{ - Default: &defaultGrp, - } - grpList, resp, err := rMgtClient.ListResourceGroups(&resourceGroupList) - if err != nil || grpList == nil || grpList.Resources == nil { - return "", fmt.Errorf("[ERROR] Error retrieving resource group: %s %s", err, resp) - } - if len(grpList.Resources) <= 0 { - return "", fmt.Errorf("[ERROR] The default resource group could not be found. Make sure you have required permissions to access the resource group") - } - return *grpList.Resources[0].ID, nil -} - -func flattenKeyPolicies(policies []kp.Policy) []map[string]interface{} { - policyMap := make([]map[string]interface{}, 0, 1) - rotationMap := make([]map[string]interface{}, 0, 1) - dualAuthMap := make([]map[string]interface{}, 0, 1) - for _, policy := range policies { - log.Println("Policy CRN Data =============>", policy.CRN) - policyCRNData := strings.Split(policy.CRN, ":") - policyInstance := map[string]interface{}{ - "id": policyCRNData[9], - "crn": policy.CRN, - "created_by": policy.CreatedBy, - "creation_date": (*(policy.CreatedAt)).String(), - "updated_by": policy.UpdatedBy, - "last_update_date": (*(policy.UpdatedAt)).String(), - } - if policy.Rotation != nil { - policyInstance["interval_month"] = policy.Rotation.Interval - rotationMap = append(rotationMap, policyInstance) - } else if policy.DualAuth != nil { - policyInstance["enabled"] = *(policy.DualAuth.Enabled) - dualAuthMap = append(dualAuthMap, policyInstance) - } - } - tempMap := map[string]interface{}{ - "rotation": rotationMap, - "dual_auth_delete": dualAuthMap, - } - policyMap = append(policyMap, tempMap) - return policyMap -} - -func flattenKeyIndividualPolicy(policy string, policies []kp.Policy) []map[string]interface{} { - rotationMap := make([]map[string]interface{}, 0, 1) - dualAuthMap := make([]map[string]interface{}, 0, 1) - for _, policy := range policies { - log.Println("Policy CRN Data =============>", policy.CRN) - policyCRNData := strings.Split(policy.CRN, ":") - policyInstance := map[string]interface{}{ - "id": policyCRNData[9], - "crn": policy.CRN, - "created_by": policy.CreatedBy, - "creation_date": (*(policy.CreatedAt)).String(), - "updated_by": policy.UpdatedBy, - "last_update_date": (*(policy.UpdatedAt)).String(), - } - if policy.Rotation != nil { - policyInstance["interval_month"] = policy.Rotation.Interval - rotationMap = append(rotationMap, policyInstance) - } else if policy.DualAuth != nil { - policyInstance["enabled"] = *(policy.DualAuth.Enabled) - dualAuthMap = append(dualAuthMap, policyInstance) - } - } - if policy == "rotation" { - return rotationMap - } else if policy == "dual_auth_delete" { - return dualAuthMap - } - return nil -} - -// IgnoreSystemLabels returns non-IBM tag keys. -func IgnoreSystemLabels(labels map[string]string) map[string]string { - result := make(map[string]string) - - for k, v := range labels { - if strings.HasPrefix(k, SystemIBMLabelPrefix) || - strings.HasPrefix(k, KubernetesLabelPrefix) || - strings.HasPrefix(k, K8sLabelPrefix) && - !strings.Contains(k, "node-local-dns-enabled") { - continue - } - - result[k] = v - } - - return result -} - -// expandCosConfig .. -func expandCosConfig(cos []interface{}) *kubernetesserviceapiv1.COSBucket { - if len(cos) == 0 || cos[0] == nil { - return &kubernetesserviceapiv1.COSBucket{} - } - in := cos[0].(map[string]interface{}) - obj := &kubernetesserviceapiv1.COSBucket{ - Bucket: ptrToString(in["bucket"].(string)), - Endpoint: ptrToString(in["endpoint"].(string)), - Region: ptrToString(in["region"].(string)), - } - return obj -} - -// expandCosCredentials .. -func expandCosCredentials(cos []interface{}) *kubernetesserviceapiv1.COSAuthorization { - if len(cos) == 0 || cos[0] == nil { - return &kubernetesserviceapiv1.COSAuthorization{} - } - in := cos[0].(map[string]interface{}) - obj := &kubernetesserviceapiv1.COSAuthorization{ - AccessKeyID: ptrToString(in["access_key-id"].(string)), - SecretAccessKey: ptrToString(in["secret_access_key"].(string)), - } - return obj -} - -// flattenHostLabels .. -func flattenHostLabels(hostLabels []interface{}) map[string]string { - labels := make(map[string]string) - for _, v := range hostLabels { - parts := strings.Split(v.(string), ":") - if parts != nil { - labels[parts[0]] = parts[1] - } - } - - return labels -} - -func flatterSatelliteZones(zones *schema.Set) []string { - zoneList := make([]string, zones.Len()) - for i, v := range zones.List() { - zoneList[i] = fmt.Sprint(v) - } - - return zoneList -} - -// error object -type ServiceErrorResponse struct { - Message string - StatusCode int - Result interface{} -} - -func beautifyError(err error, response *core.DetailedResponse) *ServiceErrorResponse { - var ( - statusCode int - result interface{} - ) - if response != nil { - statusCode = response.StatusCode - result = response.Result - } - return &ServiceErrorResponse{ - Message: err.Error(), - StatusCode: statusCode, - Result: result, - } -} - -func (response *ServiceErrorResponse) String() string { - output, err := json.MarshalIndent(response, "", " ") - if err == nil { - return fmt.Sprintf("%+v\n", string(output)) - } - return fmt.Sprintf("Error : %#v", response) -} - -// IAM Policy Management -func getResourceAttribute(name string, r iampolicymanagementv1.PolicyResource) *string { - for _, a := range r.Attributes { - if *a.Name == name { - return a.Value - } - } - return core.StringPtr("") -} - -func getSubjectAttribute(name string, s iampolicymanagementv1.PolicySubject) *string { - for _, a := range s.Attributes { - if *a.Name == name { - return a.Value - } - } - return core.StringPtr("") -} - -func setResourceAttribute(name *string, value *string, r []iampolicymanagementv1.ResourceAttribute) []iampolicymanagementv1.ResourceAttribute { - for _, a := range r { - if *a.Name == *name { - a.Value = value - return r - } - } - r = append(r, iampolicymanagementv1.ResourceAttribute{ - Name: name, - Value: value, - Operator: core.StringPtr("stringEquals"), - }) - return r -} - -func getRolesFromRoleNames(roleNames []string, roles []iampolicymanagementv1.PolicyRole) ([]iampolicymanagementv1.PolicyRole, error) { - - filteredRoles := []iampolicymanagementv1.PolicyRole{} - for _, roleName := range roleNames { - role, err := findRoleByName(roles, roleName) - if err != nil { - return []iampolicymanagementv1.PolicyRole{}, err - } - role.DisplayName = nil - filteredRoles = append(filteredRoles, role) - } - return filteredRoles, nil -} - -func mapRoleListToPolicyRoles(roleList iampolicymanagementv1.RoleList) []iampolicymanagementv1.PolicyRole { - var policyRoles []iampolicymanagementv1.PolicyRole - for _, customRole := range roleList.CustomRoles { - newPolicyRole := iampolicymanagementv1.PolicyRole{ - DisplayName: customRole.DisplayName, - RoleID: customRole.CRN, - } - policyRoles = append(policyRoles, newPolicyRole) - } - for _, serviceRole := range roleList.ServiceRoles { - newPolicyRole := iampolicymanagementv1.PolicyRole{ - DisplayName: serviceRole.DisplayName, - RoleID: serviceRole.CRN, - } - policyRoles = append(policyRoles, newPolicyRole) - } - for _, systemRole := range roleList.SystemRoles { - newPolicyRole := iampolicymanagementv1.PolicyRole{ - DisplayName: systemRole.DisplayName, - RoleID: systemRole.CRN, - } - policyRoles = append(policyRoles, newPolicyRole) - } - return policyRoles -} - -func generatePolicyOptions(d *schema.ResourceData, meta interface{}) (iampolicymanagementv1.CreatePolicyOptions, error) { - - var serviceName string - var resourceType string - resourceAttributes := []iampolicymanagementv1.ResourceAttribute{} - - if res, ok := d.GetOk("resources"); ok { - resources := res.([]interface{}) - for _, resource := range resources { - r, _ := resource.(map[string]interface{}) - - if r, ok := r["service"]; ok && r != nil { - serviceName = r.(string) - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceName"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["resource_instance_id"]; ok { - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceInstance"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["region"]; ok { - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("region"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["resource_type"]; ok { - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceType"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["resource"]; ok { - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resource"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["resource_group_id"]; ok { - if r.(string) != "" { - resourceAttr := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceGroupId"), - Value: core.StringPtr(r.(string)), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, resourceAttr) - } - } - - if r, ok := r["attributes"]; ok { - for k, v := range r.(map[string]interface{}) { - resourceAttributes = setResourceAttribute(core.StringPtr(k), core.StringPtr(v.(string)), resourceAttributes) - } - } - } - } - if r, ok := d.GetOk("resource_attributes"); ok { - for _, attribute := range r.(*schema.Set).List() { - a := attribute.(map[string]interface{}) - name := a["name"].(string) - value := a["value"].(string) - operator := a["operator"].(string) - at := iampolicymanagementv1.ResourceAttribute{ - Name: &name, - Value: &value, - Operator: &operator, - } - resourceAttributes = append(resourceAttributes, at) - } - } - - var serviceTypeResourceAttribute iampolicymanagementv1.ResourceAttribute - - if d.Get("account_management").(bool) { - serviceTypeResourceAttribute = iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceType"), - Value: core.StringPtr("platform_service"), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, serviceTypeResourceAttribute) - } - - if len(resourceAttributes) == 0 { - serviceTypeResourceAttribute = iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceType"), - Value: core.StringPtr("service"), - Operator: core.StringPtr("stringEquals"), - } - resourceAttributes = append(resourceAttributes, serviceTypeResourceAttribute) - } - - policyResources := iampolicymanagementv1.PolicyResource{ - Attributes: resourceAttributes, - } - - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return iampolicymanagementv1.CreatePolicyOptions{}, err - } - - iamPolicyManagementClient, err := meta.(ClientSession).IAMPolicyManagementV1API() - - if err != nil { - return iampolicymanagementv1.CreatePolicyOptions{}, err - } - - serviceToQuery := serviceName - - if serviceName == "" && // no specific service specified - !d.Get("account_management").(bool) && // not all account management services - resourceType != "resource-group" { // not to a resource group - serviceToQuery = "alliamserviceroles" - } - - listRoleOptions := &iampolicymanagementv1.ListRolesOptions{ - AccountID: &userDetails.userAccount, - ServiceName: &serviceToQuery, - } - - roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) - if err != nil { - return iampolicymanagementv1.CreatePolicyOptions{}, err - } - - roles := mapRoleListToPolicyRoles(*roleList) - policyRoles, err := getRolesFromRoleNames(expandStringList(d.Get("roles").([]interface{})), roles) - if err != nil { - return iampolicymanagementv1.CreatePolicyOptions{}, err - } - - return iampolicymanagementv1.CreatePolicyOptions{Roles: policyRoles, Resources: []iampolicymanagementv1.PolicyResource{policyResources}}, nil -} - -func getIBMUniqueId(accountID, userEmail string, meta interface{}) (string, error) { - userManagement, err := meta.(ClientSession).UserManagementAPI() - if err != nil { - return "", err - } - client := userManagement.UserInvite() - res, err := client.ListUsers(accountID) - if err != nil { - return "", err - } - for _, userInfo := range res { - //handling case-sensitivity in userEmail - if strings.ToLower(userInfo.Email) == strings.ToLower(userEmail) { - return userInfo.IamID, nil - } - } - return "", fmt.Errorf("User %s is not found under account %s", userEmail, accountID) -} - -func immutableResourceCustomizeDiff(resourceList []string, diff *schema.ResourceDiff) error { - - for _, rName := range resourceList { - if diff.Id() != "" && diff.HasChange(rName) && rName != sateLocZone { - return fmt.Errorf("'%s' attribute is immutable and can't be changed", rName) - } - if diff.Id() != "" && diff.HasChange(rName) && rName == sateLocZone { - o, n := diff.GetChange(rName) - old := o.(string) - new := n.(string) - if len(old) > 0 && old != new { - if !(rName == sateLocZone && strings.Contains(old, new)) { - return fmt.Errorf("'%s' attribute is immutable and can't be changed from %s to %s", rName, old, new) - } - } - } - } - return nil -} - -func flattenSatelliteWorkerPoolZones(zones *schema.Set) []kubernetesserviceapiv1.SatelliteCreateWorkerPoolZone { - zoneList := make([]kubernetesserviceapiv1.SatelliteCreateWorkerPoolZone, zones.Len()) - for i, v := range zones.List() { - data := v.(map[string]interface{}) - if v, ok := data["id"]; ok && v.(string) != "" { - zoneList[i].ID = sl.String(v.(string)) - } - } - - return zoneList -} - -func flattenSatelliteWorkerPools(list []kubernetesserviceapiv1.GetWorkerPoolResponse) []map[string]interface{} { - workerPools := make([]map[string]interface{}, len(list)) - for i, workerPool := range list { - l := map[string]interface{}{ - "id": *workerPool.ID, - "name": *workerPool.PoolName, - "isolation": *workerPool.Isolation, - "flavour": *workerPool.Flavor, - "size_per_zone": *workerPool.WorkerCount, - "state": *workerPool.Lifecycle.ActualState, - "default_worker_pool_labels": workerPool.Labels, - "host_labels": workerPool.HostLabels, - } - zones := workerPool.Zones - zonesConfig := make([]map[string]interface{}, len(zones)) - for j, zone := range zones { - z := map[string]interface{}{ - "zone": *zone.ID, - "worker_count": int(*zone.WorkerCount), - } - zonesConfig[j] = z - } - l["zones"] = zonesConfig - workerPools[i] = l - } - - return workerPools -} - -func flattenSatelliteHosts(hostList []kubernetesserviceapiv1.MultishiftQueueNode) []map[string]interface{} { - hosts := make([]map[string]interface{}, len(hostList)) - for i, host := range hostList { - l := map[string]interface{}{ - "host_id": *host.ID, - "host_name": *host.Name, - "status": *host.Health.Status, - "ip_address": *host.Assignment.IpAddress, - "cluster_name": *host.Assignment.ClusterName, - "zone": *host.Assignment.Zone, - "host_labels": *&host.Labels, - } - hosts[i] = l - } - - return hosts -} - -func flattenWorkerPoolHostLabels(hostLabels map[string]string) *schema.Set { - mapped := make([]string, len(hostLabels)) - idx := 0 - for k, v := range hostLabels { - mapped[idx] = fmt.Sprintf("%s:%v", k, v) - idx++ - } - - return newStringSet(schema.HashString, mapped) -} - -// KMS Private Endpoint -func updatePrivateURL(kpURL string) (string, error) { - var kmsEndpointURL string - if !strings.Contains(kpURL, "private") { - kmsEndpURL := strings.SplitAfter(kpURL, "https://") - if len(kmsEndpURL) == 2 { - kmsEndpointURL = kmsEndpURL[0] + "private." + kmsEndpURL[1] + "/api/v2/" - - } else { - return "", fmt.Errorf("Error in Kms EndPoint URL ") - } - } - return kmsEndpointURL, nil -} diff --git a/ibm/test-fixtures/import_profile.csv b/ibm/test-fixtures/import_profile.csv new file mode 100644 index 000000000..5e129a5be --- /dev/null +++ b/ibm/test-fixtures/import_profile.csv @@ -0,0 +1,6 @@ +"profilename","sample_tf_test_profile" +"profilemnemonic", +"profiledescription","profile Import-24Jan2022" +"##METAINFO ENDS##" +"ExternalControlId","Description","Parent","ControlId","Tags" +"1","GoalProfile11","","1000103,1000101,1000102,1000104,1000105,1000106","CIS,IAM,IAM,AWS" diff --git a/ibm/utils.go b/ibm/utils.go deleted file mode 100644 index 11105ae6a..000000000 --- a/ibm/utils.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package ibm - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -// Used for retry logic on resource timeout. -func isResourceTimeoutError(err error) bool { - timeoutErr, ok := err.(*resource.TimeoutError) - return ok && timeoutErr.LastError == nil -} -func GetPrivateServiceURLForRegion(region string) (string, error) { - var endpoints = map[string]string{ - "us-south": "https://private.us.icr.io", // us-south - "uk-south": "https://private.uk.icr.io", // uk-south - "eu-gb": "https://private.uk.icr.io", // eu-gb - "eu-central": "https://private.de.icr.io", // eu-central - "eu-de": "https://private.de.icr.io", // eu-de - "ap-north": "https://private.jp.icr.io", // ap-north - "jp-tok": "https://private.jp.icr.io", // jp-tok - "ap-south": "https://private.au.icr.io", // ap-south - "au-syd": "https://private.au.icr.io", // au-syd - "global": "https://private.icr.io", // global - "jp-osa": "https://private.jp2.icr.io", // jp-osa - } - - if url, ok := endpoints[region]; ok { - return url, nil - } - return "", fmt.Errorf("service URL for region '%s' not found", region) -} diff --git a/ibm/validators.go b/ibm/validate/validators.go similarity index 86% rename from ibm/validators.go rename to ibm/validate/validators.go index af0c5d97a..63cb4b923 100644 --- a/ibm/validators.go +++ b/ibm/validate/validators.go @@ -1,7 +1,7 @@ // Copyright IBM Corp. 2017, 2021 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 -package ibm +package validate import ( "encoding/json" @@ -12,12 +12,14 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" homedir "github.com/mitchellh/go-homedir" "github.com/IBM-Cloud/bluemix-go/helpers" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" ) var ( @@ -28,7 +30,7 @@ func init() { validHRef = regexp.MustCompile(`^http(s)?:\/\/([^\/?#]*)([^?#]*)(\?([^#]*))?(#(.*))?$`) } -func validateSecondaryIPCount(v interface{}, k string) (ws []string, errors []error) { +func ValidateSecondaryIPCount(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if value != 4 && value != 8 { errors = append(errors, fmt.Errorf( @@ -46,7 +48,7 @@ func validateServiceTags(v interface{}, k string) (ws []string, errors []error) return } -func validateAllowedStringValue(validValues []string) schema.SchemaValidateFunc { +func ValidateAllowedStringValues(validValues []string) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { input := v.(string) existed := false @@ -66,6 +68,17 @@ func validateAllowedStringValue(validValues []string) schema.SchemaValidateFunc } } +func ValidBucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + _, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value)) + if err != nil { + errors = append(errors, fmt.Errorf( + "%q cannot be parsed as RFC3339 Timestamp Format", value)) + } + + return +} + func validateRegexpLen(min, max int, regex string) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) @@ -87,7 +100,7 @@ func validateRegexpLen(min, max int, regex string) schema.SchemaValidateFunc { } } -func validateAllowedIntValue(is []int) schema.SchemaValidateFunc { +func ValidateAllowedIntValues(is []int) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(int) existed := false @@ -107,7 +120,7 @@ func validateAllowedIntValue(is []int) schema.SchemaValidateFunc { } } -func validateAllowedEnterpriseNameValue() schema.SchemaValidateFunc { +func ValidateAllowedEnterpriseNameValue() schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) @@ -119,7 +132,7 @@ func validateAllowedEnterpriseNameValue() schema.SchemaValidateFunc { } } -func validateRoutePath(v interface{}, k string) (ws []string, errors []error) { +func ValidateRoutePath(v interface{}, k string) (ws []string, errors []error) { value := v.(string) //Somehow API allows this if value == "" { @@ -143,14 +156,14 @@ func validateRoutePath(v interface{}, k string) (ws []string, errors []error) { return } -func validateRoutePort(v interface{}, k string) (ws []string, errors []error) { - return validatePortRange(1024, 65535)(v, k) +func ValidateRoutePort(v interface{}, k string) (ws []string, errors []error) { + return ValidatePortRange(1024, 65535)(v, k) } func validateAppPort(v interface{}, k string) (ws []string, errors []error) { - return validatePortRange(1024, 65535)(v, k) + return ValidatePortRange(1024, 65535)(v, k) } -func validateLBListenerPolicyPriority(v interface{}, k string) (ws []string, errors []error) { +func ValidateLBListenerPolicyPriority(v interface{}, k string) (ws []string, errors []error) { interval := v.(int) if interval < 1 || interval > 10 { errors = append(errors, fmt.Errorf( @@ -160,7 +173,7 @@ func validateLBListenerPolicyPriority(v interface{}, k string) (ws []string, err return } -func validateStringLength(v interface{}, k string) (ws []string, errors []error) { +func ValidateStringLength(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if (len(value) < 1) || (len(value) > 128) { @@ -170,7 +183,7 @@ func validateStringLength(v interface{}, k string) (ws []string, errors []error) return } -func validatePortRange(start, end int) func(v interface{}, k string) (ws []string, errors []error) { +func ValidatePortRange(start, end int) func(v interface{}, k string) (ws []string, errors []error) { f := func(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if (value < start) || (value > end) { @@ -182,7 +195,7 @@ func validatePortRange(start, end int) func(v interface{}, k string) (ws []strin return f } -func validateDomainName(v interface{}, k string) (ws []string, errors []error) { +func ValidateDomainName(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if !(strings.Contains(value, ".")) { @@ -203,7 +216,7 @@ func validateAppInstance(v interface{}, k string) (ws []string, errors []error) } -func validateWorkerNum(v interface{}, k string) (ws []string, errors []error) { +func ValidateWorkerNum(v interface{}, k string) (ws []string, errors []error) { workerNum := v.(int) if workerNum <= 0 { errors = append(errors, fmt.Errorf( @@ -229,7 +242,7 @@ func validateAppZipPath(v interface{}, k string) (ws []string, errors []error) { } -func validateNotes(v interface{}, k string) (ws []string, errors []error) { +func ValidateNotes(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if len(value) > 1000 { errors = append(errors, fmt.Errorf( @@ -238,7 +251,7 @@ func validateNotes(v interface{}, k string) (ws []string, errors []error) { return } -func validatePublicBandwidth(v interface{}, k string) (ws []string, errors []error) { +func ValidatePublicBandwidth(v interface{}, k string) (ws []string, errors []error) { bandwidth := v.(int) if bandwidth < 0 { errors = append(errors, fmt.Errorf( @@ -257,7 +270,7 @@ func validatePublicBandwidth(v interface{}, k string) (ws []string, errors []err } -func validateMaxConn(v interface{}, k string) (ws []string, errors []error) { +func ValidateMaxConn(v interface{}, k string) (ws []string, errors []error) { maxConn := v.(int) if maxConn < 1 || maxConn > 64000 { errors = append(errors, fmt.Errorf( @@ -268,7 +281,7 @@ func validateMaxConn(v interface{}, k string) (ws []string, errors []error) { return } -func validateKeyLifeTime(v interface{}, k string) (ws []string, errors []error) { +func ValidateKeyLifeTime(v interface{}, k string) (ws []string, errors []error) { secs := v.(int) if secs < 1800 || secs > 86400 { errors = append(errors, fmt.Errorf( @@ -279,7 +292,7 @@ func validateKeyLifeTime(v interface{}, k string) (ws []string, errors []error) return } -func validateWeight(v interface{}, k string) (ws []string, errors []error) { +func ValidateWeight(v interface{}, k string) (ws []string, errors []error) { weight := v.(int) if weight < 0 || weight > 100 { errors = append(errors, fmt.Errorf( @@ -289,7 +302,7 @@ func validateWeight(v interface{}, k string) (ws []string, errors []error) { return } -func validateSizePerZone(v interface{}, k string) (ws []string, errors []error) { +func ValidateSizePerZone(v interface{}, k string) (ws []string, errors []error) { sizePerZone := v.(int) if sizePerZone <= 0 { errors = append(errors, fmt.Errorf( @@ -299,7 +312,7 @@ func validateSizePerZone(v interface{}, k string) (ws []string, errors []error) return } -func validateInterval(v interface{}, k string) (ws []string, errors []error) { +func ValidateInterval(v interface{}, k string) (ws []string, errors []error) { interval := v.(int) if interval < 2 || interval > 60 { errors = append(errors, fmt.Errorf( @@ -309,7 +322,7 @@ func validateInterval(v interface{}, k string) (ws []string, errors []error) { return } -func validateMaxRetries(v interface{}, k string) (ws []string, errors []error) { +func ValidateMaxRetries(v interface{}, k string) (ws []string, errors []error) { maxRetries := v.(int) if maxRetries < 1 || maxRetries > 10 { errors = append(errors, fmt.Errorf( @@ -319,7 +332,7 @@ func validateMaxRetries(v interface{}, k string) (ws []string, errors []error) { return } -func validateTimeout(v interface{}, k string) (ws []string, errors []error) { +func ValidateTimeout(v interface{}, k string) (ws []string, errors []error) { timeout := v.(int) if timeout < 1 || timeout > 59 { errors = append(errors, fmt.Errorf( @@ -329,7 +342,7 @@ func validateTimeout(v interface{}, k string) (ws []string, errors []error) { return } -func validateURLPath(v interface{}, k string) (ws []string, errors []error) { +func ValidateURLPath(v interface{}, k string) (ws []string, errors []error) { urlPath := v.(string) if len(urlPath) > 250 || !strings.HasPrefix(urlPath, "/") { errors = append(errors, fmt.Errorf( @@ -339,7 +352,7 @@ func validateURLPath(v interface{}, k string) (ws []string, errors []error) { return } -func validateSecurityRuleDirection(v interface{}, k string) (ws []string, errors []error) { +func ValidateSecurityRuleDirection(v interface{}, k string) (ws []string, errors []error) { validDirections := map[string]bool{ "ingress": true, "egress": true, @@ -359,7 +372,7 @@ func validateSecurityRuleDirection(v interface{}, k string) (ws []string, errors return } -func validateSecurityRuleEtherType(v interface{}, k string) (ws []string, errors []error) { +func ValidateSecurityRuleEtherType(v interface{}, k string) (ws []string, errors []error) { validEtherTypes := map[string]bool{ "IPv4": true, "IPv6": true, @@ -379,8 +392,8 @@ func validateSecurityRuleEtherType(v interface{}, k string) (ws []string, errors return } -//validateIP... -func validateIP(v interface{}, k string) (ws []string, errors []error) { +// ValidateIP... +func ValidateIP(v interface{}, k string) (ws []string, errors []error) { address := v.(string) if net.ParseIP(address) == nil { errors = append(errors, fmt.Errorf( @@ -390,8 +403,8 @@ func validateIP(v interface{}, k string) (ws []string, errors []error) { return } -//validateCIDR... -func validateCIDR(v interface{}, k string) (ws []string, errors []error) { +// ValidateCIDR... +func ValidateCIDR(v interface{}, k string) (ws []string, errors []error) { address := v.(string) _, _, err := net.ParseCIDR(address) if err != nil { @@ -402,7 +415,7 @@ func validateCIDR(v interface{}, k string) (ws []string, errors []error) { return } -//validateCIDRAddress... +// validateCIDRAddress... func validateCIDRAddress() schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { address := v.(string) @@ -416,7 +429,7 @@ func validateCIDRAddress() schema.SchemaValidateFunc { } } -//validateOverlappingAddress... +// validateOverlappingAddress... func validateOverlappingAddress() schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { nonOverlappingCIDR := map[string]bool{ @@ -438,10 +451,10 @@ func validateOverlappingAddress() schema.SchemaValidateFunc { } } -//validateRemoteIP... -func validateRemoteIP(v interface{}, k string) (ws []string, errors []error) { - _, err1 := validateCIDR(v, k) - _, err2 := validateIP(v, k) +// ValidateRemoteIP... +func ValidateRemoteIP(v interface{}, k string) (ws []string, errors []error) { + _, err1 := ValidateCIDR(v, k) + _, err2 := ValidateIP(v, k) if len(err1) != 0 && len(err2) != 0 { errors = append(errors, fmt.Errorf( @@ -451,11 +464,11 @@ func validateRemoteIP(v interface{}, k string) (ws []string, errors []error) { return } -//validateIPorCIDR... +// validateIPorCIDR... func validateIPorCIDR() schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { - _, err1 := validateCIDR(v, k) - _, err2 := validateIP(v, k) + _, err1 := ValidateCIDR(v, k) + _, err2 := ValidateIP(v, k) if len(err1) != 0 && len(err2) != 0 { errors = append(errors, fmt.Errorf( @@ -466,7 +479,7 @@ func validateIPorCIDR() schema.SchemaValidateFunc { } } -func validateSecurityRuleProtocol(v interface{}, k string) (ws []string, errors []error) { +func ValidateSecurityRuleProtocol(v interface{}, k string) (ws []string, errors []error) { validProtocols := map[string]bool{ "icmp": true, "tcp": true, @@ -487,17 +500,8 @@ func validateSecurityRuleProtocol(v interface{}, k string) (ws []string, errors return } -func validateNamespace(ns string) error { - os := strings.Split(ns, "_") - if len(os) < 2 || (len(os) == 2 && (len(os[0]) == 0 || len(os[1]) == 0)) { - return fmt.Errorf( - "Namespace is (%s), it must be of the form _, provider can't find the auth key if you use _ as well", ns) - } - return nil -} - //func validateJSONString(v interface{}, k string) (ws []string, errors []error) { -// if _, err := normalizeJSONString(v); err != nil { +// if _, err := flex.NormalizeJSONString(v); err != nil { // errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) // } // if err := validateKeyValue(v); err != nil { @@ -508,7 +512,7 @@ func validateNamespace(ns string) error { func validateJSONString() schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { - if _, err := normalizeJSONString(v); err != nil { + if _, err := flex.NormalizeJSONString(v); err != nil { errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) } if err := validateKeyValue(v); err != nil { @@ -518,7 +522,7 @@ func validateJSONString() schema.SchemaValidateFunc { } } -func validateRegexp(regex string) schema.SchemaValidateFunc { +func ValidateRegexps(regex string) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) @@ -652,7 +656,7 @@ func validateFunctionName(v interface{}, k string) (ws []string, errors []error) return } -func validateStorageType(v interface{}, k string) (ws []string, errors []error) { +func ValidateStorageType(v interface{}, k string) (ws []string, errors []error) { validEtherTypes := map[string]bool{ "Endurance": true, "Performance": true, @@ -697,7 +701,7 @@ func validateRole(v interface{}, k string) (ws []string, errors []error) { return } -func validateDayOfWeek(v interface{}, k string) (ws []string, errors []error) { +func ValidateDayOfWeek(v interface{}, k string) (ws []string, errors []error) { validDayTypes := map[string]bool{ "SUNDAY": true, "MONDAY": true, @@ -722,7 +726,7 @@ func validateDayOfWeek(v interface{}, k string) (ws []string, errors []error) { return } -func validateScheduleType(v interface{}, k string) (ws []string, errors []error) { +func ValidateScheduleType(v interface{}, k string) (ws []string, errors []error) { validSchdTypes := map[string]bool{ "HOURLY": true, "DAILY": true, @@ -743,7 +747,7 @@ func validateScheduleType(v interface{}, k string) (ws []string, errors []error) return } -func validateHour(start, end int) func(v interface{}, k string) (ws []string, errors []error) { +func ValidateHour(start, end int) func(v interface{}, k string) (ws []string, errors []error) { f := func(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if (value < start) || (value > end) { @@ -755,7 +759,7 @@ func validateHour(start, end int) func(v interface{}, k string) (ws []string, er return f } -func validateMinute(start, end int) func(v interface{}, k string) (ws []string, errors []error) { +func ValidateMinute(start, end int) func(v interface{}, k string) (ws []string, errors []error) { f := func(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if (value < start) || (value > end) { @@ -767,7 +771,7 @@ func validateMinute(start, end int) func(v interface{}, k string) (ws []string, return f } -func validateDatacenterOption(v []interface{}, allowedValues []string) error { +func ValidateDatacenterOption(v []interface{}, allowedValues []string) error { for _, option := range v { if option == nil { return fmt.Errorf("Provide a valid `datacenter_choice`") @@ -784,7 +788,7 @@ func validateDatacenterOption(v []interface{}, allowedValues []string) error { return nil } -func validateLBTimeout(v interface{}, k string) (ws []string, errors []error) { +func ValidateLBTimeout(v interface{}, k string) (ws []string, errors []error) { timeout := v.(int) if timeout <= 0 || timeout > 3600 { errors = append(errors, fmt.Errorf( @@ -840,7 +844,7 @@ func validateRecordName(t string, value string) error { return nil } -func validateVLANName(v interface{}, k string) (ws []string, errors []error) { +func ValidateVLANName(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if len(value) > 20 { errors = append(errors, fmt.Errorf( @@ -849,7 +853,7 @@ func validateVLANName(v interface{}, k string) (ws []string, errors []error) { return } -func validateAuthProtocol(v interface{}, k string) (ws []string, errors []error) { +func ValidateAuthProtocol(v interface{}, k string) (ws []string, errors []error) { authProtocol := v.(string) if authProtocol != "MD5" && authProtocol != "SHA1" && authProtocol != "SHA256" { errors = append(errors, fmt.Errorf( @@ -858,8 +862,8 @@ func validateAuthProtocol(v interface{}, k string) (ws []string, errors []error) return } -//ValidateIPVersion -func validateIPVersion(v interface{}, k string) (ws []string, errors []error) { +// ValidateIPVersion +func ValidateIPVersion(v interface{}, k string) (ws []string, errors []error) { validVersions := map[string]bool{ "ipv4": true, "ipv6": true, @@ -879,11 +883,11 @@ func validateIPVersion(v interface{}, k string) (ws []string, errors []error) { return } -func isSecurityGroupAddress(s string) bool { +func IsSecurityGroupAddress(s string) bool { return net.ParseIP(s) != nil } -func isSecurityGroupCIDR(s string) bool { +func IsSecurityGroupCIDR(s string) bool { _, _, err := net.ParseCIDR(s) return err == nil } @@ -917,7 +921,7 @@ func validateGeneration(v interface{}, k string) (ws []string, errors []error) { return } -func validateEncyptionProtocol(v interface{}, k string) (ws []string, errors []error) { +func ValidateEncyptionProtocol(v interface{}, k string) (ws []string, errors []error) { encyptionProtocol := v.(string) if encyptionProtocol != "DES" && encyptionProtocol != "3DES" && encyptionProtocol != "AES128" && encyptionProtocol != "AES192" && encyptionProtocol != "AES256" { errors = append(errors, fmt.Errorf( @@ -937,7 +941,7 @@ func validateDeadPeerDetectionInterval(v interface{}, k string) (ws []string, er return } -func validateDiffieHellmanGroup(v interface{}, k string) (ws []string, errors []error) { +func ValidateDiffieHellmanGroup(v interface{}, k string) (ws []string, errors []error) { diffieHellmanGroup := v.(int) if diffieHellmanGroup != 0 && diffieHellmanGroup != 1 && diffieHellmanGroup != 2 && diffieHellmanGroup != 5 { errors = append(errors, fmt.Errorf( @@ -946,7 +950,7 @@ func validateDiffieHellmanGroup(v interface{}, k string) (ws []string, errors [] return } -func validateAllowedRangeInt(start, end int) schema.SchemaValidateFunc { +func ValidateAllowedRangeInt(start, end int) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if value < start || value > end { @@ -969,7 +973,7 @@ func validateDeadPeerDetectionTimeout(v interface{}, k string) (ws []string, err return } -func validatekeylife(v interface{}, k string) (ws []string, errors []error) { +func Validatekeylife(v interface{}, k string) (ws []string, errors []error) { keylife := v.(int) if keylife < 120 || keylife > 172800 { errors = append(errors, fmt.Errorf( @@ -978,11 +982,11 @@ func validatekeylife(v interface{}, k string) (ws []string, errors []error) { return } -func validateLBListenerPort(v interface{}, k string) (ws []string, errors []error) { - return validatePortRange(1, 65535)(v, k) +func ValidateLBListenerPort(v interface{}, k string) (ws []string, errors []error) { + return ValidatePortRange(1, 65535)(v, k) } -func validateLBListenerConnectionLimit(v interface{}, k string) (ws []string, errors []error) { +func ValidateLBListenerConnectionLimit(v interface{}, k string) (ws []string, errors []error) { conns := v.(int) if conns < 1 || conns > 15000 { errors = append(errors, fmt.Errorf( @@ -993,14 +997,14 @@ func validateLBListenerConnectionLimit(v interface{}, k string) (ws []string, er return } -//ValidateISName -func validateISName(v interface{}, k string) (ws []string, errors []error) { +// ValidateISName +func ValidateISName(v interface{}, k string) (ws []string, errors []error) { name := v.(string) acceptedcharacters, _ := regexp.MatchString(`^[a-z][-a-z0-9]*$`, name) endwithalphanumeric, _ := regexp.MatchString(`.*[a-z0-9]$`, name) length := len(name) if acceptedcharacters == true { - if length <= 40 { + if length <= 63 { if endwithalphanumeric == true { if strings.Contains(name, "--") != true { return @@ -1014,7 +1018,7 @@ func validateISName(v interface{}, k string) (ws []string, errors []error) { } } else { errors = append(errors, fmt.Errorf( - "%q (%q) should not exceed 40 characters", k, v)) + "%q (%q) should not exceed 63 characters", k, v)) } } else { @@ -1045,9 +1049,11 @@ const ( ValidateJSONParam ValidateBindedPackageName ValidateOverlappingAddress + ValidateCloudData ) // MarshalText implements the encoding.TextMarshaler interface. +// // Without this function, when FunctionalIdentifier is marshaled, it prints 0,1,2.. instead // of printing IntBetween, IntAtLeast, IntAtMost.. in JSON Output func (f FunctionIdentifier) MarshalText() ([]byte, error) { @@ -1056,7 +1062,7 @@ func (f FunctionIdentifier) MarshalText() ([]byte, error) { // Use stringer tool to generate this later. func (i FunctionIdentifier) String() string { - return [...]string{"IntBetween", "IntAtLeast", "IntAtMost", "ValidateAllowedStringValue", "StringLenBetween", "ValidateIPorCIDR", "ValidateAllowedIntValue", "ValidateRegexpLen", "ValidateRegexp", "ValidateNoZeroValues", "ValidateJSONString", "ValidateJSONParam", "ValidateBindedPackageName", "ValidateOverlappingAddress"}[i] + return [...]string{"IntBetween", "IntAtLeast", "IntAtMost", "ValidateAllowedStringValue", "StringLenBetween", "ValidateIPorCIDR", "ValidateCIDRAddress", "ValidateAllowedIntValue", "ValidateRegexpLen", "ValidateRegexp", "ValidateNoZeroValues", "ValidateJSONString", "ValidateJSONParam", "ValidateBindedPackageName", "ValidateOverlappingAddress", "ValidateCloudData"}[i] } // ValueType -- Copied from Terraform for now. You can refer to Terraform ValueType directly. @@ -1114,7 +1120,7 @@ type ValidateSchema struct { Type ValueType // The actual validation function that needs to be invoked. - // Ex: IntBetween, validateAllowedIntValue, validateAllowedStringValue + // Ex: IntBetween, ValidateAllowedIntValues, ValidateAllowedStringValues ValidateFunctionIdentifier FunctionIdentifier MinValue string @@ -1128,10 +1134,12 @@ type ValidateSchema struct { // Is this nullable Nullable bool - Optional bool - Required bool - Default interface{} - ForceNew bool + Optional bool + Required bool + Default interface{} + ForceNew bool + CloudDataType string + CloudDataRange []string } type ResourceValidator struct { @@ -1153,7 +1161,13 @@ type ValidatorDict struct { // Each object in this array is a type of map, where key == ResourceName and value == array of ValidateSchema objects. Each of these // ValidateSchema corresponds to a parameter in the resourceProvider. -var validatorDict = Validator() +// var validatorDict = Validator() + +var validatorDict ValidatorDict + +func SetValidatorDict(v ValidatorDict) { + validatorDict = v +} // This is the main validation function. This function will be used in all the provider code. func InvokeValidator(resourceName, identifier string) schema.SchemaValidateFunc { @@ -1223,7 +1237,7 @@ func invokeValidatorInternal(schema ValidateSchema) schema.SchemaValidateFunc { return validation.IntAtMost(maxValue.(int)) case ValidateAllowedStringValue: allowedValues := schema.GetValue(AllowedValues) - return validateAllowedStringValue(allowedValues.([]string)) + return ValidateAllowedStringValues(allowedValues.([]string)) case StringLenBetween: return validation.StringLenBetween(schema.MinValueLength, schema.MaxValueLength) case ValidateIPorCIDR: @@ -1232,11 +1246,11 @@ func invokeValidatorInternal(schema ValidateSchema) schema.SchemaValidateFunc { return validateCIDRAddress() case ValidateAllowedIntValue: allowedValues := schema.GetValue(AllowedValues) - return validateAllowedIntValue(allowedValues.([]int)) + return ValidateAllowedIntValues(allowedValues.([]int)) case ValidateRegexpLen: return validateRegexpLen(schema.MinValueLength, schema.MaxValueLength, schema.Regexp) case ValidateRegexp: - return validateRegexp(schema.Regexp) + return ValidateRegexps(schema.Regexp) case ValidateNoZeroValues: return validateNoZeroValues() case ValidateJSONString: @@ -1245,6 +1259,8 @@ func invokeValidatorInternal(schema ValidateSchema) schema.SchemaValidateFunc { return validateBindedPackageName() case ValidateOverlappingAddress: return validateOverlappingAddress() + case ValidateCloudData: + return nil default: return nil diff --git a/main.go b/main.go index 380b5cf1a..a3769d67d 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "log" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/provider" "github.com/IBM-Cloud/terraform-provider-ibm/version" "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" ) @@ -11,6 +11,6 @@ import ( func main() { log.Println("IBM Cloud Provider version", version.Version, version.VersionPrerelease, version.GitCommit) plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: ibm.Provider, + ProviderFunc: provider.Provider, }) } diff --git a/metadata/provider_metadata.json b/metadata/provider_metadata.json new file mode 100644 index 000000000..75ce67d89 --- /dev/null +++ b/metadata/provider_metadata.json @@ -0,0 +1,105961 @@ +{ + "Datasources": { + "ibm_account": [ + { + "name": "org_guid", + "type": "TypeString", + "description": "The guid of the org", + "required": true + }, + { + "name": "account_users", + "type": "TypeList", + "computed": true, + "elem": { + "email": { + "name": "email", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "role": { + "name": "role", + "type": "TypeString", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_api_gateway": [ + { + "name": "service_instance_crn", + "type": "TypeString", + "description": "Api Gateway Service Instance Crn", + "immutable": true, + "required": true + }, + { + "name": "endpoints", + "type": "TypeList", + "description": "List of all endpoints of an instance", + "computed": true, + "elem": { + "alias_url": { + "name": "alias_url", + "type": "TypeString", + "description": "Alias Url for an endpoint", + "computed": true + }, + "base_path": { + "name": "base_path", + "type": "TypeString", + "description": "Base path of an endpoint", + "computed": true + }, + "endpoint_id": { + "name": "endpoint_id", + "type": "TypeString", + "description": "Endpoint ID", + "computed": true + }, + "managed": { + "name": "managed", + "type": "TypeBool", + "description": "Managed indicates if endpoint is online or offline.", + "computed": true + }, + "managed_url": { + "name": "managed_url", + "type": "TypeString", + "description": "Managed url for an endpoint", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Endpoint name", + "computed": true + }, + "open_api_doc": { + "name": "open_api_doc", + "type": "TypeString", + "description": "API document that represents endpoint", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Invokable routes for an endpoint", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "shared": { + "name": "shared", + "type": "TypeBool", + "description": "The Shared status of an endpoint", + "computed": true + }, + "subscriptions": { + "name": "subscriptions", + "type": "TypeList", + "description": "List of all subscription of an endpoint", + "computed": true, + "elem": { + "client_id": { + "name": "client_id", + "type": "TypeString", + "description": "Subscription Id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subscription name", + "computed": true + }, + "secret_provided": { + "name": "secret_provided", + "type": "TypeBool", + "description": "Indicates if client secret is provided to subscription or not", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Subscription type", + "computed": true + } + } + } + } + } + ], + "ibm_app": [ + { + "name": "buildpack", + "type": "TypeString", + "description": "Buildpack to build the app. 3 options: a) Blank means autodetection; b) A Git Url pointing to a buildpack; c) Name of an installed buildpack.", + "computed": true + }, + { + "name": "environment_json", + "type": "TypeMap", + "description": "Key/value pairs of all the environment variables to run in your app. Does not include any system or service variables.", + "computed": true + }, + { + "name": "health_check_type", + "type": "TypeString", + "description": "Type of health check to perform.", + "computed": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "Define space guid to which app belongs", + "required": true + }, + { + "name": "route_guid", + "type": "TypeSet", + "description": "Define the route guids which should be bound to the application.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "disk_quota", + "type": "TypeInt", + "description": "The maximum amount of disk available to an instance of an app. In megabytes.", + "computed": true + }, + { + "name": "service_instance_guid", + "type": "TypeSet", + "description": "Define the service instance guids that should be bound to this application.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "package_state", + "type": "TypeString", + "description": "The state of the application package whether staged, pending etc", + "computed": true + }, + { + "name": "health_check_http_endpoint", + "type": "TypeString", + "description": "Endpoint called to determine if the app is healthy.", + "computed": true + }, + { + "name": "instances", + "type": "TypeInt", + "description": "The number of instances", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory each instance should have. In megabytes.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the application", + "computed": true + }, + { + "name": "health_check_timeout", + "type": "TypeInt", + "description": "Timeout in seconds for health checking of an staged app when starting up.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name for the app", + "required": true + } + ], + "ibm_app_config_collection": [ + { + "name": "include", + "type": "TypeList", + "description": "Include feature, property details in the response.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the collection.", + "cloud_data_type": "tags", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the collection.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the collection data.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Collection URL.", + "computed": true + }, + { + "name": "properties_count", + "type": "TypeInt", + "description": "Number of properties associated with the collection.", + "computed": true + }, + { + "name": "features", + "type": "TypeList", + "description": "List of Features associated with the collection.", + "computed": true, + "elem": { + "feature_id": { + "name": "feature_id", + "type": "TypeString", + "description": "feature id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Feature.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "collection_id", + "type": "TypeString", + "description": "Collection Id of the collection.", + "required": true + }, + { + "name": "features_count", + "type": "TypeInt", + "description": "Number of features associated with the collection.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Collection name.", + "computed": true + }, + { + "name": "expand", + "type": "TypeBool", + "description": "If set to true, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Collection description.", + "computed": true + }, + { + "name": "properties", + "type": "TypeList", + "description": "List of properties associated with the collection.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Property.", + "computed": true + }, + "property_id": { + "name": "property_id", + "type": "TypeString", + "description": "property id.", + "computed": true + } + } + } + ], + "ibm_app_config_collections": [ + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve.", + "optional": true + }, + { + "name": "offset", + "type": "TypeInt", + "description": "Skipped number of records.", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Total number of records.", + "computed": true + }, + { + "name": "include", + "type": "TypeList", + "description": "Include feature, property details in the response.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "expand", + "type": "TypeBool", + "description": "If set to true, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "Array of Features.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the collection.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Collection description.", + "computed": true + }, + "features": { + "name": "features", + "type": "TypeList", + "description": "List of Features associated with the collection.", + "computed": true, + "elem": { + "feature_id": { + "name": "feature_id", + "type": "TypeString", + "description": "feature id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Feature.", + "computed": true + } + } + }, + "features_count": { + "name": "features_count", + "type": "TypeInt", + "description": "Number of features associated with the collection.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Collection URL.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Collection name.", + "computed": true + }, + "properties": { + "name": "properties", + "type": "TypeList", + "description": "List of properties associated with the collection.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Property.", + "computed": true + }, + "property_id": { + "name": "property_id", + "type": "TypeString", + "description": "property id.", + "computed": true + } + } + }, + "properties_count": { + "name": "properties_count", + "type": "TypeInt", + "description": "Number of properties associated with the collection.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the collection.", + "computed": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the collection data.", + "computed": true + } + } + } + ], + "ibm_app_config_environment": [ + { + "name": "description", + "type": "TypeString", + "description": "Environment description.", + "computed": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the environment.", + "cloud_data_type": "tags", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the environment.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the environment data.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "expand", + "type": "TypeBool", + "description": "If set to `true`, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "color_code", + "type": "TypeString", + "description": "Color code to distinguish the environment. The Hex code for the color. For example `#FF0000` for `red`.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Environment URL.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Environment name.", + "computed": true + } + ], + "ibm_app_config_environments": [ + { + "name": "expand", + "type": "TypeBool", + "description": "If set to `true`, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + "optional": true + }, + { + "name": "environments", + "type": "TypeList", + "description": "Array of environments.", + "computed": true, + "elem": { + "color_code": { + "name": "color_code", + "type": "TypeString", + "description": "Color code to distinguish the environment. The Hex code for the color. For example `#FF0000` for `red`.", + "computed": true + }, + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the environment.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Environment description.", + "computed": true + }, + "environment_id": { + "name": "environment_id", + "type": "TypeString", + "description": "Environment id.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Environment URL.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Environment name.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the environment.", + "computed": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the environment data.", + "computed": true + } + } + }, + { + "name": "next", + "type": "TypeList", + "description": "URL to navigate to the next list of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "URL to navigate to the previous list of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "URL to navigate to the last page of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "filter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Total number of records.", + "computed": true + }, + { + "name": "first", + "type": "TypeList", + "description": "URL to navigate to the first page of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + } + ], + "ibm_app_config_feature": [ + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Feature name.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "The state of the feature flag.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the feature flag data.", + "computed": true + }, + { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage of the feature.", + "computed": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified feature flag.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the collection.", + "computed": true + } + } + }, + { + "name": "feature_id", + "type": "TypeString", + "description": "Feature Id.", + "required": true + }, + { + "name": "disabled_value", + "type": "TypeString", + "description": "Value of the feature when it is disabled. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + }, + { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different feature flag values for different segments.", + "computed": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "computed": true + }, + "rollout_percentage": { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage for the segment rule.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "computed": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + } + } + }, + { + "name": "enabled_value", + "type": "TypeString", + "description": "Value of the feature when it is enabled. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the feature.", + "cloud_data_type": "tags", + "computed": true + }, + { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the feature flag.", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the feature flag.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "includes", + "type": "TypeString", + "description": "Include the associated collections in the response.", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Feature description.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the feature (BOOLEAN, STRING, NUMERIC).", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Feature flag URL.", + "computed": true + } + ], + "ibm_app_config_features": [ + { + "name": "expand", + "type": "TypeBool", + "description": "If set to `true`, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + "optional": true + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + "optional": true + }, + { + "name": "features", + "type": "TypeList", + "description": "Array of Features.", + "computed": true, + "elem": { + "collections": { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified feature flag.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the collection.", + "computed": true + } + } + }, + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the feature flag.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Feature description.", + "computed": true + }, + "disabled_value": { + "name": "disabled_value", + "type": "TypeString", + "description": "Value of the feature when it is disabled. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "The state of the feature flag.", + "computed": true + }, + "enabled_value": { + "name": "enabled_value", + "type": "TypeString", + "description": "Value of the feature when it is enabled. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + }, + "feature_id": { + "name": "feature_id", + "type": "TypeString", + "description": "Feature id.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Feature flag URL.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Feature name.", + "computed": true + }, + "rollout_percentage": { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage of the feature.", + "computed": true + }, + "segment_exists": { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the feature flag.", + "computed": true + }, + "segment_rules": { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different feature flag values for different segments.", + "computed": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "computed": true + }, + "rollout_percentage": { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage for the segment rule.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "computed": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the feature.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the feature (BOOLEAN, STRING, NUMERIC).", + "computed": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the feature flag data.", + "computed": true + } + } + }, + { + "name": "first", + "type": "TypeList", + "description": "URL to navigate to the first page of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort the feature details based on the specified attribute.", + "optional": true + }, + { + "name": "segments", + "type": "TypeList", + "description": "Filter features by a list of comma separated segments.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "URL to navigate to the previous list of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Number of records returned in the current response.", + "computed": true + }, + { + "name": "last", + "type": "TypeList", + "description": "URL to navigate to the last page of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "includes", + "type": "TypeList", + "description": "Include the associated collections or targeting rules details in the response.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "next", + "type": "TypeList", + "description": "URL to navigate to the next list of records.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "URL of the response.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Filter the resources to be returned based on the associated tags. Specify the parameter as a list of comma separated tags. Returns resources associated with any of the specified tags.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "Filter features by a list of comma separated collections.", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_app_config_properties": [ + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort the feature details based on the specified attribute.", + "optional": true + }, + { + "name": "expand", + "type": "TypeBool", + "description": "If set to `true`, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "include", + "type": "TypeList", + "description": "Include the associated collections or targeting rules details in the response.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + "optional": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Filter the resources to be returned based on the associated tags. Specify the parameter as a list of comma separated tags. Returns resources associated with any of the specified tags.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "Filter features by a list of comma separated collections.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "segments", + "type": "TypeList", + "description": "Filter features by a list of comma separated segments.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + "optional": true + }, + { + "name": "properties", + "type": "TypeList", + "description": "Array of properties.", + "computed": true, + "elem": { + "collections": { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified property.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the collection.", + "computed": true + } + } + }, + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the property.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Property description.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Property URL.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + "property_id": { + "name": "property_id", + "type": "TypeString", + "description": "Property id.", + "computed": true + }, + "segment_exists": { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the property.", + "computed": true + }, + "segment_rules": { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different property values for different segments.", + "computed": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "computed": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the property.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the Property (BOOLEAN, STRING, NUMERIC).", + "computed": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the property data.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Number of records returned in the current response.", + "computed": true + } + ], + "ibm_app_config_property": [ + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the property data.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Property URL.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Property description.", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the property.", + "computed": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the property.", + "cloud_data_type": "tags", + "computed": true + }, + { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the property.", + "computed": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified property.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the collection.", + "computed": true + } + } + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "include", + "type": "TypeString", + "description": "Include the associated collections in the response.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the Property (BOOLEAN, STRING, NUMERIC).", + "computed": true + }, + { + "name": "value", + "type": "TypeString", + "description": "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + }, + { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different property values for different segments.", + "computed": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "computed": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "property_id", + "type": "TypeString", + "description": "Property Id.", + "required": true + } + ], + "ibm_app_config_segment": [ + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the segment data.", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "List of rules that determine if the entity belongs to the segment during feature / property evaluation.", + "computed": true, + "elem": { + "attribute_name": { + "name": "attribute_name", + "type": "TypeString", + "description": "Attribute name.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator to be used for the evaluation if the entity belongs to the segment.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "List of values. Entities matching any of the given values will be considered to belong to the segment", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "properties", + "type": "TypeList", + "description": "List of Features associated with the segment.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Property.", + "computed": true + }, + "property_id": { + "name": "property_id", + "type": "TypeString", + "description": "property id.", + "computed": true + } + } + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the segment.", + "cloud_data_type": "tags", + "computed": true + }, + { + "name": "includes", + "type": "TypeList", + "description": "Include feature and property details in the response.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Segment name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Segment description.", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the segment.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Segment flag URL.", + "computed": true + }, + { + "name": "features", + "type": "TypeList", + "description": "List of Features associated with the segment.", + "computed": true, + "elem": { + "feature_id": { + "name": "feature_id", + "type": "TypeString", + "description": "feature id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Feature.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "segment_id", + "type": "TypeString", + "description": "Segment id.", + "required": true + } + ], + "ibm_app_config_segments": [ + { + "name": "tags", + "type": "TypeString", + "description": "Filter the resources to be returned based on the associated tags.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "expand", + "type": "TypeBool", + "description": "If set to `true`, returns expanded view of the resource details.", + "optional": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Total number of records.", + "optional": true + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + "optional": true + }, + { + "name": "segments", + "type": "TypeList", + "description": "Array of Segments.", + "computed": true, + "elem": { + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the segment.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Segment description.", + "optional": true + }, + "features": { + "name": "features", + "type": "TypeList", + "description": "List of Features associated with the segment.", + "computed": true, + "elem": { + "feature_id": { + "name": "feature_id", + "type": "TypeString", + "description": "feature id.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Feature.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Segment URL..", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Segment name.", + "computed": true + }, + "properties": { + "name": "properties", + "type": "TypeList", + "description": "List of properties associated with the segment.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Property.", + "computed": true + }, + "property_id": { + "name": "property_id", + "type": "TypeString", + "description": "property id.", + "computed": true + } + } + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "List of rules that determine if the entity belongs to the segment during feature / property evaluation.", + "computed": true, + "elem": { + "attribute_name": { + "name": "attribute_name", + "type": "TypeString", + "description": "Attribute name.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator to be used for the evaluation if the entity belongs to the segment.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "List of values. Entities matching any of the given values will be considered to belong to the segment", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "segment_id": { + "name": "segment_id", + "type": "TypeString", + "description": "Segment id.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the segments.", + "optional": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the segment data.", + "computed": true + } + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort the segment details based on the specified attribute.", + "optional": true + }, + { + "name": "include", + "type": "TypeString", + "description": "Segment details to include the associated rules in the response", + "optional": true + } + ], + "ibm_app_config_snapshot": [ + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "git_url", + "type": "TypeString", + "description": "Git url which will be used to connect to the github account.", + "computed": true + }, + { + "name": "git_branch", + "type": "TypeString", + "description": "Branch name to which you need to write or update the configuration.", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the git config.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Git config URL.", + "computed": true + }, + { + "name": "collection", + "type": "TypeList", + "description": "Collection object.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "collection_name": { + "name": "collection_name", + "type": "TypeString", + "description": "Collection name.", + "computed": true + } + } + }, + { + "name": "git_config_id", + "type": "TypeString", + "description": "Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + "required": true + }, + { + "name": "git_config_name", + "type": "TypeString", + "description": "Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + "computed": true + }, + { + "name": "git_file_path", + "type": "TypeString", + "description": "Git file path, this is a path where your configuration file will be written.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the git config data.", + "computed": true + }, + { + "name": "last_sync_time", + "type": "TypeString", + "description": "Latest time when the snapshot was synced to git.", + "computed": true + }, + { + "name": "environment", + "type": "TypeList", + "description": "Environment object", + "computed": true, + "elem": { + "color_code": { + "name": "color_code", + "type": "TypeString", + "description": "Environment color code.", + "computed": true + }, + "environment_id": { + "name": "environment_id", + "type": "TypeString", + "description": "Environment id.", + "computed": true + }, + "environment_name": { + "name": "environment_name", + "type": "TypeString", + "description": "Environment name.", + "computed": true + } + } + } + ], + "ibm_app_config_snapshots": [ + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "collection_id", + "type": "TypeString", + "description": "Filters the response based on the specified collection_id.", + "optional": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Filters the response based on the specified environment_id.", + "optional": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records.", + "optional": true + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records.", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Total number of records.", + "computed": true + }, + { + "name": "git_config", + "type": "TypeList", + "description": "Array of git_config.", + "computed": true, + "elem": { + "collection": { + "name": "collection", + "type": "TypeList", + "description": "Collection object.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "collection_name": { + "name": "collection_name", + "type": "TypeString", + "description": "Collection name.", + "computed": true + } + } + }, + "created_time": { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the git config.", + "computed": true + }, + "environment": { + "name": "environment", + "type": "TypeList", + "description": "Environment object", + "computed": true, + "elem": { + "color_code": { + "name": "color_code", + "type": "TypeString", + "description": "Environment color code.", + "computed": true + }, + "environment_id": { + "name": "environment_id", + "type": "TypeString", + "description": "Environment id.", + "computed": true + }, + "environment_name": { + "name": "environment_name", + "type": "TypeString", + "description": "Environment name.", + "computed": true + } + } + }, + "git_branch": { + "name": "git_branch", + "type": "TypeString", + "description": "Git url which will be used to connect to the github account", + "optional": true + }, + "git_config_id": { + "name": "git_config_id", + "type": "TypeString", + "description": "Git config id", + "optional": true + }, + "git_config_name": { + "name": "git_config_name", + "type": "TypeString", + "description": "Git config name.", + "optional": true + }, + "git_file_path": { + "name": "git_file_path", + "type": "TypeString", + "description": "Git file path, this is a path where your configuration file will be written.", + "optional": true + }, + "git_url": { + "name": "git_url", + "type": "TypeString", + "description": "Git url which will be used to connect to the github account", + "optional": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Git config URL.", + "computed": true + }, + "last_sync_time": { + "name": "last_sync_time", + "type": "TypeString", + "description": "Latest time when the snapshot was synced to git.", + "computed": true + }, + "updated_time": { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the git config data.", + "computed": true + } + } + } + ], + "ibm_app_domain_private": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the private domain", + "required": true + } + ], + "ibm_app_domain_shared": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the shared domain", + "required": true + } + ], + "ibm_app_route": [ + { + "name": "space_guid", + "type": "TypeString", + "description": "The guid of the space", + "required": true + }, + { + "name": "domain_guid", + "type": "TypeString", + "description": "The guid of the domain", + "required": true + }, + { + "name": "host", + "type": "TypeString", + "description": "The host of the route", + "optional": true + }, + { + "name": "path", + "type": "TypeString", + "description": "The path of the route", + "optional": true + }, + { + "name": "port", + "type": "TypeString", + "description": "The port of the route", + "optional": true + } + ], + "ibm_appid_action_url": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The type of the action: `on_user_verified` - the URL of your custom user verified page, `on_reset_password` - the URL of your custom reset password page", + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The action URL", + "computed": true + } + ], + "ibm_appid_apm": [ + { + "name": "enabled", + "type": "TypeBool", + "description": "`true` if APM is enabled", + "computed": true + }, + { + "name": "prevent_password_with_username", + "type": "TypeBool", + "computed": true + }, + { + "name": "password_reuse", + "type": "TypeList", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "max_password_reuse": { + "name": "max_password_reuse", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "password_expiration", + "type": "TypeList", + "computed": true, + "elem": { + "days_to_expire": { + "name": "days_to_expire", + "type": "TypeInt", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + } + } + }, + { + "name": "lockout_policy", + "type": "TypeList", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "lockout_time_sec": { + "name": "lockout_time_sec", + "type": "TypeInt", + "computed": true + }, + "num_of_attempts": { + "name": "num_of_attempts", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "min_password_change_interval", + "type": "TypeList", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "min_hours_to_change_password": { + "name": "min_hours_to_change_password", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + } + ], + "ibm_appid_application": [ + { + "name": "name", + "type": "TypeString", + "description": "The application name", + "computed": true + }, + { + "name": "secret", + "type": "TypeString", + "description": "The `secret` is a secret known only to the application and the authorization server", + "secure": true, + "computed": true + }, + { + "name": "oauth_server_url", + "type": "TypeString", + "description": "Base URL for common OAuth endpoints, like `/authorization`, `/token` and `/publickeys`", + "computed": true + }, + { + "name": "profiles_url", + "type": "TypeString", + "computed": true + }, + { + "name": "discovery_endpoint", + "type": "TypeString", + "description": "This URL returns OAuth Authorization Server Metadata", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of application. Allowed types are `regularwebapp` and `singlepageapp`.", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "required": true + } + ], + "ibm_appid_application_roles": [ + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "required": true + }, + { + "name": "roles", + "type": "TypeSet", + "description": "Defined roles for an application that is registered with an App ID instance", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Application role ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Application role name", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + } + ], + "ibm_appid_application_scopes": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "required": true + }, + { + "name": "scopes", + "type": "TypeList", + "description": "A `scope` is a runtime action in your application that you register with IBM Cloud App ID to create an access permission", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_applications": [ + { + "name": "applications", + "type": "TypeList", + "computed": true, + "elem": { + "client_id": { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "required": true + }, + "discovery_endpoint": { + "name": "discovery_endpoint", + "type": "TypeString", + "description": "This URL returns OAuth Authorization Server Metadata", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The application name", + "computed": true + }, + "oauth_server_url": { + "name": "oauth_server_url", + "type": "TypeString", + "description": "Base URL for common OAuth endpoints, like `/authorization`, `/token` and `/publickeys`", + "computed": true + }, + "profiles_url": { + "name": "profiles_url", + "type": "TypeString", + "computed": true + }, + "secret": { + "name": "secret", + "type": "TypeString", + "description": "The `secret` is a secret known only to the application and the authorization server", + "secure": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of application to be registered. Allowed types are `regularwebapp` and `singlepageapp`.", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + } + ], + "ibm_appid_audit_status": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "The auditing status of the tenant.", + "computed": true + } + ], + "ibm_appid_cloud_directory_template": [ + { + "name": "base64_encoded_html_body", + "type": "TypeString", + "description": "The HTML body of the email encoded in Base64", + "computed": true + }, + { + "name": "plain_text_body", + "type": "TypeString", + "description": "The text body of the email.", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "template_name", + "type": "TypeString", + "description": "The type of email template. This can be `USER_VERIFICATION`, `WELCOME`, `PASSWORD_CHANGED`, `RESET_PASSWORD` or `MFA_VERIFICATION`", + "required": true + }, + { + "name": "language", + "type": "TypeString", + "description": "Preferred language for resource. Format as described at RFC5646. According to the configured languages codes returned from the `GET /management/v4/{tenantId}/config/ui/languages API`.", + "default_value": "en", + "optional": true + }, + { + "name": "subject", + "type": "TypeString", + "description": "The subject of the email", + "computed": true + }, + { + "name": "html_body", + "type": "TypeString", + "description": "The HTML body of the email", + "computed": true + } + ], + "ibm_appid_cloud_directory_user": [ + { + "name": "subject", + "type": "TypeString", + "description": "The user's identifier ('subject' in identity token)", + "computed": true + }, + { + "name": "display_name", + "type": "TypeString", + "description": "Cloud Directory user display name", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Current user status: `PENDING` or `CONFIRMED`", + "computed": true + }, + { + "name": "meta", + "type": "TypeList", + "description": "Cloud Directory user metadata", + "computed": true, + "elem": { + "created": { + "name": "created", + "type": "TypeString", + "description": "User creation date", + "computed": true + }, + "last_modified": { + "name": "last_modified", + "type": "TypeString", + "description": "Last user modification date", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "active", + "type": "TypeBool", + "description": "Determines if the user account is active or not", + "computed": true + }, + { + "name": "locked_until", + "type": "TypeInt", + "description": "Integer (epoch time in milliseconds), determines till when the user account will be locked", + "computed": true + }, + { + "name": "user_id", + "type": "TypeString", + "description": "Cloud Directory user ID", + "required": true + }, + { + "name": "user_name", + "type": "TypeString", + "description": "Optional username", + "computed": true + }, + { + "name": "email", + "type": "TypeSet", + "description": "A set of user emails", + "computed": true, + "elem": { + "primary": { + "name": "primary", + "type": "TypeBool", + "description": "`true` if this is primary email", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "User email", + "computed": true + } + } + } + ], + "ibm_appid_idp_cloud_directory": [ + { + "name": "identity_confirm_access_mode", + "type": "TypeString", + "computed": true + }, + { + "name": "identity_confirm_methods", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "identity_field", + "type": "TypeString", + "computed": true + }, + { + "name": "is_active", + "type": "TypeBool", + "computed": true + }, + { + "name": "reset_password_notification_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "signup_enabled", + "type": "TypeBool", + "description": "Allow users to sign-up to your app", + "computed": true + }, + { + "name": "welcome_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "reset_password_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "self_service_enabled", + "type": "TypeBool", + "description": "Allow users to manage their account from your app", + "computed": true + } + ], + "ibm_appid_idp_custom": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "computed": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "This is the public key used to validate your signed JWT. It is required to be a PEM in the RS256 or greater format.", + "computed": true + } + ], + "ibm_appid_idp_facebook": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if Facebook IDP configuration is active", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Facebook IDP configuration", + "computed": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "description": "Facebook application id", + "computed": true + }, + "application_secret": { + "name": "application_secret", + "type": "TypeString", + "description": "Facebook application secret", + "secure": true, + "computed": true + } + } + }, + { + "name": "redirect_url", + "type": "TypeString", + "description": "Paste the URI into the Valid OAuth redirect URIs field in the Facebook Login section of the Facebook Developers Portal", + "computed": true + } + ], + "ibm_appid_idp_google": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if Google IDP configuration is active", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Google IDP configuration", + "computed": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "description": "Google application id", + "computed": true + }, + "application_secret": { + "name": "application_secret", + "type": "TypeString", + "description": "Google application secret", + "computed": true + } + } + }, + { + "name": "redirect_url", + "type": "TypeString", + "description": "Paste the URI into the Authorized redirect URIs field in the Google Developer Console", + "computed": true + } + ], + "ibm_appid_idp_saml": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "SAML IDP activation", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "SAML IDP configuration", + "computed": true, + "elem": { + "authn_context": { + "name": "authn_context", + "type": "TypeList", + "description": "SAML authNContext configuration", + "computed": true, + "elem": { + "class": { + "name": "class", + "type": "TypeList", + "description": "List of `authnContext` classes", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "comparison": { + "name": "comparison", + "type": "TypeString", + "computed": true + } + } + }, + "certificates": { + "name": "certificates", + "type": "TypeList", + "description": "List of certificates, primary and optional secondary", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "Provider name", + "computed": true + }, + "encrypt_response": { + "name": "encrypt_response", + "type": "TypeBool", + "description": "`true` if SAML responses should be encrypted", + "computed": true + }, + "entity_id": { + "name": "entity_id", + "type": "TypeString", + "description": "Unique name for an Identity Provider", + "computed": true + }, + "include_scoping": { + "name": "include_scoping", + "type": "TypeBool", + "description": "`true` if scopes are included", + "computed": true + }, + "sign_in_url": { + "name": "sign_in_url", + "type": "TypeString", + "description": "SAML SSO url", + "computed": true + }, + "sign_request": { + "name": "sign_request", + "type": "TypeBool", + "description": "`true` if SAML requests should be signed", + "computed": true + } + } + } + ], + "ibm_appid_idp_saml_metadata": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "metadata", + "type": "TypeString", + "description": "SAML Metadata", + "computed": true + } + ], + "ibm_appid_languages": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "languages", + "type": "TypeList", + "description": "The list of languages that can be used to customize email templates for Cloud Directory", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_mfa": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if MFA is active", + "computed": true + } + ], + "ibm_appid_mfa_channel": [ + { + "name": "active", + "type": "TypeString", + "description": "Possible values: `email`, `sms`", + "computed": true + }, + { + "name": "sms_config", + "type": "TypeList", + "description": "Configuration for `sms` channel", + "secure": true, + "computed": true, + "elem": { + "from": { + "name": "from", + "type": "TypeString", + "description": "Sender's phone number", + "computed": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "API Key", + "secure": true, + "computed": true + }, + "secret": { + "name": "secret", + "type": "TypeString", + "description": "API Secret", + "secure": true, + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + } + ], + "ibm_appid_password_regex": [ + { + "name": "error_message", + "type": "TypeString", + "description": "Custom error message", + "computed": true + }, + { + "name": "regex", + "type": "TypeString", + "description": "The escaped regex expression rule for acceptable password", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "base64_encoded_regex", + "type": "TypeString", + "description": "The regex expression rule for acceptable password encoded in base64", + "computed": true + } + ], + "ibm_appid_redirect_urls": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "urls", + "type": "TypeList", + "description": "A list of redirect URLs", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_role": [ + { + "name": "role_id", + "type": "TypeString", + "description": "Role ID", + "required": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Unique role name", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Optional role description", + "computed": true + }, + { + "name": "access", + "type": "TypeSet", + "description": "A set of access policies that bind specific application scopes to the role", + "computed": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "computed": true + }, + "scopes": { + "name": "scopes", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_appid_roles": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "roles", + "type": "TypeList", + "computed": true, + "elem": { + "access": { + "name": "access", + "type": "TypeSet", + "computed": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "computed": true + }, + "scopes": { + "name": "scopes", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Optional role description", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Unique role name", + "computed": true + }, + "role_id": { + "name": "role_id", + "type": "TypeString", + "description": "Role ID", + "computed": true + } + } + } + ], + "ibm_appid_theme_color": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "header_color", + "type": "TypeString", + "computed": true + } + ], + "ibm_appid_theme_text": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "tab_title", + "type": "TypeString", + "computed": true + }, + { + "name": "footnote", + "type": "TypeString", + "computed": true + } + ], + "ibm_appid_token_config": [ + { + "name": "refresh_token_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "access_token_claim", + "type": "TypeSet", + "description": "A set of objects that are created when claims that are related to access tokens are mapped", + "computed": true, + "elem": { + "destination_claim": { + "name": "destination_claim", + "type": "TypeString", + "description": "Optional: Defines the custom attribute that can override the current claim in token.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`, and `attributes`.", + "computed": true + }, + "source_claim": { + "name": "source_claim", + "type": "TypeString", + "description": "Defines the claim as provided by the source. It can refer to the identity provider's user information or the user's App ID custom attributes.", + "computed": true + } + } + }, + { + "name": "id_token_claim", + "type": "TypeSet", + "description": "A set of objects that are created when claims that are related to identity tokens are mapped", + "computed": true, + "elem": { + "destination_claim": { + "name": "destination_claim", + "type": "TypeString", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "computed": true + }, + "source_claim": { + "name": "source_claim", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "required": true + }, + { + "name": "access_token_expires_in", + "type": "TypeInt", + "description": "The length of time for which access tokens are valid in seconds", + "computed": true + }, + { + "name": "refresh_token_expires_in", + "type": "TypeInt", + "description": "The length of time for which refresh tokens are valid in seconds", + "computed": true + }, + { + "name": "anonymous_token_expires_in", + "type": "TypeInt", + "description": "The length of time for which an anonymous token is valid in seconds", + "computed": true + }, + { + "name": "anonymous_access_enabled", + "type": "TypeBool", + "computed": true + } + ], + "ibm_appid_user_roles": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "required": true + }, + { + "name": "subject", + "type": "TypeString", + "description": "The user's identifier ('subject' in identity token)", + "required": true + }, + { + "name": "roles", + "type": "TypeSet", + "description": "A set of user roles", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Role ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Role name", + "computed": true + } + } + } + ], + "ibm_atracker_endpoints": [ + { + "name": "api_endpoint", + "type": "TypeList", + "description": "Activity Tracker API endpoint.", + "computed": true, + "elem": { + "private_enabled": { + "name": "private_enabled", + "type": "TypeBool", + "description": "The private endpoint is always enabled.", + "computed": true + }, + "private_url": { + "name": "private_url", + "type": "TypeString", + "description": "The private URL of Activity Tracker. This URL cannot be disabled.", + "computed": true + }, + "public_enabled": { + "name": "public_enabled", + "type": "TypeBool", + "description": "Indicates whether or not the public endpoint is enabled in the account.", + "computed": true + }, + "public_url": { + "name": "public_url", + "type": "TypeString", + "description": "The public URL of Activity Tracker in a region.", + "computed": true + } + } + } + ], + "ibm_atracker_routes": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the route.", + "optional": true + }, + { + "name": "routes", + "type": "TypeList", + "description": "A list of route resources.", + "computed": true, + "elem": { + "api_version": { + "name": "api_version", + "type": "TypeInt", + "description": "The API version of the route.", + "computed": true + }, + "created": { + "name": "created", + "type": "TypeString", + "description": "The timestamp of the route creation time.", + "computed": true, + "deprecated": "use created_at instead" + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp of the route creation time.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn of the route resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The uuid of the route resource.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the route.", + "computed": true + }, + "receive_global_events": { + "name": "receive_global_events", + "type": "TypeBool", + "description": "Indicates whether or not all global events should be forwarded to this region.", + "computed": true, + "deprecated": "use rules.locations instead" + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "The routing rules that will be evaluated in their order of the array. Once a rule is matched, the remaining rules in the route definition will be skipped.", + "computed": true, + "elem": { + "locations": { + "name": "locations", + "type": "TypeList", + "description": "Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "target_ids": { + "name": "target_ids", + "type": "TypeList", + "description": "The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "updated": { + "name": "updated", + "type": "TypeString", + "description": "The timestamp of the target last updated time.", + "computed": true, + "deprecated": "use updated_at instead" + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp of the route last updated time.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeInt", + "description": "The version of the route.", + "computed": true + } + } + } + ], + "ibm_atracker_targets": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the target resource.", + "optional": true + }, + { + "name": "targets", + "type": "TypeList", + "description": "A list of target resources.", + "computed": true, + "elem": { + "api_version": { + "name": "api_version", + "type": "TypeInt", + "description": "The API version of the target.", + "computed": true + }, + "cos_endpoint": { + "name": "cos_endpoint", + "type": "TypeList", + "description": "Property values for a Cloud Object Storage Endpoint.", + "computed": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled.", + "secure": true, + "computed": true + }, + "bucket": { + "name": "bucket", + "type": "TypeString", + "description": "The bucket name under the Cloud Object Storage instance.", + "computed": true + }, + "endpoint": { + "name": "endpoint", + "type": "TypeString", + "description": "The host name of the Cloud Object Storage endpoint.", + "computed": true + }, + "service_to_service_enabled": { + "name": "service_to_service_enabled", + "type": "TypeBool", + "description": "ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey.", + "computed": true + }, + "target_crn": { + "name": "target_crn", + "type": "TypeString", + "description": "The CRN of the Cloud Object Storage instance.", + "computed": true + } + } + }, + "cos_write_status": { + "name": "cos_write_status", + "type": "TypeList", + "description": "The status of the write attempt with the provided cos_endpoint parameters.", + "computed": true, + "elem": { + "last_failure": { + "name": "last_failure", + "type": "TypeString", + "description": "The timestamp of the failure.", + "computed": true + }, + "reason_for_last_failure": { + "name": "reason_for_last_failure", + "type": "TypeString", + "description": "Detailed description of the cause of the failure.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status such as failed or success.", + "computed": true + } + }, + "deprecated": "use write_status instead" + }, + "created": { + "name": "created", + "type": "TypeString", + "description": "The timestamp of the target creation time.", + "computed": true, + "deprecated": "use created_at instead" + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp of the target creation time.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn of the target resource.", + "computed": true + }, + "encrypt_key": { + "name": "encrypt_key", + "type": "TypeString", + "description": "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + "computed": true, + "deprecated": "use encryption_key instead" + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + "secure": true, + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The uuid of the target resource.", + "computed": true + }, + "logdna_endpoint": { + "name": "logdna_endpoint", + "type": "TypeList", + "description": "Property values for a LogDNA Endpoint.", + "computed": true, + "elem": { + "ingestion_key": { + "name": "ingestion_key", + "type": "TypeString", + "description": "The LogDNA ingestion key is used for routing logs to a specific LogDNA instance.", + "secure": true, + "computed": true + }, + "target_crn": { + "name": "target_crn", + "type": "TypeString", + "description": "The CRN of the LogDNA instance.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the target resource.", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Included this optional field if you used it to create a target in a different region other than the one you are connected.", + "computed": true + }, + "target_type": { + "name": "target_type", + "type": "TypeString", + "description": "The type of the target.", + "computed": true + }, + "updated": { + "name": "updated", + "type": "TypeString", + "description": "The timestamp of the target last updated time.", + "computed": true, + "deprecated": "use updated_at instead" + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp of the target last updated time.", + "computed": true + }, + "write_status": { + "name": "write_status", + "type": "TypeList", + "description": "The status of the write attempt to the target with the provided endpoint parameters.", + "computed": true, + "elem": { + "last_failure": { + "name": "last_failure", + "type": "TypeString", + "description": "The timestamp of the failure.", + "computed": true + }, + "reason_for_last_failure": { + "name": "reason_for_last_failure", + "type": "TypeString", + "description": "Detailed description of the cause of the failure.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status such as failed or success.", + "computed": true + } + } + } + } + } + ], + "ibm_cbr_rule": [ + { + "name": "rule_id", + "type": "TypeString", + "description": "The ID of a rule.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the rule.", + "computed": true + }, + { + "name": "enforcement_mode", + "type": "TypeString", + "description": "The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The href link to the resource.", + "computed": true + }, + { + "name": "created_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which created the resource.", + "computed": true + }, + { + "name": "last_modified_at", + "type": "TypeString", + "description": "The last time the resource was modified.", + "computed": true + }, + { + "name": "last_modified_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which modified the resource.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The rule CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "contexts", + "type": "TypeList", + "description": "The contexts this rule applies to.", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeList", + "description": "The attributes.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The attribute name.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The attribute value.", + "computed": true + } + } + } + } + }, + { + "name": "resources", + "type": "TypeList", + "description": "The resources this rule apply to.", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeList", + "description": "The resource attributes.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The attribute name.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The attribute operator.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The attribute value.", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeList", + "description": "The optional resource tags.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The tag attribute name.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The attribute operator.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The tag attribute value.", + "computed": true + } + } + } + } + }, + { + "name": "operations", + "type": "TypeList", + "description": "The operations this rule applies to.", + "computed": true, + "elem": { + "api_types": { + "name": "api_types", + "type": "TypeList", + "description": "The API types this rule applies to.", + "computed": true, + "elem": { + "api_type_id": { + "name": "api_type_id", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time the resource was created.", + "computed": true + } + ], + "ibm_cbr_zone": [ + { + "name": "account_id", + "type": "TypeString", + "description": "The id of the account owning this zone.", + "computed": true + }, + { + "name": "addresses", + "type": "TypeList", + "description": "The list of addresses in the zone.", + "computed": true, + "elem": { + "ref": { + "name": "ref", + "type": "TypeList", + "description": "A service reference value.", + "computed": true, + "elem": { + "account_id": { + "name": "account_id", + "type": "TypeString", + "description": "The id of the account owning the service.", + "computed": true + }, + "location": { + "name": "location", + "type": "TypeString", + "description": "The location.", + "computed": true + }, + "service_instance": { + "name": "service_instance", + "type": "TypeString", + "description": "The service instance.", + "computed": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "The service name.", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "The service type.", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of address.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The IP address.", + "computed": true + } + } + }, + { + "name": "excluded", + "type": "TypeList", + "description": "The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded.", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of address.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The IP address.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time the resource was created.", + "computed": true + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "The ID of a zone.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The zone CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "address_count", + "type": "TypeInt", + "description": "The number of addresses in the zone.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The href link to the resource.", + "computed": true + }, + { + "name": "last_modified_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which modified the resource.", + "computed": true + }, + { + "name": "excluded_count", + "type": "TypeInt", + "description": "The number of excluded addresses in the zone.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the zone.", + "computed": true + }, + { + "name": "last_modified_at", + "type": "TypeString", + "description": "The last time the resource was modified.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the zone.", + "computed": true + }, + { + "name": "created_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which created the resource.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline": [ + { + "name": "enable_slack_notifications", + "type": "TypeBool", + "description": "Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain.", + "computed": true + }, + { + "name": "enable_partial_cloning", + "type": "TypeBool", + "description": "Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Flag whether this pipeline is enabled.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Standard RFC 3339 Date Time String.", + "computed": true + }, + { + "name": "build_number", + "type": "TypeInt", + "description": "The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs.", + "computed": true + }, + { + "name": "definitions", + "type": "TypeList", + "description": "Definition list.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "UUID.", + "computed": true + }, + "scm_source": { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source for Tekton pipeline definition.", + "computed": true, + "elem": { + "branch": { + "name": "branch", + "type": "TypeString", + "description": "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "The path to the definition's yaml files.", + "computed": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the SCM repository service instance.", + "computed": true + }, + "tag": { + "name": "tag", + "type": "TypeString", + "description": "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the definition repository.", + "computed": true + } + } + } + } + }, + { + "name": "properties", + "type": "TypeList", + "description": "Tekton pipeline's environment properties.", + "computed": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed when using `single_select` property type.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value.", + "computed": true + } + } + }, + { + "name": "toolchain", + "type": "TypeList", + "description": "Toolchain object.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for the toolchain that contains the Tekton pipeline.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "UUID.", + "computed": true + } + } + }, + { + "name": "triggers", + "type": "TypeList", + "description": "Tekton pipeline triggers list.", + "computed": true, + "elem": { + "cron": { + "name": "cron", + "type": "TypeString", + "description": "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + "computed": true + }, + "disabled": { + "name": "disabled", + "type": "TypeBool", + "description": "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + "computed": true + }, + "event_listener": { + "name": "event_listener", + "type": "TypeString", + "description": "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + "computed": true + }, + "events": { + "name": "events", + "type": "TypeList", + "description": "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + "computed": true, + "elem": { + "pull_request": { + "name": "pull_request", + "type": "TypeBool", + "description": "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + "computed": true + }, + "pull_request_closed": { + "name": "pull_request_closed", + "type": "TypeBool", + "description": "If true, the trigger listens for 'close pull request' Git webhook events.", + "computed": true + }, + "push": { + "name": "push", + "type": "TypeBool", + "description": "If true, the trigger listens for 'push' Git webhook events.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID.", + "computed": true + }, + "max_concurrent_runs": { + "name": "max_concurrent_runs", + "type": "TypeInt", + "description": "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Trigger name.", + "computed": true + }, + "properties": { + "name": "properties", + "type": "TypeList", + "description": "Trigger properties.", + "computed": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger property.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value. Can be empty and should be omitted for `single_select` property type.", + "computed": true + } + } + }, + "scm_source": { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source repository for a Git trigger. Only needed for Git triggers.", + "computed": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "computed": true + }, + "branch": { + "name": "branch", + "type": "TypeString", + "description": "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "hook_id": { + "name": "hook_id", + "type": "TypeString", + "description": "ID of the webhook from the repo. Computed upon creation of the trigger.", + "computed": true + }, + "pattern": { + "name": "pattern", + "type": "TypeString", + "description": "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + "computed": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the repository service instance.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the repository to which the trigger is listening.", + "computed": true + } + } + }, + "secret": { + "name": "secret", + "type": "TypeList", + "description": "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + "computed": true + }, + "key_name": { + "name": "key_name", + "type": "TypeString", + "description": "Secret name, not needed if type is `internal_validation`.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Secret location, not needed if secret type is `internal_validation`.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Secret type.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Secret value, not needed if secret type is `internal_validation`.", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeList", + "description": "Trigger tags array.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "timezone": { + "name": "timezone", + "type": "TypeString", + "description": "Only needed for timer triggers. Timezone for timer trigger.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Trigger type.", + "computed": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "TypeString", + "description": "Webhook URL that can be used to trigger pipeline runs.", + "computed": true + }, + "worker": { + "name": "worker", + "type": "TypeList", + "description": "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the worker. Computed based on the worker ID.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the worker. Computed based on the worker ID.", + "computed": true + } + } + } + } + }, + { + "name": "runs_url", + "type": "TypeString", + "description": "URL for this pipeline showing the list of pipeline runs.", + "computed": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "ID of current instance.", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Pipeline status.", + "computed": true + }, + { + "name": "worker", + "type": "TypeList", + "description": "Default pipeline worker used to run the pipeline.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the worker. Computed based on the worker ID.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the worker. Computed based on the worker ID.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "String.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Standard RFC 3339 Date Time String.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline_definition": [ + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "required": true + }, + { + "name": "definition_id", + "type": "TypeString", + "description": "The definition ID.", + "required": true + }, + { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source for Tekton pipeline definition.", + "computed": true, + "elem": { + "branch": { + "name": "branch", + "type": "TypeString", + "description": "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "The path to the definition's yaml files.", + "computed": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the SCM repository service instance.", + "computed": true + }, + "tag": { + "name": "tag", + "type": "TypeString", + "description": "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the definition repository.", + "computed": true + } + } + } + ], + "ibm_cd_tekton_pipeline_property": [ + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "required": true + }, + { + "name": "property_name", + "type": "TypeString", + "description": "The property name.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + { + "name": "value", + "type": "TypeString", + "description": "Property value.", + "computed": true + }, + { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed when using `single_select` property type.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "computed": true + }, + { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline_trigger": [ + { + "name": "timezone", + "type": "TypeString", + "description": "Only needed for timer triggers. Timezone for timer trigger.", + "computed": true + }, + { + "name": "secret", + "type": "TypeList", + "description": "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + "computed": true + }, + "key_name": { + "name": "key_name", + "type": "TypeString", + "description": "Secret name, not needed if type is `internal_validation`.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Secret location, not needed if secret type is `internal_validation`.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Secret type.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Secret value, not needed if secret type is `internal_validation`.", + "computed": true + } + } + }, + { + "name": "disabled", + "type": "TypeBool", + "description": "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + "computed": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Trigger type.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger.", + "computed": true + }, + { + "name": "worker", + "type": "TypeList", + "description": "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the worker. Computed based on the worker ID.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the worker. Computed based on the worker ID.", + "computed": true + } + } + }, + { + "name": "cron", + "type": "TypeString", + "description": "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Trigger name.", + "computed": true + }, + { + "name": "max_concurrent_runs", + "type": "TypeInt", + "description": "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + "computed": true + }, + { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source repository for a Git trigger. Only needed for Git triggers.", + "computed": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "computed": true + }, + "branch": { + "name": "branch", + "type": "TypeString", + "description": "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + "computed": true + }, + "hook_id": { + "name": "hook_id", + "type": "TypeString", + "description": "ID of the webhook from the repo. Computed upon creation of the trigger.", + "computed": true + }, + "pattern": { + "name": "pattern", + "type": "TypeString", + "description": "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + "computed": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the repository service instance.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the repository to which the trigger is listening.", + "computed": true + } + } + }, + { + "name": "events", + "type": "TypeList", + "description": "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + "computed": true, + "elem": { + "pull_request": { + "name": "pull_request", + "type": "TypeBool", + "description": "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + "computed": true + }, + "pull_request_closed": { + "name": "pull_request_closed", + "type": "TypeBool", + "description": "If true, the trigger listens for 'close pull request' Git webhook events.", + "computed": true + }, + "push": { + "name": "push", + "type": "TypeBool", + "description": "If true, the trigger listens for 'push' Git webhook events.", + "computed": true + } + } + }, + { + "name": "webhook_url", + "type": "TypeString", + "description": "Webhook URL that can be used to trigger pipeline runs.", + "computed": true + }, + { + "name": "trigger_id", + "type": "TypeString", + "description": "The trigger ID.", + "required": true + }, + { + "name": "event_listener", + "type": "TypeString", + "description": "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + "computed": true + }, + { + "name": "properties", + "type": "TypeList", + "description": "Trigger properties.", + "computed": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger property.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value. Can be empty and should be omitted for `single_select` property type.", + "computed": true + } + } + }, + { + "name": "tags", + "type": "TypeList", + "description": "Trigger tags array.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_cd_tekton_pipeline_trigger_property": [ + { + "name": "property_name", + "type": "TypeString", + "description": "The property name.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "computed": true + }, + { + "name": "value", + "type": "TypeString", + "description": "Property value. Can be empty and should be omitted for `single_select` property type.", + "computed": true + }, + { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "computed": true + }, + { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "computed": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "required": true + }, + { + "name": "trigger_id", + "type": "TypeString", + "description": "The trigger ID.", + "required": true + } + ], + "ibm_cd_toolchain": [ + { + "name": "created_by", + "type": "TypeString", + "description": "Identity that created the toolchain.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Tags associated with the toolchain.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Toolchain name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Toolchain description.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "Toolchain region.", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where toolchain can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Toolchain CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Account ID where toolchain can be found.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI that can be used to retrieve toolchain.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Toolchain creation timestamp.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest toolchain update timestamp.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_appconfig": [ + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "collection_name": { + "name": "collection_name", + "type": "TypeString", + "description": "App Configuration collection.", + "computed": true + }, + "environment_name": { + "name": "environment_name", + "type": "TypeString", + "description": "App Configuration environment.", + "computed": true + }, + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain.", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + } + ], + "ibm_cd_toolchain_tool_artifactory": [ + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the Artifactory integration tile.", + "computed": true + }, + "mirror_url": { + "name": "mirror_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain.", + "computed": true + }, + "release_url": { + "name": "release_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory release repository.", + "computed": true + }, + "repository_name": { + "name": "repository_name", + "type": "TypeString", + "description": "Type the name of your artifactory repository where your docker images are located.", + "computed": true + }, + "repository_url": { + "name": "repository_url", + "type": "TypeString", + "description": "Type the URL of your artifactory repository where your docker images are located.", + "computed": true + }, + "snapshot_url": { + "name": "snapshot_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory snapshot repository.", + "computed": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type the API key for your Artifactory repository.", + "secure": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Choose the type of repository for your Artifactory integration.", + "computed": true + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "Type the User ID or email for your Artifactory repository.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_bitbucketgit": [ + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://api.bitbucket.org.", + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "computed": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable Bitbucket Issues for lightweight issue tracking.", + "computed": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_custom": [ + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "additional_properties": { + "name": "additional_properties", + "type": "TypeString", + "description": "(Advanced) Type any information that is needed to integrate with other tools in your toolchain.", + "computed": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the tool integration card.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Type a description for the tool instance.", + "computed": true + }, + "documentation_url": { + "name": "documentation_url", + "type": "TypeString", + "description": "Type the URL for your tool's documentation.", + "computed": true + }, + "image_url": { + "name": "image_url", + "type": "TypeString", + "description": "Type the URL of the icon to show on your tool integration's card.", + "computed": true + }, + "lifecycle_phase": { + "name": "lifecycle_phase", + "type": "TypeString", + "description": "Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this specific tool integration; for example: My Build and Deploy Pipeline.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type the name of the tool that you are integrating; for example: Delivery Pipeline.", + "computed": true + } + } + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_cd_toolchain_tool_devopsinsights": [ + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + } + ], + "ibm_cd_toolchain_tool_githubconsolidated": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://api.github.example.com.", + "computed": true + }, + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "computed": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.", + "computed": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_cd_toolchain_tool_githubintegrated": [ + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://github.ibm.com/api/v3.", + "computed": true + }, + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "computed": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.", + "computed": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "computed": true + }, + "legal": { + "name": "legal", + "type": "TypeBool", + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_gitlab": [ + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://gitlab.example.com/api/v4.", + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "computed": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitLab Issues for lightweight issue tracking.", + "computed": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_hashicorpvault": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "authentication_method": { + "name": "authentication_method", + "type": "TypeString", + "description": "Choose the authentication method for your HashiCorp Vault instance.", + "computed": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile.", + "computed": true + }, + "default_secret": { + "name": "default_secret", + "type": "TypeString", + "description": "Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Type or select the authentication password for your HashiCorp Vault instance.", + "secure": true, + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Type the mount path where your secrets are stored in your HashiCorp Vault instance.", + "computed": true + }, + "role_id": { + "name": "role_id", + "type": "TypeString", + "description": "Type or select the authentication role ID for your HashiCorp Vault instance.", + "secure": true, + "computed": true + }, + "secret_filter": { + "name": "secret_filter", + "type": "TypeString", + "description": "Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance.", + "computed": true + }, + "secret_id": { + "name": "secret_id", + "type": "TypeString", + "description": "Type or select the authentication secret ID for your HashiCorp Vault instance.", + "secure": true, + "computed": true + }, + "server_url": { + "name": "server_url", + "type": "TypeString", + "description": "Type the server URL for your HashiCorp Vault instance.", + "computed": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type or select the authentication token for your HashiCorp Vault instance.", + "secure": true, + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Type or select the authentication username for your HashiCorp Vault instance.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_hostedgit": [ + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://gitlab.example.com/api/v4.", + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "computed": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable Issues for lightweight issue tracking.", + "computed": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_jenkins": [ + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_token": { + "name": "api_token", + "type": "TypeString", + "description": "Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance.", + "secure": true, + "computed": true + }, + "api_user_name": { + "name": "api_user_name", + "type": "TypeString", + "description": "Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance.", + "computed": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain.", + "computed": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "TypeString", + "description": "Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_keyprotect": [ + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_nexus": [ + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the Nexus integration tile.", + "computed": true + }, + "mirror_url": { + "name": "mirror_url", + "type": "TypeString", + "description": "Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain.", + "computed": true + }, + "release_url": { + "name": "release_url", + "type": "TypeString", + "description": "Type the URL for your Nexus release repository.", + "computed": true + }, + "snapshot_url": { + "name": "snapshot_url", + "type": "TypeString", + "description": "Type the URL for your Nexus snapshot repository.", + "computed": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type the password or authentication token for your Nexus repository.", + "secure": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Choose the type of repository for your Nexus integration.", + "computed": true + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "Type the User ID or email for your Nexus repository.", + "computed": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_pagerduty": [ + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key).", + "secure": true, + "computed": true + }, + "key_type": { + "name": "key_type", + "type": "TypeString", + "description": "Select whether to integrate at the account level with an API key or at the service level with an integration key.", + "computed": true + }, + "service_id": { + "name": "service_id", + "type": "TypeString", + "description": "service_id.", + "computed": true + }, + "service_key": { + "name": "service_key", + "type": "TypeString", + "description": "Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page.", + "secure": true, + "computed": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service.", + "computed": true + }, + "service_url": { + "name": "service_url", + "type": "TypeString", + "description": "Type the URL of the PagerDuty service to post alerts to.", + "computed": true + }, + "user_email": { + "name": "user_email", + "type": "TypeString", + "description": "Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user.", + "computed": true + }, + "user_phone": { + "name": "user_phone", + "type": "TypeString", + "description": "Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default.", + "computed": true + } + } + } + ], + "ibm_cd_toolchain_tool_pipeline": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + }, + "ui_pipeline": { + "name": "ui_pipeline", + "type": "TypeBool", + "description": "When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_privateworker": [ + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain.", + "computed": true + }, + "worker_queue_credentials": { + "name": "worker_queue_credentials", + "type": "TypeString", + "description": "Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue.", + "secure": true, + "computed": true + }, + "worker_queue_identifier": { + "name": "worker_queue_identifier", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_saucelabs": [ + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "key": { + "name": "key", + "type": "TypeString", + "description": "Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page.", + "secure": true, + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Type the user name for your Sauce Labs account.", + "computed": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + } + ], + "ibm_cd_toolchain_tool_secretsmanager": [ + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "computed": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_securitycompliance": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once).", + "secure": true, + "computed": true + }, + "evidence_namespace": { + "name": "evidence_namespace", + "type": "TypeString", + "description": "The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence.", + "computed": true + }, + "evidence_repo_name": { + "name": "evidence_repo_name", + "type": "TypeString", + "description": "To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker.", + "computed": true + }, + "location": { + "name": "location", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Give this tool integration a name, for example: my-security-compliance.", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + "computed": true + }, + "scope": { + "name": "scope", + "type": "TypeString", + "description": "Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + "computed": true + }, + "trigger_info": { + "name": "trigger_info", + "type": "TypeMap", + "description": "trigger_info.", + "computed": true + }, + "trigger_scan": { + "name": "trigger_scan", + "type": "TypeString", + "description": "Enabling trigger validation scans provides details for a pipeline task to trigger a scan.", + "computed": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + } + ], + "ibm_cd_toolchain_tool_slack": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "api_token": { + "name": "api_token", + "type": "TypeString", + "description": "Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead.", + "secure": true, + "computed": true + }, + "channel_name": { + "name": "channel_name", + "type": "TypeString", + "description": "If you use a webhook, you must specify an existing Slack channel to post notifications to.", + "computed": true + }, + "pipeline_fail": { + "name": "pipeline_fail", + "type": "TypeBool", + "computed": true + }, + "pipeline_start": { + "name": "pipeline_start", + "type": "TypeBool", + "computed": true + }, + "pipeline_success": { + "name": "pipeline_success", + "type": "TypeBool", + "computed": true + }, + "team_url": { + "name": "team_url", + "type": "TypeString", + "description": "If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_.", + "computed": true + }, + "toolchain_bind": { + "name": "toolchain_bind", + "type": "TypeBool", + "computed": true + }, + "toolchain_unbind": { + "name": "toolchain_unbind", + "type": "TypeBool", + "computed": true + } + } + } + ], + "ibm_cd_toolchain_tool_sonarqube": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Tool name.", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "computed": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "computed": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "computed": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain.", + "computed": true + }, + "user_login": { + "name": "user_login", + "type": "TypeString", + "description": "If you are using an authentication token, leave this field empty.", + "computed": true + }, + "user_password": { + "name": "user_password", + "type": "TypeString", + "secure": true, + "computed": true + } + } + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "ID of the tool bound to the toolchain.", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_certificate_manager_certificate": [ + { + "name": "certificate_details", + "type": "TypeList", + "description": "List of certificate", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "computed": true + }, + "begins_on": { + "name": "begins_on", + "type": "TypeInt", + "computed": true + }, + "cert_id": { + "name": "cert_id", + "type": "TypeString", + "computed": true + }, + "data": { + "name": "data", + "type": "TypeMap", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "domains": { + "name": "domains", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "expires_on": { + "name": "expires_on", + "type": "TypeInt", + "computed": true + }, + "has_previous": { + "name": "has_previous", + "type": "TypeBool", + "computed": true + }, + "imported": { + "name": "imported", + "type": "TypeBool", + "computed": true + }, + "issuance_info": { + "name": "issuance_info", + "type": "TypeMap", + "computed": true + }, + "issuer": { + "name": "issuer", + "type": "TypeString", + "computed": true + }, + "key_algorithm": { + "name": "key_algorithm", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "certificate_manager_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "required": true + } + ], + "ibm_certificate_manager_certificates": [ + { + "name": "certificate_manager_instance_id", + "type": "TypeString", + "description": "Certificate Manager Instance ID", + "required": true + }, + { + "name": "certificates", + "type": "TypeList", + "description": "List of certificates", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "computed": true + }, + "begins_on": { + "name": "begins_on", + "type": "TypeInt", + "computed": true + }, + "cert_id": { + "name": "cert_id", + "type": "TypeString", + "computed": true + }, + "domains": { + "name": "domains", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "expires_on": { + "name": "expires_on", + "type": "TypeInt", + "computed": true + }, + "has_previous": { + "name": "has_previous", + "type": "TypeBool", + "computed": true + }, + "imported": { + "name": "imported", + "type": "TypeBool", + "computed": true + }, + "issuance_info": { + "name": "issuance_info", + "type": "TypeMap", + "computed": true + }, + "issuer": { + "name": "issuer", + "type": "TypeString", + "computed": true + }, + "key_algorithm": { + "name": "key_algorithm", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "serial_number": { + "name": "serial_number", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_cis": [ + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, my cis instance", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the environment in which cis instance exists", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the Cloud Internet Services offering, 'internet-svcs'", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the cis instance is present", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Unique identifier of resource instance", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the cis instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + } + ], + "ibm_cis_alerts": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "alert_policies", + "type": "TypeList", + "description": "Container for response information.", + "computed": true, + "elem": { + "alert_type": { + "name": "alert_type", + "type": "TypeString", + "description": "Condition for the alert", + "computed": true + }, + "conditions": { + "name": "conditions", + "type": "TypeString", + "description": "Conditions based on filter type", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Policy Description", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Is the alert policy active", + "computed": true + }, + "filters": { + "name": "filters", + "type": "TypeString", + "description": "Filters based on filter type", + "computed": true + }, + "mechanisms": { + "name": "mechanisms", + "type": "TypeList", + "description": "Delivery mechanisms for the alert, can include an email, a webhook, or both.", + "computed": true, + "elem": { + "email": { + "name": "email", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "webhooks": { + "name": "webhooks", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Policy name", + "computed": true + }, + "policy_id": { + "name": "policy_id", + "type": "TypeString", + "description": "Policy ID", + "computed": true + } + } + } + ], + "ibm_cis_cache_settings": [ + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "caching_level", + "type": "TypeList", + "description": "Cache Level Setting", + "computed": true, + "elem": { + "editable": { + "name": "editable", + "type": "TypeBool", + "description": "cache level editable", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "cache level id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "cache level modified on", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "cache level value", + "computed": true + } + } + }, + { + "name": "serve_stale_content", + "type": "TypeList", + "description": "Serve Stale Content", + "computed": true, + "elem": { + "editable": { + "name": "editable", + "type": "TypeBool", + "description": "serve stale content editable", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "serve stale content id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "serve stale content modified on", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "serve stale content value", + "computed": true + } + } + }, + { + "name": "browser_expiration", + "type": "TypeList", + "description": "Browser Expiration setting", + "computed": true, + "elem": { + "editable": { + "name": "editable", + "type": "TypeBool", + "description": "browser expiration editable", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "browser expiration id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "browser expiration modified on", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "browser expiration value", + "computed": true + } + } + }, + { + "name": "development_mode", + "type": "TypeList", + "description": "Development mode setting", + "computed": true, + "elem": { + "editable": { + "name": "editable", + "type": "TypeBool", + "description": "development mode editable", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "development mode id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "development mode modified on", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "development mode value", + "computed": true + } + } + }, + { + "name": "query_string_sort", + "type": "TypeList", + "description": "Query String sort setting", + "computed": true, + "elem": { + "editable": { + "name": "editable", + "type": "TypeBool", + "description": "query string sort editable", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "query string sort id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "query string sort modified on", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "query qtring sort value", + "computed": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + } + ], + "ibm_cis_certificates": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "certificates", + "type": "TypeList", + "description": "Collection of certificates", + "computed": true, + "elem": { + "certificate_id": { + "name": "certificate_id", + "type": "TypeString", + "description": "certificate id", + "computed": true + }, + "certificates": { + "name": "certificates", + "type": "TypeList", + "description": "Collection of certificates associated with this certificates", + "computed": true, + "elem": { + "hosts": { + "name": "hosts", + "type": "TypeList", + "description": "Hosts which certificates are ordered", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "certificate id", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "certificate status", + "computed": true + } + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "description": "Hosts which certificate need to be ordered", + "required": true, + "elem": { + "type": "TypeString" + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "certificate identifier", + "computed": true + }, + "primary_certificate": { + "name": "primary_certificate", + "type": "TypeString", + "description": "Primary certificate id", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "certificate status", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "certificate type", + "computed": true + } + } + } + ], + "ibm_cis_custom_certificates": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "required": true + }, + { + "name": "custom_certificates", + "type": "TypeList", + "computed": true, + "elem": { + "bundle_method": { + "name": "bundle_method", + "type": "TypeString", + "description": "Certificate bundle method", + "computed": true + }, + "custom_cert_id": { + "name": "custom_cert_id", + "type": "TypeString", + "computed": true + }, + "expires_on": { + "name": "expires_on", + "type": "TypeString", + "description": "certificate expires date", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "description": "hosts which the certificate uploaded to", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "issuer": { + "name": "issuer", + "type": "TypeString", + "description": "certificate issuer", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "certificate modified date", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "Certificate priority", + "computed": true + }, + "signature": { + "name": "signature", + "type": "TypeString", + "description": "certificate signature", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "certificate status", + "computed": true + }, + "uploaded_on": { + "name": "uploaded_on", + "type": "TypeString", + "description": "certificate uploaded date", + "computed": true + } + } + } + ], + "ibm_cis_custom_pages": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "required": true + }, + { + "name": "cis_custom_pages", + "type": "TypeList", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Custom page created date", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Free text", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Custom page modified date", + "computed": true + }, + "page_id": { + "name": "page_id", + "type": "TypeString", + "description": "Custom page identifier", + "computed": true + }, + "preview_target": { + "name": "preview_target", + "type": "TypeString", + "description": "Custom page preview target", + "computed": true + }, + "required_tokens": { + "name": "required_tokens", + "type": "TypeList", + "description": "Custom page state", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "Custom page state", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "Custom page url", + "computed": true + } + } + } + ], + "ibm_cis_dns_records": [ + { + "name": "cis_dns_records", + "type": "TypeList", + "description": "Collection of dns resource records", + "computed": true, + "elem": { + "content": { + "name": "content", + "type": "TypeString", + "description": "DNS Record conent info", + "computed": true + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "DNS Record created on", + "computed": true + }, + "data": { + "name": "data", + "type": "TypeMap", + "description": "DNS Record Data", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "DNS record id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "DNS Record modified on", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "DNS Record Name", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "DNS Record MX priority", + "computed": true + }, + "proxiable": { + "name": "proxiable", + "type": "TypeBool", + "description": "DNS Record proxiable", + "computed": true + }, + "proxied": { + "name": "proxied", + "type": "TypeBool", + "description": "DNS Record proxied", + "computed": true + }, + "record_id": { + "name": "record_id", + "type": "TypeString", + "description": "DNS record id", + "computed": true + }, + "ttl": { + "name": "ttl", + "type": "TypeInt", + "description": "DNS Record Time To Live", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "DNS Record Type", + "computed": true + }, + "zone_name": { + "name": "zone_name", + "type": "TypeString", + "description": "DNS Record Name", + "computed": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Zone Id", + "required": true + }, + { + "name": "file", + "type": "TypeString", + "description": "file to be exported", + "optional": true + } + ], + "ibm_cis_domain": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "type", + "type": "TypeString", + "description": "CISzone - Domain Type", + "computed": true + }, + { + "name": "verification_key", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "cname_suffix", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "computed": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "CISzone - Domain", + "required": true + }, + { + "name": "paused", + "type": "TypeBool", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "name_servers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "original_name_servers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_cis_edge_functions_actions": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "cis_edge_functions_actions", + "type": "TypeList", + "description": "List of edge functions actions", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Edge function action script created on", + "computed": true + }, + "etag": { + "name": "etag", + "type": "TypeString", + "description": "Edge function action etag", + "computed": true + }, + "handlers": { + "name": "handlers", + "type": "TypeSet", + "description": "Edge function action handlers", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Edge function action script modified on", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "description": "List of edge function action routes", + "computed": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Edge function action script name", + "computed": true + }, + "pattern_url": { + "name": "pattern_url", + "type": "TypeString", + "description": "Edge function action pattern", + "computed": true + }, + "request_limit_fail_open": { + "name": "request_limit_fail_open", + "type": "TypeBool", + "description": "Edge function action script request limit fail open", + "computed": true + }, + "trigger_id": { + "name": "trigger_id", + "type": "TypeString", + "description": "Edge function action script identifier", + "computed": true + } + } + } + } + } + ], + "ibm_cis_edge_functions_triggers": [ + { + "name": "cis_edge_functions_triggers", + "type": "TypeList", + "description": "List of edge functions triggers", + "computed": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Edge function trigger script name", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Edge function trigger id", + "computed": true + }, + "pattern_url": { + "name": "pattern_url", + "type": "TypeString", + "description": "Edge function trigger pattern", + "computed": true + }, + "request_limit_fail_open": { + "name": "request_limit_fail_open", + "type": "TypeBool", + "description": "Edge function trigger request limit fail open", + "computed": true + }, + "trigger_id": { + "name": "trigger_id", + "type": "TypeString", + "description": "Edge function trigger route id", + "computed": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + } + ], + "ibm_cis_filters": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "cis_filters_list", + "type": "TypeList", + "description": "Collection of Filter detail", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Filter Description", + "computed": true + }, + "expression": { + "name": "expression", + "type": "TypeString", + "description": "Filter Expression", + "computed": true + }, + "filter_id": { + "name": "filter_id", + "type": "TypeString", + "description": "Filter ID", + "computed": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Filter Paused", + "computed": true + } + } + } + ], + "ibm_cis_firewall": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "firewall_type", + "type": "TypeString", + "description": "Type of firewall.Allowable values are access-rules,ua-rules,lockdowns", + "required": true + }, + { + "name": "lockdown", + "type": "TypeList", + "description": "Lockdown Data", + "computed": true, + "elem": { + "configurations": { + "name": "configurations", + "type": "TypeList", + "computed": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "computed": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description", + "computed": true + }, + "lockdown_id": { + "name": "lockdown_id", + "type": "TypeString", + "description": "firewall identifier", + "computed": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Firewall rule paused or enabled", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "Firewall priority", + "computed": true + }, + "urls": { + "name": "urls", + "type": "TypeList", + "description": "URL in which firewall rule is applied", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "access_rule", + "type": "TypeList", + "description": "Access Rule Data", + "computed": true, + "elem": { + "access_rule_id": { + "name": "access_rule_id", + "type": "TypeString", + "description": "firewall identifier", + "computed": true + }, + "configuration": { + "name": "configuration", + "type": "TypeList", + "computed": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "computed": true + } + } + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "Access rule mode", + "computed": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "description": "description", + "computed": true + } + } + }, + { + "name": "ua_rule", + "type": "TypeList", + "description": "User Agent Rule Data", + "computed": true, + "elem": { + "configuration": { + "name": "configuration", + "type": "TypeList", + "computed": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "computed": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description", + "computed": true + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "user agent rule mode", + "computed": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Rule whether paused or not", + "computed": true + }, + "ua_rule_id": { + "name": "ua_rule_id", + "type": "TypeString", + "description": "firewall identifier", + "computed": true + } + } + } + ], + "ibm_cis_firewall_rules": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "Full url-encoded cloud resource name (CRN) of resource instance.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Zone identifier of the zone for which firewall rules are listed.", + "required": true + }, + { + "name": "firewall_rules", + "type": "TypeList", + "description": "Container for response information.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "The firewall action to perform, \"log\" action is only available for enterprise plan instances.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "To briefly describe the firewall rule, omitted from object if empty.", + "computed": true + }, + "filter": { + "name": "filter", + "type": "TypeMap", + "description": "An existing filter.", + "computed": true + }, + "firewall_rule_id": { + "name": "firewall_rule_id", + "type": "TypeString", + "description": "Identifier of the firewall rule.", + "computed": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Indicates if the firewall rule is active.", + "computed": true + } + } + } + ], + "ibm_cis_global_load_balancers": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "cis_glb", + "type": "TypeList", + "description": "Collection of GLB detail", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Load balancer creation date", + "computed": true + }, + "default_pool_ids": { + "name": "default_pool_ids", + "type": "TypeList", + "description": "List of default Pool IDs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description for the load balancer instance", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "set to true of LB needs to enabled", + "computed": true + }, + "fallback_pool_id": { + "name": "fallback_pool_id", + "type": "TypeString", + "description": "fallback pool ID", + "computed": true + }, + "glb_id": { + "name": "glb_id", + "type": "TypeString", + "description": "global load balancer id", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "identifier with zone id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Load balancer modified date", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "name", + "computed": true + }, + "pop_pools": { + "name": "pop_pools", + "type": "TypeList", + "computed": true, + "elem": { + "pool_ids": { + "name": "pool_ids", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "pop": { + "name": "pop", + "type": "TypeString", + "description": "pop pools region", + "computed": true + } + } + }, + "proxied": { + "name": "proxied", + "type": "TypeBool", + "description": "set to true if proxy needs to be enabled", + "computed": true + }, + "region_pools": { + "name": "region_pools", + "type": "TypeList", + "computed": true, + "elem": { + "pool_ids": { + "name": "pool_ids", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "region": { + "name": "region", + "type": "TypeString", + "computed": true + } + } + }, + "session_affinity": { + "name": "session_affinity", + "type": "TypeString", + "description": "Session affinity info", + "computed": true + }, + "steering_policy": { + "name": "steering_policy", + "type": "TypeString", + "description": "Steering policy info", + "computed": true + }, + "ttl": { + "name": "ttl", + "type": "TypeInt", + "description": "TTL value", + "computed": true + } + } + } + ], + "ibm_cis_healthchecks": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "cis_healthchecks", + "type": "TypeList", + "description": "Collection of GLB Health check/monitor detail", + "computed": true, + "elem": { + "allow_insecure": { + "name": "allow_insecure", + "type": "TypeBool", + "description": "allow_insecure", + "computed": true + }, + "cis_id": { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "computed": true + }, + "create_on": { + "name": "create_on", + "type": "TypeString", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description", + "computed": true + }, + "expected_body": { + "name": "expected_body", + "type": "TypeString", + "description": "expected_body", + "computed": true + }, + "expected_codes": { + "name": "expected_codes", + "type": "TypeString", + "description": "expected_codes", + "computed": true + }, + "follow_redirects": { + "name": "follow_redirects", + "type": "TypeBool", + "description": "follow_redirects", + "computed": true + }, + "headers": { + "name": "headers", + "type": "TypeList", + "computed": true, + "elem": { + "header": { + "name": "header", + "type": "TypeString", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "GLB Monitor/Health check id", + "computed": true + }, + "interval": { + "name": "interval", + "type": "TypeInt", + "description": "interval", + "computed": true + }, + "method": { + "name": "method", + "type": "TypeString", + "description": "method", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "computed": true + }, + "monitor_id": { + "name": "monitor_id", + "type": "TypeString", + "description": "GLB Monitor/Health check id", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "path", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "computed": true + }, + "retries": { + "name": "retries", + "type": "TypeInt", + "description": "retries", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "timeout", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "type", + "computed": true + } + } + } + ], + "ibm_cis_ip_addresses": [ + { + "name": "ipv4_cidrs", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "ipv6_cidrs", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_cis_logpush_jobs": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "logpush_job_pack", + "type": "TypeList", + "description": "logpush jobs information.", + "computed": true, + "elem": { + "dataset": { + "name": "dataset", + "type": "TypeString", + "description": "Dataset to be pulled", + "computed": true + }, + "destination_conf": { + "name": "destination_conf", + "type": "TypeString", + "description": "Uniquely identifies a resource (such as an s3 bucket) where data will be pushed.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the logpush job enabled or not", + "computed": true + }, + "frequency": { + "name": "frequency", + "type": "TypeString", + "description": "The frequency at which CIS sends batches of logs to your destination", + "computed": true + }, + "job_id": { + "name": "job_id", + "type": "TypeInt", + "description": "Associated CIS domain", + "computed": true + }, + "logpull_options": { + "name": "logpull_options", + "type": "TypeString", + "description": "Configuration string", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Logpush Job Name", + "computed": true + } + } + } + ], + "ibm_cis_mtls_apps": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "mtls_access_apps", + "type": "TypeList", + "description": "Container for Access App Response.", + "computed": true, + "elem": { + "allowed_idps": { + "name": "allowed_idps", + "type": "TypeList", + "description": "List of allowed idps.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "app_aud": { + "name": "app_aud", + "type": "TypeString", + "description": "Application Aud", + "computed": true + }, + "app_created_at": { + "name": "app_created_at", + "type": "TypeString", + "description": "Application Created At", + "computed": true + }, + "app_domain": { + "name": "app_domain", + "type": "TypeString", + "description": "Application Domain", + "computed": true + }, + "app_id": { + "name": "app_id", + "type": "TypeString", + "description": "Application ID", + "computed": true + }, + "app_name": { + "name": "app_name", + "type": "TypeString", + "description": "Application name", + "computed": true + }, + "app_type": { + "name": "app_type", + "type": "TypeString", + "description": "Application Type", + "computed": true + }, + "app_uid": { + "name": "app_uid", + "type": "TypeString", + "description": "Application UID", + "computed": true + }, + "app_updated_at": { + "name": "app_updated_at", + "type": "TypeString", + "description": "Application Updated At", + "computed": true + }, + "auto_redirect_to_identity": { + "name": "auto_redirect_to_identity", + "type": "TypeBool", + "description": "Auto Redirect to Identity", + "computed": true + }, + "session_duration": { + "name": "session_duration", + "type": "TypeString", + "description": "Session Duration", + "computed": true + } + } + }, + { + "name": "mtls_access_app_policies", + "type": "TypeList", + "description": "Access Policies Information", + "computed": true, + "elem": { + "policy_created_at": { + "name": "policy_created_at", + "type": "TypeString", + "description": "Application Created At", + "computed": true + }, + "policy_decision": { + "name": "policy_decision", + "type": "TypeString", + "description": "Policy Decision", + "computed": true + }, + "policy_id": { + "name": "policy_id", + "type": "TypeString", + "description": "Policy ID", + "computed": true + }, + "policy_name": { + "name": "policy_name", + "type": "TypeString", + "description": "Policy name", + "computed": true + }, + "policy_precedence": { + "name": "policy_precedence", + "type": "TypeInt", + "description": "Policy Precedence", + "computed": true + }, + "policy_uid": { + "name": "policy_uid", + "type": "TypeString", + "description": "Policy UID", + "computed": true + }, + "policy_updated_at": { + "name": "policy_updated_at", + "type": "TypeString", + "description": "Application Updated At", + "computed": true + } + } + } + ], + "ibm_cis_mtlss": [ + { + "name": "mtls_certificates", + "type": "TypeList", + "description": "Container for response information.", + "computed": true, + "elem": { + "associated_hostnames": { + "name": "associated_hostnames", + "type": "TypeList", + "description": "Certificate Associated Hostnames", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Certificate Created At", + "computed": true + }, + "expires_on": { + "name": "expires_on", + "type": "TypeString", + "description": "Certificate Expires On", + "computed": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "TypeString", + "description": "Certificate Fingerprint", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Certificate ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Certificate name", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Certificate Updated At", + "computed": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + } + ], + "ibm_cis_origin_auths": [ + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Associated CIS host name", + "default_value": "no_host", + "optional": true + }, + { + "name": "request_type", + "type": "TypeString", + "description": "Associated CIS Request Type", + "default_value": "zone_level", + "optional": true + }, + { + "name": "origin_pull_settings_enabled", + "type": "TypeBool", + "description": "CIS origin auth settings enabled or disabled", + "computed": true + }, + { + "name": "origin_pull_certs", + "type": "TypeList", + "description": "Certficate list", + "computed": true, + "elem": { + "cert_expires_on": { + "name": "cert_expires_on", + "type": "TypeString", + "description": "CIS origin auth certificate expiry time", + "computed": true + }, + "cert_id": { + "name": "cert_id", + "type": "TypeString", + "description": "CIS origin auth certificate id", + "computed": true + }, + "cert_issuer": { + "name": "cert_issuer", + "type": "TypeString", + "description": "CIS origin auth certificate issue", + "computed": true + }, + "cert_serial_number": { + "name": "cert_serial_number", + "type": "TypeString", + "description": "CIS origin auth certificate Serial Number", + "computed": true + }, + "cert_signature": { + "name": "cert_signature", + "type": "TypeString", + "description": "CIS origin auth certificate signature", + "computed": true + }, + "cert_status": { + "name": "cert_status", + "type": "TypeString", + "description": "CIS origin auth certificate active or not", + "computed": true + }, + "cert_uploaded_on": { + "name": "cert_uploaded_on", + "type": "TypeString", + "description": "CIS origin auth certificate upldate time", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeString", + "description": "CIS origin auth certificate detail", + "secure": true, + "computed": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + } + ], + "ibm_cis_origin_pools": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "cis_origin_pools", + "type": "TypeList", + "description": "Collection of GLB pools detail", + "computed": true, + "elem": { + "check_regions": { + "name": "check_regions", + "type": "TypeList", + "description": "List of regions", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Creation date info", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the CIS Origin Pool", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Boolean value set to true if cis origin pool needs to be enabled", + "computed": true + }, + "healthy": { + "name": "healthy", + "type": "TypeBool", + "description": "Health status", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "GLB Pools id", + "computed": true + }, + "minimum_origins": { + "name": "minimum_origins", + "type": "TypeInt", + "description": "Minimum number of Origins", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Modified date info", + "computed": true + }, + "monitor": { + "name": "monitor", + "type": "TypeString", + "description": "Monitor value", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "name", + "computed": true + }, + "notification_email": { + "name": "notification_email", + "type": "TypeString", + "description": "Email address configured to recieve the notifications", + "computed": true + }, + "origins": { + "name": "origins", + "type": "TypeList", + "description": "Origins info", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "computed": true + }, + "disabled_at": { + "name": "disabled_at", + "type": "TypeString", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "failure_reason": { + "name": "failure_reason", + "type": "TypeString", + "computed": true + }, + "healthy": { + "name": "healthy", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "weight": { + "name": "weight", + "type": "TypeFloat", + "computed": true + } + } + }, + "pool_id": { + "name": "pool_id", + "type": "TypeString", + "description": "GLB Pool id", + "computed": true + } + } + } + ], + "ibm_cis_page_rules": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "DNS Zone ID", + "required": true + }, + { + "name": "cis_page_rules", + "type": "TypeList", + "description": "Collection of page rules detail", + "computed": true, + "elem": { + "actions": { + "name": "actions", + "type": "TypeList", + "description": "Page rule actions", + "computed": true, + "elem": { + "css": { + "name": "css", + "type": "TypeString", + "description": "Minify CSS value", + "computed": true + }, + "html": { + "name": "html", + "type": "TypeString", + "description": "Minify HTML value", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Page rule target url", + "computed": true + }, + "js": { + "name": "js", + "type": "TypeString", + "description": "Minify JS value", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeInt", + "description": "Page rule actions status code", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "Page rule actions value url", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Page rule target url", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Page rule identifier", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "Page rule priority", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Page Rule status", + "computed": true + }, + "targets": { + "name": "targets", + "type": "TypeList", + "description": "Page rule targets", + "computed": true, + "elem": { + "constraint": { + "name": "constraint", + "type": "TypeList", + "description": "Page rule constraint", + "computed": true, + "elem": { + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Constraint operator", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Constraint value", + "computed": true + } + } + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Page rule target url", + "computed": true + } + } + } + } + } + ], + "ibm_cis_range_apps": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "range_apps", + "type": "TypeList", + "description": "Collection of range application detail", + "computed": true, + "elem": { + "app_id": { + "name": "app_id", + "type": "TypeString", + "description": "Application identifier", + "computed": true + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "created on date", + "computed": true + }, + "dns": { + "name": "dns", + "type": "TypeString", + "description": "Name of the DNS record for this application", + "computed": true + }, + "dns_type": { + "name": "dns_type", + "type": "TypeString", + "description": "Type of the DNS record for this application", + "computed": true + }, + "edge_ips_connectivity": { + "name": "edge_ips_connectivity", + "type": "TypeString", + "description": "Specifies the IP version.", + "computed": true + }, + "edge_ips_type": { + "name": "edge_ips_type", + "type": "TypeString", + "description": "The type of edge IP configuration.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "range app id", + "computed": true + }, + "ip_firewall": { + "name": "ip_firewall", + "type": "TypeBool", + "description": "Enables the IP Firewall for this application. Only available for TCP applications.", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "modified on date", + "computed": true + }, + "origin_direct": { + "name": "origin_direct", + "type": "TypeList", + "description": "IP address and port of the origin for this Range application.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "Defines the protocol and port for this application", + "computed": true + }, + "proxy_protocol": { + "name": "proxy_protocol", + "type": "TypeString", + "description": "Allows for the true client IP to be passed to the service.", + "computed": true + }, + "tls": { + "name": "tls", + "type": "TypeString", + "description": "Configure if and how TLS connections are terminated at the edge.", + "computed": true + }, + "traffic_type": { + "name": "traffic_type", + "type": "TypeString", + "description": "Configure how traffic is handled at the edge.", + "computed": true + } + } + } + ], + "ibm_cis_rate_limit": [ + { + "name": "cis_id", + "type": "TypeString", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "required": true + }, + { + "name": "rate_limit", + "type": "TypeList", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeList", + "computed": true, + "elem": { + "mode": { + "name": "mode", + "type": "TypeString", + "computed": true + }, + "response": { + "name": "response", + "type": "TypeList", + "computed": true, + "elem": { + "body": { + "name": "body", + "type": "TypeString", + "computed": true + }, + "content_type": { + "name": "content_type", + "type": "TypeString", + "computed": true + } + } + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "computed": true + } + } + }, + "bypass": { + "name": "bypass", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "computed": true + } + } + }, + "correlate": { + "name": "correlate", + "type": "TypeList", + "computed": true, + "elem": { + "by": { + "name": "by", + "type": "TypeString", + "computed": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "disabled": { + "name": "disabled", + "type": "TypeBool", + "computed": true + }, + "match": { + "name": "match", + "type": "TypeList", + "computed": true, + "elem": { + "request": { + "name": "request", + "type": "TypeList", + "computed": true, + "elem": { + "methods": { + "name": "methods", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "schemes": { + "name": "schemes", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "computed": true + } + } + }, + "response": { + "name": "response", + "type": "TypeList", + "computed": true, + "elem": { + "headers": { + "name": "headers", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "op": { + "name": "op", + "type": "TypeString", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "computed": true + } + } + }, + "origin_traffic": { + "name": "origin_traffic", + "type": "TypeBool", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + } + }, + "period": { + "name": "period", + "type": "TypeInt", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "computed": true + }, + "threshold": { + "name": "threshold", + "type": "TypeInt", + "computed": true + } + } + } + ], + "ibm_cis_waf_groups": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "package_id", + "type": "TypeString", + "description": "WAF Rule package id", + "required": true + }, + { + "name": "waf_groups", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "WAF Rule group description", + "computed": true + }, + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "WAF Rule group id", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "WAF Rule group id", + "computed": true + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "WAF Rule group mode on/off", + "computed": true + }, + "modified_rules_count": { + "name": "modified_rules_count", + "type": "TypeInt", + "description": "WAF Rule group modified rules count", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "WAF Rule group name", + "computed": true + }, + "rules_count": { + "name": "rules_count", + "type": "TypeInt", + "description": "WAF Rule group rules count", + "computed": true + } + } + } + ], + "ibm_cis_waf_packages": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "DNS Zone CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS domain id", + "required": true + }, + { + "name": "waf_packages", + "type": "TypeList", + "description": "Collection of GLB Health check/monitor detail", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "WAF pakcage description", + "computed": true + }, + "detection_mode": { + "name": "detection_mode", + "type": "TypeString", + "description": "WAF pakcage detection mode", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "CIS WAF package id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "WAF pakcage name", + "computed": true + }, + "package_id": { + "name": "package_id", + "type": "TypeString", + "description": "WAF pakcage ID", + "computed": true + } + } + } + ], + "ibm_cis_waf_rules": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CISzone - Domain", + "required": true + }, + { + "name": "package_id", + "type": "TypeString", + "description": "WAF rule package id", + "required": true + }, + { + "name": "waf_rules", + "type": "TypeList", + "description": "Collection of WAF Rules", + "computed": true, + "elem": { + "allowed_modes": { + "name": "allowed_modes", + "type": "TypeList", + "description": "CIS WAF Rule allowed modes", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "CIS WAF Rule descriptions", + "computed": true + }, + "group": { + "name": "group", + "type": "TypeList", + "description": "CIS WAF Rule group", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "waf rule group id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "waf rule group name", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "WAF Rule id", + "computed": true + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "CIS WAF Rule mode", + "computed": true + }, + "package_id": { + "name": "package_id", + "type": "TypeString", + "description": "WAF Package id", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeString", + "description": "CIS WAF Rule Priority", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "WAF Rule id", + "computed": true + } + } + } + ], + "ibm_cis_webhooks": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "cis_webhooks", + "type": "TypeList", + "description": "Collection of Webhook details", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Webhook Name", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Webhook Type", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "Webhook URL", + "computed": true + }, + "webhook_id": { + "name": "webhook_id", + "type": "TypeString", + "description": "Webhook ID", + "computed": true + } + } + } + ], + "ibm_cloud_shell_account_settings": [ + { + "name": "rev", + "type": "TypeString", + "description": "Unique revision number for the settings object.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeInt", + "description": "Creation timestamp in Unix epoch time.", + "computed": true + }, + { + "name": "default_enable_new_features", + "type": "TypeBool", + "description": "You can choose which Cloud Shell features are available in the account and whether any new features are enabled as they become available. The feature settings apply only to the enabled Cloud Shell locations.", + "computed": true + }, + { + "name": "default_enable_new_regions", + "type": "TypeBool", + "description": "Set whether Cloud Shell is enabled in a specific location for the account. The location determines where user and session data are stored. By default, users are routed to the nearest available location.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "IAM ID of last updater.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeInt", + "description": "Timestamp of last update in Unix epoch time.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The account ID in which the account settings belong to.", + "required": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "IAM ID of creator.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "When enabled, Cloud Shell is available to all users in the account.", + "computed": true + }, + { + "name": "features", + "type": "TypeList", + "description": "List of Cloud Shell features.", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "State of the feature.", + "computed": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Name of the feature.", + "computed": true + } + } + }, + { + "name": "regions", + "type": "TypeList", + "description": "List of Cloud Shell region settings.", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "State of the region.", + "computed": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Name of the region.", + "computed": true + } + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of api response object.", + "computed": true + } + ], + "ibm_cloudant": [ + { + "name": "version", + "type": "TypeString", + "description": "Vendor version.", + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "A number of blocks of throughput units. A block consists of 100 reads/sec, 50 writes/sec, and 5 global queries/sec of provisioned throughput capacity.", + "computed": true + }, + { + "name": "throughput", + "type": "TypeMap", + "description": "Schema for detailed information about throughput capacity with breakdown by specific throughput requests classes.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the environment in which instance exists", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of resource instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "features_flags", + "type": "TypeList", + "description": "List of feature flags.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags of Resource Instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "enable_cors", + "type": "TypeBool", + "description": "Boolean value to turn CORS on and off.", + "computed": true + }, + { + "name": "include_data_events", + "type": "TypeBool", + "description": "Include data event types in events sent to IBM Cloud Activity Tracker with LogDNA for the IBM Cloudant instance. By default only emitted events are of \"management\" type.", + "computed": true + }, + { + "name": "cors_config", + "type": "TypeList", + "description": "Configuration for CORS.", + "computed": true, + "elem": { + "allow_credentials": { + "name": "allow_credentials", + "type": "TypeBool", + "description": "Boolean value to allow authentication credentials. If set to true, browser requests must be done by using withCredentials = true.", + "computed": true + }, + "origins": { + "name": "origins", + "type": "TypeList", + "description": "An array of strings that contain allowed origin domains. You have to specify the full URL including the protocol. It is recommended that only the HTTPS protocol is used. Subdomains count as separate domains, so you have to specify all subdomains used.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the instance is present", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the instance", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the resource instance.", + "computed": true + }, + { + "name": "features", + "type": "TypeList", + "description": "List of enabled optional features.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, myobjectstorage", + "required": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The service type of the instance", + "computed": true + } + ], + "ibm_cloudant_database": [ + { + "name": "engine", + "type": "TypeString", + "description": "The engine used for the database.", + "computed": true + }, + { + "name": "props", + "type": "TypeList", + "description": "The database properties.", + "computed": true, + "elem": { + "partitioned": { + "name": "partitioned", + "type": "TypeBool", + "description": "The value is `true` for a partitioned database.", + "computed": true + } + } + }, + { + "name": "cluster", + "type": "TypeList", + "description": "Database cluster information.", + "computed": true, + "elem": { + "read_quorum": { + "name": "read_quorum", + "type": "TypeInt", + "description": "Read quorum. The number of consistent copies of a document that need to be read before a successful reply.", + "computed": true + }, + "replicas": { + "name": "replicas", + "type": "TypeInt", + "description": "The number of replicas of a database in a cluster.", + "computed": true + }, + "shards": { + "name": "shards", + "type": "TypeInt", + "description": "The number of shards in a database. Each shard is a partition of the hash value range.", + "computed": true + }, + "write_quorum": { + "name": "write_quorum", + "type": "TypeInt", + "description": "Write quorum. The number of copies of a document that need to be written before a successful reply.", + "computed": true + } + } + }, + { + "name": "disk_format_version", + "type": "TypeInt", + "description": "The version of the physical format used for the data when it is stored on disk.", + "computed": true + }, + { + "name": "doc_count", + "type": "TypeInt", + "description": "A count of the documents in the specified database.", + "computed": true + }, + { + "name": "db", + "type": "TypeString", + "description": "Path parameter to specify the database name.", + "required": true + }, + { + "name": "compact_running", + "type": "TypeBool", + "description": "True if the database compaction routine is operating on this database.", + "computed": true + }, + { + "name": "committed_update_seq", + "type": "TypeString", + "description": "An opaque string that describes the committed state of the database.", + "computed": true + }, + { + "name": "compacted_seq", + "type": "TypeString", + "description": "An opaque string that describes the compaction state of the database.", + "computed": true + }, + { + "name": "update_seq", + "type": "TypeString", + "description": "An opaque string that describes the state of the database. Do not rely on this string for counting the number of updates.", + "computed": true + }, + { + "name": "uuid", + "type": "TypeString", + "description": "The UUID of the database.", + "computed": true + }, + { + "name": "instance_crn", + "type": "TypeString", + "description": "Cloudant Instance CRN.", + "required": true + }, + { + "name": "doc_del_count", + "type": "TypeInt", + "description": "Number of deleted documents.", + "computed": true + }, + { + "name": "sizes", + "type": "TypeList", + "description": "Database size information.", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeInt", + "description": "The active size of the data in the database, in bytes.", + "computed": true + }, + "external": { + "name": "external", + "type": "TypeInt", + "description": "The total uncompressed size of the data in the database, in bytes.", + "computed": true + }, + "file": { + "name": "file", + "type": "TypeInt", + "description": "The total size of the database as stored on disk, in bytes.", + "computed": true + } + } + } + ], + "ibm_cm_catalog": [ + { + "name": "url", + "type": "TypeString", + "description": "The url for this specific catalog.", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Display Name in the requested language.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "List of tags associated with this catalog.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "short_description", + "type": "TypeString", + "description": "Description in the requested language.", + "computed": true + }, + { + "name": "catalog_icon_url", + "type": "TypeString", + "description": "URL for an icon associated with this catalog.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN associated with the catalog.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "offerings_url", + "type": "TypeString", + "description": "URL path to offerings.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource Group ID", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "catalog_identifier", + "type": "TypeString", + "description": "ID for catalog", + "immutable": true, + "required": true + }, + { + "name": "kind", + "type": "TypeString", + "description": "Kind of catalog, offering or vpe.", + "computed": true + } + ], + "ibm_cm_offering": [ + { + "name": "catalog_identifier", + "type": "TypeString", + "description": "Catalog identifier.", + "immutable": true, + "required": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Display Name in the requested language.", + "immutable": true, + "computed": true + }, + { + "name": "offering_docs_url", + "type": "TypeString", + "description": "URL for an additional docs with this offering.", + "computed": true + }, + { + "name": "short_description", + "type": "TypeString", + "description": "Short description in the requested language.", + "computed": true + }, + { + "name": "disclaimer", + "type": "TypeString", + "description": "A disclaimer for this offering.", + "computed": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The url for this specific offering.", + "computed": true + }, + { + "name": "long_description", + "type": "TypeString", + "description": "Long description in the requested language.", + "computed": true + }, + { + "name": "ibm_publish_approved", + "type": "TypeBool", + "description": "Indicates if this offering has been approved for use by all IBMers.", + "computed": true + }, + { + "name": "catalog_id", + "type": "TypeString", + "description": "The id of the catalog containing this offering.", + "computed": true + }, + { + "name": "catalog_name", + "type": "TypeString", + "description": "The name of the catalog.", + "computed": true + }, + { + "name": "permit_request_ibm_public_publish", + "type": "TypeBool", + "description": "Is it permitted to request publishing to IBM or Public.", + "computed": true + }, + { + "name": "public_publish_approved", + "type": "TypeBool", + "description": "Indicates if this offering has been approved for use by all IBM Cloud users.", + "computed": true + }, + { + "name": "publish_public_crn", + "type": "TypeString", + "description": "The crn of the public catalog entry of this offering.", + "computed": true + }, + { + "name": "offering_id", + "type": "TypeString", + "description": "The id of the catalog containing this offering.", + "immutable": true, + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn for this specific offering.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The programmatic name of this offering.", + "computed": true + }, + { + "name": "offering_icon_url", + "type": "TypeString", + "description": "URL for an icon associated with this offering.", + "computed": true + }, + { + "name": "offering_support_url", + "type": "TypeString", + "description": "URL to be displayed in the Consumption UI for getting support on this offering.", + "computed": true + }, + { + "name": "portal_approval_record", + "type": "TypeString", + "description": "The portal's approval record ID.", + "computed": true + }, + { + "name": "portal_ui_url", + "type": "TypeString", + "description": "The portal UI URL.", + "computed": true + }, + { + "name": "repo_info", + "type": "TypeList", + "description": "Repository info for offerings.", + "computed": true, + "elem": { + "token": { + "name": "token", + "type": "TypeString", + "description": "Token for private repos.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Public or enterprise GitHub.", + "computed": true + } + } + }, + { + "name": "public_original_crn", + "type": "TypeString", + "description": "The original offering CRN that this publish entry came from.", + "computed": true + }, + { + "name": "hidden", + "type": "TypeBool", + "description": "Determine if this offering should be displayed in the Consumption UI.", + "computed": true + } + ], + "ibm_cm_offering_instance": [ + { + "name": "cluster_region", + "type": "TypeString", + "description": "Cluster region (e.g., us-south).", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "id of the resource group", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "channel", + "type": "TypeString", + "description": "channel to target for the operator subscription. Required for operator bundles", + "computed": true + }, + { + "name": "instance_identifier", + "type": "TypeString", + "description": "ID for this instance", + "required": true + }, + { + "name": "offering_id", + "type": "TypeString", + "description": "Offering ID this instance was created from.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "platform CRN for this instance.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "The version this instance was installed from (not version id).", + "computed": true + }, + { + "name": "kind_format", + "type": "TypeString", + "description": "the format this instance has (helm, operator, ova...).", + "computed": true + }, + { + "name": "cluster_all_namespaces", + "type": "TypeBool", + "description": "designate to install into all namespaces.", + "computed": true + }, + { + "name": "url", + "type": "TypeString", + "description": "url reference to this object.", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "the label for this instance.", + "computed": true + }, + { + "name": "cluster_id", + "type": "TypeString", + "description": "Cluster ID.", + "computed": true + }, + { + "name": "cluster_namespaces", + "type": "TypeList", + "description": "List of target namespaces to install into.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "schematics_workspace_id", + "type": "TypeString", + "description": "id of the schematics workspace, for offerings installed through schematics", + "computed": true + }, + { + "name": "install_plan", + "type": "TypeString", + "description": "install plan for the subscription of the operator- can be either Automatic or Manual. Required for operator bundles", + "computed": true + }, + { + "name": "_rev", + "type": "TypeString", + "description": "Cloudant Revision for this instance", + "computed": true + }, + { + "name": "catalog_id", + "type": "TypeString", + "description": "Catalog ID this instance was created from.", + "computed": true + } + ], + "ibm_cm_version": [ + { + "name": "crn", + "type": "TypeString", + "description": "Version's CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Version of content type.", + "computed": true + }, + { + "name": "sha", + "type": "TypeString", + "description": "hash of the content.", + "computed": true + }, + { + "name": "catalog_id", + "type": "TypeString", + "description": "Catalog ID.", + "computed": true + }, + { + "name": "repo_url", + "type": "TypeString", + "description": "Content's repo URL.", + "computed": true + }, + { + "name": "source_url", + "type": "TypeString", + "description": "Content's source URL (e.g git repo).", + "computed": true + }, + { + "name": "tgz_url", + "type": "TypeString", + "description": "File used to on-board this version.", + "computed": true + }, + { + "name": "version_loc_id", + "type": "TypeString", + "description": "Catalog identifier.", + "immutable": true, + "required": true + } + ], + "ibm_compute_bare_metal": [ + { + "name": "public_ipv4_address", + "type": "TypeString", + "description": "The public IPv4 address of the bare metal server.", + "computed": true + }, + { + "name": "user_metadata", + "type": "TypeString", + "description": "Arbitrary data available to the computing server.", + "computed": true + }, + { + "name": "os_reference_code", + "type": "TypeString", + "computed": true + }, + { + "name": "public_bandwidth", + "type": "TypeInt", + "description": "The amount of public network traffic, allowed per month.", + "computed": true + }, + { + "name": "private_ipv4_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory in gigabytes, for the server.", + "computed": true + }, + { + "name": "block_storage_ids", + "type": "TypeSet", + "description": "Block storage to which this computing server have access.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "file_storage_ids", + "type": "TypeSet", + "description": "File storage to which this computing server have access.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "public_ipv4_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "description": "The private VLAN used for the private network interface of the server.", + "computed": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "Notes associated with the server.", + "computed": true + }, + { + "name": "ipv6_address", + "type": "TypeString", + "description": "The public IPv6 address of the bare metal server", + "computed": true + }, + { + "name": "private_ipv4_address", + "type": "TypeString", + "description": "The private IPv4 address of the bare metal server.", + "computed": true + }, + { + "name": "secondary_ip_count", + "type": "TypeInt", + "description": "The number of secondary IPv4 addresses of the bare metal server.", + "computed": true + }, + { + "name": "private_subnet", + "type": "TypeInt", + "description": "The private subnet used for the private network interface of the server.", + "computed": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "description": "The public VLAN used for the public network interface of the server.", + "computed": true + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "description": "The billing type of the server.", + "computed": true + }, + { + "name": "ipv6_enabled", + "type": "TypeBool", + "description": "Indicates whether the public IPv6 address enabled or not", + "computed": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter in which the bare metal is deployed", + "computed": true + }, + { + "name": "redundant_power_supply", + "type": "TypeBool", + "description": "When the value is `true`, it indicates additional power supply is provided.", + "computed": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created bare metal is used. If false, an error is returned", + "default_value": false, + "optional": true + }, + { + "name": "public_subnet", + "type": "TypeInt", + "description": "The public subnet used for the public network interface of the server.", + "computed": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "The domain of the bare metal server", + "optional": true, + "computed": true + }, + { + "name": "private_network_only", + "type": "TypeBool", + "description": "Specifies whether the server only has access to the private network.", + "computed": true + }, + { + "name": "redundant_network", + "type": "TypeBool", + "description": "When the value is `true`, two physical network interfaces are provided with a bonding configuration.", + "computed": true + }, + { + "name": "unbonded_network", + "type": "TypeBool", + "description": "When the value is `true`, two physical network interfaces are provided without a bonding configuration.", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "The hostname of the bare metal server", + "optional": true, + "computed": true + }, + { + "name": "network_speed", + "type": "TypeInt", + "description": "The connection speed, expressed in Mbps, for the server network components.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Tags associated with this bare metal server.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "ipv6_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "secondary_ip_addresses", + "type": "TypeList", + "description": "The public secondary IPv4 addresses of the bare metal server.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "global_identifier", + "type": "TypeString", + "description": "The unique global identifier of the bare metal server", + "optional": true, + "computed": true + } + ], + "ibm_compute_image_template": [ + { + "name": "id", + "type": "TypeInt", + "description": "The internal id of the image template", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of this image template", + "required": true + } + ], + "ibm_compute_placement_group": [ + { + "name": "name", + "type": "TypeString", + "required": true + }, + { + "name": "datacenter", + "type": "TypeString", + "computed": true + }, + { + "name": "pod", + "type": "TypeString", + "computed": true + }, + { + "name": "rule", + "type": "TypeString", + "computed": true + }, + { + "name": "virtual_guests", + "type": "TypeList", + "computed": true, + "elem": { + "domain": { + "name": "domain", + "type": "TypeString", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + } + } + } + ], + "ibm_compute_reserved_capacity": [ + { + "name": "pod", + "type": "TypeString", + "description": "Pod name", + "computed": true + }, + { + "name": "instances", + "type": "TypeInt", + "description": "no of the instances", + "computed": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "flavor of the reserved capacity", + "computed": true + }, + { + "name": "virtual_guests", + "type": "TypeList", + "computed": true, + "elem": { + "domain": { + "name": "domain", + "type": "TypeString", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of reserved instance", + "required": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created reserved capacity is used. If false, an error is returned", + "default_value": false, + "optional": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Dataceneter name", + "computed": true + } + ], + "ibm_compute_ssh_key": [ + { + "name": "label", + "type": "TypeString", + "description": "The label associated with the ssh key", + "required": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "The public ssh key", + "computed": true + }, + { + "name": "fingerprint", + "type": "TypeString", + "description": "A sequence of bytes to authenticate or lookup a longer ssh key", + "computed": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "A small note about a ssh key to use at your discretion", + "computed": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created key is used. If false, an error is returned", + "default_value": false, + "optional": true + } + ], + "ibm_compute_vm_instance": [ + { + "name": "ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "ipv4_address_private", + "type": "TypeString", + "computed": true + }, + { + "name": "ip_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "cores", + "type": "TypeInt", + "description": "Number of cpu cores", + "computed": true + }, + { + "name": "last_known_power_state", + "type": "TypeString", + "description": "The last known power state of a virtual guest in the event the guest is turned off outside of IMS or has gone offline.", + "computed": true + }, + { + "name": "public_interface_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created virtual guest is used. If false, an error is returned", + "default_value": false, + "optional": true + }, + { + "name": "private_subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "secondary_ip_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "secondary_ip_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter in which the virtual guest is deployed", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The VSI status", + "computed": true + }, + { + "name": "ipv6_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_ipv6_subnet", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ipv6_subnet_id", + "type": "TypeString", + "computed": true + }, + { + "name": "ipv6_address", + "type": "TypeString", + "computed": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "The domain of the virtual guest", + "required": true + }, + { + "name": "private_interface_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "power_state", + "type": "TypeString", + "description": "The current power state of a virtual guest.", + "computed": true + }, + { + "name": "public_subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "ip_address_id_private", + "type": "TypeInt", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "The hostname of the virtual guest", + "required": true + } + ], + "ibm_container_addons": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "addons", + "type": "TypeList", + "description": "The List of AddOns", + "computed": true, + "elem": { + "allowed_upgrade_versions": { + "name": "allowed_upgrade_versions", + "type": "TypeList", + "description": "The versions that the addon can be upgraded to", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "deprecated": { + "name": "deprecated", + "type": "TypeBool", + "description": "Determines if this addon version is deprecated", + "computed": true + }, + "health_state": { + "name": "health_state", + "type": "TypeString", + "description": "The health state for this addon, a short indication (e.g. critical, pending)", + "computed": true + }, + "health_status": { + "name": "health_status", + "type": "TypeString", + "description": "The health status for this addon, provides a description of the state (e.g. error message)", + "computed": true + }, + "min_kube_version": { + "name": "min_kube_version", + "type": "TypeString", + "description": "The minimum kubernetes version for this addon.", + "computed": true + }, + "min_ocp_version": { + "name": "min_ocp_version", + "type": "TypeString", + "description": "The minimum OpenShift version for this addon.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The addon name such as 'istio'.", + "computed": true + }, + "supported_kube_range": { + "name": "supported_kube_range", + "type": "TypeString", + "description": "The supported kubernetes version range for this addon.", + "computed": true + }, + "target_version": { + "name": "target_version", + "type": "TypeString", + "description": "The addon target version.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "description": "The addon version, omit the version if you wish to use the default version.", + "computed": true + }, + "vlan_spanning_required": { + "name": "vlan_spanning_required", + "type": "TypeBool", + "description": "VLAN spanning required for multi-zone clusters", + "computed": true + } + } + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster Name or ID", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + } + ], + "ibm_container_alb": [ + { + "name": "alb_id", + "type": "TypeString", + "description": "ALB ID", + "required": true + }, + { + "name": "alb_type", + "type": "TypeString", + "description": "ALB type", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster id", + "computed": true + }, + { + "name": "user_ip", + "type": "TypeString", + "description": "IP assigned by the user", + "computed": true + }, + { + "name": "enable", + "type": "TypeBool", + "description": "set to true if ALB needs to be enabled", + "computed": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "description": "Set to true if ALB needs to be disabled", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "ALB name", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "ALB zone", + "computed": true + } + ], + "ibm_container_alb_cert": [ + { + "name": "cert_crn", + "type": "TypeString", + "description": "Certificate CRN id", + "computed": true + }, + { + "name": "cluster_id", + "type": "TypeString", + "description": "Cluster ID", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Namespace of the secret", + "default_value": "ibm-cert-store", + "optional": true + }, + { + "name": "persistence", + "type": "TypeBool", + "description": "Persistence of secret", + "computed": true + }, + { + "name": "domain_name", + "type": "TypeString", + "description": "Domain name", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeString", + "description": "Certificate expaire on date", + "computed": true + }, + { + "name": "cloud_cert_instance_id", + "type": "TypeString", + "description": "cloud cert instance ID", + "computed": true + }, + { + "name": "secret_name", + "type": "TypeString", + "description": "Secret name", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Secret Status", + "computed": true + }, + { + "name": "issuer_name", + "type": "TypeString", + "description": "certificate issuer name", + "computed": true, + "deprecated": "This field is depricated and is not available in v2 version of ingress api" + }, + { + "name": "cluster_crn", + "type": "TypeString", + "description": "cluster CRN", + "computed": true, + "deprecated": "This field is depricated and is not available in v2 version of ingress api" + } + ], + "ibm_container_bind_service": [ + { + "name": "namespace_id", + "type": "TypeString", + "description": "namespace ID", + "required": true + }, + { + "name": "service_key_name", + "type": "TypeString", + "description": "Key info", + "computed": true + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "Cluster name or ID", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "service_instance_id", + "type": "TypeString", + "description": "Service instance ID", + "optional": true, + "computed": true + }, + { + "name": "service_instance_name", + "type": "TypeString", + "description": "serivice instance name", + "optional": true, + "computed": true + } + ], + "ibm_container_cluster": [ + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "bounded_services", + "type": "TypeSet", + "computed": true, + "elem": { + "namespace": { + "name": "namespace", + "type": "TypeString", + "computed": true + }, + "service_id": { + "name": "service_id", + "type": "TypeString", + "computed": true + }, + "service_key_name": { + "name": "service_key_name", + "type": "TypeString", + "computed": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "albs", + "type": "TypeList", + "computed": true, + "elem": { + "alb_ip": { + "name": "alb_ip", + "type": "TypeString", + "computed": true + }, + "alb_type": { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + "disable_deployment": { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "num_of_instances": { + "name": "num_of_instances", + "type": "TypeString", + "computed": true + }, + "resize": { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "list_bounded_services", + "type": "TypeBool", + "description": "If set to false bounded services won't be listed.", + "default_value": true, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name or id of the cluster", + "cloud_data_type": "cluster", + "optional": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "image_security_enforcement", + "type": "TypeBool", + "description": "True if image security enforcement is enabled", + "computed": true + }, + { + "name": "is_trusted", + "type": "TypeBool", + "computed": true + }, + { + "name": "server_url", + "type": "TypeString", + "computed": true + }, + { + "name": "vlans", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "cidr": { + "name": "cidr", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "ips": { + "name": "ips", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "is_byoip": { + "name": "is_byoip", + "type": "TypeBool", + "computed": true + }, + "is_public": { + "name": "is_public", + "type": "TypeBool", + "computed": true + } + } + } + } + }, + { + "name": "alb_type", + "type": "TypeString", + "default_value": "all", + "optional": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of workers", + "computed": true + }, + { + "name": "worker_pools", + "type": "TypeList", + "computed": true, + "elem": { + "hardware": { + "name": "hardware", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "labels": { + "name": "labels", + "type": "TypeMap", + "computed": true + }, + "machine_type": { + "name": "machine_type", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "size_per_zone": { + "name": "size_per_zone", + "type": "TypeInt", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "zones": { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "private_vlan": { + "name": "private_vlan", + "type": "TypeString", + "computed": true + }, + "public_vlan": { + "name": "public_vlan", + "type": "TypeString", + "computed": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "public_service_endpoint", + "type": "TypeBool", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "api_key_owner_name", + "type": "TypeString", + "description": "Name of the key owner", + "computed": true + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "api_key_id", + "type": "TypeString", + "description": "ID of APIkey", + "computed": true + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "Name or id of the cluster", + "optional": true, + "deprecated": "use name instead" + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "api_key_owner_email", + "type": "TypeString", + "description": "email id of the key owner", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "workers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "private_service_endpoint", + "type": "TypeBool", + "computed": true + } + ], + "ibm_container_cluster_config": [ + { + "name": "admin_key", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "host", + "type": "TypeString", + "computed": true + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "download", + "type": "TypeBool", + "description": "If set to false will not download the config, otherwise they are downloaded each time but onto the same path for a given cluster name/id", + "default_value": true, + "optional": true + }, + { + "name": "admin", + "type": "TypeBool", + "description": "If set to true will download the config for admin", + "default_value": false, + "optional": true + }, + { + "name": "network", + "type": "TypeBool", + "description": "If set to true will download the Calico network config with the Admin config", + "default_value": false, + "optional": true + }, + { + "name": "calico_config_file_path", + "type": "TypeString", + "description": "The absolute path to the calico network config file", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "config_file_path", + "type": "TypeString", + "description": "The absolute path to the kubernetes config yml file", + "computed": true + }, + { + "name": "ca_certificate", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "config_dir", + "type": "TypeString", + "description": "The directory where the cluster config to be downloaded. Default is home directory", + "optional": true, + "computed": true + }, + { + "name": "token", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "The name/id of the cluster", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "admin_certificate", + "type": "TypeString", + "secure": true, + "computed": true + } + ], + "ibm_container_cluster_versions": [ + { + "name": "valid_kube_versions", + "type": "TypeList", + "description": "List supported kube-versions", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "valid_openshift_versions", + "type": "TypeList", + "description": "List of supported openshift-versions", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + } + ], + "ibm_container_cluster_worker": [ + { + "name": "private_ip", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ip", + "type": "TypeString", + "computed": true + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the worker", + "computed": true + }, + { + "name": "private_vlan", + "type": "TypeString", + "computed": true + }, + { + "name": "public_vlan", + "type": "TypeString", + "computed": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "worker_id", + "type": "TypeString", + "description": "ID of the worker", + "required": true + }, + { + "name": "state", + "type": "TypeString", + "description": "State of the worker", + "computed": true + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + } + ], + "ibm_container_dedicated_host": [ + { + "name": "host_pool_id", + "type": "TypeString", + "description": "The id of the dedicated host pool the dedicated host is associated with", + "required": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "The flavor of the dedicated host", + "computed": true + }, + { + "name": "placement_enabled", + "type": "TypeBool", + "description": "Describes if the placement on the dedicated host is enabled", + "computed": true + }, + { + "name": "life_cycle", + "type": "TypeList", + "computed": true, + "elem": { + "actual_state": { + "name": "actual_state", + "type": "TypeString", + "computed": true + }, + "desired_state": { + "name": "desired_state", + "type": "TypeString", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "computed": true + }, + "message_date": { + "name": "message_date", + "type": "TypeString", + "computed": true + }, + "message_details": { + "name": "message_details", + "type": "TypeString", + "computed": true + }, + "message_details_date": { + "name": "message_details_date", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "resources", + "type": "TypeList", + "description": "The resources of the dedicated host", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + }, + "consumed": { + "name": "consumed", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + } + } + }, + { + "name": "workers", + "type": "TypeList", + "description": "The workers of the dedicated host", + "computed": true, + "elem": { + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "computed": true + }, + "flavor": { + "name": "flavor", + "type": "TypeString", + "computed": true + }, + "worker_id": { + "name": "worker_id", + "type": "TypeString", + "computed": true + }, + "worker_pool_id": { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone of the dedicated host", + "computed": true + }, + { + "name": "host_id", + "type": "TypeString", + "description": "The id of the dedicated host", + "required": true + } + ], + "ibm_container_dedicated_host_flavor": [ + { + "name": "flavor_class", + "type": "TypeString", + "description": "The class of the dedicated host flavor", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the dedicated host flavor", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "deprecated", + "type": "TypeBool", + "description": "Describes if the dedicated host flavor is deprecated", + "computed": true + }, + { + "name": "max_vcpus", + "type": "TypeInt", + "description": "The maximum available vcpus in the dedicated host flavor", + "computed": true + }, + { + "name": "max_memory", + "type": "TypeInt", + "description": "The maximum available memory in the dedicated host flavor", + "computed": true + }, + { + "name": "instance_storage", + "type": "TypeList", + "description": "The instance storage of the dedicated host flavor", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone of the dedicated host flavor", + "required": true + }, + { + "name": "host_flavor_id", + "type": "TypeString", + "description": "The id of the dedicated host flavor", + "required": true + } + ], + "ibm_container_dedicated_host_flavors": [ + { + "name": "zone", + "type": "TypeString", + "description": "The zone of the dedicated host flavors", + "required": true + }, + { + "name": "host_flavors", + "type": "TypeList", + "computed": true, + "elem": { + "deprecated": { + "name": "deprecated", + "type": "TypeBool", + "description": "Describes if the dedicated host flavor is deprecated", + "computed": true + }, + "flavor_class": { + "name": "flavor_class", + "type": "TypeString", + "description": "The class of the dedicated host flavor", + "computed": true + }, + "host_flavor_id": { + "name": "host_flavor_id", + "type": "TypeString", + "description": "The id of the dedicated host flavor", + "computed": true + }, + "instance_storage": { + "name": "instance_storage", + "type": "TypeList", + "description": "The instance storage of the dedicated host flavor", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "computed": true + } + } + }, + "max_memory": { + "name": "max_memory", + "type": "TypeInt", + "description": "The maximum available memory in the dedicated host flavor", + "computed": true + }, + "max_vcpus": { + "name": "max_vcpus", + "type": "TypeInt", + "description": "The maximum available vcpus in the dedicated host flavor", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "The region of the dedicated host flavor", + "computed": true + } + } + } + ], + "ibm_container_dedicated_host_pool": [ + { + "name": "metro", + "type": "TypeString", + "description": "The metro to create the dedicated host pool in", + "computed": true + }, + { + "name": "flavor_class", + "type": "TypeString", + "description": "The flavor class of the dedicated host pool", + "computed": true + }, + { + "name": "host_count", + "type": "TypeInt", + "description": "The count of the hosts under the dedicated host pool", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the dedicated host pool", + "computed": true + }, + { + "name": "zones", + "type": "TypeList", + "description": "The zones of the dedicated host pool", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + }, + "host_count": { + "name": "host_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "worker_pools", + "type": "TypeList", + "description": "The worker pools of the dedicated host pool", + "computed": true, + "elem": { + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "computed": true + }, + "worker_pool_id": { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "host_pool_id", + "type": "TypeString", + "description": "The id of the dedicated host pool", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the dedicated host pool", + "computed": true + } + ], + "ibm_container_nlb_dns": [ + { + "name": "cluster", + "type": "TypeString", + "description": "A unique name of the cluster", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "nlb_config", + "type": "TypeList", + "description": "List of nlb config of cluster", + "computed": true, + "elem": { + "cluster": { + "name": "cluster", + "type": "TypeString", + "description": "Cluster Id.", + "computed": true + }, + "dns_type": { + "name": "dns_type", + "type": "TypeString", + "description": "Type of DNS.", + "computed": true + }, + "lb_hostname": { + "name": "lb_hostname", + "type": "TypeString", + "description": "Host Name of load Balancer.", + "computed": true + }, + "nlb_ips": { + "name": "nlb_ips", + "type": "TypeList", + "description": "NLB IPs.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "nlb_sub_domain": { + "name": "nlb_sub_domain", + "type": "TypeString", + "description": "NLB Sub-Domain.", + "computed": true + }, + "secret_name": { + "name": "secret_name", + "type": "TypeString", + "description": "Name of the secret.", + "computed": true + }, + "secret_namespace": { + "name": "secret_namespace", + "type": "TypeString", + "description": "Namespace of Secret.", + "computed": true + }, + "secret_status": { + "name": "secret_status", + "type": "TypeString", + "description": "Status of Secret.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Nlb Type.", + "computed": true + } + } + } + ], + "ibm_container_storage_attachment": [ + { + "name": "volume_attachment_name", + "type": "TypeString", + "description": "Volume attachment name", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Volume attachment status", + "computed": true + }, + { + "name": "volume_type", + "type": "TypeString", + "description": "The type of volume", + "computed": true + }, + { + "name": "volume_attachment_id", + "type": "TypeString", + "description": "The volume attachment ID", + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name or ID", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker", + "type": "TypeString", + "description": "Worker node ID", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "volume", + "type": "TypeString", + "description": "Volume ID", + "computed": true + } + ], + "ibm_container_vpc_alb": [ + { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + { + "name": "load_balancer_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "alb_id", + "type": "TypeString", + "description": "ALB ID", + "required": true + }, + { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "computed": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + } + ], + "ibm_container_vpc_cluster": [ + { + "name": "public_service_endpoint", + "type": "TypeBool", + "computed": true + }, + { + "name": "image_security_enforcement", + "type": "TypeBool", + "description": "True if image security enforcement is enabled", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "private_service_endpoint", + "type": "TypeBool", + "computed": true + }, + { + "name": "api_key_owner_email", + "type": "TypeString", + "description": "email id of the key owner", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "pod_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for pods", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "albs", + "type": "TypeList", + "computed": true, + "elem": { + "alb_type": { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + "disable_deployment": { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "load_balancer_hostname": { + "name": "load_balancer_hostname", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "resize": { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name or id of the cluster", + "cloud_data_type": "cluster", + "optional": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the cluster master", + "computed": true + }, + { + "name": "health", + "type": "TypeString", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "Name or id of the cluster", + "optional": true, + "deprecated": "use name instead" + }, + { + "name": "workers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "worker_pools", + "type": "TypeList", + "computed": true, + "elem": { + "flavor": { + "name": "flavor", + "type": "TypeString", + "computed": true + }, + "host_pool_id": { + "name": "host_pool_id", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "isolation": { + "name": "isolation", + "type": "TypeString", + "computed": true + }, + "labels": { + "name": "labels", + "type": "TypeMap", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zones": { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "subnets": { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "primary": { + "name": "primary", + "type": "TypeBool", + "computed": true + } + } + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "alb_type", + "type": "TypeString", + "default_value": "all", + "optional": true + }, + { + "name": "master_url", + "type": "TypeString", + "computed": true + }, + { + "name": "api_key_owner_name", + "type": "TypeString", + "description": "Name of the key owner", + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of workers", + "computed": true + }, + { + "name": "service_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for services", + "computed": true + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "api_key_id", + "type": "TypeString", + "description": "ID of APIkey", + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "kube_version", + "type": "TypeString", + "computed": true + } + ], + "ibm_container_vpc_cluster_alb": [ + { + "name": "cluster", + "type": "TypeString", + "computed": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + { + "name": "load_balancer_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "alb_id", + "type": "TypeString", + "description": "ALB ID", + "required": true + } + ], + "ibm_container_vpc_cluster_worker": [ + { + "name": "pool_name", + "type": "TypeString", + "description": "worker pool name", + "computed": true + }, + { + "name": "network_interfaces", + "type": "TypeList", + "computed": true, + "elem": { + "cidr": { + "name": "cidr", + "type": "TypeString", + "computed": true + }, + "ip_address": { + "name": "ip_address", + "type": "TypeString", + "computed": true + }, + "subnet_id": { + "name": "subnet_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "host_pool_id", + "type": "TypeString", + "description": "ID of the dedicated host pool this worker is associated with", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "worker_id", + "type": "TypeString", + "description": "ID of the worker", + "required": true + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "Name or ID of the cluster", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "flavor", + "type": "TypeString", + "description": "flavor of the worker", + "computed": true + }, + { + "name": "kube_version", + "type": "TypeString", + "description": "kube version of the worker", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "State of the worker", + "computed": true + }, + { + "name": "pool_id", + "type": "TypeString", + "description": "worker pool id", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + } + ], + "ibm_container_vpc_cluster_worker_pool": [ + { + "name": "kms_instance_id", + "type": "TypeString", + "computed": true + }, + { + "name": "flavor", + "type": "TypeString", + "computed": true + }, + { + "name": "zones", + "type": "TypeSet", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "subnet_id": { + "name": "subnet_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "vpc_id", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "isolation", + "type": "TypeString", + "computed": true + }, + { + "name": "host_pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "crk", + "type": "TypeString", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker_pool_name", + "type": "TypeString", + "description": "worker pool name", + "required": true + }, + { + "name": "labels", + "type": "TypeMap", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_container_vpc_worker_pool": [ + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name", + "required": true + }, + { + "name": "worker_pool_name", + "type": "TypeString", + "description": "worker pool name", + "required": true + }, + { + "name": "labels", + "type": "TypeMap", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "vpc_id", + "type": "TypeString", + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "isolation", + "type": "TypeString", + "computed": true + }, + { + "name": "host_pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "kms_instance_id", + "type": "TypeString", + "computed": true + }, + { + "name": "crk", + "type": "TypeString", + "computed": true + }, + { + "name": "flavor", + "type": "TypeString", + "computed": true + }, + { + "name": "zones", + "type": "TypeSet", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "subnet_id": { + "name": "subnet_id", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_container_worker_pool": [ + { + "name": "size_per_zone", + "type": "TypeInt", + "description": "Number of nodes per zone", + "computed": true + }, + { + "name": "disk_encryption", + "type": "TypeBool", + "description": "worker node disk encrypted if set to true", + "computed": true + }, + { + "name": "labels", + "type": "TypeMap", + "description": "list of labels to worker pool", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Name or ID of the cluster", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "machine_type", + "type": "TypeString", + "description": "worker nodes machine type", + "computed": true + }, + { + "name": "hardware", + "type": "TypeString", + "description": "Hardware type", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "worker pool state", + "computed": true + }, + { + "name": "zones", + "type": "TypeList", + "description": "worker pool zones", + "computed": true, + "elem": { + "private_vlan": { + "name": "private_vlan", + "type": "TypeString", + "description": "worker pool zone private vlan", + "computed": true + }, + "public_vlan": { + "name": "public_vlan", + "type": "TypeString", + "description": "worker pool zone public vlan", + "computed": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "description": "worker pool zone worker count", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "worker pool zone name", + "computed": true + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "worker_pool_name", + "type": "TypeString", + "description": "worker pool name", + "required": true + } + ], + "ibm_cos_bucket": [ + { + "name": "s3_endpoint_direct", + "type": "TypeString", + "description": "Direct endpoint for the COS bucket", + "computed": true + }, + { + "name": "metrics_monitoring", + "type": "TypeList", + "computed": true, + "elem": { + "metrics_monitoring_crn": { + "name": "metrics_monitoring_crn", + "type": "TypeString", + "description": "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", + "computed": true + }, + "request_metrics_enabled": { + "name": "request_metrics_enabled", + "type": "TypeBool", + "description": "Request metrics will be sent to the monitoring service.", + "computed": true + }, + "usage_metrics_enabled": { + "name": "usage_metrics_enabled", + "type": "TypeBool", + "description": "Usage metrics will be sent to the monitoring service.", + "computed": true + } + } + }, + { + "name": "archive_rule", + "type": "TypeList", + "description": "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", + "computed": true, + "elem": { + "days": { + "name": "days", + "type": "TypeInt", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an archive rule for a bucket", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "object_versioning", + "type": "TypeList", + "description": "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", + "computed": true, + "elem": { + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or suspend the versioning for objects in the bucket", + "computed": true + } + } + }, + { + "name": "bucket_name", + "type": "TypeString", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "s3_endpoint_private", + "type": "TypeString", + "description": "Private endpoint for the COS bucket", + "computed": true + }, + { + "name": "noncurrent_version_expiration", + "type": "TypeList", + "description": "Enable configuration expire_rule to COS Bucket after a defined period of time", + "computed": true, + "elem": { + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an expire rule for a bucket", + "computed": true + }, + "noncurrent_days": { + "name": "noncurrent_days", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + "computed": true + } + } + }, + { + "name": "bucket_region", + "type": "TypeString", + "optional": true + }, + { + "name": "storage_class", + "type": "TypeString", + "computed": true + }, + { + "name": "s3_endpoint_public", + "type": "TypeString", + "description": "Public endpoint for the COS bucket", + "computed": true + }, + { + "name": "region_location", + "type": "TypeString", + "computed": true + }, + { + "name": "cross_region_location", + "type": "TypeString", + "computed": true + }, + { + "name": "allowed_ip", + "type": "TypeList", + "description": "List of IPv4 or IPv6 addresses", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "activity_tracking", + "type": "TypeList", + "computed": true, + "elem": { + "activity_tracker_crn": { + "name": "activity_tracker_crn", + "type": "TypeString", + "description": "The instance of Activity Tracker that will receive object event data", + "computed": true + }, + "read_data_events": { + "name": "read_data_events", + "type": "TypeBool", + "description": "If set to true, all object read events will be sent to Activity Tracker.", + "computed": true + }, + "write_data_events": { + "name": "write_data_events", + "type": "TypeBool", + "description": "If set to true, all object write events will be sent to Activity Tracker.", + "computed": true + } + } + }, + { + "name": "expire_rule", + "type": "TypeList", + "description": "Enable configuration expire_rule to COS Bucket", + "computed": true, + "elem": { + "date": { + "name": "date", + "type": "TypeString", + "description": "Specifies the date when the specific rule action takes effect.", + "computed": true + }, + "days": { + "name": "days", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an archive rule for a bucket", + "computed": true + }, + "expired_object_delete_marker": { + "name": "expired_object_delete_marker", + "type": "TypeBool", + "description": "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "bucket_type", + "type": "TypeString", + "options": "single_site_location,region_location,cross_region_location", + "optional": true + }, + { + "name": "satellite_location_id", + "type": "TypeString", + "optional": true + }, + { + "name": "single_site_location", + "type": "TypeString", + "computed": true + }, + { + "name": "retention_rule", + "type": "TypeList", + "description": "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "If an object is stored in the bucket without specifying a custom retention period.", + "computed": true + }, + "maximum": { + "name": "maximum", + "type": "TypeInt", + "description": "Maximum duration of time an object can be kept unmodified in the bucket.", + "computed": true + }, + "minimum": { + "name": "minimum", + "type": "TypeInt", + "description": "Minimum duration of time an object must be kept unmodified in the bucket", + "computed": true + }, + "permanent": { + "name": "permanent", + "type": "TypeBool", + "description": "Enable or disable the permanent retention policy on the bucket", + "computed": true + } + } + }, + { + "name": "replication_rule", + "type": "TypeList", + "description": "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + "computed": true, + "elem": { + "deletemarker_replication_status": { + "name": "deletemarker_replication_status", + "type": "TypeBool", + "description": "Indicates whether to replicate delete markers. It should be either Enable or Disable", + "computed": true + }, + "destination_bucket_crn": { + "name": "destination_bucket_crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an replication rule for a bucket", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "A unique identifier for the rule. The maximum value is 255 characters.", + "computed": true + } + } + }, + { + "name": "hard_quota", + "type": "TypeInt", + "description": "sets a maximum amount of storage (in bytes) available for a bucket", + "computed": true + }, + { + "name": "abort_incomplete_multipart_upload_days", + "type": "TypeList", + "computed": true, + "elem": { + "days_after_initiation": { + "name": "days_after_initiation", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable rule for a bucket", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + "computed": true + } + } + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:cloud-object-storage" + ] + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "options": "public,private,direct", + "optional": true + }, + { + "name": "key_protect", + "type": "TypeString", + "description": "CRN of the key you want to use data at rest encryption", + "computed": true + } + ], + "ibm_cos_bucket_object": [ + { + "name": "body", + "type": "TypeString", + "description": "COS object body", + "computed": true + }, + { + "name": "bucket_crn", + "type": "TypeString", + "description": "COS bucket CRN", + "required": true + }, + { + "name": "content_length", + "type": "TypeInt", + "description": "COS object content length", + "computed": true + }, + { + "name": "content_type", + "type": "TypeString", + "description": "COS object content type", + "computed": true + }, + { + "name": "etag", + "type": "TypeString", + "description": "COS object MD5 hexdigest", + "computed": true + }, + { + "name": "key", + "type": "TypeString", + "description": "COS object key", + "required": true + }, + { + "name": "object_sql_url", + "type": "TypeString", + "computed": true + }, + { + "name": "bucket_location", + "type": "TypeString", + "description": "COS bucket location", + "required": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "COS endpoint type: public, private, direct", + "default_value": "public", + "optional": true + }, + { + "name": "last_modified", + "type": "TypeString", + "description": "COS object last modified date", + "computed": true + }, + { + "name": "version_id", + "type": "TypeString", + "computed": true + } + ], + "ibm_cr_namespaces": [ + { + "name": "namespaces", + "type": "TypeList", + "description": "Container Registry Namespaces", + "computed": true, + "elem": { + "account": { + "name": "account", + "type": "TypeString", + "description": "The IBM Cloud account that owns the namespace.", + "computed": true + }, + "created_date": { + "name": "created_date", + "type": "TypeString", + "description": "Created Date", + "computed": true + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Created Date", + "computed": true, + "deprecated": "This field is deprecated" + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "CRN of the Namespace", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Container Registry Namespace name", + "computed": true + }, + "resource_created_date": { + "name": "resource_created_date", + "type": "TypeString", + "description": "When the namespace was assigned to a resource group.", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource Group to which namespace has to be assigned", + "computed": true + }, + "updated_date": { + "name": "updated_date", + "type": "TypeString", + "description": "Updated Date", + "computed": true + }, + "updated_on": { + "name": "updated_on", + "type": "TypeString", + "description": "Updated Date", + "computed": true, + "deprecated": "This field is deprecated" + } + } + } + ], + "ibm_database": [ + { + "name": "groups", + "type": "TypeList", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "description": "Count of scaling groups for the instance", + "computed": true + }, + "cpu": { + "name": "cpu", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_count": { + "name": "allocation_count", + "type": "TypeInt", + "description": "The current cpu allocation count", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can the number of CPUs be scaled down as well as up", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Are the number of CPUs adjustable", + "computed": true + }, + "minimum_count": { + "name": "minimum_count", + "type": "TypeInt", + "description": "The minimum number of cpus allowed", + "computed": true + }, + "step_size_count": { + "name": "step_size_count", + "type": "TypeInt", + "description": "The number of CPUs allowed to step up or down by", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The .", + "computed": true + } + } + }, + "disk": { + "name": "disk", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "description": "The current disk allocation", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can the disk size be scaled down as well as up", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Is the disk size adjustable", + "computed": true + }, + "minimum_mb": { + "name": "minimum_mb", + "type": "TypeInt", + "description": "The minimum disk size allowed", + "computed": true + }, + "step_size_mb": { + "name": "step_size_mb", + "type": "TypeInt", + "description": "The step size disk increases or decreases in", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The units disk is allocated in", + "computed": true + } + } + }, + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "Scaling group name", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "description": "The current memory allocation for a group instance", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can memory scale down as well as up.", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Is the memory size adjustable.", + "computed": true + }, + "minimum_mb": { + "name": "minimum_mb", + "type": "TypeInt", + "description": "The minimum memory size for a group instance", + "computed": true + }, + "step_size_mb": { + "name": "step_size_mb", + "type": "TypeInt", + "description": "The step size memory increases or decreases in.", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The units memory is allocated in.", + "computed": true + } + } + } + } + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "adminpassword", + "type": "TypeString", + "description": "The admin user id for the instance", + "secure": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cert_file_path", + "type": "TypeString", + "description": "The absolute path to certificate PEM file", + "computed": true + }, + { + "name": "members_memory_allocation_mb", + "type": "TypeInt", + "description": "Memory allocation required for cluster", + "computed": true, + "deprecated": "This field is deprecated please use groups" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the Database instance is present", + "cloud_data_type": "resource_group", + "optional": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "guid", + "type": "TypeString", + "description": "Unique identifier of resource instance", + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the Cloud Database service", + "optional": true + }, + { + "name": "adminuser", + "type": "TypeString", + "description": "The admin user id for the instance", + "computed": true + }, + { + "name": "connectionstrings", + "type": "TypeList", + "computed": true, + "elem": { + "bundlebase64": { + "name": "bundlebase64", + "type": "TypeString", + "description": "Cassandra base64 encoding", + "computed": true + }, + "bundlename": { + "name": "bundlename", + "type": "TypeString", + "description": "Cassandra Bundle Name", + "computed": true + }, + "certbase64": { + "name": "certbase64", + "type": "TypeString", + "description": "Certificate in base64 encoding", + "computed": true + }, + "certname": { + "name": "certname", + "type": "TypeString", + "description": "Certificate Name", + "computed": true + }, + "composed": { + "name": "composed", + "type": "TypeString", + "description": "Connection string", + "computed": true + }, + "database": { + "name": "database", + "type": "TypeString", + "description": "DB name", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "optional": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "DB host name", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeString", + "description": "DB port", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "User name", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "DB path", + "computed": true + }, + "queryoptions": { + "name": "queryoptions", + "type": "TypeString", + "description": "DB query options", + "computed": true + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "DB scheme", + "computed": true + } + }, + "deprecated": "This field is deprecated, please use ibm_database_connection instead" + }, + { + "name": "auto_scaling", + "type": "TypeList", + "description": "ICD Auto Scaling", + "computed": true, + "elem": { + "cpu": { + "name": "cpu", + "type": "TypeList", + "description": "CPU Auto Scaling", + "computed": true, + "elem": { + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "computed": true + }, + "rate_limit_count_per_member": { + "name": "rate_limit_count_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit count per number", + "computed": true + }, + "rate_limit_mb_per_member": { + "name": "rate_limit_mb_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit mb per member", + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "computed": true + } + } + }, + "disk": { + "name": "disk", + "type": "TypeList", + "description": "Disk Auto Scaling", + "computed": true, + "elem": { + "capacity_enabled": { + "name": "capacity_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: Capacity Enabled", + "computed": true + }, + "free_space_less_than_percent": { + "name": "free_space_less_than_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: Capacity Free Space Less Than Percent", + "computed": true + }, + "free_space_remaining_percent": { + "name": "free_space_remaining_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: Capacity Free Space Remaining Percent", + "computed": true + }, + "io_above_percent": { + "name": "io_above_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: IO Utilization Above Percent", + "computed": true + }, + "io_enabled": { + "name": "io_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: IO Utilization Enabled", + "computed": true + }, + "io_over_period": { + "name": "io_over_period", + "type": "TypeString", + "description": "Auto Scaling Scalar: IO Utilization Over Period", + "computed": true + }, + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "computed": true + }, + "rate_limit_count_per_member": { + "name": "rate_limit_count_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit count per number", + "computed": true + }, + "rate_limit_mb_per_member": { + "name": "rate_limit_mb_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit mb per member", + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "computed": true + } + } + }, + "memory": { + "name": "memory", + "type": "TypeList", + "description": "Memory Auto Scaling", + "computed": true, + "elem": { + "io_above_percent": { + "name": "io_above_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: IO Utilization Above Percent", + "computed": true + }, + "io_enabled": { + "name": "io_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: IO Utilization Enabled", + "computed": true + }, + "io_over_period": { + "name": "io_over_period", + "type": "TypeString", + "description": "Auto Scaling Scalar: IO Utilization Over Period", + "computed": true + }, + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "computed": true + }, + "rate_limit_count_per_member": { + "name": "rate_limit_count_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit count per number", + "computed": true + }, + "rate_limit_mb_per_member": { + "name": "rate_limit_mb_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit mb per member", + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "computed": true + } + } + } + } + }, + { + "name": "configuration_schema", + "type": "TypeString", + "description": "The configuration schema in JSON format", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, my Database instance", + "cloud_data_type": "cloud-database", + "required": true, + "cloud_data_range": [ + "resolved_to:name" + ] + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the region in which the Database instance exists", + "cloud_data_type": "region", + "optional": true + }, + { + "name": "platform_options", + "type": "TypeSet", + "description": "Platform-specific options for this deployment.r", + "computed": true, + "elem": { + "backup_encryption_key_crn": { + "name": "backup_encryption_key_crn", + "type": "TypeString", + "description": "Backup encryption key crn", + "computed": true + }, + "disk_encryption_key_crn": { + "name": "disk_encryption_key_crn", + "type": "TypeString", + "description": "Disk encryption key crn", + "computed": true + }, + "key_protect_key_id": { + "name": "key_protect_key_id", + "type": "TypeString", + "description": "Key protect key id", + "computed": true, + "deprecated": "This field is deprecated and has been replaced by disk_encryption_key_crn" + } + } + }, + { + "name": "users", + "type": "TypeSet", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "User name", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "User password", + "secure": true, + "computed": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the Database instance", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "The database version to provision if specified", + "computed": true + }, + { + "name": "members_disk_allocation_mb", + "type": "TypeInt", + "description": "Disk allocation required for cluster", + "computed": true, + "deprecated": "This field is deprecated please use groups" + }, + { + "name": "whitelist", + "type": "TypeSet", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Whitelist IP address in CIDR notation", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Unique white list description", + "computed": true + } + } + } + ], + "ibm_database_backup": [ + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when this backup was created.", + "computed": true + }, + { + "name": "backup_id", + "type": "TypeString", + "description": "Backup ID.", + "required": true + }, + { + "name": "deployment_id", + "type": "TypeString", + "description": "ID of the deployment this backup relates to.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of backup.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of this backup.", + "computed": true + }, + { + "name": "is_downloadable", + "type": "TypeBool", + "description": "Is this backup available to download?.", + "computed": true + }, + { + "name": "is_restorable", + "type": "TypeBool", + "description": "Can this backup be used to restore an instance?.", + "computed": true + }, + { + "name": "download_link", + "type": "TypeString", + "description": "URI which is currently available for file downloading.", + "computed": true + } + ], + "ibm_database_backups": [ + { + "name": "deployment_id", + "type": "TypeString", + "description": "ID of the deployment this backup relates to.", + "cloud_data_type": "cloud-database", + "optional": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "backups", + "type": "TypeList", + "description": "An array of backups.", + "computed": true, + "elem": { + "backup_id": { + "name": "backup_id", + "type": "TypeString", + "description": "ID of this backup.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when this backup was created.", + "computed": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "TypeString", + "description": "ID of the deployment this backup relates to.", + "computed": true + }, + "download_link": { + "name": "download_link", + "type": "TypeString", + "description": "URI which is currently available for file downloading.", + "computed": true + }, + "is_downloadable": { + "name": "is_downloadable", + "type": "TypeBool", + "description": "Is this backup available to download?.", + "computed": true + }, + "is_restorable": { + "name": "is_restorable", + "type": "TypeBool", + "description": "Can this backup be used to restore an instance?.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of this backup.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of backup.", + "computed": true + } + } + } + ], + "ibm_database_connection": [ + { + "name": "postgres", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "database": { + "name": "database", + "type": "TypeString", + "description": "Name of the database to use in the URI connection.", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "mqtts", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "grpc", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "mysql", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "database": { + "name": "database", + "type": "TypeString", + "description": "Name of the database to use in the URI connection.", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "deployment_id", + "type": "TypeString", + "description": "Deployment ID.", + "cloud_data_type": "cloud-database", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "cli", + "type": "TypeList", + "description": "CLI Connection.", + "computed": true, + "elem": { + "arguments": { + "name": "arguments", + "type": "TypeList", + "description": "Sets of arguments to call the executable with. The outer array corresponds to a possible way to call the CLI; the inner array is the set of arguments to use with that call.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "bin": { + "name": "bin", + "type": "TypeString", + "description": "The name of the executable the CLI should run.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "environment": { + "name": "environment", + "type": "TypeMap", + "description": "A map of environment variables for a CLI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "rediss", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "database": { + "name": "database", + "type": "TypeInt", + "description": "Number of the database to use in the URI connection.", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "https", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "bi_connector", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "user_type", + "type": "TypeString", + "description": "User type.", + "required": true + }, + { + "name": "amqps", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "stomp_ssl", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "analytics", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "ops_manager", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "emp", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "user_id", + "type": "TypeString", + "description": "User ID.", + "required": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "Endpoint Type. The endpoint must be enabled on the deployment before its connection information can be fetched.", + "required": true, + "options": "public, private, public-and-private" + }, + { + "name": "mongodb", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "browser_accessible": { + "name": "browser_accessible", + "type": "TypeBool", + "description": "Indicates the address is accessible by browser.", + "computed": true + }, + "certificate": { + "name": "certificate", + "type": "TypeList", + "computed": true, + "elem": { + "certificate_base64": { + "name": "certificate_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "composed": { + "name": "composed", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "database": { + "name": "database", + "type": "TypeString", + "description": "Name of the database to use in the URI connection.", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Path for URI connection.", + "computed": true + }, + "query_options": { + "name": "query_options", + "type": "TypeMap", + "description": "Query options to add to the URI connection.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "replica_set": { + "name": "replica_set", + "type": "TypeString", + "description": "Name of the replica set to use in the URI connection.", + "computed": true + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "Scheme/protocol for URI connection.", + "computed": true + }, + "ssl": { + "name": "ssl", + "type": "TypeBool", + "description": "Indicates ssl is required for the connection.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of connection being described.", + "computed": true + } + } + }, + { + "name": "secure", + "type": "TypeList", + "computed": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeList", + "description": "Authentication data for Connection String.", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "Authentication method for this credential.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password part of credential.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Username part of credential.", + "computed": true + } + } + }, + "bundle": { + "name": "bundle", + "type": "TypeList", + "computed": true, + "elem": { + "bundle_base64": { + "name": "bundle_base64", + "type": "TypeString", + "description": "Base64 encoded version of the certificate bundle.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name associated with the certificate.", + "computed": true + } + } + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Hostname for connection.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number for connection.", + "computed": true + } + } + } + } + } + ], + "ibm_database_point_in_time_recovery": [ + { + "name": "deployment_id", + "type": "TypeString", + "description": "Deployment ID.", + "cloud_data_type": "cloud-database", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "earliest_point_in_time_recovery_time", + "type": "TypeString", + "computed": true + } + ], + "ibm_database_remotes": [ + { + "name": "deployment_id", + "type": "TypeString", + "description": "Deployment ID.", + "cloud_data_type": "cloud-database", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "leader", + "type": "TypeString", + "description": "Leader ID, if applicable.", + "computed": true + }, + { + "name": "replicas", + "type": "TypeList", + "description": "Replica IDs, if applicable.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_database_task": [ + { + "name": "task_id", + "type": "TypeString", + "description": "Task ID.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Human-readable description of the task.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the task.", + "computed": true + }, + { + "name": "deployment_id", + "type": "TypeString", + "description": "ID of the deployment the task is being performed on.", + "computed": true + }, + { + "name": "progress_percent", + "type": "TypeInt", + "description": "Indicator as percentage of progress of the task.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the task was created.", + "computed": true + } + ], + "ibm_database_tasks": [ + { + "name": "deployment_id", + "type": "TypeString", + "description": "Deployment ID.", + "cloud_data_type": "cloud-database", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "tasks", + "type": "TypeList", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the task was created.", + "computed": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "TypeString", + "description": "ID of the deployment the task is being performed on.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Human-readable description of the task.", + "computed": true + }, + "progress_percent": { + "name": "progress_percent", + "type": "TypeInt", + "description": "Indicator as percentage of progress of the task.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the task.", + "computed": true + }, + "task_id": { + "name": "task_id", + "type": "TypeString", + "description": "ID of the task.", + "computed": true + } + } + } + ], + "ibm_dl_gateway": [ + { + "name": "bgp_base_cidr", + "type": "TypeString", + "description": "BGP base CIDR", + "computed": true + }, + { + "name": "bgp_status", + "type": "TypeString", + "description": "Gateway BGP status", + "computed": true + }, + { + "name": "bfd_interval", + "type": "TypeInt", + "description": "BFD Interval", + "computed": true + }, + { + "name": "macsec_config", + "type": "TypeList", + "description": "MACsec configuration information", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicate whether MACsec protection should be active (true) or inactive (false) for this MACsec enabled gateway", + "computed": true + }, + "active_cak": { + "name": "active_cak", + "type": "TypeString", + "description": "Active connectivity association key.", + "computed": true + }, + "cipher_suite": { + "name": "cipher_suite", + "type": "TypeString", + "description": "SAK cipher suite", + "computed": true + }, + "confidentiality_offset": { + "name": "confidentiality_offset", + "type": "TypeInt", + "description": "Confidentiality Offset", + "computed": true + }, + "cryptographic_algorithm": { + "name": "cryptographic_algorithm", + "type": "TypeString", + "description": "Cryptographic Algorithm", + "computed": true + }, + "fallback_cak": { + "name": "fallback_cak", + "type": "TypeString", + "description": "Fallback connectivity association key.", + "computed": true + }, + "key_server_priority": { + "name": "key_server_priority", + "type": "TypeInt", + "description": "Key Server Priority", + "computed": true + }, + "primary_cak": { + "name": "primary_cak", + "type": "TypeString", + "description": "Desired primary connectivity association key.", + "computed": true + }, + "sak_expiry_time": { + "name": "sak_expiry_time", + "type": "TypeInt", + "description": "Secure Association Key (SAK) expiry time in seconds", + "computed": true + }, + "security_policy": { + "name": "security_policy", + "type": "TypeString", + "description": "Packets without MACsec headers are not dropped when security_policy is should_secure.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The current status of MACsec on the device for this gateway", + "computed": true + }, + "window_size": { + "name": "window_size", + "type": "TypeInt", + "description": "Replay protection window size", + "computed": true + } + } + }, + { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of services this Gateway is attached to. Mode transit means this Gateway will be attached to Transit Gateway Service and direct means this Gateway will be attached to vpc or classic connection", + "computed": true + }, + { + "name": "operational_status", + "type": "TypeString", + "description": "Gateway operational status", + "computed": true + }, + { + "name": "bgp_cer_cidr", + "type": "TypeString", + "description": "BGP customer edge router CIDR", + "computed": true + }, + { + "name": "bfd_multiplier", + "type": "TypeInt", + "description": "BFD Multiplier", + "computed": true + }, + { + "name": "bgp_asn", + "type": "TypeInt", + "description": "BGP ASN", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "cross_connect_router", + "type": "TypeString", + "description": "Cross connect router", + "computed": true + }, + { + "name": "location_name", + "type": "TypeString", + "description": "Gateway location", + "computed": true + }, + { + "name": "metered", + "type": "TypeBool", + "description": "Metered billing option", + "computed": true + }, + { + "name": "authentication_key", + "type": "TypeString", + "description": "BGP MD5 authentication key", + "computed": true + }, + { + "name": "link_status", + "type": "TypeString", + "description": "Gateway link status", + "computed": true + }, + { + "name": "port", + "type": "TypeString", + "description": "Gateway port", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Gateway type", + "computed": true + }, + { + "name": "bgp_ibm_cidr", + "type": "TypeString", + "description": "BGP IBM CIDR", + "computed": true + }, + { + "name": "global", + "type": "TypeBool", + "description": "Gateways with global routing (true) can connect to networks outside their associated region", + "computed": true + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "VLAN allocated for this gateway", + "computed": true + }, + { + "name": "gateway_vcs", + "type": "TypeList", + "description": "Collection of direct link gateway virtual connections", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual connection", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual connection. Virtualconnection names are unique within a gateway. This is the name of thevirtual connection itself, the network being connected may have its ownname attribute", + "computed": true + }, + "network_account": { + "name": "network_account", + "type": "TypeString", + "description": "For virtual connections across two different IBM Cloud Accounts network_account indicates the account that owns the target network.", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "description": "Unique identifier of the target network. For type=vpc virtual connections this is the CRN of the target VPC. This field does not apply to type=classic connections.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Status of the virtual connection.Possible values: [pending,attached,approval_pending,rejected,expired,deleting,detached_by_network_pending,detached_by_network]", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of virtual connection. (classic,vpc)", + "computed": true + } + } + }, + { + "name": "bfd_status", + "type": "TypeString", + "description": "BFD Status", + "computed": true + }, + { + "name": "completion_notice_reject_reason", + "type": "TypeString", + "description": "Reason for completion notice rejection", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Gateway resource group", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this gateway", + "required": true + }, + { + "name": "bfd_status_updated_at", + "type": "TypeString", + "description": "BFD Status", + "computed": true + }, + { + "name": "bgp_ibm_asn", + "type": "TypeInt", + "description": "IBM BGP ASN", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN (Cloud Resource Name) of this gateway", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "location_display_name", + "type": "TypeString", + "description": "Gateway location long name", + "computed": true + }, + { + "name": "provider_api_managed", + "type": "TypeBool", + "description": "Indicates whether gateway was created through a provider portal", + "computed": true + }, + { + "name": "as_prepends", + "type": "TypeList", + "description": "List of AS Prepend configuration information", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time AS Prepend was created", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The date and time AS Prepend was created", + "computed": true + }, + "length": { + "name": "length", + "type": "TypeInt", + "description": "Number of times the ASN to appended to the AS Path", + "computed": true + }, + "policy": { + "name": "policy", + "type": "TypeString", + "description": "Route type this AS Prepend applies to", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time AS Prepend was updated", + "computed": true + } + } + }, + { + "name": "speed_mbps", + "type": "TypeInt", + "description": "Gateway speed in megabits per second", + "computed": true + }, + { + "name": "change_request", + "type": "TypeString", + "description": "Changes pending approval for provider managed Direct Link Connect gateways", + "computed": true + } + ], + "ibm_dl_gateways": [ + { + "name": "gateways", + "type": "TypeList", + "description": "Collection of direct link gateways", + "computed": true, + "elem": { + "as_prepends": { + "name": "as_prepends", + "type": "TypeList", + "description": "List of AS Prepend configuration information", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time AS Prepend was created", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The date and time AS Prepend was created", + "computed": true + }, + "length": { + "name": "length", + "type": "TypeInt", + "description": "Number of times the ASN to appended to the AS Path", + "computed": true + }, + "policy": { + "name": "policy", + "type": "TypeString", + "description": "Route type this AS Prepend applies to", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time AS Prepend was updated", + "computed": true + } + } + }, + "authentication_key": { + "name": "authentication_key", + "type": "TypeString", + "description": "BGP MD5 authentication key", + "computed": true + }, + "bfd_interval": { + "name": "bfd_interval", + "type": "TypeInt", + "description": "BFD Interval", + "computed": true + }, + "bfd_multiplier": { + "name": "bfd_multiplier", + "type": "TypeInt", + "description": "BFD Multiplier", + "computed": true + }, + "bfd_status": { + "name": "bfd_status", + "type": "TypeString", + "description": "BFD Status", + "computed": true + }, + "bfd_status_updated_at": { + "name": "bfd_status_updated_at", + "type": "TypeString", + "description": "BFD Status", + "computed": true + }, + "bgp_asn": { + "name": "bgp_asn", + "type": "TypeInt", + "description": "BGP ASN", + "computed": true + }, + "bgp_base_cidr": { + "name": "bgp_base_cidr", + "type": "TypeString", + "description": "BGP base CIDR", + "computed": true + }, + "bgp_cer_cidr": { + "name": "bgp_cer_cidr", + "type": "TypeString", + "description": "BGP customer edge router CIDR", + "computed": true + }, + "bgp_ibm_asn": { + "name": "bgp_ibm_asn", + "type": "TypeInt", + "description": "IBM BGP ASN", + "computed": true + }, + "bgp_ibm_cidr": { + "name": "bgp_ibm_cidr", + "type": "TypeString", + "description": "BGP IBM CIDR", + "computed": true + }, + "bgp_status": { + "name": "bgp_status", + "type": "TypeString", + "description": "Gateway BGP status", + "computed": true + }, + "change_request": { + "name": "change_request", + "type": "TypeString", + "description": "Changes pending approval for provider managed Direct Link Connect gateways", + "computed": true + }, + "completion_notice_reject_reason": { + "name": "completion_notice_reject_reason", + "type": "TypeString", + "description": "Reason for completion notice rejection", + "computed": true + }, + "connection_mode": { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of services this Gateway is attached to. Mode transit means this Gateway will be attached to Transit Gateway Service and direct means this Gateway will be attached to vpc or classic connection", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN (Cloud Resource Name) of this gateway", + "computed": true + }, + "cross_connect_router": { + "name": "cross_connect_router", + "type": "TypeString", + "description": "Cross connect router", + "computed": true + }, + "global": { + "name": "global", + "type": "TypeBool", + "description": "Gateways with global routing (true) can connect to networks outside their associated region", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Id of the data source gateways", + "computed": true + }, + "link_status": { + "name": "link_status", + "type": "TypeString", + "description": "Gateway link status", + "computed": true + }, + "location_display_name": { + "name": "location_display_name", + "type": "TypeString", + "description": "Gateway location long name", + "computed": true + }, + "location_name": { + "name": "location_name", + "type": "TypeString", + "description": "Gateway location", + "computed": true + }, + "macsec_config": { + "name": "macsec_config", + "type": "TypeList", + "description": "MACsec configuration information", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicate whether MACsec protection should be active (true) or inactive (false) for this MACsec enabled gateway", + "computed": true + }, + "active_cak": { + "name": "active_cak", + "type": "TypeString", + "description": "Active connectivity association key.", + "computed": true + }, + "cipher_suite": { + "name": "cipher_suite", + "type": "TypeString", + "description": "SAK cipher suite", + "computed": true + }, + "confidentiality_offset": { + "name": "confidentiality_offset", + "type": "TypeInt", + "description": "Confidentiality Offset", + "computed": true + }, + "cryptographic_algorithm": { + "name": "cryptographic_algorithm", + "type": "TypeString", + "description": "Cryptographic Algorithm", + "computed": true + }, + "fallback_cak": { + "name": "fallback_cak", + "type": "TypeString", + "description": "Fallback connectivity association key. Keys used for MACsec configuration must have names with an even number of characters from [0-9a-fA-F]", + "computed": true + }, + "key_server_priority": { + "name": "key_server_priority", + "type": "TypeInt", + "description": "Key Server Priority", + "computed": true + }, + "primary_cak": { + "name": "primary_cak", + "type": "TypeString", + "description": "Desired primary connectivity association key. Keys for a MACsec configuration must have names with an even number of characters from [0-9a-fA-F]", + "computed": true + }, + "sak_expiry_time": { + "name": "sak_expiry_time", + "type": "TypeInt", + "description": "Secure Association Key (SAK) expiry time in seconds", + "computed": true + }, + "security_policy": { + "name": "security_policy", + "type": "TypeString", + "description": "Packets without MACsec headers are not dropped when security_policy is should_secure.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The current status of MACsec on the device for this gateway", + "computed": true + }, + "window_size": { + "name": "window_size", + "type": "TypeInt", + "description": "Replay protection window size", + "computed": true + } + } + }, + "metered": { + "name": "metered", + "type": "TypeBool", + "description": "Metered billing option", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this gateway", + "computed": true + }, + "operational_status": { + "name": "operational_status", + "type": "TypeString", + "description": "Gateway operational status", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeString", + "description": "Gateway port", + "computed": true + }, + "provider_api_managed": { + "name": "provider_api_managed", + "type": "TypeBool", + "description": "Indicates whether gateway was created through a provider portal", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Gateway resource group", + "computed": true + }, + "speed_mbps": { + "name": "speed_mbps", + "type": "TypeInt", + "description": "Gateway speed in megabits per second", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Gateway type", + "computed": true + }, + "vlan": { + "name": "vlan", + "type": "TypeInt", + "description": "VLAN allocated for this gateway", + "computed": true + } + } + } + ], + "ibm_dl_locations": [ + { + "name": "offering_type", + "type": "TypeString", + "description": "The Direct Link offering type. Current supported values (dedicated and connect).", + "required": true + }, + { + "name": "locations", + "type": "TypeList", + "description": "Collection of valid locations for the specified Direct Link offering.", + "computed": true, + "elem": { + "billing_location": { + "name": "billing_location", + "type": "TypeString", + "description": "Billing location. Only present for locations where provisioning is enabled.", + "computed": true + }, + "building_colocation_owner": { + "name": "building_colocation_owner", + "type": "TypeString", + "description": "Building colocation owner. Only present for offering_type=dedicated locations where provisioning is enabled.", + "computed": true + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "Location long name", + "computed": true + }, + "location_type": { + "name": "location_type", + "type": "TypeString", + "description": "Location type", + "computed": true + }, + "macsec_enabled": { + "name": "macsec_enabled", + "type": "TypeBool", + "description": "Indicates whether location supports MACsec.", + "computed": true + }, + "market": { + "name": "market", + "type": "TypeString", + "description": "Location market", + "computed": true + }, + "market_geography": { + "name": "market_geography", + "type": "TypeString", + "description": "Location geography. Only present for locations where provisioning is enabled.", + "computed": true + }, + "mzr": { + "name": "mzr", + "type": "TypeBool", + "description": "Is location a multi-zone region (MZR). Only present for locations where provisioning is enabled.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Location short name", + "computed": true + }, + "offering_type": { + "name": "offering_type", + "type": "TypeString", + "description": "The Direct Link offering type. Current supported values (dedicated and connect).", + "computed": true + }, + "provision_enabled": { + "name": "provision_enabled", + "type": "TypeBool", + "description": "Indicates for the specific offering_type whether this location supports gateway provisioning.", + "computed": true + }, + "vpc_region": { + "name": "vpc_region", + "type": "TypeString", + "description": "Location's VPC region. Only present for locations where provisioning is enabled.", + "computed": true + } + } + } + ], + "ibm_dl_offering_speeds": [ + { + "name": "offering_type", + "type": "TypeString", + "description": "The Direct Link offering type", + "required": true, + "options": "dedicated, connect" + }, + { + "name": "offering_speeds", + "type": "TypeList", + "description": "Collection of direct link speeds", + "computed": true, + "elem": { + "capabilities": { + "name": "capabilities", + "type": "TypeList", + "description": "List of capabilities for billing option", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "link_speed": { + "name": "link_speed", + "type": "TypeInt", + "description": "Direct Link offering speed for the specified offering type", + "computed": true + }, + "macsec_enabled": { + "name": "macsec_enabled", + "type": "TypeBool", + "description": "Indicate whether speed supports MACsec", + "optional": true + } + } + } + ], + "ibm_dl_port": [ + { + "name": "supported_link_speeds", + "type": "TypeList", + "description": "Port's supported speeds in megabits per second", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "port_id", + "type": "TypeString", + "description": "Port ID", + "required": true + }, + { + "name": "direct_link_count", + "type": "TypeInt", + "description": "Count of existing Direct Link gateways in this account on this port", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Port Label", + "computed": true + }, + { + "name": "location_display_name", + "type": "TypeString", + "description": "Port location long name", + "computed": true + }, + { + "name": "location_name", + "type": "TypeString", + "description": "Port location name identifier", + "computed": true + }, + { + "name": "provider_name", + "type": "TypeString", + "description": "Port's provider name", + "computed": true + } + ], + "ibm_dl_ports": [ + { + "name": "location_name", + "type": "TypeString", + "description": "Direct Link location short name", + "optional": true + }, + { + "name": "ports", + "type": "TypeList", + "description": "Collection of direct link ports", + "computed": true, + "elem": { + "direct_link_count": { + "name": "direct_link_count", + "type": "TypeInt", + "description": "Count of existing Direct Link gateways in this account on this port", + "computed": true + }, + "label": { + "name": "label", + "type": "TypeString", + "description": "Port Label", + "computed": true + }, + "location_display_name": { + "name": "location_display_name", + "type": "TypeString", + "description": "Port location long name", + "computed": true + }, + "location_name": { + "name": "location_name", + "type": "TypeString", + "description": "Port location name identifier", + "computed": true + }, + "port_id": { + "name": "port_id", + "type": "TypeString", + "description": "Port ID", + "computed": true + }, + "provider_name": { + "name": "provider_name", + "type": "TypeString", + "description": "Port's provider name", + "computed": true + }, + "supported_link_speeds": { + "name": "supported_link_speeds", + "type": "TypeList", + "description": "Port's supported speeds in megabits per second", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + ], + "ibm_dl_provider_gateways": [ + { + "name": "gateways", + "type": "TypeList", + "description": "Collection of direct link provider ports", + "computed": true, + "elem": { + "bgp_asn": { + "name": "bgp_asn", + "type": "TypeInt", + "description": "BGP ASN", + "computed": true + }, + "bgp_cer_cidr": { + "name": "bgp_cer_cidr", + "type": "TypeString", + "description": "BGP customer edge router CIDR", + "computed": true + }, + "bgp_ibm_asn": { + "name": "bgp_ibm_asn", + "type": "TypeInt", + "description": "IBM BGP ASN", + "computed": true + }, + "bgp_ibm_cidr": { + "name": "bgp_ibm_cidr", + "type": "TypeString", + "description": "BGP IBM CIDR", + "computed": true + }, + "bgp_status": { + "name": "bgp_status", + "type": "TypeString", + "description": "Gateway BGP status", + "computed": true + }, + "change_request": { + "name": "change_request", + "type": "TypeString", + "description": "Changes pending approval for provider managed Direct Link gateways", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN (Cloud Resource Name) of this gateway", + "computed": true + }, + "customer_account_id": { + "name": "customer_account_id", + "type": "TypeString", + "description": "Customer IBM Cloud account ID for the new gateway. A gateway object containing the pending create request will become available in the specified account.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Id of the data source gateways", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this gateway", + "computed": true + }, + "operational_status": { + "name": "operational_status", + "type": "TypeString", + "description": "Gateway operational status", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeString", + "description": "Gateway port", + "computed": true + }, + "provider_api_managed": { + "name": "provider_api_managed", + "type": "TypeBool", + "description": "Indicates whether gateway was created through a provider portal", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Gateway resource group", + "computed": true + }, + "speed_mbps": { + "name": "speed_mbps", + "type": "TypeInt", + "description": "Gateway speed in megabits per second", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Gateway type", + "computed": true + }, + "vlan": { + "name": "vlan", + "type": "TypeInt", + "description": "VLAN allocated for this gateway", + "computed": true + } + } + } + ], + "ibm_dl_provider_ports": [ + { + "name": "ports", + "type": "TypeList", + "description": "Collection of direct link provider ports", + "computed": true, + "elem": { + "label": { + "name": "label", + "type": "TypeString", + "description": "Port Label", + "computed": true + }, + "location_display_name": { + "name": "location_display_name", + "type": "TypeString", + "description": "Port location long name", + "computed": true + }, + "location_name": { + "name": "location_name", + "type": "TypeString", + "description": "Port location name identifier", + "computed": true + }, + "port_id": { + "name": "port_id", + "type": "TypeString", + "description": "Port ID", + "computed": true + }, + "provider_name": { + "name": "provider_name", + "type": "TypeString", + "description": "Port's provider name", + "computed": true + }, + "supported_link_speeds": { + "name": "supported_link_speeds", + "type": "TypeList", + "description": "Port's supported speeds in megabits per second", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + ], + "ibm_dl_route_report": [ + { + "name": "overlapping_routes", + "type": "TypeList", + "description": "List of overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "overlapping routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of route", + "computed": true + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + } + } + } + } + }, + { + "name": "status", + "type": "TypeString", + "description": "Route report status", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Direct Link gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "route_report", + "type": "TypeString", + "description": "Id of the route report", + "immutable": true, + "required": true + }, + { + "name": "on_prem_routes", + "type": "TypeList", + "description": "List of onprem routes", + "computed": true, + "elem": { + "next_hop": { + "name": "next_hop", + "type": "TypeString", + "description": "Next Hop address", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for onprem routes", + "computed": true + } + } + }, + { + "name": "gateway_routes", + "type": "TypeList", + "description": "List of gateway routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for gateway routes", + "computed": true + } + } + }, + { + "name": "virtual_connection_routes", + "type": "TypeList", + "description": "Virtual Connection Routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Virtual connection routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + } + } + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + }, + "virtual_connection_name": { + "name": "virtual_connection_name", + "type": "TypeString", + "description": "Virtual connection name", + "computed": true + }, + "virtual_connection_type": { + "name": "virtual_connection_type", + "type": "TypeString", + "description": "Virtual connection type", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time report was created", + "computed": true + } + ], + "ibm_dl_route_reports": [ + { + "name": "gateway", + "type": "TypeString", + "description": "The Direct Link gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "route_reports", + "type": "TypeList", + "description": "List of route reports for a gateway", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time report was created", + "computed": true + }, + "gateway_routes": { + "name": "gateway_routes", + "type": "TypeList", + "description": "List of gateway routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for gateway routes", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Id of the route report", + "computed": true + }, + "on_prem_routes": { + "name": "on_prem_routes", + "type": "TypeList", + "description": "List of onprem routes", + "computed": true, + "elem": { + "next_hop": { + "name": "next_hop", + "type": "TypeString", + "description": "Next Hop address", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for onprem routes", + "computed": true + } + } + }, + "overlapping_routes": { + "name": "overlapping_routes", + "type": "TypeList", + "description": "List of overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "overlapping routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of route", + "computed": true + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + } + } + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Route report status", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + "virtual_connection_routes": { + "name": "virtual_connection_routes", + "type": "TypeList", + "description": "Virtual Connection Routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Virtual connection routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + } + } + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + }, + "virtual_connection_name": { + "name": "virtual_connection_name", + "type": "TypeString", + "description": "Virtual connection name", + "computed": true + }, + "virtual_connection_type": { + "name": "virtual_connection_type", + "type": "TypeString", + "description": "Virtual connection type", + "computed": true + } + } + } + } + } + ], + "ibm_dl_routers": [ + { + "name": "offering_type", + "type": "TypeString", + "description": "The Direct Link offering type", + "required": true, + "options": "dedicated" + }, + { + "name": "location_name", + "type": "TypeString", + "description": "The name of the Direct Link location", + "required": true + }, + { + "name": "cross_connect_routers", + "type": "TypeList", + "description": "Collection of Direct Link cross connect routers", + "computed": true, + "elem": { + "capabilities": { + "name": "capabilities", + "type": "TypeList", + "description": "List of capabilities for this router", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "router_name": { + "name": "router_name", + "type": "TypeString", + "description": "The name of the Router", + "computed": true + }, + "total_connections": { + "name": "total_connections", + "type": "TypeInt", + "description": "Count of existing Direct Link Dedicated gateways on this router for this account", + "computed": true + } + } + } + ], + "ibm_dns_custom_resolver_forwarding_rules": [ + { + "name": "resolver_id", + "type": "TypeString", + "description": "The unique identifier of a custom resolver.", + "required": true + }, + { + "name": "rules", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the forwarding rule.", + "computed": true + }, + "forward_to": { + "name": "forward_to", + "type": "TypeList", + "description": "The upstream DNS servers will be forwarded to.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "match": { + "name": "match", + "type": "TypeString", + "description": "The matching zone or hostname.", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Identifier of the forwarding rule.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the forwarding rule.", + "computed": true + } + } + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + } + ], + "ibm_dns_custom_resolver_secondary_zones": [ + { + "name": "resolver_id", + "type": "TypeString", + "description": "The unique identifier of a custom resolver.", + "required": true + }, + { + "name": "secondary_zones", + "type": "TypeList", + "description": "List of Secondary Zones", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Time when a secondary zone is created", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the secondary zone.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Enable/Disable the secondary zone.", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "The recent time when a secondary zone is modified", + "computed": true + }, + "secondary_zone_id": { + "name": "secondary_zone_id", + "type": "TypeString", + "description": "The unique identifier of the Secondary Zone", + "computed": true + }, + "transfer_from": { + "name": "transfer_from", + "type": "TypeList", + "description": "The addresses of DNS servers where the secondary zone data is transferred from.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "The name of the zone.", + "computed": true + } + } + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The GUID of the DNS Services instance.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + } + ], + "ibm_dns_custom_resolvers": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "custom_resolvers", + "type": "TypeList", + "description": "Custom resolver details", + "computed": true, + "elem": { + "custom_resolver_id": { + "name": "custom_resolver_id", + "type": "TypeString", + "description": "Identifier of the custom resolver", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "health": { + "name": "health", + "type": "TypeString", + "computed": true + }, + "locations": { + "name": "locations", + "type": "TypeList", + "description": "Locations on which the custom resolver will be running", + "computed": true, + "elem": { + "dns_server_ip": { + "name": "dns_server_ip", + "type": "TypeString", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "healthy": { + "name": "healthy", + "type": "TypeBool", + "computed": true + }, + "location_id": { + "name": "location_id", + "type": "TypeString", + "description": "Identifier of the custom resolver", + "computed": true + }, + "subnet_crn": { + "name": "subnet_crn", + "type": "TypeString", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the custom resolver", + "computed": true + } + } + } + ], + "ibm_dns_domain": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the domain", + "required": true + }, + { + "name": "id", + "type": "TypeInt", + "description": "A domain record's internal identifier", + "computed": true + } + ], + "ibm_dns_domain_registration": [ + { + "name": "id", + "type": "TypeInt", + "description": "A domain registration record's internal identifier", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the domain registration", + "required": true + }, + { + "name": "name_servers", + "type": "TypeList", + "description": "Custom name servers for the domain registration", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_dns_glb_monitors": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "The GUID of the private DNS.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "dns_glb_monitors", + "type": "TypeList", + "description": "Collection of GLB monitors collectors", + "computed": true, + "elem": { + "allow_insecure": { + "name": "allow_insecure", + "type": "TypeBool", + "description": "Do not validate the certificate when monitor use HTTPS. This parameter is currently only valid for HTTPS monitors.", + "computed": true + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "GLB Monitor creation date", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer monitor", + "computed": true + }, + "expected_body": { + "name": "expected_body", + "type": "TypeString", + "description": "A case-insensitive sub-string to look for in the response body", + "computed": true + }, + "expected_codes": { + "name": "expected_codes", + "type": "TypeString", + "description": "The expected HTTP response code or code range of the health check. This parameter is only valid for HTTP and HTTPS", + "computed": true + }, + "interval": { + "name": "interval", + "type": "TypeInt", + "description": "The interval between each health check", + "computed": true + }, + "method": { + "name": "method", + "type": "TypeString", + "description": "The method to use for the health check", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "GLB Monitor Modification date", + "computed": true + }, + "monitor_id": { + "name": "monitor_id", + "type": "TypeString", + "description": "Monitor Id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "The endpoint path to health check against", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "Port number to connect to for the health check", + "computed": true + }, + "retries": { + "name": "retries", + "type": "TypeInt", + "description": "The number of retries to attempt in case of a timeout before marking the origin as unhealthy", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The timeout (in seconds) before marking the health check as failed", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The protocol to use for the health check", + "computed": true + } + } + } + ], + "ibm_dns_glb_pools": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "dns_glb_pools", + "type": "TypeList", + "description": "Collection of dns resource records", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "The time when a load balancer pool is created.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer pool", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the load balancer pool is enabled", + "computed": true + }, + "health": { + "name": "health", + "type": "TypeString", + "description": "Whether the load balancer pool is enabled", + "computed": true + }, + "healthcheck_region": { + "name": "healthcheck_region", + "type": "TypeString", + "description": "Health check region of VSIs", + "computed": true + }, + "healthcheck_subnets": { + "name": "healthcheck_subnets", + "type": "TypeList", + "description": "Health check subnet crn of VSIs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "healthy_origins_threshold": { + "name": "healthy_origins_threshold", + "type": "TypeInt", + "description": "The minimum number of origins that must be healthy for this pool to serve traffic", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "The recent time when a load balancer pool is modified.", + "computed": true + }, + "monitor": { + "name": "monitor", + "type": "TypeString", + "description": "The ID of the load balancer monitor to be associated to this pool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "DNS record name", + "computed": true + }, + "notification_channel": { + "name": "notification_channel", + "type": "TypeString", + "description": "The notification channel,It is a webhook url", + "computed": true + }, + "origins": { + "name": "origins", + "type": "TypeList", + "description": "Origins info", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The address of the origin server. It can be a hostname or an IP address.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the origin server.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the origin server is enabled.", + "computed": true + }, + "health": { + "name": "health", + "type": "TypeBool", + "description": "Whether the health is `true` or `false`.", + "computed": true + }, + "health_failure_reason": { + "name": "health_failure_reason", + "type": "TypeString", + "description": "The Reason for health check failure", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the origin server.", + "computed": true + } + } + }, + "pool_id": { + "name": "pool_id", + "type": "TypeString", + "description": "DNS record id", + "computed": true + } + } + } + ], + "ibm_dns_glbs": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "The GUID of the private DNS.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone GUID", + "required": true + }, + { + "name": "dns_glbs", + "type": "TypeList", + "description": "Collection of GLB load balancer collectors", + "computed": true, + "elem": { + "az_pools": { + "name": "az_pools", + "type": "TypeList", + "description": "Map availability zones to pool ID's.", + "computed": true, + "elem": { + "availability_zone": { + "name": "availability_zone", + "type": "TypeString", + "description": "Availability zone.", + "computed": true + }, + "pools": { + "name": "pools", + "type": "TypeList", + "description": "List of load balancer pools", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "GLB Load Balancer creation date", + "computed": true + }, + "default_pools": { + "name": "default_pools", + "type": "TypeList", + "description": "A list of pool IDs ordered by their failover priority", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the load balancer is enabled", + "computed": true + }, + "fallback_pool": { + "name": "fallback_pool", + "type": "TypeString", + "description": "The pool ID to use when all other pools are detected as unhealthy", + "computed": true + }, + "glb_id": { + "name": "glb_id", + "type": "TypeString", + "description": "Load balancer Id", + "computed": true + }, + "health": { + "name": "health", + "type": "TypeString", + "description": "Healthy state of the load balancer.", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "GLB Load Balancer Modification date", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the load balancer", + "computed": true + }, + "ttl": { + "name": "ttl", + "type": "TypeInt", + "description": "Time to live in second", + "computed": true + } + } + } + ], + "ibm_dns_permitted_networks": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone ID", + "required": true + }, + { + "name": "dns_permitted_networks", + "type": "TypeList", + "description": "Collection of permitted networks", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Network creation date", + "computed": true + }, + "instance_id": { + "name": "instance_id", + "type": "TypeString", + "description": "Instance Id", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Network Modification date", + "computed": true + }, + "permitted_network": { + "name": "permitted_network", + "type": "TypeMap", + "description": "permitted network", + "computed": true + }, + "permitted_network_id": { + "name": "permitted_network_id", + "type": "TypeString", + "description": "Network Id", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "Network status", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Network Type", + "computed": true + }, + "zone_id": { + "name": "zone_id", + "type": "TypeString", + "description": "Zone Id", + "computed": true + } + } + } + ], + "ibm_dns_resource_records": [ + { + "name": "dns_resource_records", + "type": "TypeList", + "description": "Collection of dns resource records", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "DNS record id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "DNS record name", + "computed": true + }, + "rdata": { + "name": "rdata", + "type": "TypeString", + "description": "DNS record Data", + "computed": true + }, + "ttl": { + "name": "ttl", + "type": "TypeInt", + "description": "DNS record TTL", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "DNS record Type", + "computed": true + } + } + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone Id", + "required": true + } + ], + "ibm_dns_secondary": [ + { + "name": "zone_name", + "type": "TypeString", + "description": "The name of the secondary", + "required": true + }, + { + "name": "master_ip_address", + "type": "TypeString", + "computed": true + }, + { + "name": "transfer_frequency", + "type": "TypeInt", + "computed": true + }, + { + "name": "status_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "status_text", + "type": "TypeString", + "computed": true + } + ], + "ibm_dns_zones": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "dns_zones", + "type": "TypeList", + "description": "Collection of dns zones", + "computed": true, + "elem": { + "created_on": { + "name": "created_on", + "type": "TypeString", + "description": "Creation date", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Zone description", + "computed": true + }, + "instance_id": { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "computed": true + }, + "label": { + "name": "label", + "type": "TypeString", + "description": "Label", + "computed": true + }, + "modified_on": { + "name": "modified_on", + "type": "TypeString", + "description": "Modification date", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "Zone state", + "computed": true + }, + "zone_id": { + "name": "zone_id", + "type": "TypeString", + "description": "Zone ID", + "computed": true + } + } + } + ], + "ibm_en_destination": [ + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "custom_headers": { + "name": "custom_headers", + "type": "TypeMap", + "description": "Custom headers (Key-Value pair) for webhook call.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "sensitive_headers": { + "name": "sensitive_headers", + "type": "TypeList", + "description": "List of sensitive headers from custom headers.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of webhook.", + "computed": true + }, + "verb": { + "name": "verb", + "type": "TypeString", + "description": "HTTP method of webhook.", + "computed": true + } + } + } + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type Email/SMS/Webhook.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_destination_android": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type push_android.", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "sender_id": { + "name": "sender_id", + "type": "TypeString", + "description": "The Sender_id value for FCM project.", + "computed": true + }, + "server_key": { + "name": "server_key", + "type": "TypeString", + "description": "The Server_key value for FCM project.", + "computed": true + } + } + } + } + } + ], + "ibm_en_destination_chrome": [ + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The api key for chrome app authorization", + "secure": true, + "optional": true + }, + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The website url", + "optional": true + } + } + } + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type push_chrome.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_destination_firefox": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type push_firefox.", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The website url", + "optional": true + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_en_destination_ios": [ + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "certificate_content_type", + "type": "TypeString", + "description": "The Certificate Content Type to be set p8/p12.", + "computed": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "The Certificate File.", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "bundle_id": { + "name": "bundle_id", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "computed": true + }, + "cert_type": { + "name": "cert_type", + "type": "TypeString", + "description": "The Certificate Type for IOS, the values are p8/p12.", + "computed": true + }, + "is_sandbox": { + "name": "is_sandbox", + "type": "TypeBool", + "description": "The flag to determine sandbox or production environment.", + "computed": true + }, + "key_id": { + "name": "key_id", + "type": "TypeString", + "description": "The Key ID In case of P8 Certificate", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The Password for APNS Certificate in case of P12 certificate", + "computed": true + }, + "team_id": { + "name": "team_id", + "type": "TypeString", + "description": "The Team ID In case of P8 Certificate", + "computed": true + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type push_ios.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + } + ], + "ibm_en_destination_safari": [ + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "cert_type": { + "name": "cert_type", + "type": "TypeString", + "description": "The Certificate Type for IOS, the values are p8/p12.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The Password for APNS Certificate in case of P12 certificate", + "computed": true + }, + "url_format_string": { + "name": "url_format_string", + "type": "TypeString", + "description": "The Key ID In case of P8 Certificate", + "computed": true + }, + "website_name": { + "name": "website_name", + "type": "TypeString", + "description": "The Team ID In case of P8 Certificate", + "computed": true + }, + "website_push_id": { + "name": "website_push_id", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "computed": true + }, + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "computed": true + } + } + } + } + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type push_ios.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + } + ], + "ibm_en_destination_slack": [ + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type slack.", + "computed": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "url": { + "name": "url", + "type": "TypeString", + "description": "Slack webhook url", + "computed": true + } + } + } + } + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + } + ], + "ibm_en_destination_webhook": [ + { + "name": "destination_id", + "type": "TypeString", + "description": "Unique identifier for Destination.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Destination type Webhook.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "computed": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "computed": true, + "elem": { + "custom_headers": { + "name": "custom_headers", + "type": "TypeMap", + "description": "Custom headers (Key-Value pair) for webhook call.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "sensitive_headers": { + "name": "sensitive_headers", + "type": "TypeList", + "description": "List of sensitive headers from custom headers.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of webhook.", + "computed": true + }, + "verb": { + "name": "verb", + "type": "TypeString", + "description": "HTTP method of webhook.", + "computed": true + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + } + ], + "ibm_en_destinations": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "search_key", + "type": "TypeString", + "description": "Filter the destinations by name or type.", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Total number of destinations.", + "computed": true + }, + { + "name": "destinations", + "type": "TypeList", + "description": "List of destinations.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Destination description.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Destination ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Destination name.", + "computed": true + }, + "subscription_count": { + "name": "subscription_count", + "type": "TypeInt", + "description": "Subscription count.", + "computed": true + }, + "subscription_names": { + "name": "subscription_names", + "type": "TypeList", + "description": "Names of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Destination type Email/SMS/Webhook.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Updated at.", + "computed": true + } + } + } + ], + "ibm_en_source": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "source_id", + "type": "TypeString", + "description": "Unique identifier for Source.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Source name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Source description.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "The Source enable flag.", + "computed": true + } + ], + "ibm_en_subscription": [ + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of destination.", + "computed": true + }, + { + "name": "from", + "type": "TypeString", + "description": "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The destination name.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Topic name.", + "computed": true + }, + { + "name": "attributes", + "type": "TypeList", + "computed": true, + "elem": { + "add_notification_payload": { + "name": "add_notification_payload", + "type": "TypeBool", + "description": "Whether to add the notification payload to the email.", + "computed": true + }, + "additional_properties": { + "name": "additional_properties", + "type": "TypeList", + "description": "Additional attributes.", + "optional": true, + "computed": true, + "elem": { + "from_name": { + "name": "from_name", + "type": "TypeString", + "description": "The email address user name to reply to.", + "optional": true, + "computed": true + }, + "invited": { + "name": "invited", + "type": "TypeList", + "description": "The email id in case of smtp_ibm destination type.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "reply_to_mail": { + "name": "reply_to_mail", + "type": "TypeString", + "description": "The email address to reply to.", + "optional": true, + "computed": true + }, + "reply_to_name": { + "name": "reply_to_name", + "type": "TypeString", + "description": "The email address to reply to.", + "optional": true, + "computed": true + }, + "to": { + "name": "to", + "type": "TypeList", + "description": "The email id in case of smtp_ibm destination type.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "unsubscribed": { + "name": "unsubscribed", + "type": "TypeList", + "description": "The Email address which should be unsubscribed from smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeMap" + } + } + } + }, + "additionalproperties": { + "name": "additionalproperties", + "type": "TypeList", + "description": "Additional attributes for sms and webhook subscription.", + "computed": true, + "elem": { + "to": { + "name": "to", + "type": "TypeList", + "description": "The phone number to send the SMS to.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "signing_enabled": { + "name": "signing_enabled", + "type": "TypeBool", + "description": "Signing webhook attributes.", + "computed": true + } + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_subscription_android": [ + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + } + ], + "ibm_en_subscription_chrome": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + } + ], + "ibm_en_subscription_email": [ + { + "name": "attributes", + "type": "TypeList", + "computed": true, + "elem": { + "add_notification_payload": { + "name": "add_notification_payload", + "type": "TypeBool", + "description": "Whether to add the notification payload to the email.", + "computed": true + }, + "additional_properties": { + "name": "additional_properties", + "type": "TypeList", + "description": "Additional attributes.", + "optional": true, + "computed": true, + "elem": { + "from_name": { + "name": "from_name", + "type": "TypeString", + "description": "The email address username of source email address.", + "optional": true, + "computed": true + }, + "invited": { + "name": "invited", + "type": "TypeList", + "description": "The email id to be invited", + "optional": true, + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "reply_to_mail": { + "name": "reply_to_mail", + "type": "TypeString", + "description": "The email address to reply to.", + "optional": true, + "computed": true + }, + "reply_to_name": { + "name": "reply_to_name", + "type": "TypeString", + "description": "The email address user name to reply to.", + "optional": true, + "computed": true + }, + "to": { + "name": "to", + "type": "TypeList", + "description": "The email id list to whom send the mail.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "unsubscribed": { + "name": "unsubscribed", + "type": "TypeList", + "description": "The Email address which should be unsubscribed from smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeMap" + } + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + } + ], + "ibm_en_subscription_firefox": [ + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + } + ], + "ibm_en_subscription_ios": [ + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + } + ], + "ibm_en_subscription_safari": [ + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + } + ], + "ibm_en_subscription_slack": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "attributes", + "type": "TypeList", + "computed": true, + "elem": { + "attachment_color": { + "name": "attachment_color", + "type": "TypeString", + "description": "attachment color code", + "optional": true + } + } + } + ], + "ibm_en_subscription_sms": [ + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "attributes", + "type": "TypeList", + "description": "The additional attributes", + "computed": true, + "elem": { + "additional_properties": { + "name": "additional_properties", + "type": "TypeList", + "description": "Additional attributes for sms and webhook subscription.", + "computed": true, + "elem": { + "to": { + "name": "to", + "type": "TypeList", + "description": "The phone number to send the SMS to.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + } + ], + "ibm_en_subscription_webhook": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Unique identifier for result.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "attributes", + "type": "TypeList", + "computed": true, + "elem": { + "additional_properties": { + "name": "additional_properties", + "type": "TypeMap", + "description": "Additional attributes.", + "computed": true, + "elem": { + "type": "TypeList" + } + }, + "signing_enabled": { + "name": "signing_enabled", + "type": "TypeBool", + "description": "Signing webhook attributes.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_subscriptions": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "search_key", + "type": "TypeString", + "description": "Filter the subscriptions by name", + "optional": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscriptions", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the subscription.", + "computed": true + }, + "destination_id": { + "name": "destination_id", + "type": "TypeString", + "description": "ID of the destination.", + "computed": true + }, + "destination_name": { + "name": "destination_name", + "type": "TypeString", + "description": "The destination name.", + "computed": true + }, + "destination_type": { + "name": "destination_type", + "type": "TypeString", + "description": "The type of destination.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the subscription.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the subscription.", + "computed": true + }, + "topic_id": { + "name": "topic_id", + "type": "TypeString", + "description": "ID of the topic.", + "computed": true + }, + "topic_name": { + "name": "topic_name", + "type": "TypeString", + "description": "Topic name.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time of the subscription.", + "computed": true + } + } + } + ], + "ibm_en_topic": [ + { + "name": "subscriptions", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "computed": true + }, + "destination_id": { + "name": "destination_id", + "type": "TypeString", + "description": "The destination ID.", + "computed": true + }, + "destination_type": { + "name": "destination_type", + "type": "TypeString", + "description": "The type of destination.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "computed": true + }, + "topic_id": { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Unique identifier for Topic.", + "required": true + }, + { + "name": "source_count", + "type": "TypeInt", + "description": "Number of sources.", + "computed": true + }, + { + "name": "sources", + "type": "TypeList", + "description": "List of sources.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the source.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the source.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "List of rules.", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the rule is enabled or not.", + "computed": true + }, + "event_type_filter": { + "name": "event_type_filter", + "type": "TypeString", + "description": "Event type filter.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Autogenerated rule ID.", + "computed": true + }, + "notification_filter": { + "name": "notification_filter", + "type": "TypeString", + "description": "Notification filter.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Last time the topic was updated.", + "computed": true + } + } + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the topic.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last time the topic was updated.", + "computed": true + } + ], + "ibm_en_topics": [ + { + "name": "total_count", + "type": "TypeInt", + "description": "Number of topics.", + "computed": true + }, + { + "name": "search_key", + "type": "TypeString", + "description": "Filter the topic by name", + "optional": true + }, + { + "name": "topics", + "type": "TypeList", + "description": "List of topics.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the topic.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Autogenerated topic ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + "source_count": { + "name": "source_count", + "type": "TypeInt", + "description": "Number of sources.", + "computed": true + }, + "sources_names": { + "name": "sources_names", + "type": "TypeList", + "description": "List of source names.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subscription_count": { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + } + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "required": true + } + ], + "ibm_enterprise_account_groups": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the account group.", + "optional": true + }, + { + "name": "account_groups", + "type": "TypeList", + "description": "A list of account groups.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the account group was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the account group.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the account group.", + "computed": true + }, + "enterprise_account_id": { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "computed": true + }, + "enterprise_id": { + "name": "enterprise_id", + "type": "TypeString", + "description": "The enterprise ID that the account group is a part of.", + "computed": true + }, + "enterprise_path": { + "name": "enterprise_path", + "type": "TypeString", + "description": "The path from the enterprise to this particular account group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The account group ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the account group.", + "computed": true + }, + "parent": { + "name": "parent", + "type": "TypeString", + "description": "The CRN of the parent of the account group.", + "computed": true + }, + "primary_contact_email": { + "name": "primary_contact_email", + "type": "TypeString", + "description": "The email address of the primary contact of the account group.", + "computed": true + }, + "primary_contact_iam_id": { + "name": "primary_contact_iam_id", + "type": "TypeString", + "description": "The IAM ID of the primary contact of the account group.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state of the account group.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the account group was last updated.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the account group.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "The URL of the account group.", + "computed": true + } + } + } + ], + "ibm_enterprise_accounts": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the account.", + "optional": true + }, + { + "name": "accounts", + "type": "TypeList", + "description": "A list of accounts.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the account was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the account.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the account.", + "computed": true + }, + "enterprise_account_id": { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "computed": true + }, + "enterprise_id": { + "name": "enterprise_id", + "type": "TypeString", + "description": "The enterprise ID that the account is a part of.", + "computed": true + }, + "enterprise_path": { + "name": "enterprise_path", + "type": "TypeString", + "description": "The path from the enterprise to this particular account.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The account ID.", + "computed": true + }, + "is_enterprise_account": { + "name": "is_enterprise_account", + "type": "TypeBool", + "description": "The flag to indicate whether the account is an enterprise account or not.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the account.", + "computed": true + }, + "owner_email": { + "name": "owner_email", + "type": "TypeString", + "description": "The email address of the owner of the account.", + "computed": true + }, + "owner_iam_id": { + "name": "owner_iam_id", + "type": "TypeString", + "description": "The IAM ID of the owner of the account.", + "computed": true + }, + "paid": { + "name": "paid", + "type": "TypeBool", + "description": "The type of account - whether it is free or paid.", + "computed": true + }, + "parent": { + "name": "parent", + "type": "TypeString", + "description": "The CRN of the parent of the account.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state of the account.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the account was last updated.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the account.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "The URL of the account.", + "computed": true + } + } + } + ], + "ibm_enterprises": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the enterprise.", + "optional": true + }, + { + "name": "enterprises", + "type": "TypeList", + "description": "A list of enterprise objects.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the enterprise was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the enterprise.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the enterprise.", + "computed": true + }, + "domain": { + "name": "domain", + "type": "TypeString", + "description": "The domain of the enterprise.", + "computed": true + }, + "enterprise_account_id": { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The enterprise ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the enterprise.", + "computed": true + }, + "primary_contact_email": { + "name": "primary_contact_email", + "type": "TypeString", + "description": "The email of the primary contact of the enterprise.", + "computed": true + }, + "primary_contact_iam_id": { + "name": "primary_contact_iam_id", + "type": "TypeString", + "description": "The IAM ID of the primary contact of the enterprise, such as `IBMid-0123ABC`.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state of the enterprise.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the enterprise was last updated.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the enterprise.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "The URL of the enterprise.", + "computed": true + } + } + } + ], + "ibm_event_streams_schema": [ + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The ID or CRN of the Event Streams service instance", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:event-streams" + ] + }, + { + "name": "kafka_http_url", + "type": "TypeString", + "description": "The API endpoint for interacting with an Event Streams REST API", + "computed": true + }, + { + "name": "schema_id", + "type": "TypeString", + "description": "The unique ID to be assigned to the schema.", + "required": true + } + ], + "ibm_event_streams_topic": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the topic", + "required": true + }, + { + "name": "partitions", + "type": "TypeInt", + "description": "The number of partitions of the topic", + "computed": true + }, + { + "name": "config", + "type": "TypeMap", + "description": "The configuration parameters of the topic.", + "computed": true + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The CRN of the Event Streams instance", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:event-streams" + ] + }, + { + "name": "kafka_http_url", + "type": "TypeString", + "description": "The API endpoint for interacting with Event Streams REST API", + "computed": true + }, + { + "name": "kafka_brokers_sasl", + "type": "TypeList", + "description": "Kafka brokers addresses for interacting with Kafka native API", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_function_action": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of action.", + "required": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Name of the namespace.", + "required": true + }, + { + "name": "limits", + "type": "TypeList", + "computed": true, + "elem": { + "log_size": { + "name": "log_size", + "type": "TypeInt", + "description": "The maximum log size LIMIT in MB for the action.", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The maximum memory LIMIT in MB for the action (default 256.", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The timeout LIMIT in milliseconds after which the action is terminated.", + "computed": true + } + } + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the item.", + "computed": true + }, + { + "name": "action_id", + "type": "TypeString", + "computed": true + }, + { + "name": "exec", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "The code to execute when kind is not 'blackbox'.", + "computed": true + }, + "components": { + "name": "components", + "type": "TypeList", + "description": "The List of fully qualified action", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "image": { + "name": "image", + "type": "TypeString", + "description": "Container image name when kind is 'blackbox'.", + "computed": true + }, + "init": { + "name": "init", + "type": "TypeString", + "description": "Optional zipfile reference.", + "computed": true + }, + "kind": { + "name": "kind", + "type": "TypeString", + "description": "The type of action. Possible values:php:7.3, nodejs:8, swift:3, nodejs, blackbox, java, sequence, nodejs:10, python:3, python, python:2, swift, swift:4.2.", + "computed": true + }, + "main": { + "name": "main", + "type": "TypeString", + "description": "The name of the action entry point (function or fully-qualified method name when applicable)", + "computed": true + } + } + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Action visibilty.", + "computed": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on action by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeString", + "description": "All paramters set on action by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "target_endpoint_url", + "type": "TypeString", + "description": "Action target endpoint URL.", + "computed": true + } + ], + "ibm_function_namespace": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of namespace.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Namespace Description.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource Group ID.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "Namespace Location.", + "cloud_data_type": "region", + "computed": true + } + ], + "ibm_function_package": [ + { + "name": "package_id", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the package.", + "required": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Name of the namespace.", + "required": true + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Package Visibility.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the package.", + "computed": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on package by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeString", + "description": "All parameters set on package by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "bind_package_name", + "type": "TypeString", + "description": "Name of binded package.", + "computed": true + } + ], + "ibm_function_rule": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the rule.", + "required": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Name of the namespace.", + "required": true + }, + { + "name": "trigger_name", + "type": "TypeString", + "description": "Name of the trigger.", + "computed": true + }, + { + "name": "action_name", + "type": "TypeString", + "description": "Name of an action.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the rule.", + "computed": true + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Rule Visibility.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the rule", + "computed": true + }, + { + "name": "rule_id", + "type": "TypeString", + "computed": true + } + ], + "ibm_function_trigger": [ + { + "name": "trigger_id", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of Trigger.", + "required": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Name of the namespace.", + "required": true + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Trigger Visibility.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the trigger.", + "computed": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on trigger by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeString", + "description": "All parameters set on trigger by user and those set by the IBM Cloud Function backend/API.", + "computed": true + } + ], + "ibm_hpcs": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the instance is present", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the environment in which instance exists", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The service type of the instance", + "default_value": "hs-crypto", + "optional": true + }, + { + "name": "units", + "type": "TypeInt", + "description": "The number of operational crypto units for your service instance", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, myobjectstorage", + "required": true + }, + { + "name": "failover_units", + "type": "TypeInt", + "description": "The number of failover crypto units for your service instance", + "computed": true + }, + { + "name": "service_endpoints", + "type": "TypeString", + "description": "Types of the service endpoints. Possible values are `public-and-private`, `private-only`.", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the instance", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of resource instance", + "computed": true + }, + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the resource instance.", + "computed": true + }, + { + "name": "hsm_info", + "type": "TypeList", + "description": "HSM Info of HPCS CryptoUnits", + "computed": true, + "elem": { + "admins": { + "name": "admins", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "ski": { + "name": "ski", + "type": "TypeString", + "computed": true + } + } + }, + "current_mk_status": { + "name": "current_mk_status", + "type": "TypeString", + "computed": true + }, + "current_mkvp": { + "name": "current_mkvp", + "type": "TypeString", + "computed": true + }, + "hsm_id": { + "name": "hsm_id", + "type": "TypeString", + "computed": true + }, + "hsm_location": { + "name": "hsm_location", + "type": "TypeString", + "computed": true + }, + "hsm_type": { + "name": "hsm_type", + "type": "TypeString", + "computed": true + }, + "new_mk_status": { + "name": "new_mk_status", + "type": "TypeString", + "computed": true + }, + "new_mkvp": { + "name": "new_mkvp", + "type": "TypeString", + "computed": true + }, + "revocation_threshold": { + "name": "revocation_threshold", + "type": "TypeInt", + "computed": true + }, + "signature_threshold": { + "name": "signature_threshold", + "type": "TypeInt", + "computed": true + } + } + } + ], + "ibm_hpcs_key_template": [ + { + "name": "version", + "type": "TypeInt", + "description": "Version of the key template. Every time the key template is updated, the version will be updated automatically.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key template.", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "template_id", + "type": "TypeString", + "description": "UUID of the template.", + "required": true + }, + { + "name": "key", + "type": "TypeList", + "description": "Properties describing the properties of the managed key.", + "computed": true, + "elem": { + "activation_date": { + "name": "activation_date", + "type": "TypeString", + "description": "Key activation date can be provided as a period definition (e.g. PY1 means 1 year).", + "computed": true + }, + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "The algorithm of the key.", + "computed": true + }, + "expiration_date": { + "name": "expiration_date", + "type": "TypeString", + "description": "Key expiration date can be provided as a period definition (e.g. PY1 means 1 year).", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeString", + "description": "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state that the key will be in after generation.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the key template was created.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "vault", + "type": "TypeList", + "description": "Reference to a vault.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the referenced vault.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the key template.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the key template.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the key template was updated.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that updated the key.", + "computed": true + }, + { + "name": "keystores", + "type": "TypeList", + "computed": true, + "elem": { + "group": { + "name": "group", + "type": "TypeString", + "description": "Which keystore group to distribute the key to.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "computed": true + } + } + } + ], + "ibm_hpcs_keystore": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "aws_secret_access_key", + "type": "TypeString", + "description": "The secret access key used for connecting to this instance of AWS KMS.", + "secure": true, + "computed": true + }, + { + "name": "azure_service_name", + "type": "TypeString", + "description": "Service name of the key vault instance from the Azure portal.", + "computed": true + }, + { + "name": "azure_resource_group", + "type": "TypeString", + "description": "Resource group in Azure.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "aws_region", + "type": "TypeString", + "description": "AWS Region.", + "computed": true + }, + { + "name": "azure_location", + "type": "TypeString", + "description": "Location of the Azure Key Vault.", + "computed": true + }, + { + "name": "ibm_instance_id", + "type": "TypeString", + "description": "The instance ID of the IBM Cloud keystore.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "computed": true + }, + { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API key to be used for connecting to this IBM Cloud keystore.", + "secure": true, + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "vault", + "type": "TypeList", + "description": "Reference to a vault.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the referenced vault.", + "computed": true + } + } + }, + { + "name": "azure_service_principal_client_id", + "type": "TypeString", + "description": "Azure service principal client ID.", + "computed": true + }, + { + "name": "azure_subscription_id", + "type": "TypeString", + "description": "Subscription ID in Azure.", + "computed": true + }, + { + "name": "azure_environment", + "type": "TypeString", + "description": "Azure environment, usually 'Azure'.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the keystore.", + "computed": true + }, + { + "name": "groups", + "type": "TypeList", + "description": "List of groups that this keystore belongs to.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "azure_service_principal_password", + "type": "TypeString", + "description": "Azure service principal password.", + "secure": true, + "computed": true + }, + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the target keystore. It can be changed in the future.", + "computed": true + }, + { + "name": "aws_access_key_id", + "type": "TypeString", + "description": "The access key id used for connecting to this instance of AWS KMS.", + "secure": true, + "computed": true + }, + { + "name": "ibm_variant", + "type": "TypeString", + "description": "Possible IBM Cloud KMS variants.", + "computed": true + }, + { + "name": "keystore_id", + "type": "TypeString", + "description": "UUID of the keystore.", + "required": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the key.", + "computed": true + }, + { + "name": "ibm_api_endpoint", + "type": "TypeString", + "description": "API endpoint of the IBM Cloud keystore.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the target keystore was created.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the target keystore was last updated.", + "computed": true + }, + { + "name": "azure_tenant", + "type": "TypeString", + "description": "Azure tenant that the Key Vault is associated with,.", + "computed": true + }, + { + "name": "ibm_iam_endpoint", + "type": "TypeString", + "description": "Endpoint of the IAM service for this IBM Cloud keystore.", + "computed": true + }, + { + "name": "ibm_key_ring", + "type": "TypeString", + "description": "The key ring of an IBM Cloud KMS Keystore.", + "computed": true + } + ], + "ibm_hpcs_managed_key": [ + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "algorithm", + "type": "TypeString", + "description": "The algorithm of the key.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the key was last updated.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key.", + "computed": true + }, + { + "name": "instances", + "type": "TypeList", + "description": "key instances.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "keystore": { + "name": "keystore", + "type": "TypeList", + "description": "Description of properties of a key within the context of keystores.", + "computed": true, + "elem": { + "group": { + "name": "group", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "computed": true + } + } + }, + "label_in_keystore": { + "name": "label_in_keystore", + "type": "TypeString", + "description": "The label of the key.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the key instance.", + "computed": true + } + } + }, + { + "name": "activation_date", + "type": "TypeString", + "description": "First day when the key is active.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the key.", + "computed": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "UUID of the key.", + "required": true + }, + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "required": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the key.", + "computed": true + }, + { + "name": "verification_patterns", + "type": "TypeList", + "description": "A list of verification patterns of the key (e.g. public key hash for RSA keys).", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "The method used for calculating the verification pattern.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The calculated value.", + "computed": true + } + } + }, + { + "name": "expiration_date", + "type": "TypeString", + "description": "Last day when the key is active.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the key was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "vault", + "type": "TypeList", + "description": "Reference to a vault.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the referenced vault.", + "computed": true + } + } + }, + { + "name": "template", + "type": "TypeList", + "description": "Reference to a key template.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the key template.", + "computed": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the managed key.", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "The label of the key.", + "computed": true + }, + { + "name": "size", + "type": "TypeString", + "description": "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Key-value pairs associated with the key.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of a tag.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of a tag.", + "computed": true + } + } + }, + { + "name": "referenced_keystores", + "type": "TypeList", + "description": "referenced keystores.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the target keystore.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "computed": true + } + } + } + ], + "ibm_hpcs_vault": [ + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the vault was created.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the vault.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "vault_id", + "type": "TypeString", + "description": "UUID of the vault.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the vault.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the vault.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the vault was last updated.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the vault.", + "computed": true + } + ], + "ibm_iam_access_group": [ + { + "name": "access_group_name", + "type": "TypeString", + "description": "Name of the access group", + "cloud_data_type": "iam", + "optional": true, + "cloud_data_range": [ + "service:access_group", + "resolved_to:name" + ] + }, + { + "name": "groups", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the access group", + "optional": true + }, + "iam_profile_ids": { + "name": "iam_profile_ids", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "iam_service_ids": { + "name": "iam_service_ids", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "ibm_ids": { + "name": "ibm_ids", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "computed": true, + "elem": { + "conditions": { + "name": "conditions", + "type": "TypeList", + "computed": true, + "elem": { + "claim": { + "name": "claim", + "type": "TypeString", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "computed": true + } + } + }, + "expiration": { + "name": "expiration", + "type": "TypeInt", + "description": "The expiration in hours", + "computed": true + }, + "identity_provider": { + "name": "identity_provider", + "type": "TypeString", + "description": "The realm name or identity proivider url", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the Rule", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "id of the rule", + "computed": true + } + } + } + } + } + ], + "ibm_iam_access_group_policy": [ + { + "name": "access_group_id", + "type": "TypeString", + "description": "ID of access group", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:access_group", + "resolved_to:id" + ] + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort query for policies", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resource_tags": { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "computed": true + } + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_iam_account_settings": [ + { + "name": "include_history", + "type": "TypeBool", + "description": "Defines if the entity history is included in the response.", + "default_value": false, + "optional": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Unique ID of the account.", + "computed": true + }, + { + "name": "restrict_create_service_id", + "type": "TypeString", + "description": "Defines whether or not creating a Service Id is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", + "computed": true + }, + { + "name": "allowed_ip_addresses", + "type": "TypeString", + "description": "Defines the IP addresses and subnets from which IAM tokens can be created for the account.", + "computed": true + }, + { + "name": "session_expiration_in_seconds", + "type": "TypeString", + "description": "Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default.", + "computed": true + }, + { + "name": "max_sessions_per_identity", + "type": "TypeString", + "description": "Defines the max allowed sessions per identity required by the account. Value values: * Any whole number greater than '0' * NOT_SET - To unset account setting and use service default.", + "computed": true + }, + { + "name": "restrict_create_platform_apikey", + "type": "TypeString", + "description": "Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", + "computed": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the account settings.", + "computed": true + }, + { + "name": "mfa", + "type": "TypeString", + "description": "Defines the MFA trait for the account. Valid values: * NONE - No MFA trait set * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users.", + "computed": true + }, + { + "name": "history", + "type": "TypeList", + "description": "History of the Account Settings.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action of the history entry.", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of the identity which triggered the action.", + "computed": true + }, + "iam_id_account": { + "name": "iam_id_account", + "type": "TypeString", + "description": "Account of the identity which triggered the action.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "Message which summarizes the executed action.", + "computed": true + }, + "params": { + "name": "params", + "type": "TypeList", + "description": "Params of the history entry.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "timestamp": { + "name": "timestamp", + "type": "TypeString", + "description": "Timestamp when the action was triggered.", + "computed": true + } + } + }, + { + "name": "session_invalidation_in_seconds", + "type": "TypeString", + "description": "Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default.", + "computed": true + } + ], + "ibm_iam_api_key": [ + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the API key. The name is not checked for uniqueness. Therefore multiple names with the same value can exist. Access is done via the UUID of the API key.", + "computed": true + }, + { + "name": "apikey_id", + "type": "TypeString", + "description": "Unique ID of the API key.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678'.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "The API key cannot be changed if set to true.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The optional description of the API key. The 'description' property is only available if a description was provided during a create of an API key.", + "computed": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "The iam_id that this API key authenticates.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "ID of the account that this API key authenticates for.", + "computed": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "IAM ID of the user or service which created the API key.", + "computed": true + } + ], + "ibm_iam_auth_token": [ + { + "name": "iam_access_token", + "type": "TypeString", + "computed": true + }, + { + "name": "iam_refresh_token", + "type": "TypeString", + "computed": true + }, + { + "name": "uaa_access_token", + "type": "TypeString", + "computed": true + }, + { + "name": "uaa_refresh_token", + "type": "TypeString", + "computed": true + } + ], + "ibm_iam_authorization_policies": [ + { + "name": "account_id", + "type": "TypeString", + "description": "The unique ID of an account", + "optional": true, + "computed": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort query for policies", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "source_resource_group_id": { + "name": "source_resource_group_id", + "type": "TypeString", + "description": "The source resource group Id", + "computed": true + }, + "source_resource_instance_id": { + "name": "source_resource_instance_id", + "type": "TypeString", + "description": "The source resource instance Id", + "computed": true + }, + "source_resource_type": { + "name": "source_resource_type", + "type": "TypeString", + "description": "Resource type of source service", + "computed": true + }, + "source_service_account": { + "name": "source_service_account", + "type": "TypeString", + "description": "Account GUID of source service", + "computed": true + }, + "source_service_name": { + "name": "source_service_name", + "type": "TypeString", + "description": "The source service name", + "computed": true + }, + "target_resource_group_id": { + "name": "target_resource_group_id", + "type": "TypeString", + "description": "The target resource group Id", + "computed": true + }, + "target_resource_instance_id": { + "name": "target_resource_instance_id", + "type": "TypeString", + "description": "The target resource instance Id", + "computed": true + }, + "target_resource_type": { + "name": "target_resource_type", + "type": "TypeString", + "description": "Resource type of target service", + "computed": true + }, + "target_service_name": { + "name": "target_service_name", + "type": "TypeString", + "description": "The target service name", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_iam_role_actions": [ + { + "name": "service", + "type": "TypeString", + "description": "The Service Name", + "immutable": true, + "required": true + }, + { + "name": "reader", + "type": "TypeList", + "description": "Reader action ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "manager", + "type": "TypeList", + "description": "manager action ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "reader_plus", + "type": "TypeList", + "description": "readerplus action ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "writer", + "type": "TypeList", + "description": "writer action ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "actions", + "type": "TypeMap", + "description": "List of actions for different services roles", + "computed": true + } + ], + "ibm_iam_roles": [ + { + "name": "service", + "type": "TypeString", + "description": "The Service Name", + "immutable": true, + "optional": true + }, + { + "name": "roles", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_iam_service_id": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the serviceID", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:service_id", + "resolved_to:name" + ] + }, + { + "name": "service_ids", + "type": "TypeList", + "computed": true, + "elem": { + "bound_to": { + "name": "bound_to", + "type": "TypeString", + "description": "bound to of the serviceID", + "computed": true, + "deprecated": "bound_to attribute in service_ids list has been deprecated" + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "CRN of the serviceID", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description of the serviceID", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "The IAM ID of the serviceID", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "locked": { + "name": "locked", + "type": "TypeBool", + "description": "lock state of the serviceID", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "description": "Version of the serviceID", + "computed": true + } + } + } + ], + "ibm_iam_service_policy": [ + { + "name": "iam_service_id", + "type": "TypeString", + "description": "UUID of ServiceID", + "cloud_data_type": "iam", + "optional": true, + "cloud_data_range": [ + "service:service_id", + "resolved_to:id" + ] + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of ServiceID", + "optional": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort query for policies", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resource_tags": { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "computed": true + } + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_iam_trusted_profile": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile to get.", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "ims_account_id", + "type": "TypeInt", + "description": "IMS acount ID of the trusted profile.", + "computed": true + }, + { + "name": "history", + "type": "TypeList", + "description": "History of the trusted profile.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action of the history entry.", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of the identity which triggered the action.", + "computed": true + }, + "iam_id_account": { + "name": "iam_id_account", + "type": "TypeString", + "description": "Account of the identity which triggered the action.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "Message which summarizes the executed action.", + "computed": true + }, + "params": { + "name": "params", + "type": "TypeList", + "description": "Params of the history entry.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "timestamp": { + "name": "timestamp", + "type": "TypeString", + "description": "Timestamp when the action was triggered.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The optional description of the trusted profile. The 'description' property is only available if a description was provided during a create of a trusted profile.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "The iam_id of this trusted profile.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "ID of the account that this trusted profile belong to.", + "computed": true + }, + { + "name": "ims_user_id", + "type": "TypeInt", + "description": "IMS user ID of the trusted profile.", + "computed": true + } + ], + "ibm_iam_trusted_profile_claim_rule": [ + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "realm_name", + "type": "TypeString", + "description": "The realm name of the Idp this claim rule applies to.", + "computed": true + }, + { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA.", + "computed": true + }, + { + "name": "conditions", + "type": "TypeList", + "description": "Conditions of this claim rule.", + "computed": true, + "elem": { + "claim": { + "name": "claim", + "type": "TypeString", + "description": "The claim to evaluate against.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The stringified JSON value that the claim is compared to using the operator.", + "computed": true + } + } + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile.", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "ID of the claim rule to get.", + "required": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The optional claim rule name.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the Calim rule, either 'Profile-SAML' or 'Profile-CR'.", + "computed": true + }, + { + "name": "expiration", + "type": "TypeInt", + "description": "Session expiration in seconds.", + "computed": true + } + ], + "ibm_iam_trusted_profile_claim_rules": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile.", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "rules", + "type": "TypeList", + "description": "List of claim rules.", + "computed": true, + "elem": { + "conditions": { + "name": "conditions", + "type": "TypeList", + "description": "Conditions of this claim rule.", + "computed": true, + "elem": { + "claim": { + "name": "claim", + "type": "TypeString", + "description": "The claim to evaluate against.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The stringified JSON value that the claim is compared to using the operator.", + "computed": true + } + } + }, + "cr_type": { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + "entity_tag": { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + }, + "expiration": { + "name": "expiration", + "type": "TypeInt", + "description": "Session expiration in seconds.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "the unique identifier of the claim rule.", + "computed": true + }, + "modified_at": { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The optional claim rule name.", + "computed": true + }, + "realm_name": { + "name": "realm_name", + "type": "TypeString", + "description": "The realm name of the Idp this claim rule applies to.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the Calim rule, either 'Profile-SAML' or 'Profile-CR'.", + "computed": true + } + } + } + ], + "ibm_iam_trusted_profile_link": [ + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Optional name of the Link.", + "computed": true + }, + { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + "computed": true + }, + { + "name": "link", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN of the compute resource.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + "computed": true + }, + "namespace": { + "name": "namespace", + "type": "TypeString", + "description": "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + "computed": true + } + } + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile.", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "link_id", + "type": "TypeString", + "description": "ID of the link.", + "required": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + } + ], + "ibm_iam_trusted_profile_links": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile.", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "links", + "type": "TypeList", + "description": "List of links to a trusted profile.", + "computed": true, + "elem": { + "cr_type": { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + "entity_tag": { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "the unique identifier of the claim rule.", + "computed": true + }, + "link": { + "name": "link", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN of the compute resource.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + "computed": true + }, + "namespace": { + "name": "namespace", + "type": "TypeString", + "description": "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + "computed": true + } + } + }, + "modified_at": { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Optional name of the Link.", + "computed": true + } + } + } + ], + "ibm_iam_trusted_profile_policy": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "UUID of trusted profile", + "cloud_data_type": "iam", + "optional": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of trusted profile", + "optional": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort query for policies", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resource_tags": { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "computed": true + } + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_iam_trusted_profiles": [ + { + "name": "include_history", + "type": "TypeBool", + "description": "Defines if the entity history is included in the response. Default is false", + "optional": true + }, + { + "name": "profiles", + "type": "TypeList", + "description": "List of trusted profiles.", + "computed": true, + "elem": { + "account_id": { + "name": "account_id", + "type": "TypeString", + "description": "ID of the account that this trusted profile belong to.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The optional description of the trusted profile. The 'description' property is only available if a description was provided during a create of a trusted profile.", + "computed": true + }, + "entity_tag": { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", + "computed": true + }, + "history": { + "name": "history", + "type": "TypeList", + "description": "History of the trusted profile.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action of the history entry.", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of the identity which triggered the action.", + "computed": true + }, + "iam_id_account": { + "name": "iam_id_account", + "type": "TypeString", + "description": "Account of the identity which triggered the action.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "Message which summarizes the executed action.", + "computed": true + }, + "params": { + "name": "params", + "type": "TypeList", + "description": "Params of the history entry.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "timestamp": { + "name": "timestamp", + "type": "TypeString", + "description": "Timestamp when the action was triggered.", + "computed": true + } + } + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "The iam_id of this trusted profile.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "the unique identifier of the trusted profile. Example:'Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + "computed": true + }, + "ims_account_id": { + "name": "ims_account_id", + "type": "TypeInt", + "description": "IMS acount ID of the trusted profile.", + "computed": true + }, + "ims_user_id": { + "name": "ims_user_id", + "type": "TypeInt", + "description": "IMS user ID of the trusted profile.", + "computed": true + }, + "modified_at": { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", + "computed": true + } + } + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Account ID to query for trusted profiles.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the profile", + "cloud_data_type": "iam", + "optional": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:name" + ] + } + ], + "ibm_iam_user_policy": [ + { + "name": "ibm_id", + "type": "TypeString", + "description": "The ibm id or email of user", + "required": true + }, + { + "name": "sort", + "type": "TypeString", + "description": "Sort query for policies", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resource_tags": { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "computed": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "computed": true + } + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_iam_user_profile": [ + { + "name": "allowed_ip_addresses", + "type": "TypeList", + "description": "List of allowed IPv4 or IPv6 addresses", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "user_id", + "type": "TypeString", + "description": "The user ID used for login.", + "computed": true + }, + { + "name": "email", + "type": "TypeString", + "description": "The email of the user.", + "computed": true + }, + { + "name": "phonenumber", + "type": "TypeString", + "description": "The phone for the user.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "An alphanumeric value identifying the account ID.", + "computed": true + }, + { + "name": "ibm_id", + "type": "TypeString", + "description": "An alphanumeric value identifying the user's IAM ID.", + "computed": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "User's IAM ID or or email of user", + "required": true + }, + { + "name": "firstname", + "type": "TypeString", + "description": "The first name of the user.", + "computed": true + }, + { + "name": "lastname", + "type": "TypeString", + "description": "The last name of the user.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the user. Possible values are PROCESSING, PENDING, ACTIVE, DISABLED_CLASSIC_INFRASTRUCTURE, and VPN_ONLY.", + "computed": true + }, + { + "name": "altphonenumber", + "type": "TypeString", + "description": "The alternative phone number of the user.", + "computed": true + } + ], + "ibm_iam_users": [ + { + "name": "users", + "type": "TypeList", + "description": "User's Profiles", + "computed": true, + "elem": { + "account_id": { + "name": "account_id", + "type": "TypeString", + "description": "An alphanumeric value identifying the account ID.", + "computed": true + }, + "alt_phonenumber": { + "name": "alt_phonenumber", + "type": "TypeString", + "description": "The alternative phone number of the user.", + "computed": true + }, + "email": { + "name": "email", + "type": "TypeString", + "description": "The email of the user.", + "computed": true + }, + "first_name": { + "name": "first_name", + "type": "TypeString", + "description": "The first name of the user.", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "User's IAM ID or or email of user", + "computed": true + }, + "last_name": { + "name": "last_name", + "type": "TypeString", + "description": "The last name of the user.", + "computed": true + }, + "phonenumber": { + "name": "phonenumber", + "type": "TypeString", + "description": "The phone for the user.", + "computed": true + }, + "realm": { + "name": "realm", + "type": "TypeString", + "description": "The realm of the user.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state of the user. Possible values are PROCESSING, PENDING, ACTIVE, DISABLED_CLASSIC_INFRASTRUCTURE, and VPN_ONLY.", + "computed": true + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "The user ID used for login.", + "computed": true + } + } + } + ], + "ibm_is_backup_policies": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "Filters the collection to resources in the resource group with the specified identifier", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Filters the collection to resources with the exact specified name", + "optional": true + }, + { + "name": "tag", + "type": "TypeString", + "description": "Filters the collection to resources with the exact tag value", + "optional": true + }, + { + "name": "backup_policies", + "type": "TypeList", + "description": "Collection of backup policies.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this backup policy.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy.", + "computed": true + }, + "last_job_completed_at": { + "name": "last_job_completed_at", + "type": "TypeString", + "description": "The date and time that the most recent job for this backup policy completed.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the backup policy.", + "computed": true + }, + "match_resource_types": { + "name": "match_resource_types", + "type": "TypeList", + "description": "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "match_user_tags": { + "name": "match_user_tags", + "type": "TypeList", + "description": "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy.", + "computed": true + }, + "plans": { + "name": "plans", + "type": "TypeList", + "description": "The plans for the backup policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this backup policy.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + } + ], + "ibm_is_backup_policy": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this backup policy.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "match_resource_types", + "type": "TypeList", + "description": "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy.", + "optional": true, + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy.", + "computed": true + }, + { + "name": "last_job_completed_at", + "type": "TypeString", + "description": "The date and time that the most recent job for this backup policy completed.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the backup policy.", + "computed": true + }, + { + "name": "match_user_tags", + "type": "TypeList", + "description": "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "plans", + "type": "TypeList", + "description": "The plans for the backup policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this backup policy.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The backup policy identifier.", + "optional": true + } + ], + "ibm_is_backup_policy_plan": [ + { + "name": "backup_policy_id", + "type": "TypeString", + "description": "The backup policy identifier.", + "required": true + }, + { + "name": "attach_user_tags", + "type": "TypeList", + "description": "User tags to attach to each resource created by this plan.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "copy_user_tags", + "type": "TypeBool", + "description": "Indicates whether to copy the source's user tags to the created resource.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy plan was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this backup policy plan.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The backup policy plan identifier.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "optional": true, + "computed": true + }, + { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether the plan is active.", + "computed": true + }, + { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for the backup schedule.", + "computed": true + }, + { + "name": "deletion_trigger", + "type": "TypeList", + "computed": true, + "elem": { + "delete_after": { + "name": "delete_after", + "type": "TypeInt", + "description": "The maximum number of days to keep each backup after creation.", + "optional": true + }, + "delete_over_count": { + "name": "delete_over_count", + "type": "TypeInt", + "description": "The maximum number of recent backups to keep. If absent, there is no maximum.", + "computed": true + } + } + } + ], + "ibm_is_backup_policy_plans": [ + { + "name": "plans", + "type": "TypeList", + "description": "Collection of backup policy plans.", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether the plan is active.", + "computed": true + }, + "attach_user_tags": { + "name": "attach_user_tags", + "type": "TypeList", + "description": "The user tags to attach to backups (snapshots) created by this plan.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "copy_user_tags": { + "name": "copy_user_tags", + "type": "TypeBool", + "description": "Indicates whether to copy the source's user tags to the created backups (snapshots).", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy plan was created.", + "computed": true + }, + "cron_spec": { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for the backup schedule.", + "computed": true + }, + "deletion_trigger": { + "name": "deletion_trigger", + "type": "TypeList", + "optional": true, + "elem": { + "delete_after": { + "name": "delete_after", + "type": "TypeInt", + "description": "The maximum number of days to keep each backup after creation.", + "optional": true + }, + "delete_over_count": { + "name": "delete_over_count", + "type": "TypeInt", + "description": "The maximum number of recent backups to keep. If absent, there is no maximum.", + "optional": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "backup_policy_id", + "type": "TypeString", + "description": "The backup policy identifier.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "optional": true + } + ], + "ibm_is_bare_metal_server": [ + { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory, truncated to whole gibibytes", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC the bare metal server is to be a part of", + "computed": true + }, + { + "name": "boot_target", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the bare metal server was created", + "computed": true + }, + { + "name": "cpu", + "type": "TypeList", + "description": "The bare metal server CPU configuration", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The CPU architecture", + "computed": true + }, + "core_count": { + "name": "core_count", + "type": "TypeInt", + "description": "The total number of cores", + "computed": true + }, + "socket_count": { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of CPU sockets", + "computed": true + }, + "threads_per_core": { + "name": "threads_per_core", + "type": "TypeInt", + "description": "The total number of hardware threads per core", + "computed": true + } + } + }, + { + "name": "disks", + "type": "TypeList", + "description": "The disks for this bare metal server, including any disks that are associated with the boot_target.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server disk", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes)", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type name", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Bare metal server status", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Bare metal server name", + "optional": true, + "computed": true + }, + { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true, + "deprecated": "This URL of the interface" + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "image", + "type": "TypeString", + "description": "image name", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group name", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this bare metal server", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "profil name", + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second)", + "computed": true + }, + { + "name": "network_interfaces", + "type": "TypeList", + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the bare metal server", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the Bare metal server", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_is_bare_metal_server_disk": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes)", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "disk", + "type": "TypeString", + "description": "The bare metal server disk identifier", + "required": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server disk", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk", + "computed": true + } + ], + "ibm_is_bare_metal_server_disks": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "A list of bare metal server disks. Disk is a block device that is locally attached to the physical server. By default, the listed disks are sorted by their created_at property values, with the newest disk first.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server disk", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes)", + "computed": true + } + } + } + ], + "ibm_is_bare_metal_server_initialization": [ + { + "name": "image_name", + "type": "TypeString", + "description": "The user-defined or system-provided name for the image the bare metal server was provisioned from", + "computed": true + }, + { + "name": "user_accounts", + "type": "TypeList", + "description": "The user accounts that are created at initialization. There can be multiple account types distinguished by the resource_type attribute.", + "computed": true, + "elem": { + "encrypted_password": { + "name": "encrypted_password", + "type": "TypeString", + "description": "The password at initialization, encrypted using encryption_key, and returned base64-encoded", + "secure": true, + "computed": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN for the encryption key", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The password at initialization, encrypted using encryption_key, and returned base64-encoded", + "secure": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced : [ host_user_account ]", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "The username for the account created at initialization", + "computed": true + } + } + }, + { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the bare metal server", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "private_key", + "type": "TypeString", + "description": "Bare Metal Server Private Key file", + "secure": true, + "optional": true + }, + { + "name": "passphrase", + "type": "TypeString", + "description": "Passphrase for Bare Metal Server Private Key file", + "secure": true, + "optional": true + }, + { + "name": "image", + "type": "TypeString", + "description": "The unique identifier of the image the bare metal server was provisioned from", + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interface": [ + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this floating IP", + "computed": true, + "deprecated": "This field is deprecated - replaced by id" + } + } + }, + { + "name": "primary_ip", + "type": "TypeList", + "description": "IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface : [ available, deleting, failed, pending ]", + "computed": true + }, + { + "name": "allowed_vlans", + "type": "TypeSet", + "description": "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The bare metal server network interface identifier", + "required": true + }, + { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of this bare metal server network interface : [ primary, secondary ]", + "computed": true + }, + { + "name": "allow_interface_to_float", + "type": "TypeBool", + "description": "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Collection of security groups ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The id of the associated subnet", + "computed": true + }, + { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "computed": true + }, + { + "name": "mac_address", + "type": "TypeString", + "description": "The MAC address of the interface. If absent, the value is not known.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface", + "computed": true + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type : [ subnet_reserved_ip ]", + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interface_floating_ip": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The network interface identifier of bare metal server", + "required": true + }, + { + "name": "floating_ip", + "type": "TypeString", + "description": "The floating ip identifier of the network interface associated with the bare metal server", + "required": true + }, + { + "name": "address", + "type": "TypeString", + "description": "Floating IP address", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Floating IP status", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the floating IP", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Target info", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Floating IP crn", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interface_floating_ips": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The network interface identifier of bare metal server", + "required": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Floating IP address", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Floating IP crn", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the floating IP", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the floating IP", + "required": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Floating IP status", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Target info", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + } + } + } + ], + "ibm_is_bare_metal_server_network_interface_reserved_ip": [ + { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this reserved IP will be automatically deleted", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The Bare Metal Server network interface identifier.", + "required": true + }, + { + "name": "reserved_ip", + "type": "TypeString", + "description": "The reserved IP identifier.", + "required": true + }, + { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id.", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The Bare Metal Server identifier.", + "required": true + } + ], + "ibm_is_bare_metal_server_network_interface_reserved_ips": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The BareMetalServer identifier.", + "required": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The BareMetalServer network interface identifier.", + "required": true + }, + { + "name": "reserved_ips", + "type": "TypeList", + "description": "Collection of all reserved IPs bound to a network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "If reserved ip shall be deleted automatically", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "owner": { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this reserved IP", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages", + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interfaces": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "The bare metal server identifier", + "required": true + }, + { + "name": "network_interfaces", + "type": "TypeList", + "description": "A list of all network interfaces on a bare metal server. A network interface is an abstract representation of a network interface card and connects a bare metal server to a subnet. While each network interface can attach to only one subnet, multiple network interfaces can be created to attach to multiple subnets. Multiple interfaces may also attach to the same subnet.", + "computed": true, + "elem": { + "allow_interface_to_float": { + "name": "allow_interface_to_float", + "type": "TypeBool", + "description": "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + "computed": true + }, + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "computed": true + }, + "allowed_vlans": { + "name": "allowed_vlans", + "type": "TypeSet", + "description": "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + "enable_infrastructure_nat": { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "computed": true + }, + "floating_ips": { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this floating IP", + "computed": true, + "deprecated": "This field is deprecated - replaced by id" + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The id of the network interface", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + "mac_address": { + "name": "mac_address", + "type": "TypeString", + "description": "The MAC address of the interface. If absent, the value is not known.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "title: IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type : [ subnet_reserved_ip ]", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Collection of security groups ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface : [ available, deleting, failed, pending ]", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "The id of the associated subnet", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of this bare metal server network interface : [ primary, secondary ]", + "computed": true + }, + "vlan": { + "name": "vlan", + "type": "TypeInt", + "description": "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + "computed": true + } + } + } + ], + "ibm_is_bare_metal_server_profile": [ + { + "name": "bandwidth", + "type": "TypeList", + "description": "The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + { + "name": "cpu_architecture", + "type": "TypeList", + "description": "The CPU architecture for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value for this profile field", + "computed": true + } + } + }, + { + "name": "cpu_core_count", + "type": "TypeList", + "description": "The CPU core count for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + { + "name": "memory", + "type": "TypeList", + "description": "The memory (in gibibytes) for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + { + "name": "supported_trusted_platform_module_modes", + "type": "TypeList", + "description": "An array of supported trusted platform module (TPM) modes for this bare metal server profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported trusted platform module (TPM) modes", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "os_architecture", + "type": "TypeList", + "description": "The supported OS architecture(s) for a bare metal server with this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The default for this profile field", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported OS architecture(s) for a bare metal server with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the bare metal server profile's disks", + "computed": true, + "elem": { + "quantity": { + "name": "quantity", + "type": "TypeList", + "description": "The number of disks of this configuration for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "description": "The size of the disk in GB (gigabytes)", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "supported_interface_types": { + "name": "supported_interface_types", + "type": "TypeList", + "description": "The disk interface used for attaching the disk.", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported disk interfaces used for attaching the disk", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The name for this bare metal server profile", + "required": true + }, + { + "name": "family", + "type": "TypeString", + "description": "The product family this bare metal server profile belongs to", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server profile", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type for this bare metal server profile", + "computed": true + }, + { + "name": "cpu_socket_count", + "type": "TypeList", + "description": "The number of CPU sockets for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + } + ], + "ibm_is_bare_metal_server_profiles": [ + { + "name": "profiles", + "type": "TypeList", + "description": "List of BMS profile maps", + "computed": true, + "elem": { + "bandwidth": { + "name": "bandwidth", + "type": "TypeList", + "description": "The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "cpu_architecture": { + "name": "cpu_architecture", + "type": "TypeList", + "description": "The CPU architecture for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value for this profile field", + "computed": true + } + } + }, + "cpu_core_count": { + "name": "cpu_core_count", + "type": "TypeList", + "description": "The CPU core count for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "cpu_socket_count": { + "name": "cpu_socket_count", + "type": "TypeList", + "description": "The number of CPU sockets for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "Collection of the bare metal server profile's disks", + "computed": true, + "elem": { + "quantity": { + "name": "quantity", + "type": "TypeList", + "description": "The number of disks of this configuration for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "description": "The size of the disk in GB (gigabytes)", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "supported_interface_types": { + "name": "supported_interface_types", + "type": "TypeList", + "description": "The disk interface used for attaching the disk.", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported disk interfaces used for attaching the disk", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + "family": { + "name": "family", + "type": "TypeString", + "description": "The product family this bare metal server profile belongs to", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server profile", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeList", + "description": "The memory (in gibibytes) for a bare metal server with this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name for this bare metal server profile", + "computed": true + }, + "os_architecture": { + "name": "os_architecture", + "type": "TypeList", + "description": "The supported OS architecture(s) for a bare metal server with this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The default for this profile field", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported OS architecture(s) for a bare metal server with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type for this bare metal server profile", + "computed": true + }, + "supported_trusted_platform_module_modes": { + "name": "supported_trusted_platform_module_modes", + "type": "TypeList", + "description": "An array of supported trusted platform module (TPM) modes for this bare metal server profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "description": "The supported trusted platform module (TPM) modes", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + } + ], + "ibm_is_bare_metal_servers": [ + { + "name": "servers", + "type": "TypeList", + "description": "List of Bare Metal Servers", + "computed": true, + "elem": { + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second)", + "computed": true + }, + "boot_target": { + "name": "boot_target", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + "cpu": { + "name": "cpu", + "type": "TypeList", + "description": "The bare metal server CPU configuration", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The CPU architecture", + "computed": true + }, + "core_count": { + "name": "core_count", + "type": "TypeInt", + "description": "The total number of cores", + "computed": true + }, + "socket_count": { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of CPU sockets", + "computed": true + }, + "threads_per_core": { + "name": "threads_per_core", + "type": "TypeInt", + "description": "The total number of hardware threads per core", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the bare metal server was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this bare metal server", + "computed": true + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "The disks for this bare metal server, including any disks that are associated with the boot_target.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server disk", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes)", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Bare metal server id", + "computed": true + }, + "image": { + "name": "image", + "type": "TypeString", + "description": "image id", + "computed": true + }, + "keys": { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the bare metal server", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory, truncated to whole gibibytes", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Bare metal server name", + "computed": true + }, + "network_interfaces": { + "name": "network_interfaces", + "type": "TypeList", + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + "primary_network_interface": { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true, + "deprecated": "This URL of the interface" + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "IPv4, The IP address.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "profile name", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type name", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Bare metal server status", + "computed": true + }, + "status_reasons": { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the Bare metal server", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "description": "The VPC the bare metal server is to be a part of", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + } + } + } + ], + "ibm_is_dedicated_host": [ + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the dedicated host resource.", + "computed": true + }, + { + "name": "instance_placement_enabled", + "type": "TypeBool", + "description": "If set to true, instances can be placed on this dedicated host.", + "computed": true + }, + { + "name": "instances", + "type": "TypeList", + "description": "Array of instances that are allocated to this dedicated host.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + }, + { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host is available for instance creation.", + "computed": true + }, + { + "name": "vcpu", + "type": "TypeList", + "description": "The total VCPU of the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host resides in.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group this dedicated host belongs to", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "available_memory", + "type": "TypeInt", + "description": "The amount of memory in gibibytes that is currently available for instances.", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The total amount of memory in gibibytes for this host.", + "computed": true + }, + { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of sockets for this host.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + { + "name": "profile", + "type": "TypeList", + "description": "The profile this dedicated host uses.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this dedicated host profile.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique name of this dedicated host", + "required": true + }, + { + "name": "host_group", + "type": "TypeString", + "description": "The unique identifier of the dedicated host group this dedicated host belongs to", + "required": true + }, + { + "name": "available_vcpu", + "type": "TypeList", + "description": "The available VCPU for the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host's disks.", + "computed": true, + "elem": { + "available": { + "name": "available", + "type": "TypeInt", + "description": "The remaining space left for instance placement in GB (gigabytes).", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this disk.", + "computed": true + }, + "instance_disks": { + "name": "instance_disks", + "type": "TypeList", + "description": "Instance disks that are on this dedicated host disk.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this dedicated host disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this disk.", + "computed": true + }, + "provisionable": { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host disk is available for instance disk creation.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "description": "The instance disk interfaces supported for this dedicated host disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The administrative state of the dedicated host.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the dedicated host on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + } + ], + "ibm_is_dedicated_host_disk": [ + { + "name": "instance_disks", + "type": "TypeList", + "description": "Instance disks that are on this dedicated host disk.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this dedicated host disk.", + "computed": true + }, + { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host disk is available for instance disk creation.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + { + "name": "disk", + "type": "TypeString", + "description": "The dedicated host disk identifier.", + "required": true + }, + { + "name": "available", + "type": "TypeInt", + "description": "The remaining space left for instance placement in GB (gigabytes).", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this disk.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this disk.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + }, + { + "name": "supported_instance_interface_types", + "type": "TypeList", + "description": "The instance disk interfaces supported for this dedicated host disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "dedicated_host", + "type": "TypeString", + "description": "The dedicated host identifier.", + "required": true + } + ], + "ibm_is_dedicated_host_disks": [ + { + "name": "dedicated_host", + "type": "TypeString", + "description": "The dedicated host identifier.", + "required": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host's disks.", + "computed": true, + "elem": { + "available": { + "name": "available", + "type": "TypeInt", + "description": "The remaining space left for instance placement in GB (gigabytes).", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this disk.", + "computed": true + }, + "instance_disks": { + "name": "instance_disks", + "type": "TypeList", + "description": "Instance disks that are on this dedicated host disk.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this dedicated host disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this disk.", + "computed": true + }, + "provisionable": { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host disk is available for instance disk creation.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "description": "The instance disk interfaces supported for this dedicated host disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_is_dedicated_host_group": [ + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "required": true + }, + { + "name": "family", + "type": "TypeString", + "description": "The dedicated host profile family for hosts in this group.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host group.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host group resides in.", + "computed": true + }, + { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host group.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + { + "name": "class", + "type": "TypeString", + "description": "The dedicated host profile class for hosts in this group.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host group was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host group.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "dedicated_hosts", + "type": "TypeList", + "description": "The dedicated hosts that are in this dedicated host group.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group for this dedicated host group.", + "cloud_data_type": "resource_group", + "computed": true + } + ], + "ibm_is_dedicated_host_groups": [ + { + "name": "host_groups", + "type": "TypeList", + "description": "Collection of dedicated host groups.", + "computed": true, + "elem": { + "class": { + "name": "class", + "type": "TypeString", + "description": "The dedicated host profile class for hosts in this group.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host group was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host group.", + "computed": true + }, + "dedicated_hosts": { + "name": "dedicated_hosts", + "type": "TypeList", + "description": "The dedicated hosts that are in this dedicated host group.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + "family": { + "name": "family", + "type": "TypeString", + "description": "The dedicated host profile family for hosts in this group.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group for this dedicated host group.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "supported_instance_profiles": { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host group.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host group resides in.", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages.", + "computed": true + } + ], + "ibm_is_dedicated_host_profile": [ + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host profile's disks.", + "computed": true, + "elem": { + "interface_type": { + "name": "interface_type", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The interface of the disk for a dedicated host with this profileThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + } + } + }, + "quantity": { + "name": "quantity", + "type": "TypeList", + "description": "The number of disks of this type for a dedicated host with this profile.", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "description": "The size of the disk in GB (gigabytes).", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeList", + "description": "The instance disk interfaces supported for a dedicated host with this profile.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "socket_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "vcpu_architecture", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The VCPU architecture for a dedicated host with this profile.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "optional": true + }, + { + "name": "class", + "type": "TypeString", + "description": "The product class this dedicated host profile belongs to.", + "computed": true + }, + { + "name": "family", + "type": "TypeString", + "description": "The product family this dedicated host profile belongs toThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on dedicated hosts with this profile.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + { + "name": "vcpu_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + ], + "ibm_is_dedicated_host_profiles": [ + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages.", + "computed": true + }, + { + "name": "profiles", + "type": "TypeList", + "description": "Collection of dedicated host profiles.", + "computed": true, + "elem": { + "class": { + "name": "class", + "type": "TypeString", + "description": "The product class this dedicated host profile belongs to.", + "computed": true + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host profile's disks.", + "computed": true, + "elem": { + "interface_type": { + "name": "interface_type", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The interface of the disk for a dedicated host with this profileThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + } + } + }, + "quantity": { + "name": "quantity", + "type": "TypeList", + "description": "The number of disks of this type for a dedicated host with this profile.", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "description": "The size of the disk in GB (gigabytes).", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeList", + "description": "The instance disk interfaces supported for a dedicated host with this profile.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + "family": { + "name": "family", + "type": "TypeString", + "description": "The product family this dedicated host profile belongs toThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this dedicated host profile.", + "computed": true + }, + "socket_count": { + "name": "socket_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "supported_instance_profiles": { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on dedicated hosts with this profile.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + "vcpu_architecture": { + "name": "vcpu_architecture", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The VCPU architecture for a dedicated host with this profile.", + "computed": true + } + } + }, + "vcpu_count": { + "name": "vcpu_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + } + } + ], + "ibm_is_dedicated_hosts": [ + { + "name": "host_group", + "type": "TypeString", + "description": "The unique identifier of the dedicated host group this dedicated host belongs to", + "optional": true + }, + { + "name": "dedicated_hosts", + "type": "TypeList", + "description": "Collection of dedicated hosts.", + "computed": true, + "elem": { + "available_memory": { + "name": "available_memory", + "type": "TypeInt", + "description": "The amount of memory in gibibytes that is currently available for instances.", + "computed": true + }, + "available_vcpu": { + "name": "available_vcpu", + "type": "TypeList", + "description": "The available VCPU for the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host's disks.", + "computed": true, + "elem": { + "available": { + "name": "available", + "type": "TypeInt", + "description": "The remaining space left for instance placement in GB (gigabytes).", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this disk.", + "computed": true + }, + "instance_disks": { + "name": "instance_disks", + "type": "TypeList", + "description": "Instance disks that are on this dedicated host disk.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this dedicated host disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this disk.", + "computed": true + }, + "provisionable": { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host disk is available for instance disk creation.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "description": "The instance disk interfaces supported for this dedicated host disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "host_group": { + "name": "host_group", + "type": "TypeString", + "description": "The unique identifier of the dedicated host group this dedicated host is in.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + }, + "instance_placement_enabled": { + "name": "instance_placement_enabled", + "type": "TypeBool", + "description": "If set to true, instances can be placed on this dedicated host.", + "computed": true + }, + "instances": { + "name": "instances", + "type": "TypeList", + "description": "Array of instances that are allocated to this dedicated host.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the dedicated host resource.", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The total amount of memory in gibibytes for this host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeList", + "description": "The profile this dedicated host uses.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this dedicated host profile.", + "computed": true + } + } + }, + "provisionable": { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host is available for instance creation.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group for this dedicated host.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "socket_count": { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of sockets for this host.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The administrative state of the dedicated host.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the dedicated host on which the unexpected property value was encountered.", + "computed": true + }, + "supported_instance_profiles": { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + "vcpu": { + "name": "vcpu", + "type": "TypeList", + "description": "The total VCPU of the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host resides in.", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages.", + "computed": true + } + ], + "ibm_is_endpoint_gateway_targets": [ + { + "name": "resources", + "type": "TypeList", + "description": "List of resources", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "CRN for this specific object", + "computed": true + }, + "endpoint_type": { + "name": "endpoint_type", + "type": "TypeString", + "description": "Data endpoint type of this offering", + "computed": true + }, + "full_qualified_domain_names": { + "name": "full_qualified_domain_names", + "type": "TypeSet", + "description": "Fully qualified domain names", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "location": { + "name": "location", + "type": "TypeString", + "description": "Service location of this offering", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Display name in the requested language", + "computed": true + }, + "parent": { + "name": "parent", + "type": "TypeString", + "description": "Parent for this specific object", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of this offering.", + "computed": true + } + } + } + ], + "ibm_is_floating_ip": [ + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Target info", + "computed": true + }, + { + "name": "target_list", + "type": "TypeList", + "description": "The target of this floating IP.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this public gateway.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "Floating IP crn", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Floating IP tags", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the floating IP", + "required": true + }, + { + "name": "address", + "type": "TypeString", + "description": "Floating IP address", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Floating IP status", + "computed": true + } + ], + "ibm_is_floating_ips": [ + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP.", + "optional": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "Collection of floating IPs.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the floating IP was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this floating IP.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the floating IP.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "The target of this floating IP.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this public gateway.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "The primary IPv4 address.If the address has not yet been selected, the value will be `0.0.0.0`.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "zone": { + "name": "zone", + "type": "TypeList", + "description": "The zone this floating IP resides in.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this zone.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this zone.", + "computed": true + } + } + } + } + } + ], + "ibm_is_flow_log": [ + { + "name": "identifier", + "type": "TypeString", + "description": "The flow log collector identifier.", + "optional": true + }, + { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether this collector is active.", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to `true`, this flow log collector will be automatically deleted when the target is deleted.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the flow log collector was created.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the flow log collector.", + "computed": true + }, + { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this flow log collector is associated with.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this flow log collector.", + "optional": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this flow log collector.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this flow log collector.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "storage_bucket", + "type": "TypeList", + "description": "The Cloud Object Storage bucket where the collected flows are logged.", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name of this COS bucket.", + "computed": true + } + } + }, + { + "name": "target", + "type": "TypeList", + "description": "The target this collector is collecting flow logs for. If the target is an instance,subnet, or VPC, flow logs will not be collected for any network interfaces within thetarget that are themselves the target of a more specific flow log collector.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this flow log collector.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_flow_logs": [ + { + "name": "flow_log_collectors", + "type": "TypeList", + "description": "Collection of flow log collectors", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether this collector is active", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time flow log was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this flow log collector", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this flow log collector", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this flow log collector", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the flow log collector", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Flow Log Collector name", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group of flow log", + "computed": true + }, + "storage_bucket": { + "name": "storage_bucket", + "type": "TypeString", + "description": "The Cloud Object Storage bucket name where the collected flows will be logged", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "The target id that the flow log collector is to collect flow logs", + "computed": true + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "description": "The VPC this flow log collector is associated with", + "computed": true + } + } + } + ], + "ibm_is_ike_policies": [ + { + "name": "ike_policies", + "type": "TypeList", + "description": "Collection of IKE policies.", + "computed": true, + "elem": { + "authentication_algorithm": { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "The authentication algorithm.", + "computed": true + }, + "connections": { + "name": "connections", + "type": "TypeList", + "description": "The VPN gateway connections that use this IKE policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this IKE policy was created.", + "computed": true + }, + "dh_group": { + "name": "dh_group", + "type": "TypeInt", + "description": "The Diffie-Hellman group.", + "computed": true + }, + "encryption_algorithm": { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "The encryption algorithm.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The IKE policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this IKE policy.", + "computed": true + }, + "ike_version": { + "name": "ike_version", + "type": "TypeInt", + "description": "The IKE protocol version.", + "computed": true + }, + "key_lifetime": { + "name": "key_lifetime", + "type": "TypeInt", + "description": "The key lifetime in seconds.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this IKE policy.", + "computed": true + }, + "negotiation_mode": { + "name": "negotiation_mode", + "type": "TypeString", + "description": "The IKE negotiation mode. Only `main` is supported.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this IKE policy.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + } + ], + "ibm_is_ike_policy": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this IKE policy was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The IKE policy's canonical URL.", + "computed": true + }, + { + "name": "ike_version", + "type": "TypeInt", + "description": "The IKE protocol version.", + "computed": true + }, + { + "name": "negotiation_mode", + "type": "TypeString", + "description": "The IKE negotiation mode. Only `main` is supported.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this IKE policy.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The IKE policy name.", + "optional": true + }, + { + "name": "ike_policy", + "type": "TypeString", + "description": "The IKE policy identifier.", + "optional": true + }, + { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "The authentication algorithm.", + "computed": true + }, + { + "name": "key_lifetime", + "type": "TypeInt", + "description": "The key lifetime in seconds.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "connections", + "type": "TypeList", + "description": "The VPN gateway connections that use this IKE policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "dh_group", + "type": "TypeInt", + "description": "The Diffie-Hellman group.", + "computed": true + }, + { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "The encryption algorithm.", + "computed": true + } + ], + "ibm_is_image": [ + { + "name": "visibility", + "type": "TypeString", + "description": "Whether the image is publicly visible or private to the account", + "optional": true + }, + { + "name": "os", + "type": "TypeString", + "description": "Image Operating system", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this image", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", + "computed": true + }, + { + "name": "catalog_offering", + "type": "TypeList", + "computed": true, + "elem": { + "managed": { + "name": "managed", + "type": "TypeBool", + "description": "Indicates whether this image is managed as part of a catalog offering. A managed image can be provisioned using its catalog offering CRN or catalog offering version CRN.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeList", + "description": "The catalog offering version associated with this image.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this version of the IBM Cloud catalog offering.", + "computed": true + } + } + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Image name", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of this image", + "computed": true + }, + { + "name": "architecture", + "type": "TypeString", + "description": "The operating system architecture", + "computed": true + }, + { + "name": "checksum", + "type": "TypeString", + "description": "The SHA256 Checksum for this image", + "computed": true + }, + { + "name": "encryption", + "type": "TypeString", + "description": "The type of encryption used on the image", + "computed": true + }, + { + "name": "source_volume", + "type": "TypeString", + "description": "Source volume id of the image", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "Image id", + "optional": true + } + ], + "ibm_is_images": [ + { + "name": "images", + "type": "TypeList", + "description": "List of images", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The operating system architecture", + "computed": true + }, + "catalog_offering": { + "name": "catalog_offering", + "type": "TypeList", + "computed": true, + "elem": { + "managed": { + "name": "managed", + "type": "TypeBool", + "description": "Indicates whether this image is managed as part of a catalog offering. A managed image can be provisioned using its catalog offering CRN or catalog offering version CRN.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeList", + "description": "The catalog offering version associated with this image.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this version of the IBM Cloud catalog offering.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + } + } + } + } + }, + "checksum": { + "name": "checksum", + "type": "TypeString", + "description": "The SHA256 Checksum for this image", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this image", + "computed": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "description": "The type of encryption used on the image", + "computed": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this image", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Image name", + "computed": true + }, + "os": { + "name": "os", + "type": "TypeString", + "description": "Image Operating system", + "computed": true + }, + "source_volume": { + "name": "source_volume", + "type": "TypeString", + "description": "Source volume id of the image", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of this image", + "computed": true + }, + "visibility": { + "name": "visibility", + "type": "TypeString", + "description": "Whether the image is publicly visible or private to the account", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The id of the resource group", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "catalog_managed", + "type": "TypeBool", + "description": "Lists images managed as part of a catalog offering. If an image is managed, accounts in the same enterprise with access to that catalog can specify the image's catalog offering version CRN to provision virtual server instances using the image", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the image", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the image", + "options": "available, deleting, deprecated, failed, obsolete, pending, tentative, unusable", + "optional": true + }, + { + "name": "visibility", + "type": "TypeString", + "description": "Whether the image is publicly visible or private to the account", + "optional": true + } + ], + "ibm_is_instance": [ + { + "name": "memory", + "type": "TypeInt", + "description": "Instance memory", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "instance status", + "computed": true + }, + { + "name": "lifecycle_reasons", + "type": "TypeList", + "description": "The reasons for the current lifecycle_state (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the reason for this lifecycle state.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the reason for this lifecycle state.", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about the reason for this lifecycle state.", + "computed": true + } + } + }, + { + "name": "volumes", + "type": "TypeSet", + "description": "List of volumes", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions for the virtual server instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host group.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + { + "name": "passphrase", + "type": "TypeString", + "description": "Passphrase for Instance Private Key file", + "secure": true, + "optional": true + }, + { + "name": "keys", + "type": "TypeList", + "description": "Instance keys", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance key id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance key name", + "computed": true + } + } + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + "computed": true + }, + { + "name": "catalog_offering", + "type": "TypeList", + "description": "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + "computed": true, + "elem": { + "offering_crn": { + "name": "offering_crn", + "type": "TypeString", + "description": "Identifies a catalog offering by a unique CRN property", + "computed": true + }, + "version_crn": { + "name": "version_crn", + "type": "TypeString", + "description": "Identifies a version of a catalog offering by a unique CRN property", + "computed": true + } + } + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "private_key", + "type": "TypeString", + "description": "Instance Private Key file", + "optional": true + }, + { + "name": "boot_volume", + "type": "TypeList", + "description": "Instance Boot Volume", + "computed": true, + "elem": { + "device": { + "name": "device", + "type": "TypeString", + "description": "Instance Boot Volume device", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Boot Volume id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Boot Volume name", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "Instance Boot Volume's volume CRN", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "Instance Boot Volume's volume id", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "description": "Instance Boot Volume's volume name", + "computed": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the virtual server instance.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "password", + "type": "TypeString", + "description": "password for Windows Instance", + "secure": true, + "computed": true + }, + { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "list of tags for the instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Primary Network Interface id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Primary Network Interface name", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "description": "Instance Primary Network Interface port speed", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "Instance Primary Network Interface IPV4 Address", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Instance Primary Network Interface Security groups", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "Instance Primary Network Interface subnet", + "computed": true + } + } + }, + { + "name": "image", + "type": "TypeString", + "description": "Instance Image", + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "description": "The reasons for the current status (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Instance name", + "required": true + }, + { + "name": "volume_attachments", + "type": "TypeList", + "description": "Instance Volume Attachments", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Volume Attachment id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Volume Attachment name", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "Instance Boot Volume's volume CRN", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "Instance Boot Volume's volume id", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "description": "Instance Boot Volume's volume name", + "computed": true + } + } + }, + { + "name": "network_interfaces", + "type": "TypeList", + "description": "Instance Network interface info", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Network Interface id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Network Interface name", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "Instance Network Interface IPV4 Address", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Instance Network Interface Security Groups", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "Instance Network Interface subnet", + "computed": true + } + } + }, + { + "name": "vcpu", + "type": "TypeList", + "description": "Instance vCPU", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "Instance vCPU Architecture", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "Instance vCPU count", + "computed": true + } + } + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "total_network_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "Profile info", + "computed": true + }, + { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Instance resource group", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "gpu", + "type": "TypeList", + "description": "Instance GPU", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "description": "Instance GPU Count", + "computed": true + }, + "manufacturer": { + "name": "manufacturer", + "type": "TypeString", + "description": "Instance GPU Manufacturer", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "Instance GPU Memory", + "computed": true + }, + "model": { + "name": "model", + "type": "TypeString", + "description": "Instance GPU Model", + "computed": true + } + } + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance's disks.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC id", + "computed": true + } + ], + "ibm_is_instance_disk": [ + { + "name": "instance", + "type": "TypeString", + "description": "The instance identifier.", + "required": true + }, + { + "name": "disk", + "type": "TypeString", + "description": "The instance disk identifier.", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + ], + "ibm_is_instance_disks": [ + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance's disks.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + { + "name": "instance", + "type": "TypeString", + "description": "The instance identifier.", + "required": true + } + ], + "ibm_is_instance_group": [ + { + "name": "vpc", + "type": "TypeString", + "description": "vpc instance", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Instance group status - deleting, healthy, scaling, unhealthy", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group", + "required": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "description": "list of subnet IDs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "application_port", + "type": "TypeInt", + "description": "Used by the instance group when scaling up instances to supply the port for the load balancer pool member.", + "computed": true + }, + { + "name": "load_balancer_pool", + "type": "TypeString", + "description": "load balancer pool ID", + "computed": true + }, + { + "name": "instance_template", + "type": "TypeString", + "description": "instance template ID", + "computed": true + }, + { + "name": "membership_count", + "type": "TypeInt", + "description": "The number of instances in the instance group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance group", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "managers", + "type": "TypeList", + "description": "list of Managers associated with instancegroup", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_is_instance_group_manager": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the instance group manager.", + "required": true + }, + { + "name": "manager_type", + "type": "TypeString", + "description": "The type of instance group manager.", + "computed": true + }, + { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "computed": true + }, + { + "name": "policies", + "type": "TypeList", + "description": "list of Policies associated with instancegroup manager", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "aggregation_window", + "type": "TypeInt", + "description": "The time window in seconds to aggregate metrics prior to evaluation", + "computed": true + }, + { + "name": "cooldown", + "type": "TypeInt", + "description": "The duration of time in seconds to pause further scale actions after scaling has taken place", + "computed": true + }, + { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "computed": true + }, + { + "name": "manager_id", + "type": "TypeString", + "description": "The ID of instance group manager.", + "computed": true + }, + { + "name": "actions", + "type": "TypeList", + "computed": true, + "elem": { + "instance_group_manager_action": { + "name": "instance_group_manager_action", + "type": "TypeString", + "computed": true + }, + "instance_group_manager_action_name": { + "name": "instance_group_manager_action_name", + "type": "TypeString", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_instance_group_manager_action": [ + { + "name": "next_run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will next run. If empty the system is currently calculating the next run time.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "membership_count", + "type": "TypeInt", + "description": "The number of members the instance group should have at the scheduled time.", + "computed": true + }, + { + "name": "action_type", + "type": "TypeString", + "description": "The type of action for the instance group.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "computed": true + }, + { + "name": "auto_delete_timeout", + "type": "TypeInt", + "computed": true + }, + { + "name": "target_manager_name", + "type": "TypeString", + "description": "Instance group manager name of type autoscale.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group action- `active`: Action is ready to be run- `completed`: Action was completed successfully- `failed`: Action could not be completed successfully- `incompatible`: Action parameters are not compatible with the group or manager- `omitted`: Action was not applied because this action's manager was disabled.", + "computed": true + }, + { + "name": "target_manager", + "type": "TypeString", + "description": "The unique identifier for this instance group manager of type autoscale.", + "computed": true + }, + { + "name": "action_id", + "type": "TypeString", + "description": "Instance group manager action ID", + "computed": true + }, + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID of type scheduled", + "required": true + }, + { + "name": "run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will run.", + "computed": true + }, + { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for a recurring scheduled action. Actions can be applied a maximum of one time within a 5 min period.", + "computed": true + }, + { + "name": "last_applied_at", + "type": "TypeString", + "description": "The date and time the scheduled action was last applied. If empty the action has never been applied.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "instance group manager action name", + "required": true + }, + { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "computed": true + }, + { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "computed": true + } + ], + "ibm_is_instance_group_manager_actions": [ + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID", + "required": true + }, + { + "name": "instance_group_manager_actions", + "type": "TypeList", + "description": "List of instance group manager actions", + "computed": true, + "elem": { + "action_id": { + "name": "action_id", + "type": "TypeString", + "description": "Instance group manager action ID", + "computed": true + }, + "action_type": { + "name": "action_type", + "type": "TypeString", + "description": "The type of action for the instance group.", + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "computed": true + }, + "auto_delete_timeout": { + "name": "auto_delete_timeout", + "type": "TypeInt", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + }, + "cron_spec": { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for a recurring scheduled action. Actions can be applied a maximum of one time within a 5 min period.", + "computed": true + }, + "instance_group": { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + "last_applied_at": { + "name": "last_applied_at", + "type": "TypeString", + "description": "The date and time the scheduled action was last applied. If empty the action has never been applied.", + "computed": true + }, + "max_membership_count": { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "computed": true + }, + "membership_count": { + "name": "membership_count", + "type": "TypeInt", + "description": "The number of members the instance group should have at the scheduled time.", + "computed": true + }, + "min_membership_count": { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "instance group manager action name", + "computed": true + }, + "next_run_at": { + "name": "next_run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will next run. If empty the system is currently calculating the next run time.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "run_at": { + "name": "run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will run.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group action- `active`: Action is ready to be run- `completed`: Action was completed successfully- `failed`: Action could not be completed successfully- `incompatible`: Action parameters are not compatible with the group or manager- `omitted`: Action was not applied because this action's manager was disabled.", + "computed": true + }, + "target_manager": { + "name": "target_manager", + "type": "TypeString", + "description": "The unique identifier for this instance group manager of type autoscale.", + "computed": true + }, + "target_manager_name": { + "name": "target_manager_name", + "type": "TypeString", + "description": "Instance group manager name of type autoscale.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + } + } + } + ], + "ibm_is_instance_group_manager_policies": [ + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID", + "required": true + }, + { + "name": "instance_group_manager_policies", + "type": "TypeList", + "description": "List of instance group manager policies", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the instance group manager policy.", + "computed": true + }, + "metric_type": { + "name": "metric_type", + "type": "TypeString", + "description": "The type of metric to be evaluated", + "computed": true + }, + "metric_value": { + "name": "metric_value", + "type": "TypeInt", + "description": "The metric value to be evaluated", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the instance group manager policy", + "computed": true + }, + "policy_id": { + "name": "policy_id", + "type": "TypeString", + "description": "The policy ID", + "computed": true + }, + "policy_type": { + "name": "policy_type", + "type": "TypeString", + "description": "The type of Policy for the Instance Group", + "computed": true + } + } + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + } + ], + "ibm_is_instance_group_manager_policy": [ + { + "name": "metric_value", + "type": "TypeInt", + "description": "The metric value to be evaluated", + "computed": true + }, + { + "name": "policy_type", + "type": "TypeString", + "description": "The type of Policy for the Instance Group", + "computed": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "The policy ID", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the instance group manager policy", + "required": true + }, + { + "name": "metric_type", + "type": "TypeString", + "description": "The type of metric to be evaluated", + "computed": true + } + ], + "ibm_is_instance_group_managers": [ + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "instance_group_managers", + "type": "TypeList", + "description": "List of instance group managers", + "computed": true, + "elem": { + "actions": { + "name": "actions", + "type": "TypeList", + "computed": true, + "elem": { + "instance_group_manager_action": { + "name": "instance_group_manager_action", + "type": "TypeString", + "computed": true + }, + "instance_group_manager_action_name": { + "name": "instance_group_manager_action_name", + "type": "TypeString", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "computed": true + } + } + }, + "aggregation_window": { + "name": "aggregation_window", + "type": "TypeInt", + "description": "The time window in seconds to aggregate metrics prior to evaluation", + "computed": true + }, + "cooldown": { + "name": "cooldown", + "type": "TypeInt", + "description": "The duration of time in seconds to pause further scale actions after scaling has taken place", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the instance group manager.", + "computed": true + }, + "manager_id": { + "name": "manager_id", + "type": "TypeString", + "description": "The ID of instance group manager.", + "computed": true + }, + "manager_type": { + "name": "manager_type", + "type": "TypeString", + "description": "The type of instance group manager.", + "computed": true + }, + "max_membership_count": { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "computed": true + }, + "min_membership_count": { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the instance group manager.", + "computed": true + }, + "policies": { + "name": "policies", + "type": "TypeList", + "description": "list of Policies associated with instancegroup manager", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_is_instance_group_membership": [ + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group membership. Names must be unique within the instance group.", + "required": true + }, + { + "name": "delete_instance_on_membership_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the membership the instance will also be deleted.", + "computed": true + }, + { + "name": "instance_group_membership", + "type": "TypeString", + "description": "The unique identifier for this instance group membership.", + "computed": true + }, + { + "name": "instance", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + }, + "virtual_server_instance": { + "name": "virtual_server_instance", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + } + } + }, + { + "name": "instance_template", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance template.", + "computed": true + }, + "instance_template": { + "name": "instance_template", + "type": "TypeString", + "description": "The unique identifier for this instance template.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this instance template.", + "computed": true + } + } + }, + { + "name": "load_balancer_pool_member", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group membership- `deleting`: Membership is deleting dependent resources- `failed`: Membership was unable to maintain dependent resources- `healthy`: Membership is active and serving in the group- `pending`: Membership is waiting for dependent resources- `unhealthy`: Membership has unhealthy dependent resources.", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "The instance group identifier.", + "required": true + } + ], + "ibm_is_instance_group_memberships": [ + { + "name": "memberships", + "type": "TypeList", + "description": "Collection of instance group memberships.", + "computed": true, + "elem": { + "delete_instance_on_membership_delete": { + "name": "delete_instance_on_membership_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the membership the instance will also be deleted.", + "computed": true + }, + "instance": { + "name": "instance", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + }, + "virtual_server_instance": { + "name": "virtual_server_instance", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + } + } + }, + "instance_group_membership": { + "name": "instance_group_membership", + "type": "TypeString", + "description": "The unique identifier for this instance group membership.", + "computed": true + }, + "instance_template": { + "name": "instance_template", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance template.", + "computed": true + }, + "instance_template": { + "name": "instance_template", + "type": "TypeString", + "description": "The unique identifier for this instance template.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this instance template.", + "computed": true + } + } + }, + "load_balancer_pool_member": { + "name": "load_balancer_pool_member", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group membership. Names must be unique within the instance group.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group membership- `deleting`: Membership is deleting dependent resources- `failed`: Membership was unable to maintain dependent resources- `healthy`: Membership is active and serving in the group- `pending`: Membership is waiting for dependent resources- `unhealthy`: Membership has unhealthy dependent resources.", + "computed": true + } + } + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "The instance group identifier.", + "required": true + } + ], + "ibm_is_instance_groups": [ + { + "name": "instance_groups", + "type": "TypeList", + "description": "Collection of instance groups.", + "computed": true, + "elem": { + "application_port": { + "name": "application_port", + "type": "TypeInt", + "description": "Required if specifying a load balancer pool only. Used by the instance group when scaling up instances to supply the port for the load balancer pool member.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the instance group was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance group.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance group.", + "computed": true + }, + "instance_template": { + "name": "instance_template", + "type": "TypeList", + "description": "The template used to create new instances for this group.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance template.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance template.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance template.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this instance template.", + "computed": true + } + } + }, + "load_balancer_pool": { + "name": "load_balancer_pool", + "type": "TypeList", + "description": "The load balancer pool managed by this group. Instances createdby this group will have a new load balancer pool member in thatpool created.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + } + } + }, + "managers": { + "name": "managers", + "type": "TypeList", + "description": "The managers for the instance group.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance group manager.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance group manager.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group manager.", + "computed": true + } + } + }, + "membership_count": { + "name": "membership_count", + "type": "TypeInt", + "description": "The number of instances in the instance group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group- `deleting`: Group is being deleted- `healthy`: Group has `membership_count` instances- `scaling`: Instances in the group are being created or deleted to reach `membership_count`- `unhealthy`: Group is unable to reach `membership_count` instances.", + "computed": true + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "description": "The subnets to use when creating new instances.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that the instance group was updated.", + "computed": true + }, + "vpc": { + "name": "vpc", + "type": "TypeList", + "description": "The VPC the instance group resides in.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + } + } + } + ], + "ibm_is_instance_network_interface": [ + { + "name": "network_interface_name", + "type": "TypeString", + "description": "The network interface name.", + "required": true + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps.", + "computed": true + }, + { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "The primary IPv4 address.", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeList", + "description": "Collection of security groups.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of this network interface as it relates to an instance.", + "computed": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP.", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + { + "name": "subnet", + "type": "TypeList", + "description": "The associated subnet.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "instance_name", + "type": "TypeString", + "description": "The instance name.", + "required": true + }, + { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the network interface was created.", + "computed": true + }, + { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface.", + "computed": true + } + ], + "ibm_is_instance_network_interface_reserved_ip": [ + { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The instance network interface identifier.", + "required": true + }, + { + "name": "reserved_ip", + "type": "TypeString", + "description": "The reserved IP identifier.", + "required": true + }, + { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id.", + "computed": true + }, + { + "name": "instance", + "type": "TypeString", + "description": "The instance identifier.", + "required": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this reserved IP will be automatically deleted", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + ], + "ibm_is_instance_network_interface_reserved_ips": [ + { + "name": "instance", + "type": "TypeString", + "description": "The instance identifier.", + "required": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The instance network interface identifier.", + "required": true + }, + { + "name": "reserved_ips", + "type": "TypeList", + "description": "Collection of reserved IPs in this subnet.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "If reserved ip shall be deleted automatically", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "owner": { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this reserved IP", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages", + "computed": true + } + ], + "ibm_is_instance_network_interfaces": [ + { + "name": "instance_name", + "type": "TypeString", + "description": "The instance name.", + "required": true + }, + { + "name": "network_interfaces", + "type": "TypeList", + "description": "Collection of network interfaces.", + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the network interface was created.", + "computed": true + }, + "floating_ips": { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps.", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "The primary IPv4 address.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeList", + "description": "Collection of security groups.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface.", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeList", + "description": "The associated subnet.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of this network interface as it relates to an instance.", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages.", + "computed": true + } + ], + "ibm_is_instance_profile": [ + { + "name": "architecture_type", + "type": "TypeString", + "description": "The type for the OS architecture.", + "computed": true + }, + { + "name": "gpu_model", + "type": "TypeList", + "description": "GPU model of this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The possible GPU model(s) for an instance with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "total_volume_bandwidth", + "type": "TypeList", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes. An increase in this value will result in a corresponding decrease to total_network_bandwidth.", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "vcpu_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "family", + "type": "TypeString", + "description": "The product family this virtual server instance profile belongs to.", + "computed": true + }, + { + "name": "architecture_values", + "type": "TypeList", + "description": "The supported OS architecture(s) for an instance with this profile.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "bandwidth", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "architecture", + "type": "TypeString", + "description": "The default OS architecture for an instance with this profile.", + "computed": true + }, + { + "name": "gpu_manufacturer", + "type": "TypeList", + "description": "GPU manufacturer of this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The possible GPU manufacturer(s) for an instance with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance profile's disks.", + "computed": true, + "elem": { + "quantity": { + "name": "quantity", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "supported_interface_types": { + "name": "supported_interface_types", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The supported disk interfaces used for attaching the disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "port_speed", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + } + } + }, + { + "name": "vcpu_architecture", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The default VCPU architecture for an instance with this profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The VCPU architecture for an instance with this profile.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "required": true + }, + { + "name": "gpu_count", + "type": "TypeList", + "description": "GPU count of this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "gpu_memory", + "type": "TypeList", + "description": "GPU memory of this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + } + ], + "ibm_is_instance_profiles": [ + { + "name": "profiles", + "type": "TypeList", + "description": "List of instance profile maps", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The default OS architecture for an instance with this profile.", + "computed": true + }, + "architecture_type": { + "name": "architecture_type", + "type": "TypeString", + "description": "The type for the OS architecture.", + "computed": true + }, + "architecture_values": { + "name": "architecture_values", + "type": "TypeList", + "description": "The supported OS architecture(s) for an instance with this profile.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "bandwidth": { + "name": "bandwidth", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance profile's disks.", + "computed": true, + "elem": { + "quantity": { + "name": "quantity", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "size": { + "name": "size", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "supported_interface_types": { + "name": "supported_interface_types", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The supported disk interfaces used for attaching the disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + "family": { + "name": "family", + "type": "TypeString", + "description": "The product family this virtual server instance profile belongs to.", + "computed": true + }, + "gpu_count": { + "name": "gpu_count", + "type": "TypeList", + "description": "GPU count of this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "gpu_manufacturer": { + "name": "gpu_manufacturer", + "type": "TypeList", + "description": "GPU manufacturer of this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The possible GPU manufacturer(s) for an instance with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "gpu_memory": { + "name": "gpu_memory", + "type": "TypeList", + "description": "GPU memory of this profile", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "gpu_model": { + "name": "gpu_model", + "type": "TypeList", + "description": "GPU model of this profile", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The possible GPU model(s) for an instance with this profile", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeList", + "computed": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + } + } + }, + "total_volume_bandwidth": { + "name": "total_volume_bandwidth", + "type": "TypeList", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes. An increase in this value will result in a corresponding decrease to total_network_bandwidth.", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + }, + "vcpu_architecture": { + "name": "vcpu_architecture", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeString", + "description": "The default VCPU architecture for an instance with this profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The VCPU architecture for an instance with this profile.", + "computed": true + } + } + }, + "vcpu_count": { + "name": "vcpu_count", + "type": "TypeList", + "computed": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "The default value for this profile field.", + "computed": true + }, + "max": { + "name": "max", + "type": "TypeInt", + "description": "The maximum value for this profile field.", + "computed": true + }, + "min": { + "name": "min", + "type": "TypeInt", + "description": "The minimum value for this profile field.", + "computed": true + }, + "step": { + "name": "step", + "type": "TypeInt", + "description": "The increment step value for this profile field.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type for this profile field.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeInt", + "description": "The value for this profile field.", + "computed": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "The permitted values for this profile field.", + "computed": true, + "elem": { + "type": "TypeInt" + } + } + } + } + } + } + ], + "ibm_is_instance_template": [ + { + "name": "identifier", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "computed": true + }, + { + "name": "user_data", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions to use for the virtual server instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + } + } + }, + { + "name": "default_trusted_profile_target", + "type": "TypeString", + "description": "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + "computed": true + }, + { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + "computed": true + }, + { + "name": "primary_network_interface", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "network_interfaces", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "computed": true + }, + { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "computed": true + }, + { + "name": "volume_attachments", + "type": "TypeList", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "volume": { + "name": "volume", + "type": "TypeString", + "computed": true + }, + "volume_prototype": { + "name": "volume_prototype", + "type": "TypeList", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeInt", + "description": "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + "computed": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + "computed": true + }, + "iops": { + "name": "iops", + "type": "TypeInt", + "description": "The maximum I/O operations per second (IOPS) for the volume.", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "The globally unique name for the volume profile to use for this volume.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "The user tags associated with this volume.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "boot_volume_attachment", + "type": "TypeList", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "The user tags associated with this volume.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "volume": { + "name": "volume", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "computed": true + }, + { + "name": "keys", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "computed": true + }, + { + "name": "default_trusted_profile_auto_link", + "type": "TypeBool", + "description": "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + "computed": true + }, + { + "name": "image", + "type": "TypeString", + "computed": true + } + ], + "ibm_is_instance_templates": [ + { + "name": "templates", + "type": "TypeList", + "description": "Collection of instance templates", + "computed": true, + "elem": { + "availability_policy_host_failure": { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + "computed": true + }, + "boot_volume_attachment": { + "name": "boot_volume_attachment", + "type": "TypeList", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "The user tags associated with this volume.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "volume": { + "name": "volume", + "type": "TypeString", + "computed": true + } + } + }, + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "default_trusted_profile_auto_link": { + "name": "default_trusted_profile_auto_link", + "type": "TypeBool", + "description": "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + "computed": true + }, + "default_trusted_profile_target": { + "name": "default_trusted_profile_target", + "type": "TypeString", + "description": "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "image": { + "name": "image", + "type": "TypeString", + "computed": true + }, + "keys": { + "name": "keys", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "metadata_service_enabled": { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "network_interfaces": { + "name": "network_interfaces", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + "placement_target": { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions for the virtual server instance. For the target tobe changed, the instance `status` must be `stopping` or `stopped`.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + } + } + }, + "primary_network_interface": { + "name": "primary_network_interface", + "type": "TypeList", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + } + } + }, + "profile": { + "name": "profile", + "type": "TypeString", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "computed": true + }, + "total_volume_bandwidth": { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "computed": true + }, + "user_data": { + "name": "user_data", + "type": "TypeString", + "computed": true + }, + "volume_attachments": { + "name": "volume_attachments", + "type": "TypeList", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "volume": { + "name": "volume", + "type": "TypeString", + "computed": true + }, + "volume_prototype": { + "name": "volume_prototype", + "type": "TypeList", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeInt", + "description": "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + "computed": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + "computed": true + }, + "iops": { + "name": "iops", + "type": "TypeInt", + "description": "The maximum I/O operations per second (IOPS) for the volume.", + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "The globally unique name for the volume profile to use for this volume.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "The user tags associated with this volume.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_instance_volume_attachment": [ + { + "name": "instance", + "type": "TypeString", + "description": "Instance id", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this volume attachment.", + "required": true + }, + { + "name": "volume_attachment_id", + "type": "TypeString", + "description": "The unique identifier for this volume attachment", + "computed": true + }, + { + "name": "volume_reference", + "type": "TypeList", + "description": "The attached volume", + "computed": true, + "elem": { + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "The CRN for this volume", + "computed": true + }, + "volume_deleted": { + "name": "volume_deleted", + "type": "TypeString", + "description": "Link to documentation about deleted resources", + "computed": true + }, + "volume_href": { + "name": "volume_href", + "type": "TypeString", + "description": "The URL for this volume", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "The unique identifier for this volume", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "description": "The unique user-defined name for this volume", + "computed": true + } + } + }, + { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the instance the volume will also be deleted.", + "computed": true + }, + { + "name": "device", + "type": "TypeString", + "description": "A unique identifier for the device which is exposed to the instance operating system", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume attachment", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of this volume attachment, one of [ attached, attaching, deleting, detaching ]", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of volume attachment one of [ boot, data ]", + "computed": true + } + ], + "ibm_is_instance_volume_attachments": [ + { + "name": "instance", + "type": "TypeString", + "description": "Instance id", + "required": true + }, + { + "name": "volume_attachments", + "type": "TypeList", + "description": "List of volume attachments on an instance", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the instance the volume will also be deleted.", + "computed": true + }, + "device": { + "name": "device", + "type": "TypeString", + "description": "A unique identifier for the device which is exposed to the instance operating system", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume attachment", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this volume attachment.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of this volume attachment, one of [ attached, attaching, deleting, detaching ]", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of volume attachment one of [ boot, data ]", + "computed": true + }, + "volume_attachment_id": { + "name": "volume_attachment_id", + "type": "TypeString", + "description": "The unique identifier for this volume attachment", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "The CRN for this volume", + "computed": true + }, + "volume_deleted": { + "name": "volume_deleted", + "type": "TypeString", + "description": "Link to documentation about deleted resources", + "computed": true + }, + "volume_href": { + "name": "volume_href", + "type": "TypeString", + "description": "The URL for this volume", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "The unique identifier for this volume", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "description": "The unique user-defined name for this volume", + "computed": true + }, + "volume_reference": { + "name": "volume_reference", + "type": "TypeList", + "description": "The attached volume", + "computed": true, + "elem": {} + } + } + } + ], + "ibm_is_instances": [ + { + "name": "instance_group_name", + "type": "TypeString", + "description": "Instance group name to filter the instances attached to it", + "optional": true + }, + { + "name": "vpc_name", + "type": "TypeString", + "description": "Name of the vpc to filter the instances attached to it", + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Instance resource group", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "dedicated_host_name", + "type": "TypeString", + "description": "Name of the dedicated host to filter the instances attached to it", + "optional": true + }, + { + "name": "dedicated_host", + "type": "TypeString", + "description": "ID of the dedicated host to filter the instances attached to it", + "optional": true + }, + { + "name": "placement_group_name", + "type": "TypeString", + "description": "Name of the placement group to filter the instances attached to it", + "optional": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "Instance group ID to filter the instances attached to it", + "optional": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC ID to filter the instances attached to it", + "optional": true + }, + { + "name": "vpc_crn", + "type": "TypeString", + "description": "VPC CRN to filter the instances attached to it", + "optional": true + }, + { + "name": "placement_group", + "type": "TypeString", + "description": "ID of the placement group to filter the instances attached to it", + "optional": true + }, + { + "name": "instances", + "type": "TypeList", + "description": "List of instances", + "computed": true, + "elem": { + "availability_policy_host_failure": { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure.", + "computed": true + }, + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + "computed": true + }, + "boot_volume": { + "name": "boot_volume", + "type": "TypeList", + "description": "Instance Boot Volume", + "computed": true, + "elem": { + "device": { + "name": "device", + "type": "TypeString", + "description": "Instance Boot volume device", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Boot volume id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Boot volume name", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "Instance Boot volume's volume CRN", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "Instance Boot volume's volume id", + "computed": true + } + } + }, + "catalog_offering": { + "name": "catalog_offering", + "type": "TypeList", + "description": "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + "computed": true, + "elem": { + "offering_crn": { + "name": "offering_crn", + "type": "TypeString", + "description": "Identifies a catalog offering by a unique CRN property", + "computed": true + }, + "version_crn": { + "name": "version_crn", + "type": "TypeString", + "description": "Identifies a version of a catalog offering by a unique CRN property", + "computed": true + } + } + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn for this Instance", + "computed": true + }, + "disks": { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance's disks.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + "gpu": { + "name": "gpu", + "type": "TypeList", + "description": "Instance GPU", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "description": "Instance GPU Count", + "computed": true + }, + "manufacturer": { + "name": "manufacturer", + "type": "TypeString", + "description": "Instance GPU Manufacturer", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "Instance GPU Memory", + "computed": true + }, + "model": { + "name": "model", + "type": "TypeString", + "description": "Instance GPU Model", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance id", + "computed": true + }, + "image": { + "name": "image", + "type": "TypeString", + "description": "Instance Image", + "optional": true, + "computed": true + }, + "lifecycle_reasons": { + "name": "lifecycle_reasons", + "type": "TypeList", + "description": "The reasons for the current lifecycle_state (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the reason for this lifecycle state.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the reason for this lifecycle state.", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about the reason for this lifecycle state.", + "computed": true + } + } + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the virtual server instance.", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "Instance memory", + "computed": true + }, + "metadata_service_enabled": { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance name", + "computed": true + }, + "network_interfaces": { + "name": "network_interfaces", + "type": "TypeList", + "description": "Instance Network Interfaces", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Network interface id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Network interface name", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "Instance Network interface IPV4 Address", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Instance Network interface security groups", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "Instance Network interface subnet", + "computed": true + } + } + }, + "placement_target": { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions for the virtual server instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement target resource.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement target resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this placement target resource.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this placement target resource. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + "primary_network_interface": { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Instance Primary Network Interface", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance Primary Network interface id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance Primary Network interface name", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "Instance Primary Network interface IPV4 Address", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Instance Primary Network interface security groups", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "Instance Primary Network interface subnet", + "computed": true + } + } + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "Instance Profile", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Instance resource group", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Instance status", + "computed": true + }, + "status_reasons": { + "name": "status_reasons", + "type": "TypeList", + "description": "The reasons for the current status (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + "total_network_bandwidth": { + "name": "total_network_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + "computed": true + }, + "total_volume_bandwidth": { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeList", + "description": "Instance vcpu", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "Instance vcpu architecture", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "Instance vcpu count", + "computed": true + } + } + }, + "volume_attachments": { + "name": "volume_attachments", + "type": "TypeList", + "description": "Instance Volume Attachments", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Instance volume Attachment id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Instance volume Attachment name", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "description": "Instance volume Attachment's volume CRN", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "description": "Instance volume Attachment's volume id", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "description": "Instance volume Attachment's volume name", + "computed": true + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "description": "vpc attached to the instance", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "Instance zone", + "computed": true + } + } + } + ], + "ibm_is_ipsec_policies": [ + { + "name": "ipsec_policies", + "type": "TypeList", + "description": "Collection of IPsec policies.", + "computed": true, + "elem": { + "authentication_algorithm": { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "The authentication algorithm.", + "computed": true + }, + "connections": { + "name": "connections", + "type": "TypeList", + "description": "The VPN gateway connections that use this IPsec policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this IPsec policy was created.", + "computed": true + }, + "encapsulation_mode": { + "name": "encapsulation_mode", + "type": "TypeString", + "description": "The encapsulation mode used. Only `tunnel` is supported.", + "computed": true + }, + "encryption_algorithm": { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "The encryption algorithm.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The IPsec policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this IPsec policy.", + "computed": true + }, + "key_lifetime": { + "name": "key_lifetime", + "type": "TypeInt", + "description": "The key lifetime in seconds.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this IPsec policy.", + "computed": true + }, + "pfs": { + "name": "pfs", + "type": "TypeString", + "description": "Perfect Forward Secrecy.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this IPsec policy.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "transform_protocol": { + "name": "transform_protocol", + "type": "TypeString", + "description": "The transform protocol used. Only `esp` is supported.", + "computed": true + } + } + } + ], + "ibm_is_ipsec_policy": [ + { + "name": "href", + "type": "TypeString", + "description": "The IPsec policy's canonical URL.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "transform_protocol", + "type": "TypeString", + "description": "The transform protocol used. Only `esp` is supported.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The IPsec policy name.", + "optional": true + }, + { + "name": "connections", + "type": "TypeList", + "description": "The VPN gateway connections that use this IPsec policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this IPsec policy was created.", + "computed": true + }, + { + "name": "encapsulation_mode", + "type": "TypeString", + "description": "The encapsulation mode used. Only `tunnel` is supported.", + "computed": true + }, + { + "name": "pfs", + "type": "TypeString", + "description": "Perfect Forward Secrecy.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this IPsec policy.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "ipsec_policy", + "type": "TypeString", + "description": "The IPsec policy identifier.", + "optional": true + }, + { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "The authentication algorithm.", + "computed": true + }, + { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "The encryption algorithm.", + "computed": true + }, + { + "name": "key_lifetime", + "type": "TypeInt", + "description": "The key lifetime in seconds.", + "computed": true + } + ], + "ibm_is_lb": [ + { + "name": "status", + "type": "TypeString", + "description": "Load Balancer status", + "computed": true + }, + { + "name": "operating_status", + "type": "TypeString", + "description": "Load Balancer operating status", + "computed": true + }, + { + "name": "subnets", + "type": "TypeSet", + "description": "Load Balancer subnets list", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Load Balancer type", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Load Balancer", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "private_ip", + "type": "TypeList", + "description": "The private IP addresses assigned to this load balancer.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Load Balancer name", + "required": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Load Balancer securitygroups list", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags associated to Load Balancer", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Load Balancer Resource group", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "logging", + "type": "TypeBool", + "description": "Logging of Load Balancer", + "computed": true + }, + { + "name": "listeners", + "type": "TypeSet", + "description": "Load Balancer Listeners list", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pools", + "type": "TypeList", + "description": "Load Balancer Pools list", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "The load balancing algorithm.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this pool was created.", + "computed": true + }, + "health_monitor": { + "name": "health_monitor", + "type": "TypeMap", + "description": "The health monitor of this pool.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool", + "computed": true + }, + "instance_group": { + "name": "instance_group", + "type": "TypeMap", + "description": "The instance group that is managing this pool.", + "computed": true + }, + "members": { + "name": "members", + "type": "TypeList", + "description": "The backend server members of the pool.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The member's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol used for this load balancer pool.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this pool.", + "computed": true + }, + "session_persistence": { + "name": "session_persistence", + "type": "TypeMap", + "description": "The session persistence of this pool.", + "computed": true + } + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "udp_supported", + "type": "TypeBool", + "description": "Indicates whether this load balancer supports UDP.", + "computed": true + }, + { + "name": "route_mode", + "type": "TypeBool", + "description": "Indicates whether route mode is enabled for this load balancer", + "computed": true + }, + { + "name": "public_ips", + "type": "TypeList", + "description": "Load Balancer Public IPs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "private_ips", + "type": "TypeList", + "description": "Load Balancer private IPs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "security_group_supported", + "type": "TypeBool", + "description": "Security Group Supported for this Load Balancer", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Load Balancer Host Name", + "computed": true + } + ], + "ibm_is_lb_listener": [ + { + "name": "protocol", + "type": "TypeString", + "description": "The listener protocol. Load balancers in the `network` family support `tcp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "listener_id", + "type": "TypeString", + "description": "The listener identifier.", + "required": true + }, + { + "name": "connection_limit", + "type": "TypeInt", + "description": "The connection limit of the listener.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this listener was created.", + "computed": true + }, + { + "name": "https_redirect", + "type": "TypeList", + "description": "If specified, the target listener that requests are redirected to.", + "computed": true, + "elem": { + "http_status_code": { + "name": "http_status_code", + "type": "TypeInt", + "description": "The HTTP status code for this redirect.", + "computed": true + }, + "listener": { + "name": "listener", + "type": "TypeList", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener.", + "computed": true + } + } + }, + "uri": { + "name": "uri", + "type": "TypeString", + "description": "The redirect relative target URI.", + "computed": true + } + } + }, + { + "name": "policies", + "type": "TypeList", + "description": "The policies for this listener.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The policy's unique identifier.", + "computed": true + } + } + }, + { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + "computed": true + }, + { + "name": "accept_proxy_protocol", + "type": "TypeBool", + "description": "If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value.", + "computed": true + }, + { + "name": "default_pool", + "type": "TypeList", + "description": "The default pool associated with the listener.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + { + "name": "certificate_instance", + "type": "TypeList", + "description": "The certificate instance used for SSL termination. It is applicable only to `https`protocol.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this certificate instance.", + "computed": true + } + } + }, + { + "name": "port", + "type": "TypeInt", + "description": "The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + "computed": true + }, + { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this listener.", + "computed": true + } + ], + "ibm_is_lb_listener_policies": [ + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "listener", + "type": "TypeString", + "description": "The listener identifier.", + "required": true + }, + { + "name": "policies", + "type": "TypeList", + "description": "Collection of policies.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this policy was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The policy's unique identifier.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this policy.", + "computed": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "Priority of the policy. Lower value indicates higher priority.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this policy.", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "The rules for this policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The rule's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The rule's unique identifier.", + "computed": true + } + } + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "- If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "http_status_code": { + "name": "http_status_code", + "type": "TypeInt", + "description": "The HTTP status code for this redirect.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "listener": { + "name": "listener", + "type": "TypeList", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + }, + "uri": { + "name": "uri", + "type": "TypeString", + "description": "The redirect relative target URI.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "The redirect target URL.", + "computed": true + } + } + } + } + } + ], + "ibm_is_lb_listener_policy": [ + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "listener", + "type": "TypeString", + "description": "The listener identifier.", + "required": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "The policy identifier.", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this policy.", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "The rules for this policy.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The rule's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The rule's unique identifier.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this policy was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The listener policy's canonical URL.", + "computed": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "Priority of the policy. Lower value indicates higher priority.", + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this policy.", + "computed": true + }, + { + "name": "target", + "type": "TypeList", + "description": "- If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "http_status_code": { + "name": "http_status_code", + "type": "TypeInt", + "description": "The HTTP status code for this redirect.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "listener": { + "name": "listener", + "type": "TypeList", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + }, + "uri": { + "name": "uri", + "type": "TypeString", + "description": "The redirect relative target URI.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "The redirect target URL.", + "computed": true + } + } + } + ], + "ibm_is_lb_listener_policy_rule": [ + { + "name": "listener", + "type": "TypeString", + "description": "The listener identifier.", + "required": true + }, + { + "name": "policy", + "type": "TypeString", + "description": "The policy identifier.", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this rule was created.", + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this rule.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set.", + "computed": true + }, + { + "name": "value", + "type": "TypeString", + "description": "Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded.", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "rule", + "type": "TypeString", + "description": "The rule identifier.", + "required": true + }, + { + "name": "condition", + "type": "TypeString", + "description": "The condition of the rule.", + "computed": true + }, + { + "name": "field", + "type": "TypeString", + "description": "The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The rule's canonical URL.", + "computed": true + } + ], + "ibm_is_lb_listener_policy_rules": [ + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "listener", + "type": "TypeString", + "description": "The listener identifier.", + "required": true + }, + { + "name": "policy", + "type": "TypeString", + "description": "The policy identifier.", + "required": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Collection of rules.", + "computed": true, + "elem": { + "condition": { + "name": "condition", + "type": "TypeString", + "description": "The condition of the rule.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this rule was created.", + "computed": true + }, + "field": { + "name": "field", + "type": "TypeString", + "description": "The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The rule's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The rule's unique identifier.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this rule.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded.", + "computed": true + } + } + } + ], + "ibm_is_lb_listeners": [ + { + "name": "listeners", + "type": "TypeList", + "description": "Collection of listeners.", + "computed": true, + "elem": { + "accept_proxy_protocol": { + "name": "accept_proxy_protocol", + "type": "TypeBool", + "description": "If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value.", + "computed": true + }, + "certificate_instance": { + "name": "certificate_instance", + "type": "TypeList", + "description": "The certificate instance used for SSL termination. It is applicable only to `https`protocol.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this certificate instance.", + "computed": true + } + } + }, + "connection_limit": { + "name": "connection_limit", + "type": "TypeInt", + "description": "The connection limit of the listener.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this listener was created.", + "computed": true + }, + "default_pool": { + "name": "default_pool", + "type": "TypeList", + "description": "The default pool associated with the listener.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "https_redirect": { + "name": "https_redirect", + "type": "TypeList", + "description": "If specified, the target listener that requests are redirected to.", + "computed": true, + "elem": { + "http_status_code": { + "name": "http_status_code", + "type": "TypeInt", + "description": "The HTTP status code for this redirect.", + "computed": true + }, + "listener": { + "name": "listener", + "type": "TypeList", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener.", + "computed": true + } + } + }, + "uri": { + "name": "uri", + "type": "TypeString", + "description": "The redirect relative target URI.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener.", + "computed": true + }, + "policies": { + "name": "policies", + "type": "TypeList", + "description": "The policies for this listener.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The policy's unique identifier.", + "computed": true + } + } + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The listener protocol. Load balancers in the `network` family support `tcp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this listener.", + "computed": true + } + } + }, + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "immutable": true, + "required": true + } + ], + "ibm_is_lb_pool": [ + { + "name": "protocol", + "type": "TypeString", + "description": "The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this pool.", + "computed": true + }, + { + "name": "proxy_protocol", + "type": "TypeString", + "description": "The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`).", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "optional": true, + "computed": true + }, + { + "name": "algorithm", + "type": "TypeString", + "description": "The load balancing algorithm.", + "computed": true + }, + { + "name": "health_monitor", + "type": "TypeList", + "description": "The health monitor of this pool.", + "computed": true, + "elem": { + "delay": { + "name": "delay", + "type": "TypeInt", + "description": "The health check interval in seconds. Interval must be greater than timeout value.", + "computed": true + }, + "max_retries": { + "name": "max_retries", + "type": "TypeInt", + "description": "The health check max retries.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "The health check port number. If specified, this overrides the ports specified in the server member resources.", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The health check timeout in seconds.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered.", + "computed": true + }, + "url_path": { + "name": "url_path", + "type": "TypeString", + "description": "The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1).", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The pool identifier.", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this pool was created.", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeList", + "description": "The instance group that is managing this pool.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance group.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group.", + "computed": true + } + } + }, + { + "name": "members", + "type": "TypeList", + "description": "The backend server members of the pool.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The member's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + } + } + }, + { + "name": "session_persistence", + "type": "TypeList", + "description": "The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered.", + "computed": true, + "elem": { + "cookie_name": { + "name": "cookie_name", + "type": "TypeString", + "description": "The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols.", + "computed": true + } + } + } + ], + "ibm_is_lb_pool_member": [ + { + "name": "weight", + "type": "TypeInt", + "description": "Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`.", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "pool", + "type": "TypeString", + "description": "The pool identifier.", + "required": true + }, + { + "name": "member", + "type": "TypeString", + "description": "The member identifier.", + "required": true + }, + { + "name": "health", + "type": "TypeString", + "description": "Health of the server member in the pool.", + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this member.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this member was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The member's canonical URL.", + "computed": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "The port number of the application running in the server member.", + "computed": true + }, + { + "name": "target", + "type": "TypeList", + "description": "The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + } + ], + "ibm_is_lb_pool_members": [ + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "pool", + "type": "TypeString", + "description": "The pool identifier.", + "required": true + }, + { + "name": "members", + "type": "TypeList", + "description": "Collection of members.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this member was created.", + "computed": true + }, + "health": { + "name": "health", + "type": "TypeString", + "description": "Health of the server member in the pool.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The member's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "The port number of the application running in the server member.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this member.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + }, + "weight": { + "name": "weight", + "type": "TypeInt", + "description": "Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`.", + "computed": true + } + } + } + ], + "ibm_is_lb_pools": [ + { + "name": "lb", + "type": "TypeString", + "description": "The load balancer identifier.", + "required": true + }, + { + "name": "pools", + "type": "TypeList", + "description": "Collection of pools.", + "computed": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "The load balancing algorithm.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this pool was created.", + "computed": true + }, + "health_monitor": { + "name": "health_monitor", + "type": "TypeList", + "description": "The health monitor of this pool.", + "computed": true, + "elem": { + "delay": { + "name": "delay", + "type": "TypeInt", + "description": "The health check interval in seconds. Interval must be greater than timeout value.", + "computed": true + }, + "max_retries": { + "name": "max_retries", + "type": "TypeInt", + "description": "The health check max retries.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "The health check port number. If specified, this overrides the ports specified in the server member resources.", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The health check timeout in seconds.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered.", + "computed": true + }, + "url_path": { + "name": "url_path", + "type": "TypeString", + "description": "The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1).", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool.", + "computed": true + }, + "instance_group": { + "name": "instance_group", + "type": "TypeList", + "description": "The instance group that is managing this pool.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance group.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group.", + "computed": true + } + } + }, + "members": { + "name": "members", + "type": "TypeList", + "description": "The backend server members of the pool.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The member's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered.", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this pool.", + "computed": true + }, + "proxy_protocol": { + "name": "proxy_protocol", + "type": "TypeString", + "description": "The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`).", + "computed": true + }, + "session_persistence": { + "name": "session_persistence", + "type": "TypeList", + "description": "The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered.", + "computed": true, + "elem": { + "cookie_name": { + "name": "cookie_name", + "type": "TypeString", + "description": "The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols.", + "computed": true + } + } + } + } + } + ], + "ibm_is_lb_profiles": [ + { + "name": "lb_profiles", + "type": "TypeList", + "description": "Collection of load balancer profile collectors", + "computed": true, + "elem": { + "family": { + "name": "family", + "type": "TypeString", + "description": "The product family this load balancer profile belongs to", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this load balancer profile", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name for this load balancer profile", + "computed": true + }, + "route_mode_supported": { + "name": "route_mode_supported", + "type": "TypeBool", + "description": "The route mode support for a load balancer with this profile depends on its configuration", + "computed": true + }, + "route_mode_type": { + "name": "route_mode_type", + "type": "TypeString", + "description": "The route mode type for this load balancer profile, one of [fixed, dependent]", + "computed": true + }, + "udp_supported": { + "name": "udp_supported", + "type": "TypeBool", + "description": "The UDP support for a load balancer with this profile", + "computed": true + }, + "udp_supported_type": { + "name": "udp_supported_type", + "type": "TypeString", + "description": "The UDP support type for a load balancer with this profile", + "computed": true + } + } + } + ], + "ibm_is_lbs": [ + { + "name": "load_balancers", + "type": "TypeList", + "description": "Collection of load balancers", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this pool was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The load balancer's CRN", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Load Balancer Host Name", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "listeners": { + "name": "listeners", + "type": "TypeList", + "description": "Load Balancer Listeners list", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The listener's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer listener", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Load Balancer name", + "computed": true + }, + "operating_status": { + "name": "operating_status", + "type": "TypeString", + "description": "Load Balancer operating status", + "computed": true + }, + "pools": { + "name": "pools", + "type": "TypeList", + "description": "Load Balancer Pools list", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The pool's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer pool", + "computed": true + } + } + }, + "private_ip": { + "name": "private_ip", + "type": "TypeList", + "description": "The private IP addresses assigned to this load balancer.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "private_ips": { + "name": "private_ips", + "type": "TypeList", + "description": "Load Balancer private IPs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "profile": { + "name": "profile", + "type": "TypeMap", + "description": "The profile to use for this load balancer", + "computed": true + }, + "provisioning_status": { + "name": "provisioning_status", + "type": "TypeString", + "description": "The provisioning status of this load balancer", + "computed": true + }, + "public_ips": { + "name": "public_ips", + "type": "TypeList", + "description": "Load Balancer Public IPs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_controller_url": { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Load Balancer Resource group", + "computed": true + }, + "resource_group_name": { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + "resource_name": { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + "route_mode": { + "name": "route_mode", + "type": "TypeBool", + "description": "Load Balancer route mode", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Load Balancer status", + "computed": true + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "description": "Load Balancer subnets list", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The subnet's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this load balancer subnet", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this load balancer subnet", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "Tags associated to Load Balancer", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Load Balancer type", + "computed": true + }, + "udp_supported": { + "name": "udp_supported", + "type": "TypeBool", + "description": "Indicates whether this load balancer supports UDP.", + "computed": true + } + } + } + ], + "ibm_is_network_acl": [ + { + "name": "name", + "type": "TypeString", + "description": "The network acl name.", + "optional": true + }, + { + "name": "vpc_name", + "type": "TypeString", + "description": "The name of the vpc the network acl resides in.", + "optional": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "The ordered rules for this network ACL. If no rules exist, all traffic will be denied.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic.", + "computed": true + }, + "before": { + "name": "before", + "type": "TypeList", + "description": "The rule that this rule is immediately before. In a rule collection, this alwaysrefers to the next item in the collection. If absent, this is the last rule.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network ACL rule.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network ACL rule.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the rule was created.", + "computed": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "The destination CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Whether the traffic to be matched is `inbound` or `outbound`.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule.", + "computed": true + }, + "icmp": { + "name": "icmp", + "type": "TypeList", + "description": "The protocol ICMP", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow. Valid values from 0 to 255.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow. Valid values from 0 to 254.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network ACL rule.", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "The source CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + "computed": true + }, + "tcp": { + "name": "tcp", + "type": "TypeList", + "description": "TCP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + }, + "udp": { + "name": "udp", + "type": "TypeList", + "description": "UDP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + } + } + }, + { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this network ACL is a part of.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this network ACL.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "subnets", + "type": "TypeList", + "description": "The subnets to which this network ACL is attached.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + { + "name": "network_acl", + "type": "TypeString", + "description": "The network acl id.", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the network ACL was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this network ACL.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL.", + "computed": true + } + ], + "ibm_is_network_acl_rule": [ + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule", + "required": true + }, + { + "name": "source", + "type": "TypeString", + "description": "The source IP address or CIDR block.", + "computed": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination IP address or CIDR block.", + "computed": true + }, + { + "name": "tcp", + "type": "TypeList", + "description": "TCP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + }, + { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic.", + "computed": true + }, + { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule.", + "computed": true + }, + { + "name": "udp", + "type": "TypeList", + "description": "UDP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + }, + { + "name": "network_acl", + "type": "TypeString", + "description": "Network ACL id", + "required": true + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "Network ACL rule id", + "computed": true + }, + { + "name": "before", + "type": "TypeString", + "description": "The rule that this rule is immediately before. If absent, this is the last rule.", + "computed": true + }, + { + "name": "icmp", + "type": "TypeList", + "description": "The protocol ICMP", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow. Valid values from 0 to 255.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow. Valid values from 0 to 254.", + "computed": true + } + } + }, + { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule", + "computed": true + }, + { + "name": "direction", + "type": "TypeString", + "description": "Whether the traffic to be matched is inbound or outbound.", + "computed": true + } + ], + "ibm_is_network_acl_rules": [ + { + "name": "network_acl", + "type": "TypeString", + "description": "Network ACL id", + "required": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "List of network acl rules", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic.", + "computed": true + }, + "before": { + "name": "before", + "type": "TypeString", + "description": "The rule that this rule is immediately before. If absent, this is the last rule.", + "computed": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "The destination IP address or CIDR block.", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Whether the traffic to be matched is inbound or outbound.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule.", + "computed": true + }, + "icmp": { + "name": "icmp", + "type": "TypeList", + "description": "The protocol ICMP", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow. Valid values from 0 to 255.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow. Valid values from 0 to 254.", + "computed": true + } + } + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "The network acl rule id.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "The source IP address or CIDR block.", + "computed": true + }, + "tcp": { + "name": "tcp", + "type": "TypeList", + "description": "TCP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + }, + "udp": { + "name": "udp", + "type": "TypeList", + "description": "UDP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + } + } + } + ], + "ibm_is_network_acls": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group identifier.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "network_acls", + "type": "TypeList", + "description": "Collection of network ACLs.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the network ACL was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this network ACL.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network ACL.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network ACL.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this network ACL.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "The ordered rules for this network ACL. If no rules exist, all traffic will be denied.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic.", + "computed": true + }, + "before": { + "name": "before", + "type": "TypeList", + "description": "The rule that this rule is immediately before. In a rule collection, this alwaysrefers to the next item in the collection. If absent, this is the last rule.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network ACL rule.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network ACL rule.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the rule was created.", + "computed": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "The destination CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Whether the traffic to be matched is `inbound` or `outbound`.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network ACL rule.", + "computed": true + }, + "icmp": { + "name": "icmp", + "type": "TypeList", + "description": "The protocol ICMP", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow. Valid values from 0 to 255.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow. Valid values from 0 to 254.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network ACL rule.", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "The source CIDR block. The CIDR block `0.0.0.0/0` applies to all addresses.", + "computed": true + }, + "tcp": { + "name": "tcp", + "type": "TypeList", + "description": "TCP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + }, + "udp": { + "name": "udp", + "type": "TypeList", + "description": "UDP protocol", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "computed": true + } + } + } + } + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "description": "The subnets to which this network ACL is attached.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this network ACL is a part of.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + } + } + } + ], + "ibm_is_operating_system": [ + { + "name": "version", + "type": "TypeString", + "description": "The major release version of this operating system", + "computed": true + }, + { + "name": "dedicated_host_only", + "type": "TypeBool", + "description": "Flag which shows images with this operating system can only be used on dedicated hosts or dedicated host groups", + "computed": true + }, + { + "name": "display_name", + "type": "TypeString", + "description": "A unique, display-friendly name for the operating system", + "computed": true + }, + { + "name": "family", + "type": "TypeString", + "description": "The name of the software family this operating system belongs to", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this operating system", + "computed": true + }, + { + "name": "vendor", + "type": "TypeString", + "description": "The vendor of the operating system", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this operating system", + "required": true + }, + { + "name": "architecture", + "type": "TypeString", + "description": "The operating system architecture", + "computed": true + } + ], + "ibm_is_operating_systems": [ + { + "name": "operating_systems", + "type": "TypeList", + "description": "List of operating systems", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The operating system architecture", + "computed": true + }, + "dedicated_host_only": { + "name": "dedicated_host_only", + "type": "TypeBool", + "description": "Flag which shows images with this operating system can only be used on dedicated hosts or dedicated host groups", + "computed": true + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "A unique, display-friendly name for the operating system", + "computed": true + }, + "family": { + "name": "family", + "type": "TypeString", + "description": "The name of the software family this operating system belongs to", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this operating system", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this operating system", + "computed": true + }, + "vendor": { + "name": "vendor", + "type": "TypeString", + "description": "The vendor of the operating system", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "description": "The major release version of this operating system", + "computed": true + } + } + } + ], + "ibm_is_placement_group": [ + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the placement group.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this placement group.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the placement group was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement group.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "strategy", + "type": "TypeString", + "description": "The strategy for this placement group- `host_spread`: place on different compute hosts- `power_spread`: place on compute hosts that use different power sourcesThe enumerated values for this property may expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the placement group on which the unexpected strategy was encountered.", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "access_tags", + "type": "TypeSet", + "description": "List of access management tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The placement group name.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement group.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_placement_groups": [ + { + "name": "placement_groups", + "type": "TypeList", + "description": "Collection of placement groups.", + "computed": true, + "elem": { + "access_tags": { + "name": "access_tags", + "type": "TypeSet", + "description": "List of access management tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the placement group was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement group.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this placement group.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the placement group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this placement group.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this placement group.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "strategy": { + "name": "strategy", + "type": "TypeString", + "description": "The strategy for this placement group- `host_spread`: place on different compute hosts- `power_spread`: place on compute hosts that use different power sourcesThe enumerated values for this property may expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the placement group on which the unexpected strategy was encountered.", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages.", + "computed": true + } + ], + "ibm_is_public_gateway": [ + { + "name": "tags", + "type": "TypeSet", + "description": "Service tags for the public gateway instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Public gateway Name", + "required": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Public gateway resource group info", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Public gateway VPC info", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Public gateway zone info", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "floating_ip", + "type": "TypeMap", + "description": "Public gateway floating IP", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Public gateway instance status", + "computed": true + } + ], + "ibm_is_public_gateways": [ + { + "name": "public_gateways", + "type": "TypeList", + "description": "List of public gateways", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + "floating_ip": { + "name": "floating_ip", + "type": "TypeMap", + "description": "Public gateway floating IP", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Public gateway id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Public gateway Name", + "computed": true + }, + "resource_controller_url": { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + "resource_crn": { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Public gateway resource group info", + "optional": true, + "computed": true + }, + "resource_group_name": { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + "resource_name": { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + "resource_status": { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Public gateway instance status", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "Service tags for the public gateway instance", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "description": "Public gateway VPC info", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "Public gateway zone info", + "computed": true + } + } + } + ], + "ibm_is_region": [ + { + "name": "endpoint", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + } + ], + "ibm_is_regions": [ + { + "name": "regions", + "type": "TypeList", + "description": "List of regions", + "computed": true, + "elem": { + "endpoint": { + "name": "endpoint", + "type": "TypeString", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_security_group": [ + { + "name": "vpc", + "type": "TypeString", + "description": "Security group's resource group id", + "immutable": true, + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Security Rules", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Rule id", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Security group name", + "required": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_security_group_rule": [ + { + "name": "security_group_rule", + "type": "TypeString", + "description": "The rule identifier.", + "required": true + }, + { + "name": "direction", + "type": "TypeString", + "description": "The direction of traffic to enforce, either `inbound` or `outbound`.", + "computed": true + }, + { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + "computed": true + }, + { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow.", + "computed": true + }, + { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of TCP/UDP port range.", + "computed": true + }, + { + "name": "security_group", + "type": "TypeString", + "description": "The security group identifier.", + "required": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this security group rule.", + "computed": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + { + "name": "remote", + "type": "TypeList", + "description": "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "cidr_block": { + "name": "cidr_block", + "type": "TypeString", + "description": "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow.", + "computed": true + }, + { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of TCP/UDP port range.", + "computed": true + } + ], + "ibm_is_security_group_rules": [ + { + "name": "security_group", + "type": "TypeString", + "description": "The security group identifier.", + "required": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Array of rules.", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow.", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "The direction of traffic to enforce, either `inbound` or `outbound`.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this security group rule.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group rule.", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of TCP/UDP port range.", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of TCP/UDP port range.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeList", + "description": "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "cidr_block": { + "name": "cidr_block", + "type": "TypeString", + "description": "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow.", + "computed": true + } + } + } + ], + "ibm_is_security_group_target": [ + { + "name": "security_group", + "type": "TypeString", + "description": "Security group id", + "required": true + }, + { + "name": "target", + "type": "TypeString", + "description": "security group target identifier", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Security group target name", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this security group target", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource Type", + "computed": true + }, + { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources", + "computed": true + } + ], + "ibm_is_security_group_targets": [ + { + "name": "security_group", + "type": "TypeString", + "description": "Security group id", + "required": true + }, + { + "name": "targets", + "type": "TypeList", + "description": "List of targets", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this target", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Security group target name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource Type", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "security group target identifier", + "computed": true + } + } + } + ], + "ibm_is_security_groups": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "resource group identifier.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "vpc_id", + "type": "TypeString", + "description": "vpc identifier.", + "optional": true + }, + { + "name": "vpc_crn", + "type": "TypeString", + "description": "vpc crn", + "optional": true + }, + { + "name": "vpc_name", + "type": "TypeString", + "description": "vpc name.", + "optional": true + }, + { + "name": "security_groups", + "type": "TypeList", + "description": "Collection of security groups.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this security group was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this security group.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "The rules for this security group. If no rules exist, all traffic will be denied.", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow.", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "The direction of traffic to enforce, either `inbound` or `outbound`.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this security group rule.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group rule.", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version.", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of TCP/UDP port range.", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of TCP/UDP port range.", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The protocol to enforce.", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeList", + "description": "The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules).", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "cidr_block": { + "name": "cidr_block", + "type": "TypeString", + "description": "The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow.", + "computed": true + } + } + }, + "targets": { + "name": "targets", + "type": "TypeList", + "description": "The targets for this security group.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The load balancer's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this security group is a part of.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + } + } + } + ], + "ibm_is_snapshot": [ + { + "name": "source_image", + "type": "TypeString", + "description": "If present, the image id from which the data on this volume was most directly provisioned.", + "computed": true + }, + { + "name": "minimum_capacity", + "type": "TypeInt", + "description": "Minimum capacity of the snapshot", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "description": "The size of the snapshot", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "Snapshot identifier", + "optional": true + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "The globally unique name for the operating system included in this image", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type of the snapshot", + "computed": true + }, + { + "name": "captured_at", + "type": "TypeString", + "description": "The date and time that this snapshot was created", + "computed": true + }, + { + "name": "source_volume", + "type": "TypeString", + "description": "Snapshot source volume id", + "computed": true + }, + { + "name": "bootable", + "type": "TypeBool", + "description": "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "encryption", + "type": "TypeString", + "description": "Encryption type of the snapshot", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URL for the snapshot", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "User Tags for the snapshot", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Snapshot lifecycle state", + "computed": true + }, + { + "name": "backup_policy_plan", + "type": "TypeList", + "description": "If present, the backup policy plan which created this snapshot.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Snapshot name", + "optional": true + } + ], + "ibm_is_snapshots": [ + { + "name": "source_volume", + "type": "TypeString", + "description": "Filters the snapshot collection by source volume id", + "optional": true + }, + { + "name": "backup_policy_plan_id", + "type": "TypeString", + "description": "Filters the collection to backup policy jobs with the backup plan with the specified identifier", + "optional": true + }, + { + "name": "tag", + "type": "TypeString", + "description": "Filters the collection to resources with the exact tag value", + "optional": true + }, + { + "name": "snapshots", + "type": "TypeList", + "description": "List of snapshots", + "computed": true, + "elem": { + "backup_policy_plan": { + "name": "backup_policy_plan", + "type": "TypeList", + "description": "If present, the backup policy plan which created this snapshot.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced", + "computed": true + } + } + }, + "bootable": { + "name": "bootable", + "type": "TypeBool", + "description": "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + "computed": true + }, + "captured_at": { + "name": "captured_at", + "type": "TypeString", + "description": "The date and time that this snapshot was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "description": "Encryption type of the snapshot", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "URL for the snapshot", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Snapshot lifecycle state", + "computed": true + }, + "minimum_capacity": { + "name": "minimum_capacity", + "type": "TypeInt", + "description": "Minimum capacity of the snapshot", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Snapshot name", + "computed": true + }, + "operating_system": { + "name": "operating_system", + "type": "TypeString", + "description": "The globally unique name for the operating system included in this image", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type of the snapshot", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the snapshot", + "computed": true + }, + "source_image": { + "name": "source_image", + "type": "TypeString", + "description": "If present, the image id from which the data on this volume was most directly provisioned.", + "computed": true + }, + "source_volume": { + "name": "source_volume", + "type": "TypeString", + "description": "Snapshot source volume", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "User Tags for the snapshot", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Filters the snapshot collection by resources group id", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Filters the snapshot collection by snapshot name", + "optional": true + }, + { + "name": "source_image", + "type": "TypeString", + "description": "Filters the snapshot collection by source image id", + "optional": true + } + ], + "ibm_is_ssh_key": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the ssh key", + "required": true + }, + { + "name": "length", + "type": "TypeInt", + "description": "The ssh key length", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The ssh key type", + "computed": true + }, + { + "name": "fingerprint", + "type": "TypeString", + "description": "The ssh key Fingerprint", + "computed": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "SSH Public key data", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_is_ssh_keys": [ + { + "name": "keys", + "type": "TypeList", + "description": "Collection of keys.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the key was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this key.", + "computed": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "TypeString", + "description": "The fingerprint for this key. The value is returned base64-encoded and prefixed with the hash algorithm (always `SHA256`).", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this key.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this key.", + "computed": true + }, + "length": { + "name": "length", + "type": "TypeInt", + "description": "The length of this key (in bits).", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this key. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "public_key": { + "name": "public_key", + "type": "TypeString", + "description": "The public SSH key, consisting of two space-separated fields: the algorithm name, and the base64-encoded key.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this key.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The crypto-system used by this key.", + "computed": true + } + } + } + ], + "ibm_is_subnet": [ + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "routing_table", + "type": "TypeList", + "description": "The routing table for this subnet", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this routing table.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this routing table.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this routing table.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "identifier", + "type": "TypeString", + "optional": true + }, + { + "name": "access_tags", + "type": "TypeSet", + "description": "List of access tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "network_acl", + "type": "TypeString", + "computed": true + }, + { + "name": "public_gateway", + "type": "TypeString", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "vpc_name", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "ipv4_cidr_block", + "type": "TypeString", + "computed": true + }, + { + "name": "available_ipv4_address_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "total_ipv4_address_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vpc", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_is_subnet_reserved_ip": [ + { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id.", + "computed": true + }, + { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this reserved IP will be automatically deleted", + "computed": true + }, + { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier.", + "required": true + }, + { + "name": "reserved_ip", + "type": "TypeString", + "description": "The reserved IP identifier.", + "required": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the reserved IP", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + } + ], + "ibm_is_subnet_reserved_ips": [ + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier.", + "required": true + }, + { + "name": "reserved_ips", + "type": "TypeList", + "description": "Collection of reserved IPs in this subnet.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address", + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "If reserved ip shall be deleted automatically", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "owner": { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this reserved IP", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Reserved IP target id", + "computed": true + } + } + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of resources across all pages", + "computed": true + } + ], + "ibm_is_subnets": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource Group ID", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "routing_table_name", + "type": "TypeString", + "description": "Name of the routing table", + "optional": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "ID of the routing table", + "optional": true + }, + { + "name": "subnets", + "type": "TypeList", + "description": "List of subnets", + "computed": true, + "elem": { + "available_ipv4_address_count": { + "name": "available_ipv4_address_count", + "type": "TypeString", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "ipv4_cidr_block": { + "name": "ipv4_cidr_block", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "network_acl": { + "name": "network_acl", + "type": "TypeString", + "computed": true + }, + "public_gateway": { + "name": "public_gateway", + "type": "TypeString", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "computed": true + }, + "routing_table": { + "name": "routing_table", + "type": "TypeList", + "description": "The routing table for this subnet", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this routing table.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this routing table.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this routing table.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "total_ipv4_address_count": { + "name": "total_ipv4_address_count", + "type": "TypeString", + "computed": true + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_virtual_endpoint_gateway": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Endpoint gateway created date and time", + "computed": true + }, + { + "name": "health_state", + "type": "TypeString", + "description": "Endpoint gateway health state", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Endpoint gateway lifecycle state", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Endpoint gateway securitygroups list", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "target", + "type": "TypeList", + "description": "Endpoint gateway target", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The target name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The target resource type", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Endpoint gateway name", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Endpoint gateway", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "ips", + "type": "TypeList", + "description": "Endpoint gateway IPs", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Endpoint gateway IP Address", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The IPs id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The IPs name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway IP resource type", + "computed": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC id", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway resource type", + "computed": true + } + ], + "ibm_is_virtual_endpoint_gateway_ips": [ + { + "name": "gateway", + "type": "TypeString", + "required": true + }, + { + "name": "ips", + "type": "TypeList", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Endpoint gateway IP address", + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Endpoint gateway IP auto delete", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Endpoint gateway IP created date and time", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Endpoint gateway IP name", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Endpoint gateway IP id", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway IP resource type", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "Endpoint gateway detail", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The IPs target id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The IPs target name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway resource type", + "computed": true + } + } + } + } + } + ], + "ibm_is_virtual_endpoint_gateways": [ + { + "name": "virtual_endpoint_gateways", + "type": "TypeList", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Endpoint gateway created date and time", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Endpoint Gateway", + "computed": true + }, + "health_state": { + "name": "health_state", + "type": "TypeString", + "description": "Endpoint gateway health state", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Endpoint gateway id", + "computed": true + }, + "ips": { + "name": "ips", + "type": "TypeList", + "description": "Collection of reserved IPs bound to an endpoint gateway", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type(subnet_reserved_ip)", + "computed": true + } + } + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Endpoint gateway lifecycle state", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Endpoint gateway name", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group id", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway resource type", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Endpoint gateway securitygroups list", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "Endpoint gateway target", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The target crn", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The target name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The target resource type", + "computed": true + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeString", + "description": "The VPC id", + "computed": true + } + } + } + ], + "ibm_is_volume": [ + { + "name": "encryption_key", + "type": "TypeString", + "description": "Volume encryption key info", + "computed": true + }, + { + "name": "encryption_type", + "type": "TypeString", + "description": "Volume encryption type info", + "computed": true + }, + { + "name": "iops", + "type": "TypeInt", + "description": "IOPS value for the Volume", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "Volume profile name", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group name", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Volume status", + "computed": true + }, + { + "name": "source_snapshot", + "type": "TypeString", + "description": "Identifier of the snapshot from which this volume was cloned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The maximum bandwidth (in megabits per second) for the volume", + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "Vloume capacity value", + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN value for the volume instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the volume instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Volume name", + "required": true + } + ], + "ibm_is_volume_profile": [ + { + "name": "name", + "type": "TypeString", + "description": "Volume profile name", + "required": true + }, + { + "name": "family", + "type": "TypeString", + "description": "Volume profile family", + "computed": true + } + ], + "ibm_is_volume_profiles": [ + { + "name": "profiles", + "type": "TypeList", + "description": "List of Volume profile maps", + "computed": true, + "elem": { + "family": { + "name": "family", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_volumes": [ + { + "name": "volumes", + "type": "TypeList", + "description": "Collection of volumes.", + "computed": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether a running virtual server instance has an attachment to this volume.", + "computed": true + }, + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "The maximum bandwidth (in megabits per second) for the volume.", + "computed": true + }, + "busy": { + "name": "busy", + "type": "TypeBool", + "description": "Indicates whether this volume is performing an operation that must be serialized. If an operation specifies that it requires serialization, the operation will fail unless this property is `false`.", + "computed": true + }, + "capacity": { + "name": "capacity", + "type": "TypeInt", + "description": "The capacity to use for the volume (in gigabytes). The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the volume was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this volume.", + "computed": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "description": "The type of encryption used on the volume.", + "computed": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeList", + "description": "The root key used to wrap the data encryption key for the volume.This property will be present for volumes with an `encryption` type of`user_managed`.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this volume.", + "computed": true + }, + "iops": { + "name": "iops", + "type": "TypeInt", + "description": "The maximum I/O operations per second (IOPS) to use for the volume. Applicable only to volumes using a profile `family` of `custom`.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this volume.", + "computed": true + }, + "operating_system": { + "name": "operating_system", + "type": "TypeList", + "description": "The operating system associated with this volume. If absent, this volume was notcreated from an image, or the image did not include an operating system.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this operating system.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this operating system.", + "computed": true + } + } + }, + "profile": { + "name": "profile", + "type": "TypeList", + "description": "The profile this volume uses.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this volume profile.", + "computed": true + } + } + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this volume.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "source_image": { + "name": "source_image", + "type": "TypeList", + "description": "The image from which this volume was created (this may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).If absent, this volume was not created from an image.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this image.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this image.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this image.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this image.", + "computed": true + } + } + }, + "source_snapshot": { + "name": "source_snapshot", + "type": "TypeList", + "description": "The snapshot from which this volume was cloned.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this snapshot.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this snapshot.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this snapshot.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this snapshot.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the volume.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the volume on which the unexpected property value was encountered.", + "computed": true + }, + "status_reasons": { + "name": "status_reasons", + "type": "TypeList", + "description": "The reasons for the current status (if any).The enumerated reason code values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected reason code was encountered.", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason.", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason.", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "User Tags for the Volume", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "volume_attachments": { + "name": "volume_attachments", + "type": "TypeList", + "description": "The volume attachments for this volume.", + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the instance the volume will also be deleted.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "device": { + "name": "device", + "type": "TypeList", + "description": "Information about how the volume is exposed to the instance operating system.This property may be absent if the volume attachment's `status` is not `attached`.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "A unique identifier for the device which is exposed to the instance operating system.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume attachment.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this volume attachment.", + "computed": true + }, + "instance": { + "name": "instance", + "type": "TypeList", + "description": "The attached instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this volume attachment.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of volume attachment.", + "computed": true + } + } + }, + "zone": { + "name": "zone", + "type": "TypeList", + "description": "The zone this volume resides in.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this zone.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this zone.", + "computed": true + } + } + } + } + }, + { + "name": "volume_name", + "type": "TypeString", + "description": "Volume name identifier.", + "optional": true + }, + { + "name": "zone_name", + "type": "TypeString", + "description": "Zone name identifier.", + "optional": true + } + ], + "ibm_is_vpc": [ + { + "name": "identifier", + "type": "TypeString", + "optional": true + }, + { + "name": "default_network_acl_name", + "type": "TypeString", + "description": "Default Network ACL name", + "computed": true + }, + { + "name": "default_network_acl_crn", + "type": "TypeString", + "description": "Default Network ACL CRN", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "classic_access", + "type": "TypeBool", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "optional": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "default_security_group_name", + "type": "TypeString", + "description": "Default security group name", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "security_group", + "type": "TypeList", + "computed": true, + "elem": { + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "Security group id", + "computed": true + }, + "group_name": { + "name": "group_name", + "type": "TypeString", + "description": "Security group name", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Security Rules", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Rule ID", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "computed": true + } + } + } + } + }, + { + "name": "default_network_acl", + "type": "TypeString", + "computed": true + }, + { + "name": "default_routing_table", + "type": "TypeString", + "description": "Default routing table associated with VPC", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "default_security_group", + "type": "TypeString", + "description": "Security group associated with VPC", + "computed": true + }, + { + "name": "cse_source_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Cloud service endpoint IP Address", + "computed": true + }, + "zone_name": { + "name": "zone_name", + "type": "TypeString", + "description": "Location info of CSE Address", + "computed": true + } + } + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "available_ipv4_address_count": { + "name": "available_ipv4_address_count", + "type": "TypeInt", + "description": "Available IPv4 address count in the subnet", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "subent name", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "subnet status", + "computed": true + }, + "total_ipv4_address_count": { + "name": "total_ipv4_address_count", + "type": "TypeInt", + "description": "Total IPv4 address count in the subnet", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "subnet location", + "computed": true + } + } + }, + { + "name": "default_security_group_crn", + "type": "TypeString", + "description": "Default security group CRN", + "computed": true + }, + { + "name": "default_routing_table_name", + "type": "TypeString", + "description": "Default routing table name", + "computed": true + } + ], + "ibm_is_vpc_address_prefix": [ + { + "name": "zone", + "type": "TypeList", + "description": "The zone this address prefix resides in.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this zone.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this zone.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the prefix was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this address prefix.", + "computed": true + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name.", + "computed": true + }, + { + "name": "address_prefix_name", + "type": "TypeString", + "description": "The address prefix name.", + "optional": true + }, + { + "name": "cidr", + "type": "TypeString", + "description": "The CIDR block for this prefix.", + "computed": true + }, + { + "name": "has_subnets", + "type": "TypeBool", + "description": "Indicates whether subnets exist with addresses from this prefix.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "optional": true + }, + { + "name": "vpc_name", + "type": "TypeString", + "description": "The VPC name.", + "optional": true + }, + { + "name": "address_prefix", + "type": "TypeString", + "description": "The address prefix identifier.", + "optional": true + } + ], + "ibm_is_vpc_address_prefixes": [ + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", + "optional": true + }, + { + "name": "address_prefixes", + "type": "TypeList", + "description": "Collection of address prefixes.", + "computed": true, + "elem": { + "cidr": { + "name": "cidr", + "type": "TypeString", + "description": "The CIDR block for this prefix.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the prefix was created.", + "computed": true + }, + "has_subnets": { + "name": "has_subnets", + "type": "TypeBool", + "description": "Indicates whether subnets exist with addresses from this prefix.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this address prefix.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this address prefix.", + "computed": true + }, + "is_default": { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in.", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeList", + "description": "The zone this address prefix resides in.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this zone.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this zone.", + "computed": true + } + } + } + } + } + ], + "ibm_is_vpc_default_routing_table": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "Default Routing table Resource Type", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Default Routing table Lifecycle State", + "computed": true + }, + { + "name": "route_direct_link_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + "computed": true + }, + { + "name": "routes", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Route ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Route name", + "computed": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC identifier", + "required": true + }, + { + "name": "default_routing_table", + "type": "TypeString", + "description": "Default Routing Table ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Default Routing table Name", + "computed": true + }, + { + "name": "route_vpc_zone_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + "computed": true + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default routing table for this VPC", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subnet name", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "Default Routing table Href", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Default Routing table Created At", + "computed": true + }, + { + "name": "route_transit_gateway_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + "computed": true + } + ], + "ibm_is_vpc_routing_table": [ + { + "name": "route_vpc_zone_ingress", + "type": "TypeBool", + "description": "Indicates whether this routing table is used to route traffic that originates from subnets in other zones in this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + "computed": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "The routing table identifier.", + "optional": true + }, + { + "name": "route_direct_link_ingress", + "type": "TypeBool", + "description": "Indicates whether this routing table is used to route traffic that originates from[Direct Link](https://cloud.ibm.com/docs/dl/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + "computed": true + }, + { + "name": "route_transit_gateway_ingress", + "type": "TypeBool", + "description": "Indicates whether this routing table is used to route traffic that originates from from [Transit Gateway](https://cloud.ibm.com/cloud/transit-gateway/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this routing table.", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "description": "The subnets to which this routing table is attached.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "required": true + }, + { + "name": "accept_routes_from", + "type": "TypeList", + "description": "The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future.", + "computed": true, + "elem": { + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this routing table was created.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the routing table.", + "computed": true + }, + { + "name": "routes", + "type": "TypeList", + "description": "The routes for this routing table.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this route.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this route.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this route.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this routing table.", + "optional": true + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default routing table for this VPC.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + ], + "ibm_is_vpc_routing_table_route": [ + { + "name": "creator", + "type": "TypeList", + "description": "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The VPN gateway's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN gateway's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN gateway.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination of the route.", + "computed": true + }, + { + "name": "next_hop", + "type": "TypeList", + "description": "If `action` is `deliver`, the next hop that packets will be delivered to. Forother `action` values, its `address` will be `0.0.0.0`.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "origin", + "type": "TypeString", + "description": "The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "zone", + "type": "TypeList", + "description": "The zone the route applies to. (Traffic from subnets in this zone will besubject to this route.).", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this zone.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this zone.", + "computed": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The action to perform with a packet matching the route:- `delegate`: delegate to the system's built-in routes- `delegate_vpc`: delegate to the system's built-in routes, ignoring Internet-bound routes- `deliver`: deliver the packet to the specified `next_hop`- `drop`: drop the packet.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the route was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this route.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the route.", + "computed": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "The routing table identifier.", + "required": true + }, + { + "name": "route_id", + "type": "TypeString", + "description": "The VPC routing table route identifier.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this route.", + "optional": true + } + ], + "ibm_is_vpc_routing_table_routes": [ + { + "name": "vpc", + "type": "TypeString", + "description": "VPC identifier", + "required": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "Routing table identifier", + "required": true + }, + { + "name": "routes", + "type": "TypeList", + "description": "Collection of Routing Table Routes", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Routing Table Route Action", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Routing Table Route Created At", + "computed": true + }, + "creator": { + "name": "creator", + "type": "TypeList", + "description": "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The VPN gateway's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN gateway's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN gateway.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "Routing Table Route Destination", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Routing Table Route Href", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Routing Table Route Lifecycle State", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Routing Table Route Name", + "computed": true + }, + "nexthop": { + "name": "nexthop", + "type": "TypeString", + "description": "Routing Table Route Nexthop Address or VPN Gateway Connection ID", + "computed": true + }, + "origin": { + "name": "origin", + "type": "TypeString", + "description": "The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + "computed": true + }, + "route_id": { + "name": "route_id", + "type": "TypeString", + "description": "Routing Table Route ID", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "Routing Table Route Zone Name", + "computed": true + } + } + } + ], + "ibm_is_vpc_routing_tables": [ + { + "name": "vpc", + "type": "TypeString", + "description": "VPC identifier", + "required": true + }, + { + "name": "routing_tables", + "type": "TypeList", + "description": "Collection of Routing tables", + "computed": true, + "elem": { + "accept_routes_from": { + "name": "accept_routes_from", + "type": "TypeList", + "description": "The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future.", + "computed": true, + "elem": { + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Routing table Created At", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "Routing table Href", + "computed": true + }, + "is_default": { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default routing table for this VPC", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Routing table Lifecycle State", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Routing table Name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Routing table Resource Type", + "computed": true + }, + "route_direct_link_ingress": { + "name": "route_direct_link_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + "computed": true + }, + "route_transit_gateway_ingress": { + "name": "route_transit_gateway_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + "computed": true + }, + "route_vpc_zone_ingress": { + "name": "route_vpc_zone_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Route ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Route name", + "computed": true + } + } + }, + "routing_table": { + "name": "routing_table", + "type": "TypeString", + "description": "Routing Table ID", + "computed": true + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subnet name", + "computed": true + } + } + } + } + } + ], + "ibm_is_vpcs": [ + { + "name": "vpcs", + "type": "TypeList", + "description": "Collection of VPCs", + "computed": true, + "elem": { + "classic_access": { + "name": "classic_access", + "type": "TypeBool", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + "cse_source_addresses": { + "name": "cse_source_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Cloud service endpoint IP Address", + "computed": true + }, + "zone_name": { + "name": "zone_name", + "type": "TypeString", + "description": "Location info of CSE Address", + "computed": true + } + } + }, + "default_network_acl": { + "name": "default_network_acl", + "type": "TypeString", + "computed": true + }, + "default_network_acl_crn": { + "name": "default_network_acl_crn", + "type": "TypeString", + "description": "Default Network ACL CRN", + "computed": true + }, + "default_network_acl_name": { + "name": "default_network_acl_name", + "type": "TypeString", + "description": "Default Network ACL name", + "computed": true + }, + "default_routing_table": { + "name": "default_routing_table", + "type": "TypeString", + "description": "Default routing table associated with VPC", + "computed": true + }, + "default_routing_table_name": { + "name": "default_routing_table_name", + "type": "TypeString", + "description": "Default routing table name", + "computed": true + }, + "default_security_group": { + "name": "default_security_group", + "type": "TypeString", + "description": "Security group associated with VPC", + "computed": true + }, + "default_security_group_crn": { + "name": "default_security_group_crn", + "type": "TypeString", + "description": "Default security group CRN", + "computed": true + }, + "default_security_group_name": { + "name": "default_security_group_name", + "type": "TypeString", + "description": "Default security group name", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "VPC id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "VPC name", + "computed": true + }, + "resource_controller_url": { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + "resource_crn": { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "computed": true + }, + "resource_group_name": { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + "resource_name": { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + "resource_status": { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + "security_group": { + "name": "security_group", + "type": "TypeList", + "computed": true, + "elem": { + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "Security group id", + "immutable": true, + "computed": true + }, + "group_name": { + "name": "group_name", + "type": "TypeString", + "description": "Security group name", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Security Rules", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4 or ipv6", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Rule ID", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "computed": true + } + } + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "available_ipv4_address_count": { + "name": "available_ipv4_address_count", + "type": "TypeInt", + "description": "Available IPv4 address count in the subnet", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "subent name", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "subnet status", + "computed": true + }, + "total_ipv4_address_count": { + "name": "total_ipv4_address_count", + "type": "TypeInt", + "description": "Total IPv4 address count in the subnet", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "subnet location", + "computed": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_is_vpn_gateway": [ + { + "name": "mode", + "type": "TypeString", + "description": "Route mode VPN gateway.", + "computed": true + }, + { + "name": "vpc", + "type": "TypeList", + "description": "VPC for the VPN Gateway", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The VPN gateway's canonical URL.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN gateway.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway.", + "computed": true + }, + { + "name": "vpn_gateway", + "type": "TypeString", + "description": "The VPN gateway identifier.", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this VPN gateway was created.", + "computed": true + }, + { + "name": "subnet", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + } + } + }, + { + "name": "connections", + "type": "TypeList", + "description": "Connections for this VPN gateway.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN connection.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "members", + "type": "TypeList", + "description": "Collection of VPN gateway members.", + "computed": true, + "elem": { + "private_ip_address": { + "name": "private_ip_address", + "type": "TypeString", + "description": "The private IP address assigned to the VPN gateway member. This property will be present only when the VPN gateway status is`available`.", + "computed": true + }, + "public_ip_address": { + "name": "public_ip_address", + "type": "TypeString", + "description": "The public IP address assigned to the VPN gateway member.", + "computed": true + }, + "role": { + "name": "role", + "type": "TypeString", + "description": "The high availability role assigned to the VPN gateway member.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway member.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this VPN gateway.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "vpn_gateway_name", + "type": "TypeString", + "description": "The VPN gateway name.", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The VPN gateway's CRN.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_vpn_gateway_connection": [ + { + "name": "local_cidrs", + "type": "TypeList", + "description": "The local CIDRs for this resource.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vpn_gateway", + "type": "TypeString", + "description": "The VPN gateway identifier.", + "optional": true + }, + { + "name": "vpn_gateway_connection_name", + "type": "TypeString", + "description": "The VPN gateway connection name.", + "optional": true + }, + { + "name": "authentication_mode", + "type": "TypeString", + "description": "The authentication mode. Only `psk` is currently supported.", + "computed": true + }, + { + "name": "mode", + "type": "TypeString", + "description": "The mode of the VPN gateway.", + "computed": true + }, + { + "name": "peer_address", + "type": "TypeString", + "description": "The IP address of the peer VPN gateway.", + "computed": true + }, + { + "name": "psk", + "type": "TypeString", + "description": "The preshared key.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of a VPN gateway connection.", + "computed": true + }, + { + "name": "vpn_gateway_name", + "type": "TypeString", + "description": "The VPN gateway name.", + "optional": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "admin_state_up", + "type": "TypeBool", + "description": "If set to false, the VPN gateway connection is shut down.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this VPN gateway connection was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The VPN connection's canonical URL.", + "computed": true + }, + { + "name": "ipsec_policy", + "type": "TypeList", + "description": "The IPsec policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn\u0026interface=ui#ipsec-auto-negotiation-phase-2).", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The IPsec policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this IPsec policy.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this IPsec policy.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "vpn_gateway_connection", + "type": "TypeString", + "description": "The VPN gateway connection identifier.", + "optional": true + }, + { + "name": "dead_peer_detection", + "type": "TypeList", + "description": "The Dead Peer Detection settings.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Dead Peer Detection actions.", + "computed": true + }, + "interval": { + "name": "interval", + "type": "TypeInt", + "description": "Dead Peer Detection interval in seconds.", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "Dead Peer Detection timeout in seconds. Must be at least the interval.", + "computed": true + } + } + }, + { + "name": "ike_policy", + "type": "TypeList", + "description": "The IKE policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn\u0026interface=ui#ike-auto-negotiation-phase-1).", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The IKE policy's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this IKE policy.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this IKE policy.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN gateway connection.", + "computed": true + }, + { + "name": "routing_protocol", + "type": "TypeString", + "description": "Routing protocols are disabled for this VPN gateway connection.", + "computed": true + }, + { + "name": "tunnels", + "type": "TypeList", + "description": "The VPN tunnel configuration for this VPN gateway connection (in static route mode).", + "computed": true, + "elem": { + "public_ip_address": { + "name": "public_ip_address", + "type": "TypeString", + "description": "The IP address of the VPN gateway member in which the tunnel resides.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN Tunnel.", + "computed": true + } + } + }, + { + "name": "peer_cidrs", + "type": "TypeList", + "description": "The peer CIDRs for this resource.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_is_vpn_gateway_connections": [ + { + "name": "vpn_gateway", + "type": "TypeString", + "description": "The VPN gateway identifier", + "required": true + }, + { + "name": "connections", + "type": "TypeList", + "description": "Collection of VPN Gateways", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action detection for dead peer detection action", + "computed": true + }, + "admin_state_up": { + "name": "admin_state_up", + "type": "TypeBool", + "description": "VPN gateway connection admin state", + "computed": true + }, + "authentication_mode": { + "name": "authentication_mode", + "type": "TypeString", + "description": "The authentication mode", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this VPN gateway connection was created", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection", + "computed": true + }, + "ike_policy": { + "name": "ike_policy", + "type": "TypeString", + "description": "VPN gateway connection IKE Policy", + "computed": true + }, + "interval": { + "name": "interval", + "type": "TypeInt", + "description": "Interval for dead peer detection interval", + "computed": true + }, + "ipsec_policy": { + "name": "ipsec_policy", + "type": "TypeString", + "description": "IP security policy for vpn gateway connection", + "computed": true + }, + "local_cidrs": { + "name": "local_cidrs", + "type": "TypeSet", + "description": "VPN gateway connection local CIDRs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "The mode of the VPN gateway", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "VPN Gateway connection name", + "computed": true + }, + "peer_address": { + "name": "peer_address", + "type": "TypeString", + "description": "VPN gateway connection peer address", + "computed": true + }, + "peer_cidrs": { + "name": "peer_cidrs", + "type": "TypeSet", + "description": "VPN gateway connection peer CIDRs", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "VPN gateway connection status", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "Timeout for dead peer detection", + "computed": true + }, + "tunnels": { + "name": "tunnels", + "type": "TypeList", + "description": "The VPN tunnel configuration for this VPN gateway connection (in static route mode)", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address of the VPN gateway member in which the tunnel resides", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN Tunnel", + "computed": true + } + } + } + } + } + ], + "ibm_is_vpn_gateways": [ + { + "name": "vpn_gateways", + "type": "TypeList", + "description": "Collection of VPN Gateways", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this VPN gateway was created", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The VPN gateway's CRN", + "computed": true + }, + "members": { + "name": "members", + "type": "TypeList", + "description": "Collection of VPN gateway members", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The public IP address assigned to the VPN gateway member", + "computed": true + }, + "private_address": { + "name": "private_address", + "type": "TypeString", + "description": "The private IP address assigned to the VPN gateway member", + "computed": true + }, + "role": { + "name": "role", + "type": "TypeString", + "description": "The high availability role assigned to the VPN gateway member", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway member", + "computed": true + } + } + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "VPN gateway mode(policy/route)", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "VPN Gateway instance name", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "resource group identifiers", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "VPNGateway subnet info", + "computed": true + }, + "vpc": { + "name": "vpc", + "type": "TypeList", + "description": "VPC for the VPN Gateway", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + } + } + } + ], + "ibm_is_vpn_server": [ + { + "name": "protocol", + "type": "TypeString", + "description": "The transport protocol used by this VPN server.", + "computed": true + }, + { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this VPN server resides in.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPN server", + "optional": true, + "computed": true + }, + { + "name": "client_idle_timeout", + "type": "TypeInt", + "description": "The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients.", + "computed": true + }, + { + "name": "enable_split_tunneling", + "type": "TypeBool", + "description": "Indicates whether the split tunneling is enabled on this VPN server.", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Fully qualified domain name assigned to this VPN server.", + "computed": true + }, + { + "name": "client_auto_delete", + "type": "TypeBool", + "description": "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + "computed": true + }, + { + "name": "client_auto_delete_timeout", + "type": "TypeInt", + "description": "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPN server.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN server was created.", + "computed": true + }, + { + "name": "health_state", + "type": "TypeString", + "description": "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + "computed": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "The port number used by this VPN server.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this VPN server.", + "cloud_data_type": "resource_group", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "certificate", + "type": "TypeList", + "description": "The certificate instance for this VPN server.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this certificate instance.", + "computed": true + } + } + }, + { + "name": "client_dns_server_ips", + "type": "TypeList", + "description": "The DNS server addresses that will be provided to VPN clients that are connected to this VPN server.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + { + "name": "client_ip_pool", + "type": "TypeString", + "description": "The VPN client IPv4 address pool, expressed in CIDR format.", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeList", + "description": "The security groups targeting this VPN server.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN server.", + "computed": true + }, + { + "name": "private_ips", + "type": "TypeList", + "description": "The reserved IPs bound to this VPN server.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this reserved IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "subnets", + "type": "TypeList", + "description": "The subnets this VPN server is part of.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The unique identifier for this VPN server", + "optional": true + }, + { + "name": "client_authentication", + "type": "TypeList", + "description": "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + "computed": true, + "elem": { + "client_ca": { + "name": "client_ca", + "type": "TypeString", + "description": "The CRN for this certificate instance,The certificate instance used for the VPN client certificate authority (CA).", + "computed": true + }, + "identity_provider": { + "name": "identity_provider", + "type": "TypeString", + "description": "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered,The type of identity provider to be used by VPN client.", + "computed": true + }, + "method": { + "name": "method", + "type": "TypeString", + "description": "The type of authentication.", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN server.", + "computed": true + } + ], + "ibm_is_vpn_server_client": [ + { + "name": "remote_ip", + "type": "TypeList", + "description": "The remote IP address of this VPN client.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + { + "name": "remote_port", + "type": "TypeInt", + "description": "The remote port of this VPN client.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "required": true + }, + { + "name": "common_name", + "type": "TypeString", + "description": "The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN client was created.", + "computed": true + }, + { + "name": "disconnected_at", + "type": "TypeString", + "description": "The date and time that the VPN client was disconnected.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN client.", + "computed": true + }, + { + "name": "username", + "type": "TypeString", + "description": "The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server.", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The VPN client identifier.", + "required": true + }, + { + "name": "client_ip", + "type": "TypeList", + "description": "The IP address assigned to this VPN client from `client_ip_pool`.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + ], + "ibm_is_vpn_server_client_configuration": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "immutable": true, + "required": true + }, + { + "name": "file_path", + "type": "TypeString", + "description": "The File Path to store configuration.", + "immutable": true, + "optional": true + }, + { + "name": "vpn_server_client_configuration", + "type": "TypeString", + "description": "The VPN client configuration.", + "computed": true + } + ], + "ibm_is_vpn_server_clients": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "required": true + }, + { + "name": "clients", + "type": "TypeList", + "description": "Collection of VPN clients.", + "computed": true, + "elem": { + "client_ip": { + "name": "client_ip", + "type": "TypeList", + "description": "The IP address assigned to this VPN client from `client_ip_pool`.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + "common_name": { + "name": "common_name", + "type": "TypeString", + "description": "The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN client was created.", + "computed": true + }, + "disconnected_at": { + "name": "disconnected_at", + "type": "TypeString", + "description": "The date and time that the VPN client was disconnected.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN client.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN client.", + "computed": true + }, + "remote_ip": { + "name": "remote_ip", + "type": "TypeList", + "description": "The remote IP address of this VPN client.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + "remote_port": { + "name": "remote_port", + "type": "TypeInt", + "description": "The remote port of this VPN client.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server.", + "computed": true + } + } + } + ], + "ibm_is_vpn_server_route": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN route was created.", + "computed": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN route.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN route.", + "computed": true + }, + { + "name": "identifier", + "type": "TypeString", + "description": "The unique identifier for this VPN server route", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPN server route", + "optional": true, + "computed": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + ], + "ibm_is_vpn_server_routes": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "required": true + }, + { + "name": "routes", + "type": "TypeList", + "description": "Collection of VPN routes.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN route was created.", + "computed": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN route.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN route.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN route.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN route.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + } + ], + "ibm_is_vpn_servers": [ + { + "name": "vpn_servers", + "type": "TypeList", + "description": "Collection of VPN servers.", + "computed": true, + "elem": { + "certificate": { + "name": "certificate", + "type": "TypeList", + "description": "The certificate instance for this VPN server.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this certificate instance.", + "computed": true + } + } + }, + "client_authentication": { + "name": "client_authentication", + "type": "TypeList", + "description": "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + "computed": true, + "elem": { + "client_ca": { + "name": "client_ca", + "type": "TypeString", + "description": "The CRN for this certificate instance,The certificate instance used for the VPN client certificate authority (CA).", + "computed": true + }, + "identity_provider": { + "name": "identity_provider", + "type": "TypeString", + "description": "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered,The type of identity provider to be used by VPN client.", + "computed": true + }, + "method": { + "name": "method", + "type": "TypeString", + "description": "The type of authentication.", + "computed": true + } + } + }, + "client_auto_delete": { + "name": "client_auto_delete", + "type": "TypeBool", + "description": "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + "computed": true + }, + "client_auto_delete_timeout": { + "name": "client_auto_delete_timeout", + "type": "TypeInt", + "description": "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + "computed": true + }, + "client_dns_server_ips": { + "name": "client_dns_server_ips", + "type": "TypeList", + "description": "The DNS server addresses that will be provided to VPN clients that are connected to this VPN server.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + } + } + }, + "client_idle_timeout": { + "name": "client_idle_timeout", + "type": "TypeInt", + "description": "The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients.", + "computed": true + }, + "client_ip_pool": { + "name": "client_ip_pool", + "type": "TypeString", + "description": "The VPN client IPv4 address pool, expressed in CIDR format.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN server was created.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPN server.", + "computed": true + }, + "enable_split_tunneling": { + "name": "enable_split_tunneling", + "type": "TypeBool", + "description": "Indicates whether the split tunneling is enabled on this VPN server.", + "computed": true + }, + "health_state": { + "name": "health_state", + "type": "TypeString", + "description": "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "Fully qualified domain name assigned to this VPN server.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN server.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN server.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN server.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPN server.", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "description": "The port number used by this VPN server.", + "computed": true + }, + "private_ips": { + "name": "private_ips", + "type": "TypeList", + "description": "The reserved IPs bound to this VPN server.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this reserved IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "description": "The transport protocol used by this VPN server.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeList", + "description": "The resource group for this VPN server.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this resource group.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this resource group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this resource group.", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "security_groups": { + "name": "security_groups", + "type": "TypeList", + "description": "The security groups targeting this VPN server.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The security group's CRN.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The security group's canonical URL.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this security group.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this security group. Names must be unique within the VPC the security group resides in.", + "computed": true + } + } + }, + "subnets": { + "name": "subnets", + "type": "TypeList", + "description": "The subnets this VPN server is part of.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this subnet.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this subnet.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this subnet.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this subnet.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "vpc": { + "name": "vpc", + "type": "TypeSet", + "description": "The VPC this VPN server resides in.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "resource group identifier.", + "cloud_data_type": "resource_group", + "optional": true + } + ], + "ibm_is_zone": [ + { + "name": "region", + "type": "TypeString", + "cloud_data_type": "region", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "required": true + } + ], + "ibm_is_zones": [ + { + "name": "status", + "type": "TypeString", + "optional": true + }, + { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "region", + "type": "TypeString", + "cloud_data_type": "region", + "required": true + } + ], + "ibm_kms_key": [ + { + "name": "key_name", + "type": "TypeString", + "description": "The name of the key to be fetched", + "optional": true + }, + { + "name": "alias", + "type": "TypeString", + "description": "The alias associated with the key", + "optional": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "optional": true + }, + { + "name": "keys", + "type": "TypeList", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "key_ring_id": { + "name": "key_ring_id", + "type": "TypeString", + "description": "The key ring id of the key to be fetched", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "policies": { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "dual_auth_delete": { + "name": "dual_auth_delete", + "type": "TypeList", + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "computed": true + } + } + }, + "rotation": { + "name": "rotation", + "type": "TypeList", + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "interval_month": { + "name": "interval_month", + "type": "TypeInt", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "computed": true + } + } + } + } + }, + "standard_key": { + "name": "standard_key", + "type": "TypeBool", + "computed": true + } + } + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "limit", + "type": "TypeInt", + "description": "Limit till the keys to be fetched", + "optional": true + }, + { + "name": "key_id", + "type": "TypeString", + "optional": true + } + ], + "ibm_kms_key_policies": [ + { + "name": "policies", + "type": "TypeList", + "description": "Creates or updates one or more policies for the specified key", + "optional": true, + "computed": true, + "elem": { + "dual_auth_delete": { + "name": "dual_auth_delete", + "type": "TypeList", + "description": "Data associated with the dual authorization delete policy.", + "optional": true, + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the resource that created the policy.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date the policy was created. The date format follows RFC 3339.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "If set to true, Key Protect enables a dual authorization policy on a single key.", + "required": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The unique identifier for the resource that updated the policy.", + "computed": true + } + } + }, + "rotation": { + "name": "rotation", + "type": "TypeList", + "description": "Specifies the key rotation time interval in months, with a minimum of 1, and a maximum of 12", + "optional": true, + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the resource that created the policy.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date the policy was created. The date format follows RFC 3339.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + "computed": true + }, + "interval_month": { + "name": "interval_month", + "type": "TypeInt", + "description": "Specifies the key rotation time interval in months", + "required": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The unique identifier for the resource that updated the policy.", + "computed": true + } + } + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "optional": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "Key ID of the Key", + "optional": true + }, + { + "name": "alias", + "type": "TypeString", + "description": "Alias of the Key", + "optional": true + } + ], + "ibm_kms_key_rings": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "optional": true + }, + { + "name": "key_rings", + "type": "TypeList", + "description": "Key Rings for a particualer instance", + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_kms_keys": [ + { + "name": "key_name", + "type": "TypeString", + "description": "The name of the key to be fetched", + "optional": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "Limit till the keys to be fetched", + "optional": true + }, + { + "name": "alias", + "type": "TypeString", + "description": "The name of the key to be fetched", + "optional": true + }, + { + "name": "key_id", + "type": "TypeString", + "optional": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "immutable": true, + "optional": true + }, + { + "name": "keys", + "type": "TypeList", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "key_ring_id": { + "name": "key_ring_id", + "type": "TypeString", + "description": "The key ring id of the key to be fetched", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "policies": { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "dual_auth_delete": { + "name": "dual_auth_delete", + "type": "TypeList", + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "computed": true + } + } + }, + "rotation": { + "name": "rotation", + "type": "TypeList", + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "interval_month": { + "name": "interval_month", + "type": "TypeInt", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "computed": true + } + } + } + } + }, + "standard_key": { + "name": "standard_key", + "type": "TypeBool", + "computed": true + } + } + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + } + ], + "ibm_kp_key": [ + { + "name": "key_protect_id", + "type": "TypeString", + "required": true + }, + { + "name": "key_name", + "type": "TypeString", + "optional": true + }, + { + "name": "keys", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "standard_key": { + "name": "standard_key", + "type": "TypeBool", + "computed": true + } + } + } + ], + "ibm_lbaas": [ + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "vip", + "type": "TypeString", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "computed": true + }, + { + "name": "protocols", + "type": "TypeList", + "computed": true, + "elem": { + "backend_port": { + "name": "backend_port", + "type": "TypeInt", + "computed": true + }, + "backend_protocol": { + "name": "backend_protocol", + "type": "TypeString", + "computed": true + }, + "frontend_port": { + "name": "frontend_port", + "type": "TypeInt", + "computed": true + }, + "frontend_protocol": { + "name": "frontend_protocol", + "type": "TypeString", + "computed": true + }, + "load_balancing_method": { + "name": "load_balancing_method", + "type": "TypeString", + "computed": true + }, + "max_conn": { + "name": "max_conn", + "type": "TypeInt", + "computed": true + }, + "protocol_id": { + "name": "protocol_id", + "type": "TypeString", + "computed": true + }, + "session_stickiness": { + "name": "session_stickiness", + "type": "TypeString", + "computed": true + }, + "tls_certificate_id": { + "name": "tls_certificate_id", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "computed": true + }, + { + "name": "server_instances_up", + "type": "TypeInt", + "computed": true + }, + { + "name": "active_connections", + "type": "TypeInt", + "computed": true + }, + { + "name": "use_system_public_ip_pool", + "type": "TypeBool", + "computed": true + }, + { + "name": "ssl_ciphers", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health_monitors", + "type": "TypeList", + "computed": true, + "elem": { + "interval": { + "name": "interval", + "type": "TypeInt", + "computed": true + }, + "max_retries": { + "name": "max_retries", + "type": "TypeInt", + "computed": true + }, + "monitor_id": { + "name": "monitor_id", + "type": "TypeString", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "computed": true + }, + "url_path": { + "name": "url_path", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "required": true + }, + { + "name": "server_instances_down", + "type": "TypeInt", + "computed": true + }, + { + "name": "server_instances", + "type": "TypeList", + "computed": true, + "elem": { + "member_id": { + "name": "member_id", + "type": "TypeString", + "computed": true + }, + "private_ip_address": { + "name": "private_ip_address", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "weight": { + "name": "weight", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "datacenter", + "type": "TypeString", + "computed": true + } + ], + "ibm_network_vlan": [ + { + "name": "id", + "type": "TypeInt", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "number", + "type": "TypeInt", + "optional": true, + "computed": true + }, + { + "name": "router_hostname", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "virtual_guests", + "type": "TypeList", + "computed": true, + "elem": { + "domain": { + "name": "domain", + "type": "TypeString", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "cidr": { + "name": "cidr", + "type": "TypeInt", + "computed": true + }, + "gateway": { + "name": "gateway", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + }, + "subnet_size": { + "name": "subnet_size", + "type": "TypeInt", + "computed": true + }, + "subnet_type": { + "name": "subnet_type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_org": [ + { + "name": "name", + "type": "TypeString", + "description": "Org name, for example myorg@domain", + "optional": true + }, + { + "name": "org", + "type": "TypeString", + "description": "Org name, for example myorg@domain", + "optional": true, + "deprecated": "use name instead" + } + ], + "ibm_org_quota": [ + { + "name": "total_service_keys", + "type": "TypeInt", + "description": "Defines the total service keys for organization.", + "computed": true + }, + { + "name": "non_basic_services_allowed", + "type": "TypeBool", + "description": "Define non basic services are allowed for organization.", + "computed": true + }, + { + "name": "total_services", + "type": "TypeInt", + "description": "Defines the total services for organization.", + "computed": true + }, + { + "name": "total_routes", + "type": "TypeInt", + "description": "Defines the total route for organization.", + "computed": true + }, + { + "name": "trial_db_allowed", + "type": "TypeBool", + "description": "Defines trial db are allowed for organization.", + "computed": true + }, + { + "name": "app_instance_limit", + "type": "TypeInt", + "description": "Defines the total app instance limit for organization.", + "computed": true + }, + { + "name": "total_private_domains", + "type": "TypeInt", + "description": "Defines the total private domain limit for organization.v", + "computed": true + }, + { + "name": "app_tasks_limit", + "type": "TypeInt", + "description": "Defines the total app task limit for organization.", + "computed": true + }, + { + "name": "total_reserved_route_ports", + "type": "TypeInt", + "description": "Defines the number of reserved route ports for organization.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Org quota name, for example qIBM", + "required": true + }, + { + "name": "memory_limit", + "type": "TypeInt", + "description": "Defines the total memory limit for organization.", + "computed": true + }, + { + "name": "instance_memory_limit", + "type": "TypeInt", + "description": "Defines the total instance memory limit for organization.", + "computed": true + } + ], + "ibm_pi_catalog_images": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "sap", + "type": "TypeBool", + "optional": true + }, + { + "name": "vtl", + "type": "TypeBool", + "optional": true + }, + { + "name": "images", + "type": "TypeList", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "computed": true + }, + "container_format": { + "name": "container_format", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "disk_format": { + "name": "disk_format", + "type": "TypeString", + "computed": true + }, + "endianness": { + "name": "endianness", + "type": "TypeString", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "hypervisor_type": { + "name": "hypervisor_type", + "type": "TypeString", + "computed": true + }, + "image_id": { + "name": "image_id", + "type": "TypeString", + "computed": true + }, + "image_type": { + "name": "image_type", + "type": "TypeString", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "operating_system": { + "name": "operating_system", + "type": "TypeString", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "storage_pool": { + "name": "storage_pool", + "type": "TypeString", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_cloud_connection": [ + { + "name": "networks", + "type": "TypeSet", + "description": "Set of Networks attached to this cloud connection", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vpc_enabled", + "type": "TypeBool", + "description": "Enable VPC for this cloud connection", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "user_ip_address", + "type": "TypeString", + "computed": true + }, + { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of service the gateway is attached to", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "speed", + "type": "TypeInt", + "computed": true + }, + { + "name": "classic_enabled", + "type": "TypeBool", + "description": "Enable classic endpoint destination", + "computed": true + }, + { + "name": "vpc_crns", + "type": "TypeSet", + "description": "Set of VPCs attached to this cloud connection", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "port", + "type": "TypeString", + "computed": true + }, + { + "name": "gre_destination_address", + "type": "TypeString", + "description": "GRE destination IP address", + "computed": true + }, + { + "name": "gre_source_address", + "type": "TypeString", + "description": "GRE auto-assigned source IP address", + "computed": true + }, + { + "name": "pi_cloud_connection_name", + "type": "TypeString", + "description": "Cloud Connection Name to be used", + "required": true + }, + { + "name": "global_routing", + "type": "TypeBool", + "computed": true + }, + { + "name": "metered", + "type": "TypeBool", + "computed": true + }, + { + "name": "ibm_ip_address", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_cloud_connections": [ + { + "name": "connections", + "type": "TypeList", + "computed": true, + "elem": { + "classic_enabled": { + "name": "classic_enabled", + "type": "TypeBool", + "description": "Enable classic endpoint destination", + "computed": true + }, + "cloud_connection_id": { + "name": "cloud_connection_id", + "type": "TypeString", + "computed": true + }, + "connection_mode": { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of service the gateway is attached to", + "computed": true + }, + "global_routing": { + "name": "global_routing", + "type": "TypeBool", + "computed": true + }, + "gre_destination_address": { + "name": "gre_destination_address", + "type": "TypeString", + "description": "GRE destination IP address", + "computed": true + }, + "gre_source_address": { + "name": "gre_source_address", + "type": "TypeString", + "description": "GRE auto-assigned source IP address", + "computed": true + }, + "ibm_ip_address": { + "name": "ibm_ip_address", + "type": "TypeString", + "computed": true + }, + "metered": { + "name": "metered", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "networks": { + "name": "networks", + "type": "TypeSet", + "description": "Set of Networks attached to this cloud connection", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "port": { + "name": "port", + "type": "TypeString", + "computed": true + }, + "speed": { + "name": "speed", + "type": "TypeInt", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "user_ip_address": { + "name": "user_ip_address", + "type": "TypeString", + "computed": true + }, + "vpc_crns": { + "name": "vpc_crns", + "type": "TypeSet", + "description": "Set of VPCs attached to this cloud connection", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "vpc_enabled": { + "name": "vpc_enabled", + "type": "TypeBool", + "description": "Enable VPC for this cloud connection", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + } + ], + "ibm_pi_cloud_instance": [ + { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "total_processors_consumed", + "type": "TypeFloat", + "computed": true + }, + { + "name": "total_memory_consumed", + "type": "TypeFloat", + "computed": true + }, + { + "name": "pvm_instances", + "type": "TypeList", + "computed": true, + "elem": { + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "systype": { + "name": "systype", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "computed": true + }, + { + "name": "capabilities", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "total_instances", + "type": "TypeFloat", + "computed": true + }, + { + "name": "total_ssd_storage_consumed", + "type": "TypeFloat", + "computed": true + }, + { + "name": "total_standard_storage_consumed", + "type": "TypeFloat", + "computed": true + } + ], + "ibm_pi_console_languages": [ + { + "name": "console_languages", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "language code", + "computed": true + }, + "language": { + "name": "language", + "type": "TypeString", + "description": "language description", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "The unique identifier or name of the instance", + "required": true + } + ], + "ibm_pi_dhcp": [ + { + "name": "pi_dhcp_id", + "type": "TypeString", + "description": "The ID of the DHCP Server", + "required": true + }, + { + "name": "dhcp_id", + "type": "TypeString", + "description": "The ID of the DHCP Server", + "computed": true + }, + { + "name": "leases", + "type": "TypeList", + "description": "The list of DHCP Server PVM Instance leases", + "computed": true, + "elem": { + "instance_ip": { + "name": "instance_ip", + "type": "TypeString", + "description": "The IP of the PVM Instance", + "computed": true + }, + "instance_mac": { + "name": "instance_mac", + "type": "TypeString", + "description": "The MAC Address of the PVM Instance", + "computed": true + } + } + }, + { + "name": "network", + "type": "TypeString", + "description": "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + "computed": true + }, + { + "name": "network_id", + "type": "TypeString", + "description": "The ID of the DHCP Server private network", + "computed": true + }, + { + "name": "network_name", + "type": "TypeString", + "description": "The name of the DHCP Server private network", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the DHCP Server", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + } + ], + "ibm_pi_dhcps": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "servers", + "type": "TypeList", + "description": "The list of all the DHCP Servers", + "computed": true, + "elem": { + "dhcp_id": { + "name": "dhcp_id", + "type": "TypeString", + "description": "The ID of the DHCP Server", + "computed": true + }, + "network": { + "name": "network", + "type": "TypeString", + "description": "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "description": "The ID of the DHCP Server private network", + "computed": true + }, + "network_name": { + "name": "network_name", + "type": "TypeString", + "description": "The name of the DHCP Server private network", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the DHCP Server", + "computed": true + } + } + } + ], + "ibm_pi_image": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "architecture", + "type": "TypeString", + "computed": true + }, + { + "name": "storage_pool", + "type": "TypeString", + "computed": true + }, + { + "name": "image_type", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_image_name", + "type": "TypeString", + "description": "Imagename Name to be used for pvminstances", + "required": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "computed": true + }, + { + "name": "operatingsystem", + "type": "TypeString", + "computed": true + }, + { + "name": "hypervisor", + "type": "TypeString", + "computed": true + }, + { + "name": "storage_type", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_images": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "image_info", + "type": "TypeList", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "image_type": { + "name": "image_type", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "storage_pool": { + "name": "storage_pool", + "type": "TypeString", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_instance": [ + { + "name": "volumes", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health_status", + "type": "TypeString", + "computed": true + }, + { + "name": "maxmem", + "type": "TypeFloat", + "computed": true + }, + { + "name": "minproc", + "type": "TypeFloat", + "computed": true + }, + { + "name": "minmem", + "type": "TypeFloat", + "computed": true + }, + { + "name": "pin_policy", + "type": "TypeString", + "computed": true + }, + { + "name": "max_virtual_cores", + "type": "TypeInt", + "computed": true + }, + { + "name": "storage_type", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "Server Name to be used for pvminstances", + "required": true + }, + { + "name": "addresses", + "type": "TypeList", + "computed": true, + "elem": { + "external_ip": { + "name": "external_ip", + "type": "TypeString", + "computed": true + }, + "ip": { + "name": "ip", + "type": "TypeString", + "computed": true + }, + "macaddress": { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "computed": true + }, + "network_name": { + "name": "network_name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + }, + "deprecated": "This field is deprecated, use networks instead" + }, + { + "name": "networks", + "type": "TypeList", + "computed": true, + "elem": { + "external_ip": { + "name": "external_ip", + "type": "TypeString", + "computed": true + }, + "ip": { + "name": "ip", + "type": "TypeString", + "computed": true + }, + "macaddress": { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "computed": true + }, + "network_name": { + "name": "network_name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "deployment_type", + "type": "TypeString", + "computed": true + }, + { + "name": "shared_processor_pool", + "type": "TypeString", + "computed": true + }, + { + "name": "storage_pool_affinity", + "type": "TypeBool", + "computed": true + }, + { + "name": "license_repository_capacity", + "type": "TypeInt", + "computed": true + }, + { + "name": "placement_group_id", + "type": "TypeString", + "computed": true + }, + { + "name": "virtual_cores_assigned", + "type": "TypeInt", + "computed": true + }, + { + "name": "shared_processor_pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "processors", + "type": "TypeFloat", + "computed": true + }, + { + "name": "proctype", + "type": "TypeString", + "computed": true + }, + { + "name": "maxproc", + "type": "TypeFloat", + "computed": true + }, + { + "name": "min_virtual_cores", + "type": "TypeInt", + "computed": true + }, + { + "name": "storage_pool", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "memory", + "type": "TypeFloat", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_instance_ip": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "ip", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "Server Name to be used for pvminstances", + "required": true + }, + { + "name": "pi_network_name", + "type": "TypeString", + "required": true + }, + { + "name": "ipoctet", + "type": "TypeString", + "computed": true + }, + { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + { + "name": "network_id", + "type": "TypeString", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "computed": true + }, + { + "name": "external_ip", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_instance_snapshots": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "instance_snapshots", + "type": "TypeList", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "last_updated_date": { + "name": "last_updated_date", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "percent_complete": { + "name": "percent_complete", + "type": "TypeInt", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "volume_snapshots": { + "name": "volume_snapshots", + "type": "TypeMap", + "computed": true + } + } + } + ], + "ibm_pi_instance_volumes": [ + { + "name": "instance_volumes", + "type": "TypeList", + "computed": true, + "elem": { + "bootable": { + "name": "bootable", + "type": "TypeBool", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "pool": { + "name": "pool", + "type": "TypeString", + "computed": true + }, + "shareable": { + "name": "shareable", + "type": "TypeBool", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeFloat", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "Instance Name to be used for pvminstances", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "boot_volume_id", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_instances": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pvm_instances", + "type": "TypeList", + "computed": true, + "elem": { + "health_status": { + "name": "health_status", + "type": "TypeString", + "computed": true + }, + "license_repository_capacity": { + "name": "license_repository_capacity", + "type": "TypeInt", + "computed": true + }, + "max_virtual_cores": { + "name": "max_virtual_cores", + "type": "TypeInt", + "computed": true + }, + "maxmem": { + "name": "maxmem", + "type": "TypeFloat", + "computed": true + }, + "maxproc": { + "name": "maxproc", + "type": "TypeFloat", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeFloat", + "computed": true + }, + "min_virtual_cores": { + "name": "min_virtual_cores", + "type": "TypeInt", + "computed": true + }, + "minmem": { + "name": "minmem", + "type": "TypeFloat", + "computed": true + }, + "minproc": { + "name": "minproc", + "type": "TypeFloat", + "computed": true + }, + "networks": { + "name": "networks", + "type": "TypeList", + "computed": true, + "elem": { + "external_ip": { + "name": "external_ip", + "type": "TypeString", + "computed": true + }, + "ip": { + "name": "ip", + "type": "TypeString", + "computed": true + }, + "macaddress": { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "computed": true + }, + "network_name": { + "name": "network_name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + "pin_policy": { + "name": "pin_policy", + "type": "TypeString", + "computed": true + }, + "placement_group_id": { + "name": "placement_group_id", + "type": "TypeString", + "computed": true + }, + "processors": { + "name": "processors", + "type": "TypeFloat", + "computed": true + }, + "proctype": { + "name": "proctype", + "type": "TypeString", + "computed": true + }, + "pvm_instance_id": { + "name": "pvm_instance_id", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "storage_pool": { + "name": "storage_pool", + "type": "TypeString", + "computed": true + }, + "storage_pool_affinity": { + "name": "storage_pool_affinity", + "type": "TypeBool", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "computed": true + }, + "virtual_cores_assigned": { + "name": "virtual_cores_assigned", + "type": "TypeInt", + "computed": true + } + } + } + ], + "ibm_pi_key": [ + { + "name": "creation_date", + "type": "TypeString", + "description": "Date of sshkey creation", + "computed": true + }, + { + "name": "ssh_key", + "type": "TypeString", + "description": "SSH RSA key", + "secure": true, + "computed": true + }, + { + "name": "sshkey", + "type": "TypeString", + "secure": true, + "computed": true, + "deprecated": "This field is deprecated, use ssh_key instead" + }, + { + "name": "pi_key_name", + "type": "TypeString", + "description": "SSH key name for a pcloud tenant", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + } + ], + "ibm_pi_keys": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "keys", + "type": "TypeList", + "description": "SSH Keys", + "computed": true, + "elem": { + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "Date of SSH key creation", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "User defined name for the SSH key", + "computed": true + }, + "ssh_key": { + "name": "ssh_key", + "type": "TypeString", + "description": "SSH RSA key", + "computed": true + } + } + } + ], + "ibm_pi_network": [ + { + "name": "vlan_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "available_ip_count", + "type": "TypeFloat", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "computed": true, + "deprecated": "This value is deprecated in favor ofpi_network_name" + }, + { + "name": "jumbo", + "type": "TypeBool", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "computed": true + }, + { + "name": "used_ip_count", + "type": "TypeFloat", + "computed": true + }, + { + "name": "used_ip_percent", + "type": "TypeFloat", + "computed": true + }, + { + "name": "dns", + "type": "TypeSet", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_network_name", + "type": "TypeString", + "description": "Network Name to be used for pvminstances", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "cidr", + "type": "TypeString", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_network_port": [ + { + "name": "pi_network_name", + "type": "TypeString", + "description": "Network Name to be used for pvminstances", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "network_ports", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "required": true + }, + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "ipaddress": { + "name": "ipaddress", + "type": "TypeString", + "optional": true, + "computed": true + }, + "macaddress": { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + "portid": { + "name": "portid", + "type": "TypeString", + "computed": true + }, + "public_ip": { + "name": "public_ip", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_placement_group": [ + { + "name": "pi_placement_group_name", + "type": "TypeString", + "required": true + }, + { + "name": "policy", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "members", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_pi_placement_groups": [ + { + "name": "placement_groups", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "members": { + "name": "members", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "policy": { + "name": "policy", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + } + ], + "ibm_pi_public_network": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "computed": true + }, + { + "name": "vlan_id", + "type": "TypeInt", + "computed": true + } + ], + "ibm_pi_pvm_snapshots": [ + { + "name": "pvm_snapshots", + "type": "TypeList", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "last_updated_date": { + "name": "last_updated_date", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "percent_complete": { + "name": "percent_complete", + "type": "TypeInt", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "volume_snapshots": { + "name": "volume_snapshots", + "type": "TypeMap", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "required": true + } + ], + "ibm_pi_sap_profile": [ + { + "name": "type", + "type": "TypeString", + "description": "Type of profile", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_sap_profile_id", + "type": "TypeString", + "description": "SAP Profile ID", + "required": true + }, + { + "name": "certified", + "type": "TypeBool", + "description": "Has certification been performed on profile", + "computed": true + }, + { + "name": "cores", + "type": "TypeInt", + "description": "Amount of cores", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "Amount of memory (in GB)", + "computed": true + } + ], + "ibm_pi_sap_profiles": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "profiles", + "type": "TypeList", + "computed": true, + "elem": { + "certified": { + "name": "certified", + "type": "TypeBool", + "description": "Has certification been performed on profile", + "computed": true + }, + "cores": { + "name": "cores", + "type": "TypeInt", + "description": "Amount of cores", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "Amount of memory (in GB)", + "computed": true + }, + "profile_id": { + "name": "profile_id", + "type": "TypeString", + "description": "SAP Profile ID", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of profile", + "computed": true + } + } + } + ], + "ibm_pi_shared_processor_pool": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the shared processor pool", + "computed": true + }, + { + "name": "host_id", + "type": "TypeInt", + "description": "The host ID where the shared processor pool resides", + "computed": true + }, + { + "name": "available_cores", + "type": "TypeFloat", + "description": "Shared processor pool available cores", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the shared processor pool", + "computed": true + }, + { + "name": "instances", + "type": "TypeList", + "description": "List of server instances deployed in the shared processor pool", + "computed": true, + "elem": { + "availability_zone": { + "name": "availability_zone", + "type": "TypeString", + "description": "Availability zone for the server instances", + "optional": true, + "computed": true + }, + "cpus": { + "name": "cpus", + "type": "TypeInt", + "description": "The amount of cpus for the server instance", + "optional": true, + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The server instance ID", + "optional": true, + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory for the server instance", + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The server instance name", + "optional": true, + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Status of the server", + "optional": true, + "computed": true + }, + "uncapped": { + "name": "uncapped", + "type": "TypeBool", + "description": "Identifies if uncapped or not", + "optional": true, + "computed": true + }, + "vcpus": { + "name": "vcpus", + "type": "TypeFloat", + "description": "The amout of vcpus for the server instance", + "optional": true, + "computed": true + } + } + }, + { + "name": "pi_shared_processor_pool_id", + "type": "TypeString", + "required": true + }, + { + "name": "reserved_cores", + "type": "TypeInt", + "description": "The amount of reserved cores for the shared processor pool", + "computed": true + }, + { + "name": "allocated_cores", + "type": "TypeFloat", + "description": "Shared processor pool allocated cores", + "computed": true + }, + { + "name": "status_detail", + "type": "TypeString", + "description": "The status details of the shared processor pool", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + } + ], + "ibm_pi_shared_processor_pools": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "shared_processor_pools", + "type": "TypeList", + "computed": true, + "elem": { + "allocated_cores": { + "name": "allocated_cores", + "type": "TypeFloat", + "computed": true + }, + "available_cores": { + "name": "available_cores", + "type": "TypeInt", + "computed": true + }, + "host_id": { + "name": "host_id", + "type": "TypeInt", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "reserved_cores": { + "name": "reserved_cores", + "type": "TypeInt", + "computed": true + }, + "shared_processor_pool_id": { + "name": "shared_processor_pool_id", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "status_detail": { + "name": "status_detail", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_spp_placement_group": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "members", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_spp_placement_group_id", + "type": "TypeString", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "computed": true + }, + { + "name": "policy", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_spp_placement_groups": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "spp_placement_groups", + "type": "TypeList", + "computed": true, + "elem": { + "members": { + "name": "members", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "policy": { + "name": "policy", + "type": "TypeString", + "computed": true + }, + "spp_placement_group_id": { + "name": "spp_placement_group_id", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_storage_pool_capacity": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_storage_pool", + "type": "TypeString", + "description": "Storage pool name", + "required": true + }, + { + "name": "max_allocation_size", + "type": "TypeInt", + "description": "Maximum allocation storage size (GB)", + "computed": true + }, + { + "name": "storage_type", + "type": "TypeString", + "description": "Storage type of the storage pool", + "computed": true + }, + { + "name": "total_capacity", + "type": "TypeInt", + "description": "Total pool capacity (GB)", + "computed": true + } + ], + "ibm_pi_storage_pools_capacity": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "maximum_storage_allocation", + "type": "TypeMap", + "description": "Maximum storage allocation", + "computed": true + }, + { + "name": "storage_pools_capacity", + "type": "TypeList", + "description": "Storage pools capacity", + "computed": true, + "elem": { + "max_allocation_size": { + "name": "max_allocation_size", + "type": "TypeInt", + "description": "Maximum allocation storage size (GB)", + "computed": true + }, + "pool_name": { + "name": "pool_name", + "type": "TypeString", + "description": "Pool name", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "description": "Storage type of the storage pool", + "computed": true + }, + "total_capacity": { + "name": "total_capacity", + "type": "TypeInt", + "description": "Total pool capacity (GB)", + "computed": true + } + } + } + ], + "ibm_pi_storage_type_capacity": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_storage_type", + "type": "TypeString", + "description": "Storage type name", + "required": true + }, + { + "name": "maximum_storage_allocation", + "type": "TypeMap", + "description": "Maximum storage allocation", + "computed": true + }, + { + "name": "storage_pools_capacity", + "type": "TypeList", + "description": "Storage pools capacity", + "computed": true, + "elem": { + "max_allocation_size": { + "name": "max_allocation_size", + "type": "TypeInt", + "description": "Maximum allocation storage size (GB)", + "computed": true + }, + "pool_name": { + "name": "pool_name", + "type": "TypeString", + "description": "Pool name", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "description": "Storage type of the storage pool", + "computed": true + }, + "total_capacity": { + "name": "total_capacity", + "type": "TypeInt", + "description": "Total pool capacity (GB)", + "computed": true + } + } + } + ], + "ibm_pi_storage_types_capacity": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "maximum_storage_allocation", + "type": "TypeMap", + "description": "Maximum storage allocation", + "computed": true + }, + { + "name": "storage_types_capacity", + "type": "TypeList", + "description": "Storage types capacity", + "computed": true, + "elem": { + "maximum_storage_allocation": { + "name": "maximum_storage_allocation", + "type": "TypeMap", + "description": "Maximum storage allocation", + "computed": true + }, + "storage_pools_capacity": { + "name": "storage_pools_capacity", + "type": "TypeList", + "description": "Storage pools capacity", + "computed": true, + "elem": { + "max_allocation_size": { + "name": "max_allocation_size", + "type": "TypeInt", + "description": "Maximum allocation storage size (GB)", + "computed": true + }, + "pool_name": { + "name": "pool_name", + "type": "TypeString", + "description": "Pool name", + "computed": true + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "description": "Storage type of the storage pool", + "computed": true + }, + "total_capacity": { + "name": "total_capacity", + "type": "TypeInt", + "description": "Total pool capacity (GB)", + "computed": true + } + } + }, + "storage_type": { + "name": "storage_type", + "type": "TypeString", + "description": "The storage type", + "computed": true + } + } + } + ], + "ibm_pi_system_pools": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "system_pools", + "type": "TypeList", + "description": "List of available system pools within a particular DataCenter", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeMap", + "description": "Advertised capacity cores and memory (GB)", + "computed": true + }, + "core_memory_ratio": { + "name": "core_memory_ratio", + "type": "TypeFloat", + "description": "Processor to Memory (GB) Ratio", + "computed": true + }, + "max_available": { + "name": "max_available", + "type": "TypeMap", + "description": "Maximum configurable cores and memory (GB) (aggregated from all hosts)", + "computed": true + }, + "max_cores_available": { + "name": "max_cores_available", + "type": "TypeMap", + "description": "Maximum configurable cores available combined with available memory of that host", + "computed": true + }, + "max_memory_available": { + "name": "max_memory_available", + "type": "TypeMap", + "description": "Maximum configurable memory available combined with available cores of that host", + "computed": true + }, + "shared_core_ratio": { + "name": "shared_core_ratio", + "type": "TypeMap", + "description": "The min-max-default allocation percentage of shared core per vCPU", + "computed": true + }, + "system_pool_name": { + "name": "system_pool_name", + "type": "TypeString", + "description": "The system pool name", + "computed": true + }, + "systems": { + "name": "systems", + "type": "TypeList", + "description": "The DataCenter list of servers and their available resources", + "computed": true, + "elem": { + "cores": { + "name": "cores", + "type": "TypeString", + "description": "The host available Processor units", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The host identifier", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeString", + "description": "The host available RAM memory in GiB", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of system hardware", + "computed": true + } + } + } + ], + "ibm_pi_tenant": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "tenant_name", + "type": "TypeString", + "computed": true + }, + { + "name": "cloud_instances", + "type": "TypeSet", + "computed": true, + "elem": { + "cloud_instance_id": { + "name": "cloud_instance_id", + "type": "TypeString", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_pi_volume": [ + { + "name": "shareable", + "type": "TypeBool", + "computed": true + }, + { + "name": "disk_type", + "type": "TypeString", + "computed": true + }, + { + "name": "volume_pool", + "type": "TypeString", + "computed": true + }, + { + "name": "wwn", + "type": "TypeString", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "computed": true + }, + { + "name": "bootable", + "type": "TypeBool", + "computed": true + }, + { + "name": "pi_volume_name", + "type": "TypeString", + "description": "Volume Name to be used for pvminstances", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + } + ], + "ibm_pn_application_chrome": [ + { + "name": "web_site_url", + "type": "TypeString", + "description": "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Unique guid of the application using the push service.", + "required": true + }, + { + "name": "server_key", + "type": "TypeString", + "description": "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", + "computed": true + } + ], + "ibm_resource_group": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the resource group was initially created.", + "computed": true + }, + { + "name": "teams_url", + "type": "TypeString", + "description": "The URL to access the team details that associated with the resource group.", + "computed": true + }, + { + "name": "resource_linkages", + "type": "TypeSet", + "description": "An array of the resources that linked to the resource group", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Default Resource group", + "optional": true, + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "State of the resource group", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date when the resource group was last updated.", + "computed": true + }, + { + "name": "payment_methods_url", + "type": "TypeString", + "description": "The URL to access the payment methods details that associated with the resource group.", + "computed": true + }, + { + "name": "quota_url", + "type": "TypeString", + "description": "The URL to access the quota details that associated with the resource group.", + "computed": true + }, + { + "name": "quota_id", + "type": "TypeString", + "description": "An alpha-numeric value identifying the quota ID associated with the resource group.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Account ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource group name", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:name" + ] + }, + { + "name": "crn", + "type": "TypeString", + "description": "The full CRN associated with the resource group", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_resource_instance": [ + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the resource instance.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the environment in which instance exists", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The service type of the instance", + "optional": true, + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags of Resource Instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of resource instance", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, myobjectstorage", + "required": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the instance", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the instance is present", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + } + ], + "ibm_resource_key": [ + { + "name": "resource_alias_id", + "type": "TypeString", + "description": "The id of the resource alias", + "optional": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created resource key is used. If false, an error is returned", + "default_value": false, + "optional": true + }, + { + "name": "credentials", + "type": "TypeMap", + "description": "Credentials asociated with the key", + "secure": true, + "computed": true + }, + { + "name": "credentials_json", + "type": "TypeString", + "description": "Credentials asociated with the key in json string", + "secure": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "crn of resource key", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the resource key", + "required": true + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The id of the resource instance", + "cloud_data_type": "resource_instance", + "optional": true, + "cloud_data_range": [ + "service:%s" + ] + }, + { + "name": "role", + "type": "TypeString", + "description": "User role", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of resource key", + "computed": true + } + ], + "ibm_resource_quota": [ + { + "name": "max_service_instances", + "type": "TypeInt", + "description": "Defines the total service instances limit.", + "computed": true + }, + { + "name": "vsi_limit", + "type": "TypeInt", + "description": "Defines the VSI limit.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource quota name, for example Trial Quota", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the quota.", + "computed": true + }, + { + "name": "max_apps", + "type": "TypeInt", + "description": "Defines the total app limit.", + "computed": true + }, + { + "name": "max_instances_per_app", + "type": "TypeInt", + "description": "Defines the total instances limit per app.", + "computed": true + }, + { + "name": "max_app_instance_memory", + "type": "TypeString", + "description": "Defines the total memory of app instance.", + "computed": true + }, + { + "name": "total_app_memory", + "type": "TypeString", + "description": "Defines the total memory for app.", + "computed": true + } + ], + "ibm_resource_tag": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type on which the tags should be fetched", + "optional": true + }, + { + "name": "tag_type", + "type": "TypeString", + "description": "Tag type on which the tags should be fetched", + "default_value": "user", + "optional": true + }, + { + "name": "resource_id", + "type": "TypeString", + "description": "CRN of the resource on which the tags should be attached", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags associated with resource instance", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_satellite_attach_host_script": [ + { + "name": "location", + "type": "TypeString", + "description": "A unique name for the new Satellite location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "host_provider", + "type": "TypeString", + "optional": true + }, + { + "name": "host_script", + "type": "TypeString", + "description": "Attach host script content", + "computed": true + }, + { + "name": "custom_script", + "type": "TypeString", + "description": "The custom script that has to be appended to generated host script file", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "A unique name for the new Satellite location", + "computed": true + }, + { + "name": "coreos_host", + "type": "TypeBool", + "description": "If true, returns a CoreOS ignition file for the host. Otherwise, returns a RHEL attach script", + "optional": true + }, + { + "name": "labels", + "type": "TypeSet", + "description": "List of labels for the attach host", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "script_dir", + "type": "TypeString", + "description": "The directory where the satellite attach host script to be downloaded. Default is home directory", + "optional": true, + "computed": true + }, + { + "name": "script_path", + "type": "TypeString", + "description": "The absolute path to the generated host script file", + "computed": true + } + ], + "ibm_satellite_cluster": [ + { + "name": "name", + "type": "TypeString", + "description": "Name or id of the cluster", + "required": true + }, + { + "name": "kube_version", + "type": "TypeString", + "description": "Kubernetes version", + "computed": true + }, + { + "name": "private_service_endpoint", + "type": "TypeBool", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The lifecycle state of the cluster", + "computed": true + }, + { + "name": "workers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "public_service_endpoint", + "type": "TypeBool", + "computed": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the cluster", + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of workers", + "computed": true + }, + { + "name": "worker_pools", + "type": "TypeList", + "computed": true, + "elem": { + "default_worker_pool_labels": { + "name": "default_worker_pool_labels", + "type": "TypeMap", + "computed": true + }, + "flavour": { + "name": "flavour", + "type": "TypeString", + "computed": true + }, + "host_labels": { + "name": "host_labels", + "type": "TypeMap", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "isolation": { + "name": "isolation", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "size_per_zone": { + "name": "size_per_zone", + "type": "TypeInt", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "zones": { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "server_url", + "type": "TypeString", + "description": "The server URL", + "computed": true + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "Name or id of the location", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "health", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_satellite_cluster_worker_pool": [ + { + "name": "name", + "type": "TypeString", + "description": "worker pool name", + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name", + "required": true + }, + { + "name": "zones", + "type": "TypeSet", + "computed": true, + "elem": { + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "isolation", + "type": "TypeString", + "description": "Isolation of the worker node", + "computed": true + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "The operating system of the hosts in the worker pool", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "Name of the region", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "The number of workers that are attached", + "computed": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "The flavor of the satellite worker node", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the worker pool", + "computed": true + }, + { + "name": "worker_pool_labels", + "type": "TypeMap", + "description": "Labels on all the workers in the worker pool", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host_labels", + "type": "TypeMap", + "description": "Host labels on the workers", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "auto_scale_enabled", + "type": "TypeBool", + "description": "Enable auto scalling for worker pool", + "computed": true + } + ], + "ibm_satellite_cluster_worker_pool_zone_attachment": [ + { + "name": "cluster", + "type": "TypeString", + "description": "Name or id of the cluster", + "required": true + }, + { + "name": "worker_pool", + "type": "TypeString", + "description": "worker pool name", + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "worker pool zone name", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that the Satellite location is in. To list the resource group ID of the location, use the `GET /v2/satellite/getController` API method.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of workers", + "computed": true + }, + { + "name": "autobalance_enabled", + "type": "TypeBool", + "description": "Auto enabled status", + "computed": true + }, + { + "name": "messages", + "type": "TypeList", + "description": "Filter features by a list of comma separated collections.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_satellite_endpoint": [ + { + "name": "server_port", + "type": "TypeInt", + "description": "The port number of the server endpoint. For 'http-tunnel' protocol, server_port can be 0, which means any port. Such as 0 is good for 80 (http) and 443 (https).", + "computed": true + }, + { + "name": "connector_port", + "type": "TypeInt", + "description": "The connector port.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Service instance associated with this location.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "client_host", + "type": "TypeString", + "description": "The hostname which Satellite Link server listen on for the on-location endpoint, or the hostname which the connector server listen on for the on-cloud endpoint destiantion.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Whether the Endpoint is active or not.", + "computed": true + }, + { + "name": "last_change", + "type": "TypeString", + "description": "The last time modify the Endpoint configurations.", + "computed": true + }, + { + "name": "endpoint_id", + "type": "TypeString", + "description": "The Endpoint ID.", + "required": true + }, + { + "name": "connection_type", + "type": "TypeString", + "description": "The type of the endpoint.", + "computed": true + }, + { + "name": "display_name", + "type": "TypeString", + "description": "The display name of the endpoint. Endpoint names must start with a letter and end with an alphanumeric character, can contain letters, numbers, and hyphen (-), and must be 63 characters or fewer.", + "computed": true + }, + { + "name": "sni", + "type": "TypeString", + "description": "The server name indicator (SNI) which used to connect to the server endpoint. Only useful if server side requires SNI.", + "computed": true + }, + { + "name": "reject_unauth", + "type": "TypeBool", + "description": "Whether reject any connection to the server application which is not authorized with the list of supplied CAs in the fields certs.server_cert.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The service or person who created the endpoint. Must be 1000 characters or fewer.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The Location ID.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "server_protocol", + "type": "TypeString", + "description": "The protocol in the server application side. This parameter will change to default value if it is omitted even when using PATCH API. If client_protocol is 'udp', server_protocol must be 'udp'. If client_protocol is 'tcp'/'http', server_protocol could be 'tcp'/'tls' and default to 'tcp'. If client_protocol is 'tls'/'https', server_protocol could be 'tcp'/'tls' and default to 'tls'. If client_protocol is 'http-tunnel', server_protocol must be 'tcp'.", + "computed": true + }, + { + "name": "client_port", + "type": "TypeInt", + "description": "The port which Satellite Link server listen on for the on-location, or the port which the connector server listen on for the on-cloud endpoint destiantion.", + "computed": true + }, + { + "name": "certs", + "type": "TypeList", + "description": "The certs. Once it is generated, this field will always be defined even it is unused until the cert/key is deleted.", + "computed": true, + "elem": { + "client": { + "name": "client", + "type": "TypeList", + "description": "The CA which Satellite Link trust when receiving the connection from the client application.", + "computed": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The root cert or the self-signed cert of the client application.", + "computed": true, + "elem": { + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "computed": true + } + } + } + } + }, + "connector": { + "name": "connector", + "type": "TypeList", + "description": "The cert which Satellite Link connector provide to identify itself for connecting to the client/server application.", + "computed": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The end-entity cert of the connector.", + "computed": true, + "elem": { + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "computed": true + } + } + }, + "key": { + "name": "key", + "type": "TypeList", + "description": "The private key of the connector.", + "computed": true, + "elem": { + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The name of the key.", + "computed": true + } + } + } + } + }, + "server": { + "name": "server", + "type": "TypeList", + "description": "The CA which Satellite Link trust when sending the connection to server application.", + "computed": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The root cert or the self-signed cert of the server application.", + "computed": true, + "elem": { + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "computed": true + } + } + } + } + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time when the Endpoint is created.", + "computed": true + }, + { + "name": "server_host", + "type": "TypeString", + "description": "The host name or IP address of the server endpoint. For 'http-tunnel' protocol, server_host can start with '*.' , which means a wildcard to it's sub domains. Such as '*.example.com' can accept request to 'api.example.com' and 'www.example.com'.", + "computed": true + }, + { + "name": "client_mutual_auth", + "type": "TypeBool", + "description": "Whether enable mutual auth in the client application side, when client_protocol is 'tls' or 'https', this field is required.", + "computed": true + }, + { + "name": "server_mutual_auth", + "type": "TypeBool", + "description": "Whether enable mutual auth in the server application side, when client_protocol is 'tls', this field is required.", + "computed": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "The inactivity timeout in the Endpoint side.", + "computed": true + }, + { + "name": "sources", + "type": "TypeList", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the source is enabled for the endpoint.", + "computed": true + }, + "last_change": { + "name": "last_change", + "type": "TypeString", + "description": "The last time modify the Endpoint configurations.", + "computed": true + }, + "pending": { + "name": "pending", + "type": "TypeBool", + "description": "Whether the source has been enabled on this endpoint.", + "computed": true + }, + "source_id": { + "name": "source_id", + "type": "TypeString", + "description": "The Source ID.", + "computed": true + } + } + }, + { + "name": "service_name", + "type": "TypeString", + "description": "The service name of the endpoint.", + "computed": true + }, + { + "name": "performance", + "type": "TypeList", + "description": "The last performance data of the endpoint.", + "computed": true, + "elem": { + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + }, + "connection": { + "name": "connection", + "type": "TypeInt", + "description": "Concurrent connections number of moment when probe read the data.", + "computed": true + }, + "connectors": { + "name": "connectors", + "type": "TypeList", + "description": "The last performance data of the endpoint from each Connector.", + "computed": true, + "elem": { + "connections": { + "name": "connections", + "type": "TypeInt", + "description": "Concurrent connections number of moment when probe read the data from the Connector.", + "computed": true + }, + "connector": { + "name": "connector", + "type": "TypeString", + "description": "The name of the connector reported the performance data.", + "computed": true + }, + "rx_bw": { + "name": "rx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "computed": true + }, + "tx_bw": { + "name": "tx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "computed": true + } + } + }, + "rx_bandwidth": { + "name": "rx_bandwidth", + "type": "TypeInt", + "description": "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + }, + "tx_bandwidth": { + "name": "tx_bandwidth", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + } + } + }, + { + "name": "client_protocol", + "type": "TypeString", + "description": "The protocol in the client application side.", + "computed": true + } + ], + "ibm_satellite_link": [ + { + "name": "created_at", + "type": "TypeString", + "description": "Timestamp of creation of location.", + "computed": true + }, + { + "name": "last_change", + "type": "TypeString", + "description": "Timestamp of latest modification of location.", + "computed": true + }, + { + "name": "performance", + "type": "TypeList", + "description": "The last performance data of the Location.", + "computed": true, + "elem": { + "avg_latency": { + "name": "avg_latency", + "type": "TypeInt", + "description": "Average latency calculated form latency of each Connector between Tunnel Server, unit is ms. -1 means no Connector established Tunnel.", + "computed": true + }, + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + }, + "connectors": { + "name": "connectors", + "type": "TypeList", + "description": "The last performance data of the Location read from each Connector.", + "computed": true, + "elem": { + "connector": { + "name": "connector", + "type": "TypeString", + "description": "The name of the connector reported the performance data.", + "computed": true + }, + "latency": { + "name": "latency", + "type": "TypeInt", + "description": "Latency between Connector and the Tunnel Server it connected.", + "computed": true + }, + "rx_bw": { + "name": "rx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "computed": true + }, + "tx_bw": { + "name": "tx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "computed": true + } + } + }, + "health_status": { + "name": "health_status", + "type": "TypeString", + "description": "Tunnels health status based on the Tunnels number established. Down(0)/Critical(1)/Up(\u003e=2).", + "computed": true + }, + "rx_bandwidth": { + "name": "rx_bandwidth", + "type": "TypeInt", + "description": "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + }, + "tunnels": { + "name": "tunnels", + "type": "TypeInt", + "description": "Tunnels number estbalished from the Location.", + "computed": true + }, + "tx_bandwidth": { + "name": "tx_bandwidth", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", + "computed": true + } + } + }, + { + "name": "location", + "type": "TypeString", + "description": "The Location ID.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "satellite_link_host", + "type": "TypeString", + "description": "Satellite Link hostname of the location.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the location.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Enabled/Disabled.", + "computed": true + }, + { + "name": "ws_endpoint", + "type": "TypeString", + "description": "The ws endpoint of the location.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Service instance associated with this location.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_satellite_location": [ + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "hosts", + "type": "TypeList", + "computed": true, + "elem": { + "cluster_name": { + "name": "cluster_name", + "type": "TypeString", + "computed": true + }, + "host_id": { + "name": "host_id", + "type": "TypeString", + "computed": true + }, + "host_labels": { + "name": "host_labels", + "type": "TypeMap", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "host_name": { + "name": "host_name", + "type": "TypeString", + "computed": true + }, + "ip_address": { + "name": "ip_address", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "location", + "type": "TypeString", + "description": "A unique name for the new Satellite location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "Name of the resource group", + "computed": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Created Date", + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "zones", + "type": "TypeSet", + "description": "The names of at least three high availability zones to use for the location", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "Location CRN", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "logging_account_id", + "type": "TypeString", + "description": "The account ID for IBM Log Analysis with LogDNA log forwarding", + "computed": true + }, + { + "name": "host_attached_count", + "type": "TypeInt", + "description": "The total number of hosts that are attached to the Satellite location.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managed_from", + "type": "TypeString", + "description": "The IBM Cloud metro from which the Satellite location is managed", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "A description of the new Satellite location", + "computed": true + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "coreos_enabled", + "type": "TypeBool", + "description": "If Red Hat CoreOS features are enabled within the Satellite location", + "computed": true + }, + { + "name": "host_available_count", + "type": "TypeInt", + "description": "The available number of hosts that can be assigned to a cluster resource in the Satellite location.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_satellite_location_nlb_dns": [ + { + "name": "location", + "type": "TypeString", + "description": "A unique name of the Location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "nlb_config", + "type": "TypeList", + "description": "List of nlb config of Location", + "computed": true, + "elem": { + "cluster": { + "name": "cluster", + "type": "TypeString", + "description": "Cluster Id.", + "computed": true + }, + "dns_type": { + "name": "dns_type", + "type": "TypeString", + "description": "Type of DNS.", + "computed": true + }, + "lb_hostname": { + "name": "lb_hostname", + "type": "TypeString", + "description": "Host Name of load Balancer.", + "computed": true + }, + "nlb_ips": { + "name": "nlb_ips", + "type": "TypeList", + "description": "NLB IPs.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "nlb_sub_domain": { + "name": "nlb_sub_domain", + "type": "TypeString", + "description": "NLB Sub-Domain.", + "computed": true + }, + "secret_name": { + "name": "secret_name", + "type": "TypeString", + "description": "Name of the secret.", + "computed": true + }, + "secret_namespace": { + "name": "secret_namespace", + "type": "TypeString", + "description": "Namespace of Secret.", + "computed": true + }, + "secret_status": { + "name": "secret_status", + "type": "TypeString", + "description": "Status of Secret.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Nlb Type.", + "computed": true + } + } + } + ], + "ibm_scc_account_location": [ + { + "name": "results_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to get the results for the Configuration Governance component.", + "computed": true + }, + { + "name": "compliance_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Posture Management APIs.", + "computed": true + }, + { + "name": "analytics_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to generate analytics for the Posture Management component.", + "computed": true + }, + { + "name": "si_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Security Insights APIs.", + "computed": true + }, + { + "name": "regions", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The programatic ID of the available regions.", + "computed": true + } + } + }, + { + "name": "location_id", + "type": "TypeString", + "description": "The programatic ID of the location that you want to work in.", + "required": true + }, + { + "name": "main_endpoint_url", + "type": "TypeString", + "description": "The base URL for the service.", + "computed": true + }, + { + "name": "governance_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Configuration Governance APIs.", + "computed": true + } + ], + "ibm_scc_account_location_settings": [ + { + "name": "id", + "type": "TypeString", + "description": "The programatic ID of the location that you want to work in.", + "computed": true + } + ], + "ibm_scc_account_locations": [ + { + "name": "locations", + "type": "TypeList", + "computed": true, + "elem": { + "analytics_endpoint_url": { + "name": "analytics_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to generate analytics for the Posture Management component.", + "computed": true + }, + "compliance_endpoint_url": { + "name": "compliance_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Posture Management APIs.", + "computed": true + }, + "governance_endpoint_url": { + "name": "governance_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Configuration Governance APIs.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The programatic ID of the location that you want to work in.", + "computed": true + }, + "main_endpoint_url": { + "name": "main_endpoint_url", + "type": "TypeString", + "description": "The base URL for the service.", + "computed": true + }, + "regions": { + "name": "regions", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The programatic ID of the available regions.", + "computed": true + } + } + }, + "results_endpoint_url": { + "name": "results_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to get the results for the Configuration Governance component.", + "computed": true + }, + "si_endpoint_url": { + "name": "si_endpoint_url", + "type": "TypeString", + "description": "The endpoint that is used to call the Security Insights APIs.", + "computed": true + } + } + } + ], + "ibm_scc_account_notification_settings": [ + { + "name": "instance_crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect.", + "computed": true + } + ], + "ibm_scc_posture_collector": [ + { + "name": "failure_count", + "type": "TypeInt", + "description": "The number of times the collector has failed.", + "computed": true + }, + { + "name": "reset_reason", + "type": "TypeString", + "description": "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + "computed": true + }, + { + "name": "status_description", + "type": "TypeString", + "description": "The collector status.", + "computed": true + }, + { + "name": "is_ubi_image", + "type": "TypeBool", + "description": "Determines whether the collector has a Ubi image.", + "computed": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The id of the user that modified the collector.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was modified.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The id of the user that created the collector.", + "computed": true + }, + { + "name": "registration_code", + "type": "TypeString", + "description": "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + "computed": true + }, + { + "name": "reset_time", + "type": "TypeString", + "description": "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + "computed": true + }, + { + "name": "managed_by", + "type": "TypeString", + "description": "The entity that manages the collector.", + "computed": true + }, + { + "name": "collector_version", + "type": "TypeString", + "description": "The collector version. This field is populated when collector is installed.", + "computed": true + }, + { + "name": "approved_local_gateway_ip", + "type": "TypeString", + "description": "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + { + "name": "last_failed_local_gateway_ip", + "type": "TypeString", + "description": "The failed local gateway ip. This field will be populated only when collector is installed.", + "computed": true + }, + { + "name": "credential_public_key", + "type": "TypeString", + "description": "The credential public key.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of collector.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the collector.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Identifies whether the collector is enabled or not(deleted).", + "computed": true + }, + { + "name": "install_path", + "type": "TypeString", + "description": "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + "computed": true + }, + { + "name": "approved_internet_gateway_ip", + "type": "TypeString", + "description": "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + "computed": true + }, + { + "name": "use_private_endpoint", + "type": "TypeBool", + "description": "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + "computed": true + }, + { + "name": "last_failed_internet_gateway_ip", + "type": "TypeString", + "description": "The failed internet gateway ip of the collector.", + "computed": true + }, + { + "name": "is_public", + "type": "TypeBool", + "description": "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + "computed": true + }, + { + "name": "last_heartbeat", + "type": "TypeString", + "description": "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + "computed": true + }, + { + "name": "image_version", + "type": "TypeString", + "description": "The image version of the collector. This field is populated when collector is installed. \".", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was created.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the collector.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of the collector.", + "computed": true + }, + { + "name": "trial_expiry", + "type": "TypeString", + "description": "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + "computed": true + }, + { + "name": "collector_id", + "type": "TypeString", + "description": "The id for the given API.", + "required": true + }, + { + "name": "display_name", + "type": "TypeString", + "description": "The user-friendly name of the collector.", + "computed": true + } + ], + "ibm_scc_posture_collectors": [ + { + "name": "limit", + "type": "TypeInt", + "description": "The number of items to return.", + "computed": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of items in the list. This will have value as 0 when no collectors are available and below values will not be populated in that case.", + "computed": true + }, + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "next", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "collectors", + "type": "TypeList", + "description": "The array of items returned.", + "computed": true, + "elem": { + "approved_internet_gateway_ip": { + "name": "approved_internet_gateway_ip", + "type": "TypeString", + "description": "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "approved_local_gateway_ip": { + "name": "approved_local_gateway_ip", + "type": "TypeString", + "description": "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "collector_version": { + "name": "collector_version", + "type": "TypeString", + "description": "The collector version. This field is populated when collector is installed.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The id of the user that created the collector.", + "computed": true + }, + "credential_public_key": { + "name": "credential_public_key", + "type": "TypeString", + "description": "The credential public key.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the collector.", + "computed": true + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "The user-friendly name of the collector.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Identifies whether the collector is enabled or not(deleted).", + "computed": true + }, + "failure_count": { + "name": "failure_count", + "type": "TypeInt", + "description": "The number of times the collector has failed.", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The id of the collector.", + "computed": true + }, + "image_version": { + "name": "image_version", + "type": "TypeString", + "description": "The image version of the collector. This field is populated when collector is installed. \".", + "computed": true + }, + "install_path": { + "name": "install_path", + "type": "TypeString", + "description": "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + "computed": true + }, + "is_public": { + "name": "is_public", + "type": "TypeBool", + "description": "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + "computed": true + }, + "is_ubi_image": { + "name": "is_ubi_image", + "type": "TypeBool", + "description": "Determines whether the collector has a Ubi image.", + "computed": true + }, + "last_failed_internet_gateway_ip": { + "name": "last_failed_internet_gateway_ip", + "type": "TypeString", + "description": "The failed internet gateway ip of the collector.", + "computed": true + }, + "last_failed_local_gateway_ip": { + "name": "last_failed_local_gateway_ip", + "type": "TypeString", + "description": "The failed local gateway ip. This field will be populated only when collector is installed.", + "computed": true + }, + "last_heartbeat": { + "name": "last_heartbeat", + "type": "TypeString", + "description": "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + "computed": true + }, + "managed_by": { + "name": "managed_by", + "type": "TypeString", + "description": "The entity that manages the collector.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the collector.", + "computed": true + }, + "public_key": { + "name": "public_key", + "type": "TypeString", + "description": "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + "computed": true + }, + "registration_code": { + "name": "registration_code", + "type": "TypeString", + "description": "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + "computed": true + }, + "reset_reason": { + "name": "reset_reason", + "type": "TypeString", + "description": "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + "computed": true + }, + "reset_time": { + "name": "reset_time", + "type": "TypeString", + "description": "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of collector.", + "computed": true + }, + "status_description": { + "name": "status_description", + "type": "TypeString", + "description": "The collector status.", + "computed": true + }, + "trial_expiry": { + "name": "trial_expiry", + "type": "TypeString", + "description": "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the collector.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was modified.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The id of the user that modified the collector.", + "computed": true + }, + "use_private_endpoint": { + "name": "use_private_endpoint", + "type": "TypeBool", + "description": "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + "computed": true + } + } + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The offset from the start of the list (0-based).", + "computed": true + } + ], + "ibm_scc_posture_credential": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The time that the credentials was created in UTC.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user who modified the credentials.", + "computed": true + }, + { + "name": "group", + "type": "TypeList", + "description": "Credential group details.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "credential group id.", + "computed": true + }, + "passphrase": { + "name": "passphrase", + "type": "TypeString", + "description": "passphase of the credential.", + "computed": true + } + } + }, + { + "name": "credential_id", + "type": "TypeString", + "description": "The id for the given API.", + "required": true + }, + { + "name": "credential_type", + "type": "TypeString", + "description": "Credentials type.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Credentials description.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user who created the credentials.", + "computed": true + }, + { + "name": "purpose", + "type": "TypeString", + "description": "Purpose for which the credential is created.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Credentials status enabled/disbaled.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Credentials name.", + "computed": true + }, + { + "name": "display_fields", + "type": "TypeList", + "description": "Details the fields on the credential. This will change as per credential type selected.", + "computed": true, + "elem": { + "auth_url": { + "name": "auth_url", + "type": "TypeString", + "description": "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "aws_arn": { + "name": "aws_arn", + "type": "TypeString", + "description": "AWS arn value.", + "computed": true + }, + "aws_client_id": { + "name": "aws_client_id", + "type": "TypeString", + "description": "AWS client Id.This is mandatory for AWS Cloud.", + "computed": true + }, + "aws_client_secret": { + "name": "aws_client_secret", + "type": "TypeString", + "description": "AWS client secret.This is mandatory for AWS Cloud.", + "computed": true + }, + "aws_region": { + "name": "aws_region", + "type": "TypeString", + "description": "AWS region.", + "computed": true + }, + "azure_client_id": { + "name": "azure_client_id", + "type": "TypeString", + "description": "Azure client Id. This is mandatory for Azure Credential type.", + "computed": true + }, + "azure_client_secret": { + "name": "azure_client_secret", + "type": "TypeString", + "description": "Azure client secret.This is mandatory for Azure Credential type.", + "computed": true + }, + "azure_resource_group": { + "name": "azure_resource_group", + "type": "TypeString", + "description": "Azure resource group.", + "computed": true + }, + "azure_subscription_id": { + "name": "azure_subscription_id", + "type": "TypeString", + "description": "Azure subscription Id.This is mandatory for Azure Credential type.", + "computed": true + }, + "database_name": { + "name": "database_name", + "type": "TypeString", + "description": "Database name.This is mandatory for Database Credential type.", + "computed": true + }, + "ibm_api_key": { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + "computed": true + }, + "ms_365_client_id": { + "name": "ms_365_client_id", + "type": "TypeString", + "description": "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "ms_365_client_secret": { + "name": "ms_365_client_secret", + "type": "TypeString", + "description": "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "ms_365_tenant_id": { + "name": "ms_365_tenant_id", + "type": "TypeString", + "description": "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "computed": true + }, + "pem_data": { + "name": "pem_data", + "type": "TypeString", + "description": "The base64 encoded data to associate with the PEM file.", + "computed": true + }, + "pem_file_name": { + "name": "pem_file_name", + "type": "TypeString", + "description": "The name of the PEM file.", + "computed": true + }, + "project_domain_name": { + "name": "project_domain_name", + "type": "TypeString", + "description": "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "project_name": { + "name": "project_name", + "type": "TypeString", + "description": "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "user_domain_name": { + "name": "user_domain_name", + "type": "TypeString", + "description": "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "computed": true + }, + "winrm_authtype": { + "name": "winrm_authtype", + "type": "TypeString", + "description": "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_port": { + "name": "winrm_port", + "type": "TypeString", + "description": "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_usessl": { + "name": "winrm_usessl", + "type": "TypeString", + "description": "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + "computed": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The modified time that the credentials was modified in UTC.", + "computed": true + } + ], + "ibm_scc_posture_credentials": [ + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "credentials", + "type": "TypeList", + "description": "The details of a credentials.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time that the credentials was created in UTC.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user who created the credentials.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Credentials description.", + "computed": true + }, + "display_fields": { + "name": "display_fields", + "type": "TypeList", + "description": "Details the fields on the credential. This will change as per credential type selected.", + "computed": true, + "elem": { + "auth_url": { + "name": "auth_url", + "type": "TypeString", + "description": "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "aws_arn": { + "name": "aws_arn", + "type": "TypeString", + "description": "AWS arn value.", + "computed": true + }, + "aws_client_id": { + "name": "aws_client_id", + "type": "TypeString", + "description": "AWS client Id.This is mandatory for AWS Cloud.", + "computed": true + }, + "aws_client_secret": { + "name": "aws_client_secret", + "type": "TypeString", + "description": "AWS client secret.This is mandatory for AWS Cloud.", + "secure": true, + "computed": true + }, + "aws_region": { + "name": "aws_region", + "type": "TypeString", + "description": "AWS region.", + "computed": true + }, + "azure_client_id": { + "name": "azure_client_id", + "type": "TypeString", + "description": "Azure client Id. This is mandatory for Azure Credential type.", + "computed": true + }, + "azure_client_secret": { + "name": "azure_client_secret", + "type": "TypeString", + "description": "Azure client secret.This is mandatory for Azure Credential type.", + "secure": true, + "computed": true + }, + "azure_resource_group": { + "name": "azure_resource_group", + "type": "TypeString", + "description": "Azure resource group.", + "computed": true + }, + "azure_subscription_id": { + "name": "azure_subscription_id", + "type": "TypeString", + "description": "Azure subscription Id.This is mandatory for Azure Credential type.", + "computed": true + }, + "database_name": { + "name": "database_name", + "type": "TypeString", + "description": "Database name.This is mandatory for Database Credential type.", + "computed": true + }, + "ibm_api_key": { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + "secure": true, + "computed": true + }, + "ms_365_client_id": { + "name": "ms_365_client_id", + "type": "TypeString", + "description": "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "ms_365_client_secret": { + "name": "ms_365_client_secret", + "type": "TypeString", + "description": "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + "secure": true, + "computed": true + }, + "ms_365_tenant_id": { + "name": "ms_365_tenant_id", + "type": "TypeString", + "description": "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "secure": true, + "computed": true + }, + "pem_data": { + "name": "pem_data", + "type": "TypeString", + "description": "The base64 encoded data to associate with the PEM file.", + "computed": true + }, + "pem_file_name": { + "name": "pem_file_name", + "type": "TypeString", + "description": "The name of the PEM file.", + "computed": true + }, + "project_domain_name": { + "name": "project_domain_name", + "type": "TypeString", + "description": "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "project_name": { + "name": "project_name", + "type": "TypeString", + "description": "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "user_domain_name": { + "name": "user_domain_name", + "type": "TypeString", + "description": "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "computed": true + }, + "winrm_authtype": { + "name": "winrm_authtype", + "type": "TypeString", + "description": "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_port": { + "name": "winrm_port", + "type": "TypeString", + "description": "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_usessl": { + "name": "winrm_usessl", + "type": "TypeString", + "description": "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + "computed": true + } + } + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Credentials status enabled/disbaled.", + "computed": true + }, + "group": { + "name": "group", + "type": "TypeList", + "description": "Credential group details.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "credential group id.", + "computed": true + }, + "passphrase": { + "name": "passphrase", + "type": "TypeString", + "description": "passphase of the credential.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Credentials ID.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Credentials name.", + "computed": true + }, + "purpose": { + "name": "purpose", + "type": "TypeString", + "description": "Purpose for which the credential is created.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Credentials type.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The modified time that the credentials was modified in UTC.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user who modified the credentials.", + "computed": true + } + } + } + ], + "ibm_scc_posture_group_profile": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", + "required": true + }, + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "controls", + "type": "TypeList", + "description": "Profiles array.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the control.", + "computed": true + }, + "external_control_id": { + "name": "external_control_id", + "type": "TypeString", + "description": "The external identifier number of the control.", + "computed": true + }, + "goals": { + "name": "goals", + "type": "TypeList", + "description": "Mapped goals aganist the control identifier.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the goal.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The goal ID.", + "computed": true + }, + "is_auto_remediable": { + "name": "is_auto_remediable", + "type": "TypeBool", + "description": "The goal is autoremediable or not.", + "computed": true + }, + "is_automatable": { + "name": "is_automatable", + "type": "TypeBool", + "description": "The goal is automatable or not.", + "computed": true + }, + "is_manual": { + "name": "is_manual", + "type": "TypeBool", + "description": "The goal is manual check.", + "computed": true + }, + "is_remediable": { + "name": "is_remediable", + "type": "TypeBool", + "description": "The goal is remediable or not.", + "computed": true + }, + "is_reversible": { + "name": "is_reversible", + "type": "TypeBool", + "description": "The goal is reversible or not.", + "computed": true + }, + "severity": { + "name": "severity", + "type": "TypeString", + "description": "The severity of the goal.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The identifier number of the control.", + "computed": true + } + } + } + ], + "ibm_scc_posture_latest_scans": [ + { + "name": "scan_id", + "type": "TypeString", + "description": "The ID of the scan.", + "optional": true + }, + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "latest_scans", + "type": "TypeList", + "description": "The details of a scan.", + "computed": true, + "elem": { + "end_time": { + "name": "end_time", + "type": "TypeString", + "description": "The date and time the scan completed.", + "computed": true + }, + "group_profile_id": { + "name": "group_profile_id", + "type": "TypeString", + "description": "The group ID of profile.", + "computed": true + }, + "group_profile_name": { + "name": "group_profile_name", + "type": "TypeString", + "description": "The group name of the profile.", + "computed": true + }, + "profiles": { + "name": "profiles", + "type": "TypeList", + "description": "Profiles array.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "An auto-generated unique identifier for the scope.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of profile.", + "computed": true + } + } + }, + "report_run_by": { + "name": "report_run_by", + "type": "TypeString", + "description": "The entity that ran the report.", + "computed": true + }, + "report_setting_id": { + "name": "report_setting_id", + "type": "TypeString", + "description": "The unique ID for Scan that is created.", + "computed": true + }, + "result": { + "name": "result", + "type": "TypeList", + "description": "The result of a scan.The above values will not be avaialble if no scopes are available.", + "computed": true, + "elem": { + "controls_fail_count": { + "name": "controls_fail_count", + "type": "TypeInt", + "description": "The number of controls that failed the scan.", + "computed": true + }, + "controls_not_applicable_count": { + "name": "controls_not_applicable_count", + "type": "TypeInt", + "description": "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "controls_pass_count": { + "name": "controls_pass_count", + "type": "TypeInt", + "description": "The number of controls that passed the scan.", + "computed": true + }, + "controls_total_count": { + "name": "controls_total_count", + "type": "TypeInt", + "description": "The total number of controls that were included in the scan.", + "computed": true + }, + "controls_unable_to_perform_count": { + "name": "controls_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + }, + "goals_fail_count": { + "name": "goals_fail_count", + "type": "TypeInt", + "description": "The number of goals that failed the scan.", + "computed": true + }, + "goals_not_applicable_count": { + "name": "goals_not_applicable_count", + "type": "TypeInt", + "description": "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "goals_pass_count": { + "name": "goals_pass_count", + "type": "TypeInt", + "description": "The number of goals that passed the scan.", + "computed": true + }, + "goals_total_count": { + "name": "goals_total_count", + "type": "TypeInt", + "description": "The total number of goals that were included in the scan.", + "computed": true + }, + "goals_unable_to_perform_count": { + "name": "goals_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + } + } + }, + "scan_id": { + "name": "scan_id", + "type": "TypeString", + "description": "The ID of the scan.", + "computed": true + }, + "scan_name": { + "name": "scan_name", + "type": "TypeString", + "description": "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", + "computed": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The scope ID of the scan.", + "computed": true + }, + "scope_name": { + "name": "scope_name", + "type": "TypeString", + "description": "The name of the scope.", + "computed": true + }, + "start_time": { + "name": "start_time", + "type": "TypeString", + "description": "The date and time the scan was run.", + "computed": true + } + } + } + ], + "ibm_scc_posture_profile": [ + { + "name": "description", + "type": "TypeString", + "description": "A description of the profile.", + "computed": true + }, + { + "name": "reason_for_delete", + "type": "TypeString", + "description": "A reason that you want to delete a profile.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + "computed": true + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "The id for the given API.", + "required": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The user who created the profile.", + "computed": true + }, + { + "name": "no_of_controls", + "type": "TypeInt", + "description": "no of Controls.", + "computed": true + }, + { + "name": "profile_type", + "type": "TypeString", + "description": "The profile type ID. This will be 4 for profiles and 6 for group profiles.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "computed": true + }, + { + "name": "version", + "type": "TypeInt", + "description": "The version of the profile.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time that the profile was created in UTC.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The time that the profile was most recently modified in UTC.", + "computed": true + }, + { + "name": "modified_by", + "type": "TypeString", + "description": "The user who last modified the profile.", + "computed": true + }, + { + "name": "base_profile", + "type": "TypeString", + "description": "The base profile that the controls are pulled from.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of profile.", + "computed": true + } + ], + "ibm_scc_posture_profiles": [ + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "profiles", + "type": "TypeList", + "description": "Profiles.", + "computed": true, + "elem": { + "base_profile": { + "name": "base_profile", + "type": "TypeString", + "description": "The base profile that the controls are pulled from.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time that the profile was created in UTC.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The user who created the profile.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "A description of the profile.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "An auto-generated unique identifying number of the profile.", + "computed": true + }, + "modified_by": { + "name": "modified_by", + "type": "TypeString", + "description": "The user who last modified the profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "computed": true + }, + "no_of_controls": { + "name": "no_of_controls", + "type": "TypeInt", + "description": "no of Controls.", + "computed": true + }, + "reason_for_delete": { + "name": "reason_for_delete", + "type": "TypeString", + "description": "A reason that you want to delete a profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of profile.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The time that the profile was most recently modified in UTC.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeInt", + "description": "The version of the profile.", + "computed": true + } + } + } + ], + "ibm_scc_posture_scan_summaries": [ + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "summaries", + "type": "TypeList", + "description": "Summaries.", + "computed": true, + "elem": { + "end_time": { + "name": "end_time", + "type": "TypeString", + "description": "The date and time the scan completed.", + "computed": true + }, + "group_profiles": { + "name": "group_profiles", + "type": "TypeList", + "description": "The list of group profiles.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID of the profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", + "computed": true + }, + "validation_result": { + "name": "validation_result", + "type": "TypeList", + "description": "The result of a scan.The above values will not be avaialble if no scopes are available.", + "computed": true, + "elem": { + "controls_fail_count": { + "name": "controls_fail_count", + "type": "TypeInt", + "description": "The number of controls that failed the scan.", + "computed": true + }, + "controls_not_applicable_count": { + "name": "controls_not_applicable_count", + "type": "TypeInt", + "description": "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "controls_pass_count": { + "name": "controls_pass_count", + "type": "TypeInt", + "description": "The number of controls that passed the scan.", + "computed": true + }, + "controls_total_count": { + "name": "controls_total_count", + "type": "TypeInt", + "description": "The total number of controls that were included in the scan.", + "computed": true + }, + "controls_unable_to_perform_count": { + "name": "controls_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + }, + "goals_fail_count": { + "name": "goals_fail_count", + "type": "TypeInt", + "description": "The number of goals that failed the scan.", + "computed": true + }, + "goals_not_applicable_count": { + "name": "goals_not_applicable_count", + "type": "TypeInt", + "description": "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "goals_pass_count": { + "name": "goals_pass_count", + "type": "TypeInt", + "description": "The number of goals that passed the scan.", + "computed": true + }, + "goals_total_count": { + "name": "goals_total_count", + "type": "TypeInt", + "description": "The total number of goals that were included in the scan.", + "computed": true + }, + "goals_unable_to_perform_count": { + "name": "goals_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + } + } + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID of the scan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name.", + "computed": true + }, + "profiles": { + "name": "profiles", + "type": "TypeList", + "description": "The list of profiles.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID of the profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles).", + "computed": true + }, + "validation_result": { + "name": "validation_result", + "type": "TypeList", + "description": "The result of a scan.The above values will not be avaialble if no scopes are available.", + "computed": true, + "elem": { + "controls_fail_count": { + "name": "controls_fail_count", + "type": "TypeInt", + "description": "The number of controls that failed the scan.", + "computed": true + }, + "controls_not_applicable_count": { + "name": "controls_not_applicable_count", + "type": "TypeInt", + "description": "The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "controls_pass_count": { + "name": "controls_pass_count", + "type": "TypeInt", + "description": "The number of controls that passed the scan.", + "computed": true + }, + "controls_total_count": { + "name": "controls_total_count", + "type": "TypeInt", + "description": "The total number of controls that were included in the scan.", + "computed": true + }, + "controls_unable_to_perform_count": { + "name": "controls_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + }, + "goals_fail_count": { + "name": "goals_fail_count", + "type": "TypeInt", + "description": "The number of goals that failed the scan.", + "computed": true + }, + "goals_not_applicable_count": { + "name": "goals_not_applicable_count", + "type": "TypeInt", + "description": "The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found.", + "computed": true + }, + "goals_pass_count": { + "name": "goals_pass_count", + "type": "TypeInt", + "description": "The number of goals that passed the scan.", + "computed": true + }, + "goals_total_count": { + "name": "goals_total_count", + "type": "TypeInt", + "description": "The total number of goals that were included in the scan.", + "computed": true + }, + "goals_unable_to_perform_count": { + "name": "goals_unable_to_perform_count", + "type": "TypeInt", + "description": "The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected.", + "computed": true + } + } + } + } + }, + "report_run_by": { + "name": "report_run_by", + "type": "TypeString", + "description": "The entity that ran the report.", + "computed": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The ID of the scope.", + "computed": true + }, + "scope_name": { + "name": "scope_name", + "type": "TypeString", + "description": "The name of the scope.", + "computed": true + }, + "start_time": { + "name": "start_time", + "type": "TypeString", + "description": "The date and time the scan was run.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the collector as it completes a scan.", + "computed": true + } + } + }, + { + "name": "report_setting_id", + "type": "TypeString", + "description": "The report setting ID. This can be obtained from the /validations/latest_scans API call.", + "required": true + }, + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + } + ], + "ibm_scc_posture_scan_summary": [ + { + "name": "discover_id", + "type": "TypeString", + "description": "The scan discovery ID.", + "computed": true + }, + { + "name": "profile_name", + "type": "TypeString", + "description": "The scan profile name.", + "computed": true + }, + { + "name": "scope_id", + "type": "TypeString", + "description": "The scan summary scope ID.", + "computed": true + }, + { + "name": "controls", + "type": "TypeList", + "description": "The list of controls on the scan summary.", + "computed": true, + "elem": { + "desciption": { + "name": "desciption", + "type": "TypeString", + "description": "The scan profile name.", + "computed": true + }, + "external_control_id": { + "name": "external_control_id", + "type": "TypeString", + "description": "The external control ID.", + "computed": true + }, + "goals": { + "name": "goals", + "type": "TypeList", + "description": "The list of goals on the control.", + "computed": true, + "elem": { + "completed_time": { + "name": "completed_time", + "type": "TypeString", + "description": "The report completed time.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the goal.", + "computed": true + }, + "error": { + "name": "error", + "type": "TypeString", + "description": "The error on goal validation.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The goal ID.", + "computed": true + }, + "resource_result": { + "name": "resource_result", + "type": "TypeList", + "description": "The list of resource results.", + "computed": true, + "elem": { + "actual_value": { + "name": "actual_value", + "type": "TypeString", + "description": "The actual results of a resource.", + "computed": true + }, + "display_expected_value": { + "name": "display_expected_value", + "type": "TypeString", + "description": "The expected results of a resource.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The resource name.", + "computed": true + }, + "not_applicable_reason": { + "name": "not_applicable_reason", + "type": "TypeString", + "description": "The reason for goal not applicable for a resource.", + "computed": true + }, + "results_info": { + "name": "results_info", + "type": "TypeString", + "description": "The results information.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The resource control result status.", + "computed": true + }, + "types": { + "name": "types", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "severity": { + "name": "severity", + "type": "TypeString", + "description": "The severity of the goal.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The goal status.", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The scan summary control ID.", + "computed": true + }, + "resource_statistics": { + "name": "resource_statistics", + "type": "TypeList", + "description": "A scans summary controls.", + "computed": true, + "elem": { + "fail_count": { + "name": "fail_count", + "type": "TypeInt", + "description": "The resource count of fail controls.", + "computed": true + }, + "not_applicable_count": { + "name": "not_applicable_count", + "type": "TypeInt", + "description": "The resource count of not applicable(na) controls.", + "computed": true + }, + "pass_count": { + "name": "pass_count", + "type": "TypeInt", + "description": "The resource count of pass controls.", + "computed": true + }, + "unable_to_perform_count": { + "name": "unable_to_perform_count", + "type": "TypeInt", + "description": "The number of resources that were unable to be scanned against a control.", + "computed": true + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The control status.", + "computed": true + } + } + }, + { + "name": "scan_id", + "type": "TypeString", + "description": "Your Scan ID.", + "required": true + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID.", + "required": true + } + ], + "ibm_scc_posture_scope": [ + { + "name": "is_discovery_scheduled", + "type": "TypeBool", + "description": "Stores the value of scope_is_discovery_scheduled .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "scope_id", + "type": "TypeString", + "description": "The id for the given API.", + "required": true + }, + { + "name": "task_type", + "type": "TypeString", + "description": "Stores the value of scope_task_type .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "region_names", + "type": "TypeString", + "description": "Stores the value of scope_region_names .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "discovery_method", + "type": "TypeString", + "description": "Stores the value of scope_discovery_method .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Stores the value of scope_created_by .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Stores the value of scope_name .", + "computed": true + }, + { + "name": "last_discover_start_time", + "type": "TypeString", + "description": "Stores the value of scope_last_discover_start_time .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "tasks", + "type": "TypeList", + "description": "Stores the value of scope_tasks .Will be displayed only when value exists.", + "computed": true, + "elem": { + "task_created_by": { + "name": "task_created_by", + "type": "TypeString", + "description": "Stores the value of task_created_by .", + "computed": true + }, + "task_derived_status": { + "name": "task_derived_status", + "type": "TypeString", + "description": "Stores the value of task_derived_status .", + "computed": true + }, + "task_discover_id": { + "name": "task_discover_id", + "type": "TypeInt", + "description": "Stores the value of task_discover_id .", + "computed": true + }, + "task_gateway_id": { + "name": "task_gateway_id", + "type": "TypeInt", + "description": "Stores the value of task_gateway_id .", + "computed": true + }, + "task_gateway_name": { + "name": "task_gateway_name", + "type": "TypeString", + "description": "Stores the value of task_gateway_name .", + "computed": true + }, + "task_gateway_schema_id": { + "name": "task_gateway_schema_id", + "type": "TypeInt", + "description": "Stores the value of task_gateway_schema_id .", + "computed": true + }, + "task_id": { + "name": "task_id", + "type": "TypeInt", + "description": "Stores the value of task_id .", + "computed": true + }, + "task_logs": { + "name": "task_logs", + "type": "TypeList", + "description": "Stores the value of task_logs .", + "computed": true, + "elem": {} + }, + "task_schema_name": { + "name": "task_schema_name", + "type": "TypeString", + "description": "Stores the value of task_schema_name .", + "computed": true + }, + "task_start_time": { + "name": "task_start_time", + "type": "TypeInt", + "description": "Stores the value of task_start_time .", + "computed": true + }, + "task_status": { + "name": "task_status", + "type": "TypeString", + "description": "Stores the value of task_status .", + "computed": true + }, + "task_status_msg": { + "name": "task_status_msg", + "type": "TypeString", + "description": "Stores the value of task_status_msg .", + "computed": true + }, + "task_task_type": { + "name": "task_task_type", + "type": "TypeString", + "description": "Stores the value of task_task_type .", + "computed": true + }, + "task_updated_time": { + "name": "task_updated_time", + "type": "TypeInt", + "description": "Stores the value of task_updated_time .", + "computed": true + } + } + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "Stores the value of scope_modified_on .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Stores the value of scope_type .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Stores the value of scope_description .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "status_updated_time", + "type": "TypeString", + "description": "Stores the value of scope_status_updated_time .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "sub_categories_by_type", + "type": "TypeMap", + "description": "Stores the value of scope_sub_categories_by_type .Will be displayed only when value exists.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "file_type", + "type": "TypeString", + "description": "Stores the value of scope_file_type .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "partner_uuid", + "type": "TypeString", + "description": "Stores the value of partner_uuid .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "cloud_type", + "type": "TypeString", + "description": "Stores the value of scope_cloud_type .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "collectors", + "type": "TypeList", + "description": "Stores the value of collectors .Will be displayed only when value exists.", + "computed": true, + "elem": { + "approved_internet_gateway_ip": { + "name": "approved_internet_gateway_ip", + "type": "TypeString", + "description": "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "approved_local_gateway_ip": { + "name": "approved_local_gateway_ip", + "type": "TypeString", + "description": "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "collector_id": { + "name": "collector_id", + "type": "TypeString", + "description": "The id of the collector.", + "computed": true + }, + "collector_version": { + "name": "collector_version", + "type": "TypeString", + "description": "The collector version. This field is populated when collector is installed.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The id of the user that created the collector.", + "computed": true + }, + "credential_public_key": { + "name": "credential_public_key", + "type": "TypeString", + "description": "The credential public key.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the collector.", + "computed": true + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "The user-friendly name of the collector.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Identifies whether the collector is enabled or not(deleted).", + "computed": true + }, + "failure_count": { + "name": "failure_count", + "type": "TypeInt", + "description": "The number of times the collector has failed.", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + "computed": true + }, + "image_version": { + "name": "image_version", + "type": "TypeString", + "description": "The image version of the collector. This field is populated when collector is installed. \".", + "computed": true + }, + "install_path": { + "name": "install_path", + "type": "TypeString", + "description": "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + "computed": true + }, + "is_public": { + "name": "is_public", + "type": "TypeBool", + "description": "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + "computed": true + }, + "is_ubi_image": { + "name": "is_ubi_image", + "type": "TypeBool", + "description": "Determines whether the collector has a Ubi image.", + "computed": true + }, + "last_failed_internet_gateway_ip": { + "name": "last_failed_internet_gateway_ip", + "type": "TypeString", + "description": "The failed internet gateway ip of the collector.", + "computed": true + }, + "last_failed_local_gateway_ip": { + "name": "last_failed_local_gateway_ip", + "type": "TypeString", + "description": "The failed local gateway ip. This field will be populated only when collector is installed.", + "computed": true + }, + "last_heartbeat": { + "name": "last_heartbeat", + "type": "TypeString", + "description": "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + "computed": true + }, + "managed_by": { + "name": "managed_by", + "type": "TypeString", + "description": "The entity that manages the collector.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the collector.", + "computed": true + }, + "public_key": { + "name": "public_key", + "type": "TypeString", + "description": "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + "computed": true + }, + "registration_code": { + "name": "registration_code", + "type": "TypeString", + "description": "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + "computed": true + }, + "reset_reason": { + "name": "reset_reason", + "type": "TypeString", + "description": "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + "computed": true + }, + "reset_time": { + "name": "reset_time", + "type": "TypeString", + "description": "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of collector.", + "computed": true + }, + "status_description": { + "name": "status_description", + "type": "TypeString", + "description": "The collector status.", + "computed": true + }, + "trial_expiry": { + "name": "trial_expiry", + "type": "TypeString", + "description": "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the collector.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was modified.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The id of the user that modified the collector.", + "computed": true + }, + "use_private_endpoint": { + "name": "use_private_endpoint", + "type": "TypeBool", + "description": "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + "computed": true + } + } + }, + { + "name": "correlation_id", + "type": "TypeString", + "description": "A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation).", + "computed": true + }, + { + "name": "credential_attributes", + "type": "TypeString", + "description": "Stores the value of scope_credential_attributes .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "org_id", + "type": "TypeInt", + "description": "Stores the value of scope_org_id .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "tld_credential_id", + "type": "TypeInt", + "description": "Stores the value of scope_tld_credential_id .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "subset_selected", + "type": "TypeBool", + "description": "Stores the value of scope_subset_selected .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "tld_credentail", + "type": "TypeList", + "description": "Stores the value of ScopeDetailsCredential .", + "computed": true, + "elem": { + "credential_group": { + "name": "credential_group", + "type": "TypeMap", + "description": "Stores the value of credential_credential_group .", + "computed": true + }, + "credential_id": { + "name": "credential_id", + "type": "TypeString", + "description": "Stores the value of credential_id .", + "computed": true + }, + "credential_type": { + "name": "credential_type", + "type": "TypeString", + "description": "Stores the value of credential_type .", + "computed": true + }, + "data": { + "name": "data", + "type": "TypeMap", + "description": "Stores the value of credential_data .", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Stores the value of credential_description .", + "computed": true + }, + "display_fields": { + "name": "display_fields", + "type": "TypeList", + "description": "Details the fields on the credential. This will change as per credential type selected.", + "computed": true, + "elem": { + "auth_url": { + "name": "auth_url", + "type": "TypeString", + "description": "auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "aws_arn": { + "name": "aws_arn", + "type": "TypeString", + "description": "AWS arn value.", + "computed": true + }, + "aws_client_id": { + "name": "aws_client_id", + "type": "TypeString", + "description": "AWS client Id.This is mandatory for AWS Cloud.", + "computed": true + }, + "aws_client_secret": { + "name": "aws_client_secret", + "type": "TypeString", + "description": "AWS client secret.This is mandatory for AWS Cloud.", + "computed": true + }, + "aws_region": { + "name": "aws_region", + "type": "TypeString", + "description": "AWS region.", + "computed": true + }, + "azure_client_id": { + "name": "azure_client_id", + "type": "TypeString", + "description": "Azure client Id. This is mandatory for Azure Credential type.", + "computed": true + }, + "azure_client_secret": { + "name": "azure_client_secret", + "type": "TypeString", + "description": "Azure client secret.This is mandatory for Azure Credential type.", + "computed": true + }, + "azure_resource_group": { + "name": "azure_resource_group", + "type": "TypeString", + "description": "Azure resource group.", + "computed": true + }, + "azure_subscription_id": { + "name": "azure_subscription_id", + "type": "TypeString", + "description": "Azure subscription Id.This is mandatory for Azure Credential type.", + "computed": true + }, + "database_name": { + "name": "database_name", + "type": "TypeString", + "description": "Database name.This is mandatory for Database Credential type.", + "computed": true + }, + "ibm_api_key": { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API Key. This is mandatory for IBM Credential Type.", + "computed": true + }, + "ms_365_client_id": { + "name": "ms_365_client_id", + "type": "TypeString", + "description": "The MS365 client Id.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "ms_365_client_secret": { + "name": "ms_365_client_secret", + "type": "TypeString", + "description": "The MS365 client secret.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "ms_365_tenant_id": { + "name": "ms_365_tenant_id", + "type": "TypeString", + "description": "The MS365 tenantId.This is mandatory for Windows MS365 Credential type.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "computed": true + }, + "pem_data": { + "name": "pem_data", + "type": "TypeString", + "description": "The base64 encoded data to associate with the PEM file.", + "computed": true + }, + "pem_file_name": { + "name": "pem_file_name", + "type": "TypeString", + "description": "The name of the PEM file.", + "computed": true + }, + "project_domain_name": { + "name": "project_domain_name", + "type": "TypeString", + "description": "project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "project_name": { + "name": "project_name", + "type": "TypeString", + "description": "Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "user_domain_name": { + "name": "user_domain_name", + "type": "TypeString", + "description": "user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials.", + "computed": true + }, + "winrm_authtype": { + "name": "winrm_authtype", + "type": "TypeString", + "description": "Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_port": { + "name": "winrm_port", + "type": "TypeString", + "description": "Kerberos windows port.This is mandatory for Windows Kerberos Credential type.", + "computed": true + }, + "winrm_usessl": { + "name": "winrm_usessl", + "type": "TypeString", + "description": "Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type.", + "computed": true + } + } + }, + "enabled_credential_group": { + "name": "enabled_credential_group", + "type": "TypeBool", + "description": "Stores the value of credential_enabled_credential_group .", + "computed": true + }, + "gateway_key": { + "name": "gateway_key", + "type": "TypeString", + "description": "Stores the value of credential_gateway_key .", + "computed": true + }, + "groups": { + "name": "groups", + "type": "TypeList", + "description": "Stores the value of credential_groups .", + "computed": true, + "elem": { + "credential_group_id": { + "name": "credential_group_id", + "type": "TypeString", + "description": "credential group id.", + "computed": true + }, + "passphrase": { + "name": "passphrase", + "type": "TypeString", + "description": "passphase of the credential.", + "computed": true + } + } + }, + "is_enabled": { + "name": "is_enabled", + "type": "TypeBool", + "description": "Stores the value of credential_is_enabled .", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Stores the value of credential_name .", + "computed": true + }, + "purpose": { + "name": "purpose", + "type": "TypeString", + "description": "Stores the value of credential_purpose .", + "computed": true + }, + "uuid": { + "name": "uuid", + "type": "TypeString", + "description": "Stores the value of credential_uuid .", + "computed": true + }, + "version_timestamp": { + "name": "version_timestamp", + "type": "TypeMap", + "description": "Stores the value of credential_version_timestamp .", + "computed": true + } + } + }, + { + "name": "discovery_setting_id", + "type": "TypeInt", + "description": "Stores the value of scope_discovery_setting_id .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "modified_by", + "type": "TypeString", + "description": "Stores the value of scope_modified_by .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "include_new_eagerly", + "type": "TypeBool", + "description": "Stores the value of scope_include_new_eagerly .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "last_discover_completed_time", + "type": "TypeString", + "description": "Stores the value of scope_last_discover_completed_time .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "credentials_by_type", + "type": "TypeMap", + "description": "Stores the value of scope_credentials_by_type .Will be displayed only when value exists.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "credentials_by_sub_categeory_type", + "type": "TypeMap", + "description": "Stores the value of scope_credentials_by_sub_categeory_type .Will be displayed only when value exists.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "first_level_scoped_data", + "type": "TypeList", + "description": "Stores the value of scope_first_level_scoped_data .Will be displayed only when value exists.", + "computed": true, + "elem": { + "scope": { + "name": "scope", + "type": "TypeString", + "description": "Stores the value of scope .", + "computed": true + }, + "scope_changed": { + "name": "scope_changed", + "type": "TypeBool", + "description": "Stores the value of scope_changed .", + "computed": true + }, + "scope_children": { + "name": "scope_children", + "type": "TypeMap", + "description": "Stores the value of scope_children .", + "computed": true + }, + "scope_collector_id": { + "name": "scope_collector_id", + "type": "TypeInt", + "description": "Stores the value of scope_collector_id .", + "computed": true + }, + "scope_discovery_status": { + "name": "scope_discovery_status", + "type": "TypeMap", + "description": "Stores the value of scope_discovery_status .", + "computed": true + }, + "scope_drift": { + "name": "scope_drift", + "type": "TypeString", + "description": "Stores the value of scope_drift .", + "computed": true + }, + "scope_fact_status": { + "name": "scope_fact_status", + "type": "TypeMap", + "description": "Stores the value of scope_fact_status .", + "computed": true + }, + "scope_facts": { + "name": "scope_facts", + "type": "TypeString", + "description": "Stores the value of scope_facts .", + "computed": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "Stores the value of scope_id .", + "computed": true + }, + "scope_init_scope": { + "name": "scope_init_scope", + "type": "TypeString", + "description": "Stores the value of scope_init_scope .", + "computed": true + }, + "scope_list_members": { + "name": "scope_list_members", + "type": "TypeMap", + "description": "Stores the value of scope_list_members .", + "computed": true + }, + "scope_new_found": { + "name": "scope_new_found", + "type": "TypeBool", + "description": "Stores the value of scope_new_found .", + "computed": true + }, + "scope_object": { + "name": "scope_object", + "type": "TypeString", + "description": "Stores the value of scope_object .", + "computed": true + }, + "scope_overlay": { + "name": "scope_overlay", + "type": "TypeString", + "description": "Stores the value of scope_overlay .", + "computed": true + }, + "scope_parse_status": { + "name": "scope_parse_status", + "type": "TypeString", + "description": "Stores the value of scope_parse_status .", + "computed": true + }, + "scope_properties": { + "name": "scope_properties", + "type": "TypeString", + "description": "Stores the value of scope_properties .", + "computed": true + }, + "scope_resource": { + "name": "scope_resource", + "type": "TypeString", + "description": "Stores the value of scope_resource .", + "computed": true + }, + "scope_resource_attributes": { + "name": "scope_resource_attributes", + "type": "TypeMap", + "description": "Stores the value of scope_resource_attributes .", + "computed": true + }, + "scope_resource_category": { + "name": "scope_resource_category", + "type": "TypeString", + "description": "Stores the value of scope_resource_category .", + "computed": true + }, + "scope_resource_type": { + "name": "scope_resource_type", + "type": "TypeString", + "description": "Stores the value of scope_resource_type .", + "computed": true + }, + "scope_transformed_facts": { + "name": "scope_transformed_facts", + "type": "TypeMap", + "description": "Stores the value of scope_transformed_facts .", + "computed": true + } + } + }, + { + "name": "file_format", + "type": "TypeString", + "description": "Stores the value of scope_file_format .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Stores the value of scope_status .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Stores the value of scope_enabled .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "collectors_by_type", + "type": "TypeMap", + "description": "Stores the value of collectors_by_type .Will be displayed only when value exists.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "env_sub_category", + "type": "TypeString", + "description": "Stores the value of scope_env_sub_category .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "interval", + "type": "TypeInt", + "description": "Stores the value of scope_freq .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "resource_groups", + "type": "TypeString", + "description": "Stores the value of scope_resource_groups .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "discovery_methods", + "type": "TypeList", + "description": "Stores the value of scope_discovery_methods .Will be displayed only when value exists.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Stores the value of scope_created_on .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "uuid", + "type": "TypeString", + "description": "Stores the value of scope_uuid .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "cloud_type_id", + "type": "TypeInt", + "description": "Stores the value of scope_cloud_type_id .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "status_msg", + "type": "TypeString", + "description": "Stores the value of scope_status_msg .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "last_successful_discover_start_time", + "type": "TypeString", + "description": "Stores the value of scope_last_successful_discover_start_time .Will be displayed only when value exists.", + "computed": true + }, + { + "name": "last_successful_discover_completed_time", + "type": "TypeString", + "description": "Stores the value of scope_last_successful_discover_completed_time .Will be displayed only when value exists.", + "computed": true + } + ], + "ibm_scc_posture_scope_correlation": [ + { + "name": "correlation_id", + "type": "TypeString", + "description": "A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation).", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Returns the current status of a task.", + "computed": true + }, + { + "name": "start_time", + "type": "TypeString", + "description": "Returns the time that task started.", + "computed": true + }, + { + "name": "last_heartbeat", + "type": "TypeString", + "description": "Returns the time that the scope was last updated. This value exists when collector is installed and running.", + "computed": true + } + ], + "ibm_scc_posture_scopes": [ + { + "name": "first", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "last", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "previous", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "next", + "type": "TypeList", + "description": "The URL of a page.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL of a page.", + "computed": true + } + } + }, + { + "name": "scopes", + "type": "TypeList", + "description": "Scopes.", + "computed": true, + "elem": { + "collectors": { + "name": "collectors", + "type": "TypeList", + "description": "Stores the value of collectors .Will be displayed only when value exists.", + "computed": true, + "elem": { + "approved_internet_gateway_ip": { + "name": "approved_internet_gateway_ip", + "type": "TypeString", + "description": "The approved internet gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "approved_local_gateway_ip": { + "name": "approved_local_gateway_ip", + "type": "TypeString", + "description": "The approved local gateway ip of the collector. This field will be populated only when collector is installed.", + "computed": true + }, + "collector_version": { + "name": "collector_version", + "type": "TypeString", + "description": "The collector version. This field is populated when collector is installed.", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was created.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The id of the user that created the collector.", + "computed": true + }, + "credential_public_key": { + "name": "credential_public_key", + "type": "TypeString", + "description": "The credential public key.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the collector.", + "computed": true + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "The user-friendly name of the collector.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Identifies whether the collector is enabled or not(deleted).", + "computed": true + }, + "failure_count": { + "name": "failure_count", + "type": "TypeInt", + "description": "The number of times the collector has failed.", + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The id of the collector.", + "computed": true + }, + "image_version": { + "name": "image_version", + "type": "TypeString", + "description": "The image version of the collector. This field is populated when collector is installed. \".", + "computed": true + }, + "install_path": { + "name": "install_path", + "type": "TypeString", + "description": "The installation path of the collector. This field will be populated when collector is installed.The value will be folder path.", + "computed": true + }, + "is_public": { + "name": "is_public", + "type": "TypeBool", + "description": "Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + "computed": true + }, + "is_ubi_image": { + "name": "is_ubi_image", + "type": "TypeBool", + "description": "Determines whether the collector has a Ubi image.", + "computed": true + }, + "last_failed_internet_gateway_ip": { + "name": "last_failed_internet_gateway_ip", + "type": "TypeString", + "description": "The failed internet gateway ip of the collector.", + "computed": true + }, + "last_failed_local_gateway_ip": { + "name": "last_failed_local_gateway_ip", + "type": "TypeString", + "description": "The failed local gateway ip. This field will be populated only when collector is installed.", + "computed": true + }, + "last_heartbeat": { + "name": "last_heartbeat", + "type": "TypeString", + "description": "Stores the heartbeat time of a controller . This value exists when collector is installed and running.", + "computed": true + }, + "managed_by": { + "name": "managed_by", + "type": "TypeString", + "description": "The entity that manages the collector.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the collector.", + "computed": true + }, + "public_key": { + "name": "public_key", + "type": "TypeString", + "description": "The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed.", + "computed": true + }, + "registration_code": { + "name": "registration_code", + "type": "TypeString", + "description": "The registration code of the collector.This is will be used for initial authentication during installation of collector.", + "computed": true + }, + "reset_reason": { + "name": "reset_reason", + "type": "TypeString", + "description": "The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field .", + "computed": true + }, + "reset_time": { + "name": "reset_time", + "type": "TypeString", + "description": "The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of collector.", + "computed": true + }, + "status_description": { + "name": "status_description", + "type": "TypeString", + "description": "The collector status.", + "computed": true + }, + "trial_expiry": { + "name": "trial_expiry", + "type": "TypeString", + "description": "The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the collector.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The ISO Date/Time the collector was modified.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The id of the user that modified the collector.", + "computed": true + }, + "use_private_endpoint": { + "name": "use_private_endpoint", + "type": "TypeBool", + "description": "Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false.", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The time that the scope was created in UTC.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The user who created the scope.", + "computed": true + }, + "credential_type": { + "name": "credential_type", + "type": "TypeString", + "description": "The environment that the scope is targeted to.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "A detailed description of the scope.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Indicates whether scope is enabled/disabled.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "An auto-generated unique identifier for the scope.", + "computed": true + }, + "modified_by": { + "name": "modified_by", + "type": "TypeString", + "description": "The user who most recently modified the scope.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "A unique name for your scope.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The time that the scope was last modified in UTC.", + "computed": true + }, + "uuid": { + "name": "uuid", + "type": "TypeString", + "description": "Stores the value of scope_uuid .", + "computed": true + } + } + }, + { + "name": "offset", + "type": "TypeInt", + "description": "The offset of the page.", + "computed": true + }, + { + "name": "limit", + "type": "TypeInt", + "description": "The number of scopes displayed per page.", + "computed": true + }, + { + "name": "total_count", + "type": "TypeInt", + "description": "The total number of scopes. This value is 0 if no scopes are available and below fields will not be available in that case.", + "computed": true + } + ], + "ibm_schematics_action": [ + { + "name": "name", + "type": "TypeString", + "description": "The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action.", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "Action ID.", + "computed": true + }, + { + "name": "source_created_by", + "type": "TypeString", + "description": "E-mail address of user who created the Action Playbook Source.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "E-mail address of the user who updated an action.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for an action. By default, action is created in default resource group.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "bastion", + "type": "TypeList", + "description": "Describes a bastion resource.", + "computed": true, + "elem": { + "host": { + "name": "host", + "type": "TypeString", + "description": "Reference to the Inventory resource definition.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Bastion Name(Unique).", + "computed": true + } + } + }, + { + "name": "targets_ini", + "type": "TypeString", + "description": "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", + "computed": true + }, + { + "name": "source_updated_by", + "type": "TypeString", + "description": "E-mail address of user who updated the action playbook source.", + "computed": true + }, + { + "name": "inventory", + "type": "TypeString", + "description": "Target inventory record ID, used by the action or ansible playbook.", + "computed": true + }, + { + "name": "source_created_at", + "type": "TypeString", + "description": "Action Playbook Source creation time.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "E-mail address of the user who created an action.", + "computed": true + }, + { + "name": "playbook_names", + "type": "TypeList", + "description": "Playbook names retrieved from the respository.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Action description.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Action tags.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "source", + "type": "TypeList", + "description": "Source of templates, playbooks, or controls.", + "computed": true, + "elem": { + "catalog": { + "name": "catalog", + "type": "TypeList", + "description": "Connection details to IBM Cloud Catalog source.", + "computed": true, + "elem": { + "catalog_name": { + "name": "catalog_name", + "type": "TypeString", + "description": "name of the private catalog.", + "computed": true + }, + "offering_id": { + "name": "offering_id", + "type": "TypeString", + "description": "Id of the offering the IBM Catalog.", + "computed": true + }, + "offering_kind": { + "name": "offering_kind", + "type": "TypeString", + "description": "Type of the offering, in the IBM Catalog.", + "computed": true + }, + "offering_name": { + "name": "offering_name", + "type": "TypeString", + "description": "Name of the offering in the IBM Catalog.", + "computed": true + }, + "offering_repo_url": { + "name": "offering_repo_url", + "type": "TypeString", + "description": "Repo Url of the offering, in the IBM Catalog.", + "computed": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "Version string of the offering in the IBM Catalog.", + "computed": true + }, + "offering_version_id": { + "name": "offering_version_id", + "type": "TypeString", + "description": "Id of the offering version the IBM Catalog.", + "computed": true + } + } + }, + "git": { + "name": "git", + "type": "TypeList", + "description": "Connection details to Git source.", + "computed": true, + "elem": { + "computed_git_repo_url": { + "name": "computed_git_repo_url", + "type": "TypeString", + "description": "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + "computed": true + }, + "git_branch": { + "name": "git_branch", + "type": "TypeString", + "description": "Name of the branch, used to fetch the Git Repo.", + "computed": true + }, + "git_release": { + "name": "git_release", + "type": "TypeString", + "description": "Name of the release tag, used to fetch the Git Repo.", + "computed": true + }, + "git_repo_folder": { + "name": "git_repo_folder", + "type": "TypeString", + "description": "Name of the folder in the Git Repo, that contains the template.", + "computed": true + }, + "git_repo_url": { + "name": "git_repo_url", + "type": "TypeString", + "description": "URL to the GIT Repo that can be used to clone the template.", + "computed": true + }, + "git_token": { + "name": "git_token", + "type": "TypeString", + "description": "Personal Access Token to connect to Git URLs.", + "computed": true + } + } + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "computed": true + } + } + }, + { + "name": "action_outputs", + "type": "TypeList", + "description": "Output variables for the Action.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "Action Cloud Resource Name.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "account", + "type": "TypeString", + "description": "Action account ID.", + "computed": true + }, + { + "name": "user_state", + "type": "TypeList", + "description": "User defined status of the Schematics object.", + "computed": true, + "elem": { + "set_at": { + "name": "set_at", + "type": "TypeString", + "description": "When the User who set the state of the Object.", + "computed": true + }, + "set_by": { + "name": "set_by", + "type": "TypeString", + "description": "Name of the User who set the state of the Object.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution.", + "computed": true + } + } + }, + { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "computed": true + }, + { + "name": "source_updated_at", + "type": "TypeString", + "description": "The action playbook updation time.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Action updation time.", + "computed": true + }, + { + "name": "state", + "type": "TypeList", + "description": "Computed state of the Action.", + "computed": true, + "elem": { + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of automation (workspace or action).", + "computed": true + }, + "status_job_id": { + "name": "status_job_id", + "type": "TypeString", + "description": "Job id reference for this status.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Automation status message - to be displayed along with the status_code.", + "computed": true + } + } + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "source_readme_url", + "type": "TypeString", + "description": "URL of the `README` file, for the source URL.", + "computed": true + }, + { + "name": "credentials", + "type": "TypeList", + "description": "credentials of the Action.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "action_inputs", + "type": "TypeList", + "description": "Input variables for the Action.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "settings", + "type": "TypeList", + "description": "Environment variables for the Action.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Action creation time.", + "computed": true + }, + { + "name": "action_id", + "type": "TypeString", + "description": "Action Id. Use GET /actions API to look up the Action Ids in your IBM Cloud account.", + "required": true + }, + { + "name": "bastion_credential", + "type": "TypeList", + "description": "User editable variable data \u0026 system generated reference to value.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "sys_lock", + "type": "TypeList", + "description": "System lock status.", + "computed": true, + "elem": { + "sys_locked": { + "name": "sys_locked", + "type": "TypeBool", + "description": "Is the automation locked by a Schematic job ?.", + "computed": true + }, + "sys_locked_at": { + "name": "sys_locked_at", + "type": "TypeString", + "description": "When the User performed the job that lead to locking of the automation ?.", + "computed": true + }, + "sys_locked_by": { + "name": "sys_locked_by", + "type": "TypeString", + "description": "Name of the User who performed the job, that lead to the locking of the automation.", + "computed": true + } + } + }, + { + "name": "command_parameter", + "type": "TypeString", + "description": "Schematics job command parameter (playbook-name).", + "computed": true + } + ], + "ibm_schematics_inventory": [ + { + "name": "name", + "type": "TypeString", + "description": "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "Inventory id.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of your Inventory. The description can be up to 2048 characters long in size.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "inventories_ini", + "type": "TypeString", + "description": "Input inventory of host and host group for the playbook, in the .ini file format.", + "computed": true + }, + { + "name": "resource_queries", + "type": "TypeList", + "description": "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "inventory_id", + "type": "TypeString", + "description": "Resource Inventory Id. Use `GET /v2/inventories` API to look up the Resource Inventory definition Ids in your IBM Cloud account.", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Inventory creation time.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Inventory.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Inventory updation time.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Inventory.", + "computed": true + } + ], + "ibm_schematics_job": [ + { + "name": "state_store_url", + "type": "TypeString", + "description": "Job state store URL.", + "computed": true + }, + { + "name": "log_summary", + "type": "TypeList", + "description": "Job log summary record.", + "computed": true, + "elem": { + "action_job": { + "name": "action_job", + "type": "TypeList", + "description": "Flow Job log summary.", + "computed": true, + "elem": { + "play_count": { + "name": "play_count", + "type": "TypeFloat", + "description": "number of plays in playbook.", + "computed": true + }, + "recap": { + "name": "recap", + "type": "TypeList", + "description": "Recap records.", + "computed": true, + "elem": { + "changed": { + "name": "changed", + "type": "TypeFloat", + "description": "Number of changed.", + "computed": true + }, + "failed": { + "name": "failed", + "type": "TypeFloat", + "description": "Number of failed.", + "computed": true + }, + "ok": { + "name": "ok", + "type": "TypeFloat", + "description": "Number of OK.", + "computed": true + }, + "skipped": { + "name": "skipped", + "type": "TypeFloat", + "description": "Number of skipped.", + "computed": true + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "List of target or host name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "unreachable": { + "name": "unreachable", + "type": "TypeFloat", + "description": "Number of unreachable.", + "computed": true + } + } + }, + "target_count": { + "name": "target_count", + "type": "TypeFloat", + "description": "number of targets or hosts.", + "computed": true + }, + "task_count": { + "name": "task_count", + "type": "TypeFloat", + "description": "number of tasks in playbook.", + "computed": true + } + } + }, + "elapsed_time": { + "name": "elapsed_time", + "type": "TypeFloat", + "description": "Job log elapsed time (log_analyzed_till - log_start_at).", + "computed": true + }, + "flow_job": { + "name": "flow_job", + "type": "TypeList", + "description": "Flow Job log summary.", + "computed": true, + "elem": { + "workitems": { + "name": "workitems", + "type": "TypeList", + "computed": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace JOB ID.", + "computed": true + }, + "log_url": { + "name": "log_url", + "type": "TypeString", + "description": "Log url for job.", + "computed": true + }, + "resources_add": { + "name": "resources_add", + "type": "TypeFloat", + "description": "Number of resources add.", + "computed": true + }, + "resources_destroy": { + "name": "resources_destroy", + "type": "TypeFloat", + "description": "Number of resources destroy.", + "computed": true + }, + "resources_modify": { + "name": "resources_modify", + "type": "TypeFloat", + "description": "Number of resources modify.", + "computed": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "workspace ID.", + "computed": true + } + } + }, + "workitems_completed": { + "name": "workitems_completed", + "type": "TypeFloat", + "description": "Number of workitems completed successfully.", + "computed": true + }, + "workitems_failed": { + "name": "workitems_failed", + "type": "TypeFloat", + "description": "Number of workitems failed.", + "computed": true + }, + "workitems_pending": { + "name": "workitems_pending", + "type": "TypeFloat", + "description": "Number of workitems pending in the flow.", + "computed": true + } + } + }, + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "Workspace Id.", + "computed": true + }, + "job_type": { + "name": "job_type", + "type": "TypeString", + "description": "Type of Job.", + "computed": true + }, + "log_analyzed_till": { + "name": "log_analyzed_till", + "type": "TypeString", + "description": "Job log update timestamp.", + "computed": true + }, + "log_errors": { + "name": "log_errors", + "type": "TypeList", + "description": "Job log errors.", + "computed": true, + "elem": { + "error_code": { + "name": "error_code", + "type": "TypeString", + "description": "Error code in the Log.", + "computed": true + }, + "error_count": { + "name": "error_count", + "type": "TypeFloat", + "description": "Number of occurrence.", + "computed": true + }, + "error_msg": { + "name": "error_msg", + "type": "TypeString", + "description": "Summary error message in the log.", + "computed": true + } + } + }, + "log_start_at": { + "name": "log_start_at", + "type": "TypeString", + "description": "Job log start timestamp.", + "computed": true + }, + "repo_download_job": { + "name": "repo_download_job", + "type": "TypeList", + "description": "Repo download Job log summary.", + "computed": true, + "elem": { + "detected_filetype": { + "name": "detected_filetype", + "type": "TypeString", + "description": "Detected template or data file type.", + "computed": true + }, + "inputs_count": { + "name": "inputs_count", + "type": "TypeString", + "description": "Number of inputs detected.", + "computed": true + }, + "outputs_count": { + "name": "outputs_count", + "type": "TypeString", + "description": "Number of outputs detected.", + "computed": true + }, + "quarantined_file_count": { + "name": "quarantined_file_count", + "type": "TypeFloat", + "description": "Number of files quarantined.", + "computed": true + }, + "scanned_file_count": { + "name": "scanned_file_count", + "type": "TypeFloat", + "description": "Number of files scanned.", + "computed": true + } + } + }, + "system_job": { + "name": "system_job", + "type": "TypeList", + "description": "System Job log summary.", + "computed": true, + "elem": { + "failed": { + "name": "failed", + "type": "TypeFloat", + "description": "Number of failed.", + "computed": true + }, + "success": { + "name": "success", + "type": "TypeFloat", + "description": "Number of passed.", + "computed": true + }, + "target_count": { + "name": "target_count", + "type": "TypeFloat", + "description": "number of targets or hosts.", + "computed": true + } + } + }, + "workspace_job": { + "name": "workspace_job", + "type": "TypeList", + "description": "Workspace Job log summary.", + "computed": true, + "elem": { + "resources_add": { + "name": "resources_add", + "type": "TypeFloat", + "description": "Number of resources add.", + "computed": true + }, + "resources_destroy": { + "name": "resources_destroy", + "type": "TypeFloat", + "description": "Number of resources destroy.", + "computed": true + }, + "resources_modify": { + "name": "resources_modify", + "type": "TypeFloat", + "description": "Number of resources modify.", + "computed": true + } + } + } + } + }, + { + "name": "submitted_by", + "type": "TypeString", + "description": "Email address of user who submitted the job.", + "computed": true + }, + { + "name": "bastion", + "type": "TypeList", + "description": "Describes a bastion resource.", + "computed": true, + "elem": { + "host": { + "name": "host", + "type": "TypeString", + "description": "Reference to the Inventory resource definition.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Bastion Name(Unique).", + "computed": true + } + } + }, + { + "name": "status", + "type": "TypeList", + "description": "Job Status.", + "computed": true, + "elem": { + "action_job_status": { + "name": "action_job_status", + "type": "TypeList", + "description": "Action Job Status.", + "computed": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Action name.", + "computed": true + }, + "bastion_status_code": { + "name": "bastion_status_code", + "type": "TypeString", + "description": "Status of Resources.", + "computed": true + }, + "bastion_status_message": { + "name": "bastion_status_message", + "type": "TypeString", + "description": "Bastion status message - to be displayed along with the bastion_status_code;.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Action Job status message - to be displayed along with the action_status_code.", + "computed": true + }, + "targets_status_code": { + "name": "targets_status_code", + "type": "TypeString", + "description": "Status of Resources.", + "computed": true + }, + "targets_status_message": { + "name": "targets_status_message", + "type": "TypeString", + "description": "Aggregated status message for all target resources, to be displayed along with the targets_status_code;.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "flow_job_status": { + "name": "flow_job_status", + "type": "TypeList", + "description": "Environment Flow JOB Status.", + "computed": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "flow id.", + "computed": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "flow name.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Flow Job status message - to be displayed along with the status_code;.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Environment's individual workItem status details;.", + "computed": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace job id.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "workitem job status message;.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "workitem job status updation timestamp.", + "computed": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "Workspace id.", + "computed": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "workspace name.", + "computed": true + } + } + } + } + }, + "system_job_status": { + "name": "system_job_status", + "type": "TypeList", + "description": "System Job Status.", + "computed": true, + "elem": { + "schematics_resource_status": { + "name": "schematics_resource_status", + "type": "TypeList", + "description": "job staus for each schematics resource.", + "computed": true, + "elem": { + "schematics_resource_id": { + "name": "schematics_resource_id", + "type": "TypeString", + "description": "id for each resource which is targeted as a part of system job.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "system job status message.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "system_status_code": { + "name": "system_status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "system_status_message": { + "name": "system_status_message", + "type": "TypeString", + "description": "System job message.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "workspace_job_status": { + "name": "workspace_job_status", + "type": "TypeList", + "description": "Workspace Job Status.", + "computed": true, + "elem": { + "flow_status": { + "name": "flow_status", + "type": "TypeList", + "description": "Environment Flow JOB Status.", + "computed": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "flow id.", + "computed": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "flow name.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Flow Job status message - to be displayed along with the status_code;.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Environment's individual workItem status details;.", + "computed": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace job id.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "workitem job status message;.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "workitem job status updation timestamp.", + "computed": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "Workspace id.", + "computed": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "workspace name.", + "computed": true + } + } + } + } + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace).", + "computed": true + }, + "template_status": { + "name": "template_status", + "type": "TypeList", + "description": "Workspace Flow Template job status.", + "computed": true, + "elem": { + "flow_index": { + "name": "flow_index", + "type": "TypeInt", + "description": "Index of the template in the Flow.", + "computed": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template).", + "computed": true + }, + "template_id": { + "name": "template_id", + "type": "TypeString", + "description": "Template Id.", + "computed": true + }, + "template_name": { + "name": "template_name", + "type": "TypeString", + "description": "Template name.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "Workspace name.", + "computed": true + } + } + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + { + "name": "command_name", + "type": "TypeString", + "description": "Schematics job command name.", + "computed": true + }, + { + "name": "job_env_settings", + "type": "TypeList", + "description": "Environment variables used by the Job while performing Action or Workspace.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "tags", + "type": "TypeList", + "description": "User defined tags, while running the job.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Job name, uniquely derived from the related Workspace or Action.", + "computed": true + }, + { + "name": "job_id", + "type": "TypeString", + "description": "Job Id. Use `GET /v2/jobs` API to look up the Job Ids in your IBM Cloud account.", + "required": true + }, + { + "name": "command_object", + "type": "TypeString", + "description": "Name of the Schematics automation resource.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name derived from the related Workspace or Action.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "results_url", + "type": "TypeString", + "description": "Job results store URL.", + "computed": true + }, + { + "name": "command_object_id", + "type": "TypeString", + "description": "Job command object id (workspace-id, action-id).", + "computed": true + }, + { + "name": "start_at", + "type": "TypeString", + "description": "Job start time.", + "computed": true + }, + { + "name": "command_options", + "type": "TypeList", + "description": "Command line options for the command.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "submitted_at", + "type": "TypeString", + "description": "Job submission time.", + "computed": true + }, + { + "name": "data", + "type": "TypeList", + "description": "Job data.", + "computed": true, + "elem": { + "action_job_data": { + "name": "action_job_data", + "type": "TypeList", + "description": "Action Job data.", + "computed": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Flow name.", + "computed": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data used by the Action Job.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "inventory_record": { + "name": "inventory_record", + "type": "TypeList", + "description": "Complete inventory resource details with user inputs and system generated data.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Inventory creation time.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Inventory.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of your Inventory. The description can be up to 2048 characters long in size.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Inventory id.", + "computed": true + }, + "inventories_ini": { + "name": "inventories_ini", + "type": "TypeString", + "description": "Input inventory of host and host group for the playbook, in the .ini file format.", + "computed": true + }, + "location": { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + "computed": true + }, + "resource_queries": { + "name": "resource_queries", + "type": "TypeList", + "description": "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Inventory updation time.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Inventory.", + "computed": true + } + } + }, + "materialized_inventory": { + "name": "materialized_inventory", + "type": "TypeString", + "description": "Materialized inventory details used by the Action Job, in .ini format.", + "computed": true + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables data from the Action Job.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by all the templates in the Action.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "flow_job_data": { + "name": "flow_job_data", + "type": "TypeList", + "description": "Flow Job data.", + "computed": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "Flow ID.", + "computed": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "Flow Name.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Job data used by each workitem Job.", + "computed": true, + "elem": { + "command_object_id": { + "name": "command_object_id", + "type": "TypeString", + "description": "command object id.", + "computed": true + }, + "command_object_name": { + "name": "command_object_name", + "type": "TypeString", + "description": "command object name.", + "computed": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data for the workItem used in FlowJob.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "last_job": { + "name": "last_job", + "type": "TypeList", + "description": "Status of the last job executed by the workitem.", + "computed": true, + "elem": { + "command_name": { + "name": "command_name", + "type": "TypeString", + "description": "Schematics job command name.", + "computed": true + }, + "command_object": { + "name": "command_object", + "type": "TypeString", + "description": "Name of the Schematics automation resource.", + "computed": true + }, + "command_object_id": { + "name": "command_object_id", + "type": "TypeString", + "description": "Workitem command object id, maps to workspace_id or action_id.", + "computed": true + }, + "command_object_name": { + "name": "command_object_name", + "type": "TypeString", + "description": "command object name (workspace_name/action_name).", + "computed": true + }, + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "Workspace job id.", + "computed": true + }, + "job_status": { + "name": "job_status", + "type": "TypeString", + "description": "Status of Jobs.", + "computed": true + } + } + }, + "layers": { + "name": "layers", + "type": "TypeString", + "description": "layer name.", + "computed": true + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables for the workItem.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables for the workItem.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "source": { + "name": "source", + "type": "TypeList", + "description": "Source of templates, playbooks, or controls.", + "computed": true, + "elem": { + "catalog": { + "name": "catalog", + "type": "TypeList", + "description": "Connection details to IBM Cloud Catalog source.", + "computed": true, + "elem": { + "catalog_name": { + "name": "catalog_name", + "type": "TypeString", + "description": "name of the private catalog.", + "computed": true + }, + "offering_id": { + "name": "offering_id", + "type": "TypeString", + "description": "Id of the offering the IBM Catalog.", + "computed": true + }, + "offering_kind": { + "name": "offering_kind", + "type": "TypeString", + "description": "Type of the offering, in the IBM Catalog.", + "computed": true + }, + "offering_name": { + "name": "offering_name", + "type": "TypeString", + "description": "Name of the offering in the IBM Catalog.", + "computed": true + }, + "offering_repo_url": { + "name": "offering_repo_url", + "type": "TypeString", + "description": "Repo Url of the offering, in the IBM Catalog.", + "computed": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "Version string of the offering in the IBM Catalog.", + "computed": true + }, + "offering_version_id": { + "name": "offering_version_id", + "type": "TypeString", + "description": "Id of the offering version the IBM Catalog.", + "computed": true + } + } + }, + "git": { + "name": "git", + "type": "TypeList", + "description": "Connection details to Git source.", + "computed": true, + "elem": { + "computed_git_repo_url": { + "name": "computed_git_repo_url", + "type": "TypeString", + "description": "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + "computed": true + }, + "git_branch": { + "name": "git_branch", + "type": "TypeString", + "description": "Name of the branch, used to fetch the Git Repo.", + "computed": true + }, + "git_release": { + "name": "git_release", + "type": "TypeString", + "description": "Name of the release tag, used to fetch the Git Repo.", + "computed": true + }, + "git_repo_folder": { + "name": "git_repo_folder", + "type": "TypeString", + "description": "Name of the folder in the Git Repo, that contains the template.", + "computed": true + }, + "git_repo_url": { + "name": "git_repo_url", + "type": "TypeString", + "description": "URL to the GIT Repo that can be used to clone the template.", + "computed": true + }, + "git_token": { + "name": "git_token", + "type": "TypeString", + "description": "Personal Access Token to connect to Git URLs.", + "computed": true + } + } + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "computed": true + } + } + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + } + } + }, + "job_type": { + "name": "job_type", + "type": "TypeString", + "description": "Type of Job.", + "computed": true + }, + "system_job_data": { + "name": "system_job_data", + "type": "TypeList", + "description": "Controls Job data.", + "computed": true, + "elem": { + "key_id": { + "name": "key_id", + "type": "TypeString", + "description": "Key ID for which key event is generated.", + "computed": true + }, + "schematics_resource_id": { + "name": "schematics_resource_id", + "type": "TypeList", + "description": "List of the schematics resource id.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "workspace_job_data": { + "name": "workspace_job_data", + "type": "TypeList", + "description": "Workspace Job data.", + "computed": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "Flow Id.", + "computed": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "Flow name.", + "computed": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data used by the Workspace Job.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables data from the Workspace Job.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by all the templates in the Workspace.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "template_data": { + "name": "template_data", + "type": "TypeList", + "description": "Input / output data of the Template in the Workspace Job.", + "computed": true, + "elem": { + "flow_index": { + "name": "flow_index", + "type": "TypeInt", + "description": "Index of the template in the Flow.", + "computed": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Job inputs used by the Templates.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Job output from the Templates.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by the template.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + "template_id": { + "name": "template_id", + "type": "TypeString", + "description": "Template Id.", + "computed": true + }, + "template_name": { + "name": "template_name", + "type": "TypeString", + "description": "Template name.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "Workspace name.", + "computed": true + } + } + } + } + }, + { + "name": "log_store_url", + "type": "TypeString", + "description": "Job log store URL.", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "Job ID.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "command_parameter", + "type": "TypeString", + "description": "Schematics job command parameter (playbook-name).", + "computed": true + }, + { + "name": "job_inputs", + "type": "TypeList", + "description": "Job inputs used by Action or Workspace.", + "computed": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "computed": true + } + } + }, + { + "name": "end_at", + "type": "TypeString", + "description": "Job end time.", + "computed": true + }, + { + "name": "duration", + "type": "TypeString", + "description": "Duration of job execution; example 40 sec.", + "computed": true + } + ], + "ibm_schematics_output": [ + { + "name": "output_values", + "type": "TypeMap", + "computed": true + }, + { + "name": "output_json", + "type": "TypeString", + "description": "The json output in string", + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this Workspace", + "computed": true + }, + { + "name": "workspace_id", + "type": "TypeString", + "description": "The ID of the workspace for which you want to retrieve output values. To find the workspace ID, use the `GET /workspaces` API.", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The Region of the workspace.", + "cloud_data_type": "region", + "optional": true + }, + { + "name": "template_id", + "type": "TypeString", + "description": "The id of template", + "required": true + } + ], + "ibm_schematics_resource_query": [ + { + "name": "created_at", + "type": "TypeString", + "description": "Resource query creation time.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Resource query.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Resource query updation time.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Resource query.", + "computed": true + }, + { + "name": "queries", + "type": "TypeList", + "computed": true, + "elem": { + "query_condition": { + "name": "query_condition", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of resource query param variable.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the resource query param.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of the resource query param.", + "computed": true + } + } + }, + "query_select": { + "name": "query_select", + "type": "TypeList", + "description": "List of query selection parameters.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "query_type": { + "name": "query_type", + "type": "TypeString", + "description": "Type of the query(workspaces).", + "computed": true + } + } + }, + { + "name": "query_id", + "type": "TypeString", + "description": "Resource query Id. Use `GET /v2/resource_query` API to look up the Resource query definition Ids in your IBM Cloud account.", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The Region of the workspace.", + "cloud_data_type": "region", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Resource type (cluster, vsi, icd, vpc).", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource query name.", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "Resource Query id.", + "computed": true + } + ], + "ibm_schematics_state": [ + { + "name": "template_id", + "type": "TypeString", + "description": "The ID of the Terraform template for which you want to retrieve the Terraform statefile. When you create a workspace, the Terraform template that your workspace points to is assigned a unique ID. To find this ID, use the GET /v1/workspaces API and review the template_data.id value.", + "required": true + }, + { + "name": "state_store", + "type": "TypeString", + "computed": true + }, + { + "name": "state_store_json", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", + "computed": true + }, + { + "name": "workspace_id", + "type": "TypeString", + "description": "The ID of the workspace for which you want to retrieve the Terraform statefile URL. To find the workspace ID, use the GET /v1/workspaces API.", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The Region of the workspace.", + "cloud_data_type": "region", + "optional": true + } + ], + "ibm_schematics_workspace": [ + { + "name": "workspace_id", + "type": "TypeString", + "description": "The ID of the workspace. To find the workspace ID, use the `GET /v1/workspaces` API.", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The IBM Cloud location where your workspace was provisioned.", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "template_init_state_file", + "type": "TypeString", + "description": "Init state file.", + "computed": true + }, + { + "name": "template_values_metadata", + "type": "TypeList", + "description": "A list of input variables that are associated with the workspace.", + "optional": true, + "computed": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "The list of aliases for the variable name.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "cloud_data_type": { + "name": "cloud_data_type", + "type": "TypeString", + "description": "Cloud data type of the variable. eg. resource_group_id, region, vpc_id.", + "computed": true + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable only if the override value is not specified.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of the meta data.", + "computed": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "The display name of the group this variable belongs to.", + "computed": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If **true**, the variable is not displayed on UI or Command line.", + "computed": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "computed": true + }, + "link_status": { + "name": "link_status", + "type": "TypeString", + "description": "The status of the link.", + "computed": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "The regex for the variable value.", + "computed": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "The maximum length of the variable value. Applicable for the string type.", + "computed": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "The maximum value of the variable. Applicable for the integer type.", + "computed": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "The minimum length of the variable value. Applicable for the string type.", + "computed": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "The minimum value of the variable. Applicable for the integer type.", + "computed": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "The list of possible values for this variable. If type is **integer** or **date**, then the array of string is converted to array of integers or date during the runtime.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "The relative position of this variable in a list.", + "computed": true + }, + "required": { + "name": "required", + "type": "TypeBool", + "description": "If the variable required?.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "The source of this meta-data.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp when the workspace was created.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group the workspace was provisioned in.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "template_git_has_uploadedgitrepotar", + "type": "TypeBool", + "description": "Has uploaded Git repository tar.", + "optional": true, + "computed": true + }, + { + "name": "template_git_url", + "type": "TypeString", + "description": "The source URL.", + "computed": true + }, + { + "name": "locked_by", + "type": "TypeString", + "description": "The user ID that initiated a resource-related job, such as applying or destroying resources, that locked the workspace.", + "computed": true + }, + { + "name": "applied_shareddata_ids", + "type": "TypeList", + "description": "List of applied shared dataset ID.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "last_health_check_at", + "type": "TypeString", + "description": "The timestamp when the last health check was performed by Schematics.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the workspace.", + "computed": true + }, + { + "name": "template_inputs", + "type": "TypeList", + "description": "Information about the input variables that your template uses.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of your input variable.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the variable.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "If set to `true`, the value of your input variable is protected and not returned in your API response.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).\u003cbr\u003e `Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](https://cloud.ibm.com/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + "computed": true + } + } + }, + { + "name": "template_git_release", + "type": "TypeString", + "description": "The repository release.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The user ID that updated the workspace.", + "computed": true + }, + { + "name": "status_code", + "type": "TypeString", + "description": "The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace.", + "computed": true + }, + { + "name": "status_msg", + "type": "TypeString", + "description": "The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace.", + "computed": true + }, + { + "name": "catalog_ref", + "type": "TypeList", + "description": "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", + "computed": true, + "elem": { + "dry_run": { + "name": "dry_run", + "type": "TypeBool", + "description": "Dry run.", + "computed": true + }, + "item_icon_url": { + "name": "item_icon_url", + "type": "TypeString", + "description": "The URL to the icon of the software template in the IBM Cloud catalog.", + "computed": true + }, + "item_id": { + "name": "item_id", + "type": "TypeString", + "description": "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", + "computed": true + }, + "item_name": { + "name": "item_name", + "type": "TypeString", + "description": "The name of the software that you chose to install from the IBM Cloud catalog.", + "computed": true + }, + "item_readme_url": { + "name": "item_readme_url", + "type": "TypeString", + "description": "The URL to the readme file of the software template in the IBM Cloud catalog.", + "computed": true + }, + "item_url": { + "name": "item_url", + "type": "TypeString", + "description": "The URL to the software template in the IBM Cloud catalog.", + "computed": true + }, + "launch_url": { + "name": "launch_url", + "type": "TypeString", + "description": "The URL to the dashboard to access your software.", + "computed": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "The version of the software template that you chose to install from the IBM Cloud catalog.", + "computed": true + }, + "owning_account": { + "name": "owning_account", + "type": "TypeString", + "description": "Owning account ID of the catalog.", + "computed": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the workspace.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "A list of tags that are associated with the workspace.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "template_type", + "type": "TypeString", + "description": "The Terraform version that was used to run your Terraform code.", + "computed": true + }, + { + "name": "template_git_branch", + "type": "TypeString", + "description": "The repository branch.", + "computed": true + }, + { + "name": "is_frozen", + "type": "TypeBool", + "computed": true, + "deprecated": "use frozen instead" + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this workspace", + "computed": true + }, + { + "name": "template_values", + "type": "TypeString", + "description": "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", + "computed": true + }, + { + "name": "template_ref", + "type": "TypeString", + "description": "Workspace template ref.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp when the workspace was last updated.", + "computed": true + }, + { + "name": "locked_time", + "type": "TypeString", + "description": "The timestamp when the workspace was locked.", + "computed": true + }, + { + "name": "frozen", + "type": "TypeBool", + "description": "If set to true, the workspace is frozen and changes to the workspace are disabled.", + "computed": true + }, + { + "name": "frozen_at", + "type": "TypeString", + "description": "The timestamp when the workspace was frozen.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The workspace CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "runtime_data", + "type": "TypeList", + "description": "Information about the provisioning engine, state file, and runtime logs.", + "computed": true, + "elem": { + "engine_cmd": { + "name": "engine_cmd", + "type": "TypeString", + "description": "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", + "computed": true + }, + "engine_name": { + "name": "engine_name", + "type": "TypeString", + "description": "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", + "computed": true + }, + "engine_version": { + "name": "engine_version", + "type": "TypeString", + "description": "The version of the provisioning engine that was used.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", + "computed": true + }, + "log_store_url": { + "name": "log_store_url", + "type": "TypeString", + "description": "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", + "computed": true + }, + "output_values": { + "name": "output_values", + "type": "TypeList", + "description": "List of Output values.", + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "description": "List of resources.", + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "state_store_url": { + "name": "state_store_url", + "type": "TypeString", + "description": "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs.", + "computed": true + } + } + }, + { + "name": "shared_data", + "type": "TypeList", + "description": "Information about the Target used by the templates originating from IBM Cloud catalog offerings. This information is not relevant when you create a workspace from your own Terraform template.", + "computed": true, + "elem": { + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "description": "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "computed": true + }, + "cluster_name": { + "name": "cluster_name", + "type": "TypeString", + "description": "Target cluster name.", + "computed": true + }, + "entitlement_keys": { + "name": "entitlement_keys", + "type": "TypeList", + "description": "The entitlement key that you want to use to install IBM Cloud entitled software.", + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + "namespace": { + "name": "namespace", + "type": "TypeString", + "description": "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", + "computed": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "computed": true + } + } + }, + { + "name": "template_env_settings", + "type": "TypeList", + "description": "List of environment values.", + "computed": true, + "elem": { + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If set to `true`, the value of your input variable is protected and not returned in your API response.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the variable.", + "computed": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "If set to `true`, the value of your input variable is protected and not returned in your API response.", + "computed": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + "computed": true + } + } + }, + { + "name": "template_uninstall_script_name", + "type": "TypeString", + "description": "Uninstall script name.", + "computed": true + }, + { + "name": "template_git_full_url", + "type": "TypeString", + "description": "Full repository URL.", + "computed": true + }, + { + "name": "template_git_repo_sha_value", + "type": "TypeString", + "description": "The repository SHA value.", + "computed": true + }, + { + "name": "template_git_repo_url", + "type": "TypeString", + "description": "The repository URL.", + "computed": true + }, + { + "name": "frozen_by", + "type": "TypeString", + "description": "The user ID that froze the workspace.", + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "If set to true, the workspace is locked and disabled for changes.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The user ID that created the workspace.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", + "computed": true + }, + { + "name": "template_git_folder", + "type": "TypeString", + "description": "The subfolder in your GitHub or GitLab repository where your Terraform template is stored. If your template is stored in the root directory, `.` is returned.", + "computed": true + }, + { + "name": "is_locked", + "type": "TypeBool", + "description": "If set to true, the workspace is locked and disabled for changes.", + "computed": true, + "deprecated": "Use locked instead" + } + ], + "ibm_secrets_manager_secret": [ + { + "name": "secret_group_id", + "type": "TypeString", + "description": "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", + "computed": true + }, + { + "name": "versions", + "type": "TypeList", + "description": "An array that contains metadata for each secret version.", + "computed": true, + "elem": { + "auto_rotated": { + "name": "auto_rotated", + "type": "TypeBool", + "description": "Indicates whether the version of the secret was created by automatic rotation.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the entity that created the secret.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date that the version of the secret was created.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID of the secret version.", + "computed": true + } + } + }, + { + "name": "ttl", + "type": "TypeString", + "description": "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", + "computed": true + }, + { + "name": "access_groups", + "type": "TypeList", + "description": "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage \u003e Access (IAM) \u003e Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "description", + "type": "TypeString", + "description": "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", + "computed": true + }, + { + "name": "labels", + "type": "TypeList", + "description": "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "state", + "type": "TypeInt", + "description": "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "creation_date", + "type": "TypeString", + "description": "The date the secret was created. The date format follows RFC 3339.", + "computed": true + }, + { + "name": "secret_id", + "type": "TypeString", + "description": "The v4 UUID that uniquely identifies the secret.", + "required": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "Endpoint Type. 'public' or 'private'", + "default_value": "public", + "options": "public, private", + "optional": true + }, + { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the actual secret is modified. The date format follows RFC 3339.", + "computed": true + }, + { + "name": "service_id", + "type": "TypeString", + "description": "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", + "computed": true + }, + { + "name": "reuse_api_key", + "type": "TypeBool", + "description": "(IAM credentials) Reuse the service ID and API key for future read operations.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Secrets Manager instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:secrets-manager" + ] + }, + { + "name": "state_description", + "type": "TypeString", + "description": "A text representation of the secret state.", + "computed": true + }, + { + "name": "expiration_date", + "type": "TypeString", + "description": "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", + "computed": true + }, + { + "name": "next_rotation_date", + "type": "TypeString", + "description": "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", + "computed": true + }, + { + "name": "password", + "type": "TypeString", + "description": "The password to assign to this secret.", + "secure": true, + "computed": true + }, + { + "name": "api_key", + "type": "TypeString", + "description": "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", + "secure": true, + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The MIME type that represents the secret.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the entity that created the secret.", + "computed": true + }, + { + "name": "secret_data", + "type": "TypeMap", + "description": "The secret data object", + "secure": true, + "computed": true + }, + { + "name": "username", + "type": "TypeString", + "description": "The username to assign to this secret.", + "secure": true, + "computed": true + }, + { + "name": "secret_type", + "type": "TypeString", + "description": "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", + "required": true, + "options": "arbitrary,iam_credentials,imported_cert,public_cert,private_cert,username_password,kv" + }, + { + "name": "metadata", + "type": "TypeList", + "description": "The metadata that describes the resource array.", + "computed": true, + "elem": { + "collection_total": { + "name": "collection_total", + "type": "TypeInt", + "description": "The number of elements in the resource array.", + "computed": true + }, + "collection_type": { + "name": "collection_type", + "type": "TypeString", + "description": "The type of resources in the resource array.", + "computed": true + } + } + }, + { + "name": "payload", + "type": "TypeString", + "description": "The new secret data to assign to an `arbitrary` secret.", + "secure": true, + "computed": true + } + ], + "ibm_secrets_manager_secrets": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Secrets Manager instance GUID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:secrets-manager" + ] + }, + { + "name": "secret_type", + "type": "TypeString", + "description": "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", + "options": "arbitrary, iam_credentials, username_password", + "optional": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "Endpoint Type. 'public' or 'private'", + "default_value": "public", + "options": "public, private", + "optional": true + }, + { + "name": "metadata", + "type": "TypeList", + "description": "The metadata that describes the resource array.", + "computed": true, + "elem": { + "collection_total": { + "name": "collection_total", + "type": "TypeInt", + "description": "The number of elements in the resource array.", + "computed": true + }, + "collection_type": { + "name": "collection_type", + "type": "TypeString", + "description": "The type of resources in the resource array.", + "computed": true + } + } + }, + { + "name": "secrets", + "type": "TypeList", + "description": "A collection of secret resources.", + "computed": true, + "elem": { + "access_groups": { + "name": "access_groups", + "type": "TypeList", + "description": "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage \u003e Access (IAM) \u003e Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", + "secure": true, + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the entity that created the secret.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date the secret was created. The date format follows RFC 3339.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", + "computed": true + }, + "expiration_date": { + "name": "expiration_date", + "type": "TypeString", + "description": "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", + "computed": true + }, + "labels": { + "name": "labels", + "type": "TypeList", + "description": "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the actual secret is modified. The date format follows RFC 3339.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", + "computed": true + }, + "next_rotation_date": { + "name": "next_rotation_date", + "type": "TypeString", + "description": "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The password to assign to this secret.", + "secure": true, + "computed": true + }, + "payload": { + "name": "payload", + "type": "TypeString", + "description": "The new secret data to assign to an `arbitrary` secret.", + "secure": true, + "computed": true + }, + "reuse_api_key": { + "name": "reuse_api_key", + "type": "TypeBool", + "description": "(IAM credentials) Reuse the service ID and API key for future read operations.", + "computed": true + }, + "secret_data": { + "name": "secret_data", + "type": "TypeMap", + "description": "The secret data object", + "secure": true, + "computed": true + }, + "secret_group_id": { + "name": "secret_group_id", + "type": "TypeString", + "description": "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", + "computed": true + }, + "secret_id": { + "name": "secret_id", + "type": "TypeString", + "description": "The v4 UUID that uniquely identifies the secret.", + "computed": true + }, + "secret_type": { + "name": "secret_type", + "type": "TypeString", + "description": "The secret type.", + "computed": true + }, + "service_id": { + "name": "service_id", + "type": "TypeString", + "description": "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeInt", + "description": "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", + "computed": true + }, + "state_description": { + "name": "state_description", + "type": "TypeString", + "description": "A text representation of the secret state.", + "computed": true + }, + "ttl": { + "name": "ttl", + "type": "TypeString", + "description": "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The MIME type that represents the secret.", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "The username to assign to this secret.", + "secure": true, + "computed": true + }, + "versions": { + "name": "versions", + "type": "TypeList", + "description": "An array that contains metadata for each secret version.", + "computed": true, + "elem": { + "auto_rotated": { + "name": "auto_rotated", + "type": "TypeBool", + "description": "Indicates whether the version of the secret was created by automatic rotation.", + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the entity that created the secret.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date that the version of the secret was created.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID of the secret version.", + "computed": true + } + } + } + } + } + ], + "ibm_security_group": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the security group", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the security group", + "optional": true, + "computed": true + }, + { + "name": "most_recent", + "type": "TypeBool", + "description": "If true and multiple entries are found, the most recently created group is used. If false, an error is returned", + "default_value": false, + "optional": true + } + ], + "ibm_service_instance": [ + { + "name": "name", + "type": "TypeString", + "description": "Service instance name for example, speech_to_text", + "required": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The guid of the space in which the instance is present", + "required": true + }, + { + "name": "credentials", + "type": "TypeMap", + "description": "The service broker-provided credentials to use this service.", + "secure": true, + "computed": true + }, + { + "name": "service_keys", + "type": "TypeList", + "description": "Service keys asociated with the service instance", + "computed": true, + "elem": { + "credentials": { + "name": "credentials", + "type": "TypeMap", + "description": "The service key credential details like port, username etc", + "secure": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The service key name", + "computed": true + } + } + }, + { + "name": "service_plan_guid", + "type": "TypeString", + "description": "The uniquie identifier of the service offering plan type", + "computed": true + } + ], + "ibm_service_key": [ + { + "name": "credentials", + "type": "TypeMap", + "description": "Credentials asociated with the key", + "secure": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the service key", + "required": true + }, + { + "name": "service_instance_name", + "type": "TypeString", + "description": "Service instance name for example, speech_to_text", + "required": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The guid of the space in which the service instance is present", + "required": true + } + ], + "ibm_service_plan": [ + { + "name": "service", + "type": "TypeString", + "description": "Service name for example, cloudantNoSQLDB", + "required": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type ex- shared", + "required": true + } + ], + "ibm_space": [ + { + "name": "name", + "type": "TypeString", + "description": "Space name, for example dev", + "optional": true + }, + { + "name": "org", + "type": "TypeString", + "description": "The org this space belongs to", + "required": true + }, + { + "name": "auditors", + "type": "TypeSet", + "description": "The IBMID of the users who have auditor role in this space, ex - user@example.com", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managers", + "type": "TypeSet", + "description": "The IBMID of the users who have manager role in this space, ex - user@example.com", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "developers", + "type": "TypeSet", + "description": "The IBMID of the users who have developer role in this space, ex - user@example.com", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "space", + "type": "TypeString", + "description": "Space name, for example dev", + "optional": true, + "deprecated": "use name instead" + } + ], + "ibm_tg_connection_prefix_filter": [ + { + "name": "connection_id", + "type": "TypeString", + "description": "The Transit Gateway Connection identifier", + "required": true + }, + { + "name": "filter_id", + "type": "TypeString", + "description": "The Transit Gateway Connection Prefix Filter identifier", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "Whether to permit or deny the prefix filter", + "computed": true + }, + { + "name": "before", + "type": "TypeString", + "description": "Identifier of prefix filter that handles ordering", + "computed": true + }, + { + "name": "ge", + "type": "TypeInt", + "description": "IP Prefix GE", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "required": true + }, + { + "name": "le", + "type": "TypeInt", + "description": "IP Prefix LE", + "computed": true + }, + { + "name": "prefix", + "type": "TypeString", + "description": "IP Prefix", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was last updated", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was created", + "computed": true + } + ], + "ibm_tg_connection_prefix_filters": [ + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "required": true + }, + { + "name": "connection_id", + "type": "TypeString", + "description": "The Transit Gateway Connection identifier", + "required": true + }, + { + "name": "prefix_filters", + "type": "TypeList", + "description": "Collection of prefix filters", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Whether to permit or deny the prefix filter", + "computed": true + }, + "before": { + "name": "before", + "type": "TypeString", + "description": "Identifier of prefix filter that handles ordering", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was created", + "computed": true + }, + "ge": { + "name": "ge", + "type": "TypeInt", + "description": "IP Prefix GE", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "le": { + "name": "le", + "type": "TypeInt", + "description": "IP Prefix LE", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "IP Prefix", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was last updated", + "computed": true + } + } + } + ], + "ibm_tg_gateway": [ + { + "name": "name", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + { + "name": "global", + "type": "TypeBool", + "computed": true + }, + { + "name": "connections", + "type": "TypeList", + "description": "Collection of transit gateway connections", + "computed": true, + "elem": { + "base_connection_id": { + "name": "base_connection_id", + "type": "TypeString", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "local_bgp_asn": { + "name": "local_bgp_asn", + "type": "TypeInt", + "computed": true + }, + "local_gateway_ip": { + "name": "local_gateway_ip", + "type": "TypeString", + "computed": true + }, + "local_tunnel_ip": { + "name": "local_tunnel_ip", + "type": "TypeString", + "computed": true + }, + "mtu": { + "name": "mtu", + "type": "TypeInt", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "network_account_id": { + "name": "network_account_id", + "type": "TypeString", + "description": "The ID of the account which owns the network that is being connected. Generally only used if the network is in a different account than the gateway.", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "computed": true + }, + "network_type": { + "name": "network_type", + "type": "TypeString", + "computed": true + }, + "remote_bgp_asn": { + "name": "remote_bgp_asn", + "type": "TypeInt", + "computed": true + }, + "remote_gateway_ip": { + "name": "remote_gateway_ip", + "type": "TypeString", + "computed": true + }, + "remote_tunnel_ip": { + "name": "remote_tunnel_ip", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "computed": true + } + ], + "ibm_tg_gateways": [ + { + "name": "transit_gateways", + "type": "TypeList", + "description": "Collection of transit gateways", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "computed": true + }, + "global": { + "name": "global", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "location": { + "name": "location", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_tg_location": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the Location.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of the location, determining is this a multi-zone region, a single data center, or a point of presence.", + "computed": true + }, + { + "name": "billing_location", + "type": "TypeString", + "description": "The geographical location of this location, used for billing purposes.", + "computed": true + }, + { + "name": "local_connection_locations", + "type": "TypeList", + "description": "The set of network locations that are considered local for this Transit Gateway location.", + "computed": true, + "elem": { + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "A descriptive display name for the location.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Location.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the location, determining is this a multi-zone region, a single data center, or a point of presence.", + "computed": true + } + } + } + ], + "ibm_tg_locations": [ + { + "name": "locations", + "type": "TypeList", + "description": "Collection of Transit Gateway locations", + "computed": true, + "elem": { + "billing_location": { + "name": "billing_location", + "type": "TypeString", + "description": "The geographical location of this location, used for billing purposes.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the Location.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of the location, determining is this a multi-zone region, a single data center, or a point of presence.", + "computed": true + } + } + } + ], + "ibm_tg_route_report": [ + { + "name": "updated_at", + "type": "TypeString", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "required": true + }, + { + "name": "route_report", + "type": "TypeString", + "description": "The Transit Gateway Route Report identifier", + "required": true + }, + { + "name": "connections", + "type": "TypeList", + "description": "Collection of transit gateway connections", + "computed": true, + "elem": { + "bgps": { + "name": "bgps", + "type": "TypeList", + "description": "Collection of transit gateway connection's bgps", + "computed": true, + "elem": { + "as_path": { + "name": "as_path", + "type": "TypeString", + "computed": true + }, + "is_used": { + "name": "is_used", + "type": "TypeBool", + "computed": true + }, + "local_preference": { + "name": "local_preference", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway connection's used routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + { + "name": "overlapping_routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping route's details", + "computed": true, + "elem": { + "connection_id": { + "name": "connection_id", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "status", + "type": "TypeString", + "computed": true + } + ], + "ibm_tg_route_reports": [ + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "required": true + }, + { + "name": "route_reports", + "type": "TypeList", + "description": "Collection of transit gateway route reports", + "computed": true, + "elem": { + "connections": { + "name": "connections", + "type": "TypeList", + "description": "Collection of transit gateway connections", + "computed": true, + "elem": { + "bgps": { + "name": "bgps", + "type": "TypeList", + "description": "Collection of transit gateway connection's bgps", + "computed": true, + "elem": { + "as_path": { + "name": "as_path", + "type": "TypeString", + "computed": true + }, + "is_used": { + "name": "is_used", + "type": "TypeBool", + "computed": true + }, + "local_preference": { + "name": "local_preference", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway connection's used routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "overlapping_routes": { + "name": "overlapping_routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping route's details", + "computed": true, + "elem": { + "connection_id": { + "name": "connection_id", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + } + } + }, + "status": { + "name": "status", + "type": "TypeString", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "computed": true + } + } + } + ] + }, + "Resources": { + "ibm_api_gateway_endpoint": [ + { + "name": "base_path", + "type": "TypeString", + "description": "Base path of an endpoint", + "computed": true + }, + { + "name": "endpoint_id", + "type": "TypeString", + "description": "Endpoint ID", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Action type of Endpoint ALoowable values are share, unshare, manage, unmanage", + "default_value": "unshare", + "optional": true + }, + { + "name": "open_api_doc_name", + "type": "TypeString", + "description": "Json File path", + "required": true + }, + { + "name": "routes", + "type": "TypeList", + "description": "Invokable routes for an endpoint", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managed", + "type": "TypeBool", + "description": "Managed indicates if endpoint is online or offline.", + "default_value": false, + "optional": true + }, + { + "name": "shared", + "type": "TypeBool", + "description": "The Shared status of an endpoint", + "computed": true + }, + { + "name": "service_instance_crn", + "type": "TypeString", + "description": "Api Gateway Service Instance Crn", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Endpoint name", + "required": true + }, + { + "name": "provider_id", + "type": "TypeString", + "description": "Provider ID of an endpoint allowable values user-defined and whisk", + "default_value": "user-defined", + "optional": true + } + ], + "ibm_api_gateway_endpoint_subscription": [ + { + "name": "name", + "type": "TypeString", + "description": "Subscription name", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Subscription type. Allowable values are external, internal", + "required": true + }, + { + "name": "client_secret", + "type": "TypeString", + "description": "Client Sercret of a Subscription", + "secure": true, + "optional": true + }, + { + "name": "generate_secret", + "type": "TypeBool", + "description": "Indicates if Client Sercret has to be autogenerated", + "optional": true + }, + { + "name": "secret_provided", + "type": "TypeBool", + "description": "Indicates if client secret is provided to subscription or not", + "computed": true + }, + { + "name": "artifact_id", + "type": "TypeString", + "description": "Endpoint ID", + "immutable": true, + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "Subscription Id, API key that is used to create subscription", + "optional": true, + "computed": true + } + ], + "ibm_app": [ + { + "name": "instances", + "type": "TypeInt", + "description": "The number of instances", + "default_value": 1, + "optional": true + }, + { + "name": "route_guid", + "type": "TypeSet", + "description": "Define the route guids which should be bound to the application.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health_check_http_endpoint", + "type": "TypeString", + "description": "Endpoint called to determine if the app is healthy.", + "optional": true + }, + { + "name": "health_check_type", + "type": "TypeString", + "description": "Type of health check to perform.", + "default_value": "port", + "optional": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory each instance should have. In megabytes.", + "optional": true, + "computed": true + }, + { + "name": "disk_quota", + "type": "TypeInt", + "description": "The maximum amount of disk available to an instance of an app. In megabytes.", + "optional": true, + "computed": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "Define space guid to which app belongs", + "immutable": true, + "required": true + }, + { + "name": "buildpack", + "type": "TypeString", + "description": "Buildpack to build the app. 3 options: a) Blank means autodetection; b) A Git Url pointing to a buildpack; c) Name of an installed buildpack.", + "optional": true + }, + { + "name": "environment_json", + "type": "TypeMap", + "description": "Key/value pairs of all the environment variables to run in your app. Does not include any system or service variables.", + "optional": true + }, + { + "name": "command", + "type": "TypeString", + "description": "The initial command for the app", + "optional": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "description": "Define timeout to wait for the app instances to start/update/restage etc.", + "default_value": 20, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name for the app", + "required": true + }, + { + "name": "app_path", + "type": "TypeString", + "description": "Define the path of the zip file of the application.", + "required": true + }, + { + "name": "service_instance_guid", + "type": "TypeSet", + "description": "Define the service instance guids that should be bound to this application.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "app_version", + "type": "TypeString", + "description": "Version of the application", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health_check_timeout", + "type": "TypeInt", + "description": "Timeout in seconds for health checking of an staged app when starting up.", + "optional": true + } + ], + "ibm_app_config_collection": [ + { + "name": "name", + "type": "TypeString", + "description": "Collection name.", + "required": true + }, + { + "name": "properties_count", + "type": "TypeString", + "description": "Number of properties associated with the collection.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "immutable": true, + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Collection description", + "optional": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the collection", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the collection.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the collection data.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Collection URL.", + "computed": true + }, + { + "name": "features_count", + "type": "TypeString", + "description": "Number of features associated with the collection.", + "computed": true + }, + { + "name": "collection_id", + "type": "TypeString", + "description": "Collection Id.", + "required": true + } + ], + "ibm_app_config_environment": [ + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Environment name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Environment description", + "optional": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the environment data.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the environment", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "color_code", + "type": "TypeString", + "description": "Color code to distinguish the environment.", + "optional": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the environment.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Environment URL.", + "computed": true + } + ], + "ibm_app_config_feature": [ + { + "name": "enabled", + "type": "TypeBool", + "description": "The state of the feature flag.", + "computed": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the feature flag.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "feature_id", + "type": "TypeString", + "description": "Feature id.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the feature (BOOLEAN, STRING, NUMERIC).", + "required": true, + "options": "BOOLEAN, NUMERIC, STRING" + }, + { + "name": "enabled_value", + "type": "TypeString", + "description": "Value of the feature when it is enabled. The value can be BOOLEAN, STRING or a NUMERIC value as per the `type` attribute.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Feature description.", + "optional": true + }, + { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage of the feature.", + "optional": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the feature flag data.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Feature name.", + "required": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the feature.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified feature flag.", + "optional": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "required": true + } + } + }, + { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the feature flag.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different feature flag values for different segments.", + "optional": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "required": true + }, + "rollout_percentage": { + "name": "rollout_percentage", + "type": "TypeInt", + "description": "Rollout percentage for the segment rule.", + "optional": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "required": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "required": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "Feature flag URL.", + "computed": true + }, + { + "name": "disabled_value", + "type": "TypeString", + "description": "Value of the feature when it is disabled. The value can be BOOLEAN, STRING or a NUMERIC value as per the `type` attribute.", + "required": true + } + ], + "ibm_app_config_property": [ + { + "name": "href", + "type": "TypeString", + "description": "Property URL.", + "computed": true + }, + { + "name": "property_id", + "type": "TypeString", + "description": "Property id.", + "required": true + }, + { + "name": "value", + "type": "TypeString", + "description": "Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "required": true + }, + { + "name": "format", + "type": "TypeString", + "description": "Format of the feature (TEXT, JSON, YAML).", + "optional": true + }, + { + "name": "segment_rules", + "type": "TypeList", + "description": "Specify the targeting rules that is used to set different property values for different segments.", + "optional": true, + "elem": { + "order": { + "name": "order", + "type": "TypeInt", + "description": "Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation.", + "required": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Rules array.", + "required": true, + "elem": { + "segments": { + "name": "segments", + "type": "TypeList", + "description": "List of segment ids that are used for targeting using the rule.", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute.", + "required": true + } + } + }, + { + "name": "evaluation_time", + "type": "TypeString", + "description": "The last occurrence of the property value evaluation.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Property description.", + "optional": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the property.", + "cloud_data_type": "tags", + "optional": true + }, + { + "name": "segment_exists", + "type": "TypeBool", + "description": "Denotes if the targeting rules are specified for the property.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the Property (BOOLEAN, STRING, NUMERIC).", + "required": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the property.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the property data.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment Id.", + "required": true + }, + { + "name": "collections", + "type": "TypeList", + "description": "List of collection id representing the collections that are associated with the specified property.", + "optional": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "required": true + } + } + } + ], + "ibm_app_config_segment": [ + { + "name": "name", + "type": "TypeString", + "description": "Segment name.", + "required": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Segment URL.", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "List of rules that determine if the entity belongs to the segment during feature / property evaluation. An entity is identified by an unique identifier and the attributes that it defines.", + "required": true, + "elem": { + "attribute_name": { + "name": "attribute_name", + "type": "TypeString", + "description": "Attribute name.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator to be used for the evaluation if the entity belongs to the segment.", + "required": true + }, + "values": { + "name": "values", + "type": "TypeList", + "description": "List of values. Entities matching any of the given values will be considered to belong to the segment.", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the segment.", + "computed": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the segment data.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "segment_id", + "type": "TypeString", + "description": "Segment id.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Segment description.", + "optional": true + }, + { + "name": "tags", + "type": "TypeString", + "description": "Tags associated with the segments.", + "cloud_data_type": "tags", + "optional": true + } + ], + "ibm_app_config_snapshot": [ + { + "name": "environment", + "type": "TypeList", + "description": "Environment object", + "computed": true, + "elem": { + "color_code": { + "name": "color_code", + "type": "TypeString", + "description": "Environment color code.", + "computed": true + }, + "environment_id": { + "name": "environment_id", + "type": "TypeString", + "description": "Environment id.", + "computed": true + }, + "environment_name": { + "name": "environment_name", + "type": "TypeString", + "description": "Environment name.", + "computed": true + } + } + }, + { + "name": "git_config_name", + "type": "TypeString", + "description": "Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + "required": true + }, + { + "name": "git_url", + "type": "TypeString", + "description": "Git url which will be used to connect to the github account.", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "action promote", + "optional": true + }, + { + "name": "collection", + "type": "TypeList", + "description": "Collection object.", + "computed": true, + "elem": { + "collection_id": { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "computed": true + }, + "collection_name": { + "name": "collection_name", + "type": "TypeString", + "description": "Collection name.", + "computed": true + } + } + }, + { + "name": "git_file_path", + "type": "TypeString", + "description": "Git file path, this is a path where your configuration file will be written.", + "required": true + }, + { + "name": "updated_time", + "type": "TypeString", + "description": "Last modified time of the git config data.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Git config URL.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard.", + "required": true + }, + { + "name": "git_config_id", + "type": "TypeString", + "description": "Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only", + "required": true + }, + { + "name": "git_token", + "type": "TypeString", + "description": "Git token, this needs to be provided with enough permission to write and update the file.", + "secure": true, + "required": true + }, + { + "name": "collection_id", + "type": "TypeString", + "description": "Collection id.", + "required": true + }, + { + "name": "git_branch", + "type": "TypeString", + "description": "Branch name to which you need to write or update the configuration.", + "required": true + }, + { + "name": "created_time", + "type": "TypeString", + "description": "Creation time of the git config.", + "computed": true + }, + { + "name": "environment_id", + "type": "TypeString", + "description": "Environment id.", + "required": true + } + ], + "ibm_app_domain_private": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the domain", + "immutable": true, + "required": true + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The organization that owns the domain.", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_app_domain_shared": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the domain", + "immutable": true, + "required": true + }, + { + "name": "router_group_guid", + "type": "TypeString", + "description": "The guid of the router group.", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_app_route": [ + { + "name": "space_guid", + "type": "TypeString", + "description": "The guid of the associated space", + "immutable": true, + "required": true + }, + { + "name": "domain_guid", + "type": "TypeString", + "description": "The guid of the associated domain", + "immutable": true, + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "The port of the route. Supported for domains of TCP router groups only.", + "optional": true + }, + { + "name": "path", + "type": "TypeString", + "description": "The path for a route as raw text.Paths must be between 2 and 128 characters.Paths must start with a forward slash '/'.Paths must not contain a '?'", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host", + "type": "TypeString", + "description": "The host portion of the route. Required for shared-domains.", + "optional": true + } + ], + "ibm_appid_action_url": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The type of the action: `on_user_verified` - the URL of your custom user verified page, `on_reset_password` - the URL of your custom reset password page", + "immutable": true, + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The action URL", + "required": true + } + ], + "ibm_appid_apm": [ + { + "name": "min_password_change_interval", + "type": "TypeList", + "required": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "required": true + }, + "min_hours_to_change_password": { + "name": "min_hours_to_change_password", + "type": "TypeInt", + "default_value": 0, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "`true` if APM is enabled", + "required": true + }, + { + "name": "prevent_password_with_username", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + { + "name": "password_reuse", + "type": "TypeList", + "required": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "required": true + }, + "max_password_reuse": { + "name": "max_password_reuse", + "type": "TypeInt", + "default_value": 8, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "password_expiration", + "type": "TypeList", + "required": true, + "elem": { + "days_to_expire": { + "name": "days_to_expire", + "type": "TypeInt", + "default_value": 30, + "optional": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "lockout_policy", + "type": "TypeList", + "required": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "required": true + }, + "lockout_time_sec": { + "name": "lockout_time_sec", + "type": "TypeInt", + "default_value": 1800, + "optional": true + }, + "num_of_attempts": { + "name": "num_of_attempts", + "type": "TypeInt", + "default_value": 3, + "optional": true + } + }, + "max_items": 1 + } + ], + "ibm_appid_application": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The application name to be registered. Application name cannot exceed 50 characters.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of application to be registered. Allowed types are `regularwebapp` and `singlepageapp`, default is `regularwebapp`.", + "default_value": "regularwebapp", + "immutable": true, + "optional": true + }, + { + "name": "secret", + "type": "TypeString", + "description": "The `secret` is a secret known only to the application and the authorization server", + "secure": true, + "computed": true + }, + { + "name": "oauth_server_url", + "type": "TypeString", + "description": "Base URL for common OAuth endpoints, like `/authorization`, `/token` and `/publickeys`", + "computed": true + }, + { + "name": "profiles_url", + "type": "TypeString", + "computed": true + }, + { + "name": "discovery_endpoint", + "type": "TypeString", + "description": "This URL returns OAuth Authorization Server Metadata", + "computed": true + } + ], + "ibm_appid_application_roles": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "immutable": true, + "required": true + }, + { + "name": "roles", + "type": "TypeList", + "description": "A list of role IDs for roles that you want to be assigned to the application (this is different from AppID role access)", + "required": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_application_scopes": [ + { + "name": "scopes", + "type": "TypeList", + "description": "A `scope` is a runtime action in your application that you register with IBM Cloud App ID to create an access permission", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "client_id", + "type": "TypeString", + "description": "The `client_id` is a public identifier for applications", + "immutable": true, + "required": true + } + ], + "ibm_appid_audit_status": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "The auditing status of the tenant.", + "required": true + } + ], + "ibm_appid_cloud_directory_template": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "template_name", + "type": "TypeString", + "description": "The type of email template. This can be `USER_VERIFICATION`, `WELCOME`, `PASSWORD_CHANGED`, `RESET_PASSWORD` or `MFA_VERIFICATION`", + "immutable": true, + "required": true + }, + { + "name": "language", + "type": "TypeString", + "description": "Preferred language for resource. Format as described at RFC5646. According to the configured languages codes returned from the `GET /management/v4/{tenantId}/config/ui/languages API`.", + "default_value": "en", + "immutable": true, + "optional": true + }, + { + "name": "subject", + "type": "TypeString", + "description": "The subject of the email", + "required": true + }, + { + "name": "html_body", + "type": "TypeString", + "description": "The HTML body of the email", + "optional": true + }, + { + "name": "base64_encoded_html_body", + "type": "TypeString", + "description": "The HTML body of the email encoded in Base64", + "computed": true + }, + { + "name": "plain_text_body", + "type": "TypeString", + "description": "The text body of the email.", + "optional": true + } + ], + "ibm_appid_cloud_directory_user": [ + { + "name": "display_name", + "type": "TypeString", + "description": "Cloud Directory user display name", + "optional": true, + "computed": true + }, + { + "name": "user_name", + "type": "TypeString", + "description": "Optional username", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Accepted values `PENDING` or `CONFIRMED`", + "default_value": "PENDING", + "optional": true + }, + { + "name": "email", + "type": "TypeSet", + "description": "A set of user emails", + "required": true, + "elem": { + "primary": { + "name": "primary", + "type": "TypeBool", + "description": "`true` if this is primary email", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "User email", + "required": true + } + } + }, + { + "name": "active", + "type": "TypeBool", + "description": "Determines if the user account is active or not", + "default_value": true, + "optional": true + }, + { + "name": "create_profile", + "type": "TypeBool", + "description": "A boolean indication if a profile should be created for the Cloud Directory user", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "locked_until", + "type": "TypeInt", + "description": "Integer (epoch time in milliseconds), determines till when the user account will be locked", + "optional": true + }, + { + "name": "user_id", + "type": "TypeString", + "description": "Cloud Directory user ID", + "computed": true + }, + { + "name": "meta", + "type": "TypeList", + "description": "Cloud Directory user metadata", + "computed": true, + "elem": { + "created": { + "name": "created", + "type": "TypeString", + "description": "User creation date", + "computed": true + }, + "last_modified": { + "name": "last_modified", + "type": "TypeString", + "description": "Last user modification date", + "computed": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "subject", + "type": "TypeString", + "description": "The user's identifier ('subject' in identity token)", + "computed": true + }, + { + "name": "password", + "type": "TypeString", + "description": "User password", + "secure": true, + "required": true + } + ], + "ibm_appid_idp_cloud_directory": [ + { + "name": "is_active", + "type": "TypeBool", + "required": true + }, + { + "name": "self_service_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "signup_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "welcome_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "reset_password_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "identity_confirm_methods", + "type": "TypeList", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "identity_field", + "type": "TypeString", + "optional": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "immutable": true, + "required": true + }, + { + "name": "reset_password_notification_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "identity_confirm_access_mode", + "type": "TypeString", + "default_value": "FULL", + "optional": true + } + ], + "ibm_appid_idp_custom": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "required": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "This is the public key used to validate your signed JWT. It is required to be a PEM in the RS256 or greater format.", + "optional": true + } + ], + "ibm_appid_idp_facebook": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if Facebook IDP configuration is active", + "required": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Facebook IDP configuration", + "optional": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "description": "Facebook application id", + "required": true + }, + "application_secret": { + "name": "application_secret", + "type": "TypeString", + "description": "Facebook application secret", + "secure": true, + "required": true + } + }, + "max_items": 1 + }, + { + "name": "redirect_url", + "type": "TypeString", + "description": "Paste the URI into the Valid OAuth redirect URIs field in the Facebook Login section of the Facebook Developers Portal", + "computed": true + } + ], + "ibm_appid_idp_google": [ + { + "name": "config", + "type": "TypeList", + "description": "Google IDP configuration", + "optional": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "description": "Google application id", + "required": true + }, + "application_secret": { + "name": "application_secret", + "type": "TypeString", + "description": "Google application secret", + "secure": true, + "required": true + } + }, + "max_items": 1 + }, + { + "name": "redirect_url", + "type": "TypeString", + "description": "Paste the URI into the Authorized redirect URIs field in the Google Developer Console", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if Google IDP configuration is active", + "required": true + } + ], + "ibm_appid_idp_saml": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "SAML IDP activation", + "required": true + }, + { + "name": "config", + "type": "TypeList", + "description": "SAML IDP configuration", + "optional": true, + "elem": { + "authn_context": { + "name": "authn_context", + "type": "TypeList", + "description": "SAML authNContext configuration", + "optional": true, + "elem": { + "class": { + "name": "class", + "type": "TypeList", + "description": "List of `authnContext` classes", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "comparison": { + "name": "comparison", + "type": "TypeString", + "optional": true + } + }, + "max_items": 1 + }, + "certificates": { + "name": "certificates", + "type": "TypeList", + "description": "List of certificates, primary and optional secondary", + "required": true, + "elem": { + "type": "TypeString" + }, + "max_items": 2 + }, + "display_name": { + "name": "display_name", + "type": "TypeString", + "description": "Provider name", + "optional": true + }, + "encrypt_response": { + "name": "encrypt_response", + "type": "TypeBool", + "description": "`true` if SAML responses should be encrypted", + "default_value": false, + "optional": true + }, + "entity_id": { + "name": "entity_id", + "type": "TypeString", + "description": "Unique name for an Identity Provider", + "required": true + }, + "include_scoping": { + "name": "include_scoping", + "type": "TypeBool", + "description": "`true` if scopes are included", + "default_value": false, + "optional": true + }, + "sign_in_url": { + "name": "sign_in_url", + "type": "TypeString", + "description": "SAML SSO url", + "required": true + }, + "sign_request": { + "name": "sign_request", + "type": "TypeBool", + "description": "`true` if SAML requests should be signed", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + } + ], + "ibm_appid_languages": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "languages", + "type": "TypeList", + "description": "The list of languages that can be used to customize email templates for Cloud Directory", + "required": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_mfa": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "is_active", + "type": "TypeBool", + "description": "`true` if MFA is active", + "required": true + } + ], + "ibm_appid_mfa_channel": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "active", + "type": "TypeString", + "description": "Allowed values: `email`, `sms`", + "required": true + }, + { + "name": "sms_config", + "type": "TypeList", + "description": "Configuration for `sms` channel. Create Vonage account (https://dashboard.nexmo.com/sign-up) to get an API key", + "secure": true, + "optional": true, + "elem": { + "from": { + "name": "from", + "type": "TypeString", + "description": "Sender's phone number", + "required": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "API key", + "secure": true, + "required": true + }, + "secret": { + "name": "secret", + "type": "TypeString", + "description": "API secret", + "secure": true, + "required": true + } + } + } + ], + "ibm_appid_password_regex": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "base64_encoded_regex", + "type": "TypeString", + "description": "The regex expression rule for acceptable password encoded in base64", + "computed": true + }, + { + "name": "error_message", + "type": "TypeString", + "description": "Custom error message", + "optional": true + }, + { + "name": "regex", + "type": "TypeString", + "description": "The escaped regex expression rule for acceptable password", + "required": true + } + ], + "ibm_appid_redirect_urls": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "urls", + "type": "TypeList", + "description": "A list of redirect URLs", + "required": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_appid_role": [ + { + "name": "role_id", + "type": "TypeString", + "description": "Role ID", + "computed": true + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Unique role name", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Optional role description", + "optional": true + }, + { + "name": "access", + "type": "TypeSet", + "optional": true, + "elem": { + "application_id": { + "name": "application_id", + "type": "TypeString", + "description": "Application `client_id`", + "required": true + }, + "scopes": { + "name": "scopes", + "type": "TypeList", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_appid_theme_color": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "header_color", + "type": "TypeString", + "required": true + } + ], + "ibm_appid_theme_text": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "tab_title", + "type": "TypeString", + "optional": true + }, + { + "name": "footnote", + "type": "TypeString", + "optional": true + } + ], + "ibm_appid_token_config": [ + { + "name": "refresh_token_expires_in", + "type": "TypeInt", + "description": "The length of time for which refresh tokens are valid in seconds", + "default_value": 2592000, + "optional": true + }, + { + "name": "anonymous_token_expires_in", + "type": "TypeInt", + "default_value": 2592000, + "optional": true + }, + { + "name": "anonymous_access_enabled", + "type": "TypeBool", + "description": "The length of time for which an anonymous token is valid in seconds", + "optional": true, + "computed": true + }, + { + "name": "refresh_token_enabled", + "type": "TypeBool", + "optional": true, + "computed": true + }, + { + "name": "access_token_claim", + "type": "TypeSet", + "description": "A set of objects that are created when claims that are related to access tokens are mapped", + "optional": true, + "elem": { + "destination_claim": { + "name": "destination_claim", + "type": "TypeString", + "description": "Optional: Defines the custom attribute that can override the current claim in token.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`, and `attributes`.", + "required": true + }, + "source_claim": { + "name": "source_claim", + "type": "TypeString", + "description": "Defines the claim as provided by the source. It can refer to the identity provider's user information or the user's App ID custom attributes.", + "optional": true + } + } + }, + { + "name": "id_token_claim", + "type": "TypeSet", + "description": "A set of objects that are created when claims that are related to identity tokens are mapped", + "optional": true, + "elem": { + "destination_claim": { + "name": "destination_claim", + "type": "TypeString", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "required": true + }, + "source_claim": { + "name": "source_claim", + "type": "TypeString", + "optional": true + } + } + }, + { + "name": "tenant_id", + "type": "TypeString", + "description": "The service `tenantId`", + "immutable": true, + "required": true + }, + { + "name": "access_token_expires_in", + "type": "TypeInt", + "description": "The length of time for which access tokens are valid in seconds", + "optional": true, + "computed": true + } + ], + "ibm_appid_user_roles": [ + { + "name": "tenant_id", + "type": "TypeString", + "description": "The AppID instance GUID", + "immutable": true, + "required": true + }, + { + "name": "subject", + "type": "TypeString", + "description": "The user's identifier ('subject' in identity token)", + "immutable": true, + "required": true + }, + { + "name": "role_ids", + "type": "TypeSet", + "description": "A set of AppID role IDs that should be assigned to the user", + "required": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_atracker_route": [ + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the route resource.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created", + "type": "TypeString", + "description": "The timestamp of the route creation time.", + "computed": true, + "deprecated": "use created_at instead" + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp of the route creation time.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp of the route last updated time.", + "computed": true + }, + { + "name": "api_version", + "type": "TypeInt", + "description": "The API version of the route.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the route. The name must be 1000 characters or less and cannot include any special characters other than `(space) - . _ :`.", + "required": true, + "min_length": 1, + "max_length": 1000, + "matches": "^[a-zA-Z0-9 -._:]+$" + }, + { + "name": "receive_global_events", + "type": "TypeBool", + "description": "Indicates whether or not all global events should be forwarded to this region.", + "optional": true, + "deprecated": "use rules.locations instead" + }, + { + "name": "rules", + "type": "TypeList", + "description": "Routing rules that will be evaluated in their order of the array.", + "required": true, + "elem": { + "locations": { + "name": "locations", + "type": "TypeSet", + "description": "Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "target_ids": { + "name": "target_ids", + "type": "TypeSet", + "description": "The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions.", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "version", + "type": "TypeInt", + "description": "The version of the route.", + "computed": true + }, + { + "name": "updated", + "type": "TypeString", + "description": "The timestamp of the route last updated time.", + "computed": true, + "deprecated": "use updated_at instead" + } + ], + "ibm_atracker_settings": [ + { + "name": "metadata_region_primary", + "type": "TypeString", + "description": "To store all your meta data in a single region.", + "required": true, + "min_length": 3, + "max_length": 256, + "matches": "^[a-zA-Z0-9 -_]" + }, + { + "name": "private_api_endpoint_only", + "type": "TypeBool", + "description": "If you set this true then you cannot access api through public network.", + "required": true + }, + { + "name": "default_targets", + "type": "TypeList", + "description": "The target ID List. In the event that no routing rule causes the event to be sent to a target, these targets will receive the event.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "permitted_target_regions", + "type": "TypeList", + "description": "If present then only these regions may be used to define a target.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "metadata_region_backup", + "type": "TypeString", + "description": "Provide a back up region to store meta data.", + "max_length": 256, + "matches": "^[a-zA-Z0-9 -_]*", + "optional": true + }, + { + "name": "api_version", + "type": "TypeInt", + "description": "The lowest API version of targets or routes that customer might have under his or her account.", + "computed": true + } + ], + "ibm_atracker_target": [ + { + "name": "cos_write_status", + "type": "TypeList", + "description": "The status of the write attempt with the provided cos_endpoint parameters.", + "computed": true, + "elem": { + "last_failure": { + "name": "last_failure", + "type": "TypeString", + "description": "The timestamp of the failure.", + "optional": true + }, + "reason_for_last_failure": { + "name": "reason_for_last_failure", + "type": "TypeString", + "description": "Detailed description of the cause of the failure.", + "optional": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status such as failed or success.", + "optional": true + } + }, + "deprecated": "use write_status instead" + }, + { + "name": "write_status", + "type": "TypeList", + "description": "The status of the write attempt to the target with the provided endpoint parameters.", + "computed": true, + "elem": { + "last_failure": { + "name": "last_failure", + "type": "TypeString", + "description": "The timestamp of the failure.", + "optional": true + }, + "reason_for_last_failure": { + "name": "reason_for_last_failure", + "type": "TypeString", + "description": "Detailed description of the cause of the failure.", + "optional": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status such as failed or success.", + "required": true + } + } + }, + { + "name": "created", + "type": "TypeString", + "description": "The timestamp of the target creation time.", + "computed": true, + "deprecated": "use created_at instead" + }, + { + "name": "updated", + "type": "TypeString", + "description": "The timestamp of the target last updated time.", + "computed": true, + "deprecated": "use updated_at instead" + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp of the target creation time.", + "computed": true + }, + { + "name": "target_type", + "type": "TypeString", + "description": "The type of the target. It can be cloud_object_storage or logdna. Based on this type you must include cos_endpoint or logdna_endpoint.", + "immutable": true, + "required": true, + "options": "cloud_object_storage, logdna" + }, + { + "name": "cos_endpoint", + "type": "TypeList", + "description": "Property values for a Cloud Object Storage Endpoint.", + "optional": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled.", + "secure": true, + "optional": true + }, + "bucket": { + "name": "bucket", + "type": "TypeString", + "description": "The bucket name under the Cloud Object Storage instance.", + "required": true + }, + "endpoint": { + "name": "endpoint", + "type": "TypeString", + "description": "The host name of the Cloud Object Storage endpoint.", + "required": true + }, + "service_to_service_enabled": { + "name": "service_to_service_enabled", + "type": "TypeBool", + "description": "ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey.", + "optional": true + }, + "target_crn": { + "name": "target_crn", + "type": "TypeString", + "description": "The CRN of the Cloud Object Storage instance.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "logdna_endpoint", + "type": "TypeList", + "description": "Property values for a LogDNA Endpoint.", + "optional": true, + "elem": { + "ingestion_key": { + "name": "ingestion_key", + "type": "TypeString", + "description": "The LogDNA ingestion key is used for routing logs to a specific LogDNA instance.", + "secure": true, + "required": true + }, + "target_crn": { + "name": "target_crn", + "type": "TypeString", + "description": "The CRN of the LogDNA instance.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "region", + "type": "TypeString", + "description": "Include this optional field if you want to create a target in a different region other than the one you are connected.", + "immutable": true, + "min_length": 3, + "max_length": 1000, + "matches": "^[a-zA-Z0-9 -._:]+$", + "optional": true + }, + { + "name": "api_version", + "type": "TypeInt", + "description": "The API version of the target.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the target. The name must be 1000 characters or less, and cannot include any special characters other than `(space) - . _ :`.", + "required": true, + "min_length": 1, + "max_length": 1000, + "matches": "^[a-zA-Z0-9 -._:]+$" + }, + { + "name": "encrypt_key", + "type": "TypeString", + "description": "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + "computed": true, + "deprecated": "use encryption_key instead" + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp of the target last updated time.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the target resource.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response.", + "computed": true + } + ], + "ibm_cbr_rule": [ + { + "name": "resources", + "type": "TypeList", + "description": "The resources this rule apply to.", + "required": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeList", + "description": "The resource attributes.", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The attribute name.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The attribute operator.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The attribute value.", + "required": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeList", + "description": "The optional resource tags.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The tag attribute name.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The attribute operator.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The tag attribute value.", + "required": true + } + } + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The href link to the resource.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time the resource was created.", + "computed": true + }, + { + "name": "created_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which created the resource.", + "computed": true + }, + { + "name": "contexts", + "type": "TypeList", + "description": "The contexts this rule applies to.", + "required": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeList", + "description": "The attributes.", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The attribute name.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The attribute value.", + "required": true + } + } + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The rule CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "last_modified_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which modified the resource.", + "computed": true + }, + { + "name": "last_modified_at", + "type": "TypeString", + "description": "The last time the resource was modified.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the rule.", + "max_length": 300, + "matches": "^[\\x20-\\xFE]*$", + "optional": true + }, + { + "name": "operations", + "type": "TypeList", + "description": "The operations this rule applies to.", + "optional": true, + "elem": { + "api_types": { + "name": "api_types", + "type": "TypeList", + "description": "The API types this rule applies to.", + "required": true, + "elem": { + "api_type_id": { + "name": "api_type_id", + "type": "TypeString", + "required": true + } + } + } + }, + "max_items": 1 + }, + { + "name": "enforcement_mode", + "type": "TypeString", + "description": "The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced.", + "default_value": "enabled", + "options": "disabled, enabled, report", + "optional": true + }, + { + "name": "x_correlation_id", + "type": "TypeString", + "description": "The supplied or generated value of this header is logged for a request and repeated in a response header for the corresponding response. The same value is used for downstream requests and retries of those requests. If a value of this headers is not supplied in a request, the service generates a random (version 4) UUID.", + "min_length": 1, + "max_length": 1024, + "matches": "^[a-zA-Z0-9 ,\\-_]+$", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "The `Transaction-Id` header behaves as the `X-Correlation-Id` header. It is supported for backward compatibility with other IBM platform services that support the `Transaction-Id` header only. If both `X-Correlation-Id` and `Transaction-Id` are provided, `X-Correlation-Id` has the precedence over `Transaction-Id`.", + "min_length": 1, + "max_length": 1024, + "matches": "^[a-zA-Z0-9 ,\\-_]+$", + "optional": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_cbr_zone": [ + { + "name": "crn", + "type": "TypeString", + "description": "The zone CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time the resource was created.", + "computed": true + }, + { + "name": "created_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which created the resource.", + "computed": true + }, + { + "name": "address_count", + "type": "TypeInt", + "description": "The number of addresses in the zone.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "addresses", + "type": "TypeList", + "description": "The list of addresses in the zone.", + "required": true, + "elem": { + "ref": { + "name": "ref", + "type": "TypeList", + "description": "A service reference value.", + "optional": true, + "elem": { + "account_id": { + "name": "account_id", + "type": "TypeString", + "description": "The id of the account owning the service.", + "required": true + }, + "location": { + "name": "location", + "type": "TypeString", + "description": "The location.", + "optional": true + }, + "service_instance": { + "name": "service_instance", + "type": "TypeString", + "description": "The service instance.", + "optional": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "The service name.", + "optional": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "The service type.", + "optional": true + } + }, + "max_items": 1 + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of address.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The IP address.", + "optional": true + } + } + }, + { + "name": "excluded", + "type": "TypeList", + "description": "The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded.", + "optional": true, + "elem": { + "type": { + "name": "type", + "type": "TypeString", + "description": "The type of address.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The IP address.", + "optional": true + } + } + }, + { + "name": "x_correlation_id", + "type": "TypeString", + "description": "The supplied or generated value of this header is logged for a request and repeated in a response header for the corresponding response. The same value is used for downstream requests and retries of those requests. If a value of this headers is not supplied in a request, the service generates a random (version 4) UUID.", + "min_length": 1, + "max_length": 1024, + "matches": "^[a-zA-Z0-9 ,\\-_]+$", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the zone.", + "max_length": 300, + "matches": "^[\\x20-\\xFE]*$", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "The `Transaction-Id` header behaves as the `X-Correlation-Id` header. It is supported for backward compatibility with other IBM platform services that support the `Transaction-Id` header only. If both `X-Correlation-Id` and `Transaction-Id` are provided, `X-Correlation-Id` has the precedence over `Transaction-Id`.", + "min_length": 1, + "max_length": 1024, + "matches": "^[a-zA-Z0-9 ,\\-_]+$", + "optional": true + }, + { + "name": "last_modified_by_id", + "type": "TypeString", + "description": "IAM ID of the user or service which modified the resource.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The href link to the resource.", + "computed": true + }, + { + "name": "last_modified_at", + "type": "TypeString", + "description": "The last time the resource was modified.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the zone.", + "required": true, + "min_length": 1, + "max_length": 128, + "matches": "^[a-zA-Z0-9 \\-_]+$" + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The id of the account owning this zone.", + "required": true, + "min_length": 1, + "max_length": 128, + "matches": "^[a-zA-Z0-9\\-]+$" + }, + { + "name": "excluded_count", + "type": "TypeInt", + "description": "The number of excluded addresses in the zone.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline": [ + { + "name": "definitions", + "type": "TypeList", + "description": "Definition list.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "UUID.", + "computed": true + }, + "scm_source": { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source for Tekton pipeline definition.", + "required": true, + "elem": { + "branch": { + "name": "branch", + "type": "TypeString", + "description": "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "The path to the definition's yaml files.", + "required": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the SCM repository service instance.", + "computed": true + }, + "tag": { + "name": "tag", + "type": "TypeString", + "description": "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the definition repository.", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + } + } + }, + { + "name": "properties", + "type": "TypeList", + "description": "Tekton pipeline's environment properties.", + "computed": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed when using `single_select` property type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "immutable": true, + "required": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value.", + "optional": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Standard RFC 3339 Date Time String.", + "computed": true + }, + { + "name": "build_number", + "type": "TypeInt", + "description": "The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "String.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Pipeline status.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Standard RFC 3339 Date Time String.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Flag whether this pipeline is enabled.", + "computed": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "String.", + "immutable": true, + "required": true + }, + { + "name": "toolchain", + "type": "TypeList", + "description": "Toolchain object.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for the toolchain that contains the Tekton pipeline.", + "required": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "UUID.", + "required": true + } + } + }, + { + "name": "enable_slack_notifications", + "type": "TypeBool", + "description": "Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain.", + "default_value": false, + "optional": true + }, + { + "name": "enable_partial_cloning", + "type": "TypeBool", + "description": "Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work.", + "default_value": false, + "optional": true + }, + { + "name": "worker", + "type": "TypeList", + "description": "Worker object containing worker ID only. If omitted the IBM Managed shared workers are used by default.", + "optional": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "triggers", + "type": "TypeList", + "description": "Tekton pipeline triggers list.", + "computed": true, + "elem": { + "cron": { + "name": "cron", + "type": "TypeString", + "description": "Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes.", + "optional": true + }, + "disabled": { + "name": "disabled", + "type": "TypeBool", + "description": "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + "optional": true + }, + "event_listener": { + "name": "event_listener", + "type": "TypeString", + "description": "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + "required": true + }, + "events": { + "name": "events", + "type": "TypeList", + "description": "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + "optional": true, + "elem": { + "pull_request": { + "name": "pull_request", + "type": "TypeBool", + "description": "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + "optional": true + }, + "pull_request_closed": { + "name": "pull_request_closed", + "type": "TypeBool", + "description": "If true, the trigger listens for 'close pull request' Git webhook events.", + "optional": true + }, + "push": { + "name": "push", + "type": "TypeBool", + "description": "If true, the trigger listens for 'push' Git webhook events.", + "optional": true + } + }, + "max_items": 1 + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger.", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID.", + "computed": true + }, + "max_concurrent_runs": { + "name": "max_concurrent_runs", + "type": "TypeInt", + "description": "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Trigger name.", + "required": true + }, + "properties": { + "name": "properties", + "type": "TypeList", + "description": "Trigger properties.", + "optional": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger property.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "immutable": true, + "required": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value. Can be empty and should be omitted for `single_select` property type.", + "optional": true + } + } + }, + "scm_source": { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source repository for a Git trigger. Only needed for Git triggers.", + "optional": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "optional": true + }, + "branch": { + "name": "branch", + "type": "TypeString", + "description": "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "hook_id": { + "name": "hook_id", + "type": "TypeString", + "description": "ID of the webhook from the repo. Computed upon creation of the trigger.", + "computed": true + }, + "pattern": { + "name": "pattern", + "type": "TypeString", + "description": "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + "optional": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the repository service instance.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the repository to which the trigger is listening.", + "immutable": true, + "required": true + } + }, + "max_items": 1 + }, + "secret": { + "name": "secret", + "type": "TypeList", + "description": "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + "optional": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + "optional": true + }, + "key_name": { + "name": "key_name", + "type": "TypeString", + "description": "Secret name, not needed if type is `internal_validation`.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Secret location, not needed if secret type is `internal_validation`.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Secret type.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Secret value, not needed if secret type is `internal_validation`.", + "optional": true + } + }, + "max_items": 1 + }, + "tags": { + "name": "tags", + "type": "TypeList", + "description": "Trigger tags array.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "timezone": { + "name": "timezone", + "type": "TypeString", + "description": "Only needed for timer triggers. Timezone for timer trigger.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Trigger type.", + "required": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "TypeString", + "description": "Webhook URL that can be used to trigger pipeline runs.", + "optional": true + }, + "worker": { + "name": "worker", + "type": "TypeList", + "description": "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + "optional": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "immutable": true, + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the worker. Computed based on the worker ID.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the worker. Computed based on the worker ID.", + "computed": true + } + }, + "max_items": 1 + } + } + }, + { + "name": "runs_url", + "type": "TypeString", + "description": "URL for this pipeline showing the list of pipeline runs.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline_definition": [ + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[-0-9a-z]+$" + }, + { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source for Tekton pipeline definition.", + "optional": true, + "elem": { + "branch": { + "name": "branch", + "type": "TypeString", + "description": "A branch from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "The path to the definition's yaml files.", + "required": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the SCM repository service instance.", + "computed": true + }, + "tag": { + "name": "tag", + "type": "TypeString", + "description": "A tag from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the definition repository.", + "immutable": true, + "required": true + } + }, + "max_items": 1 + }, + { + "name": "definition_id", + "type": "TypeString", + "description": "UUID.", + "computed": true + } + ], + "ibm_cd_tekton_pipeline_property": [ + { + "name": "value", + "type": "TypeString", + "description": "Property value.", + "min_length": 1, + "max_length": 4096, + "matches": ".", + "optional": true + }, + { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed when using `single_select` property type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "required": true, + "options": "appconfig, integration, secure, single_select, text" + }, + { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration.", + "min_length": 1, + "max_length": 4096, + "matches": ".", + "optional": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[-0-9a-z]+$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 253, + "matches": "^[-0-9a-zA-Z_.]{1,234}$" + } + ], + "ibm_cd_tekton_pipeline_trigger": [ + { + "name": "events", + "type": "TypeList", + "description": "Only needed for Git triggers. Events object defines the events to which this Git trigger listens.", + "optional": true, + "elem": { + "pull_request": { + "name": "pull_request", + "type": "TypeBool", + "description": "If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events.", + "optional": true + }, + "pull_request_closed": { + "name": "pull_request_closed", + "type": "TypeBool", + "description": "If true, the trigger listens for 'close pull request' Git webhook events.", + "optional": true + }, + "push": { + "name": "push", + "type": "TypeBool", + "description": "If true, the trigger listens for 'push' Git webhook events.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "webhook_url", + "type": "TypeString", + "description": "Webhook URL that can be used to trigger pipeline runs.", + "computed": true + }, + { + "name": "trigger_id", + "type": "TypeString", + "description": "ID.", + "computed": true + }, + { + "name": "event_listener", + "type": "TypeString", + "description": "Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline.", + "required": true, + "min_length": 1, + "max_length": 253, + "matches": "^[-0-9a-zA-Z_.]{1,235}$" + }, + { + "name": "worker", + "type": "TypeList", + "description": "Worker used to run the trigger. If not specified the trigger will use the default pipeline worker.", + "optional": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the worker.", + "immutable": true, + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the worker. Computed based on the worker ID.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the worker. Computed based on the worker ID.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "secret", + "type": "TypeList", + "description": "Only needed for generic webhook trigger type. Secret used to start generic webhook trigger.", + "optional": true, + "elem": { + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type.", + "optional": true + }, + "key_name": { + "name": "key_name", + "type": "TypeString", + "description": "Secret name, not needed if type is `internal_validation`.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Secret location, not needed if secret type is `internal_validation`.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Secret type.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Secret value, not needed if secret type is `internal_validation`.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "cron", + "type": "TypeString", + "description": "Only needed for timer triggers. Cron expression for timer trigger.", + "min_length": 5, + "max_length": 253, + "matches": "^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\\/([0-6]))$", + "optional": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[-0-9a-z]+$" + }, + { + "name": "tags", + "type": "TypeList", + "description": "Trigger tags array.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "disabled", + "type": "TypeBool", + "description": "Flag whether the trigger is disabled. If omitted the trigger is enabled by default.", + "optional": true + }, + { + "name": "timezone", + "type": "TypeString", + "description": "Only needed for timer triggers. Timezone for timer trigger.", + "min_length": 1, + "max_length": 253, + "matches": "^[-0-9a-zA-Z_., \\/]{1,234}$", + "optional": true + }, + { + "name": "scm_source", + "type": "TypeList", + "description": "SCM source repository for a Git trigger. Only needed for Git triggers.", + "optional": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "computed": true + }, + "branch": { + "name": "branch", + "type": "TypeString", + "description": "Name of a branch from the repo. One of branch or tag must be specified, but only one or the other.", + "optional": true + }, + "hook_id": { + "name": "hook_id", + "type": "TypeString", + "description": "ID of the webhook from the repo. Computed upon creation of the trigger.", + "computed": true + }, + "pattern": { + "name": "pattern", + "type": "TypeString", + "description": "Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax.", + "optional": true + }, + "service_instance_id": { + "name": "service_instance_id", + "type": "TypeString", + "description": "ID of the repository service instance.", + "computed": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of the repository to which the trigger is listening.", + "immutable": true, + "required": true + } + }, + "max_items": 1 + }, + { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger.", + "computed": true + }, + { + "name": "properties", + "type": "TypeList", + "description": "Trigger properties.", + "computed": true, + "elem": { + "enum": { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "API URL for interacting with the trigger property.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "immutable": true, + "required": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Property value. Can be empty and should be omitted for `single_select` property type.", + "optional": true + } + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Trigger type.", + "required": true, + "options": "generic, manual, scm, timer" + }, + { + "name": "name", + "type": "TypeString", + "description": "Trigger name.", + "required": true, + "min_length": 1, + "max_length": 253, + "matches": "^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$" + }, + { + "name": "max_concurrent_runs", + "type": "TypeInt", + "description": "Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit.", + "optional": true + } + ], + "ibm_cd_tekton_pipeline_trigger_property": [ + { + "name": "value", + "type": "TypeString", + "description": "Property value.", + "min_length": 1, + "max_length": 4096, + "matches": ".", + "optional": true + }, + { + "name": "enum", + "type": "TypeList", + "description": "Options for `single_select` property type. Only needed for `single_select` property type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "Property type.", + "required": true, + "options": "appconfig, integration, secure, single_select, text" + }, + { + "name": "path", + "type": "TypeString", + "description": "A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used.", + "min_length": 1, + "max_length": 4096, + "matches": ".", + "optional": true + }, + { + "name": "pipeline_id", + "type": "TypeString", + "description": "The Tekton pipeline ID.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[-0-9a-z]+$" + }, + { + "name": "trigger_id", + "type": "TypeString", + "description": "The trigger ID.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[-0-9a-z]+$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Property name.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 253, + "matches": "^[-0-9a-zA-Z_.]{1,234}$" + } + ], + "ibm_cd_toolchain": [ + { + "name": "name", + "type": "TypeString", + "description": "Toolchain name.", + "required": true, + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$" + }, + { + "name": "location", + "type": "TypeString", + "description": "Toolchain region.", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI that can be used to retrieve toolchain.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Tags associated with the toolchain.", + "cloud_data_type": "tags", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where toolchain will be created.", + "immutable": true, + "required": true, + "min_length": 32, + "max_length": 32, + "matches": "^[0-9a-f]{32}$" + }, + { + "name": "description", + "type": "TypeString", + "description": "Describes the toolchain.", + "max_length": 500, + "matches": "^(.*?)$", + "optional": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Account ID where toolchain can be found.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Toolchain CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Toolchain creation timestamp.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest toolchain update timestamp.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Identity that created the toolchain.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_appconfig": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "collection_name": { + "name": "collection_name", + "type": "TypeString", + "description": "App Configuration collection.", + "required": true + }, + "environment_name": { + "name": "environment_name", + "type": "TypeString", + "description": "App Configuration environment.", + "required": true + }, + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain.", + "required": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "required": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + } + ], + "ibm_cd_toolchain_tool_artifactory": [ + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the Artifactory integration tile.", + "optional": true + }, + "mirror_url": { + "name": "mirror_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain.", + "required": true + }, + "release_url": { + "name": "release_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory release repository.", + "optional": true + }, + "repository_name": { + "name": "repository_name", + "type": "TypeString", + "description": "Type the name of your artifactory repository where your docker images are located.", + "optional": true + }, + "repository_url": { + "name": "repository_url", + "type": "TypeString", + "description": "Type the URL of your artifactory repository where your docker images are located.", + "optional": true + }, + "snapshot_url": { + "name": "snapshot_url", + "type": "TypeString", + "description": "Type the URL for your Artifactory snapshot repository.", + "optional": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type the API key for your Artifactory repository.", + "secure": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Choose the type of repository for your Artifactory integration.", + "required": true + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "Type the User ID or email for your Artifactory repository.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_bitbucketgit": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://api.bitbucket.org.", + "optional": true, + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "default_value": false, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable Bitbucket Issues for lightweight issue tracking.", + "default_value": true, + "optional": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "optional": true, + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "optional": true, + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "optional": true, + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "optional": true, + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "initialization", + "type": "TypeList", + "required": true, + "elem": { + "git_id": { + "name": "git_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "default_value": false, + "immutable": true, + "optional": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "immutable": true, + "optional": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "immutable": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_custom": [ + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "additional_properties": { + "name": "additional_properties", + "type": "TypeString", + "description": "(Advanced) Type any information that is needed to integrate with other tools in your toolchain.", + "optional": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the tool integration card.", + "required": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Type a description for the tool instance.", + "optional": true + }, + "documentation_url": { + "name": "documentation_url", + "type": "TypeString", + "description": "Type the URL for your tool's documentation.", + "optional": true + }, + "image_url": { + "name": "image_url", + "type": "TypeString", + "description": "Type the URL of the icon to show on your tool integration's card.", + "optional": true + }, + "lifecycle_phase": { + "name": "lifecycle_phase", + "type": "TypeString", + "description": "Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this specific tool integration; for example: My Build and Deploy Pipeline.", + "required": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type the name of the tool that you are integrating; for example: Delivery Pipeline.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_devopsinsights": [ + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + } + ], + "ibm_cd_toolchain_tool_githubconsolidated": [ + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://api.github.example.com.", + "optional": true, + "computed": true + }, + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "optional": true, + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "default_value": false, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.", + "default_value": true, + "optional": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "optional": true, + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "optional": true, + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "optional": true, + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "optional": true, + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "initialization", + "type": "TypeList", + "required": true, + "elem": { + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "default_value": false, + "immutable": true, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "default_value": false, + "immutable": true, + "optional": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "immutable": true, + "optional": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "immutable": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + } + ], + "ibm_cd_toolchain_tool_githubintegrated": [ + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "initialization", + "type": "TypeList", + "required": true, + "elem": { + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "default_value": false, + "immutable": true, + "optional": true + }, + "legal": { + "name": "legal", + "type": "TypeBool", + "default_value": true, + "immutable": true, + "optional": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "default_value": false, + "immutable": true, + "optional": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "immutable": true, + "optional": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "immutable": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://github.ibm.com/api/v3.", + "optional": true, + "computed": true + }, + "auto_init": { + "name": "auto_init", + "type": "TypeBool", + "description": "Select this checkbox to initialize this repository with a README.", + "optional": true, + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "default_value": false, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.", + "default_value": true, + "optional": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "optional": true, + "computed": true + }, + "legal": { + "name": "legal", + "type": "TypeBool", + "optional": true, + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "optional": true, + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "optional": true, + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "optional": true, + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_cd_toolchain_tool_gitlab": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://gitlab.example.com/api/v4.", + "optional": true, + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "default_value": false, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable GitLab Issues for lightweight issue tracking.", + "default_value": true, + "optional": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "optional": true, + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "optional": true, + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "optional": true, + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "optional": true, + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "initialization", + "type": "TypeList", + "required": true, + "elem": { + "git_id": { + "name": "git_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "default_value": true, + "immutable": true, + "optional": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "immutable": true, + "optional": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "immutable": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + } + ], + "ibm_cd_toolchain_tool_hashicorpvault": [ + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "authentication_method": { + "name": "authentication_method", + "type": "TypeString", + "description": "Choose the authentication method for your HashiCorp Vault instance.", + "required": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile.", + "required": true + }, + "default_secret": { + "name": "default_secret", + "type": "TypeString", + "description": "Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "required": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Type or select the authentication password for your HashiCorp Vault instance.", + "secure": true, + "optional": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "Type the mount path where your secrets are stored in your HashiCorp Vault instance.", + "required": true + }, + "role_id": { + "name": "role_id", + "type": "TypeString", + "description": "Type or select the authentication role ID for your HashiCorp Vault instance.", + "secure": true, + "optional": true + }, + "secret_filter": { + "name": "secret_filter", + "type": "TypeString", + "description": "Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance.", + "optional": true + }, + "secret_id": { + "name": "secret_id", + "type": "TypeString", + "description": "Type or select the authentication secret ID for your HashiCorp Vault instance.", + "secure": true, + "optional": true + }, + "server_url": { + "name": "server_url", + "type": "TypeString", + "description": "Type the server URL for your HashiCorp Vault instance.", + "required": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type or select the authentication token for your HashiCorp Vault instance.", + "secure": true, + "optional": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Type or select the authentication username for your HashiCorp Vault instance.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_hostedgit": [ + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_root_url": { + "name": "api_root_url", + "type": "TypeString", + "description": "e.g. https://gitlab.example.com/api/v4.", + "optional": true, + "computed": true + }, + "enable_traceability": { + "name": "enable_traceability", + "type": "TypeBool", + "description": "Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues.", + "default_value": false, + "optional": true + }, + "git_id": { + "name": "git_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "has_issues": { + "name": "has_issues", + "type": "TypeBool", + "description": "Select this check box to enable Issues for lightweight issue tracking.", + "default_value": true, + "optional": true + }, + "integration_owner": { + "name": "integration_owner", + "type": "TypeString", + "description": "Select the user which git operations will be performed as.", + "optional": true, + "computed": true + }, + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "optional": true, + "computed": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "optional": true, + "computed": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "optional": true, + "computed": true + }, + "token_url": { + "name": "token_url", + "type": "TypeString", + "description": "Integration token URL.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "initialization", + "type": "TypeList", + "required": true, + "elem": { + "owner_id": { + "name": "owner_id", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_repo": { + "name": "private_repo", + "type": "TypeBool", + "description": "Select this check box to make this repository private.", + "default_value": true, + "immutable": true, + "optional": true + }, + "repo_name": { + "name": "repo_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "repo_url": { + "name": "repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are linking to.", + "immutable": true, + "optional": true + }, + "source_repo_url": { + "name": "source_repo_url", + "type": "TypeString", + "description": "Type the URL of the repository that you are forking or cloning.", + "immutable": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_jenkins": [ + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_token": { + "name": "api_token", + "type": "TypeString", + "description": "Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance.", + "secure": true, + "optional": true + }, + "api_user_name": { + "name": "api_user_name", + "type": "TypeString", + "description": "Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance.", + "optional": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain.", + "required": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "TypeString", + "description": "Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + } + ], + "ibm_cd_toolchain_tool_keyprotect": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "required": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "required": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_nexus": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL that you want to navigate to when you click the Nexus integration tile.", + "optional": true + }, + "mirror_url": { + "name": "mirror_url", + "type": "TypeString", + "description": "Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain.", + "required": true + }, + "release_url": { + "name": "release_url", + "type": "TypeString", + "description": "Type the URL for your Nexus release repository.", + "optional": true + }, + "snapshot_url": { + "name": "snapshot_url", + "type": "TypeString", + "description": "Type the URL for your Nexus snapshot repository.", + "optional": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Type the password or authentication token for your Nexus repository.", + "secure": true, + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Choose the type of repository for your Nexus integration.", + "required": true + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "Type the User ID or email for your Nexus repository.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + } + ], + "ibm_cd_toolchain_tool_pagerduty": [ + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key).", + "secure": true, + "optional": true + }, + "key_type": { + "name": "key_type", + "type": "TypeString", + "description": "Select whether to integrate at the account level with an API key or at the service level with an integration key.", + "required": true + }, + "service_id": { + "name": "service_id", + "type": "TypeString", + "description": "service_id.", + "optional": true, + "computed": true + }, + "service_key": { + "name": "service_key", + "type": "TypeString", + "description": "Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page.", + "secure": true, + "optional": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service.", + "optional": true + }, + "service_url": { + "name": "service_url", + "type": "TypeString", + "description": "Type the URL of the PagerDuty service to post alerts to.", + "optional": true + }, + "user_email": { + "name": "user_email", + "type": "TypeString", + "description": "Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user.", + "optional": true + }, + "user_phone": { + "name": "user_phone", + "type": "TypeString", + "description": "Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_pipeline": [ + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "optional": true + }, + "ui_pipeline": { + "name": "ui_pipeline", + "type": "TypeBool", + "description": "When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser.", + "default_value": false, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + } + ], + "ibm_cd_toolchain_tool_privateworker": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain.", + "required": true + }, + "worker_queue_credentials": { + "name": "worker_queue_credentials", + "type": "TypeString", + "description": "Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue.", + "secure": true, + "required": true + }, + "worker_queue_identifier": { + "name": "worker_queue_identifier", + "type": "TypeString", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_saucelabs": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "key": { + "name": "key", + "type": "TypeString", + "description": "Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page.", + "secure": true, + "required": true + }, + "username": { + "name": "username", + "type": "TypeString", + "description": "Type the user name for your Sauce Labs account.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_secretsmanager": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "instance_name": { + "name": "instance_name", + "type": "TypeString", + "description": "The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Enter a name for this tool integration. This name is displayed on your toolchain.", + "required": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region.", + "required": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_securitycompliance": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once).", + "secure": true, + "optional": true + }, + "evidence_namespace": { + "name": "evidence_namespace", + "type": "TypeString", + "description": "The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence.", + "optional": true + }, + "evidence_repo_name": { + "name": "evidence_repo_name", + "type": "TypeString", + "description": "To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker.", + "required": true + }, + "location": { + "name": "location", + "type": "TypeString", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Give this tool integration a name, for example: my-security-compliance.", + "required": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + "optional": true + }, + "scope": { + "name": "scope", + "type": "TypeString", + "description": "Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg).", + "optional": true + }, + "trigger_info": { + "name": "trigger_info", + "type": "TypeMap", + "description": "trigger_info.", + "optional": true, + "computed": true + }, + "trigger_scan": { + "name": "trigger_scan", + "type": "TypeString", + "description": "Enabling trigger validation scans provides details for a pipeline task to trigger a scan.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + } + ], + "ibm_cd_toolchain_tool_slack": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "api_token": { + "name": "api_token", + "type": "TypeString", + "description": "Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead.", + "secure": true, + "required": true + }, + "channel_name": { + "name": "channel_name", + "type": "TypeString", + "description": "If you use a webhook, you must specify an existing Slack channel to post notifications to.", + "required": true + }, + "pipeline_fail": { + "name": "pipeline_fail", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "pipeline_start": { + "name": "pipeline_start", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "pipeline_success": { + "name": "pipeline_success", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "team_url": { + "name": "team_url", + "type": "TypeString", + "description": "If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_.", + "optional": true + }, + "toolchain_bind": { + "name": "toolchain_bind", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "toolchain_unbind": { + "name": "toolchain_unbind", + "type": "TypeBool", + "default_value": true, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + } + ], + "ibm_cd_toolchain_tool_sonarqube": [ + { + "name": "toolchain_id", + "type": "TypeString", + "description": "ID of the toolchain to bind the tool to.", + "immutable": true, + "required": true, + "min_length": 36, + "max_length": 36, + "matches": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource group where tool can be found.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "toolchain_crn", + "type": "TypeString", + "description": "CRN of toolchain which the tool is bound to.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Latest tool update timestamp.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Current configuration state of the tool.", + "computed": true + }, + { + "name": "tool_id", + "type": "TypeString", + "description": "Tool ID.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeList", + "description": "Unique key-value pairs representing parameters to be used to create the tool.", + "required": true, + "elem": { + "blind_connection": { + "name": "blind_connection", + "type": "TypeBool", + "description": "Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide.", + "default_value": false, + "optional": true + }, + "dashboard_url": { + "name": "dashboard_url", + "type": "TypeString", + "description": "Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain.", + "required": true + }, + "user_login": { + "name": "user_login", + "type": "TypeString", + "description": "If you are using an authentication token, leave this field empty.", + "optional": true + }, + "user_password": { + "name": "user_password", + "type": "TypeString", + "secure": true, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of tool.", + "max_length": 128, + "matches": "^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Tool CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URI representing the tool.", + "computed": true + }, + { + "name": "referent", + "type": "TypeList", + "description": "Information on URIs to access this resource through the UI or API.", + "computed": true, + "elem": { + "api_href": { + "name": "api_href", + "type": "TypeString", + "description": "URI representing the this resource through an API.", + "optional": true + }, + "ui_href": { + "name": "ui_href", + "type": "TypeString", + "description": "URI representing the this resource through the UI.", + "optional": true + } + } + } + ], + "ibm_cdn": [ + { + "name": "host_name", + "type": "TypeString", + "description": "Host name", + "immutable": true, + "required": true + }, + { + "name": "vendor_name", + "type": "TypeString", + "description": "Vendor name", + "default_value": "akamai", + "immutable": true, + "optional": true + }, + { + "name": "bucket_name", + "type": "TypeString", + "description": "Bucket name", + "optional": true + }, + { + "name": "cache_key_query_rule", + "type": "TypeString", + "description": "query rule info", + "default_value": "include-all", + "optional": true + }, + { + "name": "path", + "type": "TypeString", + "description": "Path details", + "default_value": "/*", + "immutable": true, + "optional": true + }, + { + "name": "origin_type", + "type": "TypeString", + "description": "Origin type info", + "default_value": "HOST_SERVER", + "immutable": true, + "optional": true + }, + { + "name": "origin_address", + "type": "TypeString", + "description": "origin address info", + "required": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Protocol name", + "default_value": "HTTP", + "immutable": true, + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status info of the CDN instance", + "computed": true + }, + { + "name": "performance_configuration", + "type": "TypeString", + "description": "performance configuration info", + "default_value": "General web delivery", + "immutable": true, + "optional": true + }, + { + "name": "cname", + "type": "TypeString", + "description": "cname info", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "file_extension", + "type": "TypeString", + "description": "File extension info", + "optional": true + }, + { + "name": "http_port", + "type": "TypeInt", + "description": "HTTP port number", + "default_value": 80, + "optional": true + }, + { + "name": "https_port", + "type": "TypeInt", + "description": "HTTPS port number", + "default_value": 443, + "optional": true + }, + { + "name": "header", + "type": "TypeString", + "description": "Header info", + "optional": true, + "computed": true + }, + { + "name": "respect_headers", + "type": "TypeBool", + "description": "respect headers info", + "default_value": true, + "optional": true + }, + { + "name": "certificate_type", + "type": "TypeString", + "description": "Certificate type", + "immutable": true, + "optional": true + } + ], + "ibm_certificate_manager_import": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the instance", + "required": true + }, + { + "name": "issuer", + "type": "TypeString", + "description": "certificate issuer info", + "computed": true + }, + { + "name": "begins_on", + "type": "TypeInt", + "description": "Certificate validity start date", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeInt", + "description": "certificate expiry date", + "computed": true + }, + { + "name": "imported", + "type": "TypeBool", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "algorithm", + "type": "TypeString", + "computed": true + }, + { + "name": "certificate_manager_instance_id", + "type": "TypeString", + "description": "Instance ID of the certificate manager resource", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the certificate instance", + "optional": true + }, + { + "name": "has_previous", + "type": "TypeBool", + "computed": true + }, + { + "name": "key_algorithm", + "type": "TypeString", + "computed": true + }, + { + "name": "data", + "type": "TypeMap", + "description": "certificate data", + "required": true + } + ], + "ibm_certificate_manager_order": [ + { + "name": "begins_on", + "type": "TypeInt", + "description": "Cerificate validity from date", + "computed": true + }, + { + "name": "certificate_manager_instance_id", + "type": "TypeString", + "description": "Certificate manager instance ID", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Certificate name", + "required": true + }, + { + "name": "domains", + "type": "TypeList", + "description": "List of domain names", + "immutable": true, + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "renew_certificate", + "type": "TypeBool", + "description": "Invokes renew functionality", + "default_value": false, + "optional": true + }, + { + "name": "issuer", + "type": "TypeString", + "description": "Certificate issuer info", + "computed": true + }, + { + "name": "key_algorithm", + "type": "TypeString", + "description": "Keyalgorithm info", + "default_value": "rsaEncryption 2048 bit", + "optional": true + }, + { + "name": "algorithm", + "type": "TypeString", + "description": "Algorithm info", + "computed": true + }, + { + "name": "imported", + "type": "TypeBool", + "description": "set to true if certificate is imported", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Certicate description", + "optional": true + }, + { + "name": "dns_provider_instance_crn", + "type": "TypeString", + "description": "DNS provider instance CRN", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the certificate", + "computed": true + }, + { + "name": "issuance_info", + "type": "TypeMap", + "computed": true + }, + { + "name": "has_previous", + "type": "TypeBool", + "description": "Has Previous", + "computed": true + }, + { + "name": "rotate_keys", + "type": "TypeBool", + "description": "Keys are sorated if set to true", + "default_value": false, + "optional": true + }, + { + "name": "domain_validation_method", + "type": "TypeString", + "description": "Domain validation methods", + "default_value": "dns-01", + "optional": true + }, + { + "name": "auto_renew_enabled", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + { + "name": "expires_on", + "type": "TypeInt", + "description": "Certificaet expairy date", + "computed": true + } + ], + "ibm_cis": [ + { + "name": "name", + "type": "TypeString", + "description": "A name for the resource instance", + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location where the instance available", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass. Must be a JSON object", + "immutable": true, + "optional": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of resource instance", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the service", + "required": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Unique identifier of resource instance", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the Cloud Internet Services offering", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_cis_alert": [ + { + "name": "filters", + "type": "TypeString", + "description": "Filters based on filter type", + "optional": true + }, + { + "name": "conditions", + "type": "TypeString", + "description": "Conditions based on filter type", + "optional": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "description", + "type": "TypeString", + "description": "Policy Description", + "optional": true + }, + { + "name": "mechanisms", + "type": "TypeList", + "description": "Delivery mechanisms for the alert, can include an email, a webhook, or both.", + "required": true, + "elem": { + "email": { + "name": "email", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "webhooks": { + "name": "webhooks", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "alert_type", + "type": "TypeString", + "description": "Condition for the alert", + "required": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "Identifier of the Alert Policy", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Policy name", + "required": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Is the alert policy active", + "required": true + } + ], + "ibm_cis_cache_settings": [ + { + "name": "serve_stale_content", + "type": "TypeString", + "description": "Serve Stale Content", + "default_value": "on", + "options": "on, off", + "optional": true + }, + { + "name": "browser_expiration", + "type": "TypeInt", + "description": "Browser Expiration setting", + "options": "0, 30, 60, 300, 1200, 1800, 3600, 7200, 10800, 14400,18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000,691200, 1382400, 2073600, 2678400, 5356800, 16070400, 31536000", + "optional": true, + "computed": true + }, + { + "name": "development_mode", + "type": "TypeString", + "description": "Development mode setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "query_string_sort", + "type": "TypeString", + "description": "Query String sort setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "purge_all", + "type": "TypeBool", + "description": "Purge all setting", + "optional": true + }, + { + "name": "purge_by_hosts", + "type": "TypeList", + "description": "Purge by hosts", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "purge_by_tags", + "type": "TypeList", + "description": "Purge by tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "caching_level", + "type": "TypeString", + "description": "Cache level setting", + "options": "basic, simplified, aggressive", + "optional": true, + "computed": true + }, + { + "name": "purge_by_urls", + "type": "TypeList", + "description": "Purge by URLs", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_cis_certificate_order": [ + { + "name": "hosts", + "type": "TypeList", + "description": "Hosts which certificate need to be ordered", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "status", + "type": "TypeString", + "description": "certificate status", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS object id or CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "certificate_id", + "type": "TypeString", + "description": "certificate id", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "certificate type", + "default_value": "dedicated", + "options": "dedicated", + "optional": true + } + ], + "ibm_cis_certificate_upload": [ + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "bundle_method", + "type": "TypeString", + "description": "Certificate bundle method", + "default_value": "ubiquitous", + "options": "ubiquitous, optimal, force", + "optional": true + }, + { + "name": "issuer", + "type": "TypeString", + "description": "certificate issuer", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "custom_cert_id", + "type": "TypeString", + "computed": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "Certificate key", + "secure": true, + "required": true + }, + { + "name": "hosts", + "type": "TypeList", + "description": "hosts which the certificate uploaded to", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "status", + "type": "TypeString", + "description": "certificate status", + "computed": true + }, + { + "name": "uploaded_on", + "type": "TypeString", + "description": "certificate uploaded date", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "certificate modified date", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeString", + "description": "certificate expires date", + "computed": true + }, + { + "name": "private_key", + "type": "TypeString", + "description": "Certificate private key", + "secure": true, + "required": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "Certificate priority", + "optional": true, + "computed": true + }, + { + "name": "signature", + "type": "TypeString", + "description": "certificate signature", + "computed": true + } + ], + "ibm_cis_custom_page": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "Custom page url", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Free text", + "computed": true + }, + { + "name": "required_tokens", + "type": "TypeList", + "description": "Custom page state", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "page_id", + "type": "TypeString", + "description": "Custom page identifier", + "immutable": true, + "required": true, + "options": "basic_challenge, waf_challenge, waf_block, ratelimit_block,country_challenge, ip_block, under_attack, 500_errors, 1000_errors, always_online" + }, + { + "name": "state", + "type": "TypeString", + "description": "Custom page state", + "computed": true + }, + { + "name": "preview_target", + "type": "TypeString", + "description": "Custom page preview target", + "computed": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Custom page created date", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Custom page modified date", + "computed": true + } + ], + "ibm_cis_dns_record": [ + { + "name": "ttl", + "type": "TypeInt", + "description": "TTL value", + "default_value": 1, + "optional": true + }, + { + "name": "proxiable", + "type": "TypeBool", + "computed": true + }, + { + "name": "record_id", + "type": "TypeString", + "computed": true + }, + { + "name": "zone_name", + "type": "TypeString", + "description": "zone name", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Record type", + "required": true + }, + { + "name": "content", + "type": "TypeString", + "description": "DNS record content", + "optional": true + }, + { + "name": "modified_on", + "type": "TypeString", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "DNS record name", + "optional": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "Priority Value", + "optional": true + }, + { + "name": "proxied", + "type": "TypeBool", + "description": "Boolean value true if proxied else flase", + "default_value": false, + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS object id or CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "data", + "type": "TypeMap", + "optional": true + } + ], + "ibm_cis_dns_records_import": [ + { + "name": "file", + "type": "TypeString", + "description": "File to import", + "immutable": true, + "required": true + }, + { + "name": "total_records_parsed", + "type": "TypeInt", + "description": "total records parsed", + "computed": true + }, + { + "name": "records_added", + "type": "TypeInt", + "description": "added records count", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + } + ], + "ibm_cis_domain": [ + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "name_servers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "domain", + "type": "TypeString", + "description": "CISzone - Domain", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "CISzone - Domain Type", + "default_value": "full", + "options": "full, partial", + "optional": true + }, + { + "name": "paused", + "type": "TypeBool", + "computed": true + }, + { + "name": "verification_key", + "type": "TypeString", + "computed": true + }, + { + "name": "cname_suffix", + "type": "TypeString", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "original_name_servers", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "domain_id", + "type": "TypeString", + "computed": true + } + ], + "ibm_cis_domain_settings": [ + { + "name": "opportunistic_encryption", + "type": "TypeString", + "description": "opportunistic_encryption setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "ipv6", + "type": "TypeString", + "description": "ipv6 setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "true_client_ip_header", + "type": "TypeString", + "description": "true_client_ip_header setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "image_size_optimization", + "type": "TypeString", + "description": "image_size_optimization setting", + "optional": true, + "computed": true + }, + { + "name": "prefetch_preload", + "type": "TypeString", + "description": "prefetch_preload setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "tls_client_auth", + "type": "TypeString", + "description": "tls_client_auth setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "waf", + "type": "TypeString", + "description": "WAF setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "ip_geolocation", + "type": "TypeString", + "description": "ip_geolocation setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "security_header", + "type": "TypeList", + "description": "Security Header Setting", + "optional": true, + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "security header enabled/disabled", + "required": true + }, + "include_subdomains": { + "name": "include_subdomains", + "type": "TypeBool", + "description": "security header subdomain included or not", + "required": true + }, + "max_age": { + "name": "max_age", + "type": "TypeInt", + "description": "security header max age", + "required": true + }, + "nosniff": { + "name": "nosniff", + "type": "TypeBool", + "description": "security header no sniff", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "max_upload", + "type": "TypeInt", + "description": "Maximum upload", + "options": "100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500", + "optional": true, + "computed": true + }, + { + "name": "minify", + "type": "TypeList", + "description": "Minify setting", + "optional": true, + "computed": true, + "elem": { + "css": { + "name": "css", + "type": "TypeString", + "description": "Minify CSS setting", + "required": true + }, + "html": { + "name": "html", + "type": "TypeString", + "description": "Minify HTML setting", + "required": true + }, + "js": { + "name": "js", + "type": "TypeString", + "description": "Minify JS setting", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "min_tls_version", + "type": "TypeString", + "description": "Minimum version of TLS required", + "default_value": "1.1", + "optional": true + }, + { + "name": "hotlink_protection", + "type": "TypeString", + "description": "hotlink_protection setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "origin_error_page_pass_thru", + "type": "TypeString", + "description": "origin_error_page_pass_thru setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "script_load_optimization", + "type": "TypeString", + "description": "script_load_optimization setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "challenge_ttl", + "type": "TypeInt", + "description": "Challenge TTL setting", + "options": "300, 900, 1800, 2700, 3600, 7200, 10800, 14400, 28800, 57600, 86400, 604800, 2592000, 31536000", + "optional": true, + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "dnssec", + "type": "TypeString", + "description": "DNS Sec setting", + "options": "active, disabled", + "optional": true, + "computed": true + }, + { + "name": "certificate_status", + "type": "TypeString", + "description": "Certificate status", + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "http2", + "type": "TypeString", + "description": "http2 setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "image_load_optimization", + "type": "TypeString", + "description": "image_load_optimization setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "automatic_https_rewrites", + "type": "TypeString", + "description": "automatic_https_rewrites setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "cipher", + "type": "TypeSet", + "description": "Cipher settings", + "options": "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305, ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-CHACHA20-POLY1305, ECDHE-ECDSA-AES128-SHA256, ECDHE-ECDSA-AES128-SHA, ECDHE-RSA-AES128-SHA256, ECDHE-RSA-AES128-SHA, AES128-GCM-SHA256, AES128-SHA256, AES128-SHA, ECDHE-ECDSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-SHA384, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA, AES256-GCM-SHA384, AES256-SHA256, AES256-SHA, DES-CBC3-SHA, AEAD-AES128-GCM-SHA256, AEAD-AES256-GCM-SHA384, AEAD-CHACHA20-POLY1305-SHA256", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "mobile_redirect", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "mobile_subdomain": { + "name": "mobile_subdomain", + "type": "TypeString", + "description": "Mobile redirect subdomain", + "optional": true, + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "mobile redirect status", + "required": true + }, + "strip_uri": { + "name": "strip_uri", + "type": "TypeBool", + "description": "mobile redirect strip URI", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "response_buffering", + "type": "TypeString", + "description": "response_buffering setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "server_side_exclude", + "type": "TypeString", + "description": "server_side_exclude setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "websockets", + "type": "TypeString", + "description": "websockets setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "cname_flattening", + "type": "TypeString", + "description": "cname_flattening setting", + "optional": true, + "computed": true + }, + { + "name": "always_use_https", + "type": "TypeString", + "description": "always_use_https setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "browser_check", + "type": "TypeString", + "description": "browser_check setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "brotli", + "type": "TypeString", + "description": "brotli setting", + "options": "on, off", + "optional": true, + "computed": true + }, + { + "name": "pseudo_ipv4", + "type": "TypeString", + "description": "pseudo_ipv4 setting", + "optional": true, + "computed": true + }, + { + "name": "ssl", + "type": "TypeString", + "description": "SSL/TLS setting", + "optional": true, + "computed": true + } + ], + "ibm_cis_edge_functions_action": [ + { + "name": "action_name", + "type": "TypeString", + "description": "Edge function action script name", + "immutable": true, + "required": true + }, + { + "name": "script", + "type": "TypeString", + "description": "Edge function action script", + "required": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + } + ], + "ibm_cis_edge_functions_trigger": [ + { + "name": "action_name", + "type": "TypeString", + "description": "Edge function trigger action name", + "optional": true + }, + { + "name": "request_limit_fail_open", + "type": "TypeBool", + "description": "Edge function trigger request limit fail open", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "trigger_id", + "type": "TypeString", + "description": "CIS Edge Functions trigger route ID", + "computed": true + }, + { + "name": "pattern_url", + "type": "TypeString", + "description": "Edge function trigger pattern", + "required": true + } + ], + "ibm_cis_filter": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "paused", + "type": "TypeBool", + "description": "Filter Paused", + "optional": true + }, + { + "name": "filter_id", + "type": "TypeString", + "description": "Filter ID", + "computed": true + }, + { + "name": "expression", + "type": "TypeString", + "description": "Filter Expression", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Filter Description", + "options": "Filter-creation", + "optional": true + } + ], + "ibm_cis_firewall": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS object id", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "immutable": true, + "required": true + }, + { + "name": "firewall_type", + "type": "TypeString", + "description": "Type of firewall.Allowable values are access-rules,ua-rules,lockdowns", + "immutable": true, + "required": true, + "options": "access_rules, ua_rules, lockdowns" + }, + { + "name": "lockdown", + "type": "TypeList", + "description": "Lockdown Data", + "optional": true, + "elem": { + "configurations": { + "name": "configurations", + "type": "TypeList", + "required": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "required": true + } + }, + "min_items": 1 + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description", + "optional": true + }, + "lockdown_id": { + "name": "lockdown_id", + "type": "TypeString", + "description": "firewall identifier", + "computed": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Firewall rule paused or enabled", + "optional": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "Firewall priority", + "optional": true + }, + "urls": { + "name": "urls", + "type": "TypeList", + "description": "URL in which firewall rule is applied", + "required": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1 + }, + { + "name": "access_rule", + "type": "TypeList", + "description": "Access Rule Data", + "optional": true, + "elem": { + "access_rule_id": { + "name": "access_rule_id", + "type": "TypeString", + "description": "access rule firewall identifier", + "computed": true + }, + "configuration": { + "name": "configuration", + "type": "TypeList", + "required": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "immutable": true, + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "Access rule mode", + "required": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "description": "description", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "ua_rule", + "type": "TypeList", + "description": "User Agent Rule Data", + "optional": true, + "elem": { + "configuration": { + "name": "configuration", + "type": "TypeList", + "required": true, + "elem": { + "target": { + "name": "target", + "type": "TypeString", + "description": "Target type", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Target value", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "description", + "optional": true + }, + "mode": { + "name": "mode", + "type": "TypeString", + "description": "user agent rule mode", + "required": true + }, + "paused": { + "name": "paused", + "type": "TypeBool", + "description": "Rule whether paused or not", + "optional": true + }, + "ua_rule_id": { + "name": "ua_rule_id", + "type": "TypeString", + "description": "User Agent firewall identifier", + "computed": true + } + }, + "max_items": 1 + } + ], + "ibm_cis_firewall_rule": [ + { + "name": "priority", + "type": "TypeInt", + "description": "Firewallrules Action", + "optional": true, + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Firewallrules Description", + "optional": true + }, + { + "name": "paused", + "type": "TypeBool", + "description": "Firewallrules Paused", + "optional": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "required": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "filter_id", + "type": "TypeString", + "description": "Firewallrules Existing FilterID", + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "Firewallrules Action", + "required": true + } + ], + "ibm_cis_global_load_balancer": [ + { + "name": "session_affinity", + "type": "TypeString", + "description": "Session affinity info", + "default_value": "none", + "optional": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "set to true of LB needs to enabled", + "default_value": true, + "optional": true + }, + { + "name": "region_pools", + "type": "TypeSet", + "optional": true, + "elem": { + "pool_ids": { + "name": "pool_ids", + "type": "TypeList", + "required": true, + "elem": { + "type": "TypeString" + } + }, + "region": { + "name": "region", + "type": "TypeString", + "required": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "name", + "type": "TypeString", + "description": "name", + "required": true + }, + { + "name": "steering_policy", + "type": "TypeString", + "description": "Steering policy info", + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Load balancer creation date", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description for the load balancer instance", + "optional": true + }, + { + "name": "ttl", + "type": "TypeInt", + "description": "TTL value", + "default_value": 60, + "optional": true + }, + { + "name": "fallback_pool_id", + "type": "TypeString", + "description": "fallback pool ID", + "required": true + }, + { + "name": "proxied", + "type": "TypeBool", + "description": "set to true if proxy needs to be enabled", + "default_value": false, + "optional": true + }, + { + "name": "default_pool_ids", + "type": "TypeSet", + "description": "List of default Pool IDs", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pop_pools", + "type": "TypeSet", + "optional": true, + "elem": { + "pool_ids": { + "name": "pool_ids", + "type": "TypeList", + "required": true, + "elem": { + "type": "TypeString" + } + }, + "pop": { + "name": "pop", + "type": "TypeString", + "description": "pop pools region", + "required": true + } + } + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Load balancer modified date", + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "glb_id", + "type": "TypeString", + "description": "global load balancer id", + "computed": true + } + ], + "ibm_cis_healthcheck": [ + { + "name": "allow_insecure", + "type": "TypeBool", + "description": "allow_insecure", + "default_value": false, + "optional": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "port number", + "min_value": "1", + "max_value": "65535", + "optional": true, + "computed": true + }, + { + "name": "method", + "type": "TypeString", + "description": "method", + "default_value": "GET", + "options": "GET, HEAD", + "optional": true + }, + { + "name": "path", + "type": "TypeString", + "description": "path", + "default_value": "/", + "optional": true + }, + { + "name": "expected_body", + "type": "TypeString", + "description": "expected_body", + "optional": true + }, + { + "name": "headers", + "type": "TypeSet", + "optional": true, + "elem": { + "header": { + "name": "header", + "type": "TypeString", + "required": true + }, + "values": { + "name": "values", + "type": "TypeSet", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "monitor_id", + "type": "TypeString", + "description": "GLB Monitor/Health check id", + "computed": true + }, + { + "name": "expected_codes", + "type": "TypeString", + "description": "expected_codes", + "optional": true + }, + { + "name": "interval", + "type": "TypeInt", + "description": "interval", + "default_value": 60, + "min_value": "5", + "max_value": "3600", + "optional": true + }, + { + "name": "follow_redirects", + "type": "TypeBool", + "description": "follow_redirects", + "default_value": false, + "optional": true + }, + { + "name": "create_on", + "type": "TypeString", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "type", + "type": "TypeString", + "description": "type", + "default_value": "http", + "options": "http, https, tcp", + "optional": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "timeout", + "default_value": 5, + "min_value": "1", + "max_value": "10", + "optional": true + }, + { + "name": "retries", + "type": "TypeInt", + "description": "retries", + "default_value": 2, + "min_value": "1", + "max_value": "3", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "description", + "default_value": " ", + "optional": true + } + ], + "ibm_cis_logpush_job": [ + { + "name": "destination_conf", + "type": "TypeString", + "description": "Uniquely identifies a resource (such as an s3 bucket) where data will be pushed.", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "logdna", + "type": "TypeString", + "description": "Information to identify the LogDNA instance the data will be pushed.", + "secure": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Logpush Job Name", + "optional": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the logpush job enabled or not", + "optional": true + }, + { + "name": "dataset", + "type": "TypeString", + "description": "Dataset to be pulled", + "required": true + }, + { + "name": "job_id", + "type": "TypeInt", + "description": "Associated CIS domain", + "computed": true + }, + { + "name": "logpull_options", + "type": "TypeString", + "description": "Configuration string", + "optional": true + }, + { + "name": "frequency", + "type": "TypeString", + "description": "The frequency at which CIS sends batches of logs to your destination", + "optional": true + } + ], + "ibm_cis_mtls": [ + { + "name": "created_at", + "type": "TypeString", + "description": "Certificate Created At", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Certificate Updated At", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeString", + "description": "Certificate Expires on", + "computed": true + }, + { + "name": "id", + "type": "TypeString", + "description": "Certificate ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Certificate name", + "required": true + }, + { + "name": "associated_hostnames", + "type": "TypeList", + "description": "Host name list to be associated", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "mtls_id", + "type": "TypeString", + "description": "Mtls transaction ID", + "computed": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "Certificate contents", + "secure": true, + "required": true + } + ], + "ibm_cis_mtls_app": [ + { + "name": "common_rule_val", + "type": "TypeString", + "description": "Policy common rule value", + "optional": true + }, + { + "name": "pol_created_at", + "type": "TypeString", + "description": "Policy Created At", + "computed": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "Policy ID", + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "Associated host domain value", + "required": true + }, + { + "name": "session_duration", + "type": "TypeString", + "description": "Duration for app validatidity", + "default_value": "24h", + "optional": true + }, + { + "name": "policy_name", + "type": "TypeString", + "description": "Policy Name", + "default_value": "mtls-policy", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "App Name", + "required": true + }, + { + "name": "app_updated_at", + "type": "TypeString", + "description": "Certificate Updated At", + "computed": true + }, + { + "name": "pol_updated_at", + "type": "TypeString", + "description": "Policy updated At", + "computed": true + }, + { + "name": "policy_decision", + "type": "TypeString", + "description": "Policy Action", + "default_value": "non_identity", + "optional": true + }, + { + "name": "app_created_at", + "type": "TypeString", + "description": "Certificate Created At", + "computed": true + }, + { + "name": "app_id", + "type": "TypeString", + "description": "APP ID", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "cert_rule_val", + "type": "TypeString", + "description": "Policy certificate rule value", + "default_value": "CA root certificate", + "optional": true + } + ], + "ibm_cis_origin_auth": [ + { + "name": "certificate", + "type": "TypeString", + "description": "Certificate content which needs to be uploaded", + "secure": true, + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Authentication status whether active or not", + "computed": true + }, + { + "name": "cert_id", + "type": "TypeString", + "description": "Certificate ID which is uploaded", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeString", + "description": "Certificate expires on", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "level", + "type": "TypeString", + "description": "Origin auth level zone or hostname", + "required": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Host name needed for host level authentication", + "optional": true + }, + { + "name": "uploaded_on", + "type": "TypeString", + "description": "Certificate uploaded on", + "computed": true + }, + { + "name": "auth_id", + "type": "TypeString", + "description": "Associated CIS auth pull job id", + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Enabel-disable origin auth for a zone or host", + "default_value": true, + "optional": true + }, + { + "name": "private_key", + "type": "TypeString", + "description": "Private key content which needs to be uploaded", + "secure": true, + "required": true + } + ], + "ibm_cis_origin_pool": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "name", + "type": "TypeString", + "description": "name", + "required": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Boolean value set to true if cis origin pool needs to be enabled", + "required": true + }, + { + "name": "monitor", + "type": "TypeString", + "description": "Monitor value", + "optional": true + }, + { + "name": "notification_email", + "type": "TypeString", + "description": "Email address configured to recieve the notifications", + "optional": true + }, + { + "name": "origins", + "type": "TypeSet", + "description": "Origins info", + "required": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "required": true + }, + "disabled_at": { + "name": "disabled_at", + "type": "TypeString", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "required": true + }, + "failure_reason": { + "name": "failure_reason", + "type": "TypeString", + "computed": true + }, + "healthy": { + "name": "healthy", + "type": "TypeBool", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "required": true + }, + "weight": { + "name": "weight", + "type": "TypeFloat", + "default_value": 1, + "optional": true + } + } + }, + { + "name": "pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "check_regions", + "type": "TypeSet", + "description": "List of regions", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health", + "type": "TypeString", + "description": "Health info", + "computed": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Creation date info", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Modified date info", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the CIS Origin Pool", + "optional": true + }, + { + "name": "minimum_origins", + "type": "TypeInt", + "description": "Minimum number of Origins", + "default_value": 1, + "optional": true + }, + { + "name": "healthy", + "type": "TypeBool", + "description": "Health status", + "computed": true + } + ], + "ibm_cis_page_rule": [ + { + "name": "id", + "type": "TypeString", + "description": "Id of the ibm_cis_page_rule", + "computed": true + }, + { + "name": "rule_id", + "type": "TypeString", + "computed": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "Page rule priority", + "default_value": 1, + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Page Rule status", + "default_value": "disabled", + "options": "active, disabled", + "optional": true + }, + { + "name": "targets", + "type": "TypeSet", + "description": "Page rule targets", + "required": true, + "elem": { + "constraint": { + "name": "constraint", + "type": "TypeList", + "description": "Page rule constraint", + "required": true, + "elem": { + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Constraint operator", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Constraint value", + "required": true + } + }, + "max_items": 1 + }, + "target": { + "name": "target", + "type": "TypeString", + "description": "Page rule target url", + "required": true + } + } + }, + { + "name": "actions", + "type": "TypeSet", + "description": "Page rule actions", + "required": true, + "elem": { + "css": { + "name": "css", + "type": "TypeString", + "description": "Minify CSS value", + "optional": true + }, + "html": { + "name": "html", + "type": "TypeString", + "description": "Minify HTML value", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Page rule target url", + "required": true + }, + "js": { + "name": "js", + "type": "TypeString", + "description": "Minify JS value", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeInt", + "description": "Page rule actions status code", + "optional": true + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "Page rule actions value url", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Page rule target url", + "optional": true + } + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + } + ], + "ibm_cis_range_app": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "dns", + "type": "TypeString", + "description": "Name of the DNS record for this application", + "required": true + }, + { + "name": "dns_type", + "type": "TypeString", + "description": "Type of the DNS record for this application", + "required": true + }, + { + "name": "origin_direct", + "type": "TypeList", + "description": "IP address and port of the origin for this Range application.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "edge_ips_type", + "type": "TypeString", + "description": "The type of edge IP configuration.", + "default_value": "dynamic", + "options": "dynamic", + "optional": true + }, + { + "name": "app_id", + "type": "TypeString", + "description": "Application identifier", + "computed": true + }, + { + "name": "ip_firewall", + "type": "TypeBool", + "description": "Enables the IP Firewall for this application. Only available for TCP applications.", + "optional": true + }, + { + "name": "proxy_protocol", + "type": "TypeString", + "description": "Allows for the true client IP to be passed to the service.", + "options": "off, v1, v2, simple", + "optional": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "origin_dns", + "type": "TypeString", + "description": "DNS record pointing to the origin for this Range application.", + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "created on date", + "computed": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Defines the protocol and port for this application", + "required": true + }, + { + "name": "origin_port", + "type": "TypeInt", + "description": "Port at the origin that listens to traffic", + "optional": true + }, + { + "name": "edge_ips_connectivity", + "type": "TypeString", + "description": "Specifies the IP version.", + "default_value": "all", + "options": "ipv4, ipv6, all", + "optional": true + }, + { + "name": "traffic_type", + "type": "TypeString", + "description": "Configure how traffic is handled at the edge.", + "default_value": "direct", + "options": "direct, http, https", + "optional": true + }, + { + "name": "tls", + "type": "TypeString", + "description": "Configure if and how TLS connections are terminated at the edge.", + "default_value": "off", + "options": "off, flexible, full, strict", + "optional": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "modified on date", + "computed": true + } + ], + "ibm_cis_rate_limit": [ + { + "name": "disabled", + "type": "TypeBool", + "description": "Whether this rate limiting rule is currently disabled.", + "default_value": false, + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "A note that you can use to describe the reason for a rate limiting rule.", + "max_length": 1024, + "optional": true + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "Rate Limit rule Id", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "period", + "type": "TypeInt", + "description": "Rate Limiting Period", + "required": true, + "min_value": "1", + "max_value": "86400" + }, + { + "name": "correlate", + "type": "TypeList", + "description": "Ratelimiting Correlate", + "optional": true, + "elem": { + "by": { + "name": "by", + "type": "TypeString", + "description": "Whether to enable NAT based rate limiting", + "default_value": "nat", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "action", + "type": "TypeList", + "description": "Rate Limiting Action", + "required": true, + "elem": { + "mode": { + "name": "mode", + "type": "TypeString", + "description": "Type of action performed.Valid values are: 'simulate', 'ban', 'challenge', 'js_challenge'.", + "required": true + }, + "response": { + "name": "response", + "type": "TypeList", + "description": "Rate Limiting Action Response", + "optional": true, + "elem": { + "body": { + "name": "body", + "type": "TypeString", + "description": "The body to return. The content here must confirm to the 'content_type'", + "required": true + }, + "content_type": { + "name": "content_type", + "type": "TypeString", + "description": "Custom content-type and body to return. It must be one of following 'text/plain', 'text/xml', 'application/json'.", + "required": true + } + }, + "max_items": 1 + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The time to perform the mitigation action. Timeout be the same or greater than the period.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "match", + "type": "TypeList", + "description": "Rate Limiting Match", + "optional": true, + "computed": true, + "elem": { + "request": { + "name": "request", + "type": "TypeList", + "description": "Rate Limiting Match Request", + "optional": true, + "computed": true, + "elem": { + "methods": { + "name": "methods", + "type": "TypeSet", + "description": "HTTP Methos of matching request. It can be one or many. Example methods 'POST', 'PUT'", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "schemes": { + "name": "schemes", + "type": "TypeSet", + "description": "HTTP Schemes of matching request. It can be one or many. Example schemes 'HTTP', 'HTTPS'.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL pattern of matching request", + "optional": true, + "computed": true + } + }, + "max_items": 1, + "min_items": 1 + }, + "response": { + "name": "response", + "type": "TypeList", + "description": "Rate Limiting Response", + "optional": true, + "elem": { + "headers": { + "name": "headers", + "type": "TypeList", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the response header to match.", + "optional": true + }, + "op": { + "name": "op", + "type": "TypeString", + "description": "The operator when matching. Valid values are 'eq' and 'ne'.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value of the header, which is exactly matched.", + "optional": true + } + } + }, + "origin_traffic": { + "name": "origin_traffic", + "type": "TypeBool", + "description": "Origin Traffic of matching response.", + "optional": true + }, + "status": { + "name": "status", + "type": "TypeSet", + "description": "HTTP Status Codes of matching response. It can be one or many. Example status codes '403', '401", + "optional": true, + "elem": { + "type": "TypeInt" + } + } + }, + "max_items": 1, + "min_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "bypass", + "type": "TypeList", + "description": "Bypass URL", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "bypass URL name", + "default_value": "url", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "bypass URL value", + "optional": true + } + } + }, + { + "name": "threshold", + "type": "TypeInt", + "description": "Rate Limiting Threshold", + "required": true, + "min_value": "1", + "max_value": "1000000" + } + ], + "ibm_cis_routing": [ + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "smart_routing", + "type": "TypeString", + "description": "Smart Routing value", + "options": "on, off", + "optional": true, + "computed": true + } + ], + "ibm_cis_tls_settings": [ + { + "name": "min_tls_version", + "type": "TypeString", + "description": "Minimum version of TLS required", + "default_value": "1.1", + "options": "1.1, 1.2, 1.3, 1.4", + "optional": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "Associated CIS domain", + "required": true + }, + { + "name": "universal_ssl", + "type": "TypeBool", + "description": "Universal SSL setting", + "optional": true, + "computed": true + }, + { + "name": "tls_1_3", + "type": "TypeString", + "description": "TLS 1.3 setting", + "options": "on, off, zrt", + "optional": true, + "computed": true + } + ], + "ibm_cis_waf_group": [ + { + "name": "description", + "type": "TypeString", + "description": "WAF Rule group description", + "computed": true + }, + { + "name": "modified_rules_count", + "type": "TypeInt", + "description": "WAF Rule group modified rules count", + "computed": true + }, + { + "name": "check_mode", + "type": "TypeBool", + "description": "Check Mode before making a create/update request", + "default_value": false, + "optional": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "mode", + "type": "TypeString", + "description": "WAF Rule group mode on/off", + "required": true, + "options": "on, off" + }, + { + "name": "group_id", + "type": "TypeString", + "description": "WAF Rule group id", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "WAF Rule group name", + "computed": true + }, + { + "name": "rules_count", + "type": "TypeInt", + "description": "WAF Rule group rules count", + "computed": true + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "package_id", + "type": "TypeString", + "description": "WAF Rule package id", + "required": true + } + ], + "ibm_cis_waf_package": [ + { + "name": "name", + "type": "TypeString", + "description": "WAF pakcage name", + "computed": true + }, + { + "name": "detection_mode", + "type": "TypeString", + "description": "WAF pakcage detection mode", + "computed": true + }, + { + "name": "sensitivity", + "type": "TypeString", + "description": "WAF pakcage sensitivity", + "required": true, + "options": "high, medium, low, off" + }, + { + "name": "action_mode", + "type": "TypeString", + "description": "WAF pakcage action mode", + "required": true, + "options": "simulate, block, challenge" + }, + { + "name": "description", + "type": "TypeString", + "description": "WAF package description", + "computed": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "package_id", + "type": "TypeString", + "description": "WAF pakcage ID", + "immutable": true, + "required": true + } + ], + "ibm_cis_waf_rule": [ + { + "name": "domain_id", + "type": "TypeString", + "description": "CIS Domain ID", + "required": true + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "CIS WAF Rule id", + "immutable": true, + "required": true + }, + { + "name": "package_id", + "type": "TypeString", + "description": "CIS WAF Rule package id", + "immutable": true, + "required": true + }, + { + "name": "mode", + "type": "TypeString", + "description": "CIS WAF Rule mode", + "required": true, + "options": "on, off, default, disable, simulate, block, challenge" + }, + { + "name": "priority", + "type": "TypeInt", + "description": "CIS WAF Rule Priority", + "computed": true + }, + { + "name": "allowed_modes", + "type": "TypeString", + "description": "CIS WAF Rule allowed modes", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS Intance CRN", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + }, + { + "name": "description", + "type": "TypeString", + "description": "CIS WAF Rule descriptions", + "computed": true + }, + { + "name": "group", + "type": "TypeList", + "description": "CIS WAF Rule group", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "waf rule group id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "waf rule group name", + "computed": true + } + } + } + ], + "ibm_cis_webhook": [ + { + "name": "webhook_id", + "type": "TypeString", + "description": "Webhook ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Webhook Name", + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "Webhook URL", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Webhook Type", + "computed": true + }, + { + "name": "secret", + "type": "TypeString", + "description": "API key needed to use the webhook", + "secure": true, + "optional": true + }, + { + "name": "cis_id", + "type": "TypeString", + "description": "CIS instance crn", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:internet-svcs" + ] + } + ], + "ibm_cloud_shell_account_settings": [ + { + "name": "type", + "type": "TypeString", + "description": "Type of api response object.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeInt", + "description": "Timestamp of last update in Unix epoch time.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The account ID in which the account settings belong to.", + "immutable": true, + "required": true + }, + { + "name": "rev", + "type": "TypeString", + "description": "Unique revision number for the settings object.", + "optional": true, + "computed": true + }, + { + "name": "default_enable_new_regions", + "type": "TypeBool", + "description": "Set whether Cloud Shell is enabled in a specific location for the account. The location determines where user and session data are stored. By default, users are routed to the nearest available location.", + "optional": true + }, + { + "name": "regions", + "type": "TypeList", + "description": "List of Cloud Shell region settings.", + "optional": true, + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "State of the region.", + "optional": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Name of the region.", + "optional": true + } + } + }, + { + "name": "created_by", + "type": "TypeString", + "description": "IAM ID of creator.", + "computed": true + }, + { + "name": "default_enable_new_features", + "type": "TypeBool", + "description": "You can choose which Cloud Shell features are available in the account and whether any new features are enabled as they become available. The feature settings apply only to the enabled Cloud Shell locations.", + "optional": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "When enabled, Cloud Shell is available to all users in the account.", + "optional": true + }, + { + "name": "features", + "type": "TypeList", + "description": "List of Cloud Shell features.", + "optional": true, + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "State of the feature.", + "optional": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Name of the feature.", + "optional": true + } + } + }, + { + "name": "created_at", + "type": "TypeInt", + "description": "Creation timestamp in Unix epoch time.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "IAM ID of last updater.", + "computed": true + } + ], + "ibm_cloudant": [ + { + "name": "parameters_json", + "type": "TypeString", + "description": "Arbitrary parameters to pass in Json string format", + "optional": true + }, + { + "name": "update_at", + "type": "TypeString", + "description": "The date when the instance was last updated.", + "computed": true + }, + { + "name": "restored_at", + "type": "TypeString", + "description": "The date when the instance under reclamation was restored.", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "throughput", + "type": "TypeMap", + "description": "Schema for detailed information about throughput capacity with breakdown by specific throughput requests classes.", + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "restored_by", + "type": "TypeString", + "description": "The subject who restored the instance back from reclamation.", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location where the instance available", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + "computed": true + }, + { + "name": "resource_aliases_url", + "type": "TypeString", + "description": "The relative path to the resource aliases for the instance.", + "computed": true + }, + { + "name": "scheduled_reclaim_by", + "type": "TypeString", + "description": "The subject who initiated the instance reclamation.", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "cors_config", + "type": "TypeList", + "description": "Configuration for CORS.", + "optional": true, + "elem": { + "allow_credentials": { + "name": "allow_credentials", + "type": "TypeBool", + "description": "Boolean value to allow authentication credentials. If set to true, browser requests must be done by using withCredentials = true.", + "default_value": true, + "optional": true + }, + "origins": { + "name": "origins", + "type": "TypeList", + "description": "An array of strings that contain allowed origin domains. You have to specify the full URL including the protocol. It is recommended that only the HTTPS protocol is used. Subdomains count as separate domains, so you have to specify all subdomains used.", + "required": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass. Must be a JSON object", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of resource instance", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of the instance, e.g. service_instance.", + "computed": true + }, + { + "name": "last_operation", + "type": "TypeMap", + "description": "The status of the last operation requested on the instance", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The subject who created the instance.", + "computed": true + }, + { + "name": "include_data_events", + "type": "TypeBool", + "description": "Include data event types in events sent to IBM Cloud Activity Tracker with LogDNA for the IBM Cloudant instance. By default only emitted events are of \"management\" type.", + "default_value": false, + "optional": true + }, + { + "name": "enable_cors", + "type": "TypeBool", + "description": "Boolean value to turn CORS on and off.", + "default_value": true, + "optional": true + }, + { + "name": "service_endpoints", + "type": "TypeString", + "description": "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", + "optional": true, + "computed": true + }, + { + "name": "plan_history", + "type": "TypeList", + "description": "The plan history of the instance.", + "computed": true, + "elem": { + "resource_plan_id": { + "name": "resource_plan_id", + "type": "TypeString", + "computed": true + }, + "start_date": { + "name": "start_date", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "sub_type", + "type": "TypeString", + "description": "The sub-type of instance, e.g. cfaas .", + "computed": true + }, + { + "name": "update_by", + "type": "TypeString", + "description": "The subject who updated the instance.", + "computed": true + }, + { + "name": "legacy_credentials", + "type": "TypeBool", + "description": "Use both legacy credentials and IAM for authentication", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "resource_plan_id", + "type": "TypeString", + "description": "The unique ID of the plan associated with the offering", + "computed": true + }, + { + "name": "target_crn", + "type": "TypeString", + "description": "The full deployment CRN as defined in the global catalog", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The current state of the instance.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A name for the resource instance", + "required": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The service type of the instance", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the service", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_id", + "type": "TypeString", + "description": "The unique ID of the offering", + "computed": true + }, + { + "name": "allow_cleanup", + "type": "TypeBool", + "description": "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the instance was created.", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "environment_crn", + "type": "TypeString", + "description": "CRN of the IBM Cloudant Dedicated Hardware plan instance", + "immutable": true, + "optional": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of resource instance", + "computed": true + }, + { + "name": "resource_group_crn", + "type": "TypeString", + "description": "The long ID (full CRN) of the resource group", + "computed": true + }, + { + "name": "deleted_at", + "type": "TypeString", + "description": "The date when the instance was deleted.", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the resource instance.", + "computed": true + }, + { + "name": "scheduled_reclaim_at", + "type": "TypeString", + "description": "The date when the instance was scheduled for reclamation.", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "A number of blocks of throughput units. A block consists of 100 reads/sec, 50 writes/sec, and 5 global queries/sec of provisioned throughput capacity.", + "default_value": 1, + "optional": true + }, + { + "name": "dashboard_url", + "type": "TypeString", + "description": "Dashboard URL to access resource.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "An alpha-numeric value identifying the account ID.", + "computed": true + }, + { + "name": "resource_bindings_url", + "type": "TypeString", + "description": "The relative path to the resource bindings for the instance.", + "computed": true + }, + { + "name": "resource_keys_url", + "type": "TypeString", + "description": "The relative path to the resource keys for the instance.", + "computed": true + }, + { + "name": "deleted_by", + "type": "TypeString", + "description": "The subject who deleted the instance.", + "computed": true + } + ], + "ibm_cloudant_database": [ + { + "name": "instance_crn", + "type": "TypeString", + "description": "Cloudant Instance CRN.", + "immutable": true, + "required": true + }, + { + "name": "db", + "type": "TypeString", + "description": "Path parameter to specify the database name.", + "immutable": true, + "required": true + }, + { + "name": "partitioned", + "type": "TypeBool", + "description": "Query parameter to specify whether to enable database partitions when creating a database.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "shards", + "type": "TypeInt", + "description": "The number of shards in the database. Each shard is a partition of the hash value range. You are encouraged to talk to support about appropriate values before changing this.", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_cm_catalog": [ + { + "name": "catalog_icon_url", + "type": "TypeString", + "description": "URL for an icon associated with this catalog.", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "List of tags associated with this catalog.", + "cloud_data_type": "tags", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "url", + "type": "TypeString", + "description": "The url for this specific catalog.", + "computed": true + }, + { + "name": "offerings_url", + "type": "TypeString", + "description": "URL path to offerings.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource Group ID", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "kind", + "type": "TypeString", + "description": "Kind of catalog, offering or vpe.", + "default_value": "offering", + "immutable": true, + "optional": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Display Name in the requested language.", + "immutable": true, + "required": true + }, + { + "name": "short_description", + "type": "TypeString", + "description": "Description in the requested language.", + "immutable": true, + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN associated with the catalog.", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_cm_offering": [ + { + "name": "crn", + "type": "TypeString", + "description": "The crn for this specific offering.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "ibm_publish_approved", + "type": "TypeBool", + "description": "Indicates if this offering has been approved for use by all IBMers.", + "computed": true + }, + { + "name": "disclaimer", + "type": "TypeString", + "description": "A disclaimer for this offering.", + "computed": true + }, + { + "name": "repo_info", + "type": "TypeList", + "description": "Repository info for offerings.", + "computed": true, + "elem": { + "token": { + "name": "token", + "type": "TypeString", + "description": "Token for private repos.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Public or enterprise GitHub.", + "computed": true + } + } + }, + { + "name": "offering_icon_url", + "type": "TypeString", + "description": "URL for an icon associated with this offering.", + "computed": true + }, + { + "name": "short_description", + "type": "TypeString", + "description": "Short description in the requested language.", + "computed": true + }, + { + "name": "public_publish_approved", + "type": "TypeBool", + "description": "Indicates if this offering has been approved for use by all IBM Cloud users.", + "computed": true + }, + { + "name": "portal_ui_url", + "type": "TypeString", + "description": "The portal UI URL.", + "computed": true + }, + { + "name": "hidden", + "type": "TypeBool", + "description": "Determine if this offering should be displayed in the Consumption UI.", + "computed": true + }, + { + "name": "public_original_crn", + "type": "TypeString", + "description": "The original offering CRN that this publish entry came from.", + "computed": true + }, + { + "name": "portal_approval_record", + "type": "TypeString", + "description": "The portal's approval record ID.", + "computed": true + }, + { + "name": "catalog_name", + "type": "TypeString", + "description": "The name of the catalog.", + "computed": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The url for this specific offering.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The programmatic name of this offering.", + "computed": true + }, + { + "name": "offering_docs_url", + "type": "TypeString", + "description": "URL for an additional docs with this offering.", + "computed": true + }, + { + "name": "long_description", + "type": "TypeString", + "description": "Long description in the requested language.", + "computed": true + }, + { + "name": "permit_request_ibm_public_publish", + "type": "TypeBool", + "description": "Is it permitted to request publishing to IBM or Public.", + "computed": true + }, + { + "name": "catalog_id", + "type": "TypeString", + "description": "The id of the catalog containing this offering.", + "immutable": true, + "required": true + }, + { + "name": "offering_id", + "type": "TypeString", + "description": "The id of the catalog containing this offering.", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Display Name in the requested language.", + "immutable": true, + "required": true + }, + { + "name": "offering_support_url", + "type": "TypeString", + "description": "URL to be displayed in the Consumption UI for getting support on this offering.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "List of tags associated with this catalog.", + "cloud_data_type": "tags", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "publish_public_crn", + "type": "TypeString", + "description": "The crn of the public catalog entry of this offering.", + "computed": true + } + ], + "ibm_cm_offering_instance": [ + { + "name": "catalog_id", + "type": "TypeString", + "description": "Catalog ID this instance was created from.", + "required": true + }, + { + "name": "cluster_region", + "type": "TypeString", + "description": "Cluster region (e.g., us-south).", + "required": true + }, + { + "name": "install_plan", + "type": "TypeString", + "description": "install plan for the subscription of the operator- can be either automatic or manual. Required for operator bundles", + "optional": true + }, + { + "name": "kind_format", + "type": "TypeString", + "description": "the format this instance has (helm, operator, ova...).", + "required": true + }, + { + "name": "cluster_all_namespaces", + "type": "TypeBool", + "description": "designate to install into all namespaces.", + "required": true + }, + { + "name": "schematics_workspace_id", + "type": "TypeString", + "description": "id of the schematics workspace, for offerings installed through schematics", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "id of the resource group", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "url", + "type": "TypeString", + "description": "url reference to this object.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "platform CRN for this instance.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "the label for this instance.", + "required": true + }, + { + "name": "offering_id", + "type": "TypeString", + "description": "Offering ID this instance was created from.", + "required": true + }, + { + "name": "version", + "type": "TypeString", + "description": "The version this instance was installed from (not version id).", + "required": true + }, + { + "name": "wait_until_successful", + "type": "TypeBool", + "description": "Whether to wait until the offering instance successfully provisions, or to return when accepted", + "default_value": true, + "optional": true + }, + { + "name": "cluster_id", + "type": "TypeString", + "description": "Cluster ID.", + "required": true + }, + { + "name": "cluster_namespaces", + "type": "TypeList", + "description": "List of target namespaces to install into.", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "channel", + "type": "TypeString", + "description": "channel to target for the operator subscription. Required for operator bundles", + "optional": true + } + ], + "ibm_cm_version": [ + { + "name": "sha", + "type": "TypeString", + "description": "hash of the content.", + "computed": true + }, + { + "name": "updated", + "type": "TypeString", + "description": "The date and time this version was last updated.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Tags array.", + "cloud_data_type": "tags", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "content", + "type": "TypeString", + "description": "byte array representing the content to be imported. Only supported for OVA images at this time.", + "immutable": true, + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Version's CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "repo_url", + "type": "TypeString", + "description": "Content's repo URL.", + "computed": true + }, + { + "name": "source_url", + "type": "TypeString", + "description": "Content's source URL (e.g git repo).", + "computed": true + }, + { + "name": "tgz_url", + "type": "TypeString", + "description": "File used to on-board this version.", + "computed": true + }, + { + "name": "offering_id", + "type": "TypeString", + "description": "Offering identification.", + "immutable": true, + "required": true + }, + { + "name": "target_kinds", + "type": "TypeList", + "description": "Target kinds. Current valid values are 'iks', 'roks', 'vcenter', and 'terraform'.", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "version", + "type": "TypeString", + "description": "Version of content type.", + "computed": true + }, + { + "name": "zipurl", + "type": "TypeString", + "description": "URL path to zip location. If not specified, must provide content in the body of this call.", + "immutable": true, + "optional": true + }, + { + "name": "catalog_id", + "type": "TypeString", + "description": "Catalog ID.", + "computed": true + }, + { + "name": "kind_id", + "type": "TypeString", + "description": "Kind ID.", + "computed": true + }, + { + "name": "catalog_identifier", + "type": "TypeString", + "description": "Catalog identifier.", + "immutable": true, + "required": true + }, + { + "name": "target_version", + "type": "TypeString", + "description": "The semver value for this new version, if not found in the zip url package content.", + "immutable": true, + "optional": true + }, + { + "name": "created", + "type": "TypeString", + "description": "The date and time this version was created.", + "computed": true + } + ], + "ibm_compute_autoscale_group": [ + { + "name": "network_vlan_ids", + "type": "TypeSet", + "description": "List of network VLAN ids", + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "regional_group", + "type": "TypeString", + "description": "regional group", + "immutable": true, + "required": true + }, + { + "name": "maximum_member_count", + "type": "TypeInt", + "description": "Maximum member count", + "required": true + }, + { + "name": "cooldown", + "type": "TypeInt", + "description": "Cooldown value", + "required": true + }, + { + "name": "virtual_server_id", + "type": "TypeInt", + "description": "virtual server ID", + "optional": true + }, + { + "name": "health_check", + "type": "TypeMap", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "required": true + }, + { + "name": "minimum_member_count", + "type": "TypeInt", + "description": "Minimum member count", + "required": true + }, + { + "name": "termination_policy", + "type": "TypeString", + "description": "Termination policy", + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Port number", + "optional": true + }, + { + "name": "virtual_guest_member_template", + "type": "TypeList", + "description": "Virtual guest member template", + "required": true, + "elem": { + "block_storage_ids": { + "name": "block_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + "bulk_vms": { + "name": "bulk_vms", + "type": "TypeSet", + "optional": true, + "elem": { + "domain": { + "name": "domain", + "type": "TypeString", + "immutable": true, + "required": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "min_items": 2 + }, + "cores": { + "name": "cores", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "datacenter": { + "name": "datacenter", + "type": "TypeString", + "optional": true, + "computed": true + }, + "datacenter_choice": { + "name": "datacenter_choice", + "type": "TypeList", + "description": "The user provided datacenter options", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + "dedicated_acct_host_only": { + "name": "dedicated_acct_host_only", + "type": "TypeBool", + "optional": true + }, + "dedicated_host_id": { + "name": "dedicated_host_id", + "type": "TypeInt", + "optional": true + }, + "dedicated_host_name": { + "name": "dedicated_host_name", + "type": "TypeString", + "optional": true + }, + "disks": { + "name": "disks", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + "domain": { + "name": "domain", + "type": "TypeString", + "optional": true + }, + "evault": { + "name": "evault", + "type": "TypeInt", + "optional": true + }, + "file_storage_ids": { + "name": "file_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + "flavor_key_name": { + "name": "flavor_key_name", + "type": "TypeString", + "description": "Flavor key name used to provision vm.", + "optional": true, + "computed": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "optional": true + }, + "hourly_billing": { + "name": "hourly_billing", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "image_id": { + "name": "image_id", + "type": "TypeInt", + "optional": true + }, + "ip_address_id": { + "name": "ip_address_id", + "type": "TypeInt", + "computed": true + }, + "ip_address_id_private": { + "name": "ip_address_id_private", + "type": "TypeInt", + "computed": true + }, + "ipv4_address": { + "name": "ipv4_address", + "type": "TypeString", + "computed": true + }, + "ipv4_address_private": { + "name": "ipv4_address_private", + "type": "TypeString", + "computed": true + }, + "ipv6_address": { + "name": "ipv6_address", + "type": "TypeString", + "computed": true + }, + "ipv6_address_id": { + "name": "ipv6_address_id", + "type": "TypeInt", + "computed": true + }, + "ipv6_enabled": { + "name": "ipv6_enabled", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "ipv6_static_enabled": { + "name": "ipv6_static_enabled", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "local_disk": { + "name": "local_disk", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "network_speed": { + "name": "network_speed", + "type": "TypeInt", + "default_value": 100, + "optional": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "optional": true + }, + "os_reference_code": { + "name": "os_reference_code", + "type": "TypeString", + "optional": true + }, + "placement_group_id": { + "name": "placement_group_id", + "type": "TypeInt", + "description": "The placement group id", + "optional": true + }, + "placement_group_name": { + "name": "placement_group_name", + "type": "TypeString", + "description": "The placement group name", + "optional": true + }, + "post_install_script_uri": { + "name": "post_install_script_uri", + "type": "TypeString", + "optional": true + }, + "private_interface_id": { + "name": "private_interface_id", + "type": "TypeInt", + "computed": true + }, + "private_network_only": { + "name": "private_network_only", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "private_security_group_ids": { + "name": "private_security_group_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + }, + "max_items": 5 + }, + "private_subnet": { + "name": "private_subnet", + "type": "TypeString", + "optional": true, + "computed": true + }, + "private_subnet_id": { + "name": "private_subnet_id", + "type": "TypeInt", + "computed": true + }, + "private_vlan_id": { + "name": "private_vlan_id", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "public_bandwidth_limited": { + "name": "public_bandwidth_limited", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "public_bandwidth_unlimited": { + "name": "public_bandwidth_unlimited", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "public_interface_id": { + "name": "public_interface_id", + "type": "TypeInt", + "computed": true + }, + "public_ipv6_subnet": { + "name": "public_ipv6_subnet", + "type": "TypeString", + "computed": true + }, + "public_ipv6_subnet_id": { + "name": "public_ipv6_subnet_id", + "type": "TypeInt", + "computed": true + }, + "public_security_group_ids": { + "name": "public_security_group_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + }, + "max_items": 5 + }, + "public_subnet": { + "name": "public_subnet", + "type": "TypeString", + "optional": true, + "computed": true + }, + "public_subnet_id": { + "name": "public_subnet_id", + "type": "TypeInt", + "computed": true + }, + "public_vlan_id": { + "name": "public_vlan_id", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "quote_id": { + "name": "quote_id", + "type": "TypeInt", + "description": "Quote ID for Quote based provisioning", + "optional": true + }, + "resource_controller_url": { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + "resource_name": { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + "resource_status": { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + "secondary_ip_addresses": { + "name": "secondary_ip_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "secondary_ip_count": { + "name": "secondary_ip_count", + "type": "TypeInt", + "optional": true + }, + "ssh_key_ids": { + "name": "ssh_key_ids", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "transient": { + "name": "transient", + "type": "TypeBool", + "optional": true + }, + "user_metadata": { + "name": "user_metadata", + "type": "TypeString", + "optional": true + } + } + } + ], + "ibm_compute_autoscale_policy": [ + { + "name": "scale_type", + "type": "TypeString", + "description": "scale type", + "required": true + }, + { + "name": "scale_amount", + "type": "TypeInt", + "description": "Scale amount", + "required": true + }, + { + "name": "cooldown", + "type": "TypeInt", + "description": "cooldown value", + "optional": true + }, + { + "name": "scale_group_id", + "type": "TypeInt", + "description": "scale group ID", + "immutable": true, + "required": true + }, + { + "name": "triggers", + "type": "TypeSet", + "optional": true, + "elem": { + "date": { + "name": "date", + "type": "TypeString", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "schedule": { + "name": "schedule", + "type": "TypeString", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "required": true + }, + "watches": { + "name": "watches", + "type": "TypeSet", + "optional": true, + "elem": { + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "metric": { + "name": "metric", + "type": "TypeString", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "required": true + }, + "period": { + "name": "period", + "type": "TypeInt", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "required": true + } + } + } + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "required": true + } + ], + "ibm_compute_bare_metal": [ + { + "name": "secondary_ip_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Host name", + "immutable": true, + "optional": true + }, + { + "name": "image_template_id", + "type": "TypeInt", + "description": "OS image template ID", + "immutable": true, + "optional": true + }, + { + "name": "network_speed", + "type": "TypeInt", + "description": "Network speed in MBPS", + "default_value": 100, + "immutable": true, + "optional": true + }, + { + "name": "private_network_only", + "type": "TypeBool", + "description": "only private network configured if is true", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "disk_key_names", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "redundant_network", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "extended_hardware_testing", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "post_install_script_uri", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "storage_groups", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "array_size": { + "name": "array_size", + "type": "TypeInt", + "description": "Array size of harddrives list", + "optional": true + }, + "array_type_id": { + "name": "array_type_id", + "type": "TypeInt", + "description": "Array type ID", + "required": true + }, + "hard_drives": { + "name": "hard_drives", + "type": "TypeList", + "description": "Hard-drives List", + "required": true, + "elem": { + "type": "TypeInt" + } + }, + "partition_template_id": { + "name": "partition_template_id", + "type": "TypeInt", + "description": "Partition template ID", + "optional": true + } + } + }, + { + "name": "private_ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "global_identifier", + "type": "TypeString", + "description": "The unique global identifier of the bare metal server", + "computed": true + }, + { + "name": "secondary_ip_count", + "type": "TypeInt", + "description": "Secondary IP addresses count", + "immutable": true, + "optional": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "Domain name", + "immutable": true, + "required": true + }, + { + "name": "datacenter", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "gpu_key_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "restricted_network", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "quote_id", + "type": "TypeInt", + "description": "Quote ID for Quote based provisioning", + "immutable": true, + "optional": true + }, + { + "name": "public_subnet", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "private_subnet", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ipv6_static_enabled", + "type": "TypeBool", + "description": "boolean value true if ipv6 static is enabled else false", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "ipv6_enabled", + "type": "TypeBool", + "description": "Boolean value true if IPV6 ia enabled or false", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "user_metadata", + "type": "TypeString", + "description": "User metadata info", + "immutable": true, + "optional": true + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "description": "Enables hourly billing", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "software_guard_extensions", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "os_key_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "public_bandwidth", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "public_ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "ipv6_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ipv6_address", + "type": "TypeString", + "computed": true + }, + { + "name": "ssh_key_ids", + "type": "TypeList", + "description": "SSH KEY IDS list", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "file_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "block_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "redundant_power_supply", + "type": "TypeBool", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "public_ipv4_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "fixed_config_preset", + "type": "TypeString", + "description": "Fixed config preset value", + "immutable": true, + "optional": true + }, + { + "name": "os_reference_code", + "type": "TypeString", + "description": "OS refernece code value", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "process_key_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "gpu_secondary_key_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "unbonded_network", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "Optional notes info", + "optional": true + }, + { + "name": "tcp_monitoring", + "type": "TypeBool", + "description": "TCP monitoring enabled if set as true", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "package_key_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "private_ipv4_address_id", + "type": "TypeInt", + "computed": true + } + ], + "ibm_compute_dedicated_host": [ + { + "name": "router_hostname", + "type": "TypeString", + "description": "The hostname of the primary router that the dedicated host is associated with.", + "immutable": true, + "required": true + }, + { + "name": "cpu_count", + "type": "TypeInt", + "description": "The capacity that the dedicated host's CPU allocation is restricted to.", + "computed": true + }, + { + "name": "disk_capacity", + "type": "TypeInt", + "description": "The capacity that the dedicated host's disk allocation is restricted to.", + "computed": true + }, + { + "name": "memory_capacity", + "type": "TypeInt", + "description": "The capacity that the dedicated host's memory allocation is restricted to.", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "hostname", + "type": "TypeString", + "description": "The host name of dedicatated host.", + "required": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "The domain of dedicatated host.", + "immutable": true, + "required": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "The data center in which the dedicatated host is to be provisioned.", + "immutable": true, + "required": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "The flavor of the dedicatated host.", + "default_value": "56_CORES_X_242_RAM_X_1_4_TB", + "immutable": true, + "optional": true + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "description": "The billing type for the dedicatated host.", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "default_value": 90, + "optional": true + } + ], + "ibm_compute_monitor": [ + { + "name": "ip_address", + "type": "TypeString", + "description": "IP Address", + "optional": true + }, + { + "name": "query_type_id", + "type": "TypeInt", + "description": "Query Type ID", + "required": true + }, + { + "name": "response_action_id", + "type": "TypeInt", + "description": "Response action ID", + "required": true + }, + { + "name": "wait_cycles", + "type": "TypeInt", + "description": "wait cycles count", + "optional": true + }, + { + "name": "notified_users", + "type": "TypeSet", + "description": "List of users notified", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "guest_id", + "type": "TypeInt", + "description": "Guest ID", + "immutable": true, + "required": true + } + ], + "ibm_compute_placement_group": [ + { + "name": "rule", + "type": "TypeString", + "description": "Rule info", + "default_value": "SPREAD", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Dataceneter name", + "immutable": true, + "required": true + }, + { + "name": "pod", + "type": "TypeString", + "description": "Pod name", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "required": true + } + ], + "ibm_compute_provisioning_hook": [ + { + "name": "uri", + "type": "TypeString", + "description": "URI of the hook", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags associated with resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Provision hook name", + "required": true + } + ], + "ibm_compute_reserved_capacity": [ + { + "name": "pod", + "type": "TypeString", + "description": "Pod name", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "required": true + }, + { + "name": "instances", + "type": "TypeInt", + "description": "no of the instances", + "required": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "flavor of the reserved capacity", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "force_create", + "type": "TypeBool", + "description": "Force the creation of reserved capacity with same name", + "optional": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Dataceneter name", + "immutable": true, + "required": true + } + ], + "ibm_compute_ssh_key": [ + { + "name": "label", + "type": "TypeString", + "description": "SSH Key label", + "required": true + }, + { + "name": "public_key", + "type": "TypeString", + "description": "Plublic Key info", + "immutable": true, + "required": true + }, + { + "name": "fingerprint", + "type": "TypeString", + "description": "SSH key fingerprint", + "computed": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "Additional notes", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_compute_ssl_certificate": [ + { + "name": "validity_begin", + "type": "TypeString", + "description": "Validity begins from", + "computed": true + }, + { + "name": "validity_end", + "type": "TypeString", + "description": "Validity ends before", + "computed": true + }, + { + "name": "key_size", + "type": "TypeInt", + "description": "SSL key size", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags set for resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "organization_name", + "type": "TypeString", + "description": "Organization name", + "computed": true + }, + { + "name": "validity_days", + "type": "TypeInt", + "description": "Validity days", + "computed": true + }, + { + "name": "create_date", + "type": "TypeString", + "description": "certificate creation date", + "computed": true + }, + { + "name": "modify_date", + "type": "TypeString", + "description": "certificate modificatiob date", + "computed": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "SSL Certifcate", + "immutable": true, + "required": true + }, + { + "name": "intermediate_certificate", + "type": "TypeString", + "description": "Intermediate certificate value", + "immutable": true, + "optional": true + }, + { + "name": "private_key", + "type": "TypeString", + "description": "SSL Private Key", + "secure": true, + "immutable": true, + "required": true + }, + { + "name": "common_name", + "type": "TypeString", + "description": "Common name", + "computed": true + } + ], + "ibm_compute_user": [ + { + "name": "state", + "type": "TypeString", + "description": "Satate name", + "required": true + }, + { + "name": "country", + "type": "TypeString", + "description": "Country name", + "required": true + }, + { + "name": "timezone", + "type": "TypeString", + "description": "time zone info", + "required": true + }, + { + "name": "has_api_key", + "type": "TypeBool", + "description": "API Key info of the user", + "default_value": false, + "optional": true + }, + { + "name": "username", + "type": "TypeString", + "description": "user name", + "optional": true, + "computed": true + }, + { + "name": "email", + "type": "TypeString", + "description": "email address of the user", + "required": true + }, + { + "name": "user_status", + "type": "TypeString", + "description": "user status info", + "default_value": "ACTIVE", + "optional": true + }, + { + "name": "password", + "type": "TypeString", + "description": "password for the user", + "secure": true, + "optional": true + }, + { + "name": "permissions", + "type": "TypeSet", + "description": "set of persmissions assigned for the user", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "first_name", + "type": "TypeString", + "description": "First name of the user", + "required": true + }, + { + "name": "address1", + "type": "TypeString", + "description": "Address info of the user", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags set for the resources", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "last_name", + "type": "TypeString", + "description": "Last name of the user", + "required": true + }, + { + "name": "address2", + "type": "TypeString", + "description": "Address info of the user", + "optional": true + }, + { + "name": "city", + "type": "TypeString", + "description": "City name", + "required": true + }, + { + "name": "api_key", + "type": "TypeString", + "description": "API key for the user", + "secure": true, + "optional": true, + "computed": true + }, + { + "name": "ibm_id", + "type": "TypeString", + "description": "IBM ID of the user", + "computed": true + }, + { + "name": "company_name", + "type": "TypeString", + "description": "comapany name", + "required": true + } + ], + "ibm_compute_vm_instance": [ + { + "name": "notes", + "type": "TypeString", + "optional": true + }, + { + "name": "evault", + "type": "TypeInt", + "immutable": true, + "optional": true + }, + { + "name": "user_metadata", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "flavor_key_name", + "type": "TypeString", + "description": "Flavor key name used to provision vm.", + "optional": true, + "computed": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "public_ipv6_subnet", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ssh_key_ids", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "secondary_ip_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "ip_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "ipv6_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "secondary_ip_count", + "type": "TypeInt", + "immutable": true, + "optional": true + }, + { + "name": "public_bandwidth_limited", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "quote_id", + "type": "TypeInt", + "description": "Quote ID for Quote based provisioning", + "immutable": true, + "optional": true + }, + { + "name": "dedicated_acct_host_only", + "type": "TypeBool", + "immutable": true, + "optional": true + }, + { + "name": "post_install_script_uri", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "private_subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_interface_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_security_group_ids", + "type": "TypeSet", + "immutable": true, + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + }, + "max_items": 5 + }, + { + "name": "private_subnet", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "disks", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "file_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "local_disk", + "type": "TypeBool", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "os_reference_code", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "reserved_capacity_id", + "type": "TypeInt", + "description": "The reserved group id", + "immutable": true, + "optional": true + }, + { + "name": "memory", + "type": "TypeInt", + "optional": true, + "computed": true + }, + { + "name": "private_security_group_ids", + "type": "TypeSet", + "immutable": true, + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + }, + "max_items": 5 + }, + { + "name": "private_network_only", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "reserved_instance_primary_disk", + "type": "TypeInt", + "description": "The primary disk of reserved instance", + "immutable": true, + "optional": true + }, + { + "name": "public_subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_bandwidth_unlimited", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "domain", + "type": "TypeString", + "optional": true + }, + { + "name": "dedicated_host_id", + "type": "TypeInt", + "immutable": true, + "optional": true + }, + { + "name": "private_interface_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "datacenter_choice", + "type": "TypeList", + "description": "The user provided datacenter options", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + { + "name": "ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "ip_address_id_private", + "type": "TypeInt", + "computed": true + }, + { + "name": "ipv6_static_enabled", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "hostname", + "type": "TypeString", + "optional": true + }, + { + "name": "public_subnet", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ipv6_enabled", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "ipv6_address", + "type": "TypeString", + "computed": true + }, + { + "name": "transient", + "type": "TypeBool", + "immutable": true, + "optional": true + }, + { + "name": "placement_group_name", + "type": "TypeString", + "description": "The placement group name", + "immutable": true, + "optional": true + }, + { + "name": "placement_group_id", + "type": "TypeInt", + "description": "The placement group id", + "immutable": true, + "optional": true + }, + { + "name": "cores", + "type": "TypeInt", + "optional": true, + "computed": true + }, + { + "name": "block_storage_ids", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "bulk_vms", + "type": "TypeSet", + "immutable": true, + "optional": true, + "elem": { + "domain": { + "name": "domain", + "type": "TypeString", + "immutable": true, + "required": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "min_items": 2 + }, + { + "name": "reserved_capacity_name", + "type": "TypeString", + "description": "The reserved group id", + "immutable": true, + "optional": true + }, + { + "name": "public_ipv6_subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "default_value": 90, + "optional": true, + "deprecated": "This field is deprecated. Use timeouts block instead" + }, + { + "name": "datacenter", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "dedicated_host_name", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "network_speed", + "type": "TypeInt", + "default_value": 100, + "optional": true + }, + { + "name": "ipv4_address_private", + "type": "TypeString", + "computed": true + }, + { + "name": "image_id", + "type": "TypeInt", + "immutable": true, + "optional": true + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "default_value": true, + "immutable": true, + "optional": true + } + ], + "ibm_container_addons": [ + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster Name or ID", + "cloud_data_type": "cluster", + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "addons", + "type": "TypeSet", + "required": true, + "elem": { + "allowed_upgrade_versions": { + "name": "allowed_upgrade_versions", + "type": "TypeList", + "description": "The versions that the addon can be upgraded to", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "deprecated": { + "name": "deprecated", + "type": "TypeBool", + "description": "Determines if this addon version is deprecated", + "computed": true + }, + "health_state": { + "name": "health_state", + "type": "TypeString", + "description": "The health state for this addon, a short indication (e.g. critical, pending)", + "computed": true + }, + "health_status": { + "name": "health_status", + "type": "TypeString", + "description": "The health status for this addon, provides a description of the state (e.g. error message)", + "computed": true + }, + "min_kube_version": { + "name": "min_kube_version", + "type": "TypeString", + "description": "The minimum kubernetes version for this addon.", + "computed": true + }, + "min_ocp_version": { + "name": "min_ocp_version", + "type": "TypeString", + "description": "The minimum OpenShift version for this addon.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The addon name such as 'istio'.", + "required": true + }, + "supported_kube_range": { + "name": "supported_kube_range", + "type": "TypeString", + "description": "The supported kubernetes version range for this addon.", + "computed": true + }, + "target_version": { + "name": "target_version", + "type": "TypeString", + "description": "The addon target version.", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "description": "The addon version, omit the version if you wish to use the default version.", + "optional": true, + "computed": true + }, + "vlan_spanning_required": { + "name": "vlan_spanning_required", + "type": "TypeBool", + "description": "VLAN spanning required for multi-zone clusters", + "computed": true + } + } + } + ], + "ibm_container_alb": [ + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster id", + "computed": true + }, + { + "name": "user_ip", + "type": "TypeString", + "description": "IP assigned by the user", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "ALB name", + "computed": true + }, + { + "name": "replicas", + "type": "TypeString", + "description": "Desired number of ALB replicas.", + "computed": true + }, + { + "name": "alb_id", + "type": "TypeString", + "description": "ALB ID", + "immutable": true, + "required": true + }, + { + "name": "enable", + "type": "TypeBool", + "description": "set to true if ALB needs to be enabled", + "optional": true, + "computed": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "description": "Set to true if ALB needs to be disabled", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "description": "Indicate whether resizing should be done", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "ALB zone", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "cloud_data_type": "region", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "alb_type", + "type": "TypeString", + "description": "ALB type", + "computed": true + } + ], + "ibm_container_alb_cert": [ + { + "name": "namespace", + "type": "TypeString", + "description": "Namespace of the secret", + "default_value": "ibm-cert-store", + "immutable": true, + "optional": true + }, + { + "name": "persistence", + "type": "TypeBool", + "description": "Persistence of secret", + "optional": true + }, + { + "name": "domain_name", + "type": "TypeString", + "description": "Domain name", + "computed": true + }, + { + "name": "expires_on", + "type": "TypeString", + "description": "Certificate expaire on date", + "computed": true + }, + { + "name": "cloud_cert_instance_id", + "type": "TypeString", + "description": "cloud cert instance ID", + "computed": true + }, + { + "name": "cluster_id", + "type": "TypeString", + "description": "Cluster ID", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "secret_name", + "type": "TypeString", + "description": "Secret name", + "immutable": true, + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Secret Status", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "region name", + "cloud_data_type": "region", + "optional": true, + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "cert_crn", + "type": "TypeString", + "description": "Certificate CRN id", + "required": true + }, + { + "name": "issuer_name", + "type": "TypeString", + "description": "certificate issuer name", + "computed": true, + "deprecated": "This field is depricated and is not available in v2 version of ingress api" + } + ], + "ibm_container_alb_create": [ + { + "name": "vlan_id", + "type": "TypeString", + "description": "The VLAN ID that you want to use for your ALBs.", + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "The ID of the cluster that the ALB belongs to.", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "replicas", + "type": "TypeString", + "description": "number of instances", + "computed": true + }, + { + "name": "enable", + "type": "TypeBool", + "description": "If set to true, the ALB is enabled by default.", + "default_value": true, + "optional": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "description": "Set to true if ALB needs to be disabled", + "computed": true + }, + { + "name": "user_ip", + "type": "TypeString", + "description": "IP assigned by the user", + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "description": "resize", + "computed": true + }, + { + "name": "ingress_image", + "type": "TypeString", + "description": "The type of Ingress image that you want to use for your ALB deployment.", + "immutable": true, + "optional": true + }, + { + "name": "alb_type", + "type": "TypeString", + "description": "The type of ALB that you want to create.", + "required": true + }, + { + "name": "nlb_version", + "type": "TypeString", + "description": "The version of the network load balancer that you want to use for the ALB.", + "immutable": true, + "optional": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone where you want to deploy the ALB.", + "immutable": true, + "required": true + }, + { + "name": "alb_id", + "type": "TypeString", + "description": "The ID of the application load balancer (ALB).", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "ALB name", + "computed": true + }, + { + "name": "ip", + "type": "TypeString", + "description": "The IP address that you want to assign to the ALB.", + "optional": true + } + ], + "ibm_container_api_key_reset": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of Resource Group", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "reset_api_key", + "type": "TypeInt", + "description": "Determines if apikey has to be reset or not", + "default_value": 1, + "optional": true + }, + { + "name": "region", + "type": "TypeString", + "description": "Region which api key has to be reset", + "cloud_data_type": "region", + "immutable": true, + "required": true + } + ], + "ibm_container_bind_service": [ + { + "name": "service_instance_id", + "type": "TypeString", + "description": "Service instance ID", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "cluster_name_id", + "type": "TypeString", + "description": "Cluster name or ID", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "service_instance_name", + "type": "TypeString", + "description": "serivice instance name", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "key", + "type": "TypeString", + "description": "Key info", + "immutable": true, + "optional": true + }, + { + "name": "role", + "type": "TypeString", + "description": "Role info", + "immutable": true, + "optional": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "namespace_id", + "type": "TypeString", + "description": "namespace ID", + "immutable": true, + "required": true + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + } + ], + "ibm_container_cluster": [ + { + "name": "no_subnet", + "type": "TypeBool", + "description": "Boolean value set to true when subnet creation is not required.", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "The datacenter where this cluster will be deployed", + "immutable": true, + "required": true + }, + { + "name": "disk_encryption", + "type": "TypeBool", + "description": "disc encryption done, if set to true.", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "kube_version", + "type": "TypeString", + "description": "Kubernetes version info", + "optional": true, + "computed": true + }, + { + "name": "hardware", + "type": "TypeString", + "description": "Hardware type", + "immutable": true, + "required": true + }, + { + "name": "wait_for_worker_update", + "type": "TypeBool", + "description": "Wait for worker node to update during kube version update.", + "default_value": true, + "optional": true + }, + { + "name": "pod_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for pods", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "force_delete_storage", + "type": "TypeBool", + "description": "Force the removal of a cluster and its persistent storage. Deleted data cannot be recovered", + "default_value": false, + "optional": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "gateway_enabled", + "type": "TypeBool", + "description": "Set true for gateway enabled clusters", + "default_value": false, + "optional": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "retry_patch_version", + "type": "TypeInt", + "description": "Argument which helps to retry the patch version updates on worker nodes. Increment the value to retry the patch updates if the previous apply fails", + "optional": true + }, + { + "name": "update_all_workers", + "type": "TypeBool", + "description": "Updates all the woker nodes if sets to true", + "default_value": false, + "optional": true + }, + { + "name": "account_guid", + "type": "TypeString", + "description": "The bluemix account guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "public_service_endpoint", + "type": "TypeBool", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "workers_info", + "type": "TypeList", + "description": "The IDs of the worker node", + "optional": true, + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "optional": true, + "computed": true + }, + "pool_name": { + "name": "pool_name", + "type": "TypeString", + "computed": true + }, + "version": { + "name": "version", + "type": "TypeString", + "optional": true, + "computed": true + } + } + }, + { + "name": "patch_version", + "type": "TypeString", + "description": "Kubernetes patch version", + "optional": true + }, + { + "name": "is_trusted", + "type": "TypeBool", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "private_vlan_id", + "type": "TypeString", + "description": "Private VLAN ID", + "immutable": true, + "optional": true + }, + { + "name": "entitlement", + "type": "TypeString", + "description": "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", + "optional": true + }, + { + "name": "server_url", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the resource", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "worker_num", + "type": "TypeInt", + "description": "Number of worker nodes", + "default_value": 0, + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "labels", + "type": "TypeMap", + "description": "list of labels to the default worker pool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "taints", + "type": "TypeSet", + "description": "WorkerPool Taints", + "optional": true, + "elem": { + "effect": { + "name": "effect", + "type": "TypeString", + "description": "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", + "required": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Key for taint", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for taint.", + "required": true + } + } + }, + { + "name": "machine_type", + "type": "TypeString", + "description": "Machine type", + "immutable": true, + "optional": true + }, + { + "name": "wait_till", + "type": "TypeString", + "description": "wait_till can be configured for Master Ready, One worker Ready or Ingress Ready", + "default_value": "IngressReady", + "optional": true + }, + { + "name": "webhook", + "type": "TypeList", + "optional": true, + "elem": { + "level": { + "name": "level", + "type": "TypeString", + "required": true + }, + "type": { + "name": "type", + "type": "TypeString", + "required": true + }, + "url": { + "name": "url", + "type": "TypeString", + "required": true + } + } + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The bluemix space guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "image_security_enforcement", + "type": "TypeBool", + "description": "Set true to enable image security enforcement policies", + "default_value": false, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The cluster name", + "immutable": true, + "required": true + }, + { + "name": "kms_config", + "type": "TypeList", + "description": "Enables KMS on a given cluster", + "optional": true, + "elem": { + "crk_id": { + "name": "crk_id", + "type": "TypeString", + "description": "ID of the customer root key.", + "required": true + }, + "instance_id": { + "name": "instance_id", + "type": "TypeString", + "description": "ID of the KMS instance to use to encrypt the cluster.", + "required": true + }, + "private_endpoint": { + "name": "private_endpoint", + "type": "TypeBool", + "description": "Specify this option to use the KMS public service endpoint.", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "default_pool_size", + "type": "TypeInt", + "description": "The size of the default worker pool", + "default_value": 1, + "optional": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "subnet_id", + "type": "TypeSet", + "description": "List of subnet IDs", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "org_guid", + "type": "TypeString", + "description": "The bluemix organization guid this cluster belongs to", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "private_service_endpoint", + "type": "TypeBool", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The cluster region", + "cloud_data_type": "region", + "optional": true, + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "billing", + "type": "TypeString", + "optional": true, + "deprecated": "This field is deprecated" + }, + { + "name": "public_vlan_id", + "type": "TypeString", + "description": "Public VLAN ID", + "immutable": true, + "optional": true + }, + { + "name": "service_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for services", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "worker_pools", + "type": "TypeList", + "computed": true, + "elem": { + "hardware": { + "name": "hardware", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "labels": { + "name": "labels", + "type": "TypeMap", + "computed": true + }, + "machine_type": { + "name": "machine_type", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "size_per_zone": { + "name": "size_per_zone", + "type": "TypeInt", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + }, + "zones": { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "private_vlan": { + "name": "private_vlan", + "type": "TypeString", + "computed": true + }, + "public_vlan": { + "name": "public_vlan", + "type": "TypeString", + "computed": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "albs", + "type": "TypeList", + "computed": true, + "elem": { + "alb_ip": { + "name": "alb_ip", + "type": "TypeString", + "computed": true + }, + "alb_type": { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + "disable_deployment": { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "num_of_instances": { + "name": "num_of_instances", + "type": "TypeString", + "computed": true + }, + "resize": { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_container_cluster_feature": [ + { + "name": "private_service_endpoint", + "type": "TypeBool", + "optional": true, + "computed": true + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "refresh_api_servers", + "type": "TypeBool", + "description": "Boolean value true of API server to be refreshed in K8S cluster", + "default_value": true, + "optional": true + }, + { + "name": "reload_workers", + "type": "TypeBool", + "description": "Boolean value set true if worker nodes to be reloaded", + "default_value": true, + "optional": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name of ID", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "public_service_endpoint", + "type": "TypeBool", + "optional": true, + "computed": true + } + ], + "ibm_container_dedicated_host": [ + { + "name": "placement_enabled", + "type": "TypeBool", + "description": "Enables/disables placement on the dedicated host", + "optional": true, + "computed": true + }, + { + "name": "host_id", + "type": "TypeString", + "description": "The id of the dedicated host", + "computed": true + }, + { + "name": "life_cycle", + "type": "TypeList", + "computed": true, + "elem": { + "actual_state": { + "name": "actual_state", + "type": "TypeString", + "computed": true + }, + "desired_state": { + "name": "desired_state", + "type": "TypeString", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "computed": true + }, + "message_date": { + "name": "message_date", + "type": "TypeString", + "computed": true + }, + "message_details": { + "name": "message_details", + "type": "TypeString", + "computed": true + }, + "message_details_date": { + "name": "message_details_date", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "resources", + "type": "TypeList", + "description": "The resources of the dedicated host", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + }, + "consumed": { + "name": "consumed", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + } + } + }, + { + "name": "workers", + "type": "TypeList", + "description": "The workers of the dedicated host", + "computed": true, + "elem": { + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "computed": true + }, + "flavor": { + "name": "flavor", + "type": "TypeString", + "computed": true + }, + "worker_id": { + "name": "worker_id", + "type": "TypeString", + "computed": true + }, + "worker_pool_id": { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "flavor", + "type": "TypeString", + "description": "The flavor of the dedicated host", + "immutable": true, + "required": true + }, + { + "name": "host_pool_id", + "type": "TypeString", + "description": "The id of the dedicated host pool the dedicated host is associated with", + "immutable": true, + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone of the dedicated host", + "immutable": true, + "required": true + } + ], + "ibm_container_dedicated_host_pool": [ + { + "name": "zones", + "type": "TypeList", + "description": "The zones of the dedicated host pool", + "computed": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeList", + "computed": true, + "elem": { + "memory_bytes": { + "name": "memory_bytes", + "type": "TypeInt", + "computed": true + }, + "vcpu": { + "name": "vcpu", + "type": "TypeInt", + "computed": true + } + } + }, + "host_count": { + "name": "host_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "worker_pools", + "type": "TypeList", + "description": "The worker pools of the dedicated host pool", + "computed": true, + "elem": { + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "computed": true + }, + "worker_pool_id": { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the dedicated host pool", + "immutable": true, + "required": true + }, + { + "name": "metro", + "type": "TypeString", + "description": "The metro to create the dedicated host pool in", + "immutable": true, + "required": true + }, + { + "name": "flavor_class", + "type": "TypeString", + "description": "The flavor class of the dedicated host pool", + "immutable": true, + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "host_count", + "type": "TypeInt", + "description": "The count of the hosts under the dedicated host pool", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the dedicated host pool", + "computed": true + } + ], + "ibm_container_nlb_dns": [ + { + "name": "cluster", + "type": "TypeString", + "description": "The name or ID of the cluster. To list the clusters that you have access to, use the `GET /v1/clusters` API or run `ibmcloud ks cluster ls`.", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "nlb_dns_type", + "type": "TypeString", + "computed": true + }, + { + "name": "nlb_ssl_secret_status", + "type": "TypeString", + "computed": true + }, + { + "name": "nlb_type", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that the cluster is in. To check the resource group ID of the cluster, use the GET /v1/clusters/idOrName API. To list available resource group IDs, run ibmcloud resource groups.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "nlb_host", + "type": "TypeString", + "immutable": true, + "required": true + }, + { + "name": "nlb_ips", + "type": "TypeSet", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "nlb_monitor_state", + "type": "TypeString", + "computed": true + }, + { + "name": "nlb_ssl_secret_name", + "type": "TypeString", + "computed": true + }, + { + "name": "secret_namespace", + "type": "TypeString", + "computed": true + } + ], + "ibm_container_storage_attachment": [ + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Volume attachment status", + "computed": true + }, + { + "name": "volume_attachment_id", + "type": "TypeString", + "description": "Volume attachment ID", + "computed": true + }, + { + "name": "volume_type", + "type": "TypeString", + "description": "The type of volume", + "computed": true + }, + { + "name": "volume", + "type": "TypeString", + "description": "VPC Volume ID", + "immutable": true, + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name or ID", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker", + "type": "TypeString", + "description": "worker node ID", + "immutable": true, + "required": true + }, + { + "name": "volume_attachment_name", + "type": "TypeString", + "description": "Volume attachment name", + "computed": true + } + ], + "ibm_container_vpc_alb": [ + { + "name": "alb_id", + "type": "TypeString", + "description": "ALB ID", + "immutable": true, + "required": true + }, + { + "name": "load_balancer_hostname", + "type": "TypeString", + "description": "Load balancer host name", + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "description": "boolean value to resize the albs", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "ALB state", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone info.", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "alb_type", + "type": "TypeString", + "description": "Type of the ALB", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "cluster id", + "computed": true + }, + { + "name": "enable", + "type": "TypeBool", + "description": "Enable the ALB instance in the cluster", + "optional": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "description": "Disable the ALB instance in the cluster", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "ALB name", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the ALB", + "computed": true + } + ], + "ibm_container_vpc_alb_create": [ + { + "name": "load_balancer_hostname", + "type": "TypeString", + "description": "Load balancer host name", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "ALB state", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone where you want to deploy the ALB.", + "immutable": true, + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "The ID of the cluster that the ALB belongs to.", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "alb_id", + "type": "TypeString", + "description": "The ID of the application load balancer (ALB).", + "immutable": true, + "computed": true + }, + { + "name": "disable_deployment", + "type": "TypeBool", + "description": "Disable the ALB instance in the cluster", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "ALB name", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of ALB that you want to create.", + "immutable": true, + "required": true + }, + { + "name": "enable", + "type": "TypeBool", + "description": "Enable the ALB instance in the cluster", + "optional": true + }, + { + "name": "alb_type", + "type": "TypeString", + "description": "Type of the ALB", + "computed": true + }, + { + "name": "resize", + "type": "TypeBool", + "description": "boolean value to resize the albs", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the ALB", + "computed": true + } + ], + "ibm_container_vpc_cluster": [ + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "wait_till", + "type": "TypeString", + "description": "wait_till can be configured for Master Ready, One worker Ready or Ingress Ready", + "default_value": "IngressReady", + "optional": true + }, + { + "name": "kube_version", + "type": "TypeString", + "description": "Kubernetes version", + "optional": true, + "computed": true + }, + { + "name": "entitlement", + "type": "TypeString", + "description": "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "Cluster nodes flavour", + "immutable": true, + "required": true + }, + { + "name": "worker_labels", + "type": "TypeMap", + "description": "Labels for default worker pool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "force_delete_storage", + "type": "TypeBool", + "description": "Force the removal of a cluster and its persistent storage. Deleted data cannot be recovered", + "default_value": false, + "optional": true + }, + { + "name": "kms_instance_id", + "type": "TypeString", + "description": "Instance ID for boot volume encryption", + "optional": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "wait_for_worker_update", + "type": "TypeBool", + "description": "Wait for worker node to update during kube version update.", + "default_value": true, + "optional": true + }, + { + "name": "pod_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for pods", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "disable_public_service_endpoint", + "type": "TypeBool", + "description": "Boolean value true if Public service endpoint to be disabled", + "default_value": false, + "optional": true + }, + { + "name": "cos_instance_crn", + "type": "TypeString", + "description": "A standard cloud object storage instance CRN to back up the internal registry in your OpenShift on VPC Gen 2 cluster", + "optional": true + }, + { + "name": "crk", + "type": "TypeString", + "description": "Root Key ID for boot volume encryption", + "optional": true + }, + { + "name": "master_status", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "retry_patch_version", + "type": "TypeInt", + "description": "Argument which helps to retry the patch version updates on worker nodes. Increment the value to retry the patch updates if the previous apply fails", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The cluster name", + "immutable": true, + "required": true + }, + { + "name": "zones", + "type": "TypeSet", + "description": "Zone info", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Zone for the worker pool in a multizone cluster", + "required": true + }, + "subnet_id": { + "name": "subnet_id", + "type": "TypeString", + "description": "The VPC subnet to assign the cluster", + "required": true + } + } + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of worker nodes in the cluster", + "default_value": 1, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for the resources", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "kms_config", + "type": "TypeList", + "description": "Enables KMS on a given cluster", + "optional": true, + "elem": { + "crk_id": { + "name": "crk_id", + "type": "TypeString", + "description": "ID of the customer root key.", + "required": true + }, + "instance_id": { + "name": "instance_id", + "type": "TypeString", + "description": "ID of the KMS instance to use to encrypt the cluster.", + "required": true + }, + "private_endpoint": { + "name": "private_endpoint", + "type": "TypeBool", + "description": "Specify this option to use the KMS public service endpoint.", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "patch_version", + "type": "TypeString", + "description": "Kubernetes patch version", + "optional": true + }, + { + "name": "master_url", + "type": "TypeString", + "computed": true + }, + { + "name": "albs", + "type": "TypeList", + "computed": true, + "elem": { + "alb_type": { + "name": "alb_type", + "type": "TypeString", + "computed": true + }, + "disable_deployment": { + "name": "disable_deployment", + "type": "TypeBool", + "computed": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "load_balancer_hostname": { + "name": "load_balancer_hostname", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "resize": { + "name": "resize", + "type": "TypeBool", + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "image_security_enforcement", + "type": "TypeBool", + "description": "Set true to enable image security enforcement policies", + "default_value": false, + "optional": true + }, + { + "name": "vpc_id", + "type": "TypeString", + "description": "The vpc id where the cluster is", + "immutable": true, + "required": true + }, + { + "name": "service_subnet", + "type": "TypeString", + "description": "Custom subnet CIDR to provide private IP addresses for services", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "taints", + "type": "TypeSet", + "description": "WorkerPool Taints", + "optional": true, + "elem": { + "effect": { + "name": "effect", + "type": "TypeString", + "description": "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", + "required": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Key for taint", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for taint.", + "required": true + } + } + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "host_pool_id", + "type": "TypeString", + "description": "The ID of the cluster's associated host pool", + "immutable": true, + "optional": true + }, + { + "name": "update_all_workers", + "type": "TypeBool", + "description": "Updates all the woker nodes if sets to true", + "default_value": false, + "optional": true + } + ], + "ibm_container_vpc_worker": [ + { + "name": "kube_config_path", + "type": "TypeString", + "description": "Path of downloaded cluster config", + "immutable": true, + "optional": true + }, + { + "name": "check_ptx_status", + "type": "TypeBool", + "description": "Check portworx status after worker replace", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "ptx_timeout", + "type": "TypeString", + "description": "Timeout for checking ptx pods/status", + "default_value": "15m", + "immutable": true, + "optional": true + }, + { + "name": "ip", + "type": "TypeString", + "description": "IP of the replaced worker", + "computed": true + }, + { + "name": "cluster_name", + "type": "TypeString", + "description": "Cluster name", + "immutable": true, + "required": true + }, + { + "name": "replace_worker", + "type": "TypeString", + "description": "Worker name/id that needs to be replaced", + "immutable": true, + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + } + ], + "ibm_container_vpc_worker_pool": [ + { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "The number of workers", + "required": true + }, + { + "name": "kms_instance_id", + "type": "TypeString", + "description": "Instance ID for boot volume encryption", + "optional": true + }, + { + "name": "taints", + "type": "TypeSet", + "description": "WorkerPool Taints", + "optional": true, + "elem": { + "effect": { + "name": "effect", + "type": "TypeString", + "description": "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", + "required": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Key for taint", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for taint.", + "required": true + } + } + }, + { + "name": "entitlement", + "type": "TypeString", + "description": "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", + "optional": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker_pool_name", + "type": "TypeString", + "description": "worker pool name", + "immutable": true, + "required": true + }, + { + "name": "labels", + "type": "TypeMap", + "description": "Labels", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vpc_id", + "type": "TypeString", + "description": "The vpc id where the cluster is", + "immutable": true, + "required": true + }, + { + "name": "host_pool_id", + "type": "TypeString", + "description": "The ID of the dedicated host pool associated with the worker pool", + "immutable": true, + "optional": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "cluster node falvor", + "immutable": true, + "required": true + }, + { + "name": "zones", + "type": "TypeSet", + "description": "Zones info", + "required": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "zone name", + "required": true + }, + "subnet_id": { + "name": "subnet_id", + "type": "TypeString", + "description": "subnet ID", + "required": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "Resource Controller URL", + "computed": true + }, + { + "name": "crk", + "type": "TypeString", + "description": "Root Key ID for boot volume encryption", + "optional": true + } + ], + "ibm_container_worker_pool": [ + { + "name": "size_per_zone", + "type": "TypeInt", + "description": "Number of nodes per zone", + "required": true + }, + { + "name": "hardware", + "type": "TypeString", + "description": "Hardware type", + "default_value": "shared", + "immutable": true, + "optional": true + }, + { + "name": "disk_encryption", + "type": "TypeBool", + "description": "worker node disk encrypted if set to true", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "taints", + "type": "TypeSet", + "description": "WorkerPool Taints", + "optional": true, + "elem": { + "effect": { + "name": "effect", + "type": "TypeString", + "description": "Effect for taint. Accepted values are NoSchedule, PreferNoSchedule and NoExecute.", + "required": true + }, + "key": { + "name": "key", + "type": "TypeString", + "description": "Key for taint", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for taint.", + "required": true + } + } + }, + { + "name": "region", + "type": "TypeString", + "description": "The worker pool region", + "cloud_data_type": "region", + "optional": true, + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Cluster name", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker_pool_name", + "type": "TypeString", + "description": "worker pool name", + "immutable": true, + "required": true + }, + { + "name": "state", + "type": "TypeString", + "description": "worker pool state", + "computed": true + }, + { + "name": "zones", + "type": "TypeList", + "computed": true, + "elem": { + "private_vlan": { + "name": "private_vlan", + "type": "TypeString", + "computed": true + }, + "public_vlan": { + "name": "public_vlan", + "type": "TypeString", + "computed": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "machine_type", + "type": "TypeString", + "description": "worker nodes machine type", + "immutable": true, + "required": true + }, + { + "name": "entitlement", + "type": "TypeString", + "description": "Entitlement option reduces additional OCP Licence cost in Openshift Clusters", + "optional": true + }, + { + "name": "worker_pool_id", + "type": "TypeString", + "computed": true + }, + { + "name": "labels", + "type": "TypeMap", + "description": "list of labels to worker pool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this cluster", + "computed": true + } + ], + "ibm_container_worker_pool_zone_attachment": [ + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "cluster name or ID", + "cloud_data_type": "cluster", + "immutable": true, + "required": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "worker_pool", + "type": "TypeString", + "description": "Workerpool name", + "immutable": true, + "required": true + }, + { + "name": "private_vlan_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The zone region", + "cloud_data_type": "region", + "optional": true, + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "worker_count", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_vlan_id", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "wait_till_albs", + "type": "TypeBool", + "description": "wait_till_albs can be configured to wait for albs during the worker pool zone attachment.", + "default_value": true, + "optional": true + } + ], + "ibm_cos_bucket": [ + { + "name": "metrics_monitoring", + "type": "TypeList", + "description": "Enables sending metrics to IBM Cloud Monitoring.", + "optional": true, + "elem": { + "metrics_monitoring_crn": { + "name": "metrics_monitoring_crn", + "type": "TypeString", + "description": "Instance of IBM Cloud Monitoring that will receive the bucket metrics.", + "required": true + }, + "request_metrics_enabled": { + "name": "request_metrics_enabled", + "type": "TypeBool", + "description": "Request metrics will be sent to the monitoring service.", + "default_value": false, + "optional": true + }, + "usage_metrics_enabled": { + "name": "usage_metrics_enabled", + "type": "TypeBool", + "description": "Usage metrics will be sent to the monitoring service.", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "resource instance ID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "matches": "^crn:.+:.+:.+:.+:.+:a\\/[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\:\\:$", + "cloud_data_range": [ + "service:cloud-object-storage" + ] + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "key_protect", + "type": "TypeString", + "description": "CRN of the key you want to use data at rest encryption", + "immutable": true, + "optional": true + }, + { + "name": "satellite_location_id", + "type": "TypeString", + "description": "Provide satellite location info.", + "immutable": true, + "optional": true + }, + { + "name": "single_site_location", + "type": "TypeString", + "description": "single site location info", + "immutable": true, + "options": "ams03,che01,hkg02,mel01,mex01,mil01,mon01,osl01,par01,sjc04,sao01,seo01,sng01,tor01", + "optional": true + }, + { + "name": "s3_endpoint_public", + "type": "TypeString", + "description": "Public endpoint for the COS bucket", + "computed": true + }, + { + "name": "allowed_ip", + "type": "TypeList", + "description": "List of IPv4 or IPv6 addresses", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "expire_rule", + "type": "TypeList", + "description": "Enable configuration expire_rule to COS Bucket after a defined period of time", + "optional": true, + "elem": { + "date": { + "name": "date", + "type": "TypeString", + "description": "Specify a rule to expire the current version of objects in bucket after a specific date.", + "optional": true + }, + "days": { + "name": "days", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "optional": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an expire rule for a bucket", + "required": true + }, + "expired_object_delete_marker": { + "name": "expired_object_delete_marker", + "type": "TypeBool", + "description": "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", + "optional": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "optional": true, + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + "optional": true, + "computed": true + } + }, + "max_items": 1000 + }, + { + "name": "noncurrent_version_expiration", + "type": "TypeList", + "description": "Enable configuration expire_rule to COS Bucket after a defined period of time", + "optional": true, + "elem": { + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an expire rule for a bucket", + "required": true + }, + "noncurrent_days": { + "name": "noncurrent_days", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "optional": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "optional": true, + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "region_location", + "type": "TypeString", + "description": "Region Location info.", + "immutable": true, + "optional": true + }, + { + "name": "s3_endpoint_direct", + "type": "TypeString", + "description": "Direct endpoint for the COS bucket", + "computed": true + }, + { + "name": "abort_incomplete_multipart_upload_days", + "type": "TypeList", + "description": "Enable abort incomplete multipart upload to COS Bucket after a defined period of time", + "optional": true, + "elem": { + "days_after_initiation": { + "name": "days_after_initiation", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "optional": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable rule for a bucket", + "required": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "optional": true, + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "archive_rule", + "type": "TypeList", + "description": "Enable configuration archive_rule (glacier/accelerated) to COS Bucket after a defined period of time", + "optional": true, + "elem": { + "days": { + "name": "days", + "type": "TypeInt", + "description": "Specifies the number of days when the specific rule action takes effect.", + "required": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an archive rule for a bucket", + "required": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier for the rule.Archive rules allow you to set a specific time frame after which objects transition to the archive. Set Rule ID for cos bucket", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Specifies the storage class/archive type to which you want the object to transition. It can be Glacier or Accelerated", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "hard_quota", + "type": "TypeInt", + "description": "sets a maximum amount of storage (in bytes) available for a bucket", + "optional": true + }, + { + "name": "force_delete", + "type": "TypeBool", + "description": "COS buckets need to be empty before they can be deleted. force_delete option empty the bucket and delete it.", + "default_value": true, + "optional": true + }, + { + "name": "cross_region_location", + "type": "TypeString", + "description": "Cros region location info", + "immutable": true, + "options": "us,eu,ap", + "optional": true + }, + { + "name": "activity_tracking", + "type": "TypeList", + "description": "Enables sending log data to Activity Tracker and LogDNA to provide visibility into object read and write events", + "optional": true, + "elem": { + "activity_tracker_crn": { + "name": "activity_tracker_crn", + "type": "TypeString", + "description": "The instance of Activity Tracker that will receive object event data", + "required": true + }, + "read_data_events": { + "name": "read_data_events", + "type": "TypeBool", + "description": "If set to true, all object read events will be sent to Activity Tracker.", + "default_value": false, + "optional": true + }, + "write_data_events": { + "name": "write_data_events", + "type": "TypeBool", + "description": "If set to true, all object write events will be sent to Activity Tracker.", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "object_versioning", + "type": "TypeList", + "description": "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", + "optional": true, + "elem": { + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or suspend the versioning for objects in the bucket", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "bucket_name", + "type": "TypeString", + "description": "COS Bucket name", + "immutable": true, + "required": true + }, + { + "name": "storage_class", + "type": "TypeString", + "description": "Storage class info", + "immutable": true, + "options": "standard,vault,cold,smart,flex,onerate_active", + "optional": true, + "computed": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "options": "public,private,direct", + "optional": true + }, + { + "name": "s3_endpoint_private", + "type": "TypeString", + "description": "Private endpoint for the COS bucket", + "computed": true + }, + { + "name": "retention_rule", + "type": "TypeList", + "description": "A retention policy is enabled at the IBM Cloud Object Storage bucket level. Minimum, maximum and default retention period are defined by this policy and apply to all objects in the bucket.", + "immutable": true, + "optional": true, + "elem": { + "default": { + "name": "default", + "type": "TypeInt", + "description": "If an object is stored in the bucket without specifying a custom retention period.", + "required": true + }, + "maximum": { + "name": "maximum", + "type": "TypeInt", + "description": "Maximum duration of time an object can be kept unmodified in the bucket.", + "required": true + }, + "minimum": { + "name": "minimum", + "type": "TypeInt", + "description": "Minimum duration of time an object must be kept unmodified in the bucket", + "required": true + }, + "permanent": { + "name": "permanent", + "type": "TypeBool", + "description": "Enable or disable the permanent retention policy on the bucket", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + } + ], + "ibm_cos_bucket_object": [ + { + "name": "body", + "type": "TypeString", + "description": "COS object body", + "computed": true + }, + { + "name": "content_length", + "type": "TypeInt", + "description": "COS object content length", + "computed": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "COS endpoint type: public, private, direct", + "default_value": "public", + "optional": true + }, + { + "name": "key", + "type": "TypeString", + "description": "COS object key", + "immutable": true, + "required": true + }, + { + "name": "object_sql_url", + "type": "TypeString", + "description": "Access the object using an SQL Query instance.The reference url is used to perform queries against objects storing structured data.", + "computed": true + }, + { + "name": "content_base64", + "type": "TypeString", + "description": "COS object content in base64 encoding", + "optional": true + }, + { + "name": "content_file", + "type": "TypeString", + "description": "COS object content file path", + "optional": true + }, + { + "name": "force_delete", + "type": "TypeBool", + "description": "COS buckets need to be empty before they can be deleted. force_delete option empty the bucket and delete it.", + "default_value": true, + "optional": true + }, + { + "name": "bucket_location", + "type": "TypeString", + "description": "COS bucket location", + "immutable": true, + "required": true + }, + { + "name": "content_type", + "type": "TypeString", + "description": "COS object content type", + "computed": true + }, + { + "name": "etag", + "type": "TypeString", + "description": "COS object MD5 hexdigest", + "optional": true, + "computed": true + }, + { + "name": "last_modified", + "type": "TypeString", + "description": "COS object last modified date", + "computed": true + }, + { + "name": "bucket_crn", + "type": "TypeString", + "description": "COS bucket CRN", + "immutable": true, + "required": true + }, + { + "name": "content", + "type": "TypeString", + "description": "COS object content", + "optional": true + }, + { + "name": "version_id", + "type": "TypeString", + "computed": true + } + ], + "ibm_cos_bucket_replication_rule": [ + { + "name": "bucket_crn", + "type": "TypeString", + "description": "COS bucket CRN", + "immutable": true, + "required": true + }, + { + "name": "bucket_location", + "type": "TypeString", + "description": "COS bucket location", + "immutable": true, + "required": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "COS endpoint type: public, private, direct", + "default_value": "public", + "optional": true + }, + { + "name": "replication_rule", + "type": "TypeSet", + "description": "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + "required": true, + "elem": { + "deletemarker_replication_status": { + "name": "deletemarker_replication_status", + "type": "TypeBool", + "description": "Indicates whether to replicate delete markers. It should be either Enable or Disable", + "optional": true, + "computed": true + }, + "destination_bucket_crn": { + "name": "destination_bucket_crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + "required": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "description": "Enable or disable an replication rule for a bucket", + "required": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "The rule applies to any objects with keys that match this prefix", + "optional": true + }, + "priority": { + "name": "priority", + "type": "TypeInt", + "description": "A priority is associated with each rule. There may be cases where multiple rules may be applicable to an object that is uploaded.", + "optional": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "A unique identifier for the rule. The maximum value is 255 characters.", + "optional": true, + "computed": true + } + }, + "max_items": 1000 + } + ], + "ibm_cr_namespace": [ + { + "name": "updated_on", + "type": "TypeString", + "description": "When the namespace was last updated.", + "computed": true, + "deprecated": "This field is deprecated" + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the namespace.", + "immutable": true, + "required": true, + "min_length": 4, + "max_length": 30, + "matches": "^[a-z0-9]+[a-z0-9_-]+[a-z0-9]+$" + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that the namespace will be created within.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "account", + "type": "TypeString", + "description": "The IBM Cloud account that owns the namespace.", + "computed": true + }, + { + "name": "created_date", + "type": "TypeString", + "description": "When the namespace was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "If the namespace has been assigned to a resource group, this is the IBM Cloud CRN representing the namespace.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_date", + "type": "TypeString", + "description": "When the namespace was last updated.", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_created_date", + "type": "TypeString", + "description": "When the namespace was assigned to a resource group.", + "computed": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "When the namespace was created.", + "computed": true, + "deprecated": "This field is deprecated" + } + ], + "ibm_cr_retention_policy": [ + { + "name": "images_per_repo", + "type": "TypeInt", + "description": "Determines how many images will be retained for each repository when the retention policy is executed. The value -1 denotes 'Unlimited' (all images are retained).", + "required": true + }, + { + "name": "retain_untagged", + "type": "TypeBool", + "description": "Determines if untagged images are retained when executing the retention policy. This is false by default meaning untagged images will be deleted when the policy is executed.", + "default_value": false, + "optional": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "The namespace to which the retention policy is attached.", + "required": true + } + ], + "ibm_database": [ + { + "name": "configuration_schema", + "type": "TypeString", + "description": "The configuration schema in JSON format", + "computed": true + }, + { + "name": "node_disk_allocation_mb", + "type": "TypeInt", + "description": "Disk allocation per node", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "remote_leader_id", + "type": "TypeString", + "description": "The CRN of leader database", + "optional": true + }, + { + "name": "configuration", + "type": "TypeString", + "description": "The configuration in JSON format", + "optional": true + }, + { + "name": "service_endpoints", + "type": "TypeString", + "description": "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", + "default_value": "public", + "options": "public, private, public-and-private", + "optional": true + }, + { + "name": "key_protect_instance", + "type": "TypeString", + "description": "The CRN of Key protect instance", + "immutable": true, + "optional": true + }, + { + "name": "key_protect_key", + "type": "TypeString", + "description": "The CRN of Key protect key", + "immutable": true, + "optional": true + }, + { + "name": "users", + "type": "TypeSet", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "User name", + "required": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "User password", + "secure": true, + "required": true + }, + "role": { + "name": "role", + "type": "TypeString", + "description": "User role. Only available for ops_manager user type.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "User type", + "default_value": "database", + "optional": true + } + } + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource instance name for example, my Database instance", + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The id of the resource group in which the Database instance is present", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "tags", + "type": "TypeSet", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "point_in_time_recovery_time", + "type": "TypeString", + "description": "The point in time recovery time stamp of the deployed instance", + "optional": true + }, + { + "name": "adminpassword", + "type": "TypeString", + "description": "The admin user password for the instance", + "secure": true, + "optional": true + }, + { + "name": "members_cpu_allocation_count", + "type": "TypeInt", + "description": "CPU allocation required for cluster", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "auto_scaling", + "type": "TypeList", + "description": "ICD Auto Scaling", + "optional": true, + "computed": true, + "elem": { + "cpu": { + "name": "cpu", + "type": "TypeList", + "description": "CPU Auto Scaling", + "optional": true, + "computed": true, + "elem": { + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "optional": true, + "computed": true + }, + "rate_limit_count_per_member": { + "name": "rate_limit_count_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit count per number", + "optional": true, + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "optional": true, + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "disk": { + "name": "disk", + "type": "TypeList", + "description": "Disk Auto Scaling", + "optional": true, + "computed": true, + "elem": { + "capacity_enabled": { + "name": "capacity_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: Capacity Enabled", + "optional": true, + "computed": true + }, + "free_space_less_than_percent": { + "name": "free_space_less_than_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: Capacity Free Space Less Than Percent", + "optional": true, + "computed": true + }, + "io_above_percent": { + "name": "io_above_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: IO Utilization Above Percent", + "optional": true, + "computed": true + }, + "io_enabled": { + "name": "io_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: IO Utilization Enabled", + "optional": true, + "computed": true + }, + "io_over_period": { + "name": "io_over_period", + "type": "TypeString", + "description": "Auto Scaling Scalar: IO Utilization Over Period", + "optional": true, + "computed": true + }, + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "optional": true, + "computed": true + }, + "rate_limit_mb_per_member": { + "name": "rate_limit_mb_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit mb per member", + "optional": true, + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "optional": true, + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "memory": { + "name": "memory", + "type": "TypeList", + "description": "Memory Auto Scaling", + "optional": true, + "computed": true, + "elem": { + "io_above_percent": { + "name": "io_above_percent", + "type": "TypeInt", + "description": "Auto Scaling Scalar: IO Utilization Above Percent", + "optional": true, + "computed": true + }, + "io_enabled": { + "name": "io_enabled", + "type": "TypeBool", + "description": "Auto Scaling Scalar: IO Utilization Enabled", + "optional": true, + "computed": true + }, + "io_over_period": { + "name": "io_over_period", + "type": "TypeString", + "description": "Auto Scaling Scalar: IO Utilization Over Period", + "optional": true, + "computed": true + }, + "rate_increase_percent": { + "name": "rate_increase_percent", + "type": "TypeInt", + "description": "Auto Scaling Rate: Increase Percent", + "optional": true, + "computed": true + }, + "rate_limit_mb_per_member": { + "name": "rate_limit_mb_per_member", + "type": "TypeInt", + "description": "Auto Scaling Rate: Limit mb per member", + "optional": true, + "computed": true + }, + "rate_period_seconds": { + "name": "rate_period_seconds", + "type": "TypeInt", + "description": "Auto Scaling Rate: Period Seconds", + "optional": true, + "computed": true + }, + "rate_units": { + "name": "rate_units", + "type": "TypeString", + "description": "Auto Scaling Rate: Units", + "optional": true, + "computed": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the Cloud Internet database service", + "immutable": true, + "required": true, + "options": "databases-for-etcd, databases-for-postgresql, databases-for-redis, databases-for-elasticsearch, databases-for-mongodb, messages-for-rabbitmq, databases-for-mysql, databases-for-cassandra, databases-for-enterprisedb" + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the Database instance", + "immutable": true, + "required": true, + "options": "standard, enterprise" + }, + { + "name": "members_memory_allocation_mb", + "type": "TypeInt", + "description": "Memory allocation required for cluster", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "node_cpu_allocation_count", + "type": "TypeInt", + "description": "CPU allocation per node", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "connectionstrings", + "type": "TypeList", + "computed": true, + "elem": { + "bundlebase64": { + "name": "bundlebase64", + "type": "TypeString", + "description": "Cassandra base64 encoding", + "computed": true + }, + "bundlename": { + "name": "bundlename", + "type": "TypeString", + "description": "Cassandra Bundle Name", + "computed": true + }, + "certbase64": { + "name": "certbase64", + "type": "TypeString", + "description": "Certificate in base64 encoding", + "computed": true + }, + "certname": { + "name": "certname", + "type": "TypeString", + "description": "Certificate Name", + "computed": true + }, + "composed": { + "name": "composed", + "type": "TypeString", + "description": "Connection string", + "computed": true + }, + "database": { + "name": "database", + "type": "TypeString", + "description": "DB name", + "computed": true + }, + "hosts": { + "name": "hosts", + "type": "TypeList", + "optional": true, + "elem": { + "hostname": { + "name": "hostname", + "type": "TypeString", + "description": "DB host name", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeString", + "description": "DB port", + "computed": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "User name", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "Password", + "computed": true + }, + "path": { + "name": "path", + "type": "TypeString", + "description": "DB path", + "computed": true + }, + "queryoptions": { + "name": "queryoptions", + "type": "TypeString", + "description": "DB query options", + "computed": true + }, + "scheme": { + "name": "scheme", + "type": "TypeString", + "description": "DB scheme", + "computed": true + } + }, + "deprecated": "This field is deprecated, please use ibm_database_connection instead" + }, + { + "name": "whitelist", + "type": "TypeSet", + "optional": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Whitelist IP address in CIDR notation", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Unique white list description", + "optional": true + } + } + }, + { + "name": "group", + "type": "TypeSet", + "optional": true, + "elem": { + "cpu": { + "name": "cpu", + "type": "TypeSet", + "optional": true, + "elem": { + "allocation_count": { + "name": "allocation_count", + "type": "TypeInt", + "required": true + } + }, + "max_items": 1 + }, + "disk": { + "name": "disk", + "type": "TypeSet", + "optional": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "required": true + } + }, + "max_items": 1 + }, + "group_id": { + "name": "group_id", + "type": "TypeString", + "required": true + }, + "members": { + "name": "members", + "type": "TypeSet", + "optional": true, + "elem": { + "allocation_count": { + "name": "allocation_count", + "type": "TypeInt", + "required": true + } + }, + "max_items": 1 + }, + "memory": { + "name": "memory", + "type": "TypeSet", + "optional": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "required": true + } + }, + "max_items": 1 + } + } + }, + { + "name": "point_in_time_recovery_deployment_id", + "type": "TypeString", + "description": "The CRN of source instance", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The resource instance status", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Unique identifier of resource instance", + "computed": true + }, + { + "name": "adminuser", + "type": "TypeString", + "description": "The admin user id for the instance", + "computed": true + }, + { + "name": "node_memory_allocation_mb", + "type": "TypeInt", + "description": "Memory allocation per node", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "plan_validation", + "type": "TypeBool", + "description": "For elasticsearch and postgres perform database parameter validation during the plan phase. Otherwise, database parameter validation happens in apply phase.", + "default_value": true, + "optional": true + }, + { + "name": "backup_id", + "type": "TypeString", + "description": "The CRN of backup source database", + "optional": true + }, + { + "name": "backup_encryption_key_crn", + "type": "TypeString", + "description": "The Backup Encryption Key CRN", + "immutable": true, + "optional": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location or the region in which Database instance exists", + "cloud_data_type": "region", + "required": true + }, + { + "name": "members_disk_allocation_mb", + "type": "TypeInt", + "description": "Disk allocation required for cluster", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "version", + "type": "TypeString", + "description": "The database version to provision if specified", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "node_count", + "type": "TypeInt", + "description": "Total number of nodes in the cluster", + "optional": true, + "computed": true, + "deprecated": "use group instead" + }, + { + "name": "groups", + "type": "TypeList", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "description": "Count of scaling groups for the instance", + "computed": true + }, + "cpu": { + "name": "cpu", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_count": { + "name": "allocation_count", + "type": "TypeInt", + "description": "The current cpu allocation count", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can the number of CPUs be scaled down as well as up", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Are the number of CPUs adjustable", + "computed": true + }, + "minimum_count": { + "name": "minimum_count", + "type": "TypeInt", + "description": "The minimum number of cpus allowed", + "computed": true + }, + "step_size_count": { + "name": "step_size_count", + "type": "TypeInt", + "description": "The number of CPUs allowed to step up or down by", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The .", + "computed": true + } + } + }, + "disk": { + "name": "disk", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "description": "The current disk allocation", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can the disk size be scaled down as well as up", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Is the disk size adjustable", + "computed": true + }, + "minimum_mb": { + "name": "minimum_mb", + "type": "TypeInt", + "description": "The minimum disk size allowed", + "computed": true + }, + "step_size_mb": { + "name": "step_size_mb", + "type": "TypeInt", + "description": "The step size disk increases or decreases in", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The units disk is allocated in", + "computed": true + } + } + }, + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "Scaling group name", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeList", + "computed": true, + "elem": { + "allocation_mb": { + "name": "allocation_mb", + "type": "TypeInt", + "description": "The current memory allocation for a group instance", + "computed": true + }, + "can_scale_down": { + "name": "can_scale_down", + "type": "TypeBool", + "description": "Can memory scale down as well as up.", + "computed": true + }, + "is_adjustable": { + "name": "is_adjustable", + "type": "TypeBool", + "description": "Is the memory size adjustable.", + "computed": true + }, + "minimum_mb": { + "name": "minimum_mb", + "type": "TypeInt", + "description": "The minimum memory size for a group instance", + "computed": true + }, + "step_size_mb": { + "name": "step_size_mb", + "type": "TypeInt", + "description": "The step size memory increases or decreases in.", + "computed": true + }, + "units": { + "name": "units", + "type": "TypeString", + "description": "The units memory is allocated in.", + "computed": true + } + } + } + } + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + } + ], + "ibm_dl_gateway": [ + { + "name": "bfd_status", + "type": "TypeString", + "description": "Gateway BFD status", + "optional": true, + "computed": true + }, + { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of services this Gateway is attached to. Mode transit means this Gateway will be attached to Transit Gateway Service and direct means this Gateway will be attached to vpc or classic connection", + "options": "direct, transit", + "optional": true, + "computed": true + }, + { + "name": "macsec_config", + "type": "TypeList", + "description": "MACsec configuration information", + "optional": true, + "elem": { + "active": { + "name": "active", + "type": "TypeBool", + "description": "Indicate whether MACsec protection should be active (true) or inactive (false) for this MACsec enabled gateway", + "required": true + }, + "active_cak": { + "name": "active_cak", + "type": "TypeString", + "description": "Active connectivity association key.", + "computed": true + }, + "cipher_suite": { + "name": "cipher_suite", + "type": "TypeString", + "description": "SAK cipher suite", + "computed": true + }, + "confidentiality_offset": { + "name": "confidentiality_offset", + "type": "TypeInt", + "description": "Confidentiality Offset", + "computed": true + }, + "cryptographic_algorithm": { + "name": "cryptographic_algorithm", + "type": "TypeString", + "description": "Cryptographic Algorithm", + "computed": true + }, + "fallback_cak": { + "name": "fallback_cak", + "type": "TypeString", + "description": "Fallback connectivity association key. Keys used for MACsec configuration must have names with an even number of characters from [0-9a-fA-F]", + "optional": true + }, + "key_server_priority": { + "name": "key_server_priority", + "type": "TypeInt", + "description": "Key Server Priority", + "computed": true + }, + "primary_cak": { + "name": "primary_cak", + "type": "TypeString", + "description": "Desired primary connectivity association key. Keys for a MACsec configuration must have names with an even number of characters from [0-9a-fA-F]", + "required": true + }, + "sak_expiry_time": { + "name": "sak_expiry_time", + "type": "TypeInt", + "description": "Secure Association Key (SAK) expiry time in seconds", + "computed": true + }, + "security_policy": { + "name": "security_policy", + "type": "TypeString", + "description": "Packets without MACsec headers are not dropped when security_policy is should_secure.", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The current status of MACsec on the device for this gateway", + "computed": true + }, + "window_size": { + "name": "window_size", + "type": "TypeInt", + "description": "Replay protection window size", + "default_value": 148809600, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "provider_api_managed", + "type": "TypeBool", + "description": "Indicates whether gateway was created through a provider portal", + "computed": true + }, + { + "name": "bgp_asn", + "type": "TypeInt", + "description": "BGP ASN", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "speed_mbps", + "type": "TypeInt", + "description": "Gateway speed in megabits per second", + "required": true + }, + { + "name": "operational_status", + "type": "TypeString", + "description": "Gateway operational status", + "computed": true + }, + { + "name": "bgp_status", + "type": "TypeString", + "description": "Gateway BGP status", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "as_prepends", + "type": "TypeList", + "description": "List of AS Prepend configuration information", + "optional": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time AS Prepend was created", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this AS Prepend", + "optional": true, + "computed": true + }, + "length": { + "name": "length", + "type": "TypeInt", + "description": "Number of times the ASN to appended to the AS Path", + "required": true + }, + "policy": { + "name": "policy", + "type": "TypeString", + "description": "Route type this AS Prepend applies to", + "required": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time AS Prepend was updated", + "computed": true + } + } + }, + { + "name": "bfd_multiplier", + "type": "TypeInt", + "description": "BFD Multiplier", + "min_value": "1", + "max_value": "255", + "optional": true + }, + { + "name": "location_name", + "type": "TypeString", + "description": "Gateway location", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "carrier_name", + "type": "TypeString", + "description": "Carrier name", + "immutable": true, + "optional": true + }, + { + "name": "bgp_ibm_asn", + "type": "TypeInt", + "description": "IBM BGP ASN", + "computed": true + }, + { + "name": "change_request", + "type": "TypeString", + "description": "Changes pending approval for provider managed Direct Link Connect gateways", + "computed": true + }, + { + "name": "location_display_name", + "type": "TypeString", + "description": "Gateway location long name", + "computed": true + }, + { + "name": "bgp_base_cidr", + "type": "TypeString", + "description": "BGP base CIDR", + "optional": true + }, + { + "name": "port", + "type": "TypeString", + "description": "Gateway port", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "metered", + "type": "TypeBool", + "description": "Metered billing option", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this gateway", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$" + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "cross_connect_router", + "type": "TypeString", + "description": "Cross connect router", + "immutable": true, + "optional": true + }, + { + "name": "loa_reject_reason", + "type": "TypeString", + "description": "Loa reject reason", + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Gateway resource group", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "bfd_interval", + "type": "TypeInt", + "description": "BFD Interval", + "min_value": "300", + "max_value": "255000", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Gateway type", + "immutable": true, + "required": true, + "options": "dedicated, connect" + }, + { + "name": "bgp_ibm_cidr", + "type": "TypeString", + "description": "BGP IBM CIDR", + "optional": true, + "computed": true + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "VLAN allocated for this gateway", + "computed": true + }, + { + "name": "completion_notice_reject_reason", + "type": "TypeString", + "description": "Reason for completion notice rejection", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN (Cloud Resource Name) of this gateway", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "authentication_key", + "type": "TypeString", + "description": "BGP MD5 authentication key", + "optional": true + }, + { + "name": "bfd_status_updated_at", + "type": "TypeString", + "description": "Date and time BFD status was updated", + "optional": true, + "computed": true + }, + { + "name": "global", + "type": "TypeBool", + "description": "Gateways with global routing (true) can connect to networks outside their associated region", + "required": true + }, + { + "name": "customer_name", + "type": "TypeString", + "description": "Customer name", + "immutable": true, + "optional": true + }, + { + "name": "bgp_cer_cidr", + "type": "TypeString", + "description": "BGP customer edge router CIDR", + "optional": true, + "computed": true + }, + { + "name": "link_status", + "type": "TypeString", + "description": "Gateway link status", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the direct link gateway", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + } + ], + "ibm_dl_provider_gateway": [ + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "bgp_ibm_asn", + "type": "TypeInt", + "description": "IBM BGP ASN", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this gateway", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$" + }, + { + "name": "speed_mbps", + "type": "TypeInt", + "description": "Gateway speed in megabits per second", + "required": true + }, + { + "name": "provider_api_managed", + "type": "TypeBool", + "description": "Indicates whether gateway was created through a provider portal", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN (Cloud Resource Name) of this gateway", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the direct link gateway", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "bgp_cer_cidr", + "type": "TypeString", + "description": "BGP customer edge router CIDR", + "optional": true, + "computed": true + }, + { + "name": "bgp_ibm_cidr", + "type": "TypeString", + "description": "BGP IBM CIDR", + "optional": true, + "computed": true + }, + { + "name": "port", + "type": "TypeString", + "description": "Gateway port", + "immutable": true, + "required": true + }, + { + "name": "operational_status", + "type": "TypeString", + "description": "Gateway operational status", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Gateway type", + "computed": true + }, + { + "name": "bgp_status", + "type": "TypeString", + "description": "Gateway BGP status", + "computed": true + }, + { + "name": "customer_account_id", + "type": "TypeString", + "description": "Customer IBM Cloud account ID for the new gateway. A gateway object containing the pending create request will become available in the specified account.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 32, + "matches": "^[0-9a-f]+$" + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "bgp_asn", + "type": "TypeInt", + "description": "BGP ASN", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "VLAN allocated for this gateway", + "optional": true, + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_dl_route_report": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time report was created", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Direct Link gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "gateway_routes", + "type": "TypeList", + "description": "List of gateway routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for gateway routes", + "computed": true + } + } + }, + { + "name": "on_prem_routes", + "type": "TypeList", + "description": "List of onprem routes", + "computed": true, + "elem": { + "next_hop": { + "name": "next_hop", + "type": "TypeString", + "description": "Next Hop address", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for onprem routes", + "computed": true + } + } + }, + { + "name": "virtual_connection_routes", + "type": "TypeList", + "description": "Virtual Connection Routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Virtual connection routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + } + } + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + }, + "virtual_connection_name": { + "name": "virtual_connection_name", + "type": "TypeString", + "description": "Virtual connection name", + "computed": true + }, + "virtual_connection_type": { + "name": "virtual_connection_type", + "type": "TypeString", + "description": "Virtual connection type", + "computed": true + } + } + }, + { + "name": "status", + "type": "TypeString", + "description": "Route report status", + "computed": true + }, + { + "name": "route_report_id", + "type": "TypeString", + "description": "Id of the route report", + "computed": true + }, + { + "name": "overlapping_routes", + "type": "TypeList", + "description": "List of overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "overlapping routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "description": "Prefix for overlapping routes", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of route", + "computed": true + }, + "virtual_connection_id": { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "Virtual connection ID", + "computed": true + } + } + } + } + } + ], + "ibm_dl_virtual_connection": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time resource was created", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the virtual connection.Possible values: [pending,attached,approval_pending,rejected,expired,deleting,detached_by_network_pending,detached_by_network]", + "computed": true + }, + { + "name": "network_account", + "type": "TypeString", + "description": "For virtual connections across two different IBM Cloud Accounts network_account indicates the account that owns the target network.", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the Direct link gateway", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of virtual connection.Allowable values (classic,vpc)", + "immutable": true, + "required": true, + "options": "classic, vpc" + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual connection. Virtualconnection names are unique within a gateway. This is the name of thevirtual connection itself, the network being connected may have its ownname attribute", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$" + }, + { + "name": "network_id", + "type": "TypeString", + "description": "Unique identifier of the target network. For type=vpc virtual connections this is the CRN of the target VPC. This field does not apply to type=classic connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "virtual_connection_id", + "type": "TypeString", + "description": "The Direct Gateway virtual connection identifier", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Direct Link gateway identifier", + "immutable": true, + "required": true + } + ], + "ibm_dns_custom_resolver": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the custom resolver", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the custom resolver.", + "optional": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the custom resolver is enabled", + "default_value": true, + "optional": true + }, + { + "name": "high_availability", + "type": "TypeBool", + "description": "Whether High Availability is enabled in custom resolver", + "default_value": true, + "optional": true + }, + { + "name": "health", + "type": "TypeString", + "description": "Healthy state of the custom resolver", + "computed": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Time when a custom resolver is created", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "custom_resolver_id", + "type": "TypeString", + "description": "Identifier of the custom resolver", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "The recent time when a custom resolver is modified", + "computed": true + }, + { + "name": "locations", + "type": "TypeList", + "description": "Locations on which the custom resolver will be running", + "optional": true, + "elem": { + "dns_server_ip": { + "name": "dns_server_ip", + "type": "TypeString", + "description": "The ip address of this dns server", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the location is enabled for the custom resolver", + "default_value": false, + "optional": true + }, + "healthy": { + "name": "healthy", + "type": "TypeBool", + "description": "Whether the DNS server in this location is healthy or not.", + "computed": true + }, + "location_id": { + "name": "location_id", + "type": "TypeString", + "description": "Location ID", + "computed": true + }, + "subnet_crn": { + "name": "subnet_crn", + "type": "TypeString", + "description": "Subnet CRN", + "required": true + } + }, + "max_items": 3 + }, + { + "name": "rules", + "type": "TypeList", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the forwarding rule.", + "computed": true + }, + "forward_to": { + "name": "forward_to", + "type": "TypeList", + "description": "The upstream DNS servers will be forwarded to.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "match": { + "name": "match", + "type": "TypeString", + "description": "The matching zone or hostname.", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Identifier of the forwarding rule.", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the forwarding rule.", + "computed": true + } + } + } + ], + "ibm_dns_custom_resolver_forwarding_rule": [ + { + "name": "forward_to", + "type": "TypeList", + "description": "The upstream DNS servers will be forwarded to.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "the time when a forwarding rule ID is created, RFC3339 format.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "resolver_id", + "type": "TypeString", + "description": "The unique identifier of a custom resolver.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the forwarding rule.", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the forwarding rule.", + "options": "hostname, zone, Default", + "optional": true + }, + { + "name": "match", + "type": "TypeString", + "description": "The matching zone or hostname.", + "optional": true, + "computed": true + } + ], + "ibm_dns_custom_resolver_location": [ + { + "name": "enabled", + "type": "TypeBool", + "description": "CRLocation Enabled", + "default_value": false, + "optional": true + }, + { + "name": "healthy", + "type": "TypeBool", + "description": "CRLocation Healthy", + "computed": true + }, + { + "name": "dns_server_ip", + "type": "TypeString", + "description": "CRLocation Server IP", + "computed": true + }, + { + "name": "cr_enabled", + "type": "TypeBool", + "default_value": true, + "optional": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "resolver_id", + "type": "TypeString", + "description": "Custom Resolver ID", + "required": true + }, + { + "name": "location_id", + "type": "TypeString", + "description": "CRLocation ID", + "computed": true + }, + { + "name": "subnet_crn", + "type": "TypeString", + "description": "CRLocation Subnet CRN", + "required": true + } + ], + "ibm_dns_custom_resolver_secondary_zone": [ + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the secondary zone", + "optional": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Secondary Zone Modification date", + "computed": true + }, + { + "name": "resolver_id", + "type": "TypeString", + "description": "The unique identifier of a custom resolver.", + "required": true + }, + { + "name": "transfer_from", + "type": "TypeList", + "description": "The addresses of DNS servers where the secondary zone data should be transferred from", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Enable/Disable the secondary zone", + "required": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Secondary Zone Creation date", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "secondary_zone_id", + "type": "TypeString", + "description": "Secondary Zone ID", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The name of the zone.", + "required": true + } + ], + "ibm_dns_domain": [ + { + "name": "name", + "type": "TypeString", + "description": "DNS name", + "immutable": true, + "required": true + }, + { + "name": "serial", + "type": "TypeString", + "description": "DNS serial info", + "computed": true + }, + { + "name": "update_date", + "type": "TypeString", + "description": "DNS update date", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "DNS target info", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "tags associated with reosurce.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_dns_domain_registration_nameservers": [ + { + "name": "dns_registration_id", + "type": "TypeString", + "description": "DNS registration ID", + "required": true + }, + { + "name": "name_servers", + "type": "TypeSet", + "description": "Custom name servers for the domain registration", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "original_name_servers", + "type": "TypeSet", + "description": "Save of name servers prior to update", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_dns_glb": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "The GUID of the private DNS.", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone Id", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the load balancer", + "required": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "GLB Load Balancer creation date", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "GLB Load Balancer Modification date", + "computed": true + }, + { + "name": "glb_id", + "type": "TypeString", + "description": "Load balancer Id", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer", + "optional": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the load balancer is enabled", + "optional": true, + "computed": true + }, + { + "name": "ttl", + "type": "TypeInt", + "description": "Time to live in second", + "default_value": 60, + "optional": true + }, + { + "name": "health", + "type": "TypeString", + "description": "Healthy state of the load balancer.", + "computed": true + }, + { + "name": "fallback_pool", + "type": "TypeString", + "description": "The pool ID to use when all other pools are detected as unhealthy", + "required": true + }, + { + "name": "default_pools", + "type": "TypeList", + "description": "A list of pool IDs ordered by their failover priority", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "az_pools", + "type": "TypeSet", + "description": "Map availability zones to pool ID's.", + "optional": true, + "elem": { + "availability_zone": { + "name": "availability_zone", + "type": "TypeString", + "description": "Availability zone.", + "required": true + }, + "pools": { + "name": "pools", + "type": "TypeList", + "description": "List of load balancer pools", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + } + ], + "ibm_dns_glb_monitor": [ + { + "name": "path", + "type": "TypeString", + "description": "The endpoint path to health check against", + "optional": true, + "computed": true + }, + { + "name": "allow_insecure", + "type": "TypeBool", + "description": "Do not validate the certificate when monitor use HTTPS. This parameter is currently only valid for HTTPS monitors.", + "optional": true, + "computed": true + }, + { + "name": "expected_codes", + "type": "TypeString", + "description": "The expected HTTP response code or code range of the health check. This parameter is only valid for HTTP and HTTPS", + "options": "200,201,202,203,204,205,206,207,208,226,2xx", + "optional": true, + "computed": true + }, + { + "name": "expected_body", + "type": "TypeString", + "description": "A case-insensitive sub-string to look for in the response body", + "optional": true + }, + { + "name": "monitor_id", + "type": "TypeString", + "description": "Monitor Id", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The protocol to use for the health check", + "default_value": "HTTP", + "options": "HTTP, HTTPS, TCP", + "optional": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "The timeout (in seconds) before marking the health check as failed", + "default_value": 5, + "optional": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "GLB Monitor Modification date", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance Id", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer monitor", + "optional": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Port number to connect to for the health check", + "optional": true, + "computed": true + }, + { + "name": "interval", + "type": "TypeInt", + "description": "The interval between each health check", + "default_value": 60, + "optional": true + }, + { + "name": "method", + "type": "TypeString", + "description": "The method to use for the health check", + "options": "GET, HEAD", + "optional": true, + "computed": true + }, + { + "name": "headers", + "type": "TypeSet", + "description": "The HTTP request headers to send in the health check", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of HTTP request header", + "required": true + }, + "value": { + "name": "value", + "type": "TypeList", + "description": "The value of HTTP request header", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "retries", + "type": "TypeInt", + "description": "The number of retries to attempt in case of a timeout before marking the origin as unhealthy", + "default_value": 1, + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "GLB Monitor creation date", + "computed": true + } + ], + "ibm_dns_glb_pool": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance Id", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "pool_id", + "type": "TypeString", + "description": "Pool Id", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique identifier of a service instance.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Descriptive text of the load balancer pool", + "optional": true + }, + { + "name": "healthy_origins_threshold", + "type": "TypeInt", + "description": "The minimum number of origins that must be healthy for this pool to serve traffic", + "optional": true + }, + { + "name": "healthcheck_subnets", + "type": "TypeList", + "description": "Health check subnet crn of VSIs", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "health", + "type": "TypeString", + "description": "Whether the load balancer pool is enabled", + "computed": true + }, + { + "name": "origins", + "type": "TypeSet", + "description": "Origins info", + "required": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The address of the origin server. It can be a hostname or an IP address.", + "required": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the origin server.", + "optional": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the origin server is enabled.", + "required": true + }, + "health": { + "name": "health", + "type": "TypeBool", + "description": "Whether the health is `true` or `false`.", + "computed": true + }, + "health_failure_reason": { + "name": "health_failure_reason", + "type": "TypeString", + "description": "The Reason for health check failure", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the origin server.", + "required": true + } + } + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the load balancer pool is enabled", + "optional": true + }, + { + "name": "monitor", + "type": "TypeString", + "description": "The ID of the load balancer monitor to be associated to this pool", + "optional": true + }, + { + "name": "healthcheck_region", + "type": "TypeString", + "description": "Health check region of VSIs", + "optional": true + }, + { + "name": "notification_channel", + "type": "TypeString", + "description": "The notification channel,It is a webhook url", + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "The time when a load balancer pool is created.", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "The recent time when a load balancer pool is modified.", + "computed": true + } + ], + "ibm_dns_permitted_network": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance Id", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone Id", + "immutable": true, + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Network Type", + "default_value": "vpc", + "immutable": true, + "optional": true + }, + { + "name": "vpc_crn", + "type": "TypeString", + "description": "VPC CRN id", + "immutable": true, + "required": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Network creation date", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Network Modification date", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Network status", + "computed": true + }, + { + "name": "permitted_network_id", + "type": "TypeString", + "description": "Network Id", + "computed": true + } + ], + "ibm_dns_record": [ + { + "name": "type", + "type": "TypeString", + "description": "DNS record type", + "immutable": true, + "required": true + }, + { + "name": "service", + "type": "TypeString", + "description": "service info", + "optional": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "priority info", + "default_value": 0, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "tags set for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host", + "type": "TypeString", + "description": "Hostname", + "required": true + }, + { + "name": "minimum_ttl", + "type": "TypeInt", + "description": "Minimun TTL configuration", + "optional": true, + "computed": true + }, + { + "name": "ttl", + "type": "TypeInt", + "description": "TTL configuration", + "required": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "protocol info", + "optional": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "port number", + "optional": true + }, + { + "name": "weight", + "type": "TypeInt", + "description": "weight info", + "default_value": 0, + "optional": true + }, + { + "name": "expire", + "type": "TypeInt", + "description": "DNS record expiry info", + "optional": true, + "computed": true + }, + { + "name": "refresh", + "type": "TypeInt", + "description": "refresh rate", + "optional": true, + "computed": true + }, + { + "name": "retry", + "type": "TypeInt", + "description": "Retry count", + "optional": true, + "computed": true + }, + { + "name": "data", + "type": "TypeString", + "description": "DNS record data", + "required": true + }, + { + "name": "mx_priority", + "type": "TypeInt", + "description": "Maximum priority", + "default_value": 0, + "optional": true + }, + { + "name": "domain_id", + "type": "TypeInt", + "description": "Domain ID of dns record instance", + "immutable": true, + "required": true + }, + { + "name": "responsible_person", + "type": "TypeString", + "description": "Responsible person for DNS record", + "optional": true, + "computed": true + } + ], + "ibm_dns_resource_record": [ + { + "name": "weight", + "type": "TypeInt", + "description": "DNS server weight", + "default_value": 0, + "optional": true + }, + { + "name": "service", + "type": "TypeString", + "description": "Service info", + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Creation Data", + "computed": true + }, + { + "name": "rdata", + "type": "TypeString", + "description": "DNS record Data", + "required": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "DNS server Priority", + "default_value": 0, + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "DNS record Type", + "immutable": true, + "required": true + }, + { + "name": "preference", + "type": "TypeInt", + "description": "DNS maximum preference", + "default_value": 0, + "optional": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "DNS server Port", + "optional": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Protocol", + "optional": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Modification date", + "computed": true + }, + { + "name": "resource_record_id", + "type": "TypeString", + "description": "Resource record ID", + "computed": true + }, + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone ID", + "immutable": true, + "required": true + }, + { + "name": "ttl", + "type": "TypeInt", + "description": "DNS record TTL", + "default_value": 900, + "optional": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + }, + { + "name": "name", + "type": "TypeString", + "description": "DNS record name", + "required": true + } + ], + "ibm_dns_reverse_record": [ + { + "name": "ipaddress", + "type": "TypeString", + "description": "IP Address", + "immutable": true, + "required": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Host name", + "required": true + }, + { + "name": "ttl", + "type": "TypeInt", + "description": "TTL value", + "optional": true + } + ], + "ibm_dns_secondary": [ + { + "name": "zone_name", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "status_id", + "type": "TypeInt", + "description": "Status ID", + "computed": true + }, + { + "name": "status_text", + "type": "TypeString", + "description": "Status text", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "master_ip_address", + "type": "TypeString", + "description": "Master IP Address", + "required": true + }, + { + "name": "transfer_frequency", + "type": "TypeInt", + "description": "Transfer frequency value", + "required": true + } + ], + "ibm_dns_zone": [ + { + "name": "zone_id", + "type": "TypeString", + "description": "Zone ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Zone description", + "optional": true + }, + { + "name": "state", + "type": "TypeString", + "description": "Zone state", + "computed": true + }, + { + "name": "label", + "type": "TypeString", + "description": "Label", + "optional": true + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Creation date", + "computed": true + }, + { + "name": "modified_on", + "type": "TypeString", + "description": "Modification date", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:dns-svcs" + ] + } + ], + "ibm_en_destination": [ + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination Webhook.", + "required": true, + "options": "webhook", + "min_length": 1 + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "custom_headers": { + "name": "custom_headers", + "type": "TypeMap", + "description": "Custom headers (Key-Value pair) for webhook call.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "sensitive_headers": { + "name": "sensitive_headers", + "type": "TypeList", + "description": "List of sensitive headers from custom headers.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of webhook.", + "optional": true + }, + "verb": { + "name": "verb", + "type": "TypeString", + "description": "HTTP method of webhook.", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + } + ], + "ibm_en_destination_android": [ + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "sender_id": { + "name": "sender_id", + "type": "TypeString", + "description": "The Sender_id value for FCM project.", + "required": true + }, + "server_key": { + "name": "server_key", + "type": "TypeString", + "description": "The Server_key value for FCM project.", + "required": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination push_android.", + "required": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + } + ], + "ibm_en_destination_chrome": [ + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "api_key": { + "name": "api_key", + "type": "TypeString", + "description": "The api key for chrome app authorization", + "secure": true, + "optional": true + }, + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The website url", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination type push_chrome.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_destination_firefox": [ + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination type push_firefox.", + "required": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The website url", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + } + ], + "ibm_en_destination_ios": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "The Certificate File.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination type push_ios.", + "required": true + }, + { + "name": "certificate_content_type", + "type": "TypeString", + "description": "The Certificate Content Type to be set p8/p12.", + "required": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "bundle_id": { + "name": "bundle_id", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "optional": true + }, + "cert_type": { + "name": "cert_type", + "type": "TypeString", + "description": "The Certificate Type for IOS, the values are p8/p12.", + "required": true + }, + "is_sandbox": { + "name": "is_sandbox", + "type": "TypeBool", + "description": "The flag to determine sandbox or production environment.", + "required": true + }, + "key_id": { + "name": "key_id", + "type": "TypeString", + "description": "The Key ID In case of P8 Certificate", + "optional": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The Password for APNS Certificate in case of P12 certificate", + "secure": true, + "optional": true + }, + "team_id": { + "name": "team_id", + "type": "TypeString", + "description": "The Team ID In case of P8 Certificate", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_en_destination_safari": [ + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination type push_ios.", + "required": true + }, + { + "name": "icon_16x16", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_32x32_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_128x128_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "icon_16x16_2x", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_32x32_2x", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_128x128_2x", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_16x16_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_32x32_2x_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "certificate", + "type": "TypeString", + "description": "The Certificate File.", + "required": true + }, + { + "name": "icon_32x32", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_16x16_2x_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "cert_type": { + "name": "cert_type", + "type": "TypeString", + "description": "The Certificate Type for IOS, the values are p8/p12.", + "required": true + }, + "password": { + "name": "password", + "type": "TypeString", + "description": "The Password for APNS Certificate in case of P12 certificate", + "secure": true, + "required": true + }, + "url_format_string": { + "name": "url_format_string", + "type": "TypeString", + "description": "The Key ID In case of P8 Certificate", + "optional": true + }, + "website_name": { + "name": "website_name", + "type": "TypeString", + "description": "The Team ID In case of P8 Certificate", + "optional": true + }, + "website_push_id": { + "name": "website_push_id", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "optional": true + }, + "website_url": { + "name": "website_url", + "type": "TypeString", + "description": "The Bundle ID In case of P8 Certificate", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "icon_128x128", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + }, + { + "name": "icon_128x128_2x_content_type", + "type": "TypeString", + "description": "The Certificate File.", + "optional": true + } + ], + "ibm_en_destination_slack": [ + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination Webhook.", + "required": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "url": { + "name": "url", + "type": "TypeString", + "description": "Slack webhook url.", + "required": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + } + ], + "ibm_en_destination_webhook": [ + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "subscription_names", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of Destination Webhook.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Destination description.", + "optional": true + }, + { + "name": "config", + "type": "TypeList", + "description": "Payload describing a destination configuration.", + "optional": true, + "elem": { + "params": { + "name": "params", + "type": "TypeList", + "optional": true, + "elem": { + "custom_headers": { + "name": "custom_headers", + "type": "TypeMap", + "description": "Custom headers (Key-Value pair) for webhook call.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "sensitive_headers": { + "name": "sensitive_headers", + "type": "TypeList", + "description": "List of sensitive headers from custom headers.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "url": { + "name": "url", + "type": "TypeString", + "description": "URL of webhook.", + "required": true + }, + "verb": { + "name": "verb", + "type": "TypeString", + "description": "HTTP method of webhook.", + "required": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "The Destintion name.", + "required": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + } + ], + "ibm_en_source": [ + { + "name": "enabled", + "type": "TypeBool", + "description": "The enabled flag for source", + "required": true + }, + { + "name": "source_id", + "type": "TypeString", + "description": "Destination ID", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The Source name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The Source description.", + "optional": true + } + ], + "ibm_en_subscription": [ + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination Webhook.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "required": true + }, + { + "name": "attributes", + "type": "TypeList", + "optional": true, + "elem": { + "add_notification_payload": { + "name": "add_notification_payload", + "type": "TypeBool", + "description": "Whether to add the notification payload to the email.", + "optional": true + }, + "from_name": { + "name": "from_name", + "type": "TypeString", + "description": "The email address from.", + "optional": true + }, + "remove": { + "name": "remove", + "type": "TypeList", + "description": "The Email address to remove the recepient from smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "reply_to": { + "name": "reply_to", + "type": "TypeString", + "description": "The email address to reply to.", + "optional": true + }, + "reply_to_name": { + "name": "reply_to_name", + "type": "TypeString", + "description": "The name of the email address user to reply to.", + "optional": true + }, + "signing_enabled": { + "name": "signing_enabled", + "type": "TypeBool", + "description": "Signing webhook attributes.", + "optional": true + }, + "to": { + "name": "to", + "type": "TypeList", + "description": "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + "optional": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1 + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "from", + "type": "TypeString", + "description": "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + } + ], + "ibm_en_subscription_android": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + } + ], + "ibm_en_subscription_chrome": [ + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + } + ], + "ibm_en_subscription_email": [ + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "attributes", + "type": "TypeList", + "optional": true, + "elem": { + "add": { + "name": "add", + "type": "TypeList", + "description": "The Email address which should be added to smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "add_notification_payload": { + "name": "add_notification_payload", + "type": "TypeBool", + "description": "Whether to add the notification payload to the email.", + "optional": true + }, + "from_name": { + "name": "from_name", + "type": "TypeString", + "description": "The email address from which email is sourced.", + "optional": true + }, + "invited": { + "name": "invited", + "type": "TypeList", + "description": "The Email address send the invite to in case of smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "reply_to_mail": { + "name": "reply_to_mail", + "type": "TypeString", + "description": "The email address to reply to.", + "optional": true + }, + "reply_to_name": { + "name": "reply_to_name", + "type": "TypeString", + "description": "The name of the email address user to reply to.", + "optional": true + }, + "to": { + "name": "to", + "type": "TypeList", + "description": "The email id in case of smtp_ibm destination type.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "unsubscribed": { + "name": "unsubscribed", + "type": "TypeList", + "description": "The Email address which should be unsubscribed from smtp_ibm.", + "optional": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1 + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "from", + "type": "TypeString", + "description": "From Email ID (it will be displayed only in case of smtp_ibm destination type).", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + } + ], + "ibm_en_subscription_firefox": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + } + ], + "ibm_en_subscription_ios": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + } + ], + "ibm_en_subscription_safari": [ + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + } + ], + "ibm_en_subscription_slack": [ + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "attributes", + "type": "TypeList", + "optional": true, + "elem": { + "attachment_color": { + "name": "attachment_color", + "type": "TypeString", + "description": "attachment color code", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_subscription_sms": [ + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destination name.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "attributes", + "type": "TypeList", + "optional": true, + "elem": { + "to": { + "name": "to", + "type": "TypeList", + "description": "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + "optional": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1 + } + ], + "ibm_en_subscription_webhook": [ + { + "name": "description", + "type": "TypeString", + "description": "Subscription description.", + "optional": true + }, + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "immutable": true, + "required": true + }, + { + "name": "subscription_id", + "type": "TypeString", + "description": "Subscription ID.", + "computed": true + }, + { + "name": "destination_type", + "type": "TypeString", + "description": "The type of Destination.", + "computed": true + }, + { + "name": "destination_name", + "type": "TypeString", + "description": "The Destintion name.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subscription name.", + "required": true + }, + { + "name": "destination_id", + "type": "TypeString", + "description": "Destination ID.", + "immutable": true, + "required": true + }, + { + "name": "attributes", + "type": "TypeList", + "optional": true, + "elem": { + "signing_enabled": { + "name": "signing_enabled", + "type": "TypeBool", + "description": "Signing webhook attributes.", + "default_value": false, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "topic_name", + "type": "TypeString", + "description": "Name of the topic.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time.", + "computed": true + } + ], + "ibm_en_topic": [ + { + "name": "topic_id", + "type": "TypeString", + "description": "Topic ID.", + "computed": true + }, + { + "name": "subscription_count", + "type": "TypeInt", + "description": "Number of subscriptions.", + "computed": true + }, + { + "name": "instance_guid", + "type": "TypeString", + "description": "Unique identifier for IBM Cloud Event Notifications instance.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the topic.", + "required": true + }, + { + "name": "sources", + "type": "TypeList", + "description": "List of sources.", + "optional": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the source.", + "required": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "List of rules.", + "optional": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the rule is enabled or not.", + "default_value": true, + "optional": true + }, + "event_type_filter": { + "name": "event_type_filter", + "type": "TypeString", + "description": "Event type filter.", + "required": true + }, + "notification_filter": { + "name": "notification_filter", + "type": "TypeString", + "description": "Notification filter.", + "default_value": "", + "optional": true + } + } + } + } + }, + { + "name": "subscriptions", + "type": "TypeList", + "description": "List of subscriptions.", + "computed": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the subscription.", + "optional": true + }, + "destination_id": { + "name": "destination_id", + "type": "TypeString", + "description": "ID of the destination.", + "computed": true + }, + "destination_type": { + "name": "destination_type", + "type": "TypeString", + "description": "The type of destination.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "ID of the subscription.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the subscription.", + "computed": true + }, + "topic_id": { + "name": "topic_id", + "type": "TypeString", + "description": "ID of the topic.", + "computed": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Last updated time of the subscription.", + "computed": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the topic.", + "optional": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Last time the topic was updated.", + "computed": true + }, + { + "name": "source_count", + "type": "TypeInt", + "description": "Number of sources.", + "computed": true + } + ], + "ibm_enterprise": [ + { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the enterprise.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the enterprise. This field must have 3 - 60 characters.", + "required": true + }, + { + "name": "primary_contact_iam_id", + "type": "TypeString", + "description": "The IAM ID of the enterprise primary contact, such as `IBMid-0123ABC`. The IAM ID must already exist.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the enterprise.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the enterprise.", + "computed": true + }, + { + "name": "primary_contact_email", + "type": "TypeString", + "description": "The email of the primary contact of the enterprise.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the enterprise was created.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the enterprise was last updated.", + "computed": true + }, + { + "name": "source_account_id", + "type": "TypeString", + "description": "The ID of the account that is used to create the enterprise.", + "immutable": true, + "required": true + }, + { + "name": "domain", + "type": "TypeString", + "description": "A domain or subdomain for the enterprise, such as `example.com` or `my.example.com`.", + "optional": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The URL of the enterprise.", + "computed": true + }, + { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the enterprise.", + "computed": true + } + ], + "ibm_enterprise_account": [ + { + "name": "owner_iam_id", + "type": "TypeString", + "description": "The IAM ID of the account owner, such as `IBMid-0123ABC`. The IAM ID must already exist.", + "immutable": true, + "optional": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the account.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the account. This field must have 3 - 60 characters.", + "immutable": true, + "optional": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The URL of the account.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the account was last updated.", + "computed": true + }, + { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "optional": true, + "computed": true + }, + { + "name": "enterprise_id", + "type": "TypeString", + "description": "The enterprise ID that the account is a part of.", + "optional": true, + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The source account id of account to be imported", + "optional": true, + "computed": true + }, + { + "name": "enterprise_path", + "type": "TypeString", + "description": "The path from the enterprise to this particular account.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the account.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the account was created.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the account.", + "computed": true + }, + { + "name": "parent", + "type": "TypeString", + "description": "The CRN of the parent under which the account will be created. The parent can be an existing account group or the enterprise itself.", + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the account.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "paid", + "type": "TypeBool", + "description": "The type of account - whether it is free or paid.", + "computed": true + }, + { + "name": "owner_email", + "type": "TypeString", + "description": "The email address of the owner of the account.", + "computed": true + }, + { + "name": "is_enterprise_account", + "type": "TypeBool", + "description": "The flag to indicate whether the account is an enterprise account or not.", + "computed": true + } + ], + "ibm_enterprise_account_group": [ + { + "name": "primary_contact_email", + "type": "TypeString", + "description": "The email address of the primary contact of the account group.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The time stamp at which the account group was last updated.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that updated the account group.", + "computed": true + }, + { + "name": "parent", + "type": "TypeString", + "description": "The CRN of the parent under which the account group will be created. The parent can be an existing account group or the enterprise itself.", + "immutable": true, + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the account group.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "enterprise_account_id", + "type": "TypeString", + "description": "The enterprise account ID.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time stamp at which the account group was created.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The IAM ID of the user or service that created the account group.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the account group. This field must have 3 - 60 characters.", + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "The URL of the account group.", + "computed": true + }, + { + "name": "primary_contact_iam_id", + "type": "TypeString", + "description": "The IAM ID of the primary contact for this account group, such as `IBMid-0123ABC`. The IAM ID must already exist.", + "required": true + }, + { + "name": "enterprise_id", + "type": "TypeString", + "description": "The enterprise ID that the account group is a part of.", + "computed": true + }, + { + "name": "enterprise_path", + "type": "TypeString", + "description": "The path from the enterprise to this particular account group.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the account group.", + "computed": true + } + ], + "ibm_event_streams_schema": [ + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The ID or the CRN of the Event Streams service instance", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:event-streams" + ] + }, + { + "name": "kafka_http_url", + "type": "TypeString", + "description": "The API endpoint for interacting with an Event Streams REST API", + "computed": true + }, + { + "name": "schema", + "type": "TypeString", + "description": "The schema in JSON format", + "required": true + }, + { + "name": "schema_id", + "type": "TypeString", + "description": "The ID to be assigned to schema, which must be unique. If this value is not specified, a generated UUID is assigned.", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_event_streams_topic": [ + { + "name": "config", + "type": "TypeMap", + "description": "The configuration parameters of a topic", + "optional": true + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The CRN of the Event Streams instance", + "cloud_data_type": "resource_instance", + "required": true, + "cloud_data_range": [ + "service:event-streams" + ] + }, + { + "name": "kafka_http_url", + "type": "TypeString", + "description": "API endpoint for interacting with Event Streams REST API", + "computed": true + }, + { + "name": "kafka_brokers_sasl", + "type": "TypeList", + "description": "Kafka brokers addresses for interacting with Kafka native API", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the topic", + "required": true + }, + { + "name": "partitions", + "type": "TypeInt", + "description": "The number of partitions", + "default_value": 1, + "optional": true + } + ], + "ibm_firewall": [ + { + "name": "password", + "type": "TypeString", + "description": "Password for the given User", + "computed": true + }, + { + "name": "firewall_type", + "type": "TypeString", + "description": "Firewall type", + "default_value": "HARDWARE_FIREWALL_DEDICATED", + "immutable": true, + "optional": true + }, + { + "name": "ha_enabled", + "type": "TypeBool", + "description": "set to true if High availability is enabled", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "description": "Public VLAN ID", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for the firewall", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "location", + "type": "TypeString", + "description": "Location info", + "cloud_data_type": "region", + "computed": true + }, + { + "name": "primary_ip", + "type": "TypeString", + "description": "Primary IP address", + "computed": true + }, + { + "name": "username", + "type": "TypeString", + "description": "User name", + "computed": true + } + ], + "ibm_firewall_policy": [ + { + "name": "firewall_id", + "type": "TypeInt", + "description": "Firewall ID", + "immutable": true, + "required": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Policy rules info", + "required": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "required": true + }, + "dst_ip_address": { + "name": "dst_ip_address", + "type": "TypeString", + "required": true + }, + "dst_ip_cidr": { + "name": "dst_ip_cidr", + "type": "TypeInt", + "required": true + }, + "dst_port_range_end": { + "name": "dst_port_range_end", + "type": "TypeInt", + "optional": true + }, + "dst_port_range_start": { + "name": "dst_port_range_start", + "type": "TypeInt", + "optional": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "optional": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "required": true + }, + "src_ip_address": { + "name": "src_ip_address", + "type": "TypeString", + "required": true + }, + "src_ip_cidr": { + "name": "src_ip_cidr", + "type": "TypeInt", + "required": true + } + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_function_action": [ + { + "name": "parameters", + "type": "TypeString", + "description": "All paramters set on action by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "IBM Cloud function namespace.", + "immutable": true, + "required": true + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Action visibilty.", + "optional": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the item.", + "computed": true + }, + { + "name": "user_defined_parameters", + "type": "TypeString", + "description": "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the action.", + "default_value": "[]", + "optional": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on action by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "action_id", + "type": "TypeString", + "computed": true + }, + { + "name": "target_endpoint_url", + "type": "TypeString", + "description": "Action target endpoint URL.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of action.", + "immutable": true, + "required": true, + "matches": "^[^/*][a-zA-Z0-9/_@.-]" + }, + { + "name": "limits", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "log_size": { + "name": "log_size", + "type": "TypeInt", + "description": "The maximum log size LIMIT in MB for the action.", + "default_value": 10, + "optional": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The maximum memory LIMIT in MB for the action (default 256.", + "default_value": 256, + "optional": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "description": "The timeout LIMIT in milliseconds after which the action is terminated.", + "default_value": 60000, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "exec", + "type": "TypeList", + "description": "Execution info", + "required": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "The code to execute.", + "optional": true, + "computed": true + }, + "code_path": { + "name": "code_path", + "type": "TypeString", + "description": "The file path of code to execute.", + "optional": true + }, + "components": { + "name": "components", + "type": "TypeList", + "description": "The List of fully qualified action.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "image": { + "name": "image", + "type": "TypeString", + "description": "Container image name when kind is 'blackbox'.", + "optional": true + }, + "init": { + "name": "init", + "type": "TypeString", + "description": "Optional zipfile reference.", + "optional": true + }, + "kind": { + "name": "kind", + "type": "TypeString", + "description": "The type of action. Possible values can be found here (https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-runtimes)", + "required": true + }, + "main": { + "name": "main", + "type": "TypeString", + "description": "The name of the action entry point (function or fully-qualified method name when applicable).", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "user_defined_annotations", + "type": "TypeString", + "description": "Annotation values in KEY VALUE format.", + "default_value": "[]", + "optional": true + } + ], + "ibm_function_namespace": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of namespace.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Namespace Description.", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "Resource Group ID.", + "immutable": true, + "required": true + }, + { + "name": "location", + "type": "TypeString", + "description": "Namespace Location.", + "cloud_data_type": "region", + "computed": true + } + ], + "ibm_function_package": [ + { + "name": "publish", + "type": "TypeBool", + "description": "Package visibilty.", + "default_value": false, + "optional": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on package by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeString", + "description": "All parameters set on package by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "user_defined_parameters", + "type": "TypeString", + "description": "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the package.", + "default_value": "[]", + "optional": true + }, + { + "name": "bind_package_name", + "type": "TypeString", + "description": "Name of package to be binded.", + "immutable": true, + "optional": true + }, + { + "name": "package_id", + "type": "TypeString", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "IBM Cloud function namespace.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of package.", + "immutable": true, + "required": true, + "matches": "\\A([\\w]|[\\w][\\w@ .-]*[\\w@.-]+)\\z" + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the item.", + "computed": true + }, + { + "name": "user_defined_annotations", + "type": "TypeString", + "description": "Annotation values in KEY VALUE format.", + "default_value": "[]", + "optional": true + } + ], + "ibm_function_rule": [ + { + "name": "rule_id", + "type": "TypeString", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "IBM Cloud function namespace.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of rule.", + "immutable": true, + "required": true, + "matches": "\\A([\\w]|[\\w][\\w@ .-]*[\\w@.-]+)\\z" + }, + { + "name": "trigger_name", + "type": "TypeString", + "description": "Name of trigger.", + "required": true + }, + { + "name": "action_name", + "type": "TypeString", + "description": "Name of action.", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of the rule.", + "computed": true + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Rule visbility.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the item.", + "computed": true + } + ], + "ibm_function_trigger": [ + { + "name": "user_defined_annotations", + "type": "TypeString", + "description": "Annotation values in KEY VALUE format.", + "default_value": "[]", + "optional": true + }, + { + "name": "user_defined_parameters", + "type": "TypeString", + "description": "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the trigger.", + "default_value": "[]", + "optional": true + }, + { + "name": "annotations", + "type": "TypeString", + "description": "All annotations set on trigger by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "parameters", + "type": "TypeString", + "description": "All parameters set on trigger by user and those set by the IBM Cloud Function backend/API.", + "computed": true + }, + { + "name": "trigger_id", + "type": "TypeString", + "computed": true + }, + { + "name": "feed", + "type": "TypeList", + "description": "Trigger feed", + "immutable": true, + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Trigger feed ACTION_NAME.", + "immutable": true, + "required": true + }, + "parameters": { + "name": "parameters", + "type": "TypeString", + "description": "Parameters values in KEY VALUE format. Parameter bindings included in the context passed to the action invoke.", + "default_value": "[]", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of Trigger.", + "immutable": true, + "required": true, + "matches": "\\A([\\w]|[\\w][\\w@ .-]*[\\w@.-]+)\\z" + }, + { + "name": "publish", + "type": "TypeBool", + "description": "Trigger visbility.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Semantic version of the item.", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "IBM Cloud function namespace.", + "immutable": true, + "required": true + } + ], + "ibm_hardware_firewall_shared": [ + { + "name": "billing_item_id", + "type": "TypeInt", + "description": "Billing Item ID", + "computed": true + }, + { + "name": "firewall_type", + "type": "TypeString", + "description": "Firewall type", + "immutable": true, + "required": true + }, + { + "name": "virtual_instance_id", + "type": "TypeInt", + "description": "Virtual instance ID", + "immutable": true, + "optional": true + }, + { + "name": "hardware_instance_id", + "type": "TypeInt", + "description": "Hardware instance ID", + "immutable": true, + "optional": true + } + ], + "ibm_hpcs": [ + { + "name": "failover_units", + "type": "TypeInt", + "description": "The number of failover crypto units for your service instance", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of HPCS instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of HPCS instance", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The subject who created the instance.", + "computed": true + }, + { + "name": "deleted_by", + "type": "TypeString", + "description": "The subject who deleted the instance.", + "computed": true + }, + { + "name": "units", + "type": "TypeInt", + "description": "The number of operational crypto units for your service instance", + "required": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the service offering `hs-crypto`", + "default_value": "hs-crypto", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "scheduled_reclaim_by", + "type": "TypeString", + "description": "The subject who initiated the instance reclamation.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A name for the HPCS instance", + "required": true + }, + { + "name": "service_endpoints", + "type": "TypeString", + "description": "Types of the service endpoints. Possible values are `public-and-private`, `private-only`.", + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "update_at", + "type": "TypeString", + "description": "The date when the instance was last updated.", + "computed": true + }, + { + "name": "deleted_at", + "type": "TypeString", + "description": "The date when the instance was deleted.", + "computed": true + }, + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the HPCS instance.", + "computed": true + }, + { + "name": "admins", + "type": "TypeSet", + "description": "Crypto Unit Administrators", + "required": true, + "elem": { + "key": { + "name": "key", + "type": "TypeString", + "description": "The administrator signature key", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Admin Name", + "required": true + }, + "token": { + "name": "token", + "type": "TypeString", + "description": "Credential giving access to the administrator signature key", + "secure": true, + "required": true + } + } + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the HPCS Instance", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of HPCS instance", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The current state of the instance.", + "computed": true + }, + { + "name": "resource_aliases_url", + "type": "TypeString", + "description": "The relative path to the resource aliases for the instance.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the instance was created.", + "computed": true + }, + { + "name": "update_by", + "type": "TypeString", + "description": "The subject who updated the instance.", + "computed": true + }, + { + "name": "restored_by", + "type": "TypeString", + "description": "The subject who restored the instance back from reclamation.", + "computed": true + }, + { + "name": "revocation_threshold", + "type": "TypeInt", + "description": "Revocation Threshold Value", + "required": true + }, + { + "name": "hsm_info", + "type": "TypeList", + "description": "HSM Configuration", + "computed": true, + "elem": { + "admins": { + "name": "admins", + "type": "TypeSet", + "description": "Crypto Unit Administrators", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Admin Name", + "computed": true + }, + "ski": { + "name": "ski", + "type": "TypeString", + "computed": true + } + } + }, + "current_mk_status": { + "name": "current_mk_status", + "type": "TypeString", + "computed": true + }, + "current_mkvp": { + "name": "current_mkvp", + "type": "TypeString", + "computed": true + }, + "hsm_id": { + "name": "hsm_id", + "type": "TypeString", + "computed": true + }, + "hsm_location": { + "name": "hsm_location", + "type": "TypeString", + "computed": true + }, + "hsm_type": { + "name": "hsm_type", + "type": "TypeString", + "computed": true + }, + "new_mk_status": { + "name": "new_mk_status", + "type": "TypeString", + "computed": true + }, + "new_mkvp": { + "name": "new_mkvp", + "type": "TypeString", + "computed": true + }, + "revocation_threshold": { + "name": "revocation_threshold", + "type": "TypeInt", + "description": "Revocation Threshold Value", + "computed": true + }, + "signature_threshold": { + "name": "signature_threshold", + "type": "TypeInt", + "description": "Signature Threshold Value", + "computed": true + } + } + }, + { + "name": "resource_keys_url", + "type": "TypeString", + "description": "The relative path to the resource keys for the instance.", + "computed": true + }, + { + "name": "scheduled_reclaim_at", + "type": "TypeString", + "description": "The date when the instance was scheduled for reclamation.", + "computed": true + }, + { + "name": "restored_at", + "type": "TypeString", + "description": "The date when the instance under reclamation was restored.", + "computed": true + }, + { + "name": "signature_threshold", + "type": "TypeInt", + "description": "Signature Threshold Value", + "required": true + }, + { + "name": "resource_bindings_url", + "type": "TypeString", + "description": "The relative path to the resource bindings for the instance.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location where the HPCS instance available", + "cloud_data_type": "region", + "required": true + }, + { + "name": "dashboard_url", + "type": "TypeString", + "description": "Dashboard URL to access resource.", + "computed": true + }, + { + "name": "signature_server_url", + "type": "TypeString", + "description": "URL of signing service", + "optional": true + } + ], + "ibm_hpcs_key_template": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the template, it will be referenced when creating managed keys.", + "required": true, + "min_length": 1, + "max_length": 30, + "matches": "^[A-Za-z][A-Za-z0-9-]*$" + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the key template.", + "max_length": 200, + "matches": "(.|\\\\n)*", + "optional": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the key template was updated.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key template.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "immutable": true, + "required": true, + "options": "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao" + }, + { + "name": "key", + "type": "TypeList", + "description": "Properties describing the properties of the managed key.", + "required": true, + "elem": { + "activation_date": { + "name": "activation_date", + "type": "TypeString", + "description": "Key activation date can be provided as a period definition (e.g. PY1 means 1 year).", + "required": true + }, + "algorithm": { + "name": "algorithm", + "type": "TypeString", + "description": "The algorithm of the key.", + "required": true + }, + "expiration_date": { + "name": "expiration_date", + "type": "TypeString", + "description": "Key expiration date can be provided as a period definition (e.g. PY1 means 1 year).", + "required": true + }, + "size": { + "name": "size", + "type": "TypeString", + "description": "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + "required": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "The state that the key will be in after generation.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the key template was created.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that updated the key.", + "computed": true + }, + { + "name": "vault", + "type": "TypeList", + "description": "ID of the Vault where the entity is to be created in.", + "required": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "keystores", + "type": "TypeList", + "description": "An array describing the type and group of target keystores the managed key is to be installed in.", + "required": true, + "elem": { + "group": { + "name": "group", + "type": "TypeString", + "description": "Which keystore group to distribute the key to.", + "required": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "required": true + } + } + }, + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "immutable": true, + "required": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_hpcs_keystore": [ + { + "name": "description", + "type": "TypeString", + "description": "Description of the keystore.", + "optional": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the key.", + "computed": true + }, + { + "name": "azure_resource_group", + "type": "TypeString", + "description": "Resource group in Azure.", + "optional": true + }, + { + "name": "azure_environment", + "type": "TypeString", + "description": "Azure environment, usually 'Azure'.", + "optional": true + }, + { + "name": "ibm_api_endpoint", + "type": "TypeString", + "description": "API endpoint of the IBM Cloud keystore.", + "optional": true + }, + { + "name": "vault", + "type": "TypeList", + "description": "Reference to a vault.", + "required": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the referenced vault.", + "computed": true + } + } + }, + { + "name": "ibm_variant", + "type": "TypeString", + "description": "Possible IBM Cloud KMS variants.", + "optional": true + }, + { + "name": "ibm_key_ring", + "type": "TypeString", + "description": "The key ring of an IBM Cloud KMS Keystore.", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the target keystore was created.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "aws_access_key_id", + "type": "TypeString", + "description": "The access key id used for connecting to this instance of AWS KMS.", + "secure": true, + "optional": true + }, + { + "name": "azure_service_principal_password", + "type": "TypeString", + "description": "Azure service principal password.", + "secure": true, + "optional": true + }, + { + "name": "azure_tenant", + "type": "TypeString", + "description": "Azure tenant that the Key Vault is associated with,.", + "optional": true + }, + { + "name": "azure_service_principal_client_id", + "type": "TypeString", + "description": "Azure service principal client ID.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the target keystore. It can be changed in the future.", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "required": true + }, + { + "name": "groups", + "type": "TypeList", + "description": "List of groups that this keystore belongs to.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "immutable": true, + "required": true, + "options": "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao" + }, + { + "name": "aws_region", + "type": "TypeString", + "description": "AWS Region.", + "optional": true + }, + { + "name": "ibm_iam_endpoint", + "type": "TypeString", + "description": "Endpoint of the IAM service for this IBM Cloud keystore.", + "optional": true + }, + { + "name": "ibm_instance_id", + "type": "TypeString", + "description": "The instance ID of the IBM Cloud keystore.", + "optional": true + }, + { + "name": "azure_service_name", + "type": "TypeString", + "description": "Service name of the key vault instance from the Azure portal.", + "optional": true + }, + { + "name": "aws_secret_access_key", + "type": "TypeString", + "description": "The secret access key used for connecting to this instance of AWS KMS.", + "secure": true, + "optional": true + }, + { + "name": "azure_subscription_id", + "type": "TypeString", + "description": "Subscription ID in Azure.", + "optional": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the target keystore was last updated.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "immutable": true, + "required": true + }, + { + "name": "azure_location", + "type": "TypeString", + "description": "Location of the Azure Key Vault.", + "optional": true + }, + { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API key to be used for connecting to this IBM Cloud keystore.", + "secure": true, + "optional": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key.", + "computed": true + } + ], + "ibm_hpcs_managed_key": [ + { + "name": "uko_vault", + "type": "TypeString", + "description": "The UUID of the Vault in which the update is to take place.", + "immutable": true, + "required": true + }, + { + "name": "verification_patterns", + "type": "TypeList", + "description": "A list of verification patterns of the key (e.g. public key hash for RSA keys).", + "computed": true, + "elem": { + "method": { + "name": "method", + "type": "TypeString", + "description": "The method used for calculating the verification pattern.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The calculated value.", + "required": true + } + } + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "algorithm", + "type": "TypeString", + "description": "The algorithm of the key.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the key was created.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "immutable": true, + "required": true, + "options": "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao" + }, + { + "name": "template_name", + "type": "TypeString", + "description": "Name of the key template to use when creating a key.", + "min_length": 1, + "max_length": 30, + "matches": "^[A-Za-z][A-Za-z0-9-]+$", + "optional": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Key-value pairs associated with the key.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of a tag.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of a tag.", + "required": true + } + } + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the key.", + "optional": true, + "computed": true + }, + { + "name": "size", + "type": "TypeString", + "description": "The size of the underlying cryptographic key or key pair. E.g. \"256\" for AES keys, or \"2048\" for RSA.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the key was last updated.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the key.", + "computed": true + }, + { + "name": "referenced_keystores", + "type": "TypeList", + "description": "referenced keystores.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "optional": true, + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the target keystore.", + "optional": true, + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "required": true + } + } + }, + { + "name": "instances", + "type": "TypeList", + "description": "key instances.", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "required": true + }, + "keystore": { + "name": "keystore", + "type": "TypeList", + "description": "Description of properties of a key within the context of keystores.", + "required": true, + "elem": { + "group": { + "name": "group", + "type": "TypeString", + "required": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of keystore.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + "label_in_keystore": { + "name": "label_in_keystore", + "type": "TypeString", + "description": "The label of the key.", + "required": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the key instance.", + "optional": true, + "computed": true + } + } + }, + { + "name": "vault", + "type": "TypeList", + "description": "ID of the Vault where the entity is to be created in.", + "required": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "label", + "type": "TypeString", + "description": "The label of the key.", + "required": true, + "min_length": 1, + "max_length": 100, + "matches": "^[A-Za-z0-9._ -]+$" + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the managed key.", + "max_length": 200, + "matches": "(.|\\\\n)*", + "optional": true + }, + { + "name": "template", + "type": "TypeList", + "description": "Reference to a key template.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "optional": true, + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the resource, as specified by RFC 4122.", + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the key template.", + "optional": true, + "computed": true + } + } + }, + { + "name": "activation_date", + "type": "TypeString", + "description": "First day when the key is active.", + "computed": true + }, + { + "name": "expiration_date", + "type": "TypeString", + "description": "Last day when the key is active.", + "computed": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "The UUID of the key.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the key.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + } + ], + "ibm_hpcs_vault": [ + { + "name": "updated_at", + "type": "TypeString", + "description": "Date and time when the vault was last updated.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "ID of the user that last updated the vault.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "A URL that uniquely identifies your cloud resource.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "region", + "type": "TypeString", + "description": "The region of the UKO instance this resource exists in.", + "immutable": true, + "required": true, + "options": "au-syd, in-che, jp-osa, jp-tok, kr-seo, eu-de, eu-gb, ca-tor, us-south, us-south-test, us-east, br-sao" + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the vault.", + "max_length": 200, + "matches": "(.|\\\\n)*", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Date and time when the vault was created.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "ID of the user that created the vault.", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "The ID of the UKO instance this resource exists in.", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:hs-crypto" + ] + }, + { + "name": "vault_id", + "type": "TypeString", + "description": "The ID of the vault.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A human-readable name to assign to your vault. To protect your privacy, do not use personal data, such as your name or location.", + "required": true, + "min_length": 1, + "max_length": 100, + "matches": "^[A-Za-z][A-Za-z0-9#@!$% '_-]*$" + } + ], + "ibm_iam_access_group": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the access group", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the access group", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_iam_access_group_account_settings": [ + { + "name": "public_access_enabled", + "type": "TypeBool", + "description": "Flag to enable/disable public access groups", + "required": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Id of the account", + "computed": true + } + ], + "ibm_iam_access_group_dynamic_rule": [ + { + "name": "expiration", + "type": "TypeInt", + "description": "The expiration in hours", + "required": true + }, + { + "name": "identity_provider", + "type": "TypeString", + "description": "The realm name or identity proivider url", + "required": true + }, + { + "name": "conditions", + "type": "TypeList", + "description": "conditions info", + "required": true, + "elem": { + "claim": { + "name": "claim", + "type": "TypeString", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "required": true + } + } + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "id of the rule", + "computed": true + }, + { + "name": "access_group_id", + "type": "TypeString", + "description": "Unique identifier of the access group", + "cloud_data_type": "iam", + "required": true, + "cloud_data_range": [ + "service:access_group", + "resolved_to:id" + ] + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the Rule", + "required": true + } + ], + "ibm_iam_access_group_members": [ + { + "name": "access_group_id", + "type": "TypeString", + "description": "Unique identifier of the access group", + "cloud_data_type": "iam", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:access_group", + "resolved_to:id" + ] + }, + { + "name": "ibm_ids", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "iam_service_ids", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "iam_profile_ids", + "type": "TypeSet", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "members", + "type": "TypeList", + "computed": true, + "elem": { + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_iam_access_group_policy": [ + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "optional": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "access_group_id", + "type": "TypeString", + "description": "ID of access group", + "cloud_data_type": "iam", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:access_group", + "resolved_to:id" + ] + }, + { + "name": "resources", + "type": "TypeList", + "optional": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "optional": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "optional": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "optional": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "optional": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "optional": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "resource_attributes", + "type": "TypeSet", + "description": "Set resource attributes.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "account_management", + "type": "TypeBool", + "description": "Give access to all account management services", + "default_value": false, + "optional": true + } + ], + "ibm_iam_account_settings": [ + { + "name": "restrict_create_service_id", + "type": "TypeString", + "description": "Defines whether or not creating a Service Id is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", + "options": "RESTRICTED, NOT_RESTRICTED, NOT_SET", + "optional": true, + "computed": true + }, + { + "name": "restrict_create_platform_apikey", + "type": "TypeString", + "description": "Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value.", + "options": "RESTRICTED, NOT_RESTRICTED, NOT_SET", + "optional": true, + "computed": true + }, + { + "name": "allowed_ip_addresses", + "type": "TypeString", + "description": "Defines the IP addresses and subnets from which IAM tokens can be created for the account.", + "optional": true + }, + { + "name": "history", + "type": "TypeList", + "description": "History of the Account Settings.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action of the history entry.", + "required": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of the identity which triggered the action.", + "required": true + }, + "iam_id_account": { + "name": "iam_id_account", + "type": "TypeString", + "description": "Account of the identity which triggered the action.", + "required": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "Message which summarizes the executed action.", + "required": true + }, + "params": { + "name": "params", + "type": "TypeList", + "description": "Params of the history entry.", + "required": true, + "elem": { + "type": "TypeString" + } + }, + "timestamp": { + "name": "timestamp", + "type": "TypeString", + "description": "Timestamp when the action was triggered.", + "required": true + } + } + }, + { + "name": "session_expiration_in_seconds", + "type": "TypeString", + "description": "Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default.", + "optional": true, + "computed": true + }, + { + "name": "include_history", + "type": "TypeBool", + "description": "Defines if the entity history is included in the response.", + "default_value": false, + "optional": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the account settings.", + "optional": true, + "computed": true + }, + { + "name": "mfa", + "type": "TypeString", + "description": "Defines the MFA trait for the account. Valid values: * NONE - No MFA trait set * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users.", + "options": "NONE, TOTP, TOTP4ALL, LEVEL1, LEVEL2, LEVEL3", + "optional": true, + "computed": true + }, + { + "name": "if_match", + "type": "TypeString", + "description": "Version of the account settings to be updated. Specify the version that you retrieved as entity_tag (ETag header) when reading the account. This value helps identifying parallel usage of this API. Pass * to indicate to update any version available. This might result in stale updates.", + "default_value": "*", + "optional": true + }, + { + "name": "session_invalidation_in_seconds", + "type": "TypeString", + "description": "Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default.", + "optional": true, + "computed": true + }, + { + "name": "max_sessions_per_identity", + "type": "TypeString", + "description": "Defines the max allowed sessions per identity required by the account. Value values: * Any whole number greater than '0' * NOT_SET - To unset account setting and use service default.", + "optional": true, + "computed": true + } + ], + "ibm_iam_api_key": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the API key. The name is not checked for uniqueness. Therefore multiple names with the same value can exist. Access is done via the UUID of the API key.", + "required": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The account ID of the API key.", + "computed": true + }, + { + "name": "entity_lock", + "type": "TypeString", + "description": "Indicates if the API key is locked for further write operations. False by default.", + "default_value": "false", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "IAM ID of the user or service which created the API key.", + "computed": true + }, + { + "name": "file", + "type": "TypeString", + "description": "File where api key is to be stored", + "optional": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "The iam_id that this API key authenticates.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The optional description of the API key. The 'description' property is only available if a description was provided during a create of an API key.", + "optional": true + }, + { + "name": "apikey_id", + "type": "TypeString", + "description": "Unique identifier of this API Key.", + "computed": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "apikey", + "type": "TypeString", + "description": "You can optionally passthrough the API key value for this API key. If passed, NO validation of that apiKey value is done, i.e. the value can be non-URL safe. If omitted, the API key management will create an URL safe opaque API key value. The value of the API key is checked for uniqueness. Please ensure enough variations when passing in this value.", + "secure": true, + "optional": true, + "computed": true + }, + { + "name": "store_value", + "type": "TypeBool", + "description": "Send true or false to set whether the API key value is retrievable in the future by using the Get details of an API key request. If you create an API key for a user, you must specify `false` or omit the value. We don't allow storing of API keys for users.", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678'.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "The API key cannot be changed if set to true.", + "computed": true + } + ], + "ibm_iam_authorization_policy": [ + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "target_service_name", + "type": "TypeString", + "description": "The target service name", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "target_resource_group_id", + "type": "TypeString", + "description": "The target resource group Id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "source_service_account", + "type": "TypeString", + "description": "Account GUID of source service", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "subject_attributes", + "type": "TypeSet", + "description": "Set subject attributes.", + "immutable": true, + "optional": true, + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "source_resource_instance_id", + "type": "TypeString", + "description": "The source resource instance Id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "target_resource_instance_id", + "type": "TypeString", + "description": "The target resource instance Id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "source_resource_group_id", + "type": "TypeString", + "description": "The source resource group Id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "target_resource_type", + "type": "TypeString", + "description": "Resource type of target service", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "optional": true + }, + { + "name": "source_service_name", + "type": "TypeString", + "description": "The source service name", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_attributes", + "type": "TypeSet", + "description": "Set resource attributes.", + "immutable": true, + "optional": true, + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "source_resource_type", + "type": "TypeString", + "description": "Resource type of source service", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_iam_authorization_policy_detach": [ + { + "name": "authorization_policy_id", + "type": "TypeString", + "description": "Authorization policy ID", + "immutable": true, + "required": true + } + ], + "ibm_iam_custom_role": [ + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the custom Role", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 30, + "matches": "^[A-Z]{1}[A-Za-z0-9]{0,29}$" + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the role", + "min_length": 1, + "max_length": 250, + "optional": true + }, + { + "name": "actions", + "type": "TypeList", + "description": "The actions of the role", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "display_name", + "type": "TypeString", + "description": "Display Name of the Custom Role", + "required": true, + "min_length": 1, + "max_length": 50 + }, + { + "name": "service", + "type": "TypeString", + "description": "The Service Name", + "immutable": true, + "required": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "crn of the Custom Role", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_iam_service_api_key": [ + { + "name": "apikey", + "type": "TypeString", + "description": "API key value for this API key", + "secure": true, + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "The API key cannot be changed if set to true", + "optional": true + }, + { + "name": "file", + "type": "TypeString", + "description": "File where api key is to be stored", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "crn of the Service API Key", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time Service API Key was created", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the Service API key", + "required": true + }, + { + "name": "iam_service_id", + "type": "TypeString", + "description": "The service iam_id that this API key authenticates", + "cloud_data_type": "iam", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:service_id", + "resolved_to:id" + ] + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The account ID of the API key", + "computed": true + }, + { + "name": "store_value", + "type": "TypeBool", + "description": "Boolean value deciding whether API key value is retrievable in the future", + "optional": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the API Key details object", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "IAM ID of the service which created the API key", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "The date and time Service API Key was modified", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "description of the API key", + "optional": true, + "computed": true + } + ], + "ibm_iam_service_id": [ + { + "name": "name", + "type": "TypeString", + "description": "Name of the serviceID", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the serviceID", + "optional": true + }, + { + "name": "version", + "type": "TypeString", + "description": "version of the serviceID", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "crn of the serviceID", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "The IAM ID of the serviceID", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "locked", + "type": "TypeBool", + "computed": true + } + ], + "ibm_iam_service_policy": [ + { + "name": "resource_attributes", + "type": "TypeSet", + "description": "Set resource attributes.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "account_management", + "type": "TypeBool", + "description": "Give access to all account management services", + "default_value": false, + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "iam_service_id", + "type": "TypeString", + "description": "UUID of ServiceID", + "cloud_data_type": "iam", + "immutable": true, + "optional": true, + "cloud_data_range": [ + "service:service_id", + "resolved_to:id" + ] + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of ServiceID", + "immutable": true, + "optional": true + }, + { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resources", + "type": "TypeList", + "optional": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "optional": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "optional": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "optional": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "optional": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "optional": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "optional": true + } + ], + "ibm_iam_trusted_profile": [ + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "The iam_id of this trusted profile.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The optional description of the trusted profile. The 'description' property is only available if a description was provided during creation of trusted profile.", + "optional": true + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "Unique identifier of this trusted profile.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name of the item. Example Cloud Resource Name: 'crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c'.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "ims_user_id", + "type": "TypeInt", + "description": "IMS user ID of the trusted profile.", + "computed": true + }, + { + "name": "history", + "type": "TypeList", + "description": "History of the trusted profile.", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Action of the history entry.", + "computed": true + }, + "iam_id": { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of the identity which triggered the action.", + "computed": true + }, + "iam_id_account": { + "name": "iam_id_account", + "type": "TypeString", + "description": "Account of the identity which triggered the action.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "Message which summarizes the executed action.", + "computed": true + }, + "params": { + "name": "params", + "type": "TypeList", + "description": "Params of the history entry.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "timestamp": { + "name": "timestamp", + "type": "TypeString", + "description": "Timestamp when the action was triggered.", + "computed": true + } + } + }, + { + "name": "account_id", + "type": "TypeString", + "description": "The account ID of the trusted profile.", + "computed": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "ims_account_id", + "type": "TypeInt", + "description": "IMS acount ID of the trusted profile.", + "computed": true + } + ], + "ibm_iam_trusted_profile_claim_rule": [ + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile to create a claim rule.", + "cloud_data_type": "iam", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "Unique identifier of this claim rule.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the calim rule, either 'Profile-SAML' or 'Profile-CR'.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the claim rule to be created or updated.", + "optional": true + }, + { + "name": "realm_name", + "type": "TypeString", + "description": "The realm name of the Idp this claim rule applies to. This field is required only if the type is specified as 'Profile-SAML'.", + "optional": true + }, + { + "name": "expiration", + "type": "TypeInt", + "description": "Session expiration in seconds, only required if type is 'Profile-SAML'.", + "optional": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "conditions", + "type": "TypeList", + "description": "Conditions of this claim rule.", + "required": true, + "elem": { + "claim": { + "name": "claim", + "type": "TypeString", + "description": "The claim to evaluate against.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The stringified JSON value that the claim is compared to using the operator.", + "required": true + } + } + }, + { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type the rule applies to, required only if type is specified as 'Profile-CR'. Valid values are VSI, IKS_SA, ROKS_SA.", + "optional": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + } + ], + "ibm_iam_trusted_profile_link": [ + { + "name": "name", + "type": "TypeString", + "description": "Optional name of the Link.", + "immutable": true, + "optional": true + }, + { + "name": "link_id", + "type": "TypeString", + "description": "Unique identifier of this link.", + "computed": true + }, + { + "name": "entity_tag", + "type": "TypeString", + "description": "version of the claim rule.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "If set contains a date time string of the creation date in ISO format.", + "computed": true + }, + { + "name": "modified_at", + "type": "TypeString", + "description": "If set contains a date time string of the last modification date in ISO format.", + "computed": true + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "ID of the trusted profile.", + "cloud_data_type": "iam", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "cr_type", + "type": "TypeString", + "description": "The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA.", + "immutable": true, + "required": true + }, + { + "name": "link", + "type": "TypeList", + "description": "Link details.", + "immutable": true, + "required": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN of the compute resource.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA.", + "optional": true + }, + "namespace": { + "name": "namespace", + "type": "TypeString", + "description": "The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + } + ], + "ibm_iam_trusted_profile_policy": [ + { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_attributes", + "type": "TypeSet", + "description": "Set resource attributes.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "UUID of Trusted Profile", + "cloud_data_type": "iam", + "immutable": true, + "optional": true, + "cloud_data_range": [ + "service:trusted_profile", + "resolved_to:id" + ] + }, + { + "name": "iam_id", + "type": "TypeString", + "description": "IAM ID of Trusted Profile", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resources", + "type": "TypeList", + "optional": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "optional": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "optional": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "optional": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "optional": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "optional": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "account_management", + "type": "TypeBool", + "description": "Give access to all account management services", + "default_value": false, + "optional": true + } + ], + "ibm_iam_user_invite": [ + { + "name": "iam_policy", + "type": "TypeList", + "optional": true, + "elem": { + "account_management": { + "name": "account_management", + "type": "TypeBool", + "description": "Give access to all account management services", + "default_value": false, + "optional": true + }, + "resources": { + "name": "resources", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "optional": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "optional": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "optional": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "optional": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "optional": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "number_of_invited_users", + "type": "TypeInt", + "description": "Number of users invited to an account", + "computed": true + }, + { + "name": "invited_users", + "type": "TypeList", + "computed": true, + "elem": { + "access_groups": { + "name": "access_groups", + "type": "TypeList", + "description": "access group ids to associate the inviting user", + "computed": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the access group", + "computed": true + }, + "policies": { + "name": "policies", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + "user_id": { + "name": "user_id", + "type": "TypeString", + "description": "ibm id or email of user", + "computed": true + }, + "user_policies": { + "name": "user_policies", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "resources": { + "name": "resources", + "type": "TypeList", + "computed": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "computed": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "computed": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "computed": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "computed": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "computed": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "computed": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "computed": true + } + } + }, + "roles": { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "classic_infra_roles", + "type": "TypeList", + "optional": true, + "elem": { + "permission_set": { + "name": "permission_set", + "type": "TypeString", + "description": "permission set for claasic infrastructure", + "optional": true + }, + "permissions": { + "name": "permissions", + "type": "TypeList", + "description": "List of permissions for claasic infrastructure", + "optional": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "cloud_foundry_roles", + "type": "TypeList", + "optional": true, + "elem": { + "org_roles": { + "name": "org_roles", + "type": "TypeList", + "description": "roles to be assigned to user in given space", + "required": true, + "elem": { + "type": "TypeString" + } + }, + "organization_guid": { + "name": "organization_guid", + "type": "TypeString", + "description": "GUID of Organization", + "required": true + }, + "spaces": { + "name": "spaces", + "type": "TypeList", + "optional": true, + "elem": { + "space_guid": { + "name": "space_guid", + "type": "TypeString", + "description": "GUID of space", + "required": true + }, + "space_roles": { + "name": "space_roles", + "type": "TypeList", + "description": "roles to be assigned to user in given space", + "required": true, + "elem": { + "type": "TypeString" + } + } + } + } + } + }, + { + "name": "users", + "type": "TypeSet", + "description": "List of ibm id or email of user", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "access_groups", + "type": "TypeList", + "description": "access group ids to associate the inviting user", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_iam_user_policy": [ + { + "name": "ibm_id", + "type": "TypeString", + "description": "The ibm id or email of user", + "immutable": true, + "required": true + }, + { + "name": "roles", + "type": "TypeList", + "description": "Role names of the policy definition", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resources", + "type": "TypeList", + "optional": true, + "elem": { + "attributes": { + "name": "attributes", + "type": "TypeMap", + "description": "Set resource attributes in the form of 'name=value,name=value....", + "optional": true, + "elem": "schema.ValueType" + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "Region of the policy definition", + "optional": true + }, + "resource": { + "name": "resource", + "type": "TypeString", + "description": "Resource of the policy definition", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "optional": true + }, + "resource_instance_id": { + "name": "resource_instance_id", + "type": "TypeString", + "description": "ID of resource instance of the policy definition", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type of the policy definition", + "optional": true + }, + "service": { + "name": "service", + "type": "TypeString", + "description": "Service name of the policy definition", + "optional": true + }, + "service_type": { + "name": "service_type", + "type": "TypeString", + "description": "Service type of the policy definition", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "resource_attributes", + "type": "TypeSet", + "description": "Set resource attributes.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "account_management", + "type": "TypeBool", + "description": "Give access to all account management services", + "default_value": false, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_tags", + "type": "TypeSet", + "description": "Set access management tags.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of attribute.", + "required": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "Operator of attribute.", + "default_value": "stringEquals", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of attribute.", + "required": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the Policy", + "optional": true + }, + { + "name": "transaction_id", + "type": "TypeString", + "description": "Set transactionID for debug", + "optional": true, + "computed": true + } + ], + "ibm_iam_user_settings": [ + { + "name": "iam_id", + "type": "TypeString", + "description": "User's IAM ID or or email of user", + "immutable": true, + "required": true + }, + { + "name": "allowed_ip_addresses", + "type": "TypeList", + "description": "List of allowed IPv4 or IPv6 addresses", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_ipsec_vpn": [ + { + "name": "service_subnet_id", + "type": "TypeInt", + "description": "Service subnet ID value", + "optional": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "internal_peer_ip_address", + "type": "TypeString", + "computed": true + }, + { + "name": "phase_two", + "type": "TypeList", + "optional": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeString", + "default_value": "MD5", + "optional": true + }, + "diffie_hellman_group": { + "name": "diffie_hellman_group", + "type": "TypeInt", + "default_value": 2, + "optional": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "default_value": "3DES", + "optional": true + }, + "keylife": { + "name": "keylife", + "type": "TypeInt", + "default_value": 3600, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "address_translation", + "type": "TypeList", + "optional": true, + "elem": { + "internal_ip_adress": { + "name": "internal_ip_adress", + "type": "TypeString", + "required": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "optional": true + }, + "remote_ip_adress": { + "name": "remote_ip_adress", + "type": "TypeString", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "customer_peer_ip", + "type": "TypeString", + "description": "Customer Peer IP Address", + "optional": true + }, + { + "name": "remote_subnet_id", + "type": "TypeInt", + "description": "Remote subnet ID value", + "optional": true + }, + { + "name": "remote_subnet", + "type": "TypeList", + "optional": true, + "elem": { + "account_id": { + "name": "account_id", + "type": "TypeInt", + "optional": true + }, + "remote_ip_adress": { + "name": "remote_ip_adress", + "type": "TypeString", + "required": true + }, + "remote_ip_cidr": { + "name": "remote_ip_cidr", + "type": "TypeString", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "computed": true + }, + { + "name": "phase_one", + "type": "TypeList", + "optional": true, + "elem": { + "authentication": { + "name": "authentication", + "type": "TypeString", + "default_value": "MD5", + "optional": true + }, + "diffie_hellman_group": { + "name": "diffie_hellman_group", + "type": "TypeInt", + "default_value": 2, + "optional": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "default_value": "3DES", + "optional": true + }, + "keylife": { + "name": "keylife", + "type": "TypeInt", + "default_value": 14400, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "preshared_key", + "type": "TypeString", + "description": "Preshared Key data", + "optional": true + }, + { + "name": "internal_subnet_id", + "type": "TypeInt", + "description": "Internal subnet ID value", + "optional": true + } + ], + "ibm_is_backup_policy": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "match_resource_types", + "type": "TypeSet", + "description": "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + "min_length": 1, + "max_length": 128, + "matches": "^[a-z][a-z0-9]*(_[a-z0-9]+)*$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "match_user_tags", + "type": "TypeSet", + "description": "The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy.", + "required": true, + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this backup policy. Names must be unique within the region this backup policy resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this backup policy.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy.", + "computed": true + }, + { + "name": "last_job_completed_at", + "type": "TypeString", + "description": "The date and time that the most recent job for this backup policy completed.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the backup policy.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_is_backup_policy_plan": [ + { + "name": "backup_policy_id", + "type": "TypeString", + "description": "The backup policy identifier.", + "immutable": true, + "required": true + }, + { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether the plan is active.", + "optional": true, + "computed": true + }, + { + "name": "deletion_trigger", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "delete_after": { + "name": "delete_after", + "type": "TypeInt", + "description": "The maximum number of days to keep each backup after creation.", + "default_value": 30, + "optional": true + }, + "delete_over_count": { + "name": "delete_over_count", + "type": "TypeString", + "description": "The maximum number of recent backups to keep. If unspecified, there will be no maximum.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this backup policy plan. Names must be unique within the backup policy this plan resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$", + "optional": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this backup policy plan.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "description": "Version of the BackupPolicyPlan.", + "computed": true + }, + { + "name": "backup_policy_plan_id", + "type": "TypeString", + "description": "The backup policy identifier.", + "computed": true + }, + { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for the backup schedule.", + "required": true, + "min_length": 9, + "max_length": 63, + "matches": "^((((\\d+,)+\\d+|([\\d\\*]+(\\/|-)\\d+)|\\d+|\\*) ?){5,7})$" + }, + { + "name": "attach_user_tags", + "type": "TypeSet", + "description": "User tags to attach to each backup (snapshot) created by this plan. If unspecified, no user tags will be attached.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "copy_user_tags", + "type": "TypeBool", + "description": "Indicates whether to copy the source's user tags to the created backups (snapshots).", + "default_value": true, + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the backup policy plan was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + } + ], + "ibm_is_bare_metal_server": [ + { + "name": "cpu", + "type": "TypeList", + "description": "The bare metal server CPU configuration", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The CPU architecture", + "computed": true + }, + "core_count": { + "name": "core_count", + "type": "TypeInt", + "description": "The total number of cores", + "computed": true + }, + "socket_count": { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of CPU sockets", + "computed": true + }, + "threads_per_core": { + "name": "threads_per_core", + "type": "TypeInt", + "description": "The total number of hardware threads per core", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server", + "computed": true + }, + { + "name": "delete_type", + "type": "TypeString", + "description": "Enables stopping type of the bare metal server before deleting", + "default_value": "hard", + "optional": true + }, + { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "required": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "default_value": false, + "optional": true + }, + "allowed_vlans": { + "name": "allowed_vlans", + "type": "TypeSet", + "description": "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + "enable_infrastructure_nat": { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "title: IPv4, The IP address.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the bare metal server", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "image", + "type": "TypeString", + "description": "image id", + "immutable": true, + "required": true + }, + { + "name": "user_data", + "type": "TypeString", + "description": "User data given for the bare metal server", + "immutable": true, + "optional": true + }, + { + "name": "action", + "type": "TypeString", + "description": "This restart/start/stops a bare metal server.", + "options": "start, restart, stop", + "optional": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "The disks for this bare metal server, including any disks that are associated with the boot_target.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this bare metal server disk", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk. Supported values are [ nvme, sata ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes)", + "computed": true + } + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the Bare metal server", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "boot_target", + "type": "TypeString", + "description": "The unique identifier for this bare metal server disk", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this bare metal server", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory, truncated to whole gibibytes", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC the bare metal server is to be a part of", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group name", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Bare metal server name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second)", + "computed": true + }, + { + "name": "network_interfaces", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "allow_interface_to_float": { + "name": "allow_interface_to_float", + "type": "TypeBool", + "description": "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + "optional": true, + "computed": true + }, + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "default_value": false, + "optional": true + }, + "allowed_vlans": { + "name": "allowed_vlans", + "type": "TypeSet", + "description": "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + "enable_infrastructure_nat": { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface. If unspecified, the name will be a hyphenated list of randomly-selected words", + "required": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "title: IPv4, The IP address.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "description": "Collection of security group ids", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "The associated subnet", + "required": true + }, + "vlan": { + "name": "vlan", + "type": "TypeInt", + "description": "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + "optional": true, + "computed": true + } + } + }, + { + "name": "profile", + "type": "TypeString", + "description": "profile name", + "immutable": true, + "required": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type name", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Bare metal server status", + "computed": true + } + ], + "ibm_is_bare_metal_server_action": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier", + "immutable": true, + "required": true + }, + { + "name": "stop_type", + "type": "TypeString", + "description": "The type of stop operation", + "default_value": "hard", + "immutable": true, + "optional": true + }, + { + "name": "action", + "type": "TypeString", + "description": "This restart/start/stops a bare metal server.", + "required": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Bare metal server status", + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + } + ], + "ibm_is_bare_metal_server_disk": [ + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier", + "required": true + }, + { + "name": "disk", + "type": "TypeString", + "description": "Bare metal server disk identifier", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Bare metal server disk name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interface": [ + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + "optional": true, + "computed": true + }, + { + "name": "hard_stop", + "type": "TypeBool", + "description": "Only used for PCI network interfaces, whether to hard/immediately stop server", + "default_value": true, + "optional": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps", + "computed": true + }, + { + "name": "primary_ip", + "type": "TypeList", + "description": "title: IPv4, The IP address.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this reserved IP will be automatically deleted when the target is deleted or when the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this reserved IP", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier for this reserved IP", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type: [ subnet_reserved_ip ]", + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The id of the associated subnet", + "required": true + }, + { + "name": "allow_interface_to_float", + "type": "TypeBool", + "description": "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + "optional": true, + "computed": true + }, + { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "optional": true, + "computed": true + }, + { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "optional": true, + "computed": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The globally unique IP identifier", + "computed": true + } + } + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Collection of security groups ids", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of this bare metal server network interface : [ primary, secondary ]", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier", + "required": true + }, + { + "name": "mac_address", + "type": "TypeString", + "description": "The MAC address of the interface. If absent, the value is not known.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type : [ subnet_reserved_ip ]", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface : [ available, deleting, failed, pending ]", + "computed": true + }, + { + "name": "allowed_vlans", + "type": "TypeSet", + "description": "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The bare metal server network interface identifier", + "computed": true + } + ], + "ibm_is_bare_metal_server_network_interface_allow_float": [ + { + "name": "floating_bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier of the server to which nic is floating to", + "computed": true + }, + { + "name": "enable_infrastructure_nat", + "type": "TypeBool", + "description": "If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations.", + "optional": true, + "computed": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The globally unique IP identifier", + "computed": true + } + } + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface : [ available, deleting, failed, pending ]", + "computed": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The bare metal server network interface identifier", + "computed": true + }, + { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "optional": true, + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Collection of security groups ids", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps", + "computed": true + }, + { + "name": "primary_ip", + "type": "TypeList", + "description": "title: IPv4, The IP address.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address", + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type : [ subnet_reserved_ip ]", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of this bare metal server network interface : [ primary, secondary ]", + "computed": true + }, + { + "name": "allow_interface_to_float", + "type": "TypeBool", + "description": "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier", + "required": true + }, + { + "name": "interface_type", + "type": "TypeString", + "description": "The network interface type: [ pci, vlan ]", + "computed": true + }, + { + "name": "mac_address", + "type": "TypeString", + "description": "The MAC address of the interface. If absent, the value is not known.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface", + "optional": true, + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The id of the associated subnet", + "required": true + }, + { + "name": "vlan", + "type": "TypeInt", + "description": "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + "required": true + } + ], + "ibm_is_bare_metal_server_network_interface_floating_ip": [ + { + "name": "floating_ip", + "type": "TypeString", + "description": "The floating ip identifier of the network interface associated with the bare metal server", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the floating IP", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Floating IP status", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Target info", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Floating IP crn", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "bare_metal_server", + "type": "TypeString", + "description": "Bare metal server identifier", + "required": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "Bare metal server network interface identifier", + "required": true + }, + { + "name": "address", + "type": "TypeString", + "description": "Floating IP address", + "computed": true + } + ], + "ibm_is_dedicated_host": [ + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "The Globally unique name of the dedicated host profile to use for this dedicated host.", + "immutable": true, + "required": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier for the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The administrative state of the dedicated host.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the dedicated host on which the unexpected property value was encountered.", + "computed": true + }, + { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + { + "name": "available_memory", + "type": "TypeInt", + "description": "The amount of memory in gibibytes that is currently available for instances.", + "computed": true + }, + { + "name": "available_vcpu", + "type": "TypeList", + "description": "The available VCPU for the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host was created.", + "computed": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the dedicated host's disks.", + "computed": true, + "elem": { + "available": { + "name": "available", + "type": "TypeInt", + "description": "The remaining space left for instance placement in GB (gigabytes).", + "computed": true + }, + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this disk.", + "computed": true + }, + "instance_disks": { + "name": "instance_disks", + "type": "TypeList", + "description": "Instance disks that are on this dedicated host disk.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the diskThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "lifecycle_state": { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of this dedicated host disk.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this disk.", + "computed": true + }, + "provisionable": { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host disk is available for instance disk creation.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + }, + "supported_instance_interface_types": { + "name": "supported_instance_interface_types", + "type": "TypeList", + "description": "The instance disk interfaces supported for this dedicated host disk.", + "computed": true, + "elem": { + "type": "TypeString" + } + } + } + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the dedicated host resource.", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host resides in.", + "computed": true + }, + { + "name": "instance_placement_enabled", + "type": "TypeBool", + "description": "If set to true, instances can be placed on this dedicated host.", + "default_value": true, + "optional": true + }, + { + "name": "host_group", + "type": "TypeString", + "description": "The unique identifier of the dedicated host group for this dedicated host.", + "immutable": true, + "required": true + }, + { + "name": "instances", + "type": "TypeList", + "description": "Array of instances that are allocated to this dedicated host.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "vcpu", + "type": "TypeList", + "description": "The total VCPU of the dedicated host.", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "description": "The VCPU architecture.", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of VCPUs assigned.", + "computed": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "memory", + "type": "TypeInt", + "description": "The total amount of memory in gibibytes for this host.", + "computed": true + }, + { + "name": "provisionable", + "type": "TypeBool", + "description": "Indicates whether this dedicated host is available for instance creation.", + "computed": true + }, + { + "name": "socket_count", + "type": "TypeInt", + "description": "The total number of sockets for this host.", + "computed": true + } + ], + "ibm_is_dedicated_host_disk_management": [ + { + "name": "dedicated_host", + "type": "TypeString", + "description": "ID of the dedicated host for which disks has to be managed", + "immutable": true, + "required": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Disk information that has to be updated.", + "required": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this disk.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk. The disk will be updated with this new name", + "required": true + } + } + } + ], + "ibm_is_dedicated_host_group": [ + { + "name": "family", + "type": "TypeString", + "description": "The dedicated host profile family for hosts in this group.", + "immutable": true, + "required": true, + "options": "balanced, compute, memory" + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host group. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host group.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "dedicated_hosts", + "type": "TypeList", + "description": "The dedicated hosts that are in this dedicated host group.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this dedicated host.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this dedicated host.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this dedicated host. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + { + "name": "class", + "type": "TypeString", + "description": "The dedicated host profile class for hosts in this group.", + "immutable": true, + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The globally unique name of the zone this dedicated host group will reside in.", + "immutable": true, + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the dedicated host group was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this dedicated host group.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + }, + { + "name": "supported_instance_profiles", + "type": "TypeList", + "description": "Array of instance profiles that can be used by instances placed on this dedicated host group.", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this virtual server instance profile.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The globally unique name for this virtual server instance profile.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_is_floating_ip": [ + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "target_list", + "type": "TypeList", + "description": "The target of this floating IP.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this public gateway.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this network interface.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface.", + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Floating IP tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "address", + "type": "TypeString", + "description": "Floating IP address", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the floating IP", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "status", + "type": "TypeString", + "description": "Floating IP status", + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "Target info", + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + } + ], + "ibm_is_flow_log": [ + { + "name": "target", + "type": "TypeString", + "description": "The target id that the flow log collector is to collect flow logs", + "immutable": true, + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time flow log was created", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the VPC Flow logs", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Flow Log Collector name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this flow log collector", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this flow log collector will be automatically deleted when the target is deleted", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "storage_bucket", + "type": "TypeString", + "description": "The Cloud Object Storage bucket name where the collected flows will be logged", + "immutable": true, + "required": true + }, + { + "name": "active", + "type": "TypeBool", + "description": "Indicates whether this collector is active", + "default_value": true, + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group of flow log", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC this flow log collector is associated with", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this flow log collector", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the flow log collector", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + } + ], + "ibm_is_ike_policy": [ + { + "name": "name", + "type": "TypeString", + "description": "IKE name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "Authentication algorithm type", + "required": true, + "options": "md5, sha1, sha256, sha512, sha384" + }, + { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "Encryption alogorithm type", + "required": true, + "options": "triple_des, aes128, aes192, aes256" + }, + { + "name": "dh_group", + "type": "TypeInt", + "description": "IKE DH group", + "required": true, + "options": "2, 5, 14, 19, 15, 16, 17, 18, 20, 21, 22, 23, 24, 31" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "IKE resource group ID", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "key_lifetime", + "type": "TypeInt", + "description": "IKE Key lifetime", + "default_value": 28800, + "optional": true + }, + { + "name": "negotiation_mode", + "type": "TypeString", + "description": "IKE negotiation mode", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "IKE href value", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "ike_version", + "type": "TypeInt", + "description": "IKE version", + "options": "1, 2", + "optional": true + }, + { + "name": "vpn_connections", + "type": "TypeList", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + } + } + } + ], + "ibm_is_image": [ + { + "name": "visibility", + "type": "TypeString", + "description": "Whether the image is publicly visible or private to the account", + "computed": true + }, + { + "name": "source_volume", + "type": "TypeString", + "description": "Image volume id", + "immutable": true, + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group for this image", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "checksum", + "type": "TypeString", + "description": "The SHA256 checksum of this image", + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the image", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "Image Operating system", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "encryption", + "type": "TypeString", + "description": "The type of encryption used on the image", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of this image", + "computed": true + }, + { + "name": "file", + "type": "TypeInt", + "description": "Details for the stored image file", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Image Href value", + "optional": true, + "computed": true + }, + { + "name": "encrypted_data_key", + "type": "TypeString", + "description": "A base64-encoded, encrypted representation of the key that was used to encrypt the data for this image", + "immutable": true, + "optional": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Image name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "size", + "type": "TypeInt", + "description": "The minimum size (in gigabytes) of a volume onto which this image may be provisioned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + } + ], + "ibm_is_instance": [ + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the virtual server instance.", + "computed": true + }, + { + "name": "dedicated_host", + "type": "TypeString", + "description": "Unique Identifier of the Dedicated Host where the instance will be placed", + "optional": true + }, + { + "name": "force_action", + "type": "TypeBool", + "description": "If set to true, the action will be forced immediately, and all queued actions deleted. Ignored for the start action.", + "default_value": false, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "list of tags for the instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "default_trusted_profile_auto_link", + "type": "TypeBool", + "description": "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "dedicated_host_group", + "type": "TypeString", + "description": "Unique Identifier of the Dedicated Host Group where the instance will be placed", + "optional": true + }, + { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "min_value": "500", + "optional": true, + "computed": true + }, + { + "name": "action", + "type": "TypeString", + "description": "Enables stopping of instance before deleting and waits till deletion is complete", + "options": "stop, start, reboot", + "optional": true + }, + { + "name": "catalog_offering", + "type": "TypeList", + "description": "The catalog offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", + "immutable": true, + "optional": true, + "elem": { + "offering_crn": { + "name": "offering_crn", + "type": "TypeString", + "description": "Identifies a catalog offering by a unique CRN property", + "immutable": true, + "optional": true + }, + "version_crn": { + "name": "version_crn", + "type": "TypeString", + "description": "Identifies a version of a catalog offering by a unique CRN property", + "immutable": true, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "network_interfaces", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "default_value": false, + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true, + "deprecated": "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead" + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "immutable": true, + "required": true + } + } + }, + { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance", + "options": "restart, stop", + "optional": true, + "computed": true + }, + { + "name": "vcpu", + "type": "TypeList", + "computed": true, + "elem": { + "architecture": { + "name": "architecture", + "type": "TypeString", + "computed": true + }, + "count": { + "name": "count", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "optional": true, + "computed": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Collection of the instance's disks.", + "computed": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the disk was created.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this instance disk.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "computed": true + }, + "interface_type": { + "name": "interface_type", + "type": "TypeString", + "description": "The disk interface used for attaching the disk.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "description": "The size of the disk in GB (gigabytes).", + "computed": true + } + } + }, + { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions for the virtual server instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement target.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement target.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this placement target.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this placement target.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "computed": true + } + } + }, + { + "name": "auto_delete_volume", + "type": "TypeBool", + "description": "Auto delete volume along with instance", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Crn for this Instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "placement_group", + "type": "TypeString", + "description": "Unique Identifier of the Placement Group for restricting the placement of the instance", + "immutable": true, + "optional": true + }, + { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "optional": true, + "computed": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether IP spoofing is allowed on this interface.", + "default_value": false, + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "port_speed": { + "name": "port_speed", + "type": "TypeInt", + "optional": true, + "computed": true, + "deprecated": "This field is deprected" + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "immutable": true, + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true, + "deprecated": "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead" + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Instance resource group", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "description": "The reasons for the current status (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "force_recovery_time", + "type": "TypeInt", + "description": "Define timeout to force the instances to start/stop in minutes.", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Instance name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "default_trusted_profile_target", + "type": "TypeString", + "description": "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + "immutable": true, + "optional": true + }, + { + "name": "user_data", + "type": "TypeString", + "description": "User data given for the instance", + "immutable": true, + "optional": true + }, + { + "name": "volumes", + "type": "TypeSet", + "description": "List of volumes", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "memory", + "type": "TypeInt", + "description": "Instance memory", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "Profile info", + "optional": true, + "computed": true + }, + { + "name": "total_network_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces.", + "computed": true + }, + { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the instance", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "volume_attachments", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "volume_crn": { + "name": "volume_crn", + "type": "TypeString", + "computed": true + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "computed": true + }, + "volume_name": { + "name": "volume_name", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "boot_volume", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "encryption": { + "name": "encryption", + "type": "TypeString", + "optional": true, + "computed": true + }, + "iops": { + "name": "iops", + "type": "TypeInt", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "optional": true, + "computed": true + }, + "snapshot": { + "name": "snapshot", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "UserTags for the volume instance", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "volume_id": { + "name": "volume_id", + "type": "TypeString", + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "status", + "type": "TypeString", + "description": "instance status", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "instance_template", + "type": "TypeString", + "description": "Id of the instance template", + "immutable": true, + "optional": true + }, + { + "name": "lifecycle_reasons", + "type": "TypeList", + "description": "The reasons for the current lifecycle_state (if any).", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the reason for this lifecycle state.", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the reason for this lifecycle state.", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about the reason for this lifecycle state.", + "computed": true + } + } + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes", + "computed": true + }, + { + "name": "wait_before_delete", + "type": "TypeBool", + "description": "Enables stopping of instance before deleting and waits till deletion is complete", + "default_value": true, + "optional": true + }, + { + "name": "image", + "type": "TypeString", + "description": "image id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "gpu", + "type": "TypeList", + "description": "The virtual server instance GPU configuration", + "computed": true, + "elem": { + "count": { + "name": "count", + "type": "TypeInt", + "description": "The number of GPUs assigned to the instance", + "computed": true + }, + "manufacturer": { + "name": "manufacturer", + "type": "TypeString", + "description": "The GPU manufacturer", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The overall amount of GPU memory in GiB (gibibytes)", + "computed": true + }, + "model": { + "name": "model", + "type": "TypeString", + "description": "The GPU model", + "computed": true + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_is_instance_action": [ + { + "name": "instance", + "type": "TypeString", + "description": "Instance identifier", + "immutable": true, + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "This restart/start/stops an instance.", + "required": true, + "options": "start, reboot, stop" + }, + { + "name": "force_action", + "type": "TypeBool", + "description": "If set to true, the action will be forced immediately, and all queued actions deleted. Ignored for the start action.", + "default_value": false, + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Instance status", + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + } + ], + "ibm_is_instance_disk_management": [ + { + "name": "instance", + "type": "TypeString", + "description": "ID of the instance for which disks has to be managed", + "immutable": true, + "required": true + }, + { + "name": "disks", + "type": "TypeList", + "description": "Disk information that has to be updated.", + "required": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this instance disk.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this disk. The disk will be updated with this new name", + "required": true + } + } + } + ], + "ibm_is_instance_group": [ + { + "name": "instances", + "type": "TypeInt", + "description": "number of instances in the intances group", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "vpc instance", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "instance_count", + "type": "TypeInt", + "description": "The number of instances in the instance group", + "default_value": 0, + "min_value": "0", + "max_value": "1000", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Instance group status - deleting, healthy, scaling, unhealthy", + "computed": true + }, + { + "name": "instance_template", + "type": "TypeString", + "description": "instance template ID", + "required": true + }, + { + "name": "subnets", + "type": "TypeList", + "description": "list of subnet IDs", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "load_balancer", + "type": "TypeString", + "description": "load balancer ID", + "optional": true + }, + { + "name": "load_balancer_pool", + "type": "TypeString", + "description": "load balancer pool ID", + "optional": true + }, + { + "name": "managers", + "type": "TypeList", + "description": "list of Managers associated with instancegroup", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for instance group", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN of this instance group", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "application_port", + "type": "TypeInt", + "description": "Used by the instance group when scaling up instances to supply the port for the load balancer pool member.", + "min_value": "1", + "max_value": "65535", + "optional": true + } + ], + "ibm_is_instance_group_manager": [ + { + "name": "policies", + "type": "TypeList", + "description": "list of Policies associated with instancegroup manager", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "actions", + "type": "TypeList", + "computed": true, + "elem": { + "instance_group_manager_action": { + "name": "instance_group_manager_action", + "type": "TypeString", + "computed": true + }, + "instance_group_manager_action_name": { + "name": "instance_group_manager_action_name", + "type": "TypeString", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "manager_type", + "type": "TypeString", + "description": "The type of instance group manager.", + "default_value": "autoscale", + "immutable": true, + "options": "autoscale, scheduled", + "optional": true + }, + { + "name": "cooldown", + "type": "TypeInt", + "description": "The duration of time in seconds to pause further scale actions after scaling has taken place", + "default_value": 300, + "min_value": "120", + "max_value": "3600", + "optional": true + }, + { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "min_value": "1", + "max_value": "1000", + "optional": true + }, + { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "default_value": 1, + "min_value": "1", + "max_value": "1000", + "optional": true + }, + { + "name": "manager_id", + "type": "TypeString", + "description": "instance group manager ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "instance group manager name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$", + "optional": true + }, + { + "name": "enable_manager", + "type": "TypeBool", + "description": "enable instance group manager", + "default_value": true, + "optional": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "aggregation_window", + "type": "TypeInt", + "description": "The time window in seconds to aggregate metrics prior to evaluation", + "default_value": 90, + "min_value": "90", + "max_value": "600", + "optional": true + } + ], + "ibm_is_instance_group_manager_action": [ + { + "name": "min_membership_count", + "type": "TypeInt", + "description": "The minimum number of members in a managed instance group", + "default_value": 1, + "min_value": "1", + "max_value": "1000", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group action- `active`: Action is ready to be run- `completed`: Action was completed successfully- `failed`: Action could not be completed successfully- `incompatible`: Action parameters are not compatible with the group or manager- `omitted`: Action was not applied because this action's manager was disabled.", + "computed": true + }, + { + "name": "action_type", + "type": "TypeString", + "description": "The type of action for the instance group.", + "computed": true + }, + { + "name": "next_run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will next run. If empty the system is currently calculating the next run time.", + "computed": true + }, + { + "name": "target_manager_name", + "type": "TypeString", + "description": "Instance group manager name of type autoscale.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + }, + { + "name": "last_applied_at", + "type": "TypeString", + "description": "The date and time the scheduled action was last applied. If empty the action has never been applied.", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "computed": true + }, + { + "name": "max_membership_count", + "type": "TypeInt", + "description": "The maximum number of members in a managed instance group", + "min_value": "1", + "max_value": "1000", + "optional": true + }, + { + "name": "target_manager", + "type": "TypeString", + "description": "The unique identifier for this instance group manager of type autoscale.", + "optional": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "action_id", + "type": "TypeString", + "description": "Instance group manager action ID", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "run_at", + "type": "TypeString", + "description": "The date and time the scheduled action will run.", + "optional": true + }, + { + "name": "cron_spec", + "type": "TypeString", + "description": "The cron specification for a recurring scheduled action. Actions can be applied a maximum of one time within a 5 min period.", + "min_length": 9, + "max_length": 63, + "matches": "^((((\\d+,)+\\d+|([\\d\\*]+(\\/|-)\\d+)|\\d+|\\*) ?){5,7})$", + "optional": true + }, + { + "name": "membership_count", + "type": "TypeInt", + "description": "The number of members the instance group should have at the scheduled time.", + "min_value": "0", + "max_value": "100", + "optional": true + }, + { + "name": "auto_delete_timeout", + "type": "TypeInt", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "instance group manager action name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$", + "optional": true + }, + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID of type scheduled", + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the instance group manager action was modified.", + "computed": true + } + ], + "ibm_is_instance_group_manager_policy": [ + { + "name": "metric_type", + "type": "TypeString", + "description": "The type of metric to be evaluated", + "required": true, + "options": "cpu,memory,network_in,network_out" + }, + { + "name": "metric_value", + "type": "TypeInt", + "description": "The metric value to be evaluated", + "required": true + }, + { + "name": "policy_type", + "type": "TypeString", + "description": "The type of Policy for the Instance Group", + "required": true, + "options": "target" + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "The Policy ID", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "instance group manager policy name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "instance group ID", + "required": true + }, + { + "name": "instance_group_manager", + "type": "TypeString", + "description": "Instance group manager ID", + "required": true + } + ], + "ibm_is_instance_group_membership": [ + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this instance group membership. Names must be unique within the instance group.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "delete_instance_on_membership_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the membership the instance will also be deleted.", + "computed": true + }, + { + "name": "instance", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this virtual server instance.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this virtual server instance (and default system hostname).", + "computed": true + }, + "virtual_server_instance": { + "name": "virtual_server_instance", + "type": "TypeString", + "description": "The unique identifier for this virtual server instance.", + "computed": true + } + } + }, + { + "name": "instance_template", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this instance template.", + "computed": true + }, + "instance_template": { + "name": "instance_template", + "type": "TypeString", + "description": "The unique identifier for this instance template.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this instance template.", + "computed": true + } + } + }, + { + "name": "load_balancer_pool_member", + "type": "TypeString", + "description": "The unique identifier for this load balancer pool member.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the instance group membership- `deleting`: Membership is deleting dependent resources- `failed`: Membership was unable to maintain dependent resources- `healthy`: Membership is active and serving in the group- `pending`: Membership is waiting for dependent resources- `unhealthy`: Membership has unhealthy dependent resources.", + "computed": true + }, + { + "name": "instance_group", + "type": "TypeString", + "description": "The instance group identifier.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 64, + "matches": "^[-0-9a-z_]+$" + }, + { + "name": "action_delete", + "type": "TypeBool", + "description": "The delete flag for this instance group membership. Must be set to true to delete instance group membership.", + "default_value": false, + "optional": true + }, + { + "name": "instance_group_membership", + "type": "TypeString", + "description": "The unique identifier for this instance group membership.", + "required": true, + "min_length": 1, + "max_length": 64, + "matches": "^[-0-9a-z_]+$" + } + ], + "ibm_is_instance_network_interface": [ + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this network interface. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "The primary IPv4 address. If specified, it must be an available address on the network interface's subnet. If unspecified, an available address on the subnet will be automatically selected.", + "immutable": true, + "matches": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", + "optional": true, + "computed": true, + "deprecated": "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead" + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "The globally unique ID of this network interface", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this network interface.", + "computed": true + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "The network interface port speed in Mbps.", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The unique identifier of the subnet.", + "immutable": true, + "required": true + }, + { + "name": "floating_ip", + "type": "TypeString", + "description": "The ID of the floating IP to attach to this network interface", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of this network interface as it relates to an instance.", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "optional": true, + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + }, + "max_items": 1 + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the network interface was created.", + "computed": true + }, + { + "name": "instance", + "type": "TypeString", + "description": "The unique identifier of the instance.", + "immutable": true, + "required": true + }, + { + "name": "floating_ips", + "type": "TypeList", + "description": "The floating IPs associated with this network interface.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The globally unique IP address.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this floating IP.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this floating IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this floating IP.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this floating IP.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the network interface.", + "computed": true + }, + { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "description": "Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface.", + "default_value": false, + "optional": true + } + ], + "ibm_is_instance_template": [ + { + "name": "primary_network_interface", + "type": "TypeList", + "description": "Primary Network interface info", + "required": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "immutable": true, + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "immutable": true, + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "immutable": true, + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "optional": true, + "computed": true, + "deprecated": "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead" + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "immutable": true, + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "user_data", + "type": "TypeString", + "description": "User data given for the instance", + "immutable": true, + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for the instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "image", + "type": "TypeString", + "description": "image name", + "immutable": true, + "required": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Instance template resource group", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "total_volume_bandwidth", + "type": "TypeInt", + "description": "The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes", + "immutable": true, + "min_value": "500", + "optional": true + }, + { + "name": "dedicated_host_group", + "type": "TypeString", + "description": "Unique Identifier of the Dedicated Host Group where the instance will be placed", + "immutable": true, + "optional": true + }, + { + "name": "network_interfaces", + "type": "TypeList", + "optional": true, + "elem": { + "allow_ip_spoofing": { + "name": "allow_ip_spoofing", + "type": "TypeBool", + "default_value": false, + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "primary_ip": { + "name": "primary_ip", + "type": "TypeList", + "description": "The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP.", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + "auto_delete": { + "name": "auto_delete", + "type": "TypeBool", + "description": "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + "immutable": true, + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "immutable": true, + "optional": true, + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "immutable": true, + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "primary_ipv4_address": { + "name": "primary_ipv4_address", + "type": "TypeString", + "optional": true, + "computed": true, + "deprecated": "primary_ipv4_address is deprecated and support will be removed. Use primary_ip instead" + }, + "security_groups": { + "name": "security_groups", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "immutable": true, + "required": true + } + } + }, + { + "name": "boot_volume", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "optional": true, + "computed": true + }, + "encryption": { + "name": "encryption", + "type": "TypeString", + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "optional": true, + "computed": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "computed": true + }, + "size": { + "name": "size", + "type": "TypeInt", + "computed": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "UserTags for the volume instance", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1 + }, + { + "name": "availability_policy_host_failure", + "type": "TypeString", + "description": "The availability policy to use for this virtual server instance", + "immutable": true, + "options": "restart, stop", + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC id", + "immutable": true, + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "Profile info", + "immutable": true, + "required": true + }, + { + "name": "default_trusted_profile_auto_link", + "type": "TypeBool", + "description": "If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "default_trusted_profile_target", + "type": "TypeString", + "description": "The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance.", + "immutable": true, + "optional": true + }, + { + "name": "placement_group", + "type": "TypeString", + "description": "Unique Identifier of the Placement Group for restricting the placement of the instance", + "immutable": true, + "optional": true + }, + { + "name": "volume_attachments", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "delete_volume_on_instance_delete": { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the instance the volume will also be deleted.", + "required": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this volume attachment.", + "required": true + }, + "volume": { + "name": "volume", + "type": "TypeString", + "description": "The unique identifier for this volume.", + "immutable": true, + "optional": true + }, + "volume_prototype": { + "name": "volume_prototype", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "capacity": { + "name": "capacity", + "type": "TypeInt", + "description": "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + "immutable": true, + "required": true + }, + "encryption_key": { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + "immutable": true, + "optional": true + }, + "iops": { + "name": "iops", + "type": "TypeInt", + "description": "The maximum I/O operations per second (IOPS) for the volume.", + "immutable": true, + "optional": true + }, + "profile": { + "name": "profile", + "type": "TypeString", + "description": "The globally unique name for the volume profile to use for this volume.", + "immutable": true, + "required": true + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "description": "UserTags for the volume instance", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + } + }, + "max_items": 1, + "min_items": 1 + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Instance Template name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "keys", + "type": "TypeSet", + "description": "SSH key Ids for the instance template", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "dedicated_host", + "type": "TypeString", + "description": "Unique Identifier of the Dedicated Host where the instance will be placed", + "immutable": true, + "optional": true + }, + { + "name": "placement_target", + "type": "TypeList", + "description": "The placement restrictions for the virtual server instance.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement target.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement target.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this placement target.", + "computed": true + } + } + }, + { + "name": "metadata_service_enabled", + "type": "TypeBool", + "description": "Indicates whether the metadata service endpoint is available to the virtual server instance", + "default_value": false, + "immutable": true, + "optional": true + } + ], + "ibm_is_instance_volume_attachment": [ + { + "name": "volume_attachment_id", + "type": "TypeString", + "description": "The unique identifier for this volume attachment", + "computed": true + }, + { + "name": "delete_volume_on_instance_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the instance the volume will also be deleted.", + "optional": true, + "computed": true + }, + { + "name": "device", + "type": "TypeString", + "description": "A unique identifier for the device which is exposed to the instance operating system", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this volume attachment", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of volume attachment one of [ boot, data ]", + "computed": true + }, + { + "name": "instance", + "type": "TypeString", + "description": "Instance id", + "immutable": true, + "required": true + }, + { + "name": "delete_volume_on_attachment_delete", + "type": "TypeBool", + "description": "If set to true, when deleting the attachment, the volume will also be deleted. Default value for this true.", + "default_value": true, + "optional": true + }, + { + "name": "volume", + "type": "TypeString", + "description": "Instance id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "snapshot", + "type": "TypeString", + "description": "The snapshot of the volume to be attached", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "volume_crn", + "type": "TypeString", + "description": "The CRN for this volume", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of this volume attachment, one of [ attached, attaching, deleting, detaching ]", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this volume attachment.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "volume_name", + "type": "TypeString", + "description": "The unique user-defined name for this volume", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "UserTags for the volume instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "profile", + "type": "TypeString", + "description": "The globally unique name for the volume profile to use for this volume.", + "options": "general-purpose, 5iops-tier, 10iops-tier, custom", + "optional": true, + "computed": true + }, + { + "name": "volume_deleted", + "type": "TypeString", + "description": "Link to documentation about deleted resources", + "computed": true + }, + { + "name": "volume_href", + "type": "TypeString", + "description": "The URL for this volume", + "computed": true + }, + { + "name": "iops", + "type": "TypeInt", + "description": "The maximum I/O operations per second (IOPS) for the volume.", + "optional": true, + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + "min_value": "10", + "max_value": "16000", + "optional": true, + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_is_ipsec_policy": [ + { + "name": "name", + "type": "TypeString", + "description": "IPSEC name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "encryption_algorithm", + "type": "TypeString", + "description": "Encryption algorithm", + "required": true, + "options": "triple_des, aes128, aes256, aes128gcm16, aes192gcm16, aes256gcm16" + }, + { + "name": "key_lifetime", + "type": "TypeInt", + "description": "IPSEC key lifetime", + "default_value": 3600, + "optional": true + }, + { + "name": "encapsulation_mode", + "type": "TypeString", + "description": "IPSEC encapsulation mode", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "authentication_algorithm", + "type": "TypeString", + "description": "Authentication alorothm", + "required": true, + "options": "md5, sha1, sha256, sha512, sha384, disabled" + }, + { + "name": "pfs", + "type": "TypeString", + "description": "PFS info", + "required": true, + "options": "disabled, group_2, group_5, group_14, group_19, group_15, group_16, group_17, group_18, group_20, group_21, group_22, group_23, group_24, group_31" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "transform_protocol", + "type": "TypeString", + "description": "IPSEC transform protocol", + "computed": true + }, + { + "name": "vpn_connections", + "type": "TypeList", + "computed": true, + "elem": { + "href": { + "name": "href", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_is_lb": [ + { + "name": "name", + "type": "TypeString", + "description": "Load Balancer name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "subnets", + "type": "TypeSet", + "description": "Load Balancer subnets list", + "required": true, + "elem": { + "type": "TypeString" + }, + "max_items": 15, + "min_items": 1 + }, + { + "name": "tags", + "type": "TypeSet", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "route_mode", + "type": "TypeBool", + "description": "Indicates whether route mode is enabled for this load balancer", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Load Balancer", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "private_ips", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Load Balancer securitygroups list", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "udp_supported", + "type": "TypeBool", + "description": "Indicates whether this load balancer supports UDP.", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Load Balancer type", + "default_value": "public", + "immutable": true, + "options": "public, private", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "operating_status", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ips", + "type": "TypeList", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "security_group_supported", + "type": "TypeBool", + "description": "Security Group Supported for this Load Balancer", + "computed": true + }, + { + "name": "logging", + "type": "TypeBool", + "description": "Logging of Load Balancer", + "default_value": false, + "optional": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "private_ip", + "type": "TypeList", + "description": "The private IP addresses assigned to this load balancer.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address to reserve, which must not already be reserved on the subnet.", + "computed": true + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this reserved IP. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the subnet the reserved IP resides in.", + "computed": true + }, + "reserved_ip": { + "name": "reserved_ip", + "type": "TypeString", + "description": "Identifies a reserved IP by a unique property.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + } + } + }, + { + "name": "profile", + "type": "TypeString", + "description": "The profile to use for this load balancer.", + "immutable": true, + "options": "network-fixed", + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + } + ], + "ibm_is_lb_listener": [ + { + "name": "certificate_instance", + "type": "TypeString", + "description": "certificate instance for the Loadbalancer", + "optional": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the LB resource", + "computed": true + }, + { + "name": "default_pool", + "type": "TypeString", + "description": "Loadbalancer default pool info", + "optional": true, + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Loadbalancer listener status", + "computed": true + }, + { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener.", + "optional": true, + "computed": true + }, + { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of the range of ports used by this listener. Only load balancers in the `network` family support more than one port per listener", + "optional": true, + "computed": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Loadbalancer listener port", + "optional": true, + "computed": true + }, + { + "name": "connection_limit", + "type": "TypeInt", + "description": "Connection limit for Loadbalancer", + "optional": true + }, + { + "name": "accept_proxy_protocol", + "type": "TypeBool", + "description": "Listener will forward proxy protocol", + "optional": true, + "computed": true + }, + { + "name": "https_redirect_status_code", + "type": "TypeInt", + "description": "The HTTP status code to be returned in the redirect response", + "optional": true + }, + { + "name": "https_redirect_uri", + "type": "TypeString", + "description": "Target URI where traffic will be redirected", + "optional": true + }, + { + "name": "https_redirect_listener", + "type": "TypeString", + "description": "ID of the listener that will be set as http redirect target", + "optional": true + }, + { + "name": "listener_id", + "type": "TypeString", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "Loadbalancer listener ID", + "immutable": true, + "required": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Loadbalancer protocol", + "required": true, + "options": "https, http, tcp, udp" + } + ], + "ibm_is_lb_listener_policy": [ + { + "name": "action", + "type": "TypeString", + "description": "Policy Action", + "immutable": true, + "required": true, + "options": "forward, redirect, reject, https_redirect" + }, + { + "name": "lb", + "type": "TypeString", + "description": "Load Balancer Listener Policy", + "immutable": true, + "required": true + }, + { + "name": "target_https_redirect_uri", + "type": "TypeString", + "description": "Target URI where traffic will be redirected", + "optional": true + }, + { + "name": "target_https_redirect_listener", + "type": "TypeString", + "description": "ID of the listener that will be set as http redirect target", + "optional": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "Listener Policy ID", + "computed": true + }, + { + "name": "target_url", + "type": "TypeString", + "description": "Policy Target URL", + "optional": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the LB resource", + "computed": true + }, + { + "name": "priority", + "type": "TypeInt", + "description": "Listener Policy Priority", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Policy name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Policy Rules", + "optional": true, + "computed": true, + "elem": { + "condition": { + "name": "condition", + "type": "TypeString", + "description": "Condition of the rule", + "required": true + }, + "field": { + "name": "field", + "type": "TypeString", + "description": "HTTP header field. This is only applicable to rule type.", + "optional": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Rule ID", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the rule", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value to be matched for rule condition", + "required": true + } + } + }, + { + "name": "target_id", + "type": "TypeString", + "description": "Listener Policy Target ID", + "optional": true + }, + { + "name": "listener", + "type": "TypeString", + "description": "Listener ID", + "immutable": true, + "required": true + }, + { + "name": "target_https_redirect_status_code", + "type": "TypeInt", + "description": "The HTTP status code to be returned in the redirect response", + "optional": true + }, + { + "name": "target_http_status_code", + "type": "TypeInt", + "description": "Listener Policy target HTTPS Status code.", + "optional": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "Listner Policy status", + "computed": true + } + ], + "ibm_is_lb_listener_policy_rule": [ + { + "name": "field", + "type": "TypeString", + "optional": true + }, + { + "name": "rule", + "type": "TypeString", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the LB resource", + "computed": true + }, + { + "name": "listener", + "type": "TypeString", + "description": "Listener ID.", + "immutable": true, + "required": true + }, + { + "name": "value", + "type": "TypeString", + "description": "policy rule value info", + "required": true + }, + { + "name": "condition", + "type": "TypeString", + "description": "Condition info of the rule.", + "required": true, + "options": "contains, equals, matches_regex" + }, + { + "name": "type", + "type": "TypeString", + "description": "Policy rule type.", + "required": true, + "options": "header, hostname, path, body, query" + }, + { + "name": "provisioning_status", + "type": "TypeString", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "Loadbalancer ID", + "immutable": true, + "required": true + }, + { + "name": "policy", + "type": "TypeString", + "description": "Listener Policy ID", + "immutable": true, + "required": true + } + ], + "ibm_is_lb_pool": [ + { + "name": "proxy_protocol", + "type": "TypeString", + "description": "PROXY protocol setting for this pool", + "options": "disabled, v1, v2", + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Load Balancer Pool name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "health_delay", + "type": "TypeInt", + "description": "Load Blancer health delay time period", + "required": true + }, + { + "name": "health_retries", + "type": "TypeInt", + "description": "Load Balancer health retry count", + "required": true + }, + { + "name": "health_monitor_port", + "type": "TypeInt", + "description": "Health monitor Port the LB Pool", + "optional": true, + "computed": true + }, + { + "name": "session_persistence_type", + "type": "TypeString", + "description": "Load Balancer Pool session persisence type.", + "options": "source_ip, app_cookie, http_cookie", + "optional": true + }, + { + "name": "session_persistence_app_cookie_name", + "type": "TypeString", + "description": "Load Balancer Pool session persisence app cookie name.", + "min_length": 1, + "max_length": 63, + "matches": "^[-A-Za-z0-9!#$%\u0026'*+.^_`~|]+$", + "optional": true + }, + { + "name": "session_persistence_http_cookie_name", + "type": "TypeString", + "description": "Load Balancer Pool session persisence http cookie name.", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the LB resource", + "computed": true + }, + { + "name": "health_timeout", + "type": "TypeInt", + "description": "Load Balancer health timeout interval", + "required": true + }, + { + "name": "health_type", + "type": "TypeString", + "description": "Load Balancer health type", + "required": true, + "options": "http, tcp, https, udp" + }, + { + "name": "health_monitor_url", + "type": "TypeString", + "description": "Health monitor URL of LB Pool", + "optional": true, + "computed": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "Status of the LB Pool", + "computed": true + }, + { + "name": "pool_id", + "type": "TypeString", + "description": "The LB Pool id", + "computed": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "Load Balancer ID", + "immutable": true, + "required": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Load Balancer Protocol", + "required": true, + "options": "http, tcp, https, udp" + }, + { + "name": "algorithm", + "type": "TypeString", + "description": "Load Balancer Pool algorithm", + "required": true, + "options": "round_robin, weighted_round_robin, least_connections" + } + ], + "ibm_is_lb_pool_member": [ + { + "name": "pool", + "type": "TypeString", + "description": "Loadblancer Poold ID", + "immutable": true, + "required": true + }, + { + "name": "lb", + "type": "TypeString", + "description": "Load balancer ID", + "immutable": true, + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Load Balancer Pool port", + "required": true + }, + { + "name": "target_address", + "type": "TypeString", + "description": "Load balancer pool member target address", + "optional": true + }, + { + "name": "provisioning_status", + "type": "TypeString", + "description": "Load balancer Pool member provisioning status", + "computed": true + }, + { + "name": "health", + "type": "TypeString", + "description": "LB Pool member health", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "LB pool member Href value", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the LB resource", + "computed": true + }, + { + "name": "target_id", + "type": "TypeString", + "description": "Load balancer pool member target id", + "optional": true + }, + { + "name": "weight", + "type": "TypeInt", + "description": "Load balcner pool member weight", + "min_value": "0", + "max_value": "100", + "optional": true, + "computed": true + } + ], + "ibm_is_network_acl": [ + { + "name": "name", + "type": "TypeString", + "description": "Network ACL name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Network ACL VPC name", + "immutable": true, + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID for the network ACL", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "optional": true, + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "required": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "required": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "required": true + }, + "icmp": { + "name": "icmp", + "type": "TypeList", + "optional": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "optional": true + } + }, + "max_items": 1 + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "required": true + }, + "source": { + "name": "source", + "type": "TypeString", + "required": true + }, + "subnets": { + "name": "subnets", + "type": "TypeInt", + "computed": true + }, + "tcp": { + "name": "tcp", + "type": "TypeList", + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + } + }, + "max_items": 1 + }, + "udp": { + "name": "udp", + "type": "TypeList", + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + } + }, + "max_items": 1 + } + } + } + ], + "ibm_is_network_acl_rule": [ + { + "name": "href", + "type": "TypeString", + "description": "The url of the rule.", + "computed": true + }, + { + "name": "tcp", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "default_value": 1, + "optional": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "default_value": 65535, + "optional": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "default_value": 1, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "udp", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "default_value": 1, + "optional": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The highest port in the range of ports to be matched", + "default_value": 65535, + "optional": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The lowest port in the range of ports to be matched", + "default_value": 1, + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "protocol", + "type": "TypeString", + "description": "The protocol of the rule.", + "computed": true + }, + { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule.", + "computed": true + }, + { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic", + "required": true, + "options": "allow, deny" + }, + { + "name": "before", + "type": "TypeString", + "description": "The rule that this rule is immediately before. If absent, this is the last rule.", + "optional": true, + "computed": true + }, + { + "name": "source", + "type": "TypeString", + "description": "The source CIDR block. The CIDR block 0.0.0.0/0 applies to all addresses.", + "required": true + }, + { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "required": true, + "options": "inbound, outbound" + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "The network acl rule id.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule. Names must be unique within the network ACL the rule resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination CIDR block. The CIDR block 0.0.0.0/0 applies to all addresses.", + "required": true + }, + { + "name": "icmp", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow. Valid values from 0 to 255.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow. Valid values from 0 to 254.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "network_acl", + "type": "TypeString", + "description": "Network ACL id", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + } + ], + "ibm_is_placement_group": [ + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "access_tags", + "type": "TypeSet", + "description": "List of access management tags", + "min_length": 1, + "max_length": 128, + "matches": "^([ ]*[A-Za-z0-9:_.-]+[ ]*)+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this placement group.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this placement group.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this placement group. If unspecified, the name will be a hyphenated list of randomly-selected words.", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier of the resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the placement group was created.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the placement group.", + "computed": true + }, + { + "name": "strategy", + "type": "TypeString", + "description": "The strategy for this placement group- `host_spread`: place on different compute hosts- `power_spread`: place on compute hosts that use different power sourcesThe enumerated values for this property may expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the placement group on which the unexpected strategy was encountered.", + "immutable": true, + "required": true, + "options": "host_spread, power_spread" + } + ], + "ibm_is_public_gateway": [ + { + "name": "resource_group", + "type": "TypeString", + "description": "Public gateway resource group info", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Public gateway VPC info", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Service tags for the public gateway instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the Public gateway instance", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "floating_ip", + "type": "TypeMap", + "optional": true, + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Public gateway instance status", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Public gateway zone info", + "immutable": true, + "required": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + } + ], + "ibm_is_security_group": [ + { + "name": "name", + "type": "TypeString", + "description": "Security group name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Security group's resource group id", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "description": "Security Rules", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource Group ID", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + } + ], + "ibm_is_security_group_network_interface_attachment": [ + { + "name": "status", + "type": "TypeString", + "description": "security group network interface attachment status", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "security group network interface attachment subnet", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "security group network interface attachment type", + "computed": true + }, + { + "name": "security_group", + "type": "TypeString", + "description": "security group network interface attachment group ID", + "immutable": true, + "required": true + }, + { + "name": "port_speed", + "type": "TypeInt", + "description": "security group network interface attachment port speed", + "computed": true + }, + { + "name": "instance_network_interface", + "type": "TypeString", + "description": "security group network interface attachment network interface ID", + "computed": true + }, + { + "name": "primary_ipv4_address", + "type": "TypeString", + "description": "security group network interface attachment Primary IPV4 address", + "computed": true + }, + { + "name": "secondary_address", + "type": "TypeSet", + "description": "security group network interface attachment secondary address", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "floating_ips", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "security group network interface attachment floating IP CRN", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "security group network interface attachment floating IP ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "security group network interface attachment floating IP name", + "computed": true + } + } + }, + { + "name": "security_groups", + "type": "TypeList", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "security group network interface attachment security group CRN", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "security group network interface attachment security group ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "security group network interface attachment security group name", + "computed": true + } + } + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the Security Group", + "computed": true + }, + { + "name": "network_interface", + "type": "TypeString", + "description": "security group network interface attachment NIC ID", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "security group network interface attachment name", + "computed": true + } + ], + "ibm_is_security_group_rule": [ + { + "name": "group", + "type": "TypeString", + "description": "Security group id", + "immutable": true, + "required": true + }, + { + "name": "icmp", + "type": "TypeList", + "description": "protocol=icmp", + "immutable": true, + "optional": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "tcp", + "type": "TypeList", + "description": "protocol=tcp", + "immutable": true, + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the Security Group", + "computed": true + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "Rule id", + "computed": true + }, + { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "required": true, + "options": "inbound, outbound" + }, + { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4", + "default_value": "ipv4", + "options": "ipv4", + "optional": true + }, + { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "optional": true, + "computed": true + }, + { + "name": "udp", + "type": "TypeList", + "description": "protocol=udp", + "immutable": true, + "optional": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "default_value": 65535, + "optional": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "default_value": 1, + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "protocol", + "type": "TypeString", + "description": "The Security Group Rule Protocol", + "computed": true + } + ], + "ibm_is_security_group_target": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource Type", + "computed": true + }, + { + "name": "security_group", + "type": "TypeString", + "description": "Security group id", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 64, + "matches": "^[-0-9a-z_]+$" + }, + { + "name": "target", + "type": "TypeString", + "description": "security group target identifier", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 64, + "matches": "^[-0-9a-z_]+$" + }, + { + "name": "name", + "type": "TypeString", + "description": "Security group target name", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Security group target", + "cloud_data_type": "crn", + "computed": true + } + ], + "ibm_is_snapshot": [ + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Snapshot lifecycle state", + "computed": true + }, + { + "name": "backup_policy_plan", + "type": "TypeList", + "description": "If present, the backup policy plan which created this snapshot.", + "computed": true, + "elem": { + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and provides some supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this backup policy plan.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this backup policy plan.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this backup policy plan.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced", + "computed": true + } + } + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "The globally unique name for the operating system included in this image", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "encryption", + "type": "TypeString", + "description": "Encryption type of the snapshot", + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "A reference to the root key used to wrap the data encryption key for the source volume.", + "computed": true + }, + { + "name": "size", + "type": "TypeInt", + "description": "The size of the snapshot", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Snapshot name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "source_volume", + "type": "TypeString", + "description": "Snapshot source volume", + "immutable": true, + "required": true + }, + { + "name": "minimum_capacity", + "type": "TypeInt", + "description": "Minimum capacity of the snapshot", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "User Tags for the snapshot", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "source_image", + "type": "TypeString", + "description": "If present, the image id from which the data on this volume was most directly provisioned.", + "computed": true + }, + { + "name": "bootable", + "type": "TypeBool", + "description": "Indicates if a boot volume attachment can be created with a volume created from this snapshot", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "URL for the snapshot", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type of the snapshot", + "computed": true + } + ], + "ibm_is_ssh_key": [ + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "SSH Key name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "public_key", + "type": "TypeString", + "description": "SSH Public key data", + "immutable": true, + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for SSH key", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Key type", + "computed": true + }, + { + "name": "fingerprint", + "type": "TypeString", + "description": "SSH key Fingerprint info", + "computed": true + }, + { + "name": "length", + "type": "TypeInt", + "description": "SSH key Length", + "computed": true + } + ], + "ibm_is_subnet": [ + { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version(s) to support for this subnet.", + "default_value": "ipv4", + "immutable": true, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Subnet name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the subnet", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group for this subnet", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "available_ipv4_address_count", + "type": "TypeInt", + "description": "The number of IPv4 addresses in this subnet that are not in-use, and have not been reserved by the user or the provider.", + "computed": true + }, + { + "name": "total_ipv4_address_count", + "type": "TypeInt", + "description": "The total number of IPv4 addresses in this subnet.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "routing table id that is associated with the subnet", + "optional": true, + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "ipv4_cidr_block", + "type": "TypeString", + "description": "IPV4 subnet - CIDR block", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "network_acl", + "type": "TypeString", + "description": "The network ACL for this subnet", + "optional": true, + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "public_gateway", + "type": "TypeString", + "description": "Public Gateway of the subnet", + "optional": true, + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC instance ID", + "immutable": true, + "required": true + }, + { + "name": "access_tags", + "type": "TypeSet", + "description": "List of access management tags", + "min_length": 1, + "max_length": 128, + "matches": "^([ ]*[A-Za-z0-9:_.-]+[ ]*)+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "zone", + "type": "TypeString", + "description": "Subnet zone info", + "immutable": true, + "required": true + } + ], + "ibm_is_subnet_network_acl_attachment": [ + { + "name": "network_acl", + "type": "TypeString", + "description": "The unique identifier of network ACL", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Network ACL name", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn for this Network ACL", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Network ACL VPC", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group ID for the network ACL", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "rules", + "type": "TypeList", + "computed": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "Whether to allow or deny matching traffic", + "computed": true + }, + "destination": { + "name": "destination", + "type": "TypeString", + "description": "The destination CIDR block", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "icmp": { + "name": "icmp", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "description": "The ICMP traffic code to allow", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "description": "The ICMP traffic type to allow", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this Network ACL rule", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "The IP version for this rule", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this rule", + "computed": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "The source CIDR block", + "computed": true + }, + "tcp": { + "name": "tcp", + "type": "TypeList", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of TCP destination port range", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of TCP destination port range", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of TCP source port range", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of TCP source port range", + "computed": true + } + } + }, + "udp": { + "name": "udp", + "type": "TypeList", + "computed": true, + "elem": { + "port_max": { + "name": "port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of UDP destination port range", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of UDP destination port range", + "computed": true + }, + "source_port_max": { + "name": "source_port_max", + "type": "TypeInt", + "description": "The inclusive upper bound of UDP source port range", + "computed": true + }, + "source_port_min": { + "name": "source_port_min", + "type": "TypeInt", + "description": "The inclusive lower bound of UDP source port range", + "computed": true + } + } + } + } + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier", + "immutable": true, + "required": true + } + ], + "ibm_is_subnet_public_gateway_attachment": [ + { + "name": "resource_type", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name of the Public gateway instance", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Public gateway instance status", + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Public gateway zone info", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Public gateway resource group info", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "Public gateway VPC info", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier", + "immutable": true, + "required": true + }, + { + "name": "public_gateway", + "type": "TypeString", + "description": "The unique identifier of public gateway", + "required": true + }, + { + "name": "floating_ip", + "type": "TypeMap", + "computed": true + } + ], + "ibm_is_subnet_reserved_ip": [ + { + "name": "address", + "type": "TypeString", + "description": "The address for this reserved IP.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the reserved IP", + "computed": true + }, + { + "name": "reserved_ip", + "type": "TypeString", + "description": "The unique identifier of the reserved IP.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the reserved IP was created.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + { + "name": "owner", + "type": "TypeString", + "description": "The owner of a reserved IP, defining whether it is managed by the user or the provider.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "If set to true, this reserved IP will be automatically deleted", + "optional": true, + "computed": true + }, + { + "name": "target", + "type": "TypeString", + "description": "The unique identifier for target.", + "optional": true, + "computed": true + } + ], + "ibm_is_subnet_routing_table_attachment": [ + { + "name": "route_vpc_zone_ingress", + "type": "TypeBool", + "description": "If true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + "computed": true + }, + { + "name": "routes", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "route ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "route name", + "computed": true + } + } + }, + { + "name": "subnet", + "type": "TypeString", + "description": "The subnet identifier", + "immutable": true, + "required": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "The unique identifier of routing table", + "required": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "he lifecycle state of the routing table [ deleting, failed, pending, stable, suspended, updating, waiting ]", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the routing table", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + { + "name": "route_transit_gateway_ingress", + "type": "TypeBool", + "description": "If true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + "computed": true + }, + { + "name": "route_direct_link_ingress", + "type": "TypeBool", + "description": "If true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + "computed": true + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default routing table for this VPC", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subnet name", + "computed": true + } + } + } + ], + "ibm_is_virtual_endpoint_gateway": [ + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for VPE", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Endpoint gateway name", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway resource type", + "options": "provider_cloud_service, provider_infrastructure_service", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Endpoint gateway created date and time", + "computed": true + }, + { + "name": "health_state", + "type": "TypeString", + "description": "Endpoint gateway health state", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Endpoint gateway lifecycle state", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "Endpoint gateway securitygroups list", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this Endpoint gateway", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "ips", + "type": "TypeList", + "description": "Endpoint gateway IPs", + "optional": true, + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP Address", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The IPs id", + "optional": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The IPs name", + "optional": true, + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The VPE Resource Type", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "description": "The Subnet id", + "optional": true + } + } + }, + { + "name": "target", + "type": "TypeList", + "description": "Endpoint gateway target", + "required": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The target crn", + "immutable": true, + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The target name", + "immutable": true, + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The target resource type", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC id", + "immutable": true, + "required": true + } + ], + "ibm_is_virtual_endpoint_gateway_ip": [ + { + "name": "gateway", + "type": "TypeString", + "description": "Endpoint gateway ID", + "immutable": true, + "required": true + }, + { + "name": "reserved_ip", + "type": "TypeString", + "description": "Endpoint gateway IP id", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Endpoint gateway IP name", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway IP resource type", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Endpoint gateway IP created date and time", + "computed": true + }, + { + "name": "auto_delete", + "type": "TypeBool", + "description": "Endpoint gateway IP auto delete", + "computed": true + }, + { + "name": "address", + "type": "TypeString", + "description": "Endpoint gateway IP address", + "computed": true + }, + { + "name": "target", + "type": "TypeList", + "description": "Endpoint gateway detail", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "The IPs target id", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The IPs target name", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "Endpoint gateway resource type", + "computed": true + } + } + } + ], + "ibm_is_volume": [ + { + "name": "status", + "type": "TypeString", + "description": "Volume status", + "computed": true + }, + { + "name": "source_snapshot", + "type": "TypeString", + "description": "Identifier of the snapshot from which this volume was cloned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "encryption_key", + "type": "TypeString", + "description": "Volume encryption key info", + "immutable": true, + "optional": true + }, + { + "name": "profile", + "type": "TypeString", + "description": "Volume profile name", + "required": true, + "options": "general-purpose, 5iops-tier, 10iops-tier, custom" + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "iops", + "type": "TypeInt", + "description": "IOPS value for the Volume", + "min_value": "100", + "max_value": "48000", + "optional": true, + "computed": true + }, + { + "name": "status_reasons", + "type": "TypeList", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeString", + "description": "A snake case string succinctly identifying the status reason", + "computed": true + }, + "message": { + "name": "message", + "type": "TypeString", + "description": "An explanation of the status reason", + "computed": true + }, + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about this status reason", + "computed": true + } + } + }, + { + "name": "delete_all_snapshots", + "type": "TypeBool", + "description": "Deletes all snapshots created from this volume", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Volume name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "encryption_type", + "type": "TypeString", + "description": "Volume encryption type info", + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "Volume capacity value", + "default_value": 100, + "min_value": "10", + "max_value": "16000", + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group name", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN value for the volume instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "UserTags for the volume instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "bandwidth", + "type": "TypeInt", + "description": "The maximum bandwidth (in megabits per second) for the volume", + "computed": true + } + ], + "ibm_is_vpc": [ + { + "name": "default_security_group_crn", + "type": "TypeString", + "description": "Default security group CRN", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "default_network_acl", + "type": "TypeString", + "description": "Default network ACL ID", + "computed": true + }, + { + "name": "default_network_acl_name", + "type": "TypeString", + "description": "Default Network ACL name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "default_security_group", + "type": "TypeString", + "description": "Security group associated with VPC", + "computed": true + }, + { + "name": "default_routing_table", + "type": "TypeString", + "description": "Default routing table associated with VPC", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource group info", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "security_group", + "type": "TypeList", + "computed": true, + "elem": { + "group_id": { + "name": "group_id", + "type": "TypeString", + "description": "Security group id", + "computed": true + }, + "group_name": { + "name": "group_name", + "type": "TypeString", + "description": "Security group name", + "computed": true + }, + "rules": { + "name": "rules", + "type": "TypeList", + "description": "Security Rules", + "computed": true, + "elem": { + "code": { + "name": "code", + "type": "TypeInt", + "computed": true + }, + "direction": { + "name": "direction", + "type": "TypeString", + "description": "Direction of traffic to enforce, either inbound or outbound", + "computed": true + }, + "ip_version": { + "name": "ip_version", + "type": "TypeString", + "description": "IP version: ipv4", + "computed": true + }, + "port_max": { + "name": "port_max", + "type": "TypeInt", + "computed": true + }, + "port_min": { + "name": "port_min", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "remote": { + "name": "remote", + "type": "TypeString", + "description": "Security group id: an IP address, a CIDR block, or a single security group identifier", + "computed": true + }, + "rule_id": { + "name": "rule_id", + "type": "TypeString", + "description": "Rule ID", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeInt", + "computed": true + } + } + } + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "cse_source_addresses", + "type": "TypeList", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "Cloud service endpoint IP Address", + "computed": true + }, + "zone_name": { + "name": "zone_name", + "type": "TypeString", + "description": "Location info of CSE Address", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "VPC name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "default_security_group_name", + "type": "TypeString", + "description": "Default security group name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "default_network_acl_crn", + "type": "TypeString", + "description": "Default Network ACL CRN", + "computed": true + }, + { + "name": "default_routing_table_name", + "type": "TypeString", + "description": "Default routing table name", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "VPC status", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "address_prefix_management", + "type": "TypeString", + "description": "Address Prefix management value", + "default_value": "auto", + "immutable": true, + "options": "auto, manual", + "optional": true + }, + { + "name": "classic_access", + "type": "TypeBool", + "description": "Set to true if classic access needs to enabled to VPC", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "available_ipv4_address_count": { + "name": "available_ipv4_address_count", + "type": "TypeInt", + "description": "Available IPv4 address count in the subnet", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "subent name", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "subnet status", + "computed": true + }, + "total_ipv4_address_count": { + "name": "total_ipv4_address_count", + "type": "TypeInt", + "description": "Total IPv4 address count in the subnet", + "computed": true + }, + "zone": { + "name": "zone", + "type": "TypeString", + "description": "subnet location", + "computed": true + } + } + } + ], + "ibm_is_vpc_address_prefix": [ + { + "name": "name", + "type": "TypeString", + "description": "Name", + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Zone name", + "immutable": true, + "required": true + }, + { + "name": "cidr", + "type": "TypeString", + "description": "CIDIR address prefix", + "immutable": true, + "required": true + }, + { + "name": "is_default", + "type": "TypeBool", + "description": "Is default prefix for this zone in this VPC", + "default_value": false, + "optional": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC id", + "immutable": true, + "required": true + }, + { + "name": "has_subnets", + "type": "TypeBool", + "description": "Boolean value, set to true if VPC instance have subnets", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the VPC resource", + "computed": true + }, + { + "name": "address_prefix", + "type": "TypeString", + "description": "The unique identifier of the address prefix", + "computed": true + } + ], + "ibm_is_vpc_route": [ + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "VPC instance ID", + "immutable": true, + "required": true + }, + { + "name": "next_hop", + "type": "TypeString", + "description": "VPC route next hop value", + "immutable": true, + "required": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the VPC resource", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "VPC route name", + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "VPC route location", + "immutable": true, + "required": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "VPC route destination CIDR value", + "immutable": true, + "required": true + } + ], + "ibm_is_vpc_routing_table": [ + { + "name": "is_default", + "type": "TypeBool", + "description": "Indicates whether this is the default routing table for this VPC", + "computed": true + }, + { + "name": "accept_routes_from_resource_type", + "type": "TypeSet", + "description": "The filters specifying the resources that may create routes in this routing table, The resource type: vpn_gateway or vpn_server", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "route_direct_link_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Direct Link to this VPC.", + "default_value": false, + "optional": true + }, + { + "name": "route_transit_gateway_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from Transit Gateway to this VPC.", + "default_value": false, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this routing table.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "routing_table", + "type": "TypeString", + "description": "The routing table identifier.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Routing table Resource Type", + "computed": true + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "immutable": true, + "required": true + }, + { + "name": "route_vpc_zone_ingress", + "type": "TypeBool", + "description": "If set to true, this routing table will be used to route traffic that originates from subnets in other zones in this VPC.", + "default_value": false, + "optional": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Routing table Href", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Routing table Created At", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Routing table Lifecycle State", + "computed": true + }, + { + "name": "subnets", + "type": "TypeList", + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Subnet ID", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Subnet name", + "computed": true + } + } + } + ], + "ibm_is_vpc_routing_table_route": [ + { + "name": "routing_table", + "type": "TypeString", + "description": "The routing table identifier.", + "immutable": true, + "required": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination of the route.", + "immutable": true, + "required": true + }, + { + "name": "next_hop", + "type": "TypeString", + "description": "If action is deliver, the next hop that packets will be delivered to. For other action values, its address will be 0.0.0.0.", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this route.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "creator", + "type": "TypeList", + "description": "If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The VPN gateway's CRN.", + "optional": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "optional": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "required": true + } + }, + "max_items": 1 + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The VPN gateway's canonical URL.", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN gateway.", + "optional": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "optional": true + } + } + }, + { + "name": "vpc", + "type": "TypeString", + "description": "The VPC identifier.", + "immutable": true, + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone to apply the route to. Traffic from subnets in this zone will be subject to this route.", + "immutable": true, + "required": true + }, + { + "name": "action", + "type": "TypeString", + "description": "The action to perform with a packet matching the route.", + "default_value": "deliver", + "immutable": true, + "options": "delegate, delegate_vpc, deliver, drop", + "optional": true + }, + { + "name": "route_id", + "type": "TypeString", + "description": "The routing table route identifier.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "Routing table route Href", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Routing table route Created At", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "Routing table route Lifecycle State", + "computed": true + }, + { + "name": "origin", + "type": "TypeString", + "description": "The origin of this route.", + "computed": true + } + ], + "ibm_is_vpn_gateway": [ + { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Created Time of the VPN Gateway", + "computed": true + }, + { + "name": "subnet", + "type": "TypeString", + "description": "VPNGateway subnet info", + "immutable": true, + "required": true + }, + { + "name": "public_ip_address2", + "type": "TypeString", + "description": "The second public IP address assigned to the VPN gateway member.", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "VPN Gateway tags list", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "members", + "type": "TypeList", + "description": "Collection of VPN gateway members", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The public IP address assigned to the VPN gateway member", + "computed": true + }, + "private_address": { + "name": "private_address", + "type": "TypeString", + "description": "The private IP address assigned to the VPN gateway member", + "computed": true + }, + "role": { + "name": "role", + "type": "TypeString", + "description": "The high availability role assigned to the VPN gateway member", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN gateway member", + "computed": true + } + } + }, + { + "name": "public_ip_address", + "type": "TypeString", + "description": "The public IP address assigned to the VPN gateway member.", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "private_ip_address2", + "type": "TypeString", + "description": "The Second Private IP address assigned to the VPN gateway member.", + "computed": true + }, + { + "name": "mode", + "type": "TypeString", + "description": "mode in VPN gateway(route/policy)", + "default_value": "route", + "immutable": true, + "options": "route,policy", + "optional": true + }, + { + "name": "vpc", + "type": "TypeList", + "description": "VPC for the VPN Gateway", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "VPN Gateway instance name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The resource group for this VPN gateway", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "private_ip_address", + "type": "TypeString", + "description": "The Private IP address assigned to the VPN gateway member.", + "computed": true + } + ], + "ibm_is_vpn_gateway_connection": [ + { + "name": "admin_state_up", + "type": "TypeBool", + "description": "VPN gateway connection admin state", + "default_value": false, + "optional": true + }, + { + "name": "local_cidrs", + "type": "TypeSet", + "description": "VPN gateway connection local CIDRs", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "authentication_mode", + "type": "TypeString", + "description": "The authentication mode", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this VPN gateway connection was created", + "computed": true + }, + { + "name": "mode", + "type": "TypeString", + "description": "The mode of the VPN gateway", + "computed": true + }, + { + "name": "vpn_gateway", + "type": "TypeString", + "description": "VPN Gateway info", + "immutable": true, + "required": true + }, + { + "name": "peer_address", + "type": "TypeString", + "description": "VPN gateway connection peer address", + "required": true + }, + { + "name": "preshared_key", + "type": "TypeString", + "description": "vpn gateway", + "required": true + }, + { + "name": "peer_cidrs", + "type": "TypeSet", + "description": "VPN gateway connection peer CIDRs", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "interval", + "type": "TypeInt", + "description": "Interval for dead peer detection interval", + "default_value": 2, + "min_value": "1", + "max_value": "86399", + "optional": true + }, + { + "name": "ike_policy", + "type": "TypeString", + "description": "VPN gateway connection IKE Policy", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "VPN Gateway connection name", + "required": true, + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$" + }, + { + "name": "action", + "type": "TypeString", + "description": "Action detection for dead peer detection action", + "default_value": "restart", + "options": "restart, clear, hold, none", + "optional": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "Timeout for dead peer detection", + "default_value": 10, + "min_value": "2", + "max_value": "86399", + "optional": true + }, + { + "name": "ipsec_policy", + "type": "TypeString", + "description": "IP security policy for vpn gateway connection", + "optional": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type", + "computed": true + }, + { + "name": "gateway_connection", + "type": "TypeString", + "description": "The unique identifier for this VPN gateway connection", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "VPN gateway connection status", + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the VPN Gateway resource", + "computed": true + }, + { + "name": "tunnels", + "type": "TypeList", + "description": "The VPN tunnel configuration for this VPN gateway connection (in static route mode)", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address of the VPN gateway member in which the tunnel resides", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "The status of the VPN Tunnel", + "computed": true + } + } + } + ], + "ibm_is_vpn_server": [ + { + "name": "certificate_crn", + "type": "TypeString", + "description": "The crn of certificate instance for this VPN server.", + "required": true + }, + { + "name": "client_authentication", + "type": "TypeList", + "description": "The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods.", + "required": true, + "elem": { + "client_ca_crn": { + "name": "client_ca_crn", + "type": "TypeString", + "description": "The crn of certificate instance to use for the VPN client certificate authority (CA).", + "optional": true + }, + "identity_provider": { + "name": "identity_provider", + "type": "TypeString", + "description": "The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access managementThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered.", + "optional": true + }, + "method": { + "name": "method", + "type": "TypeString", + "description": "The type of authentication.", + "required": true + } + }, + "max_items": 2 + }, + { + "name": "client_auto_delete", + "type": "TypeBool", + "description": "If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed.", + "computed": true + }, + { + "name": "client_auto_delete_timeout", + "type": "TypeInt", + "description": "Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN server was created.", + "computed": true + }, + { + "name": "enable_split_tunneling", + "type": "TypeBool", + "description": "Indicates whether the split tunneling is enabled on this VPN server.", + "default_value": false, + "optional": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "The port number to use for this VPN server.", + "default_value": 443, + "min_value": "1", + "max_value": "65535", + "optional": true + }, + { + "name": "vpc", + "type": "TypeList", + "description": "The VPC this VPN server resides in.", + "computed": true, + "elem": { + "crn": { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPC.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPC.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this VPC.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique user-defined name for this VPC.", + "computed": true + } + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The type of resource referenced.", + "default_value": "vpn_server", + "optional": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "client_dns_server_ips", + "type": "TypeSet", + "description": "The DNS server addresses that will be provided to VPN clients connected to this VPN server. The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "client_idle_timeout", + "type": "TypeInt", + "description": "The seconds a VPN client can be idle before this VPN server will disconnect it. Specify `0` to prevent the server from disconnecting idle clients.", + "default_value": 600, + "min_value": "0", + "max_value": "28800", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The CRN for this VPN server.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN server.", + "computed": true + }, + { + "name": "security_groups", + "type": "TypeSet", + "description": "The unique identifier for this security group. The security groups to use for this VPN server. If unspecified, the VPC's default security group is used.", + "immutable": true, + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "client_ip_pool", + "type": "TypeString", + "description": "The VPN client IPv4 address pool, expressed in CIDR format. The request must not overlap with any existing address prefixes in the VPC or any of the following reserved address ranges: - `127.0.0.0/8` (IPv4 loopback addresses) - `161.26.0.0/16` (IBM services) - `166.8.0.0/14` (Cloud Service Endpoints) - `169.254.0.0/16` (IPv4 link-local addresses) - `224.0.0.0/4` (IPv4 multicast addresses)The prefix length of the client IP address pool's CIDR must be between`/9` (8,388,608 addresses) and `/22` (1024 addresses). A CIDR block that contains twice the number of IP addresses that are required to enable the maximum number of concurrent connections is recommended.", + "required": true, + "matches": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(3[0-2]|[1-2][0-9]|[0-9]))$" + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Fully qualified domain name assigned to this VPN server.", + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN server.", + "computed": true + }, + { + "name": "vpn_server", + "type": "TypeString", + "description": "The unique identifier for this VPN server.", + "computed": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "The transport protocol to use for this VPN server.", + "default_value": "udp", + "options": "tcp, udp", + "optional": true + }, + { + "name": "subnets", + "type": "TypeSet", + "description": "The unique identifier for this subnet. The subnets to provision this VPN server in. Use subnets in different zones for high availability.", + "required": true, + "elem": { + "type": "TypeString" + }, + "max_items": 2, + "min_items": 1 + }, + { + "name": "health_state", + "type": "TypeString", + "description": "The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN server. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPC this VPN server is serving.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true + }, + { + "name": "private_ips", + "type": "TypeList", + "description": "The reserved IPs bound to this VPN server.", + "computed": true, + "elem": { + "address": { + "name": "address", + "type": "TypeString", + "description": "The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + "computed": true + }, + "deleted": { + "name": "deleted", + "type": "TypeList", + "description": "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + "computed": true, + "elem": { + "more_info": { + "name": "more_info", + "type": "TypeString", + "description": "Link to documentation about deleted resources.", + "computed": true + } + } + }, + "href": { + "name": "href", + "type": "TypeString", + "description": "The URL for this reserved IP.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The unique identifier for this reserved IP.", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The user-defined or system-provided name for this reserved IP.", + "computed": true + }, + "resource_type": { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The unique identifier for this resource group. The resource group to use. If unspecified, the account's [default resourcegroup](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_is_vpn_server_client": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "immutable": true, + "required": true + }, + { + "name": "vpn_client", + "type": "TypeString", + "description": "The VPN Client identifier.", + "immutable": true, + "required": true + }, + { + "name": "delete", + "type": "TypeBool", + "description": "The delete to use for this VPN client to be deleted or not, when false, client is disconneted and when set to true client is deleted.", + "default_value": false, + "optional": true + }, + { + "name": "status_code", + "type": "TypeInt", + "description": "status code of the result.", + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "description of the result.", + "computed": true + } + ], + "ibm_is_vpn_server_route": [ + { + "name": "vpn_server", + "type": "TypeString", + "description": "The VPN server identifier.", + "immutable": true, + "required": true + }, + { + "name": "vpn_route", + "type": "TypeString", + "description": "The VPN route identifier.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this VPN route. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPN server the VPN route resides in.", + "min_length": 1, + "max_length": 63, + "matches": "^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", + "optional": true, + "computed": true + }, + { + "name": "href", + "type": "TypeString", + "description": "The URL for this VPN route.", + "computed": true + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "The resource type.", + "computed": true + }, + { + "name": "destination", + "type": "TypeString", + "description": "The destination to use for this VPN route in the VPN server. Must be unique within the VPN server. If an incoming packet does not match any destination, it will be dropped.", + "immutable": true, + "required": true, + "matches": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(3[0-2]|[1-2][0-9]|[0-9]))$" + }, + { + "name": "action", + "type": "TypeString", + "description": "The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server, then deliver the packet to target.- `deliver`: deliver the packet to the target.- `drop`: drop the packetThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered.", + "default_value": "deliver", + "immutable": true, + "options": "deliver, drop, translate", + "optional": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that the VPN route was created.", + "computed": true + }, + { + "name": "lifecycle_state", + "type": "TypeString", + "description": "The lifecycle state of the VPN route.", + "computed": true + } + ], + "ibm_kms_key": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID or CRN", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "key_id", + "type": "TypeString", + "description": "Key ID", + "computed": true + }, + { + "name": "payload", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "iv_value", + "type": "TypeString", + "description": "Only for imported root key", + "immutable": true, + "optional": true + }, + { + "name": "expiration_date", + "type": "TypeString", + "description": "The date the key material expires. The date format follows RFC 3339. You can set an expiration date on any key on its creation. A key moves into the Deactivated state within one hour past its expiration date, if one is assigned. If you create a key without specifying an expiration date, the key does not expire", + "immutable": true, + "optional": true + }, + { + "name": "instance_crn", + "type": "TypeString", + "description": "Key protect or hpcs instance CRN", + "computed": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "force_delete", + "type": "TypeBool", + "description": "set to true to force delete the key", + "default_value": false, + "optional": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "key_ring_id", + "type": "TypeString", + "description": "Key Ring for the Key", + "default_value": "default", + "immutable": true, + "optional": true + }, + { + "name": "key_name", + "type": "TypeString", + "description": "Key name", + "immutable": true, + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "type of service hs-crypto or kms", + "computed": true + }, + { + "name": "encrypted_nonce", + "type": "TypeString", + "description": "Only for imported root key", + "immutable": true, + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Crn of the key", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "standard_key", + "type": "TypeBool", + "description": "Standard key type", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + } + ], + "ibm_kms_key_alias": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "Key ID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "alias", + "type": "TypeString", + "description": "Key protect or hpcs key alias name", + "immutable": true, + "required": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "Key ID", + "immutable": true, + "optional": true + }, + { + "name": "existing_alias", + "type": "TypeString", + "description": "Existing Alias of the Key", + "immutable": true, + "optional": true + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_kms_key_policies": [ + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect or hpcs instance GUID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "rotation", + "type": "TypeList", + "description": "Specifies the key rotation time interval in months, with a minimum of 1, and a maximum of 12", + "optional": true, + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the resource that created the policy.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date the policy was created. The date format follows RFC 3339.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + "computed": true + }, + "interval_month": { + "name": "interval_month", + "type": "TypeInt", + "description": "Specifies the key rotation time interval in months", + "required": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The unique identifier for the resource that updated the policy.", + "computed": true + } + } + }, + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "default_value": "public", + "immutable": true, + "optional": true + }, + { + "name": "dual_auth_delete", + "type": "TypeList", + "description": "Data associated with the dual authorization delete policy.", + "optional": true, + "computed": true, + "elem": { + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the resource that created the policy.", + "computed": true + }, + "creation_date": { + "name": "creation_date", + "type": "TypeString", + "description": "The date the policy was created. The date format follows RFC 3339.", + "computed": true + }, + "crn": { + "name": "crn", + "type": "TypeString", + "description": "Cloud Resource Name (CRN) that uniquely identifies your cloud resources.", + "computed": true + }, + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "If set to true, Key Protect enables a dual authorization policy on a single key.", + "required": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The v4 UUID used to uniquely identify the policy resource, as specified by RFC 4122.", + "computed": true + }, + "last_update_date": { + "name": "last_update_date", + "type": "TypeString", + "description": "Updates when the policy is replaced or modified. The date format follows RFC 3339.", + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "The unique identifier for the resource that updated the policy.", + "computed": true + } + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "Key ID", + "optional": true + }, + { + "name": "alias", + "type": "TypeString", + "optional": true + } + ], + "ibm_kms_key_rings": [ + { + "name": "endpoint_type", + "type": "TypeString", + "description": "public or private", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Key protect Instance GUID", + "cloud_data_type": "resource_instance", + "immutable": true, + "required": true, + "cloud_data_range": [ + "service:kms|hs-crypto" + ] + }, + { + "name": "key_ring_id", + "type": "TypeString", + "description": "User defined unique ID for the key ring", + "immutable": true, + "required": true, + "min_length": 2, + "max_length": 100, + "matches": "^[a-zA-Z0-9-]*$" + } + ], + "ibm_kp_key": [ + { + "name": "crn", + "type": "TypeString", + "description": "Crn of the key", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "key_id", + "type": "TypeString", + "description": "Key ID", + "computed": true + }, + { + "name": "key_name", + "type": "TypeString", + "description": "Key name", + "immutable": true, + "required": true + }, + { + "name": "force_delete", + "type": "TypeBool", + "description": "set to true to force delete the key", + "default_value": false, + "optional": true + }, + { + "name": "iv_value", + "type": "TypeString", + "description": "Only for imported root key", + "immutable": true, + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "key_protect_id", + "type": "TypeString", + "description": "Key protect instance ID", + "immutable": true, + "required": true + }, + { + "name": "standard_key", + "type": "TypeBool", + "description": "Standard key type", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "payload", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "encrypted_nonce", + "type": "TypeString", + "description": "Only for imported root key", + "immutable": true, + "optional": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + } + ], + "ibm_lb": [ + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name info", + "immutable": true, + "required": true + }, + { + "name": "ip_address", + "type": "TypeString", + "computed": true + }, + { + "name": "ssl_offload", + "type": "TypeBool", + "description": "boolean value true if SSL offload is enabled", + "default_value": false, + "optional": true + }, + { + "name": "hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "connections", + "type": "TypeInt", + "description": "Connections value", + "required": true + }, + { + "name": "ha_enabled", + "type": "TypeBool", + "description": "true if High availability is enabled", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "security_certificate_id", + "type": "TypeInt", + "description": "Security certificate ID", + "optional": true + }, + { + "name": "subnet_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "dedicated", + "type": "TypeBool", + "description": "Boolena value true if Load balncer is dedicated type", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "ssl_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags associated with resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_lb_service": [ + { + "name": "service_group_id", + "type": "TypeInt", + "description": "service group ID", + "immutable": true, + "required": true + }, + { + "name": "ip_address_id", + "type": "TypeInt", + "description": "IP Address ID", + "immutable": true, + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Port number", + "required": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Boolean value true, if enabled else false", + "required": true + }, + { + "name": "health_check_type", + "type": "TypeString", + "description": "health check type", + "required": true + }, + { + "name": "weight", + "type": "TypeInt", + "description": "Weight value", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_lb_service_group": [ + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "virtual_server_id", + "type": "TypeInt", + "description": "Virtual server ID", + "computed": true + }, + { + "name": "load_balancer_id", + "type": "TypeInt", + "description": "Loadbalancer ID", + "immutable": true, + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Port number", + "required": true + }, + { + "name": "routing_type", + "type": "TypeString", + "description": "Routing type", + "required": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "Timeout value", + "optional": true + }, + { + "name": "service_group_id", + "type": "TypeInt", + "description": "Service group ID", + "computed": true + }, + { + "name": "allocation", + "type": "TypeInt", + "description": "Allocation type", + "required": true + }, + { + "name": "routing_method", + "type": "TypeString", + "description": "Routing method", + "required": true + } + ], + "ibm_lb_vpx": [ + { + "name": "version", + "type": "TypeString", + "description": "version info", + "immutable": true, + "required": true + }, + { + "name": "management_ip_address", + "type": "TypeString", + "description": "management IP address", + "computed": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "description": "Private VLAN id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "vip_pool", + "type": "TypeList", + "description": "List of VIP ids", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type of the VPX", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "Plan info", + "immutable": true, + "required": true + }, + { + "name": "public_subnet", + "type": "TypeString", + "description": "Public subnet", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "private_subnet", + "type": "TypeString", + "description": "Private subnet", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "speed", + "type": "TypeInt", + "description": "Speed value", + "immutable": true, + "required": true + }, + { + "name": "ip_count", + "type": "TypeInt", + "description": "IP address count", + "immutable": true, + "required": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "description": "Piblic VLAN id", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of the tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_lb_vpx_ha": [ + { + "name": "primary_id", + "type": "TypeInt", + "description": "primary ID", + "immutable": true, + "required": true + }, + { + "name": "secondary_id", + "type": "TypeInt", + "description": "Secondary ID", + "immutable": true, + "required": true + }, + { + "name": "stay_secondary", + "type": "TypeBool", + "description": "Boolean value for stay secondary", + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags set for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_lb_vpx_service": [ + { + "name": "vip_id", + "type": "TypeString", + "description": "VIP id", + "immutable": true, + "required": true + }, + { + "name": "destination_ip_address", + "type": "TypeString", + "description": "Destination IP Address", + "immutable": true, + "required": true + }, + { + "name": "destination_port", + "type": "TypeInt", + "description": "Destination Port number", + "immutable": true, + "required": true + }, + { + "name": "health_check", + "type": "TypeString", + "description": "Health check info", + "required": true + }, + { + "name": "usip", + "type": "TypeString", + "description": "usip info", + "default_value": "NO", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "list of tags associated with the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "name", + "immutable": true, + "required": true + }, + { + "name": "weight", + "type": "TypeInt", + "description": "Weight value", + "required": true + }, + { + "name": "connection_limit", + "type": "TypeInt", + "description": "Number of connections limit", + "required": true + } + ], + "ibm_lb_vpx_vip": [ + { + "name": "nad_controller_id", + "type": "TypeInt", + "description": "NAD controller ID", + "immutable": true, + "required": true + }, + { + "name": "source_port", + "type": "TypeInt", + "description": "Source Port number", + "immutable": true, + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Type", + "immutable": true, + "required": true + }, + { + "name": "security_certificate_id", + "type": "TypeInt", + "description": "security certificate ID", + "immutable": true, + "optional": true + }, + { + "name": "load_balancing_method", + "type": "TypeString", + "description": "Load balancing method", + "required": true + }, + { + "name": "persistence", + "type": "TypeString", + "description": "Persistance value", + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name", + "immutable": true, + "required": true + }, + { + "name": "virtual_ip_address", + "type": "TypeString", + "description": "Virtual IP address", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_lbaas": [ + { + "name": "name", + "type": "TypeString", + "description": "The load balancer's name.", + "immutable": true, + "required": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "datacenter", + "type": "TypeString", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "default_value": 90, + "optional": true + }, + { + "name": "vip", + "type": "TypeString", + "description": "The virtual ip address of this load balancer", + "computed": true + }, + { + "name": "protocols", + "type": "TypeSet", + "description": "Protocols to be assigned to this load balancer.", + "optional": true, + "elem": { + "backend_port": { + "name": "backend_port", + "type": "TypeInt", + "description": "Backend Protocol port number. Should be in range (1, 65535)", + "required": true + }, + "backend_protocol": { + "name": "backend_protocol", + "type": "TypeString", + "description": "Backend protocol, one of 'TCP', 'HTTP', 'HTTPS'.", + "required": true + }, + "frontend_port": { + "name": "frontend_port", + "type": "TypeInt", + "description": "Frontend Protocol port number. Should be in range (1, 65535)", + "required": true + }, + "frontend_protocol": { + "name": "frontend_protocol", + "type": "TypeString", + "description": "Frontend protocol, one of 'TCP', 'HTTP', 'HTTPS'.", + "required": true + }, + "load_balancing_method": { + "name": "load_balancing_method", + "type": "TypeString", + "description": "Load balancing algorithm: 'round_robin', 'weighted_round_robin', 'least_connection'", + "default_value": "round_robin", + "optional": true + }, + "max_conn": { + "name": "max_conn", + "type": "TypeInt", + "description": "No. of connections the listener can accept. Should be between 1-64000", + "optional": true + }, + "protocol_id": { + "name": "protocol_id", + "type": "TypeString", + "description": "The UUID of a load balancer protocol", + "computed": true + }, + "session_stickiness": { + "name": "session_stickiness", + "type": "TypeString", + "description": "Session stickness. Valid values is SOURCE_IP and HTTP_COOKIE", + "optional": true + }, + "tls_certificate_id": { + "name": "tls_certificate_id", + "type": "TypeInt", + "description": "This references to SSL/TLS certificate for a protocol", + "optional": true + } + } + }, + { + "name": "ssl_ciphers", + "type": "TypeSet", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "status", + "type": "TypeString", + "description": "The operation status 'ONLINE' or 'OFFLINE' of a load balancer.", + "computed": true + }, + { + "name": "use_system_public_ip_pool", + "type": "TypeBool", + "description": "\"in public loadbalancer - Public IP address allocation done by system public IP pool or public subnet.\"", + "optional": true, + "computed": true + }, + { + "name": "health_monitors", + "type": "TypeList", + "computed": true, + "elem": { + "interval": { + "name": "interval", + "type": "TypeInt", + "computed": true + }, + "max_retries": { + "name": "max_retries", + "type": "TypeInt", + "computed": true + }, + "monitor_id": { + "name": "monitor_id", + "type": "TypeString", + "computed": true + }, + "port": { + "name": "port", + "type": "TypeInt", + "computed": true + }, + "protocol": { + "name": "protocol", + "type": "TypeString", + "computed": true + }, + "timeout": { + "name": "timeout", + "type": "TypeInt", + "computed": true + }, + "url_path": { + "name": "url_path", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of a load balancer.", + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Specifies if a load balancer is public or private", + "default_value": "PUBLIC", + "immutable": true, + "optional": true + }, + { + "name": "subnets", + "type": "TypeList", + "description": "The subnet where this Load Balancer will be provisioned.", + "immutable": true, + "required": true, + "elem": { + "type": "TypeInt" + }, + "max_items": 1, + "min_items": 1 + } + ], + "ibm_lbaas_health_monitor": [ + { + "name": "lbaas_id", + "type": "TypeString", + "description": "LBAAS id", + "immutable": true, + "required": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "Protocol value", + "required": true + }, + { + "name": "port", + "type": "TypeInt", + "description": "Port number", + "required": true + }, + { + "name": "interval", + "type": "TypeInt", + "description": "Interval value", + "default_value": 5, + "optional": true + }, + { + "name": "max_retries", + "type": "TypeInt", + "description": "Maximum retry counts", + "default_value": 2, + "optional": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "Timeout in seconds", + "default_value": 2, + "optional": true + }, + { + "name": "url_path", + "type": "TypeString", + "description": "URL Path", + "default_value": "/", + "optional": true + }, + { + "name": "monitor_id", + "type": "TypeString", + "description": "Monitor ID", + "immutable": true, + "required": true + } + ], + "ibm_lbaas_server_instance_attachment": [ + { + "name": "private_ip_address", + "type": "TypeString", + "description": "The Private IP address of a load balancer member.", + "immutable": true, + "required": true + }, + { + "name": "weight", + "type": "TypeInt", + "description": "The weight of a load balancer member.", + "optional": true, + "computed": true + }, + { + "name": "lbaas_id", + "type": "TypeString", + "description": "The UUID of a load balancer", + "immutable": true, + "required": true + }, + { + "name": "uuid", + "type": "TypeString", + "description": "The UUID of a load balancer member", + "computed": true + } + ], + "ibm_multi_vlan_firewall": [ + { + "name": "pod", + "type": "TypeString", + "description": "POD name", + "immutable": true, + "required": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "description": "Private VLAN id", + "computed": true + }, + { + "name": "firewall_type", + "type": "TypeString", + "description": "Firewall type", + "immutable": true, + "required": true + }, + { + "name": "private_ip", + "type": "TypeString", + "description": "Private IP Address", + "computed": true + }, + { + "name": "username", + "type": "TypeString", + "description": "User name", + "computed": true + }, + { + "name": "addon_configuration", + "type": "TypeList", + "description": "High Availability - [Web Filtering Add-on, NGFW Add-on, AV Add-on] or [Web Filtering Add-on, NGFW Add-on, AV Add-on]", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "description": "Public VLAN id", + "computed": true + }, + { + "name": "public_ip", + "type": "TypeString", + "description": "Public IP Address", + "computed": true + }, + { + "name": "public_ipv6", + "type": "TypeString", + "description": "Public IPV6 IP", + "computed": true + }, + { + "name": "password", + "type": "TypeString", + "description": "Password", + "secure": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "name", + "immutable": true, + "required": true + } + ], + "ibm_network_gateway": [ + { + "name": "post_install_script_uri", + "type": "TypeString", + "immutable": true, + "optional": true + }, + { + "name": "public_ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "private_vlan_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_vlan_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "members", + "type": "TypeSet", + "description": "The hardware members of this network Gateway", + "required": true, + "elem": { + "datacenter": { + "name": "datacenter", + "type": "TypeString", + "immutable": true, + "required": true + }, + "disk_key_names": { + "name": "disk_key_names", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "domain": { + "name": "domain", + "type": "TypeString", + "immutable": true, + "required": true + }, + "hostname": { + "name": "hostname", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "ipv6_address": { + "name": "ipv6_address", + "type": "TypeString", + "computed": true + }, + "ipv6_enabled": { + "name": "ipv6_enabled", + "type": "TypeBool", + "default_value": true, + "immutable": true, + "optional": true + }, + "member_id": { + "name": "member_id", + "type": "TypeInt", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "immutable": true, + "required": true + }, + "network_speed": { + "name": "network_speed", + "type": "TypeInt", + "default_value": 100, + "immutable": true, + "optional": true + }, + "notes": { + "name": "notes", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "os_key_name": { + "name": "os_key_name", + "type": "TypeString", + "default_value": "OS_VYATTA_5600_5_X_UP_TO_1GBPS_SUBSCRIPTION_EDITION_64_BIT", + "immutable": true, + "optional": true + }, + "package_key_name": { + "name": "package_key_name", + "type": "TypeString", + "default_value": "NETWORK_GATEWAY_APPLIANCE", + "immutable": true, + "optional": true + }, + "post_install_script_uri": { + "name": "post_install_script_uri", + "type": "TypeString", + "immutable": true, + "optional": true + }, + "private_ipv4_address": { + "name": "private_ipv4_address", + "type": "TypeString", + "computed": true + }, + "private_network_only": { + "name": "private_network_only", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + "private_vlan_id": { + "name": "private_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + "process_key_name": { + "name": "process_key_name", + "type": "TypeString", + "default_value": "INTEL_SINGLE_XEON_1270_3_50", + "immutable": true, + "optional": true + }, + "public_bandwidth": { + "name": "public_bandwidth", + "type": "TypeInt", + "default_value": 20000, + "immutable": true, + "optional": true + }, + "public_ipv4_address": { + "name": "public_ipv4_address", + "type": "TypeString", + "computed": true + }, + "public_vlan_id": { + "name": "public_vlan_id", + "type": "TypeInt", + "immutable": true, + "optional": true, + "computed": true + }, + "redundant_network": { + "name": "redundant_network", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + "redundant_power_supply": { + "name": "redundant_power_supply", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + "ssh_key_ids": { + "name": "ssh_key_ids", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + "storage_groups": { + "name": "storage_groups", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "array_size": { + "name": "array_size", + "type": "TypeInt", + "optional": true + }, + "array_type_id": { + "name": "array_type_id", + "type": "TypeInt", + "required": true + }, + "hard_drives": { + "name": "hard_drives", + "type": "TypeList", + "required": true, + "elem": { + "type": "TypeInt" + } + }, + "partition_template_id": { + "name": "partition_template_id", + "type": "TypeInt", + "optional": true + } + } + }, + "tags": { + "name": "tags", + "type": "TypeSet", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "tcp_monitoring": { + "name": "tcp_monitoring", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + "unbonded_network": { + "name": "unbonded_network", + "type": "TypeBool", + "default_value": false, + "immutable": true, + "optional": true + }, + "user_metadata": { + "name": "user_metadata", + "type": "TypeString", + "immutable": true, + "optional": true + } + }, + "max_items": 2, + "min_items": 1 + }, + { + "name": "associated_vlans", + "type": "TypeList", + "description": "The VLAN instances associated with this Network Gateway", + "computed": true, + "elem": { + "bypass": { + "name": "bypass", + "type": "TypeBool", + "description": "Indicates if the VLAN is in bypass or routed modes", + "computed": true + }, + "network_vlan_id": { + "name": "network_vlan_id", + "type": "TypeInt", + "description": "The Identifier of the VLAN which is associated", + "computed": true + }, + "vlan_id": { + "name": "vlan_id", + "type": "TypeInt", + "computed": true + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the gateway", + "required": true + }, + { + "name": "ssh_key_ids", + "type": "TypeList", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "private_ip_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "private_ipv4_address", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ip_address_id", + "type": "TypeInt", + "computed": true + }, + { + "name": "public_ipv6_address_id", + "type": "TypeInt", + "computed": true + } + ], + "ibm_network_gateway_vlan_association": [ + { + "name": "bypass", + "type": "TypeBool", + "description": "Indicates if the VLAN should be in bypass or routed modes", + "default_value": true, + "optional": true + }, + { + "name": "gateway_id", + "type": "TypeInt", + "description": "Gateway instance ID", + "immutable": true, + "required": true + }, + { + "name": "network_vlan_id", + "type": "TypeInt", + "description": "The Identifier of the VLAN to be associated", + "immutable": true, + "required": true + } + ], + "ibm_network_interface_sg_attachment": [ + { + "name": "network_interface_id", + "type": "TypeInt", + "description": "Network interface ID", + "immutable": true, + "required": true + }, + { + "name": "soft_reboot", + "type": "TypeBool", + "description": "Boolean value set to true, if soft reboot needs to be done.", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "security_group_id", + "type": "TypeInt", + "description": "Security group ID", + "immutable": true, + "required": true + } + ], + "ibm_network_public_ip": [ + { + "name": "ip_address", + "type": "TypeString", + "description": "IP Address", + "computed": true + }, + { + "name": "routes_to", + "type": "TypeString", + "description": "Route info", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "notes", + "type": "TypeString", + "description": "Additional notes", + "optional": true + } + ], + "ibm_network_vlan": [ + { + "name": "softlayer_managed", + "type": "TypeBool", + "description": "Zzset to true if VLAN is managed by softlayer", + "computed": true + }, + { + "name": "child_resource_count", + "type": "TypeInt", + "description": "Child resource count", + "computed": true + }, + { + "name": "subnets", + "type": "TypeSet", + "computed": true, + "elem": { + "cidr": { + "name": "cidr", + "type": "TypeInt", + "computed": true + }, + "gateway": { + "name": "gateway", + "type": "TypeString", + "computed": true + }, + "subnet": { + "name": "subnet", + "type": "TypeString", + "computed": true + }, + "subnet_size": { + "name": "subnet_size", + "type": "TypeInt", + "computed": true + }, + "subnet_type": { + "name": "subnet_type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "VLAN type", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "VLAN name", + "optional": true + }, + { + "name": "vlan_number", + "type": "TypeInt", + "description": "VLAN number", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "router_hostname", + "type": "TypeString", + "description": "router host name", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_network_vlan_spanning": [ + { + "name": "vlan_spanning", + "type": "TypeString", + "description": "VLAN Spanning set to On or Off", + "required": true + } + ], + "ibm_ob_logging": [ + { + "name": "instance_name", + "type": "TypeString", + "description": "LogDNA instance Name", + "computed": true + }, + { + "name": "agent_key", + "type": "TypeString", + "description": "Agent key name", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "discovered_agent", + "type": "TypeBool", + "description": "Discovered agent", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Namespace", + "computed": true + }, + { + "name": "logdna_ingestion_key", + "type": "TypeString", + "description": "LogDNA ingestion key", + "optional": true, + "computed": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "ID of the LogDNA service instance to latch", + "cloud_data_type": "resource_instance", + "required": true + }, + { + "name": "private_endpoint", + "type": "TypeBool", + "description": "Add this option to connect to your LogDNA service instance through the private service endpoint", + "optional": true, + "computed": true + }, + { + "name": "daemonset_name", + "type": "TypeString", + "description": "Daemon Set Name", + "computed": true + }, + { + "name": "agent_namespace", + "type": "TypeString", + "description": "Agent Namespace", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Name or ID of the cluster to be used.", + "immutable": true, + "required": true + } + ], + "ibm_ob_monitoring": [ + { + "name": "instance_id", + "type": "TypeString", + "description": "ID of the Sysdig service instance to latch", + "cloud_data_type": "resource_instance", + "required": true + }, + { + "name": "agent_key", + "type": "TypeString", + "description": "Agent key name", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "discovered_agent", + "type": "TypeBool", + "description": "Discovered agent", + "computed": true + }, + { + "name": "namespace", + "type": "TypeString", + "description": "Namespace", + "computed": true + }, + { + "name": "agent_namespace", + "type": "TypeString", + "description": "Agent Namespace", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "Name or ID of the cluster to be used.", + "immutable": true, + "required": true + }, + { + "name": "sysdig_access_key", + "type": "TypeString", + "description": "Sysdig ingestion key", + "optional": true, + "computed": true + }, + { + "name": "private_endpoint", + "type": "TypeBool", + "description": "Add this option to connect to your Sysdig service instance through the private service endpoint", + "optional": true, + "computed": true + }, + { + "name": "daemonset_name", + "type": "TypeString", + "description": "Daemon Set Name", + "computed": true + }, + { + "name": "instance_name", + "type": "TypeString", + "description": "Sysdig instance Name", + "computed": true + } + ], + "ibm_object_storage_account": [ + { + "name": "local_note", + "type": "TypeString", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "computed": true + } + ], + "ibm_org": [ + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Org name, for example myorg@domain", + "required": true + }, + { + "name": "org_quota_definition_guid", + "type": "TypeString", + "description": "Org quota guid", + "optional": true, + "computed": true + }, + { + "name": "billing_managers", + "type": "TypeSet", + "description": "The IBMID of the users who will have billing manager role in this org, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managers", + "type": "TypeSet", + "description": "The IBMID of the users who will have manager role in this org, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "auditors", + "type": "TypeSet", + "description": "The IBMID of the users who will have auditor role in this org, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "users", + "type": "TypeSet", + "description": "The IBMID of the users who will have user role in this org, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_pi_capture": [ + { + "name": "pi_capture_volume_ids", + "type": "TypeSet", + "description": "List of Data volume IDs", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_capture_cloud_storage_access_key", + "type": "TypeString", + "description": "Name of Cloud Storage Access Key", + "secure": true, + "immutable": true, + "optional": true + }, + { + "name": "pi_capture_cloud_storage_secret_key", + "type": "TypeString", + "description": "Name of the Cloud Storage Secret Key", + "secure": true, + "immutable": true, + "optional": true + }, + { + "name": "pi_capture_storage_image_path", + "type": "TypeString", + "description": "Cloud Storage Image Path (bucket-name [/folder/../..])", + "immutable": true, + "optional": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "Cloud Instance ID - This is the service_instance_id.", + "immutable": true, + "required": true + }, + { + "name": "pi_capture_name", + "type": "TypeString", + "description": "Name of the capture to create. Note : this must be unique", + "immutable": true, + "required": true + }, + { + "name": "pi_capture_destination", + "type": "TypeString", + "description": "Destination for the deployable image", + "immutable": true, + "required": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "Instance Name of the Power VM", + "immutable": true, + "required": true + }, + { + "name": "pi_capture_cloud_storage_region", + "type": "TypeString", + "description": "List of Regions to use", + "immutable": true, + "optional": true + }, + { + "name": "image_id", + "type": "TypeString", + "description": "Image ID of Capture Instance", + "computed": true + } + ], + "ibm_pi_cloud_connection": [ + { + "name": "pi_cloud_connection_name", + "type": "TypeString", + "description": "Name of the cloud connection", + "required": true + }, + { + "name": "pi_cloud_connection_global_routing", + "type": "TypeBool", + "description": "Enable global routing for this cloud connection", + "default_value": false, + "optional": true + }, + { + "name": "pi_cloud_connection_classic_enabled", + "type": "TypeBool", + "description": "Enable classic endpoint destination", + "default_value": false, + "optional": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_cloud_connection_gre_destination_address", + "type": "TypeString", + "description": "GRE destination IP address", + "optional": true + }, + { + "name": "pi_cloud_connection_vpc_enabled", + "type": "TypeBool", + "description": "Enable VPC for this cloud connection", + "default_value": false, + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Link status", + "computed": true + }, + { + "name": "port", + "type": "TypeString", + "description": "Port", + "computed": true + }, + { + "name": "connection_mode", + "type": "TypeString", + "description": "Type of service the gateway is attached to", + "computed": true + }, + { + "name": "pi_cloud_connection_metered", + "type": "TypeBool", + "description": "Enable metered for this cloud connection", + "default_value": false, + "optional": true + }, + { + "name": "pi_cloud_connection_gre_cidr", + "type": "TypeString", + "description": "GRE network in CIDR notation", + "optional": true + }, + { + "name": "pi_cloud_connection_vpc_crns", + "type": "TypeSet", + "description": "Set of VPCs to attach to this cloud connection", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_cloud_connection_transit_enabled", + "type": "TypeBool", + "description": "Enable transit gateway for this cloud connection", + "default_value": false, + "optional": true + }, + { + "name": "gre_source_address", + "type": "TypeString", + "description": "GRE auto-assigned source IP address", + "computed": true + }, + { + "name": "pi_cloud_connection_speed", + "type": "TypeInt", + "description": "Speed of the cloud connection (speed in megabits per second)", + "required": true + }, + { + "name": "pi_cloud_connection_networks", + "type": "TypeSet", + "description": "Set of Networks to attach to this cloud connection", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "cloud_connection_id", + "type": "TypeString", + "description": "Cloud connection ID", + "computed": true + }, + { + "name": "ibm_ip_address", + "type": "TypeString", + "description": "IBM IP address", + "computed": true + }, + { + "name": "user_ip_address", + "type": "TypeString", + "description": "User IP address", + "computed": true + } + ], + "ibm_pi_cloud_connection_network_attach": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "immutable": true, + "required": true + }, + { + "name": "pi_cloud_connection_id", + "type": "TypeString", + "description": "Cloud Connection ID", + "immutable": true, + "required": true + }, + { + "name": "pi_network_id", + "type": "TypeString", + "description": "Network ID to attach to this cloud connection", + "immutable": true, + "required": true + } + ], + "ibm_pi_console_language": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "The unique identifier or name of the instance", + "required": true + }, + { + "name": "pi_language_code", + "type": "TypeString", + "description": "Language code", + "required": true + } + ], + "ibm_pi_dhcp": [ + { + "name": "pi_dhcp_name", + "type": "TypeString", + "description": "Optional name of DHCP Service (will be prefixed by DHCP identifier)", + "immutable": true, + "optional": true + }, + { + "name": "pi_dhcp_snat_enabled", + "type": "TypeBool", + "description": "Indicates if SNAT will be enabled for the DHCP service", + "default_value": true, + "immutable": true, + "optional": true + }, + { + "name": "leases", + "type": "TypeList", + "description": "The list of DHCP Server PVM Instance leases", + "computed": true, + "elem": { + "instance_ip": { + "name": "instance_ip", + "type": "TypeString", + "description": "The IP of the PVM Instance", + "computed": true + }, + "instance_mac": { + "name": "instance_mac", + "type": "TypeString", + "description": "The MAC Address of the PVM Instance", + "computed": true + } + } + }, + { + "name": "network", + "type": "TypeString", + "description": "The ID of the DHCP Server private network (deprecated - replaced by network_id)", + "computed": true + }, + { + "name": "network_id", + "type": "TypeString", + "description": "The ID of the DHCP Server private network", + "computed": true + }, + { + "name": "network_name", + "type": "TypeString", + "description": "The name of the DHCP Server private network", + "computed": true + }, + { + "name": "pi_cidr", + "type": "TypeString", + "description": "Optional cidr for DHCP private network", + "immutable": true, + "optional": true + }, + { + "name": "pi_cloud_connection_id", + "type": "TypeString", + "description": "Optional cloud connection uuid to connect with DHCP private network", + "immutable": true, + "optional": true + }, + { + "name": "pi_dns_server", + "type": "TypeString", + "description": "Optional DNS Server for DHCP service", + "immutable": true, + "optional": true + }, + { + "name": "dhcp_id", + "type": "TypeString", + "description": "The ID of the DHCP Server", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the DHCP Server", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "immutable": true, + "required": true + } + ], + "ibm_pi_ike_policy": [ + { + "name": "pi_policy_name", + "type": "TypeString", + "description": "Name of the IKE Policy", + "required": true + }, + { + "name": "pi_policy_dh_group", + "type": "TypeInt", + "description": "DH group of the IKE Policy", + "required": true + }, + { + "name": "pi_policy_version", + "type": "TypeInt", + "description": "Version of the IKE Policy", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_policy_key_lifetime", + "type": "TypeInt", + "description": "Policy key lifetime", + "required": true + }, + { + "name": "pi_policy_preshared_key", + "type": "TypeString", + "description": "Preshared key used in this IKE Policy (length of preshared key must be even)", + "required": true + }, + { + "name": "pi_policy_authentication", + "type": "TypeString", + "description": "Authentication for the IKE Policy", + "default_value": "none", + "optional": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "IKE Policy ID", + "computed": true + }, + { + "name": "pi_policy_encryption", + "type": "TypeString", + "description": "Encryption of the IKE Policy", + "required": true + } + ], + "ibm_pi_image": [ + { + "name": "pi_image_name", + "type": "TypeString", + "description": "Image name", + "immutable": true, + "required": true + }, + { + "name": "pi_image_access_key", + "type": "TypeString", + "description": "Cloud Object Storage access key; required for buckets with private access", + "secure": true, + "immutable": true, + "optional": true + }, + { + "name": "image_id", + "type": "TypeString", + "description": "Image ID", + "computed": true + }, + { + "name": "pi_image_bucket_region", + "type": "TypeString", + "description": "Cloud Object Storage region", + "immutable": true, + "optional": true + }, + { + "name": "pi_affinity_volume", + "type": "TypeString", + "description": "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + "immutable": true, + "optional": true + }, + { + "name": "pi_image_bucket_file_name", + "type": "TypeString", + "description": "Cloud Object Storage image filename", + "immutable": true, + "optional": true + }, + { + "name": "pi_image_storage_type", + "type": "TypeString", + "description": "Type of storage", + "immutable": true, + "optional": true + }, + { + "name": "pi_image_storage_pool", + "type": "TypeString", + "description": "Storage pool where the image will be loaded, if provided then pi_image_storage_type and pi_affinity_policy will be ignored", + "immutable": true, + "optional": true + }, + { + "name": "pi_anti_affinity_volumes", + "type": "TypeList", + "description": "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_image_id", + "type": "TypeString", + "description": "Instance image id", + "immutable": true, + "optional": true + }, + { + "name": "pi_image_secret_key", + "type": "TypeString", + "description": "Cloud Object Storage secret key; required for buckets with private access", + "secure": true, + "immutable": true, + "optional": true + }, + { + "name": "pi_image_bucket_access", + "type": "TypeString", + "description": "Indicates if the bucket has public or private access", + "default_value": "public", + "immutable": true, + "optional": true + }, + { + "name": "pi_affinity_policy", + "type": "TypeString", + "description": "Affinity policy for image; ignored if pi_image_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + "immutable": true, + "optional": true + }, + { + "name": "pi_affinity_instance", + "type": "TypeString", + "description": "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", + "immutable": true, + "optional": true + }, + { + "name": "pi_anti_affinity_instances", + "type": "TypeList", + "description": "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + "immutable": true, + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "immutable": true, + "required": true + }, + { + "name": "pi_image_bucket_name", + "type": "TypeString", + "description": "Cloud Object Storage bucket name; bucket-name[/optional/folder]", + "immutable": true, + "optional": true + } + ], + "ibm_pi_image_export": [ + { + "name": "pi_image_bucket_name", + "type": "TypeString", + "description": "Cloud Object Storage bucket name; bucket-name[/optional/folder]", + "immutable": true, + "required": true + }, + { + "name": "pi_image_access_key", + "type": "TypeString", + "description": "Cloud Object Storage access key; required for buckets with private access", + "secure": true, + "immutable": true, + "required": true + }, + { + "name": "pi_image_secret_key", + "type": "TypeString", + "description": "Cloud Object Storage secret key; required for buckets with private access", + "secure": true, + "immutable": true, + "required": true + }, + { + "name": "pi_image_bucket_region", + "type": "TypeString", + "description": "Cloud Object Storage region", + "immutable": true, + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "immutable": true, + "required": true + }, + { + "name": "pi_image_id", + "type": "TypeString", + "description": "Instance image id", + "immutable": true, + "required": true + } + ], + "ibm_pi_instance": [ + { + "name": "pi_storage_type", + "type": "TypeString", + "description": "Storage type for server deployment", + "optional": true, + "computed": true + }, + { + "name": "pi_sap_profile_id", + "type": "TypeString", + "description": "SAP Profile ID for the amount of cores and memory", + "optional": true + }, + { + "name": "pi_sys_type", + "type": "TypeString", + "description": "PI Instance system type", + "optional": true, + "computed": true + }, + { + "name": "max_virtual_cores", + "type": "TypeInt", + "description": "Maximum Virtual Cores Assigned to the PVMInstance", + "computed": true + }, + { + "name": "min_memory", + "type": "TypeFloat", + "description": "Minimum memory", + "computed": true + }, + { + "name": "pi_storage_pool", + "type": "TypeString", + "description": "Storage Pool for server deployment; if provided then pi_affinity_policy and pi_storage_type will be ignored", + "optional": true, + "computed": true + }, + { + "name": "pin_policy", + "type": "TypeString", + "description": "PIN Policy of the Instance", + "computed": true + }, + { + "name": "pi_pin_policy", + "type": "TypeString", + "description": "Pin Policy of the instance", + "default_value": "none", + "optional": true + }, + { + "name": "pi_health_status", + "type": "TypeString", + "description": "Allow the user to set the status of the lpar so that they can connect to it faster", + "default_value": "OK", + "optional": true + }, + { + "name": "pi_virtual_cores_assigned", + "type": "TypeInt", + "description": "Virtual Cores Assigned to the PVMInstance", + "optional": true, + "computed": true + }, + { + "name": "pi_license_repository_capacity", + "type": "TypeInt", + "description": "The VTL license repository capacity TB value", + "optional": true, + "computed": true + }, + { + "name": "max_processors", + "type": "TypeFloat", + "description": "Maximum number of processors", + "computed": true + }, + { + "name": "pi_storage_pool_affinity", + "type": "TypeBool", + "description": "Indicates if all volumes attached to the server must reside in the same storage pool", + "default_value": true, + "optional": true + }, + { + "name": "instance_id", + "type": "TypeString", + "description": "Instance ID", + "cloud_data_type": "resource_instance", + "computed": true + }, + { + "name": "os_type", + "type": "TypeString", + "description": "OS Type", + "computed": true + }, + { + "name": "pi_sap_deployment_type", + "type": "TypeString", + "description": "Custom SAP Deployment Type Information", + "optional": true + }, + { + "name": "min_virtual_cores", + "type": "TypeInt", + "description": "Minimum Virtual Cores Assigned to the PVMInstance", + "computed": true + }, + { + "name": "pi_anti_affinity_volumes", + "type": "TypeList", + "description": "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_anti_affinity_instances", + "type": "TypeList", + "description": "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "shared_processor_pool_id", + "type": "TypeString", + "description": "Shared Processor Pool ID the instance is deployed on", + "computed": true + }, + { + "name": "health_status", + "type": "TypeString", + "description": "PI Instance health status", + "computed": true + }, + { + "name": "pi_image_id", + "type": "TypeString", + "description": "PI instance image id", + "required": true + }, + { + "name": "min_processors", + "type": "TypeFloat", + "description": "Minimum number of the CPUs", + "computed": true + }, + { + "name": "pi_affinity_volume", + "type": "TypeString", + "description": "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + "optional": true + }, + { + "name": "pi_placement_group_id", + "type": "TypeString", + "description": "Placement group ID", + "optional": true + }, + { + "name": "pi_deployment_type", + "type": "TypeString", + "description": "Custom Deployment Type Information", + "optional": true + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "Operating System", + "computed": true + }, + { + "name": "pi_replication_policy", + "type": "TypeString", + "description": "Replication policy for the PI Instance", + "default_value": "none", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "PI instance status", + "computed": true + }, + { + "name": "pi_migratable", + "type": "TypeBool", + "description": "set to true to enable migration of the PI instance", + "optional": true, + "computed": true + }, + { + "name": "pi_user_data", + "type": "TypeString", + "description": "Base64 encoded data to be passed in for invoking a cloud init script", + "optional": true + }, + { + "name": "pi_affinity_policy", + "type": "TypeString", + "description": "Affinity policy for pvm instance being created; ignored if pi_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + "optional": true + }, + { + "name": "pi_replicants", + "type": "TypeInt", + "description": "PI Instance replicas count", + "default_value": 1, + "optional": true + }, + { + "name": "pi_processors", + "type": "TypeFloat", + "description": "Processors count", + "optional": true, + "computed": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "PI Instance name", + "required": true + }, + { + "name": "pi_proc_type", + "type": "TypeString", + "description": "Instance processor type", + "optional": true, + "computed": true + }, + { + "name": "max_memory", + "type": "TypeFloat", + "description": "Maximum memory size", + "computed": true + }, + { + "name": "pi_volume_ids", + "type": "TypeSet", + "description": "List of PI volumes", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_affinity_instance", + "type": "TypeString", + "description": "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", + "optional": true + }, + { + "name": "pi_network", + "type": "TypeList", + "description": "List of one or more networks to attach to the instance", + "required": true, + "elem": { + "external_ip": { + "name": "external_ip", + "type": "TypeString", + "computed": true + }, + "ip_address": { + "name": "ip_address", + "type": "TypeString", + "optional": true, + "computed": true + }, + "mac_address": { + "name": "mac_address", + "type": "TypeString", + "computed": true + }, + "network_id": { + "name": "network_id", + "type": "TypeString", + "required": true + }, + "network_name": { + "name": "network_name", + "type": "TypeString", + "computed": true + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "pi_shared_processor_pool", + "type": "TypeString", + "description": "Shared Processor Pool the instance is deployed on", + "immutable": true, + "optional": true + }, + { + "name": "pi_key_pair_name", + "type": "TypeString", + "description": "SSH key name", + "optional": true + }, + { + "name": "pi_progress", + "type": "TypeFloat", + "description": "Progress of the operation", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "This is the Power Instance id that is assigned to the account", + "immutable": true, + "required": true + }, + { + "name": "pi_storage_connection", + "type": "TypeString", + "description": "Storage Connectivity Group for server deployment", + "optional": true + }, + { + "name": "pi_memory", + "type": "TypeFloat", + "description": "Memory size", + "optional": true, + "computed": true + }, + { + "name": "pi_replication_scheme", + "type": "TypeString", + "description": "Replication scheme", + "default_value": "suffix", + "optional": true + } + ], + "ibm_pi_instance_action": [ + { + "name": "pi_instance_id", + "type": "TypeString", + "description": "PVM instance ID", + "required": true + }, + { + "name": "pi_action", + "type": "TypeString", + "description": "PVM instance action type", + "required": true + }, + { + "name": "pi_health_status", + "type": "TypeString", + "description": "Set the health status of the PVM instance to connect it faster", + "default_value": "OK", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the PVM instance", + "computed": true + }, + { + "name": "progress", + "type": "TypeFloat", + "description": "The progress of an operation", + "computed": true + }, + { + "name": "health_status", + "type": "TypeString", + "description": "The PVM's health status value", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI Cloud instance id", + "required": true + } + ], + "ibm_pi_ipsec_policy": [ + { + "name": "pi_policy_authentication", + "type": "TypeString", + "description": "Authentication for the IPSec Policy", + "default_value": "none", + "optional": true + }, + { + "name": "policy_id", + "type": "TypeString", + "description": "IPSec policy ID", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_policy_name", + "type": "TypeString", + "description": "Name of the IPSec Policy", + "required": true + }, + { + "name": "pi_policy_dh_group", + "type": "TypeInt", + "description": "DH group of the IPSec Policy", + "required": true + }, + { + "name": "pi_policy_encryption", + "type": "TypeString", + "description": "Encryption of the IPSec Policy", + "required": true + }, + { + "name": "pi_policy_key_lifetime", + "type": "TypeInt", + "description": "Policy key lifetime", + "required": true + }, + { + "name": "pi_policy_pfs", + "type": "TypeBool", + "description": "Perfect Forward Secrecy", + "required": true + } + ], + "ibm_pi_key": [ + { + "name": "key_id", + "type": "TypeString", + "computed": true, + "deprecated": "User defined name for the SSH key (deprecated - replaced by name)" + }, + { + "name": "name", + "type": "TypeString", + "description": "User defined name for the SSH key", + "computed": true + }, + { + "name": "ssh_key", + "type": "TypeString", + "description": "SSH RSA key", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_key_name", + "type": "TypeString", + "description": "User defined name for the SSH key", + "required": true + }, + { + "name": "pi_ssh_key", + "type": "TypeString", + "description": "SSH RSA key", + "required": true + }, + { + "name": "creation_date", + "type": "TypeString", + "description": "Date of SSH Key creation", + "computed": true + } + ], + "ibm_pi_network": [ + { + "name": "vlan_id", + "type": "TypeFloat", + "description": "VLAN Id value", + "computed": true + }, + { + "name": "pi_dns", + "type": "TypeSet", + "description": "List of PI network DNS name", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_ipaddress_range", + "type": "TypeList", + "description": "List of one or more ip address range(s)", + "optional": true, + "computed": true, + "elem": { + "pi_ending_ip_address": { + "name": "pi_ending_ip_address", + "type": "TypeString", + "description": "Ending ip address", + "required": true + }, + "pi_starting_ip_address": { + "name": "pi_starting_ip_address", + "type": "TypeString", + "description": "Starting ip address", + "required": true + } + } + }, + { + "name": "network_id", + "type": "TypeString", + "description": "PI network ID", + "computed": true + }, + { + "name": "pi_network_jumbo", + "type": "TypeBool", + "description": "PI network enable MTU Jumbo option", + "optional": true, + "computed": true + }, + { + "name": "pi_network_type", + "type": "TypeString", + "description": "PI network type", + "required": true + }, + { + "name": "pi_network_name", + "type": "TypeString", + "description": "PI network name", + "required": true + }, + { + "name": "pi_cidr", + "type": "TypeString", + "description": "PI network CIDR", + "optional": true, + "computed": true + }, + { + "name": "pi_gateway", + "type": "TypeString", + "description": "PI network gateway", + "optional": true, + "computed": true + } + ], + "ibm_pi_network_port": [ + { + "name": "pi_network_name", + "type": "TypeString", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "required": true + }, + { + "name": "pi_network_port_description", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "pi_network_port_ipaddress", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + { + "name": "portid", + "type": "TypeString", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ip", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_network_port_attach": [ + { + "name": "network_port_id", + "type": "TypeString", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_network_port_ipaddress", + "type": "TypeString", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "port_id", + "type": "TypeString", + "computed": true, + "deprecated": "port_id attribute is deprecated, use network_port_id instead." + }, + { + "name": "pi_network_name", + "type": "TypeString", + "description": "Network Name - This is the subnet name in the Cloud instance", + "immutable": true, + "required": true + }, + { + "name": "pi_network_port_description", + "type": "TypeString", + "description": "A human readable description for this network Port", + "default_value": "Port Created via Terraform", + "immutable": true, + "optional": true + }, + { + "name": "macaddress", + "type": "TypeString", + "computed": true + }, + { + "name": "public_ip", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "immutable": true, + "required": true + }, + { + "name": "pi_instance_id", + "type": "TypeString", + "description": "Instance id to attach the network port to", + "immutable": true, + "required": true + } + ], + "ibm_pi_placement_group": [ + { + "name": "pi_placement_group_name", + "type": "TypeString", + "description": "Name of the placement group", + "required": true + }, + { + "name": "pi_placement_group_policy", + "type": "TypeString", + "description": "Policy of the placement group", + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "members", + "type": "TypeSet", + "description": "Server IDs that are the placement group members", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "placement_group_id", + "type": "TypeString", + "description": "PI placement group ID", + "computed": true + } + ], + "ibm_pi_shared_processor_pool": [ + { + "name": "spp_placement_groups", + "type": "TypeList", + "description": "SPP placement groups the shared processor pool are in", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "instances", + "type": "TypeList", + "description": "List of server instances deployed in the shared processor pool", + "computed": true, + "elem": { + "availability_zone": { + "name": "availability_zone", + "type": "TypeString", + "description": "Availability zone for the server instances", + "computed": true + }, + "cpus": { + "name": "cpus", + "type": "TypeInt", + "description": "The amount of cpus for the server instance", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The server instance ID", + "computed": true + }, + "memory": { + "name": "memory", + "type": "TypeInt", + "description": "The amount of memory for the server instance", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The server instance name", + "computed": true + }, + "status": { + "name": "status", + "type": "TypeString", + "description": "Status of the server", + "computed": true + }, + "uncapped": { + "name": "uncapped", + "type": "TypeBool", + "description": "Identifies if uncapped or not", + "computed": true + }, + "vcpus": { + "name": "vcpus", + "type": "TypeFloat", + "description": "The amout of vcpus for the server instance", + "computed": true + } + } + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_shared_processor_pool_placement_group_id", + "type": "TypeString", + "description": "Placement group the shared processor pool is created in", + "optional": true + }, + { + "name": "shared_processor_pool_id", + "type": "TypeString", + "description": "Shared processor pool ID", + "computed": true + }, + { + "name": "allocated_cores", + "type": "TypeFloat", + "description": "Shared processor pool allocated cores", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "The status of the shared processor pool", + "computed": true + }, + { + "name": "status_detail", + "type": "TypeString", + "description": "The status details of the shared processor pool", + "computed": true + }, + { + "name": "pi_shared_processor_pool_name", + "type": "TypeString", + "description": "Name of the shared processor pool", + "required": true + }, + { + "name": "pi_shared_processor_pool_host_group", + "type": "TypeString", + "description": "Host group of the shared processor pool", + "required": true + }, + { + "name": "pi_shared_processor_pool_reserved_cores", + "type": "TypeInt", + "description": "The amount of reserved cores for the shared processor pool", + "required": true + }, + { + "name": "available_cores", + "type": "TypeInt", + "description": "Shared processor pool available cores", + "computed": true + }, + { + "name": "host_id", + "type": "TypeInt", + "description": "The host ID where the shared processor pool resides", + "computed": true + } + ], + "ibm_pi_snapshot": [ + { + "name": "creation_date", + "type": "TypeString", + "computed": true + }, + { + "name": "last_update_date", + "type": "TypeString", + "computed": true + }, + { + "name": "volume_snapshots", + "type": "TypeMap", + "computed": true + }, + { + "name": "pi_instance_name", + "type": "TypeString", + "description": "Instance name / id of the pvm", + "required": true + }, + { + "name": "snapshot_id", + "type": "TypeString", + "description": "ID of the PVM instance snapshot", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "Cloud Instance ID - This is the service_instance_id.", + "required": true + }, + { + "name": "pi_description", + "type": "TypeString", + "description": "Description of the PVM instance snapshot", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Snapshot description", + "optional": true, + "deprecated": "This field is deprecated, use pi_description instead" + }, + { + "name": "pi_snap_shot_id", + "type": "TypeString", + "description": "Id of the snapshot", + "computed": true, + "deprecated": "This field is deprecated, use snapshot_id instead" + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "pi_snap_shot_name", + "type": "TypeString", + "description": "Unique name of the snapshot", + "required": true + }, + { + "name": "pi_volume_ids", + "type": "TypeSet", + "description": "List of PI volumes", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_pi_spp_placement_group": [ + { + "name": "pi_spp_placement_group_name", + "type": "TypeString", + "description": "Name of the SPP placement group", + "immutable": true, + "required": true + }, + { + "name": "pi_spp_placement_group_policy", + "type": "TypeString", + "description": "Policy of the SPP placement group", + "immutable": true, + "required": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "immutable": true, + "required": true + }, + { + "name": "members", + "type": "TypeSet", + "description": "Member SPP IDs that are the SPP placement group members", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "spp_placement_group_id", + "type": "TypeString", + "description": "SPP placement group ID", + "computed": true + } + ], + "ibm_pi_volume": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "Cloud Instance ID - This is the service_instance_id.", + "required": true + }, + { + "name": "pi_volume_shareable", + "type": "TypeBool", + "description": "Flag to indicate if the volume can be shared across multiple instances?", + "optional": true + }, + { + "name": "pi_volume_size", + "type": "TypeFloat", + "description": "Size of the volume in GB", + "required": true + }, + { + "name": "pi_affinity_policy", + "type": "TypeString", + "description": "Affinity policy for data volume being created; ignored if pi_volume_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + "optional": true + }, + { + "name": "pi_anti_affinity_volumes", + "type": "TypeList", + "description": "List of volumes to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "volume_id", + "type": "TypeString", + "description": "Volume ID", + "computed": true + }, + { + "name": "delete_on_termination", + "type": "TypeBool", + "description": "Should the volume be deleted during termination", + "computed": true + }, + { + "name": "wwn", + "type": "TypeString", + "description": "WWN Of the volume", + "computed": true + }, + { + "name": "pi_volume_name", + "type": "TypeString", + "description": "Volume Name to create", + "required": true + }, + { + "name": "pi_volume_type", + "type": "TypeString", + "description": "Type of Disk, required if pi_affinity_policy and pi_volume_pool not provided, otherwise ignored", + "optional": true, + "computed": true + }, + { + "name": "pi_affinity_instance", + "type": "TypeString", + "description": "PVM Instance (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_volume is not provided", + "optional": true + }, + { + "name": "pi_anti_affinity_instances", + "type": "TypeList", + "description": "List of pvmInstances to base volume anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "pi_volume_pool", + "type": "TypeString", + "description": "Volume pool where the volume will be created; if provided then pi_volume_type and pi_affinity_policy values will be ignored", + "optional": true, + "computed": true + }, + { + "name": "pi_affinity_volume", + "type": "TypeString", + "description": "Volume (ID or Name) to base volume affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", + "optional": true + }, + { + "name": "volume_status", + "type": "TypeString", + "description": "Volume status", + "computed": true + } + ], + "ibm_pi_volume_attach": [ + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "Cloud Instance ID - This is the service_instance_id.", + "immutable": true, + "required": true + }, + { + "name": "pi_volume_id", + "type": "TypeString", + "description": "Id of the volume to attach. Note these volumes should have been created", + "immutable": true, + "required": true + }, + { + "name": "pi_instance_id", + "type": "TypeString", + "description": "PI Instance Id", + "immutable": true, + "required": true + }, + { + "name": "status", + "type": "TypeString", + "computed": true + } + ], + "ibm_pi_vpn_connection": [ + { + "name": "connection_status", + "type": "TypeString", + "description": "Status of the VPN connection", + "computed": true + }, + { + "name": "gateway_address", + "type": "TypeString", + "description": "Public IP address of the VPN Gateway (vSRX) attached to this VPN Connection", + "computed": true + }, + { + "name": "dead_peer_detections", + "type": "TypeMap", + "description": "Dead Peer Detection", + "computed": true + }, + { + "name": "pi_vpn_connection_mode", + "type": "TypeString", + "description": "Mode used by this VPN Connection, either 'policy' or 'route'", + "required": true + }, + { + "name": "pi_networks", + "type": "TypeSet", + "description": "Set of network IDs to attach to this VPN connection", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "local_gateway_address", + "type": "TypeString", + "description": "Local Gateway address, only in 'route' mode", + "computed": true + }, + { + "name": "pi_ipsec_policy_id", + "type": "TypeString", + "description": "Unique identifier of IPSec Policy selected for this VPN Connection", + "required": true + }, + { + "name": "pi_peer_gateway_address", + "type": "TypeString", + "description": "Peer Gateway address", + "required": true + }, + { + "name": "pi_peer_subnets", + "type": "TypeSet", + "description": "Set of CIDR of peer subnets", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "connection_id", + "type": "TypeString", + "description": "VPN connection ID", + "computed": true + }, + { + "name": "pi_cloud_instance_id", + "type": "TypeString", + "description": "PI cloud instance ID", + "required": true + }, + { + "name": "pi_vpn_connection_name", + "type": "TypeString", + "description": "Name of the VPN Connection", + "required": true + }, + { + "name": "pi_ike_policy_id", + "type": "TypeString", + "description": "Unique identifier of IKE Policy selected for this VPN Connection", + "required": true + } + ], + "ibm_pn_application_chrome": [ + { + "name": "guid", + "type": "TypeString", + "description": "Unique guid of the push notification instance.", + "immutable": true, + "required": true + }, + { + "name": "server_key", + "type": "TypeString", + "description": "A server key that gives the push service an authorized access to Google services that is used for Chrome Web Push.", + "required": true + }, + { + "name": "web_site_url", + "type": "TypeString", + "description": "The URL of the WebSite / WebApp that should be permitted to subscribe to WebPush.", + "required": true + } + ], + "ibm_resource_group": [ + { + "name": "crn", + "type": "TypeString", + "description": "The full CRN associated with the resource group", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date when the resource group was last updated.", + "computed": true + }, + { + "name": "teams_url", + "type": "TypeString", + "description": "The URL to access the team details that associated with the resource group.", + "computed": true + }, + { + "name": "payment_methods_url", + "type": "TypeString", + "description": "The URL to access the payment methods details that associated with the resource group.", + "computed": true + }, + { + "name": "quota_url", + "type": "TypeString", + "description": "The URL to access the quota details that associated with the resource group.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the resource group", + "required": true + }, + { + "name": "default", + "type": "TypeBool", + "description": "Specifies whether its default resource group or not", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_linkages", + "type": "TypeSet", + "description": "An array of the resources that linked to the resource group", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "state", + "type": "TypeString", + "description": "State of the resource group", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the resource group was initially created.", + "computed": true + }, + { + "name": "quota_id", + "type": "TypeString", + "description": "An alpha-numeric value identifying the quota ID associated with the resource group.", + "computed": true + } + ], + "ibm_resource_instance": [ + { + "name": "name", + "type": "TypeString", + "description": "A name for the resource instance", + "required": true + }, + { + "name": "tags", + "type": "TypeSet", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "dashboard_url", + "type": "TypeString", + "description": "Dashboard URL to access resource.", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "An alpha-numeric value identifying the account ID.", + "computed": true + }, + { + "name": "resource_aliases_url", + "type": "TypeString", + "description": "The relative path to the resource aliases for the instance.", + "computed": true + }, + { + "name": "resource_bindings_url", + "type": "TypeString", + "description": "The relative path to the resource bindings for the instance.", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "Guid of resource instance", + "computed": true + }, + { + "name": "service_endpoints", + "type": "TypeString", + "description": "Types of the service endpoints. Possible values are 'public', 'private', 'public-and-private'.", + "optional": true, + "computed": true + }, + { + "name": "resource_group_crn", + "type": "TypeString", + "description": "The long ID (full CRN) of the resource group", + "computed": true + }, + { + "name": "resource_id", + "type": "TypeString", + "description": "The unique ID of the offering", + "computed": true + }, + { + "name": "sub_type", + "type": "TypeString", + "description": "The sub-type of instance, e.g. cfaas .", + "computed": true + }, + { + "name": "allow_cleanup", + "type": "TypeBool", + "description": "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + "computed": true + }, + { + "name": "scheduled_reclaim_by", + "type": "TypeString", + "description": "The subject who initiated the instance reclamation.", + "computed": true + }, + { + "name": "restored_at", + "type": "TypeString", + "description": "The date when the instance under reclamation was restored.", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the service", + "required": true + }, + { + "name": "deleted_at", + "type": "TypeString", + "description": "The date when the instance was deleted.", + "computed": true + }, + { + "name": "scheduled_reclaim_at", + "type": "TypeString", + "description": "The date when the instance was scheduled for reclamation.", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about the resource", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of the instance, e.g. service_instance.", + "computed": true + }, + { + "name": "resource_keys_url", + "type": "TypeString", + "description": "The relative path to the resource keys for the instance.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The subject who created the instance.", + "computed": true + }, + { + "name": "update_at", + "type": "TypeString", + "description": "The date when the instance was last updated.", + "computed": true + }, + { + "name": "restored_by", + "type": "TypeString", + "description": "The subject who restored the instance back from reclamation.", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The resource group id", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true, + "computed": true, + "cloud_data_range": [ + "resolved_to:id" + ] + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "last_operation", + "type": "TypeMap", + "description": "The status of the last operation requested on the instance", + "computed": true + }, + { + "name": "update_by", + "type": "TypeString", + "description": "The subject who updated the instance.", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass. Must be a JSON object", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Status of resource instance", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The current state of the instance.", + "computed": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "A boolean that dictates if the resource instance should be deleted (cleaned up) during the processing of a region instance delete call.", + "computed": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the service offering like cloud-object-storage, kms etc", + "immutable": true, + "required": true + }, + { + "name": "parameters_json", + "type": "TypeString", + "description": "Arbitrary parameters to pass in Json string format", + "optional": true + }, + { + "name": "plan_history", + "type": "TypeList", + "description": "The plan history of the instance.", + "computed": true, + "elem": { + "resource_plan_id": { + "name": "resource_plan_id", + "type": "TypeString", + "computed": true + }, + "start_date": { + "name": "start_date", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the instance was created.", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location where the instance available", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "resource_plan_id", + "type": "TypeString", + "description": "The unique ID of the plan associated with the offering", + "computed": true + }, + { + "name": "target_crn", + "type": "TypeString", + "description": "The full deployment CRN as defined in the global catalog", + "computed": true + }, + { + "name": "deleted_by", + "type": "TypeString", + "description": "The subject who deleted the instance.", + "computed": true + }, + { + "name": "extensions", + "type": "TypeMap", + "description": "The extended metadata as a map associated with the resource instance.", + "computed": true + } + ], + "ibm_resource_key": [ + { + "name": "status", + "type": "TypeString", + "description": "Status of resource key", + "computed": true + }, + { + "name": "guid", + "type": "TypeString", + "description": "When you create a new key, a globally unique identifier (GUID) is assigned.", + "computed": true + }, + { + "name": "iam_compatible", + "type": "TypeBool", + "description": "Specifies whether the key's credentials support IAM.", + "computed": true + }, + { + "name": "role", + "type": "TypeString", + "description": "Name of the user role.Valid roles are Writer, Reader, Manager, Administrator, Operator, Viewer, Editor and Custom Roles.", + "immutable": true, + "optional": true + }, + { + "name": "credentials", + "type": "TypeMap", + "description": "Credentials asociated with the key", + "secure": true, + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "An alpha-numeric value identifying the account ID.", + "computed": true + }, + { + "name": "source_crn", + "type": "TypeString", + "description": "The CRN of resource instance or alias associated to the key.", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The state of the key.", + "computed": true + }, + { + "name": "deleted_at", + "type": "TypeString", + "description": "The date when the key was deleted.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the resource key", + "immutable": true, + "required": true + }, + { + "name": "url", + "type": "TypeString", + "description": "When you created a new key, a relative URL path is created identifying the location of the key.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The subject who created the key.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The subject who updated the key.", + "computed": true + }, + { + "name": "deleted_by", + "type": "TypeString", + "description": "The subject who deleted the key.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "crn of resource key", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The short ID of the resource group.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass. Must be a JSON object", + "optional": true + }, + { + "name": "credentials_json", + "type": "TypeString", + "description": "Credentials asociated with the key in json string", + "secure": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_instance_url", + "type": "TypeString", + "description": "The relative path to the resource.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date when the key was created.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date when the key was last updated.", + "computed": true + }, + { + "name": "resource_instance_id", + "type": "TypeString", + "description": "The id of the resource instance for which to create resource key", + "cloud_data_type": "resource_instance", + "immutable": true, + "optional": true, + "cloud_data_range": [ + "service:%s" + ] + }, + { + "name": "resource_alias_id", + "type": "TypeString", + "description": "The id of the resource alias for which to create resource key", + "immutable": true, + "optional": true + } + ], + "ibm_resource_tag": [ + { + "name": "resource_id", + "type": "TypeString", + "description": "CRN of the resource on which the tags should be attached", + "required": true, + "min_length": 1, + "max_length": 1024, + "matches": "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$\u0026'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags associated with resource instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_type", + "type": "TypeString", + "description": "Resource type on which the tags should be attached", + "optional": true + }, + { + "name": "tag_type", + "type": "TypeString", + "description": "Type of the tag. Only allowed values are: user, or service or access (default value : user)", + "options": "service,access,user", + "optional": true, + "computed": true + }, + { + "name": "acccount_id", + "type": "TypeString", + "description": "The ID of the account that owns the resources to be tagged (required if tag-type is set to service)", + "computed": true + } + ], + "ibm_satellite_cluster": [ + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags for the resources", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "wait_for_worker_update", + "type": "TypeBool", + "description": "Wait for worker node to update during kube version update.", + "default_value": true, + "optional": true + }, + { + "name": "patch_version", + "type": "TypeString", + "description": "Kubernetes patch version", + "optional": true + }, + { + "name": "retry_patch_version", + "type": "TypeInt", + "description": "Argument which helps to retry the patch version updates on worker nodes. Increment the value to retry the patch updates if the previous apply fails", + "optional": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "The number of worker nodes per zone in the default worker pool. Required when '--host-label' is specified. (default: 0)", + "optional": true, + "computed": true + }, + { + "name": "pod_subnet", + "type": "TypeString", + "description": "User provided value for the pod subnet", + "optional": true, + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The name or ID of the Satellite location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "zones", + "type": "TypeSet", + "description": "Zone info for worker pool", + "optional": true, + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Zone for the worker pool in a multizone cluster", + "required": true + } + } + }, + { + "name": "crn_token", + "type": "TypeString", + "description": "The IBM Cloud Identity and Access Management (IAM) service CRN token for the service that creates the cluster.", + "secure": true, + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique name for the new IBM Cloud Satellite cluster", + "immutable": true, + "required": true + }, + { + "name": "pull_secret", + "type": "TypeString", + "description": "The RedHat pull secret to create the OpenShift cluster", + "optional": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "public_service_endpoint_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "state", + "type": "TypeString", + "description": "The lifecycle state of the cluster.", + "computed": true + }, + { + "name": "kube_version", + "type": "TypeString", + "description": "The OpenShift Container Platform version", + "optional": true, + "computed": true + }, + { + "name": "master_url", + "type": "TypeString", + "computed": true + }, + { + "name": "private_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "Operating system of the default worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS.", + "optional": true, + "computed": true + }, + { + "name": "public_service_endpoint_url", + "type": "TypeString", + "computed": true + }, + { + "name": "master_status", + "type": "TypeString", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of resource instance", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "disable_public_service_endpoint", + "type": "TypeBool", + "description": "Boolean value true if Public service endpoint to be disabled", + "default_value": false, + "optional": true + }, + { + "name": "service_subnet", + "type": "TypeString", + "description": "User provided value for service subnet", + "optional": true, + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "private_service_endpoint_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "enable_config_admin", + "type": "TypeBool", + "description": "Grant cluster admin access to Satellite Config to manage Kubernetes resources.", + "optional": true, + "computed": true + }, + { + "name": "default_worker_pool_labels", + "type": "TypeMap", + "description": "Labels on the default worker pool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host_labels", + "type": "TypeSet", + "description": "Labels that describe a Satellite host for default workerpool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_satellite_cluster_worker_pool": [ + { + "name": "isolation", + "type": "TypeString", + "optional": true, + "computed": true + }, + { + "name": "entitlement", + "type": "TypeString", + "optional": true + }, + { + "name": "operating_system", + "type": "TypeString", + "description": "Operating system of the worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS.", + "optional": true, + "computed": true + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Specify the desired number of workers per zone in this worker pool", + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name for the worker pool", + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "The unique name for the new IBM Cloud Satellite cluster", + "immutable": true, + "required": true + }, + { + "name": "flavor", + "type": "TypeString", + "description": "The flavor defines the amount of virtual CPU, memory, and disk space that is set up in each worker node", + "optional": true, + "computed": true + }, + { + "name": "disk_encryption", + "type": "TypeBool", + "description": "Disk encryption for worker node", + "optional": true + }, + { + "name": "zones", + "type": "TypeSet", + "description": "Zone info for worker pool", + "optional": true, + "computed": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "Zone for the worker pool in a multizone cluster", + "required": true + } + } + }, + { + "name": "worker_pool_labels", + "type": "TypeMap", + "description": "Labels on all the workers in the worker pool", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host_labels", + "type": "TypeSet", + "description": "Labels that describe a Satellite host", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + } + ], + "ibm_satellite_cluster_worker_pool_zone_attachment": [ + { + "name": "zone", + "type": "TypeString", + "immutable": true, + "required": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that the Satellite location is in. To list the resource group ID of the location, use the `GET /v2/satellite/getController` API method.", + "cloud_data_type": "resource_group", + "immutable": true, + "optional": true + }, + { + "name": "autobalance_enabled", + "type": "TypeBool", + "computed": true + }, + { + "name": "messages", + "type": "TypeList", + "description": "Filter features by a list of comma separated collections.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "worker_count", + "type": "TypeInt", + "description": "Number of workers", + "computed": true + }, + { + "name": "cluster", + "type": "TypeString", + "immutable": true, + "required": true + }, + { + "name": "worker_pool", + "type": "TypeString", + "immutable": true, + "required": true + } + ], + "ibm_satellite_endpoint": [ + { + "name": "created_by", + "type": "TypeString", + "description": "The service or person who created the endpoint. Must be 1000 characters or fewer.", + "optional": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "Service instance associated with this location.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "service_name", + "type": "TypeString", + "description": "The service name of the endpoint.", + "computed": true + }, + { + "name": "client_host", + "type": "TypeString", + "description": "The hostname which Satellite Link server listen on for the on-location endpoint, or the hostname which the connector server listen on for the on-cloud endpoint destiantion.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time when the Endpoint is created.", + "computed": true + }, + { + "name": "connection_type", + "type": "TypeString", + "description": "The type of the endpoint.", + "required": true, + "options": "cloud, location" + }, + { + "name": "client_mutual_auth", + "type": "TypeBool", + "description": "Whether enable mutual auth in the client application side, when client_protocol is 'tls' or 'https', this field is required.", + "default_value": false, + "optional": true + }, + { + "name": "reject_unauth", + "type": "TypeBool", + "description": "Whether reject any connection to the server application which is not authorized with the list of supplied CAs in the fields certs.server_cert.", + "default_value": false, + "optional": true + }, + { + "name": "endpoint_id", + "type": "TypeString", + "description": "The Endpoint ID.", + "computed": true + }, + { + "name": "performance", + "type": "TypeList", + "description": "The last performance data of the endpoint.", + "computed": true, + "elem": { + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + }, + "connection": { + "name": "connection", + "type": "TypeInt", + "description": "Concurrent connections number of moment when probe read the data.", + "optional": true + }, + "connectors": { + "name": "connectors", + "type": "TypeList", + "description": "The last performance data of the endpoint from each Connector.", + "optional": true, + "elem": { + "connections": { + "name": "connections", + "type": "TypeInt", + "description": "Concurrent connections number of moment when probe read the data from the Connector.", + "optional": true + }, + "connector": { + "name": "connector", + "type": "TypeString", + "description": "The name of the connector reported the performance data.", + "optional": true + }, + "rx_bw": { + "name": "rx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "optional": true + }, + "tx_bw": { + "name": "tx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "optional": true + } + } + }, + "rx_bandwidth": { + "name": "rx_bandwidth", + "type": "TypeInt", + "description": "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + }, + "tx_bandwidth": { + "name": "tx_bandwidth", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + } + } + }, + { + "name": "last_change", + "type": "TypeString", + "description": "The last time modify the Endpoint configurations.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The Location ID.", + "cloud_data_type": "region", + "required": true + }, + { + "name": "display_name", + "type": "TypeString", + "description": "The display name of the endpoint. Endpoint names must start with a letter and end with an alphanumeric character, can contain letters, numbers, and hyphen (-), and must be 63 characters or fewer.", + "required": true + }, + { + "name": "server_mutual_auth", + "type": "TypeBool", + "description": "Whether enable mutual auth in the server application side, when client_protocol is 'tls', this field is required.", + "default_value": false, + "optional": true + }, + { + "name": "timeout", + "type": "TypeInt", + "description": "The inactivity timeout in the Endpoint side.", + "min_value": "1", + "max_value": "180", + "optional": true + }, + { + "name": "certs", + "type": "TypeList", + "description": "The certs.", + "optional": true, + "elem": { + "client": { + "name": "client", + "type": "TypeList", + "description": "The CA which Satellite Link trust when receiving the connection from the client application.", + "optional": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The root cert or the self-signed cert of the client application.", + "optional": true, + "elem": { + "file_contents": { + "name": "file_contents", + "type": "TypeString", + "description": "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", + "optional": true + }, + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + "connector": { + "name": "connector", + "type": "TypeList", + "description": "The cert which Satellite Link connector provide to identify itself for connecting to the client/server application.", + "optional": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The end-entity cert. This is required when the key is defined.", + "optional": true, + "elem": { + "file_contents": { + "name": "file_contents", + "type": "TypeString", + "description": "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", + "optional": true + }, + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "optional": true + } + }, + "max_items": 1 + }, + "key": { + "name": "key", + "type": "TypeList", + "description": "The private key of the end-entity certificate. This is required when the cert is defined.", + "optional": true, + "elem": { + "file_contents": { + "name": "file_contents", + "type": "TypeString", + "description": "The content of the key. The private key file must be in Privacy-enhanced Electronic Mail (PEM) format.", + "optional": true + }, + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The name of the key.", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + "server": { + "name": "server", + "type": "TypeList", + "description": "The CA which Satellite Link trust when sending the connection to server application.", + "optional": true, + "elem": { + "cert": { + "name": "cert", + "type": "TypeList", + "description": "The root cert or the self-signed cert of the server application.", + "optional": true, + "elem": { + "file_contents": { + "name": "file_contents", + "type": "TypeString", + "description": "The content of the cert. The certificate file must be in Privacy-enhanced Electronic Mail (PEM) format.", + "optional": true + }, + "filename": { + "name": "filename", + "type": "TypeString", + "description": "The filename of the cert.", + "optional": true + } + }, + "max_items": 1 + } + }, + "max_items": 1 + } + }, + "max_items": 1 + }, + { + "name": "sources", + "type": "TypeList", + "computed": true, + "elem": { + "enabled": { + "name": "enabled", + "type": "TypeBool", + "description": "Whether the source is enabled for the endpoint.", + "optional": true + }, + "last_change": { + "name": "last_change", + "type": "TypeString", + "description": "The last time modify the Endpoint configurations.", + "optional": true + }, + "pending": { + "name": "pending", + "type": "TypeBool", + "description": "Whether the source has been enabled on this endpoint.", + "optional": true + }, + "source_id": { + "name": "source_id", + "type": "TypeString", + "description": "The Source ID.", + "optional": true + } + } + }, + { + "name": "connector_port", + "type": "TypeInt", + "description": "The connector port.", + "computed": true + }, + { + "name": "server_host", + "type": "TypeString", + "description": "The host name or IP address of the server endpoint. For 'http-tunnel' protocol, server_host can start with '*.' , which means a wildcard to it's sub domains. Such as '*.example.com' can accept request to 'api.example.com' and 'www.example.com'.", + "required": true + }, + { + "name": "client_protocol", + "type": "TypeString", + "description": "The protocol in the client application side.", + "required": true, + "options": "http, http-tunnel, https, tcp, tls, udp" + }, + { + "name": "server_protocol", + "type": "TypeString", + "description": "The protocol in the server application side. This parameter will change to default value if it is omitted even when using PATCH API. If client_protocol is 'udp', server_protocol must be 'udp'. If client_protocol is 'tcp'/'http', server_protocol could be 'tcp'/'tls' and default to 'tcp'. If client_protocol is 'tls'/'https', server_protocol could be 'tcp'/'tls' and default to 'tls'. If client_protocol is 'http-tunnel', server_protocol must be 'tcp'.", + "options": "tcp, tls, udp", + "optional": true + }, + { + "name": "status", + "type": "TypeString", + "description": "Whether the Endpoint is active or not.", + "computed": true + }, + { + "name": "server_port", + "type": "TypeInt", + "description": "The port number of the server endpoint. For 'http-tunnel' protocol, server_port can be 0, which means any port. Such as 0 is good for 80 (http) and 443 (https).", + "required": true + }, + { + "name": "sni", + "type": "TypeString", + "description": "The server name indicator (SNI) which used to connect to the server endpoint. Only useful if server side requires SNI.", + "optional": true + }, + { + "name": "client_port", + "type": "TypeInt", + "description": "The port which Satellite Link server listen on for the on-location, or the port which the connector server listen on for the on-cloud endpoint destiantion.", + "computed": true + } + ], + "ibm_satellite_host": [ + { + "name": "host_id", + "type": "TypeString", + "description": "The specific host ID to assign to a Satellite location or cluster", + "required": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "The zone within the cluster to assign the host to", + "optional": true, + "computed": true + }, + { + "name": "worker_pool", + "type": "TypeString", + "description": "The name or ID of the worker pool within the cluster to assign the host to", + "optional": true, + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The name or ID of the Satellite location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "cluster", + "type": "TypeString", + "description": "The name or ID of a Satellite location or cluster to assign the host to", + "optional": true, + "computed": true + }, + { + "name": "labels", + "type": "TypeSet", + "description": "List of labels for the host", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "host_provider", + "type": "TypeString", + "description": "Host Provider", + "optional": true + }, + { + "name": "host_state", + "type": "TypeString", + "description": "Health status of the host", + "computed": true + }, + { + "name": "wait_till", + "type": "TypeString", + "description": "Wait until location is normal", + "options": "location_normal", + "optional": true + } + ], + "ibm_satellite_link": [ + { + "name": "status", + "type": "TypeString", + "description": "Enabled/Disabled.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "Location ID.", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "ws_endpoint", + "type": "TypeString", + "description": "The ws endpoint of the location.", + "optional": true, + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Description of the location.", + "computed": true + }, + { + "name": "satellite_link_host", + "type": "TypeString", + "description": "Satellite Link hostname of the location.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "CRN of the Location.", + "cloud_data_type": "crn", + "immutable": true, + "required": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Timestamp of creation of location.", + "computed": true + }, + { + "name": "last_change", + "type": "TypeString", + "description": "Timestamp of latest modification of location.", + "computed": true + }, + { + "name": "performance", + "type": "TypeList", + "description": "The last performance data of the Location.", + "computed": true, + "elem": { + "avg_latency": { + "name": "avg_latency", + "type": "TypeInt", + "description": "Average latency calculated form latency of each Connector between Tunnel Server, unit is ms. -1 means no Connector established Tunnel.", + "optional": true + }, + "bandwidth": { + "name": "bandwidth", + "type": "TypeInt", + "description": "Average Tatal Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + }, + "connectors": { + "name": "connectors", + "type": "TypeList", + "description": "The last performance data of the Location read from each Connector.", + "optional": true, + "elem": { + "connector": { + "name": "connector", + "type": "TypeString", + "description": "The name of the connector reported the performance data.", + "optional": true + }, + "latency": { + "name": "latency", + "type": "TypeInt", + "description": "Latency between Connector and the Tunnel Server it connected.", + "optional": true + }, + "rx_bw": { + "name": "rx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "optional": true + }, + "tx_bw": { + "name": "tx_bw", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes read from the Connector, unit is Byte/s.", + "optional": true + } + } + }, + "health_status": { + "name": "health_status", + "type": "TypeString", + "description": "Tunnels health status based on the Tunnels number established. Down(0)/Critical(1)/Up(\u003e=2).", + "optional": true + }, + "rx_bandwidth": { + "name": "rx_bandwidth", + "type": "TypeInt", + "description": "Average Receive (to Cloud) Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + }, + "tunnels": { + "name": "tunnels", + "type": "TypeInt", + "description": "Tunnels number estbalished from the Location.", + "optional": true + }, + "tx_bandwidth": { + "name": "tx_bandwidth", + "type": "TypeInt", + "description": "Average Transmitted (to Location) Bandwidth of last two minutes, unit is Byte/s.", + "optional": true + } + } + } + ], + "ibm_satellite_location": [ + { + "name": "location", + "type": "TypeString", + "description": "A unique name for the new Satellite location", + "cloud_data_type": "region", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "A description of the new Satellite location", + "optional": true + }, + { + "name": "cos_credentials", + "type": "TypeList", + "description": "COSAuthorization - IBM Cloud Object Storage authorization keys", + "optional": true, + "elem": { + "access_key_id": { + "name": "access_key_id", + "type": "TypeString", + "description": "The HMAC secret access key ID", + "optional": true + }, + "secret_access_key": { + "name": "secret_access_key", + "type": "TypeString", + "description": "The HMAC secret access key", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "host_attached_count", + "type": "TypeInt", + "description": "The total number of hosts that are attached to the Satellite location.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managed_from", + "type": "TypeString", + "description": "The IBM Cloud metro from which the Satellite location is managed", + "required": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "Name of the resource group", + "computed": true + }, + { + "name": "ingress_secret", + "type": "TypeString", + "secure": true, + "computed": true + }, + { + "name": "resource_group_id", + "type": "TypeString", + "description": "ID of the resource group.", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags associated with resource instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "Location CRN", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "host_available_count", + "type": "TypeInt", + "description": "The available number of hosts that can be assigned to a cluster resource in the Satellite location.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "coreos_enabled", + "type": "TypeBool", + "description": "Enable Red Hat CoreOS features within the Satellite location", + "optional": true, + "computed": true + }, + { + "name": "logging_account_id", + "type": "TypeString", + "description": "The account ID for IBM Log Analysis with LogDNA log forwarding", + "optional": true + }, + { + "name": "cos_config", + "type": "TypeList", + "description": "COSBucket - IBM Cloud Object Storage bucket configuration details", + "optional": true, + "elem": { + "bucket": { + "name": "bucket", + "type": "TypeString", + "optional": true + }, + "endpoint": { + "name": "endpoint", + "type": "TypeString", + "optional": true + }, + "region": { + "name": "region", + "type": "TypeString", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "zones", + "type": "TypeSet", + "description": "The names of at least three high availability zones to use for the location", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "created_on", + "type": "TypeString", + "description": "Created Date", + "computed": true + }, + { + "name": "ingress_hostname", + "type": "TypeString", + "computed": true + } + ], + "ibm_satellite_location_nlb_dns": [ + { + "name": "location", + "type": "TypeString", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "ips", + "type": "TypeSet", + "immutable": true, + "required": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_scc_account_settings": [ + { + "name": "location_id", + "type": "TypeString", + "description": "The programatic ID of the location that you want to work in.", + "options": "us, eu, uk", + "optional": true, + "deprecated": "The attribute location_id will soon be deprecated. Please use location instead. See https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/scc_account_settings for details" + }, + { + "name": "location", + "type": "TypeList", + "description": "Location Settings.", + "cloud_data_type": "region", + "optional": true, + "elem": { + "location_id": { + "name": "location_id", + "type": "TypeString", + "description": "The programatic ID of the location that you want to work in.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "event_notifications", + "type": "TypeList", + "description": "The Event Notification settings to register.", + "optional": true, + "elem": { + "instance_crn": { + "name": "instance_crn", + "type": "TypeString", + "description": "The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect.", + "default_value": "", + "optional": true + } + }, + "max_items": 1 + } + ], + "ibm_scc_posture_collector": [ + { + "name": "name", + "type": "TypeString", + "description": "A unique name for your collector.", + "required": true, + "min_length": 3, + "max_length": 46, + "matches": "^[a-zA-Z0-9-.,_\\s]*$" + }, + { + "name": "is_public", + "type": "TypeBool", + "description": "Determines whether the collector endpoint is accessible on a public network. If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network.", + "required": true + }, + { + "name": "managed_by", + "type": "TypeString", + "description": "Determines whether the collector is an IBM or customer-managed virtual machine. Use `ibm` to allow Security and Compliance Center to create, install, and manage the collector on your behalf. The collector is installed in an OpenShift cluster and approved automatically for use. Use `customer` if you would like to install the collector by using your own virtual machine. For more information, check out the [docs](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-collector).", + "required": true, + "options": "customer, ibm" + }, + { + "name": "description", + "type": "TypeString", + "description": "A detailed description of the collector.", + "default_value": "", + "min_length": 1, + "max_length": 255, + "matches": "^[a-zA-Z0-9-._,\\s]*$", + "optional": true + }, + { + "name": "passphrase", + "type": "TypeString", + "description": "To protect the credentials that you add to the service, a passphrase is used to generate a data encryption key. The key is used to securely store your credentials and prevent anyone from accessing them.", + "min_length": 1, + "max_length": 255, + "matches": "^[a-zA-Z0-9-._,\\s]*$", + "optional": true + }, + { + "name": "is_ubi_image", + "type": "TypeBool", + "description": "Determines whether the collector has a Ubi image.", + "optional": true + } + ], + "ibm_scc_posture_credential": [ + { + "name": "purpose", + "type": "TypeString", + "description": "Purpose for which the credential is created.", + "required": true, + "options": "discovery_collection, discovery_collection_remediation, discovery_fact_collection, discovery_fact_collection_remediation, remediation", + "min_length": 1, + "max_length": 100, + "matches": "^[a-zA-Z0-9-\\\\.,_\\\\s]*$" + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "Credentials status enabled/disbaled.", + "required": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Credentials type.", + "required": true, + "options": "aws_cloud, azure_cloud, database, ibm_cloud, kerberos_windows, ms_365, openstack_cloud, username_password" + }, + { + "name": "name", + "type": "TypeString", + "description": "Credentials name.", + "required": true, + "min_length": 3, + "max_length": 30, + "matches": "^[a-zA-Z0-9-._,\\s]*$" + }, + { + "name": "description", + "type": "TypeString", + "description": "Credentials description.", + "required": true, + "min_length": 1, + "max_length": 255, + "matches": "^[a-zA-Z0-9-._,\\s]*$" + }, + { + "name": "display_fields", + "type": "TypeList", + "description": "Details the fields on the credential. This will change as per credential type selected.", + "required": true, + "elem": { + "ibm_api_key": { + "name": "ibm_api_key", + "type": "TypeString", + "description": "The IBM Cloud API Key. This is mandatory for IBM Credential Type ie when type=ibm_cloud.", + "optional": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "group", + "type": "TypeList", + "description": "Credential group details.", + "required": true, + "elem": { + "id": { + "name": "id", + "type": "TypeString", + "description": "credential group id.", + "required": true + }, + "passphrase": { + "name": "passphrase", + "type": "TypeString", + "description": "passphase of the credential.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + } + ], + "ibm_scc_posture_profile_import": [ + { + "name": "version", + "type": "TypeInt", + "description": "The version of the profile.", + "computed": true + }, + { + "name": "base_profile", + "type": "TypeString", + "description": "The base profile that the controls are pulled from.", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "The type of profile.", + "computed": true + }, + { + "name": "file", + "type": "TypeString", + "description": "File to import", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of the profile.", + "optional": true, + "computed": true + }, + { + "name": "description", + "type": "TypeString", + "description": "A description of the profile.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The user who created the profile.", + "computed": true + }, + { + "name": "modified_by", + "type": "TypeString", + "description": "The user who last modified the profile.", + "computed": true + }, + { + "name": "no_of_controls", + "type": "TypeInt", + "description": "no of Controls.", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The time that the profile was created in UTC.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The time that the profile was most recently modified in UTC.", + "computed": true + }, + { + "name": "enabled", + "type": "TypeBool", + "description": "The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false.", + "computed": true + } + ], + "ibm_scc_posture_scan_initiate_validation": [ + { + "name": "scope_id", + "type": "TypeString", + "description": "The unique ID of the scope.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 20, + "matches": "^[0-9]*$" + }, + { + "name": "profile_id", + "type": "TypeString", + "description": "The unique ID of the profile.", + "immutable": true, + "required": true, + "min_length": 1, + "max_length": 20, + "matches": "^[0-9]*$" + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of a scheduled scan.", + "immutable": true, + "min_length": 1, + "max_length": 255, + "matches": "^[a-zA-Z0-9-._,\\s]*$", + "optional": true + }, + { + "name": "frequency", + "type": "TypeInt", + "description": "The frequency at which a scan is run specified in milliseconds.", + "immutable": true, + "optional": true + }, + { + "name": "no_of_occurrences", + "type": "TypeInt", + "description": "The number of times that a scan should be run.", + "immutable": true, + "optional": true + }, + { + "name": "end_time", + "type": "TypeString", + "description": "The date on which a scan should stop running specified in UTC.", + "immutable": true, + "optional": true + }, + { + "name": "group_profile_id", + "type": "TypeString", + "description": "The ID of the profile group.", + "immutable": true, + "min_length": 1, + "max_length": 20, + "matches": "^[0-9]*$", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of a scheduled scan.", + "immutable": true, + "min_length": 1, + "max_length": 32, + "matches": "^[a-zA-Z0-9-\\.,_\\s]*$", + "optional": true + }, + { + "name": "result", + "type": "TypeString", + "description": "The ID of the profile group.", + "computed": true + } + ], + "ibm_scc_posture_scope": [ + { + "name": "collector_ids", + "type": "TypeList", + "description": "The unique IDs of the collectors that are attached to the scope.", + "required": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "credential_id", + "type": "TypeString", + "description": "The unique identifier of the credential.", + "required": true, + "min_length": 1, + "max_length": 50, + "matches": "^[a-zA-Z0-9-\\\\.,_\\\\s]*$" + }, + { + "name": "credential_type", + "type": "TypeString", + "description": "The environment that the scope is targeted to.", + "required": true, + "options": "aws, azure, gcp, hosted, ibm, on_premise, openstack, services" + }, + { + "name": "name", + "type": "TypeString", + "description": "A unique name for your scope.", + "required": true, + "min_length": 3, + "max_length": 50, + "matches": "^[a-zA-Z0-9-\\\\.,_\\s]*$" + }, + { + "name": "description", + "type": "TypeString", + "description": "A detailed description of the scope.", + "required": true, + "min_length": 1, + "max_length": 255, + "matches": "^[a-zA-Z0-9-\\\\.,_\\s]*$" + } + ], + "ibm_scc_rule": [ + { + "name": "created_by", + "type": "TypeString", + "description": "The unique identifier for the user or application that created the resource.", + "computed": true + }, + { + "name": "modified_by", + "type": "TypeString", + "description": "The unique identifier for the user or application that last modified the resource.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Your IBM Cloud account ID.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A human-readable alias to assign to your rule.", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "An extended description of your rule.", + "required": true + }, + { + "name": "rule_type", + "type": "TypeString", + "description": "The type of rule. Rules that you create are `user_defined`.", + "computed": true + }, + { + "name": "labels", + "type": "TypeList", + "description": "Labels that you can use to group and search for similar rules, such as those that help you to meet a specific organization guideline.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "enforcement_actions", + "type": "TypeList", + "description": "The actions that the service must run on your behalf when a request to create or modify the target resource does not comply with your conditions.", + "optional": true, + "elem": { + "action": { + "name": "action", + "type": "TypeString", + "description": "To block a request from completing, use `disallow`.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "creation_date", + "type": "TypeString", + "description": "The date the resource was created.", + "computed": true + }, + { + "name": "modification_date", + "type": "TypeString", + "description": "The date the resource was last modified.", + "computed": true + }, + { + "name": "required_config", + "type": "TypeList", + "description": "The requirements that must be met to determine the resource's level of compliance in accordance with the rule. Use logical operators (and/or) to define multiple property checks and conditions. To define requirements for a rule, list one or more property check objects in the and array. To add conditions to a property check, use or.", + "required": true, + "elem": { + "and": { + "name": "and", + "type": "TypeList", + "description": "A condition with the and logical operator.", + "optional": true, + "elem": { + "and": { + "name": "and", + "type": "TypeList", + "description": "A condition with the and logical operator.", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "or": { + "name": "or", + "type": "TypeList", + "description": "A condition with the or logical operator.", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "or": { + "name": "or", + "type": "TypeList", + "description": "A condition with the or logical operator.", + "optional": true, + "elem": { + "and": { + "name": "and", + "type": "TypeList", + "description": "A condition with the and logical operator.", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "or": { + "name": "or", + "type": "TypeList", + "description": "A condition with the or logical operator.", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + } + }, + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "default_value": "", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "target", + "type": "TypeList", + "description": "The properties that describe the resource that you want to targetwith the rule or template.", + "required": true, + "elem": { + "additional_target_attributes": { + "name": "additional_target_attributes", + "type": "TypeList", + "description": "An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "optional": true + }, + "operator": { + "name": "operator", + "type": "TypeString", + "description": "The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "optional": true + } + } + }, + "resource_kind": { + "name": "resource_kind", + "type": "TypeString", + "description": "The type of resource that you want to target.", + "required": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "required": true + } + }, + "max_items": 1 + } + ], + "ibm_scc_rule_attachment": [ + { + "name": "included_scope", + "type": "TypeList", + "description": "The extent at which the rule can be attached across your accounts.", + "required": true, + "elem": { + "note": { + "name": "note", + "type": "TypeString", + "description": "A short description or alias to assign to the scope.", + "optional": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate.", + "required": true + }, + "scope_type": { + "name": "scope_type", + "type": "TypeString", + "description": "The type of scope that you want to evaluate.", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "excluded_scopes", + "type": "TypeList", + "description": "The extent at which the rule can be excluded from the included scope.", + "optional": true, + "elem": { + "note": { + "name": "note", + "type": "TypeString", + "description": "A short description or alias to assign to the scope.", + "optional": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate.", + "required": true + }, + "scope_type": { + "name": "scope_type", + "type": "TypeString", + "description": "The type of scope that you want to evaluate.", + "required": true + } + } + }, + { + "name": "version", + "type": "TypeString", + "computed": true + }, + { + "name": "attachment_id", + "type": "TypeString", + "description": "The UUID that uniquely identifies the attachment.", + "computed": true + }, + { + "name": "rule_id", + "type": "TypeString", + "description": "The UUID that uniquely identifies the rule.", + "immutable": true, + "required": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Your IBM Cloud account ID.", + "required": true + } + ], + "ibm_scc_template": [ + { + "name": "target", + "type": "TypeList", + "description": "The properties that describe the resource that you want to targetwith the rule or template.", + "required": true, + "elem": { + "additional_target_attributes": { + "name": "additional_target_attributes", + "type": "TypeList", + "description": "An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template.", + "optional": true, + "elem": { + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the additional attribute that you want to use to further qualify the target.Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The value that you want to apply to `name` field.Options differ depending on the rule or template that you configure. For more information, refer to the service documentation.", + "required": true + } + } + }, + "resource_kind": { + "name": "resource_kind", + "type": "TypeString", + "description": "The type of resource that you want to target.", + "required": true + }, + "service_name": { + "name": "service_name", + "type": "TypeString", + "description": "The programmatic name of the IBM Cloud service that you want to target with the rule or template.", + "required": true + } + }, + "max_items": 1, + "min_items": 1 + }, + { + "name": "customized_defaults", + "type": "TypeList", + "description": "A list of default property values to apply to your template.", + "required": true, + "elem": { + "property": { + "name": "property", + "type": "TypeString", + "description": "The name of the resource property that you want to configure.Property options differ depending on the service or resource that you are targeting with a template. To view a list of properties that are compatible with templates, refer to the service documentation.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "The custom value that you want to apply as the default for the resource property in the `name` field.This value is used to to override the default value that is provided by IBM when a resource is created. Value options differ depending on the resource that you are configuring. To learn more about your options, refer to the service documentation.", + "required": true + } + } + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Your IBM Cloud account ID.", + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "A human-readablse alias to assign to your template.", + "required": true, + "min_length": 1, + "max_length": 32, + "matches": ".*" + }, + { + "name": "description", + "type": "TypeString", + "description": "An extended description of your template.", + "required": true, + "min_length": 1, + "max_length": 256, + "matches": ".*" + }, + { + "name": "template_id", + "type": "TypeString", + "description": "The UUID that uniquely identifies the template.", + "computed": true + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_scc_template_attachment": [ + { + "name": "attachment_id", + "type": "TypeString", + "description": "The UUID that uniquely identifies the template.", + "computed": true + }, + { + "name": "template_id", + "type": "TypeString", + "description": "The UUID that uniquely identifies the template.", + "required": true + }, + { + "name": "account_id", + "type": "TypeString", + "description": "Your IBM Cloud account ID.", + "required": true + }, + { + "name": "included_scope", + "type": "TypeList", + "description": "The extent at which the template can be attached across your accounts.", + "required": true, + "elem": { + "note": { + "name": "note", + "type": "TypeString", + "description": "A short description or alias to assign to the scope.", + "optional": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The ID of the scope, such as an enterprise, account, or account group, where you want to apply the customized defaults that are associated with a template.", + "required": true + }, + "scope_type": { + "name": "scope_type", + "type": "TypeString", + "description": "The type of scope.", + "required": true + } + } + }, + { + "name": "excluded_scopes", + "type": "TypeList", + "optional": true, + "elem": { + "note": { + "name": "note", + "type": "TypeString", + "description": "A short description or alias to assign to the scope.", + "optional": true + }, + "scope_id": { + "name": "scope_id", + "type": "TypeString", + "description": "The ID of the scope, such as an enterprise, account, or account group, where you want to apply the customized defaults that are associated with a template.", + "required": true + }, + "scope_type": { + "name": "scope_type", + "type": "TypeString", + "description": "The type of scope.", + "required": true + } + } + }, + { + "name": "version", + "type": "TypeString", + "computed": true + } + ], + "ibm_schematics_action": [ + { + "name": "credentials", + "type": "TypeList", + "description": "credentials of the Action.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "action_inputs", + "type": "TypeList", + "description": "Input variables for the Action.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + { + "name": "action_outputs", + "type": "TypeList", + "description": "Output variables for the Action.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + { + "name": "settings", + "type": "TypeList", + "description": "Environment variables for the Action.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + { + "name": "sys_lock", + "type": "TypeList", + "description": "System lock status.", + "optional": true, + "computed": true, + "elem": { + "sys_locked": { + "name": "sys_locked", + "type": "TypeBool", + "description": "Is the automation locked by a Schematic job ?.", + "optional": true + }, + "sys_locked_at": { + "name": "sys_locked_at", + "type": "TypeString", + "description": "When the User performed the job that lead to locking of the automation ?.", + "optional": true + }, + "sys_locked_by": { + "name": "sys_locked_by", + "type": "TypeString", + "description": "Name of the User who performed the job, that lead to the locking of the automation.", + "optional": true + } + } + }, + { + "name": "source_updated_at", + "type": "TypeString", + "description": "The action playbook updation time.", + "computed": true + }, + { + "name": "playbook_names", + "type": "TypeList", + "description": "Playbook names retrieved from the respository.", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action.", + "required": true, + "min_length": 1, + "max_length": 65 + }, + { + "name": "source", + "type": "TypeList", + "description": "Source of templates, playbooks, or controls.", + "optional": true, + "elem": { + "catalog": { + "name": "catalog", + "type": "TypeList", + "description": "Connection details to IBM Cloud Catalog source.", + "optional": true, + "elem": { + "catalog_name": { + "name": "catalog_name", + "type": "TypeString", + "description": "name of the private catalog.", + "optional": true + }, + "offering_id": { + "name": "offering_id", + "type": "TypeString", + "description": "Id of the offering the IBM Catalog.", + "optional": true + }, + "offering_kind": { + "name": "offering_kind", + "type": "TypeString", + "description": "Type of the offering, in the IBM Catalog.", + "optional": true + }, + "offering_name": { + "name": "offering_name", + "type": "TypeString", + "description": "Name of the offering in the IBM Catalog.", + "optional": true + }, + "offering_repo_url": { + "name": "offering_repo_url", + "type": "TypeString", + "description": "Repo Url of the offering, in the IBM Catalog.", + "optional": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "Version string of the offering in the IBM Catalog.", + "optional": true + }, + "offering_version_id": { + "name": "offering_version_id", + "type": "TypeString", + "description": "Id of the offering version the IBM Catalog.", + "optional": true + } + }, + "max_items": 1 + }, + "git": { + "name": "git", + "type": "TypeList", + "description": "Connection details to Git source.", + "optional": true, + "elem": { + "computed_git_repo_url": { + "name": "computed_git_repo_url", + "type": "TypeString", + "description": "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + "optional": true + }, + "git_branch": { + "name": "git_branch", + "type": "TypeString", + "description": "Name of the branch, used to fetch the Git Repo.", + "optional": true + }, + "git_release": { + "name": "git_release", + "type": "TypeString", + "description": "Name of the release tag, used to fetch the Git Repo.", + "optional": true + }, + "git_repo_folder": { + "name": "git_repo_folder", + "type": "TypeString", + "description": "Name of the folder in the Git Repo, that contains the template.", + "optional": true + }, + "git_repo_url": { + "name": "git_repo_url", + "type": "TypeString", + "description": "URL to the GIT Repo that can be used to clone the template.", + "optional": true + }, + "git_token": { + "name": "git_token", + "type": "TypeString", + "description": "Personal Access Token to connect to Git URLs.", + "optional": true + } + } + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "required": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Action creation time.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "E-mail address of the user who created an action.", + "computed": true + }, + { + "name": "user_state", + "type": "TypeList", + "description": "User defined status of the Schematics object.", + "optional": true, + "computed": true, + "elem": { + "set_at": { + "name": "set_at", + "type": "TypeString", + "description": "When the User who set the state of the Object.", + "optional": true, + "computed": true + }, + "set_by": { + "name": "set_by", + "type": "TypeString", + "description": "Name of the User who set the state of the Object.", + "optional": true, + "computed": true + }, + "state": { + "name": "state", + "type": "TypeString", + "description": "User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution.", + "optional": true + } + } + }, + { + "name": "crn", + "type": "TypeString", + "description": "Action Cloud Resource Name.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "source_created_at", + "type": "TypeString", + "description": "Action Playbook Source creation time.", + "computed": true + }, + { + "name": "source_created_by", + "type": "TypeString", + "description": "E-mail address of user who created the Action Playbook Source.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Action updation time.", + "computed": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "Action tags.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "bastion", + "type": "TypeList", + "description": "Describes a bastion resource.", + "optional": true, + "elem": { + "host": { + "name": "host", + "type": "TypeString", + "description": "Reference to the Inventory resource definition.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Bastion Name(Unique).", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "inventory", + "type": "TypeString", + "description": "Target inventory record ID, used by the action or ansible playbook.", + "optional": true + }, + { + "name": "state", + "type": "TypeList", + "description": "Computed state of the Action.", + "computed": true, + "elem": { + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of automation (workspace or action).", + "optional": true + }, + "status_job_id": { + "name": "status_job_id", + "type": "TypeString", + "description": "Job id reference for this status.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Automation status message - to be displayed along with the status_code.", + "optional": true + } + } + }, + { + "name": "x_github_token", + "type": "TypeString", + "description": "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Action description.", + "optional": true + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "options": "eu-de, eu-gb, us-east, us-south", + "optional": true, + "computed": true + }, + { + "name": "source_readme_url", + "type": "TypeString", + "description": "URL of the `README` file, for the source URL.", + "optional": true + }, + { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "options": "cos_bucket, external_scm, git_hub, git_hub_enterprise, git_lab, ibm_cloud_catalog, ibm_git_lab, local", + "optional": true + }, + { + "name": "command_parameter", + "type": "TypeString", + "description": "Schematics job command parameter (playbook-name).", + "optional": true + }, + { + "name": "account", + "type": "TypeString", + "description": "Action account ID.", + "computed": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for an action. By default, action is created in default resource group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "bastion_credential", + "type": "TypeList", + "description": "User editable variable data \u0026 system generated reference to value.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "targets_ini", + "type": "TypeString", + "description": "Inventory of host and host group for the playbook in `INI` file format. For example, `\"targets_ini\": \"[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5\"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps).", + "optional": true + }, + { + "name": "source_updated_by", + "type": "TypeString", + "description": "E-mail address of user who updated the action playbook source.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "E-mail address of the user who updated an action.", + "computed": true + } + ], + "ibm_schematics_inventory": [ + { + "name": "description", + "type": "TypeString", + "description": "The description of your Inventory definition. The description can be up to 2048 characters long in size.", + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for the Inventory definition. By default, Inventory definition will be created in Default Resource Group.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "inventories_ini", + "type": "TypeString", + "description": "Input inventory of host and host group for the playbook, in the `.ini` file format.", + "optional": true + }, + { + "name": "resource_queries", + "type": "TypeList", + "description": "Input resource query definitions that is used to dynamically generate the inventory of host and host group for the playbook.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Inventory creation time.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Inventory updation time.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Inventory.", + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The unique name of your Inventory definition. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + "min_length": 3, + "max_length": 64, + "optional": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Inventory.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "options": "eu-de, eu-gb, us-east, us-south", + "optional": true, + "computed": true + } + ], + "ibm_schematics_job": [ + { + "name": "description", + "type": "TypeString", + "description": "The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size.", + "computed": true + }, + { + "name": "state_store_url", + "type": "TypeString", + "description": "Job state store URL.", + "computed": true + }, + { + "name": "command_object", + "type": "TypeString", + "description": "Name of the Schematics automation resource.", + "required": true, + "options": "action, environment, system, workspace" + }, + { + "name": "command_parameter", + "type": "TypeString", + "description": "Schematics job command parameter (playbook-name).", + "optional": true + }, + { + "name": "status", + "type": "TypeList", + "description": "Job Status.", + "computed": true, + "elem": { + "action_job_status": { + "name": "action_job_status", + "type": "TypeList", + "description": "Action Job Status.", + "optional": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Action name.", + "optional": true + }, + "bastion_status_code": { + "name": "bastion_status_code", + "type": "TypeString", + "description": "Status of Resources.", + "optional": true + }, + "bastion_status_message": { + "name": "bastion_status_message", + "type": "TypeString", + "description": "Bastion status message - to be displayed along with the bastion_status_code;.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Action Job status message - to be displayed along with the action_status_code.", + "optional": true + }, + "targets_status_code": { + "name": "targets_status_code", + "type": "TypeString", + "description": "Status of Resources.", + "optional": true + }, + "targets_status_message": { + "name": "targets_status_message", + "type": "TypeString", + "description": "Aggregated status message for all target resources, to be displayed along with the targets_status_code;.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + }, + "flow_job_status": { + "name": "flow_job_status", + "type": "TypeList", + "description": "Environment Flow JOB Status.", + "optional": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "flow id.", + "optional": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "flow name.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Flow Job status message - to be displayed along with the status_code;.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Environment's individual workItem status details;.", + "optional": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace job id.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "workitem job status message;.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "workitem job status updation timestamp.", + "optional": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "Workspace id.", + "optional": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "workspace name.", + "optional": true + } + } + } + }, + "max_items": 1 + }, + "system_job_status": { + "name": "system_job_status", + "type": "TypeList", + "description": "System Job Status.", + "optional": true, + "elem": { + "schematics_resource_status": { + "name": "schematics_resource_status", + "type": "TypeList", + "description": "job staus for each schematics resource.", + "optional": true, + "elem": { + "schematics_resource_id": { + "name": "schematics_resource_id", + "type": "TypeString", + "description": "id for each resource which is targeted as a part of system job.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "system job status message.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + }, + "system_status_code": { + "name": "system_status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "system_status_message": { + "name": "system_status_message", + "type": "TypeString", + "description": "System job message.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + }, + "max_items": 1 + }, + "workspace_job_status": { + "name": "workspace_job_status", + "type": "TypeList", + "description": "Workspace Job Status.", + "optional": true, + "elem": { + "flow_status": { + "name": "flow_status", + "type": "TypeList", + "description": "Environment Flow JOB Status.", + "optional": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "flow id.", + "optional": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "flow name.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Flow Job status message - to be displayed along with the status_code;.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Environment's individual workItem status details;.", + "optional": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace job id.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "workitem job status message;.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "workitem job status updation timestamp.", + "optional": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "Workspace id.", + "optional": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "workspace name.", + "optional": true + } + } + } + }, + "max_items": 1 + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace).", + "optional": true + }, + "template_status": { + "name": "template_status", + "type": "TypeList", + "description": "Workspace Flow Template job status.", + "optional": true, + "elem": { + "flow_index": { + "name": "flow_index", + "type": "TypeInt", + "description": "Index of the template in the Flow.", + "optional": true + }, + "status_code": { + "name": "status_code", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + }, + "status_message": { + "name": "status_message", + "type": "TypeString", + "description": "Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template).", + "optional": true + }, + "template_id": { + "name": "template_id", + "type": "TypeString", + "description": "Template Id.", + "optional": true + }, + "template_name": { + "name": "template_name", + "type": "TypeString", + "description": "Template name.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "Workspace name.", + "optional": true + } + }, + "max_items": 1 + } + } + }, + { + "name": "data", + "type": "TypeList", + "description": "Job data.", + "optional": true, + "elem": { + "action_job_data": { + "name": "action_job_data", + "type": "TypeList", + "description": "Action Job data.", + "optional": true, + "elem": { + "action_name": { + "name": "action_name", + "type": "TypeString", + "description": "Flow name.", + "optional": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data used by the Action Job.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "inventory_record": { + "name": "inventory_record", + "type": "TypeList", + "description": "Complete inventory resource details with user inputs and system generated data.", + "optional": true, + "elem": { + "created_at": { + "name": "created_at", + "type": "TypeString", + "description": "Inventory creation time.", + "optional": true, + "computed": true + }, + "created_by": { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Inventory.", + "optional": true, + "computed": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of your Inventory. The description can be up to 2048 characters long in size.", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "Inventory id.", + "optional": true, + "computed": true + }, + "inventories_ini": { + "name": "inventories_ini", + "type": "TypeString", + "description": "Input inventory of host and host group for the playbook, in the .ini file format.", + "optional": true + }, + "location": { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores.", + "optional": true + }, + "resource_group": { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group.", + "optional": true + }, + "resource_queries": { + "name": "resource_queries", + "type": "TypeList", + "description": "Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Inventory updation time.", + "optional": true, + "computed": true + }, + "updated_by": { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Inventory.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "materialized_inventory": { + "name": "materialized_inventory", + "type": "TypeString", + "description": "Materialized inventory details used by the Action Job, in .ini format.", + "optional": true + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables data from the Action Job.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by all the templates in the Action.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + }, + "flow_job_data": { + "name": "flow_job_data", + "type": "TypeList", + "description": "Flow Job data.", + "optional": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "Flow ID.", + "optional": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "Flow Name.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + }, + "workitems": { + "name": "workitems", + "type": "TypeList", + "description": "Job data used by each workitem Job.", + "optional": true, + "elem": { + "command_object_id": { + "name": "command_object_id", + "type": "TypeString", + "description": "command object id.", + "optional": true + }, + "command_object_name": { + "name": "command_object_name", + "type": "TypeString", + "description": "command object name.", + "optional": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data for the workItem used in FlowJob.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "last_job": { + "name": "last_job", + "type": "TypeList", + "description": "Status of the last job executed by the workitem.", + "optional": true, + "elem": { + "command_name": { + "name": "command_name", + "type": "TypeString", + "description": "Schematics job command name.", + "optional": true + }, + "command_object": { + "name": "command_object", + "type": "TypeString", + "description": "Name of the Schematics automation resource.", + "optional": true + }, + "command_object_id": { + "name": "command_object_id", + "type": "TypeString", + "description": "Workitem command object id, maps to workspace_id or action_id.", + "optional": true + }, + "command_object_name": { + "name": "command_object_name", + "type": "TypeString", + "description": "command object name (workspace_name/action_name).", + "optional": true + }, + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "Workspace job id.", + "optional": true + }, + "job_status": { + "name": "job_status", + "type": "TypeString", + "description": "Status of Jobs.", + "optional": true + } + }, + "max_items": 1 + }, + "layers": { + "name": "layers", + "type": "TypeString", + "description": "layer name.", + "optional": true + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables for the workItem.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables for the workItem.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "source": { + "name": "source", + "type": "TypeList", + "description": "Source of templates, playbooks, or controls.", + "optional": true, + "elem": { + "catalog": { + "name": "catalog", + "type": "TypeList", + "description": "Connection details to IBM Cloud Catalog source.", + "optional": true, + "elem": { + "catalog_name": { + "name": "catalog_name", + "type": "TypeString", + "description": "name of the private catalog.", + "optional": true + }, + "offering_id": { + "name": "offering_id", + "type": "TypeString", + "description": "Id of the offering the IBM Catalog.", + "optional": true + }, + "offering_kind": { + "name": "offering_kind", + "type": "TypeString", + "description": "Type of the offering, in the IBM Catalog.", + "optional": true + }, + "offering_name": { + "name": "offering_name", + "type": "TypeString", + "description": "Name of the offering in the IBM Catalog.", + "optional": true + }, + "offering_repo_url": { + "name": "offering_repo_url", + "type": "TypeString", + "description": "Repo Url of the offering, in the IBM Catalog.", + "optional": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "Version string of the offering in the IBM Catalog.", + "optional": true + }, + "offering_version_id": { + "name": "offering_version_id", + "type": "TypeString", + "description": "Id of the offering version the IBM Catalog.", + "optional": true + } + }, + "max_items": 1 + }, + "git": { + "name": "git", + "type": "TypeList", + "description": "Connection details to Git source.", + "optional": true, + "elem": { + "computed_git_repo_url": { + "name": "computed_git_repo_url", + "type": "TypeString", + "description": "The Complete URL which is computed by git_repo_url, git_repo_folder and branch.", + "optional": true + }, + "git_branch": { + "name": "git_branch", + "type": "TypeString", + "description": "Name of the branch, used to fetch the Git Repo.", + "optional": true + }, + "git_release": { + "name": "git_release", + "type": "TypeString", + "description": "Name of the release tag, used to fetch the Git Repo.", + "optional": true + }, + "git_repo_folder": { + "name": "git_repo_folder", + "type": "TypeString", + "description": "Name of the folder in the Git Repo, that contains the template.", + "optional": true + }, + "git_repo_url": { + "name": "git_repo_url", + "type": "TypeString", + "description": "URL to the GIT Repo that can be used to clone the template.", + "optional": true + }, + "git_token": { + "name": "git_token", + "type": "TypeString", + "description": "Personal Access Token to connect to Git URLs.", + "optional": true + } + }, + "max_items": 1 + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "required": true + } + }, + "max_items": 1 + }, + "source_type": { + "name": "source_type", + "type": "TypeString", + "description": "Type of source for the Template.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + } + } + }, + "job_type": { + "name": "job_type", + "type": "TypeString", + "description": "Type of Job.", + "required": true + }, + "system_job_data": { + "name": "system_job_data", + "type": "TypeList", + "description": "Controls Job data.", + "optional": true, + "elem": { + "key_id": { + "name": "key_id", + "type": "TypeString", + "description": "Key ID for which key event is generated.", + "optional": true + }, + "schematics_resource_id": { + "name": "schematics_resource_id", + "type": "TypeList", + "description": "List of the schematics resource id.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + }, + "max_items": 1 + }, + "workspace_job_data": { + "name": "workspace_job_data", + "type": "TypeList", + "description": "Workspace Job data.", + "optional": true, + "elem": { + "flow_id": { + "name": "flow_id", + "type": "TypeString", + "description": "Flow Id.", + "optional": true + }, + "flow_name": { + "name": "flow_name", + "type": "TypeString", + "description": "Flow name.", + "optional": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Input variables data used by the Workspace Job.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Output variables data from the Workspace Job.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by all the templates in the Workspace.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "template_data": { + "name": "template_data", + "type": "TypeList", + "description": "Input / output data of the Template in the Workspace Job.", + "optional": true, + "elem": { + "flow_index": { + "name": "flow_index", + "type": "TypeInt", + "description": "Index of the template in the Flow.", + "optional": true + }, + "inputs": { + "name": "inputs", + "type": "TypeList", + "description": "Job inputs used by the Templates.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "outputs": { + "name": "outputs", + "type": "TypeList", + "description": "Job output from the Templates.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "settings": { + "name": "settings", + "type": "TypeList", + "description": "Environment variables used by the template.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "optional": true + } + }, + "max_items": 1 + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "optional": true + } + } + }, + "template_id": { + "name": "template_id", + "type": "TypeString", + "description": "Template Id.", + "optional": true + }, + "template_name": { + "name": "template_name", + "type": "TypeString", + "description": "Template name.", + "optional": true + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + } + } + }, + "updated_at": { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "optional": true + }, + "workspace_name": { + "name": "workspace_name", + "type": "TypeString", + "description": "Workspace name.", + "optional": true + } + }, + "max_items": 1 + } + } + }, + { + "name": "name", + "type": "TypeString", + "description": "Job name, uniquely derived from the related Workspace or Action.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Job status updation timestamp.", + "computed": true + }, + { + "name": "command_object_id", + "type": "TypeString", + "description": "Job command object id (workspace-id, action-id).", + "required": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "User defined tags, while running the job.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "bastion", + "type": "TypeList", + "description": "Describes a bastion resource.", + "optional": true, + "elem": { + "host": { + "name": "host", + "type": "TypeString", + "description": "Reference to the Inventory resource definition.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Bastion Name(Unique).", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "submitted_at", + "type": "TypeString", + "description": "Job submission time.", + "computed": true + }, + { + "name": "results_url", + "type": "TypeString", + "description": "Job results store URL.", + "computed": true + }, + { + "name": "job_inputs", + "type": "TypeList", + "description": "Job inputs used by Action or Workspace.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "required": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "required": true + } + } + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "options": "eu-de, eu-gb, us-east, us-south", + "optional": true, + "computed": true + }, + { + "name": "log_summary", + "type": "TypeList", + "description": "Job log summary record.", + "optional": true, + "computed": true, + "elem": { + "action_job": { + "name": "action_job", + "type": "TypeList", + "description": "Flow Job log summary.", + "optional": true, + "elem": { + "play_count": { + "name": "play_count", + "type": "TypeFloat", + "description": "number of plays in playbook.", + "optional": true, + "computed": true + }, + "recap": { + "name": "recap", + "type": "TypeList", + "description": "Recap records.", + "optional": true, + "elem": { + "changed": { + "name": "changed", + "type": "TypeFloat", + "description": "Number of changed.", + "optional": true + }, + "failed": { + "name": "failed", + "type": "TypeFloat", + "description": "Number of failed.", + "optional": true + }, + "ok": { + "name": "ok", + "type": "TypeFloat", + "description": "Number of OK.", + "optional": true + }, + "skipped": { + "name": "skipped", + "type": "TypeFloat", + "description": "Number of skipped.", + "optional": true + }, + "target": { + "name": "target", + "type": "TypeList", + "description": "List of target or host name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "unreachable": { + "name": "unreachable", + "type": "TypeFloat", + "description": "Number of unreachable.", + "optional": true + } + } + }, + "target_count": { + "name": "target_count", + "type": "TypeFloat", + "description": "number of targets or hosts.", + "optional": true, + "computed": true + }, + "task_count": { + "name": "task_count", + "type": "TypeFloat", + "description": "number of tasks in playbook.", + "optional": true, + "computed": true + } + } + }, + "elapsed_time": { + "name": "elapsed_time", + "type": "TypeFloat", + "description": "Job log elapsed time (log_analyzed_till - log_start_at).", + "optional": true, + "computed": true + }, + "flow_job": { + "name": "flow_job", + "type": "TypeList", + "description": "Flow Job log summary.", + "optional": true, + "elem": { + "workitems": { + "name": "workitems", + "type": "TypeList", + "optional": true, + "elem": { + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "workspace JOB ID.", + "optional": true + }, + "log_url": { + "name": "log_url", + "type": "TypeString", + "description": "Log url for job.", + "optional": true + }, + "resources_add": { + "name": "resources_add", + "type": "TypeFloat", + "description": "Number of resources add.", + "optional": true, + "computed": true + }, + "resources_destroy": { + "name": "resources_destroy", + "type": "TypeFloat", + "description": "Number of resources destroy.", + "optional": true, + "computed": true + }, + "resources_modify": { + "name": "resources_modify", + "type": "TypeFloat", + "description": "Number of resources modify.", + "optional": true, + "computed": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "TypeString", + "description": "workspace ID.", + "optional": true + } + } + }, + "workitems_completed": { + "name": "workitems_completed", + "type": "TypeFloat", + "description": "Number of workitems completed successfully.", + "optional": true, + "computed": true + }, + "workitems_failed": { + "name": "workitems_failed", + "type": "TypeFloat", + "description": "Number of workitems failed.", + "optional": true, + "computed": true + }, + "workitems_pending": { + "name": "workitems_pending", + "type": "TypeFloat", + "description": "Number of workitems pending in the flow.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "job_id": { + "name": "job_id", + "type": "TypeString", + "description": "Workspace Id.", + "optional": true, + "computed": true + }, + "job_type": { + "name": "job_type", + "type": "TypeString", + "description": "Type of Job.", + "optional": true + }, + "log_analyzed_till": { + "name": "log_analyzed_till", + "type": "TypeString", + "description": "Job log update timestamp.", + "optional": true, + "computed": true + }, + "log_errors": { + "name": "log_errors", + "type": "TypeList", + "description": "Job log errors.", + "optional": true, + "computed": true, + "elem": { + "error_code": { + "name": "error_code", + "type": "TypeString", + "description": "Error code in the Log.", + "optional": true + }, + "error_count": { + "name": "error_count", + "type": "TypeFloat", + "description": "Number of occurrence.", + "optional": true + }, + "error_msg": { + "name": "error_msg", + "type": "TypeString", + "description": "Summary error message in the log.", + "optional": true + } + } + }, + "log_start_at": { + "name": "log_start_at", + "type": "TypeString", + "description": "Job log start timestamp.", + "optional": true, + "computed": true + }, + "repo_download_job": { + "name": "repo_download_job", + "type": "TypeList", + "description": "Repo download Job log summary.", + "optional": true, + "elem": { + "detected_filetype": { + "name": "detected_filetype", + "type": "TypeString", + "description": "Detected template or data file type.", + "optional": true, + "computed": true + }, + "inputs_count": { + "name": "inputs_count", + "type": "TypeString", + "description": "Number of inputs detected.", + "optional": true, + "computed": true + }, + "outputs_count": { + "name": "outputs_count", + "type": "TypeString", + "description": "Number of outputs detected.", + "optional": true, + "computed": true + }, + "quarantined_file_count": { + "name": "quarantined_file_count", + "type": "TypeFloat", + "description": "Number of files quarantined.", + "optional": true, + "computed": true + }, + "scanned_file_count": { + "name": "scanned_file_count", + "type": "TypeFloat", + "description": "Number of files scanned.", + "optional": true, + "computed": true + } + } + }, + "system_job": { + "name": "system_job", + "type": "TypeList", + "description": "System Job log summary.", + "optional": true, + "elem": { + "failed": { + "name": "failed", + "type": "TypeFloat", + "description": "Number of failed.", + "optional": true + }, + "success": { + "name": "success", + "type": "TypeFloat", + "description": "Number of passed.", + "optional": true + }, + "target_count": { + "name": "target_count", + "type": "TypeFloat", + "description": "number of targets or hosts.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + }, + "workspace_job": { + "name": "workspace_job", + "type": "TypeList", + "description": "Workspace Job log summary.", + "optional": true, + "elem": { + "resources_add": { + "name": "resources_add", + "type": "TypeFloat", + "description": "Number of resources add.", + "optional": true, + "computed": true + }, + "resources_destroy": { + "name": "resources_destroy", + "type": "TypeFloat", + "description": "Number of resources destroy.", + "optional": true, + "computed": true + }, + "resources_modify": { + "name": "resources_modify", + "type": "TypeFloat", + "description": "Number of resources modify.", + "optional": true, + "computed": true + } + }, + "max_items": 1 + } + } + }, + { + "name": "start_at", + "type": "TypeString", + "description": "Job start time.", + "computed": true + }, + { + "name": "end_at", + "type": "TypeString", + "description": "Job end time.", + "computed": true + }, + { + "name": "duration", + "type": "TypeString", + "description": "Duration of job execution; example 40 sec.", + "computed": true + }, + { + "name": "command_name", + "type": "TypeString", + "description": "Schematics job command name.", + "required": true, + "options": "ansible_playbook_check, ansible_playbook_run, create_action, create_cart, create_environment, create_workspace, delete_action, delete_environment, delete_workspace, environment_init, environment_install, environment_uninstall, patch_action, patch_workspace, put_action, put_environment, put_workspace, repository_process, system_key_delete, system_key_disable, system_key_enable, system_key_restore, system_key_rotate, workspace_apply, workspace_destroy, workspace_plan, workspace_refresh" + }, + { + "name": "command_options", + "type": "TypeList", + "description": "Command line options for the command.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "job_env_settings", + "type": "TypeList", + "description": "Environment variables used by the Job while performing Action or Workspace.", + "optional": true, + "elem": { + "link": { + "name": "link", + "type": "TypeString", + "description": "Reference link to the variable value By default the expression will point to self.value.", + "optional": true, + "computed": true + }, + "metadata": { + "name": "metadata", + "type": "TypeList", + "description": "User editable metadata for the variables.", + "optional": true, + "elem": { + "aliases": { + "name": "aliases", + "type": "TypeList", + "description": "List of aliases for the variable name.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "default_value": { + "name": "default_value", + "type": "TypeString", + "description": "Default value for the variable, if the override value is not specified.", + "optional": true + }, + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of the meta data.", + "optional": true + }, + "group_by": { + "name": "group_by", + "type": "TypeString", + "description": "Display name of the group this variable belongs to.", + "optional": true + }, + "hidden": { + "name": "hidden", + "type": "TypeBool", + "description": "If true, the variable will not be displayed on UI or CLI.", + "optional": true + }, + "immutable": { + "name": "immutable", + "type": "TypeBool", + "description": "Is the variable readonly ?.", + "optional": true + }, + "matches": { + "name": "matches", + "type": "TypeString", + "description": "Regex for the variable value.", + "optional": true + }, + "max_length": { + "name": "max_length", + "type": "TypeInt", + "description": "Maximum length of the variable value. Applicable for string type.", + "optional": true + }, + "max_value": { + "name": "max_value", + "type": "TypeInt", + "description": "Maximum value of the variable. Applicable for integer type.", + "optional": true + }, + "min_length": { + "name": "min_length", + "type": "TypeInt", + "description": "Minimum length of the variable value. Applicable for string type.", + "optional": true + }, + "min_value": { + "name": "min_value", + "type": "TypeInt", + "description": "Minimum value of the variable. Applicable for integer type.", + "optional": true + }, + "options": { + "name": "options", + "type": "TypeList", + "description": "List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "position": { + "name": "position", + "type": "TypeInt", + "description": "Relative position of this variable in a list.", + "optional": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "Is the variable secure or sensitive ?.", + "optional": true + }, + "source": { + "name": "source", + "type": "TypeString", + "description": "Source of this meta-data.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "Type of the variable.", + "required": true + } + } + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the variable.", + "required": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value for the variable or reference to the value.", + "required": true + } + } + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "Resource-group name derived from the related Workspace or Action.", + "cloud_data_type": "resource_group", + "computed": true + }, + { + "name": "submitted_by", + "type": "TypeString", + "description": "Email address of user who submitted the job.", + "computed": true + }, + { + "name": "log_store_url", + "type": "TypeString", + "description": "Job log store URL.", + "computed": true + } + ], + "ibm_schematics_resource_query": [ + { + "name": "type", + "type": "TypeString", + "description": "Resource type (cluster, vsi, icd, vpc).", + "options": "vsi", + "optional": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Resource query name.", + "optional": true + }, + { + "name": "location", + "type": "TypeString", + "description": "List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics.", + "options": "eu-de, eu-gb, us-east, us-south", + "optional": true, + "computed": true + }, + { + "name": "queries", + "type": "TypeList", + "optional": true, + "elem": { + "query_condition": { + "name": "query_condition", + "type": "TypeList", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "Description of resource query param variable.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "Name of the resource query param.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Value of the resource query param.", + "optional": true + } + } + }, + "query_select": { + "name": "query_select", + "type": "TypeList", + "description": "List of query selection parameters.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + "query_type": { + "name": "query_type", + "type": "TypeString", + "description": "Type of the query(workspaces).", + "optional": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "description": "Resource query creation time.", + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "Email address of user who created the Resource query.", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "Resource query updation time.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "Email address of user who updated the Resource query.", + "computed": true + } + ], + "ibm_schematics_workspace": [ + { + "name": "status", + "type": "TypeString", + "description": "The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed.", + "computed": true + }, + { + "name": "template_uninstall_script_name", + "type": "TypeString", + "description": "Uninstall script name.", + "optional": true + }, + { + "name": "catalog_ref", + "type": "TypeList", + "description": "Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only.", + "optional": true, + "elem": { + "dry_run": { + "name": "dry_run", + "type": "TypeBool", + "description": "Dry run.", + "optional": true + }, + "item_icon_url": { + "name": "item_icon_url", + "type": "TypeString", + "description": "The URL to the icon of the software template in the IBM Cloud catalog.", + "optional": true + }, + "item_id": { + "name": "item_id", + "type": "TypeString", + "description": "The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics.", + "optional": true + }, + "item_name": { + "name": "item_name", + "type": "TypeString", + "description": "The name of the software that you chose to install from the IBM Cloud catalog.", + "optional": true + }, + "item_readme_url": { + "name": "item_readme_url", + "type": "TypeString", + "description": "The URL to the readme file of the software template in the IBM Cloud catalog.", + "optional": true + }, + "item_url": { + "name": "item_url", + "type": "TypeString", + "description": "The URL to the software template in the IBM Cloud catalog.", + "optional": true + }, + "launch_url": { + "name": "launch_url", + "type": "TypeString", + "description": "The URL to the dashboard to access your software.", + "optional": true + }, + "offering_version": { + "name": "offering_version", + "type": "TypeString", + "description": "The version of the software template that you chose to install from the IBM Cloud catalog.", + "optional": true + }, + "owning_account": { + "name": "owning_account", + "type": "TypeString", + "description": "Owning account ID of the catalog.", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "template_init_state_file", + "type": "TypeString", + "description": "The content of an existing Terraform statefile that you want to import in to your workspace. To get the content of a Terraform statefile for a specific Terraform template in an existing workspace, run `ibmcloud terraform state pull --id \u003cworkspace_id\u003e --template \u003ctemplate_id\u003e`.", + "optional": true + }, + { + "name": "template_inputs", + "type": "TypeList", + "description": "VariablesRequest -.", + "optional": true, + "elem": { + "description": { + "name": "description", + "type": "TypeString", + "description": "The description of your input variable.", + "optional": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The name of the variable.", + "required": true + }, + "secure": { + "name": "secure", + "type": "TypeBool", + "description": "If set to `true`, the value of your input variable is protected and not returned in your API response.", + "optional": true + }, + "type": { + "name": "type", + "type": "TypeString", + "description": "`Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).\u003cbr\u003e `Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints).", + "required": true + }, + "use_default": { + "name": "use_default", + "type": "TypeBool", + "description": "Variable uses default value; and is not over-ridden.", + "optional": true + }, + "value": { + "name": "value", + "type": "TypeString", + "description": "Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](/docs/schematics?topic=schematics-create-tf-config#declare-variable).", + "required": true + } + } + }, + { + "name": "template_git_branch", + "type": "TypeString", + "description": "The repository branch.", + "optional": true + }, + { + "name": "template_git_release", + "type": "TypeString", + "description": "The repository release.", + "optional": true + }, + { + "name": "template_git_repo_url", + "type": "TypeString", + "description": "The repository URL.", + "optional": true + }, + { + "name": "template_git_url", + "type": "TypeString", + "description": "The source URL.", + "optional": true + }, + { + "name": "applied_shareddata_ids", + "type": "TypeList", + "description": "List of applied shared dataset ID.", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "template_git_repo_sha_value", + "type": "TypeString", + "description": "The repository SHA value.", + "optional": true + }, + { + "name": "locked", + "type": "TypeBool", + "description": "If set to true, the workspace is locked and disabled for changes.", + "optional": true, + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The timestamp when the workspace was created.", + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The workspace CRN.", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The timestamp when the workspace was last updated.", + "computed": true + }, + { + "name": "location", + "type": "TypeString", + "description": "The location where you want to create your Schematics workspace and run the Schematics jobs. The location that you enter must match the API endpoint that you use. For example, if you use the Frankfurt API endpoint, you must specify `eu-de` as your location. If you use an API endpoint for a geography and you do not specify a location, Schematics determines the location based on availability.", + "cloud_data_type": "region", + "optional": true, + "computed": true + }, + { + "name": "template_git_folder", + "type": "TypeString", + "description": "The subfolder in your GitHub or GitLab repository where your Terraform template is stored.", + "optional": true + }, + { + "name": "template_type", + "type": "TypeString", + "description": "The Terraform version that you want to use to run your Terraform code. Enter `terraform_v0.12` to use Terraform version 0.12, and `terraform_v0.11` to use Terraform version 0.11. The Terraform config files are run with Terraform version 0.11. This is a required variable. Make sure that your Terraform config files are compatible with the Terraform version that you select.", + "required": true, + "matches": "^terraform_v(?:0\\.11|0\\.12|0\\.13|0\\.14|0\\.15|1\\.0|1\\.1)(?:\\.\\d+)?$" + }, + { + "name": "locked_time", + "type": "TypeString", + "description": "The timestamp when the workspace was locked.", + "optional": true, + "computed": true + }, + { + "name": "created_by", + "type": "TypeString", + "description": "The user ID that created the workspace.", + "computed": true + }, + { + "name": "updated_by", + "type": "TypeString", + "description": "The user ID that updated the workspace.", + "computed": true + }, + { + "name": "status_code", + "type": "TypeString", + "description": "The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace.", + "computed": true + }, + { + "name": "status_msg", + "type": "TypeString", + "description": "The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace.", + "computed": true + }, + { + "name": "template_env_settings", + "type": "TypeList", + "description": "A list of environment variables that you want to apply during the execution of a bash script or Terraform job. This field must be provided as a list of key-value pairs, for example, **TF_LOG=debug**. Each entry will be a map with one entry where `key is the environment variable name and value is value`. You can define environment variables for IBM Cloud catalog offerings that are provisioned by using a bash script. See [example to use special environment variable](https://cloud.ibm.com/docs/schematics?topic=schematics-set-parallelism#parallelism-example) that are supported by Schematics.", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + { + "name": "template_ref", + "type": "TypeString", + "description": "Workspace template ref.", + "optional": true + }, + { + "name": "x_github_token", + "type": "TypeString", + "description": "The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template.", + "optional": true + }, + { + "name": "template_values_metadata", + "type": "TypeList", + "description": "List of values metadata.", + "optional": true, + "computed": true, + "elem": { + "type": "TypeMap" + } + }, + { + "name": "frozen_by", + "type": "TypeString", + "description": "The user ID that froze the workspace.", + "optional": true + }, + { + "name": "locked_by", + "type": "TypeString", + "description": "The user ID that initiated a resource-related action, such as applying or destroying resources, that locked the workspace.", + "optional": true, + "computed": true + }, + { + "name": "runtime_data", + "type": "TypeList", + "description": "Information about the provisioning engine, state file, and runtime logs.", + "computed": true, + "elem": { + "engine_cmd": { + "name": "engine_cmd", + "type": "TypeString", + "description": "The command that was used to apply the Terraform template or IBM Cloud catalog software template.", + "optional": true + }, + "engine_name": { + "name": "engine_name", + "type": "TypeString", + "description": "The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template.", + "optional": true + }, + "engine_version": { + "name": "engine_version", + "type": "TypeString", + "description": "The version of the provisioning engine that was used.", + "optional": true + }, + "id": { + "name": "id", + "type": "TypeString", + "description": "The ID that was assigned to your Terraform template or IBM Cloud catalog software template.", + "optional": true + }, + "log_store_url": { + "name": "log_store_url", + "type": "TypeString", + "description": "The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources.", + "optional": true + }, + "output_values": { + "name": "output_values", + "type": "TypeList", + "description": "List of Output values.", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + "resources": { + "name": "resources", + "type": "TypeList", + "description": "List of resources.", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + "state_store_url": { + "name": "state_store_url", + "type": "TypeString", + "description": "The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs.", + "optional": true + } + } + }, + { + "name": "template_git_has_uploadedgitrepotar", + "type": "TypeBool", + "description": "Has uploaded git repo tar", + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The name of your workspace. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. When you create a workspace for your own Terraform template, consider including the microservice component that you set up with your Terraform template and the IBM Cloud environment where you want to deploy your resources in your name.", + "required": true, + "min_length": 1, + "max_length": 128, + "matches": "^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$" + }, + { + "name": "resource_group", + "type": "TypeString", + "description": "The ID of the resource group where you want to provision the workspace.", + "cloud_data_type": "resource_group", + "optional": true + }, + { + "name": "template_values", + "type": "TypeString", + "description": "A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `\"autoscaling: enabled: true minReplicas: 2\"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider.", + "optional": true + }, + { + "name": "frozen", + "type": "TypeBool", + "description": "If set to true, the workspace is frozen and changes to the workspace are disabled.", + "optional": true + }, + { + "name": "description", + "type": "TypeString", + "description": "The description of the workspace.", + "max_length": 2048, + "optional": true + }, + { + "name": "tags", + "type": "TypeList", + "description": "A list of tags that are associated with the workspace.", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "frozen_at", + "type": "TypeString", + "description": "The timestamp when the workspace was frozen.", + "optional": true + }, + { + "name": "last_health_check_at", + "type": "TypeString", + "description": "The timestamp when the last health check was performed by Schematics.", + "computed": true + }, + { + "name": "shared_data", + "type": "TypeList", + "description": "Information about the Target used by the templates originating from the IBM Cloud catalog offerings. This information is not relevant for workspace created using your own Terraform template.", + "optional": true, + "elem": { + "cluster_created_on": { + "name": "cluster_created_on", + "type": "TypeString", + "description": "Cluster created on.", + "optional": true + }, + "cluster_id": { + "name": "cluster_id", + "type": "TypeString", + "description": "The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "optional": true + }, + "cluster_name": { + "name": "cluster_name", + "type": "TypeString", + "description": "The cluster name.", + "optional": true + }, + "cluster_type": { + "name": "cluster_type", + "type": "TypeString", + "description": "The cluster type.", + "optional": true + }, + "entitlement_keys": { + "name": "entitlement_keys", + "type": "TypeList", + "description": "The entitlement key that you want to use to install IBM Cloud entitled software.", + "optional": true, + "elem": { + "type": "TypeMap" + } + }, + "namespace": { + "name": "namespace", + "type": "TypeString", + "description": "The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into.", + "optional": true + }, + "region": { + "name": "region", + "type": "TypeString", + "description": "The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "optional": true + }, + "resource_group_id": { + "name": "resource_group_id", + "type": "TypeString", + "description": "The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering.", + "optional": true + }, + "worker_count": { + "name": "worker_count", + "type": "TypeInt", + "description": "The cluster worker count.", + "optional": true + }, + "worker_machine_type": { + "name": "worker_machine_type", + "type": "TypeString", + "description": "The cluster worker type.", + "optional": true + } + }, + "max_items": 1 + } + ], + "ibm_security_group": [ + { + "name": "name", + "type": "TypeString", + "description": "Security group name", + "required": true + }, + { + "name": "description", + "type": "TypeString", + "description": "Security group description", + "optional": true + } + ], + "ibm_security_group_rule": [ + { + "name": "port_range_max", + "type": "TypeInt", + "description": "Port number max range", + "optional": true + }, + { + "name": "remote_group_id", + "type": "TypeInt", + "description": "remote group ID", + "optional": true + }, + { + "name": "remote_ip", + "type": "TypeString", + "description": "Remote IP Address", + "optional": true + }, + { + "name": "protocol", + "type": "TypeString", + "description": "icmp, tcp or udp", + "optional": true + }, + { + "name": "security_group_id", + "type": "TypeInt", + "description": "Security group ID", + "immutable": true, + "required": true + }, + { + "name": "direction", + "type": "TypeString", + "description": "Direction of rule: ingress or egress", + "required": true + }, + { + "name": "ether_type", + "type": "TypeString", + "description": "IP version IPv4 or IPv6", + "default_value": "IPv4", + "optional": true + }, + { + "name": "port_range_min", + "type": "TypeInt", + "description": "Port number minimum range", + "optional": true + } + ], + "ibm_service_instance": [ + { + "name": "name", + "type": "TypeString", + "description": "A name for the service instance", + "required": true + }, + { + "name": "credentials", + "type": "TypeMap", + "description": "The service broker-provided credentials to use this service.", + "secure": true, + "computed": true + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass along to the service broker. Must be a JSON object", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "space_guid", + "type": "TypeString", + "description": "The guid of the space in which the instance will be created", + "immutable": true, + "required": true + }, + { + "name": "service", + "type": "TypeString", + "description": "The name of the service offering like speech_to_text, text_to_speech etc", + "immutable": true, + "required": true + }, + { + "name": "service_keys", + "type": "TypeList", + "description": "The service keys asociated with the service instance", + "computed": true, + "elem": { + "credentials": { + "name": "credentials", + "type": "TypeMap", + "description": "The service key credential details like port, username etc", + "secure": true, + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "description": "The service key name", + "computed": true + } + } + }, + { + "name": "service_plan_guid", + "type": "TypeString", + "description": "The uniquie identifier of the service offering plan type", + "computed": true + }, + { + "name": "plan", + "type": "TypeString", + "description": "The plan type of the service", + "required": true + }, + { + "name": "wait_time_minutes", + "type": "TypeInt", + "description": "Define timeout to wait for the service instances to succeeded/deleted etc.", + "default_value": 10, + "optional": true + }, + { + "name": "dashboard_url", + "type": "TypeString", + "description": "Dashboard URL to access resource.", + "computed": true + } + ], + "ibm_service_key": [ + { + "name": "name", + "type": "TypeString", + "description": "The name of the service key", + "immutable": true, + "required": true + }, + { + "name": "service_instance_guid", + "type": "TypeString", + "description": "The guid of the service instance for which to create service key", + "immutable": true, + "required": true + }, + { + "name": "parameters", + "type": "TypeMap", + "description": "Arbitrary parameters to pass along to the service broker. Must be a JSON object", + "immutable": true, + "optional": true + }, + { + "name": "credentials", + "type": "TypeMap", + "description": "Credentials asociated with the key", + "secure": true, + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + } + ], + "ibm_space": [ + { + "name": "auditors", + "type": "TypeSet", + "description": "The IBMID of the users who will have auditor role in this space, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "managers", + "type": "TypeSet", + "description": "The IBMID of the users who will have manager role in this space, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "developers", + "type": "TypeSet", + "description": "The IBMID of the users who will have developer role in this space, ex - user@example.com", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "space_quota", + "type": "TypeString", + "description": "The name of the Space Quota Definition", + "immutable": true, + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "name", + "type": "TypeString", + "description": "The name for the space", + "required": true + }, + { + "name": "org", + "type": "TypeString", + "description": "The org this space belongs to", + "immutable": true, + "required": true + } + ], + "ibm_ssl_certificate": [ + { + "name": "validity_months", + "type": "TypeInt", + "description": "vslidity of the ssl certificate in month", + "required": true + }, + { + "name": "billing_contact_same_as_technical_flag", + "type": "TypeBool", + "description": "billing contact", + "default_value": false, + "optional": true + }, + { + "name": "server_type", + "type": "TypeString", + "description": "server type", + "required": true + }, + { + "name": "administrative_contact_same_as_technical_flag", + "type": "TypeBool", + "description": "Administrative contact same as technical flag", + "default_value": false, + "optional": true + }, + { + "name": "administrative_address_same_as_organization_flag", + "type": "TypeBool", + "description": "administrative address same as organization flag", + "default_value": false, + "optional": true + }, + { + "name": "organization_information", + "type": "TypeSet", + "description": "Organization information", + "required": true, + "elem": { + "org_address": { + "name": "org_address", + "type": "TypeSet", + "description": "Organization address", + "required": true, + "elem": { + "org_address_line1": { + "name": "org_address_line1", + "type": "TypeString", + "required": true + }, + "org_address_line2": { + "name": "org_address_line2", + "type": "TypeString", + "optional": true + }, + "org_city": { + "name": "org_city", + "type": "TypeString", + "required": true + }, + "org_country_code": { + "name": "org_country_code", + "type": "TypeString", + "required": true + }, + "org_postal_code": { + "name": "org_postal_code", + "type": "TypeString", + "required": true + }, + "org_state": { + "name": "org_state", + "type": "TypeString", + "required": true + } + } + }, + "org_fax_number": { + "name": "org_fax_number", + "type": "TypeString", + "optional": true + }, + "org_organization_name": { + "name": "org_organization_name", + "type": "TypeString", + "description": "Organization name", + "required": true + }, + "org_phone_number": { + "name": "org_phone_number", + "type": "TypeString", + "description": "Organization phone number", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "technical_contact", + "type": "TypeSet", + "description": "Technical contact info", + "required": true, + "elem": { + "tech_address": { + "name": "tech_address", + "type": "TypeSet", + "optional": true, + "elem": { + "tech_address_line1": { + "name": "tech_address_line1", + "type": "TypeString", + "optional": true + }, + "tech_address_line2": { + "name": "tech_address_line2", + "type": "TypeString", + "optional": true + }, + "tech_city": { + "name": "tech_city", + "type": "TypeString", + "optional": true + }, + "tech_country_code": { + "name": "tech_country_code", + "type": "TypeString", + "optional": true + }, + "tech_postal_code": { + "name": "tech_postal_code", + "type": "TypeString", + "optional": true + }, + "tech_state": { + "name": "tech_state", + "type": "TypeString", + "optional": true + } + } + }, + "tech_email_address": { + "name": "tech_email_address", + "type": "TypeString", + "required": true + }, + "tech_fax_number": { + "name": "tech_fax_number", + "type": "TypeString", + "optional": true + }, + "tech_first_name": { + "name": "tech_first_name", + "type": "TypeString", + "required": true + }, + "tech_last_name": { + "name": "tech_last_name", + "type": "TypeString", + "required": true + }, + "tech_organization_name": { + "name": "tech_organization_name", + "type": "TypeString", + "required": true + }, + "tech_phone_number": { + "name": "tech_phone_number", + "type": "TypeString", + "required": true + }, + "tech_title": { + "name": "tech_title", + "type": "TypeString", + "required": true + } + }, + "max_items": 1 + }, + { + "name": "certificate_signing_request", + "type": "TypeString", + "description": "certificate signing request info", + "required": true + }, + { + "name": "order_approver_email_address", + "type": "TypeString", + "description": "Email address of the approver", + "required": true + }, + { + "name": "renewal_flag", + "type": "TypeBool", + "description": "Renewal flag", + "default_value": true, + "optional": true + }, + { + "name": "technical_contact_same_as_org_address_flag", + "type": "TypeBool", + "description": "Technical contact same as org address flag", + "default_value": false, + "optional": true + }, + { + "name": "billing_address_same_as_organization_flag", + "type": "TypeBool", + "description": "billing address same as organization flag", + "default_value": false, + "optional": true + }, + { + "name": "billing_contact", + "type": "TypeSet", + "optional": true, + "elem": { + "billing_address": { + "name": "billing_address", + "type": "TypeSet", + "optional": true, + "elem": { + "billing_address_line1": { + "name": "billing_address_line1", + "type": "TypeString", + "optional": true + }, + "billing_address_line2": { + "name": "billing_address_line2", + "type": "TypeString", + "optional": true + }, + "billing_city": { + "name": "billing_city", + "type": "TypeString", + "optional": true + }, + "billing_country_code": { + "name": "billing_country_code", + "type": "TypeString", + "optional": true + }, + "billing_postal_code": { + "name": "billing_postal_code", + "type": "TypeString", + "optional": true + }, + "billing_state": { + "name": "billing_state", + "type": "TypeString", + "optional": true + } + } + }, + "billing_email_address": { + "name": "billing_email_address", + "type": "TypeString", + "optional": true + }, + "billing_fax_number": { + "name": "billing_fax_number", + "type": "TypeString", + "optional": true + }, + "billing_first_name": { + "name": "billing_first_name", + "type": "TypeString", + "optional": true + }, + "billing_last_name": { + "name": "billing_last_name", + "type": "TypeString", + "optional": true + }, + "billing_organization_name": { + "name": "billing_organization_name", + "type": "TypeString", + "optional": true + }, + "billing_phone_number": { + "name": "billing_phone_number", + "type": "TypeString", + "optional": true + }, + "billing_title": { + "name": "billing_title", + "type": "TypeString", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "administrative_contact", + "type": "TypeSet", + "optional": true, + "elem": { + "admin_address": { + "name": "admin_address", + "type": "TypeSet", + "optional": true, + "elem": { + "admin_address_line1": { + "name": "admin_address_line1", + "type": "TypeString", + "optional": true + }, + "admin_address_line2": { + "name": "admin_address_line2", + "type": "TypeString", + "optional": true + }, + "admin_city": { + "name": "admin_city", + "type": "TypeString", + "default_value": "", + "optional": true + }, + "admin_country_code": { + "name": "admin_country_code", + "type": "TypeString", + "optional": true + }, + "admin_postal_code": { + "name": "admin_postal_code", + "type": "TypeString", + "optional": true + }, + "admin_state": { + "name": "admin_state", + "type": "TypeString", + "optional": true + } + } + }, + "admin_email_address": { + "name": "admin_email_address", + "type": "TypeString", + "optional": true + }, + "admin_fax_number": { + "name": "admin_fax_number", + "type": "TypeString", + "optional": true + }, + "admin_first_name": { + "name": "admin_first_name", + "type": "TypeString", + "optional": true + }, + "admin_last_name": { + "name": "admin_last_name", + "type": "TypeString", + "optional": true + }, + "admin_organization_name": { + "name": "admin_organization_name", + "type": "TypeString", + "optional": true + }, + "admin_phone_number": { + "name": "admin_phone_number", + "type": "TypeString", + "optional": true + }, + "admin_title": { + "name": "admin_title", + "type": "TypeString", + "optional": true + } + }, + "max_items": 1 + }, + { + "name": "server_count", + "type": "TypeInt", + "description": "Server count", + "required": true + }, + { + "name": "ssl_type", + "type": "TypeString", + "description": "ssl type", + "required": true + } + ], + "ibm_storage_block": [ + { + "name": "snapshot_capacity", + "type": "TypeInt", + "description": "Snapshot capacity in GB", + "immutable": true, + "optional": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "Additional note info", + "optional": true + }, + { + "name": "allowed_ip_addresses", + "type": "TypeSet", + "description": "Allowed IP addresses", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "target_address", + "type": "TypeList", + "description": "List of target Addresses", + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "volumename", + "type": "TypeString", + "description": "Volume name", + "computed": true + }, + { + "name": "lunid", + "type": "TypeString", + "description": "LUN Id", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "os_format_type", + "type": "TypeString", + "description": "OS formatr type", + "immutable": true, + "required": true + }, + { + "name": "allowed_virtual_guest_info", + "type": "TypeSet", + "computed": true, + "elem": { + "host_iqn": { + "name": "host_iqn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "computed": true + } + }, + "deprecated": "Please use 'allowed_host_info' instead" + }, + { + "name": "allowed_host_info", + "type": "TypeList", + "computed": true, + "elem": { + "host_iqn": { + "name": "host_iqn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "allowed_virtual_guest_ids", + "type": "TypeSet", + "description": "List of allowed virtual guest IDs", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "allowed_hardware_ids", + "type": "TypeSet", + "description": "List of allowe hardware IDs", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "tags", + "type": "TypeSet", + "description": "List of tags associated with the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "Storage block size", + "required": true + }, + { + "name": "iops", + "type": "TypeFloat", + "description": "IOPS value required", + "required": true + }, + { + "name": "hostname", + "type": "TypeString", + "description": "Hostname", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Storage block type", + "immutable": true, + "required": true + }, + { + "name": "allowed_hardware_info", + "type": "TypeSet", + "computed": true, + "elem": { + "host_iqn": { + "name": "host_iqn", + "type": "TypeString", + "computed": true + }, + "id": { + "name": "id", + "type": "TypeInt", + "computed": true + }, + "password": { + "name": "password", + "type": "TypeString", + "computed": true + }, + "username": { + "name": "username", + "type": "TypeString", + "computed": true + } + }, + "deprecated": "Please use 'allowed_host_info' instead" + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "description": "Billing done hourly, if set to true", + "default_value": false, + "immutable": true, + "optional": true + } + ], + "ibm_storage_evault": [ + { + "name": "capacity", + "type": "TypeInt", + "description": "Capacity", + "required": true + }, + { + "name": "virtual_instance_id", + "type": "TypeInt", + "description": "Virtual instance ID", + "immutable": true, + "optional": true + }, + { + "name": "hardware_instance_id", + "type": "TypeInt", + "description": "Hardware instance ID", + "immutable": true, + "optional": true + }, + { + "name": "username", + "type": "TypeString", + "description": "user name", + "computed": true + }, + { + "name": "password", + "type": "TypeString", + "description": "password", + "secure": true, + "computed": true + }, + { + "name": "service_resource_name", + "type": "TypeString", + "description": "service resource name", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags set for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + } + ], + "ibm_storage_file": [ + { + "name": "hostname", + "type": "TypeString", + "description": "Hostname", + "computed": true + }, + { + "name": "snapshot_capacity", + "type": "TypeInt", + "description": "Snapshot capacity", + "immutable": true, + "optional": true + }, + { + "name": "allowed_subnets", + "type": "TypeSet", + "description": "Allowed network subnets", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "allowed_ip_addresses", + "type": "TypeSet", + "description": "Allowed range of IP addresses", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "iops", + "type": "TypeFloat", + "description": "iops rate", + "required": true + }, + { + "name": "volumename", + "type": "TypeString", + "description": "Storage volume name", + "computed": true + }, + { + "name": "allowed_virtual_guest_ids", + "type": "TypeSet", + "description": "Virtual guest ID", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + }, + { + "name": "notes", + "type": "TypeString", + "description": "Notes", + "optional": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags set for the storage volume", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "hourly_billing", + "type": "TypeBool", + "description": "Hourly based billing type", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "capacity", + "type": "TypeInt", + "description": "Storage capacity", + "required": true + }, + { + "name": "snapshot_schedule", + "type": "TypeSet", + "optional": true, + "elem": { + "day_of_week": { + "name": "day_of_week", + "type": "TypeString", + "description": "Day of the week", + "optional": true + }, + "enable": { + "name": "enable", + "type": "TypeBool", + "optional": true + }, + "hour": { + "name": "hour", + "type": "TypeInt", + "description": "Time duration in hour", + "optional": true + }, + "minute": { + "name": "minute", + "type": "TypeInt", + "description": "Time duration in minutes", + "optional": true + }, + "retention_count": { + "name": "retention_count", + "type": "TypeInt", + "description": "Retention count", + "required": true + }, + "schedule_type": { + "name": "schedule_type", + "type": "TypeString", + "description": "schedule type", + "required": true + } + }, + "max_items": 3 + }, + { + "name": "mountpoint", + "type": "TypeString", + "description": "Storage mount point", + "computed": true + }, + { + "name": "type", + "type": "TypeString", + "description": "Storage type", + "immutable": true, + "required": true + }, + { + "name": "datacenter", + "type": "TypeString", + "description": "Datacenter name", + "immutable": true, + "required": true + }, + { + "name": "allowed_hardware_ids", + "type": "TypeSet", + "description": "Hardaware ID", + "optional": true, + "computed": true, + "elem": { + "type": "TypeInt" + } + } + ], + "ibm_subnet": [ + { + "name": "capacity", + "type": "TypeInt", + "description": "number of ip addresses in the subnet", + "immutable": true, + "required": true + }, + { + "name": "vlan_id", + "type": "TypeInt", + "description": "VLAN ID for the subnet", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "endpoint_ip", + "type": "TypeString", + "description": "endpoint IP", + "immutable": true, + "optional": true + }, + { + "name": "subnet_cidr", + "type": "TypeString", + "description": "CIDR notation for the subnet", + "computed": true + }, + { + "name": "tags", + "type": "TypeSet", + "description": "tags set for the resource", + "cloud_data_type": "tags", + "optional": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "private", + "type": "TypeBool", + "description": "private subnet", + "default_value": false, + "immutable": true, + "optional": true + }, + { + "name": "type", + "type": "TypeString", + "description": "subnet type", + "immutable": true, + "required": true + }, + { + "name": "ip_version", + "type": "TypeInt", + "description": "ip version", + "default_value": 4, + "immutable": true, + "optional": true + }, + { + "name": "notes", + "type": "TypeString", + "description": "Notes", + "optional": true + } + ], + "ibm_tg_connection": [ + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this connection was created", + "computed": true + }, + { + "name": "status", + "type": "TypeString", + "description": "What is the current configuration state of this connection. Possible values: [attached,failed,pending,deleting,detaching,detached]", + "computed": true + }, + { + "name": "request_status", + "type": "TypeString", + "description": "Only visible for cross account connections, this field represents the status of the request to connect the given network between accounts.Possible values: [pending,approved,rejected,expired,detached]", + "computed": true + }, + { + "name": "connection_id", + "type": "TypeString", + "description": "The Transit Gateway Connection identifier", + "computed": true + }, + { + "name": "network_id", + "type": "TypeString", + "description": "The ID of the network being connected via this connection. This field is required for some types, such as 'vpc' or 'directlink'. The value of this is the CRN of the VPC or direct link gateway to be connected. This field is required to be unspecified for network type 'classic'.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "name", + "type": "TypeString", + "description": "The user-defined name for this transit gateway. If unspecified, the name will be the network name (the name of the VPC in the case of network type 'vpc', and the word Classic, in the case of network type 'classic').", + "min_length": 1, + "max_length": 63, + "matches": "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$", + "optional": true + }, + { + "name": "network_account_id", + "type": "TypeString", + "description": "The ID of the account which owns the network that is being connected. Generally only used if the network is in a different account than the gateway.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "local_gateway_ip", + "type": "TypeString", + "description": "The local gateway IP address. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "zone", + "type": "TypeString", + "description": "Location of GRE tunnel. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "related_crn", + "type": "TypeString", + "description": "The crn of the transit gateway", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "network_type", + "type": "TypeString", + "description": "Defines what type of network is connected via this connection. Allowable values (classic,directlink,vpc,gre_tunnel)", + "immutable": true, + "required": true, + "options": "classic, directlink, vpc, gre_tunnel" + }, + { + "name": "remote_gateway_ip", + "type": "TypeString", + "description": "The remote gateway IP address. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that this connection was last updated", + "computed": true + }, + { + "name": "local_tunnel_ip", + "type": "TypeString", + "description": "The local tunnel IP address. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "remote_bgp_asn", + "type": "TypeInt", + "description": "The remote network BGP ASN. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "base_connection_id", + "type": "TypeString", + "description": "The ID of a network_type 'classic' connection a tunnel is configured over. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + }, + { + "name": "remote_tunnel_ip", + "type": "TypeString", + "description": "The remote tunnel IP address. This field only applies to network type 'gre_tunnel' connections.", + "immutable": true, + "optional": true, + "computed": true + } + ], + "ibm_tg_connection_prefix_filter": [ + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "filter_id", + "type": "TypeString", + "description": "The Transit Gateway Connection Prefix Filter identifier", + "computed": true + }, + { + "name": "action", + "type": "TypeString", + "description": "Whether to permit or deny the prefix filter", + "required": true, + "options": "permit, deny" + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was created", + "computed": true + }, + { + "name": "ge", + "type": "TypeInt", + "description": "IP Prefix GE", + "optional": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The date and time that this prefix filter was last updated", + "computed": true + }, + { + "name": "connection_id", + "type": "TypeString", + "description": "The Transit Gateway Connection identifier", + "required": true + }, + { + "name": "before", + "type": "TypeString", + "description": "Identifier of prefix filter that handles ordering", + "optional": true + }, + { + "name": "le", + "type": "TypeInt", + "description": "IP Prefix LE", + "optional": true + }, + { + "name": "prefix", + "type": "TypeString", + "description": "IP Prefix", + "required": true + } + ], + "ibm_tg_gateway": [ + { + "name": "location", + "type": "TypeString", + "description": "Location of Transit Gateway Services", + "cloud_data_type": "region", + "immutable": true, + "required": true + }, + { + "name": "name", + "type": "TypeString", + "description": "Name Transit Gateway Services", + "required": true, + "options": "^([a-zA-Z]|[a-zA-Z][-_a-zA-Z0-9]*[a-zA-Z0-9])$}", + "min_length": 1, + "max_length": 63 + }, + { + "name": "tags", + "type": "TypeSet", + "description": "Tags for the transit gateway instance", + "min_length": 1, + "max_length": 128, + "matches": "^[A-Za-z0-9:_ .-]+$", + "optional": true, + "computed": true, + "elem": { + "type": "TypeString" + } + }, + { + "name": "status", + "type": "TypeString", + "description": "The Status of the resource", + "computed": true + }, + { + "name": "resource_controller_url", + "type": "TypeString", + "description": "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + "computed": true + }, + { + "name": "resource_name", + "type": "TypeString", + "description": "The name of the resource", + "computed": true + }, + { + "name": "resource_group_name", + "type": "TypeString", + "description": "The resource group name in which resource is provisioned", + "computed": true + }, + { + "name": "resource_status", + "type": "TypeString", + "description": "The status of the resource", + "computed": true + }, + { + "name": "resource_crn", + "type": "TypeString", + "description": "The crn of the resource", + "computed": true + }, + { + "name": "global", + "type": "TypeBool", + "description": "Allow global routing for a Transit Gateway. If unspecified, the default value is false", + "default_value": false, + "optional": true + }, + { + "name": "resource_group", + "type": "TypeString", + "cloud_data_type": "resource_group", + "optional": true, + "computed": true + }, + { + "name": "crn", + "type": "TypeString", + "description": "The crn of the resource", + "cloud_data_type": "crn", + "computed": true + }, + { + "name": "created_at", + "type": "TypeString", + "description": "The creation time of the resource", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "description": "The updation time of the resource", + "computed": true + } + ], + "ibm_tg_route_report": [ + { + "name": "connections", + "type": "TypeList", + "description": "Collection of transit gateway connections", + "computed": true, + "elem": { + "bgps": { + "name": "bgps", + "type": "TypeList", + "description": "Collection of transit gateway connection's bgps", + "computed": true, + "elem": { + "as_path": { + "name": "as_path", + "type": "TypeString", + "computed": true + }, + "is_used": { + "name": "is_used", + "type": "TypeBool", + "computed": true + }, + "local_preference": { + "name": "local_preference", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "id": { + "name": "id", + "type": "TypeString", + "computed": true + }, + "name": { + "name": "name", + "type": "TypeString", + "computed": true + }, + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway connection's used routes", + "computed": true, + "elem": { + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + }, + "type": { + "name": "type", + "type": "TypeString", + "computed": true + } + } + }, + { + "name": "created_at", + "type": "TypeString", + "computed": true + }, + { + "name": "overlapping_routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping routes", + "computed": true, + "elem": { + "routes": { + "name": "routes", + "type": "TypeList", + "description": "Collection of transit gateway overlapping route's details", + "computed": true, + "elem": { + "connection_id": { + "name": "connection_id", + "type": "TypeString", + "computed": true + }, + "prefix": { + "name": "prefix", + "type": "TypeString", + "computed": true + } + } + } + } + }, + { + "name": "status", + "type": "TypeString", + "computed": true + }, + { + "name": "updated_at", + "type": "TypeString", + "computed": true + }, + { + "name": "gateway", + "type": "TypeString", + "description": "The Transit Gateway identifier", + "immutable": true, + "required": true + }, + { + "name": "route_report_id", + "type": "TypeString", + "description": "The Transit Gateway Route Report identifier", + "computed": true + } + ] + }, + "Version": "1.47.0-beta2" +} \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh index 9ed54e853..9d374b19d 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -18,9 +18,9 @@ GIT_COMMIT=$(git rev-parse HEAD) GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true) # Determine the arch/os combos we're building for -XC_ARCH=${XC_ARCH:-"amd64"} +XC_ARCH=${XC_ARCH:-"amd64" "arm64" "arm"} XC_OS=${XC_OS:-linux darwin windows} -XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386" +XC_EXCLUDE_OSARCH="!darwin/386 !windows/arm64 !windows/arm !darwin/arm" # Delete the old dir echo "==> Removing old directory..." diff --git a/version/version.go b/version/version.go index 9a4ea2526..7f431d973 100644 --- a/version/version.go +++ b/version/version.go @@ -5,12 +5,12 @@ import ( ) // Version is the current provider main version -const Version = "1.35.0" +const Version = "1.47.0-beta3" // GitCommit is the git commit that was compiled. This will be filled in by the compiler. var GitCommit string -//VersionPrerelease is the marker for version. If this is "" (empty string) +// VersionPrerelease is the marker for version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. var VersionPrerelease = "" diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index cd76bea79..31f7a6703 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -1,13 +1,16 @@ -Activity Tracker API +Activity Tracker API Gateway -AppID Management +App ID Management App Configuration Catalog Management Certificate Manager Classic infrastructure -Cloud Databases +Cloud Database Cloud Foundry +Cloudant Databases Container Registry +Context Based Restrictions +CD Tekton Pipeline Direct Link Gateway DNS Services Enterprise Management @@ -17,6 +20,7 @@ Functions Global Tagging IBM Cloud Shell Hyper Protect Crypto Service (HPCS) +CD Toolchain Identity & Access Management (IAM) Internet services Key Management Service diff --git a/website/docs/d/app_config_collection.html.markdown b/website/docs/d/app_config_collection.html.markdown new file mode 100644 index 000000000..a7998bf82 --- /dev/null +++ b/website/docs/d/app_config_collection.html.markdown @@ -0,0 +1,63 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration collection' +description: |- + Get information about collection +--- + +# ibm_app_config_collection + +Provides a read-only data source for `collection`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration features, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example Usage + +```hcl +data "ibm_app_config_collection" "app_config_collection" { + guid = "guid" + expand = "expand" + collection_id = "collection_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `collection_id` - (Required, string) Collection Id of the collection. +- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. + +## Attribute Reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `collection_id` - The unique identifier of the collection resouce. + +- `name` - Collection name. + +- `description` - Collection description. + +- `tags` - Tags associated with the collection. + +- `created_time` - Creation time of the collection. + +- `updated_time` - Last updated time of the collection data. + +- `href` - Collection URL. + +- `features` - List of Features associated with the collection. Nested `features` blocks have the following structure: + + - `feature_id` - Feature id. + + - `name` - Feature name. + +- `properties` - List of properties associated with the collection. Nested `properties` blocks have the following structure: + + - `property_id` - Property id. + + - `name` - Property name. + +- `features_count` - Number of features associated with the collection. + +- `properties_count` - Number of features associated with the collection. \ No newline at end of file diff --git a/website/docs/d/app_config_collections.html.markdown b/website/docs/d/app_config_collections.html.markdown new file mode 100644 index 000000000..f6008ed2d --- /dev/null +++ b/website/docs/d/app_config_collections.html.markdown @@ -0,0 +1,96 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration collections' +description: |- + List all the collections. +--- + +# ibm_app_config_collections + +Provides a read-only data source for `collection`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration features flag, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example Usage + +```hcl +data "app_config_collections" "app_config_collections" { + guid = "guid" + tags = "tags" + expand = "expand" + limit = "limit" + offset = "limit" +} +``` + +## Argument Reference + +The following arguments are supported: + +- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `sort` - (optional, string) Sort the collection details based on the specified attribute. +- `tags` - (optional, string) Flter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. +- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. +- `limit` - (optional, int) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. +- `offset` - (optional, int) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. +- `properties` - (optional, array of string) Filter collections by a list of comma separated properties. +- `features` - (optional, array of string) Include the associated collections or targeting rules details in the response. +- `includes` - (optional, array of string) Include feature and property details in the response. + +## Attribute Reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the collections source. +- `collections` - Array of collections. Nested `collections` blocks have the following structure: + +- `name` - Collection name. + +- `collection_id` - Collection Id. + +- `description` - Collection description. + +- `tags` - Tags associated with the collection. + +- `created_time` - Creation time of the collection. + +- `updated_time` - Last updated time of the collection data. + +- `href` - Collection URL. + +- `features` - List of Features associated with the collection. Nested `features` blocks have the following structure: + +- `feature_id` - Feature id. + +- `name` - Feature name. + +- `properties` - List of properties associated with the collection. Nested `properties` blocks have the following structure: + +- `property_id` - Property id. + +- `name` - Property name. + +- `features_count` - Number of features associated with the collection. + +- `properties_count` - Number of features associated with the collection. + +- `total_count` - Number of records returned in the current response. + +- `first` - (List) The URL to navigate to the first page of records. + + Nested scheme for `first`: + - `href` - (String) The first `href` URL. + +- `previous` - (List) The URL to navigate to the previous list of records. + + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. + +- `last` - (List) The URL to navigate to the last list of records. + + Nested scheme for `last`: + - `href` - (String) The last `href` URL. + +- `next` - (List) The URL to navigate to the next list of records. + + Nested scheme for `next`: + - `href` - (String) The next `href` URL. diff --git a/website/docs/d/app_config_environment.html.markdown b/website/docs/d/app_config_environment.html.markdown index 596b6815d..4d1971e1d 100644 --- a/website/docs/d/app_config_environment.html.markdown +++ b/website/docs/d/app_config_environment.html.markdown @@ -8,11 +8,11 @@ description: |- # ibm_app_config_environment -Provides a read-only data source for `environment`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Retrieve information about an existing IBM Cloud App Configuration environment. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration environment, see [Managing access levels for App Configuration environments](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-service-access-level-management). -## Example Usage +## Example usage -```hcl +```terraform data "ibm_app_config_environment" "app_config_environment" { guid = "guid" expand = "expand" @@ -20,23 +20,23 @@ data "ibm_app_config_environment" "app_config_environment" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: -- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. -- `environment_id` - (Required, string) Environment Id. -- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. +- `guid` - (Required, String) GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `environment_id` - (Required, String) Environment ID. +- `expand` - (optional, Bool) If set to `true`, returns expanded view of the resource details. -## Attribute Reference +## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. -- `id` - The unique identifier of the app-config-environment. -- `name` - Environment name. -- `description` - Environment description. -- `tags` - Tags associated with the environment. -- `color_code` - Color code to distinguish the environment. The Hex code for the color. For example `#FF0000` for `red`. -- `created_time` - Creation time of the environment. -- `updated_time` - Last modified time of the environment data. -- `href` - Environment URL. +- `id` - (String) The unique identifier of the app-config-environment. +- `name` - (String) Environment name. +- `description` - (String) Environment description. +- `tags` - (String) Tags associated with the environment. +- `color_code` - (String) The color code to distinguish the environment. The Hexadecimal code for the color. For example `#FF0000` for `red`. +- `created_time` - (Timestamp) Creation time of the environment. +- `updated_time` - (Timestamp) Last modified time of the environment data. +- `href` - (String) Environment URL. diff --git a/website/docs/d/app_config_environments.html.markdown b/website/docs/d/app_config_environments.html.markdown index 0c58e3594..62d7068e0 100644 --- a/website/docs/d/app_config_environments.html.markdown +++ b/website/docs/d/app_config_environments.html.markdown @@ -8,11 +8,11 @@ description: |- # ibm_app_config_environments -Provides a read-only data source for `environments`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Retrieve information about an existing IBM Cloud App Configuration environments. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration environments, see [Managing access levels for App Configuration environments](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-service-access-level-management). -## Example Usage +## Example usage -```hcl +```terraform data "ibm_app_config_environments" "app_config_environments" { guid = "guid" tags = "tags" @@ -22,52 +22,47 @@ data "ibm_app_config_environments" "app_config_environments" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: -- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. -- `tags` - (optional, string) Flter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. -- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. -- `limit` - (optional, int) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. -- `offset` - (optional, int) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. +- `guid` - (Required, String) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `tags` - (Optional, String) Filter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. +- `expand` - (Optional, Bool) If set to `true`, returns expanded view of the resource details. +- `limit` - (Optional, Integer) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. +- `offset` - (Optional, Integer) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. -## Attribute Reference +## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. -- `id` - The unique identifier of the EnvironmentList. -- `environments` - Array of environments. Nested `environments` blocks have the following structure: +- `id` - (String) The unique identifier of the Environment List. +- `environments` - (List) Array of environments. Nested `environments` blocks have the following structure: - - `name` - Environment name. - - - `environment_id` - Environment id. - - - `description` - Environment description. - - - `tags` - Tags associated with the environment. - - - `color_code` - Color code to distinguish the environment. The Hex code for the color. For example `#FF2200` for `red`. - - - `created_time` - Creation time of the environment. - - - `updated_time` - Last modified time of the environment data. - - - `href` - Environment URL. + Nested scheme for `environments`: + - `name` - (String) Environment name. + - `environment_id` - (String) Environment ID. + - `description` - (String) The environment description. + - `tags` - (String) The tags associated with the environment. + - `color_code` - (String) The color code to distinguish the environment. The Hexadecimal code for the color. For example `#FF2200` for `red`. + - `created_time` - (Timestamp) The creation time of the environment. + - `updated_time` - (Timestamp) The last modified time of the environment data. + - `href` - (String) Environment URL. - `total_count` - Number of records returned in the current response. +- `first` - (List) URL to navigate to the first page of records. -- `first` - URL to navigate to the first page of records. Nested `first` blocks have the following structure: - - - `href` - URL. - -- `previous` - URL to navigate to the previous list of records. Nested `previous` blocks have the following structure: - - - `href` - URL. + Nested scheme for `first`: + - `href` - (String) The first `href` URL. +- `previous` - (List) URL to navigate to the previous list of records. -- `last` - URL to navigate to the last list of records. Nested `last` blocks have the following structure: + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. +- `last` - (List) URL to navigate to the last list of records. - - `href` - URL. + Nested scheme for `last`: + - `href` - (String) The last `href` URL. +- `next` - (List) URL to navigate to the next list of records. -- `next` - URL to navigate to the next list of records.. Nested `next` blocks have the following structure: - - `href` - URL. + Nested scheme for `first`: + - `href` - (String) The next `href` URL. diff --git a/website/docs/d/app_config_feature.html.markdown b/website/docs/d/app_config_feature.html.markdown index 5e75f8e50..7d266620b 100644 --- a/website/docs/d/app_config_feature.html.markdown +++ b/website/docs/d/app_config_feature.html.markdown @@ -8,11 +8,11 @@ description: |- # ibm_app_config_feature -Provides a read-only data source for `feature flag`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Retrieve information about an existing IBM Cloud App Configuration feature. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration features, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). -## Example Usage +## Example usage -```hcl +```terraform data "ibm_app_config_feature" "app_config_feature" { guid = "guid" feature_id = "feature_id" @@ -21,41 +21,45 @@ data "ibm_app_config_feature" "app_config_feature" { } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +Review the argument reference that you can specify for your data source. -- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. -- `feature_id` - (Required, string) Feature Id. -- `environment_id` - (Required, string) Environment Id. -- `includes` - (Optional, string) Include the associated collections in the response. +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `feature_id` - (Required, String) The feature ID. +- `environment_id` - (Required, String) The environment ID. +- `includes` - (Optional, String) Include the associated collections in the response. -## Attribute Reference +## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. -- `id` - The unique identifier of the feature flag resource. -- `name` - Feature name. -- `description` - Feature description. -- `type` - Type of the feature (BOOLEAN, STRING, NUMERIC). -- `enabled_value` - Value of the feature when it is enabled. The value can be Boolean, String or a Numeric value as per the `type` attribute. -- `disabled_value` - Value of the feature when it is disabled. The value can be Boolean, String or a Numeric value as per the `type` attribute. -- `enabled` - The state of the feature flag. -- `tags` - Tags associated with the feature. -- `segment_rules` - Specify the targeting rules that is used to set different feature flag values for different segments. Nested `segment_rules` blocks have the following structure: +- `id` - (String) The unique identifier of the feature flag resource. +- `name` - (String) Feature name. +- `description` - (String) Feature description. +- `type` - (String) Type of the feature (BOOLEAN, STRING, NUMERIC). +- `enabled_value` - (String) Value of the feature when it is enabled. The value can be Boolean, String or a Numeric value as per the `type` attribute. +- `disabled_value` - (String) Value of the feature when it is disabled. The value can be Boolean, String or a Numeric value as per the `type` attribute. +- `enabled` - (String) The state of the feature flag. +- `tags` - (String) Tags associated with the feature. +- `rollout_percentage` - (String) Rollout percentage of the feature. +- `segment_rules` - (List) Specify the targeting rules that is used to set different feature flag values for different segments. - - `rules` - The list of targetted segments. Nested `rules` blocks have the following structure: - - `segments` - List of segment ids that are used for targeting using the rule. - - `value` - Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. - - `order` - Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. + Nested scheme for `segment_rules`: + - `rules` - (List) The list of targeted segments. -- `segment_exists` - Denotes if the targeting rules are specified for the feature flag. -- `collections` - List of collection id representing the collections that are associated with the specified feature flag. Nested `collections` blocks have the following structure: + Nested scheme for `rules`: + - `segments` - (String) List of segment ids that are used for targeting using the rule. + - `value` - (String) Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. + - `order` - (String) Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. + - `rollout_percentage` - (String) Rollout percentage for the segment rule. +- `segment_exists` - (String) Denotes if the targeting rules are specified for the feature flag. +- `collections` - (List) List of collection ID representing the collections that are associated with the specified feature flag. - - `collection_id` - Collection id. + Nested scheme for `collections`: - - `name` - Name of the collection. - -- `created_time` - Creation time of the feature flag. -- `updated_time` - Last modified time of the feature flag data. -- `href` - Feature flag URL. + - `collection_id` - (String) The collection ID. + - `name` - (String) The name of the collection. +- `created_time` - (Timestamp) The creation time of the feature flag. +- `updated_time` - (Timestamp) The last modified time of the feature flag data. +- `href` - (String) The feature flag URL. diff --git a/website/docs/d/app_config_features.html.markdown b/website/docs/d/app_config_features.html.markdown index 58ede7929..cafd9f514 100644 --- a/website/docs/d/app_config_features.html.markdown +++ b/website/docs/d/app_config_features.html.markdown @@ -8,11 +8,11 @@ description: |- # ibm_app_config_features -Provides a read-only data source for all `feature flags`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Retrieve information about an existing IBM Cloud App Configuration features flag. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration features flag, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). -## Example Usage +## Example usage -```hcl +```terraform data "ibm_app_config_features" "app_config_features" { guid = "guid" tags = "tags" @@ -23,81 +23,72 @@ data "ibm_app_config_features" "app_config_features" { } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +Review the argument reference that you can specify for your data source. -- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. -- `environment_id` - (Required, string) Environment Id. -- `tags` - (optional, string) Flter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. -- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. -- `limit` - (optional, int) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. -- `offset` - (optional, int) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. -- `sort` - (optiona, string) Sort the feature details based on the specified attribute. -- `collections` - (optiona, array of string) Filter features by a list of comma separated collections. -- `segments` - (optiona, array of string) Filter features by a list of comma separated segments. -- `includes` - (optiona, array of string) Include the associated collections or targeting rules details in the response. +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `environment_id` - (Required, String) Environment ID. +- `tags` - (optional, String) Flter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. +- `expand` - (optional, Bool) If set to `true`, returns expanded view of the resource details. +- `limit` - (optional, Integer) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. +- `offset` - (optional, Integer) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. +- `sort` - (optiona, String) Sort the feature details based on the specified attribute. +- `collections` - (optiona, Array of String) Filter features by a list of comma separated collections. +- `segments` - (optiona, Array of String) Filter features by a list of comma separated segments. +- `includes` - (optiona, Array of String) Include the associated collections or targeting rules details in the response. -## Attribute Reference +## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. -- `id` - The unique identifier of the Features datasource. -- `features` - Array of Features. Nested `features` blocks have the following structure: - - - `name` - Feature name. - - - `feature_id` - Feature id. - - - `description` - Feature description. - - - `type` - Type of the feature (BOOLEAN, STRING, NUMERIC). - - - `enabled_value` - Value of the feature when it is enabled. - - - `disabled_value` - Value of the feature when it is disabled. - - - `tags` - Tags associated with the feature. - - - `enabled` - The state of the feature flag. - - - `segment_exists` - Denotes if the targeting rules are specified for the feature flag. - - - `segment_rules` - Segment Rules array. Nested `segment_rules` blocks have the following structure: - - - `rules` - Rules array. Nested `rules` blocks have the following structure: - - - `segments` - Segments array. - - - `value` - Value of the segment. - - - `order` - Order of the segment, used during evaluation. - - - `collections` - Collection array. Nested `collections` blocks have the following structure: - - - `collection_id` - Collection id. - - - `name` - Name of the collection. - - - `created_time` - Creation time of the feature flag. - - - `updated_time` - Last modified time of the feature flag data. - - - `href` - Feature flag URL. - -- `total_count` - Number of records returned in the current response. - -- `first` - URL to navigate to the first page of records. Nested `first` blocks have the following structure: - - - `href` - URL. - -- `previous` - URL to navigate to the previous list of records. Nested `previous` blocks have the following structure: - - - `href` - URL. - -- `last` - URL to navigate to the last list of records. Nested `last` blocks have the following structure: - - - `href` - URL. - -- `next` - URL to navigate to the next list of records.. Nested `next` blocks have the following structure: - - `href` - URL. +- `id` - (String) The unique identifier of the Features datasource. +- `features` - (List) Array of Features. + + Nested scheme for `features`: + + - `name` - (String) The feature name. + - `feature_id` - (String) The feature ID. + - `description` - (String) The feature description. + - `type` - (String) The type of the feature. Supported values are `BOOLEAN`, `STRING`, and `NUMERIC`). + - `enabled_value` - (String) The value of the feature when it is enabled. + - `disabled_value` - (String) The value of the feature when it is disabled. + - `tags` - (String) The tags associated with the feature. + - `rollout_percentage` - (String) Rollout percentage of the feature. + - `enabled` - (String) The state of the feature flag. + - `segment_exists` - (String) Denotes if the targeting rules are specified for the feature flag. + - `segment_rules` - (List) The segment rules array. + + Nested scheme for `segment_rules`: + - `rules` - (List) The rules array. + + Nested scheme for `rules`: + - `segments` - (String) The Segments array. + - `value` - (String) Value of the segment. + - `order` - (String) Order of the segment, used during evaluation. + - `rollout_percentage` - (String) Rollout percentage for the segment rule. + - `collections` - (List) The collection array. + + Nested scheme for `collections`: + - `collection_id` - (String) The collection ID. + - `name` - (String) Name of the collection. + - `created_time` - (String) Creation time of the feature flag. + - `updated_time` - (String) Last modified time of the feature flag data. + - `href` - (String) Feature flag URL. +- `total_count` - (String) Number of records returned in the current response. +- `first` - (List) The URL to navigate to the first page of records. + + Nested scheme for `first`: + - `href` - (String) The first `href` URL. +- `previous` - (List) The URL to navigate to the previous list of records. + + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. +- `last` - (List) The URL to navigate to the last list of records. + + Nested scheme for `last`: + - `href` - (String) The last `href` URL. +- `next` - (List) The URL to navigate to the next list of records. + + Nested scheme for `next`: + - `href` - (String) The next `href` URL. diff --git a/website/docs/d/app_config_properties.html.markdown b/website/docs/d/app_config_properties.html.markdown new file mode 100644 index 000000000..b9c4700e3 --- /dev/null +++ b/website/docs/d/app_config_properties.html.markdown @@ -0,0 +1,96 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration properties' +description: |- + List all the properties. +--- + +# ibm_app_config_properties + +Retrieve information about an existing IBM Cloud App Configuration properties. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration properties, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example Usage + +```terraform +data "ibm_app_config_properties" "app_config_properties" { + guid = "guid" + environment_id = "environment_id" +} +``` + +## Argument Reference + +The following arguments are supported: + +- `guid` - (Required, String) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `environment_id` - (Required, String) Environment Id. +- `tags` - (optional, String) Flter the resources to be returned based on the associated tags. Returns resources associated with any of the specified tags. +- `expand` - (optional, bool) If set to `true`, returns expanded view of the resource details. +- `limit` - (optional, int) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. +- `offset` - (optional, int) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. +- `sort` - (optiona, String) Sort the feature details based on the specified attribute. +- `collections` - (optiona, array of String) Filter properties by a list of comma separated collections. +- `segments` - (optiona, array of String) Filter properties by a list of comma separated segments. +- `includes` - (optiona, array of String) Include the associated collections or targeting rules details in the response. + +## Attribute Reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the PropertiesList. + - `properties` - (List) Array of properties. + + Nested scheme for `properties` + - `name` - (String) Property name. + - `property_id` - (String) Property id. + - `description` - (String) Property description. + - `type` - (String) Type of the Property (BOOLEAN, STRING, NUMERIC). + - `value` - Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute. + - `tags` - (String) Tags associated with the property. + - `format` - (String) Format of the property (TEXT, JSON, YAML) and this is a required attribute when TYPE STRING is used, not required for BOOLEAN and NUMERIC types. + + - `segment_rules` - (List) Specify the targeting rules that is used to set different property values for different segments. + + Nested scheme for `segment_rules` + - `rules` - (List) The rules array. + + Nested scheme for `rules` + - `segments` - (String) List of segment ids that are used for targeting using the rule. + - `value` - (String) Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. + - `order` - (String) Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. +- `segment_exists` - (String) Denotes if the targeting rules are specified for the property. +- `collections` - List of collection id representing the collections that are associated with the specified property. + + Nested `collections` blocks have the following structure: + - `collection_id` - (String) Collection id. + - `name` - (String) Name of the collection. + +- `created_time` - Creation time of the property. +- `updated_time` - Last modified time of the property data. +- `evaluation_time` - The last occurrence of the property value evaluation. +- `href` - Property URL. + +- `total_count` - Number of records returned in the current response. +- `limit` - Number of records returned +- `offset` - Skipped number of records + +- `first` - (List) The URL to navigate to the first page of records. + + Nested scheme for `first`: + - `href` - (String) The first `href` URL. + +- `previous` - (List) The URL to navigate to the previous list of records. + + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. + +- `last` - (List) The URL to navigate to the last list of records. + + Nested scheme for `last`: + - `href` - (String) The last `href` URL. + +- `next` - (List) The URL to navigate to the next list of records. + + Nested scheme for `next`: + - `href` - (String) The next `href` URL. \ No newline at end of file diff --git a/website/docs/d/app_config_property.html.markdown b/website/docs/d/app_config_property.html.markdown new file mode 100644 index 000000000..ed7690719 --- /dev/null +++ b/website/docs/d/app_config_property.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration property' +description: |- + Get information about property. +--- + +# ibm_app_config_property + +Retrieve information about an existing IBM Cloud App Configuration property. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration property, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example Usage + +```terraform +data "ibm_app_config_property" "app_config_property" { + guid = "guid" + environment_id = "environment_id" + property_id = "property_id" +} +``` + +## Argument Reference + +The following arguments are supported: + +- `guid` - (Required, String) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `environment_id` - (Required, String) Environment Id. +- `property_id` - (Required, String) Property Id. +- `include` - (Optional, String) Include the associated collections in the response. + +## Attribute Reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `property_id` - The unique identifier of the app_config_property. +- `name` - Property name. +- `description` - Property description. +- `type` - Type of the Property (BOOLEAN, STRING, NUMERIC). +- `value` - Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute. +- `tags` - Tags associated with the property. +- `format` - Format of the property (TEXT, JSON, YAML) and this is a required attribute when TYPE STRING is used, not required for BOOLEAN and NUMERIC types. +- `segment_rules` - Specify the targeting rules that is used to set different property values for different segments. Nested `segment_rules` blocks have the following structure: + - `rules` - Rules array. Nested `rules` blocks have the following structure: + - `segments` - List of segment ids that are used for targeting using the rule. + - `value` - Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. + - `order` - Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. + +- `segment_exists` - Denotes if the targeting rules are specified for the property. +- `collections` - List of collection id representing the collections that are associated with the specified property. Nested `collections` blocks have the following structure: + - `collection_id` - Collection id. + - `name` - Name of the collection. + +- `created_time` - Creation time of the property. +- `updated_time` - Last modified time of the property data. +- `evaluation_time` - The last occurrence of the property value evaluation. +- `href` - Property URL. \ No newline at end of file diff --git a/website/docs/d/app_config_segment.html.markdown b/website/docs/d/app_config_segment.html.markdown new file mode 100644 index 000000000..ded3d9c4d --- /dev/null +++ b/website/docs/d/app_config_segment.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration segment' +description: |- + Get information about segment +--- + +# ibm_app_config_segment +Retrieve information about an existing IBM Cloud App Configuration segment. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration segment, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example usage + +```terraform +data "ibm_app_config_segment" "app_config_segment" { + guid = "guid" + segment_id = "segment_id" + includes = "includes" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `segment_id` - (Required, String) The segment ID. +- `includes` - (Optional, String) Include feature and property details in the response. + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `segment_id` - (String) Segment id. +- `name` - (String) Segment name. +- `description` - (String) Segment description. +- `tags` - (String) Tags associated with the segments. +- `created_time` - (Timestamp) Creation time of the segment. +- `updated_time` - (Timestamp) Last modified time of the segment data. +- `href` - (String) Segment URL. +- `rules` - (String) List of rules that determine if the entity belongs to the segment during feature / property evaluation. + + Nested scheme for `rules`: + - `attribute_name` - (String) Attribute name. + - `operator` - (String) Operator to be used for the evaluation if the entity belongs to the segment. + - `values` - (String) List of values. Entities matching any of the given values will be considered to belong to the segment. + +- `features` - (List) List of Features associated with the segment. + + Nested scheme for `features`: + - `feature_id` - (String) Feature Id. + - `name` - (String) Feature Name. + +- `properties` - (List) List of properties associated with the segment. + + Nested scheme for `properties`: + - `property_id` - (String) Property Id. + - `name` - (String) Property Name. diff --git a/website/docs/d/app_config_segments.html.markdown b/website/docs/d/app_config_segments.html.markdown new file mode 100644 index 000000000..f5545c04a --- /dev/null +++ b/website/docs/d/app_config_segments.html.markdown @@ -0,0 +1,92 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration segments' +description: |- + List all the segments. +--- + +# ibm_app_config_segments + +Retrieve information about an existing IBM Cloud App Configuration segments. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration segments, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example usage + +```terraform +data "ibm_app_config_segments" "app_config_segments" { + guid = "guid" + tags = "tags" + expand = "expand" + limit = "limit" + offset = "limit" + include = "include" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `tags` - (optional, String) Filter the resources to be returned based on the associated tags. Specify the parameter as a list of comma separated tags. Returns resources associated with any of the specified tags. +- `expand` - (optional, String) If set to `true`, returns expanded view of the resource details. +- `limit` - (optional, Integer) The number of records to retrieve. By default, the list operation return the first 10 records. To retrieve different set of records, use `limit` with `offset` to page through the available records. +- `offset` - (optional, Integer) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. Use `offset` with `limit` to page through the available records. +- `include` - (optional, String) Segment details to include the associated rules in the response. +- `sort` - (optional, String) Sort the segment details based on the specified attribute. + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `segments` - (List) Array of Segments. + + Nested scheme for `segments`: + - `name` - (String) Segment name. + - `segment_id` - (String) Segment id. + - `description` - (String) Segment description. + - `tags` - (String) Tags associated with the segments. + - `created_time` - (String) Creation time of the segment. + - `updated_time` - (String) Last modified time of the segment data. + - `href` - (String) Segment URL. + - `rules` - (List) List of rules that determine if the entity belongs to the segment during feature / property evaluation. An entity is identified by an unique identifier and the attributes that it defines. + + Nested scheme for `rules`: + - `attribute_name` - (String) Attribute name. + - `operator` - (String) Operator to be used for the evaluation if the entity belongs to the segment. + - `values` - (String) List of values. Entities matching any of the given values will be considered to belong to the segment. + - `features` - (List) List of Features associated with the segment. + + Nested scheme for `features`: + - `feature_id` - Feature id. + - `name` - Feature name. + + - `properties` - (List) List of properties associated with the segment. + + Nested scheme for `properties`: + - `property_id` - Property id. + - `name` - Property name. + + +- `limit` - (Integer) Number of records returned +- `offset` - (Integer) Skipped number of records +- `total_count` - (Integer) Total number of records +- `first` - (List) The URL to navigate to the first page of records. + + Nested scheme for `first`: + - `href` - (String) The first `href` URL. + +- `last` - (List) The URL to navigate to the last page of records. + + Nested scheme for `last`: + - `href` - (String) The last `href` URL. + +- `previous` - (List) The URL to navigate to the previous list of records. + + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. + +- `next` - (List) The URL to navigate to the next list of records + + Nested scheme for `next`: + - `href` - (String) The next `href` URL. diff --git a/website/docs/d/app_config_snapshot.html.markdown b/website/docs/d/app_config_snapshot.html.markdown new file mode 100644 index 000000000..e2b3be771 --- /dev/null +++ b/website/docs/d/app_config_snapshot.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration Snapshot' +description: |- + Get information about Snapshot +--- + +# ibm_app_config_segment +Retrieve information about an existing IBM Cloud App Configuration snapshot. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration snapshot, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example usage + +```terraform +data "ibm_app_config_snapshot" "app_config_snapshot_read" { + guid = "guid" + git_config_id = "git_config_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `git_config_id` - (Required, String) The Git Config Id. + + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `git_config_name` - (String) Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only. +- `git_config_id` - (String) Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only +- `git_url` - (String) Git url which will be used to connect to the github account. The url must be formed in this format, https://api.github.com/repos/{owner}/{repo_name} for the personal git account. +- `git_branch` - (String) Branch name to which you need to write or update the configuration. +- `git_file_path` - (String) Git file path, this is a path where your configuration file will be written. The path must contain the file name with `json` extension. +- `collection` - (Object) Collection object will be returned containing attributes collection_id, collection_name. + + Nested scheme for `collection`: + - `collection_id` - (String) Collection id. + - `name` - (String) Name of the collection. + +- `environment` - (Object) Environment object will be returned containing attributes environment_id, environment_name, color_code. + + Nested scheme for `environment` : + - `environment_id` - (String) Environment Id. + - `environment_name` - (String) Environment name. + +- `created_time` - (Timestamp) Creation time of the git config. +- `updated_time` - (Timestamp) Last modified time of the git config data. +- `last_sync_time` - (Timestamp) Latest time when the snapshot was synced to git. +- `href` - (String) Git config URL. diff --git a/website/docs/d/app_config_snapshots.html.markdown b/website/docs/d/app_config_snapshots.html.markdown new file mode 100644 index 000000000..706d6c32f --- /dev/null +++ b/website/docs/d/app_config_snapshots.html.markdown @@ -0,0 +1,93 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration Snapshots' +description: |- + Get information about Snapshots +--- + +# ibm_app_config_segment +Retrieve information about an existing IBM Cloud App Configuration snapshots. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about App Configuration snapshot, see [App Configuration concepts](https://cloud.ibm.com//docs/app-configuration?topic=app-configuration-ac-overview). + +## Example usage + +```terraform +data "ibm_app_config_snapshots" "app_config_snapshots" { + guid = "guid" + sort = "sort" + collection_id = "collection_id" + environment_id = "environment_id" + limit = "limit" + offset = "offset" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `guid` - (Required, String) The GUID of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `collection_id` - (Optional, String) Filters the response based on the specified collection_id. +- `environment_id` - (Optional, String) Filters the response based on the specified environment_id. +- `limit` - (Optional, String) The number of records to retrieve. By default, the list operation return the first 10 records. +- `offset` - (Optional, String) The number of records to skip. By specifying `offset`, you retrieve a subset of items that starts with the `offset` value. + + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `limit` - (Integer) Number of records returned. +- `offset` - (Integer) Skipped number of records. +- `total_count` - (Integer) Total number of records + +- `first` - (List) The URL to navigate to the first page of records. + + Nested scheme for `first`: + - `href` - (String) The first `href` URL. + +- `last` - (List) The URL to navigate to the last page of records. + + Nested scheme for `last`: + - `href` - (String) The last `href` URL. + +- `previous` - (List) The URL to navigate to the previous list of records. + + Nested scheme for `previous`: + - `href` - (String) The previous `href` URL. + +- `next` - (List) The URL to navigate to the next list of records + + Nested scheme for `next`: + - `href` - (String) The next `href` URL. + + +- `git_config` - Array of git_configs. + + Nested scheme for `git_config`: + - `git_config_name` - (String) Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only. + - `git_config_id` - (String) Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only + - `git_url` - (String) Git url which will be used to connect to the github account. The url must be formed in this format, https://api.github.com/repos/{owner}/{repo_name} for the personal git account. + - `git_branch` - (String) Branch name to which you need to write or update the configuration. + - `git_file_path` - (String) Git file path, this is a path where your configuration file will be written. The path must contain the file name with `json` extension. + - `created_time` - (Timestamp) Creation time of the git config. + - `updated_time` - (Timestamp) Last modified time of the git config data. + - `last_sync_time` - (Timestamp) Latest time when the snapshot was synced to git. + - `href` - (String) Git config URL. + + - `collection` - (Object) Collection object will be returned containing attributes collection_id, collection_name. + + Nested scheme for `collection`: + - `collection_id` - (String) Collection id. + - `name` - (String) Name of the collection. + + - `environment` - (Object) Environment object will be returned containing attributes environment_id, environment_name, color_code. + + Nested scheme for `environment` : + - `environment_id` - (String) Environment Id. + - `environment_name` - (String) Environment name. + - `color_code` - (String) Color code to distinguish the environment. + + + + \ No newline at end of file diff --git a/website/docs/d/appid_action_url.html.markdown b/website/docs/d/appid_action_url.html.markdown index 140a163cf..f3e4f49ec 100644 --- a/website/docs/d/appid_action_url.html.markdown +++ b/website/docs/d/appid_action_url.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Action URL" description: |- diff --git a/website/docs/d/appid_apm.html.markdown b/website/docs/d/appid_apm.html.markdown index 08461edbd..033f79b0f 100644 --- a/website/docs/d/appid_apm.html.markdown +++ b/website/docs/d/appid_apm.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID APM" description: |- diff --git a/website/docs/d/appid_application.html.markdown b/website/docs/d/appid_application.html.markdown index 8a1d8a750..7309e92b8 100644 --- a/website/docs/d/appid_application.html.markdown +++ b/website/docs/d/appid_application.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application" description: |- diff --git a/website/docs/d/appid_application_roles.html.markdown b/website/docs/d/appid_application_roles.html.markdown index 6b6926d4e..73e4178f2 100644 --- a/website/docs/d/appid_application_roles.html.markdown +++ b/website/docs/d/appid_application_roles.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application Roles" description: |- diff --git a/website/docs/d/appid_application_scopes.html.markdown b/website/docs/d/appid_application_scopes.html.markdown index fbd26f243..8a2487da0 100644 --- a/website/docs/d/appid_application_scopes.html.markdown +++ b/website/docs/d/appid_application_scopes.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application Scopes" description: |- diff --git a/website/docs/d/appid_applications.html.markdown b/website/docs/d/appid_applications.html.markdown index a3c7f0baa..a12d87e12 100644 --- a/website/docs/d/appid_applications.html.markdown +++ b/website/docs/d/appid_applications.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Applications" description: |- diff --git a/website/docs/d/appid_audit_status.html.markdown b/website/docs/d/appid_audit_status.html.markdown index d11195501..4d666c30a 100644 --- a/website/docs/d/appid_audit_status.html.markdown +++ b/website/docs/d/appid_audit_status.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Audit Status" description: |- diff --git a/website/docs/d/appid_cloud_directory_template.html.markdown b/website/docs/d/appid_cloud_directory_template.html.markdown index 3bb5335d3..f8c9c6ef6 100644 --- a/website/docs/d/appid_cloud_directory_template.html.markdown +++ b/website/docs/d/appid_cloud_directory_template.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory Template" description: |- diff --git a/website/docs/d/appid_cloud_directory_user.html.markdown b/website/docs/d/appid_cloud_directory_user.html.markdown index 92f90c658..76c044521 100644 --- a/website/docs/d/appid_cloud_directory_user.html.markdown +++ b/website/docs/d/appid_cloud_directory_user.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory User" description: |- diff --git a/website/docs/d/appid_idp_cloud_directory.html.markdown b/website/docs/d/appid_idp_cloud_directory.html.markdown index ecd4143f8..53edffa63 100644 --- a/website/docs/d/appid_idp_cloud_directory.html.markdown +++ b/website/docs/d/appid_idp_cloud_directory.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory IDP" description: |- diff --git a/website/docs/d/appid_idp_custom.html.markdown b/website/docs/d/appid_idp_custom.html.markdown index 30de0ca72..d878384ab 100644 --- a/website/docs/d/appid_idp_custom.html.markdown +++ b/website/docs/d/appid_idp_custom.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Custom IDP" description: |- diff --git a/website/docs/d/appid_idp_facebook.html.markdown b/website/docs/d/appid_idp_facebook.html.markdown index a0083e0f2..2cfb93afd 100644 --- a/website/docs/d/appid_idp_facebook.html.markdown +++ b/website/docs/d/appid_idp_facebook.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Facebook IDP" description: |- diff --git a/website/docs/d/appid_idp_google.html.markdown b/website/docs/d/appid_idp_google.html.markdown index c287bacfa..936450c1f 100644 --- a/website/docs/d/appid_idp_google.html.markdown +++ b/website/docs/d/appid_idp_google.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Google IDP" description: |- diff --git a/website/docs/d/appid_idp_saml.html.markdown b/website/docs/d/appid_idp_saml.html.markdown index b26894ea1..b8fd648a8 100644 --- a/website/docs/d/appid_idp_saml.html.markdown +++ b/website/docs/d/appid_idp_saml.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID SAML IDP" description: |- diff --git a/website/docs/d/appid_idp_saml_metadata.html.markdown b/website/docs/d/appid_idp_saml_metadata.html.markdown index ec7c6e70d..caa1956e9 100644 --- a/website/docs/d/appid_idp_saml_metadata.html.markdown +++ b/website/docs/d/appid_idp_saml_metadata.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID IDP SAML Metadata" description: |- diff --git a/website/docs/d/appid_languages.html.markdown b/website/docs/d/appid_languages.html.markdown index 37d868da0..41744df92 100644 --- a/website/docs/d/appid_languages.html.markdown +++ b/website/docs/d/appid_languages.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Languages" description: |- diff --git a/website/docs/d/appid_mfa.html.markdown b/website/docs/d/appid_mfa.html.markdown index 2c24f62ee..e658dca5f 100644 --- a/website/docs/d/appid_mfa.html.markdown +++ b/website/docs/d/appid_mfa.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID MFA" description: |- diff --git a/website/docs/d/appid_mfa_channel.html.markdown b/website/docs/d/appid_mfa_channel.html.markdown index 1a70e215d..21c170249 100644 --- a/website/docs/d/appid_mfa_channel.html.markdown +++ b/website/docs/d/appid_mfa_channel.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID MFA" description: |- diff --git a/website/docs/d/appid_password_regex.html.markdown b/website/docs/d/appid_password_regex.html.markdown index 779ef49f6..e5c1ece2c 100644 --- a/website/docs/d/appid_password_regex.html.markdown +++ b/website/docs/d/appid_password_regex.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Password Regex" description: |- diff --git a/website/docs/d/appid_redirect_urls.html.markdown b/website/docs/d/appid_redirect_urls.html.markdown index 074042bc9..29add78a9 100644 --- a/website/docs/d/appid_redirect_urls.html.markdown +++ b/website/docs/d/appid_redirect_urls.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory Redirect URLs" description: |- diff --git a/website/docs/d/appid_role.html.markdown b/website/docs/d/appid_role.html.markdown index f3503f406..2ffe259c5 100644 --- a/website/docs/d/appid_role.html.markdown +++ b/website/docs/d/appid_role.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Role" description: |- diff --git a/website/docs/d/appid_roles.html.markdown b/website/docs/d/appid_roles.html.markdown index fb0ea6c01..05247f4b7 100644 --- a/website/docs/d/appid_roles.html.markdown +++ b/website/docs/d/appid_roles.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Roles" description: |- diff --git a/website/docs/d/appid_theme_color.html.markdown b/website/docs/d/appid_theme_color.html.markdown index bf58fbfce..81ca0946f 100644 --- a/website/docs/d/appid_theme_color.html.markdown +++ b/website/docs/d/appid_theme_color.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Theme Color" description: |- diff --git a/website/docs/d/appid_theme_text.html.markdown b/website/docs/d/appid_theme_text.html.markdown index cb9588a65..cb2511d9d 100644 --- a/website/docs/d/appid_theme_text.html.markdown +++ b/website/docs/d/appid_theme_text.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Theme Text" description: |- diff --git a/website/docs/d/appid_token_config.html.markdown b/website/docs/d/appid_token_config.html.markdown index fed89f0af..c2017e8c9 100644 --- a/website/docs/d/appid_token_config.html.markdown +++ b/website/docs/d/appid_token_config.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Token Configuration" description: |- diff --git a/website/docs/d/appid_user_roles.html.markdown b/website/docs/d/appid_user_roles.html.markdown index 2ab50e5b8..2880e4e11 100644 --- a/website/docs/d/appid_user_roles.html.markdown +++ b/website/docs/d/appid_user_roles.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID User Roles" description: |- diff --git a/website/docs/d/atracker_endpoints.html.markdown b/website/docs/d/atracker_endpoints.html.markdown index 4987667e6..aca8163ee 100644 --- a/website/docs/d/atracker_endpoints.html.markdown +++ b/website/docs/d/atracker_endpoints.html.markdown @@ -3,22 +3,22 @@ layout: "ibm" page_title: "IBM : ibm_atracker_endpoints" description: |- Get information about atracker_endpoints -subcategory: "Activity Tracker API" +subcategory: "Activity Tracker" --- # ibm_atracker_endpoints Provides a read-only data source for atracker_endpoints. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_atracker_endpoints" "atracker_endpoints" { } ``` -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/atracker_routes.html.markdown b/website/docs/d/atracker_routes.html.markdown index bb78e2c0e..8d871d958 100644 --- a/website/docs/d/atracker_routes.html.markdown +++ b/website/docs/d/atracker_routes.html.markdown @@ -3,7 +3,7 @@ layout: "ibm" page_title: "IBM : ibm_atracker_routes" description: |- Get information about atracker_routes -subcategory: "Activity Tracker API" +subcategory: "Activity Tracker" --- # ibm_atracker_routes @@ -12,7 +12,7 @@ Provides a read-only data source for atracker_routes. You can then reference the ## Example Usage -```hcl +```terraform data "ibm_atracker_routes" "atracker_routes" { name = "my-route" } @@ -29,16 +29,21 @@ Review the argument reference that you can specify for your data source. In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the atracker_routes. -* `routes` - (Required, List) A list of route resources. +* `routes` - (List) A list of route resources. Nested scheme for **routes**: - * `id` - (Required, String) The uuid of the route resource. - * `name` - (Required, String) The name of the route. - * `crn` - (Required, String) The crn of the route resource. - * `version` - (Optional, Integer) The version of the route. - * `receive_global_events` - (Required, Boolean) Indicates whether or not all global events should be forwarded to this region. - * `rules` - (Required, List) The routing rules that will be evaluated in their order of the array. + * `api_version` - (Integer) The API version of the route. + * `crn` - (String) The crn of the route resource. + * `id` - (String) The uuid of the route resource. + * `name` - (String) The name of the route. + * `rules` - (List) The routing rules that will be evaluated in their order of the array. Once a rule is matched, the remaining rules in the route definition will be skipped. Nested scheme for **rules**: - * `target_ids` - (Required, List) The target ID List. Only 1 target id is supported. - * `created` - (Optional, String) The timestamp of the route creation time. - * `updated` - (Optional, String) The timestamp of the route last updated time. - + * `target_ids` - (List) The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions. + * Constraints: The list items must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `locations` - (List) Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *. + * Constraints: The list items must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `created_at` - (String) The timestamp of the route creation time. + * `updated_at` - (String) The timestamp of the route last updated time. + * `version` - (Integer) The version of the route. + * `created` - **DEPRECATED** (String) The timestamp of the route creation time. + * `updated` - **DEPRECATED** (String) The timestamp of the route last updated time. + * `receive_global_events` - **DEPRECATED** (Boolean) Indicates whether or not all global events should be forwarded to this region. diff --git a/website/docs/d/atracker_targets.html.markdown b/website/docs/d/atracker_targets.html.markdown index 28bd61613..4049ff27e 100644 --- a/website/docs/d/atracker_targets.html.markdown +++ b/website/docs/d/atracker_targets.html.markdown @@ -3,51 +3,71 @@ layout: "ibm" page_title: "IBM : ibm_atracker_targets" description: |- Get information about atracker_targets -subcategory: "Activity Tracker API" +subcategory: "Activity Tracker" --- # ibm_atracker_targets Provides a read-only data source for atracker_targets. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_atracker_targets" "atracker_targets" { name = "a-cos-target-us-south" } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. -* `name` - (Optional, String) The name of the target resource. +* `name` - (String) The name of the target resource. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the atracker_targets. -* `targets` - (Required, List) A list of target resources. +* `targets` - (List) A list of target resources. Nested scheme for **targets**: - * `id` - (Required, String) The uuid of the target resource. - * `name` - (Required, String) The name of the target resource. - * `crn` - (Required, String) The crn of the target resource. - * `target_type` - (Required, String) The type of the target. - * Constraints: Allowable values are: cloud_object_storage - * `encrypt_key` - (Optional, String) The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response. - * `cos_endpoint` - (Optional, List) Property values for a Cloud Object Storage Endpoint. + * `id` - (String) The uuid of the target resource. + * `name` - (String) The name of the target resource. + * `crn` - (String) The crn of the target resource. + * `target_type` - (String) The type of the target. + * Constraints: Allowable values are: `cloud_object_storage`, `logdna`. + * `encrypt_key` - (String) The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response. + * `region` - (String) Included this optional field if you used it to create a target in a different region other than the one you are connected. + * `cos_endpoint` - (List) Property values for a Cloud Object Storage Endpoint. Nested scheme for **cos_endpoint**: - * `endpoint` - (Required, String) The host name of the Cloud Object Storage endpoint. - * `target_crn` - (Required, String) The CRN of the Cloud Object Storage instance. - * `bucket` - (Required, String) The bucket name under the Cloud Object Storage instance. - * `api_key` - (Required, String) The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. - * `cos_write_status` - (Optional, List) The status of the write attempt with the provided cos_endpoint parameters. + * `api_key` - (String) The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `bucket` - (String) The bucket name under the Cloud Object Storage instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. + * `endpoint` - (String) The host name of the Cloud Object Storage endpoint. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `service_to_service_enabled` - (Boolean) ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey. + * `target_crn` - (String) The CRN of the Cloud Object Storage instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. + * `logdna_endpoint` - (List) Property values for a LogDNA Endpoint. + Nested scheme for **logdna_endpoint**: + * `ingestion_key` - (String) The LogDNA ingestion key is used for routing logs to a specific LogDNA instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. + * `target_crn` - (String) The CRN of the LogDNA instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. + * `write_status` - (List) The status of the write attempt to the target with the provided endpoint parameters. + Nested scheme for **write_status**: + * `last_failure` - (String) The timestamp of the failure. + * `reason_for_last_failure` - (String) Detailed description of the cause of the failure. + * `status` - (String) The status such as failed or success. + * `created_at` - (String) The timestamp of the target creation time. + * `updated_at` - (String) The timestamp of the target last updated time. + * `api_version` - (Integer) The API version of the target. + * `cos_write_status` - **DEPRECATED** (List) The status of the write attempt with the provided cos_endpoint parameters. Nested scheme for **cos_write_status**: - * `status` - (Optional, String) The status such as failed or success. - * `last_failure` - (Optional, String) The timestamp of the failure. - * `reason_for_last_failure` - (Optional, String) Detailed description of the cause of the failure. - * `created` - (Optional, String) The timestamp of the target creation time. - * `updated` - (Optional, String) The timestamp of the target last updated time. + * `status` - (String) The status such as failed or success. + * `last_failure` - (String) The timestamp of the failure. + * `reason_for_last_failure` - (String) Detailed description of the cause of the failure. + * `created` - **DEPRECATED** (String) The timestamp of the target creation time. + * `updated` - **DEPRECATED** (String) The timestamp of the target last updated time. diff --git a/website/docs/d/cbr_rule.html.markdown b/website/docs/d/cbr_rule.html.markdown new file mode 100644 index 000000000..07925ccca --- /dev/null +++ b/website/docs/d/cbr_rule.html.markdown @@ -0,0 +1,93 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cbr_rule" +description: |- + Get information about cbr_rule +subcategory: "Context Based Restrictions" +--- + +# ibm_cbr_rule + +Provides a read-only data source for cbr_rule. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cbr_rule" "cbr_rule" { + rule_id = "rule_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `rule_id` - (Required, Forces new resource, String) The ID of a rule. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[a-fA-F0-9]{32}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cbr_rule. +* `contexts` - (List) The contexts this rule applies to. + * Constraints: The maximum length is `1000` items. The minimum length is `1` item. +Nested scheme for **contexts**: + * `attributes` - (List) The attributes. + * Constraints: The minimum length is `1` item. + Nested scheme for **attributes**: + * `name` - (String) The attribute name. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (String) The attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[\S\s]+$/`. + +* `created_at` - (String) The time the resource was created. + +* `created_by_id` - (String) IAM ID of the user or service which created the resource. + +* `crn` - (String) The rule CRN. + +* `description` - (String) The description of the rule. + * Constraints: The maximum length is `300` characters. The minimum length is `0` characters. The value must match regular expression `/^[\x20-\xFE]*$/`. + +* `enforcement_mode` - (String) The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced. + * Constraints: The default value is `enabled`. Allowable values are: `enabled`, `disabled`, `report`. + +* `href` - (String) The href link to the resource. + +* `id` - (String) The globally unique ID of the rule. + +* `last_modified_at` - (String) The last time the resource was modified. + +* `last_modified_by_id` - (String) IAM ID of the user or service which modified the resource. + +* `operations` - (List) The operations this rule applies to. +Nested scheme for **operations**: + * `api_types` - (List) The API types this rule applies to. + * Constraints: The maximum length is `100` items. The minimum length is `1` item. + Nested scheme for **api_types**: + * `api_type_id` - (String) + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.\-:]+$/`. + +* `resources` - (List) The resources this rule apply to. + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **resources**: + * `attributes` - (List) The resource attributes. + * Constraints: The minimum length is `1` item. + Nested scheme for **attributes**: + * `name` - (String) The attribute name. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `operator` - (String) The attribute operator. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (String) The attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[\S\s]+$/`. + * `tags` - (List) The optional resource tags. + * Constraints: The maximum length is `10` items. The minimum length is `1` item. + Nested scheme for **tags**: + * `name` - (String) The tag attribute name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 _.-]+$/`. + * `operator` - (String) The attribute operator. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (String) The tag attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 _*?.-]+$/`. + diff --git a/website/docs/d/cbr_zone.html.markdown b/website/docs/d/cbr_zone.html.markdown new file mode 100644 index 000000000..e91a07c49 --- /dev/null +++ b/website/docs/d/cbr_zone.html.markdown @@ -0,0 +1,99 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cbr_zone" +description: |- + Get information about cbr_zone +subcategory: "Context Based Restrictions" +--- + +# ibm_cbr_zone + +Provides a read-only data source for cbr_zone. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cbr_zone" "cbr_zone" { + zone_id = "zone_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `zone_id` - (Required, Forces new resource, String) The ID of a zone. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[a-fA-F0-9]{32}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cbr_zone. +* `account_id` - (String) The id of the account owning this zone. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. + +* `address_count` - (Integer) The number of addresses in the zone. + +* `addresses` - (List) The list of addresses in the zone. + * Constraints: The maximum length is `1000` items. The minimum length is `1` item. +Nested scheme for **addresses**: + * `ref` - (List) A service reference value. + Nested scheme for **ref**: + * `account_id` - (String) The id of the account owning the service. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. + * `location` - (String) The location. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_instance` - (String) The service instance. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-/]+$/`. + * `service_name` - (String) The service name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_type` - (String) The service type. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z_]+$/`. + * `type` - (String) The type of address. + * Constraints: Allowable values are: `ipAddress`, `ipRange`, `subnet`, `vpc`, `serviceRef`. + * `value` - (String) The IP address. + * Constraints: The maximum length is `45` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9:.]+$/`. + +* `created_at` - (String) The time the resource was created. + +* `created_by_id` - (String) IAM ID of the user or service which created the resource. + +* `crn` - (String) The zone CRN. + +* `description` - (String) The description of the zone. + * Constraints: The maximum length is `300` characters. The minimum length is `0` characters. The value must match regular expression `/^[\x20-\xFE]*$/`. + +* `excluded` - (List) The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded. + * Constraints: The maximum length is `1000` items. +Nested scheme for **excluded**: + * `ref` - (List) A service reference value. + Nested scheme for **ref**: + * `account_id` - (String) The id of the account owning the service. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. + * `location` - (String) The location. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_instance` - (String) The service instance. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-/]+$/`. + * `service_name` - (String) The service name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_type` - (String) The service type. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z_]+$/`. + * `type` - (String) The type of address. + * Constraints: Allowable values are: `ipAddress`, `ipRange`, `subnet`, `vpc`, `serviceRef`. + * `value` - (String) The IP address. + * Constraints: The maximum length is `45` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9:.]+$/`. + +* `excluded_count` - (Integer) The number of excluded addresses in the zone. + +* `href` - (String) The href link to the resource. + +* `id` - (String) The globally unique ID of the zone. + +* `last_modified_at` - (String) The last time the resource was modified. + +* `last_modified_by_id` - (String) IAM ID of the user or service which modified the resource. + +* `name` - (String) The name of the zone. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 \-_]+$/`. + diff --git a/website/docs/d/cd_tekton_pipeline.html.markdown b/website/docs/d/cd_tekton_pipeline.html.markdown new file mode 100644 index 000000000..b7d31853a --- /dev/null +++ b/website/docs/d/cd_tekton_pipeline.html.markdown @@ -0,0 +1,182 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline" +description: |- + Get information about cd_tekton_pipeline +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline + +Provides a read-only data source for cd_tekton_pipeline. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_tekton_pipeline" "cd_tekton_pipeline" { + pipeline_id = "94619026-912b-4d92-8f51-6c74f0692d90" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `pipeline_id` - (Required, Forces new resource, String) ID of current instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_tekton_pipeline. +* `build_number` - (Integer) The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs. + * Constraints: The minimum value is `1`. + +* `created_at` - (String) Standard RFC 3339 Date Time String. + +* `definitions` - (List) Definition list. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **definitions**: + * `id` - (String) UUID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `scm_source` - (List) SCM source for Tekton pipeline definition. + Nested scheme for **scm_source**: + * `branch` - (String) A branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `path` - (String) The path to the definition's yaml files. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `service_instance_id` - (String) ID of the SCM repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `tag` - (String) A tag from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]{1,235}$/`. + * `url` - (Forces new resource, String) URL of the definition repository. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `enable_partial_cloning` - (Boolean) Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work. + +* `enable_slack_notifications` - (Boolean) Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain. + +* `enabled` - (Boolean) Flag whether this pipeline is enabled. + +* `name` - (String) String. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. + +* `properties` - (List) Tekton pipeline's environment properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed when using `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +* `resource_group_id` - (String) ID. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]+$/`. + +* `runs_url` - (String) URL for this pipeline showing the list of pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `status` - (String) Pipeline status. + * Constraints: Allowable values are: `configured`, `configuring`. + +* `toolchain` - (List) Toolchain object. +Nested scheme for **toolchain**: + * `crn` - (String) The CRN for the toolchain that contains the Tekton pipeline. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + * `id` - (String) UUID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +* `triggers` - (List) Tekton pipeline triggers list. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **triggers**: + * `cron` - (String) Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. The value must match regular expression `/^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\/([0-6]))$/`. + * `disabled` - (Boolean) Flag whether the trigger is disabled. If omitted the trigger is enabled by default. + * `event_listener` - (String) Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `events` - (List) Only needed for Git triggers. Events object defines the events to which this Git trigger listens. + Nested scheme for **events**: + * `pull_request` - (Boolean) If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events. + * `pull_request_closed` - (Boolean) If true, the trigger listens for 'close pull request' Git webhook events. + * `push` - (Boolean) If true, the trigger listens for 'push' Git webhook events. + * `href` - (String) API URL for interacting with the trigger. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `id` - (String) ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `max_concurrent_runs` - (Integer) Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit. + * `name` - (String) Trigger name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. + * `properties` - (List) Trigger properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. + Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `href` - (String) API URL for interacting with the trigger property. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. Can be empty and should be omitted for `single_select` property type. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `scm_source` - (List) SCM source repository for a Git trigger. Only needed for Git triggers. + Nested scheme for **scm_source**: + * `blind_connection` - (Boolean) True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * `branch` - (String) Name of a branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `hook_id` - (String) ID of the webhook from the repo. Computed upon creation of the trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `pattern` - (String) Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^.{1,235}$/`. + * `service_instance_id` - (String) ID of the repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `url` - (Forces new resource, String) URL of the repository to which the trigger is listening. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `secret` - (List) Only needed for generic webhook trigger type. Secret used to start generic webhook trigger. + Nested scheme for **secret**: + * `algorithm` - (String) Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type. + * Constraints: Allowable values are: `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256`, `ripemd160`. + * `key_name` - (String) Secret name, not needed if type is `internal_validation`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `source` - (String) Secret location, not needed if secret type is `internal_validation`. + * Constraints: Allowable values are: `header`, `payload`, `query`. + * `type` - (String) Secret type. + * Constraints: Allowable values are: `token_matches`, `digest_matches`, `internal_validation`. + * `value` - (String) Secret value, not needed if secret type is `internal_validation`. + * Constraints: The maximum length is `4096` characters. The minimum length is `0` characters. The value must match regular expression `/./`. + * `tags` - (List) Trigger tags array. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `timezone` - (String) Only needed for timer triggers. Timezone for timer trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_., \/]{1,234}$/`. + * `type` - (String) Trigger type. + * Constraints: Allowable values are: . + * `webhook_url` - (String) Webhook URL that can be used to trigger pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `worker` - (List) Worker used to run the trigger. If not specified the trigger will use the default pipeline worker. + Nested scheme for **worker**: + * `id` - (Forces new resource, String) ID of the worker. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + * `name` - (String) Name of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_. \\(\\)\\[\\]]{1,235}$/`. + * `type` - (String) Type of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + +* `updated_at` - (String) Standard RFC 3339 Date Time String. + +* `worker` - (List) Default pipeline worker used to run the pipeline. +Nested scheme for **worker**: + * `id` - (Forces new resource, String) ID of the worker. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + * `name` - (String) Name of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_. \\(\\)\\[\\]]{1,235}$/`. + * `type` - (String) Type of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + diff --git a/website/docs/d/cd_tekton_pipeline_definition.html.markdown b/website/docs/d/cd_tekton_pipeline_definition.html.markdown new file mode 100644 index 000000000..441f471e8 --- /dev/null +++ b/website/docs/d/cd_tekton_pipeline_definition.html.markdown @@ -0,0 +1,48 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_definition" +description: |- + Get information about cd_tekton_pipeline_definition +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_definition + +Provides a read-only data source for cd_tekton_pipeline_definition. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition" { + definition_id = ibm_cd_tekton_pipeline_definition.cd_tekton_pipeline_definition.definition_id + pipeline_id = ibm_cd_tekton_pipeline_definition.cd_tekton_pipeline_definition.pipeline_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `definition_id` - (Required, Forces new resource, String) The definition ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_definition. +* `scm_source` - (List) SCM source for Tekton pipeline definition. +Nested scheme for **scm_source**: + * `branch` - (String) A branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `path` - (String) The path to the definition's yaml files. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `service_instance_id` - (String) ID of the SCM repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `tag` - (String) A tag from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]{1,235}$/`. + * `url` - (Forces new resource, String) URL of the definition repository. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + diff --git a/website/docs/d/cd_tekton_pipeline_property.html.markdown b/website/docs/d/cd_tekton_pipeline_property.html.markdown new file mode 100644 index 000000000..163d9a73c --- /dev/null +++ b/website/docs/d/cd_tekton_pipeline_property.html.markdown @@ -0,0 +1,50 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_property" +description: |- + Get information about cd_tekton_pipeline_property +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_property + +Provides a read-only data source for cd_tekton_pipeline_property. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_tekton_pipeline_property" "cd_tekton_pipeline_property" { + pipeline_id = ibm_cd_tekton_pipeline_property.cd_tekton_pipeline_property.pipeline_id + property_name = "debug-pipeline" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `property_name` - (Required, Forces new resource, String) The property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_property. +* `enum` - (List) Options for `single_select` property type. Only needed when using `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + +* `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + +* `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +* `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + +* `value` - (String) Property value. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + diff --git a/website/docs/d/cd_tekton_pipeline_trigger.html.markdown b/website/docs/d/cd_tekton_pipeline_trigger.html.markdown new file mode 100644 index 000000000..838245099 --- /dev/null +++ b/website/docs/d/cd_tekton_pipeline_trigger.html.markdown @@ -0,0 +1,121 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_trigger" +description: |- + Get information about cd_tekton_pipeline_trigger +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_trigger + +Provides a read-only data source for cd_tekton_pipeline_trigger. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger" { + pipeline_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger.pipeline_id + trigger_id = ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger.trigger_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `trigger_id` - (Required, Forces new resource, String) The trigger ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_trigger. +* `cron` - (String) Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. The value must match regular expression `/^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\/([0-6]))$/`. + +* `disabled` - (Boolean) Flag whether the trigger is disabled. If omitted the trigger is enabled by default. + +* `event_listener` - (String) Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + +* `events` - (List) Only needed for Git triggers. Events object defines the events to which this Git trigger listens. +Nested scheme for **events**: + * `pull_request` - (Boolean) If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events. + * `pull_request_closed` - (Boolean) If true, the trigger listens for 'close pull request' Git webhook events. + * `push` - (Boolean) If true, the trigger listens for 'push' Git webhook events. + +* `href` - (String) API URL for interacting with the trigger. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `max_concurrent_runs` - (Integer) Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit. + +* `name` - (String) Trigger name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. + +* `properties` - (List) Trigger properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `href` - (String) API URL for interacting with the trigger property. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. Can be empty and should be omitted for `single_select` property type. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +* `scm_source` - (List) SCM source repository for a Git trigger. Only needed for Git triggers. +Nested scheme for **scm_source**: + * `blind_connection` - (Boolean) True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * `branch` - (String) Name of a branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `hook_id` - (String) ID of the webhook from the repo. Computed upon creation of the trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `pattern` - (String) Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^.{1,235}$/`. + * `service_instance_id` - (String) ID of the repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `url` - (Forces new resource, String) URL of the repository to which the trigger is listening. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `secret` - (List) Only needed for generic webhook trigger type. Secret used to start generic webhook trigger. +Nested scheme for **secret**: + * `algorithm` - (String) Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type. + * Constraints: Allowable values are: `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256`, `ripemd160`. + * `key_name` - (String) Secret name, not needed if type is `internal_validation`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `source` - (String) Secret location, not needed if secret type is `internal_validation`. + * Constraints: Allowable values are: `header`, `payload`, `query`. + * `type` - (String) Secret type. + * Constraints: Allowable values are: `token_matches`, `digest_matches`, `internal_validation`. + * `value` - (String) Secret value, not needed if secret type is `internal_validation`. + * Constraints: The maximum length is `4096` characters. The minimum length is `0` characters. The value must match regular expression `/./`. + +* `tags` - (List) Trigger tags array. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + +* `timezone` - (String) Only needed for timer triggers. Timezone for timer trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_., \/]{1,234}$/`. + +* `type` - (String) Trigger type. + * Constraints: Allowable values are: . + +* `webhook_url` - (String) Webhook URL that can be used to trigger pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `worker` - (List) Worker used to run the trigger. If not specified the trigger will use the default pipeline worker. +Nested scheme for **worker**: + * `id` - (Forces new resource, String) ID of the worker. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + * `name` - (String) Name of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_. \\(\\)\\[\\]]{1,235}$/`. + * `type` - (String) Type of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + diff --git a/website/docs/d/cd_tekton_pipeline_trigger_property.html.markdown b/website/docs/d/cd_tekton_pipeline_trigger_property.html.markdown new file mode 100644 index 000000000..3a288c396 --- /dev/null +++ b/website/docs/d/cd_tekton_pipeline_trigger_property.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_trigger_property" +description: |- + Get information about cd_tekton_pipeline_trigger_property +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_trigger_property + +Provides a read-only data source for cd_tekton_pipeline_trigger_property. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property" { + pipeline_id = ibm_cd_tekton_pipeline_trigger_property.cd_tekton_pipeline_trigger_property.pipeline_id + property_name = "debug-pipeline" + trigger_id = ibm_cd_tekton_pipeline_trigger_property.cd_tekton_pipeline_trigger_property.trigger_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `property_name` - (Required, Forces new resource, String) The property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. +* `trigger_id` - (Required, Forces new resource, String) The trigger ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_trigger_property. +* `enum` - (List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + +* `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + +* `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +* `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + +* `value` - (String) Property value. Can be empty and should be omitted for `single_select` property type. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + diff --git a/website/docs/d/cd_toolchain.html.markdown b/website/docs/d/cd_toolchain.html.markdown new file mode 100644 index 000000000..fd538c1fe --- /dev/null +++ b/website/docs/d/cd_toolchain.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain" +description: |- + Get information about cd_toolchain +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain" "cd_toolchain" { + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain. +* `account_id` - (String) Account ID where toolchain can be found. + +* `created_at` - (String) Toolchain creation timestamp. + +* `created_by` - (String) Identity that created the toolchain. + +* `crn` - (String) Toolchain CRN. + +* `description` - (String) Toolchain description. + +* `href` - (String) URI that can be used to retrieve toolchain. + +* `location` - (String) Toolchain region. + +* `name` - (String) Toolchain name. + * Constraints: The maximum length is `128` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. + +* `resource_group_id` - (String) Resource group where toolchain can be found. + +* `tags` - (List) Tags associated with the toolchain. + +* `updated_at` - (String) Latest toolchain update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_appconfig.html.markdown b/website/docs/d/cd_toolchain_tool_appconfig.html.markdown new file mode 100644 index 000000000..4c5a8d5e4 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_appconfig.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_appconfig" +description: |- + Get information about cd_toolchain_tool_appconfig +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_appconfig + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_appconfig. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_appconfig. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `collection_name` - (String) App Configuration collection. + * Constraints: The value must match regular expression `/\\S/`. + * `environment_name` - (String) App Configuration environment. + * Constraints: The value must match regular expression `/\\S/`. + * `instance_name` - (String) The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (String) Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain. + * `region` - (String) Region. + * `resource_group` - (String) Resource group. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_artifactory.html.markdown b/website/docs/d/cd_toolchain_tool_artifactory.html.markdown new file mode 100644 index 000000000..1249bf33a --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_artifactory.html.markdown @@ -0,0 +1,72 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_artifactory" +description: |- + Get information about cd_toolchain_tool_artifactory +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_artifactory + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_artifactory. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_artifactory. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `dashboard_url` - (String) Type the URL that you want to navigate to when you click the Artifactory integration tile. + * `mirror_url` - (String) Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories. + * `name` - (String) Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain. + * `release_url` - (String) Type the URL for your Artifactory release repository. + * `repository_name` - (String) Type the name of your artifactory repository where your docker images are located. + * `repository_url` - (String) Type the URL of your artifactory repository where your docker images are located. + * `snapshot_url` - (String) Type the URL for your Artifactory snapshot repository. + * `token` - (String) Type the API key for your Artifactory repository. + * `type` - (String) Choose the type of repository for your Artifactory integration. + * Constraints: Allowable values are: `npm`, `maven`, `docker`. + * `user_id` - (String) Type the User ID or email for your Artifactory repository. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_bitbucketgit.html.markdown b/website/docs/d/cd_toolchain_tool_bitbucketgit.html.markdown new file mode 100644 index 000000000..8d4170965 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_bitbucketgit.html.markdown @@ -0,0 +1,77 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_bitbucketgit" +description: |- + Get information about cd_toolchain_tool_bitbucketgit +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_bitbucketgit + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_bitbucketgit. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_bitbucketgit" "cd_toolchain_tool_bitbucketgit" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_bitbucketgit.cd_toolchain_tool_bitbucketgit.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_bitbucketgit. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (String) e.g. https://api.bitbucket.org. + * `enable_traceability` - (Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (String) + * `has_issues` - (Boolean) Select this check box to enable Bitbucket Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (String) Select the user which git operations will be performed as. + * `owner_id` - (String) + * `private_repo` - (Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (String) + * `repo_url` - (String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (String) Integration token URL. + * `type` - (String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_custom.html.markdown b/website/docs/d/cd_toolchain_tool_custom.html.markdown new file mode 100644 index 000000000..9d63dec59 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_custom.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_custom" +description: |- + Get information about cd_toolchain_tool_custom +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_custom + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_custom. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_custom" "cd_toolchain_tool_custom" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_custom.cd_toolchain_tool_custom.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_custom. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `additional_properties` - (String) (Advanced) Type any information that is needed to integrate with other tools in your toolchain. + * `dashboard_url` - (String) Type the URL that you want to navigate to when you click the tool integration card. + * `description` - (String) Type a description for the tool instance. + * `documentation_url` - (String) Type the URL for your tool's documentation. + * `image_url` - (String) Type the URL of the icon to show on your tool integration's card. + * `lifecycle_phase` - (String) Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool. + * Constraints: Allowable values are: `THINK`, `CODE`, `DELIVER`, `RUN`, `MANAGE`, `LEARN`, `CULTURE`. + * `name` - (String) Type a name for this specific tool integration; for example: My Build and Deploy Pipeline. + * `type` - (String) Type the name of the tool that you are integrating; for example: Delivery Pipeline. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_devopsinsights.html.markdown b/website/docs/d/cd_toolchain_tool_devopsinsights.html.markdown new file mode 100644 index 000000000..a3169fbb1 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_devopsinsights.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_devopsinsights" +description: |- + Get information about cd_toolchain_tool_devopsinsights +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_devopsinsights + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_devopsinsights. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_devopsinsights" "cd_toolchain_tool_devopsinsights" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_devopsinsights.cd_toolchain_tool_devopsinsights.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_devopsinsights. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_githubconsolidated.html.markdown b/website/docs/d/cd_toolchain_tool_githubconsolidated.html.markdown new file mode 100644 index 000000000..5aff4301b --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_githubconsolidated.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_githubconsolidated" +description: |- + Get information about cd_toolchain_tool_githubconsolidated +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_githubconsolidated + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_githubconsolidated. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_githubconsolidated" "cd_toolchain_tool_githubconsolidated" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_githubconsolidated.cd_toolchain_tool_githubconsolidated.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_githubconsolidated. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (String) e.g. https://api.github.example.com. + * `auto_init` - (Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `enable_traceability` - (Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (String) + * `has_issues` - (Boolean) Select this check box to enable GitHub Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (String) Select the user which git operations will be performed as. + * `owner_id` - (String) + * `private_repo` - (Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (String) + * `repo_url` - (String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (String) Integration token URL. + * `type` - (String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_githubintegrated.html.markdown b/website/docs/d/cd_toolchain_tool_githubintegrated.html.markdown new file mode 100644 index 000000000..d6f1faa2a --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_githubintegrated.html.markdown @@ -0,0 +1,81 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_githubintegrated" +description: |- + Get information about cd_toolchain_tool_githubintegrated +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_githubintegrated + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_githubintegrated. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_githubintegrated" "cd_toolchain_tool_githubintegrated" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_githubintegrated.cd_toolchain_tool_githubintegrated.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_githubintegrated. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (String) e.g. https://github.ibm.com/api/v3. + * `auto_init` - (Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `enable_traceability` - (Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (String) + * `has_issues` - (Boolean) Select this check box to enable GitHub Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (String) Select the user which git operations will be performed as. + * `legal` - (Boolean) + * Constraints: The default value is `false`. + * `owner_id` - (String) + * `private_repo` - (Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (String) + * `repo_url` - (String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (String) Integration token URL. + * `type` - (String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_gitlab.html.markdown b/website/docs/d/cd_toolchain_tool_gitlab.html.markdown new file mode 100644 index 000000000..eb291d503 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_gitlab.html.markdown @@ -0,0 +1,77 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_gitlab" +description: |- + Get information about cd_toolchain_tool_gitlab +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_gitlab + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_gitlab. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_gitlab" "cd_toolchain_tool_gitlab" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_gitlab.cd_toolchain_tool_gitlab.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_gitlab. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (String) e.g. https://gitlab.example.com/api/v4. + * `enable_traceability` - (Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (String) + * `has_issues` - (Boolean) Select this check box to enable GitLab Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (String) Select the user which git operations will be performed as. + * `owner_id` - (String) + * `private_repo` - (Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (String) + * `repo_url` - (String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (String) Integration token URL. + * `type` - (String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_hashicorpvault.html.markdown b/website/docs/d/cd_toolchain_tool_hashicorpvault.html.markdown new file mode 100644 index 000000000..df2a46dec --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_hashicorpvault.html.markdown @@ -0,0 +1,74 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_hashicorpvault" +description: |- + Get information about cd_toolchain_tool_hashicorpvault +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_hashicorpvault + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_hashicorpvault. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_hashicorpvault" "cd_toolchain_tool_hashicorpvault" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_hashicorpvault.cd_toolchain_tool_hashicorpvault.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_hashicorpvault. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `authentication_method` - (String) Choose the authentication method for your HashiCorp Vault instance. + * Constraints: Allowable values are: `token`, `approle`, `userpass`, `github`. + * `dashboard_url` - (String) Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile. + * `default_secret` - (String) Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance. + * `name` - (String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `password` - (String) Type or select the authentication password for your HashiCorp Vault instance. + * `path` - (String) Type the mount path where your secrets are stored in your HashiCorp Vault instance. + * `role_id` - (String) Type or select the authentication role ID for your HashiCorp Vault instance. + * `secret_filter` - (String) Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance. + * `secret_id` - (String) Type or select the authentication secret ID for your HashiCorp Vault instance. + * `server_url` - (String) Type the server URL for your HashiCorp Vault instance. + * `token` - (String) Type or select the authentication token for your HashiCorp Vault instance. + * `username` - (String) Type or select the authentication username for your HashiCorp Vault instance. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_hostedgit.html.markdown b/website/docs/d/cd_toolchain_tool_hostedgit.html.markdown new file mode 100644 index 000000000..7af2730bd --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_hostedgit.html.markdown @@ -0,0 +1,77 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_hostedgit" +description: |- + Get information about cd_toolchain_tool_hostedgit +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_hostedgit + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_hostedgit. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_hostedgit" "cd_toolchain_tool_hostedgit" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_hostedgit.cd_toolchain_tool_hostedgit.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_hostedgit. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (String) e.g. https://gitlab.example.com/api/v4. + * `enable_traceability` - (Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (String) + * `has_issues` - (Boolean) Select this check box to enable Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (String) Select the user which git operations will be performed as. + * `owner_id` - (String) + * `private_repo` - (Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (String) + * `repo_url` - (String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (String) Integration token URL. + * `type` - (String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_jenkins.html.markdown b/website/docs/d/cd_toolchain_tool_jenkins.html.markdown new file mode 100644 index 000000000..9b7e00758 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_jenkins.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_jenkins" +description: |- + Get information about cd_toolchain_tool_jenkins +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_jenkins + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_jenkins. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_jenkins" "cd_toolchain_tool_jenkins" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_jenkins.cd_toolchain_tool_jenkins.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_jenkins. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_token` - (String) Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance. + * `api_user_name` - (String) Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance. + * `dashboard_url` - (String) Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain. + * `name` - (String) Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain. + * `webhook_url` - (String) Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_keyprotect.html.markdown b/website/docs/d/cd_toolchain_tool_keyprotect.html.markdown new file mode 100644 index 000000000..d62c0fa6d --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_keyprotect.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_keyprotect" +description: |- + Get information about cd_toolchain_tool_keyprotect +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_keyprotect + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_keyprotect. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_keyprotect" "cd_toolchain_tool_keyprotect" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_keyprotect.cd_toolchain_tool_keyprotect.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_keyprotect. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `instance_name` - (String) The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `region` - (String) Region. + * `resource_group` - (String) Resource group. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_nexus.html.markdown b/website/docs/d/cd_toolchain_tool_nexus.html.markdown new file mode 100644 index 000000000..8095bd873 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_nexus.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_nexus" +description: |- + Get information about cd_toolchain_tool_nexus +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_nexus + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_nexus. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_nexus" "cd_toolchain_tool_nexus" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_nexus.cd_toolchain_tool_nexus.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_nexus. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `dashboard_url` - (String) Type the URL that you want to navigate to when you click the Nexus integration tile. + * `mirror_url` - (String) Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories. + * `name` - (String) Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain. + * `release_url` - (String) Type the URL for your Nexus release repository. + * `snapshot_url` - (String) Type the URL for your Nexus snapshot repository. + * `token` - (String) Type the password or authentication token for your Nexus repository. + * `type` - (String) Choose the type of repository for your Nexus integration. + * Constraints: Allowable values are: `npm`, `maven`. + * `user_id` - (String) Type the User ID or email for your Nexus repository. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_pagerduty.html.markdown b/website/docs/d/cd_toolchain_tool_pagerduty.html.markdown new file mode 100644 index 000000000..5f800eb3d --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_pagerduty.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_pagerduty" +description: |- + Get information about cd_toolchain_tool_pagerduty +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_pagerduty + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_pagerduty. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_pagerduty" "cd_toolchain_tool_pagerduty" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_pagerduty.cd_toolchain_tool_pagerduty.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_pagerduty. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_key` - (String) Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key). + * `key_type` - (String) Select whether to integrate at the account level with an API key or at the service level with an integration key. + * Constraints: Allowable values are: `api`, `service`. + * `service_id` - (String) service_id. + * `service_key` - (String) Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page. + * `service_name` - (String) Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service. + * `service_url` - (String) Type the URL of the PagerDuty service to post alerts to. + * `user_email` - (String) Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user. + * `user_phone` - (String) Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_pipeline.html.markdown b/website/docs/d/cd_toolchain_tool_pipeline.html.markdown new file mode 100644 index 000000000..5b71d6fbb --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_pipeline.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_pipeline" +description: |- + Get information about cd_toolchain_tool_pipeline +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_pipeline + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_pipeline. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_pipeline" "cd_toolchain_tool_pipeline" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_pipeline. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `name` - (String) + * `type` - (String) + * Constraints: Allowable values are: `classic`, `tekton`. + * `ui_pipeline` - (Boolean) When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser. + * Constraints: The default value is `false`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_privateworker.html.markdown b/website/docs/d/cd_toolchain_tool_privateworker.html.markdown new file mode 100644 index 000000000..7e8bd5690 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_privateworker.html.markdown @@ -0,0 +1,64 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_privateworker" +description: |- + Get information about cd_toolchain_tool_privateworker +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_privateworker + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_privateworker. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_privateworker" "cd_toolchain_tool_privateworker" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_privateworker.cd_toolchain_tool_privateworker.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_privateworker. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `name` - (String) Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain. + * `worker_queue_credentials` - (String) Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue. + * `worker_queue_identifier` - (String) + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_saucelabs.html.markdown b/website/docs/d/cd_toolchain_tool_saucelabs.html.markdown new file mode 100644 index 000000000..c864618bc --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_saucelabs.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_saucelabs" +description: |- + Get information about cd_toolchain_tool_saucelabs +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_saucelabs + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_saucelabs. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_saucelabs" "cd_toolchain_tool_saucelabs" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_saucelabs.cd_toolchain_tool_saucelabs.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_saucelabs. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `key` - (String) Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page. + * `username` - (String) Type the user name for your Sauce Labs account. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_secretsmanager.html.markdown b/website/docs/d/cd_toolchain_tool_secretsmanager.html.markdown new file mode 100644 index 000000000..e9f564b25 --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_secretsmanager.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_secretsmanager" +description: |- + Get information about cd_toolchain_tool_secretsmanager +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_secretsmanager + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_secretsmanager. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_secretsmanager" "cd_toolchain_tool_secretsmanager" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_secretsmanager.cd_toolchain_tool_secretsmanager.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_secretsmanager. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `instance_name` - (String) The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `region` - (String) Region. + * `resource_group` - (String) Resource group. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_securitycompliance.html.markdown b/website/docs/d/cd_toolchain_tool_securitycompliance.html.markdown new file mode 100644 index 000000000..28d591d2f --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_securitycompliance.html.markdown @@ -0,0 +1,72 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_securitycompliance" +description: |- + Get information about cd_toolchain_tool_securitycompliance +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_securitycompliance + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_securitycompliance. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_securitycompliance" "cd_toolchain_tool_securitycompliance" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_securitycompliance.cd_toolchain_tool_securitycompliance.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_securitycompliance. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_key` - (String) The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once). + * Constraints: The value must match regular expression `/\\S/`. + * `evidence_namespace` - (String) The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence. + * `evidence_repo_name` - (String) To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker. + * `location` - (String) + * `name` - (String) Give this tool integration a name, for example: my-security-compliance. + * `profile` - (String) Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg). + * `scope` - (String) Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg). + * `trigger_info` - (Map) trigger_info. + * `trigger_scan` - (String) Enabling trigger validation scans provides details for a pipeline task to trigger a scan. + * Constraints: Allowable values are: `disabled`, `enabled`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_slack.html.markdown b/website/docs/d/cd_toolchain_tool_slack.html.markdown new file mode 100644 index 000000000..d68c7253a --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_slack.html.markdown @@ -0,0 +1,74 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_slack" +description: |- + Get information about cd_toolchain_tool_slack +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_slack + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_slack. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_slack" "cd_toolchain_tool_slack" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_slack.cd_toolchain_tool_slack.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_slack. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_token` - (String) Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead. + * `channel_name` - (String) If you use a webhook, you must specify an existing Slack channel to post notifications to. + * `pipeline_fail` - (Boolean) + * Constraints: The default value is `true`. + * `pipeline_start` - (Boolean) + * Constraints: The default value is `true`. + * `pipeline_success` - (Boolean) + * Constraints: The default value is `true`. + * `team_url` - (String) If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_. + * `toolchain_bind` - (Boolean) + * Constraints: The default value is `true`. + * `toolchain_unbind` - (Boolean) + * Constraints: The default value is `true`. + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cd_toolchain_tool_sonarqube.html.markdown b/website/docs/d/cd_toolchain_tool_sonarqube.html.markdown new file mode 100644 index 000000000..d5978659f --- /dev/null +++ b/website/docs/d/cd_toolchain_tool_sonarqube.html.markdown @@ -0,0 +1,67 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_sonarqube" +description: |- + Get information about cd_toolchain_tool_sonarqube +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_sonarqube + +~> **Beta:** This data source is in Beta, and is subject to change. + +Provides a read-only data source for cd_toolchain_tool_sonarqube. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cd_toolchain_tool_sonarqube" "cd_toolchain_tool_sonarqube" { + tool_id = "tool_id" + toolchain_id = ibm_cd_toolchain_tool_sonarqube.cd_toolchain_tool_sonarqube.toolchain_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `tool_id` - (Required, Forces new resource, String) ID of the tool bound to the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cd_toolchain_tool_sonarqube. +* `crn` - (String) Tool CRN. + +* `href` - (String) URI representing the tool. + +* `name` - (String) Tool name. + +* `parameters` - (List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `blind_connection` - (Boolean) Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * Constraints: The default value is `false`. + * `dashboard_url` - (String) Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain. + * `name` - (String) Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain. + * `user_login` - (String) If you are using an authentication token, leave this field empty. + * `user_password` - (String) + +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. + +* `resource_group_id` - (String) Resource group where tool can be found. + +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. + +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. + + +* `updated_at` - (String) Latest tool update timestamp. + diff --git a/website/docs/d/cis.html.markdown b/website/docs/d/cis.html.markdown index 3c5d43708..7c568bc09 100644 --- a/website/docs/d/cis.html.markdown +++ b/website/docs/d/cis.html.markdown @@ -22,6 +22,7 @@ data "ibm_cis" "cis_instance" { Review the argument references that you can specify for your data source. - `name` - (Required, String) The name of a CIS instance. +- `resource_group_id` - (Optional, String) The ID of the resource group where you want to create the service. You can retrieve the value from data source `ibm_resource_group`. If not provided creates the service in default resource group. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. @@ -30,4 +31,5 @@ In addition to the argument reference list, you can access the following attribu - `id` - (String) The CRN of your instance. - `location` - (String) The location of your instance. - `plan` - (String) The service plan for the instance. -- `status` - (String) The status of your instance. \ No newline at end of file +* `service` - (String) The service type of the instance. +* `status` - (String) Status of the resource instance. \ No newline at end of file diff --git a/website/docs/d/cis_alerts.html.markdown b/website/docs/d/cis_alerts.html.markdown new file mode 100644 index 000000000..8beceef73 --- /dev/null +++ b/website/docs/d/cis_alerts.html.markdown @@ -0,0 +1,40 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_alerts" +description: |- + Get information on an IBM Cloud Internet Services alerts. +--- + +# ibm_cis_alerts + +Retrieve information about an IBM Cloud Internet Services alerts data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_alerts" "tests" { + cis_id = ibm_cis.instance.id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The Webhook ID. It is a combination of <`policy_id`>,<`cis_id`> attributes concatenated with ":" +- `alert_policies` - (List) + - `policy_id` - (String) The Alert Policy ID. + - `name` - (String) The name of Alert policies. + - `description` - (String) Description of the Alert Policies. + - `enabled` - (Boolean) Whether this alert policies is active or not. + - `alert_type` - (String) Type of the Alert Policy. + - `mechanisms` - (List) Delivery mechanisms for the alert. + - `filters` - (String) Optional filters depending for the alert type. + - `conditions` - (String) Optional conditions depending for the alert type + diff --git a/website/docs/d/cis_auth_origin.html.markdown b/website/docs/d/cis_auth_origin.html.markdown new file mode 100644 index 000000000..54afc92b3 --- /dev/null +++ b/website/docs/d/cis_auth_origin.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_origin_auths" +description: |- + Get information on an IBM Cloud Internet Services Authentication Origin APIs. +--- + +# ibm_cis_origin_auths + +Retrieve information about an IBM Cloud Internet Services authentication Origin data sources for both Zone level and per hostname. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_origin_auths" "tests" { + cis_id = ibm_cis.instance.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. +- `domain_id` - (Required, String) The Domain ID of the CIS service instance. +- `request_type` - (Optional, String) The type of request made. Can be `zone_level` or `per_hostname`. Default value :`zone_level`. +- `hostname` - (Optional, String) The Hostname of the CIS service instance. Only needed when `request_type = per_hostname`. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The ID of the CIS service instance. +- `domain_id` - (String) The Domain ID of the CIS service instance. +- `request_type` - (String) The type of request made. Can be `zone_level` or `per_hostname`. Default value :`zone_level`. +- `hostname` - (String) The Hostname of the CIS service instance. Only needed when `request_type = per_hostname`. +- `origin_pull_settings_enabled` - (Bool) True if the Authentication Origin Settings are enabled. +- `origin_pull_certs_list` - (List) + - `cert_id` - (String) The Auth Origin Certificate ID. + - `certificate` - (String) The Auth Origin Certificate Detail. + - `cert_issuer` - (String) The Auth Origin Certificate Issuer. + - `cert_signature` - (Boolean) The Auth Origin Certificate Signature. + - `cert_status` - (String) The Auth Origin Certificate Status + - `cert_expires_on` - (String) The Auth Origin Certificate Expires On. + - `cert_uploaded_on` - (String) The Auth Origin Certificate Uploaded On. + - `cert_serial_number` - (String) The Auth Origin Certificate Serial Number. + diff --git a/website/docs/d/cis_domain.html.markdown b/website/docs/d/cis_domain.html.markdown index 0a77d49c6..cfa57bde9 100644 --- a/website/docs/d/cis_domain.html.markdown +++ b/website/docs/d/cis_domain.html.markdown @@ -37,4 +37,5 @@ In addition to all argument reference list, you can access the following attribu - `name_servers` - (String) The IBM Cloud Internet Services assigned name servers, to be passed by interpolation to the resource dns_domain_registration_nameservers. - `original_name_servers` - (String) The name servers from when the Domain was initially registered with the DNS Registrar. - `paused` - (Bool) If set to **true**, network traffic to this domain is paused. If set to **false**, network traffic to this domain is permitted. The default value is **false**. -- `status` - (String) The status of your domain. Valid values are `active`, `pending`, `initializing`, `moved`, `deleted`, and `deactivated`. After creation, the status remains pending until the DNS Registrar is updated with the CIS name servers, exported in the ‘name_servers’ variable. \ No newline at end of file +- `status` - (String) The status of your domain. Valid values are `active`, `pending`, `initializing`, `moved`, `deleted`, and `deactivated`. After creation, the status remains pending until the DNS Registrar is updated with the CIS name servers, exported in the ‘name_servers’ variable. +- `type` - (String) The type of domain created. `full`- for regular domains, & `partial` for partial domain for CNAME setup. \ No newline at end of file diff --git a/website/docs/d/cis_filters.html.markdown b/website/docs/d/cis_filters.html.markdown index 8c881e59a..3f2ef70a3 100644 --- a/website/docs/d/cis_filters.html.markdown +++ b/website/docs/d/cis_filters.html.markdown @@ -8,7 +8,7 @@ description: |- # ibm_cis_filters -Imports a read only copy of an existing Internet Services filters resource. +Retrieve information about an IBM Cloud Internet Services filters data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). ## Example usage @@ -20,19 +20,18 @@ data "ibm_cis_filters" "test" { ``` ## Argument reference - -The following arguments are supported: +Review the argument references that you can specify for your data source. - `cis_id` - (Required, String) The ID of the CIS service instance. - `domain_id` - (Required, String) The ID of the domain. -## Attributes Reference +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. -In addition to all arguments above, the following attributes are exported: - `id` - (String) The Filter ID. It is a combination of <`filter_id`>,<`domain_id`>,<`cis_id`> attributes concatenated with ":" -- `cis_filters_list` - (List of Filters) - - `expression` - (String) The expression of filter. - - `paused` - (Boolean). Whether this filter is currently disabled. - - `description` - (String) The information about this filter to help identify the purpose of it. - - `filter_id` - (String) The filter ID. +- `cis_filters_list` - (List) + - `expression` - (String) The expression of filter. + - `paused` - (Boolean). Whether this filter is currently disabled. + - `description` - (String) The information about this filter to help identify the purpose of it. + - `filter_id` - (String) The filter ID. diff --git a/website/docs/d/cis_logpush_jobs.html.markdown b/website/docs/d/cis_logpush_jobs.html.markdown new file mode 100644 index 000000000..1f92e5734 --- /dev/null +++ b/website/docs/d/cis_logpush_jobs.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_logpush_jobs" +description: |- + Get information on an IBM Cloud Internet Services logpush jobs. +--- + +# ibm_cis_logpush_jobs + +Retrieve information about an IBM Cloud Internet Services logpush jobs data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_logpush_jobs" "tests" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. +- `domain_id` - (Required, String) The Domain ID of the CIS service instance. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The Logpush Job ID. It is a combination of <`job_id`>,<`cis_id`> attributes concatenated with ":" +- `logpush_job_pack` - (List) + - `job_id` - (String) The Logpush job ID. + - `name` - (String) The name of Logpush job. + - `enabled` - (Bool) Whether the logpush job enabled or not. + - `logpull_options` - (String) Configuration string for Logpush Job. + - `destination_conf` - (String) Uniquely identifies a resource (such as an s3 bucket) where data will be pushed. + - `dataset` - (String) Dataset to be pulled for Logpush Job and the values are `http_requests`, `range_events`, `firewall_events`. + - `frequency` - (String) The frequency at which CIS sends batches of logs to your destination, `high`, `low`. + diff --git a/website/docs/d/cis_mtls.html.markdown b/website/docs/d/cis_mtls.html.markdown new file mode 100644 index 000000000..3661b9a34 --- /dev/null +++ b/website/docs/d/cis_mtls.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_mtlss" +description: |- + Get information on an IBM Cloud Internet Services mTLS. +--- + +# ibm_cis_mtlss + +Retrieve information about an IBM Cloud Internet Services mTLS data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_mtlss" "tests" { + cis_id = ibm_cis.instance.id + domain_id = ibm_cis_domain.example.id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. +- `cis_domain` - (Required, String) The Domain of the CIS service instance. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `cis_id` - (String) The ID of the CIS service instance. +- `cis_domain` - (String) The Domain of the CIS service instance. +- `mtls_certificates` - (List) + - `id` - (String) The Certificate ID. + - `name` - (String) The Certificate Name. + - `fingerprint` - (String) The Certificate Fingerprint. + - `associated_hostnames` - (String) The Certificate Associated Hostnames. + - `created_at` - (String) The Certificate Created At. + - `updated_at` - (String) The Certificate Updated At. + - `expires_on` - (String) The Certificate Expires On. + diff --git a/website/docs/d/cis_mtls_apps.html.markdown b/website/docs/d/cis_mtls_apps.html.markdown new file mode 100644 index 000000000..9531272fb --- /dev/null +++ b/website/docs/d/cis_mtls_apps.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_mtls_apps" +description: |- + Get information on an IBM Cloud Internet Services mTLS Applications and Policies. +--- + +# ibm_cis_mtlss + +Retrieve information about an IBM Cloud Internet Services mTLS Applications data sources and fetch Policies data source, with respect to Application ID. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_mtls_apps" "tests" { + cis_id = ibm_cis.instance.id + domain_id = ibm_cis_domain.example.id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. +- `cis_domain` - (Required, String) The Domain of the CIS service instance. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `cis_id` - (String) The ID of the CIS service instance. +- `cis_domain` - (String) The Domain of the CIS service instance. +- `mtls_access_apps` - (List) + - `app_id` - (String) The Application ID. + - `app_name` - (String) The Application Name. + - `app_domain` - (String) The Application Domain. + - `app_aud` - (String) The Application Aud. + - `allowed_idps` - (List) The List of allowed idps. + - `auto_redirect_to_identity` - (Bool) Auto Redirect to Identity. + - `session_duration` - (String) The Session Duration. + - `app_type` - (String) The Session Type. + - `app_uid` - (String) The Application Uid. + - `app_created_at` - (String) The Application Created At. + - `app_updated_at` - (String) The Application Updated At. +- `mtls_access_app_policies` - (List) + - `policy_id` - (String) The Policy ID. + - `policy_name` - (String) The Policy Name. + - `policy_decision` - (String) The Policy Decision. + - `policy_precedence` - (Int) The Policy Precedence. + - `policy_uid` - (String) The Policy Uid. + - `policy_created_at` - (String) The Policy Created At. + - `policy_updated_at` - (String) The Policy Updated At. + diff --git a/website/docs/d/cis_page_rules.html.markdown b/website/docs/d/cis_page_rules.html.markdown index 5e1ef773d..91d1d99e1 100644 --- a/website/docs/d/cis_page_rules.html.markdown +++ b/website/docs/d/cis_page_rules.html.markdown @@ -46,73 +46,11 @@ In addition to all argument reference list, you can access the following attribu - `actions` - (String) The actions to be performed on the URL. Nested scheme for `actions`: - - `id` - (String) The action ID. Valid values are `page rule action field map from console` to `API CF-UI map API`). - - Nested scheme for `id`: - - `automatic_https_rewrites` - (String) The automatic HTTPS rewrites. - - `always_use_https` - (String) The action conflicts with all other settings. - - `always_online` - (String) The action conflicts with all other settings. - - `browser_cache_ttl` - (String) The browser cache TTL. - - `bypass_cache_on_cookie` - (String) The bypass cache on cookie. - - `browser_check` - (String) The browser integrity check. - - `cache_deception_armor` - (String) The cache deception armor. - - `cache_level` - (String) The cache level. - - `cache_on_cookie` - (String) The cache on cookie. - - `disable_apps` - (String) The disable apps. - - `disable_performance` - (String) The disable - - `disable_security` - (String) The action conflicts with `email_obfuscation`, `server_side_exclude`, `waf`. - - `edge_cache_ttl` - (String) The edge cache TTL. - - `email_obfuscation` - (String) The Email obfuscation. - - `explicit_cache_control` - (String) The origin cache control. - - `forwarding_url` - (String) The action conflicts with all other settings. - - `host_header_override` - (String) The host header override. - - `image_load_optimization` - (String) The image load optimization. - - `image_size_optimization` - (String) The image size optimization. - - `ip_geolocation` - (String) The IP geography location header. - - `origin_error_page_pass_thru` - (String) The origin error page pass-through. - - `opportunistic_encryption` - (String) The opportunistic encryption. - - `resolve_override` - (String) The resolve override. - performance. - - `response_buffering` - (String) The response buffering. - - `script_load_optimization` - (String) The script load optimization. - - `ssl` - (String) The TLS settings. - - `security_level` - (String) The security level. - - `server_side_exclude` - (String) The server side excludes. - - `server_stale_content` - (String) The server stale content. - - `sort_query_string_for_cache` - (String) The sort query string. - - `true_client_ip_header` - (String) The true client IP header. - - `waf` - (String) The Web Application Firewall. + - `id` - (String) The action ID. Valid values are `page rule action field map from console` to `API CF-UI map API`. - `value` - (String) The values for corresponding actions. - - Nested scheme for `value`: - - `always_online` - (String) The valid values are `on`, `off`. - - `automatic_https_rewrites` - (String) The valid values are `on`, `off`. - - `browser_cache_ttl`- (Integer) The valid values are `0, 1800, 3600, 7200, 10800, 14400, 18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 691200, 1382400, 2073600, 2678400, 5356800, 16070400, 31536000`. - - `browser_check` - (String) The valid values are `on`, `off`. - - `bypass_cache_on_cookie` - (String) The valid values are `cookie tags`. - - `cache_deception_armor` - (String) The valid values are `on`, `off`. - - `cache_on_cookie` - (String) The cookie value. - - `cache_level` - (String) The valid values are `bypass`, `aggressive`, `basic`, `simplified`, `cache_everything`. - - `edge_cache_ttl` - (String) The valid values are `0, 30, 60, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 518400, 604800, 1209600, 2419200`. - - `disable_apps` - (String) The value is not required. - - `disable_performance` - (String) The value is not required. - - `email_obfuscation` - (String) The valid values are `on`, `off`. - - `explicit_cache_control` - (String) The valid values are `on`, `off`. - - `host_header_override` - (String) The header value. - - `ip_geolocation` - (String) The valid values are `on`, `off`. - - `image_load_optimization` - (String) The valid values are `on`, `off`. - - `image_size_optimization` - (String) The valid values are `on`, `off`. - - `opportunistic_encryption` - (String) The valid values are `on`, `off`. - - `origin_error_page_pass_thru` - (String) The valid values are `on`, `off`. - - `resolve_override` - (String) The value for resolving URL override. - - `response_buffering` - (String) The valid values are `on`, `off`. - - `script_load_optimization` - (String) The valid values are `off`, `lossless`, `lossy`. - - `ssl` - (String) The valid values are `off`, `flexible`, `full`, `strict`, `origin_pull`. - - `security_level` - (String) The valid values are `disable_security`, `always_use_https`. - - `server_side_exclude` - (String) The valid values are `on`, `off`. - - `server_stale_content` - (String) The valid values are `on`, `off`. - - `sort_query_string_for_cache` - (String) The valid values are `on`, `off`. - - `true_client_ip_header` - (String) The valid values are `on`, `off`. - - `waf` - (String) The valid values are `on`, `off`. + Please refer table in `ibm_cis_page_rule` resource document for corresponding valid values of `id` and `value`. - `status_code` - (String) The status code to check for URL forwarding. The required attribute for `forwarding_url` action. Valid values are `301` and `302`. It returns `0` for all other actions. - `url` - (String) The forward rule URL, a required attribute for `forwarding_url` action. + - `css` - (String) The required attribute for `minify` action. CSS supported values are `on` and `off`. + - `html` - (String) The required attribute for `minify` action. HTML supported values are `on` and `off`. + - `js` - (String) The required attribute for `minify` action. JS supported values are `on` and `off`. \ No newline at end of file diff --git a/website/docs/d/cis_waf_groups.html.markdown b/website/docs/d/cis_waf_groups.html.markdown index ba5bd395d..58bffc869 100644 --- a/website/docs/d/cis_waf_groups.html.markdown +++ b/website/docs/d/cis_waf_groups.html.markdown @@ -31,7 +31,7 @@ In addition to all argument reference list, you can access the following attribu - `description` - (String) The WAF rule group description. - `group_id` - (String) The WAF group ID. -- `modified_rules_count` - (String) Number of rules modified in WAF Group. +- `modified_rules_count` - (Integer) Number of rules modified in WAF Group. - `mode` - (String) The `on`, or `off` mode setting of the WAF rule group. - `name` - (String) The name of the WAF rule group. -- `rules_count` - (String) Number of rules in WAF Group. +- `rules_count` - (Integer) Number of rules in WAF Group. diff --git a/website/docs/d/cis_webhooks.html.markdown b/website/docs/d/cis_webhooks.html.markdown new file mode 100644 index 000000000..8e746c65f --- /dev/null +++ b/website/docs/d/cis_webhooks.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_webhooks" +description: |- + Get information on an IBM Cloud Internet Services webhooks. +--- + +# ibm_cis_webhooks + +Retrieve information about an IBM Cloud Internet Services webhooks data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +data "ibm_cis_webhooks" "test" { + cis_id = ibm_cis.instance.id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `cis_id` - (Required, String) The ID of the CIS service instance. + + +## Attributes reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The Webhook ID. It is a combination of <`webhook_id`>,<`cis_id`> attributes concatenated with ":" +- `cis_webhooks` - (List) + - `name` - (String) The name of webhook. + - `url` - (Boolean). Whether this webhook is currently disabled. + - `type` - (String) The information about this webhook to help identify the purpose of it. + - `webhook_id` - (String) The Webhook ID. + diff --git a/website/docs/d/cloud_shell_account_settings.html.markdown b/website/docs/d/cloud_shell_account_settings.html.markdown index 39c704c4d..083f94372 100644 --- a/website/docs/d/cloud_shell_account_settings.html.markdown +++ b/website/docs/d/cloud_shell_account_settings.html.markdown @@ -6,25 +6,25 @@ description: |- subcategory: "IBM Cloud Shell" --- -# ibm\_cloud_shell_account_settings +# ibm_cloud_shell_account_settings Provides a read-only data source for cloud_shell_account_settings. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "cloud_shell_account_settings" "cloud_shell_account_settings" { account_id = "account_id" } ``` -## Argument Reference +## Argument reference The following arguments are supported: * `account_id` - (Required, string) The account ID in which the account settings belong to. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: diff --git a/website/docs/d/cloudant.html.markdown b/website/docs/d/cloudant.html.markdown index 287506fb4..a565df9b0 100644 --- a/website/docs/d/cloudant.html.markdown +++ b/website/docs/d/cloudant.html.markdown @@ -3,7 +3,7 @@ layout: "ibm" page_title: "IBM : ibm_cloudant" description: |- Get information about Cloudant instance. -subcategory: "Cloud Databases" +subcategory: "Cloudant Databases" --- # ibm_cloudant diff --git a/website/docs/d/cloudant_database.html.markdown b/website/docs/d/cloudant_database.html.markdown new file mode 100644 index 000000000..f8bb0d9d0 --- /dev/null +++ b/website/docs/d/cloudant_database.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "ibm" +page_title: "IBM : cloudant_database" +description: |- + Get information about cloudant_database +subcategory: "Cloudant Databases" +--- + +# ibm\_cloudant_database + +Provides a read-only data source for cloudant_database. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_cloudant_database" "cloudant_database" { + db = var.db_name + instance_crn = ibm_cloudant.cloudant.crn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `db` - (Required, string) Path parameter to specify the database name. +* `instance_crn` - (Required, string) Path parameter to specify the cloudant instance CRN. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `cluster` - Schema for database cluster information. Nested `cluster` blocks have the following structure: + * `read_quorum` - Read quorum. The number of consistent copies of a document that need to be read before a successful reply. + * `replicas` - Schema for the number of replicas of a database in a cluster. + * `shards` - Schema for the number of shards in a database. Each shard is a partition of the hash value range. + * `write_quorum` - Write quorum. The number of copies of a document that need to be written before a successful reply. + +* `committed_update_seq` - An opaque string that describes the committed state of the database. + +* `compact_running` - True if the database compaction routine is operating on this database. + +* `compacted_seq` - An opaque string that describes the compaction state of the database. + +* `db_name` - The name of the database. + +* `disk_format_version` - The version of the physical format used for the data when it is stored on disk. + +* `doc_count` - A count of the documents in the specified database. + +* `doc_del_count` - Number of deleted documents. + +* `engine` - The engine used for the database. + +* `id` - The unique identifier of the cloudant_database. + +* `props` - Schema for database properties. Nested `props` blocks have the following structure: + * `partitioned` - The value is `true` for a partitioned database. + +* `sizes` - Schema for size information of content. Nested `sizes` blocks have the following structure: + * `active` - The active size of the content, in bytes. + * `external` - The total uncompressed size of the content, in bytes. + * `file` - The total size of the content as stored on disk, in bytes. + +* `update_seq` - An opaque string that describes the state of the database. Do not rely on this string for counting the number of updates. + +* `uuid` - The UUID of the database. + diff --git a/website/docs/d/cm_catalog.html.markdown b/website/docs/d/cm_catalog.html.markdown index 2f793efd4..dd926b9f5 100644 --- a/website/docs/d/cm_catalog.html.markdown +++ b/website/docs/d/cm_catalog.html.markdown @@ -1,40 +1,113 @@ --- -subcategory: "Catalog Management" layout: "ibm" page_title: "IBM : ibm_cm_catalog" description: |- - Get information about ibm_cm_catalog. + Get information about cm_catalog +subcategory: "Catalog Management API" --- # ibm_cm_catalog -Provides a read-only data source for `ibm_cm_catalog`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Provides a read-only data source for cm_catalog. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +## Example Usage -## Example usage - -```terraform +```hcl data "ibm_cm_catalog" "cm_catalog" { - catalog_identifier = "catalog_identifier" + catalog_identifier = ibm_cm_catalog.cm_catalog.catalog_id } ``` -## Argument reference -Review the argument reference that you can specify for your data source. - -- `catalog_identifier` - (Required, String) The catalog identifier. - - -## Attribute reference -In addition to the argument reference list, you can access the following attribute references after your data source is created. - -- `catalog_icon_url` - (String) The URL for an icon associated with the catalog. -- `crn` - (String) The CRN associated with the catalog. -- `id` - (String) The unique identifier of the `ibm_cm_catalog`. -- `kind` - (String) Kind of catalog, offering or vpe. -- `label` - (String) Display the name in the requested language. -- `offerings_url` - (String) URL path to the offerings. -- `resource_group_id` - (String) The ID of the resource group this catalog is in -- `short_description` - (String) The description in the requested language. -- `tags` - (String) The list of tags associated with this catalog. -- `url` - (String) The URL for the specific catalog. +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `catalog_identifier` - (Required, Forces new resource, String) Catalog identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cm_catalog. +* `catalog_filters` - (List) Filters for account and catalog filters. +Nested scheme for **catalog_filters**: + * `category_filters` - (Map) Filter against offering properties. + * `id_filters` - (List) Filter on offering ID's. There is an include filter and an exclule filter. Both can be set. + Nested scheme for **id_filters**: + * `exclude` - (List) Offering filter terms. + Nested scheme for **exclude**: + * `filter_terms` - (List) List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded. + * `include` - (List) Offering filter terms. + Nested scheme for **include**: + * `filter_terms` - (List) List of values to match against. If include is true, then if the offering has one of the values then the offering is included. If include is false, then if the offering has one of the values then the offering is excluded. + * `include_all` - (Boolean) -> true - Include all of the public catalog when filtering. Further settings will specifically exclude some offerings. false - Exclude all of the public catalog when filtering. Further settings will specifically include some offerings. + +* `catalog_icon_url` - (String) URL for an icon associated with this catalog. + +* `created` - (String) The date-time this catalog was created. + +* `crn` - (String) CRN associated with the catalog. + +* `disabled` - (Boolean) Denotes whether a catalog is disabled. + +* `features` - (List) List of features associated with this catalog. +Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + +* `id` - (String) Unique ID. + +* `kind` - (String) Kind of catalog. Supported kinds are offering and vpe. + +* `label` - (String) Display Name in the requested language. + +* `metadata` - (Map) Catalog specific metadata. + +* `offerings_url` - (String) URL path to offerings. + +* `owning_account` - (String) Account that owns catalog. + +* `resource_group_id` - (String) Resource group id the catalog is owned by. + +* `rev` - (String) Cloudant revision. + +* `short_description` - (String) Description in the requested language. + +* `syndication_settings` - (List) Feature information. +Nested scheme for **syndication_settings**: + * `authorization` - (List) Feature information. + Nested scheme for **authorization**: + * `last_run` - (String) Date and time last updated. + * `token` - (String) Array of syndicated namespaces. + * `clusters` - (List) Syndication clusters. + Nested scheme for **clusters**: + * `all_namespaces` - (Boolean) Syndicated to all namespaces on cluster. + * `id` - (String) Cluster ID. + * `name` - (String) Cluster name. + * `namespaces` - (List) Syndicated namespaces. + * `region` - (String) Cluster region. + * `resource_group_name` - (String) Resource group ID. + * `type` - (String) Syndication type. + * `history` - (List) Feature information. + Nested scheme for **history**: + * `clusters` - (List) Array of syndicated namespaces. + Nested scheme for **clusters**: + * `all_namespaces` - (Boolean) Syndicated to all namespaces on cluster. + * `id` - (String) Cluster ID. + * `name` - (String) Cluster name. + * `namespaces` - (List) Syndicated namespaces. + * `region` - (String) Cluster region. + * `resource_group_name` - (String) Resource group ID. + * `type` - (String) Syndication type. + * `last_run` - (String) Date and time last syndicated. + * `namespaces` - (List) Array of syndicated namespaces. + * `remove_related_components` - (Boolean) Remove related components. + +* `tags` - (List) List of tags associated with this catalog. + +* `updated` - (String) The date-time this catalog was last updated. + +* `url` - (String) The url for this specific catalog. + diff --git a/website/docs/d/cm_offering.html.markdown b/website/docs/d/cm_offering.html.markdown index 31b52666e..6621db802 100644 --- a/website/docs/d/cm_offering.html.markdown +++ b/website/docs/d/cm_offering.html.markdown @@ -1,61 +1,499 @@ --- -subcategory: "Catalog Management" layout: "ibm" page_title: "IBM : ibm_cm_offering" description: |- - Get information about ibm_cm_offering. + Get information about cm_offering +subcategory: "Catalog Management API" --- # ibm_cm_offering -Provides a read-only data source for `ibm_cm_offering`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Provides a read-only data source for cm_offering. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_cm_offering" "cm_offering" { - catalog_identifier = "catalog_identifier" - offering_id = "offering_id" + catalog_identifier = ibm_cm_offering.cm_offering.catalog_identifier + offering_identifier = ibm_cm_offering.cm_offering.offering_id } ``` +## Argument Reference -## Argument reference -Review the argument reference that you can specify for your data source. - -- `catalog_identifier` - (Required, String) The catalog identifier. -- `offering_id` - (Required, String) The offering identification. - - -## Attribute reference -In addition to all argument references list, you can access the following attribute references after your data source is created. - -- `catalog_id` - (String) The ID of the catalog containing this offering. -- `catalog_name` - (String) The name of the catalog. -- `crn` - (String) The CRN for the specific offering. -- `disclaimer` - (String) A disclaimer for the offering. -- `hidden` - (String) Determine if the offering should be displayed in the consumption console. -- `ibm_publish_approved` - (String) Indicates if the offering has been approved for use by all IBMers. -- `id` - (String) The unique identifier of the `ibm_cm_offering`. -- `label` - (String) Display the name in the requested language. -- `long_description` - (String) The long description in the requested language. -- `name` - (String) The programmatic name of the offering. -- `offering_icon_url` - (String) The URL for an icon associated with the offering. -- `offering_docs_url` - (String) The URL for an extra documentation with the offering. -- `offering_support_url` - (String) The URL to be displayed in the consumption console for getting support on the offering. -- `permit_request_ibm_public_publish` - (String) Is it permitted to request publishing to IBM or public. -- `public_publish_approved` - (String) Indicates if the offering has been approved to all IBM Cloud users. -- `public_original_crn` - (String) The original offering CRN that is published. -- `publish_public_crn` - (String) The CRN of the public catalog entry of the offering. -- `portal_approval_record` - (String) The portal's approval record ID. -- `portal_ui_url` - (String) The portal console URL. -- `provider` - (String) Provider of this offering. -- `repo_info` - (List) Repository information for offerings. Nested `repo_info` blocks have the following structure. - - Nested scheme for `rep_info`: - - `token` - (String) The token for the private repository. - - `type` - (String) The public or enterprise GitHub. - -- `short_description` - (String) The short description in the requested language. -- `url` - (String) The URL for the specific offering. +Review the argument reference that you can specify for your data source. + +* `catalog_identifier` - (Required, Forces new resource, String) Catalog identifier. +* `offering_identifier` - (Required, Forces new resource, String) Offering identification. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cm_offering. +* `badges` - (List) A list of badges for this offering. +Nested scheme for **badges**: + * `authority` - (String) Authority for the current badge. + * `constraints` - (List) An optional set of constraints indicating which versions in an Offering have this particular badge. + Nested scheme for **constraints**: + * `rule` - (Map) Rule for the current constraint. + * `type` - (String) Type of the current constraint. + * `description` - (String) Description of the current badge. + * `icon` - (String) Icon for the current badge. + * `id` - (String) ID of the current badge. + * `label` - (String) Display name for the current badge. + * `learn_more_links` - (List) Learn more links for a badge. + Nested scheme for **learn_more_links**: + * `first_party` - (String) First party link. + * `third_party` - (String) Third party link. + * `tag` - (String) Tag for the current badge. + +* `catalog_id` - (String) The id of the catalog containing this offering. + +* `catalog_name` - (String) The name of the catalog. + +* `created` - (String) The date and time this catalog was created. + +* `crn` - (String) The crn for this specific offering. + +* `deprecate_pending` - (List) Deprecation information for an Offering. +Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) + +* `disclaimer` - (String) A disclaimer for this offering. + +* `features` - (List) list of features associated with this offering. +Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + +* `hidden` - (Boolean) Determine if this offering should be displayed in the Consumption UI. + +* `ibm_publish_approved` - (Deprecated, Boolean) Indicates if this offering has been approved for use by all IBMers. + +* `image_pull_keys` - (List) Image pull keys for this offering. +Nested scheme for **image_pull_keys**: + * `description` - (String) Key description. + * `name` - (String) Key name. + * `value` - (String) Key value. + +* `keywords` - (List) List of keywords associated with offering, typically used to search for it. + +* `kinds` - (List) Array of kind. +Nested scheme for **kinds**: + * `additional_features` - (List) List of features associated with this offering. + Nested scheme for **additional_features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `created` - (String) The date and time this catalog was created. + * `format_kind` - (String) content kind, e.g., helm, vm image. + * `id` - (String) Unique ID. + * `install_kind` - (String) install kind, e.g., helm, operator, terraform. + * `metadata` - (Map) Open ended metadata information. + * `plans` - (List) list of plans. + Nested scheme for **plans**: + * `additional_features` - (List) list of features associated with this offering. + Nested scheme for **additional_features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `created` - (String) the date'time this catalog was created. + * `deployments` - (List) list of deployments. + Nested scheme for **deployments**: + * `created` - (String) the date'time this catalog was created. + * `id` - (String) unique id. + * `label` - (String) Display Name in the requested language. + * `long_description` - (String) Long description in the requested language. + * `metadata` - (Map) open ended metadata information. + * `name` - (String) The programmatic name of this offering. + * `short_description` - (String) Short description in the requested language. + * `tags` - (List) list of tags associated with this catalog. + * `updated` - (String) the date'time this catalog was last updated. + * `id` - (String) unique id. + * `label` - (String) Display Name in the requested language. + * `long_description` - (String) Long description in the requested language. + * `metadata` - (Map) open ended metadata information. + * `name` - (String) The programmatic name of this offering. + * `short_description` - (String) Short description in the requested language. + * `tags` - (List) list of tags associated with this catalog. + * `updated` - (String) the date'time this catalog was last updated. + * `tags` - (List) List of tags associated with this catalog. + * `target_kind` - (String) target cloud to install, e.g., iks, open_shift_iks. + * `updated` - (String) The date and time this catalog was last updated. + * `versions` - (List) list of versions. + Nested scheme for **versions**: + * `catalog_id` - (String) Catalog ID. + * `configuration` - (List) List of user solicited overrides. + Nested scheme for **configuration**: + * `custom_config` - (List) Render type. + Nested scheme for **custom_config**: + * `associations` - (List) List of parameters that are associated with this configuration. + Nested scheme for **associations**: + * `parameters` - (List) Parameters for this association. + Nested scheme for **parameters**: + * `name` - (String) Name of this parameter. + * `options_refresh` - (Boolean) Refresh options. + * `config_constraints` - (Map) Map of constraint parameters that will be passed to the custom widget. + * `grouping` - (String) Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment). + * `grouping_index` - (Integer) Determines the order that this configuration item shows in that particular grouping. + * `original_grouping` - (String) Original grouping type for this configuration (3 types - Target, Resource, and Deployment). + * `type` - (String) ID of the widget type. + * `default_value` - (Map) The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`. + * `description` - (String) Key description. + * `display_name` - (String) Display name for configuration type. + * `hidden` - (Boolean) Hide values. + * `key` - (String) Configuration key. + * `options` - (List) List of options of type. + * `required` - (Boolean) Is key required to install. + * `type` - (String) Value type (string, boolean, int). + * `type_metadata` - (String) The original type, as found in the source being onboarded. + * `value_constraint` - (String) Constraint associated with value, e.g., for string type - regx:[a-z]. + * `created` - (String) The date and time this version was created. + * `crn` - (String) Version's CRN. + * `deprecate_pending` - (List) Deprecation information for an Offering. + Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) + * `deprecated` - (Boolean) read only field, indicating if this version is deprecated. + * `entitlement` - (List) Entitlement license info. + Nested scheme for **entitlement**: + * `image_repo_name` - (String) Image repository name. + * `part_numbers` - (List) list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL. + * `product_id` - (String) Product ID. + * `provider_id` - (String) Provider ID. + * `provider_name` - (String) Provider name. + * `flavor` - (List) Version Flavor Information. Only supported for Product kind Solution. + Nested scheme for **flavor**: + * `index` - (Integer) Order that this flavor should appear when listed for a single version. + * `label` - (String) Label for this flavor. + * `label_i18n` - (Map) A map of translated strings, by language code. + * `name` - (String) Programmatic name for this flavor. + * `iam_permissions` - (List) List of IAM permissions that are required to consume this version. + Nested scheme for **iam_permissions**: + * `resources` - (List) Resources for this permission. + Nested scheme for **resources**: + * `description` - (String) Resource description. + * `name` - (String) Resource name. + * `role_crns` - (List) Role CRNs for this permission. + * `role_crns` - (List) Role CRNs for this permission. + * `service_name` - (String) Service name. + * `id` - (String) Unique ID. + * `image_manifest_url` - (String) If set, denotes a url to a YAML file with list of container images used by this version. + * `image_pull_key_name` - (String) ID of the image pull key to use from Offering.ImagePullKeys. + * `install` - (List) Script information. + Nested scheme for **install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + * `is_consumable` - (Boolean) Is the version able to be shared. + * `kind_id` - (String) Kind ID. + * `licenses` - (List) List of licenses the product was built with. + Nested scheme for **licenses**: + * `description` - (String) License description. + * `id` - (String) License ID. + * `name` - (String) license name. + * `type` - (String) type of license e.g., Apache xxx. + * `url` - (String) URL for the license text. + * `long_description` - (String) Long description for version. + * `long_description_i18n` - (Map) A map of translated strings, by language code. + * `metadata` - (Map) Open ended metadata information. + * `offering_id` - (String) Offering ID. + * `outputs` - (List) List of output values for this version. + Nested scheme for **outputs**: + * `description` - (String) Output description. + * `key` - (String) Output key. + * `package_version` - (String) Version of the package used to create this version. + * `pre_install` - (List) Optional pre-install instructions. + Nested scheme for **pre_install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + * `repo_url` - (String) Content's repo URL. + * `required_resources` - (List) Resource requirments for installation. + Nested scheme for **required_resources**: + * `type` - (String) Type of requirement. + * Constraints: Allowable values are: `mem`, `disk`, `cores`, `targetVersion`, `nodes`. + * `value` - (Map) mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value. + * `rev` - (String) Cloudant revision. + * `sha` - (String) hash of the content. + * `single_instance` - (Boolean) Denotes if single instance can be deployed to a given cluster. + * `solution_info` - (List) Version Solution Information. Only supported for Product kind Solution. + Nested scheme for **solution_info**: + * `architecture_diagrams` - (List) Architecture diagrams for this solution. + Nested scheme for **architecture_diagrams**: + * `description` - (String) Description of this diagram. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `diagram` - (List) Offering Media information. + Nested scheme for **diagram**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + * `cost_estimate` - (List) Cost estimate definition. + Nested scheme for **cost_estimate**: + * `currency` - (String) Cost estimate currency. + * `diff_total_hourly_cost` - (String) Difference in total hourly cost. + * `diff_total_monthly_cost` - (String) Difference in total monthly cost. + * `past_total_hourly_cost` - (String) Past total hourly cost. + * `past_total_monthly_cost` - (String) Past total monthly cost. + * `projects` - (List) Cost estimate projects. + Nested scheme for **projects**: + * `breakdown` - (List) Cost breakdown definition. + Nested scheme for **breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `diff` - (List) Cost breakdown definition. + Nested scheme for **diff**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `metadata` - (Map) Project metadata. + * `name` - (String) Project name. + * `past_breakdown` - (List) Cost breakdown definition. + Nested scheme for **past_breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `time_generated` - (String) When this estimate was generated. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_cost` - (String) Total monthly cost. + * `version` - (String) Cost estimate version. + * `dependencies` - (List) Dependencies for this solution. + Nested scheme for **dependencies**: + * `catalog_id` - (String) Optional - If not specified, assumes the Public Catalog. + * `flavors` - (List) Optional - List of dependent flavors in the specified range. + * `id` - (String) Optional - Offering ID - not required if name is set. + * `name` - (String) Optional - Programmatic Offering name. + * `version` - (String) Required - Semver value or range. + * `features` - (List) Features - titles only. + Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `source_url` - (String) Content's source URL (e.g git repo). + * `state` - (List) Offering state. + Nested scheme for **state**: + * `current` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `current_entered` - (String) Date and time of current request. + * `pending` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `pending_requested` - (String) Date and time of pending request. + * `previous` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `tags` - (List) List of tags associated with this catalog. + * `tgz_url` - (String) File used to on-board this version. + * `updated` - (String) The date and time this version was last updated. + * `validation` - (List) Validation response. + Nested scheme for **validation**: + * `last_operation` - (String) Last operation (e.g. submit_deployment, generate_installer, install_offering. + * `message` - (String) Any message needing to be conveyed as part of the validation job. + * `requested` - (String) Date and time of last validation was requested. + * `state` - (String) Current validation state - , in_progress, valid, invalid, expired. + * `target` - (Map) Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type. + * `validated` - (String) Date and time of last successful validation. + * `version` - (String) Version of content type. + * `version_locator` - (String) A dotted value of `catalogID`.`versionID`. + * `whitelisted_accounts` - (List) Whitelisted accounts for version. + +* `label` - (String) Display Name in the requested language. + +* `label_i18n` - (Map) A map of translated strings, by language code. + +* `long_description` - (String) Long description in the requested language. + +* `long_description_i18n` - (Map) A map of translated strings, by language code. + +* `media` - (List) A list of media items related to this offering. +Nested scheme for **media**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + +* `metadata` - (Map) Map of metadata values for this offering. + +* `name` - (String) The programmatic name of this offering. + +* `offering_docs_url` - (String) URL for an additional docs with this offering. + +* `offering_icon_url` - (String) URL for an icon associated with this offering. + +* `offering_support_url` - (String) [deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering. + +* `pc_managed` - (Boolean) Offering is managed by Partner Center. + +* `permit_request_ibm_public_publish` - (Deprecated, Boolean) Is it permitted to request publishing to IBM or Public. + +* `portal_approval_record` - (String) The portal's approval record ID. + +* `portal_ui_url` - (String) The portal UI URL. + +* `product_kind` - (String) The product kind. Valid values are module, solution, or empty string. + +* `provider` - (Deprecated, String) Deprecated - Provider of this offering. + +* `provider_info` - (List) Information on the provider for this offering, or omitted if no provider information is given. +Nested scheme for **provider_info**: + * `id` - (String) The id of this provider. + * `name` - (String) The name of this provider. + +* `public_original_crn` - (String) The original offering CRN that this publish entry came from. + +* `public_publish_approved` - (Deprecated, Boolean) Indicates if this offering has been approved for use by all IBM Cloud users. + +* `publish_approved` - (Boolean) Offering has been approved to publish to permitted to IBM or Public Catalog. + +* `publish_public_crn` - (String) The crn of the public catalog entry of this offering. + +* `rating` - (List) Repository info for offerings. +Nested scheme for **rating**: + * `four_star_count` - (Integer) Four start rating. + * `one_star_count` - (Integer) One start rating. + * `three_star_count` - (Integer) Three start rating. + * `two_star_count` - (Integer) Two start rating. + +* `repo_info` - (List) Repository info for offerings. +Nested scheme for **repo_info**: + * `token` - (String) Token for private repos. + * `type` - (String) Public or enterprise GitHub. + +* `rev` - (String) Cloudant revision. + +* `share_enabled` - (Boolean) Denotes sharing including access list availability of an Offering is enabled. + +* `share_with_all` - (Boolean) Denotes public availability of an Offering - if share_enabled is true. + +* `share_with_ibm` - (Boolean) Denotes IBM employee availability of an Offering - if share_enabled is true. + +* `short_description` - (String) Short description in the requested language. + +* `short_description_i18n` - (Map) A map of translated strings, by language code. + +* `support` - (List) Offering Support information. +Nested scheme for **support**: + * `locations` - (List) A list of country codes indicating where support is provided. + * `process` - (String) Support process as provided by an ISV. + * `process_i18n` - (Map) A map of translated strings, by language code. + * `support_details` - (List) A list of support options (e.g. email, phone, slack, other). + Nested scheme for **support_details**: + * `availability` - (List) Times when support is available. + Nested scheme for **availability**: + * `always_available` - (Boolean) Is this support always available. + * `times` - (List) A list of support times. + Nested scheme for **times**: + * `day` - (Integer) The day of the week, represented as an integer. + * `end_time` - (String) HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00). + * `start_time` - (String) HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00). + * `timezone` - (String) Timezone (e.g. America/New_York). + * `contact` - (String) Contact for the current support detail. + * `response_wait_time` - (List) Time descriptor. + Nested scheme for **response_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `type` - (String) Type of the current support detail. + * `support_escalation` - (List) Support escalation policy. + Nested scheme for **support_escalation**: + * `contact` - (String) Escalation contact. + * `escalation_wait_time` - (List) Time descriptor. + Nested scheme for **escalation_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `response_wait_time` - (List) Time descriptor. + Nested scheme for **response_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `support_type` - (String) Support type for this product. + * `url` - (String) URL to be displayed in the Consumption UI for getting support on this offering. + +* `tags` - (List) List of tags associated with this catalog. + +* `updated` - (String) The date and time this catalog was last updated. + +* `url` - (String) The url for this specific offering. diff --git a/website/docs/d/cm_version.html.markdown b/website/docs/d/cm_version.html.markdown index 31746de06..d66681c35 100644 --- a/website/docs/d/cm_version.html.markdown +++ b/website/docs/d/cm_version.html.markdown @@ -1,38 +1,340 @@ --- -subcategory: "Catalog Management" layout: "ibm" page_title: "IBM : ibm_cm_version" description: |- - Get information about Catalog Management version. + Get information about cm_version +subcategory: "Catalog Management API" --- # ibm_cm_version -Provides a read-only data source for `ibm_cm_version`. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Provides a read-only data source for cm_version. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_cm_version" "cm_version" { version_loc_id = "version_loc_id" } ``` +## Argument Reference -## Argument reference -Review the argument reference that you can specify for your data source. +Review the argument reference that you can specify for your data source. -- `version_loc_id` - (Required, String) A dotted value of `catalogID.versionID`. +* `version_loc_id` - (Required, String) The version locator. A dotted value of `catalogID`.`versionID`. -## Attribute reference -In addition to the argument reference list, you can access the following attribute references after your data source is created. +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the cm_version. +* `catalog_id` - (String) Catalog ID. + +* `configuration` - (List) List of user solicited overrides. +Nested scheme for **configuration**: + * `custom_config` - (List) Render type. + Nested scheme for **custom_config**: + * `associations` - (List) List of parameters that are associated with this configuration. + Nested scheme for **associations**: + * `parameters` - (List) Parameters for this association. + Nested scheme for **parameters**: + * `name` - (String) Name of this parameter. + * `options_refresh` - (Boolean) Refresh options. + * `config_constraints` - (Map) Map of constraint parameters that will be passed to the custom widget. + * `grouping` - (String) Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment). + * `grouping_index` - (Integer) Determines the order that this configuration item shows in that particular grouping. + * `original_grouping` - (String) Original grouping type for this configuration (3 types - Target, Resource, and Deployment). + * `type` - (String) ID of the widget type. + * `default_value` - (Map) The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`. + * `description` - (String) Key description. + * `display_name` - (String) Display name for configuration type. + * `hidden` - (Boolean) Hide values. + * `key` - (String) Configuration key. + * `options` - (List) List of options of type. + * `required` - (Boolean) Is key required to install. + * `type` - (String) Value type (string, boolean, int). + * `type_metadata` - (String) The original type, as found in the source being onboarded. + * `value_constraint` - (String) Constraint associated with value, e.g., for string type - regx:[a-z]. + +* `created` - (String) The date and time this version was created. + +* `crn` - (String) Version's CRN. + +* `deprecate_pending` - (List) Deprecation information for an Offering. +Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) + +* `deprecated` - (Boolean) read only field, indicating if this version is deprecated. + +* `entitlement` - (List) Entitlement license info. +Nested scheme for **entitlement**: + * `image_repo_name` - (String) Image repository name. + * `part_numbers` - (List) list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL. + * `product_id` - (String) Product ID. + * `provider_id` - (String) Provider ID. + * `provider_name` - (String) Provider name. + +* `flavor` - (List) Version Flavor Information. Only supported for Product kind Solution. +Nested scheme for **flavor**: + * `index` - (Integer) Order that this flavor should appear when listed for a single version. + * `label` - (String) Label for this flavor. + * `label_i18n` - (Map) A map of translated strings, by language code. + * `name` - (String) Programmatic name for this flavor. + +* `iam_permissions` - (List) List of IAM permissions that are required to consume this version. +Nested scheme for **iam_permissions**: + * `resources` - (List) Resources for this permission. + Nested scheme for **resources**: + * `description` - (String) Resource description. + * `name` - (String) Resource name. + * `role_crns` - (List) Role CRNs for this permission. + * `role_crns` - (List) Role CRNs for this permission. + * `service_name` - (String) Service name. + +* `image_manifest_url` - (String) If set, denotes a url to a YAML file with list of container images used by this version. + +* `image_pull_key_name` - (String) ID of the image pull key to use from Offering.ImagePullKeys. + +* `install` - (List) Script information. +Nested scheme for **install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + +* `is_consumable` - (Boolean) Is the version able to be shared. + +* `kind_id` - (String) Kind ID. + +* `licenses` - (List) List of licenses the product was built with. +Nested scheme for **licenses**: + * `description` - (String) License description. + * `id` - (String) License ID. + * `name` - (String) license name. + * `type` - (String) type of license e.g., Apache xxx. + * `url` - (String) URL for the license text. + +* `long_description` - (String) Long description for version. + +* `long_description_i18n` - (Map) A map of translated strings, by language code. + +* `metadata` - (Forces new resource, List) Generic data to be included with content being onboarded. Required for virtual server image for VPC. +Nested scheme for **metadata**: + * `source_url` - (String) Source URL for the version. + * `terraform_version` - (String) Version's terraform version. + * `validated_terraform_version` - (String) Version's validated terraform version. + * `version_name` - (String) Name of the version. + * `vsi_vpc` - (List) VSI information for this version. + Nested scheme for **vsi_vpc**: + * `file` - (List) Details for the stored image file. Required for virtual server image for VPC. + Nested scheme for **file**: + * `size` - (Integer) Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC. + * `images` - (List) Image operating system. Required for virtual server image for VPC. + Nested scheme for **images**: + * `id` - (String) Programmatic ID of virtual server image. Required for virtual server image for VPC. + * `name` - (String) Programmatic name of virtual server image. Required for virtual server image for VPC. + * `region` - (String) Region the virtual server image is available in. Required for virtual server image for VPC. + * `minimum_provisioned_size` - (Integer) Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC. + * `operating_system` - (List) Operating system included in this image. Required for virtual server image for VPC. + Nested scheme for **operating_system**: + * `architecture` - (String) Operating system architecture. Required for virtual server image for VPC. + * `dedicated_host_only` - (Boolean) Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC. + * `display_name` - (String) Unique, display-friendly name for the operating system. Required for virtual server image for VPC. + * `family` - (String) Software family for this operating system. Required for virtual server image for VPC. + * `href` - (String) URL for this operating system. Required for virtual server image for VPC. + * `name` - (String) Globally unique name for this operating system Required for virtual server image for VPC. + * `vendor` - (String) Vendor of the operating system. Required for virtual server image for VPC. + * `version` - (String) Major release version of this operating system. Required for virtual server image for VPC. + +* `offering_id` - (String) Offering ID. + +* `outputs` - (List) List of output values for this version. +Nested scheme for **outputs**: + * `description` - (String) Output description. + * `key` - (String) Output key. + +* `package_version` - (String) Version of the package used to create this version. + +* `pre_install` - (List) Optional pre-install instructions. +Nested scheme for **pre_install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + +* `repo_url` - (String) Content's repo URL. + +* `required_resources` - (List) Resource requirments for installation. +Nested scheme for **required_resources**: + * `type` - (String) Type of requirement. + * Constraints: Allowable values are: `mem`, `disk`, `cores`, `targetVersion`, `nodes`. + * `value` - (Map) mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value. + +* `rev` - (String) Cloudant revision. + +* `sha` - (String) hash of the content. + +* `single_instance` - (Boolean) Denotes if single instance can be deployed to a given cluster. + +* `solution_info` - (List) Version Solution Information. Only supported for Product kind Solution. +Nested scheme for **solution_info**: + * `architecture_diagrams` - (List) Architecture diagrams for this solution. + Nested scheme for **architecture_diagrams**: + * `description` - (String) Description of this diagram. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `diagram` - (List) Offering Media information. + Nested scheme for **diagram**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + * `cost_estimate` - (List) Cost estimate definition. + Nested scheme for **cost_estimate**: + * `currency` - (String) Cost estimate currency. + * `diff_total_hourly_cost` - (String) Difference in total hourly cost. + * `diff_total_monthly_cost` - (String) Difference in total monthly cost. + * `past_total_hourly_cost` - (String) Past total hourly cost. + * `past_total_monthly_cost` - (String) Past total monthly cost. + * `projects` - (List) Cost estimate projects. + Nested scheme for **projects**: + * `breakdown` - (List) Cost breakdown definition. + Nested scheme for **breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `diff` - (List) Cost breakdown definition. + Nested scheme for **diff**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `metadata` - (Map) Project metadata. + * `name` - (String) Project name. + * `past_breakdown` - (List) Cost breakdown definition. + Nested scheme for **past_breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `time_generated` - (String) When this estimate was generated. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_cost` - (String) Total monthly cost. + * `version` - (String) Cost estimate version. + * `dependencies` - (List) Dependencies for this solution. + Nested scheme for **dependencies**: + * `catalog_id` - (String) Optional - If not specified, assumes the Public Catalog. + * `flavors` - (List) Optional - List of dependent flavors in the specified range. + * `id` - (String) Optional - Offering ID - not required if name is set. + * `name` - (String) Optional - Programmatic Offering name. + * `version` - (String) Required - Semver value or range. + * `features` - (List) Features - titles only. + Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + +* `source_url` - (String) Content's source URL (e.g git repo). + +* `state` - (List) Offering state. +Nested scheme for **state**: + * `current` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `current_entered` - (String) Date and time of current request. + * `pending` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `pending_requested` - (String) Date and time of pending request. + * `previous` - (String) one of: new, validated, account-published, ibm-published, public-published. + +* `tags` - (List) List of tags associated with this catalog. + +* `tgz_url` - (String) File used to on-board this version. + +* `updated` - (String) The date and time this version was last updated. + +* `validation` - (List) Validation response. +Nested scheme for **validation**: + * `last_operation` - (String) Last operation (e.g. submit_deployment, generate_installer, install_offering. + * `message` - (String) Any message needing to be conveyed as part of the validation job. + * `requested` - (String) Date and time of last validation was requested. + * `state` - (String) Current validation state - , in_progress, valid, invalid, expired. + * `target` - (Map) Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type. + * `validated` - (String) Date and time of last successful validation. + +* `version` - (String) Version of content type. + +* `version_id` - (String) Unique ID. + +* `version_locator` - (String) A dotted value of `catalogID`.`versionID`. + +* `whitelisted_accounts` - (List) Whitelisted accounts for version. -- `catalog_id` - (String) The catalog ID. -- `crn` - (String) The CRN version. -- `id` - (String) The unique identifier of the `ibm_cm_version`. -- `offering_id` - (String) The offering ID. -- `repo_url` - (String) The URL of the content repository. -- `sha` - (String) The hash of the content. -- `source_url` - (String) The source URL of the content repository, for example, Git repository. -- `tgz_url` - (String) File used to onboard the version. -- `version` - (String) Version of the content type. diff --git a/website/docs/d/container_alb_cert.html.markdown b/website/docs/d/container_alb_cert.html.markdown index c7aa82b50..401b5a54c 100644 --- a/website/docs/d/container_alb_cert.html.markdown +++ b/website/docs/d/container_alb_cert.html.markdown @@ -9,7 +9,7 @@ description: |- # ibm_container_alb_cert Retrieve information about all the Kubernetes cluster ALB certificate on IBM Cloud as a read-only data source. -## Example Usage +## Example usage The following example retrieves information of an ALB certificate. ```terraform diff --git a/website/docs/d/container_cluster.html.markdown b/website/docs/d/container_cluster.html.markdown index 815d61418..fed8bf814 100644 --- a/website/docs/d/container_cluster.html.markdown +++ b/website/docs/d/container_cluster.html.markdown @@ -64,6 +64,7 @@ In addition to all argument reference list, you can access the following attribu - `bounded_services` - List of strings - A list of IBM Cloud services that are bounded to the cluster. - `crn` - (String) The CRN of the cluster. - `id` - (String) The unique identifier of the cluster. +- `image_security_enforcement` - (Bool) Indicates if image security enforcement policies are enabled in a cluster. - `ingress_hostname` - (String) The Ingress host name. - `ingress_secret` - (String) The name of the Ingress secret. - `name` - (String) The name of the cluster. diff --git a/website/docs/d/container_cluster_config.html.markdown b/website/docs/d/container_cluster_config.html.markdown index 8e398b587..712d08f0a 100644 --- a/website/docs/d/container_cluster_config.html.markdown +++ b/website/docs/d/container_cluster_config.html.markdown @@ -82,8 +82,8 @@ resource "kubernetes_namespace" "example" { } } ``` -## Example usage5 -Example Usage for connecting to Kubernetes provider for classic OpenShift cluster with host and token. +## Example usage +Example usage for connecting to Kubernetes provider for classic OpenShift cluster with host and token. ```terraform data "ibm_container_cluster_config" "cluster_foo" { diff --git a/website/docs/d/container_dedicated_host.html.markdown b/website/docs/d/container_dedicated_host.html.markdown new file mode 100644 index 000000000..ae0c542e9 --- /dev/null +++ b/website/docs/d/container_dedicated_host.html.markdown @@ -0,0 +1,61 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host" +description: |- + Get information about a dedicated host. +--- + +# ibm_container_dedicated_host + +Retrieve information about a dedicated host. For more information about dedicated hosts, see [Creating and managing dedicated hosts on VPC Gen 2 infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-dedicated-hosts). + + +## Example usage +In the following example, you can retrieve a dedicated host: + +```terraform +data "ibm_container_dedicated_host" "test_dhost" { + host_id = "abcd12-dh-abcdefgh1234567-abcd123-acbd1234" + host_pool_id = "dh-abcdefgh1234567" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. +- `host_id` - (Required, String) The unique identifier of the dedicated host. +- `host_pool_id` - (Required, String) The unique identifier of the dedicated host pool the dedicated host is associated with. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your data source is created. +- `flavor` - (String) The name of the dedicated host. +- `placement_enabled`- (Bool) Describes if the placement on the dedicated host is enabled +- `life_cycle` - (List) A nested block describes the lifecycle state of the dedicated host. + + Nested scheme for `life_cycle`: + - `actual_state` - (String) The actual state of the dedicated host. + - `desired_state` - (String) The desired state of the dedicated host. + - `message` - (String) Information message about the dedicated host's lifecycle. + - `message_date` - (String) The date of the information message. + - `message_details` - (String) Additional details of the information message. + - `message_details_date` - (String) The date of the additional details. +- `resources` - (List) A nested block describes the resources of the dedicated host. + + Nested scheme for `resources`: + - `capacity` - (List) A nested block describes the capacity of the dedicated host. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Memory capacity of the dedicated host. + - `vcpu` - (Int) VCPU capacity of the dedicated host. + - `consumed` - (List) A nested block describes the consumed resources of the dedicated host. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Consumed memory capacity of the dedicated host. + - `vcpu` - (Int) Consumed VCPU capacity of the dedicated host. +- `workers` - (List) A nested block describes the workers associated with this dedicated host. + + Nested scheme for `workers`: + - `cluster_id` - (String) The ID of the cluster the worker is associated with. + - `flavor` - (String) The flavor of the worker. + - `worker_id` - (String) The ID of the worker. + - `worker_pool_id` - (String) The ID of the worker pool the worker is associated with. +- `zone` - (String) The zone of the dedicated host. diff --git a/website/docs/d/container_dedicated_host_flavor.html.markdown b/website/docs/d/container_dedicated_host_flavor.html.markdown new file mode 100644 index 000000000..7be504813 --- /dev/null +++ b/website/docs/d/container_dedicated_host_flavor.html.markdown @@ -0,0 +1,42 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host_flavor" +description: |- + Get information about a dedicated host flavor. +--- + +# ibm_container_dedicated_host_flavor + +Retrieve information about a dedicated host flavor. For more information, about the use of dedicated host flavors, see [Creating a cluster on dedicated host infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-clusters#cluster_dedicated_host_cli). + + +## Example usage +In the following example, you can retrieve a dedicated host flavor: + +```terraform +data "ibm_container_dedicated_host_flavor" "test_dhost_flavor" { + host_flavor_id = "bx2d.host.152x608" + zone = "us-south-1" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. +- `host_flavor_id` - (Required, String) The unique identifier of the dedicated host flavor. +- `zone` - (Required, String) The zone of the dedicated host flavor. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your data source is created. +- `flavor_class` - (String) The flavor class of the dedicated host flavor. +- `region` (String) The region of the dedicated host flavor. +- `deprecated` - (String) Describes if the dedicated host flavor is deprecated. +- `max_vcpus` - (String) The maximum available vcpus in the dedicated host flavor. +- `max_memory` - (String) The maximum available memory in the dedicated host flavor. +- `instance_storage` - (List) A nested block describes the instance storage of this dedicated host flavor. + + Nested scheme for `instance_storage`: + - `count` - (Int) The count of the disks. + - `size` - (Int) The size of the instance storage. + diff --git a/website/docs/d/container_dedicated_host_flavors.html.markdown b/website/docs/d/container_dedicated_host_flavors.html.markdown new file mode 100644 index 000000000..63125d0f6 --- /dev/null +++ b/website/docs/d/container_dedicated_host_flavors.html.markdown @@ -0,0 +1,44 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host_flavors" +description: |- + List all the dedicated host flavors from a zone. +--- + +# ibm_container_dedicated_host_flavors + +List all the dedicated host flavors from a zone. For more information, about the use of dedicated host flavors, see [Creating a cluster on dedicated host infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-clusters#cluster_dedicated_host_cli). + + +## Example usage +In the following example, you can retrieve dedicated host flavors from a zone: + +```terraform +data "ibm_container_dedicated_host_flavors" "test_dhost_flavor" { + zone = "us-south-1" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. +- `zone` - (Required, String) The zone of the dedicated host flavor. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your data source is created. +- `host_flavors` - (List) A nested block describes the host flavors under the specified zone. + + Nested scheme for `host_flavors`: + - `host_flavor_id` - (String) The unique identifier of the dedicated host flavor. + - `flavor_class` - (String) The flavor class of the dedicated host flavor. + - `region` (String) The region of the dedicated host flavor. + - `deprecated` - (String) Describes if the dedicated host flavor is deprecated. + - `max_vcpus` - (String) The maximum available vcpus in the dedicated host flavor. + - `max_memory` - (String) The maximum available memory in the dedicated host flavor. + - `instance_storage` - (List) A nested block describes the instance storage of this dedicated host flavor. + + Nested scheme for `instance_storage`: + - `count` - (Int) The count of the disks. + - `size` - (Int) The size of the instance storage. + diff --git a/website/docs/d/container_dedicated_host_pool.html.markdown b/website/docs/d/container_dedicated_host_pool.html.markdown new file mode 100644 index 000000000..442362762 --- /dev/null +++ b/website/docs/d/container_dedicated_host_pool.html.markdown @@ -0,0 +1,49 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host_pool" +description: |- + Get information about a dedicated host pool. +--- + +# ibm_container_dedicated_host_pool + +Retrieve information about a dedicated host pool. For more information, about dedicated host pool, see [Creating and managing dedicated hosts on VPC Gen 2 infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-dedicated-hosts). + + +## Example usage +In the following example, you can retrieve a dedicated host pool: + +```terraform +data "ibm_container_dedicated_host_pool" "test_dhostpool" { + host_pool_id = "dh-abcdefgh1234567" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. +- `host_pool_id` - (Required, String) The unique identifier of the dedicated host pool. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your data source is created. +- `name` - (String) The name of the dedicated host pool. +- `metro`- (String) The metro to create the dedicated host pool in. +- `flavor_class` - (String) The flavor class of the dedicated host pool. +- `host_count` (Int) The count of the hosts under the dedicated host pool. +- `state` - (String) The state of the dedicated host pool. +- `zones` - (List) A nested block describes the zones of this dedicated host pool. + + Nested scheme for `zones`: + - `capacity` - (Map) A nested block describes the capacity of the zone. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Memory capacity of the zone. + - `vcpu` - (Int) VCPU capacity of the zone. + - `host_count` - (Int) The count of the hosts under the zone. + - `zone` - (String) The name of the zone. +- `worker_pools` - (List) A nested block describes the worker pools of this dedicated host pool. + + Nested scheme for `worker_pools`: + - `cluster_id` - (String) The ID of the cluster. + - `worker_pool_id` - (String) The unique identifier of the worker pool. + diff --git a/website/docs/d/container_storage_attachment.html.markdown b/website/docs/d/container_storage_attachment.html.markdown new file mode 100644 index 000000000..26810fecd --- /dev/null +++ b/website/docs/d/container_storage_attachment.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_vpc_worker_storage" +description: |- + Fetch the information about IBM container vpc worker storage attachment. +--- + +# ibm_container_storage_attachment + +Import the details of a VPC storage volume attachment of a VPC worker node as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about VPC storage volume attachment, see [Attaching a block storage volume](https://cloud.ibm.com/docs/vpc?topic=vpc-attaching-block-storage&interface=ui). + + +## Example usage + +In the following example, you can import a storage attachment of a VPC cluster worker node: + +```terraform + +data "ibm_container_storage_attachment" "volume_attach"{ + volume_attachment_id = "3567365d-7b9a-cc44-97ac-ef201653ea21" + cluster = "tf-cluster" + worker = "kube-c08evsgd0anad0v8c76g-gen2newvpc-default-00000116" +} +``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +* `cluster` - (Required, String) The name or ID of the cluster. +* `volume_attachment_id` - (Required, String) The VPC volume attachment ID. +* `worker` - (Required, String) The VPC cluster worker node ID. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +* `id` - (String) The unique identifier of the worker storage resource. The id is composed of /. +* `status` - (String) The volume attachment status. +* `volume` - (String) The VPC volume ID. +* `volume_attachment_name` - (String) The volume attachment name. +* `volume_type` - (String) The volume attachment type. diff --git a/website/docs/d/container_vpc_cluster.html.markdown b/website/docs/d/container_vpc_cluster.html.markdown index 7a06d2931..b8a5ae5a1 100644 --- a/website/docs/d/container_vpc_cluster.html.markdown +++ b/website/docs/d/container_vpc_cluster.html.markdown @@ -46,6 +46,7 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN of the cluster. - `health` - (String) The health of the cluster master. - `id` - (String) The unique identifier of the cluster. +- `image_security_enforcement` - (Bool) Indicates if image security enforcement policies are enabled in a cluster. - `ingress_hostname`- (String) The hostname that was assigned to your Ingress subdomain. - `ingress_secret` - (String) The name of the Kubernetes secret that was created for your Ingress subdomain. - `kube_version` - (String) The Kubernetes version of the cluster, including the major.minor version. @@ -66,6 +67,7 @@ In addition to all argument reference list, you can access the following attribu - `worker_count` - (Integer) The total number of worker nodes in this worker pool. - `isolation` - (String) The level of hardware isolation for the worker node. For VPC clusters, this value is always `shared`. - `id` - (String) The ID of the worker pool. + - `host_pool_id` - (String) The ID of the dedicated host pool. - `labels` - List of strings - A list of labels that are added to the worker pool. - `zones` - List of objects - A list of zones that are attached to the worker pool. diff --git a/website/docs/d/container_vpc_cluster_worker.html.markdown b/website/docs/d/container_vpc_cluster_worker.html.markdown index ccb1dbb44..32e5c153a 100644 --- a/website/docs/d/container_vpc_cluster_worker.html.markdown +++ b/website/docs/d/container_vpc_cluster_worker.html.markdown @@ -13,7 +13,7 @@ Retrieve information about the worker nodes of your IBM Cloud Kubernetes Service The following example retrieves information about a worker node with the ID in the cluster. ```terraform -data "ibm_container_cluster_worker" "worker_foo" { +data "ibm_container_vpc_cluster_worker" "worker_foo" { worker_id = "dev-mex10-pa70c4414695c041518603bfd0cd6e333a-w1" cluster_name_id = "test" } @@ -31,6 +31,7 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `cidr` - (String) The CIDR of the network. +- `host_pool_id` - (String) The ID of the dedicated host pool the worker is associated with. - `ip_address` - (String) The IP address of the worker pool that the worker node belongs to. - `network_interfaces` - (String) The network interface of the cluster. - `pool_id` - (String) The ID of the worker pool that the worker node belongs to. diff --git a/website/docs/d/container_vpc_cluster_worker_pool.html.markdown b/website/docs/d/container_vpc_cluster_worker_pool.html.markdown index 66a479c42..4754e1da7 100644 --- a/website/docs/d/container_vpc_cluster_worker_pool.html.markdown +++ b/website/docs/d/container_vpc_cluster_worker_pool.html.markdown @@ -30,6 +30,7 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `flavor` - (String) The flavour of the worker node. +- `host_pool_id` -(String) The ID of the dedicated host pool the worker pool is associated with. - `id` - (String) The unique identifier of the worker pool resource, as /. - `isolation` - (String) Isolation for the worker node. - `labels` - (String) Labels on all the workers in the worker pool. diff --git a/website/docs/d/container_vpc_worker_storage.html.markdown b/website/docs/d/container_vpc_worker_storage.html.markdown deleted file mode 100644 index e0d6269ab..000000000 --- a/website/docs/d/container_vpc_worker_storage.html.markdown +++ /dev/null @@ -1,42 +0,0 @@ ---- -subcategory: "Kubernetes Service" -layout: "ibm" -page_title: "IBM: container_vpc_worker_storage" -description: |- - Fetch the information about IBM container vpc worker storage attachment. ---- - -# ibm_container_vpc_worker_storage - -Import the details of a VPC storage volume attachment of a VPC worker node as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about VPC storage volume attachment, see [Attaching a block storage volume](https://cloud.ibm.com/docs/vpc?topic=vpc-attaching-block-storage&interface=ui). - - -## Example usage - -In the following example, you can import a storage attachment of a VPC cluster worker node: - -```terraform -data "ibm_container_vpc_worker_volume" "volume_attach"{ - volume_attachment_id = "3567365d-7b9a-cc44-97ac-ef201653ea21" - cluster = "tf-cluster" - worker = "kube-c08evsgd0anad0v8c76g-gen2newvpc-default-00000116" -} -``` - -## Argument reference - -Review the argument references that you can specify for your data source. - -* `cluster` - (Required, String) The name or ID of the cluster. -* `volume_attachment_id` - (Required, String) The VPC volume attachment ID. -* `worker` - (Required, String) The VPC cluster worker node ID. - -## Attribute reference - -In addition to all argument reference list, you can access the following attribute references after your data source is created. - -* `id` - (String) The unique identifier of the worker storage resource. The id is composed of /. -* `status` - (String) The volume attachment status. -* `volume` - (String) The VPC volume ID. -* `volume_attachment_name` - (String) The volume attachment name. -* `volume_type` - (String) The volume attachment type. diff --git a/website/docs/d/container_worker_pool.html.markdown b/website/docs/d/container_worker_pool.html.markdown index adb2968f3..783b517b3 100644 --- a/website/docs/d/container_worker_pool.html.markdown +++ b/website/docs/d/container_worker_pool.html.markdown @@ -40,3 +40,5 @@ Review the attribute references that are exported. - `public_vlan` - (String) The ID of the public VLAN. - `worker_count` - (String) Number of workers attached to this zone. - `zone` - (String) Zone name. +- `crk` - Root Key ID for boot volume encryption. +- `kms_instance_id` - Instance ID for boot volume encryption. diff --git a/website/docs/d/cos_bucket.html.markdown b/website/docs/d/cos_bucket.html.markdown index 1e86ebfcd..f677ac75e 100644 --- a/website/docs/d/cos_bucket.html.markdown +++ b/website/docs/d/cos_bucket.html.markdown @@ -6,9 +6,10 @@ description: |- Get information about IBM Cloud Object Storage bucket. --- + # ibm_cos_bucket -Creates an IBM Cloud Object Storage bucket. It also allows object storage buckets to be updated and deleted. The ibmcloud_api_key used by Terraform must have been granted sufficient IAM rights to create and modify IBM Cloud Object Storage buckets and have access to the Resource Group the Cloud Object Storage bucket will be associated with. See https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-iam for more details on setting IAM and Access Group rights to manage COS buckets. +Retrive an IBM Cloud Object Storage bucket. It also allows object storage buckets to be updated and deleted. The ibmcloud_api_key used by Terraform must have been granted sufficient IAM rights to create and modify IBM Cloud Object Storage buckets and have access to the Resource Group the Cloud Object Storage bucket will be associated with. See https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-iam for more details on setting IAM and Access Group rights to manage COS buckets. ## Example usage @@ -35,19 +36,78 @@ output "bucket_private_endpoint" { } ``` +# cos satellite bucket + +Retrive a cos satellite bucket. See the architecture https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-about-cos-satellite for more details. We are using existing cos instance to create bucket , so no need to create any cos instance via a terraform. Cos satellite does not support all features see the section **What features are currently supported?** in https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-about-cos-satellite. +IBM Satellite documentation https://cloud.ibm.com/docs/satellite?topic=satellite-getting-started . We are supporting object versioning and expiration features as of now. Firewall is not supported yet. + +## Example usage + +```terraform +data "ibm_satellite_location" "location" { + location = var.location +} + +data "ibm_cos_bucket" "cos-bucket-sat" { + bucket_name = "cos-sat-terraform" + resource_instance_id = data.ibm_resource_instance.cos_instance.id + satellite_location_id = data.ibm_satellite_location.location.id +} +``` + +# ibm_cos_bucket_replication_rule + +Retrieves information of replication configuration on an existing bucket. . For more information, about configuration options, see [Replicating objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-replication-overview). + +To configure a replication policy on a bucket, you must enable object versioning on both source and destination buckets by using the [Versioning objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). + +# Key Protect Enabled COS bucket + +Retrieves a COS bucket enabled with Key protect root key for data encryption. +https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/kms_key + + + +# Hyper Protect Crypto Services (HPCS) Enabled COS bucket +Retrieves a COS bucket enabled with data encryption using root key that is created and managed by Hyper Protect Crypto Services. +``` +data "ibm_kms_key" "test" { + instance_id = "guid-of-hs-crypto-instance" + key_name = "name-of-key" +} +OR +data "ibm_kms_key" "test" { + instance_id = "guid-of-hs-crypto-instance" + alias = "alias_name" +} +OR +data "ibm_kms_key" "test" { + instance_id = "guid-of-hs-crypto-instance" + limit = 100 + key_name = "name-of-key" +} +resource "ibm_cos_bucket" "smart-us-south" { + bucket_name = "atest-bucket" + resource_instance_id = "cos-instance-id" + region_location = "us-south" + storage_class = "smart" + key_protect = data.ibm_kms_key.test.key.0.crn +} + +``` ## Argument reference Review the argument references that you can specify for your data source. - `bucket_name` - (Required, String) The name of the bucket. -- `bucket_region` - (Required, String) The region of the bucket. -- `bucket_type` - (Required, String) The type of the bucket. Supported values are `single_site_location`, `region_location`, and `cross_region_location`. +- `bucket_region` - (Optional, String) The region of the bucket. +- `bucket_type` - (Optional, String) The type of the bucket. Supported values are `single_site_location`, `region_location`, and `cross_region_location`. - `endpoint_type` - (Optional, String) The type of the endpoint either `public` or `private` or `direct` to be used for the buckets. Default value is `public`. - `resource_instance_id` - (Required, String) The ID of the IBM Cloud Object Storage service instance for which you want to create a bucket. -- `storage_class`- (Required, String) Storage class of the bucket. Supported values are `standard`, `vault`, `cold`, `flex`, `smart`. +- `storage_class`- (Optional, String) Storage class of the bucket. Supported values are `standard`, `vault`, `cold`, `smart` for `standard` and `lite` COS plans, `onerate_active` for `cos-one-rate-plan` COS instance. +- `satellite_location_id` - (Optional, String) satellite location id. Provided by end users. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - - `allowed_ip`- (String) List of `IPv4` or `IPv6` addresses in CIDR notation to be affected by firewall. - `activity_tracking` (List) Nested block with the following structure. @@ -60,25 +120,42 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `archive_rule`: - `days` - (String) Specifies the number of days when the specific rule action takes effect. - `enable`- (Bool) Specifies archive rule status either `enable` or `disable` for a bucket. - - `type` - (String) Specifies the storage class or archive type to which you want the object to transition. Supported values are `Glacier` or `Accelerated`. - `rule_id` - (String) Unique identifier for the rule. Archive rules allow you to set a specific time frame after which objects transition to archive. + - `type` - (String) Specifies the storage class or archive type to which you want the object to transition. Supported values are `Glacier` or `Accelerated`. +- `abort_incomplete_multipart_upload_days` (List) Nested block with the following structure. + + Nested scheme for `abort_incomplete_multipart_upload_days`: + - `days_after_initiation` - (Integer) Specifies the number of days that govern the automatic cancellation of part upload. Clean up incomplete multi-part uploads after a period of time. Must be a value greater than 0. + - `enable` - (Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (String) A rule with a prefix will only apply to the objects that match. You can use multiple rules for different actions for different prefixes within the same bucket. + - `rule_id` - (String) Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket. - `crn` - (String) The CRN of the bucket. - `cross_region_location` - (String) The location to create a cross-regional bucket. - `expire_rule` (List) Nested block with the following structure. Nested scheme for `expire_rule`: - `days` - (String) Specifies the number of days when the specific rule action takes effect. + - `date` - (String) After the specifies date , the current version of objects in your bucket expires. - `enable`- (Bool) Specifies expire rule status either `enable` or `disable` for a bucket. + - `expired_object_delete_marker` - (Bool) Expired object delete markers can be automatically cleaned up to improve performance in your bucket. This cannot be used alongside version expiration. - `prefix` - (String) Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. - `rule_id` - (String) Unique identifier for the rule. Expire rules allow you to set a specific time frame after which objects are deleted. -- `id` - (String) The ID of the bucket. -- `key_protect` - (String) The CRN of the IBM Key Protect instance where a root key is already provisioned. +- `hard_quota` - (String) Maximum bytes for the bucket. +- `id` - (String) The ID of the bucket. +- `key_protect` - (String) The CRN of the IBM Key Protect instance where a root key is already provisioned. - `metrics_monitoring`- (List) Nested block with the following structure. - Nested scheme for `metrics_monitoring`: - - `metrics_monitoring_crn` - (String) The first time `metrics_monitoring` is configured. The instance of IBM Cloud monitoring that will receive the bucket metrics. - - `request_metrics_enabled` - (Bool) If set to `true`, all request metrics `ibm_cos_bucket_all_request` is sent to the monitoring service at 1 minute (`@1mins`) granularity. - - `usage_metrics_enabled`- (Bool) If set to **true**, all usage metrics (that is `bytes_used`) is sent to the monitoring service. + Nested scheme for `metrics_monitoring`: + - `metrics_monitoring_crn` - (String) The first time `metrics_monitoring` is configured. The instance of IBM Cloud monitoring that will receive the bucket metrics. + - `request_metrics_enabled` - (Bool) If set to `true`, all request metrics `ibm_cos_bucket_all_request` is sent to the monitoring service at 1 minute (`@1mins`) granularity. + - `usage_metrics_enabled`- (Bool) If set to **true**, all usage metrics (that is `bytes_used`) is sent to the monitoring service. +- `noncurrent_version_expiration` (List) Nested block with the following structure. + + Nested scheme for `noncurrent_version_expiration`: + - `enable` - (Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `noncurrent_days` - (Int) Configuration parameter in your policy that says how long to retain a non-current version before deleting it. Must be greater than 0. + - `prefix` - (String) The rule applies to any objects with keys that match this prefix. You can use multiple rules for different actions for different prefixes within the same bucket. + - `rule_id` - (String) Unique identifier for the rule. Rules allow you to remove versions from objects. Set Rule ID for cos bucket. - `object_versioning` - (List) Nestedblock have the following structure: Nested scheme for `object_verionining`: @@ -92,6 +169,18 @@ In addition to all argument reference list, you can access the following attribu - `maximum` - (String) Specifies maximum duration of time an object can be kept unmodified in the bucket. - `minimum` - (String) Specifies minimum duration of time an object must be kept unmodified in the bucket. - `permanent` - (String) Specifies a permanent retention status either enable or disable for a bucket. -- `hard_quota` - (String) Maximum bytes for the bucket. +- `replication_rule`- (List) Nested block have the following structure: + + Nested scheme for `replication_rule`: + - `rule_id`- (String) The rule id. + - `enable`- (Bool) Specifies whether the rule is enabled. Specify true for Enabling it or false for Disabling it. + - `prefix`- (String) An object key name prefix that identifies the subset of objects to which the rule applies. + - `priority`- (Int) A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority + - `deletemarker_replication_status`- (Bool) Specifies whether Object storage replicates delete markers. Specify true for Enabling it or false for Disabling it. + - `destination_bucket_crn`- (String) The CRN of your destination bucket that you want to replicate to. + - `single_site_location` - (String) The location to create a single site bucket. - `storage_class` - (String) The storage class of the bucket. +- `s3_endpoint_public` - (String) Public endpoint for cos bucket. +- `s3_endpoint_private` - (String) Private endpoint for cos bucket. +- `s3_endpoint_direct` - (String) Direct endpoint for cos bucket. diff --git a/website/docs/d/cos_bucket_object.html.markdown b/website/docs/d/cos_bucket_object.html.markdown index 15aa5b1fc..46137e838 100644 --- a/website/docs/d/cos_bucket_object.html.markdown +++ b/website/docs/d/cos_bucket_object.html.markdown @@ -7,6 +7,7 @@ description: |- --- # ibm_cos_bucket_object + Retrieves information of an object in IBM Cloud Object Storage bucket. For more information, about an IBM Cloud Object Storage bucket, see [Create some buckets to store your data](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-getting-started-cloud-object-storage#gs-create-buckets). ## Example usage @@ -46,10 +47,10 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `id` - (String) The ID of the object. +- `id` - (String) The ID of an object. - `body` - (String) Literal string value of an object content. Only supported for `text/*` and `application/json` content types. - `content_length` - (String) A standard MIME type describing the format of an object data. - `content_type` - (String) A standard MIME type describing the format of an object data. - `etag` - (String) Computed MD5 hexdigest of an object content. -- `last_modified` - (Timestamp) Last modified date of the object. A GMT formatted date. -- `object_sql_url` - (String) Access the object using an SQL Query instance. The SQL URL is a reference url used inside of an SQL statement. The reference url is used to perform queries against objects storing structured data. +- `last_modified` - (Timestamp) Last modified date of an object in a GMT formatted date. +- `object_sql_url` - (String) Access the object using an SQL Query instance. The SQL URL is a reference URL used inside an SQL statement. The reference URL is used to perform queries against objects storing structured data. diff --git a/website/docs/d/database.html.markdown b/website/docs/d/database.html.markdown index c37c4b5bd..aa0e71f38 100644 --- a/website/docs/d/database.html.markdown +++ b/website/docs/d/database.html.markdown @@ -8,15 +8,13 @@ description: |- # ibm_database -Create a read-only copy of an existing IBM Cloud database service. For more information, about an IBM Cloud datbase service instance, see [provisioning databases](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-provisioning). +Retrieve information about an existing [IBM Cloud Database instance](https://cloud.ibm.com/docs/cloud-databases). **Note** Configuration of an IBM Cloud Databases `data_source` requires that the `region` parameter is set for the IBM provider in the `provider.tf`. The region must be the same as the `location` that the IBM Cloud Databases instance is deployed into. If not specified, `us-south` is used by default. A `terraform refresh` of the `data_source` fails if the region and the location differ. - ## Example usage -The following example creates a read-only copy of the `mydatabase` instance in `us-east`. - +The following example retrieves information about the `mydatabase` instance in `us-east`. ```terraform data "ibm_database" "database" { @@ -25,7 +23,6 @@ data "ibm_database" "database" { } ``` - ## Argument reference Review the argument reference that you can specify for your data source. @@ -34,24 +31,23 @@ Review the argument reference that you can specify for your data source. - `resource_group_id`- (Optional, String) The ID of the resource group where the IBM Cloud Databases instance is deployed into. The default is `default`. - `service` - (Optional, String) The service type of the instance. To retrieve this value, run `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. - ## Attribute reference In addition to all argument references list, you can access the following attribute references after your data source is created. - `adminuser` - (String) The user ID of the default administration user for the database, such as `admin` or `root`. - `cert_file_path` - (String) The absolute path to certificate PEM file. -- `connectionstrings` (List) List of connection strings by userid for the database. For information about how to use connection strings, see the [documentation](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-connection-strings). The results are returned in pairs of the userid and string: `connectionstrings.1.name = admin connectionstrings.1.string = postgres://admin:$PASSWORD@12345aa1-1111-1111-a1aa-a1aaa11aa1a1.a1a1a111a1a11a1a111a111a1a111a111.databases.appdomain.cloud:32554/ibmclouddb?sslmode=verify-full`. +- `connectionstrings` - **Deprecated** - (List) List of connection strings by userid for the database - replaced by `bm_database_connection` For information about how to use connection strings, see the [documentation](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-connection-strings). The results are returned in pairs of the userid and string: `connectionstrings.1.name = admin connectionstrings.1.string = postgres://admin:$PASSWORD@12345aa1-1111-1111-a1aa-a1aaa11aa1a1.a1a1a111a1a11a1a111a111a1a111a111.databases.appdomain.cloud:32554/ibmclouddb?sslmode=verify-full`. +- `configuration_schema` (String) Database Configuration Schema in JSON format. - `id` - (String) The CRN of the IBM Cloud Databases instance. - `guid` - (String) The unique identifier of the IBM Cloud Databases instance. - `plan` - (String) The service plan of the IBM Cloud Databases instance. - `location` - (String) The location where the IBM Cloud Databases instance is deployed into. - `status` - (String) The status of the IBM Cloud Databases instance. -- `status` - (String) The status of resource instance. - `version` - (String) The database version. - `platform_options`- (String) The CRN of key protect key. Nested scheme for `platform_options`: - - `key_protect_key_id`- (String) The CRN of key protect key. + - `key_protect_key_id`- **Deprecated** - (String) The CRN of key protect key. - replaced by `disk_encryption_key_crn` - `disk_encryption_key_crn`- (String) The CRN of disk encryption key. - `backup_encryption_key_crn`- (String) The CRN of backup encryption key. diff --git a/website/docs/d/database_backup.html.markdown b/website/docs/d/database_backup.html.markdown new file mode 100644 index 000000000..cf9e449eb --- /dev/null +++ b/website/docs/d/database_backup.html.markdown @@ -0,0 +1,47 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_backup" +description: |- + Get information about Backup +subcategory: "Cloud Databases" +--- + +# ibm_database_backup + +Provides a read-only data source for Backup. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_backup" "database_backup" { + backup_id = "" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `backup_id` - (Required, Forces new resource, String) Backup ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `backup_id` - The unique identifier of the Backup. +* `created_at` - (Optional, String) Date and time when this backup was created. + +* `deployment_id` - (Optional, String) ID of the deployment this backup relates to. + +* `download_link` - (Optional, String) URI which is currently available for file downloading. + +* `is_downloadable` - (Optional, Boolean) Is this backup available to download?. + +* `is_restorable` - (Optional, Boolean) Can this backup be used to restore an instance?. + +* `status` - (Optional, String) The status of this backup. + * Constraints: Allowable values are: `running`, `completed`, `failed`. + +* `type` - (Optional, String) The type of backup. + * Constraints: Allowable values are: `scheduled`, `on_demand`. + diff --git a/website/docs/d/database_backups.html.markdown b/website/docs/d/database_backups.html.markdown new file mode 100644 index 000000000..58495261d --- /dev/null +++ b/website/docs/d/database_backups.html.markdown @@ -0,0 +1,43 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_backups" +description: |- + Get information about Backups +subcategory: "Cloud Databases" +--- + +# ibm_database_backups + +Provides a read-only data source for Backups. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_backups" "database_backups" { + deployment_id = "" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `deployment_id` - (Required, String) ID of the deployment this backup relates to. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `backups` - (Optional, List) An array of backups. +Nested scheme for **backups**: + * `created_at` - (Optional, String) Date and time when this backup was created. + * `deployment_id` - (Optional, String) ID of the deployment this backup relates to. + * `download_link` - (Optional, String) URI which is currently available for file downloading. + * `backup_id` - (Optional, String) ID of this backup. + * `is_downloadable` - (Optional, Boolean) Is this backup available to download?. + * `is_restorable` - (Optional, Boolean) Can this backup be used to restore an instance?. + * `status` - (Optional, String) The status of this backup. + * Constraints: Allowable values are: `running`, `completed`, `failed`. + * `type` - (Optional, String) The type of backup. + * Constraints: Allowable values are: `scheduled`, `on_demand`. + diff --git a/website/docs/d/database_connection.html.markdown b/website/docs/d/database_connection.html.markdown new file mode 100644 index 000000000..84d5859d9 --- /dev/null +++ b/website/docs/d/database_connection.html.markdown @@ -0,0 +1,370 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_connection" +description: |- + Get information about database_connection +subcategory: "Cloud Databases" +--- + +# ibm_database_connection + +Provides a read-only data source for database_connection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_connection" "database_connection" { + endpoint_type = "public" + deployment_id = ibm_database.my_db.id + user_id = "user_id" + user_type = "database" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `endpoint_type` - (Required, String) Endpoint Type. The endpoint must be enabled on the deployment before its connection information can be fetched. + * Constraints: Allowable values are: `public`, `private`. +* `deployment_id` - (Required, String) Deployment ID. +* `user_id` - (Required, String) User ID. +* `user_type` - (Required, String) User type. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the database_connection. +* `amqps` - (Optional, List) +Nested scheme for **amqps**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `analytics` - (Optional, List) +Nested scheme for **analytics**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `bi_connector` - (Optional, List) +Nested scheme for **bi_connector**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `cli` - (Optional, List) CLI Connection. +Nested scheme for **cli**: + * `arguments` - (Optional, List) Sets of arguments to call the executable with. The outer array corresponds to a possible way to call the CLI; the inner array is the set of arguments to use with that call. + * `bin` - (Optional, String) The name of the executable the CLI should run. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `environment` - (Optional, Map) A map of environment variables for a CLI connection. + * `type` - (Optional, String) Type of connection being described. + +* `emp` - (Optional, List) +Nested scheme for **emp**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `grpc` - (Optional, List) +Nested scheme for **grpc**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `https` - (Optional, List) +Nested scheme for **https**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `mongodb` - (Optional, List) +Nested scheme for **mongodb**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `database` - (Optional, String) Name of the database to use in the URI connection. + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `replica_set` - (Optional, String) Name of the replica set to use in the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `mqtts` - (Optional, List) +Nested scheme for **mqtts**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `mysql` - (Optional, List) +Nested scheme for **mysql**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `database` - (Optional, String) Name of the database to use in the URI connection. + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `ops_manager` - (Optional, List) +Nested scheme for **ops_manager**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `postgres` - (Optional, List) +Nested scheme for **postgres**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `database` - (Optional, String) Name of the database to use in the URI connection. + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `rediss` - (Optional, List) +Nested scheme for **rediss**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `database` - (Optional, Integer) Number of the database to use in the URI connection. + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + +* `secure` - (Optional, List) +Nested scheme for **secure**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `bundle` - (Optional, List) + Nested scheme for **bundle**: + * `bundle_base64` - (Optional, String) Base64 encoded version of the certificate bundle. + * `name` - (Optional, String) Name associated with the certificate. + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + +* `stomp_ssl` - (Optional, List) +Nested scheme for **stomp_ssl**: + * `authentication` - (Optional, List) Authentication data for Connection String. + Nested scheme for **authentication**: + * `method` - (Optional, String) Authentication method for this credential. + * `password` - (Optional, String) Password part of credential. + * `username` - (Optional, String) Username part of credential. + * `browser_accessible` - (Optional, Boolean) Indicates the address is accessible by browser. + * `certificate` - (Optional, List) + Nested scheme for **certificate**: + * `certificate_base64` - (Optional, String) Base64 encoded version of the certificate. + * `name` - (Optional, String) Name associated with the certificate. + * `composed` - (Optional, List) + * `hosts` - (Optional, List) + Nested scheme for **hosts**: + * `hostname` - (Optional, String) Hostname for connection. + * `port` - (Optional, Integer) Port number for connection. + * `path` - (Optional, String) Path for URI connection. + * `query_options` - (Optional, Map) Query options to add to the URI connection. + * `scheme` - (Optional, String) Scheme/protocol for URI connection. + * `ssl` - (Optional, Boolean) Indicates ssl is required for the connection. + * `type` - (Optional, String) Type of connection being described. + diff --git a/website/docs/d/database_pitr.html.markdown b/website/docs/d/database_pitr.html.markdown new file mode 100644 index 000000000..394f420ce --- /dev/null +++ b/website/docs/d/database_pitr.html.markdown @@ -0,0 +1,33 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_point_in_time_recovery" +description: |- + Get information about database_pitr +subcategory: "Cloud Databases" +--- + +# ibm_database_point_in_time_recovery + +Provides a read-only data source for database_pitr. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_point_in_time_recovery" "database_pitr" { + deployment_id = data.ibm_database.database.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `deployment_id` - (Required, Forces new resource, String) Deployment ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `deployment_id` - The unique identifier of the database_pitr. +* `earliest_point_in_time_recovery_time` - (String) - The earliest point in time recovery + diff --git a/website/docs/d/database_remotes.html.markdown b/website/docs/d/database_remotes.html.markdown new file mode 100644 index 000000000..a9fd5d677 --- /dev/null +++ b/website/docs/d/database_remotes.html.markdown @@ -0,0 +1,40 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_remotes" +description: |- + Get information about database_remotes +subcategory: "Cloud Databases" +--- + +# ibm_database_remotes + +Provides a read-only data source for database_remotes. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database" "database" { + name = "mydatabase" + location = "us-east" +} + +data "ibm_database_remotes" "database_remotes" { + deployment_id = data.ibm_database.database.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `deployment_id` - (Required, Forces new resource, String) Deployment ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the database_remotes. +* `leader` - (String) Leader ID, if applicable. + +* `replicas` - (List) Replica IDs, if applicable. + diff --git a/website/docs/d/database_task.html.markdown b/website/docs/d/database_task.html.markdown new file mode 100644 index 000000000..ce7464e44 --- /dev/null +++ b/website/docs/d/database_task.html.markdown @@ -0,0 +1,42 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_task" +description: |- + Get information about database_task +subcategory: "Cloud Databases" +--- + +# ibm_database_task + +Provides a read-only data source for database_task. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_task" "database_task" { + task_id = +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `task_id` - (Required, Forces new resource, String) Task ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `task_id` - The unique identifier of the database_task. +* `created_at` - (String) Date and time when the task was created. + +* `deployment_id` - (String) ID of the deployment the task is being performed on. + +* `description` - (String) Human-readable description of the task. + +* `progress_percent` - (Integer) Indicator as percentage of progress of the task. + +* `status` - (String) The status of the task. + * Constraints: Allowable values are: `running`, `completed`, `failed`. + diff --git a/website/docs/d/database_tasks.html.markdown b/website/docs/d/database_tasks.html.markdown new file mode 100644 index 000000000..4bb3d19d1 --- /dev/null +++ b/website/docs/d/database_tasks.html.markdown @@ -0,0 +1,41 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_database_tasks" +description: |- + Get information about database_tasks +subcategory: "Cloud Databases" +--- + +# ibm_database_tasks + +Provides a read-only data source for database_tasks. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_database_tasks" "database_tasks" { + deployment_id = data.ibm_database.database.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `deployment_id` - (Required, Forces new resource, String) Deployment ID. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `deployment_id` - The unique identifier of the database_tasks. +* `tasks` - (Optional, List) +Nested scheme for **tasks**: + * `created_at` - (Optional, String) Date and time when the task was created. + * `deployment_id` - (Optional, String) ID of the deployment the task is being performed on. + * `description` - (Optional, String) Human-readable description of the task. + * `task_id` - (Optional, String) ID of the task. + * `progress_percent` - (Optional, Integer) Indicator as percentage of progress of the task. + * `status` - (Optional, String) The status of the task. + * Constraints: Allowable values are: `running`, `completed`, `failed`. + diff --git a/website/docs/d/dl_gateway.html.markdown b/website/docs/d/dl_gateway.html.markdown index 11e73562a..76c17eb6a 100644 --- a/website/docs/d/dl_gateway.html.markdown +++ b/website/docs/d/dl_gateway.html.markdown @@ -29,6 +29,16 @@ Review the argument reference that you can specify for your resource. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. +- `as_prepends` - (List) List of AS Prepend configuration information + + Nested scheme for `as_prepend`: + - `created_at`- (String) The date and time AS Prepend was created. + - `id` - (String) The unique identifier for this AS Prepend. + - `length` - (Integer) Number of times the ASN to appended to the AS Path. + - `policy` - (String) Route type this AS Prepend applies to. Possible values are `import` and `export`. + - `prefix` - (String) Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes. + - `updated_at`- (String) The date and time AS Prepend was updated + - `authentication_key` - (String) BGP MD5 authentication key. - `bfd_interval` - (String) Minimum interval in milliseconds at which the local routing device transmits hello packets and then expects to receive a reply from a neighbor with which it has established a BFD session. - `bfd_multiplier` - (String) The number of hello packets not received by a neighbor that causes the originating interface to be declared down. diff --git a/website/docs/d/dl_gateways.html.markdown b/website/docs/d/dl_gateways.html.markdown index ad7a481d1..6c2766f3e 100644 --- a/website/docs/d/dl_gateways.html.markdown +++ b/website/docs/d/dl_gateways.html.markdown @@ -29,6 +29,16 @@ You can access the following attribute references after your data source is crea - `gateways` - (String) List of all the Direct Link Gateways in the IBM Cloud infrastructure. Nested scheme for `gateways`: + - `as_prepends` - (List) List of AS Prepend configuration information + + Nested scheme for `as_prepend`: + - `created_at`- (String) The date and time AS Prepend was created. + - `id` - (String) The unique identifier for this AS Prepend. + - `length` - (Integer) Number of times the ASN to appended to the AS Path. + - `policy` - (String) Route type this AS Prepend applies to. Possible values are `import` and `export`. + - `prefix` - (String, Optional) Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes. + - `updated_at`- (String) The date and time AS Prepend was updated + - `authentication_key` - (String) BGP MD5 authentication key. - `bfd_interval` - (String) Minimum interval in milliseconds at which the local routing device transmits hello packets and then expects to receive a reply from a neighbor with which it has established a BFD session. - `bfd_multiplier` - (String) The number of hello packets not received by a neighbor that causes the originating interface to be declared down. diff --git a/website/docs/d/dl_route_report.html.markdown b/website/docs/d/dl_route_report.html.markdown new file mode 100644 index 000000000..a8c50ad75 --- /dev/null +++ b/website/docs/d/dl_route_report.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "Direct Link Gateway" +layout: "ibm" +page_title: "IBM : dl_route_report" +description: |- + Retrieve the route report for the specified Direct Link gateway. +--- + +# ibm_dl_route_report + +Import the details of an existing infrastructure Direct Link Route Report as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about Direct Link route reports, see [Direct Link Route Report](https://cloud.ibm.com/docs/dl?topic=dl-generate-route-reports&interface=ui). + + +## Example usage + +```terraform +data "ibm_dl_route_reports" "test_dl_reports" { + gateway = ibm_dl_gateway.dl_gateway.id + route_report= ibm_dl_route_report.dl_route_report.route_report_id +} +``` + +## Argument reference +The argument reference that you need to specify for the data source. + +- `gateway`- (Required, String) Direct Link Gateway ID. +- `route_report` - (Required, String) Unique identifier of the route report + +## Attribute reference +In addition to all argument references list, you can access the following attribute references after your data source is created. +- `created_at` - (String) The date and time resource created. +- `gateway_routes` - (List) List of local/direct routes. + + Nested scheme for `gateway_routes`: + - `prefix` - (String) The prefix used in the route. +- `on_prem_routes` - (List) List of on premises routes + + Nested scheme for `on_prem_routes`: + - `prefix` - (String) The prefix used in the route. +- `overlapping_routes` - (List) List of overlapping routes. + + Nested scheme for `overlapping_routes`: + - `routes` - (List) List of overlapping connection/prefix pairs. + + Nested scheme for `routes`: + - `prefix` - (String) The overlapping prefix. + - `type` - (String) The type of route. + - `virtual_connection_id` - (String) Virtual Connection ID. This is set only when type of route is virtual_connection. + +- `status` - (String) The route report status. +- `updated_at` - (String) The date and time resource was updated. +- `virtual_connection_routes` - (List) List of routes on virtual connections. + + Nested scheme for `virtual_connection_routes` + - `routes` - (List) List of connection routes. + + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route. + - `virtual_connection_id` - (String) Virtual Connection ID + - `virtual_connection_name` - (String) Virtual Connection name + - `virtual_connection_type` - (String) Virtual Connection type diff --git a/website/docs/d/dl_route_reports.html.markdown b/website/docs/d/dl_route_reports.html.markdown new file mode 100644 index 000000000..4e3b2734f --- /dev/null +++ b/website/docs/d/dl_route_reports.html.markdown @@ -0,0 +1,62 @@ +--- +subcategory: "Direct Link Gateway" +layout: "ibm" +page_title: "IBM : dl_route_reports" +description: |- + Retrieve all route reports for the specified Direct Link gateway. +--- + +# ibm_dl_router_reports + +Import the details of an existing infrastructure Direct Link Route Reports as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about Direct Link route reports, see [Direct Link Route Report](https://cloud.ibm.com/docs/dl?topic=dl-generate-route-reports&interface=ui). + + +## Example usage + +```terraform +data "ibm_dl_route_reports" "test_dl_reports" { + gateway = ibm_dl_gateway.test_dl_gateway.id +} +``` + +## Argument reference +The argument reference that you need to specify for the data source. + +- `gateway`- (Required, String) Direct Link Gateway ID. + +## Attribute reference +In addition to all argument references list, you can access the following attribute references after your data source is created. +- `route_reports` - (String) List of all route reports for the transit gateway + + Nested scheme for `route_reports` + - `created_at` - (String) The date and time resource created. + - `gateway_routes` - (List) List of local/direct routes. + + Nested scheme for `gateway_routes`: + - `prefix` - (String) The prefix used in the route. + - `id` - (String) Route report identifier. + - `on_prem_routes` - (List) List of on premises routes + + Nested scheme for `on_prem_routes`: + - `prefix` - (String) The prefix used in the route. + - `overlapping_routes` - (List) List of overlapping routes. + + Nested scheme for `overlapping_routes`: + - `routes` - (List) List of overlapping connection/prefix pairs. + + Nested scheme for `routes`: + - `prefix` - (String) The overlapping prefix. + - `type` - (String) The type of route. + - `virtual_connection_id` - (String) Virtual Connection ID. This is set only when type of route is virtual_connection. + - `status` - (String) The route report status. + - `updated_at` - (String) The date and time resource was updated. + - `virtual_connection_routes` - (List) List of routes on virtual connections. + + Nested scheme for `virtual_connection_routes` + - `routes` - (List) List of connection routes. + + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route. + - `virtual_connection_id` - (String) Virtual Connection ID + - `virtual_connection_name` - (String) Virtual Connection name + - `virtual_connection_type` - (String) Virtual Connection type diff --git a/website/docs/d/dns_custom_resolver_forwarding_rules.html.markdown b/website/docs/d/dns_custom_resolver_forwarding_rules.html.markdown index 21e1312ff..e2d7ef370 100644 --- a/website/docs/d/dns_custom_resolver_forwarding_rules.html.markdown +++ b/website/docs/d/dns_custom_resolver_forwarding_rules.html.markdown @@ -10,7 +10,7 @@ description: |- Provides a read-only data source for forwarding rules. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information about forwarding rules, refer to [list-forwarding-rules](https://cloud.ibm.com/apidocs/dns-svcs#list-forwarding-rules) -## Example Usage +## Example usage data "ibm_dns_custom_resolver_forwarding_rules" "test-fr" { @@ -19,14 +19,14 @@ data "ibm_dns_custom_resolver_forwarding_rules" "test-fr" { } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. - `instance_id` - (Required, String) The GUID of the private DNS service instance. - `resolver_id` - (Required, String) The unique identifier of a custom resolver. -## Attribute Reference +## Attribute reference In addition to the argument references list, you can access the following attribute references after your data source are created. diff --git a/website/docs/d/dns_custom_resolver_secondary_zones.html.markdown b/website/docs/d/dns_custom_resolver_secondary_zones.html.markdown new file mode 100644 index 000000000..504a0d7c4 --- /dev/null +++ b/website/docs/d/dns_custom_resolver_secondary_zones.html.markdown @@ -0,0 +1,39 @@ +--- +subcategory: "DNS Services" +layout: "ibm" +page_title: "IBM : Secondary Zones" +description: |- + Manages IBM Cloud Infrastructure private domain name service secondary zones. +--- + +# ibm_dns_custom_resolver_secondary_zones + +Provides a read-only data source for secondary zones. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information about secondary zones, refer to [list-secondary-zones](https://cloud.ibm.com/apidocs/dns-svcs#list-secondary-zones). + +## Example usage + +```terraform +data "ibm_dns_custom_resolver_secondary_zones" "test-sz" { + instance_id = ibm_dns_custom_resolver.test.instance_id + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_id` - (Required, String) The GUID of the DNS Services instance. +- `resolver_id` - (Required, String) The unique identifier of a custom resolver. + +## Attribute reference + +In addition to the argument references list, you can access the following attribute references after your data sources are created. + +- `secondary_zones` (List) List of secondary zones. + + Nested scheme for `secondary_zones`: + - `description` - (String) Descriptive text of the secondary zone. + - `zone` - (String) The name of the zone. + - `enabled` - (String) Enable/Disable the secondary zone. + - `transfer_from` - (List) The addresses of DNS servers where the secondary zone data is transferred from. diff --git a/website/docs/d/dns_permitted_networks.html.markdown b/website/docs/d/dns_permitted_networks.html.markdown index d0b0792df..cafcece60 100644 --- a/website/docs/d/dns_permitted_networks.html.markdown +++ b/website/docs/d/dns_permitted_networks.html.markdown @@ -53,7 +53,7 @@ data "ibm_dns_permitted_networks" "test" { ## Argument reference Review the argument reference that you can specify for your data source. -- `instance_id` - (Required, String) The ID of the private DNS service instance where you created permitted networks. +- `instance_id` - (Required, String) The GUID of the private DNS service instance where you created permitted networks. - `zone_id` - (Required, String) The ID of the zone where you added the permitted networks. ## Attribute reference diff --git a/website/docs/d/dns_resource_records.html.markdown b/website/docs/d/dns_resource_records.html.markdown index af2b9529c..7460f0958 100644 --- a/website/docs/d/dns_resource_records.html.markdown +++ b/website/docs/d/dns_resource_records.html.markdown @@ -23,7 +23,7 @@ data "ibm_dns_resource_records" "ds_pdns_resource_records" { ## Argument reference Review the argument reference that you can specify for your data source. -- `instance_id` - (Required, String) The ID of the private DNS service instance. +- `instance_id` - (Required, String) The GUID of the private DNS service instance. - `zone_id` - (Required, String) The ID of the zone that you added to the private DNS service instance. ## Attribute reference diff --git a/website/docs/d/dns_zones.html.markdown b/website/docs/d/dns_zones.html.markdown index 4b60eee7b..16a81845d 100644 --- a/website/docs/d/dns_zones.html.markdown +++ b/website/docs/d/dns_zones.html.markdown @@ -25,7 +25,7 @@ data "ibm_dns_zones" "ds_pdnszones" { ## Argument reference Review the argument reference that you can specify for your data source. -- `instance_id` - (Required, String) The ID of the private DNS service instance. +- `instance_id` - (Required, String) The GUID of the private DNS service instance. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_destination.html.markdown b/website/docs/d/en_destination.html.markdown index 7842c496e..448e91160 100644 --- a/website/docs/d/en_destination.html.markdown +++ b/website/docs/d/en_destination.html.markdown @@ -10,16 +10,16 @@ description: |- Provides a read-only data source for destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_destination" "en_destination" { - instance_guid = "instance_guid" - destination_id = "destinationId" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination.destination1.destination_id } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -27,7 +27,7 @@ Review the argument reference that you can specify for your data source. - `destination_id` - (Required, String) Unique identifier for Destination. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_destination_android.html.markdown b/website/docs/d/en_destination_android.html.markdown new file mode 100644 index 000000000..86ae38115 --- /dev/null +++ b/website/docs/d/en_destination_android.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_android' +description: |- + Get information about a FCM destination +--- + +# ibm_en_destination_android + +Provides a read-only data source for FCM destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_android" "android_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_android.destinationandroidnew.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `android_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_android. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `sender_id` - (String) Sender ID for your FCM Destination Configured. + + - `server_key` - (String) Server Key for FCM Destination configured. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_chrome.html.markdown b/website/docs/d/en_destination_chrome.html.markdown new file mode 100644 index 000000000..ecfc5af17 --- /dev/null +++ b/website/docs/d/en_destination_chrome.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_chrome' +description: |- + Get information about a chrome destination +--- + +# ibm_en_destination_chrome + +Provides a read-only data source for Cbrome destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_chrome" "chrome_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_chrome.chrome_destination.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `chrome_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_chrome. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `website_url` - (String) URL of website. + + - `api_key` - (String) api key for FCM website project + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_firefox.html.markdown b/website/docs/d/en_destination_firefox.html.markdown new file mode 100644 index 000000000..230dec401 --- /dev/null +++ b/website/docs/d/en_destination_firefox.html.markdown @@ -0,0 +1,55 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_firefox' +description: |- + Get information about a firefox destination +--- + +# ibm_en_destination_firefox + +Provides a read-only data source for firefox destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_firefox" "firefox_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_firefox.firefox_destination.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `firefox_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_firefox. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `website_url` - (String) URL of website. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_ios.html.markdown b/website/docs/d/en_destination_ios.html.markdown new file mode 100644 index 000000000..470e1ac9b --- /dev/null +++ b/website/docs/d/en_destination_ios.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_ios' +description: |- + Get information about a IOS destination +--- + +# _ibm_en_destination_ios + +Provides a read-only data source for destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_ios" "ios_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_ios.destinationiosp8.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `ios_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_ios. + +- `certificate_content_type` - (String) The type of certificate, Values are p8/p12. + +- `certificate` - (binary) Certificate file. The file type allowed is .p8 and .p12 + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `cert_type` - (String) The Certificate type. Values are p8/p12. + + - `is_sandbox` - (boolean) The flag for sandbox/production environment. + + - `password` - (String) The password string for p12 certificate. + + - `team_id` - (String) The team_id value in case P8 certificate. + + - `key_id` - (String) The team_id value in case P8 certificate. + + - `bundle_id` - (String) The team_id value in case P8 certificate. + +- `updated_at` - (String) Last updated time. \ No newline at end of file diff --git a/website/docs/d/en_destination_safari.html.markdown b/website/docs/d/en_destination_safari.html.markdown new file mode 100644 index 000000000..fc3d2b839 --- /dev/null +++ b/website/docs/d/en_destination_safari.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_safari' +description: |- + Get information about a Safari destination +--- + +# ibm_en_destination_safari + +Provides a read-only data source for Webhook destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_safari" "safari_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_safari.destination1.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `safari_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_safari. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `cert_type` - (String) The Certificate type. Value is p12. + + - `password` - (String) The password string for p12 certificate. + + - `url_format_string` - (String) Website formatted url . + + - `website_name` - (String) The name of website. + + - `website_push_id` - (String) Website push ID . + + - `website_url` - (String) Website url. + + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_slack.html.markdown b/website/docs/d/en_destination_slack.html.markdown new file mode 100644 index 000000000..bc3554c65 --- /dev/null +++ b/website/docs/d/en_destination_slack.html.markdown @@ -0,0 +1,55 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_slack' +description: |- + Get information about a Slack destination +--- + +# ibm_en_destination_slack + +Provides a read-only data source for Slack destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_slack" "slack_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_slack.destination1.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `slack_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type slack. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `url` - (String) Slack Webhook url. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_webhook.html.markdown b/website/docs/d/en_destination_webhook.html.markdown new file mode 100644 index 000000000..d04a8fe43 --- /dev/null +++ b/website/docs/d/en_destination_webhook.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_webhook' +description: |- + Get information about a webhook destination +--- + +# ibm_en_destination_webhook + +Provides a read-only data source for Webhook destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_webhook" "webhook_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_webhook.destination1.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `webhook_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type Webhook. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `url` - (String) URL of webhook. + + - `verb` - (String) HTTP method of webhook. Allowable values are: `get`, `post`. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destinations.html.markdown b/website/docs/d/en_destinations.html.markdown index c8b389543..4edb06705 100644 --- a/website/docs/d/en_destinations.html.markdown +++ b/website/docs/d/en_destinations.html.markdown @@ -10,15 +10,15 @@ description: |- Provides a read-only data source for destinations. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_destinations" "en_destinations" { - instance_guid = "instance_guid" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -26,7 +26,7 @@ Review the argument reference that you can specify for your data source. - `search_key` - (Optional, String) Filter the destinations by name or type. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_fcm_destination.html.markdown b/website/docs/d/en_fcm_destination.html.markdown new file mode 100644 index 000000000..86ae38115 --- /dev/null +++ b/website/docs/d/en_fcm_destination.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_android' +description: |- + Get information about a FCM destination +--- + +# ibm_en_destination_android + +Provides a read-only data source for FCM destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_android" "android_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_android.destinationandroidnew.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `android_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type push_android. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `sender_id` - (String) Sender ID for your FCM Destination Configured. + + - `server_key` - (String) Server Key for FCM Destination configured. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_source.html.markdown b/website/docs/d/en_source.html.markdown new file mode 100644 index 000000000..f454751d8 --- /dev/null +++ b/website/docs/d/en_source.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_source' +description: |- + Get information about a Source +--- + +# ibm_en_source + +Provides a read-only data source for API sources. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_source" "en_source" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + source_id = ibm_en_source.destination1.source_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `source_id` - (Required, String) Unique identifier for API Source. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `en_source`. + +- `name` - (String) Source name. + +- `description` - (String) Source description. + +- `enabled` - (bool) Flag to enable/disable the api source. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription.html.markdown b/website/docs/d/en_subscription.html.markdown index 9f7a986f0..963c235e8 100644 --- a/website/docs/d/en_subscription.html.markdown +++ b/website/docs/d/en_subscription.html.markdown @@ -10,16 +10,16 @@ description: |- Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_subscription" "en_subscription" { - instance_guid = "instance_guid" - subscription_id = "subscription_id" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription.subscriptionemailnew.subscription_id } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -27,7 +27,7 @@ Review the argument reference that you can specify for your data source. - `subscription_id` - (Required, String) Unique identifier for Subscription. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. @@ -53,12 +53,18 @@ In addition to all argument references listed, you can access the following attr - `add_notification_payload` - (Boolean) Whether to add the notification payload to the email. - - `recipient_selection` - (String) The recipient selection method. + - `signing_enabled`- (Boolean) Signing webhook attributes. - - `reply_to` - (String) The email address to reply to. + - `signing_enabled` - (Optional, Boolean) Signing enabled. + + - `additional_properties` - (Required, List) it will be displayed only in case of smtp_ibm destination type + - `reply_to` - (String) The email address to reply to. - - `signing_enabled`- (Boolean) Signing webhook attributes. + - `reply_to_name` - (String) The Email User Name to reply to. + + - `from_name` - (String) The email address user from which email is addressed. - - `to`- (List) The phone number to send the SMS to. + - `to` - (List) The phone number to send the SMS to. +- `additionalproperties` - (List) it will be displayed only in case of sms_ibm destination type - `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_android.html.markdown b/website/docs/d/en_subscription_android.html.markdown new file mode 100644 index 000000000..d95f91a8a --- /dev/null +++ b/website/docs/d/en_subscription_android.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_android' +description: |- + Get information about a FCM subscription +--- + +# ibm_en_subscription_fcm + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_android" "fcm_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_android.subscriptionandroid.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the fcm_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_chrome.html.markdown b/website/docs/d/en_subscription_chrome.html.markdown new file mode 100644 index 000000000..918842221 --- /dev/null +++ b/website/docs/d/en_subscription_chrome.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_chrome' +description: |- + Get information about a chrome subscription +--- + +# ibm_en_subscription_chrome + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_chrome" "chrome_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_chrome.chrome_subscription.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the chrome_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_email.html.markdown b/website/docs/d/en_subscription_email.html.markdown new file mode 100644 index 000000000..f42014f25 --- /dev/null +++ b/website/docs/d/en_subscription_email.html.markdown @@ -0,0 +1,60 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_email' +description: |- + Get information about a Email subscription +--- + +# ibm_en_subscription_email + +Provides a read-only data source for Email subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_email" "email_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_email.subscriptionemail.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the email_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `add_notification_payload` - (Boolean) Whether to add the notification payload to the email. + +- `additional_properties` - (Required, List) + + - `reply_to_name` - (String) The Email User Name to reply to. + + - `reply_to_mail` - (String) The email address to reply to. + + - `signing_enabled`- (Boolean) Signing webhook attributes. + + - `to`- (Map) The Email address to send the email to. + + - `unsubscribed`- (List) The Email address which are unsusbscribed. + + - `invited`- (List) The Email address for invitation. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_fcm.html.markdown b/website/docs/d/en_subscription_fcm.html.markdown new file mode 100644 index 000000000..d95f91a8a --- /dev/null +++ b/website/docs/d/en_subscription_fcm.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_android' +description: |- + Get information about a FCM subscription +--- + +# ibm_en_subscription_fcm + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_android" "fcm_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_android.subscriptionandroid.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the fcm_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_firefox.html.markdown b/website/docs/d/en_subscription_firefox.html.markdown new file mode 100644 index 000000000..84eefb91b --- /dev/null +++ b/website/docs/d/en_subscription_firefox.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_firefox' +description: |- + Get information about a firefox subscription +--- + +# ibm_en_subscription_fcm + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_firefox" "firefox_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_firefox.firefox_subscription.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the fcm_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_ios.html.markdown b/website/docs/d/en_subscription_ios.html.markdown new file mode 100644 index 000000000..77532c727 --- /dev/null +++ b/website/docs/d/en_subscription_ios.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_ios' +description: |- + Get information about a IOS subscription +--- + +# ibm_en_subscription_ios + +Provides a read-only data source for APNS subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_ios" "ios_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_ios.subscriptionapns.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the ios_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_safari.html.markdown b/website/docs/d/en_subscription_safari.html.markdown new file mode 100644 index 000000000..af54dd33b --- /dev/null +++ b/website/docs/d/en_subscription_safari.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_safari' +description: |- + Get information about a Safari subscription +--- + +# ibm_en_subscription_safari + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_safari" "safari_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_safari.safari_subscription.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the safari_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_slack.html.markdown b/website/docs/d/en_subscription_slack.html.markdown new file mode 100644 index 000000000..9702c90df --- /dev/null +++ b/website/docs/d/en_subscription_slack.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_slack' +description: |- + Get information about a Slack subscription +--- + +# ibm_en_subscription_slack + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_slack" "slack_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_slack.subscriptionslack.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the slack_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `destination_name` - (String) The destination name. + +- `destination_type` - (String) The type of destination. + +- `topic_id` - (String) Topic ID. + +- `topic_name` - (String) Topic name. + +- `attributes` - (Required, List) + + - `attachment_color` - (String) The color code for slack attachment . + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_sms.html.markdown b/website/docs/d/en_subscription_sms.html.markdown new file mode 100644 index 000000000..c197951fb --- /dev/null +++ b/website/docs/d/en_subscription_sms.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_sms' +description: |- + Get information about a sms subscription +--- + +# ibm_en_subscription_sms + +Provides a read-only data source for SMS subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_sms" "sms_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_sms.subscriptionsmsnew.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the sms_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `additional_properties` - (Required, List) + + - `to`- (List) The phone number to send the SMS to. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscription_webhook.html.markdown b/website/docs/d/en_subscription_webhook.html.markdown new file mode 100644 index 000000000..057c67970 --- /dev/null +++ b/website/docs/d/en_subscription_webhook.html.markdown @@ -0,0 +1,56 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_webhook' +description: |- + Get information about a webhook subscription +--- + +# ibm_en_subscription_webhook + +Provides a read-only data source for subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_webhook" "webhook_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_webhook.subscriptionwebhook.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the webhook_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `destination_name` - (String) The destination name. + +- `destination_type` - (String) The type of destination. + +- `from` - (Optional, String) From Email ID (it will be displayed only in case of smtp_ibm destination type). + +- `topic_id` - (String) Topic ID. + +- `topic_name` - (String) Topic name. + +- `attributes` - (Required, List) + + - `add_notification_payload` - (Boolean) Whether to add the notification payload to the email. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_subscriptions.html.markdown b/website/docs/d/en_subscriptions.html.markdown index 26110df13..ea7fda476 100644 --- a/website/docs/d/en_subscriptions.html.markdown +++ b/website/docs/d/en_subscriptions.html.markdown @@ -10,15 +10,15 @@ description: |- Provides a read-only data source for en_subscriptions. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_subscriptions" "en_subscriptions" { - instance_guid = "instance_guid" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -26,7 +26,7 @@ Review the argument reference that you can specify for your data source. - `search_key` - (Optional, String) Filter the subscription by name. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_topic.html.markdown b/website/docs/d/en_topic.html.markdown index e0142e038..2f17379e6 100644 --- a/website/docs/d/en_topic.html.markdown +++ b/website/docs/d/en_topic.html.markdown @@ -10,16 +10,16 @@ description: |- Provides a read-only data source for topic. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_topic" "en_topic" { - instance_guid = "instance_guid" - topic_id = "topic_id" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + topic_id = ibm_en_topic.topic1.topic_id } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -27,7 +27,7 @@ Review the argument reference that you can specify for your data source. - `topic_id` - (Required, String) Unique identifier for Topic. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_topics.html.markdown b/website/docs/d/en_topics.html.markdown index dc7f49925..9b7c09989 100644 --- a/website/docs/d/en_topics.html.markdown +++ b/website/docs/d/en_topics.html.markdown @@ -10,15 +10,15 @@ description: |- Provides a read-only data source for topics. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_en_topics" "en_topics" { - instance_guid = "instance_guid" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -26,7 +26,7 @@ Review the argument reference that you can specify for your data source. - `search_key` - (Optional, String) Filter the topic by name. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/en_webhook_destination.html.markdown b/website/docs/d/en_webhook_destination.html.markdown new file mode 100644 index 000000000..d04a8fe43 --- /dev/null +++ b/website/docs/d/en_webhook_destination.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_webhook' +description: |- + Get information about a webhook destination +--- + +# ibm_en_destination_webhook + +Provides a read-only data source for Webhook destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_webhook" "webhook_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_webhook.destination1.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `webhook_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type Webhook. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `url` - (String) URL of webhook. + + - `verb` - (String) HTTP method of webhook. Allowable values are: `get`, `post`. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/event_streams_topic.html.markdown b/website/docs/d/event_streams_topic.html.markdown index 48dbdf748..2e3616514 100644 --- a/website/docs/d/event_streams_topic.html.markdown +++ b/website/docs/d/event_streams_topic.html.markdown @@ -11,7 +11,7 @@ description: |- Review the [Event Streams](https://cloud.ibm.com/docs/EventStreams?topic=EventStreams-about) resource that you can connect, administer, developed with Event Streams and integrate with the other services. -## Example Usage +## Example usage ```terraform data "ibm_resource_instance" "es_instance" { @@ -25,13 +25,13 @@ data "ibm_event_streams_topic" "es_topic" { } ``` -## Argument Reference +## Argument reference Review the argument parameters that you can specify for your data source. - `name` - (Required, string) The name of the topic. - `resource_instance_id` - (Required, string) The ID or CRN of the Event Streams service instance. -## Attribute Reference +## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your data source is created. diff --git a/website/docs/d/hpcs_key_template.html.markdown b/website/docs/d/hpcs_key_template.html.markdown new file mode 100644 index 000000000..4e28c0e05 --- /dev/null +++ b/website/docs/d/hpcs_key_template.html.markdown @@ -0,0 +1,91 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_key_template" +description: |- + Get information about key_template +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_key_template + +Provides a read-only data source for key_template. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_hpcs_key_template" "key_template" { + instance_id = "76195d24-8a31-4c6d-9050-c35f09375cfb" + region = "us-east" + template_id = "d8cc1ef7-d13b-4731-95be-1f7c98c9f524" + uko_vault = ibm_hpcs_vault.vault.vault_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `template_id` - (Required, Forces new resource, String) UUID of the template. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `template_id` - The unique identifier of the key_template. +* `created_at` - (String) Date and time when the key template was created. + +* `created_by` - (String) ID of the user that created the key template. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `description` - (String) Description of the key template. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/.*/`. + +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + +* `key` - (List) Properties describing the properties of the managed key. +Nested scheme for **key**: + * `activation_date` - (String) Key activation date can be provided as a period definition (e.g. PY1 means 1 year). + * Constraints: The maximum length is `100` characters. The minimum length is `3` characters. The value must match regular expression `/P^[0-9YMWD]+$/`. + * `algorithm` - (String) The algorithm of the key. + * Constraints: Allowable values are: `aes`, `rsa`. + * `expiration_date` - (String) Key expiration date can be provided as a period definition (e.g. PY1 means 1 year). + * Constraints: The maximum length is `100` characters. The minimum length is `3` characters. The value must match regular expression `/P^[0-9YMWD]+$/`. + * `size` - (String) The size of the underlying cryptographic key or key pair. E.g. "256" for AES keys, or "2048" for RSA. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9]+$/`. + * `state` - (String) The state that the key will be in after generation. + * Constraints: The default value is `active`. Allowable values are: `pre_activation`, `active`. + +* `keystores` - (List) + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **keystores**: + * `group` - (String) Which keystore group to distribute the key to. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. + * `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. + +* `name` - (String) Name of the key template. + * Constraints: The maximum length is `30` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Z0-9-]+$/`. + +* `updated_at` - (String) Date and time when the key template was updated. + +* `updated_by` - (String) ID of the user that updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `vault` - (List) Reference to a vault. +Nested scheme for **vault**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the referenced vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +* `version` - (Integer) Version of the key template. Every time the key template is updated, the version will be updated automatically. + * Constraints: The maximum value is `2147483647`. The minimum value is `1`. + diff --git a/website/docs/d/hpcs_keystore.html.markdown b/website/docs/d/hpcs_keystore.html.markdown new file mode 100644 index 000000000..891db4930 --- /dev/null +++ b/website/docs/d/hpcs_keystore.html.markdown @@ -0,0 +1,124 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_keystore" +description: |- + Get information about keystore +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_keystore + +Provides a read-only data source for keystore. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_hpcs_keystore" "keystore" { + instance_id = "76195d24-8a31-4c6d-9050-c35f09375cfb" + region = "us-east" + keystore_id = "d8cc1ef7-d13b-4731-95be-1f7c98c9f524" + uko_vault = ibm_hpcs_vault.vault.vault_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `keystore_id` - (Required, Forces new resource, String) UUID of the keystore. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `keystore_id` - The unique identifier of the keystore. +* `aws_access_key_id` - (String) The access key id used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_]*$/`. + +* `aws_region` - (String) AWS Region. + * Constraints: Allowable values are: `af_south_1`, `ap_east_1`, `ap_northeast_1`, `ap_northeast_2`, `ap_south_1`, `ap_southeast_1`, `ap_southeast_2`, `aws_cn_global`, `aws_global`, `aws_iso_global`, `aws_iso_b_global`, `aws_us_gov_global`, `ca_central_1`, `cn_north_1`, `cn_northwest_1`, `eu_central_1`, `eu_west_1`, `eu_west_2`, `eu_west_3`, `me_south_1`, `sa_east_1`, `us_east_1`, `us_east_2`, `us_gov_east_1`, `us_gov_west_1`, `us_iso_east_1`, `us_isob_east_1`, `us_west_1`, `us_west_2`. + +* `aws_secret_access_key` - (String) The secret access key used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_\/]*$/`. + +* `azure_environment` - (String) Azure environment, usually 'Azure'. + * Constraints: Allowable values are: `azure`, `azure_china`, `azure_germany`, `azure_us_government`. + +* `azure_location` - (String) Location of the Azure Key Vault. + * Constraints: Allowable values are: `asia_east`, `asia_southeast`, `australia_central`, `australia_central_2`, `australia_east`, `australia_southeast`, `brazil_south`, `canada_central`, `canada_east`, `china_east`, `china_east_2`, `china_north`, `china_north_2`, `europe_north`, `europe_west`, `france_central`, `france_south`, `germany_central`, `germany_northeast`, `india_central`, `india_south`, `india_west`, `japan_east`, `japan_west`, `korea_central`, `korea_south`, `south_africa_north`, `south_africa_west`, `uk_south`, `uk_west`, `us_central`, `us_dod_central`, `us_dod_east`, `us_east`, `us_east_2`, `us_gov_arizona`, `us_gov_iowa`, `us_gov_texas`, `us_gov_virginia`, `us_north_central`, `us_south_central`, `us_west`, `us_west_2`, `us_west_central`. + +* `azure_resource_group` - (String) Resource group in Azure. + * Constraints: The maximum length is `90` characters. The minimum length is `1` character. The value must match regular expression `/^[-\\w\\._\\(\\)]*[^\\.]$/`. + +* `azure_service_name` - (String) Service name of the key vault instance from the Azure portal. + * Constraints: The maximum length is `24` characters. The minimum length is `3` characters. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `azure_service_principal_client_id` - (String) Azure service principal client ID. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. + +* `azure_service_principal_password` - (String) Azure service principal password. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]+$/`. + +* `azure_subscription_id` - (String) Subscription ID in Azure. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. + +* `azure_tenant` - (String) Azure tenant that the Key Vault is associated with,. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. + +* `created_at` - (String) Date and time when the target keystore was created. + +* `created_by` - (String) ID of the user that created the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `description` - (String) Description of the keystore. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. + +* `groups` - (List) List of groups that this keystore belongs to. + * Constraints: The list items must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. The maximum length is `128` items. The minimum length is `1` item. + +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + +* `ibm_api_endpoint` - (String) API endpoint of the IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. + +* `ibm_api_key` - (String) The IBM Cloud API key to be used for connecting to this IBM Cloud keystore. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_&.]*$/`. + +* `ibm_iam_endpoint` - (String) Endpoint of the IAM service for this IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. + +* `ibm_instance_id` - (String) The instance ID of the IBM Cloud keystore. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]*$/`. + +* `ibm_key_ring` - (String) The key ring of an IBM Cloud KMS Keystore. + * Constraints: The default value is `Default`. The maximum length is `100` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9-]*$/`. + +* `ibm_variant` - (String) Possible IBM Cloud KMS variants. + * Constraints: Allowable values are: `hpcs`, `internal`, `key_protect`. + +* `name` - (String) Name of the target keystore. It can be changed in the future. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9 .-_]*$/`. + +* `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. + +* `updated_at` - (String) Date and time when the target keystore was last updated. + +* `updated_by` - (String) ID of the user that last updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `vault` - (List) Reference to a vault. +Nested scheme for **vault**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the referenced vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + diff --git a/website/docs/d/hpcs_managed_key.html.markdown b/website/docs/d/hpcs_managed_key.html.markdown new file mode 100644 index 000000000..0a92b0310 --- /dev/null +++ b/website/docs/d/hpcs_managed_key.html.markdown @@ -0,0 +1,133 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_managed_key" +description: |- + Get information about managed_key +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_managed_key + +Provides a read-only data source for managed_key. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_hpcs_managed_key" "managed_key" { + instance_id = "76195d24-8a31-4c6d-9050-c35f09375cfb" + region = "us-east" + key_id = "d8cc1ef7-d13b-4731-95be-1f7c98c9f524" + uko_vault = ibm_hpcs_vault.vault.vault_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `key_id` - (Required, Forces new resource, String) UUID of the key. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `key_id` - The unique identifier of the managed_key. +* `activation_date` - (String) First day when the key is active. + +* `algorithm` - (String) The algorithm of the key. + * Constraints: Allowable values are: `aes`, `rsa`. + +* `created_at` - (String) Date and time when the key was created. + +* `created_by` - (String) ID of the user that created the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `description` - (String) Description of the managed key. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. + +* `expiration_date` - (String) Last day when the key is active. + +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + +* `instances` - (List) key instances. + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **instances**: + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `keystore` - (List) Description of properties of a key within the context of keystores. + Nested scheme for **keystore**: + * `group` - (String) + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. + * `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. + * `label_in_keystore` - (String) The label of the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._ -]+$/`. + * `type` - (String) Type of the key instance. + * Constraints: Allowable values are: `public_key`, `private_key`, `key_pair`, `secret_key`. + +* `label` - (String) The label of the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._ -]+$/`. + +* `referenced_keystores` - (List) referenced keystores. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **referenced_keystores**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the target keystore. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9 .-_]*$/`. + * `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. + +* `size` - (String) The size of the underlying cryptographic key or key pair. E.g. "256" for AES keys, or "2048" for RSA. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9]+$/`. + +* `state` - (String) The state of the key. + * Constraints: The default value is `active`. Allowable values are: `pre_activation`, `active`, `deactivated`, `destroyed`. + +* `tags` - (List) Key-value pairs associated with the key. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **tags**: + * `name` - (String) Name of a tag. + * Constraints: The maximum length is `254` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9 -_]+$/`. + * `value` - (String) Value of a tag. + * Constraints: The maximum length is `8192` characters. The minimum length is `1` character. The value must match regular expression `/^(\\w|\\s)*$/`. + +* `template` - (List) Reference to a key template. +Nested scheme for **template**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the key template. + * Constraints: The maximum length is `30` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9-]*$/`. + +* `updated_at` - (String) Date and time when the key was last updated. + +* `updated_by` - (String) ID of the user that last updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + +* `vault` - (List) Reference to a vault. +Nested scheme for **vault**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the referenced vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +* `verification_patterns` - (List) A list of verification patterns of the key (e.g. public key hash for RSA keys). + * Constraints: The maximum length is `16` items. The minimum length is `1` item. +Nested scheme for **verification_patterns**: + * `method` - (String) The method used for calculating the verification pattern. + * Constraints: The maximum length is `100` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + * `value` - (String) The calculated value. + * Constraints: The maximum length is `100` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9+\/=]+$/`. + diff --git a/website/docs/d/hpcs_vault.html.markdown b/website/docs/d/hpcs_vault.html.markdown new file mode 100644 index 000000000..a039cc40b --- /dev/null +++ b/website/docs/d/hpcs_vault.html.markdown @@ -0,0 +1,56 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_vault" +description: |- + Get information about vault +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_vault + +Provides a read-only data source for vault. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_hpcs_vault" "vault" { + instance_id = "76195d24-8a31-4c6d-9050-c35f09375cfb" + region = "us-east" + vault_id = "5295ad47-2ce9-43c3-b9e7-e5a9482c362b" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `vault_id` - (Required, Forces new resource, String) UUID of the vault. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `vault_id` - The unique identifier of the vault. +* `created_at` - (String) Date and time when the vault was created. + +* `created_by` - (String) ID of the user that created the vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$%'_-]*$/`. + +* `description` - (Required, String) Description of the vault. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/.*/`. + +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + +* `name` - (String) Name of the vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +* `updated_at` - (String) Date and time when the vault was last updated. + +* `updated_by` - (String) ID of the user that last updated the vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + diff --git a/website/docs/d/iam_access_group.html.markdown b/website/docs/d/iam_access_group.html.markdown index 5dbec706e..7e6ca1313 100644 --- a/website/docs/d/iam_access_group.html.markdown +++ b/website/docs/d/iam_access_group.html.markdown @@ -34,6 +34,7 @@ In addition to the argument reference list, you can access the following attribu - `description` - (String) The description of the IAM access group. - `iam_service_ids` - (Array of Strings) A list of service IDs that belong to the access group. + - `iam_profile_ids` - (Array of Strings) A list of trusted profile IDs that belong to the access group. - `ibm_ids` - (Array of Strings) A list of IBM ID that belong to the access group. - `id` - (String) The ID of the IAM access group. - `name` - (String) The name of the IAM access group. diff --git a/website/docs/d/iam_access_group_policy.html.markdown b/website/docs/d/iam_access_group_policy.html.markdown new file mode 100644 index 000000000..e991a79b9 --- /dev/null +++ b/website/docs/d/iam_access_group_policy.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "Identity & Access Management (IAM)" +layout: "ibm" +page_title: "IBM : iam_access_group_policy" +description: |- + Manages IBM IAM access group policy. +--- + +# ibm_iam_access_group_policy + +Retrieve information about an IAM access group policy. For more information, about IAM role action, see [managing access to resources](https://cloud.ibm.com/docs/account?topic=account-assign-access-resources). + +## Example usage + +```terraform +resource "ibm_iam_access_group" "accgrp" { + name = "test123" +} + +resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "cloud-object-storage" + } +} + +data "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group_policy.policy.access_group_id + transaction_id = "terrformAccessGroupPolicy" +} + +``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `access_group_id` - (Required, Forces new resource, String) The ID of the access group. +- `sort`- (Optional, String) The single field sort query for policies. Allowed values are `id`, `type`, `href`, `created_at`, `created_by_id`, `last_modified_at`,`last_modified_by_id`, `state`. +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for the tracking calls. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `policies` - (List) A nested block describes IAM Policies assigned to access group. + + Nested scheme for `policies`: + - `description` (String) The description of the IAM access group Policy. + - `id` - (String) The unique identifier of the IAM access group policy. The ID is composed of `/`. + - `roles`- (String) The roles that are assigned to the policy. + - `resources`- (List of objects) A nested block describes the resources in the policy. + + Nested scheme for `resources`: + - `service` - (String) The service name of the policy definition. + - `region` - (String) The region of the policy definition. + - `resource_type` - (String) The resource type of the policy definition. + - `resource` - (String) The resource of the policy definition. + - `resource_group_id` - (String) The ID of the resource group. + - `resource_instance_id`- (String) The ID of resource instance of the policy definition. + - `service_type`- (String) The service type of the policy definition. + - `attributes` (Map) A set of resource attributes in the format `name=value,name=value`. + + - `resource_tags`- (List of objects) A nested block describes the access management tags in the policy. + + Nested scheme for `resource_tags`: + - `name` - (String) The key of an access management tag. + - `value` - (String) The value of an access management tag. + - `operator` - (String) Operator of an attribute. diff --git a/website/docs/d/iam_api_key.html.markdown b/website/docs/d/iam_api_key.html.markdown index 3f8a2b17b..bad195b06 100644 --- a/website/docs/d/iam_api_key.html.markdown +++ b/website/docs/d/iam_api_key.html.markdown @@ -1,7 +1,7 @@ --- subcategory: "Identity & Access Management (IAM)" layout: "ibm" -page_title: "IBM : iam_api_key" +page_title: "IBM : ibm_iam_api_key" sidebar_current: "docs-ibm-datasource-iam-api-key" description: |- Get information about a IAM API key. @@ -9,13 +9,13 @@ description: |- # ibm_iam_api_key -Retrieve information about an `iam_api_key` data sources. For more information, about IAM API key, see [managing user API keys](/docs/account?topic=account-userapikey). +Retrieve information about an IAM API key data sources. For more information, about IAM API key, see [managing user API keys](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui). ## Example usage ```terraform -data "iam_api_key" "iam_api_key" { +data "ibm_iam_api_key" "iam_api_key" { apikey_id = "id" } ``` @@ -31,7 +31,7 @@ Review the argument references that you can specify for your data source. In addition to the argument reference list, you can access the following attribute references after your data source is created. - `account_id` - (String) ID of the account that this API key authenticates for. -- `apikey_id` - (String) The unique identifier of the `iam_api_key`. +- `apikey_id` - (String) The unique identifier of the IBM-Cloud Api Key. - `crn` - (String) Cloud Resource Name (CRN) of the item. For example Cloud Resource Name: `crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-5678`. - `created_at` - (Timestamp) If set contains a date time string of the creation date in ISO format. - `created_by` - (String) IAM ID of the user or service which created the API key. diff --git a/website/docs/d/iam_authorization_policies.html.markdown b/website/docs/d/iam_authorization_policies.html.markdown new file mode 100644 index 000000000..68840df95 --- /dev/null +++ b/website/docs/d/iam_authorization_policies.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Identity & Access Management (IAM)" +layout: "ibm" +page_title: "IBM : iam_authorization_policy" +description: |- + Get information about an IBM IAM service authorizations. +--- + +# ibm_iam_authorization_policies + +Retrieve information about an IAM service authorization policy. For more information, about IAM service authorizations, see [using authorizations to grant access between services](https://cloud.ibm.com/docs/account?topic=account-serviceauth). + +## Example usage + +```terraform +data "ibm_iam_authorization_policies" "testacc_ds_authorization_policy" { +} + +``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `account_id` - (Optional, String) An alpha-numeric value identifying the account ID. +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for the tracking calls. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `policies` - (List) A nested block describes IAM Authorization Policies in an account. + + Nested scheme for `policies`: + - `description` (String) The description of the IAM User Policy. + - `id` - (String) The unique identifier of the IAM user policy. The ID is composed of `/`. + - `roles`- (String) The roles that are assigned to the policy. + - `resources`- (List of objects) A nested block describes the resources in the policy. + + Nested scheme for `resources`: + - `source_service_account` - (Optional, Forces new resource, string) The account GUID of source service. + - `source_service_name` - (Required, Forces new resource, string) The source service name. + - `target_service_name` - (Required, Forces new resource, string) The target service name. + - `source_resource_instance_id` - (Optional, Forces new resource, string) The source resource instance id. + - `target_resource_instance_id` - (Optional, Forces new resource, string) The target resource instance id. + - `source_resource_type` - (Optional, Forces new resource, string) The resource type of source service. + - `target_resource_type` - (Optional, Forces new resource, string) The resource type of target service. + - `source_resource_group_id` - (Optional, Forces new resource, string) The source resource group id. + - `target_resource_group_id` - (Optional, Forces new resource, string) The target resource group id. diff --git a/website/docs/d/iam_service_policy.html.markdown b/website/docs/d/iam_service_policy.html.markdown index 5d8d2060c..8c2f86798 100644 --- a/website/docs/d/iam_service_policy.html.markdown +++ b/website/docs/d/iam_service_policy.html.markdown @@ -26,6 +26,7 @@ resource "ibm_iam_service_policy" "policy" { data "ibm_iam_service_policy" "testacc_ds_service_policy" { iam_service_id = ibm_iam_service_policy.policy.iam_service_id + transaction_id = "terrformServicePolicy" } ``` @@ -37,6 +38,7 @@ Review the argument references that you can specify for your data source. - `iam_service_id` - (Required, String) The UUID of the service ID. - `iam_id` - (Optional, String) IAM ID of the service ID. One of the `iam_service_id` or `iam_id` is required argument. You can use to get cross account service ID policy. - `sort`- Optional - (String) The single field sort query for policies. +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for the tracking calls. ## Attribute reference @@ -46,7 +48,7 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `policies`: - `description` (String) The description of the IAM Service Policy. - - `id` - (String) The unique identifier of the IAM service policy. The ID is composed of `/`. If policy is created by using . The ID is composed of `/` if policy is created by using . + - `id` - (String) The unique identifier of the IAM service policy. The ID is composed of `/`. If policy is created by using . The ID is composed of `/` if policy is created by using . - `roles`- (String) The roles that are assigned to the policy. - `resources`- (List of objects) A nested block describes the resources in the policy. @@ -56,4 +58,12 @@ In addition to all argument reference list, you can access the following attribu - `region`- (String) The region of the policy definition. - `resource_type`- (String) The resource type of the policy definition. - `resource`- (String) The resource of the policy definition. - - `resource_group_id`- (String) The ID of the resource group. \ No newline at end of file + - `resource_group_id`- (String) The ID of the resource group. + - `attributes` (Map) A set of resource attributes in the format `name=value,name=value`. + + - `resource_tags`- (List of objects) A nested block describes the access management tags in the policy. + + Nested scheme for `resource_tags`: + - `name` - (String) The key of an access management tag. + - `value` - (String) The value of an access management tag. + - `operator` - (String) Operator of an attribute. \ No newline at end of file diff --git a/website/docs/d/iam_trusted_profile_claim_rules.markdown b/website/docs/d/iam_trusted_profile_claim_rules.markdown new file mode 100644 index 000000000..42b5659d7 --- /dev/null +++ b/website/docs/d/iam_trusted_profile_claim_rules.markdown @@ -0,0 +1,48 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_iam_trusted_profile_claim_rules" +description: |- + Get information about iam_trusted_profiles_claim_rules +subcategory: "Identity & Access Management (IAM)" +--- + +# ibm_iam_trusted_profile_claim_rules + +Retrieve list of IAM trusted profile claim rule as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about trusted profile claim rules, see [list claim rule for a trusted profile](https://cloud.ibm.com/apidocs/iam-identity-token-api#list-claim-rule) + +## Example usage + +```terraform +data "ibm_iam_trusted_profile_claim_rules" "iam_trusted_profiles_claim_rules" { + profile_id = "profile_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +* `profile_id` - (Required, Forces new resource, String) ID of the trusted profile. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the iam_trusted_profiles_claim_rules. +* `rules` - (List) List of claim rules. + Nested scheme for **rules**: + * `cr_type` - (String) The compute resource type. Not required if type is Profile-SAML. Valid values are VSI, IKS_SA, ROKS_SA. + * `conditions` - (List) Conditions of this claim rule. + Nested scheme for **conditions**: + * `claim` - (String) The claim to evaluate against. + * `operator` - (String) The operation to perform on the claim. valid values are EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, CONTAINS, IN. + * `value` - (String) The stringified JSON value that the claim is compared to using the operator. + * `created_at` - (String) If set contains a date time string of the creation date in ISO format. + * `entity_tag` - (String) version of the claim rule. + * `expiration` - (Integer) Session expiration in seconds. + * `id` - (String) the unique identifier of the claim rule. + * `modified_at` - (String) If set contains a date time string of the last modification date in ISO format. + * `name` - (String) The optional claim rule name. + * `realm_name` - (String) The realm name of the Idp this claim rule applies to. + * `type` - (String) Type of the Calim rule, either `Profile-SAML` or `Profile-CR`. + diff --git a/website/docs/d/iam_trusted_profile_links.html.markdown b/website/docs/d/iam_trusted_profile_links.html.markdown new file mode 100644 index 000000000..113f1ff69 --- /dev/null +++ b/website/docs/d/iam_trusted_profile_links.html.markdown @@ -0,0 +1,44 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_iam_trusted_profile_links" +description: |- + Get information about iam_trusted_profile_links +subcategory: "Identity & Access Management (IAM)" +--- + +# ibm_iam_trusted_profile_links + +Retrieve list of IAM trusted profile link as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about trusted profile link, see [list link to a trusted profile](https://cloud.ibm.com/apidocs/iam-identity-token-api#list-link) + +## Example usage + +```terraform +data "ibm_iam_trusted_profile_links" "iam_trusted_profile_links" { + profile_id = "profile_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +* `profile_id` - (Required, String) ID of the trusted profile. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the iam_trusted_profile_links. +* `links` - (List) List of links to a trusted profile. + Nested scheme for **links**: + * `cr_type` - (String) The compute resource type. Valid values are VSI, IKS_SA, ROKS_SA. + * `created_at` - (String) If set contains a date time string of the creation date in ISO format. + * `entity_tag` - (String) version of the claim rule. + * `id` - (String) the unique identifier of the claim rule. + * `link` - (List) + Nested scheme for **link**: + * `crn` - (String) The CRN of the compute resource. + * `namespace` - (String) The compute resource namespace, only required if cr_type is IKS_SA or ROKS_SA. + * `name` - (String) Name of the compute resource, only required if cr_type is IKS_SA or ROKS_SA. + * `modified_at` - (String) If set contains a date time string of the last modification date in ISO format. + * `name` - (String) Optional name of the Link. diff --git a/website/docs/d/iam_trusted_profile_policy.html.markdown b/website/docs/d/iam_trusted_profile_policy.html.markdown index 12ad20287..5ef37f5f9 100644 --- a/website/docs/d/iam_trusted_profile_policy.html.markdown +++ b/website/docs/d/iam_trusted_profile_policy.html.markdown @@ -26,6 +26,7 @@ resource "ibm_iam_trusted_profile_policy" "policy" { data "ibm_iam_trusted_profile_policy" "policy" { profile_id = ibm_iam_trusted_profile_policy.policy.profile_id + transaction_id = "terrformTrustedPolicy" } ``` @@ -37,6 +38,7 @@ Review the argument references that you can specify for your data source. - `profile_id` - (Required, String) The UUID of the trusted profile. Either `profile_id` or `iam_id` is required. - `iam_id` - (Optional, String) IAM ID of the trusted profile. Either `profile_id` or `iam_id` is required. - `sort`- Optional - (String) The single field sort query for policies. +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for the tracking calls. ## Attribute reference @@ -46,9 +48,10 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `policies`: - `description` (String) The description of the IAM trusted profile policy. - - `id` - (String) The unique identifier of the IAM trusted profile policy. The ID is composed of `/`. If policy is created by using . The ID is composed of `/` if policy is created by using . + - `id` - (String) The unique identifier of the IAM trusted profile policy. The ID is composed of `/`. If policy is created by using . The ID is composed of `/` if policy is created by using . - `roles`- (String) The roles that are assigned to the policy. - `resources`- (List of objects) A nested block describes the resources in the policy. + Nested scheme for `resources`: - `service`- (String) The service name of the policy definition. @@ -56,4 +59,12 @@ In addition to all argument reference list, you can access the following attribu - `region`- (String) The region of the policy definition. - `resource_type`- (String) The resource type of the policy definition. - `resource`- (String) The resource of the policy definition. - - `resource_group_id`- (String) The ID of the resource group. \ No newline at end of file + - `resource_group_id`- (String) The ID of the resource group. + - `attributes` (Map) A set of resource attributes in the format `name=value,name=value`. + + - `resource_tags`- (List of objects) A nested block describes the access management tags in the policy. + + Nested scheme for `resource_tags`: + - `name` - (String) The key of an access management tag. + - `value` - (String) The value of an access management tag. + - `operator` - (String) Operator of an attribute. \ No newline at end of file diff --git a/website/docs/d/iam_trusted_profiles.html.markdown b/website/docs/d/iam_trusted_profiles.html.markdown new file mode 100644 index 000000000..433f1935c --- /dev/null +++ b/website/docs/d/iam_trusted_profiles.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_iam_trusted_profiles" +description: |- + Get information about iam_trusted_profiles +subcategory: "Identity & Access Management (IAM)" +--- + +# ibm_iam_trusted_profiles + +List IAM trusted profile resource. For more information, about list trusted profile, see [List a trusted profile](https://cloud.ibm.com/apidocs/iam-identity-token-api#list-profile) + +## Example usage + +```terraform +data "ibm_iam_trusted_profiles" "iam_trusted_profiles" { + account_id = "account_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +* `account_id` - (Optional, String) Account ID to query for trusted profiles. +* `name` - (Optional, String) Name of the trusted profile to query. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the iam_trusted_profiles. + +* `profiles` - (List) List of trusted profiles. + Nested scheme for **profiles**: + * `account_id` - (String) ID of the account that this trusted profile belong to. + * `created_at` - (String) If set contains a date time string of the creation date in ISO format. + * `crn` - (String) Cloud Resource Name of the item. Example Cloud Resource Name: `crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::profile:Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c`. + * `description` - (String) The optional description of the trusted profile. The 'description' property is only available if a description was provided during a + * `entity_tag` - (String) Version of the trusted profile details object. You need to specify this value when updating the trusted profile to avoid stale updates. + * `history` - (List) History of the trusted profile. + Nested scheme for **history**: + * `action` - (String) Action of the history entry. + * `iam_id` - (String) IAM ID of the identity which triggered the action. + * `iam_id_account` - (String) Account of the identity which triggered the action. + * `message` - (String) Message which summarizes the executed action. + * `params` - (List) Params of the history entry. + * `timestamp` - (String) Timestamp when the action was triggered. + * `iam_id` - (String) The iam_id of this trusted profile. + * `id` - (String) the unique identifier of the trusted profile. Example:`Profile-94497d0d-2ac3-41bf-a993-a49d1b14627c`. + * `ims_account_id` - (Integer) IMS acount ID of the trusted profile. + * `ims_user_id` - (Integer) IMS user ID of the trusted profile. + * `modified_at` - (String) If set contains a date time string of the last modification date in ISO format. + * `name` - (String) Name of the trusted profile. The name is checked for uniqueness. Therefore trusted profiles with the same names can not exist in the same account. + diff --git a/website/docs/d/iam_user_policy.html.markdown b/website/docs/d/iam_user_policy.html.markdown index de2a7284d..5e1b43a09 100644 --- a/website/docs/d/iam_user_policy.html.markdown +++ b/website/docs/d/iam_user_policy.html.markdown @@ -25,6 +25,7 @@ resource "ibm_iam_user_policy" "policy" { data "ibm_iam_user_policy" "testacc_ds_user_policy" { ibm_id = ibm_iam_user_policy.policy.ibm_id + transaction_id = "terrformUserPolicy" } ``` @@ -35,6 +36,7 @@ Review the argument references that you can specify for your data source. - `ibm_id` - (Required, String) The IBM ID or email address of the user. - `sort`- (Optional, String) The single field sort query for policies. +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for the tracking calls. ## Attribute reference @@ -45,10 +47,8 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `policies`: - `description` (String) The description of the IAM User Policy. - `id` - (String) The unique identifier of the IAM user policy. The ID is composed of `/`. - - `roles`- (String) The roles that are assigned to the policy. - - - Nested scheme for `roles`: - - `resources`- (List of objects) A nested block describes the resources in the policy. + - `roles`- (String) The roles that are assigned to the policy. + - `resources`- (List of objects) A nested block describes the resources in the policy. Nested scheme for `resources`: - `service` - (String) The service name of the policy definition. @@ -57,3 +57,11 @@ In addition to all argument reference list, you can access the following attribu - `resource` - (String) The resource of the policy definition. - `resource_group_id` - (String) The ID of the resource group. - `resource_instance_id`- (String) The ID of resource instance of the policy definition. + - `attributes` (Map) A set of resource attributes in the format `name=value,name=value`. + + - `resource_tags`- (List of objects) A nested block describes the access management tags in the policy. + + Nested scheme for `resource_tags`: + - `name` - (String) The key of an access management tag. + - `value` - (String) The value of an access management tag. + - `operator` - (String) Operator of an attribute. diff --git a/website/docs/d/is_backup_policies.html.markdown b/website/docs/d/is_backup_policies.html.markdown new file mode 100644 index 000000000..3b21acabf --- /dev/null +++ b/website/docs/d/is_backup_policies.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_backup_policies" +description: |- + Get information about backup policies. +--- + +# ibm_is_backup_policies + +Provides a read-only data source for BackupPolicyCollection. For more information, about backup policy in your IBM Cloud VPC, see [Backup policy](https://cloud.ibm.com/docs/vpc?topic=vpc-backup-view-policies). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_backup_policies" "example" { +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `name` - (Optional, String) Filters the collection to resources with the exact specified name. +- `resource_group` - (Optional, String) Filters the collection to resources in the resource group with the specified identifier. +- `tag` - (Optional, String) Filters the collection to resources with the exact tag value. + +## Attribute Reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the BackupPolicyCollection. +- `backup_policies` - (List) Collection of backup policies. + + Nested `backup_policies` blocks have the following structure: + - `created_at` - (String) The date and time that the backup policy was created. + - `crn` - (String) The CRN for this backup policy. + - `href` - (String) The URL for this backup policy. + - `id` - (String) The unique identifier for this backup policy. + - `last_job_completed_at` - (String) he date and time that the most recent job for this backup policy completed. + - `lifecycle_state` - (String) The lifecycle state of the backup policy. + - `match_resource_types` - (List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. + - `match_user_tags` - (List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. + - `name` - (String) The unique user-defined name for this backup policy. + - `plans` - (List) The plans for the backup policy. + + Nested `plans` blocks have the following structure: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user-defined name for this backup policy plan. + - `resource_type` - (String) The type of resource referenced. + - `resource_group` - (List) The resource group object, for this backup policy. + + Nested `resource_group` blocks have the following structure: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + + diff --git a/website/docs/d/is_backup_policy.html.markdown b/website/docs/d/is_backup_policy.html.markdown new file mode 100644 index 000000000..c6e2a1119 --- /dev/null +++ b/website/docs/d/is_backup_policy.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_backup_policy" +description: |- + Get information about backup policy. +--- + +# ibm_is_backup_policy + +Provides a read-only data source for BackupPolicy. For more information, about backup policy in your IBM Cloud VPC, see [Backup policy](https://cloud.ibm.com/docs/vpc?topic=vpc-backup-view-policies). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_backup_policy" "example" { + identifier = ibm_is_backup_policy.example.id +} +``` + +## Argument Reference +Review the argument references that you can specify for your data source. + +- `backup_policy_id` - (Optional, string) Filters the collection to backup policy jobs with the backup plan with the specified identifier. +- `identifier` - (Optional, string) The backup policy identifier, `identifier` and `name` are mutually exclusive. +- `name` - (Optional, string) The unique user-defined name for backup policy, `identifier` and `name` are mutually exclusive. + +## Attribute Reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the BackupPolicy. +- `created_at` - (String) The date and time that the backup policy was created. +- `crn` - (String) The CRN for this backup policy. +- `href` - (String) The URL for this backup policy. +- `last_job_completed_at` - (String) he date and time that the most recent job for this backup policy completed. +- `lifecycle_state` - (String) The lifecycle state of the backup policy. +- `match_resource_types` - (List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. +- `match_user_tags` - (List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. +- `name` - (String) The unique user-defined name for this backup policy. +- `plans` - (List) The plans for the backup policy. + + Nested `plans` blocks have the following structure: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user-defined name for this backup policy plan. + - `resource_type` - (String) The type of resource referenced. +- `resource_group` - (List) The resource group object, for this backup policy. + + Nested `resource_group` blocks have the following structure: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. +- `resource_type` - (String) The type of resource referenced. + diff --git a/website/docs/d/is_backup_policy_plan.html.markdown b/website/docs/d/is_backup_policy_plan.html.markdown new file mode 100644 index 000000000..703b5933b --- /dev/null +++ b/website/docs/d/is_backup_policy_plan.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_backup_policy_plan" +description: |- + Get information about backup policy plan. +--- + +# ibm_is_backup_policy_plan + +Provides a read-only data source for BackupPolicyPlan. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_backup_policy_plan" "example" { + backup_policy_id = ibm_is_backup_policy.example.id + identifier = ibm_is_backup_policy_plan.example.backup_policy_plan_id +} +``` + +->**Note:** Backup Policy Jobs are getting enhanced, will be available soon. + +## Argument Reference +Review the argument references that you can specify for your data source. + +- `backup_policy_id` - (Required, String) The backup policy identifier. +- `identifier` - (Optional, String) The backup policy plan identifier, `identifier` and `name` are mutually exclusive. +- `name` - (Optional, String) The unique user-defined name for backup policy, `identifier` and `name` are mutually exclusive. + +## Attribute Reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the BackupPolicyPlan. +- `active` - (Boolean) Indicates whether the plan is active. +- `attach_user_tags` - (List) User tags to attach to each resource created by this plan. +- `copy_user_tags` - (Boolean) Indicates whether to copy the source's user tags to the created resource. +- `created_at` - (String) The date and time that the backup policy plan was created. +- `cron_spec` - (String) The cron specification for the backup schedule. + + ->**Note** The backup policy jobs (which create and delete backups for this plan) will not start until this time, and may start for up to 90 minutes after this time.All backup schedules for plans in the same policy must be at least an hour apart. + +- `deletion_trigger` (List) `deletion_trigger` block has the following structure: + + Nested scheme for `deletion_trigger`: + - `delete_after` - (Integer) The maximum number of days to keep each backup after creation. + - `delete_over_count` - (Integer) The maximum number of recent backups to keep. If absent, there is no maximum. +- `href` - (String) The URL for this backup policy plan. +- `lifecycle_state` - (String) The lifecycle state of this backup policy plan. +- `resource_type` - (String) The type of resource referenced. diff --git a/website/docs/d/is_backup_policy_plans.html.markdown b/website/docs/d/is_backup_policy_plans.html.markdown new file mode 100644 index 000000000..fb9b4d576 --- /dev/null +++ b/website/docs/d/is_backup_policy_plans.html.markdown @@ -0,0 +1,65 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_backup_policy_plans" +description: |- + Get information about backup policy plans. +--- + +# ibm_is_backup_policy_plans + +Provides a read-only data source for BackupPolicyPlanCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_backup_policy_plans" "example" { + backup_policy_id = ibm_is_backup_policy.example.id + name = "example-backup-policy-plan" +} +``` + +->**Note:** Backup Policy Jobs are getting enhanced, will be available soon. + +## Argument Reference +Review the argument references that you can specify for your data source. + +- `backup_policy_id` - (Required, string) The backup policy identifier. +- `name` - (Optional, string) The unique user-defined name for this backup policy plan. + +## Attribute Reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the BackupPolicyPlanCollection. +- `plans` - (List) Collection of backup policy plans. + + Nested `plans` blocks have the following structure: + - `active` - (Boolean) Indicates whether the plan is active. + - `attach_user_tags` - (List) User tags to attach to each resource created by this plan. + - `copy_user_tags` - (Boolean) Indicates whether to copy the source's user tags to the created resource. + - `created_at` - (String) The date and time that the backup policy plan was created. + - `cron_spec` - (String) The cron specification for the backup schedule. + + ->**Note** The backup policy jobs (which create and delete backups for this plan) will not start until this time, and may start for up to 90 minutes after this time.All backup schedules for plans in the same policy must be at least an hour apart. + + - `deletion_trigger` (List) `deletion_trigger` block has the following structure: + + Nested scheme for `deletion_trigger`: + - `delete_after` - (Integer) The maximum number of days to keep each backup after creation. + - `delete_over_count` - (Integer) The maximum number of recent backups to keep. If absent, there is no maximum. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `lifecycle_state` - (String) The lifecycle state of this backup policy plan. + - `name` - (String) The unique user-defined name for this backup policy plan. + - `resource_type` - (String) The type of resource referenced. diff --git a/website/docs/d/is_bare_metal_server.markdown b/website/docs/d/is_bare_metal_server.markdown new file mode 100644 index 000000000..f3d25475d --- /dev/null +++ b/website/docs/d/is_bare_metal_server.markdown @@ -0,0 +1,121 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : Bare Metal Server" +description: |- + Manages IBM Cloud Bare Metal Server. +--- + +# ibm\_is_bare_metal_server + +Import the details of an existing IBM Cloud Bare Metal Server as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage with identifier + +```terraform +data "ibm_is_bare_metal_server" "example" { + identifier = "9328-9849-9849-9849" +} +``` + +## Example Usage with name +```terraform +data "ibm_is_bare_metal_server" "example" { + name = "example-server" +} +``` + +## Argument Reference + +Review the argument references that you can specify for your data source. + +- `identifier` - (Optional, String) The id for this bare metal server. +- `name` - (Optional, String) The name for this bare metal server. + + ~> **NOTE** + `identifier` and `name` are mutually exclusive. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the bare metal server's network interfaces. +- `boot_target` - (String) The unique identifier for this bare metal server disk. +- `cpu` - (List) A nested block describing the CPU configuration of this bare metal server. + Nested scheme for `cpu`: + - `architecture` - (String) The architecture of the bare metal server. + - `core_count` - (Integer) The total number of cores + - `socket_count` - (Integer) The total number of CPU sockets + - `threads_per_core` - (Integer) The total number of hardware threads per core +- `created_at` - (Timestamp) The date and time that the bare metal server was created. +- `crn` - (String) The CRN for this bare metal server +- `disks` - (List) The disks for this bare metal server, including any disks that are associated with the boot_target. + Nested scheme for `disks`: + - `href` - (String) The URL for this bare metal server disk. + - `id` - (String) The unique identifier for this bare metal server disk. + - `interface_type` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. [ **nvme**, **sata** ] + - `name` - (String) The user-defined name for this disk + - `resource_type` - (String) The resource type + - `size` - (Integer) The size of the disk in GB (gigabytes) +- `href` - (String) The URL for this bare metal server +- `id` - (String) The unique identifier for this bare metal server +- `image` - (String) Image used in the bare metal server. +- `keys` - (String) Image used in the bare metal server. +- `memory` - (Integer) The amount of memory, truncated to whole gibibytes +- `name` - (String) The name of the bare metal server. +- `network_interfaces` - (List) A nested block describing the additional network interface of this instance. + Nested scheme for `network_interfaces`: + - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `href` - (String) The href of the network interface. + - `id` - (String) The id of the network interface. + - `name` - (String) The name of the network interface. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `resource_type`- (String) The resource type. + + - `security_groups` - (Array) List of security groups. + - `subnet` - (String) ID of the subnet. +- `primary_network_interface` - (List) A nested block describing the primary network interface of this bare metal server. + Nested scheme for `primary_network_interface`: + - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `href` - (String) The href of the network interface. + - `id` - (String) The id of the network interface. + - `name` - (String) The name of the network interface. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `resource_type`- (String) The resource type. + - `security_groups` - (Array) List of security groups. + - `subnet` - (String) ID of the subnet. +- `profile` - (String) The name for this bare metal server profile +- `resource_group` - (String) resource group id of the bare metal server. +- `resource_type` - (String) The type of resource referenced +- `status` - (String) The status of the bare metal server [ **failed**, **pending**, **restarting**, **running**, **starting**, **stopped**, **stopping** ] +- `status_reasons` - (List) Array of reasons for the current status (if any). + Nested scheme for `status_reasons`: + - `code` - (String) The status reason code + - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason +- `tags` - (Array) Tags associated with the instance. +- `vpc` - (String) The VPC this bare metal server resides in. +- `zone` - (String) The zone this bare metal server resides in. diff --git a/website/docs/d/is_bare_metal_server_disk.markdown b/website/docs/d/is_bare_metal_server_disk.markdown new file mode 100644 index 000000000..8648328c1 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_disk.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_disk" +description: |- + Manages IBM Cloud Bare Metal Server Disk. +--- + +# ibm\_is_bare_metal_server_disk + +Import the details of an existing IBM Cloud Bare Metal Server Disk as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal server disks, see [Storage of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-storage). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_disk" "ds_bms_disk" { + bare_metal_server = ibm_is_bare_metal_server.example.id + disk = ibm_is_bare_metal_server.example.disks.0.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The id for this bare metal server. +- `disk` - (Required, String) The id for this bare metal server disk. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `href` - (String) The URL for this bare metal server disk. +- `id` - (String) The unique identifier for this bare metal server disk. +- `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. +- `name` - (String) The user-defined name for this disk. +- `resource_type` - (String) The resource type. +- `size` - (String) The size of the disk in GB (gigabytes). + + diff --git a/website/docs/d/is_bare_metal_server_disks.markdown b/website/docs/d/is_bare_metal_server_disks.markdown new file mode 100644 index 000000000..ab12ba9b3 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_disks.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_disks" +description: |- + Manages IBM Cloud Bare Metal Server Disks. +--- + +# ibm\_is_bare_metal_server_disks + +Import the details of an existing IBM Cloud vBare Metal Server Disk collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal server disks, see [Storage of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-storage). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_disks" "ds_bmserver_disks" { + bare_metal_server = ibm_is_bare_metal_server.example.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The id for this bare metal server. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `disks` - (List of objects) A list of bare metal server disks. Disk is a block device that is locally attached to the physical server. By default, the listed disks are sorted by their created_at property values, with the newest disk first. + + Nested scheme for `disks`: + - `href` - (String) The URL for this bare metal server disk. + - `id` - (String) The unique identifier for this bare metal server disk. + - `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. + - `name` - (String) The user-defined name for this disk. + - `resource_type` - (String) The resource type. + - `size` - (String) The size of the disk in GB (gigabytes). diff --git a/website/docs/d/is_bare_metal_server_initialization.markdown b/website/docs/d/is_bare_metal_server_initialization.markdown new file mode 100644 index 000000000..9f71f8c47 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_initialization.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_disk" +description: |- + Manages IBM Cloud Bare Metal Server Disk. +--- + +# ibm\_is_bare_metal_server_disk + +Import the details of configuration variables used to initialize the bare metal server, such as the image used, SSH keys, and any configured usernames and passwords as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_initialization" "ds_bms_ini" { + bare_metal_server = ibm_is_bare_metal_server.example.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The id for this bare metal server. +- `passphrase` - (Optional, String) The passphrase that you used when you created your SSH key. If you did not enter a passphrase when you created the SSH key, do not provide this input parameter. +- `private_key` - (Optional, String) The private key of an SSH key that you want to add to your Bare metal server during creation in PEM format. It is used to decrypt the default password of the Windows administrator for the bare metal server if the image is used of type `windows`. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The unique identifier for this bare metal server. +- `image` - (String) The unique identifier for this image +- `image_name` - (String) The user-defined or system-provided name for this image. +- `keys` - (Array) List of public SSH keys used at initialization. +- `user_accounts` - (List) The size of the disk in GB (gigabytes). + Nested scheme for `user_accounts`: + - `encrypted_password` - (String) The password at initialization, encrypted using encryption_key, and returned base64-encoded. + - `encryption_key` - (String) The CRN for this key. + - `password` - (String) The password that you can use to access your bare metal server. + - `resource_type` - (String) The type of resource referenced. + - `username` - (String) The username for the account created at initialization. diff --git a/website/docs/d/is_bare_metal_server_network_interface.markdown b/website/docs/d/is_bare_metal_server_network_interface.markdown new file mode 100644 index 000000000..bb84c340d --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interface.markdown @@ -0,0 +1,63 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface" +description: |- + Manages IBM Cloud Bare Metal Server Network Interface. +--- + +# ibm\_is_bare_metal_server_network_interface + +Import the details of an existing IBM Cloud Bare Metal Server Network Interface as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [Network of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-network). + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_network_interface" "ds_bms_nic" { + bare_metal_server = "xxxx-xxxxx-xxxxx-xxxx" + network_interface = "xxxx-xxxxx-xxxxx-xxxx" +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The id for this bare metal server. +- `network_interface` - (Required, String) The id for this bare metal server network interface. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `allow_interface_to_float` - (Boolean) Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces. +- `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. +- `allowed_vlans` - (Array) Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. +- `enable_infrastructure_nat` - (Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. +- `floating_ips` - (List) The floating IPs associated with this network interface. +- `href` - (String) The URL for this network interface +- `id` - (String) The unique identifier for this network interface +- `interface_type` - (String) The network interface type, supported values are [ **pci**, **vlan** ] +- `mac_address` - (String) The MAC address of the interface. If absent, the value is not known. +- `name` - (String) The user-defined name for this network interface +- `port_speed` - (Integer) The network interface port speed in Mbps +- `primary_ip` - (List) + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href` - (String) The URL for this reserved IP + - `reserved_ip` - (String) The unique identifier for this reserved IP + - `name` - (String) The user-defined or system-provided name for this reserved IP + - `resource_type` - (String)The resource type [ **subnet_reserved_ip** ] +- `security_groups` - (Array) Collection of security groups +- `status` - (String) The status of the network interface. Supported values are [ **available**, **deleting**, **failed**, **pending** ] +- `subnet` - (List) The associated subnet +- `type` - (String) The type of this bare metal server network interface. Supported values are [ **primary**, **secondary** ] +- `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface \ No newline at end of file diff --git a/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown b/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown new file mode 100644 index 000000000..3ebf3f507 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface_floating_ip" +description: |- + Fetches floating ip information associated with network interface of a bare metal server. +--- + +# is_bare_metal_server_network_interface_floating_ip +Retrieve an information of VPC floating IP associated with network interface of a bare metal server as a read-only data source. For more information, about floating IP, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform + + data "is_bare_metal_server_network_interface_floating_ip" "test" { + bare_metal_server = ibm_is_bare_metal_server.example.id + floating_ip = ibm_is_floating_ip.example.id + network_interface = ibm_is_bare_metal_server_network_interface.example.id + } + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The bare metal server id. +- `floating_ip` - (Required, String) The identifier of the floating ip. +- `network_interface` - (Required, String) The identifier of the bare metal server network interface. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `address` - (String) The floating IP address. +- `crn` - (String) The CRN for this floating IP. +- `id` - (String) The unique identifier of the floating IP. +- `status` - (String) Provisioning status of the floating IP address. +- `tags` - (String) The tags associated with VPC. +- `target` - (String) The ID of the network interface used to allocate the floating IP address. +- `zone` - (String) The zone name where to create the floating IP address. diff --git a/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown b/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown new file mode 100644 index 000000000..dfc69fe6d --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface_floating_ips" +description: |- + Fetches all floating ip information associated with network interface of a bare metal server. +--- + +# is_bare_metal_server_network_interface_floating_ips +Retrieve an information of list of floating IPs on a bare metal network interface IBM Cloud as a read-only data source. For more information, about floating IP, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform + + data "is_bare_metal_server_network_interface_floating_ips" "test" { + bare_metal_server = "xxxx-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" + network_interface = "xxxx-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" + } + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The bare metal server id. +- `network_interface` - (Required, String) The identifier of the bare metal server network interface. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `floating_ips` - (List of objects) A list of all floating ips on the network interface of the bare metal server. + + Nested scheme for `floating_ips`: + - `address` - (String) The floating IP address. + - `crn` - (String) The CRN for this floating IP. + - `id` - (String) The unique identifier of the floating IP. + - `status` - (String) Provisioning status of the floating IP address. + - `tags` - (String) The tags associated with VPC. + - `target` - (String) The ID of the network interface used to allocate the floating IP address. + - `zone` - (String) The zone name where to create the floating IP address. diff --git a/website/docs/d/is_bare_metal_server_network_interface_reserved_ip.html.markdown b/website/docs/d/is_bare_metal_server_network_interface_reserved_ip.html.markdown new file mode 100644 index 000000000..554f201fb --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interface_reserved_ip.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reserved_ip" +description: |- + Shows the info for a reserved IP and bare metal server network interface. +--- + +# ibm\_is_bare_metal_server_network_interface_reserved_ip + +Import the details of an existing Reserved IP in a network interface of an bare metal server as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_bare_metal_server_network_interface_reserved_ip" "data_reserved_ip" { + bare_metal_server = ibm_is_bare_metal_server.test_bare_metal_server.id + network_interface = ibm_is_bare_metal_server.test_bare_metal_server.network_interfaces.0.id + reserved_ip = ibm_is_bare_metal_server.test_bare_metal_server.network_interfaces.0.ips.0.id +} +``` + +## Argument Reference + +The following arguments are supported as inputs/request params: + +- `bare_metal_server` - (Required, string) The id for the bare metal server. +- `network_interface` - (Required, string) The id for the network interface. +- `reserved_ip` - (Required, string) The id for the Reserved IP. + + +## Attribute Reference + +The following attributes are exported as output/response: + +- `auto_delete` - (String) The auto_delete boolean for reserved IP +- `created_at` - (String) The creation timestamp for the reserved IP +- `href` - (String) The unique reference for the reserved IP +- `id` - (String) The id for the reserved IP +- `name` - (String) The name for the reserved IP +- `owner` - (String) The owner of the reserved IP +- `reserved_ip` - (String) Same as `id` +- `resource_type` - (String) The type of resource +- `target` - (String) The id for the target for the reserved IP diff --git a/website/docs/d/is_bare_metal_server_network_interface_reserved_ips.html.markdown b/website/docs/d/is_bare_metal_server_network_interface_reserved_ips.html.markdown new file mode 100644 index 000000000..efbd11d55 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interface_reserved_ips.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reserved_ips" +description: |- + Lists all the info in reserved IP for Bare Metal Server network interface. +--- + +# ibm\_is_bare_metal_server_network_interface_reserved_ips + +Import the details of all the Reserved IPs in a network interface of an bare metal server as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_bare_metal_server_network_interface_reserved_ips" "data_reserved_ips" { + bare_metal_server = ibm_is_bare_metal_server.test_bare_metal_server.id + network_interface = ibm_is_bare_metal_server.test_bare_metal_server.network_interfaces.0.id +} +``` + +## Argument Reference + +The following arguments are supported as inputs/request params: + +- `bare_metal_server` - (Required, string) The id for the bare metal server. +- `network_interface` - (Required, string) The id for the network interface. + + +## Attribute Reference + +The following attributes are exported as output/response: + +- `id` - The id for the all the reserved ID (current timestamp) +- `reserved_ips` - The collection of all the reserved IPs in the network interface + - `address` - (String) The IP bound for the reserved IP + - `auto_delete` - (Bool) If reserved ip shall be deleted automatically + - `created_at` - (String) The date and time that the reserved IP was created + - `href` - (String) The URL for this reserved IP + - `reserved_ip` - (String) The unique identifier for this reserved IP + - `name` - (String) The user-defined or system-provided name for this reserved IP + - `owner` -(String) The owner of a reserved IP, defining whether it is managed by the user or the provider + - `resource_type` - (String) The resource type + - `target` - (String) The id for the target for the reserved IP. + +- `total_count` - The number of reserved IP in the network interface of the bare metal server diff --git a/website/docs/d/is_bare_metal_server_network_interfaces.markdown b/website/docs/d/is_bare_metal_server_network_interfaces.markdown new file mode 100644 index 000000000..0d9b924eb --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_interfaces.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interfaces" +description: |- + Manages IBM Cloud Bare Metal Server Network Interfaces. +--- + +# ibm\_is_bare_metal_server_network_interfaces + +Import the details of an existing IBM Cloud Bare Metal Server Network Interface collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [Network of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-network). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_network_interfaces" "ds_bms_nics" { + bare_metal_server = "xxxx-xxxxx-xxxxx-xxxx" +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `bare_metal_server` - (Required, String) The id for this bare metal server. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `network_interfaces` - (List of objects) A list of all network interfaces on a bare metal server. A network interface is an abstract representation of a network interface card and connects a bare metal server to a subnet. While each network interface can attach to only one subnet, multiple network interfaces can be created to attach to multiple subnets. Multiple interfaces may also attach to the same subnet. + + Nested scheme for `network_interfaces`: + - `allow_interface_to_float` - (Boolean) Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces. + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `allowed_vlans` - (Array) Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. + - `enable_infrastructure_nat` - (Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. + - `floating_ips` - (List) The floating IPs associated with this network interface. + - `href` - (String) The URL for this network interface + - `id` - (String) The unique identifier for this network interface + - `interface_type` - (String) The network interface type, supported values are [ **pci**, **vlan** ] + - `mac_address` - (String) The MAC address of the interface. If absent, the value is not known. + - `name` - (String) The user-defined name for this network interface + - `port_speed` - (Integer) The network interface port speed in Mbps + - `primary_ip` - (List) + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href` - (String) The URL for this reserved IP + - `reserved_ip` - (String) The unique identifier for this reserved IP + - `name` - (String) The user-defined or system-provided name for this reserved IP + - `resource_type` - (String)The resource type [ **subnet_reserved_ip** ] + + - `security_groups` - (Array) Collection of security groups + - `status` - (String) The status of the network interface. Supported values are [ **available**, **deleting**, **failed**, **pending** ] + - `subnet` - (List) The associated subnet + - `type` - (String) The type of this bare metal server network interface. Supported values are [ **primary**, **secondary** ] + - `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface + \ No newline at end of file diff --git a/website/docs/d/is_bare_metal_server_profile.markdown b/website/docs/d/is_bare_metal_server_profile.markdown new file mode 100644 index 000000000..c8b3442be --- /dev/null +++ b/website/docs/d/is_bare_metal_server_profile.markdown @@ -0,0 +1,103 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : Bare Metal Server Profile" +description: |- + Manages IBM Cloud Bare Metal Server Profile. +--- + +# ibm\_is_bare_metal_server_profile + +Import the details of an existing IBM Cloud Bare Metal Server profile as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal server profile, see [Bare Metal Servers for VPC profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-profile). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_bare_metal_server_profile" "ds_bmsprofile" { + name = "profile-name" +} + +``` + +## Argument Reference + +Review the argument references that you can specify for your data source. + +- `name` - (Required, String) The name for this profile . + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `bandwidth` - (List) The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile. + + Nested scheme for `bandwidth`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. +- `cpu_architecture` - (List) The CPU architecture for a bare metal server with this profile. + + Nested scheme for `cpu_architecture`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. +- `cpu_core_count` - (List) The CPU core count for a bare metal server with this profile. + + Nested scheme for `cpu_core_count`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. +- `cpu_socket_count` - (List) The number of CPU sockets for a bare metal server with this profile. + + Nested scheme for `cpu_socket_count`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. +- `disks` - (List) A nested block describing the collection of the bare metal server profile's disks. + + Nested scheme for `disk`: + - `quantity` - (List) The number of disks of this configuration for a bare metal server with this profile. + + Nested scheme for `quantity`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + + - `size` - (List) The size of the disk in GB (gigabytes). + + Nested scheme for `size`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `supported_interface_types` - (List) The disk interface used for attaching the disk. + + Nested scheme for `supported_interface_types`: + + - `default` - (String) The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported disk interfaces used for attaching the disk. +- `family` - (String) The product family this bare metal server profile belongs to. +- `href` - (String) The URL for this bare metal server profile. +- `id` - (String) The name of the profile. +- `memory` - (List) The memory (in gibibytes) for a bare metal server with this profile. + Nested scheme for `memory`: + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. +- `name` - (String) The name of the profile. +- `os_architecture` - (List) The supported OS architecture(s) for a bare metal server with this profile. + Nested scheme for `os_architecture`: + - `default` - (String) The default OS architecture for a bare metal server with this profile + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported OS architecture(s) for a bare metal server with this profile. +- `resource_type` - (String) The resource type. +- `supported_image_flags` - (Array) An array of flags supported by this bare metal server profile. +- `supported_trusted_platform_module_modes` - (List) An array of supported trusted platform module (TPM) modes for this bare metal server profile. + + Nested scheme for `supported_trusted_platform_module_modes`: + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported trusted platform module (TPM) modes. diff --git a/website/docs/d/is_bare_metal_server_profiles.markdown b/website/docs/d/is_bare_metal_server_profiles.markdown new file mode 100644 index 000000000..e5aba5318 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_profiles.markdown @@ -0,0 +1,98 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : Bare Metal Server Profiles" +description: |- + Manages IBM Cloud Bare Metal Server Profiles. +--- + +# ibm\_is_bare_metal_server_profiles + +Import the details of existing IBM Cloud Bare Metal Server profile collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal server profiles, see [Bare Metal Servers for VPC profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-profile). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform + +data "ibm_is_bare_metal_server_profiles" "ds_bmsprofiles" { +} + +``` + +## Attribute Reference + +Review the attribute references that you can access after you retrieve your data source. + +- `profiles` - List of all bare metal server profiles in the IBM Cloud Infrastructure. + - `bandwidth` - (List) The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile. + + Nested scheme for `bandwidth`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `cpu_architecture` - (List) The CPU architecture for a bare metal server with this profile. + + Nested scheme for `cpu_architecture`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `cpu_core_count` - (List) The CPU core count for a bare metal server with this profile. + + Nested scheme for `cpu_core_count`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `cpu_socket_count` - (List) The number of CPU sockets for a bare metal server with this profile. + + Nested scheme for `cpu_socket_count`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `disks` - (List) A nested block describing the collection of the bare metal server profile's disks. + + Nested scheme for `disk`: + - `quantity` - (List) The number of disks of this configuration for a bare metal server with this profile. + + Nested scheme for `quantity`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + + - `size` - (List) The size of the disk in GB (gigabytes). + + Nested scheme for `size`: + - `type` - (String) The type for this profile field. + - `value` - (Integer) The value for this profile field. + - `supported_interface_types` - (List) The disk interface used for attaching the disk. + + Nested scheme for `supported_interface_types`: + + - `default` - (String) The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported disk interfaces used for attaching the disk. + - `family` - (String) The product family this bare metal server profile belongs to. + - `href` - (String) The URL for this bare metal server profile. + - `id` - (String) The name of the profile. + - `memory` - (List) The memory (in gibibytes) for a bare metal server with this profile. + Nested scheme for `memory`: + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. + - `name` - (String) The name of the profile. + - `os_architecture` - (List) The supported OS architecture(s) for a bare metal server with this profile. + Nested scheme for `os_architecture`: + - `default` - (String) The default OS architecture for a bare metal server with this profile + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported OS architecture(s) for a bare metal server with this profile. + - `resource_type` - (String) The resource type. + - `supported_image_flags` - (Array) An array of flags supported by this bare metal server profile. + - `supported_trusted_platform_module_modes` - (List) An array of supported trusted platform module (TPM) modes for this bare metal server profile. + + Nested scheme for `supported_trusted_platform_module_modes`: + - `type` - (String) The type for this profile field. + - `values` - (Array) The supported trusted platform module (TPM) modes. diff --git a/website/docs/d/is_bare_metal_servers.markdown b/website/docs/d/is_bare_metal_servers.markdown new file mode 100644 index 000000000..2a4e24334 --- /dev/null +++ b/website/docs/d/is_bare_metal_servers.markdown @@ -0,0 +1,103 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : Bare Metal Servers" +description: |- + Manages IBM Cloud Bare Metal Servers. +--- + +# ibm\_is_bare_metal_servers + +Import the details of an existing IBM Cloud vBare Metal Server collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_bare_metal_servers" "example" { +} +``` + +## Attribute Reference + +Review the attribute references that you can access after you retrieve your data source. + +- `servers` - List of all all bare metal servers in the region. + - `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the bare metal server's network interfaces. + - `boot_target` - (String) The unique identifier for this bare metal server disk. + - `cpu` - (List) A nested block describing the CPU configuration of this bare metal server. + Nested scheme for `cpu`: + - `architecture` - (String) The architecture of the bare metal server. + - `core_count` - (Integer) The total number of cores + - `socket_count` - (Integer) The total number of CPU sockets + - `threads_per_core` - (Integer) The total number of hardware threads per core + - `created_at` - (Timestamp) The date and time that the bare metal server was created. + - `crn` - (String) The CRN for this bare metal server + - `disks` - (List) The disks for this bare metal server, including any disks that are associated with the boot_target. + Nested scheme for `disks`: + - `href` - (String) The URL for this bare metal server disk. + - `id` - (String) The unique identifier for this bare metal server disk. + - `interface_type` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. [ **nvme**, **sata** ] + - `name` - (String) The user-defined name for this disk + - `resource_type` - (String) The resource type + - `size` - (Integer) The size of the disk in GB (gigabytes) + - `href` - (String) The URL for this bare metal server + - `id` - (String) The unique identifier for this bare metal server + - `image` - (String) Image used in the bare metal server. + - `keys` - (String) Image used in the bare metal server. + - `memory` - (Integer) The amount of memory, truncated to whole gibibytes + - `name` - (String) The name of the bare metal server. + - `network_interfaces` - (List) A nested block describing the additional network interface of this instance. + Nested scheme for `network_interfaces`: + - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `href` - (String) The href of the network interface. + - `id` - (String) The id of the network interface. + - `name` - (String) The name of the network interface. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + Nested scheme for `primary_ip`: + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `resource_type`- (String) The resource type. + + - `security_groups` - (Array) List of security groups. + - `subnet` - (String) ID of the subnet. + - `primary_network_interface` - (List) A nested block describing the primary network interface of this bare metal server. + Nested scheme for `primary_network_interface`: + - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `href` - (String) The href of the network interface. + - `id` - (String) The id of the network interface. + - `name` - (String) The name of the network interface. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + Nested scheme for `primary_ip`: + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `resource_type`- (String) The resource type. + + - `security_groups` - (Array) List of security groups. + - `subnet` - (String) ID of the subnet. + - `profile` - (String) The name for this bare metal server profile + - `resource_group` - (String) resource group id of the bare metal server. + - `resource_type` - (String) The type of resource referenced + - `status` - (String) The status of the bare metal server [ **failed**, **pending**, **restarting**, **running**, **starting**, **stopped**, **stopping** ] + - `status_reasons` - (List) Array of reasons for the current status (if any). + Nested scheme for `status_reasons`: + - `code` - (String) The status reason code + - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason + - `tags` - (Array) Tags associated with the instance. + - `vpc` - (String) The VPC this bare metal server resides in. + - `zone` - (String) The zone this bare metal server resides in. diff --git a/website/docs/d/is_dedicated_host.html.markdown b/website/docs/d/is_dedicated_host.html.markdown index 28f79fef1..9c9082cd1 100644 --- a/website/docs/d/is_dedicated_host.html.markdown +++ b/website/docs/d/is_dedicated_host.html.markdown @@ -9,13 +9,24 @@ description: |- # ibm_is_dedicated_host Retrieve the dedicated host data sources. For more information, about dedicated host in your IBM Cloud VPC, see [Dedicated hosts](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-dedicated-hosts-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example retrieves information about the dedicated host data sources. ```terraform -data "ibm_is_dedicated_host" "is_dedicated_host" { - host_group = "1e09281b-f177-46fb-baf1-bc152b2e391a" - name = "my-dedicated-host" +data "ibm_is_dedicated_host" "example" { + host_group = ibm_is_dedicated_host_group.example.id + name = "example-dedicated-host" } ``` diff --git a/website/docs/d/is_dedicated_host_disk.html.markdown b/website/docs/d/is_dedicated_host_disk.html.markdown index ea1bb0c2b..30f3c7692 100644 --- a/website/docs/d/is_dedicated_host_disk.html.markdown +++ b/website/docs/d/is_dedicated_host_disk.html.markdown @@ -7,14 +7,26 @@ description: |- --- # ibm_is_dedicated_host_disk + Retrieve the dedicated host disk. For more information, about dedicated host disk, see [migrating a dedicated host instance to another host](https://cloud.ibm.com/docs/virtual-servers?topic=virtual-servers-migrating-dedicated-host). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_disk" "is_dedicated_host_disk" { - dedicated_host = "dedicatedhost id" - disk = "id" +data "ibm_is_dedicated_host_disk" "example" { + dedicated_host = ibm_is_dedicated_host.example.id + disk = data.ibm_is_dedicated_host_disks.example.disks.0.id } ``` @@ -28,9 +40,9 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `available` - (String) The remaining space left for instance placement in GB (gigabytes). -- `id` - (String) The unique identifier of the dedicated host disk. - `created_at` - (Timestamp) The date and time that the disk was created. - `href` - The URL for this disk. +- `id` - (String) The unique identifier of the dedicated host disk. - `instance_disks` - (List) Instance disks that are on the dedicated host disk. Nested scheme for `instance_disks`: diff --git a/website/docs/d/is_dedicated_host_disks.html.markdown b/website/docs/d/is_dedicated_host_disks.html.markdown index f290a1b74..90bda63a3 100644 --- a/website/docs/d/is_dedicated_host_disks.html.markdown +++ b/website/docs/d/is_dedicated_host_disks.html.markdown @@ -7,13 +7,25 @@ description: |- --- # ibm_is_dedicated_host_disks + Retrieve the dedicated host disk collection. For more information, about dedicated host disk collection, see [managing dedicated hosts and groups](https://cloud.ibm.com/docs/vpc?topic=vpc-manage-dedicated-hosts-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_disks" "is_dedicated_host_disks" { - dedicated_host = "dedicatedhost id" +data "ibm_is_dedicated_host_disks" "example" { + dedicated_host = ibm_is_dedicated_host.example.id } ``` @@ -47,7 +59,7 @@ In addition to the argument reference list, you can access the following attribu - `lifecycle_state` - (String) The lifecycle state of this dedicated host disk. - `name` - (String) The user-defined or system-provided name for this disk. - `provisionable` - (String) Indicates whether this dedicated host disk is available for instance disk creation. - - `resource_type` -(String) The type of resource referenced. - - `size` -(String) The size of the disk in GB (gigabytes). + - `resource_type` - (String) The type of resource referenced. + - `size` - (String) The size of the disk in GB (gigabytes). - `supported_instance_interface_types` - (String) The instance disk interfaces supported for this dedicated host disk. - `id` - (String) The unique identifier of the dedicated host disk collection. diff --git a/website/docs/d/is_dedicated_host_group.html.markdown b/website/docs/d/is_dedicated_host_group.html.markdown index efdbc4633..97ceb236c 100644 --- a/website/docs/d/is_dedicated_host_group.html.markdown +++ b/website/docs/d/is_dedicated_host_group.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_dedicated_host_group Retrieve the dedicated host group data sources. For more information, about dedicated host group in your IBM Cloud VPC, see [dedicated hosts groups](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-dedicated-hosts-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_group" "is_dedicated_host_group" { - name = "my-host-group" +data "ibm_is_dedicated_host_group" "example" { + name = "example-host-group" } ``` diff --git a/website/docs/d/is_dedicated_host_groups.html.markdown b/website/docs/d/is_dedicated_host_groups.html.markdown index 3b030d68b..c4c96d503 100644 --- a/website/docs/d/is_dedicated_host_groups.html.markdown +++ b/website/docs/d/is_dedicated_host_groups.html.markdown @@ -9,10 +9,21 @@ description: |- # ibm_is_dedicated_host_groups Retrieve an information the dedicated host group collection. For more information, about dedicated host group collection, see [managing dedicated hosts and groups](https://cloud.ibm.com/docs/vpc?topic=vpc-manage-dedicated-hosts-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_groups" "is_dedicated_host_groups" { +data "ibm_is_dedicated_host_groups" "example" { } ``` diff --git a/website/docs/d/is_dedicated_host_profile.html.markdown b/website/docs/d/is_dedicated_host_profile.html.markdown index a51bb3a6b..d6bacbbee 100644 --- a/website/docs/d/is_dedicated_host_profile.html.markdown +++ b/website/docs/d/is_dedicated_host_profile.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_dedicated_host_profile Retrieve an information about the dedicated host profile. For more information, about dedicated host groups in your IBM Cloud VPC, see [dedicated host profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-dh-profiles). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_profile" "is_dedicated_host_profile" { - name = "dh2-56x464" +data "ibm_is_dedicated_host_profile" "example" { + name = "dh2-56x464" } ``` diff --git a/website/docs/d/is_dedicated_host_profiles.html.markdown b/website/docs/d/is_dedicated_host_profiles.html.markdown index 127f5e092..860a9967c 100644 --- a/website/docs/d/is_dedicated_host_profiles.html.markdown +++ b/website/docs/d/is_dedicated_host_profiles.html.markdown @@ -9,10 +9,21 @@ description: |- # ibm_is_dedicated_host_profiles Retrieve an information about the dedicated host profiles. For more information, about dedicated host profiles, see [dedicated host profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-dh-profiles). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_host_profiles" "is_dedicated_host_profiles" { +data "ibm_is_dedicated_host_profiles" "example" { } ``` diff --git a/website/docs/d/is_dedicated_hosts.html.markdown b/website/docs/d/is_dedicated_hosts.html.markdown index 3f4c44d6d..d2322ccc3 100644 --- a/website/docs/d/is_dedicated_hosts.html.markdown +++ b/website/docs/d/is_dedicated_hosts.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_dedicated_hosts Retrieve the dedicated hosts. For more information, about dedicated hosts in the IBM Cloud VPC, see [dedicated hosts](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-dedicated-hosts-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_dedicated_hosts" "is_dedicated_hosts" { - host_group = "1e09281b-f177-46fb-baf1-bc152b2e391a" +data "ibm_is_dedicated_hosts" "example" { + host_group = ibm_is_dedicated_host_group.example.id } ``` diff --git a/website/docs/d/is_endpoint_gateway_targets.html.markdown b/website/docs/d/is_endpoint_gateway_targets.html.markdown index ad9cd2fac..24fba4e0d 100644 --- a/website/docs/d/is_endpoint_gateway_targets.html.markdown +++ b/website/docs/d/is_endpoint_gateway_targets.html.markdown @@ -9,22 +9,33 @@ description: |- # ibm_is_endpoint_gateway_targets Retrieve an information of an endpoint gateway targets on IBM Cloud as a read-only data source. For more information, about VPC endpoint gateway target, see [creating an endpoint gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-endpoint-gateway). -## Example usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** ```terraform +provider "ibm" { + region = "eu-gb" +} +``` - data "ibm_is_endpoint_gateway_targets" "endpointGatewayTargets" { - } +## Example usage +```terraform +data "ibm_is_endpoint_gateway_targets" "example" { +} ``` ## Attribute reference You can access the following attribute references after your data source is created. +- `resources` - (List) Collection of resources to be set as endpoint gateway target. Nested `resources` blocks have the following structure. -- `crn` - (String) The CRN for this specific object. -- `endpoint_type` - (String) The data endpoint type of this offering. -- `full_qualified_domain_names` - (String) The fully qualified domain names. -- `name` - (String) The display name in the requested language. -- `parent` - (String) The parent for this specific object. -- `resource_type` - (String) The resource type of this offering. -- `service_location` - (String) The service location of this offering. + Nested scheme for `resources`: + - `crn` - (String) The CRN for the specific object. + - `endpoint_type` - (String) The data endpoint type of the offering. + - `full_qualified_domain_names` - (String) The fully qualified domain names. + - `name` - (String) The display name in the requested language. + - `parent` - (String) The parent for the specific object. + - `resource_type` - (String) The resource type of the offering. + - `service_location` - (String) The service location of the offering. diff --git a/website/docs/d/is_floating_ip.html.markdown b/website/docs/d/is_floating_ip.html.markdown index f50c9b56e..5886bfa9e 100644 --- a/website/docs/d/is_floating_ip.html.markdown +++ b/website/docs/d/is_floating_ip.html.markdown @@ -9,14 +9,23 @@ description: |- # ibm_floating_ip Retrieve an information of VPC floating IP on IBM Cloud as a read-only data source. For more information, about floating IP, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). -## Example usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** ```terraform +provider "ibm" { + region = "eu-gb" +} +``` - data "ibm_is_floating_ip" "test" { - name = "test-fp" - } +## Example usage +```terraform +data "ibm_is_floating_ip" "example" { + name = "example-floating-ip" +} ``` ## Argument reference @@ -31,6 +40,25 @@ In addition to the argument reference list, you can access the following attribu - `crn` - (String) The CRN for this floating IP. - `id` - (String) The unique identifier of the floating IP. - `status` - (String) Provisioning status of the floating IP address. -- `tags` - (String) The tags associated with VPC. -- `target` - (String) The ID of the network interface used to allocate the floating IP address. +- `tags` - (String) The tags associated with the floating IP. +- `target` - (String) The unique identifier for the target to allocate the floating IP address. +- `target_list` - (List) The target of this floating IP. + Nested scheme for **target_list**: + - `crn` - (String) The CRN if target is a public gateway. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this target. + - `id` - (String) The unique identifier for this target. + - `name` - (String) The user-defined name for this target. + - `primary_ip` - (List) The reserved ip reference. + + Nested scheme for **primary_ip**: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. +- `resource_type` - (String) The resource type. - `zone` - (String) The zone name where to create the floating IP address. diff --git a/website/docs/d/is_floating_ips.html.markdown b/website/docs/d/is_floating_ips.html.markdown new file mode 100644 index 000000000..615712698 --- /dev/null +++ b/website/docs/d/is_floating_ips.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : floating_ips" +description: |- + Fetches floating IPs information. +--- + +# ibm_is_floating_ips + +Retrieve an information of VPC floating IPs on IBM Cloud. For more information, about floating IP, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +data "ibm_is_floating_ips" "example" { + name = "example-floating-ips" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `name` - (Optional, String) The unique user-defined name for this floating IP. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the Floating IPs Collection. +- `floating_ips` - (List) Collection of floating IPs. + + Nested scheme for **floating_ips**: + - `address` - (String) The globally unique IP address. + - `created_at` - (String) The date and time that the floating IP was created. + - `crn` - (String) The CRN for this floating IP. + - `href` - (String) The URL for this floating IP. + - `id` - (String) The unique identifier for this floating IP. + - `name` - (String) The unique user-defined name for this floating IP. + - `resource_group` - (List) The resource group object, for this floating IP. + + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `status` - (String) The status of the floating IP. + - `target` - (List) The target of this floating IP. + + Nested scheme for **target**: + - `crn` - (String) The CRN for this public gateway. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network interface. + - `id` - (String) The unique identifier for this network interface. + - `name` - (String) The user-defined name for this network interface. + - `primary_ip` - (List) The reserved ip reference. + + Nested scheme for **primary_ip**: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href` - (String) The URL for this reserved IP + - `name` - (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip` - (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The primary IPv4 address. If the address has not yet been selected, the value will be `0.0.0.0`. **Same as primary_ip.0.address** + - `resource_type` - (String) The resource type. + - `zone` - (List) The zone this floating IP resides in. + + Nested scheme for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. diff --git a/website/docs/d/is_flow_log.html.markdown b/website/docs/d/is_flow_log.html.markdown new file mode 100644 index 000000000..823c30541 --- /dev/null +++ b/website/docs/d/is_flow_log.html.markdown @@ -0,0 +1,88 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_flow_log" +description: |- + Get information about Flow Log Collector +--- + +# ibm_is_flow_log +Retrieve an information of VPC flow log. For more information, about VPC flow log, see [about IBM Cloud flow logs for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-flow-logs). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform + +data "ibm_is_flow_log" "example" { + identifier = ibm_is_flow_log.example.id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `identifier` - (Optional, String) The ID of the subnet, This is required when `name` is not specified. +- `name` - (Optional, String) The name of the subnet, This is required when `identifier` is not specified. +- `identifier` - (Optional, String) The ID of the subnet, This is required when name is not specified. +- `name` - (Optional, String) The name of the subnet, This is required when identifier is not specified. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `identifier` - The unique identifier of the FlowLogCollector. +- `active` - (Boolean) Indicates whether this collector is active. +- `auto_delete` - (Boolean) If set to `true`, this flow log collector will be automatically deleted when the target is deleted. +- `created_at` - (String) The date and time that the flow log collector was created. +- `crn` - (String) The CRN for this flow log collector. +- `href` - (String) The URL for this flow log collector. +- `lifecycle_state` - (String) The lifecycle state of the flow log collector. +- `name` - (String) The unique user-defined name for this flow log collector. +- `resource_group` - (List) The resource group object, for this flow log collector. + + Nested scheme for `resource_group`: + - `href` - (Required, String) The URL for this resource group. + - `id` - (Required, String) The unique identifier for this resource group. + - `name` - (Required, String) The user-defined name for this resource group. + +- `storage_bucket` - (Required, List) The Cloud Object Storage bucket where the collected flows are logged. + + Nested scheme for `storage_bucket`: + - `name` - (Required, String) The globally unique name of this Cloud Object Storage bucket. + +- `target` - (List) The target this collector is collecting flow logs for. If the target is an instance,subnet, or VPC, flow logs will not be collected for any network interfaces within the target that are themselves the target of a more specific flow log collector. + + Nested scheme for `target`: + - `crn` - (String) The CRN for this virtual server instance. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network interface. + - `id` - (String) The unique identifier for this network interface. + - `name` - (String) The user-defined name for this network interface. + - `resource_type` - (String) The resource type. Allowable values are: `network_interface`. + +- `vpc` - (List) The VPC this flow log collector is associated with. + + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + -`more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The unique user-defined name for this VPC. diff --git a/website/docs/d/is_flow_logs.html.markdown b/website/docs/d/is_flow_logs.html.markdown index f002676a3..cb2a3b87a 100644 --- a/website/docs/d/is_flow_logs.html.markdown +++ b/website/docs/d/is_flow_logs.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_flow_logs Retrieve an information of an existing IBM Cloud Infrastructure flow logs as a read-only data source. For more information, about VPC flow log, see [creating a flow log collector](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-flow-log-collector). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_flow_logs" "ds_flow_logs" { +data "ibm_is_flow_logs" "example" { } ``` @@ -32,7 +43,7 @@ Review the attribute references that you can access after you retrieve your data - `id` - (String) The unique identifier of the flow log collector. - `lifecycle_state` - (String) The lifecycle state of the flow log collector. - `name` - (String) The flow log collector name. - - `resource_group` - (String) The resource group of the flow log. + - `resource_group` - (String) The resource group Id of the flow log. - `storage_bucket` - (String) The IBM Cloud Object Storage bucket name where the flow logs are logged. - `target` - (String) The target ID that the flow log collector collects the flow logs. - `vpc` - (String) The VPC of the flow log collector that are associated. diff --git a/website/docs/d/is_ike_policies.html.markdown b/website/docs/d/is_ike_policies.html.markdown new file mode 100644 index 000000000..28b052f90 --- /dev/null +++ b/website/docs/d/is_ike_policies.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_ike_policies" +description: |- + Get information about IKEPolicyCollection +--- + +# ibm_is_ike_policies + +Provides a read-only data source for IKEPolicyCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about managing IBM Cloud VPN Gateway and IKE policy , see [about site-to-site VPN gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#policy-negotiation). + +## Example Usage + +```hcl +data "ibm_is_ike_policies" "example" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `ike_policies` - (List) Collection of IKE policies. + Nested scheme for **ike_policies**: + - `authentication_algorithm` - (String) The authentication algorithm. + - `connections` - (List) The VPN gateway connections that use this IKE policy. + Nested scheme for **connections**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. + - `created_at` - (String) The date and time that this IKE policy was created. + - `dh_group` - (Integer) The Diffie-Hellman group. + - `encryption_algorithm` - (String) The encryption algorithm. + - `href` - (String) The IKE policy's canonical URL. + - `id` - (String) The unique identifier for this IKE policy. + - `ike_version` - (Integer) The IKE protocol version. + - `key_lifetime` - (Integer) The key lifetime in seconds. + - `name` - (String) The user-defined name for this IKE policy. + - `negotiation_mode` - (String) The IKE negotiation mode. Only `main` is supported. + - `resource_group` - (List) The resource group object, for this IKE policy. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_ike_policy.html.markdown b/website/docs/d/is_ike_policy.html.markdown new file mode 100644 index 000000000..dbfae7362 --- /dev/null +++ b/website/docs/d/is_ike_policy.html.markdown @@ -0,0 +1,81 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_ike_policy" +description: |- + Get information about IKEPolicy +--- + +# ibm_is_ike_policy + +Provides a read-only data source for IKEPolicy. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about managing IBM Cloud VPN Gateway and IKE policy , see [about site-to-site VPN gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#policy-negotiation). + +## Example Usage + +```hcl +resource "ibm_is_ike_policy" "example" { + name = "my-ike-policy" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + dh_group = 2 + ike_version = 1 +} + +data "ibm_is_ike_policy" "example" { + ike_policy = ibm_is_ike_policy.example.id +} +``` + +```hcl +resource "ibm_is_ike_policy" "example" { + name = "my-ike-policy" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + dh_group = 2 + ike_version = 1 +} + +data "ibm_is_ike_policy" "example" { + name = ibm_is_ike_policy.example.name +} +``` +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `ike_policy` - (Optional, String) The IKE policy identifier. + ~> **NOTE** : One of `ike_policy` or `name` is required + +- `name` - (Optional, String) The name of the IKE policy + ~> **NOTE** : One of `ike_policy` or `name` is required + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the IKEPolicy. +- `authentication_algorithm` - (String) The authentication algorithm. +- `connections` - (List) The VPN gateway connections that use this IKE policy. + Nested scheme for **connections**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. +- `created_at` - (String) The date and time that this IKE policy was created. +- `dh_group` - (Integer) The Diffie-Hellman group. +- `encryption_algorithm` - (String) The encryption algorithm. +- `href` - (String) The IKE policy's canonical URL. +- `ike_version` - (Integer) The IKE protocol version. +- `key_lifetime` - (Integer) The key lifetime in seconds. +- `name` - (String) The user-defined name for this IKE policy. +- `negotiation_mode` - (String) The IKE negotiation mode. Only `main` is supported. +- `resource_group` - (List) The resource group object, for this IKE policy. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. +- `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_image.html.markdown b/website/docs/d/is_image.html.markdown index 7db480cff..3e8905967 100644 --- a/website/docs/d/is_image.html.markdown +++ b/website/docs/d/is_image.html.markdown @@ -9,19 +9,28 @@ description: |- # ibm_is_image Retrieve information of an existing IBM Cloud Infrastructure image as a read-only data source. For more information, about VPC custom images, see [IBM Cloud Importing and managing custom images](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-images). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_image" "ds_image" { +data "ibm_is_image" "example" { name = "centos-7.x-amd64" } ``` ```terraform - -data "ibm_is_image" "ds_image1" { - identifier = "d7bec597-4726-451f-8a63-e62e6f121c32c" +data "ibm_is_image" "example" { + identifier = ibm_is_image.example.id } ``` @@ -29,15 +38,21 @@ data "ibm_is_image" "ds_image1" { Review the argument references that you can specify for your data source. - `identifier` - (Optional, String) The id of the image. - **NOTE** : One of `identifier` or `name` is required + ~> **Note:** `name` and `identifier` are mutually exclusive. - `name` - (Optional, String) The name of the image. - **NOTE** : One of `identifier` or `name` is required + ~> **Note:** `name` and `identifier` are mutually exclusive. - `visibility` - (Optional, String) The visibility of the image. Accepted values are `public` or `private`. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - `architecture` - (String) The architecture of the image. +- `catalog_offering` - (List) The catalog offering for this image. + Nested scheme for **catalog_offering**: + - `managed` - (Bool) Indicates whether this image is managed as part of a catalog offering. If an image is managed, accounts in the same enterprise with access to that catalog can specify the image's catalog offering version CRN to provision virtual server instances using the image. + - `version` - (List) The catalog offering version associated with this image. If absent, this image is not associated with a cloud catalog offering. + Nested scheme for **version**: + - `crn` - (String) The CRN for this version of a catalog offering - `checksum`- (String) The `SHA256` checksum of the image. - `crn` - (String) The CRN for this image. - `encryption` - (String) The type of encryption used of the image. diff --git a/website/docs/d/is_images.html.markdown b/website/docs/d/is_images.html.markdown index 3169ed9af..3f501f89a 100644 --- a/website/docs/d/is_images.html.markdown +++ b/website/docs/d/is_images.html.markdown @@ -9,9 +9,20 @@ description: |- # ibm_is_images Retrieve information of an existing IBM Cloud Infrastructure images as a read-only data source. For more information, about IBM Cloud infrastructure images, see [Images](https://cloud.ibm.com/docs/vpc?topic=vpc-about-images). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage -```hcl +```terraform data "ibm_is_images" "ds_images" { } @@ -21,13 +32,15 @@ data "ibm_is_images" "ds_images" { } ``` -## Argument Reference +## Argument reference Review the argument references that you can specify for your data source. +* `catalog_managed` - (Optional, bool) Lists only those images which are managed as part of a catalog offering. * `resource_group` - (Optional, string) The id of the resource group. * `name` - (Optional, string) The name of the image. * `visibility` - (Optional, string) Visibility of the image. +* `status` - (Optional, string) Status of the image. ## Attribute reference You can access the following attribute references after your data source is created. @@ -37,6 +50,12 @@ You can access the following attribute references after your data source is crea Nested scheme for `images`: - `architecture` - (String) The architecture for this image. - `crn` - (String) The CRN for this image. + - `catalog_offering` - (List) The catalog offering for this image. + Nested scheme for **catalog_offering**: + - `managed` - (Bool) Indicates whether this image is managed as part of a catalog offering. If an image is managed, accounts in the same enterprise with access to that catalog can specify the image's catalog offering version CRN to provision virtual server instances using the image. + - `version` - (List) The catalog offering version associated with this image. If absent, this image is not associated with a cloud catalog offering. + Nested scheme for **version**: + - `crn` - (String) The CRN for this version of a catalog offering - `checksum` - (String) TThe SHA256 checksum for this image. - `encryption` - (String) The type of encryption used on the image. - `encryption_key` - (String) The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource. diff --git a/website/docs/d/is_instance.html.markdown b/website/docs/d/is_instance.html.markdown index 78cb7bb40..e8e34e5d9 100644 --- a/website/docs/d/is_instance.html.markdown +++ b/website/docs/d/is_instance.html.markdown @@ -9,50 +9,70 @@ description: |- # ibm_is_instance Retrieve information of an existing IBM Cloud virtual server instance as a read-only data source. For more information, about managing VPC instance, see [about virtual server instances for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-advanced-virtual-servers). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = file("~/.ssh/id_rsa.pub") } -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" - profile = "bc1-2x8" +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + +} +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id + profile = "bc1-2x8" + metadata_service_enabled = false + primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } network_interfaces { name = "eth1" - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -data "ibm_is_instance" "ds_instance" { - name = "${ibm_is_instance.testacc_instance.name}" +data "ibm_is_instance" "example" { + name = ibm_is_instance.example.name private_key = file("~/.ssh/id_rsa") passphrase = "" } - ``` ## Argument reference @@ -64,7 +84,8 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - +- `availability_policy_host_failure` - (String) The availability policy for this virtual server instance. The action to perform if the compute host experiences a failure. +- `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes - `boot_volume` - (List of Objects) A list of boot volumes that were created for the instance. Nested scheme for `boot_volume`: @@ -73,6 +94,13 @@ In addition to all argument reference list, you can access the following attribu - `device` - (String) The name of the device that is associated with the boot volume. - `volume_id` - (String) The ID of the volume that is associated with the boot volume attachment. - `volume_crn` - (String) The CRN of the volume that is associated with the boot volume attachment. + +- `catalog_offering` - (List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. + + Nested scheme for `catalog_offering`: + - `offering_crn` - (String) The CRN for this catalog offering. Identifies a catalog offering by this unique property + - `version_crn` - (String) The CRN for this version of a catalog offering. Identifies a version of a catalog offering by this unique property + - `crn` - (String) The CRN of the instance. - `disks` - (List) Collection of the instance's disks. Nested `disks` blocks has the following structure: @@ -99,12 +127,28 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The ID of the SSH key. - `name` - (String) The name of the SSH key that you entered when you uploaded the key to IBM Cloud. - `memory`- (Integer) The amount of memory that was allocated to the instance. +- `lifecycle_reasons`- (List) The reasons for the current lifecycle_state (if any). + + Nested scheme for `lifecycle_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this lifecycle state. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state`- (String) The lifecycle state of the virtual server instance. [ **deleting**, **failed**, **pending**, **stable**, **suspended**, **updating**, **waiting** ] +- `metadata_service_enabled` - (Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. - `network_interfaces`- (List) A list of more network interfaces that the instance uses. Nested scheme for `network_interfaces`: - `id` - (String) The ID of the more network interface. - `name` - (String) The name of the more network interface. - - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `network_interfaces.[].primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` - `subnet` - (String) The ID of the subnet that is used in the more network interface. - `security_groups` (List)A list of security groups that were created for the interface. - `password` - (String) The password that you can use to access your instance. @@ -123,17 +167,28 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `primary_network_interface`: - `id` - (String) The ID of the primary network interface. - `name` - (String) The name of the primary network interface. - - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` - `subnet` - (String) The ID of the subnet that is used in the primary network interface. - `security_groups` (List)A list of security groups that were created for the interface. - `resource_controller_url` - (String) The URL of the IBM Cloud dashboard that you can use to see details for your instance. -- `resource_group` - (String) The name of the resource group where the instance was created. +- `resource_group` - (String) The resource group id, where the instance was created. - `status` - (String) The status of the instance. - `status_reasons` - (List) Array of reasons for the current status. Nested scheme for `status_reasons`: - `code` - (String) A snake case string identifying the status reason. - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason +- `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes +- `total_network_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces. - `vpc` - (String) The ID of the VPC that the instance belongs to. - `vcpu`- (List) A list of virtual CPUs that were allocated to the instance. diff --git a/website/docs/d/is_instance_disk.html.markdown b/website/docs/d/is_instance_disk.html.markdown index 551e51489..aba081ab3 100644 --- a/website/docs/d/is_instance_disk.html.markdown +++ b/website/docs/d/is_instance_disk.html.markdown @@ -9,53 +9,73 @@ description: |- # ibm_is_instance_disk Retrieve information about an instance disk. For more information about instance disk, see [managing instance storage](https://cloud.ibm.com/docs/vpc?topic=vpc-instance-storage-provisioning). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = file("~/.ssh/id_rsa.pub") } -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id profile = "bc1-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } network_interfaces { name = "eth1" - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -data "ibm_is_instance" "ds_instance" { - name = "${ibm_is_instance.testacc_instance.name}" +data "ibm_is_instance" "example" { + name = "ibm_is_instance.example.name" private_key = file("~/.ssh/id_rsa") passphrase = "" } -data "is_instance_disk" "is_instance_disk" { - instance = data.ibm_is_instance.ds_instance.id - disk = data.ibm_is_instance.ds_instance.disks.0.id +data "is_instance_disk" "example" { + instance = data.ibm_is_instance.example.id + disk = data.ibm_is_instance.example.disks.0.id } ``` diff --git a/website/docs/d/is_instance_disks.html.markdown b/website/docs/d/is_instance_disks.html.markdown index 2e76ede21..d294d1ed6 100644 --- a/website/docs/d/is_instance_disks.html.markdown +++ b/website/docs/d/is_instance_disks.html.markdown @@ -9,52 +9,71 @@ description: |- # ibm_is_instance_disks Retrieve information about an instance disks. For more information, about an instance disks, see [managing instance storage](https://cloud.ibm.com/docs/vpc?topic=vpc-instance-storage-provisioning). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = file("~/.ssh/id_rsa.pub") } +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + +} -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id profile = "bc1-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } network_interfaces { name = "eth1" - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -data "ibm_is_instance" "ds_instance" { - name = "${ibm_is_instance.testacc_instance.name}" +data "ibm_is_instance" "example" { + name = ibm_is_instance.example.name private_key = file("~/.ssh/id_rsa") passphrase = "" } -data "is_instance_disks" "is_instance_disks" { - instance = data.ibm_is_instance.ds_instance.id +data "is_instance_disks" "example" { + instance = data.ibm_is_instance.example.id } ``` diff --git a/website/docs/d/is_instance_group.html.markdown b/website/docs/d/is_instance_group.html.markdown index a42c83683..df3c56db4 100644 --- a/website/docs/d/is_instance_group.html.markdown +++ b/website/docs/d/is_instance_group.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_instance_group Retrieve information of an exisitng VPC instance group. For more information, about VPC instance group information, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example gets an instance group information. ```terraform -data "ibm_is_instance_group" "instance_group_data" { - name = ibm_is_instance_group.instance_group.name +data "ibm_is_instance_group" "example" { + name = ibm_is_instance_group.example.name } ``` diff --git a/website/docs/d/is_instance_group_manager.html.markdown b/website/docs/d/is_instance_group_manager.html.markdown index daec7151c..2734c7aa4 100644 --- a/website/docs/d/is_instance_group_manager.html.markdown +++ b/website/docs/d/is_instance_group_manager.html.markdown @@ -9,13 +9,24 @@ description: |- # ibm_is_instance_group_manager Retrieve information about an instance group manager. For more information, about instance group manager, see [managing an instance group](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example can retrieve instance group manager info. ```terraform -data "ibm_is_instance_group_manager" "instance_group_manager" { - instance_group = "r006-76740f94-fcc4-11e9-96e7-a77723715315" - name = "testmanager" +data "ibm_is_instance_group_manager" "example" { + instance_group = ibm_is_instance_group.example.id + name = "example-instance-group-manager" } ``` diff --git a/website/docs/d/is_instance_group_manager_action.html.markdown b/website/docs/d/is_instance_group_manager_action.html.markdown index ff0876207..25c6899ae 100644 --- a/website/docs/d/is_instance_group_manager_action.html.markdown +++ b/website/docs/d/is_instance_group_manager_action.html.markdown @@ -9,13 +9,24 @@ description: |- # ibm_is_instance_group_manager_action Retrive information about an instance group manager. For more information, about VPC instance group manager action, see [scheduled scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-scheduled-scaling-vpc). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_instance_group_manager_action" "ibm_is_instance_group_manager_action" { - instance_group = "r006-76770f94-f7654-11e9-96e7-a77724435315" - instance_group_manager = "r006-76770f94-f8764-11e9-96e7-a77726534315" - name = "testinstancegroupmanageraction" +data "ibm_is_instance_group_manager_action" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id + name = "example-instance-group-manager-action" } ``` diff --git a/website/docs/d/is_instance_group_manager_actions.html.markdown b/website/docs/d/is_instance_group_manager_actions.html.markdown index 5b4df73dc..a9f3ee080 100644 --- a/website/docs/d/is_instance_group_manager_actions.html.markdown +++ b/website/docs/d/is_instance_group_manager_actions.html.markdown @@ -1,20 +1,31 @@ --- subcategory: "VPC infrastructure" layout: "ibm" -page_title: "IBM : instance_group_manager_action" +page_title: "IBM : instance_group_manager_actions" description: |- Get all information about IBM VPC instance group manager action. --- -# ibm_is_instance_group_manager_action +# ibm_is_instance_group_manager_actions Retrieve information about an instance group manager. For more information, about VPC instance group manager action, see [managing dedicated hosts and groups](https://cloud.ibm.com/docs/vpc?topic=vpc-manage-dedicated-hosts-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_instance_group_manager_action" "ibm_is_instance_group_manager_action" { - instance_group = "r006-76770f94-f7654-11e9-96e7-a77724435315" - instance_group_manager = "r006-76770f94-f8764-11e9-96e7-a77726534315" +data "ibm_is_instance_group_manager_actions" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id } ``` diff --git a/website/docs/d/is_instance_group_manager_policies.html.markdown b/website/docs/d/is_instance_group_manager_policies.html.markdown index b255ebb03..4cc0c0e2f 100644 --- a/website/docs/d/is_instance_group_manager_policies.html.markdown +++ b/website/docs/d/is_instance_group_manager_policies.html.markdown @@ -9,13 +9,24 @@ description: |- # ibm_is_instance_group_manager_policies Retrieve all the policies information of an instance group manager. For more information, about instance group manager policies information, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can retrieve a policy info of an instance group manager. ```terraform -data "ibm_is_instance_group_manager_policy" "instance_group_manager_policy" { - instance_group = "r006-76770f94-f7654-11e9-96e7-a77724435315" - instance_group_manager = "r006-76770f94-f8764-11e9-96e7-a77726534315" +data "ibm_is_instance_group_manager_policies" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id } ``` diff --git a/website/docs/d/is_instance_group_manager_policy.html.markdown b/website/docs/d/is_instance_group_manager_policy.html.markdown index cb1db3747..63d7a3ee6 100644 --- a/website/docs/d/is_instance_group_manager_policy.html.markdown +++ b/website/docs/d/is_instance_group_manager_policy.html.markdown @@ -9,14 +9,25 @@ description: |- # ibm_is_instance_group_manager_policy Retrieve information of an existing instance group manager policy. For more information, about instance group manager policy information, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can retrieve a policy info of an instance group manager. ```terraform -data "ibm_is_instance_group_manager_policy" "instance_group_manager_policy" { - instance_group = "r006-76770f94-f7654-11e9-96e7-a77724435315" - instance_group_manager = "r006-76770f94-f8764-11e9-96e7-a77726534315" - name = "testpolicy +data "ibm_is_instance_group_manager_policy" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id + name = "example-ig-manager-policy" } ``` diff --git a/website/docs/d/is_instance_group_managers.html.markdown b/website/docs/d/is_instance_group_managers.html.markdown index b21f9e60c..6480f9a67 100644 --- a/website/docs/d/is_instance_group_managers.html.markdown +++ b/website/docs/d/is_instance_group_managers.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_instance_group_managers Retrieve information of an instance group managers information of an instance group. For more information, about instance group manager, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage -In the following example, you can retrive list of instance group managers information. +In the following example, you can retrieve list of instance group managers information. ```terraform -data "ibm_is_instance_group_managers" "instance_group_managers" { - instance_group = "r006-76740f94-fcc4-11e9-96e7-a77723715315" +data "ibm_is_instance_group_managers" "example" { + instance_group = ibm_is_instance_group.example.id } ``` diff --git a/website/docs/d/is_instance_group_membership.html.markdown b/website/docs/d/is_instance_group_membership.html.markdown index a48d61718..612d17822 100644 --- a/website/docs/d/is_instance_group_membership.html.markdown +++ b/website/docs/d/is_instance_group_membership.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_instance_group_membership Retrieve information of an instance group memership. For more information, about instance group membership, see [bulk provisioning instances with instance groups](https://cloud.ibm.com/docs/vpc?topic=vpc-bulk-provisioning). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "is_instance_group_membership" "is_instance_group_membership" { - instance_group = "r006-76740f94-fcc4-11e9-96e7-a77723715315" - name = "membershipname" +data "is_instance_group_membership" "example" { + instance_group = ibm_is_instance_group.example.id + name = "example-ig-membership" } ``` diff --git a/website/docs/d/is_instance_group_memberships.html.markdown b/website/docs/d/is_instance_group_memberships.html.markdown index 20a04597d..98e2d8ae8 100644 --- a/website/docs/d/is_instance_group_memberships.html.markdown +++ b/website/docs/d/is_instance_group_memberships.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_instance_group_memberships Retrieve all the instance group membership information of an instance group. For more information, about instance group membership, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "is_instance_group_memberships" "is_instance_group_memberships" { - instance_group = "r006-76740f94-fcc4-11e9-96e7-a77723715315" +data "is_instance_group_memberships" "example" { + instance_group = ibm_is_instance_group.example.id } ``` diff --git a/website/docs/d/is_instance_groups.html.markdown b/website/docs/d/is_instance_groups.html.markdown new file mode 100644 index 000000000..29aadaf11 --- /dev/null +++ b/website/docs/d/is_instance_groups.html.markdown @@ -0,0 +1,98 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_groups" +description: |- + Get information about InstanceGroupCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_instance_groups + +Provides a read-only data source for InstanceGroupCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about instance groups , see [Managing instance groups](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-instance-group&mhsrc=ibmsearch_a&mhq=instance+group). + +**Note:** +VPC infrastructure services are regional specific and by default targets to `us-south`. If VPC service is created in a region other than `us-south`, please make sure to target the region in the provider block as shown in the `provider.tf` file, . + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```hcl +data "ibm_is_instance_groups" "is_instance_groups" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the InstanceGroupCollection. +- `instance_groups` - (List) Collection of instance groups. + Nested scheme for `instance_groups`: + - `application_port` - (Integer) Required if specifying a load balancer pool only. Used by the instance group when scaling up instances to supply the port for the load balancer pool member. + - `created_at` - (String) The date and time that the instance group was created. + - `crn` - (String) The CRN for this instance group. + - `href` - (String) The URL for this instance group. + - `id` - (String) The unique identifier for this instance group. + - `instance_template` - (List) The template used to create new instances for this group. + Nested scheme for `instance_template`: + - `crn` - (String) The CRN for this instance template. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this instance template. + - `id` - (String) The unique identifier for this instance template. + - `name` - (String) The unique user-defined name for this instance template. + - `load_balancer_pool` - (List) The load balancer pool managed by this group. Instances createdby this group will have a new load balancer pool member in thatpool created. + Nested scheme for `load_balancer_pool`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The pool's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool. + - `name` - (String) The user-defined name for this load balancer pool. + - `managers` - (List) The managers for the instance group. + Nested scheme for `managers`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this instance group manager. + - `id` - (String) The unique identifier for this instance group manager. + - `name` - (String) The user-defined name for this instance group manager. + - `membership_count` - (Integer) The number of instances in the instance group. + - `name` - (String) The user-defined name for this instance group. + - `resource_group` - (List) + Nested scheme for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `status` - (String) The status of the instance group- `deleting`: Group is being deleted- `healthy`: Group has `membership_count` instances- `scaling`: Instances in the group are being created or deleted to reach `membership_count`- `unhealthy`: Group is unable to reach `membership_count` instances. + - `subnets` - (List) The subnets to use when creating new instances. + Nested scheme for `subnets`: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. + - `resource_type` - (String) The resource type. + - `updated_at` - (String) The date and time that the instance group was updated. + - `vpc` - (List) The VPC the instance group resides in. + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The unique user-defined name for this VPC. + - `resource_type` - (String) The resource type. + \ No newline at end of file diff --git a/website/docs/d/is_instance_network_interface.html.markdown b/website/docs/d/is_instance_network_interface.html.markdown new file mode 100644 index 000000000..a4148d8b1 --- /dev/null +++ b/website/docs/d/is_instance_network_interface.html.markdown @@ -0,0 +1,140 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_instance_network_interface" +description: |- + Get information about NetworkInterface +--- + +# ibm_is_instance_network_interface + +Retrieve information of an exisitng network interface. For more information, about instance network interface, see [managing an network interfaces](https://cloud.ibm.com/docs/vpc?topic=vpc-using-instance-vnics). + + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-vpc" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = file("~/.ssh/id_rsa.pub") +} + +resource "ibm_is_instance" "example" { + name = "example-vpc" + image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" + profile = "bc1-2x8" + + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + + network_interfaces { + name = "eth1" + subnet = ibm_is_subnet.example.id + } + + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] +} + +resource "ibm_is_instance_network_interface" "example" { + instance = ibm_is_instance.example.id + subnet = ibm_is_subnet.example.id + allow_ip_spoofing = true + name = "example-network-interface" + primary_ipv4_address = "10.0.0.5" +} + +data "ibm_is_instance_network_interface" "example" { + instance_name = ibm_is_instance.example.name + network_interface_name = is_instance_network_interface.example.name +} +``` + +## Argument reference + +The following arguments are supported: + +- `instance_name` - (Required, string) The name of the instance. +- `network_interface_name` - (Required, string) The name of the network interface. + +## Attribute reference + +In addition to all arguments above, the following attributes are exported: + +- `id` - (String) The unique identifier of the NetworkInterface. +- `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + +- `created_at` - (String) The date and time that the network interface was created. + +- `floating_ips` - (List) The floating IPs associated with this network interface. Nested `floating_ips` blocks have the following structure: + - `address` - (String) The globally unique IP address. + - `crn` - (String) The CRN for this floating IP. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this floating IP. + - `id` - (String) The unique identifier for this floating IP. + - `name` - (String) The unique user-defined name for this floating IP. + +- `href` - (String) The URL for this network interface. + +- `name` - (String) The user-defined name for this network interface. + +- `port_speed` - (Integer) The network interface port speed in Mbps. + +- `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + +- `primary_ipv4_address` - (String) The primary IPv4 address. Same as `primary_ip.0.address` + +- `resource_type` - (String) The resource type. + +- `security_groups` - (List) Collection of security groups. Nested `security_groups` blocks have the following structure: + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + +- `status` - (String) The status of the network interface. + +- `subnet` - (List) The associated subnet. Nested `subnet` blocks have the following structure: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. + +- `type` - (String) The type of this network interface as it relates to an instance. + diff --git a/website/docs/d/is_instance_network_interface_reserved_ip.html.markdown b/website/docs/d/is_instance_network_interface_reserved_ip.html.markdown new file mode 100644 index 000000000..ee4cc5b8a --- /dev/null +++ b/website/docs/d/is_instance_network_interface_reserved_ip.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reserved_ip" +description: |- + Shows the info for a reserved IP and instance network interface. +--- + +# ibm\_is_instance_network_interface_reserved_ip + +Import the details of an existing Reserved IP in a network interface of an instance as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_instance_network_interface_reserved_ip" "data_reserved_ip" { + instance = ibm_is_instance.test_instance.id + network_interface = ibm_is_instance.test_instance.network_interfaces.0.id + reserved_ip = ibm_is_instance.test_instance.network_interfaces.0.ips.0.id +} +``` + +## Argument Reference + +The following arguments are supported as inputs/request params: + +- `instance` - (Required, string) The id for the instance. +- `network_interface` - (Required, string) The id for the network interface. +- `reserved_ip` - (Required, string) The id for the Reserved IP. + + +## Attribute Reference + +The following attributes are exported as output/response: + +- `auto_delete` - (String) The auto_delete boolean for reserved IP +- `created_at` - (String) The creation timestamp for the reserved IP +- `href` - (String) The unique reference for the reserved IP +- `id` - (String) The id for the reserved IP +- `name` - (String) The name for the reserved IP +- `owner` - (String) The owner of the reserved IP +- `reserved_ip` - (String) Same as `id` +- `resource_type` - (String) The type of resource +- `target` - (String) The id for the target for the reserved IP diff --git a/website/docs/d/is_instance_network_interface_reserved_ips.html.markdown b/website/docs/d/is_instance_network_interface_reserved_ips.html.markdown new file mode 100644 index 000000000..fb67e9123 --- /dev/null +++ b/website/docs/d/is_instance_network_interface_reserved_ips.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reserved_ips" +description: |- + Lists all the info in reserved IP for Instance network interface. +--- + +# ibm\_is_instance_network_interface_reserved_ips + +Import the details of all the Reserved IPs in a network interface of an instance as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_instance_network_interface_reserved_ips" "data_reserved_ips" { + instance = ibm_is_instance.test_instance.id + network_interface = ibm_is_instance.test_instance.network_interfaces.0.id +} +``` + +## Argument Reference + +The following arguments are supported as inputs/request params: + +* `instance` - (Required, string) The id for the instance. +* `network_interface` - (Required, string) The id for the network interface. + + +## Attribute Reference + +The following attributes are exported as output/response: + +- `id` - The id for the all the reserved ID (current timestamp) +- `reserved_ips` - The collection of all the reserved IPs in the network inetrface + - `address` - (String) The IP bound for the reserved IP + - `auto_delete` - (Bool) If reserved ip shall be deleted automatically + - `created_at` - (String) The date and time that the reserved IP was created + - `href` - (String) The URL for this reserved IP + - `reserved_ip` - (String) The unique identifier for this reserved IP + - `name` - (String) The user-defined or system-provided name for this reserved IP + - `owner` -(String) The owner of a reserved IP, defining whether it is managed by the user or the provider + - `resource_type` - (String) The resource type + - `target` - (String) The id for the target for the reserved IP. + +- `total_count` - The number of reserved IP in the network interface of the instance diff --git a/website/docs/d/is_instance_network_interfaces.html.markdown b/website/docs/d/is_instance_network_interfaces.html.markdown new file mode 100644 index 000000000..6a4308427 --- /dev/null +++ b/website/docs/d/is_instance_network_interfaces.html.markdown @@ -0,0 +1,127 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_instance_network_interfaces" +description: |- + Get information about Network Interface collection + +--- + +# ibm_is_instance_network_interfaces +Retrieve information of an exisitng network interfaces collection. For more information, about instance network interfaces collection, see [managing an network interfaces](https://cloud.ibm.com/docs/vpc?topic=vpc-using-instance-vnics). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = file("~/.ssh/id_rsa.pub") +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" + profile = "bc1-2x8" + + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + + network_interfaces { + name = "eth1" + subnet = ibm_is_subnet.example.id + } + + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] +} + +data "ibm_is_instance_network_interfaces" "example" { + instance_name = ibm_is_instance.example.name +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_name` - (Required, string) The name of an instance. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `network_interfaces` - (List) Collection of network interfaces. Nested `network_interfaces` blocks have the following structure: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `created_at` - (String) The date and time that the network interface was created. + - `floating_ips` - (List) The floating IPs associated with this network interface. + + Nested scheme for `floating_ips`: + - `address` - (String) The globally unique IP address. + - `crn` - (String) The CRN for this floating IP. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this floating IP. + - `id` - (String) The unique identifier for this floating IP. + - `name` - (String) The unique user-defined name for this floating IP. + - `href` - (String) The URL for this network interface. + - `id` - (String) The unique identifier for this network interface. + - `name` - (String) The user-defined name for this network interface. + - `port_speed` - (Integer) The network interface port speed in Mbps. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The primary IPv4 address. Same as `primary_ip.0.address` + - `resource_type` - (String) The resource type. + - `security_groups` - (List) Collection of security groups. + + Nested scheme for `security_groups`: + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + - `status` - (String) The status of the network interface. + - `subnet` - (List) The associated subnet. Nested `subnet` blocks have the following structure: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. + - `type` - (String) The type of this network interface as it relates to an instance. diff --git a/website/docs/d/is_instance_profile.html.markdown b/website/docs/d/is_instance_profile.html.markdown index c54679c83..51bd3d422 100644 --- a/website/docs/d/is_instance_profile.html.markdown +++ b/website/docs/d/is_instance_profile.html.markdown @@ -9,14 +9,24 @@ description: |- # ibm_is_instance_profile Retrieve information of an existing IBM Cloud virtual server instance profile. For more information, about virtual server instance profile, see [instance profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-profiles). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage -The following example retrieves information about the `b-2x8` instance profile. +The following example retrieves information about the `cx2-2x4` instance profile. ```terraform -data "ibm_is_instance_profile" "profile" { - name = "b-2x8" +data "ibm_is_instance_profile" "example" { + name = "cx2-2x4" } ``` @@ -42,6 +52,14 @@ In addition to the argument reference list, you can access the following attribu - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. +- `total_volume_bandwidth` Nested `total_volume_bandwidth` blocks have the following structure: + - `type` - The type for this profile field. + - `value` - The value for this profile field. + - `default` - The default value for this profile field. + - `max` - The maximum value for this profile field. + - `min` - The minimum value for this profile field. + - `step` - The increment step value for this profile field. + - `values` - The permitted values for this profile field. - `disks` - (List) Collection of the instance profile's disks. Nested `disks` blocks have the following structure: Nested scheme for `disks`: @@ -72,6 +90,32 @@ In addition to the argument reference list, you can access the following attribu - `type` - (String) The type for this profile field. - `values` - (String) The supported disk interfaces used for attaching the disk. - `family` - (String) The family of the virtual server instance profile. +- `gpu_count` - (List) Nested `gpu_count` blocks have the following structure: + Nested scheme for `gpu_count`: + - `default` - (String) The default value for this profile field. + - `max` - (String) The maximum value for this profile field. + - `min` - (String) The minimum value for this profile field. + - `step` - (String) The increment step value for this profile field. + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. + - `values` - (String) The permitted values for this profile field. +- `gpu_manufacturer` - (List) Nested `gpu_manufacturer` blocks have the following structure: + Nested scheme for `gpu_manufacturer`: + - `type` - (String) The type for this profile field. + - `values` - (String) The permitted values for this profile field. +- `gpu_memory` - (List) Nested `gpu_memory` blocks have the following structure: + Nested scheme for `gpu_memory`: + - `default` - (String) The default value for this profile field. + - `max` - (String) The maximum value for this profile field. + - `min` - (String) The minimum value for this profile field. + - `step` - (String) The increment step value for this profile field. + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. + - `values` - (String) The permitted values for this profile field. +- `gpu_model` - (List) Nested `gpu_model` blocks have the following structure: + Nested scheme for `gpu_model`: + - `type` - (String) The type for this profile field. + - `values` - (String) The permitted values for this profile field. - `href` - (String) The URL for this virtual server instance profile. - `memory` - (List) Nested `memory` blocks have the following structure: diff --git a/website/docs/d/is_instance_profiles.html.markdown b/website/docs/d/is_instance_profiles.html.markdown index ea7d9d7fb..fb766eeb8 100644 --- a/website/docs/d/is_instance_profiles.html.markdown +++ b/website/docs/d/is_instance_profiles.html.markdown @@ -9,12 +9,22 @@ description: |- # ibm_is_instance_profiles Retrieve information of an existing virtual server instance profiles as a read-only data source. For more information, about virtual server instance profiles, see [instance profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-profiles). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_instance_profiles" "ds_instance_profiles" { +data "ibm_is_instance_profiles" "example" { } ``` @@ -22,12 +32,17 @@ data "ibm_is_instance_profiles" "ds_instance_profiles" { ## Attribute reference You can access the following attribute references after your data source is created. -- `disks` - (List) Collection of the instance profile's disks. Nested `disks` blocks has the following structure. +- `profiles` - (List) List of all server instance profiles in the region. - Nested scheme for `disks`: - - `quantity` (List) Nested `quantity` blocks has the following structure: + Nested scheme for `profiles`: + - `architecture` - (String) The default Operating System architecture for an instance of the profile. + - `architecture_type` - (String) The type for this OS architecture. + - `architecture_values` - (String) The supported OS architecture(s) for an instance with this profile. + - `name` - (String) The name of the virtual server instance profile. + - `family` - (String) The family of the virtual server instance profile. + - `bandwidth` - (List) The collection of bandwidth information. - Nested scheme for `quantity`: + Nested scheme for `bandwidth`: - `default` - (String) The default value for this profile field. - `max` - (String) The maximum value for this profile field. - `min` - (String) The minimum value for this profile field. @@ -35,9 +50,37 @@ You can access the following attribute references after your data source is crea - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. - - `size` - (List) Nested `size` blocks has the following structure: - - Nested scheme for `size`: + - `disks` - (List) Collection of the instance profile's disks. Nested `disks` blocks has the following structure. + + Nested scheme for `disks`: + - `quantity` (List) Nested `quantity` blocks has the following structure: + + Nested scheme for `quantity`: + - `default` - (String) The default value for this profile field. + - `max` - (String) The maximum value for this profile field. + - `min` - (String) The minimum value for this profile field. + - `step` - (String) The increment step value for this profile field. + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. + - `values` - (String) The permitted values for this profile field. + - `size` - (List) Nested `size` blocks has the following structure: + + Nested scheme for `size`: + - `default` - (String) The default value for this profile field. + - `max` - (String) The maximum value for this profile field. + - `min` - (String) The minimum value for this profile field. + - `step` - (String) The increment step value for this profile field. + - `type` - (String) The type for this profile field. + - `value` - (String) The value for this profile field. + - `values` - (String) The permitted values for this profile field. + - `supported_interface_types` - (List) Nested `supported_interface_types` blocks has the following structure: + + Nested scheme for `supported_interface_type`: + - `default` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally, halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - `type` - (String) The type for this profile field. + - `values` - (String) The supported disk interfaces used for attaching the disk. + - `gpu_count` - (List) Nested `gpu_count` blocks have the following structure: + Nested scheme for `gpu_count`: - `default` - (String) The default value for this profile field. - `max` - (String) The maximum value for this profile field. - `min` - (String) The minimum value for this profile field. @@ -45,23 +88,12 @@ You can access the following attribute references after your data source is crea - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. - - `supported_interface_types` - (List) Nested `supported_interface_types` blocks has the following structure: - - Nested scheme for `supported_interface_type`: - - `default` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally, halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - `gpu_manufacturer` - (List) Nested `gpu_manufacturer` blocks have the following structure: + Nested scheme for `gpu_manufacturer`: - `type` - (String) The type for this profile field. - - `values` - (String) The supported disk interfaces used for attaching the disk. -- `profiles` - (List) List of all server instance profiles in the region. - - Nested scheme for `profiles`: - - `architecture` - (String) The default Operating System architecture for an instance of the profile. - - `architecture_type` - (String) The type for this OS architecture. - - `architecture_values` - (String) The supported OS architecture(s) for an instance with this profile. - - `name` - (String) The name of the virtual server instance profile. - - `family` - (String) The family of the virtual server instance profile. - - `bandwidth` - (List) The collection of bandwidth information. - - Nested scheme for `bandwidth`: + - `values` - (String) The permitted values for this profile field. + - `gpu_memory` - (List) Nested `gpu_memory` blocks have the following structure: + Nested scheme for `gpu_memory`: - `default` - (String) The default value for this profile field. - `max` - (String) The maximum value for this profile field. - `min` - (String) The minimum value for this profile field. @@ -69,6 +101,19 @@ You can access the following attribute references after your data source is crea - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. + - `gpu_model` - (List) Nested `gpu_model` blocks have the following structure: + Nested scheme for `gpu_model`: + - `type` - (String) The type for this profile field. + - `values` - (String) The permitted values for this profile field. + - `total_volume_bandwidth` Nested `total_volume_bandwidth` blocks have the following structure: + Nested scheme for `total_volume_bandwidth`: + - `type` - The type for this profile field. + - `value` - The value for this profile field. + - `default` - The default value for this profile field. + - `max` - The maximum value for this profile field. + - `min` - The minimum value for this profile field. + - `step` - The increment step value for this profile field. + - `values` - The permitted values for this profile field. - `href` - (String) The URL for this virtual server instance profile. - `memory` - (List) Nested `memory` blocks have the following structure: diff --git a/website/docs/d/is_instance_template.html.markdown b/website/docs/d/is_instance_template.html.markdown index a22f972bd..730db0f29 100644 --- a/website/docs/d/is_instance_template.html.markdown +++ b/website/docs/d/is_instance_template.html.markdown @@ -9,32 +9,43 @@ description: |- # ibm_is_instance_template Retrieve information of an existing IBM VPC instance template. For more information, about VPC instance templates, see [creating an instance template](https://cloud.ibm.com/docs/vpc?topic=vpc-create-instance-template). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can get information of an instance template of VPC Generation-2 infrastructure by either name or identifier. ```terraform -data "ibm_is_instance_template" "instancetemplate" { - name = "test-instance-template" +data "ibm_is_instance_template" "example" { + name = "example-instance-template" } - ``` + ```terraform -data "ibm_is_instance_template" "instancetemplate" { - identifier = "xxxxx-xxxxx-xxxxxx-xxxxx" +data "ibm_is_instance_template" "example" { + identifier = ibm_is_instance_template.example.id } - ``` ## Argument reference Review the argument references that you can specify for your data source. -- `identifier` - (Optional, String) The id of the instance template. -- `name` - (Optional, String) The name of the instance template. +- `identifier` - (Optional, String) The id of the instance template, `name` and `identifier` are mutually exclusive. +- `name` - (Optional, String) The name of the instance template, `name` and `identifier` are mutually exclusive. ## Attribute reference You can access the following attribute references after your data source is created. +- `availability_policy_host_failure` - (String) The availability policy for this virtual server instance. The action to perform if the compute host experiences a failure. - `boot_volume` - (List) A nested block describes the boot volume configuration for the template. @@ -45,11 +56,15 @@ You can access the following attribute references after your data source is crea - `name` - (String) The name of the boot volume. - `profile` - (String) The profile for the boot volume configuration. - `size` - (String) The boot volume size to configure in giga bytes. + - `tags` - (String) User Tags associated with the boot_volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `crn` - (String) The CRN of the instance template. +- `default_trusted_profile_auto_link` - (Boolean) If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted. Default is true. +- `default_trusted_profile_target` - (String) The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance. - `href` - (String) The URL of the instance template. - `id` - (String) The ID of the instance template. - `image` - (String) The ID of the image to create the template. - `keys` - (String) List of SSH key IDs used to allow log in user to the instances. +- `metadata_service_enabled` - (Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. - `name` - (String) The name of the instance template. - `network_interfaces` - (List) A nested block describes the network interfaces for the template. @@ -74,6 +89,7 @@ You can access the following attribute references after your data source is crea - `subnet` - (String) The VPC subnet to assign to the interface. - `security_groups` - (String) List of security groups of the subnet. - `resource_group` - (String) The resource group ID. +- `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `user_data` - (String) The user data provided for the instance. - `volume_attachments` - (List) A nested block describes the storage volume configuration for the template. @@ -88,5 +104,6 @@ You can access the following attribute references after your data source is crea - `encryption_key` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. - `iops` - (String) The maximum input/output operations per second (IOPS) for the volume. - `profile` - (String) The global unique name for the volume profile to use for the volume. + - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `vpc` - (String) The VPC ID that the instance templates needs to be created. - `zone` - (String) The name of the zone. diff --git a/website/docs/d/is_instance_templates.html.markdown b/website/docs/d/is_instance_templates.html.markdown index 224e16489..9ce41d0a4 100644 --- a/website/docs/d/is_instance_templates.html.markdown +++ b/website/docs/d/is_instance_templates.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_instance_templates Retrieve information of an existing IBM VPC instance templates. For more information, about VPC instance templates, see [creating an instance template](https://cloud.ibm.com/docs/vpc?topic=vpc-create-instance-template). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can get information of list of instance templates of VPC Generation-2 infrastructure. ```terraform -data "ibm_is_instance_templates" "instancetemplates" { +data "ibm_is_instance_templates" "example" { } ``` @@ -22,6 +33,7 @@ data "ibm_is_instance_templates" "instancetemplates" { You can access the following attribute references after your data source is created. - `templates` - (List of Objects) List of templates. + - `availability_policy_host_failure` - (String) The availability policy for this virtual server instance. The action to perform if the compute host experiences a failure. - `boot_volume` - (List) A nested block describes the boot volume configuration for the template. Nested scheme for `boot_volume`: @@ -31,11 +43,15 @@ You can access the following attribute references after your data source is crea - `name` - (String) The name of the boot volume. - `profile` - (String) The profile for the boot volume configuration. - `size` - (String) The boot volume size to configure in giga bytes. + - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags). - `crn` - (String) The CRN of the instance template. + - `default_trusted_profile_auto_link` - (Boolean) If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted. Default is true. + - `default_trusted_profile_target` - (String) The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance. - `href` - (String) The URL of the instance template. - `id` - (String) The ID of the instance template. - `image` - (String) The ID of the image to create the template. - `keys` - (String) List of SSH key IDs used to allow log in user to the instances. + - `metadata_service_enabled` - (Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. - `name` - (String) The name of the instance template. - `network_interfaces` - (List) A nested block describes the network interfaces for the template. @@ -57,7 +73,8 @@ You can access the following attribute references after your data source is crea - `primary_ipv4_address` - (String) The IPv4 address assigned to the primary network interface. - `subnet` - (String) The VPC subnet to assign to the interface. - `security_groups` - (String) List of security groups of the subnet. - - `resource_group` - (String) The resource group ID. + - `resource_group` - (String) The resource group ID. + - `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `user_data` - (String) The user data provided for the instance. - `volume_attachments` - (List) A nested block describes the storage volume configuration for the template. @@ -72,5 +89,6 @@ You can access the following attribute references after your data source is crea - `encryption_key` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. - `iops` - (String) The maximum input/output operations per second (IOPS) for the volume. - `profile` - (String) The global unique name for the volume profile to use for the volume. + - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `vpc` - (String) The VPC ID that the instance templates needs to be created. - `zone` - (String) The name of the zone. diff --git a/website/docs/d/is_instance_volume_attachment.html.markdown b/website/docs/d/is_instance_volume_attachment.html.markdown index 562f973db..7f4eb2561 100644 --- a/website/docs/d/is_instance_volume_attachment.html.markdown +++ b/website/docs/d/is_instance_volume_attachment.html.markdown @@ -9,14 +9,24 @@ description: |- # ibm_is_instance_volume_attachment Retrieve information of an existing IBM Cloud infrastructure instance volume attachment as a read-only data source. For more information, about VPC virtual server instances, see [Managing virtual server instances](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-virtual-server-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_instance_volume_attachment" "ds_vsi_va" { - instance = "xx-x-x-x-xxxxx - name = "test-volume" +data "ibm_is_instance_volume_attachment" "example" { + instance = ibm_is_instance.example.id + name = "example-instance-volume-attachment" } ``` diff --git a/website/docs/d/is_instance_volume_attachments.html.markdown b/website/docs/d/is_instance_volume_attachments.html.markdown index 1cadc2a18..ee66d01d1 100644 --- a/website/docs/d/is_instance_volume_attachments.html.markdown +++ b/website/docs/d/is_instance_volume_attachments.html.markdown @@ -9,13 +9,23 @@ description: |- # ibm_is_instance_volume_attachments Retrieve information of an existing IBM Cloud infrastructure instance volume attachments as a read-only data source. For more information, about VPC virtual server instances, see [Managing virtual server instances](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-virtual-server-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_instance_volume_attachments" "ds_vsi_vas" { - instance = "xx-x-x-x-xxxxx +data "ibm_is_instance_volume_attachments" "example" { + instance = ibm_is_instance.example.id } ``` diff --git a/website/docs/d/is_instances.html.markdown b/website/docs/d/is_instances.html.markdown index 747e24317..b753d0598 100644 --- a/website/docs/d/is_instances.html.markdown +++ b/website/docs/d/is_instances.html.markdown @@ -9,20 +9,30 @@ description: |- # ibm_is_instances Retrieve information of an existing IBM Cloud virtual server instances as a read-only data source. For more information, about virtual server instances, see [about virtual server instances for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-advanced-virtual-servers). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_instances" "ds_instances" { +data "ibm_is_instances" "example" { } ``` ```terraform -data "ibm_is_instances" "ds_instances1" { - vpc_name = "testacc_vpc" +data "ibm_is_instances" "example" { + vpc_name = "example-vpc" } ``` @@ -47,6 +57,8 @@ In addition to all argument reference list, you can access the following attribu - `instances`- (List of Object) A list of Virtual Servers for VPC instances that exist in your account. Nested scheme for `instances`: + - `availability_policy_host_failure` - (String) The availability policy for this virtual server instance. The action to perform if the compute host experiences a failure. + - `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes - `boot_volume`- (List) A list of boot volumes that were created for the instance. Nested scheme for `boot_volume`: @@ -55,6 +67,12 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name of the boot volume. - `volume_id` - (String) The ID of the volume that is associated with the boot volume attachment. - `volume_crn` - (String) The CRN of the volume that is associated with the boot volume attachment. + - `catalog_offering` - (List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. + + Nested scheme for `catalog_offering`: + - `offering_crn` - (String) The CRN for this catalog offering. Identifies a catalog offering by this unique property + - `version_crn` - (String) The CRN for this version of a catalog offering. Identifies a version of a catalog offering by this unique property + - `crn` - (String) The CRN of the instance. - `disks` - (List) Collection of the instance's disks. Nested `disks` blocks has the following structure: @@ -74,13 +92,29 @@ In addition to all argument reference list, you can access the following attribu - `model` - Model of the gpu. - `id` - (String) The ID that was assigned to the Virtual Servers for VPC instance. - `image` - (String) The ID of the virtual server image that is used in the instance. + - `lifecycle_reasons`- (List) The reasons for the current lifecycle_state (if any). + + Nested scheme for `lifecycle_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this lifecycle state. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state`- (String) The lifecycle state of the virtual server instance. [ **deleting**, **failed**, **pending**, **stable**, **suspended**, **updating**, **waiting** ] - `memory`- (Integer) The amount of memory that was allocated to the instance. + - `metadata_service_enabled` - (Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. - `network_interfaces`- (List) A list of more network interfaces that the instance uses. Nested scheme for `network_interfaces`: - `id` - (String) The ID of the more network interface. - `name` - (String) The name of the more network interface. - - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` - `subnet` - (String) The ID of the subnet that is used in the more network interface. - `security_groups` (List)A list of security groups that were created for the interface. - `placement_target`- (List) The placement restrictions for the virtual server instance. @@ -100,13 +134,25 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name of the primary network interface. - `subnet` - (String) The ID of the subnet that is used in the primary network interface. - `security_groups` (List)A list of security groups that were created for the interface. - - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses.- `resource_group` - (String) The name of the resource group where the instance was created. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) The IP address of the reserved IP. Same as `primary_ipv4_address` + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` + - `resource_group` - (String) The name of the resource group where the instance was created. - `status` - (String) The status of the instance. - `status_reasons` - (List) Array of reasons for the current status. Nested scheme for `status_reasons`: - `code` - (String) A snake case string identifying the status reason. - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason + - `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes + - `total_network_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces. - `volume_attachments`- (List) A list of volume attachments that were created for the instance. Nested scheme for `volume_attachments`: @@ -122,4 +168,3 @@ In addition to all argument reference list, you can access the following attribu - `count`- (Integer) The number of virtual CPUs that are allocated to the instance. - `vpc` - (String) The ID of the VPC that the instance belongs to. - `zone` - (String) The zone where the instance was created. - diff --git a/website/docs/d/is_ipsec_policies.html.markdown b/website/docs/d/is_ipsec_policies.html.markdown new file mode 100644 index 000000000..e29ac7c79 --- /dev/null +++ b/website/docs/d/is_ipsec_policies.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_ipsec_policies" +description: |- + Get information about IPsecPolicyCollection +--- + +# ibm_is_ipsec_policies + +Provides a read-only data source for IPsecPolicyCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about managing IBM Cloud VPN Gateway and IPsec policy , see [about site-to-site VPN gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#policy-negotiation). + +## Example Usage + +```hcl +data "ibm_is_ipsec_policies" "example" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `ipsec_policies` - (List) Collection of IPsec policies. + Nested scheme for **ipsec_policies**: + - `authentication_algorithm` - (String) The authentication algorithm. + - `connections` - (List) The VPN gateway connections that use this IPsec policy. + Nested scheme for **connections**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. + - `created_at` - (String) The date and time that this IPsec policy was created. + - `encapsulation_mode` - (String) The encapsulation mode used. Only `tunnel` is supported. + - `encryption_algorithm` - (String) The encryption algorithm. + - `href` - (String) The IPsec policy's canonical URL. + - `id` - (String) The unique identifier for this IPsec policy. + - `key_lifetime` - (Integer) The key lifetime in seconds. + - `name` - (String) The user-defined name for this IPsec policy. + - `pfs` - (String) Perfect Forward Secrecy. + - `resource_group` - (List) The resource group object, for this IPsec policy. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `resource_type` - (String) The resource type. + - `transform_protocol` - (String) The transform protocol used. Only `esp` is supported. diff --git a/website/docs/d/is_ipsec_policy.html.markdown b/website/docs/d/is_ipsec_policy.html.markdown new file mode 100644 index 000000000..fe95715bc --- /dev/null +++ b/website/docs/d/is_ipsec_policy.html.markdown @@ -0,0 +1,78 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_ipsec_policy" +description: |- + Get information about IPsecPolicy +--- + +# ibm_is_ipsec_policy + +Provides a read-only data source for IPsecPolicy. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about managing IBM Cloud VPN Gateway and IPsec policy , see [about site-to-site VPN gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#policy-negotiation). + +## Example Usage + +```hcl +resource "ibm_is_ipsec_policy" "example" { + name = "my-ipsec-policy" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + pfs = "disabled" +} + +data "ibm_is_ipsec_policy" "example" { + ipsec_policy = ibm_is_ipsec_policy.example.id +} +``` +```hcl +resource "ibm_is_ipsec_policy" "example" { + name = "my-ipsec-policy" + authentication_algorithm = "md5" + encryption_algorithm = "triple_des" + pfs = "disabled" +} + +data "ibm_is_ipsec_policy" "example" { + name = ibm_is_ipsec_policy.example.name +} +``` +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `ipsec_policy` - (Optional, String) The IPsec policy identifier. + ~> **NOTE** : One of `ipsec_policy` or `name` is required + +- `name` - (Optional, String) The name of the ipsec policy + ~> **NOTE** : One of `ipsec_policy` or `name` is required + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the IPsecPolicy. +- `authentication_algorithm` - (String) The authentication algorithm. +- `connections` - (List) The VPN gateway connections that use this IPsec policy. + Nested scheme for **connections**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. +- `created_at` - (String) The date and time that this IPsec policy was created. +- `encapsulation_mode` - (String) The encapsulation mode used. Only `tunnel` is supported. +- `encryption_algorithm` - (String) The encryption algorithm. +- `href` - (String) The IPsec policy's canonical URL. +- `key_lifetime` - (Integer) The key lifetime in seconds. +- `name` - (String) The user-defined name for this IPsec policy. +- `pfs` - (String) Perfect Forward Secrecy. +- `resource_group` - (List) The resource group object, for this IPsec policy. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. +- `resource_type` - (String) The resource type. +- `transform_protocol` - (String) The transform protocol used. Only `esp` is supported. + diff --git a/website/docs/d/is_lb.html.markdown b/website/docs/d/is_lb.html.markdown index 0e1895d02..a52f38405 100644 --- a/website/docs/d/is_lb.html.markdown +++ b/website/docs/d/is_lb.html.markdown @@ -7,30 +7,40 @@ description: |- --- # ibm_is_lb -Retrieve information of an existing IBM VPC Load Balancer as a read-only data source. For more information, about VPC load balancer, see [load balancers for VPC overview](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-vs-elb). +Retrieve information of an existing IBM VPC Load Balancer. For more information, about VPC load balancer, see [load balancers for VPC overview](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-vs-elb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_lb" "testacc_lb" { - name = "testlb" - subnets = [ibm_is_subnet.testacc_subnet.id] +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -data "ibm_is_lb" "ds_lb" { - name = ibm_is_lb.testacc_lb.name +data "ibm_is_lb" "example" { + name = ibm_is_lb.example.name } ``` @@ -83,8 +93,16 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `session_persistence`: - `type` - (String) The session persistence type. - `public_ips` - (String) The public IP addresses assigned to this load balancer. -- `private_ips` - (String) The private IP addresses assigned to this load balancer. -- `resource_group` - (String) The resource group where the load balancer is created. +- `private_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `private_ip`: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. +- `private_ips` - (List) The private IP addresses assigned to this load balancer. Same as `private_ip.[].address` +- `resource_group` - (String) The resource group id, where the load balancer is created. - `route_mode` - (Bool) Indicates whether route mode is enabled for this load balancer. - `security_groups`- (String) A list of security groups that are used with this load balancer. This option is supported only for application load balancers. - `security_groups_supported`- (Bool) Indicates if this load balancer supports security groups. @@ -92,3 +110,4 @@ In addition to all argument reference list, you can access the following attribu - `status` - (String) The status of load balancer. - `tags` - (String) The tags associated with the load balancer. - `type` - (String) The type of the load balancer. +- `udp_supported`- (Bool) Indicates whether this load balancer supports UDP. diff --git a/website/docs/d/is_lb_listener.html.markdown b/website/docs/d/is_lb_listener.html.markdown new file mode 100644 index 000000000..fa26668af --- /dev/null +++ b/website/docs/d/is_lb_listener.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listener" +description: |- + Get information about LoadBalancerListener +--- + +# ibm_is_lb_listener + +Provides a read-only data source for LoadBalancerListener.For more information, about load balancer listener, see [working with listeners](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-listeners). + +## Example Usage + +```terraform +data "ibm_is_lb_listener" "example" { + listener_id = ibm_is_lb_listener.example.listener_id + lb = ibm_is_lb.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `listener_id` - (Required, String) The listener identifier. +- `lb` - (Required, String) The load balancer identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListener. +- `accept_proxy_protocol` - (Boolean) If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value. + +- `certificate_instance` - (List) The certificate instance used for SSL termination. It is applicable only to `https`protocol. + Nested scheme for `certificate_instance`: + - `crn` - (String) The CRN for this certificate instance. + + -> **NOTE:** Certificate Manager is deprecated. Migrate your load balancer certificates from Certificate Manager to Secrets Manager. + +- `connection_limit` - (Integer) The connection limit of the listener. + +- `created_at` - (String) The date and time that this listener was created. + +- `default_pool` - (List) The default pool associated with the listener. +Nested scheme for `default_pool`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The pool's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool. + - `name` - (String) The user-defined name for this load balancer pool. + +- `href` - (String) The listener's canonical URL. + +- `https_redirect` - (List) If specified, the target listener that requests are redirected to. +Nested scheme for `https_redirect`: + - `http_status_code` - (Integer) The HTTP status code for this redirect. + - `listener` - (List) + Nested scheme for `listener`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener's canonical URL. + - `id` - (String) The unique identifier for this load balancer listener. + - `uri` - (String) The redirect relative target URI. + +- `policies` - (List) The policies for this listener. +Nested scheme for `policies`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener policy's canonical URL. + - `id` - (String) The policy's unique identifier. + +- `port` - (Integer) The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination. + +- `port_max` - (Integer) The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener. + +- `port_min` - (Integer) The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener. + +- `protocol` - (String) The listener protocol. Load balancers in the `network` family support `tcp` and `udp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination. + +- `provisioning_status` - (String) The provisioning status of this listener. diff --git a/website/docs/d/is_lb_listener_policies.html.markdown b/website/docs/d/is_lb_listener_policies.html.markdown new file mode 100644 index 000000000..57cb42653 --- /dev/null +++ b/website/docs/d/is_lb_listener_policies.html.markdown @@ -0,0 +1,65 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listener_policies" +description: |- + Get information about LoadBalancerListenerPolicyCollection +--- + +# ibm_is_lb_listener_policies + +Provides a read-only data source for LoadBalancerListenerPolicyCollection. For more information, about VPC load balance listener policy, see [monitoring application Load Balancer for VPC metrics](https://cloud.ibm.com/docs/vpc?topic=vpc-monitoring-metrics-alb). + +## Example Usage + +```terraform +data "ibm_is_lb_listener_policies" "is_lb_listener_policies" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `listener` - (Required, String) The listener identifier. +- `lb` - (Required, String) The load balancer identifier. +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListenerPolicyCollection. +- `policies` - (List) Collection of policies. +Nested scheme for `policies`: + - `action` - (String) The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered. + - `created_at` - (String) The date and time that this policy was created. + - `href` - (String) The listener policy's canonical URL. + - `id` - (String) The policy's unique identifier. + - `name` - (String) The user-defined name for this policy. + - `priority` - (Integer) Priority of the policy. Lower value indicates higher priority. + - `provisioning_status` - (String) The provisioning status of this policy. + - `rules` - (List) The rules for this policy. + Nested scheme for `rules`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The rule's canonical URL. + - `id` - (String) The rule's unique identifier. + - `target` - (List) - If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`. + Nested scheme for `target`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The pool's canonical URL. + - `http_status_code` - (Integer) The HTTP status code for this redirect. + - `id` - (String) The unique identifier for this load balancer pool. + - `listener` - (List) + Nested scheme for `listener`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener's canonical URL. + - `id` - (String) The unique identifier for this load balancer listener. + - `name` - (String) The user-defined name for this load balancer pool. + - `uri` - (String) The redirect relative target URI. + - `url` - (String) The redirect target URL. diff --git a/website/docs/d/is_lb_listener_policy.html.markdown b/website/docs/d/is_lb_listener_policy.html.markdown new file mode 100644 index 000000000..68d98b9a1 --- /dev/null +++ b/website/docs/d/is_lb_listener_policy.html.markdown @@ -0,0 +1,72 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listener_policy" +description: |- + Get information about LoadBalancerListenerPolicy +--- + +# ibm_is_lb_listener_policy + +Provides a read-only data source for LoadBalancerListenerPolicy. For more information, about VPC load balance listener policy, see [monitoring application Load Balancer for VPC metrics](https://cloud.ibm.com/docs/vpc?topic=vpc-monitoring-metrics-alb). + +## Example Usage + +```terraform +data "ibm_is_lb_listener_policy" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + policy_id = ibm_is_lb_listener_policy.example.policy_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `policy_id` - (Required, String) The policy identifier. +- `listener` - (Required, String) The listener identifier. +- `lb` - (Required, String) The load balancer identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListenerPolicy. +- `action` - (String) The policy action.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the policy on which the unexpected property value was encountered. + +- `created_at` - (String) The date and time that this policy was created. + +- `href` - (String) The listener policy's canonical URL. + +- `name` - (String) The user-defined name for this policy. + +- `priority` - (Integer) Priority of the policy. Lower value indicates higher priority. + +- `provisioning_status` - (String) The provisioning status of this policy. + +- `rules` - (List) The rules for this policy. +Nested scheme for `rules`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The rule's canonical URL. + - `id` - (String) The rule's unique identifier. + +- `target` - (List) - If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`. +Nested scheme for `target`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The pool's canonical URL. + - `http_status_code` - (Integer) The HTTP status code for this redirect. + - `id` - (String) The unique identifier for this load balancer pool. + - `listener` - (List) + Nested scheme for `listener`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener's canonical URL. + - `id` - (String) The unique identifier for this load balancer listener. + - `name` - (String) The user-defined name for this load balancer pool. + - `uri` - (String) The redirect relative target URI. + - `url` - (String) The redirect target URL. diff --git a/website/docs/d/is_lb_listener_policy_rule.html.markdown b/website/docs/d/is_lb_listener_policy_rule.html.markdown new file mode 100644 index 000000000..2267bb103 --- /dev/null +++ b/website/docs/d/is_lb_listener_policy_rule.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listener_policy_rule" +description: |- + Get information about LoadBalancerListenerPolicyRule +--- + +# ibm_is_lb_listener_policy_rule + +Provides a read-only data source for LoadBalancerListenerPolicyRule. For more information, about load balancer listener policy and rules, see [layer 7 load balancing policies and rules](https://cloud.ibm.com/docs/vpc?topic=vpc-layer-7-load-balancing). + +## Example Usage + +```terraform +data "ibm_is_lb_listener_policy_rule" "example" { + rule = ibm_is_lb_listener_policy_rule.example.rule + listener = ibm_is_lb_listener.example.listener_id + lb = ibm_is_lb.example.id + policy = ibm_is_lb_listener_policy.example.policy_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `rule` - (Required, String) The rule identifier. +- `listener` - (Required, String) The listener identifier. +- `lb` - (Required, String) The load balancer identifier. +- `policy` - (Required, String) The policy identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListenerPolicyRule. +- `condition` - (String) The condition of the rule. + +- `created_at` - (String) The date and time that this rule was created. + +- `field` - (String) The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional. + +- `href` - (String) The rule's canonical URL. + +- `provisioning_status` - (String) The provisioning status of this rule. + +- `type` - (String) The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set. + +- `value` - (String) Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded. diff --git a/website/docs/d/is_lb_listener_policy_rules.html.markdown b/website/docs/d/is_lb_listener_policy_rules.html.markdown new file mode 100644 index 000000000..d4f237398 --- /dev/null +++ b/website/docs/d/is_lb_listener_policy_rules.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listener_policy_rules" +description: |- + Get information about LoadBalancerListenerPolicyRuleCollection +--- + +# ibm_is_lb_listener_policy_rules + +Provides a read-only data source for LoadBalancerListenerPolicyRuleCollection. For more information, about load balancer listener policy and rules, see [layer 7 load balancing policies and rules](https://cloud.ibm.com/docs/vpc?topic=vpc-layer-7-load-balancing). +## Example Usage + +```terraform +data "ibm_is_lb_listener_policy_rules" "example" { + listener = ibm_is_lb_listener.example.listener_id + lb = ibm_is_lb.example.id + policy = ibm_is_lb_listener_policy.example.policy_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `listener` - (Required, String) The listener identifier. +- `lb` - (Required, String) The load balancer identifier. +- `policy` - (Required, String) The policy identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListenerPolicyRuleCollection. +- `rules` - (List) Collection of rules. +Nested scheme for `rules`: + - `condition` - (String) The condition of the rule. + - `created_at` - (String) The date and time that this rule was created. + - `field` - (Optional, String) The field. This is applicable to `header`, `query`, and `body` rule types.If the rule type is `header`, this property is required.If the rule type is `query`, this is optional. If specified and the rule condition is not`matches_regex`, the value must be percent-encoded.If the rule type is `body`, this is optional. + - `href` - (String) The rule's canonical URL. + - `id` - (String) The rule's unique identifier. + - `provisioning_status` - (String) The provisioning status of this rule. + - `type` - (String) The type of the rule.Body rules are applied to form-encoded request bodies using the `UTF-8` character set. + - `value` - (String) Value to be matched for rule condition.If the rule type is `query` and the rule condition is not `matches_regex`, the value must be percent-encoded. \ No newline at end of file diff --git a/website/docs/d/is_lb_listeners.html.markdown b/website/docs/d/is_lb_listeners.html.markdown new file mode 100644 index 000000000..298ecb6f6 --- /dev/null +++ b/website/docs/d/is_lb_listeners.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: "VPC infrastructure" +page_title: "IBM : ibm_is_lb_listeners" +description: |- + Get information about LoadBalancerListenerCollection +--- + +# ibm_is_lb_listeners + +Provides a read-only data source for LoadBalancerListenerCollection. For more information, about load balancer listener, see [working with listeners](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-listeners). +## Example Usage + +```terraform +data "ibm_is_lb_listeners" "example" { + lb = ibm_is_lb.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `lb` - (Required, String) The load balancer identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerListenerCollection. +- `listeners` - (List) Collection of listeners. + Nested scheme for `listeners`: + - `accept_proxy_protocol` - (Boolean) If set to `true`, this listener will accept and forward PROXY protocol information. Supported by load balancers in the `application` family (otherwise always `false`). Additional restrictions:- If this listener has `https_redirect` specified, its `accept_proxy_protocol` value must match the `accept_proxy_protocol` value of the `https_redirect` listener.- If this listener is the target of another listener's `https_redirect`, its `accept_proxy_protocol` value must match that listener's `accept_proxy_protocol` value. + - `certificate_instance` - (List) The certificate instance used for SSL termination. It is applicable only to `https`protocol. + Nested scheme for `certificate_instance`: + - `crn` - (String) The CRN for this certificate instance. + + -> **NOTE:** Certificate Manager is deprecated. Migrate your load balancer certificates from Certificate Manager to Secrets Manager. + + - `connection_limit` - (Integer) The connection limit of the listener. + - `created_at` - (String) The date and time that this listener was created. + - `default_pool` - (List) The default pool associated with the listener. + Nested scheme for `default_pool`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The pool's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool. + - `name` - (String) The user-defined name for this load balancer pool. + - `href` - (String) The listener's canonical URL. + - `https_redirect` - (List) If specified, the target listener that requests are redirected to. + Nested scheme for `https_redirect`: + - `http_status_code` - (Integer) The HTTP status code for this redirect. + - `listener` - (List) + Nested scheme for `listener`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener's canonical URL. + - `id` - (String) The unique identifier for this load balancer listener. + - `uri` - (String) The redirect relative target URI. + - `id` - (String) The unique identifier for this load balancer listener. + - `policies` - (List) The policies for this listener. + Nested scheme for `policies`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The listener policy's canonical URL. + - `id` - (String) The policy's unique identifier. + - `port` - (Integer) The listener port number, or the inclusive lower bound of the port range. Each listener in the load balancer must have a unique `port` and `protocol` combination. + - `port_max` - (Integer) The inclusive upper bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener. + - `port_min` - (Integer) The inclusive lower bound of the range of ports used by this listener.Only load balancers in the `network` family support more than one port per listener. + - `protocol` - (String) The listener protocol. Load balancers in the `network` family support `tcp` and `udp`. Load balancers in the `application` family support `tcp`, `http`, and `https`. Each listener in the load balancer must have a unique `port` and `protocol` combination. + - `provisioning_status` - (String) The provisioning status of this listener. diff --git a/website/docs/d/is_lb_pool.html.markdown b/website/docs/d/is_lb_pool.html.markdown new file mode 100644 index 000000000..88d7a66b6 --- /dev/null +++ b/website/docs/d/is_lb_pool.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_lb_pool" +description: |- + Get information about LoadBalancerPool +--- + +# ibm_is_lb_pool + +Provides a read-only data source for LoadBalancerPool. For more information, about load balancer pool, see [working with pool](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-pools). + +## Example Usage + +```terraform +data "ibm_is_lb_pool" "example" { + identifier = ibm_is_lb_pool.example.pool_id + lb = ibm_is_lb.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `identifier` - (Optional, String) The pool identifier, if the name is not specified, identifier must be specified. +- `name` - (Optional, String) The pool name, if the identifier is not specified, name must be specified. +- `lb` - (Required, String) The load balancer identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerPool. +- `algorithm` - (String) The load balancing algorithm. +- `created_at` - (String) The date and time that this pool was created. +- `health_monitor` - (List) The health monitor of this pool. + Nested scheme for `health_monitor`: + - `delay` - (Integer) The health check interval in seconds. Interval must be greater than timeout value. + - `max_retries` - (Integer) The health check max retries. + - `port` - (Integer) The health check port number. If specified, this overrides the ports specified in the server member resources. + - `timeout` - (Integer) The health check timeout in seconds. + - `type` - (String) The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered. + - `url_path` - (String) The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1). +- `href` - (String) The pool's canonical URL. +- `instance_group` - (List) The instance group that is managing this pool. + Nested scheme for `instance_group`: + - `crn` - (String) The CRN for this instance group. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this instance group. + - `id` - (String) The unique identifier for this instance group. + - `name` - (String) The user-defined name for this instance group. +- `members` - (List) The backend server members of the pool. + Nested scheme for `members`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The member's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool member. +- `name` - (String) The user-defined name for this load balancer pool. +- `protocol` - (String) The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered. +- `provisioning_status` - (String) The provisioning status of this pool. +- `proxy_protocol` - (String) The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`). +- `session_persistence` - (List) The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered. + Nested scheme for `session_persistence`: + - `cookie_name` - (String) The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed. + - `type` - (String) The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols. diff --git a/website/docs/d/is_lb_pool_member.html.markdown b/website/docs/d/is_lb_pool_member.html.markdown new file mode 100644 index 000000000..fac0ed819 --- /dev/null +++ b/website/docs/d/is_lb_pool_member.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_lb_pool_member" +description: |- + Get information about LoadBalancerPoolMember +--- + +# ibm_is_lb_pool_member + +Provides a read-only data source for LoadBalancerPoolMember. + +## Example Usage + +```terraform +data "ibm_is_lb_pool_member" "example" { + member = element(split("/",ibm_is_lb_pool_member.example.id),2) + lb = ibm_is_lb.example.id + pool = ibm_is_lb_pool.example.pool_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `member` - (Required, String) The member identifier. +- `lb` - (Required, String) The load balancer identifier. +- `pool` - (Required, String) The pool identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerPoolMember. +- `created_at` - (Required, String) The date and time that this member was created. +- `health` - (Required, String) Health of the server member in the pool. +- `href` - (Required, String) The member's canonical URL. +- `port` - (Required, Integer) The port number of the application running in the server member. +- `provisioning_status` - (Required, String) The provisioning status of this member. +- `target` - (Required, List) The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses. + Nested scheme for `target`: + - `address` - (Optional, String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `crn` - (Optional, String) The CRN for this virtual server instance. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Optional, String) The URL for this virtual server instance. + - `id` - (Optional, String) The unique identifier for this virtual server instance. + - `name` - (Optional, String) The user-defined name for this virtual server instance (and default system hostname). +- `weight` - (Optional, Integer) Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`. \ No newline at end of file diff --git a/website/docs/d/is_lb_pool_members.html.markdown b/website/docs/d/is_lb_pool_members.html.markdown new file mode 100644 index 000000000..4add5edfd --- /dev/null +++ b/website/docs/d/is_lb_pool_members.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_lb_pool_members" +description: |- + Get information about LoadBalancerPoolMemberCollection +--- + +# ibm_is_lb_pool_members + +Provides a read-only data source for LoadBalancerPoolMemberCollection. + +## Example Usage + +```terraform +data "ibm_is_lb_pool_members" "example" { + lb = ibm_is_lb.example.id + pool = ibm_is_lb_pool.example.pool_id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `lb` - (Required, String) The load balancer identifier. +- `pool` - (Required, String) The pool identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerPoolMemberCollection. +- `members` - (List) Collection of members. + Nested scheme for `members`: + - `created_at` - (String) The date and time that this member was created. + - `health` - (String) Health of the server member in the pool. + - `href` - (String) The member's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool member. + - `port` - (Integer) The port number of the application running in the server member. + - `provisioning_status` - (String) The provisioning status of this member. + - `target` - (List) The pool member target. Load balancers in the `network` family support virtual serverinstances. Load balancers in the `application` family support IP addresses. + Nested scheme for `target`: + - `address` - (String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `crn` - (String) The CRN for this virtual server instance. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this virtual server instance. + - `id` - (String) The unique identifier for this virtual server instance. + - `name` - (String) The user-defined name for this virtual server instance (and default system hostname). + - `weight` - (Integer) Weight of the server member. Applicable only if the pool algorithm is`weighted_round_robin`. diff --git a/website/docs/d/is_lb_pools.html.markdown b/website/docs/d/is_lb_pools.html.markdown new file mode 100644 index 000000000..1a2d1e8eb --- /dev/null +++ b/website/docs/d/is_lb_pools.html.markdown @@ -0,0 +1,70 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_lb_pools" +description: |- + Get information about LoadBalancerPoolCollection +--- + +# ibm_is_lb_pools + +Provides a read-only data source for LoadBalancerPoolCollection. For more information, about load balancer pool, see [working with pool](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-pools). + +## Example Usage + +```terraform +data "ibm_is_lb_pools" "example" { + lb = ibm_is_lb.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `lb` - (Required, Forces new resource, String) The load balancer identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the LoadBalancerPoolCollection. +- `pools` - (List) Collection of pools. + + Nested scheme for `pools`: + - `algorithm` - (String) The load balancing algorithm. + - `created_at` - (String) The date and time that this pool was created. + - `health_monitor` - (List) The health monitor of this pool. + Nested scheme for `health_monitor`: + - `delay` - (Integer) The health check interval in seconds. Interval must be greater than timeout value. + - `max_retries` - (Integer) The health check max retries. + - `port` - (Integer) The health check port number. If specified, this overrides the ports specified in the server member resources. + - `timeout` - (Integer) The health check timeout in seconds. + - `type` - (String) The protocol type of this load balancer pool health monitor.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the health monitor on which the unexpected property value was encountered. + - `url_path` - (String) The health check URL path. Applicable only if the health monitor `type` is `http` or`https`. This value must be in the format of an [origin-form request target](https://tools.ietf.org/html/rfc7230#section-5.3.1). + - `href` - (String) The pool's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool. + - `instance_group` - (List) The instance group that is managing this pool. + Nested scheme for `instance_group`: + - `crn` - (String) The CRN for this instance group. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this instance group. + - `id` - (String) The unique identifier for this instance group. + - `name` - (String) The user-defined name for this instance group. + - `members` - (List) The backend server members of the pool. + Nested scheme for `members`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The member's canonical URL. + - `id` - (String) The unique identifier for this load balancer pool member. + - `name` - (String) The user-defined name for this load balancer pool. + - `protocol` - (String) The protocol used for this load balancer pool.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the pool on which the unexpected property value was encountered. + - `provisioning_status` - (String) The provisioning status of this pool. + - `proxy_protocol` - (String) The PROXY protocol setting for this pool:- `v1`: Enabled with version 1 (human-readable header format)- `v2`: Enabled with version 2 (binary header format)- `disabled`: DisabledSupported by load balancers in the `application` family (otherwise always `disabled`). + - `session_persistence` - (List) The session persistence of this pool.The enumerated values for this property are expected to expand in the future. Whenprocessing this property, check for and log unknown values. Optionally haltprocessing and surface the error, or bypass the pool on which the unexpectedproperty value was encountered. + Nested scheme for `session_persistence`: + - `cookie_name` - (String) The session persistence cookie name. Applicable only for type `app_cookie`. Names starting with `IBM` are not allowed. + - `type` - (String) The session persistence type. The `http_cookie` and `app_cookie` types are applicable only to the `http` and `https` protocols. \ No newline at end of file diff --git a/website/docs/d/is_lb_profiles.html.markdown b/website/docs/d/is_lb_profiles.html.markdown index b6117116d..bd3d03378 100644 --- a/website/docs/d/is_lb_profiles.html.markdown +++ b/website/docs/d/is_lb_profiles.html.markdown @@ -7,14 +7,24 @@ description: |- --- # ibm_is_lb_profiles -Retrieve information of an existing IBM Cloud Infrastructure load balancer profiles as a read-only data source. For more information, about infrastructure load balance profiles, see [managing security and compliance with load balancers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-manage-security-compliance-lb). +Retrieve information of an existing IBM Cloud infrastructure load balancer profiles as a read-only data source. For more information, about infrastructure load balance profiles, see [managing security and compliance with load balancers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-manage-security-compliance-lb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_lb_profiles" "ds_lb_profiles" { +data "ibm_is_lb_profiles" "example" { } ``` @@ -30,3 +40,6 @@ You can access the following attribute references after your data source is crea - `name` - (String) The name for this load balancer profile. - `route_mode_supported` - (Bool) The route mode support for a load balancer with this profile. - `route_mode_type` - (String) The route mode type for this load balancer profile, one of [fixed, dependent] + - `udp_supported` - (Bool) The UDP support for a load balancer with this profile. + - `udp_supported_type` - (String) The UDP support type for a load balancer with this profile, one of [fixed, dependent] + diff --git a/website/docs/d/is_lbs.html.markdown b/website/docs/d/is_lbs.html.markdown index 88d02f40c..1d8fdd70a 100644 --- a/website/docs/d/is_lbs.html.markdown +++ b/website/docs/d/is_lbs.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_lbs Retrieve information of an existing IBM VPC load balancers as a read-only data source. For more information, about VPC load balancer, see [load balancers for VPC overview](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-vs-elb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_lbs" "ds_lbs" { - } +data "ibm_is_lbs" "example" { +} ``` @@ -53,11 +64,20 @@ Review the attribute references that you can access after you retrieve your data - `family` - (String) The product family this load balancer profile belongs to. - `href` - (String) The URL for this load balancer profile. - `name` - (String) The name for this load balancer profile. - - `private_ips` - (String) The private IP addresses assigned to this load balancer. + - `private_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `private_ip`: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `private_ips` - (String) The private IP addresses assigned to this load balancer. Same as `private_ip.[].address` - `provisioning_status` - (String) The provisioning status of this load balancer. Possible values are: **active**, **create_pending**, **delete_pending**, **failed**, **maintenance_pending**, **update_pending**- - `public_ips` - (String) The public IP addresses assigned to this load balancer. - - `resource_group` - (String) The resource group where the load balancer is created. + - `resource_group` - (String) The resource group id, where the load balancer is created. - `route_mode` - (Bool) Indicates whether route mode is enabled for this load balancer. - `status` - (String) The status of the load balancers. - `type` - (String) The type of the load balancer. - `tags` - (String) Tags associated with the load balancer. + - `udp_supported`- (Bool) Indicates whether this load balancer supports UDP. diff --git a/website/docs/d/is_network_acl.html.markdown b/website/docs/d/is_network_acl.html.markdown new file mode 100644 index 000000000..a4693da30 --- /dev/null +++ b/website/docs/d/is_network_acl.html.markdown @@ -0,0 +1,121 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : network_acl" +description: |- + Get information about IBM Network ACL. + +--- + +# ibm_is_network_acl +Retrieve information of an network ACL data source. For more information, about managing network ACL, see [create a network acl](hhttps://cloud.ibm.com/docs/vpc?topic=vpc-acl-create-ui&interface=ui). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_network_acl" "example" { + name = "example-network-acl" + vpc = ibm_is_vpc.example.id +} + +data "ibm_is_network_acl" "example" { + network_acl = ibm_is_network_acl.example.id +} + +data "ibm_is_network_acl" "is_network_acl1" { + name = ibm_is_network_acl.example.name + vpc_name = ibm_is_vpc.example.name +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `name` - (Optional, String) The name of the network ACL. +- `network_acl` - (Optional, String) The network ACL identifier. +- `vpc_name` - (Optional, String) The name of the VPC. + **Note** Provide `network_acl` or the combination of `vpc_name` and `name`. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `created_at` - (String) The date and time that the network ACL was created. +- `crn` - (String) The CRN for this network ACL. +- `href` - (String) The URL for this network ACL. +- `id` - The unique identifier of the NetworkACL. +- `name` - (String) The user-defined name for this network ACL. +- `resource_group` - (List) The resource group object, for this network ACL. + + Nested scheme for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. +- `rules`- (Array of Strings) A list of rules for a network ACL. The order in which the rules are added to the list determines the priority of the rules. For example, the first rule that you want to enforce must be specified as the first rule in this list. + + Nested scheme for `rules`: + - `name` - (String) The user-defined name for this rule. + - `action` - (String) `Allow` or `deny` matching network traffic. + - `source` - (String) The source IP address or CIDR block. + - `destination` - (String) The destination IP address or CIDR block. + - `direction` - (String) Indicates whether the traffic to be matched is `inbound` or `outbound`. + - `icmp`- (List) The protocol ICMP. + + Nested scheme for `icmp`: + - `code` - (Integer) The ICMP traffic code to allow. Valid values from `0 to 255`. If unspecified, all codes are allowed. This can only be specified if type is also specified. + - `type` - (Integer) The ICMP traffic type to allow. Valid values from `0 to 254`. If unspecified, all types are allowed by this rule. + - `tcp`- (List) The TCP protocol. + + Nested scheme for `tcp`: + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched, if unspecified, `1` is used as default. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used as default. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used as default. + - `udp`- (List) The UDP protocol. + + Nested scheme for `udp`: + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used. +- `subnets` - (List) The subnets to which this network ACL is attached. + + Nested scheme for **subnets**: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. +- `vpc` - (List) The VPC this network ACL is a part of. + + Nested scheme for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + + - `href` - (String) The URL for this VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The unique user-defined name for this VPC. + diff --git a/website/docs/d/is_network_acl_rule.html.markdown b/website/docs/d/is_network_acl_rule.html.markdown index be123ccb9..14e37b184 100644 --- a/website/docs/d/is_network_acl_rule.html.markdown +++ b/website/docs/d/is_network_acl_rule.html.markdown @@ -8,35 +8,44 @@ description: |- # ibm_is_network_acl_rule -Provides a network ACL rule read-only datasource. This allows to fetch an existing network ACL rule details. For more information, about managing IBM Cloud Network ACL , see [about network acl](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +Retrieve information of an network ACL rule data source. For more information, about managing IBM Cloud Network ACL , see [about network acl](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "vpctest" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_network_acl" "isExampleACL" { - name = "is-example-acl" - vpc = ibm_is_vpc.testacc_vpc.id -} - -resource "ibm_is_network_acl_rule" "isExampleACLRule1" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "test-nacl-rule" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" +resource "ibm_is_network_acl" "example" { + name = "example-network-acl" + vpc = ibm_is_vpc.example.id } -data "ibm_is_network_acl_rule" "testacc_dsrule"{ - network_acl = ibm_is_network_acl.isExampleACL.id - name = "test-nacl-rule" +resource "ibm_is_network_acl_rule" "example" { + network_acl = ibm_is_network_acl.example.id + name = "example-network-acl-rule" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" } +data "ibm_is_network_acl_rule" "example" { + network_acl = ibm_is_network_acl.example.id + name = "example-network-acl-rule" +} ``` ## Argument reference @@ -56,20 +65,21 @@ In addition to all argument reference list, you can access the following attribu - `direction` - (String) Whether the traffic to be matched is inbound or outbound. - `href` - (String) The URL for this network ACL rule. - `icmp` - (List) The protocol ICMP - - `code` - (Integer) The ICMP traffic code to allow. Valid values from **0 to 255**. If unspecified, all codes are allowed. This can only be specified if type is also specified. - - `type` - (Integer) The ICMP traffic type to allow. Valid values from **0 to 254**. If unspecified, all types are allowed by this rule. + - `code` - (Integer) The ICMP traffic code to allow. Valid values from **0 to 255**. If unspecified, all codes are allowed. This can only be specified if type is also specified. + - `type` - (Integer) The ICMP traffic type to allow. Valid values from **0 to 254**. If unspecified, all types are allowed by this rule. - `id` - (String) The network ACL rule identfier. This id is composed of `/\`. - `ip_version` - (String) The IP version for this rule. - `protocol` - (String) The protocol to enforce. - `rule_id` - (String) The network ACL rule ID. - `source` - (String) The source IP address or CIDR block. - `tcp` - (List) TCP protocol. - - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - `udp` - (List) UDP protocol - - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. \ No newline at end of file + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + \ No newline at end of file diff --git a/website/docs/d/is_network_acl_rules.html.markdown b/website/docs/d/is_network_acl_rules.html.markdown index 34fa98910..4d5672afd 100644 --- a/website/docs/d/is_network_acl_rules.html.markdown +++ b/website/docs/d/is_network_acl_rules.html.markdown @@ -6,28 +6,37 @@ description: |- Manages IBM Network Acl Rules. --- -# ibm\_is_network_acl_rules +# ibm_is_network_acl_rules Import the details of an existing IBM Cloud Infrastructure Network ACL Rules as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about managing IBM Cloud Network ACL , see [about network acl](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. +**provider.tf** -## Example Usage +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage ```terraform -data "ibm_is_network_acl_rules" "testacc_dsrulelist"{ - network_acl = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx +data "ibm_is_network_acl_rules" "example"{ + network_acl = ibm_is_network_acl.example.id } ``` -## Argument Reference +## Argument reference Review the argument references that you can specify for your resource. - `network_acl` - (Required, String) The network ACL identifier. -## Attribute Reference +## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/d/is_network_acls.html.markdown b/website/docs/d/is_network_acls.html.markdown new file mode 100644 index 000000000..713dd5ef2 --- /dev/null +++ b/website/docs/d/is_network_acls.html.markdown @@ -0,0 +1,111 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : network_acls" +description: |- + Get information about IBM Network ACLs. + +--- + +# ibm_is_network_acls +Retrieve information about an existing Network ACLs. For more information, about Network ACLs, see [About network ACLs](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_network_acl" "example" { + name = "example-network-acl" + vpc = ibm_is_vpc.example.id +} + +data "ibm_is_network_acls" "example" { +} +``` + +## Argument reference +Review the argument reference that you can specify for your resource. + +- `resource_group` - (Optional, String) Filters the collection to resources within one of the resource groups identified in a comma-separated list of resource group identifiers. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `network_acls` - (List) Collection of network ACLs. + + Nested scheme for `network_acls`: + - `created_at` - (String) The date and time that the network ACL was created. + - `crn` - (String) The CRN for this network ACL. + - `href` - (String) The URL for this network ACL. + - `id` - (String) The unique identifier for this network ACL. + - `name` - (String) The user-defined name for this network ACL. + - `resource_group` - (List) The resource group object, for this network ACL. + + Nested scheme for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `rules` - (Array of Strings) A list of rules for a network ACL. + + Nested scheme for `rules`: + - `name` - (String) The user-defined name for this rule. + - `action` - (String) `Allow` or `deny` matching network traffic. + - `source` - (String) The source IP address or CIDR block. + - `destination` - (String) The destination IP address or CIDR block. + - `direction` - (String) Indicates whether the traffic to be matched is `inbound` or `outbound`. + - `icmp`- (List) The protocol ICMP. + + Nested scheme for `icmp`: + - `code` - (Integer) The ICMP traffic code to allow. Valid values from 0 to 255. If unspecified, all codes are allowed. This can only be specified if type is also specified. + - `type` - (Integer) The ICMP traffic type to allow. Valid values from 0 to 254. If unspecified, all types are allowed by this rule. + - `tcp`- (List) The TCP protocol. + + Nested scheme for `tcp`: + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched, if unspecified, `1` is used as default. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used as default. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used as default. + - `udp`- (List) The UDP protocol. + + Nested scheme for `udp`: + - `port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used. + - `source_port_max` - (Integer) The highest port in the range of ports to be matched; if unspecified, `65535` is used. + - `source_port_min` - (Integer) The lowest port in the range of ports to be matched; if unspecified, `1` is used. + - `subnets` - (List) The subnets to which this network ACL is attached. + + Nested scheme for `subnets`: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. + - `vpc` - (List) The VPC this network ACL is a part of. + + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The unique user-defined name for this VPC. diff --git a/website/docs/d/is_operating_system.html.markdown b/website/docs/d/is_operating_system.html.markdown index 1cc427e3a..3a6ac2779 100644 --- a/website/docs/d/is_operating_system.html.markdown +++ b/website/docs/d/is_operating_system.html.markdown @@ -9,19 +9,29 @@ description: |- # ibm_is_operating_system Retrieve information of an existing Operating System as a read only data source. For more information, about supported Operating System, see [Images](https://cloud.ibm.com/docs/vpc?topic=vpc-about-images). -## Example usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** ```terraform -data "ibm_is_operating_system" "testacc_dsos"{ - name = "red-8-amd64" +provider "ibm" { + region = "eu-gb" } +``` +## Example usage + +```terraform +data "ibm_is_operating_system" "example" { + name = "centos-7-amd64" +} ``` ## Argument reference Review the argument references that you can specify for your data source. -- `name` - (Required, String) The global unique name of an operating system. +- `name` - (Required, String) The global unique name of an Operating System. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/is_operating_systems.html.markdown b/website/docs/d/is_operating_systems.html.markdown index 0d6011e56..93358b2b8 100644 --- a/website/docs/d/is_operating_systems.html.markdown +++ b/website/docs/d/is_operating_systems.html.markdown @@ -9,10 +9,21 @@ description: |- # ibm_is_operating_systems Retrieve information of an existing IBM Cloud Infrastructure Operating Systems as a read only data source. For more information, about supported Operating System, see [Images](https://cloud.ibm.com/docs/vpc?topic=vpc-about-images). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_operating_systems" "testacc_dsoslist"{ +data "ibm_is_operating_systems" "example"{ } ``` @@ -22,11 +33,11 @@ You can access the following attribute references after your data source is crea - `operating_systems` - (List) List of all Operating Systems in the IBM Cloud Infrastructure region. Nested scheme for `operating_system`: - - `architecture` - (String) The operating system architecture. - - `dedicated_host_only` - (String) Images with this operating system can only be used on dedicated hosts or dedicated host groups. - - `display_name` - (String) A unique, display-friendly name for the operating system. - - `family` - (String) The name of the software family this operating system belongs to. - - `href` - (String) The URL for this operating system. - - `name` - (String) The globally unique name for this operating system. - - `vendor` - (String) The vendor of the operating system. - - `version` - (String) The major release version of this operating system. + - `architecture` - (String) The Operating System architecture. + - `dedicated_host_only` - (String) Images with this Operating System can only be used on dedicated hosts or dedicated host groups. + - `display_name` - (String) A unique, display-friendly name for the Operating System. + - `family` - (String) The name of the software family this Operating System belongs to. + - `href` - (String) The URL for this Operating System. + - `name` - (String) The globally unique name for this Operating System. + - `vendor` - (String) The vendor of the Operating System. + - `version` - (String) The major release version of this Operating System. diff --git a/website/docs/d/is_placement_group.html.markdown b/website/docs/d/is_placement_group.html.markdown index 65fba187b..39c9b164b 100644 --- a/website/docs/d/is_placement_group.html.markdown +++ b/website/docs/d/is_placement_group.html.markdown @@ -7,24 +7,34 @@ description: |- --- # ibm_is_placement_group +Retrieve information of a placement group as a read-only data source. For more information, about placement group, see [managing placement groups](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-placement-group&interface=ui). -Provides a read-only data source for PlacementGroup. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example Usage +**provider.tf** -```hcl -data "is_placement_group" "is_placement_group" { - id = "id" +```terraform +provider "ibm" { + region = "eu-gb" } ``` -## Argument Reference +## Example usage + +```terraform +data "is_placement_group" "example" { + name = ibm_is_placement_group.example.name +} +``` + +## Argument reference The following arguments are supported: - `name` - (Required, String) The placement group identifier. -## Attribute Reference +## Attribute reference The following attributes are exported: diff --git a/website/docs/d/is_placement_groups.html.markdown b/website/docs/d/is_placement_groups.html.markdown index f73be334e..c53561d56 100644 --- a/website/docs/d/is_placement_groups.html.markdown +++ b/website/docs/d/is_placement_groups.html.markdown @@ -1,28 +1,39 @@ --- subcategory: "VPC infrastructure" layout: "ibm" -page_title: "IBM : Placement_Proups" +page_title: "IBM : Placement_Groups" description: |- - Get information about PlacementGroupCollection + Get information about placement groups --- # ibm_is_placement_groups -Provides a read-only data source for PlacementGroupCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Retrieve information of a placement groups as a read-only data source. For more information, about placement groups, see [managing placement groups](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-placement-group&interface=ui). -## Example Usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -```hcl -data "is_placement_groups" "is_placement_groups" { +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +data "is_placement_groups" "example" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: -## Attribute Reference +## Attribute reference The following attributes are exported: diff --git a/website/docs/d/is_public_gateway.html.markdown b/website/docs/d/is_public_gateway.html.markdown index 10a4bfc0e..ce9bfd801 100644 --- a/website/docs/d/is_public_gateway.html.markdown +++ b/website/docs/d/is_public_gateway.html.markdown @@ -7,26 +7,36 @@ description: |- --- # ibm_is_public_gateway -Retrieve information of an existing public gateway data source. For more information, about an VPC public gateway, see [about networking](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc). +Retrieve information of an existing public gateway data source as a read only data source. For more information, about an VPC public gateway, see [about networking](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_public_gateway" "testacc_gateway" { - name = "test-gateway" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_public_gateway" "example" { + name = "example-gateway" + vpc = ibm_is_vpc.example.id zone = "us-south-1" } -data "ibm_is_public_gateway" "testacc_dspgw"{ - name = ibm_is_public_gateway.testacc_public_gateway.name +data "ibm_is_public_gateway" "example" { + name = ibm_is_public_gateway.example.name } - ``` ## Argument reference diff --git a/website/docs/d/is_public_gateways.html.markdown b/website/docs/d/is_public_gateways.html.markdown index 19cd16f18..07a239cd1 100644 --- a/website/docs/d/is_public_gateways.html.markdown +++ b/website/docs/d/is_public_gateways.html.markdown @@ -7,12 +7,23 @@ description: |- --- # ibm_is_public_gateways -Retrieve information of an existing public gateways as a ready only data source. For more information, about an VPC public gateway, see [about networking](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc). +Retrieve information of an existing public gateways as a read only data source. For more information, about an VPC public gateway, see [about networking](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_public_gateways" "testacc_dspgw"{ +data "ibm_is_public_gateways" "example"{ } ``` diff --git a/website/docs/d/is_region.html.markdown b/website/docs/d/is_region.html.markdown index 8bb03efef..d761f9386 100644 --- a/website/docs/d/is_region.html.markdown +++ b/website/docs/d/is_region.html.markdown @@ -7,21 +7,40 @@ description: |- --- # ibm_is_region -Retrieve information about a VPC Generation 2 Compute region. For more information, about managing IBM Cloud region, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). +Retrieve information about a VPC Generation 2 Compute region as a read only data source. For more information, about managing IBM Cloud region, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_region" "ds_region" { +data "ibm_is_region" "example" { name = "us-south" } ``` + +```terraform + +data "ibm_is_region" "default_region" { +} + +``` + ## Argument reference Review the argument references that you can specify for your data source. -- `name` - (Required, String) The name of the region. +- `name` - (Optional, String) The name of the region. If no `name` is provided then default region `name` is taken from the provider block. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/is_regions.html.markdown b/website/docs/d/is_regions.html.markdown index f4a5f3cf5..56761981c 100644 --- a/website/docs/d/is_regions.html.markdown +++ b/website/docs/d/is_regions.html.markdown @@ -7,13 +7,24 @@ description: |- --- # ibm_is_regions -Retrieve information about VPC Generation 2 list of regions. For more information, about managing IBM Cloud region, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). +Retrieve information about VPC Generation 2 list of regions as a read only data source. For more information, about managing IBM Cloud region, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_regions" "ds_regions" { +data "ibm_is_regions" "example" { } ``` diff --git a/website/docs/d/is_security_group.html.markdown b/website/docs/d/is_security_group.html.markdown index 98494131d..3f773b10a 100644 --- a/website/docs/d/is_security_group.html.markdown +++ b/website/docs/d/is_security_group.html.markdown @@ -9,28 +9,38 @@ description: |- # ibm_is_security_group Retrieve information about a security group as a read-only data source. For more information, about managing IBM Cloud security group , see [about security group](https://cloud.ibm.com/docs/vpc?topic=vpc-using-security-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage The following example allows to create a different types of protocol rules `ALL`, `ICMP`, `UDP`, `TCP` and read the security group. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_security_group" "testacc_security_group" { - name = "test" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_security_group" "example" { + name = "example-sg" + vpc = ibm_is_vpc.example.id } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_all" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_icmp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" icmp { @@ -39,8 +49,8 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_icmp" { } } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_udp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" udp { @@ -49,8 +59,8 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_udp" { } } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_tcp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id direction = "egress" remote = "127.0.0.1" tcp { @@ -59,8 +69,8 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_tcp" { } } -data "ibm_is_security_group" "sg1_rule" { - name = ibm_is_security_group.testacc_security_group.name +data "ibm_is_security_group" "example" { + name = ibm_is_security_group.example.name } ``` diff --git a/website/docs/d/is_security_group_rule.html.markdown b/website/docs/d/is_security_group_rule.html.markdown new file mode 100644 index 000000000..712bab644 --- /dev/null +++ b/website/docs/d/is_security_group_rule.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_security_group_rule" +description: |- + Get information about is_security_group_rule +subcategory: "VPC infrastructure" +--- + +# ibm_is_security_group_rule + +Provides a read-only data source for is_security_group_rule. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +For more information, about security group rule, see [security in your VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-security-in-your-vpc). + + +## Example Usage + +```hcl +data "ibm_is_security_group_rule" "example" { + security_group_rule = ibm_is_security_group_rule.example.rule_id + security_group = ibm_is_security_group.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `security_group_rule` - (Required, String) The rule identifier. +- `security_group` - (Required, String) The security group identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the is_security_group_rule. +- `code` - (Integer) The ICMP traffic code to allow. + +- `direction` - (String) The direction of traffic to enforce, either `inbound` or `outbound`. + +- `href` - (String) The URL for this security group rule. + +- `ip_version` - (String) The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version. + +- `port_max` - (Integer) The inclusive upper bound of TCP/UDP port range. + +- `port_min` - (Integer) The inclusive lower bound of TCP/UDP port range. + +- `protocol` - (String) The protocol to enforce. + +- `remote` - (List) The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules). +Nested scheme for `remote`: + - `address` - (String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `cidr_block` - (String) The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered. + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + +- `type` - (Integer) The ICMP traffic type to allow. + diff --git a/website/docs/d/is_security_group_rules.html.markdown b/website/docs/d/is_security_group_rules.html.markdown new file mode 100644 index 000000000..c890ba5bb --- /dev/null +++ b/website/docs/d/is_security_group_rules.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_security_group_rules" +description: |- + Get information about SecurityGroupRuleCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_security_group_rules + +Provides a read-only data source for SecurityGroupRuleCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +For more information, about security group rule, see [security in your VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-security-in-your-vpc). + +## Example Usage + +```hcl +data "ibm_is_security_group_rules" "example" { + security_group = ibm_is_security_group.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `security_group` - (Required, String) The security group identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the SecurityGroupRuleCollection. +- `rules` - (List) Array of rules. +Nested scheme for `rules`: + - `code` - (Integer) The ICMP traffic code to allow. + - `direction` - (String) The direction of traffic to enforce, either `inbound` or `outbound`. + - `href` - (String) The URL for this security group rule. + - `id` - (String) The unique identifier for this security group rule. + - `ip_version` - (String) The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version. + - `port_max` - (Integer) The inclusive upper bound of TCP/UDP port range. + - `port_min` - (Integer) The inclusive lower bound of TCP/UDP port range. + - `protocol` - (String) The protocol to enforce. + - `remote` - (List) The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules). + Nested scheme for `remote`: + - `address` - (String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `cidr_block` - (String) The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered. + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + - `type` - (Integer) The ICMP traffic type to allow. + diff --git a/website/docs/d/is_security_group_target.html.markdown b/website/docs/d/is_security_group_target.html.markdown index 295865628..55ff1c2a4 100644 --- a/website/docs/d/is_security_group_target.html.markdown +++ b/website/docs/d/is_security_group_target.html.markdown @@ -10,14 +10,24 @@ description: |- # ibm_is_security_group_target Retrieve information of an existing security group target as a read only data source. For more information, about security group target, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage In the following example, you can create a security group target: ```terraform -data "ibm_is_security_group_target" "testacc_security_group_target" { - security_group = "r006-5b77aa07-7dfb-4c74-a1bd-904b23cbe198" - name = "securitygrouptargetname" +data "ibm_is_security_group_target" "example" { + security_group = ibm_is_security_group.example.id + name = "example-security-group-target" } ``` diff --git a/website/docs/d/is_security_group_targets.html.markdown b/website/docs/d/is_security_group_targets.html.markdown index 5a736d1dc..25d2efd4a 100644 --- a/website/docs/d/is_security_group_targets.html.markdown +++ b/website/docs/d/is_security_group_targets.html.markdown @@ -10,13 +10,24 @@ description: |- # ibm_is_security_group_targets Retrieve information of an existing security group targets as a read only data source. For more information, about security group targets, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can create a security group target: ```terraform -data "ibm_is_security_group_targets" "testacc_security_group_targets" { - security_group = ibm_is_security_group.testacc_security_group.id - } +data "ibm_is_security_group_targets" "example" { + security_group = ibm_is_security_group.example.id +} ``` ## Argument reference @@ -31,8 +42,8 @@ In addition to all argument reference list, you can access the following attribu - `targets` - (List) Collection of security group target references Nested scheme for `targets`: - - `crn` - (String) The CRN for this target - - `target` - (String) The unique identifier for this load balancer/network interface - - `name` - (String) The user-defined name of the target - - `resource_type` - (String) The resource type - - `more_info` - (String) Link to documentation about deleted resources + - `crn` - (String) The CRN for this target. + - `target` - (String) The unique identifier for this load balancer/network interface. + - `name` - (String) The user-defined name of the target. + - `resource_type` - (String) The resource type. + - `more_info` - (String) Link to documentation about deleted resources. diff --git a/website/docs/d/is_security_groups.html.markdown b/website/docs/d/is_security_groups.html.markdown new file mode 100644 index 000000000..b96c3fe2e --- /dev/null +++ b/website/docs/d/is_security_groups.html.markdown @@ -0,0 +1,116 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_security_groups" +description: |- + Get information about SecurityGroupCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_security_groups + +Provides a read-only data source for SecurityGroupCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +For more information, about security group, see API Docs(https://cloud.ibm.com/docs/vpc?topic=vpc-using-security-groups). + +## Example Usage + +```terraform +data "ibm_is_security_groups" "example" { +} +``` + +OR with Filters: + +Filter with VPC name + +```terraform +data "ibm_is_security_groups" "example" { + vpc_name = ibm_is_vpc.example.name +} +``` + +Filter with VPC ID + +```terraform +data "ibm_is_security_groups" "example" { + vpc_id = ibm_is_vpc.example.id +} +``` + +Filter with VPC CRN +```terraform +data "ibm_is_security_groups" "example" { + vpc_crn = ibm_is_vpc.example.crn +} +``` + +Filter with Resource Group ID + +```terraform +data "ibm_is_security_groups" "example" { + resource_group= data.ibm_resource_group.default.id +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the SecurityGroupCollection. +- `vpc_name` - Filters the collection to resources in the VPC with the exact specified name +- `vpc_id` - Filters the collection to resources in the VPC with the specified identifier +- `vpc_crn` - Filters the collection to resources in the VPC with the specified CRN +- `resource_group` - Filters the collection to resources in the resource group with the specified identifier +- `security_groups` - (List) Collection of security groups. + Nested scheme for `security_groups`: + - `created_at` - (String) The date and time that this security group was created. + - `crn` - (String) The security group's CRN. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + - `resource_group` - (List) The resource group object, for this security group. + Nested scheme for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + - `rules` - (List) The rules for this security group. If no rules exist, all traffic will be denied. + Nested scheme for `rules`: + - `code` - (Integer) The ICMP traffic code to allow. + - `direction` - (String) The direction of traffic to enforce, either `inbound` or `outbound`. + - `href` - (String) The URL for this security group rule. + - `id` - (String) The unique identifier for this security group rule. + - `ip_version` - (String) The IP version to enforce. The format of `remote.address` or `remote.cidr_block` must match this property, if they are used. Alternatively, if `remote` references a security group, then this rule only applies to IP addresses (network interfaces) in that group matching this IP version. + - `port_max` - (Integer) The inclusive upper bound of TCP/UDP port range. + - `port_min` - (Integer) The inclusive lower bound of TCP/UDP port range. + - `protocol` - (String) The protocol to enforce. + - `remote` - (List) The IP addresses or security groups from which this rule allows traffic (or to which,for outbound rules). Can be specified as an IP address, a CIDR block, or a securitygroup. A CIDR block of `0.0.0.0/0` allows traffic from any source (or to any source,for outbound rules). + Nested scheme for `remote`: + - `address` - (String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `cidr_block` - (String) The CIDR block. This property may add support for IPv6 CIDR blocks in the future. When processing a value in this property, verify that the CIDR block is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected CIDR block format was encountered. + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + - `type` - (Integer) The ICMP traffic type to allow. + - `targets` - (List) The targets for this security group. + Nested scheme for `targets`: + - `crn` - (String) The load balancer's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network interface. + - `id` - (String) The unique identifier for this network interface. + - `name` - (String) The user-defined name for this network interface. + - `resource_type` - (String) The resource type. + - `vpc` - (List) The VPC this security group is a part of. + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The unique user-defined name for this VPC. diff --git a/website/docs/d/is_snapshot.html.markdown b/website/docs/d/is_snapshot.html.markdown index 961601ab0..b82d79006 100644 --- a/website/docs/d/is_snapshot.html.markdown +++ b/website/docs/d/is_snapshot.html.markdown @@ -9,70 +9,98 @@ description: |- Import the details of existing IBM Cloud infrastructure snapshot as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about infrastructure snapshots, see [viewing snapshots](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-view). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-2" - total_ipv4_address_count = 16 +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + total_ipv4_address_count = 16 } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } -resource "ibm_is_instance" "testacc_instance" { - name = "testvsi" - image = "xxxxx-xxxxx-xxxxx-xxxxxx" +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + +} + +resource "ibm_is_instance" "example" { + name = "example-vsi" + image = ibm_is_image.example.id profile = "bx2-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id name = "eth1" } } -resource "ibm_is_snapshot" "testacc_snapshot" { - name = "testsnapshot" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id +resource "ibm_is_snapshot" "example" { + name = "example-snapshot" + source_volume = ibm_is_instance.example.volume_attachments[0].volume_id } -data "ibm_is_snapshot" "ds_snapshot1" { - identifier = ibm_is_snapshot.testacc_snapshot.id +data "ibm_is_snapshot" "example" { + identifier = ibm_is_snapshot.example.id } - ``` ```terraform - -data "ibm_is_snapshot" "ds_snapshot2" { - name = ibm_is_snapshot.testacc_snapshot.name +data "ibm_is_snapshot" "example" { + name = ibm_is_snapshot.example.name } - ``` ## Argument reference Review the argument references that you can specify for your data source. -- `identifier` - (Optional, String) The unique identifier for this snapshot. -- `name` - (Optional, String) The name of the snapshot. +- `identifier` - (Optional, String) The unique identifier for this snapshot,`name` and `identifier` are mutually exclusive. +- `name` - (Optional, String) The name of the snapshot,`name` and `identifier` are mutually exclusive. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your data source is created. +- `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot. + + Nested scheme for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user defined name for this backup policy plan. If unspecified, the name will be a hyphenated list of randomly selected words. + - `resource_type` - (String) The type of resource referenced. - `bootable` - (Bool) Indicates if a boot volume attachment can be created with a volume created from this snapshot. - `crn` - (String) The CRN for this snapshot. - `encryption` - (String) The type of encryption used on the source volume. Supported values are **provider_managed**, **user_managed**. @@ -83,3 +111,5 @@ In addition to all argument reference list, you can access the following attribu - `resource_type` - (String) The resource type. - `size` - (Integer) The size of this snapshot rounded up to the next gigabyte. - `source_image` - (String) If present, the unique identifier for the image from which the data on this volume was most directly provisioned. +- `captured_at` - (String) The date and time that this snapshot was captured. +- `tags` - (String) Tags associated with the snapshot. diff --git a/website/docs/d/is_snapshots.html.markdown b/website/docs/d/is_snapshots.html.markdown index fb744ace1..02bdf185c 100644 --- a/website/docs/d/is_snapshots.html.markdown +++ b/website/docs/d/is_snapshots.html.markdown @@ -9,16 +9,38 @@ description: |- Import the details of an existing IBM Cloud infrastructure snapshot collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax, see [viewing snapshots](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-view). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_snapshots" "ds_snapshots" { +data "ibm_is_snapshots" "example" { } ``` +## Argument reference +Review the argument references that you can specify for your data source. + +- `name` - (Optional, String) Filter snapshot collection by name of the snapshot. +- `resource_group` - (Optional, String) Filter snapshot collection by resource group id of the snapshot. +- `source_image` - (Optional, String) Filter snapshot collection by source image of the snapshot. +- `source_volume` - (Optional, String) Filter snapshot collection by source volume of the snapshot. +- `backup_policy_plan_tag` - Filters the collection to resources with the exact tag value. +- `backup_policy_plan_id` - Filters the collection to backup policy jobs with the backup plan with the specified identifier + + ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. @@ -26,6 +48,17 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `snapshots`: - `id` - (String) The unique identifier for this snapshot. + - `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot. + + Nested scheme for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user defined name for this backup policy plan. If unspecified, the name will be a hyphenated list of randomly selected words. + - `resource_type` - (String) The type of resource referenced. - `bootable` - (Bool) Indicates if a boot volume attachment can be created with a volume created from this snapshot. - `crn` - (String) The CRN for this snapshot. - `encryption` - (String) The type of encryption used on the source volume. Supported values are **provider_managed**, **user_managed** ]). @@ -36,4 +69,7 @@ In addition to all argument reference list, you can access the following attribu - `resource_type` - (String) The resource type. - `size` - (Integer) The size of this snapshot rounded up to the next gigabyte. - `source_image` - (String) If present, the unique identifier for the image from which the data on this volume was most directly provisioned. + - `captured_at` - (String) The date and time that this snapshot was captured. + - `tags` - (String) Tags associated with the snapshot. + diff --git a/website/docs/d/is_ssh_key.html.markdown b/website/docs/d/is_ssh_key.html.markdown index 89617c9e8..ec103889a 100644 --- a/website/docs/d/is_ssh_key.html.markdown +++ b/website/docs/d/is_ssh_key.html.markdown @@ -9,12 +9,23 @@ description: |- # ibm_is_ssh_key Retrieve information of an existing IBM Cloud VPC SSH key as a read only data source. For more information, see [SSH keys](https://cloud.ibm.com/docs/vpc?topic=vpc-ssh-keys). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_ssh_key" "ds_key" { - name = "test" +data "ibm_is_ssh_key" "example" { + name = "example-ssh-key" } ``` @@ -23,7 +34,6 @@ data "ibm_is_ssh_key" "ds_key" { Review the argument references that you can specify for your data source. - `name` - (Required, String) The name of the SSH key. -- `resource_group` - (Optional, string) The ID of resource group of the Key. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/is_ssh_keys.html.markdown b/website/docs/d/is_ssh_keys.html.markdown new file mode 100644 index 000000000..4dae3412c --- /dev/null +++ b/website/docs/d/is_ssh_keys.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_ssh_keys" +description: |- + Get information about KeyCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_ssh_keys + +Provides a read-only data source for KeyCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_ssh_keys" "example" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the KeyCollection. +- `keys` - (List) Collection of keys. + Nested scheme for **keys**: + - `created_at` - (String) The date and time that the key was created. + - `crn` - (String) The CRN for this key. + - `fingerprint` - (String) The fingerprint for this key. The value is returned base64-encoded and prefixed with the hash algorithm (always `SHA256`). + - `href` - (String) The URL for this key. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this key. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `length` - (Integer) The length of this key (in bits). + - Constraints: Allowable values are: `2048`, `4096`. + - `name` - (String) The unique user-defined name for this key. If unspecified, the name will be a hyphenated list of randomly-selected words. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$/`. + - `public_key` - (String) The public SSH key, consisting of two space-separated fields: the algorithm name, and the base64-encoded key. + - `resource_group` - (List) The resource group object, for this key. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this resource group. + - Constraints: The value must match regular expression `/^[0-9a-f]{32}$/`. + - `name` - (String) The user-defined name for this resource group. + - Constraints: The maximum length is `40` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-_ ]+$/`. + - `type` - (String) The crypto-system used by this key. + - Constraints: The default value is `rsa`. Allowable values are: `rsa`. diff --git a/website/docs/d/is_subnet.html.markdown b/website/docs/d/is_subnet.html.markdown index eb6533032..9021976fe 100644 --- a/website/docs/d/is_subnet.html.markdown +++ b/website/docs/d/is_subnet.html.markdown @@ -9,43 +9,53 @@ description: |- # ibm_is_subnet Retrieve information of an existing VPC Generation 2 compute subnet as a read only data source. For more information, about the IBM Cloud subnet, see [attaching subnets to a routing table](https://cloud.ibm.com/docs/vpc?topic=vpc-attach-subnets-routing-table). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage Example to retrieve the subnet information by using subnet name. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "test_subnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - ipv4_cidr_block = "192.168.0.0/1" + ipv4_cidr_block = "10.240.0.0/24" } -data "ibm_is_subnet" "ds_subnet" { - name = ibm_is_subnet.testacc_subnet.name +data "ibm_is_subnet" "example" { + name = ibm_is_subnet.example.name } ``` // Example to retrieve the subnet information by using subnet ID. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "test-subnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - ipv4_cidr_block = "192.168.0.0/1" + ipv4_cidr_block = "10.240.0.0/24" } -data "ibm_is_subnet" "ds_subnet" { - identifier = ibm_is_subnet.testacc_subnet.id +data "ibm_is_subnet" "example" { + identifier = ibm_is_subnet.example.id } ``` @@ -53,8 +63,8 @@ data "ibm_is_subnet" "ds_subnet" { ## Argument reference Review the argument references that you can specify for your data source. -- `identifier` - (Optional, String) The ID of the subnet. -- `name` - (Optional, String) The name of the subnet. +- `identifier` - (Optional, String) The ID of the subnet,`name` and `identifier` are mutually exclusive. +- `name` - (Optional, String) The name of the subnet,`name` and `identifier` are mutually exclusive. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. @@ -62,12 +72,24 @@ In addition to all argument reference list, you can access the following attribu - `access_tags` - (String) Access management tags associated for the instance. - `available_ipv4_address_count` - (Integer) The total number of available IPv4 addresses. - `crn` - (String) The CRN of subnet. +- `id` - (String) The unique ID of the subnet. - `ipv4_cidr_block` - (String) The IPv4 range of the subnet. - `ip_version` - (String) The IP version. - `name` - (String) The name of the subnet. - `network_acl` - (String) The ID of the network ACL for the subnet. - `public_gateway` - (String) The ID of the public gateway for the subnet. - `resource_group` - (String) The subnet resource group. +- `routing_table` - (List) The routing table for this subnet. + + Nested scheme for `routing_table`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this routing table. + - `id` - (String) The unique identifier for this routing table. + - `name` - (String) The user-defined name for this routing table. + - `resource_type` - (String) The type of resource referenced. - `status` - (String) The status of the subnet. - `tags` - (String) Tags associated for the instance. - `total_ipv4_address_count` - (Integer) The total number of IPv4 addresses. diff --git a/website/docs/d/is_subnet_reserved_ip.html.markdown b/website/docs/d/is_subnet_reserved_ip.html.markdown index 96667084b..5f2c2dd72 100644 --- a/website/docs/d/is_subnet_reserved_ip.html.markdown +++ b/website/docs/d/is_subnet_reserved_ip.html.markdown @@ -7,14 +7,25 @@ description: |- --- # ibm_is_subnet_reserved_ip -Retrieve information of an existing reserved IP in a subnet. For more information, about associated reserved IP subnet, see [binding and unbinding a reserved IP address](https://cloud.ibm.com/docs/vpc?topic=vpc-bind-unbind-reserved-ip). +Retrieve information of an existing reserved IP in a subnet as a read only data source. For more information, about associated reserved IP subnet, see [binding and unbinding a reserved IP address](https://cloud.ibm.com/docs/vpc?topic=vpc-bind-unbind-reserved-ip). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_subnet_reserved_ip" "data_reserved_ip" { - subnet = ibm_is_subnet.test_subnet.id - reserved_ip = ibm_is_subnet_reserved_ip.resource_res_ip.reserved_ip +data "ibm_is_subnet_reserved_ip" "example" { + subnet = ibm_is_subnet.example.id + reserved_ip = ibm_is_subnet_reserved_ip.example.reserved_ip } ``` @@ -31,6 +42,7 @@ In addition to all argument reference list, you can access the following attribu - `created_at` - (String) The creation timestamp for the reserved IP. - `href` - (String) The unique reference for the reserved IP. - `id` - (String) The ID for the reserved IP. +- `lifecycle_state` - (String) The lifecycle state of the reserved IP. [ deleting, failed, pending, stable, suspended, updating, waiting ] - `name` - (String) The name for the reserved IP. - `owner` - (String) The owner of the reserved IP. - `reserved_ip` - (String) The ID for the reserved IP. diff --git a/website/docs/d/is_subnet_reserved_ips.html.markdown b/website/docs/d/is_subnet_reserved_ips.html.markdown index 06c787c83..907ca5eda 100644 --- a/website/docs/d/is_subnet_reserved_ips.html.markdown +++ b/website/docs/d/is_subnet_reserved_ips.html.markdown @@ -7,13 +7,24 @@ description: |- --- # ibm_is_subnet_reserved_ips -Retrieve information about a reserved IP in a subnet. For more information, about associated reserved IP subnet, see [binding and unbinding a reserved IP address](https://cloud.ibm.com/docs/vpc?topic=vpc-bind-unbind-reserved-ip). +Retrieve information about a reserved IP in a subnet as a read only data source. For more information, about associated reserved IP subnet, see [binding and unbinding a reserved IP address](https://cloud.ibm.com/docs/vpc?topic=vpc-bind-unbind-reserved-ip). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_subnet_reserved_ips" "data_reserved_ips" { - subnet = ibm_is_subnet.test_subnet.id +data "ibm_is_subnet_reserved_ips" "example" { + subnet = ibm_is_subnet.example.id } ``` @@ -25,8 +36,6 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. -- `id` - (String) The ID for the all the reserved ID in current timestamp format. -- `limit` - (String) The number of reserved IPs to list. - `reserved_ips` - (List) The collection of all the reserved IPs in the subnet. Nested scheme for `reserved_ips`: @@ -34,11 +43,11 @@ In addition to the argument reference list, you can access the following attribu - `auto_delete` - (String) If reserved IP shall be deleted automatically. - `created_at` - (String) The date and time that the reserved IP was created. - `href` - (String) The URL for this reserved IP. + - `lifecycle_state` - (String) The lifecycle state of the reserved IP. [ deleting, failed, pending, stable, suspended, updating, waiting ] - `reserved_ip` - (String) The unique identifier for this reserved IP. - `name` - (String) The user defined or system provided name for this reserved IP. - `owner` - (String) The owner of a reserved IP, defining whether it is managed by the user or the provider. - `resource_type` - (String) The resource type. - `sort` - (String) The keyword on which all the reserved IPs are sorted. - `subnet` - (String) The ID for the subnet for the reserved IP. -- `total_count` - (String) The number of reserved IP in the subnet. diff --git a/website/docs/d/is_subnets.html.markdown b/website/docs/d/is_subnets.html.markdown index 846173bb1..b85935f8c 100644 --- a/website/docs/d/is_subnets.html.markdown +++ b/website/docs/d/is_subnets.html.markdown @@ -7,50 +7,61 @@ description: |- --- # ibm_is_subnets -Retrieve information about of an existing VPC subnets in an IBM Cloud account. For more information, about infrastructure subnets, see [attaching subnets to a routing table](https://cloud.ibm.com/docs/vpc?topic=vpc-attach-subnets-routing-table). +Retrieve information about of an existing VPC subnets in an IBM Cloud account as a read only data source. For more information, about infrastructure subnets, see [attaching subnets to a routing table](https://cloud.ibm.com/docs/vpc?topic=vpc-attach-subnets-routing-table). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage -```hcl -data "ibm_resource_group" "resourceGroup" { +```terraform +data "ibm_resource_group" "example" { name = "Default" } -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_routing_table" "test_cr_route_table1" { - name = "test-cr-route-table1" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_vpc_routing_table" "example" { + name = "example-vpc-routing-table" + vpc = ibm_is_vpc.example.id } -resource "ibm_is_subnet" "testacc_subnet" { - name = "test_subnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - ipv4_cidr_block = "192.168.0.0/1" - routing_table = ibm_is_vpc_routing_table.test_cr_route_table1.routing_table - resource_group = data.ibm_resource_group.resourceGroup.id + ipv4_cidr_block = "10.240.0.0/24" + routing_table = ibm_is_vpc_routing_table.example.routing_table + resource_group = data.ibm_resource_group.example.id } -data "ibm_is_subnets" "ds_subnets_resource_group" { - resource_group = data.ibm_resource_group.resourceGroup.id +data "ibm_is_subnets" "example1" { + resource_group = data.ibm_resource_group.example.id } -data "ibm_is_subnets" "ds_subnets_routing_table_name" { - routing_table_name = ibm_is_vpc_routing_table.test_cr_route_table1.name +data "ibm_is_subnets" "example2" { + routing_table_name = ibm_is_vpc_routing_table.example.name } -data "ibm_is_subnets" "ds_subnets_routing_table" { - routing_table = ibm_is_vpc_routing_table.test_cr_route_table1.id +data "ibm_is_subnets" "example3" { + routing_table = ibm_is_vpc_routing_table.example.id } -data "ibm_is_subnets" "ds_subnets" { +data "ibm_is_subnets" "example4" { } ``` -## Argument Reference +## Argument reference Review the argument references that you can specify for your data source. @@ -72,8 +83,17 @@ You can access the following attribute references after your data source is crea - `name` - (String) The name of the subnet. - `network_acl` - (String) The access control list (ACL) that is attached to the subnet. - `public_gateway`- (Bool) If set to **true**, a public gateway is attached to the subnet. If set to **false**, no public gateway for this subnet exists. - - `resource_group` - (String) The resource group that the subnet belongs to. + - `resource_group` - (String) The resource group id, that the subnet belongs to. - `total_ipv4_address_count`- (Integer) The total number of IPv4 addresses in the subnet. - `status` - (String) The status of the subnet. + - `routing_table` - (List) The routing table for this subnet. + Nested scheme for `routing_table`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this routing table. + - `id` - (String) The unique identifier for this routing table. + - `name` - (String) The user-defined name for this routing table. + - `resource_type` - (String) The type of resource referenced. - `vpc` - (String) The ID of the VPC that this subnet belongs to. - `zone` - (String) The zone where the subnet was created. diff --git a/website/docs/d/is_virtual_endpoint_gateway.html.markdown b/website/docs/d/is_virtual_endpoint_gateway.html.markdown index 55786299d..007c7403a 100644 --- a/website/docs/d/is_virtual_endpoint_gateway.html.markdown +++ b/website/docs/d/is_virtual_endpoint_gateway.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_virtual_endpoint_gateway Retrieve information of an existing IBM Cloud Infrastructure virtual endpoint gateway as a read-only data source. For more information, about the VPC endpoint gateway, see [creating an endpoint gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-endpoint-gateway). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_virtual_endpoint_gateway" "data_test" { - name = ibm_is_virtual_endpoint_gateway.endpoint_gateway.name +data "ibm_is_virtual_endpoint_gateway" "example" { + name = ibm_is_virtual_endpoint_gateway.example.name } ``` @@ -43,4 +54,6 @@ In addition to the argument reference list, you can access the following attribu - `name` - (String) The target name. - `resource_type` - (String) The resource type of the subnet reserved IP. - `vpc` - (String) The VPC ID. +- `security_groups` (List) - The security groups to use for this endpoint gateway. + diff --git a/website/docs/d/is_virtual_endpoint_gateway_ips.html.markdown b/website/docs/d/is_virtual_endpoint_gateway_ips.html.markdown index c7f9dcd4b..534ae5289 100644 --- a/website/docs/d/is_virtual_endpoint_gateway_ips.html.markdown +++ b/website/docs/d/is_virtual_endpoint_gateway_ips.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_virtual_endpoint_gateway_ips Retrieve information of an existing IBM Cloud infrastructure virtual endpoint gateway IPs as a read only data source. For more information, about the VPC endpoint gateways, see [about VPC gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-about-vpe). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_virtual_endpoint_gateway_ips" "data_test1" { - gateway = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id +data "ibm_is_virtual_endpoint_gateway_ips" "example" { + gateway = ibm_is_virtual_endpoint_gateway.example.id } ``` diff --git a/website/docs/d/is_virtual_endpoint_gateways.html.markdown b/website/docs/d/is_virtual_endpoint_gateways.html.markdown index 747b71229..a8345022f 100644 --- a/website/docs/d/is_virtual_endpoint_gateways.html.markdown +++ b/website/docs/d/is_virtual_endpoint_gateways.html.markdown @@ -9,10 +9,21 @@ description: |- # ibm_is_virtual_endpoint_gateways Retrieve information of an existing IBM Cloud infrastructure virtual endpoint gateways as a read-only data source. For more information, about the VPC endpoint gateways, see [creating an endpoint gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-endpoint-gateway). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_virtual_endpoint_gateways" "data_test" { +data "ibm_is_virtual_endpoint_gateways" "example" { } ``` @@ -42,3 +53,4 @@ In addition to the argument reference list, you can access the following attribu - `name` - (String) The endpoint gateway target name. - `resource_type` - (String) The endpoint gateway target resource type. - `vpc` - (String) The VPC ID. + - `security_groups` (List) - The security groups to use for this endpoint gateway. diff --git a/website/docs/d/is_volume.html.markdown b/website/docs/d/is_volume.html.markdown index 39f300444..2e14fd098 100644 --- a/website/docs/d/is_volume.html.markdown +++ b/website/docs/d/is_volume.html.markdown @@ -9,17 +9,27 @@ description: |- # ibm_is_volume Retrieve information of an existing IBM Cloud VSI volume. For more information, about the volume concepts, see [expandable volume concepts for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-expanding-block-storage-volumes#expandable-volume-concepts). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_volume" "testacc_volume"{ - name = "testvol" - profile = "10iops-tier" - zone = "us-south-1" +resource "ibm_is_volume" "example" { + name = "example-volume" + profile = "10iops-tier" + zone = "us-south-1" } -data "ibm_is_volume" "testacc_dsvol" { - name = ibm_is_volume.testacc_volume.name +data "ibm_is_volume" "example" { + name = ibm_is_volume.example.name } ``` @@ -33,6 +43,7 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. +- `bandwidth` - The maximum bandwidth (in megabits per second) for the volume - `capacity` - (String) The capacity of the volume in gigabytes. - `crn` - (String) The crn of this volume. - `encryption_key` - (String) The key to use for encrypting this volume. @@ -47,4 +58,5 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `status_reasons`: - `code` - (String) A snake case string identifying the status reason. - `message` - (String) An explanation of the status reason -- `tags` - (String) Tags associated with the volume. + - `more_info` - (String) Link to documentation about this status reason +- `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) diff --git a/website/docs/d/is_volume_profile.html.markdown b/website/docs/d/is_volume_profile.html.markdown index 55de4c4e5..8cdf6c968 100644 --- a/website/docs/d/is_volume_profile.html.markdown +++ b/website/docs/d/is_volume_profile.html.markdown @@ -9,12 +9,22 @@ description: |- # ibm_is_volume_profile Retrieve information of an existing IBM Cloud virtual server volume profile as a read-only data source. For more information, about virtual server volume profile, see [restoring a volume from a snapshot](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-restore). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example Usage +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage ```terraform -data "ibm_is_volume_profile" "volprofile"{ +data "ibm_is_volume_profile" "example" { name = "general-purpose" } diff --git a/website/docs/d/is_volume_profiles.html.markdown b/website/docs/d/is_volume_profiles.html.markdown index 433c0b26f..77efa299f 100644 --- a/website/docs/d/is_volume_profiles.html.markdown +++ b/website/docs/d/is_volume_profiles.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_volume_profiles Retrieve information of an existing IBM Cloud VSI. For more information, about the volumes and profiles, see [block storage profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-block-storage-profiles). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_volume_profiles" "volprofiles"{ +data "ibm_is_volume_profiles" "example" { } ``` diff --git a/website/docs/d/is_volumes.html.markdown b/website/docs/d/is_volumes.html.markdown new file mode 100644 index 000000000..62e35ad22 --- /dev/null +++ b/website/docs/d/is_volumes.html.markdown @@ -0,0 +1,140 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_volumes" +description: |- + Get information about VolumeCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_volumes + +Provides a read-only data source for VolumeCollection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_volumes" "example" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VolumeCollection. +- `volumes` - (List) Collection of volumes. + Nested scheme for **volumes**: + - `active` - (Boolean) Indicates whether a running virtual server instance has an attachment to this volume. + - `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume. + - `busy` - (Boolean) Indicates whether this volume is performing an operation that must be serialized. If an operation specifies that it requires serialization, the operation will fail unless this property is `false`. + - `capacity` - (Integer) The capacity to use for the volume (in gigabytes). The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. + - Constraints: The minimum value is `1`. + - `created_at` - (String) The date and time that the volume was created. + - `crn` - (String) The CRN for this volume. + - `encryption` - (String) The type of encryption used on the volume. + - Constraints: The default value is `provider_managed`. Allowable values are: `provider_managed`, `user_managed`. + - `encryption_key` - (Optional, List) The root key used to wrap the data encryption key for the volume.This property will be present for volumes with an `encryption` type of`user_managed`. + Nested scheme for **encryption_key**: + - `crn` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. + - `href` - (String) The URL for this volume. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this volume. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `iops` - (Integer) The maximum I/O operations per second (IOPS) to use for the volume. Applicable only to volumes using a profile `family` of `custom`. + - `name` - (String) The unique user-defined name for this volume. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `operating_system` - (Optional, List) The operating system associated with this volume. If absent, this volume was notcreated from an image, or the image did not include an operating system. + Nested scheme for **operating_system**: + - `href` - (String) The URL for this operating system. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `name` - (String) The globally unique name for this operating system. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `profile` - (List) The profile this volume uses. + Nested scheme for **profile**: + - `href` - (String) The URL for this volume profile. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `name` - (String) The globally unique name for this volume profile. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `resource_group` - (List) The resource group object, for this volume. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this resource group. + - Constraints: The value must match regular expression `/^[0-9a-f]{32}$/`. + - `name` - (String) The user-defined name for this resource group. + - Constraints: The maximum length is `40` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-_ ]+$/`. + - `source_image` - (Optional, List) The image from which this volume was created (this may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).If absent, this volume was not created from an image. + Nested scheme for **source_image**: + - `crn` - (String) The CRN for this image. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (String) The URL for this image. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this image. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (String) The user-defined or system-provided name for this image. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `source_snapshot` - (Optional, List) The snapshot from which this volume was cloned. + Nested scheme for **source_snapshot**: + - `crn` - (String) The CRN for this snapshot. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (String) The URL for this snapshot. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this snapshot. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (String) The user-defined name for this snapshot. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: `snapshot`. + - `status` - (String) The status of the volume.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the volume on which the unexpected property value was encountered. + - Constraints: Allowable values are: `available`, `failed`, `pending`, `pending_deletion`, `unusable`. + - `status_reasons` - (List) The reasons for the current status (if any).The enumerated reason code values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected reason code was encountered. + Nested scheme for **status_reasons**: + - `code` - (String) A snake case string succinctly identifying the status reason. + - Constraints: Allowable values are: `encryption_key_deleted`. The value must match regular expression `/^[a-z]+(_[a-z]+)*$/`. + - `message` - (String) An explanation of the status reason. + - `more_info` - (Optional, String) Link to documentation about this status reason. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) + - `volume_attachments` - (List) The volume attachments for this volume. + Nested scheme for **volume_attachments**: + - `delete_volume_on_instance_delete` - (Boolean) If set to true, when deleting the instance the volume will also be deleted. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `device` - (Optional, List) Information about how the volume is exposed to the instance operating system.This property may be absent if the volume attachment's `status` is not `attached`. + Nested scheme for **device**: + - `id` - (Optional, String) A unique identifier for the device which is exposed to the instance operating system. + - `href` - (String) The URL for this volume attachment. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this volume attachment. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `instance` - (List) The attached instance. + Nested scheme for **instance**: + - `crn` - (String) The CRN for this virtual server instance. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (String) The URL for this virtual server instance. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this virtual server instance. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (String) The user-defined name for this virtual server instance (and default system hostname). + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `name` - (String) The user-defined name for this volume attachment. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `type` - (String) The type of volume attachment. + - Constraints: Allowable values are: `boot`, `data`. + - `zone` - (List) The zone this volume resides in. + Nested scheme for **zone**: + - `name` - (String) The globally unique name for this zone. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + diff --git a/website/docs/d/is_vpc.html.markdown b/website/docs/d/is_vpc.html.markdown index f448d941f..a76151da3 100644 --- a/website/docs/d/is_vpc.html.markdown +++ b/website/docs/d/is_vpc.html.markdown @@ -7,26 +7,37 @@ description: |- --- # ibm_is_vpc -Retrieve information of an existing IBM Virtual Private cloud as a read-only data source. For more information, about VPC, see [getting started with Virtual Private Cloud (VPC)](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). +Retrieve information of an existing IBM Virtual Private cloud. For more information, about VPC, see [getting started with Virtual Private Cloud (VPC)](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example usage +**provider.tf** ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +provider "ibm" { + region = "eu-gb" } +``` + +## Example usage -data "ibm_is_vpc" "ds_vpc" { - name = "test" +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } +data "ibm_is_vpc" "example" { + name = "example-vpc" +} ``` ## Argument reference Review the argument references that you can specify for your data source. -- `name` - (Required, String) The name of the VPC. +~> **Note:** `name` and `identifier` are mutually exclusive. One of them is required. +- `name` - (Optional, String) The name of the VPC. +- `identifier` - (Optional, String) The id of the VPC. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/is_vpc_address_prefix.html.markdown b/website/docs/d/is_vpc_address_prefix.html.markdown new file mode 100644 index 000000000..df61af78a --- /dev/null +++ b/website/docs/d/is_vpc_address_prefix.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpc_address_prefix" +description: |- + Get information about VPC Address Prefix +--- + +# ibm_is_vpc_address_prefix + +Provides a read-only data source for VPC Address Prefix. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_vpc_address_prefix" "example" { + vpc = ibm_is_vpc.example.id + address_prefix = ibm_is_vpc_address_prefix.example.address_prefix +} +data "ibm_is_vpc_address_prefix" "example-1" { + vpc_name = ibm_is_vpc.example.name + address_prefix = ibm_is_vpc_address_prefix.example.address_prefix +} +data "ibm_is_vpc_address_prefix" "example-2" { + vpc = ibm_is_vpc.example.id + address_prefix_name = ibm_is_vpc_address_prefix.example.name +} +data "ibm_is_vpc_address_prefix" "example-3" { + vpc_name = ibm_is_vpc.example.name + address_prefix_name = ibm_is_vpc_address_prefix.example.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `address_prefix` - (String) The address prefix identifier. +- `address_prefix_name` - (String) The address prefix name. + +~> **Note:** + Provide exactly one of `address_prefix`, `address_prefix_name` + +- `vpc` - (String) The VPC identifier +- `vpc_name` - (String) Name of the VPC + + ~> **Note:** + Provide exactly one of `vpc`, `vpc_name` + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - (String) The unique identifier of the AddressPrefix. +- `cidr` - (String) The CIDR block for this prefix. + +- `created_at` - (String) The date and time that the prefix was created. + +- `has_subnets` - (Boolean) Indicates whether subnets exist with addresses from this prefix. + +- `href` - (String) The URL for this address prefix. + +- `is_default` - (Boolean) Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name. + +- `name` - (String) The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in. + +- `zone` - (List) The zone this address prefix resides in. + Nested scheme for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_vpc_address_prefixes.html.markdown b/website/docs/d/is_vpc_address_prefixes.html.markdown index 170d032a8..1fb330a08 100644 --- a/website/docs/d/is_vpc_address_prefixes.html.markdown +++ b/website/docs/d/is_vpc_address_prefixes.html.markdown @@ -1,22 +1,32 @@ --- subcategory: "VPC infrastructure" layout: "ibm" -page_title: "IBM : is_vpc_address_prefix" +page_title: "IBM : is_vpc_address_prefixes" description: |- Get information about VPC address prefixes --- -# ibm_is_vpc_address_prefix +# ibm_is_vpc_address_prefixes Retrieve information of an existing IBM Cloud address prefix collection. For more information, about VPC address prefix, see [address prefixes](https://cloud.ibm.com/docs/vpc?topic=vpc-vpc-behind-the-curtain#address-prefixes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_vpc_address_prefixes" "is_vpc_address_prefix_name" { - vpc = "r134-b5938d43-cb2f-4666-bc99-9410863ed305" - name = "outsider-sense-motor-chomp" +data "ibm_is_vpc_address_prefixes" "example" { + vpc = ibm_is_vpc.example.id + name = "example-address-prefix" } ``` @@ -31,19 +41,19 @@ In addition to all argument reference list, you can access the following attribu - `address_prefixes` - (List) Collection of the address prefixes. -Nested `address_prefixes` blocks have the following structure: -- `created_at` - (Timestamp) The date and time that the prefix was created. -- `cidr` - (String) The CIDR block for this prefix. -- `has_subnets` - (String) Indicates whether subnets exist with addresses from this prefix. -- `href` - (String) The URL for this address prefix. -- `id` - (String) The unique identifier for this address prefix. -- `is_default` - (String) Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name. -- `name` - (String) The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in. -- `zone` - (List) The zone this address prefix resides in. - -Nested `zone` blocks have the following structure: -- `href` - (String) The URL for this zone. -- `name` - (String) The globally unique name for this zone. - -- `id` - (String) The unique identifier of the AddressPrefixCollection. -- `total_count` - (String) The total number of resources across all pages. \ No newline at end of file + Nested `address_prefixes` blocks have the following structure: + - `created_at` - (Timestamp) The date and time that the prefix was created. + - `cidr` - (String) The CIDR block for this prefix. + - `has_subnets` - (String) Indicates whether subnets exist with addresses from this prefix. + - `href` - (String) The URL for this address prefix. + - `id` - (String) The unique identifier for this address prefix. + - `is_default` - (String) Indicates whether this is the default prefix for this zone in this VPC. If a default prefix was automatically created when the VPC was created, the prefix is automatically named using a hyphenated list of randomly-selected words, but may be updated with a user-specified name. + - `name` - (String) The user-defined name for this address prefix. Names must be unique within the VPC the address prefix resides in. + - `zone` - (List) The zone this address prefix resides in. + + Nested `zone` blocks have the following structure: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + + - `id` - (String) The unique identifier of the AddressPrefixCollection. + - `total_count` - (String) The total number of resources across all pages. \ No newline at end of file diff --git a/website/docs/d/is_vpc_default_routing_table.html.markdown b/website/docs/d/is_vpc_default_routing_table.html.markdown index a648ce921..da3f92526 100644 --- a/website/docs/d/is_vpc_default_routing_table.html.markdown +++ b/website/docs/d/is_vpc_default_routing_table.html.markdown @@ -9,19 +9,27 @@ description: |- # ibm_is_vpc_default_routing_table Retrieve information of an existing IBM Cloud Infrastructure Virtual Pricate Cloud default routing table as a read-only data source. For more information, about VPC default routing table, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example usage +**provider.tf** ```terraform - -resource "ibm_is_vpc" "test_vpc" { - name = "test-vpc" +provider "ibm" { + region = "eu-gb" } +``` -data "ibm_is_vpc_default_routing_table" "ds_default_routing_table" { - vpc = ibm_is_vpc.test_vpc.id +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } +data "ibm_is_vpc_default_routing_table" "example" { + vpc = ibm_is_vpc.example.id +} ``` ## Argument reference @@ -33,9 +41,9 @@ Review the argument references that you can specify for your data source. In addition to the argument reference list, you can access the following attribute references after your data source is created. - `created_at` - (Timestamp) The date and time that the default routing table was created. -- `default_routing_table` - (String) The unique identifier for the default routing table. +- `default_routing_table` - (String) The unique identifier for this routing table. - `href` - (String) The routing table URL. -- `id` - (String) The unique ID for the default routing table. +- `id` - (String) The unique identifier for this routing table. Same as `default_routing_table`. - `is_default` - (String) Indicates the default routing table for this VPC. - `lifecycle_state` - (String) The lifecycle state of the routing table. - `name` - (String) The name for the default routing table. diff --git a/website/docs/d/is_vpc_routing_table.html.markdown b/website/docs/d/is_vpc_routing_table.html.markdown new file mode 100644 index 000000000..29cd50b4c --- /dev/null +++ b/website/docs/d/is_vpc_routing_table.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_vpc_routing_table" +description: |- + Get information about RoutingTable +--- + +# ibm_is_vpc_routing_table + +Provides a read-only data source for RoutingTable. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about VPC routing tables, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes) + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage (using routing table id) +```terraform +data "ibm_is_vpc_routing_table" "example_routing_table" { + vpc = ibm_is_vpc.example_vpc.id + routing_table = ibm_is_vpc_routing_table.example_rt.routing_table +} +``` + +## Example Usage (using routing table name) +```terraform +data "ibm_is_vpc_routing_table" "example_routing_table_name" { + vpc = ibm_is_vpc.example_vpc.id + name = ibm_is_vpc_routing_table.example_rt.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `name` - (Optional, String) The VPC routing table name. Mutually exclusive with `routing_table`, one of them is required +- `routing_table` - (Optional, String) The VPC routing table identifier. Mutually exclusive with `name`, one of them is required +- `vpc` - (Required, String) The VPC identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `accept_routes_from` - (List) The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future. + Nested scheme for **accept_routes_from**: + - `resource_type` - (String) The resource type. +- `created_at` - (String) The date and time that this routing table was created. +- `href` - (String) The URL for this routing table. +- `id` - (String) The unique identifier of the RoutingTable. +- `is_default` - (Boolean) Indicates whether this is the default routing table for this VPC. +- `lifecycle_state` - (String) The lifecycle state of the routing table. + - Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `name` - (String) The user-defined name for this routing table. +- `resource_type` - (String) The resource type. +- `route_direct_link_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from [Direct Link](https://cloud.ibm.com/docs/dl/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped. +- `route_transit_gateway_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from from [Transit Gateway](https://cloud.ibm.com/cloud/transit-gateway/) to this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped. +- `route_vpc_zone_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from subnets in other zones in this VPC.Incoming traffic will be routed according to the routing table with one exception: routes with an `action` of `deliver` are treated as `drop` unless the `next_hop` is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a `next_hop` of an internet-bound IP address or a VPN gateway connection, the packet will be dropped. +- `routes` - (List) The routes for this routing table. + Nested scheme for **routes**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this route. + - `id` - (String) The unique identifier for this route. + - `name` - (String) The user-defined name for this route. +- `subnets` - (List) The subnets to which this routing table is attached. + Nested scheme for **subnets**: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. \ No newline at end of file diff --git a/website/docs/d/is_vpc_routing_table_route.html.markdown b/website/docs/d/is_vpc_routing_table_route.html.markdown new file mode 100644 index 000000000..98569eb7a --- /dev/null +++ b/website/docs/d/is_vpc_routing_table_route.html.markdown @@ -0,0 +1,100 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_vpc_routing_table_route" +description: |- + Get information about VPC routing table route. +--- + +# ibm_is_vpc_routing_table_route + +Provides a read-only data source for Route. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax.For more information, about VPC default routing table, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage (using route id) + +```terraform +data "ibm_is_vpc_routing_table_route" "example_route" { + vpc = ibm_is_vpc.example_vpc.id + routing_table = ibm_is_vpc_routing_table.example_rt.routing_table + route_id = ibm_is_vpc_routing_table_route.example_route.route_id +} +``` + +## Example Usage (using route name) +```terraform +data "ibm_is_vpc_routing_table_route" "example_route_name" { + vpc = ibm_is_vpc.example_vpc.id + routing_table = ibm_is_vpc_routing_table.example_rt.routing_table + name = ibm_is_vpc_routing_table_route.example_route.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `name` - (Optional, String) The VPC routing table name. Mutually exclusive with `routing_table`, one of them is required +- `route_id` - (Required, String) The VPC routing table route identifier. +- `routing_table` - (Optional, String) The VPC routing table identifier. Mutually exclusive with `name`, one of them is required +- `vpc` - (Required, String) The VPC identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `action` - (String) The action to perform with a packet matching the route, allowable values are: `delegate`, `delegate_vpc`, `deliver`, `drop`. + - `delegate`: delegate to the system's built-in routes + - `delegate_vpc`: delegate to the system's built-in routes, ignoring Internet-bound routes + - `deliver`: deliver the packet to the specified `next_hop` + - `drop`: drop the packet. +- `created_at` - (String) The date and time that the route was created. +- `creator` - (List) If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set. +Nested scheme for **creator**: + - `crn` - (String) The VPN gateway's CRN. + - Constraints: The maximum length is `512` characters. The minimum length is `9` characters. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (String) The VPN gateway's canonical URL. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this VPN gateway. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (String) The user-defined name for this VPN gateway. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: `vpn_gateway`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. +- `destination` - (String) The destination of the route. +- `href` - (String) The URL for this route. +- `id` - (String) The unique identifier of the Route. +- `lifecycle_state` - (String) The lifecycle state of the route. + - Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `name` - (String) The user-defined name for this route. +- `next_hop` - (List) If `action` is `deliver`, the next hop that packets will be delivered to. For other `action` values, its `address` will be `0.0.0.0`. + Nested scheme for **next_hop**: + - `address` - (String) The IP address.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. + +- `origin` - (String) The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + - Constraints: Allowable values are: `learned`, `service`, `user`. +- `zone` - (List) The zone the route applies to. (Traffic from subnets in this zone will be subject to this route). + Nested scheme for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. diff --git a/website/docs/d/is_vpc_routing_table_routes.html.markdown b/website/docs/d/is_vpc_routing_table_routes.html.markdown index 6877168f8..67e0a706c 100644 --- a/website/docs/d/is_vpc_routing_table_routes.html.markdown +++ b/website/docs/d/is_vpc_routing_table_routes.html.markdown @@ -9,26 +9,34 @@ description: |- # ibm_is_vpc_routing_table_routes Retrieve information of an existing IBM Cloud Infrastructure Virtual Private Cloud routing table routes as a read-only data source. For more information, about VPC default routing table, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example usage +**provider.tf** ```terraform +provider "ibm" { + region = "eu-gb" +} +``` -resource "ibm_is_vpc" "test_vpc" { - name = "test-vpc" +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_routing_table" "test_routing_table" { - name = "test-routing-table" - vpc = ibm_is_vpc.test_vpc.id +resource "ibm_is_vpc_routing_table" "example" { + name = "example-routing-table" + vpc = ibm_is_vpc.example.id } -data "ibm_is_vpc_routing_table_routes" "ds_routing_table_routes" { - vpc = ibm_is_vpc.test_vpc.id - routing_table = ibm_is_vpc_routing_tables.test_routing_table.routing_table +data "ibm_is_vpc_routing_table_routes" "example" { + vpc = ibm_is_vpc.example.id + routing_table = ibm_is_vpc_routing_tables.example.routing_table } - ``` ## Argument reference Review the argument references that you can specify for your data source. @@ -39,15 +47,33 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `routing_table_routes` (List) List of all the routing table in a VPC. +- `routes` (List) List of all the routing table in a VPC. - Nested scheme for `routing_table_routes`: + Nested scheme for `routes`: - `name` - (String) The name for the default routing table. - `route_id` - (String) The unique ID for the route. - `lifecycle_state` - (String) The lifecycle state of the route. - `href` - (String) The routing table URL. -- `created_at` - (Timestamp) The date and time that the route was created. + - `created_at` - (Timestamp) The date and time that the route was created. + - `creator` - (List) If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set. + Nested scheme for **creator**: + - `crn` - (String) The VPN gateway's CRN. + - Constraints: The maximum length is `512` characters. The minimum length is `9` characters. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (String) The VPN gateway's canonical URL. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (String) The unique identifier for this VPN gateway. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (String) The user-defined name for this VPN gateway. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: `vpn_gateway`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. - `action` - (String) The action to perform with a packet matching the route. - `destination` - (String) The destination of the route. - `next_hop` - (String) The next hop address of the route. + - `origin` - (String) The origin of this route:- `service`: route was directly created by a service - `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + - Constraints: Allowable values are: `learned`, `service`, `user`. - `zone` - (String) The zone name of the route. diff --git a/website/docs/d/is_vpc_routing_tables.html.markdown b/website/docs/d/is_vpc_routing_tables.html.markdown index 432206eef..e96ce7ec8 100644 --- a/website/docs/d/is_vpc_routing_tables.html.markdown +++ b/website/docs/d/is_vpc_routing_tables.html.markdown @@ -9,22 +9,30 @@ description: |- # ibm_is_vpc_routing_tables Retrieve information of an existing IBM Cloud infrastructure VPC default routing tables. For more information, about VPC routing tables, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes) +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example usage +**provider.tf** ```terraform - -resource "ibm_is_vpc" "test_vpc" { - name = "test-vpc" +provider "ibm" { + region = "eu-gb" } +``` + +## Example usage -data "ibm_is_vpc_routing_tables" "ds_routing_tables" { - vpc = ibm_is_vpc.test_vpc.id +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } +data "ibm_is_vpc_routing_tables" "example" { + vpc = ibm_is_vpc.example.id +} ``` -# + ## Argument reference Review the argument references that you can specify for your data source. @@ -36,6 +44,9 @@ In addition to the argument reference list, you can access the following attribu - `routing_tables` (List) List of all the routing tables in a VPC. Nested scheme for `routing_tables`: + - `accept_routes_from` - (List) The filters specifying the resources that may create routes in this routing table.At present, only the `resource_type` filter is permitted, and only the `vpn_gateway` value is supported, but filter support is expected to expand in the future. + Nested scheme for **accept_routes_from**: + - `resource_type` - (String) The resource type. - `created_at` - (Timestamp) The date and time the routing table was created. - `href` - (String) The routing table URL. - `is_default` - (String) Indicates whether the default routing table. @@ -46,13 +57,11 @@ In addition to the argument reference list, you can access the following attribu - `route_direct_link_ingress` - (String) Indicates if the routing table is used to route traffic that originates from Direct Link to the VPC. - `route_transit_gateway_ingress` - (String) Indicates if the routing table is used to route traffic that originates from Transit Gateway to the VPC. - `route_vpc_zone_ingress` - (String) Indicates if the routing table is used to route traffic that originates from subnets in other zones of the VPC. -- `routes` - (List) The routes for the routing table. - - Nested scheme for `routes`: - - `id` - (String) The unique ID of the route. - - `name`- (String) The user-defined name of the route. -- `subnets` - (List) The subnets to which routing table is attached. - - Nested scheme for `subnets`: - - `id` - (String) The unique ID of the subnet. - - `name` - (String) The user-defined name of the subnet. + - `routes` - (List) The routes for the routing table. + Nested scheme for `routes`: + - `id` - (String) The unique ID of the route. + - `name`- (String) The user-defined name of the route. + - `subnets` - (List) The subnets to which routing table is attached. + Nested scheme for `subnets`: + - `id` - (String) The unique ID of the subnet. + - `name` - (String) The user-defined name of the subnet. diff --git a/website/docs/d/is_vpcs.html.markdown b/website/docs/d/is_vpcs.html.markdown index cb27c4df8..09e72f644 100644 --- a/website/docs/d/is_vpcs.html.markdown +++ b/website/docs/d/is_vpcs.html.markdown @@ -7,17 +7,27 @@ description: |- --- # ibm_is_vpcs -Retrieve a list of existing IBM Virtual Private Cloud as a read-only data source. For more information, about VPC, see [getting started with Virtual Private Cloud (VPC)](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). +Retrieve information of an existing VPCs. For more information, about VPC, see [getting started with Virtual Private Cloud (VPC)](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -data "ibm_is_vpcs" "ds_vpcs" { +data "ibm_is_vpcs" "example" { } ``` diff --git a/website/docs/d/is_vpn_gateway.html.markdown b/website/docs/d/is_vpn_gateway.html.markdown new file mode 100644 index 000000000..b31f6bc25 --- /dev/null +++ b/website/docs/d/is_vpn_gateway.html.markdown @@ -0,0 +1,102 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpn_gateway" +description: |- + Get information about IBM Cloud VPN Gateway +--- + +# ibm_is_vpn_gateway + +Provides a read-only data source for VPN Gateway. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_vpn_gateway" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id +} + +data "ibm_is_vpn_gateway" "example-1" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `vpn_gateway` - (Optional, String) The VPN gateway identifier. +- `vpn_gateway_name` - (Optional, String) The VPN gateway name. + ~> **Note** Provide either `vpn_gateway` or `vpn_gateway_name` + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the is_vpn_gateway. +- `connections` - (List) Connections for this VPN gateway. + Nested scheme for **connections**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The VPN connection's canonical URL. + - `id` - (String) The unique identifier for this VPN gateway connection. + - `name` - (String) The user-defined name for this VPN connection. + - `resource_type` - (String) The resource type. + +- `created_at` - (String) The date and time that this VPN gateway was created. + +- `crn` - (String) The VPN gateway's CRN. + +- `href` - (String) The VPN gateway's canonical URL. + +- `members` - (List) Collection of VPN gateway members. + Nested scheme for **members**: + + - `private_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + Nested scheme for `private_ip`: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `private_ip_address` - (String) The private IP address assigned to the VPN gateway member. This property will be present only when the VPN gateway status is `available`. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. Same as `primary_ip.0.address` + - `public_ip_address` - (String) The public IP address assigned to the VPN gateway member. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `role` - (String) The high availability role assigned to the VPN gateway member. + - `status` - (String) The status of the VPN gateway member. + +- `mode` - (String) Route mode VPN gateway. + +- `name` - (String) The user-defined name for this VPN gateway. + +- `resource_group` - (List) The resource group object, for this VPN gateway. + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. + +- `resource_type` - (String) The resource type. + +- `status` - (String) The status of the VPN gateway. + +- `subnet` - (List) + Nested scheme for **subnet**: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. +- `vpc` - (String) The VPC this VPN server resides in. + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) - The URL for this VPC + - `id` - (String) - The unique identifier for this VPC. + - `name` - (String) - The unique user-defined name for this VPC. +- `resource_type` - (String) - The resource type. + diff --git a/website/docs/d/is_vpn_gateway_connection.html.markdown b/website/docs/d/is_vpn_gateway_connection.html.markdown new file mode 100644 index 000000000..7f62d376d --- /dev/null +++ b/website/docs/d/is_vpn_gateway_connection.html.markdown @@ -0,0 +1,106 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpn_gateway_connection" +description: |- + Get information about IBM Cloud VPN Connection +--- + +# ibm_is_vpn_gateway_connection + +Provides a read-only data source for VPN Connection. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_is_vpn_gateway_connection" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection +} +data "ibm_is_vpn_gateway_connection" "example-1" { + vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name +} +data "ibm_is_vpn_gateway_connection" "example-2" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection +} +data "ibm_is_vpn_gateway_connection" "example-3" { + vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `vpn_gateway` - (Optional, String) The VPN gateway identifier. +- `vpn_gateway_name` - (Optional, String) The VPN gateway name. +- `vpn_gateway_connection` - (Optional, String) The VPN gateway connection identifier. +- `vpn_gateway_connection_name` - (Optional, String) The VPN gateway connection name. + + ~> **Note** Provide either one of `vpn_gateway`, `vpn_gateway_name` to identifiy vpn gateway and either one of `vpn_gateway_connection`, `vpn_gateway_connection_name` to identify vpn gateway connection. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VPN gateway connection. The ID is composed of `/`. +- `admin_state_up` - (Boolean) If set to false, the VPN gateway connection is shut down. + +- `authentication_mode` - (String) The authentication mode. Only `psk` is currently supported. + +- `created_at` - (String) The date and time that this VPN gateway connection was created. + +- `dead_peer_detection` - (List) The Dead Peer Detection settings. + Nested scheme for **dead_peer_detection**: + - `action` - (String) Dead Peer Detection actions. + - `interval` - (Integer) Dead Peer Detection interval in seconds. + - `timeout` - (Integer) Dead Peer Detection timeout in seconds. Must be at least the interval. + +- `href` - (String) The VPN connection's canonical URL. + +- `ike_policy` - (List) The IKE policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#ike-auto-negotiation-phase-1). + Nested scheme for **ike_policy**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The IKE policy's canonical URL. + - `id` - (String) The unique identifier for this IKE policy. + - `name` - (String) The user-defined name for this IKE policy. + - `resource_type` - (String) The resource type. + +- `ipsec_policy` - (List) The IPsec policy. If absent, [auto-negotiation isused](https://cloud.ibm.com/docs/vpc?topic=vpc-using-vpn&interface=ui#ipsec-auto-negotiation-phase-2). + Nested scheme for **ipsec_policy**: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The IPsec policy's canonical URL. + - `id` - (String) The unique identifier for this IPsec policy. + - `name` - (String) The user-defined name for this IPsec policy. + - `resource_type` - (String) The resource type. + +- `local_cidrs` - (List) The local CIDRs for this resource. + +- `mode` - (String) The mode of the VPN gateway. + +- `name` - (String) The user-defined name for this VPN gateway connection. + +- `peer_address` - (String) The IP address of the peer VPN gateway. + +- `peer_cidrs` - (List) The peer CIDRs for this resource. + +- `psk` - (String) The preshared key. + +- `resource_type` - (String) The resource type. + +- `routing_protocol` - (String) Routing protocols are disabled for this VPN gateway connection. + +- `status` - (String) The status of a VPN gateway connection. + +- `tunnels` - (List) The VPN tunnel configuration for this VPN gateway connection (in static route mode). + Nested scheme for **tunnels**: + - `public_ip_address` - (String) The IP address of the VPN gateway member in which the tunnel resides. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `status` - (String) The status of the VPN Tunnel. + diff --git a/website/docs/d/is_vpn_gateway_connections.html.markdown b/website/docs/d/is_vpn_gateway_connections.html.markdown index 8e9e48a94..8fb46c086 100644 --- a/website/docs/d/is_vpn_gateway_connections.html.markdown +++ b/website/docs/d/is_vpn_gateway_connections.html.markdown @@ -9,13 +9,23 @@ description: |- # ibm_is_vpn_gateway_connections Retrieve information of an existing VPN gateway connections. For more information, see [adding connections to a VPN gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-adding-connections). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_vpn_gateway_connections" "ds_vpn_gateway_connections" { - vpn_gateway = ibm_is_vpn_gateway.testacc_vpnGateway.id +data "ibm_is_vpn_gateway_connections" "example" { + vpn_gateway = ibm_is_vpn_gateway.example.id } ``` diff --git a/website/docs/d/is_vpn_gateways.html.markdown b/website/docs/d/is_vpn_gateways.html.markdown index a50305c37..f6ff8a6d2 100644 --- a/website/docs/d/is_vpn_gateways.html.markdown +++ b/website/docs/d/is_vpn_gateways.html.markdown @@ -9,13 +9,22 @@ description: |- # ibm_is_vpn_gateways Retrieve information of an existing VPN gateways. For more information, about IBM Cloud VPN gateways, see [configuring ACLs and security groups for use with VPN](https://cloud.ibm.com/docs/vpc?topic=vpc-acls-security-groups-vpn). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -data "ibm_is_vpn_gateways" "ds_vpn_gateways" { - +data "ibm_is_vpn_gateways" "example" { } ``` @@ -35,11 +44,27 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `members`: - `address` - (String) The public IP address assigned to the VPN gateway member. - `role`- (String) The high availability role assigned to the VPN gateway member. - - `private_address` - (String) The private IP address assigned to the VPN gateway member. + - `private_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + Nested scheme for `private_ip`: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. + - `private_address` - (String) The private IP address assigned to the VPN gateway member. Same as `private_ip.0.address` - `status` - (String) The status of the VPN gateway member. - `resource_type` - (String) The resource type, supported value is `vpn_gateway`. - `status` - (String) The status of the VPN gateway, supported values are **available**, **deleting**, **failed**, **pending**. - `subnet` - (String) The VPN gateway subnet information. + - `vpc` - (String) The VPC this VPN server resides in. + `Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) - The URL for this VPC + - `id` - (String) - The unique identifier for this VPC. + - `name` - (String) - The unique user-defined name for this VPC. - `resource_group` - (String) The resource group ID. - `mode` - (String) The VPN gateway mode, supported values are `policy` and `route`. diff --git a/website/docs/d/is_vpn_server.html.markdown b/website/docs/d/is_vpn_server.html.markdown new file mode 100644 index 000000000..4c39bef98 --- /dev/null +++ b/website/docs/d/is_vpn_server.html.markdown @@ -0,0 +1,165 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server" +description: |- + Get information about VPNServer +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server + +Provides a read-only data source for VPNServer. For more information, about VPN Server, see [Creating a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-create-server&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_server" "example" { + identifier = ibm_is_vpn_server.example.id +} +``` + +## Argument Reference +Review the argument reference that you can specify for your data source. + +- `identifier` - (Optional, String) The ID of the VPN server. +- `name` - (Optional, String) The name of the VPN server. + + ~> **NOTE** + `identifier` and `name` are mutually exclusive. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `identifier` - The unique identifier of the VPNServer. +- `certificate` - (List) The certificate instance for this VPN server. + + Nested scheme for **certificate**: + - `crn` - (String) The CRN for this certificate instance. + +- `client_authentication` - (List) The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods. + - Constraints: The minimum length is `1` item. + + Nested scheme for **client_authentication**: + - `method` - (String) The type of authentication. + - Constraints: Allowable values are: certificate, username + - `identity_provider` - (List) The type of identity provider to be used by VPN client. + + Nested scheme for **identity_provider**: + - `provider_type` - (String) The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access management The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + - Constraints: Allowable values are: iam + - `client_ca` - (List) The certificate instance used for the VPN client certificate authority (CA). + Nested scheme for **client_ca**: + - `crn` - (String) The CRN for this certificate instance. + - `crl` - (String) The certificate revocation list contents, encoded in PEM format. + +- `client_auto_delete` - (Boolean) If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed. + +- `client_auto_delete_timeout` - (Integer) Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately. + - Constraints: The maximum value is `24`. The minimum value is `0`. + +- `client_dns_server_ips` - (List) The DNS server addresses that will be provided to VPN clients that are connected to this VPN server. + + Nested scheme for **client_dns_server_ips**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + +- `client_idle_timeout` - (Integer) The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients. + - Constraints: The maximum value is `28800`. The minimum value is `0`. + +- `client_ip_pool` - (String) The VPN client IPv4 address pool, expressed in CIDR format. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` + +- `created_at` - (String) The date and time that the VPN server was created. + +- `crn` - (String) The CRN for this VPN server. + +- `enable_split_tunneling` - (Boolean) Indicates whether the split tunneling is enabled on this VPN server. + +- `health_state` - (String) The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state. + - Constraints: Allowable values are: ok, degraded, faulted, inapplicable + +- `hostname` - (String) Fully qualified domain name assigned to this VPN server. + +- `href` - (String) The URL for this VPN server. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +- `lifecycle_state` - (String) The lifecycle state of the VPN server. + - Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended + +- `name` - (String) The unique user-defined name for this VPN server. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + +- `port` - (Integer) The port number used by this VPN server. + - Constraints: The maximum value is `65535`. The minimum value is `1`. + +- `private_ips` - (List) The reserved IPs bound to this VPN server. + + Nested scheme for **private_ips**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `href` - (String) The URL for this reserved IP. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this reserved IP. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `name` - (String) The user-defined or system-provided name for this reserved IP. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: subnet_reserved_ip + +- `protocol` - (String) The transport protocol used by this VPN server. + - Constraints: Allowable values are: udp, tcp + +- `resource_group` - (List) The resource group object, for this VPN server. + + Nested scheme for **resource_group**: + - `href` - (String) The URL for this resource group. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this resource group. + - Constraints: The value must match regular expression `/^[0-9a-f]{32}$/` + - `name` - (String) The user-defined name for this resource group. + - Constraints: The maximum length is `40` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-_ ]+$/` + +- `resource_type` - (String) The type of resource referenced. + - Constraints: Allowable values are: vpn_server + +- `security_groups` - (List) The security groups targeting this VPN server. + + Nested scheme for **security_groups**: + - `crn` - (String) The security group's CRN. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `href` - (String) The security group's canonical URL. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this security group. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `name` - (String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + +- `subnets` - (List) The subnets this VPN server is part of. + + Nested scheme for **subnets**: + - `crn` - (String) The CRN for this subnet. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `href` - (String) The URL for this subnet. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this subnet. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `name` - (String) The user-defined name for this subnet. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: subnet + diff --git a/website/docs/d/is_vpn_server_client.html.markdown b/website/docs/d/is_vpn_server_client.html.markdown new file mode 100644 index 000000000..8b2c7a5c5 --- /dev/null +++ b/website/docs/d/is_vpn_server_client.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_client" +description: |- + Get information about VPNServerClient +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server_client + +Provides a read-only data source for VPNServerClient. For more information, about VPN Server Client, see [Setting up a client VPN environment and connecting to a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-environment-setup&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_server_client" "example" { + identifier = "id" + vpn_server = ibm_is_vpn_server.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `identifier` - (Required, String) The VPN client identifier. +- `vpn_server` - (Required, String) The VPN server identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VPNServerClient. +- `client_ip` - (List) The IP address assigned to this VPN client from `client_ip_pool`. + + Nested scheme for **client_ip**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + +- `common_name` - (String) The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. + +- `created_at` - (String) The date and time that the VPN client was created. + +- `disconnected_at` - (String) The date and time that the VPN client was disconnected. + +- `href` - (String) The URL for this VPN client. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]-)([^?#]-)(\\?([^#]-))?(#(.-))?$/` + +- `remote_ip` - (List) The remote IP address of this VPN client. + + Nested scheme for **remote_ip**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + +- `remote_port` - (Integer) The remote port of this VPN client. + - Constraints: The maximum value is `65535`. The minimum value is `1`. + +- `resource_type` - (String) The resource type. + - Constraints: Allowable values are: vpn_server_client + +- `status` - (String) The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered. + - Constraints: Allowable values are: connected, disconnected + +- `username` - (String) The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server. + diff --git a/website/docs/d/is_vpn_server_client_config.html.markdown b/website/docs/d/is_vpn_server_client_config.html.markdown new file mode 100644 index 000000000..439bc7a39 --- /dev/null +++ b/website/docs/d/is_vpn_server_client_config.html.markdown @@ -0,0 +1,34 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_client_configuration" +description: |- + Get information about VPN Server Client Configuration +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server_client_configuration + +Provides a read-only data source for VPN Server Client Configuration. For more information, about VPN Server Client Configuration, see [Setting up a client VPN environment and connecting to a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-environment-setup&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_server_client_configuration" "example" { + vpn_server = ibm_is_vpn_server.example.id + file_path = "vpn_server_client_configuration.txt" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `vpn_server` - (Required, String) The VPN server identifier. +- `file_path` - (Optional, String) The File path to store configuration. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VPNServerClientConfiguration. +- `vpn_server_client_configuration` - (String) The client configuration of vpn server. diff --git a/website/docs/d/is_vpn_server_clients.html.markdown b/website/docs/d/is_vpn_server_clients.html.markdown new file mode 100644 index 000000000..e092e8dd6 --- /dev/null +++ b/website/docs/d/is_vpn_server_clients.html.markdown @@ -0,0 +1,72 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_clients" +description: |- + Get information about VPNServerClientCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server_clients + +Provides a read-only data source for VPNServerClientCollection. For more information, about VPN Server Clients, see [Setting up a client VPN environment and connecting to a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-environment-setup&interface=ui). +## Example Usage + +```terraform +data "ibm_is_vpn_server_clients" "example" { + vpn_server = ibm_is_vpn_server.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `vpn_server` - (Required, Forces new resource, String) The VPN server identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VPNServerClientCollection. +- `clients` - (List) Collection of VPN clients. + Nested scheme for **clients**: + - `client_ip` - (List) The IP address assigned to this VPN client from `client_ip_pool`. + Nested scheme for **client_ip**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + - `common_name` - (String) The common name of client certificate that the VPN client provided when connecting to the server.This property will be present only when the `certificate` client authentication method is enabled on the VPN server. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. + - `created_at` - (String) The date and time that the VPN client was created. + - `disconnected_at` - (String) The date and time that the VPN client was disconnected. + - `href` - (String) The URL for this VPN client. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this VPN client. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `remote_ip` - (List) The remote IP address of this VPN client. + Nested scheme for **remote_ip**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + - `remote_port` - (Integer) The remote port of this VPN client. + - Constraints: The maximum value is `65535`. The minimum value is `1`. + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: vpn_server_client + - `status` - (String) The status of the VPN client:- `connected`: the VPN client is `connected` to this VPN server.- `disconnected`: the VPN client is `disconnected` from this VPN server.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN client on which the unexpected property value was encountered. + - Constraints: Allowable values are: connected, disconnected + - `username` - (String) The username that this VPN client provided when connecting to the VPN server.This property will be present only when the`username` client authentication method is enabled on the VPN server. + +- `first` - (List) A link to the first page of resources. + Nested scheme for **first**: + - `href` - (String) The URL for a page of resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +- `limit` - (Integer) The maximum number of resources that can be returned by the request. + - Constraints: The maximum value is `100`. The minimum value is `1`. + +- `next` - (List) A link to the next page of resources. This property is present for all pagesexcept the last page. + Nested scheme for **next**: + - `href` - (String) The URL for a page of resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +- `total_count` - (Integer) The total number of resources across all pages. + - Constraints: The minimum value is `0`. + diff --git a/website/docs/d/is_vpn_server_route.html.markdown b/website/docs/d/is_vpn_server_route.html.markdown new file mode 100644 index 000000000..0df848944 --- /dev/null +++ b/website/docs/d/is_vpn_server_route.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_route" +description: |- + Get information about VPNServerRoute +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server_route + +Provides a read-only data source for VPNServerRoute. For more information, about VPN Server Routes, see [Managing VPN Server routes](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-to-site-routes&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_server_route" "example" { + id = ibm_is_vpn_server_route.example.vpn_route + vpn_server = ibm_is_vpn_server.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +- `id` - (Required, String) The VPN route identifier. +- `vpn_server` - (Required, String) The VPN server identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the VPNServerRoute. +- `action` - (String) The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packet The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered. + - Constraints: Allowable values are: translate, deliver, drop + +- `created_at` - (String) The date and time that the VPN route was created. + +- `destination` - (String) The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` + +- `href` - (String) The URL for this VPN route. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]-)([^?#]-)(\\?([^#]-))?(#(.-))?$/` + +- `lifecycle_state` - (String) The lifecycle state of the VPN route. + - Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended + +- `name` - (String) The user-defined name for this VPN route. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]-[a-z0-9]|[0-9][-a-z0-9]-([a-z]|[-a-z][-a-z0-9]-[a-z0-9]))$/` + +- `resource_type` - (String) The resource type. + - Constraints: Allowable values are: vpn_server_route + diff --git a/website/docs/d/is_vpn_server_routes.html.markdown b/website/docs/d/is_vpn_server_routes.html.markdown new file mode 100644 index 000000000..35c422839 --- /dev/null +++ b/website/docs/d/is_vpn_server_routes.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_routes" +description: |- + Get information about VPNServerRouteCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_vpn_server_routes + +Provides a read-only data source for VPNServerRouteCollection. For more information, about VPN Server Routes, see [Managing VPN Server routes](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-to-site-routes&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_server_routes" "example" { + vpn_server = ibm_is_vpn_server.example.id +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `vpn_server` - (Required, String) The VPN server identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the VPNServerRouteCollection. +* `first` - (List) A link to the first page of resources. +Nested scheme for **first**: + * `href` - (String) The URL for a page of resources. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +* `limit` - (Integer) The maximum number of resources that can be returned by the request. + * Constraints: The maximum value is `100`. The minimum value is `1`. + +* `next` - (List) A link to the next page of resources. This property is present for all pagesexcept the last page. +Nested scheme for **next**: + * `href` - (String) The URL for a page of resources. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +* `routes` - (List) Collection of VPN routes. + Nested scheme for **routes**: + * `action` - (String) The action to perform with a packet matching the VPN route:- `translate`: translate the source IP address to one of the private IP addresses of the VPN server.- `deliver`: deliver the packet into the VPC.- `drop`: drop the packet The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered. + * Constraints: Allowable values are: translate, deliver, drop + * `created_at` - (String) The date and time that the VPN route was created. + * `destination` - (String) The destination for this VPN route in the VPN server. If an incoming packet does not match any destination, it will be dropped. + * Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` + * `href` - (String) The URL for this VPN route. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (String) The unique identifier for this VPN route. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + * `lifecycle_state` - (String) The lifecycle state of the VPN route. + * Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended + * `name` - (String) The user-defined name for this VPN route. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + * `resource_type` - (String) The resource type. + * Constraints: Allowable values are: vpn_server_route + +* `total_count` - (Integer) The total number of resources across all pages. + * Constraints: The minimum value is `0`. + diff --git a/website/docs/d/is_vpn_servers.html.markdown b/website/docs/d/is_vpn_servers.html.markdown new file mode 100644 index 000000000..9fe8df514 --- /dev/null +++ b/website/docs/d/is_vpn_servers.html.markdown @@ -0,0 +1,139 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpn_servers" +description: |- + Manages IBM Cloud VPN Servers. +--- + +# ibm_is_vpn_servers + +Provides a read-only data source for VPNServerCollection. For more information, about VPN Server, see [Creating a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-create-server&interface=ui). + +## Example Usage + +```terraform +data "ibm_is_vpn_servers" "example" { +} +``` + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the VPNServerCollection. +* `vpn_servers` - (Required, List) Collection of VPN servers. + + Nested scheme for **vpn_servers**: + * `certificate` - (Required, List) The certificate instance for this VPN server. + + Nested scheme for **certificate**: + * `crn` - (Required, String) The CRN for this certificate instance. + * `client_authentication` - (Required, List) The methods used to authenticate VPN clients to this VPN server. VPN clients must authenticate against all provided methods. + * Constraints: The minimum length is `1` item. + + Nested scheme for **client_authentication**: + * `method` - (Required, String) The type of authentication. + * Constraints: Allowable values are: certificate, username + * `identity_provider` - (Optional, List) The type of identity provider to be used by VPN client. + + Nested scheme for **identity_provider**: + * `provider_type` - (Optional, String) The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access management The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + * Constraints: Allowable values are: iam + * `client_ca` - (Optional, List) The certificate instance used for the VPN client certificate authority (CA). + + Nested scheme for **client_ca**: + * `crn` - (Required, String) The CRN for this certificate instance. + * `crl` - (Optional, String) The certificate revocation list contents, encoded in PEM format. + * `client_auto_delete` - (Required, Boolean) If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed. + * `client_auto_delete_timeout` - (Required, Integer) Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately. + * Constraints: The maximum value is `24`. The minimum value is `0`. + * `client_dns_server_ips` - (Required, List) The DNS server addresses that will be provided to VPN clients that are connected to this VPN server. + + Nested scheme for **client_dns_server_ips**: + * `address` - (Required, String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + * Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + * `client_idle_timeout` - (Required, Integer) The seconds a VPN client can be idle before this VPN server will disconnect it. If `0`, the server will not disconnect idle clients. + * Constraints: The maximum value is `28800`. The minimum value is `0`. + * `client_ip_pool` - (Required, String) The VPN client IPv4 address pool, expressed in CIDR format. + * Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` + * `created_at` - (Required, String) The date and time that the VPN server was created. + * `crn` - (Required, String) The CRN for this VPN server. + * `enable_split_tunneling` - (Required, Boolean) Indicates whether the split tunneling is enabled on this VPN server. + * `health_state` - (Required, String) The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state. + * Constraints: Allowable values are: ok, degraded, faulted, inapplicable + * `hostname` - (Required, String) Fully qualified domain name assigned to this VPN server. + * `href` - (Required, String) The URL for this VPN server. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (Required, String) The unique identifier for this VPN server. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + * `lifecycle_state` - (Required, String) The lifecycle state of the VPN server. + * Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended + * `name` - (Required, String) The unique user-defined name for this VPN server. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + * `port` - (Required, Integer) The port number used by this VPN server. + * Constraints: The maximum value is `65535`. The minimum value is `1`. + * `private_ips` - (Required, List) The reserved IPs bound to this VPN server. + + Nested scheme for **private_ips**: + * `address` - (Required, String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + * Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + * `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for **deleted**: + * `more_info` - (Required, String) Link to documentation about deleted resources. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `href` - (Required, String) The URL for this reserved IP. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (Required, String) The unique identifier for this reserved IP. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + * `name` - (Required, String) The user-defined or system-provided name for this reserved IP. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + * `resource_type` - (Required, String) The resource type. + * Constraints: Allowable values are: subnet_reserved_ip + * `protocol` - (Required, String) The transport protocol used by this VPN server. + * Constraints: Allowable values are: udp, tcp + * `resource_group` - (Required, List) The resource group for this VPN server. + + Nested scheme for **resource_group**: + * `href` - (Required, String) The URL for this resource group. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (Required, String) The unique identifier for this resource group. + * Constraints: The value must match regular expression `/^[0-9a-f]{32}$/` + * `name` - (Required, String) The user-defined name for this resource group. + * Constraints: The maximum length is `40` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-_ ]+$/` + * `resource_type` - (Required, String) The type of resource referenced. + * Constraints: Allowable values are: vpn_server + * `security_groups` - (Required, List) The security groups targeting this VPN server. + + Nested scheme for **security_groups**: + * `crn` - (Required, String) The security group's CRN. + * `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for **deleted**: + * `more_info` - (Required, String) Link to documentation about deleted resources. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `href` - (Required, String) The security group's canonical URL. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (Required, String) The unique identifier for this security group. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + * `name` - (Required, String) The user-defined name for this security group. Names must be unique within the VPC the security group resides in. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + * `subnets` - (Required, List) The subnets this VPN server is part of. + + Nested scheme for **subnets**: + * `crn` - (Required, String) The CRN for this subnet. + * `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for **deleted**: + * `more_info` - (Required, String) Link to documentation about deleted resources. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `href` - (Required, String) The URL for this subnet. + * Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + * `id` - (Required, String) The unique identifier for this subnet. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + * `name` - (Required, String) The user-defined name for this subnet. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + * `resource_type` - (Required, String) The resource type. + * Constraints: Allowable values are: subnet + diff --git a/website/docs/d/is_zone.html.markdown b/website/docs/d/is_zone.html.markdown index 6bfe31613..68790a88f 100644 --- a/website/docs/d/is_zone.html.markdown +++ b/website/docs/d/is_zone.html.markdown @@ -9,11 +9,22 @@ description: |- # ibm_is_zone Retrieve information of an existing IBM Cloud zone in a particular region as a read-only data source. For more information, about IBM Cloud zone, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_zone" "ds_zone" { +data "ibm_is_zone" "example" { name = "us-south-1" region = "us-south" } diff --git a/website/docs/d/is_zones.html.markdown b/website/docs/d/is_zones.html.markdown index f1db02aa8..057f859e6 100644 --- a/website/docs/d/is_zones.html.markdown +++ b/website/docs/d/is_zones.html.markdown @@ -9,10 +9,21 @@ description: |- # ibm_is_zones Retrieve information of an existing IBM Cloud zones in a particular region as a read-only data source. For more information, about IBM Cloud zones, see [creating a VPC in a different region](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-in-a-different-region). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -data "ibm_is_zones" "ds_zones" { +data "ibm_is_zones" "example" { region = "us-south" } ``` diff --git a/website/docs/d/kms_key.html.markdown b/website/docs/d/kms_key.html.markdown index 75d42dc8e..22e314698 100644 --- a/website/docs/d/kms_key.html.markdown +++ b/website/docs/d/kms_key.html.markdown @@ -27,11 +27,11 @@ data "ibm_kms_key" "test" { limit = 100 key_name = "name-of-key" } -resource "ibm_cos_bucket" "flex-us-south" { +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = data.ibm_kms_key.test.key.0.crn } ``` @@ -107,7 +107,7 @@ Review the argument references that you can specify for your data source. - `key_name` - (Optional, String) The name of the key. If you want to retrieve the key by using the key alias, use the `alias` option. You must provide either the `key_name` or `alias`. -## Attribute Reference +## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - `keys` - (String) Lists the Keys of HPCS or Key-protect instance. diff --git a/website/docs/d/kms_key_policies.html.markdown b/website/docs/d/kms_key_policies.html.markdown index ade79ea09..c4bb764d9 100644 --- a/website/docs/d/kms_key_policies.html.markdown +++ b/website/docs/d/kms_key_policies.html.markdown @@ -10,29 +10,36 @@ description: |- Import the details of existing Key Protect and Hyper Protect Crypto Service (HPCS) keys policies as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. Retreives a list of key policies from the hs-crypto or key-protect instance for the provided key id. -## Example Usage +## Example usage ```terraform data "ibm_kms_key_policies" "test" { instance_id = "guid-of-keyprotect-or hs-crypto-instance" key_id = "key-id-of-the-key" } +OR +data "ibm_kms_key_policies" "test" { + instance_id = "guid-of-keyprotect-or hs-crypto-instance" + alias = "alias-of-the-key" +} ``` -## Argument Reference +## Argument reference The following arguments are supported: - `endpoint_type` - (Optional, String) The type of the public or private endpoint to be used for fetching keys. - `instance_id` - (Required, string) The keyprotect instance guid. -- `key_id` - (Required, string) The id of the key. +- `key_id` - (Required - if the alias is not provided, String) The id of the key. +- `alias` - (Required - if the key_id is not provided, String) The alias of the key. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: - `id` - (String) The CRN of the key. - `key_id` - (String) The ID of the key. +- `alias` - (String) The alias of the key. - `rotation` - (List) The key rotation time interval in months, with a minimum of 1, and a maximum of 12. Nested scheme for `rotation`: diff --git a/website/docs/d/kms_keys.html.markdown b/website/docs/d/kms_keys.html.markdown index bfb0cc3d1..b8824cf86 100644 --- a/website/docs/d/kms_keys.html.markdown +++ b/website/docs/d/kms_keys.html.markdown @@ -17,11 +17,11 @@ data "ibm_kms_keys" "test" { instance_id = "guid-of-keyprotect-or hs-crypto-instance" limit = 100 } -resource "ibm_cos_bucket" "flex-us-south" { +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = data.ibm_kms_keys.test.keys.0.crn } ``` diff --git a/website/docs/d/kp_key.html.markdown b/website/docs/d/kp_key.html.markdown index f536f8092..9f9fed38c 100644 --- a/website/docs/d/kp_key.html.markdown +++ b/website/docs/d/kp_key.html.markdown @@ -10,18 +10,18 @@ description: |- Import the details of existing keyprotect keys as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. Retreives a list of keys from the key protect instance. Configuration of an key protect key data source requires that the region parameter is set for the IBM provider in the `provider.tf` to be the same as the target key protect instance location or region. If not specified, it defaults to `us-south`. A Terraform apply will fail if the key protect instance location is set differently. For more information, about key protect keys, see [Key Protect CLI Command Reference](https://cloud.ibm.com/docs/key-protect?topic=key-protect-cli-plugin-key-protect-cli-reference). -## Example Usage +## Example usage The following example creates a read-only copy of the `mydatabase` instance in `us-east`. ```terraform data "ibm_kp_key" "test" { key_protect_id = "id-of-keyprotect-instance" } -resource "ibm_cos_bucket" "flex-us-south" { +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = data.ibm_kp_key.test.keys.0.crn } ``` diff --git a/website/docs/d/pi_catalog_images.html.markdown b/website/docs/d/pi_catalog_images.html.markdown index b1544e367..8693c9e21 100644 --- a/website/docs/d/pi_catalog_images.html.markdown +++ b/website/docs/d/pi_catalog_images.html.markdown @@ -24,7 +24,7 @@ data "ibm_pi_catalog_images" "ds_images" { * `region` - `lon` * `zone` - `lon04` - Example Usage: + Example usage: ```terraform provider "ibm" { @@ -36,7 +36,9 @@ data "ibm_pi_catalog_images" "ds_images" { ## Argument reference Review the argument reference that you can specify for your data source. -- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `sap` - (Optional, Bool) Set `true` to include SAP images. The default value is `false`. +- `vtl` - (Optional, Bool) Set `true` to include VTL images. The default value is `false`. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/pi_cloud_connection.html.markdown b/website/docs/d/pi_cloud_connection.html.markdown new file mode 100644 index 000000000..ca42eb411 --- /dev/null +++ b/website/docs/d/pi_cloud_connection.html.markdown @@ -0,0 +1,64 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_cloud_connection" +description: |- + Manages IBM Cloud connection in the Power Virtual Server cloud. +--- + +# ibm_pi_cloud_connection + +Retrieve information about an existing IBM Cloud Power Virtual Server Cloud cloud connection. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_cloud_connection" "example" { + pi_cloud_connection_name = "test_cloud_connection" + pi_cloud_instance_id = "" +} +``` + +**Notes** + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + + - `region` - `lon` + - `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_cloud_connection_name` - (Required, String) The cloud connection name to be used. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The unique identifier of the cloud connection. +- `classic_enabled` - (Bool) Is classic endpoint destination enabled? +- `connection_mode` - (String) Type of service the gateway is attached to. +- `global_routing` - (String) Is global routing enabled for this cloud connection. +- `gre_destination_address` - (String) The GRE destination IP address. +- `gre_source_address` - (String) The GRE auto-assigned source IP address. +- `ibm_ip_address` - (String) The IBM IP address. +- `metered` - (String) Is metered enabled for this cloud connection. +- `networks` - (Set of String) Set of Networks attached to this cloud connection. +- `port` - (String) Port. +- `speed` - (Integer) Speed of the cloud connection (speed in megabits per second). +- `status` - (String) Link status. +- `user_ip_address` - (String) User IP address. +- `vpc_crns` - (Set of String) Set of VPCs attached to this cloud connection. +- `vpc_enabled` - (Bool) Is VPC enabled for this cloud connection? diff --git a/website/docs/d/pi_cloud_connections.html.markdown b/website/docs/d/pi_cloud_connections.html.markdown new file mode 100644 index 000000000..8925fd81e --- /dev/null +++ b/website/docs/d/pi_cloud_connections.html.markdown @@ -0,0 +1,67 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_cloud_connections" +description: |- + Manages IBM cloud_connections in the Power Virtual Server cloud. +--- + +# ibm_pi_cloud_connections + +Retrieve information about all cloud connections as a read-only data source. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_cloud_connections" "example" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + + - `region` - `lon` + - `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `connections` - (List) List of all the Cloud Connections. + + Nested scheme for `connections`: + + - `classic_enabled` - (Bool) Is Classic endpoint destination enabled. + - `cloud_connection_id` - (String) The unique identifier of the cloud connection. + - `global_routing` - (String) Is global routing enabled for this cloud connection. + - `gre_destination_address` - (String) GRE destination IP address. + - `gre_source_address` - (String) GRE auto-assigned source IP address. + - `ibm_ip_address` - (String) IBM IP address. + - `metered` - (String) Is metered enabled for this cloud connection. + - `name` - (String) Name of the cloud connection. + - `networks` - (Set of String) Set of Networks attached to this cloud connection. + - `port` - (String) Port. + - `speed` - (Integer) Speed of the cloud connection (speed in megabits per second). + - `status` - (String) Link status. + - `user_ip_address` - (String) User IP address. + - `vpc_crns` - (Set of String) Set of VPCs attached to this cloud connection. + - `vpc_enabled` - (Bool) Is VPC enabled for this cloud connection. + - `connection_mode` - (String) Type of service the gateway is attached to. diff --git a/website/docs/d/pi_cloud_instance.html.markdown b/website/docs/d/pi_cloud_instance.html.markdown index 97604d517..5e65926b8 100644 --- a/website/docs/d/pi_cloud_instance.html.markdown +++ b/website/docs/d/pi_cloud_instance.html.markdown @@ -23,7 +23,7 @@ data "ibm_pi_cloud_instance" "ds_cloud_instance" { * `region` - `lon` * `zone` - `lon04` -Example Usage: +Example usage: ```terraform provider "ibm" { @@ -40,13 +40,23 @@ Review the argument reference that you can specify for your data source. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. -- `capabilities` - (String) Lists the capabilities for this cloud instance. -- `creation_date` - (String) The date on which the tenant was created. -- `enabled` - (Bool) Indicates whether the tenant is enabled. +- `capabilities` - (String) Lists the capabilities for this cloud instance. +- `enabled` - (Bool) Indicates whether the tenant is enabled. - `id` - (String) The unique identifier for this tenant. -- `tenant_name` - (String) The name of the tenant. -- `total_instances` - (String) The count of lpars that belong to this specific cloud instance. -- `total_memory_consumed` - (String) The total memory consumed by this service instance. -- `total_processors_consumed` - (String) The total processors consumed by this service instance. -- `total_ssd_storage_consumed` - (String) The total SSD Storage consumed by this service instance. -- `total_standard_storage_consumed` - (String) The total Standard Storage consumed by this service instance. +- `pvm_instances` - (List) PVM instances owned by the Cloud Instance. + + Nested scheme for `pvm_instances`: + - `creation_date` - (String) Date/Time of PVM creation. + - `href` - (String) Link to Cloud Instance resource. + - `id` - (String) PVM Instance ID. + - `name` - (String) Name of the server. + - `status` - (String) The status of the instance. + - `systype` - (string) System type used to host the instance. +- `region` - (String) The region the cloud instance lives. +- `tenant_id` - (String) The tenant ID that owns this cloud instance. +- `total_instances` - (String) The count of lpars that belong to this specific cloud instance. +- `total_memory_consumed` - (String) The total memory consumed by this service instance. +- `total_processors_consumed` - (String) The total processors consumed by this service instance. +- `total_ssd_storage_consumed` - (String) The total SSD Storage consumed by this service instance. +- `total_standard_storage_consumed` - (String) The total Standard Storage consumed by this service instance. + diff --git a/website/docs/d/pi_console_languages.html.markdown b/website/docs/d/pi_console_languages.html.markdown new file mode 100644 index 000000000..d5f7f36af --- /dev/null +++ b/website/docs/d/pi_console_languages.html.markdown @@ -0,0 +1,54 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_console_languages" +description: |- + Manages Instance Console Languages in the Power Virtual Server cloud. +--- + +# ibm_pi_console_languages + +Retrieve information about all the available Console Languages for an Instance. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_console_languages" "example" { + pi_cloud_instance_id = "" + pi_instance_name = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_name` - (Required, String) The unique identifier or name of the instance. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `console_languages` - (List) List of all the Console Languages. + + Nested scheme for `console_languages`: + - `code` - (String) Language code. + - `language` - (String) Language description. diff --git a/website/docs/d/pi_dhcp.html.markdown b/website/docs/d/pi_dhcp.html.markdown new file mode 100644 index 000000000..cf6f1221d --- /dev/null +++ b/website/docs/d/pi_dhcp.html.markdown @@ -0,0 +1,56 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_dhcp" +description: |- + Manages DHCP Server in the Power Virtual Server cloud. +--- + +# ibm_pi_dhcp + +Retrieve information about a DHCP Server. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_dhcp" "example" { + pi_cloud_instance_id = "" + pi_dhcp_id = "0e48e1be-9f54-4a67-ba55-7e31ce98b65a" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. +- `pi_dhcp_id` - (Required, String) The ID of the DHCP Server. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The ID of the DHCP Server. +- `leases` - (List) The list of DHCP Server PVM Instance leases. + Nested scheme for `leases`: + - `instance_ip` - (String) The IP of the PVM Instance. + - `instance_mac` - (String) The MAC Address of the PVM Instance. +- `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). +- `network_id`- (String) The ID of the DHCP Server private network. +- `network_name` - The name of the DHCP Server private network. +- `status` - (String) The status of the DHCP Server. + +**Note** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` \ No newline at end of file diff --git a/website/docs/d/pi_dhcps.html.markdown b/website/docs/d/pi_dhcps.html.markdown new file mode 100644 index 000000000..9fc3f871d --- /dev/null +++ b/website/docs/d/pi_dhcps.html.markdown @@ -0,0 +1,55 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_dhcps" +description: |- + Manages DHCP Servers in the Power Virtual Server cloud. +--- + +# ibm_pi_dhcps + +Retrieve information about all DHCP Servers. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_dhcp" "example" { + pi_cloud_instance_id = "" +} +``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `servers` - (List) The list of all the DHCP Servers. + + Nested scheme for `servers`: + - `dhcp_id` - (String) The ID of the DHCP Server. + - `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). + - `network_id`- (String) The ID of the DHCP Server private network. + - `network_name` - The name of the DHCP Server private network. + - `status` - (String) The status of the DHCP Server. + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` \ No newline at end of file diff --git a/website/docs/d/pi_image.html.markdown b/website/docs/d/pi_image.html.markdown index f2c25e7b3..fad9111aa 100644 --- a/website/docs/d/pi_image.html.markdown +++ b/website/docs/d/pi_image.html.markdown @@ -50,3 +50,4 @@ In addition to all argument reference list, you can access the following attribu - `state` - (String) The state for this image. - `storage_type` - (String) The storage type for this image. - `storage_pool` - (String) Storage pool where image resides. +- `image_type` - (String) The identifier of this image type. diff --git a/website/docs/d/pi_images.html.markdown b/website/docs/d/pi_images.html.markdown index 7e8ffe26e..791e2df2b 100644 --- a/website/docs/d/pi_images.html.markdown +++ b/website/docs/d/pi_images.html.markdown @@ -44,9 +44,10 @@ In addition to all argument reference list, you can access the following attribu - `image_info` - List of images - A list of all supported images. Nested scheme for `image_info`: - - `href` - (String) The hyper link of an image. - - `id` - (String) The unique identifier of an image. - - `name`- (String) The name of an image. - - `state` - (String) The state of an image. - - `storage_pool` - (String) Storage pool where image resides. - - `storage_type` - (String) The storage type of an image. + - `href` - (String) The hyper link of an image. + - `id` - (String) The unique identifier of an image. + - `name`- (String) The name of an image. + - `state` - (String) The state of an image. + - `storage_pool` - (String) Storage pool where image resides. + - `storage_type` - (String) The storage type of an image. + - `image_type` - (String) The identifier of this image type. diff --git a/website/docs/d/pi_instance.html.markdown b/website/docs/d/pi_instance.html.markdown index 50d201fdf..75fecd8d5 100644 --- a/website/docs/d/pi_instance.html.markdown +++ b/website/docs/d/pi_instance.html.markdown @@ -10,7 +10,7 @@ description: |- # ibm_pi_instance Retrieve information about a Power Systems Virtual Server instance. For more information, about Power Virtual Server instance, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). -## Example Usage +## Example usage ```terraform data "ibm_pi_instance" "ds_instance" { @@ -44,8 +44,19 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. +- `addresses` - (Deprecated, List of objects) - The address associated with this instance. + + Nested scheme for `addresses`: + - `ip` - (String) The IP address of the instance. + - `external_ip` - (String) The external IP address of the instance. + - `macaddress` - (String) The MAC address of the instance. + - `network_id` - (String) The network ID of the instance. + - `network_name` - (String) The network name of the instance. + - `type` - (String) The type of the network. +- `deployment_type` - (String) The custom deployment type. - `health_status` - (String) The health of the instance. - `id` - (String) The unique identifier of the instance. +- `license_repository_capacity` - The VTL license repository capacity TB value. Only available with VTL instances. - `memory` - (Float) The amount of memory that is allocated to the instance. - `minproc`- (Float) The minimum number of processors that must be allocated to the instance. - `maxproc`- (Float) The maximum number of processors that can be allocated to the instance without shutting down or rebooting the `LPAR`. @@ -53,19 +64,23 @@ In addition to all argument reference list, you can access the following attribu - `minmem`- (Float) The minimum amount of memory that must be allocated to the instance. - `maxmem`- (Float) The maximum amount of memory that can be allocated to the instance without shutting down or rebooting the `LPAR`. - `min_virtual_cores` - (Integer) The minimum cores assigned to an instance. -- `addresses` - List of objects - The address associated with this instance. +- `networks` - List of objects - The network associated with this instance. - Nested scheme for `addresses`: + Nested scheme for `networks`: - `ip` - (String) The IP address of the instance. - `external_ip` - (String) The external IP address of the instance. - `macaddress` - (String) The MAC address of the instance. - `network_id` - (String) The network ID of the instance. - `network_name` - (String) The network name of the instance. - `type` - (String) The type of the network. +- `placement_group_id`- (String) The ID of the placement group that the instance is a member. - `processors` - (Float) The number of processors that are allocated to the instance. - `proctype` - (String) The procurement type of the instance. Supported values are `shared` and `dedicated`. +- `shared_processor_pool`- (String) The name of the shared processor pool for the instance. +- `shared_processor_pool_id` - (String) The ID of the shared processor pool for the instance. - `status` - (String) The status of the instance. -- `storage_pool`- (String) Storage Pool where server is deployed. -- `storage_type` - (String) Storage type where server is deployed. +- `storage_pool` - (String) The storage Pool where server is deployed. +- `storage_pool_affinity` - (Bool) Indicates if all volumes attached to the server must reside in the same storage pool. +- `storage_type` - (String) The storage type where server is deployed. - `virtual_cores_assigned` - (Integer) The virtual cores that are assigned to the instance. -- `volumes`- (List of strings) The list of volume IDs that are attached to the instance. +- `volumes` - (List of strings) The list of volume IDs that are attached to the instance. diff --git a/website/docs/d/pi_instance_ip.html.markdown b/website/docs/d/pi_instance_ip.html.markdown index e7cbbde7c..541891d09 100644 --- a/website/docs/d/pi_instance_ip.html.markdown +++ b/website/docs/d/pi_instance_ip.html.markdown @@ -10,7 +10,7 @@ description: |- # ibm_pi_instance_ip Retrieve information about a Power Systems Virtual Server instance IP address. For more information, about Power Systems Virtual Server instance IP address, see [configuring and adding a private network subnet](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). -## Example Usage +## Example usage ```terraform data "ibm_pi_instance_ip" "ds_instance_ip" { @@ -24,7 +24,7 @@ data "ibm_pi_instance_ip" "ds_instance_ip" { * If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: * `region` - `lon` * `zone` - `lon04` - Example Usage: + Example usage: ```terraform provider "ibm" { region = "lon" @@ -44,8 +44,9 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `external_ip` - (String) The external IP of the network that is attached to this instance. -- `ip` - (String) The IP address that is attached to this instance from the subnet. - `id` - (String) The unique identifier of the network. +- `ip` - (String) The IP address that is attached to this instance from the subnet. - `ipoctet` - (String) The IP octet of the network that is attached to this instance. - `macaddress` - (String) The MAC address of the network that is attached to this instance. +- `network_id` - (String) ID of the network. - `type` - (String) The type of the network that is attached to this instance. diff --git a/website/docs/d/pi_instance_snapshots.html.markdown b/website/docs/d/pi_instance_snapshots.html.markdown new file mode 100644 index 000000000..cbe97e86f --- /dev/null +++ b/website/docs/d/pi_instance_snapshots.html.markdown @@ -0,0 +1,55 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_instance_snapshots" +description: |- + Manages an instance snapshots in the Power Virtual Server cloud. +--- + +# ibm_pi_instance_snapshots +Retrieve information about a Power Systems Virtual Server instance snapshots. For more information, about Power Virtual Server instance snapshots, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_instance_snapshots" "ds_instance_snapshots" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `instance_snapshots` - The list of Power Virtual Machine instance snapshots within the given cloud instance. + + Nested scheme for `instance_snapshots`: + - `action` - (String) Action performed on the instance snapshot. + - `creation_date` - (String) The creation date. + - `description` - (String) The description of the snapshot. + - `id` - (String) The unique identifier of the Power Systems Virtual Machine instance snapshot. + - `last_updated_date` - (String) The last Update Date. + - `name` - (String) The name of the Power Systems Virtual Machine instance snapshot. + - `percent_complete` - (Integer) The snapshot completion percentage. + - `status` - (String) The status of the Power Virtual Machine instance snapshot. + - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. \ No newline at end of file diff --git a/website/docs/d/pi_instance_volumes.html.markdown b/website/docs/d/pi_instance_volumes.html.markdown index 1b050c98b..1fc2583b2 100644 --- a/website/docs/d/pi_instance_volumes.html.markdown +++ b/website/docs/d/pi_instance_volumes.html.markdown @@ -48,12 +48,12 @@ In addition to all argument reference list, you can access the following attribu - `instance_volumes` - List of volumes - List of volumes attached to instance. Nested scheme for `instance_volumes`: - - `bootable`- (Bool) Indicates if the volume is bootable (**true**) or not (**false**). - - `href` - (String) The hyper link of the volume. - - `id` - (String) The unique identifier of the volume. - - `name` - (String) The name of the volume. - - `pool` - (String) Volume pool, name of storage pool where the volume is located. - - `shareable` - (Bool) If set to **true**, the volume can be shared across multiple Power Systems Virtual Server instances. If set to **false**, the volume can be mounted to one instance only. - - `size` - (Integer) The size of this volume in gigabytes. - - `state` - (String) The state of the volume. - - `type` - (String) The disk type that is used for this volume. + - `bootable`- (Bool) Indicates if the volume is boot capable. + - `href` - (String) The hyper link of the volume. + - `id` - (String) The unique identifier of the volume. + - `name` - (String) The name of the volume. + - `pool` - (String) Volume pool, name of storage pool where the volume is located. + - `shareable` - (Bool) Indicates if the volume is shareable between VMs. + - `size` - (Integer) The size of this volume in gigabytes. + - `state` - (String) The state of the volume. + - `type` - (String) The disk type that is used for this volume. diff --git a/website/docs/d/pi_instances.html.markdown b/website/docs/d/pi_instances.html.markdown new file mode 100644 index 000000000..ccd79cee4 --- /dev/null +++ b/website/docs/d/pi_instances.html.markdown @@ -0,0 +1,77 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_instances" +description: |- + List all the power virtual server instances for the respective cloud instance in the Power Virtual Server cloud. +--- + +# ibm_pi_instances +Retrieve information about all Power Systems Virtual Server instances for the given cloud instance. For more information, about Power Virtual Server instances, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_instances" "ds_instance" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Notes** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `pvm_instances` - List of power virtual server instances for respective cloud instance. + + Nested scheme for `pvm_instances`: + - `health_status` - (String) The health of the instance. + - `license_repository_capacity` - The VTL license repository capacity TB value. Only available with VTL instances. + - `memory` - (Float) The amount of memory that is allocated to the instance. + - `minproc`- (Float) The minimum number of processors that must be allocated to the instance. + - `maxproc`- (Float) The maximum number of processors that can be allocated to the instance without shutting down or rebooting the `LPAR`. + - `max_virtual_cores` - (Integer) The maximum value that you increase without a reboot. + - `minmem`- (Float) The minimum amount of memory that must be allocated to the instance. + - `maxmem`- (Float) The maximum amount of memory that can be allocated to the instance without shutting down or rebooting the `LPAR`. + - `min_virtual_cores` - (Integer) The minimum cores assigned to an instance. + - `networks` - List of objects - The network associated with this instance. + + Nested scheme for `networks`: + - `ip` - (String) The IP address of the instance. + - `external_ip` - (String) The external IP address of the instance. + - `macaddress` - (String) The MAC address of the instance. + - `network_id` - (String) The network ID of the instance. + - `network_name` - (String) The network name of the instance. + - `type` - (String) The type of the network. + + - `placement_group_id`- (String) The ID of the placement group that the instance is a member. + - `processors` - (Float) The number of processors that are allocated to the instance. + - `proctype` - (String) The procurement type of the instance. Supported values are `shared` and `dedicated`. + - `pvm_instance_id` - (String) The unique identifier of the instance. + - `shared_processor_pool`- (String) The name of the shared processor pool for the instance. + - `shared_processor_pool_id` - (String) The ID of the shared processor pool for the instance. + - `status` - (String) The status of the instance. + - `storage_pool` - (String) The storage Pool where server is deployed. + - `storage_pool_affinity` - (Bool) Indicates if all volumes attached to the server must reside in the same storage pool. + - `storage_type` - (String) The storage type where server is deployed. + - `virtual_cores_assigned` - (Integer) The virtual cores that are assigned to the instance. diff --git a/website/docs/d/pi_key.html.markdown b/website/docs/d/pi_key.html.markdown index 068d2ff07..fab30bd2c 100644 --- a/website/docs/d/pi_key.html.markdown +++ b/website/docs/d/pi_key.html.markdown @@ -18,6 +18,19 @@ data "ibm_pi_key" "ds_instance" { pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" } ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. +- `pi_key_name` - (Required, String) User defined name for the SSH key. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) User defined name for the SSH key +- `creation_date` - (String) Date of SSH Key creation. +- `ssh_key` - (String) SSH RSA key. **Notes** @@ -33,17 +46,4 @@ Example usage: region = "lon" zone = "lon04" } - ``` - -## Argument reference -Review the argument references that you can specify for your data source. - -- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. -- `pi_key_name` - (Required, String) The name of the key. - -## Attribute reference -In addition to all argument reference list, you can access the following attribute references after your data source is created. - -- `creation_date` - Timestamp - The timestamp when the SSH key was created. -- `id` - (String) The unique identifier of the SSH key. -- `sshkey` - (String) The public SSH key value. + ``` \ No newline at end of file diff --git a/website/docs/d/pi_keys.html.markdown b/website/docs/d/pi_keys.html.markdown new file mode 100644 index 000000000..305c0f4a9 --- /dev/null +++ b/website/docs/d/pi_keys.html.markdown @@ -0,0 +1,50 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_keys" +description: |- + Manages SSH keys in the Power Virtual Server cloud. +--- + +# ibm_pi_keys +Retrieve information about all SSH keys. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_keys" "example" { + pi_cloud_instance_id = "" +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `keys` - (List) List of all the SSH keys. + + Nested scheme for `keys`: + - `name` - (String) User defined name for the SSH key + - `creation_date` - (String) Date of SSH Key creation. + - `ssh_key` - (String) SSH RSA key. + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` \ No newline at end of file diff --git a/website/docs/d/pi_network.html.markdown b/website/docs/d/pi_network.html.markdown index c297a1f45..153b53696 100644 --- a/website/docs/d/pi_network.html.markdown +++ b/website/docs/d/pi_network.html.markdown @@ -46,6 +46,7 @@ In addition to all argument reference list, you can access the following attribu - `available_ip_count` - (Float) The total number of IP addresses that you have in your network. - `cidr` - (String) The CIDR of the network. +- `dns`- (Set of String) The DNS Servers for the network. - `gateway` - (String) The network gateway that is attached to your network. - `id` - (String) The ID of the network. - `type` - (String) The type of network. diff --git a/website/docs/d/pi_placement_group.html.markdown b/website/docs/d/pi_placement_group.html.markdown new file mode 100644 index 000000000..d90d4b83f --- /dev/null +++ b/website/docs/d/pi_placement_group.html.markdown @@ -0,0 +1,49 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_placement_group" +description: |- + Manages a placement group in the Power Virtual Server cloud. +--- + +# ibm_pi_placement_group +Retrieve information about a placement group. For more information, about placement groups, see [Managing server placement groups](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-placement-groups). + +## Example Usage + +```terraform +data "ibm_pi_placement_group" "ds_placement_group" { + pi_placement_group_name = "my-pg" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Notes** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_placement_group_name` - (Required, String) The name of the placement group. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The ID of the placement group. +- `members` - (List of strings) The list of server instances IDs that are members of the placement group. +- `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_placement_groups.html.markdown b/website/docs/d/pi_placement_groups.html.markdown new file mode 100644 index 000000000..c4ef5d794 --- /dev/null +++ b/website/docs/d/pi_placement_groups.html.markdown @@ -0,0 +1,51 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_placement_groups" +description: |- + Manages placement groups in the Power Virtual Server cloud. +--- + +# ibm_pi_placement_groups +Retrieve information about all placement groups. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_placement_groups" "example" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `placement_groups` - (List) List of all the placement groups. + + Nested scheme for `placement_groups`: + - `id` - (String) The ID of the placement group. + - `name` - (String) User defined name for the placement group. + - `members` - (List of strings) The list of server instances IDs that are members of the placement group. + - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_public_network.html.markdown b/website/docs/d/pi_public_network.html.markdown index 0d5ea6c90..9c00c9d0a 100644 --- a/website/docs/d/pi_public_network.html.markdown +++ b/website/docs/d/pi_public_network.html.markdown @@ -38,7 +38,6 @@ data "ibm_pi_public_network" "ds_public_network" { ## Argument reference Review the argument references that you can specify for your data source. -- `pi_network_name` - (Deprecated, string) The name of the network. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. ## Attribute reference diff --git a/website/docs/d/pi_pvm_snapshots.html.markdown b/website/docs/d/pi_pvm_snapshots.html.markdown new file mode 100644 index 000000000..7a2eeaf5e --- /dev/null +++ b/website/docs/d/pi_pvm_snapshots.html.markdown @@ -0,0 +1,57 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_pvm_snapshots" +description: |- + Manages an pvm instance snapshots in the Power Virtual Server cloud. +--- + +# ibm_pi_pvm_snapshots +Retrieve information about a Power Systems Virtual Server instance snapshots. For more information, about Power Virtual Server PVM instance snapshots, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_pvm_snapshots" "ds_pvm_snapshots" { + pi_instance_name = "terraform-test-instance" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_instance_name` - (Required, String) The name of the instance. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `pvm_snapshots` - The list of Power Virtual Machine instance snapshots. + + Nested scheme for `pvm_snapshots`: + - `action` - (String) Action performed on the instance snapshot. + - `creation_date` - (String) The creation date. + - `description` - (String) The description of the snapshot. + - `id` - (String) The unique identifier of the Power Virtual Machine instance snapshot. + - `last_updated_date` - (String) The last update date. + - `name` - (String) The name of the Power Virtual Machine instance snapshot. + - `percent_complete` - (Integer) The snapshot completion percentage. + - `status` - (String) The status of the Power Virtual Machine instance snapshot. + - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. \ No newline at end of file diff --git a/website/docs/d/pi_sap_profile.html.markdown b/website/docs/d/pi_sap_profile.html.markdown new file mode 100644 index 000000000..2be43b887 --- /dev/null +++ b/website/docs/d/pi_sap_profile.html.markdown @@ -0,0 +1,50 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_sap_profile" +description: |- + Manages SAP profile in the Power Virtual Server cloud. +--- + +# ibm_pi_sap_profile +Retrieve information about a SAP profile. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_sap_profile" "example" { + pi_cloud_instance_id = "" + pi_sap_profile_id = "tinytest-1x4" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_sap_profile_id` - (Required, String) SAP Profile ID. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `certified` - (Boolean) Has certification been performed on profile. +- `cores` - (Integer) Amount of cores. +- `memory` - (Integer) Amount of memory (in GB). +- `type` - (String) Type of profile. diff --git a/website/docs/d/pi_sap_profiles.html.markdown b/website/docs/d/pi_sap_profiles.html.markdown new file mode 100644 index 000000000..4106f1fa8 --- /dev/null +++ b/website/docs/d/pi_sap_profiles.html.markdown @@ -0,0 +1,52 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_sap_profiles" +description: |- + Manages SAP profiles in the Power Virtual Server cloud. +--- + +# ibm_pi_sap_profiles +Retrieve information about all SAP profiles. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_sap_profiles" "example" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `profiles` - (List) List of all the SAP Profiles. + + Nested scheme for `profiles`: + - `certified` - (Boolean) Has certification been performed on profile. + - `cores` - (Integer) Amount of cores. + - `memory` - (Integer) Amount of memory (in GB). + - `profile_id` - (String) SAP Profile ID. + - `type` - (String) Type of profile. diff --git a/website/docs/d/pi_shared_processor_pool.html.markdown b/website/docs/d/pi_shared_processor_pool.html.markdown new file mode 100644 index 000000000..b47e607be --- /dev/null +++ b/website/docs/d/pi_shared_processor_pool.html.markdown @@ -0,0 +1,64 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_shared_processor_pool" +description: |- + Manages a shared processor pool in the Power Virtual Server cloud. +--- + +# ibm_pi_shared_processor_pool +Retrieve information about a shared processor pool. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example Usage + +```terraform +data "ibm_pi_shared_processor_pool" "ds_pool" { + pi_shared_processor_pool_id = "my-spp" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Notes** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_shared_processor_pool_id` - (Required, String) The ID of the shared processor pool. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `allocated_cores` - (Float) The allocated cores in the shared processor pool. +- `available_cores` - (Integer) The available cores in the shared processor pool. +- `host_id` - (Integer) The host ID where the shared processor pool resides. +- `id` - (String) The shared processor pool's unique ID. +- `instances` - (List of Map) The list of server instances that are deployed in the shared processor pool. + Nested scheme for `instances`: + - `availability_zone` - (String) Availability zone for the server instances. + - `cpus` - (Integer) The amount of cpus for the server instance. + - `id` - (String) The server instance ID. + - `memory` - (Integer) The amount of memory for the server instance. + - `name` - (String) The server instance name. + - `status` - (String) Status of the instance. + - `uncapped` - (Bool) Identifies if uncapped or not. + - `vcpus` - (Float) The amout of vcpus for the server instance. +- `name` - (String) The name of the shared processor pool. +- `reserved_cores` - (Integer) The amount of reserved cores for the shared processor pool. +- `status` - (String) The status of the shared processor pool. +- `status_detail` - (String) The status details of the shared processor pool. diff --git a/website/docs/d/pi_shared_processor_pools.html.markdown b/website/docs/d/pi_shared_processor_pools.html.markdown new file mode 100644 index 000000000..dd9ad6d97 --- /dev/null +++ b/website/docs/d/pi_shared_processor_pools.html.markdown @@ -0,0 +1,55 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_shared_processor_pools" +description: |- + Manages the shared processor pools in the Power Virtual Server cloud. +--- + +# ibm_pi_shared_processor_pools +Retrieve information about all shared processor pools. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_shared_processor_pools" "example" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `shared_processor_pools` - (List) List of all the shared processor pools. + + Nested scheme for `shared_processor_pools`: + - `allocated_cores` - (Float) The allocated cores in the shared processor pool. + - `available_cores` - (Integer) The available cores in the shared processor pool. + - `host_id` - (Integer) The host ID where the shared processor pool resides. + - `name` - (String) The name of the shared processor pool. + - `reserved_cores` - (Integer) The amount of reserved cores for the shared processor pool. + - `shared_processor_pool_id` - (String) The shared processor pool's unique ID. + - `status` - (String) The status of the shared processor pool. + - `status_detail` - (String) The status details of the shared processor pool. \ No newline at end of file diff --git a/website/docs/d/pi_spp_placement_group.html.markdown b/website/docs/d/pi_spp_placement_group.html.markdown new file mode 100644 index 000000000..79af4c068 --- /dev/null +++ b/website/docs/d/pi_spp_placement_group.html.markdown @@ -0,0 +1,49 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_spp_placement_group" +description: |- + Manages a shared processor pool placement group in the Power Virtual Server cloud. +--- + +# ibm_pi_spp_placement_group +Retrieve information about a shared processor pool placement group. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example Usage + +```terraform +data "ibm_pi_spp_placement_group" "ds_placement_group" { + pi_spp_placement_group_id = "my-spppg" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +**Notes** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_spp_placement_group_id` - (Required, String) The ID of the shared processor pool placement group. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `members` - (List of strings) The list of shared processor pool IDs that are members of the placement group. +- `name` - (String) The name of the shared processor pool placement group. +- `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_spp_placement_groups.html.markdown b/website/docs/d/pi_spp_placement_groups.html.markdown new file mode 100644 index 000000000..61267fefb --- /dev/null +++ b/website/docs/d/pi_spp_placement_groups.html.markdown @@ -0,0 +1,51 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_spp_placement_groups" +description: |- + Manages the shared processor pool placement groups in the Power Virtual Server cloud. +--- + +# ibm_pi_spp_placement_groups +Retrieve information about all shared processor pool placement groups. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_spp_placement_groups" "example" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `spp_placement_groups` - (List) List of all the shared processor pool placement groups. + + Nested scheme for `spp_placement_groups`: + - `name` - (String) User defined name for the shared processor pool placement group. + - `members` - (List of strings) The list of shared processor pool IDs that are members of the shared processor pool placement group. + - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. + - `spp_placement_group_id` - (String) The ID of the shared processor pool placement group. diff --git a/website/docs/d/pi_storage_pool_capacity.markdown b/website/docs/d/pi_storage_pool_capacity.markdown new file mode 100644 index 000000000..41bc24aa5 --- /dev/null +++ b/website/docs/d/pi_storage_pool_capacity.markdown @@ -0,0 +1,49 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_storage_pool_capacity" +description: |- + Manages storages capacity for a storage pool in the Power Virtual Server cloud. +--- + +# ibm_pi_storage_pool_capacity +Retrieve information about storages capacity for a storage pool in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_storage_pool_capacity" "pool" { + pi_cloud_instance_id = "" + pi_storage_pool = "Tier3-Flash-1" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_storage_pool` - (Required, String) The storage pool name. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `max_allocation_size` - (Integer) Maximum allocation storage size (GB). +- `storage_type` - (String) Storage type of the storage pool. +- `total_capacity` - (Integer) Total pool capacity (GB). diff --git a/website/docs/d/pi_storage_pools_capacity.markdown b/website/docs/d/pi_storage_pools_capacity.markdown new file mode 100644 index 000000000..f5955bbc2 --- /dev/null +++ b/website/docs/d/pi_storage_pools_capacity.markdown @@ -0,0 +1,58 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_storage_pools_capacity" +description: |- + Manages storages capacity for all available storage pools in the Power Virtual Server cloud. +--- + +# ibm_pi_storage_pools_capacity +Retrieve information about storages capacity for all available storage pools in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_storage_pools_capacity" "pools" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `maximum_storage_allocation` - (Map) Maximum storage allocation. + + Nested scheme for `maximum_storage_allocation`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `storage_pool` - (String) The storage pool. + - `storage_type`- (String) The storage type. + +- `storage_pools_capacity` - (List) List of storage pools capacity. + + Nested scheme for `storage_pools_capacity`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `pool_name` - (String) The pool name. + - `storage_type` - (String) Storage type of the storage pool. + - `total_capacity` - (Integer) Total pool capacity (GB). diff --git a/website/docs/d/pi_storage_type_capacity.markdown b/website/docs/d/pi_storage_type_capacity.markdown new file mode 100644 index 000000000..1a53cbc39 --- /dev/null +++ b/website/docs/d/pi_storage_type_capacity.markdown @@ -0,0 +1,61 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_storage_type_capacity" +description: |- + Manages storages capacity for a storage type in the Power Virtual Server cloud. +--- + +# ibm_pi_storage_type_capacity +Retrieve information about storages capacity for a storage type in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_storage_type_capacity" "type" { + pi_cloud_instance_id = "" + pi_storage_type = "tier3" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_storage_type` - (Required, String) The storage type name. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `maximum_storage_allocation` - (Map) Maximum storage allocation. + + Nested scheme for `maximum_storage_allocation`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `storage_pool` - (String) The storage pool. + - `storage_type`- (String) The storage type. + +- `storage_pools_capacity` - (List) List of storage pools capacity. + + Nested scheme for `storage_pools_capacity`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `pool_name` - (String) The pool name. + - `storage_type` - (String) Storage type of the storage pool. + - `total_capacity` - (Integer) Total pool capacity (GB). + \ No newline at end of file diff --git a/website/docs/d/pi_storage_types_capacity.markdown b/website/docs/d/pi_storage_types_capacity.markdown new file mode 100644 index 000000000..1a0c75595 --- /dev/null +++ b/website/docs/d/pi_storage_types_capacity.markdown @@ -0,0 +1,70 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_storage_types_capacity" +description: |- + Manages storages capacity for all available storage types in the Power Virtual Server cloud. +--- + +# ibm_pi_storage_types_capacity +Retrieve information about storages capacity for all available storage types in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_storage_types_capacity" "types" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `maximum_storage_allocation` - (Map) Maximum storage allocation. + + Nested scheme for `maximum_storage_allocation`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `storage_pool` - (String) The storage pool. + - `storage_type`- (String) The storage type. + +- `storage_types_capacity` - (List) List of storage types capacity. + + Nested scheme for `storage_types_capacity`: + - `maximum_storage_allocation` - (Map) Maximum storage allocation. + + Nested scheme for `maximum_storage_allocation`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `storage_pool` - (String) The storage pool. + - `storage_type`- (String) The storage type. + + - `storage_pools_capacity` - (List) List of storage pools capacity. + + Nested scheme for `storage_pools_capacity`: + - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). + - `pool_name` - (String) The pool name. + - `storage_type` - (String) Storage type of the storage pool. + - `total_capacity` - (Integer) Total pool capacity (GB). + + - `storage_type` - (String) The storage type. diff --git a/website/docs/d/pi_system_pools.markdown b/website/docs/d/pi_system_pools.markdown new file mode 100644 index 000000000..28ce84b76 --- /dev/null +++ b/website/docs/d/pi_system_pools.markdown @@ -0,0 +1,88 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_system_pools" +description: |- + Manages system pools within a particular data center in the Power Virtual Server cloud. +--- + +# ibm_pi_system_pools +Retrieve information about list of system pools within a particular data center. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_system_pools" "pools" { + pi_cloud_instance_id = "" +} +``` + +**Notes** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `system_pools` - (List) The available system pools within a particular DataCenter. + + Nested scheme for `system_pools`: + - `system_pool_name` - (String) The system pool name. + - `capacity` - (Map) Advertised capacity cores and memory (GB). + + Nested scheme for `capacity`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. + + - `core_memory_ratio` - (Float) Processor to Memory (GB) Ratio. + - `max_available` - (Map) Maximum configurable cores and memory (GB) (aggregated from all hosts). + + Nested scheme for `max_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. + + - `max_cores_available` - (Map) Maximum configurable cores available combined with available memory of that host. + + Nested scheme for `max_cores_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. + + - `max_memory_available` - (Map) Maximum configurable memory available combined with available cores of that host. + + Nested scheme for `max_memory_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. + + - `shared_core_ratio` - (Map) The min-max-default allocation percentage of shared core per vCPU. + + Nested scheme for `shared_core_ratio`: + - `default` - (String) The default value. + - `max` - (String) The max value. + - `min`- (String) The min value. + + - `systems` - (List) The DataCenter list of servers and their available resources. + + Nested scheme for `systems`: + - `cores` - (String) The host available Processor units. + - `id` - (String) The host identifier. + - `memory`- (String) The host available RAM memory in GiB. + + - `type` - (String) Type of system hardware. diff --git a/website/docs/d/pi_tenant.html.markdown b/website/docs/d/pi_tenant.html.markdown index 06fb73155..1376c8540 100644 --- a/website/docs/d/pi_tenant.html.markdown +++ b/website/docs/d/pi_tenant.html.markdown @@ -44,11 +44,11 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `creation_date` - (Timestamp) The timestamp when the tenant was created. -- `cloudinstances` - (List) A list with the regions and Power Systems Virtual Server instance IDs that the tenant owns. +- `cloud_instances` - (List) A list with the regions and Power Systems Virtual Server instance IDs that the tenant owns. - Nested scheme for `cloudinstances`: + Nested scheme for `cloud_instances`: - `cloud_instance_id` - (String) The unique identifier of the cloud instance. - `region` - (String) The region of the cloud instance. -- `enabled` - (Bool) If set to **true**, the tenant is enabled for the Power Systems Virtual Server instance ID. If set to **false**, the tenant is not enabled for the instance. +- `enabled` - (Bool) Indicates if the tenant is enabled for the Power Systems Virtual Server instance ID. - `id` - (String) The ID of the tenant. -- `tenantname` - (String) The name of the tenant. +- `tenant_name` - (String) The name of the tenant. diff --git a/website/docs/d/resource_group.html.markdown b/website/docs/d/resource_group.html.markdown index 205f81203..7813e2f70 100644 --- a/website/docs/d/resource_group.html.markdown +++ b/website/docs/d/resource_group.html.markdown @@ -39,7 +39,6 @@ In addition to all argument reference list, you can access the following attribu - `account_id` - (String) Account ID. - `crn` - (String) The full CRN associated with the resource group. - `created_at` - (Timestamp) The date when the resource group initially created. -- `default` - (Bool) Specifies whether its default resource group or not. - `id` - (String) The unique identifier of the new resource group. - `payment_methods_url` - (String) The URL to access the payment methods details that is associated with the resource group. - `quota_url` - (String) The URL to access the quota details that is associated with the resource group. diff --git a/website/docs/d/resource_key.html.markdown b/website/docs/d/resource_key.html.markdown index fca830b0c..677183ec9 100644 --- a/website/docs/d/resource_key.html.markdown +++ b/website/docs/d/resource_key.html.markdown @@ -19,6 +19,37 @@ data "ibm_resource_key" "resourceKeydata" { resource_instance_id = ibm_resource_instance.resource.id } ``` +### Example to access resource credentials using credentials attribute: + +```terraform +data "ibm_resource_key" "key" { + name = "myobjectKey" + resource_instance_id = ibm_resource_instance.resource.id +} +output "access_key_id" { + value = data.ibm_resource_key.key.credentials["cos_hmac_keys.access_key_id"] +} +output "secret_access_key" { + value = data.ibm_resource_key.key.credentials["cos_hmac_keys.secret_access_key"] +} +``` +### Example to access resource credentials using credentials_json attribute: + +```terraform +data "ibm_resource_key" "key" { + name = "myobjectKey" + resource_instance_id = ibm_resource_instance.resource.id +} +locals { + resource_credentials = jsondecode(data.ibm_resource_key.key.credentials_json) +} +output "access_key_id" { + value = local.resource_credentials.cos_hmac_keys.access_key_id +} +output "secret_access_key" { + value = local.resource_credentials.cos_hmac_keys.secret_access_key +} +``` ## Argument reference Review the argument references that you can specify for your data source. @@ -31,7 +62,12 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `credentials` - The credentials associated with the key. -- `id` - The unique identifier of the resource key. -- `role` - The user role. -- `status` - The status of the resource key. +- `credentials` - (Map) The credentials associated with the key. +- `credentials_json` - (String) The credentials associated with the key in json format. +- `crn` - (String) CRN of resource key. +- `id` - (String) The unique identifier of the resource key. +- `role` - (String) The user role. +- `status` - (String) The status of the resource key. + +## Note +Credentials will be seen as redacted, if the user does not have access equal to or greater than the access of the service credentials. Please refer to the documentation to access credentials - https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui#viewing-credentials-ui. diff --git a/website/docs/d/resource_tag.html.markdown b/website/docs/d/resource_tag.html.markdown index 36138909a..546db57b0 100644 --- a/website/docs/d/resource_tag.html.markdown +++ b/website/docs/d/resource_tag.html.markdown @@ -3,12 +3,12 @@ subcategory: "Global Tagging" layout: "ibm" page_title: "IBM : resource_tag" description: |- - Manages resource tags. + Retrieve available tags on the account. --- # ibm_resource_tag -Retreive information about an existing resource tags as a read-only data source. For more information, about resource tags, see [controlling access to resources by using tags](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial). +Retreive information about an existing resource or access tags as a read-only data source. For more information, about resource tags, see [controlling access to resources by using tags](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial). ## Example usage @@ -24,13 +24,26 @@ data "ibm_resource_tag" "read_tag" { resource_id = data.ibm_satellite_location.location.crn } ``` +### Retrieve access tags + +```terraform +data "ibm_resource_tag" "access_tags" { + tag_type ="access" +} +``` +### Retrieve user tags + +```terraform +data "ibm_resource_tag" "user_tags" { +} +``` ## Argument reference Review the argument references that you can specify for your data source. -- `resource_id` - (Required, String) The CRN of the resource on which the tags should be attached. +- `resource_id` - (Optional, String) The CRN of the resource on which the tags should be attached. - `resource_type` - (Optional, String) The resource type on which the tags to be attached. - +- `tag_type` - (Optional, String) Type of the tag. Supported values are: `user`, `service`, or `access`. Default: `user` ## Attributes reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/satellite_attach_host_script.html.markdown b/website/docs/d/satellite_attach_host_script.html.markdown index bed0a16b9..824f177ec 100644 --- a/website/docs/d/satellite_attach_host_script.html.markdown +++ b/website/docs/d/satellite_attach_host_script.html.markdown @@ -11,17 +11,17 @@ Retrieve information of an existing IBM Satellite location registration script a ## Example usage -### Sample to create satellite host script to attach IBM host to Satellite control plane +### Sample to read satellite host script to attach IBM host to Satellite control plane ```terraform data "ibm_satellite_attach_host_script" "script" { location = var.location - labels = var.labels + labels = ["cpu:4"] host_provider = "ibm" } ``` -### Sample to create satellite host script to attach AWS EC2 host to Satellite control plane +### Sample to read satellite host script to attach AWS EC2 host to Satellite control plane ```terraform data "ibm_satellite_attach_host_script" "script" { @@ -30,20 +30,37 @@ data "ibm_satellite_attach_host_script" "script" { script_dir = "/tmp" host_provider = "aws" } +``` +### Sample to read satellite host script to attach IBM host to Satellite control plane + +```terraform +data "ibm_satellite_attach_host_script" "script" { + location = var.location + custom_script = < **NOTE**: exporting out the environmental variable `IBM_CLOUD_SCC_ADMIN_API_ENDPOINT` will help out if the account fails to resolve. +## Example usage + +```terraform +data "ibm_scc_account_location" "scc_account_location" { + location_id = "us" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +* `location_id` - (Required, Forces new resource, String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the scc_account_location_properties. + +* `location_id` - (Required, String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. + +* `analytics_endpoint_url` - (Optional, String) The endpoint that is used to generate analytics for the Posture Management component. + +* `compliance_endpoint_url` - (Optional, String) The endpoint that is used to call the Posture Management APIs. + +* `governance_endpoint_url` - (Optional, String) The endpoint that is used to call the Configuration Governance APIs. + +* `main_endpoint_url` - (Optional, String) The base URL for the service. + +* `results_endpoint_url` - (Optional, String) The endpoint that is used to get the results for the Configuration Governance component. + +* `regions` - (Optional, List) Nested scheme for **regions**: + * `id` - (Required, String) The programatic ID of the available regions. + * Constraints: Allowable values are: `us`, `eu`, `uk`. \ No newline at end of file diff --git a/website/docs/d/scc_account_location_settings.html.markdown b/website/docs/d/scc_account_location_settings.html.markdown new file mode 100644 index 000000000..6a7cc255e --- /dev/null +++ b/website/docs/d/scc_account_location_settings.html.markdown @@ -0,0 +1,27 @@ +--- +layout: "ibm" +subcategory: "Security and Compliance Center" +page_title: "IBM : ibm_scc_account_settings" +description: |- + Get information about scc_account_location_settings +--- + +# ibm_scc_account_settings + +Provides a read-only data source for scc_account_location_settings. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +~> **NOTE**: exporting out the environmental variable `IBM_CLOUD_SCC_ADMIN_API_ENDPOINT` will help out if the account fails to resolve. +## Example usage + +```terraform +data "ibm_scc_account_settings" "scc_account_location_settings" { +} +``` + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - (String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. diff --git a/website/docs/d/scc_account_locations.html.markdown b/website/docs/d/scc_account_locations.html.markdown new file mode 100644 index 000000000..27addeafb --- /dev/null +++ b/website/docs/d/scc_account_locations.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "ibm" +subcategory: "Security and Compliance Center" +page_title: "IBM : ibm_scc_account_locations" +description: |- + Get information about scc_account_locations +--- + +# ibm_scc_account_locations + +Provides a read-only data source for scc_account_locations. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_scc_account_locations" "scc_account_locations" { +} +``` + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the scc_account_locations. +* `locations` - (List) +Nested scheme for **locations**: + * `analytics_endpoint_url` - (String) The endpoint that is used to generate analytics for the Posture Management component. + * `compliance_endpoint_url` - (String) The endpoint that is used to call the Posture Management APIs. + * `governance_endpoint_url` - (String) The endpoint that is used to call the Configuration Governance APIs. + * `id` - (String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. + * `main_endpoint_url` - (String) The base URL for the service. + * `regions` - (List) + Nested scheme for **regions**: + * `id` - (String) The programatic ID of the available regions. + * Constraints: Allowable values are: `us`, `eu`, `uk`. + * `results_endpoint_url` - (String) The endpoint that is used to get the results for the Configuration Governance component. diff --git a/website/docs/d/scc_account_notification_settings.html.markdown b/website/docs/d/scc_account_notification_settings.html.markdown new file mode 100644 index 000000000..921ac31d4 --- /dev/null +++ b/website/docs/d/scc_account_notification_settings.html.markdown @@ -0,0 +1,27 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_account_notification_settings" +description: |- + Get information about scc_account_notification_settings +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_account_notification_settings + +Provides a read-only data source for scc_account_notification_settings. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +~> **NOTE**: exporting out the environmental variable `IBM_CLOUD_SCC_ADMIN_API_ENDPOINT` will help out if the account fails to resolve. + +## Example Usage + +```hcl +data "ibm_scc_account_notification_settings" "scc_account_notification_settings" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `instance_crn` - (Optional, String) The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect. diff --git a/website/docs/d/scc_posture_collector.html.markdown b/website/docs/d/scc_posture_collector.html.markdown new file mode 100644 index 000000000..7d9dfc600 --- /dev/null +++ b/website/docs/d/scc_posture_collector.html.markdown @@ -0,0 +1,97 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_collector" +description: |- + Get information about collector +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_collector + +Provides a read-only data source for collector. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_collector" "collector" { + collector_id = "collector_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `collector_id` - (Required, Forces new resource, String) The id for the given API. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the collector. +* `approved_internet_gateway_ip` - (Optional, String) The approved internet gateway ip of the collector. This field will be populated only when collector is installed. + +* `approved_local_gateway_ip` - (Optional, String) The approved local gateway ip of the collector. This field will be populated only when collector is installed. + +* `collector_version` - (Optional, String) The collector version. This field is populated when collector is installed. + +* `created_at` - (Required, String) The ISO Date/Time the collector was created. + +* `created_by` - (Required, String) The id of the user that created the collector. + +* `credential_public_key` - (Optional, String) The credential public key. + +* `description` - (Required, String) The description of the collector. + +* `display_name` - (Required, String) The user-friendly name of the collector. + +* `enabled` - (Required, Boolean) Identifies whether the collector is enabled or not(deleted). + +* `failure_count` - (Required, Integer) The number of times the collector has failed. + +* `hostname` - (Optional, String) The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name. + +* `image_version` - (Optional, String) The image version of the collector. This field is populated when collector is installed. ". + +* `install_path` - (Optional, String) The installation path of the collector. This field will be populated when collector is installed.The value will be folder path. + +* `is_public` - (Required, Boolean) Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. + +* `is_ubi_image` - (Optional, Boolean) Determines whether the collector has a Ubi image. + +* `last_failed_internet_gateway_ip` - (Optional, String) The failed internet gateway ip of the collector. + +* `last_failed_local_gateway_ip` - (Optional, String) The failed local gateway ip. This field will be populated only when collector is installed. + +* `last_heartbeat` - (Optional, String) Stores the heartbeat time of a controller . This value exists when collector is installed and running. + +* `managed_by` - (Required, String) The entity that manages the collector. + * Constraints: Allowable values are: `ibm`, `customer`. + +* `name` - (Required, String) The name of the collector. + +* `public_key` - (Optional, String) The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed. + +* `registration_code` - (Required, String) The registration code of the collector.This is will be used for initial authentication during installation of collector. + +* `reset_reason` - (Optional, String) The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field . + +* `reset_time` - (Optional, String) The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field. + +* `status` - (Required, String) The status of collector. + * Constraints: Allowable values are: `ready_to_install`, `core_downloaded`, `approval_required`, `approved_download_in_progress`, `approved_install_in_progress`, `install_in_progress`, `installed`, `installed_credentials_required`, `installed_assigning_credentials`, `active`, `unable_to_connect`, `waiting_for_upgrade`, `suspended`, `installation_failed`. + +* `status_description` - (Required, String) The collector status. + +* `trial_expiry` - (Optional, String) The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed. + +* `type` - (Required, String) The type of the collector. + * Constraints: Allowable values are: `restricted`, `unrestricted`. + +* `updated_at` - (Required, String) The ISO Date/Time the collector was modified. + +* `updated_by` - (Required, String) The id of the user that modified the collector. + +* `use_private_endpoint` - (Required, Boolean) Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false. + diff --git a/website/docs/d/scc_posture_collectors.html.markdown b/website/docs/d/scc_posture_collectors.html.markdown new file mode 100644 index 000000000..e4227a1b6 --- /dev/null +++ b/website/docs/d/scc_posture_collectors.html.markdown @@ -0,0 +1,85 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_collectors" +description: |- + Get information about list_collectors +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_collectors + +Provides a read-only data source for list_collectors. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_collectors" "list_collectors" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the list_collectors. +* `collectors` - (List) The array of items returned. +Nested scheme for **collectors**: + * `approved_internet_gateway_ip` - (String) The approved internet gateway ip of the collector. This field will be populated only when collector is installed. + * `approved_local_gateway_ip` - (String) The approved local gateway ip of the collector. This field will be populated only when collector is installed. + * `collector_version` - (String) The collector version. This field is populated when collector is installed. + * `created_at` - (String) The ISO Date/Time the collector was created. + * `created_by` - (String) The id of the user that created the collector. + * `credential_public_key` - (String) The credential public key. + * `description` - (String) The description of the collector. + * `display_name` - (String) The user-friendly name of the collector. + * `enabled` - (Boolean) Identifies whether the collector is enabled or not(deleted). + * `failure_count` - (Integer) The number of times the collector has failed. + * `hostname` - (String) The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name. + * `id` - (String) The id of the collector. + * `image_version` - (String) The image version of the collector. This field is populated when collector is installed. ". + * `install_path` - (String) The installation path of the collector. This field will be populated when collector is installed.The value will be folder path. + * `is_public` - (Boolean) Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. + * `is_ubi_image` - (Boolean) Determines whether the collector has a Ubi image. + * `last_failed_internet_gateway_ip` - (String) The failed internet gateway ip of the collector. + * `last_failed_local_gateway_ip` - (String) The failed local gateway ip. This field will be populated only when collector is installed. + * `last_heartbeat` - (String) Stores the heartbeat time of a controller . This value exists when collector is installed and running. + * `managed_by` - (String) The entity that manages the collector. + * Constraints: Allowable values are: `ibm`, `customer`. + * `name` - (String) The name of the collector. + * `public_key` - (String) The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed. + * `registration_code` - (String) The registration code of the collector.This is will be used for initial authentication during installation of collector. + * `reset_reason` - (String) The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field . + * `reset_time` - (String) The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field. + * `status` - (String) The status of collector. + * Constraints: Allowable values are: `ready_to_install`, `core_downloaded`, `approval_required`, `approved_download_in_progress`, `approved_install_in_progress`, `install_in_progress`, `installed`, `installed_credentials_required`, `installed_assigning_credentials`, `active`, `unable_to_connect`, `waiting_for_upgrade`, `suspended`, `installation_failed`. + * `status_description` - (String) The collector status. + * `trial_expiry` - (String) The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed. + * `type` - (String) The type of the collector. + * Constraints: Allowable values are: `restricted`, `unrestricted`. + * `updated_at` - (String) The ISO Date/Time the collector was modified. + * `updated_by` - (String) The id of the user that modified the collector. + * `use_private_endpoint` - (Boolean) Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false. + +* `first` - (List) The URL of a page. +Nested scheme for **first**: + * `href` - (String) The URL of a page. + +* `last` - (List) The URL of a page. +Nested scheme for **last**: + * `href` - (String) The URL of a page. + +* `limit` - (Integer) The number of items to return. + +* `next` - (List) The URL of a page. +Nested scheme for **next**: + * `href` - (String) The URL of a page. + +* `offset` - (Integer) The offset from the start of the list (0-based). + +* `previous` - (List) The URL of a page. +Nested scheme for **previous**: + * `href` - (String) The URL of a page. + +* `total_count` - (Integer) The total number of items in the list. This will have value as 0 when no collectors are available and below values will not be populated in that case. + diff --git a/website/docs/d/scc_posture_credential.html.markdown b/website/docs/d/scc_posture_credential.html.markdown new file mode 100644 index 000000000..8d3f52f59 --- /dev/null +++ b/website/docs/d/scc_posture_credential.html.markdown @@ -0,0 +1,110 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_credential" +description: |- + Get information about credential +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_credential + +Provides a read-only data source for credential. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_credential" "credential" { + credential_id = "credential_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `id` - (Required, Forces new resource, String) The id for the given API. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `credential_id` - The unique identifier of the credential. +* `created_at` - (Required, String) The time that the credentials was created in UTC. + +* `created_by` - (Required, String) ID of the user who created the credentials. + +* `description` - (Required, String) Credentials description. + +* `display_fields` - (Required, List) Details the fields on the credential. This will change as per credential type selected. +Nested scheme for **display_fields**: + * `auth_url` - (Optional, String) auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_arn` - (Optional, String) AWS arn value. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_id` - (Optional, String) AWS client Id.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_secret` - (Optional, String) AWS client secret.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_region` - (Optional, String) AWS region. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_id` - (Optional, String) Azure client Id. This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_secret` - (Optional, String) Azure client secret.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_resource_group` - (Optional, String) Azure resource group. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_subscription_id` - (Optional, String) Azure subscription Id.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `database_name` - (Optional, String) Database name.This is mandatory for Database Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ibm_api_key` - (Optional, String) The IBM Cloud API Key. This is mandatory for IBM Credential Type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_client_id` - (Optional, String) The MS365 client Id.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_client_secret` - (Optional, String) The MS365 client secret.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_tenant_id` - (Optional, String) The MS365 tenantId.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `password` - (Optional, String) password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `pem_data` - (Optional, String) The base64 encoded data to associate with the PEM file. + * Constraints: The maximum length is `4000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `pem_file_name` - (Optional, String) The name of the PEM file. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `project_domain_name` - (Optional, String) project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `project_name` - (Optional, String) Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `user_domain_name` - (Optional, String) user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `username` - (Optional, String) username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_authtype` - (Optional, String) Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_port` - (Optional, String) Kerberos windows port.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `winrm_usessl` - (Optional, String) Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `enabled` - (Required, Boolean) Credentials status enabled/disbaled. + +* `group` - (Required, List) Credential group details. +Nested scheme for **group**: + * `id` - (Required, String) credential group id. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `passphrase` - (Required, String) passphase of the credential. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + +* `name` - (Required, String) Credentials name. + +* `purpose` - (Required, String) Purpose for which the credential is created. + * Constraints: Allowable values are: `discovery_collection`, `discovery_fact_collection`, `remediation`, `discovery_collection_remediation`, `discovery_fact_collection_remediation`. + +* `type` - (Required, String) Credentials type. + * Constraints: Allowable values are: `username_password`, `aws_cloud`, `azure_cloud`, `database`, `kerberos_windows`, `ms_365`, `openstack_cloud`, `ibm_cloud`, `user_name_pem`. + +* `updated_at` - (Required, String) The modified time that the credentials was modified in UTC. + +* `updated_by` - (Required, String) ID of the user who modified the credentials. + diff --git a/website/docs/d/scc_posture_credentials.html.markdown b/website/docs/d/scc_posture_credentials.html.markdown new file mode 100644 index 000000000..8a4c9cd0c --- /dev/null +++ b/website/docs/d/scc_posture_credentials.html.markdown @@ -0,0 +1,108 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_credentials" +description: |- + Get information about list_credentials +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_credentials + +Provides a read-only data source for list_credentials. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_credentials" "list_credentials" { +} +``` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the list_credentials. +* `credentials` - (List) The details of a credentials. +Nested scheme for **credentials**: + * `created_at` - (String) The time that the credentials was created in UTC. + * `created_by` - (String) ID of the user who created the credentials. + * `description` - (String) Credentials description. + * `display_fields` - (List) Details the fields on the credential. This will change as per credential type selected. + Nested scheme for **display_fields**: + * `auth_url` - (String) auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_arn` - (String) AWS arn value. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_id` - (String) AWS client Id.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_secret` - (String) AWS client secret.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_region` - (String) AWS region. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_id` - (String) Azure client Id. This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_secret` - (String) Azure client secret.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_resource_group` - (String) Azure resource group. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_subscription_id` - (String) Azure subscription Id.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `database_name` - (String) Database name.This is mandatory for Database Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ibm_api_key` - (String) The IBM Cloud API Key. This is mandatory for IBM Credential Type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_client_id` - (String) The MS365 client Id.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_client_secret` - (String) The MS365 client secret.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_tenant_id` - (String) The MS365 tenantId.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `password` - (String) password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `pem_data` - (String) The base64 encoded data to associate with the PEM file. + * Constraints: The maximum length is `4000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `pem_file_name` - (String) The name of the PEM file. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `project_domain_name` - (String) project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `project_name` - (String) Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `user_domain_name` - (String) user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `username` - (String) username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_authtype` - (String) Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_port` - (String) Kerberos windows port.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `winrm_usessl` - (String) Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `enabled` - (Boolean) Credentials status enabled/disbaled. + * `group` - (List) Credential group details. + Nested scheme for **group**: + * `id` - (String) credential group id. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `passphrase` - (String) passphase of the credential. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `id` - (String) Credentials ID. + * `name` - (String) Credentials name. + * `purpose` - (String) Purpose for which the credential is created. + * Constraints: Allowable values are: `discovery_collection`, `discovery_fact_collection`, `remediation`, `discovery_collection_remediation`, `discovery_fact_collection_remediation`. + * `type` - (String) Credentials type. + * Constraints: Allowable values are: `username_password`, `aws_cloud`, `azure_cloud`, `database`, `kerberos_windows`, `ms_365`, `openstack_cloud`, `ibm_cloud`, `user_name_pem`. + * `updated_at` - (String) The modified time that the credentials was modified in UTC. + * `updated_by` - (String) ID of the user who modified the credentials. + +* `first` - (List) The URL of a page. +Nested scheme for **first**: + * `href` - (String) The URL of a page. + +* `last` - (List) The URL of a page. +Nested scheme for **last**: + * `href` - (String) The URL of a page. + +* `previous` - (List) The URL of a page. +Nested scheme for **previous**: + * `href` - (String) The URL of a page. + diff --git a/website/docs/d/scc_posture_group_profile.html.markdown b/website/docs/d/scc_posture_group_profile.html.markdown new file mode 100644 index 000000000..c59cb2525 --- /dev/null +++ b/website/docs/d/scc_posture_group_profile.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_group_profile" +description: |- + Get information about group_profile_details +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_group_profile + +Provides a read-only data source for group_profile_details. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_group_profile" "group_profile_details" { + profile_id = "profile_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `profile_id` - (Required, Forces new resource, String) The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the group_profile_details. +* `controls` - (List) Profiles array. +Nested scheme for **controls**: + * `description` - (String) The description of the control. + * `external_control_id` - (String) The external identifier number of the control. + * `goals` - (List) Mapped goals aganist the control identifier. + Nested scheme for **goals**: + * `description` - (String) The description of the goal. + * `id` - (String) The goal ID. + * `is_auto_remediable` - (Boolean) The goal is autoremediable or not. + * `is_automatable` - (Boolean) The goal is automatable or not. + * `is_manual` - (Boolean) The goal is manual check. + * `is_remediable` - (Boolean) The goal is remediable or not. + * `is_reversible` - (Boolean) The goal is reversible or not. + * `severity` - (String) The severity of the goal. + * `id` - (String) The identifier number of the control. + +* `first` - (List) The URL of a page. +Nested scheme for **first**: + * `href` - (String) The URL of a page. + +* `last` - (List) The URL of a page. +Nested scheme for **last**: + * `href` - (String) The URL of a page. + +* `previous` - (List) The URL of a page. +Nested scheme for **previous**: + * `href` - (String) The URL of a page. + diff --git a/website/docs/d/scc_posture_latest_scans.html.markdown b/website/docs/d/scc_posture_latest_scans.html.markdown index 9a18197f9..abc3d1e6b 100644 --- a/website/docs/d/scc_posture_latest_scans.html.markdown +++ b/website/docs/d/scc_posture_latest_scans.html.markdown @@ -8,64 +8,68 @@ subcategory: "Security and Compliance Center" # ibm_scc_posture_latest_scans -Review information about the security and compliance center posture latest scans. For more information, about latest scans, see [viewing evaluation results](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-results). +Provides a read-only data source for list_latest_scans. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_scc_posture_latest_scans" "list_latest_scans" { scan_id = "262" } ``` -## Argument reference +## Argument Reference Review the argument reference that you can specify for your data source. * `scan_id` - (Optional, String) The ID of the scan. -## Attribute reference +## Attribute Reference In addition to all argument references listed, you can access the following attribute references after your data source is created. -* `id` - The unique identifier of the `list_latest_scans`. -* `first` - (Optional, List) The URL of the first page of scans. +* `id` - The unique identifier of the list_latest_scans. +* `first` - (List) The URL of a page. Nested scheme for **first**: - * `href` - (Optional, String) The URL of the first page of scans. + * `href` - (String) The URL of a page. -* `last` - (Optional, List) The URL of the last page of scans. +* `last` - (List) The URL of a page. Nested scheme for **last**: - * `href` - (Optional, String) The URL of the last page of scans. + * `href` - (String) The URL of a page. -* `latest_scans` - (Optional, List) The details of a scan. +* `latest_scans` - (List) The details of a scan. Nested scheme for **latest_scans**: - * `scan_id` - (Optional, String) The ID of the scan. - * `scan_name` - (Optional, String) A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name. - * `scope_id` - (Optional, String) The ID of the scan. - * `scope_name` - (Optional, String) The name of the scope. - * `profile_id` - (Optional, String) The ID of the profile. - * `profile_name` - (Optional, String) The name of the profile. - * `profile_type` - (Optional, String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). - * Constraints: Allowable values are: **standard**, **authored**, **custom**, **standard_cv**, **temmplategroup**, **standard_certificate** - * `group_profile_id` - (Optional, String) The group ID of profile. - * `group_profile_name` - (Optional, String) The group name of the profile. - * `report_run_by` - (Optional, String) The entity that ran the report. - * `start_time` - (Optional, String) The date and time the scan was run. - * `end_time` - (Optional, String) The date and time the scan completed. - * `result` - (Optional, List) The result of a scan. + * `end_time` - (String) The date and time the scan completed. + * `group_profile_id` - (String) The group ID of profile. + * `group_profile_name` - (String) The group name of the profile. + * `profiles` - (List) Profiles array. + Nested scheme for **profiles**: + * `id` - (String) An auto-generated unique identifier for the scope. + * `name` - (String) The name of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `type` - (String) The type of profile. + * Constraints: Allowable values are: `predefined`, `custom`, `template_group`. + * `report_run_by` - (String) The entity that ran the report. + * `report_setting_id` - (String) The unique ID for Scan that is created. + * `result` - (List) The result of a scan.The above values will not be avaialble if no scopes are available. Nested scheme for **result**: - * `goals_pass_count` - (Optional, Integer) The number of goals that passed the scan. - * `goals_unable_to_perform_count` - (Optional, Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `goals_not_applicable_count` - (Optional, Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `goals_fail_count` - (Optional, Integer) The number of goals that failed the scan. - * `goals_total_count` - (Optional, Integer) The total number of goals that were included in the scan. - * `controls_pass_count` - (Optional, Integer) The number of controls that passed the scan. - * `controls_fail_count` - (Optional, Integer) The number of controls that failed the scan. - * `controls_not_applicable_count` - (Optional, Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `controls_unable_to_perform_count` - (Optional, Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `controls_total_count` - (Optional, Integer) The total number of controls that were included in the scan. + * `controls_fail_count` - (Integer) The number of controls that failed the scan. + * `controls_not_applicable_count` - (Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `controls_pass_count` - (Integer) The number of controls that passed the scan. + * `controls_total_count` - (Integer) The total number of controls that were included in the scan. + * `controls_unable_to_perform_count` - (Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `goals_fail_count` - (Integer) The number of goals that failed the scan. + * `goals_not_applicable_count` - (Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `goals_pass_count` - (Integer) The number of goals that passed the scan. + * `goals_total_count` - (Integer) The total number of goals that were included in the scan. + * `goals_unable_to_perform_count` - (Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `scan_id` - (String) The ID of the scan. + * `scan_name` - (String) A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name. + * `scope_id` - (String) The scope ID of the scan. + * `scope_name` - (String) The name of the scope. + * `start_time` - (String) The date and time the scan was run. -* `previous` - (Optional, List) The URL of the previous page of scans. +* `previous` - (List) The URL of a page. Nested scheme for **previous**: - * `href` - (Optional, String) The URL of the previous page of scans. + * `href` - (String) The URL of a page. diff --git a/website/docs/d/scc_posture_profile.html.markdown b/website/docs/d/scc_posture_profile.html.markdown new file mode 100644 index 000000000..c7cb2410a --- /dev/null +++ b/website/docs/d/scc_posture_profile.html.markdown @@ -0,0 +1,67 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_profile" +description: |- + Get information about profileDetails +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_profile + +Provides a read-only data source for profileDetails. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_profile" "profile_details" { + id = "id" + profile_type = "profile_type" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `id` - (Required, Forces new resource, String) The id for the given API. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. +* `profile_type` - (Required, String) The profile type ID. This will be 4 for profiles and 6 for group profiles. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the profileDetails. +* `base_profile` - (String) The base profile that the controls are pulled from. + +* `created_at` - (String) The time that the profile was created in UTC. + +* `created_by` - (String) The user who created the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `description` - (String) A description of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `enabled` - (Boolean) The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false. + +* `modified_by` - (String) The user who last modified the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `name` - (String) The name of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `no_of_controls` - (Integer) no of Controls. + * Constraints: The minimum value is `1`. + +* `reason_for_delete` - (String) A reason that you want to delete a profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +* `type` - (String) The type of profile. + * Constraints: Allowable values are: `predefined`, `custom`, `template_group`. + +* `updated_at` - (String) The time that the profile was most recently modified in UTC. + +* `version` - (Integer) The version of the profile. + * Constraints: The minimum value is `1`. + diff --git a/website/docs/d/scc_posture_profiles.html.markdown b/website/docs/d/scc_posture_profiles.html.markdown index 097a31f91..85777e5ba 100644 --- a/website/docs/d/scc_posture_profiles.html.markdown +++ b/website/docs/d/scc_posture_profiles.html.markdown @@ -8,74 +8,55 @@ subcategory: "Security and Compliance Center" # ibm_scc_posture_profiles -Review information about the security and compliance center posture latest scans. For more information, about profiles see [What is a profile?](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). +Provides a read-only data source for list_profiles. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_scc_posture_profiles" "list_profiles" { - profile_id = "3045" } ``` -## Argument reference -Review the argument reference that you can specify for your data source. - -* `profile_id` - (Optional, String) An auto-generated unique identifying number of the profile. - -## Attribute reference +## Attribute Reference In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the list_profiles. -* `first` - (Optional, List) The URL of the first page of profiles. +* `first` - (List) The URL of a page. Nested scheme for **first**: - * `href` - (Optional, String) The URL of the first page of profiles. + * `href` - (String) The URL of a page. -* `last` - (Optional, List) The URL of the last page of profiles. +* `last` - (List) The URL of a page. Nested scheme for **last**: - * `href` - (Optional, String) The URL of the last page of profiles. + * `href` - (String) The URL of a page. -* `previous` - (Optional, List) The URL of the previous page of profiles. +* `previous` - (List) The URL of a page. Nested scheme for **previous**: - * `href` - (Optional, String) The URL of the previous page of profiles. + * `href` - (String) The URL of a page. -* `profiles` - (Optional, List) Profiles. +* `profiles` - (List) Profiles. Nested scheme for **profiles**: - * `applicability_criteria` - (Optional, List) The criteria that defines how a profile applies. - Nested scheme for **applicability_criteria**: - * `additional_details` - (Optional, Map) Any additional details about the profile. - * `environment` - (Optional, List) A list of environments that a profile can be applied to. - * `environment_category` - (Optional, List) The type of environment that a profile is able to be applied to. - * `environment_category_description` - (Optional, Map) The type of environment that your scope is targeted to. - * `environment_description` - (Optional, Map) The environment that your scope is targeted to. - * `os_details` - (Optional, List) The Operating System that the profile applies to. - Nested scheme for **os_details**: - * `name` - (Optional, String) - * `version` - (Optional, String) - * `resource` - (Optional, List) A list of resources that a profile can be used with. - * `resource_category` - (Optional, List) The type of resource that a profile is able to be applied to. - * `resource_category_description` - (Optional, Map) The type of resource that your scope is targeted to. - * `resource_description` - (Optional, Map) The resource that is scanned as part of your scope. - * `resource_type` - (Optional, List) The resource type that the profile applies to. - * `resource_type_description` - (Optional, Map) A further classification of the type of resource that your scope is targeted to. - * `software_details` - (Optional, List) The software that the profile applies to. - Nested scheme for **software_details**: - * `name` - (Optional, String) - * `version` - (Optional, String) - * `base_profile` - (Optional, String) The base profile that the controls are pulled from. - * `created_by` - (Optional, String) The user who created the profile. - * `created_time` - (Optional, String) The time that the profile was created in UTC. - * `description` - (Optional, String) A description of the profile. - * `enabled` - (Optional, Boolean) The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false. - * `modified_by` - (Optional, String) The user who last modified the profile. - * `modified_time` - (Optional, String) The time that the profile was most recently modified in UTC. - * `name` - (Optional, String) The name of the profile. - * `profile_id` - (Optional, String) An auto-generated unique identifying number of the profile. - * `profile_type` - (Optional, String) The type of profile. - * Constraints: Allowable values are: **predefined**, **custom**, **template_group** - * `reason_for_delete` - (Optional, String) A reason that you want to delete a profile. - * `version` - (Optional, Integer) The version of the profile. - * Constraints: The minimum value is `1`. - + * `base_profile` - (String) The base profile that the controls are pulled from. + * `created_at` - (String) The time that the profile was created in UTC. + * `created_by` - (String) The user who created the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `description` - (String) A description of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `enabled` - (Boolean) The profile status. If the profile is enabled, the value is true. If the profile is disabled, the value is false. + * `id` - (String) An auto-generated unique identifying number of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `modified_by` - (String) The user who last modified the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `name` - (String) The name of the profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `no_of_controls` - (Integer) no of Controls. + * Constraints: The minimum value is `1`. + * `reason_for_delete` - (String) A reason that you want to delete a profile. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `type` - (String) The type of profile. + * Constraints: Allowable values are: `predefined`, `custom`, `template_group`. + * `updated_at` - (String) The time that the profile was most recently modified in UTC. + * `version` - (Integer) The version of the profile. + * Constraints: The minimum value is `1`. + diff --git a/website/docs/d/scc_posture_scan_summaries.html.markdown b/website/docs/d/scc_posture_scan_summaries.html.markdown index 5633e39cd..d07594441 100644 --- a/website/docs/d/scc_posture_scan_summaries.html.markdown +++ b/website/docs/d/scc_posture_scan_summaries.html.markdown @@ -8,102 +8,85 @@ subcategory: "Security and Compliance Center" # ibm_scc_posture_scan_summaries -Review information of Security and Compliance Center scan summaries see [viewing evaluation results](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-results). +Provides a read-only data source for scan_summaries. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_scc_posture_scan_summaries" "scan_summaries" { - profile_id = "profile_id" - scan_id = "262" - scope_id = "scope_id" + report_setting_id = "report_setting_id" } ``` -## Argument reference +## Argument Reference Review the argument reference that you can specify for your data source. -* `profile_id` - (Required, String) The profile ID. This can be obtained from the Security and Compliance Center console by clicking on the profile name. The URL contains the ID. -* `scan_id` - (Optional, String) The scan ID of the scan. -* `scope_id` - (Required, String) The scope ID. This can be obtained from the Security and Compliance Center console by clicking on the scope name. The URL contains the ID. +* `report_setting_id` - (Required, String) The report setting ID. This can be obtained from the /validations/latest_scans API call. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. -## Attribute reference +## Attribute Reference In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the scan_summaries. -* `first` - (Optional, List) The URL of the first scan summary. +* `first` - (List) The URL of a page. Nested scheme for **first**: - * `href` - (Optional, String) The URL of the first scan summary. -* `last` - (Optional, List) The URL of the last scan summary. + * `href` - (String) The URL of a page. + +* `last` - (List) The URL of a page. Nested scheme for **last**: - * `href` - (Optional, String) The URL of the last scan summary. -* `previous` - (Optional, List) The URL of the previous scan summary. + * `href` - (String) The URL of a page. + +* `previous` - (List) The URL of a page. Nested scheme for **previous**: - * `href` - (Optional, String) The URL of the previous scan summary. -* `summaries` - (Optional, List) Summaries. + * `href` - (String) The URL of a page. + +* `summaries` - (List) Summaries. Nested scheme for **summaries**: - * `scan_id` - (Optional, String) The ID of the scan. - * `scan_name` - (Optional, String) A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name. - * `scope_id` - (Optional, String) The ID of the scan. - * `scope_name` - (Optional, String) The name of the scope. - * `report_run_by` - (Optional, String) The entity that ran the report. - * `start_time` - (Optional, String) The date and time the scan was run. - * `end_time` - (Optional, String) The date and time the scan completed. - * `status` - (Optional, String) The status of the collector as it completes a scan. - * Constraints: - * Supported values are: **pending**, **discovery_started**, **discovery_completed**, **error_in_discovery**, **gateway_aborted**, **controller_aborted**, **not_accepted**, **waiting_for_refine**, **validation_started**, **validation_completed**, **sent_to_collector**, **discovery_in_progress**, **validation_in_progress**, **error_in_validation**, **discovery_result_posted_with_error**, **discovery_result_posted_no_error**, **validation_result_posted_with_error**, **validation_result_posted_no_error**, **fact_collection_started**, **fact_collection_in_progress**, **fact_collection_completed**, **error_in_fact_collection**, **fact_validation_started**, **fact_validation_in_progress**, **fact_validation_completed**, **error_in_fact_validation**, **abort_task_request_received**, **error_in_abort_task_request**, **abort_task_request_completed**, **user_aborted**, **abort_task_request_failed**, **remediation_started**, **remediation_in_progress**, **error_in_remediation**, **remediation_completed**, **inventory_started**, **inventory_in_progress**, **inventory_completed**, **error_in_inventory**, **inventory_completed_with_error** - * `profile` - (Optional, List) The result of a profile. - Nested scheme for **profile**: - * `profile_id` - (Optional, String) The ID of the profile. - * `profile_name` - (Optional, String) The name of the profile. - * `profile_type` - (Optional, String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). - * Constraints: - * Supported values are: **standard**, **authored**, **custom**, **standard_cv**, **templategroup**, **standard_certificate** - * `validation_result` - (Optional, List) The result of a scan. - Nested scheme for **validation_result**: - * `goals_pass_count` - (Optional, Integer) The number of goals that passed the scan. - * `goals_unable_to_perform_count` - (Optional, Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `goals_not_applicable_count` - (Optional, Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `goals_fail_count` - (Optional, Integer) The number of goals that failed the scan. - * `goals_total_count` - (Optional, Integer) The total number of goals that were included in the scan. - * `controls_pass_count` - (Optional, Integer) The number of controls that passed the scan. - * `controls_fail_count` - (Optional, Integer) The number of controls that failed the scan. - * `controls_not_applicable_count` - (Optional, Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `controls_unable_to_perform_count` - (Optional, Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `controls_total_count` - (Optional, Integer) The total number of controls that were included in the scan. - * `group_profiles` - (Optional, List) The result of a group profile. + * `end_time` - (String) The date and time the scan completed. + * `group_profiles` - (List) The list of group profiles. Nested scheme for **group_profiles**: - * `group_profile_id` - (Optional, String) The group ID of profile. - * `group_profile_name` - (Optional, String) The group name of the profile. - * `profile_type` - (Optional, String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). - * Constraints: - * Supported values are **standard**, **authored**, **custom**, **standard_cv**, **templategroup**, **standard_certificate** - * `validation_result` - (Optional, List) The result of a scan. + * `id` - (String) The ID of the profile. + * `name` - (String) The name of the profile. + * `type` - (String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). + * Constraints: Allowable values are: `standard`, `authored`, `custom`, `standard_cv`, `temmplategroup`, `standard_certificate`, `predefined`. + * `validation_result` - (List) The result of a scan.The above values will not be avaialble if no scopes are available. + Nested scheme for **validation_result**: + * `controls_fail_count` - (Integer) The number of controls that failed the scan. + * `controls_not_applicable_count` - (Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `controls_pass_count` - (Integer) The number of controls that passed the scan. + * `controls_total_count` - (Integer) The total number of controls that were included in the scan. + * `controls_unable_to_perform_count` - (Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `goals_fail_count` - (Integer) The number of goals that failed the scan. + * `goals_not_applicable_count` - (Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `goals_pass_count` - (Integer) The number of goals that passed the scan. + * `goals_total_count` - (Integer) The total number of goals that were included in the scan. + * `goals_unable_to_perform_count` - (Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `id` - (String) The ID of the scan. + * `name` - (String) A system generated name that is the combination of 12 characters in the scope name and 12 characters of a profile name. + * `profiles` - (List) The list of profiles. + Nested scheme for **profiles**: + * `id` - (String) The ID of the profile. + * `name` - (String) The name of the profile. + * `type` - (String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). + * Constraints: Allowable values are: `standard`, `authored`, `custom`, `standard_cv`, `temmplategroup`, `standard_certificate`, `predefined`. + * `validation_result` - (List) The result of a scan.The above values will not be avaialble if no scopes are available. Nested scheme for **validation_result**: - * `goals_pass_count` - (Optional, Integer) The number of goals that passed the scan. - * `goals_unable_to_perform_count` - (Optional, Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `goals_not_applicable_count` - (Optional, Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `goals_fail_count` - (Optional, Integer) The number of goals that failed the scan. - * `goals_total_count` - (Optional, Integer) The total number of goals that were included in the scan. - * `controls_pass_count` - (Optional, Integer) The number of controls that passed the scan. - * `controls_fail_count` - (Optional, Integer) The number of controls that failed the scan. - * `controls_not_applicable_count` - (Optional, Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `controls_unable_to_perform_count` - (Optional, Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `controls_total_count` - (Optional, Integer) The total number of controls that were included in the scan. - * `profiles` - (Optional, List) The result of a each profile in group profile. - Nested scheme for **profiles**: - * `profile_id` - (Optional, String) The ID of the profile. - * `profile_name` - (Optional, String) The name of the profile. - * `profile_type` - (Optional, String) The type of profile. To learn more about profile types, check out the [docs] (https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles). - * Constraints: - * Supported values are: **standard**, **authored**, **custom**, **standard_cv**, **templategroup**, **standard_certificate** - * `validation_result` - (Optional, List) The result of a scan. - Nested scheme for **validation_result**: - * `controls_pass_count` - (Optional, Integer) The number of controls that passed the scan. - * `controls_fail_count` - (Optional, Integer) The number of controls that failed the scan. - * `controls_not_applicable_count` - (Optional, Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. - * `controls_unable_to_perform_count` - (Optional, Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. - * `controls_total_count` - (Optional, Integer) The total number of controls that were included in the scan. + * `controls_fail_count` - (Integer) The number of controls that failed the scan. + * `controls_not_applicable_count` - (Integer) The number of controls that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `controls_pass_count` - (Integer) The number of controls that passed the scan. + * `controls_total_count` - (Integer) The total number of controls that were included in the scan. + * `controls_unable_to_perform_count` - (Integer) The number of controls that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `goals_fail_count` - (Integer) The number of goals that failed the scan. + * `goals_not_applicable_count` - (Integer) The number of goals that are not relevant to the current scan. A scan is listed as 'Not applicable' when information about its associated resource can't be found. + * `goals_pass_count` - (Integer) The number of goals that passed the scan. + * `goals_total_count` - (Integer) The total number of goals that were included in the scan. + * `goals_unable_to_perform_count` - (Integer) The number of goals that could not be validated. A control is listed as 'Unable to perform' when information about its associated resource can't be collected. + * `report_run_by` - (String) The entity that ran the report. + * `scope_id` - (String) The ID of the scope. + * `scope_name` - (String) The name of the scope. + * `start_time` - (String) The date and time the scan was run. + * `status` - (String) The status of the collector as it completes a scan. + * Constraints: Allowable values are: `pending`, `discovery_started`, `discovery_completed`, `error_in_discovery`, `gateway_aborted`, `controller_aborted`, `not_accepted`, `waiting_for_refine`, `validation_started`, `validation_completed`, `sent_to_collector`, `discovery_in_progress`, `validation_in_progress`, `error_in_validation`, `discovery_result_posted_with_error`, `discovery_result_posted_no_error`, `validation_result_posted_with_error`, `validation_result_posted_no_error`, `fact_collection_started`, `fact_collection_in_progress`, `fact_collection_completed`, `error_in_fact_collection`, `fact_validation_started`, `fact_validation_in_progress`, `fact_validation_completed`, `error_in_fact_validation`, `abort_task_request_received`, `error_in_abort_task_request`, `abort_task_request_completed`, `user_aborted`, `abort_task_request_failed`, `remediation_started`, `remediation_in_progress`, `error_in_remediation`, `remediation_completed`, `inventory_started`, `inventory_in_progress`, `inventory_completed`, `error_in_inventory`, `inventory_completed_with_error`. diff --git a/website/docs/d/scc_posture_scans_summary.html.markdown b/website/docs/d/scc_posture_scans_summary.html.markdown index e7ec2ae0e..0dcde79ba 100644 --- a/website/docs/d/scc_posture_scans_summary.html.markdown +++ b/website/docs/d/scc_posture_scans_summary.html.markdown @@ -8,83 +8,67 @@ subcategory: "Security and Compliance Center" # ibm_scc_posture_scan_summary -Review information of Security and Compliance Center posture scan summary see [viewing evaluation results](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-results). +Provides a read-only data source for scans_summary. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_scc_posture_scan_summary" "scans_summary" { profile_id = "profile_id" scan_id = "scan_id" } ``` -## Argument reference +## Argument Reference Review the argument reference that you can specify for your data source. -* `profile_id` - (Required, String) The profile ID. This can be obtained from the Security and Compliance Center console by clicking on the profile name. The URL contains the ID. -* `scan_id` - (Required, Forces new resource, String) The Scan ID. +* `profile_id` - (Required, String) The profile ID. This can be obtained from the Security and Compliance Center UI by clicking on the profile name. The URL contains the ID. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. +* `scan_id` - (Required, String) Your Scan ID. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. -## Attribute reference +## Attribute Reference In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the scans_summary. -* `controls` - (Optional, List) The list of controls on the scan summary. +* `controls` - (List) The list of controls on the scan summary. Nested scheme for **controls**: - * `control_id` - (Optional, String) The scan summary control ID. - * `status` - (Optional, String) The control status. - * Constraints: Supported values are: **pass**, **unable_to_perform** - * `external_control_id` - (Optional, String) The external control ID. - * `control_desciption` - (Optional, String) The scan profile name. - * `goals` - (Optional, List) The list of goals on the control. + * `desciption` - (String) The scan profile name. + * `external_control_id` - (String) The external control ID. + * `goals` - (List) The list of goals on the control. Nested scheme for **goals**: - * `goal_description` - (Optional, String) The description of the goal. - * `goal_id` - (Optional, String) The goal ID. - * `status` - (Optional, String) The goal status. - * Constraints: Supported values are: **pass**, **fail** - * `severity` - (Optional, String) The severity of the goal. - * `completed_time` - (Optional, String) The report completed time. - * `error` - (Optional, String) The error on goal validation. - * `resource_result` - (Optional, List) The list of resource results. + * `completed_time` - (String) The report completed time. + * `description` - (String) The description of the goal. + * `error` - (String) The error on goal validation. + * `id` - (String) The goal ID. + * `resource_result` - (List) The list of resource results. Nested scheme for **resource_result**: - * `resource_name` - (Optional, String) The resource name. - * `resource_types` - (Optional, String) The resource type. - * `resource_status` - (Optional, String) The resource control result status. - * Constraints: Supported values are: **pass**, **unable_to_perform** - * `display_expected_value` - (Optional, String) The expected results of a resource. - * `actual_value` - (Optional, String) The actual results of a resource. - * `results_info` - (Optional, String) The results information. - * `not_applicable_reason` - (Optional, String) The reason for goal not applicable for a resource. - * `goal_applicability_criteria` - (Optional, List) The criteria that defines how a profile applies. - Nested scheme for **goal_applicability_criteria**: - * `environment` - (Optional, List) A list of environments that a profile can be applied to. - * `environment_category` - (Optional, List) The type of environment that a profile is able to be applied to. - * `resource` - (Optional, List) A list of resources that a profile can be used with. - * `resource_category` - (Optional, List) The type of resource that a profile is able to be applied to. - * `resource_type` - (Optional, List) The resource type that the profile applies to. - * `software_details` - (Optional, List) The software that the profile applies to. - Nested scheme for **software_details**: - * `name` - (Optional, String) The name of the Operating System software. - * `version` - (Optional, String) The version of the Operating System software. - * `os_details` - (Optional, List) The Operating System that the profile applies to. - Nested scheme for **os_details**: - * `name` - (Optional, String) The name of the Operating System. - * `version` - (Optional, String) The version of the Operating System. - * `additional_details` - (Optional, Map) Any additional details about the profile. - * `environment_category_description` - (Optional, Map) The type of environment that your scope is targeted to. - * `environment_description` - (Optional, Map) The environment that your scope is targeted to. - * `resource_category_description` - (Optional, Map) The type of resource that your scope is targeted to. - * `resource_type_description` - (Optional, Map) A further classification of the type of resource that your scope is targeted to. - * `resource_description` - (Optional, Map) The resource that is scanned as part of your scope. - * `resource_statistics` - (Optional, List) A scans summary controls. + * `actual_value` - (String) The actual results of a resource. + * `display_expected_value` - (String) The expected results of a resource. + * `name` - (String) The resource name. + * `not_applicable_reason` - (String) The reason for goal not applicable for a resource. + * `results_info` - (String) The results information. + * `status` - (String) The resource control result status. + * Constraints: Allowable values are: `pass`, `unable_to_perform`. + * `types` - (String) The resource type. + * `severity` - (String) The severity of the goal. + * `status` - (String) The goal status. + * Constraints: Allowable values are: `pass`, `fail`. + * `id` - (String) The scan summary control ID. + * `resource_statistics` - (List) A scans summary controls. Nested scheme for **resource_statistics**: - * `resource_pass_count` - (Optional, Integer) The resource count of pass controls. - * `resource_fail_count` - (Optional, Integer) The resource count of fail controls. - * `resource_unable_to_perform_count` - (Optional, Integer) The number of resources that were unable to be scanned against a control. - * `resource_not_applicable_count` - (Optional, Integer) The resource count of not applicable(NA) controls. -* `discover_id` - (Optional, String) The scan discovery ID. -* `profile_name` - (Optional, String) The scan profile name. -* `scope_id` - (Optional, String) The scan summary scope ID. + * `fail_count` - (Integer) The resource count of fail controls. + * `not_applicable_count` - (Integer) The resource count of not applicable(na) controls. + * `pass_count` - (Integer) The resource count of pass controls. + * `unable_to_perform_count` - (Integer) The number of resources that were unable to be scanned against a control. + * `status` - (String) The control status. + * Constraints: Allowable values are: `pass`, `unable_to_perform`. + +* `discover_id` - (String) The scan discovery ID. + +* `profile_name` - (String) The scan profile name. + +* `scope_id` - (String) The scan summary scope ID. diff --git a/website/docs/d/scc_posture_scope.html.markdown b/website/docs/d/scc_posture_scope.html.markdown new file mode 100644 index 000000000..9331fea86 --- /dev/null +++ b/website/docs/d/scc_posture_scope.html.markdown @@ -0,0 +1,269 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_scope" +description: |- + Get information about scope +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_scope + +Provides a read-only data source for scope. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_scope" "scope" { + scope_id = "scope_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `id` - (Required, Forces new resource, String) The id for the given API. + * Constraints: The maximum length is `20` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `scope_id` - The unique identifier of the scope. +* `cloud_type` - (Optional, String) Stores the value of scope_cloud_type .Will be displayed only when value exists. + +* `cloud_type_id` - (Optional, Integer) Stores the value of scope_cloud_type_id .Will be displayed only when value exists. + +* `collectors` - (Optional, List) Stores the value of collectors .Will be displayed only when value exists. +Nested scheme for **collectors**: + * `approved_internet_gateway_ip` - (Optional, String) The approved internet gateway ip of the collector. This field will be populated only when collector is installed. + * `approved_local_gateway_ip` - (Optional, String) The approved local gateway ip of the collector. This field will be populated only when collector is installed. + * `collector_version` - (Optional, String) The collector version. This field is populated when collector is installed. + * `created_at` - (Required, String) The ISO Date/Time the collector was created. + * `created_by` - (Required, String) The id of the user that created the collector. + * `credential_public_key` - (Optional, String) The credential public key. + * `description` - (Required, String) The description of the collector. + * `display_name` - (Required, String) The user-friendly name of the collector. + * `enabled` - (Required, Boolean) Identifies whether the collector is enabled or not(deleted). + * `failure_count` - (Required, Integer) The number of times the collector has failed. + * `hostname` - (Optional, String) The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name. + * `id` - (Required, String) The id of the collector. + * `image_version` - (Optional, String) The image version of the collector. This field is populated when collector is installed. ". + * `install_path` - (Optional, String) The installation path of the collector. This field will be populated when collector is installed.The value will be folder path. + * `is_public` - (Required, Boolean) Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. + * `is_ubi_image` - (Optional, Boolean) Determines whether the collector has a Ubi image. + * `last_failed_internet_gateway_ip` - (Optional, String) The failed internet gateway ip of the collector. + * `last_failed_local_gateway_ip` - (Optional, String) The failed local gateway ip. This field will be populated only when collector is installed. + * `last_heartbeat` - (Optional, String) Stores the heartbeat time of a controller . This value exists when collector is installed and running. + * `managed_by` - (Required, String) The entity that manages the collector. + * Constraints: Allowable values are: `ibm`, `customer`. + * `name` - (Required, String) The name of the collector. + * `public_key` - (Optional, String) The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed. + * `registration_code` - (Required, String) The registration code of the collector.This is will be used for initial authentication during installation of collector. + * `reset_reason` - (Optional, String) The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field . + * `reset_time` - (Optional, String) The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field. + * `status` - (Required, String) The status of collector. + * Constraints: Allowable values are: `ready_to_install`, `core_downloaded`, `approval_required`, `approved_download_in_progress`, `approved_install_in_progress`, `install_in_progress`, `installed`, `installed_credentials_required`, `installed_assigning_credentials`, `active`, `unable_to_connect`, `waiting_for_upgrade`, `suspended`, `installation_failed`. + * `status_description` - (Required, String) The collector status. + * `trial_expiry` - (Optional, String) The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed. + * `type` - (Required, String) The type of the collector. + * Constraints: Allowable values are: `restricted`, `unrestricted`. + * `updated_at` - (Required, String) The ISO Date/Time the collector was modified. + * `updated_by` - (Required, String) The id of the user that modified the collector. + * `use_private_endpoint` - (Required, Boolean) Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false. + +* `collectors_by_type` - (Optional, Map) Stores the value of collectors_by_type .Will be displayed only when value exists. + +* `correlation_id` - (Optional, String) A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation). + +* `created_at` - (Optional, String) Stores the value of scope_created_on .Will be displayed only when value exists. + +* `created_by` - (Optional, String) Stores the value of scope_created_by .Will be displayed only when value exists. + +* `credential_attributes` - (Optional, String) Stores the value of scope_credential_attributes .Will be displayed only when value exists. + +* `credentials_by_sub_categeory_type` - (Optional, Map) Stores the value of scope_credentials_by_sub_categeory_type .Will be displayed only when value exists. + +* `credentials_by_type` - (Optional, Map) Stores the value of scope_credentials_by_type .Will be displayed only when value exists. + +* `description` - (Optional, String) Stores the value of scope_description .Will be displayed only when value exists. + +* `discovery_method` - (Optional, String) Stores the value of scope_discovery_method .Will be displayed only when value exists. + +* `discovery_methods` - (Optional, List) Stores the value of scope_discovery_methods .Will be displayed only when value exists. + +* `discovery_setting_id` - (Optional, Integer) Stores the value of scope_discovery_setting_id .Will be displayed only when value exists. + +* `enabled` - (Optional, Boolean) Stores the value of scope_enabled .Will be displayed only when value exists. + +* `env_sub_category` - (Optional, String) Stores the value of scope_env_sub_category .Will be displayed only when value exists. + +* `file_format` - (Optional, String) Stores the value of scope_file_format .Will be displayed only when value exists. + +* `file_type` - (Optional, String) Stores the value of scope_file_type .Will be displayed only when value exists. + +* `first_level_scoped_data` - (Optional, List) Stores the value of scope_first_level_scoped_data .Will be displayed only when value exists. +Nested scheme for **first_level_scoped_data**: + * `scope` - (Optional, String) Stores the value of scope . + * `scope_changed` - (Optional, Boolean) Stores the value of scope_changed . + * `scope_children` - (Optional, Map) Stores the value of scope_children . + * `scope_collector_id` - (Optional, Integer) Stores the value of scope_collector_id . + * `scope_discovery_status` - (Optional, Map) Stores the value of scope_discovery_status . + * `scope_drift` - (Optional, String) Stores the value of scope_drift . + * `scope_fact_status` - (Optional, Map) Stores the value of scope_fact_status . + * `scope_facts` - (Optional, String) Stores the value of scope_facts . + * `scope_id` - (Optional, String) Stores the value of scope_id . + * `scope_init_scope` - (Optional, String) Stores the value of scope_init_scope . + * `scope_list_members` - (Optional, Map) Stores the value of scope_list_members . + * `scope_new_found` - (Optional, Boolean) Stores the value of scope_new_found . + * `scope_object` - (Optional, String) Stores the value of scope_object . + * `scope_overlay` - (Optional, String) Stores the value of scope_overlay . + * `scope_parse_status` - (Optional, String) Stores the value of scope_parse_status . + * `scope_properties` - (Optional, String) Stores the value of scope_properties . + * `scope_resource` - (Optional, String) Stores the value of scope_resource . + * `scope_resource_attributes` - (Optional, Map) Stores the value of scope_resource_attributes . + * `scope_resource_category` - (Optional, String) Stores the value of scope_resource_category . + * `scope_resource_type` - (Optional, String) Stores the value of scope_resource_type . + * `scope_transformed_facts` - (Optional, Map) Stores the value of scope_transformed_facts . + +* `include_new_eagerly` - (Optional, Boolean) Stores the value of scope_include_new_eagerly .Will be displayed only when value exists. + +* `interval` - (Optional, Integer) Stores the value of scope_freq .Will be displayed only when value exists. + +* `is_discovery_scheduled` - (Optional, Boolean) Stores the value of scope_is_discovery_scheduled .Will be displayed only when value exists. + +* `last_discover_completed_time` - (Optional, String) Stores the value of scope_last_discover_completed_time .Will be displayed only when value exists. + +* `last_discover_start_time` - (Optional, String) Stores the value of scope_last_discover_start_time .Will be displayed only when value exists. + +* `last_successful_discover_completed_time` - (Optional, String) Stores the value of scope_last_successful_discover_completed_time .Will be displayed only when value exists. + +* `last_successful_discover_start_time` - (Optional, String) Stores the value of scope_last_successful_discover_start_time .Will be displayed only when value exists. + +* `modified_at` - (Optional, String) Stores the value of scope_modified_on .Will be displayed only when value exists. + +* `modified_by` - (Optional, String) Stores the value of scope_modified_by .Will be displayed only when value exists. + +* `name` - (Required, String) Stores the value of scope_name . + +* `org_id` - (Optional, Integer) Stores the value of scope_org_id .Will be displayed only when value exists. + +* `partner_uuid` - (Optional, String) Stores the value of partner_uuid .Will be displayed only when value exists. + +* `region_names` - (Optional, String) Stores the value of scope_region_names .Will be displayed only when value exists. + +* `resource_groups` - (Optional, String) Stores the value of scope_resource_groups .Will be displayed only when value exists. + +* `status` - (Optional, String) Stores the value of scope_status .Will be displayed only when value exists. + * Constraints: Allowable values are: `pending`, `discovery_started`, `discovery_completed`, `error_in_discover`, `gateway_aborted`, `controller_aborted`, `not_accepted`, `waiting_for_refine`, `validation_started`, `validation_completed`, `sent_to_collector`, `discovery_in_progress`, `validation_in_progress`, `error_in_validation`, `discovery_result_posted_with_error`, `discovery_result_posted_no_error`, `validation_result_posted_with_error`, `validation_result_posted_no_error`, `fact_collection_started`, `fact_collection_in_progress`, `fact_collection_completed`, `error_in_fact_collection`, `fact_validation_started`, `fact_validation_in_progress`, `fact_validation_completed`, `error_in_fact_validation`, `abort_task_request_received`, `error_in_abort_task_request`, `abort_task_request_completed`, `user_aborted`, `abort_task_request_failed`, `cve_validation_started`, `cve_validation_completed`, `cve_validation_error`, `eol_validation_started`, `eol_validation_completed`, `eol_validation_error`, `cve_regular_validation_started`, `cve_regular_validation_completed`, `cve_regular_validation_error`, `eol_regular_validation_started`, `eol_regular_validation_completed`, `eol_regular_validation_error`, `cert_validation_started`, `cert_validation_completed`, `cert_validation_error`, `cert_regular_validation_started`, `cert_regular_validation_completed`, `cert_regular_validation_error`, `remediation_started`, `remediation_in_progress`, `error_in_remediation`, `remediation_completed`, `inventory_started`, `inventory_in_progress`, `inventory_completed`, `error_in_inventory`, `inventory_completed_with_error`, `location_change_aborted`. + +* `status_msg` - (Optional, String) Stores the value of scope_status_msg .Will be displayed only when value exists. + +* `status_updated_time` - (Optional, String) Stores the value of scope_status_updated_time .Will be displayed only when value exists. + +* `sub_categories_by_type` - (Optional, Map) Stores the value of scope_sub_categories_by_type .Will be displayed only when value exists. + +* `subset_selected` - (Optional, Boolean) Stores the value of scope_subset_selected .Will be displayed only when value exists. + +* `task_type` - (Optional, String) Stores the value of scope_task_type .Will be displayed only when value exists. + * Constraints: Allowable values are: `nop`, `discover`, `evidence`, `factcollection`, `script`, `tldiscover`, `subsetvalidate`, `factvalidation`, `aborttasks`, `cve_validation`, `eol_validation`, `cve_regular_validation`, `eol_regular_validation`, `cert_regular_validation`, `cert_validation`, `remediation`, `inventory`. + +* `tasks` - (Optional, List) Stores the value of scope_tasks .Will be displayed only when value exists. +Nested scheme for **tasks**: + * `task_created_by` - (Optional, String) Stores the value of task_created_by . + * `task_derived_status` - (Optional, String) Stores the value of task_derived_status . + * Constraints: Allowable values are: `pending`, `discovery_started`, `discovery_completed`, `error_in_discover`, `gateway_aborted`, `controller_aborted`, `not_accepted`, `waiting_for_refine`, `validation_started`, `validation_completed`, `sent_to_collector`, `discovery_in_progress`, `validation_in_progress`, `error_in_validation`, `discovery_result_posted_with_error`, `discovery_result_posted_no_error`, `validation_result_posted_with_error`, `validation_result_posted_no_error`, `fact_collection_started`, `fact_collection_in_progress`, `fact_collection_completed`, `error_in_fact_collection`, `fact_validation_started`, `fact_validation_in_progress`, `fact_validation_completed`, `error_in_fact_validation`, `abort_task_request_received`, `error_in_abort_task_request`, `abort_task_request_completed`, `user_aborted`, `abort_task_request_failed`, `cve_validation_started`, `cve_validation_completed`, `cve_validation_error`, `eol_validation_started`, `eol_validation_completed`, `eol_validation_error`, `cve_regular_validation_started`, `cve_regular_validation_completed`, `cve_regular_validation_error`, `eol_regular_validation_started`, `eol_regular_validation_completed`, `eol_regular_validation_error`, `cert_validation_started`, `cert_validation_completed`, `cert_validation_error`, `cert_regular_validation_started`, `cert_regular_validation_completed`, `cert_regular_validation_error`, `remediation_started`, `remediation_in_progress`, `error_in_remediation`, `remediation_completed`, `inventory_started`, `inventory_in_progress`, `inventory_completed`, `error_in_inventory`, `inventory_completed_with_error`, `location_change_aborted`. + * `task_discover_id` - (Optional, Integer) Stores the value of task_discover_id . + * `task_gateway_id` - (Optional, Integer) Stores the value of task_gateway_id . + * `task_gateway_name` - (Optional, String) Stores the value of task_gateway_name . + * `task_gateway_schema_id` - (Optional, Integer) Stores the value of task_gateway_schema_id . + * `task_id` - (Optional, Integer) Stores the value of task_id . + * `task_logs` - (Optional, List) Stores the value of task_logs . + Nested scheme for **task_logs**: + * `task_schema_name` - (Optional, String) Stores the value of task_schema_name . + * `task_start_time` - (Optional, Integer) Stores the value of task_start_time . + * `task_status` - (Optional, String) Stores the value of task_status . + * Constraints: Allowable values are: `pending`, `discovery_started`, `discovery_completed`, `error_in_discover`, `gateway_aborted`, `controller_aborted`, `not_accepted`, `waiting_for_refine`, `validation_started`, `validation_completed`, `sent_to_collector`, `discovery_in_progress`, `validation_in_progress`, `error_in_validation`, `discovery_result_posted_with_error`, `discovery_result_posted_no_error`, `validation_result_posted_with_error`, `validation_result_posted_no_error`, `fact_collection_started`, `fact_collection_in_progress`, `fact_collection_completed`, `error_in_fact_collection`, `fact_validation_started`, `fact_validation_in_progress`, `fact_validation_completed`, `error_in_fact_validation`, `abort_task_request_received`, `error_in_abort_task_request`, `abort_task_request_completed`, `user_aborted`, `abort_task_request_failed`, `cve_validation_started`, `cve_validation_completed`, `cve_validation_error`, `eol_validation_started`, `eol_validation_completed`, `eol_validation_error`, `cve_regular_validation_started`, `cve_regular_validation_completed`, `cve_regular_validation_error`, `eol_regular_validation_started`, `eol_regular_validation_completed`, `eol_regular_validation_error`, `cert_validation_started`, `cert_validation_completed`, `cert_validation_error`, `cert_regular_validation_started`, `cert_regular_validation_completed`, `cert_regular_validation_error`, `remediation_started`, `remediation_in_progress`, `error_in_remediation`, `remediation_completed`, `inventory_started`, `inventory_in_progress`, `inventory_completed`, `error_in_inventory`, `inventory_completed_with_error`, `location_change_aborted`. + * `task_status_msg` - (Optional, String) Stores the value of task_status_msg . + * `task_task_type` - (Optional, String) Stores the value of task_task_type . + * Constraints: Allowable values are: `nop`, `discover`, `evidence`, `factcollection`, `script`, `tldiscover`, `subsetvalidate`, `factvalidation`, `aborttasks`, `cve_validation`, `eol_validation`, `cve_regular_validation`, `eol_regular_validation`, `cert_regular_validation`, `cert_validation`, `remediation`, `inventory`. + * `task_updated_time` - (Optional, Integer) Stores the value of task_updated_time . + +* `tld_credentail` - (Optional, List) Stores the value of ScopeDetailsCredential . +Nested scheme for **tld_credentail**: + * `credential_group` - (Optional, Map) Stores the value of credential_credential_group . + * `data` - (Optional, Map) Stores the value of credential_data . + * `description` - (Optional, String) Stores the value of credential_description . + * `display_fields` - (Optional, List) Details the fields on the credential. This will change as per credential type selected. + Nested scheme for **display_fields**: + * `auth_url` - (Optional, String) auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_arn` - (Optional, String) AWS arn value. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_id` - (Optional, String) AWS client Id.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `aws_client_secret` - (Optional, String) AWS client secret.This is mandatory for AWS Cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_region` - (Optional, String) AWS region. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_id` - (Optional, String) Azure client Id. This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_client_secret` - (Optional, String) Azure client secret.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_resource_group` - (Optional, String) Azure resource group. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `azure_subscription_id` - (Optional, String) Azure subscription Id.This is mandatory for Azure Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `database_name` - (Optional, String) Database name.This is mandatory for Database Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ibm_api_key` - (Optional, String) The IBM Cloud API Key. This is mandatory for IBM Credential Type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `ms_365_client_id` - (Optional, String) The MS365 client Id.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_client_secret` - (Optional, String) The MS365 client secret.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `ms_365_tenant_id` - (Optional, String) The MS365 tenantId.This is mandatory for Windows MS365 Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `password` - (Optional, String) password of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `pem_data` - (Optional, String) The base64 encoded data to associate with the PEM file. + * Constraints: The maximum length is `4000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `pem_file_name` - (Optional, String) The name of the PEM file. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `project_domain_name` - (Optional, String) project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `project_name` - (Optional, String) Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `user_domain_name` - (Optional, String) user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `username` - (Optional, String) username of the user.This is mandatory for DataBase, Kerbros,OpenStack Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_authtype` - (Optional, String) Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `winrm_port` - (Optional, String) Kerberos windows port.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `winrm_usessl` - (Optional, String) Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `enabled_credential_group` - (Optional, Boolean) Stores the value of credential_enabled_credential_group . + * `gateway_key` - (Optional, String) Stores the value of credential_gateway_key . + * `groups` - (Optional, List) Stores the value of credential_groups . + Nested scheme for **groups**: + * `id` - (Required, String) credential group id. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `passphrase` - (Required, String) passphase of the credential. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `id` - (Optional, String) Stores the value of credential_id . + * `is_enabled` - (Optional, Boolean) Stores the value of credential_is_enabled . + * `name` - (Optional, String) Stores the value of credential_name . + * `purpose` - (Optional, String) Stores the value of credential_purpose . + * `type` - (Optional, String) Stores the value of credential_type . + * `uuid` - (Optional, String) Stores the value of credential_uuid . + * `version_timestamp` - (Optional, Map) Stores the value of credential_version_timestamp . + +* `tld_credential_id` - (Optional, Integer) Stores the value of scope_tld_credential_id .Will be displayed only when value exists. + +* `type` - (Optional, String) Stores the value of scope_type .Will be displayed only when value exists. + * Constraints: Allowable values are: `validation`, `inventory`. + +* `uuid` - (Optional, String) Stores the value of scope_uuid .Will be displayed only when value exists. + diff --git a/website/docs/d/scc_posture_scope_correlation.html.markdown b/website/docs/d/scc_posture_scope_correlation.html.markdown new file mode 100644 index 000000000..1e8295b68 --- /dev/null +++ b/website/docs/d/scc_posture_scope_correlation.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_scope_correlation" +description: |- + Get information about scope_correlation +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_scope_correlation + +Provides a read-only data source for scope_correlation. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_scc_posture_scope_correlation" "scope_correlation" { + correlation_id = "correlation_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `correlation_id` - (Required, Forces new resource, String) A correlation_Id is created when a scope is created and discovery task is triggered or when a validation is triggered on a Scope. This is used to get the status of the task(discovery or validation). + * Constraints: The maximum length is `50` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the scope_correlation. +* `last_heartbeat` - (String) Returns the time that the scope was last updated. This value exists when collector is installed and running. + +* `start_time` - (String) Returns the time that task started. + +* `status` - (String) Returns the current status of a task. + diff --git a/website/docs/d/scc_posture_scopes.html.markdown b/website/docs/d/scc_posture_scopes.html.markdown index bbd033da4..802b3e2bd 100644 --- a/website/docs/d/scc_posture_scopes.html.markdown +++ b/website/docs/d/scc_posture_scopes.html.markdown @@ -8,49 +8,91 @@ subcategory: "Security and Compliance Center" # ibm_scc_posture_scopes -Review information of Security and Compliance Center posture scopes see [Managing Scopes](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes). +Provides a read-only data source for list_scopes. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example usage +## Example Usage -```terraform +```hcl data "ibm_scc_posture_scopes" "list_scopes" { - scope_id = "1" } ``` -## Argument reference -Review information of Security and Compliance Center posture scopes - -* `scope_id` - (Optional, String) An auto-generated unique identifier for the scope. - -## Attribute reference +## Attribute Reference In addition to all argument references listed, you can access the following attribute references after your data source is created. * `id` - The unique identifier of the list_scopes. -* `scopes` - (Optional, List) Scopes. +* `first` - (List) The URL of a page. +Nested scheme for **first**: + * `href` - (String) The URL of a page. + +* `last` - (List) The URL of a page. +Nested scheme for **last**: + * `href` - (String) The URL of a page. + +* `limit` - (Integer) The number of scopes displayed per page. + +* `next` - (List) The URL of a page. +Nested scheme for **next**: + * `href` - (String) The URL of a page. + +* `offset` - (Integer) The offset of the page. + +* `previous` - (List) The URL of a page. +Nested scheme for **previous**: + * `href` - (String) The URL of a page. + +* `scopes` - (List) Scopes. Nested scheme for **scopes**: - * `created_by` - (Optional, String) The user who created the scope. - * `created_time` - (Optional, String) The time that the scope was created in UTC. - * `collectors_id` - (Optional, List) The unique IDs of the collectors that are attached to the scope. - * `description` - (Optional, String) A detailed description of the scope. - * `enabled` - (Optional, Boolean) Indicates whether scope is enabled/disabled. - * `environment_type` - (Optional, String) The environment that the scope is targeted to. - * Constraints: Supported values are: **ibm**, **aws**, **azure**, **on_premise**, **hosted**, **services**, **openstack**, **gcp** - * `last_scan_status_updated_time` - (Optional, String) The last time that a scan status for a scope was updated in UTC. - * `last_scan_type` - (Optional, String) The last type of scan that was run on the scope. - * Constraints: Allowable values are: **discovery**, **validation**, **fact_collection**, **fact_validation**, **inventory**, **remediation**, **abort_tasks**, **evidence**, **script** - * `last_scan_type_description` - (Optional, String) A description of the last scan type. - * `modified_by` - (Optional, String) The user who most recently modified the scope. - * `modified_time` - (Optional, String) The time that the scope was last modified in UTC. - * `name` - (Optional, String) A unique name for your scope. - * `scope_id` - (Optional, String) An auto-generated unique identifier for the scope. - * `scans` - (Optional, List) A list of the scans that have been run on the scope. - Nested scheme for **scans**: - * `discover_id` - (Optional, String) An auto-generated unique identifier for discovery. - * `scan_id` - (Optional, String) An auto-generated unique identifier for the scan. - * `status` - (Optional, String) The status of the collector as it completes a scan. - * Constraints: Supported values are: **pending**, **discovery_started**, **discovery_completed**, **error_in_discovery**, **gateway_aborted**, **controller_aborted**, **not_accepted**, **waiting_for_refine**, **validation_started**, **validation_completed**, **sent_to_collector**, **discovery_in_progress**, **validation_in_progress**, **error_in_validation**, **discovery_result_posted_with_error**, **discovery_result_posted_no_error**, **validation_result_posted_with_error**, **validation_result_posted_no_error**, **fact_collection_started**, **fact_collection_in_progress**, **fact_collection_completed**, **error_in_fact_collection**, **fact_validation_started**, **fact_validation_in_progress**, **fact_validation_completed**, **error_in_fact_validation**, **abort_task_request_received**, **error_in_abort_task_request**, **abort_task_request_completed**, **user_aborted**, **abort_task_request_failed**, **remediation_started**, **remediation_in_progress**, **error_in_remediation**, **remediation_completed**, **inventory_started**, **inventory_in_progress**, **inventory_completed**, **error_in_inventory**, **inventory_completed_with_error** - * `status_message` - (Optional, String) The current status of the collector. + * `collectors` - (List) Stores the value of collectors .Will be displayed only when value exists. + Nested scheme for **collectors**: + * `approved_internet_gateway_ip` - (String) The approved internet gateway ip of the collector. This field will be populated only when collector is installed. + * `approved_local_gateway_ip` - (String) The approved local gateway ip of the collector. This field will be populated only when collector is installed. + * `collector_version` - (String) The collector version. This field is populated when collector is installed. + * `created_at` - (String) The ISO Date/Time the collector was created. + * `created_by` - (String) The id of the user that created the collector. + * `credential_public_key` - (String) The credential public key. + * `description` - (String) The description of the collector. + * `display_name` - (String) The user-friendly name of the collector. + * `enabled` - (Boolean) Identifies whether the collector is enabled or not(deleted). + * `failure_count` - (Integer) The number of times the collector has failed. + * `hostname` - (String) The collector host name. This field will be populated when collector is installed.This will have fully qualified domain name. + * `id` - (String) The id of the collector. + * `image_version` - (String) The image version of the collector. This field is populated when collector is installed. ". + * `install_path` - (String) The installation path of the collector. This field will be populated when collector is installed.The value will be folder path. + * `is_public` - (Boolean) Determines whether the collector endpoint is accessible on a public network.If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. + * `is_ubi_image` - (Boolean) Determines whether the collector has a Ubi image. + * `last_failed_internet_gateway_ip` - (String) The failed internet gateway ip of the collector. + * `last_failed_local_gateway_ip` - (String) The failed local gateway ip. This field will be populated only when collector is installed. + * `last_heartbeat` - (String) Stores the heartbeat time of a controller . This value exists when collector is installed and running. + * `managed_by` - (String) The entity that manages the collector. + * Constraints: Allowable values are: `ibm`, `customer`. + * `name` - (String) The name of the collector. + * `public_key` - (String) The public key of the collector.Will be used for ssl communciation between collector and orchestrator .This will be populated when collector is installed. + * `registration_code` - (String) The registration code of the collector.This is will be used for initial authentication during installation of collector. + * `reset_reason` - (String) The reason for the collector reset .User resets the collector with a reason for reset. The reason entered by the user is saved in this field . + * `reset_time` - (String) The ISO Date/Time of the collector reset. This value will be populated when a collector is reset. The data-time when the reset event is occured is captured in this field. + * `status` - (String) The status of collector. + * Constraints: Allowable values are: `ready_to_install`, `core_downloaded`, `approval_required`, `approved_download_in_progress`, `approved_install_in_progress`, `install_in_progress`, `installed`, `installed_credentials_required`, `installed_assigning_credentials`, `active`, `unable_to_connect`, `waiting_for_upgrade`, `suspended`, `installation_failed`. + * `status_description` - (String) The collector status. + * `trial_expiry` - (String) The trial expiry. This holds the expiry date of registration_code. This field will be populated when collector is installed. + * `type` - (String) The type of the collector. + * Constraints: Allowable values are: `restricted`, `unrestricted`. + * `updated_at` - (String) The ISO Date/Time the collector was modified. + * `updated_by` - (String) The id of the user that modified the collector. + * `use_private_endpoint` - (Boolean) Whether the collector should use a public or private endpoint. This value is generated based on is_public field value during collector creation. If is_public is set to true, this value will be false. + * `created_at` - (String) The time that the scope was created in UTC. + * `created_by` - (String) The user who created the scope. + * `credential_type` - (String) The environment that the scope is targeted to. + * Constraints: Allowable values are: `ibm`, `aws`, `azure`, `on_premise`, `hosted`, `services`, `openstack`, `gcp`. + * `description` - (String) A detailed description of the scope. + * `enabled` - (Boolean) Indicates whether scope is enabled/disabled. + * `id` - (String) An auto-generated unique identifier for the scope. + * `modified_by` - (String) The user who most recently modified the scope. + * `name` - (String) A unique name for your scope. + * `updated_at` - (String) The time that the scope was last modified in UTC. + * `uuid` - (String) Stores the value of scope_uuid . + +* `total_count` - (Integer) The total number of scopes. This value is 0 if no scopes are available and below fields will not be available in that case. diff --git a/website/docs/d/scc_si_note.html.markdown b/website/docs/d/scc_si_note.html.markdown index fbd010a2e..0812f599e 100644 --- a/website/docs/d/scc_si_note.html.markdown +++ b/website/docs/d/scc_si_note.html.markdown @@ -6,20 +6,23 @@ description: |- Get information about scc_si_note --- +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + # ibm_scc_si_note Provides a read-only data source for scc_si_note. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_scc_si_note" "scc_si_note" { note_id = "note_id" provider_id = "provider_id" } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. @@ -27,7 +30,7 @@ Review the argument reference that you can specify for your data source. * `note_id` - (Required, Forces new resource, String) Second part of note `name`: providers/{provider_id}/notes/{note_id}. * `provider_id` - (Required, Forces new resource, String) Part of the parent. This field contains the provider ID. For example: providers/{provider_id}. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/scc_si_notes.html.markdown b/website/docs/d/scc_si_notes.html.markdown index 90522a9f5..72056ffd0 100644 --- a/website/docs/d/scc_si_notes.html.markdown +++ b/website/docs/d/scc_si_notes.html.markdown @@ -6,27 +6,31 @@ description: |- Get information about scc_si_notes --- +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + # ibm_scc_si_notes Provides a read-only data source for scc_si_notes. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_scc_si_notes" "notes" { - page_size = 3 + provider_id = "tf-test" } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. * `account_id` - (Optional, String) Account ID is optional, if not provided value will be inferred from the token retrieved from the IBM Cloud API key. +* `provider_id` - (Required, Forces new resource, String) Part of the parent. This field contains the provider ID. For example: providers/{provider_id}. * `pages_size` - (Optional, String) Number of notes to return in the list. * `page_token` - (Optional, String) Token to provide to skip to a particular spot in the list. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/scc_si_occurrence.html.markdown b/website/docs/d/scc_si_occurrence.html.markdown new file mode 100644 index 000000000..f5061caa2 --- /dev/null +++ b/website/docs/d/scc_si_occurrence.html.markdown @@ -0,0 +1,106 @@ +--- +layout: "ibm" +subcategory: "Security and Compliance Center" +page_title: "IBM : ibm_scc_si_occurence" +description: |- + Get information about Security and Compliance Center +--- + +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + +# ibm_scc_si_occurence + +Retrieve information about a Security and Compliance Center occurrence. For more information, about Security and Compliance Center, see [getting started with Security and Compliance Center](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-getting-started). + +## Example usage + +```terraform +data "ibm_scc_si_occurence" "scc_si_occurence" { + occurrence_id = "occurrence_id" + provider_id = "provider_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `account_id` - (Optional, String) Account ID is optional, if not provided value will be inferred from the token retrieved from the IBM Cloud API key. +- `occurrence_id` - (Required, Forces new resource, String) Second part of occurrence `name`: **providers/{provider_id}/occurrences/{occurrence_id}**. +- `provider_id` - (Required, Forces new resource, String) Part of the parent. This field contains the provider ID. For example: **providers/{provider_id}**. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the scc_si_occurence. +- `context` - (Optional, List) + + Nested scheme for **context**: + - `component_name` - (Optional, String) The name of the component the occurrence applies to. + - `environment_name` - (Optional, String) The name of the environment the occurrence applies to. + - `region` - (Optional, String) The IBM Cloud region. + - `resource_crn` - (Optional, String) The resource CRN (e.g. certificate CRN, image CRN). + - `resource_id` - (Optional, String) The resource ID, in case the CRN is not available. + - `resource_name` - (Optional, String) The user-friendly resource name. + - `resource_type` - (Optional, String) The resource type name (e.g. Pod, Cluster, Certificate, Image). + - `service_crn` - (Optional, String) The service CRN (e.g. CertMgr Instance CRN). + - `service_name` - (Optional, String) The service name (e.g. CertMgr). + - `toolchain_id` - (Optional, String) The id of the toolchain the occurrence applies to. + +- `create_time` - (Optional, String) Output only. The time this `Occurrence` was created. + +- `finding` - (Optional, List) Finding provides details about a finding occurrence. + + Nested scheme for **finding**: + - `certainty` - (Optional, String) Note provider-assigned confidence on the validity of an occurrence- LOW: Low Certainty- MEDIUM: Medium Certainty- HIGH: High Certainty. + - Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`. + - `data_transferred` - (Optional, List) It provides details about data transferred between clients and servers. + + Nested scheme for **data_transferred**: + - `client_bytes` - (Optional, Integer) The number of client bytes transferred. + - `client_packets` - (Optional, Integer) The number of client packets transferred. + - `server_bytes` - (Optional, Integer) The number of server bytes transferred. + - `server_packets` - (Optional, Integer) The number of server packets transferred. + - `network_connection` - (Optional, List) It provides details about a network connection. + + Nested scheme for **network_connection**: + - `client` - (Optional, List) It provides details about a socket address. + + Nested scheme for **client**: + - `address` - (Required, String) The IP address of this socket address. + - `port` - (Optional, Integer) The port number of this socket address. + - `direction` - (Optional, String) The direction of this network connection. + - `protocol` - (Optional, String) The protocol of this network connection. + - `server` - (Optional, List) It provides details about a socket address. + + Nested scheme for **server**: + - `address` - (Required, String) The IP address of this socket address. + - `port` - (Optional, Integer) The port number of this socket address. + - `next_steps` - (Optional, List) Remediation steps for the issues reported in this finding. They override the note's next steps. + + Nested scheme for **next_steps**: + - `title` - (Optional, String) Title of this next step. + - `url` - (Optional, String) The URL associated to this next steps. + - `severity` - (Optional, String) Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact. + - Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`. + +- `id` - (Required, String) The id of the occurrence. + +- `kind` - (Required, String) The type of note. Use this field to filter notes and occurences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard. + - Constraints: Allowable values are: `FINDING`, `KPI`, `CARD`, `CARD_CONFIGURED`, `SECTION`. + +- `kpi` - (Optional, List) Kpi provides details about a KPI occurrence. + + Nested scheme for **kpi**: + - `total` - (Optional, Float) The total value of this KPI. + - `value` - (Required, Float) The value of this KPI. + +- `note_name` - (Required, String) An analysis note associated with this image, in the form "{account_id}/providers/{provider_id}/notes/{note_id}" This field can be used as a filter in list requests. + +- `remediation` - (Optional, String) A description of actions that can be taken to remedy the `Note`. + +- `resource_url` - (Optional, String) The unique URL of the resource, image or the container, for which the `Occurrence` applies. For example, https://gcr.io/provider/image@sha256:foo. This field can be used as a filter in list requests. + +- `update_time` - (Optional, String) Output only. The time this `Occurrence` was last updated. \ No newline at end of file diff --git a/website/docs/d/scc_si_occurrences.html.markdown b/website/docs/d/scc_si_occurrences.html.markdown new file mode 100644 index 000000000..cff8e8271 --- /dev/null +++ b/website/docs/d/scc_si_occurrences.html.markdown @@ -0,0 +1,106 @@ +--- +layout: "ibm" +subcategory: "Security and Compliance Center" +page_title: "IBM : ibm_scc_si_occurrences" +description: |- + Get information about Security and Compliance Center +--- + +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + +# ibm_scc_si_occurences + +Retrieve information about a Security and Compliance Center occurrences. For more information, about Security and Compliance Center, see [custom findings](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-setup_custom). + +## Example usage + +```terraform +data "ibm_scc_si_occurences" "scc_si_occurences" { + provider_id = "tf-test" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `account_id` - (Optional, String) Account ID is optional, if not provided value will be inferred from the token retrieved from the IBM Cloud API key. +- `provider_id` - (Required, Forces new resource, String) Part of the parent. This field contains the provider ID. For example: providers/{provider_id}. +- `pages_size` - (Optional, String) Number of notes to return in the list. +- `page_token` - (Optional, String) Token to provide to skip to a particular spot in the list. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `scc_si_occurences`. +- `context` - (Optional, List) + + Nested scheme for **context**: + - `component_name` - (Optional, String) The name of the component the occurrence applies to. + - `environment_name` - (Optional, String) The name of the environment the occurrence applies to. + - `region` - (Optional, String) The IBM Cloud region. + - `resource_crn` - (Optional, String) The resource CRN For example certificate CRN, image CRN. + - `resource_id` - (Optional, String) The resource ID, in case the CRN is not available. + - `resource_name` - (Optional, String) The user-friendly resource name. + - `resource_type` - (Optional, String) The resource type name For example Pod, Cluster, Certificate, Image. + - `service_crn` - (Optional, String) The service CRN For example CertMgr Instance CRN. + - `service_name` - (Optional, String) The service name For example CertMgr. + - `toolchain_id` - (Optional, String) The ID of the toolchain the occurrence applies to. + +- `create_time` - (Optional, String) Output only. The time this `Occurrence` was created. + +- `finding` - (Optional, List) Finding provides details about a finding occurrence. + + Nested scheme for **finding**: + - `certainty` - (Optional, String) Note provider-assigned confidence on the validity of an occurrence- LOW: Low Certainty- MEDIUM: Medium Certainty- HIGH: High Certainty. + - Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`. + - `data_transferred` - (Optional, List) It provides details about data transferred between clients and servers. + + Nested scheme for **data_transferred**: + - `client_bytes` - (Optional, Integer) The number of client bytes transferred. + - `client_packets` - (Optional, Integer) The number of client packets transferred. + - `server_bytes` - (Optional, Integer) The number of server bytes transferred. + - `server_packets` - (Optional, Integer) The number of server packets transferred. + - `network_connection` - (Optional, List) It provides details about a network connection. + + Nested scheme for **network_connection**: + - `client` - (Optional, List) It provides details about a socket address. + + Nested scheme for **client**: + - `address` - (Required, String) The IP address of this socket address. + - `port` - (Optional, Integer) The port number of this socket address. + - `direction` - (Optional, String) The direction of this network connection. + - `protocol` - (Optional, String) The protocol of this network connection. + - `server` - (Optional, List) It provides details about a socket address. + + Nested scheme for **server**: + - `address` - (Required, String) The IP address of this socket address. + - `port` - (Optional, Integer) The port number of this socket address. + - `next_steps` - (Optional, List) Remediation steps for the issues reported in this finding. They override the note's next steps. + + Nested scheme for **next_steps**: + - `title` - (Optional, String) Title of this next step. + - `url` - (Optional, String) The URL associated to this next steps. + - `severity` - (Optional, String) Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact. + - Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`. + +- `id` - (Required, String) The ID of the occurrence. + +- `kind` - (Required, String) The type of note. Use this field to filter notes and occurences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard. + - Constraints: Allowable values are: `FINDING`, `KPI`, `CARD`, `CARD_CONFIGURED`, `SECTION`. + +- `kpi` - (Optional, List) Kpi provides details about a KPI occurrence. +Nested scheme for **kpi**: + - `total` - (Optional, Float) The total value of this KPI. + - `value` - (Required, Float) The value of this KPI. + +- `note_name` - (Required, String) An analysis note associated with this image, in the form **{account_id}/providers/{provider_id}/notes/{note_id}** This field can be used as a filter in list requests. + +- `remediation` - (Optional, String) A description of actions that can be taken to remedy the `Note`. + +- `resource_url` - (Optional, String) The unique URL of the resource, image or the container, for which the `Occurrence` applies. For example, https://gcr.io/provider/image@sha256:foo. This field can be used as a filter in list requests. + +- `update_time` - (Optional, String) Output only. The time this `Occurrence` was last updated. + diff --git a/website/docs/d/scc_si_providers.html.markdown b/website/docs/d/scc_si_providers.html.markdown index c58a921e5..a46a8d5e5 100644 --- a/website/docs/d/scc_si_providers.html.markdown +++ b/website/docs/d/scc_si_providers.html.markdown @@ -6,30 +6,33 @@ description: |- Get information about scc_si_providers --- +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + # ibm_scc_si_providers Provides a read-only data source for scc_si_providers. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. -## Example Usage +## Example usage -```hcl +```terraform data "ibm_scc_si_providers" "providers" { limit = 4 } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your data source. * `limit` - (Optional, String) Limit the number of the returned documents to the specified number. * `skip` - (Optional, String) The offset is the index of the item from which you want to start returning data from. Default is 0. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your data source is created. -* `id` - The unique identifier of the scc_si_provider. +* `id` - The unique identifier of the scc_si_providers. * `limit` - (Optional, Integer) The number of elements returned in the current instance. The default is 200. * `providers` - (Optional, List) The providers requested. diff --git a/website/docs/d/schematics_action.html.markdown b/website/docs/d/schematics_action.html.markdown index 5ca73d74f..699f820eb 100644 --- a/website/docs/d/schematics_action.html.markdown +++ b/website/docs/d/schematics_action.html.markdown @@ -21,182 +21,225 @@ data "ibm_schematics_action" "schematics_action" { ## Argument reference Review the argument references that you can specify for your data source. -- `action_id` - (Required, String) Use GET or actions API to see the action IDs in your IBM Cloud account. +- `action_id` - (Required, String) Action Id. Use GET /actions API to look up the Action Ids in your IBM Cloud account. + +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. -- `account` - (String) The action account ID. -- `bastion` - (String) The complete target details with the user inputs and the system generated data. Nested bastion blocks have the following structure. - - Nested scheme for `bastion`: - - `name` - (String) The target name. - - `type` - (String) The target type such as, `cluster`, `vsi`, `icd`, `vpc`. - - `description` - (String) The target description. - - `resource_query` - (String) The resource selection query string. - - `credential` - (String) Override credential for each resource. Reference to credentials values, used by all the resources. - - `id` - (String) The target ID. - - `created_at` - (String) The targets creation time. - - `created_by` - (String) The Email address of the user who created the targets. - - `updated_at` - (String) The targets update time. - - `updated_by` - (String) The Email address of user who updated the targets. - - `sys_lock` - (String) The system lock status.Nested sys_lock blocks have the following structure. - - Nested scheme for `sys_lock`: - - `sys_locked` - (String) Is the workspace locked by the Schematics action? - - `sys_locked_by` - (String) The name of the user who performed the action, that lead to lock the workspace. - - `sys_locked_at` - (String) When the user performed the action that lead to lock the workspace?- - - `resource_ids` - (String) Array of the resource IDs. -- `command_parameter` - (String) Schematics job command parameter such as `playbook-name`, `capsule-name`, or `flow-name`. -- `created_at` - (Timestamp) The action creation time. -- `created_by` - (String) The Email address of the user who created an action. -- `crn` - (String) The action Cloud Resource Name. -- `credentials` - (String) Credentials of an action. Nested `credentials` blocks have the following structure. - - Nested scheme for `credentials`: - - `metadata` - (String) User editable metadata for the variables. Nested `metadata` blocks have the following structure. - - Nested scheme for `metadata`: - - `aliases` - (String) The list of an aliases for the variable name. - - `description` - (String) The description of the metadata. - - `default_value` - (String) The default value for the variable, if the override value is not specified. - - `group_by` - (String) Display name of the group this variable belongs to. - - `immutable` - (String) Is the variable read only?- - - `hidden` - (String) If set **true**, the variable will not be displayed on console or command-line. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regular expression for the variable value. - - `options` - (String) The list of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `position` - (String) Relative position of this variable in a list. - - `secure` - (String) Is the variable secure or sensitive? - - `source` - (String) Source of the meta-data. - - `type` - (String) The type of the variable. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) The name of the variable. - - `value` - (String) The value for the variable or reference to the value. -- `description` - (String) The action description. -- `id` - (String) The unique ID of the Schematics action. -- `inputs` - (String) Input variables for an action. Nested `inputs` blocks have the following structure. - - Nested scheme for `inputs`: - - `metadata` - (String) User editable metadata for the variables. Nested `metadata` blocks have the following structure. - - Nested scheme for `metadata`: - - `aliases` - (String) The list of an aliases for the variable name. - - `description` - (String) The description of the metadata. - - `default_value` - (String) The default value for the variable, if the override value is not specified. - - `group_by` - (String) The display name of the group this variable belongs to. - - `immutable` - (String) Is the variable read only? - - `hidden` - (String) If set to **true**, the variable will not be displayed on console or command-line. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regular expression for the variable value. - - `options` - (String) The list of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `position` - (String) Relative position of this variable in a list. - - `secure` - (Bool) Is the variable secure or sensitive? - - `source` - (String) The source of this metadata. - - `type` - (String) The type of the variable. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) The name of the variable. - - `value` - (String) The value for the variable or reference to the value. -- `location` - (String) List of action locations supported by Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics. -- `name` - (String) The unique action name. -- `namespace` - (String) The name of the namespace. -- `outputs` - (String) The output variables for an action. Nested `outputs` blocks have the following structure. - - Nested scheme for `outputs`: - - `metadata` - (String) User editable metadata for the variables. Nested metadata blocks have the following structure. - - Nested scheme for `metadata`: - - `aliases` - (String) List of aliases for the variable name. - - `description` - (String) Description of the meta data. - - `default_value` - (String) Default value for the variable, if the override value is not specified. - - `group_by` - (String) Display name of the group this variable belongs to. - - `immutable` - (String) Is the variable read only ? - - `hidden` - (String) If **true**, the variable will not be displayed on console or command-line. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regex for the variable value. - - `options` - (String) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `position` - (String) Relative position of this variable in a list. - - `secure` - (String) Is the variable secure or sensitive? - - `source` - (String) Source of this meta-data. - - `type` - (String) Type of the variable. - - `link` - (String) Reference link to the variable value By default the expression will point to self.value. - - `name` - (String) Name of the variable. - - `value` - (String) Value for the variable or reference to the value. -- `playbook_names` - (String) Playbook names retrieved from the repository. -- `resource_group` - (String) The resource group name for an action. By default, action is created in default resource group. -- `source_readme_url` - (String) URL of the `README` file, for the source. -- `source` - (String) Source of templates, playbooks, or controls. Nested `source` blocks have the following structure. - - Nested scheme for `source`: - - `source_type` - (String) Type of source for the template. - - `git` - (String) The connection details to Git source. Nested `Git` blocks have the following structure. - - Nested scheme for `git`: - - `git_branch` - (String) The name of the branch, used to fetch the Git Repository. - - `git_repo_folder` - (String) The name of the folder in the Git Repository, that contains the template. - - `git_release` - (String) The name of the release tag, used to fetch the Git Repository. - - `git_token` - (String) The personal access token to connect to Git URLs. - - `git_repo_url` - (String) The URL to the Git repository that can be used to clone the template. -- `source_type` - (String) Type of source for the template. -- `settings` - (String) Environment variables for an action. Nested settings blocks have the following structure. - - Nested scheme for `settings`: - - `metadata` - (String) User editable metadata for the variables. Nested metadata blocks have the following structure. - - Nested scheme for `metadata`: - - `aliases` - (String) List of aliases for the variable name. - - `description` - (String) Description of the meta data. - - `default_value` - (String) Default value for the variable, if the override value is not specified. - - `group_by` - (String) Display name of the group this variable belongs to. - - `immutable` - (String) Is the variable read only ?. - - `hidden` - (String) If true, the variable will not be displayed on console or command-line. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regex for the variable value. - - `options` - (String) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `position` - (String) Relative position of this variable in a list. - - `secure` - (String) Is the variable secure or sensitive? - - `source` - (String) Source of this meta-data. - - `type` - (String) Type of the variable. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) Name of the variable. - - `value` - (String) Value for the variable or reference to the value. -- `state` - (String) Computed state of an action. Nested `state` blocks have the following structure. - - Nested scheme for `state`: - - `status_code` - (String) The status of automation such as `workdspace`, or `action`. - - `status_message` - (String) Automation status message to be displayed along with the status code. -- `sys_lock` - (String) System lock status. Nested sys_lock blocks have the following structure. - - Nested scheme for `sys_lock`: - - `sys_locked` - (String) Is the Workspace locked by the Schematic action?- - - `sys_locked_by` - (String) Name of the user who performed the action, that lead to lock the Workspace. - - `sys_locked_at` - (String) When the user performed the action that lead to lock the Workspace?- -- `source_created_at` - (String) The Ansible playbook source creation time. -- `source_created_by` - (String) The Email address of user who created the Ansible playbook Source. -- `source_updated_at` - (String) The Ansible playbook update time. -- `source_updated_by` - (String) The Email address of user who updated the Ansible playbook source. -- `tags` - (String) The action tags. -- `targets_ini` - (String) Inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#inventory-host-grps). -- `trigger_record_id` - (String) The trigger ID. -- `updated_at` - (Timestamp) The action update time. -- `updated_by` - (String) The Email address of the user who updated an action. -- `user_state` - (String) User defined status of the Schematics object. Nested user_state blocks have the following structure. - - Nested scheme for `user_state`: - - `state` - (String) User defined states * **draft Object** can be modified, and can be used by jobs run by an author, during execution * **live Object** can be modified, and can be used by jobs during execution * **locked Object** cannot be modified, and can be used by jobs during execution * **disable Object** can be modified, and cannot be used by Jobs during execution. - - `set_by` - (String) The name of an user who set the state of an Object. - - `set_at` - (String) The user who sets the state of an object. + * `action_inputs` - (List) Input variables for the Action. +Nested scheme for **action_inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `action_outputs` - (List) Output variables for the Action. +Nested scheme for **action_outputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `bastion` - (List) Describes a bastion resource. +Nested scheme for **bastion**: + * `name` - (String) Bastion Name(Unique). + * `host` - (String) Reference to the Inventory resource definition. + +* `bastion_credential` - (List) User editable variable data & system generated reference to value. +Nested scheme for **bastion_credential**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `command_parameter` - (String) Schematics job command parameter (playbook-name). + +* `created_at` - (String) Action creation time. + +* `created_by` - (String) E-mail address of the user who created an action. + +* `credentials` - (List) credentials of the Action. +Nested scheme for **credentials**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `crn` - (String) Action Cloud Resource Name. + +* `description` - (String) Action description. + +* `id` - (String) Action ID. + +* `inventory` - (String) Target inventory record ID, used by the action or ansible playbook. + +* `name` - (String) The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action. + +* `playbook_names` - (List) Playbook names retrieved from the respository. + +* `resource_group` - (String) Resource-group name for an action. By default, action is created in default resource group. + +* `settings` - (List) Environment variables for the Action. +Nested scheme for **settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `source` - (List) Source of templates, playbooks, or controls. +Nested scheme for **source**: + * `source_type` - (Required, String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `git` - (List) Connection details to Git source. + Nested scheme for **git**: + * `computed_git_repo_url` - (String) The Complete URL which is computed by git_repo_url, git_repo_folder and branch. + * `git_repo_url` - (String) URL to the GIT Repo that can be used to clone the template. + * `git_token` - (String) Personal Access Token to connect to Git URLs. + * `git_repo_folder` - (String) Name of the folder in the Git Repo, that contains the template. + * `git_release` - (String) Name of the release tag, used to fetch the Git Repo. + * `git_branch` - (String) Name of the branch, used to fetch the Git Repo. + * `catalog` - (List) Connection details to IBM Cloud Catalog source. + Nested scheme for **catalog**: + * `catalog_name` - (String) name of the private catalog. + * `offering_name` - (String) Name of the offering in the IBM Catalog. + * `offering_version` - (String) Version string of the offering in the IBM Catalog. + * `offering_kind` - (String) Type of the offering, in the IBM Catalog. + * `offering_id` - (String) Id of the offering the IBM Catalog. + * `offering_version_id` - (String) Id of the offering version the IBM Catalog. + * `offering_repo_url` - (String) Repo Url of the offering, in the IBM Catalog. + +* `source_created_at` - (String) Action Playbook Source creation time. + +* `source_created_by` - (String) E-mail address of user who created the Action Playbook Source. + +* `source_readme_url` - (String) URL of the `README` file, for the source URL. + +* `source_type` - (String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + +* `source_updated_at` - (String) The action playbook updation time. + +* `source_updated_by` - (String) E-mail address of user who updated the action playbook source. + +* `state` - (List) Computed state of the Action. +Nested scheme for **state**: + * `status_code` - (String) Status of automation (workspace or action). + * Constraints: Allowable values are: normal, pending, disabled, critical + * `status_job_id` - (String) Job id reference for this status. + * `status_message` - (String) Automation status message - to be displayed along with the status_code. + +* `sys_lock` - (List) System lock status. +Nested scheme for **sys_lock**: + * `sys_locked` - (Boolean) Is the automation locked by a Schematic job ?. + * `sys_locked_by` - (String) Name of the User who performed the job, that lead to the locking of the automation. + * `sys_locked_at` - (String) When the User performed the job that lead to locking of the automation ?. + +* `tags` - (List) Action tags. + +* `targets_ini` - (String) Inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps). + +* `updated_at` - (String) Action updation time. + +* `updated_by` - (String) E-mail address of the user who updated an action. + +* `user_state` - (List) User defined status of the Schematics object. +Nested scheme for **user_state**: + * `state` - (String) User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution. + * Constraints: Allowable values are: draft, live, locked, disable + * `set_by` - (String) Name of the User who set the state of the Object. + * `set_at` - (String) When the User who set the state of the Object. diff --git a/website/docs/d/schematics_inventory.html.markdown b/website/docs/d/schematics_inventory.html.markdown new file mode 100644 index 000000000..0192567d2 --- /dev/null +++ b/website/docs/d/schematics_inventory.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "Schematics" +layout: "ibm" +page_title: "IBM : ibm_schematics_inventory" +sidebar_current: "docs-ibm-datasource-schematics-inventory" +description: |- + Get information about Schematics action inventory. +--- + +# ibm_schematics_inventory + +Retrieve information about the Schematics inventory. For more information, about Schematics action inventories, see [Creating resource inventories for Schematics actions](https://cloud.ibm.com/docs/schematics?topic=schematics-inventories-setup). + +## Example usage + +```terraform +data "ibm_schematics_inventory" "schematics_inventory" { + inventory_id = "inventory_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `inventory_id` - (Required, String) Resource Inventory Id. Use `GET /v2/inventories` API to look up the Resource Inventory definition Ids in your IBM Cloud account. + +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `created_at` - (String) The inventory creation time. +- `created_by` - (String) The Email address of user who created the Inventory. +- `description` - (String) The description of your inventory. The description can be up to `2048` characters long in size. +- `id` - (String) The inventory ID. +- `inventories_ini` - (String) Input inventory of host and host group for the playbook, in the .ini file format. +- `name` - (String) The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. +- `resource_group` - (String) The resource group name for the inventory definition. By default, inventory will be created in Default Resource Group. +- `resource_queries` - (List) Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook. +- `updated_at` - (String) The inventory updation time. +- `updated_by` - (String) The Email address of user who updated the inventory. diff --git a/website/docs/d/schematics_job.html.markdown b/website/docs/d/schematics_job.html.markdown index a9d8512b9..5b3bee4d6 100644 --- a/website/docs/d/schematics_job.html.markdown +++ b/website/docs/d/schematics_job.html.markdown @@ -18,210 +18,622 @@ data "ibm_schematics_job" "schematics_job" { } ``` ## Argument reference -Review the argument references that you can specify for your data source. -- `job_id` - (Required, String) Use GET or jobs API to see the job IDs in your IBM Cloud account. +Review the argument reference that you can specify for your data source. + +* `job_id` - (String) Job Id. Use `GET /v2/jobs` API to look up the Job Ids in your IBM Cloud account. + +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de ## Attribute reference -In addition to the argument reference list, you can access the following attribute references after your data source is created. - -- `bastion` - (String) The complete target details with the user inputs and the system generated data. Nested bastion blocks have the following structure. - - Nested scheme for `bastion`: - - `credential` - (String) Override credential for each resource. Reference to credentials values, used by all the resources. - - `created_at` - (String) The targets creation time. - - `created_by` - (String) The Email address of the user who created the targets. - - `description` - (String) The target description. - - `id` - (String) The target ID. - - `name` - (String) The target name. - - `resource_query` - (String) The resource selection query string. - `resource_ids` - (String) Array of the resource IDs. - - `sys_lock` - (String) The system lock status.Nested sys_lock blocks have the following structure. - - `sys_lock.sys_locked` - (String) Is the workspace locked by the Schematics action?- - - `sys_lock.sys_locked_by` - (String) The name of the user who performed the action, that lead to lock the workspace. - - `sys_lock.sys_locked_at` - (String) The action that lead to lock the workspace? - - `type` - (String) The target type such as, `cluster`, `vsi`, `icd`, `vpc`. - - `updated_at` - (String) The targets update time. - - `updated_by` - (String) The Email address of user who updated the targets. -- `command_object` - (String) The name of the Schematics automation resource. -- `command_object_id` - (String) The job command object ID such as `workspace-id`, `action-id`, or `control-id`. -- `command_name` - (String) The Schematics job command name. -- `command_parameter` - (String) The Schematics job command parameter such as `playbook-name`, `capsule-name`, or `flow-name`. -- `command_options` - (String) The command line options for the command. -- `data` (String) The Job data. Nested data blocks have the following structure. - - Nested scheme for `data`: - - `job_type` - (String) Type of the job. - - `action_job_data`- (String) The action job data. Nested `action_job_data` blocks have the following structure. - - Nested scheme for `action_job_data`: - - `action_name` - (String) The flow name. - - `inputs` - (String) The input variables for an action job. Nested `inputs` blocks have the following structure. - - Nested scheme for `inputs`: - - `metadata` - (String) User editable metadata for the variables. Nested `metadata` blocks have the following structure. - - Nested scheme for `metadata`: - - `type` - (String) The type of the variable. - - `aliases` - (String) The list of an aliases for the variable name. - - `description` - (String) The description of the metadata. - - `default_value` - (String) The default value for the variable, if the override value is not specified. - - `secure` - (String) Is the variable secure or sensitive?- - - `immutable` - (String) Is the variable read only?- - - `hidden` - (String) If set to **true**, the variable will not be displayed on console or command-line. - - `options` - (String) The list of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regular expression for the variable value. - - `position` - (String) Relative position of this variable in a list. - - `group_by` - (String) The display name of the group this variable belongs to. - - `source` - (String) The source of this metadata. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) The name of the variable. - - `value` - (String) The value for the variable or reference to the value. -- `description` - (String) The job description derived from the related action. -- `duration` - (String) Duration of job execution, for example, `40 seconds`. -- `end_at` - (String) The job end time. -- `id` - (String) The unique ID of the Schematics job. -- `id` - (String) The job ID. -- `location` - (String) List of an action locations supported by Schematics service. Note this does not limit the location of the resources provisioned using Schematics. -- `log_store_url` - (String) The job log store URL. -- `name` - (String) The unique job name, derived from the related action. -- `outputs` - (String) The output variables for an action. Nested `outputs` blocks have the following structure. - - Nested scheme for `output`: - - `metadata` - (String) User editable metadata for the variables. Nested metadata blocks have the following structure. - - Nested scheme for `metadata`: - - `type` - (String) Type of the variable. - - `aliases` - (String) List of aliases for the variable name. - - `description` - (String) Description of the meta data. - - `default_value` - (String) Default value for the variable, if the override value is not specified. - - `secure` - (String) Is the variable secure or sensitive?- - - `immutable` - (String) Is the variable read only ?- - - `hidden` - (String) If set **true**, the variable will not be displayed on console or command-line. - - `options` - (String) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regex for the variable value. - - `position` - (String) Relative position of this variable in a list. - - `group_by` - (String) Display name of the group this variable belongs to. - - `source` - (String) Source of this meta-data. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) Name of the variable. - - `value` - (String) Value for the variable or reference to the value. -- `resource_group` - (String) The resource group name derived from the related action. -- `settings` - (String) Environment variables for an action. Nested settings blocks have the following structure. - - Nested scheme for `id`: - - `metadata` - (String) User editable metadata for the variables. Nested metadata blocks have the following structure. - - Nested scheme for `metadata`: - - `type` - (String) Type of the variable. - - `aliases` - (String) List of aliases for the variable name. - - `description` - (String) Description of the meta data. - - `default_value` - (String) Default value for the variable, if the override value is not specified. - - `secure` - (String) Is the variable secure or sensitive?- - - `immutable` - (String) Is the variable read only? - - `hidden` - (String) If set **true**, the variable will not be displayed on console or command-line. - - `options` - (String) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regex for the variable value. - - `position` - (String) Relative position of this variable in a list. - - `group_by` - (String) Display name of the group this variable belongs to. - - `source` - (String) Source of this meta-data. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. - - `name` - (String) Name of the variable. - - `value` - (String) Value for the variable or reference to the value. -- `submitted_at` - (String) The job submission time. -- `submitted_by` - (String) The Email address of the user who submitted the job. -- `start_at` - (String) The job start time. -- `status` - (String) The job status. Nested `status` blocks have the following structure. - - Nested scheme for `status`: - - `action_job_status` - (String) The action job status. Nested `action_job_status` blocks have the following structure. - - Nested scheme for `action_job_status`: - - `action_name` - (String) The action name. - - `bastion_status_code` - (String) The status of the resources. - - `bastion_status_message` - (String) The bastion status message to be displayed along with the `bastion_status_code`. - - `status_code` - (String) The status of the jobs. - - `status_message` - (String) An action job status message to be displayed along with the `action_status_code`. - - `targets_status_code` - (String) -Status of the resources. - - `targets_status_message` - (String) -Aggregated status message for all target resources, to be displayed along with the targets_status_code. - - `updated_at` - (String) The job status update timestamp. -- `settings` - (String) The environment variables used by all the templates in an action. Nested `settings` blocks have the following structure. - - Nested scheme for `settings`: - - `name` - (String) Name of the variable. - - `value` - (String) Value for the variable or reference to the value. - - `metadata` - (String) User editable metadata for the variables. Nested metadata blocks have the following structure. - - Nested scheme for `metadata`: - - `type` - (String) Type of the variable. - - `aliases` - (String) List of aliases for the variable name. - - `description` - (String) Description of the meta data. - - `default_value` - (String) Default value for the variable, if the override value is not specified. - - `secure` - (String) Is the variable secure or sensitive?- - - `immutable` - (String) Is the variable read only ?- - - `hidden` - (String) If set **true**, the variable will not be displayed on console or command-line. - - `options` - (String) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. - - `min_value` - (String) Minimum value of the variable. Applicable for integer type. - - `max_value` - (String) Maximum value of the variable. Applicable for integer type. - - `min_length` - (String) Minimum length of the variable value. Applicable for string type. - - `max_length` - (String) Maximum length of the variable value. Applicable for string type. - - `matches` - (String) Regex for the variable value. - - `position` - (String) Relative position of this variable in a list. - - `group_by` - (String) Display name of the group this variable belongs to. - - `source` - (String) Source of this meta-data. - - `link` - (String) Reference link to the variable value By default the expression will point to `self.value`. -- `log_summary` - (String) -Job log summary record. Nested `log_summary` blocks have the following structure. - - Nested scheme for `log_summary`: - - `elapsed_time` - (String) The job log elapsed time `log_analyzed_till`, `log_start_at`. - - `job_id` - (String) The workspace ID. - - `job_type` - (String) The type of job. - - `log_start_at` - (String) The job log start timestamp. - - `log_analyzed_till` - (String) The job log update timestamp. - - `log_errors` - (String) -Job log errors. Nested log_errors blocks have the following structure. - - Nested scheme for `log_errors`: - - `error_code` - (String) The error code in the Log. - - `error_msg` - (String) The summary error message in the log. - - `error_count` - (String) The number of occurrence. - - `repo_download_job` - (String) -Repo download Job log summary. Nested `repo_download_job `blocks have the following structure. - - Nested scheme for `repo_download_job`: - - `detected_filetype` - (String) Detected template or data file type. - - `quarantined_file_count` - (String) The number of files quarantined. - - `inputs_count` - (String) The number of inputs detected. - - `outputs_count` - (String) The number of outputs detected. - - `scanned_file_count` - (String) The number of files scanned. - - `action_job` - (String) The flow job log summary. Nested `action_job` blocks have the following structure. - - Nested scheme for `action_job`: - - `play_count` - (String) -number of plays in playbook. - - `target_count` - (String) The number of targets or hosts. - - `task_count` - (String) The number of tasks in playbook. - - `recap` - (String) The recap records. Nested recap blocks have the following structure. - - Nested scheme for `recap`: - - `changed` - (String) The number of changed. - - `failed` - (String) The number of failed. - - `ok` - (String) -the number of OK. - - `skipped` - (String) The number of skipped. - - `target` - (String) The list of target or host name. - - `unreachable` - (String) The number of unreachable. -- `results_url` - (String) The job results store URL. -- `state_store_url` - (String) The job state store URL. -- `targets_ini` - (String) Inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#inventory-host-grps). -- `tags` - (String) The user defined tags, while running the job. -- `updated_at` - (Timestamp) The job status update timestamp. + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the schematics_job. +* `bastion` - (List) Describes a bastion resource. +Nested scheme for **bastion**: + * `name` - (String) Bastion Name(Unique). + * `host` - (String) Reference to the Inventory resource definition. + +* `command_name` - (String) Schematics job command name. + * Constraints: Allowable values are: workspace_plan, workspace_apply, workspace_destroy, workspace_refresh, ansible_playbook_run, ansible_playbook_check, create_action, put_action, patch_action, delete_action, system_key_enable, system_key_delete, system_key_disable, system_key_rotate, system_key_restore, create_workspace, put_workspace, patch_workspace, delete_workspace, create_cart, create_environment, put_environment, delete_environment, environment_init, environment_install, environment_uninstall, repository_process + +* `command_object` - (String) Name of the Schematics automation resource. + * Constraints: Allowable values are: workspace, action, system, environment + +* `command_object_id` - (String) Job command object id (workspace-id, action-id). + +* `command_options` - (List) Command line options for the command. + +* `command_parameter` - (String) Schematics job command parameter (playbook-name). + +* `data` - (List) Job data. +Nested scheme for **data**: + * `job_type` - (String) Type of Job. + * Constraints: Allowable values are: repo_download_job, workspace_job, action_job, system_job, flow-job + * `workspace_job_data` - (List) Workspace Job data. + Nested scheme for **workspace_job_data**: + * `workspace_name` - (String) Workspace name. + * `flow_id` - (String) Flow Id. + * `flow_name` - (String) Flow name. + * `inputs` - (List) Input variables data used by the Workspace Job. + Nested scheme for **inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (List) Output variables data from the Workspace Job. + Nested scheme for **outputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (List) Environment variables used by all the templates in the Workspace. + Nested scheme for **settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `template_data` - (List) Input / output data of the Template in the Workspace Job. + Nested scheme for **template_data**: + * `template_id` - (String) Template Id. + * `template_name` - (String) Template name. + * `flow_index` - (Integer) Index of the template in the Flow. + * `inputs` - (List) Job inputs used by the Templates. + Nested scheme for **inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (List) Job output from the Templates. + Nested scheme for **outputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (List) Environment variables used by the template. + Nested scheme for **settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `updated_at` - (String) Job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + * `action_job_data` - (List) Action Job data. + Nested scheme for **action_job_data**: + * `action_name` - (String) Flow name. + * `inputs` - (List) Input variables data used by the Action Job. + Nested scheme for **inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (List) Output variables data from the Action Job. + Nested scheme for **outputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (List) Environment variables used by all the templates in the Action. + Nested scheme for **settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `updated_at` - (String) Job status updation timestamp. + * `inventory_record` - (List) Complete inventory resource details with user inputs and system generated data. + Nested scheme for **inventory_record**: + * `name` - (String) The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. + * `id` - (String) Inventory id. + * `description` - (String) The description of your Inventory. The description can be up to 2048 characters long in size. + * `location` - (String) List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de + * `resource_group` - (String) Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group. + * `created_at` - (String) Inventory creation time. + * `created_by` - (String) Email address of user who created the Inventory. + * `updated_at` - (String) Inventory updation time. + * `updated_by` - (String) Email address of user who updated the Inventory. + * `inventories_ini` - (String) Input inventory of host and host group for the playbook, in the .ini file format. + * `resource_queries` - (List) Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook. + * `materialized_inventory` - (String) Materialized inventory details used by the Action Job, in .ini format. + * `system_job_data` - (List) Controls Job data. + Nested scheme for **system_job_data**: + * `key_id` - (String) Key ID for which key event is generated. + * `schematics_resource_id` - (List) List of the schematics resource id. + * `updated_at` - (String) Job status updation timestamp. + * `flow_job_data` - (List) Flow Job data. + Nested scheme for **flow_job_data**: + * `flow_id` - (String) Flow ID. + * `flow_name` - (String) Flow Name. + * `workitems` - (List) Job data used by each workitem Job. + Nested scheme for **workitems**: + * `command_object_id` - (String) command object id. + * `command_object_name` - (String) command object name. + * `layers` - (String) layer name. + * `source_type` - (String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `source` - (List) Source of templates, playbooks, or controls. + Nested scheme for **source**: + * `source_type` - (String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `git` - (List) Connection details to Git source. + Nested scheme for **git**: + * `computed_git_repo_url` - (String) The Complete URL which is computed by git_repo_url, git_repo_folder and branch. + * `git_repo_url` - (String) URL to the GIT Repo that can be used to clone the template. + * `git_token` - (String) Personal Access Token to connect to Git URLs. + * `git_repo_folder` - (String) Name of the folder in the Git Repo, that contains the template. + * `git_release` - (String) Name of the release tag, used to fetch the Git Repo. + * `git_branch` - (String) Name of the branch, used to fetch the Git Repo. + * `catalog` - (List) Connection details to IBM Cloud Catalog source. + Nested scheme for **catalog**: + * `catalog_name` - (String) name of the private catalog. + * `offering_name` - (String) Name of the offering in the IBM Catalog. + * `offering_version` - (String) Version string of the offering in the IBM Catalog. + * `offering_kind` - (String) Type of the offering, in the IBM Catalog. + * `offering_id` - (String) Id of the offering the IBM Catalog. + * `offering_version_id` - (String) Id of the offering version the IBM Catalog. + * `offering_repo_url` - (String) Repo Url of the offering, in the IBM Catalog. + * `inputs` - (List) Input variables data for the workItem used in FlowJob. + Nested scheme for **inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (List) Output variables for the workItem. + Nested scheme for **outputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (List) Environment variables for the workItem. + Nested scheme for **settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + * `last_job` - (List) Status of the last job executed by the workitem. + Nested scheme for **last_job**: + * `command_object` - (String) Name of the Schematics automation resource. + * Constraints: Allowable values are: workspace, action, system, environment + * `command_object_name` - (String) command object name (workspace_name/action_name). + * `command_object_id` - (String) Workitem command object id, maps to workspace_id or action_id. + * `command_name` - (String) Schematics job command name. + * Constraints: Allowable values are: workspace_plan, workspace_apply, workspace_destroy, workspace_refresh, ansible_playbook_run, ansible_playbook_check, create_action, put_action, patch_action, delete_action, system_key_enable, system_key_delete, system_key_disable, system_key_rotate, system_key_restore, create_workspace, put_workspace, patch_workspace, delete_workspace, create_cart, create_environment, put_environment, delete_environment, environment_init, environment_install, environment_uninstall, repository_process + * `job_id` - (String) Workspace job id. + * `job_status` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `updated_at` - (String) Job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + +* `description` - (String) The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size. + +* `duration` - (String) Duration of job execution; example 40 sec. + +* `end_at` - (String) Job end time. + +* `id` - (String) Job ID. + +* `job_env_settings` - (List) Environment variables used by the Job while performing Action or Workspace. +Nested scheme for **job_env_settings**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + +* `job_inputs` - (List) Job inputs used by Action or Workspace. +Nested scheme for **job_inputs**: + * `name` - (String) Name of the variable. + * `value` - (String) Value for the variable or reference to the value. + * `metadata` - (List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (List) List of aliases for the variable name. + * `description` - (String) Description of the meta data. + * `default_value` - (String) Default value for the variable, if the override value is not specified. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Boolean) Is the variable readonly ?. + * `hidden` - (Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (String) Regex for the variable value. + * `position` - (Integer) Relative position of this variable in a list. + * `group_by` - (String) Display name of the group this variable belongs to. + * `source` - (String) Source of this meta-data. + * `link` - (String) Reference link to the variable value By default the expression will point to self.value. + + +* `log_store_url` - (String) Job log store URL. + +* `log_summary` - (List) Job log summary record. +Nested scheme for **log_summary**: + * `job_id` - (String) Workspace Id. + * `job_type` - (String) Type of Job. + * Constraints: Allowable values are: repo_download_job, workspace_job, action_job, system_job, flow_job + * `log_start_at` - (String) Job log start timestamp. + * `log_analyzed_till` - (String) Job log update timestamp. + * `elapsed_time` - (Float) Job log elapsed time (log_analyzed_till - log_start_at). + * `log_errors` - (List) Job log errors. + Nested scheme for **log_errors**: + * `error_code` - (String) Error code in the Log. + * `error_msg` - (String) Summary error message in the log. + * `error_count` - (Float) Number of occurrence. + * `repo_download_job` - (List) Repo download Job log summary. + Nested scheme for **repo_download_job**: + * `scanned_file_count` - (Float) Number of files scanned. + * `quarantined_file_count` - (Float) Number of files quarantined. + * `detected_filetype` - (String) Detected template or data file type. + * `inputs_count` - (String) Number of inputs detected. + * `outputs_count` - (String) Number of outputs detected. + * `workspace_job` - (List) Workspace Job log summary. + Nested scheme for **workspace_job**: + * `resources_add` - (Float) Number of resources add. + * `resources_modify` - (Float) Number of resources modify. + * `resources_destroy` - (Float) Number of resources destroy. + * `flow_job` - (List) Flow Job log summary. + Nested scheme for **flow_job**: + * `workitems_completed` - (Float) Number of workitems completed successfully. + * `workitems_pending` - (Float) Number of workitems pending in the flow. + * `workitems_failed` - (Float) Number of workitems failed. + * `workitems` - (List) + Nested scheme for **workitems**: + * `workspace_id` - (String) workspace ID. + * `job_id` - (String) workspace JOB ID. + * `resources_add` - (Float) Number of resources add. + * `resources_modify` - (Float) Number of resources modify. + * `resources_destroy` - (Float) Number of resources destroy. + * `log_url` - (String) Log url for job. + * `action_job` - (List) Flow Job log summary. + Nested scheme for **action_job**: + * `target_count` - (Float) number of targets or hosts. + * `task_count` - (Float) number of tasks in playbook. + * `play_count` - (Float) number of plays in playbook. + * `recap` - (List) Recap records. + Nested scheme for **recap**: + * `target` - (List) List of target or host name. + * `ok` - (Float) Number of OK. + * `changed` - (Float) Number of changed. + * `failed` - (Float) Number of failed. + * `skipped` - (Float) Number of skipped. + * `unreachable` - (Float) Number of unreachable. + * `system_job` - (List) System Job log summary. + Nested scheme for **system_job**: + * `target_count` - (Float) number of targets or hosts. + * `success` - (Float) Number of passed. + * `failed` - (Float) Number of failed. + +* `name` - (String) Job name, uniquely derived from the related Workspace or Action. + +* `resource_group` - (String) Resource-group name derived from the related Workspace or Action. + +* `results_url` - (String) Job results store URL. + +* `start_at` - (String) Job start time. + +* `state_store_url` - (String) Job state store URL. + +* `status` - (List) Job Status. +Nested scheme for **status**: + * `workspace_job_status` - (List) Workspace Job Status. + Nested scheme for **workspace_job_status**: + * `workspace_name` - (String) Workspace name. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace). + * `flow_status` - (List) Environment Flow JOB Status. + Nested scheme for **flow_status**: + * `flow_id` - (String) flow id. + * `flow_name` - (String) flow name. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) Flow Job status message - to be displayed along with the status_code;. + * `workitems` - (List) Environment's individual workItem status details;. + Nested scheme for **workitems**: + * `workspace_id` - (String) Workspace id. + * `workspace_name` - (String) workspace name. + * `job_id` - (String) workspace job id. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) workitem job status message;. + * `updated_at` - (String) workitem job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + * `template_status` - (List) Workspace Flow Template job status. + Nested scheme for **template_status**: + * `template_id` - (String) Template Id. + * `template_name` - (String) Template name. + * `flow_index` - (Integer) Index of the template in the Flow. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template). + * `updated_at` - (String) Job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + * `action_job_status` - (List) Action Job Status. + Nested scheme for **action_job_status**: + * `action_name` - (String) Action name. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) Action Job status message - to be displayed along with the action_status_code. + * `bastion_status_code` - (String) Status of Resources. + * Constraints: Allowable values are: none, ready, processing, error + * `bastion_status_message` - (String) Bastion status message - to be displayed along with the bastion_status_code;. + * `targets_status_code` - (String) Status of Resources. + * Constraints: Allowable values are: none, ready, processing, error + * `targets_status_message` - (String) Aggregated status message for all target resources, to be displayed along with the targets_status_code;. + * `updated_at` - (String) Job status updation timestamp. + * `system_job_status` - (List) System Job Status. + Nested scheme for **system_job_status**: + * `system_status_message` - (String) System job message. + * `system_status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `schematics_resource_status` - (List) job staus for each schematics resource. + Nested scheme for **schematics_resource_status**: + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) system job status message. + * `schematics_resource_id` - (String) id for each resource which is targeted as a part of system job. + * `updated_at` - (String) Job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + * `flow_job_status` - (List) Environment Flow JOB Status. + Nested scheme for **flow_job_status**: + * `flow_id` - (String) flow id. + * `flow_name` - (String) flow name. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) Flow Job status message - to be displayed along with the status_code;. + * `workitems` - (List) Environment's individual workItem status details;. + Nested scheme for **workitems**: + * `workspace_id` - (String) Workspace id. + * `workspace_name` - (String) workspace name. + * `job_id` - (String) workspace job id. + * `status_code` - (String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (String) workitem job status message;. + * `updated_at` - (String) workitem job status updation timestamp. + * `updated_at` - (String) Job status updation timestamp. + +* `submitted_at` - (String) Job submission time. + +* `submitted_by` - (String) Email address of user who submitted the job. + +* `tags` - (List) User defined tags, while running the job. + +* `updated_at` - (String) Job status updation timestamp. diff --git a/website/docs/d/schematics_output.html.markdown b/website/docs/d/schematics_output.html.markdown index 083928df9..693e7b6ef 100644 --- a/website/docs/d/schematics_output.html.markdown +++ b/website/docs/d/schematics_output.html.markdown @@ -34,8 +34,14 @@ data "ibm_schematics_output" "test" { Review the argument references that you can specify for your data source. - `workspace_id` - (Required, String) The ID of the workspace for which you want to retrieve output values. To find the workspace ID, use the `GET /workspaces` API. +- `template_id` - (Required, String) The ID of the template +- `output_json` - (Optional, String) The json output in string +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - `id`- (String) The unique identifier of the Schematics output. +- `resource_controller_url` - (String) The URL of the IBM Cloud dashboard that can be used to explore and view details about this Workspace +- `output_values` - (Map) Output values. diff --git a/website/docs/d/schematics_resource_query.html.markdown b/website/docs/d/schematics_resource_query.html.markdown new file mode 100644 index 000000000..3f5b55df4 --- /dev/null +++ b/website/docs/d/schematics_resource_query.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "Schematics" +layout: "ibm" +page_title: "IBM : ibm_schematics_resource_query" +sidebar_current: "docs-ibm-datasource-schematics-resource-query" +description: |- + Get information about Schematics action resource query. +--- + +# ibm_schematics_resource_query + +Retrieve information about the Schematics resource query. For more information, about Schematics action resource query, see [Supported resource queries](https://cloud.ibm.com/docs/schematics?topic=schematics-inventories-setup#supported-queries). + +## Example usage + +```terraform +data "ibm_schematics_resource_query" "schematics_resource_query" { + query_id = "query_id" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `query_id` - (Required, String) Resource query ID. Use `GET /v2/resource_query` API to look up the Resource query definition Ids in your IBM Cloud account. +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `created_at` - (String) Resource query creation time. +- `created_by` - (String) Email address of user who created the Resource query. +- `id` - (String) Resource Query ID. +- `name` - (String) Resource query name. +- `queries` - (List) + + Nested scheme for **queries**: + - `query_type` - (String) Type of the query such as `workspaces`. + - Constraints: Allowable values are: `workspaces` + - `query_condition` - (List) + + Nested scheme for **query_condition**: + - `name` - (String) Name of the resource query param. + - `value` - (String) Value of the resource query param. + - `description` - (String) Description of resource query param variable. + - `query_select` - (List) List of query selection parameters. +- `type` - (String) Resource type. Supported values are `cluster`, `vsi`, `icd`, `vpc`. + - Constraints: Allowable values are: `vsi` +- `updated_at` - (String) Resource query updation time. +- `updated_by` - (String) Email address of user who updated the Resource query. diff --git a/website/docs/d/schematics_state.html.markdown b/website/docs/d/schematics_state.html.markdown index 251c4fbde..d73a40c44 100644 --- a/website/docs/d/schematics_state.html.markdown +++ b/website/docs/d/schematics_state.html.markdown @@ -23,9 +23,12 @@ data "ibm_schematics_state" "schematics_state" { ## Argument reference Review the argument references that you can specify for your data source. +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de - `template_id` - (Required, String) The ID of the Terraform template for which you want to retrieve the Terraform statefile. When you create a workspace, the Terraform template that your workspace points to is assigned a unique ID. To find this ID, use the `GET /v1/workspaces` API and review the `template_data.id` value. - `workspace_id` - (Required, String) The workspace ID for which you want to retrieve the Terraform statefile. To find the workspace ID, use the `GET /v1/workspaces` API. + ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/schematics_workspace.html.markdown b/website/docs/d/schematics_workspace.html.markdown index 43ffc6790..7b5e7aa29 100644 --- a/website/docs/d/schematics_workspace.html.markdown +++ b/website/docs/d/schematics_workspace.html.markdown @@ -20,107 +20,153 @@ data "ibm_schematics_workspace" "schematics_workspace" { ``` ## Argument reference -Review the argument references that you can specify for your data source. -- `workspace_id` - (Required, String) The workspace ID that you want to retrieve. To find the workspace ID, use the `GET /v1/workspaces API`. +Review the argument reference that you can specify for your data source. + +* `location` - (Optional,String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de + +* `workspace_id` - (Required, Forces new resource, String) The ID of the workspace. To find the workspace ID, use the `GET /v1/workspaces` API. ## Attribute reference -In addition to the argument reference list, you can access the following attribute references after your data source is created. - -- `applied_shareddata_ids` - (String) List of applied shared data set ID. -- `catalog_ref`- (String) Information about the software template that you select from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only. Nested `catalog_ref` blocks have the following structure. - - Nested scheme for `catalog_ref`: - - `dry_run`- Bool - Dry run. - - `item_icon_url`- (String) The icon URL of the software template in the IBM Cloud catalog. - - `item_id`- (String) The ID of the software template that you select to install from the IBM Cloud catalog. This software is provisioned with Schematics. - - `item_name` - (String) The name of the software that you select to install from the IBM Cloud catalog. - - `item_readme_url`- (String) The URL to the readme file of the software template in the IBM Cloud catalog. - - `item_url` - (String) The URL to the software template in the IBM Cloud catalog. - - `launch_url` - (String) The dashboard URL to access the software. - - `offering_version` - (String) The version of the software template that you select to install from the IBM Cloud catalog. -- `created_at` - (Timestamp) The workspace created timestamp. -- `created_by` - (String) The user ID that created the workspace. -- `crn` - (String) The workspace CRN. -- `description` - (String) The description of the workspace. -- `id` - (String) The unique ID of the Schematics workspace. -- `last_health_check_at` - (Timestampe) The timestamp when the last health check was performed by Schematics. -- `location` - (String) The IBM Cloud location where your workspace was provisioned. -- `name` - (String) The name of your workspace. -- `resource_group` - (String) The ID of the resource group where you want to provision the workspace. -- `runtime_data` - (String) Information about provisioning engine, state file, and runtime logs. Nested runtime_data blocks have the following structure. - - Nested scheme for `runtime_data`: - - `engine_cmd`- (String) The command used to apply the Terraform template or IBM Cloud catalog software template. - - `engine_name`- (String) The provisioning engine used to apply the Terraform template or IBM Cloud catalog software template. - - `engine_version`- (String) The version of the provisioning engine. - - `id`- (String) The ID that was assigned to your Terraform template or IBM Cloud catalog software template. - - `log_store_url`- (String) The URL to access the logs created during the creation, update, or deletion of your IBM Cloud resources. - - `output_values`- (String) The list of output values. - - `resources`- (String) The list of resources. - - `state_store_url`- (String) The URL where the Terraform statefile `terraform.tfstate` is stored. You can use the statefile to find an overview of IBM Cloud resources created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion actions. -- `shared_data` - (String) Information that is shared across templates in IBM Cloud catalog offerings. This information is not provided when you create a workspace from your own Terraform template. Nested `shared_data` blocks have the following structure. - - Nested scheme for `shared_data`: - - `cluster_id` - (String) The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering. - - `cluster_name` - (String) The target cluster name. - - `entitlement_keys` - `String` - The entitlement key that you want to use to install IBM Cloud entitled software. - - `namespace` - (String) The Kubernetes Service namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into. - - `region` - (String) The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. - - `resource_group_id` - (String) The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. -- `status` - (String) The status of the workspace. For more information, about the Schematics workspace status, see [workspace states](https://cloud.ibm.com/docs/schematics?topic=schematics-workspace-setup#wks-state). -- `tags`- (List) A list of tags that are associated with the workspace. -- `template_data`- (List) Information about the Terraform or IBM Cloud software template to use. Nested `template_data` blocks have the following structure: - - Nested scheme for `template_data`: - - `env_values` - (String) List of environment values. Nested `env_values` blocks have the following structure: - - Nested scheme for `env_values`: - - `hidden`- (String) The environment variable is hidden. - - `name`- (String) The environment variable name. - - `secure`- (String) The environment variable is secure. - - `value`- (String) Value for an environment variable. - - `folder` - (String) The subfolder in your GitHub or GitLab repository where your Terraform template is stored. - - `has_githubtoken` - (String) Has GitHub token. - - `id` - (String) The ID assigned to your Terraform template or IBM Cloud catalog software template. - - `template_type` - (String) The Terraform version used to run your Terraform code. - - `uninstall_script_name` - (String) The script name to uninstall. - - `values` - (String) A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `autoscaling: enabled: true minReplicas: 2`. The values that you define here overrides the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider. - - `values_metadata` - (String) A list of input variables that are associated with the workspace. - - `values_url` - (String) The API endpoint to access the input variables that you defined for your template. - - `variablestore` - (String) Information about the input variables that your template uses. Nested variable store blocks have the following structure. - - Nested scheme for `variablestore`: - - `description` - (String) The description of your input variable. - - `name` - (String) The name of your variable. - - `secure` - (String) If set to **true**, the value of your input variable is protected and not returned in your API response. - - `type` - (String) Terraform v0.11 supports string, list, map data type. For more information, about the syntax, see [configuring input variables](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-workspace-new). Terraform v0.12 additionally, supports bool, number and complex data types such as list(type), map(type), object({attribute name=type,.}), set(type), tuple([type]). For more information, about the syntax to use the complex data type, see [configuring variables](https://cloud.ibm.com/docs/schematics?topic=schematics-create-tf-config#configure-variables). - - `value` - (String) Enter the value as a string for the primitive types such as bool, number, string, and HCL format for the complex variables, as you provide in a `.tfvars` file. You need to enter escaped string of HCL format for the complex variable value. For more information, about how to declare variables in a Terraform configuration file and provide value to schematics, see [providing values for the declared variables](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-workspace-new). -- `template_ref` - (String) The workspace template reference. -- `template_repo` - (List) The input parameter to specify the source repository where your Schematics template is stored. - - Nested scheme for `template_repo`: - - `branch` - (String) The branch in GitHub where your Terraform template is stored. - - `full_url` - (String) The full URL repository. - - `has_uploadedgitrepotar` - (String) Has uploaded the Git repository tap archive file. - - `release` - (String) The release tag in GitHub of your Terraform template. - - `repo_sha_value` - (String) The SHA value from the repository. - - `repo_url` - (String) The URL to the repository where the IBM Cloud catalog software template is stored. - - `url` - (String) The GitHub or GitLab repository URL where your Terraform template is stored. - - `type`- (List) The Terraform version that you want to use to run your Terraform code. - - `updated_at`- (Timestamp) The timestamp when the workspace updated. - - `updated_by`- (Timestamp) The user ID of the workspace updated. -- `workspace_status`- (List) Response parameter that indicate if a workspace is frozen or locked. Nested `workspace_status` blocks have the following structure. - - Nested scheme for `workspace_status`: - - `frozen`- (Optional, Bool) If set to **true**, the workspace is frozen and changes to the workspace are disabled. - - `frozen_at` - (String) The timestamp when the workspace was frozen. - - `frozen_by` - (String) The user ID that froze the workspace. - - `locked` - (Bool) If set to **true**, the workspace is locked and disabled for changes. - - `locked_by` - (String) The workspace locked for the user who initiates a resource-related action, such as applying or destroying resources. - - `locked_time` - (Timestamp) The timestamp when the workspace is locked. -- `workspace_status_msg`- (String) Information about the last action that ran against the workspace. Nested `workspace_status_msg` blocks have the following structure. - - Nested scheme for `workspace_status_msg`: - - `status_code`- (String) The success or error code that was returned for the last plan, apply, or destroy action that ran against your workspace. - - `status_msg`- (String) The success or error message returned for the last plan, apply, or destroy action of your workspace. + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `applied_shareddata_ids` - (List) List of applied shared dataset ID. + +* `catalog_ref` - (List) Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only. +Nested scheme for **catalog_ref**: + * `dry_run` - (Boolean) Dry run. + * `owning_account` - (String) Owning account ID of the catalog. + * `item_icon_url` - (String) The URL to the icon of the software template in the IBM Cloud catalog. + * `item_id` - (String) The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics. + * `item_name` - (String) The name of the software that you chose to install from the IBM Cloud catalog. + * `item_readme_url` - (String) The URL to the readme file of the software template in the IBM Cloud catalog. + * `item_url` - (String) The URL to the software template in the IBM Cloud catalog. + * `launch_url` - (String) The URL to the dashboard to access your software. + * `offering_version` - (String) The version of the software template that you chose to install from the IBM Cloud catalog. + +* `created_at` - (String) The timestamp when the workspace was created. + +* `created_by` - (String) The user ID that created the workspace. + +* `crn` - (String) The workspace CRN. + +* `description` - (String) The description of the workspace. + +* `id` - (String) The unique identifier of the workspace. + +* `last_health_check_at` - (String) The timestamp when the last health check was performed by Schematics. + +* `name` - (String) The name of the workspace. + +* `resource_group` - (String) The resource group the workspace was provisioned in. + +* `runtime_data` - (List) Information about the provisioning engine, state file, and runtime logs. +Nested scheme for **runtime_data**: + * `engine_cmd` - (String) The command that was used to apply the Terraform template or IBM Cloud catalog software template. + * `engine_name` - (String) The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template. + * `engine_version` - (String) The version of the provisioning engine that was used. + * `id` - (String) The ID that was assigned to your Terraform template or IBM Cloud catalog software template. + * `log_store_url` - (String) The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources. + * `output_values` - (List) List of Output values. + * `resources` - (List) List of resources. + * `state_store_url` - (String) The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs. + +* `shared_data` - (List) Information about the Target used by the templates originating from IBM Cloud catalog offerings. This information is not relevant when you create a workspace from your own Terraform template. +Nested scheme for **shared_data**: + * `cluster_id` - (String) The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering. + * `cluster_name` - (String) Target cluster name. + * `entitlement_keys` - (List) The entitlement key that you want to use to install IBM Cloud entitled software. + * `namespace` - (String) The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into. + * `region` - (String) The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. + * `resource_group_id` - (String) The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. + +* `status` - (String) The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed. + +* `tags` - (List) A list of tags that are associated with the workspace. + +* `template_env_settings` - (List) List of environment values. +Nested scheme for **env_values**: + * `hidden` - (Boolean) Environment variable is hidden. + * `name` - (String) Environment variable name. + * `secure` - (Boolean) Environment variable is secure. + * `value` - (String) Value for environment variable. + +* `template_git_folder` - (String) The subfolder in your GitHub or GitLab repository where your Terraform template is stored. If your template is stored in the root directory, `.` is returned. + +* `template_type` - (String) The Terraform version that was used to run your Terraform code. + +* `template_uninstall_script_name` - (String) Uninstall script name. + +* `template_values` - (String) A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `"autoscaling: enabled: true minReplicas: 2"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider. + +* `template_values_metadata` - (List) A list of input variables that are associated with the workspace. + Nested scheme for **values_metadata**: + * `aliases` - (List) The list of aliases for the variable name. + * `cloud_data_type` - (String) Cloud data type of the variable. eg. resource_group_id, region, vpc_id. + * `default_value` - (String) Default value for the variable only if the override value is not specified. + * `description` - (String) The description of the meta data. + * `group_by` - (String) The display name of the group this variable belongs to. + * `hidden` - (Boolean) If **true**, the variable is not displayed on UI or Command line. + * `immutable` - (Boolean) Is the variable readonly ?. + * `link_status` - (String) The status of the link. + * Constraints: Allowable values are: `normal`, `broken`. + * `matches` - (String) The regex for the variable value. + * `max_length` - (Integer) The maximum length of the variable value. Applicable for the string type. + * `max_value` - (Integer) The maximum value of the variable. Applicable for the integer type. + * `min_length` - (Integer) The minimum length of the variable value. Applicable for the string type. + * `min_value` - (Integer) The minimum value of the variable. Applicable for the integer type. + * `options` - (List) The list of possible values for this variable. If type is **integer** or **date**, then the array of string is converted to array of integers or date during the runtime. + * `position` - (Integer) The relative position of this variable in a list. + * `required` - (Boolean) If the variable required?. + * `secure` - (Boolean) Is the variable secure or sensitive ?. + * `source` - (String) The source of this meta-data. + * `type` - (String) Type of the variable. + * Constraints: Allowable values are: `boolean`, `string`, `integer`, `date`, `array`, `list`, `map`, `complex`, `link`. + +* `template_inputs` - (List) Information about the input variables that your template uses. +Nested scheme for **variablestore**: + * `description` - (String) The description of your input variable. + * `name` - (String) The name of the variable. + * `secure` - (Boolean) If set to `true`, the value of your input variable is protected and not returned in your API response. + * `type` - (String) `Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints). + * `value` - (String) Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](https://cloud.ibm.com/docs/schematics?topic=schematics-create-tf-config#declare-variable). + +* `template_ref` - (String) Workspace template reference. + +* `template_git_branch` - (String) The repository branch. + +* `template_git_full_url` - (String) Full repository URL. + +* `template_git_has_uploadedgitrepotar` - (Boolean) Has uploaded Git repository tar. + +* `template_git_release` - (String) The repository release. + +* `template_git_repo_sha_value` - (String) The repository SHA value. + +* `template_git_repo_url` - (String) The repository URL. + +* `template_git_url` - (String) The source URL. + +* `type` - (List) The Terraform version that was used to run your Terraform code. + +* `updated_at` - (String) The timestamp when the workspace was last updated. + +* `updated_by` - (String) The user ID that updated the workspace. + +* `frozen` - (Boolean) If set to true, the workspace is frozen and changes to the workspace are disabled. + +* `frozen_at` - (String) The timestamp when the workspace was frozen. + +* `frozen_by` - (String) The user ID that froze the workspace. + +* `locked` - (Boolean) If set to true, the workspace is locked and disabled for changes. + +* `locked_by` - (String) The user ID that initiated a resource-related job, such as applying or destroying resources, that locked the workspace. + +* `locked_time` - (String) The timestamp when the workspace was locked. + +* `status_code` - (String) The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace. + +* `status_msg` - (String) The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace. \ No newline at end of file diff --git a/website/docs/d/secrets_manager_secret.html.markdown b/website/docs/d/secrets_manager_secret.html.markdown index 3fe6acdf7..55cf797fc 100644 --- a/website/docs/d/secrets_manager_secret.html.markdown +++ b/website/docs/d/secrets_manager_secret.html.markdown @@ -23,7 +23,7 @@ data "ibm_secrets_manager_secret" "secrets_manager_secret" { Review the argument references that you can specify for your data source. - `instance_id` - (Required, String) The secrets manager instance GUID. -- `secret_type` - (Required, String) The secret type. Supported options are `arbitrary`, `iam_credentials`, `username_password`. +- `secret_type` - (Required, String) The secret type. Supported options are `arbitrary`, `iam_credentials`, `username_password`,`imported_cert`,`public_cert`,`private_cert`,`kv`. - `secret_id` - (Required, String) The v4 UUID that uniquely identifies the secret. - `endpoint_type` - (Optional, String) The type of the endpoint used to fetch secret. Supported options are `public`, and `private`. The default value is `public`. diff --git a/website/docs/d/tg_connection_prefix_filter.html.markdown b/website/docs/d/tg_connection_prefix_filter.html.markdown new file mode 100644 index 000000000..e95ecdb1d --- /dev/null +++ b/website/docs/d/tg_connection_prefix_filter.html.markdown @@ -0,0 +1,40 @@ +--- + +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_connection_prefix_filter" +description: |- + Gets Information about IBM Cloud Infrastructure Transit Gateway Connection Prefix Filter. +--- + +# ibm_tg_connection_prefix_filter +Retrieve information of an existing IBM Cloud infrastructure transit gateway connection prefix filter as a read only data source. For more information about Transit Gateway Prefix filters, see [adding and deleting prefix filters](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui). + +## Example usage + +```terraform +data "ibm_tg_connection_prefix_filter" "tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + filter_id = ibm_tg_connection_prefix_filter.test_tg_prefix_filter.filter_id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `gateway` - (Required, String) The unique identifier of the gateway. +- `connection_id` - (Required, String) The unique identifier of the gateway connection +- `filter_id` - - (Required, String) The unique identifier of the gateway connection prefix filter + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `created_at` - (String) The date and time resource is created. +- `id` - (String) The unique identifier of this prefix filter. +- `action` - (String) Whether to permit or deny the prefix filter +- `before` - (String) Identifier of prefix filter that handles the ordering and follow semantics. When a filter reference another filter in it's before field, then the filter making the reference is applied before the referenced filter. For example: if filter A references filter B in its before field, A is applied before B. +- `ge` - (Int) The IP Prefix GE. The GE (greater than or equal to) value can be included to match all less-specific prefixes within a parent prefix above a certain length. +- `le` - (Int) The IP Prefix LE. The LE (less than or equal to) value can be included to match all more-specific prefixes within a parent prefix up to a certain length. +- `prefix` - (String) The IP Prefix +- `updated_at` - (String) The date and time resource is last updated. \ No newline at end of file diff --git a/website/docs/d/tg_connection_prefix_filters.html.markdown b/website/docs/d/tg_connection_prefix_filters.html.markdown new file mode 100644 index 000000000..6709455ac --- /dev/null +++ b/website/docs/d/tg_connection_prefix_filters.html.markdown @@ -0,0 +1,41 @@ +--- + +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_connection_prefix_filters" +description: |- + Gets Information about IBM Cloud Infrastructure Transit Gateway Connection Prefix Filters. +--- + +# ibm_tg_connection_prefix_filters +Retrieve information of existing IBM Cloud infrastructure transit gateway connection prefix filters as a read only data source. For more information about Transit Gateway Prefix filters, see [adding and deleting prefix filters](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui). + +## Example usage + +```terraform +data "ibm_tg_connection_prefix_filters" "tg_prefix_filters" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `gateway` - (Required, String) The unique identifier of the gateway. +- `connection_id` - (Required, String) The unique identifier of the gateway connection + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `prefix_filters` - (String) List of all prefix filters for the transit gateway connection + + Nested scheme for `prefix_filters`: + - `created_at` - (String) The date and time resource is created. + - `id` - (String) The unique identifier of this prefix filter. + - `action` - (String) Whether to permit or deny the prefix filter + - `before` - (String) Identifier of prefix filter that handles the ordering and follow semantics. When a filter reference another filter in it's before field, then the filter making the reference is applied before the referenced filter. For example: if filter A references filter B in its before field, A is applied before B. + - `ge` - (Int) The IP Prefix GE. The GE (greater than or equal to) value can be included to match all less-specific prefixes within a parent prefix above a certain length. + - `le` - (Int) The IP Prefix LE. The LE (less than or equal to) value can be included to match all more-specific prefixes within a parent prefix up to a certain length. + - `prefix` - (String) The IP Prefix + - `updated_at` - (String) The date and time resource is last updated. \ No newline at end of file diff --git a/website/docs/d/tg_route_report.html.markdown b/website/docs/d/tg_route_report.html.markdown new file mode 100644 index 000000000..dbdd0aa14 --- /dev/null +++ b/website/docs/d/tg_route_report.html.markdown @@ -0,0 +1,56 @@ +--- + +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_route_report" +description: |- + Manages IBM Cloud Infrastructure Transit Gateway Route Report. +--- + +# ibm_tg_route_report +Retrieve information of an existing IBM Cloud infrastructure transit gateway route report as a read only data source. For more information about Transit Gateway Route Reports, see [generating and viewing a route report](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-route-reports&interface=ui#generate-route-report-ui). + +## Example usage + +```terraform +data "ibm_tg_route_report" "tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw. + route_report = ibm_tg_route_report_test_tg_route_report.route_report_id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `gateway` - (Required, String) The unique identifier of the gateway. +- `route_report` - (Required, String) The unique identifier of the gateway route report + + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `created_at` - (Timestamp) The date and time resource is created. +- `id` - (String) The unique identifier of this route report. +- `status` - (String) The route report status. +- `updated_at` - (Timestamp) The date and time resource is last updated. +- `connections` - (String) A list of connections in the gateway + + Nested scheme for `connections`: + - `bgps` (String) A list of the connection's bgps + Nested scheme for `bgps`: + - `as_path` - (String) The bgp AS path + - `is_used` - (Bool) Indicates whether the current route is used or not + - `local_preference` (String) The local preference + - `prefix` - (String) The bgp prefix + - `id` - (String) The unique identifier for the transit gateway connection + - `name` - (String) The user-defined name for the transit gateway connection. + - `routes` - (String) A list of the connection's routes + + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route + - `type` - (String) The connection type +- `overlapping_routes` - (String) A list of overlapping routes in the gateway + + Nested scheme for `overlapping_routes`: + - `connection_id` - (String) The unique identifier for the transit gateway connection + - `prefix` - (String) The overlapping prefix diff --git a/website/docs/d/tg_route_reports.html.markdown b/website/docs/d/tg_route_reports.html.markdown new file mode 100644 index 000000000..d8dd6e801 --- /dev/null +++ b/website/docs/d/tg_route_reports.html.markdown @@ -0,0 +1,57 @@ +--- + +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_route_reports" +description: |- + Manages IBM Cloud Infrastructure Transit Gateway Route Reports. +--- + +# ibm_tg_route_reports +Retrieve information of an existing IBM Cloud infrastructure transit gateway route reports as a read only data source. For more information about Transit Gateway Route Reports, see [generating and viewing a route report](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-route-reports&interface=ui#generate-route-report-ui). + +## Example usage + +```terraform +data "ibm_tg_route_reports" "tg_route_reports" { + gateway = ibm_tg_gateway.new_tg_gw.id +} +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `gateway` - (Required, String) The unique identifier of the gateway. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `route_reports` - (String) List of all route reports for the transit gateway + + Nested scheme for `route_reports`: + - `created_at` - (Timestamp) The date and time resource is created. + - `id` - (String) The unique identifier of this route report. + - `status` - (String) The route report status. + - `updated_at` - (Timestamp) The date and time resource is last updated. + - `connections` - (String) A list of connections in the gateway + + Nested scheme for `connections`: + - `bgps` (String) A list of the connection's bgps + Nested scheme for `bgps`: + - `as_path` - (String) The bgp AS path + - `is_used` - (Bool) Indicates whether the current route is used or not + - `local_preference` (String) The local preference + - `prefix` - (String) The bgp prefix + - `id` - (String) The unique identifier for the transit gateway connection + - `name` - (String) The user-defined name for the transit gateway connection. + - `routes` - (String) A list of the connection's routes + + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route + - `type` - (String) The connection type + - `overlapping_routes` - (String) A list of overlapping routes in the gateway + + Nested scheme for `overlapping_routes`: + - `connection_id` - (String) The unique identifier for the transit gateway connection + - `prefix` - (String) The overlapping prefix + diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index b8207d209..ce3b9fde3 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -72,7 +72,6 @@ provider "ibm" { |Global Catalog|IBMCLOUD_RESOURCE_CATALOG_API_ENDPOINT| |Satellite|IBMCLOUD_SATELLITE_API_ENDPOINT| |Satellite Link|IBMCLOUD_SATELLITE_LINK_API_ENDPOINT| -|SCC Findings|IBMCLOUD_SCC_FINDINGS_API_ENDPOINT| |Schematics|IBMCLOUD_SCHEMATICS_API_ENDPOINT| |Secrets Manager|IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT| |Transit Gateway|IBMCLOUD_TG_API_ENDPOINT| diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index a390e53d5..c97353dc1 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -12,7 +12,7 @@ The IBM Cloud provider is used to manage IBM Cloud resources. The provider must Use the navigation menu on the left to read about the available data sources and resources. -## Example Usage of Provider +## Example usage of provider Terraform 0.13 and later: ```terraform @@ -20,7 +20,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "~> 1.12.0" + version = ">= 1.12.0" } } } @@ -64,7 +64,7 @@ resource "ibm_is_vpc" "testacc_vpc" { name = "test-vpc" } ``` -## Example Usage of Resources: +## Example usage of resources: ```terraform @@ -197,7 +197,7 @@ terraform plan * Find user name in the `VPN password` section under `User Details` tab -## Argument Reference +## Argument reference The following arguments are supported in the `provider` block: @@ -255,4 +255,4 @@ export IBMCLOUD_UAA_ENDPOINT="https://iam.cloud.ibm.com/cloudfoundry/login/ + +``` + +**Example** + +``` +terraform import ibm_app_config_collection.sample 272111153-c118-4116-8116-b811fbc31132/col +``` diff --git a/website/docs/r/app_config_environment.html.markdown b/website/docs/r/app_config_environment.html.markdown index efc08074c..ca65ebf8e 100644 --- a/website/docs/r/app_config_environment.html.markdown +++ b/website/docs/r/app_config_environment.html.markdown @@ -8,7 +8,7 @@ description: |- # ibm_app_config_environment -Create, update, or delete an environment by using IBM Cloud™ App Configuration. For more information, about App Configuration, see [getting started with App Configuration](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-getting-started). +Create, update, or delete an environment by using IBM Cloud™ App Configuration. For more information, about App Configuration, see [Getting started with App Configuration](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-getting-started). ## Example usage diff --git a/website/docs/r/app_config_feature.html.markdown b/website/docs/r/app_config_feature.html.markdown index a9915e852..a01b5dae2 100644 --- a/website/docs/r/app_config_feature.html.markdown +++ b/website/docs/r/app_config_feature.html.markdown @@ -22,6 +22,7 @@ resource "ibm_app_config_feature" "app_config_feature" { enabled_value = "enabled_value" environment_id = "environment_id" disabled_value = "disabled_value" + rollout_percentage = "rollout_percentage" } ``` @@ -38,15 +39,17 @@ Review the argument reference that you can specify for your resource. - `disabled_value` - (Required, String) The value of the feature when it is disabled. The value can be **BOOLEAN**, **STRING**, or **NUMERIC** value as per the `type` attribute. - `description` - (Optional, String) The feature description. - `tags` - (Optional, String) Tags associated with the feature. +- `rollout_percentage` - (String) Rollout percentage of the feature. - `segment_rules` - (Optional, List) Specify the targeting rules that is used to set different feature flag values for different segments. - `rules` - (Required, []interface{}) The rules array. - `segments` - (Required, Array of Strings) The list of segment IDs that are used for targeting using the rule. - `value` - (Required, String) The value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. - - `order` - (Required, int) The order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. + - `order` - (Required, Integer) The order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. + - `rollout_percentage` - (String) Rollout percentage for the segment rule. - `collections` - (Optional, List) The list of collection ID representing the collections that are associated with the specified feature flag. - `collection_id` - (Required, String) Collection ID. -## Attribute Reference +## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. diff --git a/website/docs/r/app_config_property.html.markdown b/website/docs/r/app_config_property.html.markdown new file mode 100644 index 000000000..e21af84c8 --- /dev/null +++ b/website/docs/r/app_config_property.html.markdown @@ -0,0 +1,74 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration property' +description: |- + Manages property. +--- + +# ibm_app_config_property + +Provides a resource for `property`. This allows property to be created, updated and deleted. For more information, about App Configuration segment, see [properties](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-properties). + +## Example Usage + +```hcl +resource "ibm_app_config_property" "app_config_property" { + guid = "guid" + environment_id = "environment_id" + name = "name" + property_id = "property_id" + type = "type" + value = "value" + description = "description" + tags = "tags" +} +``` + +## Argument Reference + +The following arguments are supported: + +- `guid` - (Required, string) guid of the App Configuration service. Get it from the service instance credentials section of the dashboard. +- `environment_id` - (Required, string) Environment Id. +- `name` - (Required, string) Property name. +- `property_id` - (Required, string) Property id. +- `type` - (Required, string) Type of the Property (BOOLEAN, STRING, NUMERIC). +- `value` - (Required, TypeMap) Value of the Property. The value can be Boolean, String or a Numeric value as per the `type` attribute. +- `description` - (Optional, string) Property description. +- `tags` - (Optional, string) Tags associated with the property. +- `format` - (Optional, string) Format of the property (TEXT, JSON, YAML) and this is a required attribute when TYPE STRING is used, not required for BOOLEAN and NUMERIC types. +- `segment_rules` - (Optional, List) Specify the targeting rules that is used to set different property values for different segments. + - `rules` - (Required, []interface{}) Rules array. + - `value` - (Required, TypeMap) Value to be used for evaluation for this rule. The value can be Boolean, String or a Numeric value as per the `type` attribute. + - `order` - (Required, int) Order of the rule, used during evaluation. The evaluation is performed in the order defined and the value associated with the first matching rule is used for evaluation. +- `collections` - (Optional, List) List of collection id representing the collections that are associated with the specified property. + - `collection_id` - (Required, string) Collection id. + +## Attribute Reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the app_config_property. +- `segment_exists` - Denotes if the targeting rules are specified for the property. +- `created_time` - Creation time of the property. +- `updated_time` - Last modified time of the property data. +- `evaluation_time` - The last occurrence of the property value evaluation. +- `href` - Property URL. + +## Import + +The `ibm_app_config_property` resource can be imported by using `guid` of the App Configuration instance, `environmentId` and `propertyId`. Get the `guid` from the service instance credentials section of the dashboard. + +**Syntax** + +``` +terraform import ibm_app_config_property.sample + +``` + +**Example** + +``` +terraform import ibm_app_config_property.sample 272111153-c118-4116-8116-b811fbc31132/dev/sample_property +``` diff --git a/website/docs/r/app_config_segment.html.markdown b/website/docs/r/app_config_segment.html.markdown new file mode 100644 index 000000000..e695a255f --- /dev/null +++ b/website/docs/r/app_config_segment.html.markdown @@ -0,0 +1,81 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration segment' +description: |- + Manages segment. +--- + +# ibm_app_config_segment + +Create, update, or delete an segment by using IBM Cloud™ App Configuration. For more information, about App Configuration segment, see [segments](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-segments). + +## Example usage + +```terraform +resource "ibm_app_config_segment" "app_config_segment" { + guid = "guid" + name = "name" + description = "description" + tags = "tags" + segment_id = "segment_id" + rules { + attribute_name = "attribute_name" + operator = "operator" + values = "values" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `guid` - (Required, String) The GUID of the App Configuration service. Fetch GUID from the service instance credentials section of the dashboard. +- `name` - (Required, String) The Segment name. +- `rules` - (Required, List) List of rules that determine if the entity belongs to the segment during feature / property evaluation. + + Nested scheme for `rules`: + - `attribute_name` - (Required, String) The Attribute name. + - `operator` - (Required, String) The Operator to be used for the evaluation if the entity belongs to the segment. + - `values` - (Required, Array of Strings) List of values. Entities matching any of the given values will be considered to belong to the segment. + +- `description` - (Optional, String) The Segment description. +- `tags` - (Optional, String) Tags associated with the segments. + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `segment_id` - (String) Segment id. +- `created_time` - (Timestamp) Creation time of the segment. +- `updated_time` - (Timestamp) Last modified time of the segment data. +- `href` - (String) Segment URL. +- `features` - (List) List of Features associated with the segment. + + Nested scheme for `features`: + - `feature_id` - (String) Feature id. + - `name` - (String) Feature name. + +- `properties` - (List) List of properties associated with the segment. + + Nested scheme for `properties`: + - `property_id` - (String) Property id. + - `name` - (String) Property name. + +## Import + +The `ibm_app_config_segment` resource can be imported by using `guid` of the App Configuration instance and `segmentId`. Get the `guid` from the service instance credentials section of the dashboard. + +**Syntax** + +``` +terraform import ibm_app_config_segment.sample + +``` + +**Example** + +``` +terraform import ibm_app_config_segment.sample 272111153-c118-4116-8116-b811fbc31132/sample_segment +``` diff --git a/website/docs/r/app_config_snapshot.html.markdown b/website/docs/r/app_config_snapshot.html.markdown new file mode 100644 index 000000000..04e61c6a3 --- /dev/null +++ b/website/docs/r/app_config_snapshot.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: 'App Configuration' +layout: 'ibm' +page_title: 'IBM : App Configuration Snapshots' +description: |- + Manages snapshots. +--- + +# ibm_app_config_snapshots + +Provides a resource for `snapshot`. This allows snapshot to be created, updated and deleted. For more information, about App Configuration snapshots, see [segments](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-snapshots). + +## Example usage + +```terraform +resource "ibm_app_config_snapshot" "app_config_snapshot" { + guid = "guid" + collection_id = "collection_id" + environment_id = "environment_id" + git_config_id = "git_config_id" + git_config_name = "git_config_name" + git_url = "git_url" + git_branch = "git_branch" + git_file_path = "git_file_path" + git_token = "git_token" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `guid` - (Required, String) The GUID of the App Configuration service. Fetch GUID from the service instance credentials section of the dashboard. +- `collection_id` - (Required, String) Collection ID +- `environment_id` - (Required, String) Environment Id +- `git_config_name` - (Required, String) Git config name. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only. +- `git_config_id` - (Required, String) Git config id. Allowed special characters are dot ( . ), hyphen( - ), underscore ( _ ) only +- `git_url` - (Required, String) Git url which will be used to connect to the github account. The url must be formed in this format, https://api.github.com/repos/{owner}/{repo_name} for the personal git account. +- `git_branch` - (Required, String) Branch name to which you need to write or update the configuration. +- `git_file_path` - (Required, String) Git file path, this is a path where your configuration file will be written. The path must contain the file name with `json` extension. +- `git_token` - (Required, String) Git token, this needs to be provided with enough permission to write and update the file. + + +## Attribute reference + +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `created_time` - (Timestamp) Creation time of the segment. +- `updated_time` - (Timestamp) Last modified time of the segment data. +- `href` - (String) Git config URL. + + +## Import + +The `ibm_app_config_snapshot` resource can be imported by using `guid` of the App Configuration instance and `git_config_id`. Get the `guid` from the service instance credentials section of the dashboard. + +**Syntax** + +``` +terraform import ibm_app_config_snapshot.sample + +``` + +**Example** + +``` +terraform import ibm_app_config_snapshot.app_config_snapshot 272111153-c118-4116-8116-b811fbc31132/sample +``` \ No newline at end of file diff --git a/website/docs/r/appid_action_url.html.markdown b/website/docs/r/appid_action_url.html.markdown index dcf0856e2..fb34c5b41 100644 --- a/website/docs/r/appid_action_url.html.markdown +++ b/website/docs/r/appid_action_url.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Action URL" description: |- diff --git a/website/docs/r/appid_apm.html.markdown b/website/docs/r/appid_apm.html.markdown index 179656846..b128009ca 100644 --- a/website/docs/r/appid_apm.html.markdown +++ b/website/docs/r/appid_apm.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID APM" description: |- diff --git a/website/docs/r/appid_application.html.markdown b/website/docs/r/appid_application.html.markdown index eec0483d3..67a47f172 100644 --- a/website/docs/r/appid_application.html.markdown +++ b/website/docs/r/appid_application.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application" description: |- diff --git a/website/docs/r/appid_application_roles.html.markdown b/website/docs/r/appid_application_roles.html.markdown index 920276002..f49b8b712 100644 --- a/website/docs/r/appid_application_roles.html.markdown +++ b/website/docs/r/appid_application_roles.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application Roles" description: |- diff --git a/website/docs/r/appid_application_scopes.html.markdown b/website/docs/r/appid_application_scopes.html.markdown index 8fb53bf69..13919adea 100644 --- a/website/docs/r/appid_application_scopes.html.markdown +++ b/website/docs/r/appid_application_scopes.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Application Scopes" description: |- diff --git a/website/docs/r/appid_audit_status.html.markdown b/website/docs/r/appid_audit_status.html.markdown index 9324540d2..5aabd9017 100644 --- a/website/docs/r/appid_audit_status.html.markdown +++ b/website/docs/r/appid_audit_status.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Audit Status" description: |- diff --git a/website/docs/r/appid_cloud_directory_template.html.markdown b/website/docs/r/appid_cloud_directory_template.html.markdown index 81f455cef..6d7a25e7b 100644 --- a/website/docs/r/appid_cloud_directory_template.html.markdown +++ b/website/docs/r/appid_cloud_directory_template.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory Template" description: |- diff --git a/website/docs/r/appid_cloud_directory_user.html.markdown b/website/docs/r/appid_cloud_directory_user.html.markdown index 4eced0dbb..86ac3b9c2 100644 --- a/website/docs/r/appid_cloud_directory_user.html.markdown +++ b/website/docs/r/appid_cloud_directory_user.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory User" description: |- diff --git a/website/docs/r/appid_idp_cloud_directory.html.markdown b/website/docs/r/appid_idp_cloud_directory.html.markdown index bb7ef3765..2816cd972 100644 --- a/website/docs/r/appid_idp_cloud_directory.html.markdown +++ b/website/docs/r/appid_idp_cloud_directory.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory IDP" description: |- diff --git a/website/docs/r/appid_idp_custom.html.markdown b/website/docs/r/appid_idp_custom.html.markdown index 3f7da49aa..25291e756 100644 --- a/website/docs/r/appid_idp_custom.html.markdown +++ b/website/docs/r/appid_idp_custom.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Custom IDP" description: |- diff --git a/website/docs/r/appid_idp_facebook.html.markdown b/website/docs/r/appid_idp_facebook.html.markdown index 72ef49d83..5bdbe5324 100644 --- a/website/docs/r/appid_idp_facebook.html.markdown +++ b/website/docs/r/appid_idp_facebook.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Facebook IDP" description: |- diff --git a/website/docs/r/appid_idp_google.html.markdown b/website/docs/r/appid_idp_google.html.markdown index 4ff9cf34d..8ba538785 100644 --- a/website/docs/r/appid_idp_google.html.markdown +++ b/website/docs/r/appid_idp_google.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Google IDP" description: |- diff --git a/website/docs/r/appid_idp_saml.html.markdown b/website/docs/r/appid_idp_saml.html.markdown index 22bbf7734..bab289d20 100644 --- a/website/docs/r/appid_idp_saml.html.markdown +++ b/website/docs/r/appid_idp_saml.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID SAML IDP" description: |- diff --git a/website/docs/r/appid_languages.html.markdown b/website/docs/r/appid_languages.html.markdown index 8a0a5ef74..b7995545c 100644 --- a/website/docs/r/appid_languages.html.markdown +++ b/website/docs/r/appid_languages.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Languages" description: |- diff --git a/website/docs/r/appid_mfa.html.markdown b/website/docs/r/appid_mfa.html.markdown index cdca659bf..42f966a04 100644 --- a/website/docs/r/appid_mfa.html.markdown +++ b/website/docs/r/appid_mfa.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID MFA" description: |- diff --git a/website/docs/r/appid_mfa_channel.html.markdown b/website/docs/r/appid_mfa_channel.html.markdown index 4008b377b..b60df2f40 100644 --- a/website/docs/r/appid_mfa_channel.html.markdown +++ b/website/docs/r/appid_mfa_channel.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID MFA" description: |- diff --git a/website/docs/r/appid_password_regex.html.markdown b/website/docs/r/appid_password_regex.html.markdown index 105320508..ca9f6f01b 100644 --- a/website/docs/r/appid_password_regex.html.markdown +++ b/website/docs/r/appid_password_regex.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Password Regex" description: |- diff --git a/website/docs/r/appid_redirect_urls.html.markdown b/website/docs/r/appid_redirect_urls.html.markdown index b32843143..a243e228e 100644 --- a/website/docs/r/appid_redirect_urls.html.markdown +++ b/website/docs/r/appid_redirect_urls.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Cloud Directory Redirect URLs" description: |- diff --git a/website/docs/r/appid_role.html.markdown b/website/docs/r/appid_role.html.markdown index 1893081bd..7cf57149b 100644 --- a/website/docs/r/appid_role.html.markdown +++ b/website/docs/r/appid_role.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Role" description: |- diff --git a/website/docs/r/appid_theme_color.html.markdown b/website/docs/r/appid_theme_color.html.markdown index 498bf4b4c..f9a3e28b5 100644 --- a/website/docs/r/appid_theme_color.html.markdown +++ b/website/docs/r/appid_theme_color.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Theme Color" description: |- diff --git a/website/docs/r/appid_theme_text.html.markdown b/website/docs/r/appid_theme_text.html.markdown index 033af6f82..05e38747b 100644 --- a/website/docs/r/appid_theme_text.html.markdown +++ b/website/docs/r/appid_theme_text.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Theme Text" description: |- diff --git a/website/docs/r/appid_token_config.html.markdown b/website/docs/r/appid_token_config.html.markdown index 1e70e6354..88671a54c 100644 --- a/website/docs/r/appid_token_config.html.markdown +++ b/website/docs/r/appid_token_config.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID Token Configuration" description: |- @@ -47,7 +47,7 @@ Review the argument references that you can specify for your resource. Nested scheme for `access_token_claim`: - `destination_claim` - (Optional, String) Defines the custom attribute that can override the current claim in token - - `source` - (Required, String) Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`, and `attributes` + - `source` - (Required, String) Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`,`ibmid`, `roles` and `attributes` - `source_claim` - (Optional, String) Defines the claim as provided by the source. It can refer to the identity provider's user information or the user's App ID custom attributes - `access_token_expires_in` - (Optional, Number) The length of time for which access tokens are valid in seconds @@ -57,7 +57,7 @@ Review the argument references that you can specify for your resource. Nested scheme for `id_token_claim`: - `destination_claim` - (Optional, String) Defines the custom attribute that can override the current claim in token - - `source` - (Required, String) Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`, and `attributes` + - `source` - (Required, String) Defines the source of the claim. Options include: `saml`, `cloud_directory`, `facebook`, `google`, `appid_custom`,`ibmid`, `roles` and `attributes` - `source_claim` - (Optional, String) Defines the claim as provided by the source. It can refer to the identity provider's user information or the user's App ID custom attributes - `refresh_token_enabled` - (Optional, Bool) Enable refresh token diff --git a/website/docs/r/appid_user_roles.html.markdown b/website/docs/r/appid_user_roles.html.markdown index 60223d810..b79cadba7 100644 --- a/website/docs/r/appid_user_roles.html.markdown +++ b/website/docs/r/appid_user_roles.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "AppID Management" +subcategory: "App ID Management" layout: "ibm" page_title: "IBM: AppID User Roles" description: |- diff --git a/website/docs/r/atracker_route.html.markdown b/website/docs/r/atracker_route.html.markdown index 76b5b1fd9..cf3570bb5 100644 --- a/website/docs/r/atracker_route.html.markdown +++ b/website/docs/r/atracker_route.html.markdown @@ -3,45 +3,53 @@ layout: "ibm" page_title: "IBM : ibm_atracker_route" description: |- Manages Activity Tracker Route. -subcategory: "Activity Tracker API" +subcategory: "Activity Tracker" --- # ibm_atracker_route Provides a resource for Activity Tracker Route. This allows Activity Tracker Route to be created, updated and deleted. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_atracker_route" "atracker_route" { name = "my-route" - receive_global_events = false rules { target_ids = [ ibm_atracker_target.atracker_target.id ] + locations = [ "us-south", "global" ] + } + lifecycle { + # Recommended to ensure that if a target ID is removed here and destroyed in a plan, this is updated first + create_before_destroy = true } } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. * `name` - (Required, String) The name of the route. The name must be 1000 characters or less and cannot include any special characters other than `(space) - . _ :`. * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/` -* `receive_global_events` - (Required, Boolean) Indicates whether or not all global events should be forwarded to this region. +* `receive_global_events` - **DEPRECATED** (Optional, Boolean) Indicates whether or not all global events should be forwarded to this region. Use rules.locations instead with `global` included. * `rules` - (Required, List) Routing rules that will be evaluated in their order of the array. Nested scheme for **rules**: - * `target_ids` - (Required, List) The target ID List. Only 1 target id is supported. + * `target_ids` - (Required, List) The target ID List. All the events will be send to all targets listed in the rule. You can include targets from other regions. + * `locations` - (Optional, List) Logs from these locations will be sent to the targets specified. Locations is a superset of regions including global and *. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. -* `id` - The unique identifier of the Activity Tracker Route. -* `created` - (Optional, String) The timestamp of the route creation time. +* `id` - The unique identifier of the atracker_route. +* `api_version` - (Integer) The API version of the route. +* `created_at` - (String) The timestamp of the route creation time. * `crn` - (Required, String) The crn of the route resource. -* `updated` - (Optional, String) The timestamp of the route last updated time. +* `updated_at` - (String) The timestamp of the route last updated time. * `version` - (Optional, Integer) The version of the route. +* `updated` - **DEPRECATED** (Optional, String) The timestamp of the route last updated time. +* `created` - **DEPRECATED** (Optional, String) The timestamp of the route creation time. ## Import diff --git a/website/docs/r/atracker_settings.html.markdown b/website/docs/r/atracker_settings.html.markdown new file mode 100644 index 000000000..be26ebf20 --- /dev/null +++ b/website/docs/r/atracker_settings.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_atracker_settings" +description: |- + Manages atracker_settings. +subcategory: "Activity Tracker" +--- + +# ibm_atracker_settings + +Provides a resource for atracker_settings. This allows atracker_settings to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_atracker_settings" "atracker_settings" { + default_targets = [ ibm_atracker_target.atracker_target.id ] + metadata_region_primary = "us-south" + metadata_region_backup = "us-east" + permitted_target_regions = us-south + private_api_endpoint_only = false + # Optional but recommended lifecycle flag to ensure target delete order is correct + lifecycle { + create_before_destroy = true + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `default_targets` - (Optional, List) The target ID List. In the event that no routing rule causes the event to be sent to a target, these targets will receive the event. + * Constraints: The list items must match regular expression `/^[a-zA-Z0-9 -]/`. +* `metadata_region_primary` - (Required, String) To store all your meta data in a single region. + * Constraints: The maximum length is `256` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -_]/`. +* `metadata_region_primary` - (Optional, String) To store all your meta data in a backup region. + * Constraints: The maximum length is `256` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -_]/`. +* `permitted_target_regions` - (Optional, List) If present then only these regions may be used to define a target. + * Constraints: The list items must match regular expression `/^[a-zA-Z0-9 -_]/`. +* `private_api_endpoint_only` - (Required, Boolean) If you set this true then you cannot access api through public network. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the atracker_settings (only one). +* `api_version` - (Required, Integer) The lowest API version of targets or routes that customer might have under his or her account. + +## Import + +You can import the `ibm_atracker_settings` resource by using `metadata_region_primary`. To store all your meta data in a single region. + +# Syntax +``` +$ terraform import ibm_atracker_settings.atracker_settings +``` + +# Example +``` +$ terraform import ibm_atracker_settings.atracker_settings us-south +``` diff --git a/website/docs/r/atracker_target.html.markdown b/website/docs/r/atracker_target.html.markdown index 3048d0abc..23329b8fb 100644 --- a/website/docs/r/atracker_target.html.markdown +++ b/website/docs/r/atracker_target.html.markdown @@ -3,57 +3,89 @@ layout: "ibm" page_title: "IBM : ibm_atracker_target" description: |- Manages Activity Tracker Target. -subcategory: "Activity Tracker API" +subcategory: "Activity Tracker" --- # ibm_atracker_target Provides a resource for Activity Tracker Target. This allows Activity Tracker Target to be created, updated and deleted. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_atracker_target" "atracker_target" { cos_endpoint { endpoint = "endpoint" target_crn = "target_crn" bucket = "bucket" - api_key = "api_key" + api_key = "api_key" } name = "my-cos-target" target_type = "cloud_object_storage" + region = "us-south" +} + +resource "ibm_atracker_target" "atracker_logdna_target" { + target_type = "logdna" + logdna_endpoint { + target_crn = "crn:v1:bluemix:public:logdna:us-south:a/11111111111111111111111111111111:22222222-2222-2222-2222-222222222222::" + ingestion_key = "xxxxxxxxxxxxxx" + } + name = "my-logdna-target" + target_type = "logdna" + region = "us-south" } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. -* `cos_endpoint` - (Required, List) Property values for a Cloud Object Storage Endpoint. +* `cos_endpoint` - (Optional, List) Property values for a Cloud Object Storage Endpoint. Nested scheme for **cos_endpoint**: + * `api_key` - (Optional, String) The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. This is required if service_to_service is not enabled. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `bucket` - (Required, String) The bucket name under the Cloud Object Storage instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. * `endpoint` - (Required, String) The host name of the Cloud Object Storage endpoint. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. + * `service_to_service_enabled` - (Optional, Boolean) ATracker service is enabled to support service to service authentication. If service to service is enabled then set this flag is true and do not supply apikey. * `target_crn` - (Required, String) The CRN of the Cloud Object Storage instance. - * `bucket` - (Required, String) The bucket name under the Cloud Object Storage instance. - * `api_key` - (Required, String) The IAM API key that has writer access to the Cloud Object Storage instance. This credential is masked in the response. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. +* `logdna_endpoint` - (Optional, List) Property values for a LogDNA Endpoint. +Nested scheme for **logdna_endpoint**: + * `ingestion_key` - (Required, String) The LogDNA ingestion key is used for routing logs to a specific LogDNA instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. + * `target_crn` - (Required, String) The CRN of the LogDNA instance. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:\/]+$/`. * `name` - (Required, String) The name of the target. The name must be 1000 characters or less, and cannot include any special characters other than `(space) - . _ :`. - * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/` -* `target_type` - (Required, Forces new resource, String) The type of the target. - * Constraints: Allowable values are: cloud_object_storage + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. +* `region` - (Optional, String) Include this optional field if you want to create a target in a different region other than the one you are connected. + * Constraints: The maximum length is `1000` characters. The minimum length is `3` characters. The value must match regular expression `/^[a-zA-Z0-9 -._:]+$/`. +* `target_type` - (Required, Forces new resource, String) The type of the target. It can be cloud_object_storage or logdna. Based on this type you must include cos_endpoint or logdna_endpoint. + * Constraints: Allowable values are: `cloud_object_storage`, `logdna`. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. - -* `id` - The unique identifier of the Activity Tracker Target. -* `cos_write_status` - (Optional, List) The status of the write attempt with the provided cos_endpoint parameters. +* `id` - The unique identifier of the atracker_target. +* `api_version` - (Required, Integer) The API version of the target. +* `created_at` - (String) The timestamp of the target creation time. +* `crn` - (Required, String) The crn of the target resource. +* `encryption_key` - (Optional, String) The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response. +* `updated_at` - (String) The timestamp of the target last updated time. +* `write_status` - (List) The status of the write attempt to the target with the provided endpoint parameters. +Nested scheme for **write_status**: + * `last_failure` - (Optional, String) The timestamp of the failure. + * `reason_for_last_failure` - (Optional, String) Detailed description of the cause of the failure. + * `status` - (Required, String) The status such as failed or success. +* `cos_write_status` - **DEPRECATED** (Optional, List) The status of the write attempt with the provided cos_endpoint parameters. Nested scheme for **cos_write_status**: * `status` - (Optional, String) The status such as failed or success. * `last_failure` - (Optional, String) The timestamp of the failure. * `reason_for_last_failure` - (Optional, String) Detailed description of the cause of the failure. -* `created` - (Optional, String) The timestamp of the target creation time. -* `crn` - (Required, String) The crn of the target resource. -* `encrypt_key` - (Optional, String) The encryption key that is used to encrypt events before Activity Tracker services buffer them on storage. This credential is masked in the response. -* `updated` - (Optional, String) The timestamp of the target last updated time. +* `created` - **DEPRECATED** (Optional, String) The timestamp of the target creation time. +* `updated` - **DEPRECATED** (Optional, String) The timestamp of the target last updated time. ## Import diff --git a/website/docs/r/cbr_rule.html.markdown b/website/docs/r/cbr_rule.html.markdown new file mode 100644 index 000000000..c5b87dbf0 --- /dev/null +++ b/website/docs/r/cbr_rule.html.markdown @@ -0,0 +1,163 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cbr_rule" +description: |- + Manages cbr_rule. +subcategory: "Context Based Restrictions" +--- + +# ibm_cbr_rule + +Provides a resource for cbr_rule. This allows cbr_rule to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cbr_rule" "cbr_rule" { + contexts { + attributes { + name = "name" + value = "value" + } + } + description = "this is an example of rule" + enforcement_mode = "enabled" + operations { + api_types { + api_type_id = "api_type_id" + } + } + resources { + attributes { + name = "name" + value = "value" + operator = "operator" + } + tags { + name = "name" + value = "value" + operator = "operator" + } + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `contexts` - (Optional, List) The contexts this rule applies to. + * Constraints: The maximum length is `1000` items. The minimum length is `1` item. +Nested scheme for **contexts**: + * `attributes` - (Required, List) The attributes. + * Constraints: The minimum length is `1` item. + Nested scheme for **attributes**: + * `name` - (Required, String) The attribute name. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (Required, String) The attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[\S\s]+$/`. +* `description` - (Optional, String) The description of the rule. + * Constraints: The maximum length is `300` characters. The minimum length is `0` characters. The value must match regular expression `/^[\x20-\xFE]*$/`. +* `enforcement_mode` - (Optional, String) The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced. + * Constraints: The default value is `enabled`. Allowable values are: `enabled`, `disabled`, `report`. +* `operations` - (Optional, List) The operations this rule applies to. +Nested scheme for **operations**: + * `api_types` - (Required, List) The API types this rule applies to. + * Constraints: The maximum length is `100` items. The minimum length is `1` item. + Nested scheme for **api_types**: + * `api_type_id` - (Required, String) + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.\-:]+$/`. +* `resources` - (Optional, List) The resources this rule apply to. + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **resources**: + * `attributes` - (Required, List) The resource attributes. + * Constraints: The minimum length is `1` item. + Nested scheme for **attributes**: + * `name` - (Required, String) The attribute name. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `operator` - (Optional, String) The attribute operator. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (Required, String) The attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[\S\s]+$/`. + * `tags` - (Optional, List) The optional resource tags. + * Constraints: The maximum length is `10` items. The minimum length is `1` item. + Nested scheme for **tags**: + * `name` - (Required, String) The tag attribute name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 _.-]+$/`. + * `operator` - (Optional, String) The attribute operator. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9]+$/`. + * `value` - (Required, String) The tag attribute value. + * Constraints: The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 _*?.-]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cbr_rule. +* `created_at` - (String) The time the resource was created. +* `created_by_id` - (String) IAM ID of the user or service which created the resource. +* `crn` - (String) The rule CRN. +* `href` - (String) The href link to the resource. +* `last_modified_at` - (String) The last time the resource was modified. +* `last_modified_by_id` - (String) IAM ID of the user or service which modified the resource. + +* `version` - Version of the cbr_rule. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cbr_rule` resource by using `id`. The globally unique ID of the rule. + +# Syntax +``` +$ terraform import ibm_cbr_rule.cbr_rule +``` diff --git a/website/docs/r/cbr_zone.html.markdown b/website/docs/r/cbr_zone.html.markdown new file mode 100644 index 000000000..f64da4b69 --- /dev/null +++ b/website/docs/r/cbr_zone.html.markdown @@ -0,0 +1,153 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cbr_zone" +description: |- + Manages cbr_zone. +subcategory: "Context Based Restrictions" +--- + +# ibm_cbr_zone + +Provides a resource for cbr_zone. This allows cbr_zone to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cbr_zone" "cbr_zone" { + account_id = "12ab34cd56ef78ab90cd12ef34ab56cd" + addresses { + type = "ipAddress" + value = "value" + } + description = "this is an example of zone" + excluded { + type = "ipAddress" + value = "value" + } + name = "an example of zone" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `account_id` - (Optional, String) The id of the account owning this zone. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. +* `addresses` - (Optional, List) The list of addresses in the zone. + * Constraints: The maximum length is `1000` items. The minimum length is `1` item. +Nested scheme for **addresses**: + * `ref` - (Optional, List) A service reference value. + Nested scheme for **ref**: + * `account_id` - (Required, String) The id of the account owning the service. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. + * `location` - (Optional, String) The location. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_instance` - (Optional, String) The service instance. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-\/]+$/`. + * `service_name` - (Optional, String) The service name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_type` - (Optional, String) The service type. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z_]+$/`. + * `type` - (Optional, String) The type of address. + * Constraints: Allowable values are: `ipAddress`, `ipRange`, `subnet`, `vpc`, `serviceRef`. + * `value` - (Optional, String) The IP address. + * Constraints: The maximum length is `45` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9:.]+$/`. +* `description` - (Optional, String) The description of the zone. + * Constraints: The maximum length is `300` characters. The minimum length is `0` characters. The value must match regular expression `/^[\x20-\xFE]*$/`. +* `excluded` - (Optional, List) The list of excluded addresses in the zone. Only addresses of type `ipAddress`, `ipRange`, and `subnet` can be excluded. + * Constraints: The maximum length is `1000` items. +Nested scheme for **excluded**: + * `ref` - (Optional, List) A service reference value. + Nested scheme for **ref**: + * `account_id` - (Required, String) The id of the account owning the service. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. + * `location` - (Optional, String) The location. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_instance` - (Optional, String) The service instance. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-/]+$/`. + * `service_name` - (Optional, String) The service name. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z\-]+$/`. + * `service_type` - (Optional, String) The service type. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-z_]+$/`. + * `type` - (Optional, String) The type of address. + * Constraints: Allowable values are: `ipAddress`, `ipRange`, `subnet`, `vpc`, `serviceRef`. + * `value` - (Optional, String) The IP address. + * Constraints: The maximum length is `45` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9:.]+$/`. +* `name` - (Optional, String) The name of the zone. + * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9 \-_]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cbr_zone. +* `address_count` - (Integer) The number of addresses in the zone. +* `created_at` - (String) The time the resource was created. +* `created_by_id` - (String) IAM ID of the user or service which created the resource. +* `crn` - (String) The zone CRN. +* `excluded_count` - (Integer) The number of excluded addresses in the zone. +* `href` - (String) The href link to the resource. +* `last_modified_at` - (String) The last time the resource was modified. +* `last_modified_by_id` - (String) IAM ID of the user or service which modified the resource. + +* `version` - Version of the cbr_zone. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cbr_zone` resource by using `id`. The globally unique ID of the zone. + +# Syntax +``` +$ terraform import ibm_cbr_zone.cbr_zone +``` diff --git a/website/docs/r/cd_tekton_pipeline.html.markdown b/website/docs/r/cd_tekton_pipeline.html.markdown new file mode 100644 index 000000000..5b4f2ba20 --- /dev/null +++ b/website/docs/r/cd_tekton_pipeline.html.markdown @@ -0,0 +1,224 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline" +description: |- + Manages cd_tekton_pipeline. +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline + +Provides a resource for cd_tekton_pipeline. This allows cd_tekton_pipeline to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_tekton_pipeline" "cd_tekton_pipeline" { + worker { + id = "id" + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `enable_partial_cloning` - (Optional, Boolean) Flag whether to enable partial cloning for this pipeline. When partial clone is enabled, only the files contained within the paths specified in definition repositories will be read and cloned. This means symbolic links may not work. + * Constraints: The default value is `false`. +* `enable_slack_notifications` - (Optional, Boolean) Flag whether to enable slack notifications for this pipeline. When enabled, pipeline run events will be published on all slack integration specified channels in the enclosing toolchain. + * Constraints: The default value is `false`. +* `worker` - (Optional, List) Worker object containing worker ID only. If omitted the IBM Managed shared workers are used by default. +Nested scheme for **worker**: + * `id` - (Required, String) ID of the worker. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_tekton_pipeline. +* `build_number` - (Integer) The latest pipeline run build number. If this property is absent, the pipeline hasn't had any pipeline runs. + * Constraints: The minimum value is `1`. +* `created_at` - (String) Standard RFC 3339 Date Time String. +* `definitions` - (List) Definition list. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **definitions**: + * `id` - (String) UUID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `scm_source` - (List) SCM source for Tekton pipeline definition. + Nested scheme for **scm_source**: + * `branch` - (String) A branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `path` - (String) The path to the definition's yaml files. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `service_instance_id` - (String) ID of the SCM repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `tag` - (String) A tag from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]{1,235}$/`. + * `url` - (Forces new resource, String) URL of the definition repository. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `enabled` - (Boolean) Flag whether this pipeline is enabled. +* `name` - (String) String. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. +* `properties` - (List) Tekton pipeline's environment properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed when using `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. +* `resource_group_id` - (String) ID. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]+$/`. +* `runs_url` - (String) URL for this pipeline showing the list of pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `status` - (String) Pipeline status. + * Constraints: Allowable values are: `configured`, `configuring`. +* `toolchain` - (List) Toolchain object. +Nested scheme for **toolchain**: + * `crn` - (String) The CRN for the toolchain that contains the Tekton pipeline. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + * `id` - (String) UUID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `triggers` - (List) Tekton pipeline triggers list. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **triggers**: + * `cron` - (String) Only needed for timer triggers. Cron expression for timer trigger. Maximum frequency is every 5 minutes. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. The value must match regular expression `/^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\/([0-6]))$/`. + * `disabled` - (Boolean) Flag whether the trigger is disabled. If omitted the trigger is enabled by default. + * `event_listener` - (String) Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `events` - (List) Only needed for Git triggers. Events object defines the events to which this Git trigger listens. + Nested scheme for **events**: + * `pull_request` - (Boolean) If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events. + * `pull_request_closed` - (Boolean) If true, the trigger listens for 'close pull request' Git webhook events. + * `push` - (Boolean) If true, the trigger listens for 'push' Git webhook events. + * `href` - (String) API URL for interacting with the trigger. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `id` - (String) ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `max_concurrent_runs` - (Integer) Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit. + * `name` - (String) Trigger name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. + * `properties` - (List) Trigger properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. + Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `href` - (String) API URL for interacting with the trigger property. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. Can be empty and should be omitted for `single_select` property type. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `scm_source` - (List) SCM source repository for a Git trigger. Only needed for Git triggers. + Nested scheme for **scm_source**: + * `blind_connection` - (Boolean) True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * `branch` - (String) Name of a branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `hook_id` - (String) ID of the webhook from the repo. Computed upon creation of the trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `pattern` - (String) Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^.{1,235}$/`. + * `service_instance_id` - (String) ID of the repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `url` - (Forces new resource, String) URL of the repository to which the trigger is listening. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `secret` - (List) Only needed for generic webhook trigger type. Secret used to start generic webhook trigger. + Nested scheme for **secret**: + * `algorithm` - (String) Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type. + * Constraints: Allowable values are: `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256`, `ripemd160`. + * `key_name` - (String) Secret name, not needed if type is `internal_validation`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `source` - (String) Secret location, not needed if secret type is `internal_validation`. + * Constraints: Allowable values are: `header`, `payload`, `query`. + * `type` - (String) Secret type. + * Constraints: Allowable values are: `token_matches`, `digest_matches`, `internal_validation`. + * `value` - (String) Secret value, not needed if secret type is `internal_validation`. + * Constraints: The maximum length is `4096` characters. The minimum length is `0` characters. The value must match regular expression `/./`. + * `tags` - (List) Trigger tags array. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `timezone` - (String) Only needed for timer triggers. Timezone for timer trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_., \/]{1,234}$/`. + * `type` - (String) Trigger type. + * Constraints: Allowable values are: . + * `webhook_url` - (String) Webhook URL that can be used to trigger pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `worker` - (List) Worker used to run the trigger. If not specified the trigger will use the default pipeline worker. + Nested scheme for **worker**: + * `id` - (Forces new resource, String) ID of the worker. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + * `name` - (String) Name of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_. \\(\\)\\[\\]]{1,235}$/`. + * `type` - (String) Type of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. +* `updated_at` - (String) Standard RFC 3339 Date Time String. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_tekton_pipeline` resource by using `id`. UUID. + +# Syntax +``` +$ terraform import ibm_cd_tekton_pipeline.cd_tekton_pipeline +``` diff --git a/website/docs/r/cd_tekton_pipeline_definition.html.markdown b/website/docs/r/cd_tekton_pipeline_definition.html.markdown new file mode 100644 index 000000000..8b9a3524f --- /dev/null +++ b/website/docs/r/cd_tekton_pipeline_definition.html.markdown @@ -0,0 +1,119 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_definition" +description: |- + Manages cd_tekton_pipeline_definition. +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_definition + +Provides a resource for cd_tekton_pipeline_definition. This allows cd_tekton_pipeline_definition to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_tekton_pipeline_definition" "cd_tekton_pipeline_definition" { + pipeline_id = "94619026-912b-4d92-8f51-6c74f0692d90" + scm_source { + url = "url" + branch = "branch" + tag = "tag" + path = "path" + service_instance_id = "service_instance_id" + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `scm_source` - (Optional, List) SCM source for Tekton pipeline definition. +Nested scheme for **scm_source**: + * `branch` - (Optional, String) A branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `path` - (Required, String) The path to the definition's yaml files. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `service_instance_id` - (Optional, String) ID of the SCM repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `tag` - (Optional, String) A tag from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_]{1,235}$/`. + * `url` - (Required, Forces new resource, String) URL of the definition repository. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_definition. +* `definition_id` - (String) UUID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_tekton_pipeline_definition` resource by using `id`. +The `id` property can be formed from `pipeline_id`, and `definition_id` in the following format: + +``` +/ +``` +* `pipeline_id`: A string in the format `94619026-912b-4d92-8f51-6c74f0692d90`. The Tekton pipeline ID. +* `definition_id`: A string in the format `94299034-d45f-4e9a-8ed5-6bd5c7bb7ada`. The definition ID. + +# Syntax +``` +$ terraform import ibm_cd_tekton_pipeline_definition.cd_tekton_pipeline_definition / +``` diff --git a/website/docs/r/cd_tekton_pipeline_property.html.markdown b/website/docs/r/cd_tekton_pipeline_property.html.markdown new file mode 100644 index 000000000..33f86bf67 --- /dev/null +++ b/website/docs/r/cd_tekton_pipeline_property.html.markdown @@ -0,0 +1,111 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_property" +description: |- + Manages cd_tekton_pipeline_property. +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_property + +Provides a resource for cd_tekton_pipeline_property. This allows cd_tekton_pipeline_property to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_tekton_pipeline_property" "cd_tekton_pipeline_property" { + name = "key1" + pipeline_id = "94619026-912b-4d92-8f51-6c74f0692d90" + type = "text" + value = "https://github.com/IBM/tekton-tutorial.git" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `enum` - (Optional, List) Options for `single_select` property type. Only needed when using `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. +* `name` - (Optional, Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. +* `path` - (Optional, String) A dot notation path for `integration` type properties to select a value from the tool integration. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `type` - (Optional, String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. +* `value` - (Optional, String) Property value. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_property. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_tekton_pipeline_property` resource by using `name`. +The `name` property can be formed from `pipeline_id`, and `property_name` in the following format: + +``` +/ +``` +* `pipeline_id`: A string in the format `94619026-912b-4d92-8f51-6c74f0692d90`. The Tekton pipeline ID. +* `property_name`: A string in the format `debug-pipeline`. The property name. + +# Syntax +``` +$ terraform import ibm_cd_tekton_pipeline_property.cd_tekton_pipeline_property / +``` diff --git a/website/docs/r/cd_tekton_pipeline_trigger.html.markdown b/website/docs/r/cd_tekton_pipeline_trigger.html.markdown new file mode 100644 index 000000000..d6ced74b0 --- /dev/null +++ b/website/docs/r/cd_tekton_pipeline_trigger.html.markdown @@ -0,0 +1,195 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_trigger" +description: |- + Manages cd_tekton_pipeline_trigger. +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_trigger + +Provides a resource for cd_tekton_pipeline_trigger. This allows cd_tekton_pipeline_trigger to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_tekton_pipeline_trigger" "cd_tekton_pipeline_trigger" { + event_listener = "pr-listener" + events { + push = true + pull_request_closed = true + pull_request = true + } + max_concurrent_runs = 3 + name = "Manual Trigger" + pipeline_id = "94619026-912b-4d92-8f51-6c74f0692d90" + scm_source { + url = "url" + branch = "branch" + pattern = "pattern" + } + secret { + type = "token_matches" + value = "value" + source = "header" + key_name = "key_name" + algorithm = "md4" + } + type = "manual" + worker { + id = "public" + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `cron` - (Optional, String) Only needed for timer triggers. Cron expression for timer trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. The value must match regular expression `/^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\/([0-6]))$/`. +* `disabled` - (Optional, Boolean) Flag whether the trigger is disabled. If omitted the trigger is enabled by default. +* `event_listener` - (Optional, String) Event listener name. The name of the event listener to which the trigger is associated. The event listeners are defined in the definition repositories of the Tekton pipeline. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. +* `events` - (Optional, List) Only needed for Git triggers. Events object defines the events to which this Git trigger listens. +Nested scheme for **events**: + * `pull_request` - (Optional, Boolean) If true, the trigger listens for 'open pull request' or 'update pull request' Git webhook events. + * `pull_request_closed` - (Optional, Boolean) If true, the trigger listens for 'close pull request' Git webhook events. + * `push` - (Optional, Boolean) If true, the trigger listens for 'push' Git webhook events. +* `max_concurrent_runs` - (Optional, Integer) Defines the maximum number of concurrent runs for this trigger. Omit this property to disable the concurrency limit. +* `name` - (Optional, String) Trigger name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][-0-9a-zA-Z_. ]{1,235}[a-zA-Z0-9]$/`. +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `scm_source` - (Optional, List) SCM source repository for a Git trigger. Only needed for Git triggers. +Nested scheme for **scm_source**: + * `blind_connection` - (Optional, Boolean) True if the repository server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * `branch` - (Optional, String) Name of a branch from the repo. One of branch or tag must be specified, but only one or the other. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `hook_id` - (Optional, String) ID of the webhook from the repo. Computed upon creation of the trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `pattern` - (Optional, String) Git branch or tag pattern to listen to. Please refer to https://github.com/micromatch/micromatch for pattern syntax. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^.{1,235}$/`. + * `service_instance_id` - (Optional, String) ID of the repository service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `url` - (Required, Forces new resource, String) URL of the repository to which the trigger is listening. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `secret` - (Optional, List) Only needed for generic webhook trigger type. Secret used to start generic webhook trigger. +Nested scheme for **secret**: + * `algorithm` - (Optional, String) Algorithm used for `digest_matches` secret type. Only needed for `digest_matches` secret type. + * Constraints: Allowable values are: `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256`, `ripemd160`. + * `key_name` - (Optional, String) Secret name, not needed if type is `internal_validation`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + * `source` - (Optional, String) Secret location, not needed if secret type is `internal_validation`. + * Constraints: Allowable values are: `header`, `payload`, `query`. + * `type` - (Optional, String) Secret type. + * Constraints: Allowable values are: `token_matches`, `digest_matches`, `internal_validation`. + * `value` - (Optional, String) Secret value, not needed if secret type is `internal_validation`. + * Constraints: The maximum length is `4096` characters. The minimum length is `0` characters. The value must match regular expression `/./`. +* `tags` - (Optional, List) Trigger tags array. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. +* `timezone` - (Optional, String) Only needed for timer triggers. Timezone for timer trigger. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_., \/]{1,234}$/`. +* `type` - (Optional, String) Trigger type. + * Constraints: Allowable values are: `manual`, `scm`, `timer`, `generic`. +* `worker` - (Optional, List) Worker used to run the trigger. If not specified the trigger will use the default pipeline worker. +Nested scheme for **worker**: + * `id` - (Required, Forces new resource, String) ID of the worker. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^(public)|(preview)|([-0-9a-fA-F]{36})$/`. + * `name` - (Optional, String) Name of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_. \\(\\)\\[\\]]{1,235}$/`. + * `type` - (Optional, String) Type of the worker. Computed based on the worker ID. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_trigger. +* `href` - (String) API URL for interacting with the trigger. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `properties` - (List) Trigger properties. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **properties**: + * `enum` - (List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. + * `href` - (String) API URL for interacting with the trigger property. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `name` - (Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. + * `path` - (String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + * `type` - (String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. + * `value` - (String) Property value. Can be empty and should be omitted for `single_select` property type. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. +* `trigger_id` - (String) ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `webhook_url` - (String) Webhook URL that can be used to trigger pipeline runs. + * Constraints: The maximum length is `2048` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_tekton_pipeline_trigger` resource by using `id`. +The `id` property can be formed from `pipeline_id`, and `trigger_id` in the following format: + +``` +/ +``` +* `pipeline_id`: A string in the format `94619026-912b-4d92-8f51-6c74f0692d90`. The Tekton pipeline ID. +* `trigger_id`: A string in the format `1bb892a1-2e04-4768-a369-b1159eace147`. The trigger ID. + +# Syntax +``` +$ terraform import ibm_cd_tekton_pipeline_trigger.cd_tekton_pipeline_trigger / +``` diff --git a/website/docs/r/cd_tekton_pipeline_trigger_property.html.markdown b/website/docs/r/cd_tekton_pipeline_trigger_property.html.markdown new file mode 100644 index 000000000..98c0f97e9 --- /dev/null +++ b/website/docs/r/cd_tekton_pipeline_trigger_property.html.markdown @@ -0,0 +1,115 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_tekton_pipeline_trigger_property" +description: |- + Manages cd_tekton_pipeline_trigger_property. +subcategory: "CD Tekton Pipeline" +--- + +# ibm_cd_tekton_pipeline_trigger_property + +Provides a resource for cd_tekton_pipeline_trigger_property. This allows cd_tekton_pipeline_trigger_property to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_tekton_pipeline_trigger_property" "cd_tekton_pipeline_trigger_property" { + name = "key1" + pipeline_id = "94619026-912b-4d92-8f51-6c74f0692d90" + trigger_id = "1bb892a1-2e04-4768-a369-b1159eace147" + type = "text" + value = "https://github.com/IBM/tekton-tutorial.git" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `enum` - (Optional, List) Options for `single_select` property type. Only needed for `single_select` property type. + * Constraints: The list items must match regular expression `/^[-0-9a-zA-Z_.]{1,235}$/`. The maximum length is `128` items. The minimum length is `0` items. +* `name` - (Optional, Forces new resource, String) Property name. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]{1,234}$/`. +* `path` - (Optional, String) A dot notation path for `integration` type properties to select a value from the tool integration. If left blank the full tool integration data will be used. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. +* `pipeline_id` - (Required, Forces new resource, String) The Tekton pipeline ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `trigger_id` - (Required, Forces new resource, String) The trigger ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `type` - (Optional, String) Property type. + * Constraints: Allowable values are: `secure`, `text`, `integration`, `single_select`, `appconfig`. +* `value` - (Optional, String) Property value. + * Constraints: The maximum length is `4096` characters. The minimum length is `1` character. The value must match regular expression `/./`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_tekton_pipeline_trigger_property. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_tekton_pipeline_trigger_property` resource by using `name`. +The `name` property can be formed from `pipeline_id`, `trigger_id`, and `property_name` in the following format: + +``` +// +``` +* `pipeline_id`: A string in the format `94619026-912b-4d92-8f51-6c74f0692d90`. The Tekton pipeline ID. +* `trigger_id`: A string in the format `1bb892a1-2e04-4768-a369-b1159eace147`. The trigger ID. +* `property_name`: A string in the format `debug-pipeline`. The property name. + +# Syntax +``` +$ terraform import ibm_cd_tekton_pipeline_trigger_property.cd_tekton_pipeline_trigger_property // +``` diff --git a/website/docs/r/cd_toolchain.html.markdown b/website/docs/r/cd_toolchain.html.markdown new file mode 100644 index 000000000..7ca9d8b5d --- /dev/null +++ b/website/docs/r/cd_toolchain.html.markdown @@ -0,0 +1,107 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain" +description: |- + Manages cd_toolchain. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain. This allows cd_toolchain to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain" "cd_toolchain" { + description = "A sample toolchain to test the API" + name = "TestToolchainV2" + resource_group_id = "6a9a01f2cff54a7f966f803d92877123" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `description` - (Optional, String) Describes the toolchain. + * Constraints: The maximum length is `500` characters. The minimum length is `0` characters. The value must match regular expression `/^(.*?)$/`. +* `name` - (Required, String) Toolchain name. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `resource_group_id` - (Required, Forces new resource, String) Resource group where toolchain will be created. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-f]{32}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain. +* `account_id` - (String) Account ID where toolchain can be found. +* `created_at` - (String) Toolchain creation timestamp. +* `created_by` - (String) Identity that created the toolchain. +* `crn` - (String) Toolchain CRN. +* `href` - (String) URI that can be used to retrieve toolchain. +* `location` - (String) Toolchain region. +* `tags` - (List) Tags associated with the toolchain. +* `updated_at` - (String) Latest toolchain update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain` resource by using `id`. Toolchain ID. + +# Syntax +``` +$ terraform import ibm_cd_toolchain.cd_toolchain +``` diff --git a/website/docs/r/cd_toolchain_tool_appconfig.html.markdown b/website/docs/r/cd_toolchain_tool_appconfig.html.markdown new file mode 100644 index 000000000..ab61274b6 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_appconfig.html.markdown @@ -0,0 +1,134 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_appconfig" +description: |- + Manages cd_toolchain_tool_appconfig. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_appconfig + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_appconfig. This allows cd_toolchain_tool_appconfig to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_appconfig" "cd_toolchain_tool_appconfig" { + parameters { + name = "name" + region = "region" + resource_group = "resource_group" + instance_name = "instance_name" + environment_name = "environment_name" + collection_name = "collection_name" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `collection_name` - (Required, String) App Configuration collection. + * Constraints: The value must match regular expression `/\\S/`. + * `environment_name` - (Required, String) App Configuration environment. + * Constraints: The value must match regular expression `/\\S/`. + * `instance_name` - (Required, String) The name of your App Configuration instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: App Configuration-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (Required, String) Type a name for this tool integration, for example: my-appconfig. This name displays on your toolchain. + * `region` - (Required, String) Region. + * `resource_group` - (Required, String) Resource group. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_appconfig. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_appconfig` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_appconfig.cd_toolchain_tool_appconfig / +``` diff --git a/website/docs/r/cd_toolchain_tool_artifactory.html.markdown b/website/docs/r/cd_toolchain_tool_artifactory.html.markdown new file mode 100644 index 000000000..69c8ed16f --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_artifactory.html.markdown @@ -0,0 +1,140 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_artifactory" +description: |- + Manages cd_toolchain_tool_artifactory. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_artifactory + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_artifactory. This allows cd_toolchain_tool_artifactory to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_artifactory" "cd_toolchain_tool_artifactory" { + parameters { + name = "name" + dashboard_url = "dashboard_url" + type = "npm" + user_id = "user_id" + token = "token" + release_url = "release_url" + mirror_url = "mirror_url" + snapshot_url = "snapshot_url" + repository_name = "repository_name" + repository_url = "repository_url" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `dashboard_url` - (Optional, String) Type the URL that you want to navigate to when you click the Artifactory integration tile. + * `mirror_url` - (Optional, String) Type the URL for your Artifactory virtual repository, which is a repository that can see your private repositories and a cache of the public repositories. + * `name` - (Required, String) Type a name for this tool integration, for example: my-artifactory. This name displays on your toolchain. + * `release_url` - (Optional, String) Type the URL for your Artifactory release repository. + * `repository_name` - (Optional, String) Type the name of your artifactory repository where your docker images are located. + * `repository_url` - (Optional, String) Type the URL of your artifactory repository where your docker images are located. + * `snapshot_url` - (Optional, String) Type the URL for your Artifactory snapshot repository. + * `token` - (Optional, String) Type the API key for your Artifactory repository. + * `type` - (Required, String) Choose the type of repository for your Artifactory integration. + * Constraints: Allowable values are: `npm`, `maven`, `docker`. + * `user_id` - (Optional, String) Type the User ID or email for your Artifactory repository. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_artifactory. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_artifactory` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_artifactory.cd_toolchain_tool_artifactory / +``` diff --git a/website/docs/r/cd_toolchain_tool_bitbucketgit.html.markdown b/website/docs/r/cd_toolchain_tool_bitbucketgit.html.markdown new file mode 100644 index 000000000..ee08d7149 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_bitbucketgit.html.markdown @@ -0,0 +1,167 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_bitbucketgit" +description: |- + Manages cd_toolchain_tool_bitbucketgit. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_bitbucketgit + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_bitbucketgit. This allows cd_toolchain_tool_bitbucketgit to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_bitbucketgit" "cd_toolchain_tool_bitbucketgit" { + initialization { + git_id = "git_id" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + type = "new" + private_repo = true + } + parameters { + git_id = "git_id" + api_root_url = "api_root_url" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + token_url = "token_url" + type = "new" + private_repo = true + has_issues = true + enable_traceability = true + integration_owner = "integration_owner" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `initialization` - (Required, List) +Nested scheme for **initialization**: + * `git_id` - (Optional, Forces new resource, String) + * `owner_id` - (Optional, Forces new resource, String) + * `private_repo` - (Optional, Forces new resource, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, Forces new resource, String) + * `repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are forking or cloning. + * `type` - (Required, Forces new resource, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (Optional, String) e.g. https://api.bitbucket.org. + * `enable_traceability` - (Optional, Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (Optional, String) + * `has_issues` - (Optional, Boolean) Select this check box to enable Bitbucket Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (Optional, String) Select the user which git operations will be performed as. + * `owner_id` - (Optional, String) + * `private_repo` - (Optional, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, String) + * `repo_url` - (Optional, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (Optional, String) Integration token URL. + * `type` - (Optional, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_bitbucketgit. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_bitbucketgit` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_bitbucketgit.cd_toolchain_tool_bitbucketgit / +``` diff --git a/website/docs/r/cd_toolchain_tool_custom.html.markdown b/website/docs/r/cd_toolchain_tool_custom.html.markdown new file mode 100644 index 000000000..aae638beb --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_custom.html.markdown @@ -0,0 +1,136 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_custom" +description: |- + Manages cd_toolchain_tool_custom. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_custom + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_custom. This allows cd_toolchain_tool_custom to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_custom" "cd_toolchain_tool_custom" { + parameters { + type = "type" + lifecycle_phase = "THINK" + image_url = "image_url" + documentation_url = "documentation_url" + name = "name" + dashboard_url = "dashboard_url" + description = "description" + additional_properties = "additional_properties" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `additional_properties` - (Optional, String) (Advanced) Type any information that is needed to integrate with other tools in your toolchain. + * `dashboard_url` - (Required, String) Type the URL that you want to navigate to when you click the tool integration card. + * `description` - (Optional, String) Type a description for the tool instance. + * `documentation_url` - (Optional, String) Type the URL for your tool's documentation. + * `image_url` - (Optional, String) Type the URL of the icon to show on your tool integration's card. + * `lifecycle_phase` - (Required, String) Select the lifecycle phase of the IBM Cloud Garage Method that is the most closely associated with this tool. + * Constraints: Allowable values are: `THINK`, `CODE`, `DELIVER`, `RUN`, `MANAGE`, `LEARN`, `CULTURE`. + * `name` - (Required, String) Type a name for this specific tool integration; for example: My Build and Deploy Pipeline. + * `type` - (Required, String) Type the name of the tool that you are integrating; for example: Delivery Pipeline. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_custom. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_custom` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_custom.cd_toolchain_tool_custom / +``` diff --git a/website/docs/r/cd_toolchain_tool_devopsinsights.html.markdown b/website/docs/r/cd_toolchain_tool_devopsinsights.html.markdown new file mode 100644 index 000000000..5b065906a --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_devopsinsights.html.markdown @@ -0,0 +1,115 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_devopsinsights" +description: |- + Manages cd_toolchain_tool_devopsinsights. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_devopsinsights + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_devopsinsights. This allows cd_toolchain_tool_devopsinsights to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_devopsinsights" "cd_toolchain_tool_devopsinsights" { + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_devopsinsights. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_devopsinsights` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_devopsinsights.cd_toolchain_tool_devopsinsights / +``` diff --git a/website/docs/r/cd_toolchain_tool_githubconsolidated.html.markdown b/website/docs/r/cd_toolchain_tool_githubconsolidated.html.markdown new file mode 100644 index 000000000..8e6f89ae3 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_githubconsolidated.html.markdown @@ -0,0 +1,173 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_githubconsolidated" +description: |- + Manages cd_toolchain_tool_githubconsolidated. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_githubconsolidated + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_githubconsolidated. This allows cd_toolchain_tool_githubconsolidated to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_githubconsolidated" "cd_toolchain_tool_githubconsolidated" { + initialization { + git_id = "git_id" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + type = "new" + private_repo = true + auto_init = true + } + parameters { + git_id = "git_id" + api_root_url = "api_root_url" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + token_url = "token_url" + type = "new" + private_repo = true + has_issues = true + auto_init = true + enable_traceability = true + integration_owner = "integration_owner" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `initialization` - (Required, List) +Nested scheme for **initialization**: + * `auto_init` - (Optional, Forces new resource, Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `git_id` - (Optional, Forces new resource, String) + * `owner_id` - (Optional, Forces new resource, String) + * `private_repo` - (Optional, Forces new resource, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, Forces new resource, String) + * `repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are forking or cloning. + * `type` - (Required, Forces new resource, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (Optional, String) e.g. https://api.github.example.com. + * `auto_init` - (Optional, Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `enable_traceability` - (Optional, Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (Optional, String) + * `has_issues` - (Optional, Boolean) Select this check box to enable GitHub Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (Optional, String) Select the user which git operations will be performed as. + * `owner_id` - (Optional, String) + * `private_repo` - (Optional, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, String) + * `repo_url` - (Optional, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (Optional, String) Integration token URL. + * `type` - (Optional, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_githubconsolidated. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_githubconsolidated` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_githubconsolidated.cd_toolchain_tool_githubconsolidated / +``` diff --git a/website/docs/r/cd_toolchain_tool_githubintegrated.html.markdown b/website/docs/r/cd_toolchain_tool_githubintegrated.html.markdown new file mode 100644 index 000000000..1471a2947 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_githubintegrated.html.markdown @@ -0,0 +1,177 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_githubintegrated" +description: |- + Manages cd_toolchain_tool_githubintegrated. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_githubintegrated + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_githubintegrated. This allows cd_toolchain_tool_githubintegrated to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_githubintegrated" "cd_toolchain_tool_githubintegrated" { + initialization { + legal = true + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + type = "new" + private_repo = true + auto_init = true + } + parameters { + git_id = "git_id" + api_root_url = "api_root_url" + legal = true + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + token_url = "token_url" + type = "new" + private_repo = true + auto_init = true + has_issues = true + enable_traceability = true + integration_owner = "integration_owner" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `initialization` - (Required, List) +Nested scheme for **initialization**: + * `auto_init` - (Optional, Forces new resource, Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `legal` - (Optional, Forces new resource, Boolean) + * Constraints: The default value is `true`. + * `owner_id` - (Optional, Forces new resource, String) + * `private_repo` - (Optional, Forces new resource, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, Forces new resource, String) + * `repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are forking or cloning. + * `type` - (Required, Forces new resource, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (Optional, String) e.g. https://github.ibm.com/api/v3. + * `auto_init` - (Optional, Boolean) Select this checkbox to initialize this repository with a README. + * Constraints: The default value is `false`. + * `enable_traceability` - (Optional, Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (Optional, String) + * `has_issues` - (Optional, Boolean) Select this check box to enable GitHub Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (Optional, String) Select the user which git operations will be performed as. + * `legal` - (Optional, Boolean) + * Constraints: The default value is `false`. + * `owner_id` - (Optional, String) + * `private_repo` - (Optional, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `false`. + * `repo_name` - (Optional, String) + * `repo_url` - (Optional, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (Optional, String) Integration token URL. + * `type` - (Optional, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_githubintegrated. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_githubintegrated` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_githubintegrated.cd_toolchain_tool_githubintegrated / +``` diff --git a/website/docs/r/cd_toolchain_tool_gitlab.html.markdown b/website/docs/r/cd_toolchain_tool_gitlab.html.markdown new file mode 100644 index 000000000..50998ec40 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_gitlab.html.markdown @@ -0,0 +1,167 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_gitlab" +description: |- + Manages cd_toolchain_tool_gitlab. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_gitlab + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_gitlab. This allows cd_toolchain_tool_gitlab to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_gitlab" "cd_toolchain_tool_gitlab" { + initialization { + git_id = "git_id" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + type = "new" + private_repo = true + } + parameters { + git_id = "git_id" + api_root_url = "api_root_url" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + token_url = "token_url" + type = "new" + private_repo = true + has_issues = true + enable_traceability = true + integration_owner = "integration_owner" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `initialization` - (Required, List) +Nested scheme for **initialization**: + * `git_id` - (Optional, Forces new resource, String) + * `owner_id` - (Optional, Forces new resource, String) + * `private_repo` - (Optional, Forces new resource, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (Optional, Forces new resource, String) + * `repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are forking or cloning. + * `type` - (Required, Forces new resource, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (Optional, String) e.g. https://gitlab.example.com/api/v4. + * `enable_traceability` - (Optional, Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (Optional, String) + * `has_issues` - (Optional, Boolean) Select this check box to enable GitLab Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (Optional, String) Select the user which git operations will be performed as. + * `owner_id` - (Optional, String) + * `private_repo` - (Optional, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (Optional, String) + * `repo_url` - (Optional, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (Optional, String) Integration token URL. + * `type` - (Optional, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_gitlab. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_gitlab` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_gitlab.cd_toolchain_tool_gitlab / +``` diff --git a/website/docs/r/cd_toolchain_tool_hashicorpvault.html.markdown b/website/docs/r/cd_toolchain_tool_hashicorpvault.html.markdown new file mode 100644 index 000000000..a90bb0684 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_hashicorpvault.html.markdown @@ -0,0 +1,144 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_hashicorpvault" +description: |- + Manages cd_toolchain_tool_hashicorpvault. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_hashicorpvault + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_hashicorpvault. This allows cd_toolchain_tool_hashicorpvault to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_hashicorpvault" "cd_toolchain_tool_hashicorpvault" { + parameters { + name = "name" + server_url = "server_url" + authentication_method = "token" + token = "token" + role_id = "role_id" + secret_id = "secret_id" + dashboard_url = "dashboard_url" + path = "path" + secret_filter = "secret_filter" + default_secret = "default_secret" + username = "username" + password = "password" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `authentication_method` - (Required, String) Choose the authentication method for your HashiCorp Vault instance. + * Constraints: Allowable values are: `token`, `approle`, `userpass`, `github`. + * `dashboard_url` - (Required, String) Type the URL that you want to navigate to when you click the HashiCorp Vault integration tile. + * `default_secret` - (Optional, String) Type a default secret name that will be selected or used if no list of secret names are returned from your HashiCorp Vault instance. + * `name` - (Required, String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `password` - (Optional, String) Type or select the authentication password for your HashiCorp Vault instance. + * `path` - (Required, String) Type the mount path where your secrets are stored in your HashiCorp Vault instance. + * `role_id` - (Optional, String) Type or select the authentication role ID for your HashiCorp Vault instance. + * `secret_filter` - (Optional, String) Type a regular expression to filter the list of secret names returned from your HashiCorp Vault instance. + * `secret_id` - (Optional, String) Type or select the authentication secret ID for your HashiCorp Vault instance. + * `server_url` - (Required, String) Type the server URL for your HashiCorp Vault instance. + * `token` - (Optional, String) Type or select the authentication token for your HashiCorp Vault instance. + * `username` - (Optional, String) Type or select the authentication username for your HashiCorp Vault instance. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_hashicorpvault. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_hashicorpvault` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_hashicorpvault.cd_toolchain_tool_hashicorpvault / +``` diff --git a/website/docs/r/cd_toolchain_tool_hostedgit.html.markdown b/website/docs/r/cd_toolchain_tool_hostedgit.html.markdown new file mode 100644 index 000000000..5edc061a5 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_hostedgit.html.markdown @@ -0,0 +1,165 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_hostedgit" +description: |- + Manages cd_toolchain_tool_hostedgit. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_hostedgit + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_hostedgit. This allows cd_toolchain_tool_hostedgit to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_hostedgit" "cd_toolchain_tool_hostedgit" { + initialization { + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + type = "new" + private_repo = true + } + parameters { + git_id = "git_id" + api_root_url = "api_root_url" + owner_id = "owner_id" + repo_name = "repo_name" + repo_url = "repo_url" + source_repo_url = "source_repo_url" + token_url = "token_url" + type = "new" + private_repo = true + has_issues = true + enable_traceability = true + integration_owner = "integration_owner" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `initialization` - (Required, List) +Nested scheme for **initialization**: + * `owner_id` - (Optional, Forces new resource, String) + * `private_repo` - (Optional, Forces new resource, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (Optional, Forces new resource, String) + * `repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, Forces new resource, String) Type the URL of the repository that you are forking or cloning. + * `type` - (Required, Forces new resource, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_root_url` - (Optional, String) e.g. https://gitlab.example.com/api/v4. + * `enable_traceability` - (Optional, Boolean) Select this check box to track the deployment of code changes by creating tags, labels and comments on commits, pull requests and referenced issues. + * Constraints: The default value is `false`. + * `git_id` - (Optional, String) + * `has_issues` - (Optional, Boolean) Select this check box to enable Issues for lightweight issue tracking. + * Constraints: The default value is `true`. + * `integration_owner` - (Optional, String) Select the user which git operations will be performed as. + * `owner_id` - (Optional, String) + * `private_repo` - (Optional, Boolean) Select this check box to make this repository private. + * Constraints: The default value is `true`. + * `repo_name` - (Optional, String) + * `repo_url` - (Optional, String) Type the URL of the repository that you are linking to. + * `source_repo_url` - (Optional, String) Type the URL of the repository that you are forking or cloning. + * `token_url` - (Optional, String) Integration token URL. + * `type` - (Optional, String) + * Constraints: Allowable values are: `new`, `fork`, `clone`, `link`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_hostedgit. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_hostedgit` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_hostedgit.cd_toolchain_tool_hostedgit / +``` diff --git a/website/docs/r/cd_toolchain_tool_jenkins.html.markdown b/website/docs/r/cd_toolchain_tool_jenkins.html.markdown new file mode 100644 index 000000000..a198840cd --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_jenkins.html.markdown @@ -0,0 +1,129 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_jenkins" +description: |- + Manages cd_toolchain_tool_jenkins. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_jenkins + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_jenkins. This allows cd_toolchain_tool_jenkins to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_jenkins" "cd_toolchain_tool_jenkins" { + parameters { + name = "name" + dashboard_url = "dashboard_url" + webhook_url = "webhook_url" + api_user_name = "api_user_name" + api_token = "api_token" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_token` - (Optional, String) Type the API token to use for Jenkins REST API calls so that DevOps Insights can collect data from Jenkins. You can find the API token on the configuration page of your Jenkins instance. + * `api_user_name` - (Optional, String) Type the user name to use with the Jenkins server's API token, which is required so that DevOps Insights can collect data from Jenkins. You can find your API user name on the configuration page of your Jenkins instance. + * `dashboard_url` - (Required, String) Type the URL of the Jenkins server that you want to open when you click the Jenkins card in your toolchain. + * `name` - (Required, String) Type a name for this tool integration, for example: my-jenkins. This name displays on your toolchain. + * `webhook_url` - (Optional, String) Use this webhook in your Jenkins jobs to send notifications to other tools in your toolchain. For details, see the Configuring Jenkins instructions. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_jenkins. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_jenkins` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_jenkins.cd_toolchain_tool_jenkins / +``` diff --git a/website/docs/r/cd_toolchain_tool_keyprotect.html.markdown b/website/docs/r/cd_toolchain_tool_keyprotect.html.markdown new file mode 100644 index 000000000..f5d278140 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_keyprotect.html.markdown @@ -0,0 +1,128 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_keyprotect" +description: |- + Manages cd_toolchain_tool_keyprotect. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_keyprotect + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_keyprotect. This allows cd_toolchain_tool_keyprotect to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_keyprotect" "cd_toolchain_tool_keyprotect" { + parameters { + name = "name" + region = "region" + resource_group = "resource_group" + instance_name = "instance_name" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `instance_name` - (Required, String) The name of your Key Protect instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Key Protect-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (Required, String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `region` - (Required, String) Region. + * `resource_group` - (Required, String) Resource group. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_keyprotect. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_keyprotect` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_keyprotect.cd_toolchain_tool_keyprotect / +``` diff --git a/website/docs/r/cd_toolchain_tool_nexus.html.markdown b/website/docs/r/cd_toolchain_tool_nexus.html.markdown new file mode 100644 index 000000000..96a6d25cf --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_nexus.html.markdown @@ -0,0 +1,136 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_nexus" +description: |- + Manages cd_toolchain_tool_nexus. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_nexus + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_nexus. This allows cd_toolchain_tool_nexus to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_nexus" "cd_toolchain_tool_nexus" { + parameters { + name = "name" + dashboard_url = "dashboard_url" + type = "npm" + user_id = "user_id" + token = "token" + release_url = "release_url" + mirror_url = "mirror_url" + snapshot_url = "snapshot_url" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `dashboard_url` - (Optional, String) Type the URL that you want to navigate to when you click the Nexus integration tile. + * `mirror_url` - (Optional, String) Type the URL for your Nexus virtual repository, which is a repository that can see your private repositories and a cache of the public repositories. + * `name` - (Required, String) Type a name for this tool integration, for example: my-nexus. This name displays on your toolchain. + * `release_url` - (Optional, String) Type the URL for your Nexus release repository. + * `snapshot_url` - (Optional, String) Type the URL for your Nexus snapshot repository. + * `token` - (Optional, String) Type the password or authentication token for your Nexus repository. + * `type` - (Required, String) Choose the type of repository for your Nexus integration. + * Constraints: Allowable values are: `npm`, `maven`. + * `user_id` - (Optional, String) Type the User ID or email for your Nexus repository. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_nexus. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_nexus` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_nexus.cd_toolchain_tool_nexus / +``` diff --git a/website/docs/r/cd_toolchain_tool_pagerduty.html.markdown b/website/docs/r/cd_toolchain_tool_pagerduty.html.markdown new file mode 100644 index 000000000..45e301dc7 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_pagerduty.html.markdown @@ -0,0 +1,136 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_pagerduty" +description: |- + Manages cd_toolchain_tool_pagerduty. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_pagerduty + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_pagerduty. This allows cd_toolchain_tool_pagerduty to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_pagerduty" "cd_toolchain_tool_pagerduty" { + parameters { + key_type = "api" + api_key = "api_key" + service_name = "service_name" + user_email = "user_email" + user_phone = "user_phone" + service_url = "service_url" + service_key = "service_key" + service_id = "service_id" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_key` - (Optional, String) Type your API access key. You can find or create this key on the Configuration/API Access section of the PagerDuty website. [PagerDuty Support article on how to get API Key](https://support.pagerduty.com/hc/en-us/articles/202829310-Generating-an-API-Key). + * `key_type` - (Required, String) Select whether to integrate at the account level with an API key or at the service level with an integration key. + * Constraints: Allowable values are: `api`, `service`. + * `service_id` - (Optional, String) service_id. + * `service_key` - (Optional, String) Type your integration key. You can find or create this key in the Integrations section of the PagerDuty service page. + * `service_name` - (Optional, String) Type the name of the PagerDuty service to post alerts to. If you want alerts to be posted to a new service, type a new name. PagerDuty will create the service. + * `service_url` - (Optional, String) Type the URL of the PagerDuty service to post alerts to. + * `user_email` - (Optional, String) Type the email address of the user to contact when an alert is posted. If you want alerts to be sent to a new email address, type the address and PagerDuty will create a user. + * `user_phone` - (Optional, String) Type the phone number of the user to contact when an alert is posted. Include the national code followed by a space and a 10-digit number; for example: +1 1234567890. If you omit the national code, it is set to +1 by default. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_pagerduty. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_pagerduty` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_pagerduty.cd_toolchain_tool_pagerduty / +``` diff --git a/website/docs/r/cd_toolchain_tool_pipeline.html.markdown b/website/docs/r/cd_toolchain_tool_pipeline.html.markdown new file mode 100644 index 000000000..71ef08e90 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_pipeline.html.markdown @@ -0,0 +1,127 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_pipeline" +description: |- + Manages cd_toolchain_tool_pipeline. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_pipeline + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_pipeline. This allows cd_toolchain_tool_pipeline to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_pipeline" "cd_toolchain_tool_pipeline" { + parameters { + name = "name" + type = "classic" + ui_pipeline = true + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `name` - (Optional, String) + * `type` - (Optional, String) + * Constraints: Allowable values are: `classic`, `tekton`. + * `ui_pipeline` - (Optional, Boolean) When this check box is selected, the applications that this pipeline deploys are shown in the View app menu on the toolchain page. This setting is best for UI apps that can be accessed from a browser. + * Constraints: The default value is `false`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_pipeline. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_pipeline` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_pipeline.cd_toolchain_tool_pipeline / +``` diff --git a/website/docs/r/cd_toolchain_tool_privateworker.html.markdown b/website/docs/r/cd_toolchain_tool_privateworker.html.markdown new file mode 100644 index 000000000..bb0dd981e --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_privateworker.html.markdown @@ -0,0 +1,125 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_privateworker" +description: |- + Manages cd_toolchain_tool_privateworker. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_privateworker + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_privateworker. This allows cd_toolchain_tool_privateworker to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_privateworker" "cd_toolchain_tool_privateworker" { + parameters { + name = "name" + worker_queue_credentials = "worker_queue_credentials" + worker_queue_identifier = "worker_queue_identifier" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `name` - (Required, String) Enter a name for this tool integration. For example, my-private-worker. This name is displayed on your toolchain. + * `worker_queue_credentials` - (Required, String) Use a secret from the secrets store, or create a service ID API key that is used by the private worker to authenticate access to the work queue. + * `worker_queue_identifier` - (Optional, String) +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_privateworker. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_privateworker` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_privateworker.cd_toolchain_tool_privateworker / +``` diff --git a/website/docs/r/cd_toolchain_tool_saucelabs.html.markdown b/website/docs/r/cd_toolchain_tool_saucelabs.html.markdown new file mode 100644 index 000000000..36aa67356 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_saucelabs.html.markdown @@ -0,0 +1,123 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_saucelabs" +description: |- + Manages cd_toolchain_tool_saucelabs. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_saucelabs + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_saucelabs. This allows cd_toolchain_tool_saucelabs to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_saucelabs" "cd_toolchain_tool_saucelabs" { + parameters { + username = "username" + key = "key" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `key` - (Required, String) Type your Sauce Labs access key. You can find your access key near the lower-left corner of your Sauce Labs account page. + * `username` - (Required, String) Type the user name for your Sauce Labs account. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_saucelabs. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_saucelabs` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_saucelabs.cd_toolchain_tool_saucelabs / +``` diff --git a/website/docs/r/cd_toolchain_tool_secretsmanager.html.markdown b/website/docs/r/cd_toolchain_tool_secretsmanager.html.markdown new file mode 100644 index 000000000..90059cbe2 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_secretsmanager.html.markdown @@ -0,0 +1,128 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_secretsmanager" +description: |- + Manages cd_toolchain_tool_secretsmanager. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_secretsmanager + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_secretsmanager. This allows cd_toolchain_tool_secretsmanager to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_secretsmanager" "cd_toolchain_tool_secretsmanager" { + parameters { + name = "name" + region = "region" + resource_group = "resource_group" + instance_name = "instance_name" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `instance_name` - (Required, String) The name of your Secrets Manager instance. You should choose an entry from the list provided based on the selected region and resource group. e.g: Secrets Manager-01. + * Constraints: The value must match regular expression `/\\S/`. + * `name` - (Required, String) Enter a name for this tool integration. This name is displayed on your toolchain. + * `region` - (Required, String) Region. + * `resource_group` - (Required, String) Resource group. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_secretsmanager. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_secretsmanager` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_secretsmanager.cd_toolchain_tool_secretsmanager / +``` diff --git a/website/docs/r/cd_toolchain_tool_securitycompliance.html.markdown b/website/docs/r/cd_toolchain_tool_securitycompliance.html.markdown new file mode 100644 index 000000000..cfc6769d4 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_securitycompliance.html.markdown @@ -0,0 +1,138 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_securitycompliance" +description: |- + Manages cd_toolchain_tool_securitycompliance. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_securitycompliance + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_securitycompliance. This allows cd_toolchain_tool_securitycompliance to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_securitycompliance" "cd_toolchain_tool_securitycompliance" { + parameters { + name = "name" + evidence_repo_name = "evidence_repo_name" + trigger_scan = "disabled" + location = "location" + evidence_namespace = "evidence_namespace" + api_key = "api_key" + scope = "scope" + profile = "profile" + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_key` - (Optional, String) The IBM Cloud API key is used to access the Security and Compliance API. You can obtain your API key with 'ibmcloud iam api-key-create' or via the console at https://cloud.ibm.com/iam#/apikeys by clicking **Create API key** (Each API key only can be viewed once). + * Constraints: The value must match regular expression `/\\S/`. + * `evidence_namespace` - (Optional, String) The kind of pipeline evidence to be displayed in Security and Compliance Center for this toolchain. The evidence locker will be searched for CD (Continuous Deployment) pipeline evidence, or for CC (Continuous Compliance) pipeline evidence. + * `evidence_repo_name` - (Required, String) To collect and store evidence for all tasks performed, a Git repository is required as an evidence locker. + * `location` - (Optional, String) + * `name` - (Required, String) Give this tool integration a name, for example: my-security-compliance. + * `profile` - (Optional, String) Select an existing profile, where a profile is a collection of security controls. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-profiles) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg). + * `scope` - (Optional, String) Select an existing scope name to narrow the focus of the validation scan. [Learn more.](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-scopes) ![](https://cloud.ibm.com/media/docs/images/icons/launch-glyph.svg). + * `trigger_info` - (Optional, Map) trigger_info. + * `trigger_scan` - (Optional, String) Enabling trigger validation scans provides details for a pipeline task to trigger a scan. + * Constraints: Allowable values are: `disabled`, `enabled`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_securitycompliance. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_securitycompliance` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_securitycompliance.cd_toolchain_tool_securitycompliance / +``` diff --git a/website/docs/r/cd_toolchain_tool_slack.html.markdown b/website/docs/r/cd_toolchain_tool_slack.html.markdown new file mode 100644 index 000000000..e239a4122 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_slack.html.markdown @@ -0,0 +1,140 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_slack" +description: |- + Manages cd_toolchain_tool_slack. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_slack + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_slack. This allows cd_toolchain_tool_slack to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_slack" "cd_toolchain_tool_slack" { + parameters { + api_token = "api_token" + channel_name = "channel_name" + team_url = "team_url" + pipeline_start = true + pipeline_success = true + pipeline_fail = true + toolchain_bind = true + toolchain_unbind = true + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `api_token` - (Required, String) Type the Slack webhook URL, which is generated by Slack as an incoming webhook. You can create or find your webhook in the Incoming Webhooks section of the [Slack API website](https://api.slack.com/incoming-webhooks). If you have been using an API key, update your configuration to use a webhook instead. + * `channel_name` - (Required, String) If you use a webhook, you must specify an existing Slack channel to post notifications to. + * `pipeline_fail` - (Optional, Boolean) + * Constraints: The default value is `true`. + * `pipeline_start` - (Optional, Boolean) + * Constraints: The default value is `true`. + * `pipeline_success` - (Optional, Boolean) + * Constraints: The default value is `true`. + * `team_url` - (Optional, String) If you use a webhook, you must specify your team name, which is the word or phrase before _.slack.com_ in your team URL. For example, if your team URL is https://team.slack.com, the team name is _team_. + * `toolchain_bind` - (Optional, Boolean) + * Constraints: The default value is `true`. + * `toolchain_unbind` - (Optional, Boolean) + * Constraints: The default value is `true`. +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_slack. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_slack` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_slack.cd_toolchain_tool_slack / +``` diff --git a/website/docs/r/cd_toolchain_tool_sonarqube.html.markdown b/website/docs/r/cd_toolchain_tool_sonarqube.html.markdown new file mode 100644 index 000000000..35609ccf3 --- /dev/null +++ b/website/docs/r/cd_toolchain_tool_sonarqube.html.markdown @@ -0,0 +1,130 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_cd_toolchain_tool_sonarqube" +description: |- + Manages cd_toolchain_tool_sonarqube. +subcategory: "CD Toolchain" +--- + +# ibm_cd_toolchain_tool_sonarqube + +~> **Beta:** This resource is in Beta, and is subject to change. + +Provides a resource for cd_toolchain_tool_sonarqube. This allows cd_toolchain_tool_sonarqube to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cd_toolchain_tool_sonarqube" "cd_toolchain_tool_sonarqube" { + parameters { + name = "name" + dashboard_url = "dashboard_url" + user_login = "user_login" + user_password = "user_password" + blind_connection = true + } + toolchain_id = "toolchain_id" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `name` - (Optional, String) Name of tool. + * Constraints: The maximum length is `128` characters. The minimum length is `0` characters. The value must match regular expression `/^([^\\x00-\\x7F]|[a-zA-Z0-9-._ ])+$/`. +* `parameters` - (Required, List) Unique key-value pairs representing parameters to be used to create the tool. +Nested scheme for **parameters**: + * `blind_connection` - (Optional, Boolean) Select this checkbox only if the server is not addressable on the public internet. IBM Cloud will not be able to validate the connection details you provide. + * Constraints: The default value is `false`. + * `dashboard_url` - (Required, String) Type the URL of the SonarQube instance that you want to open when you click the SonarQube card in your toolchain. + * `name` - (Required, String) Type a name for this tool integration, for example: my-sonarqube. This name displays on your toolchain. + * `user_login` - (Optional, String) If you are using an authentication token, leave this field empty. + * `user_password` - (Optional, String) +* `toolchain_id` - (Required, Forces new resource, String) ID of the toolchain to bind the tool to. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cd_toolchain_tool_sonarqube. +* `crn` - (String) Tool CRN. +* `href` - (String) URI representing the tool. +* `referent` - (List) Information on URIs to access this resource through the UI or API. +Nested scheme for **referent**: + * `api_href` - (String) URI representing the this resource through an API. + * `ui_href` - (String) URI representing the this resource through the UI. +* `resource_group_id` - (String) Resource group where tool can be found. +* `state` - (String) Current configuration state of the tool. + * Constraints: Allowable values are: `configured`, `configuring`, `misconfigured`, `unconfigured`. +* `toolchain_crn` - (String) CRN of toolchain which the tool is bound to. +* `tool_id` - (String) Tool ID. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/`. +* `updated_at` - (String) Latest tool update timestamp. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cd_toolchain_tool_sonarqube` resource by using `id`. +The `id` property can be formed from `toolchain_id`, and `tool_id` in the following format: + +``` +/ +``` +* `toolchain_id`: A string. ID of the toolchain to bind the tool to. +* `tool_id`: A string. ID of the tool bound to the toolchain. + +# Syntax +``` +$ terraform import ibm_cd_toolchain_tool_sonarqube.cd_toolchain_tool_sonarqube / +``` diff --git a/website/docs/r/cis.html.markdown b/website/docs/r/cis.html.markdown index ee689453e..6ddec863b 100644 --- a/website/docs/r/cis.html.markdown +++ b/website/docs/r/cis.html.markdown @@ -48,6 +48,7 @@ Review the argument references that you can specify for your resource. - `location` - (Required, String) The target location where you want to create your instance. - `name` - (Required, String) A descriptive name for your IBM Cloud Internet Services instance. +- `parameters` (Optional, Map) Arbitrary parameters to create instance. The value must be a JSON object. - `plan` - (Required, String) The name of the plan for your instance. To retrieve this value, run `ibmcloud catalog service internet-svcs` command in the [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cloud-cli-getting-started). - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the service. To retrieve this value, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. If no value is specified, the `default` resource group is used. - `tags` - (Optional, Array of strings) A list of tags that you want to associate with the instance. @@ -58,7 +59,8 @@ In addition to all argument reference list, you can access the following attribu - `guid` - (String) The unique identifier of the CIS instance. - `id` - (String) The CRN of the CIS instance. -- `status` - (String) The status of the CIS instance. +* `service` - (String) The service type of the instance. +* `status` - (String) The status of the CIS instance. ## Import diff --git a/website/docs/r/cis_alert.html.markdown b/website/docs/r/cis_alert.html.markdown new file mode 100644 index 000000000..4cedfcf26 --- /dev/null +++ b/website/docs/r/cis_alert.html.markdown @@ -0,0 +1,122 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_alert" +description: |- + Provides a IBM Cloud CIS Alert Policy. +--- + +# ibm_cis_alert + +Provides a IBM CIS Alert Policy. This resource is associated with an IBM Cloud Internet Services (CIS) instance and a CIS Domain resource. It allows to create, update, delete Alert Policy of a CIS instance. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform + +resource "ibm_cis_webhook" "test" { + cis_id = data.ibm_cis.cis.id + name = "My Slack Alert Webhook", + url ="https://hooks.slack.com/services/Ds3fdBFbV/456464Gdd", + secret = "ff1d9b80-b51d-4a06-bf67-6752fae1eb74" +} +resource "ibm_cis_alert" "test" { + depends_on = [ibm_cis_webhook.test] + cis_id = data.ibm_cis.cis.id + name = "test-alert-police" + description = "alert policy description" + enabled = true + alert_type = "g6_pool_toggle_alert" + mechanisms { + email = ["mynotifications@email.com"] + webhooks = [ibm_cis_webhook.test.webhook_id] + } + filters = <:<`crn`> attributes concatenated with ":". +- `alert_id` - (String) Unique identifier for the each Alert. + + +## Import + +The `ibm_cis_alert` resource can be imported using the `id`. The ID is formed from the `Alert ID`and the `CRN` (Cloud Resource Name) concatentated usinga `:` character. + +The CRN will be located on the **Overview** page of the Internet Services instance under the **Domain** heading of the UI, or via using the `ibmcloud cis` CLI commands. + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + +- **Alert ID** is a 32 digit character string of the form: `52bfa670237f49ecb68473033c569649`. + +**Syntax** + +``` +$ terraform import ibm_cis_alert.myorg : +``` + +**Example** + +``` +$ terraform import ibm_cis_alert.myorg +crn:v1:bluemix:public:internet-svcs-ci:global:a/01652b251c3ae2787110a995d8db0135:9054ad06-3485-421a-9300-fe3fb4b79e1d:: +``` \ No newline at end of file diff --git a/website/docs/r/cis_domain.html.markdown b/website/docs/r/cis_domain.html.markdown index 8bb14dc41..e6c9fa282 100644 --- a/website/docs/r/cis_domain.html.markdown +++ b/website/docs/r/cis_domain.html.markdown @@ -10,12 +10,25 @@ description: |- # ibm_cis_domain Creates a DNS Domain resource that represents a DNS domain assigned to Cloud Internet Services (CIS). A domain is the basic resource for working with Cloud Internet Services and is typically the first resouce that is assigned to the CIS service instance. The domain will not become `active` until the DNS Registrar is updated with the CIS name servers in the exported variable `name_servers`. Refer to the resource `dns_domain_registration_nameservers`for updating the IBM Cloud DNS Registrars name servers. For more information, about CIS DNS domain, see [setting up your Domain Name System for CIS](https://cloud.ibm.com/docs/cis?topic=cis-set-up-your-dns-for-cis). -## Example usage +## Example usage - 1 (Regular Domain) +```terraform +resource "ibm_cis_domain" "example" { + domain = "example.com" + cis_id = ibm_cis.instance.id +} + +resource "ibm_cis" "instance" { + name = "test-domain" + plan = "standard" +} +``` +## Example usage - 2 (Partial Domain) ```terraform resource "ibm_cis_domain" "example" { domain = "example.com" cis_id = ibm_cis.instance.id + type = "partial" } resource "ibm_cis" "instance" { @@ -30,6 +43,7 @@ Review the argument references that you can specify for your resource. - `cis_id` - (Required, String) The ID of the IBM Cloud Internet Services instance. - `domain` - (Required, String) The DNS domain name that you want to add to your IBM Cloud Internet Services instance. +- `type` - (String) The type of domain to be created. Default value is noted to be `full`- for regular domains, & to create a partial domain for CNAME setup, value to be used is `partial`. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -40,6 +54,9 @@ In addition to all argument reference list, you can access the following attribu - `original_name_servers` - (String) The name servers that were used when the domain was first registered with the DNS Registrar. - `paused`- (Bool) Indicates if the domain is paused and network traffic bypasses your IBM Cloud Internet Services instance. The default values is **false**. - `status` - (String) The status of the domain. Valid values are `active`, `pending`, `initializing`, `moved`, `deleted`, and `deactivated`. After creation, the status remains pending until the DNS Registrar is updated with the CIS name servers, exported in the `name_servers` variable. +- `verification_key` - (String) The verification key of the domain. +- `cname_suffix` - (String) The cname suffix of the domain. + ## Import diff --git a/website/docs/r/cis_domain_settings.html.markdown b/website/docs/r/cis_domain_settings.html.markdown index 4080405aa..94e9d5edf 100644 --- a/website/docs/r/cis_domain_settings.html.markdown +++ b/website/docs/r/cis_domain_settings.html.markdown @@ -11,7 +11,7 @@ description: |- Customize the IBM Cloud Internet Services domain settings. For more information, about Internet Services domain settings, see [adding domains to your CIS instance](https://cloud.ibm.com/docs/cis?topic=cis-multi-domain-support). -## Example usage +## Example usage 1 ```terraform resource "ibm_cis_domain_settings" "test_domain_settings" { @@ -72,6 +72,67 @@ resource "ibm_cis_domain_settings" "test" { } ``` +## Example usage 2 : For TLS v1.3 + +```terraform +resource "ibm_cis_domain_settings" "test_domain_settings" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + dnssec = "disabled" + waf = "off" + ssl = "flexible" + min_tls_version = "1.2" + cname_flattening = "flatten_all" + opportunistic_encryption = "off" + automatic_https_rewrites = "on" + always_use_https = "off" + ipv6 = "off" + browser_check = "off" + hotlink_protection = "off" + http2 = "on" + image_load_optimization = "off" + image_size_optimization = "lossless" + ip_geolocation = "off" + origin_error_page_pass_thru = "off" + brotli = "off" + pseudo_ipv4 = "off" + prefetch_preload = "off" + response_buffering = "off" + script_load_optimization = "off" + server_side_exclude = "off" + tls_client_auth = "off" + true_client_ip_header = "off" + websockets = "off" + challenge_ttl = 31536000 + max_upload = 300 + cipher = [] + minify { + css = "off" + js = "off" + html = "off" + } + security_header { + enabled = false + include_subdomains = false + max_age = 0 + nosniff = false + } + mobile_redirect { + status = "on" + mobile_subdomain = "m.domain.com" + strip_uri = true + } +} + +resource "ibm_cis_domain_settings" "test" { + cis_id = ibm_cis.instance.id + domain_id = ibm_cis_domain.example.id + waf = "on" + ssl = "full" + min_tls_version = "1.3" +} +``` + ## Argument reference Review the argument references that you can specify for your resource. @@ -80,7 +141,7 @@ Review the argument references that you can specify for your resource. - `browser_check` - (Optional, String) Enable a client browser check to look for common HTTP headers that are used by malicious users. If HTTP headers are found, access to your website is blocked. Supported values are `off` and `on`. - `brotli` - (Optional, String) Supported values are `off` and `on`. - `challenge_ttl` - (Optional, String) Challenge TTL values are `300`, `900`, `1800`, `2700`, `3600`, `7200`, `10800`, `14400`, `28800`, `57600`, `86400`, `604800`, `2592000`, and `31536000`. -- `cipher` - (Optional, String) Cipher setting values are `ECDHE-ECDSA-AES128-GCM-SHA256`, `ECDHE-ECDSA-CHACHA20-POLY1305`,`ECDHE-RSA-AES128-GCM-SHA256`, `ECDHE-RSA-CHACHA20-POLY1305`, `ECDHE-ECDSA-AES128-SHA256`, `ECDHE-ECDSA-AES128-SHA`, `ECDHE-RSA-AES128-SHA256`, `ECDHE-RSA-AES128-SHA`, `AES128-GCM-SHA256`, `AES128-SHA256`, `AES128-SHA`, `ECDHE-ECDSA-AES256-GCM-SHA384`, `ECDHE-ECDSA-AES256-SHA384`, `ECDHE-RSA-AES256-GCM-SHA384`, `ECDHE-RSA-AES256-SHA384`, `ECDHE-RSA-AES256-SHA`, `AES256-GCM-SHA384`, `AES256-SHA256`, `AES256-SHA`, `DES-CBC3-SHA`. +- `cipher` - (Optional, List) Cipher setting values are `ECDHE-ECDSA-AES128-GCM-SHA256`, `ECDHE-ECDSA-CHACHA20-POLY1305`,`ECDHE-RSA-AES128-GCM-SHA256`, `ECDHE-RSA-CHACHA20-POLY1305`, `ECDHE-ECDSA-AES128-SHA256`, `ECDHE-ECDSA-AES128-SHA`, `ECDHE-RSA-AES128-SHA256`, `ECDHE-RSA-AES128-SHA`, `AES128-GCM-SHA256`, `AES128-SHA256`, `AES128-SHA`, `ECDHE-ECDSA-AES256-GCM-SHA384`, `ECDHE-ECDSA-AES256-SHA384`, `ECDHE-RSA-AES256-GCM-SHA384`, `ECDHE-RSA-AES256-SHA384`, `ECDHE-RSA-AES256-SHA`, `AES256-GCM-SHA384`, `AES256-SHA256`, `AES256-SHA`, `DES-CBC3-SHA`. To use default cipher value, pass empty list `[]`. - `cis_id` - (Required, String) The ID of the IBM Cloud Internet Services instance. - `cname_flattening` - (Optional, String) Supported values are `flatten_at_root`, `flatten_all`, and `flatten_none`. - `domain_id` - (Required, String) The ID of the domain that you want to customize. @@ -92,7 +153,7 @@ Review the argument references that you can specify for your resource. - `ipv6` - (Optional, String) Supported values are `off` and `on`. - `ip_geolocation` - (Optional, String) Supported values are `off` and `on`. - `max_upload` - (Optional, String) Maximum upload values are `100`, `125`, `150`, `175`, `200`, `225`, `250`, `275`, `300`, `325`, `350`, `375`, `400`, `425`, `450`, `475`, and `500`. -- `min_tls_version` - (Optional, String) The minimum TLS version that you want to allow. Allowed values are `1.1`, `1.2`, or `1.3`. +- `min_tls_version` - (Optional, String) The minimum TLS version that you want to allow. Allowed values are `1.1`, `1.2`, or `1.3`. `Note: When we set min_tls_version as 1.3 we can't customize which ciphers to use. The cipher needs to be set to empty list`. - `minify` (Optional, List) Minify the setting as stated. Nested scheme for `minify`: diff --git a/website/docs/r/cis_filter.html.markdown b/website/docs/r/cis_filter.html.markdown index 943a853bf..b9ae33b6f 100644 --- a/website/docs/r/cis_filter.html.markdown +++ b/website/docs/r/cis_filter.html.markdown @@ -3,14 +3,14 @@ subcategory: "Internet services" layout: "ibm" page_title: "IBM: ibm_cis_filter" description: |- - Provides a IBM CIS Filter. + Provides a IBM Cloud CIS Filter. --- # ibm_cis_filter -Provides a IBM CIS Filter. This resource is associated with an IBM Cloud Internet Services (CIS) instance and a CIS Domain resource. It allows to create, update, delete filter of a domain of a CIS instance. +Provides a IBM CIS Filter. This resource is associated with an IBM Cloud Internet Services (CIS) instance and a CIS Domain resource. It allows to create, update, delete filter of a domain of a CIS instance. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). -## Example Usage +## Example usage ```terraform # Add a filter to the domain @@ -25,9 +25,8 @@ resource "ibm_cis_filter" "test" { ``` -## Argument Reference - -The following arguments are supported: +## Argument reference +Review the argument references that you can specify for your resource. - `cis_id` - (Required, String) The ID of the CIS service instance. - `domain_id` - (Required, String) The ID of the domain to add the Filter. @@ -36,8 +35,7 @@ The following arguments are supported: - `description` - (Optional, String) The information about this filter to help identify the purpose of it. ## Attributes Reference - -In addition to all arguments above, the following attributes are exported: +In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The ID of filter resource. It is a combination of <`filter-id`>:<`domain-id`>:<`crn`> attributes concatenated with ":". - `filter_id` - (String) Unique identifier for the Filter. diff --git a/website/docs/r/cis_firewall_rules.html.markdown b/website/docs/r/cis_firewall_rules.html.markdown index 2350cec20..dab43075f 100644 --- a/website/docs/r/cis_firewall_rules.html.markdown +++ b/website/docs/r/cis_firewall_rules.html.markdown @@ -10,7 +10,7 @@ description: |- # ibm_cis_firewall_rules -Create, update, or delete a firewall rules for a domain that you included in your IBM Cloud Internet Services instance and a CIS domain resource. For more information, about CIS firewall rules resource, see [using fields, functions, and expressions](https://cloud.ibm.com/docs/cis?topic=cis-fields-and-expressions). +Create, update, or delete a firewall rules for a domain that you included in your IBM Cloud Internet Services instance and a CIS domain resource. For more information, about CIS firewall rules resource, see [using fields, functions, and expressions](https://cloud.ibm.com/docs/cis?topic=cis-fields-and-expressions). Note - Deletion of Firewall Rules will result in deletion of the respective Filter too. ## Example usage diff --git a/website/docs/r/cis_logpush_jobs.html.markdown b/website/docs/r/cis_logpush_jobs.html.markdown new file mode 100644 index 000000000..035c8a858 --- /dev/null +++ b/website/docs/r/cis_logpush_jobs.html.markdown @@ -0,0 +1,75 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_logpush_jobs" +description: |- + Get information on an IBM Cloud Internet Services logpush jobs. +--- + +# ibm_cis_logpush_jobs + +Retrieve information about an IBM Cloud Internet Services logpush jobs data sources. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform +resource "ibm_cis_logpush_job" "test" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + name = "MylogpushJob" + enabled = false + logpull_options = "timestamps=rfc3339×tamps=rfc3339" + dataset = "http_requests" + frequency = "low" + logdna =<:<`crn`> attributes concatenated with ":". +- `job_id` - (String) Unique identifier for the each LogpushJob. + + +## Import + +The `ibm_cis_logpus_jobs` resource can be imported using the `id`. The ID is formed from the `Job ID`and the `CRN` (Cloud Resource Name) concatentated usinga `:` character. + +The CRN will be located on the **Overview** page of the Internet Services instance under the **Domain** heading of the UI, or via using the `ibmcloud cis` CLI commands. + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + +- **Job ID** is a 32 digit character string of the form: `52bfa670237f49ecb68473033c569649`. + +**Syntax** + +``` +$ terraform import ibm_cis_logpus_jobs.myorg : +``` + +**Example** + +``` +$ terraform import ibm_cis_logpus_jobs.myorg +crn:v1:bluemix:public:internet-svcs-ci:global:a/01652b251c3ae2787110a995d8db0135:9054ad06-3485-421a-9300-fe3fb4b79e1d:: +``` diff --git a/website/docs/r/cis_mtls.html.markdown b/website/docs/r/cis_mtls.html.markdown new file mode 100644 index 000000000..cd0ec2f90 --- /dev/null +++ b/website/docs/r/cis_mtls.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_mtls" +description: |- + Provides an IBM Mutual TLS(mTLS) resource. +--- + +# ibm_cis_mtls + Provides mutual TLS(mTLS) certificate settings resource. The resource allows to create(upload), update, or delete mTLS certificate settings of a domain of an IBM Cloud Internet Services CIS instance. For more information about mtls, see [CIS MTLS](https://cloud.ibm.com/docs/cis?topic=cis-mtls-features). + +## Example usage +```terraform +# Change mTLS certificate setting of CIS instance + +resource "ibm_cis_mtls" "mtls_settings" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + certificate = EOT<< + "-----BEGIN CERTIFICATE----- + ------END CERTIFICATE------" + EOT + name = "MTLS_Cert" + associated_hostnames = ["abc.abc.abc.com"] +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `cis_id` - (Required, String) The ID of the IBM Cloud Internet Services instance. +- `domain_id` - (Required, String) The ID of the domain to change cache settings. +- `certificate` - (Required, String) Content of valid MTLS certificate. +- `name` - (Required, String) Valid name for certificate. +- `associated_hostnames` - (Required, []String) Valid host names for which we want to add the certificate. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The record ID. It is a combination of `,,` attributes concatenated with `:`. +- `mtls_id` - (Computed, String) mTLS ID. +- `created_at` - (Computed, String) Time stamp string when Certificate is created'. +- `updated_at` - (Computed, String) Time stamp string when Certificate is modified'. +- `expires_on` - (Computed, String) Time stamp string when Cerftificate expires on'. +- `cert_id` - (Computed, String) Created certificate ID. + + + +## Import +The `ibm_cis_mtls` resource can be imported using the ID. The ID is formed from the mTLS ID, domain ID of the domain and the CRN concatenated using a `:` character. + +The domain ID and CRN will be located on the overview page of the IBM Cloud Internet Services instance of the console domain heading, or by using the `ibmcloud cis` command line commands. + +- **MTLS ID** is a string of the form: `fa633cc7-4afc-4875-8814-b321153fee13` + +- **Domain ID** is a 32 digit character string of the form: `9caf68812ae9b3f0377fdf986751a78f` + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + +**Syntax** + +``` +$ terraform import ibm_cis_mtls.mtls_settings :: +``` + +**Example** + +``` +$ terraform import ibm_cis_mtls.mtls_settings fa633cc7-4afc-4875-8814-b321153fee13:9caf68812ae9b3f0377fdf986751a78f:crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:: +``` + diff --git a/website/docs/r/cis_mtls_app.html.markdown b/website/docs/r/cis_mtls_app.html.markdown new file mode 100644 index 000000000..4b0dc15b8 --- /dev/null +++ b/website/docs/r/cis_mtls_app.html.markdown @@ -0,0 +1,77 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_mtls_app" +description: |- + Provides an IBM Mutual TLS app-policy resource. +--- + +# ibm_cis_mtls_app + Provides mutual TLS(mTLS) app-policy settings resource. The resource allows to create, update, or delete mTLS app settings of a domain of an IBM Cloud Internet Services CIS instance. For more information about mtls, see [CIS MTLS](https://cloud.ibm.com/docs/cis?topic=cis-mtls-features). + +## Example usage + +```terraform +# Change mTLS app-policy setting of CIS instance + +resource "ibm_cis_mtls_app" "mtls_app_settings" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + name = "MY_APP" + domain = "abc.abc.com" + session_duration = "24h" + policy_name = "MTLS_Policy" +} +``` + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `cis_id` - (Required, String) The ID of the IBM Cloud Internet Services instance. +- `domain_id` - (Required, String) The ID of the domain to change cache settings. +- `name` - (Required, String) Name for the app which you want to create. +- `domain` - (Required, String) Host domain for which we want to create app. +- `policy_name` - (Optional, String) Valid name for a policy, default name is 'mtls-policy'. +- `session_duration ` - (Optional, String) Duration string, default is '24h'. +- `cert_rule_val` - (Optional, String) Valid value for certificate rule option, default is mTLS certificate name. +- `common_rule_val` - (Optional, String) Valid value for common rule option. +- `policy_decision` - (Optional, String) Valid policy action value e.g. 'non_identity'(default), 'allow', 'deny', 'bypass'. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The record ID. It is a combination of `,,,` attributes concatenated with `:`. +- `app_created_at` - (Computed, String) Time stamp string when App is created. +- `app_updated_at` - (Computed, String) Time stamp string when App is modififed. +- `pol_created_at` - (Computed, String) Time stamp string when Policy is created. +- `pol_updated_at` - (Computed, String) Time stamp string when Policy is modified. +- `app_id` - (Computed, String) ID of created App. +- `policy_id` - (Computed, String) ID of created policy. + +## Import +The `ibm_cis_mtls_app` resource can be imported using the ID. The ID is formed from the app_id, policy_id, domain ID of the domain and the CRN concatenated using a `:` character. + +The domain ID and CRN will be located on the overview page of the IBM Cloud Internet Services instance of the console domain heading, or by using the `ibmcloud cis` command line commands. + +- **APP ID** is a string of the form: `ac633cc7-2afc-4875-9914-c521153fee15` + +- **Policy ID** is a string of the form: `fa633cc7-4afc-4875-8814-b321153fee13` + +- **Domain ID** is a 32 digit character string of the form: `9caf68812ae9b3f0377fdf986751a78f` + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + +**Syntax** + +``` +$ terraform import ibm_cis_mtls_app.mtls_app_settings :: +``` + +**Example** + +``` +$ terraform import ibm_cis_mtls_app.mtls_app_settings ac633cc7-2afc-4875-9914-c521153fee15:fa633cc7-4afc-4875-8814-b321153fee13:9caf68812ae9b3f0377fdf986751a78f:crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:: +``` + diff --git a/website/docs/r/cis_origin_auth.html.markdown b/website/docs/r/cis_origin_auth.html.markdown new file mode 100644 index 000000000..4f951564c --- /dev/null +++ b/website/docs/r/cis_origin_auth.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_origin_auth" +description: |- + Provides an IBM CIS origin auth resource. +--- + +# ibm_cis_origin_auth + Provides origin auth settings resource. The resource allows to create, update, or delete cache settings of a domain of an IBM Cloud Internet Services CIS instance. For more information about CIS origin auth, see [CIS ORIGIN AUTH](https://cloud.ibm.com/docs/cis?topic=cis-cli-plugin-cis-cli#authenticated-origin-pull). + +## Example usage + +```terraform +# Change origin auth setting of CIS instance + +resource "ibm_cis_origin_auth" "orig_auth_settings" { + cis_id = data.ibm_cis.cis.id + domain_id = data.ibm_cis_domain.cis_domain.domain_id + certificate = EOT<< + "-----BEGIN CERTIFICATE------ + ------END CERTIFICATE-------" + EOT + private_key = <,,,` attributes concatenated with `:`. +- `updated_at` - (Computed, String) Time stamp string when Certificate is modified'. +- `expires_on` - (Computed, String) Time stamp string when Cerftificate expires on'. +- `cert_id` - (Computed, String) Uploaded certificate ID. +- `status` - (Computed, String) Origin auth status enbled or not. + + +## Import +The `ibm_cis_origin_auth` resource can be imported using the ID. The ID is formed from auth ID, level, the domain ID of the domain and the CRN concatenated using a `:` character. + +The domain ID and CRN will be located on the overview page of the IBM Cloud Internet Services instance of the console domain heading, or by using the `ibmcloud cis` command line commands. + +- **Auth ID** is a string of the form: `fa633cc7-4afc-4875-8814-b321153fee13` + +- **Level** is a string of the form: `zone` + +- **Domain ID** is a 32 digit character string of the form: `9caf68812ae9b3f0377fdf986751a78f` + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + + +**Syntax** + +``` +$ terraform import ibm_cis_origin_auth.origin_auth_settings ::: +``` + +**Example** + +``` +$ terraform import ibm_cis_origin_auth.origin_auth_settings fa633cc7-4afc-4875-8814-b321153fee13:zone:9caf68812ae9b3f0377fdf986751a78f:crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:: +``` + diff --git a/website/docs/r/cis_page_rule.html.markdown b/website/docs/r/cis_page_rule.html.markdown index 9a6b9f7c4..8dbe2bf55 100644 --- a/website/docs/r/cis_page_rule.html.markdown +++ b/website/docs/r/cis_page_rule.html.markdown @@ -34,6 +34,12 @@ resource "ibm_cis_page_rule" "page_rule" { url = "https://ibm.travis-kuganes1.sdk.cistest-load.com/*" status_code = 302 } + actions { + id = "minify" + html = "off" + css = "on" + js = "off" + } } ``` @@ -44,75 +50,52 @@ Review the argument references that you can specify for your resource. Nested scheme for `actions`: - `id` - (Required, String) The action ID. Valid values are `page rule action field map from console` to `API CF-UI map API`). - - Nested scheme for `id`: - - `always_online` - (String) The action conflicts with all other settings. - - `always_use_https` - (String) The action conflicts with all other settings. - - `automatic_https_rewrites` - (String) The automatic HTTPS rewrites. - - `browser_cache_ttl` - (String) The browser cache TTL. - - `bypass_cache_on_cookie` - (String) The bypass cache on cookie. - - `browser_check` - (String) The browser integrity check. - - `cache_level` - (String) The cache level. - - `cache_on_cookie` - (String) The cache on cookie. - - `cache_deception_armor` - (String) The cache deception armor. - - `disable_security` - (String) The action conflicts with `email_obfuscation`, `server_side_exclude`, `waf`. - - `disable_apps` - (String) The disable apps. - - `disable_performance` - (String) The disable performance. - - `edge_cache_ttl` - (String) The edge cache TTL. - - `email_obfuscation` - (String) The Email obfuscation. - - `explicit_cache_control` - (String) The origin cache control. - - `forwarding_url` - (String) The action conflicts with all other settings. - - `host_header_override` - (String) The host header override. - - `image_load_optimization` - (String) The image load optimization. - - `image_size_optimization` - (String) The image size optimization. - - `ip_geolocation` - (String) The IP geography location header. - - `opportunistic_encryption` - (String) The opportunistic encryption. - - `origin_error_page_pass_thru` - (String) The origin error page pass-through. - - `resolve_override` - (String) The resolve override. - - `response_buffering` - (String) The response buffering. - - `script_load_optimization` - (String) The script load optimization. - - `ssl` - (String) The TLS settings. - - `security_level` - (String) The security level. - - `server_side_exclude` - (String) The server side excludes. - - `server_stale_content` - (String) The server stale content. - - `sort_query_string_for_cache` - (String) The sort query string. - - `true_client_ip_header` - (String) The true client IP header. - - `waf` - (String) The Web Application Firewall. + - `css` - (String) The required attribute for `minify` action. CSS supported values are `on` and `off`. + - `html` - (String) The required attribute for `minify` action. HTML supported values are `on` and `off`. + - `js` - (String) The required attribute for `minify` action. JS supported values are `on` and `off`. - `status_code` - (Optional, String) The status code to check for URL forwarding. The required attribute for `forwarding_url` action. Valid values are `301` and `302`. It returns `0` for all other actions. - `url` - (Optional, String) The forward rule URL, a required attribute for `forwarding_url` action. - `value` - (Required, String) The values for corresponding actions. - - Nested scheme for `value`: - - `always_online` - (String) The valid values are `on`, `off`. - - `automatic_https_rewrites` - (String) The valid values are `on`, `off`. - - `browser_cache_ttl`- (Integer) The valid values are `0, 1800, 3600, 7200, 10800, 14400, 18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 691200, 1382400, 2073600, 2678400, 5356800, 16070400, 31536000`. - - `browser_check` - (String) The valid values are `on`, `off`. - - `bypass_cache_on_cookie` - (String) The valid values are `cookie tags`. - - `cache_deception_armor` - (String) The valid values are `on`, `off`. - - `cache_level` - (String) The valid values are `bypass`, `aggressive`, `basic`, `simplified`, `cache_everything`. - - `cache_on_cookie` - (String) The cookie value. - - `disable_apps` - (String) The value is not required. - - `disable_performance` - (String) The value is not required. - - `edge_cache_ttl` - (String) The valid values are `0, 30, 60, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 28800, 43200, 57600, 72000, 86400, 172800, 259200, 345600, 432000, 518400, 604800, 1209600, 2419200`. - - `email_obfuscation` - (String) The valid values are `on`, `off`. - - `explicit_cache_control` - (String) The valid values are `on`, `off`. - - `host_header_override` - (String) The header value. - - `image_load_optimization` - (String) The valid values are `on`, `off`. - - `image_size_optimization` - (String) The valid values are `on`, `off`. - - `ip_geolocation` - (String) The valid values are `on`, `off`. - - `origin_error_page_pass_thru` - (String) The valid values are `on`, `off`. - - `minify` - (String) This is not supported yet. - - `opportunistic_encryption` - (String) The valid values are `on`, `off`. - - `resolve_override` - (String) The value for resolving URL override. - - `response_buffering` - (String) The valid values are `on`, `off`. - - `script_load_optimization` - (String) The valid values are `off`, `lossless`, `lossy`. - - `security_level` - (String) The valid values are `disable_security`, `always_use_https`. - - `server_side_exclude` - (String) The valid values are `on`, `off`. - - `server_stale_content` - (String) The valid values are `on`, `off`. - - `sort_query_string_for_cache` - (String) The valid values are `on`, `off`. - - `ssl` - (String) The valid values are `off`, `flexible`, `full`, `strict`, `origin_pull`. - - `true_client_ip_header` - (String) The valid values are `on`, `off`. - - `waf` - (String) The valid values are `on`, `off`. + + + ~> **NOTE** + Below table shows corresponding valid values of `id` and `value` of `actions` argument + + | id | description |valid values| + |---------------------------|-----------------------------------------------|------------| + |`always_online` |The action conflicts with all other settings. |`on`, `off`| + |`always_use_https` |The action conflicts with all other settings. |The value is not required.| + |`automatic_https_rewrites` |The automatic HTTPS rewrites. |`on`, `off`| + |`browser_cache_ttl` |The browser cache TTL. |`0`, `1800`, `3600`, `7200`, `10800`, `14400`, `18000`, `28800`, `43200`, `57600`, `72000`, `86400`, `172800`, `259200`, `345600`, `432000`, `691200`, `1382400`, `2073600`, `2678400`, `5356800`, `16070400`, `31536000`| + |`bypass_cache_on_cookie` |The bypass cache on cookie. |cookie tags| + |`browser_check` |The browser integrity check. |`on`, `off`| + |`cache_level` |The cache level. |`bypass`, `aggressive`, `basic`, `simplified`, `cache_everything`| + |`cache_on_cookie` |The cache on cookie. |The cookie value| + |`cache_deception_armor` |The cache deception armor. |`on`, `off`| + |`disable_security` |The action conflicts with `email_obfuscation`, `server_side_exclude`, `waf`.|The value is not required.| + |`disable_apps` |The disable apps. |The value is not required| + |`disable_performance` |The disable performance. |The value is not required.| + |`edge_cache_ttl` |The edge cache TTL. |`0`, `30`, `60`, `300`, `600`, `1200`, `1800`, `3600`, `7200`, `10800`, `14400`, `18000`, `28800`, `43200`, `57600`, `72000`, `86400`, `172800`, `259200`, `345600`, `432000`, `518400`, `604800`, `1209600`, `2419200`| + |`email_obfuscation` |The Email obfuscation. |`on`, `off`| + |`explicit_cache_control` |The origin cache control. |`on`, `off`| + |`forwarding_url` |The action conflicts with all other settings. |The value is not required.| + |`host_header_override` |The host header override. |The header value.| + |`image_load_optimization` |The image load optimization. |`on`, `off`| + |`image_size_optimization` |The image size optimization. |`on`, `off`| + |`ip_geolocation` |The IP geography location header. |`on`, `off`| + |`opportunistic_encryption` |The opportunistic encryption. |`on`, `off`| + |`origin_error_page_pass_thru`|The origin error page pass-through. |`on`, `off`| + |`resolve_override` |The resolve override. |The value for resolving URL override.| + |`response_buffering` |The response buffering. |`on`, `off`| + |`script_load_optimization` |The script load optimization. |`off`, `lossless`, `lossy`| + |`ssl` |The TLS settings. |`off`, `flexible`, `full`, `strict`,`origin_pull`| + |`security_level` |The security level. |`disable_security`, `always_use_https`| + |`server_side_exclude` |The server side excludes. |`on`, `off`| + |`server_stale_content` |The server stale content. |`on`, `off`| + |`sort_query_string_for_cache`|The sort query string. |`on`, `off`| + |`true_client_ip_header` |The true client IP header. |`on`, `off`| + |`waf` |The Web Application Firewall. |`on`, `off`| + |`minify` |The Minify web content |The value is not required| - `cis_id` - (Required, String) The ID of the IBM Cloud Internet Services instance. - `domain_id` - (Required, String) The ID of the IBM Cloud Internet Services domain. - `priority` - (Optional, Integer) The priority of the page rule. Default value is `1`. `Set` and `Update` are not supported yet. diff --git a/website/docs/r/cis_waf_group.html.markdown b/website/docs/r/cis_waf_group.html.markdown index 62cf332b1..810ea714d 100644 --- a/website/docs/r/cis_waf_group.html.markdown +++ b/website/docs/r/cis_waf_group.html.markdown @@ -37,9 +37,11 @@ In addition to all argument reference list, you can access the following attribu - `description` - (String) The WAF rule group description. - `id` - (String) The WAF rule group ID. It is a combination of `:::` attributes concatenated with `:`. -- `modified_rules_count`- (String) Number of rules modified in WAF Group. +- `modified_rules_count`- (Integer) Number of rules modified in WAF Group. - `name` - (String) The WAF rule group name. -- `rules_count` - (String) Number of rules in WAF Group. +- `rules_count` - (Integer) Number of rules in WAF Group. +- `check_mode` - (Boolean) If `true`, then updating the mode with same ON>ON or OFF>OFF value, will be skipped. By default, check_mode attribute is false, and it won't check the backend value before update. + ## Import The `ibm_cis_waf_group` resource can be imported by using the ID. The ID is formed from the WAF Rule Group ID, the WAF rule package ID, the domain ID of the domain and the Cloud Resource Name (CRN) Concatenated by using `:` character. diff --git a/website/docs/r/cis_webhook.html.markdown b/website/docs/r/cis_webhook.html.markdown new file mode 100644 index 000000000..1b779513c --- /dev/null +++ b/website/docs/r/cis_webhook.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "Internet services" +layout: "ibm" +page_title: "IBM: ibm_cis_webhook" +description: |- + Provides a IBM Cloud CIS Webhook. +--- + +# ibm_cis_webhook + +Provides a IBM CIS Webhook. This resource is associated with an IBM Cloud Internet Services (CIS) instance and a CIS Domain resource. It allows to create, update, delete webhook of a CIS instance. For more information, see [IBM Cloud Internet Services](https://cloud.ibm.com/docs/cis?topic=cis-about-ibm-cloud-internet-services-cis). + +## Example usage + +```terraform + +resource "ibm_cis_webhook" "test" { + cis_id = data.ibm_cis.cis.id + name = "My Slack Alert Webhook", + url ="https://hooks.slack.com/services/Ds3fdBFbV/456464Gdd", + secret = "ff1d9b80-b51d-4a06-bf67-6752fae1eb74" +} + +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `cis_id` - (Required, String) The ID of the CIS service instance. +- `name` - (Required, String) Name of the Webhook. +- `secret` - (Optional, String) This is Sensitive and optional secret or API key needed to use the webhook. +- `url` - (Required, string) Webhook Url. + +## Attributes Reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The ID of webhook resource. It is a combination of <`webhook-id`>:<`crn`> attributes concatenated with ":". +- `webhook_id` - (String) Unique identifier for the Webhook. + +## Import + +The `ibm_cis_webhook` resource can be imported using the `id`. The ID is formed from the `Webhook ID`and the `CRN` (Cloud Resource Name) concatentated usinga `:` character. + +The CRN will be located on the **Overview** page of the Internet Services instance under the **Domain** heading of the UI, or via using the `ibmcloud cis` CLI commands. + +- **CRN** is a 120 digit character string of the form: `crn:v1:bluemix:public:internet-svcs:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3::` + +- **Webhook ID** is a 32 digit character string of the form: `d72c91492cc24d8286fb713d406abe91`. + +**Syntax** + +``` +$ terraform import ibm_cis_webhook.myorg : +``` + +**Example** + +``` +$ terraform import ibm_cis_webhook.myorg +crn:v1:bluemix:public:internet-svcs-ci:global:a/01652b251c3ae2787110a995d8db0135:9054ad06-3485-421a-9300-fe3fb4b79e1d:: +``` \ No newline at end of file diff --git a/website/docs/r/cloud_shell_account_settings.html.markdown b/website/docs/r/cloud_shell_account_settings.html.markdown index 43bd4056d..e31b267b5 100644 --- a/website/docs/r/cloud_shell_account_settings.html.markdown +++ b/website/docs/r/cloud_shell_account_settings.html.markdown @@ -6,13 +6,13 @@ description: |- subcategory: "IBM Cloud Shell" --- -# ibm\_cloud_shell_account_settings +# ibm_cloud_shell_account_settings Provides a resource for cloud_shell_account_settings. This allows cloud_shell_account_settings to be updated. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_cloud_shell_account_settings" "cloud_shell_account_settings" { account_id = "12345678-abcd-1a2b-a1b2-1234567890ab" rev = "130-1bc9ec83d7b9b049890c6d4b74dddb2a" @@ -42,7 +42,7 @@ resource "ibm_cloud_shell_account_settings" "cloud_shell_account_settings" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: @@ -56,9 +56,9 @@ The following arguments are supported: * `regions` - (Optional, List) List of Cloud Shell region settings. * `enabled` - (Optional, bool) State of the region. * `key` - (Optional, string) Name of the region. -* `rev` - (Optional, string) Unique revision number for the settings object. +* `rev` - (Required, string) Unique revision number for the settings object. Required it this field is available from the data source. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: diff --git a/website/docs/r/cloudant.html.markdown b/website/docs/r/cloudant.html.markdown index df63fa6de..07ea62df4 100644 --- a/website/docs/r/cloudant.html.markdown +++ b/website/docs/r/cloudant.html.markdown @@ -3,7 +3,7 @@ layout: "ibm" page_title: "IBM : ibm_cloudant" description: |- Manages Cloudant instance. -subcategory: "Cloud Databases" +subcategory: "Cloudant Databases" --- # ibm_cloudant diff --git a/website/docs/r/cloudant_database.html.markdown b/website/docs/r/cloudant_database.html.markdown new file mode 100644 index 000000000..81d15ef8b --- /dev/null +++ b/website/docs/r/cloudant_database.html.markdown @@ -0,0 +1,52 @@ +--- +layout: "ibm" +page_title: "IBM : cloudant_database" +description: |- + Manages cloudant_database. +subcategory: "Cloudant Databases" +--- + +# ibm\_cloudant_database + +Provides a resource for cloudant_database. This allows cloudant_database to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_cloudant_database" "cloudant_database" { + instance_crn = var.instance_crn + db = var.db_name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `db` - (Required, Forces new resource, string) Path parameter to specify the database name. +* `instance_crn` - (Required, string) Path parameter to specify the cloudant instance CRN. +* `partitioned` - (Optional, Forces new resource, bool) Query parameter to specify whether to enable database partitions when creating a database. + * Constraints: The default value is `false`. +* `shards` - (Optional, Forces new resource, int) The number of shards in the database. Each shard is a partition of the hash value range. Default set by server. + * Constraints: The minimum value is `1`. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique identifier of the cloudant_database. + +## Import + +You can import the `cloudant_database` resource by using `ID`. +The `ID` property can be formed from `instance_crn`, and `db` in the following format: + +``` +/ +``` +* `db`: A string. Path parameter to specify the database name. +* `instance_crn`: A string. Path parameter to specify the cloudant instance CRN. + +``` +$ terraform import ibm_cloudant_database.cloudant_database / +``` diff --git a/website/docs/r/cm_catalog.html.markdown b/website/docs/r/cm_catalog.html.markdown index 8c6c6e3d4..92a880d7f 100644 --- a/website/docs/r/cm_catalog.html.markdown +++ b/website/docs/r/cm_catalog.html.markdown @@ -1,39 +1,114 @@ --- -subcategory: "Catalog Management" layout: "ibm" -page_title: "IBM : cm_catalog" +page_title: "IBM : ibm_cm_catalog" description: |- Manages cm_catalog. +subcategory: "Catalog Management API" --- # ibm_cm_catalog -Create, modify, or delete an `cm_catalog` resources. You can manage the settings for all catalogs across your account. For more information, about managing catalog, refer to [catalog management settings](https://cloud.ibm.com/docs/account?topic=account-account-getting-started). +Provides a resource for cm_catalog. This allows cm_catalog to be created, updated and deleted. +## Example Usage -## Example usage - -```terraform +```hcl resource "ibm_cm_catalog" "cm_catalog" { - label = "placeholder" - short_description = "placeholder" + label = "catalog_label" + short_description = "catalog description" + catalog_icon_url = "icon url" + kind = "offering" + tags = ["catalog", "tags"] } ``` +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `catalog_icon_url` - (Optional, String) URL for an icon associated with this catalog. +* `disabled` - (Optional, Boolean) Denotes whether a catalog is disabled. +* `kind` - (Optional, String) Kind of catalog. Supported kinds are offering and vpe. +* `label` - (Optional, String) Display Name in the requested language. +* `resource_group_id` - (Optional, String) Resource group id the catalog is owned by. +* `short_description` - (Optional, String) Description in the requested language. +* `tags` - (Optional, List) List of tags associated with this catalog. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cm_catalog. +* `catalog_icon_url` - (String) The url of the catalog icon. +* `created` - (String) The date-time this catalog was created. +* `crn` - (String) CRN associated with the catalog. +* `disabled` - (Boolean) Denotes whether a catalog is disabled. +* `label` - (String) Label of the catalog +* `kind` - (String) Kind of catalog. +* `offerings_url` - (String) URL path to offerings. +* `owning_account` - (String) The account ID of the owning account. +* `resource_group_id` - (String) Resource group id the catalog is owned by. +* `rev` - (String) Cloudant revision. +* `short_description` - (String) Description in the requested language. +* `tags` - (List) List of tags associated with this catalog. +* `updated` - (String) The date-time this catalog was last updated. +* `url` - (String) The url for this specific catalog. + +## Provider Configuration -## Argument reference -Review the argument reference that you can specify for your resource. +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: -- `label` - (Required, Forces new resource, String) The display name in the requested language. -- `kind` - (Optional, Forces new resource, Defaults to offering, String) The kind of the catalog, offering or vpe. -- `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group this catalog will be provisioned in -- `short_description` - (Optional, Forces new resource, String) The short description in the requested language. +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` +### Environment variables -## Attribute reference -In addition to all argument references list, you can access the following attribute references after your resource is created. +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. -- `crn` - (String) The CRN associated with the catalog. -- `id` - (String) The unique identifier of the `cm_catalog`. -- `offerings_url` - (String) The URL path to the offerings. -- `url` - (String) The URL for this specific catalog. +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cm_catalog` resource by using `id`. Unique ID. + +# Syntax +``` +$ terraform import ibm_cm_catalog.cm_catalog +``` diff --git a/website/docs/r/cm_offering.html.markdown b/website/docs/r/cm_offering.html.markdown index ea46b8e11..0b73251dc 100644 --- a/website/docs/r/cm_offering.html.markdown +++ b/website/docs/r/cm_offering.html.markdown @@ -1,55 +1,574 @@ --- -subcategory: "Catalog Management" layout: "ibm" -page_title: "IBM : cm_offering" +page_title: "IBM : ibm_cm_offering" description: |- Manages cm_offering. +subcategory: "Catalog Management API" --- # ibm_cm_offering -Create, modify, or delete an `cm_offering` resources. You can manage the settings for all catalogs across your account. For more information, about managing catalog, refer to [catalog management settings](https://cloud.ibm.com/docs/account?topic=account-account-getting-started). +Provides a resource for cm_offering. This allows cm_offering to be created, updated and deleted. +## Example Usage -## Example usage - -```terraform +```hcl resource "ibm_cm_offering" "cm_offering" { - catalog_id = "catalog_id" - label = "placeholder" - tags = [ "placeholder" ] + catalog_identifier = ibm_cm_catalog.cm_catalog.id + label = "offering label" + name = "offering name" + offering_icon_url = "icon_url" + tags = [ "tag1", "tag2" ] } ``` +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `catalog_identifier` - (Required, Forces new resource, String) Catalog identifier. +* `hidden` - (Optional, Boolean) Determine if this offering should be displayed in the Consumption UI. +* `label` - (Optional, String) Display Name in the requested language. +* `long_description` - (Optional, String) Long description in the requested language. +* `name` - (Optional, String) The programmatic name of this offering. +* `offering_icon_url` - (Optional, String) URL for an icon associated with this offering. +* `product_kind` - (Optional, String) The kind of the product. Valid values are "solution" and "software" +* `short_description` - (Optional, String) Short description in the requested language. +* `tags` - (Optional, List) List of tags associated with this catalog. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cm_offering. +* `badges` - (List) A list of badges for this offering. +Nested scheme for **badges**: + * `authority` - (String) Authority for the current badge. + * `constraints` - (List) An optional set of constraints indicating which versions in an Offering have this particular badge. + Nested scheme for **constraints**: + * `rule` - (Map) Rule for the current constraint. + * `type` - (String) Type of the current constraint. + * `description` - (String) Description of the current badge. + * `icon` - (String) Icon for the current badge. + * `id` - (String) ID of the current badge. + * `label` - (String) Display name for the current badge. + * `learn_more_links` - (List) Learn more links for a badge. + Nested scheme for **learn_more_links**: + * `first_party` - (String) First party link. + * `third_party` - (String) Third party link. + * `tag` - (String) Tag for the current badge. + +* `catalog_id` - (String) The id of the catalog containing this offering. + +* `catalog_name` - (String) The name of the catalog. + +* `created` - (String) The date and time this catalog was created. + +* `crn` - (String) The crn for this specific offering. + +* `deprecate_pending` - (List) Deprecation information for an Offering. +Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) + +* `disclaimer` - (String) A disclaimer for this offering. + +* `features` - (List) list of features associated with this offering. +Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + +* `hidden` - (Boolean) Determine if this offering should be displayed in the Consumption UI. + +* `ibm_publish_approved` - (Deprecated, Boolean) Indicates if this offering has been approved for use by all IBMers. + +* `image_pull_keys` - (List) Image pull keys for this offering. +Nested scheme for **image_pull_keys**: + * `description` - (String) Key description. + * `name` - (String) Key name. + * `value` - (String) Key value. + +* `keywords` - (List) List of keywords associated with offering, typically used to search for it. + +* `kinds` - (List) Array of kind. +Nested scheme for **kinds**: + * `additional_features` - (List) List of features associated with this offering. + Nested scheme for **additional_features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `created` - (String) The date and time this catalog was created. + * `format_kind` - (String) content kind, e.g., helm, vm image. + * `id` - (String) Unique ID. + * `install_kind` - (String) install kind, e.g., helm, operator, terraform. + * `metadata` - (Map) Open ended metadata information. + * `plans` - (List) list of plans. + Nested scheme for **plans**: + * `additional_features` - (List) list of features associated with this offering. + Nested scheme for **additional_features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `created` - (String) the date'time this catalog was created. + * `deployments` - (List) list of deployments. + Nested scheme for **deployments**: + * `created` - (String) the date'time this catalog was created. + * `id` - (String) unique id. + * `label` - (String) Display Name in the requested language. + * `long_description` - (String) Long description in the requested language. + * `metadata` - (Map) open ended metadata information. + * `name` - (String) The programmatic name of this offering. + * `short_description` - (String) Short description in the requested language. + * `tags` - (List) list of tags associated with this catalog. + * `updated` - (String) the date'time this catalog was last updated. + * `id` - (String) unique id. + * `label` - (String) Display Name in the requested language. + * `long_description` - (String) Long description in the requested language. + * `metadata` - (Map) open ended metadata information. + * `name` - (String) The programmatic name of this offering. + * `short_description` - (String) Short description in the requested language. + * `tags` - (List) list of tags associated with this catalog. + * `updated` - (String) the date'time this catalog was last updated. + * `tags` - (List) List of tags associated with this catalog. + * `target_kind` - (String) target cloud to install, e.g., iks, open_shift_iks. + * `updated` - (String) The date and time this catalog was last updated. + * `versions` - (List) list of versions. + Nested scheme for **versions**: + * `catalog_id` - (String) Catalog ID. + * `configuration` - (List) List of user solicited overrides. + Nested scheme for **configuration**: + * `custom_config` - (List) Render type. + Nested scheme for **custom_config**: + * `associations` - (List) List of parameters that are associated with this configuration. + Nested scheme for **associations**: + * `parameters` - (List) Parameters for this association. + Nested scheme for **parameters**: + * `name` - (String) Name of this parameter. + * `options_refresh` - (Boolean) Refresh options. + * `config_constraints` - (Map) Map of constraint parameters that will be passed to the custom widget. + * `grouping` - (String) Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment). + * `grouping_index` - (Integer) Determines the order that this configuration item shows in that particular grouping. + * `original_grouping` - (String) Original grouping type for this configuration (3 types - Target, Resource, and Deployment). + * `type` - (String) ID of the widget type. + * `default_value` - (Map) The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`. + * `description` - (String) Key description. + * `display_name` - (String) Display name for configuration type. + * `hidden` - (Boolean) Hide values. + * `key` - (String) Configuration key. + * `options` - (List) List of options of type. + * `required` - (Boolean) Is key required to install. + * `type` - (String) Value type (string, boolean, int). + * `type_metadata` - (String) The original type, as found in the source being onboarded. + * `value_constraint` - (String) Constraint associated with value, e.g., for string type - regx:[a-z]. + * `created` - (String) The date and time this version was created. + * `crn` - (String) Version's CRN. + * `deprecate_pending` - (List) Deprecation information for an Offering. + Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) + * `deprecated` - (Boolean) read only field, indicating if this version is deprecated. + * `entitlement` - (List) Entitlement license info. + Nested scheme for **entitlement**: + * `image_repo_name` - (String) Image repository name. + * `part_numbers` - (List) list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL. + * `product_id` - (String) Product ID. + * `provider_id` - (String) Provider ID. + * `provider_name` - (String) Provider name. + * `flavor` - (List) Version Flavor Information. Only supported for Product kind Solution. + Nested scheme for **flavor**: + * `index` - (Integer) Order that this flavor should appear when listed for a single version. + * `label` - (String) Label for this flavor. + * `label_i18n` - (Map) A map of translated strings, by language code. + * `name` - (String) Programmatic name for this flavor. + * `iam_permissions` - (List) List of IAM permissions that are required to consume this version. + Nested scheme for **iam_permissions**: + * `resources` - (List) Resources for this permission. + Nested scheme for **resources**: + * `description` - (String) Resource description. + * `name` - (String) Resource name. + * `role_crns` - (List) Role CRNs for this permission. + * `role_crns` - (List) Role CRNs for this permission. + * `service_name` - (String) Service name. + * `id` - (String) Unique ID. + * `image_manifest_url` - (String) If set, denotes a url to a YAML file with list of container images used by this version. + * `image_pull_key_name` - (String) ID of the image pull key to use from Offering.ImagePullKeys. + * `install` - (List) Script information. + Nested scheme for **install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + * `is_consumable` - (Boolean) Is the version able to be shared. + * `kind_id` - (String) Kind ID. + * `licenses` - (List) List of licenses the product was built with. + Nested scheme for **licenses**: + * `description` - (String) License description. + * `id` - (String) License ID. + * `name` - (String) license name. + * `type` - (String) type of license e.g., Apache xxx. + * `url` - (String) URL for the license text. + * `long_description` - (String) Long description for version. + * `long_description_i18n` - (Map) A map of translated strings, by language code. + * `metadata` - (Map) Open ended metadata information. + * `offering_id` - (String) Offering ID. + * `outputs` - (List) List of output values for this version. + Nested scheme for **outputs**: + * `description` - (String) Output description. + * `key` - (String) Output key. + * `package_version` - (String) Version of the package used to create this version. + * `pre_install` - (List) Optional pre-install instructions. + Nested scheme for **pre_install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. + * `repo_url` - (String) Content's repo URL. + * `required_resources` - (List) Resource requirments for installation. + Nested scheme for **required_resources**: + * `type` - (String) Type of requirement. + * Constraints: Allowable values are: `mem`, `disk`, `cores`, `targetVersion`, `nodes`. + * `value` - (Map) mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value. + * `rev` - (String) Cloudant revision. + * `sha` - (String) hash of the content. + * `single_instance` - (Boolean) Denotes if single instance can be deployed to a given cluster. + * `solution_info` - (List) Version Solution Information. Only supported for Product kind Solution. + Nested scheme for **solution_info**: + * `architecture_diagrams` - (List) Architecture diagrams for this solution. + Nested scheme for **architecture_diagrams**: + * `description` - (String) Description of this diagram. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `diagram` - (List) Offering Media information. + Nested scheme for **diagram**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + * `cost_estimate` - (List) Cost estimate definition. + Nested scheme for **cost_estimate**: + * `currency` - (String) Cost estimate currency. + * `diff_total_hourly_cost` - (String) Difference in total hourly cost. + * `diff_total_monthly_cost` - (String) Difference in total monthly cost. + * `past_total_hourly_cost` - (String) Past total hourly cost. + * `past_total_monthly_cost` - (String) Past total monthly cost. + * `projects` - (List) Cost estimate projects. + Nested scheme for **projects**: + * `breakdown` - (List) Cost breakdown definition. + Nested scheme for **breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `diff` - (List) Cost breakdown definition. + Nested scheme for **diff**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `metadata` - (Map) Project metadata. + * `name` - (String) Project name. + * `past_breakdown` - (List) Cost breakdown definition. + Nested scheme for **past_breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `time_generated` - (String) When this estimate was generated. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_cost` - (String) Total monthly cost. + * `version` - (String) Cost estimate version. + * `dependencies` - (List) Dependencies for this solution. + Nested scheme for **dependencies**: + * `catalog_id` - (String) Optional - If not specified, assumes the Public Catalog. + * `flavors` - (List) Optional - List of dependent flavors in the specified range. + * `id` - (String) Optional - Offering ID - not required if name is set. + * `name` - (String) Optional - Programmatic Offering name. + * `version` - (String) Required - Semver value or range. + * `features` - (List) Features - titles only. + Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. + * `source_url` - (String) Content's source URL (e.g git repo). + * `state` - (List) Offering state. + Nested scheme for **state**: + * `current` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `current_entered` - (String) Date and time of current request. + * `pending` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `pending_requested` - (String) Date and time of pending request. + * `previous` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `tags` - (List) List of tags associated with this catalog. + * `tgz_url` - (String) File used to on-board this version. + * `updated` - (String) The date and time this version was last updated. + * `validation` - (List) Validation response. + Nested scheme for **validation**: + * `last_operation` - (String) Last operation (e.g. submit_deployment, generate_installer, install_offering. + * `message` - (String) Any message needing to be conveyed as part of the validation job. + * `requested` - (String) Date and time of last validation was requested. + * `state` - (String) Current validation state - , in_progress, valid, invalid, expired. + * `target` - (Map) Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type. + * `validated` - (String) Date and time of last successful validation. + * `version` - (String) Version of content type. + * `version_locator` - (String) A dotted value of `catalogID`.`versionID`. + * `whitelisted_accounts` - (List) Whitelisted accounts for version. + +* `label` - (String) Display Name in the requested language. + +* `label_i18n` - (Map) A map of translated strings, by language code. + +* `long_description` - (String) Long description in the requested language. + +* `long_description_i18n` - (Map) A map of translated strings, by language code. + +* `media` - (List) A list of media items related to this offering. +Nested scheme for **media**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + +* `metadata` - (Map) Map of metadata values for this offering. + +* `name` - (String) The programmatic name of this offering. + +* `offering_docs_url` - (String) URL for an additional docs with this offering. + +* `offering_icon_url` - (String) URL for an icon associated with this offering. + +* `offering_support_url` - (String) [deprecated] - Use offering.support instead. URL to be displayed in the Consumption UI for getting support on this offering. + +* `pc_managed` - (Boolean) Offering is managed by Partner Center. + +* `permit_request_ibm_public_publish` - (Deprecated, Boolean) Is it permitted to request publishing to IBM or Public. + +* `portal_approval_record` - (String) The portal's approval record ID. + +* `portal_ui_url` - (String) The portal UI URL. + +* `product_kind` - (String) The product kind. Valid values are module, solution, or empty string. + +* `provider` - (Deprecated, String) Deprecated - Provider of this offering. + +* `provider_info` - (List) Information on the provider for this offering, or omitted if no provider information is given. +Nested scheme for **provider_info**: + * `id` - (String) The id of this provider. + * `name` - (String) The name of this provider. + +* `public_original_crn` - (String) The original offering CRN that this publish entry came from. + +* `public_publish_approved` - (Deprecated, Boolean) Indicates if this offering has been approved for use by all IBM Cloud users. + +* `publish_approved` - (Boolean) Offering has been approved to publish to permitted to IBM or Public Catalog. + +* `publish_public_crn` - (String) The crn of the public catalog entry of this offering. + +* `rating` - (List) Repository info for offerings. +Nested scheme for **rating**: + * `four_star_count` - (Integer) Four start rating. + * `one_star_count` - (Integer) One start rating. + * `three_star_count` - (Integer) Three start rating. + * `two_star_count` - (Integer) Two start rating. -## Argument reference -Review the argument reference that you can specify for your resource. - -- `catalog_identifier` - (Required, Forces new resrouce, String) Catalog identifier. -- `label` - (Optional, Forces new resrouce, String) Display the name in the requested language. -- `tags` - (Optional, Forces new resrouce, List) The list of tags associated with the catalog. - -## Attribute reference -In addition to all argument references list, you can access the following attribute references after your resource is created. - -- `catalog_id` - (String) The ID of the catalog containing this offering. -- `catalog_name` - (String) The name of the catalog. -- `crn` - (String) The CRN for the specific offering. -- `disclaimer` - (String) A disclaimer for the offering. -- `ibm_publish_approved` - (String) Indicates if the offering has been approved for use by all IBMers. -- `id` - (String) The unique identifier of the `cm_offering`. -- `long_description` - (String) The long description in the requested language. -- `name` - (String) The programmatic name of the offering. -- `permit_request_ibm_public_publish` - (String) Is it permitted to request publishing to IBM or public. -- `public_publish_approved` - (String) Indicates if the offering has been approved for use by all IBM Cloud users. -- `public_original_crn` - (String) The original offering CRN has published. -- `publish_public_crn` - (String) The CRN of the public catalog entry of an offering. -- `portal_approval_record` - (String) The portal's approval record ID. -- `portal_ui_url` - (String) The portal console URL. -- `repo_info` - (String) Repository information for an offerings. - - Nested scheme for `repo_info`: - - `token` - (String) Token for the private repository. - - `type` - (String) The public or enterprise GitHub. -- `short_description` - (String) The short description in the requested language. -- `url` - (String) The URL for the specific offering. +* `repo_info` - (List) Repository info for offerings. +Nested scheme for **repo_info**: + * `token` - (String) Token for private repos. + * `type` - (String) Public or enterprise GitHub. + +* `rev` - (String) Cloudant revision. + +* `share_enabled` - (Boolean) Denotes sharing including access list availability of an Offering is enabled. + +* `share_with_all` - (Boolean) Denotes public availability of an Offering - if share_enabled is true. + +* `share_with_ibm` - (Boolean) Denotes IBM employee availability of an Offering - if share_enabled is true. + +* `short_description` - (String) Short description in the requested language. + +* `short_description_i18n` - (Map) A map of translated strings, by language code. + +* `support` - (List) Offering Support information. +Nested scheme for **support**: + * `locations` - (List) A list of country codes indicating where support is provided. + * `process` - (String) Support process as provided by an ISV. + * `process_i18n` - (Map) A map of translated strings, by language code. + * `support_details` - (List) A list of support options (e.g. email, phone, slack, other). + Nested scheme for **support_details**: + * `availability` - (List) Times when support is available. + Nested scheme for **availability**: + * `always_available` - (Boolean) Is this support always available. + * `times` - (List) A list of support times. + Nested scheme for **times**: + * `day` - (Integer) The day of the week, represented as an integer. + * `end_time` - (String) HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00). + * `start_time` - (String) HOURS:MINUTES:SECONDS using 24 hour time (e.g. 8:15:00). + * `timezone` - (String) Timezone (e.g. America/New_York). + * `contact` - (String) Contact for the current support detail. + * `response_wait_time` - (List) Time descriptor. + Nested scheme for **response_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `type` - (String) Type of the current support detail. + * `support_escalation` - (List) Support escalation policy. + Nested scheme for **support_escalation**: + * `contact` - (String) Escalation contact. + * `escalation_wait_time` - (List) Time descriptor. + Nested scheme for **escalation_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `response_wait_time` - (List) Time descriptor. + Nested scheme for **response_wait_time**: + * `type` - (String) Valid values are hour or day. + * `value` - (Integer) Amount of time to wait in unit 'type'. + * `support_type` - (String) Support type for this product. + * `url` - (String) URL to be displayed in the Consumption UI for getting support on this offering. + +* `tags` - (List) List of tags associated with this catalog. + +* `updated` - (String) The date and time this catalog was last updated. + +* `url` - (String) The url for this specific offering. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cm_offering` resource by using `id`. +The `id` property can be formed from `catalog_identifier`, and `offering_id` in the following format: + +``` +/ +``` +* `catalog_identifier`: A string. Catalog identifier. +* `offering_id`: A string. Offering identification. + +# Syntax +``` +$ terraform import ibm_cm_offering.cm_offering / +``` diff --git a/website/docs/r/cm_version.html.markdown b/website/docs/r/cm_version.html.markdown index a90d603d6..b474839e1 100644 --- a/website/docs/r/cm_version.html.markdown +++ b/website/docs/r/cm_version.html.markdown @@ -1,49 +1,448 @@ --- -subcategory: "Catalog Management" layout: "ibm" -page_title: "IBM : cm_version" +page_title: "IBM : ibm_cm_version" description: |- Manages cm_version. +subcategory: "Catalog Management API" --- # ibm_cm_version -Create, modify, or delete an `cm_version` resources. For more information, about managing catalog version, refer to [updating your software](https://cloud.ibm.com/docs/account?topic=account-update-private). +Provides a resource for cm_version. This allows cm_version to be created, updated and deleted. +## Example Usage -## Example usage +### VSI Image +```hcl +resource "ibm_cm_version" "cm_version" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + name = ibm_cm_offering.cm_offering.name + label = ibm_cm_offering.cm_offering.label + tags = ["virtualservers"] + target_kinds = [ "vpc-x86" ] + install_kind = "instance" + import_sha = "sha" + target_version = "1.0.0" -```terraform -resource "cm_version" "cm_version" { - catalog_identifier = "catalog_identifier" - offering_id = "offering_id" - zipurl = "placeholder" + import_metadata { + operating_system { + dedicated_host_only = true + vendor = "vendor" + name = "name" + href = "href" + display_name = "display_name" + family = "family" + version = "version" + architecture = "architecture" + } + file { + size = 1 + } + minimum_provisioned_size = 1 + images { + id = "id" + name = "name" + region = "region" + } + } } ``` +### Standard Terraform Version +```hcl +resource "ibm_cm_version" "cm_version" { + catalog_identifier = ibm_cm_catalog.cm_catalog.id + offering_identifier = ibm_cm_offering.cm_offering.offering_id + target_version = "1.0.0" + zipurl = "tgz_url Ex: https://github.com/IBM-Cloud/terraform-sample/archive/refs/tags/v1.1.0.tar.gz" + include_config = true + flavor { + name = "name" + label = "label" + index = 1 + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `catalog_identifier` - (Required, Forces new resource, String) Catalog identifier. +* `flavor` - (Optional, Forces new resource, List) Version Flavor Information. Only supported for Product kind Solution. +Nested scheme for **flavor**: + * `index` - (Optional, Integer) Order that this flavor should appear when listed for a single version. + * `label` - (Optional, String) Label for this flavor. + * `label_i18n` - (Optional, Map) A map of translated strings, by language code. + * `name` - (Optional, String) Programmatic name for this flavor. +* `format_kind` - (Optional, Forces new resource, String) Format of content being onboarded. Example: vsi-image. Required for virtual server image for VPC. +* `include_config` - (Optional, Forces new resource, Boolean) Add all possible configuration values to this version when importing. +* `install_kind` - (Optional, Forces new resource, String) Install type. Example: instance. Required for virtual server image for VPC. +* `is_vsi` - (Optional, Forces new resource, Boolean) Indicates that the current terraform template is used to install a virtual server image. +* `label` - (Optional, Forces new resource, String) Display name of version. Required for virtual server image for VPC. +* `import_metadata` - (Optional, Forces new resource, List) Generic data to be included with content being onboarded. Required for virtual server image for VPC. +Nested scheme for **metadata**: + * `file` - (Optional, List) Details for the stored image file. Required for virtual server image for VPC. + Nested scheme for **file**: + * `size` - (Optional, Integer) Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC. + * `images` - (Optional, List) Image operating system. Required for virtual server image for VPC. + Nested scheme for **images**: + * `id` - (Optional, String) Programmatic ID of virtual server image. Required for virtual server image for VPC. + * `name` - (Optional, String) Programmatic name of virtual server image. Required for virtual server image for VPC. + * `region` - (Optional, String) Region the virtual server image is available in. Required for virtual server image for VPC. + * `minimum_provisioned_size` - (Optional, Integer) Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC. + * `operating_system` - (Optional, List) Operating system included in this image. Required for virtual server image for VPC. + Nested scheme for **operating_system**: + * `architecture` - (Optional, String) Operating system architecture. Required for virtual server image for VPC. + * `dedicated_host_only` - (Optional, Boolean) Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC. + * `display_name` - (Optional, String) Unique, display-friendly name for the operating system. Required for virtual server image for VPC. + * `family` - (Optional, String) Software family for this operating system. Required for virtual server image for VPC. + * `href` - (Optional, String) URL for this operating system. Required for virtual server image for VPC. + * `name` - (Optional, String) Globally unique name for this operating system Required for virtual server image for VPC. + * `vendor` - (Optional, String) Vendor of the operating system. Required for virtual server image for VPC. + * `version` - (Optional, String) Major release version of this operating system. Required for virtual server image for VPC. +* `name` - (Optional, Forces new resource, String) Name of version. Required for virtual server image for VPC. +* `offering_identifier` - (Required, Forces new resource, String) Offering identification. +* `product_kind` - (Optional, Forces new resource, String) Optional product kind for the software being onboarded. Valid values are software, module, or solution. Default value is software. +* `sha` - (Optional, Forces new resource, String) SHA256 fingerprint of the image file. Required for virtual server image for VPC. +* `tags` - (Optional, Forces new resource, List) Tags array. +* `target_kinds` - (Optional, Forces new resource, List) Deployment target of the content being onboarded. Current valid values are iks, roks, vcenter, power-iaas, terraform, and vpc-x86. Required for virtual server image for VPC. +* `target_version` - (Optional, Forces new resource, String) The semver value for this new version, if not found in the zip url package content. +* `working_directory` - (Optional, Forces new resource, String) Optional - The sub-folder within the specified tgz file that contains the software being onboarded. +* `zipurl` - (Optional, Forces new resource, String) URL path to zip location. If not specified, must provide content in the body of this call. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the cm_version. +* `catalog_id` - (String) Catalog ID. +* `configuration` - (List) List of user solicited overrides. +Nested scheme for **configuration**: + * `custom_config` - (List) Render type. + Nested scheme for **custom_config**: + * `associations` - (List) List of parameters that are associated with this configuration. + Nested scheme for **associations**: + * `parameters` - (List) Parameters for this association. + Nested scheme for **parameters**: + * `name` - (String) Name of this parameter. + * `options_refresh` - (Boolean) Refresh options. + * `config_constraints` - (Map) Map of constraint parameters that will be passed to the custom widget. + * `grouping` - (String) Determines where this configuration type is rendered (3 sections today - Target, Resource, and Deployment). + * `grouping_index` - (Integer) Determines the order that this configuration item shows in that particular grouping. + * `original_grouping` - (String) Original grouping type for this configuration (3 types - Target, Resource, and Deployment). + * `type` - (String) ID of the widget type. + * `default_value` - (Map) The default value. To use a secret when the type is password, specify a JSON encoded value of $ref:#/components/schemas/SecretInstance, prefixed with `cmsm_v1:`. + * `description` - (String) Key description. + * `display_name` - (String) Display name for configuration type. + * `hidden` - (Boolean) Hide values. + * `key` - (String) Configuration key. + * `options` - (List) List of options of type. + * `required` - (Boolean) Is key required to install. + * `type` - (String) Value type (string, boolean, int). + * `type_metadata` - (String) The original type, as found in the source being onboarded. + * `value_constraint` - (String) Constraint associated with value, e.g., for string type - regx:[a-z]. +* `created` - (String) The date and time this version was created. +* `crn` - (String) Version's CRN. +* `deprecate_pending` - (List) Deprecation information for an Offering. +Nested scheme for **deprecate_pending**: + * `deprecate_date` - (String) Date of deprecation. + * `deprecate_state` - (String) Deprecation state. + * `description` - (String) +* `deprecated` - (Boolean) read only field, indicating if this version is deprecated. +* `entitlement` - (List) Entitlement license info. +Nested scheme for **entitlement**: + * `image_repo_name` - (String) Image repository name. + * `part_numbers` - (List) list of license entitlement part numbers, eg. D1YGZLL,D1ZXILL. + * `product_id` - (String) Product ID. + * `provider_id` - (String) Provider ID. + * `provider_name` - (String) Provider name. +* `iam_permissions` - (List) List of IAM permissions that are required to consume this version. +Nested scheme for **iam_permissions**: + * `resources` - (List) Resources for this permission. + Nested scheme for **resources**: + * `description` - (String) Resource description. + * `name` - (String) Resource name. + * `role_crns` - (List) Role CRNs for this permission. + * `role_crns` - (List) Role CRNs for this permission. + * `service_name` - (String) Service name. +* `image_manifest_url` - (String) If set, denotes a url to a YAML file with list of container images used by this version. +* `image_pull_key_name` - (String) ID of the image pull key to use from Offering.ImagePullKeys. +* `install` - (List) Script information. +Nested scheme for **install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. +* `is_consumable` - (Boolean) Is the version able to be shared. +* `kind_id` - (String) Kind ID. +* `licenses` - (List) List of licenses the product was built with. +Nested scheme for **licenses**: + * `description` - (String) License description. + * `id` - (String) License ID. + * `name` - (String) license name. + * `type` - (String) type of license e.g., Apache xxx. + * `url` - (String) URL for the license text. +* `long_description` - (String) Long description for version. +* `long_description_i18n` - (Map) A map of translated strings, by language code. +* `metadata` - (Forces new resource, List) Generic data to be included with content being onboarded. Required for virtual server image for VPC. +Nested scheme for **metadata**: + * `source_url` - (String) Source URL for the version. + * `terraform_version` - (String) Version's terraform version. + * `validated_terraform_version` - (String) Version's validated terraform version. + * `version_name` - (String) Name of the version. + * `vsi_vpc` - (List) VSI information for this version. + Nested scheme for **vsi_vpc**: + * `file` - (List) Details for the stored image file. Required for virtual server image for VPC. + Nested scheme for **file**: + * `size` - (Integer) Size of the stored image file rounded up to the next gigabyte. Required for virtual server image for VPC. + * `images` - (List) Image operating system. Required for virtual server image for VPC. + Nested scheme for **images**: + * `id` - (String) Programmatic ID of virtual server image. Required for virtual server image for VPC. + * `name` - (String) Programmatic name of virtual server image. Required for virtual server image for VPC. + * `region` - (String) Region the virtual server image is available in. Required for virtual server image for VPC. + * `minimum_provisioned_size` - (Integer) Minimum size (in gigabytes) of a volume onto which this image may be provisioned. Required for virtual server image for VPC. + * `operating_system` - (List) Operating system included in this image. Required for virtual server image for VPC. + Nested scheme for **operating_system**: + * `architecture` - (String) Operating system architecture. Required for virtual server image for VPC. + * `dedicated_host_only` - (Boolean) Images with this operating system can only be used on dedicated hosts or dedicated host groups. Required for virtual server image for VPC. + * `display_name` - (String) Unique, display-friendly name for the operating system. Required for virtual server image for VPC. + * `family` - (String) Software family for this operating system. Required for virtual server image for VPC. + * `href` - (String) URL for this operating system. Required for virtual server image for VPC. + * `name` - (String) Globally unique name for this operating system Required for virtual server image for VPC. + * `vendor` - (String) Vendor of the operating system. Required for virtual server image for VPC. + * `version` - (String) Major release version of this operating system. Required for virtual server image for VPC. +* `offering_id` - (String) Offering ID. +* `outputs` - (List) List of output values for this version. +Nested scheme for **outputs**: + * `description` - (String) Output description. + * `key` - (String) Output key. +* `package_version` - (String) Version of the package used to create this version. +* `pre_install` - (List) Optional pre-install instructions. +Nested scheme for **pre_install**: + * `delete_script` - (String) Optional script that if run will remove the installed version. + * `instructions` - (String) Instruction on step and by whom (role) that are needed to take place to prepare the target for installing this version. + * `instructions_i18n` - (Map) A map of translated strings, by language code. + * `scope` - (String) Optional value indicating if this script is scoped to a namespace or the entire cluster. + * `script` - (String) Optional script that needs to be run post any pre-condition script. + * `script_permission` - (String) Optional iam permissions that are required on the target cluster to run this script. +* `repo_url` - (String) Content's repo URL. +* `required_resources` - (List) Resource requirments for installation. +Nested scheme for **required_resources**: + * `type` - (String) Type of requirement. + * Constraints: Allowable values are: `mem`, `disk`, `cores`, `targetVersion`, `nodes`. + * `value` - (Map) mem, disk, cores, and nodes can be parsed as an int. targetVersion will be a semver range value. +* `rev` - (String) Cloudant revision. +* `single_instance` - (Boolean) Denotes if single instance can be deployed to a given cluster. +* `solution_info` - (List) Version Solution Information. Only supported for Product kind Solution. +Nested scheme for **solution_info**: + * `architecture_diagrams` - (List) Architecture diagrams for this solution. + Nested scheme for **architecture_diagrams**: + * `description` - (String) Description of this diagram. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `diagram` - (List) Offering Media information. + Nested scheme for **diagram**: + * `api_url` - (String) CM API specific URL of the specified media item. + * `caption` - (String) Caption for this media item. + * `caption_i18n` - (Map) A map of translated strings, by language code. + * `thumbnail_url` - (String) Thumbnail URL for this media item. + * `type` - (String) Type of this media item. + * `url` - (String) URL of the specified media item. + * `url_proxy` - (List) Offering URL proxy information. + Nested scheme for **url_proxy**: + * `sha` - (String) SHA256 fingerprint of image. + * `url` - (String) URL of the specified media item being proxied. + * `cost_estimate` - (List) Cost estimate definition. + Nested scheme for **cost_estimate**: + * `currency` - (String) Cost estimate currency. + * `diff_total_hourly_cost` - (String) Difference in total hourly cost. + * `diff_total_monthly_cost` - (String) Difference in total monthly cost. + * `past_total_hourly_cost` - (String) Past total hourly cost. + * `past_total_monthly_cost` - (String) Past total monthly cost. + * `projects` - (List) Cost estimate projects. + Nested scheme for **projects**: + * `breakdown` - (List) Cost breakdown definition. + Nested scheme for **breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `diff` - (List) Cost breakdown definition. + Nested scheme for **diff**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `metadata` - (Map) Project metadata. + * `name` - (String) Project name. + * `past_breakdown` - (List) Cost breakdown definition. + Nested scheme for **past_breakdown**: + * `resources` - (List) Resources. + Nested scheme for **resources**: + * `cost_components` - (List) Cost components. + Nested scheme for **cost_components**: + * `hourly_cost` - (String) Cost component hourly cost. + * `hourly_quantity` - (String) Cost component hourly quantity. + * `monthly_cost` - (String) Cost component monthly cist. + * `monthly_quantity` - (String) Cost component monthly quantity. + * `name` - (String) Cost component name. + * `price` - (String) Cost component price. + * `unit` - (String) Cost component unit. + * `hourly_cost` - (String) Hourly cost. + * `metadata` - (Map) Resource metadata. + * `monthly_cost` - (String) Monthly cost. + * `name` - (String) Resource name. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_c_ost` - (String) Total monthly cost. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `summary` - (List) Cost summary definition. + Nested scheme for **summary**: + * `no_price_resource_counts` - (Map) No price resource counts. + * `total_detected_resources` - (Integer) Total detected resources. + * `total_no_price_resources` - (Integer) Total no price resources. + * `total_supported_resources` - (Integer) Total supported resources. + * `total_unsupported_resources` - (Integer) Total unsupported resources. + * `total_usage_based_resources` - (Integer) Total usage based resources. + * `unsupported_resource_counts` - (Map) Unsupported resource counts. + * `time_generated` - (String) When this estimate was generated. + * `total_hourly_cost` - (String) Total hourly cost. + * `total_monthly_cost` - (String) Total monthly cost. + * `version` - (String) Cost estimate version. + * `dependencies` - (List) Dependencies for this solution. + Nested scheme for **dependencies**: + * `catalog_id` - (String) Optional - If not specified, assumes the Public Catalog. + * `flavors` - (List) Optional - List of dependent flavors in the specified range. + * `id` - (String) Optional - Offering ID - not required if name is set. + * `name` - (String) Optional - Programmatic Offering name. + * `version` - (String) Required - Semver value or range. + * `features` - (List) Features - titles only. + Nested scheme for **features**: + * `description` - (String) Feature description. + * `description_i18n` - (Map) A map of translated strings, by language code. + * `title` - (String) Heading. + * `title_i18n` - (Map) A map of translated strings, by language code. +* `source_url` - (String) Content's source URL (e.g git repo). +* `state` - (List) Offering state. +Nested scheme for **state**: + * `current` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `current_entered` - (String) Date and time of current request. + * `pending` - (String) one of: new, validated, account-published, ibm-published, public-published. + * `pending_requested` - (String) Date and time of pending request. + * `previous` - (String) one of: new, validated, account-published, ibm-published, public-published. +* `tgz_url` - (String) File used to on-board this version. +* `updated` - (String) The date and time this version was last updated. +* `validation` - (List) Validation response. +Nested scheme for **validation**: + * `last_operation` - (String) Last operation (e.g. submit_deployment, generate_installer, install_offering. + * `message` - (String) Any message needing to be conveyed as part of the validation job. + * `requested` - (String) Date and time of last validation was requested. + * `state` - (String) Current validation state - , in_progress, valid, invalid, expired. + * `target` - (Map) Validation target information (e.g. cluster_id, region, namespace, etc). Values will vary by Content type. + * `validated` - (String) Date and time of last successful validation. +* `version_id` - (String) Unique ID. +* `version_locator` - (String) A dotted value of `catalogID`.`versionID`. +* `whitelisted_accounts` - (List) Whitelisted accounts for version. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` -## Argument reference -Review the argument reference that you can specify for your resource. - -- `catalog_identifier` - (Required, Forces new resource, String) Catalog identifier. -- `content` - (Optional, Forces new resource, String) The byte array representing the content to import. Currently supports only `OVA` images. -- `offering_id` - (Required, Forces new resource, String) Offering identification. -- `tags` - (Optional, Forces new resource, List) The tags array. -- `target_kinds` - (Optional, Forces new resource, List) The target kinds. Supported values are `iks`, `roks`, `vcenter`, and `terraform`. -- `target_version` - (Optional, Forces new resource, String) The semver value for the new version, if not found in the `zip` URL package content. -- `zipurl` - (Optional, Forces new resource, String) The URL path to `.zip` location. If not specified, must provide content in the body of the call. - - -## Attribute reference -In addition to all argument references list, you can access the following attribute references after your resource is created. - -- `catalog_id` - (String) The catalog ID. -- `crn` - (String) The CRN version. -- `id` - (String) The unique identifier and version locator of the version. -- `kind_id` - (String) The kind ID. -- `repo_url` - (String) The URL of the content repository. -- `sha` - (String) The hash of the content. -- `source_url` - (String) The source URL of the content repository, for example, Git repository. -- `tgz_url` - (String) File used to onboard the version. -- `url` - (String) The URL for the specific offering. -- `version` - (String) Version of the content type. +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_cm_version` resource by using `id`. +The `id` property can be formed from `catalog_identifier`, `offering_id`, and `version_loc_id` in the following format: + +``` +// +``` +* `catalog_identifier`: A string. Catalog identifier. +* `offering_id`: A string. Offering identification. +* `version_loc_id`: A string. A dotted value of `catalogID`.`versionID`. + +# Syntax +``` +$ terraform import ibm_cm_version.cm_version // +``` diff --git a/website/docs/r/compute_bare_metal.html.markdown b/website/docs/r/compute_bare_metal.html.markdown index 19027aa1b..067014c9c 100644 --- a/website/docs/r/compute_bare_metal.html.markdown +++ b/website/docs/r/compute_bare_metal.html.markdown @@ -192,3 +192,13 @@ In addition to all argument reference list, you can access the following attribu - `private_ipv4_address` - (String) The private IPv4 address of the Bare Metal server. - `private_ipv4_address_id` - (String) The unique identifier for the private IPv4 address of the Bare Metal server. - `secondary_ip_addresses` - (String) The public secondary IPv4 addresses of the Bare Metal server instance when `secondary_ip_count` is set to non zero value. + +## Import + +The `ibm_compute_bare_metal` resource can be imported by using Bare Metal server ID. + +**Example** + +``` +$ terraform import ibm_compute_bare_metal.server +``` diff --git a/website/docs/r/compute_reserved_capacity.html.markdown b/website/docs/r/compute_reserved_capacity.html.markdown index 61d36715c..5aed69ac0 100644 --- a/website/docs/r/compute_reserved_capacity.html.markdown +++ b/website/docs/r/compute_reserved_capacity.html.markdown @@ -41,6 +41,7 @@ Review the argument references that you can specify for your resource. - `datacenter` - (Required, Forces new resource, String) The datacenter in which you want to provision the reserved capacity. - `flavor`- (Required, String) Capacity keyname. For example, C1_2X2_1_YEAR_TERM. +- `force_create` - (Optional, Boolean) Force the creation of reserved capacity with same name. - `instances`- (Required, Forces new resource, Integer) Number of VSI instances this capacity reservation can support. - `name` - (Required, String) The descriptive that is used to identify a reserved capacity. - `pod` - (Required, Forces new resource, String) The data center pod where you want to create the reserved capacity. diff --git a/website/docs/r/compute_vm_instance.html.markdown b/website/docs/r/compute_vm_instance.html.markdown index 93cdd1028..f25691052 100644 --- a/website/docs/r/compute_vm_instance.html.markdown +++ b/website/docs/r/compute_vm_instance.html.markdown @@ -263,8 +263,8 @@ Review the argument references that you can specify for your resource. - `post_install_script_uri` - (Optional, Forces new resource, String) The URI of the script to be downloaded and executed after installation is complete. - `quote_id` - (Optional, Forces new resource, String) When you define the `quote_id`, Terraform uses the specification in the quote to create a virtual server. You can find the quote ID in the IBM Cloud portal. - `public_security_group_ids`- (Optional, Force new resource, Array of Integers) The IDs of security groups to apply on the public interface. This attribute can't be updated. You can use this parameter to add a security group to your virtual server instance when you create it. If you want to add or remove security groups later, you must use the `ibm_network_interface_sg_attachment` resource. If you use this attribute in addition to `ibm_network_interface_sg_attachment` resource, you might experience errors. So use one of these consistently for a particular virtual server instance. -- `public_subnet` - (Optional, Forces new resource, String) The public subnet for the public network interface of the instance. Accepted values are primary public networks. You can find accepted values in the [subnets doc](https://cloud.ibm.com/classic/network/subnets). -- `private_subnet` - (Optional, Forces new resource, String) The private subnet for the private network interface of the instance. Accepted values are primary private networks. You can find accepted values in the [subnets doc](https://cloud.ibm.com/classic/network/subnets). +- `public_subnet` - (Optional, Forces new resource, String) The public subnet for the public network interface of the instance. Accepted values are primary public networks. You can find accepted values in the [subnets doc](https://cloud.ibm.com/classic/network/subnets), **Note** You can see the list of public subnets of your account. +- `private_subnet` - (Optional, Forces new resource, String) The private subnet for the private network interface of the instance. Accepted values are primary private networks. You can find accepted values in the [subnets doc](https://cloud.ibm.com/classic/network/subnets), **Note** You can see the list of private subnets of your account. - `public_bandwidth_limited` - (Optional, Forces new resource, Integer) Allowed public network traffic in GB per month. It can be greater than 0 when the server is a monthly based server. Defaults to the smallest available capacity for the public bandwidth are used. **Note** Conflicts with `private_network_only` and `public_bandwidth_unlimited`. - `public_bandwidth_unlimited` - (Optional, Forces new resource, Bool) Allowed unlimited public network traffic in GB per month for a monthly based server. The `network_speed` should be 100 Mbps. Default value is **false**. **Note** Conflicts with `private_network_only` and `public_bandwidth_limited`. - `reserved_capacity_id` - (Optional, Forces new resource, Integer) The reserved capacity ID to provision the instance. diff --git a/website/docs/r/container_alb.html.markdown b/website/docs/r/container_alb.html.markdown index 7ca5c75fe..868517953 100644 --- a/website/docs/r/container_alb.html.markdown +++ b/website/docs/r/container_alb.html.markdown @@ -44,3 +44,5 @@ In addition to all argument reference list, you can access the following attribu - `cluster` - (String) The name of the cluster where the ALB is provisioned. - `id` - (String) The unique identifier of the ALB. - `name` - (String) The name of the ALB. +- `replicas` - (String) Desired number of ALB replicas. +- `resize` - (Bool) Indicate whether resizing should be done \ No newline at end of file diff --git a/website/docs/r/container_alb_create.html.markdown b/website/docs/r/container_alb_create.html.markdown new file mode 100644 index 000000000..df80d363d --- /dev/null +++ b/website/docs/r/container_alb_create.html.markdown @@ -0,0 +1,54 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_alb_create" +description: |- + Creates new IBM container Application Load Balancer. +--- + +# ibm_container_alb +Creates a new Ingres application load balancer (ALB) that is set up in your cluster. ALBs are used to set up HTTP or HTTPS load-balancing for containerized apps that are deployed into an IBM Cloud Kubernetes Service or Red Hat OpenShift on IBM Cloud cluster. For more information, about Ingress ALBs, see [about Ingress ALBs](https://cloud.ibm.com/docs/containers?topic=containers-ingress-about) + +## Example usage + +```terraform +resource "ibm_container_alb_create" "alb" { + cluster="exampleClusterName" + enable = "true" + alb_type = "private" + vlan_id = "123456" + zone = "dal10" +} + +``` + +## Timeouts + +The `ibm_container_alb_create` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for creating Instance. +- **update** - (Default 60 minutes) Used for updating Instance. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `alb_type` - (String) The type of the ALB. Supported values are `public` and `private`. +- `cluster` - (String) The name of the cluster where the ALB is going to be created. +- `enable` - (Optional, Bool) If set to **true**, the default Ingress ALB in your cluster is enabled and configured with the IBM-provided Ingress subdomain. If set to **false**, the default Ingress ALB is enabled in your cluster. +- `ingress_image` - (Optional,ForceNew,String) The type of Ingress image that you want to use for your ALB deployment. +- `ip` - (Optional,String) The IP address that you want to assign to the ALB. +- `nlb_version` - (Optional,String) The version of the network load balancer that you want to use for the ALB. +- `vlan_id` - (String) ID of the cluster's vlan where the ALB is going to be created. +- `zone` - (String) The name of cluster's zone where the ALB is going to be created. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `alb_id` - (String) The unique identifier of the ALB. To retrieve the ID, run `ibmcloud ks alb ls`. +- `name` - (String) The name of the ALB. +- `replicas` - (String) Desired number of ALB replicas. +- `resize` - (Bool) Indicate whether resizing should be done +- `user_ip` - (String) Private ALB only. The private ALB is deployed with an IP address from a user-provided private subnet. +- `disable_deployment` - (Optional, Bool) If set to **true**, the default Ingress ALB in your cluster is disabled. If set to **false**, the default Ingress ALB is enabled in your cluster and configured with the IBM-provided Ingress subdomain. \ No newline at end of file diff --git a/website/docs/r/container_bind_service.html.markdown b/website/docs/r/container_bind_service.html.markdown index 325c95585..51d92c19b 100644 --- a/website/docs/r/container_bind_service.html.markdown +++ b/website/docs/r/container_bind_service.html.markdown @@ -28,7 +28,7 @@ resource "ibm_container_bind_service" "bind_service" { Review the argument references that you can specify for your resource. - `cluster_name_id` - (Required, Forces new resource, String) The name or ID of the cluster to which you want to bind an IBM Cloud service. To find the cluster name or ID, run `ibmcloud ks cluster ls`. -- `key` - (Optional, Forces new resource, String) The name of existing service credentials that you want to use for the service. If you do not provide this option, service credentials are automatically created as part of the service binding process. +- `key` - (Optional, Forces new resource, String) The name or guid of existing service credentials that you want to use for the service. If you do not provide this option, service credentials are automatically created as part of the service binding process. - `namespace_id` - (Required, Forces new resource, String) The Kubernetes namespace where you want to create the Kubernetes secret that holds the service credentials of the service that you want to bind to the cluster. - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group where your IBM Cloud service is provisioned into. To list resource groups, run `ibmcloud resource groups`. - `role` - (Optional, Forces new resource, String) The IAM service access role that you want to use to create the service credentials for the IBM Cloud service instance. If you specified existing service credentials in the `key` parameter, settings for the `role` parameter are ignored. diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 6a1c4ef52..de79890aa 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -141,7 +141,7 @@ resource "ibm_is_vpc" "vpc1" { resource "ibm_is_subnet" "subnet1" { name = "mysubnet1" vpc = ibm_is_vpc.vpc1.id - zone = "us_south-1" + zone = "us-south-1" total_ipv4_address_count = 256 } @@ -201,6 +201,7 @@ Review the argument references that you can specify for your resource. 2. Set this argument to `cloud_pak` only if you use this cluster with a Cloud Pak that has an OpenShift entitlement. - `force_delete_storage` - (Optional, Bool) If set to **true**,force the removal of persistent storage associated with the cluster during cluster deletion. Default value is **false**. **NOTE** If `force_delete_storage` parameter is used after provisioning the cluster, then, you need to execute `terraform apply` before `terraform destroy` for `force_delete_storage` parameter to take effect. - `hardware` - (Optional, Forces new resource, String) The level of hardware isolation for your worker node. Use `dedicated` to have available physical resources dedicated to you only, or `shared` to allow physical resources to be shared with other IBM customers. This option is available for virtual machine worker node flavors only. +- `image_security_enforcement` - (Optional, Bool) Set to **true** to enable image security enforcement policies in a cluster. - `gateway_enabled` - (Optional, Bool) Set to **true** if you want to automatically create a gateway-enabled cluster. If `gateway_enabled` is set to **true**, then `private_service_endpoint` must be set to **true** at the same time. - `kms_config` - (Optional, List) Used to attach a Key Protect instance to a cluster. Nested `kms_config` block have `instance_id`, `crk_id`, `private_endpoint` structure. @@ -215,9 +216,9 @@ Review the argument references that you can specify for your resource. - `no_subnet` - (Optional, Forces new resource, Bool) If set to **true**, no portable subnet is created during cluster creation. The portable subnet is used to provide portable IP addresses for the Ingress subdomain and Kubernetes load balancer services. If set to **false**, a portable subnet is created by default. The default is **false**. - `patch_version` - (Optional, String) Updates the worker nodes with the required patch version. The patch_version should be in the format: `patch_version_fixpack_version`. For more information, about Kubernetes version information and update, see [Kubernetes version update](https://cloud.ibm.com/docs/containers?topic=containers-cs_versions). **NOTE:** To update the patch or fix pack versions of the worker nodes, run the command `ibmcloud ks workers -c output json`. Fetch the required patch & fix pack versions from `kubeVersion.target` and set the `patch_version` parameter. - `public_service_endpoint` - (Optional, Forces new resource, Bool) If set to **true**, your cluster is set up with a public service endpoint. You can use the public service endpoint to access the Kubernetes master from the public network. To use service endpoints, your account must be enabled for [Virtual Routing and Forwarding (VRF)](https://cloud.ibm.com/docs/account?topic=account-vrf-service-endpoint#vrf). For more information, see [Worker-to-master and user-to-master communication: Service endpoints](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#workeruser-master). If set to **false**, the public service endpoint is disabled for your cluster. -- `public_vlan_id` - (Optional, Forces new resource, String) The ID of the public VLAN that you want to use for your worker nodes. You can retrieve the VLAN ID with the `ibmcloud ks vlans zone ` command.

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

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

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

* **Free clusters**: If you want to provision a free cluster, you do not need to enter a private VLAN ID. Your cluster is automatically connected to a private VLAN that is owned by IBM.
* **Standard clusters**: If you create a standard cluster and you have an existing private VLAN ID for the zone where you plan to set up worker nodes, you must enter the VLAN ID. To retrieve the ID, run `ibmcloud ks vlans --zone `. If you do not have an existing private VLAN ID, do not specify this option. A private VLAN is created automatically for you. - `pod_subnet`- (Optional, String) Specify a custom subnet CIDR to provide private IP addresses for pods. The subnet must be at least `/23` or more. For more information, refer to [Pod subnet](https://cloud.ibm.com/docs/containers?topic=containers-cli-plugin-kubernetes-service-cli#pod-subnet).Yes- - `resource_group_id` - (Optional, String) The ID of the resource group where you want to provision your cluster. To retrieve the ID, use the `ibm_resource_group` data source. If no value is provided, the cluster is automatically provisioned into the `default` resource group. - `retry_patch_version` - (Optional, Integer) This argument retries the update of `patch_version` if the previous update fails. Increment the value to retry the update of `patch_version` on worker nodes. diff --git a/website/docs/r/container_dedicated_host.html.markdown b/website/docs/r/container_dedicated_host.html.markdown new file mode 100644 index 000000000..a830eb58c --- /dev/null +++ b/website/docs/r/container_dedicated_host.html.markdown @@ -0,0 +1,83 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host" +description: |- + Manages dedicated host. +--- + +# ibm_container_dedicated_host + +Provides a resource for managing a dedicated host. A dedicated host can be created or deleted. The only supported update is enabling or disabling the placement on the dedicated host. For more information about dedicated host, see [Creating and managing dedicated hosts on VPC Gen 2 infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-dedicated-hosts). + + +## Example usage +In the following example, you can create a dedicated host: + +```terraform +resource "ibm_container_dedicated_host" "test_dhost" { + flavor = "bx2d.host.152x608" + host_pool_id = "dh-abcdefgh1234567" + zone = "us-south-1" + placement_enabled = "true" +} +``` + +## Timeouts + +ibm_container_dedicated_host provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +* `create` - (Default 40 minutes) Used for creating the dedicated host. Please note that after creating the host, terraform may need to execute some update logic. +* `read` - (Default 10 minutes) Used for reading the dedicated host. +* `update` - (Default 15 minutes) Used for updating the dedicated host. +* `delete` - (Default 40 minutes) Used for deleting the dedicated host. Please note that before deleting the host, terraform may need to execute some update logic. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `flavor` - (Required, Forces new resource, String) The flavor of the dedicated host. +- `host_pool_id`- (Required, Forces new resource, String) The id of the dedicated host pool the dedicated host is associated with. +- `zone` - (Required, Forces new resource, String) The zone of the dedicated host. +- `placement_enabled` - (Optional, Bool) Enables/disables placement on the dedicated host. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `host_id` - (String) The unique identifier of the dedicated host. +- `life_cycle` - (List) A nested block describes the lifecycle state of the dedicated host. + + Nested scheme for `life_cycle`: + - `actual_state` - (String) The actual state of the dedicated host. + - `desired_state` - (String) The desired state of the dedicated host. + - `message` - (String) Information message about the dedicated host's lifecycle. + - `message_date` - (String) The date of the information message. + - `message_details` - (String) Additional details of the information message. + - `message_details_date` - (String) The date of the additional details. +- `resources` - (List) A nested block describes the resources of the dedicated host. + + Nested scheme for `resources`: + - `capacity` - (List) A nested block describes the capacity of the dedicated host. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Memory capacity of the dedicated host. + - `vcpu` - (Int) VCPU capacity of the dedicated host. + - `consumed` - (List) A nested block describes the consumed resources of the dedicated host. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Consumed memory capacity of the dedicated host. + - `vcpu` - (Int) Consumed VCPU capacity of the dedicated host. +- `workers` - (List) A nested block describes the workers associated with this dedicated host. + + Nested scheme for `workers`: + - `cluster_id` - (String) The ID of the cluster the worker is associated with. + - `flavor` - (String) The flavor of the worker. + - `worker_id` - (String) The ID of the worker. + - `worker_pool_id` - (String) The ID of the worker pool the worker is associated with. + +## Import + +The `ibm_container_dedicated_host` can be imported by using the dedicated host pool id and the dedicated host id in the following format: `/`. + +**Example** + +``` +$ terraform import ibm_container_dedicated_host.test_dhost dh-abcdefgh1234567/abcd12-dh-abcdefgh1234567-abcd123-acbd1234 diff --git a/website/docs/r/container_dedicated_host_pool.html.markdown b/website/docs/r/container_dedicated_host_pool.html.markdown new file mode 100644 index 000000000..10d0c0795 --- /dev/null +++ b/website/docs/r/container_dedicated_host_pool.html.markdown @@ -0,0 +1,70 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_dedicated_host_pool" +description: |- + Manages dedicated host pool. +--- + +# ibm_container_dedicated_host_pool + +Create or delete a dedicated host pool. For more information, about dedicated host pool, see [Creating and managing dedicated hosts on VPC Gen 2 infrastructure](https://cloud.ibm.com/docs/containers?topic=containers-dedicated-hosts). + + +## Example usage +In the following example, you can create a dedicated host pool: + +```terraform +resource "ibm_container_dedicated_host_pool" "test_dhostpool" { + name = "test_dhostpool" + flavor_class = "bx2d" + metro = "dal" +} +``` + +## Timeouts + +ibm_container_dedicated_host_pool provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +* `create` - (Default 10 minutes) Used for creating the dedicated host pool. +* `read` - (Default 10 minutes) Used for reading the dedicated host pool. +* `delete` - (Default 10 minutes) Used for deleting the dedicated host pool. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `name` - (Required, Forces new resource, String) The name of the dedicated host pool. +- `metro`- (Required, Forces new resource, String) The metro to create the dedicated host pool in. +- `flavor_class` - (Required, Forces new resource, String) The flavor class of the dedicated host pool. +- `resource_group_id` - (Optional, String) The ID of the resource group where you want to create the dedicated host pool. To retrieve the ID, use the `ibm_resource_group` data source. If no value is provided, the dedicated host pool is automatically created under the `default` resource group. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the dedicated host pool. +- `host_count` (Int) The count of the hosts under the dedicated host pool. +- `state` - (String) The state of the dedicated host pool. +- `zones` - (List) A nested block describes the zones of this dedicated host pool. + + Nested scheme for `zones`: + - `capacity` - (Map) A nested block describes the capacity of the zone. + Nested scheme for `capacity`: + - `memory_bytes` - (Int) Memory capacity of the zone. + - `vcpu` - (Int) VCPU capacity of the zone. + - `host_count` - (Int) The count of the hosts under the zone. + - `zone` - (String) The name of the zone. +- `worker_pools` - (List) A nested block describes the worker pools of this dedicated host pool. + + Nested scheme for `worker_pools`: + - `cluster_id` - (String) The ID of the cluster. + - `worker_pool_id` - (String) The unique identifier of the worker pool. + +## Import + +The `ibm_container_dedicated_host_pool` can be imported by using `id`. + +**Example** + +``` +$ terraform import ibm_container_dedicated_host_pool.test_dhostpool "dh-abcdefgh1234567" diff --git a/website/docs/r/container_nlb_dns.html.markdown b/website/docs/r/container_nlb_dns.html.markdown new file mode 100644 index 000000000..b8bb33fb0 --- /dev/null +++ b/website/docs/r/container_nlb_dns.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM : ibm_container_nlb_dns" +description: |- + Manages IBM Container Nlb +--- + +# ibm_container_nlb_dns + +Provides a resource for container_nlb_dns. This allows to add an NLB IP's to an existing host name that you created with 'ibmcloud ks nlb-dns create'. + +## Example usage + +```terraform +data "ibm_container_nlb_dns" "dns" { + cluster = var.cluster +} + +resource "ibm_container_nlb_dns" "container_nlb_dns" { + cluster = var.cluster + nlb_host = data.ibm_container_nlb_dns.dns.nlb_config.0.nlb_sub_domain + nlb_ips = var.cluster_ips +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +* `cluster` - (Required, Forces new resource, String) The name or ID of the cluster. To list the clusters that you have access to, use the `GET /v1/clusters` API or run `ibmcloud ks cluster ls`. +* `nlb_host` - (Required, Forces new resource, String) Host Name of load Balancer. +* `nlb_ips` - (Required, Set) NLB IPs. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the container_nlb_dns. +* `nlb_dns_type` - Type of DNS. +* `nlb_monitor_state` - Nlb monitor state. +* `nlb_ssl_secret_name` - Name of SSL Secret. +* `nlb_ssl_secret_status` - Status of SSL Secret. +* `nlb_type` - Nlb Type. +* `secret_namespace` - Namespace of Secret. +* `resource_group_id` - The ID of the resource group that the cluster is in. To check the resource group ID of the cluster, use the GET /v1/clusters/idOrName API. To list available resource group IDs, run ibmcloud resource groups. + +## Import + +The import functionality is not supported for this resource. diff --git a/website/docs/r/container_storage_attachment.html.markdown b/website/docs/r/container_storage_attachment.html.markdown new file mode 100644 index 000000000..fb5703df7 --- /dev/null +++ b/website/docs/r/container_storage_attachment.html.markdown @@ -0,0 +1,110 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_vpc_worker_storage" +description: |- + Manages IBM Cloud Container VPC worker storage attachment +--- + +# ibm_container_storage_attachment + +Create, update, or delete a VPC storage attachment of a VPC worker node. For more information, about VPC storage attachment, see [Attaching a block storage volume](https://cloud.ibm.com/docs/vpc?topic=vpc-attaching-block-storage&interface=ui). + + +## Example usage + +In the following example, you can create a storage attachment for a VPC cluster worker node: + +```terraform +provider "ibm" { + region ="us-south" +} + +data "ibm_resource_group" "resource_group" { + is_default = "true" +} + +resource "ibm_is_vpc" "vpc" { + name = "vpc" +} + +resource "ibm_is_subnet" "subnet" { + name = "subnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-1" + total_ipv4_address_count = 256 +} + +resource "ibm_container_vpc_cluster" "cluster" { + name = "cluster" + vpc_id = ibm_is_vpc.vpc.id + flavor = "cx2.2x4" + worker_count = 1 + wait_till = "OneWorkerNodeReady" + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = ibm_is_subnet.subnet.id + name = "us-south-1" + } + + worker_labels = { + "test" = "test-default-pool" + "test1" = "test-default-pool1" + "test2" = "test-default-pool2" + } +} + +resource "ibm_is_volume" "storage"{ + name = "volume" + profile = "10iops-tier" + zone = "us-south-1" +} + +data "ibm_container_vpc_cluster" "cluster" { + name = ibm_container_vpc_cluster.cluster.id +} + +resource "ibm_container_storage_attachment" "volume_attach"{ + volume = ibm_is_volume.storage.id + cluster = ibm_container_vpc_cluster.cluster.id + worker = data.ibm_container_vpc_cluster.cluster.workers[0] +} +``` + +## Timeouts + +The ibm_container_storage_attachment provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +* `Create` - (Default 15 minutes) Used for creating storage attachment Instance. +* `Delete` - (Default 10 minutes) Used for deleting storage attachment Instance. + + +## Argument reference + +Review the argument references that you can specify for your resource. + +* `cluster` - (Required, Forces new resource, String) The name or ID of the cluster. +* `volume` - (Required, Forces new resource, String) The ID of the VPC block volume. +* `worker` - (Required, Forces new resource, String) The ID of the VPC cluster worker node. + + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +* `id` - The unique identifier of the worker storage resource. The id is composed of /. +* `status` - (String) The volume attachment status. +* `volume_attachment_id` - (String) The volume attachment ID. +* `volume_attachment_name` - (String) The volume attachment name. +* `volume_type` - (String) The volume attachment type. + +## Import + +The ibm_container_storage_attachment can be imported using `cluster_name_id`, `worker_id` and `volume_attachment_id` + +Example + +``` +$ terraform import ibm_container_storage_attachment.example mycluster/kube-c08evsgd0anad0v8c76g-gen2newvpc-default-00000116/5c4f4d06e0dc402084922dea70850e3b-7cafe35 +``` \ No newline at end of file diff --git a/website/docs/r/container_vpc_alb.html.markdown b/website/docs/r/container_vpc_alb.html.markdown index 06fe7a911..ff9e8225b 100644 --- a/website/docs/r/container_vpc_alb.html.markdown +++ b/website/docs/r/container_vpc_alb.html.markdown @@ -38,7 +38,7 @@ Review the argument references that you can specify for your resource. **Note** You must include either `enable` or `disable_deployment` in the configuration, but must not include both. -## Attribute Reference +## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `alb_type` - (String) The ALB type. diff --git a/website/docs/r/container_vpc_alb_create.html.markdown b/website/docs/r/container_vpc_alb_create.html.markdown new file mode 100644 index 000000000..5f3f43dde --- /dev/null +++ b/website/docs/r/container_vpc_alb_create.html.markdown @@ -0,0 +1,54 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_vpc_alb" +description: |- + Creates IBM container VPC ALB. +--- + +# ibm_container_vpc_alb +Creates a new Application Load Balancer (ALB) for a VPC cluster. For more information, about IBM container VPC ALB, see [VPC: Exposing apps with load balancers for VPC](https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas). + +## Example usage +In the following example, you can configure a ALB: + +```terraform +resource ibm_container_vpc_alb_create alb { + cluster = "exampleClusterID" + type = "private" + zone = "us-south-1" + resource_group_id = "123456" + enable = "true" +} + +``` + +## Timeouts + +The ibm_container_vpc_alb_create provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The enablement or disablement of the ALB is considered failed when no response is received for 5 minutes. +- **Update** The update of the ALB is considered failed when no response is received for 5 minutes. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `cluster` - (String) The name of the cluster where the ALB is going to be created +- `enable` - (Optional, Bool) If set to **true**, the ALB in your cluster is enabled. Defaults to true +- `resource_group_id` - (Optional, String) The ID of the resource group where your cluster is provisioned into. To list resource groups, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. +- `type` - (String) The ALB type. Supported values are `public` and `private`. +- `zone` - (String) The name of the zone. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `alb_id` - (String) The unique identifier of the application load balancer. +- `alb_type` - (String) The ALB type. +- `disable_deployment` - (Bool) Disable the ALB instance in the cluster +- `load_balancer_hostname` - (String) The host name of the ALB. +- `name` - (String) The name of the ALB. +- `resize`- (Bool) Resize of the ALB. +- `state` - (String) ALB state. +- `status` - (String) The status of ALB. diff --git a/website/docs/r/container_vpc_cluster.html.markdown b/website/docs/r/container_vpc_cluster.html.markdown index 323520399..214f9808d 100644 --- a/website/docs/r/container_vpc_cluster.html.markdown +++ b/website/docs/r/container_vpc_cluster.html.markdown @@ -34,6 +34,26 @@ resource "ibm_container_vpc_cluster" "cluster" { } ``` +## Example with boot volume encryption +In the following example, you can create a Gen-2 VPC cluster with a default worker pool with one worker with boot volume encryption: + +```terraform +resource "ibm_container_vpc_cluster" "cluster" { + name = "my_vpc_cluster" + vpc_id = "r006-abb7c7ea-aadf-41bd-94c5-b8521736fadf" + kube_version = "1.17.5" + flavor = "bx2.2x8" + worker_count = "1" + resource_group_id = data.ibm_resource_group.resource_group.id + zones { + subnet_id = "0717-0c0899ce-48ac-4eb6-892d-4e2e1ff8c9478" + name = "us-south-1" + } + kms_instance_id = "8e9056e6-1936-4dd9-a0a1-51d824765e11" + crk = "804cb251-fa0a-46f5-a442-fe42cfb0ed5f" +} +``` + ### VPC Generation 2 Red Hat OpenShift on IBM Cloud cluster with existing OpenShift entitlement Create the Openshift Cluster with default worker pool entitlement with one worker node: @@ -99,7 +119,7 @@ resource "ibm_is_vpc" "vpc1" { resource "ibm_is_subnet" "subnet1" { name = "mysubnet1" vpc = ibm_is_vpc.vpc1.id - zone = "us_south-1" + zone = "us-south-1" total_ipv4_address_count = 256 } @@ -156,8 +176,10 @@ Review the argument references that you can specify for your resource. - `entitlement` - (Optional, String) Entitlement reduces additional OCP Licence cost in OpenShift clusters. Use Cloud Pak with OCP Licence entitlement to create the OpenShift cluster. **Note**
  • It is set only when the first time creation of the cluster, further modifications are not impacted.
  • Set this argument to `cloud_pak` only if you use the cluster with a Cloud Pak that has an OpenShift entitlement.
. - `force_delete_storage` - (Optional, Bool) If set to **true**,force the removal of persistent storage associated with the cluster during cluster deletion. Default value is **false**. **Note** If `force_delete_storage` parameter is used after provisioning the cluster, then, you need to execute `terraform apply` before `terraform destroy` for `force_delete_storage` parameter to take effect. - `flavor` - (Required, Forces new resource, String) The flavor of the VPC worker node that you want to use. +- `image_security_enforcement` - (Optional, Bool) Set to **true** to enable image security enforcement policies in a cluster. - `name` - (Required, Forces new resource, String) The name of the cluster. - `kms_config` - (Optional, String) Use to attach a Key Protect instance to a cluster. Nested `kms_config` block has an `instance_id`, `crk_id`, `private_endpoint`. +- `host_pool_id` - (Optional, String) If provided, the cluster will be associated with a dedicated host pool identified by this ID. Nested scheme for `kms_config`: - `crk_id` - (Optional, String) The ID of the customer root key (CRK). @@ -189,6 +211,9 @@ Review the argument references that you can specify for your resource. - `name` - (Required, Forces new resource, String) The zone name for the default worker pool in a multizone cluster. - `subnet_id` - (Required, Forces new resource, String) The VPC subnet to assign the cluster's default worker pool. +- `crk` - Root Key ID for boot volume encryption. +- `kms_instance_id` - Instance ID for boot volume encryption. + **Note** 1. For users on account to add tags to a resource, you need to assign the right access. For more information, about tags, see [Tags permission](https://cloud.ibm.com/docs/account?topic=account-access). diff --git a/website/docs/r/container_vpc_worker.html.markdown b/website/docs/r/container_vpc_worker.html.markdown new file mode 100644 index 000000000..5ff9c8c8f --- /dev/null +++ b/website/docs/r/container_vpc_worker.html.markdown @@ -0,0 +1,57 @@ +--- + +subcategory: "Kubernetes Service" +layout: "ibm" +page_title: "IBM: container_vpc_worker" +description: |- + Manages IBM container VPC worker. +--- + +# ibm_container_vpc_worker + +Replace a worker. The worker will be replaced & updated to the latest patch in the specified cluster. For more information, about VPC worker updates, see [Updating VPC worker nodes](https://cloud.ibm.com/docs/containers?topic=containers-update&interface=ui#vpc_worker_node) + + +## Example usage +In the following example, you can replace worker in a vpc cluster: + +```terraform +resource "ibm_container_vpc_worker" "test_worker" { + cluster_name = "my_vpc_cluster" + replace_worker = "kube-clusterid-mycluster-default-00001" + resource_group_id = "6015365a-9d93-4bb4-8248-79ae0db2dc21" + kube_config_path = "my_vpc_cluster.yaml" + check_ptx_status = "true" + ptx_timeout = "5m" +} +``` + +## Timeouts + +The `ibm_container_vpc_worker` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The creation of the worker is considered failed when no response is received for 30 minutes. +- **Delete** The deletion of the worker is considered failed when no response is received for 30 minutes. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `clusrer_name` - (Required, Forces new resource, String) The name or ID of the cluster. +- `replace_worker` - (Required, Forces new resource, String) The ID of the worker that needs to be replaced. +- `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group. To retrieve the ID, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. If no value is provided, the `default` resource group is used. +- `check_ptx_status` - (Optional, String) Boolean value to check the status of Portworx on the replaced worker instance. By default, this variable is set as `false`. +- `kube_config_path` - (Optional, String) The Cluster config with absolute path. If `check_ptx_status` is true, this variable should hold a valid value. To retrieve the cluster config, run `ibmcloud cluster config -c ` or use the `ibm_container_cluster_config` data source. +- `ptx_timeout` - (Optional, String) The Status of Portworx on the replaced worker is considered failed when no response is received for 15 minutes. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the worker. +- `ip` - (String) The IP of the worker. + +## Note +- This resource is different from all other resource of IBM Cloud. Worker replace has 2 operations, i.e. Delete old worker & Create a new worker. On `terraform apply`, Replace operation is being handled where both the deletion & creation happens whereas on the `terraform destroy`, only the state is cleared but not the actual resource. +- When the worker list is being provided as inputs, the list must be user generated and should not be passed from the `ibm_container_cluster` data source. +- If `terraform apply` fails during worker replace or while checking the portworx status, perform any one of the following actions before retrying. + - Resolve the issue manually and perform `terraform untaint` to proceed with the subsequent workers in the list. + - If worker replace is still needed, update the input list by replacing the existing worker id with the new worker id. diff --git a/website/docs/r/container_vpc_worker_pool.html.markdown b/website/docs/r/container_vpc_worker_pool.html.markdown index adecb33d2..fc391b9c6 100644 --- a/website/docs/r/container_vpc_worker_pool.html.markdown +++ b/website/docs/r/container_vpc_worker_pool.html.markdown @@ -12,7 +12,7 @@ description: |- Create or delete a worker pool. The worker pool will be attached to the specified cluster. For more information, about VPC worker pool, see [creating clusters](https://cloud.ibm.com/docs/containers?topic=containers-clusters). -## Example Usage +## Example usage In the following example, you can create a worker pool for a vpc cluster: ```terraform @@ -30,6 +30,26 @@ resource "ibm_container_vpc_worker_pool" "test_pool" { } ``` +In the following example, you can create a worker pool for a vpc cluster with boot volume encryption enabled: + +```terraform +resource "ibm_container_vpc_worker_pool" "test_pool" { + cluster = "my_vpc_cluster" + worker_pool_name = "my_vpc_pool" + flavor = "c2.2x4" + vpc_id = "6015365a-9d93-4bb4-8248-79ae0db2dc21" + worker_count = "1" + + zones { + name = "us-south-1" + subnet_id = "015ffb8b-efb1-4c03-8757-29335a07493b" + } + + kms_instance_id = "8e9056e6-1936-4dd9-a0a1-51d824765e11" + crk = "804cb251-fa0a-46f5-a442-fe42cfb0ed5f" +} +``` + In the follwoing example, you can create a worker pool for openshift cluster type with entitlement. ```terraform resource "ibm_container_vpc_worker_pool" "test_pool" { @@ -60,6 +80,7 @@ Review the argument references that you can specify for your resource. - `cluster` - (Required, Forces new resource, String) The name or ID of the cluster. - `entitlement`- (Optional, String) The OpenShift cluster entitlement avoids incurred OCP license charges and use cloud pak with OCP license entitlement to add the OpenShift cluster worker pool. **Note**
  • It is set as one time creation of the worker pool. There is no impacts on any modification.
  • Set the argument to `entitlement` only when you use cluster with a cloud pak that has an OpenShift entitlement.
- `flavor` - (Required, Forces new resource, String) The flavor of the worker node. +- `host_pool_id` - (Optional, String) The ID of the dedicated host pool the worker pool is associated with. - `labels` (Optional, Map) A list of labels that you want to add to all the worker nodes in the worker pool. - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group. To retrieve the ID, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. If no value is provided, the `default` resource group is used. - `taints` - (Optional, Set) A nested block that sets or removes Kubernetes taints for all worker nodes in a worker pool @@ -77,7 +98,9 @@ Review the argument references that you can specify for your resource. Nested scheme for `zones`: - `name` - (Required, String) The name of the zone. - `subnet_id` - (Required, String) The subnet that you want to use for your worker pool. - + +- `crk` - Root Key ID for boot volume encryption. +- `kms_instance_id` - Instance ID for boot volume encryption. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/container_vpc_worker_storage.html.markdown b/website/docs/r/container_vpc_worker_storage.html.markdown deleted file mode 100644 index 347f1524f..000000000 --- a/website/docs/r/container_vpc_worker_storage.html.markdown +++ /dev/null @@ -1,110 +0,0 @@ ---- - -subcategory: "Kubernetes Service" -layout: "ibm" -page_title: "IBM: container_vpc_worker_storage" -description: |- - Manages IBM Cloud Container VPC worker storage attachment ---- - -# ibm_container_vpc_worker_storage - -Create, update, or delete a VPC storage attachment of a VPC worker node. For more information, about VPC storage attachment, see [Attaching a block storage volume](https://cloud.ibm.com/docs/vpc?topic=vpc-attaching-block-storage&interface=ui). - - -## Example usage - -In the following example, you can create a storage attachment for a VPC cluster worker node: - -```terraform -provider "ibm" { - region ="us-south" -} - -data "ibm_resource_group" "resource_group" { - is_default = "true" -} - -resource "ibm_is_vpc" "vpc" { - name = "vpc" -} - -resource "ibm_is_subnet" "subnet" { - name = "subnet" - vpc = ibm_is_vpc.vpc.id - zone = "us-south-1" - total_ipv4_address_count = 256 -} - -resource "ibm_container_vpc_cluster" "cluster" { - name = "cluster" - vpc_id = ibm_is_vpc.vpc.id - flavor = "cx2.2x4" - worker_count = 1 - wait_till = "OneWorkerNodeReady" - resource_group_id = data.ibm_resource_group.resource_group.id - zones { - subnet_id = ibm_is_subnet.subnet.id - name = "us-south-1" - } - - worker_labels = { - "test" = "test-default-pool" - "test1" = "test-default-pool1" - "test2" = "test-default-pool2" - } -} - -resource "ibm_is_volume" "storage"{ - name = "volume" - profile = "10iops-tier" - zone = "us-south-1" -} - -data "ibm_container_vpc_cluster" "cluster" { - name = ibm_container_vpc_cluster.cluster.id -} - -resource "ibm_container_storage_attachment" "volume_attach"{ - volume = ibm_is_volume.storage.id - cluster = ibm_container_vpc_cluster.cluster.id - worker = data.ibm_container_vpc_cluster.cluster.workers[0] -} -``` - -## Timeouts - -The ibm_container_storage_attachment provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: - -* `Create` - (Default 15 minutes) Used for creating storage attachment Instance. -* `Delete` - (Default 10 minutes) Used for deleting storage attachment Instance. - - -## Argument reference - -Review the argument references that you can specify for your resource. - -* `cluster` - (Required, Forces new resource, String) The name or ID of the cluster. -* `volume` - (Required, Forces new resource, String) The ID of the VPC block volume. -* `worker` - (Required, Forces new resource, String) The ID of the VPC cluster worker node. - - -## Attribute reference - -In addition to all argument reference list, you can access the following attribute reference after your resource is created. - -* `id` - The unique identifier of the worker storage resource. The id is composed of /. -* `status` - (String) The volume attachment status. -* `volume_attachment_id` - (String) The volume attachment ID. -* `volume_attachment_name` - (String) The volume attachment name. -* `volume_type` - (String) The volume attachment type. - -## Import - -The ibm_container_storage_attachment can be imported using `cluster_name_id`, `worker_id` and `volume_attachment_id` - -Example - -``` -$ terraform import ibm_container_storage_attachment.example mycluster/kube-c08evsgd0anad0v8c76g-gen2newvpc-default-00000116/5c4f4d06e0dc402084922dea70850e3b-7cafe35 -``` \ No newline at end of file diff --git a/website/docs/r/container_worker_pool_zone_attachment.html.markdown b/website/docs/r/container_worker_pool_zone_attachment.html.markdown index 12757aeec..fc46c5e3d 100644 --- a/website/docs/r/container_worker_pool_zone_attachment.html.markdown +++ b/website/docs/r/container_worker_pool_zone_attachment.html.markdown @@ -57,8 +57,8 @@ The `ibm_container_worker_pool_zone_attachment` provides the following [Timeouts Review the argument references that you can specify for your resource. - `cluster` - (Required, Forces new resource, String)The name or ID of the cluster that the worker pool belongs to. -- `private_vlan_id` - (Optional, String) The ID of the private VLAN that you want to use for the zone. To find available zones, run `ibmcloud ks vlans `. If you do not have a private VLAN for that zone, do not specify this option. A private VLAN is automatically created for you. -- `public_vlan_id` - (Optional, String) The ID of the public VLAN that you want to use for the zone. To find available zones, run `ibmcloud ks vlans `. If you do not have a public VLAN for that zone, do not specify this option. A public VLAN is automatically created for you. +- `private_vlan_id` - (Optional, String) The ID of the private VLAN that you want to use for the zone. To find available zones, run `ibmcloud ks vlans --zone `. If you do not have a private VLAN for that zone, do not specify this option. A private VLAN is automatically created for you. +- `public_vlan_id` - (Optional, String) The ID of the public VLAN that you want to use for the zone. To find available zones, run `ibmcloud ks vlans --zone `. If you do not have a public VLAN for that zone, do not specify this option. A public VLAN is automatically created for you. - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group where your cluster is provisioned into. To list resource groups, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. - `wait_till_albs` - (Optional, Bool) When you add a zone to a worker pool, worker nodes are provisioned in that zone with the configuration that you defined in your worker pool. This process and enabling the ALBs on those worker nodes can take a few minutes to complete. To avoid long wait times when you run your Terraform code, you can specify the stage when you want Terraform to mark the zone attachment complete. Set to **true** to wait until all worker nodes are successfully provisioned in the zone that you added to your worker pool and all ALBs are available and healthy. If you want the worker node creation and ALB enablement to continue in the background, set this option to **false**. **Note**: `wait_till_albs` is set only for the first time creation of the resource, modification in the further executes will not any impacts. - `worker_pool` - (Required, Forces new resource, String) The name or ID of the worker pool to which you want to add a zone. diff --git a/website/docs/r/cos_bucket.html.markdown b/website/docs/r/cos_bucket.html.markdown index 3fcb68b56..6ffaa8b39 100644 --- a/website/docs/r/cos_bucket.html.markdown +++ b/website/docs/r/cos_bucket.html.markdown @@ -3,8 +3,8 @@ subcategory: "Object Storage" layout: "ibm" page_title: "IBM : Cloud Object Storage Bucket" -description: |- - Manages IBM Cloud Object Storage bucket. +description: + "Manages IBM Cloud Object Storage bucket." --- # ibm_cos_bucket @@ -39,7 +39,7 @@ resource "ibm_resource_instance" "metrics_monitor" { name = "metrics_monitor" resource_group_id = data.ibm_resource_group.cos_group.id service = "sysdig-monitor" - plan = "graduated-tier " + plan = "graduated-tier" location = "us-south" parameters = { default_receiver = true @@ -53,11 +53,11 @@ resource "ibm_cos_bucket" "standard-ams03" { storage_class = "standard" } -resource "ibm_cos_bucket" "flex-us-south" { - bucket_name = "a-flex-bucket-at-us-south" +resource "ibm_cos_bucket" "smart-us-south" { + bucket_name = "a-smart-bucket-at-us-south" resource_instance_id = ibm_resource_instance.cos_instance.id region_location = "us-south" - storage_class = "flex" + storage_class = "smart" } resource "ibm_cos_bucket" "cold-ap" { @@ -85,11 +85,11 @@ resource "ibm_cos_bucket" "standard-ams03-firewall" { allowed_ip = ["223.196.168.27", "223.196.161.38", "192.168.0.1"] } -resource "ibm_cos_bucket" "flex-us-south-firewall" { - bucket_name = "a-flex-bucket-at-us-south" +resource "ibm_cos_bucket" "smart-us-south-firewall" { + bucket_name = "a-smart-bucket-at-us-south" resource_instance_id = ibm_resource_instance.cos_instance.id single_site_location = "sjc04" - storage_class = "flex" + storage_class = "smart" activity_tracking { read_data_events = true write_data_events = true @@ -158,6 +158,69 @@ resource "ibm_cos_bucket" "expire_rule_cos" { } } +### Configure expire date/days with non current version expiration enabled on COS bucket + +resource "ibm_cos_bucket" "expirebucket" { + bucket_name = "a-bucket-expiredat" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + force_delete = true + object_versioning { + enable = true + } + expire_rule { + rule_id = "a-bucket-expire-rule" + enable = true + date = "2021-11-18" + prefix = "logs/" + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +### Configure clean up expired object delete markers on COS bucket + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-expireddelemarkertest" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } + expire_rule { + rule_id = "my-rule-id-bucket-expired" + enable = true + expired_object_delete_marker = true + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +### Configure abort incomplete multipart upload on COS bucket + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-multipartupload" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = "" + days_after_initiation = 1 + } +} + ### Configure retention rule on COS bucket resource "ibm_cos_bucket" "retention_cos" { @@ -190,57 +253,223 @@ resource "ibm_cos_bucket" "objectversioning" { ``` +# cos satellite bucket + +Create or delete an COS satellite bucket. See the architecture of COS Satellite +https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-about-cos-satellite for more details. We are using existing cos instance to create bucket , so no need to create any cos instance via a terraform. Cos satellite does not support all features see the section **What features are currently supported?** in https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-about-cos-satellite. +IBM Satellite documentation https://cloud.ibm.com/docs/satellite?topic=satellite-getting-started. We are supporting object versioning and expiration features as of now. Firewall is not supported yet. + +## Example usage + +```terraform +data "ibm_resource_group" "group" { + name = "Default" +} + +resource "ibm_satellite_location" "create_location" { + location = var.location + zones = var.location_zones + managed_from = var.managed_from + resource_group_id = data.ibm_resource_group.group.id +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "cos-sat-terraform" + resource_instance_id = data.ibm_resource_instance.cos_instance.id + satellite_location_id = data.ibm_satellite_location.create_location.id + object_versioning { + enable = true + } + expire_rule { + rule_id = "bucket-tf-rule1" + enable = false + days = 20 + prefix = "logs/" + } +} +``` + + +# Key Protect enabled COS bucket + +Create or delete an COS bucket with a key protect root key.For more details about key protect see https://cloud.ibm.com/docs/key-protect?topic=key-protect-about .We need to create and manage root key using **ibm_kms_key** resource. We are using existing cos instance to create bucket , so no need to create any cos instance via a terraform. https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key + +## Example usage + +```terraform +resource "ibm_resource_instance" "kms_instance" { + name = "instance-name" + service = "kms" + plan = "tiered-pricing" + location = "us-south" +} +resource "ibm_kms_key" "test" { + instance_id = ibm_resource_instance.kms_instance.guid + key_name = "key-name" + standard_key = false + force_delete =true +} +resource "ibm_iam_authorization_policy" "policy" { + source_service_name = "cloud-object-storage" + target_service_name = "kms" + roles = ["Reader"] +} +resource "ibm_cos_bucket" "smart-us-south" { + depends_on = [ibm_iam_authorization_policy.policy] + bucket_name = "atest-bucket" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "smart" + key_protect = ibm_kms_key.test.id +} +``` + + +# HPCS enabled COS bucket + +Create or delete a COS bucket with a Hyper Protect Crypto Services (HPCS) root key.For more details about HPCS see https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started .To enable HPCS on a COS bucket, an HPCS instance is required and needs to be initialized by loading the master key to create and manage HPCS keys. For more information on initializing the HPCS instance, see https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-initialize-hsm-recovery-crypto-unit. To create an HPCS instance using terraform, see https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/hpcs. + + +## Example usage + +```terraform +resource ibm_hpcs hpcs { + location = "us-south" + name = "test-hpcs" + plan = "standard" + units = 2 + signature_threshold = 1 + revocation_threshold = 1 + admins { + name = "admin1" + key = "/cloudTKE/1.sigkey" + token = "" + } + admins { + name = "admin2" + key = "/cloudTKE/2.sigkey" + token = "" + } +} +resource "ibm_kms_key" "key" { + instance_id = ibm_hpcs.hpcs.guid + key_name = "key-name" + standard_key = false + force_delete = true +} + +resource "ibm_iam_authorization_policy" "policy1" { + source_service_name = "cloud-object-storage" + target_service_name = "hs-crypto" + roles = ["Reader"] +} +resource "ibm_cos_bucket" "smart-us-south" { + depends_on = [ibm_iam_authorization_policy.policy] + bucket_name = "atest-bucket" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "smart" + key_protect = ibm_kms_key.key.id +} + +``` + + + +# COS One-rate plan +One-rate is one of the plans for cloud object storage instance .The One Rate plan is best suited for active workloads with large amounts of outbound bandwidth relative to storage capacity.For more information, see https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-onerate&mhsrc=ibmsearch_a&mhq=One+rate + +## Example usage + +```terraform +resource "ibm_resource_instance" "cos_instance_onerate" { + name = "cos-instance-onerate" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "cos-one-rate-plan" + location = "global" +} +resource "ibm_cos_bucket" "cos_bucket_onerate" { + bucket_name = "bucket-name" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "onerate_active" + } + + +``` + ## Argument reference Review the argument references that you can specify for your resource. -- `bucket_name` - (Required, String) The name of the bucket. -- `cross_region_location` - (Optional, String) Specify the cross-regional bucket location. Supported values are `us`, `eu`, and `ap`. If you use this parameter, do not set `single_site_location` or `region_location` at the same time. -- `endpoint_type`- (Optional, String) The type of the endpoint either `public` or `private` or `direct` to be used for buckets. Default value is `public`. -- `resource_instance_id` - (Required, String) The ID of the IBM Cloud Object Storage service instance for which you want to create a bucket. -- `region_location` - (Optional, String) The location of a regional bucket. Supported values are `au-syd`, `eu-de`, `eu-gb`, `jp-tok`, `us-east`, `us-south`, `ca-tor`, `jp-osa`, `br-sao`. If you set this parameter, do not set `single_site_location` or `cross_region_location` at the same time. -- `single_site_location` - (Optional, String) The location for a single site bucket. Supported values are: `ams03`, `che01`, `hkg02`, `mel01`, `mex01`, `mil01`, `mon01`, `osl01`, `par01`, `sjc04`, `sao01`, `seo01`, `sng01`, and `tor01`. If you set this parameter, do not set `region_location` or `cross_region_location` at the same time. -- `storage_class` - (Required, String) The storage class that you want to use for the bucket. Supported values are `standard`, `vault`, `cold`, `flex`, and `smart`. For more information, about storage classes, see [Use storage classes](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). +- `abort_incomplete_multipart_upload_days` (Optional,List) Nested block with the following structure. + + Nested scheme for `abort_incomplete_multipart_upload_days`: + - `days_after_initiation` - (Optional, Integer) Specifies the number of days that govern the automatic cancellation of part upload. Clean up incomplete multi-part uploads after a period of time. Must be a value greater than 0 and less than 3650. + - `enable` - (Required, Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (Optional, String) A rule with a prefix will only apply to the objects that match. You can use multiple rules for different actions for different prefixes within the same bucket. + - `rule_id` - (Optional, String) Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket. - `allowed_ip` - (Optional, Array of string) A list of IPv4 or IPv6 addresses in CIDR notation that you want to allow access to your IBM Cloud Object Storage bucket. - `activity_tracking`- (List of objects) Object to enable auditing with IBM Cloud Activity Tracker - Optional - Configure your IBM Cloud Activity Tracker service instance and the type of events that you want to send to your service to audit activity against your bucket. For a list of supported actions, see [Bucket actions](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-at-events#at-actions-mngt-2). Nested scheme for `activity_tracking`: + - `activity_tracker_crn`- (Required, String) The CRN of your IBM Cloud Activity Tracker service instance that you want to send your events to. This value is required only when you configure your instance for the first time. - `read_data_events`- (Required, Bool) If set to **true**, all read events against a bucket are sent to your IBM Cloud Activity Tracker service instance. - `write_data_events`- (Required, Bool) If set to **true**, all write events against a bucket are sent to your IBM Cloud Activity Tracker service instance. - - `activity_tracker_crn`- (Required, String) The CRN of your IBM Cloud Activity Tracker service instance that you want to send your events to. This value is required only when you configure your instance for the first time. -- `metrics_monitoring`- (Object) to enable metrics tracking with IBM Cloud Monitoring - Optional- Set up your IBM Cloud Monitoring service instance to receive metrics for your IBM Cloud Object Storage bucket. - - Nested scheme for `metrics_monitoring`: - - `usage_metrics_enabled` : (Optional, Bool) If set to **true**, all usage metrics that is `bytes_used` is sent to the monitoring service.e. - - `request_metrics_enabled` : (Optional, Bool) If set to **true**, all request metrics `ibm_cos_bucket_all_request` is sent to the monitoring service `@1mins` granulatiy. - - `metrics_monitoring_crn` - (Required, string) Required the first time `metrics_monitoring` is configured. The instance of IBM Cloud Monitoring receives the bucket metrics. - - **Note:** - - Request metrics are supported in all regions and console has the support. For more details check the [cloud documention](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-mm-cos-integration). - - One of the location option must be present. - `archive_rule` - (Required, List) Nested archive_rule block has following structure. Nested scheme for `archive_rule`: - - `days` - (Required, String) Specifies the number of days when the specific rule action takes effect. + - `days` - (Required, Integer) Specifies the number of days when the specific rule action takes effect. - `enable` - (Required, Bool) Specifies archive rule status either `enable` or `disable` for a bucket. - `rule_id` - (Optional, Computed, String) The unique ID for the rule. Archive rules allow you to set a specific time frame after the objects transition to the archive. - `type` - (Required, String) Specifies the storage class or archive type to which you want the object to transition. Allowed values are `Glacier` or `Accelerated`. - **Note:** Archive is available in certain regions only. For more information, see [Integrated Services](https://cloud.ibm.com/docs/cloud-object-storage/basics?topic=cloud-object-storage-service-availability). -- `expire_rule` - (Required, List) Nested expire_rule block has following structure. + **Note:** + - Archive is available in certain regions only. For more information, see [Integrated Services](https://cloud.ibm.com/docs/cloud-object-storage/basics?topic=cloud-object-storage-service-availability). + - Restoring object once archive is not supported yet. +- `bucket_name` - (Required, String) The name of the bucket. +- `cross_region_location` - (Optional, String) Specify the cross-regional bucket location. Supported values are `us`, `eu`, and `ap`. If you use this parameter, do not set `single_site_location` or `region_location` at the same time. +- `endpoint_type`- (Optional, String) The type of the endpoint either `public` or `private` or `direct` to be used for buckets. Default value is `public`. +- `expire_rule` - (Required, List) An expiration rule deletes objects after a defined period (from the object creation date). see [lifecycle actions](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). Nested expire_rule block has following structure. Nested scheme for `expire_rule`: - - `rule_id` - (Optional, Computed, String) Unique ID for the rule. Expire rules allow you to set a specific time frame after which objects are deleted. + - `days` - (Optional, Integer) Specifies the number of days when the specific rule action takes effect. + - `date` - (Optional, String) After the specifies date , the current version of objects in your bucket expires. - `enable` - (Required, Bool) Specifies expire rule status either `enable` or `disable` for a bucket. - - `days` - (Required, String) Specifies the number of days when the specific rule action takes effect. + - `expired_object_delete_marker` - (Optional, String) Expired object delete markers can be automatically cleaned up to improve performance in your bucket. This cannot be used alongside version expiration. This element for the Expiration action which will only remove delete markers that have no non-current versions at all & objects whose only version is a single delete marker. - `prefix` - (Optional, String) Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. + - `rule_id` - (Optional, Computed, String) Unique ID for the rule. Expire rules allow you to set a specific time frame after which objects are deleted. - **Note:** Both `archive_rule` and `expire_rule` must be managed by Terraform as they use the same lifecycle configuration. If user creates any of the rule outside of Terraform by using command line or console, you can see unexpected difference like removal of any of the rule or one rule overrides another. The policy cannot match as expected due to API limitations, as the lifecycle is a single API request for both archive and expire. + **Note:** + - Both `archive_rule` and `expire_rule` must be managed by Terraform as they use the same lifecycle configuration. If user creates any of the rule outside of Terraform by using command line or console, you can see unexpected difference like removal of any of the rule or one rule overrides another. The policy cannot match as expected due to API limitations, as the lifecycle is a single API request for both archive and expire. + - When versioning is enabled/suspended, regular object expiration will no longer remove objects, instead it will create a delete marker, unless the current version is already a delete marker, then nothing happens. If the only version of the object is a delete marker, then the delete marker is removed after X days, or on a specific date. + - expired_object_delete_marker element can not be used in conjunction with other expiry action elements (Days or Date). + - The expiry 3 action elements (Days, Date, ExpiredObjectDeleteMarker) are all mutually exclusive.Anyone parameter can apply among 3 (Days, Date, ExpiredObjectDeleteMarker) in expire_rule. + - You cannot specify both a Days and ExpiredObjectDeleteMarker tag on the same rule. Specifying the Days tag will automatically perform ExpiredObjectDeleteMarker cleanup once delete markers are old enough to satisfy the age criteria. You can create a separate rule with only the tag ExpiredObjectDeleteMarker to clean up delete markers as soon as they become the only version. - `force_delete`- (Optional, Bool) As the default value set to **true**, it will delete all the objects in the COS Bucket and then delete the bucket. - **Note:** `force_delete` will timeout on buckets with a large amount of objects. 24 hours before you delete the bucket you can set an expire rule to remove all the files over a day old. + **Note:** `force_delete` will timeout on buckets with a large amount of objects. 24 hours before you delete the bucket you can set an expire rule to remove all the files over a day old. +- `hard_quota` - (Optional, Integer) Sets a maximum amount of storage (in bytes) available for a bucket. For more information, check the [cloud documention](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-quota). - `key_protect` - (Optional, String) The CRN of the IBM Key Protect root key that you want to use to encrypt data that is sent and stored in IBM Cloud Object Storage. Before you can enable IBM Key Protect encryption, you must provision an instance of IBM Key Protect and authorize the service to access IBM Cloud Object Storage. For more information, see [Server-Side Encryption with IBM Key Protect or Hyper Protect Crypto Services (SSE-KP)](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-encryption). -- `object_versioning` - (List) Nested block have the following structure: +- `metrics_monitoring`- (Object) to enable metrics tracking with IBM Cloud Monitoring - Optional- Set up your IBM Cloud Monitoring service instance to receive metrics for your IBM Cloud Object Storage bucket. + + Nested scheme for `metrics_monitoring`: + - `metrics_monitoring_crn` - (Required, string) Required the first time `metrics_monitoring` is configured. The instance of IBM Cloud Monitoring receives the bucket metrics. + - `request_metrics_enabled` : (Optional, Bool) If set to **true**, all request metrics `ibm_cos_bucket_all_request` is sent to the monitoring service `@1mins` granulatiy. + - `usage_metrics_enabled` : (Optional, Bool) If set to **true**, all usage metrics that is `bytes_used` is sent to the monitoring service.e. + + **Note:** + - Request metrics are supported in all regions and console has the support. For more details check the [cloud documention](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-mm-cos-integration). + - One of the location option must be present. +- `noncurrent_version_expiration` - (Required, List) lifecycle has a versioning related expiration action: non-current version expiration. This can remove old versions of objects after they've been non-current for a specified number of days which is specified with a NoncurrentDays parameter on the rule. see [lifecycle actions](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). Nested noncurrent_version_expiration block has following structure. + + Nested scheme for `noncurrent_version_expiration`: + - `enable` - (Requried, Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `noncurrent_days` - (Optional, Integer) Configuration parameter in your policy that says how long to retain a non-current version before deleting it. Must be greater than 0. + - `prefix` - (Optional, String) The rule applies to any objects with keys that match this prefix. You can use multiple rules for different actions for different prefixes within the same bucket. + - `rule_id` - (Optional, String) Unique identifier for the rule. Rules allow you to remove versions from objects. Set Rule ID for cos bucket. +- `object_versioning` - (List) Object Versioning allows the COS user to keep multiple versions of an objet in a bucke to protect against accidental deletion or overwrites. With versioning, you can easilyrecover from both unintended user actions and application failure. Nested block have the following structure: Nested scheme for `object_versioning`: - `enable` : (Optional, Bool) Specifies Versioning status either enable or Suspended for the objects in the bucket.Default value set to false. @@ -250,11 +479,12 @@ Review the argument references that you can specify for your resource. - If cos bucket has versioning enabled and set to false, versioning will be suspended. - Versioning can only be suspended, we cannot disabled once after it is enabled. - To permanently delete individual versions of an object, a delete request must specify a version ID. - - Containers with object expiry cannot have versioning enabled or suspended, and containers with versioning enabled or suspended cannot have expiry lifecycle actions enabled to them. - COS Object versioning and COS Bucket Protection `(WORM)` cannot be used together. - Containers with proxy configuration cannot use versioning and vice versa. - SoftLayer accounts cannot use versioning. - Currently, you cannot support `MFA_Delete`, that is a feature to add additional security to version delete. +- `region_location` - (Optional, String) The location of a regional bucket. Supported values are `au-syd`, `eu-de`, `eu-gb`, `jp-tok`, `us-east`, `us-south`, `ca-tor`, `jp-osa`, `br-sao`. If you set this parameter, do not set `single_site_location` or `cross_region_location` at the same time. +- `resource_instance_id` - (Required, String) The ID of the IBM Cloud Object Storage service instance for which you want to create a bucket. - `retention_rule` - (List) Nested block have the following structure: Nested scheme for `retention rule`: @@ -268,7 +498,9 @@ Review the argument references that you can specify for your resource. - The minimum retention period must be less than or equal to the default retention period, that in turn must be less than or equal to the maximum retention period. - Permanent retention can only be enabled at a IBM Cloud Object Storage bucket level with retention policy enabled and users are able to select the permanent retention period option during object uploads. Once enabled, this process can't be reversed and objects uploaded that use a permanent retention period cannot be deleted. It's the responsibility of the users to validate at their end if there's a legitimate need to permanently store objects by using Object Storage buckets with a retention policy. - force deleting the bucket will not work if any object is still under retention. As objects cannot be deleted or overwritten until the retention period has expired and all the legal holds have been removed. -- `hard_quota` - (Optional, Integer) Sets a maximum amount of storage (in bytes) available for a bucket. For more information, check the [cloud documention](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-quota). +- `single_site_location` - (Optional, String) The location for a single site bucket. Supported values are: `ams03`, `che01`, `hkg02`, `mel01`, `mex01`, `mil01`, `mon01`, `osl01`, `par01`, `sjc04`, `sao01`, `seo01`, `sng01`, and `tor01`. If you set this parameter, do not set `region_location` or `cross_region_location` at the same time. +- `storage_class` - (Optional, String) The storage class that you want to use for the bucket. Supported values are `standard`, `vault`, `cold` and `smart` for `standard` and `lite` COS plans, `onerate_active` for `cos-one-rate-plan` COS plan.For more information, about storage classes, see [Use storage classes](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes).`storage_class` should not be used with Satellite location id. +- `satellite_location_id` - (Optional, String) satellite location id. Provided by end users. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -281,8 +513,11 @@ In addition to all argument reference list, you can access the following attribu - `resource_instance_id` - (String) The ID of IBM Cloud Object Storage instance. - `single_site_location` - (String) The location if you created a single site bucket. - `storage_class` - (String) The storage class of the bucket. +- `s3_endpoint_public` - (String) Public endpoint for cos bucket. +- `s3_endpoint_private` - (String) Private endpoint for cos bucket. +- `s3_endpoint_direct` - (String) Direct endpoint for cos bucket. -## Import +## Import IBM COS Bucket The `ibm_cos_bucket` resource can be imported by using the `id`. The ID is formed from the `CRN` (Cloud Resource Name), the `bucket type` which must be `ssl` for single_site_location, `rl` for region_location or `crl` for cross_region_location, and the bucket location. The `CRN` and bucket location can be found on the portal. id = `$CRN:meta:$buckettype:$bucketlocation` @@ -301,3 +536,16 @@ $ terraform import ibm_cos_bucket.mybucket `$CRN:meta:$buckettype:$bucketlocatio $ terraform import ibm_cos_bucket.mybucket crn:v1:bluemix:public:cloud-object-storage:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:bucket:mybucketname:meta:crl:eu:public ``` + +## Import COS Satelllite Bucket +The `cos satellite bucket` resource can be imported by using the `id`. The ID is formed from the `CRN` (Cloud Resource Name), the `satellite_location_id` which must be `sl` for satellite_location_id and the bucket location. The `CRN` and bucket location can be found on the portal. + +id = `$CRN:meta:$buckettype:$bucketlocation` + +**Example** + +``` + +$ terraform import ibm_cos_bucket.cos_bucket crn:v1:staging:public:cloud-object-storage:satloc_dal_c8fctn320qtrspbisg80:a/81ee25188545f05150650a0a4ee015bb:a2deec95-0836-4720-bfc7-ca41c28a8c66:bucket:tf-listbuckettest:meta:sl:c8fctn320qtrspbisg80:public + +``` \ No newline at end of file diff --git a/website/docs/r/cos_bucket_object.html.markdown b/website/docs/r/cos_bucket_object.html.markdown index dd032f465..e59ec4802 100644 --- a/website/docs/r/cos_bucket_object.html.markdown +++ b/website/docs/r/cos_bucket_object.html.markdown @@ -61,7 +61,7 @@ Review the argument references that you can specify for your resource. - `bucket_crn` - (Required, Forces new resource, String) The CRN of the COS bucket. - `bucket_location` - (Required, Forces new resource, String) The location of the COS bucket. - `content` - (Optional, String) Literal string value to use as an object content, which will be uploaded as UTF-8 encoded text. Conflicts with `content_base64` and `content_file`. -- `content_base64` - (Optional, String) Base64-encoded data that will be decoded and uploaded as raw bytes for an object content. This safely uploads non-UTF8 binary data, but is recommended only for small content. Conflicts with `content` and `content_file`. +- `content_base64` - (Optional, String) Base64-encoded data that will be decoded and uploaded as raw bytes for an object content. This safely uploads `non-UTF8` binary data, but is recommended only for small content. Conflicts with `content` and `content_file`. - `content_file` - (Optional, String) The path to a file that will be read and uploaded as raw bytes for an object content. Conflicts with `content` and `content_base64`. - `endpoint_type` - (Optional, String) The type of endpoint used to access COS. Supported values are `public`, `private`, or `direct`. Default value is `public`. - `etag` - (Optional, String) MD5 hexdigest used to trigger updates. The only meaningful value is `filemd5("path/to/file")`. diff --git a/website/docs/r/cos_replication.html.markdown b/website/docs/r/cos_replication.html.markdown new file mode 100644 index 000000000..e8ba249a7 --- /dev/null +++ b/website/docs/r/cos_replication.html.markdown @@ -0,0 +1,176 @@ +--- + +subcategory: "Object Storage" +layout: "ibm" +page_title: "IBM : Cloud Object Storage Bucket Replication" +description: + "Manages IBM Cloud Object Storage Bucket Replication." +--- + +# ibm_cos_bucket_replication_rule +Create/replaces or delete replication configuration on an existing bucket. For more information, about configuration options, see [Replicating objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-replication-overview). + +To configure a replication policy on a bucket, you must enable object versioning on both source and destination buckets by using the [Versioning objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). + +**Note:** + + you must have `writer` or `manager` platform roles on source bucket and sufficient platform roles to create new [IAM policies](https://cloud.ibm.com/docs/account?topic=account-iamoverview#iamoverview) that allow the source bucket to write to the destination bucket. + Add depends_on on ibm_iam_authorization_policy.policy in template to make sure replication only enabled once iam authorization policy set. + We are addressing Create functionality for replication now. Update functionality will be in-progress. + + +--- + +## Example usage +The following example creates an instance of IBM Cloud Object Storage. Then, multiple buckets are created and configured replication policy. + +```terraform +data "ibm_resource_group" "cos_group" { + name = "cos-resource-group" +} + +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "a-bucket-source" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "a-bucket-destination" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + + +### Configure IAM authorization policy + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "an-account-id" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + value = "an-account-id" + } + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + value = "bucket" + } +} + +### Configure replication policy + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "a-rule-id" + enable = "true" + prefix = "a-prefix" + priority = "a-priority-associated-with-the-rule" + deletemarker_replication_status = "Enabled/Suspened" + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } +} + +``` + +## Argument reference +Review the argument references that you can specify for your resource. +- `bucket_crn` - (Required, Forces new resource, String) The CRN of the COS bucket. +- `bucket_location` - (Required, Forces new resource, String) The location of the COS bucket. +- `endpoint_type`- (Optional, String) The type of the endpoint either `public` or `private` or `direct` to be used for buckets. Default value is `public`. +- `replication_rule`- (Required, List) Nested block have the following structure: + + Nested scheme for `replication_rule`: + - `rule_id`- (Optional, String) The rule id. + - `enable`- (Required, Bool) Specifies whether the rule is enabled. Specify true for Enabling it or false for Disabling it. + - `prefix`- (Optional, String) An object key name prefix that identifies the subset of objects to which the rule applies. + - `priority`- (Optional, Int) A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority + - `deletemarker_replication_status`- (Optional, Bool) Specifies whether Object storage replicates delete markers.Specify true for Enabling it or false for Disabling it. + - `destination_bucket_crn`- (Required, String) The CRN of your destination bucket that you want to replicate to. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The CRN of the bucket. +- `id` - (String) The ID of the bucket. + +## Import IBM COS Bucket +The `ibm_cos_bucket_replication_rule` resource can be imported by using the `id`. The ID is formed from the `CRN` (Cloud Resource Name). The `CRN` and bucket location can be found on the portal. + +id = `$CRN:meta:$bucketlocation:$endpointtype` + +**Syntax** + +``` +$ terraform import ibm_cos_bucket_replication_rule.mybucket `$CRN:meta:$bucketlocation:public` + +``` + +**Example** + +``` + +$ terraform import ibm_cos_bucket_replication_rule.mybucket crn:v1:bluemix:public:cloud-object-storage:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:bucket:mybucketname:meta:us-south:public + +``` \ No newline at end of file diff --git a/website/docs/r/cr_namespace.html.markdown b/website/docs/r/cr_namespace.html.markdown index 062598c83..539d4c4a2 100644 --- a/website/docs/r/cr_namespace.html.markdown +++ b/website/docs/r/cr_namespace.html.markdown @@ -10,7 +10,7 @@ subcategory: "Container Registry" Create or delete a Container Registry namespace. For more information about Container Registry, see [About IBM Cloud Container Registry](https://cloud.ibm.com/docs/Registry?topic=Registry-registry_overview). -## Example Usage +## Example usage The following example shows how you can configure a `namespace`. @@ -28,7 +28,7 @@ resource "ibm_cr_namespace" "rg_namespace" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: @@ -37,7 +37,7 @@ The following arguments are supported: - `resource_group_id` - (Optional, Forces new resource, string) The ID of the resource group to which you want to add the namespace. If you don't set this option, the default resource group for the account is used. - `tags` - (Optional, array of strings) The tags that are associated with the `ibm_cr_namespace`. **Note*- `Tags` are managed locally and not stored on the IBM Cloud service endpoint. -## Attribute Reference +## Attribute reference In addition to the attributes in the argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/cr_retention_policy.html.markdown b/website/docs/r/cr_retention_policy.html.markdown index c60bc1c8b..671ad0538 100644 --- a/website/docs/r/cr_retention_policy.html.markdown +++ b/website/docs/r/cr_retention_policy.html.markdown @@ -8,9 +8,9 @@ subcategory: "Container Registry" # ibm_cr_retention_policy -Provides a resource for ibm_cr_retention_policy. You can use this resource to create, update, and delete a retention policy. +Create, update, and delete about the IBM Cloud Container Registry retention policy resource. For more information, about IBM Cloud Container Registry retention policy, see [Managing access for Container Registry](https://cloud.ibm.com/docs/Registry?topic=Registry-iam). -## Example Usage +## Example usage ```terraform resource "ibm_cr_retention_policy" "cr_retention_policy" { @@ -20,17 +20,17 @@ resource "ibm_cr_retention_policy" "cr_retention_policy" { } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +Review the argument references that you can specify for your resource. -- `namespace` - (Required, string) The namespace to which the retention policy is attached. -- `images_per_repo` - (Required, int) Determines how many images are retained in each repository when the retention policy is processed. The value -1 denotes 'Unlimited' (all images are retained). -- `retain_untagged` - (Optional, bool) Determines whether untagged images are retained when the retention policy is processed. The value is false by default, which means that untagged images can be deleted when the policy runs. +- `namespace` - (Required, String) The namespace to which the retention policy is attached. +- `images_per_repo` - (Required, Integer) Determines how many images are retained in each repository when the retention policy is processed. The value `-1` denotes `Unlimited` (all images are retained). +- `retain_untagged` - (Optional, Bool) Determines whether untagged images are retained when the retention policy is processed. Default value is **false**, means untagged images can be deleted when the policy runs. -## Attribute Reference +## Attribute reference -In addition to the arguments in the Argument Reference section, the following attributes are exported: +In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - The unique identifier of the cr_retention_policy. This identifier is the same as the name of namespace to which the retention policy is attached. diff --git a/website/docs/r/database.html.markdown b/website/docs/r/database.html.markdown index 46014e74c..df23817e9 100644 --- a/website/docs/r/database.html.markdown +++ b/website/docs/r/database.html.markdown @@ -8,9 +8,9 @@ description: |- # ibm_database -Create, update, or delete a IBM Cloud Database (ICD) instance. The `ibmcloud_api_key` that are used by Terraform should grant IAM rights to create and modify IBM Cloud Databases and have access to the resource group the ICD instance is associated with. For more information, see [documentation](https://cloud.ibm.com/docs/services/databases-for-postgresql/reference-access-management.html#identity-and-access-management) to manage ICD instances. +Create, update, or delete a IBM Cloud Database (ICD) instance. The `ibmcloud_api_key` that are used by Terraform should grant IAM rights to create and modify IBM Cloud Databases and have access to the resource group the ICD instance is associated with. For more information, see [documentation](https://cloud.ibm.com/docs/services/databases-for-postgresql/reference-access-management.html#identity-and-access-management) to manage ICD instances. -If `resource_group_id` is not specified, the ICD instance is created in the default resource group. The `API_KEY` must be assigned permissions for this group. +If `resource_group_id` is not specified, the ICD instance is created in the default resource group. The `API_KEY` must be assigned permissions for this group. Configuration of an ICD resource requires that the `region` parameter is set for the IBM provider in the `provider.tf` to be the same as the target ICD `location/region`. If not specified it default to `us-south`. A `terraform apply` fails if the ICD `location` is set differently. If the Terraform configuration needs to deploy resources into multiple regions, provider alias can be used. For more information, see [Terraform provider configuration](https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances). @@ -32,11 +32,27 @@ resource "ibm_database" "" { tags = ["tag1", "tag2"] adminpassword = "password12" - members_memory_allocation_mb = 3072 - members_disk_allocation_mb = 61440 + + group { + group_id = "member" + + memory { + allocation_mb = 14336 + } + + disk { + allocation_mb = 20480 + } + + cpu { + allocation_count = 3 + } + } + users { name = "user123" password = "password12" + type = "database" } whitelist { address = "172.168.1.1/32" @@ -45,12 +61,13 @@ resource "ibm_database" "" { } output "ICD Etcd database connection string" { - value = "http://${ibm_database.test_acc.connectionstrings[0].composed}" + value = "http://${ibm_database.test_acc.ibm_database_connection.icd_conn}" } ``` -### Sample database instance by using `node_` attributes +### **Deprecated** Sample database instance by using `node_` attributes +Please Note this has been deprecated: Please use the `group` attribute instead An example to configure and deploy database by using `node_` attributes instead of `memory_`. ```terraform @@ -70,10 +87,62 @@ resource "ibm_database" "" { node_count = 3 node_memory_allocation_mb = 1024 node_disk_allocation_mb = 20480 + users { + name = "user123" + password = "password12" + type = "database" + } + whitelist { + address = "172.168.1.1/32" + description = "desc" + } +} + +output "ICD Etcd database connection string" { + value = "http://${ibm_database.test_acc.ibm_database_connection.icd_conn}" +} + +``` + +### Sample database instance by using `group` attributes +An example to configure and deploy database by using `group` attributes. + +```terraform +data "ibm_resource_group" "group" { + name = "" +} + +resource "ibm_database" "" { + name = "" + plan = "standard" + location = "eu-gb" + service = "databases-for-etcd" + resource_group_id = data.ibm_resource_group.group.id + tags = ["tag1", "tag2"] + + adminpassword = "password12" + + group { + group_id = "member" + + memory { + allocation_mb = 10240 + } + + disk { + allocation_mb = 256000 + } + + cpu { + allocation_count = 3 + } + } + users { name = "user123" password = "password12" } + whitelist { address = "172.168.1.1/32" description = "desc" @@ -81,7 +150,7 @@ resource "ibm_database" "" { } output "ICD Etcd database connection string" { - value = "http://${ibm_database.test_acc.connectionstrings[0].composed}" + value = "http://${ibm_database.test_acc.ibm_database_connection.icd_conn}" } ``` @@ -147,8 +216,8 @@ resource "ibm_database" "autoscale" { } } ``` -### Sample cassandra database instance -Cassandra takes more time than expected. It is always advisible to extend timeouts using timeouts block +### Sample Cassandra database instance +* Cassandra provisioning may require more time than the default timeout. A longer timeout value can be set with using the `timeouts` attribute. ```terraform data "ibm_resource_group" "test_acc" { @@ -162,11 +231,25 @@ resource "ibm_database" "cassandra" { plan = "enterprise" location = "us-south" adminpassword = "password12" - members_memory_allocation_mb = 36864 - members_disk_allocation_mb = 61440 + group { + group_id = "member" + + memory { + allocation_mb = 24576 + } + + disk { + allocation_mb = 368640 + } + + cpu { + allocation_count = 6 + } + } users { - name = "user123" - password = "password12" + name = "user123" + password = "password12" + type = "database" } whitelist { address = "172.168.1.2/32" @@ -180,10 +263,10 @@ resource "ibm_database" "cassandra" { } } ``` -### Sample enterprise mongo database instance -* Enterprise MongoDB takes more time than expected. It is always advisible to extend timeouts using timeouts block. +### Sample MongoDB Enterprise database instance +* MongoDB Enterprise provisioning may require more time than the default timeout. A longer timeout value can be set with using the `timeouts` attribute. * Please make sure your resources meet minimum requirements of scaling. Please refer [docs](https://cloud.ibm.com/docs/databases-for-mongodb?topic=databases-for-mongodb-pricing#scaling-per-member) for more info. -* `serive_endpoints` cannot be updated on this instance. +* `service_endpoints` cannot be updated on this instance. ```terraform data "ibm_resource_group" "test_acc" { @@ -197,12 +280,34 @@ resource "ibm_database" "mongodb" { plan = "enterprise" location = "us-south" adminpassword = "password12" - members_disk_allocation_mb = 61440 - members_memory_allocation_mb = 43008 + + group { + group_id = "member" + + memory { + allocation_mb = 24576 + } + + disk { + allocation_mb = 122880 + } + + cpu { + allocation_count = 6 + } + } + tags = ["one:two"] users { - name = "user123" - password = "password12" + name = "dbuser" + password = "password12" + type = "database" + } + users { + name = "opsmanageruser" + password = "$ecurepa$$word12" + type = "ops_manager" + role = "group_read_only" } whitelist { address = "172.168.1.2/32" @@ -215,6 +320,83 @@ resource "ibm_database" "mongodb" { } } ``` + +### Sample MongoDB Enterprise database instance with BI Connector and Analytics +* To enable Analytics and/or BI Connector for MongoDB Enterprise, a `group` attribute must be defined for the `analytics` and `bi_connector` group types with `members` scaled to at exactly `1`. +* MongoDB Enterprise provisioning may require more time than the default timeout. A longer timeout value can be set with using the `timeouts` attribute. + +```terraform +data "ibm_resource_group" "test_acc" { + is_default = true +} + +resource "ibm_database" "mongodb_enterprise" { + resource_group_id = data.ibm_resource_group.test_acc.id + name = "test" + service = "databases-for-mongodb" + plan = "enterprise" + location = "us-south" + adminpassword = "password12" + tags = ["one:two"] + + group { + group_id = "member" + + memory { + allocation_mb = 24576 + } + + disk { + allocation_mb = 122880 + } + + cpu { + allocation_count = 6 + } + } + + group { + group_id = "analytics" + + members { + allocation_count = 1 + } + } + + group { + group_id = "bi_connector" + + members { + allocation_count = 1 + } + } + + timeouts { + create = "120m" + update = "120m" + delete = "15m" + } +} + +data "ibm_database_connection" "mongodb_conn" { + deployment_id = ibm_database.mongodb_enterprise.id + user_type = "database" + user_id = "admin" + endpoint_type = "public" +} + +output "bi_connector_connection" { + description = "BI Connector connection string" + value = data.ibm_database_connection.mongodb_conn.bi_connector.0.composed.0 +} + +output "analytics_connection" { + description = "Analytics Node connection string" + value = data.ibm_database_connection.mongodb_conn.analytics.0.composed.0 +} + +``` + ### Sample EDB instance EDB takes more time than expected. It is always advisible to extend timeouts using timeouts block @@ -230,12 +412,26 @@ resource "ibm_database" "edb" { plan = "standard" location = "us-south" adminpassword = "password12" - members_memory_allocation_mb = 3072 - members_disk_allocation_mb = 61440 + group { + group_id = "member" + + memory { + allocation_mb = 12288 + } + + disk { + allocation_mb = 131072 + } + + cpu { + allocation_count = 3 + } + } tags = ["one:two"] users { - name = "user123" - password = "password12" + name = "user123" + password = "password12" + type = "database" } whitelist { address = "172.168.1.2/32" @@ -247,6 +443,41 @@ resource "ibm_database" "edb" { delete = "15m" } } +``` +### Updating configuration for postgres database + +```terraform +data "ibm_resource_group" "test_acc" { + is_default = true +} + +resource "ibm_database" "db" { + location = "us-east" + group { + group_id = "member" + + memory { + allocation_mb = 12288 + } + + disk { + allocation_mb = 131072 + } + + cpu { + allocation_count = 3 + } + } + name = "telus-database" + service = "databases-for-postgresql" + plan = "standard" + configuration = <:backup:`. If omitted, the database is provisioned empty. - `backup_encryption_key_crn`- (Optional, Forces new resource, String) The CRN of a key protect key, that you want to use for encrypting disk that holds deployment backups. A key protect CRN is in the format `crn:v1:<...>:key:`. Backup_encryption_key_crn can be added only at the time of creation and no update support are available. +- `configuration` - (Optional, Json String) Database Configuration in JSON format. Supported services `databases-for-postgresql`, `databases-for-redis` and `databases-for-enterprisedb`. For valid values please refer [API docs](https://cloud.ibm.com/apidocs/cloud-databases-api/cloud-databases-api-v4#setdatabaseconfiguration-request). - `guid` - (Optional, String) The unique identifier of the database instance. - `key_protect_key` - (Optional, Forces new resource, String) The root key CRN of a Key Management Services like Key Protect or Hyper Protect Crypto Service (HPCS) that you want to use for disk encryption. A key CRN is in the format `crn:v1:<…>:key:`. You can specify the root key during the database creation only. After the database is created, you cannot update the root key. For more information, refer [Disk encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect#using-the-key-protect-key) documentation. - `key_protect_instance` - (Optional, Forces new resource, String) The instance CRN of a Key Management Services like Key Protect or Hyper Protect Crypto Service (HPCS) that you want to use for disk encryption. An instance CRN is in the format `crn:v1:<…>::`. - `location` - (Required, String) The location where you want to deploy your instance. The location must match the `region` parameter that you specify in the `provider` block of your Terraform configuration file. The default value is `us-south`. Currently, supported regions are `us-south`, `us-east`, `eu-gb`, `eu-de`, `au-syd`, `jp-tok`, `oslo01`. -- `members_memory_allocation_mb` - (Optional, Integer) The amount of memory in megabytes for the database, split across all members. If not specified, the default setting of the database service is used, which can vary by database type. -- `members_disk_allocation_mb` - (Optional, Integer) The amount of disk space for the database, split across all members. If not specified, the default setting of the database service is used, which can vary by database type. -- `members_cpu_allocation_count` - (Optional, Integer) Enables and allocates the number of specified dedicated cores to your deployment. -- `node_count` - (Optional, Integer) The total number of nodes in the cluster. If not specified defaults to the database minimum node count. These vary by database type. See the documentation related to each database for the defaults. https://cloud.ibm.com/docs/services/databases-for-postgresql/howto-provisioning.html#list-of-additional-parameters -- `node_cpu_allocation_count` - (Optional, Integer) Enables and allocates the number of specified dedicated cores to your deployment per node. -- `node_disk_allocation_mb` - (Optional, Integer) The disk size of the database per node. As above. -- `node_memory_allocation_mb` - (Optional,Integer) The memory size for the database per node. If not specified defaults to the database default. These vary by database type. See the documentation related to each database for the defaults. https://cloud.ibm.com/docs/services/databases-for-postgresql/howto-provisioning.html#list-of-additional-parameters - - ~> **Note:** `members_memory_allocation_mb`, `members_disk_allocation_mb`, `members_cpu_allocation_count` conflicts with `node_count`,`node_cpu_allocation_count`, `node_disk_allocation_mb`, `node_memory_allocation_mb` Either members or node arguments has to be provided +- `group` - (Optional, Set) A set of group scaling values for the database. Multiple blocks are allowed. Can only be performed on is_adjustable=true groups. Values set are per-member. Values must be greater than or equal to the minimum size and must be a multiple of the step size. + + Nested scheme for `group`: + - `group_id` - (Optional, String) The ID of the scaling group. + + - `members` (Set, Optional) + + Nested scheme for `members`: + - `allocation_count` - (Optional, Integer) Allocated number of members. + + - `memory` (Set, Optional) Memory Auto Scaling in single block of memory is allowed at once. + + Nested scheme for `memory`: + - `allocation_mb` - (Optional, Integer) Allocated memory per-member. + + - `disk` (Set, Optional) + + Nested scheme for `disk`: + - `allocation_mb` - (Optional, Integer) Allocated disk per-member. + + - `cpu` (Set, Optional) + + Nested scheme for `cpu`: + - `allocation_count` - (Optional, Integer) Allocated dedicated CPU per-member. + +- `members_memory_allocation_mb` **Deprecated** - (Optional, Integer) The amount of memory in megabytes for the database, split across all members. If not specified, the default setting of the database service is used, which can vary by database type. +- `members_disk_allocation_mb` **Deprecated** - (Optional, Integer) The amount of disk space for the database, split across all members. If not specified, the default setting of the database service is used, which can vary by database type. +- `members_cpu_allocation_count` **Deprecated** - (Optional, Integer) Enables and allocates the number of specified dedicated cores to your deployment. +- `node_count` **Deprecated** - (Optional, Integer) The total number of nodes in the cluster. If not specified defaults to the database minimum node count. These vary by database type. See the documentation related to each database for the defaults. https://cloud.ibm.com/docs/databases-for-postgresql?topic=cloud-databases-provisioning#provisioning-parameters +- `node_cpu_allocation_count` **Deprecated** - (Optional, Integer) Enables and allocates the number of specified dedicated cores to your deployment per node. +- `node_disk_allocation_mb` **Deprecated** - (Optional, Integer) The disk size of the database per node. As above. +- `node_memory_allocation_mb` **Deprecated** - (Optional,Integer) The memory size for the database per node. If not specified defaults to the database default. These vary by database type. See the documentation related to each database for the defaults. https://cloud.ibm.com/docs/databases-for-postgresql?topic=cloud-databases-provisioning#provisioning-parameters + + ~> **Note:** `members_memory_allocation_mb`, `members_disk_allocation_mb`, `members_cpu_allocation_count` conflicts with `node_count`,`node_cpu_allocation_count`, `node_disk_allocation_mb`, `node_memory_allocation_mb`. `group` conflicts with `node_` and `members_` arguments. Either members, node, or group arguments have to be provided. - `name` - (Required, String) A descriptive name that is used to identify the database instance. The name must not include spaces. -- `plan` - (Required, String) The name of the service plan that you choose for your instance. All databases use `standard`. `enterprise` is supported only for cassandra (`databases-for-cassandra`) and mongodb(`databases-for-mongodb`) +- `plan` - (Required, Forces new resource, String) The name of the service plan that you choose for your instance. All databases use `standard`. `enterprise` is supported only for cassandra (`databases-for-cassandra`) and mongodb(`databases-for-mongodb`) * `plan_validation` - (Optional, bool) Enable or disable validating the database parameters for elasticsearch and postgres (more coming soon) during the plan phase. If not specified defaults to true. - `point_in_time_recovery_deployment_id` - (Optional, String) The ID of the source deployment that you want to recover back to. - `point_in_time_recovery_time` - (Optional, String) The timestamp in UTC format that you want to restore to. To retrieve the timestamp, run the `ibmcloud cdb postgresql earliest-pitr-timestamp ` command. For more information, see [Point-in-time Recovery](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-pitr). - `remote_leader_id` - (Optional, String) A CRN of the leader database to make the replica(read-only) deployment. The leader database is created by a database deployment with the same service ID. A read-only replica is set up to replicate all of your data from the leader deployment to the replica deployment by using asynchronous replication. For more information, see [Configuring Read-only Replicas](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-read-only-replicas). - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the instance. To retrieve this value, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. If no value is provided, the `default` resource group is used. -- `service` - (Required, String) The type of Cloud Databases that you want to create. Only the following services are currently accepted: `databases-for-etcd`, `databases-for-postgresql`, `databases-for-redis`, `databases-for-elasticsearch`, `messages-for-rabbitmq`,`databases-for-mongodb`,`databases-for-cassandra` and `databases-for-enterprisedb`. +- `service` - (Required, Forces new resource, String) The type of Cloud Databases that you want to create. Only the following services are currently accepted: `databases-for-etcd`, `databases-for-postgresql`, `databases-for-redis`, `databases-for-elasticsearch`, `messages-for-rabbitmq`,`databases-for-mongodb`,`databases-for-mysql`, `databases-for-cassandra` and `databases-for-enterprisedb`. - `service_endpoints` - (Optional, String) Specify whether you want to enable the public, private, or both service endpoints. Supported values are `public`, `private`, or `public-and-private`. The default is `public`. - `tags` (Optional, Array of Strings) A list of tags that you want to add to your instance. - `version` - (Optional, Forces new resource, String) The version of the database to be provisioned. If omitted, the database is created with the most recent major and minor version. - `users` - (Optional, List of Objects) A list of users that you want to create on the database. Multiple blocks are allowed. Nested scheme for `users`: - - `name` - (Optional, String) The user ID to add to the database instance. The user ID must be in the range 5 - 32 characters. - - `password` - (Optional, String) The password for the user ID. The password must be in the range 10 - 32 characters. + - `name` - (Required, String) The user name to add to the database instance. The user name must be in the range 5 - 32 characters. + - `password` - (Required, String) The password for the user. The password must be in the range 10 - 32 characters. Users + - `type` - (Optional, String) The type for the user. Examples: `database`, `ops_manager`, `read_only_replica`. The default value is `database`. + - `role` - (Optional, String) The role for the user. Only available for `ops_manager` user type. Examples: `group_read_only`, `group_data_access_admin`. + - `whitelist` - (Optional, List of Objects) A list of allowed IP addresses for the database. Multiple blocks are allowed. - + Nested scheme for `whitelist`: - `address` - (Optional, String) The IP address or range of database client addresses to be whitelisted in CIDR format. Example, `172.168.1.2/32`. - `description` - (Optional, String) A description for the allowed IP addresses range. ## Attribute reference -In addition to all argument references list, you can access the following attribute references after your resource is created. +In addition to all argument references list, you can access the following attribute references after your resource is created. - `adminuser` - (String) The user ID of the database administrator. Example, `admin` or `root`. -- `connectionstrings` - (Array) A list of connection strings for the database for each user ID. For more information, about how to use connection strings, see the [documentation](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-connection-strings). The results are returned in pairs of the userid and string: `connectionstrings.1.name = admin connectionstrings.1.string = postgres://admin:$PASSWORD@79226bd4-4076-4873-b5ce-b1dba48ff8c4.b8a5e798d2d04f2e860e54e5d042c915.databases.appdomain.cloud:32554/ibmclouddb?sslmode=verify-full` Individual string parameters can be retrieved by using Terraform variables and outputs `connectionstrings.x.hosts.x.port` and `connectionstrings.x.hosts.x.host`. +- `configuration_schema` (String) Database Configuration Schema in JSON format. +- `connectionstrings` - **Deprecated** - (Array) A list of connection strings for the database for each user ID - replaced by `bm_database_connection`. For more information, about how to use connection strings, see the [documentation](https://cloud.ibm.com/docs/databases-for-postgresql?topic=databases-for-postgresql-connection-strings). The results are returned in pairs of the userid and string: `connectionstrings.1.name = admin connectionstrings.1.string = postgres://admin:$PASSWORD@79226bd4-4076-4873-b5ce-b1dba48ff8c4.b8a5e798d2d04f2e860e54e5d042c915.databases.appdomain.cloud:32554/ibmclouddb?sslmode=verify-full` Individual string parameters can be retrieved by using Terraform variables and outputs `connectionstrings.x.hosts.x.port` and `connectionstrings.x.hosts.x.host`. - `id` - (String) The CRN of the database instance. - `status` - (String) The status of the instance. - `version` - (String) The database version. diff --git a/website/docs/r/dl_gateway.html.markdown b/website/docs/r/dl_gateway.html.markdown index ef372cf62..f61238711 100644 --- a/website/docs/r/dl_gateway.html.markdown +++ b/website/docs/r/dl_gateway.html.markdown @@ -58,6 +58,13 @@ resource "ibm_dl_gateway" "test_dl_connect" { ## Argument reference Review the argument reference that you can specify for your resource. +- `as_prepends` - (Optional, List) List of AS Prepend configuration information + + Nested scheme for `as_prepend`: + - `length` - (Required, Integer ) Number of times the ASN to appended to the AS Path. + - `policy` - (Required, String) Route type this AS Prepend applies to. Possible values are `import` and `export`. + - `prefix` - (Optional, String) Comma separated list of prefixes this AS Prepend applies to. Maximum of 10 prefixes. If not specified, this AS Prepend applies to all prefixes. + - `authentication_key` - (Optional, String) BGP MD5 authentication key. - `bfd_interval` - (String) Minimum interval in milliseconds at which the local routing device transmits hello packets and then expects to receive a reply from a neighbor with which it has established a BFD session. - `bfd_multiplier` - (String) The number of hello packets not received by a neighbor that causes the originating interface to be declared down. @@ -80,6 +87,13 @@ Review the argument reference that you can specify for your resource. ## Attribute reference In addition to all argument references list, you can access the following attribute references after your resource is created. +- `as_prepends` - (List) List of AS Prepend configuration information + + Nested scheme for `as_prepend`: + - `created_at`- (String) The date and time AS Prepend was created. + - `id` - (String) The unique identifier for this AS Prepend. + - `updated_at`- (String) The date and time AS Prepend was updated. + - `bfd_status` - (String) Gateway BFD status - `bfd_status_updated_at` - (String) Date and time BFD status was updated at - `bgp_asn` - (String) The IBM BGP ASN. diff --git a/website/docs/r/dl_provider_gateway.html.markdown b/website/docs/r/dl_provider_gateway.html.markdown index fe5435d95..05e619723 100644 --- a/website/docs/r/dl_provider_gateway.html.markdown +++ b/website/docs/r/dl_provider_gateway.html.markdown @@ -23,6 +23,7 @@ resource ibm_dl_provider_gateway test_dl_provider_gateway { speed_mbps = 1000 port = "434-c749-4f1d-b190-22" customer_account_id = "0c474da-c749-4f1d-b190-2333" + vlan = 35 } ``` @@ -36,6 +37,7 @@ Review the argument reference that you can specify for your resource. - `name` - (Required, String) The unique user-defined name for this gateway. Example: `myGateway`. - `port` - (Required, Forces new resource, String) The gateway port for type to connect gateway. - `speed_mbps`- (Required, Integer) The gateway speed in megabits per second. For example, `10.254.30.78/30`. +- `vlan` - (Optional, Integer) VLAN requested for this gateway. ## Attribute reference @@ -51,7 +53,7 @@ In addition to all argument reference list, you can access the following attribu - `operational_status` - (String) The gateway operational status. Supported values are`configuring`, `create_pending`, `create_rejected`, `delete_pending`, `provisioned`. - `port` - (String) The gateway port for `type=connect` gateways. - `provider_api_managed` - (String) Indicates whether the gateway changes need to be made via a provider portal. -- `vlan` - (String) The VLAN allocated for the gateway. You can set only for `type=connect` gateways created directly through the IBM portal. +- `vlan` - (String) VLAN requested for this gateway. ## Import The `ibm_dl_provider_gateway` resource can be imported by using gateway ID. diff --git a/website/docs/r/dl_route_report.html.markdown b/website/docs/r/dl_route_report.html.markdown new file mode 100644 index 000000000..6c553a0ae --- /dev/null +++ b/website/docs/r/dl_route_report.html.markdown @@ -0,0 +1,111 @@ +--- +subcategory: "Direct Link Gateway" +layout: "ibm" +page_title: "IBM : dl_route_report" +description: |- + Create and Delete Route Report for a DirectLink Gateway. +--- + +# ibm_dl_route_report + +Provides a resource for ibm_dl_route_report. This allows to create and delete a route report for a directlink gateway. For more information, see [about Direct Link Route Report](https://cloud.ibm.com/docs/dl?topic=dl-generate-route-reports&interface=ui). + + +## Example usage to create Direct Link Route Report on dedicated gateway +In the following example, you can create Direct Link Route Report for dedicated gateway: + +```terraform +data "ibm_dl_routers" "test_dl_routers" { + offering_type = "dedicated" + location_name = "dal10" + } + +resource ibm_dl_gateway test_dl_gateway { + bgp_asn = 64999 + global = true + metered = false + name = "Gateway1" + speed_mbps = 1000 + type = "dedicated" + cross_connect_router = data.ibm_dl_routers.test_dl_routers.cross_connect_routers[0].router_name + location_name = data.ibm_dl_routers.test_dl_routers.location_name + customer_name = "Customer1" + carrier_name = "Carrier1" + +} + +resource ibm_dl_route_report dl_route_report { + gateway = ibm_dl_gateway.test_dl_gateway.id +} +``` + +## Sample usage to create Direct Link Route Report on connect gateway +In the following example, you can create Direct Link Route Report on connect gateway: + + +```terraform +data "ibm_dl_ports" "test_ds_dl_ports" { + + } +resource "ibm_dl_gateway" "test_dl_connect" { + bgp_asn = 64999 + global = true + metered = false + name = "dl-connect-gw-1" + speed_mbps = 1000 + type = "connect" + port = data.ibm_dl_ports.test_ds_dl_ports.ports[0].port_id +} + +resource ibm_dl_route_report dl_route_report { + gateway = ibm_dl_gateway.test_dl_gateway.id +} +``` + +## Argument reference +Review the argument reference that you can specify for your resource. + +- `gateway`- (Required, Forces New, Integer) Direct Link Gateway ID. + +## Attribute reference +In addition to all argument references list, you can access the following attribute references after your resource is created. +- `created_at` - (String) The date and time resource created. +- `gateway_routes` - (List) List of local/direct routes. + Nested scheme for `gateway_routes`: + - `prefix` - (String) The prefix used in the route. +- `on_prem_routes` - (List) List of on premises routes + Nested scheme for `on_prem_routes`: + - `prefix` - (String) The prefix used in the route. +- `overlapping_routes` - (List) List of overlapping routes. + Nested scheme for `overlapping_routes`: + - `routes` - (List) List of overlapping connection/prefix pairs. + Nested scheme for `routes`: + - `prefix` - (String) The overlapping prefix. + - `type` - (String) The type of route. + - `virtual_connection_id` - (String) Virtual Connection ID. This is set only when type of route is virtual_connection. +- `route_report_id` - (String) The unique identifier of this route report. +- `status` - (String) The route report status. +- `updated_at` - (String) The date and time resource was updated. +- `virtual_connection_routes` - (List) List of routes on virtual connections. + Nested scheme for `virtual_connection_routes` + - `routes` - (List) List of connection routes. + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route. + - `virtual_connection_id` - (String) Virtual Connection ID + - `virtual_connection_name` - (String) Virtual Connection name + - `virtual_connection_type` - (String) Virtual Connection type + +## Import + +You can import the `ibm_dl_route_report` resource by using `id`. +The `id` property can be formed from `gateway` and `route_report_id` in the following format: + +``` +/ +``` +* `gateway`: A String. The unique identifier of a directlink gateway. +* `route_report_id`: A String. The unique identifier of the route report. + +``` +$ terraform import ibm_dl_route_report.dl_route_report / +``` diff --git a/website/docs/r/dns_custom_resolver.html.markdown b/website/docs/r/dns_custom_resolver.html.markdown index 77b2ddc9e..5f948325b 100644 --- a/website/docs/r/dns_custom_resolver.html.markdown +++ b/website/docs/r/dns_custom_resolver.html.markdown @@ -16,45 +16,50 @@ Provides a private DNS custom resolver resource. This allows DNS custom resolver ```terraform data "ibm_resource_group" "rg" { - is_default = true + is_default = true } resource "ibm_is_vpc" "test-pdns-cr-vpc" { - name = "test-pdns-custom-resolver-vpc" - resource_group = data.ibm_resource_group.rg.id + name = "test-pdns-custom-resolver-vpc" + resource_group = data.ibm_resource_group.rg.id } resource "ibm_is_subnet" "test-pdns-cr-subnet1" { - name = "test-pdns-cr-subnet1" - vpc = ibm_is_vpc.test-pdns-cr-vpc.id - zone = "us-south-1" - ipv4_cidr_block = "10.240.0.0/24" - resource_group = data.ibm_resource_group.rg.id + name = "test-pdns-cr-subnet1" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" + resource_group = data.ibm_resource_group.rg.id } resource "ibm_is_subnet" "test-pdns-cr-subnet2" { - name = "test-pdns-cr-subnet2" - vpc = ibm_is_vpc.test-pdns-cr-vpc.id - zone = "us-south-1" - ipv4_cidr_block = "10.240.64.0/24" - resource_group = data.ibm_resource_group.rg.id + name = "test-pdns-cr-subnet2" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.64.0/24" + resource_group = data.ibm_resource_group.rg.id } resource "ibm_resource_instance" "test-pdns-cr-instance" { - name = "test-pdns-cr-instance" - resource_group_id = data.ibm_resource_group.rg.id - location = "global" - service = "dns-svcs" - plan = "standard-dns" + name = "test-pdns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" } resource "ibm_dns_custom_resolver" "test" { - name = "test-customresolver" - instance_id = ibm_resource_instance.test-pdns-cr-instance.guid - description = "new test CR - TF" - enabled = true + name = "test-customresolver" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR - TF" + high_availability = true + enabled = true locations { - subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn - enabled = true + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true } locations { - subnet_crn = ibm_is_subnet.test-pdns-cr-subnet2.crn - enabled = true + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet2.crn + enabled = false } } ``` @@ -64,10 +69,10 @@ Review the argument reference that you can specify for your resource. - `instance_id` - (Required, String) The GUID of the private DNS service instance. - `name`- (Required, String) The name of the custom resolver. -- `enabled`- (Optional, Bool) To make custom resolver enabled/disable. +- `enabled`- (Optional, Bool) To enable or disable a custom resolver. To enable a custom resolver, it is recommended that you have at least one enabled location. The Default value is `false`. - `description` - (Optional, String) Descriptive text of the custom resolver. -- `high_availability` - (Optional, Bool) High Availability is enabled by Default, Need to add two or more locations. -- `locations`- (Optional, Set) The list of locations where this custom resolver is deployed. There is no update for location argument in resolver resource. +- `high_availability` - (Optional, Bool) High Availability is enabled by Default. To meet high availability status, configure custom resolvers with a minimum of two resolver locations. +- `locations`- (Optional, List) The list of locations where this custom resolver is deployed. A custom resolver can have a maximum of three locations, either within the same subnet or in different subnets. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your resource is created. @@ -76,7 +81,7 @@ In addition to all argument reference list, you can access the following attribu - `custom_resolver_id` - (String) The unique ID of the private DNS custom resolver. - `modified_on` - (Timestamp) The time (modified On) of the DNS Custom Resolver. - `health`- (String) The status of DNS Custom Resolver's health. Possible values are `DEGRADED`, `CRITICAL`, `HEALTHY`. -- `locations` - (Set) Locations on which the custom resolver will be running. +- `locations` - (List) Locations on which the custom resolver will be running. Nested scheme for `locations`: - `healthy`- (String) The health status. @@ -84,10 +89,20 @@ In addition to all argument reference list, you can access the following attribu - `enabled`- (Bool) Whether the location is enabled. - `location_id`- (String) The location ID. + Nested scheme for `rules`: + - `rule_id` - (String) The rule ID is unique identifier of the custom resolver forwarding rule. + - `description`- (String) Descriptive text of the forwarding rule. + - `type` - (String) Type of the forwarding rule.Constraints: Allowable values are: `zone`, `hostname`. + - `match` - (String) The matching zone or hostname. + - `forward_to` - (List) The upstream DNS servers will be forwarded to. + ## Import The `ibm_dns_custom_resolver` can be imported by using private DNS instance ID, Custom Resolver ID. -The `id` property can be formed from `custom resolver id` and `instance_id` in the following format: +The `id` property can be formed from `custom_resolver_id` and `instance_id` in the following format: + +``` : +``` **Example** diff --git a/website/docs/r/dns_custom_resolver_forwarding_rule.html.markdown b/website/docs/r/dns_custom_resolver_forwarding_rule.html.markdown index 32894c02b..d4ff90b39 100644 --- a/website/docs/r/dns_custom_resolver_forwarding_rule.html.markdown +++ b/website/docs/r/dns_custom_resolver_forwarding_rule.html.markdown @@ -74,30 +74,31 @@ Review the argument reference that you can specify for your resource. * `resolver_id` - (Required, String) The unique identifier of a custom resolver. * `description` - (Optional, String) Descriptive text of the forwarding rule. * `type` - (Optional, String) Type of the forwarding rule. - * Constraints: Allowable values are: `zone`, `hostname`. + * Constraints: Allowable values are: `zone`, `hostname`,`Default`. * `match` - (Optional, String) The matching zone or hostname. * `forward_to` - (Optional, List) The upstream DNS servers will be forwarded to. -## Attribute Reference +## Attribute reference In addition to all argument reference list, you can access the following attribute references after your resource is created. * `id` - (String) The unique identifier of the DNS custom resolver forwarding rule. * `created_on` - (String) The time when a forwarding rule is created, RFC3339 format. * `modified_on` -(String) The recent time when a forwarding rule is modified, RFC3339 format. +* `rule_id` - (String) The rule ID is unique identifier of the custom resolver forwarding rule. ## Import You can import the `ibm_dns_custom_resolver_forwarding_rule` resource by using `id`. -The `id` property can be formed from `instance_id`, `resolver_id`, and `rule_id` in the following format: +The `id` property can be formed from `rule_id`, `resolver_id`, and `instance_id` in the following format: ``` -// +:: ``` -* `instance_id`: A String. The GUID of the private DNS service instance. -* `resolver_id`: A String. The unique identifier of a custom resolver. * `rule_id`: A String. The unique identifier of a forwarding rule. +* `resolver_id`: A String. The unique identifier of a custom resolver. +* `instance_id`: A String. The GUID of the private DNS service instance. ``` -$ terraform import ibm_dns_custom_resolver_forwarding_rule.ibm_dns_custom_resolver_forwarding_rule // +$ terraform import ibm_dns_custom_resolver_forwarding_rule.ibm_dns_custom_resolver_forwarding_rule :: ``` diff --git a/website/docs/r/dns_custom_resolver_location.html.markdown b/website/docs/r/dns_custom_resolver_location.html.markdown index 7a6b08ee8..8f3f79d54 100644 --- a/website/docs/r/dns_custom_resolver_location.html.markdown +++ b/website/docs/r/dns_custom_resolver_location.html.markdown @@ -8,7 +8,49 @@ description: |- # ibm_dns_custom_resolver_location -Provides a private DNS custom resolver locations resource. This allows DNS custom resolver location to create, update, and delete. For more information, about custom resolver locations, see [add-custom-resolver-location](https://cloud.ibm.com/apidocs/dns-svcs#add-custom-resolver-location). +~> **Deprecated:** + +Beginning with version 1.42.0, using the `ibm_dns_custom_resolver_location` resource to **create** or **update** Custom Resolver Location in Terraform is deprecated. Use the composite **Custom Resolver** resource, which can handle locations, instead. +It is recommended that you do not use `ibm_dns_custom_resolver_location`. Using the deprecated resource can cause an outage. If you have used the `ibm_dns_custom_resolver_location` resource, change it to the composite Custom Resolver resource before running terraform apply. +For more information, see the [example usage](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/dns_custom_resolver#example-usage). + +If resources were created using Custom Resolver locations resource block, then follow this migration process to avoid unexpected behaviors in your infrastructure. + +1. Take a backup of your terraform state file. +2. Modify the **terraform.tfstate** file and remove the json blocks of type: "ibm_dns_custom_resolver_location" and "ibm_dns_custom_resolver", because you are going to perform a terraform import of Custom resolver and its locations from Cloud. +3. Also, modify your .tf file. Remove custom resolver location resources and add locations to the composite custom resolver block as shown in this example: + +``` +resource "ibm_dns_custom_resolver" "test" { + name = "test-customresolver" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR" + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet2.crn + enabled = true + } + } +``` + +4. Run the following terraform import command to import ibm_dns_custom_resolver into your state file: + +``` +terraform import ibm_dns_custom_resolver.test : + +Example: +terraform import ibm_dns_custom_resolver.test 9930d75f-a501-4305-80fe-ead2e38021da:e180df3b-1de8-442d-8014-881822fd27c5 +``` +Ensure that the resource custom resolver is imported successfully. + + +## ibm_dns_custom_resolver_location + +Provides a private DNS custom resolver locations resource. This allows DNS custom resolver location to create. For more information, about custom resolver locations, see [add-custom-resolver-location](https://cloud.ibm.com/apidocs/dns-svcs#add-custom-resolver-location). ## Example usage @@ -73,7 +115,7 @@ Review the argument reference that you can specify for your resource. * `instance_id` - (Required, String) The GUID of the private DNS service instance. * `resolver_id` - (Required, String) The unique identifier of a custom resolver. * `subnet_crn` - (Required, String) The subnet CRN of the VPC. -* `enabled` - (Optional, Bool) The custom resolver location will enabled or disable. +* `enabled` - (Optional, Bool) The custom resolver location will enabled or disable. Default is 'false' * `cr_enabled` - (Optional, Bool) Indicates whether to enable or disable the customer resolver. Default is 'true' diff --git a/website/docs/r/dns_custom_resolver_secondary_zone.html.markdown b/website/docs/r/dns_custom_resolver_secondary_zone.html.markdown new file mode 100644 index 000000000..2fa87b7b6 --- /dev/null +++ b/website/docs/r/dns_custom_resolver_secondary_zone.html.markdown @@ -0,0 +1,108 @@ +--- +subcategory: "DNS Services" +layout: "ibm" +page_title: "IBM : dns_custom_resolver_secondary_zone" +description: |- + Manages IBM Private DNS custom resolver secondary zone. +--- + +# ibm_dns_custom_resolver_secondary_zone + +The DNS custom resolver secondary zone resource allows users to request and manage secondary zones for a given custom resolver. By creating and enabling a secondary zone resource for a custom resolver, DNS records for a given DNS zone will be transferred from a user provided primary DNS server (on premise) to a private DNS custom resolver hosted on an IBM Cloud VPC. This framework will improve the availability, speed, and security of DNS queries for a given DNS zone. + + +## Example usage + +``` +data "ibm_resource_group" "rg" { + is_default = true +} + +# create a VPC for the subnets +resource "ibm_is_vpc" "test-pdns-cr-vpc" { + depends_on = [data.ibm_resource_group.rg] + name = "seczone-vpc" + resource_group = data.ibm_resource_group.rg.id +} + +# create subnets for the custom resolver locations +resource "ibm_is_subnet" "test-pdns-cr-subnet1" { + name = "seczone-subnet1" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" + resource_group = data.ibm_resource_group.rg.id +} + +resource "ibm_is_subnet" "test-pdns-cr-subnet2" { + name = "seczone-subnet2" + vpc = ibm_is_vpc.test-pdns-cr-vpc.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/24" + resource_group = data.ibm_resource_group.rg.id +} + +# create a DNS instance +resource "ibm_resource_instance" "test-pdns-cr-instance" { + name = "seczone-dns1" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" +} + +# create a custom resolver +resource "ibm_dns_custom_resolver" "test" { + name = "msz-test-cr2" + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + description = "new test CR - TF" + enabled = true + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet1.crn + enabled = true + } + locations { + subnet_crn = ibm_is_subnet.test-pdns-cr-subnet2.crn + enabled = true + } +} + +resource "ibm_dns_custom_resolver_secondary_zone" "test" { + instance_id = ibm_resource_instance.test-pdns-cr-instance.guid + resolver_id = ibm_dns_custom_resolver.test.custom_resolver_id + zone = "example-zone.com" + enabled = true + transfer_from = ["10.0.0.8"] +} +``` + +## Argument reference +Review the argument reference that you can specify for your resource. + +- `instance_id` - (Required, String) The unique identifier of a service instance. +- `resolver_id` - (Required, String) The GUID of the custom resolver. +- `zone` - (Required, String) The name of the zone. +- `enabled`- (Required, Bool) To enable or disable a secondary zone. +- `transfer_from`- (Required, List of Strings)The addresses of DNS servers where the secondary zone data is transferred from. +- `description` - (Optional, String) Descriptive text of the secondary zone. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your resource is created. + +- `created_on` - (Timestamp) The time (created On) of the Secondary Zone. +- `modified_on` - (Timestamp) The time (modified On) of the Secondary Zone. +- `secondary_zone_id` - (String) The unique ID of the DNS Services custom resolver secondary zone. + +## Import +The `ibm_dns_custom_resolver_secondary_zone` can be imported by using DNS Services instance ID, Custom Resolver ID, and Secondary Zone ID. +The `id` property can be formed from `instance_id`, `custom_resolver_id` and `secondary_zone_id` in the following format: + +``` +// +``` + +**Example** + +``` +terraform import ibm_dns_custom_resolver_secondary_zone.sample "d10e6956-377a-43fb-a5a6-54763a6b1dc2/63481bef-3759-4b5e-99df-73be7ba40a8a/bd2d4867-f606-45da-93b4-02dc69635d5e" +``` diff --git a/website/docs/r/dns_glb.html.markdown b/website/docs/r/dns_glb.html.markdown index 275a8ca57..806381153 100644 --- a/website/docs/r/dns_glb.html.markdown +++ b/website/docs/r/dns_glb.html.markdown @@ -21,6 +21,7 @@ resource "ibm_dns_glb" "test_pdns_glb" { zone_id = ibm_dns_zone.test_pdns_glb_zone.zone_id description = "new glb" ttl = 120 + enabled = true fallback_pool = ibm_dns_glb_pool.test_pdns_glb_pool.pool_id default_pools = [ibm_dns_glb_pool.test_pdns_glb_pool.pool_id] az_pools { @@ -45,6 +46,7 @@ Review the argument reference that you can specify for your resource. - `name` - (Required, String) The name of the Load Balancer. - `ttl` - (Optional, Integer) The time to live (TTL) in seconds. - `zone_id` - (Required, Forces new resource, String) The ID of the private DNS Zone. +- `enabled` - (Optional, Bool) Whether the load balancer is enabled. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your resource is created. diff --git a/website/docs/r/dns_glb_pool.html.markdown b/website/docs/r/dns_glb_pool.html.markdown index 9e8237aa2..a3c405cd3 100644 --- a/website/docs/r/dns_glb_pool.html.markdown +++ b/website/docs/r/dns_glb_pool.html.markdown @@ -40,7 +40,7 @@ Review the argument reference that you can specify for your resource. - `description` - (Optional, String) Descriptive text of the origin server. - `enabled`- (Required, Bool) Whether the origin server is enabled. - `healthy_origins_threshold`- (Required, Integer) The minimum number of origins that must be healthy for this pool to serve traffic. If the number of healthy origins falls below this number, the pool will be marked unhealthy and will failover to the next available pool. -- `healthcheck_region` - (Optional, String) Health check region of VSIs. Allowable values are `us-south`,`us-east`, `eu-gb`, `eu-du`, `au-syd`, `jp-tok`. +- `healthcheck_region` - (Optional, String) Health check region of VSIs. Examples: `us-south`,`us-east`, `eu-gb`, `eu-de`, `au-syd`, `jp-tok`, `jp-osa`, `ca-tor`, `br-sao`. - `healthcheck_subnets` - (List, Optional) The health check subnet CRN of VSIs. - `instance_id` - (Required, Forces new resource, String) The GUID of the private DNS on which zone has to be created. - `monitor` - (Optional, String) The ID of the Load Balancer monitor to be associated to this pool. diff --git a/website/docs/r/dns_permitted_network.html.markdown b/website/docs/r/dns_permitted_network.html.markdown index ca5c3873a..8d6ece846 100644 --- a/website/docs/r/dns_permitted_network.html.markdown +++ b/website/docs/r/dns_permitted_network.html.markdown @@ -27,7 +27,7 @@ resource "ibm_dns_permitted_network" "test-pdns-permitted-network-nw" { ## Argument reference Review the argument reference that you can specify for your resource. -- `instance_id` - (Required, String) The ID of the IBM Cloud DNS service instance where you want to add a permitted network. +- `instance_id` - (Required, String) The GUID of the IBM Cloud DNS service instance where you want to add a permitted network. - `type` - (Required, String) The type of permitted network that you want to add. Supported values are `vpc`. - `vpc_crn` - (Required, String) The CRN of the VPC that you want to add as a permitted network. - `zone_id` - (Required, String) The ID of the private DNS zone where you want to add the permitted network. diff --git a/website/docs/r/dns_zone.html.markdown b/website/docs/r/dns_zone.html.markdown index de47b9cda..9160b3cae 100644 --- a/website/docs/r/dns_zone.html.markdown +++ b/website/docs/r/dns_zone.html.markdown @@ -27,7 +27,7 @@ resource "ibm_dns_zone" "pdns-1-zone" { Review the argument reference that you can specify for your resource. - `description` - (Optional, String) The description of the DNS zone. -- `instance_id` - (Required, String) The ID of the IBM Cloud DNS service instance where you want to create a DNS zone. +- `instance_id` - (Required, String) The GUID of the IBM Cloud DNS service instance where you want to create a DNS zone. - `name` - (Required, String) The name of the DNS zone that you want to create. - `label` - (Optional, String) The label of the DNS zone. diff --git a/website/docs/r/en_destination.html.markdown b/website/docs/r/en_destination.html.markdown index 71387b41a..d5150dd2a 100644 --- a/website/docs/r/en_destination.html.markdown +++ b/website/docs/r/en_destination.html.markdown @@ -10,14 +10,14 @@ description: |- Create, update, or delete a destination by using IBM Cloud™ Event Notifications. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_en_destination" "en_destination" { - instance_guid = "instance_guid" - name = "name" - type = "webhook" - description = "descriptions" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Webhook Destination" + type = "webhook" + description = "This is en webhook destination" config { params { verb = "POST" @@ -31,7 +31,7 @@ resource "ibm_en_destination" "en_destination" { } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. @@ -58,7 +58,7 @@ Review the argument reference that you can specify for your resource. - `url` - (Optional, String) URL of webhook. - `verb` - (Optional, String) HTTP method of webhook. Allowable values are: `GET`, `POST`. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. diff --git a/website/docs/r/en_destination_android.html.markdown b/website/docs/r/en_destination_android.html.markdown new file mode 100644 index 000000000..c1ad56164 --- /dev/null +++ b/website/docs/r/en_destination_android.html.markdown @@ -0,0 +1,83 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_android' +description: |- + Manages Event Notifications destinations. +--- + +# ibm_en_destination_android + +Create, update, or delete a FCM destination by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_android" "android_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Android Destination" + type = "push_android" + description = "The Android Destination" + config { + params { + sender_id = "5237288990" + server_key = "36228ghutwervhudokmk" + } + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) push_android. + + +- `config` - (Optional, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `sender_id` - (String) Sender Id value for FCM project. + - `server_key` - (String) Server Key value for FCM project + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `android_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_android` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_android.fcm_en_destination / +``` diff --git a/website/docs/r/en_destination_chrome.html.markdown b/website/docs/r/en_destination_chrome.html.markdown new file mode 100644 index 000000000..c69b185c9 --- /dev/null +++ b/website/docs/r/en_destination_chrome.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_chrome' +description: |- + Manages Event Notification Webhook destinations. +--- + +# ibm_en_destination_chrome + +Create, update, or delete a Chrome destination by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_chrome" "chrome_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Chrome Destination" + type = "push_chrome" + description = "Destination Chrome for event notification" + config { + params { + api_key = "The FCM api key for project" + website_url = "https://testevents.com" + } + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) push_chrome. + +- `config` - (Optional, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `website_url` - (Required, string) URL of website. + - `api_key` - (Required, string) The apikey for website project. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `chrome_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_chrome` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_chrome.chrome_en_destination / +``` diff --git a/website/docs/r/en_destination_firefox.html.markdown b/website/docs/r/en_destination_firefox.html.markdown new file mode 100644 index 000000000..4b854dfe8 --- /dev/null +++ b/website/docs/r/en_destination_firefox.html.markdown @@ -0,0 +1,80 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_firefox' +description: |- + Manages Event Notification firefox destinations. +--- + +# ibm_en_destination_webhook + +Create, update, or delete a firefox destination by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_firefox" "firefox_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Firefox Destination" + type = "push_firefox" + description = "Destination firefox for event notification" + config { + params { + website_url = "https://testwebsite.com" + } + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) push_firefox. + +- `config` - (Optional, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `website_url` - (Required, String) URL of the website project. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `firefox_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_firefox` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_firefox.firefox_en_destination / +``` diff --git a/website/docs/r/en_destination_ios.html.markdown b/website/docs/r/en_destination_ios.html.markdown new file mode 100644 index 000000000..137724c70 --- /dev/null +++ b/website/docs/r/en_destination_ios.html.markdown @@ -0,0 +1,119 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_ios' +description: |- + Manages Event Notifications IOS destination. +--- + +# ibm_en_destination_ios + +Create, update, or delete IOS destination by using IBM Cloud™ Event Notifications. + +## Example usage for P8 + +```terraform +resource "ibm_en_destination_ios" "ios_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "IOS Destination Auth" + type = "push_ios" + certificate_content_type = "p8" + certificate = "${path.module}/Certificates/Auth.p8" + description = "IOS destination with P8" + config { + params { + cert_type = "p8" + is_sandbox = true + key_id = production + team_id = "2347" + bundle_id = "testp8" + } + } +} +``` +## Example usage for P12 + +```terraform +resource "ibm_en_destination_ios" "ios_en_destination" { + instance_guid = "ibm_resource_instance.en_terraform_test_resource.guid" + name = "IOS Destination " + type = "push_ios" + certificate_content_type = "p12" + certificate = "${path.module}/Certificates/prod.p12" + description = "IOS destination with P12" + config { + params { + cert_type = "p12" + is_sandbox = true + password = "apnscertpassword" + } + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) push_ios. + +- `certificate_content_type` - (Required, String) The type of certificate, Values are p8/p12. + +- `certificate` - (Required, binary) Certificate file. The file type allowed is .p8 and .p12 + +- `config` - (Required, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `cert_type` - (Required, String) The Certificate type. Values are p8/p12. + + - `is_sandbox` - (Required, boolean) The flag for sandbox/production environment. + + - `password` - (String) The password string for p12 certificate. Required in case 0f p12. + + - `team_id` - (String) The team_id value in case P8 certificate. Required in case of p8. + + - `key_id` - (String) The team_id value in case P8 certificate. Required in case of p8. + + - `bundle_id` - (String) The team_id value in case P8 certificate. Required in case of p8. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `ios_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_ios` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_ios.ios_en_destination / +``` diff --git a/website/docs/r/en_destination_safari.html.markdown b/website/docs/r/en_destination_safari.html.markdown new file mode 100644 index 000000000..0fec13b8b --- /dev/null +++ b/website/docs/r/en_destination_safari.html.markdown @@ -0,0 +1,133 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_safari' +description: |- + Manages Event Notifications Safari destination. +--- + +# ibm_en_destination_safari + +Create, update, or delete Safari destination by using IBM Cloud™ Event Notifications. + +## Example usage for Safari Destination + +```terraform +resource "ibm_en_destination_safari" "safari_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "EN Safari Destination" + type = "push_safari" + certificate = "${path.module}/Certificates/safaricert.p12" + icon_16x16 = "${path.module}/Certificates/safariicon.png" + icon_16x16_2x = "${path.module}/Certificates/safariicon.png" + icon_32x32 = "${path.module}/Certificates/safariicon.png" + icon_32x32_2x = "${path.module}/Certificates/safariicon.png" + icon_128x128 = "${path.module}/Certificates/safariicon.png" + icon_128x128_2x = "${path.module}/Certificates/safariicon.png" + icon_16x16_content_type = "png" + icon_16x16_2x_content_type = "png" + icon_32x32_content_type = "png" + icon_32x32_2x_content_type = "png" + icon_128x128_content_type = "png" + icon_128x128_2x_content_type = "png" + description = "Safari destination in EN" + config { + params { + cert_type = "p12" + password = "apnscertpassword" + url_format_string = "https://test.petstorez.com" + website_name = "petstore" + website_push_id = "petzz" + website_url = "https://test.petstorez.com" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) push_safari. + +- `certificate` - (Required, binary) Certificate file. The file type allowed is .p8 and .p12 + +- `icon_16x16` - (Optional, binary) icon file of dimension 16x16 + +- `icon_16x16_2x` - (Optional, binary) icon file of dimension 16x16x2x + +- `icon_32x32` - (Optional, binary) icon file of dimension 32x32 + +- `icon_32x32_2x` - (Optional, binary) icon file of dimension 32x32x2x + +- `icon_128x128` - (Optional, binary) icon file of dimension 128x128 + +- `icon_128x128_2x` - (Optional, binary) icon file of dimension 128x128x2x + +- `icon_16x16_content_type` - (Optional, binary) The extension of icon image of 16x16 dimension. Required in case of passing icon file. + +- `icon_16x16_2x_content_type` - (Optional, binary) The extension of icon image of 16x16x2x dimension. Required in case of passing icon file. + +- `icon_32x32_content_type` - (Optional, binary) The extension of icon image of 32x32 dimension. Required in case of passing icon file. + +- `icon_32x32_2x_content_type` - (Optional, binary) The extension of icon image of 32x32x2x dimension. Required in case of passing icon file. + +- `icon_128x128_content_type` - (Optional, binary) The extension of icon image of 128x128 dimension. Required in case of passing icon file. + +- `icon_128x128_2x_content_type` - (Optional, binary) The extension of icon image of 128x128x2x dimension. Required in case of passing icon file. + +- `config` - (Required, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `cert_type` - (String) The Certificate type. Value is p12. + + - `password` - (String) The password string for p12 certificate. + + - `url_format_string` - (String) Website formatted url . + + - `website_name` - (String) The name of website. + + - `website_push_id` - (String) Website push ID . + + - `website_url` - (String) Website url. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `safari_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_safari` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_safari.safari_en_destination / +``` diff --git a/website/docs/r/en_destination_slack.html.markdown b/website/docs/r/en_destination_slack.html.markdown new file mode 100644 index 000000000..2e509778a --- /dev/null +++ b/website/docs/r/en_destination_slack.html.markdown @@ -0,0 +1,78 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_slack' +description: |- + Manages Event Notification Slack destinations. +--- + +# ibm_en_destination_slack + +Create, update, or delete a Slack destination by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_slack" "slack_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Slack Destination" + type = "slack" + description = "Destination slack for event notification" + config { + params { + url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) slack. + +- `config` - (Optional, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `url` - (Required, String) Slack Webhook url. +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `webhook_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_slack` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_slack.slack_en_destination / +``` diff --git a/website/docs/r/en_destination_webhook.html.markdown b/website/docs/r/en_destination_webhook.html.markdown new file mode 100644 index 000000000..74caa29ac --- /dev/null +++ b/website/docs/r/en_destination_webhook.html.markdown @@ -0,0 +1,88 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_webhook' +description: |- + Manages Event Notification Webhook destinations. +--- + +# ibm_en_destination_webhook + +Create, update, or delete a Webhook destination by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_webhook" "webhook_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Webhook Destination" + type = "webhook" + description = "Destination webhook for event notification" + config { + params { + verb = "POST" + url = "https://testwebhook.com" + custom_headers = { + "authorization" = "authorization" + } + sensitive_headers = ["authorization"] + } + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) Webhook. + +- `config` - (Optional, List) Payload describing a destination configuration. + + Nested scheme for **config**: + + - `params` - (Required, List) + + Nested scheme for **params**: + + - `custom_headers` - (Optional, Map) Custom headers (Key-Value pair) for webhook call. + - `sensitive_headers` - (Optional, List) List of sensitive headers from custom headers. + - `url` - (Optional, String) URL of webhook. + - `verb` - (Optional, String) HTTP method of webhook. Allowable values are: `GET`, `POST`. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `webhook_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_webhook` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_webhook.webhook_en_destination / +``` diff --git a/website/docs/r/en_source.html.markdown b/website/docs/r/en_source.html.markdown new file mode 100644 index 000000000..7230672c9 --- /dev/null +++ b/website/docs/r/en_source.html.markdown @@ -0,0 +1,62 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_source' +description: |- + Manages Event Notifications API Sources. +--- + +# ibm_en_source + +Create, update, or delete a source by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_source" "en_source" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "EN Source" + description = "API source for Event Notifications destinations" + enabled = true +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Source name. + +- `description` - (Optional, String) The Source description. + +- `enabled` - (Optional, bool) The enabled flag to enbale the created API source. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `en_source`. +- `source_id` - (String) The unique identifier of the created destination. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_source` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `source_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `source_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_source.en_source / +``` diff --git a/website/docs/r/en_subscription.html.markdown b/website/docs/r/en_subscription.html.markdown index dfcecdccc..c5c7fe0aa 100644 --- a/website/docs/r/en_subscription.html.markdown +++ b/website/docs/r/en_subscription.html.markdown @@ -10,23 +10,50 @@ description: |- Create, update, or delete a subscription by using IBM Cloud™ Event Notifications. -## Example Usage - -```hcl -resource "ibm_en_subscription" "en_subscription" { - instance_guid = "instance_guid" - name = "name" - description = "description" - destination_id = "destinationId" - topic_id = "topicId" +## Example usage + +```terraform +resource "ibm_en_subscription" "en_subscription_webhook" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Webhook Subscription" + description = "Subscription for Webhook destination" + destination_id = ibm_en_destination.destinationwebhook.destination_id + topic_id = ibm_en_topic.topic1.topic_id attributes { - add_notification_payload = true signing_enabled = true } } + +resource "ibm_en_subscription" "en_subscription_sms" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "SMS Subscription" + description = "Subscription for SMS destination" + destination_id = "destination_id" + topic_id = ibm_en_topic.topic1.topic_id + attributes { + to = ["+15678923404", "+19643567389"] + } +} + +resource "ibm_en_subscription" "en_subscription_email" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Email Subscription" + description = "Subscription for Email destination" + destination_id = "destination_id" + topic_id = ibm_en_topic.topic1.topic_id + attributes { + add_notification_payload = true + reply_to_mail = "compliancealert@ibm.com" + reply_to_name = "Compliance User" + from_name = "en@ibm.com" + to = ["usernew1@gmail.com","testuser@gamil.com"] + } +} + + ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. @@ -43,17 +70,21 @@ Review the argument reference that you can specify for your resource. - `attributes` - (Optional, List) Subscription attributes. Nested scheme for **attributes**: - - `add_notification_payload` - (Optional, Boolean) Add notification payload. - - `signing_enabled` - (Optional, Boolean) Signing enabled. - `add_notification_payload` - (Optional, Boolean) Whether to add the notification payload to the email. - `reply_to` - (Optional, String) The email address to reply to. - - `to` - (Optional, List) The phone number to send the SMS to. + - `reply_to_name` - (Optional, String) The Email User Name to reply to. + + - `from_name` - (Optional, String) The email address user from which email is addressed. + + - `to` - (Optional, List) The phone number to send the SMS to or email id in case of Email subscription. + + - `remove` - (Optional, List) The Email address list to be provided in case of removing the email addresses from subscription. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. @@ -69,7 +100,7 @@ In addition to all argument references listed, you can access the following attr - `from` - (Optional, String) From Email ID (it will be displayed only in case of smtp_ibm destination type). -- `updated_at` - (Required, String) Last updated time. +- `updated_at` - (String) Last updated time. ## Import diff --git a/website/docs/r/en_subscription_android.html.markdown b/website/docs/r/en_subscription_android.html.markdown new file mode 100644 index 000000000..317930c22 --- /dev/null +++ b/website/docs/r/en_subscription_android.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_android' +description: |- + Manages Event Notifications Android subscription. +--- + +# ibm_en_subscription_android + +Create, update, or delete a FCM subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_android" "android_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Android Subscription" + description = "Android Subscription for Notification" + destination_id = ibm_en_destination_android.destinationandroidnew.destination_id + topic_id = ibm_en_topic.topic1.topic_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `android_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_android` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_android.android_subscription / +``` diff --git a/website/docs/r/en_subscription_chrome.html.markdown b/website/docs/r/en_subscription_chrome.html.markdown new file mode 100644 index 000000000..e64cc8931 --- /dev/null +++ b/website/docs/r/en_subscription_chrome.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_chrome' +description: |- + Manages Event Notifications Chrome subscription. +--- + +# ibm_en_subscription_chrome + +Create, update, or delete a Chrome subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_chrome" "chrome_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Chrome Subscription" + description = "Chrome Subscription for Notification" + destination_id = ibm_en_destination_chrome.chrome_destination.destination_id + topic_id = ibm_en_topic.topic1.topic_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `chrome_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_chrome` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_chrome.chrome_subscription / +``` diff --git a/website/docs/r/en_subscription_email.html.markdown b/website/docs/r/en_subscription_email.html.markdown new file mode 100644 index 000000000..edb927ff1 --- /dev/null +++ b/website/docs/r/en_subscription_email.html.markdown @@ -0,0 +1,107 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_email' +description: |- + Manages Event Notifications SMS subscription. +--- + +# ibm_en_subscription_email + +Create, update, or delete a Email subscription by using IBM Cloud™ Event Notifications. + +## Example usage for Email Subscription Creation + +```terraform +resource "ibm_en_subscription_email" "email_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Email Certificate Subscription" + description = "Subscription for Certificate expiration alert" + destination_id = "email_destination_id" + topic_id = ibm_en_topic.topic1.topic_id + attributes { + add_notification_payload = true + reply_to_mail = "compliancealert@ibm.com" + reply_to_name = "Compliance User" + from_name = "en@ibm.com" + to = ["usernew1@gmail.com","testuser@gamil.com"] + } +} +``` + +## Example usage for Email Subscription Updation + +```terraform +resource "ibm_en_subscription_email" "email_subscription" { + instance_guid = "my_instance_guid" + name = "Email Certificate Subscription" + description = "Subscription for Certificate expiration alert" + destination_id = "email_destination_id" + topic_id = "topicId" + attributes { + add_notification_payload = true + reply_to_mail = "compliancealert@ibm.com" + reply_to_name = "Compliance User" + from_name = "en@ibm.com" + add = ["productionuser@ibm.com"] + unsubscribed = ["testuser@gamil.com"] + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +- `attributes` - (Optional, List) Subscription attributes. + Nested scheme for **attributes**: + + - `reply_to_name` - (String) The Email User Name to reply to. + + - `reply_to_mail` - (String) The email address to reply to. + + - `from_name` - (Optional, String) The email address user from which email is addressed. + + - `to`- (List) The Email address to send the email to. + + - `add`- (List) The Email address to add in case of updating the list of email addressses + + - `unsubscribed`- (List) The Email address list to be provided in case of removing the email addresses from subscription + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `email_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_email` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_email.email_en_subscription / +``` diff --git a/website/docs/r/en_subscription_firefox.html.markdown b/website/docs/r/en_subscription_firefox.html.markdown new file mode 100644 index 000000000..6d0e6cac8 --- /dev/null +++ b/website/docs/r/en_subscription_firefox.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_firefox' +description: |- + Manages Event Notifications Firefox subscription. +--- + +# ibm_en_subscription_android + +Create, update, or delete a Firefox subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_firefox" "firefox_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Android Subscription" + description = "Android Subscription for Notification" + destination_id = ibm_en_destination_firefox.firefx_destination.destination_id + topic_id = ibm_en_topic.topic1.topic_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `firefox_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_firefox` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_firefox.firefox_subscription / +``` diff --git a/website/docs/r/en_subscription_ios.html.markdown b/website/docs/r/en_subscription_ios.html.markdown new file mode 100644 index 000000000..f2481d283 --- /dev/null +++ b/website/docs/r/en_subscription_ios.html.markdown @@ -0,0 +1,65 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_ios' +description: |- + Manages Event Notifications IOS subscription. +--- + +# ibm_en_subscription_ios + +Create, update, or delete a IOS subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_ios" "ios_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "IOS Subscription" + description = "IOS device subscription" + destination_id = ibm_en_destination_ios.destinationiosp8.destination_id + topic_id = ibm_en_topic.topic1.topic_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `ios_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_ios` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_ios.ios_subscription / +``` diff --git a/website/docs/r/en_subscription_safari.html.markdown b/website/docs/r/en_subscription_safari.html.markdown new file mode 100644 index 000000000..8b379e8f7 --- /dev/null +++ b/website/docs/r/en_subscription_safari.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_safari' +description: |- + Manages Event Notifications Safari subscription. +--- + +# ibm_en_subscription_safari + +Create, update, or delete a Safari subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_safari" "safari_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "safari Subscription" + description = "safari Subscription for Notification" + destination_id = ibm_en_destination_safari.safari_destination.destination_id + topic_id = ibm_en_topic.topic1.topic_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `safari_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_safari` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_safari.safari_subscription / +``` diff --git a/website/docs/r/en_subscription_slack.html.markdown b/website/docs/r/en_subscription_slack.html.markdown new file mode 100644 index 000000000..ea96ef8e2 --- /dev/null +++ b/website/docs/r/en_subscription_slack.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_slack' +description: |- + Manages Event Notifications subscription. +--- + +# ibm_en_subscription_slack + +Create, update, or delete a slack subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_slack" "slack_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Slack subscription" + description = "The Slack subscription for slack destination in Event Notifications" + destination_id = ibm_en_destination_slack.destination1.destination_id + topic_id = ibm_en_topic.topic1.topic_id + attributes { + "attachment_color" = "#FF0000" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +- `attributes` - (Optional, List) Subscription attributes. + Nested scheme for **attributes**: + + - `attachment_color` - (Optional, Boolean) The color code for slack attachment. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `slack_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_slack` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_slack.slack_subscription / +``` diff --git a/website/docs/r/en_subscription_sms.html.markdown b/website/docs/r/en_subscription_sms.html.markdown new file mode 100644 index 000000000..e9a4ee3f8 --- /dev/null +++ b/website/docs/r/en_subscription_sms.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_sms' +description: |- + Manages Event Notifications SMS subscription. +--- + +# ibm_en_subscription_sms + +Create, update, or delete a SMS subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_sms" "sms_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "News Subscription" + description = "SMS subscription for news alert" + destination_id = "sms_destination_id" + topic_id = ibm_en_topic.topic1.topic_id + attributes { + to = ["+15678923404", "+19643567389"] + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +- `attributes` - (Optional, List) Subscription attributes. + Nested scheme for **attributes**: + + - `to` - (Optional, List) The phone number to send the SMS to. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `sms_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_sms` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_sms.sms_subscription / +``` diff --git a/website/docs/r/en_subscription_webhook.html.markdown b/website/docs/r/en_subscription_webhook.html.markdown new file mode 100644 index 000000000..0c602c422 --- /dev/null +++ b/website/docs/r/en_subscription_webhook.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_webhook' +description: |- + Manages Event Notifications subscription. +--- + +# ibm_en_subscription_webhook + +Create, update, or delete a Webhook subscription by using IBM Cloud™ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_subscription_webhook" "webhook_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My webhook subscription" + description = "The webhook subscription" + destination_id = ibm_en_destination_webhook.destination1.destination_id + topic_id = ibm_en_topic.topic1.topic_id + attributes { + signing_enabled = true + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +- `attributes` - (Optional, List) Subscription attributes. + Nested scheme for **attributes**: + + - `signing_enabled` - (Optional, Boolean) Signing enabled. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `webhook_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_webhook` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_webhook.wehook_subscription / +``` diff --git a/website/docs/r/en_topic.html.markdown b/website/docs/r/en_topic.html.markdown index 9b688df23..dff19479e 100644 --- a/website/docs/r/en_topic.html.markdown +++ b/website/docs/r/en_topic.html.markdown @@ -10,17 +10,17 @@ description: |- Create, update, or delete a topic by using IBM Cloud™ Event Notifications. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_en_topic" "en_topic" { - instance_guid = "instance_guid" - name = "name" - description = "description" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "e2e topic" + description = "Topic for EN events routing" } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. @@ -44,7 +44,7 @@ Review the argument reference that you can specify for your resource. - `notification_filter` - (Optional, String) Notification filter. The minimum length is`0`characters. The value must match regular expression`/[a-zA-Z 0-9-_$.=']-/`. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. diff --git a/website/docs/r/enterprise.html.markdown b/website/docs/r/enterprise.html.markdown index a12448fe9..d9820729c 100644 --- a/website/docs/r/enterprise.html.markdown +++ b/website/docs/r/enterprise.html.markdown @@ -11,7 +11,7 @@ description: |- Create and update an enterprise. Delete operation is not supported. For more information, about enterprise management, refer to [setting up an enterprise](https://cloud.ibm.com/docs/account?topic=account-create-enterprise). -## Example Usage +## Example usage ```terraform resource "ibm_enterprise" "enterprise" { diff --git a/website/docs/r/hpcs_key_template.html.markdown b/website/docs/r/hpcs_key_template.html.markdown new file mode 100644 index 000000000..0ed692a76 --- /dev/null +++ b/website/docs/r/hpcs_key_template.html.markdown @@ -0,0 +1,104 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_key_template" +description: |- + Manages key_template. +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_key_template + +Provides a resource for key_template. This allows key_template to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_hpcs_key_template" "key_template_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeyTemplate" + description = "example key template" + key { + size = "256" + algorithm = "aes" + activation_date = "P5Y1M1W2D" + expiration_date = "P1Y2M1W4D" + state = "active" + } + keystores { + group = "Production" + type = "aws_kms" + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Must match the region of the UKO instance you are trying to work with. Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `description` - (Optional, String) Description of the key template. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. +* `key` - (Required, List) Properties describing the properties of the managed key. +Nested scheme for **key**: + * `activation_date` - (Required, String) Key activation date can be provided as a period definition (e.g. PY1 means 1 year). + * Constraints: The maximum length is `100` characters. The minimum length is `3` characters. The value must match regular expression `/P^[0-9YMWD]+$/`. + * `algorithm` - (Required, String) The algorithm of the key. + * Constraints: Allowable values are: `aes`, `rsa`. + * `expiration_date` - (Required, String) Key expiration date can be provided as a period definition (e.g. PY1 means 1 year). + * Constraints: The maximum length is `100` characters. The minimum length is `3` characters. The value must match regular expression `/P^[0-9YMWD]+$/`. + * `size` - (Required, String) The size of the underlying cryptographic key or key pair. E.g. "256" for AES keys, or "2048" for RSA. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9]+$/`. + * `state` - (Required, String) The state that the key will be in after generation. + * Constraints: The default value is `active`. Allowable values are: `pre_activation`, `active`. +* `keystores` - (Required, List) An array describing the type and group of target keystores the managed key is to be installed in. + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **keystores**: + * `group` - (Required, String) Which keystore group to distribute the key to. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. + * `type` - (Required, String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. +* `name` - (Required, String) Name of the template, it will be referenced when creating managed keys. + * Constraints: The maximum length is `30` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9-]*$/`. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. +* `vault` - (Required, List) ID of the Vault where the entity is to be created in. +Nested scheme for **vault**: + * `id` - (Required, String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `template_id` - The unique identifier of the key_template. +* `created_at` - (String) Date and time when the key template was created. +* `created_by` - (String) ID of the user that created the key template. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. +* `updated_at` - (String) Date and time when the key template was updated. +* `updated_by` - (String) ID of the user that updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `version` - (Integer) Version of the key template. Every time the key template is updated, the version will be updated automatically. + * Constraints: The maximum value is `2147483647`. The minimum value is `1`. + +## Import + +You can import the `ibm_hpcs_key_template` resource by using `region`, `instance_id`, `vault_id`, and `template_id`. + +# Syntax +```bash +$ terraform import ibm_hpcs_key_template.template /// +``` + +# Example +``` +$ terraform import ibm_hpcs_key_template.key_template us-east/76195d24-8a31-4c6d-9050-c35f09375cfb/5295ad47-2ce9-43c3-b9e7-e5a9482c362b/d8cc1ef7-d13b-4731-95be-1f7c98c9f524 +``` diff --git a/website/docs/r/hpcs_keystore.html.markdown b/website/docs/r/hpcs_keystore.html.markdown new file mode 100644 index 000000000..d0825f637 --- /dev/null +++ b/website/docs/r/hpcs_keystore.html.markdown @@ -0,0 +1,231 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_keystore" +description: |- + Manages keystore. +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_keystore + +Provides a resource for keystore. This allows keystore to be created, updated and deleted. + +## Example Usage + +AWS Keystore +```hcl +resource "ibm_hpcs_keystore" "keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "aws_kms" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformKeystore" + description = "example keystore" + groups = ["Production"] + aws_region = "eu_central_1" + aws_access_key_id = "***" + aws_secret_access_key = "***" +} +``` + +Azure Keystore +```hcl +resource "ibm_hpcs_keystore" "azure_keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "azure_key_vault" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformAzureKeystore" + description = "example azure keystore" + groups = [ "Production-Azure" ] + azure_resource_group = "EKMF-Web-Tests" + azure_location = "europe_north" + azure_service_principal_client_id = "c8e8540f-4f15-4b6b-8862-3ccdb389e35d" + azure_service_principal_password = "***" + azure_tenant = "fcf67057-50c9-4ad4-98f3-ffca64add9e9" + azure_subscription_id = "a9867d9b-582f-42f3-9392-26856b06b808" + azure_environment = "azure" + azure_service_name = "ekmf-test-in-ibm-1" +} +``` + +IBMCloud KMS Keystore +```hcl +resource "ibm_hpcs_keystore" "hpcs_keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "ibm_cloud_kms" + ibm_variant = "hpcs" + ibm_key_ring = "IBM-Cloud-KMS-Internal" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformHPCSKeystore" + description = "example internal hpcs keystore" + groups = [ "Production-HPCS" ] + ibm_api_endpoint = "https://api.us-south.hs-crypto.test.cloud.ibm.com:9105" + ibm_iam_endpoint = "https://iam.test.cloud.ibm.com" + ibm_api_key = var.ibmcloud_api_key + ibm_instance_id = ibm_hpcs_vault.vault_instance.instance_id +} +``` + +IBMCloud Internal KMS Keystore +```hcl +resource "ibm_hpcs_keystore" "hpcs_keystore_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + type = "ibm_cloud_kms" + ibm_variant = "internal" + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + name = "terraformIBMInternalKeystore" + description = "example internal hpcs keystore" + groups = [ "Production-HPCS" ] +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Must match the region of the UKO instance you are trying to work with. Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `aws_access_key_id` - (Optional, String) The access key id used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_]*$/`. +* `aws_region` - (Optional, String) AWS Region. + * Constraints: Allowable values are: `af_south_1`, `ap_east_1`, `ap_northeast_1`, `ap_northeast_2`, `ap_south_1`, `ap_southeast_1`, `ap_southeast_2`, `aws_cn_global`, `aws_global`, `aws_iso_global`, `aws_iso_b_global`, `aws_us_gov_global`, `ca_central_1`, `cn_north_1`, `cn_northwest_1`, `eu_central_1`, `eu_west_1`, `eu_west_2`, `eu_west_3`, `me_south_1`, `sa_east_1`, `us_east_1`, `us_east_2`, `us_gov_east_1`, `us_gov_west_1`, `us_iso_east_1`, `us_isob_east_1`, `us_west_1`, `us_west_2`. +* `aws_secret_access_key` - (Optional, String) The secret access key used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_\/]*$/`. +* `azure_environment` - (Optional, String) Azure environment, usually 'Azure'. + * Constraints: Allowable values are: `azure`, `azure_china`, `azure_germany`, `azure_us_government`. +* `azure_location` - (Optional, String) Location of the Azure Key Vault. + * Constraints: Allowable values are: `asia_east`, `asia_southeast`, `australia_central`, `australia_central_2`, `australia_east`, `australia_southeast`, `brazil_south`, `canada_central`, `canada_east`, `china_east`, `china_east_2`, `china_north`, `china_north_2`, `europe_north`, `europe_west`, `france_central`, `france_south`, `germany_central`, `germany_northeast`, `india_central`, `india_south`, `india_west`, `japan_east`, `japan_west`, `korea_central`, `korea_south`, `south_africa_north`, `south_africa_west`, `uk_south`, `uk_west`, `us_central`, `us_dod_central`, `us_dod_east`, `us_east`, `us_east_2`, `us_gov_arizona`, `us_gov_iowa`, `us_gov_texas`, `us_gov_virginia`, `us_north_central`, `us_south_central`, `us_west`, `us_west_2`, `us_west_central`. +* `azure_resource_group` - (Optional, String) Resource group in Azure. + * Constraints: The maximum length is `90` characters. The minimum length is `1` character. The value must match regular expression `/^[-\\w\\._\\(\\)]*[^\\.]$/`. +* `azure_service_name` - (Optional, String) Service name of the key vault instance from the Azure portal. + * Constraints: The maximum length is `24` characters. The minimum length is `3` characters. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `azure_service_principal_client_id` - (Optional, String) Azure service principal client ID. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `azure_service_principal_password` - (Optional, String) Azure service principal password. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]+$/`. +* `azure_subscription_id` - (Optional, String) Subscription ID in Azure. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `azure_tenant` - (Optional, String) Azure tenant that the Key Vault is associated with,. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `description` - (Optional, String) Description of the keystore. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. +* `groups` - (Optional, List) A list of groups that this keystore belongs to. + * Constraints: The list items must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. The maximum length is `128` items. The minimum length is `1` item. +* `ibm_api_endpoint` - (Optional, String) API endpoint of the IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. +* `ibm_api_key` - (Optional, String) The IBM Cloud API key to be used for connecting to this IBM Cloud keystore. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_&.]*$/`. +* `ibm_iam_endpoint` - (Optional, String) Endpoint of the IAM service for this IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. +* `ibm_instance_id` - (Optional, String) The instance ID of the IBM Cloud keystore. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]*$/`. +* `ibm_key_ring` - (Optional, String) The key ring of an IBM Cloud KMS Keystore. + * Constraints: The default value is `Default`. The maximum length is `100` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9-]*$/`. +* `ibm_variant` - (Optional, String) Possible IBM Cloud KMS variants. + * Constraints: Allowable values are: `hpcs`, `internal`, `key_protect`. +* `name` - (Optional, String) Name of a target keystore. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9 .-_]*$/`. +* `type` - (Required, String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. +* `vault` - (Required, List) ID of the Vault where the entity is to be created in. +Nested scheme for **vault**: + * `id` - (Required, String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `keystore_id` - The unique identifier of the keystore. +* `aws_access_key_id` - (String) The access key id used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_]*$/`. +* `aws_region` - (String) AWS Region. + * Constraints: Allowable values are: `af_south_1`, `ap_east_1`, `ap_northeast_1`, `ap_northeast_2`, `ap_south_1`, `ap_southeast_1`, `ap_southeast_2`, `aws_cn_global`, `aws_global`, `aws_iso_global`, `aws_iso_b_global`, `aws_us_gov_global`, `ca_central_1`, `cn_north_1`, `cn_northwest_1`, `eu_central_1`, `eu_west_1`, `eu_west_2`, `eu_west_3`, `me_south_1`, `sa_east_1`, `us_east_1`, `us_east_2`, `us_gov_east_1`, `us_gov_west_1`, `us_iso_east_1`, `us_isob_east_1`, `us_west_1`, `us_west_2`. +* `aws_secret_access_key` - (String) The secret access key used for connecting to this instance of AWS KMS. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_\/]*$/`. +* `azure_environment` - (String) Azure environment, usually 'Azure'. + * Constraints: Allowable values are: `azure`, `azure_china`, `azure_germany`, `azure_us_government`. +* `azure_location` - (String) Location of the Azure Key Vault. + * Constraints: Allowable values are: `asia_east`, `asia_southeast`, `australia_central`, `australia_central_2`, `australia_east`, `australia_southeast`, `brazil_south`, `canada_central`, `canada_east`, `china_east`, `china_east_2`, `china_north`, `china_north_2`, `europe_north`, `europe_west`, `france_central`, `france_south`, `germany_central`, `germany_northeast`, `india_central`, `india_south`, `india_west`, `japan_east`, `japan_west`, `korea_central`, `korea_south`, `south_africa_north`, `south_africa_west`, `uk_south`, `uk_west`, `us_central`, `us_dod_central`, `us_dod_east`, `us_east`, `us_east_2`, `us_gov_arizona`, `us_gov_iowa`, `us_gov_texas`, `us_gov_virginia`, `us_north_central`, `us_south_central`, `us_west`, `us_west_2`, `us_west_central`. +* `azure_resource_group` - (String) Resource group in Azure. + * Constraints: The maximum length is `90` characters. The minimum length is `1` character. The value must match regular expression `/^[-\\w\\._\\(\\)]*[^\\.]$/`. +* `azure_service_name` - (String) Service name of the key vault instance from the Azure portal. + * Constraints: The maximum length is `24` characters. The minimum length is `3` characters. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `azure_service_principal_client_id` - (String) Azure service principal client ID. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `azure_service_principal_password` - (String) Azure service principal password. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z_.]+$/`. +* `azure_subscription_id` - (String) Subscription ID in Azure. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `azure_tenant` - (String) Azure tenant that the Key Vault is associated with,. + * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-zA-Z]+$/`. +* `created_at` - (String) Date and time when the target keystore was created. +* `created_by` - (String) ID of the user that created the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `description` - (String) Description of the keystore. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. +* `groups` - (List) List of groups that this keystore belongs to. + * Constraints: The list items must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. The maximum length is `128` items. The minimum length is `1` item. +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. +* `ibm_api_endpoint` - (String) API endpoint of the IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. +* `ibm_api_key` - (String) The IBM Cloud API key to be used for connecting to this IBM Cloud keystore. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-_&.]*$/`. +* `ibm_iam_endpoint` - (String) Endpoint of the IAM service for this IBM Cloud keystore. + * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/-]+$/`. +* `ibm_instance_id` - (String) The instance ID of the IBM Cloud keystore. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]*$/`. +* `ibm_key_ring` - (String) The key ring of an IBM Cloud KMS Keystore. + * Constraints: The default value is `Default`. The maximum length is `100` characters. The minimum length is `2` characters. The value must match regular expression `/^[a-zA-Z0-9-]*$/`. +* `ibm_variant` - (String) Possible IBM Cloud KMS variants. + * Constraints: Allowable values are: `hpcs`, `internal`, `key_protect`. +* `name` - (String) Name of the target keystore. It can be changed in the future. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9 .-_]*$/`. +* `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. +* `updated_at` - (String) Date and time when the target keystore was last updated. +* `updated_by` - (String) ID of the user that last updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `vault` - (List) Reference to a vault. +Nested scheme for **vault**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the referenced vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +* `version` - Version of the keystore. + +## Import + +You can import the `ibm_hpcs_keystore` resource by using `region`, `instance_id`, `vault_id`, and `keystore_id`. + +# Syntax +```bash +$ terraform import ibm_hpcs_keystore.keystore /// +``` + +# Example +``` +$ terraform import ibm_hpcs_keystore.keystore us-east/76195d24-8a31-4c6d-9050-c35f09375cfb/5295ad47-2ce9-43c3-b9e7-e5a9482c362b/d8cc1ef7-d13b-4731-95be-1f7c98c9f524 +``` diff --git a/website/docs/r/hpcs_managed_key.html.markdown b/website/docs/r/hpcs_managed_key.html.markdown new file mode 100644 index 000000000..6648d8893 --- /dev/null +++ b/website/docs/r/hpcs_managed_key.html.markdown @@ -0,0 +1,133 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_managed_key" +description: |- + Manages managed_key. +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_managed_key + +Provides a resource for managed_key. This allows managed_key to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_hpcs_managed_key" "managed_key_instance" { + instance_id = ibm_hpcs_vault.vault_instance.instance_id + region = ibm_hpcs_vault.vault_instance.region + uko_vault = ibm_hpcs_vault.vault_instance.vault_id + vault { + id = ibm_hpcs_vault.vault_instance.vault_id + } + label = "terraformKey" + description = "example key" + template_name = ibm_hpcs_key_template.key_template_instance.name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Must match the region of the UKO instance you are trying to work with. Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `description` - (Optional, String) Description of the managed key. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. +* `label` - (Required, String) The label of the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._ -]+$/`. +* `tags` - (Optional, List) Key-value pairs associated with the key. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **tags**: + * `name` - (Required, String) Name of a tag. + * Constraints: The maximum length is `254` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9 -_]+$/`. + * `value` - (Required, String) Value of a tag. + * Constraints: The maximum length is `8192` characters. The minimum length is `1` character. The value must match regular expression `/^(\\w|\\s)*$/`. +* `template_name` - (Required, String) Name of the key template to use when creating a key. + * Constraints: The maximum length is `30` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9-]+$/`. +* `uko_vault` - (Required, String) The UUID of the Vault in which the update is to take place. +* `vault` - (Required, List) ID of the Vault where the entity is to be created in. +Nested scheme for **vault**: + * `id` - (Required, String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `key_id` - The unique identifier of the managed_key. +* `activation_date` - (String) First day when the key is active. +* `algorithm` - (String) The algorithm of the key. + * Constraints: Allowable values are: `aes`, `rsa`. +* `created_at` - (String) Date and time when the key was created. +* `created_by` - (String) ID of the user that created the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `expiration_date` - (String) Last day when the key is active. +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. +* `instances` - (List) key instances. + * Constraints: The maximum length is `1` item. The minimum length is `1` item. +Nested scheme for **instances**: + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `keystore` - (List) Description of properties of a key within the context of keystores. + Nested scheme for **keystore**: + * `group` - (String) + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9-_ ]+$/`. + * `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. + * `label_in_keystore` - (String) The label of the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._ -]+$/`. + * `type` - (String) Type of the key instance. + * Constraints: Allowable values are: `public_key`, `private_key`, `key_pair`, `secret_key`. +* `referenced_keystores` - (List) referenced keystores. + * Constraints: The maximum length is `128` items. The minimum length is `0` items. +Nested scheme for **referenced_keystores**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the target keystore. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9][A-Za-z0-9 .-_]*$/`. + * `type` - (String) Type of keystore. + * Constraints: Allowable values are: `aws_kms`, `azure_key_vault`, `ibm_cloud_kms`. +* `size` - (String) The size of the underlying cryptographic key or key pair. E.g. "256" for AES keys, or "2048" for RSA. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9]+$/`. +* `state` - (String) The state of the key. + * Constraints: The default value is `active`. Allowable values are: `pre_activation`, `active`, `deactivated`, `destroyed`. +* `template` - (List) Reference to a key template. +Nested scheme for **template**: + * `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. + * `id` - (String) The v4 UUID used to uniquely identify the resource, as specified by RFC 4122. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[-0-9a-z]+$/`. + * `name` - (String) Name of the key template. + * Constraints: The maximum length is `30` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9-]*$/`. +* `updated_at` - (String) Date and time when the key was last updated. +* `updated_by` - (String) ID of the user that last updated the key. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]+$/`. +* `verification_patterns` - (List) A list of verification patterns of the key (e.g. public key hash for RSA keys). + * Constraints: The maximum length is `16` items. The minimum length is `1` item. +Nested scheme for **verification_patterns**: + * `method` - (String) The method used for calculating the verification pattern. + * Constraints: The maximum length is `100` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9-]+$/`. + * `value` - (String) The calculated value. + * Constraints: The maximum length is `100` characters. The minimum length is `0` characters. The value must match regular expression `/^[A-Za-z0-9+\/=]+$/`. + +* `version` - Version of the managed_key. + +## Import + +You can import the `ibm_hpcs_managed_key` resource by using `region`, `instance_id`, `vault_id`, and `key_id`. + +# Syntax +```bash +$ terraform import ibm_hpcs_managed_key.key /// +``` + +# Example +``` +$ terraform import ibm_hpcs_managed_key.key us-east/76195d24-8a31-4c6d-9050-c35f09375cfb/5295ad47-2ce9-43c3-b9e7-e5a9482c362b/d8cc1ef7-d13b-4731-95be-1f7c98c9f524 +``` diff --git a/website/docs/r/hpcs_vault.html.markdown b/website/docs/r/hpcs_vault.html.markdown new file mode 100644 index 000000000..1608f2a13 --- /dev/null +++ b/website/docs/r/hpcs_vault.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_hpcs_vault" +description: |- + Manages vault. +subcategory: "Hyper Protect Crypto Services" +--- + +# ibm_hpcs_vault + +Provides a resource for vault. This allows vault to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_hpcs_vault" "vault_instance" { + instance_id = "76195d24-8a31-4c6d-9050-c35f09375cfb" + region = "us-east" + name = "terraformVault" + description = "example vault" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `instance_id` - (Required, String) ID of UKO Instance + * Constraints: Must match the ID of the UKO instance you are trying to work with. +* `region` - (Required, String) Region of the UKO Instance + * Constraints: Must match the region of the UKO instance you are trying to work with. Allowable values are: `au-syd`, `in-che`, `jp-osa`, `jp-tok`, `kr-seo`, `eu-de`, `eu-gb`, `ca-tor`, `us-south`, `us-south-test`, `us-east`, `br-sao`. +* `description` - (Optional, String) Description of the vault. + * Constraints: The maximum length is `200` characters. The minimum length is `0` characters. The value must match regular expression `/(.|\\n)*/`. +* `name` - (Required, String) A human-readable name to assign to your vault. To protect your privacy, do not use personal data, such as your name or location. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `vault_id` - The unique identifier of the vault. +* `created_at` - (String) Date and time when the vault was created. +* `created_by` - (String) ID of the user that created the vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$%'_-]*$/`. +* `href` - (String) A URL that uniquely identifies your cloud resource. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9._~:\/?&=-]+$/`. +* `updated_at` - (String) Date and time when the vault was last updated. +* `updated_by` - (String) ID of the user that last updated the vault. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z][A-Za-z0-9#@!$% '_-]*$/`. + +* `version` - Version of the vault. + +## Import + +You can import the `ibm_hpcs_vault` resource by using `region`, `instance_id`, and `vault_id`. + +# Syntax +```bash +$ terraform import ibm_hpcs_vault.vault // +``` + +# Example +``` +$ terraform import ibm_hpcs_vault.vault us-east/76195d24-8a31-4c6d-9050-c35f09375cfb/5295ad47-2ce9-43c3-b9e7-e5a9482c362b +``` diff --git a/website/docs/r/iam_access_group_account_settings.html.markdown b/website/docs/r/iam_access_group_account_settings.html.markdown new file mode 100644 index 000000000..c156c4198 --- /dev/null +++ b/website/docs/r/iam_access_group_account_settings.html.markdown @@ -0,0 +1,33 @@ +--- +subcategory: "Identity & Access Management (IAM)" +layout: "ibm" +page_title: "IBM : iam_access_group_account_settings" +description: |- + Manages IAM Access Groups account level settings. +--- + +# ibm_iam_access_group_account_settings + +Create, modify, or delete an `iam_access_group_account_settings` resources. Access groups can be used to define a set of permissions that you want to grant to a group of users. For more information, about IAM account settings, refer to [setting up your IBM Cloud](https://cloud.ibm.com/docs/account?topic=account-account-getting-started). + +## Example usage + +```terraform +resource "ibm_iam_access_group_account_settings" "iam_access_group_account_settings" { + public_access_enabled = true +} +``` + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `public_access_enabled` - (Optional, Bool) Defines if the public groups are included in the response for access group listing. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `account_id` - (String) Unique ID of an account. +- `public_access_enabled` - (Bool) if the public groups are enabled for access group listing. + diff --git a/website/docs/r/iam_access_group_members.html.markdown b/website/docs/r/iam_access_group_members.html.markdown index 5325eaa98..13baf44b1 100644 --- a/website/docs/r/iam_access_group_members.html.markdown +++ b/website/docs/r/iam_access_group_members.html.markdown @@ -15,7 +15,7 @@ description: |- Add, update, or remove users from an IAM access group members. For more information, about IAM access group members, see [managing public access to resources](https://cloud.ibm.com/docs/account?topic=account-public). ## Example usage -The following example creates an IAM access group and a service ID. Then, the service ID and a user with the ID `user@ibm.com` is added to the access group. +The following example creates an IAM access group, a service ID and a trusted profile ID. Then, the service ID, profile ID and a user with the ID `user@ibm.com` is added to the access group. ```terraform resource "ibm_iam_access_group" "accgroup" { @@ -26,10 +26,15 @@ resource "ibm_iam_service_id" "serviceID" { name = "testserviceid" } +resource "ibm_iam_trusted_profile" "profileID" { + name = "testprofileid" +} + resource "ibm_iam_access_group_members" "accgroupmem" { access_group_id = ibm_iam_access_group.accgroup.id ibm_ids = ["test@in.ibm.com"] iam_service_ids = [ibm_iam_service_id.serviceID.id] + iam_profile_ids = [ibm_iam_trusted_profile.profileID.id] } ``` @@ -41,6 +46,7 @@ Review the argument references that you can specify for your resource. - `access_group_id` - (Required, String) The ID of the access group. - `ibm_ids` - (Optional, Array of string) A list of IBM IDs that you want to add to or remove from the access group. - `iam_service_ids` - (Optional, Array of string) A list of service IDS that you want to add to or remove from the access group. +- `iam_profile_ids` - (Optional, Array of string) A list of trusted profile IDS that you want to add to or remove from the access group. ## Attribute reference @@ -51,8 +57,8 @@ In addition to all argument reference list, you can access the following attribu - `members` - (Array of objects) A list of members that are included in the access group. Nested scheme for `members`: - - `iam_id` - (String) The IBM ID or service ID of the member. - - `type` - (String) The type of member. Supported values are `user` or `service`. + - `iam_id` - (String) The IBM ID or service ID or profile ID of the member. + - `type` - (String) The type of member. Supported values are `user` or `service` or `profile`. ## Import diff --git a/website/docs/r/iam_access_group_policy.html.markdown b/website/docs/r/iam_access_group_policy.html.markdown index acfdea37f..40da05188 100644 --- a/website/docs/r/iam_access_group_policy.html.markdown +++ b/website/docs/r/iam_access_group_policy.html.markdown @@ -7,7 +7,7 @@ description: |- Manages IBM IAM access group policy. --- -# ibm_access_group_policy +# ibm_iam_access_group_policy Create, update, or delete an IAM policy for an IAM access group. For more information, about IBM access group policy, see [creating policies for account management service access](https://cloud.ibm.com/docs/account?topic=account-account-services#account-management-access). @@ -24,6 +24,11 @@ resource "ibm_iam_access_group" "accgrp" { resource "ibm_iam_access_group_policy" "policy" { access_group_id = ibm_iam_access_group.accgrp.id roles = ["Viewer"] + resource_tags { + name = "env" + value = "dev" + } + transaction_id = "terraformUserPolicy" } ``` @@ -51,7 +56,25 @@ resource "ibm_iam_access_group_policy" "policy" { ``` ### Access group policy using service with region -The following example creates an IAM policy that grants members of the access group the IAM `Viewer` platform role to all service instances of IBM Cloud Object Storage. +The following example creates an IAM policy that grants members of the access group the IAM `Viewer` platform role to all service instances of cloudantnosqldb in us-south region + +```terraform +resource "ibm_iam_access_group" "accgrp" { + name = "test" +} + +resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + + resources { + service = "cloudantnosqldb" + region = "us-south" + } +} +``` + +### Access group policy using service_type with region ```terraform resource "ibm_iam_access_group" "accgrp" { @@ -63,7 +86,8 @@ resource "ibm_iam_access_group_policy" "policy" { roles = ["Viewer"] resources { - service = "cloud-object-storage" + service_type = "service" + region = "us-south" } } @@ -208,7 +232,8 @@ Review the argument references that you can specify for your resource. - `resource_type` (Optional, String) The resource type of the policy definition. - `resource` (Optional, String) The resource of the policy definition. - `resources.resource_group_id` - (Optional, String) The ID of the resource group. To retrieve the ID, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. - - `service` - (Optional, String) The service name that you want to include in your policy definition. For account management services, you can find supported values in the [documentation](https://cloud.ibm.com/docs/account?topic=account-account-services#api-acct-mgmt). For other services, run the `ibmcloud catalog service-marketplace` command and retrieve the value from the **Name** column of your command line output. + - `service` - (Optional, String) The service name that you want to include in your policy definition. For account management services, you can find supported values in the [documentation](https://cloud.ibm.com/docs/account?topic=account-account-services#api-acct-mgmt). For other services, run the `ibmcloud catalog service-marketplace` command and retrieve the value from the **Name** column of your command line output. Attributes service, service_type are mutually exclusive. + - `service_type` (Optional, String) The service type of the policy definition. **Note** Attributes service, service_type are mutually exclusive. - `resource_attributes` - (Optional, List) A nested block describing the resource of this policy. **Note** Conflicts with `account_management` and `resources`. @@ -216,7 +241,15 @@ Review the argument references that you can specify for your resource. - `name` - (Required, String) Name of an attribute. Supported values are `serviceName`, `serviceInstance`, `region`,`resourceType`, `resource`, `resourceGroupId`, and other service specific resource attributes. - `value` - (Required, String) Value of an attribute. - `operator` - (Optional, string) Operator of an attribute. Default value is `stringEquals`. **Note** Conflicts with `account_management` and `resources`. -- `tags` - (Optional, Array of strings) A list of tags that you want to add to the access group policy. **Note** `Tags` are managed locally and not stored on the IBM Cloud Service Endpoint at this moment. + +- `resource_tags` (Optional, List) A nested block describing the access management tags. **Note** `resource_tags` are only allowed in policy with resource attribute serviceType, where value is equal to service. + + Nested scheme for `resource_tags`: + - `name` - (Required, String) The key of an access management tag. + - `value` - (Required, String) The value of an access management tag. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. + +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for tracking the calls. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/iam_api_key.html.markdown b/website/docs/r/iam_api_key.html.markdown index 9954daaab..4e5f5a44f 100644 --- a/website/docs/r/iam_api_key.html.markdown +++ b/website/docs/r/iam_api_key.html.markdown @@ -9,7 +9,7 @@ description: |- # ibm_iam_api_key -Create, modify, or delete an `ibm_iam_api_key` resources. For more information, about IAM API Key, see [managing user API keys](https://cloud.ibm.com/docs/account?topic=account-userapikey). +Create, modify, or delete an IAM API key resources. For more information, about IAM API Key, see [managing user API keys](https://cloud.ibm.com/docs/account?topic=account-userapikey). ## Example usage @@ -23,7 +23,7 @@ resource "ibm_iam_api_key" "iam_api_key" { Review the argument references that you can specify for your resource. -- `apikey` - (Optional, String) You can passthrough the API key value for this API key. If passed, that API key value is not validated, means, the value can be non URL safe. If omitted, the API key management creates an URL safe opaque API key value. The value of the API key is checked for uniqueness. Please ensure enough variations when passing the value. +- `apikey` - (Optional, String) You can passthrough an API key value for this API key. If passed, that API key value is not validated, means, the value can be non URL safe. If omitted, the API key management creates an URL safe opaque API key value. The value of the API key is checked for uniqueness. Please ensure enough variations when passing the value. - `description` - (Optional, String) The description of the API key. The `description` property is only available if a description was provided during API key creation. - `entity_lock` - (Optional, Bool) Indicates the API key is locked for further write operations. Default value is `false`. - `file` - (Optional, String) The file name where API key is to be stored. @@ -36,12 +36,12 @@ Review the argument references that you can specify for your resource. In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `apikey_id` - (String) The unique identifier of the `ibm_iam_api_key`. -- `created_at` - (Timestamp)If set contains a date time string of the creation date in ISO format. -- `created_by` - (String) IAM ID of the user or service that created the API key. -- `crn` - (String) Cloud Resource Name (CRN) of the item. For example, CRN = `crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-1111`. -- `entity_tag` - (String) Version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates. +- `created_at` - (Timestamp) If set contains the creation date time string in an ISO format. +- `created_by` - (String) The IAM ID of the user or service that creates the API key. +- `crn` - (String) The Cloud Resource Name (CRN) of an item. For example, CRN = `crn:v1:bluemix:public:iam-identity:us-south:a/myaccount::apikey:1234-9012-1111`. +- `entity_tag` - (String) The version of the API Key details object. You need to specify this value when updating the API key to avoid stale updates. - `locked` - (String) The API key cannot be changed if set to `true`. -- `modified_at` - (Timestamp) If set contains a date time string of the last modification date in ISO format. +- `modified_at` - (Timestamp) If set contains the last modification date in an ISO format. ## Import diff --git a/website/docs/r/iam_authorization_policy.html.markdown b/website/docs/r/iam_authorization_policy.html.markdown index 63d2e4670..16009a648 100644 --- a/website/docs/r/iam_authorization_policy.html.markdown +++ b/website/docs/r/iam_authorization_policy.html.markdown @@ -21,6 +21,7 @@ resource "ibm_iam_authorization_policy" "policy" { target_service_name = "kms" roles = ["Reader"] description = "Authorization Policy" + transaction_id = "terraformAuthorizationPolicy" } ``` @@ -31,7 +32,7 @@ resource "ibm_iam_authorization_policy" "policy" { resource "ibm_iam_authorization_policy" "policy" { source_service_name = "databases-for-postgresql" target_service_name = "kms" - roles = ["Reader", "AuthorizationDelegator"] + roles = ["Reader", "Authorization Delegator"] } ``` @@ -93,21 +94,75 @@ resource "ibm_iam_authorization_policy" "policy" { ``` + +### Authorization policy between two specific services. + +```terraform + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Reader", + ] + + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "internet-svcs" + } + + resource_attributes { + name = "cfgType" + value = "reliability" + } + + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "serviceName" + value = "cloudcerts" + } +} + +``` +If user wants to add any resource specific attributes, for example `cfgType` +specific to a service `internet-svcs` use above `resource_attributes` format.
+**Note**: The serviceName and accountId attributes are required for both resource and subject in authorization + ## Argument reference Review the argument references that you can specify for your resource. - `description` (Optional, String) The description of the Authorization Policy. - `roles` - (Required, list) The comma separated list of roles. For more information, about supported service specific roles, see [IAM roles and actions](https://cloud.ibm.com/docs/account?topic=account-iam-service-roles-actions) -- `source_service_account` - (Optional, Forces new resource, string) The account GUID of source service. -- `source_service_name` - (Required, Forces new resource, string) The source service name. -- `target_service_name` - (Required, Forces new resource, string) The target service name. -- `source_resource_instance_id` - (Optional, Forces new resource, string) The source resource instance id. -- `target_resource_instance_id` - (Optional, Forces new resource, string) The target resource instance id. -- `source_resource_type` - (Optional, Forces new resource, string) The resource type of source service. -- `target_resource_type` - (Optional, Forces new resource, string) The resource type of target service. -- `source_resource_group_id` - (Optional, Forces new resource, string) The source resource group id. -- `target_resource_group_id` - (Optional, Forces new resource, string) The target resource group id. +- `source_service_account` - (Optional, Forces new resource, string) The account GUID of source service.**Note** Conflicts with `subject_attributes`. +- `source_service_name` - (Required, Forces new resource, string) The source service name.**Note** Conflicts with `subject_attributes`. +- `target_service_name` - (Required, Forces new resource, string) The target service name.**Note** Conflicts with `resource_attributes`. +- `source_resource_instance_id` - (Optional, Forces new resource, string) The source resource instance id.**Note** Conflicts with `subject_attributes`. +- `target_resource_instance_id` - (Optional, Forces new resource, string) The target resource instance id.**Note** Conflicts with `resource_attributes`. +- `source_resource_type` - (Optional, Forces new resource, string) The resource type of source service.**Note** Conflicts with `subject_attributes`. +- `target_resource_type` - (Optional, Forces new resource, string) The resource type of target service.**Note** Conflicts with `resource_attributes`. +- `source_resource_group_id` - (Optional, Forces new resource, string) The source resource group id.**Note** Conflicts with `subject_attributes`. +- `target_resource_group_id` - (Optional, Forces new resource, string) The target resource group id.**Note** Conflicts with `resource_attributes`. +- `resource_attributes` - (Optional, Forces new resource, list) A nested block describing the resource attributes of this policy.**Note** Conflicts with `target_resource_instance_id`, `target_resource_group_id` and `target_resource_type`. + + Nested scheme for `resource_attributes`: + - `name` - (Required, String) The name of an attribute. Supported values are `serviceName` , `serviceInstance` ,`resourceType` , `resourceGroupId` `accountId` and other service specific resource attributes. + - `value` - (Required, String) The value of an attribute. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. + +- `subject_attributes` - (Optional, Forces new resource, list) A nested block describing the subject attributes of this policy.**Note** Conflicts with `source_resource_instance_id`, `source_resource_group_id` `source_resource_type` and `source_service_account`. + + Nested scheme for `subject_attributes`: + - `name` - (Required, String) The name of an attribute. Supported values are `serviceName` , `serviceInstance` , `region` , `resource` , `resourceType` , `resourceGroupId` `accountId`. + - `value` - (Required, String) The value of an attribute. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/iam_service_policy.html.markdown b/website/docs/r/iam_service_policy.html.markdown index 86d6c7a65..7b4dd179e 100644 --- a/website/docs/r/iam_service_policy.html.markdown +++ b/website/docs/r/iam_service_policy.html.markdown @@ -16,14 +16,21 @@ Create, update, or delete an IAM service policy. For more information, about IAM ### Service policy for all Identity and Access enabled services ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Viewer"] description = "IAM Service Policy" + + resource_tags { + name = "env" + value = "dev" + } + + transaction_id = "terraformServicePolicy" } ``` @@ -31,16 +38,17 @@ resource "ibm_iam_service_policy" "policy" { ### Service Policy using service with region ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id - roles = ["Viewer"] + iam_service_id = ibm_iam_service_id.service_id.id + roles = ["Viewer", "Manager"] resources { - service = "cloud-object-storage" + service = "cloudantnosqldb" + region = "us-south" } } @@ -48,7 +56,7 @@ resource "ibm_iam_service_policy" "policy" { ### Service policy by using resource instance ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } @@ -60,7 +68,7 @@ resource "ibm_resource_instance" "instance" { } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Manager", "Viewer", "Administrator"] resources { @@ -74,7 +82,7 @@ resource "ibm_iam_service_policy" "policy" { ### Service policy by using resource group ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } @@ -83,7 +91,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Viewer"] resources { @@ -97,7 +105,7 @@ resource "ibm_iam_service_policy" "policy" { ### Service policy by using resource and resource type ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } @@ -106,7 +114,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Administrator"] resources { @@ -120,7 +128,7 @@ resource "ibm_iam_service_policy" "policy" { ### Service policy by using attributes ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } @@ -129,7 +137,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Administrator"] resources { @@ -149,7 +157,7 @@ provider "ibm" { alias = "accA" ibmcloud_api_key = "Account A Api Key" } -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { provider = ibm.accA name = "test" } @@ -160,7 +168,7 @@ provider "ibm" { } resource "ibm_iam_service_policy" "policy" { provider = ibm.accB - iam_id = ibm_iam_service_id.serviceID.iam_id + iam_id = ibm_iam_service_id.service_id.iam_id roles = ["Reader"] resources { service = "cloud-object-storage" @@ -172,11 +180,11 @@ resource "ibm_iam_service_policy" "policy" { ### Service policy by using resource_attributes ```terraform -resource "ibm_iam_service_id" "serviceID" { +resource "ibm_iam_service_id" "service_id" { name = "test" } resource "ibm_iam_service_policy" "policy" { - iam_service_id = ibm_iam_service_id.serviceID.id + iam_service_id = ibm_iam_service_id.service_id.id roles = ["Viewer"] resource_attributes { name = "resource" @@ -190,6 +198,25 @@ resource "ibm_iam_service_policy" "policy" { } ``` +### Service Policy using service_type with region + +```terraform +resource "ibm_iam_service_id" "service_id" { + name = "test" +} + +resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.service_id.id + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } +} + +``` + ## Argument reference Review the argument references that you can specify for your resource. @@ -200,7 +227,8 @@ Review the argument references that you can specify for your resource. - `resources` - (List of Objects) Optional- A nested block describes the resource of this policy.**Note** Conflicts with `account_management` and `resource_attributes`. Nested scheme for `resources`: - - `service` (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. + - `service` (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. Attributes service, service_type are mutually exclusive. + - `service_type` (Optional, String) The service type of the policy definition. **Note** Attributes service, service_type are mutually exclusive. - `resource_instance_id` - (Optional, String) The ID of the resource instance of the policy definition. - `region` - (Optional, String) The region of the policy definition. - `resource_type` - (Optional, String) The resource type of the policy definition. @@ -214,7 +242,15 @@ Review the argument references that you can specify for your resource. - `value` - (Required, String) The value of an attribute. - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. **Note** Conflicts with `account_management` and `resources`. - `roles` - (Required, List) A comma separated list of roles. Valid roles are `Writer`, `Reader`, `Manager`, `Administrator`, `Operator`, `Viewer`, and `Editor`. For more information, about supported service specific roles, see [IAM roles and actions](https://cloud.ibm.com/docs/account?topic=account-iam-service-roles-actions) -- `tags` - (Optional, List of Strings) A list of tags with the service policy instance. **Note** Tags are managed locally and not stored in the IBM Cloud service endpoint at this moment. + +- `resource_tags` (Optional, List) A nested block describing the access management tags. **Note** `resource_tags` are only allowed in policy with resource attribute serviceType, where value is equal to service. + + Nested scheme for `resource_tags`: + - `name` - (Required, String) The key of an access management tag. + - `value` - (Required, String) The value of an access management tag. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. + +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for tracking the calls. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/iam_trusted_profile_policy.html.markdown b/website/docs/r/iam_trusted_profile_policy.html.markdown index daea3cb6b..b20aa4112 100644 --- a/website/docs/r/iam_trusted_profile_policy.html.markdown +++ b/website/docs/r/iam_trusted_profile_policy.html.markdown @@ -16,14 +16,20 @@ Create, update, or delete an IAM trusted profile policy. For more information, a ### Trusted Profile Policy for all Identity and Access enabled services ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Viewer"] description = "IAM Trusted Profile Policy" + + resource_tags { + name = "env" + value = "dev" + } + transaction_id = "terraformTrustedPolicy" } ``` @@ -31,16 +37,17 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy using service with region ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id - roles = ["Viewer"] + profile_id = ibm_iam_trusted_profile.profile_id.id + roles = ["Viewer", "Manager"] resources { - service = "cloud-object-storage" + service = "cloudantnosqldb" + region = "us-south" } } @@ -48,7 +55,7 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy by using resource instance ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } @@ -60,7 +67,7 @@ resource "ibm_resource_instance" "instance" { } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Manager", "Viewer", "Administrator"] resources { @@ -74,7 +81,7 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy by using resource group ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } @@ -83,7 +90,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Viewer"] resources { @@ -97,7 +104,7 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy by using resource and resource type ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } @@ -106,7 +113,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Administrator"] resources { @@ -120,7 +127,7 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy by using attributes ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } @@ -129,7 +136,7 @@ data "ibm_resource_group" "group" { } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Administrator"] resources { @@ -146,11 +153,11 @@ resource "ibm_iam_trusted_profile_policy" "policy" { ### Trusted Profile Policy by using resource_attributes ```terraform -resource "ibm_iam_trusted_profile" "profileID" { +resource "ibm_iam_trusted_profile" "profile_id" { name = "test" } resource "ibm_iam_trusted_profile_policy" "policy" { - profile_id = ibm_iam_trusted_profile.profileID.id + profile_id = ibm_iam_trusted_profile.profile_id.id roles = ["Viewer"] resource_attributes { name = "resource" @@ -162,6 +169,44 @@ resource "ibm_iam_trusted_profile_policy" "policy" { value = "messagehub" } } +``` +### Trusted Profile Policy by using resource_attributes (serviceName,serviceInstance) +```terraform +resource "ibm_iam_trusted_profile" "profile_id" { + name = "test" +} +resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profile_id.id + roles = ["Viewer"] + + resource_attributes { + name = "serviceName" + value = "databases-for-redis" + } + + resource_attributes { + name = "serviceInstance" + value = var.redis_guid + } +} +``` +### Trusted Profile Policy using service_type with region + +```terraform +resource "ibm_iam_trusted_profile" "profile_id" { + name = "test" +} + +resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profile_id.id + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } +} + ``` ## Argument reference @@ -174,7 +219,8 @@ Review the argument references that you can specify for your resource. - `resources` - (List of Objects) Optional- A nested block describes the resource of this policy.**Note** Conflicts with `account_management` and `resource_attributes`. Nested scheme for `resources`: - - `service` (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. + - `service` (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. Attributes service, service_type are mutually exclusive. + - `service_type` (Optional, String) The service type of the policy definition. **Note** Attributes service, service_type are mutually exclusive. - `resource_instance_id` - (Optional, String) The ID of the resource instance of the policy definition. - `region` - (Optional, String) The region of the policy definition. - `resource_type` - (Optional, String) The resource type of the policy definition. @@ -188,7 +234,15 @@ Review the argument references that you can specify for your resource. - `value` - (Required, String) The value of an attribute. - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. **Note** Conflicts with `account_management` and `resources`. - `roles` - (Required, List) A comma separated list of roles. Valid roles are `Writer`, `Reader`, `Manager`, `Administrator`, `Operator`, `Viewer`, and `Editor`. For more information, about supported service specific roles, see [IAM roles and actions](https://cloud.ibm.com/docs/account?topic=account-iam-service-roles-actions) -- `tags` - (Optional, List of Strings) A list of tags with the trusted profile policy instance. **Note** Tags are managed locally and not stored in the IBM Cloud service endpoint at this moment. + +- `resource_tags` (Optional, List) A nested block describing the access management tags. **Note** `resource_tags` are only allowed in policy with resource attribute serviceType, where value is equal to service. + + Nested scheme for `resource_tags`: + - `name` - (Required, String) The key of an access management tag. + - `value` - (Required, String) The value of an access management tag. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. + +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for tracking the calls. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/iam_user_policy.html.markdown b/website/docs/r/iam_user_policy.html.markdown index a0253c51a..073bc92b2 100644 --- a/website/docs/r/iam_user_policy.html.markdown +++ b/website/docs/r/iam_user_policy.html.markdown @@ -20,6 +20,12 @@ resource "ibm_iam_user_policy" "policy" { ibm_id = "test@in.ibm.com" roles = ["Viewer"] description = "IAM User Policy" + + resource_tags { + name = "env" + value = "dev" + } + } ``` @@ -29,10 +35,11 @@ resource "ibm_iam_user_policy" "policy" { ```terraform resource "ibm_iam_user_policy" "policy" { ibm_id = "test@in.ibm.com" - roles = ["Viewer"] + roles = ["Viewer", "Manager"] resources { - service = "kms" + service = "cloudantnosqldb" + region = "us-south" } } @@ -137,6 +144,21 @@ resource "ibm_iam_user_policy" "policy" { } ``` +### User policy using service_type with region + +```terraform +resource "ibm_iam_user_policy" "policy" { + ibm_id = "test@in.ibm.com" + roles = ["Viewer"] + + resources { + service_type = "service" + region = "us-south" + } +} + +``` + ## Argument reference Review the argument references that you can specify for your resource. @@ -153,15 +175,23 @@ Review the argument references that you can specify for your resource. - `resource_type` - (Optional, String) The resource type of the policy definition. - `resource` - (Optional, String) The resource of the policy definition. - `resource_group_id` - (Optional, String) The ID of the resource group. To retrieve the value, run `ibmcloud resource groups` or use the `ibm_resource_group` data source. - - `service` - (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search` command in the [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cloud-cli-getting-started). + - `service` - (Optional, String) The service name of the policy definition. You can retrieve the value by running the `ibmcloud catalog service-marketplace` or `ibmcloud catalog search` command in the [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cloud-cli-getting-started). Attributes service, service_type are mutually exclusive. + - `service_type` (Optional, String) The service type of the policy definition. **Note** Attributes service, service_type are mutually exclusive. - `resource_attributes` - (Optional, List) A nested block describing the resource of this policy. - `resource_attributes` - (Optional, List) A nested block describing the resource of this policy. **Note** Conflicts with `account_management` and `resources`. Nested scheme for `resource_attributes`: - `name` - (Required, String) The name of an Attribute. Supported values are `serviceName`, `serviceInstance`, `region`,`resourceType`, `resource`, `resourceGroupId`, and other service specific resource attributes. - `value` - (Required, String) The value of an attribute. - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. **Note**: Conflicts with `account_management` and `resources`. -- `tags` (Optional, Array of Strings) A list of tags that are associated with the service policy instance. **Note** `Tags` are managed locally and not stored on the IBM Cloud Service Endpoint at this moment. +- `resource_tags` (Optional, List) A nested block describing the access management tags. **Note** `resource_tags` are only allowed in policy with resource attribute serviceType, where value is equal to service. + + Nested scheme for `resource_tags`: + - `name` - (Required, String) The key of an access management tag. + - `value` - (Required, String) The value of an access management tag. + - `operator` - (Optional, String) Operator of an attribute. The default value is `stringEquals`. + +- `transaction_id`- (Optional, String) The TransactionID can be passed to your request for tracking the calls. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/is_backup_policy.html.markdown b/website/docs/r/is_backup_policy.html.markdown new file mode 100644 index 000000000..a6b1a5d17 --- /dev/null +++ b/website/docs/r/is_backup_policy.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_backup_policy" +description: |- + Manages BackupPolicy. +--- + +# ibm_is_backup_policy + +Provides a resource for BackupPolicy. This allows BackupPolicy to be created, updated and deleted. For more information, about backup policy in your IBM Cloud VPC, see [Backup policy](https://cloud.ibm.com/docs/vpc?topic=vpc-backup-policy-create). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +resource "ibm_is_backup_policy" "example" { + match_user_tags = ["tag1"] + name = "example-backup-policy" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +- `match_resource_types` - (Optional, List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. The default value is `["volume"]`. +- `match_user_tags` - (Required, List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. +- `name` - (Required, String) The user-defined name for this backup policy. Names must be unique within the region this backup policy resides in. +- `resource_group` - (Optional, List) The resource group id, to use. If unspecified, the account's [default resource group](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used. + + Nested scheme for `resource_group`: + - `id` - (Optional, String) The unique identifier for this resource group. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the BackupPolicy. +- `created_at` - (String) The date and time that the backup policy was created. +- `crn` - (String) The CRN for this backup policy. +- `href` - (String) The URL for this backup policy. +- `last_job_completed_at` - (String) The date and time that the most recent job for this backup policy completed. +- `lifecycle_state` - (String) The lifecycle state of the backup policy. +- `resource_type` - (String) The resource type. +- `version` - Version of the BackupPolicy. + +## Import + +You can import the `ibm_is_backup_policy` resource by using `id`. The unique identifier for this backup policy. + +# Syntax +``` +$ terraform import ibm_is_backup_policy.is_backup_policy +``` + +# Example +``` +$ terraform import ibm_is_backup_policy.is_backup_policy 0fe9e5d8-0a4d-4818-96ec-e99708644a58 +``` diff --git a/website/docs/r/is_backup_policy_plan.html.markdown b/website/docs/r/is_backup_policy_plan.html.markdown new file mode 100644 index 000000000..bc572f893 --- /dev/null +++ b/website/docs/r/is_backup_policy_plan.html.markdown @@ -0,0 +1,87 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_backup_policy_plan" +description: |- + Manages Backup Policy Plan. +--- + +# ibm_is_backup_policy_plan + +Provides a resource for BackupPolicyPlan. This allows BackupPolicyPlan to be created, updated and deleted.For more information, about backup policy plan in your IBM Cloud VPC, see [Backup policy plan](https://cloud.ibm.com/docs/vpc?topic=vpc-backup-policy-create). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +resource "ibm_is_backup_policy_plan" "example" { + backup_policy_id = "backup_policy_id" + cron_spec = "0 12 * * *" + name = "example-backup-policy-plan" +} +``` + +->**Note:** Backup Policy Jobs are getting enhanced, will be available soon. + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +- `active` - (Optional, Boolean) Indicates whether the plan is active. +- `attach_user_tags` - (Optional, List) User tags to attach to each backup (snapshot) created by this plan. If unspecified, no user tags will be attached. +- `backup_policy_id` - (Required, Forces new resource, String) The backup policy identifier. +backup_policy_plan_id +- `copy_user_tags` - (Optional, Boolean) Indicates whether to copy the source's user tags to the created backups (snapshots). The default value is `true`. +- `cron_spec` - (Required, String) The cron specification for the backup schedule. The value must match regular expression `^((((\d+,)+\d+|([\d\*]+(\/|-)\d+)|\d+|\*) ?){5,7})$`. + + ->**Note** The backup policy jobs (which create and delete backups for this plan) will not start until this time, and may start for up to 90 minutes after this time.All backup schedules for plans in the same policy must be at least an hour apart. + +- `deletion_trigger` - (Optional, List) + + Nested scheme for `deletion_trigger`: + - `delete_after` - (Optional, Integer) The maximum number of days to keep each backup after creation. Default value is 30. + - `delete_over_count` - (Optional, String) The maximum number of recent backups to keep. If unspecified, there will be no maximum. + + ->**Note** Assign back to "null" to reset to no maximum. + +- `name` - (Optional, String) The user-defined name for this backup policy plan. Names must be unique within the backup policy this plan resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the BackupPolicyPlan. +- `backup_policy_id` - (String) The backup policy identifier. +- `created_at` - (String) The date and time that the backup policy plan was created. +- `href` - (String) The URL for this backup policy plan. +- `lifecycle_state` - (String) The lifecycle state of this backup policy plan. +- `resource_type` - (String) The resource type. +- `version` - Version of the BackupPolicyPlan. + +## Import + +You can import the `ibm_is_backup_policy_plan` resource by using `id`. +The `id` property can be formed from `backup_policy_id`, and `id` in the following format: + +``` +<0fe9e5d8-0a4d-4818-96ec-e99708644a58>/<0fg9e5d8-0a4d-4818-96ec-e99708634a58> +``` +- `backup_policy_id`: A string. The backup policy identifier. +- `id`: A string. The backup policy plan identifier. + +# Syntax +``` +$ terraform import ibm_is_backup_policy_plan.is_backup_policy_plan <0fe9e5d8-0a4d-4818-96ec-e99708644a58>/<0fg9e5d8-0a4d-4818-96ec-e99708634a58> + +``` diff --git a/website/docs/r/is_bare_metal_server.markdown b/website/docs/r/is_bare_metal_server.markdown new file mode 100644 index 000000000..ac7ca7af2 --- /dev/null +++ b/website/docs/r/is_bare_metal_server.markdown @@ -0,0 +1,207 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server" +description: |- + Manages IBM bare metal sever. +--- + +# ibm\_is_bare_metal_server + +Create, update, or delete a Bare Metal Server for VPC. For more information, about managing VPC Bare Metal Server, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +In the following example, you can create a Bare Metal Server: + +### Basic Example +```terraform + +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-3" + ipv4_cidr_block = "10.240.129.0/24" +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} + +resource "ibm_is_bare_metal_server" "example" { + profile = "mx2d-metal-32x192" + name = "example-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.example.id] + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + vpc = ibm_is_vpc.example.id +} + +``` +### Reserved ip example +```terraform +resource "ibm_is_bare_metal_server" "bms" { + profile = "mx2d-metal-32x192" + name = "example-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.example.id] + primary_network_interface { + subnet = ibm_is_subnet.example.id + primary_ip { + auto_delete = true + name = "example-reserved-ip" + address = "${replace(ibm_is_subnet.example.ipv4_cidr_block, "0/28", "14")}" + } + } + vpc = ibm_is_vpc.example.id +} + +``` + +## Timeouts + +ibm_is_bare-metal_server provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - (Default 30 minutes) Used for creating bare metal server. +- `update` - (Default 30 minutes) Used for updating bare metal server or while attaching it with volume attachments or interfaces. +- `delete` - (Default 30 minutes) Used for deleting bare metal server. + +## Argument Reference + +Review the argument references that you can specify for your resource. + +- `delete_type` - (Optional, String) Type of deletion on destroy. **soft** signals running operating system to quiesce and shutdown cleanly, **hard** immediately stop the server. By default its `hard`. +- `image` - (Required, String) ID of the image. +- `keys` - (Required, List) Comma separated IDs of ssh keys. +- `name` - (Optional, String) The bare metal server name. + + -> **NOTE:** + a bare metal server can take up to 30 mins to clean up on delete, replacement/re-creation using the same name may return error + +- `network_interfaces` - (Optional, List) The additional network interfaces to create for the bare metal server to this bare metal server. Use `ibm_is_bare_metal_server_network_interface` & `ibm_is_bare_metal_server_network_interface_allow_float` resource for network interfaces. + + ~> **NOTE:** + creating network interfaces both inline with `ibm_is_bare_metal_server` & as a separate `ibm_is_bare_metal_server_network_interface` resource, will show change alternatively on both resources, to avoid this use `ibm_is_bare_metal_server_network_interface` for creating network interfaces. + + Nested scheme for `network_interfaces`: + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether IP spoofing is allowed on this interface. If false, IP spoofing is prevented on this interface. If true, IP spoofing is allowed on this interface. [default : `false`] + - `allowed_vlans` - (Optional, Array) Comma separated VLANs, Indicates what VLAN IDs (for VLAN type only) can use this physical (`PCI` type) interface. A given VLAN can only be in the `allowed_vlans` array for one PCI type adapter per bare metal server. [ conflicts with `vlan`] + - `enable_infrastructure_nat` - (Optional, Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. [default : `true`] + - `name` - (Required, String) The name of the network interface. + - `primary_ip` - (Optional, List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (Optional, String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + + - `security_groups` - (Optional, Array) Comma separated IDs of security groups. + - `subnet` - (Required, String) ID of the subnet to associate with. + - `vlan` - (Optional, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface. [ conflicts with `allowed_vlans`] + +- `primary_network_interface` - (Required, List) A nested block describing the primary network interface of this bare metal server. We can have only one primary network interface. + + Nested scheme for `primary_network_interface`: + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether IP spoofing is allowed on this interface. If false, IP spoofing is prevented on this interface. If true, IP spoofing is allowed on this interface. [default : `false`] + - `allowed_vlans` - (Optional, Array) Comma separated VLANs, Indicates what VLAN IDs (for VLAN type only) can use this physical (`PCI` type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. + - `enable_infrastructure_nat` - (Optional, Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. [default : `true`] + - `name` - (Optional, String) The name of the network interface. + - `primary_ip` - (Optional, List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (Optional, String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. `reserved_ip` is mutually exclusive with rest of the `primary_ip` attributes. + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + + - `security_groups` - (Optional, Array) Comma separated IDs of security groups. + - `subnet` - (Required, String) ID of the subnet to associate with. + +- `profile` - (Required, Forces new resource, String) The name the profile to use for this bare metal server. +- `resource_group` - (Optional, Forces new resource, String) The resource group ID for this bare metal server. +- `user_data` - (Optional, String) User data to transfer to the server bare metal server. +- `vpc` - (Required, Forces new resource, String) The VPC ID of the bare metal server is to be a part of. It must match the VPC tied to the subnets of the server's network interfaces. +- `zone` - (Required, Forces new resource, String) Name of the zone in which this bare metal server will reside in. + + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the bare metal server's network interfaces. +- `boot_target` - (String) The unique identifier for this bare metal server disk. +- `crn` - (String) The CRN for this bare metal server +- `cpu` - (String) A nested block describing the CPU configuration of this bare metal server. + + Nested scheme for `cpu`: + - `architecture` - (String) The architecture of the bare metal server. + - `core_count` - (Integer) The total number of cores + - `socket_count` - (Integer) The total number of CPU sockets + - `threads_per_core` - (Integer) The total number of hardware threads per core +- `href` - (String) The URL for this bare metal server +- `id` - (String) The unique identifier for this bare metal server +- `memory` - (Integer) The amount of memory, truncated to whole gibibytes +- `network_interfaces` - (List) The additional network interfaces to create for the bare metal server to this bare metal server. Use `ibm_is_bare_metal_server_network_interface` resource for network interfaces. + + Nested scheme for `network_interfaces`: + - `allow_ip_spoofing` - (Boolean) Indicates whether IP spoofing is allowed on this interface. If false, IP spoofing is prevented on this interface. If true, IP spoofing is allowed on this interface. [default : `false`] + - `allowed_vlans` - (Array) Comma separated VLANs, Indicates what VLAN IDs (for VLAN type only) can use this physical (`PCI` type) interface. A given VLAN can only be in the `allowed_vlans` array for one PCI type adapter per bare metal server. [ conflicts with `vlan`] + - `enable_infrastructure_nat` - (Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. [default : `true`] + - `name` - (String) The name of the network interface. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `address` - (String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `reserved_ip`- (String) The unique identifier for this reserved IP. + - `name`- (String) The user-defined or system-provided name for this reserved IP + + - `security_groups` - (Array) Comma separated IDs of security groups. + - `subnet` - (String) ID of the subnet to associate with. + - `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface. [ conflicts with `allowed_vlans`] + +- `resource_type` - (String) The type of resource. +- `status` - (String) The status of the bare metal server :[ **failed**, **pending**, **restarting**, **running**, **starting**, **stopped**, **stopping** ] +- `status_reasons` - (List) Array of reasons for the current status (if any). + + Nested `status_reasons`: + - `code` - (String) The status reason code + - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason + + +## Import + +The `ibm_is_bare_metal_server` can be imported using Bare Metal Server ID + + +## Syntax +``` +$ terraform import ibm_is_bare_metal_server.example +``` + +**Example** + +``` +$ terraform import ibm_is_bare_metal_server.example d7bec597-4726-451f-8a63-e62e6f19c32c +``` diff --git a/website/docs/r/is_bare_metal_server_action.markdown b/website/docs/r/is_bare_metal_server_action.markdown new file mode 100644 index 000000000..16ee7dfc3 --- /dev/null +++ b/website/docs/r/is_bare_metal_server_action.markdown @@ -0,0 +1,58 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_action" +description: |- + Manages IBM bare metal sever action. +--- + +# ibm\_is_bare_metal_server_action + +Start/Stop/Restart a Bare Metal Server for VPC. For more information, about managing VPC Bare Metal Server, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + + +## Example Usage + +In the following example, you can update name of a Bare Metal Server disk: + +```terraform +resource "ibm_is_bare_metal_server_action" "bms_action" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + action = "stop" + stop_type = "hard" +} +``` + +## Argument Reference + +Review the argument references that you can specify for your resource. + + +- `action` - (Required, String) The type of action to perfrom on the Bare metal server.[**start**, **stop**, **restart**] +- `bare_metal_server` - (Required, String) Bare metal server identifier. +- `stop_type` - (Optional, String) The type of stop for the `stop` action. [**soft**, **hard**]. By default its `hard` + + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `status` - (String) The status of the bare metal server :[ failed, pending, restarting, running, starting, stopped, stopping ] +- `status_reasons` - (List) Array of reasons for the current status (if any). + + Nested `status_reasons`: + - `code` - (String) The status reason code + - `message` - (String) An explanation of the status reason + - `more_info` - (String) Link to documentation about this status reason diff --git a/website/docs/r/is_bare_metal_server_disk.markdown b/website/docs/r/is_bare_metal_server_disk.markdown new file mode 100644 index 000000000..9fed0006e --- /dev/null +++ b/website/docs/r/is_bare_metal_server_disk.markdown @@ -0,0 +1,45 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_disk" +description: |- + Manages IBM bare metal sever disk name. +--- + +# ibm\_is_bare_metal_server_disk + +Rename a Bare Metal Server for disk. For more information, about managing VPC Bare Metal Server, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +In the following example, you can update name of a Bare Metal Server disk: + +```terraform +resource "ibm_is_bare_metal_server_disk" "disk" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + disk = ibm_is_bare_metal_server.bms.disks.0.id + name = "name1" +} +``` + +## Argument Reference + +Review the argument references that you can specify for your resource. + + +- `bare_metal_server` - (Required, String) Bare metal server identifier. +- `disk` - (Required, String) The unique identifier for the disk to be renamed on the Bare metal server. +- `name` - (Optional, String) The name for the disk. + diff --git a/website/docs/r/is_bare_metal_server_network_interface.markdown b/website/docs/r/is_bare_metal_server_network_interface.markdown new file mode 100644 index 000000000..b30ba37db --- /dev/null +++ b/website/docs/r/is_bare_metal_server_network_interface.markdown @@ -0,0 +1,141 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface" +description: |- + Manages IBM bare metal sever network interface. +--- + +# ibm\_is_bare_metal_server_network_interface + +Create, update, or delete a Network Interface on an existing Bare Metal Server for VPC. For more information, about managing VPC Bare Metal Server, see [Network of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-network). User `is_bare_metal_server_network_interface_allow_float` resource to create a vlan type network interface with allow float. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +In the following example, you can create a Bare Metal Server and add a network interface to it: + +```terraform +resource "ibm_is_vpc" "vpc" { + name = "testvpc" +} + +resource "ibm_is_subnet" "subnet" { + name = "testsubnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-3" + ipv4_cidr_block = "10.240.129.0/24" +} + +resource "ibm_is_ssh_key" "ssh" { + name = "testssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} + +resource "ibm_is_bare_metal_server" "bms" { + profile = "mx2d-metal-32x192" + name = "my-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + vpc = ibm_is_vpc.vpc.id +} + +resource "ibm_is_bare_metal_server_network_interface" "bms_nic" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] +} + +``` + ~> **NOTE** + Creating/Deleting a PCI type network interface would stop and start the bare metal server. Use `hard_stop` to configure the stopping type, by default `hard` is enabled, make it `false` to `soft` stop the server + +## Timeouts + +ibm_is_bare-metal_server_network_interface provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +* `create` - (Default 10 minutes) Used for creating bare metal server network interface . +* `update` - (Default 10 minutes) Used for updating bare metal server network interface. +* `delete` - (Default 10 minutes) Used for deleting bare metal server network interface. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `allowed_vlans` - (Optional, Integer) Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. This property which controls the VLANs that will be permitted to use the pci interface. + + ~> **NOTE** + Creates a PCI type interface, a physical PCI device can only be created or deleted when the bare metal server is stopped. Use `hard_stop` as `false` to `soft` stop the server, by default its `hard` + +- `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. +- `bare_metal_server` - (Required, String) The id for this bare metal server. +- `enable_infrastructure_nat` - (Optional, Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. +- `hard_stop` - (Optional, Boolean) Default is `true`. Applicable for `pci` type only, controls if the server should be hard stopped. +- `name` - (Optional, String) The user-defined name for this network interface +- `primary_ip` - (Optional, List) + - `address` - (Optional, String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. `id` is mutually exclusive with rest of the `primary_ip` attributes. + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + +- `security_groups` - (Optional, List) Collection of security groups +- `subnet` - (Required, String) The associated subnet +- `vlan` - (Optional, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface + + ~> **NOTE** + Creates a vlan type network interface, a virtual device, used through a pci device that has the vlan in its array of allowed_vlans. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `allow_interface_to_float` - (Boolean) Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces. +- `floating_ips` - (List) The floating IPs associated with this network interface. + + Nested scheme for `floating_ips`: + - `address` - (String) The floating IP address. + - `id` - (String) The unique identifier of the floating IP. +- `href` - (String) The URL for this network interface +- `id` - (String) The unique identifier for this network interface. Its of the format / +- `interface_type` - (String) The network interface type, supported values are [ **pci**, **vlan** ] +- `mac_address` - (String) The MAC address of the interface. If absent, the value is not known. +- `network_interface` - (String) The network interface id. +- `port_speed` - (Integer) The network interface port speed in Mbps +- `resource_type` - (String)The resource type [ **subnet_reserved_ip** ] +- `status` - (String) The status of the network interface. Supported values are [ **available**, **deleting**, **failed**, **pending** ] +- `type` - (String) The type of this bare metal server network interface. Supported values are [ **primary**, **secondary** ] + + + +## Import + +ibm_is_bare_metal_server can be imported using bare metal server ID and network interface id + +## Syntax + +``` +$ terraform import ibm_is_bare_metal_server_network_interface.example / +``` + +## Example + +``` +$ terraform import ibm_is_bare_metal_server_network_interface.example d7bec597-4726-451f-8a63-e62e6f19c32c/e7bec597-4726-451f-8a63-e62e6f19c32d +``` diff --git a/website/docs/r/is_bare_metal_server_network_interface_allow_float.markdown b/website/docs/r/is_bare_metal_server_network_interface_allow_float.markdown new file mode 100644 index 000000000..e4d3ddf05 --- /dev/null +++ b/website/docs/r/is_bare_metal_server_network_interface_allow_float.markdown @@ -0,0 +1,138 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface_allow_float" +description: |- + Manages IBM bare metal sever network interface allow float. +--- + +# ibm\_is_bare_metal_server_network_interface_allow_float + +Create, update, or delete a VLAN Network Interface on an existing Bare Metal Server for VPC with allow_interface_to_float set to true. For more information, about managing VPC Bare Metal Server, see [Network of Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-bare-metal-servers-network). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +In the following example, you can create a Bare Metal Server and add a network interface to it: + +```terraform +resource "ibm_is_vpc" "vpc" { + name = "testvpc" +} + +resource "ibm_is_subnet" "subnet" { + name = "testsubnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-3" + ipv4_cidr_block = "10.240.129.0/24" +} + +resource "ibm_is_ssh_key" "ssh" { + name = "testssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} + +resource "ibm_is_bare_metal_server" "bms" { + profile = "mx2d-metal-32x192" + name = "my-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + vpc = ibm_is_vpc.vpc.id +} + +resource "ibm_is_bare_metal_server_network_interface" "bms_nic" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] +} +resource "ibm_is_bare_metal_server_network_interface_allow_float" "bms_nic" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet.id + name = "eth2float" + vlan = 101 +} + +``` + +## Timeouts + +ibm_is_bare-metal_server_network_interface provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +* `create` - (Default 10 minutes) Used for creating bare metal server network interface . +* `update` - (Default 10 minutes) Used for updating bare metal server network interface. +* `delete` - (Default 10 minutes) Used for deleting bare metal server network interface. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. +- `bare_metal_server` - (Required, String) The id for this bare metal server. +- `enable_infrastructure_nat` - (Optional, Boolean) If true, the VPC infrastructure performs any needed NAT operations. If false, the packet is passed unmodified to/from the network interface, allowing the workload to perform any needed NAT operations. +- `name` - (Optional, String) The user-defined name for this network interface +- `primary_ip` - (Optional, List) + - `address` - (Optional, String) title: IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. `reserved_ip` is mutually exclusive with rest of the `primary_ip` attributes. + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + +- `security_groups` - (Optional, List) Collection of security groups +- `subnet` - (Required, String) The associated subnet id +- `vlan` - (Required, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `allow_interface_to_float` - (Boolean) Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces. +- `floating_bare_metal_server` - (String) Bare metal server id of the server to which the network interface is floating to. (Same as `bare_metal_server` if its not floating) +- `floating_ips` - (List) The floating IPs associated with this network interface. + + Nested scheme for `floating_ips`: + - `address` - (String) The floating IP address. + - `id` - (String) The unique identifier of the floating IP. +- `href` - (String) The URL for this network interface +- `id` - (String) The unique identifier for this network interface. Its of the format / +- `interface_type` - (String) The network interface type, supported values are [ **pci**, **vlan** ] +- `mac_address` - (String) The MAC address of the interface. If absent, the value is not known. +- `network_interface` - (String) The network interface id. +- `port_speed` - (Integer) The network interface port speed in Mbps +- `resource_type` - (String)The resource type [ **subnet_reserved_ip** ] +- `status` - (String) The status of the network interface. Supported values are [ **available**, **deleting**, **failed**, **pending** ] +- `type` - (String) The type of this bare metal server network interface. Supported values are [ **primary**, **secondary** ] + + + +## Import + +ibm_is_bare_metal_server can be imported using bare metal server ID and network interface id + +## Syntax + +``` +$ terraform import ibm_is_bare_metal_server_network_interface.example / +``` + +## Example + +``` +$ terraform import ibm_is_bare_metal_server.example d7bec597-4726-451f-8a63-e62e6f19c32c/d7bec597-4726-451f-8a63-e62e6f19c32c +``` diff --git a/website/docs/r/is_bare_metal_server_network_interface_floating_ip.markdown b/website/docs/r/is_bare_metal_server_network_interface_floating_ip.markdown new file mode 100644 index 000000000..555d34015 --- /dev/null +++ b/website/docs/r/is_bare_metal_server_network_interface_floating_ip.markdown @@ -0,0 +1,143 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : bare_metal_server_network_interface_floating_ip" +description: |- + Manages IBM floating IP on bare metal server network interface. +--- + +# ibm\_is_bare_metal_server_network_interface_floating_ip +Adding a floating IP address that you can associate with a Bare Metal Server. You can use the floating IP address to access your server from the public network, independent of whether the subnet is attached to a public gateway. For more information, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage +The following example shows how to create a Bare Metal Server for VPC and associate a floating IP address to a network interface on the server. + +```terraform + +resource "ibm_is_vpc" "vpc" { + name = "testvpc" +} + +resource "ibm_is_subnet" "subnet" { + name = "testsubnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-3" + ipv4_cidr_block = "10.240.129.0/24" +} + +resource "ibm_is_ssh_key" "ssh" { + name = "testssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} + +resource "ibm_is_floating_ip" "fip" { + name = "testfip1" + zone = "us-south-3" +} + +resource "ibm_is_bare_metal_server" "bms" { + profile = "bx2-metal-192x768" + name = "testserver" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.ssh.id] + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + vpc = ibm_is_vpc.vpc.id +} +resource "ibm_is_bare_metal_server_network_interface" "bms_nic" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet.id + name = "eth2" + allow_ip_spoofing = true + allowed_vlans = [101, 102] +} + +resource "ibm_is_bare_metal_server_network_interface_floating_ip" "bms_nic_fip" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + network_interface = ibm_is_bare_metal_server_network_interface.bms_nic.id + floating_ip = ibm_is_floating_ip.fip.id +} + +``` + +## Example usage +The following example shows how to create a allow float network interface and associate a floating IP address to an allow float network interface on the server. + +``` +resource "ibm_is_floating_ip" "fip2" { + name = "testfip2" + zone = "us-south-3" +} + +resource "ibm_is_bare_metal_server_network_interface_allow_float" "allow_float" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + subnet = ibm_is_subnet.subnet.id + name = "eth2" + allow_ip_spoofing = false + vlan = 101 +} + +resource "ibm_is_bare_metal_server_network_interface_floating_ip" "bms_nic_fip" { + bare_metal_server = ibm_is_bare_metal_server_network_interface_allow_float.allow_float.floating_bare_metal_server + network_interface = ibm_is_bare_metal_server_network_interface_allow_float.allow_float.network_interface + floating_ip = ibm_is_floating_ip.fip2.id +} + +``` + + +## Timeouts +The `ibm_is_bare_metal_server_network_interface_floating_ip` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create**: The creation of the floating IP address is considered `failed` if no response is received for 10 minutes. +- **delete**: The deletion of the floating IP address is considered `failed` if no response is received for 10 minutes. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `bare_metal_server` - (Required, String) Bare metal server identifier. +- `floating_ip` - (Required, String) The unique identifier for a floating IP to associate with the network interface associated with the bare metal server +- `network_interface` - (Required, String) The unique identifier for a network interface associated with the Bare metal server. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `address` - (String) The floating IP address. +- `crn` - (String) The CRN for this floating IP. +- `id` - (String) The unique identifier of the floating IP. +- `status` - (String) Provisioning status of the floating IP address. +- `tags` - (String) The tags associated with VPC. +- `target` - (String) The ID of the network interface used to allocate the floating IP address. +- `zone` - (String) The zone name where to create the floating IP address. + + +## Import +The `ibm_is_bare_metal_server_network_interface_floating_ip` resource can be imported by using bare metal server ID, network interface ID, floating ip ID. + +## Syntax +``` +terraform import ibm_is_bare_metal_server_network_interface_floating_ip.example // +``` + +## Example + +``` +$ terraform import ibm_is_bare_metal_server_network_interface_floating_ip.example d7bec597-4726-451f-8a63-e62e6f19c32c/d7bec597-4726-451f-8a63-e62e6f19c32c/d7bec597-4726-451f-8a63-e62e6f19c32c +``` diff --git a/website/docs/r/is_dedicated_host.html.markdown b/website/docs/r/is_dedicated_host.html.markdown index c60a334ff..ce4261a00 100644 --- a/website/docs/r/is_dedicated_host.html.markdown +++ b/website/docs/r/is_dedicated_host.html.markdown @@ -9,21 +9,32 @@ description: |- # ibm_is_dedicated_host Create, update, delete and suspend the dedicated host resource. For more information, about dedicated host in your IBM Cloud VPC, see [Dedicated hosts](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-dedicated-hosts-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_dedicated_host_group" "dh_group01" { +resource "ibm_is_dedicated_host_group" "example" { family = "memory" - class = "beta" - zone = "us-south-1" + class = "beta" + zone = "us-south-1" } -data "ibm_is_dedicated_host_group" "dgroup" { - name = ibm_is_dedicated_host_group.dh_group01.name +data "ibm_is_dedicated_host_group" "example" { + name = ibm_is_dedicated_host_group.example.name } -resource "ibm_is_dedicated_host" "is_dedicated_host" { - profile = "dh2-56x464" - host_group = "1e09281b-f177-46fb-baf1-bc152b2e391a" - name = "testdh02" +resource "ibm_is_dedicated_host" "example" { + profile = "dh2-56x464" + host_group = ibm_is_dedicated_host_group.example.id + name = "example-dh-host" } ``` diff --git a/website/docs/r/is_dedicated_host_disk_management.html.markdown b/website/docs/r/is_dedicated_host_disk_management.html.markdown index bfe6d830c..3b385d8d5 100644 --- a/website/docs/r/is_dedicated_host_disk_management.html.markdown +++ b/website/docs/r/is_dedicated_host_disk_management.html.markdown @@ -10,38 +10,49 @@ description: |- Create, update, delete and suspend the dedicated host disk management resource. For more information, about dedicated host disk management, see [migrating a dedicated host instance to another host](https://cloud.ibm.com/docs/virtual-servers?topic=virtual-servers-migrating-dedicated-host). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_dedicated_host_group" "dh_group01" { +resource "ibm_is_dedicated_host_group" "example" { family = "memory" - class = "beta" - zone = "us-south-1" + class = "beta" + zone = "us-south-1" } -data "ibm_is_dedicated_host_group" "dgroup" { - name = ibm_is_dedicated_host_group.dh_group01.name +data "ibm_is_dedicated_host_group" "example" { + name = ibm_is_dedicated_host_group.example.name } -resource "ibm_is_dedicated_host" "is_dedicated_host" { - profile = "dh2-56x464" - host_group = "1e09281b-f177-46fb-baf1-bc152b2e391a" - name = "testdh02" +resource "ibm_is_dedicated_host" "example" { + profile = "dh2-56x464" + host_group = ibm_is_dedicated_host_group.example.id + name = "example-dedicated-host" } -data "ibm_is_dedicated_host" "dhost" { - host_group = "1e09281b-f177-46fb-baf1-bc152b2e391a" - name = "my-dedicated-host" +data "ibm_is_dedicated_host" "example" { + host_group = ibm_is_dedicated_host_group.example.id + name = "example-dedicated-host" } -data "ibm_is_dedicated_host_disks" "test1" { - dedicated_host = data.ibm_is_dedicated_host.dhost.id +data "ibm_is_dedicated_host_disks" "example" { + dedicated_host = data.ibm_is_dedicated_host.example.id } -data "ibm_is_dedicated_host_disk" "test1" { - dedicated_host = data.ibm_is_dedicated_host.dhost.id - disk = ibm_is_dedicated_host_disk_management.disks.disks.0.id +data "ibm_is_dedicated_host_disk" "example" { + dedicated_host = data.ibm_is_dedicated_host.example.id + disk = ibm_is_dedicated_host_disk_management.example.disks.0.id } -resource "ibm_is_dedicated_host_disk_management" "disks"{ - dedicated_host = data.ibm_is_dedicated_host.dhost.id +resource "ibm_is_dedicated_host_disk_management" "example" { + dedicated_host = data.ibm_is_dedicated_host.example.id disks { - name = "mydisk01" - id = data.ibm_is_dedicated_host.dhost.disks.0.id + name = "example-disks" + id = data.ibm_is_dedicated_host.example.disks.0.id } } ``` @@ -50,7 +61,7 @@ resource "ibm_is_dedicated_host_disk_management" "disks"{ Review the argument reference that you can specify for your resource. - `dedicated_host` - (Required, Force New Resource, String) The unique-identifier of the dedicated host. -- `disks` - (Required, String) Disks that needs to be updated. Nested `disks` blocks have the following structure: +- `disks` - (Required, List) Disks that needs to be updated. Nested `disks` blocks have the following structure: Nested scheme for `disks`: - `id` - (Required, String) The unique-identifier of the dedicated host disk. diff --git a/website/docs/r/is_dedicated_host_group.html.markdown b/website/docs/r/is_dedicated_host_group.html.markdown index 1671d52c3..e7a89be15 100644 --- a/website/docs/r/is_dedicated_host_group.html.markdown +++ b/website/docs/r/is_dedicated_host_group.html.markdown @@ -9,14 +9,25 @@ description: |- # ibm_is_dedicated_host_group Create, update, delete and suspend the dedicated host resource. For more information, about dedicated host groups in your IBM Cloud VPC, see [Dedicated hosts](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-dedicated-hosts-instances). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_dedicated_host_group" "is_dedicated_host_group" { - class = "mx2" +resource "ibm_is_dedicated_host_group" "example" { + class = "mx2" family = "balanced" - zone = "us-south-1" - name = "dh-group-name" + zone = "us-south-1" + name = "example-dh-group" } ``` diff --git a/website/docs/r/is_floating_ip.html.markdown b/website/docs/r/is_floating_ip.html.markdown index 0c98c85c8..4628fed2b 100644 --- a/website/docs/r/is_floating_ip.html.markdown +++ b/website/docs/r/is_floating_ip.html.markdown @@ -10,32 +10,42 @@ description: |- # ibm_is_floating_ip Create a floating IP address that you can associate with a Virtual Servers for VPC instance. You can use the floating IP address to access your instance from the public network, independent of whether the subnet is attached to a public gateway. For more information, see [about floating IP](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-a-vpc-using-the-rest-apis#create-floating-ip-api-tutorial). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example shows how to create a Virtual Servers for VPC instance and associate a floating IP address to the primary network interface of the virtual server instance. ```terraform -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" - profile = "b-2x8" +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id + profile = "bc1-2x8" primary_network_interface { - port_speed = "1000" - subnet = "70be8eae-134c-436e-a86e-04849f84cb34" + subnet = ibm_is_subnet.example.id } - vpc = "01eda778-b822-43a2-816d-d30713df5e13" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = ["eac87f33-0c00-4da7-aa66-dc2d972148bd"] + keys = [ibm_is_ssh_key.example.id] } -resource "ibm_is_floating_ip" "testacc_floatingip" { - name = "testfip1" - target = ibm_is_instance.testacc_instance.primary_network_interface[0].id +resource "ibm_is_floating_ip" "example" { + name = "example-floating-ip" + target = ibm_is_instance.example.primary_network_interface[0].id } - ``` + -> **Note:** To access the instance using floating ip, make sure the target security group has the respective inbound rule ## Timeouts The `ibm_is_instance` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -49,10 +59,15 @@ Review the argument references that you can specify for your resource. - `name` - (Required, String) Enter a name for the floating IP address. - `resource_group` - (Optional, String) The resource group ID where you want to create the floating IP. -- `target` - (Optional, String) Enter the ID of the network interface that you want to use to allocate the IP address. If you specify this option, do not specify `zone` at the same time. **Note** conflicts with `zone`. A change in `target` which is in a different `zone` will show a change to replace current floating ip with a new one. +- `target` - (Optional, String) Enter the ID of the network interface that you want to use to allocate the IP address. If you specify this option, do not specify `zone` at the same time. + + ~> **Note:** `target` conflicts with `zone`. A change in `target` which is in a different `zone` will show a change to replace current floating ip with a new one. - `tags` (Optional, Array of Strings) Enter any tags that you want to associate with your VPC. Tags might help you find your VPC more easily after it is created. Separate multiple tags with a comma (`,`). -- `zone` - (Optional, Force New Resource, String) Enter the name of the zone where you want to create the floating IP address. To list available zones, run `ibmcloud is zones`. If you specify this option, do not specify `target` at the same time. **Note** Conflicts with `target` and one of `target`, or `zone` is mandatory. +- `zone` - (Optional, Force New Resource, String) Enter the name of the zone where you want to create the floating IP address. To list available zones, run `ibmcloud is zones`. If you specify this option, do not specify `target` at the same time. + + ~> **Note:** Conflicts with `target` and one of `target`, or `zone` is mandatory. + ~> **Note** `target` cannot be used in conjunction with the `floating_ip` argument of `ibm_is_instance_network_interface` resource and might cause cyclic dependency/unexpected issues if used used both ways. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -61,7 +76,24 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN for this floating IP. - `id` - (String) The unique identifier of the floating IP address. - `status` - (String) The provisioning status of the floating IP address. - +- `target_list` - (List) The target of this floating IP. + Nested scheme for **target_list**: + - `crn` - (String) The CRN if target is a public gateway. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this target. + - `id` - (String) The unique identifier for this target. + - `name` - (String) The user-defined name for this target. + - `primary_ip` - (List) The reserved ip reference. + + Nested scheme for **primary_ip**: + - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href`- (String) The URL for this reserved IP + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `resource_type`- (String) The resource type. ## Import The `ibm_is_floating_ip` resource can be imported by using floating IP ID. diff --git a/website/docs/r/is_flow_log.html.markdown b/website/docs/r/is_flow_log.html.markdown index d3a07e715..a3cc9f0a5 100644 --- a/website/docs/r/is_flow_log.html.markdown +++ b/website/docs/r/is_flow_log.html.markdown @@ -10,52 +10,62 @@ description: |- # ibm_is_flow_log Create, update, delete and suspend the flow log resource. For more information, about VPC flow log, see [creating a flow log collector](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-flow-log-collector). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" - profile = "b-2x8" +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id + profile = "bc1-2x8" primary_network_interface { - port_speed = "1000" - subnet = "70be8eae-134c-436e-a86e-04849f84cb34" + subnet = ibm_is_subnet.example.id } - vpc = "01eda778-b822-43a2-816d-d30713df5e13" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = ["eac87f33-0c00-4da7-aa66-dc2d972148bd"] + keys = [ibm_is_ssh_key.example.id] } -data "ibm_resource_group" "instance_group" { - name = var.resource_group +resource "ibm_resource_group" "example" { + name = "example-resource-group" } -resource "ibm_resource_instance" "instance1" { - name = "cos-instance" - resource_group_id = data.ibm_resource_group.instance_group.id +resource "ibm_resource_instance" "example" { + name = "example-cos-instance" + resource_group_id = ibm_resource_group.example.id service = "cloud-object-storage" plan = "standard" location = "global" } -resource "ibm_cos_bucket" "bucket1" { - bucket_name = "us-south-bucket-vpc1" - resource_instance_id = ibm_resource_instance.instance1.id - region_location = var.region - storage_class = "standard" +resource "ibm_cos_bucket" "example" { + bucket_name = "us-south-bucket-vpc1" + resource_instance_id = ibm_resource_instance.example.id + region_location = var.region + storage_class = "standard" } -resource ibm_is_flow_log test_flowlog { - depends_on = [ibm_cos_bucket.bucket1] - name = "test-instance-flow-log" - target = ibm_is_instance.testacc_instance.id - active = true - storage_bucket = ibm_cos_bucket.bucket1.bucket_name +resource "ibm_is_flow_log" "example" { + depends_on = [ibm_cos_bucket.example] + name = "example-instance-flow-log" + target = ibm_is_instance.example.id + active = true + storage_bucket = ibm_cos_bucket.example.bucket_name } ``` diff --git a/website/docs/r/is_ike_policy.html.markdown b/website/docs/r/is_ike_policy.html.markdown index 008c3b6a5..14a760e5f 100644 --- a/website/docs/r/is_ike_policy.html.markdown +++ b/website/docs/r/is_ike_policy.html.markdown @@ -10,13 +10,24 @@ description: |- # ibm_is_ike_policy Create, update, or cancel an Internet Key Exchange (IKE) policy. IKE is an IPSec (Internet Protocol Security) standard protocol that is used to ensure secure communication over the VPC VPN service. For more information, see [Using VPC with your VPC](https://cloud.ibm.com/docs/vpc-on-classic-network?topic=vpc-on-classic-networkusing-vpn-with-your-vpc). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can create a IKE policy: ```terraform resource "ibm_is_ike_policy" "example" { - name = "test" + name = "example-ike-policy" authentication_algorithm = "md5" encryption_algorithm = "triple_des" dh_group = 2 @@ -29,9 +40,21 @@ resource "ibm_is_ike_policy" "example" { ## Argument reference Review the argument references that you can specify for your resource. -- `authentication_algorithm` - (Required, String) Enter the algorithm that you want to use to authenticate `IPSec` peers. Available options are `md5`, `sha1`, or `sha256`. -- `dh_group` - (Required, Integer) Enter the Diffie-Hellman group that you want to use for the encryption key. Available enumeration type are `2`, `5`, `14`, or `19`. -- `encryption_algorithm` - (Required, String) Enter the algorithm that you want to use to encrypt data. Available options are: `triple_des`, `aes128`, or `aes256`. +- `authentication_algorithm` - (Required, String) Enter the algorithm that you want to use to authenticate `IKE` peers. Available options are `md5`, `sha1`, `sha256`, `sha512`, `sha384`. + + ~> **Note** + The `md5` and `sha1` algorithms have been deprecated and support will be removed from November 2022 + +- `dh_group` - (Required, Integer) Enter the Diffie-Hellman group that you want to use for the encryption key. Available enumeration type are `2`, `5`, `14`, `19`, `15`, `16` ,`17` ,`18` ,`20` ,`21` ,`22` ,`23` ,`24` ,`31` + + ~> **Note** + The Diffie-Hellman Groups 2 and 5 have been deprecated and support will be removed from November 2022 + +- `encryption_algorithm` - (Required, String) Enter the algorithm that you want to use to encrypt data. Available options are: `triple_des`, `aes128`, `aes192`, `aes256`. + + ~> **Note** + The `triple_des` algorithm has been deprecated and support will be removed from November 2022 + - `ike_version` - (Optional, Integer) Enter the IKE protocol version that you want to use. Available options are `1`, or `2`. - `key_lifetime` - (Optional, Integer)The key lifetime in seconds. `Maximum: 86400`, `Minimum: 1800`. Default is `28800`. - `name` - (Required, String) Enter a name for your IKE policy. diff --git a/website/docs/r/is_image.html.markdown b/website/docs/r/is_image.html.markdown index 918f2691e..1702c7f6c 100644 --- a/website/docs/r/is_image.html.markdown +++ b/website/docs/r/is_image.html.markdown @@ -11,6 +11,16 @@ description: |- Provide an image resource. This allows images to be created, retrieved, and deleted. For more information, about VPC custom images, see [IBM Cloud Docs: Virtual Private Cloud - IBM Cloud Importing and managing custom images](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-images). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Timeouts @@ -22,33 +32,36 @@ The `ibm_is_image` provides the following [Timeouts](https://www.terraform.io/do -## Example usage +## Example usage (using href and operating_system) ```terraform -resource "ibm_is_image" "test_is_image1" { - name = "test-image" - href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" - operating_system = "ubuntu-16-04-amd64" - encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" - encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" - +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" } ``` + ~> **NOTE** + `operating_system` is required with `href`. + +## Example usage (using volume) ```terraform -resource "ibm_is_image" "test_is_image2" { - name = "test-image2" +resource "ibm_is_image" "example" { + name = "example-image" - //optional field, either of (href, operating_system) or source_volume is required - - source_volume = "xxxx-xxxx-xxxxxxx" - encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" - encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + //optional field, either of (href, operating_system) or source_volume is required - //increase timeouts as per volume size + source_volume = "xxxx-xxxx-xxxxxxx" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + + //increase timeouts as per volume size timeouts { create = "45m" } - + } ``` @@ -57,21 +70,27 @@ Review the argument references that you can specify for your resource. - `encrypted_data_key` - (Optional, Forces new resource, String) A base64-encoded, encrypted representation of the key that was used to encrypt the data for this image. - `encryption_key` - (Optional, Forces new resource, String) The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource. -- `href` - (Required, String) The path of an image to be uploaded. - - either `href` or `source_volume` is required +- `href` - (Optional, String) The path of an image to be uploaded. The Cloud Object Store (COS) location of the image file. + + ~> **NOTE** + either `href` or `source_volume` is required - `name` - (Required, String) The descriptive name used to identify an image. - `operating_system` - (Required, String) Description of underlying OS of an image. - - `operating_system` is required with `href` + + ~> **NOTE** + `operating_system` is required with `href` - `resource_group` - (Optional, Forces new resource, String) The resource group ID for this image. -- `source_volume` - (Optional, string) The volume id of the volume from which to create the image. - - either `source_volume` or `href` is required. - - **Note** The specified volume must: - - Originate from an image, which will be used to populate this image's operating system information.(boot type volumes) - - Not be active or busy. - - During image creation, the specified volume may briefly become busy. - - Creating image from volume requires instance to which volume is attached to be in stopped status, running instance will be stopped on using this option. - - increase the default timeout as per the volume size. +- `source_volume` - (Optional, string) The volume id of the volume from which to create the image. + + ~> **NOTE** + either `source_volume` or `href` is required. + + The specified volume must: + - Originate from an image, which will be used to populate this image's operating system information.(boot type volumes) + - Not be active or busy. + - During image creation, the specified volume may briefly become busy. + - Creating image from volume requires instance to which volume is attached to be in stopped status, running instance will be stopped on using this option. + - increase the default timeout as per the volume size. - `tags` (Optional, Array of Strings) A list of tags that you want to your image. Tags can help you find the image more easily later. ## Attribute reference diff --git a/website/docs/r/is_instance.html.markdown b/website/docs/r/is_instance.html.markdown index 55dfa836f..760e38dc3 100644 --- a/website/docs/r/is_instance.html.markdown +++ b/website/docs/r/is_instance.html.markdown @@ -10,52 +10,64 @@ description: |- # ibm_is_instance Create, update, or delete a Virtual Servers for VPC instance. For more information, about managing VPC instance, see [about virtual server instances for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-advanced-virtual-servers). +**Note** +- IBM Cloud terraform provider currently provides both a standalone `ibm_is_instance_network_interface` resource and a `network_interfaces` block defined in-line in the `ibm_is_instance` resource. At this time you cannot use the `network_interfaces` block inline with `ibm_is_instance` in conjunction with the standalone resource `ibm_is_instance_network_interface`. Doing so will create a conflict of network interfaces and will overwrite it. +- VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + + **provider.tf** + + ```terraform + provider "ibm" { + region = "eu-gb" + } + ``` ## Example usage ### Sample for creating an instance in a VPC. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id profile = "bc1-2x8" + metadata_service_enabled = false boot_volume { encryption = "crn:v1:bluemix:public:kms:us-south:a/dffc98a0f1f0f95f6613b3b752286b87:e4a29d1a-2ef0-42a6-8fd2-350deb1c647e:key:5437653b-c4b1-447f-9646-b2a2a4cd6179" } primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - primary_ipv4_address = "10.240.0.6" + subnet = ibm_is_subnet.example.id + primary_ipv4_address = "10.240.0.6" // will be deprecated. Use primary_ip.[0].address allow_ip_spoofing = true } network_interfaces { name = "eth1" - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id allow_ip_spoofing = false } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] //User can configure timeouts timeouts { @@ -64,6 +76,54 @@ resource "ibm_is_instance" "testacc_instance" { delete = "15m" } } +// primary_ipv4_address deprecation +output "primary_ipv4_address" { + # value = ibm_is_instance.example.primary_network_interface.0.primary_ipv4_address // will be deprecated in future + value = ibm_is_instance.example.primary_network_interface.0.primary_ip.0.address // use this instead +} + +``` +### Sample for creating an instance with reserved ip as primary_ip reference. + +The following example shows how you can create a virtual server instance using reserved ip as the primary ip reference of the network interface + +// Example to provision instance using reserved ip + +```terraform +resource "ibm_is_subnet_reserved_ip" "example" { + subnet = ibm_is_subnet.example.id + name = "example-reserved-ip1" + address = "${replace(ibm_is_subnet.example.ipv4_cidr_block, "0/24", "13")}" +} + +resource "ibm_is_instance" "example1" { + name = "example-instance-reserved-ip" + image = ibm_is_image.example.id + profile = "bc1-2x8" + metadata_service_enabled = false + + primary_network_interface { + name = "eth0" + subnet = ibm_is_subnet.example.id + primary_ip { + reserved_ip = ibm_is_subnet_reserved_ip.example.reserved_ip + } + } + network_interfaces { + name = "eth1" + subnet = ibm_is_subnet.example.id + allow_ip_spoofing = false + primary_ip { + name = "example-reserved-ip1" + auto_delete = true + address = "${replace(ibm_is_subnet.example.ipv4_cidr_block, "0/24", "14")}" + } + } + + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] +} ``` @@ -73,70 +133,70 @@ The following example shows how you can create a virtual server instance with cu ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_security_group" "testacc_security_group" { - name = "test" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_security_group" "example" { + name = "example-security-group" + vpc = ibm_is_vpc.example.id } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_all" { - group = ibm_is_security_group.testacc_security_group.id - direction = "inbound" - remote = "127.0.0.1" - depends_on = [ibm_is_security_group.testacc_security_group] - } - - resource "ibm_is_security_group_rule" "testacc_security_group_rule_icmp" { - group = ibm_is_security_group.testacc_security_group.id - direction = "inbound" - remote = "127.0.0.1" - icmp { - code = 20 - type = 30 - } - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_all] +resource "ibm_is_security_group_rule" "example1" { + group = ibm_is_security_group.example.id + direction = "inbound" + remote = "127.0.0.1" + depends_on = [ibm_is_security_group.example] +} - } +resource "ibm_is_security_group_rule" "example2" { + group = ibm_is_security_group.example.id + direction = "inbound" + remote = "127.0.0.1" + icmp { + code = 20 + type = 30 + } + depends_on = [ibm_is_security_group_rule.example1] - resource "ibm_is_security_group_rule" "testacc_security_group_rule_udp" { - group = ibm_is_security_group.testacc_security_group.id - direction = "inbound" - remote = "127.0.0.1" - udp { - port_min = 805 - port_max = 807 - } - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_icmp] - } - - resource "ibm_is_security_group_rule" "testacc_security_group_rule_tcp" { - group = ibm_is_security_group.testacc_security_group.id - direction = "outbound" - remote = "127.0.0.1" - tcp { - port_min = 8080 - port_max = 8080 - } - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_udp] - } +} -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" +resource "ibm_is_security_group_rule" "example3" { + group = ibm_is_security_group.example.id + direction = "inbound" + remote = "127.0.0.1" + udp { + port_min = 805 + port_max = 807 + } + depends_on = [ibm_is_security_group_rule.example2] +} + +resource "ibm_is_security_group_rule" "example3" { + group = ibm_is_security_group.example.id + direction = "outbound" + remote = "127.0.0.1" + tcp { + port_min = 8080 + port_max = 8080 + } + depends_on = [ibm_is_security_group_rule.example2] +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id profile = "bc1-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - security_groups = [ibm_is_security_group.testacc_security_group.id] + subnet = ibm_is_subnet.example.id + security_groups = [ibm_is_security_group.example.id] } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_tcp] + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + depends_on = [ibm_is_security_group_rule.example3] //User can configure timeouts timeouts { @@ -146,40 +206,40 @@ resource "ibm_is_instance" "testacc_instance" { } } -data "ibm_resource_group" "default" { - name = "Default" ///give your resource grp +resource "ibm_resource_group" "example" { + name = "example-resource-group" } -resource "ibm_is_dedicated_host_group" "dh_group01" { - family = "compute" - class = "cx2" - zone = "us-south-1" - name = "my-dh-group-01" - resource_group = data.ibm_resource_group.default.id +resource "ibm_is_dedicated_host_group" "example" { + family = "compute" + class = "cx2" + zone = "us-south-1" + name = "example-dh-group-01" + resource_group = ibm_resource_group.example.id } -resource "ibm_is_dedicated_host" "is_dedicated_host" { - profile = "bx2d-host-152x608" - name = "my-dedicated-host-01" - host_group = ibm_is_dedicated_host_group.dh_group01.id - resource_group = data.ibm_resource_group.default.id +resource "ibm_is_dedicated_host" "example" { + profile = "bx2d-host-152x608" + name = "example-dedicated-host-01" + host_group = ibm_is_dedicated_host_group.example.id + resource_group = ibm_resource_group.example.id } -// Example to provision instance in a dedicated host -resource "ibm_is_instance" "testacc_instance1" { - name = "testinstance1" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" +// Example to provision an instance in a dedicated host +resource "ibm_is_instance" "example1" { + name = "example-instance-1" + image = ibm_is_image.example.id profile = "cx2-2x4" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - security_groups = [ibm_is_security_group.testacc_security_group.id] + subnet = ibm_is_subnet.example.id + security_groups = [ibm_is_security_group.example.id] } - dedicated_host = ibm_is_dedicated_host.is_dedicated_host.id - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_tcp] + dedicated_host = ibm_is_dedicated_host.example.id + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + depends_on = [ibm_is_security_group_rule.example3] //User can configure timeouts timeouts { @@ -189,21 +249,21 @@ resource "ibm_is_instance" "testacc_instance1" { } } -// Example to provision instance in a dedicated host that belongs to the provided dedicated host group -resource "ibm_is_instance" "testacc_instance2" { - name = "testinstance2" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" +// Example to provision an instance in a dedicated host that belongs to the provided dedicated host group +resource "ibm_is_instance" "example2" { + name = "example-instance-2" + image = ibm_is_image.example.id profile = "cx2-2x4" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - security_groups = [ibm_is_security_group.testacc_security_group.id] + subnet = ibm_is_subnet.example.id + security_groups = [ibm_is_security_group.example.id] } - dedicated_host_group = ibm_is_dedicated_host_group.dh_group01.id - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - depends_on = [ibm_is_security_group_rule.testacc_security_group_rule_tcp] + dedicated_host_group = ibm_is_dedicated_host_group.example.id + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + depends_on = [ibm_is_security_group_rule.example3] //User can configure timeouts timeouts { @@ -213,32 +273,57 @@ resource "ibm_is_instance" "testacc_instance2" { } } -// Example to provision instance from a snapshot, restoring boot volume from an existing snapshot +// Example to provision an instance from a snapshot, restoring boot volume from an existing snapshot -resource "ibm_is_snapshot" "testacc_snapshot" { - name = "testsnapshot" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id +resource "ibm_is_snapshot" "example" { + name = "example-snapshot" + source_volume = ibm_is_instance.example.volume_attachments[0].volume_id } -resource "ibm_is_instance" "testacc_instance_restore" { - name = "vsirestore" +resource "ibm_is_instance" "example" { + name = "example-vsi-restore" profile = "cx2-2x4" boot_volume { name = "boot-restore" - snapshot = ibm_is_snapshot.testacc_snapshot.id + snapshot = ibm_is_snapshot.example.id + tags = ["tags-0"] } primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id name = "eth1" } } + +// Example to provision an instance using an enterprise managed catalog image + +data ibm_is_images example { + catalog_managed = true +} + +resource "ibm_is_instance" "example" { + name = "example-vsi-catalog" + profile = "cx2-2x4" + catalog_offering { + version_crn = data.ibm_is_images.example.images.0.catalog_offering.0.version.0.crn + } + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + network_interfaces { + subnet = ibm_is_subnet.example.id + name = "eth1" + } +} ``` ## Timeouts @@ -253,68 +338,128 @@ The `ibm_is_instance` resource provides the following [[Timeouts](https://www.te ## Argument reference Review the argument references that you can specify for your resource. - +- `action` - (Optional, String) Action to be taken on the instance. Supported values are `stop`, `start`, or `reboot`. + + ~> **Note** + `action` allows to start, stop and reboot the instance and it is not recommended to manage the instance from terraform and other clients (UI/CLI) simultaneously, as it would cause unknown behaviour. `start` action can be performed only when the instance is in `stopped` state. `stop` and `reboot` actions can be performed only when the instance is in `running` state. It is also recommended to remove the `action` configuration from terraform once it is applied succesfully, to avoid instability in the terraform configuration later. - `auto_delete_volume`- (Optional, Bool) If set to **true**, automatically deletes the volumes that are attached to an instance. **Note** Setting this argument can bring some inconsistency in the volume resource, as the volumes is destroyed along with instances. +- `availability_policy_host_failure` - (Optional, String) The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure. Supported values are `restart` and `stop`. - `boot_volume` (Optional, List) A list of boot volumes for an instance. Nested scheme for `boot_volume`: - `encryption` - (Optional, String) The type of encryption to use for the boot volume. - `name` - (Optional, String) The name of the boot volume. + - `size` - (Optional, Integer) The size of the boot volume.(The capacity of the volume in gigabytes. This defaults to minimum capacity of the image and maximum to `250`. + + ~> **NOTE:** + Supports only expansion on update (must be attached to a running instance and must not be less than the current volume size) - `snapshot` - (Optional, Forces new resource, String) The snapshot id of the volume to be used for creating boot volume attachment - **Note** - - `snapshot` conflicts with `image` id and `instance_template` -- `dedicated_host` - (Optional, Forces new resource, String) The placement restrictions to use the virtual server instance. Unique ID of the dedicated host where the instance id placed. -- `dedicated_host_group` - (Optional, Forces new resource, String) The placement restrictions to use for the virtual server instance. Unique ID of the dedicated host group where the instance is placed. -- `placement_group` - (Optional, string) Unique Identifier of the Placement Group for restricting the placement of the instance -- `force_recovery_time` - (Optional, Integer) Define timeout (in minutes), to force the `is_instance` to recover from a perpetual "starting" state, during provisioning. And to force the is_instance to recover from a perpetual "stopping" state, during removal of user access. **Note** The force_recovery_time is used to retry multiple times until timeout. -- `image` - (Optional, String) The ID of the virtual server image that you want to use. To list supported images, run `ibmcloud is images`. - **Note** - - - `image` conflicts with `boot_volume.0.snapshot` -- `keys` - (Optional, List) A comma-separated list of SSH keys that you want to add to your instance. + ~> **Note:** + `snapshot` conflicts with `image` id, `instance_template` and `catalog_offering` + - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) +- `catalog_offering` - (Optional, List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. + Nested scheme for `catalog_offering`: + - `offering_crn` - (Optional, String) The CRN for this catalog offering. Identifies a catalog offering by this unique property + - `version_crn` - (Optional, String) The CRN for this version of a catalog offering. Identifies a version of a catalog offering by this unique property + + ~> **Note:** + `offering_crn` conflicts with `version_crn`, both are mutually exclusive. `catalog_offering` and `image` id are mutually exclusive. + `snapshot` conflicts with `image` id and `instance_template` +- `dedicated_host` - (Optional, String) The placement restrictions to use the virtual server instance. Unique ID of the dedicated host where the instance id placed. +- `dedicated_host_group` - (Optional, String) The placement restrictions to use for the virtual server instance. Unique ID of the dedicated host group where the instance is placed. + + -> **NOTE:** + An instance can be moved from one dedicated host or group to another host or group. Moving an instance from public to dedicated host or vice versa is not allowed. + +- `default_trusted_profile_auto_link` - (Optional, Forces new resource, Boolean) If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted. Default value : **true** +- `default_trusted_profile_target` - (Optional, Forces new resource, String) The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance. +- `force_action` - (Optional, Boolean) Required with `action`. If set to `true`, the action will be forced immediately, and all queued actions deleted. Ignored for the start action. +- `force_recovery_time` - (Optional, Integer) Define timeout (in minutes), to force the `is_instance` to recover from a perpetual "starting" state, during provisioning. And to force the is_instance to recover from a perpetual "stopping" state, during removal of user access. + + ~>**Note:** The force_recovery_time is used to retry multiple times until timeout. +- `image` - (Required, String) The ID of the virtual server image that you want to use. To list supported images, run `ibmcloud is images` or use `ibm_is_images` datasource. + + ~> **Note:** + `image` conflicts with `boot_volume.0.snapshot` and `catalog_offering`, not required when creating instance using `instance_template` or `catalog_offering` +- `keys` - (Required, List) A comma-separated list of SSH keys that you want to add to your instance. +- `lifecycle_reasons`- (List) The reasons for the current lifecycle_state (if any). + + Nested scheme for `lifecycle_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this lifecycle state. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state`- (String) The lifecycle state of the virtual server instance. [ **deleting**, **failed**, **pending**, **stable**, **suspended**, **updating**, **waiting** ] +- `metadata_service_enabled` - (Optional, Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. Default value : **false** - `name` - (Optional, String) The instance name. - `network_interfaces` (Optional, Forces new resource, List) A list of more network interfaces that are set up for the instance. - Nested scheme for `network_interaces`: + -> **Allowed vNIC per profile.** + **•** 2-16 vCPUs: Up to 5 vNICs
**•** 17-48 vCPUs: Up to 10 vNICs
**•** 49+ vCPUs: Up to 15 vNICs + + Nested scheme for `network_interfaces`: - `allow_ip_spoofing`- (Optional, Bool) Indicates whether IP spoofing is allowed on the interface. If **false**, IP spoofing is prevented on the interface. If **true**, IP spoofing is allowed on the interface. - **NOTE**: - - `allow_ip_spoofing` requires **IP spoofing operator** access under VPC infrastructure Services. As the **IP spoofing operator**, you can enable or disable the IP spoofing check on virtual server instances. - - Use this only if you have **IP spoofing operator** access. + + ~> **NOTE:** + `allow_ip_spoofing` requires **IP spoofing operator** access under VPC infrastructure Services. As the **IP spoofing operator**, you can enable or disable the IP spoofing check on virtual server instances. Use this only if you have **IP spoofing operator** access. - `name` - (Optional, String) The name of the network interface. - - `primary_ipv4_address` - (Optional, Forces new resource, String) The IPV4 address of the interface. + - `primary_ip` - (Optional, List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `address` - (Optional, String) The IP address of the reserved IP. This is same as `network_interfaces.[].primary_ipv4_address` + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. + - `primary_ipv4_address` - (Optional, Deprecated, Forces new resource, String) The IPV4 address of the interface. `primary_ipv4_address` will be deprecated, use `primary_ip.[0].address` instead. - `subnet` - (Required, String) The ID of the subnet. - `security_groups`- (Optional, List of strings)A comma separated list of security groups to add to the primary network interface. -- `primary_network_interface` - (Optional, List) A nested block describes the primary network interface of this instance. Only one primary network interface can be specified for an instance. +- `placement_group` - (Optional, string) Unique Identifier of the Placement Group for restricting the placement of the instance +- `primary_network_interface` - (Required, List) A nested block describes the primary network interface of this instance. Only one primary network interface can be specified for an instance. When using `instance_template`, `primary_network_interface` is not required. Nested scheme for `primary_network_interface`: - `allow_ip_spoofing`- (Optional, Bool) Indicates whether IP spoofing is allowed on the interface. If **false**, IP spoofing is prevented on the interface. If **true**, IP spoofing is allowed on the interface. - **NOTE**: - - `allow_ip_spoofing` requires **IP spoofing operator** access under VPC infrastructure Services. As the **IP spoofing operator**, you can enable or disable the IP spoofing check on virtual server instances. - - Use this only if you have **IP spoofing operator** access. + + ~> **NOTE:** + `allow_ip_spoofing` requires **IP spoofing operator** access under VPC infrastructure Services. As the **IP spoofing operator**, you can enable or disable the IP spoofing check on virtual server instances. Use this only if you have **IP spoofing operator** access. - `name` - (Optional, String) The name of the network interface. - `port_speed` - (Deprecated, Integer) Speed of the network interface. - - `primary_ipv4_address` - (Optional, Forces new resource, String) The IPV4 address of the interface. + - `primary_ip` - (Optional, List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `address` - (Optional, String) The IP address of the reserved IP. This is same as `primary_network_interface.[0].primary_ipv4_address` which will be deprecated. + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP + - `primary_ipv4_address` - (Optional, Deprecated, Forces new resource, String) The IPV4 address of the interface.`primary_ipv4_address` will be deprecated, use `primary_ip.[0].address` instead. - `subnet` - (Required, String) The ID of the subnet. - `security_groups`-List of strings-Optional-A comma separated list of security groups to add to the primary network interface. -- `profile` - (Optional, Forces new resource, String) The name of the profile that you want to use for your instance. To list supported profiles, run `ibmcloud is instance-profiles`. +- `profile` - (Required, String) The name of the profile that you want to use for your instance. Not required when using `instance_template`. To list supported profiles, run `ibmcloud is instance-profiles` or `ibm_is_instance_profiles` datasource. + + **NOTE:** + When the `profile` is changed, the VSI is restarted. The new profile must: + 1. Have matching instance disk support. Any disks associated with the current profile will be deleted, and any disks associated with the requested profile will be created. + 2. Be compatible with any placement_target(`dedicated_host`, `dedicated_host_group`, `placement_group`) constraints. For example, if the instance is placed on a dedicated host, the requested profile family must be the same as the dedicated host family. + + ~> **NOTE** + Changing a `profile` without disk to a `profile` with disk or vise versa will result in recreating(forcenew) the resource. - `resource_group` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the instance. -- `instance_template` - (Optional, String) ID of the source template. - **Note** - - - `instance_template` conflicts with `boot_volume.0.snapshot` +- `instance_template` - (Optional, String) ID of the instance template to create the instance from. To create an instance template, use `ibm_is_instance_template` resource. + + ~> **Note:** + `instance_template` conflicts with `boot_volume.0.snapshot`. When creating an instance using `instance_template`, [`image `, `primary_network_interface`, `vpc`, `zone`] are not required. - `tags` (Optional, Array of Strings) A list of tags that you want to add to your instance. Tags can help you find your instance more easily later. -- `user_data` - (Optional, String) User data to transfer to the instance. +- `total_volume_bandwidth` - (Optional, Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes +- `user_data` - (Optional, String) User data to transfer to the instance. For more information, about `user_data`, see [about user data](https://cloud.ibm.com/docs/vpc?topic=vpc-user-data). - `volumes` (Optional, List) A comma separated list of volume IDs to attach to the instance. -- `vpc` - (Optional, Forces new resource, String) The ID of the VPC where you want to create the instance. -- `zone` - (Optional, Forces new resource, String) The name of the VPC zone where you want to create the instance. +- `vpc` - (Required, Forces new resource, String) The ID of the VPC where you want to create the instance. When using `instance_template`, `vpc` is not required. +- `zone` - (Required, Forces new resource, String) The name of the VPC zone where you want to create the instance. When using `instance_template`, `zone` is not required. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - +- `bandwidth` - The total bandwidth (in megabits per second) shared across the instance's network interfaces and storage volumes - `boot_volume`- (List of Strings) A list of boot volumes that the instance uses. Nested scheme for `boot_volume`: @@ -359,7 +504,14 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name of the network interface. - `subnet` - (String) The ID of the subnet. - `security_groups`- (List of Strings) A list of security groups that are used in the network interface. - - `primary_ipv4_address` - (String) The primary IPv4 address. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `auto_delete` - (Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `address` - (String) The IP address of the reserved IP. This is same as `network_interfaces.[].primary_ipv4_address` which will be deprecated. + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP + - `primary_ipv4_address` - (String, Deprecated) The primary IPv4 address. Same as `primary_ip.[0].address` - `primary_network_interface`- (List of Strings) A list of primary network interfaces that are attached to the instance. Nested scheme for `primary_network_interface`: @@ -368,13 +520,29 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name of the primary network interface. - `subnet` - (String) The ID of the subnet that the primary network interface is attached to. - `security_groups`-List of strings-A list of security groups that are used in the primary network interface. - - `primary_ipv4_address` - (String) The primary IPv4 address. + - `primary_ip` - (List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + + Nested scheme for `primary_ip`: + - `auto_delete` - (Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `address` - (String) The IP address of the reserved IP. This is same as `primary_network_interface.[0].primary_ipv4_address` which will be deprecated. + - `name`- (String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (String) The unique identifier for this reserved IP. + - `primary_ipv4_address` - (String, Deprecated) The primary IPv4 address. Same as `primary_ip.[0].address` + ```terraform + // primary_ipv4_address deprecation + output "primary_ipv4_address" { + # value = ibm_is_instance.example.primary_network_interface.0.primary_ipv4_address // will be deprecated in future + value = ibm_is_instance.example.primary_network_interface.0.primary_ip.0.address // use this instead + } + ``` - `status` - (String) The status of the instance. - `status_reasons` - (List) Array of reasons for the current status. Nested scheme for `status_reasons`: - `code` - (String) A string with an underscore as a special character identifying the status reason. - `message` - (String) An explanation of the status reason. + - `more_info` - (String) Link to documentation about this status reason +- `total_network_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance network interfaces. - `volume_attachments`- (List of Strings) A list of volume attachments for the instance. Nested scheme for `volume_attachements`: diff --git a/website/docs/r/is_instance_action.html.markdown b/website/docs/r/is_instance_action.html.markdown new file mode 100644 index 000000000..dbb62c9b6 --- /dev/null +++ b/website/docs/r/is_instance_action.html.markdown @@ -0,0 +1,116 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : instance action" +description: |- + Manages IBM instance action. +--- + +# ibm_is_instance_action + +Start, stop, or reboot an instance for VPC. For more information, about managing VPC instance, see [about virtual server instances for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-advanced-virtual-servers). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +In the following example, you can perform instance action: + +```terraform + +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = "7eb4e35b-4257-56f8-d7da-326d85452591" + profile = "bc1-2x8" + + boot_volume { + encryption = "crn:v1:bluemix:public:kms:us-south:a/dffc98a0f1f0f95f6613b3b752286b87:e4a29d1a-2ef0-42a6-8fd2-350deb1c647e:key:5437653b-c4b1-447f-9646-b2a2a4cd6179" + } + + primary_network_interface { + subnet = ibm_is_subnet.example.id + primary_ipv4_address = "10.240.0.6" + allow_ip_spoofing = true + } + + network_interfaces { + name = "eth1" + subnet = ibm_is_subnet.example.id + allow_ip_spoofing = false + } + + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + + //User can configure timeouts + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } +} + +resource "ibm_is_instance_action" "example" { + action = "stop" + force_action = true + instance = ibm_is_instance.example.id +} + + +``` + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `action` - (Required, String) The type of action to perfrom on the instance. Supported values are `stop`, `start`, or `reboot`. +- `force_action` - (Optional, Boolean) If set to `true`, the action will be forced immediately, and all queued actions deleted. Ignored for the start action. The Default value is `false`. +- `instance` - (Required, String) Instance identifier. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `status` - (String) The status of the instance. The supported status are **failed**, **pending**, **restarting**, **running**, **starting**, **stopped**, or **stopping**. +- `status_reasons` - (List) Array of reasons for the current status (if any). + + Nested `status_reasons`: + - `code` - (String) The status reason code. + - `message` - (String) An explanation of the status reason. + - `more_info` - (String) Link to documentation about this status reason + +## Import +The `ibm_is_instance_action` resource can be imported by using instance action ID. + +**Example** + +```sh +$ terraform import ibm_is_instance_action.example d7bec597-4726-451f-8a63-e62e6f121c32c +``` diff --git a/website/docs/r/is_instance_disk_management.html.markdown b/website/docs/r/is_instance_disk_management.html.markdown index badc3c342..49d450c3b 100644 --- a/website/docs/r/is_instance_disk_management.html.markdown +++ b/website/docs/r/is_instance_disk_management.html.markdown @@ -9,60 +9,70 @@ description: |- # ibm_is_instance_disk_management Create, update, or delete an IBM instance disk management. For more information, about instance disk management, see [managing instance storage](https://cloud.ibm.com/docs/vpc?topic=vpc-instance-storage-provisioning). +**Note:** VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "10.240.0.0/24" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = file("~/.ssh/id_rsa.pub") } -resource "ibm_is_instance" "testacc_instance" { - name = "testinstance" - image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id profile = "bc1-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } network_interfaces { name = "eth1" - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-1" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -data "ibm_is_instance" "ds_instance" { - name = "${ibm_is_instance.testacc_instance.name}" +data "ibm_is_instance" "example" { + name = ibm_is_instance.example.name private_key = file("~/.ssh/id_rsa") passphrase = "" } -data "is_instance_disk" "is_instance_disk" { - instance = data.ibm_is_instance.ds_instance.id - disk = data.ibm_is_instance.ds_instance.disks.0.id +data "is_instance_disk" "example" { + instance = data.ibm_is_instance.example.id + disk = data.ibm_is_instance.example.disks.0.id } -resource "ibm_is_instance_disk_management" "disks"{ - instance = data.ibm_is_instance.ds_instance.id +resource "ibm_is_instance_disk_management" "example" { + instance = data.ibm_is_instance.example.id disks { - name = "mydisk01" - id = data.ibm_is_instance.ds_instance.disks.0.id + name = "example-disk" + id = data.ibm_is_instance.example.disks.0.id } } ``` diff --git a/website/docs/r/is_instance_group.html.markdown b/website/docs/r/is_instance_group.html.markdown index d4db09f00..d9b881633 100644 --- a/website/docs/r/is_instance_group.html.markdown +++ b/website/docs/r/is_instance_group.html.markdown @@ -11,45 +11,56 @@ description: |- Create, update or delete a instance group on VPC. For more information, about instance group, see [managing an instance group](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage In the following example, you can create a instance group on VPC Generation-2 infrastructure. ```terraform -resource "ibm_is_vpc" "vpc2" { - name = "vpc2test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet2" { - name = "subnet2" - vpc = ibm_is_vpc.vpc2.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-2" ipv4_cidr_block = "10.240.64.0/28" } -resource "ibm_is_ssh_key" "sshkey" { - name = "ssh1" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "SSH KEY" } -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testtemplate" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -resource "ibm_is_instance_group" "instance_group" { - name = "testgroup" - instance_template = ibm_is_instance_template.instancetemplate1.id +resource "ibm_is_instance_group" "example" { + name = "example-group" + instance_template = ibm_is_instance_template.example.id instance_count = 2 - subnets = [ibm_is_subnet.subnet2.id] + subnets = [ibm_is_subnet.example.id] //User can configure timeouts timeouts { @@ -75,7 +86,7 @@ Review the argument references that you can specify for your resource. - `load_balancer` - (Optional, String) The load Balancer ID, the `application_port` and `load_balancer_pool` arguments must be specified when configured. - `load_balancer_pool` - (Optional, String) The load Balancer pool ID, the `application_port` and `load_balancer` arguments must be specified when configured. - `instance_template` - (Required, Forces new resource, String) The ID of the instance template to create the instance group. -- `instance_count` - (Optional, Integer) The number of instances to create in the instance group. **Note** instance group manager must be in diables state to update the `instance_count`. +- `instance_count` - (Optional, Integer) The number of instances to create in the instance group. ~>**Note:** instance group manager must be in diables state to update the `instance_count`. - `name` - (Required, String) The instance group name. - `resource_group` - (Optional, String) The resource group ID. - `subnets` - (Required, List) The list of subnet IDs used by the instances. diff --git a/website/docs/r/is_instance_group_manager.html.markdown b/website/docs/r/is_instance_group_manager.html.markdown index e8b7d7805..48b3fe4e4 100644 --- a/website/docs/r/is_instance_group_manager.html.markdown +++ b/website/docs/r/is_instance_group_manager.html.markdown @@ -10,58 +10,69 @@ description: |- # ibm_is_instance_group_manager Create, update, or delete an instance group manager on VPC of an instance group. For more information, about instance group manager, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example creates an instance group manager. ```terraform -resource "ibm_is_vpc" "vpc2" { - name = "vpc2test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet2" { - name = "subnet2" - vpc = ibm_is_vpc.vpc2.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-2" ipv4_cidr_block = "10.240.64.0/28" } -resource "ibm_is_ssh_key" "sshkey" { - name = "ssh1" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "SSH_KEY" } -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testtemplate" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -resource "ibm_is_instance_group" "instance_group" { - name = "testgroup" - instance_template = ibm_is_instance_template.instancetemplate1.id +resource "ibm_is_instance_group" "example" { + name = "example-group" + instance_template = ibm_is_instance_template.example.id instance_count = 2 - subnets = [ibm_is_subnet.subnet2.id] + subnets = [ibm_is_subnet.example.id] //User can configure timeouts timeouts { create = "15m" delete = "15m" - update = "10m" + update = "10m" } } -resource "ibm_is_instance_group_manager" "instance_group_manager" { - name = "testmanager" +resource "ibm_is_instance_group_manager" "example" { + name = "example-ig-manager" aggregation_window = 120 - instance_group = ibm_is_instance_group.instance_group.id + instance_group = ibm_is_instance_group.example.id cooldown = 300 manager_type = "autoscale" enable_manager = true @@ -69,9 +80,9 @@ resource "ibm_is_instance_group_manager" "instance_group_manager" { min_membership_count = 1 } -resource "ibm_is_instance_group_manager" "instance_group_manager_scheduled" { - name = "testinstancegroupmanager" - instance_group = ibm_is_instance_group.instance_group.id +resource "ibm_is_instance_group_manager" "example" { + name = "example-instance-group-manager" + instance_group = ibm_is_instance_group.example.id manager_type = "scheduled" enable_manager = true } diff --git a/website/docs/r/is_instance_group_manager_action.html.markdown b/website/docs/r/is_instance_group_manager_action.html.markdown index b12a8cac4..6cf301a85 100644 --- a/website/docs/r/is_instance_group_manager_action.html.markdown +++ b/website/docs/r/is_instance_group_manager_action.html.markdown @@ -9,6 +9,17 @@ description: |- # ibm_is_instance_group_manager_action Create, update, or delete an instance group manager action on VPC. For more information, about instance group manager action, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform @@ -16,54 +27,54 @@ provider "ibm" { generation = 2 } -resource "ibm_is_vpc" "vpc2" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet2" { - name = "testsubnet" - vpc = ibm_is_vpc.vpc2.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-2" ipv4_cidr_block = "10.240.64.0/28" } -resource "ibm_is_ssh_key" "sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "SSH_KEY" } -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testinstancetemplate" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example" { + name = "example-instance-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -resource "ibm_is_instance_group" "instance_group" { - name = "testinstancegroup" - instance_template = ibm_is_instance_template.instancetemplate1.id +resource "ibm_is_instance_group" "example" { + name = "example-instance-group" + instance_template = ibm_is_instance_template.example.id instance_count = 2 - subnets = [ibm_is_subnet.subnet2.id] + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_instance_group_manager" "instance_group_manager" { - name = "testinstancegroupmanager" - instance_group = ibm_is_instance_group.instance_group.id +resource "ibm_is_instance_group_manager" "example" { + name = "example-instance-group-manager" + instance_group = ibm_is_instance_group.example.id manager_type = "scheduled" enable_manager = true } -resource "ibm_is_instance_group_manager_action" "instance_group_manager_action" { - name = "testinstancegroupmanageraction" - instance_group = ibm_is_instance_group.instance_group.id - instance_group_manager = ibm_is_instance_group_manager.instance_group_manager.manager_id +resource "ibm_is_instance_group_manager_action" "example" { + name = "example-instance-group-manager-action" + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id cron_spec = "*/5 1,2,3 * * *" membership_count = 1 } diff --git a/website/docs/r/is_instance_group_manager_policy.html.markdown b/website/docs/r/is_instance_group_manager_policy.html.markdown index 55caa1a47..25d12e134 100644 --- a/website/docs/r/is_instance_group_manager_policy.html.markdown +++ b/website/docs/r/is_instance_group_manager_policy.html.markdown @@ -9,47 +9,58 @@ description: |- # ibm_is_instance_group_manager_policy -Create update or delete a policy of an instance group manager. For more information, about instance group manager policy, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). +Create, update or delete a policy of an instance group manager. For more information, about instance group manager policy, see [creating an instance group for auto scaling](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-auto-scale-instance-group). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage In the following example, you can create a policy for instance group manager. ```terraform -resource "ibm_is_vpc" "vpc2" { - name = "vpc2test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet2" { - name = "subnet2" - vpc = ibm_is_vpc.vpc2.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-2" ipv4_cidr_block = "10.240.64.0/28" } -resource "ibm_is_ssh_key" "sshkey" { - name = "ssh1" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "SSH_KEY" } -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testtemplate" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] } -resource "ibm_is_instance_group" "instance_group" { - name = "testgroup" - instance_template = ibm_is_instance_template.instancetemplate1.id +resource "ibm_is_instance_group" "example" { + name = "example-instance-group" + instance_template = ibm_is_instance_template.example.id instance_count = 2 - subnets = [ibm_is_subnet.subnet2.id] + subnets = [ibm_is_subnet.example.id] //User can configure timeouts timeouts { @@ -59,10 +70,10 @@ resource "ibm_is_instance_group" "instance_group" { } } -resource "ibm_is_instance_group_manager" "instance_group_manager" { - name = "testmanager" +resource "ibm_is_instance_group_manager" "example" { + name = "example-instance-group-manager" aggregation_window = 120 - instance_group = ibm_is_instance_group.instance_group.id + instance_group = ibm_is_instance_group.example.id cooldown = 300 manager_type = "autoscale" enable_manager = true @@ -70,13 +81,13 @@ resource "ibm_is_instance_group_manager" "instance_group_manager" { min_membership_count = 1 } -resource "ibm_is_instance_group_manager_policy" "cpuPolicy" { - instance_group = ibm_is_instance_group.instance_group.id - instance_group_manager = ibm_is_instance_group_manager.instance_group_manager.manager_id +resource "ibm_is_instance_group_manager_policy" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_manager = ibm_is_instance_group_manager.example.manager_id metric_type = "cpu" metric_value = 70 policy_type = "target" - name = "testpolicy" + name = "example-ig-manager-policy" } ``` diff --git a/website/docs/r/is_instance_group_membership.html.markdown b/website/docs/r/is_instance_group_membership.html.markdown index 924a9bfbd..d84833106 100644 --- a/website/docs/r/is_instance_group_membership.html.markdown +++ b/website/docs/r/is_instance_group_membership.html.markdown @@ -9,13 +9,24 @@ description: |- # ibm_is_instance_group_membership Create, update, or delete a instance group memership of an instance group. For more information, about instance group membership, see [bulk provisioning instances with instance groups](https://cloud.ibm.com/docs/vpc?topic=vpc-bulk-provisioning). -## Example Usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage ```terraform -resource "is_instance_group_membership" "is_instance_group_membership" { - instance_group = "r006-76740f94-fcc4-11e9-96e7-a77723715315" - instance_group_membership = "eff45fa0-de38-4368-8a0d-28dc88c2ef9b" - name = "membershipname" +resource "is_instance_group_membership" "example" { + instance_group = ibm_is_instance_group.example.id + instance_group_membership = data.ibm_is_instance_group_memberships.example.memberships.0.instance_group_membership + name = "example-ig-membership" } ``` diff --git a/website/docs/r/is_instance_network_interface.html.markdown b/website/docs/r/is_instance_network_interface.html.markdown new file mode 100644 index 000000000..6c8339535 --- /dev/null +++ b/website/docs/r/is_instance_network_interface.html.markdown @@ -0,0 +1,136 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : is_instance_network_interface" +description: |- + Manages NetworkInterface. +--- + +# ibm_is_instance_network_interface + +Create, update, or delete an instance network interface on VPC. For more information, about instance network interface, see [managing an network interface](https://cloud.ibm.com/docs/vpc?topic=vpc-using-instance-vnics). + +**Note:** +- IBM Cloud terraform provider currently provides both a standalone `ibm_is_instance_network_interface` resource and a `network_interfaces` block defined in-line in the `ibm_is_instance` resource. At this time you cannot use the `network_interfaces` block inline with `ibm_is_instance` in conjunction with the standalone resource `ibm_is_instance_network_interface`. Doing so will create a conflict of network interfaces and will overwrite it. +- IBM Cloud terraform provider currently provides both a standalone `ibm_is_security_group_target` resource and a `security_groups` block defined in-line in the `ibm_is_instance_network_interface` resource to attach security group to a network interface target. At this time you cannot use the `security_groups` block inline with `ibm_is_instance_network_interface` in conjunction with the standalone resource `ibm_is_security_group_target`. Doing so will create a conflict of security groups attaching to the network interface and will overwrite it. +- VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + + **provider.tf** + + ```terraform + provider "ibm" { + region = "eu-gb" + } + ``` + + -> **Allowed vNIC per profile.** + **•** 2-16 vCPUs: Up to 5 vNICs
**•** 17-48 vCPUs: Up to 10 vNICs
**•** 49+ vCPUs: Up to 15 vNICs +## Example usage + +```terraform + +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + ipv4_cidr_block = "10.240.0.0/24" +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = file("~/.ssh/id_rsa.pub") +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = "a7a0626c-f97e-4180-afbe-0331ec62f32a" + profile = "bc1-2x8" + + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + + network_interfaces { + name = "eth1" + subnet = ibm_is_subnet.example.id + } + + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] +} + +resource "ibm_is_instance_network_interface" "example" { + instance = ibm_is_instance.example.id + subnet = ibm_is_subnet.example.id + allow_ip_spoofing = true + name = "example-network-interface" + primary_ipv4_address = "10.0.0.5" +} +``` + +## Argument reference + +The following arguments are supported: + +- `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. The default value is `false`. +- `floating_ip` - (Optional, String) The ID of the floating IP to attach to this network interface. +- `instance` - (Required, Forces new resource, String) The instance identifier. +- `name` - (Required, String) The user-defined name for this network interface. +- `primary_ip` - (Optional, List) The primary IP address to bind to the network interface. This can be specified using an existing reserved IP, or a prototype object for a new reserved IP. + Nested scheme for `primary_ip`: + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. + - `address` - (Optional, String) The IP address. Same as `primary_ipv4_address` + - `name`- (Optional, String) The user-defined or system-provided name for this reserved IP + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP +- `primary_ipv4_address` - (Optional, Forces new resource, String) The primary IPv4 address. If specified, it must be an available address on the network interface's subnet. If unspecified, an available address on the subnet will be automatically selected. +- `security_groups` - (Optional, List of strings) A comma separated list of security groups to add to the primary network interface. +- `subnet` - (Required, Forces new resource, String) The unique identifier of the associated subnet. + + +~> **Note** + - Only 1 floating IP can be attached to a VSI at any given time. Floating IP can be de-attached from one network interface and attached to a different network interface, but be sure to remove the floating_ip field from the previous network interface resource before adding it to a new resource. +~> **Note** + - `floating_ip` cannot be used in conjunction with the `target` argument of `ibm_is_floating_ip` resource and might cause cyclic dependency/unexpected issues if used used both ways. +~> **Note** + - Using `ibm_is_security_group_target` to attach security groups to the network interface along with `security_groups` field in this resource could cause undesired behavior. Use either one of them to associate network interface to a security group. + +## Attribute reference + +In addition to all arguments above, the following attributes are exported: + +- `created_at` - (String) The date and time that the network interface was created. +- `floating_ips` - (List) The floating IPs associated with this network interface. Nested `floating_ips` blocks have the following structure: + - `address` - (String) The globally unique IP address. + - `crn` - (String) The CRN for this floating IP. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this floating IP. + - `id` - (String) The unique identifier for this floating IP. + - `name` - (String) The unique user-defined name for this floating IP. +- `href` - (String) The URL for this network interface. +- `id` - (String) The unique identifier of the resource. Follows the format /. +- `network_interface` - (String) The unique identifier of the NetworkInterface. +- `port_speed` - (Integer) The network interface port speed in Mbps. +- `resource_type` - (String) The resource type. +- `status` - (String) The status of the network interface. +- `type` - (String) The type of this network interface as it relates to an instance. + +## Import + +You can import the `ibm_is_instance_network_interface` resource by using `id`. +The `id` property can be formed from `instance_ID`, and `network_interface_ID` in the following format: + +``` +/ +``` +- `instance`: A string. The instance identifier. +- `network_interface`: A string. The network interface identifier. + +``` +$ terraform import ibm_is_instance_network_interface.is_instance_network_interface / +``` diff --git a/website/docs/r/is_instance_template.html.markdown b/website/docs/r/is_instance_template.html.markdown index 8b022dabc..f4dfa266e 100644 --- a/website/docs/r/is_instance_template.html.markdown +++ b/website/docs/r/is_instance_template.html.markdown @@ -8,154 +8,163 @@ description: |- --- # ibm_is_instance_template -Create, update, or delete an instance template on VPC. +Create, update, or delete an instance template on VPC. For more information, about instance template, see [managing an instance template](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-instance-template). + +~>**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage The following example creates an instance template in a VPC generation-2 infrastructure. ```terraform -resource "ibm_is_vpc" "vpc2" { - name = "vpc2test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet2" { - name = "subnet2" - vpc = ibm_is_vpc.vpc2.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-2" ipv4_cidr_block = "10.240.64.0/28" } -resource "ibm_is_ssh_key" "sshkey" { - name = "ssh1" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "SSH KEY" } -data "ibm_resource_group" "default" { - name = "Default" ///give your resource grp +resource "ibm_resource_group" "example" { + name = "example-resource-group" } -resource "ibm_is_dedicated_host_group" "dh_group01" { - family = "compute" - class = "cx2" - zone = "us-south-1" - name = "my-dh-group-01" - resource_group = data.ibm_resource_group.default.id +resource "ibm_is_dedicated_host_group" "example" { + family = "compute" + class = "cx2" + zone = "us-south-1" + name = "example-dedicated-host-group-01" + resource_group = ibm_resource_group.example.id } -resource "ibm_is_dedicated_host" "is_dedicated_host" { - profile = "bx2d-host-152x608" - name = "my-dedicated-host-01" - host_group = ibm_is_dedicated_host_group.dh_group01.id - resource_group = data.ibm_resource_group.default.id +resource "ibm_is_dedicated_host" "example" { + profile = "bx2d-host-152x608" + name = "example-dedicated-host" + host_group = ibm_is_dedicated_host_group.example.id + resource_group = ibm_resource_group.example.id } -resource "ibm_is_volume" "datavol" { - name = "datavol1" - resource_group = data.ibm_resource_group.default.id +resource "ibm_is_volume" "example" { + name = "example-data-vol1" + resource_group = ibm_resource_group.example.id zone = "us-south-2" profile = "general-purpose" capacity = 50 } -data "ibm_resource_group" "default" { - is_default = true -} // Create a new volume with the volume attachment. This template format can be used with instance groups -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testtemplate" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id allow_ip_spoofing = true } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] boot_volume { - name = "testbootvol" + name = "example-boot-volume" delete_volume_on_instance_delete = true } - volume_attachments { - delete_volume_on_instance_delete = true - name = "volatt-01" - volume_prototype { - iops = 3000 - profile = "general-purpose" - capacity = 200 - } + volume_attachments { + delete_volume_on_instance_delete = true + name = "example-volume-att-01" + volume_prototype { + iops = 3000 + profile = "custom" + capacity = 200 } + } } -// Template with volume attachment that attaches exisiting storage volume. This template cannot be used with instance groups -resource "ibm_is_instance_template" "instancetemplate2" { - name = "testtemplate1" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +// Template with volume attachment that attaches existing storage volume. This template cannot be used with instance groups +resource "ibm_is_instance_template" "example1" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" - + metadata_service_enabled = false + primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id allow_ip_spoofing = true } - vpc = ibm_is_vpc.vpc2.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + keys = [ibm_is_ssh_key.example.id] boot_volume { - name = "testbootvol" + name = "example-boot-volume" delete_volume_on_instance_delete = true } - volume_attachments { - delete_volume_on_instance_delete = true - name = "volatt-01" - volume = ibm_is_volume.datavol.id - } + volume_attachments { + delete_volume_on_instance_delete = true + name = "example-volume-att" + volume = ibm_is_volume.example.id + } } -resource "ibm_is_instance_template" "instancetemplate1" { - name = "testtemplate1" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example3" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id allow_ip_spoofing = true } - dedicated_host_group = ibm_is_dedicated_host_group.dh_group01.id - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + dedicated_host_group = ibm_is_dedicated_host_group.example.id + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.example.id] boot_volume { - name = "testbootvol" + name = "example-boot-volume" delete_volume_on_instance_delete = true } } -resource "ibm_is_instance_template" "instancetemplate2" { - name = "testtemplat2" - image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" +resource "ibm_is_instance_template" "example4" { + name = "example-template" + image = ibm_is_image.example.id profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.example.id allow_ip_spoofing = true } - dedicated_host = "7eb4e35b-4257-56f8-d7da-326d85452592" - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + dedicated_host = ibm_is_dedicated_host.example.id + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.example.id] boot_volume { - name = "testbootvol" + name = "example-boot-volume" delete_volume_on_instance_delete = true } } @@ -164,6 +173,7 @@ resource "ibm_is_instance_template" "instancetemplate2" { ## Argument reference Review the argument references that you can specify for your resource. +- `availability_policy_host_failure` - (Optional, String) The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure. Supported values are `restart` and `stop`. - `boot_volume` - (Optional, List) A nested block describes the boot volume configuration for the template. @@ -171,24 +181,28 @@ Review the argument references that you can specify for your resource. - `delete_volume_on_instance_delete` - (Optional, Bool) You can configure to delete the boot volume based on instance deletion. - `encryption` - (Optional, String) The encryption key CRN to encrypt the boot volume attached. - `name` - (Optional, String) The name of the boot volume. + - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) +- `total_volume_bandwidth` - (Optional, int) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `dedicated_host` - (Optional, Force new resource,String) The placement restrictions to use for the virtual server instance. Unique Identifier of the dedicated host where the instance is placed. - **NOTE:** - - only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used + ~>**Note:** + only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used - `dedicated_host_group` - (Optional, Force new resource, String) The placement restrictions to use for the virtual server instance. Unique Identifier of the dedicated host group where the instance is placed. - **NOTE:** - - only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used + ~>**Note:** + only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used +- `default_trusted_profile_auto_link` - (Optional, Forces new resource, Boolean) If set to `true`, the system will create a link to the specified `target` trusted profile during instance creation. Regardless of whether a link is created by the system or manually using the IAM Identity service, it will be automatically deleted when the instance is deleted. Default value : **true** +- `default_trusted_profile_target` - (Optional, Forces new resource, String) The unique identifier or CRN of the default IAM trusted profile to use for this virtual server instance. - `image` - (Required, String) The ID of the image to create the template. - `keys` - (Required, List) List of SSH key IDs used to allow log in user to the instances. -- `name` - (Required, String) The name of the instance template. +- `metadata_service_enabled` - (Optional, Forces new resource, Boolean) Indicates whether the metadata service endpoint is available to the virtual server instance. Default value : **false** +- `name` - (Optional, String) The name of the instance template. - `placement_group` - (Optional, Force new resource, String) The placement restrictions to use for the virtual server instance. Unique Identifier of the placement group where the instance is placed. - **NOTE:** - - only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used - + ~>**Note:** + only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used - `profile` - (Required, String) The number of instances created in the instance group. - `primary_network_interfaces` (Required, List) A nested block describes the primary network interface for the template. @@ -207,23 +221,23 @@ Review the argument references that you can specify for your resource. - `security_groups` - (Optional, List) List of security groups of the subnet. - `subnet` - (Required, Forces new resource, String) The VPC subnet to assign to the interface. - `resource_group` - (Optional, Forces new resource, String) The resource group ID. -- `volume_attachments` - (Optional, List) A nested block describes the storage volume configuration for the template. +- `volume_attachments` - (Optional, Force new resource, List) A nested block describes the storage volume configuration for the template. Nested scheme for `volume_attachments`: - - `name` - (Required, String) The name of the boot volume. - - `volume` - (Required, String) The storage volume ID created in VPC. - - `delete_volume_on_instance_delete`- (Required, Bool) You can configure to delete the storage volume to delete based on instance deletion. - - `volume_prototype` - (Optional, Force new resource, List) - - Nested scheme for `volume_prototype`: - - `capacity` - (Optional, Integer) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. - - `encryption_key` - (Optional, String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for the resource. - - `iops` - (Optional, Integer) The maximum input and output operations per second (IOPS) for the volume. - - `profile` - (Optional, String) The global unique name for the volume profile to use for the volume. - - **Note** - - `volume_attachments` provides either `volume` with a storage volume ID, or `volume_prototype` to create a new volume. If you plan to use this template with instance group, provide the `volume_prototype`. Instance group does not support template with existing storage volume IDs. + - `delete_volume_on_instance_delete`- (Required, Bool) You can configure to delete the storage volume to delete based on instance deletion. + - `name` - (Required, String) The name of the boot volume. + - `volume` - (Optional, Forces new resource, String) The storage volume ID created in VPC. + - `volume_prototype` - (Optional, Forces new resource, List) + + Nested scheme for `volume_prototype`: + - `capacity` - (Required, Forces new resource, Integer) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. + - `encryption_key` - (Optional, Forces new resource, String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for the resource. + - `iops` - (Optional, Forces new resource, Integer) The maximum input and output operations per second (IOPS) for the volume. + - `profile` - (Required, Forces new resource, String) The global unique name for the volume profile to use for the volume. Allowed values areFor more information, about volume profiles, see [volume profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-block-storage-profiles) + - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) + + ~>**Note:** + `volume_attachments` provides either `volume` with a storage volume ID, or `volume_prototype` to create a new volume. If you plan to use this template with instance group, provide the `volume_prototype`. Instance group does not support template with existing storage volume IDs. - `vpc` - (Required, String) The VPC ID that the instance templates needs to be created. - `user_data` - (Optional, String) The user data provided for the instance. - `zone` - (Required, String) The name of the zone. diff --git a/website/docs/r/is_instance_volume_attachment.html.markdown b/website/docs/r/is_instance_volume_attachment.html.markdown index 7bb49588e..c6e58e6d4 100644 --- a/website/docs/r/is_instance_volume_attachment.html.markdown +++ b/website/docs/r/is_instance_volume_attachment.html.markdown @@ -10,50 +10,61 @@ description: |- # ibm_is_instance_volume_attachment Create, update, or delete a volume attachment on an existing instance. For more information, about VPC virtual server instances, see [Managing virtual server instances](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-virtual-server-instances). +~> **NOTE** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage (using capacity) ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-2" +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" total_ipv4_address_count = 16 } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } -resource "ibm_is_instance" "testacc_instance" { - name = "testvsi1" - image = "7eb4e35b-4257-56f8-d7da-326d85452591" +resource "ibm_is_instance" "example" { + name = "example-vsi" + image = ibm_is_image.example.id profile = "bc1-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id name = "eth1" } } -resource "ibm_is_instance_volume_attachment" "testacc_att1" { - instance = ibm_is_instance.testacc_instance.id +resource "ibm_is_instance_volume_attachment" "example" { + instance = ibm_is_instance.example.id - name = "test-vol-att-1" - profile = "general-purpose" - capacity = "20" + name = "example-vol-att-1" + profile = "general-purpose" + capacity = "20" delete_volume_on_attachment_delete = true - delete_volume_on_instance_delete = true - volume_name = "testvol1" + delete_volume_on_instance_delete = true + volume_name = "example-vol-1" //User can configure timeouts timeouts { @@ -67,37 +78,60 @@ resource "ibm_is_instance_volume_attachment" "testacc_att1" { ## Example usage (using existing volume) ```terraform -resource "ibm_is_volume" "testacc_vol" { - name = "testvol2" +resource "ibm_is_volume" "example" { + name = "example-vol" profile = "10iops-tier" zone = "us-south-2" } -resource "ibm_is_instance_volume_attachment" "testacc_att2" { - instance = ibm_is_instance.testacc_instance.id +resource "ibm_is_instance_volume_attachment" "example" { + instance = ibm_is_instance.example.id - name = "test-col-att-2" - volume = ibm_is_volume.testacc_vol.id + name = "example-col-att-2" + volume = ibm_is_volume.example.id // it is recommended to keep the delete_volume_on_attachment_delete as false here otherwise on deleting attachment, existing volume will also get deleted delete_volume_on_attachment_delete = false - delete_volume_on_instance_delete = false + delete_volume_on_instance_delete = false } ``` +## Example usage (creating new volume) + +```terraform +resource "ibm_is_instance_volume_attachment" "example" { + instance = ibm_is_instance.example.id + + name = "example-col-att-3" + iops = 100 + capacity = 50 + delete_volume_on_attachment_delete = true + delete_volume_on_instance_delete = true + volume_name = "example-vol-3" + + //User can configure timeouts + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } +} + +``` + ## Example usage (restoring using snapshot) ```terraform -resource "ibm_is_instance_volume_attachment" "testacc_att3" { - instance = ibm_is_instance.testacc_instance.id +resource "ibm_is_instance_volume_attachment" "example-vol-3" { + instance = ibm_is_instance.example.id - name = "test-col-att-3" + name = "test-col-att-4" profile = "general-purpose" snapshot = xxxx-xx-x-xxxxx delete_volume_on_attachment_delete = true delete_volume_on_instance_delete = true - volume_name = "testvol3" + volume_name = "example-vol-4" //User can configure timeouts timeouts { @@ -106,12 +140,11 @@ resource "ibm_is_instance_volume_attachment" "testacc_att3" { delete = "15m" } } - ``` ## Timeouts -The `ibm_is_instance_volume_attachment` resource provides the following [[Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: +The `ibm_is_instance_volume_attachment` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - **create**: The creation of the instance volume attachment is considered failed when no response is received for 10 minutes. @@ -121,51 +154,54 @@ The `ibm_is_instance_volume_attachment` resource provides the following [[Timeou ## Argument reference Review the argument references that you can specify for your resource. -- `capacity` - (Optional, Integer) The capacity of the volume in gigabytes. +- `capacity` - (Optional, Integer) The capacity of the volume in gigabytes. - **NOTE** - - The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. Accepted value is in [10-16000]. - - If unspecified, the capacity will be the source snapshot's `minimum_capacity` when `snapshot` is provided. - - Supports only expansion on update (must not be less than the current volume capacity) - - Can be updated only if volume is attached to an running virtual server instance. - - Stopped instance will be started on update of capacity of the volume. + ~> **NOTE** + **•** The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. Accepted value is in [10-16000].
**•** If unspecified, the capacity will be the source snapshot's `minimum_capacity` when `snapshot` is provided.
**•** Supports only expansion on update (must not be less than the current volume capacity)
**•** Can be updated only if volume is attached to an running virtual server instance.
**•** Stopped instance will be started on update of capacity of the volume.
- `delete_volume_on_attachment_delete` - (Optional, Bool) If set to **true**, when deleting the attachment, the volume will also be deleted. By default it is **true** - `delete_volume_on_instance_delete` - (Optional, Bool) If set to **true**, when deleting the instance, the volume will also be deleted. By default it is **false** - `encryption_key` - (Optional, String) The CRN of the Key Protect Root Key or Hyper Protect Crypto Service Root Key for this resource. If this property is not provided but the image is encrypted, the image's encryption_key will be used. Otherwise, the encryption type for the volume will be `provider_managed`. - `instance` - (Required, String) The id of the instance. - `iops` - (Optional, Integer) The bandwidth for the new volume. This value is required for `custom` storage profiles only. -**NOTE** - - `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. - - This table shows how storage size affects the `iops` ranges: - - | Size range (GB) | IOPS range | - |--------------------|----------------| - | 10 - 39 | 100 - 1000 | - | 40 - 79 | 100 - 2000 | - | 80 - 99 | 100 - 4000 | - | 100 - 499 | 100 - 6000 | - | 500 - 999 | 100 - 10000 | - | 1000 - 1999 | 100 - 20000 | - | 2000 - 3999 | 100 - 40000 | - | 4000 - 1999 | 100 - 40000 | - | 8000 - 1999 | 100 - 48000 | - | 10000 - 16000 | 100 - 48000 | + + ~> **NOTE** + **•** `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume.
+ **•** This table shows how storage size affects the `iops` ranges: + + | Size range (GB) | IOPS range | + |--------------------|----------------| + | 10 - 39 | 100 - 1000 | + | 40 - 79 | 100 - 2000 | + | 80 - 99 | 100 - 4000 | + | 100 - 499 | 100 - 6000 | + | 500 - 999 | 100 - 10000 | + | 1000 - 1999 | 100 - 20000 | + | 2000 - 3999 | 100 - 40000 | + | 4000 - 1999 | 100 - 40000 | + | 8000 - 1999 | 100 - 48000 | + | 10000 - 16000 | 100 - 48000 | +
- `name` - (Required, String) The name of the volume attachment. - `profile` - (Optional, String) The globally unique name for this volume profile. - **NOTE** - - tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other. - - Can be applied only if volume is attached to an running virtual server instance. - - Stopped instances will be started on update of volume. + ~> **NOTE** + **•** Allowed values are : [`general-purpose`, `5iops-tier`, `10iops-tier`, `custom`].
+ **•** If `iops` is not present, `general-purpose` is taken as the volume profile.
+ **•** If `iops` is present, `custom` is taken as the volume profile.
+ **•** Tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other.
+ **•** Can be updated only if volume is attached to an running virtual server instance.
+ **•** Stopped instances will be started on update of volume.
- `snapshot` - (Optional, String) The unique identifier for this snapshot from which to clone the new volume. - **NOTE** - - one of `capacity` or `snapshot` must be present for volume creation - - if `capacity` is not present or less than `minimum_capacity` of the snapshot, `minimum_cpacity` is taken as the volume capacity. + ~> **NOTE** + **•** one of `capacity` or `snapshot` must be present for volume creation.
+ **•** If `capacity` is not present or less than `minimum_capacity` of the snapshot, `minimum_capacity` is taken as the volume capacity.
- `volume` - (Optional, String) The unique identifier for the existing volume - `volume_name` - (Optional, String) The unique user-defined name for this new volume. +- `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) + ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/r/is_ipsec_policy.html.markdown b/website/docs/r/is_ipsec_policy.html.markdown index 2c2929ac0..ea3d90187 100644 --- a/website/docs/r/is_ipsec_policy.html.markdown +++ b/website/docs/r/is_ipsec_policy.html.markdown @@ -10,13 +10,23 @@ description: |- # ibm_is_ipsec_policy Create, update, or delete an ipsec policy resource. For more information, about ipsec policy, see [creating an IPsec policy](https://cloud.ibm.com/docs/vpc?topic=vpc-creating-ipsec-policy). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage In the following example, you can create a IPsec policy: ```terraform resource "ibm_is_ipsec_policy" "example" { - name = "test" + name = "example-ipsec-policy" authentication_algorithm = "md5" encryption_algorithm = "triple_des" pfs = "disabled" @@ -27,8 +37,19 @@ resource "ibm_is_ipsec_policy" "example" { ## Argument reference Review the argument references that you can specify for your resource. -- `authentication_algorithm` - (Required, String) Enter the algorithm that you want to use to authenticate `IPSec` peers. Available options are `md5`, `sha1`, or `sha256`. -- `encryption_algorithm` - (Required, String) Enter the algorithm that you want to use to encrypt data. Available options are: `triple_des`, `aes128`, or `aes256`. No. +- `authentication_algorithm` - (Required, String) Enter the algorithm that you want to use to authenticate `IPSec` peers. Available options are `md5`, `sha1`, `sha256`, `sha512`, `sha384`, `disabled`. + + ~> **Note** + The `md5` and `sha1` algorithms have been deprecated and support will be removed from November 2022 + + ~> **Note** + `authentication_algorithm` must be set to `disabled` if and only if the `encryption_algorithm` is `aes128gcm16`, `aes192gcm16`, or `aes256gcm16` + +- `encryption_algorithm` - (Required, String) Enter the algorithm that you want to use to encrypt data. Available options are: `triple_des`, `aes128`, `aes192`, `aes256`, `aes128gcm16`, `aes192gcm16`, `aes256gcm16` + + ~> **Note** + The `triple_des` algorithm has been deprecated and support will be removed from November 2022 + - `key_lifetime` - (Optional, Integer) Enter the time in seconds that your encryption key can be used before it expires. You must enter a number between 300 and 86400. If you do not specify this option, 3600 seconds is used. - `name` - (Required, String) Enter the name for your IPSec policy. - `pfs` - (Required, String) Enter the Perfect Forward Secrecy protocol that you want to use during a session. Available options are `disabled`, `group_2`, `group_5`, and `group_14`. diff --git a/website/docs/r/is_lb.html.markdown b/website/docs/r/is_lb.html.markdown index dc1e4633c..115b1e21a 100644 --- a/website/docs/r/is_lb.html.markdown +++ b/website/docs/r/is_lb.html.markdown @@ -10,14 +10,25 @@ description: |- # ibm_is_lb Create, update, or delete a VPC Load Balancer. For more information, about VPC load balancer, see [load balancers for VPC overview](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-vs-elb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage An example to create an application load balancer. ```terraform -resource "ibm_is_lb" "lb" { - name = "loadbalancer1" - subnets = ["04813493-15d6-4150-9948-6cc646cb67f2"] +resource "ibm_is_lb" "example" { + name = "example-load-balancer" + subnets = [ibm_is_subnet.example.id, ibm_is_subnet.example1.id] } ``` @@ -25,9 +36,9 @@ resource "ibm_is_lb" "lb" { An example to create a network load balancer. ```terraform -resource "ibm_is_lb" "lb" { - name = "loadbalancer1" - subnets = ["04813493-15d6-4150-9948-6cc646cb67f2"] +resource "ibm_is_lb" "example" { + name = "example-load-balancer" + subnets = [ibm_is_subnet.example.id] profile = "network-fixed" } @@ -48,9 +59,14 @@ Review the argument references that you can specify for your resource. - `profile` - (Optional, Forces new resource, String) For a Network Load Balancer, this attribute is required and should be set to `network-fixed`. For Application Load Balancer, profile is not a required attribute. - `resource_group` - (Optional, Forces new resource, String) The resource group where the load balancer to be created. - `route_mode` - (Optional, Forces new resource, Bool) Indicates whether route mode is enabled for this load balancer. - **NOTE** Currently, public load balancers are not supported with `route_mode` enabled. + + ~> **NOTE:** Currently, `route_mode` enabled is supported only by private network load balancers. - `security_groups` (Optional, List) A list of security groups to use for this load balancer. This option is supported only for application load balancers. - `subnets` - (Required, List) List of the subnets IDs to connect to the load balancer. + + ~> **NOTE:** + The subnets must be in the same `VPC`. The load balancer's `availability` will depend on the availability of the `zones` the specified subnets reside in. The load balancer must be in the `application` family for `updating subnets`. Load balancers in the `network` family allow only `one subnet` to be specified. + - `tags` (Optional, Array of Strings) A list of tags that you want to add to your load balancer. Tags can help you find the load balancer more easily later. - `type` - (Optional, Forces new resource, String) The type of the load balancer. Default value is `public`. Supported values are `public` and `private`. @@ -62,9 +78,18 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The unique identifier of the load balancer. - `operating_status` - (String) The operating status of this load balancer. - `public_ips` - (String) The public IP addresses assigned to this load balancer. -- `private_ips` - (String) The private IP addresses assigned to this load balancer. +- `private_ip` - (List) The Reserved IP address reference assigned to this load balancer. + + Nested scheme for `private_ip`: + - `address` - (String) IPv4 The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href` - (String) The URL for this reserved ip + - `reserved_ip`- (String) The unique identifier for this reserved IP. + - `name`- (String) The user-defined or system-provided name for this reserved IP + +- `private_ips` - (String) The private IP addresses (Reserved IP address reference) assigned to this load balancer. - `status` - (String) The status of the load balancer. - `security_groups_supported`- (Bool) Indicates if this load balancer supports security groups. +- `udp_supported`- (Bool) Indicates whether this load balancer supports UDP. ## Import diff --git a/website/docs/r/is_lb_listener.html.markdown b/website/docs/r/is_lb_listener.html.markdown index 923497b64..45fb7c799 100644 --- a/website/docs/r/is_lb_listener.html.markdown +++ b/website/docs/r/is_lb_listener.html.markdown @@ -10,25 +10,34 @@ description: |- Create, update, or delete a listener for a VPC load balancer. For more information, about load balancer listener, see [working with listeners](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-listeners). **Note** +- When provisioning the load balancer listener along with load balancer pool or pool member, Use explicit depends on the resources or perform the terraform apply with parallelism. For more information, about explicit dependencies, see [create resource dependencies](https://learn.hashicorp.com/terraform/getting-started/dependencies#implicit-and-explicit-dependencies). +- VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -When provisioning the load balancer listener along with load balancer pool or pool member, Use explicit depends on the resources or perform the terraform apply with parallelism. For more information, about explicit dependencies, see [create resource dependencies](https://learn.hashicorp.com/terraform/getting-started/dependencies#implicit-and-explicit-dependencies). + **provider.tf** + ```terraform + provider "ibm" { + region = "eu-gb" + } + ``` + ## Example usage An example, to create a load balancer listener along with the pool and pool member. ```terraform -resource "ibm_is_lb_listener" "testacc_lb_listener" { - lb = "8898e627-f61f-4ac8-be85-9db9d8bfd345" - port = "9080" - protocol = "http" - https_redirect_listener="r134-8c58bfe1-db02-4790-95ce-fe5bb892d78f" - https_redirect_status_code=301 - https_redirect_uri="/example?doc=get" + +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id + port = "9080" + protocol = "http" + https_redirect_listener = ibm_is_lb_listener.example.listener_id + https_redirect_status_code = 301 + https_redirect_uri = "/example?doc=get" } -resource "ibm_is_lb_pool" "webapptier-lb-pool" { - lb = "8898e627-f61f-4ac8-be85-9db9d8bfd345" - name = "a-webapptier-lb-pool" +resource "ibm_is_lb_pool" "example" { + lb = ibm_is_lb.example.id + name = "example-lb-pool" protocol = "http" algorithm = "round_robin" health_delay = "5" @@ -36,41 +45,41 @@ resource "ibm_is_lb_pool" "webapptier-lb-pool" { health_timeout = "2" health_type = "http" health_monitor_url = "/" - depends_on = [ibm_is_lb_listener.testacc_lb_listener] + depends_on = [ibm_is_lb_listener.example] } -resource "ibm_is_lb_pool_member" "webapptier-lb-pool-member-zone1" { +resource "ibm_is_lb_pool_member" "example" { count = "2" - lb = "8898e627-f61f-4ac8-be85-9db9d8bfd345" - pool = element(split("/", ibm_is_lb_pool.webapptier-lb-pool.id), 1) + lb = ibm_is_lb.example.id + pool = element(split("/", ibm_is_lb_pool.example.id), 1) port = "80" target_address = "192.168.0.1" - depends_on = [ibm_is_lb_listener.testacc_lb_listener] + depends_on = [ibm_is_lb_listener.example] } ``` ### Sample to create a load balancer listener policy for a `https_redirect` action. ```terraform -resource "ibm_is_lb" "lb2"{ - name = "mylb" - subnets = ["35860fed-c911-4936-8c94-f0d8577dbe5b"] +resource "ibm_is_lb" "example2" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_lb_listener" "lb_listener1"{ - lb = ibm_is_lb.lb2.id - port = "9086" - protocol = "https" - certificate_instance="crn:v1:bluemix:public:cloudcerts:us-south:a2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" +resource "ibm_is_lb_listener" "example1" { + lb = ibm_is_lb.example2.id + port = "9086" + protocol = "https" + certificate_instance = "crn:v1:bluemix:public:cloudcerts:us-south:a2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" } -resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.lb2.id - port = "9087" - protocol = "http" - https_redirect_listener = ibm_is_lb_listener.lb_listener1.listener_id +resource "ibm_is_lb_listener" "example2" { + lb = ibm_is_lb.example2.id + port = "9087" + protocol = "http" + https_redirect_listener = ibm_is_lb_listener.example1.listener_id https_redirect_status_code = 301 - https_redirect_uri = "/example?doc=geta" + https_redirect_uri = "/example?doc=geta" } ``` @@ -78,28 +87,64 @@ resource "ibm_is_lb_listener" "lb_listener2"{ ```terraform -resource "ibm_is_vpc" "vpc" { - name = "test-vpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.68.0/24" +} + +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] + profile = "network-fixed" + type = "private" + route_mode = "true" +} + +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id + protocol = "tcp" + default_pool = ibm_is_lb_pool.example.id +} +``` + +### Sample to create a public load balancer listener with range of ports. + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet" { - name = "test-subnet" - vpc = "${ibm_is_vpc.vpc.id}" - zone = "us-south-2" +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" ipv4_cidr_block = "10.240.68.0/24" } -resource "ibm_is_lb" "nlb" { - name = "test-nlb" - subnets = [ibm_is_subnet.subnet.id] - profile = "network-fixed" - type = "private" - route_mode = "true" +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] + profile = "network-fixed" + type = "public" } -resource "ibm_is_lb_listener" "nlbHttpListener1" { - lb = ibm_is_lb.nlb.id - protocol = "tcp" +resource "ibm_is_lb_listener" "example1" { + lb = ibm_is_lb.example.id + protocol = "tcp" + port_min = 100 + port_max = 200 +} +resource "ibm_is_lb_listener" "example2" { + lb = ibm_is_lb.example.id + protocol = "tcp" + port_min = 300 + port_max = 400 } ``` @@ -116,15 +161,35 @@ Review the argument references that you can specify for your resource. - `accept_proxy_protocol`- (Optional, Bool) If set to **true**, listener forwards proxy protocol information that are supported by load balancers in the application family. Default value is **false**. - `lb` - (Required, Forces new resource, String) The load balancer unique identifier. + - `port`- (Optional, Integer) The listener port number. Valid range `1` to `65535`. - **NOTE**: - - Private network load balancers with `route_mode` enabled don't support `port`, they support `port` range from `port_min`(1) - `port_max`(65535). - - Only accepted value of `port` for `route_mode` enabled private network load balancer is `1`. Any other value will show change or update-in-place and returns an error. + ~> **NOTE** + Private network load balancers with `route_mode` enabled don't support `port`, they support only one port range from `port_min (1)` - `port_max (65535)`. Only accepted value of `port` for `route_mode` enabled private network load balancer is `1`. Any other value will show change or update-in-place and returns an error. + + ~> **NOTE** + Either use `port` or (`port_min`-`port_max`) for public network load balancers +- `port_min`- (Optional, Integer) The inclusive lower bound of the range of ports used by this listener. + + ~> **NOTE** + Only load balancers in the `network` family support more than one port per listener. When route mode is enabled, only a value of `1` is supported for `port_min`. -- `protocol` - (Required, String) The listener protocol. Enumeration type are `http`, `tcp`, and `https`. Network load balancer supports only `tcp` protocol. +- `port_max`- (Optional, Integer) The inclusive upper bound of the range of ports used by this listener. + + ~> **NOTE** + Only load balancers in the `network` family support more than one port per listener. When `route mode` is enabled, only a value of `65535` is supported for port_max. + +- `protocol` - (Required, String) The listener protocol. Enumeration type are `http`, `tcp`, `https` and `udp`. Network load balancer supports only `tcp` and `udp` protocol. - `default_pool` - (Optional, String) The load balancer pool unique identifier. + ~> **NOTE** + - The specified pool must - + - Belong to this load balancer + - Have the same protocol as this listener, or have a compatible protocol. At present, the compatible protocols are http and https. + - Not already be the default_pool for another listener - `certificate_instance` - (Optional, String) The CRN of the certificate instance, it is applicable(mandatory) only to https protocol. + +-> **NOTE:** Certificate Manager is deprecated. Migrate your load balancer certificates from Certificate Manager to Secrets Manager. + - `connection_limit` - (Optional, Integer) The connection limit of the listener. Valid range is **1 to 15000**. Network load balancer do not support `connection_limit` argument. - `https_redirect_listener` - (Optional, String) ID of the listener that will be set as http redirect target. - `https_redirect_status_code` - (Optional, Integer) The HTTP status code to be returned in the redirect response, one of [301, 302, 303, 307, 308]. @@ -134,16 +199,6 @@ Review the argument references that you can specify for your resource. In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The unique identifier of the load balancer listener. -- `port_min`- (Integer) The inclusive lower bound of the range of ports used by this listener. - - **NOTE** - - Only load balancers in the `network` family support more than one port per listener. - - Currently, only load balancers operating with route mode enabled support different values for `port_min` and port_max. When route mode is enabled, only a value of `1` is supported for `port_min`. -- `port_max`- (Integer) The inclusive upper bound of the range of ports used by this listener. - - **NOTE** - - Only load balancers in the `network` family support more than one port per listener. - - Currently, only load balancers operating with `route_mode` enabled support different values for `port_min` and `port_max`. When `route mode` is enabled, only a value of `65535` is supported for port_max. - `status` - (String) The status of load balancer listener. ## Import diff --git a/website/docs/r/is_lb_listener_policy.html.markdown b/website/docs/r/is_lb_listener_policy.html.markdown index dc1a5cd44..220d6a03c 100644 --- a/website/docs/r/is_lb_listener_policy.html.markdown +++ b/website/docs/r/is_lb_listener_policy.html.markdown @@ -9,34 +9,45 @@ description: |- # ibm_is_lb_listener_policy Create, update, or delete a load balancer listener policy. For more information, about VPC load balance listener policy, see [monitoring application Load Balancer for VPC metrics](https://cloud.ibm.com/docs/vpc?topic=vpc-monitoring-metrics-alb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ### Sample to create a load balancer listener policy for a `redirect` action. ```terraform -resource "ibm_is_lb" "lb2"{ - name = "mylb" - subnets = ["35860fed-c911-4936-8c94-f0d8577dbe5b"] +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.lb2.id +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id port = "9086" protocol = "http" } -resource "ibm_is_lb_listener_policy" "lb_listener_policy" { - lb = ibm_is_lb.lb2.id - listener = ibm_is_lb_listener.lb_listener2.listener_id - action = "redirect" - priority = 2 - name = "mylistener8" +resource "ibm_is_lb_listener_policy" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "redirect" + priority = 2 + name = "example-listener-policy" target_http_status_code = 302 - target_url = "https://www.redirect.com" - rules{ - condition = "contains" - type = "header" - field = "1" - value = "2" + target_url = "https://www.redirect.com" + rules { + condition = "contains" + type = "header" + field = "1" + value = "2" } } ``` @@ -44,30 +55,31 @@ resource "ibm_is_lb_listener_policy" "lb_listener_policy" { ### Sample to create a load balancer listener policy for a `https_redirect` action. ```terraform -resource "ibm_is_lb" "lb2"{ - name = "mylb" - subnets = ["35860fed-c911-4936-8c94-f0d8577dbe5b"] +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.lb2.id - port = "9086" - protocol = "https" - certificate_instance="crn:v1:staging:public:cloudcerts:us-south:a2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id + port = "9086" + protocol = "https" + certificate_instance = "crn:v1:staging:public:cloudcerts:us-south:a2d1bace7b46e4815a81e52c6ffeba5cf:af925157-b125-4db2-b642-adacb8b9c7f5:certificate:c81627a1bf6f766379cc4b98fd2a44ed" } -resource "ibm_is_lb_listener_policy" "lb_listener_policy" { - lb = ibm_is_lb.lb2.id - action = "https_redirect" - priority = 2 - name = "mylistener8" - taget_https_redirect_listener=ibm_is_lb_listener.lb_listener2.listener_id - target_https_redirect_status_code=301 - target_https_redirect_uri="/example?doc=geta" - rules{ - condition = "contains" - type = "header" - field = "1" - value = "2" +resource "ibm_is_lb_listener_policy" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "https_redirect" + priority = 2 + name = "example-listener" + target_https_redirect_listener = ibm_is_lb_listener.example.listener_id + target_https_redirect_status_code = 301 + target_https_redirect_uri = "/example?doc=geta" + rules { + condition = "contains" + type = "header" + field = "1" + value = "2" } } ``` @@ -76,28 +88,40 @@ resource "ibm_is_lb_listener_policy" "lb_listener_policy" { ```terraform -resource "ibm_is_lb" "lb2"{ - name = "mylb" - subnets = ["35860fed-c911-4936-8c94-f0d8577dbe5b"] +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.lb2.id +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id port = "9086" protocol = "http" } -resource "ibm_is_lb_listener_policy" "lb_listener_policy" { - lb = ibm_is_lb.lb2.id - listener = ibm_is_lb_listener.lb_listener2.listener_id - action = "forward" - priority = 2 - name = "mylistener8" - target_id = "r006-beafdff0-4fe0-4db4-8f0c-b0b4ad828712" - rules{ - condition = "contains" - type = "header" - field = "1" - value = "2" + +resource "ibm_is_lb_pool" "example" { + name = "example-lb-pool" + lb = ibm_is_lb.example.id + algorithm = "round_robin" + protocol = "http" + health_delay = 60 + health_retries = 5 + health_timeout = 30 + health_type = "http" +} + +resource "ibm_is_lb_listener_policy" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "forward" + priority = 2 + name = "example-listener" + target_id = ibm_is_lb_pool.example.pool_id + rules { + condition = "contains" + type = "header" + field = "1" + value = "2" } } ``` @@ -131,7 +155,7 @@ Review the argument references that you can specify for your resource. - `target_https_redirect_status_code` - (Optional, Integer) When `action` is set to **https_redirect**, specify the HTTP status code to be returned in the redirect response. Supported values are `301`, `302`, `303`, `307`, `308`. - `target_https_redirect_uri` - (Optional, String) When `action` is set to **https_redirect**, specify the target URI where traffic will be redirected. -**Note** +~> **Note:** When action is `forward`, `target_id` should specify which pool the load balancer forwards the traffic to. When action is `redirect`, `target_url` should specify the `url` and `target_http_status_code` to specify the code used in the redirect response. diff --git a/website/docs/r/is_lb_listener_policy_rule.html.markdown b/website/docs/r/is_lb_listener_policy_rule.html.markdown index 1b5a1ced5..dd94f25a3 100644 --- a/website/docs/r/is_lb_listener_policy_rule.html.markdown +++ b/website/docs/r/is_lb_listener_policy_rule.html.markdown @@ -10,40 +10,51 @@ description: |- # ibm_is_lb_listener_policy Create, update, or delete a VPC load balancer listener policy rule. For more information, about load balancer listener policy and rules, see [layer 7 load balancing policies and rules](https://cloud.ibm.com/docs/vpc?topic=vpc-layer-7-load-balancing). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage Sample to create a load balancer listener policy rule, along with `lb` and `lb listener`. ```terraform -resource "ibm_is_lb" "lb2"{ - name = "mylb" - subnets = ["35860fed-c911-4936-8c94-f0d8577dbe5b"] +resource "ibm_is_lb" "example" { + name = "example-lb" + subnets = [ibm_is_subnet.example.id] } -resource "ibm_is_lb_listener" "lb_listener2"{ - lb = ibm_is_lb.lb2.id +resource "ibm_is_lb_listener" "example" { + lb = ibm_is_lb.example.id port = "9086" protocol = "http" } -resource "ibm_is_lb_listener_policy" "lb_listener_policy" { - lb = ibm_is_lb.lb2.id - listener = ibm_is_lb_listener.lb_listener2.listener_id - action = "redirect" - priority = 2 - name = "mylistener8" +resource "ibm_is_lb_listener_policy" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "redirect" + priority = 2 + name = "example-listener" target_http_status_code = 302 - target_url = "https://www.redirect.com" - rules{ - condition = "contains" - type = "header" - field = "1" - value = "2" + target_url = "https://www.redirect.com" + rules { + condition = "contains" + type = "header" + field = "1" + value = "2" } } -resource "ibm_is_lb_listener_policy_rule" "lb_listener_policy_rule" { - lb = ibm_is_lb.lb2.id - listener = ibm_is_lb_listener.lb_listener2.listener_id - policy = ibm_is_lb_listener_policy.lb_listener_policy.policy_id +resource "ibm_is_lb_listener_policy_rule" "example" { + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + policy = ibm_is_lb_listener_policy.example.policy_id condition = "equals" type = "header" field = "MY-APP-HEADER" diff --git a/website/docs/r/is_lb_pool.html.markdown b/website/docs/r/is_lb_pool.html.markdown index 9af694e4a..d8da0d915 100644 --- a/website/docs/r/is_lb_pool.html.markdown +++ b/website/docs/r/is_lb_pool.html.markdown @@ -10,14 +10,25 @@ description: |- # ibm_is_lb_pool Create, update, or delete a VPC load balancer pool. For more information, about load balancer pool, see [working with pool](https://cloud.ibm.com/docs/vpc?topic=vpc-nlb-pools). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ### Sample to create a load balancer pool. ```terraform -resource "ibm_is_lb_pool" "testacc_pool" { - name = "test-pool" - lb = "addfd-gg4r4-12345" +resource "ibm_is_lb_pool" "example" { + name = "example-pool" + lb = ibm_is_lb.example.id algorithm = "round_robin" protocol = "http" health_delay = 60 @@ -26,15 +37,14 @@ resource "ibm_is_lb_pool" "testacc_pool" { health_type = "http" proxy_protocol = "v1" } - ``` ### Sample to create a load balancer pool with `https` protocol. ```terraform -resource "ibm_is_lb_pool" "testacc_pool" { - name = "test-pool" - lb = "addfd-gg4r4-12345" +resource "ibm_is_lb_pool" "example" { + name = "example-pool" + lb = ibm_is_lb.example.id algorithm = "round_robin" protocol = "https" health_delay = 60 @@ -46,12 +56,12 @@ resource "ibm_is_lb_pool" "testacc_pool" { ``` -In the following example, you can create a load balancer pool with `app_cookie` session persistence: +//In the following example, you can create a load balancer pool with `app_cookie` session persistence: -```hcl -resource "ibm_is_lb_pool" "testacc_pool" { - name = "test-pool" - lb = "addfd-gg4r4-12345" +```terraform +resource "ibm_is_lb_pool" "example" { + name = "example-pool" + lb = ibm_is_lb.example.id algorithm = "round_robin" protocol = "https" health_delay = 60 @@ -65,12 +75,12 @@ resource "ibm_is_lb_pool" "testacc_pool" { ``` -In the following example, you can create a load balancer pool with `http_cookie` session persistence: +//In the following example, you can create a load balancer pool with `http_cookie` session persistence: -```hcl -resource "ibm_is_lb_pool" "testacc_pool" { - name = "test-pool" - lb = "addfd-gg4r4-12345" +```terraform +resource "ibm_is_lb_pool" "example" { + name = "example-pool" + lb = ibm_is_lb.example.id algorithm = "round_robin" protocol = "https" health_delay = 60 @@ -83,12 +93,12 @@ resource "ibm_is_lb_pool" "testacc_pool" { ``` -In the following example, you can create a load balancer pool with `source_ip` session persistence: +//In the following example, you can create a load balancer pool with `source_ip` session persistence: -```hcl -resource "ibm_is_lb_pool" "testacc_pool" { - name = "test-pool" - lb = "addfd-gg4r4-12345" +```terraform +resource "ibm_is_lb_pool" "example" { + name = "example-pool" + lb = ibm_is_lb.example.id algorithm = "round_robin" protocol = "https" health_delay = 60 @@ -120,7 +130,7 @@ Review the argument references that you can specify for your resource. - `health_monitor_port` - (Optional, Integer) The health check port number. - `lb` - (Required, Forces new resource, String) The load balancer unique identifier. - `name` - (Required, String) The name of the pool. -- `protocol` - (Required, String) The pool protocol. Enumeration type: `http`, `https`, `tcp` are supported. +- `protocol` - (Required, String) The pool protocol. Enumeration type: `http`, `https`, `tcp`, `udp` are supported. - `proxy_protocol` - (Optional, String) The proxy protocol setting for the pool that is supported by the load balancers in the application family. Valid values are `disabled`, `v1`, and `v2`. Default value is `disabled`. - `session_persistence_type` - (Optional, String) The session persistence type, Enumeration type: source_ip, app_cookie, http_cookie - `session_persistence_app_cookie_name` - (Optional, String) Session persistence app cookie name. This is applicable only to app_cookie type. diff --git a/website/docs/r/is_lb_pool_member.html.markdown b/website/docs/r/is_lb_pool_member.html.markdown index 4d585d4e7..5770443b0 100644 --- a/website/docs/r/is_lb_pool_member.html.markdown +++ b/website/docs/r/is_lb_pool_member.html.markdown @@ -8,35 +8,43 @@ description: |- --- # ibm_is_lb_pool_member -Create, update, or delete a pool member for a VPC load balancer. +Create, update, or delete a pool member for a VPC load balancer. For more information, about load balancer listener pool member, see [Creating managed pools and instance groups](https://cloud.ibm.com/docs/vpc?topic=vpc-lbaas-integration-with-instance-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ### Sample to create a load balancer pool member for application load balancer. ```terraform -resource "ibm_is_lb_pool_member" "testacc_lb_mem" { - lb = "daac2b08-fe8a-443b-9b06-1cef79922dce" - pool = "f087d3bd-3da8-452d-9ce4-c1010c9fec04" +resource "ibm_is_lb_pool_member" "example" { + lb = ibm_is_lb.example.id + pool = element(split("/", ibm_is_lb_pool.example.id), 1) port = 8080 target_address = "127.0.0.1" weight = 60 } - ``` ### Sample to create a load balancer pool member for network load balancer. ```terraform -resource "ibm_is_lb_pool_member" "testacc_lb_mem" { - lb = "daac2b08-fe8a-443b-9b06-1cef79922dce" - pool = "f087d3bd-3da8-452d-9ce4-c1010c9fec04" - port = 8080 - target_id = "54ad563a-0261-11e9-8317-bec54e704988" - weight = 60 +resource "ibm_is_lb_pool_member" "example" { + lb = ibm_is_lb.example.id + pool = element(split("/", ibm_is_lb_pool.example.id), 1) + port = 8080 + target_id = ibm_is_instance.example.id + weight = 60 } - ``` ## Timeouts @@ -55,7 +63,9 @@ Review the argument references that you can specify for your resource. - `port`- (Required, Integer) The port number of the application running in the server member. - `target_address` - (Required, String) The IP address of the pool member. - `target_id` - (Required, String) The unique identifier for the virtual server instance pool member. Required for network load balancer. -- `weight` - (Optional, Integer) Weight of the server member. This option takes effect only when the load-balancing algorithm of its belonging pool is `weighted_round_robin`, Minimum allowed weight is `0` and Maximum allowed weight is `100`. + +- `weight` - (Optional, Integer) Weight of the server member. This option takes effect only when the load-balancing algorithm of its belonging pool is `weighted_round_robin`, Minimum allowed weight is `0` and Maximum allowed weight is `100`. Default: 50, Weight of the server member. Applicable only if the pool algorithm is weighted_round_robin. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. diff --git a/website/docs/r/is_network_acl.html.markdown b/website/docs/r/is_network_acl.html.markdown index bd0854c60..7e800d230 100644 --- a/website/docs/r/is_network_acl.html.markdown +++ b/website/docs/r/is_network_acl.html.markdown @@ -10,16 +10,27 @@ description: |- # ibm_is_network_acl Create, update, or delete a network access control list (ACL). For more information, about network ACL, see [setting up network ACLs](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "vpctest" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_network_acl" "isExampleACL" { - name = "is-example-acl" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_network_acl" "example" { + name = "example-acl" + vpc = ibm_is_vpc.example.id rules { name = "outbound" action = "allow" diff --git a/website/docs/r/is_network_acl_rule.html.markdown b/website/docs/r/is_network_acl_rule.html.markdown index 48ef72500..d88e3b2d5 100644 --- a/website/docs/r/is_network_acl_rule.html.markdown +++ b/website/docs/r/is_network_acl_rule.html.markdown @@ -9,60 +9,70 @@ description: |- # ibm_is_network_acl_rule -Provides a network ACL rule resource with `icmp`, `tcp`, `udp` or `all` protocol. This allows Network ACL rule to be created, updated, and cancelled on an existing network ACL. For more information, about managing IBM Cloud Network ACL , see [about network acl](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +Provides a network ACL rule resource with `icmp`, `tcp`, `udp` or `all` protocol. This allows Network ACL rule to create, update, and delete an existing network ACL. For more information, about managing IBM Cloud Network ACL , see [about network acl](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage (all) ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "vpctest" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_network_acl" "isExampleACL" { - name = "is-example-acl" - vpc = ibm_is_vpc.testacc_vpc.id -} -resource "ibm_is_network_acl_rule" "isExampleACLRule1" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" +resource "ibm_is_network_acl" "example" { + name = "example-acl" + vpc = ibm_is_vpc.example.id +} +resource "ibm_is_network_acl_rule" "example" { + network_acl = ibm_is_network_acl.example.id + name = "outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" } -resource "ibm_is_network_acl_rule" "isExampleACLRule2" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "inbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" +resource "ibm_is_network_acl_rule" "example1" { + network_acl = ibm_is_network_acl.example.id + name = "inbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" } ``` - ## Example usage (icmp) ```terraform -resource "ibm_is_network_acl_rule" "isExampleACLRule" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" +resource "ibm_is_network_acl_rule" "example" { + network_acl = ibm_is_network_acl.example.id + name = "outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" icmp { code = 1 type = 1 } } -resource "ibm_is_network_acl_rule" "isExampleACLRule" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "inbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" +resource "ibm_is_network_acl_rule" "example1" { + network_acl = ibm_is_network_acl.example.id + name = "inbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" icmp { code = 1 type = 1 @@ -71,18 +81,16 @@ resource "ibm_is_network_acl_rule" "isExampleACLRule" { ``` - - ## Example usage (tcp/udp) ```terraform -resource "ibm_is_network_acl_rule" "isExampleACL" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" +resource "ibm_is_network_acl_rule" "example" { + network_acl = ibm_is_network_acl.example.id + name = "outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" tcp { port_max = 65535 port_min = 1 @@ -90,13 +98,13 @@ resource "ibm_is_network_acl_rule" "isExampleACL" { source_port_min = 22 } } -resource "ibm_is_network_acl_rule" "isExampleACL" { - network_acl = ibm_is_network_acl.isExampleACL.id - name = "inbound" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" +resource "ibm_is_network_acl_rule" "example1" { + network_acl = ibm_is_network_acl.example.id + name = "inbound" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" tcp { port_max = 65535 port_min = 1 @@ -106,42 +114,39 @@ resource "ibm_is_network_acl_rule" "isExampleACL" { } ``` - ## Argument reference - Review the argument references that you can specify for your resource. -- `action` - (Required, String) Whether to allow or deny matching traffic. -- `before` - (Optional, String) The unique identifier of the rule that this rule is immediately before. If absent, this is the last rule. If omitted, this rule will be inserted after all existing rules. +- `action` - (Required, String) Whether to **allow** or **deny** matching traffic. +- `before` - (Optional, String) The unique identifier of the rule that this rule is immediately before. If **absent**, this is the last rule. If **omitted**, this rule will be inserted after all existing rules. - `destination` - (Required, String) The destination IP address or CIDR block. -- `direction` - (Required, String) Whether the traffic to be matched is inbound or outbound. -- `icmp` - (Optional, List) The protocol ICMP +- `direction` - (Required, String) Whether the traffic to be matched is **inbound** or **outbound**. +- `icmp` - (Optional, List) The protocol ICMP. - Nested scheme for `icmp`: - - `code` - (Optional, Integer) The ICMP traffic code to allow. Valid values from 0 to 255. If unspecified, all codes are allowed. This can only be specified if type is also specified. - - `type` - (Optional, Integer) The ICMP traffic type to allow. Valid values from 0 to 254. If unspecified, all types are allowed by this rule. + Nested scheme for `icmp`: + - `code` - (Optional, Integer) The ICMP traffic code to allow. Valid values from 0 to 255. If unspecified, all codes are allowed. This can only be specified if type is also specified. + - `type` - (Optional, Integer) The ICMP traffic type to allow. Valid values from 0 to 254. If unspecified, all types are allowed by this rule. - `network_acl` - (Required, String) The ID of the network ACL. - `name` - (Required, String) The user-defined name for this rule. - `source` - (Required, String) The source IP address or CIDR block. - `tcp` - (Optional, List) TCP protocol. - Nested scheme for `tcp`: - - `port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - - `source_port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `source_port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + Nested scheme for `tcp`: + - `port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + - `source_port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `source_port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - `udp` - (Optional, List) UDP protocol - Nested scheme for `udp`: - - `port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - - `source_port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. - - `source_port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. - -**NOTE**: Only one type of protocol out of **icmp**, **tcp**, or **udp** can be used to create a new rule. If none is provided, **all** is selected. + Nested scheme for `udp`: + - `port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. + - `source_port_max` - (Optional, Integer) The highest port in the range of ports to be matched; if unspecified, **65535** is used. + - `source_port_min` - (Optional, Integer) The lowest port in the range of ports to be matched; if unspecified, **1** is used. -## Attribute Reference +~> **NOTE:**: Only one type of protocol out of **icmp**, **tcp**, or **udp** can be used to create a new rule. If none is provided, **all** is selected. +## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The ID of the network ACL rule. The ID is composed of `\/\.` @@ -151,7 +156,6 @@ In addition to all argument reference list, you can access the following attribu ## Import - The `ibm_is_network_acl_rule` can be imported using ID `\/\` **Example** diff --git a/website/docs/r/is_placement_group.html.markdown b/website/docs/r/is_placement_group.html.markdown index df74476d2..e52bf0e30 100644 --- a/website/docs/r/is_placement_group.html.markdown +++ b/website/docs/r/is_placement_group.html.markdown @@ -6,24 +6,35 @@ description: |- Manages PlacementGroup. --- -# ibm\_is_placement_group +# ibm_is_placement_group -Provides a resource for PlacementGroup. This allows PlacementGroup to be created, updated and deleted. +Create, update, or delete a placement group. For more information, about placement group, see [managing placement groups](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-placement-group&interface=ui). -## Example Usage +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -```hcl -resource "ibm_is_placement_group" "is_placement_group" { +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_placement_group" "example" { strategy = "host_spread" - name = "my-placement-group" + name = "example-placement-group" } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +Review the argument references that you can specify for your resource. -- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the placement group. **Note** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag). +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the placement group. ~> **Note:** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag). - `name` - (Optional, string) The unique user-defined name for this placement group. If unspecified, the name will be a hyphenated list of randomly-selected words. - `resource_group` - (Optional, string, Forces new resource) The unique identifier of the resource group to use. If unspecified, the account's - `strategy` - (Required, string, Forces new resource) The strategy for this placement group- `host_spread`: place on different compute hosts- `power_spread`: place on compute hosts that use different power sources. The enumerated values for this property may expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the placement group on which the unexpected strategy was encountered. @@ -31,9 +42,9 @@ The following arguments are supported: - `tags` - (Optional, List of Strings) The user tags to attach to the placement group. -## Attribute Reference +## Attribute reference -The following attributes are exported: +In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - The unique identifier of the PlacementGroup. - `created_at` - The date and time that the placement group was created. @@ -44,7 +55,9 @@ The following attributes are exported: ## Import -ibm_is_placement_group can be imported using ID, eg +The `ibm_is_placement_group` can be imported by using ID. + +**Example** ``` $ terraform import ibm_is_placement_group.example d7bec597-4726-451f-8a63-e62e6f19c32c diff --git a/website/docs/r/is_public_gateway.html.markdown b/website/docs/r/is_public_gateway.html.markdown index 52d38f420..ea991fc53 100644 --- a/website/docs/r/is_public_gateway.html.markdown +++ b/website/docs/r/is_public_gateway.html.markdown @@ -8,19 +8,30 @@ description: |- --- # ibm_is_public_gateway -Create, update, or delete a public gateway for a VPC subnet. Public gateways enable a VPC subnet and all the instances that are connected to the subnet to connect to the internet. For more information, see [use a Public Gateway for external connectivity of a subnet](hhttps://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc#public-gateway-for-external-connectivity). +Create, update, or delete a public gateway for a VPC subnet. Public gateways enable a VPC subnet and all the instances that are connected to the subnet to connect to the internet. For more information, see [use a Public Gateway for external connectivity of a subnet](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc#public-gateway-for-external-connectivity). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage The following example shows how you can create a public gateway for all the subnets that are located in a specific zone. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_public_gateway" "testacc_gateway" { - name = "test-gateway" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_public_gateway" "example" { + name = "example-gateway" + vpc = ibm_is_vpc.example.id zone = "us-south-1" //User can configure timeouts diff --git a/website/docs/r/is_security_group.html.markdown b/website/docs/r/is_security_group.html.markdown index 93244d24a..c2cc35e7e 100644 --- a/website/docs/r/is_security_group.html.markdown +++ b/website/docs/r/is_security_group.html.markdown @@ -10,17 +10,27 @@ description: |- # ibm_is_security_group Create, delete, and update a security group. Provides a networking security group resource that controls access to the public and private interfaces of a virtual server instance. To create rules for the security group, use the `is_security_group_rule` resource. For more information, about security group, see API Docs(https://cloud.ibm.com/docs/vpc?topic=vpc-using-security-groups). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_security_group" "testacc_security_group" { - name = "test" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_security_group" "example" { + name = "example-security-group" + vpc = ibm_is_vpc.example.id } ``` diff --git a/website/docs/r/is_security_group_network_interface_attachment.html.markdown b/website/docs/r/is_security_group_network_interface_attachment.html.markdown index 1388e85f4..8dd276023 100644 --- a/website/docs/r/is_security_group_network_interface_attachment.html.markdown +++ b/website/docs/r/is_security_group_network_interface_attachment.html.markdown @@ -10,21 +10,33 @@ description: |- # ibm_is_security_group_network_interface_attachment Create, update, or delete a security group network interface attachment. For more information, about security group network interface attachment, see [attaching and detaching security groups](https://cloud.ibm.com/docs/vpc?topic=vpc-alb-integration-with-security-groups#attaching-detaching-sg-to-alb). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_security_group_network_interface_attachment" "sgnic" { - security_group = "2d364f0a-a870-42c3-a554-000001352417" - network_interface = "6d6128aa-badc-45c4-bb0e-7c2c1c47be55" +resource "ibm_is_security_group_network_interface_attachment" "example" { + security_group = ibm_is_security_group.example.id + network_interface = ibm_is_instance.example.primary_network_interface[0].id } ``` -**Note** This resource is deprecated. Use `ibm_is_security_group_target` to attach a network interface to a security group +~> **Note:** This resource is deprecated. Use `ibm_is_security_group_target` to attach a network interface to a security group ## Argument reference Review the argument references that you can specify for your resource. -- `security_group` - (Required, Forces new resource, String) The security group ID. -- `network_interface` - (Required, Forces new resource, String) The network interface ID. +- `security_group` - (Required, Forces new resource, String) The `.id` attribute of a `ibm_is_security_group` resource or data. +- `network_interface` - (Required, Forces new resource, String) The network interface `id` that is available in the `ibm_is_instance.primary_network_interface[0].id`. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -52,19 +64,17 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name of this security group. - `type` - (String) The type of this network interface as it relates to a instance. - - ## Import The `ibm_is_security_group_network_interface_attachment` resource can be imported by using security group ID and network interface ID. **Syntax** -``` +```sh $ terraform import ibm_is_security_group_network_interface_attachment.example / ``` **Example** -``` +```sh $ terraform import ibm_is_security_group_network_interface_attachment.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb ``` diff --git a/website/docs/r/is_security_group_rule.html.markdown b/website/docs/r/is_security_group_rule.html.markdown index 3d2a0ed95..72e256a70 100644 --- a/website/docs/r/is_security_group_rule.html.markdown +++ b/website/docs/r/is_security_group_rule.html.markdown @@ -10,28 +10,38 @@ description: |- # ibm_is_security_group_rule Create, update, or delete a security group rule. When you want to create a security group and security group rule for a virtual server instance in your VPC, you must create these resources in a specific order to avoid errors during the creation of your virtual server instance. For more information, about security group rule, see [security in your VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-security-in-your-vpc). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage -In the following example, you create a different type of protocol rules `ALL`, `ICMP`, `UDP` and `TCP`. +In the following example, you create a different type of protocol rules `ALL`, `ICMP`, `UDP`, `TCP` and `ANY`. ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_security_group" "testacc_security_group" { - name = "test" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_security_group" "example" { + name = "example-security-group" + vpc = ibm_is_vpc.example.id } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_all" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_icmp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example1" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" icmp { @@ -40,8 +50,8 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_icmp" { } } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_udp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example2" { + group = ibm_is_security_group.example.id direction = "inbound" remote = "127.0.0.1" udp { @@ -50,8 +60,8 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_udp" { } } -resource "ibm_is_security_group_rule" "testacc_security_group_rule_tcp" { - group = ibm_is_security_group.testacc_security_group.id +resource "ibm_is_security_group_rule" "example3" { + group = ibm_is_security_group.example.id direction = "egress" remote = "127.0.0.1" tcp { @@ -59,6 +69,31 @@ resource "ibm_is_security_group_rule" "testacc_security_group_rule_tcp" { port_max = 8080 } } + +resource "ibm_is_security_group_rule" "example_security_group_rule_icmp_any" { + group = ibm_is_security_group.example_security_group.id + direction = "inbound" + remote = "127.0.0.1" + icmp { + } +} + +resource "ibm_is_security_group_rule" "example_security_group_rule_udp_any" { + group = ibm_is_security_group.example_security_group.id + direction = "inbound" + remote = "127.0.0.1" + udp { + } +} + +resource "ibm_is_security_group_rule" "example_security_group_rule_tcp_any" { + group = ibm_is_security_group.example_security_group.id + direction = "inbound" + remote = "127.0.0.1" + tcp { + } +} + ``` ## Argument reference @@ -84,7 +119,7 @@ Review the argument references that you can specify for your resource. - `port_min`- (Required, Integer) The UDP port range that includes minimum bound. Valid values are from 1 to 65535. - `port_max`- (Required, Integer) The UDP port range that includes maximum bound. Valid values are from 1 to 65535. -**Note** +~> **Note:** If any of the `icmp` , `tcp`, or `udp` is not specified it creates a rule with protocol `ALL`. diff --git a/website/docs/r/is_security_group_target.html.markdown b/website/docs/r/is_security_group_target.html.markdown index 80fa681fa..126a7c87d 100644 --- a/website/docs/r/is_security_group_target.html.markdown +++ b/website/docs/r/is_security_group_target.html.markdown @@ -8,26 +8,45 @@ description: |- --- # ibm_is_security_group_target + This request adds a resource to an existing security group. The supplied target identifier can be: - A network interface identifier. - An application load balancer identifier. + - An endpoint gateway identifier. + When a target is added to a security group, the security group rules are applied to the target. A request body is not required, and if supplied, is ignored. For more information, about security group target, see [required permissions](https://cloud.ibm.com/docs/vpc?topic=vpc-resource-authorizations-required-for-api-and-cli-calls). +**Note** +- IBM Cloud terraform provider currently provides both a standalone `ibm_is_security_group_target` resource and a `security_groups` block defined in-line in the `ibm_is_instance_network_interface` resource to attach security group to a network interface target. At this time you cannot use the `security_groups` block inline with `ibm_is_instance_network_interface` in conjunction with the standalone resource `ibm_is_security_group_target`. Doing so will create a conflict of security groups attaching to the network interface and will overwrite it. +- VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + + **provider.tf** + + ```terraform + provider "ibm" { + region = "eu-gb" + } + ``` + ## Example usage Sample to create a security group target. ```terraform -resource "ibm_is_security_group_target" "testacc_security_group_target" { - security_group = ibm_is_security_group.testacc_security_group.id - target = "r006-5b77aa07-7dfb-4c74-a1bd-904b23cbe198" - } +resource "ibm_is_security_group_target" "example" { + security_group = ibm_is_security_group.example.id + target = ibm_is_lb.example.id +} ``` ## Argument reference Review the argument references that you can specify for your resource. - `security_group` - (Required, Force new resource, String) The security group identifier. -- `target` - (Required, Force new resource, String) The security group target identifier. +- `target` - (Required, Force new resource, String) The security group target identifier. Could be one of the below: + - A network interface identifier. + - An application load balancer identifier. + - An endpoint gateway identifier. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -45,5 +64,4 @@ The `ibm_is_security_group_target` resource can be imported by using security gr ``` $ terraform import ibm_is_security_group_target.example r006-6c6528a7-26de-4438-9685-bf2f6bbcb1ad/r006-5b77aa07-7dfb-4c74-a1bd-904123123cbe198 - ``` diff --git a/website/docs/r/is_snapshot.html.markdown b/website/docs/r/is_snapshot.html.markdown index 45f3e6766..d267273b6 100644 --- a/website/docs/r/is_snapshot.html.markdown +++ b/website/docs/r/is_snapshot.html.markdown @@ -10,44 +10,54 @@ description: |- Create, update, or delete a snapshot. For more information, about subnet, see [creating snapshots](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-create). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. -## Example Usage +**provider.tf** ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +provider "ibm" { + region = "eu-gb" } +``` + +## Example usage -resource "ibm_is_subnet" "testacc_subnet" { - name = "testsubnet" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "us-south-2" - total_ipv4_address_count = 16 +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "testssh" +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + total_ipv4_address_count = 16 +} + +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } -resource "ibm_is_instance" "testacc_instance" { - name = "testvsi" - image = "xxxxx-xxxxx-xxxxx-xxxxxx" +resource "ibm_is_instance" "example" { + name = "example-vsi" + image = ibm_is_image.example.id profile = "bx2-2x8" primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id } - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id zone = "us-south-2" - keys = [ibm_is_ssh_key.testacc_sshkey.id] + keys = [ibm_is_ssh_key.example.id] network_interfaces { - subnet = ibm_is_subnet.testacc_subnet.id + subnet = ibm_is_subnet.example.id name = "eth1" } } -resource "ibm_is_snapshot" "testacc_snapshot" { - name = "testsnapshot" - source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id +resource "ibm_is_snapshot" "example" { + name = "example-snapshot" + source_volume = ibm_is_instance.example.volume_attachments[0].volume_id //User can configure timeouts timeouts { @@ -62,7 +72,7 @@ resource "ibm_is_snapshot" "testacc_snapshot" { The `ibm_is_snapshot` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - **create** - (Default 10 minutes) Used for creating Snapshot. -- **delete** - (Default 10 minutes) Used for deleting Snaphsot. +- **delete** - (Default 10 minutes) Used for deleting Snapshot. ## Argument reference @@ -71,10 +81,22 @@ Review the argument references that you can specify for your resource. - `name` - (Optional, String) The name of the snapshot. - `resource_group` - (Optional, Forces new resource, String) The resource group ID where the snapshot is to be created - `source_volume` - (Required, Forces new resource, String) The unique identifier for the volume for which snapshot is to be created. +- `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your snapshot. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - +- `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot. + + Nested scheme for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user defined name for this backup policy plan. If unspecified, the name will be a hyphenated list of randomly selected words. + - `resource_type` - (String) The type of resource referenced. - `bootable` - (Bool) Indicates if a boot volume attachment can be created with a volume created from this snapshot. - `crn` - (String) The CRN for this snapshot. - `encryption` - (String) The type of encryption used on the source volume. Supported values are **provider_managed**, **user_managed**. diff --git a/website/docs/r/is_ssh_key.html.markdown b/website/docs/r/is_ssh_key.html.markdown index 96f5b0ca9..20335cbb8 100644 --- a/website/docs/r/is_ssh_key.html.markdown +++ b/website/docs/r/is_ssh_key.html.markdown @@ -10,11 +10,22 @@ description: |- # ibm_is_ssh_key Create, update, or delete an SSH key. The SSH key is used to access a Generation 2 virtual server instance. For more information, about SSH key, see [managing SSH Keys](https://cloud.ibm.com/docs/vpc?topic=vpc-ssh-keys). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_ssh_key" "isExampleKey" { - name = "test-key" +resource "ibm_is_ssh_key" "example" { + name = "example-key" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } ``` diff --git a/website/docs/r/is_subnet.html.markdown b/website/docs/r/is_subnet.html.markdown index c845abec8..b137d8780 100644 --- a/website/docs/r/is_subnet.html.markdown +++ b/website/docs/r/is_subnet.html.markdown @@ -10,26 +10,37 @@ description: |- # ibm_is_subnet Create, update, or delete a subnet. For more information, about subnet, see [configuring ACLs and security groups for use with VPN](https://cloud.ibm.com/docs/vpc?topic=vpc-acls-security-groups-vpn). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_routing_table" "test_cr_route_table1" { - name = "test-cr-route-table1" - vpc = data.ibm_is_vpc.testacc_vpc.id +resource "ibm_is_vpc_routing_table" "example" { + name = "example-routing-table" + vpc = ibm_is_vpc.example.id } -resource "ibm_is_subnet" "testacc_subnet" { - name = "test_subnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" - ipv4_cidr_block = "192.168.0.0/1" - routing_table = ibm_is_vpc_routing_table.test_cr_route_table1.routing_table + ipv4_cidr_block = "10.240.0.0/24" + routing_table = ibm_is_vpc_routing_table.example.routing_table //User can configure timeouts timeouts { @@ -39,6 +50,31 @@ resource "ibm_is_subnet" "testacc_subnet" { } ``` +## Example usage with address prefix +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_vpc_address_prefix" "example" { + cidr = "10.0.1.0/24" + name = "example-add-prefix" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" +} + +resource "ibm_is_subnet" "example" { + depends_on = [ + ibm_is_vpc_address_prefix.example + ] + ipv4_cidr_block = "10.0.1.0/24" + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" +} +``` + + ## Timeouts The `ibm_is_subnet` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -50,15 +86,19 @@ The `ibm_is_subnet` resource provides the following [Timeouts](https://www.terra ## Argument reference Review the argument references that you can specify for your resource. -- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the subnet. **Note** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag). +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the subnet. ~> **Note:** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag). - `ipv4_cidr_block` - (Optional, Forces new resource, String) The IPv4 range of the subnet. + + ~> **NOTE:** + - if using a IPv4 range from a `ibm_is_vpc_address_prefix` resource, add a `depends_on` to handle hidden `ibm_is_vpc_address_prefix` dependency if not using interpolation. + - `ip_version` - (Optional, Forces new resource, String) The IP Version. The default is `ipv4`. - `name` - (Required, String) The name of the subnet. - `network_acl` - (Optional, String) The ID of the network ACL for the subnet. - `public_gateway` - (Optional, String) The ID of the public gateway for the subnet that you want to attach to the subnet. You create the public gateway with the [`ibm_is_public_gateway` resource](#provider-public-gateway). - `resource_group` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the subnet. - `routing_table` - (Optional, String) The routing table ID associated with the subnet. -- `tags` - (Optional, List of Strings) The tags associated with an instance. +- `tags` - (Optional, List of Strings) The tags associated with the subnet. - `total_ipv4_address_count` - (Optional, Forces new resource, String) The total number of IPv4 addresses. Either `ipv4_cidr_block` or `total_pv4_address_count` input parameters must be provided in the resource. - `vpc` - (Required, Forces new resource, String) The VPC ID. - `zone` - (Required, Forces new resource, String) The subnet zone name. diff --git a/website/docs/r/is_subnet_network_acl_attachment.html.markdown b/website/docs/r/is_subnet_network_acl_attachment.html.markdown index b722464f7..ba06e7e50 100644 --- a/website/docs/r/is_subnet_network_acl_attachment.html.markdown +++ b/website/docs/r/is_subnet_network_acl_attachment.html.markdown @@ -10,11 +10,22 @@ description: |- # ibm_is_subnet_network_acl_attachment Create, update, or delete a subnet network ACL attachment resource. For more information, about subnet network ACL attachment, see [setting up network ACLs](https://cloud.ibm.com/docs/vpc?topic=vpc-using-acls). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_network_acl" "isExampleACL" { - name = "is-example-acl" +resource "ibm_is_network_acl" "example" { + name = "example-acl" rules { name = "outbound" action = "allow" @@ -39,17 +50,17 @@ resource "ibm_is_network_acl" "isExampleACL" { } } -resource "ibm_is_subnet" "testacc_subnet" { - name = "test_subnet" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id zone = "us-south-1" ipv4_cidr_block = "192.168.0.0/1" } -resource "ibm_is_subnet_network_acl_attachment" attach { - subnet = ibm_is_subnet.testacc_subnet.id - network_acl = ibm_is_network_acl.isExampleACL.id +resource "ibm_is_subnet_network_acl_attachment" "example" { + subnet = ibm_is_subnet.example.id + network_acl = ibm_is_network_acl.example.id } ``` @@ -92,7 +103,7 @@ In addition to all argument reference list, you can access the following attribu - `source_port_min` - (String) The inclusive minimum bound of UDP source port range. - `subnets` - (String) The subnets to which this network ACL is attached. - `vpc` - (String) The VPC to which this network ACL is a part of. -- `resource_group` - (String) The resource group of this network ACL. +- `resource_group` - (String) The resource group (Id), of this network ACL. - `rules` - (List) The ordered rules of this network ACL. If rules does not exist, all traffic will be denied. Nested rules blocks has the following structure. Nested scheme for `rules`: diff --git a/website/docs/r/is_subnet_public_gateway_attachment.html.markdown b/website/docs/r/is_subnet_public_gateway_attachment.html.markdown new file mode 100644 index 000000000..0cdb83dd1 --- /dev/null +++ b/website/docs/r/is_subnet_public_gateway_attachment.html.markdown @@ -0,0 +1,88 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : subnet_public_gateway_attachment" +description: |- + Manages IBM Subnet public gateway attachment. +--- + +# ibm_is_subnet_public_gateway_attachment +Create, update, or delete a public gateway attachment for a VPC subnet. Public gateways enable a VPC subnet and all the instances that are connected to the subnet to connect to the internet. For more information, see [use a Public Gateway for external connectivity of a subnet](https://cloud.ibm.com/docs/vpc?topic=vpc-about-networking-for-vpc#public-gateway-for-external-connectivity). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "eu-gb-1" + total_ipv4_address_count = 16 +} + +resource "ibm_is_public_gateway" "example" { + name = "example-public-gateway" + vpc = ibm_is_vpc.example.id + zone = "eu-gb-1" +} + +resource "ibm_is_subnet_public_gateway_attachment" "example" { + subnet = ibm_is_subnet.example.id + public_gateway = ibm_is_public_gateway.example.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `public_gateway` - (Required, String) The public gateway identifier. +- `subnet` - (Required, Forces new resource, String) The subnet identifier. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The CRN for this public gateway. +- `floating_ip` - (List) The floating IP bound to this public gateway. + Nested scheme for `floating_ip`: + - `address` - (String) The globally unique IP address for this floating ip. + - `id` - (String) The unique identifier of the floating IP address. +- `id` - (String) The unique identifier of the subnet. +- `name` - (String) The user-defined name for this public gateway. +- `resource_group` - (String) The resource group identifier for this public gateway. +- `resource_group_name` - (String) The name for the resource group for this public gateway. +- `resource_type` - (String) The resource type for this public gateway. +- `status` - (String) The status of this public gateway. +- `vpc` - (String) The identifier of the VPC this public gateway serves. +- `zone` - (String) The zone this public gateway resides in. + +## Import +The `ibm_is_subnet_public_gateway_attachment` resource can be imported by using the subnet ID. + +**Syntax** + +``` +$ terraform import ibm_is_subnet_public_gateway_attachment.example +``` + +**Example** + +``` +$ terraform import ibm_is_subnet_public_gateway_attachment.example d7bec597-4726-451f-8a63-1111e6f19c32c +``` diff --git a/website/docs/r/is_subnet_reserved_ip.html.markdown b/website/docs/r/is_subnet_reserved_ip.html.markdown index 323ae9dfa..8f15fbe04 100644 --- a/website/docs/r/is_subnet_reserved_ip.html.markdown +++ b/website/docs/r/is_subnet_reserved_ip.html.markdown @@ -9,84 +9,106 @@ description: |- # ibm_is_subnet_reserved_ip Create, update, or delete a subnet. For more information, about associated reserved IP subnet, see [reserved IP subnet](https://cloud.ibm.com/docs/vpc?topic=vpc-troubleshoot-reserved-ip). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage Sample to create a reserved IP: ```terraform - // Create a VPC - resource "ibm_is_vpc" "vpc1" { - name = "my-vpc" - } - - // Create a subnet - resource "ibm_is_subnet" "subnet1" { - name = "my-subnet" - vpc = ibm_is_vpc.vpc1.id - zone = "us-south-1" - total_ipv4_address_count = 256 - } - - // Create the resrved IP in the following ways - - // Only with Subnet ID - resource "ibm_is_subnet_reserved_ip" "res_ip" { - subnet = ibm_is_subnet.subnet1.id - } - - // Subnet ID with a given name - resource "ibm_is_subnet_reserved_ip" "res_ip_name" { - subnet = ibm_is_subnet.subnet1.id - name = "my-subnet-reserved-ip" - } - - // Subnet ID with auto_delete - resource "ibm_is_subnet_reserved_ip" "res_ip_auto_delete" { - subnet = ibm_is_subnet.subnet1.id - auto_delete = true - } - - // Subnet ID with both name and auto_delete - resource "ibm_is_subnet_reserved_ip" "res_ip_auto_delete_name" { - subnet = ibm_is_subnet.subnet1.id - name = "my-subnet-reserved-ip" - auto_delete = true - } - - // Create a virtual endpoint gateway and set as a target for reserved IP - resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway" { - name = "my-endpoint-gateway-1" - target { - name = "ibm-ntp-server" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.vpc1.id - } - resource "ibm_is_subnet_reserved_ip" "reserved_ip_1" { - subnet = ibm_is_subnet.subnet1.id - name = "%s" - target = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id - } +// Create a VPC +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} + +// Create a subnet +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + total_ipv4_address_count = 256 +} + +// Create the reserved IP in the following ways + +// Only with Subnet ID +resource "ibm_is_subnet_reserved_ip" "example" { + subnet = ibm_is_subnet.example.id +} + +// Subnet ID with a given name +resource "ibm_is_subnet_reserved_ip" "example1" { + subnet = ibm_is_subnet.example.id + name = "example-subnet-reserved-ip1" +} + +// Subnet ID with auto_delete +resource "ibm_is_subnet_reserved_ip" "example2" { + subnet = ibm_is_subnet.example.id + auto_delete = true +} + +// Subnet ID with both name and auto_delete +resource "ibm_is_subnet_reserved_ip" "example3" { + subnet = ibm_is_subnet.example.id + name = "example-subnet-reserved-ip3" + auto_delete = true +} + +// Subnet ID with address, name and auto_delete +resource "ibm_is_subnet_reserved_ip" "example4" { + subnet = ibm_is_subnet.example.id + address = "${replace(ibm_is_subnet.example.ipv4_cidr_block, "0/24", "14")}" + name = "example-subnet-reserved-ip4" + auto_delete = true +} + +// Create a virtual endpoint gateway and set as a target for reserved IP +resource "ibm_is_virtual_endpoint_gateway" "example" { + name = "example-endpoint-gateway" + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.example.id +} +resource "ibm_is_subnet_reserved_ip" "example5" { + subnet = ibm_is_subnet.example.id + name = "example-subnet-reserved-ip5" + target = ibm_is_virtual_endpoint_gateway.example.id +} ``` ## Argument reference Review the argument references that you can specify for your resource. +- `address` - (Optional, Forces new resource, String) The IP address. - `auto_delete`- (Optional, Bool) If reserved IP is auto deleted. -- `name` - (Optional, String) The name of the reserved IP. **NOTE** raise error if name is given with a prefix `ibm- `. +- `name` - (Optional, String) The name of the reserved IP. + + ~> **NOTE:** raise error if name is given with a prefix `ibm- `. - `subnet` - (Required, Forces new resource, String) The subnet ID for the reserved IP. - `target` - (Optional, string) The ID for the target endpoint gateway for the reserved IP. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `address` - (String) The IP address. - `created_at` - (Timestamp) The date and time that the reserved IP was created.", - `href` - (String) The URL for this reserved IP. -- `id` - (String) The combination of the subnet ID and reserved IP ID separated by **/**. +- `id` - (String) The combination of the subnet ID and reserved IP ID, separated by **/**. +- `lifecycle_state` - (String) The lifecycle state of the reserved IP. [ deleting, failed, pending, stable, suspended, updating, waiting ] - `owner` - (String) The owner of a reserved IP, defining whether it is managed by the user or the provider. - `reserved_ip` - (String) The reserved IP. - `resource_type` - (String) The resource type. -- `target` - (String) The ID for the target endpoint gateway for the reserved IP. +- `target` - (String) The ID for the target for the reserved IP. ## Import The `ibm_is_subnet_reserved_ip` and `ibm_is_subnet` resource can be imported by using subnet ID and reserved IP ID separated by **/**. @@ -94,7 +116,7 @@ The `ibm_is_subnet_reserved_ip` and `ibm_is_subnet` resource can be imported by **Syntax** ``` -$ terraform import ibm_is_subnet.example +$ terraform import ibm_is_subnet.example / ``` **Example** diff --git a/website/docs/r/is_subnet_routing_table_attachment.html.markdown b/website/docs/r/is_subnet_routing_table_attachment.html.markdown new file mode 100644 index 000000000..feaa3bc11 --- /dev/null +++ b/website/docs/r/is_subnet_routing_table_attachment.html.markdown @@ -0,0 +1,96 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : subnet_routing_table_attachment" +description: |- + Manages IBM subnet routing table attachment. +--- + +# ibm_is_subnet_routing_table_attachment +Create, update, or delete a subnet routing table attachment resource. For more information, about subnet routing table attachment, see [setting up routing tables](https://cloud.ibm.com/docs/vpc?topic=vpc-attach-subnets-routing-table). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage + +```terraform +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} +resource "ibm_is_vpc_routing_table" "example" { + vpc = ibm_is_vpc.example.id + name = "example-rt" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.id + zone = "eu-gb-1" + total_ipv4_address_count = 16 +} + +resource "ibm_is_subnet_routing_table_attachment" "example" { + subnet = ibm_is_subnet.example.id + routing_table = ibm_is_vpc_routing_table.example.routing_table +} + +``` +## Argument reference +Review the argument references that you can specify for your resource. + +- `routing_table` - (Required, String) The routing table identity. +- `subnet` - (Required, Forces new resource, String) The subnet identifier. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `created_at` - (Timestamp) The creation date and time the routing table. +- `href` - (String) The URL of this routing table. +- `id` - (String) The unique identifier of the subnet. +- `is_default` - (Boolean) Indicates whether this is the default routing table for this VPC. +- `lifecycle_state` - (String) The lifecycle state of the routing table. +- `name` - (String) The user-defined name of this routing table. +- `resource_type` - (String) The resource type. +- `route_direct_link_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from [Direct Link](https://cloud.ibm.com/docs/dl/) to this VPC. Incoming traffic will be routed according to the routing table with one exception: routes with an action of deliver are treated as drop unless the next_hop is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a next_hop of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.. +- `route_transit_gateway_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from from [Transit Gateway](https://cloud.ibm.com/cloud/transit-gateway/) to this VPC. +Incoming traffic will be routed according to the routing table with one exception: routes with an action of deliver are treated as drop unless the next_hop is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a next_hop of an internet-bound IP address or a VPN gateway connection, the packet will be dropped. +- `route_vpc_zone_ingress` - (Boolean) Indicates whether this routing table is used to route traffic that originates from subnets in other zones in this VPC. Incoming traffic will be routed according to the routing table with one exception: routes with an action of deliver are treated as drop unless the next_hop is an IP address within the VPC's address prefix ranges. Therefore, if an incoming packet matches a route with a next_hop of an internet-bound IP address or a VPN gateway connection, the packet will be dropped.. +- `routes` - (List) The routes for this routing table. + + Nested scheme for `routes`: + - `href` - (List) The URL for this route. + - `id` - (List) The unique identifier for this route. + - `name` - (List) The user-defined name for this route. + +- `subnets` - (List) The subnets to which this routing table is attached. + + Nested scheme for `subnets`: + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The user-defined name for this subnet. + + +## Import +The `ibm_is_subnet_routing_table_attachment` resource can be imported by using the subnet ID. + +**Syntax** + +``` +$ terraform import ibm_is_subnet_routing_table_attachment.example +``` + +**Example** + +``` +$ terraform import ibm_is_subnet_routing_table_attachment.example d7bec597-4726-451f-8a63-1111e6f19c32c +``` diff --git a/website/docs/r/is_virtual_endpoint_gateway.html.markdown b/website/docs/r/is_virtual_endpoint_gateway.html.markdown index 648642aa5..f76acaf54 100644 --- a/website/docs/r/is_virtual_endpoint_gateway.html.markdown +++ b/website/docs/r/is_virtual_endpoint_gateway.html.markdown @@ -10,56 +10,72 @@ description: |- # ibm_is_virtual_endpoint_gateway Create, update, or delete a VPC endpoint gateway by using virtual endpoint gateway resource. For more information, about the VPC endpoint gateway, see [creating an endpoint gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-ordering-endpoint-gateway). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example, creates a Virtual Private Endpoint gateway. ```terraform -resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway1" { +resource "ibm_is_virtual_endpoint_gateway" "example" { - name = "my-endpoint-gateway-1" + name = "example-endpoint-gateway" target { - name = "ibm-ntp-server" + name = "ibm-ntp-server" resource_type = "provider_infrastructure_service" } - vpc = ibm_is_vpc.testacc_vpc.id - resource_group = data.ibm_resource_group.test_acc.id + vpc = ibm_is_vpc.example.id + resource_group = data.ibm_resource_group.example.id + security_groups = [ibm_is_security_group.example.id] } -resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway2" { - name = "my-endpoint-gateway-1" - target { - name = "ibm-ntp-server" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.testacc_vpc.id - ips { - subnet = ibm_is_subnet.testacc_subnet.id - name = "test-reserved-ip1" - } - resource_group = data.ibm_resource_group.test_acc.id +resource "ibm_is_virtual_endpoint_gateway" "example1" { + name = "example-endpoint-gateway-1" + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.example.id + ips { + subnet = ibm_is_subnet.example.id + name = "example-reserved-ip" + } + resource_group = data.ibm_resource_group.example.id + security_groups = [ibm_is_security_group.example.id] } -resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway3" { - name = "my-endpoint-gateway-1" - target { - name = "ibm-ntp-server" - resource_type = "provider_infrastructure_service" - } - vpc = ibm_is_vpc.testacc_vpc.id - ips { - id = "0737-5ab3c18e-6f6c-4a69-8f48-20e3456647b5" - } - resource_group = data.ibm_resource_group.test_acc.id +resource "ibm_is_virtual_endpoint_gateway" "example3" { + name = "example-endpoint-gateway-2" + target { + name = "ibm-ntp-server" + resource_type = "provider_infrastructure_service" + } + vpc = ibm_is_vpc.example.id + ips { + subnet = ibm_is_subnet.example.id + name = "example-reserved-ip" + } + resource_group = data.ibm_resource_group.example.id + security_groups = [ibm_is_security_group.example.id] } -resource "ibm_is_virtual_endpoint_gateway" "endpoint_gateway3" { - name = "my-endpoint-gateway-1" +resource "ibm_is_virtual_endpoint_gateway" "example4" { + name = "example-endpoint-gateway-3" target { crn = "crn:v1:bluemix:public:cloud-object-storage:global:::endpoint:s3.direct.mil01.cloud-object-storage.appdomain.cloud" resource_type = "provider_cloud_service" } - vpc = ibm_is_vpc.testacc_vpc.id - resource_group = data.ibm_resource_group.test_acc.id + vpc = ibm_is_vpc.example.id + resource_group = data.ibm_resource_group.example.id + security_groups = [ibm_is_security_group.example.id] } ``` @@ -74,9 +90,11 @@ Review the argument references that you can specify for your resource. - `name` - (Optional, String) The endpoint gateway resource group IPs name. - `subnet` - (Optional, String) The endpoint gateway resource group subnet ID. - **NOTE**: `id` and `subnet` are mutually exclusive. + ~> **NOTE:** `id` and `subnet` are mutually exclusive. - `resource_group` - (Optional, Forces new resource, String) The resource group ID. +- `security_groups` - (Optional, list) The security groups to use for this endpoint gateway. If unspecified, the VPC's default security group is used. + **NOTE:** either of `ibm_is_security_group_target` resource or `security_groups` attribute should be used, both can't be use together. - `tags`- (Optional, Array of Strings) A list of tags associated with the instance. - `target` - (Required, List) The endpoint gateway target. @@ -90,7 +108,7 @@ Review the argument references that you can specify for your resource. - `resource_type` - (Required, String) The endpoint gateway target resource type. The possible values are `provider_cloud_service`, `provider_infrastructure_service`. - `vpc` - (Required, Forces new resource, String) The VPC ID. -**NOTE**: `ips` configured inline in this resource are not modifiable. Prefer using `ibm_is_virtual_endpoint_gateway_ip` resource to bind/unbind new reserved IPs to endpoint gateways and use the resource `ibm_is_subnet_reserved_ip` to create new reserved IP. +~> **NOTE:** `ips` configured inline in this resource are not modifiable. Prefer using `ibm_is_virtual_endpoint_gateway_ip` resource to bind/unbind new reserved IPs to endpoint gateways and use the resource `ibm_is_subnet_reserved_ip` to create new reserved IP. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -99,7 +117,7 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN for this endpoint gateway. - `health_state` - (String) The health state of the endpoint gateway. - `id` - (String) The unique identifier of the VPE Gateway. The ID is composed of ``. -- `ips` (List) The endpoint gateway resource group. +- `ips` (List) The endpoint gateway reserved ips. Nested scheme for `ips`: - `address` - The endpoint gateway IPs Address. diff --git a/website/docs/r/is_virtual_endpoint_gateway_ip.html.markdown b/website/docs/r/is_virtual_endpoint_gateway_ip.html.markdown index 07097dc7f..47c696276 100644 --- a/website/docs/r/is_virtual_endpoint_gateway_ip.html.markdown +++ b/website/docs/r/is_virtual_endpoint_gateway_ip.html.markdown @@ -10,15 +10,25 @@ description: |- # ibm_is_virtual_endpoint_gateway_ip Create, update, or delete a VPC endpoint gateway IP by using virtual endpoint gateway resource. For more information, about the VPC endpoint gateway, see [about VPC gateways](https://cloud.ibm.com/docs/vpc?topic=vpc-about-vpe). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example creates a Virtual Private Endpoint gateway IP. ```terraform -resource "ibm_is_virtual_endpoint_gateway_ip" "virtual_endpoint_gateway_ip" { - gateway = ibm_is_virtual_endpoint_gateway.endpoint_gateway.id - reserved_ip = "0737-5ab3c18e-6f6c-4a69-8f48-20e3456647b5" +resource "ibm_is_virtual_endpoint_gateway_ip" "example" { + gateway = ibm_is_virtual_endpoint_gateway.example.id + reserved_ip = ibm_is_subnet_reserved_ip.example.reserved_ip } - ``` diff --git a/website/docs/r/is_volume.html.markdown b/website/docs/r/is_volume.html.markdown index 4624e512b..f690627af 100644 --- a/website/docs/r/is_volume.html.markdown +++ b/website/docs/r/is_volume.html.markdown @@ -10,26 +10,36 @@ description: |- # ibm_is_volume Create, update, or delete a VPC block storage volume. For more information, about the VPC block storage volume, see [getting started with VPC](https://cloud.ibm.com/docs/vpc). +~> **NOTE:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example creates a volume with 10 IOPs tier. ```terraform -resource "ibm_is_volume" "testacc_volume" { - name = "test-volume" - profile = "10iops-tier" - zone = "us-south-1" +resource "ibm_is_volume" "example" { + name = "example-volume" + profile = "10iops-tier" + zone = "us-south-1" } - ``` The following example creates a custom volume. ```terraform -resource "ibm_is_volume" "testacc_volume" { - name = "test-volume" - profile = "custom" - zone = "us-south-1" - iops = 1000 - capacity = 200 +resource "ibm_is_volume" "example" { + name = "example-volume" + profile = "custom" + zone = "us-south-1" + iops = 1000 + capacity = 200 encryption_key = "crn:v1:bluemix:public:kms:us-south:a/dffc98a0f1f0f95f6613b3b752286b87:e4a29d1a-2ef0-42a6-8fd2-350deb1c647e:key:5437653b-c4b1-447f-9646-b2a2a4cd6179" } @@ -46,16 +56,15 @@ The `ibm_is_volume` resource provides the following [Timeouts](https://www.terra Review the argument references that you can specify for your resource. - `capacity` - (Optional, Integer) (The capacity of the volume in gigabytes. This defaults to `100`, minimum to `10 ` and maximum to `16000`. - **NOTE** - - Supports only expansion on update (must be attached to a running instance and must not be less than the current volume capacity) - - Can be updated only if volume is attached to an running virtual server instance. - - Stopped instance will be started on update of capacity of the volume. + + ~> **NOTE:** Supports only expansion on update (must be attached to a running instance and must not be less than the current volume capacity). Can be updated only if volume is attached to an running virtual server instance. Stopped instance will be started on update of capacity of the volume. + +- `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume - `delete_all_snapshots` - (Optional, Bool) Deletes all snapshots created from this volume. - `encryption_key` - (Optional, Forces new resource, String) The key to use for encrypting this volume. - `iops` - (Optional, Integer) The total input/ output operations per second (IOPS) for your storage. This value is required for `custom` storage profiles only. -**NOTE** - - `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. + ~> **NOTE:** `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. This table shows how storage size affects the `iops` ranges: @@ -75,17 +84,16 @@ Review the argument references that you can specify for your resource. - `name` - (Required, String) The user-defined name for this volume.No. - `profile` - (Required, String) The profile to use for this volume. - **NOTE** - - tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. + ~> **NOTE:** tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. - `resource_group` - (Optional, Forces new resource, String) The resource group ID for this volume. - `resource_controller_url` - (Optional, Forces new resource, String) The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance. -- `tags`- (Optional, Array of Strings) A list of tags that you want to add to your volume. Tags can help you find your volume more easily later.No. +- `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `zone` - (Required, Forces new resource, String) The location of the volume. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `encryption_type` - (String) The type of ecryption used in the volume [**provider_managed**, **user_managed**]. +- `encryption_type` - (String) The type of encryption used in the volume [**provider_managed**, **user_managed**]. - `id` - (String) The unique identifier of the volume. - `source_snapshot` - ID of the snapshot, if volume was created from it. - `status` - (String) The status of volume. Supported values are **available**, **failed**, **pending**, **unusable**, or **pending_deletion**. @@ -94,6 +102,7 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `status_reasons`: - `code` - (String) A string with an underscore as a special character identifying the status reason. - `message` - (String) An explanation of the status reason. + - `more_info` - (String) Link to documentation about this status reason - `crn` - (String) The CRN for the volume. ## Import diff --git a/website/docs/r/is_vpc.html.markdown b/website/docs/r/is_vpc.html.markdown index 8114d736a..cace9e361 100644 --- a/website/docs/r/is_vpc.html.markdown +++ b/website/docs/r/is_vpc.html.markdown @@ -10,12 +10,23 @@ description: |- # ibm_is_vpc Create, update, or delete a Virtual Private Cloud (VPC). VPCs allow you to create your own space in IBM Cloud to run an isolated environment within the public cloud. VPC gives you the security of a private cloud, with the agility and ease of a public cloud. For more information, about VPC, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example to create a VPC: ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "test" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } ``` @@ -32,7 +43,6 @@ Review the argument references that you can specify for your resource. - `address_prefix_management` - (Optional, Forces new resource, String) Indicates whether a default address prefix should be created automatically `auto` or manually `manual` for each zone in this VPC. Default value is `auto`. - `classic_access` - (Optional, Bool) Specify if you want to create a VPC that can connect to classic infrastructure resources. Enter **true** to set up private network connectivity from your VPC to classic infrastructure resources that are created in the same IBM Cloud account, and **false** to disable this access. If you choose to not set up this access, you cannot enable it after the VPC is created. Make sure to review the [prerequisites](https://cloud.ibm.com/docs/vpc-on-classic-network?topic=vpc-on-classic-setting-up-access-to-your-classic-infrastructure-from-vpc#vpc-prerequisites) before you create a VPC with classic infrastructure access. Note that you can enable one VPC for classic infrastructure access per IBM Cloud account only. -- `default_network_acl`- (Deprecated, String) The ID of the default network ACL. - `default_network_acl_name` - (Optional, String) Enter the name of the default network access control list (ACL). - `default_security_group_name` - (Optional, String) Enter the name of the default security group. - `default_routing_table_name` - (Optional, String) Enter the name of the default routing table. diff --git a/website/docs/r/is_vpc_address_prefix.html.markdown b/website/docs/r/is_vpc_address_prefix.html.markdown index e4857c240..12bfe448b 100644 --- a/website/docs/r/is_vpc_address_prefix.html.markdown +++ b/website/docs/r/is_vpc_address_prefix.html.markdown @@ -10,17 +10,28 @@ description: |- # ibm_is_vpc_address_prefix Create, update, or delete an IP address prefix. For more information, about IS VPC address prefix, see [address prefixes](https://cloud.ibm.com/docs/vpc?topic=vpc-vpc-behind-the-curtain#address-prefixes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix" { - name = "test" +resource "ibm_is_vpc_address_prefix" "example" { + name = "example-address-prefix" zone = "us-south-1" - vpc = ibm_is_vpc.testacc_vpc.id + vpc = ibm_is_vpc.example.id cidr = "10.240.0.0/24" } @@ -40,8 +51,9 @@ Review the argument references that you can specify for your resource. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `id` - (String) The ID of the address prefix. +- `id` - (String) The ID of the address prefix. The ID is composed of `/`. - `has_subnets`- (Bool) Indicates whether subnets exist with addresses from this prefix. +- `address_prefix` - (String) the unique identifier of the address prefix. ## Import The `ibm_is_vpc_address_prefix` resource can be imported by using the VPC ID and VPC address prefix ID. diff --git a/website/docs/r/is_vpc_route.html.markdown b/website/docs/r/is_vpc_route.html.markdown index 73e28b92e..1f6c77199 100644 --- a/website/docs/r/is_vpc_route.html.markdown +++ b/website/docs/r/is_vpc_route.html.markdown @@ -7,19 +7,31 @@ description: |- Manages IBM IS VPC route. --- +~>**Note** This resource is deprecated, use `ibm_is_vpc_routing_table_route` instead. # ibm_is_vpc_route Create, update, or delete a VPC route. For more information, about VPC routes, see [setting up advanced routing in VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_route" "testacc_vpc_route" { - name = "routetest" - vpc = ibm_is_vpc.testacc_vpc.id +resource "ibm_is_vpc_route" "example" { + name = "example-route" + vpc = ibm_is_vpc.example.id zone = "us-south-1" destination = "192.168.4.0/24" next_hop = "10.0.0.4" diff --git a/website/docs/r/is_vpc_routing_table.html.markdown b/website/docs/r/is_vpc_routing_table.html.markdown index 8b023a7fd..ce992be1c 100644 --- a/website/docs/r/is_vpc_routing_table.html.markdown +++ b/website/docs/r/is_vpc_routing_table.html.markdown @@ -10,19 +10,30 @@ description: |- # ibm_is_vpc_routing_table Create, update, or delete an VPC routing tables. For more information, about VPC routes, see [routing tables for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc (List)routing-tables-for-vpc). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { - vpc = ibm_is_vpc.testacc_vpc.id - name = "routTabletest" - route_direct_link_ingress = true +resource "ibm_is_vpc_routing_table" "example" { + vpc = ibm_is_vpc.example.id + name = "example-vpc-routing-table" + route_direct_link_ingress = true route_transit_gateway_ingress = false - route_vpc_zone_ingress = false + route_vpc_zone_ingress = false } ``` @@ -30,6 +41,7 @@ resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { ## Argument reference Review the argument references that you can specify for your resource. +- `created_at` - (Timestamp) The date and time when the routing table was created. - `name` - (Optional, String) The routing table name. - `route_direct_link_ingress` - (Optional, Bool) If set to **true**, the routing table is used to route traffic that originates from Direct Link to the VPC. To succeed, the VPC must not already have a routing table with the property set to **true**. - `route_transit_gateway_ingress` - (Optional, Bool) If set to **true**, the routing table is used to route traffic that originates from Transit Gateway to the VPC. To succeed, the VPC must not already have a routing table with the property set to **true**. @@ -39,12 +51,13 @@ Review the argument references that you can specify for your resource. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. +- `accept_routes_from_resource_type` - (List) The reource type filter specifying the resources that may create routes in this routing table. - `href` - (String) The routing table URL. -- `id` - (String) The routing table ID. The ID is composed of `/` of the VPC route. +- `id` - (String) The unique identifier of the routing table. The ID is composed of `/`. - `is_default` - (String) Indicates the default routing table for this VPC. - `lifecycle_state` - (String) The lifecycle state of the routing table. - `resource_type` - (String) The resource type. -- `routing_table` - (String) The generated routing table ID. +- `routing_table` - (String) The unique routing table identifier. - `routes` - (List) The routes for the routing table. Nested scheme for `routes`: diff --git a/website/docs/r/is_vpc_routing_table_route.html.markdown b/website/docs/r/is_vpc_routing_table_route.html.markdown index 3a7d8a9b2..2a3808c9e 100644 --- a/website/docs/r/is_vpc_routing_table_route.html.markdown +++ b/website/docs/r/is_vpc_routing_table_route.html.markdown @@ -10,28 +10,38 @@ description: |- # ibm_is_vpc_routing_table_route Create, update, or delete of an VPC routing tables. For more information, about VPC routes, see [about routing tables and routes](https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` ## Example usage ```terraform -resource "ibm_is_vpc" "testacc_vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_vpc_routing_table" "test_ibm_is_vpc_routing_table" { - vpc = ibm_is_vpc.testacc_vpc.id - name = "routTabletest" - route_direct_link_ingress = true +resource "ibm_is_vpc_routing_table" "example" { + vpc = ibm_is_vpc.example.id + name = "example-routing-table" + route_direct_link_ingress = true route_transit_gateway_ingress = false - route_vpc_zone_ingress = false + route_vpc_zone_ingress = false } -resource "ibm_is_vpc_routing_table_route" "test_ibm_is_vpc_routing_table_route" { - vpc = ibm_is_vpc.testacc_vpc.id - routing_table = ibm_is_vpc_routing_table.test_ibm_is_vpc_routing_table.routing_table - zone = "us-south-1" - name = "custom-route-2" - destination = "192.168.4.0/24" - action = "deliver" - next_hop = ibm_is_vpn_gateway_connection.VPNGatewayConnection.gateway_connection // Example value "10.0.0.4" +resource "ibm_is_vpc_routing_table_route" "example" { + vpc = ibm_is_vpc.example.id + routing_table = ibm_is_vpc_routing_table.example.routing_table + zone = "us-south-1" + name = "custom-route-2" + destination = "192.168.4.0/24" + action = "deliver" + next_hop = ibm_is_vpn_gateway_connection.example.gateway_connection // Example value "10.0.0.4" } ``` @@ -50,10 +60,28 @@ Review the argument references that you can specify for your resource. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. +- `creator` - (Optional, List) If present, the resource that created the route. Routes with this property present cannot bedirectly deleted. All routes with an `origin` of `learned` or `service` will have thisproperty set, and future `origin` values may also have this property set. + Nested scheme for **creator**: + - `crn` - (Optional, String) The VPN gateway's CRN. + - Constraints: The maximum length is `512` characters. The minimum length is `9` characters. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `href` - (Optional, String) The VPN gateway's canonical URL. + - Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + - `id` - (Optional, String) The unique identifier for this VPN gateway. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/`. + - `name` - (Optional, String) The user-defined name for this VPN gateway. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/`. + - `resource_type` - (Optional, String) The resource type. + - Constraints: Allowable values are: `vpn_gateway`. The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/`. - `href` - (String) The routing table URL. - `id` - (String) The routing table ID. The ID is composed of `/`. - `is_default` - (String) Indicates the default routing table for this VPC. - `lifecycle_state` - (String) The lifecycle state of the route. +- `origin` - (Optional, String) The origin of this route:- `service`: route was directly created by a service- `user`: route was directly created by a userThe enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + - Constraints: Allowable values are: `learned`, `service`, `user`. - `resource_type` - (String) The resource type. ## Import diff --git a/website/docs/r/is_vpn_gateway.html.markdown b/website/docs/r/is_vpn_gateway.html.markdown index b867f427c..9b35a490f 100644 --- a/website/docs/r/is_vpn_gateway.html.markdown +++ b/website/docs/r/is_vpn_gateway.html.markdown @@ -10,6 +10,17 @@ description: |- # ibm_is_vpn_gateway Create, update, or delete a VPN gateway. For more information, about VPN gateway, see [adding connections to a VPN gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-adding-connections). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example creates a VPN gateway: @@ -46,7 +57,7 @@ Review the argument references that you can specify for your resource. - `mode`- (Optional, String) Mode in VPN gateway. Supported values are `route` or `policy`. The default value is `route`. - `name` - (Required, String) The name of the VPN gateway. -- `resource_group` - (Optional, Forces new resource, String) The resource group where the VPN gateway to be created. +- `resource_group` - (Optional, Forces new resource, String) The resource group (id), where the VPN gateway to be created. - `subnet` - (Required, Forces new resource, String) The unique identifier for this subnet. - `tags`- (Optional, Array of Strings) A list of tags that you want to add to your VPN gateway. Tags can help you find your VPN gateway more easily later. @@ -69,6 +80,18 @@ In addition to all argument reference list, you can access the following attribu - `private_ip_address` - (String) The Private IP address assigned to this VPN gateway member. - `private_ip_address2` - (String) The Second Private IP address assigned to this VPN gateway. - `status` - (String) The status of the VPN gateway. Supported values are **available**, **deleting**, **failed**, or **pending**. +- `vpc` - (String) The VPC this VPN server resides in. + Nested scheme for `vpc`: + - `crn` - (String) The CRN for this VPC. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) - The URL for this VPC + - `id` - (String) - The unique identifier for this VPC. + - `name` - (String) - The unique user-defined name for this VPC. +- `resource_type` - (String) - The resource type. + + ## Import The `ibm_is_vpn_gateway` resource can be imported by using the VPN gateway ID. diff --git a/website/docs/r/is_vpn_gateway_connection.html.markdown b/website/docs/r/is_vpn_gateway_connection.html.markdown index 44697a826..c75011a47 100644 --- a/website/docs/r/is_vpn_gateway_connection.html.markdown +++ b/website/docs/r/is_vpn_gateway_connection.html.markdown @@ -10,6 +10,17 @@ description: |- # ibm_is_vpn_gateway_connection Create, update, or delete a VPN gateway connection. For more information, about VPN gateway, see [adding connections to a VPN gateway](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-adding-connections). +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + ## Example usage The following example creates a VPN gateway: @@ -48,6 +59,26 @@ resource "ibm_is_vpn_gateway_connection" "example" { peer_cidrs = [ibm_is_subnet.example2.ipv4_cidr_block] } +``` +## Example usage ( policy mode with an active peer VPN gateway ) +The following example creates a VPN gateway: + +```terraform +resource "ibm_is_vpn_gateway" "example" { + name = "example-vpn-gateway" + subnet = ibm_is_subnet.example.id + mode = "policy" +} + +resource "ibm_is_vpn_gateway_connection" "example" { + name = "example-vpn-gateway-connection" + vpn_gateway = ibm_is_vpn_gateway.example.id + peer_address = ibm_is_vpn_gateway.example.public_ip_address != "0.0.0.0" ? ibm_is_vpn_gateway.example.public_ip_address : ibm_is_vpn_gateway.example.public_ip_address2 + preshared_key = "VPNDemoPassword" + local_cidrs = [ibm_is_subnet.example.ipv4_cidr_block] + peer_cidrs = [ibm_is_subnet.example2.ipv4_cidr_block] +} + ``` ## Timeouts @@ -61,9 +92,9 @@ Review the argument references that you can specify for your resource. - `action` - (Optional, String) Dead peer detection actions. Supported values are **restart**, **clear**, **hold**, or **none**. Default value is `restart`. - `admin_state_up` - (Optional, Bool) The VPN gateway connection status. Default value is **false**. If set to false, the VPN gateway connection is shut down. -- `ike_policy` - (Optional, String) The ID of the IKE policy. +- `ike_policy` - (Optional, String) The ID of the IKE policy. Updating value from ID to `""` or making it `null` or removing it will remove the existing policy. - `interval` - (Optional, Integer) Dead peer detection interval in seconds. Default value is 2. -- `ipsec_policy` - (Optional, String) The ID of the IPSec policy. +- `ipsec_policy` - (Optional, String) The ID of the IPSec policy. Updating value from ID to `""` or making it `null` or removing it will remove the existing policy. - `local_cidrs` - (Optional, Forces new resource, List) List of local CIDRs for this resource. - `name` - (Required, String) The name of the VPN gateway connection. - `peer_cidrs` - (Optional, Forces new resource, List) List of peer CIDRs for this resource. diff --git a/website/docs/r/is_vpn_server.html.markdown b/website/docs/r/is_vpn_server.html.markdown new file mode 100644 index 000000000..43152a58b --- /dev/null +++ b/website/docs/r/is_vpn_server.html.markdown @@ -0,0 +1,146 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : VPN-Server" +description: |- + Manages IBM VPN Server. +--- + +# ibm_is_vpn_server + +Provides a resource for VPNServer. This allows VPNServer to be created, updated and deleted. For more information, about VPN Server, see [Creating a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-create-server&interface=ui). + +## Example Usage +The following example creates a VPN Server: + +```terraform +resource "ibm_is_vpn_server" "example" { + certificate_crn = "crn:v1:bluemix:public:cloudcerts:us-south:a/efe5afc483594adaa8325e2b4d1290df:86f62739-f3a8-42ac-abea-f23255965983:certificate:00406b5615f95dba9bf7c2ab52bb3083" + client_authentication { + method = "certificate" + client_ca_crn = "crn:v1:bluemix:public:cloudcerts:us-south:a/efe5afc483594adaa8325e2b4d1290df:86f62739-f3a8-42ac-abea-f23255965983:certificate:00406b5615f95dba9bf7c2ab52bb3083" + } + client_ip_pool = "10.5.0.0/21" + client_dns_server_ips = ["192.168.3.4"] + client_idle_timeout = 2800 + enable_split_tunneling = false + name = "example-vpn-server" + port = 443 + protocol = "udp" + subnets = [ibm_is_subnet.subnet1.id] +} +``` + +## Timeouts +The `ibm_is_vpn_server` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create**: The creation of the VPN server is considered `failed` when no response is received for 10 minutes. +- **update**: The update of the VPN server is considered `failed` when no response is received for 10 minutes. +- **delete**: The deletion of the VPN server is considered `failed` when no response is received for 10 minutes. + +## Argument Reference +Review the argument references that you can specify for your resource. + +- `certificate_crn` - (Required, String) The certificate CRN instance from Certificate Manager or CRN of secret from Secrets Manager for this VPN server. As the usage of certificate CRN from Certificate Manager is getting deprecated, it is recommended to use CRN of secret from Secrets Manager. +- `client_authentication` - (Required, List) The methods used to authenticate VPN clients to this VPN server. + + Nested scheme for **client_authentication**: + - `method` - (Required, String) The type of authentication. + - Constraints: Allowable values are: certificate, username + + -> **NOTE:** + `identity_provider` and `client_ca_crn` are mutually exclusive, which means either one must be provided. When `method` has `certificate` as value `client_ca_crn` must be provided and when `method` has `username` as value `identity_provider` must be provided. + + - `identity_provider` - (Required, String) The type of identity provider to be used by VPN client.The type of identity provider to be used by the VPN client.- `iam`: IBM identity and access management The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the route on which the unexpected property value was encountered. + - Constraints: Allowable values are: iam + - `client_ca_crn` - (Required, String) The CRN of the certificate instance or CRN of the secret from secrets manager to use for the VPN client certificate authority (CA). As the usage of certificate CRN from Certificate Manager is getting deprecated, It is recommended to use Secret manger for same. + - `crl` - (Optional, String) The certificate revocation list contents, encoded in PEM format. + - Constraints: The maximum length is `2` items. The minimum length is `1` item. + +- `client_dns_server_ips` - (Optional, List) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered, the DNS server addresses that will be provided to VPN clients connected to this VPN server. +- `client_idle_timeout` - (Optional, Integer) The seconds a VPN client can be idle before this VPN server will disconnect it. Specify `0` to prevent the server from disconnecting idle clients. + - Constraints: The maximum value is `28800`. The minimum value is `0`, default is `600`. +- `client_ip_pool` - (Required, String) The VPN client IPv4 address pool, expressed in CIDR format. The request must not overlap with any existing address prefixes in the VPC or any of the following reserved address ranges: - `127.0.0.0/8` (IPv4 loopback addresses) - `161.26.0.0/16` (IBM services) - `166.8.0.0/14` (Cloud Service Endpoints) - `169.254.0.0/16` (IPv4 link-local addresses) - `224.0.0.0/4` (IPv4 multicast addresses)The prefix length of the client IP address pool's CIDR must be between`/9` (8,388,608 addresses) and `/22` (1024 addresses). A CIDR block that contains twice the number of IP addresses that are required to enable the maximum number of concurrent connections is recommended. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` +- `enable_split_tunneling` - (Optional, Boolean) Indicates whether the split tunneling is enabled on this VPN server. + - Constraints: The default value is `false`. +- `name` - (Optional, String) The user-defined name for this VPN server. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPC this VPN server is serving. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$/` +- `port` - (Optional, Integer) The port number to use for this VPN server. + - Constraints: The maximum value is `65535`. The minimum value is `1`. +- `protocol` - (Optional, String) The transport protocol to use for this VPN server. + - Constraints: The default value is `udp`. Allowable values are: udp, tcp +- `resource_group` - (Optional, Forces new resource, String) The resource group (id), where the VPN gateway to be created. +- `security_groups` - (Optional, List) The security groups to use for this VPN server. If unspecified, the VPC's default security group is used. + + Nested scheme for **security_groups**: + - `id` - (Optional, String) The unique identifier for this security group. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `crn` - (Optional, String) The security group's CRN. + - `href` - (Optional, String) The security group's canonical URL. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +- `subnets` - (Required, List) Comma-separated IDs or names of the subnets subnets to provision this VPN server in. Use subnets in different zones for high availability. User can also upgrade or downgrade the VPN server to high availability or standalone by adding/remove the subnets. + - Constraints: The minimum length is `1` item. + + Nested scheme for **subnets**: + - `id` - (Optional, String) The unique identifier for this subnet. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `crn` - (Optional, String) The CRN for this subnet. + - `href` - (Optional, String) The URL for this subnet. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the VPNServer. +- `vpn_server` - The unique identifier of the VPNServer. +- `client_auto_delete` - (Boolean) If set to `true`, disconnected VPN clients will be automatically deleted after the `client_auto_delete_timeout` time has passed. +- `client_auto_delete_timeout` - (Integer) Hours after which disconnected VPN clients will be automatically deleted. If `0`, disconnected VPN clients will be deleted immediately. + - Constraints: The maximum value is `24`. The minimum value is `0`. +- `created_at` - (String) The date and time that the VPN server was created. +- `crn` - (String) The CRN for this VPN server. +- `health_state` - (String) The health of this resource.- `ok`: Healthy- `degraded`: Suffering from compromised performance, capacity, or connectivity- `faulted`: Completely unreachable, inoperative, or otherwise entirely incapacitated- `inapplicable`: The health state does not apply because of the current lifecycle state. A resource with a lifecycle state of `failed` or `deleting` will have a health state of `inapplicable`. A `pending` resource may also have this state. + - Constraints: Allowable values are: ok, degraded, faulted, inapplicable +- `hostname` - (String) Fully qualified domain name assigned to this VPN server. +- `href` - (String) The URL for this VPN server. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` +- `lifecycle_state` - (String) The lifecycle state of the VPN server. + - Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended +- `private_ips` - (List) The reserved IPs bound to this VPN server. + + Nested scheme for **private_ips**: + - `address` - (String) The IP address. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/` + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `href` - (String) The URL for this reserved IP. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` + - `id` - (String) The unique identifier for this reserved IP. + - Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[-0-9a-z_]+$/` + - `name` - (String) The user-defined or system-provided name for this reserved IP. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^-?([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$/` + - `resource_type` - (String) The resource type. + - Constraints: Allowable values are: subnet_reserved_ip + +- `resource_type` - (String) The type of resource referenced. + - Constraints: Allowable values are: vpn_server +- `version` - Version of the VPNServer. + + +## Import + +You can import the `ibm_is_vpn_server` resource by using `id`. The unique identifier for this VPN server. + +# Syntax +``` +$ terraform import ibm_is_vpn_server.is_vpn_server +``` + +# Example +``` +$ terraform import ibm_is_vpn_server.is_vpn_server r006-d7cc5196-9864-48c4-82d8-3f30da41fcc5 +``` diff --git a/website/docs/r/is_vpn_server_client.html.markdown b/website/docs/r/is_vpn_server_client.html.markdown new file mode 100644 index 000000000..48ce023d4 --- /dev/null +++ b/website/docs/r/is_vpn_server_client.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : VPN-Server-Client" +description: |- + Manages IBM VPN Server Client Disconnect or Delete. +--- + +# ibm_is_vpn_server_client + +Provides VPNServer client delete or disconnect functionality for VPNServer. For more information, about VPN Server Client, see [Setting up a client VPN environment and connecting to a VPN server](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-environment-setup&interface=ui). + +## Example Usage + +```terraform +resource "ibm_is_vpn_server_client" "example" { + vpn_server = ibm_is_vpn_server.example.vpn_server + vpn_client = "id" + delete = true +} +``` + +## Argument Reference +Review the argument references that you can specify for your resource. + +- `vpn_server` - (Required, Forces new resource, String) The VPN server identifier. +- `vpn_client` - (Required, Forces new resource, String) The VPN client identifier. +- `delete` - (Optional, String) The delete to use for this VPN client to be deleted or not, when false, client is disconnected and when set to true client is deleted. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the VPNServerClient, it is combination of vpn_server, vpn_client, status_code. +- `status_code` - status code of the result. +- `description` - description of the result. + +## Import + +You can import the `ibm_is_vpn_server_client` resource by using `id`. The unique identifier for this VPN server client. + +# Syntax +``` +$ terraform import ibm_is_vpn_server_client.example +``` + +# Example +``` +$ terraform import ibm_is_vpn_server_client.example r006-d7cc5196-9864-48c4-82d8-3f30da41fcc5/r006-d7cc5196-9864-48c4-82d8-3h30db41acd5/202 +``` diff --git a/website/docs/r/is_vpn_server_route.html.markdown b/website/docs/r/is_vpn_server_route.html.markdown new file mode 100644 index 000000000..e84b3897b --- /dev/null +++ b/website/docs/r/is_vpn_server_route.html.markdown @@ -0,0 +1,67 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_vpn_server_route" +description: |- + Manages IBM VPN Server Route. +--- + +# ibm_is_vpn_server_route + +Provides a resource for VPNServerRoute. This allows VPNServerRoute to be created, updated and deleted. For more information, about VPN Server Routes, see [Managing VPN Server routes](https://cloud.ibm.com/docs/vpc?topic=vpc-vpn-client-to-site-routes&interface=ui). +## Example Usage + +```terraform +resource "ibm_is_vpn_server_route" "example" { + vpn_server_id = ibm_is_vpn_server.example.vpn_server + destination = "172.16.0.0/16" + action = "translate" + name = "example-vpn-server-route" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +- `action` - (Optional, String) The action to perform with a packet matching the VPN route: + - `translate`: translate the source IP address to one of the private IP addresses of the VPN server, then deliver the packet to target. + - `deliver`: deliver the packet to the target. + - `drop`: drop the packet. The enumerated values for this property are expected to expand in the future. + When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the VPN route on which the unexpected property value was encountered. + - Constraints: The default value is `deliver`. Allowable values are: translate, deliver, drop +- `destination` - (Required, String) The destination to use for this VPN route in the VPN server. Must be unique within the VPN server. If an incoming packet does not match any destination, it will be dropped. + - Constraints: The value must match regular expression `/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$/` +- `name` - (Optional, String) The user-defined name for this VPN route. If unspecified, the name will be a hyphenated list of randomly-selected words. Names must be unique within the VPN server the VPN route resides in. + - Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$/` +- `vpn_server_id` - (Required, Forces new resource, String) The VPN server identifier. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `vpn_route` - The identifier of the VPNServerRoute. +- `created_at` - (String) The date and time that the VPN route was created. +- `href` - (String) The URL for this VPN route. + - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/` +- `lifecycle_state` - (String) The lifecycle state of the VPN route. + - Constraints: Allowable values are: deleting, failed, pending, stable, updating, waiting, suspended +- `resource_type` - (String) The resource type. + - Constraints: Allowable values are: vpn_server_route + +## Import + +You can import the `ibm_is_vpn_server_route` resource by using `id`. +The `id` property can be formed from `vpn_server_id`, and `vpn_route` in the following format: +- `vpn_server_id`: A string. The VPN server identifier. +- `vpn_route`: A string. The VPN route identifier. + +``` + r134-0b5b3bed-8c95-4ded-81bf-913bf8ec5fa9/r134-299ed4f0-b279-4db3-8dfe-eff69a9fb66a +``` + +# Syntax +``` +$ terraform import ibm_is_vpn_server_route.is_vpn_server_route r134-0b5b3bed-8c95-4ded-81bf-913bf8ec5fa9/r134-299ed4f0-b279-4db3-8dfe-eff69a9fb66a +``` diff --git a/website/docs/r/kms_key.html.markdown b/website/docs/r/kms_key.html.markdown index d459e6f8f..6aa9e3451 100644 --- a/website/docs/r/kms_key.html.markdown +++ b/website/docs/r/kms_key.html.markdown @@ -13,6 +13,10 @@ This resource can be used for management of keys in both Key Protect and Hyper P After creating an Hyper Protect Crypto Service instance you need to initialize the instance properly with the crypto units, in order to create, or manage Hyper Protect Crypto Service keys. For more information, about how to initialize the Hyper Protect Crypto Service instance, see [Initialize Hyper Protect Crypto](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-initialize-hsm) only for HPCS instance. + ~>**Deprecated:** + The ability to use the ibm_kms_key resource to create or update key policies in Terraform has been removed in favor of a dedicated ibm_kms_key_policies resource. For more information, check out [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key_policies#example-usage-to-create-a-[…]and-associate-a-key-policy) + + ## Example usage to provision Key Protect service and key management ```terraform @@ -28,11 +32,11 @@ resource "ibm_kms_key" "test" { standard_key = false force_delete =true } -resource "ibm_cos_bucket" "flex-us-south" { +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = ibm_kms_key.test.id } ``` @@ -69,58 +73,6 @@ resource "ibm_kms_key" "key" { force_delete = true } ``` -## Example usage to provision KMS key with key policies - -Set policies for a key, as an automatic rotation policy or a dual authorization policy to protect against the accidental deletion of keys. - -```terraform -resource "ibm_resource_instance" "kp_instance" { - name = "test_kp" - service = "kms" - plan = "tiered-pricing" - location = "us-south" -} -resource "ibm_kms_key" "key" { - instance_id = ibm_resource_instance.kp_instance.guid - key_name = "key" - standard_key = false - expiration_date = "2020-12-05T15:43:46Z" - policies { - rotation { - interval_month = 3 - } - dual_auth_delete { - enabled = false - } - } -} -``` - -**Deprecated** : -1) Support for creating Policies along with the Key will be deprecated in future releases. -2) A new resource for creating Key pollicies has been released which can be used to create policies for existing key. -3) Use either "ibm_kms_key" or "ibm_kms_key_policies" to manage key policies but not both together. -4) If both the resources have been utilised to create policies then add licycle ignore block to "ibm_kms_key" resource to avoid any changes kms_key_policies resource to the policies. - -## Lifecycle Ignore Block Example - -``` -resource "ibm_kms_key" "kms_tf_test_key1" { - instance_id = ibm_resource_instance.kms_tf_test1.guid - key_name = "kms_tf_test_key1" - standard_key = false - force_delete = true - policies { - rotation { - interval_month = 8 - } - } - lifecycle { - ignore_changes = [ - policies, - ] - } - ``` ## Example usage to provision KMS and import a key diff --git a/website/docs/r/kms_key_alias.html.markdown b/website/docs/r/kms_key_alias.html.markdown index e2b06ef19..fcf106397 100644 --- a/website/docs/r/kms_key_alias.html.markdown +++ b/website/docs/r/kms_key_alias.html.markdown @@ -30,26 +30,33 @@ resource "ibm_kms_key_alias" "key_alias" { alias = "alias" key_id = "ibm_kms_key.test.key_id" } -resource "ibm_cos_bucket" "flex-us-south" { +OR +resource "ibm_kms_key_alias" "key_alias" { + instance_id = ibm_kms_key.test.instance_id + alias = "alias" + existing_alias = "myalias" +} +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = ibm_kms_key.test.id } ``` -**Note** +**Note** An alias that identifies a key. Each alias is unique only within the given instance and is not reserved across the Key Protect service. Each key can have up to five aliases. There is a limit of 1000 aliases per instance. Alias must be alphanumeric and cannot contain spaces or special characters other than '-' or '_'. ## Argument reference -Review the argument references that you can specify for your resource. +Review the argument references that you can specify for your resource. - `alias` - (Required, Forces new resource, String) The alias name of the key. - `endpoint_type` - (Optional, Forces new resource, String) The type of the public endpoint, or private endpoint to be used for creating keys. - `instance_id` - (Required, Forces new resource, String) The hs-crypto or key protect instance GUID. -- `key_id` - (Required, String) The key ID for which alias has to be created. +- `existing_alias` - (Required - if the key_id is not provided, String) Existing Alias of the key. +- `key_id` - (Required - if the alias is not provided, String) The key ID for which alias has to be created. ## Attribute reference diff --git a/website/docs/r/kms_key_policies.html.markdown b/website/docs/r/kms_key_policies.html.markdown index 4dec24e5a..c61cfe4c6 100644 --- a/website/docs/r/kms_key_policies.html.markdown +++ b/website/docs/r/kms_key_policies.html.markdown @@ -10,6 +10,9 @@ description: |- Provides a resource to manage key policies for Key Protect and Hyper Protect Crypto Service (HPCS) services. This allows key policies to be created and updated. Key policies can be created for an existing kms key resource. +**NOTE** +: `terraform destroy` does not remove the policies of the Key but only clears the state file. Key Policies get deleted when the associated key resource is destroyed. + ## Example usage to create a Key and associate a key policy. @@ -27,7 +30,13 @@ resource "ibm_kms_key" "key" { standard_key = false } -resource "ibm_kms_key_policies" "keyPolicy" { +resource "ibm_kms_key_alias" "key_alias" { + instance_id = ibm_kms_key.test.instance_id + alias = "alias" + key_id = "ibm_kms_key.test.key_id" +} + +resource "ibm_kms_key_policies" "key_policy" { instance_id = ibm_resource_instance.kms_instance.guid key_id = ibm_kms_key.key.key_id rotation { @@ -37,16 +46,26 @@ resource "ibm_kms_key_policies" "keyPolicy" { enabled = false } } +OR +resource "ibm_kms_key_policies" "key_policy" { + instance_id = ibm_resource_instance.kms_instance.guid + alias= ibm_kms_key_alias.key_alias.alias + rotation { + interval_month = 3 + } + dual_auth_delete { + enabled = false + } +} ``` -**NOTE** -1) `terraform destroy` does not remove the policies of the Key but only clears the state file. Key Policies get deleted when the associated key resource is destroyed. - -## Argument Reference +## Argument reference The following arguments are supported: - `endpoint_type` - (Optional, String) The type of the public or private endpoint to be used for fetching policies. +- `key_id` - (Required - if the alias is not provided, String) The ID of the key. +- `alias` - (Required - if the key_id is not provided, String) The alias created for the key. - `instance_id` - (Required, String) The key-protect instance ID for creating policies. - `rotation` - (Optional,list) The key rotation time interval in months, with a minimum of 1, and a maximum of 12. Atleast one of `rotation` and `dual_auth_delete` is required @@ -58,12 +77,13 @@ The following arguments are supported: Nested scheme for `dual_auth_delete`: - `enabled`- (Required, Bool) If set to **true**, Key Protect enables a dual authorization policy on a single key. **Note:** Once the dual authorization policy is set on the key, it cannot be reverted. A key with dual authorization policy enabled cannot be destroyed by using Terraform. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: - `id` - (String) The CRN of the key. - `key_id` - (String) The ID of the key. +- `alias` - (String) The alias of the key. - `rotation` - (List) The key rotation time interval in months, with a minimum of 1, and a maximum of 12. Nested scheme for `rotation`: diff --git a/website/docs/r/kms_key_rings.html.markdown b/website/docs/r/kms_key_rings.html.markdown index cc4267efe..c79b7b567 100644 --- a/website/docs/r/kms_key_rings.html.markdown +++ b/website/docs/r/kms_key_rings.html.markdown @@ -20,14 +20,14 @@ resource "ibm_resource_instance" "kms_instance" { plan = "tiered-pricing" location = "us-south" } -resource "ibm_kms_key_rings" "keyRing" { +resource "ibm_kms_key_rings" "key_ring" { instance_id = ibm_resource_instance.kms_instance.guid key_ring_id = "key-ring-id" } resource "ibm_kms_key" "key" { instance_id = ibm_resource_instance.kp_instance.guid key_name = "key" - key_ring_id = ibm_kms_key_rings.keyRing.key_ring_id + key_ring_id = ibm_kms_key_rings.key_ring.key_ring_id standard_key = false payload = "aW1wb3J0ZWQucGF5bG9hZA==" } diff --git a/website/docs/r/kp_key.html.markdown b/website/docs/r/kp_key.html.markdown index f08cfb216..1fdc4805b 100644 --- a/website/docs/r/kp_key.html.markdown +++ b/website/docs/r/kp_key.html.markdown @@ -9,7 +9,7 @@ description: |- # ibm_kp_key -Create, or delete a Key Protect standard or root key. To use the `ibm_kp_key` resource, the region parameter in the `provider.tf` file must be set to the same region that your Key Protect service instance. If region parameter is not specified, `us-south` is used as default. If the region in the `provider.tf` file is different from the Key Protect instance, the instance cannot be retrieved by Terraform and the Terraform action fails. +Create, or delete a Key Protect standard or root key. To use the `ibm_kp_key` resource, the region parameter in the `provider.tf` file must be set to the same region that your Key Protect service instance. If region parameter is not specified, `us-south` is used as default. If the region in the `provider.tf` file is different from the Key Protect instance, the instance cannot be retrieved by Terraform and the Terraform action fails. **Note** @@ -30,16 +30,16 @@ resource "ibm_kp_key" "test" { key_name = "key-name" standard_key = false } -resource "ibm_cos_bucket" "flex-us-south" { +resource "ibm_cos_bucket" "smart-us-south" { bucket_name = "atest-bucket" resource_instance_id = "cos-instance-id" region_location = "us-south" - storage_class = "flex" + storage_class = "smart" key_protect = ibm_kp_key.test.id } ``` ## Argument reference -Review the argument references that you can specify for your resource. +Review the argument references that you can specify for your resource. - `encrypted_nonce` - (Optional, Forces new resource, String) The encrypted nonce value that verifies your request to import a key to Key Protect. This value must be encrypted by using the key that you want to import to the service. To retrieve a nonce, use the `ibmcloud kp import-token get` command. Then, encrypt the value by running `ibmcloud kp import-token encrypt-nonce`. Only for imported root key. - `force_delete` - (Optional, Bool) If set to **true**, Key Protect forces the deletion of a root or standard key, even if this key is still in use, such as to protect an IBM Cloud Object Storage bucket. Note, the key cannot be deleted if the protected cloud resource is set up with a retention policy. Successful deletion includes the removal of any registrations that are associated with the key. Default value is **false**. **Note** Before executing Terraform destroy if `force_delete` flag is introduced after provisioning keys, a Terraform apply must be done before Terraform destroy for `force_delete` flag to take effect. diff --git a/website/docs/r/pi_capture.html.markdown b/website/docs/r/pi_capture.html.markdown new file mode 100644 index 000000000..f19f9579b --- /dev/null +++ b/website/docs/r/pi_capture.html.markdown @@ -0,0 +1,92 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_capture" +description: |- + Manages IBM Capture instance in the Power Virtual Server cloud. +--- + +# ibm_pi_capture +Create or delete for Capture Power System Virtual Server Instance + +**Note:-** +If `pi_capture_destination` is `Cloud-Storage` then delete bucket object functionality not supported by this resource , hence user need to delete bucket object manually from `Cloud Storage bucket`. + +For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). +## Example usage +The following example creates a Capture Power System Virtual Server Instance. + +```terraform +resource "ibm_pi_capture" "test_capture" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" + pi_capture_name = "terraform-test-capture" + pi_instance_name = "terraform-test-instance" + pi_capture_destination = "image-catalog" +} +``` +```terraform +resource "ibm_pi_capture" "test_capture" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" + pi_capture_name = "test-capture" + pi_instance_name = "test-vm" + pi_capture_destination = "cloud-storage" + pi_capture_cloud_storage_region = "us-east" + pi_capture_cloud_storage_access_key = "" + pi_capture_cloud_storage_secret_key = "" + pi_capture_storage_image_path = "test-bucket" +} +``` +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` +## Timeouts + +ibm_pi_capture provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 75 minutes) Used for creating capture instance . +- **delete** - (Default 50 minutes) Used for deleting capture instance. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_capture_name` - (Required, String) Name of the deployable image created for the captured PVMInstance. +- `pi_instance_name` - (Required, String) The name of the instance. +- `pi_capture_destination`- (Required, String) Destination for the deployable image. +`[image-catalog,cloud-storage,both]` +- `pi_capture_volume_ids`- (Optional, List of String) List of Data volume IDs to include in the captured PVMInstance. +- `pi_capture_cloud_storage_region`- (Optional,String) Cloud Storage Region +- `pi_capture_cloud_storage_access_key`- (Optional,String) Cloud Storage Access key +- `pi_capture_cloud_storage_secret_key`- (Optional,String) Cloud Storage Secret key +- `pi_capture_storage_image_path` - (Optional,String) Cloud Storage Image Path (bucket-name [/folder/../..]) + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The image id of the capture instance. The ID is composed of `//`. +- `image_id` - (String) The image id of the capture instance. + + +## Import + +The `ibm_pi_capture` resource can be imported by using `pi_cloud_instance_id` `pi_capture_name` and `pi_capture_destination`. + +**Example** +``` +$ terraform import ibm_pi_capture.example d7bec597-4726-451f-8a63-e62e6f19c32c/test-capture/image-catalog + +``` + diff --git a/website/docs/r/pi_cloud_connection.html.markdown b/website/docs/r/pi_cloud_connection.html.markdown new file mode 100644 index 000000000..6425e125a --- /dev/null +++ b/website/docs/r/pi_cloud_connection.html.markdown @@ -0,0 +1,88 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_cloud_connection" +description: |- + Manages IBM Cloud connection in the Power Virtual Server cloud. +--- + +# ibm_pi_cloud_connection + +Create, update, or delete for a Power Systems Virtual Server cloud connection. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +The following example enables you to create a cloud connection: + +```terraform +resource "ibm_pi_cloud_connection" "cloud_connection" { + pi_cloud_instance_id = "" + pi_cloud_connection_name = "test_cloud_connection" + pi_cloud_connection_speed = 50 +} +``` + +**Note** + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + + - `region` - `lon` + - `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_cloud_connection` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The creation of the cloud connection is considered failed if no response is received for 30 minutes. +- **Update** The updation of the cloud connection is considered failed if no response is received for 30 minutes. +- **Delete** The deletion of the cloud connection is considered failed if no response is received for 30 minutes. + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_cloud_connection_classic_enabled` - (Optional, Bool) Enable classic endpoint destination. +- `pi_cloud_connection_global_routing` - (Optional, Bool) Enable global routing for this cloud connection. +- `pi_cloud_connection_gre_cidr` - (Optional, String) The GRE network in CIDR notation. +- `pi_cloud_connection_gre_destination_address` - (Optional, String) The GRE destination IP address. +- `pi_cloud_connection_metered` - (Optional, Bool) Enable metered for this cloud connection. +- `pi_cloud_connection_name` - (Required, String) The name of the cloud connection. +- `pi_cloud_connection_networks` - (Optional, Set of String) Set of Networks to attach to this cloud connection. +- `pi_cloud_connection_speed` - (Required, String) Speed of the cloud connection (speed in megabits per second). Supported values are `50`, `100`, `200`, `500`, `1000`, `2000`, `5000`, `10000`. +- `pi_cloud_connection_vpc_enabled` - (Optional, Bool) Enable VPC for this cloud connection. +- `pi_cloud_connection_vpc_crns` - (Optional, Set of String) Set of VPC CRNs to attach to this cloud connection. +- `pi_cloud_connection_transit_enabled` - (Optional, Bool) Enable transit gateway for this cloud connection. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of cloud connection. +- `cloud_connection_id` - (String) The cloud connection ID. +- `connection_mode` - (String) Type of service the gateway is attached to. +- `gre_source_address` - (String) The GRE auto-assigned source IP address. +- `ibm_ip_address` - (String) The IBM IP address. +- `port` - (String) Port. +- `status` - (String) Link status. +- `user_ip_address` - (String) User IP address. + +## Import + +The `ibm_pi_cloud_connection` can be imported by using `power_instance_id` and `cloud_connection_id`. + +**Example** + +```sh +$ terraform import ibm_pi_cloud_connection.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_cloud_connection_network_attach.html.markdown b/website/docs/r/pi_cloud_connection_network_attach.html.markdown new file mode 100644 index 000000000..d562c7770 --- /dev/null +++ b/website/docs/r/pi_cloud_connection_network_attach.html.markdown @@ -0,0 +1,72 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_cloud_connection_network_attach" +description: |- + Manages IBM Cloud Connection Network attachment in the Power Virtual Server cloud. +--- + +# ibm_pi_cloud_connection_network_attach + +Attach, detach Network to a Cloud Connection for a Power Systems Virtual Server. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +The following example enables you attach a network to a cloud connection: + +```terraform +resource "ibm_pi_cloud_connection_network_attach" "example" { + pi_cloud_instance_id = "" + pi_cloud_connection_id = "" + pi_network_id = "" +} +``` + +**Note** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_cloud_connection_network_attach` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The attach of network to the cloud connection is considered failed if no response is received for 30 minutes. +- **Delete** The detach of network from the cloud connection is considered failed if no response is received for 30 minutes. + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_cloud_connection_id` - (Required, String) The Cloud Connection ID. +- `pi_network_id` - (Required, String) The Network ID to attach to this cloud connection. + + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of cloud connection network attachment. + +## Import + +The `ibm_pi_cloud_connection_network_attach` can be imported by using `pi_cloud_instance_id`, `pi_cloud_connection_id` and `pi_network_id`. + +**Example** + +```sh +$ terraform import ibm_pi_cloud_connection_network_attach.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb/4726d7be-c597-4438-9f8a-cea6651abc0a +``` diff --git a/website/docs/r/pi_console_language.html.markdown b/website/docs/r/pi_console_language.html.markdown new file mode 100644 index 000000000..9d3d57444 --- /dev/null +++ b/website/docs/r/pi_console_language.html.markdown @@ -0,0 +1,60 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_console_language" +description: |- + Manages Instance Console Languages in the Power Virtual Server cloud. +--- + +# ibm_pi_console_language + +Update the Console Language of a Server for your Power Systems Virtual Server instance. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example enables you to update the Console Languages of a Server: + +```terraform +resource "ibm_pi_console_language" "example" { + pi_cloud_instance_id = "" + pi_instance_name = "" + pi_language_code = "" +} +``` + +**Note** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_console_language` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 5 minutes) Used for setting a console language. +- **update** - (Default 5 minutes) Used for updating a console language. + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_name` - (Required, String) The unique identifier or name of the instance. +- `pi_language_code` - (Required, String) Language code. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the instance console language. The ID is composed of `/`. diff --git a/website/docs/r/pi_dhcp.html.markdown b/website/docs/r/pi_dhcp.html.markdown new file mode 100644 index 000000000..b39b0b9c8 --- /dev/null +++ b/website/docs/r/pi_dhcp.html.markdown @@ -0,0 +1,76 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_dhcp" +description: |- + Manages IBM DHCP Server in the Power Virtual Server cloud. +--- + +# ibm_pi_dhcp + +Create, update, or delete DHCP Server for your Power Systems Virtual Server instance. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example enables you to create a DHCP Server: + +```terraform +resource "ibm_pi_dhcp" "example" { + pi_cloud_instance_id = "" +} +``` +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_cidr` - (Optional, String) The CIDR for the DHCP private network. +- `pi_cloud_connection_id` - (Optional, String) The Cloud Connection UUID to connect with the DHCP private network. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_dhcp_name` - (Optional, String) The name of the DHCP Service that will be prefixed by the DHCP identifier. +- `pi_dhcp_snat_enabled` - (Optional, Bool) Indicates if SNAT will be enabled for the DHCP service. The default value is **true**. +- `pi_dns_server` - (Optional, String) The DNS Server for the DHCP service. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `dhcp_id` - (String) The ID of the DHCP Server. +- `id` - (String) The unique identifier of the DHCP Server. The ID is composed of `/`. +- `leases` - (List) The list of DHCP Server PVM Instance leases. + Nested scheme for `leases`: + - `instance_ip` - (String) The IP of the PVM Instance. + - `instance_mac` - (String) The MAC Address of the PVM Instance. +- `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). +- `network_id`- (String) The ID of the DHCP Server private network. +- `network_name` - The name of the DHCP Server private network. +- `status` - (String) The status of the DHCP Server. + +## Timeouts + +The `ibm_pi_dhcp` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 30 minutes) Used for creating a DHCP Server. +- **delete** - (Default 10 minutes) Used for deleting a DHCP Server. + +**Note** + +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` +## Import + +The `ibm_pi_dhcp` resource can be imported by using `pi_cloud_instance_id` and `dhcp_id`. + +```terraform +terraform import ibm_pi_dhcp.example d7bec597-4726-451f-8a63-e62e6f19c32c/0e48e1be-9f54-4a67-ba55-7e31ce98b65a +``` \ No newline at end of file diff --git a/website/docs/r/pi_image.html.markdown b/website/docs/r/pi_image.html.markdown index a6660a902..f7a0bab0d 100644 --- a/website/docs/r/pi_image.html.markdown +++ b/website/docs/r/pi_image.html.markdown @@ -21,6 +21,18 @@ resource "ibm_pi_image" "testacc_image "{ } ``` +```terraform +resource "ibm_pi_image" "testacc_image "{ + pi_image_name = "test_image" + pi_cloud_instance_id = "" + pi_image_bucket_name = "images-public-bucket" + pi_image_bucket_access = "public" + pi_image_bucket_region = "us-south" + pi_image_bucket_file_name = "rhcos-48-07222021.ova.gz" + pi_image_storage_type = "tier1" +} +``` + **Note** * Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. * If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: @@ -46,19 +58,39 @@ The ibm_pi_image provides the following [timeouts](https://www.terraform.io/ ## Argument reference Review the argument references that you can specify for your resource. -- `pi_image_name` - (Required, String) The name of an image. -- `pi_image_id` - (Required, String) The ID of an image. +- `pi_affinity_instance` - (Optional, String) PVM Instance (ID or Name) to base storage affinity policy against; required if requesting `affinity` and `pi_affinity_volume` is not provided. +- `pi_affinity_policy` - (Optional, String) Affinity policy for image; ignored if `pi_image_storage_pool` provided; for policy affinity requires one of `pi_affinity_instance` or `pi_affinity_volume` to be specified; for policy anti-affinity requires one of `pi_anti_affinity_instances` or `pi_anti_affinity_volumes` to be specified; Allowable values: `affinity`, `anti-affinity` +- `pi_affinity_volume`- (Optional, String) Volume (ID or Name) to base storage affinity policy against; required if requesting `affinity` and `pi_affinity_instance` is not provided. +- `pi_anti_affinity_instances` - (Optional, String) List of pvmInstances to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_volumes` is not provided. +- `pi_anti_affinity_volumes`- (Optional, String) List of volumes to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_instances` is not provided. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_image_name` - (Required, String) The name of an image. +- `pi_image_id` - (Optional, String) Image ID of existing source image; required for copy image. + - Either `pi_image_id` or `pi_image_bucket_name` is required. +- `pi_image_bucket_name` - (Optional, String) Cloud Object Storage bucket name; `bucket-name[/optional/folder]` + - Either `pi_image_bucket_name` or `pi_image_id` is required. +- `pi_image_access_key` - (Optional, String, Sensitive) Cloud Object Storage access key; required for buckets with private access. + - `pi_image_access_key` is required with `pi_image_secret_key` +- `pi_image_bucket_access` - (Optional, String) Indicates if the bucket has public or private access. The default value is `public`. +- `pi_image_bucket_file_name` - (Optional, String) Cloud Object Storage image filename + - `pi_image_bucket_file_name` is required with `pi_image_bucket_name` +- `pi_image_bucket_region` - (Optional, String) Cloud Object Storage region + - `pi_image_bucket_region` is required with `pi_image_bucket_name` +- `pi_image_secret_key` - (Optional, String, Sensitive) Cloud Object Storage secret key; required for buckets with private access. + - `pi_image_secret_key` is required with `pi_image_access_key` +- `pi_image_storage_pool` - (Optional, String) Storage pool where the image will be loaded, if provided then `pi_image_storage_type` and `pi_affinity_policy` will be ignored. +- `pi_image_storage_type` - (Optional, String) Type of storage. Will be ignored if `pi_image_storage_pool` or `pi_affinity_policy` is provided. If only using `pi_image_storage_type` for storage selection then the storage pool with the most available space will be selected. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `id` - (String) The unique identifier of an image. +- `id` - (String) The unique identifier of an image. The ID is composed of `/`. - `image_id` - (String) The unique identifier of an image. ## Import -The `ibm_pi_image` can be imported by using `power_instance_id` and `image_id`. +The `ibm_pi_image` can be imported by using `pi_cloud_instance_id` and `image_id`. **Example** diff --git a/website/docs/r/pi_image_export.html.markdown b/website/docs/r/pi_image_export.html.markdown new file mode 100644 index 000000000..7b1ccfaad --- /dev/null +++ b/website/docs/r/pi_image_export.html.markdown @@ -0,0 +1,65 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_image_export" +description: |- + Exports IBM Image to IBM Cloud Object Storage in the Power Virtual Server cloud. +--- + +# ibm_pi_image_export +Export an image to IBM Cloud Object Storage for Power Systems Virtual Server instance. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example enables you to export an image: + +```terraform +resource "ibm_pi_image_export" "testacc_image_export"{ + pi_cloud_instance_id = "" + pi_image_id = "test_image" + pi_image_bucket_name = "images-public-bucket" + pi_image_bucket_region = "us-south" + pi_image_access_key = "dummy-access-key" + pi_image_secret_key = "dummy-secret-key" +} +``` + +**Note** +* Ensure the exported file is cleaned up manually from the Cloud Object Storage when no longer needed. Power Systems Virtual Server does not support deleting the exported image. Updating any attribute will result in creating a new Export job. +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The ibm_pi_image provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The export image to IBM Cloud Object Storage bucket is considered failed if no response is received for 60 minutes. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_image_id` - (Required, String) The Image ID of existing source image; required for image export. +- `pi_image_bucket_name` - (Required, String) The Cloud Object Storage bucket name; `bucket-name[/optional/folder]` +- `pi_image_access_key` - (Required, String, Sensitive) The Cloud Object Storage access key; required for buckets with private access. +- `pi_image_bucket_region` - (Required, String) The Cloud Object Storage region +- `pi_image_secret_key` - (Required, String, Sensitive) The Cloud Object Storage secret key; required for buckets with private access. + + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of an image export resource. The ID is composed of `//`. + diff --git a/website/docs/r/pi_instance.html.markdown b/website/docs/r/pi_instance.html.markdown index 14a05affb..370bdfa8e 100644 --- a/website/docs/r/pi_instance.html.markdown +++ b/website/docs/r/pi_instance.html.markdown @@ -50,8 +50,9 @@ resource "ibm_pi_instance" "test-instance" { The `ibm_pi_instance` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -- **create** - The creation of the instance is considered failed if no response is received for 60 minutes. -- **delete** - The deletion of the instance is considered failed if no response is received for 60 minutes. +- **create** - The creation of the instance is considered failed if no response is received for 120 minutes. +- **Update** The updation of the instance is considered failed if no response is received for 60 minutes. +- **delete** - The deletion of the instance is considered failed if no response is received for 60 minutes. ## Argument reference @@ -63,59 +64,57 @@ Review the argument references that you can specify for your resource. - `pi_anti_affinity_instances` - (Optional, String) List of pvmInstances to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_volumes` is not provided. - `pi_anti_affinity_volumes`- (Optional, String) List of volumes to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_instances` is not provided. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_deployment_type` - (Optional, String) Custom deployment type; Allowable value: `EPIC`. - `pi_health_status` - (Optional, String) Specifies if Terraform should poll for the health status to be `OK` or `WARNING`. The default value is `OK`. - `pi_image_id` - (Required, String) The ID of the image that you want to use for your Power Systems Virtual Server instance. The image determines the operating system that is installed in your instance. To list available images, run the `ibmcloud pi images` command. - `pi_instance_name` - (Required, String) The name of the Power Systems Virtual Server instance. -- `pi_key_pair_name` - (Required, String) The name of the SSH key that you want to use to access your Power Systems Virtual Server instance. The SSH key must be uploaded to IBM Cloud. -- `pi_memory` - (Required, Float) The amount of memory that you want to assign to your instance in gigabytes. +- `pi_key_pair_name` - (Optional, String) The name of the SSH key that you want to use to access your Power Systems Virtual Server instance. The SSH key must be uploaded to IBM Cloud. +- `pi_license_repository_capacity` - (Optional, Integer) The VTL license repository capacity TB value. Only use with VTL instances. `pi_memory >= 16 + (2 * pi_license_repository_capacity)`. + - **Note**: Provisioning VTL instances is temporarily disabled. +- `pi_memory` - (Optional, Float) The amount of memory that you want to assign to your instance in gigabytes. + - Required when not creating SAP instances. Conflicts with `pi_sap_profile_id`. - `pi_migratable`- (Optional, Bool) Indicates the VM is migrated or not. -- `pi_network_ids` - (Required, List of String) The list of network IDs that you want to assign to the instance. This attribute is **Deprecated** use `pi_network` instead. -- `pi_network` - (Required, List of Map) List of one or more networks to attach to the instance. The `pi_network` object structure is documented below. +- `pi_network` - (Required, List of Map) List of one or more networks to attach to the instance. + + The `pi_network` block supports: + - `network_id` - (String) The network ID to assign to the instance. + - `ip_address` - (String) The ip address to be used of this network. - `pi_pin_policy` - (Optional, String) Select the pinning policy for your Power Systems Virtual Server instance. Supported values are `soft`, `hard`, and `none`. **Note** You can choose to soft pin (`soft`) or hard pin (`hard`) a virtual server to the physical host where it runs. When you soft pin an instance for high availability, the instance automatically migrates back to the original host once the host is back to its operating state. If the instance has a licensing restriction with the host, the hard pin option restricts the movement of the instance during remote restart, automated remote restart, DRO, and live partition migration. The default pinning policy is `none`. -- `pi_processors` - (Required, Float) The number of vCPUs to assign to the VM as visible within the guest Operating System. -- `pi_proc_type` - (Required, String) The type of processor mode in which the VM will run with `shared` or `dedicated`. -- `pi_replicants` - (Optional, Float) The number of instances that you want to provision with the same configuration. If this parameter is not set, `1` is used by default. -- `pi_replication_policy` - (Optional, String) The replication policy that you want to use. If this parameter is not set, `none` is used by default. +- `pi_placement_group_id` - (Optional, String) The ID of the placement group that the instance is in or empty quotes `""` to indicate it is not in a placement group. The meta-argument `count` and a `pi_replicants` cannot be used when specifying a placement group ID. Instances provisioning in the same placement group must be provisioned one at a time; however, to provision multiple instances on the same host or different hosts then use `pi_replicants` and `pi_replication_policy` instead of `pi_placement_group_id`. +- `pi_processors` - (Optional, Float) The number of vCPUs to assign to the VM as visible within the guest Operating System. + - Required when not creating SAP instances. Conflicts with `pi_sap_profile_id`. +- `pi_proc_type` - (Optional, String) The type of processor mode in which the VM will run with `shared`, `capped` or `dedicated`. + - Required when not creating SAP instances. Conflicts with `pi_sap_profile_id`. +- `pi_replicants` - (Optional, Integer) The number of instances that you want to provision with the same configuration. If this parameter is not set, `1` is used by default. +- `pi_replication_policy` - (Optional, String) The replication policy that you want to use, either `affinity`, `anti-affinity` or `none`. If this parameter is not set, `none` is used by default. - `pi_replication_scheme` - (Optional, String) The replication scheme that you want to set, either `prefix` or `suffix`. +- `pi_sap_profile_id` - (Optional, String) SAP Profile ID for the amount of cores and memory. + - Required only when creating SAP instances. +- `pi_sap_deployment_type` - (Optional, String) Custom SAP deployment type information (For Internal Use Only). +- `pi_shared_processor_pool` - (Optional, String) The shared processor pool for instance deployment. Conflicts with `pi_sap_profile_id`. - `pi_storage_pool` - (Optional, String) Storage Pool for server deployment; if provided then `pi_affinity_policy` and `pi_storage_type` will be ignored. +- `pi_storage_pool_affinity` - (Optional, Bool) Indicates if all volumes attached to the server must reside in the same storage pool. The default value is `true`. To attach data volumes from a different storage pool (mixed storage) set to `false` and use `pi_volume_attach` resource. Once set to `false`, cannot be set back to `true` unless all volumes attached reside in the same storage type and pool. - `pi_storage_type` - (Optional, String) - Storage type for server deployment. Only valid when you deploy one of the IBM supplied stock images. Storage type for a custom image (an imported image or an image that is created from a VM capture) defaults to the storage type the image was created in - `pi_storage_connection` - (Optional, String) - Storage Connectivity Group (SCG) for server deployment. Only supported value is `vSCSI`. -- `pi_sys_type` - (Required, String) The type of system on which to create the VM (s922/e880/any). +- `pi_sys_type` - (Optional, String) The type of system on which to create the VM (s922/e880/e980/e1080/s1022). + - Supported SAP system types are (e880/e980/e1080). - `pi_user_data` - (Optional, String) The base64 encoded form of the user data `cloud-init` to pass to the instance during creation. - `pi_virtual_cores_assigned` - (Optional, Integer) Specify the number of virtual cores to be assigned. -- `pi_volume_ids` - (Required, List of String) The list of volume IDs that you want to attach to the instance during creation. - -The `pi_network` block supports: - - `network_id` - (String) The network ID to assign to the instance. - - `ip_address` - (String) The ip address to be used of this network. - +- `pi_volume_ids` - (Optional, List of String) The list of volume IDs that you want to attach to the instance during creation. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `addresses` - Map of strings - A list of addresses that are assigned to the instance. This attribute is **Deprecated** use `pi_network` instead. - - Nested scheme for `addresses`: - - `ip` - (String) The IP address of the instance. - - `macaddress` - (String) The MAC address of the instance. - - `networkid` - (String) The network ID of the instance. - - `network_name` - (String) The network name of the instance. - - `type` - (String) The type of network. - - `external_ip` - (String) The external IP address of the instance. - `health_status` - (String) The health status of the VM. - `id` - (String) The unique identifier of the instance. The ID is composed of `/`. - `instance_id` - (String) The unique identifier of the instance. - `max_processors`- (Float) The maximum number of processors that can be allocated to the instance with shutting down or rebooting the `LPAR`. - `max_virtual_cores` - (Integer) The maximum number of virtual cores. -- `migratable` - (Bool) Indicates the VM is migrated or not.This attribute is Deprecated use `pi_migratable` instead - `min_processors` - (Float) The minimum number of processors that the instance can have. - `min_memory` - (Float) The minimum memory that was allocated to the instance. - `max_memory`- (Float) The maximum amount of memory that can be allocated to the instance without shut down or reboot the `LPAR`. - `min_virtual_cores` - (Integer) The minimum number of virtual cores. -- `status` - (String) The status of the instance. - `pin_policy` - (String) The pinning policy of the instance. -- `progress` - (Float) - Specifies the overall progress of the instance deployment process in percentage. - `pi_network` - (List of Map) - A list of networks that are assigned to the instance. - Nested scheme for `pi_network`: - `ip_address` - (String) The IP address of the network. - `mac_address` - (String) The MAC address of the network. @@ -123,7 +122,9 @@ In addition to all argument reference list, you can access the following attribu - `network_name` - (String) The name of the network. - `type` - (String) The type of network. - `external_ip` - (String) The external IP address of the network. - +- `progress` - (Float) - Specifies the overall progress of the instance deployment process in percentage. +- `shared_processor_pool_id` - (String) The ID of the shared processor pool for the instance. +- `status` - (String) The status of the instance. ## Import The `ibm_pi_instance` can be imported using `power_instance_id` and `instance_id`. diff --git a/website/docs/r/pi_instance_action.html.markdown b/website/docs/r/pi_instance_action.html.markdown new file mode 100644 index 000000000..1b8d0b99b --- /dev/null +++ b/website/docs/r/pi_instance_action.html.markdown @@ -0,0 +1,72 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_instance_action" +description: |- + Performs an action start, stop, reboot, immediate-shutdown, reset on a p VM instance. +--- + +# ibm_pi_instance_action +Performs an action on a [Power Systems Virtual Server instance](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-power-virtual-server). + +## Example usage +The following example perform an action "hard-reboot" on a Power Systems Virtual Server instance. + +```terraform +resource "ibm_pi_instance_action" "example" { + pi_cloud_instance_id = "d7bec597-4726-451f-8a63-e62e6f19c32c" + pi_instance_id = "cea6651a-bc0a-4438-9f8a-a0770b112ebb" + pi_action = "hard-reboot" +} + +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_instance_action` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - The action on the instance is considered failed if no response is received for 15 minutes. +- **Update** The update action on the instance is considered failed if no response is received for 15 minutes. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_action` - (Required, String) Name of the action to take. Allowed values are `start`, `stop`, `hard-reboot`, `soft-reboot`, `immediate-shutdown`, `reset-state`. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_health_status` - (Optional, String) Specifies if Terraform should poll for the health status to be `OK` or `WARNING`. The default value is `OK`. Ignored for `pi_action = "reset-state"`. +- `pi_instance_id` - (Required, String) Custom deployment type information (For Internal Use Only). + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `health_status` - (String) The health status of the VM. +- `id` - (String) The unique identifier of the instance. The ID is composed of `/`. +- `progress` - (Float) - The progress of the instance. +- `status` - (String) - The status of the instance. + +## Import + +The `ibm_pi_instance_action` can be imported using `cloud_instance_id` and `instance_id`. + +**Example** + +``` +$ terraform import ibm_pi_instance_action.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770b112ebb +``` diff --git a/website/docs/r/pi_key.html.markdown b/website/docs/r/pi_key.html.markdown index 66eb24443..d43ef988c 100644 --- a/website/docs/r/pi_key.html.markdown +++ b/website/docs/r/pi_key.html.markdown @@ -21,6 +21,29 @@ resource "ibm_pi_key" "testacc_sshkey" { } ``` +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. +- `pi_key_name` - (Required, String) User defined name for the SSH key. +- `pi_ssh_key` - (Required, String) SSH RSA key. + +## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the key. The ID is composed of `/`. +- `key_id` - (String) User defined name for the SSH key (deprecated - replaced by `name`). +- `name` - (String) User defined name for the SSH key +- `creation_date` - (String) Date of SSH Key creation. +- `ssh_key` - (String) SSH RSA key. + +## Timeouts + +ibm_pi_key provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for creating a SSH key. +- **delete** - (Default 60 minutes) Used for deleting a SSH key. + **Note** * Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. * If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: @@ -35,36 +58,12 @@ resource "ibm_pi_key" "testacc_sshkey" { zone = "lon04" } ``` - -## Timeouts - -ibm_pi_key provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - -- **create** - (Default 60 minutes) Used for creating a SSH key. -- **delete** - (Default 60 minutes) Used for deleting a SSH key. - - -## Argument reference -Review the argument references that you can specify for your resource. - -- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. -- `pi_creation_date` - (Optional, String) The date when the SSH key was created. -- `pi_key_name` - (Required, Integer) The name of the SSH key that you uploaded to IBM Cloud. -- `pi_ssh_key` - (Required, String) The value of the public SSH key. - - -## Attribute reference - In addition to all argument reference list, you can access the following attribute reference after your resource is created. - -- `id` - (String) The unique identifier of the key. The ID is composed of `/`. -- `key_id` - (String) The unique identifier of the key. - ## Import -The `ibm_pi_key` resource can be imported by using `power_instance_id` and `ssh_key_name`. +The `ibm_pi_key` resource can be imported by using `pi_cloud_instance_id` and `pi_key_name`. **Example** ``` $ terraform import ibm_pi_key.example d7bec597-4726-451f-8a63-e62e6f19c32c/mykey -``` +``` \ No newline at end of file diff --git a/website/docs/r/pi_network.html.markdown b/website/docs/r/pi_network.html.markdown index b9ebcfacc..b0016a7d7 100644 --- a/website/docs/r/pi_network.html.markdown +++ b/website/docs/r/pi_network.html.markdown @@ -10,7 +10,7 @@ description: |- # ibm_pi_network Create, update, or delete a network connection for your Power Systems Virtual Server instance. For more information, about power virtual server instance network, see [setting up an IBM i network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-preparing-install-server). -## Example Usage +## Example usage The following example creates a network connection for your Power Systems Virtual Server instance. ```terraform @@ -21,6 +21,11 @@ resource "ibm_pi_network" "power_networks" { pi_network_type = "vlan" pi_cidr = "" pi_dns = [<"DNS Servers">] + pi_gateway = "192.168.0.1" + pi_ipaddress_range { + pi_starting_ip_address = "192.168.0.2" + pi_ending_ip_address = "192.168.0.254" + } } ``` @@ -44,6 +49,7 @@ resource "ibm_pi_network" "power_networks" { The `ibm_pi_network` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - **create** - (Default 60 minutes) Used for creating a network. +- **update** - (Default 60 minutes) Used for updating a network. - **delete** - (Default 60 minutes) Used for deleting a network. ## Argument reference @@ -52,16 +58,21 @@ Review the argument references that you can specify for your resource. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. - `pi_network_name` - (Required, String) The name of the network. - `pi_network_type` - (Required, String) The type of network that you want to create, such as `pub-vlan` or `vlan`. -- `pi_dns`-List of strings-Optional-List of DNS entries for the network. Required for `vlan` network type. +- `pi_dns` - (Optional, Set of String) The DNS Servers for the network. Required for `vlan` network type. - `pi_cidr` - (Optional, String) The network CIDR. Required for `vlan` network type. +- `pi_gateway` - (Optional, String) The gateway ip address. +- `pi_ipaddress_range` - (Optional, List of Map) List of one or more ip address range. The `pi_ipaddress_range` object structure is documented below. + The `pi_ipaddress_range` block supports: + - `pi_ending_ip_address` - (Required, String) The ending ip address. + - `pi_starting_ip_address` - (Required, String) The staring ip address. **Note** if the `pi_gateway` or `pi_ipaddress_range` is not provided, it will calculate the value based on CIDR respectively. - `pi_network_jumbo` - (Optional, Bool) MTU Jumbo option of the network. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The unique identifier of the network. The ID is composed of `/`. -- `networkid` - (String) The unique identifier of the network. -- `vlanid` - (Integer) The ID of the VLAN that your network is attached to. +- `network_id` - (String) The unique identifier of the network. +- `vlan_id` - (Integer) The ID of the VLAN that your network is attached to. ## Import The `ibm_pi_network` resource can be imported by using `power_instance_id` and `network_id`. diff --git a/website/docs/r/pi_network_port.html.markdown b/website/docs/r/pi_network_port.html.markdown index d9b85350a..afcb10662 100644 --- a/website/docs/r/pi_network_port.html.markdown +++ b/website/docs/r/pi_network_port.html.markdown @@ -12,15 +12,15 @@ description: |- Creates or updates network port in the Power Virtual Server Cloud. For more information, about network in IBM power virutal server, see [adding or removing a public network ](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-modifying-server#adding-removing-network).. -## Example Usage +## Example usage In the following example, you can create an network_port: ```terraform resource "ibm_pi_network_port" "test-network-port" { pi_network_name = "Zone1-CFN" - pi_cloud_instance_id = "51e1879c-bcbe-4ee1-a008-49cdba0eaf60" - pi_network_port_description = "IP Reserved for Oracle RAC " + pi_cloud_instance_id = "51e1879c-bcbe-4ee1-a008-49cdba0eaf60" + pi_network_port_description = "IP Reserved for Oracle RAC " } ``` @@ -47,17 +47,17 @@ ibm_pi_network_port provides the following [timeouts](https://www.terraform.io/d - **delete** - (Default 60 minutes) Used for deleting a network_port. ## Argument reference -Review the argument references that you can specify for your resource. +Review the argument references that you can specify for your resource. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_network_name` - (Required, String) Network ID or name. - `pi_network_port_description` - (Optional, String) The description for the Network Port. -- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. -- `pi_instance_name` - (Required, String) The name of the VM. +- `pi_network_port_ipaddress` - (Optional, String) The requested ip address of this port. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `id` - (String) The unique identifier of the instance. The ID is composed of /. -- `ipaddress` - (String) The unique identifier of the instance. +- `id` - (String) The unique identifier of the instance. The ID is composed of `//`. - `macaddress` - (String) The MAC address of the port. - `portid` - (String) The ID of the port. - `public_ip` - (String) The public IP associated with the port. diff --git a/website/docs/r/pi_network_port_attach.html.markdown b/website/docs/r/pi_network_port_attach.html.markdown new file mode 100644 index 000000000..de0c14dfa --- /dev/null +++ b/website/docs/r/pi_network_port_attach.html.markdown @@ -0,0 +1,77 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_network_port_attach" +description: |- + Manages an Network Port Attachments in the Power Virtual Server Cloud. +--- + +# ibm_pi_network_port_attach +Attaches network port in the Power Virtual Server Cloud. For more information, about network in IBM power virutal server, see [adding or removing a public network +](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-modifying-server#adding-removing-network).. + +## Example usage + +In the following example, you can create an network_port_attach resource: + +```terraform +resource "ibm_pi_network_port_attach" "test-network-port-attach" { + pi_cloud_instance_id = "" + pi_instance_id = "" + pi_network_name = "" + pi_network_port_description = "" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_network_port_attach provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for attaching a network port. +- **delete** - (Default 60 minutes) Used for detaching a network port. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_id` - (Required, String) The ID of the pvm instance to attach the network port to. +- `pi_network_name` - (Required, String) The network ID or name. +- `pi_network_port_description` - (Optional, String) The description for the Network Port. +- `pi_network_port_ipaddress` - (Optional, String) The requested ip address of this port. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the instance. The ID is composed of `//`. +- `macaddress` - (String) The MAC address of the port. +- `network_port_id` - (String) The ID of the port. +- `portid` - (Deprecated, String) The ID of the port. +- `public_ip` - (String) The public IP associated with the port. +- `status` - (String) The status of the port. + + +## Import + +The `ibm_pi_network_port` resource can be imported by using `power_instance_id`, `pi_network_name` and `port_id`. + +**Example** + +``` +$ terraform import ibm_pi_network_port_attach.example d7bec597-4726-451f-8a63-e62e6f19c32c/network-name/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_placement_group.html.markdown b/website/docs/r/pi_placement_group.html.markdown new file mode 100644 index 000000000..a731f272a --- /dev/null +++ b/website/docs/r/pi_placement_group.html.markdown @@ -0,0 +1,70 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_placement_group" +description: |- + Manages a placement group in the Power Virtual Server cloud. +--- + +# ibm_pi_placement_group +Create or delete a placement group. + +## Example usage +The following example enables you to create a placement group with a group policy of affinity: + +```terraform +resource "ibm_pi_placement_group" "testacc_placement_group" { + pi_placement_group_name = "my_pg" + pi_placement_group_policy = "affinity" + pi_cloud_instance_id = "" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_placement_group provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for creating a placement group. +- **delete** - (Default 60 minutes) Used for deleting a placement group. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_placement_group_name` - (Required, String) The name of the placement group. +- `pi_placement_group_policy` - (Required, String) The value of the group's affinity policy. Valid values are `affinity` and `anti-affinity`. + + +## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the placement group. +- `members` - (List of strings) The list of server instances IDs that are members of the placement group. +- `placement_group_id` - (String) The placement group ID. + +## Import + +The `ibm_pi_placement_group` resource can be imported by using `power_instance_id` and `placement_group_id`. + +**Example** + +``` +$ terraform import ibm_pi_placement_group.example d7bec597-4726-451f-8a63-e62e6f19c32c/b17a2b7f-77ab-491c-811e-495f8d4c8947 +``` diff --git a/website/docs/r/pi_shared_processor_pool.html.markdown b/website/docs/r/pi_shared_processor_pool.html.markdown new file mode 100644 index 000000000..552d072d2 --- /dev/null +++ b/website/docs/r/pi_shared_processor_pool.html.markdown @@ -0,0 +1,85 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_shared_processor_pool" +description: |- + Manages a shared processor pool in the Power Virtual Server cloud. +--- + +# ibm_pi_shared_processor_pool +Create, update or delete a shared processor pool. + +## Example usage +The following example enables you to create a shared processor pool with a group 2 reserved cores on a s922 host group: + +```terraform +resource "ibm_pi_shared_processor_pool" "testacc_shared_processor_pool" { + pi_shared_processor_pool_name = "my_spp" + pi_shared_processor_pool_host_group = "s922" + pi_shared_processor_pool_reserved_cores = "2" + pi_cloud_instance_id = "" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_shared_processor_pool provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for creating a shared processor pool placement group. +- **delete** - (Default 60 minutes) Used for deleting a shared processor pool placement group. +- **update** - (Default 60 minutes) Used for updating a shared processor pool placement group. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_shared_processor_pool_host_group` - (Required, String) Host group of the shared processor pool. Valid values are 's922' and 'e980'. +- `pi_shared_processor_pool_name` - (Required, String) The name of the shared processor pool. +- `pi_shared_processor_pool_reserved_cores` - (Required, Integer) The amount of reserved cores for the shared processor pool. +- `pi_shared_processor_pool_placement_group_id` - (Optional, String) The ID of the placement group the shared processor pool is created in. + +## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `allocated_cores` - (Float) The allocated cores in the shared processor pool. +- `available_cores` - (Integer) The available cores in the shared processor pool. +- `host_id` - (Integer) The host ID where the shared processor pool resides. +- `instances` - (List of Map) The list of server instances that are deployed in the shared processor pool. + Nested scheme for `instances`: + - `availability_zone` - (String) Availability zone for the server instances. + - `cpus` - (Integer) The amount of cpus for the server instance. + - `id` - (String) The server instance ID. + - `memory` - (Integer) The amount of memory for the server instance. + - `name` - (String) The server instance name. + - `status` - (String) Status of the instance. + - `uncapped` - (Bool) Identifies if uncapped or not. + - `vcpus` - (Float) The amout of vcpus for the server instance. +- `shared_processor_pool_id` - (String) The shared processor pool's unique ID. +- `status` - (String) The status of the shared processor pool. +- `status_detail` - (String) The status details of the shared processor pool. + +## Import + +The `ibm_pi_shared_processor_pool` resource can be imported by using `power_instance_id` and `shared_processor_pool_id`. + +**Example** + +``` +$ terraform import ibm_pi_shared_processor_pool.example d7bec597-4726-451f-8a63-e62e6f19c32c/b17a2b7f-77ab-491c-811e-495f8d4c8947 +``` diff --git a/website/docs/r/pi_snapshot.html.markdown b/website/docs/r/pi_snapshot.html.markdown index e11160022..59d4885f2 100644 --- a/website/docs/r/pi_snapshot.html.markdown +++ b/website/docs/r/pi_snapshot.html.markdown @@ -43,15 +43,15 @@ resource "ibm_pi_snapshot" "testacc_snapshot"{ The `ibm_pi_snapshot` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - **create** - (Default 60 minutes) Used for Creating snapshot. -- **delete** - (Default 60 minutes) Used for Deleting snapshot. - **update** - (Default 60 minutes) Used for Updating snapshot. +- **delete** - (Default 10 minutes) Used for Deleting snapshot. ## Argument reference Review the argument references that you can specify for your resource. - `pi_instance_name` - (Required, String) The name of the instance you want to take a snapshot of. - `pi_snapshot_name` - (Required, String) The unique name of the snapshot. -- `description` - (Optional, String) The description for the snapshot. +- `pi_description` - (Optional, String) Description of the PVM instance snapshot. - `pi_volume_ids` - (Optional, String) The volume ID, if none provided then all volumes of the instance will be part of the snapshot. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. @@ -59,7 +59,11 @@ Review the argument references that you can specify for your resource. In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The unique identifier of the snapshot. The ID is composed of /. -- `volume_snapshots` - (String) A map of the source and target volumes. +- `snapshot_id` - (String) ID of the PVM instance snapshot. +- `status` - (String) Status of the PVM instance snapshot. +- `creation_date` - (String) Creation Date. +- `last_update_date` - (String) Last Update Date. +- `volume_snapshots` - (String) A map of volume snapshots included in the PVM instance snapshot. ## Import diff --git a/website/docs/r/pi_spp_placement_group.html.markdown b/website/docs/r/pi_spp_placement_group.html.markdown new file mode 100644 index 000000000..9e18247b2 --- /dev/null +++ b/website/docs/r/pi_spp_placement_group.html.markdown @@ -0,0 +1,69 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_spp_placement_group" +description: |- + Manages a shared processor pool placement group in the Power Virtual Server cloud. +--- + +# ibm_pi_spp_placement_group +Create, update or delete a shared processor pool placement group. + +## Example usage +The following example enables you to create a shared processor pool placement group with a group policy of affinity: + +```terraform +resource "ibm_pi_spp_placement_group" "testacc_placement_group" { + pi_spp_placement_group_name = "my_pg" + pi_spp_placement_group_policy = "affinity" + pi_cloud_instance_id = "" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_spp_placement_group provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for creating a shared processor pool placement group. +- **delete** - (Default 60 minutes) Used for deleting a shared processor pool placement group. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_spp_placement_group_name` - (Required, String) The name of the shared processor pool placement group. +- `pi_spp_placement_group_policy` - (Required, String) The value of the group's affinity policy. Valid values are `affinity` and `anti-affinity`. + + +## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the placement group. +- `members` - (List of strings) The list of server instances IDs that are members of the placement group. +- `spp_placement_group_id` - (String) The placement group ID. + +## Import + +The `ibm_spp_pi_placement_group` resource can be imported by using `power_instance_id` and `spp_placement_group_id`. + +**Example** + +``` +$ terraform import ibm_pi_spp_placement_group.example d7bec597-4726-451f-8a63-e62e6f19c32c/b17a2b7f-77ab-491c-811e-495f8d4c8947 +``` diff --git a/website/docs/r/pi_volume.html.markdown b/website/docs/r/pi_volume.html.markdown index d587b444b..160ed1b8b 100644 --- a/website/docs/r/pi_volume.html.markdown +++ b/website/docs/r/pi_volume.html.markdown @@ -42,8 +42,9 @@ resource "ibm_pi_volume" "testacc_volume"{ ibm_pi_volume provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -- **create** - (Default 60 minutes) Used for creating volume. -- **delete** - (Default 60 minutes) Used for deleting volume. +- **create** - (Default 30 minutes) Used for creating volume. +- **update** - (Default 30 minutes) Used for updating volume. +- **delete** - (Default 10 minutes) Used for deleting volume. ## Argument reference Review the argument references that you can specify for your resource. diff --git a/website/docs/r/pi_volume_attach.html.markdown b/website/docs/r/pi_volume_attach.html.markdown new file mode 100644 index 000000000..3f0799fdc --- /dev/null +++ b/website/docs/r/pi_volume_attach.html.markdown @@ -0,0 +1,67 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_volume_attach" +description: |- + Manages IBM Volume Attach in the Power Virtual Server cloud. +--- + +# ibm_pi_volume_attach +Attaches volume to a Power Systems Virtual Server instance. For more information, about managing volume, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example attaches volume to a power systems virtual server instance. + +```terraform +resource "ibm_pi_volume_attach" "testacc_volume_attach"{ + pi_cloud_instance_id = "" + pi_volume_id = "" + pi_instance_id = "" +} +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_volume_attach provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 15 minutes) Used for attaching volume. +- **delete** - (Default 15 minutes) Used for detaching volume. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_id` - (Required, String) The ID of the pvm instance to attach the volume to. +- `pi_volume_id` - (Required, String) The ID of the volume to attach. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the volume attach. The ID is composed of `//`. +- `status` - (String) The status of the volume. + +## Import + +The `ibm_pi_volume_attach` resource can be imported by using `power_instance_id`, `instance_id` and `volume_id`. + +**Example** + +``` +$ terraform import ibm_pi_volume_attach.example d7bec597-4726-451f-8a63-e62e6f19c32c/49fba6c9-23f8-40bc-9899-aca322ee7d5b/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_vpn_connection.html.markdown b/website/docs/r/pi_vpn_connection.html.markdown new file mode 100644 index 000000000..06a2b1d42 --- /dev/null +++ b/website/docs/r/pi_vpn_connection.html.markdown @@ -0,0 +1,87 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_vpn_connection" +description: |- + Manages IBM VPN Connections in the Power Virtual Server cloud. +--- + +# ibm_pi_vpn_connection +Create, update, or delete a VPN connection. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example creates a VPN Connection. + +```terraform + resource "ibm_pi_vpn_connection" "example" { + pi_cloud_instance_id = "" + pi_vpn_connection_name = "test" + pi_ike_policy_id = ibm_pi_ike_policy.policy.policy_id + pi_ipsec_policy_id = ibm_pi_ipsec_policy.policy.policy_id + pi_vpn_connection_mode = "policy" + pi_networks = [ibm_pi_network.private_network1.network_id] + pi_peer_gateway_address = "1.22.124.1" + pi_peer_subnets = ["107.0.0.0/24"] + } +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_vpn_connection provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 20 minutes) Used for creating VPN connection. +- **update** - (Default 20 minutes) Used for updating VPN connection. +- **delete** - (Default 20 minutes) Used for deleting VPN connection. + +## Argument reference +Review the argument references that you can specify for your resource. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_ike_policy_id` - (Required, String) Unique identifier of IKE Policy selected for this VPN Connection. +- `pi_ipsec_policy_id`- (Required, String) Unique identifier of IPSec Policy selected for this VPN Connection. +- `pi_networks` - (Required, Set of String) Set of network IDs to attach to this VPN connection. +- `pi_peer_gateway_address` - (Required, String) Peer Gateway address. +- `pi_peer_subnets` - (Required, Set of String) Set of CIDR of peer subnets. +- `pi_vpn_connection_mode` - (Required, String) Mode used by this VPN Connection, either `policy` or `route`. +- `pi_vpn_connection_name` - (Required, String) Name of the VPN Connection. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the VPN Connection. The ID is composed of `/`. +- `connection_id` - (String) VPN Connection ID. +- `connection_status` - (String) Status of the VPN connection. +- `dead_peer_detections` - (Map) Dead Peer Detection. + + Nested scheme for `dead_peer_detections`: + - `action` - (String) Action to take when a Peer Gateway stops responding. + - `interval` - (String) How often to test that the Peer Gateway is responsive. + - `threshold` - (String) The number of attempts to connect before tearing down the connection. +- `gateway_address` - (String) Public IP address of the VPN Gateway (vSRX) attached to this VPN Connection. +- `local_gateway_address` - (String) Local Gateway address, only in `route` mode. + + +## Import + +The `ibm_pi_vpn_connection` resource can be imported by using `power_instance_id` and `vpn_connection_id`. + +**Example** + +``` +$ terraform import ibm_pi_vpn_connection.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf451f +``` diff --git a/website/docs/r/pi_vpn_ike_policy.html.markdown b/website/docs/r/pi_vpn_ike_policy.html.markdown new file mode 100644 index 000000000..32587ca8f --- /dev/null +++ b/website/docs/r/pi_vpn_ike_policy.html.markdown @@ -0,0 +1,77 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_ike_policy" +description: |- + Manages IBM IKE Policy in the Power Virtual Server cloud. +--- + +# ibm_pi_ike_policy +Create, update, or delete a IKE Policy. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example creates a IKE Policy. + +```terraform + resource "ibm_pi_ike_policy" "example" { + pi_cloud_instance_id = "" + pi_policy_name = "test" + pi_policy_dh_group = 1 + pi_policy_encryption = "aes-256-cbc" + pi_policy_key_lifetime = 28800 + pi_policy_preshared_key = "sample" + pi_policy_version = 1 + pi_policy_authentication = "sha1" + } +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_ike_policy provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 10 minutes) Used for creating IKE Policy. +- **update** - (Default 10 minutes) Used for updating IKE Policy. +- **delete** - (Default 10 minutes) Used for deleting IKE Policy. + +## Argument reference +Review the argument references that you can specify for your resource. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_policy_authentication` - (Optional, String) Authentication for the IKE Policy. Supported values are `none`(Default), `sha-256`, `sha-384`, `sha1`. +- `pi_policy_dh_group` - (Required, Integer) DH group of the IKE Policy. Supported values are `1`,`2`,`5`,`14`,`19`,`20`,`24`. +- `pi_policy_encryption`- (Required, String) Encryption of the IKE Policy. Supported values are `aes-256-cbc`, `aes-192-cbc`, `aes-128-cbc`, `aes-256-gcm`, `aes-128-gcm`, `3des-cbc`. +- `pi_policy_key_lifetime` - (Required, Integer) Policy key lifetime. Supported values: `180` ≤ value ≤ `86400`. +- `pi_policy_name` - (Required, String) Name of the IKE Policy. +- `pi_policy_preshared_key` - (Required, String) Preshared key used in this IKE Policy (length of preshared key must be even). +- `pi_policy_version` - (Required, Integer) Version of the IKE Policy. Supported values are `1`,`2`. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the IKE Policy. The ID is composed of `/`. +- `policy_id` - (String) IKE Policy ID. + +## Import + +The `ibm_pi_ike_policy` resource can be imported by using `power_instance_id` and `policy_id`. + +**Example** + +``` +$ terraform import ibm_pi_ike_policy.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf451f +``` diff --git a/website/docs/r/pi_vpn_ipsec_policy.html.markdown b/website/docs/r/pi_vpn_ipsec_policy.html.markdown new file mode 100644 index 000000000..94e215435 --- /dev/null +++ b/website/docs/r/pi_vpn_ipsec_policy.html.markdown @@ -0,0 +1,75 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_ipsec_policy" +description: |- + Manages IBM IPSec Policy in the Power Virtual Server cloud. +--- + +# ibm_pi_ipsec_policy +Create, update, or delete a IPSec Policy. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example creates a IPSec Policy. + +```terraform + resource "ibm_pi_ipsec_policy" "example" { + pi_cloud_instance_id = "" + pi_policy_name = "test" + pi_policy_dh_group = 1 + pi_policy_encryption = "aes-256-cbc" + pi_policy_key_lifetime = 28800 + pi_policy_pfs = true + pi_policy_authentication = "hmac-sha-256-128" + } +``` + +**Note** +* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + * `region` - `lon` + * `zone` - `lon04` + + Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +ibm_pi_ipsec_policy provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 10 minutes) Used for creating IPSec Policy. +- **update** - (Default 10 minutes) Used for updating IPSec Policy. +- **delete** - (Default 10 minutes) Used for deleting IPSec Policy. + +## Argument reference +Review the argument references that you can specify for your resource. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_policy_authentication` - (Optional, String) Authentication for the IPSec Policy. Supported values are `none`(Default), `hmac-sha-256-128`, `hmac-sha1-96`. +- `pi_policy_dh_group` - (Required, Integer) DH group of the IPSec Policy. Supported values are `1`,`2`,`5`,`14`,`19`,`20`,`24`. +- `pi_policy_encryption`- (Required, String) Encryption of the IPSec Policy. Supported values are `aes-256-cbc`, `aes-192-cbc`, `aes-128-cbc`, `aes-256-gcm`, `aes-128-gcm`, `3des-cbc`. +- `pi_policy_key_lifetime` - (Required, Integer) Policy key lifetime. Supported values: `180` ≤ value ≤ `86400`. +- `pi_policy_name` - (Required, String) Name of the IPSec Policy. +- `pi_policy_pfs` - (Required, Boolean) Perfect Forward Secrecy. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the IPSec Policy. The ID is composed of `/`. +- `policy_id` - (String) IPSec Policy ID. + +## Import + +The `ibm_pi_ipsec_policy` resource can be imported by using `power_instance_id` and `policy_id`. + +**Example** + +``` +$ terraform import ibm_pi_ipsec_policy.example d7bec597-4726-451f-8a63-e62e6f19c32c/ffag151a-bc0a-4438-9f8a-b0760bbf4u1u +``` diff --git a/website/docs/r/resource_instance.html.markdown b/website/docs/r/resource_instance.html.markdown index 57eb861f0..062c8ab5d 100644 --- a/website/docs/r/resource_instance.html.markdown +++ b/website/docs/r/resource_instance.html.markdown @@ -69,6 +69,69 @@ resource "ibm_resource_instance" "myhpdbcluster" { } ``` +### Example to provision a Watson Query service instance +The following example enables you to create a service instance of IBM Watson Query. For detailed argument reference, see the tables in the [Watson Query documentation](https://cloud.ibm.com/docs/data-virtualization?topic=data-virtualization-provisioning). + +```terraform +data "ibm_resource_group" "group" { + name = "default" +} +resource "ibm_resource_instance" "wq_instance_1" { + name = "terraform-integration-1" + service = "data-virtualization" + plan = "data-virtualization-enterprise" # "data-virtualization-enterprise-dev","data-virtualization-enterprise-preprod","data-virtualization-enterprise-dev-stable" + location = "us-south" # "eu-gb", "eu-de", "jp-tok" + resource_group_id = data.ibm_resource_group.group.id + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } + +} +``` + + +### Example to provision a Analytics Engine using parameters_json argument +```terraform +resource "ibm_resource_instance" "instance" { + name = "MyServiceInstance" + plan = "standard-hourly" + location = "us-south" + service = "ibmanalyticsengine" + parameters_json = <` command. - `name` - (Required, String) A descriptive name used to identify the resource instance. - `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the service. You can retrieve the value from data source `ibm_resource_group`. If not provided creates the service in default resource group. diff --git a/website/docs/r/resource_key.html.markdown b/website/docs/r/resource_key.html.markdown index 66e40ceff..60d29e2e6 100644 --- a/website/docs/r/resource_key.html.markdown +++ b/website/docs/r/resource_key.html.markdown @@ -88,6 +88,40 @@ resource "ibm_resource_key" "resourceKey" { role = "Manager" } +``` +### Example to access resource credentials using credentials attribute: + +```terraform +resource "ibm_resource_key" "key" { + name = "my-cos-bucket-xx-key" + resource_instance_id = ibm_resource_instance.resource_instance.id + role = "Manager" +} +output "access_key_id" { + value = ibm_resource_key.key.credentials["cos_hmac_keys.access_key_id"] +} +output "secret_access_key" { + value = ibm_resource_key.key.credentials["cos_hmac_keys.secret_access_key"] +} +``` + +### Example to access resource credentials using credentials_json attribute: + +```terraform +resource "ibm_resource_key" "key" { + name = "my-cos-bucket-xx-key" + resource_instance_id = ibm_resource_instance.resource_instance.id + role = "Manager" +} +locals { + resource_credentials =jsondecode(ibm_resource_key.key.credentials_json) +} +output "access_key_id" { + value = local.resource_credentials.cos_hmac_keys.access_key_id +} +output "secret_access_key" { + value = local.resource_credentials.cos_hmac_keys.secret_access_key +} ``` ## Timeouts @@ -103,7 +137,7 @@ Review the argument references that you can specify for your resource. - `name` - (Required, Forces new resource, String) A descriptive name used to identify a resource key. - `parameters` (Optional, Map) Arbitrary parameters to pass to the resource in JSON format. If you want to create service credentials by using the private service endpoint, include the `service-endpoints = "private"` parameter. -- `role` - (Required, Forces new resource, String) The name of the user role. Valid roles are `Writer`, `Reader`, `Manager`, `Administrator`, `Operator`, `Viewer`, and `Editor`. +- `role` - (Optional, Forces new resource, String) The name of the user role. Valid roles are `Writer`, `Reader`, `Manager`, `Administrator`, `Operator`, `Viewer`, and `Editor`. This argument is Optional only during creation of service credentials for Cloud Databases and other non-IAM-enabled services and is Required for all other IAM-enabled services. - `resource_instance_id` - (Optional, Forces new resource, String) The ID of the resource instance associated with the resource key. **Note** Conflicts with `resource_alias_id`. - `resource_alias_id` - (Optional, Forces new resource, String) The ID of the resource alias associated with the resource key. **Note** Conflicts with `resource_instance_id`. - `tags` (Optional, Array of strings) Tags associated with the resource key instance. **Note** Tags are managed locally and not stored on the IBM Cloud Service Endpoint at this moment. @@ -113,7 +147,8 @@ Review the argument references that you can specify for your resource. In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `account_id` - (String) An alpha-numeric value identifying the account ID. -- `credentials` - (String) The credentials associated with the key. +- `credentials` - (Map) The credentials associated with the key. +- `credentials_json` - (String) The credentials associated with the key in json format. - `created_at` - (Timestamp) The date when the key was created. - `created_by` - (String) The subject who created the key. - `crn` - (String) The full Cloud Resource Name (CRN) associated with the key. @@ -131,3 +166,5 @@ In addition to all argument reference list, you can access the following attribu - `updated_by` - (String) The subject who updated the key. - `url` - (String) When you created a new key, a relative URL path is created identifying the location of the key. +## Note +Credentials will be seen as redacted, if the user does not have access equal to or greater than the access of the service credentials. Please refer to the documentation to access credentials - https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui#viewing-credentials-ui. diff --git a/website/docs/r/resource_tag.html.markdown b/website/docs/r/resource_tag.html.markdown index 43b8d20e9..0bff7a1ee 100644 --- a/website/docs/r/resource_tag.html.markdown +++ b/website/docs/r/resource_tag.html.markdown @@ -8,7 +8,7 @@ description: |- # ibm_resource_tag -Create, update, or delete [IBM Cloud resource tags](https://cloud.ibm.com/apidocs/tagging). +Create, update, or delete IBM Cloud resource tags. For more information, about tagging, see [IBM Cloud resource tags](https://cloud.ibm.com/apidocs/tagging). ## Example usage @@ -34,11 +34,11 @@ Review the argument references that you can specify for your resource. - `tag_type` - (Optional, String) Type of the tag. Supported values are: `user`, `service`, or `access`. The default value is user. - `tags` - (Required, Array of strings) List of tags associated with resource instance. -## Attributes Reference +## Attributes reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The unique identifier of the resource tag. -- `acccount_id` - (String) The ID of an account that owns the resources to be tagged (required if tag-type is set to service). +- `acccount_id` - (String) The ID of an account that owns the resources to be tagged. This is required if tag-type is set to service. ## Import @@ -58,7 +58,7 @@ $ terraform import ibm_resource_tag.tag crn:v1:bluemix:public:satellite:us-east ``` -Example for importing classic infrastructure tags: +Example for importing classic infrastructure tags. **Syntax** @@ -69,6 +69,5 @@ $ terraform import ibm_resource_tag.tag resource_id/resource_type **Example** ``` -$ terraform import ibm_resource_tag.tag 118398132/SoftLayer_Virtual_Guest - +$ terraform import ibm_resource_tag.tag 118398132/SoftLayer_Virtual_Guest ``` diff --git a/website/docs/r/satellite_cluster.html.markdown b/website/docs/r/satellite_cluster.html.markdown index e62610f1b..25bce4ca6 100644 --- a/website/docs/r/satellite_cluster.html.markdown +++ b/website/docs/r/satellite_cluster.html.markdown @@ -6,16 +6,16 @@ description: |- Manages IBM Cloud satellite cluster. --- -# ibm\_satellite_cluster +# ibm_satellite_cluster -Create, update, or delete [IBM Cloud Satellite Cluster](https://cloud.ibm.com/docs/openshift?topic=openshift-satellite-clusters). Set up an Red Hat® OpenShift® on IBM Cloud™ clusters in an IBM Cloud™ Satellite location, and use the hosts of your own infrastructure that you added to your location as the worker nodes for the cluster. +Create, update, or delete [IBM Cloud Satellite Cluster](https://cloud.ibm.com/docs/openshift?topic=openshift-satellite-clusters). Set up an Red Hat OpenShift® on IBM Cloud clusters in an IBM Cloud Satellite location, and use the hosts of your own infrastructure that you added to your location as the worker nodes for the cluster. -## Example Usage +## Example usage ### Create satellite cluster -```hcl +```terraform resource "ibm_satellite_cluster" "create_cluster" { name = "%s" location = var.location @@ -35,76 +35,79 @@ resource "ibm_satellite_cluster" "create_cluster" { ## Timeouts -ibm_satellite_cluster provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - -* `create` - (Default 120 minutes) Used for creating Instance. -* `read` - (Default 10 minutes) Used for reading Instance. -* `update` - (Default 120 minutes) Used for updating Instance. -* `delete` - (Default 30 minutes) Used for deleting Instance. - -## Argument Reference - -The following arguments are supported: - -* `name` - (Required, string) The unique name for the new IBM Cloud Satellite cluster. -* `location` - (Required, string) The name or ID of the Satellite location. -* `kube_version` - (Optional, string) The OpenShift Container Platform version. -* `zones` - (Optional, array of strings) The name of the zones to create the default worker pool in -* `worker_count` - (Optional, string) The number of worker nodes to create per zone in the default worker pool. -* `enable_config_admin` - (Optional, bool) User provided value to indicate opt-in agreement to SatCon admin agent. -* `host_labels` - (Optional, array of strings) Key-value pairs to label the host, such as cpu=4 to describe the host capabilities. -* `default_worker_pool_labels` - Labels on all the workers in the default worker pool. -* `pull_secret` - (Optional, string) The RedHat pull secret to create the OpenShift cluster. -* `zone` - (Optional, list) Zone for the worker pool in a multizone cluster. Nested `zone` blocks have the following structure: - * `id` - The name of the zone. -* `resource_group_id` - (Optional, string) The ID of the resource group. You can retrieve the value from data source `ibm_resource_group`. -* `tags` - (Optional, array of strings) List of tags associated with this cluster. -* `wait_for_worker_update` - (Optional, bool) Set to true to wait for kube version of woker nodes to update during the wokrer node kube version update. NOTE: setting wait_for_worker_update to false is not recommended. This results in upgrading all the worker nodes in the cluster at the same time causing the cluster downtime -* `patch_version` - (Optional, string) Set this to update the worker nodes with the required patch version. - The patch_version should be in the format - `patch_version_fixpack_version`. Learn more about the Kuberentes version [here](https://cloud.ibm.com/docs/containers?topic=containers-cs_versions). +The `ibm_satellite_cluster` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- `create` - (Default 120 minutes) Used for creating instance. +- `read` - (Default 10 minutes) Used for reading instance. +- `update` - (Default 120 minutes) Used for updating instance. +- `delete` - (Default 30 minutes) Used for deleting instance. + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `name` - (Required, String) The unique name for the new IBM Cloud Satellite cluster. +- `location` - (Required, String) The name or ID of the Satellite location. +- `kube_version` - (Optional, String) The Red Hart OpenShift Container Platform version. +- `operating_system` - (Optional, String) Operating system of the default worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS. +- `zones` - (Optional, Array of Strings) The name of the zones to create the default worker pool. +- `worker_count` - (Optional, String) The number of worker nodes to create per zone in the default worker pool. +- `enable_config_admin` - (Optional, Bool) User provided value to indicate opt-in agreement to SatCon admin agent. +- `host_labels` - (Optional, Array of Strings) Key-value pairs to label the host, such as `cpu=4` to describe the host capabilities. +- `default_worker_pool_labels` - (Optional, String) The labels on all the workers in the default worker pool. +- `pull_secret` - (Optional, String) The Red Hat pull secret to create the OpenShift cluster. +- `zone` - (Optional, List) The zone for the worker pool in a multi-zone cluster. + + Nested scheme for `zone`: + - `id` - The name of the zone. +- `resource_group_id` - (Optional, String) The ID of the resource group. You can retrieve the value from data source `ibm_resource_group`. +- `tags` - (Optional, Array of Strings) List of tags associated with this cluster. +- `wait_for_worker_update` - (Optional, Bool) Set to **true** to wait for kube version of woker nodes to update during the worker node kube version update. **NOTE** setting `wait_for_worker_update` to **false** is not recommended. This results in upgrading all the worker nodes in the cluster at the same time causing the cluster downtime. +- `patch_version` - (Optional, String) Set this to update the worker nodes with the required patch version. + The `patch_version` should be in the format - `patch_version_fixpack_version`. For more information, see [Kuberentes version](https://cloud.ibm.com/docs/containers?topic=containers-cs_versions). **NOTE**: To update the patch/fixpack versions of the worker nodes, Run the command `ibmcloud ks workers -c --output json`, fetch the required patch & fixpack versions from `kubeVersion.target` and set the patch_version parameter. -* `retry_patch_version` - (Optional, int) This argument helps to retry the update of patch_version if the previous update fails. Increment the value to retry the update of patch_version on worker nodes. -* `tags` - (Optional, array of strings) Tags associated with the container cluster instance. -* `pod_subnet` - Specify a custom subnet CIDR to provide private IP addresses for pods. The subnet must be at least '/23' or larger. For more info, refer [here](https://cloud.ibm.com/docs/containers?topic=containers-cli-plugin-kubernetes-service-cli#pod-subnet). -* `service_subnet` - Specify a custom subnet CIDR to provide private IP addresses for services. The subnet must be at least '/24' or larger. For more info, refer [here](https://cloud.ibm.com/docs/containers?topic=containers-cli-plugin-kubernetes-service-cli#service-subnet). +- `retry_patch_version` - (Optional, Integer) This argument helps to retry the update of `patch_version` if the previous update fails. Increment the value to retry the update of `patch_version` on worker nodes. +- `tags` - (Optional, Array of Strings) Tags associated with the container cluster instance. +- `pod_subnet` - Specify a custom subnet CIDR to provide private IP addresses for pods. The subnet must be at least `/23` or larger. For more information, see [Configuring VPC subnets](https://cloud.ibm.com/docs/containers?topic=containers-vpc-subnets). +- `service_subnet` - Specify a custom subnet CIDR to provide private IP addresses for services. The subnet must be at least `/24` or larger. For more information, see [Configuring VPC subnets](https://cloud.ibm.com/docs/containers?topic=containers-vpc-subnets#vpc_basics). -## Attributes Reference +## Attributes reference -In addition to all arguments above, the following attributes are exported: +In addition to all argument reference list, you can access the following attribute reference after your resource is created. -* `id` - The unique identifier of the cluster. -* `crn` - CRN of the cluster. -* `ingress_hostname` - The Ingress hostname. -* `ingress_secret` - The Ingress secret. -* `state` - State. -* `master_status` - Status of kubernetes master. -* `master_url` - The Master server URL. -* `private_service_endpoint_url` - Private service endpoint url. -* `public_service_endpoint_url` - Public service endpoint url. -* `private_service_endpoint_enabled` - Private service endpoint status. -* `public_service_endpoint_enabled` - Public service endpoint status. -* `state` - The lifecycle state of the cluster. -* `resource_group_name` - The lifecycle state of the cluster. +- `id` - (String) The unique identifier of the cluster. +- `crn` - (String) The CRN of the cluster. +- `ingress_hostname` - (String) The Ingress hostname. +- `ingress_secret` - (String) The Ingress secret. +- `state` - (String) State. +- `master_status` - (String) The status of the Kubernetes master. +- `master_url` - (String) The master server URL. +- `private_service_endpoint_url` - (String) The private service endpoint URL. +- `public_service_endpoint_url` - (String) The public service endpoint URL. +- `private_service_endpoint_enabled` - (String) The private service endpoint status. +- `public_service_endpoint_enabled` - (String) The public service endpoint status. +- `state` - (String) The lifecycle state of the cluster. +- `resource_group_name` - (String) The lifecycle state of the cluster. -**NOTE:** +**Note** 1. The following arguments are immutable and cannot be changed: -* `name` - The unique name for the new IBM Cloud Satellite cluster. -* `location` - The name or ID of the Satellite location. -* `resource_group_id` - The ID of the resource group. +- `name` - The unique name for the new IBM Cloud Satellite cluster. +- `location` - The name or ID of the Satellite location. +- `resource_group_id` - The ID of the resource group. 2. Host assignment to workerpool: -* When you attach a host to a Satellite location, the host automatically assigned to worker pools in satellite resources. - Auto-assignment works based on matching host labels (https://cloud.ibm.com/docs/satellite?topic=satellite-hosts#host-autoassign-ov). -* For manual assignment, Use `ibm_satellite_host` resource to assign the host to workerpools. +- When you attach a host to a Satellite location, the host automatically assigned to worker pools in satellite resources. + Auto-assignment works based on matching host labels (https://cloud.ibm.com/docs/satellite?topic=satellite-assigning-hosts#host-autoassign-ov). +- For manual assignment, Use `ibm_satellite_host` resource to assign the host to workerpools. ## Import -`ibm_satellite_cluster` can be imported using the location id or name. +The `ibm_satellite_cluster` can be imported using the location id or name. Example: diff --git a/website/docs/r/satellite_cluster_worker_pool.html.markdown b/website/docs/r/satellite_cluster_worker_pool.html.markdown index 7cc7dec7d..864236188 100644 --- a/website/docs/r/satellite_cluster_worker_pool.html.markdown +++ b/website/docs/r/satellite_cluster_worker_pool.html.markdown @@ -6,15 +6,15 @@ description: |- Manages IBM Cloud satellite cluster worker pool. --- -# ibm\_satellite\_cluster\_worker\_pool +# ibm_satellite_cluster_worker_pool - Create or delete a worker pool. The worker pool will be attached to the specified cluster[IBM Cloud Satellite Cluster Worker Pool](https://cloud.ibm.com/docs/satellite?topic=openshift-satellite-clusters#satcluster-worker-pools). +Create, update, or delete the Satellite cluster worker pool. The worker pool will be attached to the specified cluster[IBM Cloud Satellite Cluster Worker Pool](https://cloud.ibm.com/docs/satellite?topic=satellite-hosts#host-autoassign-ov). -## Example Usage +## Example usage ### Create satellite cluster worker pool -```hcl +```terraform resource "ibm_satellite_cluster_worker_pool" "create_cluster_wp" { name = var.worker_pool_name cluster = var.cluster @@ -32,7 +32,7 @@ resource "ibm_satellite_cluster_worker_pool" "create_cluster_wp" { ### Create satellite cluster worker pool without workers -```hcl +```terraform resource "ibm_satellite_cluster_worker_pool" "create_cluster_wp" { name = var.worker_pool_name cluster = data.ibm_satellite_cluster.read_cluster.id @@ -47,49 +47,55 @@ resource "ibm_satellite_cluster_worker_pool" "create_cluster_wp" { ## Timeouts -ibm_satellite_cluster_worker_pool provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: +The `ibm_satellite_cluster_worker_pool` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -* `create` - (Default 120 minutes) Used for creating Instance. -* `read` - (Default 10 minutes) Used for reading Instance. -* `update` - (Default 120 minutes) Used for updating Instance. -* `delete` - (Default 90 minutes) Used for deleting Instance. +- `create` - (Default 120 minutes) Used for creating Instance. +- `read` - (Default 10 minutes) Used for reading Instance. +- `update` - (Default 120 minutes) Used for updating Instance. +- `delete` - (Default 90 minutes) Used for deleting Instance. -## Argument Reference +## Argument reference -The following arguments are supported: +Review the argument references that you can specify for your resource. -* `name` - (Required, Forces new resource, string) The name of the worker pool. -* `cluster` - (Required, Forces new resource, string) The name or id of the cluster. -* `worker_count` - (Optional, Int) The number of worker nodes per zone in the worker pool. -* `flavor` - (Optional, string) The flavor defines the amount of virtual CPU, memory, and disk space that is set up in each worker node. -* `isolation` - (Optional, string) Isolation for the worker node. -* `disk_encryption` - (Optional, string) Disk encryption for worker node. -* `zones` - (Required, set) A nested block describing the zones of this worker_pool. Nested zones blocks have the following structure: - * `id` - (Required, string) Name of the zone. -* `host_labels` - (Optional, array of strings) Key-value pairs to label the host, such as cpu=4 to describe the host capabilities. -* `worker_pool_labels` - Labels on all the workers in the worker pool. -* `resource_group_id` - (Optional, Forces new resource, string) The ID of the resource group. You can retrieve the value from data source -* `entitlement` - (Optional, string) The openshift cluster entitlement avoids the OCP licence charges incurred. Use cloud paks with OCP Licence entitlement to add the Openshift cluster worker pool. +- `name` - (Required, Forces new resource, String) The name of the worker pool. +- `cluster` - (Required, Forces new resource, String) The name or id of the cluster. +- `operating_system` - (Optional, String) Operating system of the worker pool. Options are REDHAT_7_64, REDHAT_8_64, or RHCOS. +- `worker_count` - (Optional, Integer) The number of worker nodes per zone in the worker pool. +- `flavor` - (Optional, String) The flavor defines the amount of virtual CPU, memory, and disk space that is set up in each worker node. +- `isolation` - (Optional, String) Isolation for the worker node. +- `disk_encryption` - (Optional, String) Disk encryption for worker node. +- `zones` - (Required, List) A nested block describing the zones of this worker_pool. - -## Attribute Reference + Nested scheme for `zones`: + - `id` - (Required, String) The name of the zone. +- `host_labels` - (Optional, Array of Strings) Key-value pairs to label the host, such as cpu=4 to describe the host capabilities. +- `worker_pool_labels` - Labels on all the workers in the worker pool. +- `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group. You can retrieve the value from data source +- `entitlement` - (Optional, String) The openshift cluster entitlement avoids the OCP licence charges incurred. Use cloud paks with OCP Licence entitlement to add the Openshift cluster worker pool. -In addition to all arguments above, the following attributes are exported: +## Attribute reference -* `id` - The unique identifier of the worker pool resource. The id is composed of \/\.
+In addition to all argument reference list, you can access the following attribute reference after your resource is created. -**NOTE:** +- `id` - The unique identifier of the worker pool resource. The `id` is composed of \/\.
+ +**Note** Host assignment to workerpool: -* When you attach a host to a Satellite location, the host automatically assigned to worker pools in satellite resources. +- When you attach a host to a Satellite location, the host automatically assigned to worker pools in satellite resources. Auto-assignment works based on matching host labels (https://cloud.ibm.com/docs/satellite?topic=satellite-hosts#host-autoassign-ov). -* For manual assignment, Use `ibm_satellite_host` resource to assign the host to workerpools. +- For manual assignment, Use `ibm_satellite_host` resource to assign the host to workerpools. ## Import -`ibm_satellite_cluster_worker_pool` can be imported using cluster_name_id & worker_pool_id eg +The `ibm_satellite_cluster_worker_pool` can be imported by using `cluster_name_id` and `worker_pool_id`. + +**Example** ``` -$ terraform import ibm_satellite_cluster_worker_pool.example mycluster/5c4f4d06e0dc402084922dea70850e3b-7cafe35 \ No newline at end of file +$ terraform import ibm_satellite_cluster_worker_pool.example mycluster/5c4f4d06e0dc402084922dea70850e3b-7cafe35 + +``` \ No newline at end of file diff --git a/website/docs/r/satellite_cluster_worker_pool_zone_attachment.html.markdown b/website/docs/r/satellite_cluster_worker_pool_zone_attachment.html.markdown new file mode 100644 index 000000000..3bf9d712e --- /dev/null +++ b/website/docs/r/satellite_cluster_worker_pool_zone_attachment.html.markdown @@ -0,0 +1,55 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_cluster_worker_pool_zone_attachment" +description: |- + Manages IBM Cloud satellite cluster worker pool zone attachment. +--- + +# ibm_satellite_cluster_worker_pool_zone_attachment + +Provides a resource for satellite_cluster_worker_pool_zone_attachment. This allows satellite_cluster_worker_pool_zone_attachment to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_satellite_cluster_worker_pool_zone_attachment" "satellite_cluster_worker_pool_zone_attachment" { + cluster = var.cluster + worker_pool = var.worker_pool + zone = var.zone_name +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `cluster` - (Optional, Forces new resource, String) The name of the cluster. +* `resource_group_id` - (Optional, Forces new resource, String) The ID of the resource group that the Satellite location is in. To list the resource group ID of the location, use the `GET /v2/satellite/getController` API method. +* `worker_pool` - (Optional, Forces new resource, String) The name of the worker pool. +* `zone` - (Optional, Forces new resource, String) (String) The name of the zone to attach. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - (String) The unique identifier of the satellite_cluster_worker_pool_zone_attachment. +* `autobalance_enabled` - (Optional, Boolean) Auto enabled status. +* `messages` - (Optional, List) Messages. +* `worker_count` - (Optional, Integer) Number of workers in worker pool. + +## Import + +You can import the `ibm_satellite_cluster_worker_pool_zone_attachment` resource can be imported by using the `cluster` and `worker pool`, `zone name`. + +``` +// +``` +* `cluster`: A string. The cluster ID. +* `worker_pool`: A string. The worker pool name. +* `zone_name`: A string. The zone name. + +# Syntax +``` +$ terraform import ibm_satellite_cluster_worker_pool_zone_attachment.satellite_cluster_worker_pool_zone_attachment // +``` \ No newline at end of file diff --git a/website/docs/r/satellite_endpoint.html.markdown b/website/docs/r/satellite_endpoint.html.markdown index 1fa4df758..4da97dc39 100644 --- a/website/docs/r/satellite_endpoint.html.markdown +++ b/website/docs/r/satellite_endpoint.html.markdown @@ -6,13 +6,13 @@ description: |- Manages satellite endpoint. --- -# ibm\_satellite_endpoint +# ibm_satellite_endpoint Provides a resource for ibm_satellite_endpoint. This allows ibm_satellite_endpoint to be created, updated and deleted. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_satellite_endpoint" "satellite_endpoint" { location = "location_id" connection_type = "cloud" @@ -30,7 +30,7 @@ resource "ibm_satellite_endpoint" "satellite_endpoint" { } ``` -## Argument Reference +## Argument reference The following arguments are supported: @@ -61,7 +61,7 @@ The following arguments are supported: * Constraints: The maximum value is `180`. The minimum value is `1`. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: diff --git a/website/docs/r/satellite_host.html.markdown b/website/docs/r/satellite_host.html.markdown index 0b4e8ef45..ce6774af3 100644 --- a/website/docs/r/satellite_host.html.markdown +++ b/website/docs/r/satellite_host.html.markdown @@ -18,8 +18,7 @@ Create, update, or delete [IBM Cloud Satellite Host](https://cloud.ibm.com/docs/ resource "ibm_satellite_host" "assign_host" { count = 3 - location = "satellite-ibm" - cluster = "satellite-ibm" + location = var.location host_id = element(var.host_vms, count.index) labels = ["env:prod"] zone = element(var.location_zones, count.index) @@ -58,6 +57,14 @@ resource "ibm_satellite_host" "assign_host" { } ``` +## Timeouts + +The `ibm_satellite_host` provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **Create** The assignment of hosts is considered failed if no response is received for 75 minutes. +- **Update** The updation of the host assignment is considered failed if no response is received for 45 minutes. +- **Delete** The deletion of the hosts is considered failed if no response is received for 45 minutes. + ## Argument reference Review the argument references that you can specify for your resource. @@ -68,7 +75,7 @@ Review the argument references that you can specify for your resource. - `location` - (Required, String) The name or ID of the Satellite location. - `labels`- (Optional, Array of Strings) The key value pairs to label the host, such as `cpu=4` to describe the host capabilities. - `worker_pool` - (Optional, String) The name or ID of the worker pool within the cluster to assign the host to. - +`wait_till` - (Optional, String) If this argument is provided this resource will wait until location is normal. Allowed values: `location_normal` ## Attribute reference diff --git a/website/docs/r/satellite_link.html.markdown b/website/docs/r/satellite_link.html.markdown index 6c6408512..2453e831c 100644 --- a/website/docs/r/satellite_link.html.markdown +++ b/website/docs/r/satellite_link.html.markdown @@ -6,27 +6,27 @@ description: |- Manages satellite link. --- -# ibm\_satellite_link +# ibm_satellite_link Provides a resource for ibm_satellite_link. This allows ibm_satellite_link to be created, updated and deleted. -## Example Usage +## Example usage -```hcl +```terraform resource "ibm_satellite_link" "satellite_link" { crn = "crn:v1:staging:public:satellite:us-south:a/1ae4eb57181a46ceade4846519678888::location:brbats7009sqna3dtest" location_id = "brbats7009sqna3dtest" } ``` -## Argument Reference +## Argument reference The following arguments are supported: * `crn` - (Required, string) CRN of the Location. * `location` - (Required, string) Location ID. -## Attribute Reference +## Attribute reference In addition to all arguments above, the following attributes are exported: diff --git a/website/docs/r/satellite_location.html.markdown b/website/docs/r/satellite_location.html.markdown index 13f9cf89b..e5241a334 100644 --- a/website/docs/r/satellite_location.html.markdown +++ b/website/docs/r/satellite_location.html.markdown @@ -56,6 +56,7 @@ The `ibm_satellite_location` provides the following [Timeouts](https://www.terra ## Argument reference Review the argument references that you can specify for your resource. +- `coreos_enabled` - (Optional, Bool) Enable Red Hat CoreOS features within the Satellite location. - `cos_config` - (Optional, List) The IBM Cloud Object Storage bucket configuration details. Nested cos_config blocks have the following structure. Nested scheme for `cos_config`: @@ -71,7 +72,7 @@ Review the argument references that you can specify for your resource. - `is_location_exist`- (Optional, Bool) Determines the location has to be created or not. - `location` - (Required, String) The name of the location to be created or pass existing location name. - `logging_account_id` - (Optional, String) The account ID for IBM Log Analysis with LogDNA log forwarding. -- `managed_from` - (Required, String) The IBM Cloud metro from which the Satellite location is managed. To list available multizone regions, run `ibmcloud ks locations`, such as `wdc04`, `wdc06`, or `lon04`. +- `managed_from` - (Required, String) The IBM Cloud regions that you can choose from to manage your Satellite location. To list available multizone regions, run `ibmcloud ks locations`. For more information, refer to [supported IBM Cloud locations](https://cloud.ibm.com/docs/satellite?topic=satellite-sat-regions). - `zones`- Array of Strings - Optional- The names for the host zones. For high availability, allocate your hosts across these three zones based on your infrastructure provider zones. For example, `us-east-1`, `us-east-2`, `us-east-3` . diff --git a/website/docs/r/satellite_location_nlb_dns.html.markdown b/website/docs/r/satellite_location_nlb_dns.html.markdown new file mode 100644 index 000000000..cb23817c5 --- /dev/null +++ b/website/docs/r/satellite_location_nlb_dns.html.markdown @@ -0,0 +1,37 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_location_nlb_dns" +description: |- + Managed satellite location nlb dns. +--- + +# ibm_satellite\_location\_nlb\_dns + +Provides a resource to register public ip address to satellite dns records. This allows satellite dns register to be created, updated and deleted. + +## Example usage + +```terraform +resource "ibm_satellite_location_nlb_dns" "satellite_dns" { + location = "satellite-ibm" + ips = ["52.116.125.50","169.62.17.178","169.63.178.155"] +} +``` + +## Argument reference + +The following arguments are supported: + +* `ips` - (Required, Forces new resource, List) Public IP address of satellite location DNS records. +* `location` - (Required, Forces new resource, string) The name or ID of the Satellite location. + +## Attribute reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique identifier of the ibm_satellite_location_nlb_dns. + +## Import + +The import functionality is not supported for this resource. diff --git a/website/docs/r/scc_account_settings.html.markdown b/website/docs/r/scc_account_settings.html.markdown new file mode 100644 index 000000000..5c4bab92c --- /dev/null +++ b/website/docs/r/scc_account_settings.html.markdown @@ -0,0 +1,56 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_account_settings" +description: |- + Manages the account settings scc_account_settings +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_account_settings + +Provides a resource for scc_account_settings. This allows scc_account_settings to be created, updated and deleted. + +~> **NOTE**: exporting out the environmental variable `IBM_CLOUD_SCC_ADMIN_API_ENDPOINT` will help out if the account fails to resolve(e.g. `export IBMCLOUD_SCC_ADMIN_API_ENDPOINT=https://compliance.cloud.ibm.com`) + +## Example Usage + +```terraform +resource "ibm_scc_account_settings" "scc_account_settings" { + location { + location_id = "uk" + } + event_notifications { + instance_crn = "" // Optional field + } +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +> `location_id` will be Deprecated in the near future. Please adjust to using the argument `location` +* `location_id` **Deprecated** - (Optional, Forces new resource, String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. +* `event_notifications` - (Optional, List) The Event Notification settings to register. +Nested scheme for **event_notifications**: + * `instance_crn` - (Optional, String) The Cloud Resource Name (CRN) of the Event Notifications instance that you want to connect. If this field is left blank, no Event Notifications instance will be used. +* `location` - (Optional, List) Location Settings. +Nested scheme for **location**: + * `location_id` - (Required, String) The programatic ID of the location that you want to work in. + * Constraints: Allowable values are: `us`, `eu`, `uk`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the scc_account_settings. + +## Import + +You can import the `ibm_scc_account_settings` resource by using `terraform import `, with the `` being anything you want. + +# Syntax +``` +$ terraform import ibm_scc_account_settings.scc_account_settings +``` diff --git a/website/docs/r/scc_posture_collector.html.markdown b/website/docs/r/scc_posture_collector.html.markdown new file mode 100644 index 000000000..9bb280b4c --- /dev/null +++ b/website/docs/r/scc_posture_collector.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_collector" +description: |- + Manages collectors. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_collector + +Provides a resource for collectors. This allows collectors to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_scc_posture_collector" "collectors" { + description = "sample collector" + is_public = true + managed_by = "ibm" + name = "IBM-collector-sample" + passphrase = "secret" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `description` - (Optional, String) A detailed description of the collector. + * Constraints: The default value is ``. The maximum length is `1000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\._,\\s]*$/`. +* `is_public` - (Required, Boolean) Determines whether the collector endpoint is accessible on a public network. If set to `true`, the collector connects to resources in your account over a public network. If set to `false`, the collector connects to resources by using a private IP that is accessible only through the IBM Cloud private network. +* `is_ubi_image` - (Optional, Boolean) Determines whether the collector has a Ubi image. +* `managed_by` - (Required, String) Determines whether the collector is an IBM or customer-managed virtual machine. Use `ibm` to allow Security and Compliance Center to create, install, and manage the collector on your behalf. The collector is installed in an OpenShift cluster and approved automatically for use. Use `customer` if you would like to install the collector by using your own virtual machine. For more information, check out the [docs](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-collector). + * Constraints: Allowable values are: `ibm`, `customer`. +* `name` - (Required, String) A unique name for your collector. + * Constraints: The maximum length is `32` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. +* `passphrase` - (Optional, String) To protect the credentials that you add to the service, a passphrase is used to generate a data encryption key. The key is used to securely store your credentials and prevent anyone from accessing them. + * Constraints: The maximum length is `200` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\._,\\s]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the collectors. + +## Import + +You can import the `ibm_scc_posture_collector` resource by using `id`. An identifier of the collector. + +# Syntax +``` +$ terraform import ibm_scc_posture_collector.collectors +``` + +# Example +``` +$ terraform import ibm_scc_posture_collector.collectors 1 +``` diff --git a/website/docs/r/scc_posture_credential.html.markdown b/website/docs/r/scc_posture_credential.html.markdown new file mode 100644 index 000000000..4816e8272 --- /dev/null +++ b/website/docs/r/scc_posture_credential.html.markdown @@ -0,0 +1,115 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_credential" +description: |- + Manages credentials. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_credential + +Provides a resource for credentials. This allows credentials to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_scc_posture_credential" "credentials" { + description = "This credential is used for testing." + display_fields {"password":"testpassword","username":"test"} + enabled = true + group = {"id":"1","passphrase":"passphrase"} + name = "test_create" + purpose = "discovery_fact_collection_remediation" + type = "username_password" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `description` - (Required, String) Credentials description. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\._,\\s]*$/`. +* `display_fields` - (Required, List) Details the fields on the credential. This will change as per credential type selected. +Nested scheme for **display_fields**: + * `auth_url` - (Optional, String) auth url of the Open Stack cloud.This is mandatory for Open Stack Credential type ie when type=openstack_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_arn` - (Optional, String) AWS arn value.This is used for AWS Cloud ie when type=aws_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_client_id` - (Optional, String) AWS client Id.This is mandatory for AWS Cloud ie when type=aws_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_client_secret` - (Optional, String) AWS client secret.This is mandatory for AWS Cloud ie when type=aws_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `aws_region` - (Optional, String) AWS region.This is used for AWS Cloud ie when type=aws_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_client_id` - (Optional, String) Azure client Id. This is mandatory for Azure Credential type ie when type=azure_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_client_secret` - (Optional, String) Azure client secret.This is mandatory for Azure Credential type ie when type=azure_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_resource_group` - (Optional, String) Azure resource group.This field is used for Azure Credential type ie when type=azure_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `azure_subscription_id` - (Optional, String) Azure subscription Id.This is mandatory for Azure Credential type ie when type=azure_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `database_name` - (Optional, String) Database name.This is mandatory for Database Credential type ie when type=database. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `ibm_api_key` - (Optional, String) The IBM Cloud API Key. This is mandatory for IBM Credential Type ie when type=ibm_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `ms_365_client_id` - (Optional, String) The MS365 client Id.This is mandatory for Windows MS365 Credential type ie when type=ms_365. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `ms_365_client_secret` - (Optional, String) The MS365 client secret.This is mandatory for Windows MS365 Credential type ie when type=ms_365. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `ms_365_tenant_id` - (Optional, String) The MS365 tenantId.This is mandatory for Windows MS365 Credential type ie when type=ms_365. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `password` - (Optional, String) password of the user.This is mandatory for DataBase(ie type=database), Kerbros(ie type=kerberos_windows),OpenStack(ie type=openstack_cloud) and Username-Password(type=username_password) Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `pem_data` - (Optional, String) The base64 encoded data to associate with the PEM file. + * Constraints: The maximum length is `4000` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + * `pem_file_name` - (Optional, String) The name of the PEM file. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `project_domain_name` - (Optional, String) project domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type ie when type=openstack_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `project_name` - (Optional, String) Project name of the Open Stack cloud.This is mandatory for Open Stack Credential type ie when type=openstack_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `user_domain_name` - (Optional, String) user domain name of the Open Stack cloud.This is mandatory for Open Stack Credential type ie when type=openstack_cloud. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `username` - (Optional, String) username of the user.This is mandatory for DataBase(ie type=database), Kerbros(ie type=kerberos_windows),OpenStack(ie type=openstack_cloud) and Username-Password(type=username_password) Credentials. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `winrm_authtype` - (Optional, String) Kerberos windows auth type.This is mandatory for Windows Kerberos Credential type ie when type=kerberos_windows. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. + * `winrm_port` - (Optional, String) Kerberos windows port.This is mandatory for Windows Kerberos Credential type ie when type=kerberos_windows. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `winrm_usessl` - (Optional, String) Kerberos windows ssl.This is mandatory for Windows Kerberos Credential type ie when type=kerberos_windows. + * Constraints: The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. +* `enabled` - (Required, Boolean) Credentials status enabled/disbaled. +* `group` - (Required, List) Credential group details. +Nested scheme for **group**: + * `id` - (Required, String) credential group id. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9]*$/`. + * `passphrase` - (Required, String) passphase of the credential. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.\\*,_\\s]*$/`. +* `name` - (Required, String) Credentials name. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\._,\\s]*$/`. +* `purpose` - (Required, String) Purpose for which the credential is created. + * Constraints: Allowable values are: `discovery_collection`, `discovery_fact_collection`, `remediation`, `discovery_collection_remediation`, `discovery_fact_collection_remediation`. The maximum length is `100` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. +* `type` - (Required, String) Credentials type. + * Constraints: Allowable values are: `username_password`, `aws_cloud`, `azure_cloud`, `database`, `kerberos_windows`, `ms_365`, `openstack_cloud`, `ibm_cloud`, `user_name_pem`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the credentials. + +## Import + +You can import the `ibm_scc_posture_credential` resource by using `id`. An identifier of the credential. + +# Syntax +``` +$ terraform import ibm_scc_posture_credential.credentials +``` + +# Example +``` +$ terraform import ibm_scc_posture_credential.credentials 1 +``` diff --git a/website/docs/r/scc_posture_profile_import.html.markdown b/website/docs/r/scc_posture_profile_import.html.markdown new file mode 100644 index 000000000..87160fc9c --- /dev/null +++ b/website/docs/r/scc_posture_profile_import.html.markdown @@ -0,0 +1,45 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_profile_import" +description: |- + To Import profile. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_profile_import + +Provides a resource for profiles. This allows profiles to be import a profile that you formatted locally. + +## Example Usage + +```hcl +resource "ibm_scc_posture_profile_import" "profiles" { + file = "/local_path_to_import_profile.csv" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `file` - (Required, Forces new resource, String) The import data file that you want to use to import a profile. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the profiles. + +## Import + +You can import the `ibm_scc_posture_profile_import` resource by using `id`. An identifier of the profile. + +# Syntax +``` +$ terraform import ibm_scc_posture_profile_import.profiles +``` + +# Example +``` +$ terraform import ibm_scc_posture_profile_import.profiles 1 +``` diff --git a/website/docs/r/scc_posture_scan_initiate_validation.html.markdown b/website/docs/r/scc_posture_scan_initiate_validation.html.markdown new file mode 100644 index 000000000..455f27ddb --- /dev/null +++ b/website/docs/r/scc_posture_scan_initiate_validation.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_scan_initiate_validation" +description: |- + To initiate a validation scan. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_scan_initiate_validation + +Provides a resource for initiate a validation scan. This allows to initiate validation scans determine a specified scope's adherence to regulatory controls by validating the configuration of the resources in your scope to the attached profile. + +## Example Usage + +```hcl +resource "ibm_scc_posture_scan_initiate_validation" "scanInitiateValidation" { + scope_id = "scope_id" + profile_id = "profile_id" + group_profile_id = "group_profile_id" + name = "name" + description = "description" + frequency = 1 + no_of_occurrences = 1 +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `scope_id` - (Required, Forces new resource, String) - The unique ID of the scope. +* `profile_id` - (Required, Forces new resource, String) - The unique ID of the profile. +* `group_profile_id` - (Optional, String) - The ID of the profile group. +* `name` - (Optional, String) - The name of a scheduled scan. +* `description` - (Optional, String) - The description of a scheduled scan. +* `frequency` - (Optional, int) - The frequency at which a scan is run specified in milliseconds. +* `no_of_occurrences` - (Optional, int) - The number of times that a scan should be run. +* `end_time` - (Optional, String) - The date on which a scan should stop running specified in UTC. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The correlation identifier of the initiated validation scan. + +## Import + +You can import the `ibm_scc_posture_scan_initiate_validation` resource by using `id`. An identifier of the initiated validation scan. + +# Syntax +``` +$ terraform import ibm_scc_posture_scan_initiate_validation.scans +``` + +# Example +``` +$ terraform import ibm_scc_posture_scan_initiate_validation.scans 1 +``` diff --git a/website/docs/r/scc_posture_scope.html.markdown b/website/docs/r/scc_posture_scope.html.markdown new file mode 100644 index 000000000..d02236846 --- /dev/null +++ b/website/docs/r/scc_posture_scope.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_posture_scope" +description: |- + Manages scopes. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_posture_scope + +Provides a resource for scopes. This allows scopes to be created, updated and deleted. Before creation of the scope, we need to create credential and collector. + +## Example Usage + +```hcl +resource "ibm_scc_posture_scope" "scopes" { + credential_id = "5" + credential_type = "on_premise" + description = "IBMSchema" + interval = 10 + is_discovery_scheduled = true + name = "IBMSchema-new-048-test" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `collector_ids` - (Required, List) The unique IDs of the collectors that are attached to the scope. + * Constraints: The list items must match regular expression `/^[0-9]*$/`. +* `credential_id` - (Required, String) The unique identifier of the credential. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. +* `credential_type` - (Required, String) The environment that the scope is targeted to. + * Constraints: Allowable values are: `ibm`, `aws`, `azure`, `on_premise`, `hosted`, `services`, `openstack`, `gcp`. +* `description` - (Required, String) A detailed description of the scope. + * Constraints: The maximum length is `255` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. +* `interval` - (Optional, Integer) Stores the value of Frequency. This is used in case of on-prem Scope if the user wants to schedule a discovery task.The unit is seconds. Example if a user wants to trigger discovery every hour, this value will be set to 3600. +* `is_discovery_scheduled` - (Optional, Boolean) Stores the value of Discovery Scheduled.This is used in case of on-prem Scope if the user wants to schedule a discovery task. + * Constraints: The default value is `false`. +* `name` - (Required, String) A unique name for your scope. + * Constraints: The maximum length is `50` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9-\\.,_\\s]*$/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the scopes. + +## Import + +You can import the `ibm_scc_posture_scope` resource by using `id`. An identifier of the scope. + +# Syntax +``` +$ terraform import ibm_scc_posture_scope.scopes +``` + +# Example +``` +$ terraform import ibm_scc_posture_scope.scopes 1 +``` diff --git a/website/docs/r/scc_rule.html.markdown b/website/docs/r/scc_rule.html.markdown new file mode 100644 index 000000000..c78553490 --- /dev/null +++ b/website/docs/r/scc_rule.html.markdown @@ -0,0 +1,228 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_rule" +description: |- + Manages scc_rule. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_rule + +Provides a resource for scc_rule. This allows scc_rule to be created, updated and deleted. For more information about Security and Compliance Center rules, see [Defining Rules](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-rules-define&interface=ui). + +## Example Usage + +```hcl +resource "ibm_scc_rule" "scc_rule_tf_example" { + account_id = "thisIsAFake32CharacterAccountID" + name = "Terraform rule" + description = "Cloud Object Storage buckets can only be created in us-south." + labels = ["example"] + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + } + required_config { + // example of a Cloud Object Storage configuration + description = "Cloud Object Storage buckets can only be created in us-south." + property = "location" + operator = "string_equals" + value = "us-south" + } + enforcement_actions { + action = "disallow" + } +} +``` + +In the above example, COS buckets must have `location` set to `us-south` to be compliant. + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `account_id` - (Required, String) Your IBM Cloud account ID, or the account ID that you want to target. +* `name` - (Required, String) A human-readable alias to assign to your rule. + * Constraints: The maximum length is `32` characters. The minimum length is `1` character. +* `description` - (Required, String) An extended description of your rule. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. +* `labels` - (Optional, List) Labels that you can use to group and search for similar rules, such as those that help you to meet a specific organization guideline. + * Constraints: The maximum length is `32` items. +* `enforcement_actions` - (Optional, List) The actions that the service must run on your behalf when a request to create or modify the target resource does not comply with your conditions. + * Constraints: The maximum length is `1` items. +Nested scheme for **enforcement_actions**: + * `action` - (Required, String) To block a request from completing, use `disallow`. + * Constraints: Allowable values are: `disallow`. +* `target` - (Required, List) The properties that describe the resource that you want the rule or template to target. + Nested scheme for **target**: + * `additional_target_attributes` - (Optional, List) An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template. + Nested scheme for **additional_target_attributes**: + * `name` - (Required, String) The name of the additional attribute that you want to use to further qualify the target. Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation. + * `operator` - (Required, String) The way in which the `name` field is compared to its value.There are three types of operators: string, numeric, and boolean. + * Constraints: Allowable values are: + * `string_equals` + * `string_not_equals` + * `string_match` + * `string_not_match` + * `num_equals` + * `num_not_equals` + * `num_less_than` + * `num_less_than_equals` + * `num_greater_than` + * `num_greater_than_equals` + * `is_empty` + * `is_not_empty` + * `is_true` + * `is_false` + * `value` - (Optional, String) The value that you want to apply to `name` field. Options differ depending on the rule or template that you configure. For more information, refer to the service documentation. + * `resource_kind` - (Required, String) The type of resource that you want to target. + * `service_name` - (Required, String) The programmatic name of the IBM Cloud service that you want to target with the rule or template. + * Constraints: The value must match regular expression `/^[a-z-]*$/`. +* `required_config` - (Required, List) +Nested scheme for **required_config**: + * `description` - (Optional, String) + One of the following: + 1. `rule_condition`: + ~> **NOTE**: Currently the `ips_in_range` and `strings_in_list` cannot be used due to a limitation of the scc-go-sdk + * `operator` - (Required, String) The way in which the `property` field is compared to its value. To learn more, see the [docs](/docs/security-compliance?topic=security-compliance-what-is-rule#rule-operators). + * Constraints: Allowable values are: + * `is_true` + * `is_false` + * `is_empty` + * `is_not_empty` + * `string_equals` + * `string_not_equals` + * `string_match` + * `string_not_match` + * `num_equals` + * `num_not_equals` + * `num_less_than` + * `num_less_than_equals` + * `num_greater_than` + * `num_greater_than_equals` + * `property` - (Required, String) A resource configuration variable that describes the property that you want to apply to the target resource.Available options depend on the target service and resource. + * `value` - (Optional, String) The way in which you want your property to be applied. Value options differ depending on the rule that you configure. If you use a boolean operator, you do not need to input a value. + + example schema for using `rule_condition`: + ```terraform + required_config { + description = "test config" + property = "location" + operator = "string_not_equals" + value = "eu-de" + } + ``` + The above example details a `required_config` that has a single rule_condition + 2. `and/or` - (Optional, List) A list of `rule_condition` that should be set for the rule. If `and` is being used, it means that every `rule_condition` in the list must be true. If `or` is being used, it means that at least one `rule_condition` in the list needs to be true. + + ~> **NOTE**: The required_config must have only one of following: `and`, `or`, or `rule_condtion`. These values cannot be mixed with each other at the same depth (i.e. 'or' and 'and' cannot be defined at the same level/depth) + + example schema for using `and/or`: + + + + + + + + + +
Terraform JSON
+ + ```hcl + required_config { + description = "test config" + and { // rule_condition[0] + property = "storage_class" + operator = "string_equals" + value = "smart" + } + and { // rule_condition[1] + property = "location" + operator = "string_equals" + value = "us-south" + } + } + ``` + + + + ```json + required_config: { + "description": "test config", + "and": [ + { + "property": "storage_class", + "operator": "string_equals", + "value": "smart" + }, + { + "property": "location", + "operator": "string_equals", + "value": "us-south" + } + ] + } + ``` + +
+ The above example details a `required_config` that has two `rule_condition`s and it is equivalent to: + ``` + rule_condtion[0] && rule_condition[1] + ``` + + Replace both `and` with `or` in the example above if you want the following logic: + ``` + rule_condition[0] || rule_condition[1] + ``` + + Users can also create nested rules (with a maximum depth of 2 levels). + Example (with a depth of 2): + ```hcl + required_config { + and { + // A + } + and { + or { + // B + } + or { + // C + } + } + ``` + The above example is equivalent to: `A && (B || C)` + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the ibm_scc_rule. +* `created_by` - (Optional, String) The unique identifier for the user or application that created the resource. +* `creation_date` - (Optional, String) The date the resource was created. +* `enforcement_actions` - (Required, List) The actions that the service must run on your behalf when a request to create or modify the target resource does not comply with your conditions. + * Constraints: The maximum length is `1` items. +Nested scheme for **enforcement_actions**: + * `action` - (Required, String) To block a request from completing, use `disallow`. + * Constraints: Allowable values are: `disallow`. +* `modification_date` - (Optional, String) The date the resource was last modified. +* `modified_by` - (Optional, String) The unique identifier for the user or application that last modified the resource. +* `version` - Version of the ibm_scc_rule. +* `rule_type` - (Optional, String) The type of rule. Rules that you create are `user_defined`. + * Constraints: Allowable values are: `user_defined`. + +## Import + +You can import the `ibm_scc_rule` resource by using `rule_id`. The UUID that uniquely identifies the rule. + +# Syntax +``` +$ terraform import ibm_scc_rule.scc_rule +``` + +# Example +``` +$ terraform import ibm_scc_rule.scc_rule rule-81f3db5e-f9db-4c46-9de3-a4a76e66adbf +``` diff --git a/website/docs/r/scc_rule_attachment.html.markdown b/website/docs/r/scc_rule_attachment.html.markdown new file mode 100644 index 000000000..b2c020042 --- /dev/null +++ b/website/docs/r/scc_rule_attachment.html.markdown @@ -0,0 +1,91 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_rule_attachment" +description: |- + Manages scc_rule_attachment. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_rule_attachment + +Provides a resource for ibm_scc_rule_attachment. This allows ibm_scc_rule_attachment to be created, updated and deleted. For more information about Security and Compliance Center rule attachments, see [Applying Rules](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-rules-apply&interface=ui). + +~> **NOTE**: This resource depends on a `ibm_scc_rule` to be created before creating this resource. The object `ibm_scc_rule_attachment` must attach to an exiting rule. + +## Example Usage + +```hcl +resource "ibm_scc_rule" scc_rule_instance { + // example of a ibm_scc_rule that needs to be used in conjunction with ibm_scc_rule_attachment +} + +resource "ibm_scc_rule_attachment" "scc_rule_attachment_instance" { + account_id = "thisIsAFake32CharacterAccountID" + included_scope { + note = "This is a note to reference my account" + scope_id = "thisIsAFake32CharacterAccountID" // value determined by scope type + scope_type = "account" + } + excluded_scopes { + note = "This is a note to exclude a specific resource group" + scope_id = "" // value determined by scope type + scope_type = "account.resource_group" + } + rule_id = ibm_scc_rule.scc_rule_instance.id // from the resource ibm_scc_rule + depends_on = [ + ibm_scc_rule.scc_rule_instance // ensures that the rule is created first + ] +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `account_id` - (Required, String) Your IBM Cloud account ID. +* `included_scope` - (Required, List) The extent at which the rule can be attached across your accounts. +Nested scheme for **included_scope**: + * `note` - (Optional, String) A short description or alias to assign to the scope. + * `scope_id` - (Required, String) The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate. + * `scope_type` - (Required, String) The type of scope that you want to evaluate. + * Constraints: Allowable values are: + * `enterprise`, + * `enterprise.account_group`, + * `enterprise.account`, + * `account`, + * `account.resource_group`. + * `Constraints`: Only one `included_scope` item is allowed +* `rule_id` - (Required, Forces new resource, String) The UUID that uniquely identifies the rule. +* `excluded_scopes` - (Optional, List) The extent at which the rule can be excluded from the included scope. +Nested scheme for **excluded_scopes**: + * `note` - (Optional, String) A short description or alias to assign to the scope. + * `scope_id` - (Required, String) The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate. + * `scope_type` - (Required, String) The type of scope that you want to evaluate. + * Constraints: Allowable values are: + * `enterprise`, + * `enterprise.account_group`, + * `enterprise.account`, + * `account`, + * `account.resource_group`. +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `attachment_id` - (Required, String) The UUID that uniquely identifies the attachment +* `version` - Version of the ibm_scc_rule_attachment. + +## Import + +You can import the `ibm_scc_rule_attachment` resource by using `attachment_id`. +The `attachment_id` property can be formed from `rule_id`, and `attachment_id` in the following format: + +``` +/ +``` +* `rule_id`: A string. The UUID that uniquely identifies the rule. +* `attachment_id`: A string. The UUID that uniquely identifies the attachment. + +# Syntax +``` +$ terraform import ibm_scc_rule_attachment.scc_rule_attachment / +``` diff --git a/website/docs/r/scc_si_note.html.markdown b/website/docs/r/scc_si_note.html.markdown index 1eea1cb07..c246f5b37 100644 --- a/website/docs/r/scc_si_note.html.markdown +++ b/website/docs/r/scc_si_note.html.markdown @@ -6,15 +6,18 @@ description: |- Manages scc_si_note. --- +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + # ibm_scc_si_note Provides a resource for scc_si_note. This allows scc_si_note to be created, updated and deleted. -## Example Usage +## Example usage #### FINDING -```hcl +```terraform resource "ibm_scc_si_note" "finding" { provider_id = "scc" short_description = "Security Threat" @@ -38,7 +41,7 @@ resource "ibm_scc_si_note" "finding" { #### KPI -```hcl +```terraform resource "ibm_scc_si_note" "kpi" { provider_id = "scc" short_description = "Security Threat" @@ -58,7 +61,7 @@ resource "ibm_scc_si_note" "kpi" { #### CARD -```hcl +```terraform resource "ibm_scc_si_note" "ts-card-finding" { provider_id = "scc" short_description = "Security Threat" @@ -89,7 +92,7 @@ resource "ibm_scc_si_note" "ts-card-finding" { } ``` -## Argument Reference +## Argument reference Review the argument reference that you can specify for your resource. @@ -169,7 +172,7 @@ Nested scheme for **section**: * Constraints: The default value is `true`. * `short_description` - (Required, String) A one sentence description of your note. -## Attribute Reference +## Attribute reference In addition to all argument references listed, you can access the following attribute references after your resource is created. @@ -191,5 +194,5 @@ The `note_id` property can be formed from `account_id`, `provider_id`, and `note # Syntax ``` -$ terraform import ibm_scc_si_note.scc_si_note / +$ terraform import ibm_scc_si_note.scc_si_note // ``` diff --git a/website/docs/r/scc_si_occurrence.html.markdown b/website/docs/r/scc_si_occurrence.html.markdown new file mode 100644 index 000000000..c211cbb86 --- /dev/null +++ b/website/docs/r/scc_si_occurrence.html.markdown @@ -0,0 +1,142 @@ +--- +layout: "ibm" +subcategory: "Security and Compliance Center" +page_title: "IBM : ibm_scc_si_occurrence" +description: |- + Manages Security and Compliance Center occurrence. +--- + +# DEPRECATED +Security and Compliance Center - Security Insights has now deprecated, backend services are no longer available. The docs will be removed in next release. + +# ibm_scc_si_occurrence + +Create, update, or delete for a Security and Compliance Center occurrence. For more information, about Security and Compliance Center, see [getting started with Security and Compliance Center](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-getting-started). + +## Example usage + +#### FINDING + +```terraform +resource "ibm_scc_si_occurrence" "finding-occurrence" { + provider_id = var.provider_id + note_name = var.note_name + kind = "FINDING" + occurrence_id = "finding-occ" + resource_url = "https://cloud.ibm.com" + remediation = "Limit the cluster access" + finding { + severity = "LOW" + certainty = "LOW" + next_steps { + title = "Security Threat" + url = "https://cloud.ibm.com/security-compliance/findings" + } + } +} +``` + +#### KPI + +```terraform +resource "ibm_scc_si_occurrence" "kpi-occurrence" { + provider_id = var.provider_id + note_name = var.note_name + kind = "KPI" + occurrence_id = "kpi-occ" + resource_url = "https://cloud.ibm.com" + remediation = "Limit the cluster access" + kpi { + value = 40 + total = 100 + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `context` - (Optional, List) + + Nested scheme for **context**: + - `component_name` - (Optional, String) The name of the component the occurrence applies to. + - `environment_name` - (Optional, String) The name of the environment the occurrence applies to. + - `region` - (Optional, String) The IBM Cloud region. + - `resource_crn` - (Optional, String) The resource CRN (e.g. certificate CRN, image CRN). + - `resource_id` - (Optional, String) The resource ID, in case the CRN is not available. + - `resource_name` - (Optional, String) The user-friendly resource name. + - `resource_type` - (Optional, String) The resource type name (e.g. Pod, Cluster, Certificate, Image). + - `service_crn` - (Optional, String) The service CRN (e.g. CertMgr Instance CRN). + - `service_name` - (Optional, String) The service name (e.g. CertMgr). + - `toolchain_id` - (Optional, String) The id of the toolchain the occurrence applies to. +- `finding` - (Optional, List) Finding provides details about a finding occurrence. + + Nested scheme for **finding**: + - `certainty` - (Optional, String) Note provider-assigned confidence on the validity of an occurrence- LOW: Low Certainty- MEDIUM: Medium Certainty- HIGH: High Certainty. + - Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`. + - `data_transferred` - (Optional, List) It provides details about data transferred between clients and servers. + + Nested scheme for **data_transferred**: + - `client_bytes` - (Optional, Integer) The number of client bytes transferred. + - `client_packets` - (Optional, Integer) The number of client packets transferred. + - `server_bytes` - (Optional, Integer) The number of server bytes transferred. + - `server_packets` - (Optional, Integer) The number of server packets transferred. + - `network_connection` - (Optional, List) It provides details about a network connection. + + Nested scheme for **network_connection**: + * `client` - (Optional, List) It provides details about a socket address. + Nested scheme for **client**: + * `address` - (Required, String) The IP address of this socket address. + * `port` - (Optional, Integer) The port number of this socket address. + * `direction` - (Optional, String) The direction of this network connection. + * `protocol` - (Optional, String) The protocol of this network connection. + * `server` - (Optional, List) It provides details about a socket address. + Nested scheme for **server**: + * `address` - (Required, String) The IP address of this socket address. + * `port` - (Optional, Integer) The port number of this socket address. + * `next_steps` - (Optional, List) Remediation steps for the issues reported in this finding. They override the note's next steps. + Nested scheme for **next_steps**: + * `title` - (Optional, String) Title of this next step. + * `url` - (Optional, String) The URL associated to this next steps. + * `severity` - (Optional, String) Note provider-assigned severity/impact ranking- LOW: Low Impact- MEDIUM: Medium Impact- HIGH: High Impact- CRITICAL: Critical Impact. + * Constraints: Allowable values are: `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`. +* `kind` - (Required, String) The type of note. Use this field to filter notes and occurrences by kind. - FINDING: The note and occurrence represent a finding. - KPI: The note and occurrence represent a KPI value. - CARD: The note represents a card showing findings and related metric values. - CARD_CONFIGURED: The note represents a card configured for a user account. - SECTION: The note represents a section in a dashboard. + * Constraints: Allowable values are: `FINDING`, `KPI`, `CARD`, `CARD_CONFIGURED`, `SECTION`. +* `kpi` - (Optional, List) Kpi provides details about a KPI occurrence. +Nested scheme for **kpi**: + * `total` - (Optional, Float) The total value of this KPI. + * `value` - (Required, Float) The value of this KPI. +* `note_name` - (Required, String) An analysis note associated with this image, in the form "{account_id}/providers/{provider_id}/notes/{note_id}" This field can be used as a filter in list requests. +* `account_id` - (Optional, Forces new resource, String) Account ID is optional, if not provided value will be inferred from the token retrieved from the IBM Cloud API key. +* `occurrence_id` - (Required, Forces new resource, String) The ID of the occurrence. +* `provider_id` - (Required, Forces new resource, String) Part of the parent. This field contains the provider ID. For example: providers/{provider_id}. +* `remediation` - (Optional, String) A description of actions that can be taken to remedy the `Note`. +* `replace_if_exists` - (Optional, Boolean) When set to true, an existing occurrence is replaced rather than duplicated. +* `resource_url` - (Optional, String) The unique URL of the resource, image or the container, for which the `Occurrence` applies. For example, https://gcr.io/provider/image@sha256:foo. This field can be used as a filter in list requests. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the scc_si_occurrence. +- `create_time` - (Optional, String) Output only. The time this `Occurrence` was created. +- `update_time` - (Optional, String) Output only. The time this `Occurrence` was last updated. + +## Import + +You can import the `ibm_scc_si_occurrence` resource by using `id`. +The `id` property can be formed from `provider_id`, and `occurrence_id` in the following format: + +```sh +// +``` +- `account_id` - A string. AccountID from the resource has to be imported. +- `provider_id`: A string. Part of the parent. This field contains the provider ID. For example: **providers/{provider_id}**. +- `occurrence_id`: A string. Second part of occurrence `name`: **providers/{provider_id}/occurrences/{occurrence_id}**. + +# Syntax + +```sh +$ terraform import ibm_scc_si_occurrence.scc_si_occurrence // +``` diff --git a/website/docs/r/scc_template.html.markdown b/website/docs/r/scc_template.html.markdown new file mode 100644 index 000000000..3854ee6f8 --- /dev/null +++ b/website/docs/r/scc_template.html.markdown @@ -0,0 +1,85 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_template" +description: |- + Manages scc_template. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_template + +Provides a resource for scc_template. This allows scc_template to be created, updated and deleted. For more information about Security and Compliance Center templates, see [Defining Templates](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-templates-define&interface=ui). + +## Example Usage + +```hcl +resource "ibm_scc_template" "scc_template_tf_example" { + account_id = var.account_id + name = "Terraform template" + description = "COS buckets in us-south should send write data events to Activity Tracker by default" + target { + service_name = "cloud-object-storage" + resource_kind = "bucket" + additional_target_attributes { + name = "location" + value = "us-south" + } + } + customized_defaults { + property = "activity_tracking.write_data_events" + value = "true" + } +} +``` + +In the above example, new COS buckets in `us-south` will send write data events to Activity Tracker by default. + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `account_id` - (Required, String) Your IBM Cloud account ID. +* `name` - (Required, String) A human-readable alias to assign to your template. + * Constraints: The maximum length is `32` characters. The minimum length is `1` character. +* `description` - (Required, String) An extended description of your template. + * Constraints: The maximum length is `256` characters. The minimum length is `1` character. +* `target` - (Required, List) The properties that describe the resource that you want to target with the rule or template. + Nested scheme for ** target**: + * `service_name` - (Required, String) The programmatic name of the IBM Cloud service that you want to target with the + rule or template. + * Constraints: The value must match regular expression `/^[a-z-]*$/`. + * `resource_kind` - (Required, String) The type of resource that you want to target. +* `additional_target_attributes` - (Optional, List) An extra qualifier for the resource kind. When you include additional attributes, only the resources that match the definition are included in the rule or template. + * Nested scheme for **additional_target_attributes**: + * `name` - (Required, String) The name of the additional attribute that you want to use to further qualify the target. Options differ depending on the service or resource that you are targeting with a rule or template. For more information, refer to the service documentation. + * `value` - (Required, String) The value that you want to apply to `name` field. Options differ depending on the rule or template that you configure. For more information, refer to the service documentation. +* `customized_defaults` - (Required, List) A list of default property values to apply to your template. + Nested scheme for **customized_defaults**: + * `property` - (Required, String) The name of the resource property that you want to configure. Property options differ depending on the service or resource that you are targeting with a template. To view a list of properties that are compatible with templates, refer to the service documentation. + * `value` - (Required, String) The custom value that you want to apply as the default for the resource property in the `name` field. This value is used to override the default value that is provided by IBM when a resource is created. Value options differ depending on the resource that you are configuring. To learn more about your options, refer to the service documentation. + + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the ibm_scc_template. +* `created_by` - (Optional, String) The unique identifier for the user or application that created the resource. +* `creation_date` - (Optional, String) The date the resource was created. +* `modification_date` - (Optional, String) The date the resource was last modified. +* `modified_by` - (Optional, String) The unique identifier for the user or application that last modified the resource. +* `version` - Version of the ibm_scc_template. + +## Import + +You can import the `ibm_scc_template` resource by using `template_id`. The UUID that uniquely identifies the template. + +# Syntax +``` +$ terraform import ibm_scc_template.scc_template +``` + +# Example +``` +$ terraform import ibm_scc_template.scc_template template-702d1db7-ca4a-414b-8464-2b517a065c14 +``` diff --git a/website/docs/r/scc_template_attachment.html.markdown b/website/docs/r/scc_template_attachment.html.markdown new file mode 100644 index 000000000..875647e13 --- /dev/null +++ b/website/docs/r/scc_template_attachment.html.markdown @@ -0,0 +1,92 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_scc_template_attachment" +description: |- + Manages scc_template_attachment. +subcategory: "Security and Compliance Center" +--- + +# ibm_scc_template_attachment + +Provides a resource for scc_template_attachment. This allows scc_template_attachment to be created, updated and deleted. For more information about Security and Compliance Center template attachments, see [Applying Templates](https://cloud.ibm.com/docs/security-compliance?topic=security-compliance-templates-apply&interface=ui). + +~> **NOTE**: This resource depends on a `ibm_scc_template` to be created before creating this resource. The object `ibm_scc_template_attachment` must attach to an exiting template. + +## Example Usage + +```hcl +resource "ibm_scc_template" scc_template_instance { + // example of a ibm_scc_template that needs to be used in conjunction with ibm_scc_template_attachment +} + +resource "ibm_scc_template_attachment" "scc_template_attachment_instance" { + account_id = "thisIsAFake32CharacterAccountID" + included_scope { + note = "This is a note to reference my account" + scope_id = "thisIsAFake32CharacterAccountID" // value determined by scope type + scope_type = "account" + } + excluded_scopes { + note = "This is a note to exclude a specific resource group" + scope_id = "" // value determined by scope type + scope_type = "account.resource_group" + } + template_id = ibm_scc_template.scc_template_instance.id // from the resource ibm_scc_template + depends_on = [ + ibm_scc_template.scc_template_instance // ensures that the template is created first + ] +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `account_id` - (Required, String) Your IBM Cloud account ID. +* `included_scope` - (Required, List) The extent at which the template can be attached across your accounts. + Nested scheme for **included_scope**: + * `note` - (Optional, String) A short description or alias to assign to the scope. + * `scope_id` - (Required, String) The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate. + * `scope_type` - (Required, String) The type of scope that you want to evaluate. + * Constraints: Allowable values are: + * `enterprise`, + * `enterprise.account_group`, + * `enterprise.account`, + * `account`, + * `account.resource_group`. + * `Constraints`: Only one `included_scope` item is allowed +* `template_id` - (Required, Forces new resource, String) The UUID that uniquely identifies the template. +* `excluded_scopes` - (Optional, List) The extent at which the template can be excluded from the included scope. + Nested scheme for **excluded_scopes**: + * `note` - (Optional, String) A short description or alias to assign to the scope. + * `scope_id` - (Required, String) The ID of the scope, such as an enterprise, account, or account group, that you want to evaluate. + * `scope_type` - (Required, String) The type of scope that you want to evaluate. + * Constraints: Allowable values are: + * `enterprise`, + * `enterprise.account_group`, + * `enterprise.account`, + * `account`, + * `account.resource_group`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `attachment_id` - (Required, String) The UUID that uniquely identifies the attachment +* `version` - Version of the ibm_scc_template_attachment. + +## Import + +You can import the `ibm_scc_template_attachment` resource by using `attachment_id`. +The `attachment_id` property can be formed from `template_id`, and `attachment_id` in the following format: + +``` +/ +``` +* `template_id`: A string. The UUID that uniquely identifies the template. +* `attachment_id`: A string. The UUID that uniquely identifies the attachment. + +# Syntax +``` +$ terraform import ibm_scc_template_attachment.scc_template_attachment / +``` diff --git a/website/docs/r/schematics_action.html.markdown b/website/docs/r/schematics_action.html.markdown index 5ee479723..d9969b1d1 100644 --- a/website/docs/r/schematics_action.html.markdown +++ b/website/docs/r/schematics_action.html.markdown @@ -22,98 +22,207 @@ resource "ibm_schematics_action" "schematics_action" { ``` ## Argument reference -Review the argument references that you can specify for your resource. -- `bastion` - (Optional, List) Complete target details with the user inputs and the system generated data. +Review the argument reference that you can specify for your resource. - Nested scheme for `bastion`: - - `created_at` - (Optional, TypeString) The targets creation time. - - `created_by` - (Optional, String) E-mail address of the user who created the targets. - - `credential` - (Optional, String) Override credential for each resource. Reference to credentials values, that are used by the resources. - - `description` - (Optional, String) The target description. - - `id` - (Optional, String) The target ID. - - `name` - (Optional, String) The target name. - - `resource_ids` - (Optional, []interface{}) Array of the resource IDs. - - `resource_query` - (Optional, String) The resource selection query string. - - `sys_lock` - (Optional, SystemLock) The System lock status. - - `type` - (Optional, String) The target type such as `cluster`, `vsi`, `icd`, `vpc`. - - `updated_at` - (Optional, TypeString) The targets updation time. - - `updated_by` - (Optional, String) E-mail address of user who updated the targets. -- `command_parameter` - (Optional, String) The Schematics job command parameter such as `playbook-name`, `capsule-name` or `flow-name`. -- `credentials` - (Optional, List) The credentials of an action. +- `action_inputs` - (Optional, List) Input variables for the Action. +Nested scheme for **action_inputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `action_outputs` - (Optional, List) Output variables for the Action. +Nested scheme for **action_outputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `bastion` - (Optional, List) Describes a bastion resource. MaxItems: 1. +Nested scheme for **bastion**: + * `name` - (Optional, String) Bastion Name(Unique). + * `host` - (Optional, String) Reference to the Inventory resource definition. +* `bastion_credential` - (Optional, List) User editable variable data & system generated reference to value. MaxItems: 1 +Nested scheme for **bastion_credential**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `command_parameter` - (Optional, String) Schematics job command parameter (playbook-name). +* `credentials` - (Optional, List) credentials of the Action. MaxItems: 1. +Nested scheme for **credentials**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `description` - (Optional, String) Action description. +* `inventory` - (Optional, String) Target inventory record ID, used by the action or ansible playbook. +* `location` - (Optional, String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de +* `name` - (Required, String) The unique name of your action. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. **Example** you can use the name to stop action. +* `resource_group` - (Optional, String) Resource-group name for an action. By default, action is created in default resource group. +* `settings` - (Optional, List) Environment variables for the Action. +Nested scheme for **settings**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `source` - (Optional, List) Source of templates, playbooks, or controls. +Nested scheme for **source**: + * `source_type` - (Required, String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `git` - (Optional, List) Connection details to Git source. + Nested scheme for **git**: + * `computed_git_repo_url` - (Optional, String) The Complete URL which is computed by git_repo_url, git_repo_folder and branch. + * `git_repo_url` - (Optional, String) URL to the GIT Repo that can be used to clone the template. + * `git_token` - (Optional, String) Personal Access Token to connect to Git URLs. + * `git_repo_folder` - (Optional, String) Name of the folder in the Git Repo, that contains the template. + * `git_release` - (Optional, String) Name of the release tag, used to fetch the Git Repo. + * `git_branch` - (Optional, String) Name of the branch, used to fetch the Git Repo. + * `catalog` - (Optional, List) Connection details to IBM Cloud Catalog source. MaxItems:1. + Nested scheme for **catalog**: + * `catalog_name` - (Optional, String) name of the private catalog. + * `offering_name` - (Optional, String) Name of the offering in the IBM Catalog. + * `offering_version` - (Optional, String) Version string of the offering in the IBM Catalog. + * `offering_kind` - (Optional, String) Type of the offering, in the IBM Catalog. + * `offering_id` - (Optional, String) Id of the offering the IBM Catalog. + * `offering_version_id` - (Optional, String) Id of the offering version the IBM Catalog. + * `offering_repo_url` - (Optional, String) Repo Url of the offering, in the IBM Catalog. +* `source_readme_url` - (Optional, String) URL of the `README` file, for the source URL. +* `source_type` - (Optional, String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket +* `state` - (Optional, List) Computed state of the Action. +Nested scheme for **state**: + * `status_code` - (Optional, String) Status of automation (workspace or action). + * Constraints: Allowable values are: normal, pending, disabled, critical + * `status_job_id` - (Optional, String) Job id reference for this status. + * `status_message` - (Optional, String) Automation status message - to be displayed along with the status_code. +* `sys_lock` - (Optional, List) System lock status. +Nested scheme for **sys_lock**: + * `sys_locked` - (Optional, Boolean) Is the automation locked by a Schematic job ?. + * `sys_locked_by` - (Optional, String) Name of the User who performed the job, that lead to the locking of the automation. + * `sys_locked_at` - (Optional, String) When the User performed the job that lead to locking of the automation ?. +* `tags` - (Optional, List) Action tags. +* `targets_ini` - (Optional, String) Inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps). +* `user_state` - (Optional, List) User defined status of the Schematics object. +Nested scheme for **user_state**: + * `state` - (Optional, String) User-defined states * `draft` Object can be modified; can be used by Jobs run by the author, during execution * `live` Object can be modified; can be used by Jobs during execution * `locked` Object cannot be modified; can be used by Jobs during execution * `disable` Object can be modified. cannot be used by Jobs during execution. + * Constraints: Allowable values are: draft, live, locked, disable + * `set_by` - (Optional, String) Name of the User who set the state of the Object. + * `set_at` - (Optional, String) When the User who set the state of the Object. +* `x_github_token` - (Optional, String) The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template. - Nested scheme for `credentials`: - - `link` - (Optional, String) The reference link to the variable value. By default the expression will point to `self.value`. - - `metadata` - (Optional, VariableMetadata) An user editable metadata for the variables. - - `name` - (Optional, String) The name of the variable. - - `value` - (Optional, String) The value for the variable or reference to the value. -- `inputs` - (Optional, List) The input variables for an action. - - Nested scheme for `inputs`: - - `link` - (Optional, String) The reference link to the variable value. By default the expression will point to `self.value`. - - `metadata` - (Optional, VariableMetadata) An user editable metadata for the variables. - - `name` - (Optional, String) The name of the variable. - - `value` - (Optional, String) The value for the variable or reference to the value. -- `outputs` - (Optional, List) The output variables for an action. - - Nested scheme for `outputs`: - - `link` - (Optional, String) The reference link to the variable value. By default the expression will point to `self.value`. - - `metadata` - (Optional, VariableMetadata) An user editable metadata for the variables. - - `name` - (Optional, String) The name of the variable. - - `value` - (Optional, String) The value for the variable or reference to the value. -- `description` - (Optional, String) The description of an action. -- `location` - (Optional, String) List of an action locations supported by Schematics service. **Note** this does not limit the location of the resources provisioned using Schematics. -- `name` - (Optional, String) The unique name of an action. -- `resource_group` - (Optional, String) The resource group name for an action. By default, action is created in default resource group. -- `source_readme_url` - (Optional, String) The URL of the `README` file, for the source. -- `source` - (Optional, List) The source of templates, playbooks, or controls. - - Nested scheme for `source`: - - `git` - (Optional, ExternalSourceGit) The connection details to the Git source. - - `source_type` - (Required, String) Type of source for the Template. -- `source_type` - (Optional, String) The source type for the template. -- `settings` - (Optional, List) The environment variables for an action. - - Nested scheme for `settings`: - - `link` - (Optional, String) The reference link to the variable value. By default the expression will point to `self.value`. - - `metadata` - (Optional, VariableMetadata) An user editable metadata for the variables. - - `name` - (Optional, String) The name of the variable. - - `value` - (Optional, String) The value for the variable or reference to the value. -- `state` - (Optional, List) The computed state of an action. +## Attribute reference - Nested scheme for `state`: - - `status_code` - (Optional, String) The status of automation, such as `workspace` or `action`. - - `status_message` - (Optional, String) An automation status message that are displayed along with the status_code. -- `sys_lock` - (Optional, List) The system lock status. +In addition to all argument references listed, you can access the following attribute references after your resource is created. - Nested scheme for `sys_lock`: - - `sys_locked` - (Optional, Bool) Is the Workspace locked by the Schematic action? - - `sys_locked_by` - (Optional, String) The name of the user who performed the action, that lead to lock the Workspace. - - `sys_locked_at` - (Optional, TypeString) When the user performed an action has lead to lock the Workspace? -- `targets_ini` - (Optional, String) Inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](/docs/schematics?topic=schematics-schematics-cli-reference#schematics-inventory-host-grps). -- `tags`- (Optional, List) An actions tags. -- `trigger_record_id` - (Optional, String) The trigger record ID. -- `user_state` - (Optional, List) User defined status of the Schematics object. +* `id` - The unique identifier of the schematics_action. +* `account` - (Optional, String) Action account ID. +* `created_at` - (String) Action creation time. +* `created_by` - (String) E-mail address of the user who created an action. +* `crn` - (Optional, String) Action Cloud Resource Name. +* `playbook_names` - (Optional, List) Playbook names retrieved from the respository. +* `source_created_at` - (String) Action Playbook Source creation time. +* `source_created_by` - (String) E-mail address of user who created the Action Playbook Source. +* `source_updated_at` - (String) The action playbook updation time. +* `source_updated_by` - (String) E-mail address of user who updated the action playbook source. +* `updated_at` - (String) Action updation time. +* `updated_by` - (String) E-mail address of the user who updated an action. - Nested scheme for `user_state`: - - `state` - (Optional, String) User defined states * **draft Object** can be modified, and can be used by jobs run by an author, during execution * **live Object** can be modified, and can be used by jobs during execution * **locked Object** cannot be modified, and can be used by jobs during execution * disable Object can be modified, and cannot be used by Jobs during execution. - - `set_by` - (Optional, String) Name of the user who set the state of an object. - - `set_at` - (Optional, TypeString) The user who set the state of an object. -- `x_github_token` - (Optional, String) The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template. +## Import -## Attribute reference -In addition to all argument reference list, you can access the following attribute reference after your resource is created. +You can import the `ibm_schematics_action` resource by using `id`. Action ID. -- `account` - (String) An action account ID. -- `crn` - (String) An action Cloud Resource Name (`CRN`). -- `created_at` - (Timestamp) An action creation time. -- `created_by` - (String) An Email address of the user who created an action. -- `id` - (String) The unique identifier of the Schematics workspace. -- `namespace` - (String) The name of the namespace. -- `playbook_names` - (String) The playbook names retrieved from the repository. -- `source_created_at` - (Timestamp) An Ansible playbook source creation time. -- `source_created_by` - (String) An Email address of the user who created an Ansible playbook source. -- `source_updated_at` - (Timestamp) The action playbook update time. -- `source_updated_by` - (String) An Email address of the user who updated the action playbook source. -- `updated_at` - (Timestamp) An action update time. -- `updated_by` - (String) An Email address of the user who updated an action. +# Syntax +``` +$ terraform import ibm_schematics_action.schematics_action +``` \ No newline at end of file diff --git a/website/docs/r/schematics_inventory.html.markdown b/website/docs/r/schematics_inventory.html.markdown new file mode 100644 index 000000000..2ffac998d --- /dev/null +++ b/website/docs/r/schematics_inventory.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Schematics" +layout: "ibm" +page_title: "IBM : ibm_schematics_inventory" +sidebar_current: "docs-ibm-resource-schematics-inventory" +description: |- + Manages the Schematics inventory. +--- + +# ibm_schematics_inventory + +Create, update, or delete for a Schematics inventory. For more information, about Schematics action inventories, see [Creating resource inventories for Schematics actions](https://cloud.ibm.com/docs/schematics?topic=schematics-inventories-setup). + +## Example usage + +```terraform +resource "ibm_schematics_inventory" "schematics_inventory" { +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +* `description` - (Optional, String) The description of your inventory definition. The description can be up to `2048` characters long in size. +* `inventories_ini` - (Optional, String) Input inventory of host and host group for the playbook, in the `.ini` file format. +* `location` - (Optional, String) List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. **Note** this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: `us-south`, `us-east`, `eu-gb`, `eu-de` +* `name` - (Optional, String) The unique name of your inventory definition. The name can be up to `128` characters long and can include alphanumeric characters, spaces, dashes, and underscores. + * Constraints: The maximum length is `64` characters. The minimum length is `3` characters. +* `resource_group` - (Optional, String) The resource group name for the inventory definition. By default, inventory definition will be created in `Default` resource group. +* `resource_queries` - (Optional, List) Input resource query definitions that is used to dynamically generate the inventory of host and host group for the playbook. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the schematics_inventory. +* `created_at` - (String) Inventory creation time. +* `created_by` - (String) Email address of user who created the inventory. +* `updated_at` - (String) Inventory updation time. +* `updated_by` - (String) Email address of user who updated the inventory. + +## Import + +You can import the `ibm_schematics_inventory` resource by using `id`. inventory ID. + +# Syntax + +```sh +$ terraform import ibm_schematics_inventory.schematics_inventory +``` diff --git a/website/docs/r/schematics_job.html.markdown b/website/docs/r/schematics_job.html.markdown index 5df8d73bd..49c20e61d 100644 --- a/website/docs/r/schematics_job.html.markdown +++ b/website/docs/r/schematics_job.html.markdown @@ -23,80 +23,602 @@ resource "ibm_schematics_job" "schematics_job" { ``` ## Argument reference -Review the argument references that you can specify for your resource. -- `bastion`- (Optional, List) Complete target details with the user inputs and the system generated data. +Review the argument reference that you can specify for your resource. - Nested scheme for `bastion`: - - `credential`- (Optional, String) Override the credential for each resource. Reference to credentials values, used by all the resources. - - `created_at`- (Optional, TypeString) The targets creation time. - - `created_by`- (Optional, String) The Email address of the user who created the targets. - - `description`- (Optional, String) The target description. - - `id`- (Optional, String) The target ID. - - `name`- (Optional, String) The target name. - - `resource_query`- (Optional, String) The resource selection query string. - - `resource_ids`- (Optional, []interface{}) An array of the resource IDs. - - `sys_lock`- (Optional, SystemLock) The system lock status. - - `type`- (Optional, String) The target type such as `cluster`, `vsi`, `icd`, `vpc`. - - `updated_at`- (Optional, TypeString) The targets update time. - - `updated_by`- (Optional, String) The Email address of user who updated the targets. -- `command_object`- (Optional, String) The name of the Schematics automation resource. -- `command_object_id`- (Optional, String) The job command object ID. Supported values are `workspace-id`, `action-id`, or `control-id`. -- `command_name`- (Optional, String) The Schematics job command name. -- `command_parameter`- (Optional, String) The Schematics job command parameter. Supported values are `playbook-name`, `capsule-name`, or `flow-name`. -- `command_options`- (Optional, List) The command line options for the command. -- `data`- (Optional, List) The job data. +* `bastion` - (Optional, List) Describes a bastion resource. MaxItems: 1. +Nested scheme for **bastion**: + * `name` - (Optional, String) Bastion Name(Unique). + * `host` - (Optional, String) Reference to the Inventory resource definition. +* `command_name` - (Required, String) Schematics job command name. + * Constraints: Allowable values are: workspace_plan, workspace_apply, workspace_destroy, workspace_refresh, ansible_playbook_run, ansible_playbook_check, create_action, put_action, patch_action, delete_action, system_key_enable, system_key_delete, system_key_disable, system_key_rotate, system_key_restore, create_workspace, put_workspace, patch_workspace, delete_workspace, create_cart, create_environment, put_environment, delete_environment, environment_init, environment_install, environment_uninstall, repository_process +* `command_object` - (Required, String) Name of the Schematics automation resource. + * Constraints: Allowable values are: workspace, action, system, environment +* `command_object_id` - (Required, String) Job command object id (workspace-id, action-id). +* `command_options` - (Optional, List) Command line options for the command. +* `command_parameter` - (Optional, String) Schematics job command parameter (playbook-name). +* `data` - (Optional, List) Job data. +Nested scheme for **data**: + * `job_type` - (Required, String) Type of Job. + * Constraints: Allowable values are: repo_download_job, workspace_job, action_job, system_job, flow-job + * `workspace_job_data` - (Optional, List) Workspace Job data. MaxItems: 1. + Nested scheme for **workspace_job_data**: + * `workspace_name` - (Optional, String) Workspace name. + * `flow_id` - (Optional, String) Flow Id. + * `flow_name` - (Optional, String) Flow name. + * `inputs` - (Optional, List) Input variables data used by the Workspace Job. + Nested scheme for **inputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (Optional, List) Output variables data from the Workspace Job. + Nested scheme for **outputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (Optional, List) Environment variables used by all the templates in the Workspace. MaxItems: 1. + Nested scheme for **settings**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `template_data` - (Optional, List) Input / output data of the Template in the Workspace Job. + Nested scheme for **template_data**: + * `template_id` - (Optional, String) Template Id. + * `template_name` - (Optional, String) Template name. + * `flow_index` - (Optional, Integer) Index of the template in the Flow. + * `inputs` - (Optional, List) Job inputs used by the Templates. + Nested scheme for **inputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (Optional, List) Job output from the Templates. + Nested scheme for **outputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (Optional, List) Environment variables used by the template. + Nested scheme for **settings**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `action_job_data` - (Optional, List) Action Job data. + Nested scheme for **action_job_data**: + * `action_name` - (Optional, String) Flow name. + * `inputs` - (Optional, List) Input variables data used by the Action Job. + Nested scheme for **inputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (Optional, List) Output variables data from the Action Job. + Nested scheme for **outputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (Optional, List) Environment variables used by all the templates in the Action. + Nested scheme for **settings**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `inventory_record` - (Optional, List) Complete inventory resource details with user inputs and system generated data. MaxItems: 1. + Nested scheme for **inventory_record**: + * `name` - (Optional, String) The unique name of your Inventory. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. + * `id` - (Optional, String) Inventory id. + * `description` - (Optional, String) The description of your Inventory. The description can be up to 2048 characters long in size. + * `location` - (Optional, String) List of locations supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de + * `resource_group` - (Optional, String) Resource-group name for the Inventory definition. By default, Inventory will be created in Default Resource Group. + * `created_at` - (Optional, String) Inventory creation time. + * `created_by` - (Optional, String) Email address of user who created the Inventory. + * `updated_at` - (Optional, String) Inventory updation time. + * `updated_by` - (Optional, String) Email address of user who updated the Inventory. + * `inventories_ini` - (Optional, String) Input inventory of host and host group for the playbook, in the .ini file format. + * `resource_queries` - (Optional, List) Input resource queries that is used to dynamically generate the inventory of host and host group for the playbook. + * `materialized_inventory` - (Optional, String) Materialized inventory details used by the Action Job, in .ini format. + * `system_job_data` - (Optional, List) Controls Job data. MaxItems: 1. + Nested scheme for **system_job_data**: + * `key_id` - (Optional, String) Key ID for which key event is generated. + * `schematics_resource_id` - (Optional, List) List of the schematics resource id. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `flow_job_data` - (Optional, List) Flow Job data. + Nested scheme for **flow_job_data**: + * `flow_id` - (Optional, String) Flow ID. + * `flow_name` - (Optional, String) Flow Name. + * `workitems` - (Optional, List) Job data used by each workitem Job. + Nested scheme for **workitems**: + * `command_object_id` - (Optional, String) command object id. + * `command_object_name` - (Optional, String) command object name. + * `layers` - (Optional, String) layer name. + * `source_type` - (Optional, String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `source` - (Optional, List) Source of templates, playbooks, or controls. MaxItems: 1. + Nested scheme for **source**: + * `source_type` - (Required, String) Type of source for the Template. + * Constraints: Allowable values are: local, git_hub, git_hub_enterprise, git_lab, ibm_git_lab, ibm_cloud_catalog, external_scm, cos_bucket + * `git` - (Optional, List) Connection details to Git source. MaxItems: 1. + Nested scheme for **git**: + * `computed_git_repo_url` - (Optional, String) The Complete URL which is computed by git_repo_url, git_repo_folder and branch. + * `git_repo_url` - (Optional, String) URL to the GIT Repo that can be used to clone the template. + * `git_token` - (Optional, String) Personal Access Token to connect to Git URLs. + * `git_repo_folder` - (Optional, String) Name of the folder in the Git Repo, that contains the template. + * `git_release` - (Optional, String) Name of the release tag, used to fetch the Git Repo. + * `git_branch` - (Optional, String) Name of the branch, used to fetch the Git Repo. + * `catalog` - (Optional, List) Connection details to IBM Cloud Catalog source. MaxItems: 1. + Nested scheme for **catalog**: + * `catalog_name` - (Optional, String) name of the private catalog. + * `offering_name` - (Optional, String) Name of the offering in the IBM Catalog. + * `offering_version` - (Optional, String) Version string of the offering in the IBM Catalog. + * `offering_kind` - (Optional, String) Type of the offering, in the IBM Catalog. + * `offering_id` - (Optional, String) Id of the offering the IBM Catalog. + * `offering_version_id` - (Optional, String) Id of the offering version the IBM Catalog. + * `offering_repo_url` - (Optional, String) Repo Url of the offering, in the IBM Catalog. + * `inputs` - (Optional, List) Input variables data for the workItem used in FlowJob. + Nested scheme for **inputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `outputs` - (Optional, List) Output variables for the workItem. + Nested scheme for **outputs**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `settings` - (Optional, List) Environment variables for the workItem. + Nested scheme for **settings**: + * `name` - (Optional, String) Name of the variable. + * `value` - (Optional, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. MaxItems: 1. + Nested scheme for **metadata**: + * `type` - (Optional, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. + * `last_job` - (Optional, List) Status of the last job executed by the workitem. MaxItems: 1. + Nested scheme for **last_job**: + * `command_object` - (Optional, String) Name of the Schematics automation resource. + * Constraints: Allowable values are: workspace, action, system, environment + * `command_object_name` - (Optional, String) command object name (workspace_name/action_name). + * `command_object_id` - (Optional, String) Workitem command object id, maps to workspace_id or action_id. + * `command_name` - (Optional, String) Schematics job command name. + * Constraints: Allowable values are: workspace_plan, workspace_apply, workspace_destroy, workspace_refresh, ansible_playbook_run, ansible_playbook_check, create_action, put_action, patch_action, delete_action, system_key_enable, system_key_delete, system_key_disable, system_key_rotate, system_key_restore, create_workspace, put_workspace, patch_workspace, delete_workspace, create_cart, create_environment, put_environment, delete_environment, environment_init, environment_install, environment_uninstall, repository_process + * `job_id` - (Optional, String) Workspace job id. + * `job_status` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `updated_at` - (Optional, String) Job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. +* `job_env_settings` - (Optional, List) Environment variables used by the Job while performing Action or Workspace. +Nested scheme for **job_env_settings**: + * `name` - (Required, String) Name of the variable. + * `value` - (Required, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Required, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `job_inputs` - (Optional, List) Job inputs used by Action or Workspace. +Nested scheme for **job_inputs**: + * `name` - (Required, String) Name of the variable. + * `value` - (Required, String) Value for the variable or reference to the value. + * `metadata` - (Optional, List) User editable metadata for the variables. + Nested scheme for **metadata**: + * `type` - (Required, String) Type of the variable. + * Constraints: Allowable values are: boolean, string, integer, date, array, list, map, complex + * `aliases` - (Optional, List) List of aliases for the variable name. + * `description` - (Optional, String) Description of the meta data. + * `default_value` - (Optional, String) Default value for the variable, if the override value is not specified. + * `secure` - (Optional, Boolean) Is the variable secure or sensitive ?. + * `immutable` - (Optional, Boolean) Is the variable readonly ?. + * `hidden` - (Optional, Boolean) If true, the variable will not be displayed on UI or CLI. + * `options` - (Optional, List) List of possible values for this variable. If type is integer or date, then the array of string will be converted to array of integers or date during runtime. + * `min_value` - (Optional, Integer) Minimum value of the variable. Applicable for integer type. + * `max_value` - (Optional, Integer) Maximum value of the variable. Applicable for integer type. + * `min_length` - (Optional, Integer) Minimum length of the variable value. Applicable for string type. + * `max_length` - (Optional, Integer) Maximum length of the variable value. Applicable for string type. + * `matches` - (Optional, String) Regex for the variable value. + * `position` - (Optional, Integer) Relative position of this variable in a list. + * `group_by` - (Optional, String) Display name of the group this variable belongs to. + * `source` - (Optional, String) Source of this meta-data. + * `link` - (Optional, String) Reference link to the variable value By default the expression will point to self.value. +* `location` - (Optional, String) Location supported by IBM Cloud Schematics service. While creating your workspace or action, choose the right region, since it cannot be changed. Note, this does not limit the location of the IBM Cloud resources, provisioned using Schematics. + * Constraints: Allowable values are: us-south, us-east, eu-gb, eu-de +* `log_summary` - (Optional, List) Job log summary record. +Nested scheme for **log_summary**: + * `job_id` - (Optional, String) Workspace Id. + * `job_type` - (Optional, String) Type of Job. + * Constraints: Allowable values are: repo_download_job, workspace_job, action_job, system_job, flow_job + * `log_start_at` - (Optional, String) Job log start timestamp. + * `log_analyzed_till` - (Optional, String) Job log update timestamp. + * `elapsed_time` - (Optional, Float) Job log elapsed time (log_analyzed_till - log_start_at). + * `log_errors` - (Optional, List) Job log errors. + Nested scheme for **log_errors**: + * `error_code` - (Optional, String) Error code in the Log. + * `error_msg` - (Optional, String) Summary error message in the log. + * `error_count` - (Optional, Float) Number of occurrence. + * `repo_download_job` - (Optional, List) Repo download Job log summary. + Nested scheme for **repo_download_job**: + * `scanned_file_count` - (Optional, Float) Number of files scanned. + * `quarantined_file_count` - (Optional, Float) Number of files quarantined. + * `detected_filetype` - (Optional, String) Detected template or data file type. + * `inputs_count` - (Optional, String) Number of inputs detected. + * `outputs_count` - (Optional, String) Number of outputs detected. + * `workspace_job` - (Optional, List) Workspace Job log summary. MaxItems: 1. + Nested scheme for **workspace_job**: + * `resources_add` - (Optional, Float) Number of resources add. + * `resources_modify` - (Optional, Float) Number of resources modify. + * `resources_destroy` - (Optional, Float) Number of resources destroy. + * `flow_job` - (Optional, List) Flow Job log summary. MaxItems: 1. + Nested scheme for **flow_job**: + * `workitems_completed` - (Optional, Float) Number of workitems completed successfully. + * `workitems_pending` - (Optional, Float) Number of workitems pending in the flow. + * `workitems_failed` - (Optional, Float) Number of workitems failed. + * `workitems` - (Optional, List) + Nested scheme for **workitems**: + * `workspace_id` - (Optional, String) workspace ID. + * `job_id` - (Optional, String) workspace JOB ID. + * `resources_add` - (Optional, Float) Number of resources add. + * `resources_modify` - (Optional, Float) Number of resources modify. + * `resources_destroy` - (Optional, Float) Number of resources destroy. + * `log_url` - (Optional, String) Log url for job. + * `action_job` - (Optional, List) Flow Job log summary. + Nested scheme for **action_job**: + * `target_count` - (Optional, Float) number of targets or hosts. + * `task_count` - (Optional, Float) number of tasks in playbook. + * `play_count` - (Optional, Float) number of plays in playbook. + * `recap` - (Optional, List) Recap records. + Nested scheme for **recap**: + * `target` - (Optional, List) List of target or host name. + * `ok` - (Optional, Float) Number of OK. + * `changed` - (Optional, Float) Number of changed. + * `failed` - (Optional, Float) Number of failed. + * `skipped` - (Optional, Float) Number of skipped. + * `unreachable` - (Optional, Float) Number of unreachable. + * `system_job` - (Optional, List) System Job log summary. MaxItems: 1. + Nested scheme for **system_job**: + * `target_count` - (Optional, Float) number of targets or hosts. + * `success` - (Optional, Float) Number of passed. + * `failed` - (Optional, Float) Number of failed. +* `status` - (Optional, List) Job Status. MaxItems: 1. +Nested scheme for **status**: + * `workspace_job_status` - (Optional, List) Workspace Job Status. + Nested scheme for **workspace_job_status**: + * `workspace_name` - (Optional, String) Workspace name. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) Workspace job status message (eg. App1_Setup_Pending, for a 'Setup' flow in the 'App1' Workspace). + * `flow_status` - (Optional, List) Environment Flow JOB Status.MaxItems: 1. + Nested scheme for **flow_status**: + * `flow_id` - (Optional, String) flow id. + * `flow_name` - (Optional, String) flow name. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) Flow Job status message - to be displayed along with the status_code;. + * `workitems` - (Optional, List) Environment's individual workItem status details;. + Nested scheme for **workitems**: + * `workspace_id` - (Optional, String) Workspace id. + * `workspace_name` - (Optional, String) workspace name. + * `job_id` - (Optional, String) workspace job id. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) workitem job status message;. + * `updated_at` - (Optional, String) workitem job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `template_status` - (Optional, List) Workspace Flow Template job status. + Nested scheme for **template_status**: + * `template_id` - (Optional, String) Template Id. + * `template_name` - (Optional, String) Template name. + * `flow_index` - (Optional, Integer) Index of the template in the Flow. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) Template job status message (eg. VPCt1_Apply_Pending, for a 'VPCt1' Template). + * `updated_at` - (Optional, String) Job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `action_job_status` - (Optional, List) Action Job Status. + Nested scheme for **action_job_status**: + * `action_name` - (Optional, String) Action name. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) Action Job status message - to be displayed along with the action_status_code. + * `bastion_status_code` - (Optional, String) Status of Resources. + * Constraints: Allowable values are: none, ready, processing, error + * `bastion_status_message` - (Optional, String) Bastion status message - to be displayed along with the bastion_status_code;. + * `targets_status_code` - (Optional, String) Status of Resources. + * Constraints: Allowable values are: none, ready, processing, error + * `targets_status_message` - (Optional, String) Aggregated status message for all target resources, to be displayed along with the targets_status_code;. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `system_job_status` - (Optional, List) System Job Status. MaxItems: 1. + Nested scheme for **system_job_status**: + * `system_status_message` - (Optional, String) System job message. + * `system_status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `schematics_resource_status` - (Optional, List) job staus for each schematics resource. + Nested scheme for **schematics_resource_status**: + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) system job status message. + * `schematics_resource_id` - (Optional, String) id for each resource which is targeted as a part of system job. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. + * `flow_job_status` - (Optional, List) Environment Flow JOB Status. MaxItems: 1. + Nested scheme for **flow_job_status**: + * `flow_id` - (Optional, String) flow id. + * `flow_name` - (Optional, String) flow name. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) Flow Job status message - to be displayed along with the status_code;. + * `workitems` - (Optional, List) Environment's individual workItem status details;. + Nested scheme for **workitems**: + * `workspace_id` - (Optional, String) Workspace id. + * `workspace_name` - (Optional, String) workspace name. + * `job_id` - (Optional, String) workspace job id. + * `status_code` - (Optional, String) Status of Jobs. + * Constraints: Allowable values are: job_pending, job_in_progress, job_finished, job_failed, job_cancelled + * `status_message` - (Optional, String) workitem job status message;. + * `updated_at` - (Optional, String) workitem job status updation timestamp. + * `updated_at` - (Optional, String) Job status updation timestamp. +* `tags` - (Optional, List) User defined tags, while running the job. - Nested scheme for `data`: - - `action_job_data`- (Optional, String) Action Job data. - - `job_type` - (Required, String)Type of the job. -- `inputs`- (Optional, List) The job inputs used by an action. - - Nested scheme for `inputs`: - - `link`- (Optional, String) The reference link to the variable value By default the expression will point to self.value. - - `metadata`- `VariableMetadata` - Optional - User editable metadata for the variables. - - `name`- (Optional, String) The name of the variable. - - `value`- (Optional, String) The value for the variable or reference to the value. -- `location`- (Optional, String) List of action locations supported by Schematics service. **Note** this does not limit the location of the resources provisioned by using Schematics. -- `log_summary`- (Optional, List) The job log summary record. +## Attribute reference - Nested scheme for `log_summary`: - - `action_job`- (Optional, String) The job log summary flow. - - `elapsed_time`- (Optional, Float64) The job log elapsed time `log_analyzed_till`, `log_start_at`. - - `job_id`- (Optional, String) The workspace ID. - - `job_type`- (Optional, String) The type of Job. - - `log_start_at`- `TypeString` - Optional - The job log start timestamp. - - `log_analyzed_till`- (Optional, TypeString) The job log update timestamp. - - `log_errors`- (Optional, []Interface{}) The job log errors. - - `repo_download_job`- (Optional, String) The repository download job log summary. -- `settings`- (Optional, List) Environment variables used by the job while performing an action. +In addition to all argument references listed, you can access the following attribute references after your resource is created. - Nested scheme for `settings`: - - `link`- (Optional, String) Reference link to the variable value. By default the expression will point to `self.value`. - - `metadata`- (Optional, String) - User editable metadata for the variables. - - `name`- (Optional, String) Name of the variable. - - `value`- (Optional, String) Value for the variable or reference to the value. -- `status`- (Optional, List) The job status. +* `id` - The unique identifier of the schematics_job. +* `description` - (Optional, String) The description of your job is derived from the related action or workspace. The description can be up to 2048 characters long in size. +* `duration` - (Optional, String) Duration of job execution; example 40 sec. +* `end_at` - (String) Job end time. +* `log_store_url` - (Optional, String) Job log store URL. +* `name` - (Optional, String) Job name, uniquely derived from the related Workspace or Action. +* `resource_group` - (Optional, String) Resource-group name derived from the related Workspace or Action. +* `results_url` - (Optional, String) Job results store URL. +* `start_at` - (Optional, String) Job start time. +* `state_store_url` - (Optional, String) Job state store URL. +* `submitted_at` - (String) Job submission time. +* `submitted_by` - (String) Email address of user who submitted the job. +* `updated_at` - (String) Job status updation timestamp. - Nested scheme for `status`: - - `action_job_status`- (Optional, String) The action job status. -- `tags`- (Optional, List) User defined tags, while running the job. -- `x_github_token`- (Optional, String) Creates and launches the job record. +## Import -## Attribute reference -In addition to all argument reference list, you can access the following attribute reference after your resource is created. +You can import the `ibm_schematics_job` resource by using `id`. Job ID. -- `description` - (String) The job description derived from the related action. -- `duration` - (String) The duration of the job execution, for example, `40 seconds`. -- `end_at` - (String) The job end time. -- `id` - (String) The unique identifier of the Schematics job. -- `log_store_url` - (String) The job log store URL. -- `name` - (String) The job name, uniquely derived from the related action. -- `resource_group` - (String) The resource group name derived from the related action. -- `results_url` - (String) The job results store URL. -- `submitted_at` - (String) The job submission time. -- `submitted_by` - (String) The Email address of the user who submitted the job. -- `start_at` - (String) The job start time. -- `state_store_url` - (String) The job state store URL. -- `targets_ini` - (String) An inventory of host and host group for the playbook in `INI` file format. For example, `"targets_ini": "[webserverhost] 172.22.192.6 [dbhost] 172.22.192.5"`. For more information, about an inventory host group syntax, see [Inventory host groups](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#inventory-host-grps). -- `updated_at` - (Timestamp) The job status update timestamp. +# Syntax +``` +$ terraform import ibm_schematics_job.schematics_job +``` diff --git a/website/docs/r/schematics_resource_query.html.markdown b/website/docs/r/schematics_resource_query.html.markdown new file mode 100644 index 000000000..0516120d2 --- /dev/null +++ b/website/docs/r/schematics_resource_query.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: "Schematics" +layout: "ibm" +page_title: "IBM : ibm_schematics_resource_query" +sidebar_current: "docs-ibm-resource-schematics-resource-query" +description: |- + Manages the Schematics resource query. +--- + +# ibm_schematics_resource_query +Create, update, and delete a Schematics resource query. For more information, about Schematics action resource query, see [Supported resource queries](https://cloud.ibm.com/docs/schematics?topic=schematics-inventories-setup#supported-queries). + +## Example usage + +```terraform +resource "ibm_schematics_resource_query" "schematics_resource_query" { +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `name` - (Optional, String) Resource query name. +* `location` - (Optional, String) The region of the workspace. +- `queries` - (Optional, List) +Nested scheme for **queries**: + - `query_type` - (Optional, String) Type of the query(workspaces). + - Constraints: Allowable values are: workspaces + - `query_condition` - (Optional, List) + Nested scheme for **query_condition**: + - `name` - (Optional, String) Name of the resource query param. + - `value` - (Optional, String) Value of the resource query param. + - `description` - (Optional, String) Description of resource query param variable. + - `query_select` - (Optional, List) List of query selection parameters. +- `type` - (Optional, String) Resource type (cluster, vsi, icd, vpc). + - Constraints: Allowable values are: vsi + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - The unique identifier of the schematics_resource_query. +- `created_at` - (String) Resource query creation time. +- `created_by` - (String) Email address of user who created the resource query. +- `updated_at` - (String) Resource query updation time. +- `updated_by` - (String) Email address of user who updated the resource query. + +## Import + +You can import the `ibm_schematics_resource_query` resource by using `id`. + +# Syntax + +```sh +$ terraform import ibm_schematics_resource_query.schematics_resource_query +``` diff --git a/website/docs/r/schematics_workspace.html.markdown b/website/docs/r/schematics_workspace.html.markdown index a4f68cb58..59bf78430 100644 --- a/website/docs/r/schematics_workspace.html.markdown +++ b/website/docs/r/schematics_workspace.html.markdown @@ -25,84 +25,100 @@ resource "ibm_schematics_workspace" "schematics_workspace" { ## Argument reference -Review the argument references that you can specify for your resource. - -- `applied_shareddata_ids` - (Optional, List) List of applied shared data set ID. -- `catalog_ref` - (Optional, List) The software template that you select from the IBM Cloudcatalog and returned for IBM Cloud catalog offerings only. - - Nested scheme for `catalog_ref`: - - `dry_run`- (Optional, Bool) Dry run. - - `item_icon_url`- (Optional, String) The icon URL of the software template in the IBM Cloud catalog. - - `item_id`- (Optional, String) The ID of the software template that you select to install from the IBM Cloud catalog. This software is provisioned with Schematics. - - `item_name` - (Optional, String) The name of the software that you select to install from the IBM Cloud catalog. - - `item_readme_url`- (Optional, String) The URL to the readme file of the software template in the IBM Cloud catalog. - - `item_url` - (Optional, String) The URL to the software template in the IBM Cloud catalog. - - `launch_url` - (Optional, String) The dashboard URL to access the software. - - `offering_version` - (Optional, String) The version of the software template that you select to install from the IBM Cloud catalog. -- `description` - (Optional, String) The description of the workspace. -- `location` - (Optional, String) The location where you want to create your Schematics workspace and run Schematics actions. The location that you enter should match the API endpoint that you use. For example, if you use the `Frankfurt API endpoint`, you should specify `eu-de` as your location. If you use an API endpoint for a geography and you do not specify a location, Schematics determines the location based on availability. -- `name` - (Optional, String) The name of your workspace. The name can be up to **128** characters long and can include alphanumeric characters, spaces, dashes, and underscores. When you create a workspace for your own Terraform template, consider including the microservice component that you set up with your Terraform template and the IBM Cloud environment where you want to deploy your resources in your name. -- `resource_group` - (Optional, String) The ID of the resource group where you want to provision the workspace. -- `shared_data` - (Optional, String) Information that is shared across templates in IBM Cloud catalog offerings. This information is not provided when you create a workspace from your own Terraform template. - - Nested scheme for `shared_data`: - - `cluster_created_on` - (Optional, String) The cluster created on. - - `cluster_id` - (Optional, String) The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering. - - `cluster_name` - (Optional, String) The cluster name. - - `cluster_type` - (Optional, String) The cluster type. - - `entitlement_keys` - `[]interface{}]` - Optional - The entitlement key that you want to use to install IBM Cloud entitled software. - - `namespace` - (Optional, String) The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into. - - `region` - (Optional, String) The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. - - `resource_group_id` - (Optional, String) The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. - - `worker_count` - (Optional, Integer) Cluster worker count. - - `worker_machine_type` - (Optional, String) Cluster worker type. -- `tags` - (Optional, List) A list of tags that are associated with the workspace. -- `template_data` - (Optional, List) List of template data. - - Nested scheme for `template_data`: - - `env_values`- (Optional, []interface{}) A list of environment variables that you want to apply during the execution of a bash script or Terraform action. This field contains the list of key-value pairs, for example, `TF_LOG=debug`. Each entry is map with one entry where key is the environment variable name and value is value. You can define environment variables for IBM Cloud catalog offerings that are provisioned by using a bash script. - - `folder` - (Optional, String) The subfolder in your GitHub or GitLab repository where your Terraform template is stored. - - `init_state_file` - (Optional, String) The content of an existing Terraform statefile that you want to import to your workspace. To get the content of a Terraform statefile for a specific Terraform template in an existing workspace, run `ibmcloud terraform state pull id template `. - - `type` - (Optional, String) The Terraform version that you want to run your Terraform code. Enter `terraform_v0.12` to use Terraform version 0.12, and `terraform_v0.11` to use Terraform version 0.11. If value is not specified, the Terraform config files are run with Terraform version 0.11. Make sure that your Terraform config files are compatible with the Terraform version that you select. - - `uninstall_script_name` - (Optional, String) The script name to uninstall. - - `values` - (Optional, String) A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `autoscaling: enabled: true minReplicas: 2`. The values that you define here overrides the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider. - - `values_metadata` - (Optional, []interface{}) The list of values metadata. - - `variablestore` - (Optional, []interface{}) The variable request. -- `template_ref` - (Optional, String) The workspace template reference. -- `template_repo` - (Optional, List) The input parameter to specify the source repository where your Schematics template is stored. - - Nested scheme for `template_repo`: - - `branch` - (Optional, String) The branch in GitHub where your Terraform template is stored. - - `release` - (Optional, String) The release tag in GitHub of your Terraform template. - - `repo_sha_value` - (Optional, String) The SHA value from the repository. - - `repo_url` - (Optional, String) The URL to the repository where the IBM Cloud catalog software template is stored. - - `url` - (Optional, String) The GitHub or GitLab repository URL where your Terraform and public bit bucket template is stored. For more information of the environment variable syntax, see [Create workspace new](https://cloud.ibm.com/docs/schematics?topic=schematics-schematics-cli-reference#schematics-workspace-new). -- `type` - (Optional, List) The Terraform version that you want to use to run your Terraform code. Enter terraform_v0.12 to use Terraform version 0.12, and terraform_v0.11 to use Terraform version 0.11. If no value is specified, the Terraform config files are run with Terraform version 0.11. Make sure that your Terraform config files are compatible with the Terraform version that you select. -- `workspace_status` - (Optional, List) The Workspace status request. - - Nested scheme for `workspace_status`: - - `frozen`- (Optional, Bool) If set to **true**, the workspace is frozen and changes to the workspace are disabled. - - `frozen_at` - (Optional, TypeString) The timestamp when the workspace was frozen. - - `frozen_by` - (Optional, String) The user ID that froze the workspace. - - `locked` - (Optional, Bool) If set to **true**, the workspace is locked and disabled for changes. - - `locked_by` - (Optional, String) The user ID that initiated a resource-related action, such as applying or destroying resources, that locked the workspace. - - `locked_time` - (Optional, TypeString) The timestamp when the workspace was locked. -- `x_github_token` - (Optional, String) The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template. + +Review the argument reference that you can specify for your resource. + +* `applied_shareddata_ids` - (Optional, List) List of applied shared dataset ID. +* `catalog_ref` - (Optional, List) Information about the software template that you chose from the IBM Cloud catalog. This information is returned for IBM Cloud catalog offerings only. MaxItems:1. +Nested scheme for **catalog_ref**: + * `dry_run` - (Optional, Boolean) Dry run. + * `owning_account` - (Optional, String) Owning account ID of the catalog. + * `item_icon_url` - (Optional, String) The URL to the icon of the software template in the IBM Cloud catalog. + * `item_id` - (Optional, String) The ID of the software template that you chose to install from the IBM Cloud catalog. This software is provisioned with Schematics. + * `item_name` - (Optional, String) The name of the software that you chose to install from the IBM Cloud catalog. + * `item_readme_url` - (Optional, String) The URL to the readme file of the software template in the IBM Cloud catalog. + * `item_url` - (Optional, String) The URL to the software template in the IBM Cloud catalog. + * `launch_url` - (Optional, String) The URL to the dashboard to access your software. + * `offering_version` - (Optional, String) The version of the software template that you chose to install from the IBM Cloud catalog. +* `description` - (Optional, String) The description of the workspace. +* `location` - (Optional, String) The location where you want to create your Schematics workspace and run the Schematics jobs. The location that you enter must match the API endpoint that you use. For example, if you use the Frankfurt API endpoint, you must specify `eu-de` as your location. If you use an API endpoint for a geography and you do not specify a location, Schematics determines the location based on availability. +* `name` - (Required, String) The name of your workspace. The name can be up to 128 characters long and can include alphanumeric characters, spaces, dashes, and underscores. When you create a workspace for your own Terraform template, consider including the microservice component that you set up with your Terraform template and the IBM Cloud environment where you want to deploy your resources in your name. +* `resource_group` - (Optional, String) The ID of the resource group where you want to provision the workspace. +* `shared_data` - (Optional, List) Information about the Target used by the templates originating from the IBM Cloud catalog offerings. This information is not relevant for workspace created using your own Terraform template. MaxItems:1. +Nested scheme for **shared_data**: + * `cluster_created_on` - (Optional, String) Cluster created on. + * `cluster_id` - (Optional, String) The ID of the cluster where you want to provision the resources of all IBM Cloud catalog templates that are included in the catalog offering. + * `cluster_name` - (Optional, String) The cluster name. + * `cluster_type` - (Optional, String) The cluster type. + * `entitlement_keys` - (Optional, List) The entitlement key that you want to use to install IBM Cloud entitled software. + * `namespace` - (Optional, String) The Kubernetes namespace or OpenShift project where the resources of all IBM Cloud catalog templates that are included in the catalog offering are deployed into. + * `region` - (Optional, String) The IBM Cloud region that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. + * `resource_group_id` - (Optional, String) The ID of the resource group that you want to use for the resources of all IBM Cloud catalog templates that are included in the catalog offering. + * `worker_count` - (Optional, Integer) The cluster worker count. + * `worker_machine_type` - (Optional, String) The cluster worker type. +* `tags` - (Optional, List) A list of tags that are associated with the workspace. +* `template_env_settings` - (Optional, List) A list of environment variables that you want to apply during the execution of a bash script or Terraform job. This field must be provided as a list of key-value pairs, for example, **TF_LOG=debug**. Each entry will be a map with one entry where `key is the environment variable name and value is value`. You can define environment variables for IBM Cloud catalog offerings that are provisioned by using a bash script. See [example to use special environment variable](https://cloud.ibm.com/docs/schematics?topic=schematics-set-parallelism#parallelism-example) that are supported by Schematics. +* `template_git_folder` - (Optional, String) The subfolder in your GitHub or GitLab repository where your Terraform template is stored. +* `template_init_state_file` - (Optional, String) The content of an existing Terraform statefile that you want to import in to your workspace. To get the content of a Terraform statefile for a specific Terraform template in an existing workspace, run `ibmcloud terraform state pull --id --template `. +* `template_type` - (Required, String) The Terraform version that you want to use to run your Terraform code. Enter `terraform_v0.12` to use Terraform version 0.12, and `terraform_v0.11` to use Terraform version 0.11. The Terraform config files are run with Terraform version 0.11. This is a required variable. Make sure that your Terraform config files are compatible with the Terraform version that you select. See [terraform versions](https://cloud.ibm.com/docs/schematics?topic=schematics-migrating-terraform-version) that are supported by Schematics. +* `template_uninstall_script_name` - (Optional, String) Uninstall script name. +* `template_values` - (Optional, String) A list of variable values that you want to apply during the Helm chart installation. The list must be provided in JSON format, such as `"autoscaling: enabled: true minReplicas: 2"`. The values that you define here override the default Helm chart values. This field is supported only for IBM Cloud catalog offerings that are provisioned by using the Terraform Helm provider. +* `template_values_metadata` - (Optional, List) List of values metadata. +* `template_inputs` - (Optional, List) VariablesRequest -. +Nested scheme for **variablestore**: + * `description` - (Optional, String) The description of your input variable. + * `name` - (Required, String) The name of the variable. + * `secure` - (Optional, Boolean) If set to `true`, the value of your input variable is protected and not returned in your API response. + * `type` - (Required, String) `Terraform v0.11` supports `string`, `list`, `map` data type. For more information, about the syntax, see [Configuring input variables](https://www.terraform.io/docs/configuration-0-11/variables.html).
`Terraform v0.12` additionally, supports `bool`, `number` and complex data types such as `list(type)`, `map(type)`,`object({attribute name=type,..})`, `set(type)`, `tuple([type])`. For more information, about the syntax to use the complex data type, see [Configuring variables](https://www.terraform.io/docs/configuration/variables.html#type-constraints). + * `use_default` - (Optional, Boolean) Variable uses default value; and is not over-ridden. + * `value` - (Required, String) Enter the value as a string for the primitive types such as `bool`, `number`, `string`, and `HCL` format for the complex variables, as you provide in a `.tfvars` file. **You need to enter escaped string of `HCL` format for the complex variable value**. For more information, about how to declare variables in a terraform configuration file and provide value to schematics, see [Providing values for the declared variables](https://cloud.ibm.com/docs/schematics?topic=schematics-create-tf-config#declare-variable). +* `template_ref` - (Optional, String) Workspace template ref. +* `template_git_branch` - (Optional, String) The repository branch. +* `template_git_release` - (Optional, String) The repository release. +* `template_git_repo_sha_value` - (Optional, String) The repository SHA value. +* `template_git_repo_url` - (Optional, String) The repository URL. +* `template_git_url` - (Optional, String) The source URL. +* `frozen` - (Optional, Boolean) If set to true, the workspace is frozen and changes to the workspace are disabled. +* `frozen_at` - (Optional, String) The timestamp when the workspace was frozen. +* `frozen_by` - (Optional, String) The user ID that froze the workspace. +* `locked` - (Optional, Boolean) If set to true, the workspace is locked and disabled for changes. +* `locked_by` - (Optional, String) The user ID that initiated a resource-related job, such as applying or destroying resources, that locked the workspace. +* `locked_time` - (Optional, String) The timestamp when the workspace was locked. +* `x_github_token` - (Optional, String) The personal access token to authenticate with your private GitHub or GitLab repository and access your Terraform template. ## Attribute reference -In addition to all argument reference list, you can access the following attribute reference after your resource is created. - -- `id` - (String) The unique identifier of the Schematics workspace. -- `created_at` - (Timestamp) The timestamp when the workspace is created. -- `created_by ` - (String) The user ID that created the workspace. -- `crn` - (String) The workspace CRN. -- `last_health_check_at` - (String) The timestamp when the last health check is executed by Schematics. -- `runtime_data` - (String) The information about the provisioning engine, state file, and runtime logs. -- `status`- (String) The status of the workspace. For more information, see [workspace status](https://cloud.ibm.com/docs/schematics?topic=schematics-workspace-setup#wks-state). -- `updated_at`- (String) The timestamp when the workspace last updated. -- `updated_by`- (String) The user ID that updated the workspace. -- `workspace_status_msg` -String - The last action information that workspace run. +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `id` - The unique identifier of the schematics_workspace. +* `created_at` - (String) The timestamp when the workspace was created. +* `created_by` - (String) The user ID that created the workspace. +* `crn` - (Optional, String) The workspace CRN. +* `last_health_check_at` - (String) The timestamp when the last health check was performed by Schematics. +* `runtime_data` - (Optional, List) Information about the provisioning engine, state file, and runtime logs. +Nested scheme for **runtime_data**: + * `engine_cmd` - (Optional, String) The command that was used to apply the Terraform template or IBM Cloud catalog software template. + * `engine_name` - (Optional, String) The provisioning engine that was used to apply the Terraform template or IBM Cloud catalog software template. + * `engine_version` - (Optional, String) The version of the provisioning engine that was used. + * `id` - (Optional, String) The ID that was assigned to your Terraform template or IBM Cloud catalog software template. + * `log_store_url` - (Optional, String) The URL to access the logs that were created during the creation, update, or deletion of your IBM Cloud resources. + * `output_values` - (Optional, List) List of Output values. + * `resources` - (Optional, List) List of resources. + * `state_store_url` - (Optional, String) The URL where the Terraform statefile (`terraform.tfstate`) is stored. You can use the statefile to find an overview of IBM Cloud resources that were created by Schematics. Schematics uses the statefile as an inventory list to determine future create, update, or deletion jobs. +* `status` - (String) The status of the workspace. **Active**: After you successfully ran your infrastructure code by applying your Terraform execution plan, the state of your workspace changes to `Active`. **Connecting**: Schematics tries to connect to the template in your source repo. If successfully connected, the template is downloaded and metadata, such as input parameters, is extracted. After the template is downloaded, the state of the workspace changes to `Scanning`. **Draft**: The workspace is created without a reference to a GitHub or GitLab repository. **Failed**: If errors occur during the execution of your infrastructure code in IBM Cloud Schematics, your workspace status is set to `Failed`. **Inactive**: The Terraform template was scanned successfully and the workspace creation is complete. You can now start running Schematics plan and apply jobs to provision the IBM Cloud resources that you specified in your template. If you have an `Active` workspace and decide to remove all your resources, your workspace is set to `Inactive` after all your resources are removed. **In progress**: When you instruct IBM Cloud Schematics to run your infrastructure code by applying your Terraform execution plan, the status of our workspace changes to `In progress`. **Scanning**: The download of the Terraform template is complete and vulnerability scanning started. If the scan is successful, the workspace state changes to `Inactive`. If errors in your template are found, the state changes to `Template Error`. **Stopped**: The Schematics plan, apply, or destroy job was cancelled manually. **Template Error**: The Schematics template contains errors and cannot be processed. +* `updated_at` - (String) The timestamp when the workspace was last updated. +* `updated_by` - (String) The user ID that updated the workspace. +* `status_code` - (String) The success or error code that was returned for the last plan, apply, or destroy job that ran against your workspace. +* `status_msg` - (String) The success or error message that was returned for the last plan, apply, or destroy job that ran against your workspace. + +## Import + +You can import the `ibm_schematics_workspace` resource by using `id`. The unique identifier of the workspace. + +# Syntax +``` +$ terraform import ibm_schematics_workspace.schematics_workspace +``` **Note** This resource can perform create, read, update and delete operations of schematics workspace. Other schematics operations such as `Plan` and `Apply` which are available in IBM Cloud Schematics console are currently not supported. diff --git a/website/docs/r/tg_connection_prefix_filter.html.markdown b/website/docs/r/tg_connection_prefix_filter.html.markdown new file mode 100644 index 000000000..46660c005 --- /dev/null +++ b/website/docs/r/tg_connection_prefix_filter.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_connection_prefix_filter" +description: |- + Manages IBM Transit Gateway Connection Prefix Filter. +--- + +# ibm_tg_connection_prefix_filter +Create, update and delete for the transit gateways connection's prefix filter resource. For more information, about Transit Gateway connection prefix filters, see [adding and deleting prefix filters](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui). + +## Example usage + +```terraform +resource "ibm_tg_connection_prefix_filter" "test_tg_prefix_filter" { + gateway = ibm_tg_gateway.new_tg_gw.id + connection_id = ibm_tg_connection.test_ibm_tg_connection.connection_id + action = "permit" + prefix = "192.168.100.0/24" + le = 0 + ge = 32 +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `gateway` - (Required, String) The unique identifier of the gateway. +- `connection_id` - (Required, String) The unique identifier of the gateway connection +- `action` - (Required, String) Whether to permit or deny the prefix filter +- `prefix` - (Required, String) The IP Prefix +- `before` - (String) Identifier of prefix filter that handles the ordering and follow semantics. When a filter reference another filter in it's before field, then the filter making the reference is applied before the referenced filter. For example: if filter A references filter B in its before field, A is applied before B. +- `ge` - (Int) The IP Prefix GE. The GE (greater than or equal to) value can be included to match all less-specific prefixes within a parent prefix above a certain length. +- `le` - (Int) The IP Prefix LE. The LE (less than or equal to) value can be included to match all more-specific prefixes within a parent prefix up to a certain length. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `created_at` - (String) The date and time resource is created. +- `filter_id` - (String) The unique identifier of this prefix filter. +- `updated_at` - (String) The date and time resource is last updated. diff --git a/website/docs/r/tg_route_report.html.markdown b/website/docs/r/tg_route_report.html.markdown new file mode 100644 index 000000000..1bce9df91 --- /dev/null +++ b/website/docs/r/tg_route_report.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Transit Gateway" +layout: "ibm" +page_title: "IBM : tg_route_report" +description: |- + Manages IBM Transit Gateway Route Report. +--- + +# ibm_tg_route_report +Create and delete a transit gateway's route report resource. For more information about Transit Gateway Route Reports, see [generating and viewing a route report](https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-route-reports&interface=ui#generate-route-report-ui). + +## Example usage + +```terraform +resource ibm_tg_route_report" "test_tg_route_report" { + gateway = ibm_tg_gateway.new_tg_gw.id +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `gateway` - (Required, String) The unique identifier of the gateway. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your resource is created. + +- `route_report_id` - (String) The unique identifier of this route report. +- `created_at` - (Timestamp) The date and time resource is created. +- `status` - (String) The route report status. +- `updated_at` - (Timestamp) The date and time resource is last updated. +- `connections` - (String) A list of connections in the gateway + + Nested scheme for `connections`: + - `bgps` (String) A list of the connection's bgps + Nested scheme for `bgps`: + - `as_path` - (String) The bgp AS path + - `is_used` - (Bool) Indicates whether the current route is used or not + - `local_preference` (String) The local preference + - `prefix` - (String) The bgp prefix + - `id` - (String) The unique identifier for the transit gateway connection + - `name` - (String) The user-defined name for the transit gateway connection. + - `routes` - (String) A list of the connection's routes + + Nested scheme for `routes`: + - `prefix` - (String) The prefix used in the route + - `type` - (String) The connection type +- `overlapping_routes` - (String) A list of overlapping routes in the gateway + + Nested scheme for `overlapping_routes`: + - `connection_id` - (String) The unique identifier for the transit gateway connection + - `prefix` - (String) The overlapping prefix \ No newline at end of file